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