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