1 /* 2 * Copyright (c) 2011, 2015, 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.*; 29 import java.awt.font.*; 30 import java.awt.geom.*; 31 import java.awt.image.*; 32 import java.nio.*; 33 34 import sun.awt.*; 35 import sun.awt.image.*; 36 import sun.java2d.loops.*; 37 import sun.java2d.pipe.*; 38 import sun.lwawt.macosx.*; 39 40 import java.lang.annotation.Native; 41 42 /* 43 * This is the SurfaceData for a CGContextRef. 44 */ 45 public abstract class OSXSurfaceData extends BufImgSurfaceData { 46 static final float UPPER_BND = Float.MAX_VALUE / 2.0f; 47 static final float LOWER_BND = -UPPER_BND; 48 49 protected static CRenderer sQuartzPipe = null; 50 protected static CTextPipe sCocoaTextPipe = null; 51 protected static CompositeCRenderer sQuartzCompositePipe = null; 52 53 private GraphicsConfiguration fConfig; 54 private Rectangle fBounds; // bounds in user coordinates 55 56 static { 57 sQuartzPipe = new CRenderer(); // Creates the singleton quartz pipe. 58 } 59 60 // NOTE: Any subclasses must eventually call QuartzSurfaceData_InitOps in OSXSurfaceData.h 61 // This sets up the native side for the SurfaceData, and is required. 62 public OSXSurfaceData(SurfaceType sType, ColorModel cm) { 63 this(sType, cm, null, new Rectangle()); 64 } 65 66 public OSXSurfaceData(SurfaceType sType, ColorModel cm, GraphicsConfiguration config, Rectangle bounds) { 67 super(sType, cm); 68 69 this.fConfig = config; 70 71 this.fBounds = new Rectangle(bounds.x, bounds.y, bounds.width, bounds.y + bounds.height); 72 73 this.fGraphicsStates = getBufferOfSize(kSizeOfParameters); 74 this.fGraphicsStatesInt = this.fGraphicsStates.asIntBuffer(); 75 this.fGraphicsStatesFloat = this.fGraphicsStates.asFloatBuffer(); 76 this.fGraphicsStatesLong = this.fGraphicsStates.asLongBuffer(); 77 this.fGraphicsStatesObject = new Object[6]; // clip coordinates + clip types + texture paint image + stroke dash 78 // array + font + font paint 79 80 // NOTE: All access to the DrawingQueue comes through this OSXSurfaceData instance. Therefore 81 // every instance method of OSXSurfaceData that accesses the fDrawingQueue is synchronized. 82 83 // Thread.dumpStack(); 84 } 85 86 public void validatePipe(SunGraphics2D sg2d) { 87 88 if (sg2d.compositeState <= SunGraphics2D.COMP_ALPHA) { 89 if (sCocoaTextPipe == null) { 90 sCocoaTextPipe = new CTextPipe(); 91 } 92 93 sg2d.imagepipe = sQuartzPipe; 94 sg2d.drawpipe = sQuartzPipe; 95 sg2d.fillpipe = sQuartzPipe; 96 sg2d.shapepipe = sQuartzPipe; 97 sg2d.textpipe = sCocoaTextPipe; 98 } else { 99 setPipesToQuartzComposite(sg2d); 100 } 101 } 102 103 protected void setPipesToQuartzComposite(SunGraphics2D sg2d) { 104 if (sQuartzCompositePipe == null) { 105 sQuartzCompositePipe = new CompositeCRenderer(); 106 } 107 108 if (sCocoaTextPipe == null) { 109 sCocoaTextPipe = new CTextPipe(); 110 } 111 112 sg2d.imagepipe = sQuartzCompositePipe; 113 sg2d.drawpipe = sQuartzCompositePipe; 114 sg2d.fillpipe = sQuartzCompositePipe; 115 sg2d.shapepipe = sQuartzCompositePipe; 116 sg2d.textpipe = sCocoaTextPipe; 117 } 118 119 public Rectangle getBounds() { 120 // gznote: always return a copy, not the rect itself and translate into device space 121 return new Rectangle(fBounds.x, fBounds.y, fBounds.width, fBounds.height - fBounds.y); 122 } 123 124 public GraphicsConfiguration getDeviceConfiguration() { 125 return fConfig; 126 } 127 128 protected void setBounds(int x, int y, int w, int h) { 129 fBounds.setBounds(x, y, w, y + h); 130 } 131 132 // START compositing support API 133 public abstract BufferedImage copyArea(SunGraphics2D sg2d, int x, int y, int w, int h, BufferedImage image); 134 135 public abstract boolean xorSurfacePixels(SunGraphics2D sg2d, BufferedImage srcPixels, int x, int y, int w, int h, int colorXOR); 136 137 GraphicsConfiguration sDefaultGraphicsConfiguration = null; 138 139 protected BufferedImage getCompositingImage(int w, int h) { 140 if (sDefaultGraphicsConfiguration == null) { 141 sDefaultGraphicsConfiguration = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDefaultConfiguration(); 142 } 143 144 BufferedImage img = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB_PRE); 145 // clear the image. 146 clearRect(img, w, h); 147 return img; 148 } 149 150 protected BufferedImage getCompositingImageSame(BufferedImage img, int w, int h) { 151 if ((img == null) || (img.getWidth() != w) || (img.getHeight() != h)) { 152 img = getCompositingImage(w, h); 153 } 154 return img; 155 } 156 157 BufferedImage sSrcComposite = null; 158 159 public BufferedImage getCompositingSrcImage(int w, int h) { 160 // <rdar://problem/3720263>. Changed from getCompositingImageBiggerOrSame() to 161 // getCompositingImageSame(). (vm) 162 BufferedImage bim = getCompositingImageSame(sSrcComposite, w, h); 163 sSrcComposite = bim; 164 return bim; 165 } 166 167 BufferedImage sDstInComposite = null; 168 169 public BufferedImage getCompositingDstInImage(int w, int h) { 170 BufferedImage bim = getCompositingImageSame(sDstInComposite, w, h); 171 sDstInComposite = bim; 172 return bim; 173 } 174 175 BufferedImage sDstOutComposite = null; 176 177 public BufferedImage getCompositingDstOutImage(int w, int h) { 178 BufferedImage bim = getCompositingImageSame(sDstOutComposite, w, h); 179 sDstOutComposite = bim; 180 return bim; 181 } 182 183 public void clearRect(BufferedImage bim, int w, int h) { 184 Graphics2D g = bim.createGraphics(); 185 g.setComposite(AlphaComposite.Clear); 186 g.fillRect(0, 0, w, h); 187 g.dispose(); 188 } 189 190 // END compositing support API 191 192 public void invalidate() { 193 // always valid 194 } 195 196 // graphics primitives drawing implementation: 197 198 // certain primitives don't care about all the states (ex. drawing an image needs not involve setting current paint) 199 @Native static final int kPrimitive = 0; 200 @Native static final int kImage = 1; 201 @Native static final int kText = 2; 202 @Native static final int kCopyArea = 3; 203 @Native static final int kExternal = 4; 204 205 @Native static final int kLine = 5; // belongs to kPrimitive 206 @Native static final int kRect = 6; // belongs to kPrimitive 207 @Native static final int kRoundRect = 7; // belongs to kPrimitive 208 @Native static final int kOval = 8; // belongs to kPrimitive 209 @Native static final int kArc = 9; // belongs to kPrimitive 210 @Native static final int kPolygon = 10; // belongs to kPrimitive 211 @Native static final int kShape = 11; // belongs to kPrimitive 212 // static final int kImage = 12; // belongs to kImage 213 @Native static final int kString = 13; // belongs to kText 214 @Native static final int kGlyphs = 14; // belongs to kText 215 @Native static final int kUnicodes = 15; // belongs to kText 216 // static final int kCopyArea = 16; // belongs to kCopyArea 217 // static final int kExternal = 17; // belongs to kExternal 218 219 @Native static final int kCommonParameterCount = 1 + 1 + 4 + 4; // type + change flags + color info (type(1) align(1) and 220 // value(2)) + parameters ((x1, y1, x2, y2) OR (x, y, w, h)) 221 @Native static final int kLineParametersCount = kCommonParameterCount; // kCommonParameterCount 222 @Native static final int kRectParametersCount = kCommonParameterCount + 1; // kCommonParameterCount + isfill 223 @Native static final int kRoundRectParametersCount = kCommonParameterCount + 2 + 1; // kCommonParameterCount + arcW + arcH + 224 // isfill 225 @Native static final int kOvalParametersCount = kCommonParameterCount + 1; // kCommonParameterCount + isfill 226 @Native static final int kArcParametersCount = kCommonParameterCount + 2 + 1 + 1;// kCommonParameterCount + startAngle + 227 // arcAngle + isfill + type 228 @Native static final int kPolygonParametersCount = 0; // not supported 229 @Native static final int kShapeParametersCount = 0; // not supported 230 @Native static final int kImageParametersCount = kCommonParameterCount + 2 + 2 + 4 + 4; // flip horz vert + w&h + src + dst 231 @Native static final int kStringParametersCount = 0; // not supported 232 @Native static final int kGlyphsParametersCount = 0; // not supported 233 @Native static final int kUnicodesParametersCount = 0; // not supported 234 @Native static final int kPixelParametersCount = 0; // not supported 235 @Native static final int kExternalParametersCount = 0; // not supported 236 237 // for intParameters 238 // states info 239 @Native static final int kChangeFlagIndex = 0; // kBoundsChangedBit | .. | kFontChangedBit 240 // bounds info 241 @Native static final int kBoundsXIndex = 1; 242 @Native static final int kBoundsYIndex = 2; 243 @Native static final int kBoundsWidthIndex = 3; 244 @Native static final int kBoundsHeightIndex = 4; 245 // clip info 246 @Native static final int kClipStateIndex = 5; 247 @Native static final int kClipNumTypesIndex = 6; 248 @Native static final int kClipNumCoordsIndex = 7; 249 @Native static final int kClipWindingRuleIndex = 8; 250 @Native static final int kClipXIndex = 9; 251 @Native static final int kClipYIndex = 10; 252 @Native static final int kClipWidthIndex = 11; 253 @Native static final int kClipHeightIndex = 12; 254 // ctm info 255 @Native static final int kCTMaIndex = 13; 256 @Native static final int kCTMbIndex = 14; 257 @Native static final int kCTMcIndex = 15; 258 @Native static final int kCTMdIndex = 16; 259 @Native static final int kCTMtxIndex = 17; 260 @Native static final int kCTMtyIndex = 18; 261 // color info 262 @Native static final int kColorStateIndex = 19; // kColorSimple or kColorGradient or kColorTexture 263 @Native static final int kColorRGBValueIndex = 20; // if kColorSimple 264 @Native static final int kColorIndexValueIndex = 21; // if kColorSystem 265 @Native static final int kColorPointerIndex = 22; // 266 @Native static final int kColorPointerIndex2 = 23; // 267 @Native static final int kColorRGBValue1Index = 24; // if kColorGradient 268 @Native static final int kColorWidthIndex = 25; // if kColorTexture 269 @Native static final int kColorRGBValue2Index = 26; // if kColorGradient 270 @Native static final int kColorHeightIndex = 27; // if kColorTexture 271 @Native static final int kColorIsCyclicIndex = 28; // if kColorGradient (kColorNonCyclic or kColorCyclic) 272 @Native static final int kColorx1Index = 29; 273 @Native static final int kColortxIndex = 30; 274 @Native static final int kColory1Index = 31; 275 @Native static final int kColortyIndex = 32; 276 @Native static final int kColorx2Index = 33; 277 @Native static final int kColorsxIndex = 34; 278 @Native static final int kColory2Index = 35; 279 @Native static final int kColorsyIndex = 36; 280 // composite info 281 @Native static final int kCompositeRuleIndex = 37; // kCGCompositeClear or ... or kCGCompositeXor 282 @Native static final int kCompositeValueIndex = 38; 283 // stroke info 284 @Native static final int kStrokeJoinIndex = 39; // see BasicStroke.java 285 @Native static final int kStrokeCapIndex = 40; // see BasicStroke.java 286 @Native static final int kStrokeWidthIndex = 41; 287 @Native static final int kStrokeDashPhaseIndex = 42; 288 @Native static final int kStrokeLimitIndex = 43; 289 // hints info 290 @Native static final int kHintsAntialiasIndex = 44; 291 @Native static final int kHintsTextAntialiasIndex = 45; 292 @Native static final int kHintsFractionalMetricsIndex = 46; 293 @Native static final int kHintsRenderingIndex = 47; 294 @Native static final int kHintsInterpolationIndex = 48; 295 // live resizing info 296 @Native static final int kCanDrawDuringLiveResizeIndex = 49; 297 298 @Native static final int kSizeOfParameters = kCanDrawDuringLiveResizeIndex + 1; 299 300 // for objectParameters 301 @Native static final int kClipCoordinatesIndex = 0; 302 @Native static final int kClipTypesIndex = 1; 303 @Native static final int kTextureImageIndex = 2; 304 @Native static final int kStrokeDashArrayIndex = 3; 305 @Native static final int kFontIndex = 4; 306 @Native static final int kFontPaintIndex = 5; 307 308 // possible state changes 309 @Native static final int kBoundsChangedBit = 1 << 0; 310 @Native static final int kBoundsNotChangedBit = ~kBoundsChangedBit; 311 @Native static final int kClipChangedBit = 1 << 1; 312 @Native static final int kClipNotChangedBit = ~kClipChangedBit; 313 @Native static final int kCTMChangedBit = 1 << 2; 314 @Native static final int kCTMNotChangedBit = ~kCTMChangedBit; 315 @Native static final int kColorChangedBit = 1 << 3; 316 @Native static final int kColorNotChangedBit = ~kColorChangedBit; 317 @Native static final int kCompositeChangedBit = 1 << 4; 318 @Native static final int kCompositeNotChangedBit = ~kCompositeChangedBit; 319 @Native static final int kStrokeChangedBit = 1 << 5; 320 @Native static final int kStrokeNotChangedBit = ~kStrokeChangedBit; 321 @Native static final int kHintsChangedBit = 1 << 6; 322 @Native static final int kHintsNotChangedBit = ~kHintsChangedBit; 323 @Native static final int kFontChangedBit = 1 << 7; 324 @Native static final int kFontNotChangedBit = ~kFontChangedBit; 325 @Native static final int kEverythingChangedFlag = 0xffffffff; 326 327 // possible color states 328 @Native static final int kColorSimple = 0; 329 @Native static final int kColorSystem = 1; 330 @Native static final int kColorGradient = 2; 331 @Native static final int kColorTexture = 3; 332 333 // possible gradient color states 334 @Native static final int kColorNonCyclic = 0; 335 @Native static final int kColorCyclic = 1; 336 337 // possible clip states 338 @Native static final int kClipRect = 0; 339 @Native static final int kClipShape = 1; 340 341 static int getRendererTypeForPrimitive(int primitiveType) { 342 switch (primitiveType) { 343 case kImage: 344 return kImage; 345 case kCopyArea: 346 return kCopyArea; 347 case kExternal: 348 return kExternal; 349 case kString: 350 case kGlyphs: 351 case kUnicodes: 352 return kText; 353 default: 354 return kPrimitive; 355 } 356 } 357 358 int fChangeFlag; 359 protected ByteBuffer fGraphicsStates = null; 360 IntBuffer fGraphicsStatesInt = null; 361 FloatBuffer fGraphicsStatesFloat = null; 362 LongBuffer fGraphicsStatesLong = null; 363 protected Object[] fGraphicsStatesObject = null; 364 365 Rectangle userBounds = new Rectangle(); 366 float lastUserX = 0; 367 float lastUserY = 0; 368 float lastUserW = 0; 369 float lastUserH = 0; 370 371 void setUserBounds(SunGraphics2D sg2d, int x, int y, int width, int height) { 372 if ((lastUserX != x) || (lastUserY != y) || (lastUserW != width) || (lastUserH != height)) { 373 lastUserX = x; 374 lastUserY = y; 375 lastUserW = width; 376 lastUserH = height; 377 378 this.fGraphicsStatesInt.put(kBoundsXIndex, x); 379 this.fGraphicsStatesInt.put(kBoundsYIndex, y); 380 this.fGraphicsStatesInt.put(kBoundsWidthIndex, width); 381 this.fGraphicsStatesInt.put(kBoundsHeightIndex, height); 382 383 userBounds.setBounds(x, y, width, height); 384 385 this.fChangeFlag = (this.fChangeFlag | kBoundsChangedBit); 386 } else { 387 this.fChangeFlag = (this.fChangeFlag & kBoundsNotChangedBit); 388 } 389 } 390 391 static ByteBuffer getBufferOfSize(int size) { 392 ByteBuffer buffer = ByteBuffer.allocateDirect(size * 4); 393 buffer.order(ByteOrder.nativeOrder()); 394 return buffer; 395 } 396 397 FloatBuffer clipCoordinatesArray = null; 398 IntBuffer clipTypesArray = null; 399 Shape lastClipShape = null; 400 float lastClipX = 0; 401 float lastClipY = 0; 402 float lastClipW = 0; 403 float lastClipH = 0; 404 405 void setupClip(SunGraphics2D sg2d) { 406 switch (sg2d.clipState) { 407 case SunGraphics2D.CLIP_DEVICE: 408 case SunGraphics2D.CLIP_RECTANGULAR: { 409 Region clip = sg2d.getCompClip(); 410 float x = clip.getLoX(); 411 float y = clip.getLoY(); 412 float w = clip.getWidth(); 413 float h = clip.getHeight(); 414 if ((this.fGraphicsStatesInt.get(kClipStateIndex) != kClipRect) || 415 (x != lastClipX) || 416 (y != lastClipY) || 417 (w != lastClipW) || 418 (h != lastClipH)) { 419 this.fGraphicsStatesFloat.put(kClipXIndex, x); 420 this.fGraphicsStatesFloat.put(kClipYIndex, y); 421 this.fGraphicsStatesFloat.put(kClipWidthIndex, w); 422 this.fGraphicsStatesFloat.put(kClipHeightIndex, h); 423 424 lastClipX = x; 425 lastClipY = y; 426 lastClipW = w; 427 lastClipH = h; 428 429 this.fChangeFlag = (this.fChangeFlag | kClipChangedBit); 430 } else { 431 this.fChangeFlag = (this.fChangeFlag & kClipNotChangedBit); 432 } 433 this.fGraphicsStatesInt.put(kClipStateIndex, kClipRect); 434 break; 435 } 436 case SunGraphics2D.CLIP_SHAPE: { 437 // if (lastClipShape != sg2d.usrClip) shapes are mutable!, and doing "equals" traverses all 438 // the coordinates, so we might as well do all of it anyhow 439 lastClipShape = sg2d.usrClip; 440 441 GeneralPath gp = null; 442 443 if (sg2d.usrClip instanceof GeneralPath) { 444 gp = (GeneralPath) sg2d.usrClip; 445 } else { 446 gp = new GeneralPath(sg2d.usrClip); 447 } 448 449 int shapeLength = getPathLength(gp); 450 451 if ((clipCoordinatesArray == null) || (clipCoordinatesArray.capacity() < (shapeLength * 6))) { 452 clipCoordinatesArray = getBufferOfSize(shapeLength * 6).asFloatBuffer(); // segment can have a 453 // max of 6 coordinates 454 } 455 if ((clipTypesArray == null) || (clipTypesArray.capacity() < shapeLength)) { 456 clipTypesArray = getBufferOfSize(shapeLength).asIntBuffer(); 457 } 458 459 int windingRule = getPathCoordinates(gp, clipCoordinatesArray, clipTypesArray); 460 461 this.fGraphicsStatesInt.put(kClipNumTypesIndex, clipTypesArray.position()); 462 this.fGraphicsStatesInt.put(kClipNumCoordsIndex, clipCoordinatesArray.position()); 463 this.fGraphicsStatesInt.put(kClipWindingRuleIndex, windingRule); 464 this.fGraphicsStatesObject[kClipTypesIndex] = clipTypesArray; 465 this.fGraphicsStatesObject[kClipCoordinatesIndex] = clipCoordinatesArray; 466 467 this.fChangeFlag = (this.fChangeFlag | kClipChangedBit); 468 this.fGraphicsStatesInt.put(kClipStateIndex, kClipShape); 469 break; 470 } 471 } 472 473 } 474 475 final double[] lastCTM = new double[6]; 476 float lastCTMa = 0; 477 float lastCTMb = 0; 478 float lastCTMc = 0; 479 float lastCTMd = 0; 480 float lastCTMtx = 0; 481 float lastCTMty = 0; 482 483 void setupTransform(SunGraphics2D sg2d) { 484 sg2d.transform.getMatrix(lastCTM); 485 486 float a = (float) lastCTM[0]; 487 float b = (float) lastCTM[1]; 488 float c = (float) lastCTM[2]; 489 float d = (float) lastCTM[3]; 490 float tx = (float) lastCTM[4]; 491 float ty = (float) lastCTM[5]; 492 if (tx != lastCTMtx || 493 ty != lastCTMty || 494 a != lastCTMa || 495 b != lastCTMb || 496 c != lastCTMc || 497 d != lastCTMd) { 498 this.fGraphicsStatesFloat.put(kCTMaIndex, a); 499 this.fGraphicsStatesFloat.put(kCTMbIndex, b); 500 this.fGraphicsStatesFloat.put(kCTMcIndex, c); 501 this.fGraphicsStatesFloat.put(kCTMdIndex, d); 502 this.fGraphicsStatesFloat.put(kCTMtxIndex, tx); 503 this.fGraphicsStatesFloat.put(kCTMtyIndex, ty); 504 505 lastCTMa = a; 506 lastCTMb = b; 507 lastCTMc = c; 508 lastCTMd = d; 509 lastCTMtx = tx; 510 lastCTMty = ty; 511 512 this.fChangeFlag = (this.fChangeFlag | kCTMChangedBit); 513 } else { 514 this.fChangeFlag = (this.fChangeFlag & kCTMNotChangedBit); 515 } 516 } 517 518 static AffineTransform sIdentityMatrix = new AffineTransform(); 519 Paint lastPaint = null; 520 long lastPaintPtr = 0; 521 int lastPaintRGB = 0; 522 int lastPaintIndex = 0; 523 BufferedImage texturePaintImage = null; 524 525 void setupPaint(SunGraphics2D sg2d, int x, int y, int w, int h) { 526 if (sg2d.paint instanceof SystemColor) { 527 SystemColor color = (SystemColor) sg2d.paint; 528 int index = color.hashCode(); // depends on Color.java hashCode implementation! (returns "value" of color) 529 if ((this.fGraphicsStatesInt.get(kColorStateIndex) != kColorSystem) || (index != this.lastPaintIndex)) { 530 this.lastPaintIndex = index; 531 532 this.fGraphicsStatesInt.put(kColorStateIndex, kColorSystem); 533 this.fGraphicsStatesInt.put(kColorIndexValueIndex, index); 534 535 this.fChangeFlag = (this.fChangeFlag | kColorChangedBit); 536 } else { 537 this.fChangeFlag = (this.fChangeFlag & kColorNotChangedBit); 538 } 539 } else if (sg2d.paint instanceof Color) { 540 Color color = (Color) sg2d.paint; 541 int rgb = color.getRGB(); 542 if ((this.fGraphicsStatesInt.get(kColorStateIndex) != kColorSimple) || (rgb != this.lastPaintRGB)) { 543 this.lastPaintRGB = rgb; 544 545 this.fGraphicsStatesInt.put(kColorStateIndex, kColorSimple); 546 this.fGraphicsStatesInt.put(kColorRGBValueIndex, rgb); 547 548 this.fChangeFlag = (this.fChangeFlag | kColorChangedBit); 549 } else { 550 this.fChangeFlag = (this.fChangeFlag & kColorNotChangedBit); 551 } 552 } else if (sg2d.paint instanceof GradientPaint) { 553 if ((this.fGraphicsStatesInt.get(kColorStateIndex) != kColorGradient) || (lastPaint != sg2d.paint)) { 554 GradientPaint color = (GradientPaint) sg2d.paint; 555 this.fGraphicsStatesInt.put(kColorStateIndex, kColorGradient); 556 this.fGraphicsStatesInt.put(kColorRGBValue1Index, color.getColor1().getRGB()); 557 this.fGraphicsStatesInt.put(kColorRGBValue2Index, color.getColor2().getRGB()); 558 this.fGraphicsStatesInt.put(kColorIsCyclicIndex, (color.isCyclic()) ? kColorCyclic : kColorNonCyclic); 559 Point2D p = color.getPoint1(); 560 this.fGraphicsStatesFloat.put(kColorx1Index, (float) p.getX()); 561 this.fGraphicsStatesFloat.put(kColory1Index, (float) p.getY()); 562 p = color.getPoint2(); 563 this.fGraphicsStatesFloat.put(kColorx2Index, (float) p.getX()); 564 this.fGraphicsStatesFloat.put(kColory2Index, (float) p.getY()); 565 566 this.fChangeFlag = (this.fChangeFlag | kColorChangedBit); 567 } else { 568 this.fChangeFlag = (this.fChangeFlag & kColorNotChangedBit); 569 } 570 } else if (sg2d.paint instanceof TexturePaint) { 571 if ((this.fGraphicsStatesInt.get(kColorStateIndex) != kColorTexture) || (lastPaint != sg2d.paint)) { 572 TexturePaint color = (TexturePaint) sg2d.paint; 573 this.fGraphicsStatesInt.put(kColorStateIndex, kColorTexture); 574 texturePaintImage = color.getImage(); 575 SurfaceData textureSurfaceData = BufImgSurfaceData.createData(texturePaintImage); 576 this.fGraphicsStatesInt.put(kColorWidthIndex, texturePaintImage.getWidth()); 577 this.fGraphicsStatesInt.put(kColorHeightIndex, texturePaintImage.getHeight()); 578 Rectangle2D anchor = color.getAnchorRect(); 579 this.fGraphicsStatesFloat.put(kColortxIndex, (float) anchor.getX()); 580 this.fGraphicsStatesFloat.put(kColortyIndex, (float) anchor.getY()); 581 this.fGraphicsStatesFloat.put(kColorsxIndex, (float) (anchor.getWidth() / texturePaintImage.getWidth())); 582 this.fGraphicsStatesFloat.put(kColorsyIndex, (float) (anchor.getHeight() / texturePaintImage.getHeight())); 583 this.fGraphicsStatesObject[kTextureImageIndex] = textureSurfaceData; 584 585 this.fChangeFlag = (this.fChangeFlag | kColorChangedBit); 586 } else { 587 this.fChangeFlag = (this.fChangeFlag & kColorNotChangedBit); 588 } 589 } else { 590 if ((this.fGraphicsStatesInt.get(kColorStateIndex) != kColorTexture) || (lastPaint != sg2d.paint) || ((this.fChangeFlag & kBoundsChangedBit) != 0)) { 591 PaintContext context = sg2d.paint.createContext(sg2d.getDeviceColorModel(), userBounds, userBounds, sIdentityMatrix, sg2d.getRenderingHints()); 592 WritableRaster raster = (WritableRaster) (context.getRaster(userBounds.x, userBounds.y, userBounds.width, userBounds.height)); 593 ColorModel cm = context.getColorModel(); 594 texturePaintImage = new BufferedImage(cm, raster, cm.isAlphaPremultiplied(), null); 595 596 this.fGraphicsStatesInt.put(kColorStateIndex, kColorTexture); 597 this.fGraphicsStatesInt.put(kColorWidthIndex, texturePaintImage.getWidth()); 598 this.fGraphicsStatesInt.put(kColorHeightIndex, texturePaintImage.getHeight()); 599 this.fGraphicsStatesFloat.put(kColortxIndex, (float) userBounds.getX()); 600 this.fGraphicsStatesFloat.put(kColortyIndex, (float) userBounds.getY()); 601 this.fGraphicsStatesFloat.put(kColorsxIndex, 1.0f); 602 this.fGraphicsStatesFloat.put(kColorsyIndex, 1.0f); 603 this.fGraphicsStatesObject[kTextureImageIndex] = OSXOffScreenSurfaceData.createNewSurface(texturePaintImage); 604 605 606 this.fChangeFlag = (this.fChangeFlag | kColorChangedBit); 607 } else { 608 this.fChangeFlag = (this.fChangeFlag & kColorNotChangedBit); 609 } 610 } 611 lastPaint = sg2d.paint; 612 } 613 614 Composite lastComposite; 615 int lastCompositeAlphaRule = 0; 616 float lastCompositeAlphaValue = 0; 617 618 void setupComposite(SunGraphics2D sg2d) { 619 Composite composite = sg2d.composite; 620 621 if (lastComposite != composite) { 622 lastComposite = composite; 623 624 // For composite state COMP_ISCOPY, COMP_XOR or COMP_CUSTOM set alpha compositor to COPY: 625 int alphaRule = AlphaComposite.SRC_OVER; 626 float alphaValue = 1.0f; 627 628 // For composite state COMP_ISCOPY composite could be null. If it's not (or composite state == COMP_ALPHA) 629 // get alpha compositor's values: 630 if ((sg2d.compositeState <= SunGraphics2D.COMP_ALPHA) && (composite != null)) { 631 AlphaComposite alphaComposite = (AlphaComposite) composite; 632 alphaRule = alphaComposite.getRule(); 633 alphaValue = alphaComposite.getAlpha(); 634 } 635 636 // 2-17-03 VL: [Radar 3174922] 637 // For COMP_XOR and COMP_CUSTOM compositing modes we should be setting alphaRule = AlphaComposite.SRC 638 // which should map to kCGCompositeCopy. 639 640 if ((lastCompositeAlphaRule != alphaRule) || (lastCompositeAlphaValue != alphaValue)) { 641 this.fGraphicsStatesInt.put(kCompositeRuleIndex, alphaRule); 642 this.fGraphicsStatesFloat.put(kCompositeValueIndex, alphaValue); 643 644 lastCompositeAlphaRule = alphaRule; 645 lastCompositeAlphaValue = alphaValue; 646 647 this.fChangeFlag = (this.fChangeFlag | kCompositeChangedBit); 648 } else { 649 this.fChangeFlag = (this.fChangeFlag & kCompositeNotChangedBit); 650 } 651 } else { 652 this.fChangeFlag = (this.fChangeFlag & kCompositeNotChangedBit); 653 } 654 } 655 656 BasicStroke lastStroke = null; 657 static BasicStroke defaultBasicStroke = new BasicStroke(); 658 659 void setupStroke(SunGraphics2D sg2d) { 660 BasicStroke stroke = defaultBasicStroke; 661 662 if (sg2d.stroke instanceof BasicStroke) { 663 stroke = (BasicStroke) sg2d.stroke; 664 } 665 666 if (lastStroke != stroke) { 667 this.fGraphicsStatesObject[kStrokeDashArrayIndex] = stroke.getDashArray(); 668 this.fGraphicsStatesFloat.put(kStrokeDashPhaseIndex, stroke.getDashPhase()); 669 this.fGraphicsStatesInt.put(kStrokeCapIndex, stroke.getEndCap()); 670 this.fGraphicsStatesInt.put(kStrokeJoinIndex, stroke.getLineJoin()); 671 this.fGraphicsStatesFloat.put(kStrokeWidthIndex, stroke.getLineWidth()); 672 this.fGraphicsStatesFloat.put(kStrokeLimitIndex, stroke.getMiterLimit()); 673 674 this.fChangeFlag = (this.fChangeFlag | kStrokeChangedBit); 675 676 lastStroke = stroke; 677 } else { 678 this.fChangeFlag = (this.fChangeFlag & kStrokeNotChangedBit); 679 } 680 } 681 682 Font lastFont; 683 684 void setupFont(Font font, Paint paint) { 685 if (font == null) { return; } 686 687 // We have to setup the kFontPaintIndex if we have changed the color so we added the last 688 // test to see if the color has changed - needed for complex strings 689 // see Radar 3368674 690 if ((font != lastFont) || ((this.fChangeFlag & kColorChangedBit) != 0)) { 691 this.fGraphicsStatesObject[kFontIndex] = font; 692 this.fGraphicsStatesObject[kFontPaintIndex] = paint; 693 694 this.fChangeFlag = (this.fChangeFlag | kFontChangedBit); 695 696 lastFont = font; 697 } else { 698 this.fChangeFlag = (this.fChangeFlag & kFontNotChangedBit); 699 } 700 } 701 702 void setupRenderingHints(SunGraphics2D sg2d) { 703 boolean hintsChanged = false; 704 705 // Significant for draw, fill, text, and image ops: 706 int antialiasHint = sg2d.antialiasHint; 707 if (this.fGraphicsStatesInt.get(kHintsAntialiasIndex) != antialiasHint) { 708 this.fGraphicsStatesInt.put(kHintsAntialiasIndex, antialiasHint); 709 hintsChanged = true; 710 } 711 712 // Significant only for text ops: 713 int textAntialiasHint = sg2d.textAntialiasHint; 714 if (this.fGraphicsStatesInt.get(kHintsTextAntialiasIndex) != textAntialiasHint) { 715 this.fGraphicsStatesInt.put(kHintsTextAntialiasIndex, textAntialiasHint); 716 hintsChanged = true; 717 } 718 719 // Significant only for text ops: 720 int fractionalMetricsHint = sg2d.fractionalMetricsHint; 721 if (this.fGraphicsStatesInt.get(kHintsFractionalMetricsIndex) != fractionalMetricsHint) { 722 this.fGraphicsStatesInt.put(kHintsFractionalMetricsIndex, fractionalMetricsHint); 723 hintsChanged = true; 724 } 725 726 // Significant only for image ops: 727 int renderHint = sg2d.renderHint; 728 if (this.fGraphicsStatesInt.get(kHintsRenderingIndex) != renderHint) { 729 this.fGraphicsStatesInt.put(kHintsRenderingIndex, renderHint); 730 hintsChanged = true; 731 } 732 733 // Significant only for image ops: 734 Object hintValue = sg2d.getRenderingHint(RenderingHints.KEY_INTERPOLATION); 735 int interpolationHint = (hintValue != null ? ((SunHints.Value) hintValue).getIndex() : -1); 736 if (this.fGraphicsStatesInt.get(kHintsInterpolationIndex) != interpolationHint) { 737 this.fGraphicsStatesInt.put(kHintsInterpolationIndex, interpolationHint); 738 hintsChanged = true; 739 } 740 741 if (hintsChanged) { 742 this.fChangeFlag = (this.fChangeFlag | kHintsChangedBit); 743 } else { 744 this.fChangeFlag = (this.fChangeFlag & kHintsNotChangedBit); 745 } 746 } 747 748 SunGraphics2D sg2dCurrent = null; 749 Thread threadCurrent = null; 750 751 void setupGraphicsState(SunGraphics2D sg2d, int primitiveType) { 752 setupGraphicsState(sg2d, primitiveType, sg2d.font, 0, 0, fBounds.width, fBounds.height); // deviceBounds into userBounds 753 } 754 755 void setupGraphicsState(SunGraphics2D sg2d, int primitiveType, int x, int y, int w, int h) { 756 setupGraphicsState(sg2d, primitiveType, sg2d.font, x, y, w, h); 757 } 758 759 // the method below is overriden by CPeerSurface to check the last peer used to draw 760 // if the peer changed we finish lazy drawing 761 void setupGraphicsState(SunGraphics2D sg2d, int primitiveType, Font font, int x, int y, int w, int h) { 762 this.fChangeFlag = 0; 763 764 setUserBounds(sg2d, x, y, w, h); 765 766 Thread thread = Thread.currentThread(); 767 if ((this.sg2dCurrent != sg2d) || (this.threadCurrent != thread)) { 768 this.sg2dCurrent = sg2d; 769 this.threadCurrent = thread; 770 771 setupClip(sg2d); 772 setupTransform(sg2d); 773 setupPaint(sg2d, x, y, w, h); 774 setupComposite(sg2d); 775 setupStroke(sg2d); 776 setupFont(font, sg2d.paint); 777 setupRenderingHints(sg2d); 778 779 this.fChangeFlag = kEverythingChangedFlag; 780 } else { 781 int rendererType = getRendererTypeForPrimitive(primitiveType); 782 783 setupClip(sg2d); 784 setupTransform(sg2d); 785 786 if (rendererType != kCopyArea) { 787 setupComposite(sg2d); 788 setupRenderingHints(sg2d); 789 790 if ((rendererType != kImage)) { 791 setupPaint(sg2d, x, y, w, h); 792 setupStroke(sg2d); 793 } 794 if (rendererType != kPrimitive) { 795 setupFont(font, sg2d.paint); 796 } 797 798 } 799 } 800 801 this.fGraphicsStatesInt.put(kChangeFlagIndex, this.fChangeFlag); 802 } 803 804 boolean isCustomPaint(SunGraphics2D sg2d) { 805 if ((sg2d.paint instanceof Color) || (sg2d.paint instanceof SystemColor) || (sg2d.paint instanceof GradientPaint) || (sg2d.paint instanceof TexturePaint)) { return false; } 806 807 return true; 808 } 809 810 final float[] segmentCoordinatesArray = new float[6]; 811 812 int getPathLength(GeneralPath gp) { 813 int length = 0; 814 815 PathIterator pi = gp.getPathIterator(null); 816 while (pi.isDone() == false) { 817 pi.next(); 818 length++; 819 } 820 821 return length; 822 } 823 824 int getPathCoordinates(GeneralPath gp, FloatBuffer coordinates, IntBuffer types) { 825 // System.err.println("getPathCoordinates"); 826 boolean skip = false; 827 828 coordinates.clear(); 829 types.clear(); 830 831 int type; 832 833 PathIterator pi = gp.getPathIterator(null); 834 while (pi.isDone() == false) { 835 skip = false; 836 type = pi.currentSegment(segmentCoordinatesArray); 837 838 switch (type) { 839 case PathIterator.SEG_MOVETO: 840 // System.err.println(" SEG_MOVETO ("+segmentCoordinatesArray[0]+", "+segmentCoordinatesArray[1]+")"); 841 if (segmentCoordinatesArray[0] < UPPER_BND && segmentCoordinatesArray[0] > LOWER_BND && 842 segmentCoordinatesArray[1] < UPPER_BND && segmentCoordinatesArray[1] > LOWER_BND) { 843 coordinates.put(segmentCoordinatesArray[0]); 844 coordinates.put(segmentCoordinatesArray[1]); 845 } else { 846 skip = true; 847 } 848 break; 849 case PathIterator.SEG_LINETO: 850 // System.err.println(" SEG_LINETO ("+segmentCoordinatesArray[0]+", "+segmentCoordinatesArray[1]+")"); 851 if (segmentCoordinatesArray[0] < UPPER_BND && segmentCoordinatesArray[0] > LOWER_BND && 852 segmentCoordinatesArray[1] < UPPER_BND && segmentCoordinatesArray[1] > LOWER_BND) { 853 coordinates.put(segmentCoordinatesArray[0]); 854 coordinates.put(segmentCoordinatesArray[1]); 855 } else { 856 skip = true; 857 } 858 break; 859 case PathIterator.SEG_QUADTO: 860 // System.err.println(" SEG_QUADTO ("+segmentCoordinatesArray[0]+", "+segmentCoordinatesArray[1]+"), ("+segmentCoordinatesArray[2]+", "+segmentCoordinatesArray[3]+")"); 861 if (segmentCoordinatesArray[0] < UPPER_BND && segmentCoordinatesArray[0] > LOWER_BND && 862 segmentCoordinatesArray[1] < UPPER_BND && segmentCoordinatesArray[1] > LOWER_BND && 863 segmentCoordinatesArray[2] < UPPER_BND && segmentCoordinatesArray[2] > LOWER_BND && 864 segmentCoordinatesArray[3] < UPPER_BND && segmentCoordinatesArray[3] > LOWER_BND) { 865 coordinates.put(segmentCoordinatesArray[0]); 866 coordinates.put(segmentCoordinatesArray[1]); 867 coordinates.put(segmentCoordinatesArray[2]); 868 coordinates.put(segmentCoordinatesArray[3]); 869 } else { 870 skip = true; 871 } 872 break; 873 case PathIterator.SEG_CUBICTO: 874 // System.err.println(" SEG_QUADTO ("+segmentCoordinatesArray[0]+", "+segmentCoordinatesArray[1]+"), ("+segmentCoordinatesArray[2]+", "+segmentCoordinatesArray[3]+"), ("+segmentCoordinatesArray[4]+", "+segmentCoordinatesArray[5]+")"); 875 if (segmentCoordinatesArray[0] < UPPER_BND && segmentCoordinatesArray[0] > LOWER_BND && 876 segmentCoordinatesArray[1] < UPPER_BND && segmentCoordinatesArray[1] > LOWER_BND && 877 segmentCoordinatesArray[2] < UPPER_BND && segmentCoordinatesArray[2] > LOWER_BND && 878 segmentCoordinatesArray[3] < UPPER_BND && segmentCoordinatesArray[3] > LOWER_BND && 879 segmentCoordinatesArray[4] < UPPER_BND && segmentCoordinatesArray[4] > LOWER_BND && 880 segmentCoordinatesArray[5] < UPPER_BND && segmentCoordinatesArray[5] > LOWER_BND) { 881 coordinates.put(segmentCoordinatesArray[0]); 882 coordinates.put(segmentCoordinatesArray[1]); 883 coordinates.put(segmentCoordinatesArray[2]); 884 coordinates.put(segmentCoordinatesArray[3]); 885 coordinates.put(segmentCoordinatesArray[4]); 886 coordinates.put(segmentCoordinatesArray[5]); 887 } else { 888 skip = true; 889 } 890 break; 891 case PathIterator.SEG_CLOSE: 892 // System.err.println(" SEG_CLOSE"); 893 break; 894 } 895 896 if (!skip) { 897 types.put(type); 898 } 899 900 pi.next(); 901 } 902 903 return pi.getWindingRule(); 904 } 905 906 public void doLine(CRenderer renderer, SunGraphics2D sg2d, float x1, float y1, float x2, float y2) { 907 // System.err.println("-- doLine x1="+x1+" y1="+y1+" x2="+x2+" y2="+y2+" paint="+sg2d.paint); 908 setupGraphicsState(sg2d, kLine, sg2d.font, 0, 0, fBounds.width, fBounds.height); 909 renderer.doLine(this, x1, y1, x2, y2); 910 } 911 912 public void doRect(CRenderer renderer, SunGraphics2D sg2d, float x, float y, float width, float height, boolean isfill) { 913 // System.err.println("-- doRect x="+x+" y="+y+" w="+width+" h="+height+" isfill="+isfill+" paint="+sg2d.paint); 914 if ((isfill) && (isCustomPaint(sg2d))) { 915 setupGraphicsState(sg2d, kRect, (int) x, (int) y, (int) width, (int) height); 916 } else { 917 setupGraphicsState(sg2d, kRect, sg2d.font, 0, 0, fBounds.width, fBounds.height); 918 } 919 renderer.doRect(this, x, y, width, height, isfill); 920 } 921 922 public void doRoundRect(CRenderer renderer, SunGraphics2D sg2d, float x, float y, float width, float height, float arcW, float arcH, boolean isfill) { 923 // System.err.println("--- doRoundRect"); 924 if ((isfill) && (isCustomPaint(sg2d))) { 925 setupGraphicsState(sg2d, kRoundRect, (int) x, (int) y, (int) width, (int) height); 926 } else { 927 setupGraphicsState(sg2d, kRoundRect, sg2d.font, 0, 0, fBounds.width, fBounds.height); 928 } 929 renderer.doRoundRect(this, x, y, width, height, arcW, arcH, isfill); 930 } 931 932 public void doOval(CRenderer renderer, SunGraphics2D sg2d, float x, float y, float width, float height, boolean isfill) { 933 // System.err.println("--- doOval"); 934 if ((isfill) && (isCustomPaint(sg2d))) { 935 setupGraphicsState(sg2d, kOval, (int) x, (int) y, (int) width, (int) height); 936 } else { 937 setupGraphicsState(sg2d, kOval, sg2d.font, 0, 0, fBounds.width, fBounds.height); 938 } 939 renderer.doOval(this, x, y, width, height, isfill); 940 } 941 942 public void doArc(CRenderer renderer, SunGraphics2D sg2d, float x, float y, float width, float height, float startAngle, float arcAngle, int type, boolean isfill) { 943 // System.err.println("--- doArc"); 944 if ((isfill) && (isCustomPaint(sg2d))) { 945 setupGraphicsState(sg2d, kArc, (int) x, (int) y, (int) width, (int) height); 946 } else { 947 setupGraphicsState(sg2d, kArc, sg2d.font, 0, 0, fBounds.width, fBounds.height); 948 } 949 950 renderer.doArc(this, x, y, width, height, startAngle, arcAngle, type, isfill); 951 } 952 953 public void doPolygon(CRenderer renderer, SunGraphics2D sg2d, int xpoints[], int ypoints[], int npoints, boolean ispolygon, boolean isfill) { 954 // System.err.println("--- doPolygon"); 955 956 if ((isfill) && (isCustomPaint(sg2d))) { 957 int minx = xpoints[0]; 958 int miny = ypoints[0]; 959 int maxx = minx; 960 int maxy = miny; 961 for (int i = 1; i < npoints; i++) { 962 int x = xpoints[i]; 963 if (x < minx) { 964 minx = x; 965 } else if (x > maxx) { 966 maxx = x; 967 } 968 969 int y = ypoints[i]; 970 if (y < miny) { 971 miny = y; 972 } else if (y > maxy) { 973 maxy = y; 974 } 975 } 976 setupGraphicsState(sg2d, kPolygon, minx, miny, maxx - minx, maxy - miny); 977 } else { 978 setupGraphicsState(sg2d, kPolygon, sg2d.font, 0, 0, fBounds.width, fBounds.height); 979 } 980 renderer.doPoly(this, xpoints, ypoints, npoints, ispolygon, isfill); 981 } 982 983 FloatBuffer shapeCoordinatesArray = null; 984 IntBuffer shapeTypesArray = null; 985 986 public void drawfillShape(CRenderer renderer, SunGraphics2D sg2d, GeneralPath gp, boolean isfill, boolean shouldApplyOffset) { 987 // System.err.println("--- drawfillShape"); 988 989 if ((isfill) && (isCustomPaint(sg2d))) { 990 Rectangle bounds = gp.getBounds(); 991 setupGraphicsState(sg2d, kShape, bounds.x, bounds.y, bounds.width, bounds.height); 992 } else { 993 setupGraphicsState(sg2d, kShape, sg2d.font, 0, 0, fBounds.width, fBounds.height); 994 } 995 996 int shapeLength = getPathLength(gp); 997 998 if ((shapeCoordinatesArray == null) || (shapeCoordinatesArray.capacity() < (shapeLength * 6))) { 999 shapeCoordinatesArray = getBufferOfSize(shapeLength * 6).asFloatBuffer(); // segment can have a max of 6 1000 // coordinates 1001 } 1002 if ((shapeTypesArray == null) || (shapeTypesArray.capacity() < shapeLength)) { 1003 shapeTypesArray = getBufferOfSize(shapeLength).asIntBuffer(); 1004 } 1005 1006 int windingRule = getPathCoordinates(gp, shapeCoordinatesArray, shapeTypesArray); 1007 1008 renderer.doShape(this, shapeLength, shapeCoordinatesArray, shapeTypesArray, windingRule, isfill, shouldApplyOffset); 1009 } 1010 1011 public void blitImage(CRenderer renderer, SunGraphics2D sg2d, SurfaceData img, boolean fliph, boolean flipv, int sx, int sy, int sw, int sh, int dx, int dy, int dw, int dh, Color bgColor) { 1012 // System.err.println("--- blitImage sx="+sx+", sy="+sy+", sw="+sw+", sh="+sh+", img="+img); 1013 OSXOffScreenSurfaceData osxsd = (OSXOffScreenSurfaceData) img; 1014 synchronized (osxsd.getLockObject()) { 1015 int w = osxsd.bim.getWidth(); 1016 int h = osxsd.bim.getHeight(); 1017 1018 // the image itself can have outstanding graphics primitives that might need to be flushed 1019 setupGraphicsState(sg2d, kImage, sg2d.font, 0, 0, fBounds.width, fBounds.height); 1020 1021 // 04/06/04 cmc: radr://3612381 Graphics.drawImage ignores bgcolor parameter 1022 if (bgColor != null) { 1023 img = osxsd.getCopyWithBgColor(bgColor); 1024 } 1025 1026 renderer.doImage(this, img, fliph, flipv, w, h, sx, sy, sw, sh, dx, dy, dw, dh); 1027 } 1028 } 1029 1030 public interface CGContextDrawable { 1031 public void drawIntoCGContext(final long cgContext); 1032 } 1033 1034 public void drawString(CTextPipe renderer, SunGraphics2D sg2d, long nativeStrikePtr, String str, double x, double y) { 1035 // System.err.println("--- drawString str=\""+str+"\""); 1036 // see <rdar://problem/3825795>. We don't want to call anything if the string is empty! 1037 if (str.length() == 0) { return; } 1038 1039 setupGraphicsState(sg2d, kString, sg2d.font, 0, 0, fBounds.width, fBounds.height); 1040 renderer.doDrawString(this, nativeStrikePtr, str, x, y); 1041 } 1042 1043 public void drawGlyphs(CTextPipe renderer, SunGraphics2D sg2d, long nativeStrikePtr, GlyphVector gv, float x, float y) { 1044 // System.err.println("--- drawGlyphs"); 1045 setupGraphicsState(sg2d, kGlyphs, gv.getFont(), 0, 0, fBounds.width, fBounds.height); 1046 renderer.doDrawGlyphs(this, nativeStrikePtr, gv, x, y); 1047 } 1048 1049 public void drawUnicodes(CTextPipe renderer, SunGraphics2D sg2d, long nativeStrikePtr, char unicodes[], int offset, int length, float x, float y) { 1050 // System.err.println("--- drawUnicodes "+(new String(unicodes, offset, length))); 1051 setupGraphicsState(sg2d, kUnicodes, sg2d.font, 0, 0, fBounds.width, fBounds.height); 1052 if (length == 1) { 1053 renderer.doOneUnicode(this, nativeStrikePtr, unicodes[offset], x, y); 1054 } else { 1055 renderer.doUnicodes(this, nativeStrikePtr, unicodes, offset, length, x, y); 1056 } 1057 } 1058 1059 // used by copyArea: 1060 1061 Rectangle srcCopyAreaRect = new Rectangle(); 1062 Rectangle dstCopyAreaRect = new Rectangle(); 1063 Rectangle finalCopyAreaRect = new Rectangle(); 1064 Rectangle copyAreaBounds = new Rectangle(); 1065 1066 void intersection(Rectangle r1, Rectangle r2, Rectangle r3) { 1067 // this code is taken from Rectangle.java (modified to put results in r3) 1068 int tx1 = r1.x; 1069 int ty1 = r1.y; 1070 long tx2 = tx1 + r1.width; 1071 long ty2 = ty1 + r1.height; 1072 1073 int rx1 = r2.x; 1074 int ry1 = r2.y; 1075 long rx2 = rx1 + r2.width; 1076 long ry2 = ry1 + r2.height; 1077 1078 if (tx1 < rx1) tx1 = rx1; 1079 if (ty1 < ry1) ty1 = ry1; 1080 if (tx2 > rx2) tx2 = rx2; 1081 if (ty2 > ry2) ty2 = ry2; 1082 1083 tx2 -= tx1; 1084 ty2 -= ty1; 1085 1086 // tx2,ty2 will never overflow (they will never be 1087 // larger than the smallest of the two source w,h) 1088 // they might underflow, though... 1089 if (tx2 < Integer.MIN_VALUE) tx2 = Integer.MIN_VALUE; 1090 if (ty2 < Integer.MIN_VALUE) ty2 = Integer.MIN_VALUE; 1091 1092 r3.setBounds(tx1, ty1, (int) tx2, (int) ty2); 1093 } 1094 1095 /** 1096 * Clips the copy area to the heavyweight bounds and returns the clipped rectangle. 1097 * The returned clipped rectangle is in the coordinate space of the surface. 1098 */ 1099 protected Rectangle clipCopyArea(SunGraphics2D sg2d, int x, int y, int w, int h, int dx, int dy) { 1100 // we need to clip against the heavyweight bounds 1101 copyAreaBounds.setBounds(sg2d.devClip.getLoX(), sg2d.devClip.getLoY(), sg2d.devClip.getWidth(), sg2d.devClip.getHeight()); 1102 1103 // clip src rect 1104 srcCopyAreaRect.setBounds(x, y, w, h); 1105 intersection(srcCopyAreaRect, copyAreaBounds, srcCopyAreaRect); 1106 if ((srcCopyAreaRect.width <= 0) || (srcCopyAreaRect.height <= 0)) { 1107 // src rect outside bounds 1108 return null; 1109 } 1110 1111 // clip dst rect 1112 dstCopyAreaRect.setBounds(srcCopyAreaRect.x + dx, srcCopyAreaRect.y + dy, srcCopyAreaRect.width, srcCopyAreaRect.height); 1113 intersection(dstCopyAreaRect, copyAreaBounds, dstCopyAreaRect); 1114 if ((dstCopyAreaRect.width <= 0) || (dstCopyAreaRect.height <= 0)) { 1115 // dst rect outside clip 1116 return null; 1117 } 1118 1119 x = dstCopyAreaRect.x - dx; 1120 y = dstCopyAreaRect.y - dy; 1121 w = dstCopyAreaRect.width; 1122 h = dstCopyAreaRect.height; 1123 1124 finalCopyAreaRect.setBounds(x, y, w, h); 1125 1126 return finalCopyAreaRect; 1127 } 1128 1129 // <rdar://3785539> We only need to mark dirty on screen surfaces. This method is 1130 // marked as protected and it is intended for subclasses to override if they need to 1131 // be notified when the surface is dirtied. See CPeerSurfaceData.markDirty() for implementation. 1132 // We don't do anything for buffered images. 1133 protected void markDirty(boolean markAsDirty) { 1134 // do nothing by default 1135 } 1136 1137 // LazyDrawing optimization implementation: 1138 1139 @Override 1140 public boolean canRenderLCDText(SunGraphics2D sg2d) { 1141 if (sg2d.compositeState <= SunGraphics2D.COMP_ISCOPY && 1142 sg2d.paintState <= SunGraphics2D.PAINT_ALPHACOLOR && 1143 sg2d.clipState <= SunGraphics2D.CLIP_RECTANGULAR && 1144 // sg2d.surfaceData.getTransparency() == Transparency.OPAQUE && 1145 // This last test is a workaround until we fix loop selection 1146 // in the pipe validation 1147 sg2d.antialiasHint != SunHints.INTVAL_ANTIALIAS_ON) { return true; } 1148 return false; /* for now - in the future we may want to search */ 1149 } 1150 1151 public static boolean IsSimpleColor(Object c) { 1152 return ((c instanceof Color) || (c instanceof SystemColor) || (c instanceof javax.swing.plaf.ColorUIResource)); 1153 } 1154 1155 static { 1156 if ((kColorPointerIndex % 2) != 0) { 1157 System.err.println("kColorPointerIndex=" + kColorPointerIndex + " is NOT aligned for 64 bit"); 1158 System.exit(0); 1159 } 1160 } 1161 }