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