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     * Release all resources associated with the underlying caches. This should
320     * only be called after a full flushCaches().
321     *
322     * @hide
323     */
324    public static void terminateCaches() {
325        nTerminateCaches();
326    }
327
328    private static native void nTerminateCaches();
329
330    /**
331     * @hide
332     */
333    public static void initCaches() {
334        nInitCaches();
335    }
336
337    private static native void nInitCaches();
338
339    ///////////////////////////////////////////////////////////////////////////
340    // Display list
341    ///////////////////////////////////////////////////////////////////////////
342
343    int getDisplayList(int displayList) {
344        return nGetDisplayList(mRenderer, displayList);
345    }
346
347    private static native int nGetDisplayList(int renderer, int displayList);
348
349    static void destroyDisplayList(int displayList) {
350        nDestroyDisplayList(displayList);
351    }
352
353    private static native void nDestroyDisplayList(int displayList);
354
355    static int getDisplayListSize(int displayList) {
356        return nGetDisplayListSize(displayList);
357    }
358
359    private static native int nGetDisplayListSize(int displayList);
360
361    @Override
362    public boolean drawDisplayList(DisplayList displayList, int width, int height, Rect dirty) {
363        return nDrawDisplayList(mRenderer,
364                ((GLES20DisplayList) displayList).getNativeDisplayList(), width, height, dirty);
365    }
366
367    private static native boolean nDrawDisplayList(int renderer, int displayList,
368            int width, int height, Rect dirty);
369
370    @Override
371    void outputDisplayList(DisplayList displayList) {
372        nOutputDisplayList(mRenderer, ((GLES20DisplayList) displayList).getNativeDisplayList());
373    }
374
375    private static native void nOutputDisplayList(int renderer, int displayList);
376
377    ///////////////////////////////////////////////////////////////////////////
378    // Hardware layer
379    ///////////////////////////////////////////////////////////////////////////
380
381    void drawHardwareLayer(HardwareLayer layer, float x, float y, Paint paint) {
382        final GLES20Layer glLayer = (GLES20Layer) layer;
383        int modifier = paint != null ? setupColorFilter(paint) : MODIFIER_NONE;
384        final int nativePaint = paint == null ? 0 : paint.mNativePaint;
385        nDrawLayer(mRenderer, glLayer.getLayer(), x, y, nativePaint);
386        if (modifier != MODIFIER_NONE) nResetModifiers(mRenderer, modifier);
387    }
388
389    private static native void nDrawLayer(int renderer, int layer, float x, float y, int paint);
390
391    void interrupt() {
392        nInterrupt(mRenderer);
393    }
394
395    void resume() {
396        nResume(mRenderer);
397    }
398
399    private static native void nInterrupt(int renderer);
400    private static native void nResume(int renderer);
401
402    ///////////////////////////////////////////////////////////////////////////
403    // Clipping
404    ///////////////////////////////////////////////////////////////////////////
405
406    @Override
407    public boolean clipPath(Path path) {
408        throw new UnsupportedOperationException();
409    }
410
411    @Override
412    public boolean clipPath(Path path, Region.Op op) {
413        throw new UnsupportedOperationException();
414    }
415
416    @Override
417    public boolean clipRect(float left, float top, float right, float bottom) {
418        return nClipRect(mRenderer, left, top, right, bottom, Region.Op.INTERSECT.nativeInt);
419    }
420
421    private static native boolean nClipRect(int renderer, float left, float top,
422            float right, float bottom, int op);
423
424    @Override
425    public boolean clipRect(float left, float top, float right, float bottom, Region.Op op) {
426        return nClipRect(mRenderer, left, top, right, bottom, op.nativeInt);
427    }
428
429    @Override
430    public boolean clipRect(int left, int top, int right, int bottom) {
431        return nClipRect(mRenderer, left, top, right, bottom, Region.Op.INTERSECT.nativeInt);
432    }
433
434    private static native boolean nClipRect(int renderer, int left, int top, int right, int bottom,
435            int op);
436
437    @Override
438    public boolean clipRect(Rect rect) {
439        return nClipRect(mRenderer, rect.left, rect.top, rect.right, rect.bottom,
440                Region.Op.INTERSECT.nativeInt);
441    }
442
443    @Override
444    public boolean clipRect(Rect rect, Region.Op op) {
445        return nClipRect(mRenderer, rect.left, rect.top, rect.right, rect.bottom, op.nativeInt);
446    }
447
448    @Override
449    public boolean clipRect(RectF rect) {
450        return nClipRect(mRenderer, rect.left, rect.top, rect.right, rect.bottom,
451                Region.Op.INTERSECT.nativeInt);
452    }
453
454    @Override
455    public boolean clipRect(RectF rect, Region.Op op) {
456        return nClipRect(mRenderer, rect.left, rect.top, rect.right, rect.bottom, op.nativeInt);
457    }
458
459    @Override
460    public boolean clipRegion(Region region) {
461        throw new UnsupportedOperationException();
462    }
463
464    @Override
465    public boolean clipRegion(Region region, Region.Op op) {
466        throw new UnsupportedOperationException();
467    }
468
469    @Override
470    public boolean getClipBounds(Rect bounds) {
471        return nGetClipBounds(mRenderer, bounds);
472    }
473
474    private static native boolean nGetClipBounds(int renderer, Rect bounds);
475
476    @Override
477    public boolean quickReject(float left, float top, float right, float bottom, EdgeType type) {
478        return nQuickReject(mRenderer, left, top, right, bottom, type.nativeInt);
479    }
480
481    private static native boolean nQuickReject(int renderer, float left, float top,
482            float right, float bottom, int edge);
483
484    @Override
485    public boolean quickReject(Path path, EdgeType type) {
486        throw new UnsupportedOperationException();
487    }
488
489    @Override
490    public boolean quickReject(RectF rect, EdgeType type) {
491        return quickReject(rect.left, rect.top, rect.right, rect.bottom, type);
492    }
493
494    ///////////////////////////////////////////////////////////////////////////
495    // Transformations
496    ///////////////////////////////////////////////////////////////////////////
497
498    @Override
499    public void translate(float dx, float dy) {
500        if (dx != 0.0f || dy != 0.0f) nTranslate(mRenderer, dx, dy);
501    }
502
503    private static native void nTranslate(int renderer, float dx, float dy);
504
505    @Override
506    public void skew(float sx, float sy) {
507        nSkew(mRenderer, sx, sy);
508    }
509
510    private static native void nSkew(int renderer, float sx, float sy);
511
512    @Override
513    public void rotate(float degrees) {
514        nRotate(mRenderer, degrees);
515    }
516
517    private static native void nRotate(int renderer, float degrees);
518
519    @Override
520    public void scale(float sx, float sy) {
521        nScale(mRenderer, sx, sy);
522    }
523
524    private static native void nScale(int renderer, float sx, float sy);
525
526    @Override
527    public void setMatrix(Matrix matrix) {
528        nSetMatrix(mRenderer, matrix.native_instance);
529    }
530
531    private static native void nSetMatrix(int renderer, int matrix);
532
533    @Override
534    public void getMatrix(Matrix matrix) {
535        nGetMatrix(mRenderer, matrix.native_instance);
536    }
537
538    private static native void nGetMatrix(int renderer, int matrix);
539
540    @Override
541    public void concat(Matrix matrix) {
542        nConcatMatrix(mRenderer, matrix.native_instance);
543    }
544
545    private static native void nConcatMatrix(int renderer, int matrix);
546
547    ///////////////////////////////////////////////////////////////////////////
548    // State management
549    ///////////////////////////////////////////////////////////////////////////
550
551    @Override
552    public int save() {
553        return nSave(mRenderer, Canvas.CLIP_SAVE_FLAG | Canvas.MATRIX_SAVE_FLAG);
554    }
555
556    @Override
557    public int save(int saveFlags) {
558        return nSave(mRenderer, saveFlags);
559    }
560
561    private static native int nSave(int renderer, int flags);
562
563    @Override
564    public int saveLayer(RectF bounds, Paint paint, int saveFlags) {
565        if (bounds != null) {
566            return saveLayer(bounds.left, bounds.top, bounds.right, bounds.bottom, paint, saveFlags);
567        }
568
569        int modifier = paint != null ? setupColorFilter(paint) : MODIFIER_NONE;
570        final int nativePaint = paint == null ? 0 : paint.mNativePaint;
571        int count = nSaveLayer(mRenderer, nativePaint, saveFlags);
572        if (modifier != MODIFIER_NONE) nResetModifiers(mRenderer, modifier);
573        return count;
574    }
575
576    private static native int nSaveLayer(int renderer, int paint, int saveFlags);
577
578    @Override
579    public int saveLayer(float left, float top, float right, float bottom, Paint paint,
580            int saveFlags) {
581        if (left < right && top < bottom) {
582            int modifier = paint != null ? setupColorFilter(paint) : MODIFIER_NONE;
583            final int nativePaint = paint == null ? 0 : paint.mNativePaint;
584            int count = nSaveLayer(mRenderer, left, top, right, bottom, nativePaint, saveFlags);
585            if (modifier != MODIFIER_NONE) nResetModifiers(mRenderer, modifier);
586            return count;
587        }
588        return save(saveFlags);
589    }
590
591    private static native int nSaveLayer(int renderer, float left, float top,
592            float right, float bottom, int paint, int saveFlags);
593
594    @Override
595    public int saveLayerAlpha(RectF bounds, int alpha, int saveFlags) {
596        if (bounds != null) {
597            return saveLayerAlpha(bounds.left, bounds.top, bounds.right, bounds.bottom,
598                    alpha, saveFlags);
599        }
600        return nSaveLayerAlpha(mRenderer, alpha, saveFlags);
601    }
602
603    private static native int nSaveLayerAlpha(int renderer, int alpha, int saveFlags);
604
605    @Override
606    public int saveLayerAlpha(float left, float top, float right, float bottom, int alpha,
607            int saveFlags) {
608        if (left < right && top < bottom) {
609            return nSaveLayerAlpha(mRenderer, left, top, right, bottom, alpha, saveFlags);
610        }
611        return save(saveFlags);
612    }
613
614    private static native int nSaveLayerAlpha(int renderer, float left, float top, float right,
615            float bottom, int alpha, int saveFlags);
616
617    @Override
618    public void restore() {
619        nRestore(mRenderer);
620    }
621
622    private static native void nRestore(int renderer);
623
624    @Override
625    public void restoreToCount(int saveCount) {
626        nRestoreToCount(mRenderer, saveCount);
627    }
628
629    private static native void nRestoreToCount(int renderer, int saveCount);
630
631    @Override
632    public int getSaveCount() {
633        return nGetSaveCount(mRenderer);
634    }
635
636    private static native int nGetSaveCount(int renderer);
637
638    ///////////////////////////////////////////////////////////////////////////
639    // Filtering
640    ///////////////////////////////////////////////////////////////////////////
641
642    @Override
643    public void setDrawFilter(DrawFilter filter) {
644        mFilter = filter;
645    }
646
647    @Override
648    public DrawFilter getDrawFilter() {
649        return mFilter;
650    }
651
652    ///////////////////////////////////////////////////////////////////////////
653    // Drawing
654    ///////////////////////////////////////////////////////////////////////////
655
656    @Override
657    public void drawArc(RectF oval, float startAngle, float sweepAngle, boolean useCenter,
658            Paint paint) {
659        int modifiers = setupModifiers(paint);
660        nDrawArc(mRenderer, oval.left, oval.top, oval.right, oval.bottom, startAngle, sweepAngle,
661                useCenter, paint.mNativePaint);
662        if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
663    }
664
665    private static native void nDrawArc(int renderer, float left, float top,
666            float right, float bottom, float startAngle, float sweepAngle,
667            boolean useCenter, int paint);
668
669    @Override
670    public void drawARGB(int a, int r, int g, int b) {
671        drawColor((a & 0xFF) << 24 | (r & 0xFF) << 16 | (g & 0xFF) << 8 | (b & 0xFF));
672    }
673
674    @Override
675    public void drawPatch(Bitmap bitmap, byte[] chunks, RectF dst, Paint paint) {
676        // Shaders are ignored when drawing patches
677        int modifier = paint != null ? setupColorFilter(paint) : MODIFIER_NONE;
678        final int nativePaint = paint == null ? 0 : paint.mNativePaint;
679        nDrawPatch(mRenderer, bitmap.mNativeBitmap, bitmap.mBuffer, chunks,
680                dst.left, dst.top, dst.right, dst.bottom, nativePaint);
681        if (modifier != MODIFIER_NONE) nResetModifiers(mRenderer, modifier);
682    }
683
684    private static native void nDrawPatch(int renderer, int bitmap, byte[] buffer, byte[] chunks,
685            float left, float top, float right, float bottom, int paint);
686
687    @Override
688    public void drawBitmap(Bitmap bitmap, float left, float top, Paint paint) {
689        // Shaders are ignored when drawing bitmaps
690        int modifiers = paint != null ? setupModifiers(bitmap, paint) : MODIFIER_NONE;
691        final int nativePaint = paint == null ? 0 : paint.mNativePaint;
692        nDrawBitmap(mRenderer, bitmap.mNativeBitmap, bitmap.mBuffer, left, top, nativePaint);
693        if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
694    }
695
696    private static native void nDrawBitmap(
697            int renderer, int bitmap, byte[] buffer, float left, float top, int paint);
698
699    @Override
700    public void drawBitmap(Bitmap bitmap, Matrix matrix, Paint paint) {
701        // Shaders are ignored when drawing bitmaps
702        int modifiers = paint != null ? setupModifiers(bitmap, paint) : MODIFIER_NONE;
703        final int nativePaint = paint == null ? 0 : paint.mNativePaint;
704        nDrawBitmap(mRenderer, bitmap.mNativeBitmap, bitmap.mBuffer,
705                matrix.native_instance, nativePaint);
706        if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
707    }
708
709    private static native void nDrawBitmap(int renderer, int bitmap, byte[] buff,
710            int matrix, int paint);
711
712    @Override
713    public void drawBitmap(Bitmap bitmap, Rect src, Rect dst, Paint paint) {
714        // Shaders are ignored when drawing bitmaps
715        int modifiers = paint != null ? setupModifiers(bitmap, paint) : MODIFIER_NONE;
716        final int nativePaint = paint == null ? 0 : paint.mNativePaint;
717
718        int left, top, right, bottom;
719        if (src == null) {
720            left = top = 0;
721            right = bitmap.getWidth();
722            bottom = bitmap.getHeight();
723        } else {
724            left = src.left;
725            right = src.right;
726            top = src.top;
727            bottom = src.bottom;
728        }
729
730        nDrawBitmap(mRenderer, bitmap.mNativeBitmap, bitmap.mBuffer, left, top, right, bottom,
731                dst.left, dst.top, dst.right, dst.bottom, nativePaint);
732        if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
733    }
734
735    @Override
736    public void drawBitmap(Bitmap bitmap, Rect src, RectF dst, Paint paint) {
737        // Shaders are ignored when drawing bitmaps
738        int modifiers = paint != null ? setupModifiers(bitmap, paint) : MODIFIER_NONE;
739        final int nativePaint = paint == null ? 0 : paint.mNativePaint;
740
741        float left, top, right, bottom;
742        if (src == null) {
743            left = top = 0;
744            right = bitmap.getWidth();
745            bottom = bitmap.getHeight();
746        } else {
747            left = src.left;
748            right = src.right;
749            top = src.top;
750            bottom = src.bottom;
751        }
752
753        nDrawBitmap(mRenderer, bitmap.mNativeBitmap, bitmap.mBuffer, left, top, right, bottom,
754                dst.left, dst.top, dst.right, dst.bottom, nativePaint);
755        if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
756    }
757
758    private static native void nDrawBitmap(int renderer, int bitmap, byte[] buffer,
759            float srcLeft, float srcTop, float srcRight, float srcBottom,
760            float left, float top, float right, float bottom, int paint);
761
762    @Override
763    public void drawBitmap(int[] colors, int offset, int stride, float x, float y,
764            int width, int height, boolean hasAlpha, Paint paint) {
765        // Shaders are ignored when drawing bitmaps
766        int modifier = paint != null ? setupColorFilter(paint) : MODIFIER_NONE;
767        final Bitmap.Config config = hasAlpha ? Bitmap.Config.ARGB_8888 : Bitmap.Config.RGB_565;
768        final Bitmap b = Bitmap.createBitmap(colors, offset, stride, width, height, config);
769        final int nativePaint = paint == null ? 0 : paint.mNativePaint;
770        nDrawBitmap(mRenderer, b.mNativeBitmap, b.mBuffer, x, y, nativePaint);
771        b.recycle();
772        if (modifier != MODIFIER_NONE) nResetModifiers(mRenderer, modifier);
773    }
774
775    @Override
776    public void drawBitmap(int[] colors, int offset, int stride, int x, int y,
777            int width, int height, boolean hasAlpha, Paint paint) {
778        // Shaders are ignored when drawing bitmaps
779        drawBitmap(colors, offset, stride, (float) x, (float) y, width, height, hasAlpha, paint);
780    }
781
782    @Override
783    public void drawBitmapMesh(Bitmap bitmap, int meshWidth, int meshHeight, float[] verts,
784            int vertOffset, int[] colors, int colorOffset, Paint paint) {
785        if (meshWidth < 0 || meshHeight < 0 || vertOffset < 0 || colorOffset < 0) {
786            throw new ArrayIndexOutOfBoundsException();
787        }
788
789        if (meshWidth == 0 || meshHeight == 0) {
790            return;
791        }
792
793        final int count = (meshWidth + 1) * (meshHeight + 1);
794        checkRange(verts.length, vertOffset, count * 2);
795
796        // TODO: Colors are ignored for now
797        colors = null;
798        colorOffset = 0;
799
800        int modifiers = paint != null ? setupModifiers(bitmap, paint) : MODIFIER_NONE;
801        final int nativePaint = paint == null ? 0 : paint.mNativePaint;
802        nDrawBitmapMesh(mRenderer, bitmap.mNativeBitmap, bitmap.mBuffer, meshWidth, meshHeight,
803                verts, vertOffset, colors, colorOffset, nativePaint);
804        if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
805    }
806
807    private static native void nDrawBitmapMesh(int renderer, int bitmap, byte[] buffer,
808            int meshWidth, int meshHeight, float[] verts, int vertOffset,
809            int[] colors, int colorOffset, int paint);
810
811    @Override
812    public void drawCircle(float cx, float cy, float radius, Paint paint) {
813        int modifiers = setupModifiers(paint);
814        nDrawCircle(mRenderer, cx, cy, radius, paint.mNativePaint);
815        if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
816    }
817
818    private static native void nDrawCircle(int renderer, float cx, float cy,
819            float radius, int paint);
820
821    @Override
822    public void drawColor(int color) {
823        drawColor(color, PorterDuff.Mode.SRC_OVER);
824    }
825
826    @Override
827    public void drawColor(int color, PorterDuff.Mode mode) {
828        nDrawColor(mRenderer, color, mode.nativeInt);
829    }
830
831    private static native void nDrawColor(int renderer, int color, int mode);
832
833    @Override
834    public void drawLine(float startX, float startY, float stopX, float stopY, Paint paint) {
835        mLine[0] = startX;
836        mLine[1] = startY;
837        mLine[2] = stopX;
838        mLine[3] = stopY;
839        drawLines(mLine, 0, 4, paint);
840    }
841
842    @Override
843    public void drawLines(float[] pts, int offset, int count, Paint paint) {
844        if ((offset | count) < 0 || offset + count > pts.length) {
845            throw new IllegalArgumentException("The lines array must contain 4 elements per line.");
846        }
847        int modifiers = setupModifiers(paint);
848        nDrawLines(mRenderer, pts, offset, count, paint.mNativePaint);
849        if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
850    }
851
852    private static native void nDrawLines(int renderer, float[] points,
853            int offset, int count, int paint);
854
855    @Override
856    public void drawLines(float[] pts, Paint paint) {
857        drawLines(pts, 0, pts.length, paint);
858    }
859
860    @Override
861    public void drawOval(RectF oval, Paint paint) {
862        int modifiers = setupModifiers(paint);
863        nDrawOval(mRenderer, oval.left, oval.top, oval.right, oval.bottom, paint.mNativePaint);
864        if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
865    }
866
867    private static native void nDrawOval(int renderer, float left, float top,
868            float right, float bottom, int paint);
869
870    @Override
871    public void drawPaint(Paint paint) {
872        final Rect r = mClipBounds;
873        nGetClipBounds(mRenderer, r);
874        drawRect(r.left, r.top, r.right, r.bottom, paint);
875    }
876
877    @Override
878    public void drawPath(Path path, Paint paint) {
879        int modifiers = setupModifiers(paint);
880        if (path.isSimplePath) {
881            if (path.rects != null) {
882                nDrawRects(mRenderer, path.rects.mNativeRegion, paint.mNativePaint);
883            }
884        } else {
885            nDrawPath(mRenderer, path.mNativePath, paint.mNativePaint);
886        }
887        if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
888    }
889
890    private static native void nDrawPath(int renderer, int path, int paint);
891    private static native void nDrawRects(int renderer, int region, int paint);
892
893    @Override
894    public void drawPicture(Picture picture) {
895        throw new UnsupportedOperationException();
896    }
897
898    @Override
899    public void drawPicture(Picture picture, Rect dst) {
900        throw new UnsupportedOperationException();
901    }
902
903    @Override
904    public void drawPicture(Picture picture, RectF dst) {
905        throw new UnsupportedOperationException();
906    }
907
908    @Override
909    public void drawPoint(float x, float y, Paint paint) {
910        mPoint[0] = x;
911        mPoint[1] = y;
912        drawPoints(mPoint, 0, 2, paint);
913    }
914
915    @Override
916    public void drawPoints(float[] pts, Paint paint) {
917        drawPoints(pts, 0, pts.length, paint);
918    }
919
920    @Override
921    public void drawPoints(float[] pts, int offset, int count, Paint paint) {
922        int modifiers = setupModifiers(paint);
923        nDrawPoints(mRenderer, pts, offset, count, paint.mNativePaint);
924        if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
925    }
926
927    private static native void nDrawPoints(int renderer, float[] points,
928            int offset, int count, int paint);
929
930    @Override
931    public void drawPosText(char[] text, int index, int count, float[] pos, Paint paint) {
932        // TODO: Implement
933    }
934
935    @Override
936    public void drawPosText(String text, float[] pos, Paint paint) {
937        // TODO: Implement
938    }
939
940    @Override
941    public void drawRect(float left, float top, float right, float bottom, Paint paint) {
942        int modifiers = setupModifiers(paint);
943        nDrawRect(mRenderer, left, top, right, bottom, paint.mNativePaint);
944        if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
945    }
946
947    private static native void nDrawRect(int renderer, float left, float top,
948            float right, float bottom, int paint);
949
950    @Override
951    public void drawRect(Rect r, Paint paint) {
952        drawRect(r.left, r.top, r.right, r.bottom, paint);
953    }
954
955    @Override
956    public void drawRect(RectF r, Paint paint) {
957        drawRect(r.left, r.top, r.right, r.bottom, paint);
958    }
959
960    @Override
961    public void drawRGB(int r, int g, int b) {
962        drawColor(0xFF000000 | (r & 0xFF) << 16 | (g & 0xFF) << 8 | (b & 0xFF));
963    }
964
965    @Override
966    public void drawRoundRect(RectF rect, float rx, float ry, Paint paint) {
967        int modifiers = setupModifiers(paint);
968        nDrawRoundRect(mRenderer, rect.left, rect.top, rect.right, rect.bottom,
969                rx, ry, paint.mNativePaint);
970        if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
971    }
972
973    private static native void nDrawRoundRect(int renderer, float left, float top,
974            float right, float bottom, float rx, float y, int paint);
975
976    @Override
977    public void drawText(char[] text, int index, int count, float x, float y, Paint paint) {
978        if ((index | count | (index + count) | (text.length - index - count)) < 0) {
979            throw new IndexOutOfBoundsException();
980        }
981
982        int modifiers = setupModifiers(paint);
983        try {
984            nDrawText(mRenderer, text, index, count, x, y, paint.mBidiFlags, paint.mNativePaint);
985        } finally {
986            if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
987        }
988    }
989
990    private static native void nDrawText(int renderer, char[] text, int index, int count,
991            float x, float y, int bidiFlags, int paint);
992
993    @Override
994    public void drawText(CharSequence text, int start, int end, float x, float y, Paint paint) {
995        int modifiers = setupModifiers(paint);
996        try {
997            if (text instanceof String || text instanceof SpannedString ||
998                    text instanceof SpannableString) {
999                nDrawText(mRenderer, text.toString(), start, end, x, y, paint.mBidiFlags,
1000                        paint.mNativePaint);
1001            } else if (text instanceof GraphicsOperations) {
1002                ((GraphicsOperations) text).drawText(this, start, end, x, y,
1003                                                         paint);
1004            } else {
1005                char[] buf = TemporaryBuffer.obtain(end - start);
1006                TextUtils.getChars(text, start, end, buf, 0);
1007                nDrawText(mRenderer, buf, 0, end - start, x, y,
1008                        paint.mBidiFlags, paint.mNativePaint);
1009                TemporaryBuffer.recycle(buf);
1010            }
1011        } finally {
1012            if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
1013        }
1014    }
1015
1016    @Override
1017    public void drawText(String text, int start, int end, float x, float y, Paint paint) {
1018        if ((start | end | (end - start) | (text.length() - end)) < 0) {
1019            throw new IndexOutOfBoundsException();
1020        }
1021
1022        int modifiers = setupModifiers(paint);
1023        try {
1024            nDrawText(mRenderer, text, start, end, x, y, paint.mBidiFlags, paint.mNativePaint);
1025        } finally {
1026            if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
1027        }
1028    }
1029
1030    private static native void nDrawText(int renderer, String text, int start, int end,
1031            float x, float y, int bidiFlags, int paint);
1032
1033    @Override
1034    public void drawText(String text, float x, float y, Paint paint) {
1035        int modifiers = setupModifiers(paint);
1036        try {
1037            nDrawText(mRenderer, text, 0, text.length(), x, y, paint.mBidiFlags,
1038                    paint.mNativePaint);
1039        } finally {
1040            if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
1041        }
1042    }
1043
1044    @Override
1045    public void drawTextOnPath(char[] text, int index, int count, Path path, float hOffset,
1046            float vOffset, Paint paint) {
1047        // TODO: Implement
1048    }
1049
1050    @Override
1051    public void drawTextOnPath(String text, Path path, float hOffset, float vOffset, Paint paint) {
1052        // TODO: Implement
1053    }
1054
1055    @Override
1056    public void drawTextRun(char[] text, int index, int count, int contextIndex, int contextCount,
1057            float x, float y, int dir, Paint paint) {
1058        if ((index | count | text.length - index - count) < 0) {
1059            throw new IndexOutOfBoundsException();
1060        }
1061        if (dir != DIRECTION_LTR && dir != DIRECTION_RTL) {
1062            throw new IllegalArgumentException("Unknown direction: " + dir);
1063        }
1064
1065        int modifiers = setupModifiers(paint);
1066        try {
1067            nDrawTextRun(mRenderer, text, index, count, contextIndex, contextCount, x, y, dir,
1068                    paint.mNativePaint);
1069        } finally {
1070            if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
1071        }
1072    }
1073
1074    private static native void nDrawTextRun(int renderer, char[] text, int index, int count,
1075            int contextIndex, int contextCount, float x, float y, int dir, int nativePaint);
1076
1077    @Override
1078    public void drawTextRun(CharSequence text, int start, int end, int contextStart, int contextEnd,
1079            float x, float y, int dir, Paint paint) {
1080        if ((start | end | end - start | text.length() - end) < 0) {
1081            throw new IndexOutOfBoundsException();
1082        }
1083
1084        int modifiers = setupModifiers(paint);
1085        try {
1086            int flags = dir == 0 ? 0 : 1;
1087            if (text instanceof String || text instanceof SpannedString ||
1088                    text instanceof SpannableString) {
1089                nDrawTextRun(mRenderer, text.toString(), start, end, contextStart,
1090                        contextEnd, x, y, flags, paint.mNativePaint);
1091            } else if (text instanceof GraphicsOperations) {
1092                ((GraphicsOperations) text).drawTextRun(this, start, end,
1093                        contextStart, contextEnd, x, y, flags, paint);
1094            } else {
1095                int contextLen = contextEnd - contextStart;
1096                int len = end - start;
1097                char[] buf = TemporaryBuffer.obtain(contextLen);
1098                TextUtils.getChars(text, contextStart, contextEnd, buf, 0);
1099                nDrawTextRun(mRenderer, buf, start - contextStart, len, 0, contextLen,
1100                        x, y, flags, paint.mNativePaint);
1101                TemporaryBuffer.recycle(buf);
1102            }
1103        } finally {
1104            if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
1105        }
1106    }
1107
1108    private static native void nDrawTextRun(int renderer, String text, int start, int end,
1109            int contextStart, int contextEnd, float x, float y, int flags, int nativePaint);
1110
1111    @Override
1112    public void drawVertices(VertexMode mode, int vertexCount, float[] verts, int vertOffset,
1113            float[] texs, int texOffset, int[] colors, int colorOffset, short[] indices,
1114            int indexOffset, int indexCount, Paint paint) {
1115        // TODO: Implement
1116    }
1117
1118    private int setupModifiers(Bitmap b, Paint paint) {
1119        if (b.getConfig() == Bitmap.Config.ALPHA_8) {
1120            return setupModifiers(paint);
1121        }
1122
1123        final ColorFilter filter = paint.getColorFilter();
1124        if (filter != null) {
1125            nSetupColorFilter(mRenderer, filter.nativeColorFilter);
1126            return MODIFIER_COLOR_FILTER;
1127        }
1128
1129        return MODIFIER_NONE;
1130    }
1131
1132    private int setupModifiers(Paint paint) {
1133        int modifiers = MODIFIER_NONE;
1134
1135        if (paint.hasShadow) {
1136            nSetupShadow(mRenderer, paint.shadowRadius, paint.shadowDx, paint.shadowDy,
1137                    paint.shadowColor);
1138            modifiers |= MODIFIER_SHADOW;
1139        }
1140
1141        final Shader shader = paint.getShader();
1142        if (shader != null) {
1143            nSetupShader(mRenderer, shader.native_shader);
1144            modifiers |= MODIFIER_SHADER;
1145        }
1146
1147        final ColorFilter filter = paint.getColorFilter();
1148        if (filter != null) {
1149            nSetupColorFilter(mRenderer, filter.nativeColorFilter);
1150            modifiers |= MODIFIER_COLOR_FILTER;
1151        }
1152
1153        return modifiers;
1154    }
1155
1156    private int setupColorFilter(Paint paint) {
1157        final ColorFilter filter = paint.getColorFilter();
1158        if (filter != null) {
1159            nSetupColorFilter(mRenderer, filter.nativeColorFilter);
1160            return MODIFIER_COLOR_FILTER;
1161        }
1162        return MODIFIER_NONE;
1163    }
1164
1165    private static native void nSetupShader(int renderer, int shader);
1166    private static native void nSetupColorFilter(int renderer, int colorFilter);
1167    private static native void nSetupShadow(int renderer, float radius,
1168            float dx, float dy, int color);
1169
1170    private static native void nResetModifiers(int renderer, int modifiers);
1171}
1172