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