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