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 import javax.tools.annotation.GenerateNativeHeader;
  96 
  97 /**
  98  * This is a the master Graphics2D superclass for all of the Sun
  99  * Graphics implementations.  This class relies on subclasses to
 100  * manage the various device information, but provides an overall
 101  * general framework for performing all of the requests in the
 102  * Graphics and Graphics2D APIs.
 103  *
 104  * @author Jim Graham
 105  */
 106 /* No native methods here, but the constants are needed in the supporting JNI code */
 107 @GenerateNativeHeader
 108 public final class SunGraphics2D
 109     extends Graphics2D
 110     implements ConstrainableGraphics, Cloneable, DestSurfaceProvider
 111 {
 112     /*


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


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


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






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


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




 345         Region c = constrainClip;
 346         if (c == null) {
 347             c = Region.getInstanceXYXY(x, y, w, h);
 348         } else {
 349             c = c.getIntersectionXYXY(x, y, w, h);







 350             if (c == constrainClip) {
 351                 // Common case to ignore
 352                 return;
 353             }
 354         }
 355         constrainClip = c;
 356         if (!devClip.isInsideQuickCheck(c)) {
 357             devClip = devClip.getIntersection(c);
 358             validateCompClip();
 359         }
 360     }
 361 

















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


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

1543     public void setTransform(AffineTransform Tx) {
1544         if ((constrainX|constrainY) == 0) {
1545             transform.setTransform(Tx);
1546         } else {
1547             transform.setToTranslation(constrainX, constrainY);

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


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

1605     public AffineTransform getTransform() {
1606         if ((constrainX|constrainY) == 0) {
1607             return new AffineTransform(transform);
1608         }
1609         AffineTransform tx =
1610             AffineTransform.getTranslateInstance(-constrainX, -constrainY);


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


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































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

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








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







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


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





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


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












3211         }
3212 
3213         try {
3214             return imagepipe.transformImage(this, img, xform, observer);
3215         } catch (InvalidPipeException e) {
3216             try {
3217                 revalidateAll();
3218                 return imagepipe.transformImage(this, img, xform, observer);
3219             } catch (InvalidPipeException e2) {
3220                 // Still catching the exception; we are not yet ready to
3221                 // validate the surfaceData correctly.  Fail for now and
3222                 // try again next time around.
3223                 return false;
3224             }
3225         } finally {
3226             surfaceData.markDirty();
3227         }
3228     }
3229 
3230     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 import javax.tools.annotation.GenerateNativeHeader;
  96 
  97 /**
  98  * This is a the master Graphics2D superclass for all of the Sun
  99  * Graphics implementations.  This class relies on subclasses to
 100  * manage the various device information, but provides an overall
 101  * general framework for performing all of the requests in the
 102  * Graphics and Graphics2D APIs.
 103  *
 104  * @author Jim Graham
 105  */
 106 /* No native methods here, but the constants are needed in the supporting JNI code */
 107 @GenerateNativeHeader
 108 public final class SunGraphics2D
 109     extends Graphics2D
 110     implements ConstrainableGraphics, Cloneable, DestSurfaceProvider
 111 {
 112     /*


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


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


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









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


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


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


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


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


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