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>, <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>, <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 }