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