GLES20Canvas.java revision 4e7b772b733593fbe25c733e95b8dcea293234b6
1e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy/*
2e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy * Copyright (C) 2010 The Android Open Source Project
3e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy *
4e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy * Licensed under the Apache License, Version 2.0 (the "License");
5e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy * you may not use this file except in compliance with the License.
6e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy * You may obtain a copy of the License at
7e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy *
8e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy *      http://www.apache.org/licenses/LICENSE-2.0
9e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy *
10e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy * Unless required by applicable law or agreed to in writing, software
11e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy * distributed under the License is distributed on an "AS IS" BASIS,
12e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy * See the License for the specific language governing permissions and
14e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy * limitations under the License.
15e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy */
16e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
17e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guypackage android.view;
18e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
19e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guyimport android.graphics.Bitmap;
20e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guyimport android.graphics.Canvas;
21db1938e0e6ef816e228c815adccebd5cb05f2aa8Romain Guyimport android.graphics.ColorFilter;
22e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guyimport android.graphics.DrawFilter;
23e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guyimport android.graphics.Matrix;
243b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guyimport android.graphics.NinePatch;
25e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guyimport android.graphics.Paint;
265ff9df658230d49e42c43586997a02d8e4dd417eRomain Guyimport android.graphics.PaintFlagsDrawFilter;
27e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guyimport android.graphics.Path;
28e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guyimport android.graphics.Picture;
29e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guyimport android.graphics.PorterDuff;
30e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guyimport android.graphics.Rect;
31e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guyimport android.graphics.RectF;
32e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guyimport android.graphics.Region;
33d27977d1a91d5a6b3cc9fa7664ac7e835e7bd895Romain Guyimport android.graphics.Shader;
34e5e0c50f7dfaccc220725c5595080e921ffda1e4Romain Guyimport android.graphics.SurfaceTexture;
35a1db574036c9bc2d397b69f8200594027e1fff16Romain Guyimport android.graphics.TemporaryBuffer;
36a1db574036c9bc2d397b69f8200594027e1fff16Romain Guyimport android.text.GraphicsOperations;
37a1db574036c9bc2d397b69f8200594027e1fff16Romain Guyimport android.text.SpannableString;
38a1db574036c9bc2d397b69f8200594027e1fff16Romain Guyimport android.text.SpannedString;
39a1db574036c9bc2d397b69f8200594027e1fff16Romain Guyimport android.text.TextUtils;
40e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
41e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy/**
42e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy * An implementation of Canvas on top of OpenGL ES 2.0.
43e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy */
44b051e895ccb696604349c6c5efe7c4747e1d1ab6Romain Guyclass GLES20Canvas extends HardwareCanvas {
45a168d7372132d6c87835878794b6ed43d0d282fdRomain Guy    // Must match modifiers used in the JNI layer
46a168d7372132d6c87835878794b6ed43d0d282fdRomain Guy    private static final int MODIFIER_NONE = 0;
47a168d7372132d6c87835878794b6ed43d0d282fdRomain Guy    private static final int MODIFIER_SHADOW = 1;
48a168d7372132d6c87835878794b6ed43d0d282fdRomain Guy    private static final int MODIFIER_SHADER = 2;
49a168d7372132d6c87835878794b6ed43d0d282fdRomain Guy    private static final int MODIFIER_COLOR_FILTER = 4;
50a168d7372132d6c87835878794b6ed43d0d282fdRomain Guy
51e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    private final boolean mOpaque;
52fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy    private int mRenderer;
53f890fab5a6715548e520a6f010a3bfe7607ce56ePatrick Dubroy
54f890fab5a6715548e520a6f010a3bfe7607ce56ePatrick Dubroy    // The native renderer will be destroyed when this object dies.
55f890fab5a6715548e520a6f010a3bfe7607ce56ePatrick Dubroy    // DO NOT overwrite this reference once it is set.
56eea60692b060737faeaa02bb30f5b79e2202b482Romain Guy    @SuppressWarnings({"unused", "FieldCanBeLocal"})
57f890fab5a6715548e520a6f010a3bfe7607ce56ePatrick Dubroy    private CanvasFinalizer mFinalizer;
58f890fab5a6715548e520a6f010a3bfe7607ce56ePatrick Dubroy
59e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    private int mWidth;
60e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    private int mHeight;
61ce0537b80087a6225273040a987414b1dd081aa0Romain Guy
626410c0aaf13c9aec606b90ee942f2ac2d98b1609Romain Guy    private float[] mPoint;
636410c0aaf13c9aec606b90ee942f2ac2d98b1609Romain Guy    private float[] mLine;
646926c72e25b8dec3dd4b84af0819fa1937ae7296Romain Guy
656410c0aaf13c9aec606b90ee942f2ac2d98b1609Romain Guy    private Rect mClipBounds;
666410c0aaf13c9aec606b90ee942f2ac2d98b1609Romain Guy    private RectF mPathBounds;
676926c72e25b8dec3dd4b84af0819fa1937ae7296Romain Guy
686926c72e25b8dec3dd4b84af0819fa1937ae7296Romain Guy    private DrawFilter mFilter;
69da8532c6f48b4c10b5e2ccb9e08690341efa1616Romain Guy
70163935113919a184122b8b3bd672ef08c8df65dcRomain Guy    ///////////////////////////////////////////////////////////////////////////
71163935113919a184122b8b3bd672ef08c8df65dcRomain Guy    // JNI
72163935113919a184122b8b3bd672ef08c8df65dcRomain Guy    ///////////////////////////////////////////////////////////////////////////
73163935113919a184122b8b3bd672ef08c8df65dcRomain Guy
74163935113919a184122b8b3bd672ef08c8df65dcRomain Guy    private static native boolean nIsAvailable();
75163935113919a184122b8b3bd672ef08c8df65dcRomain Guy    private static boolean sIsAvailable = nIsAvailable();
76163935113919a184122b8b3bd672ef08c8df65dcRomain Guy
77163935113919a184122b8b3bd672ef08c8df65dcRomain Guy    static boolean isAvailable() {
78163935113919a184122b8b3bd672ef08c8df65dcRomain Guy        return sIsAvailable;
79163935113919a184122b8b3bd672ef08c8df65dcRomain Guy    }
80e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
81e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    ///////////////////////////////////////////////////////////////////////////
82e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    // Constructors
83e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    ///////////////////////////////////////////////////////////////////////////
84b051e895ccb696604349c6c5efe7c4747e1d1ab6Romain Guy
856c319ca1275c8db892c39b48fc54864c949f9171Romain Guy    /**
866c319ca1275c8db892c39b48fc54864c949f9171Romain Guy     * Creates a canvas to render directly on screen.
876c319ca1275c8db892c39b48fc54864c949f9171Romain Guy     */
88b051e895ccb696604349c6c5efe7c4747e1d1ab6Romain Guy    GLES20Canvas(boolean translucent) {
89b051e895ccb696604349c6c5efe7c4747e1d1ab6Romain Guy        this(false, translucent);
90b051e895ccb696604349c6c5efe7c4747e1d1ab6Romain Guy    }
916c319ca1275c8db892c39b48fc54864c949f9171Romain Guy
926c319ca1275c8db892c39b48fc54864c949f9171Romain Guy    /**
936c319ca1275c8db892c39b48fc54864c949f9171Romain Guy     * Creates a canvas to render into an FBO.
946c319ca1275c8db892c39b48fc54864c949f9171Romain Guy     */
95ada830f639591b99c3e40de22b07296c7932a33fRomain Guy    GLES20Canvas(int layer, boolean translucent) {
966c319ca1275c8db892c39b48fc54864c949f9171Romain Guy        mOpaque = !translucent;
97ada830f639591b99c3e40de22b07296c7932a33fRomain Guy        mRenderer = nCreateLayerRenderer(layer);
986c319ca1275c8db892c39b48fc54864c949f9171Romain Guy        setupFinalizer();
996c319ca1275c8db892c39b48fc54864c949f9171Romain Guy    }
100e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
101f890fab5a6715548e520a6f010a3bfe7607ce56ePatrick Dubroy    protected GLES20Canvas(boolean record, boolean translucent) {
102e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy        mOpaque = !translucent;
103e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
104b051e895ccb696604349c6c5efe7c4747e1d1ab6Romain Guy        if (record) {
105162a0217563f4665da6eb183dfce0fef740f641fJeff Brown            mRenderer = nCreateDisplayListRenderer();
106b051e895ccb696604349c6c5efe7c4747e1d1ab6Romain Guy        } else {
107b051e895ccb696604349c6c5efe7c4747e1d1ab6Romain Guy            mRenderer = nCreateRenderer();
108b051e895ccb696604349c6c5efe7c4747e1d1ab6Romain Guy        }
1096c319ca1275c8db892c39b48fc54864c949f9171Romain Guy
1106c319ca1275c8db892c39b48fc54864c949f9171Romain Guy        setupFinalizer();
1116c319ca1275c8db892c39b48fc54864c949f9171Romain Guy    }
1126c319ca1275c8db892c39b48fc54864c949f9171Romain Guy
1136c319ca1275c8db892c39b48fc54864c949f9171Romain Guy    private void setupFinalizer() {
114fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy        if (mRenderer == 0) {
115fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy            throw new IllegalStateException("Could not create GLES20Canvas renderer");
1165c13d89c1332fcc499379b9064b891187b75ca32Chet Haase        } else {
117162a0217563f4665da6eb183dfce0fef740f641fJeff Brown            mFinalizer = new CanvasFinalizer(mRenderer);
118fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy        }
119e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
120b051e895ccb696604349c6c5efe7c4747e1d1ab6Romain Guy
121162a0217563f4665da6eb183dfce0fef740f641fJeff Brown    protected void resetDisplayListRenderer() {
122162a0217563f4665da6eb183dfce0fef740f641fJeff Brown        nResetDisplayListRenderer(mRenderer);
123162a0217563f4665da6eb183dfce0fef740f641fJeff Brown    }
124162a0217563f4665da6eb183dfce0fef740f641fJeff Brown
1256c319ca1275c8db892c39b48fc54864c949f9171Romain Guy    private static native int nCreateRenderer();
126ada830f639591b99c3e40de22b07296c7932a33fRomain Guy    private static native int nCreateLayerRenderer(int layer);
127162a0217563f4665da6eb183dfce0fef740f641fJeff Brown    private static native int nCreateDisplayListRenderer();
128162a0217563f4665da6eb183dfce0fef740f641fJeff Brown    private static native void nResetDisplayListRenderer(int renderer);
1295c13d89c1332fcc499379b9064b891187b75ca32Chet Haase    private static native void nDestroyRenderer(int renderer);
1305c13d89c1332fcc499379b9064b891187b75ca32Chet Haase
131162a0217563f4665da6eb183dfce0fef740f641fJeff Brown    private static final class CanvasFinalizer {
132162a0217563f4665da6eb183dfce0fef740f641fJeff Brown        private final int mRenderer;
1335977baa1fa24125c148a72699b53e62abaf08960Chet Haase
134162a0217563f4665da6eb183dfce0fef740f641fJeff Brown        public CanvasFinalizer(int renderer) {
135f890fab5a6715548e520a6f010a3bfe7607ce56ePatrick Dubroy            mRenderer = renderer;
1365c13d89c1332fcc499379b9064b891187b75ca32Chet Haase        }
1375c13d89c1332fcc499379b9064b891187b75ca32Chet Haase
1385c13d89c1332fcc499379b9064b891187b75ca32Chet Haase        @Override
139f890fab5a6715548e520a6f010a3bfe7607ce56ePatrick Dubroy        protected void finalize() throws Throwable {
140171c592f0b7066acf279863c8a52ddabea49d3dbRomain Guy            try {
141162a0217563f4665da6eb183dfce0fef740f641fJeff Brown                nDestroyRenderer(mRenderer);
142171c592f0b7066acf279863c8a52ddabea49d3dbRomain Guy            } finally {
143171c592f0b7066acf279863c8a52ddabea49d3dbRomain Guy                super.finalize();
144171c592f0b7066acf279863c8a52ddabea49d3dbRomain Guy            }
145e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy        }
146e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
147ce0537b80087a6225273040a987414b1dd081aa0Romain Guy
148ef35927abcd089652f87a985dd6dde7afde58b92Romain Guy    @Override
149ef35927abcd089652f87a985dd6dde7afde58b92Romain Guy    public void setName(String name) {
150ef35927abcd089652f87a985dd6dde7afde58b92Romain Guy        super.setName(name);
151ef35927abcd089652f87a985dd6dde7afde58b92Romain Guy        nSetName(mRenderer, name);
152ef35927abcd089652f87a985dd6dde7afde58b92Romain Guy    }
153ef35927abcd089652f87a985dd6dde7afde58b92Romain Guy
154ef35927abcd089652f87a985dd6dde7afde58b92Romain Guy    private static native void nSetName(int renderer, String name);
155ef35927abcd089652f87a985dd6dde7afde58b92Romain Guy
156e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    ///////////////////////////////////////////////////////////////////////////
1576c319ca1275c8db892c39b48fc54864c949f9171Romain Guy    // Hardware layers
1586c319ca1275c8db892c39b48fc54864c949f9171Romain Guy    ///////////////////////////////////////////////////////////////////////////
15911cb642756093a4af901b1525375b1eb2b5c3e2bRomain Guy
16011cb642756093a4af901b1525375b1eb2b5c3e2bRomain Guy    @Override
16111cb642756093a4af901b1525375b1eb2b5c3e2bRomain Guy    void pushLayerUpdate(HardwareLayer layer) {
16211cb642756093a4af901b1525375b1eb2b5c3e2bRomain Guy        nPushLayerUpdate(mRenderer, ((GLES20RenderLayer) layer).mLayer);
16311cb642756093a4af901b1525375b1eb2b5c3e2bRomain Guy    }
16411cb642756093a4af901b1525375b1eb2b5c3e2bRomain Guy
16511cb642756093a4af901b1525375b1eb2b5c3e2bRomain Guy    @Override
166e93482f5eac3df581d57e64c2a771a96aa868585Romain Guy    void cancelLayerUpdate(HardwareLayer layer) {
167e93482f5eac3df581d57e64c2a771a96aa868585Romain Guy        nCancelLayerUpdate(mRenderer, ((GLES20RenderLayer) layer).mLayer);
168e93482f5eac3df581d57e64c2a771a96aa868585Romain Guy    }
169e93482f5eac3df581d57e64c2a771a96aa868585Romain Guy
170e93482f5eac3df581d57e64c2a771a96aa868585Romain Guy    @Override
171405436021da156fbe3c5d4de48bdefa564cf7fc0Romain Guy    void flushLayerUpdates() {
172405436021da156fbe3c5d4de48bdefa564cf7fc0Romain Guy        nFlushLayerUpdates(mRenderer);
173405436021da156fbe3c5d4de48bdefa564cf7fc0Romain Guy    }
174405436021da156fbe3c5d4de48bdefa564cf7fc0Romain Guy
175405436021da156fbe3c5d4de48bdefa564cf7fc0Romain Guy    @Override
17611cb642756093a4af901b1525375b1eb2b5c3e2bRomain Guy    void clearLayerUpdates() {
17711cb642756093a4af901b1525375b1eb2b5c3e2bRomain Guy        nClearLayerUpdates(mRenderer);
17811cb642756093a4af901b1525375b1eb2b5c3e2bRomain Guy    }
17911cb642756093a4af901b1525375b1eb2b5c3e2bRomain Guy
180a9489274d67b540804aafb587a226f7c2ae4464dRomain Guy    static native int nCreateTextureLayer(boolean opaque, int[] layerInfo);
181ada830f639591b99c3e40de22b07296c7932a33fRomain Guy    static native int nCreateLayer(int width, int height, boolean isOpaque, int[] layerInfo);
182603f6de35f21d74ae242d52d501f4f5c25ff4f4cChet Haase    static native boolean nResizeLayer(int layerId, int width, int height, int[] layerInfo);
183846a533945576e5cb1a66529ca3a52d71749f04fRomain Guy    static native void nSetOpaqueLayer(int layerId, boolean isOpaque);
184d15ebf25c595b855f6978d0600218e3ea5f31e92Chet Haase    static native void nSetLayerPaint(int layerId, int nativePaint);
185d15ebf25c595b855f6978d0600218e3ea5f31e92Chet Haase    static native void nSetLayerColorFilter(int layerId, int nativeColorFilter);
186a9489274d67b540804aafb587a226f7c2ae4464dRomain Guy    static native void nUpdateTextureLayer(int layerId, int width, int height, boolean opaque,
187a9489274d67b540804aafb587a226f7c2ae4464dRomain Guy            SurfaceTexture surface);
188ef09a210dd6ea481158b7028ec2424a7f5769ed2Romain Guy    static native void nClearLayerTexture(int layerId);
189302a9df1d50373c82923bb84ff665dfce584fb22Romain Guy    static native void nSetTextureLayerTransform(int layerId, int matrix);
190ada830f639591b99c3e40de22b07296c7932a33fRomain Guy    static native void nDestroyLayer(int layerId);
191ada830f639591b99c3e40de22b07296c7932a33fRomain Guy    static native void nDestroyLayerDeferred(int layerId);
1922bf68f063b0077ddef6ebfe54f2ae5e063c2c229Romain Guy    static native void nUpdateRenderLayer(int layerId, int renderer, int displayList,
1932bf68f063b0077ddef6ebfe54f2ae5e063c2c229Romain Guy            int left, int top, int right, int bottom);
19477a811610f99e21da7f88dafef60d09f345d0506Romain Guy    static native boolean nCopyLayer(int layerId, int bitmap);
19557066eb64c9a190d1afc87bb060bbb2d31e5b86cRomain Guy
19611cb642756093a4af901b1525375b1eb2b5c3e2bRomain Guy    private static native void nClearLayerUpdates(int renderer);
197405436021da156fbe3c5d4de48bdefa564cf7fc0Romain Guy    private static native void nFlushLayerUpdates(int renderer);
19811cb642756093a4af901b1525375b1eb2b5c3e2bRomain Guy    private static native void nPushLayerUpdate(int renderer, int layer);
199e93482f5eac3df581d57e64c2a771a96aa868585Romain Guy    private static native void nCancelLayerUpdate(int renderer, int layer);
20011cb642756093a4af901b1525375b1eb2b5c3e2bRomain Guy
2016c319ca1275c8db892c39b48fc54864c949f9171Romain Guy    ///////////////////////////////////////////////////////////////////////////
202e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    // Canvas management
203e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    ///////////////////////////////////////////////////////////////////////////
204e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
205e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
206e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public boolean isOpaque() {
207e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy        return mOpaque;
208e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
209e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
210e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
211e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public int getWidth() {
212e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy        return mWidth;
213e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
214e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
215e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
216e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public int getHeight() {
217e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy        return mHeight;
218e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
219e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
220f61970fc79e9c5cf340fa942597628242361864aRomain Guy    @Override
221f61970fc79e9c5cf340fa942597628242361864aRomain Guy    public int getMaximumBitmapWidth() {
222f61970fc79e9c5cf340fa942597628242361864aRomain Guy        return nGetMaximumTextureWidth();
223f61970fc79e9c5cf340fa942597628242361864aRomain Guy    }
224f61970fc79e9c5cf340fa942597628242361864aRomain Guy
225f61970fc79e9c5cf340fa942597628242361864aRomain Guy    @Override
226f61970fc79e9c5cf340fa942597628242361864aRomain Guy    public int getMaximumBitmapHeight() {
227f61970fc79e9c5cf340fa942597628242361864aRomain Guy        return nGetMaximumTextureHeight();
228f61970fc79e9c5cf340fa942597628242361864aRomain Guy    }
229f61970fc79e9c5cf340fa942597628242361864aRomain Guy
230f61970fc79e9c5cf340fa942597628242361864aRomain Guy    private static native int nGetMaximumTextureWidth();
231530041d3191ce817832a0108514617768e43cda6Romain Guy    private static native int nGetMaximumTextureHeight();
232f61970fc79e9c5cf340fa942597628242361864aRomain Guy
2332bf68f063b0077ddef6ebfe54f2ae5e063c2c229Romain Guy    /**
2342bf68f063b0077ddef6ebfe54f2ae5e063c2c229Romain Guy     * Returns the native OpenGLRenderer object.
2352bf68f063b0077ddef6ebfe54f2ae5e063c2c229Romain Guy     */
2362bf68f063b0077ddef6ebfe54f2ae5e063c2c229Romain Guy    int getRenderer() {
2372bf68f063b0077ddef6ebfe54f2ae5e063c2c229Romain Guy        return mRenderer;
2382bf68f063b0077ddef6ebfe54f2ae5e063c2c229Romain Guy    }
2392bf68f063b0077ddef6ebfe54f2ae5e063c2c229Romain Guy
240e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    ///////////////////////////////////////////////////////////////////////////
241e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    // Setup
242e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    ///////////////////////////////////////////////////////////////////////////
243e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
244e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
245e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public void setViewport(int width, int height) {
246e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy        mWidth = width;
247e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy        mHeight = height;
248e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
249e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy        nSetViewport(mRenderer, width, height);
250e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
251e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
2527d7b5490a0b0763e831b31bc11f17d8159b5914aRomain Guy    private static native void nSetViewport(int renderer, int width, int height);
253e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
254b051e895ccb696604349c6c5efe7c4747e1d1ab6Romain Guy    @Override
25544b2fe3fc114ee5f7273c6b0fee2cc999bf244a2Chet Haase    public int onPreDraw(Rect dirty) {
2567d7b5490a0b0763e831b31bc11f17d8159b5914aRomain Guy        if (dirty != null) {
25744b2fe3fc114ee5f7273c6b0fee2cc999bf244a2Chet Haase            return nPrepareDirty(mRenderer, dirty.left, dirty.top, dirty.right, dirty.bottom,
25844b2fe3fc114ee5f7273c6b0fee2cc999bf244a2Chet Haase                    mOpaque);
2597d7b5490a0b0763e831b31bc11f17d8159b5914aRomain Guy        } else {
26044b2fe3fc114ee5f7273c6b0fee2cc999bf244a2Chet Haase            return nPrepare(mRenderer, mOpaque);
2617d7b5490a0b0763e831b31bc11f17d8159b5914aRomain Guy        }
262e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
263b025b9c8b4efefadb01937db61a1f8ee7d2452bfRomain Guy
26444b2fe3fc114ee5f7273c6b0fee2cc999bf244a2Chet Haase    private static native int nPrepare(int renderer, boolean opaque);
26544b2fe3fc114ee5f7273c6b0fee2cc999bf244a2Chet Haase    private static native int nPrepareDirty(int renderer, int left, int top, int right, int bottom,
2667d7b5490a0b0763e831b31bc11f17d8159b5914aRomain Guy            boolean opaque);
267e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
268b051e895ccb696604349c6c5efe7c4747e1d1ab6Romain Guy    @Override
269b35ab7b72967adcfd01cec483a705dafe8b951d1Gilles Debunne    public void onPostDraw() {
270b025b9c8b4efefadb01937db61a1f8ee7d2452bfRomain Guy        nFinish(mRenderer);
271b025b9c8b4efefadb01937db61a1f8ee7d2452bfRomain Guy    }
2729ace8f5e79e76893fe4ca9e4d10f6c4056330485Romain Guy
2737d7b5490a0b0763e831b31bc11f17d8159b5914aRomain Guy    private static native void nFinish(int renderer);
274b025b9c8b4efefadb01937db61a1f8ee7d2452bfRomain Guy
275530041d3191ce817832a0108514617768e43cda6Romain Guy    /**
276530041d3191ce817832a0108514617768e43cda6Romain Guy     * Returns the size of the stencil buffer required by the underlying
277530041d3191ce817832a0108514617768e43cda6Romain Guy     * implementation.
278530041d3191ce817832a0108514617768e43cda6Romain Guy     *
279530041d3191ce817832a0108514617768e43cda6Romain Guy     * @return The minimum number of bits the stencil buffer must. Always >= 0.
280530041d3191ce817832a0108514617768e43cda6Romain Guy     *
281530041d3191ce817832a0108514617768e43cda6Romain Guy     * @hide
282530041d3191ce817832a0108514617768e43cda6Romain Guy     */
283530041d3191ce817832a0108514617768e43cda6Romain Guy    public static int getStencilSize() {
284530041d3191ce817832a0108514617768e43cda6Romain Guy        return nGetStencilSize();
285530041d3191ce817832a0108514617768e43cda6Romain Guy    }
286530041d3191ce817832a0108514617768e43cda6Romain Guy
287530041d3191ce817832a0108514617768e43cda6Romain Guy    private static native int nGetStencilSize();
288530041d3191ce817832a0108514617768e43cda6Romain Guy
28978dd96d5af20f489f0e8b288617d57774ec284f7Romain Guy    void setCountOverdrawEnabled(boolean enabled) {
29078dd96d5af20f489f0e8b288617d57774ec284f7Romain Guy        nSetCountOverdrawEnabled(mRenderer, enabled);
29178dd96d5af20f489f0e8b288617d57774ec284f7Romain Guy    }
29278dd96d5af20f489f0e8b288617d57774ec284f7Romain Guy
29378dd96d5af20f489f0e8b288617d57774ec284f7Romain Guy    static native void nSetCountOverdrawEnabled(int renderer, boolean enabled);
29478dd96d5af20f489f0e8b288617d57774ec284f7Romain Guy
29578dd96d5af20f489f0e8b288617d57774ec284f7Romain Guy    float getOverdraw() {
29678dd96d5af20f489f0e8b288617d57774ec284f7Romain Guy        return nGetOverdraw(mRenderer);
29778dd96d5af20f489f0e8b288617d57774ec284f7Romain Guy    }
29878dd96d5af20f489f0e8b288617d57774ec284f7Romain Guy
29978dd96d5af20f489f0e8b288617d57774ec284f7Romain Guy    static native float nGetOverdraw(int renderer);
30078dd96d5af20f489f0e8b288617d57774ec284f7Romain Guy
301530041d3191ce817832a0108514617768e43cda6Romain Guy    ///////////////////////////////////////////////////////////////////////////
302530041d3191ce817832a0108514617768e43cda6Romain Guy    // Functor
303530041d3191ce817832a0108514617768e43cda6Romain Guy    ///////////////////////////////////////////////////////////////////////////
304530041d3191ce817832a0108514617768e43cda6Romain Guy
305da8532c6f48b4c10b5e2ccb9e08690341efa1616Romain Guy    @Override
3066554943a1dd6854c0f4976900956e556767b49e1Romain Guy    public int callDrawGLFunction(int drawGLFunction) {
307daf98e941e140e8739458126640183b9f296a2abChet Haase        return nCallDrawGLFunction(mRenderer, drawGLFunction);
308daf98e941e140e8739458126640183b9f296a2abChet Haase    }
309daf98e941e140e8739458126640183b9f296a2abChet Haase
3106554943a1dd6854c0f4976900956e556767b49e1Romain Guy    private static native int nCallDrawGLFunction(int renderer, int drawGLFunction);
311daf98e941e140e8739458126640183b9f296a2abChet Haase
3128f3b8e32993d190a26c70c839a63d8ce4c3b16d9Romain Guy    @Override
3138f3b8e32993d190a26c70c839a63d8ce4c3b16d9Romain Guy    public int invokeFunctors(Rect dirty) {
3148f3b8e32993d190a26c70c839a63d8ce4c3b16d9Romain Guy        return nInvokeFunctors(mRenderer, dirty);
3158f3b8e32993d190a26c70c839a63d8ce4c3b16d9Romain Guy    }
3168f3b8e32993d190a26c70c839a63d8ce4c3b16d9Romain Guy
3178f3b8e32993d190a26c70c839a63d8ce4c3b16d9Romain Guy    private static native int nInvokeFunctors(int renderer, Rect dirty);
3188f3b8e32993d190a26c70c839a63d8ce4c3b16d9Romain Guy
319ba6be8a62dcdb3ffd210cd36b9af4e3a658eac47Romain Guy    @Override
320ba6be8a62dcdb3ffd210cd36b9af4e3a658eac47Romain Guy    public void detachFunctor(int functor) {
321ba6be8a62dcdb3ffd210cd36b9af4e3a658eac47Romain Guy        nDetachFunctor(mRenderer, functor);
322ba6be8a62dcdb3ffd210cd36b9af4e3a658eac47Romain Guy    }
323ba6be8a62dcdb3ffd210cd36b9af4e3a658eac47Romain Guy
324ba6be8a62dcdb3ffd210cd36b9af4e3a658eac47Romain Guy    private static native void nDetachFunctor(int renderer, int functor);
325ba6be8a62dcdb3ffd210cd36b9af4e3a658eac47Romain Guy
326ba6be8a62dcdb3ffd210cd36b9af4e3a658eac47Romain Guy    @Override
327ba6be8a62dcdb3ffd210cd36b9af4e3a658eac47Romain Guy    public void attachFunctor(int functor) {
328ba6be8a62dcdb3ffd210cd36b9af4e3a658eac47Romain Guy        nAttachFunctor(mRenderer, functor);
329ba6be8a62dcdb3ffd210cd36b9af4e3a658eac47Romain Guy    }
330ba6be8a62dcdb3ffd210cd36b9af4e3a658eac47Romain Guy
331ba6be8a62dcdb3ffd210cd36b9af4e3a658eac47Romain Guy    private static native void nAttachFunctor(int renderer, int functor);
332ba6be8a62dcdb3ffd210cd36b9af4e3a658eac47Romain Guy
333bdf7609867a3f886455c51dba91623a86cceb6e2Romain Guy    ///////////////////////////////////////////////////////////////////////////
334bdf7609867a3f886455c51dba91623a86cceb6e2Romain Guy    // Memory
335bdf7609867a3f886455c51dba91623a86cceb6e2Romain Guy    ///////////////////////////////////////////////////////////////////////////
336bdf7609867a3f886455c51dba91623a86cceb6e2Romain Guy
337bdf7609867a3f886455c51dba91623a86cceb6e2Romain Guy    /**
3386d7475d666baefaa3ba9f0dcee25238739454241Romain Guy     * Must match Caches::FlushMode values
3396d7475d666baefaa3ba9f0dcee25238739454241Romain Guy     *
340bdf7609867a3f886455c51dba91623a86cceb6e2Romain Guy     * @see #flushCaches(int)
341bdf7609867a3f886455c51dba91623a86cceb6e2Romain Guy     */
3423b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy    static final int FLUSH_CACHES_LAYERS = 0;
3436d7475d666baefaa3ba9f0dcee25238739454241Romain Guy
3446d7475d666baefaa3ba9f0dcee25238739454241Romain Guy    /**
3456d7475d666baefaa3ba9f0dcee25238739454241Romain Guy     * Must match Caches::FlushMode values
3466d7475d666baefaa3ba9f0dcee25238739454241Romain Guy     *
3476d7475d666baefaa3ba9f0dcee25238739454241Romain Guy     * @see #flushCaches(int)
3486d7475d666baefaa3ba9f0dcee25238739454241Romain Guy     */
3493b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy    static final int FLUSH_CACHES_MODERATE = 1;
350bdf7609867a3f886455c51dba91623a86cceb6e2Romain Guy
351bdf7609867a3f886455c51dba91623a86cceb6e2Romain Guy    /**
3526d7475d666baefaa3ba9f0dcee25238739454241Romain Guy     * Must match Caches::FlushMode values
3536d7475d666baefaa3ba9f0dcee25238739454241Romain Guy     *
354bdf7609867a3f886455c51dba91623a86cceb6e2Romain Guy     * @see #flushCaches(int)
355bdf7609867a3f886455c51dba91623a86cceb6e2Romain Guy     */
3563b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy    static final int FLUSH_CACHES_FULL = 2;
357bdf7609867a3f886455c51dba91623a86cceb6e2Romain Guy
358bdf7609867a3f886455c51dba91623a86cceb6e2Romain Guy    /**
359bdf7609867a3f886455c51dba91623a86cceb6e2Romain Guy     * Flush caches to reclaim as much memory as possible. The amount of memory
360bdf7609867a3f886455c51dba91623a86cceb6e2Romain Guy     * to reclaim is indicate by the level parameter.
361bdf7609867a3f886455c51dba91623a86cceb6e2Romain Guy     *
362bdf7609867a3f886455c51dba91623a86cceb6e2Romain Guy     * The level can be one of {@link #FLUSH_CACHES_MODERATE} or
363bdf7609867a3f886455c51dba91623a86cceb6e2Romain Guy     * {@link #FLUSH_CACHES_FULL}.
364bdf7609867a3f886455c51dba91623a86cceb6e2Romain Guy     *
365bdf7609867a3f886455c51dba91623a86cceb6e2Romain Guy     * @param level Hint about the amount of memory to reclaim
366bdf7609867a3f886455c51dba91623a86cceb6e2Romain Guy     */
3673b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy    static void flushCaches(int level) {
368bdf7609867a3f886455c51dba91623a86cceb6e2Romain Guy        nFlushCaches(level);
369bdf7609867a3f886455c51dba91623a86cceb6e2Romain Guy    }
370bdf7609867a3f886455c51dba91623a86cceb6e2Romain Guy
371bdf7609867a3f886455c51dba91623a86cceb6e2Romain Guy    private static native void nFlushCaches(int level);
372bdf7609867a3f886455c51dba91623a86cceb6e2Romain Guy
3738ff6b9ebeeb24a6161ec6098e6bfdf8790ee5695Romain Guy    /**
3748ff6b9ebeeb24a6161ec6098e6bfdf8790ee5695Romain Guy     * Release all resources associated with the underlying caches. This should
3758ff6b9ebeeb24a6161ec6098e6bfdf8790ee5695Romain Guy     * only be called after a full flushCaches().
3768ff6b9ebeeb24a6161ec6098e6bfdf8790ee5695Romain Guy     *
3778ff6b9ebeeb24a6161ec6098e6bfdf8790ee5695Romain Guy     * @hide
3788ff6b9ebeeb24a6161ec6098e6bfdf8790ee5695Romain Guy     */
3793b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy    static void terminateCaches() {
3808ff6b9ebeeb24a6161ec6098e6bfdf8790ee5695Romain Guy        nTerminateCaches();
3818ff6b9ebeeb24a6161ec6098e6bfdf8790ee5695Romain Guy    }
3828ff6b9ebeeb24a6161ec6098e6bfdf8790ee5695Romain Guy
3838ff6b9ebeeb24a6161ec6098e6bfdf8790ee5695Romain Guy    private static native void nTerminateCaches();
3848ff6b9ebeeb24a6161ec6098e6bfdf8790ee5695Romain Guy
3853b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy    static boolean initCaches() {
3863b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy        return nInitCaches();
3878ff6b9ebeeb24a6161ec6098e6bfdf8790ee5695Romain Guy    }
3888ff6b9ebeeb24a6161ec6098e6bfdf8790ee5695Romain Guy
3893b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy    private static native boolean nInitCaches();
3903b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy
3913b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy    ///////////////////////////////////////////////////////////////////////////
3923b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy    // Atlas
3933b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy    ///////////////////////////////////////////////////////////////////////////
3943b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy
3953b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy    static void initAtlas(GraphicBuffer buffer, int[] map) {
3963b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy        nInitAtlas(buffer, map, map.length);
3973b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy    }
3983b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy
3993b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy    private static native void nInitAtlas(GraphicBuffer buffer, int[] map, int count);
4003b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy
401b051e895ccb696604349c6c5efe7c4747e1d1ab6Romain Guy    ///////////////////////////////////////////////////////////////////////////
402b051e895ccb696604349c6c5efe7c4747e1d1ab6Romain Guy    // Display list
403b051e895ccb696604349c6c5efe7c4747e1d1ab6Romain Guy    ///////////////////////////////////////////////////////////////////////////
404b051e895ccb696604349c6c5efe7c4747e1d1ab6Romain Guy
405162a0217563f4665da6eb183dfce0fef740f641fJeff Brown    int getDisplayList(int displayList) {
406162a0217563f4665da6eb183dfce0fef740f641fJeff Brown        return nGetDisplayList(mRenderer, displayList);
407b051e895ccb696604349c6c5efe7c4747e1d1ab6Romain Guy    }
408b051e895ccb696604349c6c5efe7c4747e1d1ab6Romain Guy
409162a0217563f4665da6eb183dfce0fef740f641fJeff Brown    private static native int nGetDisplayList(int renderer, int displayList);
41065b345fa22b878e141b8fd8ece9c208df00fa40fRomain Guy
41152036b19a5f82bc4d75cfcbff99c65df8d25a99bRomain Guy    @Override
41252036b19a5f82bc4d75cfcbff99c65df8d25a99bRomain Guy    void outputDisplayList(DisplayList displayList) {
41352036b19a5f82bc4d75cfcbff99c65df8d25a99bRomain Guy        nOutputDisplayList(mRenderer, ((GLES20DisplayList) displayList).getNativeDisplayList());
41413631f3da855f200a151e7837ed9f6b079622b58Romain Guy    }
41513631f3da855f200a151e7837ed9f6b079622b58Romain Guy
41652036b19a5f82bc4d75cfcbff99c65df8d25a99bRomain Guy    private static native void nOutputDisplayList(int renderer, int displayList);
41713631f3da855f200a151e7837ed9f6b079622b58Romain Guy
418b051e895ccb696604349c6c5efe7c4747e1d1ab6Romain Guy    @Override
4191271e2cc80b01d577e9db339459ef0222bb9320dChet Haase    public int drawDisplayList(DisplayList displayList, Rect dirty, int flags) {
42033f6beb10f98e8ba96250e284876d607055d278dRomain Guy        return nDrawDisplayList(mRenderer, ((GLES20DisplayList) displayList).getNativeDisplayList(),
4211271e2cc80b01d577e9db339459ef0222bb9320dChet Haase                dirty, flags);
422b051e895ccb696604349c6c5efe7c4747e1d1ab6Romain Guy    }
423b051e895ccb696604349c6c5efe7c4747e1d1ab6Romain Guy
4246554943a1dd6854c0f4976900956e556767b49e1Romain Guy    private static native int nDrawDisplayList(int renderer, int displayList,
4251271e2cc80b01d577e9db339459ef0222bb9320dChet Haase            Rect dirty, int flags);
426da8532c6f48b4c10b5e2ccb9e08690341efa1616Romain Guy
427e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    ///////////////////////////////////////////////////////////////////////////
4286c319ca1275c8db892c39b48fc54864c949f9171Romain Guy    // Hardware layer
4296c319ca1275c8db892c39b48fc54864c949f9171Romain Guy    ///////////////////////////////////////////////////////////////////////////
4306c319ca1275c8db892c39b48fc54864c949f9171Romain Guy
431ada830f639591b99c3e40de22b07296c7932a33fRomain Guy    void drawHardwareLayer(HardwareLayer layer, float x, float y, Paint paint) {
432a4e16c58c9e3c983251e0475125a2a6f5bec2dbfChris Craik        layer.setLayerPaint(paint);
433a4e16c58c9e3c983251e0475125a2a6f5bec2dbfChris Craik
4346c319ca1275c8db892c39b48fc54864c949f9171Romain Guy        final GLES20Layer glLayer = (GLES20Layer) layer;
435a4e16c58c9e3c983251e0475125a2a6f5bec2dbfChris Craik        nDrawLayer(mRenderer, glLayer.getLayer(), x, y);
4366c319ca1275c8db892c39b48fc54864c949f9171Romain Guy    }
4376c319ca1275c8db892c39b48fc54864c949f9171Romain Guy
438a4e16c58c9e3c983251e0475125a2a6f5bec2dbfChris Craik    private static native void nDrawLayer(int renderer, int layer, float x, float y);
439aa6c24c21c727a196451332448d4e3b11a80be69Romain Guy
4406c319ca1275c8db892c39b48fc54864c949f9171Romain Guy    void interrupt() {
4416c319ca1275c8db892c39b48fc54864c949f9171Romain Guy        nInterrupt(mRenderer);
4426c319ca1275c8db892c39b48fc54864c949f9171Romain Guy    }
4436c319ca1275c8db892c39b48fc54864c949f9171Romain Guy
4446c319ca1275c8db892c39b48fc54864c949f9171Romain Guy    void resume() {
4456c319ca1275c8db892c39b48fc54864c949f9171Romain Guy        nResume(mRenderer);
4466c319ca1275c8db892c39b48fc54864c949f9171Romain Guy    }
4476c319ca1275c8db892c39b48fc54864c949f9171Romain Guy
4487d7b5490a0b0763e831b31bc11f17d8159b5914aRomain Guy    private static native void nInterrupt(int renderer);
4497d7b5490a0b0763e831b31bc11f17d8159b5914aRomain Guy    private static native void nResume(int renderer);
4506c319ca1275c8db892c39b48fc54864c949f9171Romain Guy
4516c319ca1275c8db892c39b48fc54864c949f9171Romain Guy    ///////////////////////////////////////////////////////////////////////////
4526410c0aaf13c9aec606b90ee942f2ac2d98b1609Romain Guy    // Support
4536410c0aaf13c9aec606b90ee942f2ac2d98b1609Romain Guy    ///////////////////////////////////////////////////////////////////////////
4546410c0aaf13c9aec606b90ee942f2ac2d98b1609Romain Guy
4556410c0aaf13c9aec606b90ee942f2ac2d98b1609Romain Guy    private Rect getInternalClipBounds() {
4566410c0aaf13c9aec606b90ee942f2ac2d98b1609Romain Guy        if (mClipBounds == null) mClipBounds = new Rect();
4576410c0aaf13c9aec606b90ee942f2ac2d98b1609Romain Guy        return mClipBounds;
4586410c0aaf13c9aec606b90ee942f2ac2d98b1609Romain Guy    }
4596410c0aaf13c9aec606b90ee942f2ac2d98b1609Romain Guy
4606410c0aaf13c9aec606b90ee942f2ac2d98b1609Romain Guy
4616410c0aaf13c9aec606b90ee942f2ac2d98b1609Romain Guy    private RectF getPathBounds() {
4626410c0aaf13c9aec606b90ee942f2ac2d98b1609Romain Guy        if (mPathBounds == null) mPathBounds = new RectF();
4636410c0aaf13c9aec606b90ee942f2ac2d98b1609Romain Guy        return mPathBounds;
4646410c0aaf13c9aec606b90ee942f2ac2d98b1609Romain Guy    }
4656410c0aaf13c9aec606b90ee942f2ac2d98b1609Romain Guy
4666410c0aaf13c9aec606b90ee942f2ac2d98b1609Romain Guy    private float[] getPointStorage() {
4676410c0aaf13c9aec606b90ee942f2ac2d98b1609Romain Guy        if (mPoint == null) mPoint = new float[2];
4686410c0aaf13c9aec606b90ee942f2ac2d98b1609Romain Guy        return mPoint;
4696410c0aaf13c9aec606b90ee942f2ac2d98b1609Romain Guy    }
4706410c0aaf13c9aec606b90ee942f2ac2d98b1609Romain Guy
4716410c0aaf13c9aec606b90ee942f2ac2d98b1609Romain Guy    private float[] getLineStorage() {
4726410c0aaf13c9aec606b90ee942f2ac2d98b1609Romain Guy        if (mLine == null) mLine = new float[4];
4736410c0aaf13c9aec606b90ee942f2ac2d98b1609Romain Guy        return mLine;
4746410c0aaf13c9aec606b90ee942f2ac2d98b1609Romain Guy    }
4756410c0aaf13c9aec606b90ee942f2ac2d98b1609Romain Guy
4766410c0aaf13c9aec606b90ee942f2ac2d98b1609Romain Guy    ///////////////////////////////////////////////////////////////////////////
477e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    // Clipping
478e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    ///////////////////////////////////////////////////////////////////////////
479e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
480e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
481e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public boolean clipPath(Path path) {
482735738c4ddf3229caa5f6e634bf591953ac29944Romain Guy        return nClipPath(mRenderer, path.mNativePath, Region.Op.INTERSECT.nativeInt);
483e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
484e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
485e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
486e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public boolean clipPath(Path path, Region.Op op) {
487735738c4ddf3229caa5f6e634bf591953ac29944Romain Guy        return nClipPath(mRenderer, path.mNativePath, op.nativeInt);
488e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
489e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
490735738c4ddf3229caa5f6e634bf591953ac29944Romain Guy    private static native boolean nClipPath(int renderer, int path, int op);
491735738c4ddf3229caa5f6e634bf591953ac29944Romain Guy
492e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
493e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public boolean clipRect(float left, float top, float right, float bottom) {
494079ba2c85b15e882629b8d188f5fbdb42f7f8eeaRomain Guy        return nClipRect(mRenderer, left, top, right, bottom, Region.Op.INTERSECT.nativeInt);
495e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
496bb9524b6bdddc7ac77d8628daa8b366b8a7be4a4Romain Guy
4977d7b5490a0b0763e831b31bc11f17d8159b5914aRomain Guy    private static native boolean nClipRect(int renderer, float left, float top,
498079ba2c85b15e882629b8d188f5fbdb42f7f8eeaRomain Guy            float right, float bottom, int op);
499e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
500e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
501e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public boolean clipRect(float left, float top, float right, float bottom, Region.Op op) {
502079ba2c85b15e882629b8d188f5fbdb42f7f8eeaRomain Guy        return nClipRect(mRenderer, left, top, right, bottom, op.nativeInt);
503e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
504e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
505e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
506e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public boolean clipRect(int left, int top, int right, int bottom) {
507daf98e941e140e8739458126640183b9f296a2abChet Haase        return nClipRect(mRenderer, left, top, right, bottom, Region.Op.INTERSECT.nativeInt);
508e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
509bb9524b6bdddc7ac77d8628daa8b366b8a7be4a4Romain Guy
510735738c4ddf3229caa5f6e634bf591953ac29944Romain Guy    private static native boolean nClipRect(int renderer, int left, int top,
511735738c4ddf3229caa5f6e634bf591953ac29944Romain Guy            int right, int bottom, int op);
512e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
513e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
514e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public boolean clipRect(Rect rect) {
515079ba2c85b15e882629b8d188f5fbdb42f7f8eeaRomain Guy        return nClipRect(mRenderer, rect.left, rect.top, rect.right, rect.bottom,
516079ba2c85b15e882629b8d188f5fbdb42f7f8eeaRomain Guy                Region.Op.INTERSECT.nativeInt);
517e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
518e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
519e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
520e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public boolean clipRect(Rect rect, Region.Op op) {
521079ba2c85b15e882629b8d188f5fbdb42f7f8eeaRomain Guy        return nClipRect(mRenderer, rect.left, rect.top, rect.right, rect.bottom, op.nativeInt);
522e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
523e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
524e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
525e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public boolean clipRect(RectF rect) {
526079ba2c85b15e882629b8d188f5fbdb42f7f8eeaRomain Guy        return nClipRect(mRenderer, rect.left, rect.top, rect.right, rect.bottom,
527079ba2c85b15e882629b8d188f5fbdb42f7f8eeaRomain Guy                Region.Op.INTERSECT.nativeInt);
528e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
529e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
530e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
531e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public boolean clipRect(RectF rect, Region.Op op) {
532079ba2c85b15e882629b8d188f5fbdb42f7f8eeaRomain Guy        return nClipRect(mRenderer, rect.left, rect.top, rect.right, rect.bottom, op.nativeInt);
533e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
534e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
535e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
536e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public boolean clipRegion(Region region) {
537735738c4ddf3229caa5f6e634bf591953ac29944Romain Guy        return nClipRegion(mRenderer, region.mNativeRegion, Region.Op.INTERSECT.nativeInt);
538e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
539e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
540e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
541e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public boolean clipRegion(Region region, Region.Op op) {
542735738c4ddf3229caa5f6e634bf591953ac29944Romain Guy        return nClipRegion(mRenderer, region.mNativeRegion, op.nativeInt);
543e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
544e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
545735738c4ddf3229caa5f6e634bf591953ac29944Romain Guy    private static native boolean nClipRegion(int renderer, int region, int op);
546735738c4ddf3229caa5f6e634bf591953ac29944Romain Guy
547e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
548e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public boolean getClipBounds(Rect bounds) {
5499d5316e3f56d138504565ff311145ac01621dff4Romain Guy        return nGetClipBounds(mRenderer, bounds);
550e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
551e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
5527d7b5490a0b0763e831b31bc11f17d8159b5914aRomain Guy    private static native boolean nGetClipBounds(int renderer, Rect bounds);
5539d5316e3f56d138504565ff311145ac01621dff4Romain Guy
554e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
555e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public boolean quickReject(float left, float top, float right, float bottom, EdgeType type) {
556ca79cf69d09efa0c327e9b1237d86a119aea5da7Derek Sollenberger        return nQuickReject(mRenderer, left, top, right, bottom);
557e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
558c7d53494f1fbd9f9d74af89053ff9fdb1ccbac6cRomain Guy
5597d7b5490a0b0763e831b31bc11f17d8159b5914aRomain Guy    private static native boolean nQuickReject(int renderer, float left, float top,
560ca79cf69d09efa0c327e9b1237d86a119aea5da7Derek Sollenberger            float right, float bottom);
561e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
562e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
563e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public boolean quickReject(Path path, EdgeType type) {
5646410c0aaf13c9aec606b90ee942f2ac2d98b1609Romain Guy        RectF pathBounds = getPathBounds();
5656410c0aaf13c9aec606b90ee942f2ac2d98b1609Romain Guy        path.computeBounds(pathBounds, true);
5666410c0aaf13c9aec606b90ee942f2ac2d98b1609Romain Guy        return nQuickReject(mRenderer, pathBounds.left, pathBounds.top,
5676410c0aaf13c9aec606b90ee942f2ac2d98b1609Romain Guy                pathBounds.right, pathBounds.bottom);
568e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
569e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
570e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
571e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public boolean quickReject(RectF rect, EdgeType type) {
572ca79cf69d09efa0c327e9b1237d86a119aea5da7Derek Sollenberger        return nQuickReject(mRenderer, rect.left, rect.top, rect.right, rect.bottom);
573e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
574e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
575e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    ///////////////////////////////////////////////////////////////////////////
576e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    // Transformations
577e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    ///////////////////////////////////////////////////////////////////////////
578e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
579e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
580e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public void translate(float dx, float dy) {
581807daf7df615b60ce6fc41355aabe3aa353cebabRomain Guy        if (dx != 0.0f || dy != 0.0f) nTranslate(mRenderer, dx, dy);
582e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
583f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy
5847d7b5490a0b0763e831b31bc11f17d8159b5914aRomain Guy    private static native void nTranslate(int renderer, float dx, float dy);
585e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
586e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
587e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public void skew(float sx, float sy) {
588807daf7df615b60ce6fc41355aabe3aa353cebabRomain Guy        nSkew(mRenderer, sx, sy);
589e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
590e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
5917d7b5490a0b0763e831b31bc11f17d8159b5914aRomain Guy    private static native void nSkew(int renderer, float sx, float sy);
592807daf7df615b60ce6fc41355aabe3aa353cebabRomain Guy
593e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
594e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public void rotate(float degrees) {
595f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy        nRotate(mRenderer, degrees);
596e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
597f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy
5987d7b5490a0b0763e831b31bc11f17d8159b5914aRomain Guy    private static native void nRotate(int renderer, float degrees);
599e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
600e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
601e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public void scale(float sx, float sy) {
602f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy        nScale(mRenderer, sx, sy);
603e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
604e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
6057d7b5490a0b0763e831b31bc11f17d8159b5914aRomain Guy    private static native void nScale(int renderer, float sx, float sy);
606f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy
607e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
608e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public void setMatrix(Matrix matrix) {
609e707859415f4c8e1c01228dfaa58fb0a690d442eRomain Guy        nSetMatrix(mRenderer, matrix == null ? 0 : matrix.native_instance);
610e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
611f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy
6127d7b5490a0b0763e831b31bc11f17d8159b5914aRomain Guy    private static native void nSetMatrix(int renderer, int matrix);
613e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
6145ff9df658230d49e42c43586997a02d8e4dd417eRomain Guy    @SuppressWarnings("deprecation")
615e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
616f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy    public void getMatrix(Matrix matrix) {
617f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy        nGetMatrix(mRenderer, matrix.native_instance);
618e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
619f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy
6207d7b5490a0b0763e831b31bc11f17d8159b5914aRomain Guy    private static native void nGetMatrix(int renderer, int matrix);
621e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
622e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
623e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public void concat(Matrix matrix) {
6244e7b772b733593fbe25c733e95b8dcea293234b6Romain Guy        if (matrix != null) nConcatMatrix(mRenderer, matrix.native_instance);
625e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
626e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
6277d7b5490a0b0763e831b31bc11f17d8159b5914aRomain Guy    private static native void nConcatMatrix(int renderer, int matrix);
628f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy
629e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    ///////////////////////////////////////////////////////////////////////////
630e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    // State management
631e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    ///////////////////////////////////////////////////////////////////////////
632e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
633e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
634e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public int save() {
6358aef54fa17f2a3753d9a8f2027629bc480088f69Romain Guy        return nSave(mRenderer, Canvas.CLIP_SAVE_FLAG | Canvas.MATRIX_SAVE_FLAG);
636e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
637bb9524b6bdddc7ac77d8628daa8b366b8a7be4a4Romain Guy
638e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
639e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public int save(int saveFlags) {
640bb9524b6bdddc7ac77d8628daa8b366b8a7be4a4Romain Guy        return nSave(mRenderer, saveFlags);
641e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
642e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
6437d7b5490a0b0763e831b31bc11f17d8159b5914aRomain Guy    private static native int nSave(int renderer, int flags);
644bb9524b6bdddc7ac77d8628daa8b366b8a7be4a4Romain Guy
645e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
646e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public int saveLayer(RectF bounds, Paint paint, int saveFlags) {
647189887e0ae171c1b7601991442104a30e56c50abRomain Guy        if (bounds != null) {
648189887e0ae171c1b7601991442104a30e56c50abRomain Guy            return saveLayer(bounds.left, bounds.top, bounds.right, bounds.bottom, paint, saveFlags);
649189887e0ae171c1b7601991442104a30e56c50abRomain Guy        }
650189887e0ae171c1b7601991442104a30e56c50abRomain Guy
651445c83c7755fae179cf3328e89307e2775e97a5eRomain Guy        int count;
652189887e0ae171c1b7601991442104a30e56c50abRomain Guy        int modifier = paint != null ? setupColorFilter(paint) : MODIFIER_NONE;
653445c83c7755fae179cf3328e89307e2775e97a5eRomain Guy        try {
654445c83c7755fae179cf3328e89307e2775e97a5eRomain Guy            final int nativePaint = paint == null ? 0 : paint.mNativePaint;
655445c83c7755fae179cf3328e89307e2775e97a5eRomain Guy            count = nSaveLayer(mRenderer, nativePaint, saveFlags);
656445c83c7755fae179cf3328e89307e2775e97a5eRomain Guy        } finally {
657445c83c7755fae179cf3328e89307e2775e97a5eRomain Guy            if (modifier != MODIFIER_NONE) nResetModifiers(mRenderer, modifier);
658445c83c7755fae179cf3328e89307e2775e97a5eRomain Guy        }
659189887e0ae171c1b7601991442104a30e56c50abRomain Guy        return count;
660e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
661e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
662189887e0ae171c1b7601991442104a30e56c50abRomain Guy    private static native int nSaveLayer(int renderer, int paint, int saveFlags);
663189887e0ae171c1b7601991442104a30e56c50abRomain Guy
664e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
665e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public int saveLayer(float left, float top, float right, float bottom, Paint paint,
666e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy            int saveFlags) {
66701d58e43ede5ca98cbebdd166f9b0c545032c01bRomain Guy        if (left < right && top < bottom) {
668445c83c7755fae179cf3328e89307e2775e97a5eRomain Guy            int count;
669a168d7372132d6c87835878794b6ed43d0d282fdRomain Guy            int modifier = paint != null ? setupColorFilter(paint) : MODIFIER_NONE;
670445c83c7755fae179cf3328e89307e2775e97a5eRomain Guy            try {
671445c83c7755fae179cf3328e89307e2775e97a5eRomain Guy                final int nativePaint = paint == null ? 0 : paint.mNativePaint;
672445c83c7755fae179cf3328e89307e2775e97a5eRomain Guy                count = nSaveLayer(mRenderer, left, top, right, bottom, nativePaint, saveFlags);
673445c83c7755fae179cf3328e89307e2775e97a5eRomain Guy            } finally {
674445c83c7755fae179cf3328e89307e2775e97a5eRomain Guy                if (modifier != MODIFIER_NONE) nResetModifiers(mRenderer, modifier);
675445c83c7755fae179cf3328e89307e2775e97a5eRomain Guy            }
67601d58e43ede5ca98cbebdd166f9b0c545032c01bRomain Guy            return count;
67701d58e43ede5ca98cbebdd166f9b0c545032c01bRomain Guy        }
67801d58e43ede5ca98cbebdd166f9b0c545032c01bRomain Guy        return save(saveFlags);
679e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
680e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
6817d7b5490a0b0763e831b31bc11f17d8159b5914aRomain Guy    private static native int nSaveLayer(int renderer, float left, float top,
6827d7b5490a0b0763e831b31bc11f17d8159b5914aRomain Guy            float right, float bottom, int paint, int saveFlags);
683bd6b79b40247aea7bfe13d0831c6c0472df6c636Romain Guy
684e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
685e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public int saveLayerAlpha(RectF bounds, int alpha, int saveFlags) {
686189887e0ae171c1b7601991442104a30e56c50abRomain Guy        if (bounds != null) {
687189887e0ae171c1b7601991442104a30e56c50abRomain Guy            return saveLayerAlpha(bounds.left, bounds.top, bounds.right, bounds.bottom,
688189887e0ae171c1b7601991442104a30e56c50abRomain Guy                    alpha, saveFlags);
689189887e0ae171c1b7601991442104a30e56c50abRomain Guy        }
690189887e0ae171c1b7601991442104a30e56c50abRomain Guy        return nSaveLayerAlpha(mRenderer, alpha, saveFlags);
691e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
692e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
693189887e0ae171c1b7601991442104a30e56c50abRomain Guy    private static native int nSaveLayerAlpha(int renderer, int alpha, int saveFlags);
694189887e0ae171c1b7601991442104a30e56c50abRomain Guy
695e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
696e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public int saveLayerAlpha(float left, float top, float right, float bottom, int alpha,
697e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy            int saveFlags) {
69801d58e43ede5ca98cbebdd166f9b0c545032c01bRomain Guy        if (left < right && top < bottom) {
69901d58e43ede5ca98cbebdd166f9b0c545032c01bRomain Guy            return nSaveLayerAlpha(mRenderer, left, top, right, bottom, alpha, saveFlags);
70001d58e43ede5ca98cbebdd166f9b0c545032c01bRomain Guy        }
70101d58e43ede5ca98cbebdd166f9b0c545032c01bRomain Guy        return save(saveFlags);
702e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
703e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
7047d7b5490a0b0763e831b31bc11f17d8159b5914aRomain Guy    private static native int nSaveLayerAlpha(int renderer, float left, float top, float right,
705bd6b79b40247aea7bfe13d0831c6c0472df6c636Romain Guy            float bottom, int alpha, int saveFlags);
706bd6b79b40247aea7bfe13d0831c6c0472df6c636Romain Guy
707e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
708e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public void restore() {
709bb9524b6bdddc7ac77d8628daa8b366b8a7be4a4Romain Guy        nRestore(mRenderer);
710e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
711bb9524b6bdddc7ac77d8628daa8b366b8a7be4a4Romain Guy
7127d7b5490a0b0763e831b31bc11f17d8159b5914aRomain Guy    private static native void nRestore(int renderer);
713e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
714e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
715e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public void restoreToCount(int saveCount) {
716bb9524b6bdddc7ac77d8628daa8b366b8a7be4a4Romain Guy        nRestoreToCount(mRenderer, saveCount);
717e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
718e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
7197d7b5490a0b0763e831b31bc11f17d8159b5914aRomain Guy    private static native void nRestoreToCount(int renderer, int saveCount);
720bb9524b6bdddc7ac77d8628daa8b366b8a7be4a4Romain Guy
721e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
722e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public int getSaveCount() {
723bb9524b6bdddc7ac77d8628daa8b366b8a7be4a4Romain Guy        return nGetSaveCount(mRenderer);
724e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
725bb9524b6bdddc7ac77d8628daa8b366b8a7be4a4Romain Guy
7267d7b5490a0b0763e831b31bc11f17d8159b5914aRomain Guy    private static native int nGetSaveCount(int renderer);
727e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
728e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    ///////////////////////////////////////////////////////////////////////////
729e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    // Filtering
730e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    ///////////////////////////////////////////////////////////////////////////
731e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
732e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
733e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public void setDrawFilter(DrawFilter filter) {
7346926c72e25b8dec3dd4b84af0819fa1937ae7296Romain Guy        mFilter = filter;
7355ff9df658230d49e42c43586997a02d8e4dd417eRomain Guy        if (filter == null) {
7365ff9df658230d49e42c43586997a02d8e4dd417eRomain Guy            nResetPaintFilter(mRenderer);
7375ff9df658230d49e42c43586997a02d8e4dd417eRomain Guy        } else if (filter instanceof PaintFlagsDrawFilter) {
7385ff9df658230d49e42c43586997a02d8e4dd417eRomain Guy            PaintFlagsDrawFilter flagsFilter = (PaintFlagsDrawFilter) filter;
7395ff9df658230d49e42c43586997a02d8e4dd417eRomain Guy            nSetupPaintFilter(mRenderer, flagsFilter.clearBits, flagsFilter.setBits);
7405ff9df658230d49e42c43586997a02d8e4dd417eRomain Guy        }
741e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
742e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
7435ff9df658230d49e42c43586997a02d8e4dd417eRomain Guy    private static native void nResetPaintFilter(int renderer);
7445ff9df658230d49e42c43586997a02d8e4dd417eRomain Guy    private static native void nSetupPaintFilter(int renderer, int clearBits, int setBits);
7455ff9df658230d49e42c43586997a02d8e4dd417eRomain Guy
746e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
747e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public DrawFilter getDrawFilter() {
7486926c72e25b8dec3dd4b84af0819fa1937ae7296Romain Guy        return mFilter;
749e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
750e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
751e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    ///////////////////////////////////////////////////////////////////////////
752e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    // Drawing
753e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    ///////////////////////////////////////////////////////////////////////////
754e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
755e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
756e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public void drawArc(RectF oval, float startAngle, float sweepAngle, boolean useCenter,
757e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy            Paint paint) {
758765dcf32307dbd93ce43f064c426ce157be2d2aeRomain Guy        int modifiers = setupModifiers(paint, MODIFIER_COLOR_FILTER | MODIFIER_SHADER);
759445c83c7755fae179cf3328e89307e2775e97a5eRomain Guy        try {
760445c83c7755fae179cf3328e89307e2775e97a5eRomain Guy            nDrawArc(mRenderer, oval.left, oval.top, oval.right, oval.bottom,
761445c83c7755fae179cf3328e89307e2775e97a5eRomain Guy                    startAngle, sweepAngle, useCenter, paint.mNativePaint);
762445c83c7755fae179cf3328e89307e2775e97a5eRomain Guy        } finally {
763445c83c7755fae179cf3328e89307e2775e97a5eRomain Guy            if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
764445c83c7755fae179cf3328e89307e2775e97a5eRomain Guy        }
765e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
766e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
7677d7b5490a0b0763e831b31bc11f17d8159b5914aRomain Guy    private static native void nDrawArc(int renderer, float left, float top,
7687d7b5490a0b0763e831b31bc11f17d8159b5914aRomain Guy            float right, float bottom, float startAngle, float sweepAngle,
7697d7b5490a0b0763e831b31bc11f17d8159b5914aRomain Guy            boolean useCenter, int paint);
7708b2f5267f16c295f12faab810527cd6311997e34Romain Guy
771e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
772e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public void drawARGB(int a, int r, int g, int b) {
77385bf02fc16784d935fb9eebfa9cb20fe46ff7951Romain Guy        drawColor((a & 0xFF) << 24 | (r & 0xFF) << 16 | (g & 0xFF) << 8 | (b & 0xFF));
774e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
775e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
776e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
777f3187b7df158d2de36955ddcc666ba4b8544a2ceRomain Guy    public void drawPatch(NinePatch patch, Rect dst, Paint paint) {
778f3187b7df158d2de36955ddcc666ba4b8544a2ceRomain Guy        Bitmap bitmap = patch.getBitmap();
779f3187b7df158d2de36955ddcc666ba4b8544a2ceRomain Guy        if (bitmap.isRecycled()) throw new IllegalArgumentException("Cannot draw recycled bitmaps");
780f3187b7df158d2de36955ddcc666ba4b8544a2ceRomain Guy        // Shaders are ignored when drawing patches
781f3187b7df158d2de36955ddcc666ba4b8544a2ceRomain Guy        int modifier = paint != null ? setupColorFilter(paint) : MODIFIER_NONE;
782f3187b7df158d2de36955ddcc666ba4b8544a2ceRomain Guy        try {
783f3187b7df158d2de36955ddcc666ba4b8544a2ceRomain Guy            final int nativePaint = paint == null ? 0 : paint.mNativePaint;
7840c20c3898a533b7b76f60827cb6ea02e17c5953dChris Craik            nDrawPatch(mRenderer, bitmap.mNativeBitmap, bitmap.mBuffer, patch.mNativeChunk,
785f3187b7df158d2de36955ddcc666ba4b8544a2ceRomain Guy                    dst.left, dst.top, dst.right, dst.bottom, nativePaint);
786f3187b7df158d2de36955ddcc666ba4b8544a2ceRomain Guy        } finally {
787f3187b7df158d2de36955ddcc666ba4b8544a2ceRomain Guy            if (modifier != MODIFIER_NONE) nResetModifiers(mRenderer, modifier);
788f3187b7df158d2de36955ddcc666ba4b8544a2ceRomain Guy        }
789f3187b7df158d2de36955ddcc666ba4b8544a2ceRomain Guy    }
790f3187b7df158d2de36955ddcc666ba4b8544a2ceRomain Guy
791f3187b7df158d2de36955ddcc666ba4b8544a2ceRomain Guy    @Override
7923b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy    public void drawPatch(NinePatch patch, RectF dst, Paint paint) {
7933b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy        Bitmap bitmap = patch.getBitmap();
794bc52cce276b6238e8f30f71a0dcf24209481261eRomain Guy        if (bitmap.isRecycled()) throw new IllegalArgumentException("Cannot draw recycled bitmaps");
795d27977d1a91d5a6b3cc9fa7664ac7e835e7bd895Romain Guy        // Shaders are ignored when drawing patches
796a168d7372132d6c87835878794b6ed43d0d282fdRomain Guy        int modifier = paint != null ? setupColorFilter(paint) : MODIFIER_NONE;
797445c83c7755fae179cf3328e89307e2775e97a5eRomain Guy        try {
798445c83c7755fae179cf3328e89307e2775e97a5eRomain Guy            final int nativePaint = paint == null ? 0 : paint.mNativePaint;
7990c20c3898a533b7b76f60827cb6ea02e17c5953dChris Craik            nDrawPatch(mRenderer, bitmap.mNativeBitmap, bitmap.mBuffer, patch.mNativeChunk,
800445c83c7755fae179cf3328e89307e2775e97a5eRomain Guy                    dst.left, dst.top, dst.right, dst.bottom, nativePaint);
801445c83c7755fae179cf3328e89307e2775e97a5eRomain Guy        } finally {
802445c83c7755fae179cf3328e89307e2775e97a5eRomain Guy            if (modifier != MODIFIER_NONE) nResetModifiers(mRenderer, modifier);
803445c83c7755fae179cf3328e89307e2775e97a5eRomain Guy        }
804deba785f122a47915756ffd991f5540d952cf937Romain Guy    }
805deba785f122a47915756ffd991f5540d952cf937Romain Guy
8060c20c3898a533b7b76f60827cb6ea02e17c5953dChris Craik    private static native void nDrawPatch(int renderer, int bitmap, byte[] buffer, int chunk,
807e4ac2d6b5723c95e648c489b187ddde449452c13Patrick Dubroy            float left, float top, float right, float bottom, int paint);
808deba785f122a47915756ffd991f5540d952cf937Romain Guy
809deba785f122a47915756ffd991f5540d952cf937Romain Guy    @Override
810e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public void drawBitmap(Bitmap bitmap, float left, float top, Paint paint) {
811bc52cce276b6238e8f30f71a0dcf24209481261eRomain Guy        if (bitmap.isRecycled()) throw new IllegalArgumentException("Cannot draw recycled bitmaps");
812d27977d1a91d5a6b3cc9fa7664ac7e835e7bd895Romain Guy        // Shaders are ignored when drawing bitmaps
813a168d7372132d6c87835878794b6ed43d0d282fdRomain Guy        int modifiers = paint != null ? setupModifiers(bitmap, paint) : MODIFIER_NONE;
814445c83c7755fae179cf3328e89307e2775e97a5eRomain Guy        try {
815445c83c7755fae179cf3328e89307e2775e97a5eRomain Guy            final int nativePaint = paint == null ? 0 : paint.mNativePaint;
8160c20c3898a533b7b76f60827cb6ea02e17c5953dChris Craik            nDrawBitmap(mRenderer, bitmap.mNativeBitmap, bitmap.mBuffer, left, top, nativePaint);
817445c83c7755fae179cf3328e89307e2775e97a5eRomain Guy        } finally {
818445c83c7755fae179cf3328e89307e2775e97a5eRomain Guy            if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
819445c83c7755fae179cf3328e89307e2775e97a5eRomain Guy        }
820e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
821e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
8220c20c3898a533b7b76f60827cb6ea02e17c5953dChris Craik    private static native void nDrawBitmap(int renderer, int bitmap, byte[] buffer,
8233b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy            float left, float top, int paint);
824dbd77cd444f89d94ec5333223c1bc17dbe0c90cdRomain Guy
825e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
826e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public void drawBitmap(Bitmap bitmap, Matrix matrix, Paint paint) {
827bc52cce276b6238e8f30f71a0dcf24209481261eRomain Guy        if (bitmap.isRecycled()) throw new IllegalArgumentException("Cannot draw recycled bitmaps");
828d27977d1a91d5a6b3cc9fa7664ac7e835e7bd895Romain Guy        // Shaders are ignored when drawing bitmaps
829a168d7372132d6c87835878794b6ed43d0d282fdRomain Guy        int modifiers = paint != null ? setupModifiers(bitmap, paint) : MODIFIER_NONE;
830445c83c7755fae179cf3328e89307e2775e97a5eRomain Guy        try {
831445c83c7755fae179cf3328e89307e2775e97a5eRomain Guy            final int nativePaint = paint == null ? 0 : paint.mNativePaint;
8320c20c3898a533b7b76f60827cb6ea02e17c5953dChris Craik            nDrawBitmap(mRenderer, bitmap.mNativeBitmap, bitmap.mBuffer,
8330c20c3898a533b7b76f60827cb6ea02e17c5953dChris Craik                    matrix.native_instance, nativePaint);
834445c83c7755fae179cf3328e89307e2775e97a5eRomain Guy        } finally {
835445c83c7755fae179cf3328e89307e2775e97a5eRomain Guy            if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
836445c83c7755fae179cf3328e89307e2775e97a5eRomain Guy        }
837e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
838e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
8390c20c3898a533b7b76f60827cb6ea02e17c5953dChris Craik    private static native void nDrawBitmap(int renderer, int bitmap, byte[] buffer,
8400c20c3898a533b7b76f60827cb6ea02e17c5953dChris Craik            int matrix, int paint);
841f86ef57f8bcd8ba43ce222ec6a8b4f67d3600640Romain Guy
842e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
843e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public void drawBitmap(Bitmap bitmap, Rect src, Rect dst, Paint paint) {
844bc52cce276b6238e8f30f71a0dcf24209481261eRomain Guy        if (bitmap.isRecycled()) throw new IllegalArgumentException("Cannot draw recycled bitmaps");
845d27977d1a91d5a6b3cc9fa7664ac7e835e7bd895Romain Guy        // Shaders are ignored when drawing bitmaps
846a168d7372132d6c87835878794b6ed43d0d282fdRomain Guy        int modifiers = paint != null ? setupModifiers(bitmap, paint) : MODIFIER_NONE;
847445c83c7755fae179cf3328e89307e2775e97a5eRomain Guy        try {
848445c83c7755fae179cf3328e89307e2775e97a5eRomain Guy            final int nativePaint = paint == null ? 0 : paint.mNativePaint;
849694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
850445c83c7755fae179cf3328e89307e2775e97a5eRomain Guy            int left, top, right, bottom;
851445c83c7755fae179cf3328e89307e2775e97a5eRomain Guy            if (src == null) {
852445c83c7755fae179cf3328e89307e2775e97a5eRomain Guy                left = top = 0;
853445c83c7755fae179cf3328e89307e2775e97a5eRomain Guy                right = bitmap.getWidth();
854445c83c7755fae179cf3328e89307e2775e97a5eRomain Guy                bottom = bitmap.getHeight();
855445c83c7755fae179cf3328e89307e2775e97a5eRomain Guy            } else {
856445c83c7755fae179cf3328e89307e2775e97a5eRomain Guy                left = src.left;
857445c83c7755fae179cf3328e89307e2775e97a5eRomain Guy                right = src.right;
858445c83c7755fae179cf3328e89307e2775e97a5eRomain Guy                top = src.top;
859445c83c7755fae179cf3328e89307e2775e97a5eRomain Guy                bottom = src.bottom;
860445c83c7755fae179cf3328e89307e2775e97a5eRomain Guy            }
861694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
8620c20c3898a533b7b76f60827cb6ea02e17c5953dChris Craik            nDrawBitmap(mRenderer, bitmap.mNativeBitmap, bitmap.mBuffer, left, top, right, bottom,
863445c83c7755fae179cf3328e89307e2775e97a5eRomain Guy                    dst.left, dst.top, dst.right, dst.bottom, nativePaint);
864445c83c7755fae179cf3328e89307e2775e97a5eRomain Guy        } finally {
865445c83c7755fae179cf3328e89307e2775e97a5eRomain Guy            if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
866445c83c7755fae179cf3328e89307e2775e97a5eRomain Guy        }
867e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
868e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
869e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
870e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public void drawBitmap(Bitmap bitmap, Rect src, RectF dst, Paint paint) {
871bc52cce276b6238e8f30f71a0dcf24209481261eRomain Guy        if (bitmap.isRecycled()) throw new IllegalArgumentException("Cannot draw recycled bitmaps");
872d27977d1a91d5a6b3cc9fa7664ac7e835e7bd895Romain Guy        // Shaders are ignored when drawing bitmaps
873a168d7372132d6c87835878794b6ed43d0d282fdRomain Guy        int modifiers = paint != null ? setupModifiers(bitmap, paint) : MODIFIER_NONE;
874445c83c7755fae179cf3328e89307e2775e97a5eRomain Guy        try {
875445c83c7755fae179cf3328e89307e2775e97a5eRomain Guy            final int nativePaint = paint == null ? 0 : paint.mNativePaint;
876445c83c7755fae179cf3328e89307e2775e97a5eRomain Guy
877445c83c7755fae179cf3328e89307e2775e97a5eRomain Guy            float left, top, right, bottom;
878445c83c7755fae179cf3328e89307e2775e97a5eRomain Guy            if (src == null) {
879445c83c7755fae179cf3328e89307e2775e97a5eRomain Guy                left = top = 0;
880445c83c7755fae179cf3328e89307e2775e97a5eRomain Guy                right = bitmap.getWidth();
881445c83c7755fae179cf3328e89307e2775e97a5eRomain Guy                bottom = bitmap.getHeight();
882445c83c7755fae179cf3328e89307e2775e97a5eRomain Guy            } else {
883445c83c7755fae179cf3328e89307e2775e97a5eRomain Guy                left = src.left;
884445c83c7755fae179cf3328e89307e2775e97a5eRomain Guy                right = src.right;
885445c83c7755fae179cf3328e89307e2775e97a5eRomain Guy                top = src.top;
886445c83c7755fae179cf3328e89307e2775e97a5eRomain Guy                bottom = src.bottom;
887445c83c7755fae179cf3328e89307e2775e97a5eRomain Guy            }
888445c83c7755fae179cf3328e89307e2775e97a5eRomain Guy
8890c20c3898a533b7b76f60827cb6ea02e17c5953dChris Craik            nDrawBitmap(mRenderer, bitmap.mNativeBitmap, bitmap.mBuffer, left, top, right, bottom,
890445c83c7755fae179cf3328e89307e2775e97a5eRomain Guy                    dst.left, dst.top, dst.right, dst.bottom, nativePaint);
891445c83c7755fae179cf3328e89307e2775e97a5eRomain Guy        } finally {
892445c83c7755fae179cf3328e89307e2775e97a5eRomain Guy            if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
893ff98fa5a847f66e591287154c634ef7895a9549cRomain Guy        }
894e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
895e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
8960c20c3898a533b7b76f60827cb6ea02e17c5953dChris Craik    private static native void nDrawBitmap(int renderer, int bitmap, byte[] buffer,
897ce0537b80087a6225273040a987414b1dd081aa0Romain Guy            float srcLeft, float srcTop, float srcRight, float srcBottom,
898dbd77cd444f89d94ec5333223c1bc17dbe0c90cdRomain Guy            float left, float top, float right, float bottom, int paint);
899ce0537b80087a6225273040a987414b1dd081aa0Romain Guy
900e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
901e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public void drawBitmap(int[] colors, int offset, int stride, float x, float y,
902e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy            int width, int height, boolean hasAlpha, Paint paint) {
903e651cc6239616a202f6e96ebc2ed93b4b8b3627cRomain Guy        if (width < 0) {
904e651cc6239616a202f6e96ebc2ed93b4b8b3627cRomain Guy            throw new IllegalArgumentException("width must be >= 0");
905e651cc6239616a202f6e96ebc2ed93b4b8b3627cRomain Guy        }
906e651cc6239616a202f6e96ebc2ed93b4b8b3627cRomain Guy
907e651cc6239616a202f6e96ebc2ed93b4b8b3627cRomain Guy        if (height < 0) {
908e651cc6239616a202f6e96ebc2ed93b4b8b3627cRomain Guy            throw new IllegalArgumentException("height must be >= 0");
909e651cc6239616a202f6e96ebc2ed93b4b8b3627cRomain Guy        }
910e651cc6239616a202f6e96ebc2ed93b4b8b3627cRomain Guy
911e651cc6239616a202f6e96ebc2ed93b4b8b3627cRomain Guy        if (Math.abs(stride) < width) {
912e651cc6239616a202f6e96ebc2ed93b4b8b3627cRomain Guy            throw new IllegalArgumentException("abs(stride) must be >= width");
913e651cc6239616a202f6e96ebc2ed93b4b8b3627cRomain Guy        }
914e651cc6239616a202f6e96ebc2ed93b4b8b3627cRomain Guy
915e651cc6239616a202f6e96ebc2ed93b4b8b3627cRomain Guy        int lastScanline = offset + (height - 1) * stride;
916e651cc6239616a202f6e96ebc2ed93b4b8b3627cRomain Guy        int length = colors.length;
917e651cc6239616a202f6e96ebc2ed93b4b8b3627cRomain Guy
918e651cc6239616a202f6e96ebc2ed93b4b8b3627cRomain Guy        if (offset < 0 || (offset + width > length) || lastScanline < 0 ||
919e651cc6239616a202f6e96ebc2ed93b4b8b3627cRomain Guy                (lastScanline + width > length)) {
920e651cc6239616a202f6e96ebc2ed93b4b8b3627cRomain Guy            throw new ArrayIndexOutOfBoundsException();
921e651cc6239616a202f6e96ebc2ed93b4b8b3627cRomain Guy        }
922e651cc6239616a202f6e96ebc2ed93b4b8b3627cRomain Guy
923d27977d1a91d5a6b3cc9fa7664ac7e835e7bd895Romain Guy        // Shaders are ignored when drawing bitmaps
924a168d7372132d6c87835878794b6ed43d0d282fdRomain Guy        int modifier = paint != null ? setupColorFilter(paint) : MODIFIER_NONE;
925445c83c7755fae179cf3328e89307e2775e97a5eRomain Guy        try {
926445c83c7755fae179cf3328e89307e2775e97a5eRomain Guy            final int nativePaint = paint == null ? 0 : paint.mNativePaint;
927e651cc6239616a202f6e96ebc2ed93b4b8b3627cRomain Guy            nDrawBitmap(mRenderer, colors, offset, stride, x, y,
928e651cc6239616a202f6e96ebc2ed93b4b8b3627cRomain Guy                    width, height, hasAlpha, nativePaint);
929445c83c7755fae179cf3328e89307e2775e97a5eRomain Guy        } finally {
930445c83c7755fae179cf3328e89307e2775e97a5eRomain Guy            if (modifier != MODIFIER_NONE) nResetModifiers(mRenderer, modifier);
931445c83c7755fae179cf3328e89307e2775e97a5eRomain Guy        }
932e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
933e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
934e651cc6239616a202f6e96ebc2ed93b4b8b3627cRomain Guy    private static native void nDrawBitmap(int renderer, int[] colors, int offset, int stride,
935e651cc6239616a202f6e96ebc2ed93b4b8b3627cRomain Guy            float x, float y, int width, int height, boolean hasAlpha, int nativePaint);
936e651cc6239616a202f6e96ebc2ed93b4b8b3627cRomain Guy
937e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
938e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public void drawBitmap(int[] colors, int offset, int stride, int x, int y,
939e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy            int width, int height, boolean hasAlpha, Paint paint) {
940d27977d1a91d5a6b3cc9fa7664ac7e835e7bd895Romain Guy        // Shaders are ignored when drawing bitmaps
941ce0537b80087a6225273040a987414b1dd081aa0Romain Guy        drawBitmap(colors, offset, stride, (float) x, (float) y, width, height, hasAlpha, paint);
942e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
943e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
944e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
945e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public void drawBitmapMesh(Bitmap bitmap, int meshWidth, int meshHeight, float[] verts,
946e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy            int vertOffset, int[] colors, int colorOffset, Paint paint) {
947bc52cce276b6238e8f30f71a0dcf24209481261eRomain Guy        if (bitmap.isRecycled()) throw new IllegalArgumentException("Cannot draw recycled bitmaps");
9485a7b466a2b4b7ced739bd5c31e022de61650545aRomain Guy        if (meshWidth < 0 || meshHeight < 0 || vertOffset < 0 || colorOffset < 0) {
9495a7b466a2b4b7ced739bd5c31e022de61650545aRomain Guy            throw new ArrayIndexOutOfBoundsException();
9505a7b466a2b4b7ced739bd5c31e022de61650545aRomain Guy        }
9515a7b466a2b4b7ced739bd5c31e022de61650545aRomain Guy
9525a7b466a2b4b7ced739bd5c31e022de61650545aRomain Guy        if (meshWidth == 0 || meshHeight == 0) {
9535a7b466a2b4b7ced739bd5c31e022de61650545aRomain Guy            return;
9545a7b466a2b4b7ced739bd5c31e022de61650545aRomain Guy        }
9555a7b466a2b4b7ced739bd5c31e022de61650545aRomain Guy
9565a7b466a2b4b7ced739bd5c31e022de61650545aRomain Guy        final int count = (meshWidth + 1) * (meshHeight + 1);
9575a7b466a2b4b7ced739bd5c31e022de61650545aRomain Guy        checkRange(verts.length, vertOffset, count * 2);
9585a7b466a2b4b7ced739bd5c31e022de61650545aRomain Guy
959ff316ec7a76e52572a2e89b691e6b3bba0cafba3Romain Guy        if (colors != null) {
960ff316ec7a76e52572a2e89b691e6b3bba0cafba3Romain Guy            checkRange(colors.length, colorOffset, count);
961ff316ec7a76e52572a2e89b691e6b3bba0cafba3Romain Guy        }
9625a7b466a2b4b7ced739bd5c31e022de61650545aRomain Guy
963a168d7372132d6c87835878794b6ed43d0d282fdRomain Guy        int modifiers = paint != null ? setupModifiers(bitmap, paint) : MODIFIER_NONE;
964445c83c7755fae179cf3328e89307e2775e97a5eRomain Guy        try {
9650c20c3898a533b7b76f60827cb6ea02e17c5953dChris Craik            final int nativePaint = paint == null ? 0 : paint.mNativePaint;
9660c20c3898a533b7b76f60827cb6ea02e17c5953dChris Craik            nDrawBitmapMesh(mRenderer, bitmap.mNativeBitmap, bitmap.mBuffer, meshWidth, meshHeight,
967445c83c7755fae179cf3328e89307e2775e97a5eRomain Guy                    verts, vertOffset, colors, colorOffset, nativePaint);
968445c83c7755fae179cf3328e89307e2775e97a5eRomain Guy        } finally {
969445c83c7755fae179cf3328e89307e2775e97a5eRomain Guy            if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
970445c83c7755fae179cf3328e89307e2775e97a5eRomain Guy        }
971e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
972e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
9730c20c3898a533b7b76f60827cb6ea02e17c5953dChris Craik    private static native void nDrawBitmapMesh(int renderer, int bitmap, byte[] buffer,
9745a7b466a2b4b7ced739bd5c31e022de61650545aRomain Guy            int meshWidth, int meshHeight, float[] verts, int vertOffset,
9755a7b466a2b4b7ced739bd5c31e022de61650545aRomain Guy            int[] colors, int colorOffset, int paint);
9765a7b466a2b4b7ced739bd5c31e022de61650545aRomain Guy
977e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
978e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public void drawCircle(float cx, float cy, float radius, Paint paint) {
979765dcf32307dbd93ce43f064c426ce157be2d2aeRomain Guy        int modifiers = setupModifiers(paint, MODIFIER_COLOR_FILTER | MODIFIER_SHADER);
980445c83c7755fae179cf3328e89307e2775e97a5eRomain Guy        try {
981445c83c7755fae179cf3328e89307e2775e97a5eRomain Guy            nDrawCircle(mRenderer, cx, cy, radius, paint.mNativePaint);
982445c83c7755fae179cf3328e89307e2775e97a5eRomain Guy        } finally {
983445c83c7755fae179cf3328e89307e2775e97a5eRomain Guy            if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
984445c83c7755fae179cf3328e89307e2775e97a5eRomain Guy        }
985e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
986e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
9877d7b5490a0b0763e831b31bc11f17d8159b5914aRomain Guy    private static native void nDrawCircle(int renderer, float cx, float cy,
9887d7b5490a0b0763e831b31bc11f17d8159b5914aRomain Guy            float radius, int paint);
98901d58e43ede5ca98cbebdd166f9b0c545032c01bRomain Guy
990e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
991e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public void drawColor(int color) {
99285bf02fc16784d935fb9eebfa9cb20fe46ff7951Romain Guy        drawColor(color, PorterDuff.Mode.SRC_OVER);
993e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
994e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
995e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
996e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public void drawColor(int color, PorterDuff.Mode mode) {
99785bf02fc16784d935fb9eebfa9cb20fe46ff7951Romain Guy        nDrawColor(mRenderer, color, mode.nativeInt);
998e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
99985bf02fc16784d935fb9eebfa9cb20fe46ff7951Romain Guy
10007d7b5490a0b0763e831b31bc11f17d8159b5914aRomain Guy    private static native void nDrawColor(int renderer, int color, int mode);
1001e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
1002e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
1003e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public void drawLine(float startX, float startY, float stopX, float stopY, Paint paint) {
10046410c0aaf13c9aec606b90ee942f2ac2d98b1609Romain Guy        float[] line = getLineStorage();
10056410c0aaf13c9aec606b90ee942f2ac2d98b1609Romain Guy        line[0] = startX;
10066410c0aaf13c9aec606b90ee942f2ac2d98b1609Romain Guy        line[1] = startY;
10076410c0aaf13c9aec606b90ee942f2ac2d98b1609Romain Guy        line[2] = stopX;
10086410c0aaf13c9aec606b90ee942f2ac2d98b1609Romain Guy        line[3] = stopY;
10096410c0aaf13c9aec606b90ee942f2ac2d98b1609Romain Guy        drawLines(line, 0, 4, paint);
1010e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
1011e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
1012e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
1013e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public void drawLines(float[] pts, int offset, int count, Paint paint) {
10145d11676414b3606792e23c269cf75b44faa1a2afChris Craik        if (count < 4) return;
10155d11676414b3606792e23c269cf75b44faa1a2afChris Craik
1016759ea80dca64ad652110a129e0d8bf93fea79f61Romain Guy        if ((offset | count) < 0 || offset + count > pts.length) {
1017759ea80dca64ad652110a129e0d8bf93fea79f61Romain Guy            throw new IllegalArgumentException("The lines array must contain 4 elements per line.");
1018759ea80dca64ad652110a129e0d8bf93fea79f61Romain Guy        }
1019765dcf32307dbd93ce43f064c426ce157be2d2aeRomain Guy        int modifiers = setupModifiers(paint, MODIFIER_COLOR_FILTER | MODIFIER_SHADER);
1020445c83c7755fae179cf3328e89307e2775e97a5eRomain Guy        try {
1021445c83c7755fae179cf3328e89307e2775e97a5eRomain Guy            nDrawLines(mRenderer, pts, offset, count, paint.mNativePaint);
1022445c83c7755fae179cf3328e89307e2775e97a5eRomain Guy        } finally {
1023445c83c7755fae179cf3328e89307e2775e97a5eRomain Guy            if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
1024445c83c7755fae179cf3328e89307e2775e97a5eRomain Guy        }
1025e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
1026e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
10277d7b5490a0b0763e831b31bc11f17d8159b5914aRomain Guy    private static native void nDrawLines(int renderer, float[] points,
10287d7b5490a0b0763e831b31bc11f17d8159b5914aRomain Guy            int offset, int count, int paint);
1029759ea80dca64ad652110a129e0d8bf93fea79f61Romain Guy
1030e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
1031e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public void drawLines(float[] pts, Paint paint) {
1032759ea80dca64ad652110a129e0d8bf93fea79f61Romain Guy        drawLines(pts, 0, pts.length, paint);
1033e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
1034e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
1035e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
1036e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public void drawOval(RectF oval, Paint paint) {
1037765dcf32307dbd93ce43f064c426ce157be2d2aeRomain Guy        int modifiers = setupModifiers(paint, MODIFIER_COLOR_FILTER | MODIFIER_SHADER);
1038445c83c7755fae179cf3328e89307e2775e97a5eRomain Guy        try {
1039445c83c7755fae179cf3328e89307e2775e97a5eRomain Guy            nDrawOval(mRenderer, oval.left, oval.top, oval.right, oval.bottom, paint.mNativePaint);
1040445c83c7755fae179cf3328e89307e2775e97a5eRomain Guy        } finally {
1041445c83c7755fae179cf3328e89307e2775e97a5eRomain Guy            if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
1042445c83c7755fae179cf3328e89307e2775e97a5eRomain Guy        }
1043e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
1044e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
10457d7b5490a0b0763e831b31bc11f17d8159b5914aRomain Guy    private static native void nDrawOval(int renderer, float left, float top,
10467d7b5490a0b0763e831b31bc11f17d8159b5914aRomain Guy            float right, float bottom, int paint);
1047c1cd9ba335b293f11e1082447ef08e474710a05fRomain Guy
1048e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
1049e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public void drawPaint(Paint paint) {
10506410c0aaf13c9aec606b90ee942f2ac2d98b1609Romain Guy        final Rect r = getInternalClipBounds();
10516926c72e25b8dec3dd4b84af0819fa1937ae7296Romain Guy        nGetClipBounds(mRenderer, r);
10526926c72e25b8dec3dd4b84af0819fa1937ae7296Romain Guy        drawRect(r.left, r.top, r.right, r.bottom, paint);
1053e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
1054e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
1055e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
1056e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public void drawPath(Path path, Paint paint) {
1057765dcf32307dbd93ce43f064c426ce157be2d2aeRomain Guy        int modifiers = setupModifiers(paint, MODIFIER_COLOR_FILTER | MODIFIER_SHADER);
1058445c83c7755fae179cf3328e89307e2775e97a5eRomain Guy        try {
1059445c83c7755fae179cf3328e89307e2775e97a5eRomain Guy            if (path.isSimplePath) {
1060445c83c7755fae179cf3328e89307e2775e97a5eRomain Guy                if (path.rects != null) {
1061445c83c7755fae179cf3328e89307e2775e97a5eRomain Guy                    nDrawRects(mRenderer, path.rects.mNativeRegion, paint.mNativePaint);
1062445c83c7755fae179cf3328e89307e2775e97a5eRomain Guy                }
1063445c83c7755fae179cf3328e89307e2775e97a5eRomain Guy            } else {
1064445c83c7755fae179cf3328e89307e2775e97a5eRomain Guy                nDrawPath(mRenderer, path.mNativePath, paint.mNativePaint);
1065a48a1a87ba17f20f7006eaab21dcedf86c015c13Romain Guy            }
1066445c83c7755fae179cf3328e89307e2775e97a5eRomain Guy        } finally {
1067445c83c7755fae179cf3328e89307e2775e97a5eRomain Guy            if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
1068a48a1a87ba17f20f7006eaab21dcedf86c015c13Romain Guy        }
1069e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
1070e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
10717d7b5490a0b0763e831b31bc11f17d8159b5914aRomain Guy    private static native void nDrawPath(int renderer, int path, int paint);
10727d7b5490a0b0763e831b31bc11f17d8159b5914aRomain Guy    private static native void nDrawRects(int renderer, int region, int paint);
10737fbcc0492fca03857e3c45064f4aa040af817d55Romain Guy
1074672433d90fab7383cd28beac9d4485b566a90940Romain Guy    void drawRects(float[] rects, int count, Paint paint) {
1075672433d90fab7383cd28beac9d4485b566a90940Romain Guy        int modifiers = setupModifiers(paint, MODIFIER_COLOR_FILTER | MODIFIER_SHADER);
1076672433d90fab7383cd28beac9d4485b566a90940Romain Guy        try {
1077672433d90fab7383cd28beac9d4485b566a90940Romain Guy            nDrawRects(mRenderer, rects, count, paint.mNativePaint);
1078672433d90fab7383cd28beac9d4485b566a90940Romain Guy        } finally {
1079672433d90fab7383cd28beac9d4485b566a90940Romain Guy            if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
1080672433d90fab7383cd28beac9d4485b566a90940Romain Guy        }
1081672433d90fab7383cd28beac9d4485b566a90940Romain Guy    }
1082672433d90fab7383cd28beac9d4485b566a90940Romain Guy
1083672433d90fab7383cd28beac9d4485b566a90940Romain Guy    private static native void nDrawRects(int renderer, float[] rects, int count, int paint);
1084672433d90fab7383cd28beac9d4485b566a90940Romain Guy
1085e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
1086e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public void drawPicture(Picture picture) {
1087f9d9c065ed75f1196316a9a31f92309f602cef76Romain Guy        if (picture.createdFromStream) {
1088f9d9c065ed75f1196316a9a31f92309f602cef76Romain Guy            return;
1089f9d9c065ed75f1196316a9a31f92309f602cef76Romain Guy        }
1090f9d9c065ed75f1196316a9a31f92309f602cef76Romain Guy
109175582e889d4895483309e38364266073be6d46b8Romain Guy        picture.endRecording();
109275582e889d4895483309e38364266073be6d46b8Romain Guy        // TODO: Implement rendering
1093e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
1094e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
1095e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
1096e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public void drawPicture(Picture picture, Rect dst) {
1097f9d9c065ed75f1196316a9a31f92309f602cef76Romain Guy        if (picture.createdFromStream) {
1098f9d9c065ed75f1196316a9a31f92309f602cef76Romain Guy            return;
1099f9d9c065ed75f1196316a9a31f92309f602cef76Romain Guy        }
1100f9d9c065ed75f1196316a9a31f92309f602cef76Romain Guy
110175582e889d4895483309e38364266073be6d46b8Romain Guy        save();
110275582e889d4895483309e38364266073be6d46b8Romain Guy        translate(dst.left, dst.top);
110375582e889d4895483309e38364266073be6d46b8Romain Guy        if (picture.getWidth() > 0 && picture.getHeight() > 0) {
110475582e889d4895483309e38364266073be6d46b8Romain Guy            scale(dst.width() / picture.getWidth(), dst.height() / picture.getHeight());
110575582e889d4895483309e38364266073be6d46b8Romain Guy        }
110675582e889d4895483309e38364266073be6d46b8Romain Guy        drawPicture(picture);
110775582e889d4895483309e38364266073be6d46b8Romain Guy        restore();
1108e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
1109e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
1110e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
1111e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public void drawPicture(Picture picture, RectF dst) {
1112f9d9c065ed75f1196316a9a31f92309f602cef76Romain Guy        if (picture.createdFromStream) {
1113f9d9c065ed75f1196316a9a31f92309f602cef76Romain Guy            return;
1114f9d9c065ed75f1196316a9a31f92309f602cef76Romain Guy        }
1115f9d9c065ed75f1196316a9a31f92309f602cef76Romain Guy
111675582e889d4895483309e38364266073be6d46b8Romain Guy        save();
111775582e889d4895483309e38364266073be6d46b8Romain Guy        translate(dst.left, dst.top);
111875582e889d4895483309e38364266073be6d46b8Romain Guy        if (picture.getWidth() > 0 && picture.getHeight() > 0) {
111975582e889d4895483309e38364266073be6d46b8Romain Guy            scale(dst.width() / picture.getWidth(), dst.height() / picture.getHeight());
112075582e889d4895483309e38364266073be6d46b8Romain Guy        }
112175582e889d4895483309e38364266073be6d46b8Romain Guy        drawPicture(picture);
112275582e889d4895483309e38364266073be6d46b8Romain Guy        restore();
1123e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
1124e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
1125e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
1126e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public void drawPoint(float x, float y, Paint paint) {
11276410c0aaf13c9aec606b90ee942f2ac2d98b1609Romain Guy        float[] point = getPointStorage();
11286410c0aaf13c9aec606b90ee942f2ac2d98b1609Romain Guy        point[0] = x;
11296410c0aaf13c9aec606b90ee942f2ac2d98b1609Romain Guy        point[1] = y;
11306410c0aaf13c9aec606b90ee942f2ac2d98b1609Romain Guy        drawPoints(point, 0, 2, paint);
1131e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
1132e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
1133e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
1134ed6fcb034b44d9a6ac2fc72fee6030417811f234Romain Guy    public void drawPoints(float[] pts, Paint paint) {
1135ed6fcb034b44d9a6ac2fc72fee6030417811f234Romain Guy        drawPoints(pts, 0, pts.length, paint);
1136e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
1137e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
1138e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
1139ed6fcb034b44d9a6ac2fc72fee6030417811f234Romain Guy    public void drawPoints(float[] pts, int offset, int count, Paint paint) {
11405d11676414b3606792e23c269cf75b44faa1a2afChris Craik        if (count < 2) return;
11415d11676414b3606792e23c269cf75b44faa1a2afChris Craik
1142765dcf32307dbd93ce43f064c426ce157be2d2aeRomain Guy        int modifiers = setupModifiers(paint, MODIFIER_COLOR_FILTER | MODIFIER_SHADER);
1143445c83c7755fae179cf3328e89307e2775e97a5eRomain Guy        try {
1144445c83c7755fae179cf3328e89307e2775e97a5eRomain Guy            nDrawPoints(mRenderer, pts, offset, count, paint.mNativePaint);
1145445c83c7755fae179cf3328e89307e2775e97a5eRomain Guy        } finally {
1146445c83c7755fae179cf3328e89307e2775e97a5eRomain Guy            if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
1147445c83c7755fae179cf3328e89307e2775e97a5eRomain Guy        }
1148e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
1149e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
1150ed6fcb034b44d9a6ac2fc72fee6030417811f234Romain Guy    private static native void nDrawPoints(int renderer, float[] points,
1151ed6fcb034b44d9a6ac2fc72fee6030417811f234Romain Guy            int offset, int count, int paint);
1152ed6fcb034b44d9a6ac2fc72fee6030417811f234Romain Guy
11535ff9df658230d49e42c43586997a02d8e4dd417eRomain Guy    @SuppressWarnings("deprecation")
1154e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
1155e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public void drawPosText(char[] text, int index, int count, float[] pos, Paint paint) {
1156eb9a5367e8f0e970db8509ffb2584f5376bc62edRomain Guy        if (index < 0 || index + count > text.length || count * 2 > pos.length) {
1157eb9a5367e8f0e970db8509ffb2584f5376bc62edRomain Guy            throw new IndexOutOfBoundsException();
1158eb9a5367e8f0e970db8509ffb2584f5376bc62edRomain Guy        }
1159eb9a5367e8f0e970db8509ffb2584f5376bc62edRomain Guy
1160eb9a5367e8f0e970db8509ffb2584f5376bc62edRomain Guy        int modifiers = setupModifiers(paint);
1161eb9a5367e8f0e970db8509ffb2584f5376bc62edRomain Guy        try {
1162eb9a5367e8f0e970db8509ffb2584f5376bc62edRomain Guy            nDrawPosText(mRenderer, text, index, count, pos, paint.mNativePaint);
1163eb9a5367e8f0e970db8509ffb2584f5376bc62edRomain Guy        } finally {
1164eb9a5367e8f0e970db8509ffb2584f5376bc62edRomain Guy            if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
1165eb9a5367e8f0e970db8509ffb2584f5376bc62edRomain Guy        }
1166e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
1167e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
1168eb9a5367e8f0e970db8509ffb2584f5376bc62edRomain Guy    private static native void nDrawPosText(int renderer, char[] text, int index, int count,
1169eb9a5367e8f0e970db8509ffb2584f5376bc62edRomain Guy            float[] pos, int paint);
1170eb9a5367e8f0e970db8509ffb2584f5376bc62edRomain Guy
11715ff9df658230d49e42c43586997a02d8e4dd417eRomain Guy    @SuppressWarnings("deprecation")
1172e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
1173e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public void drawPosText(String text, float[] pos, Paint paint) {
1174eb9a5367e8f0e970db8509ffb2584f5376bc62edRomain Guy        if (text.length() * 2 > pos.length) {
1175eb9a5367e8f0e970db8509ffb2584f5376bc62edRomain Guy            throw new ArrayIndexOutOfBoundsException();
1176eb9a5367e8f0e970db8509ffb2584f5376bc62edRomain Guy        }
1177eb9a5367e8f0e970db8509ffb2584f5376bc62edRomain Guy
1178eb9a5367e8f0e970db8509ffb2584f5376bc62edRomain Guy        int modifiers = setupModifiers(paint);
1179eb9a5367e8f0e970db8509ffb2584f5376bc62edRomain Guy        try {
1180eb9a5367e8f0e970db8509ffb2584f5376bc62edRomain Guy            nDrawPosText(mRenderer, text, 0, text.length(), pos, paint.mNativePaint);
1181eb9a5367e8f0e970db8509ffb2584f5376bc62edRomain Guy        } finally {
1182eb9a5367e8f0e970db8509ffb2584f5376bc62edRomain Guy            if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
1183eb9a5367e8f0e970db8509ffb2584f5376bc62edRomain Guy        }
1184e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
1185e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
1186eb9a5367e8f0e970db8509ffb2584f5376bc62edRomain Guy    private static native void nDrawPosText(int renderer, String text, int start, int end,
1187eb9a5367e8f0e970db8509ffb2584f5376bc62edRomain Guy            float[] pos, int paint);
1188eb9a5367e8f0e970db8509ffb2584f5376bc62edRomain Guy
1189e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
1190e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public void drawRect(float left, float top, float right, float bottom, Paint paint) {
1191765dcf32307dbd93ce43f064c426ce157be2d2aeRomain Guy        if (left == right || top == bottom) return;
1192765dcf32307dbd93ce43f064c426ce157be2d2aeRomain Guy        int modifiers = setupModifiers(paint, MODIFIER_COLOR_FILTER | MODIFIER_SHADER);
1193445c83c7755fae179cf3328e89307e2775e97a5eRomain Guy        try {
1194445c83c7755fae179cf3328e89307e2775e97a5eRomain Guy            nDrawRect(mRenderer, left, top, right, bottom, paint.mNativePaint);
1195445c83c7755fae179cf3328e89307e2775e97a5eRomain Guy        } finally {
1196445c83c7755fae179cf3328e89307e2775e97a5eRomain Guy            if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
1197445c83c7755fae179cf3328e89307e2775e97a5eRomain Guy        }
1198e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
1199e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
12007d7b5490a0b0763e831b31bc11f17d8159b5914aRomain Guy    private static native void nDrawRect(int renderer, float left, float top,
12017d7b5490a0b0763e831b31bc11f17d8159b5914aRomain Guy            float right, float bottom, int paint);
1202c7d53494f1fbd9f9d74af89053ff9fdb1ccbac6cRomain Guy
1203e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
1204e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public void drawRect(Rect r, Paint paint) {
1205c7d53494f1fbd9f9d74af89053ff9fdb1ccbac6cRomain Guy        drawRect(r.left, r.top, r.right, r.bottom, paint);
1206e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
1207e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
1208e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
1209c7d53494f1fbd9f9d74af89053ff9fdb1ccbac6cRomain Guy    public void drawRect(RectF r, Paint paint) {
1210c7d53494f1fbd9f9d74af89053ff9fdb1ccbac6cRomain Guy        drawRect(r.left, r.top, r.right, r.bottom, paint);
1211e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
1212e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
1213e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
1214e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public void drawRGB(int r, int g, int b) {
121585bf02fc16784d935fb9eebfa9cb20fe46ff7951Romain Guy        drawColor(0xFF000000 | (r & 0xFF) << 16 | (g & 0xFF) << 8 | (b & 0xFF));
1216e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
1217e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
1218e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
1219e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public void drawRoundRect(RectF rect, float rx, float ry, Paint paint) {
1220765dcf32307dbd93ce43f064c426ce157be2d2aeRomain Guy        int modifiers = setupModifiers(paint, MODIFIER_COLOR_FILTER | MODIFIER_SHADER);
1221445c83c7755fae179cf3328e89307e2775e97a5eRomain Guy        try {
1222445c83c7755fae179cf3328e89307e2775e97a5eRomain Guy            nDrawRoundRect(mRenderer, rect.left, rect.top, rect.right, rect.bottom,
1223445c83c7755fae179cf3328e89307e2775e97a5eRomain Guy                    rx, ry, paint.mNativePaint);
1224445c83c7755fae179cf3328e89307e2775e97a5eRomain Guy        } finally {
1225445c83c7755fae179cf3328e89307e2775e97a5eRomain Guy            if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
1226445c83c7755fae179cf3328e89307e2775e97a5eRomain Guy        }
1227e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
1228e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
12297d7b5490a0b0763e831b31bc11f17d8159b5914aRomain Guy    private static native void nDrawRoundRect(int renderer, float left, float top,
123001d58e43ede5ca98cbebdd166f9b0c545032c01bRomain Guy            float right, float bottom, float rx, float y, int paint);
123101d58e43ede5ca98cbebdd166f9b0c545032c01bRomain Guy
1232e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
1233e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public void drawText(char[] text, int index, int count, float x, float y, Paint paint) {
1234a1db574036c9bc2d397b69f8200594027e1fff16Romain Guy        if ((index | count | (index + count) | (text.length - index - count)) < 0) {
1235a1db574036c9bc2d397b69f8200594027e1fff16Romain Guy            throw new IndexOutOfBoundsException();
1236a1db574036c9bc2d397b69f8200594027e1fff16Romain Guy        }
123761c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy
1238a168d7372132d6c87835878794b6ed43d0d282fdRomain Guy        int modifiers = setupModifiers(paint);
123961c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy        try {
1240da12f389eb4be0c08ca3fa9ca7663f4977858df5Fabrice Di Meglio            nDrawText(mRenderer, text, index, count, x, y, paint.mBidiFlags, paint.mNativePaint);
124161c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy        } finally {
1242a168d7372132d6c87835878794b6ed43d0d282fdRomain Guy            if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
124361c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy        }
1244e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
1245a1db574036c9bc2d397b69f8200594027e1fff16Romain Guy
12467d7b5490a0b0763e831b31bc11f17d8159b5914aRomain Guy    private static native void nDrawText(int renderer, char[] text, int index, int count,
1247da12f389eb4be0c08ca3fa9ca7663f4977858df5Fabrice Di Meglio            float x, float y, int bidiFlags, int paint);
1248e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
1249e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
1250e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public void drawText(CharSequence text, int start, int end, float x, float y, Paint paint) {
1251a168d7372132d6c87835878794b6ed43d0d282fdRomain Guy        int modifiers = setupModifiers(paint);
125261c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy        try {
125361c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy            if (text instanceof String || text instanceof SpannedString ||
125461c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy                    text instanceof SpannableString) {
1255da12f389eb4be0c08ca3fa9ca7663f4977858df5Fabrice Di Meglio                nDrawText(mRenderer, text.toString(), start, end, x, y, paint.mBidiFlags,
1256da12f389eb4be0c08ca3fa9ca7663f4977858df5Fabrice Di Meglio                        paint.mNativePaint);
125761c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy            } else if (text instanceof GraphicsOperations) {
125861c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy                ((GraphicsOperations) text).drawText(this, start, end, x, y,
125961c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy                                                         paint);
126061c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy            } else {
126161c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy                char[] buf = TemporaryBuffer.obtain(end - start);
126261c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy                TextUtils.getChars(text, start, end, buf, 0);
1263da12f389eb4be0c08ca3fa9ca7663f4977858df5Fabrice Di Meglio                nDrawText(mRenderer, buf, 0, end - start, x, y,
1264da12f389eb4be0c08ca3fa9ca7663f4977858df5Fabrice Di Meglio                        paint.mBidiFlags, paint.mNativePaint);
126561c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy                TemporaryBuffer.recycle(buf);
126661c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy            }
126761c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy        } finally {
1268a168d7372132d6c87835878794b6ed43d0d282fdRomain Guy            if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
1269a1db574036c9bc2d397b69f8200594027e1fff16Romain Guy        }
1270e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
1271e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
1272e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
1273e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public void drawText(String text, int start, int end, float x, float y, Paint paint) {
1274a1db574036c9bc2d397b69f8200594027e1fff16Romain Guy        if ((start | end | (end - start) | (text.length() - end)) < 0) {
1275a1db574036c9bc2d397b69f8200594027e1fff16Romain Guy            throw new IndexOutOfBoundsException();
1276a1db574036c9bc2d397b69f8200594027e1fff16Romain Guy        }
127761c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy
1278a168d7372132d6c87835878794b6ed43d0d282fdRomain Guy        int modifiers = setupModifiers(paint);
127961c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy        try {
1280da12f389eb4be0c08ca3fa9ca7663f4977858df5Fabrice Di Meglio            nDrawText(mRenderer, text, start, end, x, y, paint.mBidiFlags, paint.mNativePaint);
128161c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy        } finally {
1282a168d7372132d6c87835878794b6ed43d0d282fdRomain Guy            if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
128361c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy        }
1284e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
1285e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
12867d7b5490a0b0763e831b31bc11f17d8159b5914aRomain Guy    private static native void nDrawText(int renderer, String text, int start, int end,
1287da12f389eb4be0c08ca3fa9ca7663f4977858df5Fabrice Di Meglio            float x, float y, int bidiFlags, int paint);
1288a1db574036c9bc2d397b69f8200594027e1fff16Romain Guy
1289e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
1290e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public void drawText(String text, float x, float y, Paint paint) {
1291a168d7372132d6c87835878794b6ed43d0d282fdRomain Guy        int modifiers = setupModifiers(paint);
129261c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy        try {
1293da12f389eb4be0c08ca3fa9ca7663f4977858df5Fabrice Di Meglio            nDrawText(mRenderer, text, 0, text.length(), x, y, paint.mBidiFlags,
1294da12f389eb4be0c08ca3fa9ca7663f4977858df5Fabrice Di Meglio                    paint.mNativePaint);
129561c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy        } finally {
1296a168d7372132d6c87835878794b6ed43d0d282fdRomain Guy            if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
129761c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy        }
1298e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
1299e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
1300e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
1301e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public void drawTextOnPath(char[] text, int index, int count, Path path, float hOffset,
1302e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy            float vOffset, Paint paint) {
1303325740fb444af8fc7fb0119b2e30ce322c2ae134Romain Guy        if (index < 0 || index + count > text.length) {
1304325740fb444af8fc7fb0119b2e30ce322c2ae134Romain Guy            throw new ArrayIndexOutOfBoundsException();
1305325740fb444af8fc7fb0119b2e30ce322c2ae134Romain Guy        }
1306325740fb444af8fc7fb0119b2e30ce322c2ae134Romain Guy
1307325740fb444af8fc7fb0119b2e30ce322c2ae134Romain Guy        int modifiers = setupModifiers(paint);
1308325740fb444af8fc7fb0119b2e30ce322c2ae134Romain Guy        try {
1309325740fb444af8fc7fb0119b2e30ce322c2ae134Romain Guy            nDrawTextOnPath(mRenderer, text, index, count, path.mNativePath, hOffset, vOffset,
1310da12f389eb4be0c08ca3fa9ca7663f4977858df5Fabrice Di Meglio                    paint.mBidiFlags, paint.mNativePaint);
1311325740fb444af8fc7fb0119b2e30ce322c2ae134Romain Guy        } finally {
1312325740fb444af8fc7fb0119b2e30ce322c2ae134Romain Guy            if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
1313325740fb444af8fc7fb0119b2e30ce322c2ae134Romain Guy        }
1314e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
1315e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
1316325740fb444af8fc7fb0119b2e30ce322c2ae134Romain Guy    private static native void nDrawTextOnPath(int renderer, char[] text, int index, int count,
1317da12f389eb4be0c08ca3fa9ca7663f4977858df5Fabrice Di Meglio            int path, float hOffset, float vOffset, int bidiFlags, int nativePaint);
1318325740fb444af8fc7fb0119b2e30ce322c2ae134Romain Guy
1319e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
1320e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public void drawTextOnPath(String text, Path path, float hOffset, float vOffset, Paint paint) {
1321325740fb444af8fc7fb0119b2e30ce322c2ae134Romain Guy        if (text.length() == 0) return;
1322325740fb444af8fc7fb0119b2e30ce322c2ae134Romain Guy
1323325740fb444af8fc7fb0119b2e30ce322c2ae134Romain Guy        int modifiers = setupModifiers(paint);
1324325740fb444af8fc7fb0119b2e30ce322c2ae134Romain Guy        try {
1325325740fb444af8fc7fb0119b2e30ce322c2ae134Romain Guy            nDrawTextOnPath(mRenderer, text, 0, text.length(), path.mNativePath, hOffset, vOffset,
1326da12f389eb4be0c08ca3fa9ca7663f4977858df5Fabrice Di Meglio                    paint.mBidiFlags, paint.mNativePaint);
1327325740fb444af8fc7fb0119b2e30ce322c2ae134Romain Guy        } finally {
1328325740fb444af8fc7fb0119b2e30ce322c2ae134Romain Guy            if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
1329325740fb444af8fc7fb0119b2e30ce322c2ae134Romain Guy        }
1330e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
1331e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
1332325740fb444af8fc7fb0119b2e30ce322c2ae134Romain Guy    private static native void nDrawTextOnPath(int renderer, String text, int start, int end,
1333da12f389eb4be0c08ca3fa9ca7663f4977858df5Fabrice Di Meglio            int path, float hOffset, float vOffset, int bidiFlags, int nativePaint);
1334325740fb444af8fc7fb0119b2e30ce322c2ae134Romain Guy
1335e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
1336e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public void drawTextRun(char[] text, int index, int count, int contextIndex, int contextCount,
1337da12f389eb4be0c08ca3fa9ca7663f4977858df5Fabrice Di Meglio            float x, float y, int dir, Paint paint) {
133861c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy        if ((index | count | text.length - index - count) < 0) {
133961c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy            throw new IndexOutOfBoundsException();
134061c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy        }
1341da12f389eb4be0c08ca3fa9ca7663f4977858df5Fabrice Di Meglio        if (dir != DIRECTION_LTR && dir != DIRECTION_RTL) {
1342da12f389eb4be0c08ca3fa9ca7663f4977858df5Fabrice Di Meglio            throw new IllegalArgumentException("Unknown direction: " + dir);
1343da12f389eb4be0c08ca3fa9ca7663f4977858df5Fabrice Di Meglio        }
134461c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy
1345a168d7372132d6c87835878794b6ed43d0d282fdRomain Guy        int modifiers = setupModifiers(paint);
134661c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy        try {
1347da12f389eb4be0c08ca3fa9ca7663f4977858df5Fabrice Di Meglio            nDrawTextRun(mRenderer, text, index, count, contextIndex, contextCount, x, y, dir,
134861c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy                    paint.mNativePaint);
134961c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy        } finally {
1350a168d7372132d6c87835878794b6ed43d0d282fdRomain Guy            if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
135161c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy        }
1352e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
1353e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
13547d7b5490a0b0763e831b31bc11f17d8159b5914aRomain Guy    private static native void nDrawTextRun(int renderer, char[] text, int index, int count,
1355da12f389eb4be0c08ca3fa9ca7663f4977858df5Fabrice Di Meglio            int contextIndex, int contextCount, float x, float y, int dir, int nativePaint);
135661c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy
1357e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
1358e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public void drawTextRun(CharSequence text, int start, int end, int contextStart, int contextEnd,
1359da12f389eb4be0c08ca3fa9ca7663f4977858df5Fabrice Di Meglio            float x, float y, int dir, Paint paint) {
136061c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy        if ((start | end | end - start | text.length() - end) < 0) {
136161c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy            throw new IndexOutOfBoundsException();
136261c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy        }
136361c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy
1364a168d7372132d6c87835878794b6ed43d0d282fdRomain Guy        int modifiers = setupModifiers(paint);
136561c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy        try {
1366da12f389eb4be0c08ca3fa9ca7663f4977858df5Fabrice Di Meglio            int flags = dir == 0 ? 0 : 1;
136761c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy            if (text instanceof String || text instanceof SpannedString ||
136861c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy                    text instanceof SpannableString) {
136961c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy                nDrawTextRun(mRenderer, text.toString(), start, end, contextStart,
1370da12f389eb4be0c08ca3fa9ca7663f4977858df5Fabrice Di Meglio                        contextEnd, x, y, flags, paint.mNativePaint);
137161c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy            } else if (text instanceof GraphicsOperations) {
137261c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy                ((GraphicsOperations) text).drawTextRun(this, start, end,
1373da12f389eb4be0c08ca3fa9ca7663f4977858df5Fabrice Di Meglio                        contextStart, contextEnd, x, y, flags, paint);
137461c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy            } else {
137561c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy                int contextLen = contextEnd - contextStart;
137661c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy                int len = end - start;
137761c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy                char[] buf = TemporaryBuffer.obtain(contextLen);
137861c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy                TextUtils.getChars(text, contextStart, contextEnd, buf, 0);
137961c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy                nDrawTextRun(mRenderer, buf, start - contextStart, len, 0, contextLen,
1380da12f389eb4be0c08ca3fa9ca7663f4977858df5Fabrice Di Meglio                        x, y, flags, paint.mNativePaint);
138161c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy                TemporaryBuffer.recycle(buf);
138261c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy            }
138361c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy        } finally {
1384a168d7372132d6c87835878794b6ed43d0d282fdRomain Guy            if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
138561c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy        }
1386e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
1387e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
13887d7b5490a0b0763e831b31bc11f17d8159b5914aRomain Guy    private static native void nDrawTextRun(int renderer, String text, int start, int end,
1389da12f389eb4be0c08ca3fa9ca7663f4977858df5Fabrice Di Meglio            int contextStart, int contextEnd, float x, float y, int flags, int nativePaint);
139061c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy
1391e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
1392e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public void drawVertices(VertexMode mode, int vertexCount, float[] verts, int vertOffset,
1393e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy            float[] texs, int texOffset, int[] colors, int colorOffset, short[] indices,
1394e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy            int indexOffset, int indexCount, Paint paint) {
13956926c72e25b8dec3dd4b84af0819fa1937ae7296Romain Guy        // TODO: Implement
1396e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
1397d27977d1a91d5a6b3cc9fa7664ac7e835e7bd895Romain Guy
1398a168d7372132d6c87835878794b6ed43d0d282fdRomain Guy    private int setupModifiers(Bitmap b, Paint paint) {
1399445c83c7755fae179cf3328e89307e2775e97a5eRomain Guy        if (b.getConfig() != Bitmap.Config.ALPHA_8) {
1400445c83c7755fae179cf3328e89307e2775e97a5eRomain Guy            final ColorFilter filter = paint.getColorFilter();
1401445c83c7755fae179cf3328e89307e2775e97a5eRomain Guy            if (filter != null) {
1402445c83c7755fae179cf3328e89307e2775e97a5eRomain Guy                nSetupColorFilter(mRenderer, filter.nativeColorFilter);
1403445c83c7755fae179cf3328e89307e2775e97a5eRomain Guy                return MODIFIER_COLOR_FILTER;
1404445c83c7755fae179cf3328e89307e2775e97a5eRomain Guy            }
140556215274f25d0040af00bf69b0df990894c0b4b0Romain Guy
1406445c83c7755fae179cf3328e89307e2775e97a5eRomain Guy            return MODIFIER_NONE;
1407445c83c7755fae179cf3328e89307e2775e97a5eRomain Guy        } else {
1408445c83c7755fae179cf3328e89307e2775e97a5eRomain Guy            return setupModifiers(paint);
140956215274f25d0040af00bf69b0df990894c0b4b0Romain Guy        }
1410a168d7372132d6c87835878794b6ed43d0d282fdRomain Guy    }
1411a168d7372132d6c87835878794b6ed43d0d282fdRomain Guy
1412a168d7372132d6c87835878794b6ed43d0d282fdRomain Guy    private int setupModifiers(Paint paint) {
1413a168d7372132d6c87835878794b6ed43d0d282fdRomain Guy        int modifiers = MODIFIER_NONE;
1414db1938e0e6ef816e228c815adccebd5cb05f2aa8Romain Guy
14151e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy        if (paint.hasShadow) {
14161e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy            nSetupShadow(mRenderer, paint.shadowRadius, paint.shadowDx, paint.shadowDy,
14171e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy                    paint.shadowColor);
1418a168d7372132d6c87835878794b6ed43d0d282fdRomain Guy            modifiers |= MODIFIER_SHADOW;
14191e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy        }
14201e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy
1421d27977d1a91d5a6b3cc9fa7664ac7e835e7bd895Romain Guy        final Shader shader = paint.getShader();
1422d27977d1a91d5a6b3cc9fa7664ac7e835e7bd895Romain Guy        if (shader != null) {
142306f96e2652e4855b6520ad9dd70583677605b79aRomain Guy            nSetupShader(mRenderer, shader.native_shader);
1424a168d7372132d6c87835878794b6ed43d0d282fdRomain Guy            modifiers |= MODIFIER_SHADER;
1425db1938e0e6ef816e228c815adccebd5cb05f2aa8Romain Guy        }
1426db1938e0e6ef816e228c815adccebd5cb05f2aa8Romain Guy
1427db1938e0e6ef816e228c815adccebd5cb05f2aa8Romain Guy        final ColorFilter filter = paint.getColorFilter();
1428db1938e0e6ef816e228c815adccebd5cb05f2aa8Romain Guy        if (filter != null) {
1429db1938e0e6ef816e228c815adccebd5cb05f2aa8Romain Guy            nSetupColorFilter(mRenderer, filter.nativeColorFilter);
1430a168d7372132d6c87835878794b6ed43d0d282fdRomain Guy            modifiers |= MODIFIER_COLOR_FILTER;
1431db1938e0e6ef816e228c815adccebd5cb05f2aa8Romain Guy        }
1432db1938e0e6ef816e228c815adccebd5cb05f2aa8Romain Guy
1433a168d7372132d6c87835878794b6ed43d0d282fdRomain Guy        return modifiers;
1434db1938e0e6ef816e228c815adccebd5cb05f2aa8Romain Guy    }
14351e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy
1436765dcf32307dbd93ce43f064c426ce157be2d2aeRomain Guy    private int setupModifiers(Paint paint, int flags) {
1437765dcf32307dbd93ce43f064c426ce157be2d2aeRomain Guy        int modifiers = MODIFIER_NONE;
1438765dcf32307dbd93ce43f064c426ce157be2d2aeRomain Guy
1439765dcf32307dbd93ce43f064c426ce157be2d2aeRomain Guy        if (paint.hasShadow && (flags & MODIFIER_SHADOW) != 0) {
1440765dcf32307dbd93ce43f064c426ce157be2d2aeRomain Guy            nSetupShadow(mRenderer, paint.shadowRadius, paint.shadowDx, paint.shadowDy,
1441765dcf32307dbd93ce43f064c426ce157be2d2aeRomain Guy                    paint.shadowColor);
1442765dcf32307dbd93ce43f064c426ce157be2d2aeRomain Guy            modifiers |= MODIFIER_SHADOW;
1443765dcf32307dbd93ce43f064c426ce157be2d2aeRomain Guy        }
1444765dcf32307dbd93ce43f064c426ce157be2d2aeRomain Guy
1445765dcf32307dbd93ce43f064c426ce157be2d2aeRomain Guy        final Shader shader = paint.getShader();
1446765dcf32307dbd93ce43f064c426ce157be2d2aeRomain Guy        if (shader != null && (flags & MODIFIER_SHADER) != 0) {
1447765dcf32307dbd93ce43f064c426ce157be2d2aeRomain Guy            nSetupShader(mRenderer, shader.native_shader);
1448765dcf32307dbd93ce43f064c426ce157be2d2aeRomain Guy            modifiers |= MODIFIER_SHADER;
1449765dcf32307dbd93ce43f064c426ce157be2d2aeRomain Guy        }
1450765dcf32307dbd93ce43f064c426ce157be2d2aeRomain Guy
1451765dcf32307dbd93ce43f064c426ce157be2d2aeRomain Guy        final ColorFilter filter = paint.getColorFilter();
1452765dcf32307dbd93ce43f064c426ce157be2d2aeRomain Guy        if (filter != null && (flags & MODIFIER_COLOR_FILTER) != 0) {
1453765dcf32307dbd93ce43f064c426ce157be2d2aeRomain Guy            nSetupColorFilter(mRenderer, filter.nativeColorFilter);
1454765dcf32307dbd93ce43f064c426ce157be2d2aeRomain Guy            modifiers |= MODIFIER_COLOR_FILTER;
1455765dcf32307dbd93ce43f064c426ce157be2d2aeRomain Guy        }
1456765dcf32307dbd93ce43f064c426ce157be2d2aeRomain Guy
1457765dcf32307dbd93ce43f064c426ce157be2d2aeRomain Guy        return modifiers;
1458765dcf32307dbd93ce43f064c426ce157be2d2aeRomain Guy    }
1459765dcf32307dbd93ce43f064c426ce157be2d2aeRomain Guy
1460a168d7372132d6c87835878794b6ed43d0d282fdRomain Guy    private int setupColorFilter(Paint paint) {
1461db1938e0e6ef816e228c815adccebd5cb05f2aa8Romain Guy        final ColorFilter filter = paint.getColorFilter();
1462db1938e0e6ef816e228c815adccebd5cb05f2aa8Romain Guy        if (filter != null) {
1463db1938e0e6ef816e228c815adccebd5cb05f2aa8Romain Guy            nSetupColorFilter(mRenderer, filter.nativeColorFilter);
1464a168d7372132d6c87835878794b6ed43d0d282fdRomain Guy            return MODIFIER_COLOR_FILTER;
1465d27977d1a91d5a6b3cc9fa7664ac7e835e7bd895Romain Guy        }
146656215274f25d0040af00bf69b0df990894c0b4b0Romain Guy        return MODIFIER_NONE;
1467d27977d1a91d5a6b3cc9fa7664ac7e835e7bd895Romain Guy    }
1468a168d7372132d6c87835878794b6ed43d0d282fdRomain Guy
14697d7b5490a0b0763e831b31bc11f17d8159b5914aRomain Guy    private static native void nSetupShader(int renderer, int shader);
14707d7b5490a0b0763e831b31bc11f17d8159b5914aRomain Guy    private static native void nSetupColorFilter(int renderer, int colorFilter);
14717d7b5490a0b0763e831b31bc11f17d8159b5914aRomain Guy    private static native void nSetupShadow(int renderer, float radius,
14727d7b5490a0b0763e831b31bc11f17d8159b5914aRomain Guy            float dx, float dy, int color);
14731e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy
1474a168d7372132d6c87835878794b6ed43d0d282fdRomain Guy    private static native void nResetModifiers(int renderer, int modifiers);
1475e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy}
1476