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