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