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.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 CompositePipe 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 PixelToShapeConverter AAColorViaShape; 378 protected static final AAShapePipe AAClipColorShape; 379 protected static final PixelToShapeConverter 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 PixelToShapeConverter AAPaintViaShape; 389 protected static final AAShapePipe AAClipPaintShape; 390 protected static final PixelToShapeConverter 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 PixelToShapeConverter AACompViaShape; 400 protected static final AAShapePipe AAClipCompShape; 401 protected static final PixelToShapeConverter 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 static { 431 colorPrimitives = new LoopPipe(); 432 433 outlineTextRenderer = new OutlineTextRenderer(); 434 solidTextRenderer = new SolidTextRenderer(); 435 aaTextRenderer = new AATextRenderer(); 436 lcdTextRenderer = new LCDTextRenderer(); 437 438 colorPipe = new AlphaColorPipe(); 439 // colorShape = colorPrimitives; 440 colorViaShape = new PixelToShapeLoopConverter(colorPrimitives); 441 colorViaPgram = new PixelToPgramLoopConverter(colorPrimitives, 442 colorPrimitives, 443 1.0, 0.25, true); 444 colorText = new TextRenderer(colorPipe); 445 clipColorPipe = new SpanClipRenderer(colorPipe); 446 clipColorText = new TextRenderer(clipColorPipe); 447 AAColorShape = new AAShapePipe(colorPipe); 448 AAColorViaShape = new PixelToShapeConverter(AAColorShape); 449 AAClipColorShape = new AAShapePipe(clipColorPipe); 450 AAClipColorViaShape = new PixelToShapeConverter(AAClipColorShape); 451 452 paintPipe = new AlphaPaintPipe(); 453 paintShape = new SpanShapeRenderer.Composite(paintPipe); 454 paintViaShape = new PixelToShapeConverter(paintShape); 455 paintText = new TextRenderer(paintPipe); 456 clipPaintPipe = new SpanClipRenderer(paintPipe); 457 clipPaintText = new TextRenderer(clipPaintPipe); 458 AAPaintShape = new AAShapePipe(paintPipe); 459 AAPaintViaShape = new PixelToShapeConverter(AAPaintShape); 460 AAClipPaintShape = new AAShapePipe(clipPaintPipe); 461 AAClipPaintViaShape = new PixelToShapeConverter(AAClipPaintShape); 462 463 compPipe = new GeneralCompositePipe(); 464 compShape = new SpanShapeRenderer.Composite(compPipe); 465 compViaShape = new PixelToShapeConverter(compShape); 466 compText = new TextRenderer(compPipe); 467 clipCompPipe = new SpanClipRenderer(compPipe); 468 clipCompText = new TextRenderer(clipCompPipe); 469 AACompShape = new AAShapePipe(compPipe); 470 AACompViaShape = new PixelToShapeConverter(AACompShape); 471 AAClipCompShape = new AAShapePipe(clipCompPipe); 472 AAClipCompViaShape = new PixelToShapeConverter(AAClipCompShape); 473 474 imagepipe = new DrawImage(); 475 } 476 477 /* Not all surfaces and rendering mode combinations support LCD text. */ 478 static final int LOOP_UNKNOWN = 0; 479 static final int LOOP_FOUND = 1; 480 static final int LOOP_NOTFOUND = 2; 481 int haveLCDLoop; 482 int havePgramXORLoop; 483 int havePgramSolidLoop; 484 485 public boolean canRenderLCDText(SunGraphics2D sg2d) { 486 // For now the answer can only be true in the following cases: 487 if (sg2d.compositeState <= SunGraphics2D.COMP_ISCOPY && 488 sg2d.paintState <= SunGraphics2D.PAINT_ALPHACOLOR && 489 sg2d.clipState <= SunGraphics2D.CLIP_RECTANGULAR && 490 sg2d.surfaceData.getTransparency() == Transparency.OPAQUE) 491 { 492 if (haveLCDLoop == LOOP_UNKNOWN) { 493 DrawGlyphListLCD loop = 494 DrawGlyphListLCD.locate(SurfaceType.AnyColor, 495 CompositeType.SrcNoEa, 496 getSurfaceType()); 497 haveLCDLoop = (loop != null) ? LOOP_FOUND : LOOP_NOTFOUND; 498 } 499 return haveLCDLoop == LOOP_FOUND; 500 } 501 return false; /* for now - in the future we may want to search */ 502 } 503 504 public boolean canRenderParallelograms(SunGraphics2D sg2d) { 505 if (sg2d.paintState <= sg2d.PAINT_ALPHACOLOR) { 506 if (sg2d.compositeState == sg2d.COMP_XOR) { 507 if (havePgramXORLoop == LOOP_UNKNOWN) { 508 FillParallelogram loop = 509 FillParallelogram.locate(SurfaceType.AnyColor, 510 CompositeType.Xor, 511 getSurfaceType()); 512 havePgramXORLoop = 513 (loop != null) ? LOOP_FOUND : LOOP_NOTFOUND; 514 } 515 return havePgramXORLoop == LOOP_FOUND; 516 } else if (sg2d.compositeState <= sg2d.COMP_ISCOPY && 517 sg2d.antialiasHint != SunHints.INTVAL_ANTIALIAS_ON && 518 sg2d.clipState != sg2d.CLIP_SHAPE) 519 { 520 if (havePgramSolidLoop == LOOP_UNKNOWN) { 521 FillParallelogram loop = 522 FillParallelogram.locate(SurfaceType.AnyColor, 523 CompositeType.SrcNoEa, 524 getSurfaceType()); 525 havePgramSolidLoop = 526 (loop != null) ? LOOP_FOUND : LOOP_NOTFOUND; 527 } 528 return havePgramSolidLoop == LOOP_FOUND; 529 } 530 } 531 return false; 532 } 533 534 public void validatePipe(SunGraphics2D sg2d) { 535 sg2d.imagepipe = imagepipe; 536 if (sg2d.compositeState == sg2d.COMP_XOR) { 537 if (sg2d.paintState > sg2d.PAINT_ALPHACOLOR) { 538 sg2d.drawpipe = paintViaShape; 539 sg2d.fillpipe = paintViaShape; 540 sg2d.shapepipe = paintShape; 541 // REMIND: Ideally custom paint mode would use glyph 542 // rendering as opposed to outline rendering but the 543 // glyph paint rendering pipeline uses MaskBlit which 544 // is not defined for XOR. This means that text drawn 545 // in XOR mode with a Color object is different than 546 // text drawn in XOR mode with a Paint object. 547 sg2d.textpipe = outlineTextRenderer; 548 } else { 549 PixelToShapeConverter converter; 550 if (canRenderParallelograms(sg2d)) { 551 converter = colorViaPgram; 552 // Note that we use the transforming pipe here because it 553 // will examine the shape and possibly perform an optimized 554 // operation if it can be simplified. The simplifications 555 // will be valid for all STROKE and TRANSFORM types. 556 sg2d.shapepipe = colorViaPgram; 557 } else { 558 converter = colorViaShape; 559 sg2d.shapepipe = colorPrimitives; 560 } 561 if (sg2d.clipState == sg2d.CLIP_SHAPE) { 562 sg2d.drawpipe = converter; 563 sg2d.fillpipe = converter; 564 // REMIND: We should not be changing text strategies 565 // between outline and glyph rendering based upon the 566 // presence of a complex clip as that could cause a 567 // mismatch when drawing the same text both clipped 568 // and unclipped on two separate rendering passes. 569 // Unfortunately, all of the clipped glyph rendering 570 // pipelines rely on the use of the MaskBlit operation 571 // which is not defined for XOR. 572 sg2d.textpipe = outlineTextRenderer; 573 } else { 574 if (sg2d.transformState >= sg2d.TRANSFORM_TRANSLATESCALE) { 575 sg2d.drawpipe = converter; 576 sg2d.fillpipe = converter; 577 } else { 578 if (sg2d.strokeState != sg2d.STROKE_THIN) { 579 sg2d.drawpipe = converter; 580 } else { 581 sg2d.drawpipe = colorPrimitives; 582 } 583 sg2d.fillpipe = colorPrimitives; 584 } 585 sg2d.textpipe = solidTextRenderer; 586 } 587 // assert(sg2d.surfaceData == this); 588 } 589 } else if (sg2d.compositeState == sg2d.COMP_CUSTOM) { 590 if (sg2d.antialiasHint == SunHints.INTVAL_ANTIALIAS_ON) { 591 if (sg2d.clipState == sg2d.CLIP_SHAPE) { 592 sg2d.drawpipe = AAClipCompViaShape; 593 sg2d.fillpipe = AAClipCompViaShape; 594 sg2d.shapepipe = AAClipCompShape; 595 sg2d.textpipe = clipCompText; 596 } else { 597 sg2d.drawpipe = AACompViaShape; 598 sg2d.fillpipe = AACompViaShape; 599 sg2d.shapepipe = AACompShape; 600 sg2d.textpipe = compText; 601 } 602 } else { 603 sg2d.drawpipe = compViaShape; 604 sg2d.fillpipe = compViaShape; 605 sg2d.shapepipe = compShape; 606 if (sg2d.clipState == sg2d.CLIP_SHAPE) { 607 sg2d.textpipe = clipCompText; 608 } else { 609 sg2d.textpipe = compText; 610 } 611 } 612 } else if (sg2d.antialiasHint == SunHints.INTVAL_ANTIALIAS_ON) { 613 sg2d.alphafill = getMaskFill(sg2d); 614 // assert(sg2d.surfaceData == this); 615 if (sg2d.alphafill != null) { 616 if (sg2d.clipState == sg2d.CLIP_SHAPE) { 617 sg2d.drawpipe = AAClipColorViaShape; 618 sg2d.fillpipe = AAClipColorViaShape; 619 sg2d.shapepipe = AAClipColorShape; 620 sg2d.textpipe = clipColorText; 621 } else { 622 sg2d.drawpipe = AAColorViaShape; 623 sg2d.fillpipe = AAColorViaShape; 624 sg2d.shapepipe = AAColorShape; 625 if (sg2d.paintState > sg2d.PAINT_OPAQUECOLOR || 626 sg2d.compositeState > sg2d.COMP_ISCOPY) 627 { 628 sg2d.textpipe = colorText; 629 } else { 630 sg2d.textpipe = getTextPipe(sg2d, true /* AA==ON */); 631 } 632 } 633 } else { 634 if (sg2d.clipState == sg2d.CLIP_SHAPE) { 635 sg2d.drawpipe = AAClipPaintViaShape; 636 sg2d.fillpipe = AAClipPaintViaShape; 637 sg2d.shapepipe = AAClipPaintShape; 638 sg2d.textpipe = clipPaintText; 639 } else { 640 sg2d.drawpipe = AAPaintViaShape; 641 sg2d.fillpipe = AAPaintViaShape; 642 sg2d.shapepipe = AAPaintShape; 643 sg2d.textpipe = paintText; 644 } 645 } 646 } else if (sg2d.paintState > sg2d.PAINT_ALPHACOLOR || 647 sg2d.compositeState > sg2d.COMP_ISCOPY || 648 sg2d.clipState == sg2d.CLIP_SHAPE) 649 { 650 sg2d.drawpipe = paintViaShape; 651 sg2d.fillpipe = paintViaShape; 652 sg2d.shapepipe = paintShape; 653 sg2d.alphafill = getMaskFill(sg2d); 654 // assert(sg2d.surfaceData == this); 655 if (sg2d.alphafill != null) { 656 if (sg2d.clipState == sg2d.CLIP_SHAPE) { 657 sg2d.textpipe = clipColorText; 658 } else { 659 sg2d.textpipe = colorText; 660 } 661 } else { 662 if (sg2d.clipState == sg2d.CLIP_SHAPE) { 663 sg2d.textpipe = clipPaintText; 664 } else { 665 sg2d.textpipe = paintText; 666 } 667 } 668 } else { 669 PixelToShapeConverter converter; 670 if (canRenderParallelograms(sg2d)) { 671 converter = colorViaPgram; 672 // Note that we use the transforming pipe here because it 673 // will examine the shape and possibly perform an optimized 674 // operation if it can be simplified. The simplifications 675 // will be valid for all STROKE and TRANSFORM types. 676 sg2d.shapepipe = colorViaPgram; 677 } else { 678 converter = colorViaShape; 679 sg2d.shapepipe = colorPrimitives; 680 } 681 if (sg2d.transformState >= sg2d.TRANSFORM_TRANSLATESCALE) { 682 sg2d.drawpipe = converter; 683 sg2d.fillpipe = converter; 684 } else { 685 if (sg2d.strokeState != sg2d.STROKE_THIN) { 686 sg2d.drawpipe = converter; 687 } else { 688 sg2d.drawpipe = colorPrimitives; 689 } 690 sg2d.fillpipe = colorPrimitives; 691 } 692 693 sg2d.textpipe = getTextPipe(sg2d, false /* AA==OFF */); 694 // assert(sg2d.surfaceData == this); 695 } 696 697 // check for loops 698 if (sg2d.textpipe instanceof LoopBasedPipe || 699 sg2d.shapepipe instanceof LoopBasedPipe || 700 sg2d.fillpipe instanceof LoopBasedPipe || 701 sg2d.drawpipe instanceof LoopBasedPipe || 702 sg2d.imagepipe instanceof LoopBasedPipe) 703 { 704 sg2d.loops = getRenderLoops(sg2d); 705 } 706 } 707 708 /* Return the text pipe to be used based on the graphics AA hint setting, 709 * and the rest of the graphics state is compatible with these loops. 710 * If the text AA hint is "DEFAULT", then the AA graphics hint requests 711 * the AA text renderer, else it requests the B&W text renderer. 712 */ 713 private TextPipe getTextPipe(SunGraphics2D sg2d, boolean aaHintIsOn) { 714 715 /* Try to avoid calling getFontInfo() unless its needed to 716 * resolve one of the new AA types. 717 */ 718 switch (sg2d.textAntialiasHint) { 719 case SunHints.INTVAL_TEXT_ANTIALIAS_DEFAULT: 720 if (aaHintIsOn) { 721 return aaTextRenderer; 722 } else { 723 return solidTextRenderer; 724 } 725 case SunHints.INTVAL_TEXT_ANTIALIAS_OFF: 726 return solidTextRenderer; 727 728 case SunHints.INTVAL_TEXT_ANTIALIAS_ON: 729 return aaTextRenderer; 730 731 default: 732 switch (sg2d.getFontInfo().aaHint) { 733 734 case SunHints.INTVAL_TEXT_ANTIALIAS_LCD_HRGB: 735 case SunHints.INTVAL_TEXT_ANTIALIAS_LCD_VRGB: 736 return lcdTextRenderer; 737 738 case SunHints.INTVAL_TEXT_ANTIALIAS_ON: 739 return aaTextRenderer; 740 741 case SunHints.INTVAL_TEXT_ANTIALIAS_OFF: 742 return solidTextRenderer; 743 744 /* This should not be reached as the FontInfo will 745 * always explicitly set its hint value. So whilst 746 * this could be collapsed to returning say just 747 * solidTextRenderer, or even removed, its left 748 * here in case DEFAULT is ever passed in. 749 */ 750 default: 751 if (aaHintIsOn) { 752 return aaTextRenderer; 753 } else { 754 return solidTextRenderer; 755 } 756 } 757 } 758 } 759 760 private static SurfaceType getPaintSurfaceType(SunGraphics2D sg2d) { 761 switch (sg2d.paintState) { 762 case SunGraphics2D.PAINT_OPAQUECOLOR: 763 return SurfaceType.OpaqueColor; 764 case SunGraphics2D.PAINT_ALPHACOLOR: 765 return SurfaceType.AnyColor; 766 case SunGraphics2D.PAINT_GRADIENT: 767 if (sg2d.paint.getTransparency() == OPAQUE) { 768 return SurfaceType.OpaqueGradientPaint; 769 } else { 770 return SurfaceType.GradientPaint; 771 } 772 case SunGraphics2D.PAINT_LIN_GRADIENT: 773 if (sg2d.paint.getTransparency() == OPAQUE) { 774 return SurfaceType.OpaqueLinearGradientPaint; 775 } else { 776 return SurfaceType.LinearGradientPaint; 777 } 778 case SunGraphics2D.PAINT_RAD_GRADIENT: 779 if (sg2d.paint.getTransparency() == OPAQUE) { 780 return SurfaceType.OpaqueRadialGradientPaint; 781 } else { 782 return SurfaceType.RadialGradientPaint; 783 } 784 case SunGraphics2D.PAINT_TEXTURE: 785 if (sg2d.paint.getTransparency() == OPAQUE) { 786 return SurfaceType.OpaqueTexturePaint; 787 } else { 788 return SurfaceType.TexturePaint; 789 } 790 default: 791 case SunGraphics2D.PAINT_CUSTOM: 792 return SurfaceType.AnyPaint; 793 } 794 } 795 796 /** 797 * Returns a MaskFill object that can be used on this destination 798 * with the source (paint) and composite types determined by the given 799 * SunGraphics2D, or null if no such MaskFill object can be located. 800 * Subclasses can override this method if they wish to filter other 801 * attributes (such as the hardware capabilities of the destination 802 * surface) before returning a specific MaskFill object. 803 */ 804 protected MaskFill getMaskFill(SunGraphics2D sg2d) { 805 return MaskFill.getFromCache(getPaintSurfaceType(sg2d), 806 sg2d.imageComp, 807 getSurfaceType()); 808 } 809 810 private static RenderCache loopcache = new RenderCache(30); 811 812 /** 813 * Return a RenderLoops object containing all of the basic 814 * GraphicsPrimitive objects for rendering to the destination 815 * surface with the current attributes of the given SunGraphics2D. 816 */ 817 public RenderLoops getRenderLoops(SunGraphics2D sg2d) { 818 SurfaceType src = getPaintSurfaceType(sg2d); 819 CompositeType comp = (sg2d.compositeState == sg2d.COMP_ISCOPY 820 ? CompositeType.SrcNoEa 821 : sg2d.imageComp); 822 SurfaceType dst = sg2d.getSurfaceData().getSurfaceType(); 823 824 Object o = loopcache.get(src, comp, dst); 825 if (o != null) { 826 return (RenderLoops) o; 827 } 828 829 RenderLoops loops = makeRenderLoops(src, comp, dst); 830 loopcache.put(src, comp, dst, loops); 831 return loops; 832 } 833 834 /** 835 * Construct and return a RenderLoops object containing all of 836 * the basic GraphicsPrimitive objects for rendering to the 837 * destination surface with the given source, destination, and 838 * composite types. 839 */ 840 public static RenderLoops makeRenderLoops(SurfaceType src, 841 CompositeType comp, 842 SurfaceType dst) 843 { 844 RenderLoops loops = new RenderLoops(); 845 loops.drawLineLoop = DrawLine.locate(src, comp, dst); 846 loops.fillRectLoop = FillRect.locate(src, comp, dst); 847 loops.drawRectLoop = DrawRect.locate(src, comp, dst); 848 loops.drawPolygonsLoop = DrawPolygons.locate(src, comp, dst); 849 loops.drawPathLoop = DrawPath.locate(src, comp, dst); 850 loops.fillPathLoop = FillPath.locate(src, comp, dst); 851 loops.fillSpansLoop = FillSpans.locate(src, comp, dst); 852 loops.fillParallelogramLoop = FillParallelogram.locate(src, comp, dst); 853 loops.drawParallelogramLoop = DrawParallelogram.locate(src, comp, dst); 854 loops.drawGlyphListLoop = DrawGlyphList.locate(src, comp, dst); 855 loops.drawGlyphListAALoop = DrawGlyphListAA.locate(src, comp, dst); 856 loops.drawGlyphListLCDLoop = DrawGlyphListLCD.locate(src, comp, dst); 857 /* 858 System.out.println("drawLine: "+loops.drawLineLoop); 859 System.out.println("fillRect: "+loops.fillRectLoop); 860 System.out.println("drawRect: "+loops.drawRectLoop); 861 System.out.println("drawPolygons: "+loops.drawPolygonsLoop); 862 System.out.println("fillSpans: "+loops.fillSpansLoop); 863 System.out.println("drawGlyphList: "+loops.drawGlyphListLoop); 864 System.out.println("drawGlyphListAA: "+loops.drawGlyphListAALoop); 865 System.out.println("drawGlyphListLCD: "+loops.drawGlyphListLCDLoop); 866 */ 867 return loops; 868 } 869 870 /** 871 * Return the GraphicsConfiguration object that describes this 872 * destination surface. 873 */ 874 public abstract GraphicsConfiguration getDeviceConfiguration(); 875 876 /** 877 * Return the SurfaceType object that describes the destination 878 * surface. 879 */ 880 public final SurfaceType getSurfaceType() { 881 return surfaceType; 882 } 883 884 /** 885 * Return the ColorModel for the destination surface. 886 */ 887 public final ColorModel getColorModel() { 888 return colorModel; 889 } 890 891 /** 892 * Returns the type of this <code>Transparency</code>. 893 * @return the field type of this <code>Transparency</code>, which is 894 * either OPAQUE, BITMASK or TRANSLUCENT. 895 */ 896 public int getTransparency() { 897 return getColorModel().getTransparency(); 898 } 899 900 /** 901 * Return a readable Raster which contains the pixels for the 902 * specified rectangular region of the destination surface. 903 * The coordinate origin of the returned Raster is the same as 904 * the device space origin of the destination surface. 905 * In some cases the returned Raster might also be writeable. 906 * In most cases, the returned Raster might contain more pixels 907 * than requested. 908 * 909 * @see useTightBBoxes 910 */ 911 public abstract Raster getRaster(int x, int y, int w, int h); 912 913 /** 914 * Does the pixel accessibility of the destination surface 915 * suggest that rendering algorithms might want to take 916 * extra time to calculate a more accurate bounding box for 917 * the operation being performed? 918 * The typical case when this will be true is when a copy of 919 * the pixels has to be made when doing a getRaster. The 920 * fewer pixels copied, the faster the operation will go. 921 * 922 * @see getRaster 923 */ 924 public boolean useTightBBoxes() { 925 // Note: The native equivalent would trigger on VISIBLE_TO_NATIVE 926 // REMIND: This is not used - should be obsoleted maybe 927 return true; 928 } 929 930 /** 931 * Returns the pixel data for the specified Argb value packed 932 * into an integer for easy storage and conveyance. 933 */ 934 public int pixelFor(int rgb) { 935 return surfaceType.pixelFor(rgb, colorModel); 936 } 937 938 /** 939 * Returns the pixel data for the specified color packed into an 940 * integer for easy storage and conveyance. 941 * 942 * This method will use the getRGB() method of the Color object 943 * and defer to the pixelFor(int rgb) method if not overridden. 944 * 945 * For now this is a convenience function, but for cases where 946 * the highest quality color conversion is requested, this method 947 * should be overridden in those cases so that a more direct 948 * conversion of the color to the destination color space 949 * can be done using the additional information in the Color 950 * object. 951 */ 952 public int pixelFor(Color c) { 953 return pixelFor(c.getRGB()); 954 } 955 956 /** 957 * Returns the Argb representation for the specified integer value 958 * which is packed in the format of the associated ColorModel. 959 */ 960 public int rgbFor(int pixel) { 961 return surfaceType.rgbFor(pixel, colorModel); 962 } 963 964 /** 965 * Returns the bounds of the destination surface. 966 */ 967 public abstract Rectangle getBounds(); 968 969 static java.security.Permission compPermission; 970 971 /** 972 * Performs Security Permissions checks to see if a Custom 973 * Composite object should be allowed access to the pixels 974 * of this surface. 975 */ 976 protected void checkCustomComposite() { 977 SecurityManager sm = System.getSecurityManager(); 978 if (sm != null) { 979 if (compPermission == null) { 980 compPermission = 981 new java.awt.AWTPermission("readDisplayPixels"); 982 } 983 sm.checkPermission(compPermission); 984 } 985 } 986 987 /** 988 * Fetches private field IndexColorModel.allgrayopaque 989 * which is true when all palette entries in the color 990 * model are gray and opaque. 991 */ 992 protected static native boolean isOpaqueGray(IndexColorModel icm); 993 994 /** 995 * For our purposes null and NullSurfaceData are the same as 996 * they represent a disposed surface. 997 */ 998 public static boolean isNull(SurfaceData sd) { 999 if (sd == null || sd == NullSurfaceData.theInstance) { 1000 return true; 1001 } 1002 return false; 1003 } 1004 1005 /** 1006 * Performs a copyarea within this surface. Returns 1007 * false if there is no algorithm to perform the copyarea 1008 * given the current settings of the SunGraphics2D. 1009 */ 1010 public boolean copyArea(SunGraphics2D sg2d, 1011 int x, int y, int w, int h, int dx, int dy) 1012 { 1013 return false; 1014 } 1015 1016 /** 1017 * Synchronously releases resources associated with this surface. 1018 */ 1019 public void flush() {} 1020 1021 /** 1022 * Returns destination associated with this SurfaceData. This could be 1023 * either an Image or a Component; subclasses of SurfaceData are 1024 * responsible for returning the appropriate object. 1025 */ 1026 public abstract Object getDestination(); 1027 }