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