1 /*
   2  * Copyright (c) 2010, 2014, 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     @SuppressWarnings("cast")
 182     public void Scale(SurfaceData src, SurfaceData dst, Composite comp, Region clip, int sx1, int sy1, int sx2, int sy2, double dx1, double dy1,
 183             double dx2, double dy2) {
 184         try {
 185             SunToolkit.awtLock();
 186 
 187             XRSurfaceData x11sdDst = (XRSurfaceData) dst;
 188             x11sdDst.validateAsDestination(null, clip);
 189             XRSurfaceData x11sdSrc = (XRSurfaceData) src;
 190             x11sdDst.maskBuffer.validateCompositeState(comp, null, null, null);
 191 
 192             double xScale = (dx2 - dx1) / (sx2 - sx1);
 193             double yScale = (dy2 - dy1) / (sy2 - sy1);
 194 
 195             sx1 *= xScale;
 196             sx2 *= xScale;
 197             sy1 *= yScale;
 198             sy2 *= yScale;
 199 
 200             dx1 = Math.ceil(dx1 - 0.5);
 201             dy1 = Math.ceil(dy1 - 0.5);
 202             dx2 = Math.ceil(dx2 - 0.5);
 203             dy2 = Math.ceil(dy2 - 0.5);
 204 
 205             AffineTransform xForm = AffineTransform.getScaleInstance(1 / xScale, 1 / yScale);
 206 
 207             x11sdSrc.validateAsSource(xForm, XRUtils.RepeatNone, XRUtils.FAST);
 208             x11sdDst.maskBuffer.compositeBlit(x11sdSrc, x11sdDst, (int) sx1, (int) sy1, (int) dx1, (int) dy1, (int) (dx2 - dx1), (int) (dy2 - dy1));
 209         } finally {
 210             SunToolkit.awtUnlock();
 211         }
 212     }
 213 }
 214 
 215 /**
 216  * Called also if scale+transform is set
 217  *
 218  * @author Clemens Eisserer
 219  */
 220 class XRPMTransformedBlit extends TransformBlit {
 221     final Rectangle compositeBounds = new Rectangle();
 222     final double[] srcCoords = new double[8];
 223     final double[] dstCoords = new double[8];
 224 
 225     public XRPMTransformedBlit(SurfaceType srcType, SurfaceType dstType) {
 226         super(srcType, CompositeType.AnyAlpha, dstType);
 227     }
 228 
 229     /*
 230      * Calculates the composition-rectangle required for transformed blits.
 231      * For composite operations where the composition-rectangle defines
 232      * the modified destination area, coordinates are rounded.
 233      * Otherwise the composition window rectangle is sized large enough
 234      * to not clip away any pixels.
 235      */
 236     protected void adjustCompositeBounds(boolean isQuadrantRotated, AffineTransform tr,
 237             int dstx, int dsty, int width, int height) {
 238         srcCoords[0] = dstx;
 239         srcCoords[1] = dsty;
 240         srcCoords[2] = dstx + width;
 241         srcCoords[3] = dsty + height;
 242 
 243         double minX, minY, maxX, maxY;
 244         if (isQuadrantRotated) {
 245             tr.transform(srcCoords, 0, dstCoords, 0, 2);
 246 
 247             minX = Math.min(dstCoords[0], dstCoords[2]);
 248             minY = Math.min(dstCoords[1], dstCoords[3]);
 249             maxX = Math.max(dstCoords[0], dstCoords[2]);
 250             maxY = Math.max(dstCoords[1], dstCoords[3]);
 251 
 252             minX = Math.ceil(minX - 0.5);
 253             minY = Math.ceil(minY - 0.5);
 254             maxX = Math.ceil(maxX - 0.5);
 255             maxY = Math.ceil(maxY - 0.5);
 256         } else {
 257             srcCoords[4] = dstx;
 258             srcCoords[5] = dsty + height;
 259             srcCoords[6] = dstx + width;
 260             srcCoords[7] = dsty;
 261 
 262             tr.transform(srcCoords, 0, dstCoords, 0, 4);
 263 
 264             minX = Math.min(dstCoords[0], Math.min(dstCoords[2], Math.min(dstCoords[4], dstCoords[6])));
 265             minY = Math.min(dstCoords[1], Math.min(dstCoords[3], Math.min(dstCoords[5], dstCoords[7])));
 266             maxX = Math.max(dstCoords[0], Math.max(dstCoords[2], Math.max(dstCoords[4], dstCoords[6])));
 267             maxY = Math.max(dstCoords[1], Math.max(dstCoords[3], Math.max(dstCoords[5], dstCoords[7])));
 268 
 269             minX = Math.floor(minX);
 270             minY = Math.floor(minY);
 271             maxX = Math.ceil(maxX);
 272             maxY = Math.ceil(maxY);
 273         }
 274 
 275         compositeBounds.x = (int) minX;
 276         compositeBounds.y = (int) minY;
 277         compositeBounds.width = (int) (maxX - minX);
 278         compositeBounds.height = (int) (maxY - minY);
 279     }
 280 
 281     public void Transform(SurfaceData src, SurfaceData dst, Composite comp, Region clip, AffineTransform xform,
 282             int hint, int srcx, int srcy, int dstx, int dsty, int width, int height) {
 283         try {
 284             SunToolkit.awtLock();
 285 
 286             XRSurfaceData x11sdDst = (XRSurfaceData) dst;
 287             XRSurfaceData x11sdSrc = (XRSurfaceData) src;
 288             XRCompositeManager xrMgr = XRCompositeManager.getInstance(x11sdSrc);
 289 
 290             float extraAlpha = ((AlphaComposite) comp).getAlpha();
 291             int filter = XRUtils.ATransOpToXRQuality(hint);
 292             boolean isQuadrantRotated = XRUtils.isTransformQuadrantRotated(xform);
 293 
 294             adjustCompositeBounds(isQuadrantRotated, xform, dstx, dsty, width, height);
 295 
 296             x11sdDst.validateAsDestination(null, clip);
 297             x11sdDst.maskBuffer.validateCompositeState(comp, null, null, null);
 298 
 299             AffineTransform trx = AffineTransform.getTranslateInstance(-compositeBounds.x, -compositeBounds.y);
 300             trx.concatenate(xform);
 301             AffineTransform maskTX = (AffineTransform) trx.clone();
 302             trx.translate(-srcx, -srcy);
 303 
 304             try {
 305                 trx.invert();
 306             } catch (NoninvertibleTransformException ex) {
 307                 trx.setToIdentity();
 308             }
 309 
 310             if (filter != XRUtils.FAST && (!isQuadrantRotated || extraAlpha != 1.0f)) {
 311                 XRMaskImage mask = x11sdSrc.maskBuffer.getMaskImage();
 312 
 313                 // For quadrant-transformed blits geometry is not stored inside the mask
 314                 // therefore we can use a repeating 1x1 mask for applying extra alpha.
 315                 int maskPicture = isQuadrantRotated ? xrMgr.getExtraAlphaMask()
 316                         : mask.prepareBlitMask(x11sdDst, maskTX, width, height);
 317 
 318                 x11sdSrc.validateAsSource(trx, XRUtils.RepeatPad, filter);
 319                 x11sdDst.maskBuffer.con.renderComposite(xrMgr.getCompRule(), x11sdSrc.picture,
 320                         maskPicture, x11sdDst.picture, 0, 0, 0, 0, compositeBounds.x, compositeBounds.y,
 321                         compositeBounds.width, compositeBounds.height);
 322             } else {
 323                 int repeat = filter == XRUtils.FAST ? XRUtils.RepeatNone : XRUtils.RepeatPad;
 324 
 325                 x11sdSrc.validateAsSource(trx, repeat, filter);
 326 
 327                 // compositeBlit takes care of extra alpha
 328                 x11sdDst.maskBuffer.compositeBlit(x11sdSrc, x11sdDst, 0, 0, compositeBounds.x,
 329                         compositeBounds.y, compositeBounds.width, compositeBounds.height);
 330             }
 331         } finally {
 332             SunToolkit.awtUnlock();
 333         }
 334     }
 335 }
 336 
 337 class XrSwToPMBlit extends Blit {
 338     Blit pmToSurfaceBlit;
 339 
 340     XrSwToPMBlit(SurfaceType srcType, SurfaceType dstType) {
 341         super(srcType, CompositeType.AnyAlpha, dstType);
 342         pmToSurfaceBlit = new XRPMBlit(dstType, dstType);
 343     }
 344 
 345     public void Blit(SurfaceData src, SurfaceData dst, Composite comp, Region clip, int sx, int sy, int dx, int dy, int w, int h) {
 346         // If the blit is write-only (putimge), no need for a temporary VI.
 347         if (CompositeType.SrcOverNoEa.equals(comp) && (src.getTransparency() == Transparency.OPAQUE)) {
 348             Blit opaqueSwToSurfaceBlit = Blit.getFromCache(src.getSurfaceType(), CompositeType.SrcNoEa, dst.getSurfaceType());
 349             opaqueSwToSurfaceBlit.Blit(src, dst, comp, clip, sx, sy, dx, dy, w, h);
 350         } else {
 351             try {
 352                 SunToolkit.awtLock();
 353 
 354                 XRSurfaceData vImgSurface = XRPMBlitLoops.cacheToTmpSurface(src, (XRSurfaceData) dst, w, h, sx, sy);
 355                 pmToSurfaceBlit.Blit(vImgSurface, dst, comp, clip, 0, 0, dx, dy, w, h);
 356             } finally {
 357                 SunToolkit.awtUnlock();
 358             }
 359         }
 360     }
 361 }
 362 
 363 class XrSwToPMScaledBlit extends ScaledBlit {
 364     ScaledBlit pmToSurfaceBlit;
 365 
 366     XrSwToPMScaledBlit(SurfaceType srcType, SurfaceType dstType) {
 367         super(srcType, CompositeType.AnyAlpha, dstType);
 368         pmToSurfaceBlit = new XRPMScaledBlit(dstType, dstType);
 369     }
 370 
 371     public void Scale(SurfaceData src, SurfaceData dst, Composite comp, Region clip, int sx1, int sy1, int sx2, int sy2, double dx1, double dy1,
 372             double dx2, double dy2) {
 373         {
 374             int w = sx2 - sx1;
 375             int h = sy2 - sy1;
 376 
 377             try {
 378                 SunToolkit.awtLock();
 379                 XRSurfaceData vImgSurface = XRPMBlitLoops.cacheToTmpSurface(src, (XRSurfaceData) dst, w, h, sx1, sy1);
 380                 pmToSurfaceBlit.Scale(vImgSurface, dst, comp, clip, 0, 0, w, h, dx1, dy1, dx2, dy2);
 381             } finally {
 382                 SunToolkit.awtUnlock();
 383             }
 384         }
 385     }
 386 }
 387 
 388 class XrSwToPMTransformedBlit extends TransformBlit {
 389     TransformBlit pmToSurfaceBlit;
 390 
 391     XrSwToPMTransformedBlit(SurfaceType srcType, SurfaceType dstType) {
 392         super(srcType, CompositeType.AnyAlpha, dstType);
 393         pmToSurfaceBlit = new XRPMTransformedBlit(dstType, dstType);
 394     }
 395 
 396     public void Transform(SurfaceData src, SurfaceData dst, Composite comp, Region clip, AffineTransform xform, int hint, int sx, int sy, int dstx,
 397             int dsty, int w, int h) {
 398         try {
 399             SunToolkit.awtLock();
 400 
 401             XRSurfaceData vImgSurface = XRPMBlitLoops.cacheToTmpSurface(src, (XRSurfaceData) dst, w, h, sx, sy);
 402             pmToSurfaceBlit.Transform(vImgSurface, dst, comp, clip, xform, hint, 0, 0, dstx, dsty, w, h);
 403         } finally {
 404             SunToolkit.awtUnlock();
 405         }
 406     }
 407 }