Home | History | Annotate | Download | only in graphics
      1 /*
      2  * Copyright (C) 2006 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package android.graphics;
     18 
     19 /**
     20  * The Path class encapsulates compound (multiple contour) geometric paths
     21  * consisting of straight line segments, quadratic curves, and cubic curves.
     22  * It can be drawn with canvas.drawPath(path, paint), either filled or stroked
     23  * (based on the paint's Style), or it can be used for clipping or to draw
     24  * text on a path.
     25  */
     26 public class Path {
     27 
     28     /**
     29      * Create an empty path
     30      */
     31     public Path() {
     32         mNativePath = init1();
     33     }
     34 
     35     /**
     36      * Create a new path, copying the contents from the src path.
     37      *
     38      * @param src The path to copy from when initializing the new path
     39      */
     40     public Path(Path src) {
     41         int valNative = 0;
     42         if (src != null) {
     43             valNative = src.mNativePath;
     44         }
     45         mNativePath = init2(valNative);
     46     }
     47 
     48     /**
     49      * Clear any lines and curves from the path, making it empty.
     50      * This does NOT change the fill-type setting.
     51      */
     52     public void reset() {
     53         native_reset(mNativePath);
     54     }
     55 
     56     /**
     57      * Rewinds the path: clears any lines and curves from the path but
     58      * keeps the internal data structure for faster reuse.
     59      */
     60     public void rewind() {
     61         native_rewind(mNativePath);
     62     }
     63 
     64     /** Replace the contents of this with the contents of src.
     65     */
     66     public void set(Path src) {
     67         if (this != src) {
     68             native_set(mNativePath, src.mNativePath);
     69         }
     70     }
     71 
     72     /** Enum for the ways a path may be filled
     73     */
     74     public enum FillType {
     75         // these must match the values in SkPath.h
     76         WINDING         (0),
     77         EVEN_ODD        (1),
     78         INVERSE_WINDING (2),
     79         INVERSE_EVEN_ODD(3);
     80 
     81         FillType(int ni) {
     82             nativeInt = ni;
     83         }
     84         final int nativeInt;
     85     }
     86 
     87     // these must be in the same order as their native values
     88     private static final FillType[] sFillTypeArray = {
     89         FillType.WINDING,
     90         FillType.EVEN_ODD,
     91         FillType.INVERSE_WINDING,
     92         FillType.INVERSE_EVEN_ODD
     93     };
     94 
     95     /**
     96      * Return the path's fill type. This defines how "inside" is
     97      * computed. The default value is WINDING.
     98      *
     99      * @return the path's fill type
    100      */
    101     public FillType getFillType() {
    102         return sFillTypeArray[native_getFillType(mNativePath)];
    103     }
    104 
    105     /**
    106      * Set the path's fill type. This defines how "inside" is computed.
    107      *
    108      * @param ft The new fill type for this path
    109      */
    110     public void setFillType(FillType ft) {
    111         native_setFillType(mNativePath, ft.nativeInt);
    112     }
    113 
    114     /**
    115      * Returns true if the filltype is one of the INVERSE variants
    116      *
    117      * @return true if the filltype is one of the INVERSE variants
    118      */
    119     public boolean isInverseFillType() {
    120         final int ft = native_getFillType(mNativePath);
    121         return (ft & 2) != 0;
    122     }
    123 
    124     /**
    125      * Toggles the INVERSE state of the filltype
    126      */
    127     public void toggleInverseFillType() {
    128         int ft = native_getFillType(mNativePath);
    129         ft ^= 2;
    130         native_setFillType(mNativePath, ft);
    131     }
    132 
    133     /**
    134      * Returns true if the path is empty (contains no lines or curves)
    135      *
    136      * @return true if the path is empty (contains no lines or curves)
    137      */
    138     public boolean isEmpty() {
    139         return native_isEmpty(mNativePath);
    140     }
    141 
    142     /**
    143      * Returns true if the path specifies a rectangle. If so, and if rect is
    144      * not null, set rect to the bounds of the path. If the path does not
    145      * specify a rectangle, return false and ignore rect.
    146      *
    147      * @param rect If not null, returns the bounds of the path if it specifies
    148      *             a rectangle
    149      * @return     true if the path specifies a rectangle
    150      */
    151     public boolean isRect(RectF rect) {
    152         return native_isRect(mNativePath, rect);
    153     }
    154 
    155     /**
    156      * Compute the bounds of the control points of the path, and write the
    157      * answer into bounds. If the path contains 0 or 1 points, the bounds is
    158      * set to (0,0,0,0)
    159      *
    160      * @param bounds Returns the computed bounds of the path's control points.
    161      * @param exact This parameter is no longer used.
    162      */
    163     public void computeBounds(RectF bounds, boolean exact) {
    164         native_computeBounds(mNativePath, bounds);
    165     }
    166 
    167     /**
    168      * Hint to the path to prepare for adding more points. This can allow the
    169      * path to more efficiently allocate its storage.
    170      *
    171      * @param extraPtCount The number of extra points that may be added to this
    172      *                     path
    173      */
    174     public void incReserve(int extraPtCount) {
    175         native_incReserve(mNativePath, extraPtCount);
    176     }
    177 
    178     /**
    179      * Set the beginning of the next contour to the point (x,y).
    180      *
    181      * @param x The x-coordinate of the start of a new contour
    182      * @param y The y-coordinate of the start of a new contour
    183      */
    184     public void moveTo(float x, float y) {
    185         native_moveTo(mNativePath, x, y);
    186     }
    187 
    188     /**
    189      * Set the beginning of the next contour relative to the last point on the
    190      * previous contour. If there is no previous contour, this is treated the
    191      * same as moveTo().
    192      *
    193      * @param dx The amount to add to the x-coordinate of the end of the
    194      *           previous contour, to specify the start of a new contour
    195      * @param dy The amount to add to the y-coordinate of the end of the
    196      *           previous contour, to specify the start of a new contour
    197      */
    198     public void rMoveTo(float dx, float dy) {
    199         native_rMoveTo(mNativePath, dx, dy);
    200     }
    201 
    202     /**
    203      * Add a line from the last point to the specified point (x,y).
    204      * If no moveTo() call has been made for this contour, the first point is
    205      * automatically set to (0,0).
    206      *
    207      * @param x The x-coordinate of the end of a line
    208      * @param y The y-coordinate of the end of a line
    209      */
    210     public void lineTo(float x, float y) {
    211         native_lineTo(mNativePath, x, y);
    212     }
    213 
    214     /**
    215      * Same as lineTo, but the coordinates are considered relative to the last
    216      * point on this contour. If there is no previous point, then a moveTo(0,0)
    217      * is inserted automatically.
    218      *
    219      * @param dx The amount to add to the x-coordinate of the previous point on
    220      *           this contour, to specify a line
    221      * @param dy The amount to add to the y-coordinate of the previous point on
    222      *           this contour, to specify a line
    223      */
    224     public void rLineTo(float dx, float dy) {
    225         native_rLineTo(mNativePath, dx, dy);
    226     }
    227 
    228     /**
    229      * Add a quadratic bezier from the last point, approaching control point
    230      * (x1,y1), and ending at (x2,y2). If no moveTo() call has been made for
    231      * this contour, the first point is automatically set to (0,0).
    232      *
    233      * @param x1 The x-coordinate of the control point on a quadratic curve
    234      * @param y1 The y-coordinate of the control point on a quadratic curve
    235      * @param x2 The x-coordinate of the end point on a quadratic curve
    236      * @param y2 The y-coordinate of the end point on a quadratic curve
    237      */
    238     public void quadTo(float x1, float y1, float x2, float y2) {
    239         native_quadTo(mNativePath, x1, y1, x2, y2);
    240     }
    241 
    242     /**
    243      * Same as quadTo, but the coordinates are considered relative to the last
    244      * point on this contour. If there is no previous point, then a moveTo(0,0)
    245      * is inserted automatically.
    246      *
    247      * @param dx1 The amount to add to the x-coordinate of the last point on
    248      *            this contour, for the control point of a quadratic curve
    249      * @param dy1 The amount to add to the y-coordinate of the last point on
    250      *            this contour, for the control point of a quadratic curve
    251      * @param dx2 The amount to add to the x-coordinate of the last point on
    252      *            this contour, for the end point of a quadratic curve
    253      * @param dy2 The amount to add to the y-coordinate of the last point on
    254      *            this contour, for the end point of a quadratic curve
    255      */
    256     public void rQuadTo(float dx1, float dy1, float dx2, float dy2) {
    257         native_rQuadTo(mNativePath, dx1, dy1, dx2, dy2);
    258     }
    259 
    260     /**
    261      * Add a cubic bezier from the last point, approaching control points
    262      * (x1,y1) and (x2,y2), and ending at (x3,y3). If no moveTo() call has been
    263      * made for this contour, the first point is automatically set to (0,0).
    264      *
    265      * @param x1 The x-coordinate of the 1st control point on a cubic curve
    266      * @param y1 The y-coordinate of the 1st control point on a cubic curve
    267      * @param x2 The x-coordinate of the 2nd control point on a cubic curve
    268      * @param y2 The y-coordinate of the 2nd control point on a cubic curve
    269      * @param x3 The x-coordinate of the end point on a cubic curve
    270      * @param y3 The y-coordinate of the end point on a cubic curve
    271      */
    272     public void cubicTo(float x1, float y1, float x2, float y2,
    273                         float x3, float y3) {
    274         native_cubicTo(mNativePath, x1, y1, x2, y2, x3, y3);
    275     }
    276 
    277     /**
    278      * Same as cubicTo, but the coordinates are considered relative to the
    279      * current point on this contour. If there is no previous point, then a
    280      * moveTo(0,0) is inserted automatically.
    281      */
    282     public void rCubicTo(float x1, float y1, float x2, float y2,
    283                          float x3, float y3) {
    284         native_rCubicTo(mNativePath, x1, y1, x2, y2, x3, y3);
    285     }
    286 
    287     /**
    288      * Append the specified arc to the path as a new contour. If the start of
    289      * the path is different from the path's current last point, then an
    290      * automatic lineTo() is added to connect the current contour to the
    291      * start of the arc. However, if the path is empty, then we call moveTo()
    292      * with the first point of the arc. The sweep angle is tread mod 360.
    293      *
    294      * @param oval        The bounds of oval defining shape and size of the arc
    295      * @param startAngle  Starting angle (in degrees) where the arc begins
    296      * @param sweepAngle  Sweep angle (in degrees) measured clockwise, treated
    297      *                    mod 360.
    298      * @param forceMoveTo If true, always begin a new contour with the arc
    299      */
    300     public void arcTo(RectF oval, float startAngle, float sweepAngle,
    301                       boolean forceMoveTo) {
    302         native_arcTo(mNativePath, oval, startAngle, sweepAngle, forceMoveTo);
    303     }
    304 
    305     /**
    306      * Append the specified arc to the path as a new contour. If the start of
    307      * the path is different from the path's current last point, then an
    308      * automatic lineTo() is added to connect the current contour to the
    309      * start of the arc. However, if the path is empty, then we call moveTo()
    310      * with the first point of the arc.
    311      *
    312      * @param oval        The bounds of oval defining shape and size of the arc
    313      * @param startAngle  Starting angle (in degrees) where the arc begins
    314      * @param sweepAngle  Sweep angle (in degrees) measured clockwise
    315      */
    316     public void arcTo(RectF oval, float startAngle, float sweepAngle) {
    317         native_arcTo(mNativePath, oval, startAngle, sweepAngle, false);
    318     }
    319 
    320     /**
    321      * Close the current contour. If the current point is not equal to the
    322      * first point of the contour, a line segment is automatically added.
    323      */
    324     public void close() {
    325         native_close(mNativePath);
    326     }
    327 
    328     /**
    329      * Specifies how closed shapes (e.g. rects, ovals) are oriented when they
    330      * are added to a path.
    331      */
    332     public enum Direction {
    333         /** clockwise */
    334         CW  (0),    // must match enum in SkPath.h
    335         /** counter-clockwise */
    336         CCW (1);    // must match enum in SkPath.h
    337 
    338         Direction(int ni) {
    339             nativeInt = ni;
    340         }
    341         final int nativeInt;
    342     }
    343 
    344     /**
    345      * Add a closed rectangle contour to the path
    346      *
    347      * @param rect The rectangle to add as a closed contour to the path
    348      * @param dir  The direction to wind the rectangle's contour
    349      */
    350     public void addRect(RectF rect, Direction dir) {
    351         if (rect == null) {
    352             throw new NullPointerException("need rect parameter");
    353         }
    354         native_addRect(mNativePath, rect, dir.nativeInt);
    355     }
    356 
    357     /**
    358      * Add a closed rectangle contour to the path
    359      *
    360      * @param left   The left side of a rectangle to add to the path
    361      * @param top    The top of a rectangle to add to the path
    362      * @param right  The right side of a rectangle to add to the path
    363      * @param bottom The bottom of a rectangle to add to the path
    364      * @param dir    The direction to wind the rectangle's contour
    365      */
    366     public void addRect(float left, float top, float right, float bottom,
    367                         Direction dir) {
    368         native_addRect(mNativePath, left, top, right, bottom, dir.nativeInt);
    369     }
    370 
    371     /**
    372      * Add a closed oval contour to the path
    373      *
    374      * @param oval The bounds of the oval to add as a closed contour to the path
    375      * @param dir  The direction to wind the oval's contour
    376      */
    377     public void addOval(RectF oval, Direction dir) {
    378         if (oval == null) {
    379             throw new NullPointerException("need oval parameter");
    380         }
    381         native_addOval(mNativePath, oval, dir.nativeInt);
    382     }
    383 
    384     /**
    385      * Add a closed circle contour to the path
    386      *
    387      * @param x   The x-coordinate of the center of a circle to add to the path
    388      * @param y   The y-coordinate of the center of a circle to add to the path
    389      * @param radius The radius of a circle to add to the path
    390      * @param dir    The direction to wind the circle's contour
    391      */
    392     public void addCircle(float x, float y, float radius, Direction dir) {
    393         native_addCircle(mNativePath, x, y, radius, dir.nativeInt);
    394     }
    395 
    396     /**
    397      * Add the specified arc to the path as a new contour.
    398      *
    399      * @param oval The bounds of oval defining the shape and size of the arc
    400      * @param startAngle Starting angle (in degrees) where the arc begins
    401      * @param sweepAngle Sweep angle (in degrees) measured clockwise
    402      */
    403     public void addArc(RectF oval, float startAngle, float sweepAngle) {
    404         if (oval == null) {
    405             throw new NullPointerException("need oval parameter");
    406         }
    407         native_addArc(mNativePath, oval, startAngle, sweepAngle);
    408     }
    409 
    410     /**
    411         * Add a closed round-rectangle contour to the path
    412      *
    413      * @param rect The bounds of a round-rectangle to add to the path
    414      * @param rx   The x-radius of the rounded corners on the round-rectangle
    415      * @param ry   The y-radius of the rounded corners on the round-rectangle
    416      * @param dir  The direction to wind the round-rectangle's contour
    417      */
    418     public void addRoundRect(RectF rect, float rx, float ry, Direction dir) {
    419         if (rect == null) {
    420             throw new NullPointerException("need rect parameter");
    421         }
    422         native_addRoundRect(mNativePath, rect, rx, ry, dir.nativeInt);
    423     }
    424 
    425     /**
    426      * Add a closed round-rectangle contour to the path. Each corner receives
    427      * two radius values [X, Y]. The corners are ordered top-left, top-right,
    428      * bottom-right, bottom-left
    429      *
    430      * @param rect The bounds of a round-rectangle to add to the path
    431      * @param radii Array of 8 values, 4 pairs of [X,Y] radii
    432      * @param dir  The direction to wind the round-rectangle's contour
    433      */
    434     public void addRoundRect(RectF rect, float[] radii, Direction dir) {
    435         if (rect == null) {
    436             throw new NullPointerException("need rect parameter");
    437         }
    438         if (radii.length < 8) {
    439             throw new ArrayIndexOutOfBoundsException("radii[] needs 8 values");
    440         }
    441         native_addRoundRect(mNativePath, rect, radii, dir.nativeInt);
    442     }
    443 
    444     /**
    445      * Add a copy of src to the path, offset by (dx,dy)
    446      *
    447      * @param src The path to add as a new contour
    448      * @param dx  The amount to translate the path in X as it is added
    449      */
    450     public void addPath(Path src, float dx, float dy) {
    451         native_addPath(mNativePath, src.mNativePath, dx, dy);
    452     }
    453 
    454     /**
    455      * Add a copy of src to the path
    456      *
    457      * @param src The path that is appended to the current path
    458      */
    459     public void addPath(Path src) {
    460         native_addPath(mNativePath, src.mNativePath);
    461     }
    462 
    463     /**
    464      * Add a copy of src to the path, transformed by matrix
    465      *
    466      * @param src The path to add as a new contour
    467      */
    468     public void addPath(Path src, Matrix matrix) {
    469         native_addPath(mNativePath, src.mNativePath, matrix.native_instance);
    470     }
    471 
    472     /**
    473      * Offset the path by (dx,dy), returning true on success
    474      *
    475      * @param dx  The amount in the X direction to offset the entire path
    476      * @param dy  The amount in the Y direction to offset the entire path
    477      * @param dst The translated path is written here. If this is null, then
    478      *            the original path is modified.
    479      */
    480     public void offset(float dx, float dy, Path dst) {
    481         int dstNative = 0;
    482         if (dst != null) {
    483             dstNative = dst.mNativePath;
    484         }
    485         native_offset(mNativePath, dx, dy, dstNative);
    486     }
    487 
    488     /**
    489      * Offset the path by (dx,dy), returning true on success
    490      *
    491      * @param dx The amount in the X direction to offset the entire path
    492      * @param dy The amount in the Y direction to offset the entire path
    493      */
    494     public void offset(float dx, float dy) {
    495         native_offset(mNativePath, dx, dy);
    496     }
    497 
    498     /**
    499      * Sets the last point of the path.
    500      *
    501      * @param dx The new X coordinate for the last point
    502      * @param dy The new Y coordinate for the last point
    503      */
    504     public void setLastPoint(float dx, float dy) {
    505         native_setLastPoint(mNativePath, dx, dy);
    506     }
    507 
    508     /**
    509      * Transform the points in this path by matrix, and write the answer
    510      * into dst. If dst is null, then the the original path is modified.
    511      *
    512      * @param matrix The matrix to apply to the path
    513      * @param dst    The transformed path is written here. If dst is null,
    514      *               then the the original path is modified
    515      */
    516     public void transform(Matrix matrix, Path dst) {
    517         int dstNative = 0;
    518         if (dst != null) {
    519             dstNative = dst.mNativePath;
    520         }
    521         native_transform(mNativePath, matrix.native_instance, dstNative);
    522     }
    523 
    524     /**
    525      * Transform the points in this path by matrix.
    526      *
    527      * @param matrix The matrix to apply to the path
    528      */
    529     public void transform(Matrix matrix) {
    530         native_transform(mNativePath, matrix.native_instance);
    531     }
    532 
    533     protected void finalize() throws Throwable {
    534         try {
    535             finalizer(mNativePath);
    536         } finally {
    537             super.finalize();
    538         }
    539     }
    540 
    541     /*package*/ final int ni() {
    542         return mNativePath;
    543     }
    544 
    545     private static native int init1();
    546     private static native int init2(int nPath);
    547     private static native void native_reset(int nPath);
    548     private static native void native_rewind(int nPath);
    549     private static native void native_set(int native_dst, int native_src);
    550     private static native int native_getFillType(int nPath);
    551     private static native void native_setFillType(int nPath, int ft);
    552     private static native boolean native_isEmpty(int nPath);
    553     private static native boolean native_isRect(int nPath, RectF rect);
    554     private static native void native_computeBounds(int nPath, RectF bounds);
    555     private static native void native_incReserve(int nPath, int extraPtCount);
    556     private static native void native_moveTo(int nPath, float x, float y);
    557     private static native void native_rMoveTo(int nPath, float dx, float dy);
    558     private static native void native_lineTo(int nPath, float x, float y);
    559     private static native void native_rLineTo(int nPath, float dx, float dy);
    560     private static native void native_quadTo(int nPath, float x1, float y1,
    561                                              float x2, float y2);
    562     private static native void native_rQuadTo(int nPath, float dx1, float dy1,
    563                                               float dx2, float dy2);
    564     private static native void native_cubicTo(int nPath, float x1, float y1,
    565                                         float x2, float y2, float x3, float y3);
    566     private static native void native_rCubicTo(int nPath, float x1, float y1,
    567                                         float x2, float y2, float x3, float y3);
    568     private static native void native_arcTo(int nPath, RectF oval,
    569                     float startAngle, float sweepAngle, boolean forceMoveTo);
    570     private static native void native_close(int nPath);
    571     private static native void native_addRect(int nPath, RectF rect, int dir);
    572     private static native void native_addRect(int nPath, float left, float top,
    573                                             float right, float bottom, int dir);
    574     private static native void native_addOval(int nPath, RectF oval, int dir);
    575     private static native void native_addCircle(int nPath, float x, float y,
    576                                                 float radius, int dir);
    577     private static native void native_addArc(int nPath, RectF oval,
    578                                             float startAngle, float sweepAngle);
    579     private static native void native_addRoundRect(int nPath, RectF rect,
    580                                                    float rx, float ry, int dir);
    581     private static native void native_addRoundRect(int nPath, RectF r,
    582                                                    float[] radii, int dir);
    583     private static native void native_addPath(int nPath, int src, float dx,
    584                                               float dy);
    585     private static native void native_addPath(int nPath, int src);
    586     private static native void native_addPath(int nPath, int src, int matrix);
    587     private static native void native_offset(int nPath, float dx, float dy,
    588                                              int dst_path);
    589     private static native void native_offset(int nPath, float dx, float dy);
    590     private static native void native_setLastPoint(int nPath, float dx, float dy);
    591     private static native void native_transform(int nPath, int matrix,
    592                                                 int dst_path);
    593     private static native void native_transform(int nPath, int matrix);
    594     private static native void finalizer(int nPath);
    595 
    596     private final int mNativePath;
    597 }
    598