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