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