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