Canvas_Delegate.java revision a4510a75757b82207f677609b970010f59c774ba
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 17package android.graphics; 18 19import com.android.ide.common.rendering.api.LayoutLog; 20import com.android.layoutlib.bridge.Bridge; 21import com.android.layoutlib.bridge.impl.DelegateManager; 22import com.android.layoutlib.bridge.impl.GcSnapshot; 23import com.android.tools.layoutlib.annotations.LayoutlibDelegate; 24 25import android.graphics.Bitmap.Config; 26import android.graphics.Paint_Delegate.FontInfo; 27import android.text.TextUtils; 28 29import java.awt.Color; 30import java.awt.Composite; 31import java.awt.Graphics2D; 32import java.awt.Rectangle; 33import java.awt.RenderingHints; 34import java.awt.Shape; 35import java.awt.geom.AffineTransform; 36import java.awt.image.BufferedImage; 37import java.util.List; 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 */ 53public 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 // ---- delegate helper data ---- 60 61 private final static boolean[] sBoolOut = new boolean[1]; 62 63 // ---- delegate data ---- 64 private Bitmap_Delegate mBitmap; 65 private GcSnapshot mSnapshot; 66 67 private DrawFilter_Delegate mDrawFilter = null; 68 69 // ---- Public Helper methods ---- 70 71 /** 72 * Returns the native delegate associated to a given {@link Canvas} object. 73 */ 74 public static Canvas_Delegate getDelegate(Canvas canvas) { 75 return sManager.getDelegate(canvas.mNativeCanvas); 76 } 77 78 /** 79 * Returns the native delegate associated to a given an int referencing a {@link Canvas} object. 80 */ 81 public static Canvas_Delegate getDelegate(int native_canvas) { 82 return sManager.getDelegate(native_canvas); 83 } 84 85 /** 86 * Returns the current {@link Graphics2D} used to draw. 87 */ 88 public GcSnapshot getSnapshot() { 89 return mSnapshot; 90 } 91 92 /** 93 * Returns the {@link DrawFilter} delegate or null if none have been set. 94 * 95 * @return the delegate or null. 96 */ 97 public DrawFilter_Delegate getDrawFilter() { 98 return mDrawFilter; 99 } 100 101 // ---- native methods ---- 102 103 @LayoutlibDelegate 104 /*package*/ static boolean isOpaque(Canvas thisCanvas) { 105 // get the delegate from the native int. 106 Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.mNativeCanvas); 107 if (canvasDelegate == null) { 108 return false; 109 } 110 111 return canvasDelegate.mBitmap.getConfig() == Config.RGB_565; 112 } 113 114 @LayoutlibDelegate 115 /*package*/ static int getWidth(Canvas thisCanvas) { 116 // get the delegate from the native int. 117 Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.mNativeCanvas); 118 if (canvasDelegate == null) { 119 return 0; 120 } 121 122 return canvasDelegate.mBitmap.getImage().getWidth(); 123 } 124 125 @LayoutlibDelegate 126 /*package*/ static int getHeight(Canvas thisCanvas) { 127 // get the delegate from the native int. 128 Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.mNativeCanvas); 129 if (canvasDelegate == null) { 130 return 0; 131 } 132 133 return canvasDelegate.mBitmap.getImage().getHeight(); 134 } 135 136 @LayoutlibDelegate 137 /*package*/ static void translate(Canvas thisCanvas, float dx, float dy) { 138 // get the delegate from the native int. 139 Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.mNativeCanvas); 140 if (canvasDelegate == null) { 141 return; 142 } 143 144 canvasDelegate.getSnapshot().translate(dx, dy); 145 } 146 147 @LayoutlibDelegate 148 /*package*/ static void rotate(Canvas thisCanvas, float degrees) { 149 // get the delegate from the native int. 150 Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.mNativeCanvas); 151 if (canvasDelegate == null) { 152 return; 153 } 154 155 canvasDelegate.getSnapshot().rotate(Math.toRadians(degrees)); 156 } 157 158 @LayoutlibDelegate 159 /*package*/ static void scale(Canvas thisCanvas, float sx, float sy) { 160 // get the delegate from the native int. 161 Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.mNativeCanvas); 162 if (canvasDelegate == null) { 163 return; 164 } 165 166 canvasDelegate.getSnapshot().scale(sx, sy); 167 } 168 169 @LayoutlibDelegate 170 /*package*/ static void skew(Canvas thisCanvas, float kx, float ky) { 171 // get the delegate from the native int. 172 Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.mNativeCanvas); 173 if (canvasDelegate == null) { 174 return; 175 } 176 177 // get the current top graphics2D object. 178 GcSnapshot g = canvasDelegate.getSnapshot(); 179 180 // get its current matrix 181 AffineTransform currentTx = g.getTransform(); 182 // get the AffineTransform for the given skew. 183 float[] mtx = Matrix_Delegate.getSkew(kx, ky); 184 AffineTransform matrixTx = Matrix_Delegate.getAffineTransform(mtx); 185 186 // combine them so that the given matrix is applied after. 187 currentTx.preConcatenate(matrixTx); 188 189 // give it to the graphics2D as a new matrix replacing all previous transform 190 g.setTransform(currentTx); 191 } 192 193 @LayoutlibDelegate 194 /*package*/ static boolean clipRect(Canvas thisCanvas, RectF rect) { 195 return clipRect(thisCanvas, rect.left, rect.top, rect.right, rect.bottom); 196 } 197 198 @LayoutlibDelegate 199 /*package*/ static boolean clipRect(Canvas thisCanvas, Rect rect) { 200 return clipRect(thisCanvas, (float) rect.left, (float) rect.top, 201 (float) rect.right, (float) rect.bottom); 202 } 203 204 @LayoutlibDelegate 205 /*package*/ static boolean clipRect(Canvas thisCanvas, float left, float top, float right, 206 float bottom) { 207 // get the delegate from the native int. 208 Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.mNativeCanvas); 209 if (canvasDelegate == null) { 210 return false; 211 } 212 213 return canvasDelegate.clipRect(left, top, right, bottom, Region.Op.INTERSECT.nativeInt); 214 } 215 216 @LayoutlibDelegate 217 /*package*/ static boolean clipRect(Canvas thisCanvas, int left, int top, int right, 218 int bottom) { 219 220 return clipRect(thisCanvas, (float) left, (float) top, (float) right, (float) bottom); 221 } 222 223 @LayoutlibDelegate 224 /*package*/ static int save(Canvas thisCanvas) { 225 return save(thisCanvas, Canvas.MATRIX_SAVE_FLAG | Canvas.CLIP_SAVE_FLAG); 226 } 227 228 @LayoutlibDelegate 229 /*package*/ static int save(Canvas thisCanvas, int saveFlags) { 230 // get the delegate from the native int. 231 Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.mNativeCanvas); 232 if (canvasDelegate == null) { 233 return 0; 234 } 235 236 return canvasDelegate.save(saveFlags); 237 } 238 239 @LayoutlibDelegate 240 /*package*/ static void restore(Canvas thisCanvas) { 241 // get the delegate from the native int. 242 Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.mNativeCanvas); 243 if (canvasDelegate == null) { 244 return; 245 } 246 247 canvasDelegate.restore(); 248 } 249 250 @LayoutlibDelegate 251 /*package*/ static int getSaveCount(Canvas thisCanvas) { 252 // get the delegate from the native int. 253 Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.mNativeCanvas); 254 if (canvasDelegate == null) { 255 return 0; 256 } 257 258 return canvasDelegate.getSnapshot().size(); 259 } 260 261 @LayoutlibDelegate 262 /*package*/ static void restoreToCount(Canvas thisCanvas, int saveCount) { 263 // get the delegate from the native int. 264 Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.mNativeCanvas); 265 if (canvasDelegate == null) { 266 return; 267 } 268 269 canvasDelegate.restoreTo(saveCount); 270 } 271 272 @LayoutlibDelegate 273 /*package*/ static void drawPoints(Canvas thisCanvas, float[] pts, int offset, int count, 274 Paint paint) { 275 // FIXME 276 Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED, 277 "Canvas.drawPoint is not supported.", null, null /*data*/); 278 } 279 280 @LayoutlibDelegate 281 /*package*/ static void drawPoint(Canvas thisCanvas, float x, float y, Paint paint) { 282 // FIXME 283 Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED, 284 "Canvas.drawPoint is not supported.", null, null /*data*/); 285 } 286 287 @LayoutlibDelegate 288 /*package*/ static void drawLines(Canvas thisCanvas, 289 final float[] pts, final int offset, final int count, 290 Paint paint) { 291 draw(thisCanvas.mNativeCanvas, paint.mNativePaint, false /*compositeOnly*/, 292 false /*forceSrcMode*/, new GcSnapshot.Drawable() { 293 public void draw(Graphics2D graphics, Paint_Delegate paint) { 294 for (int i = 0 ; i < count ; i += 4) { 295 graphics.drawLine((int)pts[i + offset], (int)pts[i + offset + 1], 296 (int)pts[i + offset + 2], (int)pts[i + offset + 3]); 297 } 298 } 299 }); 300 } 301 302 @LayoutlibDelegate 303 /*package*/ static void freeCaches() { 304 // nothing to be done here. 305 } 306 307 @LayoutlibDelegate 308 /*package*/ static int initRaster(int nativeBitmapOrZero) { 309 if (nativeBitmapOrZero > 0) { 310 // get the Bitmap from the int 311 Bitmap_Delegate bitmapDelegate = Bitmap_Delegate.getDelegate(nativeBitmapOrZero); 312 313 // create a new Canvas_Delegate with the given bitmap and return its new native int. 314 Canvas_Delegate newDelegate = new Canvas_Delegate(bitmapDelegate); 315 316 return sManager.addNewDelegate(newDelegate); 317 } else { 318 // create a new Canvas_Delegate and return its new native int. 319 Canvas_Delegate newDelegate = new Canvas_Delegate(); 320 321 return sManager.addNewDelegate(newDelegate); 322 } 323 } 324 325 @LayoutlibDelegate 326 /*package*/ static void native_setBitmap(int nativeCanvas, int bitmap) { 327 // get the delegate from the native int. 328 Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas); 329 if (canvasDelegate == null) { 330 return; 331 } 332 333 // get the delegate from the native int. 334 Bitmap_Delegate bitmapDelegate = Bitmap_Delegate.getDelegate(bitmap); 335 if (bitmapDelegate == null) { 336 return; 337 } 338 339 canvasDelegate.setBitmap(bitmapDelegate); 340 } 341 342 @LayoutlibDelegate 343 /*package*/ static int native_saveLayer(int nativeCanvas, RectF bounds, 344 int paint, int layerFlags) { 345 // get the delegate from the native int. 346 Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas); 347 if (canvasDelegate == null) { 348 return 0; 349 } 350 351 Paint_Delegate paintDelegate = Paint_Delegate.getDelegate(paint); 352 if (paintDelegate == null) { 353 return 0; 354 } 355 356 return canvasDelegate.saveLayer(bounds, paintDelegate, layerFlags); 357 } 358 359 @LayoutlibDelegate 360 /*package*/ static int native_saveLayer(int nativeCanvas, float l, 361 float t, float r, float b, 362 int paint, int layerFlags) { 363 // get the delegate from the native int. 364 Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas); 365 if (canvasDelegate == null) { 366 return 0; 367 } 368 369 Paint_Delegate paintDelegate = Paint_Delegate.getDelegate(paint); 370 if (paintDelegate == null) { 371 return 0; 372 } 373 374 return canvasDelegate.saveLayer(new RectF(l, t, r, b), 375 paintDelegate, layerFlags); 376 } 377 378 @LayoutlibDelegate 379 /*package*/ static int native_saveLayerAlpha(int nativeCanvas, 380 RectF bounds, int alpha, 381 int layerFlags) { 382 // get the delegate from the native int. 383 Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas); 384 if (canvasDelegate == null) { 385 return 0; 386 } 387 388 return canvasDelegate.saveLayerAlpha(bounds, alpha, layerFlags); 389 } 390 391 @LayoutlibDelegate 392 /*package*/ static int native_saveLayerAlpha(int nativeCanvas, float l, 393 float t, float r, float b, 394 int alpha, int layerFlags) { 395 // get the delegate from the native int. 396 Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas); 397 if (canvasDelegate == null) { 398 return 0; 399 } 400 401 return canvasDelegate.saveLayerAlpha(new RectF(l, t, r, b), alpha, layerFlags); 402 } 403 404 405 @LayoutlibDelegate 406 /*package*/ static void native_concat(int nCanvas, int nMatrix) { 407 // get the delegate from the native int. 408 Canvas_Delegate canvasDelegate = sManager.getDelegate(nCanvas); 409 if (canvasDelegate == null) { 410 return; 411 } 412 413 Matrix_Delegate matrixDelegate = Matrix_Delegate.getDelegate(nMatrix); 414 if (matrixDelegate == null) { 415 return; 416 } 417 418 // get the current top graphics2D object. 419 GcSnapshot snapshot = canvasDelegate.getSnapshot(); 420 421 // get its current matrix 422 AffineTransform currentTx = snapshot.getTransform(); 423 // get the AffineTransform of the given matrix 424 AffineTransform matrixTx = matrixDelegate.getAffineTransform(); 425 426 // combine them so that the given matrix is applied after. 427 currentTx.preConcatenate(matrixTx); 428 429 // give it to the graphics2D as a new matrix replacing all previous transform 430 snapshot.setTransform(currentTx); 431 } 432 433 @LayoutlibDelegate 434 /*package*/ static void native_setMatrix(int nCanvas, int nMatrix) { 435 // get the delegate from the native int. 436 Canvas_Delegate canvasDelegate = sManager.getDelegate(nCanvas); 437 if (canvasDelegate == null) { 438 return; 439 } 440 441 Matrix_Delegate matrixDelegate = Matrix_Delegate.getDelegate(nMatrix); 442 if (matrixDelegate == null) { 443 return; 444 } 445 446 // get the current top graphics2D object. 447 GcSnapshot snapshot = canvasDelegate.getSnapshot(); 448 449 // get the AffineTransform of the given matrix 450 AffineTransform matrixTx = matrixDelegate.getAffineTransform(); 451 452 // give it to the graphics2D as a new matrix replacing all previous transform 453 snapshot.setTransform(matrixTx); 454 455 if (matrixDelegate.hasPerspective()) { 456 assert false; 457 Bridge.getLog().fidelityWarning(LayoutLog.TAG_MATRIX_AFFINE, 458 "android.graphics.Canvas#setMatrix(android.graphics.Matrix) only " + 459 "supports affine transformations.", null, null /*data*/); 460 } 461 } 462 463 @LayoutlibDelegate 464 /*package*/ static boolean native_clipRect(int nCanvas, 465 float left, float top, 466 float right, float bottom, 467 int regionOp) { 468 469 // get the delegate from the native int. 470 Canvas_Delegate canvasDelegate = sManager.getDelegate(nCanvas); 471 if (canvasDelegate == null) { 472 return false; 473 } 474 475 return canvasDelegate.clipRect(left, top, right, bottom, regionOp); 476 } 477 478 @LayoutlibDelegate 479 /*package*/ static boolean native_clipPath(int nativeCanvas, 480 int nativePath, 481 int regionOp) { 482 Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas); 483 if (canvasDelegate == null) { 484 return true; 485 } 486 487 Path_Delegate pathDelegate = Path_Delegate.getDelegate(nativePath); 488 if (pathDelegate == null) { 489 return true; 490 } 491 492 return canvasDelegate.mSnapshot.clip(pathDelegate.getJavaShape(), regionOp); 493 } 494 495 @LayoutlibDelegate 496 /*package*/ static boolean native_clipRegion(int nativeCanvas, 497 int nativeRegion, 498 int regionOp) { 499 Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas); 500 if (canvasDelegate == null) { 501 return true; 502 } 503 504 Region_Delegate region = Region_Delegate.getDelegate(nativeRegion); 505 if (region == null) { 506 return true; 507 } 508 509 return canvasDelegate.mSnapshot.clip(region.getJavaArea(), regionOp); 510 } 511 512 @LayoutlibDelegate 513 /*package*/ static void nativeSetDrawFilter(int nativeCanvas, int nativeFilter) { 514 Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas); 515 if (canvasDelegate == null) { 516 return; 517 } 518 519 canvasDelegate.mDrawFilter = DrawFilter_Delegate.getDelegate(nativeFilter); 520 521 if (canvasDelegate.mDrawFilter != null && 522 canvasDelegate.mDrawFilter.isSupported() == false) { 523 Bridge.getLog().fidelityWarning(LayoutLog.TAG_DRAWFILTER, 524 canvasDelegate.mDrawFilter.getSupportMessage(), null, null /*data*/); 525 } 526 } 527 528 @LayoutlibDelegate 529 /*package*/ static boolean native_getClipBounds(int nativeCanvas, 530 Rect bounds) { 531 // get the delegate from the native int. 532 Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas); 533 if (canvasDelegate == null) { 534 return false; 535 } 536 537 Rectangle rect = canvasDelegate.getSnapshot().getClip().getBounds(); 538 if (rect != null && rect.isEmpty() == false) { 539 bounds.left = rect.x; 540 bounds.top = rect.y; 541 bounds.right = rect.x + rect.width; 542 bounds.bottom = rect.y + rect.height; 543 return true; 544 } 545 546 return false; 547 } 548 549 @LayoutlibDelegate 550 /*package*/ static void native_getCTM(int canvas, int matrix) { 551 // get the delegate from the native int. 552 Canvas_Delegate canvasDelegate = sManager.getDelegate(canvas); 553 if (canvasDelegate == null) { 554 return; 555 } 556 557 Matrix_Delegate matrixDelegate = Matrix_Delegate.getDelegate(matrix); 558 if (matrixDelegate == null) { 559 return; 560 } 561 562 AffineTransform transform = canvasDelegate.getSnapshot().getTransform(); 563 matrixDelegate.set(Matrix_Delegate.makeValues(transform)); 564 } 565 566 @LayoutlibDelegate 567 /*package*/ static boolean native_quickReject(int nativeCanvas, 568 RectF rect, 569 int native_edgeType) { 570 // FIXME properly implement quickReject 571 return false; 572 } 573 574 @LayoutlibDelegate 575 /*package*/ static boolean native_quickReject(int nativeCanvas, 576 int path, 577 int native_edgeType) { 578 // FIXME properly implement quickReject 579 return false; 580 } 581 582 @LayoutlibDelegate 583 /*package*/ static boolean native_quickReject(int nativeCanvas, 584 float left, float top, 585 float right, float bottom, 586 int native_edgeType) { 587 // FIXME properly implement quickReject 588 return false; 589 } 590 591 @LayoutlibDelegate 592 /*package*/ static void native_drawRGB(int nativeCanvas, int r, int g, int b) { 593 native_drawColor(nativeCanvas, 0xFF000000 | r << 16 | (g&0xFF) << 8 | (b&0xFF), 594 PorterDuff.Mode.SRC_OVER.nativeInt); 595 596 } 597 598 @LayoutlibDelegate 599 /*package*/ static void native_drawARGB(int nativeCanvas, int a, int r, int g, int b) { 600 native_drawColor(nativeCanvas, a << 24 | (r&0xFF) << 16 | (g&0xFF) << 8 | (b&0xFF), 601 PorterDuff.Mode.SRC_OVER.nativeInt); 602 } 603 604 @LayoutlibDelegate 605 /*package*/ static void native_drawColor(int nativeCanvas, int color) { 606 native_drawColor(nativeCanvas, color, PorterDuff.Mode.SRC_OVER.nativeInt); 607 } 608 609 @LayoutlibDelegate 610 /*package*/ static void native_drawColor(int nativeCanvas, final int color, final int mode) { 611 // get the delegate from the native int. 612 Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas); 613 if (canvasDelegate == null) { 614 return; 615 } 616 617 final int w = canvasDelegate.mBitmap.getImage().getWidth(); 618 final int h = canvasDelegate.mBitmap.getImage().getHeight(); 619 draw(nativeCanvas, new GcSnapshot.Drawable() { 620 621 public void draw(Graphics2D graphics, Paint_Delegate paint) { 622 // reset its transform just in case 623 graphics.setTransform(new AffineTransform()); 624 625 // set the color 626 graphics.setColor(new Color(color, true /*alpha*/)); 627 628 Composite composite = PorterDuffXfermode_Delegate.getComposite( 629 PorterDuffXfermode_Delegate.getPorterDuffMode(mode), 0xFF); 630 if (composite != null) { 631 graphics.setComposite(composite); 632 } 633 634 graphics.fillRect(0, 0, w, h); 635 } 636 }); 637 } 638 639 @LayoutlibDelegate 640 /*package*/ static void native_drawPaint(int nativeCanvas, int paint) { 641 // FIXME 642 Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED, 643 "Canvas.drawPaint is not supported.", null, null /*data*/); 644 } 645 646 @LayoutlibDelegate 647 /*package*/ static void native_drawLine(int nativeCanvas, 648 final float startX, final float startY, final float stopX, final float stopY, 649 int paint) { 650 651 draw(nativeCanvas, paint, false /*compositeOnly*/, false /*forceSrcMode*/, 652 new GcSnapshot.Drawable() { 653 public void draw(Graphics2D graphics, Paint_Delegate paint) { 654 graphics.drawLine((int)startX, (int)startY, (int)stopX, (int)stopY); 655 } 656 }); 657 } 658 659 @LayoutlibDelegate 660 /*package*/ static void native_drawRect(int nativeCanvas, RectF rect, 661 int paint) { 662 native_drawRect(nativeCanvas, rect.left, rect.top, rect.right, rect.bottom, paint); 663 } 664 665 @LayoutlibDelegate 666 /*package*/ static void native_drawRect(int nativeCanvas, 667 final float left, final float top, final float right, final float bottom, int paint) { 668 669 draw(nativeCanvas, paint, false /*compositeOnly*/, false /*forceSrcMode*/, 670 new GcSnapshot.Drawable() { 671 public void draw(Graphics2D graphics, Paint_Delegate paint) { 672 int style = paint.getStyle(); 673 674 // draw 675 if (style == Paint.Style.FILL.nativeInt || 676 style == Paint.Style.FILL_AND_STROKE.nativeInt) { 677 graphics.fillRect((int)left, (int)top, 678 (int)(right-left), (int)(bottom-top)); 679 } 680 681 if (style == Paint.Style.STROKE.nativeInt || 682 style == Paint.Style.FILL_AND_STROKE.nativeInt) { 683 graphics.drawRect((int)left, (int)top, 684 (int)(right-left), (int)(bottom-top)); 685 } 686 } 687 }); 688 } 689 690 @LayoutlibDelegate 691 /*package*/ static void native_drawOval(int nativeCanvas, final RectF oval, int paint) { 692 if (oval.right > oval.left && oval.bottom > oval.top) { 693 draw(nativeCanvas, paint, false /*compositeOnly*/, false /*forceSrcMode*/, 694 new GcSnapshot.Drawable() { 695 public void draw(Graphics2D graphics, Paint_Delegate paint) { 696 int style = paint.getStyle(); 697 698 // draw 699 if (style == Paint.Style.FILL.nativeInt || 700 style == Paint.Style.FILL_AND_STROKE.nativeInt) { 701 graphics.fillOval((int)oval.left, (int)oval.top, 702 (int)oval.width(), (int)oval.height()); 703 } 704 705 if (style == Paint.Style.STROKE.nativeInt || 706 style == Paint.Style.FILL_AND_STROKE.nativeInt) { 707 graphics.drawOval((int)oval.left, (int)oval.top, 708 (int)oval.width(), (int)oval.height()); 709 } 710 } 711 }); 712 } 713 } 714 715 @LayoutlibDelegate 716 /*package*/ static void native_drawCircle(int nativeCanvas, 717 float cx, float cy, float radius, int paint) { 718 native_drawOval(nativeCanvas, 719 new RectF(cx - radius, cy - radius, radius*2, radius*2), 720 paint); 721 } 722 723 @LayoutlibDelegate 724 /*package*/ static void native_drawArc(int nativeCanvas, 725 RectF oval, float startAngle, float sweep, boolean useCenter, int paint) { 726 // FIXME 727 Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED, 728 "Canvas.drawArc is not supported.", null, null /*data*/); 729 } 730 731 @LayoutlibDelegate 732 /*package*/ static void native_drawRoundRect(int nativeCanvas, 733 final RectF rect, final float rx, final float ry, int paint) { 734 735 draw(nativeCanvas, paint, false /*compositeOnly*/, false /*forceSrcMode*/, 736 new GcSnapshot.Drawable() { 737 public void draw(Graphics2D graphics, Paint_Delegate paint) { 738 int style = paint.getStyle(); 739 740 // draw 741 if (style == Paint.Style.FILL.nativeInt || 742 style == Paint.Style.FILL_AND_STROKE.nativeInt) { 743 graphics.fillRoundRect( 744 (int)rect.left, (int)rect.top, 745 (int)rect.width(), (int)rect.height(), 746 (int)rx, (int)ry); 747 } 748 749 if (style == Paint.Style.STROKE.nativeInt || 750 style == Paint.Style.FILL_AND_STROKE.nativeInt) { 751 graphics.drawRoundRect( 752 (int)rect.left, (int)rect.top, 753 (int)rect.width(), (int)rect.height(), 754 (int)rx, (int)ry); 755 } 756 } 757 }); 758 } 759 760 @LayoutlibDelegate 761 /*package*/ static void native_drawPath(int nativeCanvas, int path, int paint) { 762 final Path_Delegate pathDelegate = Path_Delegate.getDelegate(path); 763 if (pathDelegate == null) { 764 return; 765 } 766 767 draw(nativeCanvas, paint, false /*compositeOnly*/, false /*forceSrcMode*/, 768 new GcSnapshot.Drawable() { 769 public void draw(Graphics2D graphics, Paint_Delegate paint) { 770 Shape shape = pathDelegate.getJavaShape(); 771 int style = paint.getStyle(); 772 773 if (style == Paint.Style.FILL.nativeInt || 774 style == Paint.Style.FILL_AND_STROKE.nativeInt) { 775 graphics.fill(shape); 776 } 777 778 if (style == Paint.Style.STROKE.nativeInt || 779 style == Paint.Style.FILL_AND_STROKE.nativeInt) { 780 graphics.draw(shape); 781 } 782 } 783 }); 784 } 785 786 @LayoutlibDelegate 787 /*package*/ static void native_drawBitmap(Canvas thisCanvas, int nativeCanvas, int bitmap, 788 float left, float top, 789 int nativePaintOrZero, 790 int canvasDensity, 791 int screenDensity, 792 int bitmapDensity) { 793 // get the delegate from the native int. 794 Bitmap_Delegate bitmapDelegate = Bitmap_Delegate.getDelegate(bitmap); 795 if (bitmapDelegate == null) { 796 return; 797 } 798 799 BufferedImage image = bitmapDelegate.getImage(); 800 float right = left + image.getWidth(); 801 float bottom = top + image.getHeight(); 802 803 drawBitmap(nativeCanvas, bitmapDelegate, nativePaintOrZero, 804 0, 0, image.getWidth(), image.getHeight(), 805 (int)left, (int)top, (int)right, (int)bottom); 806 } 807 808 @LayoutlibDelegate 809 /*package*/ static void native_drawBitmap(Canvas thisCanvas, int nativeCanvas, int bitmap, 810 Rect src, RectF dst, 811 int nativePaintOrZero, 812 int screenDensity, 813 int bitmapDensity) { 814 // get the delegate from the native int. 815 Bitmap_Delegate bitmapDelegate = Bitmap_Delegate.getDelegate(bitmap); 816 if (bitmapDelegate == null) { 817 return; 818 } 819 820 BufferedImage image = bitmapDelegate.getImage(); 821 822 if (src == null) { 823 drawBitmap(nativeCanvas, bitmapDelegate, nativePaintOrZero, 824 0, 0, image.getWidth(), image.getHeight(), 825 (int)dst.left, (int)dst.top, (int)dst.right, (int)dst.bottom); 826 } else { 827 drawBitmap(nativeCanvas, bitmapDelegate, nativePaintOrZero, 828 src.left, src.top, src.width(), src.height(), 829 (int)dst.left, (int)dst.top, (int)dst.right, (int)dst.bottom); 830 } 831 } 832 833 @LayoutlibDelegate 834 /*package*/ static void native_drawBitmap(int nativeCanvas, int bitmap, 835 Rect src, Rect dst, 836 int nativePaintOrZero, 837 int screenDensity, 838 int bitmapDensity) { 839 // get the delegate from the native int. 840 Bitmap_Delegate bitmapDelegate = Bitmap_Delegate.getDelegate(bitmap); 841 if (bitmapDelegate == null) { 842 return; 843 } 844 845 BufferedImage image = bitmapDelegate.getImage(); 846 847 if (src == null) { 848 drawBitmap(nativeCanvas, bitmapDelegate, nativePaintOrZero, 849 0, 0, image.getWidth(), image.getHeight(), 850 dst.left, dst.top, dst.right, dst.bottom); 851 } else { 852 drawBitmap(nativeCanvas, bitmapDelegate, nativePaintOrZero, 853 src.left, src.top, src.width(), src.height(), 854 dst.left, dst.top, dst.right, dst.bottom); 855 } 856 } 857 858 @LayoutlibDelegate 859 /*package*/ static void native_drawBitmap(int nativeCanvas, int[] colors, 860 int offset, int stride, final float x, 861 final float y, int width, int height, 862 boolean hasAlpha, 863 int nativePaintOrZero) { 864 865 // create a temp BufferedImage containing the content. 866 final BufferedImage image = new BufferedImage(width, height, 867 hasAlpha ? BufferedImage.TYPE_INT_ARGB : BufferedImage.TYPE_INT_RGB); 868 image.setRGB(0, 0, width, height, colors, offset, stride); 869 870 draw(nativeCanvas, nativePaintOrZero, true /*compositeOnly*/, false /*forceSrcMode*/, 871 new GcSnapshot.Drawable() { 872 public void draw(Graphics2D graphics, Paint_Delegate paint) { 873 if (paint != null && paint.isFilterBitmap()) { 874 graphics.setRenderingHint(RenderingHints.KEY_INTERPOLATION, 875 RenderingHints.VALUE_INTERPOLATION_BILINEAR); 876 } 877 878 graphics.drawImage(image, (int) x, (int) y, null); 879 } 880 }); 881 } 882 883 @LayoutlibDelegate 884 /*package*/ static void nativeDrawBitmapMatrix(int nCanvas, int nBitmap, 885 int nMatrix, int nPaint) { 886 // get the delegate from the native int. 887 Canvas_Delegate canvasDelegate = sManager.getDelegate(nCanvas); 888 if (canvasDelegate == null) { 889 return; 890 } 891 892 // get the delegate from the native int, which can be null 893 Paint_Delegate paintDelegate = Paint_Delegate.getDelegate(nPaint); 894 895 // get the delegate from the native int. 896 Bitmap_Delegate bitmapDelegate = Bitmap_Delegate.getDelegate(nBitmap); 897 if (bitmapDelegate == null) { 898 return; 899 } 900 901 final BufferedImage image = getImageToDraw(bitmapDelegate, paintDelegate, sBoolOut); 902 903 Matrix_Delegate matrixDelegate = Matrix_Delegate.getDelegate(nMatrix); 904 if (matrixDelegate == null) { 905 return; 906 } 907 908 final AffineTransform mtx = matrixDelegate.getAffineTransform(); 909 910 canvasDelegate.getSnapshot().draw(new GcSnapshot.Drawable() { 911 public void draw(Graphics2D graphics, Paint_Delegate paint) { 912 if (paint != null && paint.isFilterBitmap()) { 913 graphics.setRenderingHint(RenderingHints.KEY_INTERPOLATION, 914 RenderingHints.VALUE_INTERPOLATION_BILINEAR); 915 } 916 917 //FIXME add support for canvas, screen and bitmap densities. 918 graphics.drawImage(image, mtx, null); 919 } 920 }, paintDelegate, true /*compositeOnly*/, false /*forceSrcMode*/); 921 } 922 923 @LayoutlibDelegate 924 /*package*/ static void nativeDrawBitmapMesh(int nCanvas, int nBitmap, 925 int meshWidth, int meshHeight, float[] verts, int vertOffset, int[] colors, 926 int colorOffset, int nPaint) { 927 // FIXME 928 Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED, 929 "Canvas.drawBitmapMesh is not supported.", null, null /*data*/); 930 } 931 932 @LayoutlibDelegate 933 /*package*/ static void nativeDrawVertices(int nCanvas, int mode, int n, 934 float[] verts, int vertOffset, 935 float[] texs, int texOffset, 936 int[] colors, int colorOffset, 937 short[] indices, int indexOffset, 938 int indexCount, int nPaint) { 939 // FIXME 940 Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED, 941 "Canvas.drawVertices is not supported.", null, null /*data*/); 942 } 943 944 @LayoutlibDelegate 945 /*package*/ static void native_drawText(int nativeCanvas, 946 final char[] text, final int index, final int count, 947 final float startX, final float startY, int flags, int paint) { 948 draw(nativeCanvas, paint, false /*compositeOnly*/, false /*forceSrcMode*/, 949 new GcSnapshot.Drawable() { 950 public void draw(Graphics2D graphics, Paint_Delegate paint) { 951 // WARNING: the logic in this method is similar to Paint_Delegate.measureText. 952 // Any change to this method should be reflected in Paint.measureText 953 // Paint.TextAlign indicates how the text is positioned relative to X. 954 // LEFT is the default and there's nothing to do. 955 float x = startX; 956 float y = startY; 957 if (paint.getTextAlign() != Paint.Align.LEFT.nativeInt) { 958 float m = paint.measureText(text, index, count); 959 if (paint.getTextAlign() == Paint.Align.CENTER.nativeInt) { 960 x -= m / 2; 961 } else if (paint.getTextAlign() == Paint.Align.RIGHT.nativeInt) { 962 x -= m; 963 } 964 } 965 966 List<FontInfo> fonts = paint.getFonts(); 967 968 if (fonts.size() > 0) { 969 FontInfo mainFont = fonts.get(0); 970 int i = index; 971 int lastIndex = index + count; 972 while (i < lastIndex) { 973 // always start with the main font. 974 int upTo = mainFont.mFont.canDisplayUpTo(text, i, lastIndex); 975 if (upTo == -1) { 976 // draw all the rest and exit. 977 graphics.setFont(mainFont.mFont); 978 graphics.drawChars(text, i, lastIndex - i, (int)x, (int)y); 979 return; 980 } else if (upTo > 0) { 981 // draw what's possible 982 graphics.setFont(mainFont.mFont); 983 graphics.drawChars(text, i, upTo - i, (int)x, (int)y); 984 985 // compute the width that was drawn to increase x 986 x += mainFont.mMetrics.charsWidth(text, i, upTo - i); 987 988 // move index to the first non displayed char. 989 i = upTo; 990 991 // don't call continue at this point. Since it is certain the main font 992 // cannot display the font a index upTo (now ==i), we move on to the 993 // fallback fonts directly. 994 } 995 996 // no char supported, attempt to read the next char(s) with the 997 // fallback font. In this case we only test the first character 998 // and then go back to test with the main font. 999 // Special test for 2-char characters. 1000 boolean foundFont = false; 1001 for (int f = 1 ; f < fonts.size() ; f++) { 1002 FontInfo fontInfo = fonts.get(f); 1003 1004 // need to check that the font can display the character. We test 1005 // differently if the char is a high surrogate. 1006 int charCount = Character.isHighSurrogate(text[i]) ? 2 : 1; 1007 upTo = fontInfo.mFont.canDisplayUpTo(text, i, i + charCount); 1008 if (upTo == -1) { 1009 // draw that char 1010 graphics.setFont(fontInfo.mFont); 1011 graphics.drawChars(text, i, charCount, (int)x, (int)y); 1012 1013 // update x 1014 x += fontInfo.mMetrics.charsWidth(text, i, charCount); 1015 1016 // update the index in the text, and move on 1017 i += charCount; 1018 foundFont = true; 1019 break; 1020 1021 } 1022 } 1023 1024 // in case no font can display the char, display it with the main font. 1025 // (it'll put a square probably) 1026 if (foundFont == false) { 1027 int charCount = Character.isHighSurrogate(text[i]) ? 2 : 1; 1028 1029 graphics.setFont(mainFont.mFont); 1030 graphics.drawChars(text, i, charCount, (int)x, (int)y); 1031 1032 // measure it to advance x 1033 x += mainFont.mMetrics.charsWidth(text, i, charCount); 1034 1035 // and move to the next chars. 1036 i += charCount; 1037 } 1038 } 1039 } 1040 } 1041 }); 1042 } 1043 1044 @LayoutlibDelegate 1045 /*package*/ static void native_drawText(int nativeCanvas, String text, 1046 int start, int end, float x, float y, int flags, int paint) { 1047 int count = end - start; 1048 char[] buffer = TemporaryBuffer.obtain(count); 1049 TextUtils.getChars(text, start, end, buffer, 0); 1050 1051 native_drawText(nativeCanvas, buffer, 0, count, x, y, flags, paint); 1052 } 1053 1054 @LayoutlibDelegate 1055 /*package*/ static void native_drawTextRun(int nativeCanvas, String text, 1056 int start, int end, int contextStart, int contextEnd, 1057 float x, float y, int flags, int paint) { 1058 int count = end - start; 1059 char[] buffer = TemporaryBuffer.obtain(count); 1060 TextUtils.getChars(text, start, end, buffer, 0); 1061 1062 native_drawText(nativeCanvas, buffer, 0, count, x, y, flags, paint); 1063 } 1064 1065 @LayoutlibDelegate 1066 /*package*/ static void native_drawTextRun(int nativeCanvas, char[] text, 1067 int start, int count, int contextStart, int contextCount, 1068 float x, float y, int flags, int paint) { 1069 native_drawText(nativeCanvas, text, start, count, x, y, flags, paint); 1070 } 1071 1072 @LayoutlibDelegate 1073 /*package*/ static void native_drawPosText(int nativeCanvas, 1074 char[] text, int index, 1075 int count, float[] pos, 1076 int paint) { 1077 // FIXME 1078 Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED, 1079 "Canvas.drawPosText is not supported.", null, null /*data*/); 1080 } 1081 1082 @LayoutlibDelegate 1083 /*package*/ static void native_drawPosText(int nativeCanvas, 1084 String text, float[] pos, 1085 int paint) { 1086 // FIXME 1087 Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED, 1088 "Canvas.drawPosText is not supported.", null, null /*data*/); 1089 } 1090 1091 @LayoutlibDelegate 1092 /*package*/ static void native_drawTextOnPath(int nativeCanvas, 1093 char[] text, int index, 1094 int count, int path, 1095 float hOffset, 1096 float vOffset, int bidiFlags, 1097 int paint) { 1098 // FIXME 1099 Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED, 1100 "Canvas.drawTextOnPath is not supported.", null, null /*data*/); 1101 } 1102 1103 @LayoutlibDelegate 1104 /*package*/ static void native_drawTextOnPath(int nativeCanvas, 1105 String text, int path, 1106 float hOffset, 1107 float vOffset, 1108 int flags, int paint) { 1109 // FIXME 1110 Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED, 1111 "Canvas.drawTextOnPath is not supported.", null, null /*data*/); 1112 } 1113 1114 @LayoutlibDelegate 1115 /*package*/ static void native_drawPicture(int nativeCanvas, 1116 int nativePicture) { 1117 // FIXME 1118 Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED, 1119 "Canvas.drawPicture is not supported.", null, null /*data*/); 1120 } 1121 1122 @LayoutlibDelegate 1123 /*package*/ static void finalizer(int nativeCanvas) { 1124 // get the delegate from the native int so that it can be disposed. 1125 Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas); 1126 if (canvasDelegate == null) { 1127 return; 1128 } 1129 1130 canvasDelegate.dispose(); 1131 1132 // remove it from the manager. 1133 sManager.removeJavaReferenceFor(nativeCanvas); 1134 } 1135 1136 // ---- Private delegate/helper methods ---- 1137 1138 /** 1139 * Executes a {@link GcSnapshot.Drawable} with a given canvas and paint. 1140 * <p>Note that the drawable may actually be executed several times if there are 1141 * layers involved (see {@link #saveLayer(RectF, int, int)}. 1142 */ 1143 private static void draw(int nCanvas, int nPaint, boolean compositeOnly, boolean forceSrcMode, 1144 GcSnapshot.Drawable drawable) { 1145 // get the delegate from the native int. 1146 Canvas_Delegate canvasDelegate = sManager.getDelegate(nCanvas); 1147 if (canvasDelegate == null) { 1148 return; 1149 } 1150 1151 // get the paint which can be null if nPaint is 0; 1152 Paint_Delegate paintDelegate = Paint_Delegate.getDelegate(nPaint); 1153 1154 canvasDelegate.getSnapshot().draw(drawable, paintDelegate, compositeOnly, forceSrcMode); 1155 } 1156 1157 /** 1158 * Executes a {@link GcSnapshot.Drawable} with a given canvas. No paint object will be provided 1159 * to {@link GcSnapshot.Drawable#draw(Graphics2D, Paint_Delegate)}. 1160 * <p>Note that the drawable may actually be executed several times if there are 1161 * layers involved (see {@link #saveLayer(RectF, int, int)}. 1162 */ 1163 private static void draw(int nCanvas, GcSnapshot.Drawable drawable) { 1164 // get the delegate from the native int. 1165 Canvas_Delegate canvasDelegate = sManager.getDelegate(nCanvas); 1166 if (canvasDelegate == null) { 1167 return; 1168 } 1169 1170 canvasDelegate.mSnapshot.draw(drawable); 1171 } 1172 1173 private Canvas_Delegate(Bitmap_Delegate bitmap) { 1174 mSnapshot = GcSnapshot.createDefaultSnapshot(mBitmap = bitmap); 1175 } 1176 1177 private Canvas_Delegate() { 1178 mSnapshot = GcSnapshot.createDefaultSnapshot(null /*image*/); 1179 } 1180 1181 /** 1182 * Disposes of the {@link Graphics2D} stack. 1183 */ 1184 private void dispose() { 1185 mSnapshot.dispose(); 1186 } 1187 1188 private int save(int saveFlags) { 1189 // get the current save count 1190 int count = mSnapshot.size(); 1191 1192 mSnapshot = mSnapshot.save(saveFlags); 1193 1194 // return the old save count 1195 return count; 1196 } 1197 1198 private int saveLayerAlpha(RectF rect, int alpha, int saveFlags) { 1199 Paint_Delegate paint = new Paint_Delegate(); 1200 paint.setAlpha(alpha); 1201 return saveLayer(rect, paint, saveFlags); 1202 } 1203 1204 private int saveLayer(RectF rect, Paint_Delegate paint, int saveFlags) { 1205 // get the current save count 1206 int count = mSnapshot.size(); 1207 1208 mSnapshot = mSnapshot.saveLayer(rect, paint, saveFlags); 1209 1210 // return the old save count 1211 return count; 1212 } 1213 1214 /** 1215 * Restores the {@link GcSnapshot} to <var>saveCount</var> 1216 * @param saveCount the saveCount 1217 */ 1218 private void restoreTo(int saveCount) { 1219 mSnapshot = mSnapshot.restoreTo(saveCount); 1220 } 1221 1222 /** 1223 * Restores the {@link GcSnapshot} to <var>saveCount</var> 1224 * @param saveCount the saveCount 1225 */ 1226 private void restore() { 1227 mSnapshot = mSnapshot.restore(); 1228 } 1229 1230 private boolean clipRect(float left, float top, float right, float bottom, int regionOp) { 1231 return mSnapshot.clipRect(left, top, right, bottom, regionOp); 1232 } 1233 1234 private void setBitmap(Bitmap_Delegate bitmap) { 1235 mBitmap = bitmap; 1236 assert mSnapshot.size() == 1; 1237 mSnapshot.setBitmap(mBitmap); 1238 } 1239 1240 private static void drawBitmap( 1241 int nativeCanvas, 1242 Bitmap_Delegate bitmap, 1243 int nativePaintOrZero, 1244 final int sleft, final int stop, final int sright, final int sbottom, 1245 final int dleft, final int dtop, final int dright, final int dbottom) { 1246 // get the delegate from the native int. 1247 Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas); 1248 if (canvasDelegate == null) { 1249 return; 1250 } 1251 1252 // get the paint, which could be null if the int is 0 1253 Paint_Delegate paintDelegate = Paint_Delegate.getDelegate(nativePaintOrZero); 1254 1255 final BufferedImage image = getImageToDraw(bitmap, paintDelegate, sBoolOut); 1256 1257 draw(nativeCanvas, nativePaintOrZero, true /*compositeOnly*/, sBoolOut[0], 1258 new GcSnapshot.Drawable() { 1259 public void draw(Graphics2D graphics, Paint_Delegate paint) { 1260 if (paint != null && paint.isFilterBitmap()) { 1261 graphics.setRenderingHint(RenderingHints.KEY_INTERPOLATION, 1262 RenderingHints.VALUE_INTERPOLATION_BILINEAR); 1263 } 1264 1265 //FIXME add support for canvas, screen and bitmap densities. 1266 graphics.drawImage(image, dleft, dtop, dright, dbottom, 1267 sleft, stop, sright, sbottom, null); 1268 } 1269 }); 1270 } 1271 1272 1273 /** 1274 * Returns a BufferedImage ready for drawing, based on the bitmap and paint delegate. 1275 * The image returns, through a 1-size boolean array, whether the drawing code should 1276 * use a SRC composite no matter what the paint says. 1277 * 1278 * @param bitmap the bitmap 1279 * @param paint the paint that will be used to draw 1280 * @param forceSrcMode whether the composite will have to be SRC 1281 * @return the image to draw 1282 */ 1283 private static BufferedImage getImageToDraw(Bitmap_Delegate bitmap, Paint_Delegate paint, 1284 boolean[] forceSrcMode) { 1285 BufferedImage image = bitmap.getImage(); 1286 forceSrcMode[0] = false; 1287 1288 // if the bitmap config is alpha_8, then we erase all color value from it 1289 // before drawing it. 1290 if (bitmap.getConfig() == Bitmap.Config.ALPHA_8) { 1291 fixAlpha8Bitmap(image); 1292 } else if (bitmap.hasAlpha() == false) { 1293 // hasAlpha is merely a rendering hint. There can in fact be alpha values 1294 // in the bitmap but it should be ignored at drawing time. 1295 // There is two ways to do this: 1296 // - override the composite to be SRC. This can only be used if the composite 1297 // was going to be SRC or SRC_OVER in the first place 1298 // - Create a different bitmap to draw in which all the alpha channel values is set 1299 // to 0xFF. 1300 if (paint != null) { 1301 Xfermode_Delegate xfermodeDelegate = paint.getXfermode(); 1302 if (xfermodeDelegate instanceof PorterDuffXfermode_Delegate) { 1303 PorterDuff.Mode mode = 1304 ((PorterDuffXfermode_Delegate)xfermodeDelegate).getMode(); 1305 1306 forceSrcMode[0] = mode == PorterDuff.Mode.SRC_OVER || 1307 mode == PorterDuff.Mode.SRC; 1308 } 1309 } 1310 1311 // if we can't force SRC mode, then create a temp bitmap of TYPE_RGB 1312 if (forceSrcMode[0] == false) { 1313 image = Bitmap_Delegate.createCopy(image, BufferedImage.TYPE_INT_RGB, 0xFF); 1314 } 1315 } 1316 1317 return image; 1318 } 1319 1320 private static void fixAlpha8Bitmap(final BufferedImage image) { 1321 int w = image.getWidth(); 1322 int h = image.getHeight(); 1323 int[] argb = new int[w * h]; 1324 image.getRGB(0, 0, image.getWidth(), image.getHeight(), argb, 0, image.getWidth()); 1325 1326 final int length = argb.length; 1327 for (int i = 0 ; i < length; i++) { 1328 argb[i] &= 0xFF000000; 1329 } 1330 image.setRGB(0, 0, w, h, argb, 0, w); 1331 } 1332} 1333 1334