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 <android_runtime/AndroidRuntime.h>
20
21 #include "Canvas.h"
22 #include "SkDrawFilter.h"
23 #include "SkGraphics.h"
24 #include "SkPorterDuff.h"
25 #include "Paint.h"
26 #include "TypefaceImpl.h"
27
28 #include "MinikinUtils.h"
29
30 namespace android {
31
32 namespace CanvasJNI {
33
get_canvas(jlong canvasHandle)34 static Canvas* get_canvas(jlong canvasHandle) {
35 return reinterpret_cast<Canvas*>(canvasHandle);
36 }
37
finalizer(JNIEnv * env,jobject clazz,jlong canvasHandle)38 static void finalizer(JNIEnv* env, jobject clazz, jlong canvasHandle) {
39 delete get_canvas(canvasHandle);
40 }
41
42 // Native wrapper constructor used by Canvas(Bitmap)
initRaster(JNIEnv * env,jobject,jlong bitmapHandle)43 static jlong initRaster(JNIEnv* env, jobject, jlong bitmapHandle) {
44 SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
45 return reinterpret_cast<jlong>(Canvas::create_canvas(bitmap));
46 }
47
48 // Set the given bitmap as the new draw target (wrapped in a new SkCanvas),
49 // optionally copying canvas matrix & clip state.
setBitmap(JNIEnv * env,jobject,jlong canvasHandle,jlong bitmapHandle,jboolean copyState)50 static void setBitmap(JNIEnv* env, jobject, jlong canvasHandle, jlong bitmapHandle,
51 jboolean copyState) {
52 SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
53 get_canvas(canvasHandle)->setBitmap(bitmap, copyState);
54 }
55
isOpaque(JNIEnv *,jobject,jlong canvasHandle)56 static jboolean isOpaque(JNIEnv*, jobject, jlong canvasHandle) {
57 return get_canvas(canvasHandle)->isOpaque() ? JNI_TRUE : JNI_FALSE;
58 }
59
getWidth(JNIEnv *,jobject,jlong canvasHandle)60 static jint getWidth(JNIEnv*, jobject, jlong canvasHandle) {
61 return static_cast<jint>(get_canvas(canvasHandle)->width());
62 }
63
getHeight(JNIEnv *,jobject,jlong canvasHandle)64 static jint getHeight(JNIEnv*, jobject, jlong canvasHandle) {
65 return static_cast<jint>(get_canvas(canvasHandle)->height());
66 }
67
getSaveCount(JNIEnv *,jobject,jlong canvasHandle)68 static jint getSaveCount(JNIEnv*, jobject, jlong canvasHandle) {
69 return static_cast<jint>(get_canvas(canvasHandle)->getSaveCount());
70 }
71
save(JNIEnv *,jobject,jlong canvasHandle,jint flagsHandle)72 static jint save(JNIEnv*, jobject, jlong canvasHandle, jint flagsHandle) {
73 SkCanvas::SaveFlags flags = static_cast<SkCanvas::SaveFlags>(flagsHandle);
74 return static_cast<jint>(get_canvas(canvasHandle)->save(flags));
75 }
76
saveLayer(JNIEnv * env,jobject,jlong canvasHandle,jfloat l,jfloat t,jfloat r,jfloat b,jlong paintHandle,jint flagsHandle)77 static jint saveLayer(JNIEnv* env, jobject, jlong canvasHandle, jfloat l, jfloat t,
78 jfloat r, jfloat b, jlong paintHandle, jint flagsHandle) {
79 Paint* paint = reinterpret_cast<Paint*>(paintHandle);
80 SkCanvas::SaveFlags flags = static_cast<SkCanvas::SaveFlags>(flagsHandle);
81 return static_cast<jint>(get_canvas(canvasHandle)->saveLayer(l, t, r, b, paint, flags));
82 }
83
saveLayerAlpha(JNIEnv * env,jobject,jlong canvasHandle,jfloat l,jfloat t,jfloat r,jfloat b,jint alpha,jint flagsHandle)84 static jint saveLayerAlpha(JNIEnv* env, jobject, jlong canvasHandle, jfloat l, jfloat t,
85 jfloat r, jfloat b, jint alpha, jint flagsHandle) {
86 SkCanvas::SaveFlags flags = static_cast<SkCanvas::SaveFlags>(flagsHandle);
87 return static_cast<jint>(get_canvas(canvasHandle)->saveLayerAlpha(l, t, r, b, alpha, flags));
88 }
89
restore(JNIEnv * env,jobject,jlong canvasHandle)90 static void restore(JNIEnv* env, jobject, jlong canvasHandle) {
91 Canvas* canvas = get_canvas(canvasHandle);
92 if (canvas->getSaveCount() <= 1) { // cannot restore anymore
93 doThrowISE(env, "Underflow in restore");
94 return;
95 }
96 canvas->restore();
97 }
98
restoreToCount(JNIEnv * env,jobject,jlong canvasHandle,jint restoreCount)99 static void restoreToCount(JNIEnv* env, jobject, jlong canvasHandle, jint restoreCount) {
100 Canvas* canvas = get_canvas(canvasHandle);
101 if (restoreCount < 1 || restoreCount > canvas->getSaveCount()) {
102 doThrowIAE(env, "Underflow in restoreToCount");
103 return;
104 }
105 canvas->restoreToCount(restoreCount);
106 }
107
getCTM(JNIEnv * env,jobject,jlong canvasHandle,jlong matrixHandle)108 static void getCTM(JNIEnv* env, jobject, jlong canvasHandle, jlong matrixHandle) {
109 SkMatrix* matrix = reinterpret_cast<SkMatrix*>(matrixHandle);
110 get_canvas(canvasHandle)->getMatrix(matrix);
111 }
112
setMatrix(JNIEnv * env,jobject,jlong canvasHandle,jlong matrixHandle)113 static void setMatrix(JNIEnv* env, jobject, jlong canvasHandle, jlong matrixHandle) {
114 const SkMatrix* matrix = reinterpret_cast<SkMatrix*>(matrixHandle);
115 get_canvas(canvasHandle)->setMatrix(matrix ? *matrix : SkMatrix::I());
116 }
117
concat(JNIEnv * env,jobject,jlong canvasHandle,jlong matrixHandle)118 static void concat(JNIEnv* env, jobject, jlong canvasHandle, jlong matrixHandle) {
119 const SkMatrix* matrix = reinterpret_cast<SkMatrix*>(matrixHandle);
120 get_canvas(canvasHandle)->concat(*matrix);
121 }
122
rotate(JNIEnv *,jobject,jlong canvasHandle,jfloat degrees)123 static void rotate(JNIEnv*, jobject, jlong canvasHandle, jfloat degrees) {
124 get_canvas(canvasHandle)->rotate(degrees);
125 }
126
scale(JNIEnv *,jobject,jlong canvasHandle,jfloat sx,jfloat sy)127 static void scale(JNIEnv*, jobject, jlong canvasHandle, jfloat sx, jfloat sy) {
128 get_canvas(canvasHandle)->scale(sx, sy);
129 }
130
skew(JNIEnv *,jobject,jlong canvasHandle,jfloat sx,jfloat sy)131 static void skew(JNIEnv*, jobject, jlong canvasHandle, jfloat sx, jfloat sy) {
132 get_canvas(canvasHandle)->skew(sx, sy);
133 }
134
translate(JNIEnv *,jobject,jlong canvasHandle,jfloat dx,jfloat dy)135 static void translate(JNIEnv*, jobject, jlong canvasHandle, jfloat dx, jfloat dy) {
136 get_canvas(canvasHandle)->translate(dx, dy);
137 }
138
getClipBounds(JNIEnv * env,jobject,jlong canvasHandle,jobject bounds)139 static jboolean getClipBounds(JNIEnv* env, jobject, jlong canvasHandle, jobject bounds) {
140 SkRect r;
141 SkIRect ir;
142 bool result = get_canvas(canvasHandle)->getClipBounds(&r);
143
144 if (!result) {
145 r.setEmpty();
146 }
147 r.round(&ir);
148
149 (void)GraphicsJNI::irect_to_jrect(ir, env, bounds);
150 return result ? JNI_TRUE : JNI_FALSE;
151 }
152
quickRejectRect(JNIEnv * env,jobject,jlong canvasHandle,jfloat left,jfloat top,jfloat right,jfloat bottom)153 static jboolean quickRejectRect(JNIEnv* env, jobject, jlong canvasHandle,
154 jfloat left, jfloat top, jfloat right, jfloat bottom) {
155 bool result = get_canvas(canvasHandle)->quickRejectRect(left, top, right, bottom);
156 return result ? JNI_TRUE : JNI_FALSE;
157 }
158
quickRejectPath(JNIEnv * env,jobject,jlong canvasHandle,jlong pathHandle)159 static jboolean quickRejectPath(JNIEnv* env, jobject, jlong canvasHandle, jlong pathHandle) {
160 SkPath* path = reinterpret_cast<SkPath*>(pathHandle);
161 bool result = get_canvas(canvasHandle)->quickRejectPath(*path);
162 return result ? JNI_TRUE : JNI_FALSE;
163 }
164
clipRect(JNIEnv *,jobject,jlong canvasHandle,jfloat l,jfloat t,jfloat r,jfloat b,jint opHandle)165 static jboolean clipRect(JNIEnv*, jobject, jlong canvasHandle, jfloat l, jfloat t,
166 jfloat r, jfloat b, jint opHandle) {
167 SkRegion::Op op = static_cast<SkRegion::Op>(opHandle);
168 bool emptyClip = get_canvas(canvasHandle)->clipRect(l, t, r, b, op);
169 return emptyClip ? JNI_FALSE : JNI_TRUE;
170 }
171
clipPath(JNIEnv * env,jobject,jlong canvasHandle,jlong pathHandle,jint opHandle)172 static jboolean clipPath(JNIEnv* env, jobject, jlong canvasHandle, jlong pathHandle,
173 jint opHandle) {
174 SkPath* path = reinterpret_cast<SkPath*>(pathHandle);
175 SkRegion::Op op = static_cast<SkRegion::Op>(opHandle);
176 bool emptyClip = get_canvas(canvasHandle)->clipPath(path, op);
177 return emptyClip ? JNI_FALSE : JNI_TRUE;
178 }
179
clipRegion(JNIEnv * env,jobject,jlong canvasHandle,jlong deviceRgnHandle,jint opHandle)180 static jboolean clipRegion(JNIEnv* env, jobject, jlong canvasHandle, jlong deviceRgnHandle,
181 jint opHandle) {
182 SkRegion* deviceRgn = reinterpret_cast<SkRegion*>(deviceRgnHandle);
183 SkRegion::Op op = static_cast<SkRegion::Op>(opHandle);
184 bool emptyClip = get_canvas(canvasHandle)->clipRegion(deviceRgn, op);
185 return emptyClip ? JNI_FALSE : JNI_TRUE;
186 }
187
drawColor(JNIEnv * env,jobject,jlong canvasHandle,jint color,jint modeHandle)188 static void drawColor(JNIEnv* env, jobject, jlong canvasHandle, jint color, jint modeHandle) {
189 SkPorterDuff::Mode mode = static_cast<SkPorterDuff::Mode>(modeHandle);
190 get_canvas(canvasHandle)->drawColor(color, SkPorterDuff::ToXfermodeMode(mode));
191 }
192
drawPaint(JNIEnv * env,jobject,jlong canvasHandle,jlong paintHandle)193 static void drawPaint(JNIEnv* env, jobject, jlong canvasHandle, jlong paintHandle) {
194 Paint* paint = reinterpret_cast<Paint*>(paintHandle);
195 get_canvas(canvasHandle)->drawPaint(*paint);
196 }
197
drawPoint(JNIEnv *,jobject,jlong canvasHandle,jfloat x,jfloat y,jlong paintHandle)198 static void drawPoint(JNIEnv*, jobject, jlong canvasHandle, jfloat x, jfloat y,
199 jlong paintHandle) {
200 const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
201 get_canvas(canvasHandle)->drawPoint(x, y, *paint);
202 }
203
drawPoints(JNIEnv * env,jobject,jlong canvasHandle,jfloatArray jptsArray,jint offset,jint count,jlong paintHandle)204 static void drawPoints(JNIEnv* env, jobject, jlong canvasHandle, jfloatArray jptsArray,
205 jint offset, jint count, jlong paintHandle) {
206 NPE_CHECK_RETURN_VOID(env, jptsArray);
207 AutoJavaFloatArray autoPts(env, jptsArray);
208 float* floats = autoPts.ptr();
209 const int length = autoPts.length();
210
211 if ((offset | count) < 0 || offset + count > length) {
212 doThrowAIOOBE(env);
213 return;
214 }
215
216 const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
217 get_canvas(canvasHandle)->drawPoints(floats + offset, count, *paint);
218 }
219
drawLine(JNIEnv * env,jobject,jlong canvasHandle,jfloat startX,jfloat startY,jfloat stopX,jfloat stopY,jlong paintHandle)220 static void drawLine(JNIEnv* env, jobject, jlong canvasHandle, jfloat startX, jfloat startY,
221 jfloat stopX, jfloat stopY, jlong paintHandle) {
222 Paint* paint = reinterpret_cast<Paint*>(paintHandle);
223 get_canvas(canvasHandle)->drawLine(startX, startY, stopX, stopY, *paint);
224 }
225
drawLines(JNIEnv * env,jobject,jlong canvasHandle,jfloatArray jptsArray,jint offset,jint count,jlong paintHandle)226 static void drawLines(JNIEnv* env, jobject, jlong canvasHandle, jfloatArray jptsArray,
227 jint offset, jint count, jlong paintHandle) {
228 NPE_CHECK_RETURN_VOID(env, jptsArray);
229 AutoJavaFloatArray autoPts(env, jptsArray);
230 float* floats = autoPts.ptr();
231 const int length = autoPts.length();
232
233 if ((offset | count) < 0 || offset + count > length) {
234 doThrowAIOOBE(env);
235 return;
236 }
237
238 const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
239 get_canvas(canvasHandle)->drawLines(floats + offset, count, *paint);
240 }
241
drawRect(JNIEnv * env,jobject,jlong canvasHandle,jfloat left,jfloat top,jfloat right,jfloat bottom,jlong paintHandle)242 static void drawRect(JNIEnv* env, jobject, jlong canvasHandle, jfloat left, jfloat top,
243 jfloat right, jfloat bottom, jlong paintHandle) {
244 const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
245 get_canvas(canvasHandle)->drawRect(left, top, right, bottom, *paint);
246 }
247
drawRoundRect(JNIEnv * env,jobject,jlong canvasHandle,jfloat left,jfloat top,jfloat right,jfloat bottom,jfloat rx,jfloat ry,jlong paintHandle)248 static void drawRoundRect(JNIEnv* env, jobject, jlong canvasHandle, jfloat left, jfloat top,
249 jfloat right, jfloat bottom, jfloat rx, jfloat ry, jlong paintHandle) {
250 const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
251 get_canvas(canvasHandle)->drawRoundRect(left, top, right, bottom, rx, ry, *paint);
252 }
253
drawCircle(JNIEnv * env,jobject,jlong canvasHandle,jfloat cx,jfloat cy,jfloat radius,jlong paintHandle)254 static void drawCircle(JNIEnv* env, jobject, jlong canvasHandle, jfloat cx, jfloat cy,
255 jfloat radius, jlong paintHandle) {
256 const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
257 get_canvas(canvasHandle)->drawCircle(cx, cy, radius, *paint);
258 }
259
drawOval(JNIEnv * env,jobject,jlong canvasHandle,jfloat left,jfloat top,jfloat right,jfloat bottom,jlong paintHandle)260 static void drawOval(JNIEnv* env, jobject, jlong canvasHandle, jfloat left, jfloat top,
261 jfloat right, jfloat bottom, jlong paintHandle) {
262 const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
263 get_canvas(canvasHandle)->drawOval(left, top, right, bottom, *paint);
264 }
265
drawArc(JNIEnv * env,jobject,jlong canvasHandle,jfloat left,jfloat top,jfloat right,jfloat bottom,jfloat startAngle,jfloat sweepAngle,jboolean useCenter,jlong paintHandle)266 static void drawArc(JNIEnv* env, jobject, jlong canvasHandle, jfloat left, jfloat top,
267 jfloat right, jfloat bottom, jfloat startAngle, jfloat sweepAngle,
268 jboolean useCenter, jlong paintHandle) {
269 const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
270 get_canvas(canvasHandle)->drawArc(left, top, right, bottom, startAngle, sweepAngle,
271 useCenter, *paint);
272 }
273
drawPath(JNIEnv * env,jobject,jlong canvasHandle,jlong pathHandle,jlong paintHandle)274 static void drawPath(JNIEnv* env, jobject, jlong canvasHandle, jlong pathHandle,
275 jlong paintHandle) {
276 const SkPath* path = reinterpret_cast<SkPath*>(pathHandle);
277 const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
278 get_canvas(canvasHandle)->drawPath(*path, *paint);
279 }
280
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)281 static void drawVertices(JNIEnv* env, jobject, jlong canvasHandle,
282 jint modeHandle, jint vertexCount,
283 jfloatArray jverts, jint vertIndex,
284 jfloatArray jtexs, jint texIndex,
285 jintArray jcolors, jint colorIndex,
286 jshortArray jindices, jint indexIndex,
287 jint indexCount, jlong paintHandle) {
288 AutoJavaFloatArray vertA(env, jverts, vertIndex + vertexCount);
289 AutoJavaFloatArray texA(env, jtexs, texIndex + vertexCount);
290 AutoJavaIntArray colorA(env, jcolors, colorIndex + vertexCount);
291 AutoJavaShortArray indexA(env, jindices, indexIndex + indexCount);
292
293 const float* verts = vertA.ptr() + vertIndex;
294 const float* texs = texA.ptr() + vertIndex;
295 const int* colors = NULL;
296 const uint16_t* indices = NULL;
297
298 if (jcolors != NULL) {
299 colors = colorA.ptr() + colorIndex;
300 }
301 if (jindices != NULL) {
302 indices = (const uint16_t*)(indexA.ptr() + indexIndex);
303 }
304
305 SkCanvas::VertexMode mode = static_cast<SkCanvas::VertexMode>(modeHandle);
306 const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
307 get_canvas(canvasHandle)->drawVertices(mode, vertexCount, verts, texs, colors,
308 indices, indexCount, *paint);
309 }
310
drawBitmap(JNIEnv * env,jobject jcanvas,jlong canvasHandle,jlong bitmapHandle,jfloat left,jfloat top,jlong paintHandle,jint canvasDensity,jint screenDensity,jint bitmapDensity)311 static void drawBitmap(JNIEnv* env, jobject jcanvas, jlong canvasHandle, jlong bitmapHandle,
312 jfloat left, jfloat top, jlong paintHandle, jint canvasDensity,
313 jint screenDensity, jint bitmapDensity) {
314 Canvas* canvas = get_canvas(canvasHandle);
315 const SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
316 const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
317
318 if (canvasDensity == bitmapDensity || canvasDensity == 0 || bitmapDensity == 0) {
319 if (screenDensity != 0 && screenDensity != bitmapDensity) {
320 Paint filteredPaint;
321 if (paint) {
322 filteredPaint = *paint;
323 }
324 filteredPaint.setFilterLevel(Paint::kLow_FilterLevel);
325 canvas->drawBitmap(*bitmap, left, top, &filteredPaint);
326 } else {
327 canvas->drawBitmap(*bitmap, left, top, paint);
328 }
329 } else {
330 canvas->save(SkCanvas::kMatrixClip_SaveFlag);
331 SkScalar scale = canvasDensity / (float)bitmapDensity;
332 canvas->translate(left, top);
333 canvas->scale(scale, scale);
334
335 Paint filteredPaint;
336 if (paint) {
337 filteredPaint = *paint;
338 }
339 filteredPaint.setFilterLevel(Paint::kLow_FilterLevel);
340
341 canvas->drawBitmap(*bitmap, 0, 0, &filteredPaint);
342 canvas->restore();
343 }
344 }
345
drawBitmapMatrix(JNIEnv * env,jobject,jlong canvasHandle,jlong bitmapHandle,jlong matrixHandle,jlong paintHandle)346 static void drawBitmapMatrix(JNIEnv* env, jobject, jlong canvasHandle, jlong bitmapHandle,
347 jlong matrixHandle, jlong paintHandle) {
348 const SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
349 const SkMatrix* matrix = reinterpret_cast<SkMatrix*>(matrixHandle);
350 const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
351 get_canvas(canvasHandle)->drawBitmap(*bitmap, *matrix, paint);
352 }
353
drawBitmapRect(JNIEnv * env,jobject,jlong canvasHandle,jlong bitmapHandle,float srcLeft,float srcTop,float srcRight,float srcBottom,float dstLeft,float dstTop,float dstRight,float dstBottom,jlong paintHandle,jint screenDensity,jint bitmapDensity)354 static void drawBitmapRect(JNIEnv* env, jobject, jlong canvasHandle, jlong bitmapHandle,
355 float srcLeft, float srcTop, float srcRight, float srcBottom,
356 float dstLeft, float dstTop, float dstRight, float dstBottom,
357 jlong paintHandle, jint screenDensity, jint bitmapDensity) {
358 Canvas* canvas = get_canvas(canvasHandle);
359 const SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
360 const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
361
362 if (screenDensity != 0 && screenDensity != bitmapDensity) {
363 Paint filteredPaint;
364 if (paint) {
365 filteredPaint = *paint;
366 }
367 filteredPaint.setFilterLevel(Paint::kLow_FilterLevel);
368 canvas->drawBitmap(*bitmap, srcLeft, srcTop, srcRight, srcBottom,
369 dstLeft, dstTop, dstRight, dstBottom, &filteredPaint);
370 } else {
371 canvas->drawBitmap(*bitmap, srcLeft, srcTop, srcRight, srcBottom,
372 dstLeft, dstTop, dstRight, dstBottom, paint);
373 }
374 }
375
drawBitmapArray(JNIEnv * env,jobject,jlong canvasHandle,jintArray jcolors,jint offset,jint stride,jfloat x,jfloat y,jint width,jint height,jboolean hasAlpha,jlong paintHandle)376 static void drawBitmapArray(JNIEnv* env, jobject, jlong canvasHandle,
377 jintArray jcolors, jint offset, jint stride,
378 jfloat x, jfloat y, jint width, jint height,
379 jboolean hasAlpha, jlong paintHandle) {
380 // Note: If hasAlpha is false, kRGB_565_SkColorType will be used, which will
381 // correct the alphaType to kOpaque_SkAlphaType.
382 SkImageInfo info = SkImageInfo::Make(width, height,
383 hasAlpha ? kN32_SkColorType : kRGB_565_SkColorType,
384 kPremul_SkAlphaType);
385 SkBitmap bitmap;
386 if (!bitmap.allocPixels(info)) {
387 return;
388 }
389
390 if (!GraphicsJNI::SetPixels(env, jcolors, offset, stride, 0, 0, width, height, bitmap)) {
391 return;
392 }
393
394 const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
395 get_canvas(canvasHandle)->drawBitmap(bitmap, x, y, paint);
396 }
397
drawBitmapMesh(JNIEnv * env,jobject,jlong canvasHandle,jlong bitmapHandle,jint meshWidth,jint meshHeight,jfloatArray jverts,jint vertIndex,jintArray jcolors,jint colorIndex,jlong paintHandle)398 static void drawBitmapMesh(JNIEnv* env, jobject, jlong canvasHandle, jlong bitmapHandle,
399 jint meshWidth, jint meshHeight, jfloatArray jverts,
400 jint vertIndex, jintArray jcolors, jint colorIndex, jlong paintHandle) {
401 const int ptCount = (meshWidth + 1) * (meshHeight + 1);
402 AutoJavaFloatArray vertA(env, jverts, vertIndex + (ptCount << 1));
403 AutoJavaIntArray colorA(env, jcolors, colorIndex + ptCount);
404
405 const SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
406 const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
407 get_canvas(canvasHandle)->drawBitmapMesh(*bitmap, meshWidth, meshHeight,
408 vertA.ptr(), colorA.ptr(), paint);
409 }
410
411 class DrawTextFunctor {
412 public:
DrawTextFunctor(const Layout & layout,Canvas * canvas,uint16_t * glyphs,float * pos,const SkPaint & paint,float x,float y,MinikinRect & bounds)413 DrawTextFunctor(const Layout& layout, Canvas* canvas, uint16_t* glyphs, float* pos,
414 const SkPaint& paint, float x, float y, MinikinRect& bounds)
415 : layout(layout), canvas(canvas), glyphs(glyphs), pos(pos), paint(paint),
416 x(x), y(y), bounds(bounds) { }
417
operator ()(size_t start,size_t end)418 void operator()(size_t start, size_t end) {
419 if (canvas->drawTextAbsolutePos()) {
420 for (size_t i = start; i < end; i++) {
421 glyphs[i] = layout.getGlyphId(i);
422 pos[2 * i] = x + layout.getX(i);
423 pos[2 * i + 1] = y + layout.getY(i);
424 }
425 } else {
426 for (size_t i = start; i < end; i++) {
427 glyphs[i] = layout.getGlyphId(i);
428 pos[2 * i] = layout.getX(i);
429 pos[2 * i + 1] = layout.getY(i);
430 }
431 }
432
433 size_t glyphCount = end - start;
434 canvas->drawText(glyphs + start, pos + (2 * start), glyphCount, paint, x, y,
435 bounds.mLeft , bounds.mTop , bounds.mRight , bounds.mBottom);
436 }
437 private:
438 const Layout& layout;
439 Canvas* canvas;
440 uint16_t* glyphs;
441 float* pos;
442 const SkPaint& paint;
443 float x;
444 float y;
445 MinikinRect& bounds;
446 };
447
448 // Same values used by Skia
449 #define kStdStrikeThru_Offset (-6.0f / 21.0f)
450 #define kStdUnderline_Offset (1.0f / 9.0f)
451 #define kStdUnderline_Thickness (1.0f / 18.0f)
452
drawTextDecorations(Canvas * canvas,float x,float y,float length,const SkPaint & paint)453 void drawTextDecorations(Canvas* canvas, float x, float y, float length, const SkPaint& paint) {
454 uint32_t flags;
455 SkDrawFilter* drawFilter = canvas->getDrawFilter();
456 if (drawFilter) {
457 SkPaint paintCopy(paint);
458 drawFilter->filter(&paintCopy, SkDrawFilter::kText_Type);
459 flags = paintCopy.getFlags();
460 } else {
461 flags = paint.getFlags();
462 }
463 if (flags & (SkPaint::kUnderlineText_Flag | SkPaint::kStrikeThruText_Flag)) {
464 SkScalar left = x;
465 SkScalar right = x + length;
466 float textSize = paint.getTextSize();
467 float strokeWidth = fmax(textSize * kStdUnderline_Thickness, 1.0f);
468 if (flags & SkPaint::kUnderlineText_Flag) {
469 SkScalar top = y + textSize * kStdUnderline_Offset - 0.5f * strokeWidth;
470 SkScalar bottom = y + textSize * kStdUnderline_Offset + 0.5f * strokeWidth;
471 canvas->drawRect(left, top, right, bottom, paint);
472 }
473 if (flags & SkPaint::kStrikeThruText_Flag) {
474 SkScalar top = y + textSize * kStdStrikeThru_Offset - 0.5f * strokeWidth;
475 SkScalar bottom = y + textSize * kStdStrikeThru_Offset + 0.5f * strokeWidth;
476 canvas->drawRect(left, top, right, bottom, paint);
477 }
478 }
479 }
480
drawText(Canvas * canvas,const uint16_t * text,int start,int count,int contextCount,float x,float y,int bidiFlags,const Paint & origPaint,TypefaceImpl * typeface)481 void drawText(Canvas* canvas, const uint16_t* text, int start, int count, int contextCount,
482 float x, float y, int bidiFlags, const Paint& origPaint, TypefaceImpl* typeface) {
483 // minikin may modify the original paint
484 Paint paint(origPaint);
485
486 Layout layout;
487 MinikinUtils::doLayout(&layout, &paint, bidiFlags, typeface, text, start, count, contextCount);
488
489 size_t nGlyphs = layout.nGlyphs();
490 uint16_t* glyphs = new uint16_t[nGlyphs];
491 float* pos = new float[nGlyphs * 2];
492
493 x += MinikinUtils::xOffsetForTextAlign(&paint, layout);
494
495 MinikinRect bounds;
496 layout.getBounds(&bounds);
497
498 DrawTextFunctor f(layout, canvas, glyphs, pos, paint, x, y, bounds);
499 MinikinUtils::forFontRun(layout, &paint, f);
500
501 drawTextDecorations(canvas, x, y, layout.getAdvance(), paint);
502
503 delete[] glyphs;
504 delete[] pos;
505 }
506
drawTextChars(JNIEnv * env,jobject,jlong canvasHandle,jcharArray text,jint index,jint count,jfloat x,jfloat y,jint bidiFlags,jlong paintHandle,jlong typefaceHandle)507 static void drawTextChars(JNIEnv* env, jobject, jlong canvasHandle, jcharArray text,
508 jint index, jint count, jfloat x, jfloat y, jint bidiFlags,
509 jlong paintHandle, jlong typefaceHandle) {
510 Paint* paint = reinterpret_cast<Paint*>(paintHandle);
511 TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefaceHandle);
512 jchar* jchars = env->GetCharArrayElements(text, NULL);
513 drawText(get_canvas(canvasHandle), jchars + index, 0, count, count, x, y,
514 bidiFlags, *paint, typeface);
515 env->ReleaseCharArrayElements(text, jchars, JNI_ABORT);
516 }
517
drawTextString(JNIEnv * env,jobject,jlong canvasHandle,jstring text,jint start,jint end,jfloat x,jfloat y,jint bidiFlags,jlong paintHandle,jlong typefaceHandle)518 static void drawTextString(JNIEnv* env, jobject, jlong canvasHandle, jstring text,
519 jint start, jint end, jfloat x, jfloat y, jint bidiFlags,
520 jlong paintHandle, jlong typefaceHandle) {
521 Paint* paint = reinterpret_cast<Paint*>(paintHandle);
522 TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefaceHandle);
523 const int count = end - start;
524 const jchar* jchars = env->GetStringChars(text, NULL);
525 drawText(get_canvas(canvasHandle), jchars + start, 0, count, count, x, y,
526 bidiFlags, *paint, typeface);
527 env->ReleaseStringChars(text, jchars);
528 }
529
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)530 static void drawTextRunChars(JNIEnv* env, jobject, jlong canvasHandle, jcharArray text, jint index,
531 jint count, jint contextIndex, jint contextCount, jfloat x, jfloat y,
532 jboolean isRtl, jlong paintHandle, jlong typefaceHandle) {
533 Paint* paint = reinterpret_cast<Paint*>(paintHandle);
534 TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefaceHandle);
535
536 const int bidiFlags = isRtl ? kBidi_Force_RTL : kBidi_Force_LTR;
537 jchar* jchars = env->GetCharArrayElements(text, NULL);
538 drawText(get_canvas(canvasHandle), jchars + contextIndex, index - contextIndex, count,
539 contextCount, x, y, bidiFlags, *paint, typeface);
540 env->ReleaseCharArrayElements(text, jchars, JNI_ABORT);
541 }
542
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)543 static void drawTextRunString(JNIEnv* env, jobject obj, jlong canvasHandle, jstring text,
544 jint start, jint end, jint contextStart, jint contextEnd,
545 jfloat x, jfloat y, jboolean isRtl, jlong paintHandle,
546 jlong typefaceHandle) {
547 Paint* paint = reinterpret_cast<Paint*>(paintHandle);
548 TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefaceHandle);
549
550 int bidiFlags = isRtl ? kBidi_Force_RTL : kBidi_Force_LTR;
551 jint count = end - start;
552 jint contextCount = contextEnd - contextStart;
553 const jchar* jchars = env->GetStringChars(text, NULL);
554 drawText(get_canvas(canvasHandle), jchars + contextStart, start - contextStart, count,
555 contextCount, x, y, bidiFlags, *paint, typeface);
556 env->ReleaseStringChars(text, jchars);
557 }
558
drawPosTextChars(JNIEnv * env,jobject,jlong canvasHandle,jcharArray text,jint index,jint count,jfloatArray pos,jlong paintHandle)559 static void drawPosTextChars(JNIEnv* env, jobject, jlong canvasHandle, jcharArray text,
560 jint index, jint count, jfloatArray pos, jlong paintHandle) {
561 Paint* paint = reinterpret_cast<Paint*>(paintHandle);
562 jchar* jchars = text ? env->GetCharArrayElements(text, NULL) : NULL;
563 float* posArray = pos ? env->GetFloatArrayElements(pos, NULL) : NULL;
564 int posCount = pos ? env->GetArrayLength(pos) >> 1: 0;
565
566 get_canvas(canvasHandle)->drawPosText(jchars + index, posArray, count << 1, posCount, *paint);
567
568 if (text) {
569 env->ReleaseCharArrayElements(text, jchars, 0);
570 }
571 if (pos) {
572 env->ReleaseFloatArrayElements(pos, posArray, 0);
573 }
574 }
575
576
drawPosTextString(JNIEnv * env,jobject,jlong canvasHandle,jstring text,jfloatArray pos,jlong paintHandle)577 static void drawPosTextString(JNIEnv* env, jobject, jlong canvasHandle, jstring text,
578 jfloatArray pos, jlong paintHandle) {
579 Paint* paint = reinterpret_cast<Paint*>(paintHandle);
580 const jchar* jchars = text ? env->GetStringChars(text, NULL) : NULL;
581 int byteLength = text ? env->GetStringLength(text) : 0;
582 float* posArray = pos ? env->GetFloatArrayElements(pos, NULL) : NULL;
583 int posCount = pos ? env->GetArrayLength(pos) >> 1: 0;
584
585 get_canvas(canvasHandle)->drawPosText(jchars , posArray, byteLength << 1, posCount, *paint);
586
587 if (text) {
588 env->ReleaseStringChars(text, jchars);
589 }
590 if (pos) {
591 env->ReleaseFloatArrayElements(pos, posArray, 0);
592 }
593 }
594
595 class DrawTextOnPathFunctor {
596 public:
DrawTextOnPathFunctor(const Layout & layout,Canvas * canvas,float hOffset,float vOffset,const Paint & paint,const SkPath & path)597 DrawTextOnPathFunctor(const Layout& layout, Canvas* canvas, float hOffset,
598 float vOffset, const Paint& paint, const SkPath& path)
599 : layout(layout), canvas(canvas), hOffset(hOffset), vOffset(vOffset),
600 paint(paint), path(path) {
601 }
operator ()(size_t start,size_t end)602 void operator()(size_t start, size_t end) {
603 uint16_t glyphs[1];
604 for (size_t i = start; i < end; i++) {
605 glyphs[0] = layout.getGlyphId(i);
606 float x = hOffset + layout.getX(i);
607 float y = vOffset + layout.getY(i);
608 canvas->drawTextOnPath(glyphs, 1, path, x, y, paint);
609 }
610 }
611 private:
612 const Layout& layout;
613 Canvas* canvas;
614 float hOffset;
615 float vOffset;
616 const Paint& paint;
617 const SkPath& path;
618 };
619
drawTextOnPath(Canvas * canvas,const uint16_t * text,int count,int bidiFlags,const SkPath & path,float hOffset,float vOffset,const Paint & paint,TypefaceImpl * typeface)620 static void drawTextOnPath(Canvas* canvas, const uint16_t* text, int count, int bidiFlags,
621 const SkPath& path, float hOffset, float vOffset,
622 const Paint& paint, TypefaceImpl* typeface) {
623 Paint paintCopy(paint);
624 Layout layout;
625 MinikinUtils::doLayout(&layout, &paintCopy, bidiFlags, typeface, text, 0, count, count);
626 hOffset += MinikinUtils::hOffsetForTextAlign(&paintCopy, layout, path);
627
628 // Set align to left for drawing, as we don't want individual
629 // glyphs centered or right-aligned; the offset above takes
630 // care of all alignment.
631 paintCopy.setTextAlign(Paint::kLeft_Align);
632
633 DrawTextOnPathFunctor f(layout, canvas, hOffset, vOffset, paintCopy, path);
634 MinikinUtils::forFontRun(layout, &paintCopy, f);
635 }
636
drawTextOnPathChars(JNIEnv * env,jobject,jlong canvasHandle,jcharArray text,jint index,jint count,jlong pathHandle,jfloat hOffset,jfloat vOffset,jint bidiFlags,jlong paintHandle,jlong typefaceHandle)637 static void drawTextOnPathChars(JNIEnv* env, jobject, jlong canvasHandle, jcharArray text,
638 jint index, jint count, jlong pathHandle, jfloat hOffset,
639 jfloat vOffset, jint bidiFlags, jlong paintHandle,
640 jlong typefaceHandle) {
641 SkPath* path = reinterpret_cast<SkPath*>(pathHandle);
642 Paint* paint = reinterpret_cast<Paint*>(paintHandle);
643 TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefaceHandle);
644
645 jchar* jchars = env->GetCharArrayElements(text, NULL);
646
647 drawTextOnPath(get_canvas(canvasHandle), jchars + index, count, bidiFlags, *path,
648 hOffset, vOffset, *paint, typeface);
649
650 env->ReleaseCharArrayElements(text, jchars, 0);
651 }
652
drawTextOnPathString(JNIEnv * env,jobject,jlong canvasHandle,jstring text,jlong pathHandle,jfloat hOffset,jfloat vOffset,jint bidiFlags,jlong paintHandle,jlong typefaceHandle)653 static void drawTextOnPathString(JNIEnv* env, jobject, jlong canvasHandle, jstring text,
654 jlong pathHandle, jfloat hOffset, jfloat vOffset,
655 jint bidiFlags, jlong paintHandle, jlong typefaceHandle) {
656 SkPath* path = reinterpret_cast<SkPath*>(pathHandle);
657 Paint* paint = reinterpret_cast<Paint*>(paintHandle);
658 TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefaceHandle);
659
660 const jchar* jchars = env->GetStringChars(text, NULL);
661 int count = env->GetStringLength(text);
662
663 drawTextOnPath(get_canvas(canvasHandle), jchars, count, bidiFlags, *path,
664 hOffset, vOffset, *paint, typeface);
665
666 env->ReleaseStringChars(text, jchars);
667 }
668
setDrawFilter(JNIEnv * env,jobject,jlong canvasHandle,jlong filterHandle)669 static void setDrawFilter(JNIEnv* env, jobject, jlong canvasHandle, jlong filterHandle) {
670 get_canvas(canvasHandle)->setDrawFilter(reinterpret_cast<SkDrawFilter*>(filterHandle));
671 }
672
freeCaches(JNIEnv * env,jobject)673 static void freeCaches(JNIEnv* env, jobject) {
674 SkGraphics::PurgeFontCache();
675 }
676
freeTextLayoutCaches(JNIEnv * env,jobject)677 static void freeTextLayoutCaches(JNIEnv* env, jobject) {
678 Layout::purgeCaches();
679 }
680
681 }; // namespace CanvasJNI
682
683 static JNINativeMethod gMethods[] = {
684 {"finalizer", "(J)V", (void*) CanvasJNI::finalizer},
685 {"initRaster", "(J)J", (void*) CanvasJNI::initRaster},
686 {"native_setBitmap", "(JJZ)V", (void*) CanvasJNI::setBitmap},
687 {"native_isOpaque","(J)Z", (void*) CanvasJNI::isOpaque},
688 {"native_getWidth","(J)I", (void*) CanvasJNI::getWidth},
689 {"native_getHeight","(J)I", (void*) CanvasJNI::getHeight},
690 {"native_save","(JI)I", (void*) CanvasJNI::save},
691 {"native_saveLayer","(JFFFFJI)I", (void*) CanvasJNI::saveLayer},
692 {"native_saveLayerAlpha","(JFFFFII)I", (void*) CanvasJNI::saveLayerAlpha},
693 {"native_getSaveCount","(J)I", (void*) CanvasJNI::getSaveCount},
694 {"native_restore","(J)V", (void*) CanvasJNI::restore},
695 {"native_restoreToCount","(JI)V", (void*) CanvasJNI::restoreToCount},
696 {"native_getCTM", "(JJ)V", (void*)CanvasJNI::getCTM},
697 {"native_setMatrix","(JJ)V", (void*) CanvasJNI::setMatrix},
698 {"native_concat","(JJ)V", (void*) CanvasJNI::concat},
699 {"native_rotate","(JF)V", (void*) CanvasJNI::rotate},
700 {"native_scale","(JFF)V", (void*) CanvasJNI::scale},
701 {"native_skew","(JFF)V", (void*) CanvasJNI::skew},
702 {"native_translate","(JFF)V", (void*) CanvasJNI::translate},
703 {"native_getClipBounds","(JLandroid/graphics/Rect;)Z", (void*) CanvasJNI::getClipBounds},
704 {"native_quickReject","(JJ)Z", (void*) CanvasJNI::quickRejectPath},
705 {"native_quickReject","(JFFFF)Z", (void*)CanvasJNI::quickRejectRect},
706 {"native_clipRect","(JFFFFI)Z", (void*) CanvasJNI::clipRect},
707 {"native_clipPath","(JJI)Z", (void*) CanvasJNI::clipPath},
708 {"native_clipRegion","(JJI)Z", (void*) CanvasJNI::clipRegion},
709 {"native_drawColor","(JII)V", (void*) CanvasJNI::drawColor},
710 {"native_drawPaint","(JJ)V", (void*) CanvasJNI::drawPaint},
711 {"native_drawPoint", "(JFFJ)V", (void*) CanvasJNI::drawPoint},
712 {"native_drawPoints", "(J[FIIJ)V", (void*) CanvasJNI::drawPoints},
713 {"native_drawLine", "(JFFFFJ)V", (void*) CanvasJNI::drawLine},
714 {"native_drawLines", "(J[FIIJ)V", (void*) CanvasJNI::drawLines},
715 {"native_drawRect","(JFFFFJ)V", (void*) CanvasJNI::drawRect},
716 {"native_drawRoundRect","(JFFFFFFJ)V", (void*) CanvasJNI::drawRoundRect},
717 {"native_drawCircle","(JFFFJ)V", (void*) CanvasJNI::drawCircle},
718 {"native_drawOval","(JFFFFJ)V", (void*) CanvasJNI::drawOval},
719 {"native_drawArc","(JFFFFFFZJ)V", (void*) CanvasJNI::drawArc},
720 {"native_drawPath","(JJJ)V", (void*) CanvasJNI::drawPath},
721 {"nativeDrawVertices", "(JII[FI[FI[II[SIIJ)V", (void*)CanvasJNI::drawVertices},
722 {"native_drawBitmap","(JJFFJIII)V", (void*) CanvasJNI::drawBitmap},
723 {"nativeDrawBitmapMatrix", "(JJJJ)V", (void*)CanvasJNI::drawBitmapMatrix},
724 {"native_drawBitmap","(JJFFFFFFFFJII)V", (void*) CanvasJNI::drawBitmapRect},
725 {"native_drawBitmap", "(J[IIIFFIIZJ)V", (void*)CanvasJNI::drawBitmapArray},
726 {"nativeDrawBitmapMesh", "(JJII[FI[IIJ)V", (void*)CanvasJNI::drawBitmapMesh},
727 {"native_drawText","(J[CIIFFIJJ)V", (void*) CanvasJNI::drawTextChars},
728 {"native_drawText","(JLjava/lang/String;IIFFIJJ)V", (void*) CanvasJNI::drawTextString},
729 {"native_drawTextRun","(J[CIIIIFFZJJ)V", (void*) CanvasJNI::drawTextRunChars},
730 {"native_drawTextRun","(JLjava/lang/String;IIIIFFZJJ)V", (void*) CanvasJNI::drawTextRunString},
731 {"native_drawTextOnPath","(J[CIIJFFIJJ)V", (void*) CanvasJNI::drawTextOnPathChars},
732 {"native_drawTextOnPath","(JLjava/lang/String;JFFIJJ)V", (void*) CanvasJNI::drawTextOnPathString},
733 {"nativeSetDrawFilter", "(JJ)V", (void*) CanvasJNI::setDrawFilter},
734 {"freeCaches", "()V", (void*) CanvasJNI::freeCaches},
735 {"freeTextLayoutCaches", "()V", (void*) CanvasJNI::freeTextLayoutCaches}
736 };
737
register_android_graphics_Canvas(JNIEnv * env)738 int register_android_graphics_Canvas(JNIEnv* env) {
739 return AndroidRuntime::registerNativeMethods(env, "android/graphics/Canvas", gMethods, NELEM(gMethods));
740 }
741
742 }; // namespace android
743