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