KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > fop > pdf > PDFState


1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one or more
3  * contributor license agreements. See the NOTICE file distributed with
4  * this work for additional information regarding copyright ownership.
5  * The ASF licenses this file to You under the Apache License, Version 2.0
6  * (the "License"); you may not use this file except in compliance with
7  * the License. You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */

17
18 /* $Id: PDFState.java 437210 2006-08-26 18:59:42Z jeremias $ */
19  
20 package org.apache.fop.pdf;
21
22 import java.io.Serializable JavaDoc;
23 import java.util.List JavaDoc;
24 import java.util.Iterator JavaDoc;
25
26 import java.awt.Color JavaDoc;
27 import java.awt.Paint JavaDoc;
28 import java.awt.Shape JavaDoc;
29 import java.awt.geom.AffineTransform JavaDoc;
30 import java.awt.geom.Area JavaDoc;
31 import java.awt.geom.GeneralPath JavaDoc;
32
33 /**
34  * This keeps information about the current state when writing to pdf.
35  * It allows for creating new graphics states with the q operator.
36  * This class is only used to store the information about the state
37  * the caller needs to handle the actual pdf operators.
38  *
39  * When setting the state for pdf there are three possible ways of
40  * handling the situation.
41  * The values can be set to override previous or default values.
42  * A new state can be added and then the values set.
43  * The current state can be popped and values will return to a
44  * previous state then the necessary values can be overridden.
45  * The current transform behaves differently to other values as the
46  * matrix is combined with the current resolved value.
47  * It is impossible to optimise the result without analysing the all
48  * the possible combinations after completing.
49  */

50 public class PDFState {
51
52     private Data data = new Data();
53     
54     private List JavaDoc stateStack = new java.util.ArrayList JavaDoc();
55
56     /**
57      * PDF State for storing graphics state.
58      */

59     public PDFState() {
60
61     }
62
63     /**
64      * Push the current state onto the stack.
65      * This call should be used when the q operator is used
66      * so that the state is known when popped.
67      */

68     public void push() {
69         Data copy;
70         try {
71             copy = (Data)getData().clone();
72             getData().resetTransform();
73         } catch (CloneNotSupportedException JavaDoc e) {
74             throw new RuntimeException JavaDoc(e.getMessage());
75         }
76         stateStack.add(copy);
77     }
78
79     /**
80      * @return the currently valid state
81      */

82     public Data getData() {
83         return data;
84     }
85     
86     /**
87      * Pop the state from the stack and set current values to popped state.
88      * This should be called when a Q operator is used so
89      * the state is restored to the correct values.
90      * @return the restored state, null if the stack is empty
91      */

92     public Data pop() {
93         if (getStackLevel() > 0) {
94             Data popped = (Data)stateStack.remove(stateStack.size() - 1);
95
96             data = popped;
97             return popped;
98         } else {
99             return null;
100         }
101     }
102
103     /**
104      * Get the current stack level.
105      *
106      * @return the current stack level
107      */

108     public int getStackLevel() {
109         return stateStack.size();
110     }
111
112     /**
113      * Restore the state to a particular level.
114      * this can be used to restore to a known level without making
115      * multiple pop calls.
116      *
117      * @param stack the level to restore to
118      */

119     /*
120     public void restoreLevel(int stack) {
121         int pos = stack;
122         while (stateStack.size() > pos + 1) {
123             stateStack.remove(stateStack.size() - 1);
124         }
125         if (stateStack.size() > pos) {
126             pop();
127         }
128     }*/

129
130     /**
131      * Set the current line dash.
132      * Check if setting the line dash to the given values
133      * will make a change and then set the state to the new values.
134      *
135      * @param array the line dash array
136      * @param offset the line dash start offset
137      * @return true if the line dash has changed
138      */

139     /*
140     public boolean setLineDash(int[] array, int offset) {
141         return false;
142     }*/

143
144     /**
145      * Set the current line width.
146      * @param width the line width in points
147      * @return true if the line width has changed
148      */

149     public boolean setLineWidth(float width) {
150         if (getData().lineWidth != width) {
151             getData().lineWidth = width;
152             return true;
153         } else {
154             return false;
155         }
156     }
157     
158     /**
159      * Set the current color.
160      * Check if the new color is a change and then set the current color.
161      *
162      * @param col the color to set
163      * @return true if the color has changed
164      */

165     public boolean setColor(Color JavaDoc col) {
166         if (!col.equals(getData().color)) {
167             getData().color = col;
168             return true;
169         } else {
170             return false;
171         }
172     }
173
174     /**
175      * Set the current background color.
176      * Check if the background color will change and then set the new color.
177      *
178      * @param col the new background color
179      * @return true if the background color has changed
180      */

181     public boolean setBackColor(Color JavaDoc col) {
182         if (!col.equals(getData().backcolor)) {
183             getData().backcolor = col;
184             return true;
185         } else {
186             return false;
187         }
188     }
189
190     /**
191      * Set the current paint.
192      * This checks if the paint will change and then sets the current paint.
193      *
194      * @param p the new paint
195      * @return true if the new paint changes the current paint
196      */

197     public boolean setPaint(Paint JavaDoc p) {
198         if (getData().paint == null) {
199             if (p != null) {
200                 getData().paint = p;
201                 return true;
202             }
203         } else if (!data.paint.equals(p)) {
204             getData().paint = p;
205             return true;
206         }
207         return false;
208     }
209
210     /**
211      * Check if the clip will change the current state.
212      * A clip is assumed to be used in a situation where it will add
213      * to any clip in the current or parent states.
214      * A clip cannot be cleared, this can only be achieved by going to
215      * a parent level with the correct clip.
216      * If the clip is different then it may start a new state so that
217      * it can return to the previous clip.
218      *
219      * @param cl the clip shape to check
220      * @return true if the clip will change the current clip.
221      */

222     public boolean checkClip(Shape JavaDoc cl) {
223         if (getData().clip == null) {
224             if (cl != null) {
225                 return true;
226             }
227         } else if (!new Area JavaDoc(getData().clip).equals(new Area JavaDoc(cl))) {
228             return true;
229         }
230         //TODO check for clips that are larger than the current
231
return false;
232     }
233
234     /**
235      * Set the current clip.
236      * This either sets a new clip or sets the clip to the intersect of
237      * the old clip and the new clip.
238      *
239      * @param cl the new clip in the current state
240      */

241     public void setClip(Shape JavaDoc cl) {
242         if (getData().clip != null) {
243             Area JavaDoc newClip = new Area JavaDoc(getData().clip);
244             newClip.intersect(new Area JavaDoc(cl));
245             getData().clip = new GeneralPath JavaDoc(newClip);
246         } else {
247             getData().clip = cl;
248         }
249     }
250
251     /**
252      * Check the current transform.
253      * The transform for the current state is the combination of all
254      * transforms in the current state. The parameter is compared
255      * against this current transform.
256      *
257      * @param tf the transform the check against
258      * @return true if the new transform is different then the current transform
259      */

260     public boolean checkTransform(AffineTransform JavaDoc tf) {
261         return !tf.equals(getData().transform);
262     }
263
264     /**
265      * Set a new transform.
266      * This transform is appended to the transform of
267      * the current graphic state.
268      *
269      * @param tf the transform to concatonate to the current level transform
270      * @deprecated This method name is misleading. Use concatenate(AffineTransform) instead!
271      */

272     public void setTransform(AffineTransform JavaDoc tf) {
273         concatenate(tf);
274     }
275     
276     /**
277      * Concatenates the given AffineTransform to the current one.
278      * @param tf the transform to concatenate to the current level transform
279      */

280     public void concatenate(AffineTransform JavaDoc tf) {
281         getData().concatenate(tf);
282     }
283
284     /**
285      * Get the current transform.
286      * This gets the combination of all transforms in the
287      * current state.
288      *
289      * @return the calculate combined transform for the current state
290      */

291     public AffineTransform JavaDoc getTransform() {
292        AffineTransform JavaDoc tf;
293        AffineTransform JavaDoc at = new AffineTransform JavaDoc();
294        for (Iterator JavaDoc iter = stateStack.iterator(); iter.hasNext();) {
295            Data d = (Data)iter.next();
296            tf = d.transform;
297            at.concatenate(tf);
298        }
299        at.concatenate(getData().transform);
300        return at;
301     }
302
303     /**
304      * Get the grapics state.
305      * This gets the combination of all graphic states for
306      * the current context.
307      * This is the graphic state set with the gs operator not
308      * the other graphic state changes.
309      *
310      * @return the calculated ExtGState in the current context
311      */

312     public PDFGState getGState() {
313         PDFGState defaultState = PDFGState.DEFAULT;
314
315         PDFGState state;
316         PDFGState newstate = new PDFGState();
317         newstate.addValues(defaultState);
318         for (Iterator JavaDoc iter = stateStack.iterator(); iter.hasNext();) {
319             Data d = (Data)iter.next();
320             state = d.gstate;
321             if (state != null) {
322                 newstate.addValues(state);
323             }
324         }
325         if (getData().gstate != null) {
326             newstate.addValues(getData().gstate);
327         }
328
329         return newstate;
330     }
331     
332     public class Data implements Cloneable JavaDoc, Serializable JavaDoc {
333         
334         public Color JavaDoc color = Color.black;
335         public Color JavaDoc backcolor = Color.black;
336         public Paint JavaDoc paint = null;
337         public Paint JavaDoc backPaint = null;
338         public int lineCap = 0;
339         public int lineJoin = 0;
340         public float lineWidth = 1;
341         public float miterLimit = 0;
342         public boolean text = false;
343         public int dashOffset = 0;
344         public int[] dashArray = new int[0];
345         public AffineTransform JavaDoc transform = new AffineTransform JavaDoc();
346         public float fontSize = 0;
347         public String JavaDoc fontName = "";
348         public Shape JavaDoc clip = null;
349         public PDFGState gstate = null;
350
351         
352         /** @see java.lang.Object#clone() */
353         public Object JavaDoc clone() throws CloneNotSupportedException JavaDoc {
354             Data obj = new Data();
355             obj.color = this.color;
356             obj.backcolor = this.backcolor;
357             obj.paint = this.paint;
358             obj.backPaint = this.paint;
359             obj.lineCap = this.lineCap;
360             obj.lineJoin = this.lineJoin;
361             obj.lineWidth = this.lineWidth;
362             obj.miterLimit = this.miterLimit;
363             obj.text = this.text;
364             obj.dashOffset = this.dashOffset;
365             obj.dashArray = this.dashArray;
366             obj.transform = new AffineTransform JavaDoc(this.transform);
367             obj.fontSize = this.fontSize;
368             obj.fontName = this.fontName;
369             obj.clip = this.clip;
370             obj.gstate = this.gstate;
371             return obj;
372         }
373         
374         /**
375          * Get the current Transform.
376          */

377         public AffineTransform JavaDoc getTransform() {
378             return transform;
379         }
380
381         public void resetTransform() {
382             transform = new AffineTransform JavaDoc();
383         }
384
385         /**
386          * Concatenate the given AffineTransform with the current thus creating
387          * a new viewport. Note that all concatenation operations are logged
388          * so they can be replayed if necessary (ex. for block-containers with
389          * "fixed" positioning.
390          * @param at Transformation to perform
391          */

392         public void concatenate(AffineTransform JavaDoc at) {
393             transform.concatenate(at);
394         }
395         
396         /** @see java.lang.Object#toString() */
397         public String JavaDoc toString() {
398             return super.toString() + ", " + this.transform;
399         }
400     }
401 }
402
403
Popular Tags