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;


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,
3231                           BufferedImageOp op,
3232                           int x,




  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, -constrainY);
1642         tx.concatenate(transform);
1643         return tx;
1644     }
1645 
1646     /**
1647      * Returns the current Transform ignoring the "constrain"
1648      * rectangle.
1649      */
1650     public AffineTransform cloneTransform() {
1651         return new AffineTransform(transform);
1652     }
1653 
1654     /**
1655      * Returns the current Paint in the Graphics2D state.
1656      * @see #setPaint
1657      * @see java.awt.Graphics#setColor
1658      */
1659     public Paint getPaint() {
1660         return paint;
1661     }


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


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


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