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 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 <= sg2d.PAINT_ALPHACOLOR) {
 524             if (sg2d.compositeState == sg2d.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 <= sg2d.COMP_ISCOPY &&
 535                        sg2d.antialiasHint != SunHints.INTVAL_ANTIALIAS_ON &&
 536                        sg2d.clipState != sg2d.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 == sg2d.COMP_XOR) {
 555             if (sg2d.paintState > sg2d.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 == sg2d.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 >= sg2d.TRANSFORM_TRANSLATESCALE) {
 593                         sg2d.drawpipe = converter;
 594                         sg2d.fillpipe = converter;
 595                     } else {
 596                         if (sg2d.strokeState != sg2d.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 == sg2d.COMP_CUSTOM) {
 608             if (sg2d.antialiasHint == SunHints.INTVAL_ANTIALIAS_ON) {
 609                 if (sg2d.clipState == sg2d.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 == sg2d.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 == sg2d.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 > sg2d.PAINT_ALPHACOLOR ||
 648                         sg2d.compositeState > sg2d.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 == sg2d.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 > sg2d.PAINT_ALPHACOLOR ||
 669                    sg2d.compositeState > sg2d.COMP_ISCOPY ||
 670                    sg2d.clipState == sg2d.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 == sg2d.CLIP_SHAPE) {
 679                     sg2d.textpipe = clipColorText;
 680                 } else {
 681                     sg2d.textpipe = colorText;
 682                 }
 683             } else {
 684                 if (sg2d.clipState == sg2d.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 >= sg2d.TRANSFORM_TRANSLATESCALE) {
 704                 sg2d.drawpipe = converter;
 705                 sg2d.fillpipe = converter;
 706             } else {
 707                 if (sg2d.strokeState != sg2d.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 == sg2d.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 }