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