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 112 private static native void initIDs(); 113 114 private Object blitProxyKey; 115 private StateTrackableDelegate stateDelegate; 116 117 static { 118 initIDs(); 119 } 120 121 protected SurfaceData(SurfaceType surfaceType, ColorModel cm) { 122 this(State.STABLE, surfaceType, cm); 123 } 124 125 protected SurfaceData(State state, SurfaceType surfaceType, ColorModel cm) { 126 this(StateTrackableDelegate.createInstance(state), surfaceType, cm); 127 } 128 129 protected SurfaceData(StateTrackableDelegate trackable, 130 SurfaceType surfaceType, ColorModel cm) 131 { 132 this.stateDelegate = trackable; 133 this.colorModel = cm; 134 this.surfaceType = surfaceType; 135 valid = true; 136 } 137 138 protected SurfaceData(State state) { 139 this.stateDelegate = StateTrackableDelegate.createInstance(state); 140 valid = true; 141 } 142 143 /** 144 * Subclasses can set a "blit proxy key" which will be used 145 * along with the SurfaceManager.getCacheData() mechanism to 146 * store acceleration-compatible cached copies of source images. 147 * This key is a "tag" used to identify which cached copies 148 * are compatible with this destination SurfaceData. 149 * The getSourceSurfaceData() method uses this key to manage 150 * cached copies of a source image as described below. 151 * <p> 152 * The Object used as this key should be as unique as it needs 153 * to be to ensure that multiple acceleratible destinations can 154 * each store their cached copies separately under different keys 155 * without interfering with each other or getting back the wrong 156 * cached copy. 157 * <p> 158 * Many acceleratable SurfaceData objects can use their own 159 * GraphicsConfiguration as their proxy key as the GC object will 160 * typically be unique to a given screen and pixel format, but 161 * other rendering destinations may have more or less stringent 162 * sharing requirements. For instance, X11 pixmaps can be 163 * shared on a given screen by any GraphicsConfiguration that 164 * has the same depth and SurfaceType. Multiple such GCs with 165 * the same depth and SurfaceType can exist per screen so storing 166 * a different cached proxy for each would be a waste. One can 167 * imagine platforms where a single cached copy can be created 168 * and shared across all screens and pixel formats - such 169 * implementations could use a single heavily shared key Object. 170 */ 171 protected void setBlitProxyKey(Object key) { 172 // Caching is effectively disabled if we never have a proxy key 173 // since the getSourceSurfaceData() method only does caching 174 // if the key is not null. 175 if (SurfaceDataProxy.isCachingAllowed()) { 176 this.blitProxyKey = key; 177 } 178 } 179 180 /** 181 * This method is called on a destination SurfaceData to choose 182 * the best SurfaceData from a source Image for an imaging 183 * operation, with help from its SurfaceManager. 184 * The method may determine that the default SurfaceData was 185 * really the best choice in the first place, or it may decide 186 * to use a cached surface. Some general decisions about whether 187 * acceleration is enabled are made by this method, but any 188 * decision based on the type of the source image is made in 189 * the makeProxyFor method below when it comes up with the 190 * appropriate SurfaceDataProxy instance. 191 * The parameters describe the type of imaging operation being performed. 192 * <p> 193 * If a blitProxyKey was supplied by the subclass then it is 194 * used to potentially override the choice of source SurfaceData. 195 * The outline of this process is: 196 * <ol> 197 * <li> Image pipeline asks destSD to find an appropriate 198 * srcSD for a given source Image object. 199 * <li> destSD gets the SurfaceManager of the source Image 200 * and first retrieves the default SD from it using 201 * getPrimarySurfaceData() 202 * <li> destSD uses its "blit proxy key" (if set) to look for 203 * some cached data stored in the source SurfaceManager 204 * <li> If the cached data is null then makeProxyFor() is used 205 * to create some cached data which is stored back in the 206 * source SurfaceManager under the same key for future uses. 207 * <li> The cached data will be a SurfaceDataProxy object. 208 * <li> The SurfaceDataProxy object is then consulted to 209 * return a replacement SurfaceData object (typically 210 * a cached copy if appropriate, or the original if not). 211 * </ol> 212 */ 213 public SurfaceData getSourceSurfaceData(Image img, 214 int txtype, 215 CompositeType comp, 216 Color bgColor) 217 { 218 SurfaceManager srcMgr = SurfaceManager.getManager(img); 219 SurfaceData srcData = srcMgr.getPrimarySurfaceData(); 220 if (img.getAccelerationPriority() > 0.0f && 221 blitProxyKey != null) 222 { 223 SurfaceDataProxy sdp = 224 (SurfaceDataProxy) srcMgr.getCacheData(blitProxyKey); 225 if (sdp == null || !sdp.isValid()) { 226 if (srcData.getState() == State.UNTRACKABLE) { 227 sdp = SurfaceDataProxy.UNCACHED; 228 } else { 229 sdp = makeProxyFor(srcData); 230 } 231 srcMgr.setCacheData(blitProxyKey, sdp); 232 } 233 srcData = sdp.replaceData(srcData, txtype, comp, bgColor); 234 } 235 return srcData; 236 } 237 238 /** 239 * This method is called on a destination SurfaceData to choose 240 * a proper SurfaceDataProxy subclass for a source SurfaceData 241 * to use to control when and with what surface to override a 242 * given image operation. The argument is the default SurfaceData 243 * for the source Image. 244 * <p> 245 * The type of the return object is chosen based on the 246 * acceleration capabilities of this SurfaceData and the 247 * type of the given source SurfaceData object. 248 * <p> 249 * In some cases the original SurfaceData will always be the 250 * best choice to use to blit to this SurfaceData. This can 251 * happen if the source image is a hardware surface of the 252 * same type as this one and so acceleration will happen without 253 * any caching. It may also be the case that the source image 254 * can never be accelerated on this SurfaceData - for example 255 * because it is translucent and there are no accelerated 256 * translucent image ops for this surface. 257 * <p> 258 * In those cases there is a special SurfaceDataProxy.UNCACHED 259 * instance that represents a NOP for caching purposes - it 260 * always returns the original sourceSD object as the replacement 261 * copy so no caching is ever performed. 262 */ 263 public SurfaceDataProxy makeProxyFor(SurfaceData srcData) { 264 return SurfaceDataProxy.UNCACHED; 265 } 266 267 /** 268 * Extracts the SurfaceManager from the given Image, and then 269 * returns the SurfaceData object that would best be suited as the 270 * destination surface in some rendering operation. 271 */ 272 public static SurfaceData getPrimarySurfaceData(Image img) { 273 SurfaceManager sMgr = SurfaceManager.getManager(img); 274 return sMgr.getPrimarySurfaceData(); 275 } 276 277 /** 278 * Restores the contents of the given Image and then returns the new 279 * SurfaceData object in use by the Image's SurfaceManager. 280 */ 281 public static SurfaceData restoreContents(Image img) { 282 SurfaceManager sMgr = SurfaceManager.getManager(img); 283 return sMgr.restoreContents(); 284 } 285 286 public State getState() { 287 return stateDelegate.getState(); 288 } 289 290 public StateTracker getStateTracker() { 291 return stateDelegate.getStateTracker(); 292 } 293 294 /** 295 * Marks this surface as dirty. 296 */ 297 public final void markDirty() { 298 stateDelegate.markDirty(); 299 } 300 301 /** 302 * Sets the value of the surfaceLost variable, which indicates whether 303 * something has happened to the rendering surface such that it needs 304 * to be restored and re-rendered. 305 */ 306 public void setSurfaceLost(boolean lost) { 307 surfaceLost = lost; 308 stateDelegate.markDirty(); 309 } 310 311 public boolean isSurfaceLost() { 312 return surfaceLost; 313 } 314 315 /** 316 * Returns a boolean indicating whether or not this SurfaceData is valid. 317 */ 318 public final boolean isValid() { 319 return valid; 320 } 321 322 public Object getDisposerReferent() { 323 return disposerReferent; 324 } 325 326 public long getNativeOps() { 327 return pData; 328 } 329 330 /** 331 * Sets this SurfaceData object to the invalid state. All Graphics 332 * objects must get a new SurfaceData object via the refresh method 333 * and revalidate their pipelines before continuing. 334 */ 335 public void invalidate() { 336 valid = false; 337 stateDelegate.markDirty(); 338 } 339 340 /** 341 * Certain changes in the configuration of a surface require the 342 * invalidation of existing associated SurfaceData objects and 343 * the creation of brand new ones. These changes include size, 344 * ColorModel, or SurfaceType. Existing Graphics objects 345 * which are directed at such surfaces, however, must continue 346 * to render to them even after the change occurs underneath 347 * the covers. The getReplacement() method is called from 348 * SunGraphics2D.revalidateAll() when the associated SurfaceData 349 * is found to be invalid so that a Graphics object can continue 350 * to render to the surface in its new configuration. 351 * 352 * Such changes only tend to happen to window based surfaces since 353 * most image based surfaces never change size or pixel format. 354 * Even VolatileImage objects never change size and they only 355 * change their pixel format when manually validated against a 356 * new GraphicsConfiguration, at which point old Graphics objects 357 * are no longer expected to render to them after the validation 358 * step. Thus, only window based surfaces really need to deal 359 * with this form of replacement. 360 */ 361 public abstract SurfaceData getReplacement(); 362 363 protected static final LoopPipe colorPrimitives; 364 365 public static final TextPipe outlineTextRenderer; 366 public static final TextPipe solidTextRenderer; 367 public static final TextPipe aaTextRenderer; 368 public static final TextPipe lcdTextRenderer; 369 370 protected static final AlphaColorPipe colorPipe; 371 protected static final PixelToShapeConverter colorViaShape; 372 protected static final PixelToParallelogramConverter colorViaPgram; 373 protected static final TextPipe colorText; 374 protected static final CompositePipe clipColorPipe; 375 protected static final TextPipe clipColorText; 376 protected static final AAShapePipe AAColorShape; 377 protected static final PixelToParallelogramConverter AAColorViaShape; 378 protected static final PixelToParallelogramConverter AAColorViaPgram; 379 protected static final AAShapePipe AAClipColorShape; 380 protected static final PixelToParallelogramConverter AAClipColorViaShape; 381 382 protected static final CompositePipe paintPipe; 383 protected static final SpanShapeRenderer paintShape; 384 protected static final PixelToShapeConverter paintViaShape; 385 protected static final TextPipe paintText; 386 protected static final CompositePipe clipPaintPipe; 387 protected static final TextPipe clipPaintText; 388 protected static final AAShapePipe AAPaintShape; 389 protected static final PixelToParallelogramConverter AAPaintViaShape; 390 protected static final AAShapePipe AAClipPaintShape; 391 protected static final PixelToParallelogramConverter AAClipPaintViaShape; 392 393 protected static final CompositePipe compPipe; 394 protected static final SpanShapeRenderer compShape; 395 protected static final PixelToShapeConverter compViaShape; 396 protected static final TextPipe compText; 397 protected static final CompositePipe clipCompPipe; 398 protected static final TextPipe clipCompText; 399 protected static final AAShapePipe AACompShape; 400 protected static final PixelToParallelogramConverter AACompViaShape; 401 protected static final AAShapePipe AAClipCompShape; 402 protected static final PixelToParallelogramConverter AAClipCompViaShape; 403 404 protected static final DrawImagePipe imagepipe; 405 406 // Utility subclass to add the LoopBasedPipe tagging interface 407 static class PixelToShapeLoopConverter 408 extends PixelToShapeConverter 409 implements LoopBasedPipe 410 { 411 public PixelToShapeLoopConverter(ShapeDrawPipe pipe) { 412 super(pipe); 413 } 414 } 415 416 // Utility subclass to add the LoopBasedPipe tagging interface 417 static class PixelToPgramLoopConverter 418 extends PixelToParallelogramConverter 419 implements LoopBasedPipe 420 { 421 public PixelToPgramLoopConverter(ShapeDrawPipe shapepipe, 422 ParallelogramPipe pgrampipe, 423 double minPenSize, 424 double normPosition, 425 boolean adjustfill) 426 { 427 super(shapepipe, pgrampipe, minPenSize, normPosition, adjustfill); 428 } 429 } 430 431 private static PixelToParallelogramConverter 432 makeConverter(AAShapePipe renderer, 433 ParallelogramPipe pgrampipe) 434 { 435 return new PixelToParallelogramConverter(renderer, 436 pgrampipe, 437 1.0/8.0, 0.499, 438 false); 439 } 440 441 private static PixelToParallelogramConverter 442 makeConverter(AAShapePipe renderer) 443 { 444 return makeConverter(renderer, renderer); 445 } 446 447 static { 448 colorPrimitives = new LoopPipe(); 449 450 outlineTextRenderer = new OutlineTextRenderer(); 451 solidTextRenderer = new SolidTextRenderer(); 452 aaTextRenderer = new AATextRenderer(); 453 lcdTextRenderer = new LCDTextRenderer(); 454 455 colorPipe = new AlphaColorPipe(); 456 // colorShape = colorPrimitives; 457 colorViaShape = new PixelToShapeLoopConverter(colorPrimitives); 458 colorViaPgram = new PixelToPgramLoopConverter(colorPrimitives, 459 colorPrimitives, 460 1.0, 0.25, true); 461 colorText = new TextRenderer(colorPipe); 462 clipColorPipe = new SpanClipRenderer(colorPipe); 463 clipColorText = new TextRenderer(clipColorPipe); 464 AAColorShape = new AAShapePipe(colorPipe); 465 AAColorViaShape = makeConverter(AAColorShape); 466 AAColorViaPgram = makeConverter(AAColorShape, colorPipe); 467 AAClipColorShape = new AAShapePipe(clipColorPipe); 468 AAClipColorViaShape = makeConverter(AAClipColorShape); 469 470 paintPipe = new AlphaPaintPipe(); 471 paintShape = new SpanShapeRenderer.Composite(paintPipe); 472 paintViaShape = new PixelToShapeConverter(paintShape); 473 paintText = new TextRenderer(paintPipe); 474 clipPaintPipe = new SpanClipRenderer(paintPipe); 475 clipPaintText = new TextRenderer(clipPaintPipe); 476 AAPaintShape = new AAShapePipe(paintPipe); 477 AAPaintViaShape = makeConverter(AAPaintShape); 478 AAClipPaintShape = new AAShapePipe(clipPaintPipe); 479 AAClipPaintViaShape = makeConverter(AAClipPaintShape); 480 481 compPipe = new GeneralCompositePipe(); 482 compShape = new SpanShapeRenderer.Composite(compPipe); 483 compViaShape = new PixelToShapeConverter(compShape); 484 compText = new TextRenderer(compPipe); 485 clipCompPipe = new SpanClipRenderer(compPipe); 486 clipCompText = new TextRenderer(clipCompPipe); 487 AACompShape = new AAShapePipe(compPipe); 488 AACompViaShape = makeConverter(AACompShape); 489 AAClipCompShape = new AAShapePipe(clipCompPipe); 490 AAClipCompViaShape = makeConverter(AAClipCompShape); 491 492 imagepipe = new DrawImage(); 493 } 494 495 /* Not all surfaces and rendering mode combinations support LCD text. */ 496 static final int LOOP_UNKNOWN = 0; 497 static final int LOOP_FOUND = 1; 498 static final int LOOP_NOTFOUND = 2; 499 int haveLCDLoop; 500 int havePgramXORLoop; 501 int havePgramSolidLoop; 502 503 public boolean canRenderLCDText(SunGraphics2D sg2d) { 504 // For now the answer can only be true in the following cases: 505 if (sg2d.compositeState <= SunGraphics2D.COMP_ISCOPY && 506 sg2d.paintState <= SunGraphics2D.PAINT_ALPHACOLOR && 507 sg2d.clipState <= SunGraphics2D.CLIP_RECTANGULAR && 508 sg2d.surfaceData.getTransparency() == Transparency.OPAQUE) 509 { 510 if (haveLCDLoop == LOOP_UNKNOWN) { 511 DrawGlyphListLCD loop = 512 DrawGlyphListLCD.locate(SurfaceType.AnyColor, 513 CompositeType.SrcNoEa, 514 getSurfaceType()); 515 haveLCDLoop = (loop != null) ? LOOP_FOUND : LOOP_NOTFOUND; 516 } 517 return haveLCDLoop == LOOP_FOUND; 518 } 519 return false; /* for now - in the future we may want to search */ 520 } 521 522 public boolean canRenderParallelograms(SunGraphics2D sg2d) { 523 if (sg2d.paintState <= 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 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 */ 735 private TextPipe getTextPipe(SunGraphics2D sg2d, boolean aaHintIsOn) { 736 737 /* Try to avoid calling getFontInfo() unless its needed to 738 * resolve one of the new AA types. 739 */ 740 switch (sg2d.textAntialiasHint) { 741 case SunHints.INTVAL_TEXT_ANTIALIAS_DEFAULT: 742 if (aaHintIsOn) { 743 return aaTextRenderer; 744 } else { 745 return solidTextRenderer; 746 } 747 case SunHints.INTVAL_TEXT_ANTIALIAS_OFF: 748 return solidTextRenderer; 749 750 case SunHints.INTVAL_TEXT_ANTIALIAS_ON: 751 return aaTextRenderer; 752 753 default: 754 switch (sg2d.getFontInfo().aaHint) { 755 756 case SunHints.INTVAL_TEXT_ANTIALIAS_LCD_HRGB: 757 case SunHints.INTVAL_TEXT_ANTIALIAS_LCD_VRGB: 758 return lcdTextRenderer; 759 760 case SunHints.INTVAL_TEXT_ANTIALIAS_ON: 761 return aaTextRenderer; 762 763 case SunHints.INTVAL_TEXT_ANTIALIAS_OFF: 764 return solidTextRenderer; 765 766 /* This should not be reached as the FontInfo will 767 * always explicitly set its hint value. So whilst 768 * this could be collapsed to returning say just 769 * solidTextRenderer, or even removed, its left 770 * here in case DEFAULT is ever passed in. 771 */ 772 default: 773 if (aaHintIsOn) { 774 return aaTextRenderer; 775 } else { 776 return solidTextRenderer; 777 } 778 } 779 } 780 } 781 782 private static SurfaceType getPaintSurfaceType(SunGraphics2D sg2d) { 783 switch (sg2d.paintState) { 784 case SunGraphics2D.PAINT_OPAQUECOLOR: 785 return SurfaceType.OpaqueColor; 786 case SunGraphics2D.PAINT_ALPHACOLOR: 787 return SurfaceType.AnyColor; 788 case SunGraphics2D.PAINT_GRADIENT: 789 if (sg2d.paint.getTransparency() == OPAQUE) { 790 return SurfaceType.OpaqueGradientPaint; 791 } else { 792 return SurfaceType.GradientPaint; 793 } 794 case SunGraphics2D.PAINT_LIN_GRADIENT: 795 if (sg2d.paint.getTransparency() == OPAQUE) { 796 return SurfaceType.OpaqueLinearGradientPaint; 797 } else { 798 return SurfaceType.LinearGradientPaint; 799 } 800 case SunGraphics2D.PAINT_RAD_GRADIENT: 801 if (sg2d.paint.getTransparency() == OPAQUE) { 802 return SurfaceType.OpaqueRadialGradientPaint; 803 } else { 804 return SurfaceType.RadialGradientPaint; 805 } 806 case SunGraphics2D.PAINT_TEXTURE: 807 if (sg2d.paint.getTransparency() == OPAQUE) { 808 return SurfaceType.OpaqueTexturePaint; 809 } else { 810 return SurfaceType.TexturePaint; 811 } 812 default: 813 case SunGraphics2D.PAINT_CUSTOM: 814 return SurfaceType.AnyPaint; 815 } 816 } 817 818 private static CompositeType getFillCompositeType(SunGraphics2D sg2d) { 819 CompositeType compType = sg2d.imageComp; 820 if (sg2d.compositeState == 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 */ 838 protected MaskFill getMaskFill(SunGraphics2D sg2d) { 839 SurfaceType src = getPaintSurfaceType(sg2d); 840 CompositeType comp = getFillCompositeType(sg2d); 841 SurfaceType dst = getSurfaceType(); 842 return MaskFill.getFromCache(src, comp, dst); 843 } 844 845 private static RenderCache loopcache = new RenderCache(30); 846 847 /** 848 * Return a RenderLoops object containing all of the basic 849 * GraphicsPrimitive objects for rendering to the destination 850 * surface with the current attributes of the given SunGraphics2D. 851 */ 852 public RenderLoops getRenderLoops(SunGraphics2D sg2d) { 853 SurfaceType src = getPaintSurfaceType(sg2d); 854 CompositeType comp = getFillCompositeType(sg2d); 855 SurfaceType dst = sg2d.getSurfaceData().getSurfaceType(); 856 857 Object o = loopcache.get(src, comp, dst); 858 if (o != null) { 859 return (RenderLoops) o; 860 } 861 862 RenderLoops loops = makeRenderLoops(src, comp, dst); 863 loopcache.put(src, comp, dst, loops); 864 return loops; 865 } 866 867 /** 868 * Construct and return a RenderLoops object containing all of 869 * the basic GraphicsPrimitive objects for rendering to the 870 * destination surface with the given source, destination, and 871 * composite types. 872 */ 873 public static RenderLoops makeRenderLoops(SurfaceType src, 874 CompositeType comp, 875 SurfaceType dst) 876 { 877 RenderLoops loops = new RenderLoops(); 878 loops.drawLineLoop = DrawLine.locate(src, comp, dst); 879 loops.fillRectLoop = FillRect.locate(src, comp, dst); 880 loops.drawRectLoop = DrawRect.locate(src, comp, dst); 881 loops.drawPolygonsLoop = DrawPolygons.locate(src, comp, dst); 882 loops.drawPathLoop = DrawPath.locate(src, comp, dst); 883 loops.fillPathLoop = FillPath.locate(src, comp, dst); 884 loops.fillSpansLoop = FillSpans.locate(src, comp, dst); 885 loops.fillParallelogramLoop = FillParallelogram.locate(src, comp, dst); 886 loops.drawParallelogramLoop = DrawParallelogram.locate(src, comp, dst); 887 loops.drawGlyphListLoop = DrawGlyphList.locate(src, comp, dst); 888 loops.drawGlyphListAALoop = DrawGlyphListAA.locate(src, comp, dst); 889 loops.drawGlyphListLCDLoop = DrawGlyphListLCD.locate(src, comp, dst); 890 /* 891 System.out.println("drawLine: "+loops.drawLineLoop); 892 System.out.println("fillRect: "+loops.fillRectLoop); 893 System.out.println("drawRect: "+loops.drawRectLoop); 894 System.out.println("drawPolygons: "+loops.drawPolygonsLoop); 895 System.out.println("fillSpans: "+loops.fillSpansLoop); 896 System.out.println("drawGlyphList: "+loops.drawGlyphListLoop); 897 System.out.println("drawGlyphListAA: "+loops.drawGlyphListAALoop); 898 System.out.println("drawGlyphListLCD: "+loops.drawGlyphListLCDLoop); 899 */ 900 return loops; 901 } 902 903 /** 904 * Return the GraphicsConfiguration object that describes this 905 * destination surface. 906 */ 907 public abstract GraphicsConfiguration getDeviceConfiguration(); 908 909 /** 910 * Return the SurfaceType object that describes the destination 911 * surface. 912 */ 913 public final SurfaceType getSurfaceType() { 914 return surfaceType; 915 } 916 917 /** 918 * Return the ColorModel for the destination surface. 919 */ 920 public final ColorModel getColorModel() { 921 return colorModel; 922 } 923 924 /** 925 * Returns the type of this <code>Transparency</code>. 926 * @return the field type of this <code>Transparency</code>, which is 927 * either OPAQUE, BITMASK or TRANSLUCENT. 928 */ 929 public int getTransparency() { 930 return getColorModel().getTransparency(); 931 } 932 933 /** 934 * Return a readable Raster which contains the pixels for the 935 * specified rectangular region of the destination surface. 936 * The coordinate origin of the returned Raster is the same as 937 * the device space origin of the destination surface. 938 * In some cases the returned Raster might also be writeable. 939 * In most cases, the returned Raster might contain more pixels 940 * than requested. 941 * 942 * @see #useTightBBoxes 943 */ 944 public abstract Raster getRaster(int x, int y, int w, int h); 945 946 /** 947 * Does the pixel accessibility of the destination surface 948 * suggest that rendering algorithms might want to take 949 * extra time to calculate a more accurate bounding box for 950 * the operation being performed? 951 * The typical case when this will be true is when a copy of 952 * the pixels has to be made when doing a getRaster. The 953 * fewer pixels copied, the faster the operation will go. 954 * 955 * @see #getRaster 956 */ 957 public boolean useTightBBoxes() { 958 // Note: The native equivalent would trigger on VISIBLE_TO_NATIVE 959 // REMIND: This is not used - should be obsoleted maybe 960 return true; 961 } 962 963 /** 964 * Returns the pixel data for the specified Argb value packed 965 * into an integer for easy storage and conveyance. 966 */ 967 public int pixelFor(int rgb) { 968 return surfaceType.pixelFor(rgb, colorModel); 969 } 970 971 /** 972 * Returns the pixel data for the specified color packed into an 973 * integer for easy storage and conveyance. 974 * 975 * This method will use the getRGB() method of the Color object 976 * and defer to the pixelFor(int rgb) method if not overridden. 977 * 978 * For now this is a convenience function, but for cases where 979 * the highest quality color conversion is requested, this method 980 * should be overridden in those cases so that a more direct 981 * conversion of the color to the destination color space 982 * can be done using the additional information in the Color 983 * object. 984 */ 985 public int pixelFor(Color c) { 986 return pixelFor(c.getRGB()); 987 } 988 989 /** 990 * Returns the Argb representation for the specified integer value 991 * which is packed in the format of the associated ColorModel. 992 */ 993 public int rgbFor(int pixel) { 994 return surfaceType.rgbFor(pixel, colorModel); 995 } 996 997 /** 998 * Returns the bounds of the destination surface. 999 */ 1000 public abstract Rectangle getBounds(); 1001 1002 static java.security.Permission compPermission; 1003 1004 /** 1005 * Performs Security Permissions checks to see if a Custom 1006 * Composite object should be allowed access to the pixels 1007 * of this surface. 1008 */ 1009 protected void checkCustomComposite() { 1010 SecurityManager sm = System.getSecurityManager(); 1011 if (sm != null) { 1012 if (compPermission == null) { 1013 compPermission = 1014 new java.awt.AWTPermission("readDisplayPixels"); 1015 } 1016 sm.checkPermission(compPermission); 1017 } 1018 } 1019 1020 /** 1021 * Fetches private field IndexColorModel.allgrayopaque 1022 * which is true when all palette entries in the color 1023 * model are gray and opaque. 1024 */ 1025 protected static native boolean isOpaqueGray(IndexColorModel icm); 1026 1027 /** 1028 * For our purposes null and NullSurfaceData are the same as 1029 * they represent a disposed surface. 1030 */ 1031 public static boolean isNull(SurfaceData sd) { 1032 if (sd == null || sd == NullSurfaceData.theInstance) { 1033 return true; 1034 } 1035 return false; 1036 } 1037 1038 /** 1039 * Performs a copyarea within this surface. Returns 1040 * false if there is no algorithm to perform the copyarea 1041 * given the current settings of the SunGraphics2D. 1042 */ 1043 public boolean copyArea(SunGraphics2D sg2d, 1044 int x, int y, int w, int h, int dx, int dy) 1045 { 1046 return false; 1047 } 1048 1049 /** 1050 * Synchronously releases resources associated with this surface. 1051 */ 1052 public void flush() {} 1053 1054 /** 1055 * Returns destination associated with this SurfaceData. This could be 1056 * either an Image or a Component; subclasses of SurfaceData are 1057 * responsible for returning the appropriate object. 1058 */ 1059 public abstract Object getDestination(); 1060 1061 /** 1062 * Returns default scale factor of the destination surface. Scale factor 1063 * describes the mapping between virtual and physical coordinates of the 1064 * SurfaceData. If the scale is 2 then virtual pixel coordinates need to be 1065 * doubled for physical pixels. 1066 */ 1067 public int getDefaultScale() { 1068 return 1; 1069 } 1070 }