1 /* 2 * Copyright (c) 1997, 2016, 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 package sun.java2d.pipe; 26 27 import java.awt.BasicStroke; 28 import java.awt.Rectangle; 29 import java.awt.Shape; 30 import java.awt.geom.Rectangle2D; 31 import sun.awt.SunHints; 32 import sun.java2d.ReentrantContext; 33 import sun.java2d.ReentrantContextProvider; 34 import sun.java2d.ReentrantContextProviderTL; 35 import sun.java2d.SunGraphics2D; 36 37 /** 38 * This class is used to convert raw geometry into 8-bit alpha tiles 39 * using an AATileGenerator for application by the next stage of 40 * the pipeline. 41 * This class sets up the Generator and computes the alpha tiles 42 * and then passes them on to a CompositePipe object for painting. 43 */ 44 public final class AAShapePipe 45 implements ShapeDrawPipe, ParallelogramPipe 46 { 47 static final RenderingEngine renderengine = RenderingEngine.getInstance(); 48 49 // Per-thread TileState (~1K very small so do not use any Weak Reference) 50 private static final ReentrantContextProvider<TileState> tileStateProvider = 51 new ReentrantContextProviderTL<TileState>( 52 ReentrantContextProvider.REF_HARD) 53 { 54 @Override 55 protected TileState newContext() { 56 return new TileState(); 57 } 58 }; 59 60 final CompositePipe outpipe; 61 62 public AAShapePipe(CompositePipe pipe) { 63 outpipe = pipe; 64 } 65 66 @Override 67 public void draw(SunGraphics2D sg, Shape s) { 68 final BasicStroke bs; 69 70 if (sg.stroke instanceof BasicStroke) { 71 bs = (BasicStroke) sg.stroke; 72 } else { 73 s = sg.stroke.createStrokedShape(s); 74 bs = null; 75 } 76 77 renderPath(sg, s, bs); 78 } 79 80 @Override 81 public void fill(SunGraphics2D sg, Shape s) { 82 renderPath(sg, s, null); 83 } 84 85 @Override 86 public void fillParallelogram(SunGraphics2D sg, 87 double ux1, double uy1, 88 double ux2, double uy2, 89 double x, double y, 90 double dx1, double dy1, 91 double dx2, double dy2) 92 { 93 final TileState ts = tileStateProvider.acquire(); 94 try { 95 final int[] abox = ts.abox; 96 97 final AATileGenerator aatg = 98 renderengine.getAATileGenerator(x, y, dx1, dy1, dx2, dy2, 0, 0, 99 sg.getCompClip(), abox); 100 if (aatg != null) { 101 renderTiles(sg, ts.computeBBox(ux1, uy1, ux2, uy2), 102 aatg, abox, ts); 103 } 104 } finally { 105 tileStateProvider.release(ts); 106 } 107 } 108 109 @Override 110 public void drawParallelogram(SunGraphics2D sg, 111 double ux1, double uy1, 112 double ux2, double uy2, 113 double x, double y, 114 double dx1, double dy1, 115 double dx2, double dy2, 116 double lw1, double lw2) 117 { 118 final TileState ts = tileStateProvider.acquire(); 119 try { 120 final int[] abox = ts.abox; 121 122 final AATileGenerator aatg = 123 renderengine.getAATileGenerator(x, y, dx1, dy1, dx2, dy2, lw1, 124 lw2, sg.getCompClip(), abox); 125 if (aatg != null) { 126 // Note that bbox is of the original shape, not the wide path. 127 // This is appropriate for handing to Paint methods... 128 renderTiles(sg, ts.computeBBox(ux1, uy1, ux2, uy2), 129 aatg, abox, ts); 130 } 131 } finally { 132 tileStateProvider.release(ts); 133 } 134 } 135 136 public void renderPath(SunGraphics2D sg, Shape s, BasicStroke bs) { 137 final boolean adjust = (bs != null && 138 sg.strokeHint != SunHints.INTVAL_STROKE_PURE); 139 final boolean thin = (sg.strokeState <= SunGraphics2D.STROKE_THINDASHED); 140 141 final TileState ts = tileStateProvider.acquire(); 142 try { 143 final int[] abox = ts.abox; 144 145 final AATileGenerator aatg = 146 renderengine.getAATileGenerator(s, sg.transform, sg.getCompClip(), 147 bs, thin, adjust, abox); 148 if (aatg != null) { 149 renderTiles(sg, s, aatg, abox, ts); 150 } 151 } finally { 152 tileStateProvider.release(ts); 153 } 154 } 155 156 public void renderTiles(SunGraphics2D sg, Shape s, 157 final AATileGenerator aatg, 158 final int[] abox, final TileState ts) 159 { 160 Object context = null; 161 try { 162 // reentrance: outpipe may also use AAShapePipe: 163 context = outpipe.startSequence(sg, s, 164 ts.computeDevBox(abox), 165 abox); 166 167 // copy of int[] abox as local variables for performance: 168 final int x0 = abox[0]; 169 final int y0 = abox[1]; 170 final int x1 = abox[2]; 171 final int y1 = abox[3]; 172 173 final int tw = aatg.getTileWidth(); 174 final int th = aatg.getTileHeight(); 175 176 // get tile from thread local storage: 177 final byte[] alpha = ts.getAlphaTile(tw * th); 178 byte[] atile; 179 180 for (int y = y0; y < y1; y += th) { 181 final int h = Math.min(th, y1 - y); 182 183 for (int x = x0; x < x1; x += tw) { 184 final int w = Math.min(tw, x1 - x); 185 186 final int a = aatg.getTypicalAlpha(); 187 188 if (a == 0x00 || !outpipe.needTile(context, x, y, w, h)) { 189 aatg.nextTile(); 190 outpipe.skipTile(context, x, y); 191 continue; 192 } 193 if (a == 0xff) { 194 atile = null; 195 aatg.nextTile(); 196 } else { 197 atile = alpha; 198 aatg.getAlpha(alpha, 0, tw); 199 } 200 201 outpipe.renderPathTile(context, atile, 0, tw, x, y, w, h); 202 } 203 } 204 } finally { 205 aatg.dispose(); 206 if (context != null) { 207 outpipe.endSequence(context); 208 } 209 } 210 } 211 212 // Tile state used by AAShapePipe 213 static final class TileState extends ReentrantContext { 214 // cached tile (32 x 32 tile by default) 215 private byte[] theTile = new byte[32 * 32]; 216 // dirty aabox array 217 final int[] abox = new int[4]; 218 // dirty bbox rectangle 219 private final Rectangle dev = new Rectangle(); 220 // dirty bbox rectangle2D.Double 221 private final Rectangle2D.Double bbox2D = new Rectangle2D.Double(); 222 223 byte[] getAlphaTile(int len) { 224 byte[] t = theTile; 225 if (t.length < len) { 226 // create a larger tile and may free current theTile (too small) 227 theTile = t = new byte[len]; 228 } 229 return t; 230 } 231 232 Rectangle computeDevBox(final int[] abox) { 233 final Rectangle box = this.dev; 234 box.x = abox[0]; 235 box.y = abox[1]; 236 box.width = abox[2] - abox[0]; 237 box.height = abox[3] - abox[1]; 238 return box; 239 } 240 241 Rectangle2D computeBBox(double ux1, double uy1, 242 double ux2, double uy2) 243 { 244 if ((ux2 -= ux1) < 0.0) { 245 ux1 += ux2; 246 ux2 = -ux2; 247 } 248 if ((uy2 -= uy1) < 0.0) { 249 uy1 += uy2; 250 uy2 = -uy2; 251 } 252 final Rectangle2D.Double box = this.bbox2D; 253 box.x = ux1; 254 box.y = uy1; 255 box.width = ux2; 256 box.height = uy2; 257 return box; 258 } 259 } 260 }