GLES20Canvas.java revision 8aef54fa17f2a3753d9a8f2027629bc480088f69
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;
24e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guyimport android.graphics.Paint;
25e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guyimport android.graphics.Path;
26e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guyimport android.graphics.Picture;
27e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guyimport android.graphics.PorterDuff;
28e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guyimport android.graphics.Rect;
29e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guyimport android.graphics.RectF;
30e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guyimport android.graphics.Region;
31d27977d1a91d5a6b3cc9fa7664ac7e835e7bd895Romain Guyimport android.graphics.Shader;
32a1db574036c9bc2d397b69f8200594027e1fff16Romain Guyimport android.graphics.TemporaryBuffer;
33a1db574036c9bc2d397b69f8200594027e1fff16Romain Guyimport android.text.GraphicsOperations;
34a1db574036c9bc2d397b69f8200594027e1fff16Romain Guyimport android.text.SpannableString;
35a1db574036c9bc2d397b69f8200594027e1fff16Romain Guyimport android.text.SpannedString;
36a1db574036c9bc2d397b69f8200594027e1fff16Romain Guyimport android.text.TextUtils;
37e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
38e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guyimport javax.microedition.khronos.opengles.GL;
39e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
40e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy/**
41e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy * An implementation of Canvas on top of OpenGL ES 2.0.
42e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy */
43e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guyclass GLES20Canvas extends Canvas {
44e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @SuppressWarnings({"FieldCanBeLocal", "UnusedDeclaration"})
45e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    private final GL mGl;
46e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    private final boolean mOpaque;
47fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy    private int mRenderer;
48e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
49e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    private int mWidth;
50e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    private int mHeight;
51ce0537b80087a6225273040a987414b1dd081aa0Romain Guy
52ce0537b80087a6225273040a987414b1dd081aa0Romain Guy    private final float[] mPoint = new float[2];
53ce0537b80087a6225273040a987414b1dd081aa0Romain Guy    private final float[] mLine = new float[4];
546926c72e25b8dec3dd4b84af0819fa1937ae7296Romain Guy
556926c72e25b8dec3dd4b84af0819fa1937ae7296Romain Guy    private final Rect mClipBounds = new Rect();
566926c72e25b8dec3dd4b84af0819fa1937ae7296Romain Guy
576926c72e25b8dec3dd4b84af0819fa1937ae7296Romain Guy    private DrawFilter mFilter;
58da8532c6f48b4c10b5e2ccb9e08690341efa1616Romain Guy
59da8532c6f48b4c10b5e2ccb9e08690341efa1616Romain Guy    private boolean mContextLocked;
60da8532c6f48b4c10b5e2ccb9e08690341efa1616Romain Guy
61163935113919a184122b8b3bd672ef08c8df65dcRomain Guy    ///////////////////////////////////////////////////////////////////////////
62163935113919a184122b8b3bd672ef08c8df65dcRomain Guy    // JNI
63163935113919a184122b8b3bd672ef08c8df65dcRomain Guy    ///////////////////////////////////////////////////////////////////////////
64163935113919a184122b8b3bd672ef08c8df65dcRomain Guy
65163935113919a184122b8b3bd672ef08c8df65dcRomain Guy    private static native boolean nIsAvailable();
66163935113919a184122b8b3bd672ef08c8df65dcRomain Guy    private static boolean sIsAvailable = nIsAvailable();
67163935113919a184122b8b3bd672ef08c8df65dcRomain Guy
68163935113919a184122b8b3bd672ef08c8df65dcRomain Guy    static boolean isAvailable() {
69163935113919a184122b8b3bd672ef08c8df65dcRomain Guy        return sIsAvailable;
70163935113919a184122b8b3bd672ef08c8df65dcRomain Guy    }
71e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
72e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    ///////////////////////////////////////////////////////////////////////////
73e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    // Constructors
74e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    ///////////////////////////////////////////////////////////////////////////
75e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
76e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    GLES20Canvas(GL gl, boolean translucent) {
77e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy        mGl = gl;
78e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy        mOpaque = !translucent;
79e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
80e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy        mRenderer = nCreateRenderer();
81fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy        if (mRenderer == 0) {
82fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy            throw new IllegalStateException("Could not create GLES20Canvas renderer");
83fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy        }
84e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
85fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy
86e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    private native int nCreateRenderer();
87e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
88fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy    /**
89fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy     * This method <strong>must</strong> be called before releasing a
90fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy     * reference to a GLES20Canvas. This method is responsible for freeing
91fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy     * native resources associated with the hardware. Not invoking this
92fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy     * method properly can result in memory leaks.
93fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy     *
94fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy     * @hide
95fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy     */
96fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy    public synchronized void destroy() {
97fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy        if (mRenderer != 0) {
98e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy            nDestroyRenderer(mRenderer);
99fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy            mRenderer = 0;
100e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy        }
101e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
102ce0537b80087a6225273040a987414b1dd081aa0Romain Guy
103e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    private native void nDestroyRenderer(int renderer);
104e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
105e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    ///////////////////////////////////////////////////////////////////////////
106e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    // Canvas management
107e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    ///////////////////////////////////////////////////////////////////////////
108e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
109e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
110e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public boolean isHardwareAccelerated() {
111e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy        return true;
112e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
113e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
114e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
115e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public void setBitmap(Bitmap bitmap) {
116e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy        throw new UnsupportedOperationException();
117e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
118e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
119e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
120e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public boolean isOpaque() {
121e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy        return mOpaque;
122e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
123e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
124e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
125e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public int getWidth() {
126e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy        return mWidth;
127e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
128e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
129e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
130e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public int getHeight() {
131e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy        return mHeight;
132e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
133e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
134e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    ///////////////////////////////////////////////////////////////////////////
135e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    // Setup
136e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    ///////////////////////////////////////////////////////////////////////////
137e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
138e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
139e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public void setViewport(int width, int height) {
140e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy        mWidth = width;
141e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy        mHeight = height;
142e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
143e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy        nSetViewport(mRenderer, width, height);
144e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
145e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
146e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    private native void nSetViewport(int renderer, int width, int height);
147e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
148e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    void onPreDraw() {
149e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy        nPrepare(mRenderer);
150e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
151e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
152e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    private native void nPrepare(int renderer);
153e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
154da8532c6f48b4c10b5e2ccb9e08690341efa1616Romain Guy    @Override
155da8532c6f48b4c10b5e2ccb9e08690341efa1616Romain Guy    public boolean acquireContext() {
156da8532c6f48b4c10b5e2ccb9e08690341efa1616Romain Guy        if (!mContextLocked) {
157da8532c6f48b4c10b5e2ccb9e08690341efa1616Romain Guy            nAcquireContext(mRenderer);
158da8532c6f48b4c10b5e2ccb9e08690341efa1616Romain Guy            mContextLocked = true;
159da8532c6f48b4c10b5e2ccb9e08690341efa1616Romain Guy        }
160da8532c6f48b4c10b5e2ccb9e08690341efa1616Romain Guy        return mContextLocked;
161da8532c6f48b4c10b5e2ccb9e08690341efa1616Romain Guy    }
162da8532c6f48b4c10b5e2ccb9e08690341efa1616Romain Guy
163da8532c6f48b4c10b5e2ccb9e08690341efa1616Romain Guy    private native void nAcquireContext(int renderer);
164da8532c6f48b4c10b5e2ccb9e08690341efa1616Romain Guy
165da8532c6f48b4c10b5e2ccb9e08690341efa1616Romain Guy    @Override
166da8532c6f48b4c10b5e2ccb9e08690341efa1616Romain Guy    public void releaseContext() {
167da8532c6f48b4c10b5e2ccb9e08690341efa1616Romain Guy        if (mContextLocked) {
168da8532c6f48b4c10b5e2ccb9e08690341efa1616Romain Guy            nReleaseContext(mRenderer);
169da8532c6f48b4c10b5e2ccb9e08690341efa1616Romain Guy            mContextLocked = false;
170da8532c6f48b4c10b5e2ccb9e08690341efa1616Romain Guy        }
171da8532c6f48b4c10b5e2ccb9e08690341efa1616Romain Guy    }
172da8532c6f48b4c10b5e2ccb9e08690341efa1616Romain Guy
173da8532c6f48b4c10b5e2ccb9e08690341efa1616Romain Guy    private native void nReleaseContext(int renderer);
174da8532c6f48b4c10b5e2ccb9e08690341efa1616Romain Guy
175e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    ///////////////////////////////////////////////////////////////////////////
176e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    // Clipping
177e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    ///////////////////////////////////////////////////////////////////////////
178e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
179e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
180e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public boolean clipPath(Path path) {
181e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy        throw new UnsupportedOperationException();
182e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
183e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
184e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
185e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public boolean clipPath(Path path, Region.Op op) {
186e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy        throw new UnsupportedOperationException();
187e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
188e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
189e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
190e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public boolean clipRect(float left, float top, float right, float bottom) {
191079ba2c85b15e882629b8d188f5fbdb42f7f8eeaRomain Guy        return nClipRect(mRenderer, left, top, right, bottom, Region.Op.INTERSECT.nativeInt);
192e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
193bb9524b6bdddc7ac77d8628daa8b366b8a7be4a4Romain Guy
194079ba2c85b15e882629b8d188f5fbdb42f7f8eeaRomain Guy    private native boolean nClipRect(int renderer, float left, float top,
195079ba2c85b15e882629b8d188f5fbdb42f7f8eeaRomain Guy            float right, float bottom, int op);
196e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
197e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
198e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public boolean clipRect(float left, float top, float right, float bottom, Region.Op op) {
199079ba2c85b15e882629b8d188f5fbdb42f7f8eeaRomain Guy        return nClipRect(mRenderer, left, top, right, bottom, op.nativeInt);
200e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
201e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
202e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
203e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public boolean clipRect(int left, int top, int right, int bottom) {
204079ba2c85b15e882629b8d188f5fbdb42f7f8eeaRomain Guy        return nClipRect(mRenderer, left, top, right, bottom, Region.Op.INTERSECT.nativeInt);
205e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
206bb9524b6bdddc7ac77d8628daa8b366b8a7be4a4Romain Guy
207079ba2c85b15e882629b8d188f5fbdb42f7f8eeaRomain Guy    private native boolean nClipRect(int renderer, int left, int top, int right, int bottom, int op);
208e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
209e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
210e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public boolean clipRect(Rect rect) {
211079ba2c85b15e882629b8d188f5fbdb42f7f8eeaRomain Guy        return nClipRect(mRenderer, rect.left, rect.top, rect.right, rect.bottom,
212079ba2c85b15e882629b8d188f5fbdb42f7f8eeaRomain Guy                Region.Op.INTERSECT.nativeInt);
213e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
214e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
215e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
216e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public boolean clipRect(Rect rect, Region.Op op) {
217079ba2c85b15e882629b8d188f5fbdb42f7f8eeaRomain Guy        return nClipRect(mRenderer, rect.left, rect.top, rect.right, rect.bottom, op.nativeInt);
218e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
219e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
220e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
221e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public boolean clipRect(RectF rect) {
222079ba2c85b15e882629b8d188f5fbdb42f7f8eeaRomain Guy        return nClipRect(mRenderer, rect.left, rect.top, rect.right, rect.bottom,
223079ba2c85b15e882629b8d188f5fbdb42f7f8eeaRomain Guy                Region.Op.INTERSECT.nativeInt);
224e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
225e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
226e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
227e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public boolean clipRect(RectF rect, Region.Op op) {
228079ba2c85b15e882629b8d188f5fbdb42f7f8eeaRomain Guy        return nClipRect(mRenderer, rect.left, rect.top, rect.right, rect.bottom, op.nativeInt);
229e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
230e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
231e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
232e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public boolean clipRegion(Region region) {
233e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy        throw new UnsupportedOperationException();
234e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
235e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
236e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
237e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public boolean clipRegion(Region region, Region.Op op) {
238e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy        throw new UnsupportedOperationException();
239e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
240e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
241e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
242e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public boolean getClipBounds(Rect bounds) {
2439d5316e3f56d138504565ff311145ac01621dff4Romain Guy        return nGetClipBounds(mRenderer, bounds);
244e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
245e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
2469d5316e3f56d138504565ff311145ac01621dff4Romain Guy    private native boolean nGetClipBounds(int renderer, Rect bounds);
2479d5316e3f56d138504565ff311145ac01621dff4Romain Guy
248e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
249e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public boolean quickReject(float left, float top, float right, float bottom, EdgeType type) {
250c7d53494f1fbd9f9d74af89053ff9fdb1ccbac6cRomain Guy        return nQuickReject(mRenderer, left, top, right, bottom, type.nativeInt);
251e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
252c7d53494f1fbd9f9d74af89053ff9fdb1ccbac6cRomain Guy
253c7d53494f1fbd9f9d74af89053ff9fdb1ccbac6cRomain Guy    private native boolean nQuickReject(int renderer, float left, float top,
254c7d53494f1fbd9f9d74af89053ff9fdb1ccbac6cRomain Guy            float right, float bottom, int edge);
255e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
256e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
257e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public boolean quickReject(Path path, EdgeType type) {
258bb9524b6bdddc7ac77d8628daa8b366b8a7be4a4Romain Guy        throw new UnsupportedOperationException();
259e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
260e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
261e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
262e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public boolean quickReject(RectF rect, EdgeType type) {
263bb9524b6bdddc7ac77d8628daa8b366b8a7be4a4Romain Guy        return quickReject(rect.left, rect.top, rect.right, rect.bottom, type);
264e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
265e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
266e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    ///////////////////////////////////////////////////////////////////////////
267e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    // Transformations
268e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    ///////////////////////////////////////////////////////////////////////////
269e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
270e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
271e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public void translate(float dx, float dy) {
272f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy        nTranslate(mRenderer, dx, dy);
273e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
274f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy
275f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy    private native void nTranslate(int renderer, float dx, float dy);
276e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
277e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
278e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public void skew(float sx, float sy) {
279e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy        throw new UnsupportedOperationException();
280e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
281e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
282e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
283e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public void rotate(float degrees) {
284f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy        nRotate(mRenderer, degrees);
285e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
286f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy
287f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy    private native void nRotate(int renderer, float degrees);
288e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
289e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
290e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public void scale(float sx, float sy) {
291f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy        nScale(mRenderer, sx, sy);
292e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
293e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
294f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy    private native void nScale(int renderer, float sx, float sy);
295f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy
296e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
297e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public void setMatrix(Matrix matrix) {
298f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy        nSetMatrix(mRenderer, matrix.native_instance);
299e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
300f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy
301f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy    private native void nSetMatrix(int renderer, int matrix);
302e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
303e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
304f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy    public void getMatrix(Matrix matrix) {
305f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy        nGetMatrix(mRenderer, matrix.native_instance);
306e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
307f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy
308f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy    private native void nGetMatrix(int renderer, int matrix);
309e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
310e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
311e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public void concat(Matrix matrix) {
312f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy        nConcatMatrix(mRenderer, matrix.native_instance);
313e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
314e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
315f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy    private native void nConcatMatrix(int renderer, int matrix);
316f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy
317e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    ///////////////////////////////////////////////////////////////////////////
318e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    // State management
319e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    ///////////////////////////////////////////////////////////////////////////
320e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
321e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
322e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public int save() {
3238aef54fa17f2a3753d9a8f2027629bc480088f69Romain Guy        return nSave(mRenderer, Canvas.CLIP_SAVE_FLAG | Canvas.MATRIX_SAVE_FLAG);
324e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
325bb9524b6bdddc7ac77d8628daa8b366b8a7be4a4Romain Guy
326e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
327e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public int save(int saveFlags) {
328bb9524b6bdddc7ac77d8628daa8b366b8a7be4a4Romain Guy        return nSave(mRenderer, saveFlags);
329e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
330e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
331bb9524b6bdddc7ac77d8628daa8b366b8a7be4a4Romain Guy    private native int nSave(int renderer, int flags);
332bb9524b6bdddc7ac77d8628daa8b366b8a7be4a4Romain Guy
333e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
334e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public int saveLayer(RectF bounds, Paint paint, int saveFlags) {
335bd6b79b40247aea7bfe13d0831c6c0472df6c636Romain Guy        return saveLayer(bounds.left, bounds.top, bounds.right, bounds.bottom, paint, saveFlags);
336e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
337e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
338e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
339e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public int saveLayer(float left, float top, float right, float bottom, Paint paint,
340e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy            int saveFlags) {
341bd6b79b40247aea7bfe13d0831c6c0472df6c636Romain Guy        int nativePaint = paint == null ? 0 : paint.mNativePaint;
342bd6b79b40247aea7bfe13d0831c6c0472df6c636Romain Guy        return nSaveLayer(mRenderer, left, top, right, bottom, nativePaint, saveFlags);
343e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
344e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
345bd6b79b40247aea7bfe13d0831c6c0472df6c636Romain Guy    private native int nSaveLayer(int renderer, float left, float top, float right, float bottom,
346bd6b79b40247aea7bfe13d0831c6c0472df6c636Romain Guy            int paint, int saveFlags);
347bd6b79b40247aea7bfe13d0831c6c0472df6c636Romain Guy
348e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
349e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public int saveLayerAlpha(RectF bounds, int alpha, int saveFlags) {
350bd6b79b40247aea7bfe13d0831c6c0472df6c636Romain Guy        return saveLayerAlpha(bounds.left, bounds.top, bounds.right, bounds.bottom,
351bd6b79b40247aea7bfe13d0831c6c0472df6c636Romain Guy                alpha, saveFlags);
352e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
353e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
354e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
355e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public int saveLayerAlpha(float left, float top, float right, float bottom, int alpha,
356e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy            int saveFlags) {
357bd6b79b40247aea7bfe13d0831c6c0472df6c636Romain Guy        return nSaveLayerAlpha(mRenderer, left, top, right, bottom, alpha, saveFlags);
358e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
359e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
360bd6b79b40247aea7bfe13d0831c6c0472df6c636Romain Guy    private native int nSaveLayerAlpha(int renderer, float left, float top, float right,
361bd6b79b40247aea7bfe13d0831c6c0472df6c636Romain Guy            float bottom, int alpha, int saveFlags);
362bd6b79b40247aea7bfe13d0831c6c0472df6c636Romain Guy
363e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
364e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public void restore() {
365bb9524b6bdddc7ac77d8628daa8b366b8a7be4a4Romain Guy        nRestore(mRenderer);
366e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
367bb9524b6bdddc7ac77d8628daa8b366b8a7be4a4Romain Guy
368bb9524b6bdddc7ac77d8628daa8b366b8a7be4a4Romain Guy    private native void nRestore(int renderer);
369e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
370e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
371e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public void restoreToCount(int saveCount) {
372bb9524b6bdddc7ac77d8628daa8b366b8a7be4a4Romain Guy        nRestoreToCount(mRenderer, saveCount);
373e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
374e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
375bb9524b6bdddc7ac77d8628daa8b366b8a7be4a4Romain Guy    private native void nRestoreToCount(int renderer, int saveCount);
376bb9524b6bdddc7ac77d8628daa8b366b8a7be4a4Romain Guy
377e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
378e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public int getSaveCount() {
379bb9524b6bdddc7ac77d8628daa8b366b8a7be4a4Romain Guy        return nGetSaveCount(mRenderer);
380e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
381bb9524b6bdddc7ac77d8628daa8b366b8a7be4a4Romain Guy
382bb9524b6bdddc7ac77d8628daa8b366b8a7be4a4Romain Guy    private native int nGetSaveCount(int renderer);
383e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
384e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    ///////////////////////////////////////////////////////////////////////////
385e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    // Filtering
386e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    ///////////////////////////////////////////////////////////////////////////
387e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
388e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
389e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public void setDrawFilter(DrawFilter filter) {
3906926c72e25b8dec3dd4b84af0819fa1937ae7296Romain Guy        mFilter = filter;
391e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
392e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
393e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
394e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public DrawFilter getDrawFilter() {
3956926c72e25b8dec3dd4b84af0819fa1937ae7296Romain Guy        return mFilter;
396e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
397e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
398e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    ///////////////////////////////////////////////////////////////////////////
399e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    // Drawing
400e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    ///////////////////////////////////////////////////////////////////////////
401e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
402e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
403e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public void drawArc(RectF oval, float startAngle, float sweepAngle, boolean useCenter,
404e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy            Paint paint) {
405e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy        throw new UnsupportedOperationException();
406e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
407e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
408e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
409e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public void drawARGB(int a, int r, int g, int b) {
41085bf02fc16784d935fb9eebfa9cb20fe46ff7951Romain Guy        drawColor((a & 0xFF) << 24 | (r & 0xFF) << 16 | (g & 0xFF) << 8 | (b & 0xFF));
411e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
412e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
413e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
414deba785f122a47915756ffd991f5540d952cf937Romain Guy    public void drawPatch(Bitmap bitmap, byte[] chunks, RectF dst, Paint paint) {
415d27977d1a91d5a6b3cc9fa7664ac7e835e7bd895Romain Guy        // Shaders are ignored when drawing patches
416db1938e0e6ef816e228c815adccebd5cb05f2aa8Romain Guy        boolean hasColorFilter = paint != null && setupColorFilter(paint);
417deba785f122a47915756ffd991f5540d952cf937Romain Guy        final int nativePaint = paint == null ? 0 : paint.mNativePaint;
418dbd77cd444f89d94ec5333223c1bc17dbe0c90cdRomain Guy        nDrawPatch(mRenderer, bitmap.mNativeBitmap, chunks, dst.left, dst.top,
419dbd77cd444f89d94ec5333223c1bc17dbe0c90cdRomain Guy                dst.right, dst.bottom, nativePaint);
420db1938e0e6ef816e228c815adccebd5cb05f2aa8Romain Guy        if (hasColorFilter) nResetModifiers(mRenderer);
421deba785f122a47915756ffd991f5540d952cf937Romain Guy    }
422deba785f122a47915756ffd991f5540d952cf937Romain Guy
423deba785f122a47915756ffd991f5540d952cf937Romain Guy    private native void nDrawPatch(int renderer, int bitmap, byte[] chunks, float left, float top,
424dbd77cd444f89d94ec5333223c1bc17dbe0c90cdRomain Guy            float right, float bottom, int paint);
425deba785f122a47915756ffd991f5540d952cf937Romain Guy
426deba785f122a47915756ffd991f5540d952cf937Romain Guy    @Override
427e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public void drawBitmap(Bitmap bitmap, float left, float top, Paint paint) {
428d27977d1a91d5a6b3cc9fa7664ac7e835e7bd895Romain Guy        // Shaders are ignored when drawing bitmaps
429db1938e0e6ef816e228c815adccebd5cb05f2aa8Romain Guy        boolean hasColorFilter = paint != null && setupColorFilter(paint);
430ce0537b80087a6225273040a987414b1dd081aa0Romain Guy        final int nativePaint = paint == null ? 0 : paint.mNativePaint;
431dbd77cd444f89d94ec5333223c1bc17dbe0c90cdRomain Guy        nDrawBitmap(mRenderer, bitmap.mNativeBitmap, left, top, nativePaint);
432db1938e0e6ef816e228c815adccebd5cb05f2aa8Romain Guy        if (hasColorFilter) nResetModifiers(mRenderer);
433e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
434e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
435dbd77cd444f89d94ec5333223c1bc17dbe0c90cdRomain Guy    private native void nDrawBitmap(int renderer, int bitmap, float left, float top, int paint);
436dbd77cd444f89d94ec5333223c1bc17dbe0c90cdRomain Guy
437e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
438e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public void drawBitmap(Bitmap bitmap, Matrix matrix, Paint paint) {
439d27977d1a91d5a6b3cc9fa7664ac7e835e7bd895Romain Guy        // Shaders are ignored when drawing bitmaps
440db1938e0e6ef816e228c815adccebd5cb05f2aa8Romain Guy        boolean hasColorFilter = paint != null && setupColorFilter(paint);
441ce0537b80087a6225273040a987414b1dd081aa0Romain Guy        final int nativePaint = paint == null ? 0 : paint.mNativePaint;
442dbd77cd444f89d94ec5333223c1bc17dbe0c90cdRomain Guy        nDrawBitmap(mRenderer, bitmap.mNativeBitmap, matrix.native_instance, nativePaint);
443db1938e0e6ef816e228c815adccebd5cb05f2aa8Romain Guy        if (hasColorFilter) nResetModifiers(mRenderer);
444e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
445e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
446dbd77cd444f89d94ec5333223c1bc17dbe0c90cdRomain Guy    private native void nDrawBitmap(int renderer, int bitmap, int matrix, int paint);
447f86ef57f8bcd8ba43ce222ec6a8b4f67d3600640Romain Guy
448e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
449e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public void drawBitmap(Bitmap bitmap, Rect src, Rect dst, Paint paint) {
450d27977d1a91d5a6b3cc9fa7664ac7e835e7bd895Romain Guy        // Shaders are ignored when drawing bitmaps
451db1938e0e6ef816e228c815adccebd5cb05f2aa8Romain Guy        boolean hasColorFilter = paint != null && setupColorFilter(paint);
452ce0537b80087a6225273040a987414b1dd081aa0Romain Guy        final int nativePaint = paint == null ? 0 : paint.mNativePaint;
453694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
454694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        int left, top, right, bottom;
455694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        if (src == null) {
456694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy            left = top = 0;
457694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy            right = bitmap.getWidth();
458694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy            bottom = bitmap.getHeight();
459694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        } else {
460694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy            left = src.left;
461694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy            right = src.right;
462694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy            top = src.top;
463694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy            bottom = src.bottom;
464694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        }
465694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
466694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        nDrawBitmap(mRenderer, bitmap.mNativeBitmap, left, top, right, bottom,
467694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy                dst.left, dst.top, dst.right, dst.bottom, nativePaint);
468db1938e0e6ef816e228c815adccebd5cb05f2aa8Romain Guy        if (hasColorFilter) nResetModifiers(mRenderer);
469e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
470e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
471e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
472e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public void drawBitmap(Bitmap bitmap, Rect src, RectF dst, Paint paint) {
473d27977d1a91d5a6b3cc9fa7664ac7e835e7bd895Romain Guy        // Shaders are ignored when drawing bitmaps
474db1938e0e6ef816e228c815adccebd5cb05f2aa8Romain Guy        boolean hasColorFilter = paint != null && setupColorFilter(paint);
475ce0537b80087a6225273040a987414b1dd081aa0Romain Guy        final int nativePaint = paint == null ? 0 : paint.mNativePaint;
476ce0537b80087a6225273040a987414b1dd081aa0Romain Guy        nDrawBitmap(mRenderer, bitmap.mNativeBitmap, src.left, src.top, src.right, src.bottom,
477694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy                dst.left, dst.top, dst.right, dst.bottom, nativePaint);
478db1938e0e6ef816e228c815adccebd5cb05f2aa8Romain Guy        if (hasColorFilter) nResetModifiers(mRenderer);
479e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
480e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
481ce0537b80087a6225273040a987414b1dd081aa0Romain Guy    private native void nDrawBitmap(int renderer, int bitmap,
482ce0537b80087a6225273040a987414b1dd081aa0Romain Guy            float srcLeft, float srcTop, float srcRight, float srcBottom,
483dbd77cd444f89d94ec5333223c1bc17dbe0c90cdRomain Guy            float left, float top, float right, float bottom, int paint);
484ce0537b80087a6225273040a987414b1dd081aa0Romain Guy
485e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
486e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public void drawBitmap(int[] colors, int offset, int stride, float x, float y,
487e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy            int width, int height, boolean hasAlpha, Paint paint) {
488d27977d1a91d5a6b3cc9fa7664ac7e835e7bd895Romain Guy        // Shaders are ignored when drawing bitmaps
489db1938e0e6ef816e228c815adccebd5cb05f2aa8Romain Guy        boolean hasColorFilter = paint != null && setupColorFilter(paint);
4906926c72e25b8dec3dd4b84af0819fa1937ae7296Romain Guy        final Bitmap.Config config = hasAlpha ? Bitmap.Config.ARGB_8888 : Bitmap.Config.RGB_565;
4916926c72e25b8dec3dd4b84af0819fa1937ae7296Romain Guy        final Bitmap b = Bitmap.createBitmap(colors, offset, stride, width, height, config);
4926926c72e25b8dec3dd4b84af0819fa1937ae7296Romain Guy        final int nativePaint = paint == null ? 0 : paint.mNativePaint;
4936926c72e25b8dec3dd4b84af0819fa1937ae7296Romain Guy        nDrawBitmap(mRenderer, b.mNativeBitmap, x, y, nativePaint);
4946926c72e25b8dec3dd4b84af0819fa1937ae7296Romain Guy        b.recycle();
495db1938e0e6ef816e228c815adccebd5cb05f2aa8Romain Guy        if (hasColorFilter) nResetModifiers(mRenderer);
496e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
497e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
498e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
499e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public void drawBitmap(int[] colors, int offset, int stride, int x, int y,
500e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy            int width, int height, boolean hasAlpha, Paint paint) {
501d27977d1a91d5a6b3cc9fa7664ac7e835e7bd895Romain Guy        // Shaders are ignored when drawing bitmaps
502ce0537b80087a6225273040a987414b1dd081aa0Romain Guy        drawBitmap(colors, offset, stride, (float) x, (float) y, width, height, hasAlpha, paint);
503e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
504e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
505e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
506e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public void drawBitmapMesh(Bitmap bitmap, int meshWidth, int meshHeight, float[] verts,
507e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy            int vertOffset, int[] colors, int colorOffset, Paint paint) {
5086926c72e25b8dec3dd4b84af0819fa1937ae7296Romain Guy        // TODO: Implement
509e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
510e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
511e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
512e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public void drawCircle(float cx, float cy, float radius, Paint paint) {
513e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy        throw new UnsupportedOperationException();
514e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
515e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
516e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
517e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public void drawColor(int color) {
51885bf02fc16784d935fb9eebfa9cb20fe46ff7951Romain Guy        drawColor(color, PorterDuff.Mode.SRC_OVER);
519e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
520e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
521e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
522e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public void drawColor(int color, PorterDuff.Mode mode) {
52385bf02fc16784d935fb9eebfa9cb20fe46ff7951Romain Guy        nDrawColor(mRenderer, color, mode.nativeInt);
524e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
52585bf02fc16784d935fb9eebfa9cb20fe46ff7951Romain Guy
52685bf02fc16784d935fb9eebfa9cb20fe46ff7951Romain Guy    private native void nDrawColor(int renderer, int color, int mode);
527e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
528e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
529e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public void drawLine(float startX, float startY, float stopX, float stopY, Paint paint) {
530ce0537b80087a6225273040a987414b1dd081aa0Romain Guy        mLine[0] = startX;
531ce0537b80087a6225273040a987414b1dd081aa0Romain Guy        mLine[1] = startY;
532ce0537b80087a6225273040a987414b1dd081aa0Romain Guy        mLine[2] = stopX;
533ce0537b80087a6225273040a987414b1dd081aa0Romain Guy        mLine[3] = stopY;
534ce0537b80087a6225273040a987414b1dd081aa0Romain Guy        drawLines(mLine, 0, 1, paint);
535e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
536e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
537e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
538e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public void drawLines(float[] pts, int offset, int count, Paint paint) {
539e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy        // TODO: Implement
540e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
541e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
542e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
543e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public void drawLines(float[] pts, Paint paint) {
544ce0537b80087a6225273040a987414b1dd081aa0Romain Guy        drawLines(pts, 0, pts.length / 4, paint);
545e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
546e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
547e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
548e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public void drawOval(RectF oval, Paint paint) {
549e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy        throw new UnsupportedOperationException();
550e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
551e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
552e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
553e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public void drawPaint(Paint paint) {
5546926c72e25b8dec3dd4b84af0819fa1937ae7296Romain Guy        final Rect r = mClipBounds;
5556926c72e25b8dec3dd4b84af0819fa1937ae7296Romain Guy        nGetClipBounds(mRenderer, r);
5566926c72e25b8dec3dd4b84af0819fa1937ae7296Romain Guy        drawRect(r.left, r.top, r.right, r.bottom, paint);
557e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
558e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
559e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
560e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public void drawPath(Path path, Paint paint) {
5617fbcc0492fca03857e3c45064f4aa040af817d55Romain Guy        boolean hasModifier = setupModifiers(paint);
562a48a1a87ba17f20f7006eaab21dcedf86c015c13Romain Guy        if (path.isSimplePath) {
563a48a1a87ba17f20f7006eaab21dcedf86c015c13Romain Guy            if (path.rects != null) {
564a48a1a87ba17f20f7006eaab21dcedf86c015c13Romain Guy                nDrawRects(mRenderer, path.rects.mNativeRegion, paint.mNativePaint);
565a48a1a87ba17f20f7006eaab21dcedf86c015c13Romain Guy            }
566a48a1a87ba17f20f7006eaab21dcedf86c015c13Romain Guy        } else {
567a48a1a87ba17f20f7006eaab21dcedf86c015c13Romain Guy            nDrawPath(mRenderer, path.mNativePath, paint.mNativePaint);
568a48a1a87ba17f20f7006eaab21dcedf86c015c13Romain Guy        }
5697fbcc0492fca03857e3c45064f4aa040af817d55Romain Guy        if (hasModifier) nResetModifiers(mRenderer);
570e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
571e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
5727fbcc0492fca03857e3c45064f4aa040af817d55Romain Guy    private native void nDrawPath(int renderer, int path, int paint);
573a48a1a87ba17f20f7006eaab21dcedf86c015c13Romain Guy    private native void nDrawRects(int renderer, int region, int paint);
5747fbcc0492fca03857e3c45064f4aa040af817d55Romain Guy
575e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
576e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public void drawPicture(Picture picture) {
577e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy        throw new UnsupportedOperationException();
578e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
579e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
580e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
581e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public void drawPicture(Picture picture, Rect dst) {
582e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy        throw new UnsupportedOperationException();
583e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
584e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
585e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
586e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public void drawPicture(Picture picture, RectF dst) {
587e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy        throw new UnsupportedOperationException();
588e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
589e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
590e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
591e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public void drawPoint(float x, float y, Paint paint) {
592ce0537b80087a6225273040a987414b1dd081aa0Romain Guy        mPoint[0] = x;
593ce0537b80087a6225273040a987414b1dd081aa0Romain Guy        mPoint[1] = y;
594ce0537b80087a6225273040a987414b1dd081aa0Romain Guy        drawPoints(mPoint, 0, 1, paint);
595e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
596e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
597e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
598e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public void drawPoints(float[] pts, int offset, int count, Paint paint) {
599e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy        // TODO: Implement
600e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
601e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
602e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
603e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public void drawPoints(float[] pts, Paint paint) {
604ce0537b80087a6225273040a987414b1dd081aa0Romain Guy        drawPoints(pts, 0, pts.length / 2, paint);
605e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
606e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
607e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
608e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public void drawPosText(char[] text, int index, int count, float[] pos, Paint paint) {
609e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy        throw new UnsupportedOperationException();
610e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
611e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
612e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
613e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public void drawPosText(String text, float[] pos, Paint paint) {
614e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy        throw new UnsupportedOperationException();
615e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
616e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
617e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
618e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public void drawRect(float left, float top, float right, float bottom, Paint paint) {
619db1938e0e6ef816e228c815adccebd5cb05f2aa8Romain Guy        boolean hasModifier = setupModifiers(paint);
620c7d53494f1fbd9f9d74af89053ff9fdb1ccbac6cRomain Guy        nDrawRect(mRenderer, left, top, right, bottom, paint.mNativePaint);
621db1938e0e6ef816e228c815adccebd5cb05f2aa8Romain Guy        if (hasModifier) nResetModifiers(mRenderer);
622e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
623e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
624c7d53494f1fbd9f9d74af89053ff9fdb1ccbac6cRomain Guy    private native void nDrawRect(int renderer, float left, float top, float right, float bottom,
625c7d53494f1fbd9f9d74af89053ff9fdb1ccbac6cRomain Guy            int paint);
626c7d53494f1fbd9f9d74af89053ff9fdb1ccbac6cRomain Guy
627e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
628e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public void drawRect(Rect r, Paint paint) {
629c7d53494f1fbd9f9d74af89053ff9fdb1ccbac6cRomain Guy        drawRect(r.left, r.top, r.right, r.bottom, paint);
630e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
631e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
632e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
633c7d53494f1fbd9f9d74af89053ff9fdb1ccbac6cRomain Guy    public void drawRect(RectF r, Paint paint) {
634c7d53494f1fbd9f9d74af89053ff9fdb1ccbac6cRomain Guy        drawRect(r.left, r.top, r.right, r.bottom, paint);
635e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
636e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
637e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
638e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public void drawRGB(int r, int g, int b) {
63985bf02fc16784d935fb9eebfa9cb20fe46ff7951Romain Guy        drawColor(0xFF000000 | (r & 0xFF) << 16 | (g & 0xFF) << 8 | (b & 0xFF));
640e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
641e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
642e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
643e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public void drawRoundRect(RectF rect, float rx, float ry, Paint paint) {
644d27977d1a91d5a6b3cc9fa7664ac7e835e7bd895Romain Guy        // TODO: Implement
645e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
646e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
647e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
648e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public void drawText(char[] text, int index, int count, float x, float y, Paint paint) {
649a1db574036c9bc2d397b69f8200594027e1fff16Romain Guy        if ((index | count | (index + count) | (text.length - index - count)) < 0) {
650a1db574036c9bc2d397b69f8200594027e1fff16Romain Guy            throw new IndexOutOfBoundsException();
651a1db574036c9bc2d397b69f8200594027e1fff16Romain Guy        }
65261c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy
653db1938e0e6ef816e228c815adccebd5cb05f2aa8Romain Guy        boolean hasModifier = setupModifiers(paint);
65461c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy        try {
65561c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy            nDrawText(mRenderer, text, index, count, x, y, paint.mBidiFlags, paint.mNativePaint);
65661c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy        } finally {
65761c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy            if (hasModifier) nResetModifiers(mRenderer);
65861c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy        }
659e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
660a1db574036c9bc2d397b69f8200594027e1fff16Romain Guy
661a1db574036c9bc2d397b69f8200594027e1fff16Romain Guy    private native void nDrawText(int renderer, char[] text, int index, int count, float x, float y,
662a1db574036c9bc2d397b69f8200594027e1fff16Romain Guy            int bidiFlags, int paint);
663e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
664e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
665e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public void drawText(CharSequence text, int start, int end, float x, float y, Paint paint) {
666db1938e0e6ef816e228c815adccebd5cb05f2aa8Romain Guy        boolean hasModifier = setupModifiers(paint);
66761c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy        try {
66861c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy            if (text instanceof String || text instanceof SpannedString ||
66961c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy                    text instanceof SpannableString) {
67061c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy                nDrawText(mRenderer, text.toString(), start, end, x, y, paint.mBidiFlags,
67161c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy                        paint.mNativePaint);
67261c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy            } else if (text instanceof GraphicsOperations) {
67361c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy                ((GraphicsOperations) text).drawText(this, start, end, x, y,
67461c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy                                                         paint);
67561c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy            } else {
67661c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy                char[] buf = TemporaryBuffer.obtain(end - start);
67761c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy                TextUtils.getChars(text, start, end, buf, 0);
67861c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy                nDrawText(mRenderer, buf, 0, end - start, x, y, paint.mBidiFlags, paint.mNativePaint);
67961c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy                TemporaryBuffer.recycle(buf);
68061c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy            }
68161c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy        } finally {
68261c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy            if (hasModifier) nResetModifiers(mRenderer);
683a1db574036c9bc2d397b69f8200594027e1fff16Romain Guy        }
684e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
685e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
686e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
687e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public void drawText(String text, int start, int end, float x, float y, Paint paint) {
688a1db574036c9bc2d397b69f8200594027e1fff16Romain Guy        if ((start | end | (end - start) | (text.length() - end)) < 0) {
689a1db574036c9bc2d397b69f8200594027e1fff16Romain Guy            throw new IndexOutOfBoundsException();
690a1db574036c9bc2d397b69f8200594027e1fff16Romain Guy        }
69161c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy
692db1938e0e6ef816e228c815adccebd5cb05f2aa8Romain Guy        boolean hasModifier = setupModifiers(paint);
69361c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy        try {
69461c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy            nDrawText(mRenderer, text, start, end, x, y, paint.mBidiFlags, paint.mNativePaint);
69561c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy        } finally {
69661c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy            if (hasModifier) nResetModifiers(mRenderer);
69761c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy        }
698e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
699e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
700a1db574036c9bc2d397b69f8200594027e1fff16Romain Guy    private native void nDrawText(int renderer, String text, int start, int end, float x, float y,
701a1db574036c9bc2d397b69f8200594027e1fff16Romain Guy            int bidiFlags, int paint);
702a1db574036c9bc2d397b69f8200594027e1fff16Romain Guy
703e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
704e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public void drawText(String text, float x, float y, Paint paint) {
705db1938e0e6ef816e228c815adccebd5cb05f2aa8Romain Guy        boolean hasModifier = setupModifiers(paint);
70661c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy        try {
70761c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy            nDrawText(mRenderer, text, 0, text.length(), x, y, paint.mBidiFlags,
70861c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy                    paint.mNativePaint);
70961c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy        } finally {
71061c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy            if (hasModifier) nResetModifiers(mRenderer);
71161c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy        }
712e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
713e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
714e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
715e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public void drawTextOnPath(char[] text, int index, int count, Path path, float hOffset,
716e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy            float vOffset, Paint paint) {
717e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy        throw new UnsupportedOperationException();
718e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
719e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
720e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
721e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public void drawTextOnPath(String text, Path path, float hOffset, float vOffset, Paint paint) {
722e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy        throw new UnsupportedOperationException();
723e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
724e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
725e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
726e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public void drawTextRun(char[] text, int index, int count, int contextIndex, int contextCount,
727e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy            float x, float y, int dir, Paint paint) {
72861c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy        if ((index | count | text.length - index - count) < 0) {
72961c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy            throw new IndexOutOfBoundsException();
73061c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy        }
73161c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy        if (dir != DIRECTION_LTR && dir != DIRECTION_RTL) {
73261c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy            throw new IllegalArgumentException("Unknown direction: " + dir);
73361c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy        }
73461c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy
73561c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy        boolean hasModifier = setupModifiers(paint);
73661c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy        try {
73761c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy            nDrawTextRun(mRenderer, text, index, count, contextIndex, contextCount, x, y, dir,
73861c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy                    paint.mNativePaint);
73961c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy        } finally {
74061c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy            if (hasModifier) nResetModifiers(mRenderer);
74161c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy        }
742e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
743e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
74461c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy    private native void nDrawTextRun(int renderer, char[] text, int index, int count,
74561c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy            int contextIndex, int contextCount, float x, float y, int dir, int nativePaint);
74661c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy
747e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
748e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public void drawTextRun(CharSequence text, int start, int end, int contextStart, int contextEnd,
749e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy            float x, float y, int dir, Paint paint) {
75061c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy        if ((start | end | end - start | text.length() - end) < 0) {
75161c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy            throw new IndexOutOfBoundsException();
75261c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy        }
75361c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy
75461c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy        boolean hasModifier = setupModifiers(paint);
75561c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy        try {
75661c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy            int flags = dir == 0 ? 0 : 1;
75761c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy            if (text instanceof String || text instanceof SpannedString ||
75861c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy                    text instanceof SpannableString) {
75961c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy                nDrawTextRun(mRenderer, text.toString(), start, end, contextStart,
76061c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy                        contextEnd, x, y, flags, paint.mNativePaint);
76161c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy            } else if (text instanceof GraphicsOperations) {
76261c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy                ((GraphicsOperations) text).drawTextRun(this, start, end,
76361c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy                        contextStart, contextEnd, x, y, flags, paint);
76461c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy            } else {
76561c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy                int contextLen = contextEnd - contextStart;
76661c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy                int len = end - start;
76761c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy                char[] buf = TemporaryBuffer.obtain(contextLen);
76861c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy                TextUtils.getChars(text, contextStart, contextEnd, buf, 0);
76961c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy                nDrawTextRun(mRenderer, buf, start - contextStart, len, 0, contextLen,
77061c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy                        x, y, flags, paint.mNativePaint);
77161c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy                TemporaryBuffer.recycle(buf);
77261c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy            }
77361c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy        } finally {
77461c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy            if (hasModifier) nResetModifiers(mRenderer);
77561c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy        }
776e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
777e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
77861c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy    private native void nDrawTextRun(int renderer, String text, int start, int end,
77961c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy            int contextStart, int contextEnd, float x, float y, int flags, int nativePaint);
78061c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy
781e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
782e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public void drawVertices(VertexMode mode, int vertexCount, float[] verts, int vertOffset,
783e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy            float[] texs, int texOffset, int[] colors, int colorOffset, short[] indices,
784e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy            int indexOffset, int indexCount, Paint paint) {
7856926c72e25b8dec3dd4b84af0819fa1937ae7296Romain Guy        // TODO: Implement
786e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
787d27977d1a91d5a6b3cc9fa7664ac7e835e7bd895Romain Guy
788db1938e0e6ef816e228c815adccebd5cb05f2aa8Romain Guy    private boolean setupModifiers(Paint paint) {
789db1938e0e6ef816e228c815adccebd5cb05f2aa8Romain Guy        boolean hasModifier = false;
790db1938e0e6ef816e228c815adccebd5cb05f2aa8Romain Guy
7911e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy        if (paint.hasShadow) {
7921e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy            nSetupShadow(mRenderer, paint.shadowRadius, paint.shadowDx, paint.shadowDy,
7931e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy                    paint.shadowColor);
7941e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy            hasModifier = true;
7951e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy        }
7961e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy
797d27977d1a91d5a6b3cc9fa7664ac7e835e7bd895Romain Guy        final Shader shader = paint.getShader();
798d27977d1a91d5a6b3cc9fa7664ac7e835e7bd895Romain Guy        if (shader != null) {
79906f96e2652e4855b6520ad9dd70583677605b79aRomain Guy            nSetupShader(mRenderer, shader.native_shader);
800db1938e0e6ef816e228c815adccebd5cb05f2aa8Romain Guy            hasModifier = true;
801db1938e0e6ef816e228c815adccebd5cb05f2aa8Romain Guy        }
802db1938e0e6ef816e228c815adccebd5cb05f2aa8Romain Guy
803db1938e0e6ef816e228c815adccebd5cb05f2aa8Romain Guy        final ColorFilter filter = paint.getColorFilter();
804db1938e0e6ef816e228c815adccebd5cb05f2aa8Romain Guy        if (filter != null) {
805db1938e0e6ef816e228c815adccebd5cb05f2aa8Romain Guy            nSetupColorFilter(mRenderer, filter.nativeColorFilter);
806db1938e0e6ef816e228c815adccebd5cb05f2aa8Romain Guy            hasModifier = true;
807db1938e0e6ef816e228c815adccebd5cb05f2aa8Romain Guy        }
808db1938e0e6ef816e228c815adccebd5cb05f2aa8Romain Guy
809db1938e0e6ef816e228c815adccebd5cb05f2aa8Romain Guy        return hasModifier;
810db1938e0e6ef816e228c815adccebd5cb05f2aa8Romain Guy    }
8111e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy
812db1938e0e6ef816e228c815adccebd5cb05f2aa8Romain Guy    private boolean setupColorFilter(Paint paint) {
813db1938e0e6ef816e228c815adccebd5cb05f2aa8Romain Guy        final ColorFilter filter = paint.getColorFilter();
814db1938e0e6ef816e228c815adccebd5cb05f2aa8Romain Guy        if (filter != null) {
815db1938e0e6ef816e228c815adccebd5cb05f2aa8Romain Guy            nSetupColorFilter(mRenderer, filter.nativeColorFilter);
81606f96e2652e4855b6520ad9dd70583677605b79aRomain Guy            return true;
817d27977d1a91d5a6b3cc9fa7664ac7e835e7bd895Romain Guy        }
818db1938e0e6ef816e228c815adccebd5cb05f2aa8Romain Guy        return false;
819d27977d1a91d5a6b3cc9fa7664ac7e835e7bd895Romain Guy    }
820db1938e0e6ef816e228c815adccebd5cb05f2aa8Romain Guy
82106f96e2652e4855b6520ad9dd70583677605b79aRomain Guy    private native void nSetupShader(int renderer, int shader);
822db1938e0e6ef816e228c815adccebd5cb05f2aa8Romain Guy    private native void nSetupColorFilter(int renderer, int colorFilter);
8231e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy    private native void nSetupShadow(int renderer, float radius, float dx, float dy, int color);
8241e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy
825db1938e0e6ef816e228c815adccebd5cb05f2aa8Romain Guy    private native void nResetModifiers(int renderer);
826e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy}
827