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