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