src/share/classes/sun/java2d/SunGraphics2D.java

Print this page




  48 import java.awt.image.ColorModel;
  49 import java.awt.GraphicsConfiguration;
  50 import java.awt.Paint;
  51 import java.awt.GradientPaint;
  52 import java.awt.LinearGradientPaint;
  53 import java.awt.RadialGradientPaint;
  54 import java.awt.TexturePaint;
  55 import java.awt.geom.Rectangle2D;
  56 import java.awt.geom.PathIterator;
  57 import java.awt.geom.GeneralPath;
  58 import java.awt.Shape;
  59 import java.awt.Stroke;
  60 import java.awt.FontMetrics;
  61 import java.awt.Rectangle;
  62 import java.text.AttributedCharacterIterator;
  63 import java.awt.Font;
  64 import java.awt.image.ImageObserver;
  65 import java.awt.Transparency;
  66 import java.awt.font.GlyphVector;
  67 import java.awt.font.TextLayout;


  68 import sun.font.FontDesignMetrics;
  69 import sun.font.FontUtilities;
  70 import sun.java2d.pipe.PixelDrawPipe;
  71 import sun.java2d.pipe.PixelFillPipe;
  72 import sun.java2d.pipe.ShapeDrawPipe;
  73 import sun.java2d.pipe.ValidatePipe;
  74 import sun.java2d.pipe.ShapeSpanIterator;
  75 import sun.java2d.pipe.Region;
  76 import sun.java2d.pipe.TextPipe;
  77 import sun.java2d.pipe.DrawImagePipe;
  78 import sun.java2d.pipe.LoopPipe;
  79 import sun.java2d.loops.FontInfo;
  80 import sun.java2d.loops.RenderLoops;
  81 import sun.java2d.loops.CompositeType;
  82 import sun.java2d.loops.SurfaceType;
  83 import sun.java2d.loops.Blit;
  84 import sun.java2d.loops.MaskFill;
  85 import sun.font.FontManager;
  86 import java.awt.font.FontRenderContext;
  87 import sun.java2d.loops.XORComposite;
  88 import sun.awt.ConstrainableGraphics;
  89 import sun.awt.SunHints;
  90 import java.util.Map;
  91 import java.util.Iterator;
  92 import sun.java2d.DestSurfaceProvider;
  93 import sun.misc.PerformanceLogger;
  94 
  95 /**
  96  * This is a the master Graphics2D superclass for all of the Sun
  97  * Graphics implementations.  This class relies on subclasses to
  98  * manage the various device information, but provides an overall
  99  * general framework for performing all of the requests in the
 100  * Graphics and Graphics2D APIs.
 101  *
 102  * @author Jim Graham
 103  */
 104 public final class SunGraphics2D
 105     extends Graphics2D
 106     implements ConstrainableGraphics, Cloneable, DestSurfaceProvider
 107 {
 108     /*
 109      * Attribute States
 110      */
 111     /* Paint */
 112     public static final int PAINT_CUSTOM       = 6; /* Any other Paint object */


 186     protected Font font;
 187     protected FontMetrics fontMetrics;
 188 
 189     public int renderHint;
 190     public int antialiasHint;
 191     public int textAntialiasHint;
 192     protected int fractionalMetricsHint;
 193 
 194     /* A gamma adjustment to the colour used in lcd text blitting */
 195     public int lcdTextContrast;
 196     private static int lcdTextContrastDefaultValue = 140;
 197 
 198     private int interpolationHint;      // raw value of rendering Hint
 199     public int strokeHint;
 200 
 201     public int interpolationType;       // algorithm choice based on
 202                                         // interpolation and render Hints
 203 
 204     public RenderingHints hints;
 205 
 206     public Region constrainClip;                // lightweight bounds
 207     public int constrainX;
 208     public int constrainY;
 209 
 210     public Region clipRegion;
 211     public Shape usrClip;
 212     protected Region devClip;           // Actual physical drawable


 213 
 214     // cached state for text rendering
 215     private boolean validFontInfo;
 216     private FontInfo fontInfo;
 217     private FontInfo glyphVectorFontInfo;
 218     private FontRenderContext glyphVectorFRC;
 219 
 220     private final static int slowTextTransformMask =
 221                             AffineTransform.TYPE_GENERAL_TRANSFORM
 222                         |   AffineTransform.TYPE_MASK_ROTATION
 223                         |   AffineTransform.TYPE_FLIP;
 224 
 225     static {
 226         if (PerformanceLogger.loggingEnabled()) {
 227             PerformanceLogger.setTime("SunGraphics2D static initialization");
 228         }
 229     }
 230 
 231     public SunGraphics2D(SurfaceData sd, Color fg, Color bg, Font f) {
 232         surfaceData = sd;


 235 
 236         transform = new AffineTransform();
 237         stroke = defaultStroke;
 238         composite = defaultComposite;
 239         paint = foregroundColor;
 240 
 241         imageComp = CompositeType.SrcOverNoEa;
 242 
 243         renderHint = SunHints.INTVAL_RENDER_DEFAULT;
 244         antialiasHint = SunHints.INTVAL_ANTIALIAS_OFF;
 245         textAntialiasHint = SunHints.INTVAL_TEXT_ANTIALIAS_DEFAULT;
 246         fractionalMetricsHint = SunHints.INTVAL_FRACTIONALMETRICS_OFF;
 247         lcdTextContrast = lcdTextContrastDefaultValue;
 248         interpolationHint = -1;
 249         strokeHint = SunHints.INTVAL_STROKE_DEFAULT;
 250 
 251         interpolationType = AffineTransformOp.TYPE_NEAREST_NEIGHBOR;
 252 
 253         validateColor();
 254 






 255         font = f;
 256         if (font == null) {
 257             font = defaultFont;
 258         }
 259 
 260         setDevClip(sd.getBounds());
 261         invalidatePipe();
 262     }
 263 
 264     protected Object clone() {
 265         try {
 266             SunGraphics2D g = (SunGraphics2D) super.clone();
 267             g.transform = new AffineTransform(this.transform);
 268             if (hints != null) {
 269                 g.hints = (RenderingHints) this.hints.clone();
 270             }
 271             /* FontInfos are re-used, so must be cloned too, if they
 272              * are valid, and be nulled out if invalid.
 273              * The implied trade-off is that there is more to be gained
 274              * from re-using these objects than is lost by having to


 299     public Graphics create() {
 300         return (Graphics) clone();
 301     }
 302 
 303     public void setDevClip(int x, int y, int w, int h) {
 304         Region c = constrainClip;
 305         if (c == null) {
 306             devClip = Region.getInstanceXYWH(x, y, w, h);
 307         } else {
 308             devClip = c.getIntersectionXYWH(x, y, w, h);
 309         }
 310         validateCompClip();
 311     }
 312 
 313     public void setDevClip(Rectangle r) {
 314         setDevClip(r.x, r.y, r.width, r.height);
 315     }
 316 
 317     /**
 318      * Constrain rendering for lightweight objects.
 319      *
 320      * REMIND: This method will back off to the "workaround"
 321      * of using translate and clipRect if the Graphics
 322      * to be constrained has a complex transform.  The
 323      * drawback of the workaround is that the resulting
 324      * clip and device origin cannot be "enforced".
 325      *
 326      * @exception IllegalStateException If the Graphics
 327      * to be constrained has a complex transform.
 328      */
 329     public void constrain(int x, int y, int w, int h) {
 330         if ((x|y) != 0) {
 331             translate(x, y);
 332         }
 333         if (transformState >= TRANSFORM_TRANSLATESCALE) {
 334             clipRect(0, 0, w, h);
 335             return;
 336         }
 337         x = constrainX = transX;
 338         y = constrainY = transY;
 339         w = Region.dimAdd(x, w);
 340         h = Region.dimAdd(y, h);




 341         Region c = constrainClip;
 342         if (c == null) {
 343             c = Region.getInstanceXYXY(x, y, w, h);
 344         } else {
 345             c = c.getIntersectionXYXY(x, y, w, h);







 346             if (c == constrainClip) {
 347                 // Common case to ignore
 348                 return;
 349             }
 350         }
 351         constrainClip = c;
 352         if (!devClip.isInsideQuickCheck(c)) {
 353             devClip = devClip.getIntersection(c);
 354             validateCompClip();
 355         }
 356     }
 357 

















 358     protected static ValidatePipe invalidpipe = new ValidatePipe();
 359 
 360     /*
 361      * Invalidate the pipeline
 362      */
 363     protected void invalidatePipe() {
 364         drawpipe = invalidpipe;
 365         fillpipe = invalidpipe;
 366         shapepipe = invalidpipe;
 367         textpipe = invalidpipe;
 368         imagepipe = invalidpipe;
 369         loops = null;
 370     }
 371 
 372     public void validatePipe() {
 373         /* This workaround is for the situation when we update the Pipelines
 374          * for invalid SurfaceData and run further code when the current
 375          * pipeline doesn't support the type of new SurfaceData created during
 376          * the current pipeline's work (in place of the invalid SurfaceData).
 377          * Usually SurfaceData and Pipelines are repaired (through revalidateAll)


1519      */
1520     public void translate(int x, int y) {
1521         transform.translate(x, y);
1522         if (transformState <= TRANSFORM_INT_TRANSLATE) {
1523             transX += x;
1524             transY += y;
1525             transformState = (((transX | transY) == 0) ?
1526                               TRANSFORM_ISIDENT : TRANSFORM_INT_TRANSLATE);
1527         } else {
1528             invalidateTransform();
1529         }
1530     }
1531 
1532     /**
1533      * Sets the Transform in the current graphics state.
1534      * @param Tx The Transform object to be used in the rendering process.
1535      * @see #transform
1536      * @see TransformChain
1537      * @see AffineTransform
1538      */

1539     public void setTransform(AffineTransform Tx) {
1540         if ((constrainX|constrainY) == 0) {
1541             transform.setTransform(Tx);
1542         } else {
1543             transform.setToTranslation(constrainX, constrainY);

1544             transform.concatenate(Tx);
1545         }
1546         invalidateTransform();
1547     }
1548 
1549     protected void invalidateTransform() {
1550         int type = transform.getType();
1551         int origTransformState = transformState;
1552         if (type == AffineTransform.TYPE_IDENTITY) {
1553             transformState = TRANSFORM_ISIDENT;
1554             transX = transY = 0;
1555         } else if (type == AffineTransform.TYPE_TRANSLATION) {
1556             double dtx = transform.getTranslateX();
1557             double dty = transform.getTranslateY();
1558             transX = (int) Math.floor(dtx + 0.5);
1559             transY = (int) Math.floor(dty + 0.5);
1560             if (dtx == transX && dty == transY) {
1561                 transformState = TRANSFORM_INT_TRANSLATE;
1562             } else {
1563                 transformState = TRANSFORM_ANY_TRANSLATE;


1581              */
1582             cachedFRC = null;
1583             this.validFontInfo = false;
1584             this.fontMetrics = null;
1585             this.glyphVectorFontInfo = null;
1586 
1587             if (transformState != origTransformState) {
1588                 invalidatePipe();
1589             }
1590         }
1591         if (strokeState != STROKE_CUSTOM) {
1592             validateBasicStroke((BasicStroke) stroke);
1593         }
1594     }
1595 
1596     /**
1597      * Returns the current Transform in the Graphics2D state.
1598      * @see #transform
1599      * @see #setTransform
1600      */

1601     public AffineTransform getTransform() {
1602         if ((constrainX|constrainY) == 0) {
1603             return new AffineTransform(transform);
1604         }
1605         AffineTransform tx =
1606             AffineTransform.getTranslateInstance(-constrainX, -constrainY);


1607         tx.concatenate(transform);
1608         return tx;
1609     }
1610 
1611     /**
1612      * Returns the current Transform ignoring the "constrain"
1613      * rectangle.
1614      */
1615     public AffineTransform cloneTransform() {
1616         return new AffineTransform(transform);
1617     }
1618 
1619     /**
1620      * Returns the current Paint in the Graphics2D state.
1621      * @see #setPaint
1622      * @see java.awt.Graphics#setColor
1623      */
1624     public Paint getPaint() {
1625         return paint;
1626     }


2970             return;
2971         }
2972 
2973         try {
2974             textpipe.drawChars(this, chData, 0, length, x, y);
2975         } catch (InvalidPipeException e) {
2976             try {
2977                 revalidateAll();
2978                 textpipe.drawChars(this, chData, 0, length, x, y);
2979             } catch (InvalidPipeException e2) {
2980                 // Still catching the exception; we are not yet ready to
2981                 // validate the surfaceData correctly.  Fail for now and
2982                 // try again next time around.
2983             }
2984         } finally {
2985             surfaceData.markDirty();
2986         }
2987     }
2988 // end of text rendering methods
2989 































2990     /**
2991      * Draws an image scaled to x,y,w,h in nonblocking mode with a
2992      * callback object.
2993      */
2994     public boolean drawImage(Image img, int x, int y, int width, int height,
2995                              ImageObserver observer) {
2996         return drawImage(img, x, y, width, height, null, observer);
2997     }
2998 
2999     /**
3000      * Not part of the advertised API but a useful utility method
3001      * to call internally.  This is for the case where we are
3002      * drawing to/from given coordinates using a given width/height,
3003      * but we guarantee that the weidth/height of the src and dest
3004      * areas are equal (no scale needed).

3005      */
3006     public boolean copyImage(Image img, int dx, int dy, int sx, int sy,
3007                              int width, int height, Color bgcolor,
3008                              ImageObserver observer) {
3009         try {
3010             return imagepipe.copyImage(this, img, dx, dy, sx, sy,
3011                                        width, height, bgcolor, observer);
3012         } catch (InvalidPipeException e) {
3013             try {
3014                 revalidateAll();
3015                 return imagepipe.copyImage(this, img, dx, dy, sx, sy,
3016                                            width, height, bgcolor, observer);
3017             } catch (InvalidPipeException e2) {
3018                 // Still catching the exception; we are not yet ready to
3019                 // validate the surfaceData correctly.  Fail for now and
3020                 // try again next time around.
3021                 return false;
3022             }
3023         } finally {
3024             surfaceData.markDirty();
3025         }
3026     }
3027 
3028     /**
3029      * Draws an image scaled to x,y,w,h in nonblocking mode with a
3030      * solid background color and a callback object.
3031      */
3032     public boolean drawImage(Image img, int x, int y, int width, int height,
3033                              Color bg, ImageObserver observer) {
3034 
3035         if (img == null) {
3036             return true;
3037         }
3038 
3039         if ((width == 0) || (height == 0)) {
3040             return true;
3041         }
3042         if (width == img.getWidth(null) && height == img.getHeight(null)) {








3043             return copyImage(img, x, y, 0, 0, width, height, bg, observer);
3044         }
3045 
3046         try {
3047             return imagepipe.scaleImage(this, img, x, y, width, height,
3048                                         bg, observer);
3049         } catch (InvalidPipeException e) {
3050             try {
3051                 revalidateAll();
3052                 return imagepipe.scaleImage(this, img, x, y, width, height,
3053                                             bg, observer);
3054             } catch (InvalidPipeException e2) {
3055                 // Still catching the exception; we are not yet ready to
3056                 // validate the surfaceData correctly.  Fail for now and
3057                 // try again next time around.
3058                 return false;
3059             }
3060         } finally {
3061             surfaceData.markDirty();
3062         }
3063     }
3064 
3065     /**
3066      * Draws an image at x,y in nonblocking mode.
3067      */
3068     public boolean drawImage(Image img, int x, int y, ImageObserver observer) {
3069         return drawImage(img, x, y, null, observer);
3070     }
3071 
3072     /**
3073      * Draws an image at x,y in nonblocking mode with a solid background
3074      * color and a callback object.
3075      */
3076     public boolean drawImage(Image img, int x, int y, Color bg,
3077                              ImageObserver observer) {
3078 
3079         if (img == null) {
3080             return true;
3081         }
3082 







3083         try {
3084             return imagepipe.copyImage(this, img, x, y, bg, observer);
3085         } catch (InvalidPipeException e) {
3086             try {
3087                 revalidateAll();
3088                 return imagepipe.copyImage(this, img, x, y, bg, observer);
3089             } catch (InvalidPipeException e2) {
3090                 // Still catching the exception; we are not yet ready to
3091                 // validate the surfaceData correctly.  Fail for now and
3092                 // try again next time around.
3093                 return false;
3094             }
3095         } finally {
3096             surfaceData.markDirty();
3097         }
3098     }
3099 
3100     /**
3101      * Draws a subrectangle of an image scaled to a destination rectangle
3102      * in nonblocking mode with a callback object.


3111 
3112     /**
3113      * Draws a subrectangle of an image scaled to a destination rectangle in
3114      * nonblocking mode with a solid background color and a callback object.
3115      */
3116     public boolean drawImage(Image img,
3117                              int dx1, int dy1, int dx2, int dy2,
3118                              int sx1, int sy1, int sx2, int sy2,
3119                              Color bgcolor, ImageObserver observer) {
3120 
3121         if (img == null) {
3122             return true;
3123         }
3124 
3125         if (dx1 == dx2 || dy1 == dy2 ||
3126             sx1 == sx2 || sy1 == sy2)
3127         {
3128             return true;
3129         }
3130 





3131         if (((sx2 - sx1) == (dx2 - dx1)) &&
3132             ((sy2 - sy1) == (dy2 - dy1)))
3133         {
3134             // Not a scale - forward it to a copy routine
3135             int srcX, srcY, dstX, dstY, width, height;
3136             if (sx2 > sx1) {
3137                 width = sx2 - sx1;
3138                 srcX = sx1;
3139                 dstX = dx1;
3140             } else {
3141                 width = sx1 - sx2;
3142                 srcX = sx2;
3143                 dstX = dx2;
3144             }
3145             if (sy2 > sy1) {
3146                 height = sy2-sy1;
3147                 srcY = sy1;
3148                 dstY = dy1;
3149             } else {
3150                 height = sy1-sy2;


3187      * paint or color and composite attributes. Note that the result is
3188      * undefined, if the given transform is non-invertible.
3189      * @param img The image to be drawn.
3190      * @param xform The transformation from image space into user space.
3191      * @param observer The image observer to be notified on the image producing
3192      * progress.
3193      * @see #transform
3194      * @see #setComposite
3195      * @see #setClip
3196      */
3197     public boolean drawImage(Image img,
3198                              AffineTransform xform,
3199                              ImageObserver observer) {
3200 
3201         if (img == null) {
3202             return true;
3203         }
3204 
3205         if (xform == null || xform.isIdentity()) {
3206             return drawImage(img, 0, 0, null, observer);












3207         }
3208 
3209         try {
3210             return imagepipe.transformImage(this, img, xform, observer);
3211         } catch (InvalidPipeException e) {
3212             try {
3213                 revalidateAll();
3214                 return imagepipe.transformImage(this, img, xform, observer);
3215             } catch (InvalidPipeException e2) {
3216                 // Still catching the exception; we are not yet ready to
3217                 // validate the surfaceData correctly.  Fail for now and
3218                 // try again next time around.
3219                 return false;
3220             }
3221         } finally {
3222             surfaceData.markDirty();
3223         }
3224     }
3225 
3226     public void drawImage(BufferedImage bImg,




  48 import java.awt.image.ColorModel;
  49 import java.awt.GraphicsConfiguration;
  50 import java.awt.Paint;
  51 import java.awt.GradientPaint;
  52 import java.awt.LinearGradientPaint;
  53 import java.awt.RadialGradientPaint;
  54 import java.awt.TexturePaint;
  55 import java.awt.geom.Rectangle2D;
  56 import java.awt.geom.PathIterator;
  57 import java.awt.geom.GeneralPath;
  58 import java.awt.Shape;
  59 import java.awt.Stroke;
  60 import java.awt.FontMetrics;
  61 import java.awt.Rectangle;
  62 import java.text.AttributedCharacterIterator;
  63 import java.awt.Font;
  64 import java.awt.image.ImageObserver;
  65 import java.awt.Transparency;
  66 import java.awt.font.GlyphVector;
  67 import java.awt.font.TextLayout;
  68 
  69 import sun.awt.image.SurfaceManager;
  70 import sun.font.FontDesignMetrics;
  71 import sun.font.FontUtilities;
  72 import sun.java2d.pipe.PixelDrawPipe;
  73 import sun.java2d.pipe.PixelFillPipe;
  74 import sun.java2d.pipe.ShapeDrawPipe;
  75 import sun.java2d.pipe.ValidatePipe;
  76 import sun.java2d.pipe.ShapeSpanIterator;
  77 import sun.java2d.pipe.Region;
  78 import sun.java2d.pipe.TextPipe;
  79 import sun.java2d.pipe.DrawImagePipe;
  80 import sun.java2d.pipe.LoopPipe;
  81 import sun.java2d.loops.FontInfo;
  82 import sun.java2d.loops.RenderLoops;
  83 import sun.java2d.loops.CompositeType;
  84 import sun.java2d.loops.SurfaceType;
  85 import sun.java2d.loops.Blit;
  86 import sun.java2d.loops.MaskFill;

  87 import java.awt.font.FontRenderContext;
  88 import sun.java2d.loops.XORComposite;
  89 import sun.awt.ConstrainableGraphics;
  90 import sun.awt.SunHints;
  91 import java.util.Map;
  92 import java.util.Iterator;

  93 import sun.misc.PerformanceLogger;
  94 
  95 /**
  96  * This is a the master Graphics2D superclass for all of the Sun
  97  * Graphics implementations.  This class relies on subclasses to
  98  * manage the various device information, but provides an overall
  99  * general framework for performing all of the requests in the
 100  * Graphics and Graphics2D APIs.
 101  *
 102  * @author Jim Graham
 103  */
 104 public final class SunGraphics2D
 105     extends Graphics2D
 106     implements ConstrainableGraphics, Cloneable, DestSurfaceProvider
 107 {
 108     /*
 109      * Attribute States
 110      */
 111     /* Paint */
 112     public static final int PAINT_CUSTOM       = 6; /* Any other Paint object */


 186     protected Font font;
 187     protected FontMetrics fontMetrics;
 188 
 189     public int renderHint;
 190     public int antialiasHint;
 191     public int textAntialiasHint;
 192     protected int fractionalMetricsHint;
 193 
 194     /* A gamma adjustment to the colour used in lcd text blitting */
 195     public int lcdTextContrast;
 196     private static int lcdTextContrastDefaultValue = 140;
 197 
 198     private int interpolationHint;      // raw value of rendering Hint
 199     public int strokeHint;
 200 
 201     public int interpolationType;       // algorithm choice based on
 202                                         // interpolation and render Hints
 203 
 204     public RenderingHints hints;
 205 
 206     public Region constrainClip;        // lightweight bounds in pixels
 207     public int constrainX;
 208     public int constrainY;
 209 
 210     public Region clipRegion;
 211     public Shape usrClip;
 212     protected Region devClip;           // Actual physical drawable in pixels
 213 
 214     private final int devScale;         // Actual physical scale factor
 215 
 216     // cached state for text rendering
 217     private boolean validFontInfo;
 218     private FontInfo fontInfo;
 219     private FontInfo glyphVectorFontInfo;
 220     private FontRenderContext glyphVectorFRC;
 221 
 222     private final static int slowTextTransformMask =
 223                             AffineTransform.TYPE_GENERAL_TRANSFORM
 224                         |   AffineTransform.TYPE_MASK_ROTATION
 225                         |   AffineTransform.TYPE_FLIP;
 226 
 227     static {
 228         if (PerformanceLogger.loggingEnabled()) {
 229             PerformanceLogger.setTime("SunGraphics2D static initialization");
 230         }
 231     }
 232 
 233     public SunGraphics2D(SurfaceData sd, Color fg, Color bg, Font f) {
 234         surfaceData = sd;


 237 
 238         transform = new AffineTransform();
 239         stroke = defaultStroke;
 240         composite = defaultComposite;
 241         paint = foregroundColor;
 242 
 243         imageComp = CompositeType.SrcOverNoEa;
 244 
 245         renderHint = SunHints.INTVAL_RENDER_DEFAULT;
 246         antialiasHint = SunHints.INTVAL_ANTIALIAS_OFF;
 247         textAntialiasHint = SunHints.INTVAL_TEXT_ANTIALIAS_DEFAULT;
 248         fractionalMetricsHint = SunHints.INTVAL_FRACTIONALMETRICS_OFF;
 249         lcdTextContrast = lcdTextContrastDefaultValue;
 250         interpolationHint = -1;
 251         strokeHint = SunHints.INTVAL_STROKE_DEFAULT;
 252 
 253         interpolationType = AffineTransformOp.TYPE_NEAREST_NEIGHBOR;
 254 
 255         validateColor();
 256 
 257         devScale = sd.getDefaultScale();
 258         if (devScale != 1) {
 259             transform.setToScale(devScale, devScale);
 260             invalidateTransform();
 261         }
 262 
 263         font = f;
 264         if (font == null) {
 265             font = defaultFont;
 266         }
 267 
 268         setDevClip(sd.getBounds());
 269         invalidatePipe();
 270     }
 271 
 272     protected Object clone() {
 273         try {
 274             SunGraphics2D g = (SunGraphics2D) super.clone();
 275             g.transform = new AffineTransform(this.transform);
 276             if (hints != null) {
 277                 g.hints = (RenderingHints) this.hints.clone();
 278             }
 279             /* FontInfos are re-used, so must be cloned too, if they
 280              * are valid, and be nulled out if invalid.
 281              * The implied trade-off is that there is more to be gained
 282              * from re-using these objects than is lost by having to


 307     public Graphics create() {
 308         return (Graphics) clone();
 309     }
 310 
 311     public void setDevClip(int x, int y, int w, int h) {
 312         Region c = constrainClip;
 313         if (c == null) {
 314             devClip = Region.getInstanceXYWH(x, y, w, h);
 315         } else {
 316             devClip = c.getIntersectionXYWH(x, y, w, h);
 317         }
 318         validateCompClip();
 319     }
 320 
 321     public void setDevClip(Rectangle r) {
 322         setDevClip(r.x, r.y, r.width, r.height);
 323     }
 324 
 325     /**
 326      * Constrain rendering for lightweight objects.









 327      */
 328     public void constrain(int x, int y, int w, int h, Region region) {
 329         if ((x | y) != 0) {
 330             translate(x, y);
 331         }
 332         if (transformState > TRANSFORM_TRANSLATESCALE) {
 333             clipRect(0, 0, w, h);
 334             return;
 335         }
 336         // changes parameters according to the current scale and translate.
 337         final double scaleX = transform.getScaleX();
 338         final double scaleY = transform.getScaleY();
 339         x = constrainX = (int) transform.getTranslateX();
 340         y = constrainY = (int) transform.getTranslateY();
 341         w = Region.dimAdd(x, Region.clipScale(w, scaleX));
 342         h = Region.dimAdd(y, Region.clipScale(h, scaleY));
 343 
 344         Region c = constrainClip;
 345         if (c == null) {
 346             c = Region.getInstanceXYXY(x, y, w, h);
 347         } else {
 348             c = c.getIntersectionXYXY(x, y, w, h);
 349         }
 350         if (region != null) {
 351             region = region.getScaledRegion(scaleX, scaleY);
 352             region = region.getTranslatedRegion(x, y);
 353             c = c.getIntersection(region);
 354         }
 355 
 356         if (c == constrainClip) {
 357             // Common case to ignore
 358             return;
 359         }
 360 
 361         constrainClip = c;
 362         if (!devClip.isInsideQuickCheck(c)) {
 363             devClip = devClip.getIntersection(c);
 364             validateCompClip();
 365         }
 366     }
 367 
 368     /**
 369      * Constrain rendering for lightweight objects.
 370      *
 371      * REMIND: This method will back off to the "workaround"
 372      * of using translate and clipRect if the Graphics
 373      * to be constrained has a complex transform.  The
 374      * drawback of the workaround is that the resulting
 375      * clip and device origin cannot be "enforced".
 376      *
 377      * @exception IllegalStateException If the Graphics
 378      * to be constrained has a complex transform.
 379      */
 380     @Override
 381     public void constrain(int x, int y, int w, int h) {
 382         constrain(x, y, w, h, null);
 383     }
 384 
 385     protected static ValidatePipe invalidpipe = new ValidatePipe();
 386 
 387     /*
 388      * Invalidate the pipeline
 389      */
 390     protected void invalidatePipe() {
 391         drawpipe = invalidpipe;
 392         fillpipe = invalidpipe;
 393         shapepipe = invalidpipe;
 394         textpipe = invalidpipe;
 395         imagepipe = invalidpipe;
 396         loops = null;
 397     }
 398 
 399     public void validatePipe() {
 400         /* This workaround is for the situation when we update the Pipelines
 401          * for invalid SurfaceData and run further code when the current
 402          * pipeline doesn't support the type of new SurfaceData created during
 403          * the current pipeline's work (in place of the invalid SurfaceData).
 404          * Usually SurfaceData and Pipelines are repaired (through revalidateAll)


1546      */
1547     public void translate(int x, int y) {
1548         transform.translate(x, y);
1549         if (transformState <= TRANSFORM_INT_TRANSLATE) {
1550             transX += x;
1551             transY += y;
1552             transformState = (((transX | transY) == 0) ?
1553                               TRANSFORM_ISIDENT : TRANSFORM_INT_TRANSLATE);
1554         } else {
1555             invalidateTransform();
1556         }
1557     }
1558 
1559     /**
1560      * Sets the Transform in the current graphics state.
1561      * @param Tx The Transform object to be used in the rendering process.
1562      * @see #transform
1563      * @see TransformChain
1564      * @see AffineTransform
1565      */
1566     @Override
1567     public void setTransform(AffineTransform Tx) {
1568         if ((constrainX | constrainY) == 0 && devScale == 1) {
1569             transform.setTransform(Tx);
1570         } else {
1571             transform.setTransform(devScale, 0, 0, devScale, constrainX,
1572                                    constrainY);
1573             transform.concatenate(Tx);
1574         }
1575         invalidateTransform();
1576     }
1577 
1578     protected void invalidateTransform() {
1579         int type = transform.getType();
1580         int origTransformState = transformState;
1581         if (type == AffineTransform.TYPE_IDENTITY) {
1582             transformState = TRANSFORM_ISIDENT;
1583             transX = transY = 0;
1584         } else if (type == AffineTransform.TYPE_TRANSLATION) {
1585             double dtx = transform.getTranslateX();
1586             double dty = transform.getTranslateY();
1587             transX = (int) Math.floor(dtx + 0.5);
1588             transY = (int) Math.floor(dty + 0.5);
1589             if (dtx == transX && dty == transY) {
1590                 transformState = TRANSFORM_INT_TRANSLATE;
1591             } else {
1592                 transformState = TRANSFORM_ANY_TRANSLATE;


1610              */
1611             cachedFRC = null;
1612             this.validFontInfo = false;
1613             this.fontMetrics = null;
1614             this.glyphVectorFontInfo = null;
1615 
1616             if (transformState != origTransformState) {
1617                 invalidatePipe();
1618             }
1619         }
1620         if (strokeState != STROKE_CUSTOM) {
1621             validateBasicStroke((BasicStroke) stroke);
1622         }
1623     }
1624 
1625     /**
1626      * Returns the current Transform in the Graphics2D state.
1627      * @see #transform
1628      * @see #setTransform
1629      */
1630     @Override
1631     public AffineTransform getTransform() {
1632         if ((constrainX | constrainY) == 0 && devScale == 1) {
1633             return new AffineTransform(transform);
1634         }
1635         final double invScale = 1.0 / devScale;
1636         AffineTransform tx = new AffineTransform(invScale, 0, 0, invScale,
1637                                                  -constrainX * invScale,
1638                                                  -constrainY * invScale);
1639         tx.concatenate(transform);
1640         return tx;
1641     }
1642 
1643     /**
1644      * Returns the current Transform ignoring the "constrain"
1645      * rectangle.
1646      */
1647     public AffineTransform cloneTransform() {
1648         return new AffineTransform(transform);
1649     }
1650 
1651     /**
1652      * Returns the current Paint in the Graphics2D state.
1653      * @see #setPaint
1654      * @see java.awt.Graphics#setColor
1655      */
1656     public Paint getPaint() {
1657         return paint;
1658     }


3002             return;
3003         }
3004 
3005         try {
3006             textpipe.drawChars(this, chData, 0, length, x, y);
3007         } catch (InvalidPipeException e) {
3008             try {
3009                 revalidateAll();
3010                 textpipe.drawChars(this, chData, 0, length, x, y);
3011             } catch (InvalidPipeException e2) {
3012                 // Still catching the exception; we are not yet ready to
3013                 // validate the surfaceData correctly.  Fail for now and
3014                 // try again next time around.
3015             }
3016         } finally {
3017             surfaceData.markDirty();
3018         }
3019     }
3020 // end of text rendering methods
3021 
3022     private static boolean isHiDPIImage(final Image img) {
3023         return SurfaceManager.getImageScale(img) != 1;
3024     }
3025 
3026     private boolean drawHiDPIImage(Image img, int dx1, int dy1, int dx2,
3027                                    int dy2, int sx1, int sy1, int sx2, int sy2,
3028                                    Color bgcolor, ImageObserver observer) {
3029         final int scale = SurfaceManager.getImageScale(img);
3030         sx1 = Region.clipScale(sx1, scale);
3031         sx2 = Region.clipScale(sx2, scale);
3032         sy1 = Region.clipScale(sy1, scale);
3033         sy2 = Region.clipScale(sy2, scale);
3034         try {
3035             return imagepipe.scaleImage(this, img, dx1, dy1, dx2, dy2, sx1, sy1,
3036                                         sx2, sy2, bgcolor, observer);
3037         } catch (InvalidPipeException e) {
3038             try {
3039                 revalidateAll();
3040                 return imagepipe.scaleImage(this, img, dx1, dy1, dx2, dy2, sx1,
3041                                             sy1, sx2, sy2, bgcolor, observer);
3042             } catch (InvalidPipeException e2) {
3043                 // Still catching the exception; we are not yet ready to
3044                 // validate the surfaceData correctly.  Fail for now and
3045                 // try again next time around.
3046                 return false;
3047             }
3048         } finally {
3049             surfaceData.markDirty();
3050         }
3051     }
3052 
3053     /**
3054      * Draws an image scaled to x,y,w,h in nonblocking mode with a
3055      * callback object.
3056      */
3057     public boolean drawImage(Image img, int x, int y, int width, int height,
3058                              ImageObserver observer) {
3059         return drawImage(img, x, y, width, height, null, observer);
3060     }
3061 
3062     /**
3063      * Not part of the advertised API but a useful utility method
3064      * to call internally.  This is for the case where we are
3065      * drawing to/from given coordinates using a given width/height,
3066      * but we guarantee that the surfaceData's width/height of the src and dest
3067      * areas are equal (no scale needed). Note that this method intentionally
3068      * ignore scale factor of the source image, and copy it as is.
3069      */
3070     public boolean copyImage(Image img, int dx, int dy, int sx, int sy,
3071                              int width, int height, Color bgcolor,
3072                              ImageObserver observer) {
3073         try {
3074             return imagepipe.copyImage(this, img, dx, dy, sx, sy,
3075                                        width, height, bgcolor, observer);
3076         } catch (InvalidPipeException e) {
3077             try {
3078                 revalidateAll();
3079                 return imagepipe.copyImage(this, img, dx, dy, sx, sy,
3080                                            width, height, bgcolor, observer);
3081             } catch (InvalidPipeException e2) {
3082                 // Still catching the exception; we are not yet ready to
3083                 // validate the surfaceData correctly.  Fail for now and
3084                 // try again next time around.
3085                 return false;
3086             }
3087         } finally {
3088             surfaceData.markDirty();
3089         }
3090     }
3091 
3092     /**
3093      * Draws an image scaled to x,y,w,h in nonblocking mode with a
3094      * solid background color and a callback object.
3095      */
3096     public boolean drawImage(Image img, int x, int y, int width, int height,
3097                              Color bg, ImageObserver observer) {
3098 
3099         if (img == null) {
3100             return true;
3101         }
3102 
3103         if ((width == 0) || (height == 0)) {
3104             return true;
3105         }
3106 
3107         final int imgW = img.getWidth(null);
3108         final int imgH = img.getHeight(null);
3109         if (isHiDPIImage(img)) {
3110             return drawHiDPIImage(img, x, y, x + width, y + height, 0, 0, imgW,
3111                                   imgH, bg, observer);
3112         }
3113 
3114         if (width == imgW && height == imgH) {
3115             return copyImage(img, x, y, 0, 0, width, height, bg, observer);
3116         }
3117 
3118         try {
3119             return imagepipe.scaleImage(this, img, x, y, width, height,
3120                                         bg, observer);
3121         } catch (InvalidPipeException e) {
3122             try {
3123                 revalidateAll();
3124                 return imagepipe.scaleImage(this, img, x, y, width, height,
3125                                             bg, observer);
3126             } catch (InvalidPipeException e2) {
3127                 // Still catching the exception; we are not yet ready to
3128                 // validate the surfaceData correctly.  Fail for now and
3129                 // try again next time around.
3130                 return false;
3131             }
3132         } finally {
3133             surfaceData.markDirty();
3134         }
3135     }
3136 
3137     /**
3138      * Draws an image at x,y in nonblocking mode.
3139      */
3140     public boolean drawImage(Image img, int x, int y, ImageObserver observer) {
3141         return drawImage(img, x, y, null, observer);
3142     }
3143 
3144     /**
3145      * Draws an image at x,y in nonblocking mode with a solid background
3146      * color and a callback object.
3147      */
3148     public boolean drawImage(Image img, int x, int y, Color bg,
3149                              ImageObserver observer) {
3150 
3151         if (img == null) {
3152             return true;
3153         }
3154 
3155         if (isHiDPIImage(img)) {
3156             final int imgW = img.getWidth(null);
3157             final int imgH = img.getHeight(null);
3158             return drawHiDPIImage(img, x, y, x + imgW, y + imgH, 0, 0, imgW,
3159                                   imgH, bg, observer);
3160         }
3161 
3162         try {
3163             return imagepipe.copyImage(this, img, x, y, bg, observer);
3164         } catch (InvalidPipeException e) {
3165             try {
3166                 revalidateAll();
3167                 return imagepipe.copyImage(this, img, x, y, bg, observer);
3168             } catch (InvalidPipeException e2) {
3169                 // Still catching the exception; we are not yet ready to
3170                 // validate the surfaceData correctly.  Fail for now and
3171                 // try again next time around.
3172                 return false;
3173             }
3174         } finally {
3175             surfaceData.markDirty();
3176         }
3177     }
3178 
3179     /**
3180      * Draws a subrectangle of an image scaled to a destination rectangle
3181      * in nonblocking mode with a callback object.


3190 
3191     /**
3192      * Draws a subrectangle of an image scaled to a destination rectangle in
3193      * nonblocking mode with a solid background color and a callback object.
3194      */
3195     public boolean drawImage(Image img,
3196                              int dx1, int dy1, int dx2, int dy2,
3197                              int sx1, int sy1, int sx2, int sy2,
3198                              Color bgcolor, ImageObserver observer) {
3199 
3200         if (img == null) {
3201             return true;
3202         }
3203 
3204         if (dx1 == dx2 || dy1 == dy2 ||
3205             sx1 == sx2 || sy1 == sy2)
3206         {
3207             return true;
3208         }
3209 
3210         if (isHiDPIImage(img)) {
3211             return drawHiDPIImage(img, dx1, dy1, dx2, dy2, sx1, sy1, sx2, sy2,
3212                                   bgcolor, observer);
3213         }
3214 
3215         if (((sx2 - sx1) == (dx2 - dx1)) &&
3216             ((sy2 - sy1) == (dy2 - dy1)))
3217         {
3218             // Not a scale - forward it to a copy routine
3219             int srcX, srcY, dstX, dstY, width, height;
3220             if (sx2 > sx1) {
3221                 width = sx2 - sx1;
3222                 srcX = sx1;
3223                 dstX = dx1;
3224             } else {
3225                 width = sx1 - sx2;
3226                 srcX = sx2;
3227                 dstX = dx2;
3228             }
3229             if (sy2 > sy1) {
3230                 height = sy2-sy1;
3231                 srcY = sy1;
3232                 dstY = dy1;
3233             } else {
3234                 height = sy1-sy2;


3271      * paint or color and composite attributes. Note that the result is
3272      * undefined, if the given transform is non-invertible.
3273      * @param img The image to be drawn.
3274      * @param xform The transformation from image space into user space.
3275      * @param observer The image observer to be notified on the image producing
3276      * progress.
3277      * @see #transform
3278      * @see #setComposite
3279      * @see #setClip
3280      */
3281     public boolean drawImage(Image img,
3282                              AffineTransform xform,
3283                              ImageObserver observer) {
3284 
3285         if (img == null) {
3286             return true;
3287         }
3288 
3289         if (xform == null || xform.isIdentity()) {
3290             return drawImage(img, 0, 0, null, observer);
3291         }
3292 
3293         if (isHiDPIImage(img)) {
3294             final int w = img.getWidth(null);
3295             final int h = img.getHeight(null);
3296             final AffineTransform tx = new AffineTransform(transform);
3297             transform(xform);
3298             boolean result = drawHiDPIImage(img, 0, 0, w, h, 0, 0, w, h, null,
3299                                             observer);
3300             transform.setTransform(tx);
3301             invalidateTransform();
3302             return result;
3303         }
3304 
3305         try {
3306             return imagepipe.transformImage(this, img, xform, observer);
3307         } catch (InvalidPipeException e) {
3308             try {
3309                 revalidateAll();
3310                 return imagepipe.transformImage(this, img, xform, observer);
3311             } catch (InvalidPipeException e2) {
3312                 // Still catching the exception; we are not yet ready to
3313                 // validate the surfaceData correctly.  Fail for now and
3314                 // try again next time around.
3315                 return false;
3316             }
3317         } finally {
3318             surfaceData.markDirty();
3319         }
3320     }
3321 
3322     public void drawImage(BufferedImage bImg,