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.util.*; 30 31 /** 32 * We render non-antialiased geometry (consisting of rectangles) into a mask, 33 * which is later used in a composition step. 34 * To avoid mask-allocations of large size, MaskTileManager splits 35 * geometry larger than MASK_SIZE into several tiles, 36 * and stores the geometry in instances of MaskTile. 37 * 38 * @author Clemens Eisserer 39 */ 40 41 public class MaskTileManager { 42 43 public static final int MASK_SIZE = 256; 44 45 MaskTile mainTile = new MaskTile(); 46 47 ArrayList<MaskTile> tileList; 48 int allocatedTiles = 0; 49 int xTiles, yTiles; 50 51 XRCompositeManager xrMgr; 52 XRBackend con; 53 54 int maskPixmap; 55 int maskPicture; 56 long maskGC; 57 58 public MaskTileManager(XRCompositeManager xrMgr, int parentXid) { 59 tileList = new ArrayList<MaskTile>(); 60 this.xrMgr = xrMgr; 61 this.con = xrMgr.getBackend(); 62 63 maskPixmap = con.createPixmap(parentXid, 8, MASK_SIZE, MASK_SIZE); 64 maskPicture = con.createPicture(maskPixmap, XRUtils.PictStandardA8); 65 con.renderRectangle(maskPicture, XRUtils.PictOpClear, 66 new XRColor(Color.black), 67 0, 0, MASK_SIZE, MASK_SIZE); 68 maskGC = con.createGC(maskPixmap); 69 con.setGCExposures(maskGC, false); 70 } 71 72 /** 73 * Transfers the geometry stored (rectangles, lines) to one or more masks, 74 * and renders the result to the destination surface. 75 */ 76 public void fillMask(XRSurfaceData dst) { 77 78 boolean maskRequired = xrMgr.maskRequired(); 79 boolean maskEvaluated = XRUtils.isMaskEvaluated(xrMgr.compRule); 80 81 if (maskRequired && maskEvaluated) { 82 mainTile.calculateDirtyAreas(); 83 DirtyRegion dirtyArea = mainTile.getDirtyArea().cloneRegion(); 84 mainTile.translate(-dirtyArea.x, -dirtyArea.y); 85 86 XRColor maskColor = xrMgr.getMaskColor(); 87 88 // We don't need tiling if all geometry fits in a single tile 89 if (dirtyArea.getWidth() <= MASK_SIZE && 90 dirtyArea.getHeight() <= MASK_SIZE) 91 { 92 compositeSingleTile(dst, mainTile, dirtyArea, 93 maskRequired, 0, 0, maskColor); 94 } else { 95 allocTiles(dirtyArea); 96 tileRects(); 97 98 for (int i = 0; i < yTiles; i++) { 99 for (int m = 0; m < xTiles; m++) { 100 MaskTile tile = tileList.get(i * xTiles + m); 101 102 int tileStartX = m * MASK_SIZE; 103 int tileStartY = i * MASK_SIZE; 104 compositeSingleTile(dst, tile, dirtyArea, maskRequired, 105 tileStartX, tileStartY, maskColor); 106 } 107 } 108 } 109 } else { 110 /* 111 * If a mask would be required to store geometry (maskRequired) 112 * composition has to be done rectangle-by-rectagle. 113 */ 114 if(xrMgr.isSolidPaintActive()) { 115 xrMgr.XRRenderRectangles(dst, mainTile.getRects()); 116 } else { 117 xrMgr.XRCompositeRectangles(dst, mainTile.getRects()); 118 } 119 } 120 121 mainTile.reset(); 122 } 123 124 /** 125 * Uploads aa geometry generated for maskblit/fill into the mask pixmap. 126 */ 127 public int uploadMask(int w, int h, int maskscan, int maskoff, byte[] mask) { 128 int maskPic = XRUtils.None; 129 130 if (mask != null) { 131 float maskAlpha = 132 xrMgr.isTexturePaintActive() ? xrMgr.getExtraAlpha() : 1.0f; 133 con.putMaskImage(maskPixmap, maskGC, mask, 0, 0, 0, 0, 134 w, h, maskoff, maskscan, maskAlpha); 135 maskPic = maskPicture; 136 } else if (xrMgr.isTexturePaintActive()) { 137 maskPic = xrMgr.getExtraAlphaMask(); 138 } 139 140 return maskPic; 141 } 142 143 /** 144 * Clears the area of the mask-pixmap used for uploading aa coverage values. 145 */ 146 public void clearUploadMask(int mask, int w, int h) { 147 if (mask == maskPicture) { 148 con.renderRectangle(maskPicture, XRUtils.PictOpClear, 149 XRColor.NO_ALPHA, 0, 0, w, h); 150 } 151 } 152 153 154 /** 155 * Renders the rectangles provided to the mask, and does a composition 156 * operation with the properties set inXRCompositeManager. 157 */ 158 protected void compositeSingleTile(XRSurfaceData dst, MaskTile tile, 159 DirtyRegion dirtyArea, 160 boolean maskRequired, 161 int tileStartX, int tileStartY, 162 XRColor maskColor) { 163 if (tile.rects.getSize() > 0) { 164 DirtyRegion tileDirtyArea = tile.getDirtyArea(); 165 166 int x = tileDirtyArea.x + tileStartX + dirtyArea.x; 167 int y = tileDirtyArea.y + tileStartY + dirtyArea.y; 168 int width = tileDirtyArea.x2 - tileDirtyArea.x; 169 int height = tileDirtyArea.y2 - tileDirtyArea.y; 170 width = Math.min(width, MASK_SIZE); 171 height = Math.min(height, MASK_SIZE); 172 173 int rectCnt = tile.rects.getSize(); 174 175 if (maskRequired) { 176 int mask = XRUtils.None; 177 178 /* 179 * Optimization: When the tile only contains one rectangle, the 180 * composite-operation boundaries can be used as geometry 181 */ 182 if (rectCnt > 1) { 183 con.renderRectangles(maskPicture, XRUtils.PictOpSrc, 184 maskColor, tile.rects); 185 mask = maskPicture; 186 } else { 187 if (xrMgr.isTexturePaintActive()) { 188 mask = xrMgr.getExtraAlphaMask(); 189 } 190 } 191 192 xrMgr.XRComposite(XRUtils.None, mask, dst.getPicture(), 193 x, y, tileDirtyArea.x, tileDirtyArea.y, 194 x, y, width, height); 195 196 /* Clear dirty rectangle of the rect-mask */ 197 if (rectCnt > 1) { 198 con.renderRectangle(maskPicture, XRUtils.PictOpClear, 199 XRColor.NO_ALPHA, 200 tileDirtyArea.x, tileDirtyArea.y, 201 width, height); 202 } 203 204 tile.reset(); 205 } else if (rectCnt > 0) { 206 tile.rects.translateRects(tileStartX + dirtyArea.x, 207 tileStartY + dirtyArea.y); 208 xrMgr.XRRenderRectangles(dst, tile.rects); 209 } 210 } 211 } 212 213 214 /** 215 * Allocates enough MaskTile instances, to cover the whole 216 * mask area, or resets existing ones. 217 */ 218 protected void allocTiles(DirtyRegion maskArea) { 219 xTiles = (maskArea.getWidth() / MASK_SIZE) + 1; 220 yTiles = (maskArea.getHeight() / MASK_SIZE) + 1; 221 int tileCnt = xTiles * yTiles; 222 223 if (tileCnt > allocatedTiles) { 224 for (int i = 0; i < tileCnt; i++) { 225 if (i < allocatedTiles) { 226 tileList.get(i).reset(); 227 } else { 228 tileList.add(new MaskTile()); 229 } 230 } 231 232 allocatedTiles = tileCnt; 233 } 234 } 235 236 /** 237 * Tiles the stored rectangles, if they are larger than the MASK_SIZE 238 */ 239 protected void tileRects() { 240 GrowableRectArray rects = mainTile.rects; 241 242 for (int i = 0; i < rects.getSize(); i++) { 243 int tileXStartIndex = rects.getX(i) / MASK_SIZE; 244 int tileYStartIndex = rects.getY(i) / MASK_SIZE; 245 int tileXLength = 246 ((rects.getX(i) + rects.getWidth(i)) / MASK_SIZE + 1) - 247 tileXStartIndex; 248 int tileYLength = 249 ((rects.getY(i) + rects.getHeight(i)) / MASK_SIZE + 1) - 250 tileYStartIndex; 251 252 for (int n = 0; n < tileYLength; n++) { 253 for (int m = 0; m < tileXLength; m++) { 254 255 int tileIndex = 256 xTiles * (tileYStartIndex + n) + tileXStartIndex + m; 257 MaskTile tile = tileList.get(tileIndex); 258 259 GrowableRectArray rectTileList = tile.getRects(); 260 int tileArrayIndex = rectTileList.getNextIndex(); 261 262 int tileStartPosX = (tileXStartIndex + m) * MASK_SIZE; 263 int tileStartPosY = (tileYStartIndex + n) * MASK_SIZE; 264 265 rectTileList.setX(tileArrayIndex, rects.getX(i) - tileStartPosX); 266 rectTileList.setY(tileArrayIndex, rects.getY(i) - tileStartPosY); 267 rectTileList.setWidth(tileArrayIndex, rects.getWidth(i)); 268 rectTileList.setHeight(tileArrayIndex, rects.getHeight(i)); 269 270 limitRectCoords(rectTileList, tileArrayIndex); 271 272 tile.getDirtyArea().growDirtyRegion 273 (rectTileList.getX(tileArrayIndex), 274 rectTileList.getY(tileArrayIndex), 275 rectTileList.getWidth(tileArrayIndex) + 276 rectTileList.getX(tileArrayIndex), 277 rectTileList.getHeight(tileArrayIndex) + 278 rectTileList.getY(tileArrayIndex)); 279 } 280 } 281 } 282 } 283 284 /** 285 * Limits the rect's coordinates to the mask coordinates. The result is used 286 * by growDirtyRegion. 287 */ 288 private void limitRectCoords(GrowableRectArray rects, int index) { 289 if ((rects.getX(index) + rects.getWidth(index)) > MASK_SIZE) { 290 rects.setWidth(index, MASK_SIZE - rects.getX(index)); 291 } 292 if ((rects.getY(index) + rects.getHeight(index)) > MASK_SIZE) { 293 rects.setHeight(index, MASK_SIZE - rects.getY(index)); 294 } 295 if (rects.getX(index) < 0) { 296 rects.setWidth(index, rects.getWidth(index) + rects.getX(index)); 297 rects.setX(index, 0); 298 } 299 if (rects.getY(index) < 0) { 300 rects.setHeight(index, rects.getHeight(index) + rects.getY(index)); 301 rects.setY(index, 0); 302 } 303 } 304 305 /** 306 * @return MainTile to which rectangles are added before composition. 307 */ 308 public MaskTile getMainTile() { 309 return mainTile; 310 } 311 }