android_graphics_Canvas.cpp revision b29b16e5423fe7deab8ebf3da512c6d2192f19b5
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
186// SkRegion::Op and SkClipOp are numerically identical, so we can freely cast
187// from one to the other (though SkClipOp is destined to become a strict subset)
188static_assert(SkRegion::kDifference_Op == static_cast<SkRegion::Op>(SkClipOp::kDifference), "");
189static_assert(SkRegion::kIntersect_Op == static_cast<SkRegion::Op>(SkClipOp::kIntersect), "");
190static_assert(SkRegion::kUnion_Op == static_cast<SkRegion::Op>(SkClipOp::kUnion), "");
191static_assert(SkRegion::kXOR_Op == static_cast<SkRegion::Op>(SkClipOp::kXOR), "");
192static_assert(SkRegion::kReverseDifference_Op == static_cast<SkRegion::Op>(SkClipOp::kReverseDifference), "");
193static_assert(SkRegion::kReplace_Op == static_cast<SkRegion::Op>(SkClipOp::kReplace), "");
194
195static SkClipOp opHandleToClipOp(jint opHandle) {
196    // The opHandle is defined in Canvas.java to be Region::Op
197    SkRegion::Op rgnOp = static_cast<SkRegion::Op>(opHandle);
198
199    // In the future, when we no longer support the wide range of ops (e.g. Union, Xor)
200    // this function can perform a range check and throw an unsupported-exception.
201    // e.g. if (rgnOp != kIntersect && rgnOp != kDifference) throw...
202
203    // Skia now takes a different type, SkClipOp, as the parameter to clipping calls
204    // This type is binary compatible with SkRegion::Op, so a static_cast<> is safe.
205    return static_cast<SkClipOp>(rgnOp);
206}
207
208static jboolean clipRect(JNIEnv*, jobject, jlong canvasHandle, jfloat l, jfloat t,
209                         jfloat r, jfloat b, jint opHandle) {
210    bool nonEmptyClip = get_canvas(canvasHandle)->clipRect(l, t, r, b,
211            opHandleToClipOp(opHandle));
212    return nonEmptyClip ? JNI_TRUE : JNI_FALSE;
213}
214
215static jboolean clipPath(JNIEnv* env, jobject, jlong canvasHandle, jlong pathHandle,
216                         jint opHandle) {
217    SkPath* path = reinterpret_cast<SkPath*>(pathHandle);
218    bool nonEmptyClip = get_canvas(canvasHandle)->clipPath(path, opHandleToClipOp(opHandle));
219    return nonEmptyClip ? JNI_TRUE : JNI_FALSE;
220}
221
222static void drawColor(JNIEnv* env, jobject, jlong canvasHandle, jint color, jint modeHandle) {
223    SkBlendMode mode = static_cast<SkBlendMode>(modeHandle);
224    get_canvas(canvasHandle)->drawColor(color, mode);
225}
226
227static void drawPaint(JNIEnv* env, jobject, jlong canvasHandle, jlong paintHandle) {
228    Paint* paint = reinterpret_cast<Paint*>(paintHandle);
229    get_canvas(canvasHandle)->drawPaint(*paint);
230}
231
232static void drawPoint(JNIEnv*, jobject, jlong canvasHandle, jfloat x, jfloat y,
233                      jlong paintHandle) {
234    const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
235    get_canvas(canvasHandle)->drawPoint(x, y, *paint);
236}
237
238static void drawPoints(JNIEnv* env, jobject, jlong canvasHandle, jfloatArray jptsArray,
239                       jint offset, jint count, jlong paintHandle) {
240    NPE_CHECK_RETURN_VOID(env, jptsArray);
241    AutoJavaFloatArray autoPts(env, jptsArray);
242    float* floats = autoPts.ptr();
243    const int length = autoPts.length();
244
245    if ((offset | count) < 0 || offset + count > length) {
246        doThrowAIOOBE(env);
247        return;
248    }
249
250    const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
251    get_canvas(canvasHandle)->drawPoints(floats + offset, count, *paint);
252}
253
254static void drawLine(JNIEnv* env, jobject, jlong canvasHandle, jfloat startX, jfloat startY,
255                     jfloat stopX, jfloat stopY, jlong paintHandle) {
256    Paint* paint = reinterpret_cast<Paint*>(paintHandle);
257    get_canvas(canvasHandle)->drawLine(startX, startY, stopX, stopY, *paint);
258}
259
260static void drawLines(JNIEnv* env, jobject, jlong canvasHandle, jfloatArray jptsArray,
261                      jint offset, jint count, jlong paintHandle) {
262    NPE_CHECK_RETURN_VOID(env, jptsArray);
263    AutoJavaFloatArray autoPts(env, jptsArray);
264    float* floats = autoPts.ptr();
265    const int length = autoPts.length();
266
267    if ((offset | count) < 0 || offset + count > length) {
268        doThrowAIOOBE(env);
269        return;
270    }
271
272    const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
273    get_canvas(canvasHandle)->drawLines(floats + offset, count, *paint);
274}
275
276static void drawRect(JNIEnv* env, jobject, jlong canvasHandle, jfloat left, jfloat top,
277                     jfloat right, jfloat bottom, jlong paintHandle) {
278    const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
279    get_canvas(canvasHandle)->drawRect(left, top, right, bottom, *paint);
280}
281
282static void drawRegion(JNIEnv* env, jobject, jlong canvasHandle, jlong regionHandle,
283                       jlong paintHandle) {
284    const SkRegion* region = reinterpret_cast<SkRegion*>(regionHandle);
285    const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
286    get_canvas(canvasHandle)->drawRegion(*region, *paint);
287}
288
289static void drawRoundRect(JNIEnv* env, jobject, jlong canvasHandle, jfloat left, jfloat top,
290                          jfloat right, jfloat bottom, jfloat rx, jfloat ry, jlong paintHandle) {
291    const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
292    get_canvas(canvasHandle)->drawRoundRect(left, top, right, bottom, rx, ry, *paint);
293}
294
295static void drawCircle(JNIEnv* env, jobject, jlong canvasHandle, jfloat cx, jfloat cy,
296                       jfloat radius, jlong paintHandle) {
297    const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
298    get_canvas(canvasHandle)->drawCircle(cx, cy, radius, *paint);
299}
300
301static void drawOval(JNIEnv* env, jobject, jlong canvasHandle, jfloat left, jfloat top,
302                     jfloat right, jfloat bottom, jlong paintHandle) {
303    const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
304    get_canvas(canvasHandle)->drawOval(left, top, right, bottom, *paint);
305}
306
307static void drawArc(JNIEnv* env, jobject, jlong canvasHandle, jfloat left, jfloat top,
308                    jfloat right, jfloat bottom, jfloat startAngle, jfloat sweepAngle,
309                    jboolean useCenter, jlong paintHandle) {
310    const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
311    get_canvas(canvasHandle)->drawArc(left, top, right, bottom, startAngle, sweepAngle,
312                                       useCenter, *paint);
313}
314
315static void drawPath(JNIEnv* env, jobject, jlong canvasHandle, jlong pathHandle,
316                     jlong paintHandle) {
317    const SkPath* path = reinterpret_cast<SkPath*>(pathHandle);
318    const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
319    get_canvas(canvasHandle)->drawPath(*path, *paint);
320}
321
322static void drawVertices(JNIEnv* env, jobject, jlong canvasHandle,
323                         jint modeHandle, jint vertexCount,
324                         jfloatArray jverts, jint vertIndex,
325                         jfloatArray jtexs, jint texIndex,
326                         jintArray jcolors, jint colorIndex,
327                         jshortArray jindices, jint indexIndex,
328                         jint indexCount, jlong paintHandle) {
329    AutoJavaFloatArray  vertA(env, jverts, vertIndex + vertexCount);
330    AutoJavaFloatArray  texA(env, jtexs, texIndex + vertexCount);
331    AutoJavaIntArray    colorA(env, jcolors, colorIndex + vertexCount);
332    AutoJavaShortArray  indexA(env, jindices, indexIndex + indexCount);
333
334    const float* verts = vertA.ptr() + vertIndex;
335    const float* texs = texA.ptr() + vertIndex;
336    const int* colors = NULL;
337    const uint16_t* indices = NULL;
338
339    if (jcolors != NULL) {
340        colors = colorA.ptr() + colorIndex;
341    }
342    if (jindices != NULL) {
343        indices = (const uint16_t*)(indexA.ptr() + indexIndex);
344    }
345
346    SkCanvas::VertexMode mode = static_cast<SkCanvas::VertexMode>(modeHandle);
347    const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
348    get_canvas(canvasHandle)->drawVertices(mode, vertexCount, verts, texs, colors,
349                                           indices, indexCount, *paint);
350}
351
352static void drawNinePatch(JNIEnv* env, jobject, jlong canvasHandle, jlong bitmapHandle,
353        jlong chunkHandle, jfloat left, jfloat top, jfloat right, jfloat bottom,
354        jlong paintHandle, jint dstDensity, jint srcDensity) {
355
356    Canvas* canvas = get_canvas(canvasHandle);
357    Bitmap& bitmap = android::bitmap::toBitmap(env, bitmapHandle);
358    const android::Res_png_9patch* chunk = reinterpret_cast<android::Res_png_9patch*>(chunkHandle);
359    const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
360
361    if (CC_LIKELY(dstDensity == srcDensity || dstDensity == 0 || srcDensity == 0)) {
362        canvas->drawNinePatch(bitmap, *chunk, left, top, right, bottom, paint);
363    } else {
364        canvas->save(SaveFlags::MatrixClip);
365
366        SkScalar scale = dstDensity / (float)srcDensity;
367        canvas->translate(left, top);
368        canvas->scale(scale, scale);
369
370        Paint filteredPaint;
371        if (paint) {
372            filteredPaint = *paint;
373        }
374        filteredPaint.setFilterQuality(kLow_SkFilterQuality);
375
376        canvas->drawNinePatch(bitmap, *chunk, 0, 0, (right-left)/scale, (bottom-top)/scale,
377                &filteredPaint);
378
379        canvas->restore();
380    }
381}
382
383static void drawBitmap(JNIEnv* env, jobject, jlong canvasHandle, jobject jbitmap,
384                       jfloat left, jfloat top, jlong paintHandle, jint canvasDensity,
385                       jint screenDensity, jint bitmapDensity) {
386    Canvas* canvas = get_canvas(canvasHandle);
387    Bitmap& bitmap = android::bitmap::toBitmap(env, jbitmap);
388    const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
389
390    if (canvasDensity == bitmapDensity || canvasDensity == 0 || bitmapDensity == 0) {
391        if (screenDensity != 0 && screenDensity != bitmapDensity) {
392            Paint filteredPaint;
393            if (paint) {
394                filteredPaint = *paint;
395            }
396            filteredPaint.setFilterQuality(kLow_SkFilterQuality);
397            canvas->drawBitmap(bitmap, left, top, &filteredPaint);
398        } else {
399            canvas->drawBitmap(bitmap, left, top, paint);
400        }
401    } else {
402        canvas->save(SaveFlags::MatrixClip);
403        SkScalar scale = canvasDensity / (float)bitmapDensity;
404        canvas->translate(left, top);
405        canvas->scale(scale, scale);
406
407        Paint filteredPaint;
408        if (paint) {
409            filteredPaint = *paint;
410        }
411        filteredPaint.setFilterQuality(kLow_SkFilterQuality);
412
413        canvas->drawBitmap(bitmap, 0, 0, &filteredPaint);
414        canvas->restore();
415    }
416}
417
418static void drawBitmapMatrix(JNIEnv* env, jobject, jlong canvasHandle, jobject jbitmap,
419                             jlong matrixHandle, jlong paintHandle) {
420    const SkMatrix* matrix = reinterpret_cast<SkMatrix*>(matrixHandle);
421    const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
422    Bitmap& bitmap = android::bitmap::toBitmap(env, jbitmap);
423    get_canvas(canvasHandle)->drawBitmap(bitmap, *matrix, paint);
424}
425
426static void drawBitmapRect(JNIEnv* env, jobject, jlong canvasHandle, jobject jbitmap,
427                           float srcLeft, float srcTop, float srcRight, float srcBottom,
428                           float dstLeft, float dstTop, float dstRight, float dstBottom,
429                           jlong paintHandle, jint screenDensity, jint bitmapDensity) {
430    Canvas* canvas = get_canvas(canvasHandle);
431    const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
432
433    Bitmap& bitmap = android::bitmap::toBitmap(env, jbitmap);
434    if (screenDensity != 0 && screenDensity != bitmapDensity) {
435        Paint filteredPaint;
436        if (paint) {
437            filteredPaint = *paint;
438        }
439        filteredPaint.setFilterQuality(kLow_SkFilterQuality);
440        canvas->drawBitmap(bitmap, srcLeft, srcTop, srcRight, srcBottom,
441                           dstLeft, dstTop, dstRight, dstBottom, &filteredPaint);
442    } else {
443        canvas->drawBitmap(bitmap, srcLeft, srcTop, srcRight, srcBottom,
444                           dstLeft, dstTop, dstRight, dstBottom, paint);
445    }
446}
447
448static void drawBitmapArray(JNIEnv* env, jobject, jlong canvasHandle,
449                            jintArray jcolors, jint offset, jint stride,
450                            jfloat x, jfloat y, jint width, jint height,
451                            jboolean hasAlpha, jlong paintHandle) {
452    // Note: If hasAlpha is false, kRGB_565_SkColorType will be used, which will
453    // correct the alphaType to kOpaque_SkAlphaType.
454    SkImageInfo info = SkImageInfo::MakeN32(width, height, kPremul_SkAlphaType,
455            GraphicsJNI::defaultColorSpace());
456    SkBitmap bitmap;
457    bitmap.setInfo(info);
458    sk_sp<Bitmap> androidBitmap = Bitmap::allocateHeapBitmap(&bitmap, NULL);
459    if (!androidBitmap) {
460        return;
461    }
462
463    if (!GraphicsJNI::SetPixels(env, jcolors, offset, stride, 0, 0, width, height, bitmap)) {
464        return;
465    }
466
467    const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
468    get_canvas(canvasHandle)->drawBitmap(*androidBitmap, x, y, paint);
469}
470
471static void drawBitmapMesh(JNIEnv* env, jobject, jlong canvasHandle, jobject jbitmap,
472                           jint meshWidth, jint meshHeight, jfloatArray jverts,
473                           jint vertIndex, jintArray jcolors, jint colorIndex, jlong paintHandle) {
474    const int ptCount = (meshWidth + 1) * (meshHeight + 1);
475    AutoJavaFloatArray vertA(env, jverts, vertIndex + (ptCount << 1));
476    AutoJavaIntArray colorA(env, jcolors, colorIndex + ptCount);
477
478    const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
479    Bitmap& bitmap = android::bitmap::toBitmap(env, jbitmap);
480    get_canvas(canvasHandle)->drawBitmapMesh(bitmap, meshWidth, meshHeight,
481                                             vertA.ptr(), colorA.ptr(), paint);
482}
483
484static void drawTextChars(JNIEnv* env, jobject, jlong canvasHandle, jcharArray text,
485                          jint index, jint count, jfloat x, jfloat y, jint bidiFlags,
486                          jlong paintHandle, jlong typefaceHandle) {
487    Paint* paint = reinterpret_cast<Paint*>(paintHandle);
488    Typeface* typeface = reinterpret_cast<Typeface*>(typefaceHandle);
489    jchar* jchars = env->GetCharArrayElements(text, NULL);
490    get_canvas(canvasHandle)->drawText(jchars + index, 0, count, count, x, y,
491                                       bidiFlags, *paint, typeface);
492    env->ReleaseCharArrayElements(text, jchars, JNI_ABORT);
493}
494
495static void drawTextString(JNIEnv* env, jobject, jlong canvasHandle, jstring text,
496                           jint start, jint end, jfloat x, jfloat y, jint bidiFlags,
497                           jlong paintHandle, jlong typefaceHandle) {
498    Paint* paint = reinterpret_cast<Paint*>(paintHandle);
499    Typeface* typeface = reinterpret_cast<Typeface*>(typefaceHandle);
500    const int count = end - start;
501    const jchar* jchars = env->GetStringChars(text, NULL);
502    get_canvas(canvasHandle)->drawText(jchars + start, 0, count, count, x, y,
503                                       bidiFlags, *paint, typeface);
504    env->ReleaseStringChars(text, jchars);
505}
506
507static void drawTextRunChars(JNIEnv* env, jobject, jlong canvasHandle, jcharArray text, jint index,
508                             jint count, jint contextIndex, jint contextCount, jfloat x, jfloat y,
509                             jboolean isRtl, jlong paintHandle, jlong typefaceHandle) {
510    Paint* paint = reinterpret_cast<Paint*>(paintHandle);
511    Typeface* typeface = reinterpret_cast<Typeface*>(typefaceHandle);
512
513    const int bidiFlags = isRtl ? minikin::kBidi_Force_RTL : minikin::kBidi_Force_LTR;
514    jchar* jchars = env->GetCharArrayElements(text, NULL);
515    get_canvas(canvasHandle)->drawText(jchars + contextIndex, index - contextIndex, count,
516                                       contextCount, x, y, bidiFlags, *paint, typeface);
517    env->ReleaseCharArrayElements(text, jchars, JNI_ABORT);
518}
519
520static void drawTextRunString(JNIEnv* env, jobject obj, jlong canvasHandle, jstring text,
521                              jint start, jint end, jint contextStart, jint contextEnd,
522                              jfloat x, jfloat y, jboolean isRtl, jlong paintHandle,
523                              jlong typefaceHandle) {
524    Paint* paint = reinterpret_cast<Paint*>(paintHandle);
525    Typeface* typeface = reinterpret_cast<Typeface*>(typefaceHandle);
526
527    int bidiFlags = isRtl ? minikin::kBidi_Force_RTL : minikin::kBidi_Force_LTR;
528    jint count = end - start;
529    jint contextCount = contextEnd - contextStart;
530    const jchar* jchars = env->GetStringChars(text, NULL);
531    get_canvas(canvasHandle)->drawText(jchars + contextStart, start - contextStart, count,
532                                       contextCount, x, y, bidiFlags, *paint, typeface);
533    env->ReleaseStringChars(text, jchars);
534}
535
536static void drawTextOnPathChars(JNIEnv* env, jobject, jlong canvasHandle, jcharArray text,
537                                jint index, jint count, jlong pathHandle, jfloat hOffset,
538                                jfloat vOffset, jint bidiFlags, jlong paintHandle,
539                                jlong typefaceHandle) {
540    SkPath* path = reinterpret_cast<SkPath*>(pathHandle);
541    Paint* paint = reinterpret_cast<Paint*>(paintHandle);
542    Typeface* typeface = reinterpret_cast<Typeface*>(typefaceHandle);
543
544    jchar* jchars = env->GetCharArrayElements(text, NULL);
545
546    get_canvas(canvasHandle)->drawTextOnPath(jchars + index, count, bidiFlags, *path,
547                   hOffset, vOffset, *paint, typeface);
548
549    env->ReleaseCharArrayElements(text, jchars, 0);
550}
551
552static void drawTextOnPathString(JNIEnv* env, jobject, jlong canvasHandle, jstring text,
553                                 jlong pathHandle, jfloat hOffset, jfloat vOffset,
554                                 jint bidiFlags, jlong paintHandle, jlong typefaceHandle) {
555    SkPath* path = reinterpret_cast<SkPath*>(pathHandle);
556    Paint* paint = reinterpret_cast<Paint*>(paintHandle);
557    Typeface* typeface = reinterpret_cast<Typeface*>(typefaceHandle);
558
559    const jchar* jchars = env->GetStringChars(text, NULL);
560    int count = env->GetStringLength(text);
561
562    get_canvas(canvasHandle)->drawTextOnPath(jchars, count, bidiFlags, *path,
563                   hOffset, vOffset, *paint, typeface);
564
565    env->ReleaseStringChars(text, jchars);
566}
567
568static void setDrawFilter(JNIEnv* env, jobject, jlong canvasHandle, jlong filterHandle) {
569    get_canvas(canvasHandle)->setDrawFilter(reinterpret_cast<SkDrawFilter*>(filterHandle));
570}
571
572static void freeCaches(JNIEnv* env, jobject) {
573    SkGraphics::PurgeFontCache();
574}
575
576static void freeTextLayoutCaches(JNIEnv* env, jobject) {
577    minikin::Layout::purgeCaches();
578}
579
580}; // namespace CanvasJNI
581
582static const JNINativeMethod gMethods[] = {
583    {"nGetNativeFinalizer", "()J", (void*) CanvasJNI::getNativeFinalizer},
584    {"nInitRaster", "(Landroid/graphics/Bitmap;)J", (void*) CanvasJNI::initRaster},
585    {"nFreeCaches", "()V", (void*) CanvasJNI::freeCaches},
586    {"nFreeTextLayoutCaches", "()V", (void*) CanvasJNI::freeTextLayoutCaches},
587
588    // ------------ @FastNative ----------------
589    {"nSetBitmap", "(JLandroid/graphics/Bitmap;)V", (void*) CanvasJNI::setBitmap},
590    {"nIsOpaque","(J)Z", (void*) CanvasJNI::isOpaque},
591    {"nGetWidth","(J)I", (void*) CanvasJNI::getWidth},
592    {"nGetHeight","(J)I", (void*) CanvasJNI::getHeight},
593    {"nSetHighContrastText","(JZ)V", (void*) CanvasJNI::setHighContrastText},
594    {"nSave","(JI)I", (void*) CanvasJNI::save},
595    {"nSaveLayer","(JFFFFJI)I", (void*) CanvasJNI::saveLayer},
596    {"nSaveLayerAlpha","(JFFFFII)I", (void*) CanvasJNI::saveLayerAlpha},
597    {"nGetSaveCount","(J)I", (void*) CanvasJNI::getSaveCount},
598    {"nRestore","(JZ)V", (void*) CanvasJNI::restore},
599    {"nRestoreToCount","(JIZ)V", (void*) CanvasJNI::restoreToCount},
600    {"nGetCTM", "(JJ)V", (void*)CanvasJNI::getCTM},
601    {"nSetMatrix","(JJ)V", (void*) CanvasJNI::setMatrix},
602    {"nConcat","(JJ)V", (void*) CanvasJNI::concat},
603    {"nRotate","(JF)V", (void*) CanvasJNI::rotate},
604    {"nScale","(JFF)V", (void*) CanvasJNI::scale},
605    {"nSkew","(JFF)V", (void*) CanvasJNI::skew},
606    {"nTranslate","(JFF)V", (void*) CanvasJNI::translate},
607    {"nGetClipBounds","(JLandroid/graphics/Rect;)Z", (void*) CanvasJNI::getClipBounds},
608    {"nQuickReject","(JJ)Z", (void*) CanvasJNI::quickRejectPath},
609    {"nQuickReject","(JFFFF)Z", (void*)CanvasJNI::quickRejectRect},
610    {"nClipRect","(JFFFFI)Z", (void*) CanvasJNI::clipRect},
611    {"nClipPath","(JJI)Z", (void*) CanvasJNI::clipPath},
612    {"nSetDrawFilter", "(JJ)V", (void*) CanvasJNI::setDrawFilter},
613};
614
615// If called from Canvas these are regular JNI
616// If called from DisplayListCanvas they are @FastNative
617static const JNINativeMethod gDrawMethods[] = {
618    {"nDrawColor","(JII)V", (void*) CanvasJNI::drawColor},
619    {"nDrawPaint","(JJ)V", (void*) CanvasJNI::drawPaint},
620    {"nDrawPoint", "(JFFJ)V", (void*) CanvasJNI::drawPoint},
621    {"nDrawPoints", "(J[FIIJ)V", (void*) CanvasJNI::drawPoints},
622    {"nDrawLine", "(JFFFFJ)V", (void*) CanvasJNI::drawLine},
623    {"nDrawLines", "(J[FIIJ)V", (void*) CanvasJNI::drawLines},
624    {"nDrawRect","(JFFFFJ)V", (void*) CanvasJNI::drawRect},
625    {"nDrawRegion", "(JJJ)V", (void*) CanvasJNI::drawRegion },
626    {"nDrawRoundRect","(JFFFFFFJ)V", (void*) CanvasJNI::drawRoundRect},
627    {"nDrawCircle","(JFFFJ)V", (void*) CanvasJNI::drawCircle},
628    {"nDrawOval","(JFFFFJ)V", (void*) CanvasJNI::drawOval},
629    {"nDrawArc","(JFFFFFFZJ)V", (void*) CanvasJNI::drawArc},
630    {"nDrawPath","(JJJ)V", (void*) CanvasJNI::drawPath},
631    {"nDrawVertices", "(JII[FI[FI[II[SIIJ)V", (void*)CanvasJNI::drawVertices},
632    {"nDrawNinePatch", "(JJJFFFFJII)V", (void*)CanvasJNI::drawNinePatch},
633    {"nDrawBitmapMatrix", "(JLandroid/graphics/Bitmap;JJ)V", (void*)CanvasJNI::drawBitmapMatrix},
634    {"nDrawBitmapMesh", "(JLandroid/graphics/Bitmap;II[FI[IIJ)V", (void*)CanvasJNI::drawBitmapMesh},
635    {"nDrawBitmap","(JLandroid/graphics/Bitmap;FFJIII)V", (void*) CanvasJNI::drawBitmap},
636    {"nDrawBitmap","(JLandroid/graphics/Bitmap;FFFFFFFFJII)V", (void*) CanvasJNI::drawBitmapRect},
637    {"nDrawBitmap", "(J[IIIFFIIZJ)V", (void*)CanvasJNI::drawBitmapArray},
638    {"nDrawText","(J[CIIFFIJJ)V", (void*) CanvasJNI::drawTextChars},
639    {"nDrawText","(JLjava/lang/String;IIFFIJJ)V", (void*) CanvasJNI::drawTextString},
640    {"nDrawTextRun","(J[CIIIIFFZJJ)V", (void*) CanvasJNI::drawTextRunChars},
641    {"nDrawTextRun","(JLjava/lang/String;IIIIFFZJJ)V", (void*) CanvasJNI::drawTextRunString},
642    {"nDrawTextOnPath","(J[CIIJFFIJJ)V", (void*) CanvasJNI::drawTextOnPathChars},
643    {"nDrawTextOnPath","(JLjava/lang/String;JFFIJJ)V", (void*) CanvasJNI::drawTextOnPathString},
644};
645
646int register_android_graphics_Canvas(JNIEnv* env) {
647    int ret = 0;
648    ret |= RegisterMethodsOrDie(env, "android/graphics/Canvas", gMethods, NELEM(gMethods));
649    ret |= RegisterMethodsOrDie(env, "android/graphics/BaseCanvas", gDrawMethods, NELEM(gDrawMethods));
650    ret |= RegisterMethodsOrDie(env, "android/view/RecordingCanvas", gDrawMethods, NELEM(gDrawMethods));
651    return ret;
652
653}
654
655}; // namespace android
656