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