xref: /aosp_15_r20/frameworks/base/libs/hwui/jni/Path.cpp (revision d57664e9bc4670b3ecf6748a746a57c557b6bc9e)
1*d57664e9SAndroid Build Coastguard Worker /* libs/android_runtime/android/graphics/Path.cpp
2*d57664e9SAndroid Build Coastguard Worker **
3*d57664e9SAndroid Build Coastguard Worker ** Copyright 2006, The Android Open Source Project
4*d57664e9SAndroid Build Coastguard Worker **
5*d57664e9SAndroid Build Coastguard Worker ** Licensed under the Apache License, Version 2.0 (the "License");
6*d57664e9SAndroid Build Coastguard Worker ** you may not use this file except in compliance with the License.
7*d57664e9SAndroid Build Coastguard Worker ** You may obtain a copy of the License at
8*d57664e9SAndroid Build Coastguard Worker **
9*d57664e9SAndroid Build Coastguard Worker **     http://www.apache.org/licenses/LICENSE-2.0
10*d57664e9SAndroid Build Coastguard Worker **
11*d57664e9SAndroid Build Coastguard Worker ** Unless required by applicable law or agreed to in writing, software
12*d57664e9SAndroid Build Coastguard Worker ** distributed under the License is distributed on an "AS IS" BASIS,
13*d57664e9SAndroid Build Coastguard Worker ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14*d57664e9SAndroid Build Coastguard Worker ** See the License for the specific language governing permissions and
15*d57664e9SAndroid Build Coastguard Worker ** limitations under the License.
16*d57664e9SAndroid Build Coastguard Worker */
17*d57664e9SAndroid Build Coastguard Worker 
18*d57664e9SAndroid Build Coastguard Worker // This file was generated from the C++ include file: SkPath.h
19*d57664e9SAndroid Build Coastguard Worker // Any changes made to this file will be discarded by the build.
20*d57664e9SAndroid Build Coastguard Worker // To change this file, either edit the include, or device/tools/gluemaker/main.cpp,
21*d57664e9SAndroid Build Coastguard Worker // or one of the auxilary file specifications in device/tools/gluemaker.
22*d57664e9SAndroid Build Coastguard Worker 
23*d57664e9SAndroid Build Coastguard Worker #include "GraphicsJNI.h"
24*d57664e9SAndroid Build Coastguard Worker 
25*d57664e9SAndroid Build Coastguard Worker #include "SkPath.h"
26*d57664e9SAndroid Build Coastguard Worker #include "SkPathOps.h"
27*d57664e9SAndroid Build Coastguard Worker #include "SkGeometry.h" // WARNING: Internal Skia Header
28*d57664e9SAndroid Build Coastguard Worker 
29*d57664e9SAndroid Build Coastguard Worker #include <vector>
30*d57664e9SAndroid Build Coastguard Worker #include <map>
31*d57664e9SAndroid Build Coastguard Worker 
32*d57664e9SAndroid Build Coastguard Worker namespace android {
33*d57664e9SAndroid Build Coastguard Worker 
34*d57664e9SAndroid Build Coastguard Worker class SkPathGlue {
35*d57664e9SAndroid Build Coastguard Worker public:
36*d57664e9SAndroid Build Coastguard Worker 
finalizer(SkPath * obj)37*d57664e9SAndroid Build Coastguard Worker     static void finalizer(SkPath* obj) {
38*d57664e9SAndroid Build Coastguard Worker         delete obj;
39*d57664e9SAndroid Build Coastguard Worker     }
40*d57664e9SAndroid Build Coastguard Worker 
41*d57664e9SAndroid Build Coastguard Worker     // ---------------- Regular JNI -----------------------------
42*d57664e9SAndroid Build Coastguard Worker 
init(JNIEnv * env,jclass clazz)43*d57664e9SAndroid Build Coastguard Worker     static jlong init(JNIEnv* env, jclass clazz) {
44*d57664e9SAndroid Build Coastguard Worker         return reinterpret_cast<jlong>(new SkPath());
45*d57664e9SAndroid Build Coastguard Worker     }
46*d57664e9SAndroid Build Coastguard Worker 
init_Path(JNIEnv * env,jclass clazz,jlong valHandle)47*d57664e9SAndroid Build Coastguard Worker     static jlong init_Path(JNIEnv* env, jclass clazz, jlong valHandle) {
48*d57664e9SAndroid Build Coastguard Worker         SkPath* val = reinterpret_cast<SkPath*>(valHandle);
49*d57664e9SAndroid Build Coastguard Worker         return reinterpret_cast<jlong>(new SkPath(*val));
50*d57664e9SAndroid Build Coastguard Worker     }
51*d57664e9SAndroid Build Coastguard Worker 
getFinalizer(JNIEnv * env,jclass clazz)52*d57664e9SAndroid Build Coastguard Worker     static jlong getFinalizer(JNIEnv* env, jclass clazz) {
53*d57664e9SAndroid Build Coastguard Worker         return static_cast<jlong>(reinterpret_cast<uintptr_t>(&finalizer));
54*d57664e9SAndroid Build Coastguard Worker     }
55*d57664e9SAndroid Build Coastguard Worker 
set(JNIEnv * env,jclass clazz,jlong dstHandle,jlong srcHandle)56*d57664e9SAndroid Build Coastguard Worker     static void set(JNIEnv* env, jclass clazz, jlong dstHandle, jlong srcHandle) {
57*d57664e9SAndroid Build Coastguard Worker         SkPath* dst = reinterpret_cast<SkPath*>(dstHandle);
58*d57664e9SAndroid Build Coastguard Worker         const SkPath* src = reinterpret_cast<SkPath*>(srcHandle);
59*d57664e9SAndroid Build Coastguard Worker         *dst = *src;
60*d57664e9SAndroid Build Coastguard Worker     }
61*d57664e9SAndroid Build Coastguard Worker 
computeBounds(JNIEnv * env,jclass clazz,jlong objHandle,jobject jbounds)62*d57664e9SAndroid Build Coastguard Worker     static void computeBounds(JNIEnv* env, jclass clazz, jlong objHandle, jobject jbounds) {
63*d57664e9SAndroid Build Coastguard Worker         SkPath* obj = reinterpret_cast<SkPath*>(objHandle);
64*d57664e9SAndroid Build Coastguard Worker         const SkRect& bounds = obj->getBounds();
65*d57664e9SAndroid Build Coastguard Worker         GraphicsJNI::rect_to_jrectf(bounds, env, jbounds);
66*d57664e9SAndroid Build Coastguard Worker     }
67*d57664e9SAndroid Build Coastguard Worker 
incReserve(JNIEnv * env,jclass clazz,jlong objHandle,jint extraPtCount)68*d57664e9SAndroid Build Coastguard Worker     static void incReserve(JNIEnv* env, jclass clazz, jlong objHandle, jint extraPtCount) {
69*d57664e9SAndroid Build Coastguard Worker         SkPath* obj = reinterpret_cast<SkPath*>(objHandle);
70*d57664e9SAndroid Build Coastguard Worker         obj->incReserve(extraPtCount);
71*d57664e9SAndroid Build Coastguard Worker     }
72*d57664e9SAndroid Build Coastguard Worker 
moveTo__FF(JNIEnv * env,jclass clazz,jlong objHandle,jfloat x,jfloat y)73*d57664e9SAndroid Build Coastguard Worker     static void moveTo__FF(JNIEnv* env, jclass clazz, jlong objHandle, jfloat x, jfloat y) {
74*d57664e9SAndroid Build Coastguard Worker         SkPath* obj = reinterpret_cast<SkPath*>(objHandle);
75*d57664e9SAndroid Build Coastguard Worker         obj->moveTo(x, y);
76*d57664e9SAndroid Build Coastguard Worker     }
77*d57664e9SAndroid Build Coastguard Worker 
rMoveTo(JNIEnv * env,jclass clazz,jlong objHandle,jfloat dx,jfloat dy)78*d57664e9SAndroid Build Coastguard Worker     static void rMoveTo(JNIEnv* env, jclass clazz, jlong objHandle, jfloat dx, jfloat dy) {
79*d57664e9SAndroid Build Coastguard Worker         SkPath* obj = reinterpret_cast<SkPath*>(objHandle);
80*d57664e9SAndroid Build Coastguard Worker         obj->rMoveTo(dx, dy);
81*d57664e9SAndroid Build Coastguard Worker     }
82*d57664e9SAndroid Build Coastguard Worker 
lineTo__FF(JNIEnv * env,jclass clazz,jlong objHandle,jfloat x,jfloat y)83*d57664e9SAndroid Build Coastguard Worker     static void lineTo__FF(JNIEnv* env, jclass clazz, jlong objHandle, jfloat x, jfloat y) {
84*d57664e9SAndroid Build Coastguard Worker         SkPath* obj = reinterpret_cast<SkPath*>(objHandle);
85*d57664e9SAndroid Build Coastguard Worker         obj->lineTo(x, y);
86*d57664e9SAndroid Build Coastguard Worker     }
87*d57664e9SAndroid Build Coastguard Worker 
rLineTo(JNIEnv * env,jclass clazz,jlong objHandle,jfloat dx,jfloat dy)88*d57664e9SAndroid Build Coastguard Worker     static void rLineTo(JNIEnv* env, jclass clazz, jlong objHandle, jfloat dx, jfloat dy) {
89*d57664e9SAndroid Build Coastguard Worker         SkPath* obj = reinterpret_cast<SkPath*>(objHandle);
90*d57664e9SAndroid Build Coastguard Worker         obj->rLineTo(dx, dy);
91*d57664e9SAndroid Build Coastguard Worker     }
92*d57664e9SAndroid Build Coastguard Worker 
quadTo__FFFF(JNIEnv * env,jclass clazz,jlong objHandle,jfloat x1,jfloat y1,jfloat x2,jfloat y2)93*d57664e9SAndroid Build Coastguard Worker     static void quadTo__FFFF(JNIEnv* env, jclass clazz, jlong objHandle, jfloat x1, jfloat y1,
94*d57664e9SAndroid Build Coastguard Worker             jfloat x2, jfloat y2) {
95*d57664e9SAndroid Build Coastguard Worker         SkPath* obj = reinterpret_cast<SkPath*>(objHandle);
96*d57664e9SAndroid Build Coastguard Worker         obj->quadTo(x1, y1, x2, y2);
97*d57664e9SAndroid Build Coastguard Worker     }
98*d57664e9SAndroid Build Coastguard Worker 
rQuadTo(JNIEnv * env,jclass clazz,jlong objHandle,jfloat dx1,jfloat dy1,jfloat dx2,jfloat dy2)99*d57664e9SAndroid Build Coastguard Worker     static void rQuadTo(JNIEnv* env, jclass clazz, jlong objHandle, jfloat dx1, jfloat dy1,
100*d57664e9SAndroid Build Coastguard Worker             jfloat dx2, jfloat dy2) {
101*d57664e9SAndroid Build Coastguard Worker         SkPath* obj = reinterpret_cast<SkPath*>(objHandle);
102*d57664e9SAndroid Build Coastguard Worker         obj->rQuadTo(dx1, dy1, dx2, dy2);
103*d57664e9SAndroid Build Coastguard Worker     }
104*d57664e9SAndroid Build Coastguard Worker 
conicTo(JNIEnv * env,jclass clazz,jlong objHandle,jfloat x1,jfloat y1,jfloat x2,jfloat y2,jfloat weight)105*d57664e9SAndroid Build Coastguard Worker     static void conicTo(JNIEnv* env, jclass clazz, jlong objHandle, jfloat x1, jfloat y1, jfloat x2,
106*d57664e9SAndroid Build Coastguard Worker                         jfloat y2, jfloat weight) {
107*d57664e9SAndroid Build Coastguard Worker         SkPath* obj = reinterpret_cast<SkPath*>(objHandle);
108*d57664e9SAndroid Build Coastguard Worker         obj->conicTo(x1, y1, x2, y2, weight);
109*d57664e9SAndroid Build Coastguard Worker     }
110*d57664e9SAndroid Build Coastguard Worker 
rConicTo(JNIEnv * env,jclass clazz,jlong objHandle,jfloat dx1,jfloat dy1,jfloat dx2,jfloat dy2,jfloat weight)111*d57664e9SAndroid Build Coastguard Worker     static void rConicTo(JNIEnv* env, jclass clazz, jlong objHandle, jfloat dx1, jfloat dy1,
112*d57664e9SAndroid Build Coastguard Worker                          jfloat dx2, jfloat dy2, jfloat weight) {
113*d57664e9SAndroid Build Coastguard Worker         SkPath* obj = reinterpret_cast<SkPath*>(objHandle);
114*d57664e9SAndroid Build Coastguard Worker         obj->rConicTo(dx1, dy1, dx2, dy2, weight);
115*d57664e9SAndroid Build Coastguard Worker     }
116*d57664e9SAndroid Build Coastguard Worker 
cubicTo__FFFFFF(JNIEnv * env,jclass clazz,jlong objHandle,jfloat x1,jfloat y1,jfloat x2,jfloat y2,jfloat x3,jfloat y3)117*d57664e9SAndroid Build Coastguard Worker     static void cubicTo__FFFFFF(JNIEnv* env, jclass clazz, jlong objHandle, jfloat x1, jfloat y1,
118*d57664e9SAndroid Build Coastguard Worker             jfloat x2, jfloat y2, jfloat x3, jfloat y3) {
119*d57664e9SAndroid Build Coastguard Worker         SkPath* obj = reinterpret_cast<SkPath*>(objHandle);
120*d57664e9SAndroid Build Coastguard Worker         obj->cubicTo(x1, y1, x2, y2, x3, y3);
121*d57664e9SAndroid Build Coastguard Worker     }
122*d57664e9SAndroid Build Coastguard Worker 
rCubicTo(JNIEnv * env,jclass clazz,jlong objHandle,jfloat x1,jfloat y1,jfloat x2,jfloat y2,jfloat x3,jfloat y3)123*d57664e9SAndroid Build Coastguard Worker     static void rCubicTo(JNIEnv* env, jclass clazz, jlong objHandle, jfloat x1, jfloat y1,
124*d57664e9SAndroid Build Coastguard Worker             jfloat x2, jfloat y2, jfloat x3, jfloat y3) {
125*d57664e9SAndroid Build Coastguard Worker         SkPath* obj = reinterpret_cast<SkPath*>(objHandle);
126*d57664e9SAndroid Build Coastguard Worker         obj->rCubicTo(x1, y1, x2, y2, x3, y3);
127*d57664e9SAndroid Build Coastguard Worker     }
128*d57664e9SAndroid Build Coastguard Worker 
arcTo(JNIEnv * env,jclass clazz,jlong objHandle,jfloat left,jfloat top,jfloat right,jfloat bottom,jfloat startAngle,jfloat sweepAngle,jboolean forceMoveTo)129*d57664e9SAndroid Build Coastguard Worker     static void arcTo(JNIEnv* env, jclass clazz, jlong objHandle, jfloat left, jfloat top,
130*d57664e9SAndroid Build Coastguard Worker             jfloat right, jfloat bottom, jfloat startAngle, jfloat sweepAngle,
131*d57664e9SAndroid Build Coastguard Worker             jboolean forceMoveTo) {
132*d57664e9SAndroid Build Coastguard Worker         SkPath* obj = reinterpret_cast<SkPath*>(objHandle);
133*d57664e9SAndroid Build Coastguard Worker         SkRect oval = SkRect::MakeLTRB(left, top, right, bottom);
134*d57664e9SAndroid Build Coastguard Worker         obj->arcTo(oval, startAngle, sweepAngle, forceMoveTo);
135*d57664e9SAndroid Build Coastguard Worker     }
136*d57664e9SAndroid Build Coastguard Worker 
close(JNIEnv * env,jclass clazz,jlong objHandle)137*d57664e9SAndroid Build Coastguard Worker     static void close(JNIEnv* env, jclass clazz, jlong objHandle) {
138*d57664e9SAndroid Build Coastguard Worker         SkPath* obj = reinterpret_cast<SkPath*>(objHandle);
139*d57664e9SAndroid Build Coastguard Worker         obj->close();
140*d57664e9SAndroid Build Coastguard Worker     }
141*d57664e9SAndroid Build Coastguard Worker 
addRect(JNIEnv * env,jclass clazz,jlong objHandle,jfloat left,jfloat top,jfloat right,jfloat bottom,jint dirHandle)142*d57664e9SAndroid Build Coastguard Worker     static void addRect(JNIEnv* env, jclass clazz, jlong objHandle,
143*d57664e9SAndroid Build Coastguard Worker             jfloat left, jfloat top, jfloat right, jfloat bottom, jint dirHandle) {
144*d57664e9SAndroid Build Coastguard Worker         SkPath* obj = reinterpret_cast<SkPath*>(objHandle);
145*d57664e9SAndroid Build Coastguard Worker         SkPathDirection dir = static_cast<SkPathDirection>(dirHandle);
146*d57664e9SAndroid Build Coastguard Worker         obj->addRect(left, top, right, bottom, dir);
147*d57664e9SAndroid Build Coastguard Worker     }
148*d57664e9SAndroid Build Coastguard Worker 
addOval(JNIEnv * env,jclass clazz,jlong objHandle,jfloat left,jfloat top,jfloat right,jfloat bottom,jint dirHandle)149*d57664e9SAndroid Build Coastguard Worker     static void addOval(JNIEnv* env, jclass clazz, jlong objHandle,
150*d57664e9SAndroid Build Coastguard Worker             jfloat left, jfloat top, jfloat right, jfloat bottom, jint dirHandle) {
151*d57664e9SAndroid Build Coastguard Worker         SkPath* obj = reinterpret_cast<SkPath*>(objHandle);
152*d57664e9SAndroid Build Coastguard Worker         SkPathDirection dir = static_cast<SkPathDirection>(dirHandle);
153*d57664e9SAndroid Build Coastguard Worker         SkRect oval = SkRect::MakeLTRB(left, top, right, bottom);
154*d57664e9SAndroid Build Coastguard Worker         obj->addOval(oval, dir);
155*d57664e9SAndroid Build Coastguard Worker     }
156*d57664e9SAndroid Build Coastguard Worker 
addCircle(JNIEnv * env,jclass clazz,jlong objHandle,jfloat x,jfloat y,jfloat radius,jint dirHandle)157*d57664e9SAndroid Build Coastguard Worker     static void addCircle(JNIEnv* env, jclass clazz, jlong objHandle, jfloat x, jfloat y,
158*d57664e9SAndroid Build Coastguard Worker             jfloat radius, jint dirHandle) {
159*d57664e9SAndroid Build Coastguard Worker         SkPath* obj = reinterpret_cast<SkPath*>(objHandle);
160*d57664e9SAndroid Build Coastguard Worker         SkPathDirection dir = static_cast<SkPathDirection>(dirHandle);
161*d57664e9SAndroid Build Coastguard Worker         obj->addCircle(x, y, radius, dir);
162*d57664e9SAndroid Build Coastguard Worker     }
163*d57664e9SAndroid Build Coastguard Worker 
addArc(JNIEnv * env,jclass clazz,jlong objHandle,jfloat left,jfloat top,jfloat right,jfloat bottom,jfloat startAngle,jfloat sweepAngle)164*d57664e9SAndroid Build Coastguard Worker     static void addArc(JNIEnv* env, jclass clazz, jlong objHandle, jfloat left, jfloat top,
165*d57664e9SAndroid Build Coastguard Worker             jfloat right, jfloat bottom, jfloat startAngle, jfloat sweepAngle) {
166*d57664e9SAndroid Build Coastguard Worker         SkRect oval = SkRect::MakeLTRB(left, top, right, bottom);
167*d57664e9SAndroid Build Coastguard Worker         SkPath* obj = reinterpret_cast<SkPath*>(objHandle);
168*d57664e9SAndroid Build Coastguard Worker         obj->addArc(oval, startAngle, sweepAngle);
169*d57664e9SAndroid Build Coastguard Worker     }
170*d57664e9SAndroid Build Coastguard Worker 
addRoundRectXY(JNIEnv * env,jclass clazz,jlong objHandle,jfloat left,jfloat top,jfloat right,jfloat bottom,jfloat rx,jfloat ry,jint dirHandle)171*d57664e9SAndroid Build Coastguard Worker     static void addRoundRectXY(JNIEnv* env, jclass clazz, jlong objHandle, jfloat left, jfloat top,
172*d57664e9SAndroid Build Coastguard Worker             jfloat right, jfloat bottom, jfloat rx, jfloat ry, jint dirHandle) {
173*d57664e9SAndroid Build Coastguard Worker         SkRect rect = SkRect::MakeLTRB(left, top, right, bottom);
174*d57664e9SAndroid Build Coastguard Worker         SkPath* obj = reinterpret_cast<SkPath*>(objHandle);
175*d57664e9SAndroid Build Coastguard Worker         SkPathDirection dir = static_cast<SkPathDirection>(dirHandle);
176*d57664e9SAndroid Build Coastguard Worker         obj->addRoundRect(rect, rx, ry, dir);
177*d57664e9SAndroid Build Coastguard Worker     }
178*d57664e9SAndroid Build Coastguard Worker 
addRoundRect8(JNIEnv * env,jclass clazz,jlong objHandle,jfloat left,jfloat top,jfloat right,jfloat bottom,jfloatArray array,jint dirHandle)179*d57664e9SAndroid Build Coastguard Worker     static void addRoundRect8(JNIEnv* env, jclass clazz, jlong objHandle, jfloat left, jfloat top,
180*d57664e9SAndroid Build Coastguard Worker                 jfloat right, jfloat bottom, jfloatArray array, jint dirHandle) {
181*d57664e9SAndroid Build Coastguard Worker         SkRect rect = SkRect::MakeLTRB(left, top, right, bottom);
182*d57664e9SAndroid Build Coastguard Worker         SkPath* obj = reinterpret_cast<SkPath*>(objHandle);
183*d57664e9SAndroid Build Coastguard Worker         SkPathDirection dir = static_cast<SkPathDirection>(dirHandle);
184*d57664e9SAndroid Build Coastguard Worker         AutoJavaFloatArray  afa(env, array, 8);
185*d57664e9SAndroid Build Coastguard Worker         const float* src = afa.ptr();
186*d57664e9SAndroid Build Coastguard Worker         obj->addRoundRect(rect, src, dir);
187*d57664e9SAndroid Build Coastguard Worker     }
188*d57664e9SAndroid Build Coastguard Worker 
addPath__PathFF(JNIEnv * env,jclass clazz,jlong objHandle,jlong srcHandle,jfloat dx,jfloat dy)189*d57664e9SAndroid Build Coastguard Worker     static void addPath__PathFF(JNIEnv* env, jclass clazz, jlong objHandle, jlong srcHandle,
190*d57664e9SAndroid Build Coastguard Worker             jfloat dx, jfloat dy) {
191*d57664e9SAndroid Build Coastguard Worker         SkPath* obj = reinterpret_cast<SkPath*>(objHandle);
192*d57664e9SAndroid Build Coastguard Worker         SkPath* src = reinterpret_cast<SkPath*>(srcHandle);
193*d57664e9SAndroid Build Coastguard Worker         obj->addPath(*src, dx, dy);
194*d57664e9SAndroid Build Coastguard Worker     }
195*d57664e9SAndroid Build Coastguard Worker 
addPath__Path(JNIEnv * env,jclass clazz,jlong objHandle,jlong srcHandle)196*d57664e9SAndroid Build Coastguard Worker     static void addPath__Path(JNIEnv* env, jclass clazz, jlong objHandle, jlong srcHandle) {
197*d57664e9SAndroid Build Coastguard Worker         SkPath* obj = reinterpret_cast<SkPath*>(objHandle);
198*d57664e9SAndroid Build Coastguard Worker         SkPath* src = reinterpret_cast<SkPath*>(srcHandle);
199*d57664e9SAndroid Build Coastguard Worker         obj->addPath(*src);
200*d57664e9SAndroid Build Coastguard Worker     }
201*d57664e9SAndroid Build Coastguard Worker 
addPath__PathMatrix(JNIEnv * env,jclass clazz,jlong objHandle,jlong srcHandle,jlong matrixHandle)202*d57664e9SAndroid Build Coastguard Worker     static void addPath__PathMatrix(JNIEnv* env, jclass clazz, jlong objHandle, jlong srcHandle,
203*d57664e9SAndroid Build Coastguard Worker             jlong matrixHandle) {
204*d57664e9SAndroid Build Coastguard Worker         SkPath* obj = reinterpret_cast<SkPath*>(objHandle);
205*d57664e9SAndroid Build Coastguard Worker         SkPath* src = reinterpret_cast<SkPath*>(srcHandle);
206*d57664e9SAndroid Build Coastguard Worker         SkMatrix* matrix = reinterpret_cast<SkMatrix*>(matrixHandle);
207*d57664e9SAndroid Build Coastguard Worker         obj->addPath(*src, *matrix);
208*d57664e9SAndroid Build Coastguard Worker     }
209*d57664e9SAndroid Build Coastguard Worker 
offset__FF(JNIEnv * env,jclass clazz,jlong objHandle,jfloat dx,jfloat dy)210*d57664e9SAndroid Build Coastguard Worker     static void offset__FF(JNIEnv* env, jclass clazz, jlong objHandle, jfloat dx, jfloat dy) {
211*d57664e9SAndroid Build Coastguard Worker         SkPath* obj = reinterpret_cast<SkPath*>(objHandle);
212*d57664e9SAndroid Build Coastguard Worker         obj->offset(dx, dy);
213*d57664e9SAndroid Build Coastguard Worker     }
214*d57664e9SAndroid Build Coastguard Worker 
setLastPoint(JNIEnv * env,jclass clazz,jlong objHandle,jfloat dx,jfloat dy)215*d57664e9SAndroid Build Coastguard Worker     static void setLastPoint(JNIEnv* env, jclass clazz, jlong objHandle, jfloat dx, jfloat dy) {
216*d57664e9SAndroid Build Coastguard Worker         SkPath* obj = reinterpret_cast<SkPath*>(objHandle);
217*d57664e9SAndroid Build Coastguard Worker         obj->setLastPt(dx, dy);
218*d57664e9SAndroid Build Coastguard Worker     }
219*d57664e9SAndroid Build Coastguard Worker 
interpolate(JNIEnv * env,jclass clazz,jlong startHandle,jlong endHandle,jfloat t,jlong interpolatedHandle)220*d57664e9SAndroid Build Coastguard Worker     static jboolean interpolate(JNIEnv* env, jclass clazz, jlong startHandle, jlong endHandle,
221*d57664e9SAndroid Build Coastguard Worker                                 jfloat t, jlong interpolatedHandle) {
222*d57664e9SAndroid Build Coastguard Worker         SkPath* startPath = reinterpret_cast<SkPath*>(startHandle);
223*d57664e9SAndroid Build Coastguard Worker         SkPath* endPath = reinterpret_cast<SkPath*>(endHandle);
224*d57664e9SAndroid Build Coastguard Worker         SkPath* interpolatedPath = reinterpret_cast<SkPath*>(interpolatedHandle);
225*d57664e9SAndroid Build Coastguard Worker         return startPath->interpolate(*endPath, t, interpolatedPath);
226*d57664e9SAndroid Build Coastguard Worker     }
227*d57664e9SAndroid Build Coastguard Worker 
transform__MatrixPath(JNIEnv * env,jclass clazz,jlong objHandle,jlong matrixHandle,jlong dstHandle)228*d57664e9SAndroid Build Coastguard Worker     static void transform__MatrixPath(JNIEnv* env, jclass clazz, jlong objHandle, jlong matrixHandle,
229*d57664e9SAndroid Build Coastguard Worker             jlong dstHandle) {
230*d57664e9SAndroid Build Coastguard Worker         SkPath* obj = reinterpret_cast<SkPath*>(objHandle);
231*d57664e9SAndroid Build Coastguard Worker         SkMatrix* matrix = reinterpret_cast<SkMatrix*>(matrixHandle);
232*d57664e9SAndroid Build Coastguard Worker         SkPath* dst = reinterpret_cast<SkPath*>(dstHandle);
233*d57664e9SAndroid Build Coastguard Worker         obj->transform(*matrix, dst);
234*d57664e9SAndroid Build Coastguard Worker     }
235*d57664e9SAndroid Build Coastguard Worker 
transform__Matrix(JNIEnv * env,jclass clazz,jlong objHandle,jlong matrixHandle)236*d57664e9SAndroid Build Coastguard Worker     static void transform__Matrix(JNIEnv* env, jclass clazz, jlong objHandle, jlong matrixHandle) {
237*d57664e9SAndroid Build Coastguard Worker         SkPath* obj = reinterpret_cast<SkPath*>(objHandle);
238*d57664e9SAndroid Build Coastguard Worker         SkMatrix* matrix = reinterpret_cast<SkMatrix*>(matrixHandle);
239*d57664e9SAndroid Build Coastguard Worker         obj->transform(*matrix);
240*d57664e9SAndroid Build Coastguard Worker     }
241*d57664e9SAndroid Build Coastguard Worker 
op(JNIEnv * env,jclass clazz,jlong p1Handle,jlong p2Handle,jint opHandle,jlong rHandle)242*d57664e9SAndroid Build Coastguard Worker     static jboolean op(JNIEnv* env, jclass clazz, jlong p1Handle, jlong p2Handle, jint opHandle,
243*d57664e9SAndroid Build Coastguard Worker             jlong rHandle) {
244*d57664e9SAndroid Build Coastguard Worker         SkPath* p1  = reinterpret_cast<SkPath*>(p1Handle);
245*d57664e9SAndroid Build Coastguard Worker         SkPath* p2  = reinterpret_cast<SkPath*>(p2Handle);
246*d57664e9SAndroid Build Coastguard Worker         SkPathOp op = static_cast<SkPathOp>(opHandle);
247*d57664e9SAndroid Build Coastguard Worker         SkPath* r   = reinterpret_cast<SkPath*>(rHandle);
248*d57664e9SAndroid Build Coastguard Worker         return Op(*p1, *p2, op, r);
249*d57664e9SAndroid Build Coastguard Worker      }
250*d57664e9SAndroid Build Coastguard Worker 
251*d57664e9SAndroid Build Coastguard Worker     typedef SkPoint (*bezierCalculation)(float t, const SkPoint* points);
252*d57664e9SAndroid Build Coastguard Worker 
addMove(std::vector<SkPoint> & segmentPoints,std::vector<float> & lengths,const SkPoint & point)253*d57664e9SAndroid Build Coastguard Worker     static void addMove(std::vector<SkPoint>& segmentPoints, std::vector<float>& lengths,
254*d57664e9SAndroid Build Coastguard Worker             const SkPoint& point) {
255*d57664e9SAndroid Build Coastguard Worker         float length = 0;
256*d57664e9SAndroid Build Coastguard Worker         if (!lengths.empty()) {
257*d57664e9SAndroid Build Coastguard Worker             length = lengths.back();
258*d57664e9SAndroid Build Coastguard Worker         }
259*d57664e9SAndroid Build Coastguard Worker         segmentPoints.push_back(point);
260*d57664e9SAndroid Build Coastguard Worker         lengths.push_back(length);
261*d57664e9SAndroid Build Coastguard Worker     }
262*d57664e9SAndroid Build Coastguard Worker 
addLine(std::vector<SkPoint> & segmentPoints,std::vector<float> & lengths,const SkPoint & toPoint)263*d57664e9SAndroid Build Coastguard Worker     static void addLine(std::vector<SkPoint>& segmentPoints, std::vector<float>& lengths,
264*d57664e9SAndroid Build Coastguard Worker             const SkPoint& toPoint) {
265*d57664e9SAndroid Build Coastguard Worker         if (segmentPoints.empty()) {
266*d57664e9SAndroid Build Coastguard Worker             segmentPoints.push_back(SkPoint::Make(0, 0));
267*d57664e9SAndroid Build Coastguard Worker             lengths.push_back(0);
268*d57664e9SAndroid Build Coastguard Worker         } else if (segmentPoints.back() == toPoint) {
269*d57664e9SAndroid Build Coastguard Worker             return; // Empty line
270*d57664e9SAndroid Build Coastguard Worker         }
271*d57664e9SAndroid Build Coastguard Worker         float length = lengths.back() + SkPoint::Distance(segmentPoints.back(), toPoint);
272*d57664e9SAndroid Build Coastguard Worker         segmentPoints.push_back(toPoint);
273*d57664e9SAndroid Build Coastguard Worker         lengths.push_back(length);
274*d57664e9SAndroid Build Coastguard Worker     }
275*d57664e9SAndroid Build Coastguard Worker 
cubicCoordinateCalculation(float t,float p0,float p1,float p2,float p3)276*d57664e9SAndroid Build Coastguard Worker     static float cubicCoordinateCalculation(float t, float p0, float p1, float p2, float p3) {
277*d57664e9SAndroid Build Coastguard Worker         float oneMinusT = 1 - t;
278*d57664e9SAndroid Build Coastguard Worker         float oneMinusTSquared = oneMinusT * oneMinusT;
279*d57664e9SAndroid Build Coastguard Worker         float oneMinusTCubed = oneMinusTSquared * oneMinusT;
280*d57664e9SAndroid Build Coastguard Worker         float tSquared = t * t;
281*d57664e9SAndroid Build Coastguard Worker         float tCubed = tSquared * t;
282*d57664e9SAndroid Build Coastguard Worker         return (oneMinusTCubed * p0) + (3 * oneMinusTSquared * t * p1)
283*d57664e9SAndroid Build Coastguard Worker                 + (3 * oneMinusT * tSquared * p2) + (tCubed * p3);
284*d57664e9SAndroid Build Coastguard Worker     }
285*d57664e9SAndroid Build Coastguard Worker 
cubicBezierCalculation(float t,const SkPoint * points)286*d57664e9SAndroid Build Coastguard Worker     static SkPoint cubicBezierCalculation(float t, const SkPoint* points) {
287*d57664e9SAndroid Build Coastguard Worker         float x = cubicCoordinateCalculation(t, points[0].x(), points[1].x(),
288*d57664e9SAndroid Build Coastguard Worker             points[2].x(), points[3].x());
289*d57664e9SAndroid Build Coastguard Worker         float y = cubicCoordinateCalculation(t, points[0].y(), points[1].y(),
290*d57664e9SAndroid Build Coastguard Worker             points[2].y(), points[3].y());
291*d57664e9SAndroid Build Coastguard Worker         return SkPoint::Make(x, y);
292*d57664e9SAndroid Build Coastguard Worker     }
293*d57664e9SAndroid Build Coastguard Worker 
quadraticCoordinateCalculation(float t,float p0,float p1,float p2)294*d57664e9SAndroid Build Coastguard Worker     static float quadraticCoordinateCalculation(float t, float p0, float p1, float p2) {
295*d57664e9SAndroid Build Coastguard Worker         float oneMinusT = 1 - t;
296*d57664e9SAndroid Build Coastguard Worker         return oneMinusT * ((oneMinusT * p0) + (t * p1)) + t * ((oneMinusT * p1) + (t * p2));
297*d57664e9SAndroid Build Coastguard Worker     }
298*d57664e9SAndroid Build Coastguard Worker 
quadraticBezierCalculation(float t,const SkPoint * points)299*d57664e9SAndroid Build Coastguard Worker     static SkPoint quadraticBezierCalculation(float t, const SkPoint* points) {
300*d57664e9SAndroid Build Coastguard Worker         float x = quadraticCoordinateCalculation(t, points[0].x(), points[1].x(), points[2].x());
301*d57664e9SAndroid Build Coastguard Worker         float y = quadraticCoordinateCalculation(t, points[0].y(), points[1].y(), points[2].y());
302*d57664e9SAndroid Build Coastguard Worker         return SkPoint::Make(x, y);
303*d57664e9SAndroid Build Coastguard Worker     }
304*d57664e9SAndroid Build Coastguard Worker 
305*d57664e9SAndroid Build Coastguard Worker     // Subdivide a section of the Bezier curve, set the mid-point and the mid-t value.
306*d57664e9SAndroid Build Coastguard Worker     // Returns true if further subdivision is necessary as defined by errorSquared.
subdividePoints(const SkPoint * points,bezierCalculation bezierFunction,float t0,const SkPoint & p0,float t1,const SkPoint & p1,float & midT,SkPoint & midPoint,float errorSquared)307*d57664e9SAndroid Build Coastguard Worker     static bool subdividePoints(const SkPoint* points, bezierCalculation bezierFunction,
308*d57664e9SAndroid Build Coastguard Worker             float t0, const SkPoint &p0, float t1, const SkPoint &p1,
309*d57664e9SAndroid Build Coastguard Worker             float& midT, SkPoint &midPoint, float errorSquared) {
310*d57664e9SAndroid Build Coastguard Worker         midT = (t1 + t0) / 2;
311*d57664e9SAndroid Build Coastguard Worker         float midX = (p1.x() + p0.x()) / 2;
312*d57664e9SAndroid Build Coastguard Worker         float midY = (p1.y() + p0.y()) / 2;
313*d57664e9SAndroid Build Coastguard Worker 
314*d57664e9SAndroid Build Coastguard Worker         midPoint = (*bezierFunction)(midT, points);
315*d57664e9SAndroid Build Coastguard Worker         float xError = midPoint.x() - midX;
316*d57664e9SAndroid Build Coastguard Worker         float yError = midPoint.y() - midY;
317*d57664e9SAndroid Build Coastguard Worker         float midErrorSquared = (xError * xError) + (yError * yError);
318*d57664e9SAndroid Build Coastguard Worker         return midErrorSquared > errorSquared;
319*d57664e9SAndroid Build Coastguard Worker     }
320*d57664e9SAndroid Build Coastguard Worker 
321*d57664e9SAndroid Build Coastguard Worker     // Divides Bezier curves until linear interpolation is very close to accurate, using
322*d57664e9SAndroid Build Coastguard Worker     // errorSquared as a metric. Cubic Bezier curves can have an inflection point that improperly
323*d57664e9SAndroid Build Coastguard Worker     // short-circuit subdivision. If you imagine an S shape, the top and bottom points being the
324*d57664e9SAndroid Build Coastguard Worker     // starting and end points, linear interpolation would mark the center where the curve places
325*d57664e9SAndroid Build Coastguard Worker     // the point. It is clearly not the case that we can linearly interpolate at that point.
326*d57664e9SAndroid Build Coastguard Worker     // doubleCheckDivision forces a second examination between subdivisions to ensure that linear
327*d57664e9SAndroid Build Coastguard Worker     // interpolation works.
addBezier(const SkPoint * points,bezierCalculation bezierFunction,std::vector<SkPoint> & segmentPoints,std::vector<float> & lengths,float errorSquared,bool doubleCheckDivision)328*d57664e9SAndroid Build Coastguard Worker     static void addBezier(const SkPoint* points,
329*d57664e9SAndroid Build Coastguard Worker             bezierCalculation bezierFunction, std::vector<SkPoint>& segmentPoints,
330*d57664e9SAndroid Build Coastguard Worker             std::vector<float>& lengths, float errorSquared, bool doubleCheckDivision) {
331*d57664e9SAndroid Build Coastguard Worker         typedef std::map<float, SkPoint> PointMap;
332*d57664e9SAndroid Build Coastguard Worker         PointMap tToPoint;
333*d57664e9SAndroid Build Coastguard Worker 
334*d57664e9SAndroid Build Coastguard Worker         tToPoint[0] = (*bezierFunction)(0, points);
335*d57664e9SAndroid Build Coastguard Worker         tToPoint[1] = (*bezierFunction)(1, points);
336*d57664e9SAndroid Build Coastguard Worker 
337*d57664e9SAndroid Build Coastguard Worker         PointMap::iterator iter = tToPoint.begin();
338*d57664e9SAndroid Build Coastguard Worker         PointMap::iterator next = iter;
339*d57664e9SAndroid Build Coastguard Worker         ++next;
340*d57664e9SAndroid Build Coastguard Worker         while (next != tToPoint.end()) {
341*d57664e9SAndroid Build Coastguard Worker             bool needsSubdivision = true;
342*d57664e9SAndroid Build Coastguard Worker             SkPoint midPoint;
343*d57664e9SAndroid Build Coastguard Worker             do {
344*d57664e9SAndroid Build Coastguard Worker                 float midT;
345*d57664e9SAndroid Build Coastguard Worker                 needsSubdivision = subdividePoints(points, bezierFunction, iter->first,
346*d57664e9SAndroid Build Coastguard Worker                     iter->second, next->first, next->second, midT, midPoint, errorSquared);
347*d57664e9SAndroid Build Coastguard Worker                 if (!needsSubdivision && doubleCheckDivision) {
348*d57664e9SAndroid Build Coastguard Worker                     SkPoint quarterPoint;
349*d57664e9SAndroid Build Coastguard Worker                     float quarterT;
350*d57664e9SAndroid Build Coastguard Worker                     needsSubdivision = subdividePoints(points, bezierFunction, iter->first,
351*d57664e9SAndroid Build Coastguard Worker                         iter->second, midT, midPoint, quarterT, quarterPoint, errorSquared);
352*d57664e9SAndroid Build Coastguard Worker                     if (needsSubdivision) {
353*d57664e9SAndroid Build Coastguard Worker                         // Found an inflection point. No need to double-check.
354*d57664e9SAndroid Build Coastguard Worker                         doubleCheckDivision = false;
355*d57664e9SAndroid Build Coastguard Worker                     }
356*d57664e9SAndroid Build Coastguard Worker                 }
357*d57664e9SAndroid Build Coastguard Worker                 if (needsSubdivision) {
358*d57664e9SAndroid Build Coastguard Worker                     next = tToPoint.insert(iter, PointMap::value_type(midT, midPoint));
359*d57664e9SAndroid Build Coastguard Worker                 }
360*d57664e9SAndroid Build Coastguard Worker             } while (needsSubdivision);
361*d57664e9SAndroid Build Coastguard Worker             iter = next;
362*d57664e9SAndroid Build Coastguard Worker             next++;
363*d57664e9SAndroid Build Coastguard Worker         }
364*d57664e9SAndroid Build Coastguard Worker 
365*d57664e9SAndroid Build Coastguard Worker         // Now that each division can use linear interpolation with less than the allowed error
366*d57664e9SAndroid Build Coastguard Worker         for (iter = tToPoint.begin(); iter != tToPoint.end(); ++iter) {
367*d57664e9SAndroid Build Coastguard Worker             addLine(segmentPoints, lengths, iter->second);
368*d57664e9SAndroid Build Coastguard Worker         }
369*d57664e9SAndroid Build Coastguard Worker     }
370*d57664e9SAndroid Build Coastguard Worker 
createVerbSegments(const SkPath::Iter & pathIter,SkPath::Verb verb,const SkPoint * points,std::vector<SkPoint> & segmentPoints,std::vector<float> & lengths,float errorSquared,float errorConic)371*d57664e9SAndroid Build Coastguard Worker     static void createVerbSegments(const SkPath::Iter& pathIter, SkPath::Verb verb,
372*d57664e9SAndroid Build Coastguard Worker             const SkPoint* points, std::vector<SkPoint>& segmentPoints,
373*d57664e9SAndroid Build Coastguard Worker             std::vector<float>& lengths, float errorSquared, float errorConic) {
374*d57664e9SAndroid Build Coastguard Worker         switch (verb) {
375*d57664e9SAndroid Build Coastguard Worker             case SkPath::kMove_Verb:
376*d57664e9SAndroid Build Coastguard Worker                 addMove(segmentPoints, lengths, points[0]);
377*d57664e9SAndroid Build Coastguard Worker                 break;
378*d57664e9SAndroid Build Coastguard Worker             case SkPath::kClose_Verb:
379*d57664e9SAndroid Build Coastguard Worker                 addLine(segmentPoints, lengths, points[0]);
380*d57664e9SAndroid Build Coastguard Worker                 break;
381*d57664e9SAndroid Build Coastguard Worker             case SkPath::kLine_Verb:
382*d57664e9SAndroid Build Coastguard Worker                 addLine(segmentPoints, lengths, points[1]);
383*d57664e9SAndroid Build Coastguard Worker                 break;
384*d57664e9SAndroid Build Coastguard Worker             case SkPath::kQuad_Verb:
385*d57664e9SAndroid Build Coastguard Worker                 addBezier(points, quadraticBezierCalculation, segmentPoints, lengths,
386*d57664e9SAndroid Build Coastguard Worker                     errorSquared, false);
387*d57664e9SAndroid Build Coastguard Worker                 break;
388*d57664e9SAndroid Build Coastguard Worker             case SkPath::kCubic_Verb:
389*d57664e9SAndroid Build Coastguard Worker                 addBezier(points, cubicBezierCalculation, segmentPoints, lengths,
390*d57664e9SAndroid Build Coastguard Worker                     errorSquared, true);
391*d57664e9SAndroid Build Coastguard Worker                 break;
392*d57664e9SAndroid Build Coastguard Worker             case SkPath::kConic_Verb: {
393*d57664e9SAndroid Build Coastguard Worker                 SkAutoConicToQuads converter;
394*d57664e9SAndroid Build Coastguard Worker                 const SkPoint* quads = converter.computeQuads(
395*d57664e9SAndroid Build Coastguard Worker                         points, pathIter.conicWeight(), errorConic);
396*d57664e9SAndroid Build Coastguard Worker                 for (int i = 0; i < converter.countQuads(); i++) {
397*d57664e9SAndroid Build Coastguard Worker                     // Note: offset each subsequent quad by 2, since end points are shared
398*d57664e9SAndroid Build Coastguard Worker                     const SkPoint* quad = quads + i * 2;
399*d57664e9SAndroid Build Coastguard Worker                     addBezier(quad, quadraticBezierCalculation, segmentPoints, lengths,
400*d57664e9SAndroid Build Coastguard Worker                         errorConic, false);
401*d57664e9SAndroid Build Coastguard Worker                 }
402*d57664e9SAndroid Build Coastguard Worker                 break;
403*d57664e9SAndroid Build Coastguard Worker             }
404*d57664e9SAndroid Build Coastguard Worker             default:
405*d57664e9SAndroid Build Coastguard Worker                 static_assert(SkPath::kMove_Verb == 0
406*d57664e9SAndroid Build Coastguard Worker                                 && SkPath::kLine_Verb == 1
407*d57664e9SAndroid Build Coastguard Worker                                 && SkPath::kQuad_Verb == 2
408*d57664e9SAndroid Build Coastguard Worker                                 && SkPath::kConic_Verb == 3
409*d57664e9SAndroid Build Coastguard Worker                                 && SkPath::kCubic_Verb == 4
410*d57664e9SAndroid Build Coastguard Worker                                 && SkPath::kClose_Verb == 5
411*d57664e9SAndroid Build Coastguard Worker                                 && SkPath::kDone_Verb == 6,
412*d57664e9SAndroid Build Coastguard Worker                         "Path enum changed, new types may have been added.");
413*d57664e9SAndroid Build Coastguard Worker                 break;
414*d57664e9SAndroid Build Coastguard Worker         }
415*d57664e9SAndroid Build Coastguard Worker     }
416*d57664e9SAndroid Build Coastguard Worker 
417*d57664e9SAndroid Build Coastguard Worker     // Returns a float[] with each point along the path represented by 3 floats
418*d57664e9SAndroid Build Coastguard Worker     // * fractional length along the path that the point resides
419*d57664e9SAndroid Build Coastguard Worker     // * x coordinate
420*d57664e9SAndroid Build Coastguard Worker     // * y coordinate
421*d57664e9SAndroid Build Coastguard Worker     // Note that more than one point may have the same length along the path in
422*d57664e9SAndroid Build Coastguard Worker     // the case of a move.
423*d57664e9SAndroid Build Coastguard Worker     // NULL can be returned if the Path is empty.
approximate(JNIEnv * env,jclass clazz,jlong pathHandle,float acceptableError)424*d57664e9SAndroid Build Coastguard Worker     static jfloatArray approximate(JNIEnv* env, jclass clazz, jlong pathHandle,
425*d57664e9SAndroid Build Coastguard Worker             float acceptableError) {
426*d57664e9SAndroid Build Coastguard Worker         SkPath* path = reinterpret_cast<SkPath*>(pathHandle);
427*d57664e9SAndroid Build Coastguard Worker         SkASSERT(path);
428*d57664e9SAndroid Build Coastguard Worker         SkPath::Iter pathIter(*path, false);
429*d57664e9SAndroid Build Coastguard Worker         SkPath::Verb verb;
430*d57664e9SAndroid Build Coastguard Worker         SkPoint points[4];
431*d57664e9SAndroid Build Coastguard Worker         std::vector<SkPoint> segmentPoints;
432*d57664e9SAndroid Build Coastguard Worker         std::vector<float> lengths;
433*d57664e9SAndroid Build Coastguard Worker         float errorSquared = acceptableError * acceptableError;
434*d57664e9SAndroid Build Coastguard Worker         float errorConic = acceptableError / 2; // somewhat arbitrary
435*d57664e9SAndroid Build Coastguard Worker 
436*d57664e9SAndroid Build Coastguard Worker         while ((verb = pathIter.next(points)) != SkPath::kDone_Verb) {
437*d57664e9SAndroid Build Coastguard Worker             createVerbSegments(pathIter, verb, points, segmentPoints, lengths,
438*d57664e9SAndroid Build Coastguard Worker                     errorSquared, errorConic);
439*d57664e9SAndroid Build Coastguard Worker         }
440*d57664e9SAndroid Build Coastguard Worker 
441*d57664e9SAndroid Build Coastguard Worker         if (segmentPoints.empty()) {
442*d57664e9SAndroid Build Coastguard Worker             int numVerbs = path->countVerbs();
443*d57664e9SAndroid Build Coastguard Worker             if (numVerbs == 1) {
444*d57664e9SAndroid Build Coastguard Worker                 addMove(segmentPoints, lengths, path->getPoint(0));
445*d57664e9SAndroid Build Coastguard Worker             } else {
446*d57664e9SAndroid Build Coastguard Worker                 // Invalid or empty path. Fall back to point(0,0)
447*d57664e9SAndroid Build Coastguard Worker                 addMove(segmentPoints, lengths, SkPoint());
448*d57664e9SAndroid Build Coastguard Worker             }
449*d57664e9SAndroid Build Coastguard Worker         }
450*d57664e9SAndroid Build Coastguard Worker 
451*d57664e9SAndroid Build Coastguard Worker         float totalLength = lengths.back();
452*d57664e9SAndroid Build Coastguard Worker         if (totalLength == 0) {
453*d57664e9SAndroid Build Coastguard Worker             // Lone Move instructions should still be able to animate at the same value.
454*d57664e9SAndroid Build Coastguard Worker             segmentPoints.push_back(segmentPoints.back());
455*d57664e9SAndroid Build Coastguard Worker             lengths.push_back(1);
456*d57664e9SAndroid Build Coastguard Worker             totalLength = 1;
457*d57664e9SAndroid Build Coastguard Worker         }
458*d57664e9SAndroid Build Coastguard Worker 
459*d57664e9SAndroid Build Coastguard Worker         size_t numPoints = segmentPoints.size();
460*d57664e9SAndroid Build Coastguard Worker         size_t approximationArraySize = numPoints * 3;
461*d57664e9SAndroid Build Coastguard Worker 
462*d57664e9SAndroid Build Coastguard Worker         float* approximation = new float[approximationArraySize];
463*d57664e9SAndroid Build Coastguard Worker 
464*d57664e9SAndroid Build Coastguard Worker         int approximationIndex = 0;
465*d57664e9SAndroid Build Coastguard Worker         for (size_t i = 0; i < numPoints; i++) {
466*d57664e9SAndroid Build Coastguard Worker             const SkPoint& point = segmentPoints[i];
467*d57664e9SAndroid Build Coastguard Worker             approximation[approximationIndex++] = lengths[i] / totalLength;
468*d57664e9SAndroid Build Coastguard Worker             approximation[approximationIndex++] = point.x();
469*d57664e9SAndroid Build Coastguard Worker             approximation[approximationIndex++] = point.y();
470*d57664e9SAndroid Build Coastguard Worker         }
471*d57664e9SAndroid Build Coastguard Worker 
472*d57664e9SAndroid Build Coastguard Worker         jfloatArray result = env->NewFloatArray(approximationArraySize);
473*d57664e9SAndroid Build Coastguard Worker         env->SetFloatArrayRegion(result, 0, approximationArraySize, approximation);
474*d57664e9SAndroid Build Coastguard Worker         delete[] approximation;
475*d57664e9SAndroid Build Coastguard Worker         return result;
476*d57664e9SAndroid Build Coastguard Worker     }
477*d57664e9SAndroid Build Coastguard Worker 
478*d57664e9SAndroid Build Coastguard Worker     // ---------------- @FastNative -----------------------------
479*d57664e9SAndroid Build Coastguard Worker 
isRect(JNIEnv * env,jclass clazz,jlong objHandle,jobject jrect)480*d57664e9SAndroid Build Coastguard Worker     static jboolean isRect(JNIEnv* env, jclass clazz, jlong objHandle, jobject jrect) {
481*d57664e9SAndroid Build Coastguard Worker         SkRect rect;
482*d57664e9SAndroid Build Coastguard Worker         SkPath* obj = reinterpret_cast<SkPath*>(objHandle);
483*d57664e9SAndroid Build Coastguard Worker         jboolean result = obj->isRect(&rect);
484*d57664e9SAndroid Build Coastguard Worker         if (jrect) {
485*d57664e9SAndroid Build Coastguard Worker             GraphicsJNI::rect_to_jrectf(rect, env, jrect);
486*d57664e9SAndroid Build Coastguard Worker         }
487*d57664e9SAndroid Build Coastguard Worker         return result;
488*d57664e9SAndroid Build Coastguard Worker     }
489*d57664e9SAndroid Build Coastguard Worker 
490*d57664e9SAndroid Build Coastguard Worker     // ---------------- @CriticalNative -------------------------
491*d57664e9SAndroid Build Coastguard Worker 
getGenerationID(CRITICAL_JNI_PARAMS_COMMA jlong pathHandle)492*d57664e9SAndroid Build Coastguard Worker     static jint getGenerationID(CRITICAL_JNI_PARAMS_COMMA jlong pathHandle) {
493*d57664e9SAndroid Build Coastguard Worker         return (reinterpret_cast<SkPath*>(pathHandle)->getGenerationID());
494*d57664e9SAndroid Build Coastguard Worker     }
495*d57664e9SAndroid Build Coastguard Worker 
isInterpolatable(CRITICAL_JNI_PARAMS_COMMA jlong startHandle,jlong endHandle)496*d57664e9SAndroid Build Coastguard Worker     static jboolean isInterpolatable(CRITICAL_JNI_PARAMS_COMMA jlong startHandle, jlong endHandle) {
497*d57664e9SAndroid Build Coastguard Worker         SkPath* startPath = reinterpret_cast<SkPath*>(startHandle);
498*d57664e9SAndroid Build Coastguard Worker         SkPath* endPath = reinterpret_cast<SkPath*>(endHandle);
499*d57664e9SAndroid Build Coastguard Worker         return startPath->isInterpolatable(*endPath);
500*d57664e9SAndroid Build Coastguard Worker     }
501*d57664e9SAndroid Build Coastguard Worker 
reset(CRITICAL_JNI_PARAMS_COMMA jlong objHandle)502*d57664e9SAndroid Build Coastguard Worker     static void reset(CRITICAL_JNI_PARAMS_COMMA jlong objHandle) {
503*d57664e9SAndroid Build Coastguard Worker         SkPath* obj = reinterpret_cast<SkPath*>(objHandle);
504*d57664e9SAndroid Build Coastguard Worker         obj->reset();
505*d57664e9SAndroid Build Coastguard Worker     }
506*d57664e9SAndroid Build Coastguard Worker 
rewind(CRITICAL_JNI_PARAMS_COMMA jlong objHandle)507*d57664e9SAndroid Build Coastguard Worker     static void rewind(CRITICAL_JNI_PARAMS_COMMA jlong objHandle) {
508*d57664e9SAndroid Build Coastguard Worker         SkPath* obj = reinterpret_cast<SkPath*>(objHandle);
509*d57664e9SAndroid Build Coastguard Worker         obj->rewind();
510*d57664e9SAndroid Build Coastguard Worker     }
511*d57664e9SAndroid Build Coastguard Worker 
isEmpty(CRITICAL_JNI_PARAMS_COMMA jlong objHandle)512*d57664e9SAndroid Build Coastguard Worker     static jboolean isEmpty(CRITICAL_JNI_PARAMS_COMMA jlong objHandle) {
513*d57664e9SAndroid Build Coastguard Worker         SkPath* obj = reinterpret_cast<SkPath*>(objHandle);
514*d57664e9SAndroid Build Coastguard Worker         return obj->isEmpty();
515*d57664e9SAndroid Build Coastguard Worker     }
516*d57664e9SAndroid Build Coastguard Worker 
isConvex(CRITICAL_JNI_PARAMS_COMMA jlong objHandle)517*d57664e9SAndroid Build Coastguard Worker     static jboolean isConvex(CRITICAL_JNI_PARAMS_COMMA jlong objHandle) {
518*d57664e9SAndroid Build Coastguard Worker         SkPath* obj = reinterpret_cast<SkPath*>(objHandle);
519*d57664e9SAndroid Build Coastguard Worker         return obj->isConvex();
520*d57664e9SAndroid Build Coastguard Worker     }
521*d57664e9SAndroid Build Coastguard Worker 
getFillType(CRITICAL_JNI_PARAMS_COMMA jlong objHandle)522*d57664e9SAndroid Build Coastguard Worker     static jint getFillType(CRITICAL_JNI_PARAMS_COMMA jlong objHandle) {
523*d57664e9SAndroid Build Coastguard Worker         SkPath* obj = reinterpret_cast<SkPath*>(objHandle);
524*d57664e9SAndroid Build Coastguard Worker         return static_cast<int>(obj->getFillType());
525*d57664e9SAndroid Build Coastguard Worker     }
526*d57664e9SAndroid Build Coastguard Worker 
setFillType(CRITICAL_JNI_PARAMS_COMMA jlong pathHandle,jint ftHandle)527*d57664e9SAndroid Build Coastguard Worker     static void setFillType(CRITICAL_JNI_PARAMS_COMMA jlong pathHandle, jint ftHandle) {;
528*d57664e9SAndroid Build Coastguard Worker         SkPath* path = reinterpret_cast<SkPath*>(pathHandle);
529*d57664e9SAndroid Build Coastguard Worker         SkPathFillType ft = static_cast<SkPathFillType>(ftHandle);
530*d57664e9SAndroid Build Coastguard Worker         path->setFillType(ft);
531*d57664e9SAndroid Build Coastguard Worker     }
532*d57664e9SAndroid Build Coastguard Worker };
533*d57664e9SAndroid Build Coastguard Worker 
534*d57664e9SAndroid Build Coastguard Worker static const JNINativeMethod methods[] = {
535*d57664e9SAndroid Build Coastguard Worker         {"nInit", "()J", (void*)SkPathGlue::init},
536*d57664e9SAndroid Build Coastguard Worker         {"nInit", "(J)J", (void*)SkPathGlue::init_Path},
537*d57664e9SAndroid Build Coastguard Worker         {"nGetFinalizer", "()J", (void*)SkPathGlue::getFinalizer},
538*d57664e9SAndroid Build Coastguard Worker         {"nSet", "(JJ)V", (void*)SkPathGlue::set},
539*d57664e9SAndroid Build Coastguard Worker         {"nComputeBounds", "(JLandroid/graphics/RectF;)V", (void*)SkPathGlue::computeBounds},
540*d57664e9SAndroid Build Coastguard Worker         {"nIncReserve", "(JI)V", (void*)SkPathGlue::incReserve},
541*d57664e9SAndroid Build Coastguard Worker         {"nMoveTo", "(JFF)V", (void*)SkPathGlue::moveTo__FF},
542*d57664e9SAndroid Build Coastguard Worker         {"nRMoveTo", "(JFF)V", (void*)SkPathGlue::rMoveTo},
543*d57664e9SAndroid Build Coastguard Worker         {"nLineTo", "(JFF)V", (void*)SkPathGlue::lineTo__FF},
544*d57664e9SAndroid Build Coastguard Worker         {"nRLineTo", "(JFF)V", (void*)SkPathGlue::rLineTo},
545*d57664e9SAndroid Build Coastguard Worker         {"nQuadTo", "(JFFFF)V", (void*)SkPathGlue::quadTo__FFFF},
546*d57664e9SAndroid Build Coastguard Worker         {"nRQuadTo", "(JFFFF)V", (void*)SkPathGlue::rQuadTo},
547*d57664e9SAndroid Build Coastguard Worker         {"nConicTo", "(JFFFFF)V", (void*)SkPathGlue::conicTo},
548*d57664e9SAndroid Build Coastguard Worker         {"nRConicTo", "(JFFFFF)V", (void*)SkPathGlue::rConicTo},
549*d57664e9SAndroid Build Coastguard Worker         {"nCubicTo", "(JFFFFFF)V", (void*)SkPathGlue::cubicTo__FFFFFF},
550*d57664e9SAndroid Build Coastguard Worker         {"nRCubicTo", "(JFFFFFF)V", (void*)SkPathGlue::rCubicTo},
551*d57664e9SAndroid Build Coastguard Worker         {"nArcTo", "(JFFFFFFZ)V", (void*)SkPathGlue::arcTo},
552*d57664e9SAndroid Build Coastguard Worker         {"nClose", "(J)V", (void*)SkPathGlue::close},
553*d57664e9SAndroid Build Coastguard Worker         {"nAddRect", "(JFFFFI)V", (void*)SkPathGlue::addRect},
554*d57664e9SAndroid Build Coastguard Worker         {"nAddOval", "(JFFFFI)V", (void*)SkPathGlue::addOval},
555*d57664e9SAndroid Build Coastguard Worker         {"nAddCircle", "(JFFFI)V", (void*)SkPathGlue::addCircle},
556*d57664e9SAndroid Build Coastguard Worker         {"nAddArc", "(JFFFFFF)V", (void*)SkPathGlue::addArc},
557*d57664e9SAndroid Build Coastguard Worker         {"nAddRoundRect", "(JFFFFFFI)V", (void*)SkPathGlue::addRoundRectXY},
558*d57664e9SAndroid Build Coastguard Worker         {"nAddRoundRect", "(JFFFF[FI)V", (void*)SkPathGlue::addRoundRect8},
559*d57664e9SAndroid Build Coastguard Worker         {"nAddPath", "(JJFF)V", (void*)SkPathGlue::addPath__PathFF},
560*d57664e9SAndroid Build Coastguard Worker         {"nAddPath", "(JJ)V", (void*)SkPathGlue::addPath__Path},
561*d57664e9SAndroid Build Coastguard Worker         {"nAddPath", "(JJJ)V", (void*)SkPathGlue::addPath__PathMatrix},
562*d57664e9SAndroid Build Coastguard Worker         {"nInterpolate", "(JJFJ)Z", (void*)SkPathGlue::interpolate},
563*d57664e9SAndroid Build Coastguard Worker         {"nOffset", "(JFF)V", (void*)SkPathGlue::offset__FF},
564*d57664e9SAndroid Build Coastguard Worker         {"nSetLastPoint", "(JFF)V", (void*)SkPathGlue::setLastPoint},
565*d57664e9SAndroid Build Coastguard Worker         {"nTransform", "(JJJ)V", (void*)SkPathGlue::transform__MatrixPath},
566*d57664e9SAndroid Build Coastguard Worker         {"nTransform", "(JJ)V", (void*)SkPathGlue::transform__Matrix},
567*d57664e9SAndroid Build Coastguard Worker         {"nOp", "(JJIJ)Z", (void*)SkPathGlue::op},
568*d57664e9SAndroid Build Coastguard Worker         {"nApproximate", "(JF)[F", (void*)SkPathGlue::approximate},
569*d57664e9SAndroid Build Coastguard Worker 
570*d57664e9SAndroid Build Coastguard Worker         // ------- @FastNative below here ----------------------
571*d57664e9SAndroid Build Coastguard Worker         {"nIsRect", "(JLandroid/graphics/RectF;)Z", (void*)SkPathGlue::isRect},
572*d57664e9SAndroid Build Coastguard Worker 
573*d57664e9SAndroid Build Coastguard Worker         // ------- @CriticalNative below here ------------------
574*d57664e9SAndroid Build Coastguard Worker         {"nGetGenerationID", "(J)I", (void*)SkPathGlue::getGenerationID},
575*d57664e9SAndroid Build Coastguard Worker         {"nIsInterpolatable", "(JJ)Z", (void*)SkPathGlue::isInterpolatable},
576*d57664e9SAndroid Build Coastguard Worker         {"nReset", "(J)V", (void*)SkPathGlue::reset},
577*d57664e9SAndroid Build Coastguard Worker         {"nRewind", "(J)V", (void*)SkPathGlue::rewind},
578*d57664e9SAndroid Build Coastguard Worker         {"nIsEmpty", "(J)Z", (void*)SkPathGlue::isEmpty},
579*d57664e9SAndroid Build Coastguard Worker         {"nIsConvex", "(J)Z", (void*)SkPathGlue::isConvex},
580*d57664e9SAndroid Build Coastguard Worker         {"nGetFillType", "(J)I", (void*)SkPathGlue::getFillType},
581*d57664e9SAndroid Build Coastguard Worker         {"nSetFillType", "(JI)V", (void*)SkPathGlue::setFillType},
582*d57664e9SAndroid Build Coastguard Worker };
583*d57664e9SAndroid Build Coastguard Worker 
register_android_graphics_Path(JNIEnv * env)584*d57664e9SAndroid Build Coastguard Worker int register_android_graphics_Path(JNIEnv* env) {
585*d57664e9SAndroid Build Coastguard Worker     return RegisterMethodsOrDie(env, "android/graphics/Path", methods, NELEM(methods));
586*d57664e9SAndroid Build Coastguard Worker 
587*d57664e9SAndroid Build Coastguard Worker     static_assert(0 == (int)SkPathDirection::kCW,  "direction_mismatch");
588*d57664e9SAndroid Build Coastguard Worker     static_assert(1 == (int)SkPathDirection::kCCW, "direction_mismatch");
589*d57664e9SAndroid Build Coastguard Worker }
590*d57664e9SAndroid Build Coastguard Worker 
591*d57664e9SAndroid Build Coastguard Worker }
592