001: /*
002: * Copyright (c) 2007, intarsys consulting GmbH
003: *
004: * Redistribution and use in source and binary forms, with or without
005: * modification, are permitted provided that the following conditions are met:
006: *
007: * - Redistributions of source code must retain the above copyright notice,
008: * this list of conditions and the following disclaimer.
009: *
010: * - Redistributions in binary form must reproduce the above copyright notice,
011: * this list of conditions and the following disclaimer in the documentation
012: * and/or other materials provided with the distribution.
013: *
014: * - Neither the name of intarsys nor the names of its contributors may be used
015: * to endorse or promote products derived from this software without specific
016: * prior written permission.
017: *
018: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
019: * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
020: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
021: * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
022: * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
023: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
024: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
025: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
026: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
027: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
028: * POSSIBILITY OF SUCH DAMAGE.
029: */
030: package de.intarsys.pdf.content;
031:
032: import java.awt.Shape;
033: import java.awt.geom.GeneralPath;
034:
035: /**
036: * A {@link ICSDevice} creating AWT {@link Shape} instances from the path
037: * painting operators.
038: *
039: */
040: abstract public class CSShapeDevice extends CSDeviceAdapter {
041: /** The shape currently in construction by graphics operations. */
042: private GeneralPath currentShape;
043:
044: /**
045: * The x coordinate of the current point in the active shape.
046: *
047: * <p>
048: * This is "cached" to ease life with bezier curves
049: * </p>
050: */
051: private float currentX;
052:
053: /**
054: * The y coordinate of the current point in the active shape.
055: *
056: * <p>
057: * This is "cached" to ease life with bezier curves
058: * </p>
059: */
060: private float currentY;
061:
062: /**
063: * The x coordinate of the initial point in the active subpath of the shape.
064: *
065: * <p>
066: * This is "cached" to ease life with bezier curves
067: * </p>
068: */
069: private float initialX;
070:
071: /**
072: * The y coordinate of the initial point in the active subpath of the shape.
073: *
074: * <p>
075: * This is "cached" to ease life with bezier curves
076: * </p>
077: */
078: private float initialY;
079:
080: /** Flag if clipping is requested by the current path creating operations */
081: private boolean clip;
082:
083: /** Flag which clipping mode is requested when clip is true; */
084: private boolean clipEvenOdd;
085:
086: protected void basicClip(Shape shape) {
087: // override in subclass
088: }
089:
090: protected void basicDraw(Shape shape) {
091: // override in subclass
092: }
093:
094: protected void basicFill(Shape shape) {
095: // override in subclass
096: }
097:
098: protected GeneralPath getCurrentShape() {
099: return currentShape;
100: }
101:
102: /*
103: * (non-Javadoc)
104: *
105: * @see de.intarsys.pdf.content.CSDeviceAdapter#pathClipEvenOdd()
106: */
107: public void pathClipEvenOdd() {
108: clip = true;
109: clipEvenOdd = true;
110: }
111:
112: /*
113: * (non-Javadoc)
114: *
115: * @see de.intarsys.pdf.content.CSDeviceAdapter#pathClipNonZero()
116: */
117: public void pathClipNonZero() {
118: clip = true;
119: clipEvenOdd = false;
120: }
121:
122: /*
123: * (non-Javadoc)
124: *
125: * @see de.intarsys.pdf.content.CSDeviceAdapter#pathClose()
126: */
127: public void pathClose() {
128: privateClosePath();
129: }
130:
131: /*
132: * (non-Javadoc)
133: *
134: * @see de.intarsys.pdf.content.CSDeviceAdapter#pathCloseFillStrokeEvenOdd()
135: */
136: public void pathCloseFillStrokeEvenOdd() {
137: privateClosePath();
138: currentShape.setWindingRule(GeneralPath.WIND_EVEN_ODD);
139: basicFill(getCurrentShape());
140: basicDraw(getCurrentShape());
141: privateClip();
142: }
143:
144: /*
145: * (non-Javadoc)
146: *
147: * @see de.intarsys.pdf.content.CSDeviceAdapter#pathCloseFillStrokeNonZero()
148: */
149: public void pathCloseFillStrokeNonZero() {
150: privateClosePath();
151: currentShape.setWindingRule(GeneralPath.WIND_NON_ZERO);
152: basicFill(getCurrentShape());
153: basicDraw(getCurrentShape());
154: privateClip();
155: }
156:
157: /*
158: * (non-Javadoc)
159: *
160: * @see de.intarsys.pdf.content.CSDeviceAdapter#pathCloseStroke()
161: */
162: public void pathCloseStroke() {
163: privateClosePath();
164: basicDraw(getCurrentShape());
165: privateClip();
166: }
167:
168: /*
169: * (non-Javadoc)
170: *
171: * @see de.intarsys.pdf.content.CSDeviceAdapter#pathEnd()
172: */
173: public void pathEnd() {
174: privateClip();
175: }
176:
177: /*
178: * (non-Javadoc)
179: *
180: * @see de.intarsys.pdf.content.CSDeviceAdapter#pathFillEvenOdd()
181: */
182: public void pathFillEvenOdd() {
183: currentShape.setWindingRule(GeneralPath.WIND_EVEN_ODD);
184: basicFill(getCurrentShape());
185: privateClip();
186: }
187:
188: /*
189: * (non-Javadoc)
190: *
191: * @see de.intarsys.pdf.content.CSDeviceAdapter#pathFillNonZero()
192: */
193: public void pathFillNonZero() {
194: currentShape.setWindingRule(GeneralPath.WIND_NON_ZERO);
195: basicFill(getCurrentShape());
196: privateClip();
197: }
198:
199: /*
200: * (non-Javadoc)
201: *
202: * @see de.intarsys.pdf.content.CSDeviceAdapter#pathFillStrokeEvenOdd()
203: */
204: public void pathFillStrokeEvenOdd() {
205: currentShape.setWindingRule(GeneralPath.WIND_EVEN_ODD);
206: basicFill(getCurrentShape());
207: basicDraw(getCurrentShape());
208: privateClip();
209: }
210:
211: /*
212: * (non-Javadoc)
213: *
214: * @see de.intarsys.pdf.content.CSDeviceAdapter#pathFillStrokeNonZero()
215: */
216: public void pathFillStrokeNonZero() {
217: currentShape.setWindingRule(GeneralPath.WIND_NON_ZERO);
218: basicFill(getCurrentShape());
219: basicDraw(getCurrentShape());
220: privateClip();
221: }
222:
223: /*
224: * (non-Javadoc)
225: *
226: * @see de.intarsys.pdf.content.CSDeviceAdapter#pathStroke()
227: */
228: public void pathStroke() {
229: basicDraw(getCurrentShape());
230: privateClip();
231: }
232:
233: /*
234: * (non-Javadoc)
235: *
236: * @see de.intarsys.pdf.content.CSDeviceAdapter#penCurveToC(float, float,
237: * float, float, float, float)
238: */
239: public void penCurveToC(float x1, float y1, float x2, float y2,
240: float x3, float y3) {
241: currentShape.curveTo(x1, y1, x2, y2, x3, y3);
242: currentX = x3;
243: currentY = y3;
244: }
245:
246: /*
247: * (non-Javadoc)
248: *
249: * @see de.intarsys.pdf.content.CSDeviceAdapter#penCurveToV(float, float,
250: * float, float)
251: */
252: public void penCurveToV(float x2, float y2, float x3, float y3) {
253: currentShape.curveTo(currentX, currentY, x2, y2, x3, y3);
254: currentX = x3;
255: currentY = y3;
256: }
257:
258: /*
259: * (non-Javadoc)
260: *
261: * @see de.intarsys.pdf.content.CSDeviceAdapter#penCurveToY(float, float,
262: * float, float)
263: */
264: public void penCurveToY(float x1, float y1, float x3, float y3) {
265: currentShape.curveTo(x1, y1, x3, y3, x3, y3);
266: currentX = x3;
267: currentY = y3;
268: }
269:
270: /*
271: * (non-Javadoc)
272: *
273: * @see de.intarsys.pdf.content.CSDeviceAdapter#penLineTo(float, float)
274: */
275: public void penLineTo(float x, float y) {
276: currentShape.lineTo(x, y);
277: currentX = x;
278: currentY = y;
279: }
280:
281: /*
282: * (non-Javadoc)
283: *
284: * @see de.intarsys.pdf.content.CSDeviceAdapter#penMoveTo(float, float)
285: */
286: public void penMoveTo(float x, float y) {
287: clip = false;
288: clipEvenOdd = false;
289: if (currentShape == null) {
290: currentShape = new GeneralPath();
291: }
292: currentShape.moveTo(x, y);
293: initialX = x;
294: initialY = y;
295: currentX = x;
296: currentY = y;
297: }
298:
299: /*
300: * (non-Javadoc)
301: *
302: * @see de.intarsys.pdf.content.CSDeviceAdapter#penRectangle(float, float,
303: * float, float)
304: */
305: public void penRectangle(float x, float y, float w, float h) {
306: clip = false;
307: clipEvenOdd = false;
308: if (currentShape == null) {
309: currentShape = new GeneralPath();
310: }
311: currentShape.moveTo(x, y);
312: currentShape.lineTo(x + w, y);
313: currentShape.lineTo(x + w, y + h);
314: currentShape.lineTo(x, y + h);
315: currentShape.closePath();
316: initialX = x;
317: initialY = y;
318: currentX = x;
319: currentY = y;
320: }
321:
322: /**
323: * Finalize the rendering of a path.
324: *
325: * <p>
326: * Together with draw, fill and clip these form the rendering part of the
327: * path operations. Dependent on the rendering operation draw and fill
328: * (maybe none) are called. clip must always be called at the end of the
329: * rendering sequence.
330: * </p>
331: */
332: protected boolean privateClip() {
333: if (clip) {
334: if (clipEvenOdd) {
335: currentShape.setWindingRule(GeneralPath.WIND_EVEN_ODD);
336: } else {
337: currentShape.setWindingRule(GeneralPath.WIND_NON_ZERO);
338: }
339: basicClip(currentShape);
340: clip = false;
341: currentShape = null;
342: return true;
343: }
344: clip = false;
345: currentShape = null;
346: return false;
347: }
348:
349: protected void privateClosePath() {
350: currentShape.closePath();
351: currentX = initialX;
352: currentY = initialY;
353: }
354: }
|