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