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