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