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