1 /* 2 * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 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 initIDs()112 private static native void initIDs(); 113 114 private Object blitProxyKey; 115 private StateTrackableDelegate stateDelegate; 116 117 static { initIDs()118 initIDs(); 119 } 120 SurfaceData(SurfaceType surfaceType, ColorModel cm)121 protected SurfaceData(SurfaceType surfaceType, ColorModel cm) { 122 this(State.STABLE, surfaceType, cm); 123 } 124 SurfaceData(State state, SurfaceType surfaceType, ColorModel cm)125 protected SurfaceData(State state, SurfaceType surfaceType, ColorModel cm) { 126 this(StateTrackableDelegate.createInstance(state), surfaceType, cm); 127 } 128 SurfaceData(StateTrackableDelegate trackable, SurfaceType surfaceType, ColorModel cm)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 SurfaceData(State state)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 */ setBlitProxyKey(Object key)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 */ getSourceSurfaceData(Image img, int txtype, CompositeType comp, Color bgColor)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 */ makeProxyFor(SurfaceData srcData)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 */ getPrimarySurfaceData(Image img)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 */ restoreContents(Image img)281 public static SurfaceData restoreContents(Image img) { 282 SurfaceManager sMgr = SurfaceManager.getManager(img); 283 return sMgr.restoreContents(); 284 } 285 getState()286 public State getState() { 287 return stateDelegate.getState(); 288 } 289 getStateTracker()290 public StateTracker getStateTracker() { 291 return stateDelegate.getStateTracker(); 292 } 293 294 /** 295 * Marks this surface as dirty. 296 */ markDirty()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 */ setSurfaceLost(boolean lost)306 public void setSurfaceLost(boolean lost) { 307 surfaceLost = lost; 308 stateDelegate.markDirty(); 309 } 310 isSurfaceLost()311 public boolean isSurfaceLost() { 312 return surfaceLost; 313 } 314 315 /** 316 * Returns a boolean indicating whether or not this SurfaceData is valid. 317 */ isValid()318 public final boolean isValid() { 319 return valid; 320 } 321 getDisposerReferent()322 public Object getDisposerReferent() { 323 return disposerReferent; 324 } 325 getNativeOps()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 */ invalidate()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 */ getReplacement()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 { PixelToShapeLoopConverter(ShapeDrawPipe pipe)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 { PixelToPgramLoopConverter(ShapeDrawPipe shapepipe, ParallelogramPipe pgrampipe, double minPenSize, double normPosition, boolean adjustfill)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 makeConverter(AAShapePipe renderer, ParallelogramPipe pgrampipe)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 makeConverter(AAShapePipe renderer)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 canRenderLCDText(SunGraphics2D sg2d)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 canRenderParallelograms(SunGraphics2D sg2d)522 public boolean canRenderParallelograms(SunGraphics2D sg2d) { 523 if (sg2d.paintState <= SunGraphics2D.PAINT_ALPHACOLOR) { 524 if (sg2d.compositeState == SunGraphics2D.COMP_XOR) { 525 if (havePgramXORLoop == LOOP_UNKNOWN) { 526 FillParallelogram loop = 527 FillParallelogram.locate(SurfaceType.AnyColor, 528 CompositeType.Xor, 529 getSurfaceType()); 530 havePgramXORLoop = 531 (loop != null) ? LOOP_FOUND : LOOP_NOTFOUND; 532 } 533 return havePgramXORLoop == LOOP_FOUND; 534 } else if (sg2d.compositeState <= SunGraphics2D.COMP_ISCOPY && 535 sg2d.antialiasHint != SunHints.INTVAL_ANTIALIAS_ON && 536 sg2d.clipState != SunGraphics2D.CLIP_SHAPE) 537 { 538 if (havePgramSolidLoop == LOOP_UNKNOWN) { 539 FillParallelogram loop = 540 FillParallelogram.locate(SurfaceType.AnyColor, 541 CompositeType.SrcNoEa, 542 getSurfaceType()); 543 havePgramSolidLoop = 544 (loop != null) ? LOOP_FOUND : LOOP_NOTFOUND; 545 } 546 return havePgramSolidLoop == LOOP_FOUND; 547 } 548 } 549 return false; 550 } 551 validatePipe(SunGraphics2D sg2d)552 public void validatePipe(SunGraphics2D sg2d) { 553 sg2d.imagepipe = imagepipe; 554 if (sg2d.compositeState == SunGraphics2D.COMP_XOR) { 555 if (sg2d.paintState > SunGraphics2D.PAINT_ALPHACOLOR) { 556 sg2d.drawpipe = paintViaShape; 557 sg2d.fillpipe = paintViaShape; 558 sg2d.shapepipe = paintShape; 559 // REMIND: Ideally custom paint mode would use glyph 560 // rendering as opposed to outline rendering but the 561 // glyph paint rendering pipeline uses MaskBlit which 562 // is not defined for XOR. This means that text drawn 563 // in XOR mode with a Color object is different than 564 // text drawn in XOR mode with a Paint object. 565 sg2d.textpipe = outlineTextRenderer; 566 } else { 567 PixelToShapeConverter converter; 568 if (canRenderParallelograms(sg2d)) { 569 converter = colorViaPgram; 570 // Note that we use the transforming pipe here because it 571 // will examine the shape and possibly perform an optimized 572 // operation if it can be simplified. The simplifications 573 // will be valid for all STROKE and TRANSFORM types. 574 sg2d.shapepipe = colorViaPgram; 575 } else { 576 converter = colorViaShape; 577 sg2d.shapepipe = colorPrimitives; 578 } 579 if (sg2d.clipState == SunGraphics2D.CLIP_SHAPE) { 580 sg2d.drawpipe = converter; 581 sg2d.fillpipe = converter; 582 // REMIND: We should not be changing text strategies 583 // between outline and glyph rendering based upon the 584 // presence of a complex clip as that could cause a 585 // mismatch when drawing the same text both clipped 586 // and unclipped on two separate rendering passes. 587 // Unfortunately, all of the clipped glyph rendering 588 // pipelines rely on the use of the MaskBlit operation 589 // which is not defined for XOR. 590 sg2d.textpipe = outlineTextRenderer; 591 } else { 592 if (sg2d.transformState >= SunGraphics2D.TRANSFORM_TRANSLATESCALE) { 593 sg2d.drawpipe = converter; 594 sg2d.fillpipe = converter; 595 } else { 596 if (sg2d.strokeState != SunGraphics2D.STROKE_THIN) { 597 sg2d.drawpipe = converter; 598 } else { 599 sg2d.drawpipe = colorPrimitives; 600 } 601 sg2d.fillpipe = colorPrimitives; 602 } 603 sg2d.textpipe = solidTextRenderer; 604 } 605 // assert(sg2d.surfaceData == this); 606 } 607 } else if (sg2d.compositeState == SunGraphics2D.COMP_CUSTOM) { 608 if (sg2d.antialiasHint == SunHints.INTVAL_ANTIALIAS_ON) { 609 if (sg2d.clipState == SunGraphics2D.CLIP_SHAPE) { 610 sg2d.drawpipe = AAClipCompViaShape; 611 sg2d.fillpipe = AAClipCompViaShape; 612 sg2d.shapepipe = AAClipCompViaShape; 613 sg2d.textpipe = clipCompText; 614 } else { 615 sg2d.drawpipe = AACompViaShape; 616 sg2d.fillpipe = AACompViaShape; 617 sg2d.shapepipe = AACompViaShape; 618 sg2d.textpipe = compText; 619 } 620 } else { 621 sg2d.drawpipe = compViaShape; 622 sg2d.fillpipe = compViaShape; 623 sg2d.shapepipe = compShape; 624 if (sg2d.clipState == SunGraphics2D.CLIP_SHAPE) { 625 sg2d.textpipe = clipCompText; 626 } else { 627 sg2d.textpipe = compText; 628 } 629 } 630 } else if (sg2d.antialiasHint == SunHints.INTVAL_ANTIALIAS_ON) { 631 sg2d.alphafill = getMaskFill(sg2d); 632 // assert(sg2d.surfaceData == this); 633 if (sg2d.alphafill != null) { 634 if (sg2d.clipState == SunGraphics2D.CLIP_SHAPE) { 635 sg2d.drawpipe = AAClipColorViaShape; 636 sg2d.fillpipe = AAClipColorViaShape; 637 sg2d.shapepipe = AAClipColorViaShape; 638 sg2d.textpipe = clipColorText; 639 } else { 640 PixelToParallelogramConverter converter = 641 (sg2d.alphafill.canDoParallelograms() 642 ? AAColorViaPgram 643 : AAColorViaShape); 644 sg2d.drawpipe = converter; 645 sg2d.fillpipe = converter; 646 sg2d.shapepipe = converter; 647 if (sg2d.paintState > SunGraphics2D.PAINT_ALPHACOLOR || 648 sg2d.compositeState > SunGraphics2D.COMP_ISCOPY) 649 { 650 sg2d.textpipe = colorText; 651 } else { 652 sg2d.textpipe = getTextPipe(sg2d, true /* AA==ON */); 653 } 654 } 655 } else { 656 if (sg2d.clipState == SunGraphics2D.CLIP_SHAPE) { 657 sg2d.drawpipe = AAClipPaintViaShape; 658 sg2d.fillpipe = AAClipPaintViaShape; 659 sg2d.shapepipe = AAClipPaintViaShape; 660 sg2d.textpipe = clipPaintText; 661 } else { 662 sg2d.drawpipe = AAPaintViaShape; 663 sg2d.fillpipe = AAPaintViaShape; 664 sg2d.shapepipe = AAPaintViaShape; 665 sg2d.textpipe = paintText; 666 } 667 } 668 } else if (sg2d.paintState > SunGraphics2D.PAINT_ALPHACOLOR || 669 sg2d.compositeState > SunGraphics2D.COMP_ISCOPY || 670 sg2d.clipState == SunGraphics2D.CLIP_SHAPE) 671 { 672 sg2d.drawpipe = paintViaShape; 673 sg2d.fillpipe = paintViaShape; 674 sg2d.shapepipe = paintShape; 675 sg2d.alphafill = getMaskFill(sg2d); 676 // assert(sg2d.surfaceData == this); 677 if (sg2d.alphafill != null) { 678 if (sg2d.clipState == SunGraphics2D.CLIP_SHAPE) { 679 sg2d.textpipe = clipColorText; 680 } else { 681 sg2d.textpipe = colorText; 682 } 683 } else { 684 if (sg2d.clipState == SunGraphics2D.CLIP_SHAPE) { 685 sg2d.textpipe = clipPaintText; 686 } else { 687 sg2d.textpipe = paintText; 688 } 689 } 690 } else { 691 PixelToShapeConverter converter; 692 if (canRenderParallelograms(sg2d)) { 693 converter = colorViaPgram; 694 // Note that we use the transforming pipe here because it 695 // will examine the shape and possibly perform an optimized 696 // operation if it can be simplified. The simplifications 697 // will be valid for all STROKE and TRANSFORM types. 698 sg2d.shapepipe = colorViaPgram; 699 } else { 700 converter = colorViaShape; 701 sg2d.shapepipe = colorPrimitives; 702 } 703 if (sg2d.transformState >= SunGraphics2D.TRANSFORM_TRANSLATESCALE) { 704 sg2d.drawpipe = converter; 705 sg2d.fillpipe = converter; 706 } else { 707 if (sg2d.strokeState != SunGraphics2D.STROKE_THIN) { 708 sg2d.drawpipe = converter; 709 } else { 710 sg2d.drawpipe = colorPrimitives; 711 } 712 sg2d.fillpipe = colorPrimitives; 713 } 714 715 sg2d.textpipe = getTextPipe(sg2d, false /* AA==OFF */); 716 // assert(sg2d.surfaceData == this); 717 } 718 719 // check for loops 720 if (sg2d.textpipe instanceof LoopBasedPipe || 721 sg2d.shapepipe instanceof LoopBasedPipe || 722 sg2d.fillpipe instanceof LoopBasedPipe || 723 sg2d.drawpipe instanceof LoopBasedPipe || 724 sg2d.imagepipe instanceof LoopBasedPipe) 725 { 726 sg2d.loops = getRenderLoops(sg2d); 727 } 728 } 729 730 /* Return the text pipe to be used based on the graphics AA hint setting, 731 * and the rest of the graphics state is compatible with these loops. 732 * If the text AA hint is "DEFAULT", then the AA graphics hint requests 733 * the AA text renderer, else it requests the B&W text renderer. 734 */ getTextPipe(SunGraphics2D sg2d, boolean aaHintIsOn)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 getPaintSurfaceType(SunGraphics2D sg2d)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 getFillCompositeType(SunGraphics2D sg2d)818 private static CompositeType getFillCompositeType(SunGraphics2D sg2d) { 819 CompositeType compType = sg2d.imageComp; 820 if (sg2d.compositeState == SunGraphics2D.COMP_ISCOPY) { 821 if (compType == CompositeType.SrcOverNoEa) { 822 compType = CompositeType.OpaqueSrcOverNoEa; 823 } else { 824 compType = CompositeType.SrcNoEa; 825 } 826 } 827 return compType; 828 } 829 830 /** 831 * Returns a MaskFill object that can be used on this destination 832 * with the source (paint) and composite types determined by the given 833 * SunGraphics2D, or null if no such MaskFill object can be located. 834 * Subclasses can override this method if they wish to filter other 835 * attributes (such as the hardware capabilities of the destination 836 * surface) before returning a specific MaskFill object. 837 */ getMaskFill(SunGraphics2D sg2d)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 */ getRenderLoops(SunGraphics2D sg2d)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 */ makeRenderLoops(SurfaceType src, CompositeType comp, SurfaceType dst)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 */ getDeviceConfiguration()907 public abstract GraphicsConfiguration getDeviceConfiguration(); 908 909 /** 910 * Return the SurfaceType object that describes the destination 911 * surface. 912 */ getSurfaceType()913 public final SurfaceType getSurfaceType() { 914 return surfaceType; 915 } 916 917 /** 918 * Return the ColorModel for the destination surface. 919 */ getColorModel()920 public final ColorModel getColorModel() { 921 return colorModel; 922 } 923 924 /** 925 * Returns the type of this {@code Transparency}. 926 * @return the field type of this {@code Transparency}, which is 927 * either OPAQUE, BITMASK or TRANSLUCENT. 928 */ getTransparency()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 */ getRaster(int x, int y, int w, int h)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 */ useTightBBoxes()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 */ pixelFor(int rgb)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 */ pixelFor(Color c)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 */ rgbFor(int pixel)993 public int rgbFor(int pixel) { 994 return surfaceType.rgbFor(pixel, colorModel); 995 } 996 997 /** 998 * Returns the bounds of the destination surface. 999 */ getBounds()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 */ checkCustomComposite()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 */ isOpaqueGray(IndexColorModel icm)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 */ isNull(SurfaceData sd)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 * @param x the x coordinate of the area in device space 1044 * @param y the y coordinate of the area in device space 1045 * @param w the width of the area in device space 1046 * @param h the height of the area in device space 1047 */ copyArea(SunGraphics2D sg2d, int x, int y, int w, int h, int dx, int dy)1048 public boolean copyArea(SunGraphics2D sg2d, 1049 int x, int y, int w, int h, int dx, int dy) 1050 { 1051 return false; 1052 } 1053 1054 /** 1055 * Synchronously releases resources associated with this surface. 1056 */ flush()1057 public void flush() {} 1058 1059 /** 1060 * Returns destination associated with this SurfaceData. This could be 1061 * either an Image or a Component; subclasses of SurfaceData are 1062 * responsible for returning the appropriate object. 1063 */ getDestination()1064 public abstract Object getDestination(); 1065 1066 /** 1067 * Returns default horizontal scale factor of the destination surface. Scale 1068 * factor describes the mapping between virtual and physical coordinates of the 1069 * SurfaceData. If the scale is 2 then virtual pixel coordinates need to be 1070 * doubled for physical pixels. 1071 */ getDefaultScaleX()1072 public double getDefaultScaleX() { 1073 return 1; 1074 } 1075 1076 /** 1077 * Returns default vertical scale factor of the destination surface. Scale 1078 * factor describes the mapping between virtual and physical coordinates of the 1079 * SurfaceData. If the scale is 2 then virtual pixel coordinates need to be 1080 * doubled for physical pixels. 1081 */ getDefaultScaleY()1082 public double getDefaultScaleY() { 1083 return 1; 1084 } 1085 } 1086