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
31 namespace android {
32
33 namespace CanvasJNI {
34
get_canvas(jlong canvasHandle)35 static Canvas* get_canvas(jlong canvasHandle) {
36 return reinterpret_cast<Canvas*>(canvasHandle);
37 }
38
delete_canvas(Canvas * canvas)39 static void delete_canvas(Canvas* canvas) {
40 delete canvas;
41 }
42
getNativeFinalizer(JNIEnv * env,jobject clazz)43 static jlong getNativeFinalizer(JNIEnv* env, jobject clazz) {
44 return static_cast<jlong>(reinterpret_cast<uintptr_t>(&delete_canvas));
45 }
46
47 // Native wrapper constructor used by Canvas(Bitmap)
initRaster(JNIEnv * env,jobject,jobject jbitmap)48 static jlong initRaster(JNIEnv* env, jobject, jobject jbitmap) {
49 SkBitmap bitmap;
50 if (jbitmap != NULL) {
51 GraphicsJNI::getSkBitmap(env, jbitmap, &bitmap);
52 }
53 return reinterpret_cast<jlong>(Canvas::create_canvas(bitmap));
54 }
55
56 // Set the given bitmap as the new draw target (wrapped in a new SkCanvas),
57 // optionally copying canvas matrix & clip state.
setBitmap(JNIEnv * env,jobject,jlong canvasHandle,jobject jbitmap)58 static void setBitmap(JNIEnv* env, jobject, jlong canvasHandle, jobject jbitmap) {
59 SkBitmap bitmap;
60 if (jbitmap != NULL) {
61 GraphicsJNI::getSkBitmap(env, jbitmap, &bitmap);
62 }
63 get_canvas(canvasHandle)->setBitmap(bitmap);
64 }
65
isOpaque(JNIEnv *,jobject,jlong canvasHandle)66 static jboolean isOpaque(JNIEnv*, jobject, jlong canvasHandle) {
67 return get_canvas(canvasHandle)->isOpaque() ? JNI_TRUE : JNI_FALSE;
68 }
69
getWidth(JNIEnv *,jobject,jlong canvasHandle)70 static jint getWidth(JNIEnv*, jobject, jlong canvasHandle) {
71 return static_cast<jint>(get_canvas(canvasHandle)->width());
72 }
73
getHeight(JNIEnv *,jobject,jlong canvasHandle)74 static jint getHeight(JNIEnv*, jobject, jlong canvasHandle) {
75 return static_cast<jint>(get_canvas(canvasHandle)->height());
76 }
77
setHighContrastText(JNIEnv *,jobject,jlong canvasHandle,jboolean highContrastText)78 static void setHighContrastText(JNIEnv*, jobject, jlong canvasHandle, jboolean highContrastText) {
79 Canvas* canvas = get_canvas(canvasHandle);
80 canvas->setHighContrastText(highContrastText);
81 }
82
getSaveCount(JNIEnv *,jobject,jlong canvasHandle)83 static jint getSaveCount(JNIEnv*, jobject, jlong canvasHandle) {
84 return static_cast<jint>(get_canvas(canvasHandle)->getSaveCount());
85 }
86
save(JNIEnv *,jobject,jlong canvasHandle,jint flagsHandle)87 static jint save(JNIEnv*, jobject, 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(JNIEnv * env,jobject,jlong canvasHandle,jfloat l,jfloat t,jfloat r,jfloat b,jlong paintHandle,jint flagsHandle)92 static jint saveLayer(JNIEnv* env, jobject, 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(JNIEnv * env,jobject,jlong canvasHandle,jfloat l,jfloat t,jfloat r,jfloat b,jint alpha,jint flagsHandle)99 static jint saveLayerAlpha(JNIEnv* env, jobject, 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
restore(JNIEnv * env,jobject,jlong canvasHandle,jboolean throwOnUnderflow)105 static void restore(JNIEnv* env, jobject, jlong canvasHandle, jboolean throwOnUnderflow) {
106 Canvas* canvas = get_canvas(canvasHandle);
107 if (canvas->getSaveCount() <= 1) { // cannot restore anymore
108 if (throwOnUnderflow) {
109 doThrowISE(env, "Underflow in restore - more restores than saves");
110 }
111 return; // compat behavior - return without throwing
112 }
113 canvas->restore();
114 }
115
restoreToCount(JNIEnv * env,jobject,jlong canvasHandle,jint restoreCount,jboolean throwOnUnderflow)116 static void restoreToCount(JNIEnv* env, jobject, jlong canvasHandle, jint restoreCount,
117 jboolean throwOnUnderflow) {
118 Canvas* canvas = get_canvas(canvasHandle);
119 if (restoreCount < 1 || restoreCount > canvas->getSaveCount()) {
120 if (throwOnUnderflow) {
121 doThrowIAE(env, "Underflow in restoreToCount - more restores than saves");
122 return;
123 }
124 restoreCount = 1; // compat behavior - restore as far as possible
125 }
126 canvas->restoreToCount(restoreCount);
127 }
128
getCTM(JNIEnv * env,jobject,jlong canvasHandle,jlong matrixHandle)129 static void getCTM(JNIEnv* env, jobject, jlong canvasHandle, jlong matrixHandle) {
130 SkMatrix* matrix = reinterpret_cast<SkMatrix*>(matrixHandle);
131 get_canvas(canvasHandle)->getMatrix(matrix);
132 }
133
setMatrix(JNIEnv * env,jobject,jlong canvasHandle,jlong matrixHandle)134 static void setMatrix(JNIEnv* env, jobject, jlong canvasHandle, jlong matrixHandle) {
135 const SkMatrix* matrix = reinterpret_cast<SkMatrix*>(matrixHandle);
136 get_canvas(canvasHandle)->setMatrix(matrix ? *matrix : SkMatrix::I());
137 }
138
concat(JNIEnv * env,jobject,jlong canvasHandle,jlong matrixHandle)139 static void concat(JNIEnv* env, jobject, jlong canvasHandle, jlong matrixHandle) {
140 const SkMatrix* matrix = reinterpret_cast<SkMatrix*>(matrixHandle);
141 get_canvas(canvasHandle)->concat(*matrix);
142 }
143
rotate(JNIEnv *,jobject,jlong canvasHandle,jfloat degrees)144 static void rotate(JNIEnv*, jobject, jlong canvasHandle, jfloat degrees) {
145 get_canvas(canvasHandle)->rotate(degrees);
146 }
147
scale(JNIEnv *,jobject,jlong canvasHandle,jfloat sx,jfloat sy)148 static void scale(JNIEnv*, jobject, jlong canvasHandle, jfloat sx, jfloat sy) {
149 get_canvas(canvasHandle)->scale(sx, sy);
150 }
151
skew(JNIEnv *,jobject,jlong canvasHandle,jfloat sx,jfloat sy)152 static void skew(JNIEnv*, jobject, jlong canvasHandle, jfloat sx, jfloat sy) {
153 get_canvas(canvasHandle)->skew(sx, sy);
154 }
155
translate(JNIEnv *,jobject,jlong canvasHandle,jfloat dx,jfloat dy)156 static void translate(JNIEnv*, jobject, jlong canvasHandle, jfloat dx, jfloat dy) {
157 get_canvas(canvasHandle)->translate(dx, dy);
158 }
159
getClipBounds(JNIEnv * env,jobject,jlong canvasHandle,jobject bounds)160 static jboolean getClipBounds(JNIEnv* env, jobject, jlong canvasHandle, jobject bounds) {
161 SkRect r;
162 SkIRect ir;
163 bool result = get_canvas(canvasHandle)->getClipBounds(&r);
164
165 if (!result) {
166 r.setEmpty();
167 }
168 r.round(&ir);
169
170 (void)GraphicsJNI::irect_to_jrect(ir, env, bounds);
171 return result ? JNI_TRUE : JNI_FALSE;
172 }
173
quickRejectRect(JNIEnv * env,jobject,jlong canvasHandle,jfloat left,jfloat top,jfloat right,jfloat bottom)174 static jboolean quickRejectRect(JNIEnv* env, jobject, jlong canvasHandle,
175 jfloat left, jfloat top, jfloat right, jfloat bottom) {
176 bool result = get_canvas(canvasHandle)->quickRejectRect(left, top, right, bottom);
177 return result ? JNI_TRUE : JNI_FALSE;
178 }
179
quickRejectPath(JNIEnv * env,jobject,jlong canvasHandle,jlong pathHandle)180 static jboolean quickRejectPath(JNIEnv* env, jobject, jlong canvasHandle, jlong pathHandle) {
181 SkPath* path = reinterpret_cast<SkPath*>(pathHandle);
182 bool result = get_canvas(canvasHandle)->quickRejectPath(*path);
183 return result ? JNI_TRUE : JNI_FALSE;
184 }
185
clipRect(JNIEnv *,jobject,jlong canvasHandle,jfloat l,jfloat t,jfloat r,jfloat b,jint opHandle)186 static jboolean clipRect(JNIEnv*, jobject, jlong canvasHandle, jfloat l, jfloat t,
187 jfloat r, jfloat b, jint opHandle) {
188 SkRegion::Op op = static_cast<SkRegion::Op>(opHandle);
189 bool nonEmptyClip = get_canvas(canvasHandle)->clipRect(l, t, r, b, op);
190 return nonEmptyClip ? JNI_TRUE : JNI_FALSE;
191 }
192
clipPath(JNIEnv * env,jobject,jlong canvasHandle,jlong pathHandle,jint opHandle)193 static jboolean clipPath(JNIEnv* env, jobject, jlong canvasHandle, jlong pathHandle,
194 jint opHandle) {
195 SkPath* path = reinterpret_cast<SkPath*>(pathHandle);
196 SkRegion::Op op = static_cast<SkRegion::Op>(opHandle);
197 bool nonEmptyClip = get_canvas(canvasHandle)->clipPath(path, op);
198 return nonEmptyClip ? JNI_TRUE : JNI_FALSE;
199 }
200
clipRegion(JNIEnv * env,jobject,jlong canvasHandle,jlong deviceRgnHandle,jint opHandle)201 static jboolean clipRegion(JNIEnv* env, jobject, jlong canvasHandle, jlong deviceRgnHandle,
202 jint opHandle) {
203 SkRegion* deviceRgn = reinterpret_cast<SkRegion*>(deviceRgnHandle);
204 SkRegion::Op op = static_cast<SkRegion::Op>(opHandle);
205 bool nonEmptyClip = get_canvas(canvasHandle)->clipRegion(deviceRgn, op);
206 return nonEmptyClip ? JNI_TRUE : JNI_FALSE;
207 }
208
drawColor(JNIEnv * env,jobject,jlong canvasHandle,jint color,jint modeHandle)209 static void drawColor(JNIEnv* env, jobject, jlong canvasHandle, jint color, jint modeHandle) {
210 SkXfermode::Mode mode = static_cast<SkXfermode::Mode>(modeHandle);
211 get_canvas(canvasHandle)->drawColor(color, mode);
212 }
213
drawPaint(JNIEnv * env,jobject,jlong canvasHandle,jlong paintHandle)214 static void drawPaint(JNIEnv* env, jobject, jlong canvasHandle, jlong paintHandle) {
215 Paint* paint = reinterpret_cast<Paint*>(paintHandle);
216 get_canvas(canvasHandle)->drawPaint(*paint);
217 }
218
drawPoint(JNIEnv *,jobject,jlong canvasHandle,jfloat x,jfloat y,jlong paintHandle)219 static void drawPoint(JNIEnv*, jobject, jlong canvasHandle, jfloat x, jfloat y,
220 jlong paintHandle) {
221 const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
222 get_canvas(canvasHandle)->drawPoint(x, y, *paint);
223 }
224
drawPoints(JNIEnv * env,jobject,jlong canvasHandle,jfloatArray jptsArray,jint offset,jint count,jlong paintHandle)225 static void drawPoints(JNIEnv* env, jobject, jlong canvasHandle, jfloatArray jptsArray,
226 jint offset, jint count, jlong paintHandle) {
227 NPE_CHECK_RETURN_VOID(env, jptsArray);
228 AutoJavaFloatArray autoPts(env, jptsArray);
229 float* floats = autoPts.ptr();
230 const int length = autoPts.length();
231
232 if ((offset | count) < 0 || offset + count > length) {
233 doThrowAIOOBE(env);
234 return;
235 }
236
237 const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
238 get_canvas(canvasHandle)->drawPoints(floats + offset, count, *paint);
239 }
240
drawLine(JNIEnv * env,jobject,jlong canvasHandle,jfloat startX,jfloat startY,jfloat stopX,jfloat stopY,jlong paintHandle)241 static void drawLine(JNIEnv* env, jobject, jlong canvasHandle, jfloat startX, jfloat startY,
242 jfloat stopX, jfloat stopY, jlong paintHandle) {
243 Paint* paint = reinterpret_cast<Paint*>(paintHandle);
244 get_canvas(canvasHandle)->drawLine(startX, startY, stopX, stopY, *paint);
245 }
246
drawLines(JNIEnv * env,jobject,jlong canvasHandle,jfloatArray jptsArray,jint offset,jint count,jlong paintHandle)247 static void drawLines(JNIEnv* env, jobject, jlong canvasHandle, jfloatArray jptsArray,
248 jint offset, jint count, jlong paintHandle) {
249 NPE_CHECK_RETURN_VOID(env, jptsArray);
250 AutoJavaFloatArray autoPts(env, jptsArray);
251 float* floats = autoPts.ptr();
252 const int length = autoPts.length();
253
254 if ((offset | count) < 0 || offset + count > length) {
255 doThrowAIOOBE(env);
256 return;
257 }
258
259 const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
260 get_canvas(canvasHandle)->drawLines(floats + offset, count, *paint);
261 }
262
drawRect(JNIEnv * env,jobject,jlong canvasHandle,jfloat left,jfloat top,jfloat right,jfloat bottom,jlong paintHandle)263 static void drawRect(JNIEnv* env, jobject, jlong canvasHandle, jfloat left, jfloat top,
264 jfloat right, jfloat bottom, jlong paintHandle) {
265 const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
266 get_canvas(canvasHandle)->drawRect(left, top, right, bottom, *paint);
267 }
268
drawRegion(JNIEnv * env,jobject,jlong canvasHandle,jlong regionHandle,jlong paintHandle)269 static void drawRegion(JNIEnv* env, jobject, jlong canvasHandle, jlong regionHandle,
270 jlong paintHandle) {
271 const SkRegion* region = reinterpret_cast<SkRegion*>(regionHandle);
272 const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
273 get_canvas(canvasHandle)->drawRegion(*region, *paint);
274 }
275
drawRoundRect(JNIEnv * env,jobject,jlong canvasHandle,jfloat left,jfloat top,jfloat right,jfloat bottom,jfloat rx,jfloat ry,jlong paintHandle)276 static void drawRoundRect(JNIEnv* env, jobject, jlong canvasHandle, jfloat left, jfloat top,
277 jfloat right, jfloat bottom, jfloat rx, jfloat ry, jlong paintHandle) {
278 const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
279 get_canvas(canvasHandle)->drawRoundRect(left, top, right, bottom, rx, ry, *paint);
280 }
281
drawCircle(JNIEnv * env,jobject,jlong canvasHandle,jfloat cx,jfloat cy,jfloat radius,jlong paintHandle)282 static void drawCircle(JNIEnv* env, jobject, jlong canvasHandle, jfloat cx, jfloat cy,
283 jfloat radius, jlong paintHandle) {
284 const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
285 get_canvas(canvasHandle)->drawCircle(cx, cy, radius, *paint);
286 }
287
drawOval(JNIEnv * env,jobject,jlong canvasHandle,jfloat left,jfloat top,jfloat right,jfloat bottom,jlong paintHandle)288 static void drawOval(JNIEnv* env, jobject, jlong canvasHandle, jfloat left, jfloat top,
289 jfloat right, jfloat bottom, jlong paintHandle) {
290 const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
291 get_canvas(canvasHandle)->drawOval(left, top, right, bottom, *paint);
292 }
293
drawArc(JNIEnv * env,jobject,jlong canvasHandle,jfloat left,jfloat top,jfloat right,jfloat bottom,jfloat startAngle,jfloat sweepAngle,jboolean useCenter,jlong paintHandle)294 static void drawArc(JNIEnv* env, jobject, jlong canvasHandle, jfloat left, jfloat top,
295 jfloat right, jfloat bottom, jfloat startAngle, jfloat sweepAngle,
296 jboolean useCenter, jlong paintHandle) {
297 const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
298 get_canvas(canvasHandle)->drawArc(left, top, right, bottom, startAngle, sweepAngle,
299 useCenter, *paint);
300 }
301
drawPath(JNIEnv * env,jobject,jlong canvasHandle,jlong pathHandle,jlong paintHandle)302 static void drawPath(JNIEnv* env, jobject, jlong canvasHandle, jlong pathHandle,
303 jlong paintHandle) {
304 const SkPath* path = reinterpret_cast<SkPath*>(pathHandle);
305 const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
306 get_canvas(canvasHandle)->drawPath(*path, *paint);
307 }
308
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)309 static void drawVertices(JNIEnv* env, jobject, jlong canvasHandle,
310 jint modeHandle, jint vertexCount,
311 jfloatArray jverts, jint vertIndex,
312 jfloatArray jtexs, jint texIndex,
313 jintArray jcolors, jint colorIndex,
314 jshortArray jindices, jint indexIndex,
315 jint indexCount, jlong paintHandle) {
316 AutoJavaFloatArray vertA(env, jverts, vertIndex + vertexCount);
317 AutoJavaFloatArray texA(env, jtexs, texIndex + vertexCount);
318 AutoJavaIntArray colorA(env, jcolors, colorIndex + vertexCount);
319 AutoJavaShortArray indexA(env, jindices, indexIndex + indexCount);
320
321 const float* verts = vertA.ptr() + vertIndex;
322 const float* texs = texA.ptr() + vertIndex;
323 const int* colors = NULL;
324 const uint16_t* indices = NULL;
325
326 if (jcolors != NULL) {
327 colors = colorA.ptr() + colorIndex;
328 }
329 if (jindices != NULL) {
330 indices = (const uint16_t*)(indexA.ptr() + indexIndex);
331 }
332
333 SkCanvas::VertexMode mode = static_cast<SkCanvas::VertexMode>(modeHandle);
334 const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
335 get_canvas(canvasHandle)->drawVertices(mode, vertexCount, verts, texs, colors,
336 indices, indexCount, *paint);
337 }
338
drawNinePatch(JNIEnv * env,jobject,jlong canvasHandle,jlong bitmapHandle,jlong chunkHandle,jfloat left,jfloat top,jfloat right,jfloat bottom,jlong paintHandle,jint dstDensity,jint srcDensity)339 static void drawNinePatch(JNIEnv* env, jobject, jlong canvasHandle, jlong bitmapHandle,
340 jlong chunkHandle, jfloat left, jfloat top, jfloat right, jfloat bottom,
341 jlong paintHandle, jint dstDensity, jint srcDensity) {
342
343 Canvas* canvas = get_canvas(canvasHandle);
344 Bitmap* bitmap = reinterpret_cast<Bitmap*>(bitmapHandle);
345 SkBitmap skiaBitmap;
346 bitmap->getSkBitmap(&skiaBitmap);
347 const android::Res_png_9patch* chunk = reinterpret_cast<android::Res_png_9patch*>(chunkHandle);
348 const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
349
350 if (CC_LIKELY(dstDensity == srcDensity || dstDensity == 0 || srcDensity == 0)) {
351 canvas->drawNinePatch(skiaBitmap, *chunk, left, top, right, bottom, paint);
352 } else {
353 canvas->save(SaveFlags::MatrixClip);
354
355 SkScalar scale = dstDensity / (float)srcDensity;
356 canvas->translate(left, top);
357 canvas->scale(scale, scale);
358
359 Paint filteredPaint;
360 if (paint) {
361 filteredPaint = *paint;
362 }
363 filteredPaint.setFilterQuality(kLow_SkFilterQuality);
364
365 canvas->drawNinePatch(skiaBitmap, *chunk, 0, 0, (right-left)/scale, (bottom-top)/scale,
366 &filteredPaint);
367
368 canvas->restore();
369 }
370 }
371
drawBitmap(JNIEnv * env,jobject jcanvas,jlong canvasHandle,jobject jbitmap,jfloat left,jfloat top,jlong paintHandle,jint canvasDensity,jint screenDensity,jint bitmapDensity)372 static void drawBitmap(JNIEnv* env, jobject jcanvas, jlong canvasHandle, jobject jbitmap,
373 jfloat left, jfloat top, jlong paintHandle, jint canvasDensity,
374 jint screenDensity, jint bitmapDensity) {
375 Canvas* canvas = get_canvas(canvasHandle);
376 SkBitmap bitmap;
377 GraphicsJNI::getSkBitmap(env, jbitmap, &bitmap);
378 const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
379
380 if (canvasDensity == bitmapDensity || canvasDensity == 0 || bitmapDensity == 0) {
381 if (screenDensity != 0 && screenDensity != bitmapDensity) {
382 Paint filteredPaint;
383 if (paint) {
384 filteredPaint = *paint;
385 }
386 filteredPaint.setFilterQuality(kLow_SkFilterQuality);
387 canvas->drawBitmap(bitmap, left, top, &filteredPaint);
388 } else {
389 canvas->drawBitmap(bitmap, left, top, paint);
390 }
391 } else {
392 canvas->save(SaveFlags::MatrixClip);
393 SkScalar scale = canvasDensity / (float)bitmapDensity;
394 canvas->translate(left, top);
395 canvas->scale(scale, scale);
396
397 Paint filteredPaint;
398 if (paint) {
399 filteredPaint = *paint;
400 }
401 filteredPaint.setFilterQuality(kLow_SkFilterQuality);
402
403 canvas->drawBitmap(bitmap, 0, 0, &filteredPaint);
404 canvas->restore();
405 }
406 }
407
drawBitmapMatrix(JNIEnv * env,jobject,jlong canvasHandle,jobject jbitmap,jlong matrixHandle,jlong paintHandle)408 static void drawBitmapMatrix(JNIEnv* env, jobject, jlong canvasHandle, jobject jbitmap,
409 jlong matrixHandle, jlong paintHandle) {
410 const SkMatrix* matrix = reinterpret_cast<SkMatrix*>(matrixHandle);
411 const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
412 SkBitmap bitmap;
413 GraphicsJNI::getSkBitmap(env, jbitmap, &bitmap);
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 SkBitmap bitmap;
425 GraphicsJNI::getSkBitmap(env, jbitmap, &bitmap);
426 if (screenDensity != 0 && screenDensity != bitmapDensity) {
427 Paint filteredPaint;
428 if (paint) {
429 filteredPaint = *paint;
430 }
431 filteredPaint.setFilterQuality(kLow_SkFilterQuality);
432 canvas->drawBitmap(bitmap, srcLeft, srcTop, srcRight, srcBottom,
433 dstLeft, dstTop, dstRight, dstBottom, &filteredPaint);
434 } else {
435 canvas->drawBitmap(bitmap, srcLeft, srcTop, srcRight, srcBottom,
436 dstLeft, dstTop, dstRight, dstBottom, paint);
437 }
438 }
439
drawBitmapArray(JNIEnv * env,jobject,jlong canvasHandle,jintArray jcolors,jint offset,jint stride,jfloat x,jfloat y,jint width,jint height,jboolean hasAlpha,jlong paintHandle)440 static void drawBitmapArray(JNIEnv* env, jobject, jlong canvasHandle,
441 jintArray jcolors, jint offset, jint stride,
442 jfloat x, jfloat y, jint width, jint height,
443 jboolean hasAlpha, jlong paintHandle) {
444 // Note: If hasAlpha is false, kRGB_565_SkColorType will be used, which will
445 // correct the alphaType to kOpaque_SkAlphaType.
446 SkImageInfo info = SkImageInfo::Make(width, height,
447 hasAlpha ? kN32_SkColorType : kRGB_565_SkColorType,
448 kPremul_SkAlphaType);
449 SkBitmap bitmap;
450 bitmap.setInfo(info);
451 if (!GraphicsJNI::allocatePixels(env, &bitmap, NULL)) {
452 return;
453 }
454
455 if (!GraphicsJNI::SetPixels(env, jcolors, offset, stride, 0, 0, width, height, bitmap)) {
456 return;
457 }
458
459 const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
460 get_canvas(canvasHandle)->drawBitmap(bitmap, x, y, paint);
461 }
462
drawBitmapMesh(JNIEnv * env,jobject,jlong canvasHandle,jobject jbitmap,jint meshWidth,jint meshHeight,jfloatArray jverts,jint vertIndex,jintArray jcolors,jint colorIndex,jlong paintHandle)463 static void drawBitmapMesh(JNIEnv* env, jobject, jlong canvasHandle, jobject jbitmap,
464 jint meshWidth, jint meshHeight, jfloatArray jverts,
465 jint vertIndex, jintArray jcolors, jint colorIndex, jlong paintHandle) {
466 const int ptCount = (meshWidth + 1) * (meshHeight + 1);
467 AutoJavaFloatArray vertA(env, jverts, vertIndex + (ptCount << 1));
468 AutoJavaIntArray colorA(env, jcolors, colorIndex + ptCount);
469
470 const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
471 SkBitmap bitmap;
472 GraphicsJNI::getSkBitmap(env, jbitmap, &bitmap);
473 get_canvas(canvasHandle)->drawBitmapMesh(bitmap, meshWidth, meshHeight,
474 vertA.ptr(), colorA.ptr(), paint);
475 }
476
drawTextChars(JNIEnv * env,jobject,jlong canvasHandle,jcharArray text,jint index,jint count,jfloat x,jfloat y,jint bidiFlags,jlong paintHandle,jlong typefaceHandle)477 static void drawTextChars(JNIEnv* env, jobject, jlong canvasHandle, jcharArray text,
478 jint index, jint count, jfloat x, jfloat y, jint bidiFlags,
479 jlong paintHandle, jlong typefaceHandle) {
480 Paint* paint = reinterpret_cast<Paint*>(paintHandle);
481 Typeface* typeface = reinterpret_cast<Typeface*>(typefaceHandle);
482 jchar* jchars = env->GetCharArrayElements(text, NULL);
483 get_canvas(canvasHandle)->drawText(jchars + index, 0, count, count, x, y,
484 bidiFlags, *paint, typeface);
485 env->ReleaseCharArrayElements(text, jchars, JNI_ABORT);
486 }
487
drawTextString(JNIEnv * env,jobject,jlong canvasHandle,jstring text,jint start,jint end,jfloat x,jfloat y,jint bidiFlags,jlong paintHandle,jlong typefaceHandle)488 static void drawTextString(JNIEnv* env, jobject, jlong canvasHandle, jstring text,
489 jint start, jint end, jfloat x, jfloat y, jint bidiFlags,
490 jlong paintHandle, jlong typefaceHandle) {
491 Paint* paint = reinterpret_cast<Paint*>(paintHandle);
492 Typeface* typeface = reinterpret_cast<Typeface*>(typefaceHandle);
493 const int count = end - start;
494 const jchar* jchars = env->GetStringChars(text, NULL);
495 get_canvas(canvasHandle)->drawText(jchars + start, 0, count, count, x, y,
496 bidiFlags, *paint, typeface);
497 env->ReleaseStringChars(text, jchars);
498 }
499
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)500 static void drawTextRunChars(JNIEnv* env, jobject, jlong canvasHandle, jcharArray text, jint index,
501 jint count, jint contextIndex, jint contextCount, jfloat x, jfloat y,
502 jboolean isRtl, jlong paintHandle, jlong typefaceHandle) {
503 Paint* paint = reinterpret_cast<Paint*>(paintHandle);
504 Typeface* typeface = reinterpret_cast<Typeface*>(typefaceHandle);
505
506 const int bidiFlags = isRtl ? kBidi_Force_RTL : kBidi_Force_LTR;
507 jchar* jchars = env->GetCharArrayElements(text, NULL);
508 get_canvas(canvasHandle)->drawText(jchars + contextIndex, index - contextIndex, count,
509 contextCount, x, y, bidiFlags, *paint, typeface);
510 env->ReleaseCharArrayElements(text, jchars, JNI_ABORT);
511 }
512
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)513 static void drawTextRunString(JNIEnv* env, jobject obj, jlong canvasHandle, jstring text,
514 jint start, jint end, jint contextStart, jint contextEnd,
515 jfloat x, jfloat y, jboolean isRtl, jlong paintHandle,
516 jlong typefaceHandle) {
517 Paint* paint = reinterpret_cast<Paint*>(paintHandle);
518 Typeface* typeface = reinterpret_cast<Typeface*>(typefaceHandle);
519
520 int bidiFlags = isRtl ? kBidi_Force_RTL : kBidi_Force_LTR;
521 jint count = end - start;
522 jint contextCount = contextEnd - contextStart;
523 const jchar* jchars = env->GetStringChars(text, NULL);
524 get_canvas(canvasHandle)->drawText(jchars + contextStart, start - contextStart, count,
525 contextCount, x, y, bidiFlags, *paint, typeface);
526 env->ReleaseStringChars(text, jchars);
527 }
528
drawTextOnPathChars(JNIEnv * env,jobject,jlong canvasHandle,jcharArray text,jint index,jint count,jlong pathHandle,jfloat hOffset,jfloat vOffset,jint bidiFlags,jlong paintHandle,jlong typefaceHandle)529 static void drawTextOnPathChars(JNIEnv* env, jobject, jlong canvasHandle, jcharArray text,
530 jint index, jint count, jlong pathHandle, jfloat hOffset,
531 jfloat vOffset, jint bidiFlags, jlong paintHandle,
532 jlong typefaceHandle) {
533 SkPath* path = reinterpret_cast<SkPath*>(pathHandle);
534 Paint* paint = reinterpret_cast<Paint*>(paintHandle);
535 Typeface* typeface = reinterpret_cast<Typeface*>(typefaceHandle);
536
537 jchar* jchars = env->GetCharArrayElements(text, NULL);
538
539 get_canvas(canvasHandle)->drawTextOnPath(jchars + index, count, bidiFlags, *path,
540 hOffset, vOffset, *paint, typeface);
541
542 env->ReleaseCharArrayElements(text, jchars, 0);
543 }
544
drawTextOnPathString(JNIEnv * env,jobject,jlong canvasHandle,jstring text,jlong pathHandle,jfloat hOffset,jfloat vOffset,jint bidiFlags,jlong paintHandle,jlong typefaceHandle)545 static void drawTextOnPathString(JNIEnv* env, jobject, jlong canvasHandle, jstring text,
546 jlong pathHandle, jfloat hOffset, jfloat vOffset,
547 jint bidiFlags, jlong paintHandle, jlong typefaceHandle) {
548 SkPath* path = reinterpret_cast<SkPath*>(pathHandle);
549 Paint* paint = reinterpret_cast<Paint*>(paintHandle);
550 Typeface* typeface = reinterpret_cast<Typeface*>(typefaceHandle);
551
552 const jchar* jchars = env->GetStringChars(text, NULL);
553 int count = env->GetStringLength(text);
554
555 get_canvas(canvasHandle)->drawTextOnPath(jchars, count, bidiFlags, *path,
556 hOffset, vOffset, *paint, typeface);
557
558 env->ReleaseStringChars(text, jchars);
559 }
560
setDrawFilter(JNIEnv * env,jobject,jlong canvasHandle,jlong filterHandle)561 static void setDrawFilter(JNIEnv* env, jobject, jlong canvasHandle, jlong filterHandle) {
562 get_canvas(canvasHandle)->setDrawFilter(reinterpret_cast<SkDrawFilter*>(filterHandle));
563 }
564
freeCaches(JNIEnv * env,jobject)565 static void freeCaches(JNIEnv* env, jobject) {
566 SkGraphics::PurgeFontCache();
567 }
568
freeTextLayoutCaches(JNIEnv * env,jobject)569 static void freeTextLayoutCaches(JNIEnv* env, jobject) {
570 Layout::purgeCaches();
571 }
572
573 }; // namespace CanvasJNI
574
575 static const JNINativeMethod gMethods[] = {
576 {"getNativeFinalizer", "()J", (void*) CanvasJNI::getNativeFinalizer},
577 {"initRaster", "(Landroid/graphics/Bitmap;)J", (void*) CanvasJNI::initRaster},
578 {"native_setBitmap", "!(JLandroid/graphics/Bitmap;)V", (void*) CanvasJNI::setBitmap},
579 {"native_isOpaque","!(J)Z", (void*) CanvasJNI::isOpaque},
580 {"native_getWidth","!(J)I", (void*) CanvasJNI::getWidth},
581 {"native_getHeight","!(J)I", (void*) CanvasJNI::getHeight},
582 {"native_setHighContrastText","!(JZ)V", (void*) CanvasJNI::setHighContrastText},
583 {"native_save","!(JI)I", (void*) CanvasJNI::save},
584 {"native_saveLayer","!(JFFFFJI)I", (void*) CanvasJNI::saveLayer},
585 {"native_saveLayerAlpha","!(JFFFFII)I", (void*) CanvasJNI::saveLayerAlpha},
586 {"native_getSaveCount","!(J)I", (void*) CanvasJNI::getSaveCount},
587 {"native_restore","!(JZ)V", (void*) CanvasJNI::restore},
588 {"native_restoreToCount","!(JIZ)V", (void*) CanvasJNI::restoreToCount},
589 {"native_getCTM", "!(JJ)V", (void*)CanvasJNI::getCTM},
590 {"native_setMatrix","!(JJ)V", (void*) CanvasJNI::setMatrix},
591 {"native_concat","!(JJ)V", (void*) CanvasJNI::concat},
592 {"native_rotate","!(JF)V", (void*) CanvasJNI::rotate},
593 {"native_scale","!(JFF)V", (void*) CanvasJNI::scale},
594 {"native_skew","!(JFF)V", (void*) CanvasJNI::skew},
595 {"native_translate","!(JFF)V", (void*) CanvasJNI::translate},
596 {"native_getClipBounds","!(JLandroid/graphics/Rect;)Z", (void*) CanvasJNI::getClipBounds},
597 {"native_quickReject","!(JJ)Z", (void*) CanvasJNI::quickRejectPath},
598 {"native_quickReject","!(JFFFF)Z", (void*)CanvasJNI::quickRejectRect},
599 {"native_clipRect","!(JFFFFI)Z", (void*) CanvasJNI::clipRect},
600 {"native_clipPath","!(JJI)Z", (void*) CanvasJNI::clipPath},
601 {"native_clipRegion","!(JJI)Z", (void*) CanvasJNI::clipRegion},
602 {"native_drawColor","!(JII)V", (void*) CanvasJNI::drawColor},
603 {"native_drawPaint","!(JJ)V", (void*) CanvasJNI::drawPaint},
604 {"native_drawPoint", "!(JFFJ)V", (void*) CanvasJNI::drawPoint},
605 {"native_drawPoints", "!(J[FIIJ)V", (void*) CanvasJNI::drawPoints},
606 {"native_drawLine", "!(JFFFFJ)V", (void*) CanvasJNI::drawLine},
607 {"native_drawLines", "!(J[FIIJ)V", (void*) CanvasJNI::drawLines},
608 {"native_drawRect","!(JFFFFJ)V", (void*) CanvasJNI::drawRect},
609 {"native_drawRegion", "!(JJJ)V", (void*) CanvasJNI::drawRegion },
610 {"native_drawRoundRect","!(JFFFFFFJ)V", (void*) CanvasJNI::drawRoundRect},
611 {"native_drawCircle","!(JFFFJ)V", (void*) CanvasJNI::drawCircle},
612 {"native_drawOval","!(JFFFFJ)V", (void*) CanvasJNI::drawOval},
613 {"native_drawArc","!(JFFFFFFZJ)V", (void*) CanvasJNI::drawArc},
614 {"native_drawPath","!(JJJ)V", (void*) CanvasJNI::drawPath},
615 {"nativeDrawVertices", "!(JII[FI[FI[II[SIIJ)V", (void*)CanvasJNI::drawVertices},
616 {"native_drawNinePatch", "!(JJJFFFFJII)V", (void*)CanvasJNI::drawNinePatch},
617 {"native_drawBitmap","(JLandroid/graphics/Bitmap;FFJIII)V", (void*) CanvasJNI::drawBitmap},
618 {"nativeDrawBitmapMatrix", "!(JLandroid/graphics/Bitmap;JJ)V", (void*)CanvasJNI::drawBitmapMatrix},
619 {"native_drawBitmap","(JLandroid/graphics/Bitmap;FFFFFFFFJII)V", (void*) CanvasJNI::drawBitmapRect},
620 {"native_drawBitmap", "(J[IIIFFIIZJ)V", (void*)CanvasJNI::drawBitmapArray},
621 {"nativeDrawBitmapMesh", "!(JLandroid/graphics/Bitmap;II[FI[IIJ)V", (void*)CanvasJNI::drawBitmapMesh},
622 {"native_drawText","!(J[CIIFFIJJ)V", (void*) CanvasJNI::drawTextChars},
623 {"native_drawText","!(JLjava/lang/String;IIFFIJJ)V", (void*) CanvasJNI::drawTextString},
624 {"native_drawTextRun","!(J[CIIIIFFZJJ)V", (void*) CanvasJNI::drawTextRunChars},
625 {"native_drawTextRun","!(JLjava/lang/String;IIIIFFZJJ)V", (void*) CanvasJNI::drawTextRunString},
626 {"native_drawTextOnPath","!(J[CIIJFFIJJ)V", (void*) CanvasJNI::drawTextOnPathChars},
627 {"native_drawTextOnPath","!(JLjava/lang/String;JFFIJJ)V", (void*) CanvasJNI::drawTextOnPathString},
628 {"nativeSetDrawFilter", "!(JJ)V", (void*) CanvasJNI::setDrawFilter},
629 {"freeCaches", "()V", (void*) CanvasJNI::freeCaches},
630 {"freeTextLayoutCaches", "()V", (void*) CanvasJNI::freeTextLayoutCaches}
631 };
632
register_android_graphics_Canvas(JNIEnv * env)633 int register_android_graphics_Canvas(JNIEnv* env) {
634 return RegisterMethodsOrDie(env, "android/graphics/Canvas", gMethods, NELEM(gMethods));
635 }
636
637 }; // namespace android
638