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