diff options
Diffstat (limited to 'src/solaris/classes/sun/java2d/xr/MaskTileManager.java')
-rw-r--r-- | src/solaris/classes/sun/java2d/xr/MaskTileManager.java | 327 |
1 files changed, 327 insertions, 0 deletions
diff --git a/src/solaris/classes/sun/java2d/xr/MaskTileManager.java b/src/solaris/classes/sun/java2d/xr/MaskTileManager.java new file mode 100644 index 000000000..535e648f4 --- /dev/null +++ b/src/solaris/classes/sun/java2d/xr/MaskTileManager.java @@ -0,0 +1,327 @@ +/* + * Copyright 2010 Sun Microsystems, Inc. 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. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package sun.java2d.xr; + +import java.awt.*; +import java.util.*; + +/** + * We render non-antialiased geometry (consisting of rectangles) into a mask, + * which is later used in a composition step. + * To avoid mask-allocations of large size, MaskTileManager splits + * geometry larger than MASK_SIZE into several tiles, + * and stores the geometry in instances of MaskTile. + * + * @author Clemens Eisserer + */ + +public class MaskTileManager { + + public static final int MASK_SIZE = 256; + + MaskTile mainTile = new MaskTile(); + + ArrayList<MaskTile> tileList; + int allocatedTiles = 0; + int xTiles, yTiles; + + XRCompositeManager xrMgr; + XRBackend con; + + int maskPixmap; + int maskPicture; + long maskGC; + int lineMaskPixmap; + int lineMaskPicture; + long drawLineGC; + long clearLineGC; + + public MaskTileManager(XRCompositeManager xrMgr, int parentXid) { + tileList = new ArrayList<MaskTile>(); + this.xrMgr = xrMgr; + this.con = xrMgr.getBackend(); + + maskPixmap = con.createPixmap(parentXid, 8, MASK_SIZE, MASK_SIZE); + maskPicture = con.createPicture(maskPixmap, XRUtils.PictStandardA8); + con.renderRectangle(maskPicture, XRUtils.PictOpClear, + new XRColor(Color.black), + 0, 0, MASK_SIZE, MASK_SIZE); + maskGC = con.createGC(maskPixmap); + con.setGCExposures(maskGC, false); + + lineMaskPixmap = con.createPixmap(parentXid, 8, MASK_SIZE, MASK_SIZE); + lineMaskPicture = + con.createPicture(lineMaskPixmap, XRUtils.PictStandardA8); + con.renderRectangle(lineMaskPicture, XRUtils.PictOpClear, + new XRColor(Color.black), 0, 0, MASK_SIZE, MASK_SIZE); + + drawLineGC = con.createGC(lineMaskPixmap); + con.setGCExposures(drawLineGC, false); + con.setGCForeground(drawLineGC, 255); + + clearLineGC = con.createGC(lineMaskPixmap); + con.setGCExposures(clearLineGC, false); + con.setGCForeground(clearLineGC, 0); + } + + /** + * Adds a rectangle to the mask. + */ + public void addRect(int x, int y, int width, int height) { + mainTile.addRect(x, y, width, height); + } + + /** + * Adds a line to the mask. + */ + public void addLine(int x1, int y1, int x2, int y2) { + mainTile.addLine(x1, y1, x2, y2); + } + + /** + * Transfers the geometry stored (rectangles, lines) to one or more masks, + * and renders the result to the destination surface. + */ + public void fillMask(XRSurfaceData dst) { + + boolean maskRequired = xrMgr.maskRequired(); + + if (maskRequired) { + mainTile.calculateDirtyAreas(); + DirtyRegion dirtyArea = mainTile.getDirtyArea().cloneRegion(); + mainTile.translate(-dirtyArea.x, -dirtyArea.y); + + XRColor maskColor = xrMgr.getMaskColor(); + + // We don't need tiling if all geometry fits in a single tile + if (dirtyArea.getWidth() <= MASK_SIZE && + dirtyArea.getHeight() <= MASK_SIZE) + { + compositeSingleTile(dst, mainTile, dirtyArea, + maskRequired, 0, 0, maskColor); + } else { + allocTiles(dirtyArea); + tileRects(); + + for (int i = 0; i < yTiles; i++) { + for (int m = 0; m < xTiles; m++) { + MaskTile tile = tileList.get(i * xTiles + m); + + int tileStartX = m * MASK_SIZE; + int tileStartY = i * MASK_SIZE; + compositeSingleTile(dst, tile, dirtyArea, maskRequired, + tileStartX, tileStartY, maskColor); + } + } + } + } else { + xrMgr.XRRenderRectangles(dst, mainTile.getRects()); + } + + mainTile.reset(); + } + + /** + * Uploads aa geometry generated for maskblit/fill into the mask pixmap. + */ + public int uploadMask(int w, int h, int maskscan, int maskoff, byte[] mask) { + int maskPic = XRUtils.None; + + if (mask != null) { + float maskAlpha = + xrMgr.isTexturePaintActive() ? xrMgr.getExtraAlpha() : 1.0f; + con.putMaskImage(maskPixmap, maskGC, mask, 0, 0, 0, 0, + w, h, maskoff, maskscan, maskAlpha); + maskPic = maskPicture; + } else if (xrMgr.isTexturePaintActive()) { + maskPic = xrMgr.getExtraAlphaMask(); + } + + return maskPic; + } + + /** + * Clears the area of the mask-pixmap used for uploading aa coverage values. + */ + public void clearUploadMask(int mask, int w, int h) { + if (mask == maskPicture) { + con.renderRectangle(maskPicture, XRUtils.PictOpClear, + XRColor.NO_ALPHA, 0, 0, w, h); + } + } + + + /** + * Renders the rectangles provided to the mask, and does a composition + * operation with the properties set inXRCompositeManager. + */ + protected void compositeSingleTile(XRSurfaceData dst, MaskTile tile, + DirtyRegion dirtyArea, + boolean maskRequired, + int tileStartX, int tileStartY, + XRColor maskColor) { + if (tile.rects.getSize() > 0) { + DirtyRegion tileDirtyArea = tile.getDirtyArea(); + + int x = tileDirtyArea.x + tileStartX + dirtyArea.x; + int y = tileDirtyArea.y + tileStartY + dirtyArea.y; + int width = tileDirtyArea.x2 - tileDirtyArea.x; + int height = tileDirtyArea.y2 - tileDirtyArea.y; + width = Math.min(width, MASK_SIZE); + height = Math.min(height, MASK_SIZE); + + int rectCnt = tile.rects.getSize(); + + if (maskRequired) { + int mask = XRUtils.None; + + /* + * Optimization: When the tile only contains one rectangle, the + * composite-operation boundaries can be used as geometry + */ + if (rectCnt > 1) { + con.renderRectangles(maskPicture, XRUtils.PictOpSrc, + maskColor, tile.rects); + mask = maskPicture; + } else { + if (xrMgr.isTexturePaintActive()) { + mask = xrMgr.getExtraAlphaMask(); + } + } + + xrMgr.XRComposite(XRUtils.None, mask, dst.getPicture(), + x, y, tileDirtyArea.x, tileDirtyArea.y, + x, y, width, height); + + /* Clear dirty rectangle of the rect-mask */ + if (rectCnt > 1) { + con.renderRectangle(maskPicture, XRUtils.PictOpClear, + XRColor.NO_ALPHA, + tileDirtyArea.x, tileDirtyArea.y, + width, height); + } + + tile.reset(); + } else if (rectCnt > 0) { + tile.rects.translateRects(tileStartX + dirtyArea.x, + tileStartY + dirtyArea.y); + xrMgr.XRRenderRectangles(dst, tile.rects); + } + } + } + + + /** + * Allocates enough MaskTile instances, to cover the whole + * mask area, or resets existing ones. + */ + protected void allocTiles(DirtyRegion maskArea) { + xTiles = (maskArea.getWidth() / MASK_SIZE) + 1; + yTiles = (maskArea.getHeight() / MASK_SIZE) + 1; + int tileCnt = xTiles * yTiles; + + if (tileCnt > allocatedTiles) { + for (int i = 0; i < tileCnt; i++) { + if (i < allocatedTiles) { + tileList.get(i).reset(); + } else { + tileList.add(new MaskTile()); + } + } + + allocatedTiles = tileCnt; + } + } + + /** + * Tiles the stored rectangles, if they are larger than the MASK_SIZE + */ + protected void tileRects() { + GrowableRectArray rects = mainTile.rects; + + for (int i = 0; i < rects.getSize(); i++) { + int tileXStartIndex = rects.getX(i) / MASK_SIZE; + int tileYStartIndex = rects.getY(i) / MASK_SIZE; + int tileXLength = + ((rects.getX(i) + rects.getWidth(i)) / MASK_SIZE + 1) - + tileXStartIndex; + int tileYLength = + ((rects.getY(i) + rects.getHeight(i)) / MASK_SIZE + 1) - + tileYStartIndex; + + for (int n = 0; n < tileYLength; n++) { + for (int m = 0; m < tileXLength; m++) { + + int tileIndex = + xTiles * (tileYStartIndex + n) + tileXStartIndex + m; + MaskTile tile = tileList.get(tileIndex); + + GrowableRectArray rectTileList = tile.getRects(); + int tileArrayIndex = rectTileList.getNextIndex(); + + int tileStartPosX = (tileXStartIndex + m) * MASK_SIZE; + int tileStartPosY = (tileYStartIndex + n) * MASK_SIZE; + + rectTileList.setX(tileArrayIndex, rects.getX(i) - tileStartPosX); + rectTileList.setY(tileArrayIndex, rects.getY(i) - tileStartPosY); + rectTileList.setWidth(tileArrayIndex, rects.getWidth(i)); + rectTileList.setHeight(tileArrayIndex, rects.getHeight(i)); + + limitRectCoords(rectTileList, tileArrayIndex); + + tile.getDirtyArea().growDirtyRegion + (rectTileList.getX(tileArrayIndex), + rectTileList.getY(tileArrayIndex), + rectTileList.getWidth(tileArrayIndex) + + rectTileList.getX(tileArrayIndex), + rectTileList.getHeight(tileArrayIndex) + + rectTileList.getY(tileArrayIndex)); + } + } + } + } + + /** + * Limits the rect's coordinates to the mask coordinates. The result is used + * by growDirtyRegion. + */ + private void limitRectCoords(GrowableRectArray rects, int index) { + if ((rects.getX(index) + rects.getWidth(index)) > MASK_SIZE) { + rects.setWidth(index, MASK_SIZE - rects.getX(index)); + } + if ((rects.getY(index) + rects.getHeight(index)) > MASK_SIZE) { + rects.setHeight(index, MASK_SIZE - rects.getY(index)); + } + if (rects.getX(index) < 0) { + rects.setWidth(index, rects.getWidth(index) + rects.getX(index)); + rects.setX(index, 0); + } + if (rects.getY(index) < 0) { + rects.setHeight(index, rects.getHeight(index) + rects.getY(index)); + rects.setY(index, 0); + } + } +} |