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