GLES20Canvas.java revision 2836c4722a156ec78d7f4101b394885a354f5dd6
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.view; 18 19import android.graphics.Bitmap; 20import android.graphics.Canvas; 21import android.graphics.CanvasProperty; 22import android.graphics.DrawFilter; 23import android.graphics.Matrix; 24import android.graphics.NinePatch; 25import android.graphics.Paint; 26import android.graphics.PaintFlagsDrawFilter; 27import android.graphics.Path; 28import android.graphics.Picture; 29import android.graphics.PorterDuff; 30import android.graphics.Rect; 31import android.graphics.RectF; 32import android.graphics.Region; 33import android.graphics.Shader; 34import android.graphics.TemporaryBuffer; 35import android.text.GraphicsOperations; 36import android.text.SpannableString; 37import android.text.SpannedString; 38import android.text.TextUtils; 39 40/** 41 * An implementation of Canvas on top of OpenGL ES 2.0. 42 */ 43class GLES20Canvas extends HardwareCanvas { 44 // Must match modifiers used in the JNI layer 45 private static final int MODIFIER_NONE = 0; 46 private static final int MODIFIER_SHADER = 2; 47 48 private final boolean mOpaque; 49 protected long mRenderer; 50 51 // The native renderer will be destroyed when this object dies. 52 // DO NOT overwrite this reference once it is set. 53 @SuppressWarnings({"unused", "FieldCanBeLocal"}) 54 private CanvasFinalizer mFinalizer; 55 56 private int mWidth; 57 private int mHeight; 58 59 private float[] mPoint; 60 private float[] mLine; 61 62 private Rect mClipBounds; 63 private RectF mPathBounds; 64 65 private DrawFilter mFilter; 66 67 /////////////////////////////////////////////////////////////////////////// 68 // JNI 69 /////////////////////////////////////////////////////////////////////////// 70 71 private static native boolean nIsAvailable(); 72 private static boolean sIsAvailable = nIsAvailable(); 73 74 static boolean isAvailable() { 75 return sIsAvailable; 76 } 77 78 /////////////////////////////////////////////////////////////////////////// 79 // Constructors 80 /////////////////////////////////////////////////////////////////////////// 81 82 /** 83 * Creates a canvas to render directly on screen. 84 */ 85 GLES20Canvas(boolean translucent) { 86 this(false, translucent); 87 } 88 89 protected GLES20Canvas(boolean record, boolean translucent) { 90 mOpaque = !translucent; 91 92 if (record) { 93 mRenderer = nCreateDisplayListRenderer(); 94 } else { 95 mRenderer = nCreateRenderer(); 96 } 97 98 setupFinalizer(); 99 } 100 101 private void setupFinalizer() { 102 if (mRenderer == 0) { 103 throw new IllegalStateException("Could not create GLES20Canvas renderer"); 104 } else { 105 mFinalizer = new CanvasFinalizer(mRenderer); 106 } 107 } 108 109 private static native long nCreateRenderer(); 110 private static native long nCreateDisplayListRenderer(); 111 private static native void nResetDisplayListRenderer(long renderer); 112 private static native void nDestroyRenderer(long renderer); 113 114 private static final class CanvasFinalizer { 115 private final long mRenderer; 116 117 public CanvasFinalizer(long renderer) { 118 mRenderer = renderer; 119 } 120 121 @Override 122 protected void finalize() throws Throwable { 123 try { 124 nDestroyRenderer(mRenderer); 125 } finally { 126 super.finalize(); 127 } 128 } 129 } 130 131 public static void setProperty(String name, String value) { 132 nSetProperty(name, value); 133 } 134 135 private static native void nSetProperty(String name, String value); 136 137 /////////////////////////////////////////////////////////////////////////// 138 // Hardware layers 139 /////////////////////////////////////////////////////////////////////////// 140 141 @Override 142 void pushLayerUpdate(HardwareLayer layer) { 143 nPushLayerUpdate(mRenderer, layer.getLayer()); 144 } 145 146 @Override 147 void cancelLayerUpdate(HardwareLayer layer) { 148 nCancelLayerUpdate(mRenderer, layer.getLayer()); 149 } 150 151 @Override 152 void flushLayerUpdates() { 153 nFlushLayerUpdates(mRenderer); 154 } 155 156 @Override 157 void clearLayerUpdates() { 158 nClearLayerUpdates(mRenderer); 159 } 160 161 static native boolean nCopyLayer(long layerId, long bitmap); 162 private static native void nClearLayerUpdates(long renderer); 163 private static native void nFlushLayerUpdates(long renderer); 164 private static native void nPushLayerUpdate(long renderer, long layer); 165 private static native void nCancelLayerUpdate(long renderer, long layer); 166 167 /////////////////////////////////////////////////////////////////////////// 168 // Canvas management 169 /////////////////////////////////////////////////////////////////////////// 170 171 @Override 172 public boolean isOpaque() { 173 return mOpaque; 174 } 175 176 @Override 177 public int getWidth() { 178 return mWidth; 179 } 180 181 @Override 182 public int getHeight() { 183 return mHeight; 184 } 185 186 @Override 187 public int getMaximumBitmapWidth() { 188 return nGetMaximumTextureWidth(); 189 } 190 191 @Override 192 public int getMaximumBitmapHeight() { 193 return nGetMaximumTextureHeight(); 194 } 195 196 private static native int nGetMaximumTextureWidth(); 197 private static native int nGetMaximumTextureHeight(); 198 199 /** 200 * Returns the native OpenGLRenderer object. 201 */ 202 long getRenderer() { 203 return mRenderer; 204 } 205 206 /////////////////////////////////////////////////////////////////////////// 207 // Setup 208 /////////////////////////////////////////////////////////////////////////// 209 210 @Override 211 public void setViewport(int width, int height) { 212 mWidth = width; 213 mHeight = height; 214 215 nSetViewport(mRenderer, width, height); 216 } 217 218 private static native void nSetViewport(long renderer, int width, int height); 219 220 @Override 221 public int onPreDraw(Rect dirty) { 222 if (dirty != null) { 223 return nPrepareDirty(mRenderer, dirty.left, dirty.top, dirty.right, dirty.bottom, 224 mOpaque); 225 } else { 226 return nPrepare(mRenderer, mOpaque); 227 } 228 } 229 230 private static native int nPrepare(long renderer, boolean opaque); 231 private static native int nPrepareDirty(long renderer, int left, int top, int right, int bottom, 232 boolean opaque); 233 234 @Override 235 public void onPostDraw() { 236 nFinish(mRenderer); 237 } 238 239 private static native void nFinish(long renderer); 240 241 /** 242 * Returns the size of the stencil buffer required by the underlying 243 * implementation. 244 * 245 * @return The minimum number of bits the stencil buffer must. Always >= 0. 246 * 247 * @hide 248 */ 249 public static int getStencilSize() { 250 return nGetStencilSize(); 251 } 252 253 private static native int nGetStencilSize(); 254 255 /////////////////////////////////////////////////////////////////////////// 256 // Functor 257 /////////////////////////////////////////////////////////////////////////// 258 259 @Override 260 public int callDrawGLFunction(long drawGLFunction) { 261 return nCallDrawGLFunction(mRenderer, drawGLFunction); 262 } 263 264 private static native int nCallDrawGLFunction(long renderer, long drawGLFunction); 265 266 /////////////////////////////////////////////////////////////////////////// 267 // Memory 268 /////////////////////////////////////////////////////////////////////////// 269 270 /** 271 * Must match Caches::FlushMode values 272 * 273 * @see #flushCaches(int) 274 */ 275 static final int FLUSH_CACHES_LAYERS = 0; 276 277 /** 278 * Must match Caches::FlushMode values 279 * 280 * @see #flushCaches(int) 281 */ 282 static final int FLUSH_CACHES_MODERATE = 1; 283 284 /** 285 * Must match Caches::FlushMode values 286 * 287 * @see #flushCaches(int) 288 */ 289 static final int FLUSH_CACHES_FULL = 2; 290 291 /** 292 * Flush caches to reclaim as much memory as possible. The amount of memory 293 * to reclaim is indicate by the level parameter. 294 * 295 * The level can be one of {@link #FLUSH_CACHES_MODERATE} or 296 * {@link #FLUSH_CACHES_FULL}. 297 * 298 * @param level Hint about the amount of memory to reclaim 299 */ 300 static void flushCaches(int level) { 301 nFlushCaches(level); 302 } 303 304 private static native void nFlushCaches(int level); 305 306 /** 307 * Release all resources associated with the underlying caches. This should 308 * only be called after a full flushCaches(). 309 * 310 * @hide 311 */ 312 static void terminateCaches() { 313 nTerminateCaches(); 314 } 315 316 private static native void nTerminateCaches(); 317 318 static boolean initCaches() { 319 return nInitCaches(); 320 } 321 322 private static native boolean nInitCaches(); 323 324 /////////////////////////////////////////////////////////////////////////// 325 // Atlas 326 /////////////////////////////////////////////////////////////////////////// 327 328 static void initAtlas(GraphicBuffer buffer, long[] map) { 329 nInitAtlas(buffer, map, map.length); 330 } 331 332 private static native void nInitAtlas(GraphicBuffer buffer, long[] map, int count); 333 334 /////////////////////////////////////////////////////////////////////////// 335 // Display list 336 /////////////////////////////////////////////////////////////////////////// 337 338 protected static native long nFinishRecording(long renderer); 339 340 @Override 341 public int drawDisplayList(RenderNode displayList, Rect dirty, int flags) { 342 return nDrawDisplayList(mRenderer, displayList.getNativeDisplayList(), 343 dirty, flags); 344 } 345 346 private static native int nDrawDisplayList(long renderer, long displayList, 347 Rect dirty, int flags); 348 349 /////////////////////////////////////////////////////////////////////////// 350 // Hardware layer 351 /////////////////////////////////////////////////////////////////////////// 352 353 void drawHardwareLayer(HardwareLayer layer, float x, float y, Paint paint) { 354 layer.setLayerPaint(paint); 355 nDrawLayer(mRenderer, layer.getLayer(), x, y); 356 } 357 358 private static native void nDrawLayer(long renderer, long layer, float x, float y); 359 360 /////////////////////////////////////////////////////////////////////////// 361 // Support 362 /////////////////////////////////////////////////////////////////////////// 363 364 private Rect getInternalClipBounds() { 365 if (mClipBounds == null) mClipBounds = new Rect(); 366 return mClipBounds; 367 } 368 369 370 private RectF getPathBounds() { 371 if (mPathBounds == null) mPathBounds = new RectF(); 372 return mPathBounds; 373 } 374 375 private float[] getPointStorage() { 376 if (mPoint == null) mPoint = new float[2]; 377 return mPoint; 378 } 379 380 private float[] getLineStorage() { 381 if (mLine == null) mLine = new float[4]; 382 return mLine; 383 } 384 385 /////////////////////////////////////////////////////////////////////////// 386 // Clipping 387 /////////////////////////////////////////////////////////////////////////// 388 389 @Override 390 public boolean clipPath(Path path) { 391 return nClipPath(mRenderer, path.mNativePath, Region.Op.INTERSECT.nativeInt); 392 } 393 394 @Override 395 public boolean clipPath(Path path, Region.Op op) { 396 return nClipPath(mRenderer, path.mNativePath, op.nativeInt); 397 } 398 399 private static native boolean nClipPath(long renderer, long path, int op); 400 401 @Override 402 public boolean clipRect(float left, float top, float right, float bottom) { 403 return nClipRect(mRenderer, left, top, right, bottom, Region.Op.INTERSECT.nativeInt); 404 } 405 406 private static native boolean nClipRect(long renderer, float left, float top, 407 float right, float bottom, int op); 408 409 @Override 410 public boolean clipRect(float left, float top, float right, float bottom, Region.Op op) { 411 return nClipRect(mRenderer, left, top, right, bottom, op.nativeInt); 412 } 413 414 @Override 415 public boolean clipRect(int left, int top, int right, int bottom) { 416 return nClipRect(mRenderer, left, top, right, bottom, Region.Op.INTERSECT.nativeInt); 417 } 418 419 private static native boolean nClipRect(long renderer, int left, int top, 420 int right, int bottom, int op); 421 422 @Override 423 public boolean clipRect(Rect rect) { 424 return nClipRect(mRenderer, rect.left, rect.top, rect.right, rect.bottom, 425 Region.Op.INTERSECT.nativeInt); 426 } 427 428 @Override 429 public boolean clipRect(Rect rect, Region.Op op) { 430 return nClipRect(mRenderer, rect.left, rect.top, rect.right, rect.bottom, op.nativeInt); 431 } 432 433 @Override 434 public boolean clipRect(RectF rect) { 435 return nClipRect(mRenderer, rect.left, rect.top, rect.right, rect.bottom, 436 Region.Op.INTERSECT.nativeInt); 437 } 438 439 @Override 440 public boolean clipRect(RectF rect, Region.Op op) { 441 return nClipRect(mRenderer, rect.left, rect.top, rect.right, rect.bottom, op.nativeInt); 442 } 443 444 @Override 445 public boolean clipRegion(Region region) { 446 return nClipRegion(mRenderer, region.mNativeRegion, Region.Op.INTERSECT.nativeInt); 447 } 448 449 @Override 450 public boolean clipRegion(Region region, Region.Op op) { 451 return nClipRegion(mRenderer, region.mNativeRegion, op.nativeInt); 452 } 453 454 private static native boolean nClipRegion(long renderer, long region, int op); 455 456 @Override 457 public boolean getClipBounds(Rect bounds) { 458 return nGetClipBounds(mRenderer, bounds); 459 } 460 461 private static native boolean nGetClipBounds(long renderer, Rect bounds); 462 463 @Override 464 public boolean quickReject(float left, float top, float right, float bottom, EdgeType type) { 465 return nQuickReject(mRenderer, left, top, right, bottom); 466 } 467 468 private static native boolean nQuickReject(long renderer, float left, float top, 469 float right, float bottom); 470 471 @Override 472 public boolean quickReject(Path path, EdgeType type) { 473 RectF pathBounds = getPathBounds(); 474 path.computeBounds(pathBounds, true); 475 return nQuickReject(mRenderer, pathBounds.left, pathBounds.top, 476 pathBounds.right, pathBounds.bottom); 477 } 478 479 @Override 480 public boolean quickReject(RectF rect, EdgeType type) { 481 return nQuickReject(mRenderer, rect.left, rect.top, rect.right, rect.bottom); 482 } 483 484 /////////////////////////////////////////////////////////////////////////// 485 // Transformations 486 /////////////////////////////////////////////////////////////////////////// 487 488 @Override 489 public void translate(float dx, float dy) { 490 if (dx != 0.0f || dy != 0.0f) nTranslate(mRenderer, dx, dy); 491 } 492 493 private static native void nTranslate(long renderer, float dx, float dy); 494 495 @Override 496 public void skew(float sx, float sy) { 497 nSkew(mRenderer, sx, sy); 498 } 499 500 private static native void nSkew(long renderer, float sx, float sy); 501 502 @Override 503 public void rotate(float degrees) { 504 nRotate(mRenderer, degrees); 505 } 506 507 private static native void nRotate(long renderer, float degrees); 508 509 @Override 510 public void scale(float sx, float sy) { 511 nScale(mRenderer, sx, sy); 512 } 513 514 private static native void nScale(long renderer, float sx, float sy); 515 516 @Override 517 public void setMatrix(Matrix matrix) { 518 nSetMatrix(mRenderer, matrix == null ? 0 : matrix.native_instance); 519 } 520 521 private static native void nSetMatrix(long renderer, long matrix); 522 523 @SuppressWarnings("deprecation") 524 @Override 525 public void getMatrix(Matrix matrix) { 526 nGetMatrix(mRenderer, matrix.native_instance); 527 } 528 529 private static native void nGetMatrix(long renderer, long matrix); 530 531 @Override 532 public void concat(Matrix matrix) { 533 if (matrix != null) nConcatMatrix(mRenderer, matrix.native_instance); 534 } 535 536 private static native void nConcatMatrix(long renderer, long matrix); 537 538 /////////////////////////////////////////////////////////////////////////// 539 // State management 540 /////////////////////////////////////////////////////////////////////////// 541 542 @Override 543 public int save() { 544 return nSave(mRenderer, Canvas.CLIP_SAVE_FLAG | Canvas.MATRIX_SAVE_FLAG); 545 } 546 547 @Override 548 public int save(int saveFlags) { 549 return nSave(mRenderer, saveFlags); 550 } 551 552 private static native int nSave(long renderer, int flags); 553 554 @Override 555 public int saveLayer(RectF bounds, Paint paint, int saveFlags) { 556 if (bounds != null) { 557 return saveLayer(bounds.left, bounds.top, bounds.right, bounds.bottom, paint, saveFlags); 558 } 559 560 final long nativePaint = paint == null ? 0 : paint.mNativePaint; 561 return nSaveLayer(mRenderer, nativePaint, saveFlags); 562 } 563 564 private static native int nSaveLayer(long renderer, long paint, int saveFlags); 565 566 @Override 567 public int saveLayer(float left, float top, float right, float bottom, Paint paint, 568 int saveFlags) { 569 if (left < right && top < bottom) { 570 final long nativePaint = paint == null ? 0 : paint.mNativePaint; 571 return nSaveLayer(mRenderer, left, top, right, bottom, nativePaint, saveFlags); 572 } 573 return save(saveFlags); 574 } 575 576 private static native int nSaveLayer(long renderer, float left, float top, 577 float right, float bottom, long paint, int saveFlags); 578 579 @Override 580 public int saveLayerAlpha(RectF bounds, int alpha, int saveFlags) { 581 if (bounds != null) { 582 return saveLayerAlpha(bounds.left, bounds.top, bounds.right, bounds.bottom, 583 alpha, saveFlags); 584 } 585 return nSaveLayerAlpha(mRenderer, alpha, saveFlags); 586 } 587 588 private static native int nSaveLayerAlpha(long renderer, int alpha, int saveFlags); 589 590 @Override 591 public int saveLayerAlpha(float left, float top, float right, float bottom, int alpha, 592 int saveFlags) { 593 if (left < right && top < bottom) { 594 return nSaveLayerAlpha(mRenderer, left, top, right, bottom, alpha, saveFlags); 595 } 596 return save(saveFlags); 597 } 598 599 private static native int nSaveLayerAlpha(long renderer, float left, float top, float right, 600 float bottom, int alpha, int saveFlags); 601 602 @Override 603 public void restore() { 604 nRestore(mRenderer); 605 } 606 607 private static native void nRestore(long renderer); 608 609 @Override 610 public void restoreToCount(int saveCount) { 611 nRestoreToCount(mRenderer, saveCount); 612 } 613 614 private static native void nRestoreToCount(long renderer, int saveCount); 615 616 @Override 617 public int getSaveCount() { 618 return nGetSaveCount(mRenderer); 619 } 620 621 private static native int nGetSaveCount(long renderer); 622 623 /////////////////////////////////////////////////////////////////////////// 624 // Filtering 625 /////////////////////////////////////////////////////////////////////////// 626 627 @Override 628 public void setDrawFilter(DrawFilter filter) { 629 mFilter = filter; 630 if (filter == null) { 631 nResetPaintFilter(mRenderer); 632 } else if (filter instanceof PaintFlagsDrawFilter) { 633 PaintFlagsDrawFilter flagsFilter = (PaintFlagsDrawFilter) filter; 634 nSetupPaintFilter(mRenderer, flagsFilter.clearBits, flagsFilter.setBits); 635 } 636 } 637 638 private static native void nResetPaintFilter(long renderer); 639 private static native void nSetupPaintFilter(long renderer, int clearBits, int setBits); 640 641 @Override 642 public DrawFilter getDrawFilter() { 643 return mFilter; 644 } 645 646 /////////////////////////////////////////////////////////////////////////// 647 // Drawing 648 /////////////////////////////////////////////////////////////////////////// 649 650 @Override 651 public void drawArc(RectF oval, float startAngle, float sweepAngle, boolean useCenter, 652 Paint paint) { 653 int modifiers = setupModifiers(paint, MODIFIER_SHADER); 654 try { 655 nDrawArc(mRenderer, oval.left, oval.top, oval.right, oval.bottom, 656 startAngle, sweepAngle, useCenter, paint.mNativePaint); 657 } finally { 658 if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers); 659 } 660 } 661 662 private static native void nDrawArc(long renderer, float left, float top, 663 float right, float bottom, float startAngle, float sweepAngle, 664 boolean useCenter, long paint); 665 666 @Override 667 public void drawARGB(int a, int r, int g, int b) { 668 drawColor((a & 0xFF) << 24 | (r & 0xFF) << 16 | (g & 0xFF) << 8 | (b & 0xFF)); 669 } 670 671 @Override 672 public void drawPatch(NinePatch patch, Rect dst, Paint paint) { 673 Bitmap bitmap = patch.getBitmap(); 674 throwIfCannotDraw(bitmap); 675 // Shaders are ignored when drawing patches 676 final long nativePaint = paint == null ? 0 : paint.mNativePaint; 677 nDrawPatch(mRenderer, bitmap.mNativeBitmap, bitmap.mBuffer, patch.mNativeChunk, 678 dst.left, dst.top, dst.right, dst.bottom, nativePaint); 679 } 680 681 @Override 682 public void drawPatch(NinePatch patch, RectF dst, Paint paint) { 683 Bitmap bitmap = patch.getBitmap(); 684 throwIfCannotDraw(bitmap); 685 // Shaders are ignored when drawing patches 686 final long nativePaint = paint == null ? 0 : paint.mNativePaint; 687 nDrawPatch(mRenderer, bitmap.mNativeBitmap, bitmap.mBuffer, patch.mNativeChunk, 688 dst.left, dst.top, dst.right, dst.bottom, nativePaint); 689 } 690 691 private static native void nDrawPatch(long renderer, long bitmap, byte[] buffer, long chunk, 692 float left, float top, float right, float bottom, long paint); 693 694 @Override 695 public void drawBitmap(Bitmap bitmap, float left, float top, Paint paint) { 696 throwIfCannotDraw(bitmap); 697 // Shaders are ignored when drawing bitmaps 698 int modifiers = paint != null ? setupModifiers(bitmap, paint) : MODIFIER_NONE; 699 try { 700 final long nativePaint = paint == null ? 0 : paint.mNativePaint; 701 nDrawBitmap(mRenderer, bitmap.mNativeBitmap, bitmap.mBuffer, left, top, nativePaint); 702 } finally { 703 if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers); 704 } 705 } 706 707 private static native void nDrawBitmap(long renderer, long bitmap, byte[] buffer, 708 float left, float top, long paint); 709 710 @Override 711 public void drawBitmap(Bitmap bitmap, Matrix matrix, Paint paint) { 712 throwIfCannotDraw(bitmap); 713 // Shaders are ignored when drawing bitmaps 714 int modifiers = paint != null ? setupModifiers(bitmap, paint) : MODIFIER_NONE; 715 try { 716 final long nativePaint = paint == null ? 0 : paint.mNativePaint; 717 nDrawBitmap(mRenderer, bitmap.mNativeBitmap, bitmap.mBuffer, 718 matrix.native_instance, nativePaint); 719 } finally { 720 if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers); 721 } 722 } 723 724 private static native void nDrawBitmap(long renderer, long bitmap, byte[] buffer, 725 long matrix, long paint); 726 727 @Override 728 public void drawBitmap(Bitmap bitmap, Rect src, Rect dst, Paint paint) { 729 throwIfCannotDraw(bitmap); 730 // Shaders are ignored when drawing bitmaps 731 int modifiers = paint != null ? setupModifiers(bitmap, paint) : MODIFIER_NONE; 732 try { 733 final long nativePaint = paint == null ? 0 : paint.mNativePaint; 734 735 int left, top, right, bottom; 736 if (src == null) { 737 left = top = 0; 738 right = bitmap.getWidth(); 739 bottom = bitmap.getHeight(); 740 } else { 741 left = src.left; 742 right = src.right; 743 top = src.top; 744 bottom = src.bottom; 745 } 746 747 nDrawBitmap(mRenderer, bitmap.mNativeBitmap, bitmap.mBuffer, left, top, right, bottom, 748 dst.left, dst.top, dst.right, dst.bottom, nativePaint); 749 } finally { 750 if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers); 751 } 752 } 753 754 @Override 755 public void drawBitmap(Bitmap bitmap, Rect src, RectF dst, Paint paint) { 756 throwIfCannotDraw(bitmap); 757 // Shaders are ignored when drawing bitmaps 758 int modifiers = paint != null ? setupModifiers(bitmap, paint) : MODIFIER_NONE; 759 try { 760 final long nativePaint = paint == null ? 0 : paint.mNativePaint; 761 762 float left, top, right, bottom; 763 if (src == null) { 764 left = top = 0; 765 right = bitmap.getWidth(); 766 bottom = bitmap.getHeight(); 767 } else { 768 left = src.left; 769 right = src.right; 770 top = src.top; 771 bottom = src.bottom; 772 } 773 774 nDrawBitmap(mRenderer, bitmap.mNativeBitmap, bitmap.mBuffer, left, top, right, bottom, 775 dst.left, dst.top, dst.right, dst.bottom, nativePaint); 776 } finally { 777 if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers); 778 } 779 } 780 781 private static native void nDrawBitmap(long renderer, long bitmap, byte[] buffer, 782 float srcLeft, float srcTop, float srcRight, float srcBottom, 783 float left, float top, float right, float bottom, long paint); 784 785 @Override 786 public void drawBitmap(int[] colors, int offset, int stride, float x, float y, 787 int width, int height, boolean hasAlpha, Paint paint) { 788 if (width < 0) { 789 throw new IllegalArgumentException("width must be >= 0"); 790 } 791 792 if (height < 0) { 793 throw new IllegalArgumentException("height must be >= 0"); 794 } 795 796 if (Math.abs(stride) < width) { 797 throw new IllegalArgumentException("abs(stride) must be >= width"); 798 } 799 800 int lastScanline = offset + (height - 1) * stride; 801 int length = colors.length; 802 803 if (offset < 0 || (offset + width > length) || lastScanline < 0 || 804 (lastScanline + width > length)) { 805 throw new ArrayIndexOutOfBoundsException(); 806 } 807 808 // Shaders are ignored when drawing bitmaps 809 final long nativePaint = paint == null ? 0 : paint.mNativePaint; 810 nDrawBitmap(mRenderer, colors, offset, stride, x, y, 811 width, height, hasAlpha, nativePaint); 812 } 813 814 private static native void nDrawBitmap(long renderer, int[] colors, int offset, int stride, 815 float x, float y, int width, int height, boolean hasAlpha, long nativePaint); 816 817 @Override 818 public void drawBitmap(int[] colors, int offset, int stride, int x, int y, 819 int width, int height, boolean hasAlpha, Paint paint) { 820 // Shaders are ignored when drawing bitmaps 821 drawBitmap(colors, offset, stride, (float) x, (float) y, width, height, hasAlpha, paint); 822 } 823 824 @Override 825 public void drawBitmapMesh(Bitmap bitmap, int meshWidth, int meshHeight, float[] verts, 826 int vertOffset, int[] colors, int colorOffset, Paint paint) { 827 throwIfCannotDraw(bitmap); 828 if (meshWidth < 0 || meshHeight < 0 || vertOffset < 0 || colorOffset < 0) { 829 throw new ArrayIndexOutOfBoundsException(); 830 } 831 832 if (meshWidth == 0 || meshHeight == 0) { 833 return; 834 } 835 836 final int count = (meshWidth + 1) * (meshHeight + 1); 837 checkRange(verts.length, vertOffset, count * 2); 838 839 if (colors != null) { 840 checkRange(colors.length, colorOffset, count); 841 } 842 843 int modifiers = paint != null ? setupModifiers(bitmap, paint) : MODIFIER_NONE; 844 try { 845 final long nativePaint = paint == null ? 0 : paint.mNativePaint; 846 nDrawBitmapMesh(mRenderer, bitmap.mNativeBitmap, bitmap.mBuffer, meshWidth, meshHeight, 847 verts, vertOffset, colors, colorOffset, nativePaint); 848 } finally { 849 if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers); 850 } 851 } 852 853 private static native void nDrawBitmapMesh(long renderer, long bitmap, byte[] buffer, 854 int meshWidth, int meshHeight, float[] verts, int vertOffset, 855 int[] colors, int colorOffset, long paint); 856 857 @Override 858 public void drawCircle(float cx, float cy, float radius, Paint paint) { 859 int modifiers = setupModifiers(paint, MODIFIER_SHADER); 860 try { 861 nDrawCircle(mRenderer, cx, cy, radius, paint.mNativePaint); 862 } finally { 863 if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers); 864 } 865 } 866 867 private static native void nDrawCircle(long renderer, float cx, float cy, 868 float radius, long paint); 869 870 @Override 871 public void drawCircle(CanvasProperty<Float> cx, CanvasProperty<Float> cy, 872 CanvasProperty<Float> radius, CanvasProperty<Paint> paint) { 873 nDrawCircle(mRenderer, cx.getNativeContainer(), cy.getNativeContainer(), 874 radius.getNativeContainer(), paint.getNativeContainer()); 875 } 876 877 private static native void nDrawCircle(long renderer, long propCx, 878 long propCy, long propRadius, long propPaint); 879 880 @Override 881 public void drawColor(int color) { 882 drawColor(color, PorterDuff.Mode.SRC_OVER); 883 } 884 885 @Override 886 public void drawColor(int color, PorterDuff.Mode mode) { 887 nDrawColor(mRenderer, color, mode.nativeInt); 888 } 889 890 private static native void nDrawColor(long renderer, int color, int mode); 891 892 @Override 893 public void drawLine(float startX, float startY, float stopX, float stopY, Paint paint) { 894 float[] line = getLineStorage(); 895 line[0] = startX; 896 line[1] = startY; 897 line[2] = stopX; 898 line[3] = stopY; 899 drawLines(line, 0, 4, paint); 900 } 901 902 @Override 903 public void drawLines(float[] pts, int offset, int count, Paint paint) { 904 if (count < 4) return; 905 906 if ((offset | count) < 0 || offset + count > pts.length) { 907 throw new IllegalArgumentException("The lines array must contain 4 elements per line."); 908 } 909 int modifiers = setupModifiers(paint, MODIFIER_SHADER); 910 try { 911 nDrawLines(mRenderer, pts, offset, count, paint.mNativePaint); 912 } finally { 913 if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers); 914 } 915 } 916 917 private static native void nDrawLines(long renderer, float[] points, 918 int offset, int count, long paint); 919 920 @Override 921 public void drawLines(float[] pts, Paint paint) { 922 drawLines(pts, 0, pts.length, paint); 923 } 924 925 @Override 926 public void drawOval(RectF oval, Paint paint) { 927 int modifiers = setupModifiers(paint, MODIFIER_SHADER); 928 try { 929 nDrawOval(mRenderer, oval.left, oval.top, oval.right, oval.bottom, paint.mNativePaint); 930 } finally { 931 if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers); 932 } 933 } 934 935 private static native void nDrawOval(long renderer, float left, float top, 936 float right, float bottom, long paint); 937 938 @Override 939 public void drawPaint(Paint paint) { 940 final Rect r = getInternalClipBounds(); 941 nGetClipBounds(mRenderer, r); 942 drawRect(r.left, r.top, r.right, r.bottom, paint); 943 } 944 945 @Override 946 public void drawPath(Path path, Paint paint) { 947 int modifiers = setupModifiers(paint, MODIFIER_SHADER); 948 try { 949 if (path.isSimplePath) { 950 if (path.rects != null) { 951 nDrawRects(mRenderer, path.rects.mNativeRegion, paint.mNativePaint); 952 } 953 } else { 954 nDrawPath(mRenderer, path.mNativePath, paint.mNativePaint); 955 } 956 } finally { 957 if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers); 958 } 959 } 960 961 private static native void nDrawPath(long renderer, long path, long paint); 962 private static native void nDrawRects(long renderer, long region, long paint); 963 964 void drawRects(float[] rects, int count, Paint paint) { 965 int modifiers = setupModifiers(paint, MODIFIER_SHADER); 966 try { 967 nDrawRects(mRenderer, rects, count, paint.mNativePaint); 968 } finally { 969 if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers); 970 } 971 } 972 973 private static native void nDrawRects(long renderer, float[] rects, int count, long paint); 974 975 @Override 976 public void drawPicture(Picture picture) { 977 if (picture.createdFromStream) { 978 return; 979 } 980 981 picture.endRecording(); 982 // TODO: Implement rendering 983 } 984 985 @Override 986 public void drawPicture(Picture picture, Rect dst) { 987 if (picture.createdFromStream) { 988 return; 989 } 990 991 save(); 992 translate(dst.left, dst.top); 993 if (picture.getWidth() > 0 && picture.getHeight() > 0) { 994 scale(dst.width() / picture.getWidth(), dst.height() / picture.getHeight()); 995 } 996 drawPicture(picture); 997 restore(); 998 } 999 1000 @Override 1001 public void drawPicture(Picture picture, RectF dst) { 1002 if (picture.createdFromStream) { 1003 return; 1004 } 1005 1006 save(); 1007 translate(dst.left, dst.top); 1008 if (picture.getWidth() > 0 && picture.getHeight() > 0) { 1009 scale(dst.width() / picture.getWidth(), dst.height() / picture.getHeight()); 1010 } 1011 drawPicture(picture); 1012 restore(); 1013 } 1014 1015 @Override 1016 public void drawPoint(float x, float y, Paint paint) { 1017 float[] point = getPointStorage(); 1018 point[0] = x; 1019 point[1] = y; 1020 drawPoints(point, 0, 2, paint); 1021 } 1022 1023 @Override 1024 public void drawPoints(float[] pts, Paint paint) { 1025 drawPoints(pts, 0, pts.length, paint); 1026 } 1027 1028 @Override 1029 public void drawPoints(float[] pts, int offset, int count, Paint paint) { 1030 if (count < 2) return; 1031 1032 int modifiers = setupModifiers(paint, MODIFIER_SHADER); 1033 try { 1034 nDrawPoints(mRenderer, pts, offset, count, paint.mNativePaint); 1035 } finally { 1036 if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers); 1037 } 1038 } 1039 1040 private static native void nDrawPoints(long renderer, float[] points, 1041 int offset, int count, long paint); 1042 1043 @SuppressWarnings("deprecation") 1044 @Override 1045 public void drawPosText(char[] text, int index, int count, float[] pos, Paint paint) { 1046 if (index < 0 || index + count > text.length || count * 2 > pos.length) { 1047 throw new IndexOutOfBoundsException(); 1048 } 1049 1050 int modifiers = setupModifiers(paint); 1051 try { 1052 nDrawPosText(mRenderer, text, index, count, pos, paint.mNativePaint); 1053 } finally { 1054 if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers); 1055 } 1056 } 1057 1058 private static native void nDrawPosText(long renderer, char[] text, int index, int count, 1059 float[] pos, long paint); 1060 1061 @SuppressWarnings("deprecation") 1062 @Override 1063 public void drawPosText(String text, float[] pos, Paint paint) { 1064 if (text.length() * 2 > pos.length) { 1065 throw new ArrayIndexOutOfBoundsException(); 1066 } 1067 1068 int modifiers = setupModifiers(paint); 1069 try { 1070 nDrawPosText(mRenderer, text, 0, text.length(), pos, paint.mNativePaint); 1071 } finally { 1072 if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers); 1073 } 1074 } 1075 1076 private static native void nDrawPosText(long renderer, String text, int start, int end, 1077 float[] pos, long paint); 1078 1079 @Override 1080 public void drawRect(float left, float top, float right, float bottom, Paint paint) { 1081 if (left == right || top == bottom) return; 1082 int modifiers = setupModifiers(paint, MODIFIER_SHADER); 1083 try { 1084 nDrawRect(mRenderer, left, top, right, bottom, paint.mNativePaint); 1085 } finally { 1086 if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers); 1087 } 1088 } 1089 1090 private static native void nDrawRect(long renderer, float left, float top, 1091 float right, float bottom, long paint); 1092 1093 @Override 1094 public void drawRect(Rect r, Paint paint) { 1095 drawRect(r.left, r.top, r.right, r.bottom, paint); 1096 } 1097 1098 @Override 1099 public void drawRect(RectF r, Paint paint) { 1100 drawRect(r.left, r.top, r.right, r.bottom, paint); 1101 } 1102 1103 @Override 1104 public void drawRGB(int r, int g, int b) { 1105 drawColor(0xFF000000 | (r & 0xFF) << 16 | (g & 0xFF) << 8 | (b & 0xFF)); 1106 } 1107 1108 @Override 1109 public void drawRoundRect(float left, float top, float right, float bottom, float rx, float ry, 1110 Paint paint) { 1111 int modifiers = setupModifiers(paint, MODIFIER_SHADER); 1112 try { 1113 nDrawRoundRect(mRenderer, left, top, right, bottom, rx, ry, paint.mNativePaint); 1114 } finally { 1115 if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers); 1116 } 1117 } 1118 1119 private static native void nDrawRoundRect(long renderer, float left, float top, 1120 float right, float bottom, float rx, float y, long paint); 1121 1122 @Override 1123 public void drawText(char[] text, int index, int count, float x, float y, Paint paint) { 1124 if ((index | count | (index + count) | (text.length - index - count)) < 0) { 1125 throw new IndexOutOfBoundsException(); 1126 } 1127 1128 int modifiers = setupModifiers(paint); 1129 try { 1130 nDrawText(mRenderer, text, index, count, x, y, paint.mBidiFlags, paint.mNativePaint, 1131 paint.mNativeTypeface); 1132 } finally { 1133 if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers); 1134 } 1135 } 1136 1137 private static native void nDrawText(long renderer, char[] text, int index, int count, 1138 float x, float y, int bidiFlags, long paint, long typeface); 1139 1140 @Override 1141 public void drawText(CharSequence text, int start, int end, float x, float y, Paint paint) { 1142 int modifiers = setupModifiers(paint); 1143 try { 1144 if (text instanceof String || text instanceof SpannedString || 1145 text instanceof SpannableString) { 1146 nDrawText(mRenderer, text.toString(), start, end, x, y, paint.mBidiFlags, 1147 paint.mNativePaint, paint.mNativeTypeface); 1148 } else if (text instanceof GraphicsOperations) { 1149 ((GraphicsOperations) text).drawText(this, start, end, x, y, 1150 paint); 1151 } else { 1152 char[] buf = TemporaryBuffer.obtain(end - start); 1153 TextUtils.getChars(text, start, end, buf, 0); 1154 nDrawText(mRenderer, buf, 0, end - start, x, y, 1155 paint.mBidiFlags, paint.mNativePaint, paint.mNativeTypeface); 1156 TemporaryBuffer.recycle(buf); 1157 } 1158 } finally { 1159 if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers); 1160 } 1161 } 1162 1163 @Override 1164 public void drawText(String text, int start, int end, float x, float y, Paint paint) { 1165 if ((start | end | (end - start) | (text.length() - end)) < 0) { 1166 throw new IndexOutOfBoundsException(); 1167 } 1168 1169 int modifiers = setupModifiers(paint); 1170 try { 1171 nDrawText(mRenderer, text, start, end, x, y, paint.mBidiFlags, paint.mNativePaint, 1172 paint.mNativeTypeface); 1173 } finally { 1174 if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers); 1175 } 1176 } 1177 1178 private static native void nDrawText(long renderer, String text, int start, int end, 1179 float x, float y, int bidiFlags, long paint, long typeface); 1180 1181 @Override 1182 public void drawText(String text, float x, float y, Paint paint) { 1183 int modifiers = setupModifiers(paint); 1184 try { 1185 nDrawText(mRenderer, text, 0, text.length(), x, y, paint.mBidiFlags, 1186 paint.mNativePaint, paint.mNativeTypeface); 1187 } finally { 1188 if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers); 1189 } 1190 } 1191 1192 @Override 1193 public void drawTextOnPath(char[] text, int index, int count, Path path, float hOffset, 1194 float vOffset, Paint paint) { 1195 if (index < 0 || index + count > text.length) { 1196 throw new ArrayIndexOutOfBoundsException(); 1197 } 1198 1199 int modifiers = setupModifiers(paint); 1200 try { 1201 nDrawTextOnPath(mRenderer, text, index, count, path.mNativePath, hOffset, vOffset, 1202 paint.mBidiFlags, paint.mNativePaint); 1203 } finally { 1204 if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers); 1205 } 1206 } 1207 1208 private static native void nDrawTextOnPath(long renderer, char[] text, int index, int count, 1209 long path, float hOffset, float vOffset, int bidiFlags, long nativePaint); 1210 1211 @Override 1212 public void drawTextOnPath(String text, Path path, float hOffset, float vOffset, Paint paint) { 1213 if (text.length() == 0) return; 1214 1215 int modifiers = setupModifiers(paint); 1216 try { 1217 nDrawTextOnPath(mRenderer, text, 0, text.length(), path.mNativePath, hOffset, vOffset, 1218 paint.mBidiFlags, paint.mNativePaint); 1219 } finally { 1220 if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers); 1221 } 1222 } 1223 1224 private static native void nDrawTextOnPath(long renderer, String text, int start, int end, 1225 long path, float hOffset, float vOffset, int bidiFlags, long nativePaint); 1226 1227 @Override 1228 public void drawTextRun(char[] text, int index, int count, int contextIndex, int contextCount, 1229 float x, float y, int dir, Paint paint) { 1230 if ((index | count | text.length - index - count) < 0) { 1231 throw new IndexOutOfBoundsException(); 1232 } 1233 if (dir != DIRECTION_LTR && dir != DIRECTION_RTL) { 1234 throw new IllegalArgumentException("Unknown direction: " + dir); 1235 } 1236 1237 int modifiers = setupModifiers(paint); 1238 try { 1239 nDrawTextRun(mRenderer, text, index, count, contextIndex, contextCount, x, y, dir, 1240 paint.mNativePaint, paint.mNativeTypeface); 1241 } finally { 1242 if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers); 1243 } 1244 } 1245 1246 private static native void nDrawTextRun(long renderer, char[] text, int index, int count, 1247 int contextIndex, int contextCount, float x, float y, int dir, long nativePaint, long nativeTypeface); 1248 1249 @Override 1250 public void drawTextRun(CharSequence text, int start, int end, int contextStart, int contextEnd, 1251 float x, float y, int dir, Paint paint) { 1252 if ((start | end | end - start | text.length() - end) < 0) { 1253 throw new IndexOutOfBoundsException(); 1254 } 1255 1256 int modifiers = setupModifiers(paint); 1257 try { 1258 int flags = dir == 0 ? 0 : 1; 1259 if (text instanceof String || text instanceof SpannedString || 1260 text instanceof SpannableString) { 1261 nDrawTextRun(mRenderer, text.toString(), start, end, contextStart, 1262 contextEnd, x, y, flags, paint.mNativePaint, paint.mNativeTypeface); 1263 } else if (text instanceof GraphicsOperations) { 1264 ((GraphicsOperations) text).drawTextRun(this, start, end, 1265 contextStart, contextEnd, x, y, flags, paint); 1266 } else { 1267 int contextLen = contextEnd - contextStart; 1268 int len = end - start; 1269 char[] buf = TemporaryBuffer.obtain(contextLen); 1270 TextUtils.getChars(text, contextStart, contextEnd, buf, 0); 1271 nDrawTextRun(mRenderer, buf, start - contextStart, len, 0, contextLen, 1272 x, y, flags, paint.mNativePaint, paint.mNativeTypeface); 1273 TemporaryBuffer.recycle(buf); 1274 } 1275 } finally { 1276 if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers); 1277 } 1278 } 1279 1280 private static native void nDrawTextRun(long renderer, String text, int start, int end, 1281 int contextStart, int contextEnd, float x, float y, int flags, long nativePaint, long nativeTypeface); 1282 1283 @Override 1284 public void drawVertices(VertexMode mode, int vertexCount, float[] verts, int vertOffset, 1285 float[] texs, int texOffset, int[] colors, int colorOffset, short[] indices, 1286 int indexOffset, int indexCount, Paint paint) { 1287 // TODO: Implement 1288 } 1289 1290 private int setupModifiers(Bitmap b, Paint paint) { 1291 if (b.getConfig() != Bitmap.Config.ALPHA_8) { 1292 return MODIFIER_NONE; 1293 } else { 1294 return setupModifiers(paint); 1295 } 1296 } 1297 1298 private int setupModifiers(Paint paint) { 1299 int modifiers = MODIFIER_NONE; 1300 1301 final Shader shader = paint.getShader(); 1302 if (shader != null) { 1303 nSetupShader(mRenderer, shader.native_shader); 1304 modifiers |= MODIFIER_SHADER; 1305 } 1306 1307 return modifiers; 1308 } 1309 1310 private int setupModifiers(Paint paint, int flags) { 1311 int modifiers = MODIFIER_NONE; 1312 1313 final Shader shader = paint.getShader(); 1314 if (shader != null && (flags & MODIFIER_SHADER) != 0) { 1315 nSetupShader(mRenderer, shader.native_shader); 1316 modifiers |= MODIFIER_SHADER; 1317 } 1318 1319 return modifiers; 1320 } 1321 1322 private static native void nSetupShader(long renderer, long shader); 1323 1324 private static native void nResetModifiers(long renderer, int modifiers); 1325} 1326