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