android_graphics_Canvas.cpp revision b57dd722f1dc0663417da37d3a82f8283ad3c982
1500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev/*
2500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev * Copyright (C) 2014 The Android Open Source Project
3500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev *
4500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev * Licensed under the Apache License, Version 2.0 (the "License");
5500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev * you may not use this file except in compliance with the License.
6500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev * You may obtain a copy of the License at
7500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev *
8500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev *      http://www.apache.org/licenses/LICENSE-2.0
9500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev *
10500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev * Unless required by applicable law or agreed to in writing, software
11500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev * distributed under the License is distributed on an "AS IS" BASIS,
12500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev * See the License for the specific language governing permissions and
14500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev * limitations under the License.
15500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev */
16500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev
17500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev#include "jni.h"
18500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev#include "GraphicsJNI.h"
19500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev#include "core_jni_helpers.h"
20500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev
21500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev#include <Canvas.h>
22500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev#include "SkDrawFilter.h"
23500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev#include "SkGraphics.h"
24500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev#include "Paint.h"
25500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev#include "TypefaceImpl.h"
26500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev
27500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev#include "MinikinUtils.h"
28500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev
29500a0c30d4dcd012218c3e44a62926a1c34a259fStan Ilievnamespace android {
30500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev
31500a0c30d4dcd012218c3e44a62926a1c34a259fStan Ilievnamespace CanvasJNI {
32500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev
33500a0c30d4dcd012218c3e44a62926a1c34a259fStan Ilievstatic Canvas* get_canvas(jlong canvasHandle) {
34500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev    return reinterpret_cast<Canvas*>(canvasHandle);
35500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev}
36500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev
37500a0c30d4dcd012218c3e44a62926a1c34a259fStan Ilievstatic void finalizer(JNIEnv* env, jobject clazz, jlong canvasHandle) {
38500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev    delete get_canvas(canvasHandle);
39500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev}
40500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev
41500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev// Native wrapper constructor used by Canvas(Bitmap)
42500a0c30d4dcd012218c3e44a62926a1c34a259fStan Ilievstatic jlong initRaster(JNIEnv* env, jobject, jobject jbitmap) {
43500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev    SkBitmap bitmap;
44500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev    if (jbitmap != NULL) {
45500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev        GraphicsJNI::getSkBitmap(env, jbitmap, &bitmap);
46500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev    }
47500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev    return reinterpret_cast<jlong>(Canvas::create_canvas(bitmap));
48500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev}
49b7d34b64dd32e3d84bd43344c9c3d9ad098129afDerek Sollenberger
50b7d34b64dd32e3d84bd43344c9c3d9ad098129afDerek Sollenberger// Set the given bitmap as the new draw target (wrapped in a new SkCanvas),
51189e87498f666e94dc8c8201e7bac56bb09b9251Derek Sollenberger// optionally copying canvas matrix & clip state.
52189e87498f666e94dc8c8201e7bac56bb09b9251Derek Sollenbergerstatic void setBitmap(JNIEnv* env, jobject, jlong canvasHandle, jobject jbitmap) {
53189e87498f666e94dc8c8201e7bac56bb09b9251Derek Sollenberger    SkBitmap bitmap;
54189e87498f666e94dc8c8201e7bac56bb09b9251Derek Sollenberger    if (jbitmap != NULL) {
55189e87498f666e94dc8c8201e7bac56bb09b9251Derek Sollenberger        GraphicsJNI::getSkBitmap(env, jbitmap, &bitmap);
56b7d34b64dd32e3d84bd43344c9c3d9ad098129afDerek Sollenberger    }
57b7d34b64dd32e3d84bd43344c9c3d9ad098129afDerek Sollenberger    get_canvas(canvasHandle)->setBitmap(bitmap);
58b7d34b64dd32e3d84bd43344c9c3d9ad098129afDerek Sollenberger}
59b7d34b64dd32e3d84bd43344c9c3d9ad098129afDerek Sollenberger
60b7d34b64dd32e3d84bd43344c9c3d9ad098129afDerek Sollenbergerstatic jboolean isOpaque(JNIEnv*, jobject, jlong canvasHandle) {
61b7d34b64dd32e3d84bd43344c9c3d9ad098129afDerek Sollenberger    return get_canvas(canvasHandle)->isOpaque() ? JNI_TRUE : JNI_FALSE;
62b7d34b64dd32e3d84bd43344c9c3d9ad098129afDerek Sollenberger}
63b7d34b64dd32e3d84bd43344c9c3d9ad098129afDerek Sollenberger
64b7d34b64dd32e3d84bd43344c9c3d9ad098129afDerek Sollenbergerstatic jint getWidth(JNIEnv*, jobject, jlong canvasHandle) {
65b7d34b64dd32e3d84bd43344c9c3d9ad098129afDerek Sollenberger    return static_cast<jint>(get_canvas(canvasHandle)->width());
66b7d34b64dd32e3d84bd43344c9c3d9ad098129afDerek Sollenberger}
67500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev
68500a0c30d4dcd012218c3e44a62926a1c34a259fStan Ilievstatic jint getHeight(JNIEnv*, jobject, jlong canvasHandle) {
69500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev    return static_cast<jint>(get_canvas(canvasHandle)->height());
70500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev}
71500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev
72500a0c30d4dcd012218c3e44a62926a1c34a259fStan Ilievstatic jint getSaveCount(JNIEnv*, jobject, jlong canvasHandle) {
73500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev    return static_cast<jint>(get_canvas(canvasHandle)->getSaveCount());
74500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev}
75500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev
76500a0c30d4dcd012218c3e44a62926a1c34a259fStan Ilievstatic jint save(JNIEnv*, jobject, jlong canvasHandle, jint flagsHandle) {
77500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev    SkCanvas::SaveFlags flags = static_cast<SkCanvas::SaveFlags>(flagsHandle);
78500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev    return static_cast<jint>(get_canvas(canvasHandle)->save(flags));
79500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev}
80500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev
81500a0c30d4dcd012218c3e44a62926a1c34a259fStan Ilievstatic jint saveLayer(JNIEnv* env, jobject, jlong canvasHandle, jfloat l, jfloat t,
82500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev                      jfloat r, jfloat b, jlong paintHandle, jint flagsHandle) {
83500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev    Paint* paint  = reinterpret_cast<Paint*>(paintHandle);
84500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev    SkCanvas::SaveFlags flags = static_cast<SkCanvas::SaveFlags>(flagsHandle);
85500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev    return static_cast<jint>(get_canvas(canvasHandle)->saveLayer(l, t, r, b, paint, flags));
86500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev}
87500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev
88500a0c30d4dcd012218c3e44a62926a1c34a259fStan Ilievstatic jint saveLayerAlpha(JNIEnv* env, jobject, jlong canvasHandle, jfloat l, jfloat t,
89500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev                           jfloat r, jfloat b, jint alpha, jint flagsHandle) {
90500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev    SkCanvas::SaveFlags flags = static_cast<SkCanvas::SaveFlags>(flagsHandle);
91500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev    return static_cast<jint>(get_canvas(canvasHandle)->saveLayerAlpha(l, t, r, b, alpha, flags));
92500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev}
93500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev
94500a0c30d4dcd012218c3e44a62926a1c34a259fStan Ilievstatic void restore(JNIEnv* env, jobject, jlong canvasHandle, jboolean throwOnUnderflow) {
95500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev    Canvas* canvas = get_canvas(canvasHandle);
96500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev    if (canvas->getSaveCount() <= 1) {  // cannot restore anymore
97500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev        if (throwOnUnderflow) {
98500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev            doThrowISE(env, "Underflow in restore - more restores than saves");
99500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev        }
100500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev        return; // compat behavior - return without throwing
101500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev    }
102500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev    canvas->restore();
103500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev}
104500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev
105500a0c30d4dcd012218c3e44a62926a1c34a259fStan Ilievstatic void restoreToCount(JNIEnv* env, jobject, jlong canvasHandle, jint restoreCount,
106500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev        jboolean throwOnUnderflow) {
107500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev    Canvas* canvas = get_canvas(canvasHandle);
108500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev    if (restoreCount < 1 || restoreCount > canvas->getSaveCount()) {
109500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev        if (throwOnUnderflow) {
110500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev            doThrowIAE(env, "Underflow in restoreToCount - more restores than saves");
111500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev            return;
112500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev        }
113500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev        restoreCount = 1; // compat behavior - restore as far as possible
114500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev    }
115500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev    canvas->restoreToCount(restoreCount);
116500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev}
117500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev
118500a0c30d4dcd012218c3e44a62926a1c34a259fStan Ilievstatic void getCTM(JNIEnv* env, jobject, jlong canvasHandle, jlong matrixHandle) {
119500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev    SkMatrix* matrix = reinterpret_cast<SkMatrix*>(matrixHandle);
120500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev    get_canvas(canvasHandle)->getMatrix(matrix);
121500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev}
122500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev
123500a0c30d4dcd012218c3e44a62926a1c34a259fStan Ilievstatic void setMatrix(JNIEnv* env, jobject, jlong canvasHandle, jlong matrixHandle) {
124500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev    const SkMatrix* matrix = reinterpret_cast<SkMatrix*>(matrixHandle);
125500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev    get_canvas(canvasHandle)->setMatrix(matrix ? *matrix : SkMatrix::I());
126500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev}
127500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev
128500a0c30d4dcd012218c3e44a62926a1c34a259fStan Ilievstatic void concat(JNIEnv* env, jobject, jlong canvasHandle, jlong matrixHandle) {
129500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev    const SkMatrix* matrix = reinterpret_cast<SkMatrix*>(matrixHandle);
130500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev    get_canvas(canvasHandle)->concat(*matrix);
131500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev}
132500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev
133500a0c30d4dcd012218c3e44a62926a1c34a259fStan Ilievstatic void rotate(JNIEnv*, jobject, jlong canvasHandle, jfloat degrees) {
134500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev    get_canvas(canvasHandle)->rotate(degrees);
135500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev}
136500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev
137500a0c30d4dcd012218c3e44a62926a1c34a259fStan Ilievstatic void scale(JNIEnv*, jobject, jlong canvasHandle, jfloat sx, jfloat sy) {
138500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev    get_canvas(canvasHandle)->scale(sx, sy);
139500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev}
140500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev
141500a0c30d4dcd012218c3e44a62926a1c34a259fStan Ilievstatic void skew(JNIEnv*, jobject, jlong canvasHandle, jfloat sx, jfloat sy) {
142500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev    get_canvas(canvasHandle)->skew(sx, sy);
143500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev}
144500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev
145500a0c30d4dcd012218c3e44a62926a1c34a259fStan Ilievstatic void translate(JNIEnv*, jobject, jlong canvasHandle, jfloat dx, jfloat dy) {
146500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev    get_canvas(canvasHandle)->translate(dx, dy);
147500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev}
148500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev
149500a0c30d4dcd012218c3e44a62926a1c34a259fStan Ilievstatic jboolean getClipBounds(JNIEnv* env, jobject, jlong canvasHandle, jobject bounds) {
150500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev    SkRect   r;
151500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev    SkIRect ir;
152500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev    bool result = get_canvas(canvasHandle)->getClipBounds(&r);
153500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev
154500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev    if (!result) {
155500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev        r.setEmpty();
156500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev    }
157500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev    r.round(&ir);
158500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev
159500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev    (void)GraphicsJNI::irect_to_jrect(ir, env, bounds);
160500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev    return result ? JNI_TRUE : JNI_FALSE;
161500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev}
162500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev
163500a0c30d4dcd012218c3e44a62926a1c34a259fStan Ilievstatic jboolean quickRejectRect(JNIEnv* env, jobject, jlong canvasHandle,
164500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev                                jfloat left, jfloat top, jfloat right, jfloat bottom) {
165500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev    bool result = get_canvas(canvasHandle)->quickRejectRect(left, top, right, bottom);
166500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev    return result ? JNI_TRUE : JNI_FALSE;
167500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev}
168500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev
169500a0c30d4dcd012218c3e44a62926a1c34a259fStan Ilievstatic jboolean quickRejectPath(JNIEnv* env, jobject, jlong canvasHandle, jlong pathHandle) {
170500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev    SkPath* path = reinterpret_cast<SkPath*>(pathHandle);
171500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev    bool result = get_canvas(canvasHandle)->quickRejectPath(*path);
172500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev    return result ? JNI_TRUE : JNI_FALSE;
173500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev}
174500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev
175500a0c30d4dcd012218c3e44a62926a1c34a259fStan Ilievstatic jboolean clipRect(JNIEnv*, jobject, jlong canvasHandle, jfloat l, jfloat t,
176500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev                         jfloat r, jfloat b, jint opHandle) {
177500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev    SkRegion::Op op = static_cast<SkRegion::Op>(opHandle);
178500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev    bool nonEmptyClip = get_canvas(canvasHandle)->clipRect(l, t, r, b, op);
179500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev    return nonEmptyClip ? JNI_TRUE : JNI_FALSE;
180500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev}
181500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev
182500a0c30d4dcd012218c3e44a62926a1c34a259fStan Ilievstatic jboolean clipPath(JNIEnv* env, jobject, jlong canvasHandle, jlong pathHandle,
183500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev                         jint opHandle) {
184500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev    SkPath* path = reinterpret_cast<SkPath*>(pathHandle);
185500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev    SkRegion::Op op = static_cast<SkRegion::Op>(opHandle);
186500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev    bool nonEmptyClip = get_canvas(canvasHandle)->clipPath(path, op);
187500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev    return nonEmptyClip ? JNI_TRUE : JNI_FALSE;
188500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev}
189500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev
190500a0c30d4dcd012218c3e44a62926a1c34a259fStan Ilievstatic jboolean clipRegion(JNIEnv* env, jobject, jlong canvasHandle, jlong deviceRgnHandle,
191500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev                           jint opHandle) {
192500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev    SkRegion* deviceRgn = reinterpret_cast<SkRegion*>(deviceRgnHandle);
193500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev    SkRegion::Op op = static_cast<SkRegion::Op>(opHandle);
194500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev    bool nonEmptyClip = get_canvas(canvasHandle)->clipRegion(deviceRgn, op);
195500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev    return nonEmptyClip ? JNI_TRUE : JNI_FALSE;
196500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev}
197500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev
198500a0c30d4dcd012218c3e44a62926a1c34a259fStan Ilievstatic void drawColor(JNIEnv* env, jobject, jlong canvasHandle, jint color, jint modeHandle) {
199500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev    SkXfermode::Mode mode = static_cast<SkXfermode::Mode>(modeHandle);
200500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev    get_canvas(canvasHandle)->drawColor(color, mode);
201500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev}
202500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev
203500a0c30d4dcd012218c3e44a62926a1c34a259fStan Ilievstatic void drawPaint(JNIEnv* env, jobject, jlong canvasHandle, jlong paintHandle) {
204500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev    Paint* paint = reinterpret_cast<Paint*>(paintHandle);
205500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev    get_canvas(canvasHandle)->drawPaint(*paint);
206500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev}
207500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev
208500a0c30d4dcd012218c3e44a62926a1c34a259fStan Ilievstatic void drawPoint(JNIEnv*, jobject, jlong canvasHandle, jfloat x, jfloat y,
209500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev                      jlong paintHandle) {
210500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev    const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
211500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev    get_canvas(canvasHandle)->drawPoint(x, y, *paint);
212500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev}
213500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev
214500a0c30d4dcd012218c3e44a62926a1c34a259fStan Ilievstatic void drawPoints(JNIEnv* env, jobject, jlong canvasHandle, jfloatArray jptsArray,
215500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev                       jint offset, jint count, jlong paintHandle) {
216500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev    NPE_CHECK_RETURN_VOID(env, jptsArray);
217500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev    AutoJavaFloatArray autoPts(env, jptsArray);
218500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev    float* floats = autoPts.ptr();
219500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev    const int length = autoPts.length();
220500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev
221500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev    if ((offset | count) < 0 || offset + count > length) {
222500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev        doThrowAIOOBE(env);
223500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev        return;
224500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev    }
225500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev
226500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev    const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
227500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev    get_canvas(canvasHandle)->drawPoints(floats + offset, count, *paint);
228500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev}
229500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev
230500a0c30d4dcd012218c3e44a62926a1c34a259fStan Ilievstatic void drawLine(JNIEnv* env, jobject, jlong canvasHandle, jfloat startX, jfloat startY,
231500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev                     jfloat stopX, jfloat stopY, jlong paintHandle) {
232500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev    Paint* paint = reinterpret_cast<Paint*>(paintHandle);
233500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev    get_canvas(canvasHandle)->drawLine(startX, startY, stopX, stopY, *paint);
234500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev}
235500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev
236500a0c30d4dcd012218c3e44a62926a1c34a259fStan Ilievstatic void drawLines(JNIEnv* env, jobject, jlong canvasHandle, jfloatArray jptsArray,
237500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev                      jint offset, jint count, jlong paintHandle) {
238500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev    NPE_CHECK_RETURN_VOID(env, jptsArray);
239500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev    AutoJavaFloatArray autoPts(env, jptsArray);
240500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev    float* floats = autoPts.ptr();
241500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev    const int length = autoPts.length();
242500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev
243500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev    if ((offset | count) < 0 || offset + count > length) {
244500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev        doThrowAIOOBE(env);
245500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev        return;
246500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev    }
247500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev
248500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev    const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
249500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev    get_canvas(canvasHandle)->drawLines(floats + offset, count, *paint);
250500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev}
251500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev
252500a0c30d4dcd012218c3e44a62926a1c34a259fStan Ilievstatic void drawRect(JNIEnv* env, jobject, jlong canvasHandle, jfloat left, jfloat top,
253500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev                     jfloat right, jfloat bottom, jlong paintHandle) {
254500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev    const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
255500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev    get_canvas(canvasHandle)->drawRect(left, top, right, bottom, *paint);
256500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev}
257500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev
258500a0c30d4dcd012218c3e44a62926a1c34a259fStan Ilievstatic void drawRoundRect(JNIEnv* env, jobject, jlong canvasHandle, jfloat left, jfloat top,
259500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev                          jfloat right, jfloat bottom, jfloat rx, jfloat ry, jlong paintHandle) {
260500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev    const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
261500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev    get_canvas(canvasHandle)->drawRoundRect(left, top, right, bottom, rx, ry, *paint);
262500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev}
263500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev
264500a0c30d4dcd012218c3e44a62926a1c34a259fStan Ilievstatic void drawCircle(JNIEnv* env, jobject, jlong canvasHandle, jfloat cx, jfloat cy,
265500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev                       jfloat radius, jlong paintHandle) {
266500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev    const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
267500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev    get_canvas(canvasHandle)->drawCircle(cx, cy, radius, *paint);
268500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev}
269500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev
270500a0c30d4dcd012218c3e44a62926a1c34a259fStan Ilievstatic void drawOval(JNIEnv* env, jobject, jlong canvasHandle, jfloat left, jfloat top,
2714bda6bfaa6b8cb775f18f2453720d05f4cb29152Matt Sarett                     jfloat right, jfloat bottom, jlong paintHandle) {
2724bda6bfaa6b8cb775f18f2453720d05f4cb29152Matt Sarett    const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
2734bda6bfaa6b8cb775f18f2453720d05f4cb29152Matt Sarett    get_canvas(canvasHandle)->drawOval(left, top, right, bottom, *paint);
2744bda6bfaa6b8cb775f18f2453720d05f4cb29152Matt Sarett}
2754bda6bfaa6b8cb775f18f2453720d05f4cb29152Matt Sarett
2764bda6bfaa6b8cb775f18f2453720d05f4cb29152Matt Sarettstatic void drawArc(JNIEnv* env, jobject, jlong canvasHandle, jfloat left, jfloat top,
2774bda6bfaa6b8cb775f18f2453720d05f4cb29152Matt Sarett                    jfloat right, jfloat bottom, jfloat startAngle, jfloat sweepAngle,
2784bda6bfaa6b8cb775f18f2453720d05f4cb29152Matt Sarett                    jboolean useCenter, jlong paintHandle) {
2794bda6bfaa6b8cb775f18f2453720d05f4cb29152Matt Sarett    const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
2804bda6bfaa6b8cb775f18f2453720d05f4cb29152Matt Sarett    get_canvas(canvasHandle)->drawArc(left, top, right, bottom, startAngle, sweepAngle,
2814bda6bfaa6b8cb775f18f2453720d05f4cb29152Matt Sarett                                       useCenter, *paint);
2824bda6bfaa6b8cb775f18f2453720d05f4cb29152Matt Sarett}
2834bda6bfaa6b8cb775f18f2453720d05f4cb29152Matt Sarett
2844bda6bfaa6b8cb775f18f2453720d05f4cb29152Matt Sarettstatic void drawPath(JNIEnv* env, jobject, jlong canvasHandle, jlong pathHandle,
285500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev                     jlong paintHandle) {
286500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev    const SkPath* path = reinterpret_cast<SkPath*>(pathHandle);
287500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev    const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
288    get_canvas(canvasHandle)->drawPath(*path, *paint);
289}
290
291static void drawVertices(JNIEnv* env, jobject, jlong canvasHandle,
292                         jint modeHandle, jint vertexCount,
293                         jfloatArray jverts, jint vertIndex,
294                         jfloatArray jtexs, jint texIndex,
295                         jintArray jcolors, jint colorIndex,
296                         jshortArray jindices, jint indexIndex,
297                         jint indexCount, jlong paintHandle) {
298    AutoJavaFloatArray  vertA(env, jverts, vertIndex + vertexCount);
299    AutoJavaFloatArray  texA(env, jtexs, texIndex + vertexCount);
300    AutoJavaIntArray    colorA(env, jcolors, colorIndex + vertexCount);
301    AutoJavaShortArray  indexA(env, jindices, indexIndex + indexCount);
302
303    const float* verts = vertA.ptr() + vertIndex;
304    const float* texs = texA.ptr() + vertIndex;
305    const int* colors = NULL;
306    const uint16_t* indices = NULL;
307
308    if (jcolors != NULL) {
309        colors = colorA.ptr() + colorIndex;
310    }
311    if (jindices != NULL) {
312        indices = (const uint16_t*)(indexA.ptr() + indexIndex);
313    }
314
315    SkCanvas::VertexMode mode = static_cast<SkCanvas::VertexMode>(modeHandle);
316    const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
317    get_canvas(canvasHandle)->drawVertices(mode, vertexCount, verts, texs, colors,
318                                           indices, indexCount, *paint);
319}
320
321static void drawBitmap(JNIEnv* env, jobject jcanvas, jlong canvasHandle, jobject jbitmap,
322                       jfloat left, jfloat top, jlong paintHandle, jint canvasDensity,
323                       jint screenDensity, jint bitmapDensity) {
324    Canvas* canvas = get_canvas(canvasHandle);
325    SkBitmap bitmap;
326    GraphicsJNI::getSkBitmap(env, jbitmap, &bitmap);
327    const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
328
329    if (canvasDensity == bitmapDensity || canvasDensity == 0 || bitmapDensity == 0) {
330        if (screenDensity != 0 && screenDensity != bitmapDensity) {
331            Paint filteredPaint;
332            if (paint) {
333                filteredPaint = *paint;
334            }
335            filteredPaint.setFilterQuality(kLow_SkFilterQuality);
336            canvas->drawBitmap(bitmap, left, top, &filteredPaint);
337        } else {
338            canvas->drawBitmap(bitmap, left, top, paint);
339        }
340    } else {
341        canvas->save(SkCanvas::kMatrixClip_SaveFlag);
342        SkScalar scale = canvasDensity / (float)bitmapDensity;
343        canvas->translate(left, top);
344        canvas->scale(scale, scale);
345
346        Paint filteredPaint;
347        if (paint) {
348            filteredPaint = *paint;
349        }
350        filteredPaint.setFilterQuality(kLow_SkFilterQuality);
351
352        canvas->drawBitmap(bitmap, 0, 0, &filteredPaint);
353        canvas->restore();
354    }
355}
356
357static void drawBitmapMatrix(JNIEnv* env, jobject, jlong canvasHandle, jobject jbitmap,
358                             jlong matrixHandle, jlong paintHandle) {
359    const SkMatrix* matrix = reinterpret_cast<SkMatrix*>(matrixHandle);
360    const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
361    SkBitmap bitmap;
362    GraphicsJNI::getSkBitmap(env, jbitmap, &bitmap);
363    get_canvas(canvasHandle)->drawBitmap(bitmap, *matrix, paint);
364}
365
366static void drawBitmapRect(JNIEnv* env, jobject, jlong canvasHandle, jobject jbitmap,
367                           float srcLeft, float srcTop, float srcRight, float srcBottom,
368                           float dstLeft, float dstTop, float dstRight, float dstBottom,
369                           jlong paintHandle, jint screenDensity, jint bitmapDensity) {
370    Canvas* canvas = get_canvas(canvasHandle);
371    const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
372
373    SkBitmap bitmap;
374    GraphicsJNI::getSkBitmap(env, jbitmap, &bitmap);
375    if (screenDensity != 0 && screenDensity != bitmapDensity) {
376        Paint filteredPaint;
377        if (paint) {
378            filteredPaint = *paint;
379        }
380        filteredPaint.setFilterQuality(kLow_SkFilterQuality);
381        canvas->drawBitmap(bitmap, srcLeft, srcTop, srcRight, srcBottom,
382                           dstLeft, dstTop, dstRight, dstBottom, &filteredPaint);
383    } else {
384        canvas->drawBitmap(bitmap, srcLeft, srcTop, srcRight, srcBottom,
385                           dstLeft, dstTop, dstRight, dstBottom, paint);
386    }
387}
388
389static void drawBitmapArray(JNIEnv* env, jobject, jlong canvasHandle,
390                            jintArray jcolors, jint offset, jint stride,
391                            jfloat x, jfloat y, jint width, jint height,
392                            jboolean hasAlpha, jlong paintHandle) {
393    // Note: If hasAlpha is false, kRGB_565_SkColorType will be used, which will
394    // correct the alphaType to kOpaque_SkAlphaType.
395    SkImageInfo info = SkImageInfo::Make(width, height,
396                           hasAlpha ? kN32_SkColorType : kRGB_565_SkColorType,
397                           kPremul_SkAlphaType);
398    SkBitmap bitmap;
399    bitmap.setInfo(info);
400    if (!GraphicsJNI::allocatePixels(env, &bitmap, NULL)) {
401        return;
402    }
403
404    if (!GraphicsJNI::SetPixels(env, jcolors, offset, stride, 0, 0, width, height, bitmap)) {
405        return;
406    }
407
408    const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
409    get_canvas(canvasHandle)->drawBitmap(bitmap, x, y, paint);
410}
411
412static void drawBitmapMesh(JNIEnv* env, jobject, jlong canvasHandle, jobject jbitmap,
413                           jint meshWidth, jint meshHeight, jfloatArray jverts,
414                           jint vertIndex, jintArray jcolors, jint colorIndex, jlong paintHandle) {
415    const int ptCount = (meshWidth + 1) * (meshHeight + 1);
416    AutoJavaFloatArray vertA(env, jverts, vertIndex + (ptCount << 1));
417    AutoJavaIntArray colorA(env, jcolors, colorIndex + ptCount);
418
419    const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
420    SkBitmap bitmap;
421    GraphicsJNI::getSkBitmap(env, jbitmap, &bitmap);
422    get_canvas(canvasHandle)->drawBitmapMesh(bitmap, meshWidth, meshHeight,
423                                             vertA.ptr(), colorA.ptr(), paint);
424}
425
426class DrawTextFunctor {
427public:
428    DrawTextFunctor(const Layout& layout, Canvas* canvas, uint16_t* glyphs, float* pos,
429                    const SkPaint& paint, float x, float y, MinikinRect& bounds,
430                    float totalAdvance)
431            : layout(layout), canvas(canvas), glyphs(glyphs), pos(pos), paint(paint),
432              x(x), y(y), bounds(bounds), totalAdvance(totalAdvance) { }
433
434    void operator()(size_t start, size_t end) {
435        if (canvas->drawTextAbsolutePos()) {
436            for (size_t i = start; i < end; i++) {
437                glyphs[i] = layout.getGlyphId(i);
438                pos[2 * i] = x + layout.getX(i);
439                pos[2 * i + 1] = y + layout.getY(i);
440            }
441        } else {
442            for (size_t i = start; i < end; i++) {
443                glyphs[i] = layout.getGlyphId(i);
444                pos[2 * i] = layout.getX(i);
445                pos[2 * i + 1] = layout.getY(i);
446            }
447        }
448
449        size_t glyphCount = end - start;
450        canvas->drawText(glyphs + start, pos + (2 * start), glyphCount, paint, x, y,
451                         bounds.mLeft, bounds.mTop, bounds.mRight, bounds.mBottom,
452                         totalAdvance);
453    }
454private:
455    const Layout& layout;
456    Canvas* canvas;
457    uint16_t* glyphs;
458    float* pos;
459    const SkPaint& paint;
460    float x;
461    float y;
462    MinikinRect& bounds;
463    float totalAdvance;
464};
465
466// Same values used by Skia
467#define kStdStrikeThru_Offset   (-6.0f / 21.0f)
468#define kStdUnderline_Offset    (1.0f / 9.0f)
469#define kStdUnderline_Thickness (1.0f / 18.0f)
470
471void drawTextDecorations(Canvas* canvas, float x, float y, float length, const SkPaint& paint) {
472    uint32_t flags;
473    SkDrawFilter* drawFilter = canvas->getDrawFilter();
474    if (drawFilter) {
475        SkPaint paintCopy(paint);
476        drawFilter->filter(&paintCopy, SkDrawFilter::kText_Type);
477        flags = paintCopy.getFlags();
478    } else {
479        flags = paint.getFlags();
480    }
481    if (flags & (SkPaint::kUnderlineText_Flag | SkPaint::kStrikeThruText_Flag)) {
482        SkScalar left = x;
483        SkScalar right = x + length;
484        float textSize = paint.getTextSize();
485        float strokeWidth = fmax(textSize * kStdUnderline_Thickness, 1.0f);
486        if (flags & SkPaint::kUnderlineText_Flag) {
487            SkScalar top = y + textSize * kStdUnderline_Offset - 0.5f * strokeWidth;
488            SkScalar bottom = y + textSize * kStdUnderline_Offset + 0.5f * strokeWidth;
489            canvas->drawRect(left, top, right, bottom, paint);
490        }
491        if (flags & SkPaint::kStrikeThruText_Flag) {
492            SkScalar top = y + textSize * kStdStrikeThru_Offset - 0.5f * strokeWidth;
493            SkScalar bottom = y + textSize * kStdStrikeThru_Offset + 0.5f * strokeWidth;
494            canvas->drawRect(left, top, right, bottom, paint);
495        }
496    }
497}
498
499void drawText(Canvas* canvas, const uint16_t* text, int start, int count, int contextCount,
500             float x, float y, int bidiFlags, const Paint& origPaint, TypefaceImpl* typeface) {
501    // minikin may modify the original paint
502    Paint paint(origPaint);
503
504    Layout layout;
505    MinikinUtils::doLayout(&layout, &paint, bidiFlags, typeface, text, start, count, contextCount);
506
507    size_t nGlyphs = layout.nGlyphs();
508    uint16_t* glyphs = new uint16_t[nGlyphs];
509    float* pos = new float[nGlyphs * 2];
510
511    x += MinikinUtils::xOffsetForTextAlign(&paint, layout);
512
513    MinikinRect bounds;
514    layout.getBounds(&bounds);
515    if (!canvas->drawTextAbsolutePos()) {
516        bounds.offset(x, y);
517    }
518
519    DrawTextFunctor f(layout, canvas, glyphs, pos, paint, x, y, bounds, layout.getAdvance());
520    MinikinUtils::forFontRun(layout, &paint, f);
521
522    drawTextDecorations(canvas, x, y, layout.getAdvance(), paint);
523
524    delete[] glyphs;
525    delete[] pos;
526}
527
528static void drawTextChars(JNIEnv* env, jobject, jlong canvasHandle, jcharArray text,
529                          jint index, jint count, jfloat x, jfloat y, jint bidiFlags,
530                          jlong paintHandle, jlong typefaceHandle) {
531    Paint* paint = reinterpret_cast<Paint*>(paintHandle);
532    TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefaceHandle);
533    jchar* jchars = env->GetCharArrayElements(text, NULL);
534    drawText(get_canvas(canvasHandle), jchars + index, 0, count, count, x, y,
535                                       bidiFlags, *paint, typeface);
536    env->ReleaseCharArrayElements(text, jchars, JNI_ABORT);
537}
538
539static void drawTextString(JNIEnv* env, jobject, jlong canvasHandle, jstring text,
540                           jint start, jint end, jfloat x, jfloat y, jint bidiFlags,
541                           jlong paintHandle, jlong typefaceHandle) {
542    Paint* paint = reinterpret_cast<Paint*>(paintHandle);
543    TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefaceHandle);
544    const int count = end - start;
545    const jchar* jchars = env->GetStringChars(text, NULL);
546    drawText(get_canvas(canvasHandle), jchars + start, 0, count, count, x, y,
547                                       bidiFlags, *paint, typeface);
548    env->ReleaseStringChars(text, jchars);
549}
550
551static void drawTextRunChars(JNIEnv* env, jobject, jlong canvasHandle, jcharArray text, jint index,
552                             jint count, jint contextIndex, jint contextCount, jfloat x, jfloat y,
553                             jboolean isRtl, jlong paintHandle, jlong typefaceHandle) {
554    Paint* paint = reinterpret_cast<Paint*>(paintHandle);
555    TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefaceHandle);
556
557    const int bidiFlags = isRtl ? kBidi_Force_RTL : kBidi_Force_LTR;
558    jchar* jchars = env->GetCharArrayElements(text, NULL);
559    drawText(get_canvas(canvasHandle), jchars + contextIndex, index - contextIndex, count,
560                                       contextCount, x, y, bidiFlags, *paint, typeface);
561    env->ReleaseCharArrayElements(text, jchars, JNI_ABORT);
562}
563
564static void drawTextRunString(JNIEnv* env, jobject obj, jlong canvasHandle, jstring text,
565                              jint start, jint end, jint contextStart, jint contextEnd,
566                              jfloat x, jfloat y, jboolean isRtl, jlong paintHandle,
567                              jlong typefaceHandle) {
568    Paint* paint = reinterpret_cast<Paint*>(paintHandle);
569    TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefaceHandle);
570
571    int bidiFlags = isRtl ? kBidi_Force_RTL : kBidi_Force_LTR;
572    jint count = end - start;
573    jint contextCount = contextEnd - contextStart;
574    const jchar* jchars = env->GetStringChars(text, NULL);
575    drawText(get_canvas(canvasHandle), jchars + contextStart, start - contextStart, count,
576                                       contextCount, x, y, bidiFlags, *paint, typeface);
577    env->ReleaseStringChars(text, jchars);
578}
579
580class DrawTextOnPathFunctor {
581public:
582    DrawTextOnPathFunctor(const Layout& layout, Canvas* canvas, float hOffset,
583                float vOffset, const Paint& paint, const SkPath& path)
584            : layout(layout), canvas(canvas), hOffset(hOffset), vOffset(vOffset),
585                paint(paint), path(path) {
586    }
587    void operator()(size_t start, size_t end) {
588        uint16_t glyphs[1];
589        for (size_t i = start; i < end; i++) {
590            glyphs[0] = layout.getGlyphId(i);
591            float x = hOffset + layout.getX(i);
592            float y = vOffset + layout.getY(i);
593            canvas->drawTextOnPath(glyphs, 1, path, x, y, paint);
594        }
595    }
596private:
597    const Layout& layout;
598    Canvas* canvas;
599    float hOffset;
600    float vOffset;
601    const Paint& paint;
602    const SkPath& path;
603};
604
605static void drawTextOnPath(Canvas* canvas, const uint16_t* text, int count, int bidiFlags,
606                           const SkPath& path, float hOffset, float vOffset,
607                           const Paint& paint, TypefaceImpl* typeface) {
608    Paint paintCopy(paint);
609    Layout layout;
610    MinikinUtils::doLayout(&layout, &paintCopy, bidiFlags, typeface, text, 0, count, count);
611    hOffset += MinikinUtils::hOffsetForTextAlign(&paintCopy, layout, path);
612
613    // Set align to left for drawing, as we don't want individual
614    // glyphs centered or right-aligned; the offset above takes
615    // care of all alignment.
616    paintCopy.setTextAlign(Paint::kLeft_Align);
617
618    DrawTextOnPathFunctor f(layout, canvas, hOffset, vOffset, paintCopy, path);
619    MinikinUtils::forFontRun(layout, &paintCopy, f);
620}
621
622static void drawTextOnPathChars(JNIEnv* env, jobject, jlong canvasHandle, jcharArray text,
623                                jint index, jint count, jlong pathHandle, jfloat hOffset,
624                                jfloat vOffset, jint bidiFlags, jlong paintHandle,
625                                jlong typefaceHandle) {
626    SkPath* path = reinterpret_cast<SkPath*>(pathHandle);
627    Paint* paint = reinterpret_cast<Paint*>(paintHandle);
628    TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefaceHandle);
629
630    jchar* jchars = env->GetCharArrayElements(text, NULL);
631
632    drawTextOnPath(get_canvas(canvasHandle), jchars + index, count, bidiFlags, *path,
633                   hOffset, vOffset, *paint, typeface);
634
635    env->ReleaseCharArrayElements(text, jchars, 0);
636}
637
638static void drawTextOnPathString(JNIEnv* env, jobject, jlong canvasHandle, jstring text,
639                                 jlong pathHandle, jfloat hOffset, jfloat vOffset,
640                                 jint bidiFlags, jlong paintHandle, jlong typefaceHandle) {
641    SkPath* path = reinterpret_cast<SkPath*>(pathHandle);
642    Paint* paint = reinterpret_cast<Paint*>(paintHandle);
643    TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefaceHandle);
644
645    const jchar* jchars = env->GetStringChars(text, NULL);
646    int count = env->GetStringLength(text);
647
648    drawTextOnPath(get_canvas(canvasHandle), jchars, count, bidiFlags, *path,
649                   hOffset, vOffset, *paint, typeface);
650
651    env->ReleaseStringChars(text, jchars);
652}
653
654static void setDrawFilter(JNIEnv* env, jobject, jlong canvasHandle, jlong filterHandle) {
655    get_canvas(canvasHandle)->setDrawFilter(reinterpret_cast<SkDrawFilter*>(filterHandle));
656}
657
658static void freeCaches(JNIEnv* env, jobject) {
659    SkGraphics::PurgeFontCache();
660}
661
662static void freeTextLayoutCaches(JNIEnv* env, jobject) {
663    Layout::purgeCaches();
664}
665
666}; // namespace CanvasJNI
667
668static const JNINativeMethod gMethods[] = {
669    {"finalizer", "(J)V", (void*) CanvasJNI::finalizer},
670    {"initRaster", "(Landroid/graphics/Bitmap;)J", (void*) CanvasJNI::initRaster},
671    {"native_setBitmap", "(JLandroid/graphics/Bitmap;)V", (void*) CanvasJNI::setBitmap},
672    {"native_isOpaque","(J)Z", (void*) CanvasJNI::isOpaque},
673    {"native_getWidth","(J)I", (void*) CanvasJNI::getWidth},
674    {"native_getHeight","(J)I", (void*) CanvasJNI::getHeight},
675    {"native_save","(JI)I", (void*) CanvasJNI::save},
676    {"native_saveLayer","(JFFFFJI)I", (void*) CanvasJNI::saveLayer},
677    {"native_saveLayerAlpha","(JFFFFII)I", (void*) CanvasJNI::saveLayerAlpha},
678    {"native_getSaveCount","(J)I", (void*) CanvasJNI::getSaveCount},
679    {"native_restore","(JZ)V", (void*) CanvasJNI::restore},
680    {"native_restoreToCount","(JIZ)V", (void*) CanvasJNI::restoreToCount},
681    {"native_getCTM", "(JJ)V", (void*)CanvasJNI::getCTM},
682    {"native_setMatrix","(JJ)V", (void*) CanvasJNI::setMatrix},
683    {"native_concat","(JJ)V", (void*) CanvasJNI::concat},
684    {"native_rotate","(JF)V", (void*) CanvasJNI::rotate},
685    {"native_scale","(JFF)V", (void*) CanvasJNI::scale},
686    {"native_skew","(JFF)V", (void*) CanvasJNI::skew},
687    {"native_translate","(JFF)V", (void*) CanvasJNI::translate},
688    {"native_getClipBounds","(JLandroid/graphics/Rect;)Z", (void*) CanvasJNI::getClipBounds},
689    {"native_quickReject","(JJ)Z", (void*) CanvasJNI::quickRejectPath},
690    {"native_quickReject","(JFFFF)Z", (void*)CanvasJNI::quickRejectRect},
691    {"native_clipRect","(JFFFFI)Z", (void*) CanvasJNI::clipRect},
692    {"native_clipPath","(JJI)Z", (void*) CanvasJNI::clipPath},
693    {"native_clipRegion","(JJI)Z", (void*) CanvasJNI::clipRegion},
694    {"native_drawColor","(JII)V", (void*) CanvasJNI::drawColor},
695    {"native_drawPaint","(JJ)V", (void*) CanvasJNI::drawPaint},
696    {"native_drawPoint", "(JFFJ)V", (void*) CanvasJNI::drawPoint},
697    {"native_drawPoints", "(J[FIIJ)V", (void*) CanvasJNI::drawPoints},
698    {"native_drawLine", "(JFFFFJ)V", (void*) CanvasJNI::drawLine},
699    {"native_drawLines", "(J[FIIJ)V", (void*) CanvasJNI::drawLines},
700    {"native_drawRect","(JFFFFJ)V", (void*) CanvasJNI::drawRect},
701    {"native_drawRoundRect","(JFFFFFFJ)V", (void*) CanvasJNI::drawRoundRect},
702    {"native_drawCircle","(JFFFJ)V", (void*) CanvasJNI::drawCircle},
703    {"native_drawOval","(JFFFFJ)V", (void*) CanvasJNI::drawOval},
704    {"native_drawArc","(JFFFFFFZJ)V", (void*) CanvasJNI::drawArc},
705    {"native_drawPath","(JJJ)V", (void*) CanvasJNI::drawPath},
706    {"nativeDrawVertices", "(JII[FI[FI[II[SIIJ)V", (void*)CanvasJNI::drawVertices},
707    {"native_drawBitmap","(JLandroid/graphics/Bitmap;FFJIII)V", (void*) CanvasJNI::drawBitmap},
708    {"nativeDrawBitmapMatrix", "(JLandroid/graphics/Bitmap;JJ)V", (void*)CanvasJNI::drawBitmapMatrix},
709    {"native_drawBitmap","(JLandroid/graphics/Bitmap;FFFFFFFFJII)V", (void*) CanvasJNI::drawBitmapRect},
710    {"native_drawBitmap", "(J[IIIFFIIZJ)V", (void*)CanvasJNI::drawBitmapArray},
711    {"nativeDrawBitmapMesh", "(JLandroid/graphics/Bitmap;II[FI[IIJ)V", (void*)CanvasJNI::drawBitmapMesh},
712    {"native_drawText","(J[CIIFFIJJ)V", (void*) CanvasJNI::drawTextChars},
713    {"native_drawText","(JLjava/lang/String;IIFFIJJ)V", (void*) CanvasJNI::drawTextString},
714    {"native_drawTextRun","(J[CIIIIFFZJJ)V", (void*) CanvasJNI::drawTextRunChars},
715    {"native_drawTextRun","(JLjava/lang/String;IIIIFFZJJ)V", (void*) CanvasJNI::drawTextRunString},
716    {"native_drawTextOnPath","(J[CIIJFFIJJ)V", (void*) CanvasJNI::drawTextOnPathChars},
717    {"native_drawTextOnPath","(JLjava/lang/String;JFFIJJ)V", (void*) CanvasJNI::drawTextOnPathString},
718    {"nativeSetDrawFilter", "(JJ)V", (void*) CanvasJNI::setDrawFilter},
719    {"freeCaches", "()V", (void*) CanvasJNI::freeCaches},
720    {"freeTextLayoutCaches", "()V", (void*) CanvasJNI::freeTextLayoutCaches}
721};
722
723int register_android_graphics_Canvas(JNIEnv* env) {
724    return RegisterMethodsOrDie(env, "android/graphics/Canvas", gMethods, NELEM(gMethods));
725}
726
727}; // namespace android
728