GLES20Canvas.java revision 1e45aae5de003657e5d18f74d34998f5de5db5b7
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;
47e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    private final 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;
58163935113919a184122b8b3bd672ef08c8df65dcRomain Guy
59163935113919a184122b8b3bd672ef08c8df65dcRomain Guy    ///////////////////////////////////////////////////////////////////////////
60163935113919a184122b8b3bd672ef08c8df65dcRomain Guy    // JNI
61163935113919a184122b8b3bd672ef08c8df65dcRomain Guy    ///////////////////////////////////////////////////////////////////////////
62163935113919a184122b8b3bd672ef08c8df65dcRomain Guy
63163935113919a184122b8b3bd672ef08c8df65dcRomain Guy    private static native boolean nIsAvailable();
64163935113919a184122b8b3bd672ef08c8df65dcRomain Guy    private static boolean sIsAvailable = nIsAvailable();
65163935113919a184122b8b3bd672ef08c8df65dcRomain Guy
66163935113919a184122b8b3bd672ef08c8df65dcRomain Guy    static boolean isAvailable() {
67163935113919a184122b8b3bd672ef08c8df65dcRomain Guy        return sIsAvailable;
68163935113919a184122b8b3bd672ef08c8df65dcRomain Guy    }
69e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
70e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    ///////////////////////////////////////////////////////////////////////////
71e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    // Constructors
72e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    ///////////////////////////////////////////////////////////////////////////
73e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
74e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    GLES20Canvas(GL gl, boolean translucent) {
75e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy        mGl = gl;
76e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy        mOpaque = !translucent;
77e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
78e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy        mRenderer = nCreateRenderer();
79e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
80e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
81e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    private native int nCreateRenderer();
82e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
83e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
84e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    protected void finalize() throws Throwable {
85e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy        try {
86e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy            super.finalize();
87e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy        } finally {
88e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy            nDestroyRenderer(mRenderer);
89e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy        }
90e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
91ce0537b80087a6225273040a987414b1dd081aa0Romain Guy
92e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    private native void nDestroyRenderer(int renderer);
93e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
94e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    ///////////////////////////////////////////////////////////////////////////
95e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    // Canvas management
96e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    ///////////////////////////////////////////////////////////////////////////
97e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
98e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
99e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public boolean isHardwareAccelerated() {
100e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy        return true;
101e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
102e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
103e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
104e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public void setBitmap(Bitmap bitmap) {
105e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy        throw new UnsupportedOperationException();
106e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
107e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
108e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
109e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public boolean isOpaque() {
110e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy        return mOpaque;
111e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
112e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
113e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
114e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public int getWidth() {
115e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy        return mWidth;
116e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
117e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
118e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
119e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public int getHeight() {
120e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy        return mHeight;
121e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
122e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
123e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    ///////////////////////////////////////////////////////////////////////////
124e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    // Setup
125e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    ///////////////////////////////////////////////////////////////////////////
126e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
127e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
128e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public void setViewport(int width, int height) {
129e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy        mWidth = width;
130e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy        mHeight = height;
131e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
132e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy        nSetViewport(mRenderer, width, height);
133e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
134e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
135e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    private native void nSetViewport(int renderer, int width, int height);
136e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
137e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    void onPreDraw() {
138e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy        nPrepare(mRenderer);
139e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
140e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
141e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    private native void nPrepare(int renderer);
142e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
143e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    ///////////////////////////////////////////////////////////////////////////
144e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    // Clipping
145e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    ///////////////////////////////////////////////////////////////////////////
146e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
147e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
148e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public boolean clipPath(Path path) {
149e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy        throw new UnsupportedOperationException();
150e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
151e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
152e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
153e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public boolean clipPath(Path path, Region.Op op) {
154e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy        throw new UnsupportedOperationException();
155e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
156e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
157e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
158e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public boolean clipRect(float left, float top, float right, float bottom) {
159079ba2c85b15e882629b8d188f5fbdb42f7f8eeaRomain Guy        return nClipRect(mRenderer, left, top, right, bottom, Region.Op.INTERSECT.nativeInt);
160e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
161bb9524b6bdddc7ac77d8628daa8b366b8a7be4a4Romain Guy
162079ba2c85b15e882629b8d188f5fbdb42f7f8eeaRomain Guy    private native boolean nClipRect(int renderer, float left, float top,
163079ba2c85b15e882629b8d188f5fbdb42f7f8eeaRomain Guy            float right, float bottom, int op);
164e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
165e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
166e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public boolean clipRect(float left, float top, float right, float bottom, Region.Op op) {
167079ba2c85b15e882629b8d188f5fbdb42f7f8eeaRomain Guy        return nClipRect(mRenderer, left, top, right, bottom, op.nativeInt);
168e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
169e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
170e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
171e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public boolean clipRect(int left, int top, int right, int bottom) {
172079ba2c85b15e882629b8d188f5fbdb42f7f8eeaRomain Guy        return nClipRect(mRenderer, left, top, right, bottom, Region.Op.INTERSECT.nativeInt);
173e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
174bb9524b6bdddc7ac77d8628daa8b366b8a7be4a4Romain Guy
175079ba2c85b15e882629b8d188f5fbdb42f7f8eeaRomain Guy    private native boolean nClipRect(int renderer, int left, int top, int right, int bottom, int op);
176e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
177e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
178e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public boolean clipRect(Rect rect) {
179079ba2c85b15e882629b8d188f5fbdb42f7f8eeaRomain Guy        return nClipRect(mRenderer, rect.left, rect.top, rect.right, rect.bottom,
180079ba2c85b15e882629b8d188f5fbdb42f7f8eeaRomain Guy                Region.Op.INTERSECT.nativeInt);
181e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
182e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
183e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
184e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public boolean clipRect(Rect rect, Region.Op op) {
185079ba2c85b15e882629b8d188f5fbdb42f7f8eeaRomain Guy        return nClipRect(mRenderer, rect.left, rect.top, rect.right, rect.bottom, op.nativeInt);
186e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
187e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
188e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
189e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public boolean clipRect(RectF rect) {
190079ba2c85b15e882629b8d188f5fbdb42f7f8eeaRomain Guy        return nClipRect(mRenderer, rect.left, rect.top, rect.right, rect.bottom,
191079ba2c85b15e882629b8d188f5fbdb42f7f8eeaRomain Guy                Region.Op.INTERSECT.nativeInt);
192e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
193e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
194e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
195e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public boolean clipRect(RectF rect, Region.Op op) {
196079ba2c85b15e882629b8d188f5fbdb42f7f8eeaRomain Guy        return nClipRect(mRenderer, rect.left, rect.top, rect.right, rect.bottom, op.nativeInt);
197e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
198e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
199e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
200e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public boolean clipRegion(Region region) {
201e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy        throw new UnsupportedOperationException();
202e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
203e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
204e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
205e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public boolean clipRegion(Region region, Region.Op op) {
206e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy        throw new UnsupportedOperationException();
207e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
208e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
209e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
210e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public boolean getClipBounds(Rect bounds) {
2119d5316e3f56d138504565ff311145ac01621dff4Romain Guy        return nGetClipBounds(mRenderer, bounds);
212e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
213e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
2149d5316e3f56d138504565ff311145ac01621dff4Romain Guy    private native boolean nGetClipBounds(int renderer, Rect bounds);
2159d5316e3f56d138504565ff311145ac01621dff4Romain Guy
216e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
217e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public boolean quickReject(float left, float top, float right, float bottom, EdgeType type) {
218c7d53494f1fbd9f9d74af89053ff9fdb1ccbac6cRomain Guy        return nQuickReject(mRenderer, left, top, right, bottom, type.nativeInt);
219e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
220c7d53494f1fbd9f9d74af89053ff9fdb1ccbac6cRomain Guy
221c7d53494f1fbd9f9d74af89053ff9fdb1ccbac6cRomain Guy    private native boolean nQuickReject(int renderer, float left, float top,
222c7d53494f1fbd9f9d74af89053ff9fdb1ccbac6cRomain Guy            float right, float bottom, int edge);
223e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
224e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
225e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public boolean quickReject(Path path, EdgeType type) {
226bb9524b6bdddc7ac77d8628daa8b366b8a7be4a4Romain Guy        throw new UnsupportedOperationException();
227e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
228e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
229e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
230e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public boolean quickReject(RectF rect, EdgeType type) {
231bb9524b6bdddc7ac77d8628daa8b366b8a7be4a4Romain Guy        return quickReject(rect.left, rect.top, rect.right, rect.bottom, type);
232e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
233e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
234e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    ///////////////////////////////////////////////////////////////////////////
235e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    // Transformations
236e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    ///////////////////////////////////////////////////////////////////////////
237e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
238e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
239e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public void translate(float dx, float dy) {
240f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy        nTranslate(mRenderer, dx, dy);
241e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
242f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy
243f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy    private native void nTranslate(int renderer, float dx, float dy);
244e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
245e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
246e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public void skew(float sx, float sy) {
247e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy        throw new UnsupportedOperationException();
248e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
249e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
250e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
251e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public void rotate(float degrees) {
252f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy        nRotate(mRenderer, degrees);
253e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
254f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy
255f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy    private native void nRotate(int renderer, float degrees);
256e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
257e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
258e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public void scale(float sx, float sy) {
259f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy        nScale(mRenderer, sx, sy);
260e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
261e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
262f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy    private native void nScale(int renderer, float sx, float sy);
263f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy
264e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
265e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public void setMatrix(Matrix matrix) {
266f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy        nSetMatrix(mRenderer, matrix.native_instance);
267e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
268f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy
269f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy    private native void nSetMatrix(int renderer, int matrix);
270e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
271e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
272f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy    public void getMatrix(Matrix matrix) {
273f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy        nGetMatrix(mRenderer, matrix.native_instance);
274e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
275f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy
276f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy    private native void nGetMatrix(int renderer, int matrix);
277e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
278e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
279e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public void concat(Matrix matrix) {
280f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy        nConcatMatrix(mRenderer, matrix.native_instance);
281e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
282e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
283f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy    private native void nConcatMatrix(int renderer, int matrix);
284f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy
285e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    ///////////////////////////////////////////////////////////////////////////
286e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    // State management
287e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    ///////////////////////////////////////////////////////////////////////////
288e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
289e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
290e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public int save() {
291bb9524b6bdddc7ac77d8628daa8b366b8a7be4a4Romain Guy        return nSave(mRenderer, 0);
292e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
293bb9524b6bdddc7ac77d8628daa8b366b8a7be4a4Romain Guy
294e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
295e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public int save(int saveFlags) {
296bb9524b6bdddc7ac77d8628daa8b366b8a7be4a4Romain Guy        return nSave(mRenderer, saveFlags);
297e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
298e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
299bb9524b6bdddc7ac77d8628daa8b366b8a7be4a4Romain Guy    private native int nSave(int renderer, int flags);
300bb9524b6bdddc7ac77d8628daa8b366b8a7be4a4Romain Guy
301e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
302e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public int saveLayer(RectF bounds, Paint paint, int saveFlags) {
303bd6b79b40247aea7bfe13d0831c6c0472df6c636Romain Guy        return saveLayer(bounds.left, bounds.top, bounds.right, bounds.bottom, paint, saveFlags);
304e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
305e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
306e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
307e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public int saveLayer(float left, float top, float right, float bottom, Paint paint,
308e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy            int saveFlags) {
309bd6b79b40247aea7bfe13d0831c6c0472df6c636Romain Guy        int nativePaint = paint == null ? 0 : paint.mNativePaint;
310bd6b79b40247aea7bfe13d0831c6c0472df6c636Romain Guy        return nSaveLayer(mRenderer, left, top, right, bottom, nativePaint, saveFlags);
311e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
312e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
313bd6b79b40247aea7bfe13d0831c6c0472df6c636Romain Guy    private native int nSaveLayer(int renderer, float left, float top, float right, float bottom,
314bd6b79b40247aea7bfe13d0831c6c0472df6c636Romain Guy            int paint, int saveFlags);
315bd6b79b40247aea7bfe13d0831c6c0472df6c636Romain Guy
316e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
317e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public int saveLayerAlpha(RectF bounds, int alpha, int saveFlags) {
318bd6b79b40247aea7bfe13d0831c6c0472df6c636Romain Guy        return saveLayerAlpha(bounds.left, bounds.top, bounds.right, bounds.bottom,
319bd6b79b40247aea7bfe13d0831c6c0472df6c636Romain Guy                alpha, saveFlags);
320e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
321e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
322e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
323e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public int saveLayerAlpha(float left, float top, float right, float bottom, int alpha,
324e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy            int saveFlags) {
325bd6b79b40247aea7bfe13d0831c6c0472df6c636Romain Guy        return nSaveLayerAlpha(mRenderer, left, top, right, bottom, alpha, saveFlags);
326e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
327e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
328bd6b79b40247aea7bfe13d0831c6c0472df6c636Romain Guy    private native int nSaveLayerAlpha(int renderer, float left, float top, float right,
329bd6b79b40247aea7bfe13d0831c6c0472df6c636Romain Guy            float bottom, int alpha, int saveFlags);
330bd6b79b40247aea7bfe13d0831c6c0472df6c636Romain Guy
331e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
332e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public void restore() {
333bb9524b6bdddc7ac77d8628daa8b366b8a7be4a4Romain Guy        nRestore(mRenderer);
334e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
335bb9524b6bdddc7ac77d8628daa8b366b8a7be4a4Romain Guy
336bb9524b6bdddc7ac77d8628daa8b366b8a7be4a4Romain Guy    private native void nRestore(int renderer);
337e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
338e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
339e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public void restoreToCount(int saveCount) {
340bb9524b6bdddc7ac77d8628daa8b366b8a7be4a4Romain Guy        nRestoreToCount(mRenderer, saveCount);
341e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
342e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
343bb9524b6bdddc7ac77d8628daa8b366b8a7be4a4Romain Guy    private native void nRestoreToCount(int renderer, int saveCount);
344bb9524b6bdddc7ac77d8628daa8b366b8a7be4a4Romain Guy
345e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
346e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public int getSaveCount() {
347bb9524b6bdddc7ac77d8628daa8b366b8a7be4a4Romain Guy        return nGetSaveCount(mRenderer);
348e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
349bb9524b6bdddc7ac77d8628daa8b366b8a7be4a4Romain Guy
350bb9524b6bdddc7ac77d8628daa8b366b8a7be4a4Romain Guy    private native int nGetSaveCount(int renderer);
351e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
352e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    ///////////////////////////////////////////////////////////////////////////
353e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    // Filtering
354e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    ///////////////////////////////////////////////////////////////////////////
355e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
356e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
357e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public void setDrawFilter(DrawFilter filter) {
3586926c72e25b8dec3dd4b84af0819fa1937ae7296Romain Guy        mFilter = filter;
359e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
360e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
361e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
362e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public DrawFilter getDrawFilter() {
3636926c72e25b8dec3dd4b84af0819fa1937ae7296Romain Guy        return mFilter;
364e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
365e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
366e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    ///////////////////////////////////////////////////////////////////////////
367e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    // Drawing
368e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    ///////////////////////////////////////////////////////////////////////////
369e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
370e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
371e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public void drawArc(RectF oval, float startAngle, float sweepAngle, boolean useCenter,
372e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy            Paint paint) {
373e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy        throw new UnsupportedOperationException();
374e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
375e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
376e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
377e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public void drawARGB(int a, int r, int g, int b) {
37885bf02fc16784d935fb9eebfa9cb20fe46ff7951Romain Guy        drawColor((a & 0xFF) << 24 | (r & 0xFF) << 16 | (g & 0xFF) << 8 | (b & 0xFF));
379e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
380e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
381e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
382deba785f122a47915756ffd991f5540d952cf937Romain Guy    public void drawPatch(Bitmap bitmap, byte[] chunks, RectF dst, Paint paint) {
383d27977d1a91d5a6b3cc9fa7664ac7e835e7bd895Romain Guy        // Shaders are ignored when drawing patches
384db1938e0e6ef816e228c815adccebd5cb05f2aa8Romain Guy        boolean hasColorFilter = paint != null && setupColorFilter(paint);
385deba785f122a47915756ffd991f5540d952cf937Romain Guy        final int nativePaint = paint == null ? 0 : paint.mNativePaint;
386dbd77cd444f89d94ec5333223c1bc17dbe0c90cdRomain Guy        nDrawPatch(mRenderer, bitmap.mNativeBitmap, chunks, dst.left, dst.top,
387dbd77cd444f89d94ec5333223c1bc17dbe0c90cdRomain Guy                dst.right, dst.bottom, nativePaint);
388db1938e0e6ef816e228c815adccebd5cb05f2aa8Romain Guy        if (hasColorFilter) nResetModifiers(mRenderer);
389deba785f122a47915756ffd991f5540d952cf937Romain Guy    }
390deba785f122a47915756ffd991f5540d952cf937Romain Guy
391deba785f122a47915756ffd991f5540d952cf937Romain Guy    private native void nDrawPatch(int renderer, int bitmap, byte[] chunks, float left, float top,
392dbd77cd444f89d94ec5333223c1bc17dbe0c90cdRomain Guy            float right, float bottom, int paint);
393deba785f122a47915756ffd991f5540d952cf937Romain Guy
394deba785f122a47915756ffd991f5540d952cf937Romain Guy    @Override
395e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public void drawBitmap(Bitmap bitmap, float left, float top, Paint paint) {
396d27977d1a91d5a6b3cc9fa7664ac7e835e7bd895Romain Guy        // Shaders are ignored when drawing bitmaps
397db1938e0e6ef816e228c815adccebd5cb05f2aa8Romain Guy        boolean hasColorFilter = paint != null && setupColorFilter(paint);
398ce0537b80087a6225273040a987414b1dd081aa0Romain Guy        final int nativePaint = paint == null ? 0 : paint.mNativePaint;
399dbd77cd444f89d94ec5333223c1bc17dbe0c90cdRomain Guy        nDrawBitmap(mRenderer, bitmap.mNativeBitmap, left, top, nativePaint);
400db1938e0e6ef816e228c815adccebd5cb05f2aa8Romain Guy        if (hasColorFilter) nResetModifiers(mRenderer);
401e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
402e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
403dbd77cd444f89d94ec5333223c1bc17dbe0c90cdRomain Guy    private native void nDrawBitmap(int renderer, int bitmap, float left, float top, int paint);
404dbd77cd444f89d94ec5333223c1bc17dbe0c90cdRomain Guy
405e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
406e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public void drawBitmap(Bitmap bitmap, Matrix matrix, Paint paint) {
407d27977d1a91d5a6b3cc9fa7664ac7e835e7bd895Romain Guy        // Shaders are ignored when drawing bitmaps
408db1938e0e6ef816e228c815adccebd5cb05f2aa8Romain Guy        boolean hasColorFilter = paint != null && setupColorFilter(paint);
409ce0537b80087a6225273040a987414b1dd081aa0Romain Guy        final int nativePaint = paint == null ? 0 : paint.mNativePaint;
410dbd77cd444f89d94ec5333223c1bc17dbe0c90cdRomain Guy        nDrawBitmap(mRenderer, bitmap.mNativeBitmap, matrix.native_instance, nativePaint);
411db1938e0e6ef816e228c815adccebd5cb05f2aa8Romain Guy        if (hasColorFilter) nResetModifiers(mRenderer);
412e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
413e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
414dbd77cd444f89d94ec5333223c1bc17dbe0c90cdRomain Guy    private native void nDrawBitmap(int renderer, int bitmap, int matrix, int paint);
415f86ef57f8bcd8ba43ce222ec6a8b4f67d3600640Romain Guy
416e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
417e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public void drawBitmap(Bitmap bitmap, Rect src, Rect dst, Paint paint) {
418d27977d1a91d5a6b3cc9fa7664ac7e835e7bd895Romain Guy        // Shaders are ignored when drawing bitmaps
419db1938e0e6ef816e228c815adccebd5cb05f2aa8Romain Guy        boolean hasColorFilter = paint != null && setupColorFilter(paint);
420ce0537b80087a6225273040a987414b1dd081aa0Romain Guy        final int nativePaint = paint == null ? 0 : paint.mNativePaint;
421694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
422694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        int left, top, right, bottom;
423694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        if (src == null) {
424694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy            left = top = 0;
425694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy            right = bitmap.getWidth();
426694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy            bottom = bitmap.getHeight();
427694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        } else {
428694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy            left = src.left;
429694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy            right = src.right;
430694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy            top = src.top;
431694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy            bottom = src.bottom;
432694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        }
433694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
434694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        nDrawBitmap(mRenderer, bitmap.mNativeBitmap, left, top, right, bottom,
435694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy                dst.left, dst.top, dst.right, dst.bottom, nativePaint);
436db1938e0e6ef816e228c815adccebd5cb05f2aa8Romain Guy        if (hasColorFilter) nResetModifiers(mRenderer);
437e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
438e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
439e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
440e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public void drawBitmap(Bitmap bitmap, Rect src, RectF dst, Paint paint) {
441d27977d1a91d5a6b3cc9fa7664ac7e835e7bd895Romain Guy        // Shaders are ignored when drawing bitmaps
442db1938e0e6ef816e228c815adccebd5cb05f2aa8Romain Guy        boolean hasColorFilter = paint != null && setupColorFilter(paint);
443ce0537b80087a6225273040a987414b1dd081aa0Romain Guy        final int nativePaint = paint == null ? 0 : paint.mNativePaint;
444ce0537b80087a6225273040a987414b1dd081aa0Romain Guy        nDrawBitmap(mRenderer, bitmap.mNativeBitmap, src.left, src.top, src.right, src.bottom,
445694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy                dst.left, dst.top, dst.right, dst.bottom, nativePaint);
446db1938e0e6ef816e228c815adccebd5cb05f2aa8Romain Guy        if (hasColorFilter) nResetModifiers(mRenderer);
447e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
448e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
449ce0537b80087a6225273040a987414b1dd081aa0Romain Guy    private native void nDrawBitmap(int renderer, int bitmap,
450ce0537b80087a6225273040a987414b1dd081aa0Romain Guy            float srcLeft, float srcTop, float srcRight, float srcBottom,
451dbd77cd444f89d94ec5333223c1bc17dbe0c90cdRomain Guy            float left, float top, float right, float bottom, int paint);
452ce0537b80087a6225273040a987414b1dd081aa0Romain Guy
453e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
454e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public void drawBitmap(int[] colors, int offset, int stride, float x, float y,
455e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy            int width, int height, boolean hasAlpha, Paint paint) {
456d27977d1a91d5a6b3cc9fa7664ac7e835e7bd895Romain Guy        // Shaders are ignored when drawing bitmaps
457db1938e0e6ef816e228c815adccebd5cb05f2aa8Romain Guy        boolean hasColorFilter = paint != null && setupColorFilter(paint);
4586926c72e25b8dec3dd4b84af0819fa1937ae7296Romain Guy        final Bitmap.Config config = hasAlpha ? Bitmap.Config.ARGB_8888 : Bitmap.Config.RGB_565;
4596926c72e25b8dec3dd4b84af0819fa1937ae7296Romain Guy        final Bitmap b = Bitmap.createBitmap(colors, offset, stride, width, height, config);
4606926c72e25b8dec3dd4b84af0819fa1937ae7296Romain Guy        final int nativePaint = paint == null ? 0 : paint.mNativePaint;
4616926c72e25b8dec3dd4b84af0819fa1937ae7296Romain Guy        nDrawBitmap(mRenderer, b.mNativeBitmap, x, y, nativePaint);
4626926c72e25b8dec3dd4b84af0819fa1937ae7296Romain Guy        b.recycle();
463db1938e0e6ef816e228c815adccebd5cb05f2aa8Romain Guy        if (hasColorFilter) nResetModifiers(mRenderer);
464e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
465e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
466e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
467e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public void drawBitmap(int[] colors, int offset, int stride, int x, int y,
468e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy            int width, int height, boolean hasAlpha, Paint paint) {
469d27977d1a91d5a6b3cc9fa7664ac7e835e7bd895Romain Guy        // Shaders are ignored when drawing bitmaps
470ce0537b80087a6225273040a987414b1dd081aa0Romain Guy        drawBitmap(colors, offset, stride, (float) x, (float) y, width, height, hasAlpha, paint);
471e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
472e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
473e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
474e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public void drawBitmapMesh(Bitmap bitmap, int meshWidth, int meshHeight, float[] verts,
475e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy            int vertOffset, int[] colors, int colorOffset, Paint paint) {
4766926c72e25b8dec3dd4b84af0819fa1937ae7296Romain Guy        // TODO: Implement
477e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
478e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
479e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
480e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public void drawCircle(float cx, float cy, float radius, Paint paint) {
481e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy        throw new UnsupportedOperationException();
482e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
483e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
484e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
485e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public void drawColor(int color) {
48685bf02fc16784d935fb9eebfa9cb20fe46ff7951Romain Guy        drawColor(color, PorterDuff.Mode.SRC_OVER);
487e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
488e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
489e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
490e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public void drawColor(int color, PorterDuff.Mode mode) {
49185bf02fc16784d935fb9eebfa9cb20fe46ff7951Romain Guy        nDrawColor(mRenderer, color, mode.nativeInt);
492e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
49385bf02fc16784d935fb9eebfa9cb20fe46ff7951Romain Guy
49485bf02fc16784d935fb9eebfa9cb20fe46ff7951Romain Guy    private native void nDrawColor(int renderer, int color, int mode);
495e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
496e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
497e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public void drawLine(float startX, float startY, float stopX, float stopY, Paint paint) {
498ce0537b80087a6225273040a987414b1dd081aa0Romain Guy        mLine[0] = startX;
499ce0537b80087a6225273040a987414b1dd081aa0Romain Guy        mLine[1] = startY;
500ce0537b80087a6225273040a987414b1dd081aa0Romain Guy        mLine[2] = stopX;
501ce0537b80087a6225273040a987414b1dd081aa0Romain Guy        mLine[3] = stopY;
502ce0537b80087a6225273040a987414b1dd081aa0Romain Guy        drawLines(mLine, 0, 1, paint);
503e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
504e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
505e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
506e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public void drawLines(float[] pts, int offset, int count, Paint paint) {
507e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy        // TODO: Implement
508e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
509e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
510e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
511e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public void drawLines(float[] pts, Paint paint) {
512ce0537b80087a6225273040a987414b1dd081aa0Romain Guy        drawLines(pts, 0, pts.length / 4, paint);
513e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
514e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
515e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
516e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public void drawOval(RectF oval, Paint paint) {
517e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy        throw new UnsupportedOperationException();
518e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
519e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
520e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
521e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public void drawPaint(Paint paint) {
5226926c72e25b8dec3dd4b84af0819fa1937ae7296Romain Guy        final Rect r = mClipBounds;
5236926c72e25b8dec3dd4b84af0819fa1937ae7296Romain Guy        nGetClipBounds(mRenderer, r);
5246926c72e25b8dec3dd4b84af0819fa1937ae7296Romain Guy        drawRect(r.left, r.top, r.right, r.bottom, paint);
525e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
526e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
527e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
528e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public void drawPath(Path path, Paint paint) {
5297fbcc0492fca03857e3c45064f4aa040af817d55Romain Guy        boolean hasModifier = setupModifiers(paint);
530a48a1a87ba17f20f7006eaab21dcedf86c015c13Romain Guy        if (path.isSimplePath) {
531a48a1a87ba17f20f7006eaab21dcedf86c015c13Romain Guy            if (path.rects != null) {
532a48a1a87ba17f20f7006eaab21dcedf86c015c13Romain Guy                nDrawRects(mRenderer, path.rects.mNativeRegion, paint.mNativePaint);
533a48a1a87ba17f20f7006eaab21dcedf86c015c13Romain Guy            }
534a48a1a87ba17f20f7006eaab21dcedf86c015c13Romain Guy        } else {
535a48a1a87ba17f20f7006eaab21dcedf86c015c13Romain Guy            nDrawPath(mRenderer, path.mNativePath, paint.mNativePaint);
536a48a1a87ba17f20f7006eaab21dcedf86c015c13Romain Guy        }
5377fbcc0492fca03857e3c45064f4aa040af817d55Romain Guy        if (hasModifier) nResetModifiers(mRenderer);
538e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
539e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
5407fbcc0492fca03857e3c45064f4aa040af817d55Romain Guy    private native void nDrawPath(int renderer, int path, int paint);
541a48a1a87ba17f20f7006eaab21dcedf86c015c13Romain Guy    private native void nDrawRects(int renderer, int region, int paint);
5427fbcc0492fca03857e3c45064f4aa040af817d55Romain Guy
543e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
544e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public void drawPicture(Picture picture) {
545e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy        throw new UnsupportedOperationException();
546e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
547e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
548e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
549e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public void drawPicture(Picture picture, Rect dst) {
550e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy        throw new UnsupportedOperationException();
551e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
552e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
553e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
554e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public void drawPicture(Picture picture, RectF dst) {
555e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy        throw new UnsupportedOperationException();
556e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
557e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
558e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
559e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public void drawPoint(float x, float y, Paint paint) {
560ce0537b80087a6225273040a987414b1dd081aa0Romain Guy        mPoint[0] = x;
561ce0537b80087a6225273040a987414b1dd081aa0Romain Guy        mPoint[1] = y;
562ce0537b80087a6225273040a987414b1dd081aa0Romain Guy        drawPoints(mPoint, 0, 1, paint);
563e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
564e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
565e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
566e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public void drawPoints(float[] pts, int offset, int count, Paint paint) {
567e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy        // TODO: Implement
568e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
569e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
570e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
571e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public void drawPoints(float[] pts, Paint paint) {
572ce0537b80087a6225273040a987414b1dd081aa0Romain Guy        drawPoints(pts, 0, pts.length / 2, paint);
573e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
574e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
575e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
576e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public void drawPosText(char[] text, int index, int count, float[] pos, Paint paint) {
577e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy        throw new UnsupportedOperationException();
578e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
579e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
580e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
581e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public void drawPosText(String text, float[] pos, Paint paint) {
582e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy        throw new UnsupportedOperationException();
583e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
584e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
585e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
586e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public void drawRect(float left, float top, float right, float bottom, Paint paint) {
587db1938e0e6ef816e228c815adccebd5cb05f2aa8Romain Guy        boolean hasModifier = setupModifiers(paint);
588c7d53494f1fbd9f9d74af89053ff9fdb1ccbac6cRomain Guy        nDrawRect(mRenderer, left, top, right, bottom, paint.mNativePaint);
589db1938e0e6ef816e228c815adccebd5cb05f2aa8Romain Guy        if (hasModifier) nResetModifiers(mRenderer);
590e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
591e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
592c7d53494f1fbd9f9d74af89053ff9fdb1ccbac6cRomain Guy    private native void nDrawRect(int renderer, float left, float top, float right, float bottom,
593c7d53494f1fbd9f9d74af89053ff9fdb1ccbac6cRomain Guy            int paint);
594c7d53494f1fbd9f9d74af89053ff9fdb1ccbac6cRomain Guy
595e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
596e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public void drawRect(Rect r, Paint paint) {
597c7d53494f1fbd9f9d74af89053ff9fdb1ccbac6cRomain Guy        drawRect(r.left, r.top, r.right, r.bottom, paint);
598e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
599e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
600e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
601c7d53494f1fbd9f9d74af89053ff9fdb1ccbac6cRomain Guy    public void drawRect(RectF r, Paint paint) {
602c7d53494f1fbd9f9d74af89053ff9fdb1ccbac6cRomain Guy        drawRect(r.left, r.top, r.right, r.bottom, paint);
603e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
604e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
605e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
606e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public void drawRGB(int r, int g, int b) {
60785bf02fc16784d935fb9eebfa9cb20fe46ff7951Romain Guy        drawColor(0xFF000000 | (r & 0xFF) << 16 | (g & 0xFF) << 8 | (b & 0xFF));
608e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
609e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
610e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
611e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public void drawRoundRect(RectF rect, float rx, float ry, Paint paint) {
612d27977d1a91d5a6b3cc9fa7664ac7e835e7bd895Romain Guy        // TODO: Implement
613e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
614e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
615e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
616e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public void drawText(char[] text, int index, int count, float x, float y, Paint paint) {
617a1db574036c9bc2d397b69f8200594027e1fff16Romain Guy        if ((index | count | (index + count) | (text.length - index - count)) < 0) {
618a1db574036c9bc2d397b69f8200594027e1fff16Romain Guy            throw new IndexOutOfBoundsException();
619a1db574036c9bc2d397b69f8200594027e1fff16Romain Guy        }
62061c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy
621db1938e0e6ef816e228c815adccebd5cb05f2aa8Romain Guy        boolean hasModifier = setupModifiers(paint);
62261c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy        try {
62361c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy            nDrawText(mRenderer, text, index, count, x, y, paint.mBidiFlags, paint.mNativePaint);
62461c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy        } finally {
62561c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy            if (hasModifier) nResetModifiers(mRenderer);
62661c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy        }
627e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
628a1db574036c9bc2d397b69f8200594027e1fff16Romain Guy
629a1db574036c9bc2d397b69f8200594027e1fff16Romain Guy    private native void nDrawText(int renderer, char[] text, int index, int count, float x, float y,
630a1db574036c9bc2d397b69f8200594027e1fff16Romain Guy            int bidiFlags, int paint);
631e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
632e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
633e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public void drawText(CharSequence text, int start, int end, float x, float y, Paint paint) {
634db1938e0e6ef816e228c815adccebd5cb05f2aa8Romain Guy        boolean hasModifier = setupModifiers(paint);
63561c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy        try {
63661c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy            if (text instanceof String || text instanceof SpannedString ||
63761c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy                    text instanceof SpannableString) {
63861c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy                nDrawText(mRenderer, text.toString(), start, end, x, y, paint.mBidiFlags,
63961c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy                        paint.mNativePaint);
64061c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy            } else if (text instanceof GraphicsOperations) {
64161c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy                ((GraphicsOperations) text).drawText(this, start, end, x, y,
64261c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy                                                         paint);
64361c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy            } else {
64461c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy                char[] buf = TemporaryBuffer.obtain(end - start);
64561c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy                TextUtils.getChars(text, start, end, buf, 0);
64661c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy                nDrawText(mRenderer, buf, 0, end - start, x, y, paint.mBidiFlags, paint.mNativePaint);
64761c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy                TemporaryBuffer.recycle(buf);
64861c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy            }
64961c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy        } finally {
65061c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy            if (hasModifier) nResetModifiers(mRenderer);
651a1db574036c9bc2d397b69f8200594027e1fff16Romain Guy        }
652e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
653e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
654e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
655e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public void drawText(String text, int start, int end, float x, float y, Paint paint) {
656a1db574036c9bc2d397b69f8200594027e1fff16Romain Guy        if ((start | end | (end - start) | (text.length() - end)) < 0) {
657a1db574036c9bc2d397b69f8200594027e1fff16Romain Guy            throw new IndexOutOfBoundsException();
658a1db574036c9bc2d397b69f8200594027e1fff16Romain Guy        }
65961c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy
660db1938e0e6ef816e228c815adccebd5cb05f2aa8Romain Guy        boolean hasModifier = setupModifiers(paint);
66161c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy        try {
66261c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy            nDrawText(mRenderer, text, start, end, x, y, paint.mBidiFlags, paint.mNativePaint);
66361c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy        } finally {
66461c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy            if (hasModifier) nResetModifiers(mRenderer);
66561c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy        }
666e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
667e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
668a1db574036c9bc2d397b69f8200594027e1fff16Romain Guy    private native void nDrawText(int renderer, String text, int start, int end, float x, float y,
669a1db574036c9bc2d397b69f8200594027e1fff16Romain Guy            int bidiFlags, int paint);
670a1db574036c9bc2d397b69f8200594027e1fff16Romain Guy
671e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
672e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public void drawText(String text, float x, float y, Paint paint) {
673db1938e0e6ef816e228c815adccebd5cb05f2aa8Romain Guy        boolean hasModifier = setupModifiers(paint);
67461c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy        try {
67561c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy            nDrawText(mRenderer, text, 0, text.length(), x, y, paint.mBidiFlags,
67661c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy                    paint.mNativePaint);
67761c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy        } finally {
67861c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy            if (hasModifier) nResetModifiers(mRenderer);
67961c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy        }
680e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
681e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
682e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
683e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public void drawTextOnPath(char[] text, int index, int count, Path path, float hOffset,
684e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy            float vOffset, Paint paint) {
685e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy        throw new UnsupportedOperationException();
686e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
687e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
688e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
689e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public void drawTextOnPath(String text, Path path, float hOffset, float vOffset, Paint paint) {
690e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy        throw new UnsupportedOperationException();
691e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
692e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
693e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
694e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public void drawTextRun(char[] text, int index, int count, int contextIndex, int contextCount,
695e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy            float x, float y, int dir, Paint paint) {
69661c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy        if ((index | count | text.length - index - count) < 0) {
69761c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy            throw new IndexOutOfBoundsException();
69861c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy        }
69961c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy        if (dir != DIRECTION_LTR && dir != DIRECTION_RTL) {
70061c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy            throw new IllegalArgumentException("Unknown direction: " + dir);
70161c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy        }
70261c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy
70361c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy        boolean hasModifier = setupModifiers(paint);
70461c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy        try {
70561c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy            nDrawTextRun(mRenderer, text, index, count, contextIndex, contextCount, x, y, dir,
70661c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy                    paint.mNativePaint);
70761c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy        } finally {
70861c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy            if (hasModifier) nResetModifiers(mRenderer);
70961c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy        }
710e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
711e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
71261c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy    private native void nDrawTextRun(int renderer, char[] text, int index, int count,
71361c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy            int contextIndex, int contextCount, float x, float y, int dir, int nativePaint);
71461c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy
715e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
716e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public void drawTextRun(CharSequence text, int start, int end, int contextStart, int contextEnd,
717e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy            float x, float y, int dir, Paint paint) {
71861c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy        if ((start | end | end - start | text.length() - end) < 0) {
71961c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy            throw new IndexOutOfBoundsException();
72061c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy        }
72161c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy
72261c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy        boolean hasModifier = setupModifiers(paint);
72361c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy        try {
72461c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy            int flags = dir == 0 ? 0 : 1;
72561c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy            if (text instanceof String || text instanceof SpannedString ||
72661c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy                    text instanceof SpannableString) {
72761c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy                nDrawTextRun(mRenderer, text.toString(), start, end, contextStart,
72861c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy                        contextEnd, x, y, flags, paint.mNativePaint);
72961c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy            } else if (text instanceof GraphicsOperations) {
73061c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy                ((GraphicsOperations) text).drawTextRun(this, start, end,
73161c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy                        contextStart, contextEnd, x, y, flags, paint);
73261c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy            } else {
73361c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy                int contextLen = contextEnd - contextStart;
73461c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy                int len = end - start;
73561c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy                char[] buf = TemporaryBuffer.obtain(contextLen);
73661c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy                TextUtils.getChars(text, contextStart, contextEnd, buf, 0);
73761c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy                nDrawTextRun(mRenderer, buf, start - contextStart, len, 0, contextLen,
73861c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy                        x, y, flags, paint.mNativePaint);
73961c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy                TemporaryBuffer.recycle(buf);
74061c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy            }
74161c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy        } finally {
74261c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy            if (hasModifier) nResetModifiers(mRenderer);
74361c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy        }
744e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
745e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
74661c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy    private native void nDrawTextRun(int renderer, String text, int start, int end,
74761c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy            int contextStart, int contextEnd, float x, float y, int flags, int nativePaint);
74861c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy
749e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    @Override
750e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    public void drawVertices(VertexMode mode, int vertexCount, float[] verts, int vertOffset,
751e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy            float[] texs, int texOffset, int[] colors, int colorOffset, short[] indices,
752e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy            int indexOffset, int indexCount, Paint paint) {
7536926c72e25b8dec3dd4b84af0819fa1937ae7296Romain Guy        // TODO: Implement
754e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy    }
755d27977d1a91d5a6b3cc9fa7664ac7e835e7bd895Romain Guy
756db1938e0e6ef816e228c815adccebd5cb05f2aa8Romain Guy    private boolean setupModifiers(Paint paint) {
757db1938e0e6ef816e228c815adccebd5cb05f2aa8Romain Guy        boolean hasModifier = false;
758db1938e0e6ef816e228c815adccebd5cb05f2aa8Romain Guy
7591e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy        if (paint.hasShadow) {
7601e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy            nSetupShadow(mRenderer, paint.shadowRadius, paint.shadowDx, paint.shadowDy,
7611e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy                    paint.shadowColor);
7621e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy            hasModifier = true;
7631e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy        }
7641e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy
765d27977d1a91d5a6b3cc9fa7664ac7e835e7bd895Romain Guy        final Shader shader = paint.getShader();
766d27977d1a91d5a6b3cc9fa7664ac7e835e7bd895Romain Guy        if (shader != null) {
76706f96e2652e4855b6520ad9dd70583677605b79aRomain Guy            nSetupShader(mRenderer, shader.native_shader);
768db1938e0e6ef816e228c815adccebd5cb05f2aa8Romain Guy            hasModifier = true;
769db1938e0e6ef816e228c815adccebd5cb05f2aa8Romain Guy        }
770db1938e0e6ef816e228c815adccebd5cb05f2aa8Romain Guy
771db1938e0e6ef816e228c815adccebd5cb05f2aa8Romain Guy        final ColorFilter filter = paint.getColorFilter();
772db1938e0e6ef816e228c815adccebd5cb05f2aa8Romain Guy        if (filter != null) {
773db1938e0e6ef816e228c815adccebd5cb05f2aa8Romain Guy            nSetupColorFilter(mRenderer, filter.nativeColorFilter);
774db1938e0e6ef816e228c815adccebd5cb05f2aa8Romain Guy            hasModifier = true;
775db1938e0e6ef816e228c815adccebd5cb05f2aa8Romain Guy        }
776db1938e0e6ef816e228c815adccebd5cb05f2aa8Romain Guy
777db1938e0e6ef816e228c815adccebd5cb05f2aa8Romain Guy        return hasModifier;
778db1938e0e6ef816e228c815adccebd5cb05f2aa8Romain Guy    }
7791e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy
780db1938e0e6ef816e228c815adccebd5cb05f2aa8Romain Guy    private boolean setupColorFilter(Paint paint) {
781db1938e0e6ef816e228c815adccebd5cb05f2aa8Romain Guy        final ColorFilter filter = paint.getColorFilter();
782db1938e0e6ef816e228c815adccebd5cb05f2aa8Romain Guy        if (filter != null) {
783db1938e0e6ef816e228c815adccebd5cb05f2aa8Romain Guy            nSetupColorFilter(mRenderer, filter.nativeColorFilter);
78406f96e2652e4855b6520ad9dd70583677605b79aRomain Guy            return true;
785d27977d1a91d5a6b3cc9fa7664ac7e835e7bd895Romain Guy        }
786db1938e0e6ef816e228c815adccebd5cb05f2aa8Romain Guy        return false;
787d27977d1a91d5a6b3cc9fa7664ac7e835e7bd895Romain Guy    }
788db1938e0e6ef816e228c815adccebd5cb05f2aa8Romain Guy
78906f96e2652e4855b6520ad9dd70583677605b79aRomain Guy    private native void nSetupShader(int renderer, int shader);
790db1938e0e6ef816e228c815adccebd5cb05f2aa8Romain Guy    private native void nSetupColorFilter(int renderer, int colorFilter);
7911e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy    private native void nSetupShadow(int renderer, float radius, float dx, float dy, int color);
7921e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy
793db1938e0e6ef816e228c815adccebd5cb05f2aa8Romain Guy    private native void nResetModifiers(int renderer);
794e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy}
795