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