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