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