8027169: Xrender: Cleaner version of the fix for 7159455 Nimbus scrollbar glitch
authorprr
Wed, 23 Oct 2013 08:46:54 -0700
changeset 21236 ee742f4ec299
parent 21235 38393a2aaf88
child 21237 1b9c1510de61
8027169: Xrender: Cleaner version of the fix for 7159455 Nimbus scrollbar glitch Reviewed-by: prr, bae
jdk/src/solaris/classes/sun/java2d/xr/XRPMBlitLoops.java
--- a/jdk/src/solaris/classes/sun/java2d/xr/XRPMBlitLoops.java	Wed Oct 23 08:56:56 2013 +0400
+++ b/jdk/src/solaris/classes/sun/java2d/xr/XRPMBlitLoops.java	Wed Oct 23 08:46:54 2013 -0700
@@ -178,9 +178,6 @@
         super(srcType, CompositeType.AnyAlpha, dstType);
     }
 
-    /*
-     * TODO: This breaks scales with non-integer coordinates!?!?!
-     */
     public void Scale(SurfaceData src, SurfaceData dst, Composite comp, Region clip, int sx1, int sy1, int sx2, int sy2, double dx1, double dy1,
             double dx2, double dy2) {
         try {
@@ -199,19 +196,14 @@
             sy1 *= yScale;
             sy2 *= yScale;
 
+            dx1 = Math.ceil(dx1 - 0.5);
+            dy1 = Math.ceil(dy1 - 0.5);
+            dx2 = Math.ceil(dx2 - 0.5);
+            dy2 = Math.ceil(dy2 - 0.5);
+
             AffineTransform xForm = AffineTransform.getScaleInstance(1 / xScale, 1 / yScale);
 
-            x11sdSrc.validateAsSource(xForm, XRUtils.RepeatNone, XRUtils.FAST); /*
-                                                                                 * TODO:
-                                                                                 * padded
-                                                                                 * blit
-                                                                                 * required
-                                                                                 * :
-                                                                                 * -
-                                                                                 * /
-                                                                                 * ?
-                                                                                 * ?
-                                                                                 */
+            x11sdSrc.validateAsSource(xForm, XRUtils.RepeatNone, XRUtils.FAST);
             x11sdDst.maskBuffer.compositeBlit(x11sdSrc, x11sdDst, (int) sx1, (int) sy1, (int) dx1, (int) dy1, (int) (dx2 - dx1), (int) (dy2 - dy1));
         } finally {
             SunToolkit.awtUnlock();
@@ -234,43 +226,55 @@
     }
 
     /*
-     * Calculates the composite-rectangle required for transformed blits. This
-     * method is functionally equal to: Shape shp =
-     * xform.createTransformedShape(rect); Rectangle bounds = shp.getBounds();
-     * but performs significantly better.
-     * Returns true if the destination shape is parallel to x/y axis
+     * Calculates the composition-rectangle required for transformed blits.
+     * For composite operations where the composition-rectangle defines
+     * the modified destination area, coordinates are rounded.
+     * Otherwise the composition window rectangle is sized large enough
+     * to not clip away any pixels.
      */
-    protected boolean adjustCompositeBounds(AffineTransform tr, int dstx, int dsty, int width, int height) {
+    protected void adjustCompositeBounds(boolean isQuadrantRotated, AffineTransform tr,
+            int dstx, int dsty, int width, int height) {
         srcCoords[0] = dstx;
         srcCoords[1] = dsty;
         srcCoords[2] = dstx + width;
-        srcCoords[3] = dsty;
-        srcCoords[4] = dstx + width;
-        srcCoords[5] = dsty + height;
-        srcCoords[6] = dstx;
-        srcCoords[7] = dsty + height;
+        srcCoords[3] = dsty + height;
 
-        tr.transform(srcCoords, 0, dstCoords, 0, 4);
+        double minX, minY, maxX, maxY;
+        if (isQuadrantRotated) {
+            tr.transform(srcCoords, 0, dstCoords, 0, 2);
+
+            minX = Math.min(dstCoords[0], dstCoords[2]);
+            minY = Math.min(dstCoords[1], dstCoords[3]);
+            maxX = Math.max(dstCoords[0], dstCoords[2]);
+            maxY = Math.max(dstCoords[1], dstCoords[3]);
 
-        double minX = Math.min(dstCoords[0], Math.min(dstCoords[2], Math.min(dstCoords[4], dstCoords[6])));
-        double minY = Math.min(dstCoords[1], Math.min(dstCoords[3], Math.min(dstCoords[5], dstCoords[7])));
-        double maxX = Math.max(dstCoords[0], Math.max(dstCoords[2], Math.max(dstCoords[4], dstCoords[6])));
-        double maxY = Math.max(dstCoords[1], Math.max(dstCoords[3], Math.max(dstCoords[5], dstCoords[7])));
+            minX = Math.ceil(minX - 0.5);
+            minY = Math.ceil(minY - 0.5);
+            maxX = Math.ceil(maxX - 0.5);
+            maxY = Math.ceil(maxY - 0.5);
+        } else {
+            srcCoords[4] = dstx;
+            srcCoords[5] = dsty + height;
+            srcCoords[6] = dstx + width;
+            srcCoords[7] = dsty;
 
-        minX = Math.round(minX);
-        minY = Math.round(minY);
-        maxX = Math.round(maxX);
-        maxY = Math.round(maxY);
+            tr.transform(srcCoords, 0, dstCoords, 0, 4);
+
+            minX = Math.min(dstCoords[0], Math.min(dstCoords[2], Math.min(dstCoords[4], dstCoords[6])));
+            minY = Math.min(dstCoords[1], Math.min(dstCoords[3], Math.min(dstCoords[5], dstCoords[7])));
+            maxX = Math.max(dstCoords[0], Math.max(dstCoords[2], Math.max(dstCoords[4], dstCoords[6])));
+            maxY = Math.max(dstCoords[1], Math.max(dstCoords[3], Math.max(dstCoords[5], dstCoords[7])));
+
+            minX = Math.floor(minX);
+            minY = Math.floor(minY);
+            maxX = Math.ceil(maxX);
+            maxY = Math.ceil(maxY);
+        }
 
         compositeBounds.x = (int) minX;
         compositeBounds.y = (int) minY;
         compositeBounds.width = (int) (maxX - minX);
         compositeBounds.height = (int) (maxY - minY);
-
-        boolean is0or180 = (dstCoords[1] == dstCoords[3]) && (dstCoords[2] == dstCoords[4]);
-        boolean is90or270 = (dstCoords[0] == dstCoords[2]) && (dstCoords[3] == dstCoords[5]);
-
-        return is0or180 || is90or270;
     }
 
     public void Transform(SurfaceData src, SurfaceData dst, Composite comp, Region clip, AffineTransform xform,
@@ -280,9 +284,13 @@
 
             XRSurfaceData x11sdDst = (XRSurfaceData) dst;
             XRSurfaceData x11sdSrc = (XRSurfaceData) src;
+            XRCompositeManager xrMgr = XRCompositeManager.getInstance(x11sdSrc);
 
+            float extraAlpha = ((AlphaComposite) comp).getAlpha();
             int filter = XRUtils.ATransOpToXRQuality(hint);
-            boolean isAxisAligned = adjustCompositeBounds(xform, dstx, dsty, width, height);
+            boolean isQuadrantRotated = XRUtils.isTransformQuadrantRotated(xform);
+
+            adjustCompositeBounds(isQuadrantRotated, xform, dstx, dsty, width, height);
 
             x11sdDst.validateAsDestination(null, clip);
             x11sdDst.maskBuffer.validateCompositeState(comp, null, null, null);
@@ -298,21 +306,26 @@
                 trx.setToIdentity();
             }
 
-            boolean omitMask = (filter == XRUtils.FAST)
-                    || (isAxisAligned && ((AlphaComposite) comp).getAlpha() == 1.0f);
-
-            if (!omitMask) {
+            if (filter != XRUtils.FAST && (!isQuadrantRotated || extraAlpha != 1.0f)) {
                 XRMaskImage mask = x11sdSrc.maskBuffer.getMaskImage();
 
+                // For quadrant-transformed blits geometry is not stored inside the mask
+                // therefore we can use a repeating 1x1 mask for applying extra alpha.
+                int maskPicture = isQuadrantRotated ? xrMgr.getExtraAlphaMask()
+                        : mask.prepareBlitMask(x11sdDst, maskTX, width, height);
+
                 x11sdSrc.validateAsSource(trx, XRUtils.RepeatPad, filter);
-                int maskPicture = mask.prepareBlitMask(x11sdDst, maskTX, width, height);
-                x11sdDst.maskBuffer.con.renderComposite(XRCompositeManager.getInstance(x11sdSrc).getCompRule(), x11sdSrc.picture, maskPicture, x11sdDst.picture,
-                        0, 0, 0, 0, compositeBounds.x, compositeBounds.y, compositeBounds.width, compositeBounds.height);
+                x11sdDst.maskBuffer.con.renderComposite(xrMgr.getCompRule(), x11sdSrc.picture,
+                        maskPicture, x11sdDst.picture, 0, 0, 0, 0, compositeBounds.x, compositeBounds.y,
+                        compositeBounds.width, compositeBounds.height);
             } else {
                 int repeat = filter == XRUtils.FAST ? XRUtils.RepeatNone : XRUtils.RepeatPad;
 
                 x11sdSrc.validateAsSource(trx, repeat, filter);
-                x11sdDst.maskBuffer.compositeBlit(x11sdSrc, x11sdDst, 0, 0, compositeBounds.x, compositeBounds.y, compositeBounds.width, compositeBounds.height);
+
+                // compositeBlit takes care of extra alpha
+                x11sdDst.maskBuffer.compositeBlit(x11sdSrc, x11sdDst, 0, 0, compositeBounds.x,
+                        compositeBounds.y, compositeBounds.width, compositeBounds.height);
             }
         } finally {
             SunToolkit.awtUnlock();
@@ -329,9 +342,7 @@
     }
 
     public void Blit(SurfaceData src, SurfaceData dst, Composite comp, Region clip, int sx, int sy, int dx, int dy, int w, int h) {
-        /*
-         * If the blit is write-only (putimge), no need for a temporary VI.
-         */
+        // If the blit is write-only (putimge), no need for a temporary VI.
         if (CompositeType.SrcOverNoEa.equals(comp) && (src.getTransparency() == Transparency.OPAQUE)) {
             Blit opaqueSwToSurfaceBlit = Blit.getFromCache(src.getSurfaceType(), CompositeType.SrcNoEa, dst.getSurfaceType());
             opaqueSwToSurfaceBlit.Blit(src, dst, comp, clip, sx, sy, dx, dy, w, h);