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