• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
17 package android.view;
18 
19 import android.graphics.Bitmap;
20 import android.graphics.Canvas;
21 import android.graphics.ColorFilter;
22 import android.graphics.DrawFilter;
23 import android.graphics.Matrix;
24 import android.graphics.Paint;
25 import android.graphics.PaintFlagsDrawFilter;
26 import android.graphics.Path;
27 import android.graphics.Picture;
28 import android.graphics.PorterDuff;
29 import android.graphics.Rect;
30 import android.graphics.RectF;
31 import android.graphics.Region;
32 import android.graphics.Shader;
33 import android.graphics.SurfaceTexture;
34 import android.graphics.TemporaryBuffer;
35 import android.text.GraphicsOperations;
36 import android.text.SpannableString;
37 import android.text.SpannedString;
38 import android.text.TextUtils;
39 
40 /**
41  * An implementation of Canvas on top of OpenGL ES 2.0.
42  */
43 class GLES20Canvas extends HardwareCanvas {
44     // Must match modifiers used in the JNI layer
45     private static final int MODIFIER_NONE = 0;
46     private static final int MODIFIER_SHADOW = 1;
47     private static final int MODIFIER_SHADER = 2;
48     private static final int MODIFIER_COLOR_FILTER = 4;
49 
50     private final boolean mOpaque;
51     private int mRenderer;
52 
53     // The native renderer will be destroyed when this object dies.
54     // DO NOT overwrite this reference once it is set.
55     @SuppressWarnings({"unused", "FieldCanBeLocal"})
56     private CanvasFinalizer mFinalizer;
57 
58     private int mWidth;
59     private int mHeight;
60 
61     private final float[] mPoint = new float[2];
62     private final float[] mLine = new float[4];
63 
64     private final Rect mClipBounds = new Rect();
65     private final RectF mPathBounds = new RectF();
66 
67     private DrawFilter mFilter;
68 
69     ///////////////////////////////////////////////////////////////////////////
70     // JNI
71     ///////////////////////////////////////////////////////////////////////////
72 
nIsAvailable()73     private static native boolean nIsAvailable();
74     private static boolean sIsAvailable = nIsAvailable();
75 
isAvailable()76     static boolean isAvailable() {
77         return sIsAvailable;
78     }
79 
80     ///////////////////////////////////////////////////////////////////////////
81     // Constructors
82     ///////////////////////////////////////////////////////////////////////////
83 
84     /**
85      * Creates a canvas to render directly on screen.
86      */
GLES20Canvas(boolean translucent)87     GLES20Canvas(boolean translucent) {
88         this(false, translucent);
89     }
90 
91     /**
92      * Creates a canvas to render into an FBO.
93      */
GLES20Canvas(int layer, boolean translucent)94     GLES20Canvas(int layer, boolean translucent) {
95         mOpaque = !translucent;
96         mRenderer = nCreateLayerRenderer(layer);
97         setupFinalizer();
98     }
99 
GLES20Canvas(boolean record, boolean translucent)100     protected GLES20Canvas(boolean record, boolean translucent) {
101         mOpaque = !translucent;
102 
103         if (record) {
104             mRenderer = nCreateDisplayListRenderer();
105         } else {
106             mRenderer = nCreateRenderer();
107         }
108 
109         setupFinalizer();
110     }
111 
setupFinalizer()112     private void setupFinalizer() {
113         if (mRenderer == 0) {
114             throw new IllegalStateException("Could not create GLES20Canvas renderer");
115         } else {
116             mFinalizer = new CanvasFinalizer(mRenderer);
117         }
118     }
119 
resetDisplayListRenderer()120     protected void resetDisplayListRenderer() {
121         nResetDisplayListRenderer(mRenderer);
122     }
123 
nCreateRenderer()124     private static native int nCreateRenderer();
nCreateLayerRenderer(int layer)125     private static native int nCreateLayerRenderer(int layer);
nCreateDisplayListRenderer()126     private static native int nCreateDisplayListRenderer();
nResetDisplayListRenderer(int renderer)127     private static native void nResetDisplayListRenderer(int renderer);
nDestroyRenderer(int renderer)128     private static native void nDestroyRenderer(int renderer);
129 
130     private static final class CanvasFinalizer {
131         private final int mRenderer;
132 
CanvasFinalizer(int renderer)133         public CanvasFinalizer(int renderer) {
134             mRenderer = renderer;
135         }
136 
137         @Override
finalize()138         protected void finalize() throws Throwable {
139             try {
140                 nDestroyRenderer(mRenderer);
141             } finally {
142                 super.finalize();
143             }
144         }
145     }
146 
147     ///////////////////////////////////////////////////////////////////////////
148     // Hardware layers
149     ///////////////////////////////////////////////////////////////////////////
150 
nCreateTextureLayer(boolean opaque, int[] layerInfo)151     static native int nCreateTextureLayer(boolean opaque, int[] layerInfo);
nCreateLayer(int width, int height, boolean isOpaque, int[] layerInfo)152     static native int nCreateLayer(int width, int height, boolean isOpaque, int[] layerInfo);
nResizeLayer(int layerId, int width, int height, int[] layerInfo)153     static native void nResizeLayer(int layerId, int width, int height, int[] layerInfo);
nUpdateTextureLayer(int layerId, int width, int height, boolean opaque, SurfaceTexture surface)154     static native void nUpdateTextureLayer(int layerId, int width, int height, boolean opaque,
155             SurfaceTexture surface);
nSetTextureLayerTransform(int layerId, int matrix)156     static native void nSetTextureLayerTransform(int layerId, int matrix);
nDestroyLayer(int layerId)157     static native void nDestroyLayer(int layerId);
nDestroyLayerDeferred(int layerId)158     static native void nDestroyLayerDeferred(int layerId);
nFlushLayer(int layerId)159     static native void nFlushLayer(int layerId);
nUpdateRenderLayer(int layerId, int renderer, int displayList, int left, int top, int right, int bottom)160     static native void nUpdateRenderLayer(int layerId, int renderer, int displayList,
161             int left, int top, int right, int bottom);
nCopyLayer(int layerId, int bitmap)162     static native boolean nCopyLayer(int layerId, int bitmap);
163 
164     ///////////////////////////////////////////////////////////////////////////
165     // Canvas management
166     ///////////////////////////////////////////////////////////////////////////
167 
168     @Override
isOpaque()169     public boolean isOpaque() {
170         return mOpaque;
171     }
172 
173     @Override
getWidth()174     public int getWidth() {
175         return mWidth;
176     }
177 
178     @Override
getHeight()179     public int getHeight() {
180         return mHeight;
181     }
182 
183     @Override
getMaximumBitmapWidth()184     public int getMaximumBitmapWidth() {
185         return nGetMaximumTextureWidth();
186     }
187 
188     @Override
getMaximumBitmapHeight()189     public int getMaximumBitmapHeight() {
190         return nGetMaximumTextureHeight();
191     }
192 
nGetMaximumTextureWidth()193     private static native int nGetMaximumTextureWidth();
nGetMaximumTextureHeight()194     private static native int nGetMaximumTextureHeight();
195 
196     /**
197      * Returns the native OpenGLRenderer object.
198      */
getRenderer()199     int getRenderer() {
200         return mRenderer;
201     }
202 
203     ///////////////////////////////////////////////////////////////////////////
204     // Setup
205     ///////////////////////////////////////////////////////////////////////////
206 
207     @Override
setViewport(int width, int height)208     public void setViewport(int width, int height) {
209         mWidth = width;
210         mHeight = height;
211 
212         nSetViewport(mRenderer, width, height);
213     }
214 
nSetViewport(int renderer, int width, int height)215     private static native void nSetViewport(int renderer, int width, int height);
216 
217     @Override
onPreDraw(Rect dirty)218     public int onPreDraw(Rect dirty) {
219         if (dirty != null) {
220             return nPrepareDirty(mRenderer, dirty.left, dirty.top, dirty.right, dirty.bottom,
221                     mOpaque);
222         } else {
223             return nPrepare(mRenderer, mOpaque);
224         }
225     }
226 
nPrepare(int renderer, boolean opaque)227     private static native int nPrepare(int renderer, boolean opaque);
nPrepareDirty(int renderer, int left, int top, int right, int bottom, boolean opaque)228     private static native int nPrepareDirty(int renderer, int left, int top, int right, int bottom,
229             boolean opaque);
230 
231     @Override
onPostDraw()232     public void onPostDraw() {
233         nFinish(mRenderer);
234     }
235 
nFinish(int renderer)236     private static native void nFinish(int renderer);
237 
238     /**
239      * Returns the size of the stencil buffer required by the underlying
240      * implementation.
241      *
242      * @return The minimum number of bits the stencil buffer must. Always >= 0.
243      *
244      * @hide
245      */
getStencilSize()246     public static int getStencilSize() {
247         return nGetStencilSize();
248     }
249 
nGetStencilSize()250     private static native int nGetStencilSize();
251 
252     ///////////////////////////////////////////////////////////////////////////
253     // Functor
254     ///////////////////////////////////////////////////////////////////////////
255 
256     @Override
callDrawGLFunction(int drawGLFunction)257     public int callDrawGLFunction(int drawGLFunction) {
258         return nCallDrawGLFunction(mRenderer, drawGLFunction);
259     }
260 
nCallDrawGLFunction(int renderer, int drawGLFunction)261     private static native int nCallDrawGLFunction(int renderer, int drawGLFunction);
262 
263     @Override
invokeFunctors(Rect dirty)264     public int invokeFunctors(Rect dirty) {
265         return nInvokeFunctors(mRenderer, dirty);
266     }
267 
nInvokeFunctors(int renderer, Rect dirty)268     private static native int nInvokeFunctors(int renderer, Rect dirty);
269 
270     @Override
detachFunctor(int functor)271     public void detachFunctor(int functor) {
272         nDetachFunctor(mRenderer, functor);
273     }
274 
nDetachFunctor(int renderer, int functor)275     private static native void nDetachFunctor(int renderer, int functor);
276 
277     @Override
attachFunctor(int functor)278     public void attachFunctor(int functor) {
279         nAttachFunctor(mRenderer, functor);
280     }
281 
nAttachFunctor(int renderer, int functor)282     private static native void nAttachFunctor(int renderer, int functor);
283 
284     ///////////////////////////////////////////////////////////////////////////
285     // Memory
286     ///////////////////////////////////////////////////////////////////////////
287 
288     /**
289      * Must match Caches::FlushMode values
290      *
291      * @see #flushCaches(int)
292      */
293     public static final int FLUSH_CACHES_LAYERS = 0;
294 
295     /**
296      * Must match Caches::FlushMode values
297      *
298      * @see #flushCaches(int)
299      */
300     public static final int FLUSH_CACHES_MODERATE = 1;
301 
302     /**
303      * Must match Caches::FlushMode values
304      *
305      * @see #flushCaches(int)
306      */
307     public static final int FLUSH_CACHES_FULL = 2;
308 
309     /**
310      * Flush caches to reclaim as much memory as possible. The amount of memory
311      * to reclaim is indicate by the level parameter.
312      *
313      * The level can be one of {@link #FLUSH_CACHES_MODERATE} or
314      * {@link #FLUSH_CACHES_FULL}.
315      *
316      * @param level Hint about the amount of memory to reclaim
317      *
318      * @hide
319      */
flushCaches(int level)320     public static void flushCaches(int level) {
321         nFlushCaches(level);
322     }
323 
nFlushCaches(int level)324     private static native void nFlushCaches(int level);
325 
326     /**
327      * Release all resources associated with the underlying caches. This should
328      * only be called after a full flushCaches().
329      *
330      * @hide
331      */
terminateCaches()332     public static void terminateCaches() {
333         nTerminateCaches();
334     }
335 
nTerminateCaches()336     private static native void nTerminateCaches();
337 
338     /**
339      * @hide
340      */
initCaches()341     public static void initCaches() {
342         nInitCaches();
343     }
344 
nInitCaches()345     private static native void nInitCaches();
346 
347     ///////////////////////////////////////////////////////////////////////////
348     // Display list
349     ///////////////////////////////////////////////////////////////////////////
350 
getDisplayList(int displayList)351     int getDisplayList(int displayList) {
352         return nGetDisplayList(mRenderer, displayList);
353     }
354 
nGetDisplayList(int renderer, int displayList)355     private static native int nGetDisplayList(int renderer, int displayList);
356 
destroyDisplayList(int displayList)357     static void destroyDisplayList(int displayList) {
358         nDestroyDisplayList(displayList);
359     }
360 
nDestroyDisplayList(int displayList)361     private static native void nDestroyDisplayList(int displayList);
362 
getDisplayListSize(int displayList)363     static int getDisplayListSize(int displayList) {
364         return nGetDisplayListSize(displayList);
365     }
366 
nGetDisplayListSize(int displayList)367     private static native int nGetDisplayListSize(int displayList);
368 
setDisplayListName(int displayList, String name)369     static void setDisplayListName(int displayList, String name) {
370         nSetDisplayListName(displayList, name);
371     }
372 
nSetDisplayListName(int displayList, String name)373     private static native void nSetDisplayListName(int displayList, String name);
374 
375     @Override
drawDisplayList(DisplayList displayList, Rect dirty, int flags)376     public int drawDisplayList(DisplayList displayList, Rect dirty, int flags) {
377         return nDrawDisplayList(mRenderer, ((GLES20DisplayList) displayList).getNativeDisplayList(),
378                 dirty, flags);
379     }
380 
nDrawDisplayList(int renderer, int displayList, Rect dirty, int flags)381     private static native int nDrawDisplayList(int renderer, int displayList,
382             Rect dirty, int flags);
383 
384     @Override
outputDisplayList(DisplayList displayList)385     void outputDisplayList(DisplayList displayList) {
386         nOutputDisplayList(mRenderer, ((GLES20DisplayList) displayList).getNativeDisplayList());
387     }
388 
nOutputDisplayList(int renderer, int displayList)389     private static native void nOutputDisplayList(int renderer, int displayList);
390 
391     ///////////////////////////////////////////////////////////////////////////
392     // Hardware layer
393     ///////////////////////////////////////////////////////////////////////////
394 
drawHardwareLayer(HardwareLayer layer, float x, float y, Paint paint)395     void drawHardwareLayer(HardwareLayer layer, float x, float y, Paint paint) {
396         final GLES20Layer glLayer = (GLES20Layer) layer;
397         int modifier = paint != null ? setupColorFilter(paint) : MODIFIER_NONE;
398         try {
399             final int nativePaint = paint == null ? 0 : paint.mNativePaint;
400             nDrawLayer(mRenderer, glLayer.getLayer(), x, y, nativePaint);
401         } finally {
402             if (modifier != MODIFIER_NONE) nResetModifiers(mRenderer, modifier);
403         }
404     }
405 
nDrawLayer(int renderer, int layer, float x, float y, int paint)406     private static native void nDrawLayer(int renderer, int layer, float x, float y, int paint);
407 
interrupt()408     void interrupt() {
409         nInterrupt(mRenderer);
410     }
411 
resume()412     void resume() {
413         nResume(mRenderer);
414     }
415 
nInterrupt(int renderer)416     private static native void nInterrupt(int renderer);
nResume(int renderer)417     private static native void nResume(int renderer);
418 
419     ///////////////////////////////////////////////////////////////////////////
420     // Clipping
421     ///////////////////////////////////////////////////////////////////////////
422 
423     @Override
clipPath(Path path)424     public boolean clipPath(Path path) {
425         // TODO: Implement
426         path.computeBounds(mPathBounds, true);
427         return nClipRect(mRenderer, mPathBounds.left, mPathBounds.top,
428                 mPathBounds.right, mPathBounds.bottom, Region.Op.INTERSECT.nativeInt);
429     }
430 
431     @Override
clipPath(Path path, Region.Op op)432     public boolean clipPath(Path path, Region.Op op) {
433         // TODO: Implement
434         path.computeBounds(mPathBounds, true);
435         return nClipRect(mRenderer, mPathBounds.left, mPathBounds.top,
436                 mPathBounds.right, mPathBounds.bottom, op.nativeInt);
437     }
438 
439     @Override
clipRect(float left, float top, float right, float bottom)440     public boolean clipRect(float left, float top, float right, float bottom) {
441         return nClipRect(mRenderer, left, top, right, bottom, Region.Op.INTERSECT.nativeInt);
442     }
443 
nClipRect(int renderer, float left, float top, float right, float bottom, int op)444     private static native boolean nClipRect(int renderer, float left, float top,
445             float right, float bottom, int op);
446 
447     @Override
clipRect(float left, float top, float right, float bottom, Region.Op op)448     public boolean clipRect(float left, float top, float right, float bottom, Region.Op op) {
449         return nClipRect(mRenderer, left, top, right, bottom, op.nativeInt);
450     }
451 
452     @Override
clipRect(int left, int top, int right, int bottom)453     public boolean clipRect(int left, int top, int right, int bottom) {
454         return nClipRect(mRenderer, left, top, right, bottom, Region.Op.INTERSECT.nativeInt);
455     }
456 
nClipRect(int renderer, int left, int top, int right, int bottom, int op)457     private static native boolean nClipRect(int renderer, int left, int top, int right, int bottom,
458             int op);
459 
460     @Override
clipRect(Rect rect)461     public boolean clipRect(Rect rect) {
462         return nClipRect(mRenderer, rect.left, rect.top, rect.right, rect.bottom,
463                 Region.Op.INTERSECT.nativeInt);
464     }
465 
466     @Override
clipRect(Rect rect, Region.Op op)467     public boolean clipRect(Rect rect, Region.Op op) {
468         return nClipRect(mRenderer, rect.left, rect.top, rect.right, rect.bottom, op.nativeInt);
469     }
470 
471     @Override
clipRect(RectF rect)472     public boolean clipRect(RectF rect) {
473         return nClipRect(mRenderer, rect.left, rect.top, rect.right, rect.bottom,
474                 Region.Op.INTERSECT.nativeInt);
475     }
476 
477     @Override
clipRect(RectF rect, Region.Op op)478     public boolean clipRect(RectF rect, Region.Op op) {
479         return nClipRect(mRenderer, rect.left, rect.top, rect.right, rect.bottom, op.nativeInt);
480     }
481 
482     @Override
clipRegion(Region region)483     public boolean clipRegion(Region region) {
484         // TODO: Implement
485         region.getBounds(mClipBounds);
486         return nClipRect(mRenderer, mClipBounds.left, mClipBounds.top,
487                 mClipBounds.right, mClipBounds.bottom, Region.Op.INTERSECT.nativeInt);
488     }
489 
490     @Override
clipRegion(Region region, Region.Op op)491     public boolean clipRegion(Region region, Region.Op op) {
492         // TODO: Implement
493         region.getBounds(mClipBounds);
494         return nClipRect(mRenderer, mClipBounds.left, mClipBounds.top,
495                 mClipBounds.right, mClipBounds.bottom, op.nativeInt);
496     }
497 
498     @Override
getClipBounds(Rect bounds)499     public boolean getClipBounds(Rect bounds) {
500         return nGetClipBounds(mRenderer, bounds);
501     }
502 
nGetClipBounds(int renderer, Rect bounds)503     private static native boolean nGetClipBounds(int renderer, Rect bounds);
504 
505     @Override
quickReject(float left, float top, float right, float bottom, EdgeType type)506     public boolean quickReject(float left, float top, float right, float bottom, EdgeType type) {
507         return nQuickReject(mRenderer, left, top, right, bottom, type.nativeInt);
508     }
509 
nQuickReject(int renderer, float left, float top, float right, float bottom, int edge)510     private static native boolean nQuickReject(int renderer, float left, float top,
511             float right, float bottom, int edge);
512 
513     @Override
quickReject(Path path, EdgeType type)514     public boolean quickReject(Path path, EdgeType type) {
515         path.computeBounds(mPathBounds, true);
516         return nQuickReject(mRenderer, mPathBounds.left, mPathBounds.top,
517                 mPathBounds.right, mPathBounds.bottom, type.nativeInt);
518     }
519 
520     @Override
quickReject(RectF rect, EdgeType type)521     public boolean quickReject(RectF rect, EdgeType type) {
522         return nQuickReject(mRenderer, rect.left, rect.top, rect.right, rect.bottom, type.nativeInt);
523     }
524 
525     ///////////////////////////////////////////////////////////////////////////
526     // Transformations
527     ///////////////////////////////////////////////////////////////////////////
528 
529     @Override
translate(float dx, float dy)530     public void translate(float dx, float dy) {
531         if (dx != 0.0f || dy != 0.0f) nTranslate(mRenderer, dx, dy);
532     }
533 
nTranslate(int renderer, float dx, float dy)534     private static native void nTranslate(int renderer, float dx, float dy);
535 
536     @Override
skew(float sx, float sy)537     public void skew(float sx, float sy) {
538         nSkew(mRenderer, sx, sy);
539     }
540 
nSkew(int renderer, float sx, float sy)541     private static native void nSkew(int renderer, float sx, float sy);
542 
543     @Override
rotate(float degrees)544     public void rotate(float degrees) {
545         nRotate(mRenderer, degrees);
546     }
547 
nRotate(int renderer, float degrees)548     private static native void nRotate(int renderer, float degrees);
549 
550     @Override
scale(float sx, float sy)551     public void scale(float sx, float sy) {
552         nScale(mRenderer, sx, sy);
553     }
554 
nScale(int renderer, float sx, float sy)555     private static native void nScale(int renderer, float sx, float sy);
556 
557     @Override
setMatrix(Matrix matrix)558     public void setMatrix(Matrix matrix) {
559         nSetMatrix(mRenderer, matrix == null ? 0 : matrix.native_instance);
560     }
561 
nSetMatrix(int renderer, int matrix)562     private static native void nSetMatrix(int renderer, int matrix);
563 
564     @SuppressWarnings("deprecation")
565     @Override
getMatrix(Matrix matrix)566     public void getMatrix(Matrix matrix) {
567         nGetMatrix(mRenderer, matrix.native_instance);
568     }
569 
nGetMatrix(int renderer, int matrix)570     private static native void nGetMatrix(int renderer, int matrix);
571 
572     @Override
concat(Matrix matrix)573     public void concat(Matrix matrix) {
574         nConcatMatrix(mRenderer, matrix.native_instance);
575     }
576 
nConcatMatrix(int renderer, int matrix)577     private static native void nConcatMatrix(int renderer, int matrix);
578 
579     ///////////////////////////////////////////////////////////////////////////
580     // State management
581     ///////////////////////////////////////////////////////////////////////////
582 
583     @Override
save()584     public int save() {
585         return nSave(mRenderer, Canvas.CLIP_SAVE_FLAG | Canvas.MATRIX_SAVE_FLAG);
586     }
587 
588     @Override
save(int saveFlags)589     public int save(int saveFlags) {
590         return nSave(mRenderer, saveFlags);
591     }
592 
nSave(int renderer, int flags)593     private static native int nSave(int renderer, int flags);
594 
595     @Override
saveLayer(RectF bounds, Paint paint, int saveFlags)596     public int saveLayer(RectF bounds, Paint paint, int saveFlags) {
597         if (bounds != null) {
598             return saveLayer(bounds.left, bounds.top, bounds.right, bounds.bottom, paint, saveFlags);
599         }
600 
601         int count;
602         int modifier = paint != null ? setupColorFilter(paint) : MODIFIER_NONE;
603         try {
604             final int nativePaint = paint == null ? 0 : paint.mNativePaint;
605             count = nSaveLayer(mRenderer, nativePaint, saveFlags);
606         } finally {
607             if (modifier != MODIFIER_NONE) nResetModifiers(mRenderer, modifier);
608         }
609         return count;
610     }
611 
nSaveLayer(int renderer, int paint, int saveFlags)612     private static native int nSaveLayer(int renderer, int paint, int saveFlags);
613 
614     @Override
saveLayer(float left, float top, float right, float bottom, Paint paint, int saveFlags)615     public int saveLayer(float left, float top, float right, float bottom, Paint paint,
616             int saveFlags) {
617         if (left < right && top < bottom) {
618             int count;
619             int modifier = paint != null ? setupColorFilter(paint) : MODIFIER_NONE;
620             try {
621                 final int nativePaint = paint == null ? 0 : paint.mNativePaint;
622                 count = nSaveLayer(mRenderer, left, top, right, bottom, nativePaint, saveFlags);
623             } finally {
624                 if (modifier != MODIFIER_NONE) nResetModifiers(mRenderer, modifier);
625             }
626             return count;
627         }
628         return save(saveFlags);
629     }
630 
nSaveLayer(int renderer, float left, float top, float right, float bottom, int paint, int saveFlags)631     private static native int nSaveLayer(int renderer, float left, float top,
632             float right, float bottom, int paint, int saveFlags);
633 
634     @Override
saveLayerAlpha(RectF bounds, int alpha, int saveFlags)635     public int saveLayerAlpha(RectF bounds, int alpha, int saveFlags) {
636         if (bounds != null) {
637             return saveLayerAlpha(bounds.left, bounds.top, bounds.right, bounds.bottom,
638                     alpha, saveFlags);
639         }
640         return nSaveLayerAlpha(mRenderer, alpha, saveFlags);
641     }
642 
nSaveLayerAlpha(int renderer, int alpha, int saveFlags)643     private static native int nSaveLayerAlpha(int renderer, int alpha, int saveFlags);
644 
645     @Override
saveLayerAlpha(float left, float top, float right, float bottom, int alpha, int saveFlags)646     public int saveLayerAlpha(float left, float top, float right, float bottom, int alpha,
647             int saveFlags) {
648         if (left < right && top < bottom) {
649             return nSaveLayerAlpha(mRenderer, left, top, right, bottom, alpha, saveFlags);
650         }
651         return save(saveFlags);
652     }
653 
nSaveLayerAlpha(int renderer, float left, float top, float right, float bottom, int alpha, int saveFlags)654     private static native int nSaveLayerAlpha(int renderer, float left, float top, float right,
655             float bottom, int alpha, int saveFlags);
656 
657     @Override
restore()658     public void restore() {
659         nRestore(mRenderer);
660     }
661 
nRestore(int renderer)662     private static native void nRestore(int renderer);
663 
664     @Override
restoreToCount(int saveCount)665     public void restoreToCount(int saveCount) {
666         nRestoreToCount(mRenderer, saveCount);
667     }
668 
nRestoreToCount(int renderer, int saveCount)669     private static native void nRestoreToCount(int renderer, int saveCount);
670 
671     @Override
getSaveCount()672     public int getSaveCount() {
673         return nGetSaveCount(mRenderer);
674     }
675 
nGetSaveCount(int renderer)676     private static native int nGetSaveCount(int renderer);
677 
678     ///////////////////////////////////////////////////////////////////////////
679     // Filtering
680     ///////////////////////////////////////////////////////////////////////////
681 
682     @Override
setDrawFilter(DrawFilter filter)683     public void setDrawFilter(DrawFilter filter) {
684         mFilter = filter;
685         if (filter == null) {
686             nResetPaintFilter(mRenderer);
687         } else if (filter instanceof PaintFlagsDrawFilter) {
688             PaintFlagsDrawFilter flagsFilter = (PaintFlagsDrawFilter) filter;
689             nSetupPaintFilter(mRenderer, flagsFilter.clearBits, flagsFilter.setBits);
690         }
691     }
692 
nResetPaintFilter(int renderer)693     private static native void nResetPaintFilter(int renderer);
nSetupPaintFilter(int renderer, int clearBits, int setBits)694     private static native void nSetupPaintFilter(int renderer, int clearBits, int setBits);
695 
696     @Override
getDrawFilter()697     public DrawFilter getDrawFilter() {
698         return mFilter;
699     }
700 
701     ///////////////////////////////////////////////////////////////////////////
702     // Drawing
703     ///////////////////////////////////////////////////////////////////////////
704 
705     @Override
drawArc(RectF oval, float startAngle, float sweepAngle, boolean useCenter, Paint paint)706     public void drawArc(RectF oval, float startAngle, float sweepAngle, boolean useCenter,
707             Paint paint) {
708         int modifiers = setupModifiers(paint, MODIFIER_COLOR_FILTER | MODIFIER_SHADER);
709         try {
710             nDrawArc(mRenderer, oval.left, oval.top, oval.right, oval.bottom,
711                     startAngle, sweepAngle, useCenter, paint.mNativePaint);
712         } finally {
713             if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
714         }
715     }
716 
nDrawArc(int renderer, float left, float top, float right, float bottom, float startAngle, float sweepAngle, boolean useCenter, int paint)717     private static native void nDrawArc(int renderer, float left, float top,
718             float right, float bottom, float startAngle, float sweepAngle,
719             boolean useCenter, int paint);
720 
721     @Override
drawARGB(int a, int r, int g, int b)722     public void drawARGB(int a, int r, int g, int b) {
723         drawColor((a & 0xFF) << 24 | (r & 0xFF) << 16 | (g & 0xFF) << 8 | (b & 0xFF));
724     }
725 
726     @Override
drawPatch(Bitmap bitmap, byte[] chunks, RectF dst, Paint paint)727     public void drawPatch(Bitmap bitmap, byte[] chunks, RectF dst, Paint paint) {
728         if (bitmap.isRecycled()) throw new IllegalArgumentException("Cannot draw recycled bitmaps");
729         // Shaders are ignored when drawing patches
730         int modifier = paint != null ? setupColorFilter(paint) : MODIFIER_NONE;
731         try {
732             final int nativePaint = paint == null ? 0 : paint.mNativePaint;
733             nDrawPatch(mRenderer, bitmap.mNativeBitmap, bitmap.mBuffer, chunks,
734                     dst.left, dst.top, dst.right, dst.bottom, nativePaint);
735         } finally {
736             if (modifier != MODIFIER_NONE) nResetModifiers(mRenderer, modifier);
737         }
738     }
739 
nDrawPatch(int renderer, int bitmap, byte[] buffer, byte[] chunks, float left, float top, float right, float bottom, int paint)740     private static native void nDrawPatch(int renderer, int bitmap, byte[] buffer, byte[] chunks,
741             float left, float top, float right, float bottom, int paint);
742 
743     @Override
drawBitmap(Bitmap bitmap, float left, float top, Paint paint)744     public void drawBitmap(Bitmap bitmap, float left, float top, Paint paint) {
745         if (bitmap.isRecycled()) throw new IllegalArgumentException("Cannot draw recycled bitmaps");
746         // Shaders are ignored when drawing bitmaps
747         int modifiers = paint != null ? setupModifiers(bitmap, paint) : MODIFIER_NONE;
748         try {
749             final int nativePaint = paint == null ? 0 : paint.mNativePaint;
750             nDrawBitmap(mRenderer, bitmap.mNativeBitmap, bitmap.mBuffer, left, top, nativePaint);
751         } finally {
752             if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
753         }
754     }
755 
nDrawBitmap( int renderer, int bitmap, byte[] buffer, float left, float top, int paint)756     private static native void nDrawBitmap(
757             int renderer, int bitmap, byte[] buffer, float left, float top, int paint);
758 
759     @Override
drawBitmap(Bitmap bitmap, Matrix matrix, Paint paint)760     public void drawBitmap(Bitmap bitmap, Matrix matrix, Paint paint) {
761         if (bitmap.isRecycled()) throw new IllegalArgumentException("Cannot draw recycled bitmaps");
762         // Shaders are ignored when drawing bitmaps
763         int modifiers = paint != null ? setupModifiers(bitmap, paint) : MODIFIER_NONE;
764         try {
765             final int nativePaint = paint == null ? 0 : paint.mNativePaint;
766             nDrawBitmap(mRenderer, bitmap.mNativeBitmap, bitmap.mBuffer,
767                     matrix.native_instance, nativePaint);
768         } finally {
769             if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
770         }
771     }
772 
nDrawBitmap(int renderer, int bitmap, byte[] buff, int matrix, int paint)773     private static native void nDrawBitmap(int renderer, int bitmap, byte[] buff,
774             int matrix, int paint);
775 
776     @Override
drawBitmap(Bitmap bitmap, Rect src, Rect dst, Paint paint)777     public void drawBitmap(Bitmap bitmap, Rect src, Rect dst, Paint paint) {
778         if (bitmap.isRecycled()) throw new IllegalArgumentException("Cannot draw recycled bitmaps");
779         // Shaders are ignored when drawing bitmaps
780         int modifiers = paint != null ? setupModifiers(bitmap, paint) : MODIFIER_NONE;
781         try {
782             final int nativePaint = paint == null ? 0 : paint.mNativePaint;
783 
784             int left, top, right, bottom;
785             if (src == null) {
786                 left = top = 0;
787                 right = bitmap.getWidth();
788                 bottom = bitmap.getHeight();
789             } else {
790                 left = src.left;
791                 right = src.right;
792                 top = src.top;
793                 bottom = src.bottom;
794             }
795 
796             nDrawBitmap(mRenderer, bitmap.mNativeBitmap, bitmap.mBuffer, left, top, right, bottom,
797                     dst.left, dst.top, dst.right, dst.bottom, nativePaint);
798         } finally {
799             if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
800         }
801     }
802 
803     @Override
drawBitmap(Bitmap bitmap, Rect src, RectF dst, Paint paint)804     public void drawBitmap(Bitmap bitmap, Rect src, RectF dst, Paint paint) {
805         if (bitmap.isRecycled()) throw new IllegalArgumentException("Cannot draw recycled bitmaps");
806         // Shaders are ignored when drawing bitmaps
807         int modifiers = paint != null ? setupModifiers(bitmap, paint) : MODIFIER_NONE;
808         try {
809             final int nativePaint = paint == null ? 0 : paint.mNativePaint;
810 
811             float left, top, right, bottom;
812             if (src == null) {
813                 left = top = 0;
814                 right = bitmap.getWidth();
815                 bottom = bitmap.getHeight();
816             } else {
817                 left = src.left;
818                 right = src.right;
819                 top = src.top;
820                 bottom = src.bottom;
821             }
822 
823             nDrawBitmap(mRenderer, bitmap.mNativeBitmap, bitmap.mBuffer, left, top, right, bottom,
824                     dst.left, dst.top, dst.right, dst.bottom, nativePaint);
825         } finally {
826             if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
827         }
828     }
829 
nDrawBitmap(int renderer, int bitmap, byte[] buffer, float srcLeft, float srcTop, float srcRight, float srcBottom, float left, float top, float right, float bottom, int paint)830     private static native void nDrawBitmap(int renderer, int bitmap, byte[] buffer,
831             float srcLeft, float srcTop, float srcRight, float srcBottom,
832             float left, float top, float right, float bottom, int paint);
833 
834     @Override
drawBitmap(int[] colors, int offset, int stride, float x, float y, int width, int height, boolean hasAlpha, Paint paint)835     public void drawBitmap(int[] colors, int offset, int stride, float x, float y,
836             int width, int height, boolean hasAlpha, Paint paint) {
837         if (width < 0) {
838             throw new IllegalArgumentException("width must be >= 0");
839         }
840 
841         if (height < 0) {
842             throw new IllegalArgumentException("height must be >= 0");
843         }
844 
845         if (Math.abs(stride) < width) {
846             throw new IllegalArgumentException("abs(stride) must be >= width");
847         }
848 
849         int lastScanline = offset + (height - 1) * stride;
850         int length = colors.length;
851 
852         if (offset < 0 || (offset + width > length) || lastScanline < 0 ||
853                 (lastScanline + width > length)) {
854             throw new ArrayIndexOutOfBoundsException();
855         }
856 
857         // Shaders are ignored when drawing bitmaps
858         int modifier = paint != null ? setupColorFilter(paint) : MODIFIER_NONE;
859         try {
860             final int nativePaint = paint == null ? 0 : paint.mNativePaint;
861             nDrawBitmap(mRenderer, colors, offset, stride, x, y,
862                     width, height, hasAlpha, nativePaint);
863         } finally {
864             if (modifier != MODIFIER_NONE) nResetModifiers(mRenderer, modifier);
865         }
866     }
867 
nDrawBitmap(int renderer, int[] colors, int offset, int stride, float x, float y, int width, int height, boolean hasAlpha, int nativePaint)868     private static native void nDrawBitmap(int renderer, int[] colors, int offset, int stride,
869             float x, float y, int width, int height, boolean hasAlpha, int nativePaint);
870 
871     @Override
drawBitmap(int[] colors, int offset, int stride, int x, int y, int width, int height, boolean hasAlpha, Paint paint)872     public void drawBitmap(int[] colors, int offset, int stride, int x, int y,
873             int width, int height, boolean hasAlpha, Paint paint) {
874         // Shaders are ignored when drawing bitmaps
875         drawBitmap(colors, offset, stride, (float) x, (float) y, width, height, hasAlpha, paint);
876     }
877 
878     @Override
drawBitmapMesh(Bitmap bitmap, int meshWidth, int meshHeight, float[] verts, int vertOffset, int[] colors, int colorOffset, Paint paint)879     public void drawBitmapMesh(Bitmap bitmap, int meshWidth, int meshHeight, float[] verts,
880             int vertOffset, int[] colors, int colorOffset, Paint paint) {
881         if (bitmap.isRecycled()) throw new IllegalArgumentException("Cannot draw recycled bitmaps");
882         if (meshWidth < 0 || meshHeight < 0 || vertOffset < 0 || colorOffset < 0) {
883             throw new ArrayIndexOutOfBoundsException();
884         }
885 
886         if (meshWidth == 0 || meshHeight == 0) {
887             return;
888         }
889 
890         final int count = (meshWidth + 1) * (meshHeight + 1);
891         checkRange(verts.length, vertOffset, count * 2);
892 
893         // TODO: Colors are ignored for now
894         colors = null;
895         colorOffset = 0;
896 
897         int modifiers = paint != null ? setupModifiers(bitmap, paint) : MODIFIER_NONE;
898         try {
899             final int nativePaint = paint == null ? 0 : paint.mNativePaint;
900             nDrawBitmapMesh(mRenderer, bitmap.mNativeBitmap, bitmap.mBuffer, meshWidth, meshHeight,
901                     verts, vertOffset, colors, colorOffset, nativePaint);
902         } finally {
903             if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
904         }
905     }
906 
nDrawBitmapMesh(int renderer, int bitmap, byte[] buffer, int meshWidth, int meshHeight, float[] verts, int vertOffset, int[] colors, int colorOffset, int paint)907     private static native void nDrawBitmapMesh(int renderer, int bitmap, byte[] buffer,
908             int meshWidth, int meshHeight, float[] verts, int vertOffset,
909             int[] colors, int colorOffset, int paint);
910 
911     @Override
drawCircle(float cx, float cy, float radius, Paint paint)912     public void drawCircle(float cx, float cy, float radius, Paint paint) {
913         int modifiers = setupModifiers(paint, MODIFIER_COLOR_FILTER | MODIFIER_SHADER);
914         try {
915             nDrawCircle(mRenderer, cx, cy, radius, paint.mNativePaint);
916         } finally {
917             if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
918         }
919     }
920 
nDrawCircle(int renderer, float cx, float cy, float radius, int paint)921     private static native void nDrawCircle(int renderer, float cx, float cy,
922             float radius, int paint);
923 
924     @Override
drawColor(int color)925     public void drawColor(int color) {
926         drawColor(color, PorterDuff.Mode.SRC_OVER);
927     }
928 
929     @Override
drawColor(int color, PorterDuff.Mode mode)930     public void drawColor(int color, PorterDuff.Mode mode) {
931         nDrawColor(mRenderer, color, mode.nativeInt);
932     }
933 
nDrawColor(int renderer, int color, int mode)934     private static native void nDrawColor(int renderer, int color, int mode);
935 
936     @Override
drawLine(float startX, float startY, float stopX, float stopY, Paint paint)937     public void drawLine(float startX, float startY, float stopX, float stopY, Paint paint) {
938         mLine[0] = startX;
939         mLine[1] = startY;
940         mLine[2] = stopX;
941         mLine[3] = stopY;
942         drawLines(mLine, 0, 4, paint);
943     }
944 
945     @Override
drawLines(float[] pts, int offset, int count, Paint paint)946     public void drawLines(float[] pts, int offset, int count, Paint paint) {
947         if ((offset | count) < 0 || offset + count > pts.length) {
948             throw new IllegalArgumentException("The lines array must contain 4 elements per line.");
949         }
950         int modifiers = setupModifiers(paint, MODIFIER_COLOR_FILTER | MODIFIER_SHADER);
951         try {
952             nDrawLines(mRenderer, pts, offset, count, paint.mNativePaint);
953         } finally {
954             if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
955         }
956     }
957 
nDrawLines(int renderer, float[] points, int offset, int count, int paint)958     private static native void nDrawLines(int renderer, float[] points,
959             int offset, int count, int paint);
960 
961     @Override
drawLines(float[] pts, Paint paint)962     public void drawLines(float[] pts, Paint paint) {
963         drawLines(pts, 0, pts.length, paint);
964     }
965 
966     @Override
drawOval(RectF oval, Paint paint)967     public void drawOval(RectF oval, Paint paint) {
968         int modifiers = setupModifiers(paint, MODIFIER_COLOR_FILTER | MODIFIER_SHADER);
969         try {
970             nDrawOval(mRenderer, oval.left, oval.top, oval.right, oval.bottom, paint.mNativePaint);
971         } finally {
972             if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
973         }
974     }
975 
nDrawOval(int renderer, float left, float top, float right, float bottom, int paint)976     private static native void nDrawOval(int renderer, float left, float top,
977             float right, float bottom, int paint);
978 
979     @Override
drawPaint(Paint paint)980     public void drawPaint(Paint paint) {
981         final Rect r = mClipBounds;
982         nGetClipBounds(mRenderer, r);
983         drawRect(r.left, r.top, r.right, r.bottom, paint);
984     }
985 
986     @Override
drawPath(Path path, Paint paint)987     public void drawPath(Path path, Paint paint) {
988         int modifiers = setupModifiers(paint, MODIFIER_COLOR_FILTER | MODIFIER_SHADER);
989         try {
990             if (path.isSimplePath) {
991                 if (path.rects != null) {
992                     nDrawRects(mRenderer, path.rects.mNativeRegion, paint.mNativePaint);
993                 }
994             } else {
995                 nDrawPath(mRenderer, path.mNativePath, paint.mNativePaint);
996             }
997         } finally {
998             if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
999         }
1000     }
1001 
nDrawPath(int renderer, int path, int paint)1002     private static native void nDrawPath(int renderer, int path, int paint);
nDrawRects(int renderer, int region, int paint)1003     private static native void nDrawRects(int renderer, int region, int paint);
1004 
1005     @Override
drawPicture(Picture picture)1006     public void drawPicture(Picture picture) {
1007         if (picture.createdFromStream) {
1008             return;
1009         }
1010 
1011         picture.endRecording();
1012         // TODO: Implement rendering
1013     }
1014 
1015     @Override
drawPicture(Picture picture, Rect dst)1016     public void drawPicture(Picture picture, Rect dst) {
1017         if (picture.createdFromStream) {
1018             return;
1019         }
1020 
1021         save();
1022         translate(dst.left, dst.top);
1023         if (picture.getWidth() > 0 && picture.getHeight() > 0) {
1024             scale(dst.width() / picture.getWidth(), dst.height() / picture.getHeight());
1025         }
1026         drawPicture(picture);
1027         restore();
1028     }
1029 
1030     @Override
drawPicture(Picture picture, RectF dst)1031     public void drawPicture(Picture picture, RectF dst) {
1032         if (picture.createdFromStream) {
1033             return;
1034         }
1035 
1036         save();
1037         translate(dst.left, dst.top);
1038         if (picture.getWidth() > 0 && picture.getHeight() > 0) {
1039             scale(dst.width() / picture.getWidth(), dst.height() / picture.getHeight());
1040         }
1041         drawPicture(picture);
1042         restore();
1043     }
1044 
1045     @Override
drawPoint(float x, float y, Paint paint)1046     public void drawPoint(float x, float y, Paint paint) {
1047         mPoint[0] = x;
1048         mPoint[1] = y;
1049         drawPoints(mPoint, 0, 2, paint);
1050     }
1051 
1052     @Override
drawPoints(float[] pts, Paint paint)1053     public void drawPoints(float[] pts, Paint paint) {
1054         drawPoints(pts, 0, pts.length, paint);
1055     }
1056 
1057     @Override
drawPoints(float[] pts, int offset, int count, Paint paint)1058     public void drawPoints(float[] pts, int offset, int count, Paint paint) {
1059         int modifiers = setupModifiers(paint, MODIFIER_COLOR_FILTER | MODIFIER_SHADER);
1060         try {
1061             nDrawPoints(mRenderer, pts, offset, count, paint.mNativePaint);
1062         } finally {
1063             if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
1064         }
1065     }
1066 
nDrawPoints(int renderer, float[] points, int offset, int count, int paint)1067     private static native void nDrawPoints(int renderer, float[] points,
1068             int offset, int count, int paint);
1069 
1070     @SuppressWarnings("deprecation")
1071     @Override
drawPosText(char[] text, int index, int count, float[] pos, Paint paint)1072     public void drawPosText(char[] text, int index, int count, float[] pos, Paint paint) {
1073         if (index < 0 || index + count > text.length || count * 2 > pos.length) {
1074             throw new IndexOutOfBoundsException();
1075         }
1076 
1077         int modifiers = setupModifiers(paint);
1078         try {
1079             nDrawPosText(mRenderer, text, index, count, pos, paint.mNativePaint);
1080         } finally {
1081             if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
1082         }
1083     }
1084 
nDrawPosText(int renderer, char[] text, int index, int count, float[] pos, int paint)1085     private static native void nDrawPosText(int renderer, char[] text, int index, int count,
1086             float[] pos, int paint);
1087 
1088     @SuppressWarnings("deprecation")
1089     @Override
drawPosText(String text, float[] pos, Paint paint)1090     public void drawPosText(String text, float[] pos, Paint paint) {
1091         if (text.length() * 2 > pos.length) {
1092             throw new ArrayIndexOutOfBoundsException();
1093         }
1094 
1095         int modifiers = setupModifiers(paint);
1096         try {
1097             nDrawPosText(mRenderer, text, 0, text.length(), pos, paint.mNativePaint);
1098         } finally {
1099             if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
1100         }
1101     }
1102 
nDrawPosText(int renderer, String text, int start, int end, float[] pos, int paint)1103     private static native void nDrawPosText(int renderer, String text, int start, int end,
1104             float[] pos, int paint);
1105 
1106     @Override
drawRect(float left, float top, float right, float bottom, Paint paint)1107     public void drawRect(float left, float top, float right, float bottom, Paint paint) {
1108         if (left == right || top == bottom) return;
1109         int modifiers = setupModifiers(paint, MODIFIER_COLOR_FILTER | MODIFIER_SHADER);
1110         try {
1111             nDrawRect(mRenderer, left, top, right, bottom, paint.mNativePaint);
1112         } finally {
1113             if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
1114         }
1115     }
1116 
nDrawRect(int renderer, float left, float top, float right, float bottom, int paint)1117     private static native void nDrawRect(int renderer, float left, float top,
1118             float right, float bottom, int paint);
1119 
1120     @Override
drawRect(Rect r, Paint paint)1121     public void drawRect(Rect r, Paint paint) {
1122         drawRect(r.left, r.top, r.right, r.bottom, paint);
1123     }
1124 
1125     @Override
drawRect(RectF r, Paint paint)1126     public void drawRect(RectF r, Paint paint) {
1127         drawRect(r.left, r.top, r.right, r.bottom, paint);
1128     }
1129 
1130     @Override
drawRGB(int r, int g, int b)1131     public void drawRGB(int r, int g, int b) {
1132         drawColor(0xFF000000 | (r & 0xFF) << 16 | (g & 0xFF) << 8 | (b & 0xFF));
1133     }
1134 
1135     @Override
drawRoundRect(RectF rect, float rx, float ry, Paint paint)1136     public void drawRoundRect(RectF rect, float rx, float ry, Paint paint) {
1137         int modifiers = setupModifiers(paint, MODIFIER_COLOR_FILTER | MODIFIER_SHADER);
1138         try {
1139             nDrawRoundRect(mRenderer, rect.left, rect.top, rect.right, rect.bottom,
1140                     rx, ry, paint.mNativePaint);
1141         } finally {
1142             if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
1143         }
1144     }
1145 
nDrawRoundRect(int renderer, float left, float top, float right, float bottom, float rx, float y, int paint)1146     private static native void nDrawRoundRect(int renderer, float left, float top,
1147             float right, float bottom, float rx, float y, int paint);
1148 
1149     @Override
drawText(char[] text, int index, int count, float x, float y, Paint paint)1150     public void drawText(char[] text, int index, int count, float x, float y, Paint paint) {
1151         if ((index | count | (index + count) | (text.length - index - count)) < 0) {
1152             throw new IndexOutOfBoundsException();
1153         }
1154 
1155         int modifiers = setupModifiers(paint);
1156         try {
1157             nDrawText(mRenderer, text, index, count, x, y, paint.mBidiFlags, paint.mNativePaint);
1158         } finally {
1159             if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
1160         }
1161     }
1162 
nDrawText(int renderer, char[] text, int index, int count, float x, float y, int bidiFlags, int paint)1163     private static native void nDrawText(int renderer, char[] text, int index, int count,
1164             float x, float y, int bidiFlags, int paint);
1165 
1166     @Override
drawText(CharSequence text, int start, int end, float x, float y, Paint paint)1167     public void drawText(CharSequence text, int start, int end, float x, float y, Paint paint) {
1168         int modifiers = setupModifiers(paint);
1169         try {
1170             if (text instanceof String || text instanceof SpannedString ||
1171                     text instanceof SpannableString) {
1172                 nDrawText(mRenderer, text.toString(), start, end, x, y, paint.mBidiFlags,
1173                         paint.mNativePaint);
1174             } else if (text instanceof GraphicsOperations) {
1175                 ((GraphicsOperations) text).drawText(this, start, end, x, y,
1176                                                          paint);
1177             } else {
1178                 char[] buf = TemporaryBuffer.obtain(end - start);
1179                 TextUtils.getChars(text, start, end, buf, 0);
1180                 nDrawText(mRenderer, buf, 0, end - start, x, y,
1181                         paint.mBidiFlags, paint.mNativePaint);
1182                 TemporaryBuffer.recycle(buf);
1183             }
1184         } finally {
1185             if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
1186         }
1187     }
1188 
1189     @Override
drawText(String text, int start, int end, float x, float y, Paint paint)1190     public void drawText(String text, int start, int end, float x, float y, Paint paint) {
1191         if ((start | end | (end - start) | (text.length() - end)) < 0) {
1192             throw new IndexOutOfBoundsException();
1193         }
1194 
1195         int modifiers = setupModifiers(paint);
1196         try {
1197             nDrawText(mRenderer, text, start, end, x, y, paint.mBidiFlags, paint.mNativePaint);
1198         } finally {
1199             if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
1200         }
1201     }
1202 
nDrawText(int renderer, String text, int start, int end, float x, float y, int bidiFlags, int paint)1203     private static native void nDrawText(int renderer, String text, int start, int end,
1204             float x, float y, int bidiFlags, int paint);
1205 
1206     @Override
drawText(String text, float x, float y, Paint paint)1207     public void drawText(String text, float x, float y, Paint paint) {
1208         int modifiers = setupModifiers(paint);
1209         try {
1210             nDrawText(mRenderer, text, 0, text.length(), x, y, paint.mBidiFlags,
1211                     paint.mNativePaint);
1212         } finally {
1213             if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
1214         }
1215     }
1216 
1217     @Override
drawTextOnPath(char[] text, int index, int count, Path path, float hOffset, float vOffset, Paint paint)1218     public void drawTextOnPath(char[] text, int index, int count, Path path, float hOffset,
1219             float vOffset, Paint paint) {
1220         if (index < 0 || index + count > text.length) {
1221             throw new ArrayIndexOutOfBoundsException();
1222         }
1223 
1224         int modifiers = setupModifiers(paint);
1225         try {
1226             nDrawTextOnPath(mRenderer, text, index, count, path.mNativePath, hOffset, vOffset,
1227                     paint.mBidiFlags, paint.mNativePaint);
1228         } finally {
1229             if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
1230         }
1231     }
1232 
nDrawTextOnPath(int renderer, char[] text, int index, int count, int path, float hOffset, float vOffset, int bidiFlags, int nativePaint)1233     private static native void nDrawTextOnPath(int renderer, char[] text, int index, int count,
1234             int path, float hOffset, float vOffset, int bidiFlags, int nativePaint);
1235 
1236     @Override
drawTextOnPath(String text, Path path, float hOffset, float vOffset, Paint paint)1237     public void drawTextOnPath(String text, Path path, float hOffset, float vOffset, Paint paint) {
1238         if (text.length() == 0) return;
1239 
1240         int modifiers = setupModifiers(paint);
1241         try {
1242             nDrawTextOnPath(mRenderer, text, 0, text.length(), path.mNativePath, hOffset, vOffset,
1243                     paint.mBidiFlags, paint.mNativePaint);
1244         } finally {
1245             if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
1246         }
1247     }
1248 
nDrawTextOnPath(int renderer, String text, int start, int end, int path, float hOffset, float vOffset, int bidiFlags, int nativePaint)1249     private static native void nDrawTextOnPath(int renderer, String text, int start, int end,
1250             int path, float hOffset, float vOffset, int bidiFlags, int nativePaint);
1251 
1252     @Override
drawTextRun(char[] text, int index, int count, int contextIndex, int contextCount, float x, float y, int dir, Paint paint)1253     public void drawTextRun(char[] text, int index, int count, int contextIndex, int contextCount,
1254             float x, float y, int dir, Paint paint) {
1255         if ((index | count | text.length - index - count) < 0) {
1256             throw new IndexOutOfBoundsException();
1257         }
1258         if (dir != DIRECTION_LTR && dir != DIRECTION_RTL) {
1259             throw new IllegalArgumentException("Unknown direction: " + dir);
1260         }
1261 
1262         int modifiers = setupModifiers(paint);
1263         try {
1264             nDrawTextRun(mRenderer, text, index, count, contextIndex, contextCount, x, y, dir,
1265                     paint.mNativePaint);
1266         } finally {
1267             if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
1268         }
1269     }
1270 
nDrawTextRun(int renderer, char[] text, int index, int count, int contextIndex, int contextCount, float x, float y, int dir, int nativePaint)1271     private static native void nDrawTextRun(int renderer, char[] text, int index, int count,
1272             int contextIndex, int contextCount, float x, float y, int dir, int nativePaint);
1273 
1274     @Override
drawTextRun(CharSequence text, int start, int end, int contextStart, int contextEnd, float x, float y, int dir, Paint paint)1275     public void drawTextRun(CharSequence text, int start, int end, int contextStart, int contextEnd,
1276             float x, float y, int dir, Paint paint) {
1277         if ((start | end | end - start | text.length() - end) < 0) {
1278             throw new IndexOutOfBoundsException();
1279         }
1280 
1281         int modifiers = setupModifiers(paint);
1282         try {
1283             int flags = dir == 0 ? 0 : 1;
1284             if (text instanceof String || text instanceof SpannedString ||
1285                     text instanceof SpannableString) {
1286                 nDrawTextRun(mRenderer, text.toString(), start, end, contextStart,
1287                         contextEnd, x, y, flags, paint.mNativePaint);
1288             } else if (text instanceof GraphicsOperations) {
1289                 ((GraphicsOperations) text).drawTextRun(this, start, end,
1290                         contextStart, contextEnd, x, y, flags, paint);
1291             } else {
1292                 int contextLen = contextEnd - contextStart;
1293                 int len = end - start;
1294                 char[] buf = TemporaryBuffer.obtain(contextLen);
1295                 TextUtils.getChars(text, contextStart, contextEnd, buf, 0);
1296                 nDrawTextRun(mRenderer, buf, start - contextStart, len, 0, contextLen,
1297                         x, y, flags, paint.mNativePaint);
1298                 TemporaryBuffer.recycle(buf);
1299             }
1300         } finally {
1301             if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
1302         }
1303     }
1304 
nDrawTextRun(int renderer, String text, int start, int end, int contextStart, int contextEnd, float x, float y, int flags, int nativePaint)1305     private static native void nDrawTextRun(int renderer, String text, int start, int end,
1306             int contextStart, int contextEnd, float x, float y, int flags, int nativePaint);
1307 
1308     @Override
drawVertices(VertexMode mode, int vertexCount, float[] verts, int vertOffset, float[] texs, int texOffset, int[] colors, int colorOffset, short[] indices, int indexOffset, int indexCount, Paint paint)1309     public void drawVertices(VertexMode mode, int vertexCount, float[] verts, int vertOffset,
1310             float[] texs, int texOffset, int[] colors, int colorOffset, short[] indices,
1311             int indexOffset, int indexCount, Paint paint) {
1312         // TODO: Implement
1313     }
1314 
setupModifiers(Bitmap b, Paint paint)1315     private int setupModifiers(Bitmap b, Paint paint) {
1316         if (b.getConfig() != Bitmap.Config.ALPHA_8) {
1317             final ColorFilter filter = paint.getColorFilter();
1318             if (filter != null) {
1319                 nSetupColorFilter(mRenderer, filter.nativeColorFilter);
1320                 return MODIFIER_COLOR_FILTER;
1321             }
1322 
1323             return MODIFIER_NONE;
1324         } else {
1325             return setupModifiers(paint);
1326         }
1327     }
1328 
setupModifiers(Paint paint)1329     private int setupModifiers(Paint paint) {
1330         int modifiers = MODIFIER_NONE;
1331 
1332         if (paint.hasShadow) {
1333             nSetupShadow(mRenderer, paint.shadowRadius, paint.shadowDx, paint.shadowDy,
1334                     paint.shadowColor);
1335             modifiers |= MODIFIER_SHADOW;
1336         }
1337 
1338         final Shader shader = paint.getShader();
1339         if (shader != null) {
1340             nSetupShader(mRenderer, shader.native_shader);
1341             modifiers |= MODIFIER_SHADER;
1342         }
1343 
1344         final ColorFilter filter = paint.getColorFilter();
1345         if (filter != null) {
1346             nSetupColorFilter(mRenderer, filter.nativeColorFilter);
1347             modifiers |= MODIFIER_COLOR_FILTER;
1348         }
1349 
1350         return modifiers;
1351     }
1352 
setupModifiers(Paint paint, int flags)1353     private int setupModifiers(Paint paint, int flags) {
1354         int modifiers = MODIFIER_NONE;
1355 
1356         if (paint.hasShadow && (flags & MODIFIER_SHADOW) != 0) {
1357             nSetupShadow(mRenderer, paint.shadowRadius, paint.shadowDx, paint.shadowDy,
1358                     paint.shadowColor);
1359             modifiers |= MODIFIER_SHADOW;
1360         }
1361 
1362         final Shader shader = paint.getShader();
1363         if (shader != null && (flags & MODIFIER_SHADER) != 0) {
1364             nSetupShader(mRenderer, shader.native_shader);
1365             modifiers |= MODIFIER_SHADER;
1366         }
1367 
1368         final ColorFilter filter = paint.getColorFilter();
1369         if (filter != null && (flags & MODIFIER_COLOR_FILTER) != 0) {
1370             nSetupColorFilter(mRenderer, filter.nativeColorFilter);
1371             modifiers |= MODIFIER_COLOR_FILTER;
1372         }
1373 
1374         return modifiers;
1375     }
1376 
setupColorFilter(Paint paint)1377     private int setupColorFilter(Paint paint) {
1378         final ColorFilter filter = paint.getColorFilter();
1379         if (filter != null) {
1380             nSetupColorFilter(mRenderer, filter.nativeColorFilter);
1381             return MODIFIER_COLOR_FILTER;
1382         }
1383         return MODIFIER_NONE;
1384     }
1385 
nSetupShader(int renderer, int shader)1386     private static native void nSetupShader(int renderer, int shader);
nSetupColorFilter(int renderer, int colorFilter)1387     private static native void nSetupColorFilter(int renderer, int colorFilter);
nSetupShadow(int renderer, float radius, float dx, float dy, int color)1388     private static native void nSetupShadow(int renderer, float radius,
1389             float dx, float dy, int color);
1390 
nResetModifiers(int renderer, int modifiers)1391     private static native void nResetModifiers(int renderer, int modifiers);
1392 }
1393