| /* |
| * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. |
| * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
| * |
| * This code is free software; you can redistribute it and/or modify it |
| * under the terms of the GNU General Public License version 2 only, as |
| * published by the Free Software Foundation. Oracle designates this |
| * particular file as subject to the "Classpath" exception as provided |
| * by Oracle in the LICENSE file that accompanied this code. |
| * |
| * This code is distributed in the hope that it will be useful, but WITHOUT |
| * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
| * version 2 for more details (a copy is included in the LICENSE file that |
| * accompanied this code). |
| * |
| * You should have received a copy of the GNU General Public License version |
| * 2 along with this work; if not, write to the Free Software Foundation, |
| * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
| * |
| * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
| * or visit www.oracle.com if you need additional information or have any |
| * questions. |
| */ |
| |
| package sun.java2d.xr; |
| |
| import java.awt.*; |
| import java.awt.geom.*; |
| |
| import java.security.AccessController; |
| import java.security.PrivilegedAction; |
| |
| import sun.font.*; |
| import sun.java2d.*; |
| import sun.java2d.jules.*; |
| import sun.java2d.loops.*; |
| |
| /** |
| * Manages per-application resources, e.g. the 1x1 pixmap used for solid color |
| * fill as well as per-application state e.g. the currently set source picture |
| * used for composition . |
| * |
| * @author Clemens Eisserer |
| */ |
| |
| public class XRCompositeManager { |
| private static boolean enableGradCache = true; |
| private static XRCompositeManager instance; |
| |
| private static final int SOLID = 0; |
| private static final int TEXTURE = 1; |
| private static final int GRADIENT = 2; |
| |
| int srcType; |
| XRSolidSrcPict solidSrc32; |
| XRSurfaceData texture; |
| XRSurfaceData gradient; |
| int alphaMask = XRUtils.None; |
| |
| XRColor solidColor = new XRColor(); |
| float extraAlpha = 1.0f; |
| byte compRule = XRUtils.PictOpOver; |
| XRColor alphaColor = new XRColor(); |
| |
| XRSurfaceData solidSrcPict; |
| int alphaMaskPict; |
| int gradCachePixmap; |
| int gradCachePicture; |
| |
| boolean xorEnabled = false; |
| int validatedPixel = 0; |
| Composite validatedComp; |
| Paint validatedPaint; |
| float validatedExtraAlpha = 1.0f; |
| |
| XRBackend con; |
| MaskTileManager maskBuffer; |
| XRTextRenderer textRenderer; |
| XRMaskImage maskImage; |
| |
| public static synchronized XRCompositeManager getInstance( |
| XRSurfaceData surface) { |
| if (instance == null) { |
| instance = new XRCompositeManager(surface); |
| } |
| return instance; |
| } |
| |
| private XRCompositeManager(XRSurfaceData surface) { |
| con = new XRBackendNative(); |
| |
| String gradProp = |
| AccessController.doPrivileged(new PrivilegedAction<String>() { |
| public String run() { |
| return System.getProperty("sun.java2d.xrgradcache"); |
| } |
| }); |
| |
| enableGradCache = gradProp == null || |
| !(gradProp.equalsIgnoreCase("false") || |
| gradProp.equalsIgnoreCase("f")); |
| |
| XRPaints.register(this); |
| |
| initResources(surface); |
| |
| maskBuffer = new MaskTileManager(this, surface.getXid()); |
| textRenderer = new XRTextRenderer(this); |
| maskImage = new XRMaskImage(this, surface.getXid()); |
| } |
| |
| public void initResources(XRSurfaceData surface) { |
| int parentXid = surface.getXid(); |
| |
| solidSrc32 = new XRSolidSrcPict(con, parentXid); |
| setForeground(0); |
| |
| int extraAlphaMask = con.createPixmap(parentXid, 8, 1, 1); |
| alphaMaskPict = con.createPicture(extraAlphaMask, |
| XRUtils.PictStandardA8); |
| con.setPictureRepeat(alphaMaskPict, XRUtils.RepeatNormal); |
| con.renderRectangle(alphaMaskPict, XRUtils.PictOpClear, |
| XRColor.NO_ALPHA, 0, 0, 1, 1); |
| |
| if (enableGradCache) { |
| gradCachePixmap = con.createPixmap(parentXid, 32, |
| MaskTileManager.MASK_SIZE, MaskTileManager.MASK_SIZE); |
| gradCachePicture = con.createPicture(gradCachePixmap, |
| XRUtils.PictStandardARGB32); |
| } |
| } |
| |
| public void setForeground(int pixel) { |
| solidColor.setColorValues(pixel, true); |
| } |
| |
| public void setGradientPaint(XRSurfaceData gradient) { |
| if (this.gradient != null) { |
| con.freePicture(this.gradient.picture); |
| } |
| this.gradient = gradient; |
| srcType = GRADIENT; |
| } |
| |
| public void setTexturePaint(XRSurfaceData texture) { |
| this.texture = texture; |
| this.srcType = TEXTURE; |
| } |
| |
| public void XRResetPaint() { |
| srcType = SOLID; |
| } |
| |
| public void validateCompositeState(Composite comp, AffineTransform xform, |
| Paint paint, SunGraphics2D sg2d) { |
| boolean updatePaint = (paint != validatedPaint) || paint == null; |
| |
| // validate composite |
| if ((comp != validatedComp)) { |
| if (comp != null) { |
| setComposite(comp); |
| } else { |
| comp = AlphaComposite.getInstance(AlphaComposite.SRC_OVER); |
| setComposite(comp); |
| } |
| // the paint state is dependent on the composite state, so make |
| // sure we update the color below |
| updatePaint = true; |
| validatedComp = comp; |
| } |
| |
| if (sg2d != null && (validatedPixel != sg2d.pixel || updatePaint)) { |
| validatedPixel = sg2d.pixel; |
| setForeground(validatedPixel); |
| } |
| |
| // validate paint |
| if (updatePaint) { |
| if (paint != null && sg2d != null |
| && sg2d.paintState >= SunGraphics2D.PAINT_GRADIENT) { |
| XRPaints.setPaint(sg2d, paint); |
| } else { |
| XRResetPaint(); |
| } |
| validatedPaint = paint; |
| } |
| |
| if (srcType != SOLID) { |
| AffineTransform at = (AffineTransform) xform.clone(); |
| try { |
| at.invert(); |
| } catch (NoninvertibleTransformException e) { |
| at.setToIdentity(); |
| } |
| getCurrentSource().validateAsSource(at, -1, XRUtils.ATransOpToXRQuality(sg2d.interpolationType)); |
| } |
| } |
| |
| private void setComposite(Composite comp) { |
| if (comp instanceof AlphaComposite) { |
| AlphaComposite aComp = (AlphaComposite) comp; |
| validatedExtraAlpha = aComp.getAlpha(); |
| |
| this.compRule = XRUtils.j2dAlphaCompToXR(aComp.getRule()); |
| this.extraAlpha = validatedExtraAlpha; |
| |
| if (extraAlpha == 1.0f) { |
| alphaMask = XRUtils.None; |
| alphaColor.alpha = XRColor.FULL_ALPHA.alpha; |
| } else { |
| alphaColor.alpha = XRColor |
| .byteToXRColorValue((int) (extraAlpha * 255)); |
| alphaMask = alphaMaskPict; |
| con.renderRectangle(alphaMaskPict, XRUtils.PictOpSrc, |
| alphaColor, 0, 0, 1, 1); |
| } |
| |
| xorEnabled = false; |
| } else if (comp instanceof XORComposite) { |
| /* XOR composite validation is handled in XRSurfaceData */ |
| xorEnabled = true; |
| } else { |
| throw new InternalError( |
| "Composite accaleration not implemented for: " |
| + comp.getClass().getName()); |
| } |
| } |
| |
| public boolean maskRequired() { |
| return (!xorEnabled) |
| && ((srcType != SOLID) |
| || (srcType == SOLID && (solidColor.alpha != 0xffff) || (extraAlpha != 1.0f))); |
| } |
| |
| public void XRComposite(int src, int mask, int dst, int srcX, int srcY, |
| int maskX, int maskY, int dstX, int dstY, int width, int height) { |
| int cachedSrc = (src == XRUtils.None) ? getCurrentSource().picture : src; |
| int cachedX = srcX; |
| int cachedY = srcY; |
| |
| if (enableGradCache && gradient != null |
| && cachedSrc == gradient.picture) { |
| con.renderComposite(XRUtils.PictOpSrc, gradient.picture, |
| XRUtils.None, gradCachePicture, srcX, srcY, 0, 0, 0, 0, |
| width, height); |
| cachedX = 0; |
| cachedY = 0; |
| cachedSrc = gradCachePicture; |
| } |
| |
| con.renderComposite(compRule, cachedSrc, mask, dst, cachedX, cachedY, |
| maskX, maskY, dstX, dstY, width, height); |
| } |
| |
| public void XRCompositeTraps(int dst, int srcX, int srcY, |
| TrapezoidList trapList) { |
| int renderReferenceX = 0; |
| int renderReferenceY = 0; |
| |
| if (trapList.getP1YLeft(0) < trapList.getP2YLeft(0)) { |
| renderReferenceX = trapList.getP1XLeft(0); |
| renderReferenceY = trapList.getP1YLeft(0); |
| } else { |
| renderReferenceX = trapList.getP2XLeft(0); |
| renderReferenceY = trapList.getP2YLeft(0); |
| } |
| |
| renderReferenceX = (int) Math.floor(XRUtils |
| .XFixedToDouble(renderReferenceX)); |
| renderReferenceY = (int) Math.floor(XRUtils |
| .XFixedToDouble(renderReferenceY)); |
| |
| con.renderCompositeTrapezoids(compRule, getCurrentSource().picture, |
| XRUtils.PictStandardA8, dst, renderReferenceX, |
| renderReferenceY, trapList); |
| } |
| |
| public void XRRenderRectangles(XRSurfaceData dst, GrowableRectArray rects) { |
| if (xorEnabled) { |
| con.GCRectangles(dst.getXid(), dst.getGC(), rects); |
| } else { |
| if (rects.getSize() == 1) { |
| con.renderRectangle(dst.getPicture(), compRule, solidColor, |
| rects.getX(0), rects.getY(0), rects.getWidth(0), rects.getHeight(0)); |
| } else { |
| con.renderRectangles(dst.getPicture(), compRule, solidColor, rects); |
| } |
| } |
| } |
| |
| public void XRCompositeRectangles(XRSurfaceData dst, GrowableRectArray rects) { |
| int srcPict = getCurrentSource().picture; |
| |
| for(int i=0; i < rects.getSize(); i++) { |
| int x = rects.getX(i); |
| int y = rects.getY(i); |
| int width = rects.getWidth(i); |
| int height = rects.getHeight(i); |
| |
| con.renderComposite(compRule, srcPict, XRUtils.None, dst.picture, x, y, 0, 0, x, y, width, height); |
| } |
| } |
| |
| protected XRSurfaceData getCurrentSource() { |
| switch(srcType) { |
| case SOLID: |
| return solidSrc32.prepareSrcPict(validatedPixel); |
| case TEXTURE: |
| return texture; |
| case GRADIENT: |
| return gradient; |
| } |
| |
| return null; |
| } |
| |
| public void compositeBlit(XRSurfaceData src, XRSurfaceData dst, int sx, |
| int sy, int dx, int dy, int w, int h) { |
| con.renderComposite(compRule, src.picture, alphaMask, dst.picture, sx, |
| sy, 0, 0, dx, dy, w, h); |
| } |
| |
| public void compositeText(XRSurfaceData dst, int sx, int sy, int glyphSet, |
| int maskFormat, GrowableEltArray elts) { |
| /* |
| * Try to emulate the SRC blend mode with SRC_OVER. |
| * We bail out during pipe validation for cases where this is not possible. |
| */ |
| byte textCompRule = (compRule != XRUtils.PictOpSrc) ? compRule : XRUtils.PictOpOver; |
| con.XRenderCompositeText(textCompRule, getCurrentSource().picture, dst.picture, |
| maskFormat, sx, sy, 0, 0, glyphSet, elts); |
| } |
| |
| public XRColor getMaskColor() { |
| return !isTexturePaintActive() ? XRColor.FULL_ALPHA : getAlphaColor(); |
| } |
| |
| public int getExtraAlphaMask() { |
| return alphaMask; |
| } |
| |
| public boolean isTexturePaintActive() { |
| return srcType == TEXTURE; |
| } |
| |
| public boolean isSolidPaintActive() { |
| return srcType == SOLID; |
| } |
| |
| public XRColor getAlphaColor() { |
| return alphaColor; |
| } |
| |
| public XRBackend getBackend() { |
| return con; |
| } |
| |
| public float getExtraAlpha() { |
| return validatedExtraAlpha; |
| } |
| |
| public byte getCompRule() { |
| return compRule; |
| } |
| |
| public XRTextRenderer getTextRenderer() { |
| return textRenderer; |
| } |
| |
| public MaskTileManager getMaskBuffer() { |
| return maskBuffer; |
| } |
| |
| public XRMaskImage getMaskImage() { |
| return maskImage; |
| } |
| } |