aboutsummaryrefslogtreecommitdiff
path: root/src/solaris/classes/sun/java2d/xr/MaskTileManager.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/solaris/classes/sun/java2d/xr/MaskTileManager.java')
-rw-r--r--src/solaris/classes/sun/java2d/xr/MaskTileManager.java327
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);
+ }
+ }
+}