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