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