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 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 
getInstance( XRSurfaceData surface)81     public static synchronized XRCompositeManager getInstance(
82             XRSurfaceData surface) {
83         if (instance == null) {
84             instance = new XRCompositeManager(surface);
85         }
86         return instance;
87     }
88 
XRCompositeManager(XRSurfaceData surface)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 
initResources(XRSurfaceData surface)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 
setForeground(int pixel)133     public void setForeground(int pixel) {
134         solidColor.setColorValues(pixel);
135     }
136 
setGradientPaint(XRSurfaceData gradient)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 
setTexturePaint(XRSurfaceData texture)145     public void setTexturePaint(XRSurfaceData texture) {
146         this.texture = texture;
147         this.srcType = TEXTURE;
148     }
149 
XRResetPaint()150     public void XRResetPaint() {
151         srcType = SOLID;
152     }
153 
validateCompositeState(Composite comp, AffineTransform xform, Paint paint, SunGraphics2D sg2d)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 
setComposite(Composite comp)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 
maskRequired()229     public boolean maskRequired() {
230         return (!xorEnabled)
231                 && ((srcType != SOLID)
232                         || (srcType == SOLID && (solidColor.alpha != 0xffff) || (extraAlpha != 1.0f)));
233     }
234 
XRComposite(int src, int mask, int dst, int srcX, int srcY, int maskX, int maskY, int dstX, int dstY, int width, int height)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 
XRRenderRectangles(XRSurfaceData dst, GrowableRectArray rects)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 
XRCompositeRectangles(XRSurfaceData dst, GrowableRectArray rects)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 
getCurrentSource()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 
compositeBlit(XRSurfaceData src, XRSurfaceData dst, int sx, int sy, int dx, int dy, int w, int h)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 
compositeText(XRSurfaceData dst, int sx, int sy, int glyphSet, int maskFormat, GrowableEltArray elts)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 
getMaskColor()311     public XRColor getMaskColor() {
312         return !isTexturePaintActive() ? XRColor.FULL_ALPHA : getAlphaColor();
313     }
314 
getExtraAlphaMask()315     public int getExtraAlphaMask() {
316         return alphaMask;
317     }
318 
isTexturePaintActive()319     public boolean isTexturePaintActive() {
320         return srcType == TEXTURE;
321     }
322 
isSolidPaintActive()323     public boolean isSolidPaintActive() {
324         return srcType == SOLID;
325     }
326 
getAlphaColor()327     public XRColor getAlphaColor() {
328         return alphaColor;
329     }
330 
getBackend()331     public XRBackend getBackend() {
332         return con;
333     }
334 
getExtraAlpha()335     public float getExtraAlpha() {
336         return validatedExtraAlpha;
337     }
338 
getCompRule()339     public byte getCompRule() {
340         return compRule;
341     }
342 
getTextRenderer()343     public XRTextRenderer getTextRenderer() {
344         return textRenderer;
345     }
346 
getMaskBuffer()347     public MaskTileManager getMaskBuffer() {
348         return maskBuffer;
349     }
350 
getMaskImage()351     public XRMaskImage getMaskImage() {
352         return maskImage;
353     }
354 }
355