blob: 19aad6129807cfe7e3dcaa066f42f9aacdc3602f [file] [log] [blame]
Derek Sollenberger8872b382014-06-23 14:13:53 -04001/*
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"
Andreas Gampeed6b9df2014-11-20 22:02:20 -080019#include "core_jni_helpers.h"
Derek Sollenberger8872b382014-06-23 14:13:53 -040020
21#include "Canvas.h"
Derek Sollenbergeracb40992014-07-21 15:22:10 -040022#include "SkDrawFilter.h"
Derek Sollenberger8872b382014-06-23 14:13:53 -040023#include "SkGraphics.h"
24#include "SkPorterDuff.h"
Behdad Esfahbod6ba30b82014-07-15 16:22:32 -040025#include "Paint.h"
Derek Sollenberger8872b382014-06-23 14:13:53 -040026#include "TypefaceImpl.h"
27
Derek Sollenberger8872b382014-06-23 14:13:53 -040028#include "MinikinUtils.h"
29
30namespace android {
31
32namespace CanvasJNI {
33
34static Canvas* get_canvas(jlong canvasHandle) {
35 return reinterpret_cast<Canvas*>(canvasHandle);
36}
37
38static void finalizer(JNIEnv* env, jobject clazz, jlong canvasHandle) {
39 delete get_canvas(canvasHandle);
40}
41
42// Native wrapper constructor used by Canvas(Bitmap)
43static 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.
50static 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
56static jboolean isOpaque(JNIEnv*, jobject, jlong canvasHandle) {
57 return get_canvas(canvasHandle)->isOpaque() ? JNI_TRUE : JNI_FALSE;
58}
59
60static jint getWidth(JNIEnv*, jobject, jlong canvasHandle) {
61 return static_cast<jint>(get_canvas(canvasHandle)->width());
62}
63
64static jint getHeight(JNIEnv*, jobject, jlong canvasHandle) {
65 return static_cast<jint>(get_canvas(canvasHandle)->height());
66}
67
68static jint getSaveCount(JNIEnv*, jobject, jlong canvasHandle) {
69 return static_cast<jint>(get_canvas(canvasHandle)->getSaveCount());
70}
71
72static 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
77static jint saveLayer(JNIEnv* env, jobject, jlong canvasHandle, jfloat l, jfloat t,
78 jfloat r, jfloat b, jlong paintHandle, jint flagsHandle) {
Behdad Esfahbod6ba30b82014-07-15 16:22:32 -040079 Paint* paint = reinterpret_cast<Paint*>(paintHandle);
Derek Sollenberger8872b382014-06-23 14:13:53 -040080 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
84static 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
90static 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
99static 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
108static void getCTM(JNIEnv* env, jobject, jlong canvasHandle, jlong matrixHandle) {
109 SkMatrix* matrix = reinterpret_cast<SkMatrix*>(matrixHandle);
110 get_canvas(canvasHandle)->getMatrix(matrix);
111}
112
113static 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
118static 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
123static void rotate(JNIEnv*, jobject, jlong canvasHandle, jfloat degrees) {
124 get_canvas(canvasHandle)->rotate(degrees);
125}
126
127static void scale(JNIEnv*, jobject, jlong canvasHandle, jfloat sx, jfloat sy) {
128 get_canvas(canvasHandle)->scale(sx, sy);
129}
130
131static void skew(JNIEnv*, jobject, jlong canvasHandle, jfloat sx, jfloat sy) {
132 get_canvas(canvasHandle)->skew(sx, sy);
133}
134
135static void translate(JNIEnv*, jobject, jlong canvasHandle, jfloat dx, jfloat dy) {
136 get_canvas(canvasHandle)->translate(dx, dy);
137}
138
139static 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
153static 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
159static 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
165static 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
172static 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
180static 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
188static 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
193static void drawPaint(JNIEnv* env, jobject, jlong canvasHandle, jlong paintHandle) {
Behdad Esfahbod6ba30b82014-07-15 16:22:32 -0400194 Paint* paint = reinterpret_cast<Paint*>(paintHandle);
Derek Sollenberger8872b382014-06-23 14:13:53 -0400195 get_canvas(canvasHandle)->drawPaint(*paint);
196}
197
198static void drawPoint(JNIEnv*, jobject, jlong canvasHandle, jfloat x, jfloat y,
199 jlong paintHandle) {
Behdad Esfahbod6ba30b82014-07-15 16:22:32 -0400200 const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
Derek Sollenberger8872b382014-06-23 14:13:53 -0400201 get_canvas(canvasHandle)->drawPoint(x, y, *paint);
202}
203
204static 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
Behdad Esfahbod6ba30b82014-07-15 16:22:32 -0400216 const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
Derek Sollenberger8872b382014-06-23 14:13:53 -0400217 get_canvas(canvasHandle)->drawPoints(floats + offset, count, *paint);
218}
219
220static void drawLine(JNIEnv* env, jobject, jlong canvasHandle, jfloat startX, jfloat startY,
221 jfloat stopX, jfloat stopY, jlong paintHandle) {
Behdad Esfahbod6ba30b82014-07-15 16:22:32 -0400222 Paint* paint = reinterpret_cast<Paint*>(paintHandle);
Derek Sollenberger8872b382014-06-23 14:13:53 -0400223 get_canvas(canvasHandle)->drawLine(startX, startY, stopX, stopY, *paint);
224}
225
226static 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
Behdad Esfahbod6ba30b82014-07-15 16:22:32 -0400238 const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
Derek Sollenberger8872b382014-06-23 14:13:53 -0400239 get_canvas(canvasHandle)->drawLines(floats + offset, count, *paint);
240}
241
242static void drawRect(JNIEnv* env, jobject, jlong canvasHandle, jfloat left, jfloat top,
243 jfloat right, jfloat bottom, jlong paintHandle) {
Behdad Esfahbod6ba30b82014-07-15 16:22:32 -0400244 const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
Derek Sollenberger8872b382014-06-23 14:13:53 -0400245 get_canvas(canvasHandle)->drawRect(left, top, right, bottom, *paint);
246}
247
248static void drawRoundRect(JNIEnv* env, jobject, jlong canvasHandle, jfloat left, jfloat top,
249 jfloat right, jfloat bottom, jfloat rx, jfloat ry, jlong paintHandle) {
Behdad Esfahbod6ba30b82014-07-15 16:22:32 -0400250 const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
Derek Sollenberger8872b382014-06-23 14:13:53 -0400251 get_canvas(canvasHandle)->drawRoundRect(left, top, right, bottom, rx, ry, *paint);
252}
253
254static void drawCircle(JNIEnv* env, jobject, jlong canvasHandle, jfloat cx, jfloat cy,
255 jfloat radius, jlong paintHandle) {
Behdad Esfahbod6ba30b82014-07-15 16:22:32 -0400256 const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
Derek Sollenberger8872b382014-06-23 14:13:53 -0400257 get_canvas(canvasHandle)->drawCircle(cx, cy, radius, *paint);
258}
259
260static void drawOval(JNIEnv* env, jobject, jlong canvasHandle, jfloat left, jfloat top,
261 jfloat right, jfloat bottom, jlong paintHandle) {
Behdad Esfahbod6ba30b82014-07-15 16:22:32 -0400262 const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
Derek Sollenberger8872b382014-06-23 14:13:53 -0400263 get_canvas(canvasHandle)->drawOval(left, top, right, bottom, *paint);
264}
265
266static 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) {
Behdad Esfahbod6ba30b82014-07-15 16:22:32 -0400269 const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
Derek Sollenberger8872b382014-06-23 14:13:53 -0400270 get_canvas(canvasHandle)->drawArc(left, top, right, bottom, startAngle, sweepAngle,
271 useCenter, *paint);
272}
273
274static void drawPath(JNIEnv* env, jobject, jlong canvasHandle, jlong pathHandle,
275 jlong paintHandle) {
276 const SkPath* path = reinterpret_cast<SkPath*>(pathHandle);
Behdad Esfahbod6ba30b82014-07-15 16:22:32 -0400277 const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
Derek Sollenberger8872b382014-06-23 14:13:53 -0400278 get_canvas(canvasHandle)->drawPath(*path, *paint);
279}
280
281static 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);
Behdad Esfahbod6ba30b82014-07-15 16:22:32 -0400306 const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
Derek Sollenberger8872b382014-06-23 14:13:53 -0400307 get_canvas(canvasHandle)->drawVertices(mode, vertexCount, verts, texs, colors,
308 indices, indexCount, *paint);
309}
310
311static 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);
Behdad Esfahbod6ba30b82014-07-15 16:22:32 -0400316 const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
Derek Sollenberger8872b382014-06-23 14:13:53 -0400317
318 if (canvasDensity == bitmapDensity || canvasDensity == 0 || bitmapDensity == 0) {
319 if (screenDensity != 0 && screenDensity != bitmapDensity) {
Behdad Esfahbod6ba30b82014-07-15 16:22:32 -0400320 Paint filteredPaint;
Derek Sollenberger8872b382014-06-23 14:13:53 -0400321 if (paint) {
322 filteredPaint = *paint;
323 }
Behdad Esfahbod6ba30b82014-07-15 16:22:32 -0400324 filteredPaint.setFilterLevel(Paint::kLow_FilterLevel);
Derek Sollenberger8872b382014-06-23 14:13:53 -0400325 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
Behdad Esfahbod6ba30b82014-07-15 16:22:32 -0400335 Paint filteredPaint;
Derek Sollenberger8872b382014-06-23 14:13:53 -0400336 if (paint) {
337 filteredPaint = *paint;
338 }
Behdad Esfahbod6ba30b82014-07-15 16:22:32 -0400339 filteredPaint.setFilterLevel(Paint::kLow_FilterLevel);
Derek Sollenberger8872b382014-06-23 14:13:53 -0400340
341 canvas->drawBitmap(*bitmap, 0, 0, &filteredPaint);
342 canvas->restore();
343 }
344}
345
346static 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);
Behdad Esfahbod6ba30b82014-07-15 16:22:32 -0400350 const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
Derek Sollenberger8872b382014-06-23 14:13:53 -0400351 get_canvas(canvasHandle)->drawBitmap(*bitmap, *matrix, paint);
352}
353
354static 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);
Behdad Esfahbod6ba30b82014-07-15 16:22:32 -0400360 const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
Derek Sollenberger8872b382014-06-23 14:13:53 -0400361
362 if (screenDensity != 0 && screenDensity != bitmapDensity) {
Behdad Esfahbod6ba30b82014-07-15 16:22:32 -0400363 Paint filteredPaint;
Derek Sollenberger8872b382014-06-23 14:13:53 -0400364 if (paint) {
365 filteredPaint = *paint;
366 }
Behdad Esfahbod6ba30b82014-07-15 16:22:32 -0400367 filteredPaint.setFilterLevel(Paint::kLow_FilterLevel);
Derek Sollenberger8872b382014-06-23 14:13:53 -0400368 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
376static 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
Behdad Esfahbod6ba30b82014-07-15 16:22:32 -0400394 const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
Derek Sollenberger8872b382014-06-23 14:13:53 -0400395 get_canvas(canvasHandle)->drawBitmap(bitmap, x, y, paint);
396}
397
398static 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);
Behdad Esfahbod6ba30b82014-07-15 16:22:32 -0400406 const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
Derek Sollenberger8872b382014-06-23 14:13:53 -0400407 get_canvas(canvasHandle)->drawBitmapMesh(*bitmap, meshWidth, meshHeight,
408 vertA.ptr(), colorA.ptr(), paint);
409}
410
Derek Sollenbergeracb40992014-07-21 15:22:10 -0400411class DrawTextFunctor {
412public:
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
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 }
437private:
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
453void 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
481void 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;
Behdad Esfahbod63c5c782014-07-25 14:54:46 -0400487 MinikinUtils::doLayout(&layout, &paint, bidiFlags, typeface, text, start, count, contextCount);
Derek Sollenbergeracb40992014-07-21 15:22:10 -0400488
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
Derek Sollenberger8872b382014-06-23 14:13:53 -0400507static 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) {
Behdad Esfahbod6ba30b82014-07-15 16:22:32 -0400510 Paint* paint = reinterpret_cast<Paint*>(paintHandle);
Derek Sollenberger8872b382014-06-23 14:13:53 -0400511 TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefaceHandle);
512 jchar* jchars = env->GetCharArrayElements(text, NULL);
Derek Sollenbergeracb40992014-07-21 15:22:10 -0400513 drawText(get_canvas(canvasHandle), jchars + index, 0, count, count, x, y,
Derek Sollenberger8872b382014-06-23 14:13:53 -0400514 bidiFlags, *paint, typeface);
515 env->ReleaseCharArrayElements(text, jchars, JNI_ABORT);
516}
517
518static 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) {
Behdad Esfahbod6ba30b82014-07-15 16:22:32 -0400521 Paint* paint = reinterpret_cast<Paint*>(paintHandle);
Derek Sollenberger8872b382014-06-23 14:13:53 -0400522 TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefaceHandle);
523 const int count = end - start;
524 const jchar* jchars = env->GetStringChars(text, NULL);
Derek Sollenbergeracb40992014-07-21 15:22:10 -0400525 drawText(get_canvas(canvasHandle), jchars + start, 0, count, count, x, y,
Derek Sollenberger8872b382014-06-23 14:13:53 -0400526 bidiFlags, *paint, typeface);
527 env->ReleaseStringChars(text, jchars);
528}
529
530static 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) {
Behdad Esfahbod6ba30b82014-07-15 16:22:32 -0400533 Paint* paint = reinterpret_cast<Paint*>(paintHandle);
Derek Sollenberger8872b382014-06-23 14:13:53 -0400534 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);
Derek Sollenbergeracb40992014-07-21 15:22:10 -0400538 drawText(get_canvas(canvasHandle), jchars + contextIndex, index - contextIndex, count,
Derek Sollenberger8872b382014-06-23 14:13:53 -0400539 contextCount, x, y, bidiFlags, *paint, typeface);
540 env->ReleaseCharArrayElements(text, jchars, JNI_ABORT);
541}
542
543static 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) {
Behdad Esfahbod6ba30b82014-07-15 16:22:32 -0400547 Paint* paint = reinterpret_cast<Paint*>(paintHandle);
Derek Sollenberger8872b382014-06-23 14:13:53 -0400548 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);
Derek Sollenbergeracb40992014-07-21 15:22:10 -0400554 drawText(get_canvas(canvasHandle), jchars + contextStart, start - contextStart, count,
Derek Sollenberger8872b382014-06-23 14:13:53 -0400555 contextCount, x, y, bidiFlags, *paint, typeface);
556 env->ReleaseStringChars(text, jchars);
557}
558
Derek Sollenberger8872b382014-06-23 14:13:53 -0400559class DrawTextOnPathFunctor {
560public:
561 DrawTextOnPathFunctor(const Layout& layout, Canvas* canvas, float hOffset,
Behdad Esfahbod6ba30b82014-07-15 16:22:32 -0400562 float vOffset, const Paint& paint, const SkPath& path)
Derek Sollenberger8872b382014-06-23 14:13:53 -0400563 : layout(layout), canvas(canvas), hOffset(hOffset), vOffset(vOffset),
564 paint(paint), path(path) {
565 }
566 void operator()(size_t start, size_t end) {
567 uint16_t glyphs[1];
568 for (size_t i = start; i < end; i++) {
569 glyphs[0] = layout.getGlyphId(i);
570 float x = hOffset + layout.getX(i);
571 float y = vOffset + layout.getY(i);
572 canvas->drawTextOnPath(glyphs, 1, path, x, y, paint);
573 }
574 }
575private:
576 const Layout& layout;
577 Canvas* canvas;
578 float hOffset;
579 float vOffset;
Behdad Esfahbod6ba30b82014-07-15 16:22:32 -0400580 const Paint& paint;
Derek Sollenberger8872b382014-06-23 14:13:53 -0400581 const SkPath& path;
582};
583
584static void drawTextOnPath(Canvas* canvas, const uint16_t* text, int count, int bidiFlags,
585 const SkPath& path, float hOffset, float vOffset,
Behdad Esfahbod6ba30b82014-07-15 16:22:32 -0400586 const Paint& paint, TypefaceImpl* typeface) {
587 Paint paintCopy(paint);
Derek Sollenberger8872b382014-06-23 14:13:53 -0400588 Layout layout;
Behdad Esfahbod63c5c782014-07-25 14:54:46 -0400589 MinikinUtils::doLayout(&layout, &paintCopy, bidiFlags, typeface, text, 0, count, count);
Derek Sollenberger8872b382014-06-23 14:13:53 -0400590 hOffset += MinikinUtils::hOffsetForTextAlign(&paintCopy, layout, path);
591
592 // Set align to left for drawing, as we don't want individual
593 // glyphs centered or right-aligned; the offset above takes
594 // care of all alignment.
Behdad Esfahbod6ba30b82014-07-15 16:22:32 -0400595 paintCopy.setTextAlign(Paint::kLeft_Align);
Derek Sollenberger8872b382014-06-23 14:13:53 -0400596
597 DrawTextOnPathFunctor f(layout, canvas, hOffset, vOffset, paintCopy, path);
598 MinikinUtils::forFontRun(layout, &paintCopy, f);
599}
600
601static void drawTextOnPathChars(JNIEnv* env, jobject, jlong canvasHandle, jcharArray text,
602 jint index, jint count, jlong pathHandle, jfloat hOffset,
603 jfloat vOffset, jint bidiFlags, jlong paintHandle,
604 jlong typefaceHandle) {
605 SkPath* path = reinterpret_cast<SkPath*>(pathHandle);
Behdad Esfahbod6ba30b82014-07-15 16:22:32 -0400606 Paint* paint = reinterpret_cast<Paint*>(paintHandle);
Derek Sollenberger8872b382014-06-23 14:13:53 -0400607 TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefaceHandle);
608
609 jchar* jchars = env->GetCharArrayElements(text, NULL);
610
611 drawTextOnPath(get_canvas(canvasHandle), jchars + index, count, bidiFlags, *path,
612 hOffset, vOffset, *paint, typeface);
613
614 env->ReleaseCharArrayElements(text, jchars, 0);
615}
616
617static void drawTextOnPathString(JNIEnv* env, jobject, jlong canvasHandle, jstring text,
618 jlong pathHandle, jfloat hOffset, jfloat vOffset,
619 jint bidiFlags, jlong paintHandle, jlong typefaceHandle) {
620 SkPath* path = reinterpret_cast<SkPath*>(pathHandle);
Behdad Esfahbod6ba30b82014-07-15 16:22:32 -0400621 Paint* paint = reinterpret_cast<Paint*>(paintHandle);
Derek Sollenberger8872b382014-06-23 14:13:53 -0400622 TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefaceHandle);
623
624 const jchar* jchars = env->GetStringChars(text, NULL);
625 int count = env->GetStringLength(text);
626
627 drawTextOnPath(get_canvas(canvasHandle), jchars, count, bidiFlags, *path,
628 hOffset, vOffset, *paint, typeface);
629
630 env->ReleaseStringChars(text, jchars);
631}
632
633static void setDrawFilter(JNIEnv* env, jobject, jlong canvasHandle, jlong filterHandle) {
634 get_canvas(canvasHandle)->setDrawFilter(reinterpret_cast<SkDrawFilter*>(filterHandle));
635}
636
637static void freeCaches(JNIEnv* env, jobject) {
638 SkGraphics::PurgeFontCache();
639}
640
641static void freeTextLayoutCaches(JNIEnv* env, jobject) {
642 Layout::purgeCaches();
643}
644
645}; // namespace CanvasJNI
646
647static JNINativeMethod gMethods[] = {
648 {"finalizer", "(J)V", (void*) CanvasJNI::finalizer},
649 {"initRaster", "(J)J", (void*) CanvasJNI::initRaster},
650 {"native_setBitmap", "(JJZ)V", (void*) CanvasJNI::setBitmap},
651 {"native_isOpaque","(J)Z", (void*) CanvasJNI::isOpaque},
652 {"native_getWidth","(J)I", (void*) CanvasJNI::getWidth},
653 {"native_getHeight","(J)I", (void*) CanvasJNI::getHeight},
654 {"native_save","(JI)I", (void*) CanvasJNI::save},
655 {"native_saveLayer","(JFFFFJI)I", (void*) CanvasJNI::saveLayer},
656 {"native_saveLayerAlpha","(JFFFFII)I", (void*) CanvasJNI::saveLayerAlpha},
657 {"native_getSaveCount","(J)I", (void*) CanvasJNI::getSaveCount},
658 {"native_restore","(J)V", (void*) CanvasJNI::restore},
659 {"native_restoreToCount","(JI)V", (void*) CanvasJNI::restoreToCount},
660 {"native_getCTM", "(JJ)V", (void*)CanvasJNI::getCTM},
661 {"native_setMatrix","(JJ)V", (void*) CanvasJNI::setMatrix},
662 {"native_concat","(JJ)V", (void*) CanvasJNI::concat},
663 {"native_rotate","(JF)V", (void*) CanvasJNI::rotate},
664 {"native_scale","(JFF)V", (void*) CanvasJNI::scale},
665 {"native_skew","(JFF)V", (void*) CanvasJNI::skew},
666 {"native_translate","(JFF)V", (void*) CanvasJNI::translate},
667 {"native_getClipBounds","(JLandroid/graphics/Rect;)Z", (void*) CanvasJNI::getClipBounds},
668 {"native_quickReject","(JJ)Z", (void*) CanvasJNI::quickRejectPath},
669 {"native_quickReject","(JFFFF)Z", (void*)CanvasJNI::quickRejectRect},
670 {"native_clipRect","(JFFFFI)Z", (void*) CanvasJNI::clipRect},
671 {"native_clipPath","(JJI)Z", (void*) CanvasJNI::clipPath},
672 {"native_clipRegion","(JJI)Z", (void*) CanvasJNI::clipRegion},
673 {"native_drawColor","(JII)V", (void*) CanvasJNI::drawColor},
674 {"native_drawPaint","(JJ)V", (void*) CanvasJNI::drawPaint},
675 {"native_drawPoint", "(JFFJ)V", (void*) CanvasJNI::drawPoint},
676 {"native_drawPoints", "(J[FIIJ)V", (void*) CanvasJNI::drawPoints},
677 {"native_drawLine", "(JFFFFJ)V", (void*) CanvasJNI::drawLine},
678 {"native_drawLines", "(J[FIIJ)V", (void*) CanvasJNI::drawLines},
679 {"native_drawRect","(JFFFFJ)V", (void*) CanvasJNI::drawRect},
680 {"native_drawRoundRect","(JFFFFFFJ)V", (void*) CanvasJNI::drawRoundRect},
681 {"native_drawCircle","(JFFFJ)V", (void*) CanvasJNI::drawCircle},
682 {"native_drawOval","(JFFFFJ)V", (void*) CanvasJNI::drawOval},
683 {"native_drawArc","(JFFFFFFZJ)V", (void*) CanvasJNI::drawArc},
684 {"native_drawPath","(JJJ)V", (void*) CanvasJNI::drawPath},
685 {"nativeDrawVertices", "(JII[FI[FI[II[SIIJ)V", (void*)CanvasJNI::drawVertices},
686 {"native_drawBitmap","(JJFFJIII)V", (void*) CanvasJNI::drawBitmap},
687 {"nativeDrawBitmapMatrix", "(JJJJ)V", (void*)CanvasJNI::drawBitmapMatrix},
688 {"native_drawBitmap","(JJFFFFFFFFJII)V", (void*) CanvasJNI::drawBitmapRect},
689 {"native_drawBitmap", "(J[IIIFFIIZJ)V", (void*)CanvasJNI::drawBitmapArray},
690 {"nativeDrawBitmapMesh", "(JJII[FI[IIJ)V", (void*)CanvasJNI::drawBitmapMesh},
691 {"native_drawText","(J[CIIFFIJJ)V", (void*) CanvasJNI::drawTextChars},
692 {"native_drawText","(JLjava/lang/String;IIFFIJJ)V", (void*) CanvasJNI::drawTextString},
693 {"native_drawTextRun","(J[CIIIIFFZJJ)V", (void*) CanvasJNI::drawTextRunChars},
694 {"native_drawTextRun","(JLjava/lang/String;IIIIFFZJJ)V", (void*) CanvasJNI::drawTextRunString},
695 {"native_drawTextOnPath","(J[CIIJFFIJJ)V", (void*) CanvasJNI::drawTextOnPathChars},
696 {"native_drawTextOnPath","(JLjava/lang/String;JFFIJJ)V", (void*) CanvasJNI::drawTextOnPathString},
697 {"nativeSetDrawFilter", "(JJ)V", (void*) CanvasJNI::setDrawFilter},
698 {"freeCaches", "()V", (void*) CanvasJNI::freeCaches},
699 {"freeTextLayoutCaches", "()V", (void*) CanvasJNI::freeTextLayoutCaches}
700};
701
702int register_android_graphics_Canvas(JNIEnv* env) {
Andreas Gampeed6b9df2014-11-20 22:02:20 -0800703 return RegisterMethodsOrDie(env, "android/graphics/Canvas", gMethods, NELEM(gMethods));
Derek Sollenberger8872b382014-06-23 14:13:53 -0400704}
705
706}; // namespace android