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