2370N/A/*
2685N/A * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
2370N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
2370N/A *
2370N/A * This code is free software; you can redistribute it and/or modify it
2370N/A * under the terms of the GNU General Public License version 2 only, as
2685N/A * published by the Free Software Foundation. Oracle designates this
2370N/A * particular file as subject to the "Classpath" exception as provided
2685N/A * by Oracle in the LICENSE file that accompanied this code.
2370N/A *
2370N/A * This code is distributed in the hope that it will be useful, but WITHOUT
2370N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
2370N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
2370N/A * version 2 for more details (a copy is included in the LICENSE file that
2370N/A * accompanied this code).
2370N/A *
2370N/A * You should have received a copy of the GNU General Public License version
2370N/A * 2 along with this work; if not, write to the Free Software Foundation,
2370N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
2370N/A *
2685N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
2685N/A * or visit www.oracle.com if you need additional information or have any
2685N/A * questions.
2370N/A */
2370N/A
2370N/Apackage sun.java2d.xr;
2370N/A
2370N/Aimport java.awt.*;
2370N/Aimport java.util.*;
2370N/A
2370N/A/**
2370N/A * We render non-antialiased geometry (consisting of rectangles) into a mask,
2370N/A * which is later used in a composition step.
2370N/A * To avoid mask-allocations of large size, MaskTileManager splits
2370N/A * geometry larger than MASK_SIZE into several tiles,
2370N/A * and stores the geometry in instances of MaskTile.
2370N/A *
2370N/A * @author Clemens Eisserer
2370N/A */
2370N/A
2370N/Apublic class MaskTileManager {
2370N/A
2370N/A public static final int MASK_SIZE = 256;
2370N/A
2370N/A MaskTile mainTile = new MaskTile();
2370N/A
2370N/A ArrayList<MaskTile> tileList;
2370N/A int allocatedTiles = 0;
2370N/A int xTiles, yTiles;
2370N/A
2370N/A XRCompositeManager xrMgr;
2370N/A XRBackend con;
2370N/A
2370N/A int maskPixmap;
2370N/A int maskPicture;
2370N/A long maskGC;
2370N/A int lineMaskPixmap;
2370N/A int lineMaskPicture;
2370N/A long drawLineGC;
2370N/A long clearLineGC;
2370N/A
2370N/A public MaskTileManager(XRCompositeManager xrMgr, int parentXid) {
2370N/A tileList = new ArrayList<MaskTile>();
2370N/A this.xrMgr = xrMgr;
2370N/A this.con = xrMgr.getBackend();
2370N/A
2370N/A maskPixmap = con.createPixmap(parentXid, 8, MASK_SIZE, MASK_SIZE);
2370N/A maskPicture = con.createPicture(maskPixmap, XRUtils.PictStandardA8);
2370N/A con.renderRectangle(maskPicture, XRUtils.PictOpClear,
2370N/A new XRColor(Color.black),
2370N/A 0, 0, MASK_SIZE, MASK_SIZE);
2370N/A maskGC = con.createGC(maskPixmap);
2370N/A con.setGCExposures(maskGC, false);
2370N/A
2370N/A lineMaskPixmap = con.createPixmap(parentXid, 8, MASK_SIZE, MASK_SIZE);
2370N/A lineMaskPicture =
2370N/A con.createPicture(lineMaskPixmap, XRUtils.PictStandardA8);
2370N/A con.renderRectangle(lineMaskPicture, XRUtils.PictOpClear,
2370N/A new XRColor(Color.black), 0, 0, MASK_SIZE, MASK_SIZE);
2370N/A
2370N/A drawLineGC = con.createGC(lineMaskPixmap);
2370N/A con.setGCExposures(drawLineGC, false);
2370N/A con.setGCForeground(drawLineGC, 255);
2370N/A
2370N/A clearLineGC = con.createGC(lineMaskPixmap);
2370N/A con.setGCExposures(clearLineGC, false);
2370N/A con.setGCForeground(clearLineGC, 0);
2370N/A }
2370N/A
2370N/A /**
2370N/A * Adds a rectangle to the mask.
2370N/A */
2370N/A public void addRect(int x, int y, int width, int height) {
2370N/A mainTile.addRect(x, y, width, height);
2370N/A }
2370N/A
2370N/A /**
2370N/A * Adds a line to the mask.
2370N/A */
2370N/A public void addLine(int x1, int y1, int x2, int y2) {
2370N/A mainTile.addLine(x1, y1, x2, y2);
2370N/A }
2370N/A
2370N/A /**
2370N/A * Transfers the geometry stored (rectangles, lines) to one or more masks,
2370N/A * and renders the result to the destination surface.
2370N/A */
2370N/A public void fillMask(XRSurfaceData dst) {
2370N/A
2370N/A boolean maskRequired = xrMgr.maskRequired();
2370N/A
2370N/A if (maskRequired) {
2370N/A mainTile.calculateDirtyAreas();
2370N/A DirtyRegion dirtyArea = mainTile.getDirtyArea().cloneRegion();
2370N/A mainTile.translate(-dirtyArea.x, -dirtyArea.y);
2370N/A
2370N/A XRColor maskColor = xrMgr.getMaskColor();
2370N/A
2370N/A // We don't need tiling if all geometry fits in a single tile
2370N/A if (dirtyArea.getWidth() <= MASK_SIZE &&
2370N/A dirtyArea.getHeight() <= MASK_SIZE)
2370N/A {
2370N/A compositeSingleTile(dst, mainTile, dirtyArea,
2370N/A maskRequired, 0, 0, maskColor);
2370N/A } else {
2370N/A allocTiles(dirtyArea);
2370N/A tileRects();
2370N/A
2370N/A for (int i = 0; i < yTiles; i++) {
2370N/A for (int m = 0; m < xTiles; m++) {
2370N/A MaskTile tile = tileList.get(i * xTiles + m);
2370N/A
2370N/A int tileStartX = m * MASK_SIZE;
2370N/A int tileStartY = i * MASK_SIZE;
2370N/A compositeSingleTile(dst, tile, dirtyArea, maskRequired,
2370N/A tileStartX, tileStartY, maskColor);
2370N/A }
2370N/A }
2370N/A }
2370N/A } else {
2370N/A xrMgr.XRRenderRectangles(dst, mainTile.getRects());
2370N/A }
2370N/A
2370N/A mainTile.reset();
2370N/A }
2370N/A
2370N/A /**
2370N/A * Uploads aa geometry generated for maskblit/fill into the mask pixmap.
2370N/A */
2370N/A public int uploadMask(int w, int h, int maskscan, int maskoff, byte[] mask) {
2370N/A int maskPic = XRUtils.None;
2370N/A
2370N/A if (mask != null) {
2370N/A float maskAlpha =
2370N/A xrMgr.isTexturePaintActive() ? xrMgr.getExtraAlpha() : 1.0f;
2370N/A con.putMaskImage(maskPixmap, maskGC, mask, 0, 0, 0, 0,
2370N/A w, h, maskoff, maskscan, maskAlpha);
2370N/A maskPic = maskPicture;
2370N/A } else if (xrMgr.isTexturePaintActive()) {
2370N/A maskPic = xrMgr.getExtraAlphaMask();
2370N/A }
2370N/A
2370N/A return maskPic;
2370N/A }
2370N/A
2370N/A /**
2370N/A * Clears the area of the mask-pixmap used for uploading aa coverage values.
2370N/A */
2370N/A public void clearUploadMask(int mask, int w, int h) {
2370N/A if (mask == maskPicture) {
2370N/A con.renderRectangle(maskPicture, XRUtils.PictOpClear,
2370N/A XRColor.NO_ALPHA, 0, 0, w, h);
2370N/A }
2370N/A }
2370N/A
2370N/A
2370N/A /**
2370N/A * Renders the rectangles provided to the mask, and does a composition
2370N/A * operation with the properties set inXRCompositeManager.
2370N/A */
2370N/A protected void compositeSingleTile(XRSurfaceData dst, MaskTile tile,
2370N/A DirtyRegion dirtyArea,
2370N/A boolean maskRequired,
2370N/A int tileStartX, int tileStartY,
2370N/A XRColor maskColor) {
2370N/A if (tile.rects.getSize() > 0) {
2370N/A DirtyRegion tileDirtyArea = tile.getDirtyArea();
2370N/A
2370N/A int x = tileDirtyArea.x + tileStartX + dirtyArea.x;
2370N/A int y = tileDirtyArea.y + tileStartY + dirtyArea.y;
2370N/A int width = tileDirtyArea.x2 - tileDirtyArea.x;
2370N/A int height = tileDirtyArea.y2 - tileDirtyArea.y;
2370N/A width = Math.min(width, MASK_SIZE);
2370N/A height = Math.min(height, MASK_SIZE);
2370N/A
2370N/A int rectCnt = tile.rects.getSize();
2370N/A
2370N/A if (maskRequired) {
2370N/A int mask = XRUtils.None;
2370N/A
2370N/A /*
2370N/A * Optimization: When the tile only contains one rectangle, the
2370N/A * composite-operation boundaries can be used as geometry
2370N/A */
2370N/A if (rectCnt > 1) {
2370N/A con.renderRectangles(maskPicture, XRUtils.PictOpSrc,
2370N/A maskColor, tile.rects);
2370N/A mask = maskPicture;
2370N/A } else {
2370N/A if (xrMgr.isTexturePaintActive()) {
2370N/A mask = xrMgr.getExtraAlphaMask();
2370N/A }
2370N/A }
2370N/A
2370N/A xrMgr.XRComposite(XRUtils.None, mask, dst.getPicture(),
2370N/A x, y, tileDirtyArea.x, tileDirtyArea.y,
2370N/A x, y, width, height);
2370N/A
2370N/A /* Clear dirty rectangle of the rect-mask */
2370N/A if (rectCnt > 1) {
2370N/A con.renderRectangle(maskPicture, XRUtils.PictOpClear,
2370N/A XRColor.NO_ALPHA,
2370N/A tileDirtyArea.x, tileDirtyArea.y,
2370N/A width, height);
2370N/A }
2370N/A
2370N/A tile.reset();
2370N/A } else if (rectCnt > 0) {
2370N/A tile.rects.translateRects(tileStartX + dirtyArea.x,
2370N/A tileStartY + dirtyArea.y);
2370N/A xrMgr.XRRenderRectangles(dst, tile.rects);
2370N/A }
2370N/A }
2370N/A }
2370N/A
2370N/A
2370N/A /**
2370N/A * Allocates enough MaskTile instances, to cover the whole
2370N/A * mask area, or resets existing ones.
2370N/A */
2370N/A protected void allocTiles(DirtyRegion maskArea) {
2370N/A xTiles = (maskArea.getWidth() / MASK_SIZE) + 1;
2370N/A yTiles = (maskArea.getHeight() / MASK_SIZE) + 1;
2370N/A int tileCnt = xTiles * yTiles;
2370N/A
2370N/A if (tileCnt > allocatedTiles) {
2370N/A for (int i = 0; i < tileCnt; i++) {
2370N/A if (i < allocatedTiles) {
2370N/A tileList.get(i).reset();
2370N/A } else {
2370N/A tileList.add(new MaskTile());
2370N/A }
2370N/A }
2370N/A
2370N/A allocatedTiles = tileCnt;
2370N/A }
2370N/A }
2370N/A
2370N/A /**
2370N/A * Tiles the stored rectangles, if they are larger than the MASK_SIZE
2370N/A */
2370N/A protected void tileRects() {
2370N/A GrowableRectArray rects = mainTile.rects;
2370N/A
2370N/A for (int i = 0; i < rects.getSize(); i++) {
2370N/A int tileXStartIndex = rects.getX(i) / MASK_SIZE;
2370N/A int tileYStartIndex = rects.getY(i) / MASK_SIZE;
2370N/A int tileXLength =
2370N/A ((rects.getX(i) + rects.getWidth(i)) / MASK_SIZE + 1) -
2370N/A tileXStartIndex;
2370N/A int tileYLength =
2370N/A ((rects.getY(i) + rects.getHeight(i)) / MASK_SIZE + 1) -
2370N/A tileYStartIndex;
2370N/A
2370N/A for (int n = 0; n < tileYLength; n++) {
2370N/A for (int m = 0; m < tileXLength; m++) {
2370N/A
2370N/A int tileIndex =
2370N/A xTiles * (tileYStartIndex + n) + tileXStartIndex + m;
2370N/A MaskTile tile = tileList.get(tileIndex);
2370N/A
2370N/A GrowableRectArray rectTileList = tile.getRects();
2370N/A int tileArrayIndex = rectTileList.getNextIndex();
2370N/A
2370N/A int tileStartPosX = (tileXStartIndex + m) * MASK_SIZE;
2370N/A int tileStartPosY = (tileYStartIndex + n) * MASK_SIZE;
2370N/A
2370N/A rectTileList.setX(tileArrayIndex, rects.getX(i) - tileStartPosX);
2370N/A rectTileList.setY(tileArrayIndex, rects.getY(i) - tileStartPosY);
2370N/A rectTileList.setWidth(tileArrayIndex, rects.getWidth(i));
2370N/A rectTileList.setHeight(tileArrayIndex, rects.getHeight(i));
2370N/A
2370N/A limitRectCoords(rectTileList, tileArrayIndex);
2370N/A
2370N/A tile.getDirtyArea().growDirtyRegion
2370N/A (rectTileList.getX(tileArrayIndex),
2370N/A rectTileList.getY(tileArrayIndex),
2370N/A rectTileList.getWidth(tileArrayIndex) +
2370N/A rectTileList.getX(tileArrayIndex),
2370N/A rectTileList.getHeight(tileArrayIndex) +
2370N/A rectTileList.getY(tileArrayIndex));
2370N/A }
2370N/A }
2370N/A }
2370N/A }
2370N/A
2370N/A /**
2370N/A * Limits the rect's coordinates to the mask coordinates. The result is used
2370N/A * by growDirtyRegion.
2370N/A */
2370N/A private void limitRectCoords(GrowableRectArray rects, int index) {
2370N/A if ((rects.getX(index) + rects.getWidth(index)) > MASK_SIZE) {
2370N/A rects.setWidth(index, MASK_SIZE - rects.getX(index));
2370N/A }
2370N/A if ((rects.getY(index) + rects.getHeight(index)) > MASK_SIZE) {
2370N/A rects.setHeight(index, MASK_SIZE - rects.getY(index));
2370N/A }
2370N/A if (rects.getX(index) < 0) {
2370N/A rects.setWidth(index, rects.getWidth(index) + rects.getX(index));
2370N/A rects.setX(index, 0);
2370N/A }
2370N/A if (rects.getY(index) < 0) {
2370N/A rects.setHeight(index, rects.getHeight(index) + rects.getY(index));
2370N/A rects.setY(index, 0);
2370N/A }
2370N/A }
2370N/A}