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