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