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] = sun.awt.image.BufImgSurfaceData.createData(texturePaintImage); 604 605 context.dispose(); 606 607 this.fChangeFlag = (this.fChangeFlag | kColorChangedBit); 608 } else { 609 this.fChangeFlag = (this.fChangeFlag & kColorNotChangedBit); 610 } 611 } 612 lastPaint = sg2d.paint; 613 } 614 615 Composite lastComposite; 616 int lastCompositeAlphaRule = 0; 617 float lastCompositeAlphaValue = 0; 618 619 void setupComposite(SunGraphics2D sg2d) { 620 Composite composite = sg2d.composite; 621 622 if (lastComposite != composite) { 623 lastComposite = composite; 624 625 // For composite state COMP_ISCOPY, COMP_XOR or COMP_CUSTOM set alpha compositor to COPY: 626 int alphaRule = AlphaComposite.SRC_OVER; 627 float alphaValue = 1.0f; 628 629 // For composite state COMP_ISCOPY composite could be null. If it's not (or composite state == COMP_ALPHA) 630 // get alpha compositor's values: 631 if ((sg2d.compositeState <= SunGraphics2D.COMP_ALPHA) && (composite != null)) { 632 AlphaComposite alphaComposite = (AlphaComposite) composite; 633 alphaRule = alphaComposite.getRule(); 634 alphaValue = alphaComposite.getAlpha(); 635 } 636 637 // 2-17-03 VL: [Radar 3174922] 638 // For COMP_XOR and COMP_CUSTOM compositing modes we should be setting alphaRule = AlphaComposite.SRC 639 // which should map to kCGCompositeCopy. 640 641 if ((lastCompositeAlphaRule != alphaRule) || (lastCompositeAlphaValue != alphaValue)) { 642 this.fGraphicsStatesInt.put(kCompositeRuleIndex, alphaRule); 643 this.fGraphicsStatesFloat.put(kCompositeValueIndex, alphaValue); 644 645 lastCompositeAlphaRule = alphaRule; 646 lastCompositeAlphaValue = alphaValue; 647 648 this.fChangeFlag = (this.fChangeFlag | kCompositeChangedBit); 649 } else { 650 this.fChangeFlag = (this.fChangeFlag & kCompositeNotChangedBit); 651 } 652 } else { 653 this.fChangeFlag = (this.fChangeFlag & kCompositeNotChangedBit); 654 } 655 } 656 657 BasicStroke lastStroke = null; 658 static BasicStroke defaultBasicStroke = new BasicStroke(); 659 660 void setupStroke(SunGraphics2D sg2d) { 661 BasicStroke stroke = defaultBasicStroke; 662 663 if (sg2d.stroke instanceof BasicStroke) { 664 stroke = (BasicStroke) sg2d.stroke; 665 } 666 667 if (lastStroke != stroke) { 668 this.fGraphicsStatesObject[kStrokeDashArrayIndex] = stroke.getDashArray(); 669 this.fGraphicsStatesFloat.put(kStrokeDashPhaseIndex, stroke.getDashPhase()); 670 this.fGraphicsStatesInt.put(kStrokeCapIndex, stroke.getEndCap()); 671 this.fGraphicsStatesInt.put(kStrokeJoinIndex, stroke.getLineJoin()); 672 this.fGraphicsStatesFloat.put(kStrokeWidthIndex, stroke.getLineWidth()); 673 this.fGraphicsStatesFloat.put(kStrokeLimitIndex, stroke.getMiterLimit()); 674 675 this.fChangeFlag = (this.fChangeFlag | kStrokeChangedBit); 676 677 lastStroke = stroke; 678 } else { 679 this.fChangeFlag = (this.fChangeFlag & kStrokeNotChangedBit); 680 } 681 } 682 683 Font lastFont; 684 685 void setupFont(Font font, Paint paint) { 686 if (font == null) { return; } 687 688 // We have to setup the kFontPaintIndex if we have changed the color so we added the last 689 // test to see if the color has changed - needed for complex strings 690 // see Radar 3368674 691 if ((font != lastFont) || ((this.fChangeFlag & kColorChangedBit) != 0)) { 692 this.fGraphicsStatesObject[kFontIndex] = font; 693 this.fGraphicsStatesObject[kFontPaintIndex] = paint; 694 695 this.fChangeFlag = (this.fChangeFlag | kFontChangedBit); 696 697 lastFont = font; 698 } else { 699 this.fChangeFlag = (this.fChangeFlag & kFontNotChangedBit); 700 } 701 } 702 703 void setupRenderingHints(SunGraphics2D sg2d) { 704 boolean hintsChanged = false; 705 706 // Significant for draw, fill, text, and image ops: 707 int antialiasHint = sg2d.antialiasHint; 708 if (this.fGraphicsStatesInt.get(kHintsAntialiasIndex) != antialiasHint) { 709 this.fGraphicsStatesInt.put(kHintsAntialiasIndex, antialiasHint); 710 hintsChanged = true; 711 } 712 713 // Significant only for text ops: 714 int textAntialiasHint = sg2d.textAntialiasHint; 715 if (this.fGraphicsStatesInt.get(kHintsTextAntialiasIndex) != textAntialiasHint) { 716 this.fGraphicsStatesInt.put(kHintsTextAntialiasIndex, textAntialiasHint); 717 hintsChanged = true; 718 } 719 720 // Significant only for text ops: 721 int fractionalMetricsHint = sg2d.fractionalMetricsHint; 722 if (this.fGraphicsStatesInt.get(kHintsFractionalMetricsIndex) != fractionalMetricsHint) { 723 this.fGraphicsStatesInt.put(kHintsFractionalMetricsIndex, fractionalMetricsHint); 724 hintsChanged = true; 725 } 726 727 // Significant only for image ops: 728 int renderHint = sg2d.renderHint; 729 if (this.fGraphicsStatesInt.get(kHintsRenderingIndex) != renderHint) { 730 this.fGraphicsStatesInt.put(kHintsRenderingIndex, renderHint); 731 hintsChanged = true; 732 } 733 734 // Significant only for image ops: 735 Object hintValue = sg2d.getRenderingHint(RenderingHints.KEY_INTERPOLATION); 736 int interpolationHint = (hintValue != null ? ((SunHints.Value) hintValue).getIndex() : -1); 737 if (this.fGraphicsStatesInt.get(kHintsInterpolationIndex) != interpolationHint) { 738 this.fGraphicsStatesInt.put(kHintsInterpolationIndex, interpolationHint); 739 hintsChanged = true; 740 } 741 742 if (hintsChanged) { 743 this.fChangeFlag = (this.fChangeFlag | kHintsChangedBit); 744 } else { 745 this.fChangeFlag = (this.fChangeFlag & kHintsNotChangedBit); 746 } 747 } 748 749 SunGraphics2D sg2dCurrent = null; 750 Thread threadCurrent = null; 751 752 void setupGraphicsState(SunGraphics2D sg2d, int primitiveType) { 753 setupGraphicsState(sg2d, primitiveType, sg2d.font, 0, 0, fBounds.width, fBounds.height); // deviceBounds into userBounds 754 } 755 756 void setupGraphicsState(SunGraphics2D sg2d, int primitiveType, int x, int y, int w, int h) { 757 setupGraphicsState(sg2d, primitiveType, sg2d.font, x, y, w, h); 758 } 759 760 // the method below is overriden by CPeerSurface to check the last peer used to draw 761 // if the peer changed we finish lazy drawing 762 void setupGraphicsState(SunGraphics2D sg2d, int primitiveType, Font font, int x, int y, int w, int h) { 763 this.fChangeFlag = 0; 764 765 setUserBounds(sg2d, x, y, w, h); 766 767 Thread thread = Thread.currentThread(); 768 if ((this.sg2dCurrent != sg2d) || (this.threadCurrent != thread)) { 769 this.sg2dCurrent = sg2d; 770 this.threadCurrent = thread; 771 772 setupClip(sg2d); 773 setupTransform(sg2d); 774 setupPaint(sg2d, x, y, w, h); 775 setupComposite(sg2d); 776 setupStroke(sg2d); 777 setupFont(font, sg2d.paint); 778 setupRenderingHints(sg2d); 779 780 this.fChangeFlag = kEverythingChangedFlag; 781 } else { 782 int rendererType = getRendererTypeForPrimitive(primitiveType); 783 784 setupClip(sg2d); 785 setupTransform(sg2d); 786 787 if (rendererType != kCopyArea) { 788 setupComposite(sg2d); 789 setupRenderingHints(sg2d); 790 791 if ((rendererType != kImage)) { 792 setupPaint(sg2d, x, y, w, h); 793 setupStroke(sg2d); 794 } 795 if (rendererType != kPrimitive) { 796 setupFont(font, sg2d.paint); 797 } 798 799 } 800 } 801 802 this.fGraphicsStatesInt.put(kChangeFlagIndex, this.fChangeFlag); 803 } 804 805 boolean isCustomPaint(SunGraphics2D sg2d) { 806 if ((sg2d.paint instanceof Color) || (sg2d.paint instanceof SystemColor) || (sg2d.paint instanceof GradientPaint) || (sg2d.paint instanceof TexturePaint)) { return false; } 807 808 return true; 809 } 810 811 final float[] segmentCoordinatesArray = new float[6]; 812 813 int getPathLength(GeneralPath gp) { 814 int length = 0; 815 816 PathIterator pi = gp.getPathIterator(null); 817 while (pi.isDone() == false) { 818 pi.next(); 819 length++; 820 } 821 822 return length; 823 } 824 825 int getPathCoordinates(GeneralPath gp, FloatBuffer coordinates, IntBuffer types) { 826 // System.err.println("getPathCoordinates"); 827 boolean skip = false; 828 829 coordinates.clear(); 830 types.clear(); 831 832 int type; 833 834 PathIterator pi = gp.getPathIterator(null); 835 while (pi.isDone() == false) { 836 skip = false; 837 type = pi.currentSegment(segmentCoordinatesArray); 838 839 switch (type) { 840 case PathIterator.SEG_MOVETO: 841 // System.err.println(" SEG_MOVETO ("+segmentCoordinatesArray[0]+", "+segmentCoordinatesArray[1]+")"); 842 if (segmentCoordinatesArray[0] < UPPER_BND && segmentCoordinatesArray[0] > LOWER_BND && 843 segmentCoordinatesArray[1] < UPPER_BND && segmentCoordinatesArray[1] > LOWER_BND) { 844 coordinates.put(segmentCoordinatesArray[0]); 845 coordinates.put(segmentCoordinatesArray[1]); 846 } else { 847 skip = true; 848 } 849 break; 850 case PathIterator.SEG_LINETO: 851 // System.err.println(" SEG_LINETO ("+segmentCoordinatesArray[0]+", "+segmentCoordinatesArray[1]+")"); 852 if (segmentCoordinatesArray[0] < UPPER_BND && segmentCoordinatesArray[0] > LOWER_BND && 853 segmentCoordinatesArray[1] < UPPER_BND && segmentCoordinatesArray[1] > LOWER_BND) { 854 coordinates.put(segmentCoordinatesArray[0]); 855 coordinates.put(segmentCoordinatesArray[1]); 856 } else { 857 skip = true; 858 } 859 break; 860 case PathIterator.SEG_QUADTO: 861 // System.err.println(" SEG_QUADTO ("+segmentCoordinatesArray[0]+", "+segmentCoordinatesArray[1]+"), ("+segmentCoordinatesArray[2]+", "+segmentCoordinatesArray[3]+")"); 862 if (segmentCoordinatesArray[0] < UPPER_BND && segmentCoordinatesArray[0] > LOWER_BND && 863 segmentCoordinatesArray[1] < UPPER_BND && segmentCoordinatesArray[1] > LOWER_BND && 864 segmentCoordinatesArray[2] < UPPER_BND && segmentCoordinatesArray[2] > LOWER_BND && 865 segmentCoordinatesArray[3] < UPPER_BND && segmentCoordinatesArray[3] > LOWER_BND) { 866 coordinates.put(segmentCoordinatesArray[0]); 867 coordinates.put(segmentCoordinatesArray[1]); 868 coordinates.put(segmentCoordinatesArray[2]); 869 coordinates.put(segmentCoordinatesArray[3]); 870 } else { 871 skip = true; 872 } 873 break; 874 case PathIterator.SEG_CUBICTO: 875 // System.err.println(" SEG_QUADTO ("+segmentCoordinatesArray[0]+", "+segmentCoordinatesArray[1]+"), ("+segmentCoordinatesArray[2]+", "+segmentCoordinatesArray[3]+"), ("+segmentCoordinatesArray[4]+", "+segmentCoordinatesArray[5]+")"); 876 if (segmentCoordinatesArray[0] < UPPER_BND && segmentCoordinatesArray[0] > LOWER_BND && 877 segmentCoordinatesArray[1] < UPPER_BND && segmentCoordinatesArray[1] > LOWER_BND && 878 segmentCoordinatesArray[2] < UPPER_BND && segmentCoordinatesArray[2] > LOWER_BND && 879 segmentCoordinatesArray[3] < UPPER_BND && segmentCoordinatesArray[3] > LOWER_BND && 880 segmentCoordinatesArray[4] < UPPER_BND && segmentCoordinatesArray[4] > LOWER_BND && 881 segmentCoordinatesArray[5] < UPPER_BND && segmentCoordinatesArray[5] > LOWER_BND) { 882 coordinates.put(segmentCoordinatesArray[0]); 883 coordinates.put(segmentCoordinatesArray[1]); 884 coordinates.put(segmentCoordinatesArray[2]); 885 coordinates.put(segmentCoordinatesArray[3]); 886 coordinates.put(segmentCoordinatesArray[4]); 887 coordinates.put(segmentCoordinatesArray[5]); 888 } else { 889 skip = true; 890 } 891 break; 892 case PathIterator.SEG_CLOSE: 893 // System.err.println(" SEG_CLOSE"); 894 break; 895 } 896 897 if (!skip) { 898 types.put(type); 899 } 900 901 pi.next(); 902 } 903 904 return pi.getWindingRule(); 905 } 906 907 public void doLine(CRenderer renderer, SunGraphics2D sg2d, float x1, float y1, float x2, float y2) { 908 // System.err.println("-- doLine x1="+x1+" y1="+y1+" x2="+x2+" y2="+y2+" paint="+sg2d.paint); 909 setupGraphicsState(sg2d, kLine, sg2d.font, 0, 0, fBounds.width, fBounds.height); 910 renderer.doLine(this, x1, y1, x2, y2); 911 } 912 913 public void doRect(CRenderer renderer, SunGraphics2D sg2d, float x, float y, float width, float height, boolean isfill) { 914 // System.err.println("-- doRect x="+x+" y="+y+" w="+width+" h="+height+" isfill="+isfill+" paint="+sg2d.paint); 915 if ((isfill) && (isCustomPaint(sg2d))) { 916 setupGraphicsState(sg2d, kRect, (int) x, (int) y, (int) width, (int) height); 917 } else { 918 setupGraphicsState(sg2d, kRect, sg2d.font, 0, 0, fBounds.width, fBounds.height); 919 } 920 renderer.doRect(this, x, y, width, height, isfill); 921 } 922 923 public void doRoundRect(CRenderer renderer, SunGraphics2D sg2d, float x, float y, float width, float height, float arcW, float arcH, boolean isfill) { 924 // System.err.println("--- doRoundRect"); 925 if ((isfill) && (isCustomPaint(sg2d))) { 926 setupGraphicsState(sg2d, kRoundRect, (int) x, (int) y, (int) width, (int) height); 927 } else { 928 setupGraphicsState(sg2d, kRoundRect, sg2d.font, 0, 0, fBounds.width, fBounds.height); 929 } 930 renderer.doRoundRect(this, x, y, width, height, arcW, arcH, isfill); 931 } 932 933 public void doOval(CRenderer renderer, SunGraphics2D sg2d, float x, float y, float width, float height, boolean isfill) { 934 // System.err.println("--- doOval"); 935 if ((isfill) && (isCustomPaint(sg2d))) { 936 setupGraphicsState(sg2d, kOval, (int) x, (int) y, (int) width, (int) height); 937 } else { 938 setupGraphicsState(sg2d, kOval, sg2d.font, 0, 0, fBounds.width, fBounds.height); 939 } 940 renderer.doOval(this, x, y, width, height, isfill); 941 } 942 943 public void doArc(CRenderer renderer, SunGraphics2D sg2d, float x, float y, float width, float height, float startAngle, float arcAngle, int type, boolean isfill) { 944 // System.err.println("--- doArc"); 945 if ((isfill) && (isCustomPaint(sg2d))) { 946 setupGraphicsState(sg2d, kArc, (int) x, (int) y, (int) width, (int) height); 947 } else { 948 setupGraphicsState(sg2d, kArc, sg2d.font, 0, 0, fBounds.width, fBounds.height); 949 } 950 951 renderer.doArc(this, x, y, width, height, startAngle, arcAngle, type, isfill); 952 } 953 954 public void doPolygon(CRenderer renderer, SunGraphics2D sg2d, int xpoints[], int ypoints[], int npoints, boolean ispolygon, boolean isfill) { 955 // System.err.println("--- doPolygon"); 956 957 if ((isfill) && (isCustomPaint(sg2d))) { 958 int minx = xpoints[0]; 959 int miny = ypoints[0]; 960 int maxx = minx; 961 int maxy = miny; 962 for (int i = 1; i < npoints; i++) { 963 int x = xpoints[i]; 964 if (x < minx) { 965 minx = x; 966 } else if (x > maxx) { 967 maxx = x; 968 } 969 970 int y = ypoints[i]; 971 if (y < miny) { 972 miny = y; 973 } else if (y > maxy) { 974 maxy = y; 975 } 976 } 977 setupGraphicsState(sg2d, kPolygon, minx, miny, maxx - minx, maxy - miny); 978 } else { 979 setupGraphicsState(sg2d, kPolygon, sg2d.font, 0, 0, fBounds.width, fBounds.height); 980 } 981 renderer.doPoly(this, xpoints, ypoints, npoints, ispolygon, isfill); 982 } 983 984 FloatBuffer shapeCoordinatesArray = null; 985 IntBuffer shapeTypesArray = null; 986 987 public void drawfillShape(CRenderer renderer, SunGraphics2D sg2d, GeneralPath gp, boolean isfill, boolean shouldApplyOffset) { 988 // System.err.println("--- drawfillShape"); 989 990 if ((isfill) && (isCustomPaint(sg2d))) { 991 Rectangle bounds = gp.getBounds(); 992 setupGraphicsState(sg2d, kShape, bounds.x, bounds.y, bounds.width, bounds.height); 993 } else { 994 setupGraphicsState(sg2d, kShape, sg2d.font, 0, 0, fBounds.width, fBounds.height); 995 } 996 997 int shapeLength = getPathLength(gp); 998 999 if ((shapeCoordinatesArray == null) || (shapeCoordinatesArray.capacity() < (shapeLength * 6))) { 1000 shapeCoordinatesArray = getBufferOfSize(shapeLength * 6).asFloatBuffer(); // segment can have a max of 6 1001 // coordinates 1002 } 1003 if ((shapeTypesArray == null) || (shapeTypesArray.capacity() < shapeLength)) { 1004 shapeTypesArray = getBufferOfSize(shapeLength).asIntBuffer(); 1005 } 1006 1007 int windingRule = getPathCoordinates(gp, shapeCoordinatesArray, shapeTypesArray); 1008 1009 renderer.doShape(this, shapeLength, shapeCoordinatesArray, shapeTypesArray, windingRule, isfill, shouldApplyOffset); 1010 } 1011 1012 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) { 1013 // System.err.println("--- blitImage sx="+sx+", sy="+sy+", sw="+sw+", sh="+sh+", img="+img); 1014 OSXOffScreenSurfaceData osxsd = (OSXOffScreenSurfaceData) img; 1015 synchronized (osxsd.getLockObject()) { 1016 int w = osxsd.bim.getWidth(); 1017 int h = osxsd.bim.getHeight(); 1018 1019 // the image itself can have outstanding graphics primitives that might need to be flushed 1020 setupGraphicsState(sg2d, kImage, sg2d.font, 0, 0, fBounds.width, fBounds.height); 1021 1022 // 04/06/04 cmc: radr://3612381 Graphics.drawImage ignores bgcolor parameter 1023 if (bgColor != null) { 1024 img = osxsd.getCopyWithBgColor(bgColor); 1025 } 1026 1027 renderer.doImage(this, img, fliph, flipv, w, h, sx, sy, sw, sh, dx, dy, dw, dh); 1028 } 1029 } 1030 1031 public interface CGContextDrawable { 1032 public void drawIntoCGContext(final long cgContext); 1033 } 1034 1035 public void drawString(CTextPipe renderer, SunGraphics2D sg2d, long nativeStrikePtr, String str, double x, double y) { 1036 // System.err.println("--- drawString str=\""+str+"\""); 1037 // see <rdar://problem/3825795>. We don't want to call anything if the string is empty! 1038 if (str.length() == 0) { return; } 1039 1040 setupGraphicsState(sg2d, kString, sg2d.font, 0, 0, fBounds.width, fBounds.height); 1041 renderer.doDrawString(this, nativeStrikePtr, str, x, y); 1042 } 1043 1044 public void drawGlyphs(CTextPipe renderer, SunGraphics2D sg2d, long nativeStrikePtr, GlyphVector gv, float x, float y) { 1045 // System.err.println("--- drawGlyphs"); 1046 setupGraphicsState(sg2d, kGlyphs, gv.getFont(), 0, 0, fBounds.width, fBounds.height); 1047 renderer.doDrawGlyphs(this, nativeStrikePtr, gv, x, y); 1048 } 1049 1050 public void drawUnicodes(CTextPipe renderer, SunGraphics2D sg2d, long nativeStrikePtr, char unicodes[], int offset, int length, float x, float y) { 1051 // System.err.println("--- drawUnicodes "+(new String(unicodes, offset, length))); 1052 setupGraphicsState(sg2d, kUnicodes, sg2d.font, 0, 0, fBounds.width, fBounds.height); 1053 if (length == 1) { 1054 renderer.doOneUnicode(this, nativeStrikePtr, unicodes[offset], x, y); 1055 } else { 1056 renderer.doUnicodes(this, nativeStrikePtr, unicodes, offset, length, x, y); 1057 } 1058 } 1059 1060 // used by copyArea: 1061 1062 Rectangle srcCopyAreaRect = new Rectangle(); 1063 Rectangle dstCopyAreaRect = new Rectangle(); 1064 Rectangle finalCopyAreaRect = new Rectangle(); 1065 Rectangle copyAreaBounds = new Rectangle(); 1066 1067 void intersection(Rectangle r1, Rectangle r2, Rectangle r3) { 1068 // this code is taken from Rectangle.java (modified to put results in r3) 1069 int tx1 = r1.x; 1070 int ty1 = r1.y; 1071 long tx2 = tx1 + r1.width; 1072 long ty2 = ty1 + r1.height; 1073 1074 int rx1 = r2.x; 1075 int ry1 = r2.y; 1076 long rx2 = rx1 + r2.width; 1077 long ry2 = ry1 + r2.height; 1078 1079 if (tx1 < rx1) tx1 = rx1; 1080 if (ty1 < ry1) ty1 = ry1; 1081 if (tx2 > rx2) tx2 = rx2; 1082 if (ty2 > ry2) ty2 = ry2; 1083 1084 tx2 -= tx1; 1085 ty2 -= ty1; 1086 1087 // tx2,ty2 will never overflow (they will never be 1088 // larger than the smallest of the two source w,h) 1089 // they might underflow, though... 1090 if (tx2 < Integer.MIN_VALUE) tx2 = Integer.MIN_VALUE; 1091 if (ty2 < Integer.MIN_VALUE) ty2 = Integer.MIN_VALUE; 1092 1093 r3.setBounds(tx1, ty1, (int) tx2, (int) ty2); 1094 } 1095 1096 /** 1097 * Clips the copy area to the heavywieght bounds and returns the cliped rectangle. 1098 * The returned clipped rectangle is in the coordinate space of the surface. 1099 */ 1100 protected Rectangle clipCopyArea(SunGraphics2D sg2d, int x, int y, int w, int h, int dx, int dy) { 1101 // we need to clip against the heavyweight bounds 1102 copyAreaBounds.setBounds(sg2d.devClip.getLoX(), sg2d.devClip.getLoY(), sg2d.devClip.getWidth(), sg2d.devClip.getHeight()); 1103 1104 // clip src rect 1105 srcCopyAreaRect.setBounds(x, y, w, h); 1106 intersection(srcCopyAreaRect, copyAreaBounds, srcCopyAreaRect); 1107 if ((srcCopyAreaRect.width <= 0) || (srcCopyAreaRect.height <= 0)) { 1108 // src rect outside bounds 1109 return null; 1110 } 1111 1112 // clip dst rect 1113 dstCopyAreaRect.setBounds(srcCopyAreaRect.x + dx, srcCopyAreaRect.y + dy, srcCopyAreaRect.width, srcCopyAreaRect.height); 1114 intersection(dstCopyAreaRect, copyAreaBounds, dstCopyAreaRect); 1115 if ((dstCopyAreaRect.width <= 0) || (dstCopyAreaRect.height <= 0)) { 1116 // dst rect outside clip 1117 return null; 1118 } 1119 1120 x = dstCopyAreaRect.x - dx; 1121 y = dstCopyAreaRect.y - dy; 1122 w = dstCopyAreaRect.width; 1123 h = dstCopyAreaRect.height; 1124 1125 finalCopyAreaRect.setBounds(x, y, w, h); 1126 1127 return finalCopyAreaRect; 1128 } 1129 1130 // <rdar://3785539> We only need to mark dirty on screen surfaces. This method is 1131 // marked as protected and it is intended for subclasses to override if they need to 1132 // be notified when the surface is dirtied. See CPeerSurfaceData.markDirty() for implementation. 1133 // We don't do anything for buffered images. 1134 protected void markDirty(boolean markAsDirty) { 1135 // do nothing by default 1136 } 1137 1138 // LazyDrawing optimization implementation: 1139 1140 @Override 1141 public boolean canRenderLCDText(SunGraphics2D sg2d) { 1142 if (sg2d.compositeState <= SunGraphics2D.COMP_ISCOPY && 1143 sg2d.paintState <= SunGraphics2D.PAINT_ALPHACOLOR && 1144 sg2d.clipState <= SunGraphics2D.CLIP_RECTANGULAR && 1145 // sg2d.surfaceData.getTransparency() == Transparency.OPAQUE && 1146 // This last test is a workaround until we fix loop selection 1147 // in the pipe validation 1148 sg2d.antialiasHint != SunHints.INTVAL_ANTIALIAS_ON) { return true; } 1149 return false; /* for now - in the future we may want to search */ 1150 } 1151 1152 public static boolean IsSimpleColor(Object c) { 1153 return ((c instanceof Color) || (c instanceof SystemColor) || (c instanceof javax.swing.plaf.ColorUIResource)); 1154 } 1155 1156 static { 1157 if ((kColorPointerIndex % 2) != 0) { 1158 System.err.println("kColorPointerIndex=" + kColorPointerIndex + " is NOT aligned for 64 bit"); 1159 System.exit(0); 1160 } 1161 } 1162 }