1 /* 2 * Copyright (c) 2010, 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 80 if (maskRequired) { 81 mainTile.calculateDirtyAreas(); 82 DirtyRegion dirtyArea = mainTile.getDirtyArea().cloneRegion(); 83 mainTile.translate(-dirtyArea.x, -dirtyArea.y); 84 85 XRColor maskColor = xrMgr.getMaskColor(); 86 87 // We don't need tiling if all geometry fits in a single tile 88 if (dirtyArea.getWidth() <= MASK_SIZE && 89 dirtyArea.getHeight() <= MASK_SIZE) 90 { 91 compositeSingleTile(dst, mainTile, dirtyArea, 92 maskRequired, 0, 0, maskColor); 93 } else { 94 allocTiles(dirtyArea); 95 tileRects(); 96 97 for (int i = 0; i < yTiles; i++) { 98 for (int m = 0; m < xTiles; m++) { 99 MaskTile tile = tileList.get(i * xTiles + m); 100 101 int tileStartX = m * MASK_SIZE; 102 int tileStartY = i * MASK_SIZE; 103 compositeSingleTile(dst, tile, dirtyArea, maskRequired, 104 tileStartX, tileStartY, maskColor); 105 } 106 } 107 } 108 } else { 109 xrMgr.XRRenderRectangles(dst, mainTile.getRects()); 110 } 111 112 mainTile.reset(); 113 } 114 115 /** 116 * Uploads aa geometry generated for maskblit/fill into the mask pixmap. 117 */ 118 public int uploadMask(int w, int h, int maskscan, int maskoff, byte[] mask) { 119 int maskPic = XRUtils.None; 120 121 if (mask != null) { 122 float maskAlpha = 123 xrMgr.isTexturePaintActive() ? xrMgr.getExtraAlpha() : 1.0f; 124 con.putMaskImage(maskPixmap, maskGC, mask, 0, 0, 0, 0, 125 w, h, maskoff, maskscan, maskAlpha); 126 maskPic = maskPicture; 127 } else if (xrMgr.isTexturePaintActive()) { 128 maskPic = xrMgr.getExtraAlphaMask(); 129 } 130 131 return maskPic; 132 } 133 134 /** 135 * Clears the area of the mask-pixmap used for uploading aa coverage values. 136 */ 137 public void clearUploadMask(int mask, int w, int h) { 138 if (mask == maskPicture) { 139 con.renderRectangle(maskPicture, XRUtils.PictOpClear, 140 XRColor.NO_ALPHA, 0, 0, w, h); 141 } 142 } 143 144 145 /** 146 * Renders the rectangles provided to the mask, and does a composition 147 * operation with the properties set inXRCompositeManager. 148 */ 149 protected void compositeSingleTile(XRSurfaceData dst, MaskTile tile, 150 DirtyRegion dirtyArea, 151 boolean maskRequired, 152 int tileStartX, int tileStartY, 153 XRColor maskColor) { 154 if (tile.rects.getSize() > 0) { 155 DirtyRegion tileDirtyArea = tile.getDirtyArea(); 156 157 int x = tileDirtyArea.x + tileStartX + dirtyArea.x; 158 int y = tileDirtyArea.y + tileStartY + dirtyArea.y; 159 int width = tileDirtyArea.x2 - tileDirtyArea.x; 160 int height = tileDirtyArea.y2 - tileDirtyArea.y; 161 width = Math.min(width, MASK_SIZE); 162 height = Math.min(height, MASK_SIZE); 163 164 int rectCnt = tile.rects.getSize(); 165 166 if (maskRequired) { 167 int mask = XRUtils.None; 168 169 /* 170 * Optimization: When the tile only contains one rectangle, the 171 * composite-operation boundaries can be used as geometry 172 */ 173 if (rectCnt > 1) { 174 con.renderRectangles(maskPicture, XRUtils.PictOpSrc, 175 maskColor, tile.rects); 176 mask = maskPicture; 177 } else { 178 if (xrMgr.isTexturePaintActive()) { 179 mask = xrMgr.getExtraAlphaMask(); 180 } 181 } 182 183 xrMgr.XRComposite(XRUtils.None, mask, dst.getPicture(), 184 x, y, tileDirtyArea.x, tileDirtyArea.y, 185 x, y, width, height); 186 187 /* Clear dirty rectangle of the rect-mask */ 188 if (rectCnt > 1) { 189 con.renderRectangle(maskPicture, XRUtils.PictOpClear, 190 XRColor.NO_ALPHA, 191 tileDirtyArea.x, tileDirtyArea.y, 192 width, height); 193 } 194 195 tile.reset(); 196 } else if (rectCnt > 0) { 197 tile.rects.translateRects(tileStartX + dirtyArea.x, 198 tileStartY + dirtyArea.y); 199 xrMgr.XRRenderRectangles(dst, tile.rects); 200 } 201 } 202 } 203 204 205 /** 206 * Allocates enough MaskTile instances, to cover the whole 207 * mask area, or resets existing ones. 208 */ 209 protected void allocTiles(DirtyRegion maskArea) { 210 xTiles = (maskArea.getWidth() / MASK_SIZE) + 1; 211 yTiles = (maskArea.getHeight() / MASK_SIZE) + 1; 212 int tileCnt = xTiles * yTiles; 213 214 if (tileCnt > allocatedTiles) { 215 for (int i = 0; i < tileCnt; i++) { 216 if (i < allocatedTiles) { 217 tileList.get(i).reset(); 218 } else { 219 tileList.add(new MaskTile()); 220 } 221 } 222 223 allocatedTiles = tileCnt; 224 } 225 } 226 227 /** 228 * Tiles the stored rectangles, if they are larger than the MASK_SIZE 229 */ 230 protected void tileRects() { 231 GrowableRectArray rects = mainTile.rects; 232 233 for (int i = 0; i < rects.getSize(); i++) { 234 int tileXStartIndex = rects.getX(i) / MASK_SIZE; 235 int tileYStartIndex = rects.getY(i) / MASK_SIZE; 236 int tileXLength = 237 ((rects.getX(i) + rects.getWidth(i)) / MASK_SIZE + 1) - 238 tileXStartIndex; 239 int tileYLength = 240 ((rects.getY(i) + rects.getHeight(i)) / MASK_SIZE + 1) - 241 tileYStartIndex; 242 243 for (int n = 0; n < tileYLength; n++) { 244 for (int m = 0; m < tileXLength; m++) { 245 246 int tileIndex = 247 xTiles * (tileYStartIndex + n) + tileXStartIndex + m; 248 MaskTile tile = tileList.get(tileIndex); 249 250 GrowableRectArray rectTileList = tile.getRects(); 251 int tileArrayIndex = rectTileList.getNextIndex(); 252 253 int tileStartPosX = (tileXStartIndex + m) * MASK_SIZE; 254 int tileStartPosY = (tileYStartIndex + n) * MASK_SIZE; 255 256 rectTileList.setX(tileArrayIndex, rects.getX(i) - tileStartPosX); 257 rectTileList.setY(tileArrayIndex, rects.getY(i) - tileStartPosY); 258 rectTileList.setWidth(tileArrayIndex, rects.getWidth(i)); 259 rectTileList.setHeight(tileArrayIndex, rects.getHeight(i)); 260 261 limitRectCoords(rectTileList, tileArrayIndex); 262 263 tile.getDirtyArea().growDirtyRegion 264 (rectTileList.getX(tileArrayIndex), 265 rectTileList.getY(tileArrayIndex), 266 rectTileList.getWidth(tileArrayIndex) + 267 rectTileList.getX(tileArrayIndex), 268 rectTileList.getHeight(tileArrayIndex) + 269 rectTileList.getY(tileArrayIndex)); 270 } 271 } 272 } 273 } 274 275 /** 276 * Limits the rect's coordinates to the mask coordinates. The result is used 277 * by growDirtyRegion. 278 */ 279 private void limitRectCoords(GrowableRectArray rects, int index) { 280 if ((rects.getX(index) + rects.getWidth(index)) > MASK_SIZE) { 281 rects.setWidth(index, MASK_SIZE - rects.getX(index)); 282 } 283 if ((rects.getY(index) + rects.getHeight(index)) > MASK_SIZE) { 284 rects.setHeight(index, MASK_SIZE - rects.getY(index)); 285 } 286 if (rects.getX(index) < 0) { 287 rects.setWidth(index, rects.getWidth(index) + rects.getX(index)); 288 rects.setX(index, 0); 289 } 290 if (rects.getY(index) < 0) { 291 rects.setHeight(index, rects.getHeight(index) + rects.getY(index)); 292 rects.setY(index, 0); 293 } 294 } 295 296 /** 297 * @return MainTile to which rectangles are added before composition. 298 */ 299 public MaskTile getMainTile() { 300 return mainTile; 301 } 302 }