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 // SkRegion::Op and SkClipOp are numerically identical, so we can freely cast
192 // from one to the other (though SkClipOp is destined to become a strict subset)
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 static_assert(SkRegion::kUnion_Op == static_cast<SkRegion::Op>(SkClipOp::kUnion_deprecated), "");
196 static_assert(SkRegion::kXOR_Op == static_cast<SkRegion::Op>(SkClipOp::kXOR_deprecated), "");
197 static_assert(SkRegion::kReverseDifference_Op == static_cast<SkRegion::Op>(SkClipOp::kReverseDifference_deprecated), "");
198 static_assert(SkRegion::kReplace_Op == static_cast<SkRegion::Op>(SkClipOp::kReplace_deprecated), "");
199
opHandleToClipOp(jint opHandle)200 static SkClipOp opHandleToClipOp(jint opHandle) {
201 // The opHandle is defined in Canvas.java to be Region::Op
202 SkRegion::Op rgnOp = static_cast<SkRegion::Op>(opHandle);
203
204 // In the future, when we no longer support the wide range of ops (e.g. Union, Xor)
205 // this function can perform a range check and throw an unsupported-exception.
206 // e.g. if (rgnOp != kIntersect && rgnOp != kDifference) throw...
207
208 // Skia now takes a different type, SkClipOp, as the parameter to clipping calls
209 // This type is binary compatible with SkRegion::Op, so a static_cast<> is safe.
210 return static_cast<SkClipOp>(rgnOp);
211 }
212
clipRect(CRITICAL_JNI_PARAMS_COMMA jlong canvasHandle,jfloat l,jfloat t,jfloat r,jfloat b,jint opHandle)213 static jboolean clipRect(CRITICAL_JNI_PARAMS_COMMA jlong canvasHandle, jfloat l, jfloat t,
214 jfloat r, jfloat b, jint opHandle) {
215 bool nonEmptyClip = get_canvas(canvasHandle)->clipRect(l, t, r, b,
216 opHandleToClipOp(opHandle));
217 return nonEmptyClip ? JNI_TRUE : JNI_FALSE;
218 }
219
clipPath(CRITICAL_JNI_PARAMS_COMMA jlong canvasHandle,jlong pathHandle,jint opHandle)220 static jboolean clipPath(CRITICAL_JNI_PARAMS_COMMA jlong canvasHandle, jlong pathHandle,
221 jint opHandle) {
222 SkPath* path = reinterpret_cast<SkPath*>(pathHandle);
223 bool nonEmptyClip = get_canvas(canvasHandle)->clipPath(path, opHandleToClipOp(opHandle));
224 return nonEmptyClip ? JNI_TRUE : JNI_FALSE;
225 }
226
drawColor(JNIEnv * env,jobject,jlong canvasHandle,jint color,jint modeHandle)227 static void drawColor(JNIEnv* env, jobject, jlong canvasHandle, jint color, jint modeHandle) {
228 SkBlendMode mode = static_cast<SkBlendMode>(modeHandle);
229 get_canvas(canvasHandle)->drawColor(color, mode);
230 }
231
drawColorLong(JNIEnv * env,jobject,jlong canvasHandle,jlong colorSpaceHandle,jlong colorLong,jint modeHandle)232 static void drawColorLong(JNIEnv* env, jobject, jlong canvasHandle, jlong colorSpaceHandle,
233 jlong colorLong, jint modeHandle) {
234 SkColor4f color = GraphicsJNI::convertColorLong(colorLong);
235 sk_sp<SkColorSpace> cs = GraphicsJNI::getNativeColorSpace(colorSpaceHandle);
236 SkPaint p;
237 p.setColor4f(color, cs.get());
238
239 SkBlendMode mode = static_cast<SkBlendMode>(modeHandle);
240 p.setBlendMode(mode);
241 get_canvas(canvasHandle)->drawPaint(p);
242 }
243
drawPaint(JNIEnv * env,jobject,jlong canvasHandle,jlong paintHandle)244 static void drawPaint(JNIEnv* env, jobject, jlong canvasHandle, jlong paintHandle) {
245 Paint* paint = reinterpret_cast<Paint*>(paintHandle);
246 get_canvas(canvasHandle)->drawPaint(*paint);
247 }
248
drawPoint(JNIEnv *,jobject,jlong canvasHandle,jfloat x,jfloat y,jlong paintHandle)249 static void drawPoint(JNIEnv*, jobject, jlong canvasHandle, jfloat x, jfloat y,
250 jlong paintHandle) {
251 const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
252 get_canvas(canvasHandle)->drawPoint(x, y, *paint);
253 }
254
drawPoints(JNIEnv * env,jobject,jlong canvasHandle,jfloatArray jptsArray,jint offset,jint count,jlong paintHandle)255 static void drawPoints(JNIEnv* env, jobject, jlong canvasHandle, jfloatArray jptsArray,
256 jint offset, jint count, jlong paintHandle) {
257 NPE_CHECK_RETURN_VOID(env, jptsArray);
258 AutoJavaFloatArray autoPts(env, jptsArray);
259 float* floats = autoPts.ptr();
260 const int length = autoPts.length();
261
262 if ((offset | count) < 0 || offset + count > length) {
263 doThrowAIOOBE(env);
264 return;
265 }
266
267 const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
268 get_canvas(canvasHandle)->drawPoints(floats + offset, count, *paint);
269 }
270
drawLine(JNIEnv * env,jobject,jlong canvasHandle,jfloat startX,jfloat startY,jfloat stopX,jfloat stopY,jlong paintHandle)271 static void drawLine(JNIEnv* env, jobject, jlong canvasHandle, jfloat startX, jfloat startY,
272 jfloat stopX, jfloat stopY, jlong paintHandle) {
273 Paint* paint = reinterpret_cast<Paint*>(paintHandle);
274 get_canvas(canvasHandle)->drawLine(startX, startY, stopX, stopY, *paint);
275 }
276
drawLines(JNIEnv * env,jobject,jlong canvasHandle,jfloatArray jptsArray,jint offset,jint count,jlong paintHandle)277 static void drawLines(JNIEnv* env, jobject, jlong canvasHandle, jfloatArray jptsArray,
278 jint offset, jint count, jlong paintHandle) {
279 NPE_CHECK_RETURN_VOID(env, jptsArray);
280 AutoJavaFloatArray autoPts(env, jptsArray);
281 float* floats = autoPts.ptr();
282 const int length = autoPts.length();
283
284 if ((offset | count) < 0 || offset + count > length) {
285 doThrowAIOOBE(env);
286 return;
287 }
288
289 const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
290 get_canvas(canvasHandle)->drawLines(floats + offset, count, *paint);
291 }
292
drawRect(JNIEnv * env,jobject,jlong canvasHandle,jfloat left,jfloat top,jfloat right,jfloat bottom,jlong paintHandle)293 static void drawRect(JNIEnv* env, jobject, jlong canvasHandle, jfloat left, jfloat top,
294 jfloat right, jfloat bottom, jlong paintHandle) {
295 const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
296 get_canvas(canvasHandle)->drawRect(left, top, right, bottom, *paint);
297 }
298
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)299 static void drawDoubleRoundRectXY(JNIEnv* env, jobject, jlong canvasHandle, jfloat outerLeft,
300 jfloat outerTop, jfloat outerRight, jfloat outerBottom, jfloat outerRx,
301 jfloat outerRy, jfloat innerLeft, jfloat innerTop, jfloat innerRight,
302 jfloat innerBottom, jfloat innerRx, jfloat innerRy, jlong paintHandle) {
303 const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
304 get_canvas(canvasHandle)->drawDoubleRoundRectXY(
305 outerLeft, outerTop, outerRight, outerBottom, outerRx, outerRy,
306 innerLeft, innerTop, innerRight, innerBottom, innerRx, innerRy, *paint);
307 }
308
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)309 static void drawDoubleRoundRectRadii(JNIEnv* env, jobject, jlong canvasHandle, jfloat outerLeft,
310 jfloat outerTop, jfloat outerRight, jfloat outerBottom, jfloatArray jouterRadii,
311 jfloat innerLeft, jfloat innerTop, jfloat innerRight,
312 jfloat innerBottom, jfloatArray jinnerRadii, jlong paintHandle) {
313 const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
314
315 float outerRadii[8];
316 float innerRadii[8];
317 env->GetFloatArrayRegion(jouterRadii, 0, 8, outerRadii);
318 env->GetFloatArrayRegion(jinnerRadii, 0, 8, innerRadii);
319 get_canvas(canvasHandle)->drawDoubleRoundRectRadii(
320 outerLeft, outerTop, outerRight, outerBottom, outerRadii,
321 innerLeft, innerTop, innerRight, innerBottom, innerRadii, *paint);
322
323 }
324
drawRegion(JNIEnv * env,jobject,jlong canvasHandle,jlong regionHandle,jlong paintHandle)325 static void drawRegion(JNIEnv* env, jobject, jlong canvasHandle, jlong regionHandle,
326 jlong paintHandle) {
327 const SkRegion* region = reinterpret_cast<SkRegion*>(regionHandle);
328 const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
329 get_canvas(canvasHandle)->drawRegion(*region, *paint);
330 }
331
drawRoundRect(JNIEnv * env,jobject,jlong canvasHandle,jfloat left,jfloat top,jfloat right,jfloat bottom,jfloat rx,jfloat ry,jlong paintHandle)332 static void drawRoundRect(JNIEnv* env, jobject, jlong canvasHandle, jfloat left, jfloat top,
333 jfloat right, jfloat bottom, jfloat rx, jfloat ry, jlong paintHandle) {
334 const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
335 get_canvas(canvasHandle)->drawRoundRect(left, top, right, bottom, rx, ry, *paint);
336 }
337
drawCircle(JNIEnv * env,jobject,jlong canvasHandle,jfloat cx,jfloat cy,jfloat radius,jlong paintHandle)338 static void drawCircle(JNIEnv* env, jobject, jlong canvasHandle, jfloat cx, jfloat cy,
339 jfloat radius, jlong paintHandle) {
340 const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
341 get_canvas(canvasHandle)->drawCircle(cx, cy, radius, *paint);
342 }
343
drawOval(JNIEnv * env,jobject,jlong canvasHandle,jfloat left,jfloat top,jfloat right,jfloat bottom,jlong paintHandle)344 static void drawOval(JNIEnv* env, jobject, jlong canvasHandle, jfloat left, jfloat top,
345 jfloat right, jfloat bottom, jlong paintHandle) {
346 const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
347 get_canvas(canvasHandle)->drawOval(left, top, right, bottom, *paint);
348 }
349
drawArc(JNIEnv * env,jobject,jlong canvasHandle,jfloat left,jfloat top,jfloat right,jfloat bottom,jfloat startAngle,jfloat sweepAngle,jboolean useCenter,jlong paintHandle)350 static void drawArc(JNIEnv* env, jobject, jlong canvasHandle, jfloat left, jfloat top,
351 jfloat right, jfloat bottom, jfloat startAngle, jfloat sweepAngle,
352 jboolean useCenter, jlong paintHandle) {
353 const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
354 get_canvas(canvasHandle)->drawArc(left, top, right, bottom, startAngle, sweepAngle,
355 useCenter, *paint);
356 }
357
drawPath(JNIEnv * env,jobject,jlong canvasHandle,jlong pathHandle,jlong paintHandle)358 static void drawPath(JNIEnv* env, jobject, jlong canvasHandle, jlong pathHandle,
359 jlong paintHandle) {
360 const SkPath* path = reinterpret_cast<SkPath*>(pathHandle);
361 const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
362 get_canvas(canvasHandle)->drawPath(*path, *paint);
363 }
364
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)365 static void drawVertices(JNIEnv* env, jobject, jlong canvasHandle,
366 jint modeHandle, jint floatCount,
367 jfloatArray jverts, jint vertIndex,
368 jfloatArray jtexs, jint texIndex,
369 jintArray jcolors, jint colorIndex,
370 jshortArray jindices, jint indexIndex,
371 jint indexCount, jlong paintHandle) {
372
373 const int vertexCount = floatCount >> 1; // 2 floats per SkPoint
374
375 AutoJavaFloatArray vertA(env, jverts, vertIndex + floatCount);
376 AutoJavaFloatArray texA(env, jtexs, texIndex + floatCount);
377 AutoJavaIntArray colorA(env, jcolors, colorIndex + vertexCount);
378 AutoJavaShortArray indexA(env, jindices, indexIndex + indexCount);
379
380 const float* verts = vertA.ptr() + vertIndex;
381 const float* texs = texA.ptr() + vertIndex;
382 const int* colors = NULL;
383 const uint16_t* indices = NULL;
384
385 if (jcolors != NULL) {
386 colors = colorA.ptr() + colorIndex;
387 }
388 if (jindices != NULL) {
389 indices = (const uint16_t*)(indexA.ptr() + indexIndex);
390 }
391
392 SkVertices::VertexMode mode = static_cast<SkVertices::VertexMode>(modeHandle);
393 const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
394 get_canvas(canvasHandle)->drawVertices(SkVertices::MakeCopy(mode, vertexCount,
395 reinterpret_cast<const SkPoint*>(verts),
396 reinterpret_cast<const SkPoint*>(texs),
397 reinterpret_cast<const SkColor*>(colors),
398 indexCount, indices).get(),
399 SkBlendMode::kModulate, *paint);
400 }
401
drawNinePatch(JNIEnv * env,jobject,jlong canvasHandle,jlong bitmapHandle,jlong chunkHandle,jfloat left,jfloat top,jfloat right,jfloat bottom,jlong paintHandle,jint dstDensity,jint srcDensity)402 static void drawNinePatch(JNIEnv* env, jobject, jlong canvasHandle, jlong bitmapHandle,
403 jlong chunkHandle, jfloat left, jfloat top, jfloat right, jfloat bottom,
404 jlong paintHandle, jint dstDensity, jint srcDensity) {
405
406 Canvas* canvas = get_canvas(canvasHandle);
407 Bitmap& bitmap = android::bitmap::toBitmap(bitmapHandle);
408 const android::Res_png_9patch* chunk = reinterpret_cast<android::Res_png_9patch*>(chunkHandle);
409 const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
410
411 if (CC_LIKELY(dstDensity == srcDensity || dstDensity == 0 || srcDensity == 0)) {
412 canvas->drawNinePatch(bitmap, *chunk, left, top, right, bottom, paint);
413 } else {
414 canvas->save(SaveFlags::MatrixClip);
415
416 SkScalar scale = dstDensity / (float)srcDensity;
417 canvas->translate(left, top);
418 canvas->scale(scale, scale);
419
420 Paint filteredPaint;
421 if (paint) {
422 filteredPaint = *paint;
423 }
424 filteredPaint.setFilterQuality(kLow_SkFilterQuality);
425
426 canvas->drawNinePatch(bitmap, *chunk, 0, 0, (right-left)/scale, (bottom-top)/scale,
427 &filteredPaint);
428
429 canvas->restore();
430 }
431 }
432
drawBitmap(JNIEnv * env,jobject,jlong canvasHandle,jlong bitmapHandle,jfloat left,jfloat top,jlong paintHandle,jint canvasDensity,jint screenDensity,jint bitmapDensity)433 static void drawBitmap(JNIEnv* env, jobject, jlong canvasHandle, jlong bitmapHandle,
434 jfloat left, jfloat top, jlong paintHandle, jint canvasDensity,
435 jint screenDensity, jint bitmapDensity) {
436 Canvas* canvas = get_canvas(canvasHandle);
437 Bitmap& bitmap = android::bitmap::toBitmap(bitmapHandle);
438 const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
439
440 if (canvasDensity == bitmapDensity || canvasDensity == 0 || bitmapDensity == 0) {
441 if (screenDensity != 0 && screenDensity != bitmapDensity) {
442 Paint filteredPaint;
443 if (paint) {
444 filteredPaint = *paint;
445 }
446 filteredPaint.setFilterQuality(kLow_SkFilterQuality);
447 canvas->drawBitmap(bitmap, left, top, &filteredPaint);
448 } else {
449 canvas->drawBitmap(bitmap, left, top, paint);
450 }
451 } else {
452 canvas->save(SaveFlags::MatrixClip);
453 SkScalar scale = canvasDensity / (float)bitmapDensity;
454 canvas->translate(left, top);
455 canvas->scale(scale, scale);
456
457 Paint filteredPaint;
458 if (paint) {
459 filteredPaint = *paint;
460 }
461 filteredPaint.setFilterQuality(kLow_SkFilterQuality);
462
463 canvas->drawBitmap(bitmap, 0, 0, &filteredPaint);
464 canvas->restore();
465 }
466 }
467
drawBitmapMatrix(JNIEnv * env,jobject,jlong canvasHandle,jlong bitmapHandle,jlong matrixHandle,jlong paintHandle)468 static void drawBitmapMatrix(JNIEnv* env, jobject, jlong canvasHandle, jlong bitmapHandle,
469 jlong matrixHandle, jlong paintHandle) {
470 const SkMatrix* matrix = reinterpret_cast<SkMatrix*>(matrixHandle);
471 const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
472 Bitmap& bitmap = android::bitmap::toBitmap(bitmapHandle);
473 get_canvas(canvasHandle)->drawBitmap(bitmap, *matrix, paint);
474 }
475
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)476 static void drawBitmapRect(JNIEnv* env, jobject, jlong canvasHandle, jlong bitmapHandle,
477 float srcLeft, float srcTop, float srcRight, float srcBottom,
478 float dstLeft, float dstTop, float dstRight, float dstBottom,
479 jlong paintHandle, jint screenDensity, jint bitmapDensity) {
480 Canvas* canvas = get_canvas(canvasHandle);
481 const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
482
483 Bitmap& bitmap = android::bitmap::toBitmap(bitmapHandle);
484 if (screenDensity != 0 && screenDensity != bitmapDensity) {
485 Paint filteredPaint;
486 if (paint) {
487 filteredPaint = *paint;
488 }
489 filteredPaint.setFilterQuality(kLow_SkFilterQuality);
490 canvas->drawBitmap(bitmap, srcLeft, srcTop, srcRight, srcBottom,
491 dstLeft, dstTop, dstRight, dstBottom, &filteredPaint);
492 } else {
493 canvas->drawBitmap(bitmap, srcLeft, srcTop, srcRight, srcBottom,
494 dstLeft, dstTop, dstRight, dstBottom, paint);
495 }
496 }
497
drawBitmapArray(JNIEnv * env,jobject,jlong canvasHandle,jintArray jcolors,jint offset,jint stride,jfloat x,jfloat y,jint width,jint height,jboolean hasAlpha,jlong paintHandle)498 static void drawBitmapArray(JNIEnv* env, jobject, jlong canvasHandle,
499 jintArray jcolors, jint offset, jint stride,
500 jfloat x, jfloat y, jint width, jint height,
501 jboolean hasAlpha, jlong paintHandle) {
502 // Note: If hasAlpha is false, kRGB_565_SkColorType will be used, which will
503 // correct the alphaType to kOpaque_SkAlphaType.
504 SkImageInfo info = SkImageInfo::Make(width, height,
505 hasAlpha ? kN32_SkColorType : kRGB_565_SkColorType,
506 kPremul_SkAlphaType);
507 SkBitmap bitmap;
508 bitmap.setInfo(info);
509 sk_sp<Bitmap> androidBitmap = Bitmap::allocateHeapBitmap(&bitmap);
510 if (!androidBitmap) {
511 return;
512 }
513
514 if (!GraphicsJNI::SetPixels(env, jcolors, offset, stride, 0, 0, width, height, &bitmap)) {
515 return;
516 }
517
518 const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
519 get_canvas(canvasHandle)->drawBitmap(*androidBitmap, x, y, paint);
520 }
521
drawBitmapMesh(JNIEnv * env,jobject,jlong canvasHandle,jlong bitmapHandle,jint meshWidth,jint meshHeight,jfloatArray jverts,jint vertIndex,jintArray jcolors,jint colorIndex,jlong paintHandle)522 static void drawBitmapMesh(JNIEnv* env, jobject, jlong canvasHandle, jlong bitmapHandle,
523 jint meshWidth, jint meshHeight, jfloatArray jverts,
524 jint vertIndex, jintArray jcolors, jint colorIndex, jlong paintHandle) {
525 if (Canvas::GetApiLevel() < __ANDROID_API_P__) {
526 // Before P we forgot to respect these. Now that we do respect them, explicitly
527 // zero them for backward compatibility.
528 vertIndex = 0;
529 colorIndex = 0;
530 }
531
532 const int ptCount = (meshWidth + 1) * (meshHeight + 1);
533 AutoJavaFloatArray vertA(env, jverts, vertIndex + (ptCount << 1));
534 AutoJavaIntArray colorA(env, jcolors, colorIndex + ptCount);
535
536 const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
537 Bitmap& bitmap = android::bitmap::toBitmap(bitmapHandle);
538 get_canvas(canvasHandle)->drawBitmapMesh(bitmap, meshWidth, meshHeight,
539 vertA.ptr() + vertIndex*2,
540 colorA.ptr() + colorIndex, paint);
541 }
542
drawGlyphs(JNIEnv * env,jobject,jlong canvasHandle,jintArray glyphIds,jfloatArray positions,jint glyphOffset,jint positionOffset,jint glyphCount,jlong fontHandle,jlong paintHandle)543 static void drawGlyphs(JNIEnv* env, jobject, jlong canvasHandle, jintArray glyphIds,
544 jfloatArray positions, jint glyphOffset, jint positionOffset,
545 jint glyphCount, jlong fontHandle, jlong paintHandle) {
546 Paint* paint = reinterpret_cast<Paint*>(paintHandle);
547 FontWrapper* font = reinterpret_cast<FontWrapper*>(fontHandle);
548 AutoJavaIntArray glyphIdArray(env, glyphIds);
549 AutoJavaFloatArray positionArray(env, positions);
550 get_canvas(canvasHandle)->drawGlyphs(
551 *font->font.get(),
552 glyphIdArray.ptr() + glyphOffset,
553 positionArray.ptr() + positionOffset,
554 glyphCount,
555 *paint);
556 }
557
drawTextChars(JNIEnv * env,jobject,jlong canvasHandle,jcharArray charArray,jint index,jint count,jfloat x,jfloat y,jint bidiFlags,jlong paintHandle)558 static void drawTextChars(JNIEnv* env, jobject, jlong canvasHandle, jcharArray charArray,
559 jint index, jint count, jfloat x, jfloat y, jint bidiFlags,
560 jlong paintHandle) {
561 Paint* paint = reinterpret_cast<Paint*>(paintHandle);
562 const Typeface* typeface = paint->getAndroidTypeface();
563 ScopedCharArrayRO text(env, charArray);
564 // drawTextString and drawTextChars doesn't use context info
565 get_canvas(canvasHandle)->drawText(
566 text.get() + index, count, // text buffer
567 0, count, // draw range
568 0, count, // context range
569 x, y, // draw position
570 static_cast<minikin::Bidi>(bidiFlags), *paint, typeface, nullptr /* measured text */);
571 }
572
drawTextString(JNIEnv * env,jobject,jlong canvasHandle,jstring strObj,jint start,jint end,jfloat x,jfloat y,jint bidiFlags,jlong paintHandle)573 static void drawTextString(JNIEnv* env, jobject, jlong canvasHandle, jstring strObj,
574 jint start, jint end, jfloat x, jfloat y, jint bidiFlags,
575 jlong paintHandle) {
576 ScopedStringChars text(env, strObj);
577 Paint* paint = reinterpret_cast<Paint*>(paintHandle);
578 const Typeface* typeface = paint->getAndroidTypeface();
579 const int count = end - start;
580 // drawTextString and drawTextChars doesn't use context info
581 get_canvas(canvasHandle)->drawText(
582 text.get() + start, count, // text buffer
583 0, count, // draw range
584 0, count, // context range
585 x, y, // draw position
586 static_cast<minikin::Bidi>(bidiFlags), *paint, typeface, nullptr /* measured text */);
587 }
588
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)589 static void drawTextRunChars(JNIEnv* env, jobject, jlong canvasHandle, jcharArray charArray,
590 jint index, jint count, jint contextIndex, jint contextCount,
591 jfloat x, jfloat y, jboolean isRtl, jlong paintHandle,
592 jlong mtHandle) {
593 minikin::MeasuredText* mt = reinterpret_cast<minikin::MeasuredText*>(mtHandle);
594 const minikin::Bidi bidiFlags = isRtl ? minikin::Bidi::FORCE_RTL : minikin::Bidi::FORCE_LTR;
595
596 ScopedCharArrayRO text(env, charArray);
597 Paint* paint = reinterpret_cast<Paint*>(paintHandle);
598 const Typeface* typeface = paint->getAndroidTypeface();
599 get_canvas(canvasHandle)->drawText(
600 text.get(), text.size(), // text buffer
601 index, count, // draw range
602 contextIndex, contextCount, // context range,
603 x, y, // draw position
604 bidiFlags, *paint, typeface, mt);
605 }
606
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)607 static void drawTextRunString(JNIEnv* env, jobject obj, jlong canvasHandle, jstring strObj,
608 jint start, jint end, jint contextStart, jint contextEnd,
609 jfloat x, jfloat y, jboolean isRtl, jlong paintHandle) {
610 const minikin::Bidi bidiFlags = isRtl ? minikin::Bidi::FORCE_RTL : minikin::Bidi::FORCE_LTR;
611
612 ScopedStringChars text(env, strObj);
613 Paint* paint = reinterpret_cast<Paint*>(paintHandle);
614 const Typeface* typeface = paint->getAndroidTypeface();
615 get_canvas(canvasHandle)->drawText(
616 text.get(), text.size(), // text buffer
617 start, end - start, // draw range
618 contextStart, contextEnd - contextStart, // context range
619 x, y, // draw position
620 bidiFlags, *paint, typeface, nullptr /* measured text */);
621 }
622
drawTextOnPathChars(JNIEnv * env,jobject,jlong canvasHandle,jcharArray text,jint index,jint count,jlong pathHandle,jfloat hOffset,jfloat vOffset,jint bidiFlags,jlong paintHandle)623 static void drawTextOnPathChars(JNIEnv* env, jobject, jlong canvasHandle, jcharArray text,
624 jint index, jint count, jlong pathHandle, jfloat hOffset,
625 jfloat vOffset, jint bidiFlags, jlong paintHandle) {
626 SkPath* path = reinterpret_cast<SkPath*>(pathHandle);
627 Paint* paint = reinterpret_cast<Paint*>(paintHandle);
628 const Typeface* typeface = paint->getAndroidTypeface();
629
630 jchar* jchars = env->GetCharArrayElements(text, NULL);
631
632 get_canvas(canvasHandle)->drawTextOnPath(jchars + index, count,
633 static_cast<minikin::Bidi>(bidiFlags), *path, hOffset, vOffset, *paint, typeface);
634
635 env->ReleaseCharArrayElements(text, jchars, 0);
636 }
637
drawTextOnPathString(JNIEnv * env,jobject,jlong canvasHandle,jstring text,jlong pathHandle,jfloat hOffset,jfloat vOffset,jint bidiFlags,jlong paintHandle)638 static void drawTextOnPathString(JNIEnv* env, jobject, jlong canvasHandle, jstring text,
639 jlong pathHandle, jfloat hOffset, jfloat vOffset,
640 jint bidiFlags, jlong paintHandle) {
641 SkPath* path = reinterpret_cast<SkPath*>(pathHandle);
642 Paint* paint = reinterpret_cast<Paint*>(paintHandle);
643 const Typeface* typeface = paint->getAndroidTypeface();
644
645 const jchar* jchars = env->GetStringChars(text, NULL);
646 int count = env->GetStringLength(text);
647
648 get_canvas(canvasHandle)->drawTextOnPath(jchars, count, static_cast<minikin::Bidi>(bidiFlags),
649 *path, hOffset, vOffset, *paint, typeface);
650
651 env->ReleaseStringChars(text, jchars);
652 }
653
setPaintFilter(CRITICAL_JNI_PARAMS_COMMA jlong canvasHandle,jlong filterHandle)654 static void setPaintFilter(CRITICAL_JNI_PARAMS_COMMA jlong canvasHandle, jlong filterHandle) {
655 PaintFilter* paintFilter = reinterpret_cast<PaintFilter*>(filterHandle);
656 get_canvas(canvasHandle)->setPaintFilter(sk_ref_sp(paintFilter));
657 }
658
freeCaches(JNIEnv * env,jobject)659 static void freeCaches(JNIEnv* env, jobject) {
660 SkGraphics::PurgeFontCache();
661 }
662
freeTextLayoutCaches(JNIEnv * env,jobject)663 static void freeTextLayoutCaches(JNIEnv* env, jobject) {
664 minikin::Layout::purgeCaches();
665 }
666
setCompatibilityVersion(JNIEnv * env,jobject,jint apiLevel)667 static void setCompatibilityVersion(JNIEnv* env, jobject, jint apiLevel) {
668 Canvas::setCompatibilityVersion(apiLevel);
669 }
670
punchHole(JNIEnv * env,jobject,jlong canvasPtr,jfloat left,jfloat top,jfloat right,jfloat bottom,jfloat rx,jfloat ry)671 static void punchHole(JNIEnv* env, jobject, jlong canvasPtr, jfloat left, jfloat top, jfloat right,
672 jfloat bottom, jfloat rx, jfloat ry) {
673 auto canvas = reinterpret_cast<Canvas*>(canvasPtr);
674 canvas->punchHole(SkRRect::MakeRectXY(SkRect::MakeLTRB(left, top, right, bottom), rx, ry));
675 }
676
677 }; // namespace CanvasJNI
678
679 static const JNINativeMethod gMethods[] = {
680 {"nGetNativeFinalizer", "()J", (void*) CanvasJNI::getNativeFinalizer},
681 {"nFreeCaches", "()V", (void*) CanvasJNI::freeCaches},
682 {"nFreeTextLayoutCaches", "()V", (void*) CanvasJNI::freeTextLayoutCaches},
683 {"nSetCompatibilityVersion", "(I)V", (void*) CanvasJNI::setCompatibilityVersion},
684
685 // ------------ @FastNative ----------------
686 {"nInitRaster", "(J)J", (void*) CanvasJNI::initRaster},
687 {"nSetBitmap", "(JJ)V", (void*) CanvasJNI::setBitmap},
688 {"nGetClipBounds","(JLandroid/graphics/Rect;)Z", (void*) CanvasJNI::getClipBounds},
689
690 // ------------ @CriticalNative ----------------
691 {"nIsOpaque","(J)Z", (void*) CanvasJNI::isOpaque},
692 {"nGetWidth","(J)I", (void*) CanvasJNI::getWidth},
693 {"nGetHeight","(J)I", (void*) CanvasJNI::getHeight},
694 {"nSave","(JI)I", (void*) CanvasJNI::save},
695 {"nSaveLayer","(JFFFFJ)I", (void*) CanvasJNI::saveLayer},
696 {"nSaveLayerAlpha","(JFFFFI)I", (void*) CanvasJNI::saveLayerAlpha},
697 {"nSaveUnclippedLayer","(JIIII)I", (void*) CanvasJNI::saveUnclippedLayer},
698 {"nRestoreUnclippedLayer","(JIJ)V", (void*) CanvasJNI::restoreUnclippedLayer},
699 {"nGetSaveCount","(J)I", (void*) CanvasJNI::getSaveCount},
700 {"nRestore","(J)Z", (void*) CanvasJNI::restore},
701 {"nRestoreToCount","(JI)V", (void*) CanvasJNI::restoreToCount},
702 {"nGetMatrix", "(JJ)V", (void*)CanvasJNI::getMatrix},
703 {"nSetMatrix","(JJ)V", (void*) CanvasJNI::setMatrix},
704 {"nConcat","(JJ)V", (void*) CanvasJNI::concat},
705 {"nRotate","(JF)V", (void*) CanvasJNI::rotate},
706 {"nScale","(JFF)V", (void*) CanvasJNI::scale},
707 {"nSkew","(JFF)V", (void*) CanvasJNI::skew},
708 {"nTranslate","(JFF)V", (void*) CanvasJNI::translate},
709 {"nQuickReject","(JJ)Z", (void*) CanvasJNI::quickRejectPath},
710 {"nQuickReject","(JFFFF)Z", (void*)CanvasJNI::quickRejectRect},
711 {"nClipRect","(JFFFFI)Z", (void*) CanvasJNI::clipRect},
712 {"nClipPath","(JJI)Z", (void*) CanvasJNI::clipPath},
713 {"nSetDrawFilter", "(JJ)V", (void*) CanvasJNI::setPaintFilter},
714 };
715
716 // If called from Canvas these are regular JNI
717 // If called from DisplayListCanvas they are @FastNative
718 static const JNINativeMethod gDrawMethods[] = {
719 {"nDrawColor","(JII)V", (void*) CanvasJNI::drawColor},
720 {"nDrawColor","(JJJI)V", (void*) CanvasJNI::drawColorLong},
721 {"nDrawPaint","(JJ)V", (void*) CanvasJNI::drawPaint},
722 {"nDrawPoint", "(JFFJ)V", (void*) CanvasJNI::drawPoint},
723 {"nDrawPoints", "(J[FIIJ)V", (void*) CanvasJNI::drawPoints},
724 {"nDrawLine", "(JFFFFJ)V", (void*) CanvasJNI::drawLine},
725 {"nDrawLines", "(J[FIIJ)V", (void*) CanvasJNI::drawLines},
726 {"nDrawRect","(JFFFFJ)V", (void*) CanvasJNI::drawRect},
727 {"nDrawRegion", "(JJJ)V", (void*) CanvasJNI::drawRegion },
728 {"nDrawRoundRect","(JFFFFFFJ)V", (void*) CanvasJNI::drawRoundRect},
729 {"nDrawDoubleRoundRect", "(JFFFFFFFFFFFFJ)V", (void*) CanvasJNI::drawDoubleRoundRectXY},
730 {"nDrawDoubleRoundRect", "(JFFFF[FFFFF[FJ)V", (void*) CanvasJNI::drawDoubleRoundRectRadii},
731 {"nDrawCircle","(JFFFJ)V", (void*) CanvasJNI::drawCircle},
732 {"nDrawOval","(JFFFFJ)V", (void*) CanvasJNI::drawOval},
733 {"nDrawArc","(JFFFFFFZJ)V", (void*) CanvasJNI::drawArc},
734 {"nDrawPath","(JJJ)V", (void*) CanvasJNI::drawPath},
735 {"nDrawVertices", "(JII[FI[FI[II[SIIJ)V", (void*)CanvasJNI::drawVertices},
736 {"nDrawNinePatch", "(JJJFFFFJII)V", (void*)CanvasJNI::drawNinePatch},
737 {"nDrawBitmapMatrix", "(JJJJ)V", (void*)CanvasJNI::drawBitmapMatrix},
738 {"nDrawBitmapMesh", "(JJII[FI[IIJ)V", (void*)CanvasJNI::drawBitmapMesh},
739 {"nDrawBitmap","(JJFFJIII)V", (void*) CanvasJNI::drawBitmap},
740 {"nDrawBitmap","(JJFFFFFFFFJII)V", (void*) CanvasJNI::drawBitmapRect},
741 {"nDrawBitmap", "(J[IIIFFIIZJ)V", (void*)CanvasJNI::drawBitmapArray},
742 {"nDrawGlyphs", "(J[I[FIIIJJ)V", (void*)CanvasJNI::drawGlyphs},
743 {"nDrawText","(J[CIIFFIJ)V", (void*) CanvasJNI::drawTextChars},
744 {"nDrawText","(JLjava/lang/String;IIFFIJ)V", (void*) CanvasJNI::drawTextString},
745 {"nDrawTextRun","(J[CIIIIFFZJJ)V", (void*) CanvasJNI::drawTextRunChars},
746 {"nDrawTextRun","(JLjava/lang/String;IIIIFFZJ)V", (void*) CanvasJNI::drawTextRunString},
747 {"nDrawTextOnPath","(J[CIIJFFIJ)V", (void*) CanvasJNI::drawTextOnPathChars},
748 {"nDrawTextOnPath","(JLjava/lang/String;JFFIJ)V", (void*) CanvasJNI::drawTextOnPathString},
749 {"nPunchHole", "(JFFFFFF)V", (void*) CanvasJNI::punchHole}
750 };
751
register_android_graphics_Canvas(JNIEnv * env)752 int register_android_graphics_Canvas(JNIEnv* env) {
753 int ret = 0;
754 ret |= RegisterMethodsOrDie(env, "android/graphics/Canvas", gMethods, NELEM(gMethods));
755 ret |= RegisterMethodsOrDie(env, "android/graphics/BaseCanvas", gDrawMethods, NELEM(gDrawMethods));
756 ret |= RegisterMethodsOrDie(env, "android/graphics/BaseRecordingCanvas", gDrawMethods, NELEM(gDrawMethods));
757 return ret;
758
759 }
760
761 }; // namespace android
762