1 /* 2 * Copyright (c) 2010, 2018, 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, RectTileManager splits 35 * geometry larger than MASK_SIZE into several tiles, 36 * and stores the geometry in instances of RectTile. 37 * 38 * @author Clemens Eisserer 39 */ 40 41 public class RectTileManager { 42 43 public static final int MASK_SIZE = 256; 44 45 RectTile mainTile = new RectTile(); 46 47 ArrayList<RectTile> 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 RectTileManager(XRCompositeManager xrMgr, int parentXid) { 59 tileList = new ArrayList<RectTile>(); 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 RectTile 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 * Renders the rectangles provided to the mask, and does a composition 126 * operation with the properties set inXRCompositeManager. 127 */ 128 protected void compositeSingleTile(XRSurfaceData dst, RectTile tile, 129 DirtyRegion dirtyArea, 130 boolean maskRequired, 131 int tileStartX, int tileStartY, 132 XRColor maskColor) { 133 if (tile.rects.getSize() > 0) { 134 DirtyRegion tileDirtyArea = tile.getDirtyArea(); 135 136 int x = tileDirtyArea.x + tileStartX + dirtyArea.x; 137 int y = tileDirtyArea.y + tileStartY + dirtyArea.y; 138 int width = tileDirtyArea.x2 - tileDirtyArea.x; 139 int height = tileDirtyArea.y2 - tileDirtyArea.y; 140 width = Math.min(width, MASK_SIZE); 141 height = Math.min(height, MASK_SIZE); 142 143 int rectCnt = tile.rects.getSize(); 144 145 if (maskRequired) { 146 int mask = XRUtils.None; 147 148 /* 149 * Optimization: When the tile only contains one rectangle, the 150 * composite-operation boundaries can be used as geometry 151 */ 152 if (rectCnt > 1) { 153 con.renderRectangles(maskPicture, XRUtils.PictOpSrc, 154 maskColor, tile.rects); 155 mask = maskPicture; 156 } else { 157 if (xrMgr.isTexturePaintActive()) { 158 mask = xrMgr.getExtraAlphaMask(); 159 } 160 } 161 162 xrMgr.XRComposite(XRUtils.None, mask, dst.getPicture(), 163 x, y, tileDirtyArea.x, tileDirtyArea.y, 164 x, y, width, height); 165 166 /* Clear dirty rectangle of the rect-mask */ 167 if (rectCnt > 1) { 168 con.renderRectangle(maskPicture, XRUtils.PictOpClear, 169 XRColor.NO_ALPHA, 170 tileDirtyArea.x, tileDirtyArea.y, 171 width, height); 172 } 173 174 tile.reset(); 175 } else if (rectCnt > 0) { 176 tile.rects.translateRects(tileStartX + dirtyArea.x, 177 tileStartY + dirtyArea.y); 178 xrMgr.XRRenderRectangles(dst, tile.rects); 179 } 180 } 181 } 182 183 184 /** 185 * Allocates enough RectTile instances, to cover the whole 186 * mask area, or resets existing ones. 187 */ 188 protected void allocTiles(DirtyRegion maskArea) { 189 xTiles = (maskArea.getWidth() / MASK_SIZE) + 1; 190 yTiles = (maskArea.getHeight() / MASK_SIZE) + 1; 191 int tileCnt = xTiles * yTiles; 192 193 if (tileCnt > allocatedTiles) { 194 for (int i = 0; i < tileCnt; i++) { 195 if (i < allocatedTiles) { 196 tileList.get(i).reset(); 197 } else { 198 tileList.add(new RectTile()); 199 } 200 } 201 202 allocatedTiles = tileCnt; 203 } 204 } 205 206 /** 207 * Tiles the stored rectangles, if they are larger than the MASK_SIZE 208 */ 209 protected void tileRects() { 210 GrowableRectArray rects = mainTile.rects; 211 212 for (int i = 0; i < rects.getSize(); i++) { 213 int tileXStartIndex = rects.getX(i) / MASK_SIZE; 214 int tileYStartIndex = rects.getY(i) / MASK_SIZE; 215 int tileXLength = 216 ((rects.getX(i) + rects.getWidth(i)) / MASK_SIZE + 1) - 217 tileXStartIndex; 218 int tileYLength = 219 ((rects.getY(i) + rects.getHeight(i)) / MASK_SIZE + 1) - 220 tileYStartIndex; 221 222 for (int n = 0; n < tileYLength; n++) { 223 for (int m = 0; m < tileXLength; m++) { 224 225 int tileIndex = 226 xTiles * (tileYStartIndex + n) + tileXStartIndex + m; 227 RectTile tile = tileList.get(tileIndex); 228 229 GrowableRectArray rectTileList = tile.getRects(); 230 int tileArrayIndex = rectTileList.getNextIndex(); 231 232 int tileStartPosX = (tileXStartIndex + m) * MASK_SIZE; 233 int tileStartPosY = (tileYStartIndex + n) * MASK_SIZE; 234 235 rectTileList.setX(tileArrayIndex, rects.getX(i) - tileStartPosX); 236 rectTileList.setY(tileArrayIndex, rects.getY(i) - tileStartPosY); 237 rectTileList.setWidth(tileArrayIndex, rects.getWidth(i)); 238 rectTileList.setHeight(tileArrayIndex, rects.getHeight(i)); 239 240 limitRectCoords(rectTileList, tileArrayIndex); 241 242 tile.getDirtyArea().growDirtyRegion 243 (rectTileList.getX(tileArrayIndex), 244 rectTileList.getY(tileArrayIndex), 245 rectTileList.getWidth(tileArrayIndex) + 246 rectTileList.getX(tileArrayIndex), 247 rectTileList.getHeight(tileArrayIndex) + 248 rectTileList.getY(tileArrayIndex)); 249 } 250 } 251 } 252 } 253 254 /** 255 * Limits the rect's coordinates to the mask coordinates. The result is used 256 * by growDirtyRegion. 257 */ 258 private void limitRectCoords(GrowableRectArray rects, int index) { 259 if ((rects.getX(index) + rects.getWidth(index)) > MASK_SIZE) { 260 rects.setWidth(index, MASK_SIZE - rects.getX(index)); 261 } 262 if ((rects.getY(index) + rects.getHeight(index)) > MASK_SIZE) { 263 rects.setHeight(index, MASK_SIZE - rects.getY(index)); 264 } 265 if (rects.getX(index) < 0) { 266 rects.setWidth(index, rects.getWidth(index) + rects.getX(index)); 267 rects.setX(index, 0); 268 } 269 if (rects.getY(index) < 0) { 270 rects.setHeight(index, rects.getHeight(index) + rects.getY(index)); 271 rects.setY(index, 0); 272 } 273 } 274 275 /** 276 * @return MainTile to which rectangles are added before composition. 277 */ 278 public RectTile getMainTile() { 279 return mainTile; 280 } 281 }