GLES20Canvas.java revision 171c592f0b7066acf279863c8a52ddabea49d3db
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.TemporaryBuffer; 33import android.text.GraphicsOperations; 34import android.text.SpannableString; 35import android.text.SpannedString; 36import android.text.TextUtils; 37 38/** 39 * An implementation of Canvas on top of OpenGL ES 2.0. 40 */ 41class GLES20Canvas extends HardwareCanvas { 42 private final boolean mOpaque; 43 private int mRenderer; 44 45 // The native renderer will be destroyed when this object dies. 46 // DO NOT overwrite this reference once it is set. 47 private CanvasFinalizer mFinalizer; 48 49 private int mWidth; 50 private int mHeight; 51 52 private final float[] mPoint = new float[2]; 53 private final float[] mLine = new float[4]; 54 55 private final Rect mClipBounds = new Rect(); 56 57 private DrawFilter mFilter; 58 59 private boolean mContextLocked; 60 61 /////////////////////////////////////////////////////////////////////////// 62 // JNI 63 /////////////////////////////////////////////////////////////////////////// 64 65 private static native boolean nIsAvailable(); 66 private static boolean sIsAvailable = nIsAvailable(); 67 68 static boolean isAvailable() { 69 return sIsAvailable; 70 } 71 72 /////////////////////////////////////////////////////////////////////////// 73 // Constructors 74 /////////////////////////////////////////////////////////////////////////// 75 76 GLES20Canvas(boolean translucent) { 77 this(false, translucent); 78 } 79 80 protected GLES20Canvas(boolean record, boolean translucent) { 81 mOpaque = !translucent; 82 83 setupRenderer(record); 84 } 85 86 protected void setupRenderer(boolean record) { 87 if (record) { 88 mRenderer = nGetDisplayListRenderer(mRenderer); 89 } else { 90 mRenderer = nCreateRenderer(); 91 } 92 93 if (mRenderer == 0) { 94 throw new IllegalStateException("Could not create GLES20Canvas renderer"); 95 } else { 96 mFinalizer = CanvasFinalizer.getFinalizer(mFinalizer, mRenderer); 97 } 98 } 99 100 private native int nCreateRenderer(); 101 private static native int nGetDisplayListRenderer(int renderer); 102 private static native void nDestroyRenderer(int renderer); 103 104 private static class CanvasFinalizer { 105 int mRenderer; 106 107 // Factory method returns new instance if old one is null, or old instance 108 // otherwise, destroying native renderer along the way as necessary 109 static CanvasFinalizer getFinalizer(CanvasFinalizer oldFinalizer, int renderer) { 110 if (oldFinalizer == null) { 111 return new CanvasFinalizer(renderer); 112 } 113 oldFinalizer.replaceNativeObject(renderer); 114 return oldFinalizer; 115 } 116 117 private CanvasFinalizer(int renderer) { 118 mRenderer = renderer; 119 } 120 121 private void replaceNativeObject(int newRenderer) { 122 if (mRenderer != 0 && newRenderer != mRenderer) { 123 nDestroyRenderer(mRenderer); 124 } 125 mRenderer = newRenderer; 126 } 127 128 @Override 129 protected void finalize() throws Throwable { 130 try { 131 replaceNativeObject(0); 132 } finally { 133 super.finalize(); 134 } 135 } 136 } 137 138 /////////////////////////////////////////////////////////////////////////// 139 // Canvas management 140 /////////////////////////////////////////////////////////////////////////// 141 142 @Override 143 public boolean isOpaque() { 144 return mOpaque; 145 } 146 147 @Override 148 public int getWidth() { 149 return mWidth; 150 } 151 152 @Override 153 public int getHeight() { 154 return mHeight; 155 } 156 157 /////////////////////////////////////////////////////////////////////////// 158 // Setup 159 /////////////////////////////////////////////////////////////////////////// 160 161 @Override 162 public void setViewport(int width, int height) { 163 mWidth = width; 164 mHeight = height; 165 166 nSetViewport(mRenderer, width, height); 167 } 168 169 private native void nSetViewport(int renderer, int width, int height); 170 171 @Override 172 void onPreDraw() { 173 nPrepare(mRenderer, mOpaque); 174 } 175 176 private native void nPrepare(int renderer, boolean opaque); 177 178 @Override 179 void onPostDraw() { 180 nFinish(mRenderer); 181 } 182 183 private native void nFinish(int renderer); 184 185 @Override 186 public boolean acquireContext() { 187 if (!mContextLocked) { 188 nAcquireContext(mRenderer); 189 mContextLocked = true; 190 } 191 return mContextLocked; 192 } 193 194 private native void nAcquireContext(int renderer); 195 196 @Override 197 public void releaseContext() { 198 if (mContextLocked) { 199 nReleaseContext(mRenderer); 200 mContextLocked = false; 201 } 202 } 203 204 private native void nReleaseContext(int renderer); 205 206 /////////////////////////////////////////////////////////////////////////// 207 // Display list 208 /////////////////////////////////////////////////////////////////////////// 209 210 int getDisplayList() { 211 return nGetDisplayList(mRenderer); 212 } 213 214 private native int nGetDisplayList(int renderer); 215 216 static void destroyDisplayList(int displayList) { 217 nDestroyDisplayList(displayList); 218 } 219 220 private static native void nDestroyDisplayList(int displayList); 221 222 @Override 223 public void drawDisplayList(DisplayList displayList) { 224 nDrawDisplayList(mRenderer, ((GLES20DisplayList) displayList).mNativeDisplayList); 225 } 226 227 private native void nDrawDisplayList(int renderer, int displayList); 228 229 /////////////////////////////////////////////////////////////////////////// 230 // Clipping 231 /////////////////////////////////////////////////////////////////////////// 232 233 @Override 234 public boolean clipPath(Path path) { 235 throw new UnsupportedOperationException(); 236 } 237 238 @Override 239 public boolean clipPath(Path path, Region.Op op) { 240 throw new UnsupportedOperationException(); 241 } 242 243 @Override 244 public boolean clipRect(float left, float top, float right, float bottom) { 245 return nClipRect(mRenderer, left, top, right, bottom, Region.Op.INTERSECT.nativeInt); 246 } 247 248 private native boolean nClipRect(int renderer, float left, float top, 249 float right, float bottom, int op); 250 251 @Override 252 public boolean clipRect(float left, float top, float right, float bottom, Region.Op op) { 253 return nClipRect(mRenderer, left, top, right, bottom, op.nativeInt); 254 } 255 256 @Override 257 public boolean clipRect(int left, int top, int right, int bottom) { 258 return nClipRect(mRenderer, left, top, right, bottom, Region.Op.INTERSECT.nativeInt); 259 } 260 261 private native boolean nClipRect(int renderer, int left, int top, int right, int bottom, int op); 262 263 @Override 264 public boolean clipRect(Rect rect) { 265 return nClipRect(mRenderer, rect.left, rect.top, rect.right, rect.bottom, 266 Region.Op.INTERSECT.nativeInt); 267 } 268 269 @Override 270 public boolean clipRect(Rect rect, Region.Op op) { 271 return nClipRect(mRenderer, rect.left, rect.top, rect.right, rect.bottom, op.nativeInt); 272 } 273 274 @Override 275 public boolean clipRect(RectF rect) { 276 return nClipRect(mRenderer, rect.left, rect.top, rect.right, rect.bottom, 277 Region.Op.INTERSECT.nativeInt); 278 } 279 280 @Override 281 public boolean clipRect(RectF rect, Region.Op op) { 282 return nClipRect(mRenderer, rect.left, rect.top, rect.right, rect.bottom, op.nativeInt); 283 } 284 285 @Override 286 public boolean clipRegion(Region region) { 287 throw new UnsupportedOperationException(); 288 } 289 290 @Override 291 public boolean clipRegion(Region region, Region.Op op) { 292 throw new UnsupportedOperationException(); 293 } 294 295 @Override 296 public boolean getClipBounds(Rect bounds) { 297 return nGetClipBounds(mRenderer, bounds); 298 } 299 300 private native boolean nGetClipBounds(int renderer, Rect bounds); 301 302 @Override 303 public boolean quickReject(float left, float top, float right, float bottom, EdgeType type) { 304 return nQuickReject(mRenderer, left, top, right, bottom, type.nativeInt); 305 } 306 307 private native boolean nQuickReject(int renderer, float left, float top, 308 float right, float bottom, int edge); 309 310 @Override 311 public boolean quickReject(Path path, EdgeType type) { 312 throw new UnsupportedOperationException(); 313 } 314 315 @Override 316 public boolean quickReject(RectF rect, EdgeType type) { 317 return quickReject(rect.left, rect.top, rect.right, rect.bottom, type); 318 } 319 320 /////////////////////////////////////////////////////////////////////////// 321 // Transformations 322 /////////////////////////////////////////////////////////////////////////// 323 324 @Override 325 public void translate(float dx, float dy) { 326 nTranslate(mRenderer, dx, dy); 327 } 328 329 private native void nTranslate(int renderer, float dx, float dy); 330 331 @Override 332 public void skew(float sx, float sy) { 333 throw new UnsupportedOperationException(); 334 } 335 336 @Override 337 public void rotate(float degrees) { 338 nRotate(mRenderer, degrees); 339 } 340 341 private native void nRotate(int renderer, float degrees); 342 343 @Override 344 public void scale(float sx, float sy) { 345 nScale(mRenderer, sx, sy); 346 } 347 348 private native void nScale(int renderer, float sx, float sy); 349 350 @Override 351 public void setMatrix(Matrix matrix) { 352 nSetMatrix(mRenderer, matrix.native_instance); 353 } 354 355 private native void nSetMatrix(int renderer, int matrix); 356 357 @Override 358 public int getNativeMatrix() { 359 return nGetMatrix(mRenderer); 360 } 361 362 private native int nGetMatrix(int renderer); 363 364 @Override 365 public void getMatrix(Matrix matrix) { 366 nGetMatrix(mRenderer, matrix.native_instance); 367 } 368 369 private native void nGetMatrix(int renderer, int matrix); 370 371 @Override 372 public void concat(Matrix matrix) { 373 nConcatMatrix(mRenderer, matrix.native_instance); 374 } 375 376 private native void nConcatMatrix(int renderer, int matrix); 377 378 /////////////////////////////////////////////////////////////////////////// 379 // State management 380 /////////////////////////////////////////////////////////////////////////// 381 382 @Override 383 public int save() { 384 return nSave(mRenderer, Canvas.CLIP_SAVE_FLAG | Canvas.MATRIX_SAVE_FLAG); 385 } 386 387 @Override 388 public int save(int saveFlags) { 389 return nSave(mRenderer, saveFlags); 390 } 391 392 private native int nSave(int renderer, int flags); 393 394 @Override 395 public int saveLayer(RectF bounds, Paint paint, int saveFlags) { 396 return saveLayer(bounds.left, bounds.top, bounds.right, bounds.bottom, paint, saveFlags); 397 } 398 399 @Override 400 public int saveLayer(float left, float top, float right, float bottom, Paint paint, 401 int saveFlags) { 402 boolean hasColorFilter = paint != null && setupColorFilter(paint); 403 final int nativePaint = paint == null ? 0 : paint.mNativePaint; 404 int count = nSaveLayer(mRenderer, left, top, right, bottom, nativePaint, saveFlags); 405 if (hasColorFilter) nResetModifiers(mRenderer); 406 return count; 407 } 408 409 private native int nSaveLayer(int renderer, float left, float top, float right, float bottom, 410 int paint, int saveFlags); 411 412 @Override 413 public int saveLayerAlpha(RectF bounds, int alpha, int saveFlags) { 414 return saveLayerAlpha(bounds.left, bounds.top, bounds.right, bounds.bottom, 415 alpha, saveFlags); 416 } 417 418 @Override 419 public int saveLayerAlpha(float left, float top, float right, float bottom, int alpha, 420 int saveFlags) { 421 return nSaveLayerAlpha(mRenderer, left, top, right, bottom, alpha, saveFlags); 422 } 423 424 private native int nSaveLayerAlpha(int renderer, float left, float top, float right, 425 float bottom, int alpha, int saveFlags); 426 427 @Override 428 public void restore() { 429 nRestore(mRenderer); 430 } 431 432 private native void nRestore(int renderer); 433 434 @Override 435 public void restoreToCount(int saveCount) { 436 nRestoreToCount(mRenderer, saveCount); 437 } 438 439 private native void nRestoreToCount(int renderer, int saveCount); 440 441 @Override 442 public int getSaveCount() { 443 return nGetSaveCount(mRenderer); 444 } 445 446 private native int nGetSaveCount(int renderer); 447 448 /////////////////////////////////////////////////////////////////////////// 449 // Filtering 450 /////////////////////////////////////////////////////////////////////////// 451 452 @Override 453 public void setDrawFilter(DrawFilter filter) { 454 mFilter = filter; 455 } 456 457 @Override 458 public DrawFilter getDrawFilter() { 459 return mFilter; 460 } 461 462 /////////////////////////////////////////////////////////////////////////// 463 // Drawing 464 /////////////////////////////////////////////////////////////////////////// 465 466 @Override 467 public void drawArc(RectF oval, float startAngle, float sweepAngle, boolean useCenter, 468 Paint paint) { 469 throw new UnsupportedOperationException(); 470 } 471 472 @Override 473 public void drawARGB(int a, int r, int g, int b) { 474 drawColor((a & 0xFF) << 24 | (r & 0xFF) << 16 | (g & 0xFF) << 8 | (b & 0xFF)); 475 } 476 477 @Override 478 public void drawPatch(Bitmap bitmap, byte[] chunks, RectF dst, Paint paint) { 479 // Shaders are ignored when drawing patches 480 boolean hasColorFilter = paint != null && setupColorFilter(paint); 481 final int nativePaint = paint == null ? 0 : paint.mNativePaint; 482 nDrawPatch(mRenderer, bitmap.mNativeBitmap, bitmap.mBuffer, chunks, 483 dst.left, dst.top, dst.right, dst.bottom, nativePaint); 484 if (hasColorFilter) nResetModifiers(mRenderer); 485 } 486 487 private native void nDrawPatch(int renderer, int bitmap, byte[] buffer, byte[] chunks, 488 float left, float top, float right, float bottom, int paint); 489 490 @Override 491 public void drawBitmap(Bitmap bitmap, float left, float top, Paint paint) { 492 // Shaders are ignored when drawing bitmaps 493 boolean hasColorFilter = paint != null && setupColorFilter(paint); 494 final int nativePaint = paint == null ? 0 : paint.mNativePaint; 495 nDrawBitmap(mRenderer, bitmap.mNativeBitmap, bitmap.mBuffer, left, top, nativePaint); 496 if (hasColorFilter) nResetModifiers(mRenderer); 497 } 498 499 private native void nDrawBitmap( 500 int renderer, int bitmap, byte[] buffer, float left, float top, int paint); 501 502 @Override 503 public void drawBitmap(Bitmap bitmap, Matrix matrix, Paint paint) { 504 // Shaders are ignored when drawing bitmaps 505 boolean hasColorFilter = paint != null && setupColorFilter(paint); 506 final int nativePaint = paint == null ? 0 : paint.mNativePaint; 507 nDrawBitmap(mRenderer, bitmap.mNativeBitmap, bitmap.mBuffer, 508 matrix.native_instance, nativePaint); 509 if (hasColorFilter) nResetModifiers(mRenderer); 510 } 511 512 private native void nDrawBitmap(int renderer, int bitmap, byte[] buff, int matrix, int paint); 513 514 @Override 515 public void drawBitmap(Bitmap bitmap, Rect src, Rect dst, Paint paint) { 516 // Shaders are ignored when drawing bitmaps 517 boolean hasColorFilter = paint != null && setupColorFilter(paint); 518 final int nativePaint = paint == null ? 0 : paint.mNativePaint; 519 520 int left, top, right, bottom; 521 if (src == null) { 522 left = top = 0; 523 right = bitmap.getWidth(); 524 bottom = bitmap.getHeight(); 525 } else { 526 left = src.left; 527 right = src.right; 528 top = src.top; 529 bottom = src.bottom; 530 } 531 532 nDrawBitmap(mRenderer, bitmap.mNativeBitmap, bitmap.mBuffer, left, top, right, bottom, 533 dst.left, dst.top, dst.right, dst.bottom, nativePaint); 534 if (hasColorFilter) nResetModifiers(mRenderer); 535 } 536 537 @Override 538 public void drawBitmap(Bitmap bitmap, Rect src, RectF dst, Paint paint) { 539 // Shaders are ignored when drawing bitmaps 540 boolean hasColorFilter = paint != null && setupColorFilter(paint); 541 final int nativePaint = paint == null ? 0 : paint.mNativePaint; 542 nDrawBitmap(mRenderer, bitmap.mNativeBitmap, bitmap.mBuffer, src.left, src.top, src.right, 543 src.bottom, dst.left, dst.top, dst.right, dst.bottom, nativePaint); 544 if (hasColorFilter) nResetModifiers(mRenderer); 545 } 546 547 private native void nDrawBitmap(int renderer, int bitmap, byte[] buffer, 548 float srcLeft, float srcTop, float srcRight, float srcBottom, 549 float left, float top, float right, float bottom, int paint); 550 551 @Override 552 public void drawBitmap(int[] colors, int offset, int stride, float x, float y, 553 int width, int height, boolean hasAlpha, Paint paint) { 554 // Shaders are ignored when drawing bitmaps 555 boolean hasColorFilter = paint != null && setupColorFilter(paint); 556 final Bitmap.Config config = hasAlpha ? Bitmap.Config.ARGB_8888 : Bitmap.Config.RGB_565; 557 final Bitmap b = Bitmap.createBitmap(colors, offset, stride, width, height, config); 558 final int nativePaint = paint == null ? 0 : paint.mNativePaint; 559 nDrawBitmap(mRenderer, b.mNativeBitmap, b.mBuffer, x, y, nativePaint); 560 b.recycle(); 561 if (hasColorFilter) nResetModifiers(mRenderer); 562 } 563 564 @Override 565 public void drawBitmap(int[] colors, int offset, int stride, int x, int y, 566 int width, int height, boolean hasAlpha, Paint paint) { 567 // Shaders are ignored when drawing bitmaps 568 drawBitmap(colors, offset, stride, (float) x, (float) y, width, height, hasAlpha, paint); 569 } 570 571 @Override 572 public void drawBitmapMesh(Bitmap bitmap, int meshWidth, int meshHeight, float[] verts, 573 int vertOffset, int[] colors, int colorOffset, Paint paint) { 574 // TODO: Implement 575 } 576 577 @Override 578 public void drawCircle(float cx, float cy, float radius, Paint paint) { 579 throw new UnsupportedOperationException(); 580 } 581 582 @Override 583 public void drawColor(int color) { 584 drawColor(color, PorterDuff.Mode.SRC_OVER); 585 } 586 587 @Override 588 public void drawColor(int color, PorterDuff.Mode mode) { 589 nDrawColor(mRenderer, color, mode.nativeInt); 590 } 591 592 private native void nDrawColor(int renderer, int color, int mode); 593 594 @Override 595 public void drawLine(float startX, float startY, float stopX, float stopY, Paint paint) { 596 mLine[0] = startX; 597 mLine[1] = startY; 598 mLine[2] = stopX; 599 mLine[3] = stopY; 600 drawLines(mLine, 0, 4, paint); 601 } 602 603 @Override 604 public void drawLines(float[] pts, int offset, int count, Paint paint) { 605 if ((offset | count) < 0 || offset + count > pts.length) { 606 throw new IllegalArgumentException("The lines array must contain 4 elements per line."); 607 } 608 boolean hasModifier = setupModifiers(paint); 609 nDrawLines(mRenderer, pts, offset, count, paint.mNativePaint); 610 if (hasModifier) nResetModifiers(mRenderer); 611 } 612 613 private native void nDrawLines(int renderer, float[] points, int offset, int count, int paint); 614 615 @Override 616 public void drawLines(float[] pts, Paint paint) { 617 drawLines(pts, 0, pts.length, paint); 618 } 619 620 @Override 621 public void drawOval(RectF oval, Paint paint) { 622 throw new UnsupportedOperationException(); 623 } 624 625 @Override 626 public void drawPaint(Paint paint) { 627 final Rect r = mClipBounds; 628 nGetClipBounds(mRenderer, r); 629 drawRect(r.left, r.top, r.right, r.bottom, paint); 630 } 631 632 @Override 633 public void drawPath(Path path, Paint paint) { 634 boolean hasModifier = setupModifiers(paint); 635 if (path.isSimplePath) { 636 if (path.rects != null) { 637 nDrawRects(mRenderer, path.rects.mNativeRegion, paint.mNativePaint); 638 } 639 } else { 640 nDrawPath(mRenderer, path.mNativePath, paint.mNativePaint); 641 } 642 if (hasModifier) nResetModifiers(mRenderer); 643 } 644 645 private native void nDrawPath(int renderer, int path, int paint); 646 private native void nDrawRects(int renderer, int region, int paint); 647 648 @Override 649 public void drawPicture(Picture picture) { 650 throw new UnsupportedOperationException(); 651 } 652 653 @Override 654 public void drawPicture(Picture picture, Rect dst) { 655 throw new UnsupportedOperationException(); 656 } 657 658 @Override 659 public void drawPicture(Picture picture, RectF dst) { 660 throw new UnsupportedOperationException(); 661 } 662 663 @Override 664 public void drawPoint(float x, float y, Paint paint) { 665 mPoint[0] = x; 666 mPoint[1] = y; 667 drawPoints(mPoint, 0, 1, paint); 668 } 669 670 @Override 671 public void drawPoints(float[] pts, int offset, int count, Paint paint) { 672 // TODO: Implement 673 } 674 675 @Override 676 public void drawPoints(float[] pts, Paint paint) { 677 drawPoints(pts, 0, pts.length / 2, paint); 678 } 679 680 @Override 681 public void drawPosText(char[] text, int index, int count, float[] pos, Paint paint) { 682 throw new UnsupportedOperationException(); 683 } 684 685 @Override 686 public void drawPosText(String text, float[] pos, Paint paint) { 687 throw new UnsupportedOperationException(); 688 } 689 690 @Override 691 public void drawRect(float left, float top, float right, float bottom, Paint paint) { 692 boolean hasModifier = setupModifiers(paint); 693 nDrawRect(mRenderer, left, top, right, bottom, paint.mNativePaint); 694 if (hasModifier) nResetModifiers(mRenderer); 695 } 696 697 private native void nDrawRect(int renderer, float left, float top, float right, float bottom, 698 int paint); 699 700 @Override 701 public void drawRect(Rect r, Paint paint) { 702 drawRect(r.left, r.top, r.right, r.bottom, paint); 703 } 704 705 @Override 706 public void drawRect(RectF r, Paint paint) { 707 drawRect(r.left, r.top, r.right, r.bottom, paint); 708 } 709 710 @Override 711 public void drawRGB(int r, int g, int b) { 712 drawColor(0xFF000000 | (r & 0xFF) << 16 | (g & 0xFF) << 8 | (b & 0xFF)); 713 } 714 715 @Override 716 public void drawRoundRect(RectF rect, float rx, float ry, Paint paint) { 717 // TODO: Implement 718 } 719 720 @Override 721 public void drawText(char[] text, int index, int count, float x, float y, Paint paint) { 722 if ((index | count | (index + count) | (text.length - index - count)) < 0) { 723 throw new IndexOutOfBoundsException(); 724 } 725 726 boolean hasModifier = setupModifiers(paint); 727 try { 728 nDrawText(mRenderer, text, index, count, x, y, paint.mBidiFlags, paint.mNativePaint); 729 } finally { 730 if (hasModifier) nResetModifiers(mRenderer); 731 } 732 } 733 734 private native void nDrawText(int renderer, char[] text, int index, int count, float x, float y, 735 int bidiFlags, int paint); 736 737 @Override 738 public void drawText(CharSequence text, int start, int end, float x, float y, Paint paint) { 739 boolean hasModifier = setupModifiers(paint); 740 try { 741 if (text instanceof String || text instanceof SpannedString || 742 text instanceof SpannableString) { 743 nDrawText(mRenderer, text.toString(), start, end, x, y, paint.mBidiFlags, 744 paint.mNativePaint); 745 } else if (text instanceof GraphicsOperations) { 746 ((GraphicsOperations) text).drawText(this, start, end, x, y, 747 paint); 748 } else { 749 char[] buf = TemporaryBuffer.obtain(end - start); 750 TextUtils.getChars(text, start, end, buf, 0); 751 nDrawText(mRenderer, buf, 0, end - start, x, y, paint.mBidiFlags, paint.mNativePaint); 752 TemporaryBuffer.recycle(buf); 753 } 754 } finally { 755 if (hasModifier) nResetModifiers(mRenderer); 756 } 757 } 758 759 @Override 760 public void drawText(String text, int start, int end, float x, float y, Paint paint) { 761 if ((start | end | (end - start) | (text.length() - end)) < 0) { 762 throw new IndexOutOfBoundsException(); 763 } 764 765 boolean hasModifier = setupModifiers(paint); 766 try { 767 nDrawText(mRenderer, text, start, end, x, y, paint.mBidiFlags, paint.mNativePaint); 768 } finally { 769 if (hasModifier) nResetModifiers(mRenderer); 770 } 771 } 772 773 private native void nDrawText(int renderer, String text, int start, int end, float x, float y, 774 int bidiFlags, int paint); 775 776 @Override 777 public void drawText(String text, float x, float y, Paint paint) { 778 boolean hasModifier = setupModifiers(paint); 779 try { 780 nDrawText(mRenderer, text, 0, text.length(), x, y, paint.mBidiFlags, 781 paint.mNativePaint); 782 } finally { 783 if (hasModifier) nResetModifiers(mRenderer); 784 } 785 } 786 787 @Override 788 public void drawTextOnPath(char[] text, int index, int count, Path path, float hOffset, 789 float vOffset, Paint paint) { 790 throw new UnsupportedOperationException(); 791 } 792 793 @Override 794 public void drawTextOnPath(String text, Path path, float hOffset, float vOffset, Paint paint) { 795 throw new UnsupportedOperationException(); 796 } 797 798 @Override 799 public void drawTextRun(char[] text, int index, int count, int contextIndex, int contextCount, 800 float x, float y, int dir, Paint paint) { 801 if ((index | count | text.length - index - count) < 0) { 802 throw new IndexOutOfBoundsException(); 803 } 804 if (dir != DIRECTION_LTR && dir != DIRECTION_RTL) { 805 throw new IllegalArgumentException("Unknown direction: " + dir); 806 } 807 808 boolean hasModifier = setupModifiers(paint); 809 try { 810 nDrawTextRun(mRenderer, text, index, count, contextIndex, contextCount, x, y, dir, 811 paint.mNativePaint); 812 } finally { 813 if (hasModifier) nResetModifiers(mRenderer); 814 } 815 } 816 817 private native void nDrawTextRun(int renderer, char[] text, int index, int count, 818 int contextIndex, int contextCount, float x, float y, int dir, int nativePaint); 819 820 @Override 821 public void drawTextRun(CharSequence text, int start, int end, int contextStart, int contextEnd, 822 float x, float y, int dir, Paint paint) { 823 if ((start | end | end - start | text.length() - end) < 0) { 824 throw new IndexOutOfBoundsException(); 825 } 826 827 boolean hasModifier = setupModifiers(paint); 828 try { 829 int flags = dir == 0 ? 0 : 1; 830 if (text instanceof String || text instanceof SpannedString || 831 text instanceof SpannableString) { 832 nDrawTextRun(mRenderer, text.toString(), start, end, contextStart, 833 contextEnd, x, y, flags, paint.mNativePaint); 834 } else if (text instanceof GraphicsOperations) { 835 ((GraphicsOperations) text).drawTextRun(this, start, end, 836 contextStart, contextEnd, x, y, flags, paint); 837 } else { 838 int contextLen = contextEnd - contextStart; 839 int len = end - start; 840 char[] buf = TemporaryBuffer.obtain(contextLen); 841 TextUtils.getChars(text, contextStart, contextEnd, buf, 0); 842 nDrawTextRun(mRenderer, buf, start - contextStart, len, 0, contextLen, 843 x, y, flags, paint.mNativePaint); 844 TemporaryBuffer.recycle(buf); 845 } 846 } finally { 847 if (hasModifier) nResetModifiers(mRenderer); 848 } 849 } 850 851 private native void nDrawTextRun(int renderer, String text, int start, int end, 852 int contextStart, int contextEnd, float x, float y, int flags, int nativePaint); 853 854 @Override 855 public void drawVertices(VertexMode mode, int vertexCount, float[] verts, int vertOffset, 856 float[] texs, int texOffset, int[] colors, int colorOffset, short[] indices, 857 int indexOffset, int indexCount, Paint paint) { 858 // TODO: Implement 859 } 860 861 private boolean setupModifiers(Paint paint) { 862 boolean hasModifier = false; 863 864 if (paint.hasShadow) { 865 nSetupShadow(mRenderer, paint.shadowRadius, paint.shadowDx, paint.shadowDy, 866 paint.shadowColor); 867 hasModifier = true; 868 } 869 870 final Shader shader = paint.getShader(); 871 if (shader != null) { 872 nSetupShader(mRenderer, shader.native_shader); 873 hasModifier = true; 874 } 875 876 final ColorFilter filter = paint.getColorFilter(); 877 if (filter != null) { 878 nSetupColorFilter(mRenderer, filter.nativeColorFilter); 879 hasModifier = true; 880 } 881 882 return hasModifier; 883 } 884 885 private boolean setupColorFilter(Paint paint) { 886 final ColorFilter filter = paint.getColorFilter(); 887 if (filter != null) { 888 nSetupColorFilter(mRenderer, filter.nativeColorFilter); 889 return true; 890 } 891 return false; 892 } 893 894 private native void nSetupShader(int renderer, int shader); 895 private native void nSetupColorFilter(int renderer, int colorFilter); 896 private native void nSetupShadow(int renderer, float radius, float dx, float dy, int color); 897 898 private native void nResetModifiers(int renderer); 899} 900