• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2014 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "GraphicsJNI.h"
18 
19 #ifdef __ANDROID_
20 #include <android/api-level.h>
21 #else
22 #define __ANDROID_API_P__ 28
23 #endif
24 #include <androidfw/ResourceTypes.h>
25 #include <hwui/Canvas.h>
26 #include <hwui/Paint.h>
27 #include <hwui/PaintFilter.h>
28 #include <hwui/Typeface.h>
29 #include <minikin/Layout.h>
30 #include <nativehelper/ScopedPrimitiveArray.h>
31 #include <nativehelper/ScopedStringChars.h>
32 
33 #include "FontUtils.h"
34 #include "Bitmap.h"
35 #include "SkGraphics.h"
36 #include "SkRegion.h"
37 #include "SkVertices.h"
38 #include "SkRRect.h"
39 
40 namespace minikin {
41 class MeasuredText;
42 }  // namespace minikin
43 
44 namespace android {
45 
46 namespace CanvasJNI {
47 
get_canvas(jlong canvasHandle)48 static Canvas* get_canvas(jlong canvasHandle) {
49     return reinterpret_cast<Canvas*>(canvasHandle);
50 }
51 
delete_canvas(Canvas * canvas)52 static void delete_canvas(Canvas* canvas) {
53     delete canvas;
54 }
55 
getNativeFinalizer(JNIEnv * env,jobject clazz)56 static jlong getNativeFinalizer(JNIEnv* env, jobject clazz) {
57     return static_cast<jlong>(reinterpret_cast<uintptr_t>(&delete_canvas));
58 }
59 
60 // Native wrapper constructor used by Canvas(Bitmap)
initRaster(JNIEnv * env,jobject,jlong bitmapHandle)61 static jlong initRaster(JNIEnv* env, jobject, jlong bitmapHandle) {
62     SkBitmap bitmap;
63     if (bitmapHandle != 0) {
64         bitmap::toBitmap(bitmapHandle).getSkBitmap(&bitmap);
65     }
66     return reinterpret_cast<jlong>(Canvas::create_canvas(bitmap));
67 }
68 
69 // Set the given bitmap as the new draw target (wrapped in a new SkCanvas),
70 // optionally copying canvas matrix & clip state.
setBitmap(JNIEnv * env,jobject,jlong canvasHandle,jlong bitmapHandle)71 static void setBitmap(JNIEnv* env, jobject, jlong canvasHandle, jlong bitmapHandle) {
72     SkBitmap bitmap;
73     if (bitmapHandle != 0) {
74         bitmap::toBitmap(bitmapHandle).getSkBitmap(&bitmap);
75     }
76     get_canvas(canvasHandle)->setBitmap(bitmap);
77 }
78 
isOpaque(CRITICAL_JNI_PARAMS_COMMA jlong canvasHandle)79 static jboolean isOpaque(CRITICAL_JNI_PARAMS_COMMA jlong canvasHandle) {
80     return get_canvas(canvasHandle)->isOpaque() ? JNI_TRUE : JNI_FALSE;
81 }
82 
getWidth(CRITICAL_JNI_PARAMS_COMMA jlong canvasHandle)83 static jint getWidth(CRITICAL_JNI_PARAMS_COMMA jlong canvasHandle) {
84     return static_cast<jint>(get_canvas(canvasHandle)->width());
85 }
86 
getHeight(CRITICAL_JNI_PARAMS_COMMA jlong canvasHandle)87 static jint getHeight(CRITICAL_JNI_PARAMS_COMMA jlong canvasHandle) {
88     return static_cast<jint>(get_canvas(canvasHandle)->height());
89 }
90 
save(CRITICAL_JNI_PARAMS_COMMA jlong canvasHandle,jint flagsHandle)91 static jint save(CRITICAL_JNI_PARAMS_COMMA jlong canvasHandle, jint flagsHandle) {
92     SaveFlags::Flags flags = static_cast<SaveFlags::Flags>(flagsHandle);
93     return static_cast<jint>(get_canvas(canvasHandle)->save(flags));
94 }
95 
saveLayer(CRITICAL_JNI_PARAMS_COMMA jlong canvasHandle,jfloat l,jfloat t,jfloat r,jfloat b,jlong paintHandle)96 static jint saveLayer(CRITICAL_JNI_PARAMS_COMMA jlong canvasHandle, jfloat l, jfloat t,
97                       jfloat r, jfloat b, jlong paintHandle) {
98     Paint* paint  = reinterpret_cast<Paint*>(paintHandle);
99     return static_cast<jint>(get_canvas(canvasHandle)->saveLayer(l, t, r, b, paint));
100 }
101 
saveLayerAlpha(CRITICAL_JNI_PARAMS_COMMA jlong canvasHandle,jfloat l,jfloat t,jfloat r,jfloat b,jint alpha)102 static jint saveLayerAlpha(CRITICAL_JNI_PARAMS_COMMA jlong canvasHandle, jfloat l, jfloat t,
103                            jfloat r, jfloat b, jint alpha) {
104     return static_cast<jint>(get_canvas(canvasHandle)->saveLayerAlpha(l, t, r, b, alpha));
105 }
106 
saveUnclippedLayer(CRITICAL_JNI_PARAMS_COMMA jlong canvasHandle,jint l,jint t,jint r,jint b)107 static jint saveUnclippedLayer(CRITICAL_JNI_PARAMS_COMMA jlong canvasHandle, jint l, jint t, jint r, jint b) {
108     return reinterpret_cast<jint>(get_canvas(canvasHandle)->saveUnclippedLayer(l, t, r, b));
109 }
110 
restoreUnclippedLayer(CRITICAL_JNI_PARAMS_COMMA jlong canvasHandle,jint saveCount,jlong paintHandle)111 static void restoreUnclippedLayer(CRITICAL_JNI_PARAMS_COMMA jlong canvasHandle, jint saveCount, jlong paintHandle) {
112     Paint* paint = reinterpret_cast<Paint*>(paintHandle);
113     get_canvas(canvasHandle)->restoreUnclippedLayer(saveCount, *paint);
114 }
115 
restore(CRITICAL_JNI_PARAMS_COMMA jlong canvasHandle)116 static jboolean restore(CRITICAL_JNI_PARAMS_COMMA jlong canvasHandle) {
117     Canvas* canvas = get_canvas(canvasHandle);
118     if (canvas->getSaveCount() <= 1) {
119         return false; // cannot restore anymore
120     }
121     canvas->restore();
122     return true; // success
123 }
124 
restoreToCount(CRITICAL_JNI_PARAMS_COMMA jlong canvasHandle,jint saveCount)125 static void restoreToCount(CRITICAL_JNI_PARAMS_COMMA jlong canvasHandle, jint saveCount) {
126     Canvas* canvas = get_canvas(canvasHandle);
127     canvas->restoreToCount(saveCount);
128 }
129 
getSaveCount(CRITICAL_JNI_PARAMS_COMMA jlong canvasHandle)130 static jint getSaveCount(CRITICAL_JNI_PARAMS_COMMA jlong canvasHandle) {
131     return static_cast<jint>(get_canvas(canvasHandle)->getSaveCount());
132 }
133 
getMatrix(CRITICAL_JNI_PARAMS_COMMA jlong canvasHandle,jlong matrixHandle)134 static void getMatrix(CRITICAL_JNI_PARAMS_COMMA jlong canvasHandle, jlong matrixHandle) {
135     SkMatrix* matrix = reinterpret_cast<SkMatrix*>(matrixHandle);
136     get_canvas(canvasHandle)->getMatrix(matrix);
137 }
138 
setMatrix(CRITICAL_JNI_PARAMS_COMMA jlong canvasHandle,jlong matrixHandle)139 static void setMatrix(CRITICAL_JNI_PARAMS_COMMA jlong canvasHandle, jlong matrixHandle) {
140     const SkMatrix* matrix = reinterpret_cast<SkMatrix*>(matrixHandle);
141     get_canvas(canvasHandle)->setMatrix(matrix ? *matrix : SkMatrix::I());
142 }
143 
concat(CRITICAL_JNI_PARAMS_COMMA jlong canvasHandle,jlong matrixHandle)144 static void concat(CRITICAL_JNI_PARAMS_COMMA jlong canvasHandle, jlong matrixHandle) {
145     const SkMatrix* matrix = reinterpret_cast<SkMatrix*>(matrixHandle);
146     get_canvas(canvasHandle)->concat(*matrix);
147 }
148 
rotate(CRITICAL_JNI_PARAMS_COMMA jlong canvasHandle,jfloat degrees)149 static void rotate(CRITICAL_JNI_PARAMS_COMMA jlong canvasHandle, jfloat degrees) {
150     get_canvas(canvasHandle)->rotate(degrees);
151 }
152 
scale(CRITICAL_JNI_PARAMS_COMMA jlong canvasHandle,jfloat sx,jfloat sy)153 static void scale(CRITICAL_JNI_PARAMS_COMMA jlong canvasHandle, jfloat sx, jfloat sy) {
154     get_canvas(canvasHandle)->scale(sx, sy);
155 }
156 
skew(CRITICAL_JNI_PARAMS_COMMA jlong canvasHandle,jfloat sx,jfloat sy)157 static void skew(CRITICAL_JNI_PARAMS_COMMA jlong canvasHandle, jfloat sx, jfloat sy) {
158     get_canvas(canvasHandle)->skew(sx, sy);
159 }
160 
translate(CRITICAL_JNI_PARAMS_COMMA jlong canvasHandle,jfloat dx,jfloat dy)161 static void translate(CRITICAL_JNI_PARAMS_COMMA jlong canvasHandle, jfloat dx, jfloat dy) {
162     get_canvas(canvasHandle)->translate(dx, dy);
163 }
164 
getClipBounds(JNIEnv * env,jobject,jlong canvasHandle,jobject bounds)165 static jboolean getClipBounds(JNIEnv* env, jobject, jlong canvasHandle, jobject bounds) {
166     SkRect   r;
167     SkIRect ir;
168     bool result = get_canvas(canvasHandle)->getClipBounds(&r);
169 
170     if (!result) {
171         r.setEmpty();
172     }
173     r.round(&ir);
174 
175     (void)GraphicsJNI::irect_to_jrect(ir, env, bounds);
176     return result ? JNI_TRUE : JNI_FALSE;
177 }
178 
quickRejectRect(CRITICAL_JNI_PARAMS_COMMA jlong canvasHandle,jfloat left,jfloat top,jfloat right,jfloat bottom)179 static jboolean quickRejectRect(CRITICAL_JNI_PARAMS_COMMA jlong canvasHandle,
180                                 jfloat left, jfloat top, jfloat right, jfloat bottom) {
181     bool result = get_canvas(canvasHandle)->quickRejectRect(left, top, right, bottom);
182     return result ? JNI_TRUE : JNI_FALSE;
183 }
184 
quickRejectPath(CRITICAL_JNI_PARAMS_COMMA jlong canvasHandle,jlong pathHandle)185 static jboolean quickRejectPath(CRITICAL_JNI_PARAMS_COMMA jlong canvasHandle, jlong pathHandle) {
186     SkPath* path = reinterpret_cast<SkPath*>(pathHandle);
187     bool result = get_canvas(canvasHandle)->quickRejectPath(*path);
188     return result ? JNI_TRUE : JNI_FALSE;
189 }
190 
191 // SkClipOp is a strict subset of SkRegion::Op and is castable back and forth for their
192 // shared operations (intersect and difference).
193 static_assert(SkRegion::kDifference_Op == static_cast<SkRegion::Op>(SkClipOp::kDifference), "");
194 static_assert(SkRegion::kIntersect_Op == static_cast<SkRegion::Op>(SkClipOp::kIntersect), "");
195 
clipRect(CRITICAL_JNI_PARAMS_COMMA jlong canvasHandle,jfloat l,jfloat t,jfloat r,jfloat b,jint opHandle)196 static jboolean clipRect(CRITICAL_JNI_PARAMS_COMMA jlong canvasHandle, jfloat l, jfloat t,
197                          jfloat r, jfloat b, jint opHandle) {
198     // The opHandle is defined in Canvas.java to be Region::Op
199     SkRegion::Op rgnOp = static_cast<SkRegion::Op>(opHandle);
200     bool nonEmptyClip;
201     switch (rgnOp) {
202         case SkRegion::Op::kIntersect_Op:
203         case SkRegion::Op::kDifference_Op:
204             // Intersect and difference are supported clip operations
205             nonEmptyClip =
206                     get_canvas(canvasHandle)->clipRect(l, t, r, b, static_cast<SkClipOp>(rgnOp));
207             break;
208         case SkRegion::Op::kReplace_Op:
209             // Replace is emulated to support legacy apps older than P
210             nonEmptyClip = get_canvas(canvasHandle)->replaceClipRect_deprecated(l, t, r, b);
211             break;
212         default:
213             // All other operations would expand the clip and are no longer supported,
214             // so log and skip (to avoid breaking legacy apps).
215             ALOGW("Ignoring unsupported clip operation %d", opHandle);
216             SkRect clipBounds;  // ignored
217             nonEmptyClip = get_canvas(canvasHandle)->getClipBounds(&clipBounds);
218             break;
219     }
220     return nonEmptyClip ? JNI_TRUE : JNI_FALSE;
221 }
222 
clipPath(CRITICAL_JNI_PARAMS_COMMA jlong canvasHandle,jlong pathHandle,jint opHandle)223 static jboolean clipPath(CRITICAL_JNI_PARAMS_COMMA jlong canvasHandle, jlong pathHandle,
224                          jint opHandle) {
225     SkRegion::Op rgnOp = static_cast<SkRegion::Op>(opHandle);
226     SkPath* path = reinterpret_cast<SkPath*>(pathHandle);
227     bool nonEmptyClip;
228     switch (rgnOp) {
229         case SkRegion::Op::kIntersect_Op:
230         case SkRegion::Op::kDifference_Op:
231             nonEmptyClip = get_canvas(canvasHandle)->clipPath(path, static_cast<SkClipOp>(rgnOp));
232             break;
233         case SkRegion::Op::kReplace_Op:
234             nonEmptyClip = get_canvas(canvasHandle)->replaceClipPath_deprecated(path);
235             break;
236         default:
237             ALOGW("Ignoring unsupported clip operation %d", opHandle);
238             SkRect clipBounds;  // ignored
239             nonEmptyClip = get_canvas(canvasHandle)->getClipBounds(&clipBounds);
240             break;
241     }
242     return nonEmptyClip ? JNI_TRUE : JNI_FALSE;
243 }
244 
drawColor(JNIEnv * env,jobject,jlong canvasHandle,jint color,jint modeHandle)245 static void drawColor(JNIEnv* env, jobject, jlong canvasHandle, jint color, jint modeHandle) {
246     SkBlendMode mode = static_cast<SkBlendMode>(modeHandle);
247     get_canvas(canvasHandle)->drawColor(color, mode);
248 }
249 
drawColorLong(JNIEnv * env,jobject,jlong canvasHandle,jlong colorSpaceHandle,jlong colorLong,jint modeHandle)250 static void drawColorLong(JNIEnv* env, jobject, jlong canvasHandle, jlong colorSpaceHandle,
251         jlong colorLong, jint modeHandle) {
252     SkColor4f color = GraphicsJNI::convertColorLong(colorLong);
253     sk_sp<SkColorSpace> cs = GraphicsJNI::getNativeColorSpace(colorSpaceHandle);
254     Paint p;
255     p.setColor4f(color, cs.get());
256 
257     SkBlendMode mode = static_cast<SkBlendMode>(modeHandle);
258     p.setBlendMode(mode);
259     get_canvas(canvasHandle)->drawPaint(p);
260 }
261 
drawPaint(JNIEnv * env,jobject,jlong canvasHandle,jlong paintHandle)262 static void drawPaint(JNIEnv* env, jobject, jlong canvasHandle, jlong paintHandle) {
263     Paint* paint = reinterpret_cast<Paint*>(paintHandle);
264     get_canvas(canvasHandle)->drawPaint(*paint);
265 }
266 
drawPoint(JNIEnv *,jobject,jlong canvasHandle,jfloat x,jfloat y,jlong paintHandle)267 static void drawPoint(JNIEnv*, jobject, jlong canvasHandle, jfloat x, jfloat y,
268                       jlong paintHandle) {
269     const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
270     get_canvas(canvasHandle)->drawPoint(x, y, *paint);
271 }
272 
drawPoints(JNIEnv * env,jobject,jlong canvasHandle,jfloatArray jptsArray,jint offset,jint count,jlong paintHandle)273 static void drawPoints(JNIEnv* env, jobject, jlong canvasHandle, jfloatArray jptsArray,
274                        jint offset, jint count, jlong paintHandle) {
275     NPE_CHECK_RETURN_VOID(env, jptsArray);
276     AutoJavaFloatArray autoPts(env, jptsArray);
277     float* floats = autoPts.ptr();
278     const int length = autoPts.length();
279 
280     if ((offset | count) < 0 || offset + count > length) {
281         doThrowAIOOBE(env);
282         return;
283     }
284 
285     const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
286     get_canvas(canvasHandle)->drawPoints(floats + offset, count, *paint);
287 }
288 
drawLine(JNIEnv * env,jobject,jlong canvasHandle,jfloat startX,jfloat startY,jfloat stopX,jfloat stopY,jlong paintHandle)289 static void drawLine(JNIEnv* env, jobject, jlong canvasHandle, jfloat startX, jfloat startY,
290                      jfloat stopX, jfloat stopY, jlong paintHandle) {
291     Paint* paint = reinterpret_cast<Paint*>(paintHandle);
292     get_canvas(canvasHandle)->drawLine(startX, startY, stopX, stopY, *paint);
293 }
294 
drawLines(JNIEnv * env,jobject,jlong canvasHandle,jfloatArray jptsArray,jint offset,jint count,jlong paintHandle)295 static void drawLines(JNIEnv* env, jobject, jlong canvasHandle, jfloatArray jptsArray,
296                       jint offset, jint count, jlong paintHandle) {
297     NPE_CHECK_RETURN_VOID(env, jptsArray);
298     AutoJavaFloatArray autoPts(env, jptsArray);
299     float* floats = autoPts.ptr();
300     const int length = autoPts.length();
301 
302     if ((offset | count) < 0 || offset + count > length) {
303         doThrowAIOOBE(env);
304         return;
305     }
306 
307     const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
308     get_canvas(canvasHandle)->drawLines(floats + offset, count, *paint);
309 }
310 
drawRect(JNIEnv * env,jobject,jlong canvasHandle,jfloat left,jfloat top,jfloat right,jfloat bottom,jlong paintHandle)311 static void drawRect(JNIEnv* env, jobject, jlong canvasHandle, jfloat left, jfloat top,
312                      jfloat right, jfloat bottom, jlong paintHandle) {
313     const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
314     get_canvas(canvasHandle)->drawRect(left, top, right, bottom, *paint);
315 }
316 
drawDoubleRoundRectXY(JNIEnv * env,jobject,jlong canvasHandle,jfloat outerLeft,jfloat outerTop,jfloat outerRight,jfloat outerBottom,jfloat outerRx,jfloat outerRy,jfloat innerLeft,jfloat innerTop,jfloat innerRight,jfloat innerBottom,jfloat innerRx,jfloat innerRy,jlong paintHandle)317 static void drawDoubleRoundRectXY(JNIEnv* env, jobject, jlong canvasHandle, jfloat outerLeft,
318                     jfloat outerTop, jfloat outerRight, jfloat outerBottom, jfloat outerRx,
319                     jfloat outerRy, jfloat innerLeft, jfloat innerTop, jfloat innerRight,
320                     jfloat innerBottom, jfloat innerRx, jfloat innerRy, jlong paintHandle) {
321     const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
322     get_canvas(canvasHandle)->drawDoubleRoundRectXY(
323                     outerLeft, outerTop, outerRight, outerBottom, outerRx, outerRy,
324                     innerLeft, innerTop, innerRight, innerBottom, innerRx, innerRy, *paint);
325 }
326 
drawDoubleRoundRectRadii(JNIEnv * env,jobject,jlong canvasHandle,jfloat outerLeft,jfloat outerTop,jfloat outerRight,jfloat outerBottom,jfloatArray jouterRadii,jfloat innerLeft,jfloat innerTop,jfloat innerRight,jfloat innerBottom,jfloatArray jinnerRadii,jlong paintHandle)327 static void drawDoubleRoundRectRadii(JNIEnv* env, jobject, jlong canvasHandle, jfloat outerLeft,
328                      jfloat outerTop, jfloat outerRight, jfloat outerBottom, jfloatArray jouterRadii,
329                      jfloat innerLeft, jfloat innerTop, jfloat innerRight,
330                      jfloat innerBottom, jfloatArray jinnerRadii, jlong paintHandle) {
331     const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
332 
333     float outerRadii[8];
334     float innerRadii[8];
335     env->GetFloatArrayRegion(jouterRadii, 0, 8, outerRadii);
336     env->GetFloatArrayRegion(jinnerRadii, 0, 8, innerRadii);
337     get_canvas(canvasHandle)->drawDoubleRoundRectRadii(
338                     outerLeft, outerTop, outerRight, outerBottom, outerRadii,
339                     innerLeft, innerTop, innerRight, innerBottom, innerRadii, *paint);
340 
341 }
342 
drawRegion(JNIEnv * env,jobject,jlong canvasHandle,jlong regionHandle,jlong paintHandle)343 static void drawRegion(JNIEnv* env, jobject, jlong canvasHandle, jlong regionHandle,
344                        jlong paintHandle) {
345     const SkRegion* region = reinterpret_cast<SkRegion*>(regionHandle);
346     const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
347     get_canvas(canvasHandle)->drawRegion(*region, *paint);
348 }
349 
drawRoundRect(JNIEnv * env,jobject,jlong canvasHandle,jfloat left,jfloat top,jfloat right,jfloat bottom,jfloat rx,jfloat ry,jlong paintHandle)350 static void drawRoundRect(JNIEnv* env, jobject, jlong canvasHandle, jfloat left, jfloat top,
351                           jfloat right, jfloat bottom, jfloat rx, jfloat ry, jlong paintHandle) {
352     const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
353     get_canvas(canvasHandle)->drawRoundRect(left, top, right, bottom, rx, ry, *paint);
354 }
355 
drawCircle(JNIEnv * env,jobject,jlong canvasHandle,jfloat cx,jfloat cy,jfloat radius,jlong paintHandle)356 static void drawCircle(JNIEnv* env, jobject, jlong canvasHandle, jfloat cx, jfloat cy,
357                        jfloat radius, jlong paintHandle) {
358     const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
359     get_canvas(canvasHandle)->drawCircle(cx, cy, radius, *paint);
360 }
361 
drawOval(JNIEnv * env,jobject,jlong canvasHandle,jfloat left,jfloat top,jfloat right,jfloat bottom,jlong paintHandle)362 static void drawOval(JNIEnv* env, jobject, jlong canvasHandle, jfloat left, jfloat top,
363                      jfloat right, jfloat bottom, jlong paintHandle) {
364     const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
365     get_canvas(canvasHandle)->drawOval(left, top, right, bottom, *paint);
366 }
367 
drawArc(JNIEnv * env,jobject,jlong canvasHandle,jfloat left,jfloat top,jfloat right,jfloat bottom,jfloat startAngle,jfloat sweepAngle,jboolean useCenter,jlong paintHandle)368 static void drawArc(JNIEnv* env, jobject, jlong canvasHandle, jfloat left, jfloat top,
369                     jfloat right, jfloat bottom, jfloat startAngle, jfloat sweepAngle,
370                     jboolean useCenter, jlong paintHandle) {
371     const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
372     get_canvas(canvasHandle)->drawArc(left, top, right, bottom, startAngle, sweepAngle,
373                                        useCenter, *paint);
374 }
375 
drawPath(JNIEnv * env,jobject,jlong canvasHandle,jlong pathHandle,jlong paintHandle)376 static void drawPath(JNIEnv* env, jobject, jlong canvasHandle, jlong pathHandle,
377                      jlong paintHandle) {
378     const SkPath* path = reinterpret_cast<SkPath*>(pathHandle);
379     const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
380     get_canvas(canvasHandle)->drawPath(*path, *paint);
381 }
382 
drawVertices(JNIEnv * env,jobject,jlong canvasHandle,jint modeHandle,jint floatCount,jfloatArray jverts,jint vertIndex,jfloatArray jtexs,jint texIndex,jintArray jcolors,jint colorIndex,jshortArray jindices,jint indexIndex,jint indexCount,jlong paintHandle)383 static void drawVertices(JNIEnv* env, jobject, jlong canvasHandle,
384                          jint modeHandle, jint floatCount,
385                          jfloatArray jverts, jint vertIndex,
386                          jfloatArray jtexs, jint texIndex,
387                          jintArray jcolors, jint colorIndex,
388                          jshortArray jindices, jint indexIndex,
389                          jint indexCount, jlong paintHandle) {
390 
391     const int vertexCount = floatCount >> 1;  // 2 floats per SkPoint
392 
393     AutoJavaFloatArray  vertA(env, jverts, vertIndex + floatCount);
394     AutoJavaFloatArray  texA(env, jtexs, texIndex + floatCount);
395     AutoJavaIntArray    colorA(env, jcolors, colorIndex + vertexCount);
396     AutoJavaShortArray  indexA(env, jindices, indexIndex + indexCount);
397 
398     const float* verts = vertA.ptr() + vertIndex;
399     const float* texs = texA.ptr() + vertIndex;
400     const int* colors = NULL;
401     const uint16_t* indices = NULL;
402 
403     if (jcolors != NULL) {
404         colors = colorA.ptr() + colorIndex;
405     }
406     if (jindices != NULL) {
407         indices = (const uint16_t*)(indexA.ptr() + indexIndex);
408     }
409 
410     SkVertices::VertexMode vertexMode = static_cast<SkVertices::VertexMode>(modeHandle);
411     const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
412 
413     // Preserve legacy Skia behavior: ignore the shader if there are no texs set.
414     Paint noShaderPaint;
415     if (jtexs == NULL) {
416         noShaderPaint = Paint(*paint);
417         noShaderPaint.setShader(nullptr);
418         paint = &noShaderPaint;
419     }
420     // Since https://skia-review.googlesource.com/c/skia/+/473676, Skia will blend paint and vertex
421     // colors when no shader is provided. This ternary uses kDst to mimic the old behavior of
422     // ignoring the paint and using the vertex colors directly when no shader is provided.
423     SkBlendMode blendMode = paint->getShader() ? SkBlendMode::kModulate : SkBlendMode::kDst;
424 
425     get_canvas(canvasHandle)
426             ->drawVertices(SkVertices::MakeCopy(
427                                    vertexMode, vertexCount, reinterpret_cast<const SkPoint*>(verts),
428                                    reinterpret_cast<const SkPoint*>(texs),
429                                    reinterpret_cast<const SkColor*>(colors), indexCount, indices)
430                                    .get(),
431                            blendMode, *paint);
432 }
433 
drawNinePatch(JNIEnv * env,jobject,jlong canvasHandle,jlong bitmapHandle,jlong chunkHandle,jfloat left,jfloat top,jfloat right,jfloat bottom,jlong paintHandle,jint dstDensity,jint srcDensity)434 static void drawNinePatch(JNIEnv* env, jobject, jlong canvasHandle, jlong bitmapHandle,
435         jlong chunkHandle, jfloat left, jfloat top, jfloat right, jfloat bottom,
436         jlong paintHandle, jint dstDensity, jint srcDensity) {
437 
438     Canvas* canvas = get_canvas(canvasHandle);
439     Bitmap& bitmap = android::bitmap::toBitmap(bitmapHandle);
440     const android::Res_png_9patch* chunk = reinterpret_cast<android::Res_png_9patch*>(chunkHandle);
441     const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
442 
443     if (CC_LIKELY(dstDensity == srcDensity || dstDensity == 0 || srcDensity == 0)) {
444         canvas->drawNinePatch(bitmap, *chunk, left, top, right, bottom, paint);
445     } else {
446         canvas->save(SaveFlags::MatrixClip);
447 
448         SkScalar scale = dstDensity / (float)srcDensity;
449         canvas->translate(left, top);
450         canvas->scale(scale, scale);
451 
452         Paint filteredPaint;
453         if (paint) {
454             filteredPaint = *paint;
455         }
456         filteredPaint.setFilterBitmap(true);
457 
458         canvas->drawNinePatch(bitmap, *chunk, 0, 0, (right-left)/scale, (bottom-top)/scale,
459                 &filteredPaint);
460 
461         canvas->restore();
462     }
463 }
464 
drawBitmap(JNIEnv * env,jobject,jlong canvasHandle,jlong bitmapHandle,jfloat left,jfloat top,jlong paintHandle,jint canvasDensity,jint screenDensity,jint bitmapDensity)465 static void drawBitmap(JNIEnv* env, jobject, jlong canvasHandle, jlong bitmapHandle,
466                        jfloat left, jfloat top, jlong paintHandle, jint canvasDensity,
467                        jint screenDensity, jint bitmapDensity) {
468     Canvas* canvas = get_canvas(canvasHandle);
469     Bitmap& bitmap = android::bitmap::toBitmap(bitmapHandle);
470     const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
471 
472     if (canvasDensity == bitmapDensity || canvasDensity == 0 || bitmapDensity == 0) {
473         if (screenDensity != 0 && screenDensity != bitmapDensity) {
474             Paint filteredPaint;
475             if (paint) {
476                 filteredPaint = *paint;
477             }
478             filteredPaint.setFilterBitmap(true);
479             canvas->drawBitmap(bitmap, left, top, &filteredPaint);
480         } else {
481             canvas->drawBitmap(bitmap, left, top, paint);
482         }
483     } else {
484         canvas->save(SaveFlags::MatrixClip);
485         SkScalar scale = canvasDensity / (float)bitmapDensity;
486         canvas->translate(left, top);
487         canvas->scale(scale, scale);
488 
489         Paint filteredPaint;
490         if (paint) {
491             filteredPaint = *paint;
492         }
493         filteredPaint.setFilterBitmap(true);
494 
495         canvas->drawBitmap(bitmap, 0, 0, &filteredPaint);
496         canvas->restore();
497     }
498 }
499 
drawBitmapMatrix(JNIEnv * env,jobject,jlong canvasHandle,jlong bitmapHandle,jlong matrixHandle,jlong paintHandle)500 static void drawBitmapMatrix(JNIEnv* env, jobject, jlong canvasHandle, jlong bitmapHandle,
501                              jlong matrixHandle, jlong paintHandle) {
502     const SkMatrix* matrix = reinterpret_cast<SkMatrix*>(matrixHandle);
503     const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
504     Bitmap& bitmap = android::bitmap::toBitmap(bitmapHandle);
505     get_canvas(canvasHandle)->drawBitmap(bitmap, *matrix, paint);
506 }
507 
drawBitmapRect(JNIEnv * env,jobject,jlong canvasHandle,jlong bitmapHandle,float srcLeft,float srcTop,float srcRight,float srcBottom,float dstLeft,float dstTop,float dstRight,float dstBottom,jlong paintHandle,jint screenDensity,jint bitmapDensity)508 static void drawBitmapRect(JNIEnv* env, jobject, jlong canvasHandle, jlong bitmapHandle,
509                            float srcLeft, float srcTop, float srcRight, float srcBottom,
510                            float dstLeft, float dstTop, float dstRight, float dstBottom,
511                            jlong paintHandle, jint screenDensity, jint bitmapDensity) {
512     Canvas* canvas = get_canvas(canvasHandle);
513     const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
514 
515     Bitmap& bitmap = android::bitmap::toBitmap(bitmapHandle);
516     if (screenDensity != 0 && screenDensity != bitmapDensity) {
517         Paint filteredPaint;
518         if (paint) {
519             filteredPaint = *paint;
520         }
521         filteredPaint.setFilterBitmap(true);
522         canvas->drawBitmap(bitmap, srcLeft, srcTop, srcRight, srcBottom,
523                            dstLeft, dstTop, dstRight, dstBottom, &filteredPaint);
524     } else {
525         canvas->drawBitmap(bitmap, srcLeft, srcTop, srcRight, srcBottom,
526                            dstLeft, dstTop, dstRight, dstBottom, paint);
527     }
528 }
529 
drawBitmapArray(JNIEnv * env,jobject,jlong canvasHandle,jintArray jcolors,jint offset,jint stride,jfloat x,jfloat y,jint width,jint height,jboolean hasAlpha,jlong paintHandle)530 static void drawBitmapArray(JNIEnv* env, jobject, jlong canvasHandle,
531                             jintArray jcolors, jint offset, jint stride,
532                             jfloat x, jfloat y, jint width, jint height,
533                             jboolean hasAlpha, jlong paintHandle) {
534     // Note: If hasAlpha is false, kRGB_565_SkColorType will be used, which will
535     // correct the alphaType to kOpaque_SkAlphaType.
536     SkImageInfo info = SkImageInfo::Make(width, height,
537                            hasAlpha ? kN32_SkColorType : kRGB_565_SkColorType,
538                            kPremul_SkAlphaType);
539     SkBitmap bitmap;
540     bitmap.setInfo(info);
541     sk_sp<Bitmap> androidBitmap = Bitmap::allocateHeapBitmap(&bitmap);
542     if (!androidBitmap) {
543         return;
544     }
545 
546     if (!GraphicsJNI::SetPixels(env, jcolors, offset, stride, 0, 0, width, height, &bitmap)) {
547         return;
548     }
549 
550     const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
551     get_canvas(canvasHandle)->drawBitmap(*androidBitmap, x, y, paint);
552 }
553 
drawBitmapMesh(JNIEnv * env,jobject,jlong canvasHandle,jlong bitmapHandle,jint meshWidth,jint meshHeight,jfloatArray jverts,jint vertIndex,jintArray jcolors,jint colorIndex,jlong paintHandle)554 static void drawBitmapMesh(JNIEnv* env, jobject, jlong canvasHandle, jlong bitmapHandle,
555                            jint meshWidth, jint meshHeight, jfloatArray jverts,
556                            jint vertIndex, jintArray jcolors, jint colorIndex, jlong paintHandle) {
557     if (Canvas::GetApiLevel() < __ANDROID_API_P__) {
558         // Before P we forgot to respect these. Now that we do respect them, explicitly
559         // zero them for backward compatibility.
560         vertIndex = 0;
561         colorIndex = 0;
562     }
563 
564     const int ptCount = (meshWidth + 1) * (meshHeight + 1);
565     AutoJavaFloatArray vertA(env, jverts, vertIndex + (ptCount << 1));
566     AutoJavaIntArray colorA(env, jcolors, colorIndex + ptCount);
567 
568     const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
569     Bitmap& bitmap = android::bitmap::toBitmap(bitmapHandle);
570     get_canvas(canvasHandle)->drawBitmapMesh(bitmap, meshWidth, meshHeight,
571                                              vertA.ptr() + vertIndex*2,
572                                              colorA.ptr() + colorIndex, paint);
573 }
574 
drawGlyphs(JNIEnv * env,jobject,jlong canvasHandle,jintArray glyphIds,jfloatArray positions,jint glyphOffset,jint positionOffset,jint glyphCount,jlong fontHandle,jlong paintHandle)575 static void drawGlyphs(JNIEnv* env, jobject, jlong canvasHandle, jintArray glyphIds,
576                        jfloatArray positions, jint glyphOffset, jint positionOffset,
577                        jint glyphCount, jlong fontHandle, jlong paintHandle) {
578     Paint* paint = reinterpret_cast<Paint*>(paintHandle);
579     FontWrapper* font = reinterpret_cast<FontWrapper*>(fontHandle);
580     AutoJavaIntArray glyphIdArray(env, glyphIds);
581     AutoJavaFloatArray positionArray(env, positions);
582     get_canvas(canvasHandle)->drawGlyphs(
583         *font->font.get(),
584         glyphIdArray.ptr() + glyphOffset,
585         positionArray.ptr() + positionOffset,
586         glyphCount,
587         *paint);
588 }
589 
drawTextChars(JNIEnv * env,jobject,jlong canvasHandle,jcharArray charArray,jint index,jint count,jfloat x,jfloat y,jint bidiFlags,jlong paintHandle)590 static void drawTextChars(JNIEnv* env, jobject, jlong canvasHandle, jcharArray charArray,
591                           jint index, jint count, jfloat x, jfloat y, jint bidiFlags,
592                           jlong paintHandle) {
593     Paint* paint = reinterpret_cast<Paint*>(paintHandle);
594     const Typeface* typeface = paint->getAndroidTypeface();
595     ScopedCharArrayRO text(env, charArray);
596     // drawTextString and drawTextChars doesn't use context info
597     get_canvas(canvasHandle)->drawText(
598             text.get() + index, count,  // text buffer
599             0, count,  // draw range
600             0, count,  // context range
601             x, y,  // draw position
602             static_cast<minikin::Bidi>(bidiFlags), *paint, typeface, nullptr /* measured text */);
603 }
604 
drawTextString(JNIEnv * env,jobject,jlong canvasHandle,jstring strObj,jint start,jint end,jfloat x,jfloat y,jint bidiFlags,jlong paintHandle)605 static void drawTextString(JNIEnv* env, jobject, jlong canvasHandle, jstring strObj,
606                            jint start, jint end, jfloat x, jfloat y, jint bidiFlags,
607                            jlong paintHandle) {
608     ScopedStringChars text(env, strObj);
609     Paint* paint = reinterpret_cast<Paint*>(paintHandle);
610     const Typeface* typeface = paint->getAndroidTypeface();
611     const int count = end - start;
612     // drawTextString and drawTextChars doesn't use context info
613     get_canvas(canvasHandle)->drawText(
614             text.get() + start, count,  // text buffer
615             0, count,  // draw range
616             0, count,  // context range
617             x, y,  // draw position
618             static_cast<minikin::Bidi>(bidiFlags), *paint, typeface, nullptr /* measured text */);
619 }
620 
drawTextRunChars(JNIEnv * env,jobject,jlong canvasHandle,jcharArray charArray,jint index,jint count,jint contextIndex,jint contextCount,jfloat x,jfloat y,jboolean isRtl,jlong paintHandle,jlong mtHandle)621 static void drawTextRunChars(JNIEnv* env, jobject, jlong canvasHandle, jcharArray charArray,
622                              jint index, jint count, jint contextIndex, jint contextCount,
623                              jfloat x, jfloat y, jboolean isRtl, jlong paintHandle,
624                              jlong mtHandle) {
625     minikin::MeasuredText* mt = reinterpret_cast<minikin::MeasuredText*>(mtHandle);
626     const minikin::Bidi bidiFlags = isRtl ? minikin::Bidi::FORCE_RTL : minikin::Bidi::FORCE_LTR;
627 
628     ScopedCharArrayRO text(env, charArray);
629     Paint* paint = reinterpret_cast<Paint*>(paintHandle);
630     const Typeface* typeface = paint->getAndroidTypeface();
631     get_canvas(canvasHandle)->drawText(
632             text.get(), text.size(),  // text buffer
633             index, count,  // draw range
634             contextIndex, contextCount,  // context range,
635             x, y,  // draw position
636             bidiFlags, *paint, typeface, mt);
637 }
638 
drawTextRunString(JNIEnv * env,jobject obj,jlong canvasHandle,jstring strObj,jint start,jint end,jint contextStart,jint contextEnd,jfloat x,jfloat y,jboolean isRtl,jlong paintHandle)639 static void drawTextRunString(JNIEnv* env, jobject obj, jlong canvasHandle, jstring strObj,
640                               jint start, jint end, jint contextStart, jint contextEnd,
641                               jfloat x, jfloat y, jboolean isRtl, jlong paintHandle) {
642     const minikin::Bidi bidiFlags = isRtl ? minikin::Bidi::FORCE_RTL : minikin::Bidi::FORCE_LTR;
643 
644     ScopedStringChars text(env, strObj);
645     Paint* paint = reinterpret_cast<Paint*>(paintHandle);
646     const Typeface* typeface = paint->getAndroidTypeface();
647     get_canvas(canvasHandle)->drawText(
648             text.get(), text.size(),  // text buffer
649             start, end - start,  // draw range
650             contextStart, contextEnd - contextStart,  // context range
651             x, y,  // draw position
652             bidiFlags, *paint, typeface, nullptr /* measured text */);
653 }
654 
drawTextOnPathChars(JNIEnv * env,jobject,jlong canvasHandle,jcharArray text,jint index,jint count,jlong pathHandle,jfloat hOffset,jfloat vOffset,jint bidiFlags,jlong paintHandle)655 static void drawTextOnPathChars(JNIEnv* env, jobject, jlong canvasHandle, jcharArray text,
656                                 jint index, jint count, jlong pathHandle, jfloat hOffset,
657                                 jfloat vOffset, jint bidiFlags, jlong paintHandle) {
658     SkPath* path = reinterpret_cast<SkPath*>(pathHandle);
659     Paint* paint = reinterpret_cast<Paint*>(paintHandle);
660     const Typeface* typeface = paint->getAndroidTypeface();
661 
662     jchar* jchars = env->GetCharArrayElements(text, NULL);
663 
664     get_canvas(canvasHandle)->drawTextOnPath(jchars + index, count,
665             static_cast<minikin::Bidi>(bidiFlags), *path, hOffset, vOffset, *paint, typeface);
666 
667     env->ReleaseCharArrayElements(text, jchars, 0);
668 }
669 
drawTextOnPathString(JNIEnv * env,jobject,jlong canvasHandle,jstring text,jlong pathHandle,jfloat hOffset,jfloat vOffset,jint bidiFlags,jlong paintHandle)670 static void drawTextOnPathString(JNIEnv* env, jobject, jlong canvasHandle, jstring text,
671                                  jlong pathHandle, jfloat hOffset, jfloat vOffset,
672                                  jint bidiFlags, jlong paintHandle) {
673     SkPath* path = reinterpret_cast<SkPath*>(pathHandle);
674     Paint* paint = reinterpret_cast<Paint*>(paintHandle);
675     const Typeface* typeface = paint->getAndroidTypeface();
676 
677     const jchar* jchars = env->GetStringChars(text, NULL);
678     int count = env->GetStringLength(text);
679 
680     get_canvas(canvasHandle)->drawTextOnPath(jchars, count, static_cast<minikin::Bidi>(bidiFlags),
681             *path, hOffset, vOffset, *paint, typeface);
682 
683     env->ReleaseStringChars(text, jchars);
684 }
685 
setPaintFilter(CRITICAL_JNI_PARAMS_COMMA jlong canvasHandle,jlong filterHandle)686 static void setPaintFilter(CRITICAL_JNI_PARAMS_COMMA jlong canvasHandle, jlong filterHandle) {
687     PaintFilter* paintFilter = reinterpret_cast<PaintFilter*>(filterHandle);
688     get_canvas(canvasHandle)->setPaintFilter(sk_ref_sp(paintFilter));
689 }
690 
freeCaches(JNIEnv * env,jobject)691 static void freeCaches(JNIEnv* env, jobject) {
692     SkGraphics::PurgeFontCache();
693 }
694 
freeTextLayoutCaches(JNIEnv * env,jobject)695 static void freeTextLayoutCaches(JNIEnv* env, jobject) {
696     minikin::Layout::purgeCaches();
697 }
698 
setCompatibilityVersion(JNIEnv * env,jobject,jint apiLevel)699 static void setCompatibilityVersion(JNIEnv* env, jobject, jint apiLevel) {
700     Canvas::setCompatibilityVersion(apiLevel);
701 }
702 
punchHole(JNIEnv * env,jobject,jlong canvasPtr,jfloat left,jfloat top,jfloat right,jfloat bottom,jfloat rx,jfloat ry)703 static void punchHole(JNIEnv* env, jobject, jlong canvasPtr, jfloat left, jfloat top, jfloat right,
704         jfloat bottom, jfloat rx, jfloat ry) {
705     auto canvas = reinterpret_cast<Canvas*>(canvasPtr);
706     canvas->punchHole(SkRRect::MakeRectXY(SkRect::MakeLTRB(left, top, right, bottom), rx, ry));
707 }
708 
709 }; // namespace CanvasJNI
710 
711 static const JNINativeMethod gMethods[] = {
712     {"nGetNativeFinalizer", "()J", (void*) CanvasJNI::getNativeFinalizer},
713     {"nFreeCaches", "()V", (void*) CanvasJNI::freeCaches},
714     {"nFreeTextLayoutCaches", "()V", (void*) CanvasJNI::freeTextLayoutCaches},
715     {"nSetCompatibilityVersion", "(I)V", (void*) CanvasJNI::setCompatibilityVersion},
716 
717     // ------------ @FastNative ----------------
718     {"nInitRaster", "(J)J", (void*) CanvasJNI::initRaster},
719     {"nSetBitmap", "(JJ)V", (void*) CanvasJNI::setBitmap},
720     {"nGetClipBounds","(JLandroid/graphics/Rect;)Z", (void*) CanvasJNI::getClipBounds},
721 
722     // ------------ @CriticalNative ----------------
723     {"nIsOpaque","(J)Z", (void*) CanvasJNI::isOpaque},
724     {"nGetWidth","(J)I", (void*) CanvasJNI::getWidth},
725     {"nGetHeight","(J)I", (void*) CanvasJNI::getHeight},
726     {"nSave","(JI)I", (void*) CanvasJNI::save},
727     {"nSaveLayer","(JFFFFJ)I", (void*) CanvasJNI::saveLayer},
728     {"nSaveLayerAlpha","(JFFFFI)I", (void*) CanvasJNI::saveLayerAlpha},
729     {"nSaveUnclippedLayer","(JIIII)I", (void*) CanvasJNI::saveUnclippedLayer},
730     {"nRestoreUnclippedLayer","(JIJ)V", (void*) CanvasJNI::restoreUnclippedLayer},
731     {"nGetSaveCount","(J)I", (void*) CanvasJNI::getSaveCount},
732     {"nRestore","(J)Z", (void*) CanvasJNI::restore},
733     {"nRestoreToCount","(JI)V", (void*) CanvasJNI::restoreToCount},
734     {"nGetMatrix", "(JJ)V", (void*)CanvasJNI::getMatrix},
735     {"nSetMatrix","(JJ)V", (void*) CanvasJNI::setMatrix},
736     {"nConcat","(JJ)V", (void*) CanvasJNI::concat},
737     {"nRotate","(JF)V", (void*) CanvasJNI::rotate},
738     {"nScale","(JFF)V", (void*) CanvasJNI::scale},
739     {"nSkew","(JFF)V", (void*) CanvasJNI::skew},
740     {"nTranslate","(JFF)V", (void*) CanvasJNI::translate},
741     {"nQuickReject","(JJ)Z", (void*) CanvasJNI::quickRejectPath},
742     {"nQuickReject","(JFFFF)Z", (void*)CanvasJNI::quickRejectRect},
743     {"nClipRect","(JFFFFI)Z", (void*) CanvasJNI::clipRect},
744     {"nClipPath","(JJI)Z", (void*) CanvasJNI::clipPath},
745     {"nSetDrawFilter", "(JJ)V", (void*) CanvasJNI::setPaintFilter},
746 };
747 
748 // If called from Canvas these are regular JNI
749 // If called from DisplayListCanvas they are @FastNative
750 static const JNINativeMethod gDrawMethods[] = {
751     {"nDrawColor","(JII)V", (void*) CanvasJNI::drawColor},
752     {"nDrawColor","(JJJI)V", (void*) CanvasJNI::drawColorLong},
753     {"nDrawPaint","(JJ)V", (void*) CanvasJNI::drawPaint},
754     {"nDrawPoint", "(JFFJ)V", (void*) CanvasJNI::drawPoint},
755     {"nDrawPoints", "(J[FIIJ)V", (void*) CanvasJNI::drawPoints},
756     {"nDrawLine", "(JFFFFJ)V", (void*) CanvasJNI::drawLine},
757     {"nDrawLines", "(J[FIIJ)V", (void*) CanvasJNI::drawLines},
758     {"nDrawRect","(JFFFFJ)V", (void*) CanvasJNI::drawRect},
759     {"nDrawRegion", "(JJJ)V", (void*) CanvasJNI::drawRegion },
760     {"nDrawRoundRect","(JFFFFFFJ)V", (void*) CanvasJNI::drawRoundRect},
761     {"nDrawDoubleRoundRect", "(JFFFFFFFFFFFFJ)V", (void*) CanvasJNI::drawDoubleRoundRectXY},
762     {"nDrawDoubleRoundRect", "(JFFFF[FFFFF[FJ)V", (void*) CanvasJNI::drawDoubleRoundRectRadii},
763     {"nDrawCircle","(JFFFJ)V", (void*) CanvasJNI::drawCircle},
764     {"nDrawOval","(JFFFFJ)V", (void*) CanvasJNI::drawOval},
765     {"nDrawArc","(JFFFFFFZJ)V", (void*) CanvasJNI::drawArc},
766     {"nDrawPath","(JJJ)V", (void*) CanvasJNI::drawPath},
767     {"nDrawVertices", "(JII[FI[FI[II[SIIJ)V", (void*)CanvasJNI::drawVertices},
768     {"nDrawNinePatch", "(JJJFFFFJII)V", (void*)CanvasJNI::drawNinePatch},
769     {"nDrawBitmapMatrix", "(JJJJ)V", (void*)CanvasJNI::drawBitmapMatrix},
770     {"nDrawBitmapMesh", "(JJII[FI[IIJ)V", (void*)CanvasJNI::drawBitmapMesh},
771     {"nDrawBitmap","(JJFFJIII)V", (void*) CanvasJNI::drawBitmap},
772     {"nDrawBitmap","(JJFFFFFFFFJII)V", (void*) CanvasJNI::drawBitmapRect},
773     {"nDrawBitmap", "(J[IIIFFIIZJ)V", (void*)CanvasJNI::drawBitmapArray},
774     {"nDrawGlyphs", "(J[I[FIIIJJ)V", (void*)CanvasJNI::drawGlyphs},
775     {"nDrawText","(J[CIIFFIJ)V", (void*) CanvasJNI::drawTextChars},
776     {"nDrawText","(JLjava/lang/String;IIFFIJ)V", (void*) CanvasJNI::drawTextString},
777     {"nDrawTextRun","(J[CIIIIFFZJJ)V", (void*) CanvasJNI::drawTextRunChars},
778     {"nDrawTextRun","(JLjava/lang/String;IIIIFFZJ)V", (void*) CanvasJNI::drawTextRunString},
779     {"nDrawTextOnPath","(J[CIIJFFIJ)V", (void*) CanvasJNI::drawTextOnPathChars},
780     {"nDrawTextOnPath","(JLjava/lang/String;JFFIJ)V", (void*) CanvasJNI::drawTextOnPathString},
781     {"nPunchHole", "(JFFFFFF)V", (void*) CanvasJNI::punchHole}
782 };
783 
register_android_graphics_Canvas(JNIEnv * env)784 int register_android_graphics_Canvas(JNIEnv* env) {
785     int ret = 0;
786     ret |= RegisterMethodsOrDie(env, "android/graphics/Canvas", gMethods, NELEM(gMethods));
787     ret |= RegisterMethodsOrDie(env, "android/graphics/BaseCanvas", gDrawMethods, NELEM(gDrawMethods));
788     ret |= RegisterMethodsOrDie(env, "android/graphics/BaseRecordingCanvas", gDrawMethods, NELEM(gDrawMethods));
789     return ret;
790 
791 }
792 
793 }; // namespace android
794