1 /* 2 * Copyright (c) 1998, 2017, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 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>, <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>, <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, y1)</code> and <code>(x2, 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 + width - 1</code>. 524 * The top and bottom edges are at 525 * {@code y} and <code>y + height - 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 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 + width</code>, 577 * respectively. The top and bottom edges of the rectangle are at 578 * {@code y} and <code>y + 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 + width - 1</code>, 601 * respectively. The top and bottom edges of the rectangle are at 602 * {@code y} and <code>y + height - 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 + 1</code> pixels wide 629 * and <code>height + 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 degrees 671 * is at the 3 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>, <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 + 1</code> pixels wide 681 * by <code>height + 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 degrees 707 * is at the 3 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>, <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 + 1</code> pixels wide 717 * by <code>height + 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>, <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>, <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 - 1</code> 772 * line segments are line segments from 773 * <code>(xPoints[i - 1], yPoints[i - 1])</code> 774 * to <code>(xPoints[i], yPoints[i])</code>, for 775 * 1 ≤ <i>i</i> ≤ {@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 - 1</code> 801 * line segments are line segments from 802 * <code>(xPoints[i - 1], yPoints[i - 1])</code> 803 * to <code>(xPoints[i], yPoints[i])</code>, for 804 * 1 ≤ <i>i</i> ≤ {@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>, <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>, <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>, <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>, <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>, <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 }