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
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 }