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