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