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      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</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       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</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       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</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       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</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         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</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       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</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      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</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       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>, <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       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</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       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</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       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</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        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</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        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</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    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</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    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</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    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</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    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</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       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</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       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</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       1.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 str 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 java.awt.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 java.awt.GradientPaint
1564      * @see java.awt.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 RenderingHints
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 AffineTransform
1651      */
1652     public void transform(AffineTransform Tx) {
1653         mGraphics.transform(Tx);
1654     }
1655 
1656     /**
1657      * Sets the Transform in the current graphics state.
1658      * @param Tx The Transform object to be used in the rendering process.
1659      * @see #transform
1660      * @see AffineTransform
1661      */
1662     public void setTransform(AffineTransform Tx) {
1663         mGraphics.setTransform(Tx);
1664     }
1665 
1666     /**
1667      * Returns the current Transform in the Graphics2D state.
1668      * @see #transform
1669      * @see #setTransform
1670      */
1671     public AffineTransform getTransform() {
1672         return mGraphics.getTransform();
1673     }
1674 
1675     /**
1676      * Returns the current Paint in the Graphics2D state.
1677      * @see #setPaint
1678      * @see java.awt.Graphics#setColor
1679      */
1680     public Paint getPaint() {
1681         return mGraphics.getPaint();
1682     }
1683 
1684     /**
1685      * Returns the current Composite in the Graphics2D state.
1686      * @see #setComposite
1687      */
1688     public Composite getComposite() {
1689         return mGraphics.getComposite();
1690     }
1691 
1692     /**
1693      * Sets the background color in this context used for clearing a region.
1694      * When Graphics2D is constructed for a component, the backgroung color is
1695      * inherited from the component. Setting the background color in the
1696      * Graphics2D context only affects the subsequent clearRect() calls and
1697      * not the background color of the component. To change the background
1698      * of the component, use appropriate methods of the component.
1699      * @param color The background color that should be used in
1700      * subsequent calls to clearRect().
1701      * @see #getBackground
1702      * @see Graphics#clearRect
1703      */
1704     public void setBackground(Color color) {
1705         mGraphics.setBackground(color);
1706     }
1707 
1708     /**
1709      * Returns the background color used for clearing a region.
1710      * @see #setBackground
1711      */
1712     public Color getBackground() {
1713         return mGraphics.getBackground();
1714     }
1715 
1716     /**
1717      * Returns the current Stroke in the Graphics2D state.
1718      * @see #setStroke
1719      */
1720     public Stroke getStroke() {
1721         return mGraphics.getStroke();
1722     }
1723 
1724     /**
1725      * Intersects the current clip with the interior of the specified Shape
1726      * and sets the current clip to the resulting intersection.
1727      * The indicated shape is transformed with the current transform in the
1728      * Graphics2D state before being intersected with the current clip.
1729      * This method is used to make the current clip smaller.
1730      * To make the clip larger, use any setClip method.
1731      * @param s The Shape to be intersected with the current clip.
1732      */
1733      public void clip(Shape s) {
1734         mGraphics.clip(s);
1735      }
1736 
1737      /**
1738       * Return true if the Rectangle <code>rect</code>
1739       * intersects the area into which the application
1740       * has drawn.
1741       */
1742      public boolean hitsDrawingArea(Rectangle rect) {
1743 
1744          return mDrawingArea.intersects((float) rect.getMinY(),
1745                                         (float) rect.getMaxY());
1746      }
1747 
1748      /**
1749       * Return the object holding the summary of the
1750       * drawing done by the printing application.
1751       */
1752      public PeekMetrics getMetrics() {
1753         return mPrintMetrics;
1754      }
1755 
1756  /* Support Routines for Calculating the Drawing Area */
1757 
1758    /**
1759      * Shift the rectangle 'rect' to the position ('x', 'y')
1760      * and add the resulting rectangle to the area representing
1761      * the part of the page which is drawn into.
1762      */
1763     private void addDrawingRect(Rectangle2D rect, float x, float y) {
1764 
1765         addDrawingRect((float) (rect.getX() + x),
1766                        (float) (rect.getY() + y),
1767                        (float) rect.getWidth(),
1768                        (float) rect.getHeight());
1769 
1770     }
1771 
1772     private void addDrawingRect(float x, float y, float width, float height) {
1773 
1774         Rectangle2D.Float bbox = new Rectangle2D.Float(x, y, width, height);
1775         addDrawingRect(bbox);
1776     }
1777 
1778     /**
1779      * Add the rectangle 'rect' to the area representing
1780      * the part of the page which is drawn into.
1781      */
1782     private void addDrawingRect(Rectangle2D rect) {
1783 
1784         /*  For testing purposes the following line can be uncommented.
1785             When uncommented it causes the entire page to be rasterized
1786             thus eliminating errors caused by a faulty bounding box
1787             calculation.
1788         */
1789         //mDrawingArea.addInfinite();
1790 
1791 
1792 
1793         AffineTransform matrix = getTransform();
1794 
1795         Shape transShape = matrix.createTransformedShape(rect);
1796 
1797         Rectangle2D transRect = transShape.getBounds2D();
1798 
1799         mDrawingArea.add((float) transRect.getMinY(),
1800                          (float) transRect.getMaxY());
1801 
1802 
1803     }
1804 
1805     /**
1806      * Add the stroked shape to the area representing
1807      * the part of the page which is drawn into.
1808      */
1809     private void addStrokeShape(Shape s) {
1810         Shape transShape = getStroke().createStrokedShape(s);
1811         addDrawingRect(transShape.getBounds2D());
1812     }
1813 
1814     /* Image Observer */
1815 
1816     /**
1817      * Notify this object when the height or width become available
1818      * for an image.
1819      */
1820     public synchronized boolean imageUpdate(Image img, int infoFlags,
1821                                             int x, int y,
1822                                             int width, int height) {
1823 
1824         boolean gotInfo = false;
1825 
1826         if((infoFlags & (WIDTH | HEIGHT)) != 0) {
1827             gotInfo = true;
1828             notify();
1829         }
1830 
1831         return gotInfo;
1832     }
1833 
1834     private synchronized int getImageWidth(Image img) {
1835 
1836         /* Wait for the width the image to
1837          * become available.
1838          */
1839         while (img.getWidth(this) == -1) {
1840             try {
1841                 wait();
1842             } catch (InterruptedException e) {
1843             }
1844         }
1845 
1846 
1847         return img.getWidth(this);
1848     }
1849 
1850     private synchronized int getImageHeight(Image img) {
1851 
1852         /* Wait for the height the image to
1853          * become available.
1854          */
1855         while (img.getHeight(this) == -1) {
1856             try {
1857                 wait();
1858             } catch (InterruptedException e) {
1859             }
1860         }
1861 
1862 
1863         return img.getHeight(this);
1864     }
1865 
1866     /**
1867      * This private class does not return from its constructor
1868      * until 'img's width and height are available.
1869      */
1870     protected class ImageWaiter implements ImageObserver {
1871 
1872         private int mWidth;
1873         private int mHeight;
1874         private boolean badImage = false;
1875 
1876         ImageWaiter(Image img) {
1877             waitForDimensions(img);
1878         }
1879 
1880         public int getWidth() {
1881             return mWidth;
1882         }
1883 
1884         public int getHeight() {
1885             return mHeight;
1886         }
1887 
1888         synchronized private void waitForDimensions(Image img) {
1889             mHeight = img.getHeight(this);
1890             mWidth = img.getWidth(this);
1891             while (!badImage && (mWidth < 0 || mHeight < 0)) {
1892                 try {
1893                     Thread.sleep(50);
1894                 } catch(InterruptedException e) {
1895                     // do nothing.
1896                 }
1897                 mHeight = img.getHeight(this);
1898                 mWidth = img.getWidth(this);
1899             }
1900             if (badImage) {
1901                 mHeight = 0;
1902                 mWidth = 0;
1903             }
1904         }
1905 
1906         synchronized public boolean imageUpdate(Image image, int flags,
1907                                                 int x, int y, int w, int h) {
1908 
1909             boolean dontCallMeAgain = (flags & (HEIGHT | ABORT | ERROR)) != 0;
1910             badImage = (flags & (ABORT | ERROR)) != 0;
1911 
1912             return dontCallMeAgain;
1913         }
1914 
1915     }
1916 }