src/share/classes/sun/java2d/SunGraphics2D.java
Print this page
*** 63,72 ****
--- 63,74 ----
import java.awt.Font;
import java.awt.image.ImageObserver;
import java.awt.Transparency;
import java.awt.font.GlyphVector;
import java.awt.font.TextLayout;
+
+ import sun.awt.image.SurfaceManager;
import sun.font.FontDesignMetrics;
import sun.font.FontUtilities;
import sun.java2d.pipe.PixelDrawPipe;
import sun.java2d.pipe.PixelFillPipe;
import sun.java2d.pipe.ShapeDrawPipe;
*** 80,97 ****
import sun.java2d.loops.RenderLoops;
import sun.java2d.loops.CompositeType;
import sun.java2d.loops.SurfaceType;
import sun.java2d.loops.Blit;
import sun.java2d.loops.MaskFill;
- import sun.font.FontManager;
import java.awt.font.FontRenderContext;
import sun.java2d.loops.XORComposite;
import sun.awt.ConstrainableGraphics;
import sun.awt.SunHints;
import java.util.Map;
import java.util.Iterator;
- import sun.java2d.DestSurfaceProvider;
import sun.misc.PerformanceLogger;
/**
* This is a the master Graphics2D superclass for all of the Sun
* Graphics implementations. This class relies on subclasses to
--- 82,97 ----
*** 201,217 ****
public int interpolationType; // algorithm choice based on
// interpolation and render Hints
public RenderingHints hints;
! public Region constrainClip; // lightweight bounds
public int constrainX;
public int constrainY;
public Region clipRegion;
public Shape usrClip;
! protected Region devClip; // Actual physical drawable
// cached state for text rendering
private boolean validFontInfo;
private FontInfo fontInfo;
private FontInfo glyphVectorFontInfo;
--- 201,219 ----
public int interpolationType; // algorithm choice based on
// interpolation and render Hints
public RenderingHints hints;
! public Region constrainClip; // lightweight bounds in pixels
public int constrainX;
public int constrainY;
public Region clipRegion;
public Shape usrClip;
! protected Region devClip; // Actual physical drawable in pixels
!
! private final int devScale; // Actual physical scale factor
// cached state for text rendering
private boolean validFontInfo;
private FontInfo fontInfo;
private FontInfo glyphVectorFontInfo;
*** 250,259 ****
--- 252,267 ----
interpolationType = AffineTransformOp.TYPE_NEAREST_NEIGHBOR;
validateColor();
+ devScale = sd.getDefaultScale();
+ if (devScale != 1) {
+ transform.setToScale(devScale, devScale);
+ invalidateTransform();
+ }
+
font = f;
if (font == null) {
font = defaultFont;
}
*** 314,362 ****
setDevClip(r.x, r.y, r.width, r.height);
}
/**
* Constrain rendering for lightweight objects.
- *
- * REMIND: This method will back off to the "workaround"
- * of using translate and clipRect if the Graphics
- * to be constrained has a complex transform. The
- * drawback of the workaround is that the resulting
- * clip and device origin cannot be "enforced".
- *
- * @exception IllegalStateException If the Graphics
- * to be constrained has a complex transform.
*/
! public void constrain(int x, int y, int w, int h) {
! if ((x|y) != 0) {
translate(x, y);
}
! if (transformState >= TRANSFORM_TRANSLATESCALE) {
clipRect(0, 0, w, h);
return;
}
! x = constrainX = transX;
! y = constrainY = transY;
! w = Region.dimAdd(x, w);
! h = Region.dimAdd(y, h);
Region c = constrainClip;
if (c == null) {
c = Region.getInstanceXYXY(x, y, w, h);
} else {
c = c.getIntersectionXYXY(x, y, w, h);
if (c == constrainClip) {
// Common case to ignore
return;
}
! }
constrainClip = c;
if (!devClip.isInsideQuickCheck(c)) {
devClip = devClip.getIntersection(c);
validateCompClip();
}
}
protected static ValidatePipe invalidpipe = new ValidatePipe();
/*
* Invalidate the pipeline
*/
--- 322,389 ----
setDevClip(r.x, r.y, r.width, r.height);
}
/**
* Constrain rendering for lightweight objects.
*/
! public void constrain(int x, int y, int w, int h, Region region) {
! if ((x | y) != 0) {
translate(x, y);
}
! if (transformState > TRANSFORM_TRANSLATESCALE) {
clipRect(0, 0, w, h);
return;
}
! // changes parameters according to the current scale and translate.
! final double scaleX = transform.getScaleX();
! final double scaleY = transform.getScaleY();
! x = constrainX = (int) transform.getTranslateX();
! y = constrainY = (int) transform.getTranslateY();
! w = Region.dimAdd(x, Region.clipScale(w, scaleX));
! h = Region.dimAdd(y, Region.clipScale(h, scaleY));
!
Region c = constrainClip;
if (c == null) {
c = Region.getInstanceXYXY(x, y, w, h);
} else {
c = c.getIntersectionXYXY(x, y, w, h);
+ }
+ if (region != null) {
+ region = region.getScaledRegion(scaleX, scaleY);
+ region = region.getTranslatedRegion(x, y);
+ c = c.getIntersection(region);
+ }
+
if (c == constrainClip) {
// Common case to ignore
return;
}
!
constrainClip = c;
if (!devClip.isInsideQuickCheck(c)) {
devClip = devClip.getIntersection(c);
validateCompClip();
}
}
+ /**
+ * Constrain rendering for lightweight objects.
+ *
+ * REMIND: This method will back off to the "workaround"
+ * of using translate and clipRect if the Graphics
+ * to be constrained has a complex transform. The
+ * drawback of the workaround is that the resulting
+ * clip and device origin cannot be "enforced".
+ *
+ * @exception IllegalStateException If the Graphics
+ * to be constrained has a complex transform.
+ */
+ @Override
+ public void constrain(int x, int y, int w, int h) {
+ constrain(x, y, w, h, null);
+ }
+
protected static ValidatePipe invalidpipe = new ValidatePipe();
/*
* Invalidate the pipeline
*/
*** 1534,1548 ****
* @param Tx The Transform object to be used in the rendering process.
* @see #transform
* @see TransformChain
* @see AffineTransform
*/
public void setTransform(AffineTransform Tx) {
! if ((constrainX|constrainY) == 0) {
transform.setTransform(Tx);
} else {
! transform.setToTranslation(constrainX, constrainY);
transform.concatenate(Tx);
}
invalidateTransform();
}
--- 1561,1577 ----
* @param Tx The Transform object to be used in the rendering process.
* @see #transform
* @see TransformChain
* @see AffineTransform
*/
+ @Override
public void setTransform(AffineTransform Tx) {
! if ((constrainX | constrainY) == 0 && devScale == 1) {
transform.setTransform(Tx);
} else {
! transform.setTransform(devScale, 0, 0, devScale, constrainX,
! constrainY);
transform.concatenate(Tx);
}
invalidateTransform();
}
*** 1596,1611 ****
/**
* Returns the current Transform in the Graphics2D state.
* @see #transform
* @see #setTransform
*/
public AffineTransform getTransform() {
! if ((constrainX|constrainY) == 0) {
return new AffineTransform(transform);
}
! AffineTransform tx =
! AffineTransform.getTranslateInstance(-constrainX, -constrainY);
tx.concatenate(transform);
return tx;
}
/**
--- 1625,1643 ----
/**
* Returns the current Transform in the Graphics2D state.
* @see #transform
* @see #setTransform
*/
+ @Override
public AffineTransform getTransform() {
! if ((constrainX | constrainY) == 0 && devScale == 1) {
return new AffineTransform(transform);
}
! final double invScale = 1.0 / devScale;
! AffineTransform tx = new AffineTransform(invScale, 0, 0, invScale,
! -constrainX * invScale,
! -constrainY * invScale);
tx.concatenate(transform);
return tx;
}
/**
*** 2985,2994 ****
--- 3017,3057 ----
surfaceData.markDirty();
}
}
// end of text rendering methods
+ private static boolean isHiDPIImage(final Image img) {
+ return SurfaceManager.getImageScale(img) != 1;
+ }
+
+ 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) {
+ 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);
+ try {
+ return imagepipe.scaleImage(this, img, dx1, dy1, dx2, dy2, sx1, sy1,
+ sx2, sy2, bgcolor, observer);
+ } catch (InvalidPipeException e) {
+ try {
+ revalidateAll();
+ return imagepipe.scaleImage(this, img, dx1, dy1, dx2, dy2, sx1,
+ sy1, sx2, sy2, bgcolor, observer);
+ } catch (InvalidPipeException e2) {
+ // Still catching the exception; we are not yet ready to
+ // validate the surfaceData correctly. Fail for now and
+ // try again next time around.
+ return false;
+ }
+ } finally {
+ surfaceData.markDirty();
+ }
+ }
+
/**
* 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,
*** 2998,3009 ****
/**
* Not part of the advertised API but a useful utility method
* to call internally. This is for the case where we are
* drawing to/from given coordinates using a given width/height,
! * but we guarantee that the weidth/height of the src and dest
! * areas are equal (no scale needed).
*/
public boolean copyImage(Image img, int dx, int dy, int sx, int sy,
int width, int height, Color bgcolor,
ImageObserver observer) {
try {
--- 3061,3073 ----
/**
* Not part of the advertised API but a useful utility method
* to call internally. This is for the case where we are
* drawing to/from given coordinates using a given width/height,
! * but we guarantee that the surfaceData's width/height of the src and dest
! * areas are equal (no scale needed). Note that this method intentionally
! * ignore scale factor of the source image, and copy it as is.
*/
public boolean copyImage(Image img, int dx, int dy, int sx, int sy,
int width, int height, Color bgcolor,
ImageObserver observer) {
try {
*** 3037,3047 ****
}
if ((width == 0) || (height == 0)) {
return true;
}
! if (width == img.getWidth(null) && height == img.getHeight(null)) {
return copyImage(img, x, y, 0, 0, width, height, bg, observer);
}
try {
return imagepipe.scaleImage(this, img, x, y, width, height,
--- 3101,3119 ----
}
if ((width == 0) || (height == 0)) {
return true;
}
!
! final int imgW = img.getWidth(null);
! final int imgH = img.getHeight(null);
! if (isHiDPIImage(img)) {
! return drawHiDPIImage(img, x, y, x + width, y + height, 0, 0, imgW,
! imgH, bg, observer);
! }
!
! if (width == imgW && height == imgH) {
return copyImage(img, x, y, 0, 0, width, height, bg, observer);
}
try {
return imagepipe.scaleImage(this, img, x, y, width, height,
*** 3078,3087 ****
--- 3150,3166 ----
if (img == null) {
return true;
}
+ if (isHiDPIImage(img)) {
+ final int imgW = img.getWidth(null);
+ final int imgH = img.getHeight(null);
+ return drawHiDPIImage(img, x, y, x + imgW, y + imgH, 0, 0, imgW,
+ imgH, bg, observer);
+ }
+
try {
return imagepipe.copyImage(this, img, x, y, bg, observer);
} catch (InvalidPipeException e) {
try {
revalidateAll();
*** 3126,3135 ****
--- 3205,3219 ----
sx1 == sx2 || sy1 == sy2)
{
return true;
}
+ if (isHiDPIImage(img)) {
+ return drawHiDPIImage(img, dx1, dy1, dx2, dy2, sx1, sy1, sx2, sy2,
+ bgcolor, observer);
+ }
+
if (((sx2 - sx1) == (dx2 - dx1)) &&
((sy2 - sy1) == (dy2 - dy1)))
{
// Not a scale - forward it to a copy routine
int srcX, srcY, dstX, dstY, width, height;
*** 3204,3213 ****
--- 3288,3309 ----
if (xform == null || xform.isIdentity()) {
return drawImage(img, 0, 0, null, observer);
}
+ if (isHiDPIImage(img)) {
+ final int w = img.getWidth(null);
+ final int h = img.getHeight(null);
+ final AffineTransform tx = new AffineTransform(transform);
+ transform(xform);
+ boolean result = drawHiDPIImage(img, 0, 0, w, h, 0, 0, w, h, null,
+ observer);
+ transform.setTransform(tx);
+ invalidateTransform();
+ return result;
+ }
+
try {
return imagepipe.transformImage(this, img, xform, observer);
} catch (InvalidPipeException e) {
try {
revalidateAll();