1 /*
   2  * Copyright (c) 1998, 2018, 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} 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 }