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) {
|