View Javadoc
1   /*
2    * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved.
3    * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4    *
5    * This code is free software; you can redistribute it and/or modify it
6    * under the terms of the GNU General Public License version 2 only, as
7    * published by the Free Software Foundation.  Oracle designates this
8    * particular file as subject to the "Classpath" exception as provided
9    * by Oracle in the LICENSE file that accompanied this code.
10   *
11   * This code is distributed in the hope that it will be useful, but WITHOUT
12   * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13   * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14   * version 2 for more details (a copy is included in the LICENSE file that
15   * accompanied this code).
16   *
17   * You should have received a copy of the GNU General Public License version
18   * 2 along with this work; if not, write to the Free Software Foundation,
19   * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20   *
21   * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22   * or visit www.oracle.com if you need additional information or have any
23   * questions.
24   */
25  
26  package sun.java2d;
27  
28  import java.awt.Color;
29  import java.awt.Rectangle;
30  import java.awt.Transparency;
31  import java.awt.GraphicsConfiguration;
32  import java.awt.Image;
33  import java.awt.image.ColorModel;
34  import java.awt.image.IndexColorModel;
35  import java.awt.image.Raster;
36  
37  import sun.java2d.loops.RenderCache;
38  import sun.java2d.loops.RenderLoops;
39  import sun.java2d.loops.CompositeType;
40  import sun.java2d.loops.SurfaceType;
41  import sun.java2d.loops.MaskFill;
42  import sun.java2d.loops.DrawLine;
43  import sun.java2d.loops.FillRect;
44  import sun.java2d.loops.DrawRect;
45  import sun.java2d.loops.DrawPolygons;
46  import sun.java2d.loops.DrawPath;
47  import sun.java2d.loops.FillPath;
48  import sun.java2d.loops.FillSpans;
49  import sun.java2d.loops.FillParallelogram;
50  import sun.java2d.loops.DrawParallelogram;
51  import sun.java2d.loops.FontInfo;
52  import sun.java2d.loops.DrawGlyphList;
53  import sun.java2d.loops.DrawGlyphListAA;
54  import sun.java2d.loops.DrawGlyphListLCD;
55  import sun.java2d.pipe.LoopPipe;
56  import sun.java2d.pipe.ShapeDrawPipe;
57  import sun.java2d.pipe.ParallelogramPipe;
58  import sun.java2d.pipe.CompositePipe;
59  import sun.java2d.pipe.GeneralCompositePipe;
60  import sun.java2d.pipe.SpanClipRenderer;
61  import sun.java2d.pipe.SpanShapeRenderer;
62  import sun.java2d.pipe.AAShapePipe;
63  import sun.java2d.pipe.AlphaPaintPipe;
64  import sun.java2d.pipe.AlphaColorPipe;
65  import sun.java2d.pipe.PixelToShapeConverter;
66  import sun.java2d.pipe.PixelToParallelogramConverter;
67  import sun.java2d.pipe.TextPipe;
68  import sun.java2d.pipe.TextRenderer;
69  import sun.java2d.pipe.AATextRenderer;
70  import sun.java2d.pipe.LCDTextRenderer;
71  import sun.java2d.pipe.SolidTextRenderer;
72  import sun.java2d.pipe.OutlineTextRenderer;
73  import sun.java2d.pipe.DrawImagePipe;
74  import sun.java2d.pipe.DrawImage;
75  import sun.awt.SunHints;
76  import sun.awt.image.SurfaceManager;
77  import sun.java2d.pipe.LoopBasedPipe;
78  
79  /**
80   * This class provides various pieces of information relevant to a
81   * particular drawing surface.  The information obtained from this
82   * object describes the pixels of a particular instance of a drawing
83   * surface and can only be shared among the various graphics objects
84   * that target the same BufferedImage or the same screen Component.
85   * <p>
86   * Each SurfaceData object holds a StateTrackableDelegate object
87   * which tracks both changes to the content of the pixels of this
88   * surface and changes to the overall state of the pixels - such
89   * as becoming invalid or losing the surface.  The delegate is
90   * marked "dirty" whenever the setSurfaceLost() or invalidate()
91   * methods are called and should also be marked "dirty" by the
92   * rendering pipelines whenever they modify the pixels of this
93   * SurfaceData.
94   * <p>
95   * If you get a StateTracker from a SurfaceData and it reports
96   * that it is still "current", then you can trust that the pixels
97   * have not changed and that the SurfaceData is still valid and
98   * has not lost its underlying storage (surfaceLost) since you
99   * retrieved the tracker.
100  */
101 public abstract class SurfaceData
102     implements Transparency, DisposerTarget, StateTrackable, Surface
103 {
104     private long pData;
105     private boolean valid;
106     private boolean surfaceLost; // = false;
107     private SurfaceType surfaceType;
108     private ColorModel colorModel;
109 
110     private Object disposerReferent = new Object();
111 
112     private static native void initIDs();
113 
114     private Object blitProxyKey;
115     private StateTrackableDelegate stateDelegate;
116 
117     static {
118         initIDs();
119     }
120 
121     protected SurfaceData(SurfaceType surfaceType, ColorModel cm) {
122         this(State.STABLE, surfaceType, cm);
123     }
124 
125     protected SurfaceData(State state, SurfaceType surfaceType, ColorModel cm) {
126         this(StateTrackableDelegate.createInstance(state), surfaceType, cm);
127     }
128 
129     protected SurfaceData(StateTrackableDelegate trackable,
130                           SurfaceType surfaceType, ColorModel cm)
131     {
132         this.stateDelegate = trackable;
133         this.colorModel = cm;
134         this.surfaceType = surfaceType;
135         valid = true;
136     }
137 
138     protected SurfaceData(State state) {
139         this.stateDelegate = StateTrackableDelegate.createInstance(state);
140         valid = true;
141     }
142 
143     /**
144      * Subclasses can set a "blit proxy key" which will be used
145      * along with the SurfaceManager.getCacheData() mechanism to
146      * store acceleration-compatible cached copies of source images.
147      * This key is a "tag" used to identify which cached copies
148      * are compatible with this destination SurfaceData.
149      * The getSourceSurfaceData() method uses this key to manage
150      * cached copies of a source image as described below.
151      * <p>
152      * The Object used as this key should be as unique as it needs
153      * to be to ensure that multiple acceleratible destinations can
154      * each store their cached copies separately under different keys
155      * without interfering with each other or getting back the wrong
156      * cached copy.
157      * <p>
158      * Many acceleratable SurfaceData objects can use their own
159      * GraphicsConfiguration as their proxy key as the GC object will
160      * typically be unique to a given screen and pixel format, but
161      * other rendering destinations may have more or less stringent
162      * sharing requirements.  For instance, X11 pixmaps can be
163      * shared on a given screen by any GraphicsConfiguration that
164      * has the same depth and SurfaceType.  Multiple such GCs with
165      * the same depth and SurfaceType can exist per screen so storing
166      * a different cached proxy for each would be a waste.  One can
167      * imagine platforms where a single cached copy can be created
168      * and shared across all screens and pixel formats - such
169      * implementations could use a single heavily shared key Object.
170      */
171     protected void setBlitProxyKey(Object key) {
172         // Caching is effectively disabled if we never have a proxy key
173         // since the getSourceSurfaceData() method only does caching
174         // if the key is not null.
175         if (SurfaceDataProxy.isCachingAllowed()) {
176             this.blitProxyKey = key;
177         }
178     }
179 
180     /**
181      * This method is called on a destination SurfaceData to choose
182      * the best SurfaceData from a source Image for an imaging
183      * operation, with help from its SurfaceManager.
184      * The method may determine that the default SurfaceData was
185      * really the best choice in the first place, or it may decide
186      * to use a cached surface.  Some general decisions about whether
187      * acceleration is enabled are made by this method, but any
188      * decision based on the type of the source image is made in
189      * the makeProxyFor method below when it comes up with the
190      * appropriate SurfaceDataProxy instance.
191      * The parameters describe the type of imaging operation being performed.
192      * <p>
193      * If a blitProxyKey was supplied by the subclass then it is
194      * used to potentially override the choice of source SurfaceData.
195      * The outline of this process is:
196      * <ol>
197      * <li> Image pipeline asks destSD to find an appropriate
198      *      srcSD for a given source Image object.
199      * <li> destSD gets the SurfaceManager of the source Image
200      *      and first retrieves the default SD from it using
201      *      getPrimarySurfaceData()
202      * <li> destSD uses its "blit proxy key" (if set) to look for
203      *      some cached data stored in the source SurfaceManager
204      * <li> If the cached data is null then makeProxyFor() is used
205      *      to create some cached data which is stored back in the
206      *      source SurfaceManager under the same key for future uses.
207      * <li> The cached data will be a SurfaceDataProxy object.
208      * <li> The SurfaceDataProxy object is then consulted to
209      *      return a replacement SurfaceData object (typically
210      *      a cached copy if appropriate, or the original if not).
211      * </ol>
212      */
213     public SurfaceData getSourceSurfaceData(Image img,
214                                             int txtype,
215                                             CompositeType comp,
216                                             Color bgColor)
217     {
218         SurfaceManager srcMgr = SurfaceManager.getManager(img);
219         SurfaceData srcData = srcMgr.getPrimarySurfaceData();
220         if (img.getAccelerationPriority() > 0.0f &&
221             blitProxyKey != null)
222         {
223             SurfaceDataProxy sdp =
224                 (SurfaceDataProxy) srcMgr.getCacheData(blitProxyKey);
225             if (sdp == null || !sdp.isValid()) {
226                 if (srcData.getState() == State.UNTRACKABLE) {
227                     sdp = SurfaceDataProxy.UNCACHED;
228                 } else {
229                     sdp = makeProxyFor(srcData);
230                 }
231                 srcMgr.setCacheData(blitProxyKey, sdp);
232             }
233             srcData = sdp.replaceData(srcData, txtype, comp, bgColor);
234         }
235         return srcData;
236     }
237 
238     /**
239      * This method is called on a destination SurfaceData to choose
240      * a proper SurfaceDataProxy subclass for a source SurfaceData
241      * to use to control when and with what surface to override a
242      * given image operation.  The argument is the default SurfaceData
243      * for the source Image.
244      * <p>
245      * The type of the return object is chosen based on the
246      * acceleration capabilities of this SurfaceData and the
247      * type of the given source SurfaceData object.
248      * <p>
249      * In some cases the original SurfaceData will always be the
250      * best choice to use to blit to this SurfaceData.  This can
251      * happen if the source image is a hardware surface of the
252      * same type as this one and so acceleration will happen without
253      * any caching.  It may also be the case that the source image
254      * can never be accelerated on this SurfaceData - for example
255      * because it is translucent and there are no accelerated
256      * translucent image ops for this surface.
257      * <p>
258      * In those cases there is a special SurfaceDataProxy.UNCACHED
259      * instance that represents a NOP for caching purposes - it
260      * always returns the original sourceSD object as the replacement
261      * copy so no caching is ever performed.
262      */
263     public SurfaceDataProxy makeProxyFor(SurfaceData srcData) {
264         return SurfaceDataProxy.UNCACHED;
265     }
266 
267     /**
268      * Extracts the SurfaceManager from the given Image, and then
269      * returns the SurfaceData object that would best be suited as the
270      * destination surface in some rendering operation.
271      */
272     public static SurfaceData getPrimarySurfaceData(Image img) {
273         SurfaceManager sMgr = SurfaceManager.getManager(img);
274         return sMgr.getPrimarySurfaceData();
275     }
276 
277     /**
278      * Restores the contents of the given Image and then returns the new
279      * SurfaceData object in use by the Image's SurfaceManager.
280      */
281     public static SurfaceData restoreContents(Image img) {
282         SurfaceManager sMgr = SurfaceManager.getManager(img);
283         return sMgr.restoreContents();
284     }
285 
286     public State getState() {
287         return stateDelegate.getState();
288     }
289 
290     public StateTracker getStateTracker() {
291         return stateDelegate.getStateTracker();
292     }
293 
294     /**
295      * Marks this surface as dirty.
296      */
297     public final void markDirty() {
298         stateDelegate.markDirty();
299     }
300 
301     /**
302      * Sets the value of the surfaceLost variable, which indicates whether
303      * something has happened to the rendering surface such that it needs
304      * to be restored and re-rendered.
305      */
306     public void setSurfaceLost(boolean lost) {
307         surfaceLost = lost;
308         stateDelegate.markDirty();
309     }
310 
311     public boolean isSurfaceLost() {
312         return surfaceLost;
313     }
314 
315     /**
316      * Returns a boolean indicating whether or not this SurfaceData is valid.
317      */
318     public final boolean isValid() {
319         return valid;
320     }
321 
322     public Object getDisposerReferent() {
323         return disposerReferent;
324     }
325 
326     public long getNativeOps() {
327         return pData;
328     }
329 
330     /**
331      * Sets this SurfaceData object to the invalid state.  All Graphics
332      * objects must get a new SurfaceData object via the refresh method
333      * and revalidate their pipelines before continuing.
334      */
335     public void invalidate() {
336         valid = false;
337         stateDelegate.markDirty();
338     }
339 
340     /**
341      * Certain changes in the configuration of a surface require the
342      * invalidation of existing associated SurfaceData objects and
343      * the creation of brand new ones.  These changes include size,
344      * ColorModel, or SurfaceType.  Existing Graphics objects
345      * which are directed at such surfaces, however, must continue
346      * to render to them even after the change occurs underneath
347      * the covers.  The getReplacement() method is called from
348      * SunGraphics2D.revalidateAll() when the associated SurfaceData
349      * is found to be invalid so that a Graphics object can continue
350      * to render to the surface in its new configuration.
351      *
352      * Such changes only tend to happen to window based surfaces since
353      * most image based surfaces never change size or pixel format.
354      * Even VolatileImage objects never change size and they only
355      * change their pixel format when manually validated against a
356      * new GraphicsConfiguration, at which point old Graphics objects
357      * are no longer expected to render to them after the validation
358      * step.  Thus, only window based surfaces really need to deal
359      * with this form of replacement.
360      */
361     public abstract SurfaceData getReplacement();
362 
363     protected static final LoopPipe colorPrimitives;
364 
365     public static final TextPipe outlineTextRenderer;
366     public static final TextPipe solidTextRenderer;
367     public static final TextPipe aaTextRenderer;
368     public static final TextPipe lcdTextRenderer;
369 
370     protected static final AlphaColorPipe colorPipe;
371     protected static final PixelToShapeConverter colorViaShape;
372     protected static final PixelToParallelogramConverter colorViaPgram;
373     protected static final TextPipe colorText;
374     protected static final CompositePipe clipColorPipe;
375     protected static final TextPipe clipColorText;
376     protected static final AAShapePipe AAColorShape;
377     protected static final PixelToParallelogramConverter AAColorViaShape;
378     protected static final PixelToParallelogramConverter AAColorViaPgram;
379     protected static final AAShapePipe AAClipColorShape;
380     protected static final PixelToParallelogramConverter AAClipColorViaShape;
381 
382     protected static final CompositePipe paintPipe;
383     protected static final SpanShapeRenderer paintShape;
384     protected static final PixelToShapeConverter paintViaShape;
385     protected static final TextPipe paintText;
386     protected static final CompositePipe clipPaintPipe;
387     protected static final TextPipe clipPaintText;
388     protected static final AAShapePipe AAPaintShape;
389     protected static final PixelToParallelogramConverter AAPaintViaShape;
390     protected static final AAShapePipe AAClipPaintShape;
391     protected static final PixelToParallelogramConverter AAClipPaintViaShape;
392 
393     protected static final CompositePipe compPipe;
394     protected static final SpanShapeRenderer compShape;
395     protected static final PixelToShapeConverter compViaShape;
396     protected static final TextPipe compText;
397     protected static final CompositePipe clipCompPipe;
398     protected static final TextPipe clipCompText;
399     protected static final AAShapePipe AACompShape;
400     protected static final PixelToParallelogramConverter AACompViaShape;
401     protected static final AAShapePipe AAClipCompShape;
402     protected static final PixelToParallelogramConverter AAClipCompViaShape;
403 
404     protected static final DrawImagePipe imagepipe;
405 
406     // Utility subclass to add the LoopBasedPipe tagging interface
407     static class PixelToShapeLoopConverter
408         extends PixelToShapeConverter
409         implements LoopBasedPipe
410     {
411         public PixelToShapeLoopConverter(ShapeDrawPipe pipe) {
412             super(pipe);
413         }
414     }
415 
416     // Utility subclass to add the LoopBasedPipe tagging interface
417     static class PixelToPgramLoopConverter
418         extends PixelToParallelogramConverter
419         implements LoopBasedPipe
420     {
421         public PixelToPgramLoopConverter(ShapeDrawPipe shapepipe,
422                                          ParallelogramPipe pgrampipe,
423                                          double minPenSize,
424                                          double normPosition,
425                                          boolean adjustfill)
426         {
427             super(shapepipe, pgrampipe, minPenSize, normPosition, adjustfill);
428         }
429     }
430 
431     private static PixelToParallelogramConverter
432         makeConverter(AAShapePipe renderer,
433                       ParallelogramPipe pgrampipe)
434     {
435         return new PixelToParallelogramConverter(renderer,
436                                                  pgrampipe,
437                                                  1.0/8.0, 0.499,
438                                                  false);
439     }
440 
441     private static PixelToParallelogramConverter
442         makeConverter(AAShapePipe renderer)
443     {
444         return makeConverter(renderer, renderer);
445     }
446 
447     static {
448         colorPrimitives = new LoopPipe();
449 
450         outlineTextRenderer = new OutlineTextRenderer();
451         solidTextRenderer = new SolidTextRenderer();
452         aaTextRenderer = new AATextRenderer();
453         lcdTextRenderer = new LCDTextRenderer();
454 
455         colorPipe = new AlphaColorPipe();
456         // colorShape = colorPrimitives;
457         colorViaShape = new PixelToShapeLoopConverter(colorPrimitives);
458         colorViaPgram = new PixelToPgramLoopConverter(colorPrimitives,
459                                                       colorPrimitives,
460                                                       1.0, 0.25, true);
461         colorText = new TextRenderer(colorPipe);
462         clipColorPipe = new SpanClipRenderer(colorPipe);
463         clipColorText = new TextRenderer(clipColorPipe);
464         AAColorShape = new AAShapePipe(colorPipe);
465         AAColorViaShape = makeConverter(AAColorShape);
466         AAColorViaPgram = makeConverter(AAColorShape, colorPipe);
467         AAClipColorShape = new AAShapePipe(clipColorPipe);
468         AAClipColorViaShape = makeConverter(AAClipColorShape);
469 
470         paintPipe = new AlphaPaintPipe();
471         paintShape = new SpanShapeRenderer.Composite(paintPipe);
472         paintViaShape = new PixelToShapeConverter(paintShape);
473         paintText = new TextRenderer(paintPipe);
474         clipPaintPipe = new SpanClipRenderer(paintPipe);
475         clipPaintText = new TextRenderer(clipPaintPipe);
476         AAPaintShape = new AAShapePipe(paintPipe);
477         AAPaintViaShape = makeConverter(AAPaintShape);
478         AAClipPaintShape = new AAShapePipe(clipPaintPipe);
479         AAClipPaintViaShape = makeConverter(AAClipPaintShape);
480 
481         compPipe = new GeneralCompositePipe();
482         compShape = new SpanShapeRenderer.Composite(compPipe);
483         compViaShape = new PixelToShapeConverter(compShape);
484         compText = new TextRenderer(compPipe);
485         clipCompPipe = new SpanClipRenderer(compPipe);
486         clipCompText = new TextRenderer(clipCompPipe);
487         AACompShape = new AAShapePipe(compPipe);
488         AACompViaShape = makeConverter(AACompShape);
489         AAClipCompShape = new AAShapePipe(clipCompPipe);
490         AAClipCompViaShape = makeConverter(AAClipCompShape);
491 
492         imagepipe = new DrawImage();
493     }
494 
495     /* Not all surfaces and rendering mode combinations support LCD text. */
496     static final int LOOP_UNKNOWN = 0;
497     static final int LOOP_FOUND = 1;
498     static final int LOOP_NOTFOUND = 2;
499     int haveLCDLoop;
500     int havePgramXORLoop;
501     int havePgramSolidLoop;
502 
503     public boolean canRenderLCDText(SunGraphics2D sg2d) {
504         // For now the answer can only be true in the following cases:
505         if (sg2d.compositeState <= SunGraphics2D.COMP_ISCOPY &&
506             sg2d.paintState <= SunGraphics2D.PAINT_ALPHACOLOR &&
507             sg2d.clipState <= SunGraphics2D.CLIP_RECTANGULAR &&
508             sg2d.surfaceData.getTransparency() == Transparency.OPAQUE)
509         {
510             if (haveLCDLoop == LOOP_UNKNOWN) {
511                 DrawGlyphListLCD loop =
512                     DrawGlyphListLCD.locate(SurfaceType.AnyColor,
513                                             CompositeType.SrcNoEa,
514                                             getSurfaceType());
515                 haveLCDLoop = (loop != null) ? LOOP_FOUND : LOOP_NOTFOUND;
516             }
517             return haveLCDLoop == LOOP_FOUND;
518         }
519         return false; /* for now - in the future we may want to search */
520     }
521 
522     public boolean canRenderParallelograms(SunGraphics2D sg2d) {
523         if (sg2d.paintState <= SunGraphics2D.PAINT_ALPHACOLOR) {
524             if (sg2d.compositeState == SunGraphics2D.COMP_XOR) {
525                 if (havePgramXORLoop == LOOP_UNKNOWN) {
526                     FillParallelogram loop =
527                         FillParallelogram.locate(SurfaceType.AnyColor,
528                                                  CompositeType.Xor,
529                                                  getSurfaceType());
530                     havePgramXORLoop =
531                         (loop != null) ? LOOP_FOUND : LOOP_NOTFOUND;
532                 }
533                 return havePgramXORLoop == LOOP_FOUND;
534             } else if (sg2d.compositeState <= SunGraphics2D.COMP_ISCOPY &&
535                        sg2d.antialiasHint != SunHints.INTVAL_ANTIALIAS_ON &&
536                        sg2d.clipState != SunGraphics2D.CLIP_SHAPE)
537             {
538                 if (havePgramSolidLoop == LOOP_UNKNOWN) {
539                     FillParallelogram loop =
540                         FillParallelogram.locate(SurfaceType.AnyColor,
541                                                  CompositeType.SrcNoEa,
542                                                  getSurfaceType());
543                     havePgramSolidLoop =
544                         (loop != null) ? LOOP_FOUND : LOOP_NOTFOUND;
545                 }
546                 return havePgramSolidLoop == LOOP_FOUND;
547             }
548         }
549         return false;
550     }
551 
552     public void validatePipe(SunGraphics2D sg2d) {
553         sg2d.imagepipe = imagepipe;
554         if (sg2d.compositeState == SunGraphics2D.COMP_XOR) {
555             if (sg2d.paintState > SunGraphics2D.PAINT_ALPHACOLOR) {
556                 sg2d.drawpipe = paintViaShape;
557                 sg2d.fillpipe = paintViaShape;
558                 sg2d.shapepipe = paintShape;
559                 // REMIND: Ideally custom paint mode would use glyph
560                 // rendering as opposed to outline rendering but the
561                 // glyph paint rendering pipeline uses MaskBlit which
562                 // is not defined for XOR.  This means that text drawn
563                 // in XOR mode with a Color object is different than
564                 // text drawn in XOR mode with a Paint object.
565                 sg2d.textpipe = outlineTextRenderer;
566             } else {
567                 PixelToShapeConverter converter;
568                 if (canRenderParallelograms(sg2d)) {
569                     converter = colorViaPgram;
570                     // Note that we use the transforming pipe here because it
571                     // will examine the shape and possibly perform an optimized
572                     // operation if it can be simplified.  The simplifications
573                     // will be valid for all STROKE and TRANSFORM types.
574                     sg2d.shapepipe = colorViaPgram;
575                 } else {
576                     converter = colorViaShape;
577                     sg2d.shapepipe = colorPrimitives;
578                 }
579                 if (sg2d.clipState == SunGraphics2D.CLIP_SHAPE) {
580                     sg2d.drawpipe = converter;
581                     sg2d.fillpipe = converter;
582                     // REMIND: We should not be changing text strategies
583                     // between outline and glyph rendering based upon the
584                     // presence of a complex clip as that could cause a
585                     // mismatch when drawing the same text both clipped
586                     // and unclipped on two separate rendering passes.
587                     // Unfortunately, all of the clipped glyph rendering
588                     // pipelines rely on the use of the MaskBlit operation
589                     // which is not defined for XOR.
590                     sg2d.textpipe = outlineTextRenderer;
591                 } else {
592                     if (sg2d.transformState >= SunGraphics2D.TRANSFORM_TRANSLATESCALE) {
593                         sg2d.drawpipe = converter;
594                         sg2d.fillpipe = converter;
595                     } else {
596                         if (sg2d.strokeState != SunGraphics2D.STROKE_THIN) {
597                             sg2d.drawpipe = converter;
598                         } else {
599                             sg2d.drawpipe = colorPrimitives;
600                         }
601                         sg2d.fillpipe = colorPrimitives;
602                     }
603                     sg2d.textpipe = solidTextRenderer;
604                 }
605                 // assert(sg2d.surfaceData == this);
606             }
607         } else if (sg2d.compositeState == SunGraphics2D.COMP_CUSTOM) {
608             if (sg2d.antialiasHint == SunHints.INTVAL_ANTIALIAS_ON) {
609                 if (sg2d.clipState == SunGraphics2D.CLIP_SHAPE) {
610                     sg2d.drawpipe = AAClipCompViaShape;
611                     sg2d.fillpipe = AAClipCompViaShape;
612                     sg2d.shapepipe = AAClipCompViaShape;
613                     sg2d.textpipe = clipCompText;
614                 } else {
615                     sg2d.drawpipe = AACompViaShape;
616                     sg2d.fillpipe = AACompViaShape;
617                     sg2d.shapepipe = AACompViaShape;
618                     sg2d.textpipe = compText;
619                 }
620             } else {
621                 sg2d.drawpipe = compViaShape;
622                 sg2d.fillpipe = compViaShape;
623                 sg2d.shapepipe = compShape;
624                 if (sg2d.clipState == SunGraphics2D.CLIP_SHAPE) {
625                     sg2d.textpipe = clipCompText;
626                 } else {
627                     sg2d.textpipe = compText;
628                 }
629             }
630         } else if (sg2d.antialiasHint == SunHints.INTVAL_ANTIALIAS_ON) {
631             sg2d.alphafill = getMaskFill(sg2d);
632             // assert(sg2d.surfaceData == this);
633             if (sg2d.alphafill != null) {
634                 if (sg2d.clipState == SunGraphics2D.CLIP_SHAPE) {
635                     sg2d.drawpipe = AAClipColorViaShape;
636                     sg2d.fillpipe = AAClipColorViaShape;
637                     sg2d.shapepipe = AAClipColorViaShape;
638                     sg2d.textpipe = clipColorText;
639                 } else {
640                     PixelToParallelogramConverter converter =
641                         (sg2d.alphafill.canDoParallelograms()
642                          ? AAColorViaPgram
643                          : AAColorViaShape);
644                     sg2d.drawpipe = converter;
645                     sg2d.fillpipe = converter;
646                     sg2d.shapepipe = converter;
647                     if (sg2d.paintState > SunGraphics2D.PAINT_ALPHACOLOR ||
648                         sg2d.compositeState > SunGraphics2D.COMP_ISCOPY)
649                     {
650                         sg2d.textpipe = colorText;
651                     } else {
652                         sg2d.textpipe = getTextPipe(sg2d, true /* AA==ON */);
653                     }
654                 }
655             } else {
656                 if (sg2d.clipState == SunGraphics2D.CLIP_SHAPE) {
657                     sg2d.drawpipe = AAClipPaintViaShape;
658                     sg2d.fillpipe = AAClipPaintViaShape;
659                     sg2d.shapepipe = AAClipPaintViaShape;
660                     sg2d.textpipe = clipPaintText;
661                 } else {
662                     sg2d.drawpipe = AAPaintViaShape;
663                     sg2d.fillpipe = AAPaintViaShape;
664                     sg2d.shapepipe = AAPaintViaShape;
665                     sg2d.textpipe = paintText;
666                 }
667             }
668         } else if (sg2d.paintState > SunGraphics2D.PAINT_ALPHACOLOR ||
669                    sg2d.compositeState > SunGraphics2D.COMP_ISCOPY ||
670                    sg2d.clipState == SunGraphics2D.CLIP_SHAPE)
671         {
672             sg2d.drawpipe = paintViaShape;
673             sg2d.fillpipe = paintViaShape;
674             sg2d.shapepipe = paintShape;
675             sg2d.alphafill = getMaskFill(sg2d);
676             // assert(sg2d.surfaceData == this);
677             if (sg2d.alphafill != null) {
678                 if (sg2d.clipState == SunGraphics2D.CLIP_SHAPE) {
679                     sg2d.textpipe = clipColorText;
680                 } else {
681                     sg2d.textpipe = colorText;
682                 }
683             } else {
684                 if (sg2d.clipState == SunGraphics2D.CLIP_SHAPE) {
685                     sg2d.textpipe = clipPaintText;
686                 } else {
687                     sg2d.textpipe = paintText;
688                 }
689             }
690         } else {
691             PixelToShapeConverter converter;
692             if (canRenderParallelograms(sg2d)) {
693                 converter = colorViaPgram;
694                 // Note that we use the transforming pipe here because it
695                 // will examine the shape and possibly perform an optimized
696                 // operation if it can be simplified.  The simplifications
697                 // will be valid for all STROKE and TRANSFORM types.
698                 sg2d.shapepipe = colorViaPgram;
699             } else {
700                 converter = colorViaShape;
701                 sg2d.shapepipe = colorPrimitives;
702             }
703             if (sg2d.transformState >= SunGraphics2D.TRANSFORM_TRANSLATESCALE) {
704                 sg2d.drawpipe = converter;
705                 sg2d.fillpipe = converter;
706             } else {
707                 if (sg2d.strokeState != SunGraphics2D.STROKE_THIN) {
708                     sg2d.drawpipe = converter;
709                 } else {
710                     sg2d.drawpipe = colorPrimitives;
711                 }
712                 sg2d.fillpipe = colorPrimitives;
713             }
714 
715             sg2d.textpipe = getTextPipe(sg2d, false /* AA==OFF */);
716             // assert(sg2d.surfaceData == this);
717         }
718 
719         // check for loops
720         if (sg2d.textpipe  instanceof LoopBasedPipe ||
721             sg2d.shapepipe instanceof LoopBasedPipe ||
722             sg2d.fillpipe  instanceof LoopBasedPipe ||
723             sg2d.drawpipe  instanceof LoopBasedPipe ||
724             sg2d.imagepipe instanceof LoopBasedPipe)
725         {
726             sg2d.loops = getRenderLoops(sg2d);
727         }
728     }
729 
730     /* Return the text pipe to be used based on the graphics AA hint setting,
731      * and the rest of the graphics state is compatible with these loops.
732      * If the text AA hint is "DEFAULT", then the AA graphics hint requests
733      * the AA text renderer, else it requests the B&W text renderer.
734      */
735     private TextPipe getTextPipe(SunGraphics2D sg2d, boolean aaHintIsOn) {
736 
737         /* Try to avoid calling getFontInfo() unless its needed to
738          * resolve one of the new AA types.
739          */
740         switch (sg2d.textAntialiasHint) {
741         case SunHints.INTVAL_TEXT_ANTIALIAS_DEFAULT:
742             if (aaHintIsOn) {
743                 return aaTextRenderer;
744             } else {
745                 return solidTextRenderer;
746             }
747         case SunHints.INTVAL_TEXT_ANTIALIAS_OFF:
748             return solidTextRenderer;
749 
750         case SunHints.INTVAL_TEXT_ANTIALIAS_ON:
751             return aaTextRenderer;
752 
753         default:
754             switch (sg2d.getFontInfo().aaHint) {
755 
756             case SunHints.INTVAL_TEXT_ANTIALIAS_LCD_HRGB:
757             case SunHints.INTVAL_TEXT_ANTIALIAS_LCD_VRGB:
758                 return lcdTextRenderer;
759 
760             case SunHints.INTVAL_TEXT_ANTIALIAS_ON:
761                 return aaTextRenderer;
762 
763             case SunHints.INTVAL_TEXT_ANTIALIAS_OFF:
764                 return solidTextRenderer;
765 
766                  /* This should not be reached as the FontInfo will
767                  * always explicitly set its hint value. So whilst
768                  * this could be collapsed to returning say just
769                  * solidTextRenderer, or even removed, its left
770                  * here in case DEFAULT is ever passed in.
771                  */
772             default:
773                 if (aaHintIsOn) {
774                     return aaTextRenderer;
775                 } else {
776                     return solidTextRenderer;
777                 }
778             }
779         }
780     }
781 
782     private static SurfaceType getPaintSurfaceType(SunGraphics2D sg2d) {
783         switch (sg2d.paintState) {
784         case SunGraphics2D.PAINT_OPAQUECOLOR:
785             return SurfaceType.OpaqueColor;
786         case SunGraphics2D.PAINT_ALPHACOLOR:
787             return SurfaceType.AnyColor;
788         case SunGraphics2D.PAINT_GRADIENT:
789             if (sg2d.paint.getTransparency() == OPAQUE) {
790                 return SurfaceType.OpaqueGradientPaint;
791             } else {
792                 return SurfaceType.GradientPaint;
793             }
794         case SunGraphics2D.PAINT_LIN_GRADIENT:
795             if (sg2d.paint.getTransparency() == OPAQUE) {
796                 return SurfaceType.OpaqueLinearGradientPaint;
797             } else {
798                 return SurfaceType.LinearGradientPaint;
799             }
800         case SunGraphics2D.PAINT_RAD_GRADIENT:
801             if (sg2d.paint.getTransparency() == OPAQUE) {
802                 return SurfaceType.OpaqueRadialGradientPaint;
803             } else {
804                 return SurfaceType.RadialGradientPaint;
805             }
806         case SunGraphics2D.PAINT_TEXTURE:
807             if (sg2d.paint.getTransparency() == OPAQUE) {
808                 return SurfaceType.OpaqueTexturePaint;
809             } else {
810                 return SurfaceType.TexturePaint;
811             }
812         default:
813         case SunGraphics2D.PAINT_CUSTOM:
814             return SurfaceType.AnyPaint;
815         }
816     }
817 
818     private static CompositeType getFillCompositeType(SunGraphics2D sg2d) {
819         CompositeType compType = sg2d.imageComp;
820         if (sg2d.compositeState == SunGraphics2D.COMP_ISCOPY) {
821             if (compType == CompositeType.SrcOverNoEa) {
822                 compType = CompositeType.OpaqueSrcOverNoEa;
823             } else {
824                 compType = CompositeType.SrcNoEa;
825             }
826         }
827         return compType;
828     }
829 
830     /**
831      * Returns a MaskFill object that can be used on this destination
832      * with the source (paint) and composite types determined by the given
833      * SunGraphics2D, or null if no such MaskFill object can be located.
834      * Subclasses can override this method if they wish to filter other
835      * attributes (such as the hardware capabilities of the destination
836      * surface) before returning a specific MaskFill object.
837      */
838     protected MaskFill getMaskFill(SunGraphics2D sg2d) {
839         SurfaceType src = getPaintSurfaceType(sg2d);
840         CompositeType comp = getFillCompositeType(sg2d);
841         SurfaceType dst = getSurfaceType();
842         return MaskFill.getFromCache(src, comp, dst);
843     }
844 
845     private static RenderCache loopcache = new RenderCache(30);
846 
847     /**
848      * Return a RenderLoops object containing all of the basic
849      * GraphicsPrimitive objects for rendering to the destination
850      * surface with the current attributes of the given SunGraphics2D.
851      */
852     public RenderLoops getRenderLoops(SunGraphics2D sg2d) {
853         SurfaceType src = getPaintSurfaceType(sg2d);
854         CompositeType comp = getFillCompositeType(sg2d);
855         SurfaceType dst = sg2d.getSurfaceData().getSurfaceType();
856 
857         Object o = loopcache.get(src, comp, dst);
858         if (o != null) {
859             return (RenderLoops) o;
860         }
861 
862         RenderLoops loops = makeRenderLoops(src, comp, dst);
863         loopcache.put(src, comp, dst, loops);
864         return loops;
865     }
866 
867     /**
868      * Construct and return a RenderLoops object containing all of
869      * the basic GraphicsPrimitive objects for rendering to the
870      * destination surface with the given source, destination, and
871      * composite types.
872      */
873     public static RenderLoops makeRenderLoops(SurfaceType src,
874                                               CompositeType comp,
875                                               SurfaceType dst)
876     {
877         RenderLoops loops = new RenderLoops();
878         loops.drawLineLoop = DrawLine.locate(src, comp, dst);
879         loops.fillRectLoop = FillRect.locate(src, comp, dst);
880         loops.drawRectLoop = DrawRect.locate(src, comp, dst);
881         loops.drawPolygonsLoop = DrawPolygons.locate(src, comp, dst);
882         loops.drawPathLoop = DrawPath.locate(src, comp, dst);
883         loops.fillPathLoop = FillPath.locate(src, comp, dst);
884         loops.fillSpansLoop = FillSpans.locate(src, comp, dst);
885         loops.fillParallelogramLoop = FillParallelogram.locate(src, comp, dst);
886         loops.drawParallelogramLoop = DrawParallelogram.locate(src, comp, dst);
887         loops.drawGlyphListLoop = DrawGlyphList.locate(src, comp, dst);
888         loops.drawGlyphListAALoop = DrawGlyphListAA.locate(src, comp, dst);
889         loops.drawGlyphListLCDLoop = DrawGlyphListLCD.locate(src, comp, dst);
890         /*
891         System.out.println("drawLine: "+loops.drawLineLoop);
892         System.out.println("fillRect: "+loops.fillRectLoop);
893         System.out.println("drawRect: "+loops.drawRectLoop);
894         System.out.println("drawPolygons: "+loops.drawPolygonsLoop);
895         System.out.println("fillSpans: "+loops.fillSpansLoop);
896         System.out.println("drawGlyphList: "+loops.drawGlyphListLoop);
897         System.out.println("drawGlyphListAA: "+loops.drawGlyphListAALoop);
898         System.out.println("drawGlyphListLCD: "+loops.drawGlyphListLCDLoop);
899         */
900         return loops;
901     }
902 
903     /**
904      * Return the GraphicsConfiguration object that describes this
905      * destination surface.
906      */
907     public abstract GraphicsConfiguration getDeviceConfiguration();
908 
909     /**
910      * Return the SurfaceType object that describes the destination
911      * surface.
912      */
913     public final SurfaceType getSurfaceType() {
914         return surfaceType;
915     }
916 
917     /**
918      * Return the ColorModel for the destination surface.
919      */
920     public final ColorModel getColorModel() {
921         return colorModel;
922     }
923 
924     /**
925      * Returns the type of this <code>Transparency</code>.
926      * @return the field type of this <code>Transparency</code>, which is
927      *          either OPAQUE, BITMASK or TRANSLUCENT.
928      */
929     public int getTransparency() {
930         return getColorModel().getTransparency();
931     }
932 
933     /**
934      * Return a readable Raster which contains the pixels for the
935      * specified rectangular region of the destination surface.
936      * The coordinate origin of the returned Raster is the same as
937      * the device space origin of the destination surface.
938      * In some cases the returned Raster might also be writeable.
939      * In most cases, the returned Raster might contain more pixels
940      * than requested.
941      *
942      * @see useTightBBoxes
943      */
944     public abstract Raster getRaster(int x, int y, int w, int h);
945 
946     /**
947      * Does the pixel accessibility of the destination surface
948      * suggest that rendering algorithms might want to take
949      * extra time to calculate a more accurate bounding box for
950      * the operation being performed?
951      * The typical case when this will be true is when a copy of
952      * the pixels has to be made when doing a getRaster.  The
953      * fewer pixels copied, the faster the operation will go.
954      *
955      * @see getRaster
956      */
957     public boolean useTightBBoxes() {
958         // Note: The native equivalent would trigger on VISIBLE_TO_NATIVE
959         // REMIND: This is not used - should be obsoleted maybe
960         return true;
961     }
962 
963     /**
964      * Returns the pixel data for the specified Argb value packed
965      * into an integer for easy storage and conveyance.
966      */
967     public int pixelFor(int rgb) {
968         return surfaceType.pixelFor(rgb, colorModel);
969     }
970 
971     /**
972      * Returns the pixel data for the specified color packed into an
973      * integer for easy storage and conveyance.
974      *
975      * This method will use the getRGB() method of the Color object
976      * and defer to the pixelFor(int rgb) method if not overridden.
977      *
978      * For now this is a convenience function, but for cases where
979      * the highest quality color conversion is requested, this method
980      * should be overridden in those cases so that a more direct
981      * conversion of the color to the destination color space
982      * can be done using the additional information in the Color
983      * object.
984      */
985     public int pixelFor(Color c) {
986         return pixelFor(c.getRGB());
987     }
988 
989     /**
990      * Returns the Argb representation for the specified integer value
991      * which is packed in the format of the associated ColorModel.
992      */
993     public int rgbFor(int pixel) {
994         return surfaceType.rgbFor(pixel, colorModel);
995     }
996 
997     /**
998      * Returns the bounds of the destination surface.
999      */
1000     public abstract Rectangle getBounds();
1001 
1002     static java.security.Permission compPermission;
1003 
1004     /**
1005      * Performs Security Permissions checks to see if a Custom
1006      * Composite object should be allowed access to the pixels
1007      * of this surface.
1008      */
1009     protected void checkCustomComposite() {
1010         SecurityManager sm = System.getSecurityManager();
1011         if (sm != null) {
1012             if (compPermission == null) {
1013                 compPermission =
1014                     new java.awt.AWTPermission("readDisplayPixels");
1015             }
1016             sm.checkPermission(compPermission);
1017         }
1018     }
1019 
1020     /**
1021      * Fetches private field IndexColorModel.allgrayopaque
1022      * which is true when all palette entries in the color
1023      * model are gray and opaque.
1024      */
1025     protected static native boolean isOpaqueGray(IndexColorModel icm);
1026 
1027     /**
1028      * For our purposes null and NullSurfaceData are the same as
1029      * they represent a disposed surface.
1030      */
1031     public static boolean isNull(SurfaceData sd) {
1032         if (sd == null || sd == NullSurfaceData.theInstance) {
1033             return true;
1034         }
1035         return false;
1036     }
1037 
1038     /**
1039      * Performs a copyarea within this surface.  Returns
1040      * false if there is no algorithm to perform the copyarea
1041      * given the current settings of the SunGraphics2D.
1042      */
1043     public boolean copyArea(SunGraphics2D sg2d,
1044                             int x, int y, int w, int h, int dx, int dy)
1045     {
1046         return false;
1047     }
1048 
1049     /**
1050      * Synchronously releases resources associated with this surface.
1051      */
1052     public void flush() {}
1053 
1054     /**
1055      * Returns destination associated with this SurfaceData.  This could be
1056      * either an Image or a Component; subclasses of SurfaceData are
1057      * responsible for returning the appropriate object.
1058      */
1059     public abstract Object getDestination();
1060 
1061     /**
1062      * Returns default scale factor of the destination surface. Scale factor
1063      * describes the mapping between virtual and physical coordinates of the
1064      * SurfaceData. If the scale is 2 then virtual pixel coordinates need to be
1065      * doubled for physical pixels.
1066      */
1067     public int getDefaultScale() {
1068         return 1;
1069     }
1070 }