1 /*
   2  * Copyright (c) 2010, 2013, 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 java.awt.*;
  29 import java.awt.geom.*;
  30 
  31 import java.security.AccessController;
  32 import java.security.PrivilegedAction;
  33 
  34 import sun.font.*;
  35 import sun.java2d.*;
  36 import sun.java2d.loops.*;
  37 
  38 /**
  39  * Manages per-application resources, e.g. the 1x1 pixmap used for solid color
  40  * fill as well as per-application state e.g. the currently set source picture
  41  * used for composition .
  42  *
  43  * @author Clemens Eisserer
  44  */
  45 
  46 public class XRCompositeManager {
  47     private static boolean enableGradCache = true;
  48     private static XRCompositeManager instance;
  49 
  50     private static final int SOLID = 0;
  51     private static final int TEXTURE = 1;
  52     private static final int GRADIENT = 2;
  53 
  54     int srcType;
  55     XRSolidSrcPict solidSrc32;
  56     XRSurfaceData texture;
  57     XRSurfaceData gradient;
  58     int alphaMask = XRUtils.None;
  59 
  60     XRColor solidColor = new XRColor();
  61     float extraAlpha = 1.0f;
  62     byte compRule = XRUtils.PictOpOver;
  63     XRColor alphaColor = new XRColor();
  64 
  65     XRSurfaceData solidSrcPict;
  66     int alphaMaskPict;
  67     int gradCachePixmap;
  68     int gradCachePicture;
  69 
  70     boolean xorEnabled = false;
  71     int validatedPixel = 0;
  72     Composite validatedComp;
  73     Paint validatedPaint;
  74     float validatedExtraAlpha = 1.0f;
  75 
  76     XRBackend con;
  77     MaskTileManager maskBuffer;
  78     XRTextRenderer textRenderer;
  79     XRMaskImage maskImage;
  80 
  81     public static synchronized XRCompositeManager getInstance(
  82             XRSurfaceData surface) {
  83         if (instance == null) {
  84             instance = new XRCompositeManager(surface);
  85         }
  86         return instance;
  87     }
  88 
  89     private XRCompositeManager(XRSurfaceData surface) {
  90         con = new XRBackendNative();
  91 
  92         String gradProp =
  93             AccessController.doPrivileged(new PrivilegedAction<String>() {
  94                 public String run() {
  95                     return System.getProperty("sun.java2d.xrgradcache");
  96                 }
  97             });
  98 
  99         enableGradCache = gradProp == null ||
 100                           !(gradProp.equalsIgnoreCase("false") ||
 101                           gradProp.equalsIgnoreCase("f"));
 102 
 103         XRPaints.register(this);
 104 
 105         initResources(surface);
 106 
 107         maskBuffer = new MaskTileManager(this, surface.getXid());
 108         textRenderer = new XRTextRenderer(this);
 109         maskImage = new XRMaskImage(this, surface.getXid());
 110     }
 111 
 112     public void initResources(XRSurfaceData surface) {
 113         int parentXid = surface.getXid();
 114 
 115         solidSrc32 = new XRSolidSrcPict(con, parentXid);
 116         setForeground(0);
 117 
 118         int extraAlphaMask = con.createPixmap(parentXid, 8, 1, 1);
 119         alphaMaskPict = con.createPicture(extraAlphaMask,
 120                 XRUtils.PictStandardA8);
 121         con.setPictureRepeat(alphaMaskPict, XRUtils.RepeatNormal);
 122         con.renderRectangle(alphaMaskPict, XRUtils.PictOpClear,
 123                 XRColor.NO_ALPHA, 0, 0, 1, 1);
 124 
 125         if (enableGradCache) {
 126             gradCachePixmap = con.createPixmap(parentXid, 32,
 127                     MaskTileManager.MASK_SIZE, MaskTileManager.MASK_SIZE);
 128             gradCachePicture = con.createPicture(gradCachePixmap,
 129                     XRUtils.PictStandardARGB32);
 130         }
 131     }
 132 
 133     public void setForeground(int pixel) {
 134         solidColor.setColorValues(pixel);
 135     }
 136 
 137     public void setGradientPaint(XRSurfaceData gradient) {
 138         if (this.gradient != null) {
 139             con.freePicture(this.gradient.picture);
 140         }
 141         this.gradient = gradient;
 142         srcType = GRADIENT;
 143     }
 144 
 145     public void setTexturePaint(XRSurfaceData texture) {
 146         this.texture = texture;
 147         this.srcType = TEXTURE;
 148     }
 149 
 150     public void XRResetPaint() {
 151         srcType = SOLID;
 152     }
 153 
 154     public void validateCompositeState(Composite comp, AffineTransform xform,
 155             Paint paint, SunGraphics2D sg2d) {
 156         boolean updatePaint = (paint != validatedPaint) || paint == null;
 157 
 158         // validate composite
 159         if ((comp != validatedComp)) {
 160             if (comp != null) {
 161                 setComposite(comp);
 162             } else {
 163                 comp = AlphaComposite.getInstance(AlphaComposite.SRC_OVER);
 164                 setComposite(comp);
 165             }
 166             // the paint state is dependent on the composite state, so make
 167             // sure we update the color below
 168             updatePaint = true;
 169             validatedComp = comp;
 170         }
 171 
 172         if (sg2d != null && (validatedPixel != sg2d.pixel  || updatePaint)) {
 173             validatedPixel = sg2d.pixel;
 174             setForeground(validatedPixel);
 175         }
 176 
 177         // validate paint
 178         if (updatePaint) {
 179             if (paint != null && sg2d != null
 180                     && sg2d.paintState >= SunGraphics2D.PAINT_GRADIENT) {
 181                 XRPaints.setPaint(sg2d, paint);
 182             } else {
 183                 XRResetPaint();
 184             }
 185             validatedPaint = paint;
 186         }
 187 
 188         if (srcType != SOLID) {
 189             AffineTransform at = (AffineTransform) xform.clone();
 190             try {
 191                 at.invert();
 192             } catch (NoninvertibleTransformException e) {
 193                 at.setToIdentity();
 194             }
 195             getCurrentSource().validateAsSource(at, -1, XRUtils.ATransOpToXRQuality(sg2d.interpolationType));
 196         }
 197     }
 198 
 199     private void setComposite(Composite comp) {
 200         if (comp instanceof AlphaComposite) {
 201             AlphaComposite aComp = (AlphaComposite) comp;
 202             validatedExtraAlpha = aComp.getAlpha();
 203 
 204             this.compRule = XRUtils.j2dAlphaCompToXR(aComp.getRule());
 205             this.extraAlpha = validatedExtraAlpha;
 206 
 207             if (extraAlpha == 1.0f) {
 208                 alphaMask = XRUtils.None;
 209                 alphaColor.alpha = XRColor.FULL_ALPHA.alpha;
 210             } else {
 211                 alphaColor.alpha = XRColor
 212                         .byteToXRColorValue((int) (extraAlpha * 255));
 213                 alphaMask = alphaMaskPict;
 214                 con.renderRectangle(alphaMaskPict, XRUtils.PictOpSrc,
 215                         alphaColor, 0, 0, 1, 1);
 216             }
 217 
 218             xorEnabled = false;
 219         } else if (comp instanceof XORComposite) {
 220             /* XOR composite validation is handled in XRSurfaceData */
 221             xorEnabled = true;
 222         } else {
 223             throw new InternalError(
 224                     "Composite accaleration not implemented for: "
 225                             + comp.getClass().getName());
 226         }
 227     }
 228 
 229     public boolean maskRequired() {
 230         return (!xorEnabled)
 231                 && ((srcType != SOLID)
 232                         || (srcType == SOLID && (solidColor.alpha != 0xffff) || (extraAlpha != 1.0f)));
 233     }
 234 
 235     public void XRComposite(int src, int mask, int dst, int srcX, int srcY,
 236             int maskX, int maskY, int dstX, int dstY, int width, int height) {
 237         int cachedSrc = (src == XRUtils.None) ? getCurrentSource().picture : src;
 238         int cachedX = srcX;
 239         int cachedY = srcY;
 240 
 241         if (enableGradCache && gradient != null
 242                 && cachedSrc == gradient.picture) {
 243             con.renderComposite(XRUtils.PictOpSrc, gradient.picture,
 244                     XRUtils.None, gradCachePicture, srcX, srcY, 0, 0, 0, 0,
 245                     width, height);
 246             cachedX = 0;
 247             cachedY = 0;
 248             cachedSrc = gradCachePicture;
 249         }
 250 
 251         con.renderComposite(compRule, cachedSrc, mask, dst, cachedX, cachedY,
 252                 maskX, maskY, dstX, dstY, width, height);
 253     }
 254 
 255     public void XRRenderRectangles(XRSurfaceData dst, GrowableRectArray rects) {
 256         if (xorEnabled) {
 257             con.GCRectangles(dst.getXid(), dst.getGC(), rects);
 258         } else {
 259             if (rects.getSize() == 1) {
 260                 con.renderRectangle(dst.getPicture(), compRule, solidColor,
 261                         rects.getX(0), rects.getY(0), rects.getWidth(0), rects.getHeight(0));
 262             } else {
 263                 con.renderRectangles(dst.getPicture(), compRule, solidColor, rects);
 264             }
 265         }
 266     }
 267 
 268     public void XRCompositeRectangles(XRSurfaceData dst, GrowableRectArray rects) {
 269         int srcPict = getCurrentSource().picture;
 270 
 271         for(int i=0; i < rects.getSize(); i++) {
 272             int x = rects.getX(i);
 273             int y = rects.getY(i);
 274             int width = rects.getWidth(i);
 275             int height = rects.getHeight(i);
 276 
 277             con.renderComposite(compRule, srcPict, XRUtils.None, dst.picture, x, y, 0, 0, x, y, width, height);
 278         }
 279     }
 280 
 281     protected XRSurfaceData getCurrentSource() {
 282         switch(srcType) {
 283         case SOLID:
 284             return solidSrc32.prepareSrcPict(validatedPixel);
 285         case TEXTURE:
 286             return texture;
 287         case GRADIENT:
 288             return gradient;
 289         }
 290 
 291         return null;
 292     }
 293 
 294     public void compositeBlit(XRSurfaceData src, XRSurfaceData dst, int sx,
 295             int sy, int dx, int dy, int w, int h) {
 296         con.renderComposite(compRule, src.picture, alphaMask, dst.picture, sx,
 297                 sy, 0, 0, dx, dy, w, h);
 298     }
 299 
 300     public void compositeText(XRSurfaceData dst, int sx, int sy, int glyphSet,
 301             int maskFormat, GrowableEltArray elts) {
 302         /*
 303          * Try to emulate the SRC blend mode with SRC_OVER.
 304          * We bail out during pipe validation for cases where this is not possible.
 305          */
 306         byte textCompRule = (compRule != XRUtils.PictOpSrc) ? compRule : XRUtils.PictOpOver;
 307         con.XRenderCompositeText(textCompRule, getCurrentSource().picture, dst.picture,
 308                 maskFormat, sx, sy, 0, 0, glyphSet, elts);
 309     }
 310 
 311     public XRColor getMaskColor() {
 312         return !isTexturePaintActive() ? XRColor.FULL_ALPHA : getAlphaColor();
 313     }
 314 
 315     public int getExtraAlphaMask() {
 316         return alphaMask;
 317     }
 318 
 319     public boolean isTexturePaintActive() {
 320         return srcType == TEXTURE;
 321     }
 322 
 323     public boolean isSolidPaintActive() {
 324         return srcType == SOLID;
 325     }
 326 
 327     public XRColor getAlphaColor() {
 328         return alphaColor;
 329     }
 330 
 331     public XRBackend getBackend() {
 332         return con;
 333     }
 334 
 335     public float getExtraAlpha() {
 336         return validatedExtraAlpha;
 337     }
 338 
 339     public byte getCompRule() {
 340         return compRule;
 341     }
 342 
 343     public XRTextRenderer getTextRenderer() {
 344         return textRenderer;
 345     }
 346 
 347     public MaskTileManager getMaskBuffer() {
 348         return maskBuffer;
 349     }
 350 
 351     public XRMaskImage getMaskImage() {
 352         return maskImage;
 353     }
 354 }