blob: f8b2ced4373f58bc79722e2a6ce2b72ee1e9e2ee [file] [log] [blame] [edit]
/*
* Copyright 2015 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef SkPathBuilder_DEFINED
#define SkPathBuilder_DEFINED
#include "include/core/SkMatrix.h"
#include "include/core/SkPath.h"
#include "include/core/SkPathIter.h"
#include "include/core/SkPathTypes.h"
#include "include/core/SkPoint.h"
#include "include/core/SkRect.h"
#include "include/core/SkRefCnt.h"
#include "include/core/SkScalar.h"
#include "include/core/SkSpan.h"
#include "include/core/SkTypes.h"
#include "include/private/SkPathRef.h"
#include "include/private/base/SkTArray.h"
#include <cstdint>
#include <optional>
#include <tuple>
class SkPathData;
class SkRRect;
struct SkPathRaw;
class SkString;
class SK_API SkPathBuilder {
public:
/** Constructs an empty SkPathBuilder. By default, SkPathBuilder has no verbs, no SkPoint, and
no weights. FillType is set to kWinding.
@return empty SkPathBuilder
*/
SkPathBuilder();
/** Constructs an empty SkPathBuilder with the given FillType. By default, SkPathBuilder has no
verbs, no SkPoint, and no weights.
@param fillType SkPathFillType to set on the SkPathBuilder.
@return empty SkPathBuilder
*/
explicit SkPathBuilder(SkPathFillType fillType);
/** Constructs an SkPathBuilder that is a copy of an existing SkPath.
Copies the FillType and replays all of the verbs from the SkPath into the SkPathBuilder.
@param path SkPath to copy
@return SkPathBuilder
*/
explicit SkPathBuilder(const SkPath& path);
SkPathBuilder(const SkPathBuilder&) = default;
~SkPathBuilder();
/** Sets an SkPathBuilder to be a copy of an existing SkPath.
Copies the FillType and replays all of the verbs from the SkPath into the SkPathBuilder.
@param path SkPath to copy
@return SkPathBuilder
*/
SkPathBuilder& operator=(const SkPath&);
SkPathBuilder& operator=(const SkPathBuilder&) = default;
bool operator==(const SkPathBuilder&) const;
bool operator!=(const SkPathBuilder& o) const { return !(*this == o); }
/** Returns SkPathFillType, the rule used to fill SkPath.
@return current SkPathFillType setting
*/
SkPathFillType fillType() const { return fFillType; }
/** Returns minimum and maximum axes values of SkPoint array.
Returns (0, 0, 0, 0) if SkPathBuilder contains no points.
SkRect returned includes all SkPoint added to SkPathBuilder, including SkPoint associated
with kMove_Verb that define empty contours.
If any of the points are non-finite, returns {}.
@return bounds of all SkPoint in SkPoint array, or {}.
*/
std::optional<SkRect> computeFiniteBounds() const {
return SkRect::Bounds(fPts);
}
// DEPRECATED -- returns "empty" if the bounds are non-finite
SkRect computeBounds() const {
if (auto bounds = this->computeFiniteBounds()) {
return *bounds;
}
return SkRect::MakeEmpty();
}
/** Returns an SkPath representing the current state of the SkPathBuilder. The builder is
unchanged after returning the path.
@param mx if present, applied to the points after they are copied into the resulting path.
@return SkPath representing the current state of the builder.
*/
SkPath snapshot(const SkMatrix* mx = nullptr) const;
/** Returns an SkPath representing the current state of the SkPathBuilder. The builder is
reset to empty after returning the path.
@param mx if present, applied to the points after they are copied into the resulting path.
@return SkPath representing the current state of the builder.
*/
SkPath detach(const SkMatrix* mx = nullptr);
sk_sp<SkPathData> snapshotData() const;
sk_sp<SkPathData> detachData();
/** Sets SkPathFillType, the rule used to fill SkPath. While there is no
check that ft is legal, values outside of SkPathFillType are not supported.
@param ft SkPathFillType to be used by SKPaths generated from this builder.
@return reference to SkPathBuilder
*/
SkPathBuilder& setFillType(SkPathFillType ft) { fFillType = ft; return *this; }
/** Specifies whether SkPath is volatile; whether it will be altered or discarded
by the caller after it is drawn. SkPath by default have volatile set false, allowing
Skia to attach a cache of data which speeds repeated drawing.
Mark temporary paths, discarded or modified after use, as volatile
to inform Skia that the path need not be cached.
Mark animating SkPath volatile to improve performance.
Mark unchanging SkPath non-volatile to improve repeated rendering.
raster surface SkPath draws are affected by volatile for some shadows.
GPU surface SkPath draws are affected by volatile for some shadows and concave geometries.
@param isVolatile true if caller will alter SkPath after drawing
@return reference to SkPathBuilder
*/
SkPathBuilder& setIsVolatile(bool isVolatile) { fIsVolatile = isVolatile; return *this; }
/** Sets SkPathBuilder to its initial state.
Removes verb array, SkPoint array, and weights, and sets FillType to kWinding.
Internal storage associated with SkPathBuilder is released.
@return reference to SkPathBuilder
*/
SkPathBuilder& reset();
/** Specifies the beginning of contour. If the previous verb was a "move" verb,
* then this just replaces the point value of that move, otherwise it appends a new
* "move" verb to the builder using the point.
*
* Thus, each contour can only have 1 move verb in it (the last one specified).
*/
SkPathBuilder& moveTo(SkPoint point);
SkPathBuilder& moveTo(SkScalar x, SkScalar y) {
return this->moveTo(SkPoint::Make(x, y));
}
/** Adds line from last point to SkPoint p. If SkPathBuilder is empty, or last SkPath::Verb is
kClose_Verb, last point is set to (0, 0) before adding line.
lineTo() first appends kMove_Verb to verb array and (0, 0) to SkPoint array, if needed.
lineTo() then appends kLine_Verb to verb array and SkPoint p to SkPoint array.
@param p end SkPoint of added line
@return reference to SkPathBuilder
*/
SkPathBuilder& lineTo(SkPoint pt);
/** Adds line from last point to (x, y). If SkPathBuilder is empty, or last SkPath::Verb is
kClose_Verb, last point is set to (0, 0) before adding line.
lineTo() appends kMove_Verb to verb array and (0, 0) to SkPoint array, if needed.
lineTo() then appends kLine_Verb to verb array and (x, y) to SkPoint array.
@param x end of added line on x-axis
@param y end of added line on y-axis
@return reference to SkPathBuilder
*/
SkPathBuilder& lineTo(SkScalar x, SkScalar y) { return this->lineTo(SkPoint::Make(x, y)); }
/** Adds quad from last point towards SkPoint p1, to SkPoint p2.
If SkPathBuilder is empty, or last SkPath::Verb is kClose_Verb, last point is set to (0, 0)
before adding quad.
Appends kMove_Verb to verb array and (0, 0) to SkPoint array, if needed;
then appends kQuad_Verb to verb array; and SkPoint p1, p2
to SkPoint array.
@param p1 control SkPoint of added quad
@param p2 end SkPoint of added quad
@return reference to SkPathBuilder
*/
SkPathBuilder& quadTo(SkPoint pt1, SkPoint pt2);
/** Adds quad from last point towards (x1, y1), to (x2, y2).
If SkPath is empty, or last SkPath::Verb is kClose_Verb, last point is set to (0, 0)
before adding quad.
Appends kMove_Verb to verb array and (0, 0) to SkPoint array, if needed;
then appends kQuad_Verb to verb array; and (x1, y1), (x2, y2)
to SkPoint array.
@param x1 control SkPoint of quad on x-axis
@param y1 control SkPoint of quad on y-axis
@param x2 end SkPoint of quad on x-axis
@param y2 end SkPoint of quad on y-axis
@return reference to SkPath
example: https://fiddle.skia.org/c/@Path_quadTo
*/
SkPathBuilder& quadTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2) {
return this->quadTo(SkPoint::Make(x1, y1), SkPoint::Make(x2, y2));
}
/** Adds quad from last point towards the first SkPoint in pts, to the second.
If SkPathBuilder is empty, or last SkPath::Verb is kClose_Verb, last point is set to (0, 0)
before adding quad.
Appends kMove_Verb to verb array and (0, 0) to SkPoint array, if needed;
then appends kQuad_Verb to verb array; and the SkPoints to SkPoint array.
@param pts control point and endpoint of added quad.
@return reference to SkPathBuilder
*/
SkPathBuilder& quadTo(const SkPoint pts[2]) { return this->quadTo(pts[0], pts[1]); }
/** Adds conic from last point towards pt1, to pt2, weighted by w.
If SkPathBuilder is empty, or last SkPath::Verb is kClose_Verb, last point is set to (0, 0)
before adding conic.
Appends kMove_Verb to verb array and (0, 0) to SkPoint array, if needed.
If w is finite and not one, appends kConic_Verb to verb array;
and pt1, pt2 to SkPoint array; and w to conic weights.
If w is one, appends kQuad_Verb to verb array, and
pt1, pt2 to SkPoint array.
If w is not finite, appends kLine_Verb twice to verb array, and
pt1, pt2 to SkPoint array.
@param pt1 control SkPoint of conic
@param pt2 end SkPoint of conic
@param w weight of added conic
@return reference to SkPathBuilder
*/
SkPathBuilder& conicTo(SkPoint pt1, SkPoint pt2, SkScalar w);
/** Adds conic from last point towards (x1, y1), to (x2, y2), weighted by w.
If SkPathBuilder is empty, or last SkPath::Verb is kClose_Verb, last point is set to (0, 0)
before adding conic.
Appends kMove_Verb to verb array and (0, 0) to SkPoint array, if needed.
If w is finite and not one, appends kConic_Verb to verb array;
and (x1, y1), (x2, y2) to SkPoint array; and w to conic weights.
If w is one, appends kQuad_Verb to verb array, and
(x1, y1), (x2, y2) to SkPoint array.
If w is not finite, appends kLine_Verb twice to verb array, and
(x1, y1), (x2, y2) to SkPoint array.
@param x1 control SkPoint of conic on x-axis
@param y1 control SkPoint of conic on y-axis
@param x2 end SkPoint of conic on x-axis
@param y2 end SkPoint of conic on y-axis
@param w weight of added conic
@return reference to SkPathBuilder
*/
SkPathBuilder& conicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2, SkScalar w) {
return this->conicTo(SkPoint::Make(x1, y1), SkPoint::Make(x2, y2), w);
}
/** Adds conic from last point towards SkPoint p1, to SkPoint p2, weighted by w.
If SkPathBuilder is empty, or last SkPath::Verb is kClose_Verb, last point is set to (0, 0)
before adding conic.
Appends kMove_Verb to verb array and (0, 0) to SkPoint array, if needed.
If w is finite and not one, appends kConic_Verb to verb array;
and SkPoint p1, p2 to SkPoint array; and w to conic weights.
If w is one, appends kQuad_Verb to verb array, and SkPoint p1, p2
to SkPoint array.
If w is not finite, appends kLine_Verb twice to verb array, and
SkPoint p1, p2 to SkPoint array.
@param p1 control SkPoint of added conic
@param p2 end SkPoint of added conic
@param w weight of added conic
@return reference to SkPathBuilder
*/
SkPathBuilder& conicTo(const SkPoint pts[2], SkScalar w) {
return this->conicTo(pts[0], pts[1], w);
}
/** Adds cubic from last point towards SkPoint p1, then towards SkPoint p2, ending at
SkPoint p3. If SkPathBuilder is empty, or last SkPath::Verb is kClose_Verb, last point is
set to (0, 0) before adding cubic.
Appends kMove_Verb to verb array and (0, 0) to SkPoint array, if needed;
then appends kCubic_Verb to verb array; and SkPoint p1, p2, p3
to SkPoint array.
@param p1 first control SkPoint of cubic
@param p2 second control SkPoint of cubic
@param p3 end SkPoint of cubic
@return reference to SkPathBuilder
*/
SkPathBuilder& cubicTo(SkPoint pt1, SkPoint pt2, SkPoint pt3);
/** Adds cubic from last point towards (x1, y1), then towards (x2, y2), ending at
(x3, y3). If SkPathBuilder is empty, or last SkPath::Verb is kClose_Verb, last point is set
to (0, 0) before adding cubic.
Appends kMove_Verb to verb array and (0, 0) to SkPoint array, if needed;
then appends kCubic_Verb to verb array; and (x1, y1), (x2, y2), (x3, y3)
to SkPoint array.
@param x1 first control SkPoint of cubic on x-axis
@param y1 first control SkPoint of cubic on y-axis
@param x2 second control SkPoint of cubic on x-axis
@param y2 second control SkPoint of cubic on y-axis
@param x3 end SkPoint of cubic on x-axis
@param y3 end SkPoint of cubic on y-axis
@return reference to SkPathBuilder
*/
SkPathBuilder& cubicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2, SkScalar x3, SkScalar y3) {
return this->cubicTo(SkPoint::Make(x1, y1), SkPoint::Make(x2, y2), SkPoint::Make(x3, y3));
}
/** Adds cubic from last point towards the first SkPoint, then towards the second, ending at
the third. If SkPathBuilder is empty, or last SkPath::Verb is kClose_Verb, last point is
set to (0, 0) before adding cubic.
Appends kMove_Verb to verb array and (0, 0) to SkPoint array, if needed;
then appends kCubic_Verb to verb array; and SkPoint p1, p2, p3
to SkPoint array.
@param pts first and second control SkPoints of cubic, and end SkPoint.
@return reference to SkPathBuilder
*/
SkPathBuilder& cubicTo(const SkPoint pts[3]) {
return this->cubicTo(pts[0], pts[1], pts[2]);
}
/** Appends kClose_Verb to SkPathBuilder. A closed contour connects the first and last SkPoint
with line, forming a continuous loop. Open and closed contour draw the same
with SkPaint::kFill_Style. With SkPaint::kStroke_Style, open contour draws
SkPaint::Cap at contour start and end; closed contour draws
SkPaint::Join at contour start and end.
close() has no effect if SkPathBuilder is empty or last SkPath SkPath::Verb is kClose_Verb.
@return reference to SkPathBuilder
*/
SkPathBuilder& close();
/** Append a series of lineTo(...)
@param pts span of SkPoint
@return reference to SkPathBuilder.
*/
SkPathBuilder& polylineTo(SkSpan<const SkPoint> pts);
// Relative versions of segments, relative to the previous position.
/** Adds beginning of contour relative to last point.
If SkPathBuilder is empty, starts contour at (dx, dy).
Otherwise, start contour at last point offset by (dx, dy).
Function name stands for "relative move to".
@param pt vector offset from last point to contour start
@return reference to SkPathBuilder
example: https://fiddle.skia.org/c/@Path_rMoveTo
*/
SkPathBuilder& rMoveTo(SkPoint pt);
/** Adds line from last point to vector given by pt. If SkPathBuilder is empty, or last
SkPath::Verb is kClose_Verb, last point is set to (0, 0) before adding line.
Appends kMove_Verb to verb array and (0, 0) to SkPoint array, if needed;
then appends kLine_Verb to verb array and line end to SkPoint array.
Line end is last point plus vector given by pt.
Function name stands for "relative line to".
@param pt vector offset from last point to line end
@return reference to SkPathBuilder
*/
SkPathBuilder& rLineTo(SkPoint pt);
/** Adds line from last point to vector (dx, dy). If SkPathBuilder is empty, or last
SkPath::Verb is kClose_Verb, last point is set to (0, 0) before adding line.
Appends kMove_Verb to verb array and (0, 0) to SkPoint array, if needed;
then appends kLine_Verb to verb array and line end to SkPoint array.
Line end is last point plus vector (dx, dy).
Function name stands for "relative line to".
@param dx offset from last point to line end on x-axis
@param dy offset from last point to line end on y-axis
@return reference to SkPathBuilder
*/
SkPathBuilder& rLineTo(SkScalar x, SkScalar y) { return this->rLineTo({x, y}); }
/** Adds quad from last point towards vector pt1, to vector pt2.
If SkPathBuilder is empty, or last SkPath::Verb
is kClose_Verb, last point is set to (0, 0) before adding quad.
Appends kMove_Verb to verb array and (0, 0) to SkPoint array,
if needed; then appends kQuad_Verb to verb array; and appends quad
control and quad end to SkPoint array.
Quad control is last point plus vector pt1.
Quad end is last point plus vector pt2.
Function name stands for "relative quad to".
@param pt1 offset vector from last point to quad control
@param pt2 offset vector from last point to quad end
@return reference to SkPathBuilder
*/
SkPathBuilder& rQuadTo(SkPoint pt1, SkPoint pt2);
/** Adds quad from last point towards vector (dx1, dy1), to vector (dx2, dy2).
If SkPathBuilder is empty, or last SkPath::Verb
is kClose_Verb, last point is set to (0, 0) before adding quad.
Appends kMove_Verb to verb array and (0, 0) to SkPoint array,
if needed; then appends kQuad_Verb to verb array; and appends quad
control and quad end to SkPoint array.
Quad control is last point plus vector (dx1, dy1).
Quad end is last point plus vector (dx2, dy2).
Function name stands for "relative quad to".
@param dx1 offset from last point to quad control on x-axis
@param dy1 offset from last point to quad control on y-axis
@param dx2 offset from last point to quad end on x-axis
@param dy2 offset from last point to quad end on y-axis
@return reference to SkPathBuilder
*/
SkPathBuilder& rQuadTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2) {
return this->rQuadTo({x1, y1}, {x2, y2});
}
/** Adds conic from last point towards vector p1, to vector p2,
weighted by w. If SkPathBuilder is empty, or last SkPath::Verb
is kClose_Verb, last point is set to (0, 0) before adding conic.
Appends kMove_Verb to verb array and (0, 0) to SkPoint array,
if needed.
If w is finite and not one, next appends kConic_Verb to verb array,
and w is recorded as conic weight; otherwise, if w is one, appends
kQuad_Verb to verb array; or if w is not finite, appends kLine_Verb
twice to verb array.
In all cases appends SkPoint control and end to SkPoint array.
control is last point plus vector p1.
end is last point plus vector p2.
Function name stands for "relative conic to".
@param p1 offset vector from last point to conic control
@param p2 offset vector from last point to conic end
@param w weight of added conic
@return reference to SkPathBuilder
*/
SkPathBuilder& rConicTo(SkPoint p1, SkPoint p2, SkScalar w);
/** Adds conic from last point towards vector (dx1, dy1), to vector (dx2, dy2),
weighted by w. If SkPathBuilder is empty, or last SkPath::Verb
is kClose_Verb, last point is set to (0, 0) before adding conic.
Appends kMove_Verb to verb array and (0, 0) to SkPoint array,
if needed.
If w is finite and not one, next appends kConic_Verb to verb array,
and w is recorded as conic weight; otherwise, if w is one, appends
kQuad_Verb to verb array; or if w is not finite, appends kLine_Verb
twice to verb array.
In all cases appends SkPoint control and end to SkPoint array.
control is last point plus vector (dx1, dy1).
end is last point plus vector (dx2, dy2).
Function name stands for "relative conic to".
@param dx1 offset from last point to conic control on x-axis
@param dy1 offset from last point to conic control on y-axis
@param dx2 offset from last point to conic end on x-axis
@param dy2 offset from last point to conic end on y-axis
@param w weight of added conic
@return reference to SkPathBuilder
*/
SkPathBuilder& rConicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2, SkScalar w) {
return this->rConicTo({x1, y1}, {x2, y2}, w);
}
/** Adds cubic from last point towards vector pt1, then towards
vector pt2, to vector pt3.
If SkPathBuilder is empty, or last SkPath::Verb
is kClose_Verb, last point is set to (0, 0) before adding cubic.
Appends kMove_Verb to verb array and (0, 0) to SkPoint array,
if needed; then appends kCubic_Verb to verb array; and appends cubic
control and cubic end to SkPoint array.
Cubic control is last point plus vector (dx1, dy1).
Cubic end is last point plus vector (dx2, dy2).
Function name stands for "relative cubic to".
@param pt1 offset vector from last point to first cubic control
@param pt2 offset vector from last point to second cubic control
@param pt3 offset vector from last point to cubic end
@return reference to SkPathBuilder
*/
SkPathBuilder& rCubicTo(SkPoint pt1, SkPoint pt2, SkPoint pt3);
/** Adds cubic from last point towards vector (dx1, dy1), then towards
vector (dx2, dy2), to vector (dx3, dy3).
If SkPathBuilder is empty, or last SkPath::Verb
is kClose_Verb, last point is set to (0, 0) before adding cubic.
Appends kMove_Verb to verb array and (0, 0) to SkPoint array,
if needed; then appends kCubic_Verb to verb array; and appends cubic
control and cubic end to SkPoint array.
Cubic control is last point plus vector (dx1, dy1).
Cubic end is last point plus vector (dx2, dy2).
Function name stands for "relative cubic to".
@param dx1 offset from last point to first cubic control on x-axis
@param dy1 offset from last point to first cubic control on y-axis
@param dx2 offset from last point to second cubic control on x-axis
@param dy2 offset from last point to second cubic control on y-axis
@param dx3 offset from last point to cubic end on x-axis
@param dy3 offset from last point to cubic end on y-axis
@return reference to SkPathBuilder
*/
SkPathBuilder& rCubicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2, SkScalar x3, SkScalar y3) {
return this->rCubicTo({x1, y1}, {x2, y2}, {x3, y3});
}
// Arcs
enum ArcSize {
kSmall_ArcSize, //!< smaller of arc pair
kLarge_ArcSize, //!< larger of arc pair
};
/** Appends arc to SkPathBuilder, relative to last SkPath SkPoint. Arc is implemented by one or
more conic, weighted to describe part of oval with radii (rx, ry) rotated by
xAxisRotate degrees. Arc curves from last SkPathBuilder SkPoint to relative end SkPoint:
(dx, dy), choosing one of four possible routes: clockwise or
counterclockwise, and smaller or larger. If SkPathBuilder is empty, the start arc SkPoint
is (0, 0).
Arc sweep is always less than 360 degrees. arcTo() appends line to end SkPoint
if either radii are zero, or if last SkPath SkPoint equals end SkPoint.
arcTo() scales radii (rx, ry) to fit last SkPath SkPoint and end SkPoint if both are
greater than zero but too small to describe an arc.
arcTo() appends up to four conic curves.
arcTo() implements the functionality of svg arc, although SVG "sweep-flag" value is
opposite the integer value of sweep; SVG "sweep-flag" uses 1 for clockwise, while
kCW_Direction cast to int is zero.
@param r radii on axes before x-axis rotation
@param xAxisRotate x-axis rotation in degrees; positive values are clockwise
@param largeArc chooses smaller or larger arc
@param sweep chooses clockwise or counterclockwise arc
@param dxdy offset end of arc from last SkPath point
@return reference to SkPath
*/
SkPathBuilder& rArcTo(SkPoint r, SkScalar xAxisRotate, ArcSize largeArc,
SkPathDirection sweep, SkPoint dxdy);
/** Appends arc to the builder. Arc added is part of ellipse
bounded by oval, from startAngle through sweepAngle. Both startAngle and
sweepAngle are measured in degrees, where zero degrees is aligned with the
positive x-axis, and positive sweeps extends arc clockwise.
arcTo() adds line connecting the builder's last point to initial arc point if forceMoveTo
is false and the builder is not empty. Otherwise, added contour begins with first point
of arc. Angles greater than -360 and less than 360 are treated modulo 360.
@param oval bounds of ellipse containing arc
@param startAngleDeg starting angle of arc in degrees
@param sweepAngleDeg sweep, in degrees. Positive is clockwise; treated modulo 360
@param forceMoveTo true to start a new contour with arc
@return reference to the builder
*/
SkPathBuilder& arcTo(const SkRect& oval, SkScalar startAngleDeg, SkScalar sweepAngleDeg,
bool forceMoveTo);
/** Appends arc to SkPath, after appending line if needed. Arc is implemented by conic
weighted to describe part of circle. Arc is contained by tangent from
last SkPath point to p1, and tangent from p1 to p2. Arc
is part of circle sized to radius, positioned so it touches both tangent lines.
If last SkPath SkPoint does not start arc, arcTo() appends connecting line to SkPath.
The length of vector from p1 to p2 does not affect arc.
Arc sweep is always less than 180 degrees. If radius is zero, or if
tangents are nearly parallel, arcTo() appends line from last SkPath SkPoint to p1.
arcTo() appends at most one line and one conic.
arcTo() implements the functionality of PostScript arct and HTML Canvas arcTo.
@param p1 SkPoint common to pair of tangents
@param p2 end of second tangent
@param radius distance from arc to circle center
@return reference to SkPath
*/
SkPathBuilder& arcTo(SkPoint p1, SkPoint p2, SkScalar radius);
/** Appends arc to SkPath. Arc is implemented by one or more conic weighted to describe
part of oval with radii (r.fX, r.fY) rotated by xAxisRotate degrees. Arc curves
from last SkPath SkPoint to (xy.fX, xy.fY), choosing one of four possible routes:
clockwise or counterclockwise,
and smaller or larger.
Arc sweep is always less than 360 degrees. arcTo() appends line to xy if either
radii are zero, or if last SkPath SkPoint equals (xy.fX, xy.fY). arcTo() scales radii r to
fit last SkPath SkPoint and xy if both are greater than zero but too small to describe
an arc.
arcTo() appends up to four conic curves.
arcTo() implements the functionality of SVG arc, although SVG sweep-flag value is
opposite the integer value of sweep; SVG sweep-flag uses 1 for clockwise, while
kCW_Direction cast to int is zero.
@param r radii on axes before x-axis rotation
@param xAxisRotate x-axis rotation in degrees; positive values are clockwise
@param largeArc chooses smaller or larger arc
@param sweep chooses clockwise or counterclockwise arc
@param xy end of arc
@return reference to SkPath
*/
SkPathBuilder& arcTo(SkPoint r, SkScalar xAxisRotate, ArcSize largeArc, SkPathDirection sweep,
SkPoint xy);
/** Appends arc to the builder, as the start of new contour. Arc added is part of ellipse
bounded by oval, from startAngle through sweepAngle. Both startAngle and
sweepAngle are measured in degrees, where zero degrees is aligned with the
positive x-axis, and positive sweeps extends arc clockwise.
If sweepAngle <= -360, or sweepAngle >= 360; and startAngle modulo 90 is nearly
zero, append oval instead of arc. Otherwise, sweepAngle values are treated
modulo 360, and arc may or may not draw depending on numeric rounding.
@param oval bounds of ellipse containing arc
@param startAngleDeg starting angle of arc in degrees
@param sweepAngleDeg sweep, in degrees. Positive is clockwise; treated modulo 360
@return reference to this builder
*/
SkPathBuilder& addArc(const SkRect& oval, SkScalar startAngleDeg, SkScalar sweepAngleDeg);
SkPathBuilder& addLine(SkPoint a, SkPoint b) {
return this->moveTo(a).lineTo(b);
}
/** Adds a new contour to the SkPathBuilder, defined by the rect, and wound in the
specified direction. The verbs added to the path will be:
kMove, kLine, kLine, kLine, kClose
start specifies which corner to begin the contour:
0: upper-left corner
1: upper-right corner
2: lower-right corner
3: lower-left corner
This start point also acts as the implied beginning of the subsequent,
contour, if it does not have an explicit moveTo(). e.g.
path.addRect(...)
// if we don't say moveTo() here, we will use the rect's start point
path.lineTo(...)
@param rect SkRect to add as a closed contour
@param dir SkPath::Direction to orient the new contour
@param start initial corner of SkRect to add
@return reference to SkPathBuilder
*/
SkPathBuilder& addRect(const SkRect&, SkPathDirection, unsigned startIndex);
/** Adds a new contour to the SkPathBuilder, defined by the rect, and wound in the
specified direction. The verbs added to the path will be:
kMove, kLine, kLine, kLine, kClose
The contour starts at the upper-left corner of the rect, which also acts as the implied
beginning of the subsequent contour, if it does not have an explicit moveTo(). e.g.
path.addRect(...)
// if we don't say moveTo() here, we will use the rect's upper-left corner
path.lineTo(...)
@param rect SkRect to add as a closed contour
@param dir SkPath::Direction to orient the new contour
@return reference to SkPathBuilder
*/
SkPathBuilder& addRect(const SkRect& rect, SkPathDirection dir = SkPathDirection::kDefault) {
return this->addRect(rect, dir, 0);
}
/** Adds oval to SkPathBuilder, appending kMove_Verb, four kConic_Verb, and kClose_Verb.
Oval is upright ellipse bounded by SkRect oval with radii equal to half oval width
and half oval height. Oval begins at (oval.fRight, oval.centerY()) and continues
clockwise if dir is kCW_Direction, counterclockwise if dir is kCCW_Direction.
@param oval bounds of ellipse added
@param dir SkPath::Direction to wind ellipse
@return reference to SkPathBuilder
*/
SkPathBuilder& addOval(const SkRect&, SkPathDirection, unsigned startIndex);
/** Appends SkRRect to SkPathBuilder, creating a new closed contour. If dir is kCW_Direction,
SkRRect winds clockwise. If dir is kCCW_Direction, SkRRect winds counterclockwise.
After appending, SkPathBuilder may be empty, or may contain: SkRect, oval, or SkRRect.
@param rrect SkRRect to add
@param dir SkPath::Direction to wind SkRRect
@param start index of initial point of SkRRect
@return reference to SkPathBuilder
*/
SkPathBuilder& addRRect(const SkRRect& rrect, SkPathDirection, unsigned start);
/** Appends SkRRect to SkPathBuilder, creating a new closed contour. If dir is kCW_Direction,
SkRRect starts at top-left of the lower-left corner and winds clockwise. If dir is
kCCW_Direction, SkRRect starts at the bottom-left of the upper-left corner and winds
counterclockwise.
After appending, SkPathBuilder may be empty, or may contain: SkRect, oval, or SkRRect.
@param rrect SkRRect to add
@param dir SkPath::Direction to wind SkRRect
@return reference to SkPathBuilder
*/
SkPathBuilder& addRRect(const SkRRect& rrect, SkPathDirection dir = SkPathDirection::kDefault) {
// legacy start indices: 6 (CW) and 7 (CCW)
return this->addRRect(rrect, dir, dir == SkPathDirection::kCW ? 6 : 7);
}
/** Adds oval to SkPathBuilder, appending kMove_Verb, four kConic_Verb, and kClose_Verb.
Oval is upright ellipse bounded by SkRect oval with radii equal to half oval width
and half oval height. Oval begins at start and continues
clockwise if dir is kCW_Direction, counterclockwise if dir is kCCW_Direction.
@param oval bounds of ellipse added
@param dir SkPath::Direction to wind ellipse
@return reference to SkPath
example: https://fiddle.skia.org/c/@Path_addOval_2
*/
SkPathBuilder& addOval(const SkRect& oval, SkPathDirection dir = SkPathDirection::kDefault) {
// legacy start index: 1
return this->addOval(oval, dir, 1);
}
/** Adds circle centered at (x, y) of size radius to SkPathBuilder, appending kMove_Verb,
four kConic_Verb, and kClose_Verb. Circle begins at: (x + radius, y), continuing
clockwise if dir is kCW_Direction, and counterclockwise if dir is kCCW_Direction.
Has no effect if radius is zero or negative.
@param x center of circle
@param y center of circle
@param radius distance from center to edge
@param dir SkPath::Direction to wind circle
@return reference to SkPathBuilder
*/
SkPathBuilder& addCircle(SkScalar x, SkScalar y, SkScalar radius,
SkPathDirection dir = SkPathDirection::kDefault);
/** Adds contour created from line array, adding (pts.size() - 1) line segments.
Contour added starts at pts[0], then adds a line for every additional SkPoint
in pts array. If close is true, appends kClose_Verb to SkPath, connecting
pts[count - 1] and pts[0].
@param pts array of line sharing end and start SkPoint
@param close true to add line connecting contour end and start
@return reference to SkPath
*/
SkPathBuilder& addPolygon(SkSpan<const SkPoint> pts, bool close);
/** Appends src to SkPathBuilder, offset by (dx, dy).
If mode is kAppend_AddPathMode, src verb array, SkPoint array, and conic weights are
added unaltered. If mode is kExtend_AddPathMode, add line before appending
verbs, SkPoint, and conic weights.
@param src SkPath verbs, SkPoint, and conic weights to add
@param dx offset added to src SkPoint array x-axis coordinates
@param dy offset added to src SkPoint array y-axis coordinates
@param mode kAppend_AddPathMode or kExtend_AddPathMode
@return reference to SkPathBuilder
*/
SkPathBuilder& addPath(const SkPath& src, SkScalar dx, SkScalar dy,
SkPath::AddPathMode mode = SkPath::kAppend_AddPathMode);
/** Appends src to SkPathBuilder.
If mode is kAppend_AddPathMode, src verb array, SkPoint array, and conic weights are
added unaltered. If mode is kExtend_AddPathMode, add line before appending
verbs, SkPoint, and conic weights.
@param src SkPath verbs, SkPoint, and conic weights to add
@param mode kAppend_AddPathMode or kExtend_AddPathMode
@return reference to SkPathBuilder
*/
SkPathBuilder& addPath(const SkPath& src,
SkPath::AddPathMode mode = SkPath::kAppend_AddPathMode) {
return this->addPath(src, SkMatrix::I(), mode);
}
/** Appends src to SkPathBuilder, transformed by matrix. Transformed curves may have different
verbs, SkPoint, and conic weights.
If mode is kAppend_AddPathMode, src verb array, SkPoint array, and conic weights are
added unaltered. If mode is kExtend_AddPathMode, add line before appending
verbs, SkPoint, and conic weights.
@param src SkPath verbs, SkPoint, and conic weights to add
@param matrix transform applied to src
@param mode kAppend_AddPathMode or kExtend_AddPathMode
@return reference to SkPathBuilder
*/
SkPathBuilder& addPath(const SkPath& src, const SkMatrix& matrix,
SkPath::AddPathMode mode = SkPath::AddPathMode::kAppend_AddPathMode);
// Performance hint, to reserve extra storage for subsequent calls to lineTo, quadTo, etc.
/** Grows SkPathBuilder verb array and SkPoint array to contain additional space.
May improve performance and use less memory by
reducing the number and size of allocations when creating SkPathBuilder.
@param extraPtCount number of additional SkPoint to allocate
@param extraVerbCount number of additional verbs
@param extraConicCount number of additional conic weights
*/
void incReserve(int extraPtCount, int extraVerbCount, int extraConicCount);
/** Grows SkPathBuilder verb array and SkPoint array to contain additional space.
May improve performance and use less memory by
reducing the number and size of allocations when creating SkPathBuilder.
@param extraPtCount number of additional SkPoints and verbs to allocate
*/
void incReserve(int extraPtCount) {
this->incReserve(extraPtCount, extraPtCount, 0);
}
/** Offsets SkPoint array by (dx, dy).
@param dx offset added to SkPoint array x-axis coordinates
@param dy offset added to SkPoint array y-axis coordinates
*/
SkPathBuilder& offset(SkScalar dx, SkScalar dy);
/** Transforms verb array, SkPoint array, and weight by matrix.
transform may change verbs and increase their number.
@param matrix SkMatrix to apply to SkPath
@param pc whether to apply perspective clipping
*/
SkPathBuilder& transform(const SkMatrix& matrix);
/*
* Returns true if the builder is empty, or all of its points are finite.
*/
bool isFinite() const;
/** Replaces SkPathFillType with its inverse. The inverse of SkPathFillType describes the area
unmodified by the original SkPathFillType.
*/
SkPathBuilder& toggleInverseFillType() {
fFillType = (SkPathFillType)((unsigned)fFillType ^ 2);
return *this;
}
/** Returns if SkPath is empty.
Empty SkPathBuilder may have FillType but has no SkPoint, SkPath::Verb, or conic weight.
SkPathBuilder() constructs empty SkPathBuilder; reset() and rewind() make SkPath empty.
@return true if the path contains no SkPath::Verb array
*/
bool isEmpty() const { return fVerbs.empty(); }
/** Returns last point on SkPathBuilder. Returns nullopt if SkPoint array is empty.
@return last SkPoint if SkPoint array contains one or more SkPoint, otherwise nullopt
example: https://fiddle.skia.org/c/@Path_getLastPt
*/
std::optional<SkPoint> getLastPt() const;
/** Change the point at the specified index (see countPoints()).
* If index is out of range, the call does nothing.
*
* @param index which point to replace
* @param p the new point value
*/
void setPoint(size_t index, SkPoint p);
/** Sets the last point on the path. If SkPoint array is empty, append kMove_Verb to
verb array and append p to SkPoint array.
@param x x-value of last point
@param y y-value of last point
*/
void setLastPt(SkScalar x, SkScalar y);
/** Returns the number of points in SkPathBuilder.
SkPoint count is initially zero.
@return SkPathBuilder SkPoint array length
*/
int countPoints() const { return fPts.size(); }
/** Returns if SkPathFillType describes area outside SkPath geometry. The inverse fill area
extends indefinitely.
@return true if FillType is kInverseWinding or kInverseEvenOdd
*/
bool isInverseFillType() const { return SkPathFillType_IsInverse(fFillType); }
#ifdef SK_SUPPORT_UNSPANNED_APIS
SkPathBuilder& addPolygon(const SkPoint pts[], int count, bool close) {
return this->addPolygon({pts, count}, close);
}
SkPathBuilder& polylineTo(const SkPoint pts[], int count) {
return this->polylineTo({pts, count});
}
#endif
SkSpan<const SkPoint> points() const {
return fPts;
}
SkSpan<const SkPathVerb> verbs() const {
return fVerbs;
}
SkSpan<const float> conicWeights() const {
return fConicWeights;
}
SkPathBuilder& addRaw(const SkPathRaw&);
SkPathIter iter() const;
enum class DumpFormat {
kDecimal,
kHex,
};
SkString dumpToString(DumpFormat = DumpFormat::kDecimal) const;
void dump(DumpFormat) const;
// can't use default argument easily in debugger, so we name this
// helper explicitly.
void dump() const { this->dump(DumpFormat::kDecimal); }
private:
SkPathRef::PointsArray fPts;
SkPathRef::VerbsArray fVerbs;
SkPathRef::ConicWeightsArray fConicWeights;
SkPathFillType fFillType;
bool fIsVolatile;
SkPathConvexity fConvexity;
unsigned fSegmentMask;
SkPoint fLastMovePoint;
int fLastMoveIndex; // only needed until SkPath is immutable
bool fNeedsMoveVerb;
SkPathIsAType fType = SkPathIsAType::kGeneral;
SkPathIsAData fIsA {};
// called right before we add a (non-move) verb
void ensureMove() {
fType = SkPathIsAType::kGeneral;
if (fNeedsMoveVerb) {
this->moveTo(fLastMovePoint);
}
}
SkPath make(sk_sp<SkPathRef>) const;
bool isZeroLengthSincePoint(int startPtIndex) const;
SkPathBuilder& privateReverseAddPath(const SkPath&);
SkPathBuilder& privateReversePathTo(const SkPath&);
std::tuple<SkPoint*, SkScalar*> growForVerbsInPath(const SkPathRef& path);
friend class SkPathPriv;
friend class SkStroke;
friend class SkPathStroker;
};
#endif