src/share/classes/sun/java2d/SunGraphics2D.java
Print this page
@@ -59,10 +59,11 @@
import java.awt.Stroke;
import java.awt.FontMetrics;
import java.awt.Rectangle;
import java.text.AttributedCharacterIterator;
import java.awt.Font;
+import java.awt.Point;
import java.awt.image.ImageObserver;
import java.awt.Transparency;
import java.awt.font.GlyphVector;
import java.awt.font.TextLayout;
@@ -91,10 +92,17 @@
import java.util.Map;
import java.util.Iterator;
import sun.misc.PerformanceLogger;
import java.lang.annotation.Native;
+import sun.awt.image.MultiResolutionImage;
+
+import static java.awt.geom.AffineTransform.TYPE_FLIP;
+import static java.awt.geom.AffineTransform.TYPE_MASK_SCALE;
+import static java.awt.geom.AffineTransform.TYPE_TRANSLATION;
+import sun.awt.image.MultiResolutionToolkitImage;
+import sun.awt.image.ToolkitImage;
/**
* This is a the master Graphics2D superclass for all of the Sun
* Graphics implementations. This class relies on subclasses to
* manage the various device information, but provides an overall
@@ -235,10 +243,11 @@
public Region clipRegion;
public Shape usrClip;
protected Region devClip; // Actual physical drawable in pixels
private final int devScale; // Actual physical scale factor
+ private int resolutionVariantHint;
// cached state for text rendering
private boolean validFontInfo;
private FontInfo fontInfo;
private FontInfo glyphVectorFontInfo;
@@ -272,10 +281,11 @@
textAntialiasHint = SunHints.INTVAL_TEXT_ANTIALIAS_DEFAULT;
fractionalMetricsHint = SunHints.INTVAL_FRACTIONALMETRICS_OFF;
lcdTextContrast = lcdTextContrastDefaultValue;
interpolationHint = -1;
strokeHint = SunHints.INTVAL_STROKE_DEFAULT;
+ resolutionVariantHint = SunHints.INTVAL_RESOLUTION_VARIANT_DEFAULT;
interpolationType = AffineTransformOp.TYPE_NEAREST_NEIGHBOR;
validateColor();
@@ -1247,10 +1257,14 @@
break;
case SunHints.INTKEY_STROKE_CONTROL:
stateChanged = (strokeHint != newHint);
strokeHint = newHint;
break;
+ case SunHints.INTKEY_RESOLUTION_VARIANT:
+ stateChanged = (resolutionVariantHint != newHint);
+ resolutionVariantHint = newHint;
+ break;
default:
recognized = false;
stateChanged = false;
break;
}
@@ -1320,10 +1334,13 @@
}
return null;
case SunHints.INTKEY_STROKE_CONTROL:
return SunHints.Value.get(SunHints.INTKEY_STROKE_CONTROL,
strokeHint);
+ case SunHints.INTKEY_RESOLUTION_VARIANT:
+ return SunHints.Value.get(SunHints.INTKEY_RESOLUTION_VARIANT,
+ resolutionVariantHint);
}
return null;
}
/**
@@ -3048,22 +3065,62 @@
surfaceData.markDirty();
}
}
// end of text rendering methods
- private static boolean isHiDPIImage(final Image img) {
- return SurfaceManager.getImageScale(img) != 1;
+ private boolean isHiDPIImage(final Image img) {
+ return (SurfaceManager.getImageScale(img) != 1) ||
+ (resolutionVariantHint != SunHints.INTVAL_RESOLUTION_VARIANT_OFF
+ && img instanceof MultiResolutionImage);
}
private boolean drawHiDPIImage(Image img, int dx1, int dy1, int dx2,
int dy2, int sx1, int sy1, int sx2, int sy2,
Color bgcolor, ImageObserver observer) {
+
+ if (SurfaceManager.getImageScale(img) != 1) { // Volatile Image
final int scale = SurfaceManager.getImageScale(img);
sx1 = Region.clipScale(sx1, scale);
sx2 = Region.clipScale(sx2, scale);
sy1 = Region.clipScale(sy1, scale);
sy2 = Region.clipScale(sy2, scale);
+ } else if (img instanceof MultiResolutionImage) {
+ // get scaled destination image size
+
+ int width = img.getWidth(observer);
+ int height = img.getHeight(observer);
+
+ Image resolutionVariant = getResolutionVariant(
+ (MultiResolutionImage) img, width, height,
+ dx1, dy1, dx2, dy2, sx1, sy1, sx2, sy2);
+
+ if (resolutionVariant != img && resolutionVariant != null) {
+ // recalculate source region for the resolution variant
+
+ ImageObserver rvObserver = MultiResolutionToolkitImage.
+ getResolutionVariantObserver(img, observer,
+ width, height, -1, -1);
+
+ int rvWidth = resolutionVariant.getWidth(rvObserver);
+ int rvHeight = resolutionVariant.getHeight(rvObserver);
+
+ if (0 < width && 0 < height && 0 < rvWidth && 0 < rvHeight) {
+
+ float widthScale = ((float) rvWidth) / width;
+ float heightScale = ((float) rvHeight) / height;
+
+ sx1 = Region.clipScale(sx1, widthScale);
+ sy1 = Region.clipScale(sy1, heightScale);
+ sx2 = Region.clipScale(sx2, widthScale);
+ sy2 = Region.clipScale(sy2, heightScale);
+
+ observer = rvObserver;
+ img = resolutionVariant;
+ }
+ }
+ }
+
try {
return imagepipe.scaleImage(this, img, dx1, dy1, dx2, dy2, sx1, sy1,
sx2, sy2, bgcolor, observer);
} catch (InvalidPipeException e) {
try {
@@ -3079,10 +3136,58 @@
} finally {
surfaceData.markDirty();
}
}
+ private Image getResolutionVariant(MultiResolutionImage img,
+ int srcWidth, int srcHeight, int dx1, int dy1, int dx2, int dy2,
+ int sx1, int sy1, int sx2, int sy2) {
+
+ if (srcWidth <= 0 || srcHeight <= 0) {
+ return null;
+ }
+
+ int sw = sx2 - sx1;
+ int sh = sy2 - sy1;
+
+ if (sw == 0 || sh == 0) {
+ return null;
+ }
+
+ int type = transform.getType();
+ int dw = dx2 - dx1;
+ int dh = dy2 - dy1;
+ double destRegionWidth;
+ double destRegionHeight;
+
+ if ((type & ~(TYPE_TRANSLATION | TYPE_FLIP)) == 0) {
+ destRegionWidth = dw;
+ destRegionHeight = dh;
+ } else if ((type & ~(TYPE_TRANSLATION | TYPE_FLIP | TYPE_MASK_SCALE)) == 0) {
+ destRegionWidth = dw * transform.getScaleX();
+ destRegionHeight = dh * transform.getScaleY();
+ } else {
+ destRegionWidth = dw * Math.hypot(
+ transform.getScaleX(), transform.getShearY());
+ destRegionHeight = dh * Math.hypot(
+ transform.getShearX(), transform.getScaleY());
+ }
+
+ int destImageWidth = (int) Math.abs(srcWidth * destRegionWidth / sw);
+ int destImageHeight = (int) Math.abs(srcHeight * destRegionHeight / sh);
+
+ Image resolutionVariant
+ = img.getResolutionVariant(destImageWidth, destImageHeight);
+
+ if (resolutionVariant instanceof ToolkitImage
+ && ((ToolkitImage) resolutionVariant).hasError()) {
+ return null;
+ }
+
+ return resolutionVariant;
+ }
+
/**
* Draws an image scaled to x,y,w,h in nonblocking mode with a
* callback object.
*/
public boolean drawImage(Image img, int x, int y, int width, int height,