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