GLES20Canvas.java revision b2a4b52e8d5e499d33e2765e8c47851bf0266299
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.TemporaryBuffer;
33import android.text.GraphicsOperations;
34import android.text.SpannableString;
35import android.text.SpannedString;
36import android.text.TextUtils;
37
38/**
39 * An implementation of Canvas on top of OpenGL ES 2.0.
40 */
41class GLES20Canvas extends HardwareCanvas {
42    // Must match modifiers used in the JNI layer
43    private static final int MODIFIER_NONE = 0;
44    private static final int MODIFIER_SHADOW = 1;
45    private static final int MODIFIER_SHADER = 2;
46    private static final int MODIFIER_COLOR_FILTER = 4;
47
48    private final boolean mOpaque;
49    private int mRenderer;
50
51    // The native renderer will be destroyed when this object dies.
52    // DO NOT overwrite this reference once it is set.
53    private CanvasFinalizer mFinalizer;
54
55    private int mWidth;
56    private int mHeight;
57
58    private final float[] mPoint = new float[2];
59    private final float[] mLine = new float[4];
60
61    private final Rect mClipBounds = new Rect();
62
63    private DrawFilter mFilter;
64
65    ///////////////////////////////////////////////////////////////////////////
66    // JNI
67    ///////////////////////////////////////////////////////////////////////////
68
69    private static native boolean nIsAvailable();
70    private static boolean sIsAvailable = nIsAvailable();
71
72    static boolean isAvailable() {
73        return sIsAvailable;
74    }
75
76    ///////////////////////////////////////////////////////////////////////////
77    // Constructors
78    ///////////////////////////////////////////////////////////////////////////
79
80    /**
81     * Creates a canvas to render directly on screen.
82     */
83    GLES20Canvas(boolean translucent) {
84        this(false, translucent);
85    }
86
87    /**
88     * Creates a canvas to render into an FBO.
89     */
90    GLES20Canvas(int layer, boolean translucent) {
91        mOpaque = !translucent;
92        mRenderer = nCreateLayerRenderer(layer);
93        setupFinalizer();
94    }
95
96    protected GLES20Canvas(boolean record, boolean translucent) {
97        mOpaque = !translucent;
98
99        setupRenderer(record);
100    }
101
102    protected void setupRenderer(boolean record) {
103        if (record) {
104            mRenderer = nGetDisplayListRenderer(mRenderer);
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 = CanvasFinalizer.getFinalizer(mFinalizer, mRenderer);
117        }
118    }
119
120    private static native int nCreateRenderer();
121    private static native int nCreateLayerRenderer(int layer);
122    private static native int nGetDisplayListRenderer(int renderer);
123    private static native void nDestroyRenderer(int renderer);
124
125    private static class CanvasFinalizer {
126        int mRenderer;
127
128        // Factory method returns new instance if old one is null, or old instance
129        // otherwise, destroying native renderer along the way as necessary
130        static CanvasFinalizer getFinalizer(CanvasFinalizer oldFinalizer, int renderer) {
131            if (oldFinalizer == null) {
132                return new CanvasFinalizer(renderer);
133            }
134            oldFinalizer.replaceNativeObject(renderer);
135            return oldFinalizer;
136        }
137
138        private CanvasFinalizer(int renderer) {
139            mRenderer = renderer;
140        }
141
142        private void replaceNativeObject(int newRenderer) {
143            if (mRenderer != 0 && newRenderer != mRenderer) {
144                nDestroyRenderer(mRenderer);
145            }
146            mRenderer = newRenderer;
147        }
148
149        @Override
150        protected void finalize() throws Throwable {
151            try {
152                replaceNativeObject(0);
153            } finally {
154                super.finalize();
155            }
156        }
157    }
158
159    ///////////////////////////////////////////////////////////////////////////
160    // Hardware layers
161    ///////////////////////////////////////////////////////////////////////////
162
163    static native int nCreateTextureLayer(int[] layerInfo);
164    static native int nCreateLayer(int width, int height, boolean isOpaque, int[] layerInfo);
165    static native void nResizeLayer(int layerId, int width, int height, int[] layerInfo);
166    static native void nUpdateTextureLayer(int layerId, int width, int height, int surface);
167    static native void nDestroyLayer(int layerId);
168    static native void nDestroyLayerDeferred(int layerId);
169
170    ///////////////////////////////////////////////////////////////////////////
171    // Canvas management
172    ///////////////////////////////////////////////////////////////////////////
173
174    @Override
175    public boolean isOpaque() {
176        return mOpaque;
177    }
178
179    @Override
180    public int getWidth() {
181        return mWidth;
182    }
183
184    @Override
185    public int getHeight() {
186        return mHeight;
187    }
188
189    ///////////////////////////////////////////////////////////////////////////
190    // Setup
191    ///////////////////////////////////////////////////////////////////////////
192
193    @Override
194    public void setViewport(int width, int height) {
195        mWidth = width;
196        mHeight = height;
197
198        nSetViewport(mRenderer, width, height);
199    }
200
201    private static native void nSetViewport(int renderer, int width, int height);
202
203    /**
204     * @hide
205     */
206    public static boolean preserveBackBuffer() {
207        return nPreserveBackBuffer();
208    }
209
210    private static native boolean nPreserveBackBuffer();
211
212    @Override
213    void onPreDraw(Rect dirty) {
214        if (dirty != null) {
215            nPrepareDirty(mRenderer, dirty.left, dirty.top, dirty.right, dirty.bottom, mOpaque);
216        } else {
217            nPrepare(mRenderer, mOpaque);
218        }
219    }
220
221    private static native void nPrepare(int renderer, boolean opaque);
222    private static native void nPrepareDirty(int renderer, int left, int top, int right, int bottom,
223            boolean opaque);
224
225    @Override
226    void onPostDraw() {
227        nFinish(mRenderer);
228    }
229
230    private static native void nFinish(int renderer);
231
232    @Override
233    public boolean callDrawGLFunction(int drawGLFunction) {
234        return nCallDrawGLFunction(mRenderer, drawGLFunction);
235    }
236
237    private static native boolean nCallDrawGLFunction(int renderer, int drawGLFunction);
238
239    ///////////////////////////////////////////////////////////////////////////
240    // Display list
241    ///////////////////////////////////////////////////////////////////////////
242
243    int getDisplayList() {
244        return nGetDisplayList(mRenderer);
245    }
246
247    private static native int nGetDisplayList(int renderer);
248
249    static void destroyDisplayList(int displayList) {
250        nDestroyDisplayList(displayList);
251    }
252
253    private static native void nDestroyDisplayList(int displayList);
254
255    @Override
256    public boolean drawDisplayList(DisplayList displayList, int width, int height, Rect dirty) {
257        return nDrawDisplayList(mRenderer,
258                ((GLES20DisplayList) displayList).mNativeDisplayList, width, height, dirty);
259    }
260
261    private static native boolean nDrawDisplayList(int renderer, int displayList,
262            int width, int height, Rect dirty);
263
264    @Override
265    void outputDisplayList(DisplayList displayList) {
266        nOutputDisplayList(mRenderer, ((GLES20DisplayList) displayList).mNativeDisplayList);
267    }
268
269    private static native void nOutputDisplayList(int renderer, int displayList);
270
271    ///////////////////////////////////////////////////////////////////////////
272    // Hardware layer
273    ///////////////////////////////////////////////////////////////////////////
274
275    void drawHardwareLayer(HardwareLayer layer, float x, float y, Paint paint) {
276        final GLES20Layer glLayer = (GLES20Layer) layer;
277        int modifier = paint != null ? setupColorFilter(paint) : MODIFIER_NONE;
278        final int nativePaint = paint == null ? 0 : paint.mNativePaint;
279        nDrawLayer(mRenderer, glLayer.getLayer(), x, y, nativePaint);
280        if (modifier != MODIFIER_NONE) nResetModifiers(mRenderer, modifier);
281    }
282
283    private static native void nDrawLayer(int renderer, int layer, float x, float y, int paint);
284
285    void interrupt() {
286        nInterrupt(mRenderer);
287    }
288
289    void resume() {
290        nResume(mRenderer);
291    }
292
293    private static native void nInterrupt(int renderer);
294    private static native void nResume(int renderer);
295
296    ///////////////////////////////////////////////////////////////////////////
297    // Clipping
298    ///////////////////////////////////////////////////////////////////////////
299
300    @Override
301    public boolean clipPath(Path path) {
302        throw new UnsupportedOperationException();
303    }
304
305    @Override
306    public boolean clipPath(Path path, Region.Op op) {
307        throw new UnsupportedOperationException();
308    }
309
310    @Override
311    public boolean clipRect(float left, float top, float right, float bottom) {
312        return nClipRect(mRenderer, left, top, right, bottom, Region.Op.INTERSECT.nativeInt);
313    }
314
315    private static native boolean nClipRect(int renderer, float left, float top,
316            float right, float bottom, int op);
317
318    @Override
319    public boolean clipRect(float left, float top, float right, float bottom, Region.Op op) {
320        return nClipRect(mRenderer, left, top, right, bottom, op.nativeInt);
321    }
322
323    @Override
324    public boolean clipRect(int left, int top, int right, int bottom) {
325        return nClipRect(mRenderer, left, top, right, bottom, Region.Op.INTERSECT.nativeInt);
326    }
327
328    private static native boolean nClipRect(int renderer, int left, int top, int right, int bottom,
329            int op);
330
331    @Override
332    public boolean clipRect(Rect rect) {
333        return nClipRect(mRenderer, rect.left, rect.top, rect.right, rect.bottom,
334                Region.Op.INTERSECT.nativeInt);
335    }
336
337    @Override
338    public boolean clipRect(Rect rect, Region.Op op) {
339        return nClipRect(mRenderer, rect.left, rect.top, rect.right, rect.bottom, op.nativeInt);
340    }
341
342    @Override
343    public boolean clipRect(RectF rect) {
344        return nClipRect(mRenderer, rect.left, rect.top, rect.right, rect.bottom,
345                Region.Op.INTERSECT.nativeInt);
346    }
347
348    @Override
349    public boolean clipRect(RectF rect, Region.Op op) {
350        return nClipRect(mRenderer, rect.left, rect.top, rect.right, rect.bottom, op.nativeInt);
351    }
352
353    @Override
354    public boolean clipRegion(Region region) {
355        throw new UnsupportedOperationException();
356    }
357
358    @Override
359    public boolean clipRegion(Region region, Region.Op op) {
360        throw new UnsupportedOperationException();
361    }
362
363    @Override
364    public boolean getClipBounds(Rect bounds) {
365        return nGetClipBounds(mRenderer, bounds);
366    }
367
368    private static native boolean nGetClipBounds(int renderer, Rect bounds);
369
370    @Override
371    public boolean quickReject(float left, float top, float right, float bottom, EdgeType type) {
372        return nQuickReject(mRenderer, left, top, right, bottom, type.nativeInt);
373    }
374
375    private static native boolean nQuickReject(int renderer, float left, float top,
376            float right, float bottom, int edge);
377
378    @Override
379    public boolean quickReject(Path path, EdgeType type) {
380        throw new UnsupportedOperationException();
381    }
382
383    @Override
384    public boolean quickReject(RectF rect, EdgeType type) {
385        return quickReject(rect.left, rect.top, rect.right, rect.bottom, type);
386    }
387
388    ///////////////////////////////////////////////////////////////////////////
389    // Transformations
390    ///////////////////////////////////////////////////////////////////////////
391
392    @Override
393    public void translate(float dx, float dy) {
394        if (dx != 0.0f || dy != 0.0f) nTranslate(mRenderer, dx, dy);
395    }
396
397    private static native void nTranslate(int renderer, float dx, float dy);
398
399    @Override
400    public void skew(float sx, float sy) {
401        nSkew(mRenderer, sx, sy);
402    }
403
404    private static native void nSkew(int renderer, float sx, float sy);
405
406    @Override
407    public void rotate(float degrees) {
408        nRotate(mRenderer, degrees);
409    }
410
411    private static native void nRotate(int renderer, float degrees);
412
413    @Override
414    public void scale(float sx, float sy) {
415        nScale(mRenderer, sx, sy);
416    }
417
418    private static native void nScale(int renderer, float sx, float sy);
419
420    @Override
421    public void setMatrix(Matrix matrix) {
422        nSetMatrix(mRenderer, matrix.native_instance);
423    }
424
425    private static native void nSetMatrix(int renderer, int matrix);
426
427    @Override
428    public int getNativeMatrix() {
429        return nGetMatrix(mRenderer);
430    }
431
432    private static native int nGetMatrix(int renderer);
433
434    @Override
435    public void getMatrix(Matrix matrix) {
436        nGetMatrix(mRenderer, matrix.native_instance);
437    }
438
439    private static native void nGetMatrix(int renderer, int matrix);
440
441    @Override
442    public void concat(Matrix matrix) {
443        nConcatMatrix(mRenderer, matrix.native_instance);
444    }
445
446    private static native void nConcatMatrix(int renderer, int matrix);
447
448    ///////////////////////////////////////////////////////////////////////////
449    // State management
450    ///////////////////////////////////////////////////////////////////////////
451
452    @Override
453    public int save() {
454        return nSave(mRenderer, Canvas.CLIP_SAVE_FLAG | Canvas.MATRIX_SAVE_FLAG);
455    }
456
457    @Override
458    public int save(int saveFlags) {
459        return nSave(mRenderer, saveFlags);
460    }
461
462    private static native int nSave(int renderer, int flags);
463
464    @Override
465    public int saveLayer(RectF bounds, Paint paint, int saveFlags) {
466        return saveLayer(bounds.left, bounds.top, bounds.right, bounds.bottom, paint, saveFlags);
467    }
468
469    @Override
470    public int saveLayer(float left, float top, float right, float bottom, Paint paint,
471            int saveFlags) {
472        if (left < right && top < bottom) {
473            int modifier = paint != null ? setupColorFilter(paint) : MODIFIER_NONE;
474            final int nativePaint = paint == null ? 0 : paint.mNativePaint;
475            int count = nSaveLayer(mRenderer, left, top, right, bottom, nativePaint, saveFlags);
476            if (modifier != MODIFIER_NONE) nResetModifiers(mRenderer, modifier);
477            return count;
478        }
479        return save(saveFlags);
480    }
481
482    private static native int nSaveLayer(int renderer, float left, float top,
483            float right, float bottom, int paint, int saveFlags);
484
485    @Override
486    public int saveLayerAlpha(RectF bounds, int alpha, int saveFlags) {
487        return saveLayerAlpha(bounds.left, bounds.top, bounds.right, bounds.bottom,
488                alpha, saveFlags);
489    }
490
491    @Override
492    public int saveLayerAlpha(float left, float top, float right, float bottom, int alpha,
493            int saveFlags) {
494        if (left < right && top < bottom) {
495            return nSaveLayerAlpha(mRenderer, left, top, right, bottom, alpha, saveFlags);
496        }
497        return save(saveFlags);
498    }
499
500    private static native int nSaveLayerAlpha(int renderer, float left, float top, float right,
501            float bottom, int alpha, int saveFlags);
502
503    @Override
504    public void restore() {
505        nRestore(mRenderer);
506    }
507
508    private static native void nRestore(int renderer);
509
510    @Override
511    public void restoreToCount(int saveCount) {
512        nRestoreToCount(mRenderer, saveCount);
513    }
514
515    private static native void nRestoreToCount(int renderer, int saveCount);
516
517    @Override
518    public int getSaveCount() {
519        return nGetSaveCount(mRenderer);
520    }
521
522    private static native int nGetSaveCount(int renderer);
523
524    ///////////////////////////////////////////////////////////////////////////
525    // Filtering
526    ///////////////////////////////////////////////////////////////////////////
527
528    @Override
529    public void setDrawFilter(DrawFilter filter) {
530        mFilter = filter;
531    }
532
533    @Override
534    public DrawFilter getDrawFilter() {
535        return mFilter;
536    }
537
538    ///////////////////////////////////////////////////////////////////////////
539    // Drawing
540    ///////////////////////////////////////////////////////////////////////////
541
542    @Override
543    public void drawArc(RectF oval, float startAngle, float sweepAngle, boolean useCenter,
544            Paint paint) {
545        int modifiers = setupModifiers(paint);
546        nDrawArc(mRenderer, oval.left, oval.top, oval.right, oval.bottom, startAngle, sweepAngle,
547                useCenter, paint.mNativePaint);
548        if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
549    }
550
551    private static native void nDrawArc(int renderer, float left, float top,
552            float right, float bottom, float startAngle, float sweepAngle,
553            boolean useCenter, int paint);
554
555    @Override
556    public void drawARGB(int a, int r, int g, int b) {
557        drawColor((a & 0xFF) << 24 | (r & 0xFF) << 16 | (g & 0xFF) << 8 | (b & 0xFF));
558    }
559
560    @Override
561    public void drawPatch(Bitmap bitmap, byte[] chunks, RectF dst, Paint paint) {
562        // Shaders are ignored when drawing patches
563        int modifier = paint != null ? setupColorFilter(paint) : MODIFIER_NONE;
564        final int nativePaint = paint == null ? 0 : paint.mNativePaint;
565        nDrawPatch(mRenderer, bitmap.mNativeBitmap, bitmap.mBuffer, chunks,
566                dst.left, dst.top, dst.right, dst.bottom, nativePaint);
567        if (modifier != MODIFIER_NONE) nResetModifiers(mRenderer, modifier);
568    }
569
570    private static native void nDrawPatch(int renderer, int bitmap, byte[] buffer, byte[] chunks,
571            float left, float top, float right, float bottom, int paint);
572
573    @Override
574    public void drawBitmap(Bitmap bitmap, float left, float top, Paint paint) {
575        // Shaders are ignored when drawing bitmaps
576        int modifiers = paint != null ? setupModifiers(bitmap, paint) : MODIFIER_NONE;
577        final int nativePaint = paint == null ? 0 : paint.mNativePaint;
578        nDrawBitmap(mRenderer, bitmap.mNativeBitmap, bitmap.mBuffer, left, top, nativePaint);
579        if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
580    }
581
582    private static native void nDrawBitmap(
583            int renderer, int bitmap, byte[] buffer, float left, float top, int paint);
584
585    @Override
586    public void drawBitmap(Bitmap bitmap, Matrix matrix, Paint paint) {
587        // Shaders are ignored when drawing bitmaps
588        int modifiers = paint != null ? setupModifiers(bitmap, paint) : MODIFIER_NONE;
589        final int nativePaint = paint == null ? 0 : paint.mNativePaint;
590        nDrawBitmap(mRenderer, bitmap.mNativeBitmap, bitmap.mBuffer,
591                matrix.native_instance, nativePaint);
592        if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
593    }
594
595    private static native void nDrawBitmap(int renderer, int bitmap, byte[] buff,
596            int matrix, int paint);
597
598    @Override
599    public void drawBitmap(Bitmap bitmap, Rect src, Rect dst, Paint paint) {
600        // Shaders are ignored when drawing bitmaps
601        int modifiers = paint != null ? setupModifiers(bitmap, paint) : MODIFIER_NONE;
602        final int nativePaint = paint == null ? 0 : paint.mNativePaint;
603
604        int left, top, right, bottom;
605        if (src == null) {
606            left = top = 0;
607            right = bitmap.getWidth();
608            bottom = bitmap.getHeight();
609        } else {
610            left = src.left;
611            right = src.right;
612            top = src.top;
613            bottom = src.bottom;
614        }
615
616        nDrawBitmap(mRenderer, bitmap.mNativeBitmap, bitmap.mBuffer, left, top, right, bottom,
617                dst.left, dst.top, dst.right, dst.bottom, nativePaint);
618        if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
619    }
620
621    @Override
622    public void drawBitmap(Bitmap bitmap, Rect src, RectF dst, Paint paint) {
623        // Shaders are ignored when drawing bitmaps
624        int modifiers = paint != null ? setupModifiers(bitmap, paint) : MODIFIER_NONE;
625        final int nativePaint = paint == null ? 0 : paint.mNativePaint;
626        nDrawBitmap(mRenderer, bitmap.mNativeBitmap, bitmap.mBuffer, src.left, src.top, src.right,
627                src.bottom, dst.left, dst.top, dst.right, dst.bottom, nativePaint);
628        if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
629    }
630
631    private static native void nDrawBitmap(int renderer, int bitmap, byte[] buffer,
632            float srcLeft, float srcTop, float srcRight, float srcBottom,
633            float left, float top, float right, float bottom, int paint);
634
635    @Override
636    public void drawBitmap(int[] colors, int offset, int stride, float x, float y,
637            int width, int height, boolean hasAlpha, Paint paint) {
638        // Shaders are ignored when drawing bitmaps
639        int modifier = paint != null ? setupColorFilter(paint) : MODIFIER_NONE;
640        final Bitmap.Config config = hasAlpha ? Bitmap.Config.ARGB_8888 : Bitmap.Config.RGB_565;
641        final Bitmap b = Bitmap.createBitmap(colors, offset, stride, width, height, config);
642        final int nativePaint = paint == null ? 0 : paint.mNativePaint;
643        nDrawBitmap(mRenderer, b.mNativeBitmap, b.mBuffer, x, y, nativePaint);
644        b.recycle();
645        if (modifier != MODIFIER_NONE) nResetModifiers(mRenderer, modifier);
646    }
647
648    @Override
649    public void drawBitmap(int[] colors, int offset, int stride, int x, int y,
650            int width, int height, boolean hasAlpha, Paint paint) {
651        // Shaders are ignored when drawing bitmaps
652        drawBitmap(colors, offset, stride, (float) x, (float) y, width, height, hasAlpha, paint);
653    }
654
655    @Override
656    public void drawBitmapMesh(Bitmap bitmap, int meshWidth, int meshHeight, float[] verts,
657            int vertOffset, int[] colors, int colorOffset, Paint paint) {
658        if (meshWidth < 0 || meshHeight < 0 || vertOffset < 0 || colorOffset < 0) {
659            throw new ArrayIndexOutOfBoundsException();
660        }
661
662        if (meshWidth == 0 || meshHeight == 0) {
663            return;
664        }
665
666        final int count = (meshWidth + 1) * (meshHeight + 1);
667        checkRange(verts.length, vertOffset, count * 2);
668
669        // TODO: Colors are ignored for now
670        colors = null;
671        colorOffset = 0;
672
673        int modifiers = paint != null ? setupModifiers(bitmap, paint) : MODIFIER_NONE;
674        final int nativePaint = paint == null ? 0 : paint.mNativePaint;
675        nDrawBitmapMesh(mRenderer, bitmap.mNativeBitmap, bitmap.mBuffer, meshWidth, meshHeight,
676                verts, vertOffset, colors, colorOffset, nativePaint);
677        if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
678    }
679
680    private static native void nDrawBitmapMesh(int renderer, int bitmap, byte[] buffer,
681            int meshWidth, int meshHeight, float[] verts, int vertOffset,
682            int[] colors, int colorOffset, int paint);
683
684    @Override
685    public void drawCircle(float cx, float cy, float radius, Paint paint) {
686        int modifiers = setupModifiers(paint);
687        nDrawCircle(mRenderer, cx, cy, radius, paint.mNativePaint);
688        if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
689    }
690
691    private static native void nDrawCircle(int renderer, float cx, float cy,
692            float radius, int paint);
693
694    @Override
695    public void drawColor(int color) {
696        drawColor(color, PorterDuff.Mode.SRC_OVER);
697    }
698
699    @Override
700    public void drawColor(int color, PorterDuff.Mode mode) {
701        nDrawColor(mRenderer, color, mode.nativeInt);
702    }
703
704    private static native void nDrawColor(int renderer, int color, int mode);
705
706    @Override
707    public void drawLine(float startX, float startY, float stopX, float stopY, Paint paint) {
708        mLine[0] = startX;
709        mLine[1] = startY;
710        mLine[2] = stopX;
711        mLine[3] = stopY;
712        drawLines(mLine, 0, 4, paint);
713    }
714
715    @Override
716    public void drawLines(float[] pts, int offset, int count, Paint paint) {
717        if ((offset | count) < 0 || offset + count > pts.length) {
718            throw new IllegalArgumentException("The lines array must contain 4 elements per line.");
719        }
720        int modifiers = setupModifiers(paint);
721        nDrawLines(mRenderer, pts, offset, count, paint.mNativePaint);
722        if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
723    }
724
725    private static native void nDrawLines(int renderer, float[] points,
726            int offset, int count, int paint);
727
728    @Override
729    public void drawLines(float[] pts, Paint paint) {
730        drawLines(pts, 0, pts.length, paint);
731    }
732
733    @Override
734    public void drawOval(RectF oval, Paint paint) {
735        int modifiers = setupModifiers(paint);
736        nDrawOval(mRenderer, oval.left, oval.top, oval.right, oval.bottom, paint.mNativePaint);
737        if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
738    }
739
740    private static native void nDrawOval(int renderer, float left, float top,
741            float right, float bottom, int paint);
742
743    @Override
744    public void drawPaint(Paint paint) {
745        final Rect r = mClipBounds;
746        nGetClipBounds(mRenderer, r);
747        drawRect(r.left, r.top, r.right, r.bottom, paint);
748    }
749
750    @Override
751    public void drawPath(Path path, Paint paint) {
752        int modifiers = setupModifiers(paint);
753        if (path.isSimplePath) {
754            if (path.rects != null) {
755                nDrawRects(mRenderer, path.rects.mNativeRegion, paint.mNativePaint);
756            }
757        } else {
758            nDrawPath(mRenderer, path.mNativePath, paint.mNativePaint);
759        }
760        if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
761    }
762
763    private static native void nDrawPath(int renderer, int path, int paint);
764    private static native void nDrawRects(int renderer, int region, int paint);
765
766    @Override
767    public void drawPicture(Picture picture) {
768        throw new UnsupportedOperationException();
769    }
770
771    @Override
772    public void drawPicture(Picture picture, Rect dst) {
773        throw new UnsupportedOperationException();
774    }
775
776    @Override
777    public void drawPicture(Picture picture, RectF dst) {
778        throw new UnsupportedOperationException();
779    }
780
781    @Override
782    public void drawPoint(float x, float y, Paint paint) {
783        mPoint[0] = x;
784        mPoint[1] = y;
785        drawPoints(mPoint, 0, 2, paint);
786    }
787
788    @Override
789    public void drawPoints(float[] pts, Paint paint) {
790        drawPoints(pts, 0, pts.length, paint);
791    }
792
793    @Override
794    public void drawPoints(float[] pts, int offset, int count, Paint paint) {
795        int modifiers = setupModifiers(paint);
796        nDrawPoints(mRenderer, pts, offset, count, paint.mNativePaint);
797        if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
798    }
799
800    private static native void nDrawPoints(int renderer, float[] points,
801            int offset, int count, int paint);
802
803    @Override
804    public void drawPosText(char[] text, int index, int count, float[] pos, Paint paint) {
805        // TODO: Implement
806    }
807
808    @Override
809    public void drawPosText(String text, float[] pos, Paint paint) {
810        // TODO: Implement
811    }
812
813    @Override
814    public void drawRect(float left, float top, float right, float bottom, Paint paint) {
815        int modifiers = setupModifiers(paint);
816        nDrawRect(mRenderer, left, top, right, bottom, paint.mNativePaint);
817        if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
818    }
819
820    private static native void nDrawRect(int renderer, float left, float top,
821            float right, float bottom, int paint);
822
823    @Override
824    public void drawRect(Rect r, Paint paint) {
825        drawRect(r.left, r.top, r.right, r.bottom, paint);
826    }
827
828    @Override
829    public void drawRect(RectF r, Paint paint) {
830        drawRect(r.left, r.top, r.right, r.bottom, paint);
831    }
832
833    @Override
834    public void drawRGB(int r, int g, int b) {
835        drawColor(0xFF000000 | (r & 0xFF) << 16 | (g & 0xFF) << 8 | (b & 0xFF));
836    }
837
838    @Override
839    public void drawRoundRect(RectF rect, float rx, float ry, Paint paint) {
840        int modifiers = setupModifiers(paint);
841        nDrawRoundRect(mRenderer, rect.left, rect.top, rect.right, rect.bottom,
842                rx, ry, paint.mNativePaint);
843        if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
844    }
845
846    private static native void nDrawRoundRect(int renderer, float left, float top,
847            float right, float bottom, float rx, float y, int paint);
848
849    @Override
850    public void drawText(char[] text, int index, int count, float x, float y, Paint paint) {
851        if ((index | count | (index + count) | (text.length - index - count)) < 0) {
852            throw new IndexOutOfBoundsException();
853        }
854
855        int modifiers = setupModifiers(paint);
856        try {
857            nDrawText(mRenderer, text, index, count, x, y, paint.mBidiFlags, paint.mNativePaint);
858        } finally {
859            if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
860        }
861    }
862
863    private static native void nDrawText(int renderer, char[] text, int index, int count,
864            float x, float y, int bidiFlags, int paint);
865
866    @Override
867    public void drawText(CharSequence text, int start, int end, float x, float y, Paint paint) {
868        int modifiers = setupModifiers(paint);
869        try {
870            if (text instanceof String || text instanceof SpannedString ||
871                    text instanceof SpannableString) {
872                nDrawText(mRenderer, text.toString(), start, end, x, y, paint.mBidiFlags,
873                        paint.mNativePaint);
874            } else if (text instanceof GraphicsOperations) {
875                ((GraphicsOperations) text).drawText(this, start, end, x, y,
876                                                         paint);
877            } else {
878                char[] buf = TemporaryBuffer.obtain(end - start);
879                TextUtils.getChars(text, start, end, buf, 0);
880                nDrawText(mRenderer, buf, 0, end - start, x, y,
881                        paint.mBidiFlags, paint.mNativePaint);
882                TemporaryBuffer.recycle(buf);
883            }
884        } finally {
885            if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
886        }
887    }
888
889    @Override
890    public void drawText(String text, int start, int end, float x, float y, Paint paint) {
891        if ((start | end | (end - start) | (text.length() - end)) < 0) {
892            throw new IndexOutOfBoundsException();
893        }
894
895        int modifiers = setupModifiers(paint);
896        try {
897            nDrawText(mRenderer, text, start, end, x, y, paint.mBidiFlags, paint.mNativePaint);
898        } finally {
899            if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
900        }
901    }
902
903    private static native void nDrawText(int renderer, String text, int start, int end,
904            float x, float y, int bidiFlags, int paint);
905
906    @Override
907    public void drawText(String text, float x, float y, Paint paint) {
908        int modifiers = setupModifiers(paint);
909        try {
910            nDrawText(mRenderer, text, 0, text.length(), x, y, paint.mBidiFlags,
911                    paint.mNativePaint);
912        } finally {
913            if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
914        }
915    }
916
917    @Override
918    public void drawTextOnPath(char[] text, int index, int count, Path path, float hOffset,
919            float vOffset, Paint paint) {
920        // TODO: Implement
921    }
922
923    @Override
924    public void drawTextOnPath(String text, Path path, float hOffset, float vOffset, Paint paint) {
925        // TODO: Implement
926    }
927
928    @Override
929    public void drawTextRun(char[] text, int index, int count, int contextIndex, int contextCount,
930            float x, float y, int dir, Paint paint) {
931        if ((index | count | text.length - index - count) < 0) {
932            throw new IndexOutOfBoundsException();
933        }
934        if (dir != DIRECTION_LTR && dir != DIRECTION_RTL) {
935            throw new IllegalArgumentException("Unknown direction: " + dir);
936        }
937
938        int modifiers = setupModifiers(paint);
939        try {
940            nDrawTextRun(mRenderer, text, index, count, contextIndex, contextCount, x, y, dir,
941                    paint.mNativePaint);
942        } finally {
943            if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
944        }
945    }
946
947    private static native void nDrawTextRun(int renderer, char[] text, int index, int count,
948            int contextIndex, int contextCount, float x, float y, int dir, int nativePaint);
949
950    @Override
951    public void drawTextRun(CharSequence text, int start, int end, int contextStart, int contextEnd,
952            float x, float y, int dir, Paint paint) {
953        if ((start | end | end - start | text.length() - end) < 0) {
954            throw new IndexOutOfBoundsException();
955        }
956
957        int modifiers = setupModifiers(paint);
958        try {
959            int flags = dir == 0 ? 0 : 1;
960            if (text instanceof String || text instanceof SpannedString ||
961                    text instanceof SpannableString) {
962                nDrawTextRun(mRenderer, text.toString(), start, end, contextStart,
963                        contextEnd, x, y, flags, paint.mNativePaint);
964            } else if (text instanceof GraphicsOperations) {
965                ((GraphicsOperations) text).drawTextRun(this, start, end,
966                        contextStart, contextEnd, x, y, flags, paint);
967            } else {
968                int contextLen = contextEnd - contextStart;
969                int len = end - start;
970                char[] buf = TemporaryBuffer.obtain(contextLen);
971                TextUtils.getChars(text, contextStart, contextEnd, buf, 0);
972                nDrawTextRun(mRenderer, buf, start - contextStart, len, 0, contextLen,
973                        x, y, flags, paint.mNativePaint);
974                TemporaryBuffer.recycle(buf);
975            }
976        } finally {
977            if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
978        }
979    }
980
981    private static native void nDrawTextRun(int renderer, String text, int start, int end,
982            int contextStart, int contextEnd, float x, float y, int flags, int nativePaint);
983
984    @Override
985    public void drawVertices(VertexMode mode, int vertexCount, float[] verts, int vertOffset,
986            float[] texs, int texOffset, int[] colors, int colorOffset, short[] indices,
987            int indexOffset, int indexCount, Paint paint) {
988        // TODO: Implement
989    }
990
991    private int setupModifiers(Bitmap b, Paint paint) {
992        if (b.getConfig() == Bitmap.Config.ALPHA_8) {
993            return setupModifiers(paint);
994        }
995
996        final ColorFilter filter = paint.getColorFilter();
997        if (filter != null) {
998            nSetupColorFilter(mRenderer, filter.nativeColorFilter);
999            return MODIFIER_COLOR_FILTER;
1000        }
1001
1002        return MODIFIER_NONE;
1003    }
1004
1005    private int setupModifiers(Paint paint) {
1006        int modifiers = MODIFIER_NONE;
1007
1008        if (paint.hasShadow) {
1009            nSetupShadow(mRenderer, paint.shadowRadius, paint.shadowDx, paint.shadowDy,
1010                    paint.shadowColor);
1011            modifiers |= MODIFIER_SHADOW;
1012        }
1013
1014        final Shader shader = paint.getShader();
1015        if (shader != null) {
1016            nSetupShader(mRenderer, shader.native_shader);
1017            modifiers |= MODIFIER_SHADER;
1018        }
1019
1020        final ColorFilter filter = paint.getColorFilter();
1021        if (filter != null) {
1022            nSetupColorFilter(mRenderer, filter.nativeColorFilter);
1023            modifiers |= MODIFIER_COLOR_FILTER;
1024        }
1025
1026        return modifiers;
1027    }
1028
1029    private int setupColorFilter(Paint paint) {
1030        final ColorFilter filter = paint.getColorFilter();
1031        if (filter != null) {
1032            nSetupColorFilter(mRenderer, filter.nativeColorFilter);
1033            return MODIFIER_COLOR_FILTER;
1034        }
1035        return MODIFIER_NONE;
1036    }
1037
1038    private static native void nSetupShader(int renderer, int shader);
1039    private static native void nSetupColorFilter(int renderer, int colorFilter);
1040    private static native void nSetupShadow(int renderer, float radius,
1041            float dx, float dy, int color);
1042
1043    private static native void nResetModifiers(int renderer, int modifiers);
1044}
1045