author | dxu |
Thu, 04 Apr 2013 15:39:17 -0700 | |
changeset 16734 | da1901d79073 |
parent 12813 | c10ab96dcf41 |
child 16843 | 21ec7ce3e580 |
permissions | -rw-r--r-- |
2 | 1 |
/* |
16734
da1901d79073
8000406: change files using @GenerateNativeHeader to use @Native
dxu
parents:
12813
diff
changeset
|
2 |
* Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved. |
2 | 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 |
|
5506 | 7 |
* published by the Free Software Foundation. Oracle designates this |
2 | 8 |
* particular file as subject to the "Classpath" exception as provided |
5506 | 9 |
* by Oracle in the LICENSE file that accompanied this code. |
2 | 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 |
* |
|
5506 | 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. |
|
2 | 24 |
*/ |
25 |
||
26 |
package sun.java2d; |
|
27 |
||
28 |
import java.awt.Graphics; |
|
29 |
import java.awt.Graphics2D; |
|
30 |
import java.awt.RenderingHints; |
|
31 |
import java.awt.RenderingHints.Key; |
|
32 |
import java.awt.geom.Area; |
|
33 |
import java.awt.geom.AffineTransform; |
|
34 |
import java.awt.geom.NoninvertibleTransformException; |
|
35 |
import java.awt.AlphaComposite; |
|
36 |
import java.awt.BasicStroke; |
|
37 |
import java.awt.image.BufferedImage; |
|
38 |
import java.awt.image.BufferedImageOp; |
|
39 |
import java.awt.image.RenderedImage; |
|
40 |
import java.awt.image.renderable.RenderableImage; |
|
41 |
import java.awt.image.renderable.RenderContext; |
|
42 |
import java.awt.image.AffineTransformOp; |
|
43 |
import java.awt.image.Raster; |
|
44 |
import java.awt.image.WritableRaster; |
|
45 |
import java.awt.Image; |
|
46 |
import java.awt.Composite; |
|
47 |
import java.awt.Color; |
|
48 |
import java.awt.image.ColorModel; |
|
49 |
import java.awt.GraphicsConfiguration; |
|
50 |
import java.awt.Paint; |
|
51 |
import java.awt.GradientPaint; |
|
52 |
import java.awt.LinearGradientPaint; |
|
53 |
import java.awt.RadialGradientPaint; |
|
54 |
import java.awt.TexturePaint; |
|
55 |
import java.awt.geom.Rectangle2D; |
|
56 |
import java.awt.geom.PathIterator; |
|
57 |
import java.awt.geom.GeneralPath; |
|
58 |
import java.awt.Shape; |
|
59 |
import java.awt.Stroke; |
|
60 |
import java.awt.FontMetrics; |
|
61 |
import java.awt.Rectangle; |
|
62 |
import java.text.AttributedCharacterIterator; |
|
63 |
import java.awt.Font; |
|
64 |
import java.awt.image.ImageObserver; |
|
65 |
import java.awt.Transparency; |
|
66 |
import java.awt.font.GlyphVector; |
|
67 |
import java.awt.font.TextLayout; |
|
68 |
import sun.font.FontDesignMetrics; |
|
3928 | 69 |
import sun.font.FontUtilities; |
2 | 70 |
import sun.java2d.pipe.PixelDrawPipe; |
71 |
import sun.java2d.pipe.PixelFillPipe; |
|
72 |
import sun.java2d.pipe.ShapeDrawPipe; |
|
73 |
import sun.java2d.pipe.ValidatePipe; |
|
74 |
import sun.java2d.pipe.ShapeSpanIterator; |
|
75 |
import sun.java2d.pipe.Region; |
|
76 |
import sun.java2d.pipe.TextPipe; |
|
77 |
import sun.java2d.pipe.DrawImagePipe; |
|
78 |
import sun.java2d.pipe.LoopPipe; |
|
79 |
import sun.java2d.loops.FontInfo; |
|
80 |
import sun.java2d.loops.RenderLoops; |
|
81 |
import sun.java2d.loops.CompositeType; |
|
82 |
import sun.java2d.loops.SurfaceType; |
|
83 |
import sun.java2d.loops.Blit; |
|
84 |
import sun.java2d.loops.MaskFill; |
|
85 |
import sun.font.FontManager; |
|
86 |
import java.awt.font.FontRenderContext; |
|
87 |
import sun.java2d.loops.XORComposite; |
|
88 |
import sun.awt.ConstrainableGraphics; |
|
89 |
import sun.awt.SunHints; |
|
90 |
import java.util.Map; |
|
91 |
import java.util.Iterator; |
|
887 | 92 |
import sun.java2d.DestSurfaceProvider; |
2 | 93 |
import sun.misc.PerformanceLogger; |
94 |
||
16734
da1901d79073
8000406: change files using @GenerateNativeHeader to use @Native
dxu
parents:
12813
diff
changeset
|
95 |
import java.lang.annotation.Native; |
12813
c10ab96dcf41
7170969: Add @GenerateNativeHeader to classes whose fields need to be exported for JNI
erikj
parents:
12047
diff
changeset
|
96 |
|
2 | 97 |
/** |
98 |
* This is a the master Graphics2D superclass for all of the Sun |
|
99 |
* Graphics implementations. This class relies on subclasses to |
|
100 |
* manage the various device information, but provides an overall |
|
101 |
* general framework for performing all of the requests in the |
|
102 |
* Graphics and Graphics2D APIs. |
|
103 |
* |
|
104 |
* @author Jim Graham |
|
105 |
*/ |
|
106 |
public final class SunGraphics2D |
|
107 |
extends Graphics2D |
|
887 | 108 |
implements ConstrainableGraphics, Cloneable, DestSurfaceProvider |
2 | 109 |
{ |
110 |
/* |
|
111 |
* Attribute States |
|
112 |
*/ |
|
113 |
/* Paint */ |
|
16734
da1901d79073
8000406: change files using @GenerateNativeHeader to use @Native
dxu
parents:
12813
diff
changeset
|
114 |
@Native |
2 | 115 |
public static final int PAINT_CUSTOM = 6; /* Any other Paint object */ |
16734
da1901d79073
8000406: change files using @GenerateNativeHeader to use @Native
dxu
parents:
12813
diff
changeset
|
116 |
@Native |
2 | 117 |
public static final int PAINT_TEXTURE = 5; /* Tiled Image */ |
16734
da1901d79073
8000406: change files using @GenerateNativeHeader to use @Native
dxu
parents:
12813
diff
changeset
|
118 |
@Native |
2 | 119 |
public static final int PAINT_RAD_GRADIENT = 4; /* Color RadialGradient */ |
16734
da1901d79073
8000406: change files using @GenerateNativeHeader to use @Native
dxu
parents:
12813
diff
changeset
|
120 |
@Native |
2 | 121 |
public static final int PAINT_LIN_GRADIENT = 3; /* Color LinearGradient */ |
16734
da1901d79073
8000406: change files using @GenerateNativeHeader to use @Native
dxu
parents:
12813
diff
changeset
|
122 |
@Native |
2 | 123 |
public static final int PAINT_GRADIENT = 2; /* Color Gradient */ |
16734
da1901d79073
8000406: change files using @GenerateNativeHeader to use @Native
dxu
parents:
12813
diff
changeset
|
124 |
@Native |
2 | 125 |
public static final int PAINT_ALPHACOLOR = 1; /* Non-opaque Color */ |
16734
da1901d79073
8000406: change files using @GenerateNativeHeader to use @Native
dxu
parents:
12813
diff
changeset
|
126 |
@Native |
2 | 127 |
public static final int PAINT_OPAQUECOLOR = 0; /* Opaque Color */ |
128 |
||
129 |
/* Composite*/ |
|
16734
da1901d79073
8000406: change files using @GenerateNativeHeader to use @Native
dxu
parents:
12813
diff
changeset
|
130 |
@Native |
2 | 131 |
public static final int COMP_CUSTOM = 3;/* Custom Composite */ |
16734
da1901d79073
8000406: change files using @GenerateNativeHeader to use @Native
dxu
parents:
12813
diff
changeset
|
132 |
@Native |
2 | 133 |
public static final int COMP_XOR = 2;/* XOR Mode Composite */ |
16734
da1901d79073
8000406: change files using @GenerateNativeHeader to use @Native
dxu
parents:
12813
diff
changeset
|
134 |
@Native |
2 | 135 |
public static final int COMP_ALPHA = 1;/* AlphaComposite */ |
16734
da1901d79073
8000406: change files using @GenerateNativeHeader to use @Native
dxu
parents:
12813
diff
changeset
|
136 |
@Native |
2 | 137 |
public static final int COMP_ISCOPY = 0;/* simple stores into destination, |
138 |
* i.e. Src, SrcOverNoEa, and other |
|
139 |
* alpha modes which replace |
|
140 |
* the destination. |
|
141 |
*/ |
|
142 |
||
143 |
/* Stroke */ |
|
16734
da1901d79073
8000406: change files using @GenerateNativeHeader to use @Native
dxu
parents:
12813
diff
changeset
|
144 |
@Native |
2 | 145 |
public static final int STROKE_CUSTOM = 3; /* custom Stroke */ |
16734
da1901d79073
8000406: change files using @GenerateNativeHeader to use @Native
dxu
parents:
12813
diff
changeset
|
146 |
@Native |
2 | 147 |
public static final int STROKE_WIDE = 2; /* BasicStroke */ |
16734
da1901d79073
8000406: change files using @GenerateNativeHeader to use @Native
dxu
parents:
12813
diff
changeset
|
148 |
@Native |
2 | 149 |
public static final int STROKE_THINDASHED = 1; /* BasicStroke */ |
16734
da1901d79073
8000406: change files using @GenerateNativeHeader to use @Native
dxu
parents:
12813
diff
changeset
|
150 |
@Native |
2 | 151 |
public static final int STROKE_THIN = 0; /* BasicStroke */ |
152 |
||
153 |
/* Transform */ |
|
16734
da1901d79073
8000406: change files using @GenerateNativeHeader to use @Native
dxu
parents:
12813
diff
changeset
|
154 |
@Native |
2 | 155 |
public static final int TRANSFORM_GENERIC = 4; /* any 3x2 */ |
16734
da1901d79073
8000406: change files using @GenerateNativeHeader to use @Native
dxu
parents:
12813
diff
changeset
|
156 |
@Native |
2 | 157 |
public static final int TRANSFORM_TRANSLATESCALE = 3; /* scale XY */ |
16734
da1901d79073
8000406: change files using @GenerateNativeHeader to use @Native
dxu
parents:
12813
diff
changeset
|
158 |
@Native |
2 | 159 |
public static final int TRANSFORM_ANY_TRANSLATE = 2; /* non-int translate */ |
16734
da1901d79073
8000406: change files using @GenerateNativeHeader to use @Native
dxu
parents:
12813
diff
changeset
|
160 |
@Native |
2 | 161 |
public static final int TRANSFORM_INT_TRANSLATE = 1; /* int translate */ |
16734
da1901d79073
8000406: change files using @GenerateNativeHeader to use @Native
dxu
parents:
12813
diff
changeset
|
162 |
@Native |
2 | 163 |
public static final int TRANSFORM_ISIDENT = 0; /* Identity */ |
164 |
||
165 |
/* Clipping */ |
|
16734
da1901d79073
8000406: change files using @GenerateNativeHeader to use @Native
dxu
parents:
12813
diff
changeset
|
166 |
@Native |
2 | 167 |
public static final int CLIP_SHAPE = 2; /* arbitrary clip */ |
16734
da1901d79073
8000406: change files using @GenerateNativeHeader to use @Native
dxu
parents:
12813
diff
changeset
|
168 |
@Native |
2 | 169 |
public static final int CLIP_RECTANGULAR = 1; /* rectangular clip */ |
16734
da1901d79073
8000406: change files using @GenerateNativeHeader to use @Native
dxu
parents:
12813
diff
changeset
|
170 |
@Native |
2 | 171 |
public static final int CLIP_DEVICE = 0; /* no clipping set */ |
172 |
||
173 |
/* The following fields are used when the current Paint is a Color. */ |
|
174 |
public int eargb; // ARGB value with ExtraAlpha baked in |
|
175 |
public int pixel; // pixel value for eargb |
|
176 |
||
177 |
public SurfaceData surfaceData; |
|
178 |
||
179 |
public PixelDrawPipe drawpipe; |
|
180 |
public PixelFillPipe fillpipe; |
|
181 |
public DrawImagePipe imagepipe; |
|
182 |
public ShapeDrawPipe shapepipe; |
|
183 |
public TextPipe textpipe; |
|
184 |
public MaskFill alphafill; |
|
185 |
||
186 |
public RenderLoops loops; |
|
187 |
||
188 |
public CompositeType imageComp; /* Image Transparency checked on fly */ |
|
189 |
||
190 |
public int paintState; |
|
191 |
public int compositeState; |
|
192 |
public int strokeState; |
|
193 |
public int transformState; |
|
194 |
public int clipState; |
|
195 |
||
196 |
public Color foregroundColor; |
|
197 |
public Color backgroundColor; |
|
198 |
||
199 |
public AffineTransform transform; |
|
200 |
public int transX; |
|
201 |
public int transY; |
|
202 |
||
203 |
protected static final Stroke defaultStroke = new BasicStroke(); |
|
204 |
protected static final Composite defaultComposite = AlphaComposite.SrcOver; |
|
205 |
private static final Font defaultFont = |
|
206 |
new Font(Font.DIALOG, Font.PLAIN, 12); |
|
207 |
||
208 |
public Paint paint; |
|
209 |
public Stroke stroke; |
|
210 |
public Composite composite; |
|
211 |
protected Font font; |
|
212 |
protected FontMetrics fontMetrics; |
|
213 |
||
214 |
public int renderHint; |
|
215 |
public int antialiasHint; |
|
216 |
public int textAntialiasHint; |
|
12047
320a714614e9
7113349: Initial changeset for Macosx port to jdk
michaelm
parents:
11902
diff
changeset
|
217 |
protected int fractionalMetricsHint; |
2 | 218 |
|
219 |
/* A gamma adjustment to the colour used in lcd text blitting */ |
|
220 |
public int lcdTextContrast; |
|
221 |
private static int lcdTextContrastDefaultValue = 140; |
|
222 |
||
223 |
private int interpolationHint; // raw value of rendering Hint |
|
224 |
public int strokeHint; |
|
225 |
||
226 |
public int interpolationType; // algorithm choice based on |
|
227 |
// interpolation and render Hints |
|
228 |
||
229 |
public RenderingHints hints; |
|
230 |
||
231 |
public Region constrainClip; // lightweight bounds |
|
232 |
public int constrainX; |
|
233 |
public int constrainY; |
|
234 |
||
235 |
public Region clipRegion; |
|
236 |
public Shape usrClip; |
|
237 |
protected Region devClip; // Actual physical drawable |
|
238 |
||
239 |
// cached state for text rendering |
|
240 |
private boolean validFontInfo; |
|
241 |
private FontInfo fontInfo; |
|
242 |
private FontInfo glyphVectorFontInfo; |
|
243 |
private FontRenderContext glyphVectorFRC; |
|
244 |
||
245 |
private final static int slowTextTransformMask = |
|
246 |
AffineTransform.TYPE_GENERAL_TRANSFORM |
|
247 |
| AffineTransform.TYPE_MASK_ROTATION |
|
248 |
| AffineTransform.TYPE_FLIP; |
|
249 |
||
250 |
static { |
|
251 |
if (PerformanceLogger.loggingEnabled()) { |
|
252 |
PerformanceLogger.setTime("SunGraphics2D static initialization"); |
|
253 |
} |
|
254 |
} |
|
255 |
||
256 |
public SunGraphics2D(SurfaceData sd, Color fg, Color bg, Font f) { |
|
257 |
surfaceData = sd; |
|
258 |
foregroundColor = fg; |
|
259 |
backgroundColor = bg; |
|
260 |
||
261 |
transform = new AffineTransform(); |
|
262 |
stroke = defaultStroke; |
|
263 |
composite = defaultComposite; |
|
264 |
paint = foregroundColor; |
|
265 |
||
266 |
imageComp = CompositeType.SrcOverNoEa; |
|
267 |
||
268 |
renderHint = SunHints.INTVAL_RENDER_DEFAULT; |
|
269 |
antialiasHint = SunHints.INTVAL_ANTIALIAS_OFF; |
|
270 |
textAntialiasHint = SunHints.INTVAL_TEXT_ANTIALIAS_DEFAULT; |
|
271 |
fractionalMetricsHint = SunHints.INTVAL_FRACTIONALMETRICS_OFF; |
|
272 |
lcdTextContrast = lcdTextContrastDefaultValue; |
|
273 |
interpolationHint = -1; |
|
274 |
strokeHint = SunHints.INTVAL_STROKE_DEFAULT; |
|
275 |
||
276 |
interpolationType = AffineTransformOp.TYPE_NEAREST_NEIGHBOR; |
|
277 |
||
278 |
validateColor(); |
|
279 |
||
280 |
font = f; |
|
281 |
if (font == null) { |
|
282 |
font = defaultFont; |
|
283 |
} |
|
284 |
||
285 |
setDevClip(sd.getBounds()); |
|
286 |
invalidatePipe(); |
|
287 |
} |
|
288 |
||
289 |
protected Object clone() { |
|
290 |
try { |
|
291 |
SunGraphics2D g = (SunGraphics2D) super.clone(); |
|
292 |
g.transform = new AffineTransform(this.transform); |
|
293 |
if (hints != null) { |
|
294 |
g.hints = (RenderingHints) this.hints.clone(); |
|
295 |
} |
|
296 |
/* FontInfos are re-used, so must be cloned too, if they |
|
297 |
* are valid, and be nulled out if invalid. |
|
298 |
* The implied trade-off is that there is more to be gained |
|
299 |
* from re-using these objects than is lost by having to |
|
300 |
* clone them when the SG2D is cloned. |
|
301 |
*/ |
|
302 |
if (this.fontInfo != null) { |
|
303 |
if (this.validFontInfo) { |
|
304 |
g.fontInfo = (FontInfo)this.fontInfo.clone(); |
|
305 |
} else { |
|
306 |
g.fontInfo = null; |
|
307 |
} |
|
308 |
} |
|
309 |
if (this.glyphVectorFontInfo != null) { |
|
310 |
g.glyphVectorFontInfo = |
|
311 |
(FontInfo)this.glyphVectorFontInfo.clone(); |
|
312 |
g.glyphVectorFRC = this.glyphVectorFRC; |
|
313 |
} |
|
314 |
//g.invalidatePipe(); |
|
315 |
return g; |
|
316 |
} catch (CloneNotSupportedException e) { |
|
317 |
} |
|
318 |
return null; |
|
319 |
} |
|
320 |
||
321 |
/** |
|
322 |
* Create a new SunGraphics2D based on this one. |
|
323 |
*/ |
|
324 |
public Graphics create() { |
|
325 |
return (Graphics) clone(); |
|
326 |
} |
|
327 |
||
328 |
public void setDevClip(int x, int y, int w, int h) { |
|
329 |
Region c = constrainClip; |
|
330 |
if (c == null) { |
|
331 |
devClip = Region.getInstanceXYWH(x, y, w, h); |
|
332 |
} else { |
|
333 |
devClip = c.getIntersectionXYWH(x, y, w, h); |
|
334 |
} |
|
335 |
validateCompClip(); |
|
336 |
} |
|
337 |
||
338 |
public void setDevClip(Rectangle r) { |
|
339 |
setDevClip(r.x, r.y, r.width, r.height); |
|
340 |
} |
|
341 |
||
342 |
/** |
|
343 |
* Constrain rendering for lightweight objects. |
|
344 |
* |
|
345 |
* REMIND: This method will back off to the "workaround" |
|
346 |
* of using translate and clipRect if the Graphics |
|
347 |
* to be constrained has a complex transform. The |
|
348 |
* drawback of the workaround is that the resulting |
|
349 |
* clip and device origin cannot be "enforced". |
|
350 |
* |
|
351 |
* @exception IllegalStateException If the Graphics |
|
352 |
* to be constrained has a complex transform. |
|
353 |
*/ |
|
354 |
public void constrain(int x, int y, int w, int h) { |
|
355 |
if ((x|y) != 0) { |
|
356 |
translate(x, y); |
|
357 |
} |
|
358 |
if (transformState >= TRANSFORM_TRANSLATESCALE) { |
|
359 |
clipRect(0, 0, w, h); |
|
360 |
return; |
|
361 |
} |
|
362 |
x = constrainX = transX; |
|
363 |
y = constrainY = transY; |
|
364 |
w = Region.dimAdd(x, w); |
|
365 |
h = Region.dimAdd(y, h); |
|
366 |
Region c = constrainClip; |
|
367 |
if (c == null) { |
|
368 |
c = Region.getInstanceXYXY(x, y, w, h); |
|
369 |
} else { |
|
370 |
c = c.getIntersectionXYXY(x, y, w, h); |
|
371 |
if (c == constrainClip) { |
|
372 |
// Common case to ignore |
|
373 |
return; |
|
374 |
} |
|
375 |
} |
|
376 |
constrainClip = c; |
|
377 |
if (!devClip.isInsideQuickCheck(c)) { |
|
378 |
devClip = devClip.getIntersection(c); |
|
379 |
validateCompClip(); |
|
380 |
} |
|
381 |
} |
|
382 |
||
383 |
protected static ValidatePipe invalidpipe = new ValidatePipe(); |
|
384 |
||
385 |
/* |
|
386 |
* Invalidate the pipeline |
|
387 |
*/ |
|
388 |
protected void invalidatePipe() { |
|
389 |
drawpipe = invalidpipe; |
|
390 |
fillpipe = invalidpipe; |
|
391 |
shapepipe = invalidpipe; |
|
392 |
textpipe = invalidpipe; |
|
393 |
imagepipe = invalidpipe; |
|
4250
e88776b21913
6896068: SunGraphics2D exposes a reference to itself while non fully initialised.
neugens
parents:
3928
diff
changeset
|
394 |
loops = null; |
2 | 395 |
} |
396 |
||
397 |
public void validatePipe() { |
|
11897
9e80dbac0293
7112642: Incorrect checking for graphics rendering object
bagiras
parents:
5506
diff
changeset
|
398 |
/* This workaround is for the situation when we update the Pipelines |
9e80dbac0293
7112642: Incorrect checking for graphics rendering object
bagiras
parents:
5506
diff
changeset
|
399 |
* for invalid SurfaceData and run further code when the current |
9e80dbac0293
7112642: Incorrect checking for graphics rendering object
bagiras
parents:
5506
diff
changeset
|
400 |
* pipeline doesn't support the type of new SurfaceData created during |
9e80dbac0293
7112642: Incorrect checking for graphics rendering object
bagiras
parents:
5506
diff
changeset
|
401 |
* the current pipeline's work (in place of the invalid SurfaceData). |
9e80dbac0293
7112642: Incorrect checking for graphics rendering object
bagiras
parents:
5506
diff
changeset
|
402 |
* Usually SurfaceData and Pipelines are repaired (through revalidateAll) |
9e80dbac0293
7112642: Incorrect checking for graphics rendering object
bagiras
parents:
5506
diff
changeset
|
403 |
* and called again in the exception handlers */ |
9e80dbac0293
7112642: Incorrect checking for graphics rendering object
bagiras
parents:
5506
diff
changeset
|
404 |
|
9e80dbac0293
7112642: Incorrect checking for graphics rendering object
bagiras
parents:
5506
diff
changeset
|
405 |
if (!surfaceData.isValid()) { |
9e80dbac0293
7112642: Incorrect checking for graphics rendering object
bagiras
parents:
5506
diff
changeset
|
406 |
throw new InvalidPipeException("attempt to validate Pipe with invalid SurfaceData"); |
9e80dbac0293
7112642: Incorrect checking for graphics rendering object
bagiras
parents:
5506
diff
changeset
|
407 |
} |
9e80dbac0293
7112642: Incorrect checking for graphics rendering object
bagiras
parents:
5506
diff
changeset
|
408 |
|
2 | 409 |
surfaceData.validatePipe(this); |
410 |
} |
|
411 |
||
412 |
/* |
|
413 |
* Intersect two Shapes by the simplest method, attempting to produce |
|
414 |
* a simplified result. |
|
415 |
* The boolean arguments keep1 and keep2 specify whether or not |
|
416 |
* the first or second shapes can be modified during the operation |
|
417 |
* or whether that shape must be "kept" unmodified. |
|
418 |
*/ |
|
419 |
Shape intersectShapes(Shape s1, Shape s2, boolean keep1, boolean keep2) { |
|
420 |
if (s1 instanceof Rectangle && s2 instanceof Rectangle) { |
|
421 |
return ((Rectangle) s1).intersection((Rectangle) s2); |
|
422 |
} |
|
423 |
if (s1 instanceof Rectangle2D) { |
|
424 |
return intersectRectShape((Rectangle2D) s1, s2, keep1, keep2); |
|
425 |
} else if (s2 instanceof Rectangle2D) { |
|
426 |
return intersectRectShape((Rectangle2D) s2, s1, keep2, keep1); |
|
427 |
} |
|
428 |
return intersectByArea(s1, s2, keep1, keep2); |
|
429 |
} |
|
430 |
||
431 |
/* |
|
432 |
* Intersect a Rectangle with a Shape by the simplest method, |
|
433 |
* attempting to produce a simplified result. |
|
434 |
* The boolean arguments keep1 and keep2 specify whether or not |
|
435 |
* the first or second shapes can be modified during the operation |
|
436 |
* or whether that shape must be "kept" unmodified. |
|
437 |
*/ |
|
438 |
Shape intersectRectShape(Rectangle2D r, Shape s, |
|
439 |
boolean keep1, boolean keep2) { |
|
440 |
if (s instanceof Rectangle2D) { |
|
441 |
Rectangle2D r2 = (Rectangle2D) s; |
|
442 |
Rectangle2D outrect; |
|
443 |
if (!keep1) { |
|
444 |
outrect = r; |
|
445 |
} else if (!keep2) { |
|
446 |
outrect = r2; |
|
447 |
} else { |
|
448 |
outrect = new Rectangle2D.Float(); |
|
449 |
} |
|
450 |
double x1 = Math.max(r.getX(), r2.getX()); |
|
451 |
double x2 = Math.min(r.getX() + r.getWidth(), |
|
452 |
r2.getX() + r2.getWidth()); |
|
453 |
double y1 = Math.max(r.getY(), r2.getY()); |
|
454 |
double y2 = Math.min(r.getY() + r.getHeight(), |
|
455 |
r2.getY() + r2.getHeight()); |
|
456 |
||
457 |
if (((x2 - x1) < 0) || ((y2 - y1) < 0)) |
|
458 |
// Width or height is negative. No intersection. |
|
459 |
outrect.setFrameFromDiagonal(0, 0, 0, 0); |
|
460 |
else |
|
461 |
outrect.setFrameFromDiagonal(x1, y1, x2, y2); |
|
462 |
return outrect; |
|
463 |
} |
|
464 |
if (r.contains(s.getBounds2D())) { |
|
465 |
if (keep2) { |
|
466 |
s = cloneShape(s); |
|
467 |
} |
|
468 |
return s; |
|
469 |
} |
|
470 |
return intersectByArea(r, s, keep1, keep2); |
|
471 |
} |
|
472 |
||
473 |
protected static Shape cloneShape(Shape s) { |
|
474 |
return new GeneralPath(s); |
|
475 |
} |
|
476 |
||
477 |
/* |
|
478 |
* Intersect two Shapes using the Area class. Presumably other |
|
479 |
* attempts at simpler intersection methods proved fruitless. |
|
480 |
* The boolean arguments keep1 and keep2 specify whether or not |
|
481 |
* the first or second shapes can be modified during the operation |
|
482 |
* or whether that shape must be "kept" unmodified. |
|
483 |
* @see #intersectShapes |
|
484 |
* @see #intersectRectShape |
|
485 |
*/ |
|
486 |
Shape intersectByArea(Shape s1, Shape s2, boolean keep1, boolean keep2) { |
|
487 |
Area a1, a2; |
|
488 |
||
489 |
// First see if we can find an overwriteable source shape |
|
490 |
// to use as our destination area to avoid duplication. |
|
491 |
if (!keep1 && (s1 instanceof Area)) { |
|
492 |
a1 = (Area) s1; |
|
493 |
} else if (!keep2 && (s2 instanceof Area)) { |
|
494 |
a1 = (Area) s2; |
|
495 |
s2 = s1; |
|
496 |
} else { |
|
497 |
a1 = new Area(s1); |
|
498 |
} |
|
499 |
||
500 |
if (s2 instanceof Area) { |
|
501 |
a2 = (Area) s2; |
|
502 |
} else { |
|
503 |
a2 = new Area(s2); |
|
504 |
} |
|
505 |
||
506 |
a1.intersect(a2); |
|
507 |
if (a1.isRectangular()) { |
|
508 |
return a1.getBounds(); |
|
509 |
} |
|
510 |
||
511 |
return a1; |
|
512 |
} |
|
513 |
||
514 |
/* |
|
515 |
* Intersect usrClip bounds and device bounds to determine the composite |
|
516 |
* rendering boundaries. |
|
517 |
*/ |
|
518 |
public Region getCompClip() { |
|
519 |
if (!surfaceData.isValid()) { |
|
520 |
// revalidateAll() implicitly recalculcates the composite clip |
|
521 |
revalidateAll(); |
|
522 |
} |
|
523 |
||
524 |
return clipRegion; |
|
525 |
} |
|
526 |
||
527 |
public Font getFont() { |
|
528 |
if (font == null) { |
|
529 |
font = defaultFont; |
|
530 |
} |
|
531 |
return font; |
|
532 |
} |
|
533 |
||
534 |
private static final double[] IDENT_MATRIX = {1, 0, 0, 1}; |
|
535 |
private static final AffineTransform IDENT_ATX = |
|
536 |
new AffineTransform(); |
|
537 |
||
538 |
private static final int MINALLOCATED = 8; |
|
539 |
private static final int TEXTARRSIZE = 17; |
|
540 |
private static double[][] textTxArr = new double[TEXTARRSIZE][]; |
|
541 |
private static AffineTransform[] textAtArr = |
|
542 |
new AffineTransform[TEXTARRSIZE]; |
|
543 |
||
544 |
static { |
|
545 |
for (int i=MINALLOCATED;i<TEXTARRSIZE;i++) { |
|
546 |
textTxArr[i] = new double [] {i, 0, 0, i}; |
|
547 |
textAtArr[i] = new AffineTransform( textTxArr[i]); |
|
548 |
} |
|
549 |
} |
|
550 |
||
551 |
// cached state for various draw[String,Char,Byte] optimizations |
|
552 |
public FontInfo checkFontInfo(FontInfo info, Font font, |
|
553 |
FontRenderContext frc) { |
|
554 |
/* Do not create a FontInfo object as part of construction of an |
|
555 |
* SG2D as its possible it may never be needed - ie if no text |
|
556 |
* is drawn using this SG2D. |
|
557 |
*/ |
|
558 |
if (info == null) { |
|
559 |
info = new FontInfo(); |
|
560 |
} |
|
561 |
||
562 |
float ptSize = font.getSize2D(); |
|
563 |
int txFontType; |
|
564 |
AffineTransform devAt, textAt=null; |
|
565 |
if (font.isTransformed()) { |
|
566 |
textAt = font.getTransform(); |
|
567 |
textAt.scale(ptSize, ptSize); |
|
568 |
txFontType = textAt.getType(); |
|
569 |
info.originX = (float)textAt.getTranslateX(); |
|
570 |
info.originY = (float)textAt.getTranslateY(); |
|
571 |
textAt.translate(-info.originX, -info.originY); |
|
572 |
if (transformState >= TRANSFORM_TRANSLATESCALE) { |
|
573 |
transform.getMatrix(info.devTx = new double[4]); |
|
574 |
devAt = new AffineTransform(info.devTx); |
|
575 |
textAt.preConcatenate(devAt); |
|
576 |
} else { |
|
577 |
info.devTx = IDENT_MATRIX; |
|
578 |
devAt = IDENT_ATX; |
|
579 |
} |
|
580 |
textAt.getMatrix(info.glyphTx = new double[4]); |
|
581 |
double shearx = textAt.getShearX(); |
|
582 |
double scaley = textAt.getScaleY(); |
|
583 |
if (shearx != 0) { |
|
584 |
scaley = Math.sqrt(shearx * shearx + scaley * scaley); |
|
585 |
} |
|
586 |
info.pixelHeight = (int)(Math.abs(scaley)+0.5); |
|
587 |
} else { |
|
588 |
txFontType = AffineTransform.TYPE_IDENTITY; |
|
589 |
info.originX = info.originY = 0; |
|
590 |
if (transformState >= TRANSFORM_TRANSLATESCALE) { |
|
591 |
transform.getMatrix(info.devTx = new double[4]); |
|
592 |
devAt = new AffineTransform(info.devTx); |
|
593 |
info.glyphTx = new double[4]; |
|
594 |
for (int i = 0; i < 4; i++) { |
|
595 |
info.glyphTx[i] = info.devTx[i] * ptSize; |
|
596 |
} |
|
597 |
textAt = new AffineTransform(info.glyphTx); |
|
598 |
double shearx = transform.getShearX(); |
|
599 |
double scaley = transform.getScaleY(); |
|
600 |
if (shearx != 0) { |
|
601 |
scaley = Math.sqrt(shearx * shearx + scaley * scaley); |
|
602 |
} |
|
603 |
info.pixelHeight = (int)(Math.abs(scaley * ptSize)+0.5); |
|
604 |
} else { |
|
605 |
/* If the double represents a common integral, we |
|
606 |
* may have pre-allocated objects. |
|
607 |
* A "sparse" array be seems to be as fast as a switch |
|
608 |
* even for 3 or 4 pt sizes, and is more flexible. |
|
609 |
* This should perform comparably in single-threaded |
|
610 |
* rendering to the old code which synchronized on the |
|
611 |
* class and scale better on MP systems. |
|
612 |
*/ |
|
613 |
int pszInt = (int)ptSize; |
|
614 |
if (ptSize == pszInt && |
|
615 |
pszInt >= MINALLOCATED && pszInt < TEXTARRSIZE) { |
|
616 |
info.glyphTx = textTxArr[pszInt]; |
|
617 |
textAt = textAtArr[pszInt]; |
|
618 |
info.pixelHeight = pszInt; |
|
619 |
} else { |
|
620 |
info.pixelHeight = (int)(ptSize+0.5); |
|
621 |
} |
|
622 |
if (textAt == null) { |
|
623 |
info.glyphTx = new double[] {ptSize, 0, 0, ptSize}; |
|
624 |
textAt = new AffineTransform(info.glyphTx); |
|
625 |
} |
|
626 |
||
627 |
info.devTx = IDENT_MATRIX; |
|
628 |
devAt = IDENT_ATX; |
|
629 |
} |
|
630 |
} |
|
631 |
||
3928 | 632 |
info.font2D = FontUtilities.getFont2D(font); |
2 | 633 |
|
634 |
int fmhint = fractionalMetricsHint; |
|
635 |
if (fmhint == SunHints.INTVAL_FRACTIONALMETRICS_DEFAULT) { |
|
636 |
fmhint = SunHints.INTVAL_FRACTIONALMETRICS_OFF; |
|
637 |
} |
|
638 |
info.lcdSubPixPos = false; // conditionally set true in LCD mode. |
|
639 |
||
640 |
/* The text anti-aliasing hints that are set by the client need |
|
641 |
* to be interpreted for the current state and stored in the |
|
642 |
* FontInfo.aahint which is what will actually be used and |
|
643 |
* will be one of OFF, ON, LCD_HRGB or LCD_VRGB. |
|
644 |
* This is what pipe selection code should typically refer to, not |
|
645 |
* textAntialiasHint. This means we are now evaluating the meaning |
|
646 |
* of "default" here. Any pipe that really cares about that will |
|
647 |
* also need to consult that variable. |
|
648 |
* Otherwise these are being used only as args to getStrike, |
|
649 |
* and are encapsulated in that object which is part of the |
|
650 |
* FontInfo, so we do not need to store them directly as fields |
|
651 |
* in the FontInfo object. |
|
652 |
* That could change if FontInfo's were more selectively |
|
653 |
* revalidated when graphics state changed. Presently this |
|
654 |
* method re-evaluates all fields in the fontInfo. |
|
655 |
* The strike doesn't need to know the RGB subpixel order. Just |
|
656 |
* if its H or V orientation, so if an LCD option is specified we |
|
657 |
* always pass in the RGB hint to the strike. |
|
658 |
* frc is non-null only if this is a GlyphVector. For reasons |
|
659 |
* which are probably a historical mistake the AA hint in a GV |
|
660 |
* is honoured when we render, overriding the Graphics setting. |
|
661 |
*/ |
|
662 |
int aahint; |
|
663 |
if (frc == null) { |
|
664 |
aahint = textAntialiasHint; |
|
665 |
} else { |
|
666 |
aahint = ((SunHints.Value)frc.getAntiAliasingHint()).getIndex(); |
|
667 |
} |
|
668 |
if (aahint == SunHints.INTVAL_TEXT_ANTIALIAS_DEFAULT) { |
|
669 |
if (antialiasHint == SunHints.INTVAL_ANTIALIAS_ON) { |
|
670 |
aahint = SunHints.INTVAL_TEXT_ANTIALIAS_ON; |
|
671 |
} else { |
|
672 |
aahint = SunHints.INTVAL_TEXT_ANTIALIAS_OFF; |
|
673 |
} |
|
674 |
} else { |
|
675 |
/* If we are in checkFontInfo because a rendering hint has been |
|
676 |
* set then all pipes are revalidated. But we can also |
|
677 |
* be here because setFont() has been called when the 'gasp' |
|
678 |
* hint is set, as then the font size determines the text pipe. |
|
679 |
* See comments in SunGraphics2d.setFont(Font). |
|
680 |
*/ |
|
681 |
if (aahint == SunHints.INTVAL_TEXT_ANTIALIAS_GASP) { |
|
682 |
if (info.font2D.useAAForPtSize(info.pixelHeight)) { |
|
683 |
aahint = SunHints.INTVAL_TEXT_ANTIALIAS_ON; |
|
684 |
} else { |
|
685 |
aahint = SunHints.INTVAL_TEXT_ANTIALIAS_OFF; |
|
686 |
} |
|
687 |
} else if (aahint >= SunHints.INTVAL_TEXT_ANTIALIAS_LCD_HRGB) { |
|
688 |
/* loops for default rendering modes are installed in the SG2D |
|
689 |
* constructor. If there are none this will be null. |
|
690 |
* Not all compositing modes update the render loops, so |
|
691 |
* we also test that this is a mode we know should support |
|
692 |
* this. One minor issue is that the loops aren't necessarily |
|
693 |
* installed for a new rendering mode until after this |
|
694 |
* method is called during pipeline validation. So it is |
|
695 |
* theoretically possible that it was set to null for a |
|
696 |
* compositing mode, the composite is then set back to Src, |
|
697 |
* but the loop is still null when this is called and AA=ON |
|
698 |
* is installed instead of an LCD mode. |
|
699 |
* However this is done in the right order in SurfaceData.java |
|
700 |
* so this is not likely to be a problem - but not |
|
701 |
* guaranteed. |
|
702 |
*/ |
|
703 |
if ( |
|
704 |
!surfaceData.canRenderLCDText(this) |
|
705 |
// loops.drawGlyphListLCDLoop == null || |
|
706 |
// compositeState > COMP_ISCOPY || |
|
707 |
// paintState > PAINT_ALPHACOLOR |
|
708 |
) { |
|
709 |
aahint = SunHints.INTVAL_TEXT_ANTIALIAS_ON; |
|
710 |
} else { |
|
711 |
info.lcdRGBOrder = true; |
|
712 |
/* Collapse these into just HRGB or VRGB. |
|
713 |
* Pipe selection code needs only to test for these two. |
|
714 |
* Since these both select the same pipe anyway its |
|
715 |
* tempting to collapse into one value. But they are |
|
716 |
* different strikes (glyph caches) so the distinction |
|
717 |
* needs to be made for that purpose. |
|
718 |
*/ |
|
719 |
if (aahint == SunHints.INTVAL_TEXT_ANTIALIAS_LCD_HBGR) { |
|
720 |
aahint = SunHints.INTVAL_TEXT_ANTIALIAS_LCD_HRGB; |
|
721 |
info.lcdRGBOrder = false; |
|
722 |
} else if |
|
723 |
(aahint == SunHints.INTVAL_TEXT_ANTIALIAS_LCD_VBGR) { |
|
724 |
aahint = SunHints.INTVAL_TEXT_ANTIALIAS_LCD_VRGB; |
|
725 |
info.lcdRGBOrder = false; |
|
726 |
} |
|
727 |
/* Support subpixel positioning only for the case in |
|
728 |
* which the horizontal resolution is increased |
|
729 |
*/ |
|
730 |
info.lcdSubPixPos = |
|
731 |
fmhint == SunHints.INTVAL_FRACTIONALMETRICS_ON && |
|
732 |
aahint == SunHints.INTVAL_TEXT_ANTIALIAS_LCD_HRGB; |
|
733 |
} |
|
734 |
} |
|
735 |
} |
|
736 |
info.aaHint = aahint; |
|
737 |
info.fontStrike = info.font2D.getStrike(font, devAt, textAt, |
|
738 |
aahint, fmhint); |
|
739 |
return info; |
|
740 |
} |
|
741 |
||
742 |
public static boolean isRotated(double [] mtx) { |
|
743 |
if ((mtx[0] == mtx[3]) && |
|
744 |
(mtx[1] == 0.0) && |
|
745 |
(mtx[2] == 0.0) && |
|
746 |
(mtx[0] > 0.0)) |
|
747 |
{ |
|
748 |
return false; |
|
749 |
} |
|
750 |
||
751 |
return true; |
|
752 |
} |
|
753 |
||
754 |
public void setFont(Font font) { |
|
755 |
/* replacing the reference equality test font != this.font with |
|
756 |
* !font.equals(this.font) did not yield any measurable difference |
|
757 |
* in testing, but there may be yet to be identified cases where it |
|
758 |
* is beneficial. |
|
759 |
*/ |
|
760 |
if (font != null && font!=this.font/*!font.equals(this.font)*/) { |
|
761 |
/* In the GASP AA case the textpipe depends on the glyph size |
|
762 |
* as determined by graphics and font transforms as well as the |
|
763 |
* font size, and information in the font. But we may invalidate |
|
764 |
* the pipe only to find that it made no difference. |
|
765 |
* Deferring pipe invalidation to checkFontInfo won't work because |
|
766 |
* when called we may already be rendering to the wrong pipe. |
|
767 |
* So, if the font is transformed, or the graphics has more than |
|
768 |
* a simple scale, we'll take that as enough of a hint to |
|
769 |
* revalidate everything. But if they aren't we will |
|
770 |
* use the font's point size to query the gasp table and see if |
|
771 |
* what it says matches what's currently being used, in which |
|
772 |
* case there's no need to invalidate the textpipe. |
|
773 |
* This should be sufficient for all typical uses cases. |
|
774 |
*/ |
|
775 |
if (textAntialiasHint == SunHints.INTVAL_TEXT_ANTIALIAS_GASP && |
|
776 |
textpipe != invalidpipe && |
|
777 |
(transformState > TRANSFORM_ANY_TRANSLATE || |
|
778 |
font.isTransformed() || |
|
779 |
fontInfo == null || // Precaution, if true shouldn't get here |
|
780 |
(fontInfo.aaHint == SunHints.INTVAL_TEXT_ANTIALIAS_ON) != |
|
3928 | 781 |
FontUtilities.getFont2D(font). |
782 |
useAAForPtSize(font.getSize()))) { |
|
2 | 783 |
textpipe = invalidpipe; |
784 |
} |
|
785 |
this.font = font; |
|
786 |
this.fontMetrics = null; |
|
787 |
this.validFontInfo = false; |
|
788 |
} |
|
789 |
} |
|
790 |
||
791 |
public FontInfo getFontInfo() { |
|
792 |
if (!validFontInfo) { |
|
793 |
this.fontInfo = checkFontInfo(this.fontInfo, font, null); |
|
794 |
validFontInfo = true; |
|
795 |
} |
|
796 |
return this.fontInfo; |
|
797 |
} |
|
798 |
||
799 |
/* Used by drawGlyphVector which specifies its own font. */ |
|
800 |
public FontInfo getGVFontInfo(Font font, FontRenderContext frc) { |
|
801 |
if (glyphVectorFontInfo != null && |
|
802 |
glyphVectorFontInfo.font == font && |
|
803 |
glyphVectorFRC == frc) { |
|
804 |
return glyphVectorFontInfo; |
|
805 |
} else { |
|
806 |
glyphVectorFRC = frc; |
|
807 |
return glyphVectorFontInfo = |
|
808 |
checkFontInfo(glyphVectorFontInfo, font, frc); |
|
809 |
} |
|
810 |
} |
|
811 |
||
812 |
public FontMetrics getFontMetrics() { |
|
813 |
if (this.fontMetrics != null) { |
|
814 |
return this.fontMetrics; |
|
815 |
} |
|
816 |
/* NB the constructor and the setter disallow "font" being null */ |
|
817 |
return this.fontMetrics = |
|
818 |
FontDesignMetrics.getMetrics(font, getFontRenderContext()); |
|
819 |
} |
|
820 |
||
821 |
public FontMetrics getFontMetrics(Font font) { |
|
822 |
if ((this.fontMetrics != null) && (font == this.font)) { |
|
823 |
return this.fontMetrics; |
|
824 |
} |
|
825 |
FontMetrics fm = |
|
826 |
FontDesignMetrics.getMetrics(font, getFontRenderContext()); |
|
827 |
||
828 |
if (this.font == font) { |
|
829 |
this.fontMetrics = fm; |
|
830 |
} |
|
831 |
return fm; |
|
832 |
} |
|
833 |
||
834 |
/** |
|
835 |
* Checks to see if a Path intersects the specified Rectangle in device |
|
836 |
* space. The rendering attributes taken into account include the |
|
837 |
* clip, transform, and stroke attributes. |
|
838 |
* @param rect The area in device space to check for a hit. |
|
839 |
* @param p The path to check for a hit. |
|
840 |
* @param onStroke Flag to choose between testing the stroked or |
|
841 |
* the filled path. |
|
842 |
* @return True if there is a hit, false otherwise. |
|
843 |
* @see #setStroke |
|
844 |
* @see #fillPath |
|
845 |
* @see #drawPath |
|
846 |
* @see #transform |
|
847 |
* @see #setTransform |
|
848 |
* @see #clip |
|
849 |
* @see #setClip |
|
850 |
*/ |
|
851 |
public boolean hit(Rectangle rect, Shape s, boolean onStroke) { |
|
852 |
if (onStroke) { |
|
853 |
s = stroke.createStrokedShape(s); |
|
854 |
} |
|
855 |
||
856 |
s = transformShape(s); |
|
857 |
if ((constrainX|constrainY) != 0) { |
|
858 |
rect = new Rectangle(rect); |
|
859 |
rect.translate(constrainX, constrainY); |
|
860 |
} |
|
861 |
||
862 |
return s.intersects(rect); |
|
863 |
} |
|
864 |
||
865 |
/** |
|
866 |
* Return the ColorModel associated with this Graphics2D. |
|
867 |
*/ |
|
868 |
public ColorModel getDeviceColorModel() { |
|
869 |
return surfaceData.getColorModel(); |
|
870 |
} |
|
871 |
||
872 |
/** |
|
873 |
* Return the device configuration associated with this Graphics2D. |
|
874 |
*/ |
|
875 |
public GraphicsConfiguration getDeviceConfiguration() { |
|
876 |
return surfaceData.getDeviceConfiguration(); |
|
877 |
} |
|
878 |
||
879 |
/** |
|
880 |
* Return the SurfaceData object assigned to manage the destination |
|
881 |
* drawable surface of this Graphics2D. |
|
882 |
*/ |
|
883 |
public final SurfaceData getSurfaceData() { |
|
884 |
return surfaceData; |
|
885 |
} |
|
886 |
||
887 |
/** |
|
888 |
* Sets the Composite in the current graphics state. Composite is used |
|
889 |
* in all drawing methods such as drawImage, drawString, drawPath, |
|
890 |
* and fillPath. It specifies how new pixels are to be combined with |
|
891 |
* the existing pixels on the graphics device in the rendering process. |
|
892 |
* @param comp The Composite object to be used for drawing. |
|
893 |
* @see java.awt.Graphics#setXORMode |
|
894 |
* @see java.awt.Graphics#setPaintMode |
|
895 |
* @see AlphaComposite |
|
896 |
*/ |
|
897 |
public void setComposite(Composite comp) { |
|
898 |
if (composite == comp) { |
|
899 |
return; |
|
900 |
} |
|
901 |
int newCompState; |
|
902 |
CompositeType newCompType; |
|
903 |
if (comp instanceof AlphaComposite) { |
|
904 |
AlphaComposite alphacomp = (AlphaComposite) comp; |
|
905 |
newCompType = CompositeType.forAlphaComposite(alphacomp); |
|
906 |
if (newCompType == CompositeType.SrcOverNoEa) { |
|
907 |
if (paintState == PAINT_OPAQUECOLOR || |
|
908 |
(paintState > PAINT_ALPHACOLOR && |
|
909 |
paint.getTransparency() == Transparency.OPAQUE)) |
|
910 |
{ |
|
911 |
newCompState = COMP_ISCOPY; |
|
912 |
} else { |
|
913 |
newCompState = COMP_ALPHA; |
|
914 |
} |
|
915 |
} else if (newCompType == CompositeType.SrcNoEa || |
|
916 |
newCompType == CompositeType.Src || |
|
917 |
newCompType == CompositeType.Clear) |
|
918 |
{ |
|
919 |
newCompState = COMP_ISCOPY; |
|
920 |
} else if (surfaceData.getTransparency() == Transparency.OPAQUE && |
|
921 |
newCompType == CompositeType.SrcIn) |
|
922 |
{ |
|
923 |
newCompState = COMP_ISCOPY; |
|
924 |
} else { |
|
925 |
newCompState = COMP_ALPHA; |
|
926 |
} |
|
927 |
} else if (comp instanceof XORComposite) { |
|
928 |
newCompState = COMP_XOR; |
|
929 |
newCompType = CompositeType.Xor; |
|
930 |
} else if (comp == null) { |
|
931 |
throw new IllegalArgumentException("null Composite"); |
|
932 |
} else { |
|
933 |
surfaceData.checkCustomComposite(); |
|
934 |
newCompState = COMP_CUSTOM; |
|
935 |
newCompType = CompositeType.General; |
|
936 |
} |
|
937 |
if (compositeState != newCompState || |
|
938 |
imageComp != newCompType) |
|
939 |
{ |
|
940 |
compositeState = newCompState; |
|
941 |
imageComp = newCompType; |
|
942 |
invalidatePipe(); |
|
943 |
validFontInfo = false; |
|
944 |
} |
|
945 |
composite = comp; |
|
946 |
if (paintState <= PAINT_ALPHACOLOR) { |
|
947 |
validateColor(); |
|
948 |
} |
|
949 |
} |
|
950 |
||
951 |
/** |
|
952 |
* Sets the Paint in the current graphics state. |
|
953 |
* @param paint The Paint object to be used to generate color in |
|
954 |
* the rendering process. |
|
955 |
* @see java.awt.Graphics#setColor |
|
956 |
* @see GradientPaint |
|
957 |
* @see TexturePaint |
|
958 |
*/ |
|
959 |
public void setPaint(Paint paint) { |
|
960 |
if (paint instanceof Color) { |
|
961 |
setColor((Color) paint); |
|
962 |
return; |
|
963 |
} |
|
964 |
if (paint == null || this.paint == paint) { |
|
965 |
return; |
|
966 |
} |
|
967 |
this.paint = paint; |
|
968 |
if (imageComp == CompositeType.SrcOverNoEa) { |
|
969 |
// special case where compState depends on opacity of paint |
|
970 |
if (paint.getTransparency() == Transparency.OPAQUE) { |
|
971 |
if (compositeState != COMP_ISCOPY) { |
|
972 |
compositeState = COMP_ISCOPY; |
|
973 |
} |
|
974 |
} else { |
|
975 |
if (compositeState == COMP_ISCOPY) { |
|
976 |
compositeState = COMP_ALPHA; |
|
977 |
} |
|
978 |
} |
|
979 |
} |
|
11080
7e18e343964e
7117914: Fix javac warnings in src/share/classes/sun/java2d
neugens
parents:
5506
diff
changeset
|
980 |
Class<? extends Paint> paintClass = paint.getClass(); |
2 | 981 |
if (paintClass == GradientPaint.class) { |
982 |
paintState = PAINT_GRADIENT; |
|
983 |
} else if (paintClass == LinearGradientPaint.class) { |
|
984 |
paintState = PAINT_LIN_GRADIENT; |
|
985 |
} else if (paintClass == RadialGradientPaint.class) { |
|
986 |
paintState = PAINT_RAD_GRADIENT; |
|
987 |
} else if (paintClass == TexturePaint.class) { |
|
988 |
paintState = PAINT_TEXTURE; |
|
989 |
} else { |
|
990 |
paintState = PAINT_CUSTOM; |
|
991 |
} |
|
992 |
validFontInfo = false; |
|
993 |
invalidatePipe(); |
|
994 |
} |
|
995 |
||
996 |
static final int NON_UNIFORM_SCALE_MASK = |
|
997 |
(AffineTransform.TYPE_GENERAL_TRANSFORM | |
|
998 |
AffineTransform.TYPE_GENERAL_SCALE); |
|
999 |
public static final double MinPenSizeAA = |
|
1000 |
sun.java2d.pipe.RenderingEngine.getInstance().getMinimumAAPenSize(); |
|
1001 |
public static final double MinPenSizeAASquared = |
|
1002 |
(MinPenSizeAA * MinPenSizeAA); |
|
1003 |
// Since inaccuracies in the trig package can cause us to |
|
1004 |
// calculated a rotated pen width of just slightly greater |
|
1005 |
// than 1.0, we add a fudge factor to our comparison value |
|
1006 |
// here so that we do not misclassify single width lines as |
|
1007 |
// wide lines under certain rotations. |
|
1008 |
public static final double MinPenSizeSquared = 1.000000001; |
|
1009 |
||
1010 |
private void validateBasicStroke(BasicStroke bs) { |
|
1011 |
boolean aa = (antialiasHint == SunHints.INTVAL_ANTIALIAS_ON); |
|
1012 |
if (transformState < TRANSFORM_TRANSLATESCALE) { |
|
1013 |
if (aa) { |
|
1014 |
if (bs.getLineWidth() <= MinPenSizeAA) { |
|
1015 |
if (bs.getDashArray() == null) { |
|
1016 |
strokeState = STROKE_THIN; |
|
1017 |
} else { |
|
1018 |
strokeState = STROKE_THINDASHED; |
|
1019 |
} |
|
1020 |
} else { |
|
1021 |
strokeState = STROKE_WIDE; |
|
1022 |
} |
|
1023 |
} else { |
|
1024 |
if (bs == defaultStroke) { |
|
1025 |
strokeState = STROKE_THIN; |
|
1026 |
} else if (bs.getLineWidth() <= 1.0f) { |
|
1027 |
if (bs.getDashArray() == null) { |
|
1028 |
strokeState = STROKE_THIN; |
|
1029 |
} else { |
|
1030 |
strokeState = STROKE_THINDASHED; |
|
1031 |
} |
|
1032 |
} else { |
|
1033 |
strokeState = STROKE_WIDE; |
|
1034 |
} |
|
1035 |
} |
|
1036 |
} else { |
|
1037 |
double widthsquared; |
|
1038 |
if ((transform.getType() & NON_UNIFORM_SCALE_MASK) == 0) { |
|
1039 |
/* sqrt omitted, compare to squared limits below. */ |
|
1040 |
widthsquared = Math.abs(transform.getDeterminant()); |
|
1041 |
} else { |
|
1042 |
/* First calculate the "maximum scale" of this transform. */ |
|
1043 |
double A = transform.getScaleX(); // m00 |
|
1044 |
double C = transform.getShearX(); // m01 |
|
1045 |
double B = transform.getShearY(); // m10 |
|
1046 |
double D = transform.getScaleY(); // m11 |
|
1047 |
||
1048 |
/* |
|
1049 |
* Given a 2 x 2 affine matrix [ A B ] such that |
|
1050 |
* [ C D ] |
|
1051 |
* v' = [x' y'] = [Ax + Cy, Bx + Dy], we want to |
|
1052 |
* find the maximum magnitude (norm) of the vector v' |
|
1053 |
* with the constraint (x^2 + y^2 = 1). |
|
1054 |
* The equation to maximize is |
|
1055 |
* |v'| = sqrt((Ax+Cy)^2+(Bx+Dy)^2) |
|
1056 |
* or |v'| = sqrt((AA+BB)x^2 + 2(AC+BD)xy + (CC+DD)y^2). |
|
1057 |
* Since sqrt is monotonic we can maximize |v'|^2 |
|
1058 |
* instead and plug in the substitution y = sqrt(1 - x^2). |
|
1059 |
* Trigonometric equalities can then be used to get |
|
1060 |
* rid of most of the sqrt terms. |
|
1061 |
*/ |
|
1062 |
double EA = A*A + B*B; // x^2 coefficient |
|
1063 |
double EB = 2*(A*C + B*D); // xy coefficient |
|
1064 |
double EC = C*C + D*D; // y^2 coefficient |
|
1065 |
||
1066 |
/* |
|
1067 |
* There is a lot of calculus omitted here. |
|
1068 |
* |
|
1069 |
* Conceptually, in the interests of understanding the |
|
1070 |
* terms that the calculus produced we can consider |
|
1071 |
* that EA and EC end up providing the lengths along |
|
1072 |
* the major axes and the hypot term ends up being an |
|
1073 |
* adjustment for the additional length along the off-axis |
|
1074 |
* angle of rotated or sheared ellipses as well as an |
|
1075 |
* adjustment for the fact that the equation below |
|
1076 |
* averages the two major axis lengths. (Notice that |
|
1077 |
* the hypot term contains a part which resolves to the |
|
1078 |
* difference of these two axis lengths in the absence |
|
1079 |
* of rotation.) |
|
1080 |
* |
|
1081 |
* In the calculus, the ratio of the EB and (EA-EC) terms |
|
1082 |
* ends up being the tangent of 2*theta where theta is |
|
1083 |
* the angle that the long axis of the ellipse makes |
|
1084 |
* with the horizontal axis. Thus, this equation is |
|
1085 |
* calculating the length of the hypotenuse of a triangle |
|
1086 |
* along that axis. |
|
1087 |
*/ |
|
1088 |
double hypot = Math.sqrt(EB*EB + (EA-EC)*(EA-EC)); |
|
1089 |
||
1090 |
/* sqrt omitted, compare to squared limits below. */ |
|
1091 |
widthsquared = ((EA + EC + hypot)/2.0); |
|
1092 |
} |
|
1093 |
if (bs != defaultStroke) { |
|
1094 |
widthsquared *= bs.getLineWidth() * bs.getLineWidth(); |
|
1095 |
} |
|
1096 |
if (widthsquared <= |
|
1097 |
(aa ? MinPenSizeAASquared : MinPenSizeSquared)) |
|
1098 |
{ |
|
1099 |
if (bs.getDashArray() == null) { |
|
1100 |
strokeState = STROKE_THIN; |
|
1101 |
} else { |
|
1102 |
strokeState = STROKE_THINDASHED; |
|
1103 |
} |
|
1104 |
} else { |
|
1105 |
strokeState = STROKE_WIDE; |
|
1106 |
} |
|
1107 |
} |
|
1108 |
} |
|
1109 |
||
1110 |
/* |
|
1111 |
* Sets the Stroke in the current graphics state. |
|
1112 |
* @param s The Stroke object to be used to stroke a Path in |
|
1113 |
* the rendering process. |
|
1114 |
* @see BasicStroke |
|
1115 |
*/ |
|
1116 |
public void setStroke(Stroke s) { |
|
1117 |
if (s == null) { |
|
1118 |
throw new IllegalArgumentException("null Stroke"); |
|
1119 |
} |
|
1120 |
int saveStrokeState = strokeState; |
|
1121 |
stroke = s; |
|
1122 |
if (s instanceof BasicStroke) { |
|
1123 |
validateBasicStroke((BasicStroke) s); |
|
1124 |
} else { |
|
1125 |
strokeState = STROKE_CUSTOM; |
|
1126 |
} |
|
1127 |
if (strokeState != saveStrokeState) { |
|
1128 |
invalidatePipe(); |
|
1129 |
} |
|
1130 |
} |
|
1131 |
||
1132 |
/** |
|
1133 |
* Sets the preferences for the rendering algorithms. |
|
1134 |
* Hint categories include controls for rendering quality and |
|
1135 |
* overall time/quality trade-off in the rendering process. |
|
1136 |
* @param hintKey The key of hint to be set. The strings are |
|
1137 |
* defined in the RenderingHints class. |
|
1138 |
* @param hintValue The value indicating preferences for the specified |
|
1139 |
* hint category. These strings are defined in the RenderingHints |
|
1140 |
* class. |
|
1141 |
* @see RenderingHints |
|
1142 |
*/ |
|
1143 |
public void setRenderingHint(Key hintKey, Object hintValue) { |
|
1144 |
// If we recognize the key, we must recognize the value |
|
1145 |
// otherwise throw an IllegalArgumentException |
|
1146 |
// and do not change the Hints object |
|
1147 |
// If we do not recognize the key, just pass it through |
|
1148 |
// to the Hints object untouched |
|
1149 |
if (!hintKey.isCompatibleValue(hintValue)) { |
|
1150 |
throw new IllegalArgumentException |
|
1151 |
(hintValue+" is not compatible with "+hintKey); |
|
1152 |
} |
|
1153 |
if (hintKey instanceof SunHints.Key) { |
|
1154 |
boolean stateChanged; |
|
1155 |
boolean textStateChanged = false; |
|
1156 |
boolean recognized = true; |
|
1157 |
SunHints.Key sunKey = (SunHints.Key) hintKey; |
|
1158 |
int newHint; |
|
1159 |
if (sunKey == SunHints.KEY_TEXT_ANTIALIAS_LCD_CONTRAST) { |
|
1160 |
newHint = ((Integer)hintValue).intValue(); |
|
1161 |
} else { |
|
1162 |
newHint = ((SunHints.Value) hintValue).getIndex(); |
|
1163 |
} |
|
1164 |
switch (sunKey.getIndex()) { |
|
1165 |
case SunHints.INTKEY_RENDERING: |
|
1166 |
stateChanged = (renderHint != newHint); |
|
1167 |
if (stateChanged) { |
|
1168 |
renderHint = newHint; |
|
1169 |
if (interpolationHint == -1) { |
|
1170 |
interpolationType = |
|
1171 |
(newHint == SunHints.INTVAL_RENDER_QUALITY |
|
1172 |
? AffineTransformOp.TYPE_BILINEAR |
|
1173 |
: AffineTransformOp.TYPE_NEAREST_NEIGHBOR); |
|
1174 |
} |
|
1175 |
} |
|
1176 |
break; |
|
1177 |
case SunHints.INTKEY_ANTIALIASING: |
|
1178 |
stateChanged = (antialiasHint != newHint); |
|
1179 |
antialiasHint = newHint; |
|
1180 |
if (stateChanged) { |
|
1181 |
textStateChanged = |
|
1182 |
(textAntialiasHint == |
|
1183 |
SunHints.INTVAL_TEXT_ANTIALIAS_DEFAULT); |
|
1184 |
if (strokeState != STROKE_CUSTOM) { |
|
1185 |
validateBasicStroke((BasicStroke) stroke); |
|
1186 |
} |
|
1187 |
} |
|
1188 |
break; |
|
1189 |
case SunHints.INTKEY_TEXT_ANTIALIASING: |
|
1190 |
stateChanged = (textAntialiasHint != newHint); |
|
1191 |
textStateChanged = stateChanged; |
|
1192 |
textAntialiasHint = newHint; |
|
1193 |
break; |
|
1194 |
case SunHints.INTKEY_FRACTIONALMETRICS: |
|
1195 |
stateChanged = (fractionalMetricsHint != newHint); |
|
1196 |
textStateChanged = stateChanged; |
|
1197 |
fractionalMetricsHint = newHint; |
|
1198 |
break; |
|
1199 |
case SunHints.INTKEY_AATEXT_LCD_CONTRAST: |
|
1200 |
stateChanged = false; |
|
1201 |
/* Already have validated it is an int 100 <= newHint <= 250 */ |
|
1202 |
lcdTextContrast = newHint; |
|
1203 |
break; |
|
1204 |
case SunHints.INTKEY_INTERPOLATION: |
|
1205 |
interpolationHint = newHint; |
|
1206 |
switch (newHint) { |
|
1207 |
case SunHints.INTVAL_INTERPOLATION_BICUBIC: |
|
1208 |
newHint = AffineTransformOp.TYPE_BICUBIC; |
|
1209 |
break; |
|
1210 |
case SunHints.INTVAL_INTERPOLATION_BILINEAR: |
|
1211 |
newHint = AffineTransformOp.TYPE_BILINEAR; |
|
1212 |
break; |
|
1213 |
default: |
|
1214 |
case SunHints.INTVAL_INTERPOLATION_NEAREST_NEIGHBOR: |
|
1215 |
newHint = AffineTransformOp.TYPE_NEAREST_NEIGHBOR; |
|
1216 |
break; |
|
1217 |
} |
|
1218 |
stateChanged = (interpolationType != newHint); |
|
1219 |
interpolationType = newHint; |
|
1220 |
break; |
|
1221 |
case SunHints.INTKEY_STROKE_CONTROL: |
|
1222 |
stateChanged = (strokeHint != newHint); |
|
1223 |
strokeHint = newHint; |
|
1224 |
break; |
|
1225 |
default: |
|
1226 |
recognized = false; |
|
1227 |
stateChanged = false; |
|
1228 |
break; |
|
1229 |
} |
|
1230 |
if (recognized) { |
|
1231 |
if (stateChanged) { |
|
1232 |
invalidatePipe(); |
|
1233 |
if (textStateChanged) { |
|
1234 |
fontMetrics = null; |
|
1235 |
this.cachedFRC = null; |
|
1236 |
validFontInfo = false; |
|
1237 |
this.glyphVectorFontInfo = null; |
|
1238 |
} |
|
1239 |
} |
|
1240 |
if (hints != null) { |
|
1241 |
hints.put(hintKey, hintValue); |
|
1242 |
} |
|
1243 |
return; |
|
1244 |
} |
|
1245 |
} |
|
1246 |
// Nothing we recognize so none of "our state" has changed |
|
1247 |
if (hints == null) { |
|
1248 |
hints = makeHints(null); |
|
1249 |
} |
|
1250 |
hints.put(hintKey, hintValue); |
|
1251 |
} |
|
1252 |
||
1253 |
||
1254 |
/** |
|
1255 |
* Returns the preferences for the rendering algorithms. |
|
1256 |
* @param hintCategory The category of hint to be set. The strings |
|
1257 |
* are defined in the RenderingHints class. |
|
1258 |
* @return The preferences for rendering algorithms. The strings |
|
1259 |
* are defined in the RenderingHints class. |
|
1260 |
* @see RenderingHints |
|
1261 |
*/ |
|
1262 |
public Object getRenderingHint(Key hintKey) { |
|
1263 |
if (hints != null) { |
|
1264 |
return hints.get(hintKey); |
|
1265 |
} |
|
1266 |
if (!(hintKey instanceof SunHints.Key)) { |
|
1267 |
return null; |
|
1268 |
} |
|
1269 |
int keyindex = ((SunHints.Key)hintKey).getIndex(); |
|
1270 |
switch (keyindex) { |
|
1271 |
case SunHints.INTKEY_RENDERING: |
|
1272 |
return SunHints.Value.get(SunHints.INTKEY_RENDERING, |
|
1273 |
renderHint); |
|
1274 |
case SunHints.INTKEY_ANTIALIASING: |
|
1275 |
return SunHints.Value.get(SunHints.INTKEY_ANTIALIASING, |
|
1276 |
antialiasHint); |
|
1277 |
case SunHints.INTKEY_TEXT_ANTIALIASING: |
|
1278 |
return SunHints.Value.get(SunHints.INTKEY_TEXT_ANTIALIASING, |
|
1279 |
textAntialiasHint); |
|
1280 |
case SunHints.INTKEY_FRACTIONALMETRICS: |
|
1281 |
return SunHints.Value.get(SunHints.INTKEY_FRACTIONALMETRICS, |
|
1282 |
fractionalMetricsHint); |
|
1283 |
case SunHints.INTKEY_AATEXT_LCD_CONTRAST: |
|
1284 |
return new Integer(lcdTextContrast); |
|
1285 |
case SunHints.INTKEY_INTERPOLATION: |
|
1286 |
switch (interpolationHint) { |
|
1287 |
case SunHints.INTVAL_INTERPOLATION_NEAREST_NEIGHBOR: |
|
1288 |
return SunHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR; |
|
1289 |
case SunHints.INTVAL_INTERPOLATION_BILINEAR: |
|
1290 |
return SunHints.VALUE_INTERPOLATION_BILINEAR; |
|
1291 |
case SunHints.INTVAL_INTERPOLATION_BICUBIC: |
|
1292 |
return SunHints.VALUE_INTERPOLATION_BICUBIC; |
|
1293 |
} |
|
1294 |
return null; |
|
1295 |
case SunHints.INTKEY_STROKE_CONTROL: |
|
1296 |
return SunHints.Value.get(SunHints.INTKEY_STROKE_CONTROL, |
|
1297 |
strokeHint); |
|
1298 |
} |
|
1299 |
return null; |
|
1300 |
} |
|
1301 |
||
1302 |
/** |
|
1303 |
* Sets the preferences for the rendering algorithms. |
|
1304 |
* Hint categories include controls for rendering quality and |
|
1305 |
* overall time/quality trade-off in the rendering process. |
|
1306 |
* @param hints The rendering hints to be set |
|
1307 |
* @see RenderingHints |
|
1308 |
*/ |
|
1309 |
public void setRenderingHints(Map<?,?> hints) { |
|
1310 |
this.hints = null; |
|
1311 |
renderHint = SunHints.INTVAL_RENDER_DEFAULT; |
|
1312 |
antialiasHint = SunHints.INTVAL_ANTIALIAS_OFF; |
|
1313 |
textAntialiasHint = SunHints.INTVAL_TEXT_ANTIALIAS_DEFAULT; |
|
1314 |
fractionalMetricsHint = SunHints.INTVAL_FRACTIONALMETRICS_OFF; |
|
1315 |
lcdTextContrast = lcdTextContrastDefaultValue; |
|
1316 |
interpolationHint = -1; |
|
1317 |
interpolationType = AffineTransformOp.TYPE_NEAREST_NEIGHBOR; |
|
1318 |
boolean customHintPresent = false; |
|
11080
7e18e343964e
7117914: Fix javac warnings in src/share/classes/sun/java2d
neugens
parents:
5506
diff
changeset
|
1319 |
Iterator<?> iter = hints.keySet().iterator(); |
2 | 1320 |
while (iter.hasNext()) { |
1321 |
Object key = iter.next(); |
|
1322 |
if (key == SunHints.KEY_RENDERING || |
|
1323 |
key == SunHints.KEY_ANTIALIASING || |
|
1324 |
key == SunHints.KEY_TEXT_ANTIALIASING || |
|
1325 |
key == SunHints.KEY_FRACTIONALMETRICS || |
|
1326 |
key == SunHints.KEY_TEXT_ANTIALIAS_LCD_CONTRAST || |
|
1327 |
key == SunHints.KEY_STROKE_CONTROL || |
|
1328 |
key == SunHints.KEY_INTERPOLATION) |
|
1329 |
{ |
|
1330 |
setRenderingHint((Key) key, hints.get(key)); |
|
1331 |
} else { |
|
1332 |
customHintPresent = true; |
|
1333 |
} |
|
1334 |
} |
|
1335 |
if (customHintPresent) { |
|
1336 |
this.hints = makeHints(hints); |
|
1337 |
} |
|
1338 |
invalidatePipe(); |
|
1339 |
} |
|
1340 |
||
1341 |
/** |
|
1342 |
* Adds a number of preferences for the rendering algorithms. |
|
1343 |
* Hint categories include controls for rendering quality and |
|
1344 |
* overall time/quality trade-off in the rendering process. |
|
1345 |
* @param hints The rendering hints to be set |
|
1346 |
* @see RenderingHints |
|
1347 |
*/ |
|
1348 |
public void addRenderingHints(Map<?,?> hints) { |
|
1349 |
boolean customHintPresent = false; |
|
11080
7e18e343964e
7117914: Fix javac warnings in src/share/classes/sun/java2d
neugens
parents:
5506
diff
changeset
|
1350 |
Iterator<?> iter = hints.keySet().iterator(); |
2 | 1351 |
while (iter.hasNext()) { |
1352 |
Object key = iter.next(); |
|
1353 |
if (key == SunHints.KEY_RENDERING || |
|
1354 |
key == SunHints.KEY_ANTIALIASING || |
|
1355 |
key == SunHints.KEY_TEXT_ANTIALIASING || |
|
1356 |
key == SunHints.KEY_FRACTIONALMETRICS || |
|
1357 |
key == SunHints.KEY_TEXT_ANTIALIAS_LCD_CONTRAST || |
|
1358 |
key == SunHints.KEY_STROKE_CONTROL || |
|
1359 |
key == SunHints.KEY_INTERPOLATION) |
|
1360 |
{ |
|
1361 |
setRenderingHint((Key) key, hints.get(key)); |
|
1362 |
} else { |
|
1363 |
customHintPresent = true; |
|
1364 |
} |
|
1365 |
} |
|
1366 |
if (customHintPresent) { |
|
1367 |
if (this.hints == null) { |
|
1368 |
this.hints = makeHints(hints); |
|
1369 |
} else { |
|
1370 |
this.hints.putAll(hints); |
|
1371 |
} |
|
1372 |
} |
|
1373 |
} |
|
1374 |
||
1375 |
/** |
|
1376 |
* Gets the preferences for the rendering algorithms. |
|
1377 |
* Hint categories include controls for rendering quality and |
|
1378 |
* overall time/quality trade-off in the rendering process. |
|
1379 |
* @see RenderingHints |
|
1380 |
*/ |
|
1381 |
public RenderingHints getRenderingHints() { |
|
1382 |
if (hints == null) { |
|
1383 |
return makeHints(null); |
|
1384 |
} else { |
|
1385 |
return (RenderingHints) hints.clone(); |
|
1386 |
} |
|
1387 |
} |
|
1388 |
||
1389 |
RenderingHints makeHints(Map hints) { |
|
1390 |
RenderingHints model = new RenderingHints(hints); |
|
1391 |
model.put(SunHints.KEY_RENDERING, |
|
1392 |
SunHints.Value.get(SunHints.INTKEY_RENDERING, |
|
1393 |
renderHint)); |
|
1394 |
model.put(SunHints.KEY_ANTIALIASING, |
|
1395 |
SunHints.Value.get(SunHints.INTKEY_ANTIALIASING, |
|
1396 |
antialiasHint)); |
|
1397 |
model.put(SunHints.KEY_TEXT_ANTIALIASING, |
|
1398 |
SunHints.Value.get(SunHints.INTKEY_TEXT_ANTIALIASING, |
|
1399 |
textAntialiasHint)); |
|
1400 |
model.put(SunHints.KEY_FRACTIONALMETRICS, |
|
1401 |
SunHints.Value.get(SunHints.INTKEY_FRACTIONALMETRICS, |
|
1402 |
fractionalMetricsHint)); |
|
1403 |
model.put(SunHints.KEY_TEXT_ANTIALIAS_LCD_CONTRAST, |
|
438
2ae294e4518c
6613529: Avoid duplicate object creation within JDK packages
dav
parents:
2
diff
changeset
|
1404 |
Integer.valueOf(lcdTextContrast)); |
2 | 1405 |
Object value; |
1406 |
switch (interpolationHint) { |
|
1407 |
case SunHints.INTVAL_INTERPOLATION_NEAREST_NEIGHBOR: |
|
1408 |
value = SunHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR; |
|
1409 |
break; |
|
1410 |
case SunHints.INTVAL_INTERPOLATION_BILINEAR: |
|
1411 |
value = SunHints.VALUE_INTERPOLATION_BILINEAR; |
|
1412 |
break; |
|
1413 |
case SunHints.INTVAL_INTERPOLATION_BICUBIC: |
|
1414 |
value = SunHints.VALUE_INTERPOLATION_BICUBIC; |
|
1415 |
break; |
|
1416 |
default: |
|
1417 |
value = null; |
|
1418 |
break; |
|
1419 |
} |
|
1420 |
if (value != null) { |
|
1421 |
model.put(SunHints.KEY_INTERPOLATION, value); |
|
1422 |
} |
|
1423 |
model.put(SunHints.KEY_STROKE_CONTROL, |
|
1424 |
SunHints.Value.get(SunHints.INTKEY_STROKE_CONTROL, |
|
1425 |
strokeHint)); |
|
1426 |
return model; |
|
1427 |
} |
|
1428 |
||
1429 |
/** |
|
1430 |
* Concatenates the current transform of this Graphics2D with a |
|
1431 |
* translation transformation. |
|
1432 |
* This is equivalent to calling transform(T), where T is an |
|
1433 |
* AffineTransform represented by the following matrix: |
|
1434 |
* <pre> |
|
1435 |
* [ 1 0 tx ] |
|
1436 |
* [ 0 1 ty ] |
|
1437 |
* [ 0 0 1 ] |
|
1438 |
* </pre> |
|
1439 |
*/ |
|
1440 |
public void translate(double tx, double ty) { |
|
1441 |
transform.translate(tx, ty); |
|
1442 |
invalidateTransform(); |
|
1443 |
} |
|
1444 |
||
1445 |
/** |
|
1446 |
* Concatenates the current transform of this Graphics2D with a |
|
1447 |
* rotation transformation. |
|
1448 |
* This is equivalent to calling transform(R), where R is an |
|
1449 |
* AffineTransform represented by the following matrix: |
|
1450 |
* <pre> |
|
1451 |
* [ cos(theta) -sin(theta) 0 ] |
|
1452 |
* [ sin(theta) cos(theta) 0 ] |
|
1453 |
* [ 0 0 1 ] |
|
1454 |
* </pre> |
|
1455 |
* Rotating with a positive angle theta rotates points on the positive |
|
1456 |
* x axis toward the positive y axis. |
|
1457 |
* @param theta The angle of rotation in radians. |
|
1458 |
*/ |
|
1459 |
public void rotate(double theta) { |
|
1460 |
transform.rotate(theta); |
|
1461 |
invalidateTransform(); |
|
1462 |
} |
|
1463 |
||
1464 |
/** |
|
1465 |
* Concatenates the current transform of this Graphics2D with a |
|
1466 |
* translated rotation transformation. |
|
1467 |
* This is equivalent to the following sequence of calls: |
|
1468 |
* <pre> |
|
1469 |
* translate(x, y); |
|
1470 |
* rotate(theta); |
|
1471 |
* translate(-x, -y); |
|
1472 |
* </pre> |
|
1473 |
* Rotating with a positive angle theta rotates points on the positive |
|
1474 |
* x axis toward the positive y axis. |
|
1475 |
* @param theta The angle of rotation in radians. |
|
1476 |
* @param x The x coordinate of the origin of the rotation |
|
1477 |
* @param y The x coordinate of the origin of the rotation |
|
1478 |
*/ |
|
1479 |
public void rotate(double theta, double x, double y) { |
|
1480 |
transform.rotate(theta, x, y); |
|
1481 |
invalidateTransform(); |
|
1482 |
} |
|
1483 |
||
1484 |
/** |
|
1485 |
* Concatenates the current transform of this Graphics2D with a |
|
1486 |
* scaling transformation. |
|
1487 |
* This is equivalent to calling transform(S), where S is an |
|
1488 |
* AffineTransform represented by the following matrix: |
|
1489 |
* <pre> |
|
1490 |
* [ sx 0 0 ] |
|
1491 |
* [ 0 sy 0 ] |
|
1492 |
* [ 0 0 1 ] |
|
1493 |
* </pre> |
|
1494 |
*/ |
|
1495 |
public void scale(double sx, double sy) { |
|
1496 |
transform.scale(sx, sy); |
|
1497 |
invalidateTransform(); |
|
1498 |
} |
|
1499 |
||
1500 |
/** |
|
1501 |
* Concatenates the current transform of this Graphics2D with a |
|
1502 |
* shearing transformation. |
|
1503 |
* This is equivalent to calling transform(SH), where SH is an |
|
1504 |
* AffineTransform represented by the following matrix: |
|
1505 |
* <pre> |
|
1506 |
* [ 1 shx 0 ] |
|
1507 |
* [ shy 1 0 ] |
|
1508 |
* [ 0 0 1 ] |
|
1509 |
* </pre> |
|
1510 |
* @param shx The factor by which coordinates are shifted towards the |
|
1511 |
* positive X axis direction according to their Y coordinate |
|
1512 |
* @param shy The factor by which coordinates are shifted towards the |
|
1513 |
* positive Y axis direction according to their X coordinate |
|
1514 |
*/ |
|
1515 |
public void shear(double shx, double shy) { |
|
1516 |
transform.shear(shx, shy); |
|
1517 |
invalidateTransform(); |
|
1518 |
} |
|
1519 |
||
1520 |
/** |
|
1521 |
* Composes a Transform object with the transform in this |
|
1522 |
* Graphics2D according to the rule last-specified-first-applied. |
|
1523 |
* If the currrent transform is Cx, the result of composition |
|
1524 |
* with Tx is a new transform Cx'. Cx' becomes the current |
|
1525 |
* transform for this Graphics2D. |
|
1526 |
* Transforming a point p by the updated transform Cx' is |
|
1527 |
* equivalent to first transforming p by Tx and then transforming |
|
1528 |
* the result by the original transform Cx. In other words, |
|
1529 |
* Cx'(p) = Cx(Tx(p)). |
|
1530 |
* A copy of the Tx is made, if necessary, so further |
|
1531 |
* modifications to Tx do not affect rendering. |
|
1532 |
* @param Tx The Transform object to be composed with the current |
|
1533 |
* transform. |
|
1534 |
* @see #setTransform |
|
1535 |
* @see AffineTransform |
|
1536 |
*/ |
|
1537 |
public void transform(AffineTransform xform) { |
|
1538 |
this.transform.concatenate(xform); |
|
1539 |
invalidateTransform(); |
|
1540 |
} |
|
1541 |
||
1542 |
/** |
|
1543 |
* Translate |
|
1544 |
*/ |
|
1545 |
public void translate(int x, int y) { |
|
1546 |
transform.translate(x, y); |
|
1547 |
if (transformState <= TRANSFORM_INT_TRANSLATE) { |
|
1548 |
transX += x; |
|
1549 |
transY += y; |
|
1550 |
transformState = (((transX | transY) == 0) ? |
|
1551 |
TRANSFORM_ISIDENT : TRANSFORM_INT_TRANSLATE); |
|
1552 |
} else { |
|
1553 |
invalidateTransform(); |
|
1554 |
} |
|
1555 |
} |
|
1556 |
||
1557 |
/** |
|
1558 |
* Sets the Transform in the current graphics state. |
|
1559 |
* @param Tx The Transform object to be used in the rendering process. |
|
1560 |
* @see #transform |
|
1561 |
* @see TransformChain |
|
1562 |
* @see AffineTransform |
|
1563 |
*/ |
|
1564 |
public void setTransform(AffineTransform Tx) { |
|
1565 |
if ((constrainX|constrainY) == 0) { |
|
1566 |
transform.setTransform(Tx); |
|
1567 |
} else { |
|
1568 |
transform.setToTranslation(constrainX, constrainY); |
|
1569 |
transform.concatenate(Tx); |
|
1570 |
} |
|
1571 |
invalidateTransform(); |
|
1572 |
} |
|
1573 |
||
1574 |
protected void invalidateTransform() { |
|
1575 |
int type = transform.getType(); |
|
1576 |
int origTransformState = transformState; |
|
1577 |
if (type == AffineTransform.TYPE_IDENTITY) { |
|
1578 |
transformState = TRANSFORM_ISIDENT; |
|
1579 |
transX = transY = 0; |
|
1580 |
} else if (type == AffineTransform.TYPE_TRANSLATION) { |
|
1581 |
double dtx = transform.getTranslateX(); |
|
1582 |
double dty = transform.getTranslateY(); |
|
1583 |
transX = (int) Math.floor(dtx + 0.5); |
|
1584 |
transY = (int) Math.floor(dty + 0.5); |
|
1585 |
if (dtx == transX && dty == transY) { |
|
1586 |
transformState = TRANSFORM_INT_TRANSLATE; |
|
1587 |
} else { |
|
1588 |
transformState = TRANSFORM_ANY_TRANSLATE; |
|
1589 |
} |
|
1590 |
} else if ((type & (AffineTransform.TYPE_FLIP | |
|
1591 |
AffineTransform.TYPE_MASK_ROTATION | |
|
1592 |
AffineTransform.TYPE_GENERAL_TRANSFORM)) == 0) |
|
1593 |
{ |
|
1594 |
transformState = TRANSFORM_TRANSLATESCALE; |
|
1595 |
transX = transY = 0; |
|
1596 |
} else { |
|
1597 |
transformState = TRANSFORM_GENERIC; |
|
1598 |
transX = transY = 0; |
|
1599 |
} |
|
1600 |
||
1601 |
if (transformState >= TRANSFORM_TRANSLATESCALE || |
|
1602 |
origTransformState >= TRANSFORM_TRANSLATESCALE) |
|
1603 |
{ |
|
1604 |
/* Its only in this case that the previous or current transform |
|
1605 |
* was more than a translate that font info is invalidated |
|
1606 |
*/ |
|
1607 |
cachedFRC = null; |
|
1608 |
this.validFontInfo = false; |
|
1609 |
this.fontMetrics = null; |
|
1610 |
this.glyphVectorFontInfo = null; |
|
1611 |
||
1612 |
if (transformState != origTransformState) { |
|
1613 |
invalidatePipe(); |
|
1614 |
} |
|
1615 |
} |
|
1616 |
if (strokeState != STROKE_CUSTOM) { |
|
1617 |
validateBasicStroke((BasicStroke) stroke); |
|
1618 |
} |
|
1619 |
} |
|
1620 |
||
1621 |
/** |
|
1622 |
* Returns the current Transform in the Graphics2D state. |
|
1623 |
* @see #transform |
|
1624 |
* @see #setTransform |
|
1625 |
*/ |
|
1626 |
public AffineTransform getTransform() { |
|
1627 |
if ((constrainX|constrainY) == 0) { |
|
1628 |
return new AffineTransform(transform); |
|
1629 |
} |
|
1630 |
AffineTransform tx = |
|
1631 |
AffineTransform.getTranslateInstance(-constrainX, -constrainY); |
|
1632 |
tx.concatenate(transform); |
|
1633 |
return tx; |
|
1634 |
} |
|
1635 |
||
1636 |
/** |
|
1637 |
* Returns the current Transform ignoring the "constrain" |
|
1638 |
* rectangle. |
|
1639 |
*/ |
|
1640 |
public AffineTransform cloneTransform() { |
|
1641 |
return new AffineTransform(transform); |
|
1642 |
} |
|
1643 |
||
1644 |
/** |
|
1645 |
* Returns the current Paint in the Graphics2D state. |
|
1646 |
* @see #setPaint |
|
1647 |
* @see java.awt.Graphics#setColor |
|
1648 |
*/ |
|
1649 |
public Paint getPaint() { |
|
1650 |
return paint; |
|
1651 |
} |
|
1652 |
||
1653 |
/** |
|
1654 |
* Returns the current Composite in the Graphics2D state. |
|
1655 |
* @see #setComposite |
|
1656 |
*/ |
|
1657 |
public Composite getComposite() { |
|
1658 |
return composite; |
|
1659 |
} |
|
1660 |
||
1661 |
public Color getColor() { |
|
1662 |
return foregroundColor; |
|
1663 |
} |
|
1664 |
||
1665 |
/* |
|
1666 |
* Validate the eargb and pixel fields against the current color. |
|
1667 |
* |
|
1668 |
* The eargb field must take into account the extraAlpha |
|
1669 |
* value of an AlphaComposite. It may also take into account |
|
1670 |
* the Fsrc Porter-Duff blending function if such a function is |
|
1671 |
* a constant (see handling of Clear mode below). For instance, |
|
1672 |
* by factoring in the (Fsrc == 0) state of the Clear mode we can |
|
1673 |
* use a SrcNoEa loop just as easily as a general Alpha loop |
|
1674 |
* since the math will be the same in both cases. |
|
1675 |
* |
|
1676 |
* The pixel field will always be the best pixel data choice for |
|
1677 |
* the final result of all calculations applied to the eargb field. |
|
1678 |
* |
|
1679 |
* Note that this method is only necessary under the following |
|
1680 |
* conditions: |
|
1681 |
* (paintState <= PAINT_ALPHA_COLOR && |
|
1682 |
* compositeState <= COMP_CUSTOM) |
|
1683 |
* though nothing bad will happen if it is run in other states. |
|
1684 |
*/ |
|
1685 |
final void validateColor() { |
|
1686 |
int eargb; |
|
1687 |
if (imageComp == CompositeType.Clear) { |
|
1688 |
eargb = 0; |
|
1689 |
} else { |
|
1690 |
eargb = foregroundColor.getRGB(); |
|
1691 |
if (compositeState <= COMP_ALPHA && |
|
1692 |
imageComp != CompositeType.SrcNoEa && |
|
1693 |
imageComp != CompositeType.SrcOverNoEa) |
|
1694 |
{ |
|
1695 |
AlphaComposite alphacomp = (AlphaComposite) composite; |
|
1696 |
int a = Math.round(alphacomp.getAlpha() * (eargb >>> 24)); |
|
1697 |
eargb = (eargb & 0x00ffffff) | (a << 24); |
|
1698 |
} |
|
1699 |
} |
|
1700 |
this.eargb = eargb; |
|
1701 |
this.pixel = surfaceData.pixelFor(eargb); |
|
1702 |
} |
|
1703 |
||
1704 |
public void setColor(Color color) { |
|
1705 |
if (color == null || color == paint) { |
|
1706 |
return; |
|
1707 |
} |
|
1708 |
this.paint = foregroundColor = color; |
|
1709 |
validateColor(); |
|
1710 |
if ((eargb >> 24) == -1) { |
|
1711 |
if (paintState == PAINT_OPAQUECOLOR) { |
|
1712 |
return; |
|
1713 |
} |
|
1714 |
paintState = PAINT_OPAQUECOLOR; |
|
1715 |
if (imageComp == CompositeType.SrcOverNoEa) { |
|
1716 |
// special case where compState depends on opacity of paint |
|
1717 |
compositeState = COMP_ISCOPY; |
|
1718 |
} |
|
1719 |
} else { |
|
1720 |
if (paintState == PAINT_ALPHACOLOR) { |
|
1721 |
return; |
|
1722 |
} |
|
1723 |
paintState = PAINT_ALPHACOLOR; |
|
1724 |
if (imageComp == CompositeType.SrcOverNoEa) { |
|
1725 |
// special case where compState depends on opacity of paint |
|
1726 |
compositeState = COMP_ALPHA; |
|
1727 |
} |
|
1728 |
} |
|
1729 |
validFontInfo = false; |
|
1730 |
invalidatePipe(); |
|
1731 |
} |
|
1732 |
||
1733 |
/** |
|
1734 |
* Sets the background color in this context used for clearing a region. |
|
1735 |
* When Graphics2D is constructed for a component, the backgroung color is |
|
1736 |
* inherited from the component. Setting the background color in the |
|
1737 |
* Graphics2D context only affects the subsequent clearRect() calls and |
|
1738 |
* not the background color of the component. To change the background |
|
1739 |
* of the component, use appropriate methods of the component. |
|
1740 |
* @param color The background color that should be used in |
|
1741 |
* subsequent calls to clearRect(). |
|
1742 |
* @see getBackground |
|
1743 |
* @see Graphics.clearRect() |
|
1744 |
*/ |
|
1745 |
public void setBackground(Color color) { |
|
1746 |
backgroundColor = color; |
|
1747 |
} |
|
1748 |
||
1749 |
/** |
|
1750 |
* Returns the background color used for clearing a region. |
|
1751 |
* @see setBackground |
|
1752 |
*/ |
|
1753 |
public Color getBackground() { |
|
1754 |
return backgroundColor; |
|
1755 |
} |
|
1756 |
||
1757 |
/** |
|
1758 |
* Returns the current Stroke in the Graphics2D state. |
|
1759 |
* @see setStroke |
|
1760 |
*/ |
|
1761 |
public Stroke getStroke() { |
|
1762 |
return stroke; |
|
1763 |
} |
|
1764 |
||
1765 |
public Rectangle getClipBounds() { |
|
1766 |
Rectangle r; |
|
1767 |
if (clipState == CLIP_DEVICE) { |
|
1768 |
r = null; |
|
1769 |
} else if (transformState <= TRANSFORM_INT_TRANSLATE) { |
|
1770 |
if (usrClip instanceof Rectangle) { |
|
1771 |
r = new Rectangle((Rectangle) usrClip); |
|
1772 |
} else { |
|
1773 |
r = usrClip.getBounds(); |
|
1774 |
} |
|
1775 |
r.translate(-transX, -transY); |
|
1776 |
} else { |
|
1777 |
r = getClip().getBounds(); |
|
1778 |
} |
|
1779 |
return r; |
|
1780 |
} |
|
1781 |
||
1782 |
public Rectangle getClipBounds(Rectangle r) { |
|
1783 |
if (clipState != CLIP_DEVICE) { |
|
1784 |
if (transformState <= TRANSFORM_INT_TRANSLATE) { |
|
1785 |
if (usrClip instanceof Rectangle) { |
|
1786 |
r.setBounds((Rectangle) usrClip); |
|
1787 |
} else { |
|
1788 |
r.setBounds(usrClip.getBounds()); |
|
1789 |
} |
|
1790 |
r.translate(-transX, -transY); |
|
1791 |
} else { |
|
1792 |
r.setBounds(getClip().getBounds()); |
|
1793 |
} |
|
1794 |
} else if (r == null) { |
|
1795 |
throw new NullPointerException("null rectangle parameter"); |
|
1796 |
} |
|
1797 |
return r; |
|
1798 |
} |
|
1799 |
||
1800 |
public boolean hitClip(int x, int y, int width, int height) { |
|
1801 |
if (width <= 0 || height <= 0) { |
|
1802 |
return false; |
|
1803 |
} |
|
1804 |
if (transformState > TRANSFORM_INT_TRANSLATE) { |
|
1805 |
// Note: Technically the most accurate test would be to |
|
1806 |
// raster scan the parallelogram of the transformed rectangle |
|
1807 |
// and do a span for span hit test against the clip, but for |
|
1808 |
// speed we approximate the test with a bounding box of the |
|
1809 |
// transformed rectangle. The cost of rasterizing the |
|
1810 |
// transformed rectangle is probably high enough that it is |
|
1811 |
// not worth doing so to save the caller from having to call |
|
1812 |
// a rendering method where we will end up discovering the |
|
1813 |
// same answer in about the same amount of time anyway. |
|
1814 |
// This logic breaks down if this hit test is being performed |
|
1815 |
// on the bounds of a group of shapes in which case it might |
|
1816 |
// be beneficial to be a little more accurate to avoid lots |
|
1817 |
// of subsequent rendering calls. In either case, this relaxed |
|
1818 |
// test should not be significantly less accurate than the |
|
1819 |
// optimal test for most transforms and so the conservative |
|
1820 |
// answer should not cause too much extra work. |
|
1821 |
||
1822 |
double d[] = { |
|
1823 |
x, y, |
|
1824 |
x+width, y, |
|
1825 |
x, y+height, |
|
1826 |
x+width, y+height |
|
1827 |
}; |
|
1828 |
transform.transform(d, 0, d, 0, 4); |
|
1829 |
x = (int) Math.floor(Math.min(Math.min(d[0], d[2]), |
|
1830 |
Math.min(d[4], d[6]))); |
|
1831 |
y = (int) Math.floor(Math.min(Math.min(d[1], d[3]), |
|
1832 |
Math.min(d[5], d[7]))); |
|
1833 |
width = (int) Math.ceil(Math.max(Math.max(d[0], d[2]), |
|
1834 |
Math.max(d[4], d[6]))); |
|
1835 |
height = (int) Math.ceil(Math.max(Math.max(d[1], d[3]), |
|
1836 |
Math.max(d[5], d[7]))); |
|
1837 |
} else { |
|
1838 |
x += transX; |
|
1839 |
y += transY; |
|
1840 |
width += x; |
|
1841 |
height += y; |
|
1842 |
} |
|
11899
d2eb55fd95a1
7121482: some sun/java2d and sun/awt tests failed with InvalidPipeException since 1.7.0_03b02, 6u31b02
bagiras
parents:
11897
diff
changeset
|
1843 |
|
d2eb55fd95a1
7121482: some sun/java2d and sun/awt tests failed with InvalidPipeException since 1.7.0_03b02, 6u31b02
bagiras
parents:
11897
diff
changeset
|
1844 |
try { |
d2eb55fd95a1
7121482: some sun/java2d and sun/awt tests failed with InvalidPipeException since 1.7.0_03b02, 6u31b02
bagiras
parents:
11897
diff
changeset
|
1845 |
if (!getCompClip().intersectsQuickCheckXYXY(x, y, width, height)) { |
d2eb55fd95a1
7121482: some sun/java2d and sun/awt tests failed with InvalidPipeException since 1.7.0_03b02, 6u31b02
bagiras
parents:
11897
diff
changeset
|
1846 |
return false; |
d2eb55fd95a1
7121482: some sun/java2d and sun/awt tests failed with InvalidPipeException since 1.7.0_03b02, 6u31b02
bagiras
parents:
11897
diff
changeset
|
1847 |
} |
d2eb55fd95a1
7121482: some sun/java2d and sun/awt tests failed with InvalidPipeException since 1.7.0_03b02, 6u31b02
bagiras
parents:
11897
diff
changeset
|
1848 |
} catch (InvalidPipeException e) { |
2 | 1849 |
return false; |
1850 |
} |
|
1851 |
// REMIND: We could go one step further here and examine the |
|
1852 |
// non-rectangular clip shape more closely if there is one. |
|
1853 |
// Since the clip has already been rasterized, the performance |
|
1854 |
// penalty of doing the scan is probably still within the bounds |
|
1855 |
// of a good tradeoff between speed and quality of the answer. |
|
1856 |
return true; |
|
1857 |
} |
|
1858 |
||
1859 |
protected void validateCompClip() { |
|
1860 |
int origClipState = clipState; |
|
1861 |
if (usrClip == null) { |
|
1862 |
clipState = CLIP_DEVICE; |
|
1863 |
clipRegion = devClip; |
|
1864 |
} else if (usrClip instanceof Rectangle2D) { |
|
1865 |
clipState = CLIP_RECTANGULAR; |
|
1866 |
if (usrClip instanceof Rectangle) { |
|
1867 |
clipRegion = devClip.getIntersection((Rectangle)usrClip); |
|
1868 |
} else { |
|
1869 |
clipRegion = devClip.getIntersection(usrClip.getBounds()); |
|
1870 |
} |
|
1871 |
} else { |
|
1872 |
PathIterator cpi = usrClip.getPathIterator(null); |
|
1873 |
int box[] = new int[4]; |
|
1874 |
ShapeSpanIterator sr = LoopPipe.getFillSSI(this); |
|
1875 |
try { |
|
1876 |
sr.setOutputArea(devClip); |
|
1877 |
sr.appendPath(cpi); |
|
1878 |
sr.getPathBox(box); |
|
1879 |
Region r = Region.getInstance(box); |
|
1880 |
r.appendSpans(sr); |
|
1881 |
clipRegion = r; |
|
1882 |
clipState = |
|
1883 |
r.isRectangular() ? CLIP_RECTANGULAR : CLIP_SHAPE; |
|
1884 |
} finally { |
|
1885 |
sr.dispose(); |
|
1886 |
} |
|
1887 |
} |
|
1888 |
if (origClipState != clipState && |
|
1889 |
(clipState == CLIP_SHAPE || origClipState == CLIP_SHAPE)) |
|
1890 |
{ |
|
1891 |
validFontInfo = false; |
|
1892 |
invalidatePipe(); |
|
1893 |
} |
|
1894 |
} |
|
1895 |
||
1896 |
static final int NON_RECTILINEAR_TRANSFORM_MASK = |
|
1897 |
(AffineTransform.TYPE_GENERAL_TRANSFORM | |
|
1898 |
AffineTransform.TYPE_GENERAL_ROTATION); |
|
1899 |
||
1900 |
protected Shape transformShape(Shape s) { |
|
1901 |
if (s == null) { |
|
1902 |
return null; |
|
1903 |
} |
|
1904 |
if (transformState > TRANSFORM_INT_TRANSLATE) { |
|
1905 |
return transformShape(transform, s); |
|
1906 |
} else { |
|
1907 |
return transformShape(transX, transY, s); |
|
1908 |
} |
|
1909 |
} |
|
1910 |
||
1911 |
public Shape untransformShape(Shape s) { |
|
1912 |
if (s == null) { |
|
1913 |
return null; |
|
1914 |
} |
|
1915 |
if (transformState > TRANSFORM_INT_TRANSLATE) { |
|
1916 |
try { |
|
1917 |
return transformShape(transform.createInverse(), s); |
|
1918 |
} catch (NoninvertibleTransformException e) { |
|
1919 |
return null; |
|
1920 |
} |
|
1921 |
} else { |
|
1922 |
return transformShape(-transX, -transY, s); |
|
1923 |
} |
|
1924 |
} |
|
1925 |
||
1926 |
protected static Shape transformShape(int tx, int ty, Shape s) { |
|
1927 |
if (s == null) { |
|
1928 |
return null; |
|
1929 |
} |
|
1930 |
||
1931 |
if (s instanceof Rectangle) { |
|
1932 |
Rectangle r = s.getBounds(); |
|
1933 |
r.translate(tx, ty); |
|
1934 |
return r; |
|
1935 |
} |
|
1936 |
if (s instanceof Rectangle2D) { |
|
1937 |
Rectangle2D rect = (Rectangle2D) s; |
|
1938 |
return new Rectangle2D.Double(rect.getX() + tx, |
|
1939 |
rect.getY() + ty, |
|
1940 |
rect.getWidth(), |
|
1941 |
rect.getHeight()); |
|
1942 |
} |
|
1943 |
||
1944 |
if (tx == 0 && ty == 0) { |
|
1945 |
return cloneShape(s); |
|
1946 |
} |
|
1947 |
||
1948 |
AffineTransform mat = AffineTransform.getTranslateInstance(tx, ty); |
|
1949 |
return mat.createTransformedShape(s); |
|
1950 |
} |
|
1951 |
||
1952 |
protected static Shape transformShape(AffineTransform tx, Shape clip) { |
|
1953 |
if (clip == null) { |
|
1954 |
return null; |
|
1955 |
} |
|
1956 |
||
1957 |
if (clip instanceof Rectangle2D && |
|
1958 |
(tx.getType() & NON_RECTILINEAR_TRANSFORM_MASK) == 0) |
|
1959 |
{ |
|
1960 |
Rectangle2D rect = (Rectangle2D) clip; |
|
1961 |
double matrix[] = new double[4]; |
|
1962 |
matrix[0] = rect.getX(); |
|
1963 |
matrix[1] = rect.getY(); |
|
1964 |
matrix[2] = matrix[0] + rect.getWidth(); |
|
1965 |
matrix[3] = matrix[1] + rect.getHeight(); |
|
1966 |
tx.transform(matrix, 0, matrix, 0, 2); |
|
1967 |
rect = new Rectangle2D.Float(); |
|
1968 |
rect.setFrameFromDiagonal(matrix[0], matrix[1], |
|
1969 |
matrix[2], matrix[3]); |
|
1970 |
return rect; |
|
1971 |
} |
|
1972 |
||
1973 |
if (tx.isIdentity()) { |
|
1974 |
return cloneShape(clip); |
|
1975 |
} |
|
1976 |
||
1977 |
return tx.createTransformedShape(clip); |
|
1978 |
} |
|
1979 |
||
1980 |
public void clipRect(int x, int y, int w, int h) { |
|
1981 |
clip(new Rectangle(x, y, w, h)); |
|
1982 |
} |
|
1983 |
||
1984 |
public void setClip(int x, int y, int w, int h) { |
|
1985 |
setClip(new Rectangle(x, y, w, h)); |
|
1986 |
} |
|
1987 |
||
1988 |
public Shape getClip() { |
|
1989 |
return untransformShape(usrClip); |
|
1990 |
} |
|
1991 |
||
1992 |
public void setClip(Shape sh) { |
|
1993 |
usrClip = transformShape(sh); |
|
1994 |
validateCompClip(); |
|
1995 |
} |
|
1996 |
||
1997 |
/** |
|
1998 |
* Intersects the current clip with the specified Path and sets the |
|
1999 |
* current clip to the resulting intersection. The clip is transformed |
|
2000 |
* with the current transform in the Graphics2D state before being |
|
2001 |
* intersected with the current clip. This method is used to make the |
|
2002 |
* current clip smaller. To make the clip larger, use any setClip method. |
|
2003 |
* @param p The Path to be intersected with the current clip. |
|
2004 |
*/ |
|
2005 |
public void clip(Shape s) { |
|
2006 |
s = transformShape(s); |
|
2007 |
if (usrClip != null) { |
|
2008 |
s = intersectShapes(usrClip, s, true, true); |
|
2009 |
} |
|
2010 |
usrClip = s; |
|
2011 |
validateCompClip(); |
|
2012 |
} |
|
2013 |
||
2014 |
public void setPaintMode() { |
|
2015 |
setComposite(AlphaComposite.SrcOver); |
|
2016 |
} |
|
2017 |
||
2018 |
public void setXORMode(Color c) { |
|
2019 |
if (c == null) { |
|
2020 |
throw new IllegalArgumentException("null XORColor"); |
|
2021 |
} |
|
2022 |
setComposite(new XORComposite(c, surfaceData)); |
|
2023 |
} |
|
2024 |
||
2025 |
Blit lastCAblit; |
|
2026 |
Composite lastCAcomp; |
|
2027 |
||
2028 |
public void copyArea(int x, int y, int w, int h, int dx, int dy) { |
|
2029 |
try { |
|
2030 |
doCopyArea(x, y, w, h, dx, dy); |
|
2031 |
} catch (InvalidPipeException e) { |
|
2032 |
try { |
|
11899
d2eb55fd95a1
7121482: some sun/java2d and sun/awt tests failed with InvalidPipeException since 1.7.0_03b02, 6u31b02
bagiras
parents:
11897
diff
changeset
|
2033 |
revalidateAll(); |
2 | 2034 |
doCopyArea(x, y, w, h, dx, dy); |
2035 |
} catch (InvalidPipeException e2) { |
|
2036 |
// Still catching the exception; we are not yet ready to |
|
2037 |
// validate the surfaceData correctly. Fail for now and |
|
2038 |
// try again next time around. |
|
2039 |
} |
|
2040 |
} finally { |
|
2041 |
surfaceData.markDirty(); |
|
2042 |
} |
|
2043 |
} |
|
2044 |
||
2045 |
private void doCopyArea(int x, int y, int w, int h, int dx, int dy) { |
|
2046 |
if (w <= 0 || h <= 0) { |
|
2047 |
return; |
|
2048 |
} |
|
2049 |
SurfaceData theData = surfaceData; |
|
2050 |
if (theData.copyArea(this, x, y, w, h, dx, dy)) { |
|
2051 |
return; |
|
2052 |
} |
|
2053 |
if (transformState >= TRANSFORM_TRANSLATESCALE) { |
|
2054 |
throw new InternalError("transformed copyArea not implemented yet"); |
|
2055 |
} |
|
2056 |
// REMIND: This method does not deal with missing data from the |
|
2057 |
// source object (i.e. it does not send exposure events...) |
|
2058 |
||
2059 |
Region clip = getCompClip(); |
|
2060 |
||
2061 |
Composite comp = composite; |
|
2062 |
if (lastCAcomp != comp) { |
|
2063 |
SurfaceType dsttype = theData.getSurfaceType(); |
|
2064 |
CompositeType comptype = imageComp; |
|
2065 |
if (CompositeType.SrcOverNoEa.equals(comptype) && |
|
2066 |
theData.getTransparency() == Transparency.OPAQUE) |
|
2067 |
{ |
|
2068 |
comptype = CompositeType.SrcNoEa; |
|
2069 |
} |
|
2070 |
lastCAblit = Blit.locate(dsttype, comptype, dsttype); |
|
2071 |
lastCAcomp = comp; |
|
2072 |
} |
|
2073 |
||
2074 |
x += transX; |
|
2075 |
y += transY; |
|
2076 |
||
2077 |
Blit ob = lastCAblit; |
|
2078 |
if (dy == 0 && dx > 0 && dx < w) { |
|
2079 |
while (w > 0) { |
|
2080 |
int partW = Math.min(w, dx); |
|
2081 |
w -= partW; |
|
2082 |
int sx = x + w; |
|
2083 |
ob.Blit(theData, theData, comp, clip, |
|
2084 |
sx, y, sx+dx, y+dy, partW, h); |
|
2085 |
} |
|
2086 |
return; |
|
2087 |
} |
|
2088 |
if (dy > 0 && dy < h && dx > -w && dx < w) { |
|
2089 |
while (h > 0) { |
|
2090 |
int partH = Math.min(h, dy); |
|
2091 |
h -= partH; |
|
2092 |
int sy = y + h; |
|
2093 |
ob.Blit(theData, theData, comp, clip, |
|
2094 |
x, sy, x+dx, sy+dy, w, partH); |
|
2095 |
} |
|
2096 |
return; |
|
2097 |
} |
|
2098 |
ob.Blit(theData, theData, comp, clip, x, y, x+dx, y+dy, w, h); |
|
2099 |
} |
|
2100 |
||
2101 |
/* |
|
2102 |
public void XcopyArea(int x, int y, int w, int h, int dx, int dy) { |
|
2103 |
Rectangle rect = new Rectangle(x, y, w, h); |
|
2104 |
rect = transformBounds(rect, transform); |
|
2105 |
Point2D point = new Point2D.Float(dx, dy); |
|
2106 |
Point2D root = new Point2D.Float(0, 0); |
|
2107 |
point = transform.transform(point, point); |
|
2108 |
root = transform.transform(root, root); |
|
2109 |
int fdx = (int)(point.getX()-root.getX()); |
|
2110 |
int fdy = (int)(point.getY()-root.getY()); |
|
2111 |
||
2112 |
Rectangle r = getCompBounds().intersection(rect.getBounds()); |
|
2113 |
||
2114 |
if (r.isEmpty()) { |
|
2115 |
return; |
|
2116 |
} |
|
2117 |
||
2118 |
// Begin Rasterizer for Clip Shape |
|
2119 |
boolean skipClip = true; |
|
2120 |
byte[] clipAlpha = null; |
|
2121 |
||
2122 |
if (clipState == CLIP_SHAPE) { |
|
2123 |
||
2124 |
int box[] = new int[4]; |
|
2125 |
||
2126 |
clipRegion.getBounds(box); |
|
2127 |
Rectangle devR = new Rectangle(box[0], box[1], |
|
2128 |
box[2] - box[0], |
|
2129 |
box[3] - box[1]); |
|
2130 |
if (!devR.isEmpty()) { |
|
2131 |
OutputManager mgr = getOutputManager(); |
|
2132 |
RegionIterator ri = clipRegion.getIterator(); |
|
2133 |
while (ri.nextYRange(box)) { |
|
2134 |
int spany = box[1]; |
|
2135 |
int spanh = box[3] - spany; |
|
2136 |
while (ri.nextXBand(box)) { |
|
2137 |
int spanx = box[0]; |
|
2138 |
int spanw = box[2] - spanx; |
|
2139 |
mgr.copyArea(this, null, |
|
2140 |
spanw, 0, |
|
2141 |
spanx, spany, |
|
2142 |
spanw, spanh, |
|
2143 |
fdx, fdy, |
|
2144 |
null); |
|
2145 |
} |
|
2146 |
} |
|
2147 |
} |
|
2148 |
return; |
|
2149 |
} |
|
2150 |
// End Rasterizer for Clip Shape |
|
2151 |
||
2152 |
getOutputManager().copyArea(this, null, |
|
2153 |
r.width, 0, |
|
2154 |
r.x, r.y, r.width, |
|
2155 |
r.height, fdx, fdy, |
|
2156 |
null); |
|
2157 |
} |
|
2158 |
*/ |
|
2159 |
||
2160 |
public void drawLine(int x1, int y1, int x2, int y2) { |
|
2161 |
try { |
|
2162 |
drawpipe.drawLine(this, x1, y1, x2, y2); |
|
2163 |
} catch (InvalidPipeException e) { |
|
2164 |
try { |
|
11899
d2eb55fd95a1
7121482: some sun/java2d and sun/awt tests failed with InvalidPipeException since 1.7.0_03b02, 6u31b02
bagiras
parents:
11897
diff
changeset
|
2165 |
revalidateAll(); |
2 | 2166 |
drawpipe.drawLine(this, x1, y1, x2, y2); |
2167 |
} catch (InvalidPipeException e2) { |
|
2168 |
// Still catching the exception; we are not yet ready to |
|
2169 |
// validate the surfaceData correctly. Fail for now and |
|
2170 |
// try again next time around. |
|
2171 |
} |
|
2172 |
} finally { |
|
2173 |
surfaceData.markDirty(); |
|
2174 |
} |
|
2175 |
} |
|
2176 |
||
2177 |
public void drawRoundRect(int x, int y, int w, int h, int arcW, int arcH) { |
|
2178 |
try { |
|
2179 |
drawpipe.drawRoundRect(this, x, y, w, h, arcW, arcH); |
|
2180 |
} catch (InvalidPipeException e) { |
|
2181 |
try { |
|
11899
d2eb55fd95a1
7121482: some sun/java2d and sun/awt tests failed with InvalidPipeException since 1.7.0_03b02, 6u31b02
bagiras
parents:
11897
diff
changeset
|
2182 |
revalidateAll(); |
2 | 2183 |
drawpipe.drawRoundRect(this, x, y, w, h, arcW, arcH); |
2184 |
} catch (InvalidPipeException e2) { |
|
2185 |
// Still catching the exception; we are not yet ready to |
|
2186 |
// validate the surfaceData correctly. Fail for now and |
|
2187 |
// try again next time around. |
|
2188 |
} |
|
2189 |
} finally { |
|
2190 |
surfaceData.markDirty(); |
|
2191 |
} |
|
2192 |
} |
|
2193 |
||
2194 |
public void fillRoundRect(int x, int y, int w, int h, int arcW, int arcH) { |
|
2195 |
try { |
|
2196 |
fillpipe.fillRoundRect(this, x, y, w, h, arcW, arcH); |
|
2197 |
} catch (InvalidPipeException e) { |
|
2198 |
try { |
|
11899
d2eb55fd95a1
7121482: some sun/java2d and sun/awt tests failed with InvalidPipeException since 1.7.0_03b02, 6u31b02
bagiras
parents:
11897
diff
changeset
|
2199 |
revalidateAll(); |
2 | 2200 |
fillpipe.fillRoundRect(this, x, y, w, h, arcW, arcH); |
2201 |
} catch (InvalidPipeException e2) { |
|
2202 |
// Still catching the exception; we are not yet ready to |
|
2203 |
// validate the surfaceData correctly. Fail for now and |
|
2204 |
// try again next time around. |
|
2205 |
} |
|
2206 |
} finally { |
|
2207 |
surfaceData.markDirty(); |
|
2208 |
} |
|
2209 |
} |
|
2210 |
||
2211 |
public void drawOval(int x, int y, int w, int h) { |
|
2212 |
try { |
|
2213 |
drawpipe.drawOval(this, x, y, w, h); |
|
2214 |
} catch (InvalidPipeException e) { |
|
2215 |
try { |
|
11899
d2eb55fd95a1
7121482: some sun/java2d and sun/awt tests failed with InvalidPipeException since 1.7.0_03b02, 6u31b02
bagiras
parents:
11897
diff
changeset
|
2216 |
revalidateAll(); |
2 | 2217 |
drawpipe.drawOval(this, x, y, w, h); |
2218 |
} catch (InvalidPipeException e2) { |
|
2219 |
// Still catching the exception; we are not yet ready to |
|
2220 |
// validate the surfaceData correctly. Fail for now and |
|
2221 |
// try again next time around. |
|
2222 |
} |
|
2223 |
} finally { |
|
2224 |
surfaceData.markDirty(); |
|
2225 |
} |
|
2226 |
} |
|
2227 |
||
2228 |
public void fillOval(int x, int y, int w, int h) { |
|
2229 |
try { |
|
2230 |
fillpipe.fillOval(this, x, y, w, h); |
|
2231 |
} catch (InvalidPipeException e) { |
|
2232 |
try { |
|
11899
d2eb55fd95a1
7121482: some sun/java2d and sun/awt tests failed with InvalidPipeException since 1.7.0_03b02, 6u31b02
bagiras
parents:
11897
diff
changeset
|
2233 |
revalidateAll(); |
2 | 2234 |
fillpipe.fillOval(this, x, y, w, h); |
2235 |
} catch (InvalidPipeException e2) { |
|
2236 |
// Still catching the exception; we are not yet ready to |
|
2237 |
// validate the surfaceData correctly. Fail for now and |
|
2238 |
// try again next time around. |
|
2239 |
} |
|
2240 |
} finally { |
|
2241 |
surfaceData.markDirty(); |
|
2242 |
} |
|
2243 |
} |
|
2244 |
||
2245 |
public void drawArc(int x, int y, int w, int h, |
|
2246 |
int startAngl, int arcAngl) { |
|
2247 |
try { |
|
2248 |
drawpipe.drawArc(this, x, y, w, h, startAngl, arcAngl); |
|
2249 |
} catch (InvalidPipeException e) { |
|
2250 |
try { |
|
11899
d2eb55fd95a1
7121482: some sun/java2d and sun/awt tests failed with InvalidPipeException since 1.7.0_03b02, 6u31b02
bagiras
parents:
11897
diff
changeset
|
2251 |
revalidateAll(); |
2 | 2252 |
drawpipe.drawArc(this, x, y, w, h, startAngl, arcAngl); |
2253 |
} catch (InvalidPipeException e2) { |
|
2254 |
// Still catching the exception; we are not yet ready to |
|
2255 |
// validate the surfaceData correctly. Fail for now and |
|
2256 |
// try again next time around. |
|
2257 |
} |
|
2258 |
} finally { |
|
2259 |
surfaceData.markDirty(); |
|
2260 |
} |
|
2261 |
} |
|
2262 |
||
2263 |
public void fillArc(int x, int y, int w, int h, |
|
2264 |
int startAngl, int arcAngl) { |
|
2265 |
try { |
|
2266 |
fillpipe.fillArc(this, x, y, w, h, startAngl, arcAngl); |
|
2267 |
} catch (InvalidPipeException e) { |
|
2268 |
try { |
|
11899
d2eb55fd95a1
7121482: some sun/java2d and sun/awt tests failed with InvalidPipeException since 1.7.0_03b02, 6u31b02
bagiras
parents:
11897
diff
changeset
|
2269 |
revalidateAll(); |
2 | 2270 |
fillpipe.fillArc(this, x, y, w, h, startAngl, arcAngl); |
2271 |
} catch (InvalidPipeException e2) { |
|
2272 |
// Still catching the exception; we are not yet ready to |
|
2273 |
// validate the surfaceData correctly. Fail for now and |
|
2274 |
// try again next time around. |
|
2275 |
} |
|
2276 |
} finally { |
|
2277 |
surfaceData.markDirty(); |
|
2278 |
} |
|
2279 |
} |
|
2280 |
||
2281 |
public void drawPolyline(int xPoints[], int yPoints[], int nPoints) { |
|
2282 |
try { |
|
2283 |
drawpipe.drawPolyline(this, xPoints, yPoints, nPoints); |
|
2284 |
} catch (InvalidPipeException e) { |
|
2285 |
try { |
|
11899
d2eb55fd95a1
7121482: some sun/java2d and sun/awt tests failed with InvalidPipeException since 1.7.0_03b02, 6u31b02
bagiras
parents:
11897
diff
changeset
|
2286 |
revalidateAll(); |
2 | 2287 |
drawpipe.drawPolyline(this, xPoints, yPoints, nPoints); |
2288 |
} catch (InvalidPipeException e2) { |
|
2289 |
// Still catching the exception; we are not yet ready to |
|
2290 |
// validate the surfaceData correctly. Fail for now and |
|
2291 |
// try again next time around. |
|
2292 |
} |
|
2293 |
} finally { |
|
2294 |
surfaceData.markDirty(); |
|
2295 |
} |
|
2296 |
} |
|
2297 |
||
2298 |
public void drawPolygon(int xPoints[], int yPoints[], int nPoints) { |
|
2299 |
try { |
|
2300 |
drawpipe.drawPolygon(this, xPoints, yPoints, nPoints); |
|
2301 |
} catch (InvalidPipeException e) { |
|
2302 |
try { |
|
11899
d2eb55fd95a1
7121482: some sun/java2d and sun/awt tests failed with InvalidPipeException since 1.7.0_03b02, 6u31b02
bagiras
parents:
11897
diff
changeset
|
2303 |
revalidateAll(); |
2 | 2304 |
drawpipe.drawPolygon(this, xPoints, yPoints, nPoints); |
2305 |
} catch (InvalidPipeException e2) { |
|
2306 |
// Still catching the exception; we are not yet ready to |
|
2307 |
// validate the surfaceData correctly. Fail for now and |
|
2308 |
// try again next time around. |
|
2309 |
} |
|
2310 |
} finally { |
|
2311 |
surfaceData.markDirty(); |
|
2312 |
} |
|
2313 |
} |
|
2314 |
||
2315 |
public void fillPolygon(int xPoints[], int yPoints[], int nPoints) { |
|
2316 |
try { |
|
2317 |
fillpipe.fillPolygon(this, xPoints, yPoints, nPoints); |
|
2318 |
} catch (InvalidPipeException e) { |
|
2319 |
try { |
|
11899
d2eb55fd95a1
7121482: some sun/java2d and sun/awt tests failed with InvalidPipeException since 1.7.0_03b02, 6u31b02
bagiras
parents:
11897
diff
changeset
|
2320 |
revalidateAll(); |
2 | 2321 |
fillpipe.fillPolygon(this, xPoints, yPoints, nPoints); |
2322 |
} catch (InvalidPipeException e2) { |
|
2323 |
// Still catching the exception; we are not yet ready to |
|
2324 |
// validate the surfaceData correctly. Fail for now and |
|
2325 |
// try again next time around. |
|
2326 |
} |
|
2327 |
} finally { |
|
2328 |
surfaceData.markDirty(); |
|
2329 |
} |
|
2330 |
} |
|
2331 |
||
2332 |
public void drawRect (int x, int y, int w, int h) { |
|
2333 |
try { |
|
2334 |
drawpipe.drawRect(this, x, y, w, h); |
|
2335 |
} catch (InvalidPipeException e) { |
|
2336 |
try { |
|
11899
d2eb55fd95a1
7121482: some sun/java2d and sun/awt tests failed with InvalidPipeException since 1.7.0_03b02, 6u31b02
bagiras
parents:
11897
diff
changeset
|
2337 |
revalidateAll(); |
2 | 2338 |
drawpipe.drawRect(this, x, y, w, h); |
2339 |
} catch (InvalidPipeException e2) { |
|
2340 |
// Still catching the exception; we are not yet ready to |
|
2341 |
// validate the surfaceData correctly. Fail for now and |
|
2342 |
// try again next time around. |
|
2343 |
} |
|
2344 |
} finally { |
|
2345 |
surfaceData.markDirty(); |
|
2346 |
} |
|
2347 |
} |
|
2348 |
||
2349 |
public void fillRect (int x, int y, int w, int h) { |
|
2350 |
try { |
|
2351 |
fillpipe.fillRect(this, x, y, w, h); |
|
2352 |
} catch (InvalidPipeException e) { |
|
2353 |
try { |
|
11899
d2eb55fd95a1
7121482: some sun/java2d and sun/awt tests failed with InvalidPipeException since 1.7.0_03b02, 6u31b02
bagiras
parents:
11897
diff
changeset
|
2354 |
revalidateAll(); |
2 | 2355 |
fillpipe.fillRect(this, x, y, w, h); |
2356 |
} catch (InvalidPipeException e2) { |
|
2357 |
// Still catching the exception; we are not yet ready to |
|
2358 |
// validate the surfaceData correctly. Fail for now and |
|
2359 |
// try again next time around. |
|
2360 |
} |
|
2361 |
} finally { |
|
2362 |
surfaceData.markDirty(); |
|
2363 |
} |
|
2364 |
} |
|
2365 |
||
2366 |
private void revalidateAll() { |
|
2367 |
try { |
|
2368 |
// REMIND: This locking needs to be done around the |
|
2369 |
// caller of this method so that the pipe stays valid |
|
2370 |
// long enough to call the new primitive. |
|
2371 |
// REMIND: No locking yet in screen SurfaceData objects! |
|
2372 |
// surfaceData.lock(); |
|
2373 |
surfaceData = surfaceData.getReplacement(); |
|
2374 |
if (surfaceData == null) { |
|
2375 |
surfaceData = NullSurfaceData.theInstance; |
|
2376 |
} |
|
2377 |
||
2378 |
// this will recalculate the composite clip |
|
2379 |
setDevClip(surfaceData.getBounds()); |
|
2380 |
||
2381 |
if (paintState <= PAINT_ALPHACOLOR) { |
|
2382 |
validateColor(); |
|
2383 |
} |
|
2384 |
if (composite instanceof XORComposite) { |
|
2385 |
Color c = ((XORComposite) composite).getXorColor(); |
|
2386 |
setComposite(new XORComposite(c, surfaceData)); |
|
2387 |
} |
|
2388 |
validatePipe(); |
|
2389 |
} finally { |
|
2390 |
// REMIND: No locking yet in screen SurfaceData objects! |
|
2391 |
// surfaceData.unlock(); |
|
2392 |
} |
|
2393 |
} |
|
2394 |
||
2395 |
public void clearRect(int x, int y, int w, int h) { |
|
2396 |
// REMIND: has some "interesting" consequences if threads are |
|
2397 |
// not synchronized |
|
2398 |
Composite c = composite; |
|
2399 |
Paint p = paint; |
|
2400 |
setComposite(AlphaComposite.Src); |
|
2401 |
setColor(getBackground()); |
|
2402 |
fillRect(x, y, w, h); |
|
2403 |
setPaint(p); |
|
2404 |
setComposite(c); |
|
2405 |
} |
|
2406 |
||
2407 |
/** |
|
2408 |
* Strokes the outline of a Path using the settings of the current |
|
2409 |
* graphics state. The rendering attributes applied include the |
|
2410 |
* clip, transform, paint or color, composite and stroke attributes. |
|
2411 |
* @param p The path to be drawn. |
|
2412 |
* @see #setStroke |
|
2413 |
* @see #setPaint |
|
2414 |
* @see java.awt.Graphics#setColor |
|
2415 |
* @see #transform |
|
2416 |
* @see #setTransform |
|
2417 |
* @see #clip |
|
2418 |
* @see #setClip |
|
2419 |
* @see #setComposite |
|
2420 |
*/ |
|
2421 |
public void draw(Shape s) { |
|
2422 |
try { |
|
2423 |
shapepipe.draw(this, s); |
|
2424 |
} catch (InvalidPipeException e) { |
|
2425 |
try { |
|
11899
d2eb55fd95a1
7121482: some sun/java2d and sun/awt tests failed with InvalidPipeException since 1.7.0_03b02, 6u31b02
bagiras
parents:
11897
diff
changeset
|
2426 |
revalidateAll(); |
2 | 2427 |
shapepipe.draw(this, s); |
2428 |
} catch (InvalidPipeException e2) { |
|
2429 |
// Still catching the exception; we are not yet ready to |
|
2430 |
// validate the surfaceData correctly. Fail for now and |
|
2431 |
// try again next time around. |
|
2432 |
} |
|
2433 |
} finally { |
|
2434 |
surfaceData.markDirty(); |
|
2435 |
} |
|
2436 |
} |
|
2437 |
||
2438 |
||
2439 |
/** |
|
2440 |
* Fills the interior of a Path using the settings of the current |
|
2441 |
* graphics state. The rendering attributes applied include the |
|
2442 |
* clip, transform, paint or color, and composite. |
|
2443 |
* @see #setPaint |
|
2444 |
* @see java.awt.Graphics#setColor |
|
2445 |
* @see #transform |
|
2446 |
* @see #setTransform |
|
2447 |
* @see #setComposite |
|
2448 |
* @see #clip |
|
2449 |
* @see #setClip |
|
2450 |
*/ |
|
2451 |
public void fill(Shape s) { |
|
2452 |
try { |
|
2453 |
shapepipe.fill(this, s); |
|
2454 |
} catch (InvalidPipeException e) { |
|
2455 |
try { |
|
11899
d2eb55fd95a1
7121482: some sun/java2d and sun/awt tests failed with InvalidPipeException since 1.7.0_03b02, 6u31b02
bagiras
parents:
11897
diff
changeset
|
2456 |
revalidateAll(); |
2 | 2457 |
shapepipe.fill(this, s); |
2458 |
} catch (InvalidPipeException e2) { |
|
2459 |
// Still catching the exception; we are not yet ready to |
|
2460 |
// validate the surfaceData correctly. Fail for now and |
|
2461 |
// try again next time around. |
|
2462 |
} |
|
2463 |
} finally { |
|
2464 |
surfaceData.markDirty(); |
|
2465 |
} |
|
2466 |
} |
|
2467 |
||
2468 |
/** |
|
2469 |
* Returns true if the given AffineTransform is an integer |
|
2470 |
* translation. |
|
2471 |
*/ |
|
2472 |
private static boolean isIntegerTranslation(AffineTransform xform) { |
|
2473 |
if (xform.isIdentity()) { |
|
2474 |
return true; |
|
2475 |
} |
|
2476 |
if (xform.getType() == AffineTransform.TYPE_TRANSLATION) { |
|
2477 |
double tx = xform.getTranslateX(); |
|
2478 |
double ty = xform.getTranslateY(); |
|
2479 |
return (tx == (int)tx && ty == (int)ty); |
|
2480 |
} |
|
2481 |
return false; |
|
2482 |
} |
|
2483 |
||
2484 |
/** |
|
2485 |
* Returns the index of the tile corresponding to the supplied position |
|
2486 |
* given the tile grid offset and size along the same axis. |
|
2487 |
*/ |
|
2488 |
private static int getTileIndex(int p, int tileGridOffset, int tileSize) { |
|
2489 |
p -= tileGridOffset; |
|
2490 |
if (p < 0) { |
|
2491 |
p += 1 - tileSize; // force round to -infinity (ceiling) |
|
2492 |
} |
|
2493 |
return p/tileSize; |
|
2494 |
} |
|
2495 |
||
2496 |
/** |
|
2497 |
* Returns a rectangle in image coordinates that may be required |
|
2498 |
* in order to draw the given image into the given clipping region |
|
2499 |
* through a pair of AffineTransforms. In addition, horizontal and |
|
2500 |
* vertical padding factors for antialising and interpolation may |
|
2501 |
* be used. |
|
2502 |
*/ |
|
2503 |
private static Rectangle getImageRegion(RenderedImage img, |
|
2504 |
Region compClip, |
|
2505 |
AffineTransform transform, |
|
2506 |
AffineTransform xform, |
|
2507 |
int padX, int padY) { |
|
2508 |
Rectangle imageRect = |
|
2509 |
new Rectangle(img.getMinX(), img.getMinY(), |
|
2510 |
img.getWidth(), img.getHeight()); |
|
2511 |
||
2512 |
Rectangle result = null; |
|
2513 |
try { |
|
2514 |
double p[] = new double[8]; |
|
2515 |
p[0] = p[2] = compClip.getLoX(); |
|
2516 |
p[4] = p[6] = compClip.getHiX(); |
|
2517 |
p[1] = p[5] = compClip.getLoY(); |
|
2518 |
p[3] = p[7] = compClip.getHiY(); |
|
2519 |
||
2520 |
// Inverse transform the output bounding rect |
|
2521 |
transform.inverseTransform(p, 0, p, 0, 4); |
|
2522 |
xform.inverseTransform(p, 0, p, 0, 4); |
|
2523 |
||
2524 |
// Determine a bounding box for the inverse transformed region |
|
2525 |
double x0,x1,y0,y1; |
|
2526 |
x0 = x1 = p[0]; |
|
2527 |
y0 = y1 = p[1]; |
|
2528 |
||
2529 |
for (int i = 2; i < 8; ) { |
|
2530 |
double pt = p[i++]; |
|
2531 |
if (pt < x0) { |
|
2532 |
x0 = pt; |
|
2533 |
} else if (pt > x1) { |
|
2534 |
x1 = pt; |
|
2535 |
} |
|
2536 |
pt = p[i++]; |
|
2537 |
if (pt < y0) { |
|
2538 |
y0 = pt; |
|
2539 |
} else if (pt > y1) { |
|
2540 |
y1 = pt; |
|
2541 |
} |
|
2542 |
} |
|
2543 |
||
2544 |
// This is padding for anti-aliasing and such. It may |
|
2545 |
// be more than is needed. |
|
2546 |
int x = (int)x0 - padX; |
|
2547 |
int w = (int)(x1 - x0 + 2*padX); |
|
2548 |
int y = (int)y0 - padY; |
|
2549 |
int h = (int)(y1 - y0 + 2*padY); |
|
2550 |
||
2551 |
Rectangle clipRect = new Rectangle(x,y,w,h); |
|
2552 |
result = clipRect.intersection(imageRect); |
|
2553 |
} catch (NoninvertibleTransformException nte) { |
|
2554 |
// Worst case bounds are the bounds of the image. |
|
2555 |
result = imageRect; |
|
2556 |
} |
|
2557 |
||
2558 |
return result; |
|
2559 |
} |
|
2560 |
||
2561 |
/** |
|
2562 |
* Draws an image, applying a transform from image space into user space |
|
2563 |
* before drawing. |
|
2564 |
* The transformation from user space into device space is done with |
|
2565 |
* the current transform in the Graphics2D. |
|
2566 |
* The given transformation is applied to the image before the |
|
2567 |
* transform attribute in the Graphics2D state is applied. |
|
2568 |
* The rendering attributes applied include the clip, transform, |
|
2569 |
* and composite attributes. Note that the result is |
|
2570 |
* undefined, if the given transform is noninvertible. |
|
2571 |
* @param img The image to be drawn. Does nothing if img is null. |
|
2572 |
* @param xform The transformation from image space into user space. |
|
2573 |
* @see #transform |
|
2574 |
* @see #setTransform |
|
2575 |
* @see #setComposite |
|
2576 |
* @see #clip |
|
2577 |
* @see #setClip |
|
2578 |
*/ |
|
2579 |
public void drawRenderedImage(RenderedImage img, |
|
2580 |
AffineTransform xform) { |
|
2581 |
||
2582 |
if (img == null) { |
|
2583 |
return; |
|
2584 |
} |
|
2585 |
||
2586 |
// BufferedImage case: use a simple drawImage call |
|
2587 |
if (img instanceof BufferedImage) { |
|
2588 |
BufferedImage bufImg = (BufferedImage)img; |
|
2589 |
drawImage(bufImg,xform,null); |
|
2590 |
return; |
|
2591 |
} |
|
2592 |
||
2593 |
// transformState tracks the state of transform and |
|
2594 |
// transX, transY contain the integer casts of the |
|
2595 |
// translation factors |
|
2596 |
boolean isIntegerTranslate = |
|
2597 |
(transformState <= TRANSFORM_INT_TRANSLATE) && |
|
2598 |
isIntegerTranslation(xform); |
|
2599 |
||
2600 |
// Include padding for interpolation/antialiasing if necessary |
|
2601 |
int pad = isIntegerTranslate ? 0 : 3; |
|
2602 |
||
11899
d2eb55fd95a1
7121482: some sun/java2d and sun/awt tests failed with InvalidPipeException since 1.7.0_03b02, 6u31b02
bagiras
parents:
11897
diff
changeset
|
2603 |
Region clip; |
d2eb55fd95a1
7121482: some sun/java2d and sun/awt tests failed with InvalidPipeException since 1.7.0_03b02, 6u31b02
bagiras
parents:
11897
diff
changeset
|
2604 |
try { |
d2eb55fd95a1
7121482: some sun/java2d and sun/awt tests failed with InvalidPipeException since 1.7.0_03b02, 6u31b02
bagiras
parents:
11897
diff
changeset
|
2605 |
clip = getCompClip(); |
d2eb55fd95a1
7121482: some sun/java2d and sun/awt tests failed with InvalidPipeException since 1.7.0_03b02, 6u31b02
bagiras
parents:
11897
diff
changeset
|
2606 |
} catch (InvalidPipeException e) { |
d2eb55fd95a1
7121482: some sun/java2d and sun/awt tests failed with InvalidPipeException since 1.7.0_03b02, 6u31b02
bagiras
parents:
11897
diff
changeset
|
2607 |
return; |
d2eb55fd95a1
7121482: some sun/java2d and sun/awt tests failed with InvalidPipeException since 1.7.0_03b02, 6u31b02
bagiras
parents:
11897
diff
changeset
|
2608 |
} |
d2eb55fd95a1
7121482: some sun/java2d and sun/awt tests failed with InvalidPipeException since 1.7.0_03b02, 6u31b02
bagiras
parents:
11897
diff
changeset
|
2609 |
|
2 | 2610 |
// Determine the region of the image that may contribute to |
2611 |
// the clipped drawing area |
|
2612 |
Rectangle region = getImageRegion(img, |
|
11899
d2eb55fd95a1
7121482: some sun/java2d and sun/awt tests failed with InvalidPipeException since 1.7.0_03b02, 6u31b02
bagiras
parents:
11897
diff
changeset
|
2613 |
clip, |
2 | 2614 |
transform, |
2615 |
xform, |
|
2616 |
pad, pad); |
|
2617 |
if (region.width <= 0 || region.height <= 0) { |
|
2618 |
return; |
|
2619 |
} |
|
2620 |
||
2621 |
// Attempt to optimize integer translation of tiled images. |
|
2622 |
// Although theoretically we are O.K. if the concatenation of |
|
2623 |
// the user transform and the device transform is an integer |
|
2624 |
// translation, we'll play it safe and only optimize the case |
|
2625 |
// where both are integer translations. |
|
2626 |
if (isIntegerTranslate) { |
|
2627 |
// Use optimized code |
|
2628 |
// Note that drawTranslatedRenderedImage calls copyImage |
|
2629 |
// which takes the user space to device space transform into |
|
2630 |
// account, but we need to provide the image space to user space |
|
2631 |
// translations. |
|
2632 |
||
2633 |
drawTranslatedRenderedImage(img, region, |
|
2634 |
(int) xform.getTranslateX(), |
|
2635 |
(int) xform.getTranslateY()); |
|
2636 |
return; |
|
2637 |
} |
|
2638 |
||
2639 |
// General case: cobble the necessary region into a single Raster |
|
2640 |
Raster raster = img.getData(region); |
|
2641 |
||
2642 |
// Make a new Raster with the same contents as raster |
|
2643 |
// but starting at (0, 0). This raster is thus in the same |
|
2644 |
// coordinate system as the SampleModel of the original raster. |
|
2645 |
WritableRaster wRaster = |
|
2646 |
Raster.createWritableRaster(raster.getSampleModel(), |
|
2647 |
raster.getDataBuffer(), |
|
2648 |
null); |
|
2649 |
||
2650 |
// If the original raster was in a different coordinate |
|
2651 |
// system than its SampleModel, we need to perform an |
|
2652 |
// additional translation in order to get the (minX, minY) |
|
2653 |
// pixel of raster to be pixel (0, 0) of wRaster. We also |
|
2654 |
// have to have the correct width and height. |
|
2655 |
int minX = raster.getMinX(); |
|
2656 |
int minY = raster.getMinY(); |
|
2657 |
int width = raster.getWidth(); |
|
2658 |
int height = raster.getHeight(); |
|
2659 |
int px = minX - raster.getSampleModelTranslateX(); |
|
2660 |
int py = minY - raster.getSampleModelTranslateY(); |
|
2661 |
if (px != 0 || py != 0 || width != wRaster.getWidth() || |
|
2662 |
height != wRaster.getHeight()) { |
|
2663 |
wRaster = |
|
2664 |
wRaster.createWritableChild(px, |
|
2665 |
py, |
|
2666 |
width, |
|
2667 |
height, |
|
2668 |
0, 0, |
|
2669 |
null); |
|
2670 |
} |
|
2671 |
||
2672 |
// Now we have a BufferedImage starting at (0, 0) |
|
2673 |
// with the same contents that started at (minX, minY) |
|
2674 |
// in raster. So we must draw the BufferedImage with a |
|
2675 |
// translation of (minX, minY). |
|
2676 |
AffineTransform transXform = (AffineTransform)xform.clone(); |
|
2677 |
transXform.translate(minX, minY); |
|
2678 |
||
2679 |
ColorModel cm = img.getColorModel(); |
|
2680 |
BufferedImage bufImg = new BufferedImage(cm, |
|
2681 |
wRaster, |
|
2682 |
cm.isAlphaPremultiplied(), |
|
2683 |
null); |
|
2684 |
drawImage(bufImg, transXform, null); |
|
2685 |
} |
|
2686 |
||
2687 |
/** |
|
2688 |
* Intersects <code>destRect</code> with <code>clip</code> and |
|
2689 |
* overwrites <code>destRect</code> with the result. |
|
2690 |
* Returns false if the intersection was empty, true otherwise. |
|
2691 |
*/ |
|
2692 |
private boolean clipTo(Rectangle destRect, Rectangle clip) { |
|
2693 |
int x1 = Math.max(destRect.x, clip.x); |
|
2694 |
int x2 = Math.min(destRect.x + destRect.width, clip.x + clip.width); |
|
2695 |
int y1 = Math.max(destRect.y, clip.y); |
|
2696 |
int y2 = Math.min(destRect.y + destRect.height, clip.y + clip.height); |
|
2697 |
if (((x2 - x1) < 0) || ((y2 - y1) < 0)) { |
|
2698 |
destRect.width = -1; // Set both just to be safe |
|
2699 |
destRect.height = -1; |
|
2700 |
return false; |
|
2701 |
} else { |
|
2702 |
destRect.x = x1; |
|
2703 |
destRect.y = y1; |
|
2704 |
destRect.width = x2 - x1; |
|
2705 |
destRect.height = y2 - y1; |
|
2706 |
return true; |
|
2707 |
} |
|
2708 |
} |
|
2709 |
||
2710 |
/** |
|
2711 |
* Draw a portion of a RenderedImage tile-by-tile with a given |
|
2712 |
* integer image to user space translation. The user to |
|
2713 |
* device transform must also be an integer translation. |
|
2714 |
*/ |
|
2715 |
private void drawTranslatedRenderedImage(RenderedImage img, |
|
2716 |
Rectangle region, |
|
2717 |
int i2uTransX, |
|
2718 |
int i2uTransY) { |
|
2719 |
// Cache tile grid info |
|
2720 |
int tileGridXOffset = img.getTileGridXOffset(); |
|
2721 |
int tileGridYOffset = img.getTileGridYOffset(); |
|
2722 |
int tileWidth = img.getTileWidth(); |
|
2723 |
int tileHeight = img.getTileHeight(); |
|
2724 |
||
2725 |
// Determine the tile index extrema in each direction |
|
2726 |
int minTileX = |
|
2727 |
getTileIndex(region.x, tileGridXOffset, tileWidth); |
|
2728 |
int minTileY = |
|
2729 |
getTileIndex(region.y, tileGridYOffset, tileHeight); |
|
2730 |
int maxTileX = |
|
2731 |
getTileIndex(region.x + region.width - 1, |
|
2732 |
tileGridXOffset, tileWidth); |
|
2733 |
int maxTileY = |
|
2734 |
getTileIndex(region.y + region.height - 1, |
|
2735 |
tileGridYOffset, tileHeight); |
|
2736 |
||
2737 |
// Create a single ColorModel to use for all BufferedImages |
|
2738 |
ColorModel colorModel = img.getColorModel(); |
|
2739 |
||
2740 |
// Reuse the same Rectangle for each iteration |
|
2741 |
Rectangle tileRect = new Rectangle(); |
|
2742 |
||
2743 |
for (int ty = minTileY; ty <= maxTileY; ty++) { |
|
2744 |
for (int tx = minTileX; tx <= maxTileX; tx++) { |
|
2745 |
// Get the current tile. |
|
2746 |
Raster raster = img.getTile(tx, ty); |
|
2747 |
||
2748 |
// Fill in tileRect with the tile bounds |
|
2749 |
tileRect.x = tx*tileWidth + tileGridXOffset; |
|
2750 |
tileRect.y = ty*tileHeight + tileGridYOffset; |
|
2751 |
tileRect.width = tileWidth; |
|
2752 |
tileRect.height = tileHeight; |
|
2753 |
||
2754 |
// Clip the tile against the image bounds and |
|
2755 |
// backwards mapped clip region |
|
2756 |
// The result can't be empty |
|
2757 |
clipTo(tileRect, region); |
|
2758 |
||
2759 |
// Create a WritableRaster containing the tile |
|
2760 |
WritableRaster wRaster = null; |
|
2761 |
if (raster instanceof WritableRaster) { |
|
2762 |
wRaster = (WritableRaster)raster; |
|
2763 |
} else { |
|
2764 |
// Create a WritableRaster in the same coordinate system |
|
2765 |
// as the original raster. |
|
2766 |
wRaster = |
|
2767 |
Raster.createWritableRaster(raster.getSampleModel(), |
|
2768 |
raster.getDataBuffer(), |
|
2769 |
null); |
|
2770 |
} |
|
2771 |
||
2772 |
// Translate wRaster to start at (0, 0) and to contain |
|
2773 |
// only the relevent portion of the tile |
|
2774 |
wRaster = wRaster.createWritableChild(tileRect.x, tileRect.y, |
|
2775 |
tileRect.width, |
|
2776 |
tileRect.height, |
|
2777 |
0, 0, |
|
2778 |
null); |
|
2779 |
||
2780 |
// Wrap wRaster in a BufferedImage |
|
2781 |
BufferedImage bufImg = |
|
2782 |
new BufferedImage(colorModel, |
|
2783 |
wRaster, |
|
2784 |
colorModel.isAlphaPremultiplied(), |
|
2785 |
null); |
|
2786 |
// Now we have a BufferedImage starting at (0, 0) that |
|
2787 |
// represents data from a Raster starting at |
|
2788 |
// (tileRect.x, tileRect.y). Additionally, it needs |
|
2789 |
// to be translated by (i2uTransX, i2uTransY). We call |
|
2790 |
// copyImage to draw just the region of interest |
|
2791 |
// without needing to create a child image. |
|
2792 |
copyImage(bufImg, tileRect.x + i2uTransX, |
|
2793 |
tileRect.y + i2uTransY, 0, 0, tileRect.width, |
|
2794 |
tileRect.height, null, null); |
|
2795 |
} |
|
2796 |
} |
|
2797 |
} |
|
2798 |
||
2799 |
public void drawRenderableImage(RenderableImage img, |
|
2800 |
AffineTransform xform) { |
|
2801 |
||
2802 |
if (img == null) { |
|
2803 |
return; |
|
2804 |
} |
|
2805 |
||
2806 |
AffineTransform pipeTransform = transform; |
|
2807 |
AffineTransform concatTransform = new AffineTransform(xform); |
|
2808 |
concatTransform.concatenate(pipeTransform); |
|
2809 |
AffineTransform reverseTransform; |
|
2810 |
||
2811 |
RenderContext rc = new RenderContext(concatTransform); |
|
2812 |
||
2813 |
try { |
|
2814 |
reverseTransform = pipeTransform.createInverse(); |
|
2815 |
} catch (NoninvertibleTransformException nte) { |
|
2816 |
rc = new RenderContext(pipeTransform); |
|
2817 |
reverseTransform = new AffineTransform(); |
|
2818 |
} |
|
2819 |
||
2820 |
RenderedImage rendering = img.createRendering(rc); |
|
2821 |
drawRenderedImage(rendering,reverseTransform); |
|
2822 |
} |
|
2823 |
||
2824 |
||
2825 |
||
2826 |
/* |
|
2827 |
* Transform the bounding box of the BufferedImage |
|
2828 |
*/ |
|
2829 |
protected Rectangle transformBounds(Rectangle rect, |
|
2830 |
AffineTransform tx) { |
|
2831 |
if (tx.isIdentity()) { |
|
2832 |
return rect; |
|
2833 |
} |
|
2834 |
||
2835 |
Shape s = transformShape(tx, rect); |
|
2836 |
return s.getBounds(); |
|
2837 |
} |
|
2838 |
||
2839 |
// text rendering methods |
|
2840 |
public void drawString(String str, int x, int y) { |
|
2841 |
if (str == null) { |
|
2842 |
throw new NullPointerException("String is null"); |
|
2843 |
} |
|
2844 |
||
2845 |
if (font.hasLayoutAttributes()) { |
|
551
6a51745b2784
6699843: IllegalArgumentException when using Graphics.drawString( "", 0, 0 )
prr
parents:
2
diff
changeset
|
2846 |
if (str.length() == 0) { |
6a51745b2784
6699843: IllegalArgumentException when using Graphics.drawString( "", 0, 0 )
prr
parents:
2
diff
changeset
|
2847 |
return; |
6a51745b2784
6699843: IllegalArgumentException when using Graphics.drawString( "", 0, 0 )
prr
parents:
2
diff
changeset
|
2848 |
} |
2 | 2849 |
new TextLayout(str, font, getFontRenderContext()).draw(this, x, y); |
2850 |
return; |
|
2851 |
} |
|
2852 |
||
2853 |
try { |
|
2854 |
textpipe.drawString(this, str, x, y); |
|
2855 |
} catch (InvalidPipeException e) { |
|
2856 |
try { |
|
11899
d2eb55fd95a1
7121482: some sun/java2d and sun/awt tests failed with InvalidPipeException since 1.7.0_03b02, 6u31b02
bagiras
parents:
11897
diff
changeset
|
2857 |
revalidateAll(); |
2 | 2858 |
textpipe.drawString(this, str, x, y); |
2859 |
} catch (InvalidPipeException e2) { |
|
2860 |
// Still catching the exception; we are not yet ready to |
|
2861 |
// validate the surfaceData correctly. Fail for now and |
|
2862 |
// try again next time around. |
|
2863 |
} |
|
2864 |
} finally { |
|
2865 |
surfaceData.markDirty(); |
|
2866 |
} |
|
2867 |
} |
|
2868 |
||
2869 |
public void drawString(String str, float x, float y) { |
|
2870 |
if (str == null) { |
|
2871 |
throw new NullPointerException("String is null"); |
|
2872 |
} |
|
2873 |
||
2874 |
if (font.hasLayoutAttributes()) { |
|
551
6a51745b2784
6699843: IllegalArgumentException when using Graphics.drawString( "", 0, 0 )
prr
parents:
2
diff
changeset
|
2875 |
if (str.length() == 0) { |
6a51745b2784
6699843: IllegalArgumentException when using Graphics.drawString( "", 0, 0 )
prr
parents:
2
diff
changeset
|
2876 |
return; |
6a51745b2784
6699843: IllegalArgumentException when using Graphics.drawString( "", 0, 0 )
prr
parents:
2
diff
changeset
|
2877 |
} |
2 | 2878 |
new TextLayout(str, font, getFontRenderContext()).draw(this, x, y); |
2879 |
return; |
|
2880 |
} |
|
2881 |
||
2882 |
try { |
|
2883 |
textpipe.drawString(this, str, x, y); |
|
2884 |
} catch (InvalidPipeException e) { |
|
2885 |
try { |
|
11899
d2eb55fd95a1
7121482: some sun/java2d and sun/awt tests failed with InvalidPipeException since 1.7.0_03b02, 6u31b02
bagiras
parents:
11897
diff
changeset
|
2886 |
revalidateAll(); |
2 | 2887 |
textpipe.drawString(this, str, x, y); |
2888 |
} catch (InvalidPipeException e2) { |
|
2889 |
// Still catching the exception; we are not yet ready to |
|
2890 |
// validate the surfaceData correctly. Fail for now and |
|
2891 |
// try again next time around. |
|
2892 |
} |
|
2893 |
} finally { |
|
2894 |
surfaceData.markDirty(); |
|
2895 |
} |
|
2896 |
} |
|
2897 |
||
2898 |
public void drawString(AttributedCharacterIterator iterator, |
|
2899 |
int x, int y) { |
|
2900 |
if (iterator == null) { |
|
2901 |
throw new NullPointerException("AttributedCharacterIterator is null"); |
|
2902 |
} |
|
551
6a51745b2784
6699843: IllegalArgumentException when using Graphics.drawString( "", 0, 0 )
prr
parents:
2
diff
changeset
|
2903 |
if (iterator.getBeginIndex() == iterator.getEndIndex()) { |
6a51745b2784
6699843: IllegalArgumentException when using Graphics.drawString( "", 0, 0 )
prr
parents:
2
diff
changeset
|
2904 |
return; /* nothing to draw */ |
6a51745b2784
6699843: IllegalArgumentException when using Graphics.drawString( "", 0, 0 )
prr
parents:
2
diff
changeset
|
2905 |
} |
2 | 2906 |
TextLayout tl = new TextLayout(iterator, getFontRenderContext()); |
2907 |
tl.draw(this, (float) x, (float) y); |
|
2908 |
} |
|
2909 |
||
2910 |
public void drawString(AttributedCharacterIterator iterator, |
|
2911 |
float x, float y) { |
|
2912 |
if (iterator == null) { |
|
2913 |
throw new NullPointerException("AttributedCharacterIterator is null"); |
|
2914 |
} |
|
551
6a51745b2784
6699843: IllegalArgumentException when using Graphics.drawString( "", 0, 0 )
prr
parents:
2
diff
changeset
|
2915 |
if (iterator.getBeginIndex() == iterator.getEndIndex()) { |
6a51745b2784
6699843: IllegalArgumentException when using Graphics.drawString( "", 0, 0 )
prr
parents:
2
diff
changeset
|
2916 |
return; /* nothing to draw */ |
6a51745b2784
6699843: IllegalArgumentException when using Graphics.drawString( "", 0, 0 )
prr
parents:
2
diff
changeset
|
2917 |
} |
2 | 2918 |
TextLayout tl = new TextLayout(iterator, getFontRenderContext()); |
2919 |
tl.draw(this, x, y); |
|
2920 |
} |
|
2921 |
||
2922 |
public void drawGlyphVector(GlyphVector gv, float x, float y) |
|
2923 |
{ |
|
2924 |
if (gv == null) { |
|
2925 |
throw new NullPointerException("GlyphVector is null"); |
|
2926 |
} |
|
2927 |
||
2928 |
try { |
|
2929 |
textpipe.drawGlyphVector(this, gv, x, y); |
|
2930 |
} catch (InvalidPipeException e) { |
|
2931 |
try { |
|
11899
d2eb55fd95a1
7121482: some sun/java2d and sun/awt tests failed with InvalidPipeException since 1.7.0_03b02, 6u31b02
bagiras
parents:
11897
diff
changeset
|
2932 |
revalidateAll(); |
2 | 2933 |
textpipe.drawGlyphVector(this, gv, x, y); |
2934 |
} catch (InvalidPipeException e2) { |
|
2935 |
// Still catching the exception; we are not yet ready to |
|
2936 |
// validate the surfaceData correctly. Fail for now and |
|
2937 |
// try again next time around. |
|
2938 |
} |
|
2939 |
} finally { |
|
2940 |
surfaceData.markDirty(); |
|
2941 |
} |
|
2942 |
} |
|
2943 |
||
2944 |
public void drawChars(char data[], int offset, int length, int x, int y) { |
|
2945 |
||
2946 |
if (data == null) { |
|
2947 |
throw new NullPointerException("char data is null"); |
|
2948 |
} |
|
2949 |
if (offset < 0 || length < 0 || offset + length > data.length) { |
|
2950 |
throw new ArrayIndexOutOfBoundsException("bad offset/length"); |
|
2951 |
} |
|
2952 |
if (font.hasLayoutAttributes()) { |
|
551
6a51745b2784
6699843: IllegalArgumentException when using Graphics.drawString( "", 0, 0 )
prr
parents:
2
diff
changeset
|
2953 |
if (data.length == 0) { |
6a51745b2784
6699843: IllegalArgumentException when using Graphics.drawString( "", 0, 0 )
prr
parents:
2
diff
changeset
|
2954 |
return; |
6a51745b2784
6699843: IllegalArgumentException when using Graphics.drawString( "", 0, 0 )
prr
parents:
2
diff
changeset
|
2955 |
} |
2 | 2956 |
new TextLayout(new String(data, offset, length), |
2957 |
font, getFontRenderContext()).draw(this, x, y); |
|
2958 |
return; |
|
2959 |
} |
|
2960 |
||
2961 |
try { |
|
2962 |
textpipe.drawChars(this, data, offset, length, x, y); |
|
2963 |
} catch (InvalidPipeException e) { |
|
2964 |
try { |
|
11899
d2eb55fd95a1
7121482: some sun/java2d and sun/awt tests failed with InvalidPipeException since 1.7.0_03b02, 6u31b02
bagiras
parents:
11897
diff
changeset
|
2965 |
revalidateAll(); |
2 | 2966 |
textpipe.drawChars(this, data, offset, length, x, y); |
2967 |
} catch (InvalidPipeException e2) { |
|
2968 |
// Still catching the exception; we are not yet ready to |
|
2969 |
// validate the surfaceData correctly. Fail for now and |
|
2970 |
// try again next time around. |
|
2971 |
} |
|
2972 |
} finally { |
|
2973 |
surfaceData.markDirty(); |
|
2974 |
} |
|
2975 |
} |
|
2976 |
||
2977 |
public void drawBytes(byte data[], int offset, int length, int x, int y) { |
|
2978 |
if (data == null) { |
|
2979 |
throw new NullPointerException("byte data is null"); |
|
2980 |
} |
|
2981 |
if (offset < 0 || length < 0 || offset + length > data.length) { |
|
2982 |
throw new ArrayIndexOutOfBoundsException("bad offset/length"); |
|
2983 |
} |
|
2984 |
/* Byte data is interpreted as 8-bit ASCII. Re-use drawChars loops */ |
|
2985 |
char chData[] = new char[length]; |
|
2986 |
for (int i = length; i-- > 0; ) { |
|
2987 |
chData[i] = (char)(data[i+offset] & 0xff); |
|
2988 |
} |
|
2989 |
if (font.hasLayoutAttributes()) { |
|
551
6a51745b2784
6699843: IllegalArgumentException when using Graphics.drawString( "", 0, 0 )
prr
parents:
2
diff
changeset
|
2990 |
if (data.length == 0) { |
6a51745b2784
6699843: IllegalArgumentException when using Graphics.drawString( "", 0, 0 )
prr
parents:
2
diff
changeset
|
2991 |
return; |
6a51745b2784
6699843: IllegalArgumentException when using Graphics.drawString( "", 0, 0 )
prr
parents:
2
diff
changeset
|
2992 |
} |
2 | 2993 |
new TextLayout(new String(chData), |
2994 |
font, getFontRenderContext()).draw(this, x, y); |
|
2995 |
return; |
|
2996 |
} |
|
2997 |
||
2998 |
try { |
|
2999 |
textpipe.drawChars(this, chData, 0, length, x, y); |
|
3000 |
} catch (InvalidPipeException e) { |
|
3001 |
try { |
|
11899
d2eb55fd95a1
7121482: some sun/java2d and sun/awt tests failed with InvalidPipeException since 1.7.0_03b02, 6u31b02
bagiras
parents:
11897
diff
changeset
|
3002 |
revalidateAll(); |
2 | 3003 |
textpipe.drawChars(this, chData, 0, length, x, y); |
3004 |
} catch (InvalidPipeException e2) { |
|
3005 |
// Still catching the exception; we are not yet ready to |
|
3006 |
// validate the surfaceData correctly. Fail for now and |
|
3007 |
// try again next time around. |
|
3008 |
} |
|
3009 |
} finally { |
|
3010 |
surfaceData.markDirty(); |
|
3011 |
} |
|
3012 |
} |
|
3013 |
// end of text rendering methods |
|
3014 |
||
3015 |
/** |
|
3016 |
* Draws an image scaled to x,y,w,h in nonblocking mode with a |
|
3017 |
* callback object. |
|
3018 |
*/ |
|
3019 |
public boolean drawImage(Image img, int x, int y, int width, int height, |
|
3020 |
ImageObserver observer) { |
|
3021 |
return drawImage(img, x, y, width, height, null, observer); |
|
3022 |
} |
|
3023 |
||
3024 |
/** |
|
3025 |
* Not part of the advertised API but a useful utility method |
|
3026 |
* to call internally. This is for the case where we are |
|
3027 |
* drawing to/from given coordinates using a given width/height, |
|
3028 |
* but we guarantee that the weidth/height of the src and dest |
|
3029 |
* areas are equal (no scale needed). |
|
3030 |
*/ |
|
3031 |
public boolean copyImage(Image img, int dx, int dy, int sx, int sy, |
|
3032 |
int width, int height, Color bgcolor, |
|
3033 |
ImageObserver observer) { |
|
3034 |
try { |
|
3035 |
return imagepipe.copyImage(this, img, dx, dy, sx, sy, |
|
3036 |
width, height, bgcolor, observer); |
|
3037 |
} catch (InvalidPipeException e) { |
|
3038 |
try { |
|
11899
d2eb55fd95a1
7121482: some sun/java2d and sun/awt tests failed with InvalidPipeException since 1.7.0_03b02, 6u31b02
bagiras
parents:
11897
diff
changeset
|
3039 |
revalidateAll(); |
2 | 3040 |
return imagepipe.copyImage(this, img, dx, dy, sx, sy, |
3041 |
width, height, bgcolor, observer); |
|
3042 |
} catch (InvalidPipeException e2) { |
|
3043 |
// Still catching the exception; we are not yet ready to |
|
3044 |
// validate the surfaceData correctly. Fail for now and |
|
3045 |
// try again next time around. |
|
3046 |
return false; |
|
3047 |
} |
|
3048 |
} finally { |
|
3049 |
surfaceData.markDirty(); |
|
3050 |
} |
|
3051 |
} |
|
3052 |
||
3053 |
/** |
|
3054 |
* Draws an image scaled to x,y,w,h in nonblocking mode with a |
|
3055 |
* solid background color and a callback object. |
|
3056 |
*/ |
|
3057 |
public boolean drawImage(Image img, int x, int y, int width, int height, |
|
3058 |
Color bg, ImageObserver observer) { |
|
3059 |
||
3060 |
if (img == null) { |
|
3061 |
return true; |
|
3062 |
} |
|
3063 |
||
3064 |
if ((width == 0) || (height == 0)) { |
|
3065 |
return true; |
|
3066 |
} |
|
3067 |
if (width == img.getWidth(null) && height == img.getHeight(null)) { |
|
3068 |
return copyImage(img, x, y, 0, 0, width, height, bg, observer); |
|
3069 |
} |
|
3070 |
||
3071 |
try { |
|
3072 |
return imagepipe.scaleImage(this, img, x, y, width, height, |
|
3073 |
bg, observer); |
|
3074 |
} catch (InvalidPipeException e) { |
|
3075 |
try { |
|
11899
d2eb55fd95a1
7121482: some sun/java2d and sun/awt tests failed with InvalidPipeException since 1.7.0_03b02, 6u31b02
bagiras
parents:
11897
diff
changeset
|
3076 |
revalidateAll(); |
2 | 3077 |
return imagepipe.scaleImage(this, img, x, y, width, height, |
3078 |
bg, observer); |
|
3079 |
} catch (InvalidPipeException e2) { |
|
3080 |
// Still catching the exception; we are not yet ready to |
|
3081 |
// validate the surfaceData correctly. Fail for now and |
|
3082 |
// try again next time around. |
|
3083 |
return false; |
|
3084 |
} |
|
3085 |
} finally { |
|
3086 |
surfaceData.markDirty(); |
|
3087 |
} |
|
3088 |
} |
|
3089 |
||
3090 |
/** |
|
3091 |
* Draws an image at x,y in nonblocking mode. |
|
3092 |
*/ |
|
3093 |
public boolean drawImage(Image img, int x, int y, ImageObserver observer) { |
|
3094 |
return drawImage(img, x, y, null, observer); |
|
3095 |
} |
|
3096 |
||
3097 |
/** |
|
3098 |
* Draws an image at x,y in nonblocking mode with a solid background |
|
3099 |
* color and a callback object. |
|
3100 |
*/ |
|
3101 |
public boolean drawImage(Image img, int x, int y, Color bg, |
|
3102 |
ImageObserver observer) { |
|
3103 |
||
3104 |
if (img == null) { |
|
3105 |
return true; |
|
3106 |
} |
|
3107 |
||
3108 |
try { |
|
3109 |
return imagepipe.copyImage(this, img, x, y, bg, observer); |
|
3110 |
} catch (InvalidPipeException e) { |
|
3111 |
try { |
|
11899
d2eb55fd95a1
7121482: some sun/java2d and sun/awt tests failed with InvalidPipeException since 1.7.0_03b02, 6u31b02
bagiras
parents:
11897
diff
changeset
|
3112 |
revalidateAll(); |
2 | 3113 |
return imagepipe.copyImage(this, img, x, y, bg, observer); |
3114 |
} catch (InvalidPipeException e2) { |
|
3115 |
// Still catching the exception; we are not yet ready to |
|
3116 |
// validate the surfaceData correctly. Fail for now and |
|
3117 |
// try again next time around. |
|
3118 |
return false; |
|
3119 |
} |
|
3120 |
} finally { |
|
3121 |
surfaceData.markDirty(); |
|
3122 |
} |
|
3123 |
} |
|
3124 |
||
3125 |
/** |
|
3126 |
* Draws a subrectangle of an image scaled to a destination rectangle |
|
3127 |
* in nonblocking mode with a callback object. |
|
3128 |
*/ |
|
3129 |
public boolean drawImage(Image img, |
|
3130 |
int dx1, int dy1, int dx2, int dy2, |
|
3131 |
int sx1, int sy1, int sx2, int sy2, |
|
3132 |
ImageObserver observer) { |
|
3133 |
return drawImage(img, dx1, dy1, dx2, dy2, sx1, sy1, sx2, sy2, null, |
|
3134 |
observer); |
|
3135 |
} |
|
3136 |
||
3137 |
/** |
|
3138 |
* Draws a subrectangle of an image scaled to a destination rectangle in |
|
3139 |
* nonblocking mode with a solid background color and a callback object. |
|
3140 |
*/ |
|
3141 |
public boolean drawImage(Image img, |
|
3142 |
int dx1, int dy1, int dx2, int dy2, |
|
3143 |
int sx1, int sy1, int sx2, int sy2, |
|
3144 |
Color bgcolor, ImageObserver observer) { |
|
3145 |
||
3146 |
if (img == null) { |
|
3147 |
return true; |
|
3148 |
} |
|
3149 |
||
3150 |
if (dx1 == dx2 || dy1 == dy2 || |
|
3151 |
sx1 == sx2 || sy1 == sy2) |
|
3152 |
{ |
|
3153 |
return true; |
|
3154 |
} |
|
3155 |
||
3156 |
if (((sx2 - sx1) == (dx2 - dx1)) && |
|
3157 |
((sy2 - sy1) == (dy2 - dy1))) |
|
3158 |
{ |
|
3159 |
// Not a scale - forward it to a copy routine |
|
3160 |
int srcX, srcY, dstX, dstY, width, height; |
|
3161 |
if (sx2 > sx1) { |
|
3162 |
width = sx2 - sx1; |
|
3163 |
srcX = sx1; |
|
3164 |
dstX = dx1; |
|
3165 |
} else { |
|
3166 |
width = sx1 - sx2; |
|
3167 |
srcX = sx2; |
|
3168 |
dstX = dx2; |
|
3169 |
} |
|
3170 |
if (sy2 > sy1) { |
|
3171 |
height = sy2-sy1; |
|
3172 |
srcY = sy1; |
|
3173 |
dstY = dy1; |
|
3174 |
} else { |
|
3175 |
height = sy1-sy2; |
|
3176 |
srcY = sy2; |
|
3177 |
dstY = dy2; |
|
3178 |
} |
|
3179 |
return copyImage(img, dstX, dstY, srcX, srcY, |
|
3180 |
width, height, bgcolor, observer); |
|
3181 |
} |
|
3182 |
||
3183 |
try { |
|
3184 |
return imagepipe.scaleImage(this, img, dx1, dy1, dx2, dy2, |
|
3185 |
sx1, sy1, sx2, sy2, bgcolor, |
|
3186 |
observer); |
|
3187 |
} catch (InvalidPipeException e) { |
|
3188 |
try { |
|
11899
d2eb55fd95a1
7121482: some sun/java2d and sun/awt tests failed with InvalidPipeException since 1.7.0_03b02, 6u31b02
bagiras
parents:
11897
diff
changeset
|
3189 |
revalidateAll(); |
2 | 3190 |
return imagepipe.scaleImage(this, img, dx1, dy1, dx2, dy2, |
3191 |
sx1, sy1, sx2, sy2, bgcolor, |
|
3192 |
observer); |
|
3193 |
} catch (InvalidPipeException e2) { |
|
3194 |
// Still catching the exception; we are not yet ready to |
|
3195 |
// validate the surfaceData correctly. Fail for now and |
|
3196 |
// try again next time around. |
|
3197 |
return false; |
|
3198 |
} |
|
3199 |
} finally { |
|
3200 |
surfaceData.markDirty(); |
|
3201 |
} |
|
3202 |
} |
|
3203 |
||
3204 |
/** |
|
3205 |
* Draw an image, applying a transform from image space into user space |
|
3206 |
* before drawing. |
|
3207 |
* The transformation from user space into device space is done with |
|
3208 |
* the current transform in the Graphics2D. |
|
3209 |
* The given transformation is applied to the image before the |
|
3210 |
* transform attribute in the Graphics2D state is applied. |
|
3211 |
* The rendering attributes applied include the clip, transform, |
|
3212 |
* paint or color and composite attributes. Note that the result is |
|
3213 |
* undefined, if the given transform is non-invertible. |
|
3214 |
* @param img The image to be drawn. |
|
3215 |
* @param xform The transformation from image space into user space. |
|
3216 |
* @param observer The image observer to be notified on the image producing |
|
3217 |
* progress. |
|
3218 |
* @see #transform |
|
3219 |
* @see #setComposite |
|
3220 |
* @see #setClip |
|
3221 |
*/ |
|
3222 |
public boolean drawImage(Image img, |
|
3223 |
AffineTransform xform, |
|
3224 |
ImageObserver observer) { |
|
3225 |
||
3226 |
if (img == null) { |
|
3227 |
return true; |
|
3228 |
} |
|
3229 |
||
3230 |
if (xform == null || xform.isIdentity()) { |
|
3231 |
return drawImage(img, 0, 0, null, observer); |
|
3232 |
} |
|
3233 |
||
3234 |
try { |
|
3235 |
return imagepipe.transformImage(this, img, xform, observer); |
|
3236 |
} catch (InvalidPipeException e) { |
|
3237 |
try { |
|
11899
d2eb55fd95a1
7121482: some sun/java2d and sun/awt tests failed with InvalidPipeException since 1.7.0_03b02, 6u31b02
bagiras
parents:
11897
diff
changeset
|
3238 |
revalidateAll(); |
2 | 3239 |
return imagepipe.transformImage(this, img, xform, observer); |
3240 |
} catch (InvalidPipeException e2) { |
|
3241 |
// Still catching the exception; we are not yet ready to |
|
3242 |
// validate the surfaceData correctly. Fail for now and |
|
3243 |
// try again next time around. |
|
3244 |
return false; |
|
3245 |
} |
|
3246 |
} finally { |
|
3247 |
surfaceData.markDirty(); |
|
3248 |
} |
|
3249 |
} |
|
3250 |
||
3251 |
public void drawImage(BufferedImage bImg, |
|
3252 |
BufferedImageOp op, |
|
3253 |
int x, |
|
3254 |
int y) { |
|
3255 |
||
3256 |
if (bImg == null) { |
|
3257 |
return; |
|
3258 |
} |
|
3259 |
||
3260 |
try { |
|
3261 |
imagepipe.transformImage(this, bImg, op, x, y); |
|
3262 |
} catch (InvalidPipeException e) { |
|
3263 |
try { |
|
11899
d2eb55fd95a1
7121482: some sun/java2d and sun/awt tests failed with InvalidPipeException since 1.7.0_03b02, 6u31b02
bagiras
parents:
11897
diff
changeset
|
3264 |
revalidateAll(); |
2 | 3265 |
imagepipe.transformImage(this, bImg, op, x, y); |
3266 |
} catch (InvalidPipeException e2) { |
|
3267 |
// Still catching the exception; we are not yet ready to |
|
3268 |
// validate the surfaceData correctly. Fail for now and |
|
3269 |
// try again next time around. |
|
3270 |
} |
|
3271 |
} finally { |
|
3272 |
surfaceData.markDirty(); |
|
3273 |
} |
|
3274 |
} |
|
3275 |
||
3276 |
/** |
|
3277 |
* Get the rendering context of the font |
|
3278 |
* within this Graphics2D context. |
|
3279 |
*/ |
|
3280 |
public FontRenderContext getFontRenderContext() { |
|
3281 |
if (cachedFRC == null) { |
|
3282 |
int aahint = textAntialiasHint; |
|
3283 |
if (aahint == SunHints.INTVAL_TEXT_ANTIALIAS_DEFAULT && |
|
3284 |
antialiasHint == SunHints.INTVAL_ANTIALIAS_ON) { |
|
3285 |
aahint = SunHints.INTVAL_TEXT_ANTIALIAS_ON; |
|
3286 |
} |
|
3287 |
// Translation components should be excluded from the FRC transform |
|
3288 |
AffineTransform tx = null; |
|
3289 |
if (transformState >= TRANSFORM_TRANSLATESCALE) { |
|
3290 |
if (transform.getTranslateX() == 0 && |
|
3291 |
transform.getTranslateY() == 0) { |
|
3292 |
tx = transform; |
|
3293 |
} else { |
|
3294 |
tx = new AffineTransform(transform.getScaleX(), |
|
3295 |
transform.getShearY(), |
|
3296 |
transform.getShearX(), |
|
3297 |
transform.getScaleY(), |
|
3298 |
0, 0); |
|
3299 |
} |
|
3300 |
} |
|
3301 |
cachedFRC = new FontRenderContext(tx, |
|
3302 |
SunHints.Value.get(SunHints.INTKEY_TEXT_ANTIALIASING, aahint), |
|
3303 |
SunHints.Value.get(SunHints.INTKEY_FRACTIONALMETRICS, |
|
3304 |
fractionalMetricsHint)); |
|
3305 |
} |
|
3306 |
return cachedFRC; |
|
3307 |
} |
|
3308 |
private FontRenderContext cachedFRC; |
|
3309 |
||
3310 |
/** |
|
3311 |
* This object has no resources to dispose of per se, but the |
|
3312 |
* doc comments for the base method in java.awt.Graphics imply |
|
3313 |
* that this object will not be useable after it is disposed. |
|
3314 |
* So, we sabotage the object to prevent further use to prevent |
|
3315 |
* developers from relying on behavior that may not work on |
|
3316 |
* other, less forgiving, VMs that really need to dispose of |
|
3317 |
* resources. |
|
3318 |
*/ |
|
3319 |
public void dispose() { |
|
3320 |
surfaceData = NullSurfaceData.theInstance; |
|
3321 |
invalidatePipe(); |
|
3322 |
} |
|
3323 |
||
3324 |
/** |
|
3325 |
* Graphics has a finalize method that automatically calls dispose() |
|
3326 |
* for subclasses. For SunGraphics2D we do not need to be finalized |
|
3327 |
* so that method simply causes us to be enqueued on the Finalizer |
|
3328 |
* queues for no good reason. Unfortunately, that method and |
|
3329 |
* implementation are now considered part of the public contract |
|
3330 |
* of that base class so we can not remove or gut the method. |
|
3331 |
* We override it here with an empty method and the VM is smart |
|
3332 |
* enough to know that if our override is empty then it should not |
|
3333 |
* mark us as finalizeable. |
|
3334 |
*/ |
|
3335 |
public void finalize() { |
|
3336 |
// DO NOT REMOVE THIS METHOD |
|
3337 |
} |
|
3338 |
||
3339 |
/** |
|
3340 |
* Returns destination that this Graphics renders to. This could be |
|
3341 |
* either an Image or a Component; subclasses of SurfaceData are |
|
3342 |
* responsible for returning the appropriate object. |
|
3343 |
*/ |
|
3344 |
public Object getDestination() { |
|
3345 |
return surfaceData.getDestination(); |
|
3346 |
} |
|
887 | 3347 |
|
3348 |
/** |
|
3349 |
* {@inheritDoc} |
|
3350 |
* |
|
3351 |
* @see sun.java2d.DestSurfaceProvider#getDestSurface |
|
3352 |
*/ |
|
3353 |
@Override |
|
3354 |
public Surface getDestSurface() { |
|
3355 |
return surfaceData; |
|
3356 |
} |
|
2 | 3357 |
} |