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