GLES20Canvas.java revision 84fce187b0ae79adc5b4e64c26f72c8ed59e9703
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 // TODO: Implement 912 } 913 914 @Override 915 public void drawPicture(Picture picture, Rect dst) { 916 // TODO: Implement 917 } 918 919 @Override 920 public void drawPicture(Picture picture, RectF dst) { 921 // TODO: Implement 922 } 923 924 @Override 925 public void drawPoint(float x, float y, Paint paint) { 926 mPoint[0] = x; 927 mPoint[1] = y; 928 drawPoints(mPoint, 0, 2, paint); 929 } 930 931 @Override 932 public void drawPoints(float[] pts, Paint paint) { 933 drawPoints(pts, 0, pts.length, paint); 934 } 935 936 @Override 937 public void drawPoints(float[] pts, int offset, int count, Paint paint) { 938 int modifiers = setupModifiers(paint); 939 nDrawPoints(mRenderer, pts, offset, count, paint.mNativePaint); 940 if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers); 941 } 942 943 private static native void nDrawPoints(int renderer, float[] points, 944 int offset, int count, int paint); 945 946 @Override 947 public void drawPosText(char[] text, int index, int count, float[] pos, Paint paint) { 948 if (index < 0 || index + count > text.length || count * 2 > pos.length) { 949 throw new IndexOutOfBoundsException(); 950 } 951 952 int modifiers = setupModifiers(paint); 953 try { 954 nDrawPosText(mRenderer, text, index, count, pos, paint.mNativePaint); 955 } finally { 956 if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers); 957 } 958 } 959 960 private static native void nDrawPosText(int renderer, char[] text, int index, int count, 961 float[] pos, int paint); 962 963 @Override 964 public void drawPosText(String text, float[] pos, Paint paint) { 965 if (text.length() * 2 > pos.length) { 966 throw new ArrayIndexOutOfBoundsException(); 967 } 968 969 int modifiers = setupModifiers(paint); 970 try { 971 nDrawPosText(mRenderer, text, 0, text.length(), pos, paint.mNativePaint); 972 } finally { 973 if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers); 974 } 975 } 976 977 private static native void nDrawPosText(int renderer, String text, int start, int end, 978 float[] pos, int paint); 979 980 @Override 981 public void drawRect(float left, float top, float right, float bottom, Paint paint) { 982 int modifiers = setupModifiers(paint); 983 nDrawRect(mRenderer, left, top, right, bottom, paint.mNativePaint); 984 if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers); 985 } 986 987 private static native void nDrawRect(int renderer, float left, float top, 988 float right, float bottom, int paint); 989 990 @Override 991 public void drawRect(Rect r, Paint paint) { 992 drawRect(r.left, r.top, r.right, r.bottom, paint); 993 } 994 995 @Override 996 public void drawRect(RectF r, Paint paint) { 997 drawRect(r.left, r.top, r.right, r.bottom, paint); 998 } 999 1000 @Override 1001 public void drawRGB(int r, int g, int b) { 1002 drawColor(0xFF000000 | (r & 0xFF) << 16 | (g & 0xFF) << 8 | (b & 0xFF)); 1003 } 1004 1005 @Override 1006 public void drawRoundRect(RectF rect, float rx, float ry, Paint paint) { 1007 int modifiers = setupModifiers(paint); 1008 nDrawRoundRect(mRenderer, rect.left, rect.top, rect.right, rect.bottom, 1009 rx, ry, paint.mNativePaint); 1010 if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers); 1011 } 1012 1013 private static native void nDrawRoundRect(int renderer, float left, float top, 1014 float right, float bottom, float rx, float y, int paint); 1015 1016 @Override 1017 public void drawText(char[] text, int index, int count, float x, float y, Paint paint) { 1018 if ((index | count | (index + count) | (text.length - index - count)) < 0) { 1019 throw new IndexOutOfBoundsException(); 1020 } 1021 1022 int modifiers = setupModifiers(paint); 1023 try { 1024 nDrawText(mRenderer, text, index, count, x, y, paint.mBidiFlags, paint.mNativePaint); 1025 } finally { 1026 if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers); 1027 } 1028 } 1029 1030 private static native void nDrawText(int renderer, char[] text, int index, int count, 1031 float x, float y, int bidiFlags, int paint); 1032 1033 @Override 1034 public void drawText(CharSequence text, int start, int end, float x, float y, Paint paint) { 1035 int modifiers = setupModifiers(paint); 1036 try { 1037 if (text instanceof String || text instanceof SpannedString || 1038 text instanceof SpannableString) { 1039 nDrawText(mRenderer, text.toString(), start, end, x, y, paint.mBidiFlags, 1040 paint.mNativePaint); 1041 } else if (text instanceof GraphicsOperations) { 1042 ((GraphicsOperations) text).drawText(this, start, end, x, y, 1043 paint); 1044 } else { 1045 char[] buf = TemporaryBuffer.obtain(end - start); 1046 TextUtils.getChars(text, start, end, buf, 0); 1047 nDrawText(mRenderer, buf, 0, end - start, x, y, 1048 paint.mBidiFlags, paint.mNativePaint); 1049 TemporaryBuffer.recycle(buf); 1050 } 1051 } finally { 1052 if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers); 1053 } 1054 } 1055 1056 @Override 1057 public void drawText(String text, int start, int end, float x, float y, Paint paint) { 1058 if ((start | end | (end - start) | (text.length() - end)) < 0) { 1059 throw new IndexOutOfBoundsException(); 1060 } 1061 1062 int modifiers = setupModifiers(paint); 1063 try { 1064 nDrawText(mRenderer, text, start, end, x, y, paint.mBidiFlags, paint.mNativePaint); 1065 } finally { 1066 if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers); 1067 } 1068 } 1069 1070 private static native void nDrawText(int renderer, String text, int start, int end, 1071 float x, float y, int bidiFlags, int paint); 1072 1073 @Override 1074 public void drawText(String text, float x, float y, Paint paint) { 1075 int modifiers = setupModifiers(paint); 1076 try { 1077 nDrawText(mRenderer, text, 0, text.length(), x, y, paint.mBidiFlags, 1078 paint.mNativePaint); 1079 } finally { 1080 if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers); 1081 } 1082 } 1083 1084 @Override 1085 public void drawTextOnPath(char[] text, int index, int count, Path path, float hOffset, 1086 float vOffset, Paint paint) { 1087 // TODO: Implement 1088 } 1089 1090 @Override 1091 public void drawTextOnPath(String text, Path path, float hOffset, float vOffset, Paint paint) { 1092 // TODO: Implement 1093 } 1094 1095 @Override 1096 public void drawTextRun(char[] text, int index, int count, int contextIndex, int contextCount, 1097 float x, float y, int dir, Paint paint) { 1098 if ((index | count | text.length - index - count) < 0) { 1099 throw new IndexOutOfBoundsException(); 1100 } 1101 if (dir != DIRECTION_LTR && dir != DIRECTION_RTL) { 1102 throw new IllegalArgumentException("Unknown direction: " + dir); 1103 } 1104 1105 int modifiers = setupModifiers(paint); 1106 try { 1107 nDrawTextRun(mRenderer, text, index, count, contextIndex, contextCount, x, y, dir, 1108 paint.mNativePaint); 1109 } finally { 1110 if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers); 1111 } 1112 } 1113 1114 private static native void nDrawTextRun(int renderer, char[] text, int index, int count, 1115 int contextIndex, int contextCount, float x, float y, int dir, int nativePaint); 1116 1117 @Override 1118 public void drawTextRun(CharSequence text, int start, int end, int contextStart, int contextEnd, 1119 float x, float y, int dir, Paint paint) { 1120 if ((start | end | end - start | text.length() - end) < 0) { 1121 throw new IndexOutOfBoundsException(); 1122 } 1123 1124 int modifiers = setupModifiers(paint); 1125 try { 1126 int flags = dir == 0 ? 0 : 1; 1127 if (text instanceof String || text instanceof SpannedString || 1128 text instanceof SpannableString) { 1129 nDrawTextRun(mRenderer, text.toString(), start, end, contextStart, 1130 contextEnd, x, y, flags, paint.mNativePaint); 1131 } else if (text instanceof GraphicsOperations) { 1132 ((GraphicsOperations) text).drawTextRun(this, start, end, 1133 contextStart, contextEnd, x, y, flags, paint); 1134 } else { 1135 int contextLen = contextEnd - contextStart; 1136 int len = end - start; 1137 char[] buf = TemporaryBuffer.obtain(contextLen); 1138 TextUtils.getChars(text, contextStart, contextEnd, buf, 0); 1139 nDrawTextRun(mRenderer, buf, start - contextStart, len, 0, contextLen, 1140 x, y, flags, paint.mNativePaint); 1141 TemporaryBuffer.recycle(buf); 1142 } 1143 } finally { 1144 if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers); 1145 } 1146 } 1147 1148 private static native void nDrawTextRun(int renderer, String text, int start, int end, 1149 int contextStart, int contextEnd, float x, float y, int flags, int nativePaint); 1150 1151 @Override 1152 public void drawVertices(VertexMode mode, int vertexCount, float[] verts, int vertOffset, 1153 float[] texs, int texOffset, int[] colors, int colorOffset, short[] indices, 1154 int indexOffset, int indexCount, Paint paint) { 1155 // TODO: Implement 1156 } 1157 1158 private int setupModifiers(Bitmap b, Paint paint) { 1159 if (b.getConfig() == Bitmap.Config.ALPHA_8) { 1160 return setupModifiers(paint); 1161 } 1162 1163 final ColorFilter filter = paint.getColorFilter(); 1164 if (filter != null) { 1165 nSetupColorFilter(mRenderer, filter.nativeColorFilter); 1166 return MODIFIER_COLOR_FILTER; 1167 } 1168 1169 return MODIFIER_NONE; 1170 } 1171 1172 private int setupModifiers(Paint paint) { 1173 int modifiers = MODIFIER_NONE; 1174 1175 if (paint.hasShadow) { 1176 nSetupShadow(mRenderer, paint.shadowRadius, paint.shadowDx, paint.shadowDy, 1177 paint.shadowColor); 1178 modifiers |= MODIFIER_SHADOW; 1179 } 1180 1181 final Shader shader = paint.getShader(); 1182 if (shader != null) { 1183 nSetupShader(mRenderer, shader.native_shader); 1184 modifiers |= MODIFIER_SHADER; 1185 } 1186 1187 final ColorFilter filter = paint.getColorFilter(); 1188 if (filter != null) { 1189 nSetupColorFilter(mRenderer, filter.nativeColorFilter); 1190 modifiers |= MODIFIER_COLOR_FILTER; 1191 } 1192 1193 return modifiers; 1194 } 1195 1196 private int setupColorFilter(Paint paint) { 1197 final ColorFilter filter = paint.getColorFilter(); 1198 if (filter != null) { 1199 nSetupColorFilter(mRenderer, filter.nativeColorFilter); 1200 return MODIFIER_COLOR_FILTER; 1201 } 1202 return MODIFIER_NONE; 1203 } 1204 1205 private static native void nSetupShader(int renderer, int shader); 1206 private static native void nSetupColorFilter(int renderer, int colorFilter); 1207 private static native void nSetupShadow(int renderer, float radius, 1208 float dx, float dy, int color); 1209 1210 private static native void nResetModifiers(int renderer, int modifiers); 1211} 1212