GLES20Canvas.java revision 7c1a49f5f5ed6613d736464bf5001b777e89ced2
1/*
2 * Copyright (C) 2010 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package android.view;
18
19import android.graphics.Bitmap;
20import android.graphics.Canvas;
21import android.graphics.ColorFilter;
22import android.graphics.DrawFilter;
23import android.graphics.Matrix;
24import android.graphics.Paint;
25import android.graphics.PaintFlagsDrawFilter;
26import android.graphics.Path;
27import android.graphics.Picture;
28import android.graphics.PorterDuff;
29import android.graphics.Rect;
30import android.graphics.RectF;
31import android.graphics.Region;
32import android.graphics.Shader;
33import android.graphics.SurfaceTexture;
34import android.graphics.TemporaryBuffer;
35import android.text.GraphicsOperations;
36import android.text.SpannableString;
37import android.text.SpannedString;
38import android.text.TextUtils;
39
40/**
41 * An implementation of Canvas on top of OpenGL ES 2.0.
42 */
43class 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
73    private static native boolean nIsAvailable();
74    private static boolean sIsAvailable = nIsAvailable();
75
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     */
87    GLES20Canvas(boolean translucent) {
88        this(false, translucent);
89    }
90
91    /**
92     * Creates a canvas to render into an FBO.
93     */
94    GLES20Canvas(int layer, boolean translucent) {
95        mOpaque = !translucent;
96        mRenderer = nCreateLayerRenderer(layer);
97        setupFinalizer();
98    }
99
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
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
120    protected void resetDisplayListRenderer() {
121        nResetDisplayListRenderer(mRenderer);
122    }
123
124    private static native int nCreateRenderer();
125    private static native int nCreateLayerRenderer(int layer);
126    private static native int nCreateDisplayListRenderer();
127    private static native void nResetDisplayListRenderer(int renderer);
128    private static native void nDestroyRenderer(int renderer);
129
130    private static final class CanvasFinalizer {
131        private final int mRenderer;
132
133        public CanvasFinalizer(int renderer) {
134            mRenderer = renderer;
135        }
136
137        @Override
138        protected void finalize() throws Throwable {
139            try {
140                nDestroyRenderer(mRenderer);
141            } finally {
142                super.finalize();
143            }
144        }
145    }
146
147    @Override
148    public void setName(String name) {
149        super.setName(name);
150        nSetName(mRenderer, name);
151    }
152
153    private static native void nSetName(int renderer, String name);
154
155    ///////////////////////////////////////////////////////////////////////////
156    // Hardware layers
157    ///////////////////////////////////////////////////////////////////////////
158
159    @Override
160    void pushLayerUpdate(HardwareLayer layer) {
161        nPushLayerUpdate(mRenderer, ((GLES20RenderLayer) layer).mLayer);
162    }
163
164    @Override
165    void clearLayerUpdates() {
166        nClearLayerUpdates(mRenderer);
167    }
168
169    static native int nCreateTextureLayer(boolean opaque, int[] layerInfo);
170    static native int nCreateLayer(int width, int height, boolean isOpaque, int[] layerInfo);
171    static native boolean nResizeLayer(int layerId, int width, int height, int[] layerInfo);
172    static native void nSetOpaqueLayer(int layerId, boolean isOpaque);
173    static native void nSetLayerPaint(int layerId, int nativePaint);
174    static native void nSetLayerColorFilter(int layerId, int nativeColorFilter);
175    static native void nUpdateTextureLayer(int layerId, int width, int height, boolean opaque,
176            SurfaceTexture surface);
177    static native void nClearLayerTexture(int layerId);
178    static native void nSetTextureLayerTransform(int layerId, int matrix);
179    static native void nDestroyLayer(int layerId);
180    static native void nDestroyLayerDeferred(int layerId);
181    static native void nUpdateRenderLayer(int layerId, int renderer, int displayList,
182            int left, int top, int right, int bottom);
183    static native boolean nCopyLayer(int layerId, int bitmap);
184
185    private static native void nClearLayerUpdates(int renderer);
186    private static native void nPushLayerUpdate(int renderer, int layer);
187
188    ///////////////////////////////////////////////////////////////////////////
189    // Canvas management
190    ///////////////////////////////////////////////////////////////////////////
191
192    @Override
193    public boolean isOpaque() {
194        return mOpaque;
195    }
196
197    @Override
198    public int getWidth() {
199        return mWidth;
200    }
201
202    @Override
203    public int getHeight() {
204        return mHeight;
205    }
206
207    @Override
208    public int getMaximumBitmapWidth() {
209        return nGetMaximumTextureWidth();
210    }
211
212    @Override
213    public int getMaximumBitmapHeight() {
214        return nGetMaximumTextureHeight();
215    }
216
217    private static native int nGetMaximumTextureWidth();
218    private static native int nGetMaximumTextureHeight();
219
220    /**
221     * Returns the native OpenGLRenderer object.
222     */
223    int getRenderer() {
224        return mRenderer;
225    }
226
227    ///////////////////////////////////////////////////////////////////////////
228    // Setup
229    ///////////////////////////////////////////////////////////////////////////
230
231    @Override
232    public void setViewport(int width, int height) {
233        mWidth = width;
234        mHeight = height;
235
236        nSetViewport(mRenderer, width, height);
237    }
238
239    private static native void nSetViewport(int renderer, int width, int height);
240
241    @Override
242    public int onPreDraw(Rect dirty) {
243        if (dirty != null) {
244            return nPrepareDirty(mRenderer, dirty.left, dirty.top, dirty.right, dirty.bottom,
245                    mOpaque);
246        } else {
247            return nPrepare(mRenderer, mOpaque);
248        }
249    }
250
251    private static native int nPrepare(int renderer, boolean opaque);
252    private static native int nPrepareDirty(int renderer, int left, int top, int right, int bottom,
253            boolean opaque);
254
255    @Override
256    public void onPostDraw() {
257        nFinish(mRenderer);
258    }
259
260    private static native void nFinish(int renderer);
261
262    /**
263     * Returns the size of the stencil buffer required by the underlying
264     * implementation.
265     *
266     * @return The minimum number of bits the stencil buffer must. Always >= 0.
267     *
268     * @hide
269     */
270    public static int getStencilSize() {
271        return nGetStencilSize();
272    }
273
274    private static native int nGetStencilSize();
275
276    ///////////////////////////////////////////////////////////////////////////
277    // Functor
278    ///////////////////////////////////////////////////////////////////////////
279
280    @Override
281    public int callDrawGLFunction(int drawGLFunction) {
282        return nCallDrawGLFunction(mRenderer, drawGLFunction);
283    }
284
285    private static native int nCallDrawGLFunction(int renderer, int drawGLFunction);
286
287    @Override
288    public int invokeFunctors(Rect dirty) {
289        return nInvokeFunctors(mRenderer, dirty);
290    }
291
292    private static native int nInvokeFunctors(int renderer, Rect dirty);
293
294    @Override
295    public void detachFunctor(int functor) {
296        nDetachFunctor(mRenderer, functor);
297    }
298
299    private static native void nDetachFunctor(int renderer, int functor);
300
301    @Override
302    public void attachFunctor(int functor) {
303        nAttachFunctor(mRenderer, functor);
304    }
305
306    private static native void nAttachFunctor(int renderer, int functor);
307
308    ///////////////////////////////////////////////////////////////////////////
309    // Memory
310    ///////////////////////////////////////////////////////////////////////////
311
312    /**
313     * Must match Caches::FlushMode values
314     *
315     * @see #flushCaches(int)
316     */
317    public static final int FLUSH_CACHES_LAYERS = 0;
318
319    /**
320     * Must match Caches::FlushMode values
321     *
322     * @see #flushCaches(int)
323     */
324    public static final int FLUSH_CACHES_MODERATE = 1;
325
326    /**
327     * Must match Caches::FlushMode values
328     *
329     * @see #flushCaches(int)
330     */
331    public static final int FLUSH_CACHES_FULL = 2;
332
333    /**
334     * Flush caches to reclaim as much memory as possible. The amount of memory
335     * to reclaim is indicate by the level parameter.
336     *
337     * The level can be one of {@link #FLUSH_CACHES_MODERATE} or
338     * {@link #FLUSH_CACHES_FULL}.
339     *
340     * @param level Hint about the amount of memory to reclaim
341     *
342     * @hide
343     */
344    public static void flushCaches(int level) {
345        nFlushCaches(level);
346    }
347
348    private static native void nFlushCaches(int level);
349
350    /**
351     * Release all resources associated with the underlying caches. This should
352     * only be called after a full flushCaches().
353     *
354     * @hide
355     */
356    public static void terminateCaches() {
357        nTerminateCaches();
358    }
359
360    private static native void nTerminateCaches();
361
362    /**
363     * @hide
364     */
365    public static void initCaches() {
366        nInitCaches();
367    }
368
369    private static native void nInitCaches();
370
371    ///////////////////////////////////////////////////////////////////////////
372    // Display list
373    ///////////////////////////////////////////////////////////////////////////
374
375    int getDisplayList(int displayList) {
376        return nGetDisplayList(mRenderer, displayList);
377    }
378
379    private static native int nGetDisplayList(int renderer, int displayList);
380
381    static void destroyDisplayList(int displayList) {
382        nDestroyDisplayList(displayList);
383    }
384
385    private static native void nDestroyDisplayList(int displayList);
386
387    static int getDisplayListSize(int displayList) {
388        return nGetDisplayListSize(displayList);
389    }
390
391    private static native int nGetDisplayListSize(int displayList);
392
393    static void setDisplayListName(int displayList, String name) {
394        nSetDisplayListName(displayList, name);
395    }
396
397    private static native void nSetDisplayListName(int displayList, String name);
398
399    @Override
400    public int drawDisplayList(DisplayList displayList, Rect dirty, int flags) {
401        return nDrawDisplayList(mRenderer, ((GLES20DisplayList) displayList).getNativeDisplayList(),
402                dirty, flags);
403    }
404
405    private static native int nDrawDisplayList(int renderer, int displayList,
406            Rect dirty, int flags);
407
408    @Override
409    void outputDisplayList(DisplayList displayList) {
410        nOutputDisplayList(mRenderer, ((GLES20DisplayList) displayList).getNativeDisplayList());
411    }
412
413    private static native void nOutputDisplayList(int renderer, int displayList);
414
415    ///////////////////////////////////////////////////////////////////////////
416    // Hardware layer
417    ///////////////////////////////////////////////////////////////////////////
418
419    void drawHardwareLayer(HardwareLayer layer, float x, float y, Paint paint) {
420        final GLES20Layer glLayer = (GLES20Layer) layer;
421        final int nativePaint = paint == null ? 0 : paint.mNativePaint;
422        nDrawLayer(mRenderer, glLayer.getLayer(), x, y, nativePaint);
423    }
424
425    private static native void nDrawLayer(int renderer, int layer, float x, float y, int paint);
426
427    void interrupt() {
428        nInterrupt(mRenderer);
429    }
430
431    void resume() {
432        nResume(mRenderer);
433    }
434
435    private static native void nInterrupt(int renderer);
436    private static native void nResume(int renderer);
437
438    ///////////////////////////////////////////////////////////////////////////
439    // Clipping
440    ///////////////////////////////////////////////////////////////////////////
441
442    @Override
443    public boolean clipPath(Path path) {
444        return nClipPath(mRenderer, path.mNativePath, Region.Op.INTERSECT.nativeInt);
445    }
446
447    @Override
448    public boolean clipPath(Path path, Region.Op op) {
449        return nClipPath(mRenderer, path.mNativePath, op.nativeInt);
450    }
451
452    private static native boolean nClipPath(int renderer, int path, int op);
453
454    @Override
455    public boolean clipRect(float left, float top, float right, float bottom) {
456        return nClipRect(mRenderer, left, top, right, bottom, Region.Op.INTERSECT.nativeInt);
457    }
458
459    private static native boolean nClipRect(int renderer, float left, float top,
460            float right, float bottom, int op);
461
462    @Override
463    public boolean clipRect(float left, float top, float right, float bottom, Region.Op op) {
464        return nClipRect(mRenderer, left, top, right, bottom, op.nativeInt);
465    }
466
467    @Override
468    public boolean clipRect(int left, int top, int right, int bottom) {
469        return nClipRect(mRenderer, left, top, right, bottom, Region.Op.INTERSECT.nativeInt);
470    }
471
472    private static native boolean nClipRect(int renderer, int left, int top,
473            int right, int bottom, int op);
474
475    @Override
476    public boolean clipRect(Rect rect) {
477        return nClipRect(mRenderer, rect.left, rect.top, rect.right, rect.bottom,
478                Region.Op.INTERSECT.nativeInt);
479    }
480
481    @Override
482    public boolean clipRect(Rect rect, Region.Op op) {
483        return nClipRect(mRenderer, rect.left, rect.top, rect.right, rect.bottom, op.nativeInt);
484    }
485
486    @Override
487    public boolean clipRect(RectF rect) {
488        return nClipRect(mRenderer, rect.left, rect.top, rect.right, rect.bottom,
489                Region.Op.INTERSECT.nativeInt);
490    }
491
492    @Override
493    public boolean clipRect(RectF rect, Region.Op op) {
494        return nClipRect(mRenderer, rect.left, rect.top, rect.right, rect.bottom, op.nativeInt);
495    }
496
497    @Override
498    public boolean clipRegion(Region region) {
499        return nClipRegion(mRenderer, region.mNativeRegion, Region.Op.INTERSECT.nativeInt);
500    }
501
502    @Override
503    public boolean clipRegion(Region region, Region.Op op) {
504        return nClipRegion(mRenderer, region.mNativeRegion, op.nativeInt);
505    }
506
507    private static native boolean nClipRegion(int renderer, int region, int op);
508
509    @Override
510    public boolean getClipBounds(Rect bounds) {
511        return nGetClipBounds(mRenderer, bounds);
512    }
513
514    private static native boolean nGetClipBounds(int renderer, Rect bounds);
515
516    @Override
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
521    private static native boolean nQuickReject(int renderer, float left, float top,
522            float right, float bottom, int edge);
523
524    @Override
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
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
541    public void translate(float dx, float dy) {
542        if (dx != 0.0f || dy != 0.0f) nTranslate(mRenderer, dx, dy);
543    }
544
545    private static native void nTranslate(int renderer, float dx, float dy);
546
547    @Override
548    public void skew(float sx, float sy) {
549        nSkew(mRenderer, sx, sy);
550    }
551
552    private static native void nSkew(int renderer, float sx, float sy);
553
554    @Override
555    public void rotate(float degrees) {
556        nRotate(mRenderer, degrees);
557    }
558
559    private static native void nRotate(int renderer, float degrees);
560
561    @Override
562    public void scale(float sx, float sy) {
563        nScale(mRenderer, sx, sy);
564    }
565
566    private static native void nScale(int renderer, float sx, float sy);
567
568    @Override
569    public void setMatrix(Matrix matrix) {
570        nSetMatrix(mRenderer, matrix == null ? 0 : matrix.native_instance);
571    }
572
573    private static native void nSetMatrix(int renderer, int matrix);
574
575    @SuppressWarnings("deprecation")
576    @Override
577    public void getMatrix(Matrix matrix) {
578        nGetMatrix(mRenderer, matrix.native_instance);
579    }
580
581    private static native void nGetMatrix(int renderer, int matrix);
582
583    @Override
584    public void concat(Matrix matrix) {
585        nConcatMatrix(mRenderer, matrix.native_instance);
586    }
587
588    private static native void nConcatMatrix(int renderer, int matrix);
589
590    ///////////////////////////////////////////////////////////////////////////
591    // State management
592    ///////////////////////////////////////////////////////////////////////////
593
594    @Override
595    public int save() {
596        return nSave(mRenderer, Canvas.CLIP_SAVE_FLAG | Canvas.MATRIX_SAVE_FLAG);
597    }
598
599    @Override
600    public int save(int saveFlags) {
601        return nSave(mRenderer, saveFlags);
602    }
603
604    private static native int nSave(int renderer, int flags);
605
606    @Override
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
623    private static native int nSaveLayer(int renderer, int paint, int saveFlags);
624
625    @Override
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
642    private static native int nSaveLayer(int renderer, float left, float top,
643            float right, float bottom, int paint, int saveFlags);
644
645    @Override
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
654    private static native int nSaveLayerAlpha(int renderer, int alpha, int saveFlags);
655
656    @Override
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
665    private static native int nSaveLayerAlpha(int renderer, float left, float top, float right,
666            float bottom, int alpha, int saveFlags);
667
668    @Override
669    public void restore() {
670        nRestore(mRenderer);
671    }
672
673    private static native void nRestore(int renderer);
674
675    @Override
676    public void restoreToCount(int saveCount) {
677        nRestoreToCount(mRenderer, saveCount);
678    }
679
680    private static native void nRestoreToCount(int renderer, int saveCount);
681
682    @Override
683    public int getSaveCount() {
684        return nGetSaveCount(mRenderer);
685    }
686
687    private static native int nGetSaveCount(int renderer);
688
689    ///////////////////////////////////////////////////////////////////////////
690    // Filtering
691    ///////////////////////////////////////////////////////////////////////////
692
693    @Override
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
704    private static native void nResetPaintFilter(int renderer);
705    private static native void nSetupPaintFilter(int renderer, int clearBits, int setBits);
706
707    @Override
708    public DrawFilter getDrawFilter() {
709        return mFilter;
710    }
711
712    ///////////////////////////////////////////////////////////////////////////
713    // Drawing
714    ///////////////////////////////////////////////////////////////////////////
715
716    @Override
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
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
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
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
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
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
767    private static native void nDrawBitmap(
768            int renderer, int bitmap, byte[] buffer, float left, float top, int paint);
769
770    @Override
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
784    private static native void nDrawBitmap(int renderer, int bitmap, byte[] buff,
785            int matrix, int paint);
786
787    @Override
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
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
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
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
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
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
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
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
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
932    private static native void nDrawCircle(int renderer, float cx, float cy,
933            float radius, int paint);
934
935    @Override
936    public void drawColor(int color) {
937        drawColor(color, PorterDuff.Mode.SRC_OVER);
938    }
939
940    @Override
941    public void drawColor(int color, PorterDuff.Mode mode) {
942        nDrawColor(mRenderer, color, mode.nativeInt);
943    }
944
945    private static native void nDrawColor(int renderer, int color, int mode);
946
947    @Override
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
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
969    private static native void nDrawLines(int renderer, float[] points,
970            int offset, int count, int paint);
971
972    @Override
973    public void drawLines(float[] pts, Paint paint) {
974        drawLines(pts, 0, pts.length, paint);
975    }
976
977    @Override
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
987    private static native void nDrawOval(int renderer, float left, float top,
988            float right, float bottom, int paint);
989
990    @Override
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
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
1013    private static native void nDrawPath(int renderer, int path, int paint);
1014    private static native void nDrawRects(int renderer, int region, int paint);
1015
1016    void drawRects(float[] rects, int count, Paint paint) {
1017        int modifiers = setupModifiers(paint, MODIFIER_COLOR_FILTER | MODIFIER_SHADER);
1018        try {
1019            nDrawRects(mRenderer, rects, count, paint.mNativePaint);
1020        } finally {
1021            if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
1022        }
1023    }
1024
1025    private static native void nDrawRects(int renderer, float[] rects, int count, int paint);
1026
1027    @Override
1028    public void drawPicture(Picture picture) {
1029        if (picture.createdFromStream) {
1030            return;
1031        }
1032
1033        picture.endRecording();
1034        // TODO: Implement rendering
1035    }
1036
1037    @Override
1038    public void drawPicture(Picture picture, Rect dst) {
1039        if (picture.createdFromStream) {
1040            return;
1041        }
1042
1043        save();
1044        translate(dst.left, dst.top);
1045        if (picture.getWidth() > 0 && picture.getHeight() > 0) {
1046            scale(dst.width() / picture.getWidth(), dst.height() / picture.getHeight());
1047        }
1048        drawPicture(picture);
1049        restore();
1050    }
1051
1052    @Override
1053    public void drawPicture(Picture picture, RectF dst) {
1054        if (picture.createdFromStream) {
1055            return;
1056        }
1057
1058        save();
1059        translate(dst.left, dst.top);
1060        if (picture.getWidth() > 0 && picture.getHeight() > 0) {
1061            scale(dst.width() / picture.getWidth(), dst.height() / picture.getHeight());
1062        }
1063        drawPicture(picture);
1064        restore();
1065    }
1066
1067    @Override
1068    public void drawPoint(float x, float y, Paint paint) {
1069        mPoint[0] = x;
1070        mPoint[1] = y;
1071        drawPoints(mPoint, 0, 2, paint);
1072    }
1073
1074    @Override
1075    public void drawPoints(float[] pts, Paint paint) {
1076        drawPoints(pts, 0, pts.length, paint);
1077    }
1078
1079    @Override
1080    public void drawPoints(float[] pts, int offset, int count, Paint paint) {
1081        int modifiers = setupModifiers(paint, MODIFIER_COLOR_FILTER | MODIFIER_SHADER);
1082        try {
1083            nDrawPoints(mRenderer, pts, offset, count, paint.mNativePaint);
1084        } finally {
1085            if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
1086        }
1087    }
1088
1089    private static native void nDrawPoints(int renderer, float[] points,
1090            int offset, int count, int paint);
1091
1092    @SuppressWarnings("deprecation")
1093    @Override
1094    public void drawPosText(char[] text, int index, int count, float[] pos, Paint paint) {
1095        if (index < 0 || index + count > text.length || count * 2 > pos.length) {
1096            throw new IndexOutOfBoundsException();
1097        }
1098
1099        int modifiers = setupModifiers(paint);
1100        try {
1101            nDrawPosText(mRenderer, text, index, count, pos, paint.mNativePaint);
1102        } finally {
1103            if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
1104        }
1105    }
1106
1107    private static native void nDrawPosText(int renderer, char[] text, int index, int count,
1108            float[] pos, int paint);
1109
1110    @SuppressWarnings("deprecation")
1111    @Override
1112    public void drawPosText(String text, float[] pos, Paint paint) {
1113        if (text.length() * 2 > pos.length) {
1114            throw new ArrayIndexOutOfBoundsException();
1115        }
1116
1117        int modifiers = setupModifiers(paint);
1118        try {
1119            nDrawPosText(mRenderer, text, 0, text.length(), pos, paint.mNativePaint);
1120        } finally {
1121            if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
1122        }
1123    }
1124
1125    private static native void nDrawPosText(int renderer, String text, int start, int end,
1126            float[] pos, int paint);
1127
1128    @Override
1129    public void drawRect(float left, float top, float right, float bottom, Paint paint) {
1130        if (left == right || top == bottom) return;
1131        int modifiers = setupModifiers(paint, MODIFIER_COLOR_FILTER | MODIFIER_SHADER);
1132        try {
1133            nDrawRect(mRenderer, left, top, right, bottom, paint.mNativePaint);
1134        } finally {
1135            if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
1136        }
1137    }
1138
1139    private static native void nDrawRect(int renderer, float left, float top,
1140            float right, float bottom, int paint);
1141
1142    @Override
1143    public void drawRect(Rect r, Paint paint) {
1144        drawRect(r.left, r.top, r.right, r.bottom, paint);
1145    }
1146
1147    @Override
1148    public void drawRect(RectF r, Paint paint) {
1149        drawRect(r.left, r.top, r.right, r.bottom, paint);
1150    }
1151
1152    @Override
1153    public void drawRGB(int r, int g, int b) {
1154        drawColor(0xFF000000 | (r & 0xFF) << 16 | (g & 0xFF) << 8 | (b & 0xFF));
1155    }
1156
1157    @Override
1158    public void drawRoundRect(RectF rect, float rx, float ry, Paint paint) {
1159        int modifiers = setupModifiers(paint, MODIFIER_COLOR_FILTER | MODIFIER_SHADER);
1160        try {
1161            nDrawRoundRect(mRenderer, rect.left, rect.top, rect.right, rect.bottom,
1162                    rx, ry, paint.mNativePaint);
1163        } finally {
1164            if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
1165        }
1166    }
1167
1168    private static native void nDrawRoundRect(int renderer, float left, float top,
1169            float right, float bottom, float rx, float y, int paint);
1170
1171    @Override
1172    public void drawText(char[] text, int index, int count, float x, float y, Paint paint) {
1173        if ((index | count | (index + count) | (text.length - index - count)) < 0) {
1174            throw new IndexOutOfBoundsException();
1175        }
1176
1177        int modifiers = setupModifiers(paint);
1178        try {
1179            nDrawText(mRenderer, text, index, count, x, y, paint.mBidiFlags, paint.mNativePaint);
1180        } finally {
1181            if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
1182        }
1183    }
1184
1185    private static native void nDrawText(int renderer, char[] text, int index, int count,
1186            float x, float y, int bidiFlags, int paint);
1187
1188    @Override
1189    public void drawText(CharSequence text, int start, int end, float x, float y, Paint paint) {
1190        int modifiers = setupModifiers(paint);
1191        try {
1192            if (text instanceof String || text instanceof SpannedString ||
1193                    text instanceof SpannableString) {
1194                nDrawText(mRenderer, text.toString(), start, end, x, y, paint.mBidiFlags,
1195                        paint.mNativePaint);
1196            } else if (text instanceof GraphicsOperations) {
1197                ((GraphicsOperations) text).drawText(this, start, end, x, y,
1198                                                         paint);
1199            } else {
1200                char[] buf = TemporaryBuffer.obtain(end - start);
1201                TextUtils.getChars(text, start, end, buf, 0);
1202                nDrawText(mRenderer, buf, 0, end - start, x, y,
1203                        paint.mBidiFlags, paint.mNativePaint);
1204                TemporaryBuffer.recycle(buf);
1205            }
1206        } finally {
1207            if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
1208        }
1209    }
1210
1211    @Override
1212    public void drawText(String text, int start, int end, float x, float y, Paint paint) {
1213        if ((start | end | (end - start) | (text.length() - end)) < 0) {
1214            throw new IndexOutOfBoundsException();
1215        }
1216
1217        int modifiers = setupModifiers(paint);
1218        try {
1219            nDrawText(mRenderer, text, start, end, x, y, paint.mBidiFlags, paint.mNativePaint);
1220        } finally {
1221            if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
1222        }
1223    }
1224
1225    private static native void nDrawText(int renderer, String text, int start, int end,
1226            float x, float y, int bidiFlags, int paint);
1227
1228    @Override
1229    public void drawText(String text, float x, float y, Paint paint) {
1230        int modifiers = setupModifiers(paint);
1231        try {
1232            nDrawText(mRenderer, text, 0, text.length(), x, y, paint.mBidiFlags,
1233                    paint.mNativePaint);
1234        } finally {
1235            if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
1236        }
1237    }
1238
1239    @Override
1240    public void drawTextOnPath(char[] text, int index, int count, Path path, float hOffset,
1241            float vOffset, Paint paint) {
1242        if (index < 0 || index + count > text.length) {
1243            throw new ArrayIndexOutOfBoundsException();
1244        }
1245
1246        int modifiers = setupModifiers(paint);
1247        try {
1248            nDrawTextOnPath(mRenderer, text, index, count, path.mNativePath, hOffset, vOffset,
1249                    paint.mBidiFlags, paint.mNativePaint);
1250        } finally {
1251            if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
1252        }
1253    }
1254
1255    private static native void nDrawTextOnPath(int renderer, char[] text, int index, int count,
1256            int path, float hOffset, float vOffset, int bidiFlags, int nativePaint);
1257
1258    @Override
1259    public void drawTextOnPath(String text, Path path, float hOffset, float vOffset, Paint paint) {
1260        if (text.length() == 0) return;
1261
1262        int modifiers = setupModifiers(paint);
1263        try {
1264            nDrawTextOnPath(mRenderer, text, 0, text.length(), path.mNativePath, hOffset, vOffset,
1265                    paint.mBidiFlags, paint.mNativePaint);
1266        } finally {
1267            if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
1268        }
1269    }
1270
1271    private static native void nDrawTextOnPath(int renderer, String text, int start, int end,
1272            int path, float hOffset, float vOffset, int bidiFlags, int nativePaint);
1273
1274    @Override
1275    public void drawTextRun(char[] text, int index, int count, int contextIndex, int contextCount,
1276            float x, float y, int dir, Paint paint) {
1277        if ((index | count | text.length - index - count) < 0) {
1278            throw new IndexOutOfBoundsException();
1279        }
1280        if (dir != DIRECTION_LTR && dir != DIRECTION_RTL) {
1281            throw new IllegalArgumentException("Unknown direction: " + dir);
1282        }
1283
1284        int modifiers = setupModifiers(paint);
1285        try {
1286            nDrawTextRun(mRenderer, text, index, count, contextIndex, contextCount, x, y, dir,
1287                    paint.mNativePaint);
1288        } finally {
1289            if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
1290        }
1291    }
1292
1293    private static native void nDrawTextRun(int renderer, char[] text, int index, int count,
1294            int contextIndex, int contextCount, float x, float y, int dir, int nativePaint);
1295
1296    @Override
1297    public void drawTextRun(CharSequence text, int start, int end, int contextStart, int contextEnd,
1298            float x, float y, int dir, Paint paint) {
1299        if ((start | end | end - start | text.length() - end) < 0) {
1300            throw new IndexOutOfBoundsException();
1301        }
1302
1303        int modifiers = setupModifiers(paint);
1304        try {
1305            int flags = dir == 0 ? 0 : 1;
1306            if (text instanceof String || text instanceof SpannedString ||
1307                    text instanceof SpannableString) {
1308                nDrawTextRun(mRenderer, text.toString(), start, end, contextStart,
1309                        contextEnd, x, y, flags, paint.mNativePaint);
1310            } else if (text instanceof GraphicsOperations) {
1311                ((GraphicsOperations) text).drawTextRun(this, start, end,
1312                        contextStart, contextEnd, x, y, flags, paint);
1313            } else {
1314                int contextLen = contextEnd - contextStart;
1315                int len = end - start;
1316                char[] buf = TemporaryBuffer.obtain(contextLen);
1317                TextUtils.getChars(text, contextStart, contextEnd, buf, 0);
1318                nDrawTextRun(mRenderer, buf, start - contextStart, len, 0, contextLen,
1319                        x, y, flags, paint.mNativePaint);
1320                TemporaryBuffer.recycle(buf);
1321            }
1322        } finally {
1323            if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
1324        }
1325    }
1326
1327    private static native void nDrawTextRun(int renderer, String text, int start, int end,
1328            int contextStart, int contextEnd, float x, float y, int flags, int nativePaint);
1329
1330    @Override
1331    public void drawVertices(VertexMode mode, int vertexCount, float[] verts, int vertOffset,
1332            float[] texs, int texOffset, int[] colors, int colorOffset, short[] indices,
1333            int indexOffset, int indexCount, Paint paint) {
1334        // TODO: Implement
1335    }
1336
1337    private int setupModifiers(Bitmap b, Paint paint) {
1338        if (b.getConfig() != Bitmap.Config.ALPHA_8) {
1339            final ColorFilter filter = paint.getColorFilter();
1340            if (filter != null) {
1341                nSetupColorFilter(mRenderer, filter.nativeColorFilter);
1342                return MODIFIER_COLOR_FILTER;
1343            }
1344
1345            return MODIFIER_NONE;
1346        } else {
1347            return setupModifiers(paint);
1348        }
1349    }
1350
1351    private int setupModifiers(Paint paint) {
1352        int modifiers = MODIFIER_NONE;
1353
1354        if (paint.hasShadow) {
1355            nSetupShadow(mRenderer, paint.shadowRadius, paint.shadowDx, paint.shadowDy,
1356                    paint.shadowColor);
1357            modifiers |= MODIFIER_SHADOW;
1358        }
1359
1360        final Shader shader = paint.getShader();
1361        if (shader != null) {
1362            nSetupShader(mRenderer, shader.native_shader);
1363            modifiers |= MODIFIER_SHADER;
1364        }
1365
1366        final ColorFilter filter = paint.getColorFilter();
1367        if (filter != null) {
1368            nSetupColorFilter(mRenderer, filter.nativeColorFilter);
1369            modifiers |= MODIFIER_COLOR_FILTER;
1370        }
1371
1372        return modifiers;
1373    }
1374
1375    private int setupModifiers(Paint paint, int flags) {
1376        int modifiers = MODIFIER_NONE;
1377
1378        if (paint.hasShadow && (flags & MODIFIER_SHADOW) != 0) {
1379            nSetupShadow(mRenderer, paint.shadowRadius, paint.shadowDx, paint.shadowDy,
1380                    paint.shadowColor);
1381            modifiers |= MODIFIER_SHADOW;
1382        }
1383
1384        final Shader shader = paint.getShader();
1385        if (shader != null && (flags & MODIFIER_SHADER) != 0) {
1386            nSetupShader(mRenderer, shader.native_shader);
1387            modifiers |= MODIFIER_SHADER;
1388        }
1389
1390        final ColorFilter filter = paint.getColorFilter();
1391        if (filter != null && (flags & MODIFIER_COLOR_FILTER) != 0) {
1392            nSetupColorFilter(mRenderer, filter.nativeColorFilter);
1393            modifiers |= MODIFIER_COLOR_FILTER;
1394        }
1395
1396        return modifiers;
1397    }
1398
1399    private int setupColorFilter(Paint paint) {
1400        final ColorFilter filter = paint.getColorFilter();
1401        if (filter != null) {
1402            nSetupColorFilter(mRenderer, filter.nativeColorFilter);
1403            return MODIFIER_COLOR_FILTER;
1404        }
1405        return MODIFIER_NONE;
1406    }
1407
1408    private static native void nSetupShader(int renderer, int shader);
1409    private static native void nSetupColorFilter(int renderer, int colorFilter);
1410    private static native void nSetupShadow(int renderer, float radius,
1411            float dx, float dy, int color);
1412
1413    private static native void nResetModifiers(int renderer, int modifiers);
1414}
1415