Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: org/apache/batik/ext/awt/g2d/GraphicContext.java


1   /*
2   
3      Copyright 2001,2003  The Apache Software Foundation 
4   
5      Licensed under the Apache License, Version 2.0 (the "License");
6      you may not use this file except in compliance with the License.
7      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  package org.apache.batik.ext.awt.g2d;
19  
20  import java.awt.AlphaComposite;
21  import java.awt.BasicStroke;
22  import java.awt.Color;
23  import java.awt.Composite;
24  import java.awt.Font;
25  import java.awt.Paint;
26  import java.awt.Rectangle;
27  import java.awt.RenderingHints;
28  import java.awt.Shape;
29  import java.awt.Stroke;
30  import java.awt.font.FontRenderContext;
31  import java.awt.geom.AffineTransform;
32  import java.awt.geom.Area;
33  import java.awt.geom.GeneralPath;
34  import java.awt.geom.NoninvertibleTransformException;
35  import java.util.Map;
36  import java.util.Vector;
37  
38  /**
39   * Handles the attributes in a graphic context:<br>
40   * + Composite <br>
41   * + Font <br>
42   * + Paint <br>
43   * + Stroke <br>
44   * + Clip <br>
45   * + RenderingHints <br>
46   * + AffineTransform <br>
47   *
48   * @author <a href="mailto:cjolif@ilog.fr">Christophe Jolif</a>
49   * @author <a href="mailto:vincent.hardy@eng.sun.com">Vincent Hardy</a>
50   * @version $Id: GraphicContext.java,v 1.10 2005/04/02 14:26:09 deweese Exp $
51   */
52  public class GraphicContext implements Cloneable{
53      /**
54       * Default Transform to be used for creating FontRenderContext.
55       */
56      protected AffineTransform defaultTransform = new AffineTransform();
57  
58      /**
59       * Current AffineTransform. This is the concatenation
60       * of the original AffineTransform (i.e., last setTransform
61       * invocation) and the following transform invocations,
62       * as captured by originalTransform and the transformStack.
63       */
64      protected AffineTransform transform = new AffineTransform();
65  
66      /**
67       * Transform stack
68       */
69      protected Vector transformStack = new Vector();
70  
71      /**
72       * Defines whether the transform stack is valide or not.
73       * This is for use by the class clients. The client should
74       * validate the stack every time it starts using it. The
75       * stack becomes invalid when a new transform is set.
76       * @see #invalidateTransformStack()
77       * @see #isTransformStackValid
78       * @see #setTransform
79       */
80      protected boolean transformStackValid = true;
81  
82      /**
83       * Current Paint
84       */
85      protected Paint paint = Color.black;
86  
87      /**
88       * Current Stroke
89       */
90      protected Stroke stroke = new BasicStroke();
91  
92      /**
93       * Current Composite
94       */
95      protected Composite composite = AlphaComposite.SrcOver;
96  
97      /**
98       * Current clip
99       */
100     protected Shape clip = null;
101 
102     /**
103      * Current set of RenderingHints
104      */
105     protected RenderingHints hints = new RenderingHints(null);
106 
107     /**
108      * Current Font
109      */
110     protected Font font = new Font("sanserif", Font.PLAIN, 12);
111 
112     /**
113      * Current background color.
114      */
115     protected Color background = new Color(0, 0, 0, 0);
116 
117     /**
118      * Current foreground color
119      */
120     protected Color foreground = Color.black;
121 
122     /**
123      * Default constructor
124      */
125     public GraphicContext() {
126         // to workaround a JDK bug
127         hints.put(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_DEFAULT);
128     }
129 
130     /**
131      * @param defaultDeviceTransform Default affine transform applied to map the user space to the
132      *                               user space.
133      */
134     public GraphicContext(AffineTransform defaultDeviceTransform) {
135         this();
136         defaultTransform = new AffineTransform(defaultDeviceTransform);
137         transform = new AffineTransform(defaultTransform);
138         if (!defaultTransform.isIdentity())
139             transformStack.addElement(TransformStackElement.createGeneralTransformElement(defaultTransform));
140     }
141 
142     /**
143      * @return a deep copy of this context
144      */
145     public Object clone(){
146         GraphicContext copyGc = new GraphicContext(defaultTransform);
147 
148         //
149         // Now, copy each GC element in turn
150         //
151 
152         // Default transform
153         /* Set in constructor */
154 
155         // Transform
156         copyGc.transform = new AffineTransform(this.transform);
157 
158         // Transform stack
159         copyGc.transformStack = new Vector();
160         for(int i=0; i<this.transformStack.size(); i++){
161             TransformStackElement stackElement =
162                 (TransformStackElement)this.transformStack.elementAt(i);
163             copyGc.transformStack.addElement(stackElement.clone());
164         }
165 
166         // Transform stack validity
167         copyGc.transformStackValid = this.transformStackValid;
168 
169         // Paint (immutable by requirement)
170         copyGc.paint = this.paint;
171 
172         // Stroke (immutable by requirement)
173         copyGc.stroke = this.stroke;
174 
175         // Composite (immutable by requirement)
176         copyGc.composite = this.composite;
177 
178         // Clip
179         if(clip != null)
180             copyGc.clip = new GeneralPath(clip);
181         else
182             copyGc.clip = null;
183 
184         // RenderingHints
185         copyGc.hints = (RenderingHints)this.hints.clone();
186 
187         // Font (immutable)
188         copyGc.font = this.font;
189 
190         // Background, Foreground (immutable)
191         copyGc.background = this.background;
192         copyGc.foreground = this.foreground;
193 
194         return copyGc;
195     }
196 
197     /**
198      * Gets this graphics context's current color.
199      * @return    this graphics context's current color.
200      * @see       java.awt.Color
201      * @see       java.awt.Graphics#setColor
202      */
203     public Color getColor(){
204         return foreground;
205     }
206 
207     /**
208      * Sets this graphics context's current color to the specified
209      * color. All subsequent graphics operations using this graphics
210      * context use this specified color.
211      * @param     c   the new rendering color.
212      * @see       java.awt.Color
213      * @see       java.awt.Graphics#getColor
214      */
215     public void setColor(Color c){
216         if(c == null)
217             return;
218 
219         if(paint != c)
220             setPaint(c);
221     }
222 
223     /**
224      * Gets the current font.
225      * @return    this graphics context's current font.
226      * @see       java.awt.Font
227      * @see       java.awt.Graphics#setFont
228      */
229     public Font getFont(){
230         return font;
231     }
232 
233     /**
234      * Sets this graphics context's font to the specified font.
235      * All subsequent text operations using this graphics context
236      * use this font.
237      * @param  font   the font.
238      * @see     java.awt.Graphics#getFont
239      */
240     public void setFont(Font font){
241         if(font != null)
242             this.font = font;
243     }
244 
245     /**
246      * Returns the bounding rectangle of the current clipping area.
247      * This method refers to the user clip, which is independent of the
248      * clipping associated with device bounds and window visibility.
249      * If no clip has previously been set, or if the clip has been
250      * cleared using <code>setClip(null)</code>, this method returns
251      * <code>null</code>.
252      * The coordinates in the rectangle are relative to the coordinate
253      * system origin of this graphics context.
254      * @return      the bounding rectangle of the current clipping area,
255      *              or <code>null</code> if no clip is set.
256      * @see         java.awt.Graphics#getClip
257      * @see         java.awt.Graphics#clipRect
258      * @see         java.awt.Graphics#setClip(int, int, int, int)
259      * @see         java.awt.Graphics#setClip(Shape)
260      * @since       JDK1.1
261      */
262     public Rectangle getClipBounds(){
263         Shape c = getClip();
264         if(c==null)
265             return null;
266         else
267             return c.getBounds();
268     }
269 
270 
271     /**
272      * Intersects the current clip with the specified rectangle.
273      * The resulting clipping area is the intersection of the current
274      * clipping area and the specified rectangle.  If there is no
275      * current clipping area, either because the clip has never been
276      * set, or the clip has been cleared using <code>setClip(null)</code>,
277      * the specified rectangle becomes the new clip.
278      * This method sets the user clip, which is independent of the
279      * clipping associated with device bounds and window visibility.
280      * This method can only be used to make the current clip smaller.
281      * To set the current clip larger, use any of the setClip methods.
282      * Rendering operations have no effect outside of the clipping area.
283      * @param x the x coordinate of the rectangle to intersect the clip with
284      * @param y the y coordinate of the rectangle to intersect the clip with
285      * @param width the width of the rectangle to intersect the clip with
286      * @param height the height of the rectangle to intersect the clip with
287      * @see #setClip(int, int, int, int)
288      * @see #setClip(Shape)
289      */
290     public void clipRect(int x, int y, int width, int height){
291         clip(new Rectangle(x, y, width, height));
292     }
293 
294 
295     /**
296      * Sets the current clip to the rectangle specified by the given
297      * coordinates.  This method sets the user clip, which is
298      * independent of the clipping associated with device bounds
299      * and window visibility.
300      * Rendering operations have no effect outside of the clipping area.
301      * @param       x the <i>x</i> coordinate of the new clip rectangle.
302      * @param       y the <i>y</i> coordinate of the new clip rectangle.
303      * @param       width the width of the new clip rectangle.
304      * @param       height the height of the new clip rectangle.
305      * @see         java.awt.Graphics#clipRect
306      * @see         java.awt.Graphics#setClip(Shape)
307      * @since       JDK1.1
308      */
309     public void setClip(int x, int y, int width, int height){
310         setClip(new Rectangle(x, y, width, height));
311     }
312 
313 
314     /**
315      * Gets the current clipping area.
316      * This method returns the user clip, which is independent of the
317      * clipping associated with device bounds and window visibility.
318      * If no clip has previously been set, or if the clip has been
319      * cleared using <code>setClip(null)</code>, this method returns
320      * <code>null</code>.
321      * @return      a <code>Shape</code> object representing the
322      *              current clipping area, or <code>null</code> if
323      *              no clip is set.
324      * @see         java.awt.Graphics#getClipBounds
325      * @see         java.awt.Graphics#clipRect
326      * @see         java.awt.Graphics#setClip(int, int, int, int)
327      * @see         java.awt.Graphics#setClip(Shape)
328      * @since       JDK1.1
329      */
330     public Shape getClip(){
331         try{
332             return transform.createInverse().createTransformedShape(clip);
333         }catch(NoninvertibleTransformException e){
334             return null;
335         }
336     }
337 
338 
339     /**
340      * Sets the current clipping area to an arbitrary clip shape.
341      * Not all objects that implement the <code>Shape</code>
342      * interface can be used to set the clip.  The only
343      * <code>Shape</code> objects that are guaranteed to be
344      * supported are <code>Shape</code> objects that are
345      * obtained via the <code>getClip</code> method and via
346      * <code>Rectangle</code> objects.  This method sets the
347      * user clip, which is independent of the clipping associated
348      * with device bounds and window visibility.
349      * @param clip the <code>Shape</code> to use to set the clip
350      * @see         java.awt.Graphics#getClip()
351      * @see         java.awt.Graphics#clipRect
352      * @see         java.awt.Graphics#setClip(int, int, int, int)
353      * @since       JDK1.1
354      */
355     public void setClip(Shape clip) {
356         if (clip != null)
357             this.clip = transform.createTransformedShape(clip);
358         else
359             this.clip = null;
360     }
361 
362     /**
363      * Sets the <code>Composite</code> for the <code>Graphics2D</code> context.
364      * The <code>Composite</code> is used in all drawing methods such as
365      * <code>drawImage</code>, <code>drawString</code>, <code>draw</code>,
366      * and <code>fill</code>.  It specifies how new pixels are to be combined
367      * with the existing pixels on the graphics device during the rendering
368      * process.
369      * <p>If this <code>Graphics2D</code> context is drawing to a
370      * <code>Component</code> on the display screen and the
371      * <code>Composite</code> is a custom object rather than an
372      * instance of the <code>AlphaComposite</code> class, and if
373      * there is a security manager, its <code>checkPermission</code>
374      * method is called with an <code>AWTPermission("readDisplayPixels")</code>
375      * permission.
376      * @throws SecurityException
377      *         if a custom <code>Composite</code> object is being
378      *         used to render to the screen and a security manager
379      *         is set and its <code>checkPermission</code> method
380      *         does not allow the operation.
381      * @param comp the <code>Composite</code> object to be used for rendering
382      * @see java.awt.Graphics#setXORMode
383      * @see java.awt.Graphics#setPaintMode
384      * @see java.awt.AlphaComposite
385      */
386     public void setComposite(Composite comp){
387         this.composite = comp;
388     }
389 
390 
391     /**
392      * Sets the <code>Paint</code> attribute for the
393      * <code>Graphics2D</code> context.  Calling this method
394      * with a <code>null</code> <code>Paint</code> object does
395      * not have any effect on the current <code>Paint</code> attribute
396      * of this <code>Graphics2D</code>.
397      * @param paint the <code>Paint</code> object to be used to generate
398      * color during the rendering process, or <code>null</code>
399      * @see java.awt.Graphics#setColor
400      * @see java.awt.GradientPaint
401      * @see java.awt.TexturePaint
402      */
403     public void setPaint( Paint paint ){
404         if(paint == null)
405             return;
406 
407         this.paint = paint;
408         if(paint instanceof Color)
409             foreground = (Color)paint;
410     }
411 
412 
413     /**
414      * Sets the <code>Stroke</code> for the <code>Graphics2D</code> context.
415      * @param s the <code>Stroke</code> object to be used to stroke a
416      * <code>Shape</code> during the rendering process
417      * @see BasicStroke
418      */
419     public void setStroke(Stroke s){
420         stroke = s;
421     }
422 
423     /**
424      * Sets the value of a single preference for the rendering algorithms.
425      * Hint categories include controls for rendering quality and overall
426      * time/quality trade-off in the rendering process.  Refer to the
427      * <code>RenderingHints</code> class for definitions of some common
428      * keys and values.
429      * @param hintKey the key of the hint to be set.
430      * @param hintValue the value indicating preferences for the specified
431      * hint category.
432      * @see RenderingHints
433      */
434     public void setRenderingHint(RenderingHints.Key hintKey, Object hintValue){
435         hints.put(hintKey, hintValue);
436     }
437 
438 
439     /**
440      * Returns the value of a single preference for the rendering algorithms.
441      * Hint categories include controls for rendering quality and overall
442      * time/quality trade-off in the rendering process.  Refer to the
443      * <code>RenderingHints</code> class for definitions of some common
444      * keys and values.
445      * @param hintKey the key corresponding to the hint to get.
446      * @return an object representing the value for the specified hint key.
447      * Some of the keys and their associated values are defined in the
448      * <code>RenderingHints</code> class.
449      * @see RenderingHints
450      */
451     public Object getRenderingHint(RenderingHints.Key hintKey){
452         return hints.get(hintKey);
453     }
454 
455 
456     /**
457      * Replaces the values of all preferences for the rendering
458      * algorithms with the specified <code>hints</code>.
459      * The existing values for all rendering hints are discarded and
460      * the new set of known hints and values are initialized from the
461      * specified {@link Map} object.
462      * Hint categories include controls for rendering quality and
463      * overall time/quality trade-off in the rendering process.
464      * Refer to the <code>RenderingHints</code> class for definitions of
465      * some common keys and values.
466      * @param hints the rendering hints to be set
467      * @see RenderingHints
468      */
469     public void setRenderingHints(Map hints){
470         this.hints = new RenderingHints(hints);
471     }
472 
473 
474     /**
475      * Sets the values of an arbitrary number of preferences for the
476      * rendering algorithms.
477      * Only values for the rendering hints that are present in the
478      * specified <code>Map</code> object are modified.
479      * All other preferences not present in the specified
480      * object are left unmodified.
481      * Hint categories include controls for rendering quality and
482      * overall time/quality trade-off in the rendering process.
483      * Refer to the <code>RenderingHints</code> class for definitions of
484      * some common keys and values.
485      * @param hints the rendering hints to be set
486      * @see RenderingHints
487      */
488     public void addRenderingHints(Map hints){
489         this.hints.putAll(hints);
490     }
491 
492 
493     /**
494      * Gets the preferences for the rendering algorithms.  Hint categories
495      * include controls for rendering quality and overall time/quality
496      * trade-off in the rendering process.
497      * Returns all of the hint key/value pairs that were ever specified in
498      * one operation.  Refer to the
499      * <code>RenderingHints</code> class for definitions of some common
500      * keys and values.
501      * @return a reference to an instance of <code>RenderingHints</code>
502      * that contains the current preferences.
503      * @see RenderingHints
504      */
505     public RenderingHints getRenderingHints(){
506         return hints;
507     }
508 
509     /**
510      * Translates the origin of the graphics context to the point
511      * (<i>x</i>,&nbsp;<i>y</i>) in the current coordinate system.
512      * Modifies this graphics context so that its new origin corresponds
513      * to the point (<i>x</i>,&nbsp;<i>y</i>) in this graphics context's
514      * original coordinate system.  All coordinates used in subsequent
515      * rendering operations on this graphics context will be relative
516      * to this new origin.
517      * @param  x   the <i>x</i> coordinate.
518      * @param  y   the <i>y</i> coordinate.
519      */
520     public void translate(int x, int y){
521         if(x!=0 || y!=0){
522             transform.translate(x, y);
523             transformStack.addElement(TransformStackElement.createTranslateElement(x, y));
524         }
525     }
526 
527 
528     /**
529      * Concatenates the current
530      * <code>Graphics2D</code> <code>Transform</code>
531      * with a translation transform.
532      * Subsequent rendering is translated by the specified
533      * distance relative to the previous position.
534      * This is equivalent to calling transform(T), where T is an
535      * <code>AffineTransform</code> represented by the following matrix:
536      * <pre>
537      *          [   1    0    tx  ]
538      *          [   0    1    ty  ]
539      *          [   0    0    1   ]
540      * </pre>
541      * @param tx the distance to translate along the x-axis
542      * @param ty the distance to translate along the y-axis
543      */
544     public void translate(double tx, double ty){
545         transform.translate(tx, ty);
546         transformStack.addElement(TransformStackElement.createTranslateElement(tx, ty));
547     }
548 
549     /**
550      * Concatenates the current <code>Graphics2D</code>
551      * <code>Transform</code> with a rotation transform.
552      * Subsequent rendering is rotated by the specified radians relative
553      * to the previous origin.
554      * This is equivalent to calling <code>transform(R)</code>, where R is an
555      * <code>AffineTransform</code> represented by the following matrix:
556      * <pre>
557      *          [   cos(theta)    -sin(theta)    0   ]
558      *          [   sin(theta)     cos(theta)    0   ]
559      *          [       0              0         1   ]
560      * </pre>
561      * Rotating with a positive angle theta rotates points on the positive
562      * x axis toward the positive y axis.
563      * @param theta the angle of rotation in radians
564      */
565     public void rotate(double theta){
566         transform.rotate(theta);
567         transformStack.addElement(TransformStackElement.createRotateElement(theta));
568     }
569 
570     /**
571      * Concatenates the current <code>Graphics2D</code>
572      * <code>Transform</code> with a translated rotation
573      * transform.  Subsequent rendering is transformed by a transform
574      * which is constructed by translating to the specified location,
575      * rotating by the specified radians, and translating back by the same
576      * amount as the original translation.  This is equivalent to the
577      * following sequence of calls:
578      * <pre>
579      *          translate(x, y);
580      *          rotate(theta);
581      *          translate(-x, -y);
582      * </pre>
583      * Rotating with a positive angle theta rotates points on the positive
584      * x axis toward the positive y axis.
585      * @param theta the angle of rotation in radians
586      * @param x x coordinate of the origin of the rotation
587      * @param y y coordinate of the origin of the rotation
588      */
589     public void rotate(double theta, double x, double y){
590         transform.rotate(theta, x, y);
591         transformStack.addElement(TransformStackElement.createTranslateElement(x, y));
592         transformStack.addElement(TransformStackElement.createRotateElement(theta));
593         transformStack.addElement(TransformStackElement.createTranslateElement(-x, -y));
594     }
595 
596     /**
597      * Concatenates the current <code>Graphics2D</code>
598      * <code>Transform</code> with a scaling transformation
599      * Subsequent rendering is resized according to the specified scaling
600      * factors relative to the previous scaling.
601      * This is equivalent to calling <code>transform(S)</code>, where S is an
602      * <code>AffineTransform</code> represented by the following matrix:
603      * <pre>
604      *          [   sx   0    0   ]
605      *          [   0    sy   0   ]
606      *          [   0    0    1   ]
607      * </pre>
608      * @param sx the amount by which X coordinates in subsequent
609      * rendering operations are multiplied relative to previous
610      * rendering operations.
611      * @param sy the amount by which Y coordinates in subsequent
612      * rendering operations are multiplied relative to previous
613      * rendering operations.
614      */
615     public void scale(double sx, double sy){
616         transform.scale(sx, sy);
617         transformStack.addElement(TransformStackElement.createScaleElement(sx, sy));
618     }
619 
620     /**
621      * Concatenates the current <code>Graphics2D</code>
622      * <code>Transform</code> with a shearing transform.
623      * Subsequent renderings are sheared by the specified
624      * multiplier relative to the previous position.
625      * This is equivalent to calling <code>transform(SH)</code>, where SH
626      * is an <code>AffineTransform</code> represented by the following
627      * matrix:
628      * <pre>
629      *          [   1   shx   0   ]
630      *          [  shy   1    0   ]
631      *          [   0    0    1   ]
632      * </pre>
633      * @param shx the multiplier by which coordinates are shifted in
634      * the positive X axis direction as a function of their Y coordinate
635      * @param shy the multiplier by which coordinates are shifted in
636      * the positive Y axis direction as a function of their X coordinate
637      */
638     public void shear(double shx, double shy){
639         transform.shear(shx, shy);
640         transformStack.addElement(TransformStackElement.createShearElement(shx, shy));
641     }
642 
643     /**
644      * Composes an <code>AffineTransform</code> object with the
645      * <code>Transform</code> in this <code>Graphics2D</code> according
646      * to the rule last-specified-first-applied.  If the current
647      * <code>Transform</code> is Cx, the result of composition
648      * with Tx is a new <code>Transform</code> Cx'.  Cx' becomes the
649      * current <code>Transform</code> for this <code>Graphics2D</code>.
650      * Transforming a point p by the updated <code>Transform</code> Cx' is
651      * equivalent to first transforming p by Tx and then transforming
652      * the result by the original <code>Transform</code> Cx.  In other
653      * words, Cx'(p) = Cx(Tx(p)).  A copy of the Tx is made, if necessary,
654      * so further modifications to Tx do not affect rendering.
655      * @param Tx the <code>AffineTransform</code> object to be composed with
656      * the current <code>Transform</code>
657      * @see #setTransform
658      * @see AffineTransform
659      */
660     public void transform(AffineTransform Tx){
661         transform.concatenate(Tx);
662         transformStack.addElement(TransformStackElement.createGeneralTransformElement(Tx));
663     }
664 
665     /**
666      * Sets the <code>Transform</code> in the <code>Graphics2D</code>
667      * context.
668      * @param Tx the <code>AffineTransform</code> object to be used in the
669      * rendering process
670      * @see #transform
671      * @see AffineTransform
672      */
673     public void setTransform(AffineTransform Tx){
674         transform = new AffineTransform(Tx);
675         invalidateTransformStack();
676         if(!Tx.isIdentity())
677             transformStack.addElement(TransformStackElement.createGeneralTransformElement(Tx));
678     }
679 
680     /**
681      * Marks the GraphicContext's isNewTransformStack to false
682      * as a memento that the current transform stack was read and
683      * has not been reset. Only the setTransform method can
684      * override this memento.
685      */
686     public void validateTransformStack(){
687         transformStackValid = true;
688     }
689 
690     /**
691      * Checks the status of the transform stack
692      */
693     public boolean isTransformStackValid(){
694         return transformStackValid;
695     }
696 
697     /**
698      * @return array containing the successive transforms that
699      *         were concatenated with the original one.
700      */
701     public TransformStackElement[] getTransformStack(){
702         TransformStackElement stack[] = new TransformStackElement[transformStack.size()];
703         transformStack.copyInto(stack);
704         return stack;
705     }
706 
707     /**
708      * Marks the GraphicContext's isNewTransformStack to true
709      * as a memento that the current transform stack was reset
710      * since it was last read. Only validateTransformStack
711      * can override this memento
712      */
713     protected void invalidateTransformStack(){
714         transformStack.removeAllElements();
715         transformStackValid = false;
716     }
717 
718     /**
719      * Returns a copy of the current <code>Transform</code> in the
720      * <code>Graphics2D</code> context.
721      * @return the current <code>AffineTransform</code> in the
722      *             <code>Graphics2D</code> context.
723      * @see #transform
724      * @see #setTransform
725      */
726     public AffineTransform getTransform(){
727         return new AffineTransform(transform);
728     }
729 
730     /**
731      * Returns the current <code>Paint</code> of the
732      * <code>Graphics2D</code> context.
733      * @return the current <code>Graphics2D</code> <code>Paint</code>,
734      * which defines a color or pattern.
735      * @see #setPaint
736      * @see java.awt.Graphics#setColor
737      */
738     public Paint getPaint(){
739         return paint;
740     }
741 
742 
743     /**
744      * Returns the current <code>Composite</code> in the
745      * <code>Graphics2D</code> context.
746      * @return the current <code>Graphics2D</code> <code>Composite</code>,
747      *              which defines a compositing style.
748      * @see #setComposite
749      */
750     public Composite getComposite(){
751         return composite;
752     }
753 
754     /**
755      * Sets the background color for the <code>Graphics2D</code> context.
756      * The background color is used for clearing a region.
757      * When a <code>Graphics2D</code> is constructed for a
758      * <code>Component</code>, the background color is
759      * inherited from the <code>Component</code>. Setting the background color
760      * in the <code>Graphics2D</code> context only affects the subsequent
761      * <code>clearRect</code> calls and not the background color of the
762      * <code>Component</code>.  To change the background
763      * of the <code>Component</code>, use appropriate methods of
764      * the <code>Component</code>.
765      * @param color the background color that isused in
766      * subsequent calls to <code>clearRect</code>
767      * @see #getBackground
768      * @see java.awt.Graphics#clearRect
769      */
770     public void setBackground(Color color){
771         if(color == null)
772             return;
773 
774         background = color;
775     }
776 
777 
778     /**
779      * Returns the background color used for clearing a region.
780      * @return the current <code>Graphics2D</code> <code>Color</code>,
781      * which defines the background color.
782      * @see #setBackground
783      */
784     public Color getBackground(){
785         return background;
786     }
787 
788     /**
789      * Returns the current <code>Stroke</code> in the
790      * <code>Graphics2D</code> context.
791      * @return the current <code>Graphics2D</code> <code>Stroke</code>,
792      *                 which defines the line style.
793      * @see #setStroke
794      */
795     public Stroke getStroke(){
796         return stroke;
797     }
798 
799 
800     /**
801      * Intersects the current <code>Clip</code> with the interior of the
802      * specified <code>Shape</code> and sets the <code>Clip</code> to the
803      * resulting intersection.  The specified <code>Shape</code> is
804      * transformed with the current <code>Graphics2D</code>
805      * <code>Transform</code> before being intersected with the current
806      * <code>Clip</code>.  This method is used to make the current
807      * <code>Clip</code> smaller.
808      * To make the <code>Clip</code> larger, use <code>setClip</code>.
809      * The <i>user clip</i> modified by this method is independent of the
810      * clipping associated with device bounds and visibility.  If no clip has
811      * previously been set, or if the clip has been cleared using
812      * {@link java.awt.Graphics#setClip(Shape) setClip} with a
813      * <code>null</code> argument, the specified <code>Shape</code> becomes
814      * the new user clip.
815      * @param s the <code>Shape</code> to be intersected with the current
816      *          <code>Clip</code>.  If <code>s</code> is <code>null</code>,
817      *          this method clears the current <code>Clip</code>.
818      */
819     public void clip(Shape s){
820         if (s != null)
821             s = transform.createTransformedShape(s);
822 
823         if (clip != null) {
824             Area newClip = new Area(clip);
825             newClip.intersect(new Area(s));
826             clip = new GeneralPath(newClip);
827         } else {
828             clip = s;
829         }
830     }
831 
832     /**
833      * Get the rendering context of the <code>Font</code> within this
834      * <code>Graphics2D</code> context.
835      * The {@link FontRenderContext}
836      * encapsulates application hints such as anti-aliasing and
837      * fractional metrics, as well as target device specific information
838      * such as dots-per-inch.  This information should be provided by the
839      * application when using objects that perform typographical
840      * formatting, such as <code>Font</code> and
841      * <code>TextLayout</code>.  This information should also be provided
842      * by applications that perform their own layout and need accurate
843      * measurements of various characteristics of glyphs such as advance
844      * and line height when various rendering hints have been applied to
845      * the text rendering.
846      *
847      * @return a reference to an instance of FontRenderContext.
848      * @see java.awt.font.FontRenderContext
849      * @see java.awt.Font#createGlyphVector
850      * @see java.awt.font.TextLayout
851      * @since     JDK1.2
852      */
853     public FontRenderContext getFontRenderContext(){
854         //
855         // Find if antialiasing should be used.
856         //
857         Object antialiasingHint = hints.get(RenderingHints.KEY_TEXT_ANTIALIASING);
858         boolean isAntialiased = true;
859         if(antialiasingHint != RenderingHints.VALUE_TEXT_ANTIALIAS_ON &&
860            antialiasingHint != RenderingHints.VALUE_TEXT_ANTIALIAS_DEFAULT){
861 
862             // If antialias was not turned off, then use the general rendering
863             // hint.
864             if(antialiasingHint != RenderingHints.VALUE_TEXT_ANTIALIAS_OFF){
865                 antialiasingHint = hints.get(RenderingHints.KEY_ANTIALIASING);
866 
867                 // Test general hint
868                 if(antialiasingHint != RenderingHints.VALUE_ANTIALIAS_ON &&
869                    antialiasingHint != RenderingHints.VALUE_ANTIALIAS_DEFAULT){
870                     // Antialiasing was not requested. However, if it was not turned
871                     // off explicitly, use it.
872                     if(antialiasingHint == RenderingHints.VALUE_ANTIALIAS_OFF)
873                         isAntialiased = false;
874                 }
875             }
876             else
877                 isAntialiased = false;
878 
879         }
880 
881         //
882         // Find out whether fractional metrics should be used.
883         //
884         boolean useFractionalMetrics = true;
885         if(hints.get(RenderingHints.KEY_FRACTIONALMETRICS)
886            == RenderingHints.VALUE_FRACTIONALMETRICS_OFF)
887             useFractionalMetrics = false;
888 
889         FontRenderContext frc = new FontRenderContext(defaultTransform,
890                                                       isAntialiased,
891                                                       useFractionalMetrics);
892         return frc;
893     }
894 }