1 /*
   2  * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package sun.java2d.xr;
  27 
  28 import sun.awt.SunToolkit;
  29 import sun.awt.image.*;
  30 import sun.java2d.loops.*;
  31 import sun.java2d.pipe.*;
  32 import sun.java2d.*;
  33 import java.awt.*;
  34 import java.awt.geom.*;
  35 import java.lang.ref.*;
  36 
  37 public class XRPMBlitLoops {
  38 
  39     static WeakReference<SunVolatileImage> argbTmpPM = new WeakReference<SunVolatileImage>(null);
  40     static WeakReference<SunVolatileImage> rgbTmpPM = new WeakReference<SunVolatileImage>(null);
  41 
  42     public XRPMBlitLoops() {
  43     }
  44 
  45     public static void register() {
  46         GraphicsPrimitive[] primitives = { new XRPMBlit(XRSurfaceData.IntRgbX11, XRSurfaceData.IntRgbX11),
  47                 new XRPMBlit(XRSurfaceData.IntRgbX11, XRSurfaceData.IntArgbPreX11),
  48                 new XRPMBlit(XRSurfaceData.IntArgbPreX11, XRSurfaceData.IntRgbX11),
  49                 new XRPMBlit(XRSurfaceData.IntArgbPreX11, XRSurfaceData.IntArgbPreX11),
  50 
  51                 new XRPMScaledBlit(XRSurfaceData.IntRgbX11, XRSurfaceData.IntRgbX11),
  52                 new XRPMScaledBlit(XRSurfaceData.IntRgbX11, XRSurfaceData.IntArgbPreX11),
  53                 new XRPMScaledBlit(XRSurfaceData.IntArgbPreX11, XRSurfaceData.IntRgbX11),
  54                 new XRPMScaledBlit(XRSurfaceData.IntArgbPreX11, XRSurfaceData.IntArgbPreX11),
  55 
  56                 new XRPMTransformedBlit(XRSurfaceData.IntRgbX11, XRSurfaceData.IntRgbX11),
  57                 new XRPMTransformedBlit(XRSurfaceData.IntRgbX11, XRSurfaceData.IntArgbPreX11),
  58                 new XRPMTransformedBlit(XRSurfaceData.IntArgbPreX11, XRSurfaceData.IntRgbX11),
  59                 new XRPMTransformedBlit(XRSurfaceData.IntArgbPreX11, XRSurfaceData.IntArgbPreX11),
  60 
  61                 /* SW -> Surface Blits */
  62                 new XrSwToPMBlit(SurfaceType.IntArgb, XRSurfaceData.IntRgbX11),
  63                 new XrSwToPMBlit(SurfaceType.IntRgb, XRSurfaceData.IntRgbX11),
  64                 new XrSwToPMBlit(SurfaceType.IntBgr, XRSurfaceData.IntRgbX11),
  65                 new XrSwToPMBlit(SurfaceType.ThreeByteBgr, XRSurfaceData.IntRgbX11),
  66                 new XrSwToPMBlit(SurfaceType.Ushort565Rgb, XRSurfaceData.IntRgbX11),
  67                 new XrSwToPMBlit(SurfaceType.Ushort555Rgb, XRSurfaceData.IntRgbX11),
  68                 new XrSwToPMBlit(SurfaceType.ByteIndexed, XRSurfaceData.IntRgbX11),
  69 
  70                 new XrSwToPMBlit(SurfaceType.IntArgb, XRSurfaceData.IntArgbPreX11),
  71                 new XrSwToPMBlit(SurfaceType.IntRgb, XRSurfaceData.IntArgbPreX11),
  72                 new XrSwToPMBlit(SurfaceType.IntBgr, XRSurfaceData.IntArgbPreX11),
  73                 new XrSwToPMBlit(SurfaceType.ThreeByteBgr, XRSurfaceData.IntArgbPreX11),
  74                 new XrSwToPMBlit(SurfaceType.Ushort565Rgb, XRSurfaceData.IntArgbPreX11),
  75                 new XrSwToPMBlit(SurfaceType.Ushort555Rgb, XRSurfaceData.IntArgbPreX11),
  76                 new XrSwToPMBlit(SurfaceType.ByteIndexed, XRSurfaceData.IntArgbPreX11),
  77 
  78                 /* SW->Surface Scales */
  79                 new XrSwToPMScaledBlit(SurfaceType.IntArgb, XRSurfaceData.IntRgbX11),
  80                 new XrSwToPMScaledBlit(SurfaceType.IntRgb, XRSurfaceData.IntRgbX11),
  81                 new XrSwToPMScaledBlit(SurfaceType.IntBgr, XRSurfaceData.IntRgbX11),
  82                 new XrSwToPMScaledBlit(SurfaceType.ThreeByteBgr, XRSurfaceData.IntRgbX11),
  83                 new XrSwToPMScaledBlit(SurfaceType.Ushort565Rgb, XRSurfaceData.IntRgbX11),
  84                 new XrSwToPMScaledBlit(SurfaceType.Ushort555Rgb, XRSurfaceData.IntRgbX11),
  85                 new XrSwToPMScaledBlit(SurfaceType.ByteIndexed, XRSurfaceData.IntRgbX11),
  86 
  87                 new XrSwToPMScaledBlit(SurfaceType.IntArgb, XRSurfaceData.IntArgbPreX11),
  88                 new XrSwToPMScaledBlit(SurfaceType.IntRgb, XRSurfaceData.IntArgbPreX11),
  89                 new XrSwToPMScaledBlit(SurfaceType.IntBgr, XRSurfaceData.IntArgbPreX11),
  90                 new XrSwToPMScaledBlit(SurfaceType.ThreeByteBgr, XRSurfaceData.IntArgbPreX11),
  91                 new XrSwToPMScaledBlit(SurfaceType.Ushort565Rgb, XRSurfaceData.IntArgbPreX11),
  92                 new XrSwToPMScaledBlit(SurfaceType.Ushort555Rgb, XRSurfaceData.IntArgbPreX11),
  93                 new XrSwToPMScaledBlit(SurfaceType.ByteIndexed, XRSurfaceData.IntArgbPreX11),
  94 
  95                 /* SW->Surface Transforms */
  96                 new XrSwToPMTransformedBlit(SurfaceType.IntArgb, XRSurfaceData.IntRgbX11),
  97                 new XrSwToPMTransformedBlit(SurfaceType.IntRgb, XRSurfaceData.IntRgbX11),
  98                 new XrSwToPMTransformedBlit(SurfaceType.IntBgr, XRSurfaceData.IntRgbX11),
  99                 new XrSwToPMTransformedBlit(SurfaceType.ThreeByteBgr, XRSurfaceData.IntRgbX11),
 100                 new XrSwToPMTransformedBlit(SurfaceType.Ushort565Rgb, XRSurfaceData.IntRgbX11),
 101                 new XrSwToPMTransformedBlit(SurfaceType.Ushort555Rgb, XRSurfaceData.IntRgbX11),
 102                 new XrSwToPMTransformedBlit(SurfaceType.ByteIndexed, XRSurfaceData.IntRgbX11),
 103 
 104                 new XrSwToPMTransformedBlit(SurfaceType.IntArgb, XRSurfaceData.IntArgbPreX11),
 105                 new XrSwToPMTransformedBlit(SurfaceType.IntRgb, XRSurfaceData.IntArgbPreX11),
 106                 new XrSwToPMTransformedBlit(SurfaceType.IntBgr, XRSurfaceData.IntArgbPreX11),
 107                 new XrSwToPMTransformedBlit(SurfaceType.ThreeByteBgr, XRSurfaceData.IntArgbPreX11),
 108                 new XrSwToPMTransformedBlit(SurfaceType.Ushort565Rgb, XRSurfaceData.IntArgbPreX11),
 109                 new XrSwToPMTransformedBlit(SurfaceType.Ushort555Rgb, XRSurfaceData.IntArgbPreX11),
 110                 new XrSwToPMTransformedBlit(SurfaceType.ByteIndexed, XRSurfaceData.IntArgbPreX11), };
 111         GraphicsPrimitiveMgr.register(primitives);
 112     }
 113 
 114     /**
 115      * Caches a SW surface using a temporary pixmap. The pixmap is held by a WeakReference,
 116      *  allowing it to shrink again after some time.
 117      */
 118     protected static XRSurfaceData cacheToTmpSurface(SurfaceData src, XRSurfaceData dst, int w, int h, int sx, int sy) {
 119         SunVolatileImage vImg;
 120         SurfaceType vImgSurfaceType;
 121 
 122         if (src.getTransparency() == Transparency.OPAQUE) {
 123             vImg = rgbTmpPM.get();
 124             vImgSurfaceType = SurfaceType.IntRgb;
 125         } else {
 126             vImg = argbTmpPM.get();
 127             vImgSurfaceType = SurfaceType.IntArgbPre;
 128         }
 129 
 130         if (vImg == null || vImg.getWidth() < w || vImg.getHeight() < h) {
 131             if (vImg != null) {
 132                 vImg.flush();
 133             }
 134             vImg = (SunVolatileImage) dst.getGraphicsConfig().createCompatibleVolatileImage(w, h, src.getTransparency());
 135             vImg.setAccelerationPriority(1.0f);
 136 
 137             if (src.getTransparency() == SurfaceData.OPAQUE) {
 138                 rgbTmpPM = new WeakReference<SunVolatileImage>(vImg);
 139             } else {
 140                 argbTmpPM = new WeakReference<SunVolatileImage>(vImg);
 141             }
 142         }
 143 
 144         Blit swToSurfaceBlit = Blit.getFromCache(src.getSurfaceType(), CompositeType.SrcNoEa, vImgSurfaceType);
 145         XRSurfaceData vImgSurface = (XRSurfaceData) vImg.getDestSurface();
 146         swToSurfaceBlit.Blit(src, vImgSurface, AlphaComposite.Src, null,
 147                              sx, sy, 0, 0, w, h);
 148 
 149         return vImgSurface;
 150     }
 151 }
 152 
 153 class XRPMBlit extends Blit {
 154     public XRPMBlit(SurfaceType srcType, SurfaceType dstType) {
 155         super(srcType, CompositeType.AnyAlpha, dstType);
 156     }
 157 
 158     public void Blit(SurfaceData src, SurfaceData dst, Composite comp, Region clip, int sx, int sy, int dx, int dy, int w, int h) {
 159         try {
 160             SunToolkit.awtLock();
 161 
 162             XRSurfaceData x11sdDst = (XRSurfaceData) dst;
 163             x11sdDst.validateAsDestination(null, clip);
 164             XRSurfaceData x11sdSrc = (XRSurfaceData) src;
 165             x11sdSrc.validateAsSource(null, XRUtils.RepeatNone, XRUtils.FAST);
 166 
 167             x11sdDst.maskBuffer.validateCompositeState(comp, null, null, null);
 168 
 169             x11sdDst.maskBuffer.compositeBlit(x11sdSrc, x11sdDst, sx, sy, dx, dy, w, h);
 170         } finally {
 171             SunToolkit.awtUnlock();
 172         }
 173     }
 174 }
 175 
 176 class XRPMScaledBlit extends ScaledBlit {
 177     public XRPMScaledBlit(SurfaceType srcType, SurfaceType dstType) {
 178         super(srcType, CompositeType.AnyAlpha, dstType);
 179     }
 180 
 181     /*
 182      * TODO: This breaks scales with non-integer coordinates!?!?!
 183      */
 184     public void Scale(SurfaceData src, SurfaceData dst, Composite comp, Region clip, int sx1, int sy1, int sx2, int sy2, double dx1, double dy1,
 185             double dx2, double dy2) {
 186         try {
 187             SunToolkit.awtLock();
 188 
 189             XRSurfaceData x11sdDst = (XRSurfaceData) dst;
 190             x11sdDst.validateAsDestination(null, clip);
 191             XRSurfaceData x11sdSrc = (XRSurfaceData) src;
 192             x11sdDst.maskBuffer.validateCompositeState(comp, null, null, null);
 193 
 194             double xScale = (dx2 - dx1) / (sx2 - sx1);
 195             double yScale = (dy2 - dy1) / (sy2 - sy1);
 196 
 197             sx1 *= xScale;
 198             sx2 *= xScale;
 199             sy1 *= yScale;
 200             sy2 *= yScale;
 201 
 202             AffineTransform xForm = AffineTransform.getScaleInstance(1 / xScale, 1 / yScale);
 203 
 204             x11sdSrc.validateAsSource(xForm, XRUtils.RepeatNone, XRUtils.FAST); /*
 205                                                                                  * TODO:
 206                                                                                  * padded
 207                                                                                  * blit
 208                                                                                  * required
 209                                                                                  * :
 210                                                                                  * -
 211                                                                                  * /
 212                                                                                  * ?
 213                                                                                  * ?
 214                                                                                  */
 215             x11sdDst.maskBuffer.compositeBlit(x11sdSrc, x11sdDst, (int) sx1, (int) sy1, (int) dx1, (int) dy1, (int) (dx2 - dx1), (int) (dy2 - dy1));
 216         } finally {
 217             SunToolkit.awtUnlock();
 218         }
 219     }
 220 }
 221 
 222 /**
 223  * Called also if scale+transform is set
 224  *
 225  * @author Clemens Eisserer
 226  */
 227 class XRPMTransformedBlit extends TransformBlit {
 228 
 229     public XRPMTransformedBlit(SurfaceType srcType, SurfaceType dstType) {
 230         super(srcType, CompositeType.AnyAlpha, dstType);
 231     }
 232 
 233     /*
 234      * Calculates the composite-rectangle required for transformed blits. This
 235      * method is functionally equal to: Shape shp =
 236      * xform.createTransformedShape(rect); Rectangle bounds = shp.getBounds();
 237      * but performs significantly better.
 238      */
 239     public Rectangle getCompositeBounds(AffineTransform tr, int dstx, int dsty, int width, int height) {
 240         double[] compBounds = new double[8];
 241         compBounds[0] = dstx;
 242         compBounds[1] = dsty;
 243         compBounds[2] = dstx + width;
 244         compBounds[3] = dsty;
 245         compBounds[4] = dstx + width;
 246         compBounds[5] = dsty + height;
 247         compBounds[6] = dstx;
 248         compBounds[7] = dsty + height;
 249 
 250         tr.transform(compBounds, 0, compBounds, 0, 4);
 251 
 252         double minX = Math.min(compBounds[0], Math.min(compBounds[2], Math.min(compBounds[4], compBounds[6])));
 253         double minY = Math.min(compBounds[1], Math.min(compBounds[3], Math.min(compBounds[5], compBounds[7])));
 254         double maxX = Math.max(compBounds[0], Math.max(compBounds[2], Math.max(compBounds[4], compBounds[6])));
 255         double maxY = Math.max(compBounds[1], Math.max(compBounds[3], Math.max(compBounds[5], compBounds[7])));
 256 
 257         minX = Math.floor(minX);
 258         minY = Math.floor(minY);
 259         maxX = Math.ceil(maxX);
 260         maxY = Math.ceil(maxY);
 261 
 262         return new Rectangle((int) minX, (int) minY, (int) (maxX - minX), (int) (maxY - minY));
 263     }
 264 
 265     public void Transform(SurfaceData src, SurfaceData dst, Composite comp, Region clip, AffineTransform xform, int hint, int srcx, int srcy,
 266             int dstx, int dsty, int width, int height) {
 267         try {
 268             SunToolkit.awtLock();
 269 
 270             int filter = XRUtils.ATransOpToXRQuality(hint);
 271 
 272             XRSurfaceData x11sdDst = (XRSurfaceData) dst;
 273             x11sdDst.validateAsDestination(null, clip);
 274             XRSurfaceData x11sdSrc = (XRSurfaceData) src;
 275             x11sdDst.maskBuffer.validateCompositeState(comp, null, null, null);
 276 
 277             Rectangle bounds = getCompositeBounds(xform, dstx, dsty, width, height);
 278 
 279             AffineTransform trx = AffineTransform.getTranslateInstance((-bounds.x), (-bounds.y));
 280             trx.concatenate(xform);
 281             AffineTransform maskTX = (AffineTransform) trx.clone();
 282 
 283             trx.translate(-srcx, -srcy);
 284 
 285             try {
 286                 trx.invert();
 287             } catch (NoninvertibleTransformException ex) {
 288                 trx.setToIdentity();
 289                 System.err.println("Reseted to identity!");
 290             }
 291 
 292             boolean omitMask = isMaskOmittable(trx, comp, filter);
 293 
 294             if (!omitMask) {
 295                 XRMaskImage mask = x11sdSrc.maskBuffer.getMaskImage();
 296 
 297                 x11sdSrc.validateAsSource(trx, XRUtils.RepeatPad, filter);
 298                 int maskPicture = mask.prepareBlitMask(x11sdDst, maskTX, width, height);
 299                 x11sdDst.maskBuffer.con.renderComposite(XRCompositeManager.getInstance(x11sdSrc).getCompRule(), x11sdSrc.picture, maskPicture, x11sdDst.picture,
 300                         0, 0, 0, 0, bounds.x, bounds.y, bounds.width, bounds.height);
 301             } else {
 302                 int repeat = filter == XRUtils.FAST ? XRUtils.RepeatNone : XRUtils.RepeatPad;
 303 
 304                 x11sdSrc.validateAsSource(trx, repeat, filter);
 305                 x11sdDst.maskBuffer.compositeBlit(x11sdSrc, x11sdDst, 0, 0, bounds.x, bounds.y, bounds.width, bounds.height);
 306             }
 307         } finally {
 308             SunToolkit.awtUnlock();
 309         }
 310     }
 311 
 312     /* TODO: Is mask ever omitable??? ... should be for 90 degree rotation and no shear, but we always need to use RepeatPad */
 313     protected static boolean isMaskOmittable(AffineTransform trx, Composite comp, int filter) {
 314         return (filter == XRUtils.FAST || trx.getTranslateX() == (int) trx.getTranslateX() /*
 315                                                                                             * If
 316                                                                                             * translate
 317                                                                                             * is
 318                                                                                             * integer
 319                                                                                             * only
 320                                                                                             */
 321                 && trx.getTranslateY() == (int) trx.getTranslateY() && (trx.getShearX() == 0 && trx.getShearY() == 0 // Only
 322                 // 90 degree
 323                 // rotation
 324                 || trx.getShearX() == -trx.getShearY())) && ((AlphaComposite) comp).getAlpha() == 1.0f; // No
 325         // ExtraAlpha!=1
 326     }
 327 }
 328 
 329 class XrSwToPMBlit extends Blit {
 330     Blit pmToSurfaceBlit;
 331 
 332     XrSwToPMBlit(SurfaceType srcType, SurfaceType dstType) {
 333         super(srcType, CompositeType.AnyAlpha, dstType);
 334         pmToSurfaceBlit = new XRPMBlit(dstType, dstType);
 335     }
 336 
 337     public void Blit(SurfaceData src, SurfaceData dst, Composite comp, Region clip, int sx, int sy, int dx, int dy, int w, int h) {
 338         /*
 339          * If the blit is write-only (putimge), no need for a temporary VI.
 340          */
 341         if (CompositeType.SrcOverNoEa.equals(comp) && (src.getTransparency() == Transparency.OPAQUE)) {
 342             Blit opaqueSwToSurfaceBlit = Blit.getFromCache(src.getSurfaceType(), CompositeType.SrcNoEa, dst.getSurfaceType());
 343             opaqueSwToSurfaceBlit.Blit(src, dst, comp, clip, sx, sy, dx, dy, w, h);
 344         } else {
 345             try {
 346                 SunToolkit.awtLock();
 347 
 348                 XRSurfaceData vImgSurface = XRPMBlitLoops.cacheToTmpSurface(src, (XRSurfaceData) dst, w, h, sx, sy);
 349                 pmToSurfaceBlit.Blit(vImgSurface, dst, comp, clip, 0, 0, dx, dy, w, h);
 350             } finally {
 351                 SunToolkit.awtUnlock();
 352             }
 353         }
 354     }
 355 }
 356 
 357 class XrSwToPMScaledBlit extends ScaledBlit {
 358     ScaledBlit pmToSurfaceBlit;
 359 
 360     XrSwToPMScaledBlit(SurfaceType srcType, SurfaceType dstType) {
 361         super(srcType, CompositeType.AnyAlpha, dstType);
 362         pmToSurfaceBlit = new XRPMScaledBlit(dstType, dstType);
 363     }
 364 
 365     public void Scale(SurfaceData src, SurfaceData dst, Composite comp, Region clip, int sx1, int sy1, int sx2, int sy2, double dx1, double dy1,
 366             double dx2, double dy2) {
 367         {
 368             int w = sx2 - sx1;
 369             int h = sy2 - sy1;
 370 
 371             try {
 372                 SunToolkit.awtLock();
 373                 XRSurfaceData vImgSurface = XRPMBlitLoops.cacheToTmpSurface(src, (XRSurfaceData) dst, w, h, sx1, sy1);
 374                 pmToSurfaceBlit.Scale(vImgSurface, dst, comp, clip, 0, 0, w, h, dx1, dy1, dx2, dy2);
 375             } finally {
 376                 SunToolkit.awtUnlock();
 377             }
 378         }
 379     }
 380 }
 381 
 382 class XrSwToPMTransformedBlit extends TransformBlit {
 383     TransformBlit pmToSurfaceBlit;
 384 
 385     XrSwToPMTransformedBlit(SurfaceType srcType, SurfaceType dstType) {
 386         super(srcType, CompositeType.AnyAlpha, dstType);
 387         pmToSurfaceBlit = new XRPMTransformedBlit(dstType, dstType);
 388     }
 389 
 390     public void Transform(SurfaceData src, SurfaceData dst, Composite comp, Region clip, AffineTransform xform, int hint, int sx, int sy, int dstx,
 391             int dsty, int w, int h) {
 392         try {
 393             SunToolkit.awtLock();
 394 
 395             XRSurfaceData vImgSurface = XRPMBlitLoops.cacheToTmpSurface(src, (XRSurfaceData) dst, w, h, sx, sy);
 396             pmToSurfaceBlit.Transform(vImgSurface, dst, comp, clip, xform, hint, 0, 0, dstx, dsty, w, h);
 397         } finally {
 398             SunToolkit.awtUnlock();
 399         }
 400     }
 401 }