View Javadoc
1   /*
2    * Copyright (c) 1998, 2006, Oracle and/or its affiliates. All rights reserved.
3    * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4    *
5    * This code is free software; you can redistribute it and/or modify it
6    * under the terms of the GNU General Public License version 2 only, as
7    * published by the Free Software Foundation.  Oracle designates this
8    * particular file as subject to the "Classpath" exception as provided
9    * by Oracle in the LICENSE file that accompanied this code.
10   *
11   * This code is distributed in the hope that it will be useful, but WITHOUT
12   * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13   * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14   * version 2 for more details (a copy is included in the LICENSE file that
15   * accompanied this code).
16   *
17   * You should have received a copy of the GNU General Public License version
18   * 2 along with this work; if not, write to the Free Software Foundation,
19   * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20   *
21   * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22   * or visit www.oracle.com if you need additional information or have any
23   * questions.
24   */
25  
26  package sun.print;
27  
28  import java.util.Map;
29  
30  import java.awt.BasicStroke;
31  import java.awt.Color;
32  import java.awt.Composite;
33  import java.awt.Graphics;
34  import java.awt.Graphics2D;
35  import java.awt.Font;
36  import java.awt.FontMetrics;
37  import java.awt.font.FontRenderContext;
38  import java.awt.Graphics;
39  import java.awt.GraphicsConfiguration;
40  import java.awt.Image;
41  import java.awt.Paint;
42  import java.awt.Rectangle;
43  import java.awt.Shape;
44  import java.awt.Stroke;
45  import java.awt.RenderingHints;
46  import java.awt.RenderingHints.Key;
47  
48  import java.awt.font.GlyphVector;
49  import java.awt.font.TextLayout;
50  
51  import java.awt.geom.AffineTransform;
52  import java.awt.geom.Line2D;
53  import java.awt.geom.Point2D;
54  import java.awt.geom.Rectangle2D;
55  import java.awt.geom.RoundRectangle2D;
56  import java.awt.image.BufferedImage;
57  import java.awt.image.BufferedImageOp;
58  import java.awt.image.ImageObserver;
59  import java.awt.image.RenderedImage;
60  import java.awt.image.renderable.RenderableImage;
61  import java.awt.print.PrinterGraphics;
62  import java.awt.print.PrinterJob;
63  
64  import java.text.AttributedCharacterIterator;
65  
66  import sun.java2d.Spans;
67  
68  public class PeekGraphics extends Graphics2D
69                            implements PrinterGraphics,
70                                       ImageObserver,
71                                       Cloneable {
72  
73      /**
74       * Drawing methods will be forwarded to this object.
75       */
76      Graphics2D mGraphics;
77  
78      /**
79       * The PrinterJob controlling the current printing.
80       */
81      PrinterJob mPrinterJob;
82  
83      /**
84       * Keeps track of where drawing occurs on the page.
85       */
86      private Spans mDrawingArea = new Spans();
87  
88      /**
89       * Track information about the types of drawing
90       * performed by the printing application.
91       */
92      private PeekMetrics mPrintMetrics = new PeekMetrics();
93  
94      /**
95       * If true the application will only be drawing AWT style
96       * graphics, no Java2D graphics.
97       */
98      private boolean mAWTDrawingOnly = false;
99  
100     /**
101      * The new PeekGraphics2D will forward state changing
102      * calls to 'graphics'. 'printerJob' is stored away
103      * so that the printing application can get the PrinterJob
104      * if needed.
105      */
106     public PeekGraphics(Graphics2D graphics, PrinterJob printerJob) {
107 
108         mGraphics = graphics;
109         mPrinterJob = printerJob;
110     }
111 
112     /**
113      * Return the Graphics2D object that does the drawing
114      * for this instance.
115      */
116     public Graphics2D getDelegate() {
117         return mGraphics;
118     }
119 
120     /**
121      * Set the Graphics2D instance which will do the
122      * drawing.
123      */
124     public void setDelegate(Graphics2D graphics) {
125         mGraphics = graphics;
126     }
127 
128     public PrinterJob getPrinterJob() {
129         return mPrinterJob;
130     }
131 
132     /**
133      * The caller promises that only AWT graphics will be drawn.
134      * The print system can use this information to make general
135      * assumptions about the types of graphics to be drawn without
136      * requiring the application to draw the contents multiple
137      * times.
138      */
139     public void setAWTDrawingOnly() {
140         mAWTDrawingOnly = true;
141     }
142 
143     public boolean getAWTDrawingOnly() {
144         return mAWTDrawingOnly;
145     }
146 
147     /**
148      * Return a Spans instance describing the parts of the page in
149      * to which drawing occurred.
150      */
151     public Spans getDrawingArea() {
152         return mDrawingArea;
153     }
154 
155     /**
156      * Returns the device configuration associated with this Graphics2D.
157      */
158     public GraphicsConfiguration getDeviceConfiguration() {
159         return ((RasterPrinterJob)mPrinterJob).getPrinterGraphicsConfig();
160     }
161 
162 /* The Delegated Graphics Methods */
163 
164     /**
165      * Creates a new <code>Graphics</code> object that is
166      * a copy of this <code>Graphics</code> object.
167      * @return     a new graphics context that is a copy of
168      *                       this graphics context.
169      * @since      JDK1.0
170      */
171     public Graphics create() {
172         PeekGraphics newGraphics = null;
173 
174         try {
175             newGraphics = (PeekGraphics) clone();
176             newGraphics.mGraphics = (Graphics2D) mGraphics.create();
177 
178         /* This exception can not happen unless this
179          * class no longer implements the Cloneable
180          * interface.
181          */
182         } catch (CloneNotSupportedException e) {
183             // can never happen.
184         }
185 
186         return newGraphics;
187     }
188 
189     /**
190      * Translates the origin of the graphics context to the point
191      * (<i>x</i>,&nbsp;<i>y</i>) in the current coordinate system.
192      * Modifies this graphics context so that its new origin corresponds
193      * to the point (<i>x</i>,&nbsp;<i>y</i>) in this graphics context's
194      * original coordinate system.  All coordinates used in subsequent
195      * rendering operations on this graphics context will be relative
196      * to this new origin.
197      * @param  x   the <i>x</i> coordinate.
198      * @param  y   the <i>y</i> coordinate.
199      * @since   JDK1.0
200      */
201     public void translate(int x, int y) {
202         mGraphics.translate(x, y);
203     }
204 
205     /**
206      * Concatenates the current transform of this Graphics2D with a
207      * translation transformation.
208      * This is equivalent to calling transform(T), where T is an
209      * AffineTransform represented by the following matrix:
210      * <pre>
211      *          [   1    0    tx  ]
212      *          [   0    1    ty  ]
213      *          [   0    0    1   ]
214      * </pre>
215      */
216     public void translate(double tx, double ty) {
217         mGraphics.translate(tx, ty);
218     }
219 
220     /**
221      * Concatenates the current transform of this Graphics2D with a
222      * rotation transformation.
223      * This is equivalent to calling transform(R), where R is an
224      * AffineTransform represented by the following matrix:
225      * <pre>
226      *          [   cos(theta)    -sin(theta)    0   ]
227      *          [   sin(theta)     cos(theta)    0   ]
228      *          [       0              0         1   ]
229      * </pre>
230      * Rotating with a positive angle theta rotates points on the positive
231      * x axis toward the positive y axis.
232      * @param theta The angle of rotation in radians.
233      */
234     public void rotate(double theta) {
235         mGraphics.rotate(theta);
236     }
237 
238     /**
239      * Concatenates the current transform of this Graphics2D with a
240      * translated rotation transformation.
241      * This is equivalent to the following sequence of calls:
242      * <pre>
243      *          translate(x, y);
244      *          rotate(theta);
245      *          translate(-x, -y);
246      * </pre>
247      * Rotating with a positive angle theta rotates points on the positive
248      * x axis toward the positive y axis.
249      * @param theta The angle of rotation in radians.
250      * @param x The x coordinate of the origin of the rotation
251      * @param y The x coordinate of the origin of the rotation
252      */
253     public void rotate(double theta, double x, double y) {
254         mGraphics.rotate(theta, x, y);
255     }
256 
257     /**
258      * Concatenates the current transform of this Graphics2D with a
259      * scaling transformation.
260      * This is equivalent to calling transform(S), where S is an
261      * AffineTransform represented by the following matrix:
262      * <pre>
263      *          [   sx   0    0   ]
264      *          [   0    sy   0   ]
265      *          [   0    0    1   ]
266      * </pre>
267      */
268     public void scale(double sx, double sy) {
269         mGraphics.scale(sx, sy);
270     }
271 
272     /**
273      * Concatenates the current transform of this Graphics2D with a
274      * shearing transformation.
275      * This is equivalent to calling transform(SH), where SH is an
276      * AffineTransform represented by the following matrix:
277      * <pre>
278      *          [   1   shx   0   ]
279      *          [  shy   1    0   ]
280      *          [   0    0    1   ]
281      * </pre>
282      * @param shx The factor by which coordinates are shifted towards the
283      * positive X axis direction according to their Y coordinate
284      * @param shy The factor by which coordinates are shifted towards the
285      * positive Y axis direction according to their X coordinate
286      */
287     public void shear(double shx, double shy) {
288         mGraphics.shear(shx, shy);
289     }
290 
291     /**
292      * Gets this graphics context's current color.
293      * @return    this graphics context's current color.
294      * @see       java.awt.Color
295      * @see       java.awt.Graphics#setColor
296      * @since     JDK1.0
297      */
298     public Color getColor() {
299         return mGraphics.getColor();
300     }
301 
302     /**
303      * Sets this graphics context's current color to the specified
304      * color. All subsequent graphics operations using this graphics
305      * context use this specified color.
306      * @param     c   the new rendering color.
307      * @see       java.awt.Color
308      * @see       java.awt.Graphics#getColor
309      * @since     JDK1.0
310      */
311     public void setColor(Color c) {
312         mGraphics.setColor(c);
313     }
314 
315     /**
316      * Sets the paint mode of this graphics context to overwrite the
317      * destination with this graphics context's current color.
318      * This sets the logical pixel operation function to the paint or
319      * overwrite mode.  All subsequent rendering operations will
320      * overwrite the destination with the current color.
321      * @since   JDK1.0
322      */
323     public void setPaintMode() {
324         mGraphics.setPaintMode();
325     }
326 
327     /**
328      * Sets the paint mode of this graphics context to alternate between
329      * this graphics context's current color and the new specified color.
330      * This specifies that logical pixel operations are performed in the
331      * XOR mode, which alternates pixels between the current color and
332      * a specified XOR color.
333      * <p>
334      * When drawing operations are performed, pixels which are the
335      * current color are changed to the specified color, and vice versa.
336      * <p>
337      * Pixels that are of colors other than those two colors are changed
338      * in an unpredictable but reversible manner; if the same figure is
339      * drawn twice, then all pixels are restored to their original values.
340      * @param     c1 the XOR alternation color
341      * @since     JDK1.0
342      */
343     public void setXORMode(Color c1) {
344         mGraphics.setXORMode(c1);
345     }
346 
347     /**
348      * Gets the current font.
349      * @return    this graphics context's current font.
350      * @see       java.awt.Font
351      * @see       java.awt.Graphics#setFont
352      * @since     JDK1.0
353      */
354     public Font getFont() {
355         return mGraphics.getFont();
356     }
357 
358     /**
359      * Sets this graphics context's font to the specified font.
360      * All subsequent text operations using this graphics context
361      * use this font.
362      * @param  font   the font.
363      * @see     java.awt.Graphics#getFont
364      * @see     java.awt.Graphics#drawChars(java.lang.String, int, int)
365      * @see     java.awt.Graphics#drawString(byte[], int, int, int, int)
366      * @see     java.awt.Graphics#drawBytes(char[], int, int, int, int)
367      * @since   JDK1.0
368     */
369     public void setFont(Font font) {
370         mGraphics.setFont(font);
371     }
372 
373     /**
374      * Gets the font metrics for the specified font.
375      * @return    the font metrics for the specified font.
376      * @param     f the specified font
377      * @see       java.awt.Graphics#getFont
378      * @see       java.awt.FontMetrics
379      * @see       java.awt.Graphics#getFontMetrics()
380      * @since     JDK1.0
381      */
382     public FontMetrics getFontMetrics(Font f) {
383         return mGraphics.getFontMetrics(f);
384     }
385 
386     /**
387     * Get the rendering context of the font
388     * within this Graphics2D context.
389     */
390     public FontRenderContext getFontRenderContext() {
391         return mGraphics.getFontRenderContext();
392     }
393 
394     /**
395      * Returns the bounding rectangle of the current clipping area.
396      * The coordinates in the rectangle are relative to the coordinate
397      * system origin of this graphics context.
398      * @return      the bounding rectangle of the current clipping area.
399      * @see         java.awt.Graphics#getClip
400      * @see         java.awt.Graphics#clipRect
401      * @see         java.awt.Graphics#setClip(int, int, int, int)
402      * @see         java.awt.Graphics#setClip(Shape)
403      * @since       JDK1.1
404      */
405     public Rectangle getClipBounds() {
406         return mGraphics.getClipBounds();
407     }
408 
409 
410     /**
411      * Intersects the current clip with the specified rectangle.
412      * The resulting clipping area is the intersection of the current
413      * clipping area and the specified rectangle.
414      * This method can only be used to make the current clip smaller.
415      * To set the current clip larger, use any of the setClip methods.
416      * Rendering operations have no effect outside of the clipping area.
417      * @param x the x coordinate of the rectangle to intersect the clip with
418      * @param y the y coordinate of the rectangle to intersect the clip with
419      * @param width the width of the rectangle to intersect the clip with
420      * @param height the height of the rectangle to intersect the clip with
421      * @see #setClip(int, int, int, int)
422      * @see #setClip(Shape)
423      */
424     public void clipRect(int x, int y, int width, int height) {
425         mGraphics.clipRect(x, y, width, height);
426     }
427 
428 
429     /**
430      * Sets the current clip to the rectangle specified by the given
431      * coordinates.
432      * Rendering operations have no effect outside of the clipping area.
433      * @param       x the <i>x</i> coordinate of the new clip rectangle.
434      * @param       y the <i>y</i> coordinate of the new clip rectangle.
435      * @param       width the width of the new clip rectangle.
436      * @param       height the height of the new clip rectangle.
437      * @see         java.awt.Graphics#clipRect
438      * @see         java.awt.Graphics#setClip(Shape)
439      * @since       JDK1.1
440      */
441     public void setClip(int x, int y, int width, int height) {
442         mGraphics.setClip(x, y, width, height);
443     }
444 
445     /**
446      * Gets the current clipping area.
447      * @return      a <code>Shape</code> object representing the
448      *                      current clipping area.
449      * @see         java.awt.Graphics#getClipBounds
450      * @see         java.awt.Graphics#clipRect
451      * @see         java.awt.Graphics#setClip(int, int, int, int)
452      * @see         java.awt.Graphics#setClip(Shape)
453      * @since       JDK1.1
454      */
455     public Shape getClip() {
456         return mGraphics.getClip();
457     }
458 
459 
460     /**
461      * Sets the current clipping area to an arbitrary clip shape.
462      * Not all objects which implement the <code>Shape</code>
463      * interface can be used to set the clip.  The only
464      * <code>Shape</code> objects which are guaranteed to be
465      * supported are <code>Shape</code> objects which are
466      * obtained via the <code>getClip</code> method and via
467      * <code>Rectangle</code> objects.
468      * @see         java.awt.Graphics#getClip()
469      * @see         java.awt.Graphics#clipRect
470      * @see         java.awt.Graphics#setClip(int, int, int, int)
471      * @since       JDK1.1
472      */
473     public void setClip(Shape clip) {
474         mGraphics.setClip(clip);
475     }
476 
477 
478     /**
479      * Copies an area of the component by a distance specified by
480      * <code>dx</code> and <code>dy</code>. From the point specified
481      * by <code>x</code> and <code>y</code>, this method
482      * copies downwards and to the right.  To copy an area of the
483      * component to the left or upwards, specify a negative value for
484      * <code>dx</code> or <code>dy</code>.
485      * If a portion of the source rectangle lies outside the bounds
486      * of the component, or is obscured by another window or component,
487      * <code>copyArea</code> will be unable to copy the associated
488      * pixels. The area that is omitted can be refreshed by calling
489      * the component's <code>paint</code> method.
490      * @param       x the <i>x</i> coordinate of the source rectangle.
491      * @param       y the <i>y</i> coordinate of the source rectangle.
492      * @param       width the width of the source rectangle.
493      * @param       height the height of the source rectangle.
494      * @param       dx the horizontal distance to copy the pixels.
495      * @param       dy the vertical distance to copy the pixels.
496      * @since       JDK1.0
497      */
498     public void copyArea(int x, int y, int width, int height,
499                          int dx, int dy) {
500         // This method is not supported for printing so we do nothing here.
501     }
502 
503     /**
504      * Draws a line, using the current color, between the points
505      * <code>(x1,&nbsp;y1)</code> and <code>(x2,&nbsp;y2)</code>
506      * in this graphics context's coordinate system.
507      * @param   x1  the first point's <i>x</i> coordinate.
508      * @param   y1  the first point's <i>y</i> coordinate.
509      * @param   x2  the second point's <i>x</i> coordinate.
510      * @param   y2  the second point's <i>y</i> coordinate.
511      * @since   JDK1.0
512      */
513     public void drawLine(int x1, int y1, int x2, int y2) {
514         addStrokeShape(new Line2D.Float(x1, y1, x2, y2));
515         mPrintMetrics.draw(this);
516     }
517 
518 
519 
520     /**
521      * Fills the specified rectangle.
522      * The left and right edges of the rectangle are at
523      * <code>x</code> and <code>x&nbsp;+&nbsp;width&nbsp;-&nbsp;1</code>.
524      * The top and bottom edges are at
525      * <code>y</code> and <code>y&nbsp;+&nbsp;height&nbsp;-&nbsp;1</code>.
526      * The resulting rectangle covers an area
527      * <code>width</code> pixels wide by
528      * <code>height</code> pixels tall.
529      * The rectangle is filled using the graphics context's current color.
530      * @param         x   the <i>x</i> coordinate
531      *                         of the rectangle to be filled.
532      * @param         y   the <i>y</i> coordinate
533      *                         of the rectangle to be filled.
534      * @param         width   the width of the rectangle to be filled.
535      * @param         height   the height of the rectangle to be filled.
536      * @see           java.awt.Graphics#fillRect
537      * @see           java.awt.Graphics#clearRect
538      * @since         JDK1.0
539      */
540     public void fillRect(int x, int y, int width, int height) {
541 
542         addDrawingRect(new Rectangle2D.Float(x, y, width, height));
543         mPrintMetrics.fill(this);
544 
545     }
546 
547     /**
548      * Clears the specified rectangle by filling it with the background
549      * color of the current drawing surface. This operation does not
550      * use the current paint mode.
551      * <p>
552      * Beginning with Java&nbsp;1.1, the background color
553      * of offscreen images may be system dependent. Applications should
554      * use <code>setColor</code> followed by <code>fillRect</code> to
555      * ensure that an offscreen image is cleared to a specific color.
556      * @param       x the <i>x</i> coordinate of the rectangle to clear.
557      * @param       y the <i>y</i> coordinate of the rectangle to clear.
558      * @param       width the width of the rectangle to clear.
559      * @param       height the height of the rectangle to clear.
560      * @see         java.awt.Graphics#fillRect(int, int, int, int)
561      * @see         java.awt.Graphics#drawRect
562      * @see         java.awt.Graphics#setColor(java.awt.Color)
563      * @see         java.awt.Graphics#setPaintMode
564      * @see         java.awt.Graphics#setXORMode(java.awt.Color)
565      * @since       JDK1.0
566      */
567     public void clearRect(int x, int y, int width, int height) {
568         Rectangle2D.Float rect = new Rectangle2D.Float(x, y, width, height);
569         addDrawingRect(rect);
570         mPrintMetrics.clear(this);
571     }
572 
573     /**
574      * Draws an outlined round-cornered rectangle using this graphics
575      * context's current color. The left and right edges of the rectangle
576      * are at <code>x</code> and <code>x&nbsp;+&nbsp;width</code>,
577      * respectively. The top and bottom edges of the rectangle are at
578      * <code>y</code> and <code>y&nbsp;+&nbsp;height</code>.
579      * @param      x the <i>x</i> coordinate of the rectangle to be drawn.
580      * @param      y the <i>y</i> coordinate of the rectangle to be drawn.
581      * @param      width the width of the rectangle to be drawn.
582      * @param      height the height of the rectangle to be drawn.
583      * @param      arcWidth the horizontal diameter of the arc
584      *                    at the four corners.
585      * @param      arcHeight the vertical diameter of the arc
586      *                    at the four corners.
587      * @see        java.awt.Graphics#fillRoundRect
588      * @since      JDK1.0
589      */
590     public void drawRoundRect(int x, int y, int width, int height,
591                               int arcWidth, int arcHeight) {
592         addStrokeShape(new RoundRectangle2D.Float(x, y, width, height, arcWidth, arcHeight));
593         mPrintMetrics.draw(this);
594 
595     }
596 
597     /**
598      * Fills the specified rounded corner rectangle with the current color.
599      * The left and right edges of the rectangle
600      * are at <code>x</code> and <code>x&nbsp;+&nbsp;width&nbsp;-&nbsp;1</code>,
601      * respectively. The top and bottom edges of the rectangle are at
602      * <code>y</code> and <code>y&nbsp;+&nbsp;height&nbsp;-&nbsp;1</code>.
603      * @param       x the <i>x</i> coordinate of the rectangle to be filled.
604      * @param       y the <i>y</i> coordinate of the rectangle to be filled.
605      * @param       width the width of the rectangle to be filled.
606      * @param       height the height of the rectangle to be filled.
607      * @param       arcWidth the horizontal diameter
608      *                     of the arc at the four corners.
609      * @param       arcHeight the vertical diameter
610      *                     of the arc at the four corners.
611      * @see         java.awt.Graphics#drawRoundRect
612      * @since       JDK1.0
613      */
614     public void fillRoundRect(int x, int y, int width, int height,
615                                        int arcWidth, int arcHeight) {
616         Rectangle2D.Float rect = new Rectangle2D.Float(x, y,width, height);
617         addDrawingRect(rect);
618         mPrintMetrics.fill(this);
619     }
620 
621     /**
622      * Draws the outline of an oval.
623      * The result is a circle or ellipse that fits within the
624      * rectangle specified by the <code>x</code>, <code>y</code>,
625      * <code>width</code>, and <code>height</code> arguments.
626      * <p>
627      * The oval covers an area that is
628      * <code>width&nbsp;+&nbsp;1</code> pixels wide
629      * and <code>height&nbsp;+&nbsp;1</code> pixels tall.
630      * @param       x the <i>x</i> coordinate of the upper left
631      *                     corner of the oval to be drawn.
632      * @param       y the <i>y</i> coordinate of the upper left
633      *                     corner of the oval to be drawn.
634      * @param       width the width of the oval to be drawn.
635      * @param       height the height of the oval to be drawn.
636      * @see         java.awt.Graphics#fillOval
637      * @since       JDK1.0
638      */
639     public void drawOval(int x, int y, int width, int height) {
640         addStrokeShape(new Rectangle2D.Float(x, y,  width, height));
641         mPrintMetrics.draw(this);
642     }
643 
644     /**
645      * Fills an oval bounded by the specified rectangle with the
646      * current color.
647      * @param       x the <i>x</i> coordinate of the upper left corner
648      *                     of the oval to be filled.
649      * @param       y the <i>y</i> coordinate of the upper left corner
650      *                     of the oval to be filled.
651      * @param       width the width of the oval to be filled.
652      * @param       height the height of the oval to be filled.
653      * @see         java.awt.Graphics#drawOval
654      * @since       JDK1.0
655      */
656     public void fillOval(int x, int y, int width, int height) {
657         Rectangle2D.Float rect = new Rectangle2D.Float(x, y, width, height);
658         addDrawingRect(rect);
659         mPrintMetrics.fill(this);
660 
661     }
662 
663 
664     /**
665      * Draws the outline of a circular or elliptical arc
666      * covering the specified rectangle.
667      * <p>
668      * The resulting arc begins at <code>startAngle</code> and extends
669      * for <code>arcAngle</code> degrees, using the current color.
670      * Angles are interpreted such that 0&nbsp;degrees
671      * is at the 3&nbsp;o'clock position.
672      * A positive value indicates a counter-clockwise rotation
673      * while a negative value indicates a clockwise rotation.
674      * <p>
675      * The center of the arc is the center of the rectangle whose origin
676      * is (<i>x</i>,&nbsp;<i>y</i>) and whose size is specified by the
677      * <code>width</code> and <code>height</code> arguments.
678      * <p>
679      * The resulting arc covers an area
680      * <code>width&nbsp;+&nbsp;1</code> pixels wide
681      * by <code>height&nbsp;+&nbsp;1</code> pixels tall.
682      * @param        x the <i>x</i> coordinate of the
683      *                    upper-left corner of the arc to be drawn.
684      * @param        y the <i>y</i>  coordinate of the
685      *                    upper-left corner of the arc to be drawn.
686      * @param        width the width of the arc to be drawn.
687      * @param        height the height of the arc to be drawn.
688      * @param        startAngle the beginning angle.
689      * @param        arcAngle the angular extent of the arc,
690      *                    relative to the start angle.
691      * @see         java.awt.Graphics#fillArc
692      * @since       JDK1.0
693      */
694     public void drawArc(int x, int y, int width, int height,
695                                  int startAngle, int arcAngle) {
696         addStrokeShape(new Rectangle2D.Float(x, y,  width, height));
697         mPrintMetrics.draw(this);
698 
699     }
700 
701     /**
702      * Fills a circular or elliptical arc covering the specified rectangle.
703      * <p>
704      * The resulting arc begins at <code>startAngle</code> and extends
705      * for <code>arcAngle</code> degrees.
706      * Angles are interpreted such that 0&nbsp;degrees
707      * is at the 3&nbsp;o'clock position.
708      * A positive value indicates a counter-clockwise rotation
709      * while a negative value indicates a clockwise rotation.
710      * <p>
711      * The center of the arc is the center of the rectangle whose origin
712      * is (<i>x</i>,&nbsp;<i>y</i>) and whose size is specified by the
713      * <code>width</code> and <code>height</code> arguments.
714      * <p>
715      * The resulting arc covers an area
716      * <code>width&nbsp;+&nbsp;1</code> pixels wide
717      * by <code>height&nbsp;+&nbsp;1</code> pixels tall.
718      * @param        x the <i>x</i> coordinate of the
719      *                    upper-left corner of the arc to be filled.
720      * @param        y the <i>y</i>  coordinate of the
721      *                    upper-left corner of the arc to be filled.
722      * @param        width the width of the arc to be filled.
723      * @param        height the height of the arc to be filled.
724      * @param        startAngle the beginning angle.
725      * @param        arcAngle the angular extent of the arc,
726      *                    relative to the start angle.
727      * @see         java.awt.Graphics#drawArc
728      * @since       JDK1.0
729      */
730     public void fillArc(int x, int y, int width, int height,
731                         int startAngle, int arcAngle) {
732         Rectangle2D.Float rect = new Rectangle2D.Float(x, y,width, height);
733         addDrawingRect(rect);
734         mPrintMetrics.fill(this);
735 
736     }
737 
738     /**
739      * Draws a sequence of connected lines defined by
740      * arrays of <i>x</i> and <i>y</i> coordinates.
741      * Each pair of (<i>x</i>,&nbsp;<i>y</i>) coordinates defines a point.
742      * The figure is not closed if the first point
743      * differs from the last point.
744      * @param       xPoints an array of <i>x</i> points
745      * @param       yPoints an array of <i>y</i> points
746      * @param       nPoints the total number of points
747      * @see         java.awt.Graphics#drawPolygon(int[], int[], int)
748      * @since       JDK1.1
749      */
750    public void drawPolyline(int xPoints[], int yPoints[],
751                              int nPoints) {
752         if (nPoints > 0) {
753             int x = xPoints[0];
754             int y = yPoints[0];
755 
756             for (int i = 1; i < nPoints; i++) {
757                 drawLine(x, y, xPoints[i], yPoints[i]);
758                 x = xPoints[i];
759                 y = yPoints[i];
760             }
761         }
762 
763     }
764 
765     /**
766      * Draws a closed polygon defined by
767      * arrays of <i>x</i> and <i>y</i> coordinates.
768      * Each pair of (<i>x</i>,&nbsp;<i>y</i>) coordinates defines a point.
769      * <p>
770      * This method draws the polygon defined by <code>nPoint</code> line
771      * segments, where the first <code>nPoint&nbsp;-&nbsp;1</code>
772      * line segments are line segments from
773      * <code>(xPoints[i&nbsp;-&nbsp;1],&nbsp;yPoints[i&nbsp;-&nbsp;1])</code>
774      * to <code>(xPoints[i],&nbsp;yPoints[i])</code>, for
775      * 1&nbsp;&le;&nbsp;<i>i</i>&nbsp;&le;&nbsp;<code>nPoints</code>.
776      * The figure is automatically closed by drawing a line connecting
777      * the final point to the first point, if those points are different.
778      * @param        xPoints   a an array of <code>x</code> coordinates.
779      * @param        yPoints   a an array of <code>y</code> coordinates.
780      * @param        nPoints   a the total number of points.
781      * @see          java.awt.Graphics#fillPolygon
782      * @see          java.awt.Graphics#drawPolyline
783      * @since        JDK1.0
784      */
785     public void drawPolygon(int xPoints[], int yPoints[],
786                             int nPoints) {
787         if (nPoints > 0) {
788             drawPolyline(xPoints, yPoints, nPoints);
789             drawLine(xPoints[nPoints - 1], yPoints[nPoints - 1],
790                      xPoints[0], yPoints[0]);
791         }
792 
793     }
794 
795     /**
796      * Fills a closed polygon defined by
797      * arrays of <i>x</i> and <i>y</i> coordinates.
798      * <p>
799      * This method draws the polygon defined by <code>nPoint</code> line
800      * segments, where the first <code>nPoint&nbsp;-&nbsp;1</code>
801      * line segments are line segments from
802      * <code>(xPoints[i&nbsp;-&nbsp;1],&nbsp;yPoints[i&nbsp;-&nbsp;1])</code>
803      * to <code>(xPoints[i],&nbsp;yPoints[i])</code>, for
804      * 1&nbsp;&le;&nbsp;<i>i</i>&nbsp;&le;&nbsp;<code>nPoints</code>.
805      * The figure is automatically closed by drawing a line connecting
806      * the final point to the first point, if those points are different.
807      * <p>
808      * The area inside the polygon is defined using an
809      * even-odd fill rule, also known as the alternating rule.
810      * @param        xPoints   a an array of <code>x</code> coordinates.
811      * @param        yPoints   a an array of <code>y</code> coordinates.
812      * @param        nPoints   a the total number of points.
813      * @see          java.awt.Graphics#drawPolygon(int[], int[], int)
814      * @since        JDK1.0
815      */
816     public void fillPolygon(int xPoints[], int yPoints[],
817                             int nPoints) {
818         if (nPoints > 0) {
819             int minX = xPoints[0];
820             int minY = yPoints[0];
821             int maxX = xPoints[0];
822             int maxY = yPoints[0];
823 
824             for (int i = 1; i < nPoints; i++) {
825 
826                 if (xPoints[i] < minX) {
827                     minX = xPoints[i];
828                 } else if (xPoints[i] > maxX) {
829                     maxX = xPoints[i];
830                 }
831 
832                 if (yPoints[i] < minY) {
833                     minY = yPoints[i];
834                 } else if (yPoints[i] > maxY) {
835                     maxY = yPoints[i];
836                 }
837             }
838 
839             addDrawingRect(minX, minY, maxX - minX, maxY - minY);
840         }
841 
842         mPrintMetrics.fill(this);
843 
844     }
845 
846 
847     /**
848      * Draws the text given by the specified string, using this
849      * graphics context's current font and color. The baseline of the
850      * first character is at position (<i>x</i>,&nbsp;<i>y</i>) in this
851      * graphics context's coordinate system.
852      * @param       str      the string to be drawn.
853      * @param       x        the <i>x</i> coordinate.
854      * @param       y        the <i>y</i> coordinate.
855      * @see         java.awt.Graphics#drawBytes
856      * @see         java.awt.Graphics#drawChars
857      * @since       JDK1.0
858      */
859     public void drawString(String str, int x, int y) {
860 
861         drawString(str, (float)x, (float)y);
862     }
863 
864     /**
865      * Draws the text given by the specified iterator, using this
866      * graphics context's current color. The iterator has to specify a font
867      * for each character. The baseline of the
868      * first character is at position (<i>x</i>,&nbsp;<i>y</i>) in this
869      * graphics context's coordinate system.
870      * The rendering attributes applied include the clip, transform,
871      * paint or color, and composite attributes.
872      * For characters in script systems such as Hebrew and Arabic,
873      * the glyphs may be draw from right to left, in which case the
874      * coordinate supplied is the the location of the leftmost character
875      * on the baseline.
876      * @param iterator the iterator whose text is to be drawn
877      * @param x,y the coordinates where the iterator's text should be drawn.
878      * @see #setPaint
879      * @see java.awt.Graphics#setColor
880      * @see #setTransform
881      * @see #setComposite
882      * @see #setClip
883      */
884     public void drawString(AttributedCharacterIterator iterator,
885                                     int x, int y) {
886 
887         drawString(iterator,  (float)x, (float)y);
888     }
889 
890     /**
891      * Draws the text given by the specified iterator, using this
892      * graphics context's current color. The iterator has to specify a font
893      * for each character. The baseline of the
894      * first character is at position (<i>x</i>,&nbsp;<i>y</i>) in this
895      * graphics context's coordinate system.
896      * The rendering attributes applied include the clip, transform,
897      * paint or color, and composite attributes.
898      * For characters in script systems such as Hebrew and Arabic,
899      * the glyphs may be draw from right to left, in which case the
900      * coordinate supplied is the the location of the leftmost character
901      * on the baseline.
902      * @param iterator the iterator whose text is to be drawn
903      * @param x,y the coordinates where the iterator's text should be drawn.
904      * @see #setPaint
905      * @see java.awt.Graphics#setColor
906      * @see #setTransform
907      * @see #setComposite
908      * @see #setClip
909      */
910     public void drawString(AttributedCharacterIterator iterator,
911                                     float x, float y) {
912         if (iterator == null) {
913             throw new
914                 NullPointerException("AttributedCharacterIterator is null");
915         }
916 
917         TextLayout layout = new TextLayout(iterator, getFontRenderContext());
918         layout.draw(this, x, y);
919     }
920 
921 
922     /**
923      * Draws as much of the specified image as is currently available.
924      * The image is drawn with its top-left corner at
925      * (<i>x</i>,&nbsp;<i>y</i>) in this graphics context's coordinate
926      * space. Transparent pixels in the image do not affect whatever
927      * pixels are already there.
928      * <p>
929      * This method returns immediately in all cases, even if the
930      * complete image has not yet been loaded, and it has not been dithered
931      * and converted for the current output device.
932      * <p>
933      * If the image has not yet been completely loaded, then
934      * <code>drawImage</code> returns <code>false</code>. As more of
935      * the image becomes available, the process that draws the image notifies
936      * the specified image observer.
937      * @param    img the specified image to be drawn.
938      * @param    x   the <i>x</i> coordinate.
939      * @param    y   the <i>y</i> coordinate.
940      * @param    observer    object to be notified as more of
941      *                          the image is converted.
942      * @see      java.awt.Image
943      * @see      java.awt.image.ImageObserver
944      * @see      java.awt.image.ImageObserver#imageUpdate(java.awt.Image, int, int, int, int, int)
945      * @since    JDK1.0
946      */
947     public boolean drawImage(Image img, int x, int y,
948                              ImageObserver observer) {
949 
950         if (img == null) {
951             return true;
952         }
953 
954         /* The ImageWaiter creation does not return until the
955          * image is loaded.
956          */
957         ImageWaiter dim = new ImageWaiter(img);
958 
959         addDrawingRect(x, y, dim.getWidth(), dim.getHeight());
960         mPrintMetrics.drawImage(this, img);
961 
962         return mGraphics.drawImage(img, x, y, observer);
963     }
964 
965 
966     /**
967      * Draws as much of the specified image as has already been scaled
968      * to fit inside the specified rectangle.
969      * <p>
970      * The image is drawn inside the specified rectangle of this
971      * graphics context's coordinate space, and is scaled if
972      * necessary. Transparent pixels do not affect whatever pixels
973      * are already there.
974      * <p>
975      * This method returns immediately in all cases, even if the
976      * entire image has not yet been scaled, dithered, and converted
977      * for the current output device.
978      * If the current output representation is not yet complete, then
979      * <code>drawImage</code> returns <code>false</code>. As more of
980      * the image becomes available, the process that draws the image notifies
981      * the image observer by calling its <code>imageUpdate</code> method.
982      * <p>
983      * A scaled version of an image will not necessarily be
984      * available immediately just because an unscaled version of the
985      * image has been constructed for this output device.  Each size of
986      * the image may be cached separately and generated from the original
987      * data in a separate image production sequence.
988      * @param    img    the specified image to be drawn.
989      * @param    x      the <i>x</i> coordinate.
990      * @param    y      the <i>y</i> coordinate.
991      * @param    width  the width of the rectangle.
992      * @param    height the height of the rectangle.
993      * @param    observer    object to be notified as more of
994      *                          the image is converted.
995      * @see      java.awt.Image
996      * @see      java.awt.image.ImageObserver
997      * @see      java.awt.image.ImageObserver#imageUpdate(java.awt.Image, int, int, int, int, int)
998      * @since    JDK1.0
999      */
1000     public boolean drawImage(Image img, int x, int y,
1001                              int width, int height,
1002                              ImageObserver observer) {
1003 
1004         if (img == null) {
1005             return true;
1006         }
1007         addDrawingRect(x, y, width, height);
1008         mPrintMetrics.drawImage(this, img);
1009 
1010         return mGraphics.drawImage(img, x, y, width, height, observer);
1011 
1012     }
1013 
1014     /**
1015      * Draws as much of the specified image as is currently available.
1016      * The image is drawn with its top-left corner at
1017      * (<i>x</i>,&nbsp;<i>y</i>) in this graphics context's coordinate
1018      * space.  Transparent pixels are drawn in the specified
1019      * background color.
1020      * <p>
1021      * This operation is equivalent to filling a rectangle of the
1022      * width and height of the specified image with the given color and then
1023      * drawing the image on top of it, but possibly more efficient.
1024      * <p>
1025      * This method returns immediately in all cases, even if the
1026      * complete image has not yet been loaded, and it has not been dithered
1027      * and converted for the current output device.
1028      * <p>
1029      * If the image has not yet been completely loaded, then
1030      * <code>drawImage</code> returns <code>false</code>. As more of
1031      * the image becomes available, the process that draws the image notifies
1032      * the specified image observer.
1033      * @param    img    the specified image to be drawn.
1034      * @param    x      the <i>x</i> coordinate.
1035      * @param    y      the <i>y</i> coordinate.
1036      * @param    bgcolor the background color to paint under the
1037      *                         non-opaque portions of the image.
1038      * @param    observer    object to be notified as more of
1039      *                          the image is converted.
1040      * @see      java.awt.Image
1041      * @see      java.awt.image.ImageObserver
1042      * @see      java.awt.image.ImageObserver#imageUpdate(java.awt.Image, int, int, int, int, int)
1043      * @since    JDK1.0
1044      */
1045    public boolean drawImage(Image img, int x, int y,
1046                              Color bgcolor,
1047                              ImageObserver observer) {
1048 
1049         if (img == null) {
1050             return true;
1051         }
1052 
1053         /* The ImageWaiter creation does not return until the
1054          * image is loaded.
1055          */
1056         ImageWaiter dim = new ImageWaiter(img);
1057 
1058         addDrawingRect(x, y, dim.getWidth(), dim.getHeight());
1059         mPrintMetrics.drawImage(this, img);
1060 
1061         return mGraphics.drawImage(img, x, y, bgcolor, observer);
1062     }
1063 
1064 
1065     /**
1066      * Draws as much of the specified image as has already been scaled
1067      * to fit inside the specified rectangle.
1068      * <p>
1069      * The image is drawn inside the specified rectangle of this
1070      * graphics context's coordinate space, and is scaled if
1071      * necessary. Transparent pixels are drawn in the specified
1072      * background color.
1073      * This operation is equivalent to filling a rectangle of the
1074      * width and height of the specified image with the given color and then
1075      * drawing the image on top of it, but possibly more efficient.
1076      * <p>
1077      * This method returns immediately in all cases, even if the
1078      * entire image has not yet been scaled, dithered, and converted
1079      * for the current output device.
1080      * If the current output representation is not yet complete then
1081      * <code>drawImage</code> returns <code>false</code>. As more of
1082      * the image becomes available, the process that draws the image notifies
1083      * the specified image observer.
1084      * <p>
1085      * A scaled version of an image will not necessarily be
1086      * available immediately just because an unscaled version of the
1087      * image has been constructed for this output device.  Each size of
1088      * the image may be cached separately and generated from the original
1089      * data in a separate image production sequence.
1090      * @param    img       the specified image to be drawn.
1091      * @param    x         the <i>x</i> coordinate.
1092      * @param    y         the <i>y</i> coordinate.
1093      * @param    width     the width of the rectangle.
1094      * @param    height    the height of the rectangle.
1095      * @param    bgcolor   the background color to paint under the
1096      *                         non-opaque portions of the image.
1097      * @param    observer    object to be notified as more of
1098      *                          the image is converted.
1099      * @see      java.awt.Image
1100      * @see      java.awt.image.ImageObserver
1101      * @see      java.awt.image.ImageObserver#imageUpdate(java.awt.Image, int, int, int, int, int)
1102      * @since    JDK1.0
1103      */
1104     public boolean drawImage(Image img, int x, int y,
1105                              int width, int height,
1106                              Color bgcolor,
1107                              ImageObserver observer) {
1108 
1109         if (img == null) {
1110             return true;
1111         }
1112 
1113         addDrawingRect(x, y, width, height);
1114         mPrintMetrics.drawImage(this, img);
1115 
1116         return mGraphics.drawImage(img, x, y, width, height, bgcolor, observer);
1117 
1118     }
1119 
1120     /**
1121      * Draws as much of the specified area of the specified image as is
1122      * currently available, scaling it on the fly to fit inside the
1123      * specified area of the destination drawable surface. Transparent pixels
1124      * do not affect whatever pixels are already there.
1125      * <p>
1126      * This method returns immediately in all cases, even if the
1127      * image area to be drawn has not yet been scaled, dithered, and converted
1128      * for the current output device.
1129      * If the current output representation is not yet complete then
1130      * <code>drawImage</code> returns <code>false</code>. As more of
1131      * the image becomes available, the process that draws the image notifies
1132      * the specified image observer.
1133      * <p>
1134      * This method always uses the unscaled version of the image
1135      * to render the scaled rectangle and performs the required
1136      * scaling on the fly. It does not use a cached, scaled version
1137      * of the image for this operation. Scaling of the image from source
1138      * to destination is performed such that the first coordinate
1139      * of the source rectangle is mapped to the first coordinate of
1140      * the destination rectangle, and the second source coordinate is
1141      * mapped to the second destination coordinate. The subimage is
1142      * scaled and flipped as needed to preserve those mappings.
1143      * @param       img the specified image to be drawn
1144      * @param       dx1 the <i>x</i> coordinate of the first corner of the
1145      *                    destination rectangle.
1146      * @param       dy1 the <i>y</i> coordinate of the first corner of the
1147      *                    destination rectangle.
1148      * @param       dx2 the <i>x</i> coordinate of the second corner of the
1149      *                    destination rectangle.
1150      * @param       dy2 the <i>y</i> coordinate of the second corner of the
1151      *                    destination rectangle.
1152      * @param       sx1 the <i>x</i> coordinate of the first corner of the
1153      *                    source rectangle.
1154      * @param       sy1 the <i>y</i> coordinate of the first corner of the
1155      *                    source rectangle.
1156      * @param       sx2 the <i>x</i> coordinate of the second corner of the
1157      *                    source rectangle.
1158      * @param       sy2 the <i>y</i> coordinate of the second corner of the
1159      *                    source rectangle.
1160      * @param       observer object to be notified as more of the image is
1161      *                    scaled and converted.
1162      * @see         java.awt.Image
1163      * @see         java.awt.image.ImageObserver
1164      * @see         java.awt.image.ImageObserver#imageUpdate(java.awt.Image, int, int, int, int, int)
1165      * @since       JDK1.1
1166      */
1167     public boolean drawImage(Image img,
1168                              int dx1, int dy1, int dx2, int dy2,
1169                              int sx1, int sy1, int sx2, int sy2,
1170                              ImageObserver observer) {
1171 
1172         if (img == null) {
1173             return true;
1174         }
1175 
1176         int width = dx2 - dx1;
1177         int height = dy2 - dy1;
1178 
1179         addDrawingRect(dx1, dy1, width, height);
1180         mPrintMetrics.drawImage(this, img);
1181 
1182         return mGraphics.drawImage(img, dx1, dy1, dx2, dy2,
1183                                sx1, sy1, sx2, sy2, observer);
1184 
1185     }
1186 
1187 
1188     /**
1189      * Draws as much of the specified area of the specified image as is
1190      * currently available, scaling it on the fly to fit inside the
1191      * specified area of the destination drawable surface.
1192      * <p>
1193      * Transparent pixels are drawn in the specified background color.
1194      * This operation is equivalent to filling a rectangle of the
1195      * width and height of the specified image with the given color and then
1196      * drawing the image on top of it, but possibly more efficient.
1197      * <p>
1198      * This method returns immediately in all cases, even if the
1199      * image area to be drawn has not yet been scaled, dithered, and converted
1200      * for the current output device.
1201      * If the current output representation is not yet complete then
1202      * <code>drawImage</code> returns <code>false</code>. As more of
1203      * the image becomes available, the process that draws the image notifies
1204      * the specified image observer.
1205      * <p>
1206      * This method always uses the unscaled version of the image
1207      * to render the scaled rectangle and performs the required
1208      * scaling on the fly. It does not use a cached, scaled version
1209      * of the image for this operation. Scaling of the image from source
1210      * to destination is performed such that the first coordinate
1211      * of the source rectangle is mapped to the first coordinate of
1212      * the destination rectangle, and the second source coordinate is
1213      * mapped to the second destination coordinate. The subimage is
1214      * scaled and flipped as needed to preserve those mappings.
1215      * @param       img the specified image to be drawn
1216      * @param       dx1 the <i>x</i> coordinate of the first corner of the
1217      *                    destination rectangle.
1218      * @param       dy1 the <i>y</i> coordinate of the first corner of the
1219      *                    destination rectangle.
1220      * @param       dx2 the <i>x</i> coordinate of the second corner of the
1221      *                    destination rectangle.
1222      * @param       dy2 the <i>y</i> coordinate of the second corner of the
1223      *                    destination rectangle.
1224      * @param       sx1 the <i>x</i> coordinate of the first corner of the
1225      *                    source rectangle.
1226      * @param       sy1 the <i>y</i> coordinate of the first corner of the
1227      *                    source rectangle.
1228      * @param       sx2 the <i>x</i> coordinate of the second corner of the
1229      *                    source rectangle.
1230      * @param       sy2 the <i>y</i> coordinate of the second corner of the
1231      *                    source rectangle.
1232      * @param       bgcolor the background color to paint under the
1233      *                    non-opaque portions of the image.
1234      * @param       observer object to be notified as more of the image is
1235      *                    scaled and converted.
1236      * @see         java.awt.Image
1237      * @see         java.awt.image.ImageObserver
1238      * @see         java.awt.image.ImageObserver#imageUpdate(java.awt.Image, int, int, int, int, int)
1239      * @since       JDK1.1
1240      */
1241     public boolean drawImage(Image img,
1242                              int dx1, int dy1, int dx2, int dy2,
1243                              int sx1, int sy1, int sx2, int sy2,
1244                              Color bgcolor,
1245                              ImageObserver observer) {
1246 
1247         if (img == null) {
1248             return true;
1249         }
1250 
1251         int width = dx2 - dx1;
1252         int height = dy2 - dy1;
1253 
1254         addDrawingRect(dx1, dy1, width, height);
1255         mPrintMetrics.drawImage(this, img);
1256 
1257         return mGraphics.drawImage(img, dx1, dy1, dx2, dy2,
1258                                sx1, sy1, sx2, sy2, bgcolor, observer);
1259 
1260     }
1261 
1262 
1263     /**
1264      * Draws an image, applying a transform from image space into user space
1265      * before drawing.
1266      * The transformation from user space into device space is done with
1267      * the current transform in the Graphics2D.
1268      * The given transformation is applied to the image before the
1269      * transform attribute in the Graphics2D state is applied.
1270      * The rendering attributes applied include the clip, transform,
1271      * and composite attributes. Note that the result is
1272      * undefined, if the given transform is noninvertible.
1273      * @param img The image to be drawn.
1274      * @param xform The transformation from image space into user space.
1275      * @see #transform
1276      * @see #setTransform
1277      * @see #setComposite
1278      * @see #clip
1279      * @see #setClip
1280      */
1281     public void drawRenderedImage(RenderedImage img,
1282                                   AffineTransform xform) {
1283 
1284         if (img == null) {
1285             return;
1286         }
1287 
1288         mPrintMetrics.drawImage(this, img);
1289         mDrawingArea.addInfinite();
1290     }
1291 
1292 
1293     public void drawRenderableImage(RenderableImage img,
1294                                     AffineTransform xform) {
1295 
1296         if (img == null) {
1297             return;
1298         }
1299 
1300         mPrintMetrics.drawImage(this, img);
1301         mDrawingArea.addInfinite();
1302     }
1303 
1304     /**
1305      * Disposes of this graphics context and releases
1306      * any system resources that it is using.
1307      * A <code>Graphics</code> object cannot be used after
1308      * <code>dispose</code>has been called.
1309      * <p>
1310      * When a Java program runs, a large number of <code>Graphics</code>
1311      * objects can be created within a short time frame.
1312      * Although the finalization process of the garbage collector
1313      * also disposes of the same system resources, it is preferable
1314      * to manually free the associated resources by calling this
1315      * method rather than to rely on a finalization process which
1316      * may not run to completion for a long period of time.
1317      * <p>
1318      * Graphics objects which are provided as arguments to the
1319      * <code>paint</code> and <code>update</code> methods
1320      * of components are automatically released by the system when
1321      * those methods return. For efficiency, programmers should
1322      * call <code>dispose</code> when finished using
1323      * a <code>Graphics</code> object only if it was created
1324      * directly from a component or another <code>Graphics</code> object.
1325      * @see         java.awt.Graphics#finalize
1326      * @see         java.awt.Component#paint
1327      * @see         java.awt.Component#update
1328      * @see         java.awt.Component#getGraphics
1329      * @see         java.awt.Graphics#create
1330      * @since       JDK1.0
1331      */
1332     public void dispose() {
1333         mGraphics.dispose();
1334     }
1335 
1336     /**
1337      * Empty finalizer as no clean up needed here.
1338      */
1339     public void finalize() {
1340     }
1341 
1342 /* The Delegated Graphics2D Methods */
1343 
1344     /**
1345      * Strokes the outline of a Shape using the settings of the current
1346      * graphics state.  The rendering attributes applied include the
1347      * clip, transform, paint or color, composite and stroke attributes.
1348      * @param s The shape to be drawn.
1349      * @see #setStroke
1350      * @see #setPaint
1351      * @see java.awt.Graphics#setColor
1352      * @see #transform
1353      * @see #setTransform
1354      * @see #clip
1355      * @see #setClip
1356      * @see #setComposite
1357      */
1358     public void draw(Shape s) {
1359         addStrokeShape(s);
1360         mPrintMetrics.draw(this);
1361     }
1362 
1363 
1364     /**
1365      * Draws an image, applying a transform from image space into user space
1366      * before drawing.
1367      * The transformation from user space into device space is done with
1368      * the current transform in the Graphics2D.
1369      * The given transformation is applied to the image before the
1370      * transform attribute in the Graphics2D state is applied.
1371      * The rendering attributes applied include the clip, transform,
1372      * and composite attributes. Note that the result is
1373      * undefined, if the given transform is noninvertible.
1374      * @param img The image to be drawn.
1375      * @param xform The transformation from image space into user space.
1376      * @param obs The image observer to be notified as more of the image
1377      * is converted.
1378      * @see #transform
1379      * @see #setTransform
1380      * @see #setComposite
1381      * @see #clip
1382      * @see #setClip
1383      */
1384     public boolean drawImage(Image img,
1385                              AffineTransform xform,
1386                              ImageObserver obs) {
1387 
1388         if (img == null) {
1389             return true;
1390         }
1391 
1392         mDrawingArea.addInfinite();
1393         mPrintMetrics.drawImage(this, img);
1394 
1395         return mGraphics.drawImage(img, xform, obs);
1396 
1397 
1398 //      if (mDrawingArea[0] != null) {
1399 //          Rectangle2D.Double bbox = new Rectangle2D.Double();
1400 //          Point2D leftTop = new Point2D.Double(0, 0);
1401 //          Point2D rightBottom = new Point2D.Double(getImageWidth(img),
1402 //                                                   getImageHeight(img));
1403 
1404 //          xform.transform(leftTop, leftTop);
1405 //          xform.transform(rightBottom, rightBottom);
1406 
1407 //          bbox.setBoundsFromDiagonal(leftTop, rightBottom);
1408 //          addDrawingRect(bbox);
1409 
1410 //      }
1411     }
1412 
1413 
1414     /**
1415      * Draws a BufferedImage that is filtered with a BufferedImageOp.
1416      * The rendering attributes applied include the clip, transform
1417      * and composite attributes.  This is equivalent to:
1418      * <pre>
1419      * img1 = op.filter(img, null);
1420      * drawImage(img1, new AffineTransform(1f,0f,0f,1f,x,y), null);
1421      * </pre>
1422      * @param op The filter to be applied to the image before drawing.
1423      * @param img The BufferedImage to be drawn.
1424      * @param x,y The location in user space where the image should be drawn.
1425      * @see #transform
1426      * @see #setTransform
1427      * @see #setComposite
1428      * @see #clip
1429      * @see #setClip
1430      */
1431     public void drawImage(BufferedImage img,
1432                           BufferedImageOp op,
1433                           int x,
1434                           int y) {
1435 
1436         if (img == null) {
1437             return;
1438         }
1439 
1440         mPrintMetrics.drawImage(this, (RenderedImage) img);
1441         mDrawingArea.addInfinite();
1442     }
1443 
1444 
1445     /**
1446      * Draws a string of text.
1447      * The rendering attributes applied include the clip, transform,
1448      * paint or color, font and composite attributes.
1449      * @param s The string to be drawn.
1450      * @param x,y The coordinates where the string should be drawn.
1451      * @see #setPaint
1452      * @see java.awt.Graphics#setColor
1453      * @see java.awt.Graphics#setFont
1454      * @see #transform
1455      * @see #setTransform
1456      * @see #setComposite
1457      * @see #clip
1458      * @see #setClip
1459      */
1460     public void drawString(String str,
1461                            float x,
1462                            float y) {
1463 
1464         if (str.length() == 0) {
1465             return;
1466         }
1467         /* Logical bounds close enough and is used for GlyphVector */
1468         FontRenderContext frc = getFontRenderContext();
1469         Rectangle2D bbox = getFont().getStringBounds(str, frc);
1470         addDrawingRect(bbox, x, y);
1471         mPrintMetrics.drawText(this);
1472     }
1473 
1474     /**
1475      * Draws a GlyphVector.
1476      * The rendering attributes applied include the clip, transform,
1477      * paint or color, and composite attributes.  The GlyphVector specifies
1478      * individual glyphs from a Font.
1479      * @param g The GlyphVector to be drawn.
1480      * @param x,y The coordinates where the glyphs should be drawn.
1481      * @see #setPaint
1482      * @see java.awt.Graphics#setColor
1483      * @see #transform
1484      * @see #setTransform
1485      * @see #setComposite
1486      * @see #clip
1487      * @see #setClip
1488      */
1489     public void drawGlyphVector(GlyphVector g,
1490                            float x,
1491                            float y) {
1492 
1493         Rectangle2D bbox = g.getLogicalBounds();
1494         addDrawingRect(bbox, x, y);
1495         mPrintMetrics.drawText(this);
1496 
1497     }
1498 
1499     /**
1500      * Fills the interior of a Shape using the settings of the current
1501      * graphics state. The rendering attributes applied include the
1502      * clip, transform, paint or color, and composite.
1503      * @see #setPaint
1504      * @see java.awt.Graphics#setColor
1505      * @see #transform
1506      * @see #setTransform
1507      * @see #setComposite
1508      * @see #clip
1509      * @see #setClip
1510      */
1511     public void fill(Shape s) {
1512         addDrawingRect(s.getBounds());
1513         mPrintMetrics.fill(this);
1514 
1515     }
1516 
1517 
1518     /**
1519      * Checks to see if the outline of a Shape intersects the specified
1520      * Rectangle in device space.
1521      * The rendering attributes taken into account include the
1522      * clip, transform, and stroke attributes.
1523      * @param rect The area in device space to check for a hit.
1524      * @param s The shape to check for a hit.
1525      * @param onStroke Flag to choose between testing the stroked or
1526      * the filled shape.
1527      * @return True if there is a hit, false otherwise.
1528      * @see #setStroke
1529      * @see #fill
1530      * @see #draw
1531      * @see #transform
1532      * @see #setTransform
1533      * @see #clip
1534      * @see #setClip
1535      */
1536     public boolean hit(Rectangle rect,
1537                        Shape s,
1538                        boolean onStroke) {
1539 
1540         return mGraphics.hit(rect, s, onStroke);
1541     }
1542 
1543     /**
1544      * Sets the Composite in the current graphics state. Composite is used
1545      * in all drawing methods such as drawImage, drawString, draw,
1546      * and fill.  It specifies how new pixels are to be combined with
1547      * the existing pixels on the graphics device in the rendering process.
1548      * @param comp The Composite object to be used for drawing.
1549      * @see java.awt.Graphics#setXORMode
1550      * @see java.awt.Graphics#setPaintMode
1551      * @see AlphaComposite
1552      */
1553     public void setComposite(Composite comp) {
1554         mGraphics.setComposite(comp);
1555     }
1556 
1557 
1558     /**
1559      * Sets the Paint in the current graphics state.
1560      * @param paint The Paint object to be used to generate color in
1561      * the rendering process.
1562      * @see java.awt.Graphics#setColor
1563      * @see GradientPaint
1564      * @see TexturePaint
1565      */
1566     public void setPaint(Paint paint) {
1567         mGraphics.setPaint(paint);
1568     }
1569 
1570     /**
1571      * Sets the Stroke in the current graphics state.
1572      * @param s The Stroke object to be used to stroke a Shape in
1573      * the rendering process.
1574      * @see BasicStroke
1575      */
1576     public void setStroke(Stroke s) {
1577         mGraphics.setStroke(s);
1578     }
1579 
1580     /**
1581      * Sets the preferences for the rendering algorithms.
1582      * Hint categories include controls for rendering quality and
1583      * overall time/quality trade-off in the rendering process.
1584      * @param hintCategory The category of hint to be set.
1585      * @param hintValue The value indicating preferences for the specified
1586      * hint category.
1587      * @see RenderingHints
1588      */
1589     public void setRenderingHint(Key hintCategory, Object hintValue) {
1590         mGraphics.setRenderingHint(hintCategory, hintValue);
1591     }
1592 
1593     /**
1594      * Returns the preferences for the rendering algorithms.
1595      * @param hintCategory The category of hint to be set.
1596      * @return The preferences for rendering algorithms.
1597      * @see RenderingHings
1598      */
1599     public Object getRenderingHint(Key hintCategory) {
1600         return mGraphics.getRenderingHint(hintCategory);
1601     }
1602 
1603     /**
1604      * Sets the preferences for the rendering algorithms.
1605      * Hint categories include controls for rendering quality and
1606      * overall time/quality trade-off in the rendering process.
1607      * @param hints The rendering hints to be set
1608      * @see RenderingHints
1609      */
1610     public void setRenderingHints(Map<?,?> hints) {
1611         mGraphics.setRenderingHints(hints);
1612     }
1613 
1614     /**
1615      * Adds a number of preferences for the rendering algorithms.
1616      * Hint categories include controls for rendering quality and
1617      * overall time/quality trade-off in the rendering process.
1618      * @param hints The rendering hints to be set
1619      * @see RenderingHints
1620      */
1621     public void addRenderingHints(Map<?,?> hints) {
1622         mGraphics.addRenderingHints(hints);
1623     }
1624 
1625     /**
1626      * Gets the preferences for the rendering algorithms.
1627      * Hint categories include controls for rendering quality and
1628      * overall time/quality trade-off in the rendering process.
1629      * @see RenderingHints
1630      */
1631     public RenderingHints getRenderingHints() {
1632         return mGraphics.getRenderingHints();
1633     }
1634 
1635     /**
1636      * Composes a Transform object with the transform in this
1637      * Graphics2D according to the rule last-specified-first-applied.
1638      * If the currrent transform is Cx, the result of composition
1639      * with Tx is a new transform Cx'.  Cx' becomes the current
1640      * transform for this Graphics2D.
1641      * Transforming a point p by the updated transform Cx' is
1642      * equivalent to first transforming p by Tx and then transforming
1643      * the result by the original transform Cx.  In other words,
1644      * Cx'(p) = Cx(Tx(p)).
1645      * A copy of the Tx is made, if necessary, so further
1646      * modifications to Tx do not affect rendering.
1647      * @param Tx The Transform object to be composed with the current
1648      * transform.
1649      * @see #setTransform
1650      * @see TransformChain
1651      * @see AffineTransform
1652      */
1653     public void transform(AffineTransform Tx) {
1654         mGraphics.transform(Tx);
1655     }
1656 
1657     /**
1658      * Sets the Transform in the current graphics state.
1659      * @param Tx The Transform object to be used in the rendering process.
1660      * @see #transform
1661      * @see TransformChain
1662      * @see AffineTransform
1663      */
1664     public void setTransform(AffineTransform Tx) {
1665         mGraphics.setTransform(Tx);
1666     }
1667 
1668     /**
1669      * Returns the current Transform in the Graphics2D state.
1670      * @see #transform
1671      * @see #setTransform
1672      */
1673     public AffineTransform getTransform() {
1674         return mGraphics.getTransform();
1675     }
1676 
1677     /**
1678      * Returns the current Paint in the Graphics2D state.
1679      * @see #setPaint
1680      * @see java.awt.Graphics#setColor
1681      */
1682     public Paint getPaint() {
1683         return mGraphics.getPaint();
1684     }
1685 
1686     /**
1687      * Returns the current Composite in the Graphics2D state.
1688      * @see #setComposite
1689      */
1690     public Composite getComposite() {
1691         return mGraphics.getComposite();
1692     }
1693 
1694     /**
1695      * Sets the background color in this context used for clearing a region.
1696      * When Graphics2D is constructed for a component, the backgroung color is
1697      * inherited from the component. Setting the background color in the
1698      * Graphics2D context only affects the subsequent clearRect() calls and
1699      * not the background color of the component. To change the background
1700      * of the component, use appropriate methods of the component.
1701      * @param color The background color that should be used in
1702      * subsequent calls to clearRect().
1703      * @see getBackground
1704      * @see Graphics.clearRect()
1705      */
1706     public void setBackground(Color color) {
1707         mGraphics.setBackground(color);
1708     }
1709 
1710     /**
1711      * Returns the background color used for clearing a region.
1712      * @see setBackground
1713      */
1714     public Color getBackground() {
1715         return mGraphics.getBackground();
1716     }
1717 
1718     /**
1719      * Returns the current Stroke in the Graphics2D state.
1720      * @see setStroke
1721      */
1722     public Stroke getStroke() {
1723         return mGraphics.getStroke();
1724     }
1725 
1726     /**
1727      * Intersects the current clip with the interior of the specified Shape
1728      * and sets the current clip to the resulting intersection.
1729      * The indicated shape is transformed with the current transform in the
1730      * Graphics2D state before being intersected with the current clip.
1731      * This method is used to make the current clip smaller.
1732      * To make the clip larger, use any setClip method.
1733      * @param s The Shape to be intersected with the current clip.
1734      */
1735      public void clip(Shape s) {
1736         mGraphics.clip(s);
1737      }
1738 
1739      /**
1740       * Return true if the Rectangle <code>rect</code>
1741       * intersects the area into which the application
1742       * has drawn.
1743       */
1744      public boolean hitsDrawingArea(Rectangle rect) {
1745 
1746          return mDrawingArea.intersects((float) rect.getMinY(),
1747                                         (float) rect.getMaxY());
1748      }
1749 
1750      /**
1751       * Return the object holding the summary of the
1752       * drawing done by the printing application.
1753       */
1754      public PeekMetrics getMetrics() {
1755         return mPrintMetrics;
1756      }
1757 
1758  /* Support Routines for Calculating the Drawing Area */
1759 
1760    /**
1761      * Shift the rectangle 'rect' to the position ('x', 'y')
1762      * and add the resulting rectangle to the area representing
1763      * the part of the page which is drawn into.
1764      */
1765     private void addDrawingRect(Rectangle2D rect, float x, float y) {
1766 
1767         addDrawingRect((float) (rect.getX() + x),
1768                        (float) (rect.getY() + y),
1769                        (float) rect.getWidth(),
1770                        (float) rect.getHeight());
1771 
1772     }
1773 
1774     private void addDrawingRect(float x, float y, float width, float height) {
1775 
1776         Rectangle2D.Float bbox = new Rectangle2D.Float(x, y, width, height);
1777         addDrawingRect(bbox);
1778     }
1779 
1780     /**
1781      * Add the rectangle 'rect' to the area representing
1782      * the part of the page which is drawn into.
1783      */
1784     private void addDrawingRect(Rectangle2D rect) {
1785 
1786         /*  For testing purposes the following line can be uncommented.
1787             When uncommented it causes the entire page to be rasterized
1788             thus eliminating errors caused by a faulty bounding box
1789             calculation.
1790         */
1791         //mDrawingArea.addInfinite();
1792 
1793 
1794 
1795         AffineTransform matrix = getTransform();
1796 
1797         Shape transShape = matrix.createTransformedShape(rect);
1798 
1799         Rectangle2D transRect = transShape.getBounds2D();
1800 
1801         mDrawingArea.add((float) transRect.getMinY(),
1802                          (float) transRect.getMaxY());
1803 
1804 
1805     }
1806 
1807     /**
1808      * Add the stroked shape to the area representing
1809      * the part of the page which is drawn into.
1810      */
1811     private void addStrokeShape(Shape s) {
1812         Shape transShape = getStroke().createStrokedShape(s);
1813         addDrawingRect(transShape.getBounds2D());
1814     }
1815 
1816     /* Image Observer */
1817 
1818     /**
1819      * Notify this object when the height or width become available
1820      * for an image.
1821      */
1822     public synchronized boolean imageUpdate(Image img, int infoFlags,
1823                                             int x, int y,
1824                                             int width, int height) {
1825 
1826         boolean gotInfo = false;
1827 
1828         if((infoFlags & (WIDTH | HEIGHT)) != 0) {
1829             gotInfo = true;
1830             notify();
1831         }
1832 
1833         return gotInfo;
1834     }
1835 
1836     private synchronized int getImageWidth(Image img) {
1837 
1838         /* Wait for the width the image to
1839          * become available.
1840          */
1841         while (img.getWidth(this) == -1) {
1842             try {
1843                 wait();
1844             } catch (InterruptedException e) {
1845             }
1846         }
1847 
1848 
1849         return img.getWidth(this);
1850     }
1851 
1852     private synchronized int getImageHeight(Image img) {
1853 
1854         /* Wait for the height the image to
1855          * become available.
1856          */
1857         while (img.getHeight(this) == -1) {
1858             try {
1859                 wait();
1860             } catch (InterruptedException e) {
1861             }
1862         }
1863 
1864 
1865         return img.getHeight(this);
1866     }
1867 
1868     /**
1869      * This private class does not return from its constructor
1870      * until 'img's width and height are available.
1871      */
1872     protected class ImageWaiter implements ImageObserver {
1873 
1874         private int mWidth;
1875         private int mHeight;
1876         private boolean badImage = false;
1877 
1878         ImageWaiter(Image img) {
1879             waitForDimensions(img);
1880         }
1881 
1882         public int getWidth() {
1883             return mWidth;
1884         }
1885 
1886         public int getHeight() {
1887             return mHeight;
1888         }
1889 
1890         synchronized private void waitForDimensions(Image img) {
1891             mHeight = img.getHeight(this);
1892             mWidth = img.getWidth(this);
1893             while (!badImage && (mWidth < 0 || mHeight < 0)) {
1894                 try {
1895                     Thread.sleep(50);
1896                 } catch(InterruptedException e) {
1897                     // do nothing.
1898                 }
1899                 mHeight = img.getHeight(this);
1900                 mWidth = img.getWidth(this);
1901             }
1902             if (badImage) {
1903                 mHeight = 0;
1904                 mWidth = 0;
1905             }
1906         }
1907 
1908         synchronized public boolean imageUpdate(Image image, int flags,
1909                                                 int x, int y, int w, int h) {
1910 
1911             boolean dontCallMeAgain = (flags & (HEIGHT | ABORT | ERROR)) != 0;
1912             badImage = (flags & (ABORT | ERROR)) != 0;
1913 
1914             return dontCallMeAgain;
1915         }
1916 
1917     }
1918 }