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