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 }