1/*
2 * Copyright (c) 1998, 2017, 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
26package sun.print;
27
28import java.util.Map;
29
30import java.awt.BasicStroke;
31import java.awt.Color;
32import java.awt.Composite;
33import java.awt.Graphics;
34import java.awt.Graphics2D;
35import java.awt.Font;
36import java.awt.FontMetrics;
37import java.awt.font.FontRenderContext;
38import java.awt.Graphics;
39import java.awt.GraphicsConfiguration;
40import java.awt.Image;
41import java.awt.Paint;
42import java.awt.Rectangle;
43import java.awt.Shape;
44import java.awt.Stroke;
45import java.awt.RenderingHints;
46import java.awt.RenderingHints.Key;
47
48import java.awt.font.GlyphVector;
49import java.awt.font.TextLayout;
50
51import java.awt.geom.AffineTransform;
52import java.awt.geom.Line2D;
53import java.awt.geom.Point2D;
54import java.awt.geom.Rectangle2D;
55import java.awt.geom.RoundRectangle2D;
56import java.awt.image.BufferedImage;
57import java.awt.image.BufferedImageOp;
58import java.awt.image.ImageObserver;
59import java.awt.image.RenderedImage;
60import java.awt.image.renderable.RenderableImage;
61import java.awt.print.PrinterGraphics;
62import java.awt.print.PrinterJob;
63
64import java.text.AttributedCharacterIterator;
65
66import sun.java2d.Spans;
67
68public 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} object that is
166     * a copy of this {@code Graphics} object.
167     * @return     a new graphics context that is a copy of
168     *                       this graphics context.
169     * @since      1.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   1.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     1.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     1.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   1.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     1.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     1.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(char[], int, int, int, int)
365     * @see     java.awt.Graphics#drawString(String, int, int)
366     * @see     java.awt.Graphics#drawBytes(byte[], int, int, int, int)
367     * @since   1.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     1.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       1.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       1.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} 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       1.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}
463     * interface can be used to set the clip.  The only
464     * {@code Shape} objects which are guaranteed to be
465     * supported are {@code Shape} objects which are
466     * obtained via the {@code getClip} method and via
467     * {@code Rectangle} 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       1.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} and {@code dy}. From the point specified
481     * by {@code x} and {@code y}, 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} or {@code dy}.
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} 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} 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       1.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   1.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} and <code>x&nbsp;+&nbsp;width&nbsp;-&nbsp;1</code>.
524     * The top and bottom edges are at
525     * {@code y} and <code>y&nbsp;+&nbsp;height&nbsp;-&nbsp;1</code>.
526     * The resulting rectangle covers an area
527     * {@code width} pixels wide by
528     * {@code height} 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         1.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} followed by {@code fillRect} 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       1.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} and <code>x&nbsp;+&nbsp;width</code>,
577     * respectively. The top and bottom edges of the rectangle are at
578     * {@code y} 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      1.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} 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} 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       1.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 y},
625     * {@code width}, and {@code height} 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       1.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       1.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} and extends
669     * for {@code arcAngle} 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} and {@code height} 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       1.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} and extends
705     * for {@code arcAngle} 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} and {@code height} 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       1.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       1.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} 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}.
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} coordinates.
779     * @param        yPoints   a an array of {@code y} coordinates.
780     * @param        nPoints   a the total number of points.
781     * @see          java.awt.Graphics#fillPolygon
782     * @see          java.awt.Graphics#drawPolyline
783     * @since        1.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} 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}.
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} coordinates.
811     * @param        yPoints   a an array of {@code y} coordinates.
812     * @param        nPoints   a the total number of points.
813     * @see          java.awt.Graphics#drawPolygon(int[], int[], int)
814     * @since        1.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       1.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 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 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} returns {@code false}. 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    1.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} returns {@code false}. As more of
980     * the image becomes available, the process that draws the image notifies
981     * the image observer by calling its {@code imageUpdate} 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    1.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} returns {@code false}. 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    1.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} returns {@code false}. 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    1.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} returns {@code false}. 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       1.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} returns {@code false}. 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       1.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} object cannot be used after
1308     * {@code dispose} has been called.
1309     * <p>
1310     * When a Java program runs, a large number of {@code Graphics}
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} and {@code update} methods
1320     * of components are automatically released by the system when
1321     * those methods return. For efficiency, programmers should
1322     * call {@code dispose} when finished using
1323     * a {@code Graphics} object only if it was created
1324     * directly from a component or another {@code Graphics} 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       1.0
1331     */
1332    public void dispose() {
1333        mGraphics.dispose();
1334    }
1335
1336    /**
1337     * Empty finalizer as no clean up needed here.
1338     */
1339    @SuppressWarnings("deprecation")
1340    public void finalize() {
1341    }
1342
1343/* The Delegated Graphics2D Methods */
1344
1345    /**
1346     * Strokes the outline of a Shape using the settings of the current
1347     * graphics state.  The rendering attributes applied include the
1348     * clip, transform, paint or color, composite and stroke attributes.
1349     * @param s The shape to be drawn.
1350     * @see #setStroke
1351     * @see #setPaint
1352     * @see java.awt.Graphics#setColor
1353     * @see #transform
1354     * @see #setTransform
1355     * @see #clip
1356     * @see #setClip
1357     * @see #setComposite
1358     */
1359    public void draw(Shape s) {
1360        addStrokeShape(s);
1361        mPrintMetrics.draw(this);
1362    }
1363
1364
1365    /**
1366     * Draws an image, applying a transform from image space into user space
1367     * before drawing.
1368     * The transformation from user space into device space is done with
1369     * the current transform in the Graphics2D.
1370     * The given transformation is applied to the image before the
1371     * transform attribute in the Graphics2D state is applied.
1372     * The rendering attributes applied include the clip, transform,
1373     * and composite attributes. Note that the result is
1374     * undefined, if the given transform is noninvertible.
1375     * @param img The image to be drawn.
1376     * @param xform The transformation from image space into user space.
1377     * @param obs The image observer to be notified as more of the image
1378     * is converted.
1379     * @see #transform
1380     * @see #setTransform
1381     * @see #setComposite
1382     * @see #clip
1383     * @see #setClip
1384     */
1385    public boolean drawImage(Image img,
1386                             AffineTransform xform,
1387                             ImageObserver obs) {
1388
1389        if (img == null) {
1390            return true;
1391        }
1392
1393        mDrawingArea.addInfinite();
1394        mPrintMetrics.drawImage(this, img);
1395
1396        return mGraphics.drawImage(img, xform, obs);
1397
1398
1399//      if (mDrawingArea[0] != null) {
1400//          Rectangle2D.Double bbox = new Rectangle2D.Double();
1401//          Point2D leftTop = new Point2D.Double(0, 0);
1402//          Point2D rightBottom = new Point2D.Double(getImageWidth(img),
1403//                                                   getImageHeight(img));
1404
1405//          xform.transform(leftTop, leftTop);
1406//          xform.transform(rightBottom, rightBottom);
1407
1408//          bbox.setBoundsFromDiagonal(leftTop, rightBottom);
1409//          addDrawingRect(bbox);
1410
1411//      }
1412    }
1413
1414
1415    /**
1416     * Draws a BufferedImage that is filtered with a BufferedImageOp.
1417     * The rendering attributes applied include the clip, transform
1418     * and composite attributes.  This is equivalent to:
1419     * <pre>
1420     * img1 = op.filter(img, null);
1421     * drawImage(img1, new AffineTransform(1f,0f,0f,1f,x,y), null);
1422     * </pre>
1423     * @param op The filter to be applied to the image before drawing.
1424     * @param img The BufferedImage to be drawn.
1425     * @param x,y The location in user space where the image should be drawn.
1426     * @see #transform
1427     * @see #setTransform
1428     * @see #setComposite
1429     * @see #clip
1430     * @see #setClip
1431     */
1432    public void drawImage(BufferedImage img,
1433                          BufferedImageOp op,
1434                          int x,
1435                          int y) {
1436
1437        if (img == null) {
1438            return;
1439        }
1440
1441        mPrintMetrics.drawImage(this, (RenderedImage) img);
1442        mDrawingArea.addInfinite();
1443    }
1444
1445
1446    /**
1447     * Draws a string of text.
1448     * The rendering attributes applied include the clip, transform,
1449     * paint or color, font and composite attributes.
1450     * @param str The string to be drawn.
1451     * @param x,y The coordinates where the string should be drawn.
1452     * @see #setPaint
1453     * @see java.awt.Graphics#setColor
1454     * @see java.awt.Graphics#setFont
1455     * @see #transform
1456     * @see #setTransform
1457     * @see #setComposite
1458     * @see #clip
1459     * @see #setClip
1460     */
1461    public void drawString(String str,
1462                           float x,
1463                           float y) {
1464
1465        if (str.length() == 0) {
1466            return;
1467        }
1468        /* Logical bounds close enough and is used for GlyphVector */
1469        FontRenderContext frc = getFontRenderContext();
1470        Rectangle2D bbox = getFont().getStringBounds(str, frc);
1471        addDrawingRect(bbox, x, y);
1472        mPrintMetrics.drawText(this);
1473    }
1474
1475    /**
1476     * Draws a GlyphVector.
1477     * The rendering attributes applied include the clip, transform,
1478     * paint or color, and composite attributes.  The GlyphVector specifies
1479     * individual glyphs from a Font.
1480     * @param g The GlyphVector to be drawn.
1481     * @param x,y The coordinates where the glyphs should be drawn.
1482     * @see #setPaint
1483     * @see java.awt.Graphics#setColor
1484     * @see #transform
1485     * @see #setTransform
1486     * @see #setComposite
1487     * @see #clip
1488     * @see #setClip
1489     */
1490    public void drawGlyphVector(GlyphVector g,
1491                           float x,
1492                           float y) {
1493
1494        Rectangle2D bbox = g.getLogicalBounds();
1495        addDrawingRect(bbox, x, y);
1496        mPrintMetrics.drawText(this);
1497
1498    }
1499
1500    /**
1501     * Fills the interior of a Shape using the settings of the current
1502     * graphics state. The rendering attributes applied include the
1503     * clip, transform, paint or color, and composite.
1504     * @see #setPaint
1505     * @see java.awt.Graphics#setColor
1506     * @see #transform
1507     * @see #setTransform
1508     * @see #setComposite
1509     * @see #clip
1510     * @see #setClip
1511     */
1512    public void fill(Shape s) {
1513        addDrawingRect(s.getBounds());
1514        mPrintMetrics.fill(this);
1515
1516    }
1517
1518
1519    /**
1520     * Checks to see if the outline of a Shape intersects the specified
1521     * Rectangle in device space.
1522     * The rendering attributes taken into account include the
1523     * clip, transform, and stroke attributes.
1524     * @param rect The area in device space to check for a hit.
1525     * @param s The shape to check for a hit.
1526     * @param onStroke Flag to choose between testing the stroked or
1527     * the filled shape.
1528     * @return True if there is a hit, false otherwise.
1529     * @see #setStroke
1530     * @see #fill
1531     * @see #draw
1532     * @see #transform
1533     * @see #setTransform
1534     * @see #clip
1535     * @see #setClip
1536     */
1537    public boolean hit(Rectangle rect,
1538                       Shape s,
1539                       boolean onStroke) {
1540
1541        return mGraphics.hit(rect, s, onStroke);
1542    }
1543
1544    /**
1545     * Sets the Composite in the current graphics state. Composite is used
1546     * in all drawing methods such as drawImage, drawString, draw,
1547     * and fill.  It specifies how new pixels are to be combined with
1548     * the existing pixels on the graphics device in the rendering process.
1549     * @param comp The Composite object to be used for drawing.
1550     * @see java.awt.Graphics#setXORMode
1551     * @see java.awt.Graphics#setPaintMode
1552     * @see java.awt.AlphaComposite
1553     */
1554    public void setComposite(Composite comp) {
1555        mGraphics.setComposite(comp);
1556    }
1557
1558
1559    /**
1560     * Sets the Paint in the current graphics state.
1561     * @param paint The Paint object to be used to generate color in
1562     * the rendering process.
1563     * @see java.awt.Graphics#setColor
1564     * @see java.awt.GradientPaint
1565     * @see java.awt.TexturePaint
1566     */
1567    public void setPaint(Paint paint) {
1568        mGraphics.setPaint(paint);
1569    }
1570
1571    /**
1572     * Sets the Stroke in the current graphics state.
1573     * @param s The Stroke object to be used to stroke a Shape in
1574     * the rendering process.
1575     * @see BasicStroke
1576     */
1577    public void setStroke(Stroke s) {
1578        mGraphics.setStroke(s);
1579    }
1580
1581    /**
1582     * Sets the preferences for the rendering algorithms.
1583     * Hint categories include controls for rendering quality and
1584     * overall time/quality trade-off in the rendering process.
1585     * @param hintCategory The category of hint to be set.
1586     * @param hintValue The value indicating preferences for the specified
1587     * hint category.
1588     * @see RenderingHints
1589     */
1590    public void setRenderingHint(Key hintCategory, Object hintValue) {
1591        mGraphics.setRenderingHint(hintCategory, hintValue);
1592    }
1593
1594    /**
1595     * Returns the preferences for the rendering algorithms.
1596     * @param hintCategory The category of hint to be set.
1597     * @return The preferences for rendering algorithms.
1598     * @see RenderingHints
1599     */
1600    public Object getRenderingHint(Key hintCategory) {
1601        return mGraphics.getRenderingHint(hintCategory);
1602    }
1603
1604    /**
1605     * Sets the preferences for the rendering algorithms.
1606     * Hint categories include controls for rendering quality and
1607     * overall time/quality trade-off in the rendering process.
1608     * @param hints The rendering hints to be set
1609     * @see RenderingHints
1610     */
1611    public void setRenderingHints(Map<?,?> hints) {
1612        mGraphics.setRenderingHints(hints);
1613    }
1614
1615    /**
1616     * Adds a number of preferences for the rendering algorithms.
1617     * Hint categories include controls for rendering quality and
1618     * overall time/quality trade-off in the rendering process.
1619     * @param hints The rendering hints to be set
1620     * @see RenderingHints
1621     */
1622    public void addRenderingHints(Map<?,?> hints) {
1623        mGraphics.addRenderingHints(hints);
1624    }
1625
1626    /**
1627     * Gets the preferences for the rendering algorithms.
1628     * Hint categories include controls for rendering quality and
1629     * overall time/quality trade-off in the rendering process.
1630     * @see RenderingHints
1631     */
1632    public RenderingHints getRenderingHints() {
1633        return mGraphics.getRenderingHints();
1634    }
1635
1636    /**
1637     * Composes a Transform object with the transform in this
1638     * Graphics2D according to the rule last-specified-first-applied.
1639     * If the currrent transform is Cx, the result of composition
1640     * with Tx is a new transform Cx'.  Cx' becomes the current
1641     * transform for this Graphics2D.
1642     * Transforming a point p by the updated transform Cx' is
1643     * equivalent to first transforming p by Tx and then transforming
1644     * the result by the original transform Cx.  In other words,
1645     * Cx'(p) = Cx(Tx(p)).
1646     * A copy of the Tx is made, if necessary, so further
1647     * modifications to Tx do not affect rendering.
1648     * @param Tx The Transform object to be composed with the current
1649     * transform.
1650     * @see #setTransform
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 AffineTransform
1662     */
1663    public void setTransform(AffineTransform Tx) {
1664        mGraphics.setTransform(Tx);
1665    }
1666
1667    /**
1668     * Returns the current Transform in the Graphics2D state.
1669     * @see #transform
1670     * @see #setTransform
1671     */
1672    public AffineTransform getTransform() {
1673        return mGraphics.getTransform();
1674    }
1675
1676    /**
1677     * Returns the current Paint in the Graphics2D state.
1678     * @see #setPaint
1679     * @see java.awt.Graphics#setColor
1680     */
1681    public Paint getPaint() {
1682        return mGraphics.getPaint();
1683    }
1684
1685    /**
1686     * Returns the current Composite in the Graphics2D state.
1687     * @see #setComposite
1688     */
1689    public Composite getComposite() {
1690        return mGraphics.getComposite();
1691    }
1692
1693    /**
1694     * Sets the background color in this context used for clearing a region.
1695     * When Graphics2D is constructed for a component, the backgroung color is
1696     * inherited from the component. Setting the background color in the
1697     * Graphics2D context only affects the subsequent clearRect() calls and
1698     * not the background color of the component. To change the background
1699     * of the component, use appropriate methods of the component.
1700     * @param color The background color that should be used in
1701     * subsequent calls to clearRect().
1702     * @see #getBackground
1703     * @see Graphics#clearRect
1704     */
1705    public void setBackground(Color color) {
1706        mGraphics.setBackground(color);
1707    }
1708
1709    /**
1710     * Returns the background color used for clearing a region.
1711     * @see #setBackground
1712     */
1713    public Color getBackground() {
1714        return mGraphics.getBackground();
1715    }
1716
1717    /**
1718     * Returns the current Stroke in the Graphics2D state.
1719     * @see #setStroke
1720     */
1721    public Stroke getStroke() {
1722        return mGraphics.getStroke();
1723    }
1724
1725    /**
1726     * Intersects the current clip with the interior of the specified Shape
1727     * and sets the current clip to the resulting intersection.
1728     * The indicated shape is transformed with the current transform in the
1729     * Graphics2D state before being intersected with the current clip.
1730     * This method is used to make the current clip smaller.
1731     * To make the clip larger, use any setClip method.
1732     * @param s The Shape to be intersected with the current clip.
1733     */
1734     public void clip(Shape s) {
1735        mGraphics.clip(s);
1736     }
1737
1738     /**
1739      * Return true if the Rectangle {@code rect}
1740      * intersects the area into which the application
1741      * has drawn.
1742      */
1743     public boolean hitsDrawingArea(Rectangle rect) {
1744
1745         return mDrawingArea.intersects((float) rect.getMinY(),
1746                                        (float) rect.getMaxY());
1747     }
1748
1749     /**
1750      * Return the object holding the summary of the
1751      * drawing done by the printing application.
1752      */
1753     public PeekMetrics getMetrics() {
1754        return mPrintMetrics;
1755     }
1756
1757 /* Support Routines for Calculating the Drawing Area */
1758
1759   /**
1760     * Shift the rectangle 'rect' to the position ('x', 'y')
1761     * and add the resulting rectangle to the area representing
1762     * the part of the page which is drawn into.
1763     */
1764    private void addDrawingRect(Rectangle2D rect, float x, float y) {
1765
1766        addDrawingRect((float) (rect.getX() + x),
1767                       (float) (rect.getY() + y),
1768                       (float) rect.getWidth(),
1769                       (float) rect.getHeight());
1770
1771    }
1772
1773    private void addDrawingRect(float x, float y, float width, float height) {
1774
1775        Rectangle2D.Float bbox = new Rectangle2D.Float(x, y, width, height);
1776        addDrawingRect(bbox);
1777    }
1778
1779    /**
1780     * Add the rectangle 'rect' to the area representing
1781     * the part of the page which is drawn into.
1782     */
1783    private void addDrawingRect(Rectangle2D rect) {
1784
1785        /*  For testing purposes the following line can be uncommented.
1786            When uncommented it causes the entire page to be rasterized
1787            thus eliminating errors caused by a faulty bounding box
1788            calculation.
1789        */
1790        //mDrawingArea.addInfinite();
1791
1792
1793
1794        AffineTransform matrix = getTransform();
1795
1796        Shape transShape = matrix.createTransformedShape(rect);
1797
1798        Rectangle2D transRect = transShape.getBounds2D();
1799
1800        mDrawingArea.add((float) transRect.getMinY(),
1801                         (float) transRect.getMaxY());
1802
1803
1804    }
1805
1806    /**
1807     * Add the stroked shape to the area representing
1808     * the part of the page which is drawn into.
1809     */
1810    private void addStrokeShape(Shape s) {
1811        Shape transShape = getStroke().createStrokedShape(s);
1812        addDrawingRect(transShape.getBounds2D());
1813    }
1814
1815    /* Image Observer */
1816
1817    /**
1818     * Notify this object when the height or width become available
1819     * for an image.
1820     */
1821    public synchronized boolean imageUpdate(Image img, int infoFlags,
1822                                            int x, int y,
1823                                            int width, int height) {
1824
1825        boolean gotInfo = false;
1826
1827        if((infoFlags & (WIDTH | HEIGHT)) != 0) {
1828            gotInfo = true;
1829            notify();
1830        }
1831
1832        return gotInfo;
1833    }
1834
1835    private synchronized int getImageWidth(Image img) {
1836
1837        /* Wait for the width the image to
1838         * become available.
1839         */
1840        while (img.getWidth(this) == -1) {
1841            try {
1842                wait();
1843            } catch (InterruptedException e) {
1844            }
1845        }
1846
1847
1848        return img.getWidth(this);
1849    }
1850
1851    private synchronized int getImageHeight(Image img) {
1852
1853        /* Wait for the height the image to
1854         * become available.
1855         */
1856        while (img.getHeight(this) == -1) {
1857            try {
1858                wait();
1859            } catch (InterruptedException e) {
1860            }
1861        }
1862
1863
1864        return img.getHeight(this);
1865    }
1866
1867    /**
1868     * This private class does not return from its constructor
1869     * until 'img's width and height are available.
1870     */
1871    protected class ImageWaiter implements ImageObserver {
1872
1873        private int mWidth;
1874        private int mHeight;
1875        private boolean badImage = false;
1876
1877        ImageWaiter(Image img) {
1878            waitForDimensions(img);
1879        }
1880
1881        public int getWidth() {
1882            return mWidth;
1883        }
1884
1885        public int getHeight() {
1886            return mHeight;
1887        }
1888
1889        private synchronized void waitForDimensions(Image img) {
1890            mHeight = img.getHeight(this);
1891            mWidth = img.getWidth(this);
1892            while (!badImage && (mWidth < 0 || mHeight < 0)) {
1893                try {
1894                    Thread.sleep(50);
1895                } catch(InterruptedException e) {
1896                    // do nothing.
1897                }
1898                mHeight = img.getHeight(this);
1899                mWidth = img.getWidth(this);
1900            }
1901            if (badImage) {
1902                mHeight = 0;
1903                mWidth = 0;
1904            }
1905        }
1906
1907        public synchronized boolean imageUpdate(Image image, int flags,
1908                                                int x, int y, int w, int h) {
1909
1910            boolean dontCallMeAgain = (flags & (HEIGHT | ABORT | ERROR)) != 0;
1911            badImage = (flags & (ABORT | ERROR)) != 0;
1912
1913            return dontCallMeAgain;
1914        }
1915
1916    }
1917}
1918