1 /*
2 * Copyright (c) 2015, 2017, 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.marlin;
27
28 import java.awt.geom.Path2D;
29 import java.lang.ref.WeakReference;
30 import java.util.concurrent.atomic.AtomicInteger;
31 import sun.java2d.ReentrantContext;
32 import sun.java2d.marlin.ArrayCacheConst.CacheStats;
33 import sun.java2d.marlin.DMarlinRenderingEngine.NormalizingPathIterator;
34
35 /**
36 * This class is a renderer context dedicated to a single thread
37 */
38 final class DRendererContext extends ReentrantContext implements IRendererContext {
39
40 // RendererContext creation counter
41 private static final AtomicInteger CTX_COUNT = new AtomicInteger(1);
42
43 /**
44 * Create a new renderer context
45 *
46 * @return new RendererContext instance
47 */
48 static DRendererContext createContext() {
49 return new DRendererContext("ctx"
50 + Integer.toString(CTX_COUNT.getAndIncrement()));
51 }
52
53 // Smallest object used as Cleaner's parent reference
54 private final Object cleanerObj;
55 // dirty flag indicating an exception occured during pipeline in pathTo()
56 boolean dirty = false;
57 // shared data
58 final double[] double6 = new double[6];
59 // shared curve (dirty) (Renderer / Stroker)
60 final DCurve curve = new DCurve();
61 // MarlinRenderingEngine NormalizingPathIterator NearestPixelCenter:
62 final NormalizingPathIterator nPCPathIterator;
63 // MarlinRenderingEngine NearestPixelQuarter NormalizingPathIterator:
64 final NormalizingPathIterator nPQPathIterator;
65 // MarlinRenderingEngine.TransformingPathConsumer2D
66 final DTransformingPathConsumer2D transformerPC2D;
67 // recycled Path2D instance (weak)
68 private WeakReference<Path2D.Double> refPath2D = null;
69 final DRenderer renderer;
70 final DStroker stroker;
71 // Simplifies out collinear lines
72 final DCollinearSimplifier simplifier = new DCollinearSimplifier();
73 final DDasher dasher;
74 final MarlinTileGenerator ptg;
75 final MarlinCache cache;
76 // flag indicating the shape is stroked (1) or filled (0)
77 int stroking = 0;
78 // flag indicating to clip the shape
79 boolean doClip = false;
80 // flag indicating if the path is closed or not (in advance) to handle properly caps
81 boolean closedPath = false;
82 // clip rectangle (ymin, ymax, xmin, xmax):
83 final double[] clipRect = new double[4];
84
85 // Array caches:
86 /* clean int[] cache (zero-filled) = 5 refs */
87 private final IntArrayCache cleanIntCache = new IntArrayCache(true, 5);
88 /* dirty int[] cache = 5 refs */
89 private final IntArrayCache dirtyIntCache = new IntArrayCache(false, 5);
90 /* dirty double[] cache = 4 refs (2 polystack) */
91 private final DoubleArrayCache dirtyDoubleCache = new DoubleArrayCache(false, 4);
92 /* dirty byte[] cache = 2 ref (2 polystack) */
93 private final ByteArrayCache dirtyByteCache = new ByteArrayCache(false, 2);
94
95 // RendererContext statistics
96 final RendererStats stats;
97
98 final PathConsumer2DAdapter p2dAdapter = new PathConsumer2DAdapter();
99
100
101 /**
102 * Constructor
103 *
104 * @param name context name (debugging)
105 */
106 DRendererContext(final String name) {
107 if (LOG_CREATE_CONTEXT) {
108 MarlinUtils.logInfo("new RendererContext = " + name);
109 }
110 this.cleanerObj = new Object();
111
112 // create first stats (needed by newOffHeapArray):
113 if (DO_STATS || DO_MONITORS) {
114 stats = RendererStats.createInstance(cleanerObj, name);
115 // push cache stats:
116 stats.cacheStats = new CacheStats[] { cleanIntCache.stats,
117 dirtyIntCache.stats, dirtyDoubleCache.stats, dirtyByteCache.stats
118 };
119 } else {
120 stats = null;
121 }
122
123 // NormalizingPathIterator instances:
124 nPCPathIterator = new NormalizingPathIterator.NearestPixelCenter(double6);
125 nPQPathIterator = new NormalizingPathIterator.NearestPixelQuarter(double6);
126
127 // MarlinRenderingEngine.TransformingPathConsumer2D
128 transformerPC2D = new DTransformingPathConsumer2D(this);
129
130 // Renderer:
131 cache = new MarlinCache(this);
132 renderer = new DRenderer(this); // needs MarlinCache from rdrCtx.cache
133 ptg = new MarlinTileGenerator(stats, renderer, cache);
134
135 stroker = new DStroker(this);
136 dasher = new DDasher(this);
137 }
138
139 /**
140 * Disposes this renderer context:
141 * clean up before reusing this context
142 */
143 void dispose() {
144 if (DO_STATS) {
145 if (stats.totalOffHeap > stats.totalOffHeapMax) {
146 stats.totalOffHeapMax = stats.totalOffHeap;
147 }
148 stats.totalOffHeap = 0L;
149 }
150 stroking = 0;
151 doClip = false;
152 closedPath = false;
153
154 // if context is maked as DIRTY:
155 if (dirty) {
156 // may happen if an exception if thrown in the pipeline processing:
157 // force cleanup of all possible pipelined blocks (except Renderer):
158
159 // NormalizingPathIterator instances:
160 this.nPCPathIterator.dispose();
161 this.nPQPathIterator.dispose();
162 // Dasher:
163 this.dasher.dispose();
164 // Stroker:
165 this.stroker.dispose();
166
167 // mark context as CLEAN:
168 dirty = false;
169 }
170 }
171
172 Path2D.Double getPath2D() {
173 // resolve reference:
174 Path2D.Double p2d
175 = (refPath2D != null) ? refPath2D.get() : null;
176
177 // create a new Path2D ?
178 if (p2d == null) {
179 p2d = new Path2D.Double(WIND_NON_ZERO, INITIAL_EDGES_COUNT); // 32K
180
181 // update weak reference:
182 refPath2D = new WeakReference<Path2D.Double>(p2d);
183 }
184 // reset the path anyway:
185 p2d.reset();
186 return p2d;
187 }
188
189 @Override
190 public RendererStats stats() {
191 return stats;
192 }
193
194 @Override
195 public OffHeapArray newOffHeapArray(final long initialSize) {
196 if (DO_STATS) {
197 stats.totalOffHeapInitial += initialSize;
198 }
199 return new OffHeapArray(cleanerObj, initialSize);
200 }
201
202 @Override
203 public IntArrayCache.Reference newCleanIntArrayRef(final int initialSize) {
204 return cleanIntCache.createRef(initialSize);
205 }
206
207 IntArrayCache.Reference newDirtyIntArrayRef(final int initialSize) {
208 return dirtyIntCache.createRef(initialSize);
209 }
210
211 DoubleArrayCache.Reference newDirtyDoubleArrayRef(final int initialSize) {
212 return dirtyDoubleCache.createRef(initialSize);
213 }
214
215 ByteArrayCache.Reference newDirtyByteArrayRef(final int initialSize) {
216 return dirtyByteCache.createRef(initialSize);
217 }
218
219 static final class PathConsumer2DAdapter implements DPathConsumer2D {
220 private sun.awt.geom.PathConsumer2D out;
221
222 PathConsumer2DAdapter() {}
223
224 PathConsumer2DAdapter init(sun.awt.geom.PathConsumer2D out) {
225 this.out = out;
226 return this;
227 }
228
229 @Override
230 public void moveTo(double x0, double y0) {
231 out.moveTo((float)x0, (float)y0);
232 }
233
234 @Override
235 public void lineTo(double x1, double y1) {
236 out.lineTo((float)x1, (float)y1);
237 }
238
239 @Override
240 public void closePath() {
241 out.closePath();
242 }
243
244 @Override
245 public void pathDone() {
246 out.pathDone();
247 }
248
249 @Override
250 public void curveTo(double x1, double y1,
251 double x2, double y2,
252 double x3, double y3)
253 {
254 out.curveTo((float)x1, (float)y1,
255 (float)x2, (float)y2,
256 (float)x3, (float)y3);
257 }
258
259 @Override
260 public void quadTo(double x1, double y1, double x2, double y2) {
261 out.quadTo((float)x1, (float)y1, (float)x2, (float)y2);
262 }
263
264 @Override
265 public long getNativeConsumer() {
266 throw new InternalError("Not using a native peer");
267 }
268 }
269 }