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