1 /*
2  * Copyright (C) 2006 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.graphics;
18 
19 /**
20  * The Path class encapsulates compound (multiple contour) geometric paths
21  * consisting of straight line segments, quadratic curves, and cubic curves.
22  * It can be drawn with canvas.drawPath(path, paint), either filled or stroked
23  * (based on the paint's Style), or it can be used for clipping or to draw
24  * text on a path.
25  */
26 public class Path {
27     /**
28      * @hide
29      */
30     public final long mNativePath;
31 
32     /**
33      * @hide
34      */
35     public boolean isSimplePath = true;
36     /**
37      * @hide
38      */
39     public Region rects;
40     private Direction mLastDirection = null;
41 
42     /**
43      * Create an empty path
44      */
Path()45     public Path() {
46         mNativePath = init1();
47     }
48 
49     /**
50      * Create a new path, copying the contents from the src path.
51      *
52      * @param src The path to copy from when initializing the new path
53      */
Path(Path src)54     public Path(Path src) {
55         long valNative = 0;
56         if (src != null) {
57             valNative = src.mNativePath;
58             isSimplePath = src.isSimplePath;
59             if (src.rects != null) {
60                 rects = new Region(src.rects);
61             }
62         }
63         mNativePath = init2(valNative);
64     }
65 
66     /**
67      * Clear any lines and curves from the path, making it empty.
68      * This does NOT change the fill-type setting.
69      */
reset()70     public void reset() {
71         isSimplePath = true;
72         mLastDirection = null;
73         if (rects != null) rects.setEmpty();
74         // We promised not to change this, so preserve it around the native
75         // call, which does now reset fill type.
76         final FillType fillType = getFillType();
77         native_reset(mNativePath);
78         setFillType(fillType);
79     }
80 
81     /**
82      * Rewinds the path: clears any lines and curves from the path but
83      * keeps the internal data structure for faster reuse.
84      */
rewind()85     public void rewind() {
86         isSimplePath = true;
87         mLastDirection = null;
88         if (rects != null) rects.setEmpty();
89         native_rewind(mNativePath);
90     }
91 
92     /** Replace the contents of this with the contents of src.
93     */
set(Path src)94     public void set(Path src) {
95         if (this != src) {
96             isSimplePath = src.isSimplePath;
97             native_set(mNativePath, src.mNativePath);
98         }
99     }
100 
101     /**
102      * The logical operations that can be performed when combining two paths.
103      *
104      * @see #op(Path, android.graphics.Path.Op)
105      * @see #op(Path, Path, android.graphics.Path.Op)
106      */
107     public enum Op {
108         /**
109          * Subtract the second path from the first path.
110          */
111         DIFFERENCE,
112         /**
113          * Intersect the two paths.
114          */
115         INTERSECT,
116         /**
117          * Union (inclusive-or) the two paths.
118          */
119         UNION,
120         /**
121          * Exclusive-or the two paths.
122          */
123         XOR,
124         /**
125          * Subtract the first path from the second path.
126          */
127         REVERSE_DIFFERENCE
128     }
129 
130     /**
131      * Set this path to the result of applying the Op to this path and the specified path.
132      * The resulting path will be constructed from non-overlapping contours.
133      * The curve order is reduced where possible so that cubics may be turned
134      * into quadratics, and quadratics maybe turned into lines.
135      *
136      * @param path The second operand (for difference, the subtrahend)
137      *
138      * @return True if operation succeeded, false otherwise and this path remains unmodified.
139      *
140      * @see Op
141      * @see #op(Path, Path, android.graphics.Path.Op)
142      */
op(Path path, Op op)143     public boolean op(Path path, Op op) {
144         return op(this, path, op);
145     }
146 
147     /**
148      * Set this path to the result of applying the Op to the two specified paths.
149      * The resulting path will be constructed from non-overlapping contours.
150      * The curve order is reduced where possible so that cubics may be turned
151      * into quadratics, and quadratics maybe turned into lines.
152      *
153      * @param path1 The first operand (for difference, the minuend)
154      * @param path2 The second operand (for difference, the subtrahend)
155      *
156      * @return True if operation succeeded, false otherwise and this path remains unmodified.
157      *
158      * @see Op
159      * @see #op(Path, android.graphics.Path.Op)
160      */
op(Path path1, Path path2, Op op)161     public boolean op(Path path1, Path path2, Op op) {
162         if (native_op(path1.mNativePath, path2.mNativePath, op.ordinal(), this.mNativePath)) {
163             isSimplePath = false;
164             rects = null;
165             return true;
166         }
167         return false;
168     }
169 
170     /**
171      * Returns the path's convexity, as defined by the content of the path.
172      * <p>
173      * A path is convex if it has a single contour, and only ever curves in a
174      * single direction.
175      * <p>
176      * This function will calculate the convexity of the path from its control
177      * points, and cache the result.
178      *
179      * @return True if the path is convex.
180      */
isConvex()181     public boolean isConvex() {
182         return native_isConvex(mNativePath);
183     }
184 
185     /**
186      * Enum for the ways a path may be filled.
187      */
188     public enum FillType {
189         // these must match the values in SkPath.h
190         /**
191          * Specifies that "inside" is computed by a non-zero sum of signed
192          * edge crossings.
193          */
194         WINDING         (0),
195         /**
196          * Specifies that "inside" is computed by an odd number of edge
197          * crossings.
198          */
199         EVEN_ODD        (1),
200         /**
201          * Same as {@link #WINDING}, but draws outside of the path, rather than inside.
202          */
203         INVERSE_WINDING (2),
204         /**
205          * Same as {@link #EVEN_ODD}, but draws outside of the path, rather than inside.
206          */
207         INVERSE_EVEN_ODD(3);
208 
FillType(int ni)209         FillType(int ni) {
210             nativeInt = ni;
211         }
212 
213         final int nativeInt;
214     }
215 
216     // these must be in the same order as their native values
217     static final FillType[] sFillTypeArray = {
218         FillType.WINDING,
219         FillType.EVEN_ODD,
220         FillType.INVERSE_WINDING,
221         FillType.INVERSE_EVEN_ODD
222     };
223 
224     /**
225      * Return the path's fill type. This defines how "inside" is
226      * computed. The default value is WINDING.
227      *
228      * @return the path's fill type
229      */
getFillType()230     public FillType getFillType() {
231         return sFillTypeArray[native_getFillType(mNativePath)];
232     }
233 
234     /**
235      * Set the path's fill type. This defines how "inside" is computed.
236      *
237      * @param ft The new fill type for this path
238      */
setFillType(FillType ft)239     public void setFillType(FillType ft) {
240         native_setFillType(mNativePath, ft.nativeInt);
241     }
242 
243     /**
244      * Returns true if the filltype is one of the INVERSE variants
245      *
246      * @return true if the filltype is one of the INVERSE variants
247      */
isInverseFillType()248     public boolean isInverseFillType() {
249         final int ft = native_getFillType(mNativePath);
250         return (ft & FillType.INVERSE_WINDING.nativeInt) != 0;
251     }
252 
253     /**
254      * Toggles the INVERSE state of the filltype
255      */
toggleInverseFillType()256     public void toggleInverseFillType() {
257         int ft = native_getFillType(mNativePath);
258         ft ^= FillType.INVERSE_WINDING.nativeInt;
259         native_setFillType(mNativePath, ft);
260     }
261 
262     /**
263      * Returns true if the path is empty (contains no lines or curves)
264      *
265      * @return true if the path is empty (contains no lines or curves)
266      */
isEmpty()267     public boolean isEmpty() {
268         return native_isEmpty(mNativePath);
269     }
270 
271     /**
272      * Returns true if the path specifies a rectangle. If so, and if rect is
273      * not null, set rect to the bounds of the path. If the path does not
274      * specify a rectangle, return false and ignore rect.
275      *
276      * @param rect If not null, returns the bounds of the path if it specifies
277      *             a rectangle
278      * @return     true if the path specifies a rectangle
279      */
isRect(RectF rect)280     public boolean isRect(RectF rect) {
281         return native_isRect(mNativePath, rect);
282     }
283 
284     /**
285      * Compute the bounds of the control points of the path, and write the
286      * answer into bounds. If the path contains 0 or 1 points, the bounds is
287      * set to (0,0,0,0)
288      *
289      * @param bounds Returns the computed bounds of the path's control points.
290      * @param exact This parameter is no longer used.
291      */
292     @SuppressWarnings({"UnusedDeclaration"})
computeBounds(RectF bounds, boolean exact)293     public void computeBounds(RectF bounds, boolean exact) {
294         native_computeBounds(mNativePath, bounds);
295     }
296 
297     /**
298      * Hint to the path to prepare for adding more points. This can allow the
299      * path to more efficiently allocate its storage.
300      *
301      * @param extraPtCount The number of extra points that may be added to this
302      *                     path
303      */
incReserve(int extraPtCount)304     public void incReserve(int extraPtCount) {
305         native_incReserve(mNativePath, extraPtCount);
306     }
307 
308     /**
309      * Set the beginning of the next contour to the point (x,y).
310      *
311      * @param x The x-coordinate of the start of a new contour
312      * @param y The y-coordinate of the start of a new contour
313      */
moveTo(float x, float y)314     public void moveTo(float x, float y) {
315         native_moveTo(mNativePath, x, y);
316     }
317 
318     /**
319      * Set the beginning of the next contour relative to the last point on the
320      * previous contour. If there is no previous contour, this is treated the
321      * same as moveTo().
322      *
323      * @param dx The amount to add to the x-coordinate of the end of the
324      *           previous contour, to specify the start of a new contour
325      * @param dy The amount to add to the y-coordinate of the end of the
326      *           previous contour, to specify the start of a new contour
327      */
rMoveTo(float dx, float dy)328     public void rMoveTo(float dx, float dy) {
329         native_rMoveTo(mNativePath, dx, dy);
330     }
331 
332     /**
333      * Add a line from the last point to the specified point (x,y).
334      * If no moveTo() call has been made for this contour, the first point is
335      * automatically set to (0,0).
336      *
337      * @param x The x-coordinate of the end of a line
338      * @param y The y-coordinate of the end of a line
339      */
lineTo(float x, float y)340     public void lineTo(float x, float y) {
341         isSimplePath = false;
342         native_lineTo(mNativePath, x, y);
343     }
344 
345     /**
346      * Same as lineTo, but the coordinates are considered relative to the last
347      * point on this contour. If there is no previous point, then a moveTo(0,0)
348      * is inserted automatically.
349      *
350      * @param dx The amount to add to the x-coordinate of the previous point on
351      *           this contour, to specify a line
352      * @param dy The amount to add to the y-coordinate of the previous point on
353      *           this contour, to specify a line
354      */
rLineTo(float dx, float dy)355     public void rLineTo(float dx, float dy) {
356         isSimplePath = false;
357         native_rLineTo(mNativePath, dx, dy);
358     }
359 
360     /**
361      * Add a quadratic bezier from the last point, approaching control point
362      * (x1,y1), and ending at (x2,y2). If no moveTo() call has been made for
363      * this contour, the first point is automatically set to (0,0).
364      *
365      * @param x1 The x-coordinate of the control point on a quadratic curve
366      * @param y1 The y-coordinate of the control point on a quadratic curve
367      * @param x2 The x-coordinate of the end point on a quadratic curve
368      * @param y2 The y-coordinate of the end point on a quadratic curve
369      */
quadTo(float x1, float y1, float x2, float y2)370     public void quadTo(float x1, float y1, float x2, float y2) {
371         isSimplePath = false;
372         native_quadTo(mNativePath, x1, y1, x2, y2);
373     }
374 
375     /**
376      * Same as quadTo, but the coordinates are considered relative to the last
377      * point on this contour. If there is no previous point, then a moveTo(0,0)
378      * is inserted automatically.
379      *
380      * @param dx1 The amount to add to the x-coordinate of the last point on
381      *            this contour, for the control point of a quadratic curve
382      * @param dy1 The amount to add to the y-coordinate of the last point on
383      *            this contour, for the control point of a quadratic curve
384      * @param dx2 The amount to add to the x-coordinate of the last point on
385      *            this contour, for the end point of a quadratic curve
386      * @param dy2 The amount to add to the y-coordinate of the last point on
387      *            this contour, for the end point of a quadratic curve
388      */
rQuadTo(float dx1, float dy1, float dx2, float dy2)389     public void rQuadTo(float dx1, float dy1, float dx2, float dy2) {
390         isSimplePath = false;
391         native_rQuadTo(mNativePath, dx1, dy1, dx2, dy2);
392     }
393 
394     /**
395      * Add a cubic bezier from the last point, approaching control points
396      * (x1,y1) and (x2,y2), and ending at (x3,y3). If no moveTo() call has been
397      * made for this contour, the first point is automatically set to (0,0).
398      *
399      * @param x1 The x-coordinate of the 1st control point on a cubic curve
400      * @param y1 The y-coordinate of the 1st control point on a cubic curve
401      * @param x2 The x-coordinate of the 2nd control point on a cubic curve
402      * @param y2 The y-coordinate of the 2nd control point on a cubic curve
403      * @param x3 The x-coordinate of the end point on a cubic curve
404      * @param y3 The y-coordinate of the end point on a cubic curve
405      */
cubicTo(float x1, float y1, float x2, float y2, float x3, float y3)406     public void cubicTo(float x1, float y1, float x2, float y2,
407                         float x3, float y3) {
408         isSimplePath = false;
409         native_cubicTo(mNativePath, x1, y1, x2, y2, x3, y3);
410     }
411 
412     /**
413      * Same as cubicTo, but the coordinates are considered relative to the
414      * current point on this contour. If there is no previous point, then a
415      * moveTo(0,0) is inserted automatically.
416      */
rCubicTo(float x1, float y1, float x2, float y2, float x3, float y3)417     public void rCubicTo(float x1, float y1, float x2, float y2,
418                          float x3, float y3) {
419         isSimplePath = false;
420         native_rCubicTo(mNativePath, x1, y1, x2, y2, x3, y3);
421     }
422 
423     /**
424      * Append the specified arc to the path as a new contour. If the start of
425      * the path is different from the path's current last point, then an
426      * automatic lineTo() is added to connect the current contour to the
427      * start of the arc. However, if the path is empty, then we call moveTo()
428      * with the first point of the arc.
429      *
430      * @param oval        The bounds of oval defining shape and size of the arc
431      * @param startAngle  Starting angle (in degrees) where the arc begins
432      * @param sweepAngle  Sweep angle (in degrees) measured clockwise, treated
433      *                    mod 360.
434      * @param forceMoveTo If true, always begin a new contour with the arc
435      */
arcTo(RectF oval, float startAngle, float sweepAngle, boolean forceMoveTo)436     public void arcTo(RectF oval, float startAngle, float sweepAngle,
437                       boolean forceMoveTo) {
438         arcTo(oval.left, oval.top, oval.right, oval.bottom, startAngle, sweepAngle, forceMoveTo);
439     }
440 
441     /**
442      * Append the specified arc to the path as a new contour. If the start of
443      * the path is different from the path's current last point, then an
444      * automatic lineTo() is added to connect the current contour to the
445      * start of the arc. However, if the path is empty, then we call moveTo()
446      * with the first point of the arc.
447      *
448      * @param oval        The bounds of oval defining shape and size of the arc
449      * @param startAngle  Starting angle (in degrees) where the arc begins
450      * @param sweepAngle  Sweep angle (in degrees) measured clockwise
451      */
arcTo(RectF oval, float startAngle, float sweepAngle)452     public void arcTo(RectF oval, float startAngle, float sweepAngle) {
453         arcTo(oval.left, oval.top, oval.right, oval.bottom, startAngle, sweepAngle, false);
454     }
455 
456     /**
457      * Append the specified arc to the path as a new contour. If the start of
458      * the path is different from the path's current last point, then an
459      * automatic lineTo() is added to connect the current contour to the
460      * start of the arc. However, if the path is empty, then we call moveTo()
461      * with the first point of the arc.
462      *
463      * @param startAngle  Starting angle (in degrees) where the arc begins
464      * @param sweepAngle  Sweep angle (in degrees) measured clockwise, treated
465      *                    mod 360.
466      * @param forceMoveTo If true, always begin a new contour with the arc
467      */
arcTo(float left, float top, float right, float bottom, float startAngle, float sweepAngle, boolean forceMoveTo)468     public void arcTo(float left, float top, float right, float bottom, float startAngle,
469             float sweepAngle, boolean forceMoveTo) {
470         isSimplePath = false;
471         native_arcTo(mNativePath, left, top, right, bottom, startAngle, sweepAngle, forceMoveTo);
472     }
473 
474     /**
475      * Close the current contour. If the current point is not equal to the
476      * first point of the contour, a line segment is automatically added.
477      */
close()478     public void close() {
479         isSimplePath = false;
480         native_close(mNativePath);
481     }
482 
483     /**
484      * Specifies how closed shapes (e.g. rects, ovals) are oriented when they
485      * are added to a path.
486      */
487     public enum Direction {
488         /** clockwise */
489         CW  (1),    // must match enum in SkPath.h
490         /** counter-clockwise */
491         CCW (2);    // must match enum in SkPath.h
492 
Direction(int ni)493         Direction(int ni) {
494             nativeInt = ni;
495         }
496         final int nativeInt;
497     }
498 
detectSimplePath(float left, float top, float right, float bottom, Direction dir)499     private void detectSimplePath(float left, float top, float right, float bottom, Direction dir) {
500         if (mLastDirection == null) {
501             mLastDirection = dir;
502         }
503         if (mLastDirection != dir) {
504             isSimplePath = false;
505         } else {
506             if (rects == null) rects = new Region();
507             rects.op((int) left, (int) top, (int) right, (int) bottom, Region.Op.UNION);
508         }
509     }
510 
511     /**
512      * Add a closed rectangle contour to the path
513      *
514      * @param rect The rectangle to add as a closed contour to the path
515      * @param dir  The direction to wind the rectangle's contour
516      */
addRect(RectF rect, Direction dir)517     public void addRect(RectF rect, Direction dir) {
518         addRect(rect.left, rect.top, rect.right, rect.bottom, dir);
519     }
520 
521     /**
522      * Add a closed rectangle contour to the path
523      *
524      * @param left   The left side of a rectangle to add to the path
525      * @param top    The top of a rectangle to add to the path
526      * @param right  The right side of a rectangle to add to the path
527      * @param bottom The bottom of a rectangle to add to the path
528      * @param dir    The direction to wind the rectangle's contour
529      */
addRect(float left, float top, float right, float bottom, Direction dir)530     public void addRect(float left, float top, float right, float bottom, Direction dir) {
531         detectSimplePath(left, top, right, bottom, dir);
532         native_addRect(mNativePath, left, top, right, bottom, dir.nativeInt);
533     }
534 
535     /**
536      * Add a closed oval contour to the path
537      *
538      * @param oval The bounds of the oval to add as a closed contour to the path
539      * @param dir  The direction to wind the oval's contour
540      */
addOval(RectF oval, Direction dir)541     public void addOval(RectF oval, Direction dir) {
542         addOval(oval.left, oval.top, oval.right, oval.bottom, dir);
543     }
544 
545     /**
546      * Add a closed oval contour to the path
547      *
548      * @param dir The direction to wind the oval's contour
549      */
addOval(float left, float top, float right, float bottom, Direction dir)550     public void addOval(float left, float top, float right, float bottom, Direction dir) {
551         isSimplePath = false;
552         native_addOval(mNativePath, left, top, right, bottom, dir.nativeInt);
553     }
554 
555     /**
556      * Add a closed circle contour to the path
557      *
558      * @param x   The x-coordinate of the center of a circle to add to the path
559      * @param y   The y-coordinate of the center of a circle to add to the path
560      * @param radius The radius of a circle to add to the path
561      * @param dir    The direction to wind the circle's contour
562      */
addCircle(float x, float y, float radius, Direction dir)563     public void addCircle(float x, float y, float radius, Direction dir) {
564         isSimplePath = false;
565         native_addCircle(mNativePath, x, y, radius, dir.nativeInt);
566     }
567 
568     /**
569      * Add the specified arc to the path as a new contour.
570      *
571      * @param oval The bounds of oval defining the shape and size of the arc
572      * @param startAngle Starting angle (in degrees) where the arc begins
573      * @param sweepAngle Sweep angle (in degrees) measured clockwise
574      */
addArc(RectF oval, float startAngle, float sweepAngle)575     public void addArc(RectF oval, float startAngle, float sweepAngle) {
576         addArc(oval.left, oval.top, oval.right, oval.bottom, startAngle, sweepAngle);
577     }
578 
579     /**
580      * Add the specified arc to the path as a new contour.
581      *
582      * @param startAngle Starting angle (in degrees) where the arc begins
583      * @param sweepAngle Sweep angle (in degrees) measured clockwise
584      */
addArc(float left, float top, float right, float bottom, float startAngle, float sweepAngle)585     public void addArc(float left, float top, float right, float bottom, float startAngle,
586             float sweepAngle) {
587         isSimplePath = false;
588         native_addArc(mNativePath, left, top, right, bottom, startAngle, sweepAngle);
589     }
590 
591     /**
592         * Add a closed round-rectangle contour to the path
593      *
594      * @param rect The bounds of a round-rectangle to add to the path
595      * @param rx   The x-radius of the rounded corners on the round-rectangle
596      * @param ry   The y-radius of the rounded corners on the round-rectangle
597      * @param dir  The direction to wind the round-rectangle's contour
598      */
addRoundRect(RectF rect, float rx, float ry, Direction dir)599     public void addRoundRect(RectF rect, float rx, float ry, Direction dir) {
600         addRoundRect(rect.left, rect.top, rect.right, rect.bottom, rx, ry, dir);
601     }
602 
603     /**
604      * Add a closed round-rectangle contour to the path
605      *
606      * @param rx   The x-radius of the rounded corners on the round-rectangle
607      * @param ry   The y-radius of the rounded corners on the round-rectangle
608      * @param dir  The direction to wind the round-rectangle's contour
609      */
addRoundRect(float left, float top, float right, float bottom, float rx, float ry, Direction dir)610     public void addRoundRect(float left, float top, float right, float bottom, float rx, float ry,
611             Direction dir) {
612         isSimplePath = false;
613         native_addRoundRect(mNativePath, left, top, right, bottom, rx, ry, dir.nativeInt);
614     }
615 
616     /**
617      * Add a closed round-rectangle contour to the path. Each corner receives
618      * two radius values [X, Y]. The corners are ordered top-left, top-right,
619      * bottom-right, bottom-left
620      *
621      * @param rect The bounds of a round-rectangle to add to the path
622      * @param radii Array of 8 values, 4 pairs of [X,Y] radii
623      * @param dir  The direction to wind the round-rectangle's contour
624      */
addRoundRect(RectF rect, float[] radii, Direction dir)625     public void addRoundRect(RectF rect, float[] radii, Direction dir) {
626         if (rect == null) {
627             throw new NullPointerException("need rect parameter");
628         }
629         addRoundRect(rect.left, rect.top, rect.right, rect.bottom, radii, dir);
630     }
631 
632     /**
633      * Add a closed round-rectangle contour to the path. Each corner receives
634      * two radius values [X, Y]. The corners are ordered top-left, top-right,
635      * bottom-right, bottom-left
636      *
637      * @param radii Array of 8 values, 4 pairs of [X,Y] radii
638      * @param dir  The direction to wind the round-rectangle's contour
639      */
addRoundRect(float left, float top, float right, float bottom, float[] radii, Direction dir)640     public void addRoundRect(float left, float top, float right, float bottom, float[] radii,
641             Direction dir) {
642         if (radii.length < 8) {
643             throw new ArrayIndexOutOfBoundsException("radii[] needs 8 values");
644         }
645         isSimplePath = false;
646         native_addRoundRect(mNativePath, left, top, right, bottom, radii, dir.nativeInt);
647     }
648 
649     /**
650      * Add a copy of src to the path, offset by (dx,dy)
651      *
652      * @param src The path to add as a new contour
653      * @param dx  The amount to translate the path in X as it is added
654      */
addPath(Path src, float dx, float dy)655     public void addPath(Path src, float dx, float dy) {
656         isSimplePath = false;
657         native_addPath(mNativePath, src.mNativePath, dx, dy);
658     }
659 
660     /**
661      * Add a copy of src to the path
662      *
663      * @param src The path that is appended to the current path
664      */
addPath(Path src)665     public void addPath(Path src) {
666         isSimplePath = false;
667         native_addPath(mNativePath, src.mNativePath);
668     }
669 
670     /**
671      * Add a copy of src to the path, transformed by matrix
672      *
673      * @param src The path to add as a new contour
674      */
addPath(Path src, Matrix matrix)675     public void addPath(Path src, Matrix matrix) {
676         if (!src.isSimplePath) isSimplePath = false;
677         native_addPath(mNativePath, src.mNativePath, matrix.native_instance);
678     }
679 
680     /**
681      * Offset the path by (dx,dy)
682      *
683      * @param dx  The amount in the X direction to offset the entire path
684      * @param dy  The amount in the Y direction to offset the entire path
685      * @param dst The translated path is written here. If this is null, then
686      *            the original path is modified.
687      */
offset(float dx, float dy, Path dst)688     public void offset(float dx, float dy, Path dst) {
689         long dstNative = 0;
690         if (dst != null) {
691             dstNative = dst.mNativePath;
692             dst.isSimplePath = false;
693         }
694         native_offset(mNativePath, dx, dy, dstNative);
695     }
696 
697     /**
698      * Offset the path by (dx,dy)
699      *
700      * @param dx The amount in the X direction to offset the entire path
701      * @param dy The amount in the Y direction to offset the entire path
702      */
offset(float dx, float dy)703     public void offset(float dx, float dy) {
704         isSimplePath = false;
705         native_offset(mNativePath, dx, dy);
706     }
707 
708     /**
709      * Sets the last point of the path.
710      *
711      * @param dx The new X coordinate for the last point
712      * @param dy The new Y coordinate for the last point
713      */
setLastPoint(float dx, float dy)714     public void setLastPoint(float dx, float dy) {
715         isSimplePath = false;
716         native_setLastPoint(mNativePath, dx, dy);
717     }
718 
719     /**
720      * Transform the points in this path by matrix, and write the answer
721      * into dst. If dst is null, then the the original path is modified.
722      *
723      * @param matrix The matrix to apply to the path
724      * @param dst    The transformed path is written here. If dst is null,
725      *               then the the original path is modified
726      */
transform(Matrix matrix, Path dst)727     public void transform(Matrix matrix, Path dst) {
728         long dstNative = 0;
729         if (dst != null) {
730             dst.isSimplePath = false;
731             dstNative = dst.mNativePath;
732         }
733         native_transform(mNativePath, matrix.native_instance, dstNative);
734     }
735 
736     /**
737      * Transform the points in this path by matrix.
738      *
739      * @param matrix The matrix to apply to the path
740      */
transform(Matrix matrix)741     public void transform(Matrix matrix) {
742         isSimplePath = false;
743         native_transform(mNativePath, matrix.native_instance);
744     }
745 
finalize()746     protected void finalize() throws Throwable {
747         try {
748             finalizer(mNativePath);
749         } finally {
750             super.finalize();
751         }
752     }
753 
ni()754     final long ni() {
755         return mNativePath;
756     }
757 
758     /**
759      * Approximate the <code>Path</code> with a series of line segments.
760      * This returns float[] with the array containing point components.
761      * There are three components for each point, in order:
762      * <ul>
763      *     <li>Fraction along the length of the path that the point resides</li>
764      *     <li>The x coordinate of the point</li>
765      *     <li>The y coordinate of the point</li>
766      * </ul>
767      * <p>Two points may share the same fraction along its length when there is
768      * a move action within the Path.</p>
769      *
770      * @param acceptableError The acceptable error for a line on the
771      *                        Path. Typically this would be 0.5 so that
772      *                        the error is less than half a pixel.
773      * @return An array of components for points approximating the Path.
774      * @hide
775      */
approximate(float acceptableError)776     public float[] approximate(float acceptableError) {
777         return native_approximate(mNativePath, acceptableError);
778     }
779 
init1()780     private static native long init1();
init2(long nPath)781     private static native long init2(long nPath);
native_reset(long nPath)782     private static native void native_reset(long nPath);
native_rewind(long nPath)783     private static native void native_rewind(long nPath);
native_set(long native_dst, long native_src)784     private static native void native_set(long native_dst, long native_src);
native_isConvex(long nPath)785     private static native boolean native_isConvex(long nPath);
native_getFillType(long nPath)786     private static native int native_getFillType(long nPath);
native_setFillType(long nPath, int ft)787     private static native void native_setFillType(long nPath, int ft);
native_isEmpty(long nPath)788     private static native boolean native_isEmpty(long nPath);
native_isRect(long nPath, RectF rect)789     private static native boolean native_isRect(long nPath, RectF rect);
native_computeBounds(long nPath, RectF bounds)790     private static native void native_computeBounds(long nPath, RectF bounds);
native_incReserve(long nPath, int extraPtCount)791     private static native void native_incReserve(long nPath, int extraPtCount);
native_moveTo(long nPath, float x, float y)792     private static native void native_moveTo(long nPath, float x, float y);
native_rMoveTo(long nPath, float dx, float dy)793     private static native void native_rMoveTo(long nPath, float dx, float dy);
native_lineTo(long nPath, float x, float y)794     private static native void native_lineTo(long nPath, float x, float y);
native_rLineTo(long nPath, float dx, float dy)795     private static native void native_rLineTo(long nPath, float dx, float dy);
native_quadTo(long nPath, float x1, float y1, float x2, float y2)796     private static native void native_quadTo(long nPath, float x1, float y1,
797                                              float x2, float y2);
native_rQuadTo(long nPath, float dx1, float dy1, float dx2, float dy2)798     private static native void native_rQuadTo(long nPath, float dx1, float dy1,
799                                               float dx2, float dy2);
native_cubicTo(long nPath, float x1, float y1, float x2, float y2, float x3, float y3)800     private static native void native_cubicTo(long nPath, float x1, float y1,
801                                         float x2, float y2, float x3, float y3);
native_rCubicTo(long nPath, float x1, float y1, float x2, float y2, float x3, float y3)802     private static native void native_rCubicTo(long nPath, float x1, float y1,
803                                         float x2, float y2, float x3, float y3);
native_arcTo(long nPath, float left, float top, float right, float bottom, float startAngle, float sweepAngle, boolean forceMoveTo)804     private static native void native_arcTo(long nPath, float left, float top,
805                                             float right, float bottom, float startAngle,
806                                             float sweepAngle, boolean forceMoveTo);
native_close(long nPath)807     private static native void native_close(long nPath);
native_addRect(long nPath, float left, float top, float right, float bottom, int dir)808     private static native void native_addRect(long nPath, float left, float top,
809                                             float right, float bottom, int dir);
native_addOval(long nPath, float left, float top, float right, float bottom, int dir)810     private static native void native_addOval(long nPath, float left, float top,
811             float right, float bottom, int dir);
native_addCircle(long nPath, float x, float y, float radius, int dir)812     private static native void native_addCircle(long nPath, float x, float y, float radius, int dir);
native_addArc(long nPath, float left, float top, float right, float bottom, float startAngle, float sweepAngle)813     private static native void native_addArc(long nPath, float left, float top,
814                                              float right, float bottom,
815                                              float startAngle, float sweepAngle);
native_addRoundRect(long nPath, float left, float top, float right, float bottom, float rx, float ry, int dir)816     private static native void native_addRoundRect(long nPath, float left, float top,
817                                                    float right, float bottom,
818                                                    float rx, float ry, int dir);
native_addRoundRect(long nPath, float left, float top, float right, float bottom, float[] radii, int dir)819     private static native void native_addRoundRect(long nPath, float left, float top,
820                                                    float right, float bottom,
821                                                    float[] radii, int dir);
native_addPath(long nPath, long src, float dx, float dy)822     private static native void native_addPath(long nPath, long src, float dx, float dy);
native_addPath(long nPath, long src)823     private static native void native_addPath(long nPath, long src);
native_addPath(long nPath, long src, long matrix)824     private static native void native_addPath(long nPath, long src, long matrix);
native_offset(long nPath, float dx, float dy, long dst_path)825     private static native void native_offset(long nPath, float dx, float dy, long dst_path);
native_offset(long nPath, float dx, float dy)826     private static native void native_offset(long nPath, float dx, float dy);
native_setLastPoint(long nPath, float dx, float dy)827     private static native void native_setLastPoint(long nPath, float dx, float dy);
native_transform(long nPath, long matrix, long dst_path)828     private static native void native_transform(long nPath, long matrix, long dst_path);
native_transform(long nPath, long matrix)829     private static native void native_transform(long nPath, long matrix);
native_op(long path1, long path2, int op, long result)830     private static native boolean native_op(long path1, long path2, int op, long result);
finalizer(long nPath)831     private static native void finalizer(long nPath);
native_approximate(long nPath, float error)832     private static native float[] native_approximate(long nPath, float error);
833 }
834