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