Canvas_Delegate.java revision c2e9651bf386a1f7bf7fc706cf5424950570470c
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)); 484 485 // set the mode and alpha. 486 int alpha = color >>> 24; 487 float falpha = alpha / 255.f; 488 489 setModeInGraphics(graphics, mode, falpha); 490 491 graphics.fillRect(0, 0, canvasDelegate.mBufferedImage.getWidth(), 492 canvasDelegate.mBufferedImage.getHeight()); 493 } finally { 494 // dispose Graphics2D object 495 graphics.dispose(); 496 } 497 } 498 499 /*package*/ static void native_drawPaint(int nativeCanvas, int paint) { 500 // FIXME 501 throw new UnsupportedOperationException(); 502 } 503 504 /*package*/ static void native_drawLine(int nativeCanvas, float startX, 505 float startY, float stopX, 506 float stopY, int paint) { 507 // get the delegate from the native int. 508 Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas); 509 if (canvasDelegate == null) { 510 assert false; 511 return; 512 } 513 514 // get the delegate from the native int. 515 Paint_Delegate paintDelegate = Paint_Delegate.getDelegate(paint); 516 if (paintDelegate == null) { 517 assert false; 518 return; 519 } 520 521 // get a Graphics2D object configured with the drawing parameters. 522 Graphics2D g = canvasDelegate.getCustomGraphics(paintDelegate); 523 524 g.drawLine((int)startX, (int)startY, (int)stopX, (int)stopY); 525 526 // dispose Graphics2D object 527 g.dispose(); 528 } 529 530 /*package*/ static void native_drawRect(int nativeCanvas, RectF rect, 531 int paint) { 532 native_drawRect(nativeCanvas, rect.left, rect.top, rect.right, rect.bottom, paint); 533 } 534 535 /*package*/ static void native_drawRect(int nativeCanvas, float left, 536 float top, float right, 537 float bottom, int paint) { 538 // get the delegate from the native int. 539 Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas); 540 if (canvasDelegate == null) { 541 assert false; 542 return; 543 } 544 545 // get the delegate from the native int. 546 Paint_Delegate paintDelegate = Paint_Delegate.getDelegate(paint); 547 if (paintDelegate == null) { 548 assert false; 549 return; 550 } 551 552 if (right > left && bottom > top) { 553 // get a Graphics2D object configured with the drawing parameters. 554 Graphics2D g = canvasDelegate.getCustomGraphics(paintDelegate); 555 556 int style = paintDelegate.getStyle(); 557 558 // draw 559 if (style == Paint.Style.FILL.nativeInt || 560 style == Paint.Style.FILL_AND_STROKE.nativeInt) { 561 g.fillRect((int)left, (int)top, (int)(right-left), (int)(bottom-top)); 562 } 563 564 if (style == Paint.Style.STROKE.nativeInt || 565 style == Paint.Style.FILL_AND_STROKE.nativeInt) { 566 g.drawRect((int)left, (int)top, (int)(right-left), (int)(bottom-top)); 567 } 568 569 // dispose Graphics2D object 570 g.dispose(); 571 } 572 } 573 574 /*package*/ static void native_drawOval(int nativeCanvas, RectF oval, 575 int paint) { 576 // get the delegate from the native int. 577 Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas); 578 if (canvasDelegate == null) { 579 assert false; 580 return; 581 } 582 583 // get the delegate from the native int. 584 Paint_Delegate paintDelegate = Paint_Delegate.getDelegate(paint); 585 if (paintDelegate == null) { 586 assert false; 587 return; 588 } 589 590 if (oval.right > oval.left && oval.bottom > oval.top) { 591 // get a Graphics2D object configured with the drawing parameters. 592 Graphics2D g = canvasDelegate.getCustomGraphics(paintDelegate); 593 594 int style = paintDelegate.getStyle(); 595 596 // draw 597 if (style == Paint.Style.FILL.nativeInt || 598 style == Paint.Style.FILL_AND_STROKE.nativeInt) { 599 g.fillOval((int)oval.left, (int)oval.top, (int)oval.width(), (int)oval.height()); 600 } 601 602 if (style == Paint.Style.STROKE.nativeInt || 603 style == Paint.Style.FILL_AND_STROKE.nativeInt) { 604 g.drawOval((int)oval.left, (int)oval.top, (int)oval.width(), (int)oval.height()); 605 } 606 607 // dispose Graphics2D object 608 g.dispose(); 609 } 610 } 611 612 /*package*/ static void native_drawCircle(int nativeCanvas, float cx, 613 float cy, float radius, 614 int paint) { 615 native_drawOval(nativeCanvas, 616 new RectF(cx - radius, cy - radius, radius*2, radius*2), 617 paint); 618 } 619 620 /*package*/ static void native_drawArc(int nativeCanvas, RectF oval, 621 float startAngle, float sweep, 622 boolean useCenter, int paint) { 623 // FIXME 624 throw new UnsupportedOperationException(); 625 } 626 627 /*package*/ static void native_drawRoundRect(int nativeCanvas, 628 RectF rect, float rx, 629 float ry, int paint) { 630 // get the delegate from the native int. 631 Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas); 632 if (canvasDelegate == null) { 633 assert false; 634 return; 635 } 636 637 // get the delegate from the native int. 638 Paint_Delegate paintDelegate = Paint_Delegate.getDelegate(paint); 639 if (paintDelegate == null) { 640 assert false; 641 return; 642 } 643 644 if (rect.right > rect.left && rect.bottom > rect.top) { 645 // get a Graphics2D object configured with the drawing parameters. 646 Graphics2D g = canvasDelegate.getCustomGraphics(paintDelegate); 647 648 int style = paintDelegate.getStyle(); 649 650 // draw 651 if (style == Paint.Style.FILL.nativeInt || 652 style == Paint.Style.FILL_AND_STROKE.nativeInt) { 653 g.fillRoundRect( 654 (int)rect.left, (int)rect.top, (int)rect.width(), (int)rect.height(), 655 (int)rx, (int)ry); 656 } 657 658 if (style == Paint.Style.STROKE.nativeInt || 659 style == Paint.Style.FILL_AND_STROKE.nativeInt) { 660 g.drawRoundRect( 661 (int)rect.left, (int)rect.top, (int)rect.width(), (int)rect.height(), 662 (int)rx, (int)ry); 663 } 664 665 // dispose Graphics2D object 666 g.dispose(); 667 } 668 } 669 670 /*package*/ static void native_drawPath(int nativeCanvas, int path, 671 int paint) { 672 // FIXME 673 throw new UnsupportedOperationException(); 674 } 675 676 /*package*/ static void native_drawBitmap(Canvas thisCanvas, int nativeCanvas, int bitmap, 677 float left, float top, 678 int nativePaintOrZero, 679 int canvasDensity, 680 int screenDensity, 681 int bitmapDensity) { 682 // FIXME 683 throw new UnsupportedOperationException(); 684 } 685 686 /*package*/ static void native_drawBitmap(Canvas thisCanvas, int nativeCanvas, int bitmap, 687 Rect src, RectF dst, 688 int nativePaintOrZero, 689 int screenDensity, 690 int bitmapDensity) { 691 // get the delegate from the native int. 692 Bitmap_Delegate bitmapDelegate = Bitmap_Delegate.getDelegate(bitmap); 693 if (bitmapDelegate == null) { 694 assert false; 695 return; 696 } 697 698 BufferedImage image = bitmapDelegate.getImage(); 699 700 if (src == null) { 701 drawBitmap(nativeCanvas, image, nativePaintOrZero, 702 0, 0, image.getWidth(), image.getHeight(), 703 (int)dst.left, (int)dst.top, (int)dst.right, (int)dst.bottom); 704 } else { 705 drawBitmap(nativeCanvas, image, nativePaintOrZero, 706 src.left, src.top, src.width(), src.height(), 707 (int)dst.left, (int)dst.top, (int)dst.right, (int)dst.bottom); 708 } 709 } 710 711 /*package*/ static void native_drawBitmap(int nativeCanvas, int bitmap, 712 Rect src, Rect dst, 713 int nativePaintOrZero, 714 int screenDensity, 715 int bitmapDensity) { 716 // get the delegate from the native int. 717 Bitmap_Delegate bitmapDelegate = Bitmap_Delegate.getDelegate(bitmap); 718 if (bitmapDelegate == null) { 719 assert false; 720 return; 721 } 722 723 BufferedImage image = bitmapDelegate.getImage(); 724 725 if (src == null) { 726 drawBitmap(nativeCanvas, image, nativePaintOrZero, 727 0, 0, image.getWidth(), image.getHeight(), 728 dst.left, dst.top, dst.right, dst.bottom); 729 } else { 730 drawBitmap(nativeCanvas, image, nativePaintOrZero, 731 src.left, src.top, src.width(), src.height(), 732 dst.left, dst.top, dst.right, dst.bottom); 733 } 734 } 735 736 /*package*/ static void native_drawBitmap(int nativeCanvas, int[] colors, 737 int offset, int stride, float x, 738 float y, int width, int height, 739 boolean hasAlpha, 740 int nativePaintOrZero) { 741 // FIXME 742 throw new UnsupportedOperationException(); 743 } 744 745 /*package*/ static void nativeDrawBitmapMatrix(int nCanvas, int nBitmap, 746 int nMatrix, int nPaint) { 747 // FIXME 748 throw new UnsupportedOperationException(); 749 } 750 751 /*package*/ static void nativeDrawBitmapMesh(int nCanvas, int nBitmap, 752 int meshWidth, int meshHeight, 753 float[] verts, int vertOffset, 754 int[] colors, int colorOffset, int nPaint) { 755 // FIXME 756 throw new UnsupportedOperationException(); 757 } 758 759 /*package*/ static void nativeDrawVertices(int nCanvas, int mode, int n, 760 float[] verts, int vertOffset, float[] texs, int texOffset, 761 int[] colors, int colorOffset, short[] indices, 762 int indexOffset, int indexCount, int nPaint) { 763 // FIXME 764 throw new UnsupportedOperationException(); 765 } 766 767 /*package*/ static void native_drawText(int nativeCanvas, char[] text, 768 int index, int count, float x, 769 float y, int flags, int paint) { 770 // WARNING: the logic in this method is similar to Paint.measureText. 771 // Any change to this method should be reflected in Paint.measureText 772 773 // get the delegate from the native int. 774 Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas); 775 if (canvasDelegate == null) { 776 assert false; 777 return; 778 } 779 780 // get the delegate from the native int. 781 Paint_Delegate paintDelegate = Paint_Delegate.getDelegate(paint); 782 if (paintDelegate == null) { 783 assert false; 784 return; 785 } 786 787 Graphics2D g = (Graphics2D) canvasDelegate.getCustomGraphics(paintDelegate); 788 try { 789 // Paint.TextAlign indicates how the text is positioned relative to X. 790 // LEFT is the default and there's nothing to do. 791 if (paintDelegate.getTextAlign() != Paint.Align.LEFT.nativeInt) { 792 float m = paintDelegate.measureText(text, index, count); 793 if (paintDelegate.getTextAlign() == Paint.Align.CENTER.nativeInt) { 794 x -= m / 2; 795 } else if (paintDelegate.getTextAlign() == Paint.Align.RIGHT.nativeInt) { 796 x -= m; 797 } 798 } 799 800 List<FontInfo> fonts = paintDelegate.getFonts(); 801 802 if (fonts.size() > 0) { 803 FontInfo mainFont = fonts.get(0); 804 int i = index; 805 int lastIndex = index + count; 806 while (i < lastIndex) { 807 // always start with the main font. 808 int upTo = mainFont.mFont.canDisplayUpTo(text, i, lastIndex); 809 if (upTo == -1) { 810 // draw all the rest and exit. 811 g.setFont(mainFont.mFont); 812 g.drawChars(text, i, lastIndex - i, (int)x, (int)y); 813 return; 814 } else if (upTo > 0) { 815 // draw what's possible 816 g.setFont(mainFont.mFont); 817 g.drawChars(text, i, upTo - i, (int)x, (int)y); 818 819 // compute the width that was drawn to increase x 820 x += mainFont.mMetrics.charsWidth(text, i, upTo - i); 821 822 // move index to the first non displayed char. 823 i = upTo; 824 825 // don't call continue at this point. Since it is certain the main font 826 // cannot display the font a index upTo (now ==i), we move on to the 827 // fallback fonts directly. 828 } 829 830 // no char supported, attempt to read the next char(s) with the 831 // fallback font. In this case we only test the first character 832 // and then go back to test with the main font. 833 // Special test for 2-char characters. 834 boolean foundFont = false; 835 for (int f = 1 ; f < fonts.size() ; f++) { 836 FontInfo fontInfo = fonts.get(f); 837 838 // need to check that the font can display the character. We test 839 // differently if the char is a high surrogate. 840 int charCount = Character.isHighSurrogate(text[i]) ? 2 : 1; 841 upTo = fontInfo.mFont.canDisplayUpTo(text, i, i + charCount); 842 if (upTo == -1) { 843 // draw that char 844 g.setFont(fontInfo.mFont); 845 g.drawChars(text, i, charCount, (int)x, (int)y); 846 847 // update x 848 x += fontInfo.mMetrics.charsWidth(text, i, charCount); 849 850 // update the index in the text, and move on 851 i += charCount; 852 foundFont = true; 853 break; 854 855 } 856 } 857 858 // in case no font can display the char, display it with the main font. 859 // (it'll put a square probably) 860 if (foundFont == false) { 861 int charCount = Character.isHighSurrogate(text[i]) ? 2 : 1; 862 863 g.setFont(mainFont.mFont); 864 g.drawChars(text, i, charCount, (int)x, (int)y); 865 866 // measure it to advance x 867 x += mainFont.mMetrics.charsWidth(text, i, charCount); 868 869 // and move to the next chars. 870 i += charCount; 871 } 872 } 873 } 874 } finally { 875 g.dispose(); 876 } 877 } 878 879 /*package*/ static void native_drawText(int nativeCanvas, String text, 880 int start, int end, float x, 881 float y, int flags, int paint) { 882 int count = end - start; 883 char[] buffer = TemporaryBuffer.obtain(count); 884 TextUtils.getChars(text, start, end, buffer, 0); 885 886 native_drawText(nativeCanvas, buffer, 0, count, x, y, flags, paint); 887 } 888 889 /*package*/ static void native_drawTextRun(int nativeCanvas, String text, 890 int start, int end, int contextStart, int contextEnd, 891 float x, float y, int flags, int paint) { 892 int count = end - start; 893 char[] buffer = TemporaryBuffer.obtain(count); 894 TextUtils.getChars(text, start, end, buffer, 0); 895 896 native_drawText(nativeCanvas, buffer, start, end, x, y, flags, paint); 897 } 898 899 /*package*/ static void native_drawTextRun(int nativeCanvas, char[] text, 900 int start, int count, int contextStart, int contextCount, 901 float x, float y, int flags, int paint) { 902 native_drawText(nativeCanvas, text, 0, count, x, y, flags, paint); 903 } 904 905 /*package*/ static void native_drawPosText(int nativeCanvas, 906 char[] text, int index, 907 int count, float[] pos, 908 int paint) { 909 // FIXME 910 throw new UnsupportedOperationException(); 911 } 912 913 /*package*/ static void native_drawPosText(int nativeCanvas, 914 String text, float[] pos, 915 int paint) { 916 // FIXME 917 throw new UnsupportedOperationException(); 918 } 919 920 /*package*/ static void native_drawTextOnPath(int nativeCanvas, 921 char[] text, int index, 922 int count, int path, 923 float hOffset, 924 float vOffset, int bidiFlags, 925 int paint) { 926 // FIXME 927 throw new UnsupportedOperationException(); 928 } 929 930 /*package*/ static void native_drawTextOnPath(int nativeCanvas, 931 String text, int path, 932 float hOffset, 933 float vOffset, 934 int flags, int paint) { 935 // FIXME 936 throw new UnsupportedOperationException(); 937 } 938 939 /*package*/ static void native_drawPicture(int nativeCanvas, 940 int nativePicture) { 941 // FIXME 942 throw new UnsupportedOperationException(); 943 } 944 945 /*package*/ static void finalizer(int nativeCanvas) { 946 sManager.removeDelegate(nativeCanvas); 947 } 948 949 // ---- Private delegate/helper methods ---- 950 951 private Canvas_Delegate(BufferedImage image) { 952 setBitmap(image); 953 } 954 955 private Canvas_Delegate() { 956 } 957 958 private void setBitmap(BufferedImage image) { 959 mBufferedImage = image; 960 mGraphicsStack.push(mBufferedImage.createGraphics()); 961 } 962 963 /** 964 * Creates a new {@link Graphics2D} based on the {@link Paint} parameters. 965 * <p/>The object must be disposed ({@link Graphics2D#dispose()}) after being used. 966 */ 967 private Graphics2D getCustomGraphics(Paint_Delegate paint) { 968 // make new one 969 Graphics2D g = getGraphics2d(); 970 g = (Graphics2D)g.create(); 971 972 // configure it 973 974 if (paint.isAntiAliased()) { 975 g.setRenderingHint( 976 RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); 977 g.setRenderingHint( 978 RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON); 979 } 980 981 boolean useColorPaint = true; 982 983 // get the shader first, as it'll replace the color if it can be used it. 984 Shader_Delegate shaderDelegate = Shader_Delegate.getDelegate(paint.getShader()); 985 if (shaderDelegate != null) { 986 java.awt.Paint shaderPaint = shaderDelegate.getJavaPaint(); 987 if (shaderPaint != null) { 988 g.setPaint(shaderPaint); 989 useColorPaint = false; 990 } else { 991 if (mLogger != null) { 992 mLogger.warning(String.format( 993 "Shader '%1$s' is not supported in the Layout Editor.", 994 shaderDelegate.getClass().getCanonicalName())); 995 } 996 } 997 } 998 999 // need to get the alpha to set it in the composite. 1000 float falpha = 1.f; 1001 1002 if (useColorPaint) { 1003 g.setColor(new Color(paint.getColor())); 1004 1005 // the alpha is taken from the alpha channel of the color 1006 int alpha = paint.getAlpha(); 1007 falpha = alpha / 255.f; 1008 } 1009 1010 int style = paint.getStyle(); 1011 if (style == Paint.Style.STROKE.nativeInt || 1012 style == Paint.Style.FILL_AND_STROKE.nativeInt) { 1013 1014 PathEffect_Delegate effectDelegate = PathEffect_Delegate.getDelegate( 1015 paint.getPathEffect()); 1016 1017 if (effectDelegate instanceof DashPathEffect_Delegate) { 1018 DashPathEffect_Delegate dpe = (DashPathEffect_Delegate)effectDelegate; 1019 g.setStroke(new BasicStroke( 1020 paint.getStrokeWidth(), 1021 paint.getJavaCap(), 1022 paint.getJavaJoin(), 1023 paint.getStrokeMiter(), 1024 dpe.getIntervals(), 1025 dpe.getPhase())); 1026 } else { 1027 g.setStroke(new BasicStroke( 1028 paint.getStrokeWidth(), 1029 paint.getJavaCap(), 1030 paint.getJavaJoin(), 1031 paint.getStrokeMiter())); 1032 } 1033 } 1034 1035 Xfermode_Delegate xfermodeDelegate = Xfermode_Delegate.getDelegate(paint.getXfermode()); 1036 if (xfermodeDelegate instanceof PorterDuffXfermode_Delegate) { 1037 int mode = ((PorterDuffXfermode_Delegate)xfermodeDelegate).getMode(); 1038 1039 setModeInGraphics(g, mode, falpha); 1040 } else { 1041 // default mode is src_over 1042 g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, falpha)); 1043 1044 // if xfermode wasn't null, then it's something we don't support. log it. 1045 if (mLogger != null && xfermodeDelegate != null) { 1046 mLogger.warning(String.format( 1047 "Xfermode '%1$s' is not supported in the Layout Editor.", 1048 xfermodeDelegate.getClass().getCanonicalName())); 1049 } 1050 } 1051 1052 return g; 1053 } 1054 1055 private static void setModeInGraphics(Graphics2D g, int mode, float falpha) { 1056 for (PorterDuff.Mode m : PorterDuff.Mode.values()) { 1057 if (m.nativeInt == mode) { 1058 setModeInGraphics(g, m, falpha); 1059 return; 1060 } 1061 } 1062 } 1063 1064 private static void setModeInGraphics(Graphics2D g, PorterDuff.Mode mode, float falpha) { 1065 switch (mode) { 1066 case CLEAR: 1067 g.setComposite(AlphaComposite.getInstance(AlphaComposite.CLEAR, falpha)); 1068 break; 1069 case DARKEN: 1070 break; 1071 case DST: 1072 g.setComposite(AlphaComposite.getInstance(AlphaComposite.DST, falpha)); 1073 break; 1074 case DST_ATOP: 1075 g.setComposite(AlphaComposite.getInstance(AlphaComposite.DST_ATOP, falpha)); 1076 break; 1077 case DST_IN: 1078 g.setComposite(AlphaComposite.getInstance(AlphaComposite.DST_IN, falpha)); 1079 break; 1080 case DST_OUT: 1081 g.setComposite(AlphaComposite.getInstance(AlphaComposite.DST_OUT, falpha)); 1082 break; 1083 case DST_OVER: 1084 g.setComposite(AlphaComposite.getInstance(AlphaComposite.DST_OVER, falpha)); 1085 break; 1086 case LIGHTEN: 1087 break; 1088 case MULTIPLY: 1089 break; 1090 case SCREEN: 1091 break; 1092 case SRC: 1093 g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC, falpha)); 1094 break; 1095 case SRC_ATOP: 1096 g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, falpha)); 1097 break; 1098 case SRC_IN: 1099 g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_IN, falpha)); 1100 break; 1101 case SRC_OUT: 1102 g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OUT, falpha)); 1103 break; 1104 case SRC_OVER: 1105 g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, falpha)); 1106 break; 1107 case XOR: 1108 g.setComposite(AlphaComposite.getInstance(AlphaComposite.XOR, falpha)); 1109 break; 1110 } 1111 } 1112 1113 1114 private static void drawBitmap( 1115 int nativeCanvas, 1116 BufferedImage image, 1117 int nativePaintOrZero, 1118 int sleft, int stop, int sright, int sbottom, 1119 int dleft, int dtop, int dright, int dbottom) { 1120 // get the delegate from the native int. 1121 Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas); 1122 if (canvasDelegate == null) { 1123 assert false; 1124 return; 1125 } 1126 1127 // get the delegate from the native int. 1128 Paint_Delegate paintDelegate = null; 1129 if (nativePaintOrZero > 0) { 1130 paintDelegate = Paint_Delegate.getDelegate(nativePaintOrZero); 1131 if (paintDelegate == null) { 1132 assert false; 1133 return; 1134 } 1135 } 1136 1137 drawBitmap(canvasDelegate, image, paintDelegate, 1138 sleft, stop, sright, sbottom, 1139 dleft, dtop, dright, dbottom); 1140 } 1141 1142 private static void drawBitmap( 1143 Canvas_Delegate canvasDelegate, 1144 BufferedImage image, 1145 Paint_Delegate paintDelegate, 1146 int sleft, int stop, int sright, int sbottom, 1147 int dleft, int dtop, int dright, int dbottom) { 1148 1149 Graphics2D g = canvasDelegate.getGraphics2d(); 1150 1151 Composite c = null; 1152 1153 if (paintDelegate != null) { 1154 if (paintDelegate.isFilterBitmap()) { 1155 g = (Graphics2D)g.create(); 1156 g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, 1157 RenderingHints.VALUE_INTERPOLATION_BILINEAR); 1158 } 1159 1160 if (paintDelegate.getAlpha() != 0xFF) { 1161 c = g.getComposite(); 1162 g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1163 paintDelegate.getAlpha()/255.f)); 1164 } 1165 } 1166 1167 g.drawImage(image, dleft, dtop, dright, dbottom, 1168 sleft, stop, sright, sbottom, null); 1169 1170 if (paintDelegate != null) { 1171 if (paintDelegate.isFilterBitmap()) { 1172 g.dispose(); 1173 } 1174 if (c != null) { 1175 g.setComposite(c); 1176 } 1177 } 1178 } 1179 1180} 1181 1182