Source Code Cross Referenced for RenderedOp.java in  » 6.0-JDK-Modules » Java-Advanced-Imaging » javax » media » jai » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » 6.0 JDK Modules » Java Advanced Imaging » javax.media.jai 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:         * $RCSfile: RenderedOp.java,v $
0003:         *
0004:         * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved.
0005:         *
0006:         * Use is subject to license terms.
0007:         *
0008:         * $Revision: 1.2 $
0009:         * $Date: 2006/06/16 22:52:04 $
0010:         * $State: Exp $
0011:         */
0012:        package javax.media.jai;
0013:
0014:        import com.sun.media.jai.util.ImageUtil;
0015:        import com.sun.media.jai.util.PropertyUtil;
0016:        import java.awt.Point;
0017:        import java.awt.Rectangle;
0018:        import java.awt.RenderingHints;
0019:        import java.awt.Shape;
0020:        import java.awt.geom.Area;
0021:        import java.awt.geom.GeneralPath;
0022:        import java.awt.geom.PathIterator;
0023:        import java.awt.geom.Point2D;
0024:        import java.awt.image.ColorModel;
0025:        import java.awt.image.ImageProducer;
0026:        import java.awt.image.Raster;
0027:        import java.awt.image.RenderedImage;
0028:        import java.awt.image.SampleModel;
0029:        import java.awt.image.WritableRaster;
0030:        import java.awt.image.renderable.ParameterBlock;
0031:        import java.beans.PropertyChangeEvent;
0032:        import java.beans.PropertyChangeListener;
0033:        import java.io.IOException;
0034:        import java.io.ObjectInputStream;
0035:        import java.io.ObjectOutputStream;
0036:        import java.io.Serializable;
0037:        import java.lang.ref.WeakReference;
0038:        import java.util.Arrays;
0039:        import java.util.ArrayList;
0040:        import java.util.Collection;
0041:        import java.util.Enumeration;
0042:        import java.util.HashSet;
0043:        import java.util.Hashtable;
0044:        import java.util.Iterator;
0045:        import java.util.List;
0046:        import java.util.Locale;
0047:        import java.util.Set;
0048:        import java.util.Vector;
0049:        import javax.media.jai.registry.RIFRegistry;
0050:        import javax.media.jai.registry.RenderedRegistryMode;
0051:        import javax.media.jai.remote.PlanarImageServerProxy;
0052:        import javax.media.jai.remote.SerializableRenderedImage;
0053:        import javax.media.jai.util.CaselessStringKey;
0054:        import javax.media.jai.util.ImagingListener;
0055:
0056:        /**
0057:         * A node in a rendered imaging chain.  A <code>RenderedOp</code> stores
0058:         * an operation name, a <code>ParameterBlock</code> containing sources and
0059:         * parameters, and a <code>RenderingHints</code> containing hints which
0060:         * may be used in rendering the node.  A set of nodes may be joined together
0061:         * via the source <code>Vector</code>s within their respective
0062:         * <code>ParameterBlock</code>s to form a <u>d</u>irected <u>a</u>cyclic
0063:         * <u>g</u>raph (DAG).  The topology, i.e., connectivity, of the graph may be
0064:         * altered by changing the node's sources.  The operation name, parameters,
0065:         * and rendering hints may also be changed.
0066:         *
0067:         * <p> Such chains are useful for example as arguments to a
0068:         * <code>RemoteImage</code>; they convey the structure of an imaging
0069:         * chain in a compact representation and at a suitably high level of
0070:         * abstraction to allow the server some leeway in materializing the
0071:         * results.  They are also useful in that a chain may be manipulated
0072:         * dynamically and rendered multiple times.  Thus for example the same
0073:         * chain of operations may be applied to different images or the parameters
0074:         * of certain operations in a chain may be modified interactively.
0075:         *
0076:         * <p> A <code>RenderedOp</code> may be constructed directly as, for example,
0077:         * <pre>
0078:         * <code>
0079:         * ParameterBlock pb =
0080:         *     (new ParameterBlock()).add("SomeFile.tif");
0081:         * RenderedOp node = new RenderedOp("fileload", pb, null);
0082:         * </code>
0083:         * </pre>
0084:         * or via the <code>create</code> or <code>createNS()</code> methods defined
0085:         * in the <code>JAI</code> class.  The difference between direct construction
0086:         * of a node and creation via a convenience method is that in the latter case:
0087:         *
0088:         * <ol>
0089:         * <li> It is verified that the operation supports the rendered mode.</li>
0090:         * <li> Using the <code>validateArguments()</code> method of the associated
0091:         *      <code>OperationDescriptor</code>, the arguments (sources and parameters)
0092:         *      are validated as being compatible with the specified operation.</li>
0093:         * <li> Global <code>RenderingHints</code> maintained by the <code>JAI</code>
0094:         *      instance are merged with the local <code>RenderingHints</code> with the
0095:         *      local hints taking precedence.</li>
0096:         * <li> If the operation is defined to be "immediate" (the
0097:         *      <code>isImmediate()</code> method of the corresponding
0098:         *      <code>OperationDescriptor</code> returns <code>true</code>)
0099:         *      then the node is rendered.</li>
0100:         * </ol>
0101:         *
0102:         * <p> When a chain of nodes is rendered by any means a "parallel" chain of
0103:         * <code>RenderedImage</code>s is created.  Each node in the chain of
0104:         * <code>RenderedOp</code>s corresponds to a node in the chain of
0105:         * <code>RenderedImage</code>s.  <code>RenderedImage</code> methods invoked
0106:         * on the <code>RenderedOp</code> are in general forwarded to the associated
0107:         * <code>RenderedImage</code> which is referred to as the <i>rendering</i>
0108:         * of the node.
0109:         *
0110:         * <p> The translation between <code>RenderedOp</code> chains and
0111:         * <code>RenderedImage</code> (usually <code>OpImage</code>) chains makes
0112:         * use of two levels of indirection provided by the
0113:         * <code>OperationRegistry</code> and <code>RenderedImageFactory</code>
0114:         * (RIF) facilities.  First, the local <code>OperationRegistry</code> is
0115:         * used to map the operation name into a RIF.  This RIF then constructs
0116:         * a <code>RenderedImage</code> (usually an <code>OpImage</code>) which
0117:         * does the actual image data processing.  The local
0118:         * <code>OperationRegistry</code> is used in order to take advantage
0119:         * of the best possible implementation of the operation, e.g., RIFs that
0120:         * provide acceleration for certain cases or RIFs that are known to a server
0121:         * without having to burden the client.
0122:         *
0123:         * <p> A node may be rendered explicitly by invoking the method
0124:         * <code>getRendering()</code> which also returns the rendering of the
0125:         * node.  A node may be rendered implicitly by invoking any method
0126:         * defined in the <code>RenderedImage</code> interface.  A node may also be
0127:         * rendered implicitly by invoking any method the execution of which
0128:         * <ul>
0129:         * <li> requires some dimensional quantity of the image such as its
0130:         * bounds or tile layout;</li>
0131:         * <li> retrieves image data by any means;</li>
0132:         * </ul>
0133:         * The current rendering may be obtained without forcing the rendering of
0134:         * an unrendered node via the method <code>getCurrentRendering()</code>.
0135:         * A node may also be re-rendered via <code>getNewRendering()</code> which
0136:         * regenerates the rendering from the existing set of sources, parameters,
0137:         * and hints.
0138:         *
0139:         * <p> A rendering of a node may also be obtained by means of the
0140:         * <code>createInstance()</code> method.  This method returns a
0141:         * <code>PlanarImage</code> rendering without marking the node as
0142:         * having been rendered.  If the node is not marked as rendered then it
0143:         * will not fire <code>RenderingChangeEvent</code>s as described below.
0144:         *
0145:         * <p> <code>RenderedOp</code> nodes may participate in Java Bean-style
0146:         * events.  The <code>PropertyChangeEmitter</code> methods may be used
0147:         * to register and unregister <code>PropertyChangeListener</code>s.
0148:         * <code>RenderedOp</code>s are also <code>PropertyChangeListener</code>s
0149:         * so that they may be registered as listeners of other
0150:         * <code>PropertyChangeEmitter</code>s or the equivalent.  Each
0151:         * <code>RenderedOp</code> also automatically receives any
0152:         * <code>RenderingChangeEvent</code>s emitted by any of its sources which
0153:         * are also <code>RenderedOp</code>s or any <code>CollectionChangeEvent</code>s
0154:         * from any <code>CollectionOp</code> sources.
0155:         *
0156:         * <p> Certain <code>PropertyChangeEvent</code>s may be emitted by the
0157:         * <code>RenderedOp</code>.  These include the
0158:         * <code>PropertyChangeEventJAI</code>s and
0159:         * <code>PropertySourceChangeEvent</code>s required by virtue of implementing
0160:         * the <code>OperationNode</code> interface.  Additionally a
0161:         * <code>RenderingChangeEvent</code> may be emitted if the node has already
0162:         * been rendered and both of the following conditions are satisfied:
0163:         * <ol>
0164:         * <li>A. any of the critical attributes is changed (edited), i.e., the
0165:         * operation name, operation registry, node sources, parameters, or rendering
0166:         * hints; or
0167:         * <br>B. the node receives a <code>RenderingChangeEvent</code> from one of
0168:         * its <code>RenderedOp</code> sources or a <code>CollectionChangeEvent</code>
0169:         * from one of its <code>CollectionOp</code> sources.</li>
0170:         * <li>the old and new renderings differ over some non-empty region.</li>
0171:         * </ol>
0172:         *
0173:         * <p> When a rendered <code>RenderedOp</code> node receives a
0174:         * <code>RenderingChangeEvent</code> from a <code>RenderedOp</code> source,
0175:         * then if the rendering is an <code>OpImage</code>, the region of
0176:         * the current rendering which may be retained will be determined by using
0177:         * <code>mapSourceRect()</code> to forward map the bounds of the invalid
0178:         * region.  A similar procedure is used for "InvalidRegion" events emitted
0179:         * by source <code>RenderedImage</code>s such as <code>TiledImage</code>s.
0180:         * If a critical attribute of the node is edited, then the
0181:         * <code>getInvalidRegion()</code> method of the corresponding
0182:         * <code>OperationDescriptor</code> will be used to determine the
0183:         * invalid region.  If the complement of the invalid region contains any tiles
0184:         * of the current rendering and the rendering is an <code>OpImage</code>, a
0185:         * new rendering of the node will be generated and the
0186:         * identified tiles will be retained from the old rendering insofar as
0187:         * possible.  This might involve for example adding tiles to a
0188:         * <code>TileCache</code> under the ownership of the new rendering.  A
0189:         * <code>RenderingChangeEvent</code> will then be fired to all
0190:         * <code>PropertyChangeListener</code>s of the node, and to any sinks that
0191:         * are <code>PropertyChangeListener</code>s.  The <code>newRendering</code>
0192:         * parameter of the event constructor (which may be retrieved via the
0193:         * <code>getNewValue()</code> method of the event) will be set to either
0194:         * the new rendering of the node or to <code>null</code> if it was not
0195:         * possible to retain any tiles of the previous rendering.
0196:         *
0197:         * <p> <code>RenderedOp</code> nodes are <code>WritablePropertySource</code>s
0198:         * and so manage a name-value database of image meta-data also known as image
0199:         * properties.  Properties may be set on and requested from a node.  The
0200:         * value of a property not explicitly set on the node (via
0201:         * <code>setProperty()</code>) is obtained from the property environment of
0202:         * the node.  When a property is derived from the property environment it is
0203:         * cached locally to ensure synchronization, i.e., that properties do not
0204:         * change spontaneously if for example the same property is modified upstream.
0205:         *
0206:         * <p> The property environment of a <code>RenderedOp</code> is initially
0207:         * derived from that of the corresponding <code>OperationDescriptor</code>
0208:         * as maintained by the <code>OperationRegistry</code>.  It may be modified
0209:         * locally by adding <code>PropertyGenerator</code>s, directives to copy
0210:         * certain properties from specific sources, or requests to suppress certain
0211:         * properties.  These modifications per se cannot be undone directly but
0212:         * may be eliminated as a side effect of other changes to the node as
0213:         * described below.
0214:         *
0215:         * <p> The <code>RenderedOp</code> itself synthesizes several property values,
0216:         * which may neither be set nor removed.  These are: <code>image_width</code>,
0217:         * <code>image_height</code>, <code>image_min_x_coord</code>,
0218:         * <code>image_min_y_coord</code>, <code>tile_cache</code> and
0219:         * <code>tile_cache_key</code>.  These properties are referred to as
0220:         * <i>synthetic properties</i>.  The property <code>tile_cache_key</code>
0221:         * has a value of type {@link TileCache} which indicates where the tiles
0222:         * of the rendering are cached, if anywhere.  The value of the property
0223:         * <code>tile_cache_key</code> is a {@link RenderedImage} by which the
0224:         * cached tiles are referenced in the indicated cache.  If the rendering
0225:         * is of type {@link OpImage} or
0226:         * {@link javax.media.jai.remote.PlanarImageServerProxy} then the value of
0227:         * <code>tile_cache_key</code> will be set to the rendering itself and the
0228:         * value of <code>tile_cache</code> to the value returned by invoking
0229:         * <code>getTileCache()</code> on the rendering.  Otherwise these properties
0230:         * will be set to the same values as the properties of the same names set
0231:         * on the rendering.  It is legal for these properties to have the value
0232:         * <code>java.awt.Image.UndefinedProperty</code>.
0233:         *
0234:         * <p> When a property value is requested an attempt will be made to derive
0235:         * it from the several entities in the following order of precedence:
0236:         * <ol>
0237:         * <li> synthetic properties; </li>
0238:         * <li> local properties; </li>
0239:         * <li> the rendering of the node; </li>
0240:         * <li> any registered <code>PropertyGenerator</code>s, or
0241:         * <br> a source specified via a copy-from-source directive;</li>
0242:         * <li> the first node source which defines the property. </li>
0243:         * </ol>
0244:         * Local properties are those which have been cached locally either by virtue
0245:         * of direct invocation of <code>setProperty()</code> or due to caching of a
0246:         * property derived from the property environment.  Note that the properties
0247:         * of a node are not copied to its rendering.
0248:         *
0249:         * <p> All dynamically computed properties of a <code>RenderedOp</code> which
0250:         * have been cached locally, i.e., those cached properties which were not set
0251:         * by an explicit call to <code>setProperty()</code>, will be cleared when any
0252:         * of the critical attributes of the node is edited.  By implication these
0253:         * properties will also be cleared when a <code>RenderingChangeEvent</code>
0254:         * is received from any node source.  The property environment or the cached
0255:         * properties may also be cleared by invoking <code>resetProperties()</code>.
0256:         *
0257:         * <p> As mentioned, a <code>RenderedOp</code> chain created on a client
0258:         * may be passed to a server via a <code>RemoteImage</code>.  Whether the
0259:         * node has been previously rendered is irrelevant to its ability to be
0260:         * serialized.  Any <code>RenderedImage</code> sources which are not
0261:         * <code>Serializable</code> will be wrapped in
0262:         * <code>SerializableRenderedImage</code>s for serialization.  The tile
0263:         * transmission parameters will be determined from the
0264:         * <code>RenderingHints</code> of the node.  All other non-serializable
0265:         * objects will attempt to be serialized using
0266:         * <code>SerializerFactory</code>.  If no <code>Serializer</code> is
0267:         * available for a particular object, a
0268:         * <code>java.io.NotSerializableException</code> may result.  Image
0269:         * properties (meta-data) are serialized insofar as they are serializable:
0270:         * non-serializable components are simply eliminated from the local cache
0271:         * of properties and from the property environment.
0272:         *
0273:         * <p> Note that <code>RenderedOp</code> nodes used to instantiate
0274:         * operations which have a corresponding <code>OperationDescriptor</code>
0275:         * the <code>isImmediate()</code> method of which returns
0276:         * <code>true</code> are rendered upon deserialization.
0277:         *
0278:         * <p> <code>RenderedOp</code> represents a single <code>PlanarImage</code>
0279:         * as a node in a <code>RenderedImage</code> operation chain.  Its companion
0280:         * classes, <code>RenderableOp</code> and <code>CollectionOp</code>, represent
0281:         * nodes in operation chains of <code>RenderableImage</code>s and
0282:         * <code>CollectionImage</code>s, respectively.
0283:         *
0284:         *
0285:         * @see CollectionOp
0286:         * @see JAI
0287:         * @see OperationDescriptor
0288:         * @see OperationRegistry
0289:         * @see OpImage
0290:         * @see RenderableOp
0291:         * @see RenderingChangeEvent
0292:         * @see javax.media.jai.remote.SerializableRenderedImage
0293:         * @see javax.media.jai.remote.Serializer
0294:         * @see javax.media.jai.remote.SerializerFactory
0295:         * @see java.awt.RenderingHints
0296:         * @see java.awt.image.renderable.ParameterBlock
0297:         * @see java.awt.image.renderable.RenderedImageFactory
0298:         *
0299:         */
0300:        public class RenderedOp extends PlanarImage implements  OperationNode,
0301:                PropertyChangeListener, Serializable {
0302:
0303:            /**
0304:             * An object to assist in implementing <code>OperationNode</code>.
0305:             *
0306:             * @since JAI 1.1
0307:             */
0308:            protected OperationNodeSupport nodeSupport;
0309:
0310:            /**
0311:             * The <code>PropertySource</code> containing the combined properties
0312:             * of all of the node's sources.
0313:             */
0314:            protected transient PropertySource thePropertySource;
0315:
0316:            /** The rendering of the current image, not preserved over RMI. */
0317:            protected transient PlanarImage theImage;
0318:
0319:            /**
0320:             * The RenderingHints when the node was last rendered, i.e., when
0321:             * "theImage" was set to its current value.
0322:             */
0323:            private transient RenderingHints oldHints;
0324:
0325:            /** Names of synthesized properties. */
0326:            // XXX Synthetic properties should never be inherited. This might imply
0327:            // a need for setting non-inheritable in addition to suppressed properties.
0328:            private static List synthProps;
0329:
0330:            /** Synthesized properties. */
0331:            private Hashtable synthProperties = null;
0332:
0333:            /** Node event names. */
0334:            private static Set nodeEventNames = null;
0335:
0336:            /**
0337:             * Whether dispose() has been invoked.
0338:             */
0339:            private boolean isDisposed = false;
0340:
0341:            static {
0342:                CaselessStringKey[] propKeys = new CaselessStringKey[] {
0343:                        new CaselessStringKey("image_width"),
0344:                        new CaselessStringKey("image_height"),
0345:                        new CaselessStringKey("image_min_x_coord"),
0346:                        new CaselessStringKey("image_min_y_coord"),
0347:                        new CaselessStringKey("tile_cache"),
0348:                        new CaselessStringKey("tile_cache_key") };
0349:                synthProps = Arrays.asList(propKeys);
0350:
0351:                nodeEventNames = new HashSet();
0352:                nodeEventNames.add("operationname");
0353:                nodeEventNames.add("operationregistry");
0354:                nodeEventNames.add("parameterblock");
0355:                nodeEventNames.add("sources");
0356:                nodeEventNames.add("parameters");
0357:                nodeEventNames.add("renderinghints");
0358:            }
0359:
0360:            /**
0361:             * Constructs a <code>RenderedOp</code> that will be used to
0362:             * instantiate a particular rendered operation from the specified
0363:             * operation registry, an operation name, a <code>ParameterBlock</code>,
0364:             * and a set of rendering hints.
0365:             *
0366:             * <p> This method does not validate the contents of the supplied
0367:             * <code>ParameterBlock</code>.  The caller should ensure that
0368:             * the sources and parameters in the <code>ParameterBlock</code>
0369:             * are suitable for the operation this node represents; otherwise
0370:             * some form of error or exception may occur at the time of rendering.
0371:             *
0372:             * <p> The <code>ParameterBlock</code> may include
0373:             * <code>DeferredData</code> parameters.  These will not be evaluated
0374:             * until their values are actually required, i.e., when the node is
0375:             * rendered.
0376:             *
0377:             * <p> The node is added automatically as a sink of any
0378:             * <code>PlanarImage</code> or <code>CollectionImage</code> sources.
0379:             *
0380:             * @param registry  The <code>OperationRegistry</code> to be used for
0381:             *        instantiation.  if <code>null</code>, the default registry
0382:             *        is used.  Saved by reference.
0383:             * @param opName  The operation name.  Saved by reference.
0384:             * @param pb  The sources and parameters. If <code>null</code>,
0385:             *        it is assumed that this node has no sources and parameters.
0386:             *        This parameter is cloned.
0387:             * @param hints  The rendering hints.  If <code>null</code>, it is assumed
0388:             *        that no hints are associated with the rendering.
0389:             *        This parameter is cloned.
0390:             *
0391:             * @throws IllegalArgumentException if <code>opName</code> is
0392:             *         <code>null</code>.
0393:             */
0394:            public RenderedOp(OperationRegistry registry, String opName,
0395:                    ParameterBlock pb, RenderingHints hints) {
0396:                super (new ImageLayout(), null, null);
0397:
0398:                if (pb == null) {
0399:                    // Ensure that the PB is non-null.
0400:                    pb = new ParameterBlock();
0401:                } else {
0402:                    // Clone the PB per the doc.
0403:                    pb = (ParameterBlock) pb.clone();
0404:                }
0405:
0406:                if (hints != null) {
0407:                    // Clone the hints per the doc.
0408:                    hints = (RenderingHints) hints.clone();
0409:                }
0410:
0411:                nodeSupport = new OperationNodeSupport(getRegistryModeName(),
0412:                        opName, registry, pb, hints, eventManager);
0413:
0414:                // Add the node as a PropertyChangeListener of itself for
0415:                // the critical attributes of the node.  Case is ignored
0416:                // in the property names but infix caps are used here anyway.
0417:                addPropertyChangeListener("OperationName", this );
0418:                addPropertyChangeListener("OperationRegistry", this );
0419:                addPropertyChangeListener("ParameterBlock", this );
0420:                addPropertyChangeListener("Sources", this );
0421:                addPropertyChangeListener("Parameters", this );
0422:                addPropertyChangeListener("RenderingHints", this );
0423:
0424:                // Add self as a sink of any PlanarImage or CollectionImage sources.
0425:                Vector nodeSources = pb.getSources();
0426:                if (nodeSources != null) {
0427:                    Iterator it = nodeSources.iterator();
0428:                    while (it.hasNext()) {
0429:                        Object src = it.next();
0430:                        if (src instanceof  PlanarImage) {
0431:                            ((PlanarImage) src).addSink(this );
0432:                        } else if (src instanceof  CollectionImage) {
0433:                            ((CollectionImage) src).addSink(this );
0434:                        }
0435:                    }
0436:                }
0437:            }
0438:
0439:            /**
0440:             * Constructs a <code>RenderedOp</code> that will be used to
0441:             * instantiate a particular rendered operation from the default
0442:             * operation registry, an operation name, a <code>ParameterBlock</code>,
0443:             * and a set of rendering hints.  The default operation registry
0444:             * is used.
0445:             *
0446:             * <p> This method does not validate the contents of the supplied
0447:             * <code>ParameterBlock</code>.  The caller should ensure that
0448:             * the sources and parameters in the <code>ParameterBlock</code>
0449:             * are suitable for the operation this node represents; otherwise
0450:             * some form of error or exception may occur at the time of rendering.
0451:             *
0452:             * <p> The <code>ParameterBlock</code> may include
0453:             * <code>DeferredData</code> parameters.  These will not be evaluated
0454:             * until their values are actually required, i.e., when the node is
0455:             * rendered.
0456:             *
0457:             * <p> The node is added automatically as a sink of any
0458:             * <code>PlanarImage</code> or <code>CollectionImage</code> sources.
0459:             *
0460:             * @param opName  The operation name.  Saved by reference.
0461:             * @param pb  The sources and parameters. If <code>null</code>,
0462:             *        it is assumed that this node has no sources and parameters.
0463:             *        This parameter is cloned.
0464:             * @param hints  The rendering hints.  If <code>null</code>, it is assumed
0465:             *        that no hints are associated with the rendering.
0466:             *        This parameter is cloned.
0467:             *
0468:             * @throws IllegalArgumentException if <code>opName</code> is
0469:             *         <code>null</code>.
0470:             */
0471:            public RenderedOp(String opName, ParameterBlock pb,
0472:                    RenderingHints hints) {
0473:                this (null, opName, pb, hints);
0474:            }
0475:
0476:            /**
0477:             * A <code>TileComputationListener</code> to pass to the
0478:             * <code>scheduleTiles()</code> method of the rendering to intercept
0479:             * method calls such that the image reference is this
0480:             * <code>RenderedOp</code>.
0481:             */
0482:            private class TCL implements  TileComputationListener {
0483:                RenderedOp node;
0484:
0485:                private TCL(RenderedOp node) {
0486:                    this .node = node;
0487:                }
0488:
0489:                public void tileComputed(Object eventSource,
0490:                        TileRequest[] requests, PlanarImage image, int tileX,
0491:                        int tileY, Raster tile) {
0492:                    if (image == theImage) {
0493:                        // Forward call to all listeners.
0494:                        TileComputationListener[] listeners = getTileComputationListeners();
0495:
0496:                        if (listeners != null) {
0497:                            int numListeners = listeners.length;
0498:
0499:                            for (int i = 0; i < numListeners; i++) {
0500:                                listeners[i].tileComputed(node, requests,
0501:                                        image, tileX, tileY, tile);
0502:                            }
0503:                        }
0504:                    }
0505:                }
0506:
0507:                public void tileCancelled(Object eventSource,
0508:                        TileRequest[] requests, PlanarImage image, int tileX,
0509:                        int tileY) {
0510:                    if (image == theImage) {
0511:                        // Forward call to all listeners.
0512:                        TileComputationListener[] listeners = getTileComputationListeners();
0513:
0514:                        if (listeners != null) {
0515:                            int numListeners = listeners.length;
0516:
0517:                            for (int i = 0; i < numListeners; i++) {
0518:                                listeners[i].tileCancelled(node, requests,
0519:                                        image, tileX, tileY);
0520:                            }
0521:                        }
0522:                    }
0523:                }
0524:
0525:                public void tileComputationFailure(Object eventSource,
0526:                        TileRequest[] requests, PlanarImage image, int tileX,
0527:                        int tileY, Throwable situation) {
0528:                    if (image == theImage) {
0529:                        // Forward call to all listeners.
0530:                        TileComputationListener[] listeners = getTileComputationListeners();
0531:
0532:                        if (listeners != null) {
0533:                            int numListeners = listeners.length;
0534:
0535:                            for (int i = 0; i < numListeners; i++) {
0536:                                listeners[i].tileComputationFailure(node,
0537:                                        requests, image, tileX, tileY,
0538:                                        situation);
0539:                            }
0540:                        }
0541:                    }
0542:                }
0543:            }
0544:
0545:            /**
0546:             * Returns the name of the <code>RegistryMode</code> corresponding to
0547:             * this <code>RenderedOp</code>.  This method always returns the
0548:             * <code>String</code> "rendered".
0549:             *
0550:             * @since JAI 1.1
0551:             */
0552:            public String getRegistryModeName() {
0553:                return RegistryMode.getMode("rendered").getName();
0554:            }
0555:
0556:            /* ----- Critical attribute main accessors and mutators. ----- */
0557:
0558:            /**
0559:             * Returns the <code>OperationRegistry</code> that is used
0560:             * by this node.  If the registry is not set, the default
0561:             * registry is returned.
0562:             */
0563:            public synchronized OperationRegistry getRegistry() {
0564:                return nodeSupport.getRegistry();
0565:            }
0566:
0567:            /**
0568:             * Sets the <code>OperationRegistry</code> that is used by
0569:             * this node.  If the specified registry is <code>null</code>, the
0570:             * default registry is used.  The parameter is saved by reference.
0571:             *
0572:             * <p> If the supplied registry does not equal the current registry, a
0573:             * <code>PropertyChangeEventJAI</code> named "OperationRegistry"
0574:             * will be fired and a <code>RenderingChangeEvent</code> may be
0575:             * fired if the node has already been rendered.
0576:             *
0577:             * @param registry  The new <code>OperationRegistry</code> to be set;
0578:             *        it may be <code>null</code>.
0579:             */
0580:            public synchronized void setRegistry(OperationRegistry registry) {
0581:                nodeSupport.setRegistry(registry);
0582:            }
0583:
0584:            /**
0585:             * Returns the name of the operation this node represents as
0586:             * a <code>String</code>.
0587:             */
0588:            public synchronized String getOperationName() {
0589:                return nodeSupport.getOperationName();
0590:            }
0591:
0592:            /**
0593:             * Sets the name of the operation this node represents.
0594:             * The parameter is saved by reference.
0595:             *
0596:             * <p> If the supplied name does not equal the current operation name, a
0597:             * <code>PropertyChangeEventJAI</code> named "OperationName"
0598:             * will be fired and a <code>RenderingChangeEvent</code> may be
0599:             * fired if the node has already been rendered.
0600:             *
0601:             * @param opName  The new operation name to be set.
0602:             *
0603:             * @throws IllegalArgumentException if <code>opName</code> is
0604:             *         <code>null</code>.
0605:             */
0606:            public synchronized void setOperationName(String opName) {
0607:                nodeSupport.setOperationName(opName);
0608:            }
0609:
0610:            /** Returns a clone of the <code>ParameterBlock</code> of this node. */
0611:            public synchronized ParameterBlock getParameterBlock() {
0612:                return (ParameterBlock) nodeSupport.getParameterBlock().clone();
0613:            }
0614:
0615:            /**
0616:             * Sets the <code>ParameterBlock</code> of this node.
0617:             * If the specified new <code>ParameterBlock</code> is <code>null</code>,
0618:             * it is assumed that this node has no input sources and parameters.
0619:             * The supplied parameter is cloned.
0620:             *
0621:             * <p> This method does not validate the content of the supplied
0622:             * <code>ParameterBlock</code>.  The caller should ensure that
0623:             * the sources and parameters in the <code>ParameterBlock</code>
0624:             * are suitable for the operation this node represents; otherwise
0625:             * some form of error or exception may occur at the time of rendering.
0626:             *
0627:             * <p> If the supplied <code>ParameterBlock</code> does not equal the
0628:             * current <code>ParameterBlock</code>, a
0629:             * <code>PropertyChangeEventJAI</code> named "ParameterBlock", "Sources",
0630:             * or "Parameters" will be fired. A <code>RenderingChangeEvent</code>
0631:             * may also be fired if the node has already been rendered.
0632:             *
0633:             * <p> The <code>ParameterBlock</code> may include
0634:             * <code>DeferredData</code> parameters.  These will not be evaluated
0635:             * until their values are actually required, i.e., when the node is
0636:             * rendered.
0637:             *
0638:             * <p> The node is registered as a sink of any <code>PlanarImage</code>
0639:             * or <code>CollectionImage</code> sources contained in the supplied
0640:             * <code>ParameterBlock</code>.  The node is also removed as a sink of
0641:             * any previous <code>PlanarImage</code> or <code>CollectionImage</code>
0642:             * sources if these are not in the new <code>ParameterBlock</code>.
0643:             *
0644:             * @param pb  The new <code>ParameterBlock</code> to be set;
0645:             *        it may be <code>null</code>.
0646:             */
0647:            public synchronized void setParameterBlock(ParameterBlock pb) {
0648:                Vector nodeSources = nodeSupport.getParameterBlock()
0649:                        .getSources();
0650:                if (nodeSources != null && nodeSources.size() > 0) {
0651:                    Iterator it = nodeSources.iterator();
0652:                    while (it.hasNext()) {
0653:                        Object src = it.next();
0654:                        if (src instanceof  PlanarImage) {
0655:                            ((PlanarImage) src).removeSink(this );
0656:                        } else if (src instanceof  CollectionImage) {
0657:                            ((CollectionImage) src).removeSink(this );
0658:                        }
0659:                    }
0660:                }
0661:
0662:                if (pb != null) {
0663:                    Vector newSources = pb.getSources();
0664:                    ;
0665:                    if (newSources != null && newSources.size() > 0) {
0666:                        Iterator it = newSources.iterator();
0667:                        while (it.hasNext()) {
0668:                            Object src = it.next();
0669:                            if (src instanceof  PlanarImage) {
0670:                                ((PlanarImage) src).addSink(this );
0671:                            } else if (src instanceof  CollectionImage) {
0672:                                ((CollectionImage) src).addSink(this );
0673:                            }
0674:                        }
0675:                    }
0676:                }
0677:
0678:                nodeSupport.setParameterBlock(pb == null ? new ParameterBlock()
0679:                        : (ParameterBlock) pb.clone());
0680:            }
0681:
0682:            /**
0683:             * Returns a clone of the <code>RenderingHints</code> of this node or
0684:             * <code>null</code>.
0685:             */
0686:            public RenderingHints getRenderingHints() {
0687:                RenderingHints hints = nodeSupport.getRenderingHints();
0688:                return hints == null ? null : (RenderingHints) hints.clone();
0689:            }
0690:
0691:            /**
0692:             * Sets the <code>RenderingHints</code> of this node.
0693:             * The supplied parameter is cloned if non-<code>null</code>.
0694:             *
0695:             * <p> If the supplied <code>RenderingHints</code> does not equal the
0696:             * current <code>RenderingHints</code>, a
0697:             * <code>PropertyChangeEventJAI</code> named "RenderingHints"
0698:             * will be fired and a <code>RenderingChangeEvent</code> may be
0699:             * fired if the node has already been rendered.
0700:             *
0701:             * @param hints The new <code>RenderingHints</code> to be set;
0702:             *        it may be <code>null</code>.
0703:             */
0704:            public synchronized void setRenderingHints(RenderingHints hints) {
0705:                if (hints != null) {
0706:                    hints = (RenderingHints) hints.clone();
0707:                }
0708:                nodeSupport.setRenderingHints(hints);
0709:            }
0710:
0711:            /* ----- Rendering generation methods. ----- */
0712:
0713:            /**
0714:             * Instantiate a <code>PlanarImage</code> that computes the result
0715:             * of this <code>RenderedOp</code>.  The local
0716:             * <code>OperationRegistry</code> of this node is used to translate
0717:             * the operation name into a <code>RenderedImageFactory</code> and
0718:             * eventually an actual <code>RenderedImage</code> (usually an
0719:             * <code>OpImage</code>).
0720:             *
0721:             * <p> During this method, all the sources supplied in the
0722:             * <code>ParameterBlock</code> are checked. If any of the sources
0723:             * is a <code>RenderedOp</code>, a rendering of that source is
0724:             * created. This propagates all the way up to the top of the op
0725:             * chain.  If any of the sources is a <code>Collection</code>,
0726:             * then the collection is passed to the operation as-is. If there
0727:             * is a <code>RenderedOp</code> anywhere in the collection, it is
0728:             * up to the individual operation to create the rendering for that
0729:             * <code>RenderedOp</code>.
0730:             *
0731:             * <p> This method does not validate the sources and parameters
0732:             * stored in the <code>ParameterBlock</code> against the specification
0733:             * of the operation this node represents.  It is the responsibility
0734:             * of the caller to ensure that the data in the
0735:             * <code>ParameterBlock</code> are suitable for this operation.
0736:             * Otherwise, some kind of exception or error will occur.
0737:             *
0738:             * <p> Invoking this method will cause any source <code>RenderedOp</code>
0739:             * nodes to be rendered using <code>getRendering()</code> and any
0740:             * source <code>CollectionOp</code> nodes to be rendered using
0741:             * <code>getCollection()</code>.  Any <code>DeferredData</code> parameters
0742:             * in the <code>ParameterBlock</code> will also be evaluated.
0743:             *
0744:             * <p> The <code>RenderedImage</code> generated by the selected
0745:             * <code>RenderedImageFactory</code> will be converted to a
0746:             * <code>PlanarImage</code> by invoking
0747:             * <code>PlanarImage.wrapRenderedImage()</code>.
0748:             *
0749:             * @return The resulting image as a <code>PlanarImage</code>.
0750:             *
0751:             * @throws RuntimeException if the image factory charged with rendering
0752:             *         the node is unable to create a rendering.
0753:             */
0754:            public synchronized PlanarImage createInstance() {
0755:                return createInstance(false);
0756:            }
0757:
0758:            /**
0759:             * This method performs the actions described by the documentation of
0760:             * <code>createInstance()</code> optionally marking the node as rendered
0761:             * according to the parameter.
0762:             *
0763:             * @throws RuntimeException if the image factory charged with rendering
0764:             *         the node is unable to create a rendering.
0765:             *
0766:             * @see #createInstance()
0767:             *
0768:             * @since JAI 1.1
0769:             */
0770:            protected synchronized PlanarImage createInstance(
0771:                    boolean isNodeRendered) {
0772:                ParameterBlock pb = new ParameterBlock();
0773:                Vector parameters = nodeSupport.getParameterBlock()
0774:                        .getParameters();
0775:
0776:                // Evaluate and DeferredData parameters.
0777:                pb.setParameters(ImageUtil.evaluateParameters(parameters));
0778:
0779:                int numSources = getNumSources();
0780:                for (int i = 0; i < numSources; i++) {
0781:                    Object source = getNodeSource(i);
0782:                    Object ai = null;
0783:
0784:                    if (source instanceof  RenderedOp) {
0785:                        RenderedOp src = (RenderedOp) source;
0786:                        ai = isNodeRendered ? src.getRendering() : src
0787:                                .createInstance();
0788:                    } else if (source instanceof  CollectionOp) {
0789:                        ai = ((CollectionOp) source).getCollection();
0790:                    } else if ((source instanceof  RenderedImage)
0791:                            || (source instanceof  Collection)) {
0792:                        // XXX: RenderedImageList - bpb 8 dec 2000
0793:                        // If source is a RenderedImageAdapter which is wrapping a
0794:                        // RenderedImageList whose primary image is a RenderedOp,
0795:                        // set ai to the rendering of that RenderedOp.
0796:                        ai = source;
0797:                    } else {
0798:                        // Source is some other type. Pass on (for now).
0799:                        ai = source;
0800:                    }
0801:                    pb.addSource(ai);
0802:                }
0803:
0804:                // Create the rendering.
0805:                RenderedImage rendering = RIFRegistry.create(getRegistry(),
0806:                        nodeSupport.getOperationName(), pb, nodeSupport
0807:                                .getRenderingHints());
0808:
0809:                // Throw an exception if the rendering is null.
0810:                if (rendering == null) {
0811:                    throw new RuntimeException(JaiI18N.getString("RenderedOp0"));
0812:                }
0813:
0814:                // XXX: RenderedImageList - bpb 8 dec 2000
0815:                // If rendering is a wrapped RenderedImageList whose primary image
0816:                // is a RenderedOp, reset the sources of the primary image
0817:                // to the source List of this node. That is to say, replace
0818:                // the OpImage sources with RenderedOp sources. Also, register
0819:                // this node as a PropertyChangeListener of the primary image.
0820:                // Somehow this node also needs to be able to identify
0821:                // RenderingChangeEvents emitted by the primary image.
0822:                // The invalid region would be extracted from such RCEs and used
0823:                // in creating a new RCE with this node as its source which would
0824:                // be fired as usual to all listeners and sinks.
0825:
0826:                // Ensure that the rendering is a PlanarImage.
0827:                PlanarImage instance = PlanarImage.wrapRenderedImage(rendering);
0828:
0829:                // Save the RenderingHints.
0830:                oldHints = nodeSupport.getRenderingHints() == null ? null
0831:                        : (RenderingHints) nodeSupport.getRenderingHints()
0832:                                .clone();
0833:
0834:                return instance;
0835:            }
0836:
0837:            /**
0838:             * Creates a <code>PlanarImage</code> rendering if none exists
0839:             * and sets <code>theImage</code> to the resulting value.  This method
0840:             * performs the same actions as <code>createInstance()</code> but sets
0841:             * <code>theImage</code> to the result.
0842:             *
0843:             * @throws RuntimeException if the image factory charged with rendering
0844:             *         the node is unable to create a rendering.
0845:             *
0846:             * @see #createInstance()
0847:             *
0848:             * @since JAI 1.1
0849:             */
0850:            protected synchronized void createRendering() {
0851:                if (theImage == null) {
0852:                    setImageLayout(new ImageLayout(
0853:                            theImage = createInstance(true)));
0854:
0855:                    if (theImage != null) {
0856:                        // Get listeners, wrap, and add to OpImage listener list.
0857:                        theImage.addTileComputationListener(new TCL(this ));
0858:                    }
0859:                }
0860:            }
0861:
0862:            /**
0863:             * Returns the <code>PlanarImage</code> rendering associated with this
0864:             * <code>RenderedOp</code> node.  This method performs the same action
0865:             * as <code>createRendering()</code> but returns <code>theImage</code>.
0866:             *
0867:             * @throws RuntimeException if the image factory charged with rendering
0868:             *         the node is unable to create a rendering.
0869:             *
0870:             * @see #createRendering()
0871:             * @see #createInstance()
0872:             */
0873:            public PlanarImage getRendering() {
0874:                createRendering();
0875:                return theImage;
0876:            }
0877:
0878:            /**
0879:             * Returns the value of the protected variable <code>theImage</code>
0880:             * which may be <code>null</code> if no rendering has yet been created.
0881:             * This method does not force the node to be rendered.
0882:             *
0883:             * @since JAI 1.1
0884:             */
0885:            public PlanarImage getCurrentRendering() {
0886:                return theImage;
0887:            }
0888:
0889:            /**
0890:             * Forces the node to be re-rendered and returns the new rendering.
0891:             *
0892:             * <p> If the node has not yet been rendered this method is identical to
0893:             * <code>getRendering()</code>.
0894:             *
0895:             * <p> If the node has already been rendered, then a new rendering will be
0896:             * generated. The synthetic and locally cached properties and the property
0897:             * environment of the node will all be reset.  All registered
0898:             * <code>PropertyChangeListener</code>s and any
0899:             * <code>PropertyChangeListener</code> sinks will be notifed of the
0900:             * change in the rendering via a <code>RenderingChangeEvent</code>
0901:             * the invalid region of which will be <code>null</code>.
0902:             *
0903:             * <p> This method could be used for example to trigger a
0904:             * re-rendering of the node in cases where this would not happen
0905:             * automatically but is desirable to the application.  One
0906:             * example occurs if a parameter of the operation is a referent of
0907:             * some other entity which changes but the parameter itself does not
0908:             * change according to <code>equals()</code>.  This could occur for
0909:             * example for an image file input operation wherein the path to the
0910:             * file remains the same but the content of the file changes.
0911:             *
0912:             * @return The (possibly regenerated) rendering of the node. This value
0913:             * may be ignored if the intent of invoking the method was merely to
0914:             * re-render the node and generate events for
0915:             * <code>RenderingChangeEvent</code> listeners.
0916:             *
0917:             * @since JAI 1.1
0918:             */
0919:            public PlanarImage getNewRendering() {
0920:                if (theImage == null) {
0921:                    return getRendering();
0922:                }
0923:
0924:                // Save the previous rendering.
0925:                PlanarImage theOldImage = theImage;
0926:
0927:                // Clear the current rendering.
0928:                theImage = null;
0929:
0930:                // XXX The rest of this method is effectively duplicated from the
0931:                // end of propertyChange(). Should another method be created to be
0932:                // called in these two places in order to avoid code duplication?
0933:
0934:                // Re-render the node.
0935:                createRendering();
0936:
0937:                // Clear the synthetic and cached properties and reset the
0938:                // property source.
0939:                resetProperties(true);
0940:
0941:                // Create the event object.
0942:                RenderingChangeEvent rcEvent = new RenderingChangeEvent(this ,
0943:                        theOldImage, theImage, null);
0944:
0945:                // Fire to all registered listeners.
0946:                eventManager.firePropertyChange(rcEvent);
0947:
0948:                // Fire an event to all PropertyChangeListener sinks.
0949:                Vector sinks = getSinks();
0950:                if (sinks != null) {
0951:                    int numSinks = sinks.size();
0952:                    for (int i = 0; i < numSinks; i++) {
0953:                        Object sink = sinks.get(i);
0954:                        if (sink instanceof  PropertyChangeListener) {
0955:                            ((PropertyChangeListener) sink)
0956:                                    .propertyChange(rcEvent);
0957:                        }
0958:                    }
0959:                }
0960:
0961:                return theImage;
0962:            }
0963:
0964:            /* ----- PropertyChangeListener method. ----- */
0965:
0966:            /**
0967:             * Implementation of <code>PropertyChangeListener</code>.
0968:             *
0969:             * <p> When invoked with an event which is an instance of
0970:             * <code>RenderingChangeEvent</code> or <code>CollectionChangeEvent</code>
0971:             * emitted by a <code>RenderedOp</code> or <code>CollectionOp</code>,
0972:             * respectively, the node will respond by re-rendering itself while
0973:             * retaining any tiles possible.  It will respond to an "InvalidRegion"
0974:             * event emitted by a source <code>RenderedImage</code> in a manner
0975:             * similar to that applied for <code>RenderingChangeEvent</code>s.
0976:             *
0977:             * @see TiledImage#propertyChange
0978:             *
0979:             * @since JAI 1.1
0980:             */
0981:            public synchronized void propertyChange(PropertyChangeEvent evt) {
0982:                //
0983:                // React if and only if the node has been rendered and
0984:                // A: a non-PropertySourceChangeEvent PropertyChangeEventJAI
0985:                //    was received from this node, or
0986:                // B: a RenderingChangeEvent was received from a source RenderedOp, or
0987:                // C: a CollectionChangeEvent was received from a source CollectionOp, or
0988:                // D: an "InvalidRegion" event was received from a source RenderedImage.
0989:                //
0990:
0991:                // Cache event and node sources.
0992:                Object evtSrc = evt.getSource();
0993:                Vector nodeSources = nodeSupport.getParameterBlock()
0994:                        .getSources();
0995:
0996:                // Get the name of the bean property and convert it to lower
0997:                // case now for efficiency later.
0998:                String propName = evt.getPropertyName().toLowerCase(
0999:                        Locale.ENGLISH);
1000:
1001:                if (theImage != null
1002:                        && ((evt instanceof  PropertyChangeEventJAI
1003:                                && evtSrc == this 
1004:                                && !(evt instanceof  PropertySourceChangeEvent) && nodeEventNames
1005:                                .contains(propName)) || ((evt instanceof  RenderingChangeEvent
1006:                                || evt instanceof  CollectionChangeEvent || (evt instanceof  PropertyChangeEventJAI
1007:                                && evtSrc instanceof  RenderedImage && propName
1008:                                .equals("invalidregion"))) && nodeSources
1009:                                .contains(evtSrc)))) {
1010:
1011:                    // Save the previous rendering.
1012:                    PlanarImage theOldImage = theImage;
1013:
1014:                    // Initialize the event flag.
1015:                    boolean fireEvent = false;
1016:
1017:                    // Set default invalid region to null (the entire image).
1018:                    Shape invalidRegion = null;
1019:
1020:                    if (evtSrc == this 
1021:                            && (propName.equals("operationname") || propName
1022:                                    .equals("operationregistry"))) {
1023:
1024:                        // Operation name or OperationRegistry changed:
1025:                        // invalidate the entire rendering.
1026:                        fireEvent = true;
1027:                        theImage = null;
1028:
1029:                    } else if (evt instanceof  RenderingChangeEvent
1030:                            || (evtSrc instanceof  RenderedImage && propName
1031:                                    .equals("invalidregion"))) {
1032:
1033:                        // Set the event flag.
1034:                        fireEvent = true;
1035:
1036:                        Shape srcInvalidRegion = null;
1037:
1038:                        if (evt instanceof  RenderingChangeEvent) {
1039:                            // RenderingChangeEvent presumably from a source RenderedOp.
1040:                            RenderingChangeEvent rcEvent = (RenderingChangeEvent) evt;
1041:
1042:                            // Get the invalidated region of the source.
1043:                            srcInvalidRegion = rcEvent.getInvalidRegion();
1044:
1045:                            // If entire source is invalid replace with source bounds.
1046:                            if (srcInvalidRegion == null) {
1047:                                srcInvalidRegion = ((PlanarImage) rcEvent
1048:                                        .getOldValue()).getBounds();
1049:                            }
1050:                        } else {
1051:                            // Get the invalidated region of the source.
1052:                            srcInvalidRegion = (Shape) evt.getNewValue();
1053:
1054:                            // If entire source is invalid replace with source bounds.
1055:                            if (srcInvalidRegion == null) {
1056:                                RenderedImage rSrc = (RenderedImage) evtSrc;
1057:                                srcInvalidRegion = new Rectangle(
1058:                                        rSrc.getMinX(), rSrc.getMinY(), rSrc
1059:                                                .getWidth(), rSrc.getHeight());
1060:                            }
1061:                        }
1062:
1063:                        // Only process further if the rendering is an OpImage.
1064:                        if (!(theImage instanceof  OpImage)) {
1065:
1066:                            // Clear the current rendering.
1067:                            theImage = null;
1068:
1069:                        } else {
1070:                            // Save the previous rendering as an OpImage.
1071:                            OpImage oldOpImage = (OpImage) theImage;
1072:
1073:                            // Cache source invalid bounds.
1074:                            Rectangle srcInvalidBounds = srcInvalidRegion
1075:                                    .getBounds();
1076:
1077:                            // If bounds are empty, replace srcInvalidRegion with
1078:                            // the complement of the image bounds within the
1079:                            // bounds of all tiles.
1080:                            if (srcInvalidBounds.isEmpty()) {
1081:                                int x = oldOpImage.tileXToX(oldOpImage
1082:                                        .getMinTileX());
1083:                                int y = oldOpImage.tileYToY(oldOpImage
1084:                                        .getMinTileY());
1085:                                int w = oldOpImage.getNumXTiles()
1086:                                        * oldOpImage.getTileWidth();
1087:                                int h = oldOpImage.getNumYTiles()
1088:                                        * oldOpImage.getTileHeight();
1089:                                Rectangle tileBounds = new Rectangle(x, y, w, h);
1090:                                Rectangle imageBounds = oldOpImage.getBounds();
1091:                                if (!tileBounds.equals(imageBounds)) {
1092:                                    Area tmpArea = new Area(tileBounds);
1093:                                    tmpArea.subtract(new Area(imageBounds));
1094:                                    srcInvalidRegion = tmpArea;
1095:                                    srcInvalidBounds = srcInvalidRegion
1096:                                            .getBounds();
1097:                                }
1098:                            }
1099:
1100:                            // ----- Determine invalid destination region. -----
1101:
1102:                            boolean saveAllTiles = false;
1103:                            ArrayList validTiles = null;
1104:                            if (srcInvalidBounds.isEmpty()) {
1105:                                invalidRegion = srcInvalidRegion;
1106:                                saveAllTiles = true;
1107:                            } else {
1108:                                // Get index of source which changed.
1109:                                int idx = nodeSources.indexOf(evtSrc);
1110:
1111:                                // Determine bounds of invalid destination region.
1112:                                Rectangle dstRegionBounds = oldOpImage
1113:                                        .mapSourceRect(srcInvalidBounds, idx);
1114:
1115:                                if (dstRegionBounds == null) {
1116:                                    dstRegionBounds = oldOpImage.getBounds();
1117:                                }
1118:
1119:                                // Determine invalid destination region.
1120:                                Point[] indices = getTileIndices(dstRegionBounds);
1121:                                int numIndices = indices != null ? indices.length
1122:                                        : 0;
1123:                                GeneralPath gp = null;
1124:
1125:                                for (int i = 0; i < numIndices; i++) {
1126:                                    if (i % 1000 == 0 && gp != null)
1127:                                        gp = new GeneralPath(new Area(gp));
1128:
1129:                                    Rectangle dstRect = getTileRect(
1130:                                            indices[i].x, indices[i].y);
1131:                                    Rectangle srcRect = oldOpImage.mapDestRect(
1132:                                            dstRect, idx);
1133:                                    if (srcRect == null) {
1134:                                        gp = null;
1135:                                        break;
1136:                                    }
1137:                                    if (srcInvalidRegion.intersects(srcRect)) {
1138:                                        if (gp == null) {
1139:                                            gp = new GeneralPath(dstRect);
1140:                                        } else {
1141:                                            gp.append(dstRect, false);
1142:                                        }
1143:                                    } else {
1144:                                        if (validTiles == null) {
1145:                                            validTiles = new ArrayList();
1146:                                        }
1147:                                        validTiles.add(indices[i]);
1148:                                    }
1149:                                }
1150:
1151:                                invalidRegion = (gp == null) ? null : new Area(
1152:                                        gp);
1153:                            }
1154:
1155:                            // Clear the current rendering.
1156:                            theImage = null;
1157:
1158:                            // Retrieve the old TileCache.
1159:                            TileCache oldCache = oldOpImage.getTileCache();
1160:
1161:                            // Only perform further processing if there is a cache
1162:                            // and there are tiles to save.
1163:                            if (oldCache != null
1164:                                    && (saveAllTiles || validTiles != null)) {
1165:                                // Re-render the node.
1166:                                createRendering();
1167:
1168:                                // Only perform further processing if the new
1169:                                // rendering is an OpImage with a non-null TileCache.
1170:                                if (theImage instanceof  OpImage
1171:                                        && ((OpImage) theImage).getTileCache() != null) {
1172:                                    OpImage newOpImage = (OpImage) theImage;
1173:                                    TileCache newCache = newOpImage
1174:                                            .getTileCache();
1175:                                    Object tileCacheMetric = newOpImage
1176:                                            .getTileCacheMetric();
1177:
1178:                                    if (saveAllTiles) {
1179:                                        Raster[] tiles = oldCache
1180:                                                .getTiles(oldOpImage);
1181:                                        int numTiles = tiles == null ? 0
1182:                                                : tiles.length;
1183:                                        for (int i = 0; i < numTiles; i++) {
1184:                                            Raster tile = tiles[i];
1185:                                            int tx = newOpImage.XToTileX(tile
1186:                                                    .getMinX());
1187:                                            int ty = newOpImage.YToTileY(tile
1188:                                                    .getMinY());
1189:                                            newCache.add(newOpImage, tx, ty,
1190:                                                    tile, tileCacheMetric);
1191:                                        }
1192:                                    } else { // save some, but not all, tiles
1193:                                        int numValidTiles = validTiles.size();
1194:                                        for (int i = 0; i < numValidTiles; i++) {
1195:                                            Point tileIndex = (Point) validTiles
1196:                                                    .get(i);
1197:                                            Raster tile = oldCache.getTile(
1198:                                                    oldOpImage, tileIndex.x,
1199:                                                    tileIndex.y);
1200:                                            if (tile != null) {
1201:                                                newCache.add(newOpImage,
1202:                                                        tileIndex.x,
1203:                                                        tileIndex.y, tile,
1204:                                                        tileCacheMetric);
1205:                                            }
1206:                                        }
1207:                                    }
1208:                                }
1209:                            }
1210:                        }
1211:                    } else { // not op name or registry change nor RenderingChangeEvent
1212:                        ParameterBlock oldPB = null;
1213:                        ParameterBlock newPB = null;
1214:
1215:                        boolean checkInvalidRegion = false;
1216:                        if (propName.equals("parameterblock")) {
1217:                            oldPB = (ParameterBlock) evt.getOldValue();
1218:                            newPB = (ParameterBlock) evt.getNewValue();
1219:                            checkInvalidRegion = true;
1220:                        } else if (propName.equals("sources")) {
1221:                            // Replace source(s)
1222:                            Vector params = nodeSupport.getParameterBlock()
1223:                                    .getParameters();
1224:                            oldPB = new ParameterBlock((Vector) evt
1225:                                    .getOldValue(), params);
1226:                            newPB = new ParameterBlock((Vector) evt
1227:                                    .getNewValue(), params);
1228:                            checkInvalidRegion = true;
1229:                        } else if (propName.equals("parameters")) {
1230:                            // Replace parameter(s)
1231:                            oldPB = new ParameterBlock(nodeSources,
1232:                                    (Vector) evt.getOldValue());
1233:                            newPB = new ParameterBlock(nodeSources,
1234:                                    (Vector) evt.getNewValue());
1235:                            checkInvalidRegion = true;
1236:                        } else if (propName.equals("renderinghints")) {
1237:                            oldPB = newPB = nodeSupport.getParameterBlock();
1238:                            checkInvalidRegion = true;
1239:                        } else if (evt instanceof  CollectionChangeEvent) {
1240:                            // Event from a CollectionOp source.
1241:
1242:                            // Replace appropriate source.
1243:                            int collectionIndex = nodeSources.indexOf(evtSrc);
1244:                            Vector oldSources = (Vector) nodeSources.clone();
1245:                            Vector newSources = (Vector) nodeSources.clone();
1246:                            oldSources.set(collectionIndex, evt.getOldValue());
1247:                            newSources.set(collectionIndex, evt.getNewValue());
1248:
1249:                            Vector params = nodeSupport.getParameterBlock()
1250:                                    .getParameters();
1251:
1252:                            oldPB = new ParameterBlock(oldSources, params);
1253:                            newPB = new ParameterBlock(newSources, params);
1254:
1255:                            checkInvalidRegion = true;
1256:                        }
1257:
1258:                        if (checkInvalidRegion) {
1259:                            // Set event flag.
1260:                            fireEvent = true;
1261:
1262:                            // Get the associated OperationDescriptor.
1263:                            OperationRegistry registry = nodeSupport
1264:                                    .getRegistry();
1265:                            OperationDescriptor odesc = (OperationDescriptor) registry
1266:                                    .getDescriptor(OperationDescriptor.class,
1267:                                            nodeSupport.getOperationName());
1268:
1269:                            // Evaluate any DeferredData parameters.
1270:                            oldPB = ImageUtil.evaluateParameters(oldPB);
1271:                            newPB = ImageUtil.evaluateParameters(newPB);
1272:
1273:                            // Determine the invalid region.
1274:                            invalidRegion = (Shape) odesc.getInvalidRegion(
1275:                                    RenderedRegistryMode.MODE_NAME, oldPB,
1276:                                    oldHints, newPB, nodeSupport
1277:                                            .getRenderingHints(), this );
1278:
1279:                            if (invalidRegion == null
1280:                                    || !(theImage instanceof  OpImage)) {
1281:
1282:                                // Can't save any tiles; clear the rendering.
1283:                                theImage = null;
1284:
1285:                            } else {
1286:                                // Create a new rendering.
1287:                                OpImage oldRendering = (OpImage) theImage;
1288:                                theImage = null;
1289:                                createRendering();
1290:
1291:                                // If the new rendering is also an OpImage,
1292:                                // save some tiles.
1293:                                if (theImage instanceof  OpImage
1294:                                        && oldRendering.getTileCache() != null
1295:                                        && ((OpImage) theImage).getTileCache() != null) {
1296:                                    OpImage newRendering = (OpImage) theImage;
1297:
1298:                                    // Save some values.
1299:                                    TileCache oldCache = oldRendering
1300:                                            .getTileCache();
1301:                                    TileCache newCache = newRendering
1302:                                            .getTileCache();
1303:                                    Object tileCacheMetric = newRendering
1304:                                            .getTileCacheMetric();
1305:
1306:                                    // If bounds are empty, replace invalidRegion with
1307:                                    // the complement of the image bounds within the
1308:                                    // bounds of all tiles.
1309:                                    if (invalidRegion.getBounds().isEmpty()) {
1310:                                        int x = oldRendering
1311:                                                .tileXToX(oldRendering
1312:                                                        .getMinTileX());
1313:                                        int y = oldRendering
1314:                                                .tileYToY(oldRendering
1315:                                                        .getMinTileY());
1316:                                        int w = oldRendering.getNumXTiles()
1317:                                                * oldRendering.getTileWidth();
1318:                                        int h = oldRendering.getNumYTiles()
1319:                                                * oldRendering.getTileHeight();
1320:                                        Rectangle tileBounds = new Rectangle(x,
1321:                                                y, w, h);
1322:                                        Rectangle imageBounds = oldRendering
1323:                                                .getBounds();
1324:                                        if (!tileBounds.equals(imageBounds)) {
1325:                                            Area tmpArea = new Area(tileBounds);
1326:                                            tmpArea.subtract(new Area(
1327:                                                    imageBounds));
1328:                                            invalidRegion = tmpArea;
1329:                                        }
1330:                                    }
1331:
1332:                                    if (invalidRegion.getBounds().isEmpty()) {
1333:                                        // Save all tiles.
1334:                                        Raster[] tiles = oldCache
1335:                                                .getTiles(oldRendering);
1336:                                        int numTiles = tiles == null ? 0
1337:                                                : tiles.length;
1338:                                        for (int i = 0; i < numTiles; i++) {
1339:                                            Raster tile = tiles[i];
1340:                                            int tx = newRendering.XToTileX(tile
1341:                                                    .getMinX());
1342:                                            int ty = newRendering.YToTileY(tile
1343:                                                    .getMinY());
1344:                                            newCache.add(newRendering, tx, ty,
1345:                                                    tile, tileCacheMetric);
1346:                                        }
1347:                                    } else {
1348:                                        // Copy tiles not in invalid region from old
1349:                                        // TileCache to new TileCache.
1350:                                        Raster[] tiles = oldCache
1351:                                                .getTiles(oldRendering);
1352:                                        int numTiles = tiles == null ? 0
1353:                                                : tiles.length;
1354:                                        for (int i = 0; i < numTiles; i++) {
1355:                                            Raster tile = tiles[i];
1356:                                            Rectangle bounds = tile.getBounds();
1357:                                            if (!invalidRegion
1358:                                                    .intersects(bounds)) {
1359:                                                newCache
1360:                                                        .add(
1361:                                                                newRendering,
1362:                                                                newRendering
1363:                                                                        .XToTileX(bounds.x),
1364:                                                                newRendering
1365:                                                                        .YToTileY(bounds.y),
1366:                                                                tile,
1367:                                                                tileCacheMetric);
1368:                                            }
1369:                                        }
1370:                                    }
1371:                                }
1372:                            }
1373:                        }
1374:                    }
1375:
1376:                    // Re-render the node. This will only occur if theImage
1377:                    // has been set to null above.
1378:                    createRendering();
1379:
1380:                    // Fire an event if the flag was set.
1381:                    if (fireEvent) {
1382:                        // Clear the synthetic and cached properties and reset the
1383:                        // property source.
1384:                        resetProperties(true);
1385:
1386:                        // Create the event object.
1387:                        RenderingChangeEvent rcEvent = new RenderingChangeEvent(
1388:                                this , theOldImage, theImage, invalidRegion);
1389:
1390:                        // Fire to all registered listeners.
1391:                        eventManager.firePropertyChange(rcEvent);
1392:
1393:                        // Fire an event to all PropertyChangeListener sinks.
1394:                        Vector sinks = getSinks();
1395:                        if (sinks != null) {
1396:                            int numSinks = sinks.size();
1397:                            for (int i = 0; i < numSinks; i++) {
1398:                                Object sink = sinks.get(i);
1399:                                if (sink instanceof  PropertyChangeListener) {
1400:                                    ((PropertyChangeListener) sink)
1401:                                            .propertyChange(rcEvent);
1402:                                }
1403:                            }
1404:                        }
1405:                    }
1406:                }
1407:            }
1408:
1409:            /* ----- Node source methods: interact with ParameterBlock sources ----- */
1410:
1411:            /**
1412:             * Adds a source to the <code>ParameterBlock</code> of this node.
1413:             * This is a convenience method that invokes
1414:             * <code>setParameterBlock()</code> and so adheres to the same event
1415:             * firing behavior.
1416:             *
1417:             * @param source The source to be added to the
1418:             *        <code>ParameterBlock</code>
1419:             * @deprecated as of JAI 1.1 Use <code>addSource(Object)</code>.
1420:             */
1421:            public synchronized void addNodeSource(Object source) {
1422:                addSource(source);
1423:            }
1424:
1425:            /**
1426:             * Sets the specified source stored in the <code>ParameterBlock</code>
1427:             * of this node to a new source object.
1428:             * This is a convenience method that invokes
1429:             * <code>setParameterBlock()</code> and so adheres to the same event
1430:             * firing behavior.
1431:             *
1432:             * @param source The Source to be set.
1433:             * @param index  The Index at which it is to be set.
1434:             *
1435:             * @throws IllegalArgumentException if
1436:             *         <code>source</code> is <code>null</code>.
1437:             * @throws ArrayIndexOutOfBoundsException if
1438:             *         <code>index</code> is invalid.
1439:             * @deprecated as of JAI 1.1 Use <code>setSource(Object,int)</code>.
1440:             */
1441:            public synchronized void setNodeSource(Object source, int index) {
1442:                setSource(source, index);
1443:            }
1444:
1445:            /**
1446:             * Returns the specified source stored in the
1447:             * <code>ParameterBlock</code> of this node.
1448:             * If there is no source corresponding to the specified index, an
1449:             * <code>ArrayIndexOutOfBoundsException</code> will be thrown.
1450:             *
1451:             * @param index  The index of the source.
1452:             * @deprecated as of JAI 1.1 Use <code>getSourceObject(int)</code>.
1453:             */
1454:            public synchronized Object getNodeSource(int index) {
1455:                return nodeSupport.getParameterBlock().getSource(index);
1456:            }
1457:
1458:            /* ----- Parameter methods: interact with ParameterBlock params ----- */
1459:
1460:            /**
1461:             * Returns the number of parameters stored in the
1462:             * <code>ParameterBlock</code> of this node.
1463:             */
1464:            public synchronized int getNumParameters() {
1465:                return nodeSupport.getParameterBlock().getNumParameters();
1466:            }
1467:
1468:            /**
1469:             * Returns a clone of the <code>Vector</code> of parameters stored in the
1470:             * <code>ParameterBlock</code> of this node.
1471:             */
1472:            public synchronized Vector getParameters() {
1473:                // In the Sun JDK ParameterBlock the parameter Vector is never null.
1474:                Vector params = nodeSupport.getParameterBlock().getParameters();
1475:                return params == null ? null : (Vector) params.clone();
1476:            }
1477:
1478:            /**
1479:             * Returns the specified parameter stored in the
1480:             * <code>ParameterBlock</code> of this node as a <code>byte</code>.
1481:             * An <code>ArrayIndexOutOfBoundsException</code> may occur if an
1482:             * invalid index is supplied
1483:             *
1484:             * @param index  The index of the parameter.
1485:             *
1486:             * @throws ArrayIndexOutOfBoundsException if
1487:             * <code>index</code> is invalid.
1488:             */
1489:            public synchronized byte getByteParameter(int index) {
1490:                return nodeSupport.getParameterBlock().getByteParameter(index);
1491:            }
1492:
1493:            /**
1494:             * Returns the specified parameter stored in the
1495:             * <code>ParameterBlock</code> of this node as a <code>char</code>.
1496:             * An <code>ArrayIndexOutOfBoundsException</code> may occur if an
1497:             * invalid index is supplied
1498:             *
1499:             * @param index  The index of the parameter.
1500:             *
1501:             * @throws ArrayIndexOutOfBoundsException if
1502:             * <code>index</code> is invalid.
1503:             */
1504:            public synchronized char getCharParameter(int index) {
1505:                return nodeSupport.getParameterBlock().getCharParameter(index);
1506:            }
1507:
1508:            /**
1509:             * Returns the specified parameter stored in the
1510:             * <code>ParameterBlock</code> of this node as a <code>short</code>.
1511:             * An <code>ArrayIndexOutOfBoundsException</code> may occur if an
1512:             * invalid index is supplied
1513:             *
1514:             * @param index  The index of the parameter.
1515:             *
1516:             * @throws ArrayIndexOutOfBoundsException if
1517:             * <code>index</code> is invalid.
1518:             */
1519:            public synchronized short getShortParameter(int index) {
1520:                return nodeSupport.getParameterBlock().getShortParameter(index);
1521:            }
1522:
1523:            /**
1524:             * Returns the specified parameter stored in the
1525:             * <code>ParameterBlock</code> of this node as an <code>int</code>.
1526:             * An <code>ArrayIndexOutOfBoundsException</code> may occur if an
1527:             * invalid index is supplied
1528:             *
1529:             * @param index  The index of the parameter.
1530:             *
1531:             * @throws ArrayIndexOutOfBoundsException if
1532:             * <code>index</code> is invalid.
1533:             */
1534:            public synchronized int getIntParameter(int index) {
1535:                return nodeSupport.getParameterBlock().getIntParameter(index);
1536:
1537:            }
1538:
1539:            /**
1540:             * Returns the specified parameter stored in the
1541:             * <code>ParameterBlock</code> of this node as a <code>long</code>.
1542:             * An <code>ArrayIndexOutOfBoundsException</code> may occur if an
1543:             * invalid index is supplied
1544:             *
1545:             * @param index  The index of the parameter.
1546:             *
1547:             * @throws ArrayIndexOutOfBoundsException if
1548:             * <code>index</code> is invalid.
1549:             */
1550:            public synchronized long getLongParameter(int index) {
1551:                return nodeSupport.getParameterBlock().getLongParameter(index);
1552:            }
1553:
1554:            /**
1555:             * Returns the specified parameter stored in the
1556:             * <code>ParameterBlock</code> of this node as a <code>float</code>.
1557:             * An <code>ArrayIndexOutOfBoundsException</code> may occur if an
1558:             * invalid index is supplied
1559:             *
1560:             * @param index  The index of the parameter.
1561:             *
1562:             * @throws ArrayIndexOutOfBoundsException if
1563:             * <code>index</code> is invalid.
1564:             */
1565:            public synchronized float getFloatParameter(int index) {
1566:                return nodeSupport.getParameterBlock().getFloatParameter(index);
1567:            }
1568:
1569:            /**
1570:             * Returns the specified parameter stored in the
1571:             * <code>ParameterBlock</code> of this node as a <code>double</code>.
1572:             * An <code>ArrayIndexOutOfBoundsException</code> may occur if an
1573:             * invalid index is supplied
1574:             *
1575:             * @param index  The index of the parameter.
1576:             *
1577:             * @throws ArrayIndexOutOfBoundsException if
1578:             * <code>index</code> is invalid.
1579:             */
1580:            public synchronized double getDoubleParameter(int index) {
1581:                return nodeSupport.getParameterBlock()
1582:                        .getDoubleParameter(index);
1583:            }
1584:
1585:            /**
1586:             * Returns the specified parameter stored in the
1587:             * <code>ParameterBlock</code> of this node as an <code>Object</code>.
1588:             * An <code>ArrayIndexOutOfBoundsException</code> may occur if an
1589:             * invalid index is supplied
1590:             *
1591:             * @param index  The index of the parameter.
1592:             *
1593:             * @throws ArrayIndexOutOfBoundsException if
1594:             * <code>index</code> is invalid.
1595:             */
1596:            public synchronized Object getObjectParameter(int index) {
1597:                return nodeSupport.getParameterBlock()
1598:                        .getObjectParameter(index);
1599:            }
1600:
1601:            /**
1602:             * Sets all the parameters of this node.
1603:             * This is a convenience method that invokes
1604:             * <code>setParameterBlock()</code> and so adheres to the same event
1605:             * firing behavior.
1606:             *
1607:             * <p> The <code>Vector</code> may include
1608:             * <code>DeferredData</code> parameters.  These will not be evaluated
1609:             * until their values are actually required, i.e., when the node is
1610:             * rendered.
1611:             *
1612:             * @since JAI 1.1
1613:             */
1614:            public synchronized void setParameters(Vector parameters) {
1615:                ParameterBlock pb = (ParameterBlock) nodeSupport
1616:                        .getParameterBlock().clone();
1617:                pb.setParameters(parameters);
1618:                nodeSupport.setParameterBlock(pb);
1619:            }
1620:
1621:            /**
1622:             * Sets one of the node's parameters to a <code>byte</code>.
1623:             * If the <code>index</code> lies beyond the current source list,
1624:             * the list is extended with nulls as needed.
1625:             * This is a convenience method that invokes
1626:             * <code>setParameter(Object,int)</code> and so adheres to the same event
1627:             * firing behavior.
1628:             *
1629:             * @param param The parameter, as a <code>byte</code>.
1630:             * @param index The index of the parameter.
1631:             */
1632:            public synchronized void setParameter(byte param, int index) {
1633:                setParameter(new Byte(param), index);
1634:            }
1635:
1636:            /**
1637:             * Sets one of the node's parameters to a <code>char</code>.
1638:             * If the <code>index</code> lies beyond the current source list,
1639:             * the list is extended with nulls as needed.
1640:             * This is a convenience method that invokes
1641:             * <code>setParameter(Object,int)</code> and so adheres to the same event
1642:             * firing behavior.
1643:             *
1644:             * @param param The parameter, as a <code>char</code>.
1645:             * @param index The index of the parameter.
1646:             */
1647:            public synchronized void setParameter(char param, int index) {
1648:                setParameter(new Character(param), index);
1649:            }
1650:
1651:            /**
1652:             * Sets one of the node's parameters to a <code>short</code>.
1653:             * If the <code>index</code> lies beyond the current source list,
1654:             * the list is extended with nulls as needed.
1655:             *
1656:             * @param param The parameter, as a <code>short</code>.
1657:             * @param index The index of the parameter.
1658:             */
1659:            public synchronized void setParameter(short param, int index) {
1660:                setParameter(new Short(param), index);
1661:            }
1662:
1663:            /**
1664:             * Sets one of the node's parameters to an <code>in</code>t.
1665:             * If the <code>index</code> lies beyond the current source list,
1666:             * the list is extended with nulls as needed.
1667:             *
1668:             * @param param The parameter, as an <code>int</code>.
1669:             * @param index The index of the parameter.
1670:             */
1671:            public synchronized void setParameter(int param, int index) {
1672:                setParameter(new Integer(param), index);
1673:            }
1674:
1675:            /**
1676:             * Sets one of the node's parameters to a <code>long</code>.
1677:             * If the <code>index</code> lies beyond the current source list,
1678:             * the list is extended with nulls as needed.
1679:             *
1680:             * @param param The parameter, as a <code>long</code>.
1681:             * @param index The index of the parameter.
1682:             */
1683:            public synchronized void setParameter(long param, int index) {
1684:                setParameter(new Long(param), index);
1685:            }
1686:
1687:            /**
1688:             * Sets one of the node's parameters to a <code>float</code>.
1689:             * If the <code>index</code> lies beyond the current source list,
1690:             * the list is extended with nulls as needed.
1691:             *
1692:             * @param param The parameter, as a <code>float</code>.
1693:             * @param index The index of the parameter.
1694:             */
1695:            public synchronized void setParameter(float param, int index) {
1696:                setParameter(new Float(param), index);
1697:            }
1698:
1699:            /**
1700:             * Sets one of the node's parameters to a <code>double</code>.
1701:             * If the <code>index</code> lies beyond the current source list,
1702:             * the list is extended with nulls as needed.
1703:             *
1704:             * @param param The parameter, as a <code>double</code>.
1705:             * @param index The index of the parameter.
1706:             */
1707:            public synchronized void setParameter(double param, int index) {
1708:                setParameter(new Double(param), index);
1709:            }
1710:
1711:            /**
1712:             * Sets one of the node's parameters to an <code>Object</code>.
1713:             * If the <code>index</code> lies beyond the current source list,
1714:             * the list is extended with nulls as needed.
1715:             * This is a convenience method that invokes
1716:             * <code>setParameterBlock()</code> and so adheres to the same event
1717:             * firing behavior.
1718:             *
1719:             * <p> The <code>Object</code> may be a
1720:             * <code>DeferredData</code> instance.  It will not be evaluated
1721:             * until its value is actually required, i.e., when the node is
1722:             * rendered.
1723:             *
1724:             * @param param The parameter, as an <code>Object</code>.
1725:             * @param index The index of the parameter.
1726:             */
1727:            public synchronized void setParameter(Object param, int index) {
1728:                ParameterBlock pb = (ParameterBlock) nodeSupport
1729:                        .getParameterBlock().clone();
1730:                pb.set(param, index);
1731:                nodeSupport.setParameterBlock(pb);
1732:            }
1733:
1734:            /* ----- RenderingHints methods. ----- */
1735:
1736:            /**
1737:             * Sets a hint in the <code>RenderingHints</code> of this node.  This
1738:             * is a convenience method which calls <code>setRenderingHints()</code>
1739:             * and so adheres to the same event firing behavior.
1740:             *
1741:             * @throws IllegalArgumentException
1742:             *         if the key or value is <code>null</code>.
1743:             * @throws IllegalArgumentException
1744:             *         value is not appropriate for the specified key.
1745:             *
1746:             * @since JAI 1.1
1747:             */
1748:            public synchronized void setRenderingHint(RenderingHints.Key key,
1749:                    Object value) {
1750:
1751:                if (key == null || value == null) {
1752:                    throw new IllegalArgumentException(JaiI18N
1753:                            .getString("Generic0"));
1754:                }
1755:
1756:                RenderingHints rh = nodeSupport.getRenderingHints();
1757:                if (rh == null) {
1758:                    nodeSupport
1759:                            .setRenderingHints(new RenderingHints(key, value));
1760:                } else {
1761:                    rh.put(key, value);
1762:                    nodeSupport.setRenderingHints(rh);
1763:                }
1764:            }
1765:
1766:            /**
1767:             * Gets a hint from the <code>RenderingHints</code> of this node.
1768:             *
1769:             * @return the value associated with the specified key or
1770:             *         <code>null</code> if the key is not mapped to any value.
1771:             *
1772:             * @since JAI 1.1
1773:             */
1774:            public synchronized Object getRenderingHint(RenderingHints.Key key) {
1775:                RenderingHints rh = nodeSupport.getRenderingHints();
1776:                return rh == null ? null : rh.get(key);
1777:            }
1778:
1779:            /* ----- Property-related methods. ----- */
1780:
1781:            /** Creates a <code>PropertySource</code> if none exists. */
1782:            private synchronized void createPropertySource() {
1783:                if (thePropertySource == null) {
1784:                    // Create a <code>PropertySource</code> wrapper of the rendering.
1785:                    PropertySource defaultPS = new PropertySource() {
1786:                        /**
1787:                         * Retrieve the names from an instance of the node.
1788:                         */
1789:                        public String[] getPropertyNames() {
1790:                            return getRendering().getPropertyNames();
1791:                        }
1792:
1793:                        public String[] getPropertyNames(String prefix) {
1794:                            return PropertyUtil.getPropertyNames(
1795:                                    getPropertyNames(), prefix);
1796:                        }
1797:
1798:                        public Class getPropertyClass(String name) {
1799:                            return null;
1800:                        }
1801:
1802:                        /**
1803:                         * Retrieve the actual property values from a rendering
1804:                         * of the node.
1805:                         */
1806:                        public Object getProperty(String name) {
1807:                            return getRendering().getProperty(name);
1808:                        }
1809:                    };
1810:
1811:                    // Create a <code>PropertySource</code> encapsulating the
1812:                    // property environment of the node.
1813:                    thePropertySource = nodeSupport.getPropertySource(this ,
1814:                            defaultPS);
1815:
1816:                    // Add the <code>PropertySource</code> to the helper object.
1817:                    properties.addProperties(thePropertySource);
1818:                }
1819:            }
1820:
1821:            /**
1822:             * Resets the <code>PropertySource</code>.  If the parameter is
1823:             * <code>true</code> then the property environment is completely
1824:             * reset; if <code>false</code> then only cached properties are
1825:             * cleared, i.e., those which were derived from the property
1826:             * environment and are now stored in the local cache.
1827:             *
1828:             * @since JAI 1.1
1829:             */
1830:            protected synchronized void resetProperties(
1831:                    boolean resetPropertySource) {
1832:                properties.clearCachedProperties();
1833:                if (resetPropertySource && thePropertySource != null) {
1834:                    synthProperties = null;
1835:                    properties.removePropertySource(thePropertySource);
1836:                    thePropertySource = null;
1837:                }
1838:            }
1839:
1840:            /**
1841:             * Returns the names of properties available from this node.
1842:             * These properties are a combination of those derived
1843:             * from prior nodes in the imaging chain, those set locally,
1844:             * and a number of locally derived, immutable properties
1845:             * based on the rendering associated with this node --
1846:             * height, width, and so forth.
1847:             *
1848:             * @return An array of <code>String</code>s containing valid
1849:             *         property names.
1850:             */
1851:            public synchronized String[] getPropertyNames() {
1852:                createPropertySource();
1853:
1854:                // Initialize names to synthetic property names.
1855:                Vector names = new Vector(synthProps);
1856:
1857:                // Create a dummy key for later use.
1858:                CaselessStringKey key = new CaselessStringKey("");
1859:
1860:                // Get property names managed by WritablePropertySourceImpl.
1861:                // This includes those of thePropertySource.
1862:                String[] localNames = properties.getPropertyNames();
1863:                if (localNames != null) {
1864:                    int length = localNames.length;
1865:                    for (int i = 0; i < length; i++) {
1866:                        key.setName(localNames[i]);
1867:
1868:                        // Check for duplicates being inserted
1869:                        if (!names.contains(key)) {
1870:                            names.add(key.clone());
1871:                        }
1872:                    }
1873:                }
1874:
1875:                // Return an array.
1876:                String[] propertyNames = null;
1877:                int numNames = names.size();
1878:                if (numNames > 0) {
1879:                    propertyNames = new String[numNames];
1880:                    for (int i = 0; i < numNames; i++) {
1881:                        propertyNames[i] = ((CaselessStringKey) names.get(i))
1882:                                .getName();
1883:                    }
1884:                }
1885:
1886:                return propertyNames;
1887:            }
1888:
1889:            /**
1890:             * Returns the class expected to be returned by a request for
1891:             * the property with the specified name.  If this information
1892:             * is unavailable, <code>null</code> will be returned.
1893:             *
1894:             * @exception IllegalArgumentException if <code>name</code>
1895:             *                                     is <code>null</code>.
1896:             *
1897:             * @return The <code>Class</code> expected to be return by a
1898:             *         request for the value of this property or <code>null</code>.
1899:             *
1900:             * @since JAI 1.1
1901:             */
1902:            public Class getPropertyClass(String name) {
1903:                createPropertySource();
1904:                return properties.getPropertyClass(name);
1905:            }
1906:
1907:            /** Initialize the synthProperties Hashtable if needed. */
1908:            private synchronized void createSynthProperties() {
1909:                if (synthProperties == null) {
1910:                    synthProperties = new Hashtable();
1911:                    synthProperties.put(new CaselessStringKey("image_width"),
1912:                            new Integer(theImage.getWidth()));
1913:                    synthProperties.put(new CaselessStringKey("image_height"),
1914:                            new Integer(theImage.getHeight()));
1915:                    synthProperties.put(new CaselessStringKey(
1916:                            "image_min_x_coord"), new Integer(theImage
1917:                            .getMinX()));
1918:                    synthProperties.put(new CaselessStringKey(
1919:                            "image_min_y_coord"), new Integer(theImage
1920:                            .getMinY()));
1921:
1922:                    if (theImage instanceof  OpImage) {
1923:                        synthProperties.put(new CaselessStringKey(
1924:                                "tile_cache_key"), theImage);
1925:                        Object tileCache = ((OpImage) theImage).getTileCache();
1926:                        synthProperties
1927:                                .put(
1928:                                        new CaselessStringKey("tile_cache"),
1929:                                        tileCache == null ? java.awt.Image.UndefinedProperty
1930:                                                : tileCache);
1931:                    } else if (theImage instanceof  PlanarImageServerProxy) {
1932:                        synthProperties.put(new CaselessStringKey(
1933:                                "tile_cache_key"), theImage);
1934:                        Object tileCache = ((PlanarImageServerProxy) theImage)
1935:                                .getTileCache();
1936:                        synthProperties
1937:                                .put(
1938:                                        new CaselessStringKey("tile_cache"),
1939:                                        tileCache == null ? java.awt.Image.UndefinedProperty
1940:                                                : tileCache);
1941:                    } else {
1942:                        Object tileCacheKey = theImage
1943:                                .getProperty("tile_cache_key");
1944:                        synthProperties
1945:                                .put(
1946:                                        new CaselessStringKey("tile_cache_key"),
1947:                                        tileCacheKey == null ? java.awt.Image.UndefinedProperty
1948:                                                : tileCacheKey);
1949:                        Object tileCache = theImage.getProperty("tile_cache");
1950:                        synthProperties
1951:                                .put(
1952:                                        new CaselessStringKey("tile_cache"),
1953:                                        tileCache == null ? java.awt.Image.UndefinedProperty
1954:                                                : tileCache);
1955:                    }
1956:                }
1957:            }
1958:
1959:            /**
1960:             * Returns the property associated with the specified property name,
1961:             * or <code>java.awt.Image.UndefinedProperty</code> if the specified
1962:             * property is not set on the image.  If <code>name</code> equals the
1963:             * name of any synthetic property, i.e., <code>image_width</code>,
1964:             * <code>image_height</code>, <code>image_min_x_coord</code>, or
1965:             * <code>image_min_y_coord</code>, then the node will be rendered.
1966:             *
1967:             * @param name A <code>String</code> naming the property.
1968:             *
1969:             * @throws IllegalArgumentException if
1970:             *         <code>name</code> is <code>null</code>.
1971:             */
1972:            public synchronized Object getProperty(String name) {
1973:
1974:                if (name == null)
1975:                    throw new IllegalArgumentException(JaiI18N
1976:                            .getString("Generic0"));
1977:
1978:                createPropertySource();
1979:                CaselessStringKey key = new CaselessStringKey(name);
1980:
1981:                // Attempt to retrieve from synthetic properties.
1982:                // If present, return the value directly.
1983:                if (synthProps.contains(key)) {
1984:                    createRendering();
1985:
1986:                    // Create synthProperties Hashtable "just in time."
1987:                    createSynthProperties();
1988:                    return synthProperties.get(key);
1989:                }
1990:
1991:                // Attempt to retrieve from local properties.
1992:                Object value = properties.getProperty(name);
1993:
1994:                // If still undefined, query the property environment.
1995:                if (value == java.awt.Image.UndefinedProperty) {
1996:                    value = thePropertySource.getProperty(name);
1997:                }
1998:
1999:                // Special case handling of ROI property: clip to destination bounds.
2000:                // XXX Do we really want to do this (clip ROI to dest bounds)?
2001:                if (value != java.awt.Image.UndefinedProperty
2002:                        && name.equalsIgnoreCase("roi") && value instanceof  ROI) {
2003:                    ROI roi = (ROI) value;
2004:                    Rectangle imageBounds = getBounds();
2005:                    if (!imageBounds.contains(roi.getBounds())) {
2006:                        value = roi.intersect(new ROIShape(imageBounds));
2007:                    }
2008:                }
2009:
2010:                return value;
2011:            }
2012:
2013:            /**
2014:             * Sets a local property on a node.  The synthetic properties
2015:             * (containing image width, height, and location) may not be set.
2016:             * Local property settings override properties derived from prior
2017:             * nodes in the imaging chain.
2018:             *
2019:             * <p> If the node is serialized then serializable properties will
2020:             * also be serialized but non-serializable properties will be lost.
2021:             *
2022:             * @param name A <code>String</code> representing the property name.
2023:             * @param value The property's value, as an <code>Object</code>.
2024:             *
2025:             * @throws IllegalArgumentException if
2026:             * <code>name</code> is <code>null</code>.
2027:             * @throws IllegalArgumentException if
2028:             * <code>value</code> is <code>null</code>.
2029:             * @throws RuntimeException if <code>name</code>
2030:             * conflicts with Synthetic property.
2031:             */
2032:            public synchronized void setProperty(String name, Object value) {
2033:                if (name == null)
2034:                    throw new IllegalArgumentException(JaiI18N
2035:                            .getString("Generic0"));
2036:                if (value == null)
2037:                    throw new IllegalArgumentException(JaiI18N
2038:                            .getString("Generic0"));
2039:
2040:                // Check whether property conflicts with synthetic properties.
2041:                if (synthProps.contains(new CaselessStringKey(name))) {
2042:                    throw new RuntimeException(JaiI18N.getString("RenderedOp4"));
2043:                }
2044:
2045:                createPropertySource();
2046:                super .setProperty(name, value);
2047:            }
2048:
2049:            /**
2050:             * Removes the named property from the local property
2051:             * set of the <code>RenderedOp</code> as well as from its property
2052:             * environment.  The synthetic properties
2053:             * (containing image width, height, and position) may not be removed.
2054:             *
2055:             * @exception IllegalArgumentException if <code>name</code>
2056:             *                                     is <code>null</code>.
2057:             * @throws RuntimeException if <code>name</code>
2058:             * conflicts with Synthetic property.
2059:             *
2060:             * @since JAI 1.1
2061:             */
2062:            public void removeProperty(String name) {
2063:                if (name == null)
2064:                    throw new IllegalArgumentException(JaiI18N
2065:                            .getString("Generic0"));
2066:
2067:                // Check whether property conflicts with synthetic properties.
2068:                if (synthProps.contains(new CaselessStringKey(name))) {
2069:                    throw new RuntimeException(JaiI18N.getString("RenderedOp4"));
2070:                }
2071:
2072:                createPropertySource();
2073:                properties.removeProperty(name);
2074:            }
2075:
2076:            /**
2077:             * Returns the property associated with the specified property name,
2078:             * or <code>java.awt.Image.UndefinedProperty</code> if the specified
2079:             * property is not set on the image.  This method is dynamic in the
2080:             * sense that subsequent invocations of this method on the same object
2081:             * may return different values as a function of changes in the property
2082:             * environment of the node, e.g., a change in which
2083:             * <code>PropertyGenerator</code>s are registered or in the values
2084:             * associated with properties of node sources.  The case of the property
2085:             * name passed to this method is ignored.
2086:             *
2087:             * @param name A <code>String</code> naming the property.
2088:             *
2089:             * @throws IllegalArgumentException if
2090:             *         <code>name</code> is <code>null</code>.
2091:             *
2092:             * @since JAI 1.1
2093:             */
2094:            public synchronized Object getDynamicProperty(String name) {
2095:                createPropertySource();
2096:                return thePropertySource.getProperty(name);
2097:            }
2098:
2099:            /**
2100:             * Adds a <code>PropertyGenerator</code> to the node.  The property values
2101:             * emitted by this property generator override any previous
2102:             * definitions.
2103:             *
2104:             * @param pg A <code>PropertyGenerator</code> to be added to this node's
2105:             *        property environment.
2106:             *
2107:             * @throws IllegalArgumentException if
2108:             * <code>pg</code> is <code>null</code>.
2109:             */
2110:            public synchronized void addPropertyGenerator(PropertyGenerator pg) {
2111:                nodeSupport.addPropertyGenerator(pg);
2112:            }
2113:
2114:            /**
2115:             * Forces a property to be copied from the specified source node.
2116:             * By default, a property is copied from the first source node
2117:             * that emits it.  The result of specifying an invalid source is
2118:             * undefined.
2119:             *
2120:             * @param propertyName the name of the property to be copied.
2121:             * @param sourceIndex the index of the from which to copy the property.
2122:             * @throws IllegalArgumentException if <code>propertyName</code> is
2123:             *         <code>null</code>.
2124:             *
2125:             * @since JAI 1.1
2126:             */
2127:            public synchronized void copyPropertyFromSource(
2128:                    String propertyName, int sourceIndex) {
2129:                nodeSupport.copyPropertyFromSource(propertyName, sourceIndex);
2130:            }
2131:
2132:            /**
2133:             * Removes a named property from the property environment of this
2134:             * node.  Unless the property is stored locally either due
2135:             * to having been set explicitly via <code>setProperty()</code>
2136:             * or to having been cached for property
2137:             * synchronization purposes, subsequent calls to
2138:             * <code>getProperty(name)</code> will return
2139:             * <code>java.awt.Image.UndefinedProperty</code>, and <code>name</code>
2140:             * will not appear on the list of properties emitted by
2141:             * <code>getPropertyNames()</code>.  To delete the property from the
2142:             * local property set of the node, <code>removeProperty()</code> should
2143:             * be used.
2144:             *
2145:             * @param name A <code>String</code> naming the property to be suppressed.
2146:             *
2147:             * @throws IllegalArgumentException if
2148:             * <code>name</code> is <code>null</code>.
2149:             * @throws IllegalArgumentException if <code>name</code>
2150:             * conflicts with Synthetic property.
2151:             */
2152:            public synchronized void suppressProperty(String name) {
2153:                if (name == null)
2154:                    throw new IllegalArgumentException(JaiI18N
2155:                            .getString("Generic0"));
2156:
2157:                if (synthProps.contains(new CaselessStringKey(name))) {
2158:                    throw new IllegalArgumentException(JaiI18N
2159:                            .getString("RenderedOp5"));
2160:                }
2161:
2162:                nodeSupport.suppressProperty(name);
2163:            }
2164:
2165:            /*****************************************************************
2166:             * The following methods override public or protected methods in *
2167:             * PlanarImage  thus causing this node to be rendered.           *
2168:             ****************************************************************/
2169:
2170:            /**
2171:             * Renders the node if it has not already been rendered, and returns
2172:             * the X coordinate of the leftmost column of the rendered image.
2173:             */
2174:            public int getMinX() {
2175:                createRendering();
2176:                return theImage.getMinX();
2177:            }
2178:
2179:            /**
2180:             * Renders the node if it has not already been rendered, and returns
2181:             * the X coordinate of the uppermost row of the rendered image.
2182:             */
2183:            public int getMinY() {
2184:                createRendering();
2185:                return theImage.getMinY();
2186:            }
2187:
2188:            /**
2189:             * Renders the node if it has not already been rendered,
2190:             * and returns the width of the rendered image.
2191:             */
2192:            public int getWidth() {
2193:                createRendering();
2194:                return theImage.getWidth();
2195:            }
2196:
2197:            /**
2198:             * Renders the node if it has not already been rendered,
2199:             * and returns the height of the rendered image.
2200:             */
2201:            public int getHeight() {
2202:                createRendering();
2203:                return theImage.getHeight();
2204:            }
2205:
2206:            /**
2207:             * Renders the node if it has not already been rendered,
2208:             * and returns the tile width of the rendered image.
2209:             */
2210:            public int getTileWidth() {
2211:                createRendering();
2212:                return theImage.getTileWidth();
2213:            }
2214:
2215:            /**
2216:             * Renders the node if it has not already been rendered,
2217:             * and returns the tile height of the rendered image.
2218:             */
2219:            public int getTileHeight() {
2220:                createRendering();
2221:                return theImage.getTileHeight();
2222:            }
2223:
2224:            /**
2225:             * Renders the node if it has not already been rendered,
2226:             * and returns the tile grid X offset of the rendered image.
2227:             */
2228:            public int getTileGridXOffset() {
2229:                createRendering();
2230:                return theImage.getTileGridXOffset();
2231:            }
2232:
2233:            /**
2234:             * Renders the node if it has not already been rendered,
2235:             * and returns the tile grid Y offset of the rendered image.
2236:             */
2237:            public int getTileGridYOffset() {
2238:                createRendering();
2239:                return theImage.getTileGridYOffset();
2240:            }
2241:
2242:            /**
2243:             * Renders the node if it has not already been rendered, and
2244:             * returns the <code>SampleModel</code> of the rendered image.
2245:             */
2246:            public SampleModel getSampleModel() {
2247:                createRendering();
2248:                return theImage.getSampleModel();
2249:            }
2250:
2251:            /**
2252:             * Renders the node if it has not already been rendered, and
2253:             * returns the <code>ColorModel</code> of the rendered image.
2254:             */
2255:            public ColorModel getColorModel() {
2256:                createRendering();
2257:                return theImage.getColorModel();
2258:            }
2259:
2260:            /**
2261:             * Renders the node if it has not already been rendered,
2262:             * and returns the specified tile of the rendered image.
2263:             *
2264:             * @param tileX The X index of the tile.
2265:             * @param tileY The Y index of the tile.
2266:             *
2267:             * @return  The requested tile as a <code>Raster</code>.
2268:             */
2269:            public Raster getTile(int tileX, int tileY) {
2270:                createRendering();
2271:                return theImage.getTile(tileX, tileY);
2272:            }
2273:
2274:            /**
2275:             * Renders the node if it has not already been rendered, and
2276:             * returns the entire rendered image as a <code>Raster</code>.
2277:             */
2278:            public Raster getData() {
2279:                createRendering();
2280:                return theImage.getData();
2281:            }
2282:
2283:            /**
2284:             * Renders the node if it has not already been rendered, and
2285:             * returns a specified rectangular region of the rendered
2286:             * image as a <code>Raster</code>.
2287:             */
2288:            public Raster getData(Rectangle rect) {
2289:                createRendering();
2290:                return theImage.getData(rect);
2291:            }
2292:
2293:            /**
2294:             * Renders the node if it has not already been rendered, and
2295:             * copies and returns the entire rendered image into a single raster.
2296:             */
2297:            public WritableRaster copyData() {
2298:                createRendering();
2299:                return theImage.copyData();
2300:            }
2301:
2302:            /**
2303:             * Renders the node if it has not already been rendered, and
2304:             * copies a specified rectangle of the rendered image into
2305:             * the given <code>WritableRaster</code>.
2306:             *
2307:             * @param raster A <code>WritableRaster</code> to be filled with image data.
2308:             * @return A reference to the supplied <code>WritableRaster</code>.
2309:             *
2310:             */
2311:            public WritableRaster copyData(WritableRaster raster) {
2312:                createRendering();
2313:                return theImage.copyData(raster);
2314:            }
2315:
2316:            /**
2317:             * Renders the node if it has not already been rendered, and
2318:             * returns the tiles indicated by the <code>tileIndices</code>
2319:             * of the rendered image as an array of <code>Raster</code>s.
2320:             *
2321:             * @param tileIndices An array of Points representing TileIndices.
2322:             * @return An array of Raster containing the tiles corresponding
2323:             *         to the given TileIndices.
2324:             *
2325:             * @throws IllegalArgumentException  If <code>tileIndices</code> is
2326:             *         <code>null</code>.
2327:             */
2328:            public Raster[] getTiles(Point tileIndices[]) {
2329:                createRendering();
2330:                return theImage.getTiles(tileIndices);
2331:            }
2332:
2333:            /**
2334:             * Queues a list of tiles for computation.  Registered listeners
2335:             * will be notified after each tile has been computed.  The event
2336:             * source parameter passed to such listeners will be the node itself;
2337:             * the image parameter will be the rendering of the node.  The
2338:             * <code>RenderedOp</code> itself in fact should monitor any
2339:             * <code>TileComputationListener</code> events of its rendering and
2340:             * forward any such events to any of its registered listeners.
2341:             *
2342:             * @param tileIndices A list of tile indices indicating which tiles
2343:             *        to schedule for computation.
2344:             * @throws IllegalArgumentException  If <code>tileIndices</code> is
2345:             *         <code>null</code>.
2346:             *
2347:             * @since JAI 1.1
2348:             */
2349:            public TileRequest queueTiles(Point[] tileIndices) {
2350:                createRendering();
2351:                return theImage.queueTiles(tileIndices);
2352:            }
2353:
2354:            /**
2355:             * Issue an advisory cancellation request to nullify processing of
2356:             * the indicated tiles.
2357:             *
2358:             * @param request The request for which tiles are to be cancelled.
2359:             * @param tileIndices The tiles to be cancelled; may be <code>null</code>.
2360:             *        Any tiles not actually in the <code>TileRequest</code> will be
2361:             *        ignored.
2362:             * @throws IllegalArgumentException  If <code>request</code> is
2363:             *         <code>null</code>.
2364:             *
2365:             * @since JAI 1.1
2366:             */
2367:            public void cancelTiles(TileRequest request, Point[] tileIndices) {
2368:                if (request == null) {
2369:                    throw new IllegalArgumentException(JaiI18N
2370:                            .getString("Generic4"));
2371:                }
2372:                createRendering();
2373:                theImage.cancelTiles(request, tileIndices);
2374:            }
2375:
2376:            /**
2377:             * Renders the node if it has not already been rendered.
2378:             * Hints that the given tiles of the rendered image might be
2379:             * needed in the near future.
2380:             *
2381:             * @param tileIndices A list of tileIndices indicating which tiles
2382:             *        to prefetch.
2383:             *
2384:             * @throws IllegalArgumentException  If <code>tileIndices</code> is
2385:             *         <code>null</code>.
2386:             */
2387:            public void prefetchTiles(Point tileIndices[]) {
2388:                createRendering();
2389:                theImage.prefetchTiles(tileIndices);
2390:            }
2391:
2392:            // ----- Methods dealing with source Vector: forward call to ParamBlock.
2393:
2394:            /**
2395:             * Adds a <code>PlanarImage</code> source to the
2396:             * <code>ParameterBlock</code> of this node.
2397:             * This is a convenience method that invokes
2398:             * <code>setParameterBlock()</code> and so adheres to the same event
2399:             * firing behavior.
2400:             *
2401:             * <p><i> Note that the behavior of this method has changed as of
2402:             * Java Advanced Imaging 1.1.  To obtain the previous behavior use
2403:             * <code>getRendering().addSource()</code>.  The description of the
2404:             * previous behavior is as follows:
2405:             * <blockquote>
2406:             *
2407:             * Renders the node if it has not already been rendered, and
2408:             * adds a <code>PlanarImage</code> source to the list of sources
2409:             * of the rendered image.
2410:             *
2411:             * </blockquote>
2412:             * </i>
2413:             *
2414:             * @param source The source to be added to the
2415:             *        <code>ParameterBlock</code>
2416:             *
2417:             * @throws IllegalArgumentException if <code>source</code> is
2418:             *         <code>null</code>.
2419:             *
2420:             * @deprecated as of JAI 1.1. Use <code>addSource(Object)</code>.
2421:             */
2422:            public synchronized void addSource(PlanarImage source) {
2423:                Object sourceObject = source;
2424:                addSource(sourceObject);
2425:            }
2426:
2427:            /**
2428:             * Sets the specified source stored in the <code>ParameterBlock</code>
2429:             * of this node to a new <code>PlanarImage</code> source.
2430:             * This is a convenience method that invokes
2431:             * <code>setParameterBlock()</code> and so adheres to the same event
2432:             * firing behavior.
2433:             *
2434:             * <p><i> Note that the behavior of this method has changed as of
2435:             * Java Advanced Imaging 1.1.  To obtain the previous behavior use
2436:             * <code>getRendering().setSource()</code>.  The description of the
2437:             * previous behavior is as follows:
2438:             * <blockquote>
2439:             *
2440:             * Renders the node if it has not already been rendered, and
2441:             * sets the specified source of the rendered image to the
2442:             * supplied <code>PlanarImage</code>.
2443:             * An <code>ArrayIndexOutOfBoundsException</code> may be thrown if
2444:             * an invalid <code>index</code> is supplied.
2445:             *
2446:             * </blockquote>
2447:             * </i>
2448:             *
2449:             * @param source The source, as a <code>PlanarImage</code>.
2450:             * @param index The index of the source.
2451:             * @throws IllegalArgumentException if <code>source</code> is
2452:             *         <code>null</code>.
2453:             * @throws ArrayIndexOutOfBoundsException if
2454:             *         <code>index</code> is invalid.
2455:             *
2456:             * @deprecated as of JAI 1.1. Use <code>setSource(Object, int)</code>.
2457:             */
2458:            public synchronized void setSource(PlanarImage source, int index) {
2459:                Object sourceObject = source;
2460:                setSource(sourceObject, index);
2461:            }
2462:
2463:            /**
2464:             * Returns the specified <code>PlanarImage</code> source stored in the
2465:             * <code>ParameterBlock</code> of this node.
2466:             * If there is no source corresponding to the specified index, an
2467:             * <code>ArrayIndexOutOfBoundsException</code> will be thrown.
2468:             *
2469:             * <p><i> Note that the behavior of this method has changed as of
2470:             * Java Advanced Imaging 1.1.  To obtain the previous behavior use
2471:             * <code>getRendering().getSource()</code>.  The description of the
2472:             * previous behavior is as follows:
2473:             * <blockquote>
2474:             *
2475:             * Renders the node if it has not already been rendered, and
2476:             * returns the specified <code>PlanarImage</code> source of
2477:             * the rendered image. If there is no source corresponding to
2478:             * the specified index, this method will throw an
2479:             * <code>ArrayIndexOutOfBoundsException</code>.
2480:             * The source returned may differ from the source stored in
2481:             * the <code>ParameterBlock</code> of this node.
2482:             *
2483:             * </blockquote>
2484:             * </i>
2485:             *
2486:             * @param index  The index of the desired source.
2487:             * @return       A <code>PlanarImage</code> source.
2488:             * @throws ArrayIndexOutOfBoundsException if
2489:             *         <code>index</code> is invalid.
2490:             * @throws ClassCastException if the source at the indicated index is
2491:             *         not a <code>PlanarImage</code>.
2492:             *
2493:             * @deprecated as of JAI 1.1. Use <code>getSourceObject()</code>.
2494:             */
2495:            public PlanarImage getSource(int index) {
2496:                return (PlanarImage) nodeSupport.getParameterBlock().getSource(
2497:                        index);
2498:            }
2499:
2500:            /**
2501:             * Removes the specified <code>PlanarImage</code> source from the
2502:             * <code>ParameterBlock</code> of this node.
2503:             *
2504:             * <p><i> Note that the behavior of this method has changed as of
2505:             * Java Advanced Imaging 1.1.  To obtain the previous behavior use
2506:             * <code>getRendering().removeSource()</code>.  The description of the
2507:             * previous behavior is as follows:
2508:             * <blockquote>
2509:             *
2510:             * Renders the node if it has not already been rendered, and
2511:             * removes a <code>PlanarImage</code> source from the list
2512:             * of sources of the rendered image.
2513:             *
2514:             * </blockquote>
2515:             * </i>
2516:             *
2517:             * @param source A <code>PlanarImage</code> to be removed.
2518:             *
2519:             * @throws IllegalArgumentException if
2520:             * <code>source</code> is <code>null</code>.
2521:             * @return <code>true</code> if the element was present, <code>false</code>
2522:             * otherwise.
2523:             *
2524:             * @deprecated as of JAI 1.1. Use <code>removeSource(Object)</code>.
2525:             */
2526:            public synchronized boolean removeSource(PlanarImage source) {
2527:                Object sourceObject = source;
2528:                return removeSource(sourceObject);
2529:            }
2530:
2531:            /**
2532:             * Adds a source to the <code>ParameterBlock</code> of this node.
2533:             * This is a convenience method that invokes
2534:             * <code>setParameterBlock()</code> and so adheres to the same event
2535:             * firing behavior.
2536:             *
2537:             * <p> The node is added automatically as a sink if the source is a
2538:             * <code>PlanarImage</code> or a <code>CollectionImage</code>.
2539:             *
2540:             * @param source The source to be added to the
2541:             *        <code>ParameterBlock</code>
2542:             * @throws IllegalArgumentException if
2543:             *         <code>source</code> is <code>null</code>.
2544:             *
2545:             * @since JAI 1.1
2546:             */
2547:            public synchronized void addSource(Object source) {
2548:                if (source == null)
2549:                    throw new IllegalArgumentException(JaiI18N
2550:                            .getString("Generic0"));
2551:
2552:                ParameterBlock pb = (ParameterBlock) nodeSupport
2553:                        .getParameterBlock().clone();
2554:                pb.addSource(source);
2555:                nodeSupport.setParameterBlock(pb);
2556:
2557:                if (source instanceof  PlanarImage) {
2558:                    ((PlanarImage) source).addSink(this );
2559:                } else if (source instanceof  CollectionImage) {
2560:                    ((CollectionImage) source).addSink(this );
2561:                }
2562:            }
2563:
2564:            /**
2565:             * Sets the specified source stored in the <code>ParameterBlock</code>
2566:             * of this node to a new source object.
2567:             * This is a convenience method that invokes
2568:             * <code>setParameterBlock()</code> and so adheres to the same event
2569:             * firing behavior.
2570:             *
2571:             * <p> The node is added automatically as a sink if the source is a
2572:             * <code>PlanarImage</code> or a <code>CollectionImage</code>.  If
2573:             * appropriate the node is removed as a sink of any previous source
2574:             * at the same index.
2575:             *
2576:             * @param source The Source to be set.
2577:             * @param index  The Index at which it is to be set.
2578:             *
2579:             * @throws IllegalArgumentException if
2580:             *         <code>source</code> is <code>null</code>.
2581:             * @throws ArrayIndexOutOfBoundsException if
2582:             *         <code>index</code> is invalid.
2583:             *
2584:             * @since JAI 1.1
2585:             */
2586:            public synchronized void setSource(Object source, int index) {
2587:                if (source == null)
2588:                    throw new IllegalArgumentException(JaiI18N
2589:                            .getString("Generic0"));
2590:
2591:                ParameterBlock pb = (ParameterBlock) nodeSupport
2592:                        .getParameterBlock().clone();
2593:
2594:                if (index < pb.getNumSources()) {
2595:                    Object priorSource = pb.getSource(index);
2596:                    if (priorSource instanceof  PlanarImage) {
2597:                        ((PlanarImage) priorSource).removeSink(this );
2598:                    } else if (priorSource instanceof  CollectionImage) {
2599:                        ((CollectionImage) priorSource).removeSink(this );
2600:                    }
2601:                }
2602:
2603:                pb.setSource(source, index);
2604:                nodeSupport.setParameterBlock(pb);
2605:
2606:                if (source instanceof  PlanarImage) {
2607:                    ((PlanarImage) source).addSink(this );
2608:                } else if (source instanceof  CollectionImage) {
2609:                    ((CollectionImage) source).addSink(this );
2610:                }
2611:            }
2612:
2613:            /**
2614:             * Removes the specified <code>Object</code> source from the
2615:             * <code>ParameterBlock</code> of this node.
2616:             *
2617:             * <p> The node is removed automatically as a sink if the source is a
2618:             * <code>PlanarImage</code> or a <code>CollectionImage</code>.
2619:             *
2620:             * @param source A <code>Object</code> to be removed.
2621:             *
2622:             * @throws IllegalArgumentException if
2623:             * <code>source</code> is <code>null</code>.
2624:             * @return <code>true</code> if the element was present, <code>false</code>
2625:             * otherwise.
2626:             *
2627:             * @since JAI 1.1
2628:             */
2629:            public synchronized boolean removeSource(Object source) {
2630:                if (source == null) {
2631:                    throw new IllegalArgumentException(JaiI18N
2632:                            .getString("Generic0"));
2633:                }
2634:
2635:                ParameterBlock pb = (ParameterBlock) nodeSupport
2636:                        .getParameterBlock().clone();
2637:
2638:                Vector nodeSources = pb.getSources();
2639:                if (nodeSources.contains(source)) {
2640:                    if (source instanceof  PlanarImage) {
2641:                        ((PlanarImage) source).removeSink(this );
2642:                    } else if (source instanceof  CollectionImage) {
2643:                        ((CollectionImage) source).removeSink(this );
2644:                    }
2645:                }
2646:
2647:                boolean result = nodeSources.remove(source);
2648:                nodeSupport.setParameterBlock(pb);
2649:
2650:                return result;
2651:            }
2652:
2653:            /**
2654:             * Returns the specified <code>PlanarImage</code> source stored in the
2655:             * <code>ParameterBlock</code> of this node.
2656:             * If there is no source corresponding to the specified index, an
2657:             * <code>ArrayIndexOutOfBoundsException</code> will be thrown.
2658:             *
2659:             * @param index  The index of the desired source.
2660:             * @return       A <code>PlanarImage</code> source.
2661:             * @throws ArrayIndexOutOfBoundsException if
2662:             *         <code>index</code> is invalid.
2663:             * @throws ClassCastException if the source at the indicated index is
2664:             *         not a <code>PlanarImage</code>.
2665:             *
2666:             * @since JAI 1.1
2667:             */
2668:            public PlanarImage getSourceImage(int index) {
2669:                return (PlanarImage) nodeSupport.getParameterBlock().getSource(
2670:                        index);
2671:            }
2672:
2673:            /**
2674:             * Returns the specified source stored in the
2675:             * <code>ParameterBlock</code> of this node.
2676:             * If there is no source corresponding to the specified index, an
2677:             * <code>ArrayIndexOutOfBoundsException</code> will be thrown.
2678:             *
2679:             * @param index  The index of the source.
2680:             * @throws ArrayIndexOutOfBoundsException if
2681:             *         <code>index</code> is invalid.
2682:             *
2683:             * @since JAI 1.1
2684:             */
2685:            public synchronized Object getSourceObject(int index) {
2686:                return nodeSupport.getParameterBlock().getSource(index);
2687:            }
2688:
2689:            /**
2690:             * Returns the number of sources stored in the
2691:             * <code>ParameterBlock</code> of this node.
2692:             * This may differ from the number of sources of the rendered image.
2693:             */
2694:            public int getNumSources() {
2695:                // This method must return the number of sources of this node,
2696:                // not the number of sources of the rendered image. Otherwise,
2697:                // it'll cause exception in some cases.
2698:                return nodeSupport.getParameterBlock().getNumSources();
2699:            }
2700:
2701:            /**
2702:             * Returns a clone of the <code>Vector</code> of sources stored in the
2703:             * <code>ParameterBlock</code> of this node.
2704:             * This may differ from the source vector of the rendering of the node.
2705:             */
2706:            public synchronized Vector getSources() {
2707:                Vector srcs = nodeSupport.getParameterBlock().getSources();
2708:                return srcs == null ? null : (Vector) srcs.clone();
2709:            }
2710:
2711:            /**
2712:             * Replaces the sources in the <code>ParameterBlock</code> of this node
2713:             * with a new list of sources.
2714:             * This is a convenience method that invokes
2715:             * <code>setParameterBlock()</code> and so adheres to the same event
2716:             * firing behavior.
2717:             *
2718:             * <p> The node is added automatically as a sink of any source which is a
2719:             * <code>PlanarImage</code> or a <code>CollectionImage</code>.  It is
2720:             * also automatically removed as a sink of any such prior sources which
2721:             * are no longer sources.
2722:             *
2723:             * @param sourceList  A <code>List</code> of sources.
2724:             *
2725:             * @throws IllegalArgumentException if
2726:             *         <code>sourceList</code> is <code>null</code>.
2727:             */
2728:            public synchronized void setSources(List sourceList) {
2729:                if (sourceList == null)
2730:                    throw new IllegalArgumentException(JaiI18N
2731:                            .getString("Generic0"));
2732:
2733:                ParameterBlock pb = (ParameterBlock) nodeSupport
2734:                        .getParameterBlock().clone();
2735:
2736:                Iterator it = pb.getSources().iterator();
2737:                while (it.hasNext()) {
2738:                    Object priorSource = it.next();
2739:                    if (!sourceList.contains(priorSource)) {
2740:                        if (priorSource instanceof  PlanarImage) {
2741:                            ((PlanarImage) priorSource).removeSink(this );
2742:                        } else if (priorSource instanceof  CollectionImage) {
2743:                            ((CollectionImage) priorSource).removeSink(this );
2744:                        }
2745:                    }
2746:                }
2747:
2748:                pb.removeSources();
2749:
2750:                int size = sourceList.size();
2751:                for (int i = 0; i < size; i++) {
2752:                    Object src = sourceList.get(i);
2753:                    pb.addSource(src);
2754:                    if (src instanceof  PlanarImage) {
2755:                        ((PlanarImage) src).addSink(this );
2756:                    } else if (src instanceof  CollectionImage) {
2757:                        ((CollectionImage) src).addSink(this );
2758:                    }
2759:                }
2760:
2761:                nodeSupport.setParameterBlock(pb);
2762:            }
2763:
2764:            /**
2765:             * Removes all the sources stored in the
2766:             * <code>ParameterBlock</code> of this node.
2767:             * This is a convenience method that invokes
2768:             * <code>setParameterBlock()</code> and so adheres to the same event
2769:             * firing behavior.
2770:             *
2771:             * <p> The node is removed automatically as a sink of any source which
2772:             * is a <code>PlanarImage</code> or a <code>CollectionImage</code>.
2773:             */
2774:            public synchronized void removeSources() {
2775:                ParameterBlock pb = (ParameterBlock) nodeSupport
2776:                        .getParameterBlock().clone();
2777:                Iterator it = pb.getSources().iterator();
2778:                while (it.hasNext()) {
2779:                    Object priorSource = it.next();
2780:                    if (priorSource instanceof  PlanarImage) {
2781:                        ((PlanarImage) priorSource).removeSink(this );
2782:                    } else if (priorSource instanceof  CollectionImage) {
2783:                        ((CollectionImage) priorSource).removeSink(this );
2784:                    }
2785:                    it.remove();
2786:                }
2787:                nodeSupport.setParameterBlock(pb);
2788:            }
2789:
2790:            // ----- Methods dealing with sinks Vector.
2791:
2792:            /**
2793:             * Adds a <code>PlanarImage</code> sink to the list of sinks of the node.
2794:             *
2795:             * <p><i> Note that the behavior of this method has changed as of
2796:             * Java Advanced Imaging 1.1.  To obtain the previous behavior use
2797:             * <code>getRendering().addSink()</code>.  The description of the
2798:             * previous behavior is as follows:
2799:             * <blockquote>
2800:             *
2801:             * Renders the node if it has not already been rendered, and
2802:             * adds a <code>PlanarImage</code> sink to the list of sinks
2803:             * of the rendered image.
2804:             *
2805:             * </blockquote>
2806:             *
2807:             * <p> Note also that this class no longer overrides
2808:             * <code>getSinks()</code>.  To obtain the previous behavior of
2809:             * <code>getSinks()</code> use <code>getRendering().getSinks()</code>.
2810:             * </i>
2811:             *
2812:             * @throws IllegalArgumentException if
2813:             * <code>sink</code> is <code>null</code>.
2814:             */
2815:            public synchronized void addSink(PlanarImage sink) {
2816:                if (sink == null) {
2817:                    throw new IllegalArgumentException(JaiI18N
2818:                            .getString("Generic0"));
2819:                }
2820:                super .addSink(sink);
2821:            }
2822:
2823:            /**
2824:             * Removes a <code>PlanarImage</code> sink from the list of sinks of
2825:             * the node.
2826:             *
2827:             * <p><i> Note that the behavior of this method has changed as of
2828:             * Java Advanced Imaging 1.1.  To obtain the previous behavior use
2829:             * <code>getRendering().removeSink()</code>.  The description of the
2830:             * previous behavior is as follows:
2831:             * <blockquote>
2832:             *
2833:             * Renders the node if it has not already been rendered, and
2834:             * removes a <code>PlanarImage</code> sink from the list of sinks
2835:             * of the rendered image.
2836:             *
2837:             * </blockquote>
2838:             *
2839:             * <p> Note also that this class no longer overrides
2840:             * <code>getSinks()</code>.  To obtain the previous behavior of
2841:             * <code>getSinks()</code> use <code>getRendering().getSinks()</code>.
2842:             * </i>
2843:             *
2844:             * @throws IllegalArgumentException if
2845:             * <code>sink</code> is <code>null</code>.
2846:             */
2847:            public synchronized boolean removeSink(PlanarImage sink) {
2848:                if (sink == null) {
2849:                    throw new IllegalArgumentException(JaiI18N
2850:                            .getString("Generic0"));
2851:                }
2852:                return super .removeSink(sink);
2853:            }
2854:
2855:            /**
2856:             * Removes all sinks from the list of sinks of the node.
2857:             *
2858:             * @since JAI 1.1
2859:             */
2860:            public void removeSinks() {
2861:                super .removeSinks();
2862:            }
2863:
2864:            /**
2865:             * Adds a sink to the list of node sinks.  If the sink is an
2866:             * instance of <code>PropertyChangeListener</code> it will be
2867:             * notified in the same manner as registered listeners for the
2868:             * changes to the "Rendering" property of this node as long as its
2869:             * <code>WeakReference</code> has not yet been cleared.
2870:             *
2871:             * @throws IllegalArgumentException if
2872:             * <code>sink</code> is <code>null</code>.
2873:             *
2874:             * @since JAI 1.1
2875:             */
2876:            public boolean addSink(Object sink) {
2877:                if (sink == null) {
2878:                    throw new IllegalArgumentException(JaiI18N
2879:                            .getString("Generic0"));
2880:                }
2881:                return super .addSink(sink);
2882:            }
2883:
2884:            /**
2885:             * Removes a sink from the list of node sinks.  If the sink
2886:             * is a <code>PropertyChangeListener</code> for the "Rendering"
2887:             * property of this node it will no longer be eligible for
2888:             * notification events indicating a change in this property.
2889:             *
2890:             * @throws IllegalArgumentException if
2891:             * <code>sink</code> is <code>null</code>.
2892:             *
2893:             * @since JAI 1.1
2894:             */
2895:            public boolean removeSink(Object sink) {
2896:                if (sink == null) {
2897:                    throw new IllegalArgumentException(JaiI18N
2898:                            .getString("Generic0"));
2899:                }
2900:                return super .removeSink(sink);
2901:            }
2902:
2903:            /* ----- Image coordinate mapping methods ----- */
2904:
2905:            /**
2906:             * Computes the position in the specified source that best
2907:             * matches the supplied destination image position. If it
2908:             * is not possible to compute the requested position,
2909:             * <code>null</code> will be returned. If the point is mapped
2910:             * outside the source bounds, the coordinate value or <code>null</code>
2911:             * may be returned at the discretion of the implementation.
2912:             *
2913:             * <p>If the rendering of the node is an <code>OpImage</code>, the
2914:             * call is forwarded to the equivalent method of the rendering.
2915:             * Otherwise <code>destPt</code> is returned to indicate the identity
2916:             * mapping. In either case if the node had not been rendered it will
2917:             * be.</p>
2918:             *
2919:             * @param destPt the position in destination image coordinates
2920:             * to map to source image coordinates.
2921:             * @param sourceIndex the index of the source image.
2922:             *
2923:             * @return a <code>Point2D</code> of the same class as
2924:             * <code>destPt</code> or <code>null</code>.
2925:             *
2926:             * @throws IllegalArgumentException if <code>destPt</code> is
2927:             * <code>null</code>.
2928:             * @throws IndexOutOfBoundsException if <code>sourceIndex</code> is
2929:             * negative or greater than or equal to the number of sources.
2930:             *
2931:             * @since JAI 1.1.2
2932:             */
2933:            public Point2D mapDestPoint(Point2D destPt, int sourceIndex) {
2934:                if (destPt == null) {
2935:                    throw new IllegalArgumentException(JaiI18N
2936:                            .getString("Generic0"));
2937:                } else if (sourceIndex < 0 || sourceIndex >= getNumSources()) {
2938:                    throw new IndexOutOfBoundsException(JaiI18N
2939:                            .getString("Generic1"));
2940:                }
2941:
2942:                createRendering();
2943:
2944:                if (theImage != null && theImage instanceof  OpImage) {
2945:                    return ((OpImage) theImage).mapDestPoint(destPt,
2946:                            sourceIndex);
2947:                }
2948:
2949:                return destPt;
2950:            }
2951:
2952:            /**
2953:             * Computes the position in the destination that best
2954:             * matches the supplied source image position. If it
2955:             * is not possible to compute the requested position,
2956:             * <code>null</code> will be returned. If the point is mapped
2957:             * outside the destination bounds, the coordinate value or
2958:             * <code>null</code> may be returned at the discretion of the
2959:             * implementation.
2960:             *
2961:             * <p>If the rendering of the node is an <code>OpImage</code>, the
2962:             * call is forwarded to the equivalent method of the rendering.
2963:             * Otherwise <code>sourcePt</code> is returned to indicate the identity
2964:             * mapping. In either case if the node had not been rendered it will
2965:             * be.</p>
2966:             *
2967:             * @param sourcePt the position in source image coordinates
2968:             * to map to destination image coordinates.
2969:             * @param sourceIndex the index of the source image.
2970:             *
2971:             * @return a <code>Point2D</code> of the same class as
2972:             * <code>sourcePt</code> or <code>null</code>.
2973:             *
2974:             * @throws IllegalArgumentException if <code>sourcePt</code> is
2975:             * <code>null</code>.
2976:             * @throws IndexOutOfBoundsException if <code>sourceIndex</code> is
2977:             * negative or greater than or equal to the number of sources.
2978:             *
2979:             * @since JAI 1.1.2
2980:             */
2981:            public Point2D mapSourcePoint(Point2D sourcePt, int sourceIndex) {
2982:                if (sourcePt == null) {
2983:                    throw new IllegalArgumentException(JaiI18N
2984:                            .getString("Generic0"));
2985:                } else if (sourceIndex < 0 || sourceIndex >= getNumSources()) {
2986:                    throw new IndexOutOfBoundsException(JaiI18N
2987:                            .getString("Generic1"));
2988:                }
2989:
2990:                createRendering();
2991:
2992:                if (theImage != null && theImage instanceof  OpImage) {
2993:                    return ((OpImage) theImage).mapSourcePoint(sourcePt,
2994:                            sourceIndex);
2995:                }
2996:
2997:                return sourcePt;
2998:            }
2999:
3000:            /* ----- Object cleanup ----- */
3001:
3002:            /**
3003:             * Hints that this node and its rendering will no longer be used.
3004:             *
3005:             * <p>If <code>theImage</code> is non-<code>null</code>, then this
3006:             * call is first forwarded to <code>theImage.dispose()</code>.
3007:             * Subsequent to this <code>super.dispose()</code> is invoked.</p>
3008:             *
3009:             * <p> The results of referencing an image after a call to
3010:             * <code>dispose()</code> are undefined.</p>
3011:             *
3012:             * @since JAI 1.1.2
3013:             */
3014:            public synchronized void dispose() {
3015:                if (isDisposed) {
3016:                    return;
3017:                }
3018:
3019:                isDisposed = true;
3020:
3021:                if (theImage != null) {
3022:                    theImage.dispose();
3023:                }
3024:
3025:                super .dispose();
3026:            }
3027:
3028:            /* ----- [De]serialization methods ----- */
3029:
3030:            /** Serializes the <code>RenderedOp</code>. */
3031:            private void writeObject(ObjectOutputStream out) throws IOException {
3032:                // Write non-static and non-transient fields.
3033:                out.defaultWriteObject();
3034:
3035:                // Explicitly serialize the required superclass fields.
3036:                out.writeObject(eventManager);
3037:                out.writeObject(properties);
3038:            }
3039:
3040:            /**
3041:             * Deserialize the <code>RenderedOp</code>.
3042:             */
3043:            private synchronized void readObject(ObjectInputStream in)
3044:                    throws IOException, ClassNotFoundException {
3045:
3046:                // Read non-static and non-transient fields.
3047:                in.defaultReadObject();
3048:
3049:                // Explicitly deserialize the required superclass fields.
3050:                eventManager = (PropertyChangeSupportJAI) in.readObject();
3051:                properties = (WritablePropertySourceImpl) in.readObject();
3052:
3053:                // If this operation requires immediate rendering then render it.
3054:                OperationDescriptor odesc = (OperationDescriptor) getRegistry()
3055:                        .getDescriptor("rendered",
3056:                                nodeSupport.getOperationName());
3057:
3058:                if (odesc.isImmediate()) {
3059:                    createRendering();
3060:                }
3061:            }
3062:
3063:            void sendExceptionToListener(String message, Exception e) {
3064:                ImagingListener listener = (ImagingListener) getRenderingHints()
3065:                        .get(JAI.KEY_IMAGING_LISTENER);
3066:
3067:                listener.errorOccurred(message, e, this , false);
3068:            }
3069:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.