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