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 
initIDs()112     private static native void initIDs();
113 
114     private Object blitProxyKey;
115     private StateTrackableDelegate stateDelegate;
116 
117     static {
initIDs()118         initIDs();
119     }
120 
SurfaceData(SurfaceType surfaceType, ColorModel cm)121     protected SurfaceData(SurfaceType surfaceType, ColorModel cm) {
122         this(State.STABLE, surfaceType, cm);
123     }
124 
SurfaceData(State state, SurfaceType surfaceType, ColorModel cm)125     protected SurfaceData(State state, SurfaceType surfaceType, ColorModel cm) {
126         this(StateTrackableDelegate.createInstance(state), surfaceType, cm);
127     }
128 
SurfaceData(StateTrackableDelegate trackable, SurfaceType surfaceType, ColorModel cm)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 
SurfaceData(State state)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      */
setBlitProxyKey(Object key)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      */
getSourceSurfaceData(Image img, int txtype, CompositeType comp, Color bgColor)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      */
makeProxyFor(SurfaceData srcData)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      */
getPrimarySurfaceData(Image img)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      */
restoreContents(Image img)281     public static SurfaceData restoreContents(Image img) {
282         SurfaceManager sMgr = SurfaceManager.getManager(img);
283         return sMgr.restoreContents();
284     }
285 
getState()286     public State getState() {
287         return stateDelegate.getState();
288     }
289 
getStateTracker()290     public StateTracker getStateTracker() {
291         return stateDelegate.getStateTracker();
292     }
293 
294     /**
295      * Marks this surface as dirty.
296      */
markDirty()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      */
setSurfaceLost(boolean lost)306     public void setSurfaceLost(boolean lost) {
307         surfaceLost = lost;
308         stateDelegate.markDirty();
309     }
310 
isSurfaceLost()311     public boolean isSurfaceLost() {
312         return surfaceLost;
313     }
314 
315     /**
316      * Returns a boolean indicating whether or not this SurfaceData is valid.
317      */
isValid()318     public final boolean isValid() {
319         return valid;
320     }
321 
getDisposerReferent()322     public Object getDisposerReferent() {
323         return disposerReferent;
324     }
325 
getNativeOps()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      */
invalidate()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      */
getReplacement()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     {
PixelToShapeLoopConverter(ShapeDrawPipe pipe)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     {
PixelToPgramLoopConverter(ShapeDrawPipe shapepipe, ParallelogramPipe pgrampipe, double minPenSize, double normPosition, boolean adjustfill)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
makeConverter(AAShapePipe renderer, ParallelogramPipe pgrampipe)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
makeConverter(AAShapePipe renderer)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 
canRenderLCDText(SunGraphics2D sg2d)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 
canRenderParallelograms(SunGraphics2D sg2d)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 
validatePipe(SunGraphics2D sg2d)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      */
getTextPipe(SunGraphics2D sg2d, boolean aaHintIsOn)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 
getPaintSurfaceType(SunGraphics2D sg2d)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 
getFillCompositeType(SunGraphics2D sg2d)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      */
getMaskFill(SunGraphics2D sg2d)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      */
getRenderLoops(SunGraphics2D sg2d)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      */
makeRenderLoops(SurfaceType src, CompositeType comp, SurfaceType dst)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      */
getDeviceConfiguration()907     public abstract GraphicsConfiguration getDeviceConfiguration();
908 
909     /**
910      * Return the SurfaceType object that describes the destination
911      * surface.
912      */
getSurfaceType()913     public final SurfaceType getSurfaceType() {
914         return surfaceType;
915     }
916 
917     /**
918      * Return the ColorModel for the destination surface.
919      */
getColorModel()920     public final ColorModel getColorModel() {
921         return colorModel;
922     }
923 
924     /**
925      * Returns the type of this {@code Transparency}.
926      * @return the field type of this {@code Transparency}, which is
927      *          either OPAQUE, BITMASK or TRANSLUCENT.
928      */
getTransparency()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      */
getRaster(int x, int y, int w, int h)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      */
useTightBBoxes()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      */
pixelFor(int rgb)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      */
pixelFor(Color c)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      */
rgbFor(int pixel)993     public int rgbFor(int pixel) {
994         return surfaceType.rgbFor(pixel, colorModel);
995     }
996 
997     /**
998      * Returns the bounds of the destination surface.
999      */
getBounds()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      */
checkCustomComposite()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      */
isOpaqueGray(IndexColorModel icm)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      */
isNull(SurfaceData sd)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      * @param x the x coordinate of the area in device space
1044      * @param y the y coordinate of the area in device space
1045      * @param w the width of the area in device space
1046      * @param h the height of the area in device space
1047      */
copyArea(SunGraphics2D sg2d, int x, int y, int w, int h, int dx, int dy)1048     public boolean copyArea(SunGraphics2D sg2d,
1049                             int x, int y, int w, int h, int dx, int dy)
1050     {
1051         return false;
1052     }
1053 
1054     /**
1055      * Synchronously releases resources associated with this surface.
1056      */
flush()1057     public void flush() {}
1058 
1059     /**
1060      * Returns destination associated with this SurfaceData.  This could be
1061      * either an Image or a Component; subclasses of SurfaceData are
1062      * responsible for returning the appropriate object.
1063      */
getDestination()1064     public abstract Object getDestination();
1065 
1066     /**
1067      * Returns default horizontal scale factor of the destination surface. Scale
1068      * factor describes the mapping between virtual and physical coordinates of the
1069      * SurfaceData. If the scale is 2 then virtual pixel coordinates need to be
1070      * doubled for physical pixels.
1071      */
getDefaultScaleX()1072     public double getDefaultScaleX() {
1073         return 1;
1074     }
1075 
1076     /**
1077      * Returns default vertical scale factor of the destination surface. Scale
1078      * factor describes the mapping between virtual and physical coordinates of the
1079      * SurfaceData. If the scale is 2 then virtual pixel coordinates need to be
1080      * doubled for physical pixels.
1081      */
getDefaultScaleY()1082     public double getDefaultScaleY() {
1083         return 1;
1084     }
1085 }
1086