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