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