GLES20Canvas.java revision 9c4b79af221b53f602f946faa9ff317a596a0c39
1/*
2 * Copyright (C) 2010 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package android.view;
18
19import android.graphics.Bitmap;
20import android.graphics.Canvas;
21import android.graphics.ColorFilter;
22import android.graphics.DrawFilter;
23import android.graphics.Matrix;
24import android.graphics.Paint;
25import android.graphics.Path;
26import android.graphics.Picture;
27import android.graphics.PorterDuff;
28import android.graphics.Rect;
29import android.graphics.RectF;
30import android.graphics.Region;
31import android.graphics.Shader;
32import android.graphics.SurfaceTexture;
33import android.graphics.TemporaryBuffer;
34import android.text.GraphicsOperations;
35import android.text.SpannableString;
36import android.text.SpannedString;
37import android.text.TextUtils;
38
39/**
40 * An implementation of Canvas on top of OpenGL ES 2.0.
41 */
42class GLES20Canvas extends HardwareCanvas {
43    // Must match modifiers used in the JNI layer
44    private static final int MODIFIER_NONE = 0;
45    private static final int MODIFIER_SHADOW = 1;
46    private static final int MODIFIER_SHADER = 2;
47    private static final int MODIFIER_COLOR_FILTER = 4;
48
49    private final boolean mOpaque;
50    private int mRenderer;
51
52    // The native renderer will be destroyed when this object dies.
53    // DO NOT overwrite this reference once it is set.
54    @SuppressWarnings({"unused", "FieldCanBeLocal"})
55    private CanvasFinalizer mFinalizer;
56
57    private int mWidth;
58    private int mHeight;
59
60    private final float[] mPoint = new float[2];
61    private final float[] mLine = new float[4];
62
63    private final Rect mClipBounds = new Rect();
64
65    private DrawFilter mFilter;
66
67    ///////////////////////////////////////////////////////////////////////////
68    // JNI
69    ///////////////////////////////////////////////////////////////////////////
70
71    private static native boolean nIsAvailable();
72    private static boolean sIsAvailable = nIsAvailable();
73
74    static boolean isAvailable() {
75        return sIsAvailable;
76    }
77
78    ///////////////////////////////////////////////////////////////////////////
79    // Constructors
80    ///////////////////////////////////////////////////////////////////////////
81
82    /**
83     * Creates a canvas to render directly on screen.
84     */
85    GLES20Canvas(boolean translucent) {
86        this(false, translucent);
87    }
88
89    /**
90     * Creates a canvas to render into an FBO.
91     */
92    GLES20Canvas(int layer, boolean translucent) {
93        mOpaque = !translucent;
94        mRenderer = nCreateLayerRenderer(layer);
95        setupFinalizer();
96    }
97
98    protected GLES20Canvas(boolean record, boolean translucent) {
99        mOpaque = !translucent;
100
101        if (record) {
102            mRenderer = nCreateDisplayListRenderer();
103        } else {
104            mRenderer = nCreateRenderer();
105        }
106
107        setupFinalizer();
108    }
109
110    private void setupFinalizer() {
111        if (mRenderer == 0) {
112            throw new IllegalStateException("Could not create GLES20Canvas renderer");
113        } else {
114            mFinalizer = new CanvasFinalizer(mRenderer);
115        }
116    }
117
118    protected void resetDisplayListRenderer() {
119        nResetDisplayListRenderer(mRenderer);
120    }
121
122    private static native int nCreateRenderer();
123    private static native int nCreateLayerRenderer(int layer);
124    private static native int nCreateDisplayListRenderer();
125    private static native void nResetDisplayListRenderer(int renderer);
126    private static native void nDestroyRenderer(int renderer);
127
128    private static final class CanvasFinalizer {
129        private final int mRenderer;
130
131        public CanvasFinalizer(int renderer) {
132            mRenderer = renderer;
133        }
134
135        @Override
136        protected void finalize() throws Throwable {
137            try {
138                nDestroyRenderer(mRenderer);
139            } finally {
140                super.finalize();
141            }
142        }
143    }
144
145    ///////////////////////////////////////////////////////////////////////////
146    // Hardware layers
147    ///////////////////////////////////////////////////////////////////////////
148
149    static native int nCreateTextureLayer(boolean opaque, int[] layerInfo);
150    static native int nCreateLayer(int width, int height, boolean isOpaque, int[] layerInfo);
151    static native void nResizeLayer(int layerId, int width, int height, int[] layerInfo);
152    static native void nUpdateTextureLayer(int layerId, int width, int height, boolean opaque,
153            SurfaceTexture surface);
154    static native void nSetTextureLayerTransform(int layerId, int matrix);
155    static native void nDestroyLayer(int layerId);
156    static native void nDestroyLayerDeferred(int layerId);
157    static native void nFlushLayer(int layerId);
158    static native boolean nCopyLayer(int layerId, int bitmap);
159
160    ///////////////////////////////////////////////////////////////////////////
161    // Canvas management
162    ///////////////////////////////////////////////////////////////////////////
163
164    @Override
165    public boolean isOpaque() {
166        return mOpaque;
167    }
168
169    @Override
170    public int getWidth() {
171        return mWidth;
172    }
173
174    @Override
175    public int getHeight() {
176        return mHeight;
177    }
178
179    @Override
180    public int getMaximumBitmapWidth() {
181        return nGetMaximumTextureWidth();
182    }
183
184    @Override
185    public int getMaximumBitmapHeight() {
186        return nGetMaximumTextureHeight();
187    }
188
189    private static native int nGetMaximumTextureWidth();
190    private static native int nGetMaximumTextureHeight();
191
192    ///////////////////////////////////////////////////////////////////////////
193    // Setup
194    ///////////////////////////////////////////////////////////////////////////
195
196    @Override
197    public void setViewport(int width, int height) {
198        mWidth = width;
199        mHeight = height;
200
201        nSetViewport(mRenderer, width, height);
202    }
203
204    private static native void nSetViewport(int renderer, int width, int height);
205
206    /**
207     * Preserves the back buffer of the current surface after a buffer swap.
208     * Calling this method sets the EGL_SWAP_BEHAVIOR attribute of the current
209     * surface to EGL_BUFFER_PRESERVED. Calling this method requires an EGL
210     * config that supports EGL_SWAP_BEHAVIOR_PRESERVED_BIT.
211     *
212     * @return True if the swap behavior was successfully changed,
213     *         false otherwise.
214     *
215     * @hide
216     */
217    public static boolean preserveBackBuffer() {
218        return nPreserveBackBuffer();
219    }
220
221    private static native boolean nPreserveBackBuffer();
222
223    /**
224     * Indicates whether the current surface preserves its back buffer
225     * after a buffer swap.
226     *
227     * @return True, if the surface's EGL_SWAP_BEHAVIOR is EGL_BUFFER_PRESERVED,
228     *         false otherwise
229     *
230     * @hide
231     */
232    public static boolean isBackBufferPreserved() {
233        return nIsBackBufferPreserved();
234    }
235
236    private static native boolean nIsBackBufferPreserved();
237
238    /**
239     * Disables v-sync. For performance testing only.
240     *
241     * @hide
242     */
243    public static void disableVsync() {
244        nDisableVsync();
245    }
246
247    private static native void nDisableVsync();
248
249    @Override
250    void onPreDraw(Rect dirty) {
251        if (dirty != null) {
252            nPrepareDirty(mRenderer, dirty.left, dirty.top, dirty.right, dirty.bottom, mOpaque);
253        } else {
254            nPrepare(mRenderer, mOpaque);
255        }
256    }
257
258    private static native void nPrepare(int renderer, boolean opaque);
259    private static native void nPrepareDirty(int renderer, int left, int top, int right, int bottom,
260            boolean opaque);
261
262    @Override
263    void onPostDraw() {
264        nFinish(mRenderer);
265    }
266
267    private static native void nFinish(int renderer);
268
269    @Override
270    public boolean callDrawGLFunction(int drawGLFunction) {
271        return nCallDrawGLFunction(mRenderer, drawGLFunction);
272    }
273
274    private static native boolean nCallDrawGLFunction(int renderer, int drawGLFunction);
275
276
277    ///////////////////////////////////////////////////////////////////////////
278    // Memory
279    ///////////////////////////////////////////////////////////////////////////
280
281    /**
282     * Must match Caches::FlushMode values
283     *
284     * @see #flushCaches(int)
285     */
286    public static final int FLUSH_CACHES_LAYERS = 0;
287
288    /**
289     * Must match Caches::FlushMode values
290     *
291     * @see #flushCaches(int)
292     */
293    public static final int FLUSH_CACHES_MODERATE = 1;
294
295    /**
296     * Must match Caches::FlushMode values
297     *
298     * @see #flushCaches(int)
299     */
300    public static final int FLUSH_CACHES_FULL = 2;
301
302    /**
303     * Flush caches to reclaim as much memory as possible. The amount of memory
304     * to reclaim is indicate by the level parameter.
305     *
306     * The level can be one of {@link #FLUSH_CACHES_MODERATE} or
307     * {@link #FLUSH_CACHES_FULL}.
308     *
309     * @param level Hint about the amount of memory to reclaim
310     *
311     * @hide
312     */
313    public static void flushCaches(int level) {
314        nFlushCaches(level);
315    }
316
317    private static native void nFlushCaches(int level);
318
319    /**
320     * Release all resources associated with the underlying caches. This should
321     * only be called after a full flushCaches().
322     *
323     * @hide
324     */
325    public static void terminateCaches() {
326        nTerminateCaches();
327    }
328
329    private static native void nTerminateCaches();
330
331    /**
332     * @hide
333     */
334    public static void initCaches() {
335        nInitCaches();
336    }
337
338    private static native void nInitCaches();
339
340    ///////////////////////////////////////////////////////////////////////////
341    // Display list
342    ///////////////////////////////////////////////////////////////////////////
343
344    int getDisplayList(int displayList) {
345        return nGetDisplayList(mRenderer, displayList);
346    }
347
348    private static native int nGetDisplayList(int renderer, int displayList);
349
350    static void destroyDisplayList(int displayList) {
351        nDestroyDisplayList(displayList);
352    }
353
354    private static native void nDestroyDisplayList(int displayList);
355
356    static int getDisplayListSize(int displayList) {
357        return nGetDisplayListSize(displayList);
358    }
359
360    private static native int nGetDisplayListSize(int displayList);
361
362    @Override
363    public boolean drawDisplayList(DisplayList displayList, int width, int height, Rect dirty) {
364        return nDrawDisplayList(mRenderer,
365                ((GLES20DisplayList) displayList).getNativeDisplayList(), width, height, dirty);
366    }
367
368    private static native boolean nDrawDisplayList(int renderer, int displayList,
369            int width, int height, Rect dirty);
370
371    @Override
372    void outputDisplayList(DisplayList displayList) {
373        nOutputDisplayList(mRenderer, ((GLES20DisplayList) displayList).getNativeDisplayList());
374    }
375
376    private static native void nOutputDisplayList(int renderer, int displayList);
377
378    ///////////////////////////////////////////////////////////////////////////
379    // Hardware layer
380    ///////////////////////////////////////////////////////////////////////////
381
382    void drawHardwareLayer(HardwareLayer layer, float x, float y, Paint paint) {
383        final GLES20Layer glLayer = (GLES20Layer) layer;
384        int modifier = paint != null ? setupColorFilter(paint) : MODIFIER_NONE;
385        final int nativePaint = paint == null ? 0 : paint.mNativePaint;
386        nDrawLayer(mRenderer, glLayer.getLayer(), x, y, nativePaint);
387        if (modifier != MODIFIER_NONE) nResetModifiers(mRenderer, modifier);
388    }
389
390    private static native void nDrawLayer(int renderer, int layer, float x, float y, int paint);
391
392    void interrupt() {
393        nInterrupt(mRenderer);
394    }
395
396    void resume() {
397        nResume(mRenderer);
398    }
399
400    private static native void nInterrupt(int renderer);
401    private static native void nResume(int renderer);
402
403    ///////////////////////////////////////////////////////////////////////////
404    // Clipping
405    ///////////////////////////////////////////////////////////////////////////
406
407    @Override
408    public boolean clipPath(Path path) {
409        throw new UnsupportedOperationException();
410    }
411
412    @Override
413    public boolean clipPath(Path path, Region.Op op) {
414        throw new UnsupportedOperationException();
415    }
416
417    @Override
418    public boolean clipRect(float left, float top, float right, float bottom) {
419        return nClipRect(mRenderer, left, top, right, bottom, Region.Op.INTERSECT.nativeInt);
420    }
421
422    private static native boolean nClipRect(int renderer, float left, float top,
423            float right, float bottom, int op);
424
425    @Override
426    public boolean clipRect(float left, float top, float right, float bottom, Region.Op op) {
427        return nClipRect(mRenderer, left, top, right, bottom, op.nativeInt);
428    }
429
430    @Override
431    public boolean clipRect(int left, int top, int right, int bottom) {
432        return nClipRect(mRenderer, left, top, right, bottom, Region.Op.INTERSECT.nativeInt);
433    }
434
435    private static native boolean nClipRect(int renderer, int left, int top, int right, int bottom,
436            int op);
437
438    @Override
439    public boolean clipRect(Rect rect) {
440        return nClipRect(mRenderer, rect.left, rect.top, rect.right, rect.bottom,
441                Region.Op.INTERSECT.nativeInt);
442    }
443
444    @Override
445    public boolean clipRect(Rect rect, Region.Op op) {
446        return nClipRect(mRenderer, rect.left, rect.top, rect.right, rect.bottom, op.nativeInt);
447    }
448
449    @Override
450    public boolean clipRect(RectF rect) {
451        return nClipRect(mRenderer, rect.left, rect.top, rect.right, rect.bottom,
452                Region.Op.INTERSECT.nativeInt);
453    }
454
455    @Override
456    public boolean clipRect(RectF rect, Region.Op op) {
457        return nClipRect(mRenderer, rect.left, rect.top, rect.right, rect.bottom, op.nativeInt);
458    }
459
460    @Override
461    public boolean clipRegion(Region region) {
462        throw new UnsupportedOperationException();
463    }
464
465    @Override
466    public boolean clipRegion(Region region, Region.Op op) {
467        throw new UnsupportedOperationException();
468    }
469
470    @Override
471    public boolean getClipBounds(Rect bounds) {
472        return nGetClipBounds(mRenderer, bounds);
473    }
474
475    private static native boolean nGetClipBounds(int renderer, Rect bounds);
476
477    @Override
478    public boolean quickReject(float left, float top, float right, float bottom, EdgeType type) {
479        return nQuickReject(mRenderer, left, top, right, bottom, type.nativeInt);
480    }
481
482    private static native boolean nQuickReject(int renderer, float left, float top,
483            float right, float bottom, int edge);
484
485    @Override
486    public boolean quickReject(Path path, EdgeType type) {
487        throw new UnsupportedOperationException();
488    }
489
490    @Override
491    public boolean quickReject(RectF rect, EdgeType type) {
492        return quickReject(rect.left, rect.top, rect.right, rect.bottom, type);
493    }
494
495    ///////////////////////////////////////////////////////////////////////////
496    // Transformations
497    ///////////////////////////////////////////////////////////////////////////
498
499    @Override
500    public void translate(float dx, float dy) {
501        if (dx != 0.0f || dy != 0.0f) nTranslate(mRenderer, dx, dy);
502    }
503
504    private static native void nTranslate(int renderer, float dx, float dy);
505
506    @Override
507    public void skew(float sx, float sy) {
508        nSkew(mRenderer, sx, sy);
509    }
510
511    private static native void nSkew(int renderer, float sx, float sy);
512
513    @Override
514    public void rotate(float degrees) {
515        nRotate(mRenderer, degrees);
516    }
517
518    private static native void nRotate(int renderer, float degrees);
519
520    @Override
521    public void scale(float sx, float sy) {
522        nScale(mRenderer, sx, sy);
523    }
524
525    private static native void nScale(int renderer, float sx, float sy);
526
527    @Override
528    public void setMatrix(Matrix matrix) {
529        nSetMatrix(mRenderer, matrix == null ? 0 : matrix.native_instance);
530    }
531
532    private static native void nSetMatrix(int renderer, int matrix);
533
534    @Override
535    public void getMatrix(Matrix matrix) {
536        nGetMatrix(mRenderer, matrix.native_instance);
537    }
538
539    private static native void nGetMatrix(int renderer, int matrix);
540
541    @Override
542    public void concat(Matrix matrix) {
543        nConcatMatrix(mRenderer, matrix.native_instance);
544    }
545
546    private static native void nConcatMatrix(int renderer, int matrix);
547
548    ///////////////////////////////////////////////////////////////////////////
549    // State management
550    ///////////////////////////////////////////////////////////////////////////
551
552    @Override
553    public int save() {
554        return nSave(mRenderer, Canvas.CLIP_SAVE_FLAG | Canvas.MATRIX_SAVE_FLAG);
555    }
556
557    @Override
558    public int save(int saveFlags) {
559        return nSave(mRenderer, saveFlags);
560    }
561
562    private static native int nSave(int renderer, int flags);
563
564    @Override
565    public int saveLayer(RectF bounds, Paint paint, int saveFlags) {
566        if (bounds != null) {
567            return saveLayer(bounds.left, bounds.top, bounds.right, bounds.bottom, paint, saveFlags);
568        }
569
570        int modifier = paint != null ? setupColorFilter(paint) : MODIFIER_NONE;
571        final int nativePaint = paint == null ? 0 : paint.mNativePaint;
572        int count = nSaveLayer(mRenderer, nativePaint, saveFlags);
573        if (modifier != MODIFIER_NONE) nResetModifiers(mRenderer, modifier);
574        return count;
575    }
576
577    private static native int nSaveLayer(int renderer, int paint, int saveFlags);
578
579    @Override
580    public int saveLayer(float left, float top, float right, float bottom, Paint paint,
581            int saveFlags) {
582        if (left < right && top < bottom) {
583            int modifier = paint != null ? setupColorFilter(paint) : MODIFIER_NONE;
584            final int nativePaint = paint == null ? 0 : paint.mNativePaint;
585            int count = nSaveLayer(mRenderer, left, top, right, bottom, nativePaint, saveFlags);
586            if (modifier != MODIFIER_NONE) nResetModifiers(mRenderer, modifier);
587            return count;
588        }
589        return save(saveFlags);
590    }
591
592    private static native int nSaveLayer(int renderer, float left, float top,
593            float right, float bottom, int paint, int saveFlags);
594
595    @Override
596    public int saveLayerAlpha(RectF bounds, int alpha, int saveFlags) {
597        if (bounds != null) {
598            return saveLayerAlpha(bounds.left, bounds.top, bounds.right, bounds.bottom,
599                    alpha, saveFlags);
600        }
601        return nSaveLayerAlpha(mRenderer, alpha, saveFlags);
602    }
603
604    private static native int nSaveLayerAlpha(int renderer, int alpha, int saveFlags);
605
606    @Override
607    public int saveLayerAlpha(float left, float top, float right, float bottom, int alpha,
608            int saveFlags) {
609        if (left < right && top < bottom) {
610            return nSaveLayerAlpha(mRenderer, left, top, right, bottom, alpha, saveFlags);
611        }
612        return save(saveFlags);
613    }
614
615    private static native int nSaveLayerAlpha(int renderer, float left, float top, float right,
616            float bottom, int alpha, int saveFlags);
617
618    @Override
619    public void restore() {
620        nRestore(mRenderer);
621    }
622
623    private static native void nRestore(int renderer);
624
625    @Override
626    public void restoreToCount(int saveCount) {
627        nRestoreToCount(mRenderer, saveCount);
628    }
629
630    private static native void nRestoreToCount(int renderer, int saveCount);
631
632    @Override
633    public int getSaveCount() {
634        return nGetSaveCount(mRenderer);
635    }
636
637    private static native int nGetSaveCount(int renderer);
638
639    ///////////////////////////////////////////////////////////////////////////
640    // Filtering
641    ///////////////////////////////////////////////////////////////////////////
642
643    @Override
644    public void setDrawFilter(DrawFilter filter) {
645        mFilter = filter;
646    }
647
648    @Override
649    public DrawFilter getDrawFilter() {
650        return mFilter;
651    }
652
653    ///////////////////////////////////////////////////////////////////////////
654    // Drawing
655    ///////////////////////////////////////////////////////////////////////////
656
657    @Override
658    public void drawArc(RectF oval, float startAngle, float sweepAngle, boolean useCenter,
659            Paint paint) {
660        int modifiers = setupModifiers(paint);
661        nDrawArc(mRenderer, oval.left, oval.top, oval.right, oval.bottom, startAngle, sweepAngle,
662                useCenter, paint.mNativePaint);
663        if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
664    }
665
666    private static native void nDrawArc(int renderer, float left, float top,
667            float right, float bottom, float startAngle, float sweepAngle,
668            boolean useCenter, int paint);
669
670    @Override
671    public void drawARGB(int a, int r, int g, int b) {
672        drawColor((a & 0xFF) << 24 | (r & 0xFF) << 16 | (g & 0xFF) << 8 | (b & 0xFF));
673    }
674
675    @Override
676    public void drawPatch(Bitmap bitmap, byte[] chunks, RectF dst, Paint paint) {
677        // Shaders are ignored when drawing patches
678        int modifier = paint != null ? setupColorFilter(paint) : MODIFIER_NONE;
679        final int nativePaint = paint == null ? 0 : paint.mNativePaint;
680        nDrawPatch(mRenderer, bitmap.mNativeBitmap, bitmap.mBuffer, chunks,
681                dst.left, dst.top, dst.right, dst.bottom, nativePaint);
682        if (modifier != MODIFIER_NONE) nResetModifiers(mRenderer, modifier);
683    }
684
685    private static native void nDrawPatch(int renderer, int bitmap, byte[] buffer, byte[] chunks,
686            float left, float top, float right, float bottom, int paint);
687
688    @Override
689    public void drawBitmap(Bitmap bitmap, float left, float top, Paint paint) {
690        // Shaders are ignored when drawing bitmaps
691        int modifiers = paint != null ? setupModifiers(bitmap, paint) : MODIFIER_NONE;
692        final int nativePaint = paint == null ? 0 : paint.mNativePaint;
693        nDrawBitmap(mRenderer, bitmap.mNativeBitmap, bitmap.mBuffer, left, top, nativePaint);
694        if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
695    }
696
697    private static native void nDrawBitmap(
698            int renderer, int bitmap, byte[] buffer, float left, float top, int paint);
699
700    @Override
701    public void drawBitmap(Bitmap bitmap, Matrix matrix, Paint paint) {
702        // Shaders are ignored when drawing bitmaps
703        int modifiers = paint != null ? setupModifiers(bitmap, paint) : MODIFIER_NONE;
704        final int nativePaint = paint == null ? 0 : paint.mNativePaint;
705        nDrawBitmap(mRenderer, bitmap.mNativeBitmap, bitmap.mBuffer,
706                matrix.native_instance, nativePaint);
707        if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
708    }
709
710    private static native void nDrawBitmap(int renderer, int bitmap, byte[] buff,
711            int matrix, int paint);
712
713    @Override
714    public void drawBitmap(Bitmap bitmap, Rect src, Rect dst, Paint paint) {
715        // Shaders are ignored when drawing bitmaps
716        int modifiers = paint != null ? setupModifiers(bitmap, paint) : MODIFIER_NONE;
717        final int nativePaint = paint == null ? 0 : paint.mNativePaint;
718
719        int left, top, right, bottom;
720        if (src == null) {
721            left = top = 0;
722            right = bitmap.getWidth();
723            bottom = bitmap.getHeight();
724        } else {
725            left = src.left;
726            right = src.right;
727            top = src.top;
728            bottom = src.bottom;
729        }
730
731        nDrawBitmap(mRenderer, bitmap.mNativeBitmap, bitmap.mBuffer, left, top, right, bottom,
732                dst.left, dst.top, dst.right, dst.bottom, nativePaint);
733        if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
734    }
735
736    @Override
737    public void drawBitmap(Bitmap bitmap, Rect src, RectF dst, Paint paint) {
738        // Shaders are ignored when drawing bitmaps
739        int modifiers = paint != null ? setupModifiers(bitmap, paint) : MODIFIER_NONE;
740        final int nativePaint = paint == null ? 0 : paint.mNativePaint;
741
742        float left, top, right, bottom;
743        if (src == null) {
744            left = top = 0;
745            right = bitmap.getWidth();
746            bottom = bitmap.getHeight();
747        } else {
748            left = src.left;
749            right = src.right;
750            top = src.top;
751            bottom = src.bottom;
752        }
753
754        nDrawBitmap(mRenderer, bitmap.mNativeBitmap, bitmap.mBuffer, left, top, right, bottom,
755                dst.left, dst.top, dst.right, dst.bottom, nativePaint);
756        if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
757    }
758
759    private static native void nDrawBitmap(int renderer, int bitmap, byte[] buffer,
760            float srcLeft, float srcTop, float srcRight, float srcBottom,
761            float left, float top, float right, float bottom, int paint);
762
763    @Override
764    public void drawBitmap(int[] colors, int offset, int stride, float x, float y,
765            int width, int height, boolean hasAlpha, Paint paint) {
766        // Shaders are ignored when drawing bitmaps
767        int modifier = paint != null ? setupColorFilter(paint) : MODIFIER_NONE;
768        final Bitmap.Config config = hasAlpha ? Bitmap.Config.ARGB_8888 : Bitmap.Config.RGB_565;
769        final Bitmap b = Bitmap.createBitmap(colors, offset, stride, width, height, config);
770        final int nativePaint = paint == null ? 0 : paint.mNativePaint;
771        nDrawBitmap(mRenderer, b.mNativeBitmap, b.mBuffer, x, y, nativePaint);
772        b.recycle();
773        if (modifier != MODIFIER_NONE) nResetModifiers(mRenderer, modifier);
774    }
775
776    @Override
777    public void drawBitmap(int[] colors, int offset, int stride, int x, int y,
778            int width, int height, boolean hasAlpha, Paint paint) {
779        // Shaders are ignored when drawing bitmaps
780        drawBitmap(colors, offset, stride, (float) x, (float) y, width, height, hasAlpha, paint);
781    }
782
783    @Override
784    public void drawBitmapMesh(Bitmap bitmap, int meshWidth, int meshHeight, float[] verts,
785            int vertOffset, int[] colors, int colorOffset, Paint paint) {
786        if (meshWidth < 0 || meshHeight < 0 || vertOffset < 0 || colorOffset < 0) {
787            throw new ArrayIndexOutOfBoundsException();
788        }
789
790        if (meshWidth == 0 || meshHeight == 0) {
791            return;
792        }
793
794        final int count = (meshWidth + 1) * (meshHeight + 1);
795        checkRange(verts.length, vertOffset, count * 2);
796
797        // TODO: Colors are ignored for now
798        colors = null;
799        colorOffset = 0;
800
801        int modifiers = paint != null ? setupModifiers(bitmap, paint) : MODIFIER_NONE;
802        final int nativePaint = paint == null ? 0 : paint.mNativePaint;
803        nDrawBitmapMesh(mRenderer, bitmap.mNativeBitmap, bitmap.mBuffer, meshWidth, meshHeight,
804                verts, vertOffset, colors, colorOffset, nativePaint);
805        if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
806    }
807
808    private static native void nDrawBitmapMesh(int renderer, int bitmap, byte[] buffer,
809            int meshWidth, int meshHeight, float[] verts, int vertOffset,
810            int[] colors, int colorOffset, int paint);
811
812    @Override
813    public void drawCircle(float cx, float cy, float radius, Paint paint) {
814        int modifiers = setupModifiers(paint);
815        nDrawCircle(mRenderer, cx, cy, radius, paint.mNativePaint);
816        if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
817    }
818
819    private static native void nDrawCircle(int renderer, float cx, float cy,
820            float radius, int paint);
821
822    @Override
823    public void drawColor(int color) {
824        drawColor(color, PorterDuff.Mode.SRC_OVER);
825    }
826
827    @Override
828    public void drawColor(int color, PorterDuff.Mode mode) {
829        nDrawColor(mRenderer, color, mode.nativeInt);
830    }
831
832    private static native void nDrawColor(int renderer, int color, int mode);
833
834    @Override
835    public void drawLine(float startX, float startY, float stopX, float stopY, Paint paint) {
836        mLine[0] = startX;
837        mLine[1] = startY;
838        mLine[2] = stopX;
839        mLine[3] = stopY;
840        drawLines(mLine, 0, 4, paint);
841    }
842
843    @Override
844    public void drawLines(float[] pts, int offset, int count, Paint paint) {
845        if ((offset | count) < 0 || offset + count > pts.length) {
846            throw new IllegalArgumentException("The lines array must contain 4 elements per line.");
847        }
848        int modifiers = setupModifiers(paint);
849        nDrawLines(mRenderer, pts, offset, count, paint.mNativePaint);
850        if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
851    }
852
853    private static native void nDrawLines(int renderer, float[] points,
854            int offset, int count, int paint);
855
856    @Override
857    public void drawLines(float[] pts, Paint paint) {
858        drawLines(pts, 0, pts.length, paint);
859    }
860
861    @Override
862    public void drawOval(RectF oval, Paint paint) {
863        int modifiers = setupModifiers(paint);
864        nDrawOval(mRenderer, oval.left, oval.top, oval.right, oval.bottom, paint.mNativePaint);
865        if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
866    }
867
868    private static native void nDrawOval(int renderer, float left, float top,
869            float right, float bottom, int paint);
870
871    @Override
872    public void drawPaint(Paint paint) {
873        final Rect r = mClipBounds;
874        nGetClipBounds(mRenderer, r);
875        drawRect(r.left, r.top, r.right, r.bottom, paint);
876    }
877
878    @Override
879    public void drawPath(Path path, Paint paint) {
880        int modifiers = setupModifiers(paint);
881        if (path.isSimplePath) {
882            if (path.rects != null) {
883                nDrawRects(mRenderer, path.rects.mNativeRegion, paint.mNativePaint);
884            }
885        } else {
886            nDrawPath(mRenderer, path.mNativePath, paint.mNativePaint);
887        }
888        if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
889    }
890
891    private static native void nDrawPath(int renderer, int path, int paint);
892    private static native void nDrawRects(int renderer, int region, int paint);
893
894    @Override
895    public void drawPicture(Picture picture) {
896        throw new UnsupportedOperationException();
897    }
898
899    @Override
900    public void drawPicture(Picture picture, Rect dst) {
901        throw new UnsupportedOperationException();
902    }
903
904    @Override
905    public void drawPicture(Picture picture, RectF dst) {
906        throw new UnsupportedOperationException();
907    }
908
909    @Override
910    public void drawPoint(float x, float y, Paint paint) {
911        mPoint[0] = x;
912        mPoint[1] = y;
913        drawPoints(mPoint, 0, 2, paint);
914    }
915
916    @Override
917    public void drawPoints(float[] pts, Paint paint) {
918        drawPoints(pts, 0, pts.length, paint);
919    }
920
921    @Override
922    public void drawPoints(float[] pts, int offset, int count, Paint paint) {
923        int modifiers = setupModifiers(paint);
924        nDrawPoints(mRenderer, pts, offset, count, paint.mNativePaint);
925        if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
926    }
927
928    private static native void nDrawPoints(int renderer, float[] points,
929            int offset, int count, int paint);
930
931    @Override
932    public void drawPosText(char[] text, int index, int count, float[] pos, Paint paint) {
933        // TODO: Implement
934    }
935
936    @Override
937    public void drawPosText(String text, float[] pos, Paint paint) {
938        // TODO: Implement
939    }
940
941    @Override
942    public void drawRect(float left, float top, float right, float bottom, Paint paint) {
943        int modifiers = setupModifiers(paint);
944        nDrawRect(mRenderer, left, top, right, bottom, paint.mNativePaint);
945        if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
946    }
947
948    private static native void nDrawRect(int renderer, float left, float top,
949            float right, float bottom, int paint);
950
951    @Override
952    public void drawRect(Rect r, Paint paint) {
953        drawRect(r.left, r.top, r.right, r.bottom, paint);
954    }
955
956    @Override
957    public void drawRect(RectF r, Paint paint) {
958        drawRect(r.left, r.top, r.right, r.bottom, paint);
959    }
960
961    @Override
962    public void drawRGB(int r, int g, int b) {
963        drawColor(0xFF000000 | (r & 0xFF) << 16 | (g & 0xFF) << 8 | (b & 0xFF));
964    }
965
966    @Override
967    public void drawRoundRect(RectF rect, float rx, float ry, Paint paint) {
968        int modifiers = setupModifiers(paint);
969        nDrawRoundRect(mRenderer, rect.left, rect.top, rect.right, rect.bottom,
970                rx, ry, paint.mNativePaint);
971        if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
972    }
973
974    private static native void nDrawRoundRect(int renderer, float left, float top,
975            float right, float bottom, float rx, float y, int paint);
976
977    @Override
978    public void drawText(char[] text, int index, int count, float x, float y, Paint paint) {
979        if ((index | count | (index + count) | (text.length - index - count)) < 0) {
980            throw new IndexOutOfBoundsException();
981        }
982
983        int modifiers = setupModifiers(paint);
984        try {
985            nDrawText(mRenderer, text, index, count, x, y, paint.mBidiFlags, paint.mNativePaint);
986        } finally {
987            if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
988        }
989    }
990
991    private static native void nDrawText(int renderer, char[] text, int index, int count,
992            float x, float y, int bidiFlags, int paint);
993
994    @Override
995    public void drawText(CharSequence text, int start, int end, float x, float y, Paint paint) {
996        int modifiers = setupModifiers(paint);
997        try {
998            if (text instanceof String || text instanceof SpannedString ||
999                    text instanceof SpannableString) {
1000                nDrawText(mRenderer, text.toString(), start, end, x, y, paint.mBidiFlags,
1001                        paint.mNativePaint);
1002            } else if (text instanceof GraphicsOperations) {
1003                ((GraphicsOperations) text).drawText(this, start, end, x, y,
1004                                                         paint);
1005            } else {
1006                char[] buf = TemporaryBuffer.obtain(end - start);
1007                TextUtils.getChars(text, start, end, buf, 0);
1008                nDrawText(mRenderer, buf, 0, end - start, x, y,
1009                        paint.mBidiFlags, paint.mNativePaint);
1010                TemporaryBuffer.recycle(buf);
1011            }
1012        } finally {
1013            if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
1014        }
1015    }
1016
1017    @Override
1018    public void drawText(String text, int start, int end, float x, float y, Paint paint) {
1019        if ((start | end | (end - start) | (text.length() - end)) < 0) {
1020            throw new IndexOutOfBoundsException();
1021        }
1022
1023        int modifiers = setupModifiers(paint);
1024        try {
1025            nDrawText(mRenderer, text, start, end, x, y, paint.mBidiFlags, paint.mNativePaint);
1026        } finally {
1027            if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
1028        }
1029    }
1030
1031    private static native void nDrawText(int renderer, String text, int start, int end,
1032            float x, float y, int bidiFlags, int paint);
1033
1034    @Override
1035    public void drawText(String text, float x, float y, Paint paint) {
1036        int modifiers = setupModifiers(paint);
1037        try {
1038            nDrawText(mRenderer, text, 0, text.length(), x, y, paint.mBidiFlags,
1039                    paint.mNativePaint);
1040        } finally {
1041            if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
1042        }
1043    }
1044
1045    @Override
1046    public void drawTextOnPath(char[] text, int index, int count, Path path, float hOffset,
1047            float vOffset, Paint paint) {
1048        // TODO: Implement
1049    }
1050
1051    @Override
1052    public void drawTextOnPath(String text, Path path, float hOffset, float vOffset, Paint paint) {
1053        // TODO: Implement
1054    }
1055
1056    @Override
1057    public void drawTextRun(char[] text, int index, int count, int contextIndex, int contextCount,
1058            float x, float y, int dir, Paint paint) {
1059        if ((index | count | text.length - index - count) < 0) {
1060            throw new IndexOutOfBoundsException();
1061        }
1062        if (dir != DIRECTION_LTR && dir != DIRECTION_RTL) {
1063            throw new IllegalArgumentException("Unknown direction: " + dir);
1064        }
1065
1066        int modifiers = setupModifiers(paint);
1067        try {
1068            nDrawTextRun(mRenderer, text, index, count, contextIndex, contextCount, x, y, dir,
1069                    paint.mNativePaint);
1070        } finally {
1071            if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
1072        }
1073    }
1074
1075    private static native void nDrawTextRun(int renderer, char[] text, int index, int count,
1076            int contextIndex, int contextCount, float x, float y, int dir, int nativePaint);
1077
1078    @Override
1079    public void drawTextRun(CharSequence text, int start, int end, int contextStart, int contextEnd,
1080            float x, float y, int dir, Paint paint) {
1081        if ((start | end | end - start | text.length() - end) < 0) {
1082            throw new IndexOutOfBoundsException();
1083        }
1084
1085        int modifiers = setupModifiers(paint);
1086        try {
1087            int flags = dir == 0 ? 0 : 1;
1088            if (text instanceof String || text instanceof SpannedString ||
1089                    text instanceof SpannableString) {
1090                nDrawTextRun(mRenderer, text.toString(), start, end, contextStart,
1091                        contextEnd, x, y, flags, paint.mNativePaint);
1092            } else if (text instanceof GraphicsOperations) {
1093                ((GraphicsOperations) text).drawTextRun(this, start, end,
1094                        contextStart, contextEnd, x, y, flags, paint);
1095            } else {
1096                int contextLen = contextEnd - contextStart;
1097                int len = end - start;
1098                char[] buf = TemporaryBuffer.obtain(contextLen);
1099                TextUtils.getChars(text, contextStart, contextEnd, buf, 0);
1100                nDrawTextRun(mRenderer, buf, start - contextStart, len, 0, contextLen,
1101                        x, y, flags, paint.mNativePaint);
1102                TemporaryBuffer.recycle(buf);
1103            }
1104        } finally {
1105            if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
1106        }
1107    }
1108
1109    private static native void nDrawTextRun(int renderer, String text, int start, int end,
1110            int contextStart, int contextEnd, float x, float y, int flags, int nativePaint);
1111
1112    @Override
1113    public void drawVertices(VertexMode mode, int vertexCount, float[] verts, int vertOffset,
1114            float[] texs, int texOffset, int[] colors, int colorOffset, short[] indices,
1115            int indexOffset, int indexCount, Paint paint) {
1116        // TODO: Implement
1117    }
1118
1119    private int setupModifiers(Bitmap b, Paint paint) {
1120        if (b.getConfig() == Bitmap.Config.ALPHA_8) {
1121            return setupModifiers(paint);
1122        }
1123
1124        final ColorFilter filter = paint.getColorFilter();
1125        if (filter != null) {
1126            nSetupColorFilter(mRenderer, filter.nativeColorFilter);
1127            return MODIFIER_COLOR_FILTER;
1128        }
1129
1130        return MODIFIER_NONE;
1131    }
1132
1133    private int setupModifiers(Paint paint) {
1134        int modifiers = MODIFIER_NONE;
1135
1136        if (paint.hasShadow) {
1137            nSetupShadow(mRenderer, paint.shadowRadius, paint.shadowDx, paint.shadowDy,
1138                    paint.shadowColor);
1139            modifiers |= MODIFIER_SHADOW;
1140        }
1141
1142        final Shader shader = paint.getShader();
1143        if (shader != null) {
1144            nSetupShader(mRenderer, shader.native_shader);
1145            modifiers |= MODIFIER_SHADER;
1146        }
1147
1148        final ColorFilter filter = paint.getColorFilter();
1149        if (filter != null) {
1150            nSetupColorFilter(mRenderer, filter.nativeColorFilter);
1151            modifiers |= MODIFIER_COLOR_FILTER;
1152        }
1153
1154        return modifiers;
1155    }
1156
1157    private int setupColorFilter(Paint paint) {
1158        final ColorFilter filter = paint.getColorFilter();
1159        if (filter != null) {
1160            nSetupColorFilter(mRenderer, filter.nativeColorFilter);
1161            return MODIFIER_COLOR_FILTER;
1162        }
1163        return MODIFIER_NONE;
1164    }
1165
1166    private static native void nSetupShader(int renderer, int shader);
1167    private static native void nSetupColorFilter(int renderer, int colorFilter);
1168    private static native void nSetupShadow(int renderer, float radius,
1169            float dx, float dy, int color);
1170
1171    private static native void nResetModifiers(int renderer, int modifiers);
1172}
1173