001: /*
002:
003: Licensed to the Apache Software Foundation (ASF) under one or more
004: contributor license agreements. See the NOTICE file distributed with
005: this work for additional information regarding copyright ownership.
006: The ASF licenses this file to You under the Apache License, Version 2.0
007: (the "License"); you may not use this file except in compliance with
008: the License. You may obtain a copy of the License at
009:
010: http://www.apache.org/licenses/LICENSE-2.0
011:
012: Unless required by applicable law or agreed to in writing, software
013: distributed under the License is distributed on an "AS IS" BASIS,
014: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015: See the License for the specific language governing permissions and
016: limitations under the License.
017:
018: */
019: package org.apache.batik.gvt;
020:
021: import java.awt.Paint;
022: import java.awt.PaintContext;
023: import java.awt.Rectangle;
024: import java.awt.RenderingHints;
025: import java.awt.geom.AffineTransform;
026: import java.awt.geom.Rectangle2D;
027: import java.awt.image.ColorModel;
028: import java.awt.image.Raster;
029:
030: import org.apache.batik.ext.awt.image.PadMode;
031: import org.apache.batik.ext.awt.image.renderable.Filter;
032: import org.apache.batik.ext.awt.image.renderable.PadRable8Bit;
033:
034: /**
035: * The PatternPaint class provides a way to fill a Shape with a a pattern
036: * defined as a GVT Tree.
037: *
038: * @author <a href="mailto:vincent.hardy@eng.sun.com">Vincent Hardy</a>
039: * @version $Id: PatternPaint.java 478188 2006-11-22 15:19:17Z dvholten $
040: */
041: public class PatternPaint implements Paint {
042:
043: /**
044: * The <tt>GraphicsNode</tt> that this <tt>Paint</tt> uses to
045: * produce the pixel pattern
046: */
047: private GraphicsNode node;
048:
049: /**
050: * The region to which this paint is constrained
051: */
052: private Rectangle2D patternRegion;
053:
054: /**
055: * Additional pattern transform, added on top of the
056: * user space to device space transform (i.e., before
057: * the tiling space
058: */
059: private AffineTransform patternTransform;
060:
061: /*
062: * The basic tile to fill the region with.
063: * we replicate this out in the Context.
064: */
065: private Filter tile;
066:
067: /**
068: * Controls whether or not the pattern overflows
069: * the pattern tile
070: */
071: private boolean overflow;
072:
073: private PatternPaintContext lastContext;
074:
075: /**
076: * Constructs a new <tt>PatternPaint</tt>.
077: *
078: * @param node Used to generate the paint pixel pattern
079: * @param patternRegion Region to which this paint is constrained
080: * @param overflow controls whether or not the node can overflow
081: * the patternRegion.
082: * @param patternTransform additional transform added on
083: * top of the user space to device space transform.
084: */
085: public PatternPaint(GraphicsNode node, Rectangle2D patternRegion,
086: boolean overflow, AffineTransform patternTransform) {
087:
088: if (node == null) {
089: throw new IllegalArgumentException();
090: }
091:
092: if (patternRegion == null) {
093: throw new IllegalArgumentException();
094: }
095:
096: this .node = node;
097: this .patternRegion = patternRegion;
098: this .overflow = overflow;
099: this .patternTransform = patternTransform;
100:
101: // Wrap the input node so that the primitivePaint
102: // in GraphicsNodeRable takes the filter, clip....
103: // into account.
104: CompositeGraphicsNode comp = new CompositeGraphicsNode();
105: comp.getChildren().add(node);
106: Filter gnr = comp.getGraphicsNodeRable(true);
107:
108: Rectangle2D padBounds = (Rectangle2D) patternRegion.clone();
109:
110: // When there is overflow, make sure we take the full node bounds into
111: // account.
112: if (overflow) {
113: Rectangle2D nodeBounds = comp.getBounds();
114: // System.out.println("Comp Bounds : " + nodeBounds);
115: // System.out.println("Node Bounds : " + node.getBounds(gnrc));
116: padBounds.add(nodeBounds);
117: }
118:
119: // System.out.println("Pattern region : " + patternRegion);
120: // System.out.println("Node txf : " + node.getTransform());
121: tile = new PadRable8Bit(gnr, padBounds, PadMode.ZERO_PAD);
122: }
123:
124: /**
125: * Returns the graphics node that define the pattern.
126: */
127: public GraphicsNode getGraphicsNode() {
128: return node;
129: }
130:
131: /**
132: * Returns the pattern region.
133: */
134: public Rectangle2D getPatternRect() {
135: return (Rectangle2D) patternRegion.clone();
136: }
137:
138: /**
139: * Returns the additional transform of the pattern paint.
140: */
141: public AffineTransform getPatternTransform() {
142: return patternTransform;
143: }
144:
145: public boolean getOverflow() {
146: return overflow;
147: }
148:
149: /**
150: * Creates and returns a context used to generate the pattern.
151: */
152: public PaintContext createContext(ColorModel cm,
153: Rectangle deviceBounds, Rectangle2D userBounds,
154: AffineTransform xform, RenderingHints hints) {
155: // Concatenate the patternTransform to xform
156: if (patternTransform != null) {
157: xform = new AffineTransform(xform);
158: xform.concatenate(patternTransform);
159: }
160:
161: if ((lastContext != null)
162: && lastContext.getColorModel().equals(cm)) {
163:
164: double[] p = new double[6];
165: double[] q = new double[6];
166: xform.getMatrix(p);
167: lastContext.getUsr2Dev().getMatrix(q);
168: if ((p[0] == q[0]) && (p[1] == q[1]) && (p[2] == q[2])
169: && (p[3] == q[3])) {
170: if ((p[4] == q[4]) && (p[5] == q[5]))
171: return lastContext;
172: else
173: return new PatternPaintContextWrapper(lastContext,
174: (int) (q[4] - p[4] + 0.5), (int) (q[5]
175: - p[5] + 0.5));
176: }
177: }
178: // System.out.println("CreateContext Called: " + this);
179: // System.out.println("CM : " + cm);
180: // System.out.println("xForm : " + xform);
181:
182: lastContext = new PatternPaintContext(cm, xform, hints, tile,
183: patternRegion, overflow);
184: return lastContext;
185: }
186:
187: /**
188: * Returns the transparency mode for this pattern paint.
189: */
190: public int getTransparency() {
191: return TRANSLUCENT;
192: }
193:
194: static class PatternPaintContextWrapper implements PaintContext {
195: PatternPaintContext ppc;
196: int xShift, yShift;
197:
198: PatternPaintContextWrapper(PatternPaintContext ppc, int xShift,
199: int yShift) {
200: this .ppc = ppc;
201: this .xShift = xShift;
202: this .yShift = yShift;
203: }
204:
205: public void dispose() {
206: }
207:
208: public ColorModel getColorModel() {
209: return ppc.getColorModel();
210: }
211:
212: public Raster getRaster(int x, int y, int width, int height) {
213: return ppc.getRaster(x + xShift, y + yShift, width, height);
214: }
215: }
216: }
|