1 /* 2 * Copyright (C) 2010 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.graphics; 18 19 import com.android.ide.common.rendering.api.LayoutLog; 20 import com.android.layoutlib.bridge.Bridge; 21 import com.android.layoutlib.bridge.impl.DelegateManager; 22 import com.android.layoutlib.bridge.impl.GcSnapshot; 23 import com.android.layoutlib.bridge.impl.PorterDuffUtility; 24 import com.android.tools.layoutlib.annotations.LayoutlibDelegate; 25 26 import android.graphics.Bitmap.Config; 27 import android.text.TextUtils; 28 29 import java.awt.Color; 30 import java.awt.Composite; 31 import java.awt.Graphics2D; 32 import java.awt.Rectangle; 33 import java.awt.RenderingHints; 34 import java.awt.Shape; 35 import java.awt.geom.AffineTransform; 36 import java.awt.geom.Arc2D; 37 import java.awt.image.BufferedImage; 38 39 40 /** 41 * Delegate implementing the native methods of android.graphics.Canvas 42 * 43 * Through the layoutlib_create tool, the original native methods of Canvas have been replaced 44 * by calls to methods of the same name in this delegate class. 45 * 46 * This class behaves like the original native implementation, but in Java, keeping previously 47 * native data into its own objects and mapping them to int that are sent back and forth between 48 * it and the original Canvas class. 49 * 50 * @see DelegateManager 51 * 52 */ 53 public final class Canvas_Delegate { 54 55 // ---- delegate manager ---- 56 private static final DelegateManager<Canvas_Delegate> sManager = 57 new DelegateManager<Canvas_Delegate>(Canvas_Delegate.class); 58 59 60 // ---- delegate helper data ---- 61 62 private final static boolean[] sBoolOut = new boolean[1]; 63 64 65 // ---- delegate data ---- 66 private Bitmap_Delegate mBitmap; 67 private GcSnapshot mSnapshot; 68 69 private DrawFilter_Delegate mDrawFilter = null; 70 71 72 // ---- Public Helper methods ---- 73 74 /** 75 * Returns the native delegate associated to a given {@link Canvas} object. 76 */ getDelegate(Canvas canvas)77 public static Canvas_Delegate getDelegate(Canvas canvas) { 78 return sManager.getDelegate(canvas.getNativeCanvasWrapper()); 79 } 80 81 /** 82 * Returns the native delegate associated to a given an int referencing a {@link Canvas} object. 83 */ getDelegate(long native_canvas)84 public static Canvas_Delegate getDelegate(long native_canvas) { 85 return sManager.getDelegate(native_canvas); 86 } 87 88 /** 89 * Returns the current {@link Graphics2D} used to draw. 90 */ getSnapshot()91 public GcSnapshot getSnapshot() { 92 return mSnapshot; 93 } 94 95 /** 96 * Returns the {@link DrawFilter} delegate or null if none have been set. 97 * 98 * @return the delegate or null. 99 */ getDrawFilter()100 public DrawFilter_Delegate getDrawFilter() { 101 return mDrawFilter; 102 } 103 104 // ---- native methods ---- 105 106 @LayoutlibDelegate freeCaches()107 /*package*/ static void freeCaches() { 108 // nothing to be done here. 109 } 110 111 @LayoutlibDelegate freeTextLayoutCaches()112 /*package*/ static void freeTextLayoutCaches() { 113 // nothing to be done here yet. 114 } 115 116 @LayoutlibDelegate initRaster(long nativeBitmapOrZero)117 /*package*/ static long initRaster(long nativeBitmapOrZero) { 118 if (nativeBitmapOrZero > 0) { 119 // get the Bitmap from the int 120 Bitmap_Delegate bitmapDelegate = Bitmap_Delegate.getDelegate(nativeBitmapOrZero); 121 122 // create a new Canvas_Delegate with the given bitmap and return its new native int. 123 Canvas_Delegate newDelegate = new Canvas_Delegate(bitmapDelegate); 124 125 return sManager.addNewDelegate(newDelegate); 126 } 127 128 // create a new Canvas_Delegate and return its new native int. 129 Canvas_Delegate newDelegate = new Canvas_Delegate(); 130 131 return sManager.addNewDelegate(newDelegate); 132 } 133 134 @LayoutlibDelegate 135 /*package*/ native_setBitmap(long canvas, long bitmap, boolean copyState)136 static void native_setBitmap(long canvas, long bitmap, boolean copyState) { 137 Canvas_Delegate canvasDelegate = sManager.getDelegate(canvas); 138 Bitmap_Delegate bitmapDelegate = Bitmap_Delegate.getDelegate(bitmap); 139 if (canvasDelegate == null || bitmapDelegate==null) { 140 return; 141 } 142 canvasDelegate.mBitmap = bitmapDelegate; 143 canvasDelegate.mSnapshot = GcSnapshot.createDefaultSnapshot(bitmapDelegate); 144 } 145 146 @LayoutlibDelegate native_isOpaque(long nativeCanvas)147 /*package*/ static boolean native_isOpaque(long nativeCanvas) { 148 // get the delegate from the native int. 149 Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas); 150 if (canvasDelegate == null) { 151 return false; 152 } 153 154 return canvasDelegate.mBitmap.getConfig() == Config.RGB_565; 155 } 156 157 @LayoutlibDelegate native_getWidth(long nativeCanvas)158 /*package*/ static int native_getWidth(long nativeCanvas) { 159 // get the delegate from the native int. 160 Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas); 161 if (canvasDelegate == null) { 162 return 0; 163 } 164 165 return canvasDelegate.mBitmap.getImage().getWidth(); 166 } 167 168 @LayoutlibDelegate native_getHeight(long nativeCanvas)169 /*package*/ static int native_getHeight(long nativeCanvas) { 170 // get the delegate from the native int. 171 Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas); 172 if (canvasDelegate == null) { 173 return 0; 174 } 175 176 return canvasDelegate.mBitmap.getImage().getHeight(); 177 } 178 179 @LayoutlibDelegate native_save(long nativeCanvas, int saveFlags)180 /*package*/ static int native_save(long nativeCanvas, int saveFlags) { 181 // get the delegate from the native int. 182 Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas); 183 if (canvasDelegate == null) { 184 return 0; 185 } 186 187 return canvasDelegate.save(saveFlags); 188 } 189 190 @LayoutlibDelegate native_saveLayer(long nativeCanvas, float l, float t, float r, float b, long paint, int layerFlags)191 /*package*/ static int native_saveLayer(long nativeCanvas, float l, 192 float t, float r, float b, 193 long paint, int layerFlags) { 194 // get the delegate from the native int. 195 Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas); 196 if (canvasDelegate == null) { 197 return 0; 198 } 199 200 Paint_Delegate paintDelegate = Paint_Delegate.getDelegate(paint); 201 if (paintDelegate == null) { 202 return 0; 203 } 204 205 return canvasDelegate.saveLayer(new RectF(l, t, r, b), 206 paintDelegate, layerFlags); 207 } 208 209 @LayoutlibDelegate native_saveLayerAlpha(long nativeCanvas, float l, float t, float r, float b, int alpha, int layerFlags)210 /*package*/ static int native_saveLayerAlpha(long nativeCanvas, float l, 211 float t, float r, float b, 212 int alpha, int layerFlags) { 213 // get the delegate from the native int. 214 Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas); 215 if (canvasDelegate == null) { 216 return 0; 217 } 218 219 return canvasDelegate.saveLayerAlpha(new RectF(l, t, r, b), alpha, layerFlags); 220 } 221 222 @LayoutlibDelegate native_restore(long nativeCanvas)223 /*package*/ static void native_restore(long nativeCanvas) { 224 // get the delegate from the native int. 225 Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas); 226 if (canvasDelegate == null) { 227 return; 228 } 229 230 canvasDelegate.restore(); 231 } 232 233 @LayoutlibDelegate native_restoreToCount(long nativeCanvas, int saveCount)234 /*package*/ static void native_restoreToCount(long nativeCanvas, int saveCount) { 235 // get the delegate from the native int. 236 Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas); 237 if (canvasDelegate == null) { 238 return; 239 } 240 241 canvasDelegate.restoreTo(saveCount); 242 } 243 244 @LayoutlibDelegate native_getSaveCount(long nativeCanvas)245 /*package*/ static int native_getSaveCount(long nativeCanvas) { 246 // get the delegate from the native int. 247 Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas); 248 if (canvasDelegate == null) { 249 return 0; 250 } 251 252 return canvasDelegate.getSnapshot().size(); 253 } 254 255 @LayoutlibDelegate native_translate(long nativeCanvas, float dx, float dy)256 /*package*/ static void native_translate(long nativeCanvas, float dx, float dy) { 257 // get the delegate from the native int. 258 Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas); 259 if (canvasDelegate == null) { 260 return; 261 } 262 263 canvasDelegate.getSnapshot().translate(dx, dy); 264 } 265 266 @LayoutlibDelegate native_scale(long nativeCanvas, float sx, float sy)267 /*package*/ static void native_scale(long nativeCanvas, float sx, float sy) { 268 // get the delegate from the native int. 269 Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas); 270 if (canvasDelegate == null) { 271 return; 272 } 273 274 canvasDelegate.getSnapshot().scale(sx, sy); 275 } 276 277 @LayoutlibDelegate native_rotate(long nativeCanvas, float degrees)278 /*package*/ static void native_rotate(long nativeCanvas, float degrees) { 279 // get the delegate from the native int. 280 Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas); 281 if (canvasDelegate == null) { 282 return; 283 } 284 285 canvasDelegate.getSnapshot().rotate(Math.toRadians(degrees)); 286 } 287 288 @LayoutlibDelegate native_skew(long nativeCanvas, float kx, float ky)289 /*package*/ static void native_skew(long nativeCanvas, float kx, float ky) { 290 // get the delegate from the native int. 291 Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas); 292 if (canvasDelegate == null) { 293 return; 294 } 295 296 // get the current top graphics2D object. 297 GcSnapshot g = canvasDelegate.getSnapshot(); 298 299 // get its current matrix 300 AffineTransform currentTx = g.getTransform(); 301 // get the AffineTransform for the given skew. 302 float[] mtx = Matrix_Delegate.getSkew(kx, ky); 303 AffineTransform matrixTx = Matrix_Delegate.getAffineTransform(mtx); 304 305 // combine them so that the given matrix is applied after. 306 currentTx.preConcatenate(matrixTx); 307 308 // give it to the graphics2D as a new matrix replacing all previous transform 309 g.setTransform(currentTx); 310 } 311 312 @LayoutlibDelegate native_concat(long nCanvas, long nMatrix)313 /*package*/ static void native_concat(long nCanvas, long nMatrix) { 314 // get the delegate from the native int. 315 Canvas_Delegate canvasDelegate = sManager.getDelegate(nCanvas); 316 if (canvasDelegate == null) { 317 return; 318 } 319 320 Matrix_Delegate matrixDelegate = Matrix_Delegate.getDelegate(nMatrix); 321 if (matrixDelegate == null) { 322 return; 323 } 324 325 // get the current top graphics2D object. 326 GcSnapshot snapshot = canvasDelegate.getSnapshot(); 327 328 // get its current matrix 329 AffineTransform currentTx = snapshot.getTransform(); 330 // get the AffineTransform of the given matrix 331 AffineTransform matrixTx = matrixDelegate.getAffineTransform(); 332 333 // combine them so that the given matrix is applied after. 334 currentTx.concatenate(matrixTx); 335 336 // give it to the graphics2D as a new matrix replacing all previous transform 337 snapshot.setTransform(currentTx); 338 } 339 340 @LayoutlibDelegate native_setMatrix(long nCanvas, long nMatrix)341 /*package*/ static void native_setMatrix(long nCanvas, long nMatrix) { 342 // get the delegate from the native int. 343 Canvas_Delegate canvasDelegate = sManager.getDelegate(nCanvas); 344 if (canvasDelegate == null) { 345 return; 346 } 347 348 Matrix_Delegate matrixDelegate = Matrix_Delegate.getDelegate(nMatrix); 349 if (matrixDelegate == null) { 350 return; 351 } 352 353 // get the current top graphics2D object. 354 GcSnapshot snapshot = canvasDelegate.getSnapshot(); 355 356 // get the AffineTransform of the given matrix 357 AffineTransform matrixTx = matrixDelegate.getAffineTransform(); 358 359 // give it to the graphics2D as a new matrix replacing all previous transform 360 snapshot.setTransform(matrixTx); 361 362 if (matrixDelegate.hasPerspective()) { 363 assert false; 364 Bridge.getLog().fidelityWarning(LayoutLog.TAG_MATRIX_AFFINE, 365 "android.graphics.Canvas#setMatrix(android.graphics.Matrix) only " + 366 "supports affine transformations.", null, null /*data*/); 367 } 368 } 369 370 @LayoutlibDelegate native_clipRect(long nCanvas, float left, float top, float right, float bottom, int regionOp)371 /*package*/ static boolean native_clipRect(long nCanvas, 372 float left, float top, 373 float right, float bottom, 374 int regionOp) { 375 // get the delegate from the native int. 376 Canvas_Delegate canvasDelegate = sManager.getDelegate(nCanvas); 377 if (canvasDelegate == null) { 378 return false; 379 } 380 381 return canvasDelegate.clipRect(left, top, right, bottom, regionOp); 382 } 383 384 @LayoutlibDelegate native_clipPath(long nativeCanvas, long nativePath, int regionOp)385 /*package*/ static boolean native_clipPath(long nativeCanvas, 386 long nativePath, 387 int regionOp) { 388 Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas); 389 if (canvasDelegate == null) { 390 return true; 391 } 392 393 Path_Delegate pathDelegate = Path_Delegate.getDelegate(nativePath); 394 if (pathDelegate == null) { 395 return true; 396 } 397 398 return canvasDelegate.mSnapshot.clip(pathDelegate.getJavaShape(), regionOp); 399 } 400 401 @LayoutlibDelegate native_clipRegion(long nativeCanvas, long nativeRegion, int regionOp)402 /*package*/ static boolean native_clipRegion(long nativeCanvas, 403 long nativeRegion, 404 int regionOp) { 405 Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas); 406 if (canvasDelegate == null) { 407 return true; 408 } 409 410 Region_Delegate region = Region_Delegate.getDelegate(nativeRegion); 411 if (region == null) { 412 return true; 413 } 414 415 return canvasDelegate.mSnapshot.clip(region.getJavaArea(), regionOp); 416 } 417 418 @LayoutlibDelegate nativeSetDrawFilter(long nativeCanvas, long nativeFilter)419 /*package*/ static void nativeSetDrawFilter(long nativeCanvas, long nativeFilter) { 420 Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas); 421 if (canvasDelegate == null) { 422 return; 423 } 424 425 canvasDelegate.mDrawFilter = DrawFilter_Delegate.getDelegate(nativeFilter); 426 427 if (canvasDelegate.mDrawFilter != null && 428 canvasDelegate.mDrawFilter.isSupported() == false) { 429 Bridge.getLog().fidelityWarning(LayoutLog.TAG_DRAWFILTER, 430 canvasDelegate.mDrawFilter.getSupportMessage(), null, null /*data*/); 431 } 432 } 433 434 @LayoutlibDelegate native_getClipBounds(long nativeCanvas, Rect bounds)435 /*package*/ static boolean native_getClipBounds(long nativeCanvas, 436 Rect bounds) { 437 // get the delegate from the native int. 438 Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas); 439 if (canvasDelegate == null) { 440 return false; 441 } 442 443 Rectangle rect = canvasDelegate.getSnapshot().getClip().getBounds(); 444 if (rect != null && rect.isEmpty() == false) { 445 bounds.left = rect.x; 446 bounds.top = rect.y; 447 bounds.right = rect.x + rect.width; 448 bounds.bottom = rect.y + rect.height; 449 return true; 450 } 451 452 return false; 453 } 454 455 @LayoutlibDelegate native_getCTM(long canvas, long matrix)456 /*package*/ static void native_getCTM(long canvas, long matrix) { 457 // get the delegate from the native int. 458 Canvas_Delegate canvasDelegate = sManager.getDelegate(canvas); 459 if (canvasDelegate == null) { 460 return; 461 } 462 463 Matrix_Delegate matrixDelegate = Matrix_Delegate.getDelegate(matrix); 464 if (matrixDelegate == null) { 465 return; 466 } 467 468 AffineTransform transform = canvasDelegate.getSnapshot().getTransform(); 469 matrixDelegate.set(Matrix_Delegate.makeValues(transform)); 470 } 471 472 @LayoutlibDelegate native_quickReject(long nativeCanvas, long path)473 /*package*/ static boolean native_quickReject(long nativeCanvas, long path) { 474 // FIXME properly implement quickReject 475 return false; 476 } 477 478 @LayoutlibDelegate native_quickReject(long nativeCanvas, float left, float top, float right, float bottom)479 /*package*/ static boolean native_quickReject(long nativeCanvas, 480 float left, float top, 481 float right, float bottom) { 482 // FIXME properly implement quickReject 483 return false; 484 } 485 486 @LayoutlibDelegate native_drawColor(long nativeCanvas, final int color, final int mode)487 /*package*/ static void native_drawColor(long nativeCanvas, final int color, final int mode) { 488 // get the delegate from the native int. 489 Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas); 490 if (canvasDelegate == null) { 491 return; 492 } 493 494 final int w = canvasDelegate.mBitmap.getImage().getWidth(); 495 final int h = canvasDelegate.mBitmap.getImage().getHeight(); 496 draw(nativeCanvas, new GcSnapshot.Drawable() { 497 498 @Override 499 public void draw(Graphics2D graphics, Paint_Delegate paint) { 500 // reset its transform just in case 501 graphics.setTransform(new AffineTransform()); 502 503 // set the color 504 graphics.setColor(new Color(color, true /*alpha*/)); 505 506 Composite composite = PorterDuffUtility.getComposite( 507 PorterDuffUtility.getPorterDuffMode(mode), 0xFF); 508 if (composite != null) { 509 graphics.setComposite(composite); 510 } 511 512 graphics.fillRect(0, 0, w, h); 513 } 514 }); 515 } 516 517 @LayoutlibDelegate native_drawPaint(long nativeCanvas, long paint)518 /*package*/ static void native_drawPaint(long nativeCanvas, long paint) { 519 // FIXME 520 Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED, 521 "Canvas.drawPaint is not supported.", null, null /*data*/); 522 } 523 524 @LayoutlibDelegate native_drawPoint(long nativeCanvas, float x, float y, long nativePaint)525 /*package*/ static void native_drawPoint(long nativeCanvas, float x, float y, 526 long nativePaint) { 527 // FIXME 528 Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED, 529 "Canvas.drawPoint is not supported.", null, null /*data*/); 530 } 531 532 @LayoutlibDelegate native_drawPoints(long nativeCanvas, float[] pts, int offset, int count, long nativePaint)533 /*package*/ static void native_drawPoints(long nativeCanvas, float[] pts, int offset, int count, 534 long nativePaint) { 535 // FIXME 536 Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED, 537 "Canvas.drawPoint is not supported.", null, null /*data*/); 538 } 539 540 @LayoutlibDelegate native_drawLine(long nativeCanvas, final float startX, final float startY, final float stopX, final float stopY, long paint)541 /*package*/ static void native_drawLine(long nativeCanvas, 542 final float startX, final float startY, final float stopX, final float stopY, 543 long paint) { 544 draw(nativeCanvas, paint, false /*compositeOnly*/, false /*forceSrcMode*/, 545 new GcSnapshot.Drawable() { 546 @Override 547 public void draw(Graphics2D graphics, Paint_Delegate paintDelegate) { 548 graphics.drawLine((int)startX, (int)startY, (int)stopX, (int)stopY); 549 } 550 }); 551 } 552 553 @LayoutlibDelegate native_drawLines(long nativeCanvas, final float[] pts, final int offset, final int count, long nativePaint)554 /*package*/ static void native_drawLines(long nativeCanvas, 555 final float[] pts, final int offset, final int count, 556 long nativePaint) { 557 draw(nativeCanvas, nativePaint, false /*compositeOnly*/, 558 false /*forceSrcMode*/, new GcSnapshot.Drawable() { 559 @Override 560 public void draw(Graphics2D graphics, Paint_Delegate paintDelegate) { 561 for (int i = 0; i < count; i += 4) { 562 graphics.drawLine((int) pts[i + offset], (int) pts[i + offset + 1], 563 (int) pts[i + offset + 2], (int) pts[i + offset + 3]); 564 } 565 } 566 }); 567 } 568 569 @LayoutlibDelegate native_drawRect(long nativeCanvas, final float left, final float top, final float right, final float bottom, long paint)570 /*package*/ static void native_drawRect(long nativeCanvas, 571 final float left, final float top, final float right, final float bottom, long paint) { 572 573 draw(nativeCanvas, paint, false /*compositeOnly*/, false /*forceSrcMode*/, 574 new GcSnapshot.Drawable() { 575 @Override 576 public void draw(Graphics2D graphics, Paint_Delegate paintDelegate) { 577 int style = paintDelegate.getStyle(); 578 579 // draw 580 if (style == Paint.Style.FILL.nativeInt || 581 style == Paint.Style.FILL_AND_STROKE.nativeInt) { 582 graphics.fillRect((int)left, (int)top, 583 (int)(right-left), (int)(bottom-top)); 584 } 585 586 if (style == Paint.Style.STROKE.nativeInt || 587 style == Paint.Style.FILL_AND_STROKE.nativeInt) { 588 graphics.drawRect((int)left, (int)top, 589 (int)(right-left), (int)(bottom-top)); 590 } 591 } 592 }); 593 } 594 595 @LayoutlibDelegate native_drawOval(long nativeCanvas, final float left, final float top, final float right, final float bottom, long paint)596 /*package*/ static void native_drawOval(long nativeCanvas, final float left, 597 final float top, final float right, final float bottom, long paint) { 598 if (right > left && bottom > top) { 599 draw(nativeCanvas, paint, false /*compositeOnly*/, false /*forceSrcMode*/, 600 new GcSnapshot.Drawable() { 601 @Override 602 public void draw(Graphics2D graphics, Paint_Delegate paintDelegate) { 603 int style = paintDelegate.getStyle(); 604 605 // draw 606 if (style == Paint.Style.FILL.nativeInt || 607 style == Paint.Style.FILL_AND_STROKE.nativeInt) { 608 graphics.fillOval((int)left, (int)top, 609 (int)(right - left), (int)(bottom - top)); 610 } 611 612 if (style == Paint.Style.STROKE.nativeInt || 613 style == Paint.Style.FILL_AND_STROKE.nativeInt) { 614 graphics.drawOval((int)left, (int)top, 615 (int)(right - left), (int)(bottom - top)); 616 } 617 } 618 }); 619 } 620 } 621 622 @LayoutlibDelegate native_drawCircle(long nativeCanvas, float cx, float cy, float radius, long paint)623 /*package*/ static void native_drawCircle(long nativeCanvas, 624 float cx, float cy, float radius, long paint) { 625 native_drawOval(nativeCanvas, 626 cx - radius, cy - radius, cx + radius, cy + radius, 627 paint); 628 } 629 630 @LayoutlibDelegate native_drawArc(long nativeCanvas, final float left, final float top, final float right, final float bottom, final float startAngle, final float sweep, final boolean useCenter, long paint)631 /*package*/ static void native_drawArc(long nativeCanvas, 632 final float left, final float top, final float right, final float bottom, 633 final float startAngle, final float sweep, 634 final boolean useCenter, long paint) { 635 if (right > left && bottom > top) { 636 draw(nativeCanvas, paint, false /*compositeOnly*/, false /*forceSrcMode*/, 637 new GcSnapshot.Drawable() { 638 @Override 639 public void draw(Graphics2D graphics, Paint_Delegate paintDelegate) { 640 int style = paintDelegate.getStyle(); 641 642 Arc2D.Float arc = new Arc2D.Float( 643 left, top, right - left, bottom - top, 644 -startAngle, -sweep, 645 useCenter ? Arc2D.PIE : Arc2D.OPEN); 646 647 // draw 648 if (style == Paint.Style.FILL.nativeInt || 649 style == Paint.Style.FILL_AND_STROKE.nativeInt) { 650 graphics.fill(arc); 651 } 652 653 if (style == Paint.Style.STROKE.nativeInt || 654 style == Paint.Style.FILL_AND_STROKE.nativeInt) { 655 graphics.draw(arc); 656 } 657 } 658 }); 659 } 660 } 661 662 @LayoutlibDelegate native_drawRoundRect(long nativeCanvas, final float left, final float top, final float right, final float bottom, final float rx, final float ry, long paint)663 /*package*/ static void native_drawRoundRect(long nativeCanvas, 664 final float left, final float top, final float right, final float bottom, 665 final float rx, final float ry, long paint) { 666 draw(nativeCanvas, paint, false /*compositeOnly*/, false /*forceSrcMode*/, 667 new GcSnapshot.Drawable() { 668 @Override 669 public void draw(Graphics2D graphics, Paint_Delegate paintDelegate) { 670 int style = paintDelegate.getStyle(); 671 672 // draw 673 if (style == Paint.Style.FILL.nativeInt || 674 style == Paint.Style.FILL_AND_STROKE.nativeInt) { 675 graphics.fillRoundRect( 676 (int)left, (int)top, 677 (int)(right - left), (int)(bottom - top), 678 (int)rx, (int)ry); 679 } 680 681 if (style == Paint.Style.STROKE.nativeInt || 682 style == Paint.Style.FILL_AND_STROKE.nativeInt) { 683 graphics.drawRoundRect( 684 (int)left, (int)top, 685 (int)(right - left), (int)(bottom - top), 686 (int)rx, (int)ry); 687 } 688 } 689 }); 690 } 691 692 @LayoutlibDelegate native_drawPath(long nativeCanvas, long path, long paint)693 /*package*/ static void native_drawPath(long nativeCanvas, long path, long paint) { 694 final Path_Delegate pathDelegate = Path_Delegate.getDelegate(path); 695 if (pathDelegate == null) { 696 return; 697 } 698 699 draw(nativeCanvas, paint, false /*compositeOnly*/, false /*forceSrcMode*/, 700 new GcSnapshot.Drawable() { 701 @Override 702 public void draw(Graphics2D graphics, Paint_Delegate paintDelegate) { 703 Shape shape = pathDelegate.getJavaShape(); 704 int style = paintDelegate.getStyle(); 705 706 if (style == Paint.Style.FILL.nativeInt || 707 style == Paint.Style.FILL_AND_STROKE.nativeInt) { 708 graphics.fill(shape); 709 } 710 711 if (style == Paint.Style.STROKE.nativeInt || 712 style == Paint.Style.FILL_AND_STROKE.nativeInt) { 713 graphics.draw(shape); 714 } 715 } 716 }); 717 } 718 719 @LayoutlibDelegate native_drawBitmap(Canvas thisCanvas, long nativeCanvas, long bitmap, float left, float top, long nativePaintOrZero, int canvasDensity, int screenDensity, int bitmapDensity)720 /*package*/ static void native_drawBitmap(Canvas thisCanvas, long nativeCanvas, long bitmap, 721 float left, float top, 722 long nativePaintOrZero, 723 int canvasDensity, 724 int screenDensity, 725 int bitmapDensity) { 726 // get the delegate from the native int. 727 Bitmap_Delegate bitmapDelegate = Bitmap_Delegate.getDelegate(bitmap); 728 if (bitmapDelegate == null) { 729 return; 730 } 731 732 BufferedImage image = bitmapDelegate.getImage(); 733 float right = left + image.getWidth(); 734 float bottom = top + image.getHeight(); 735 736 drawBitmap(nativeCanvas, bitmapDelegate, nativePaintOrZero, 737 0, 0, image.getWidth(), image.getHeight(), 738 (int)left, (int)top, (int)right, (int)bottom); 739 } 740 741 @LayoutlibDelegate native_drawBitmap(Canvas thisCanvas, long nativeCanvas, long bitmap, float srcLeft, float srcTop, float srcRight, float srcBottom, float dstLeft, float dstTop, float dstRight, float dstBottom, long nativePaintOrZero, int screenDensity, int bitmapDensity)742 /*package*/ static void native_drawBitmap(Canvas thisCanvas, long nativeCanvas, long bitmap, 743 float srcLeft, float srcTop, float srcRight, float srcBottom, 744 float dstLeft, float dstTop, float dstRight, float dstBottom, 745 long nativePaintOrZero, int screenDensity, int bitmapDensity) { 746 // get the delegate from the native int. 747 Bitmap_Delegate bitmapDelegate = Bitmap_Delegate.getDelegate(bitmap); 748 if (bitmapDelegate == null) { 749 return; 750 } 751 752 drawBitmap(nativeCanvas, bitmapDelegate, nativePaintOrZero, 753 (int)srcLeft, (int)srcTop, (int)srcRight, (int)srcBottom, 754 (int)dstLeft, (int)dstTop, (int)dstRight, (int)dstBottom); 755 } 756 757 @LayoutlibDelegate native_drawBitmap(long nativeCanvas, int[] colors, int offset, int stride, final float x, final float y, int width, int height, boolean hasAlpha, long nativePaintOrZero)758 /*package*/ static void native_drawBitmap(long nativeCanvas, int[] colors, 759 int offset, int stride, final float x, 760 final float y, int width, int height, 761 boolean hasAlpha, 762 long nativePaintOrZero) { 763 // create a temp BufferedImage containing the content. 764 final BufferedImage image = new BufferedImage(width, height, 765 hasAlpha ? BufferedImage.TYPE_INT_ARGB : BufferedImage.TYPE_INT_RGB); 766 image.setRGB(0, 0, width, height, colors, offset, stride); 767 768 draw(nativeCanvas, nativePaintOrZero, true /*compositeOnly*/, false /*forceSrcMode*/, 769 new GcSnapshot.Drawable() { 770 @Override 771 public void draw(Graphics2D graphics, Paint_Delegate paint) { 772 if (paint != null && paint.isFilterBitmap()) { 773 graphics.setRenderingHint(RenderingHints.KEY_INTERPOLATION, 774 RenderingHints.VALUE_INTERPOLATION_BILINEAR); 775 } 776 777 graphics.drawImage(image, (int) x, (int) y, null); 778 } 779 }); 780 } 781 782 @LayoutlibDelegate nativeDrawBitmapMatrix(long nCanvas, long nBitmap, long nMatrix, long nPaint)783 /*package*/ static void nativeDrawBitmapMatrix(long nCanvas, long nBitmap, 784 long nMatrix, long nPaint) { 785 // get the delegate from the native int. 786 Canvas_Delegate canvasDelegate = sManager.getDelegate(nCanvas); 787 if (canvasDelegate == null) { 788 return; 789 } 790 791 // get the delegate from the native int, which can be null 792 Paint_Delegate paintDelegate = Paint_Delegate.getDelegate(nPaint); 793 794 // get the delegate from the native int. 795 Bitmap_Delegate bitmapDelegate = Bitmap_Delegate.getDelegate(nBitmap); 796 if (bitmapDelegate == null) { 797 return; 798 } 799 800 final BufferedImage image = getImageToDraw(bitmapDelegate, paintDelegate, sBoolOut); 801 802 Matrix_Delegate matrixDelegate = Matrix_Delegate.getDelegate(nMatrix); 803 if (matrixDelegate == null) { 804 return; 805 } 806 807 final AffineTransform mtx = matrixDelegate.getAffineTransform(); 808 809 canvasDelegate.getSnapshot().draw(new GcSnapshot.Drawable() { 810 @Override 811 public void draw(Graphics2D graphics, Paint_Delegate paint) { 812 if (paint != null && paint.isFilterBitmap()) { 813 graphics.setRenderingHint(RenderingHints.KEY_INTERPOLATION, 814 RenderingHints.VALUE_INTERPOLATION_BILINEAR); 815 } 816 817 //FIXME add support for canvas, screen and bitmap densities. 818 graphics.drawImage(image, mtx, null); 819 } 820 }, paintDelegate, true /*compositeOnly*/, false /*forceSrcMode*/); 821 } 822 823 @LayoutlibDelegate nativeDrawBitmapMesh(long nCanvas, long nBitmap, int meshWidth, int meshHeight, float[] verts, int vertOffset, int[] colors, int colorOffset, long nPaint)824 /*package*/ static void nativeDrawBitmapMesh(long nCanvas, long nBitmap, 825 int meshWidth, int meshHeight, float[] verts, int vertOffset, int[] colors, 826 int colorOffset, long nPaint) { 827 // FIXME 828 Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED, 829 "Canvas.drawBitmapMesh is not supported.", null, null /*data*/); 830 } 831 832 @LayoutlibDelegate nativeDrawVertices(long nCanvas, int mode, int n, float[] verts, int vertOffset, float[] texs, int texOffset, int[] colors, int colorOffset, short[] indices, int indexOffset, int indexCount, long nPaint)833 /*package*/ static void nativeDrawVertices(long nCanvas, int mode, int n, 834 float[] verts, int vertOffset, 835 float[] texs, int texOffset, 836 int[] colors, int colorOffset, 837 short[] indices, int indexOffset, 838 int indexCount, long nPaint) { 839 // FIXME 840 Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED, 841 "Canvas.drawVertices is not supported.", null, null /*data*/); 842 } 843 844 @LayoutlibDelegate native_drawText(long nativeCanvas, char[] text, int index, int count, float startX, float startY, int flags, long paint, long typeface)845 /*package*/ static void native_drawText(long nativeCanvas, char[] text, int index, int count, 846 float startX, float startY, int flags, long paint, long typeface) { 847 drawText(nativeCanvas, text, index, count, startX, startY, flags == Canvas.DIRECTION_RTL, 848 paint, typeface); 849 } 850 851 @LayoutlibDelegate native_drawText(long nativeCanvas, String text, int start, int end, float x, float y, final int flags, long paint, long typeface)852 /*package*/ static void native_drawText(long nativeCanvas, String text, 853 int start, int end, float x, float y, final int flags, long paint, 854 long typeface) { 855 int count = end - start; 856 char[] buffer = TemporaryBuffer.obtain(count); 857 TextUtils.getChars(text, start, end, buffer, 0); 858 859 native_drawText(nativeCanvas, buffer, 0, count, x, y, flags, paint, typeface); 860 } 861 862 @LayoutlibDelegate native_drawTextRun(long nativeCanvas, String text, int start, int end, int contextStart, int contextEnd, float x, float y, boolean isRtl, long paint, long typeface)863 /*package*/ static void native_drawTextRun(long nativeCanvas, String text, 864 int start, int end, int contextStart, int contextEnd, 865 float x, float y, boolean isRtl, long paint, long typeface) { 866 int count = end - start; 867 char[] buffer = TemporaryBuffer.obtain(count); 868 TextUtils.getChars(text, start, end, buffer, 0); 869 870 drawText(nativeCanvas, buffer, 0, count, x, y, isRtl, paint, typeface); 871 } 872 873 @LayoutlibDelegate native_drawTextRun(long nativeCanvas, char[] text, int start, int count, int contextStart, int contextCount, float x, float y, boolean isRtl, long paint, long typeface)874 /*package*/ static void native_drawTextRun(long nativeCanvas, char[] text, 875 int start, int count, int contextStart, int contextCount, 876 float x, float y, boolean isRtl, long paint, long typeface) { 877 drawText(nativeCanvas, text, start, count, x, y, isRtl, paint, typeface); 878 } 879 880 @LayoutlibDelegate native_drawTextOnPath(long nativeCanvas, char[] text, int index, int count, long path, float hOffset, float vOffset, int bidiFlags, long paint, long typeface)881 /*package*/ static void native_drawTextOnPath(long nativeCanvas, 882 char[] text, int index, 883 int count, long path, 884 float hOffset, 885 float vOffset, int bidiFlags, 886 long paint, long typeface) { 887 // FIXME 888 Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED, 889 "Canvas.drawTextOnPath is not supported.", null, null /*data*/); 890 } 891 892 @LayoutlibDelegate native_drawTextOnPath(long nativeCanvas, String text, long path, float hOffset, float vOffset, int bidiFlags, long paint, long typeface)893 /*package*/ static void native_drawTextOnPath(long nativeCanvas, 894 String text, long path, 895 float hOffset, 896 float vOffset, 897 int bidiFlags, long paint, 898 long typeface) { 899 // FIXME 900 Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED, 901 "Canvas.drawTextOnPath is not supported.", null, null /*data*/); 902 } 903 904 @LayoutlibDelegate finalizer(long nativeCanvas)905 /*package*/ static void finalizer(long nativeCanvas) { 906 // get the delegate from the native int so that it can be disposed. 907 Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas); 908 if (canvasDelegate == null) { 909 return; 910 } 911 912 canvasDelegate.dispose(); 913 914 // remove it from the manager. 915 sManager.removeJavaReferenceFor(nativeCanvas); 916 } 917 918 919 // ---- Private delegate/helper methods ---- 920 921 /** 922 * Executes a {@link GcSnapshot.Drawable} with a given canvas and paint. 923 * <p>Note that the drawable may actually be executed several times if there are 924 * layers involved (see {@link #saveLayer(RectF, Paint_Delegate, int)}. 925 */ draw(long nCanvas, long nPaint, boolean compositeOnly, boolean forceSrcMode, GcSnapshot.Drawable drawable)926 private static void draw(long nCanvas, long nPaint, boolean compositeOnly, boolean forceSrcMode, 927 GcSnapshot.Drawable drawable) { 928 // get the delegate from the native int. 929 Canvas_Delegate canvasDelegate = sManager.getDelegate(nCanvas); 930 if (canvasDelegate == null) { 931 return; 932 } 933 934 // get the paint which can be null if nPaint is 0; 935 Paint_Delegate paintDelegate = Paint_Delegate.getDelegate(nPaint); 936 937 canvasDelegate.getSnapshot().draw(drawable, paintDelegate, compositeOnly, forceSrcMode); 938 } 939 940 /** 941 * Executes a {@link GcSnapshot.Drawable} with a given canvas. No paint object will be provided 942 * to {@link GcSnapshot.Drawable#draw(Graphics2D, Paint_Delegate)}. 943 * <p>Note that the drawable may actually be executed several times if there are 944 * layers involved (see {@link #saveLayer(RectF, Paint_Delegate, int)}. 945 */ draw(long nCanvas, GcSnapshot.Drawable drawable)946 private static void draw(long nCanvas, GcSnapshot.Drawable drawable) { 947 // get the delegate from the native int. 948 Canvas_Delegate canvasDelegate = sManager.getDelegate(nCanvas); 949 if (canvasDelegate == null) { 950 return; 951 } 952 953 canvasDelegate.mSnapshot.draw(drawable); 954 } 955 drawText(long nativeCanvas, final char[] text, final int index, final int count, final float startX, final float startY, final boolean isRtl, long paint, final long typeface)956 private static void drawText(long nativeCanvas, final char[] text, final int index, 957 final int count, final float startX, final float startY, final boolean isRtl, 958 long paint, final long typeface) { 959 960 draw(nativeCanvas, paint, false /*compositeOnly*/, false /*forceSrcMode*/, 961 new GcSnapshot.Drawable() { 962 @Override 963 public void draw(Graphics2D graphics, Paint_Delegate paintDelegate) { 964 // WARNING: the logic in this method is similar to Paint_Delegate.measureText. 965 // Any change to this method should be reflected in Paint.measureText 966 967 // assert that the typeface passed is actually the one stored in paint. 968 assert (typeface == paintDelegate.mNativeTypeface); 969 970 // Paint.TextAlign indicates how the text is positioned relative to X. 971 // LEFT is the default and there's nothing to do. 972 float x = startX; 973 int limit = index + count; 974 if (paintDelegate.getTextAlign() != Paint.Align.LEFT.nativeInt) { 975 RectF bounds = paintDelegate.measureText(text, index, count, null, 0, 976 isRtl); 977 float m = bounds.right - bounds.left; 978 if (paintDelegate.getTextAlign() == Paint.Align.CENTER.nativeInt) { 979 x -= m / 2; 980 } else if (paintDelegate.getTextAlign() == Paint.Align.RIGHT.nativeInt) { 981 x -= m; 982 } 983 } 984 985 new BidiRenderer(graphics, paintDelegate, text).setRenderLocation(x, startY) 986 .renderText(index, limit, isRtl, null, 0, true); 987 } 988 }); 989 } 990 Canvas_Delegate(Bitmap_Delegate bitmap)991 private Canvas_Delegate(Bitmap_Delegate bitmap) { 992 mSnapshot = GcSnapshot.createDefaultSnapshot(mBitmap = bitmap); 993 } 994 Canvas_Delegate()995 private Canvas_Delegate() { 996 mSnapshot = GcSnapshot.createDefaultSnapshot(null /*image*/); 997 } 998 999 /** 1000 * Disposes of the {@link Graphics2D} stack. 1001 */ dispose()1002 private void dispose() { 1003 mSnapshot.dispose(); 1004 } 1005 save(int saveFlags)1006 private int save(int saveFlags) { 1007 // get the current save count 1008 int count = mSnapshot.size(); 1009 1010 mSnapshot = mSnapshot.save(saveFlags); 1011 1012 // return the old save count 1013 return count; 1014 } 1015 saveLayerAlpha(RectF rect, int alpha, int saveFlags)1016 private int saveLayerAlpha(RectF rect, int alpha, int saveFlags) { 1017 Paint_Delegate paint = new Paint_Delegate(); 1018 paint.setAlpha(alpha); 1019 return saveLayer(rect, paint, saveFlags); 1020 } 1021 saveLayer(RectF rect, Paint_Delegate paint, int saveFlags)1022 private int saveLayer(RectF rect, Paint_Delegate paint, int saveFlags) { 1023 // get the current save count 1024 int count = mSnapshot.size(); 1025 1026 mSnapshot = mSnapshot.saveLayer(rect, paint, saveFlags); 1027 1028 // return the old save count 1029 return count; 1030 } 1031 1032 /** 1033 * Restores the {@link GcSnapshot} to <var>saveCount</var> 1034 * @param saveCount the saveCount 1035 */ restoreTo(int saveCount)1036 private void restoreTo(int saveCount) { 1037 mSnapshot = mSnapshot.restoreTo(saveCount); 1038 } 1039 1040 /** 1041 * Restores the {@link GcSnapshot} to <var>saveCount</var> 1042 * @param saveCount the saveCount 1043 */ restore()1044 private void restore() { 1045 mSnapshot = mSnapshot.restore(); 1046 } 1047 clipRect(float left, float top, float right, float bottom, int regionOp)1048 private boolean clipRect(float left, float top, float right, float bottom, int regionOp) { 1049 return mSnapshot.clipRect(left, top, right, bottom, regionOp); 1050 } 1051 drawBitmap( long nativeCanvas, Bitmap_Delegate bitmap, long nativePaintOrZero, final int sleft, final int stop, final int sright, final int sbottom, final int dleft, final int dtop, final int dright, final int dbottom)1052 private static void drawBitmap( 1053 long nativeCanvas, 1054 Bitmap_Delegate bitmap, 1055 long nativePaintOrZero, 1056 final int sleft, final int stop, final int sright, final int sbottom, 1057 final int dleft, final int dtop, final int dright, final int dbottom) { 1058 // get the delegate from the native int. 1059 Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas); 1060 if (canvasDelegate == null) { 1061 return; 1062 } 1063 1064 // get the paint, which could be null if the int is 0 1065 Paint_Delegate paintDelegate = Paint_Delegate.getDelegate(nativePaintOrZero); 1066 1067 final BufferedImage image = getImageToDraw(bitmap, paintDelegate, sBoolOut); 1068 1069 draw(nativeCanvas, nativePaintOrZero, true /*compositeOnly*/, sBoolOut[0], 1070 new GcSnapshot.Drawable() { 1071 @Override 1072 public void draw(Graphics2D graphics, Paint_Delegate paint) { 1073 if (paint != null && paint.isFilterBitmap()) { 1074 graphics.setRenderingHint(RenderingHints.KEY_INTERPOLATION, 1075 RenderingHints.VALUE_INTERPOLATION_BILINEAR); 1076 } 1077 1078 //FIXME add support for canvas, screen and bitmap densities. 1079 graphics.drawImage(image, dleft, dtop, dright, dbottom, 1080 sleft, stop, sright, sbottom, null); 1081 } 1082 }); 1083 } 1084 1085 1086 /** 1087 * Returns a BufferedImage ready for drawing, based on the bitmap and paint delegate. 1088 * The image returns, through a 1-size boolean array, whether the drawing code should 1089 * use a SRC composite no matter what the paint says. 1090 * 1091 * @param bitmap the bitmap 1092 * @param paint the paint that will be used to draw 1093 * @param forceSrcMode whether the composite will have to be SRC 1094 * @return the image to draw 1095 */ getImageToDraw(Bitmap_Delegate bitmap, Paint_Delegate paint, boolean[] forceSrcMode)1096 private static BufferedImage getImageToDraw(Bitmap_Delegate bitmap, Paint_Delegate paint, 1097 boolean[] forceSrcMode) { 1098 BufferedImage image = bitmap.getImage(); 1099 forceSrcMode[0] = false; 1100 1101 // if the bitmap config is alpha_8, then we erase all color value from it 1102 // before drawing it. 1103 if (bitmap.getConfig() == Bitmap.Config.ALPHA_8) { 1104 fixAlpha8Bitmap(image); 1105 } else if (bitmap.hasAlpha() == false) { 1106 // hasAlpha is merely a rendering hint. There can in fact be alpha values 1107 // in the bitmap but it should be ignored at drawing time. 1108 // There is two ways to do this: 1109 // - override the composite to be SRC. This can only be used if the composite 1110 // was going to be SRC or SRC_OVER in the first place 1111 // - Create a different bitmap to draw in which all the alpha channel values is set 1112 // to 0xFF. 1113 if (paint != null) { 1114 Xfermode_Delegate xfermodeDelegate = paint.getXfermode(); 1115 if (xfermodeDelegate instanceof PorterDuffXfermode_Delegate) { 1116 PorterDuff.Mode mode = 1117 ((PorterDuffXfermode_Delegate)xfermodeDelegate).getMode(); 1118 1119 forceSrcMode[0] = mode == PorterDuff.Mode.SRC_OVER || 1120 mode == PorterDuff.Mode.SRC; 1121 } 1122 } 1123 1124 // if we can't force SRC mode, then create a temp bitmap of TYPE_RGB 1125 if (forceSrcMode[0] == false) { 1126 image = Bitmap_Delegate.createCopy(image, BufferedImage.TYPE_INT_RGB, 0xFF); 1127 } 1128 } 1129 1130 return image; 1131 } 1132 fixAlpha8Bitmap(final BufferedImage image)1133 private static void fixAlpha8Bitmap(final BufferedImage image) { 1134 int w = image.getWidth(); 1135 int h = image.getHeight(); 1136 int[] argb = new int[w * h]; 1137 image.getRGB(0, 0, image.getWidth(), image.getHeight(), argb, 0, image.getWidth()); 1138 1139 final int length = argb.length; 1140 for (int i = 0 ; i < length; i++) { 1141 argb[i] &= 0xFF000000; 1142 } 1143 image.setRGB(0, 0, w, h, argb, 0, w); 1144 } 1145 } 1146 1147