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