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