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