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