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