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

Print this page

        

@@ -63,10 +63,12 @@
 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,18 +82,16 @@
 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;
 
 import javax.tools.annotation.GenerateNativeHeader;
 
 /**

@@ -205,17 +205,19 @@
     public int interpolationType;       // algorithm choice based on
                                         // interpolation and render Hints
 
     public RenderingHints hints;
 
-    public Region constrainClip;                // lightweight bounds
+    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
+    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;

@@ -254,10 +256,16 @@
 
         interpolationType = AffineTransformOp.TYPE_NEAREST_NEIGHBOR;
 
         validateColor();
 
+        devScale = sd.getDefaultScale();
+        if (devScale != 1) {
+            transform.setToScale(devScale, devScale);
+            invalidateTransform();
+        }
+
         font = f;
         if (font == null) {
             font = defaultFont;
         }
 

@@ -318,49 +326,68 @@
         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) {
+    public void constrain(int x, int y, int w, int h, Region region) {
+        if ((x | y) != 0) {
             translate(x, y);
         }
-        if (transformState >= TRANSFORM_TRANSLATESCALE) {
+        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);
+        // 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
      */

@@ -1538,15 +1565,17 @@
      * @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) {
+        if ((constrainX | constrainY) == 0 && devScale == 1) {
             transform.setTransform(Tx);
         } else {
-            transform.setToTranslation(constrainX, constrainY);
+            transform.setTransform(devScale, 0, 0, devScale, constrainX,
+                                   constrainY);
             transform.concatenate(Tx);
         }
         invalidateTransform();
     }
 

@@ -1600,16 +1629,18 @@
     /**
      * Returns the current Transform in the Graphics2D state.
      * @see #transform
      * @see #setTransform
      */
+    @Override
     public AffineTransform getTransform() {
-        if ((constrainX|constrainY) == 0) {
+        if ((constrainX | constrainY) == 0 && devScale == 1) {
             return new AffineTransform(transform);
         }
-        AffineTransform tx =
-            AffineTransform.getTranslateInstance(-constrainX, -constrainY);
+        final double invScale = 1.0 / devScale;
+        AffineTransform tx = new AffineTransform(invScale, 0, 0, invScale,
+                                                 -constrainX, -constrainY);
         tx.concatenate(transform);
         return tx;
     }
 
     /**

@@ -2989,10 +3020,41 @@
             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,

@@ -3002,12 +3064,13 @@
 
     /**
      * 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).
+     * 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 {

@@ -3041,11 +3104,19 @@
         }
 
         if ((width == 0) || (height == 0)) {
             return true;
         }
-        if (width == img.getWidth(null) && height == img.getHeight(null)) {
+
+        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,

@@ -3082,10 +3153,17 @@
 
         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();

@@ -3130,10 +3208,15 @@
             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;

@@ -3208,10 +3291,22 @@
 
         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();