author | mchung |
Tue, 14 Apr 2009 17:43:45 -0700 | |
changeset 2695 | d75c6ebf3ac6 |
parent 2 | 90ce3da70b43 |
child 5506 | 202f599c92aa |
permissions | -rw-r--r-- |
2 | 1 |
/* |
2 |
* Copyright 2007 Sun Microsystems, Inc. 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. Sun designates this |
|
8 |
* particular file as subject to the "Classpath" exception as provided |
|
9 |
* by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, |
|
22 |
* CA 95054 USA or visit www.sun.com if you need additional information or |
|
23 |
* have any questions. |
|
24 |
*/ |
|
25 |
||
26 |
package sun.java2d.pipe; |
|
27 |
||
28 |
import java.awt.Shape; |
|
29 |
import java.awt.BasicStroke; |
|
30 |
import java.awt.geom.PathIterator; |
|
31 |
import java.awt.geom.AffineTransform; |
|
32 |
||
33 |
import java.security.PrivilegedAction; |
|
34 |
import java.security.AccessController; |
|
35 |
import java.util.ServiceLoader; |
|
36 |
import sun.security.action.GetPropertyAction; |
|
37 |
||
38 |
import sun.awt.geom.PathConsumer2D; |
|
39 |
||
40 |
/** |
|
41 |
* This class abstracts a number of features for which the Java 2D |
|
42 |
* implementation relies on proprietary licensed software libraries. |
|
43 |
* Access to those features is now achieved by retrieving the singleton |
|
44 |
* instance of this class and calling the appropriate methods on it. |
|
45 |
* The 3 primary features abstracted here include: |
|
46 |
* <dl> |
|
47 |
* <dt>Shape createStrokedShape(Shape, [BasicStroke attributes]); |
|
48 |
* <dd>This method implements the functionality of the method of the |
|
49 |
* same name on the {@link BasicStroke} class. |
|
50 |
* <dt>void strokeTo(Shape, [rendering parameters], PathConsumer2D); |
|
51 |
* <dd>This method performs widening of the source path on the fly |
|
52 |
* and sends the results to the given {@link PathConsumer2D} object. |
|
53 |
* This procedure avoids having to create an intermediate Shape |
|
54 |
* object to hold the results of the {@code createStrokedShape} method. |
|
55 |
* The main user of this method is the Java 2D non-antialiasing renderer. |
|
56 |
* <dt>AATileGenerator getAATileGenerator(Shape, [rendering parameters]); |
|
57 |
* <dd>This method returns an object which can iterate over the |
|
58 |
* specified bounding box and produce tiles of coverage values for |
|
59 |
* antialiased rendering. The details of the operation of the |
|
60 |
* {@link AATileGenerator} object are explained in its class comments. |
|
61 |
* </dl> |
|
62 |
* Additionally, the following informational method supplies important |
|
63 |
* data about the implementation. |
|
64 |
* <dl> |
|
65 |
* <dt>float getMinimumAAPenSize() |
|
66 |
* <dd>This method provides information on how small the BasicStroke |
|
67 |
* line width can get before dropouts occur. Rendering with a BasicStroke |
|
68 |
* is defined to never allow the line to have breaks, gaps, or dropouts |
|
69 |
* even if the width is set to 0.0f, so this information allows the |
|
70 |
* {@link SunGraphics2D} class to detect the "thin line" case and set |
|
71 |
* the rendering attributes accordingly. |
|
72 |
* </dl> |
|
73 |
* At startup the runtime will load a single instance of this class. |
|
74 |
* It searches the classpath for a registered provider of this API |
|
75 |
* and returns either the last one it finds, or the instance whose |
|
76 |
* class name matches the value supplied in the System property |
|
77 |
* {@code sun.java2d.renderer}. |
|
78 |
* Additionally, a runtime System property flag can be set to trace |
|
79 |
* all calls to methods on the {@code RenderingEngine} in use by |
|
80 |
* setting the sun.java2d.renderer.trace property to any non-null value. |
|
81 |
* <p> |
|
82 |
* Parts of the system that need to use any of the above features should |
|
83 |
* call {@code RenderingEngine.getInstance()} to obtain the properly |
|
84 |
* registered (and possibly trace-enabled) version of the RenderingEngine. |
|
85 |
*/ |
|
86 |
public abstract class RenderingEngine { |
|
87 |
private static RenderingEngine reImpl; |
|
88 |
||
89 |
/** |
|
90 |
* Returns an instance of {@code RenderingEngine} as determined |
|
91 |
* by the installation environment and runtime flags. |
|
92 |
* <p> |
|
93 |
* A specific instance of the {@code RenderingEngine} can be |
|
94 |
* chosen by specifying the runtime flag: |
|
95 |
* <pre> |
|
96 |
* java -Dsun.java2d.renderer=<classname> |
|
97 |
* </pre> |
|
2695
d75c6ebf3ac6
6818072: Load Ductus using Class.forName if exist instead of using the service loader
mchung
parents:
2
diff
changeset
|
98 |
* |
d75c6ebf3ac6
6818072: Load Ductus using Class.forName if exist instead of using the service loader
mchung
parents:
2
diff
changeset
|
99 |
* If no specific {@code RenderingEngine} is specified on the command |
d75c6ebf3ac6
6818072: Load Ductus using Class.forName if exist instead of using the service loader
mchung
parents:
2
diff
changeset
|
100 |
* or Ductus renderer is specified, it will attempt loading the |
d75c6ebf3ac6
6818072: Load Ductus using Class.forName if exist instead of using the service loader
mchung
parents:
2
diff
changeset
|
101 |
* sun.dc.DuctusRenderingEngine class using Class.forName as a fastpath; |
d75c6ebf3ac6
6818072: Load Ductus using Class.forName if exist instead of using the service loader
mchung
parents:
2
diff
changeset
|
102 |
* if not found, use the ServiceLoader. |
2 | 103 |
* If no specific {@code RenderingEngine} is specified on the command |
104 |
* line then the last one returned by enumerating all subclasses of |
|
105 |
* {@code RenderingEngine} known to the ServiceLoader is used. |
|
106 |
* <p> |
|
107 |
* Runtime tracing of the actions of the {@code RenderingEngine} |
|
108 |
* can be enabled by specifying the runtime flag: |
|
109 |
* <pre> |
|
110 |
* java -Dsun.java2d.renderer.trace=<any string> |
|
111 |
* </pre> |
|
112 |
* @return an instance of {@code RenderingEngine} |
|
113 |
* @since 1.7 |
|
114 |
*/ |
|
115 |
public static synchronized RenderingEngine getInstance() { |
|
116 |
if (reImpl != null) { |
|
117 |
return reImpl; |
|
118 |
} |
|
119 |
||
120 |
reImpl = (RenderingEngine) |
|
121 |
AccessController.doPrivileged(new PrivilegedAction() { |
|
122 |
public Object run() { |
|
2695
d75c6ebf3ac6
6818072: Load Ductus using Class.forName if exist instead of using the service loader
mchung
parents:
2
diff
changeset
|
123 |
final String ductusREClass = "sun.dc.DuctusRenderingEngine"; |
2 | 124 |
String reClass = |
2695
d75c6ebf3ac6
6818072: Load Ductus using Class.forName if exist instead of using the service loader
mchung
parents:
2
diff
changeset
|
125 |
System.getProperty("sun.java2d.renderer", ductusREClass); |
d75c6ebf3ac6
6818072: Load Ductus using Class.forName if exist instead of using the service loader
mchung
parents:
2
diff
changeset
|
126 |
if (reClass.equals(ductusREClass)) { |
d75c6ebf3ac6
6818072: Load Ductus using Class.forName if exist instead of using the service loader
mchung
parents:
2
diff
changeset
|
127 |
try { |
d75c6ebf3ac6
6818072: Load Ductus using Class.forName if exist instead of using the service loader
mchung
parents:
2
diff
changeset
|
128 |
Class cls = Class.forName(ductusREClass); |
d75c6ebf3ac6
6818072: Load Ductus using Class.forName if exist instead of using the service loader
mchung
parents:
2
diff
changeset
|
129 |
return cls.newInstance(); |
d75c6ebf3ac6
6818072: Load Ductus using Class.forName if exist instead of using the service loader
mchung
parents:
2
diff
changeset
|
130 |
} catch (ClassNotFoundException x) { |
d75c6ebf3ac6
6818072: Load Ductus using Class.forName if exist instead of using the service loader
mchung
parents:
2
diff
changeset
|
131 |
// not found |
d75c6ebf3ac6
6818072: Load Ductus using Class.forName if exist instead of using the service loader
mchung
parents:
2
diff
changeset
|
132 |
} catch (IllegalAccessException x) { |
d75c6ebf3ac6
6818072: Load Ductus using Class.forName if exist instead of using the service loader
mchung
parents:
2
diff
changeset
|
133 |
// should not reach here |
d75c6ebf3ac6
6818072: Load Ductus using Class.forName if exist instead of using the service loader
mchung
parents:
2
diff
changeset
|
134 |
} catch (InstantiationException x) { |
d75c6ebf3ac6
6818072: Load Ductus using Class.forName if exist instead of using the service loader
mchung
parents:
2
diff
changeset
|
135 |
// should not reach here |
d75c6ebf3ac6
6818072: Load Ductus using Class.forName if exist instead of using the service loader
mchung
parents:
2
diff
changeset
|
136 |
} |
d75c6ebf3ac6
6818072: Load Ductus using Class.forName if exist instead of using the service loader
mchung
parents:
2
diff
changeset
|
137 |
} |
2 | 138 |
|
139 |
ServiceLoader<RenderingEngine> reLoader = |
|
140 |
ServiceLoader.loadInstalled(RenderingEngine.class); |
|
141 |
||
142 |
RenderingEngine service = null; |
|
143 |
||
144 |
for (RenderingEngine re : reLoader) { |
|
145 |
service = re; |
|
146 |
if (re.getClass().getName().equals(reClass)) { |
|
147 |
break; |
|
148 |
} |
|
149 |
} |
|
150 |
return service; |
|
151 |
} |
|
152 |
}); |
|
153 |
||
154 |
if (reImpl == null) { |
|
155 |
throw new InternalError("No RenderingEngine module found"); |
|
156 |
} |
|
157 |
||
158 |
GetPropertyAction gpa = |
|
159 |
new GetPropertyAction("sun.java2d.renderer.trace"); |
|
160 |
String reTrace = (String) AccessController.doPrivileged(gpa); |
|
161 |
if (reTrace != null) { |
|
162 |
reImpl = new Tracer(reImpl); |
|
163 |
} |
|
164 |
||
165 |
return reImpl; |
|
166 |
} |
|
167 |
||
168 |
/** |
|
169 |
* Create a widened path as specified by the parameters. |
|
170 |
* <p> |
|
171 |
* The specified {@code src} {@link Shape} is widened according |
|
172 |
* to the specified attribute parameters as per the |
|
173 |
* {@link BasicStroke} specification. |
|
174 |
* |
|
175 |
* @param src the source path to be widened |
|
176 |
* @param width the width of the widened path as per {@code BasicStroke} |
|
177 |
* @param caps the end cap decorations as per {@code BasicStroke} |
|
178 |
* @param join the segment join decorations as per {@code BasicStroke} |
|
179 |
* @param miterlimit the miter limit as per {@code BasicStroke} |
|
180 |
* @param dashes the dash length array as per {@code BasicStroke} |
|
181 |
* @param dashphase the initial dash phase as per {@code BasicStroke} |
|
182 |
* @return the widened path stored in a new {@code Shape} object |
|
183 |
* @since 1.7 |
|
184 |
*/ |
|
185 |
public abstract Shape createStrokedShape(Shape src, |
|
186 |
float width, |
|
187 |
int caps, |
|
188 |
int join, |
|
189 |
float miterlimit, |
|
190 |
float dashes[], |
|
191 |
float dashphase); |
|
192 |
||
193 |
/** |
|
194 |
* Sends the geometry for a widened path as specified by the parameters |
|
195 |
* to the specified consumer. |
|
196 |
* <p> |
|
197 |
* The specified {@code src} {@link Shape} is widened according |
|
198 |
* to the parameters specified by the {@link BasicStroke} object. |
|
199 |
* Adjustments are made to the path as appropriate for the |
|
200 |
* {@link VALUE_STROKE_NORMALIZE} hint if the {@code normalize} |
|
201 |
* boolean parameter is true. |
|
202 |
* Adjustments are made to the path as appropriate for the |
|
203 |
* {@link VALUE_ANTIALIAS_ON} hint if the {@code antialias} |
|
204 |
* boolean parameter is true. |
|
205 |
* <p> |
|
206 |
* The geometry of the widened path is forwarded to the indicated |
|
207 |
* {@link PathConsumer2D} object as it is calculated. |
|
208 |
* |
|
209 |
* @param src the source path to be widened |
|
210 |
* @param bs the {@code BasicSroke} object specifying the |
|
211 |
* decorations to be applied to the widened path |
|
212 |
* @param normalize indicates whether stroke normalization should |
|
213 |
* be applied |
|
214 |
* @param antialias indicates whether or not adjustments appropriate |
|
215 |
* to antialiased rendering should be applied |
|
216 |
* @param consumer the {@code PathConsumer2D} instance to forward |
|
217 |
* the widened geometry to |
|
218 |
* @since 1.7 |
|
219 |
*/ |
|
220 |
public abstract void strokeTo(Shape src, |
|
221 |
AffineTransform at, |
|
222 |
BasicStroke bs, |
|
223 |
boolean thin, |
|
224 |
boolean normalize, |
|
225 |
boolean antialias, |
|
226 |
PathConsumer2D consumer); |
|
227 |
||
228 |
/** |
|
229 |
* Construct an antialiased tile generator for the given shape with |
|
230 |
* the given rendering attributes and store the bounds of the tile |
|
231 |
* iteration in the bbox parameter. |
|
232 |
* The {@code at} parameter specifies a transform that should affect |
|
233 |
* both the shape and the {@code BasicStroke} attributes. |
|
234 |
* The {@code clip} parameter specifies the current clip in effect |
|
235 |
* in device coordinates and can be used to prune the data for the |
|
236 |
* operation, but the renderer is not required to perform any |
|
237 |
* clipping. |
|
238 |
* If the {@code BasicStroke} parameter is null then the shape |
|
239 |
* should be filled as is, otherwise the attributes of the |
|
240 |
* {@code BasicStroke} should be used to specify a draw operation. |
|
241 |
* The {@code thin} parameter indicates whether or not the |
|
242 |
* transformed {@code BasicStroke} represents coordinates smaller |
|
243 |
* than the minimum resolution of the antialiasing rasterizer as |
|
244 |
* specified by the {@code getMinimumAAPenWidth()} method. |
|
245 |
* <p> |
|
246 |
* Upon returning, this method will fill the {@code bbox} parameter |
|
247 |
* with 4 values indicating the bounds of the iteration of the |
|
248 |
* tile generator. |
|
249 |
* The iteration order of the tiles will be as specified by the |
|
250 |
* pseudo-code: |
|
251 |
* <pre> |
|
252 |
* for (y = bbox[1]; y < bbox[3]; y += tileheight) { |
|
253 |
* for (x = bbox[0]; x < bbox[2]; x += tilewidth) { |
|
254 |
* } |
|
255 |
* } |
|
256 |
* </pre> |
|
257 |
* If there is no output to be rendered, this method may return |
|
258 |
* null. |
|
259 |
* |
|
260 |
* @param s the shape to be rendered (fill or draw) |
|
261 |
* @param at the transform to be applied to the shape and the |
|
262 |
* stroke attributes |
|
263 |
* @param clip the current clip in effect in device coordinates |
|
264 |
* @param bs if non-null, a {@code BasicStroke} whose attributes |
|
265 |
* should be applied to this operation |
|
266 |
* @param thin true if the transformed stroke attributes are smaller |
|
267 |
* than the minimum dropout pen width |
|
268 |
* @param normalize true if the {@code VALUE_STROKE_NORMALIZE} |
|
269 |
* {@code RenderingHint} is in effect |
|
270 |
* @param bbox returns the bounds of the iteration |
|
271 |
* @return the {@code AATileGenerator} instance to be consulted |
|
272 |
* for tile coverages, or null if there is no output to render |
|
273 |
* @since 1.7 |
|
274 |
*/ |
|
275 |
public abstract AATileGenerator getAATileGenerator(Shape s, |
|
276 |
AffineTransform at, |
|
277 |
Region clip, |
|
278 |
BasicStroke bs, |
|
279 |
boolean thin, |
|
280 |
boolean normalize, |
|
281 |
int bbox[]); |
|
282 |
||
283 |
/** |
|
284 |
* Returns the minimum pen width that the antialiasing rasterizer |
|
285 |
* can represent without dropouts occuring. |
|
286 |
* @since 1.7 |
|
287 |
*/ |
|
288 |
public abstract float getMinimumAAPenSize(); |
|
289 |
||
290 |
/** |
|
291 |
* Utility method to feed a {@link PathConsumer2D} object from a |
|
292 |
* given {@link PathIterator}. |
|
293 |
* This method deals with the details of running the iterator and |
|
294 |
* feeding the consumer a segment at a time. |
|
295 |
*/ |
|
296 |
public static void feedConsumer(PathIterator pi, PathConsumer2D consumer) { |
|
297 |
float coords[] = new float[6]; |
|
298 |
while (!pi.isDone()) { |
|
299 |
switch (pi.currentSegment(coords)) { |
|
300 |
case PathIterator.SEG_MOVETO: |
|
301 |
consumer.moveTo(coords[0], coords[1]); |
|
302 |
break; |
|
303 |
case PathIterator.SEG_LINETO: |
|
304 |
consumer.lineTo(coords[0], coords[1]); |
|
305 |
break; |
|
306 |
case PathIterator.SEG_QUADTO: |
|
307 |
consumer.quadTo(coords[0], coords[1], |
|
308 |
coords[2], coords[3]); |
|
309 |
break; |
|
310 |
case PathIterator.SEG_CUBICTO: |
|
311 |
consumer.curveTo(coords[0], coords[1], |
|
312 |
coords[2], coords[3], |
|
313 |
coords[4], coords[5]); |
|
314 |
break; |
|
315 |
case PathIterator.SEG_CLOSE: |
|
316 |
consumer.closePath(); |
|
317 |
break; |
|
318 |
} |
|
319 |
pi.next(); |
|
320 |
} |
|
321 |
} |
|
322 |
||
323 |
static class Tracer extends RenderingEngine { |
|
324 |
RenderingEngine target; |
|
325 |
String name; |
|
326 |
||
327 |
public Tracer(RenderingEngine target) { |
|
328 |
this.target = target; |
|
329 |
name = target.getClass().getName(); |
|
330 |
} |
|
331 |
||
332 |
public Shape createStrokedShape(Shape src, |
|
333 |
float width, |
|
334 |
int caps, |
|
335 |
int join, |
|
336 |
float miterlimit, |
|
337 |
float dashes[], |
|
338 |
float dashphase) |
|
339 |
{ |
|
340 |
System.out.println(name+".createStrokedShape("+ |
|
341 |
src.getClass().getName()+", "+ |
|
342 |
"width = "+width+", "+ |
|
343 |
"caps = "+caps+", "+ |
|
344 |
"join = "+join+", "+ |
|
345 |
"miter = "+miterlimit+", "+ |
|
346 |
"dashes = "+dashes+", "+ |
|
347 |
"dashphase = "+dashphase+")"); |
|
348 |
return target.createStrokedShape(src, |
|
349 |
width, caps, join, miterlimit, |
|
350 |
dashes, dashphase); |
|
351 |
} |
|
352 |
||
353 |
public void strokeTo(Shape src, |
|
354 |
AffineTransform at, |
|
355 |
BasicStroke bs, |
|
356 |
boolean thin, |
|
357 |
boolean normalize, |
|
358 |
boolean antialias, |
|
359 |
PathConsumer2D consumer) |
|
360 |
{ |
|
361 |
System.out.println(name+".strokeTo("+ |
|
362 |
src.getClass().getName()+", "+ |
|
363 |
at+", "+ |
|
364 |
bs+", "+ |
|
365 |
(thin ? "thin" : "wide")+", "+ |
|
366 |
(normalize ? "normalized" : "pure")+", "+ |
|
367 |
(antialias ? "AA" : "non-AA")+", "+ |
|
368 |
consumer.getClass().getName()+")"); |
|
369 |
target.strokeTo(src, at, bs, thin, normalize, antialias, consumer); |
|
370 |
} |
|
371 |
||
372 |
public float getMinimumAAPenSize() { |
|
373 |
System.out.println(name+".getMinimumAAPenSize()"); |
|
374 |
return target.getMinimumAAPenSize(); |
|
375 |
} |
|
376 |
||
377 |
public AATileGenerator getAATileGenerator(Shape s, |
|
378 |
AffineTransform at, |
|
379 |
Region clip, |
|
380 |
BasicStroke bs, |
|
381 |
boolean thin, |
|
382 |
boolean normalize, |
|
383 |
int bbox[]) |
|
384 |
{ |
|
385 |
System.out.println(name+".getAATileGenerator("+ |
|
386 |
s.getClass().getName()+", "+ |
|
387 |
at+", "+ |
|
388 |
clip+", "+ |
|
389 |
bs+", "+ |
|
390 |
(thin ? "thin" : "wide")+", "+ |
|
391 |
(normalize ? "normalized" : "pure")+")"); |
|
392 |
return target.getAATileGenerator(s, at, clip, |
|
393 |
bs, thin, normalize, |
|
394 |
bbox); |
|
395 |
} |
|
396 |
} |
|
397 |
} |