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