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