GLES20Canvas.java revision da96f8ac2c1c35a54f3f36e6d776cb386a251d03
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.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        nDrawBitmap(mRenderer, bitmap.mNativeBitmap, bitmap.mBuffer, src.left, src.top, src.right,
742                src.bottom, dst.left, dst.top, dst.right, dst.bottom, nativePaint);
743        if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
744    }
745
746    private static native void nDrawBitmap(int renderer, int bitmap, byte[] buffer,
747            float srcLeft, float srcTop, float srcRight, float srcBottom,
748            float left, float top, float right, float bottom, int paint);
749
750    @Override
751    public void drawBitmap(int[] colors, int offset, int stride, float x, float y,
752            int width, int height, boolean hasAlpha, Paint paint) {
753        // Shaders are ignored when drawing bitmaps
754        int modifier = paint != null ? setupColorFilter(paint) : MODIFIER_NONE;
755        final Bitmap.Config config = hasAlpha ? Bitmap.Config.ARGB_8888 : Bitmap.Config.RGB_565;
756        final Bitmap b = Bitmap.createBitmap(colors, offset, stride, width, height, config);
757        final int nativePaint = paint == null ? 0 : paint.mNativePaint;
758        nDrawBitmap(mRenderer, b.mNativeBitmap, b.mBuffer, x, y, nativePaint);
759        b.recycle();
760        if (modifier != MODIFIER_NONE) nResetModifiers(mRenderer, modifier);
761    }
762
763    @Override
764    public void drawBitmap(int[] colors, int offset, int stride, int x, int y,
765            int width, int height, boolean hasAlpha, Paint paint) {
766        // Shaders are ignored when drawing bitmaps
767        drawBitmap(colors, offset, stride, (float) x, (float) y, width, height, hasAlpha, paint);
768    }
769
770    @Override
771    public void drawBitmapMesh(Bitmap bitmap, int meshWidth, int meshHeight, float[] verts,
772            int vertOffset, int[] colors, int colorOffset, Paint paint) {
773        if (meshWidth < 0 || meshHeight < 0 || vertOffset < 0 || colorOffset < 0) {
774            throw new ArrayIndexOutOfBoundsException();
775        }
776
777        if (meshWidth == 0 || meshHeight == 0) {
778            return;
779        }
780
781        final int count = (meshWidth + 1) * (meshHeight + 1);
782        checkRange(verts.length, vertOffset, count * 2);
783
784        // TODO: Colors are ignored for now
785        colors = null;
786        colorOffset = 0;
787
788        int modifiers = paint != null ? setupModifiers(bitmap, paint) : MODIFIER_NONE;
789        final int nativePaint = paint == null ? 0 : paint.mNativePaint;
790        nDrawBitmapMesh(mRenderer, bitmap.mNativeBitmap, bitmap.mBuffer, meshWidth, meshHeight,
791                verts, vertOffset, colors, colorOffset, nativePaint);
792        if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
793    }
794
795    private static native void nDrawBitmapMesh(int renderer, int bitmap, byte[] buffer,
796            int meshWidth, int meshHeight, float[] verts, int vertOffset,
797            int[] colors, int colorOffset, int paint);
798
799    @Override
800    public void drawCircle(float cx, float cy, float radius, Paint paint) {
801        int modifiers = setupModifiers(paint);
802        nDrawCircle(mRenderer, cx, cy, radius, paint.mNativePaint);
803        if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
804    }
805
806    private static native void nDrawCircle(int renderer, float cx, float cy,
807            float radius, int paint);
808
809    @Override
810    public void drawColor(int color) {
811        drawColor(color, PorterDuff.Mode.SRC_OVER);
812    }
813
814    @Override
815    public void drawColor(int color, PorterDuff.Mode mode) {
816        nDrawColor(mRenderer, color, mode.nativeInt);
817    }
818
819    private static native void nDrawColor(int renderer, int color, int mode);
820
821    @Override
822    public void drawLine(float startX, float startY, float stopX, float stopY, Paint paint) {
823        mLine[0] = startX;
824        mLine[1] = startY;
825        mLine[2] = stopX;
826        mLine[3] = stopY;
827        drawLines(mLine, 0, 4, paint);
828    }
829
830    @Override
831    public void drawLines(float[] pts, int offset, int count, Paint paint) {
832        if ((offset | count) < 0 || offset + count > pts.length) {
833            throw new IllegalArgumentException("The lines array must contain 4 elements per line.");
834        }
835        int modifiers = setupModifiers(paint);
836        nDrawLines(mRenderer, pts, offset, count, paint.mNativePaint);
837        if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
838    }
839
840    private static native void nDrawLines(int renderer, float[] points,
841            int offset, int count, int paint);
842
843    @Override
844    public void drawLines(float[] pts, Paint paint) {
845        drawLines(pts, 0, pts.length, paint);
846    }
847
848    @Override
849    public void drawOval(RectF oval, Paint paint) {
850        int modifiers = setupModifiers(paint);
851        nDrawOval(mRenderer, oval.left, oval.top, oval.right, oval.bottom, paint.mNativePaint);
852        if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
853    }
854
855    private static native void nDrawOval(int renderer, float left, float top,
856            float right, float bottom, int paint);
857
858    @Override
859    public void drawPaint(Paint paint) {
860        final Rect r = mClipBounds;
861        nGetClipBounds(mRenderer, r);
862        drawRect(r.left, r.top, r.right, r.bottom, paint);
863    }
864
865    @Override
866    public void drawPath(Path path, Paint paint) {
867        int modifiers = setupModifiers(paint);
868        if (path.isSimplePath) {
869            if (path.rects != null) {
870                nDrawRects(mRenderer, path.rects.mNativeRegion, paint.mNativePaint);
871            }
872        } else {
873            nDrawPath(mRenderer, path.mNativePath, paint.mNativePaint);
874        }
875        if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
876    }
877
878    private static native void nDrawPath(int renderer, int path, int paint);
879    private static native void nDrawRects(int renderer, int region, int paint);
880
881    @Override
882    public void drawPicture(Picture picture) {
883        throw new UnsupportedOperationException();
884    }
885
886    @Override
887    public void drawPicture(Picture picture, Rect dst) {
888        throw new UnsupportedOperationException();
889    }
890
891    @Override
892    public void drawPicture(Picture picture, RectF dst) {
893        throw new UnsupportedOperationException();
894    }
895
896    @Override
897    public void drawPoint(float x, float y, Paint paint) {
898        mPoint[0] = x;
899        mPoint[1] = y;
900        drawPoints(mPoint, 0, 2, paint);
901    }
902
903    @Override
904    public void drawPoints(float[] pts, Paint paint) {
905        drawPoints(pts, 0, pts.length, paint);
906    }
907
908    @Override
909    public void drawPoints(float[] pts, int offset, int count, Paint paint) {
910        int modifiers = setupModifiers(paint);
911        nDrawPoints(mRenderer, pts, offset, count, paint.mNativePaint);
912        if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
913    }
914
915    private static native void nDrawPoints(int renderer, float[] points,
916            int offset, int count, int paint);
917
918    @Override
919    public void drawPosText(char[] text, int index, int count, float[] pos, Paint paint) {
920        // TODO: Implement
921    }
922
923    @Override
924    public void drawPosText(String text, float[] pos, Paint paint) {
925        // TODO: Implement
926    }
927
928    @Override
929    public void drawRect(float left, float top, float right, float bottom, Paint paint) {
930        int modifiers = setupModifiers(paint);
931        nDrawRect(mRenderer, left, top, right, bottom, paint.mNativePaint);
932        if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
933    }
934
935    private static native void nDrawRect(int renderer, float left, float top,
936            float right, float bottom, int paint);
937
938    @Override
939    public void drawRect(Rect r, Paint paint) {
940        drawRect(r.left, r.top, r.right, r.bottom, paint);
941    }
942
943    @Override
944    public void drawRect(RectF r, Paint paint) {
945        drawRect(r.left, r.top, r.right, r.bottom, paint);
946    }
947
948    @Override
949    public void drawRGB(int r, int g, int b) {
950        drawColor(0xFF000000 | (r & 0xFF) << 16 | (g & 0xFF) << 8 | (b & 0xFF));
951    }
952
953    @Override
954    public void drawRoundRect(RectF rect, float rx, float ry, Paint paint) {
955        int modifiers = setupModifiers(paint);
956        nDrawRoundRect(mRenderer, rect.left, rect.top, rect.right, rect.bottom,
957                rx, ry, paint.mNativePaint);
958        if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
959    }
960
961    private static native void nDrawRoundRect(int renderer, float left, float top,
962            float right, float bottom, float rx, float y, int paint);
963
964    @Override
965    public void drawText(char[] text, int index, int count, float x, float y, Paint paint) {
966        if ((index | count | (index + count) | (text.length - index - count)) < 0) {
967            throw new IndexOutOfBoundsException();
968        }
969
970        int modifiers = setupModifiers(paint);
971        try {
972            nDrawText(mRenderer, text, index, count, x, y, paint.mBidiFlags, paint.mNativePaint);
973        } finally {
974            if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
975        }
976    }
977
978    private static native void nDrawText(int renderer, char[] text, int index, int count,
979            float x, float y, int bidiFlags, int paint);
980
981    @Override
982    public void drawText(CharSequence text, int start, int end, float x, float y, Paint paint) {
983        int modifiers = setupModifiers(paint);
984        try {
985            if (text instanceof String || text instanceof SpannedString ||
986                    text instanceof SpannableString) {
987                nDrawText(mRenderer, text.toString(), start, end, x, y, paint.mBidiFlags,
988                        paint.mNativePaint);
989            } else if (text instanceof GraphicsOperations) {
990                ((GraphicsOperations) text).drawText(this, start, end, x, y,
991                                                         paint);
992            } else {
993                char[] buf = TemporaryBuffer.obtain(end - start);
994                TextUtils.getChars(text, start, end, buf, 0);
995                nDrawText(mRenderer, buf, 0, end - start, x, y,
996                        paint.mBidiFlags, paint.mNativePaint);
997                TemporaryBuffer.recycle(buf);
998            }
999        } finally {
1000            if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
1001        }
1002    }
1003
1004    @Override
1005    public void drawText(String text, int start, int end, float x, float y, Paint paint) {
1006        if ((start | end | (end - start) | (text.length() - end)) < 0) {
1007            throw new IndexOutOfBoundsException();
1008        }
1009
1010        int modifiers = setupModifiers(paint);
1011        try {
1012            nDrawText(mRenderer, text, start, end, x, y, paint.mBidiFlags, paint.mNativePaint);
1013        } finally {
1014            if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
1015        }
1016    }
1017
1018    private static native void nDrawText(int renderer, String text, int start, int end,
1019            float x, float y, int bidiFlags, int paint);
1020
1021    @Override
1022    public void drawText(String text, float x, float y, Paint paint) {
1023        int modifiers = setupModifiers(paint);
1024        try {
1025            nDrawText(mRenderer, text, 0, text.length(), x, y, paint.mBidiFlags,
1026                    paint.mNativePaint);
1027        } finally {
1028            if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
1029        }
1030    }
1031
1032    @Override
1033    public void drawTextOnPath(char[] text, int index, int count, Path path, float hOffset,
1034            float vOffset, Paint paint) {
1035        // TODO: Implement
1036    }
1037
1038    @Override
1039    public void drawTextOnPath(String text, Path path, float hOffset, float vOffset, Paint paint) {
1040        // TODO: Implement
1041    }
1042
1043    @Override
1044    public void drawTextRun(char[] text, int index, int count, int contextIndex, int contextCount,
1045            float x, float y, int dir, Paint paint) {
1046        if ((index | count | text.length - index - count) < 0) {
1047            throw new IndexOutOfBoundsException();
1048        }
1049        if (dir != DIRECTION_LTR && dir != DIRECTION_RTL) {
1050            throw new IllegalArgumentException("Unknown direction: " + dir);
1051        }
1052
1053        int modifiers = setupModifiers(paint);
1054        try {
1055            nDrawTextRun(mRenderer, text, index, count, contextIndex, contextCount, x, y, dir,
1056                    paint.mNativePaint);
1057        } finally {
1058            if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
1059        }
1060    }
1061
1062    private static native void nDrawTextRun(int renderer, char[] text, int index, int count,
1063            int contextIndex, int contextCount, float x, float y, int dir, int nativePaint);
1064
1065    @Override
1066    public void drawTextRun(CharSequence text, int start, int end, int contextStart, int contextEnd,
1067            float x, float y, int dir, Paint paint) {
1068        if ((start | end | end - start | text.length() - end) < 0) {
1069            throw new IndexOutOfBoundsException();
1070        }
1071
1072        int modifiers = setupModifiers(paint);
1073        try {
1074            int flags = dir == 0 ? 0 : 1;
1075            if (text instanceof String || text instanceof SpannedString ||
1076                    text instanceof SpannableString) {
1077                nDrawTextRun(mRenderer, text.toString(), start, end, contextStart,
1078                        contextEnd, x, y, flags, paint.mNativePaint);
1079            } else if (text instanceof GraphicsOperations) {
1080                ((GraphicsOperations) text).drawTextRun(this, start, end,
1081                        contextStart, contextEnd, x, y, flags, paint);
1082            } else {
1083                int contextLen = contextEnd - contextStart;
1084                int len = end - start;
1085                char[] buf = TemporaryBuffer.obtain(contextLen);
1086                TextUtils.getChars(text, contextStart, contextEnd, buf, 0);
1087                nDrawTextRun(mRenderer, buf, start - contextStart, len, 0, contextLen,
1088                        x, y, flags, paint.mNativePaint);
1089                TemporaryBuffer.recycle(buf);
1090            }
1091        } finally {
1092            if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
1093        }
1094    }
1095
1096    private static native void nDrawTextRun(int renderer, String text, int start, int end,
1097            int contextStart, int contextEnd, float x, float y, int flags, int nativePaint);
1098
1099    @Override
1100    public void drawVertices(VertexMode mode, int vertexCount, float[] verts, int vertOffset,
1101            float[] texs, int texOffset, int[] colors, int colorOffset, short[] indices,
1102            int indexOffset, int indexCount, Paint paint) {
1103        // TODO: Implement
1104    }
1105
1106    private int setupModifiers(Bitmap b, Paint paint) {
1107        if (b.getConfig() == Bitmap.Config.ALPHA_8) {
1108            return setupModifiers(paint);
1109        }
1110
1111        final ColorFilter filter = paint.getColorFilter();
1112        if (filter != null) {
1113            nSetupColorFilter(mRenderer, filter.nativeColorFilter);
1114            return MODIFIER_COLOR_FILTER;
1115        }
1116
1117        return MODIFIER_NONE;
1118    }
1119
1120    private int setupModifiers(Paint paint) {
1121        int modifiers = MODIFIER_NONE;
1122
1123        if (paint.hasShadow) {
1124            nSetupShadow(mRenderer, paint.shadowRadius, paint.shadowDx, paint.shadowDy,
1125                    paint.shadowColor);
1126            modifiers |= MODIFIER_SHADOW;
1127        }
1128
1129        final Shader shader = paint.getShader();
1130        if (shader != null) {
1131            nSetupShader(mRenderer, shader.native_shader);
1132            modifiers |= MODIFIER_SHADER;
1133        }
1134
1135        final ColorFilter filter = paint.getColorFilter();
1136        if (filter != null) {
1137            nSetupColorFilter(mRenderer, filter.nativeColorFilter);
1138            modifiers |= MODIFIER_COLOR_FILTER;
1139        }
1140
1141        return modifiers;
1142    }
1143
1144    private int setupColorFilter(Paint paint) {
1145        final ColorFilter filter = paint.getColorFilter();
1146        if (filter != null) {
1147            nSetupColorFilter(mRenderer, filter.nativeColorFilter);
1148            return MODIFIER_COLOR_FILTER;
1149        }
1150        return MODIFIER_NONE;
1151    }
1152
1153    private static native void nSetupShader(int renderer, int shader);
1154    private static native void nSetupColorFilter(int renderer, int colorFilter);
1155    private static native void nSetupShadow(int renderer, float radius,
1156            float dx, float dy, int color);
1157
1158    private static native void nResetModifiers(int renderer, int modifiers);
1159}
1160