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

Print this page




  44 import java.awt.image.WritableRaster;
  45 import java.awt.Image;
  46 import java.awt.Composite;
  47 import java.awt.Color;
  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 java.lang.annotation.Native;



  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 public final class SunGraphics2D
 107     extends Graphics2D
 108     implements ConstrainableGraphics, Cloneable, DestSurfaceProvider
 109 {
 110     /*
 111      * Attribute States
 112      */
 113     /* Paint */
 114     @Native
 115     public static final int PAINT_CUSTOM       = 6; /* Any other Paint object */


 220     public int lcdTextContrast;
 221     private static int lcdTextContrastDefaultValue = 140;
 222 
 223     private int interpolationHint;      // raw value of rendering Hint
 224     public int strokeHint;
 225 
 226     public int interpolationType;       // algorithm choice based on
 227                                         // interpolation and render Hints
 228 
 229     public RenderingHints hints;
 230 
 231     public Region constrainClip;        // lightweight bounds in pixels
 232     public int constrainX;
 233     public int constrainY;
 234 
 235     public Region clipRegion;
 236     public Shape usrClip;
 237     protected Region devClip;           // Actual physical drawable in pixels
 238 
 239     private final int devScale;         // Actual physical scale factor

 240 
 241     // cached state for text rendering
 242     private boolean validFontInfo;
 243     private FontInfo fontInfo;
 244     private FontInfo glyphVectorFontInfo;
 245     private FontRenderContext glyphVectorFRC;
 246 
 247     private final static int slowTextTransformMask =
 248                             AffineTransform.TYPE_GENERAL_TRANSFORM
 249                         |   AffineTransform.TYPE_MASK_ROTATION
 250                         |   AffineTransform.TYPE_FLIP;
 251 
 252     static {
 253         if (PerformanceLogger.loggingEnabled()) {
 254             PerformanceLogger.setTime("SunGraphics2D static initialization");
 255         }
 256     }
 257 
 258     public SunGraphics2D(SurfaceData sd, Color fg, Color bg, Font f) {
 259         surfaceData = sd;


 263         transform = new AffineTransform();
 264         stroke = defaultStroke;
 265         composite = defaultComposite;
 266         paint = foregroundColor;
 267 
 268         imageComp = CompositeType.SrcOverNoEa;
 269 
 270         renderHint = SunHints.INTVAL_RENDER_DEFAULT;
 271         antialiasHint = SunHints.INTVAL_ANTIALIAS_OFF;
 272         textAntialiasHint = SunHints.INTVAL_TEXT_ANTIALIAS_DEFAULT;
 273         fractionalMetricsHint = SunHints.INTVAL_FRACTIONALMETRICS_OFF;
 274         lcdTextContrast = lcdTextContrastDefaultValue;
 275         interpolationHint = -1;
 276         strokeHint = SunHints.INTVAL_STROKE_DEFAULT;
 277 
 278         interpolationType = AffineTransformOp.TYPE_NEAREST_NEIGHBOR;
 279 
 280         validateColor();
 281 
 282         devScale = sd.getDefaultScale();

 283         if (devScale != 1) {
 284             transform.setToScale(devScale, devScale);
 285             invalidateTransform();


 286         }
 287 
 288         font = f;
 289         if (font == null) {
 290             font = defaultFont;
 291         }
 292 
 293         setDevClip(sd.getBounds());
 294         invalidatePipe();
 295     }
 296 
 297     protected Object clone() {
 298         try {
 299             SunGraphics2D g = (SunGraphics2D) super.clone();
 300             g.transform = new AffineTransform(this.transform);
 301             if (hints != null) {
 302                 g.hints = (RenderingHints) this.hints.clone();
 303             }
 304             /* FontInfos are re-used, so must be cloned too, if they
 305              * are valid, and be nulled out if invalid.


1232                 interpolationHint = newHint;
1233                 switch (newHint) {
1234                 case SunHints.INTVAL_INTERPOLATION_BICUBIC:
1235                     newHint = AffineTransformOp.TYPE_BICUBIC;
1236                     break;
1237                 case SunHints.INTVAL_INTERPOLATION_BILINEAR:
1238                     newHint = AffineTransformOp.TYPE_BILINEAR;
1239                     break;
1240                 default:
1241                 case SunHints.INTVAL_INTERPOLATION_NEAREST_NEIGHBOR:
1242                     newHint = AffineTransformOp.TYPE_NEAREST_NEIGHBOR;
1243                     break;
1244                 }
1245                 stateChanged = (interpolationType != newHint);
1246                 interpolationType = newHint;
1247                 break;
1248             case SunHints.INTKEY_STROKE_CONTROL:
1249                 stateChanged = (strokeHint != newHint);
1250                 strokeHint = newHint;
1251                 break;




1252             default:
1253                 recognized = false;
1254                 stateChanged = false;
1255                 break;
1256             }
1257             if (recognized) {
1258                 if (stateChanged) {
1259                     invalidatePipe();
1260                     if (textStateChanged) {
1261                         fontMetrics = null;
1262                         this.cachedFRC = null;
1263                         validFontInfo = false;
1264                         this.glyphVectorFontInfo = null;
1265                     }
1266                 }
1267                 if (hints != null) {
1268                     hints.put(hintKey, hintValue);
1269                 }
1270                 return;
1271             }


1305             return SunHints.Value.get(SunHints.INTKEY_TEXT_ANTIALIASING,
1306                                       textAntialiasHint);
1307         case SunHints.INTKEY_FRACTIONALMETRICS:
1308             return SunHints.Value.get(SunHints.INTKEY_FRACTIONALMETRICS,
1309                                       fractionalMetricsHint);
1310         case SunHints.INTKEY_AATEXT_LCD_CONTRAST:
1311             return new Integer(lcdTextContrast);
1312         case SunHints.INTKEY_INTERPOLATION:
1313             switch (interpolationHint) {
1314             case SunHints.INTVAL_INTERPOLATION_NEAREST_NEIGHBOR:
1315                 return SunHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR;
1316             case SunHints.INTVAL_INTERPOLATION_BILINEAR:
1317                 return SunHints.VALUE_INTERPOLATION_BILINEAR;
1318             case SunHints.INTVAL_INTERPOLATION_BICUBIC:
1319                 return SunHints.VALUE_INTERPOLATION_BICUBIC;
1320             }
1321             return null;
1322         case SunHints.INTKEY_STROKE_CONTROL:
1323             return SunHints.Value.get(SunHints.INTKEY_STROKE_CONTROL,
1324                                       strokeHint);



1325         }
1326         return null;
1327     }
1328 
1329     /**
1330      * Sets the preferences for the rendering algorithms.
1331      * Hint categories include controls for rendering quality and
1332      * overall time/quality trade-off in the rendering process.
1333      * @param hints The rendering hints to be set
1334      * @see RenderingHints
1335      */
1336     public void setRenderingHints(Map<?,?> hints) {
1337         this.hints = null;
1338         renderHint = SunHints.INTVAL_RENDER_DEFAULT;
1339         antialiasHint = SunHints.INTVAL_ANTIALIAS_OFF;
1340         textAntialiasHint = SunHints.INTVAL_TEXT_ANTIALIAS_DEFAULT;
1341         fractionalMetricsHint = SunHints.INTVAL_FRACTIONALMETRICS_OFF;
1342         lcdTextContrast = lcdTextContrastDefaultValue;
1343         interpolationHint = -1;
1344         interpolationType = AffineTransformOp.TYPE_NEAREST_NEIGHBOR;


3033             return;
3034         }
3035 
3036         try {
3037             textpipe.drawChars(this, chData, 0, length, x, y);
3038         } catch (InvalidPipeException e) {
3039             try {
3040                 revalidateAll();
3041                 textpipe.drawChars(this, chData, 0, length, x, y);
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             }
3047         } finally {
3048             surfaceData.markDirty();
3049         }
3050     }
3051 // end of text rendering methods
3052 
3053     private static boolean isHiDPIImage(final Image img) {
3054         return SurfaceManager.getImageScale(img) != 1;


3055     }
3056 
3057     private boolean drawHiDPIImage(Image img, int dx1, int dy1, int dx2,
3058                                    int dy2, int sx1, int sy1, int sx2, int sy2,
3059                                    Color bgcolor, ImageObserver observer) {


3060         final int scale = SurfaceManager.getImageScale(img);
3061         sx1 = Region.clipScale(sx1, scale);
3062         sx2 = Region.clipScale(sx2, scale);
3063         sy1 = Region.clipScale(sy1, scale);
3064         sy2 = Region.clipScale(sy2, scale);


































3065         try {
3066             return imagepipe.scaleImage(this, img, dx1, dy1, dx2, dy2, sx1, sy1,
3067                                         sx2, sy2, bgcolor, observer);
3068         } catch (InvalidPipeException e) {
3069             try {
3070                 revalidateAll();
3071                 return imagepipe.scaleImage(this, img, dx1, dy1, dx2, dy2, sx1,
3072                                             sy1, sx2, sy2, bgcolor, observer);
3073             } catch (InvalidPipeException e2) {
3074                 // Still catching the exception; we are not yet ready to
3075                 // validate the surfaceData correctly.  Fail for now and
3076                 // try again next time around.
3077                 return false;
3078             }
3079         } finally {
3080             surfaceData.markDirty();
3081         }
3082     }
3083 











































3084     /**
3085      * Draws an image scaled to x,y,w,h in nonblocking mode with a
3086      * callback object.
3087      */
3088     public boolean drawImage(Image img, int x, int y, int width, int height,
3089                              ImageObserver observer) {
3090         return drawImage(img, x, y, width, height, null, observer);
3091     }
3092 
3093     /**
3094      * Not part of the advertised API but a useful utility method
3095      * to call internally.  This is for the case where we are
3096      * drawing to/from given coordinates using a given width/height,
3097      * but we guarantee that the surfaceData's width/height of the src and dest
3098      * areas are equal (no scale needed). Note that this method intentionally
3099      * ignore scale factor of the source image, and copy it as is.
3100      */
3101     public boolean copyImage(Image img, int dx, int dy, int sx, int sy,
3102                              int width, int height, Color bgcolor,
3103                              ImageObserver observer) {




  44 import java.awt.image.WritableRaster;
  45 import java.awt.Image;
  46 import java.awt.Composite;
  47 import java.awt.Color;
  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.Point;
  65 import java.awt.image.ImageObserver;
  66 import java.awt.Transparency;
  67 import java.awt.font.GlyphVector;
  68 import java.awt.font.TextLayout;
  69 
  70 import sun.awt.image.SurfaceManager;
  71 import sun.font.FontDesignMetrics;
  72 import sun.font.FontUtilities;
  73 import sun.java2d.pipe.PixelDrawPipe;
  74 import sun.java2d.pipe.PixelFillPipe;
  75 import sun.java2d.pipe.ShapeDrawPipe;
  76 import sun.java2d.pipe.ValidatePipe;
  77 import sun.java2d.pipe.ShapeSpanIterator;
  78 import sun.java2d.pipe.Region;
  79 import sun.java2d.pipe.TextPipe;
  80 import sun.java2d.pipe.DrawImagePipe;
  81 import sun.java2d.pipe.LoopPipe;
  82 import sun.java2d.loops.FontInfo;
  83 import sun.java2d.loops.RenderLoops;
  84 import sun.java2d.loops.CompositeType;
  85 import sun.java2d.loops.SurfaceType;
  86 import sun.java2d.loops.Blit;
  87 import sun.java2d.loops.MaskFill;
  88 import java.awt.font.FontRenderContext;
  89 import sun.java2d.loops.XORComposite;
  90 import sun.awt.ConstrainableGraphics;
  91 import sun.awt.SunHints;
  92 import java.util.Map;
  93 import java.util.Iterator;
  94 import sun.misc.PerformanceLogger;
  95 
  96 import java.lang.annotation.Native;
  97 import com.sun.awt.MultiResolutionImage;
  98 import java.awt.Dimension;
  99 import sun.awt.OSInfo;
 100 
 101 /**
 102  * This is a the master Graphics2D superclass for all of the Sun
 103  * Graphics implementations.  This class relies on subclasses to
 104  * manage the various device information, but provides an overall
 105  * general framework for performing all of the requests in the
 106  * Graphics and Graphics2D APIs.
 107  *
 108  * @author Jim Graham
 109  */
 110 public final class SunGraphics2D
 111     extends Graphics2D
 112     implements ConstrainableGraphics, Cloneable, DestSurfaceProvider
 113 {
 114     /*
 115      * Attribute States
 116      */
 117     /* Paint */
 118     @Native
 119     public static final int PAINT_CUSTOM       = 6; /* Any other Paint object */


 224     public int lcdTextContrast;
 225     private static int lcdTextContrastDefaultValue = 140;
 226 
 227     private int interpolationHint;      // raw value of rendering Hint
 228     public int strokeHint;
 229 
 230     public int interpolationType;       // algorithm choice based on
 231                                         // interpolation and render Hints
 232 
 233     public RenderingHints hints;
 234 
 235     public Region constrainClip;        // lightweight bounds in pixels
 236     public int constrainX;
 237     public int constrainY;
 238 
 239     public Region clipRegion;
 240     public Shape usrClip;
 241     protected Region devClip;           // Actual physical drawable in pixels
 242 
 243     private final int devScale;         // Actual physical scale factor
 244     private int resolutionVariantHint;
 245 
 246     // cached state for text rendering
 247     private boolean validFontInfo;
 248     private FontInfo fontInfo;
 249     private FontInfo glyphVectorFontInfo;
 250     private FontRenderContext glyphVectorFRC;
 251 
 252     private final static int slowTextTransformMask =
 253                             AffineTransform.TYPE_GENERAL_TRANSFORM
 254                         |   AffineTransform.TYPE_MASK_ROTATION
 255                         |   AffineTransform.TYPE_FLIP;
 256 
 257     static {
 258         if (PerformanceLogger.loggingEnabled()) {
 259             PerformanceLogger.setTime("SunGraphics2D static initialization");
 260         }
 261     }
 262 
 263     public SunGraphics2D(SurfaceData sd, Color fg, Color bg, Font f) {
 264         surfaceData = sd;


 268         transform = new AffineTransform();
 269         stroke = defaultStroke;
 270         composite = defaultComposite;
 271         paint = foregroundColor;
 272 
 273         imageComp = CompositeType.SrcOverNoEa;
 274 
 275         renderHint = SunHints.INTVAL_RENDER_DEFAULT;
 276         antialiasHint = SunHints.INTVAL_ANTIALIAS_OFF;
 277         textAntialiasHint = SunHints.INTVAL_TEXT_ANTIALIAS_DEFAULT;
 278         fractionalMetricsHint = SunHints.INTVAL_FRACTIONALMETRICS_OFF;
 279         lcdTextContrast = lcdTextContrastDefaultValue;
 280         interpolationHint = -1;
 281         strokeHint = SunHints.INTVAL_STROKE_DEFAULT;
 282 
 283         interpolationType = AffineTransformOp.TYPE_NEAREST_NEIGHBOR;
 284 
 285         validateColor();
 286 
 287         devScale = sd.getDefaultScale();
 288         resolutionVariantHint = SunHints.INTVAL_RESOLUTION_VARIANT_DEFAULT;
 289         if (devScale != 1) {
 290             transform.setToScale(devScale, devScale);
 291             invalidateTransform();
 292         } else if (!OSInfo.getOSType().equals(OSInfo.OSType.MACOSX)) {
 293             resolutionVariantHint = SunHints.INTVAL_RESOLUTION_VARIANT_OFF;
 294         }
 295 
 296         font = f;
 297         if (font == null) {
 298             font = defaultFont;
 299         }
 300 
 301         setDevClip(sd.getBounds());
 302         invalidatePipe();
 303     }
 304 
 305     protected Object clone() {
 306         try {
 307             SunGraphics2D g = (SunGraphics2D) super.clone();
 308             g.transform = new AffineTransform(this.transform);
 309             if (hints != null) {
 310                 g.hints = (RenderingHints) this.hints.clone();
 311             }
 312             /* FontInfos are re-used, so must be cloned too, if they
 313              * are valid, and be nulled out if invalid.


1240                 interpolationHint = newHint;
1241                 switch (newHint) {
1242                 case SunHints.INTVAL_INTERPOLATION_BICUBIC:
1243                     newHint = AffineTransformOp.TYPE_BICUBIC;
1244                     break;
1245                 case SunHints.INTVAL_INTERPOLATION_BILINEAR:
1246                     newHint = AffineTransformOp.TYPE_BILINEAR;
1247                     break;
1248                 default:
1249                 case SunHints.INTVAL_INTERPOLATION_NEAREST_NEIGHBOR:
1250                     newHint = AffineTransformOp.TYPE_NEAREST_NEIGHBOR;
1251                     break;
1252                 }
1253                 stateChanged = (interpolationType != newHint);
1254                 interpolationType = newHint;
1255                 break;
1256             case SunHints.INTKEY_STROKE_CONTROL:
1257                 stateChanged = (strokeHint != newHint);
1258                 strokeHint = newHint;
1259                 break;
1260             case SunHints.INTKEY_RESOLUTION_VARIANT:
1261                 stateChanged = (resolutionVariantHint != newHint);
1262                 resolutionVariantHint = newHint;
1263                 break;
1264             default:
1265                 recognized = false;
1266                 stateChanged = false;
1267                 break;
1268             }
1269             if (recognized) {
1270                 if (stateChanged) {
1271                     invalidatePipe();
1272                     if (textStateChanged) {
1273                         fontMetrics = null;
1274                         this.cachedFRC = null;
1275                         validFontInfo = false;
1276                         this.glyphVectorFontInfo = null;
1277                     }
1278                 }
1279                 if (hints != null) {
1280                     hints.put(hintKey, hintValue);
1281                 }
1282                 return;
1283             }


1317             return SunHints.Value.get(SunHints.INTKEY_TEXT_ANTIALIASING,
1318                                       textAntialiasHint);
1319         case SunHints.INTKEY_FRACTIONALMETRICS:
1320             return SunHints.Value.get(SunHints.INTKEY_FRACTIONALMETRICS,
1321                                       fractionalMetricsHint);
1322         case SunHints.INTKEY_AATEXT_LCD_CONTRAST:
1323             return new Integer(lcdTextContrast);
1324         case SunHints.INTKEY_INTERPOLATION:
1325             switch (interpolationHint) {
1326             case SunHints.INTVAL_INTERPOLATION_NEAREST_NEIGHBOR:
1327                 return SunHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR;
1328             case SunHints.INTVAL_INTERPOLATION_BILINEAR:
1329                 return SunHints.VALUE_INTERPOLATION_BILINEAR;
1330             case SunHints.INTVAL_INTERPOLATION_BICUBIC:
1331                 return SunHints.VALUE_INTERPOLATION_BICUBIC;
1332             }
1333             return null;
1334         case SunHints.INTKEY_STROKE_CONTROL:
1335             return SunHints.Value.get(SunHints.INTKEY_STROKE_CONTROL,
1336                                       strokeHint);
1337         case SunHints.INTKEY_RESOLUTION_VARIANT:
1338             return SunHints.Value.get(SunHints.INTKEY_RESOLUTION_VARIANT,
1339                                       resolutionVariantHint);
1340         }
1341         return null;
1342     }
1343 
1344     /**
1345      * Sets the preferences for the rendering algorithms.
1346      * Hint categories include controls for rendering quality and
1347      * overall time/quality trade-off in the rendering process.
1348      * @param hints The rendering hints to be set
1349      * @see RenderingHints
1350      */
1351     public void setRenderingHints(Map<?,?> hints) {
1352         this.hints = null;
1353         renderHint = SunHints.INTVAL_RENDER_DEFAULT;
1354         antialiasHint = SunHints.INTVAL_ANTIALIAS_OFF;
1355         textAntialiasHint = SunHints.INTVAL_TEXT_ANTIALIAS_DEFAULT;
1356         fractionalMetricsHint = SunHints.INTVAL_FRACTIONALMETRICS_OFF;
1357         lcdTextContrast = lcdTextContrastDefaultValue;
1358         interpolationHint = -1;
1359         interpolationType = AffineTransformOp.TYPE_NEAREST_NEIGHBOR;


3048             return;
3049         }
3050 
3051         try {
3052             textpipe.drawChars(this, chData, 0, length, x, y);
3053         } catch (InvalidPipeException e) {
3054             try {
3055                 revalidateAll();
3056                 textpipe.drawChars(this, chData, 0, length, x, y);
3057             } catch (InvalidPipeException e2) {
3058                 // Still catching the exception; we are not yet ready to
3059                 // validate the surfaceData correctly.  Fail for now and
3060                 // try again next time around.
3061             }
3062         } finally {
3063             surfaceData.markDirty();
3064         }
3065     }
3066 // end of text rendering methods
3067 
3068     private boolean isHiDPIImage(final Image img) {
3069         return (SurfaceManager.getImageScale(img) != 1) ||
3070                (resolutionVariantHint != SunHints.INTVAL_RESOLUTION_VARIANT_OFF
3071                     && img instanceof MultiResolutionImage);
3072     }
3073 
3074     private boolean drawHiDPIImage(Image img, int dx1, int dy1, int dx2,
3075                                    int dy2, int sx1, int sy1, int sx2, int sy2,
3076                                    Color bgcolor, ImageObserver observer) {
3077 
3078         if (SurfaceManager.getImageScale(img) != 1) {  // Volatile Image
3079             final int scale = SurfaceManager.getImageScale(img);
3080             sx1 = Region.clipScale(sx1, scale);
3081             sx2 = Region.clipScale(sx2, scale);
3082             sy1 = Region.clipScale(sy1, scale);
3083             sy2 = Region.clipScale(sy2, scale);
3084         } else if (img instanceof MultiResolutionImage) {
3085             // get scaled destination image size
3086 
3087             int width = img.getWidth(null);
3088             int height = img.getHeight(null);
3089 
3090             Dimension destImageSize = getTransformedDestImageSize(width, height,
3091                     dx1, dy1, dx2, dy2, sx1, sy1, sx2, sy2);
3092 
3093             Image resolutionVariant = (destImageSize == null) ? null
3094                     : ((MultiResolutionImage) img).getResolutionVariant(
3095                             destImageSize.width, destImageSize.height);
3096 
3097             if (resolutionVariant != null && resolutionVariant != img) {
3098                 // recalculate source region for the resolution variant
3099 
3100                 int scaledWidth = resolutionVariant.getWidth(null);
3101                 int scaledHeight = resolutionVariant.getHeight(null);
3102 
3103                 if (0 < width && 0 < height
3104                         && 0 < scaledWidth && 0 < scaledHeight) {
3105 
3106                     float widthScale = (float) scaledWidth / width;
3107                     float heightScale = (float) scaledHeight / height;
3108 
3109                     sx1 = Region.clipScale(sx1, widthScale);
3110                     sy1 = Region.clipScale(sy1, heightScale);
3111                     sx2 = Region.clipScale(sx2, widthScale);
3112                     sy2 = Region.clipScale(sy2, heightScale);
3113                     img = resolutionVariant;
3114                 }
3115             }
3116         }
3117 
3118         try {
3119             return imagepipe.scaleImage(this, img, dx1, dy1, dx2, dy2, sx1, sy1,
3120                                         sx2, sy2, bgcolor, observer);
3121         } catch (InvalidPipeException e) {
3122             try {
3123                 revalidateAll();
3124                 return imagepipe.scaleImage(this, img, dx1, dy1, dx2, dy2, sx1,
3125                                             sy1, sx2, sy2, bgcolor, 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     private Dimension getTransformedDestImageSize(int srcWidth, int srcHeight, int dx1, int dy1,
3138             int dx2, int dy2, int sx1, int sy1, int sx2, int sy2) {
3139 
3140         if (srcWidth <= 0 || srcHeight <= 0) {
3141             return null;
3142         }
3143 
3144         int sx = sx2 - sx1;
3145         int sy = sy2 - sy1;
3146 
3147         if (sx == 0 || sy == 0) {
3148             return null;
3149         }
3150 
3151         int transformType = transform.getType();
3152         int dx = dx2 - dx1;
3153         int dy = dy2 - dy1;
3154         double destRegionWidth;
3155         double destRegionHeight;
3156 
3157         if (transformType <= AffineTransform.TYPE_TRANSLATION
3158                 || transformType == AffineTransform.TYPE_FLIP) {
3159             destRegionWidth = dx;
3160             destRegionHeight = dy;
3161         } else if (transformType <= AffineTransform.TYPE_MASK_SCALE) {
3162             destRegionWidth = dx * transform.getScaleX();
3163             destRegionHeight = dy * transform.getScaleY();
3164         } else {
3165             Point[] corners = new Point[]{new Point(dx1, dy1),
3166                 new Point(dx2, dy1), new Point(dx1, dy2)};
3167             transform.transform(corners, 0, corners, 0, 3);
3168             destRegionWidth = (int) Point.distance(
3169                     corners[1].x, corners[1].y, corners[0].x, corners[0].y);
3170             destRegionHeight = (int) Point.distance(
3171                     corners[2].x, corners[2].y, corners[0].x, corners[0].y);
3172         }
3173 
3174         double distImageWidth = Math.abs(srcWidth * destRegionWidth / sx);
3175         double distImageHeight = Math.abs(srcHeight * destRegionHeight / sy);
3176 
3177         return new Dimension((int) distImageWidth, (int) distImageHeight);
3178     }
3179 
3180     /**
3181      * Draws an image scaled to x,y,w,h in nonblocking mode with a
3182      * callback object.
3183      */
3184     public boolean drawImage(Image img, int x, int y, int width, int height,
3185                              ImageObserver observer) {
3186         return drawImage(img, x, y, width, height, null, observer);
3187     }
3188 
3189     /**
3190      * Not part of the advertised API but a useful utility method
3191      * to call internally.  This is for the case where we are
3192      * drawing to/from given coordinates using a given width/height,
3193      * but we guarantee that the surfaceData's width/height of the src and dest
3194      * areas are equal (no scale needed). Note that this method intentionally
3195      * ignore scale factor of the source image, and copy it as is.
3196      */
3197     public boolean copyImage(Image img, int dx, int dy, int sx, int sy,
3198                              int width, int height, Color bgcolor,
3199                              ImageObserver observer) {