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