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 import android.annotation.FloatRange;
20 import android.annotation.NonNull;
21 import android.annotation.Nullable;
22 import android.annotation.Size;
23 
24 import dalvik.annotation.optimization.CriticalNative;
25 import dalvik.annotation.optimization.FastNative;
26 
27 import libcore.util.NativeAllocationRegistry;
28 
29 /**
30  * The Path class encapsulates compound (multiple contour) geometric paths
31  * consisting of straight line segments, quadratic curves, and cubic curves.
32  * It can be drawn with canvas.drawPath(path, paint), either filled or stroked
33  * (based on the paint's Style), or it can be used for clipping or to draw
34  * text on a path.
35  */
36 public class Path {
37 
38     private static final NativeAllocationRegistry sRegistry =
39             NativeAllocationRegistry.createMalloced(
40                 Path.class.getClassLoader(), nGetFinalizer());
41 
42     /**
43      * @hide
44      */
45     public final long mNativePath;
46 
47     /**
48      * Create an empty path
49      */
Path()50     public Path() {
51         mNativePath = nInit();
52         sRegistry.registerNativeAllocation(this, mNativePath);
53     }
54 
55     /**
56      * Create a new path, copying the contents from the src path.
57      *
58      * @param src The path to copy from when initializing the new path
59      */
Path(@ullable Path src)60     public Path(@Nullable Path src) {
61         mNativePath = nInit(src != null ? src.mNativePath : 0);
62         sRegistry.registerNativeAllocation(this, mNativePath);
63     }
64 
65     /**
66      * Clear any lines and curves from the path, making it empty.
67      * This does NOT change the fill-type setting.
68      */
reset()69     public void reset() {
70         // We promised not to change this, so preserve it around the native
71         // call, which does now reset fill type.
72         final FillType fillType = getFillType();
73         nReset(mNativePath);
74         setFillType(fillType);
75     }
76 
77     /**
78      * Rewinds the path: clears any lines and curves from the path but
79      * keeps the internal data structure for faster reuse.
80      */
rewind()81     public void rewind() {
82         nRewind(mNativePath);
83     }
84 
85     /** Replace the contents of this with the contents of src.
86     */
set(@onNull Path src)87     public void set(@NonNull Path src) {
88         if (this == src) {
89             return;
90         }
91         nSet(mNativePath, src.mNativePath);
92     }
93 
94     /**
95      * Returns an iterator over the segments of this path.
96      *
97      * @return the Iterator object
98      */
99     @NonNull
getPathIterator()100     public PathIterator getPathIterator() {
101         return new PathIterator(this);
102     }
103 
104     /**
105      * The logical operations that can be performed when combining two paths.
106      *
107      * @see #op(Path, android.graphics.Path.Op)
108      * @see #op(Path, Path, android.graphics.Path.Op)
109      */
110     public enum Op {
111         /**
112          * Subtract the second path from the first path.
113          */
114         DIFFERENCE,
115         /**
116          * Intersect the two paths.
117          */
118         INTERSECT,
119         /**
120          * Union (inclusive-or) the two paths.
121          */
122         UNION,
123         /**
124          * Exclusive-or the two paths.
125          */
126         XOR,
127         /**
128          * Subtract the first path from the second path.
129          */
130         REVERSE_DIFFERENCE
131     }
132 
133     /**
134      * Set this path to the result of applying the Op to this path and the specified path.
135      * The resulting path will be constructed from non-overlapping contours.
136      * The curve order is reduced where possible so that cubics may be turned
137      * into quadratics, and quadratics maybe turned into lines.
138      *
139      * @param path The second operand (for difference, the subtrahend)
140      *
141      * @return True if operation succeeded, false otherwise and this path remains unmodified.
142      *
143      * @see Op
144      * @see #op(Path, Path, android.graphics.Path.Op)
145      */
op(@onNull Path path, @NonNull Op op)146     public boolean op(@NonNull Path path, @NonNull Op op) {
147         return op(this, path, op);
148     }
149 
150     /**
151      * Set this path to the result of applying the Op to the two specified paths.
152      * The resulting path will be constructed from non-overlapping contours.
153      * The curve order is reduced where possible so that cubics may be turned
154      * into quadratics, and quadratics maybe turned into lines.
155      *
156      * @param path1 The first operand (for difference, the minuend)
157      * @param path2 The second operand (for difference, the subtrahend)
158      *
159      * @return True if operation succeeded, false otherwise and this path remains unmodified.
160      *
161      * @see Op
162      * @see #op(Path, android.graphics.Path.Op)
163      */
op(@onNull Path path1, @NonNull Path path2, @NonNull Op op)164     public boolean op(@NonNull Path path1, @NonNull Path path2, @NonNull Op op) {
165         return nOp(path1.mNativePath, path2.mNativePath, op.ordinal(), this.mNativePath);
166     }
167 
168     /**
169      * Returns the path's convexity, as defined by the content of the path.
170      * <p>
171      * A path is convex if it has a single contour, and only ever curves in a
172      * single direction.
173      * <p>
174      * This function will calculate the convexity of the path from its control
175      * points, and cache the result.
176      *
177      * @return True if the path is convex.
178      *
179      * @deprecated This method is not reliable. The way convexity is computed may change from
180      * release to release, and convexity could change based on a matrix as well. This method was
181      * useful when non-convex Paths were unable to be used in certain contexts, but that is no
182      * longer the case.
183      */
184     @Deprecated
isConvex()185     public boolean isConvex() {
186         return nIsConvex(mNativePath);
187     }
188 
189     /**
190      * Enum for the ways a path may be filled.
191      */
192     public enum FillType {
193         // these must match the values in SkPath.h
194         /**
195          * Specifies that "inside" is computed by a non-zero sum of signed
196          * edge crossings.
197          */
198         WINDING         (0),
199         /**
200          * Specifies that "inside" is computed by an odd number of edge
201          * crossings.
202          */
203         EVEN_ODD        (1),
204         /**
205          * Same as {@link #WINDING}, but draws outside of the path, rather than inside.
206          */
207         INVERSE_WINDING (2),
208         /**
209          * Same as {@link #EVEN_ODD}, but draws outside of the path, rather than inside.
210          */
211         INVERSE_EVEN_ODD(3);
212 
FillType(int ni)213         FillType(int ni) {
214             nativeInt = ni;
215         }
216 
217         final int nativeInt;
218     }
219 
220     // these must be in the same order as their native values
221     static final FillType[] sFillTypeArray = {
222         FillType.WINDING,
223         FillType.EVEN_ODD,
224         FillType.INVERSE_WINDING,
225         FillType.INVERSE_EVEN_ODD
226     };
227 
228     /**
229      * Return the path's fill type. This defines how "inside" is
230      * computed. The default value is WINDING.
231      *
232      * @return the path's fill type
233      */
234     @NonNull
getFillType()235     public FillType getFillType() {
236         return sFillTypeArray[nGetFillType(mNativePath)];
237     }
238 
239     /**
240      * Set the path's fill type. This defines how "inside" is computed.
241      *
242      * @param ft The new fill type for this path
243      */
setFillType(@onNull FillType ft)244     public void setFillType(@NonNull FillType ft) {
245         nSetFillType(mNativePath, ft.nativeInt);
246     }
247 
248     /**
249      * Returns true if the filltype is one of the INVERSE variants
250      *
251      * @return true if the filltype is one of the INVERSE variants
252      */
isInverseFillType()253     public boolean isInverseFillType() {
254         final int ft = nGetFillType(mNativePath);
255         return (ft & FillType.INVERSE_WINDING.nativeInt) != 0;
256     }
257 
258     /**
259      * Toggles the INVERSE state of the filltype
260      */
toggleInverseFillType()261     public void toggleInverseFillType() {
262         int ft = nGetFillType(mNativePath);
263         ft ^= FillType.INVERSE_WINDING.nativeInt;
264         nSetFillType(mNativePath, ft);
265     }
266 
267     /**
268      * Returns true if the path is empty (contains no lines or curves)
269      *
270      * @return true if the path is empty (contains no lines or curves)
271      */
isEmpty()272     public boolean isEmpty() {
273         return nIsEmpty(mNativePath);
274     }
275 
276     /**
277      * Returns true if the path specifies a rectangle. If so, and if rect is
278      * not null, set rect to the bounds of the path. If the path does not
279      * specify a rectangle, return false and ignore rect.
280      *
281      * @param rect If not null, returns the bounds of the path if it specifies
282      *             a rectangle
283      * @return     true if the path specifies a rectangle
284      */
isRect(@ullable RectF rect)285     public boolean isRect(@Nullable  RectF rect) {
286         return nIsRect(mNativePath, rect);
287     }
288 
289     /**
290      * Compute the bounds of the control points of the path, and write the
291      * answer into bounds. If the path contains 0 or 1 points, the bounds is
292      * set to (0,0,0,0)
293      *
294      * @param bounds Returns the computed bounds of the path's control points.
295      * @param exact This parameter is no longer used.
296      */
297     @SuppressWarnings({"UnusedDeclaration"})
computeBounds(@onNull RectF bounds, boolean exact)298     public void computeBounds(@NonNull RectF bounds, boolean exact) {
299         nComputeBounds(mNativePath, bounds);
300     }
301 
302     /**
303      * Hint to the path to prepare for adding more points. This can allow the
304      * path to more efficiently allocate its storage.
305      *
306      * @param extraPtCount The number of extra points that may be added to this
307      *                     path
308      */
incReserve(int extraPtCount)309     public void incReserve(int extraPtCount) {
310         nIncReserve(mNativePath, extraPtCount);
311     }
312 
313     /**
314      * Set the beginning of the next contour to the point (x,y).
315      *
316      * @param x The x-coordinate of the start of a new contour
317      * @param y The y-coordinate of the start of a new contour
318      */
moveTo(float x, float y)319     public void moveTo(float x, float y) {
320         nMoveTo(mNativePath, x, y);
321     }
322 
323     /**
324      * Set the beginning of the next contour relative to the last point on the
325      * previous contour. If there is no previous contour, this is treated the
326      * same as moveTo().
327      *
328      * @param dx The amount to add to the x-coordinate of the end of the
329      *           previous contour, to specify the start of a new contour
330      * @param dy The amount to add to the y-coordinate of the end of the
331      *           previous contour, to specify the start of a new contour
332      */
rMoveTo(float dx, float dy)333     public void rMoveTo(float dx, float dy) {
334         nRMoveTo(mNativePath, dx, dy);
335     }
336 
337     /**
338      * Add a line from the last point to the specified point (x,y).
339      * If no moveTo() call has been made for this contour, the first point is
340      * automatically set to (0,0).
341      *
342      * @param x The x-coordinate of the end of a line
343      * @param y The y-coordinate of the end of a line
344      */
lineTo(float x, float y)345     public void lineTo(float x, float y) {
346         nLineTo(mNativePath, x, y);
347     }
348 
349     /**
350      * Same as lineTo, but the coordinates are considered relative to the last
351      * point on this contour. If there is no previous point, then a moveTo(0,0)
352      * is inserted automatically.
353      *
354      * @param dx The amount to add to the x-coordinate of the previous point on
355      *           this contour, to specify a line
356      * @param dy The amount to add to the y-coordinate of the previous point on
357      *           this contour, to specify a line
358      */
rLineTo(float dx, float dy)359     public void rLineTo(float dx, float dy) {
360         nRLineTo(mNativePath, dx, dy);
361     }
362 
363     /**
364      * Add a quadratic bezier from the last point, approaching control point
365      * (x1,y1), and ending at (x2,y2). If no moveTo() call has been made for
366      * this contour, the first point is automatically set to (0,0).
367      *
368      * @param x1 The x-coordinate of the control point on a quadratic curve
369      * @param y1 The y-coordinate of the control point on a quadratic curve
370      * @param x2 The x-coordinate of the end point on a quadratic curve
371      * @param y2 The y-coordinate of the end point on a quadratic curve
372      */
quadTo(float x1, float y1, float x2, float y2)373     public void quadTo(float x1, float y1, float x2, float y2) {
374         nQuadTo(mNativePath, x1, y1, x2, y2);
375     }
376 
377     /**
378      * Same as quadTo, but the coordinates are considered relative to the last
379      * point on this contour. If there is no previous point, then a moveTo(0,0)
380      * is inserted automatically.
381      *
382      * @param dx1 The amount to add to the x-coordinate of the last point on
383      *            this contour, for the control point of a quadratic curve
384      * @param dy1 The amount to add to the y-coordinate of the last point on
385      *            this contour, for the control point of a quadratic curve
386      * @param dx2 The amount to add to the x-coordinate of the last point on
387      *            this contour, for the end point of a quadratic curve
388      * @param dy2 The amount to add to the y-coordinate of the last point on
389      *            this contour, for the end point of a quadratic curve
390      */
rQuadTo(float dx1, float dy1, float dx2, float dy2)391     public void rQuadTo(float dx1, float dy1, float dx2, float dy2) {
392         nRQuadTo(mNativePath, dx1, dy1, dx2, dy2);
393     }
394 
395     /**
396      * Add a quadratic bezier from the last point, approaching control point
397      * (x1,y1), and ending at (x2,y2), weighted by <code>weight</code>. If no
398      * moveTo() call has been made for this contour, the first point is
399      * automatically set to (0,0).
400      *
401      * A weight of 1 is equivalent to calling {@link #quadTo(float, float, float, float)}.
402      * A weight of 0 is equivalent to calling {@link #lineTo(float, float)} to
403      * <code>(x1, y1)</code> followed by {@link #lineTo(float, float)} to <code>(x2, y2)</code>.
404      *
405      * @param x1 The x-coordinate of the control point on a conic curve
406      * @param y1 The y-coordinate of the control point on a conic curve
407      * @param x2 The x-coordinate of the end point on a conic curve
408      * @param y2 The y-coordinate of the end point on a conic curve
409      * @param weight The weight of the conic applied to the curve. A value of 1 is equivalent
410      *               to a quadratic with the given control and anchor points and a value of 0 is
411      *               equivalent to a line to the first and another line to the second point.
412      */
conicTo(float x1, float y1, float x2, float y2, float weight)413     public void conicTo(float x1, float y1, float x2, float y2, float weight) {
414         nConicTo(mNativePath, x1, y1, x2, y2, weight);
415     }
416 
417     /**
418      * Same as conicTo, but the coordinates are considered relative to the last
419      * point on this contour. If there is no previous point, then a moveTo(0,0)
420      * is inserted automatically.
421      *
422      * @param dx1 The amount to add to the x-coordinate of the last point on
423      *            this contour, for the control point of a conic curve
424      * @param dy1 The amount to add to the y-coordinate of the last point on
425      *            this contour, for the control point of a conic curve
426      * @param dx2 The amount to add to the x-coordinate of the last point on
427      *            this contour, for the end point of a conic curve
428      * @param dy2 The amount to add to the y-coordinate of the last point on
429      *            this contour, for the end point of a conic curve
430      * @param weight The weight of the conic applied to the curve. A value of 1 is equivalent
431      *               to a quadratic with the given control and anchor points and a value of 0 is
432      *               equivalent to a line to the first and another line to the second point.
433      */
rConicTo(float dx1, float dy1, float dx2, float dy2, float weight)434     public void rConicTo(float dx1, float dy1, float dx2, float dy2, float weight) {
435         nRConicTo(mNativePath, dx1, dy1, dx2, dy2, weight);
436     }
437 
438     /**
439      * Add a cubic bezier from the last point, approaching control points
440      * (x1,y1) and (x2,y2), and ending at (x3,y3). If no moveTo() call has been
441      * made for this contour, the first point is automatically set to (0,0).
442      *
443      * @param x1 The x-coordinate of the 1st control point on a cubic curve
444      * @param y1 The y-coordinate of the 1st control point on a cubic curve
445      * @param x2 The x-coordinate of the 2nd control point on a cubic curve
446      * @param y2 The y-coordinate of the 2nd control point on a cubic curve
447      * @param x3 The x-coordinate of the end point on a cubic curve
448      * @param y3 The y-coordinate of the end point on a cubic curve
449      */
cubicTo(float x1, float y1, float x2, float y2, float x3, float y3)450     public void cubicTo(float x1, float y1, float x2, float y2,
451                         float x3, float y3) {
452         nCubicTo(mNativePath, x1, y1, x2, y2, x3, y3);
453     }
454 
455     /**
456      * Same as cubicTo, but the coordinates are considered relative to the
457      * current point on this contour. If there is no previous point, then a
458      * moveTo(0,0) is inserted automatically.
459      */
rCubicTo(float x1, float y1, float x2, float y2, float x3, float y3)460     public void rCubicTo(float x1, float y1, float x2, float y2,
461                          float x3, float y3) {
462         nRCubicTo(mNativePath, x1, y1, x2, y2, x3, y3);
463     }
464 
465     /**
466      * Append the specified arc to the path as a new contour. If the start of
467      * the path is different from the path's current last point, then an
468      * automatic lineTo() is added to connect the current contour to the
469      * start of the arc. However, if the path is empty, then we call moveTo()
470      * with the first point of the arc.
471      *
472      * @param oval        The bounds of oval defining shape and size of the arc
473      * @param startAngle  Starting angle (in degrees) where the arc begins
474      * @param sweepAngle  Sweep angle (in degrees) measured clockwise, treated
475      *                    mod 360.
476      * @param forceMoveTo If true, always begin a new contour with the arc
477      */
arcTo(@onNull RectF oval, float startAngle, float sweepAngle, boolean forceMoveTo)478     public void arcTo(@NonNull RectF oval, float startAngle, float sweepAngle,
479                       boolean forceMoveTo) {
480         arcTo(oval.left, oval.top, oval.right, oval.bottom, startAngle, sweepAngle, forceMoveTo);
481     }
482 
483     /**
484      * Append the specified arc to the path as a new contour. If the start of
485      * the path is different from the path's current last point, then an
486      * automatic lineTo() is added to connect the current contour to the
487      * start of the arc. However, if the path is empty, then we call moveTo()
488      * with the first point of the arc.
489      *
490      * @param oval        The bounds of oval defining shape and size of the arc
491      * @param startAngle  Starting angle (in degrees) where the arc begins
492      * @param sweepAngle  Sweep angle (in degrees) measured clockwise
493      */
arcTo(@onNull RectF oval, float startAngle, float sweepAngle)494     public void arcTo(@NonNull RectF oval, float startAngle, float sweepAngle) {
495         arcTo(oval.left, oval.top, oval.right, oval.bottom, startAngle, sweepAngle, false);
496     }
497 
498     /**
499      * Append the specified arc to the path as a new contour. If the start of
500      * the path is different from the path's current last point, then an
501      * automatic lineTo() is added to connect the current contour to the
502      * start of the arc. However, if the path is empty, then we call moveTo()
503      * with the first point of the arc.
504      *
505      * @param startAngle  Starting angle (in degrees) where the arc begins
506      * @param sweepAngle  Sweep angle (in degrees) measured clockwise, treated
507      *                    mod 360.
508      * @param forceMoveTo If true, always begin a new contour with the arc
509      */
arcTo(float left, float top, float right, float bottom, float startAngle, float sweepAngle, boolean forceMoveTo)510     public void arcTo(float left, float top, float right, float bottom, float startAngle,
511             float sweepAngle, boolean forceMoveTo) {
512         nArcTo(mNativePath, left, top, right, bottom, startAngle, sweepAngle, forceMoveTo);
513     }
514 
515     /**
516      * Close the current contour. If the current point is not equal to the
517      * first point of the contour, a line segment is automatically added.
518      */
close()519     public void close() {
520         nClose(mNativePath);
521     }
522 
523     /**
524      * Specifies how closed shapes (e.g. rects, ovals) are oriented when they
525      * are added to a path.
526      */
527     public enum Direction {
528         /** clockwise */
529         CW  (0),    // must match enum in SkPath.h
530         /** counter-clockwise */
531         CCW (1);    // must match enum in SkPath.h
532 
Direction(int ni)533         Direction(int ni) {
534             nativeInt = ni;
535         }
536         final int nativeInt;
537     }
538 
539     /**
540      * Add a closed rectangle contour to the path
541      *
542      * @param rect The rectangle to add as a closed contour to the path
543      * @param dir  The direction to wind the rectangle's contour
544      */
addRect(@onNull RectF rect, @NonNull Direction dir)545     public void addRect(@NonNull RectF rect, @NonNull Direction dir) {
546         addRect(rect.left, rect.top, rect.right, rect.bottom, dir);
547     }
548 
549     /**
550      * Add a closed rectangle contour to the path
551      *
552      * @param left   The left side of a rectangle to add to the path
553      * @param top    The top of a rectangle to add to the path
554      * @param right  The right side of a rectangle to add to the path
555      * @param bottom The bottom of a rectangle to add to the path
556      * @param dir    The direction to wind the rectangle's contour
557      */
addRect(float left, float top, float right, float bottom, @NonNull Direction dir)558     public void addRect(float left, float top, float right, float bottom, @NonNull Direction dir) {
559         nAddRect(mNativePath, left, top, right, bottom, dir.nativeInt);
560     }
561 
562     /**
563      * Add a closed oval contour to the path
564      *
565      * @param oval The bounds of the oval to add as a closed contour to the path
566      * @param dir  The direction to wind the oval's contour
567      */
addOval(@onNull RectF oval, @NonNull Direction dir)568     public void addOval(@NonNull RectF oval, @NonNull Direction dir) {
569         addOval(oval.left, oval.top, oval.right, oval.bottom, dir);
570     }
571 
572     /**
573      * Add a closed oval contour to the path
574      *
575      * @param dir The direction to wind the oval's contour
576      */
addOval(float left, float top, float right, float bottom, @NonNull Direction dir)577     public void addOval(float left, float top, float right, float bottom, @NonNull Direction dir) {
578         nAddOval(mNativePath, left, top, right, bottom, dir.nativeInt);
579     }
580 
581     /**
582      * Add a closed circle contour to the path
583      *
584      * @param x   The x-coordinate of the center of a circle to add to the path
585      * @param y   The y-coordinate of the center of a circle to add to the path
586      * @param radius The radius of a circle to add to the path
587      * @param dir    The direction to wind the circle's contour
588      */
addCircle(float x, float y, float radius, @NonNull Direction dir)589     public void addCircle(float x, float y, float radius, @NonNull Direction dir) {
590         nAddCircle(mNativePath, x, y, radius, dir.nativeInt);
591     }
592 
593     /**
594      * Add the specified arc to the path as a new contour.
595      *
596      * @param oval The bounds of oval defining the shape and size of the arc
597      * @param startAngle Starting angle (in degrees) where the arc begins
598      * @param sweepAngle Sweep angle (in degrees) measured clockwise
599      */
addArc(@onNull RectF oval, float startAngle, float sweepAngle)600     public void addArc(@NonNull RectF oval, float startAngle, float sweepAngle) {
601         addArc(oval.left, oval.top, oval.right, oval.bottom, startAngle, sweepAngle);
602     }
603 
604     /**
605      * Add the specified arc to the path as a new contour.
606      *
607      * @param startAngle Starting angle (in degrees) where the arc begins
608      * @param sweepAngle Sweep angle (in degrees) measured clockwise
609      */
addArc(float left, float top, float right, float bottom, float startAngle, float sweepAngle)610     public void addArc(float left, float top, float right, float bottom, float startAngle,
611             float sweepAngle) {
612         nAddArc(mNativePath, left, top, right, bottom, startAngle, sweepAngle);
613     }
614 
615     /**
616         * Add a closed round-rectangle contour to the path
617      *
618      * @param rect The bounds of a round-rectangle to add to the path
619      * @param rx   The x-radius of the rounded corners on the round-rectangle
620      * @param ry   The y-radius of the rounded corners on the round-rectangle
621      * @param dir  The direction to wind the round-rectangle's contour
622      */
addRoundRect(@onNull RectF rect, float rx, float ry, @NonNull Direction dir)623     public void addRoundRect(@NonNull RectF rect, float rx, float ry, @NonNull Direction dir) {
624         addRoundRect(rect.left, rect.top, rect.right, rect.bottom, rx, ry, dir);
625     }
626 
627     /**
628      * Add a closed round-rectangle contour to the path
629      *
630      * @param rx   The x-radius of the rounded corners on the round-rectangle
631      * @param ry   The y-radius of the rounded corners on the round-rectangle
632      * @param dir  The direction to wind the round-rectangle's contour
633      */
addRoundRect(float left, float top, float right, float bottom, float rx, float ry, @NonNull Direction dir)634     public void addRoundRect(float left, float top, float right, float bottom, float rx, float ry,
635             @NonNull Direction dir) {
636         nAddRoundRect(mNativePath, left, top, right, bottom, rx, ry, dir.nativeInt);
637     }
638 
639     /**
640      * Add a closed round-rectangle contour to the path. Each corner receives
641      * two radius values [X, Y]. The corners are ordered top-left, top-right,
642      * bottom-right, bottom-left
643      *
644      * @param rect The bounds of a round-rectangle to add to the path
645      * @param radii Array of 8 values, 4 pairs of [X,Y] radii
646      * @param dir  The direction to wind the round-rectangle's contour
647      */
addRoundRect(@onNull RectF rect, @NonNull float[] radii, @NonNull Direction dir)648     public void addRoundRect(@NonNull RectF rect, @NonNull float[] radii, @NonNull Direction dir) {
649         if (rect == null) {
650             throw new NullPointerException("need rect parameter");
651         }
652         addRoundRect(rect.left, rect.top, rect.right, rect.bottom, radii, dir);
653     }
654 
655     /**
656      * Add a closed round-rectangle contour to the path. Each corner receives
657      * two radius values [X, Y]. The corners are ordered top-left, top-right,
658      * bottom-right, bottom-left
659      *
660      * @param radii Array of 8 values, 4 pairs of [X,Y] radii
661      * @param dir  The direction to wind the round-rectangle's contour
662      */
addRoundRect(float left, float top, float right, float bottom, @NonNull float[] radii, @NonNull Direction dir)663     public void addRoundRect(float left, float top, float right, float bottom,
664             @NonNull float[] radii, @NonNull Direction dir) {
665         if (radii.length < 8) {
666             throw new ArrayIndexOutOfBoundsException("radii[] needs 8 values");
667         }
668         nAddRoundRect(mNativePath, left, top, right, bottom, radii, dir.nativeInt);
669     }
670 
671     /**
672      * Add a copy of src to the path, offset by (dx,dy)
673      *
674      * @param src The path to add as a new contour
675      * @param dx  The amount to translate the path in X as it is added
676      */
addPath(@onNull Path src, float dx, float dy)677     public void addPath(@NonNull Path src, float dx, float dy) {
678         nAddPath(mNativePath, src.mNativePath, dx, dy);
679     }
680 
681     /**
682      * Add a copy of src to the path
683      *
684      * @param src The path that is appended to the current path
685      */
addPath(@onNull Path src)686     public void addPath(@NonNull Path src) {
687         nAddPath(mNativePath, src.mNativePath);
688     }
689 
690     /**
691      * Add a copy of src to the path, transformed by matrix
692      *
693      * @param src The path to add as a new contour
694      */
addPath(@onNull Path src, @NonNull Matrix matrix)695     public void addPath(@NonNull Path src, @NonNull Matrix matrix) {
696         nAddPath(mNativePath, src.mNativePath, matrix.ni());
697     }
698 
699     /**
700      * Offset the path by (dx,dy)
701      *
702      * @param dx  The amount in the X direction to offset the entire path
703      * @param dy  The amount in the Y direction to offset the entire path
704      * @param dst The translated path is written here. If this is null, then
705      *            the original path is modified.
706      */
offset(float dx, float dy, @Nullable Path dst)707     public void offset(float dx, float dy, @Nullable Path dst) {
708         if (dst != null) {
709             dst.set(this);
710         } else {
711             dst = this;
712         }
713         dst.offset(dx, dy);
714     }
715 
716     /**
717      * Offset the path by (dx,dy)
718      *
719      * @param dx The amount in the X direction to offset the entire path
720      * @param dy The amount in the Y direction to offset the entire path
721      */
offset(float dx, float dy)722     public void offset(float dx, float dy) {
723         nOffset(mNativePath, dx, dy);
724     }
725 
726     /**
727      * Sets the last point of the path.
728      *
729      * @param dx The new X coordinate for the last point
730      * @param dy The new Y coordinate for the last point
731      */
setLastPoint(float dx, float dy)732     public void setLastPoint(float dx, float dy) {
733         nSetLastPoint(mNativePath, dx, dy);
734     }
735 
736     /**
737      * Transform the points in this path by matrix, and write the answer
738      * into dst. If dst is null, then the the original path is modified.
739      *
740      * @param matrix The matrix to apply to the path
741      * @param dst    The transformed path is written here. If dst is null,
742      *               then the the original path is modified
743      */
transform(@onNull Matrix matrix, @Nullable Path dst)744     public void transform(@NonNull Matrix matrix, @Nullable Path dst) {
745         nTransform(mNativePath, matrix.ni(), dst != null ? dst.mNativePath : 0);
746     }
747 
748     /**
749      * Transform the points in this path by matrix.
750      *
751      * @param matrix The matrix to apply to the path
752      */
transform(@onNull Matrix matrix)753     public void transform(@NonNull Matrix matrix) {
754         nTransform(mNativePath, matrix.ni());
755     }
756 
757     /** @hide */
readOnlyNI()758     public final long readOnlyNI() {
759         return mNativePath;
760     }
761 
mutateNI()762     final long mutateNI() {
763         return mNativePath;
764     }
765 
766     /**
767      * Approximate the <code>Path</code> with a series of line segments.
768      * This returns float[] with the array containing point components.
769      * There are three components for each point, in order:
770      * <ul>
771      *     <li>Fraction along the length of the path that the point resides</li>
772      *     <li>The x coordinate of the point</li>
773      *     <li>The y coordinate of the point</li>
774      * </ul>
775      * <p>Two points may share the same fraction along its length when there is
776      * a move action within the Path.</p>
777      *
778      * @param acceptableError The acceptable error for a line on the
779      *                        Path. Typically this would be 0.5 so that
780      *                        the error is less than half a pixel.
781      * @return An array of components for points approximating the Path.
782      */
783     @NonNull
784     @Size(min = 6, multiple = 3)
approximate(@loatRangefrom = 0) float acceptableError)785     public float[] approximate(@FloatRange(from = 0) float acceptableError) {
786         if (acceptableError < 0) {
787             throw new IllegalArgumentException("AcceptableError must be greater than or equal to 0");
788         }
789         return nApproximate(mNativePath, acceptableError);
790     }
791 
792     /**
793      * Returns the generation ID of this path. The generation ID changes
794      * whenever the path is modified. This can be used as an efficient way to
795      * check if a path has changed.
796      *
797      * @return The current generation ID for this path
798      */
getGenerationId()799     public int getGenerationId()  {
800         return nGetGenerationID(mNativePath);
801     }
802 
803     /**
804      * Two paths can be interpolated, by calling {@link #interpolate(Path, float, Path)}, if they
805      * have exactly the same structure. That is, both paths must have the same
806      * operations, in the same order. If any of the operations are
807      * of type {@link PathIterator#VERB_CONIC}, then the weights of those conics must also match.
808      *
809      * @param otherPath The other <code>Path</code> being interpolated to from this one.
810      * @return true if interpolation is possible, false otherwise
811      */
isInterpolatable(@onNull Path otherPath)812     public boolean isInterpolatable(@NonNull Path otherPath) {
813         return nIsInterpolatable(mNativePath, otherPath.mNativePath);
814     }
815 
816     /**
817      * This method will linearly interpolate from this path to <code>otherPath</code> given
818      * the interpolation parameter <code>t</code>, returning the result in
819      * <code>interpolatedPath</code>. Interpolation will only succeed if the structures of the
820      * two paths match exactly, as discussed in {@link #isInterpolatable(Path)}.
821      *
822      * @param otherPath The other <code>Path</code> being interpolated to.
823      * @param t The interpolation parameter. A value of 0 results in a <code>Path</code>
824      *          equivalent to this path, a value of 1 results in one equivalent to
825      *          <code>otherPath</code>.
826      * @param interpolatedPath The interpolated results.
827      */
interpolate(@onNull Path otherPath, float t, @NonNull Path interpolatedPath)828     public boolean interpolate(@NonNull Path otherPath, float t, @NonNull Path interpolatedPath) {
829         return nInterpolate(mNativePath, otherPath.mNativePath, t, interpolatedPath.mNativePath);
830     }
831 
832     // ------------------ Regular JNI ------------------------
833 
nInit()834     private static native long nInit();
nInit(long nPath)835     private static native long nInit(long nPath);
nGetFinalizer()836     private static native long nGetFinalizer();
nSet(long native_dst, long nSrc)837     private static native void nSet(long native_dst, long nSrc);
nComputeBounds(long nPath, RectF bounds)838     private static native void nComputeBounds(long nPath, RectF bounds);
nIncReserve(long nPath, int extraPtCount)839     private static native void nIncReserve(long nPath, int extraPtCount);
nMoveTo(long nPath, float x, float y)840     private static native void nMoveTo(long nPath, float x, float y);
nRMoveTo(long nPath, float dx, float dy)841     private static native void nRMoveTo(long nPath, float dx, float dy);
nLineTo(long nPath, float x, float y)842     private static native void nLineTo(long nPath, float x, float y);
nRLineTo(long nPath, float dx, float dy)843     private static native void nRLineTo(long nPath, float dx, float dy);
nQuadTo(long nPath, float x1, float y1, float x2, float y2)844     private static native void nQuadTo(long nPath, float x1, float y1, float x2, float y2);
nRQuadTo(long nPath, float dx1, float dy1, float dx2, float dy2)845     private static native void nRQuadTo(long nPath, float dx1, float dy1, float dx2, float dy2);
nConicTo(long nPath, float x1, float y1, float x2, float y2, float weight)846     private static native void nConicTo(long nPath, float x1, float y1, float x2, float y2,
847             float weight);
nRConicTo(long nPath, float dx1, float dy1, float dx2, float dy2, float weight)848     private static native void nRConicTo(long nPath, float dx1, float dy1, float dx2, float dy2,
849             float weight);
nCubicTo(long nPath, float x1, float y1, float x2, float y2, float x3, float y3)850     private static native void nCubicTo(long nPath, float x1, float y1, float x2, float y2,
851             float x3, float y3);
nRCubicTo(long nPath, float x1, float y1, float x2, float y2, float x3, float y3)852     private static native void nRCubicTo(long nPath, float x1, float y1, float x2, float y2,
853             float x3, float y3);
nArcTo(long nPath, float left, float top, float right, float bottom, float startAngle, float sweepAngle, boolean forceMoveTo)854     private static native void nArcTo(long nPath, float left, float top, float right, float bottom,
855             float startAngle, float sweepAngle, boolean forceMoveTo);
nClose(long nPath)856     private static native void nClose(long nPath);
nAddRect(long nPath, float left, float top, float right, float bottom, int dir)857     private static native void nAddRect(long nPath, float left, float top,
858             float right, float bottom, int dir);
nAddOval(long nPath, float left, float top, float right, float bottom, int dir)859     private static native void nAddOval(long nPath, float left, float top,
860             float right, float bottom, int dir);
nAddCircle(long nPath, float x, float y, float radius, int dir)861     private static native void nAddCircle(long nPath, float x, float y, float radius, int dir);
nAddArc(long nPath, float left, float top, float right, float bottom, float startAngle, float sweepAngle)862     private static native void nAddArc(long nPath, float left, float top, float right, float bottom,
863             float startAngle, float sweepAngle);
nAddRoundRect(long nPath, float left, float top, float right, float bottom, float rx, float ry, int dir)864     private static native void nAddRoundRect(long nPath, float left, float top,
865             float right, float bottom, float rx, float ry, int dir);
nAddRoundRect(long nPath, float left, float top, float right, float bottom, float[] radii, int dir)866     private static native void nAddRoundRect(long nPath, float left, float top,
867             float right, float bottom, float[] radii, int dir);
nAddPath(long nPath, long src, float dx, float dy)868     private static native void nAddPath(long nPath, long src, float dx, float dy);
nAddPath(long nPath, long src)869     private static native void nAddPath(long nPath, long src);
nAddPath(long nPath, long src, long matrix)870     private static native void nAddPath(long nPath, long src, long matrix);
nOffset(long nPath, float dx, float dy)871     private static native void nOffset(long nPath, float dx, float dy);
nSetLastPoint(long nPath, float dx, float dy)872     private static native void nSetLastPoint(long nPath, float dx, float dy);
nTransform(long nPath, long matrix, long dst_path)873     private static native void nTransform(long nPath, long matrix, long dst_path);
nTransform(long nPath, long matrix)874     private static native void nTransform(long nPath, long matrix);
nOp(long path1, long path2, int op, long result)875     private static native boolean nOp(long path1, long path2, int op, long result);
nApproximate(long nPath, float error)876     private static native float[] nApproximate(long nPath, float error);
nInterpolate(long startPath, long endPath, float t, long interpolatedPath)877     private static native boolean nInterpolate(long startPath, long endPath, float t,
878             long interpolatedPath);
879 
880     // ------------------ Fast JNI ------------------------
881 
882     @FastNative
nIsRect(long nPath, RectF rect)883     private static native boolean nIsRect(long nPath, RectF rect);
884 
885     // ------------------ Critical JNI ------------------------
886 
887     @CriticalNative
nGetGenerationID(long nativePath)888     private static native int nGetGenerationID(long nativePath);
889     @CriticalNative
nIsInterpolatable(long startPath, long endPath)890     private static native boolean nIsInterpolatable(long startPath, long endPath);
891     @CriticalNative
nReset(long nPath)892     private static native void nReset(long nPath);
893     @CriticalNative
nRewind(long nPath)894     private static native void nRewind(long nPath);
895     @CriticalNative
nIsEmpty(long nPath)896     private static native boolean nIsEmpty(long nPath);
897     @CriticalNative
nIsConvex(long nPath)898     private static native boolean nIsConvex(long nPath);
899     @CriticalNative
nGetFillType(long nPath)900     private static native int nGetFillType(long nPath);
901     @CriticalNative
nSetFillType(long nPath, int ft)902     private static native void nSetFillType(long nPath, int ft);
903 }
904