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