GLES20Canvas.java revision c1cd9ba335b293f11e1082447ef08e474710a05f
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 void releaseContext() {
224        if (mContextLocked) {
225            nReleaseContext(mRenderer);
226            mContextLocked = false;
227        }
228    }
229
230    private native void nReleaseContext(int renderer);
231
232    ///////////////////////////////////////////////////////////////////////////
233    // Display list
234    ///////////////////////////////////////////////////////////////////////////
235
236    int getDisplayList() {
237        return nGetDisplayList(mRenderer);
238    }
239
240    private native int nGetDisplayList(int renderer);
241
242    static void destroyDisplayList(int displayList) {
243        nDestroyDisplayList(displayList);
244    }
245
246    private static native void nDestroyDisplayList(int displayList);
247
248    @Override
249    public void drawDisplayList(DisplayList displayList) {
250        nDrawDisplayList(mRenderer, ((GLES20DisplayList) displayList).mNativeDisplayList);
251    }
252
253    private native void nDrawDisplayList(int renderer, int displayList);
254
255    ///////////////////////////////////////////////////////////////////////////
256    // Hardware layer
257    ///////////////////////////////////////////////////////////////////////////
258
259    void drawHardwareLayer(HardwareLayer layer, float x, float y, Paint paint) {
260        final GLES20Layer glLayer = (GLES20Layer) layer;
261        boolean hasColorFilter = paint != null && setupColorFilter(paint);
262        final int nativePaint = paint == null ? 0 : paint.mNativePaint;
263        nDrawLayer(mRenderer, glLayer.getLayer(), x, y, nativePaint);
264        if (hasColorFilter) nResetModifiers(mRenderer);
265    }
266
267    private native void nDrawLayer(int renderer, int layer, float x, float y, int paint);
268
269    void interrupt() {
270        nInterrupt(mRenderer);
271    }
272
273    void resume() {
274        nResume(mRenderer);
275    }
276
277    private native void nInterrupt(int renderer);
278    private native void nResume(int renderer);
279
280    ///////////////////////////////////////////////////////////////////////////
281    // Clipping
282    ///////////////////////////////////////////////////////////////////////////
283
284    @Override
285    public boolean clipPath(Path path) {
286        throw new UnsupportedOperationException();
287    }
288
289    @Override
290    public boolean clipPath(Path path, Region.Op op) {
291        throw new UnsupportedOperationException();
292    }
293
294    @Override
295    public boolean clipRect(float left, float top, float right, float bottom) {
296        return nClipRect(mRenderer, left, top, right, bottom, Region.Op.INTERSECT.nativeInt);
297    }
298
299    private native boolean nClipRect(int renderer, float left, float top,
300            float right, float bottom, int op);
301
302    @Override
303    public boolean clipRect(float left, float top, float right, float bottom, Region.Op op) {
304        return nClipRect(mRenderer, left, top, right, bottom, op.nativeInt);
305    }
306
307    @Override
308    public boolean clipRect(int left, int top, int right, int bottom) {
309        return nClipRect(mRenderer, left, top, right, bottom, Region.Op.INTERSECT.nativeInt);
310    }
311
312    private native boolean nClipRect(int renderer, int left, int top, int right, int bottom, int op);
313
314    @Override
315    public boolean clipRect(Rect rect) {
316        return nClipRect(mRenderer, rect.left, rect.top, rect.right, rect.bottom,
317                Region.Op.INTERSECT.nativeInt);
318    }
319
320    @Override
321    public boolean clipRect(Rect rect, Region.Op op) {
322        return nClipRect(mRenderer, rect.left, rect.top, rect.right, rect.bottom, op.nativeInt);
323    }
324
325    @Override
326    public boolean clipRect(RectF rect) {
327        return nClipRect(mRenderer, rect.left, rect.top, rect.right, rect.bottom,
328                Region.Op.INTERSECT.nativeInt);
329    }
330
331    @Override
332    public boolean clipRect(RectF rect, Region.Op op) {
333        return nClipRect(mRenderer, rect.left, rect.top, rect.right, rect.bottom, op.nativeInt);
334    }
335
336    @Override
337    public boolean clipRegion(Region region) {
338        throw new UnsupportedOperationException();
339    }
340
341    @Override
342    public boolean clipRegion(Region region, Region.Op op) {
343        throw new UnsupportedOperationException();
344    }
345
346    @Override
347    public boolean getClipBounds(Rect bounds) {
348        return nGetClipBounds(mRenderer, bounds);
349    }
350
351    private native boolean nGetClipBounds(int renderer, Rect bounds);
352
353    @Override
354    public boolean quickReject(float left, float top, float right, float bottom, EdgeType type) {
355        return nQuickReject(mRenderer, left, top, right, bottom, type.nativeInt);
356    }
357
358    private native boolean nQuickReject(int renderer, float left, float top,
359            float right, float bottom, int edge);
360
361    @Override
362    public boolean quickReject(Path path, EdgeType type) {
363        throw new UnsupportedOperationException();
364    }
365
366    @Override
367    public boolean quickReject(RectF rect, EdgeType type) {
368        return quickReject(rect.left, rect.top, rect.right, rect.bottom, type);
369    }
370
371    ///////////////////////////////////////////////////////////////////////////
372    // Transformations
373    ///////////////////////////////////////////////////////////////////////////
374
375    @Override
376    public void translate(float dx, float dy) {
377        if (dx != 0.0f || dy != 0.0f) nTranslate(mRenderer, dx, dy);
378    }
379
380    private native void nTranslate(int renderer, float dx, float dy);
381
382    @Override
383    public void skew(float sx, float sy) {
384        nSkew(mRenderer, sx, sy);
385    }
386
387    private native void nSkew(int renderer, float sx, float sy);
388
389    @Override
390    public void rotate(float degrees) {
391        nRotate(mRenderer, degrees);
392    }
393
394    private native void nRotate(int renderer, float degrees);
395
396    @Override
397    public void scale(float sx, float sy) {
398        nScale(mRenderer, sx, sy);
399    }
400
401    private native void nScale(int renderer, float sx, float sy);
402
403    @Override
404    public void setMatrix(Matrix matrix) {
405        nSetMatrix(mRenderer, matrix.native_instance);
406    }
407
408    private native void nSetMatrix(int renderer, int matrix);
409
410    @Override
411    public int getNativeMatrix() {
412        return nGetMatrix(mRenderer);
413    }
414
415    private native int nGetMatrix(int renderer);
416
417    @Override
418    public void getMatrix(Matrix matrix) {
419        nGetMatrix(mRenderer, matrix.native_instance);
420    }
421
422    private native void nGetMatrix(int renderer, int matrix);
423
424    @Override
425    public void concat(Matrix matrix) {
426        nConcatMatrix(mRenderer, matrix.native_instance);
427    }
428
429    private native void nConcatMatrix(int renderer, int matrix);
430
431    ///////////////////////////////////////////////////////////////////////////
432    // State management
433    ///////////////////////////////////////////////////////////////////////////
434
435    @Override
436    public int save() {
437        return nSave(mRenderer, Canvas.CLIP_SAVE_FLAG | Canvas.MATRIX_SAVE_FLAG);
438    }
439
440    @Override
441    public int save(int saveFlags) {
442        return nSave(mRenderer, saveFlags);
443    }
444
445    private native int nSave(int renderer, int flags);
446
447    @Override
448    public int saveLayer(RectF bounds, Paint paint, int saveFlags) {
449        return saveLayer(bounds.left, bounds.top, bounds.right, bounds.bottom, paint, saveFlags);
450    }
451
452    @Override
453    public int saveLayer(float left, float top, float right, float bottom, Paint paint,
454            int saveFlags) {
455        if (left < right && top < bottom) {
456            boolean hasColorFilter = paint != null && setupColorFilter(paint);
457            final int nativePaint = paint == null ? 0 : paint.mNativePaint;
458            int count = nSaveLayer(mRenderer, left, top, right, bottom, nativePaint, saveFlags);
459            if (hasColorFilter) nResetModifiers(mRenderer);
460            return count;
461        }
462        return save(saveFlags);
463    }
464
465    private native int nSaveLayer(int renderer, float left, float top, float right, float bottom,
466            int paint, int saveFlags);
467
468    @Override
469    public int saveLayerAlpha(RectF bounds, int alpha, int saveFlags) {
470        return saveLayerAlpha(bounds.left, bounds.top, bounds.right, bounds.bottom,
471                alpha, saveFlags);
472    }
473
474    @Override
475    public int saveLayerAlpha(float left, float top, float right, float bottom, int alpha,
476            int saveFlags) {
477        if (left < right && top < bottom) {
478            return nSaveLayerAlpha(mRenderer, left, top, right, bottom, alpha, saveFlags);
479        }
480        return save(saveFlags);
481    }
482
483    private native int nSaveLayerAlpha(int renderer, float left, float top, float right,
484            float bottom, int alpha, int saveFlags);
485
486    @Override
487    public void restore() {
488        nRestore(mRenderer);
489    }
490
491    private native void nRestore(int renderer);
492
493    @Override
494    public void restoreToCount(int saveCount) {
495        nRestoreToCount(mRenderer, saveCount);
496    }
497
498    private native void nRestoreToCount(int renderer, int saveCount);
499
500    @Override
501    public int getSaveCount() {
502        return nGetSaveCount(mRenderer);
503    }
504
505    private native int nGetSaveCount(int renderer);
506
507    ///////////////////////////////////////////////////////////////////////////
508    // Filtering
509    ///////////////////////////////////////////////////////////////////////////
510
511    @Override
512    public void setDrawFilter(DrawFilter filter) {
513        mFilter = filter;
514    }
515
516    @Override
517    public DrawFilter getDrawFilter() {
518        return mFilter;
519    }
520
521    ///////////////////////////////////////////////////////////////////////////
522    // Drawing
523    ///////////////////////////////////////////////////////////////////////////
524
525    @Override
526    public void drawArc(RectF oval, float startAngle, float sweepAngle, boolean useCenter,
527            Paint paint) {
528        // TODO: Implement
529    }
530
531    @Override
532    public void drawARGB(int a, int r, int g, int b) {
533        drawColor((a & 0xFF) << 24 | (r & 0xFF) << 16 | (g & 0xFF) << 8 | (b & 0xFF));
534    }
535
536    @Override
537    public void drawPatch(Bitmap bitmap, byte[] chunks, RectF dst, Paint paint) {
538        // Shaders are ignored when drawing patches
539        boolean hasColorFilter = paint != null && setupColorFilter(paint);
540        final int nativePaint = paint == null ? 0 : paint.mNativePaint;
541        nDrawPatch(mRenderer, bitmap.mNativeBitmap, bitmap.mBuffer, chunks,
542                dst.left, dst.top, dst.right, dst.bottom, nativePaint);
543        if (hasColorFilter) nResetModifiers(mRenderer);
544    }
545
546    private native void nDrawPatch(int renderer, int bitmap, byte[] buffer, byte[] chunks,
547            float left, float top, float right, float bottom, int paint);
548
549    @Override
550    public void drawBitmap(Bitmap bitmap, float left, float top, Paint paint) {
551        // Shaders are ignored when drawing bitmaps
552        boolean hasColorFilter = paint != null && setupColorFilter(paint);
553        final int nativePaint = paint == null ? 0 : paint.mNativePaint;
554        nDrawBitmap(mRenderer, bitmap.mNativeBitmap, bitmap.mBuffer, left, top, nativePaint);
555        if (hasColorFilter) nResetModifiers(mRenderer);
556    }
557
558    private native void nDrawBitmap(
559            int renderer, int bitmap, byte[] buffer, float left, float top, int paint);
560
561    @Override
562    public void drawBitmap(Bitmap bitmap, Matrix matrix, Paint paint) {
563        // Shaders are ignored when drawing bitmaps
564        boolean hasColorFilter = paint != null && setupColorFilter(paint);
565        final int nativePaint = paint == null ? 0 : paint.mNativePaint;
566        nDrawBitmap(mRenderer, bitmap.mNativeBitmap, bitmap.mBuffer,
567                matrix.native_instance, nativePaint);
568        if (hasColorFilter) nResetModifiers(mRenderer);
569    }
570
571    private native void nDrawBitmap(int renderer, int bitmap, byte[] buff, int matrix, int paint);
572
573    @Override
574    public void drawBitmap(Bitmap bitmap, Rect src, Rect dst, Paint paint) {
575        // Shaders are ignored when drawing bitmaps
576        boolean hasColorFilter = paint != null && setupColorFilter(paint);
577        final int nativePaint = paint == null ? 0 : paint.mNativePaint;
578
579        int left, top, right, bottom;
580        if (src == null) {
581            left = top = 0;
582            right = bitmap.getWidth();
583            bottom = bitmap.getHeight();
584        } else {
585            left = src.left;
586            right = src.right;
587            top = src.top;
588            bottom = src.bottom;
589        }
590
591        nDrawBitmap(mRenderer, bitmap.mNativeBitmap, bitmap.mBuffer, left, top, right, bottom,
592                dst.left, dst.top, dst.right, dst.bottom, nativePaint);
593        if (hasColorFilter) nResetModifiers(mRenderer);
594    }
595
596    @Override
597    public void drawBitmap(Bitmap bitmap, Rect src, RectF dst, Paint paint) {
598        // Shaders are ignored when drawing bitmaps
599        boolean hasColorFilter = paint != null && setupColorFilter(paint);
600        final int nativePaint = paint == null ? 0 : paint.mNativePaint;
601        nDrawBitmap(mRenderer, bitmap.mNativeBitmap, bitmap.mBuffer, src.left, src.top, src.right,
602                src.bottom, dst.left, dst.top, dst.right, dst.bottom, nativePaint);
603        if (hasColorFilter) nResetModifiers(mRenderer);
604    }
605
606    private native void nDrawBitmap(int renderer, int bitmap, byte[] buffer,
607            float srcLeft, float srcTop, float srcRight, float srcBottom,
608            float left, float top, float right, float bottom, int paint);
609
610    @Override
611    public void drawBitmap(int[] colors, int offset, int stride, float x, float y,
612            int width, int height, boolean hasAlpha, Paint paint) {
613        // Shaders are ignored when drawing bitmaps
614        boolean hasColorFilter = paint != null && setupColorFilter(paint);
615        final Bitmap.Config config = hasAlpha ? Bitmap.Config.ARGB_8888 : Bitmap.Config.RGB_565;
616        final Bitmap b = Bitmap.createBitmap(colors, offset, stride, width, height, config);
617        final int nativePaint = paint == null ? 0 : paint.mNativePaint;
618        nDrawBitmap(mRenderer, b.mNativeBitmap, b.mBuffer, x, y, nativePaint);
619        b.recycle();
620        if (hasColorFilter) nResetModifiers(mRenderer);
621    }
622
623    @Override
624    public void drawBitmap(int[] colors, int offset, int stride, int x, int y,
625            int width, int height, boolean hasAlpha, Paint paint) {
626        // Shaders are ignored when drawing bitmaps
627        drawBitmap(colors, offset, stride, (float) x, (float) y, width, height, hasAlpha, paint);
628    }
629
630    @Override
631    public void drawBitmapMesh(Bitmap bitmap, int meshWidth, int meshHeight, float[] verts,
632            int vertOffset, int[] colors, int colorOffset, Paint paint) {
633        if (meshWidth < 0 || meshHeight < 0 || vertOffset < 0 || colorOffset < 0) {
634            throw new ArrayIndexOutOfBoundsException();
635        }
636
637        if (meshWidth == 0 || meshHeight == 0) {
638            return;
639        }
640
641        final int count = (meshWidth + 1) * (meshHeight + 1);
642        checkRange(verts.length, vertOffset, count * 2);
643
644        // TODO: Colors are ignored for now
645        colors = null;
646        colorOffset = 0;
647
648        boolean hasColorFilter = paint != null && setupColorFilter(paint);
649        final int nativePaint = paint == null ? 0 : paint.mNativePaint;
650        nDrawBitmapMesh(mRenderer, bitmap.mNativeBitmap, bitmap.mBuffer, meshWidth, meshHeight,
651                verts, vertOffset, colors, colorOffset, nativePaint);
652        if (hasColorFilter) nResetModifiers(mRenderer);
653    }
654
655    private native void nDrawBitmapMesh(int renderer, int bitmap, byte[] buffer,
656            int meshWidth, int meshHeight, float[] verts, int vertOffset,
657            int[] colors, int colorOffset, int paint);
658
659    @Override
660    public void drawCircle(float cx, float cy, float radius, Paint paint) {
661        boolean hasModifier = setupModifiers(paint);
662        nDrawCircle(mRenderer, cx, cy, radius, paint.mNativePaint);
663        if (hasModifier) nResetModifiers(mRenderer);
664    }
665
666    private native void nDrawCircle(int renderer, float cx, float cy, float radius, int paint);
667
668    @Override
669    public void drawColor(int color) {
670        drawColor(color, PorterDuff.Mode.SRC_OVER);
671    }
672
673    @Override
674    public void drawColor(int color, PorterDuff.Mode mode) {
675        nDrawColor(mRenderer, color, mode.nativeInt);
676    }
677
678    private native void nDrawColor(int renderer, int color, int mode);
679
680    @Override
681    public void drawLine(float startX, float startY, float stopX, float stopY, Paint paint) {
682        mLine[0] = startX;
683        mLine[1] = startY;
684        mLine[2] = stopX;
685        mLine[3] = stopY;
686        drawLines(mLine, 0, 4, paint);
687    }
688
689    @Override
690    public void drawLines(float[] pts, int offset, int count, Paint paint) {
691        if ((offset | count) < 0 || offset + count > pts.length) {
692            throw new IllegalArgumentException("The lines array must contain 4 elements per line.");
693        }
694        boolean hasModifier = setupModifiers(paint);
695        nDrawLines(mRenderer, pts, offset, count, paint.mNativePaint);
696        if (hasModifier) nResetModifiers(mRenderer);
697    }
698
699    private native void nDrawLines(int renderer, float[] points, int offset, int count, int paint);
700
701    @Override
702    public void drawLines(float[] pts, Paint paint) {
703        drawLines(pts, 0, pts.length, paint);
704    }
705
706    @Override
707    public void drawOval(RectF oval, Paint paint) {
708        boolean hasModifier = setupModifiers(paint);
709        nDrawOval(mRenderer, oval.left, oval.top, oval.right, oval.bottom, paint.mNativePaint);
710        if (hasModifier) nResetModifiers(mRenderer);
711    }
712
713    private native void nDrawOval(int renderer, float left, float top, float right, float bottom,
714            int paint);
715
716    @Override
717    public void drawPaint(Paint paint) {
718        final Rect r = mClipBounds;
719        nGetClipBounds(mRenderer, r);
720        drawRect(r.left, r.top, r.right, r.bottom, paint);
721    }
722
723    @Override
724    public void drawPath(Path path, Paint paint) {
725        boolean hasModifier = setupModifiers(paint);
726        if (path.isSimplePath) {
727            if (path.rects != null) {
728                nDrawRects(mRenderer, path.rects.mNativeRegion, paint.mNativePaint);
729            }
730        } else {
731            nDrawPath(mRenderer, path.mNativePath, paint.mNativePaint);
732        }
733        if (hasModifier) nResetModifiers(mRenderer);
734    }
735
736    private native void nDrawPath(int renderer, int path, int paint);
737    private native void nDrawRects(int renderer, int region, int paint);
738
739    @Override
740    public void drawPicture(Picture picture) {
741        throw new UnsupportedOperationException();
742    }
743
744    @Override
745    public void drawPicture(Picture picture, Rect dst) {
746        throw new UnsupportedOperationException();
747    }
748
749    @Override
750    public void drawPicture(Picture picture, RectF dst) {
751        throw new UnsupportedOperationException();
752    }
753
754    @Override
755    public void drawPoint(float x, float y, Paint paint) {
756        mPoint[0] = x;
757        mPoint[1] = y;
758        drawPoints(mPoint, 0, 1, paint);
759    }
760
761    @Override
762    public void drawPoints(float[] pts, int offset, int count, Paint paint) {
763        // TODO: Implement
764    }
765
766    @Override
767    public void drawPoints(float[] pts, Paint paint) {
768        drawPoints(pts, 0, pts.length / 2, paint);
769    }
770
771    @Override
772    public void drawPosText(char[] text, int index, int count, float[] pos, Paint paint) {
773        // TODO: Implement
774    }
775
776    @Override
777    public void drawPosText(String text, float[] pos, Paint paint) {
778        // TODO: Implement
779    }
780
781    @Override
782    public void drawRect(float left, float top, float right, float bottom, Paint paint) {
783        boolean hasModifier = setupModifiers(paint);
784        nDrawRect(mRenderer, left, top, right, bottom, paint.mNativePaint);
785        if (hasModifier) nResetModifiers(mRenderer);
786    }
787
788    private native void nDrawRect(int renderer, float left, float top, float right, float bottom,
789            int paint);
790
791    @Override
792    public void drawRect(Rect r, Paint paint) {
793        drawRect(r.left, r.top, r.right, r.bottom, paint);
794    }
795
796    @Override
797    public void drawRect(RectF r, Paint paint) {
798        drawRect(r.left, r.top, r.right, r.bottom, paint);
799    }
800
801    @Override
802    public void drawRGB(int r, int g, int b) {
803        drawColor(0xFF000000 | (r & 0xFF) << 16 | (g & 0xFF) << 8 | (b & 0xFF));
804    }
805
806    @Override
807    public void drawRoundRect(RectF rect, float rx, float ry, Paint paint) {
808        boolean hasModifier = setupModifiers(paint);
809        nDrawRoundRect(mRenderer, rect.left, rect.top, rect.right, rect.bottom,
810                rx, ry, paint.mNativePaint);
811        if (hasModifier) nResetModifiers(mRenderer);
812    }
813
814    private native void nDrawRoundRect(int renderer, float left, float top,
815            float right, float bottom, float rx, float y, int paint);
816
817    @Override
818    public void drawText(char[] text, int index, int count, float x, float y, Paint paint) {
819        if ((index | count | (index + count) | (text.length - index - count)) < 0) {
820            throw new IndexOutOfBoundsException();
821        }
822
823        boolean hasModifier = setupModifiers(paint);
824        try {
825            nDrawText(mRenderer, text, index, count, x, y, paint.mBidiFlags, paint.mNativePaint);
826        } finally {
827            if (hasModifier) nResetModifiers(mRenderer);
828        }
829    }
830
831    private native void nDrawText(int renderer, char[] text, int index, int count, float x, float y,
832            int bidiFlags, int paint);
833
834    @Override
835    public void drawText(CharSequence text, int start, int end, float x, float y, Paint paint) {
836        boolean hasModifier = setupModifiers(paint);
837        try {
838            if (text instanceof String || text instanceof SpannedString ||
839                    text instanceof SpannableString) {
840                nDrawText(mRenderer, text.toString(), start, end, x, y, paint.mBidiFlags,
841                        paint.mNativePaint);
842            } else if (text instanceof GraphicsOperations) {
843                ((GraphicsOperations) text).drawText(this, start, end, x, y,
844                                                         paint);
845            } else {
846                char[] buf = TemporaryBuffer.obtain(end - start);
847                TextUtils.getChars(text, start, end, buf, 0);
848                nDrawText(mRenderer, buf, 0, end - start, x, y, paint.mBidiFlags, paint.mNativePaint);
849                TemporaryBuffer.recycle(buf);
850            }
851        } finally {
852            if (hasModifier) nResetModifiers(mRenderer);
853        }
854    }
855
856    @Override
857    public void drawText(String text, int start, int end, float x, float y, Paint paint) {
858        if ((start | end | (end - start) | (text.length() - end)) < 0) {
859            throw new IndexOutOfBoundsException();
860        }
861
862        boolean hasModifier = setupModifiers(paint);
863        try {
864            nDrawText(mRenderer, text, start, end, x, y, paint.mBidiFlags, paint.mNativePaint);
865        } finally {
866            if (hasModifier) nResetModifiers(mRenderer);
867        }
868    }
869
870    private native void nDrawText(int renderer, String text, int start, int end, float x, float y,
871            int bidiFlags, int paint);
872
873    @Override
874    public void drawText(String text, float x, float y, Paint paint) {
875        boolean hasModifier = setupModifiers(paint);
876        try {
877            nDrawText(mRenderer, text, 0, text.length(), x, y, paint.mBidiFlags,
878                    paint.mNativePaint);
879        } finally {
880            if (hasModifier) nResetModifiers(mRenderer);
881        }
882    }
883
884    @Override
885    public void drawTextOnPath(char[] text, int index, int count, Path path, float hOffset,
886            float vOffset, Paint paint) {
887        // TODO: Implement
888    }
889
890    @Override
891    public void drawTextOnPath(String text, Path path, float hOffset, float vOffset, Paint paint) {
892        // TODO: Implement
893    }
894
895    @Override
896    public void drawTextRun(char[] text, int index, int count, int contextIndex, int contextCount,
897            float x, float y, int dir, Paint paint) {
898        if ((index | count | text.length - index - count) < 0) {
899            throw new IndexOutOfBoundsException();
900        }
901        if (dir != DIRECTION_LTR && dir != DIRECTION_RTL) {
902            throw new IllegalArgumentException("Unknown direction: " + dir);
903        }
904
905        boolean hasModifier = setupModifiers(paint);
906        try {
907            nDrawTextRun(mRenderer, text, index, count, contextIndex, contextCount, x, y, dir,
908                    paint.mNativePaint);
909        } finally {
910            if (hasModifier) nResetModifiers(mRenderer);
911        }
912    }
913
914    private native void nDrawTextRun(int renderer, char[] text, int index, int count,
915            int contextIndex, int contextCount, float x, float y, int dir, int nativePaint);
916
917    @Override
918    public void drawTextRun(CharSequence text, int start, int end, int contextStart, int contextEnd,
919            float x, float y, int dir, Paint paint) {
920        if ((start | end | end - start | text.length() - end) < 0) {
921            throw new IndexOutOfBoundsException();
922        }
923
924        boolean hasModifier = setupModifiers(paint);
925        try {
926            int flags = dir == 0 ? 0 : 1;
927            if (text instanceof String || text instanceof SpannedString ||
928                    text instanceof SpannableString) {
929                nDrawTextRun(mRenderer, text.toString(), start, end, contextStart,
930                        contextEnd, x, y, flags, paint.mNativePaint);
931            } else if (text instanceof GraphicsOperations) {
932                ((GraphicsOperations) text).drawTextRun(this, start, end,
933                        contextStart, contextEnd, x, y, flags, paint);
934            } else {
935                int contextLen = contextEnd - contextStart;
936                int len = end - start;
937                char[] buf = TemporaryBuffer.obtain(contextLen);
938                TextUtils.getChars(text, contextStart, contextEnd, buf, 0);
939                nDrawTextRun(mRenderer, buf, start - contextStart, len, 0, contextLen,
940                        x, y, flags, paint.mNativePaint);
941                TemporaryBuffer.recycle(buf);
942            }
943        } finally {
944            if (hasModifier) nResetModifiers(mRenderer);
945        }
946    }
947
948    private native void nDrawTextRun(int renderer, String text, int start, int end,
949            int contextStart, int contextEnd, float x, float y, int flags, int nativePaint);
950
951    @Override
952    public void drawVertices(VertexMode mode, int vertexCount, float[] verts, int vertOffset,
953            float[] texs, int texOffset, int[] colors, int colorOffset, short[] indices,
954            int indexOffset, int indexCount, Paint paint) {
955        // TODO: Implement
956    }
957
958    private boolean setupModifiers(Paint paint) {
959        boolean hasModifier = false;
960
961        if (paint.hasShadow) {
962            nSetupShadow(mRenderer, paint.shadowRadius, paint.shadowDx, paint.shadowDy,
963                    paint.shadowColor);
964            hasModifier = true;
965        }
966
967        final Shader shader = paint.getShader();
968        if (shader != null) {
969            nSetupShader(mRenderer, shader.native_shader);
970            hasModifier = true;
971        }
972
973        final ColorFilter filter = paint.getColorFilter();
974        if (filter != null) {
975            nSetupColorFilter(mRenderer, filter.nativeColorFilter);
976            hasModifier = true;
977        }
978
979        return hasModifier;
980    }
981
982    private boolean setupColorFilter(Paint paint) {
983        final ColorFilter filter = paint.getColorFilter();
984        if (filter != null) {
985            nSetupColorFilter(mRenderer, filter.nativeColorFilter);
986            return true;
987        }
988        return false;
989    }
990
991    private native void nSetupShader(int renderer, int shader);
992    private native void nSetupColorFilter(int renderer, int colorFilter);
993    private native void nSetupShadow(int renderer, float radius, float dx, float dy, int color);
994
995    private native void nResetModifiers(int renderer);
996}
997