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