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