| 1 | /* | 
|---|
| 2 | * Copyright 2015 Google Inc. | 
|---|
| 3 | * | 
|---|
| 4 | * Use of this source code is governed by a BSD-style license that can be | 
|---|
| 5 | * found in the LICENSE file. | 
|---|
| 6 | */ | 
|---|
| 7 |  | 
|---|
| 8 | #ifndef SkPathBuilder_DEFINED | 
|---|
| 9 | #define SkPathBuilder_DEFINED | 
|---|
| 10 |  | 
|---|
| 11 | #include "include/core/SkMatrix.h" | 
|---|
| 12 | #include "include/core/SkPath.h" | 
|---|
| 13 | #include "include/core/SkPathTypes.h" | 
|---|
| 14 | #include "include/private/SkTDArray.h" | 
|---|
| 15 |  | 
|---|
| 16 | class SK_API SkPathBuilder { | 
|---|
| 17 | public: | 
|---|
| 18 | SkPathBuilder(); | 
|---|
| 19 | ~SkPathBuilder(); | 
|---|
| 20 |  | 
|---|
| 21 | SkPath snapshot();  // the builder is unchanged after returning this path | 
|---|
| 22 | SkPath detach();    // the builder is reset to empty after returning this path | 
|---|
| 23 |  | 
|---|
| 24 | SkPathBuilder& setFillType(SkPathFillType ft) { fFillType = ft; return *this; } | 
|---|
| 25 | SkPathBuilder& setIsVolatile(bool isVolatile) { fIsVolatile = isVolatile; return *this; } | 
|---|
| 26 |  | 
|---|
| 27 | SkPathBuilder& reset(); | 
|---|
| 28 |  | 
|---|
| 29 | SkPathBuilder& moveTo(SkPoint pt); | 
|---|
| 30 | SkPathBuilder& moveTo(SkScalar x, SkScalar y) { return this->moveTo(SkPoint::Make(x, y)); } | 
|---|
| 31 |  | 
|---|
| 32 | SkPathBuilder& lineTo(SkPoint pt); | 
|---|
| 33 | SkPathBuilder& lineTo(SkScalar x, SkScalar y) { return this->lineTo(SkPoint::Make(x, y)); } | 
|---|
| 34 |  | 
|---|
| 35 | SkPathBuilder& quadTo(SkPoint pt1, SkPoint pt2); | 
|---|
| 36 | SkPathBuilder& quadTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2) { | 
|---|
| 37 | return this->quadTo(SkPoint::Make(x1, y1), SkPoint::Make(x2, y2)); | 
|---|
| 38 | } | 
|---|
| 39 | SkPathBuilder& quadTo(const SkPoint pts[2]) { return this->quadTo(pts[0], pts[1]); } | 
|---|
| 40 |  | 
|---|
| 41 | SkPathBuilder& conicTo(SkPoint pt1, SkPoint pt2, SkScalar w); | 
|---|
| 42 | SkPathBuilder& conicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2, SkScalar w) { | 
|---|
| 43 | return this->conicTo(SkPoint::Make(x1, y1), SkPoint::Make(x2, y2), w); | 
|---|
| 44 | } | 
|---|
| 45 | SkPathBuilder& conicTo(const SkPoint pts[2], SkScalar w) { | 
|---|
| 46 | return this->conicTo(pts[0], pts[1], w); | 
|---|
| 47 | } | 
|---|
| 48 |  | 
|---|
| 49 | SkPathBuilder& cubicTo(SkPoint pt1, SkPoint pt2, SkPoint pt3); | 
|---|
| 50 | SkPathBuilder& cubicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2, SkScalar x3, SkScalar y3) { | 
|---|
| 51 | return this->cubicTo(SkPoint::Make(x1, y1), SkPoint::Make(x2, y2), SkPoint::Make(x3, y3)); | 
|---|
| 52 | } | 
|---|
| 53 | SkPathBuilder& cubicTo(const SkPoint pts[3]) { | 
|---|
| 54 | return this->cubicTo(pts[0], pts[1], pts[2]); | 
|---|
| 55 | } | 
|---|
| 56 |  | 
|---|
| 57 | SkPathBuilder& close(); | 
|---|
| 58 |  | 
|---|
| 59 | // Relative versions of segments, relative to the previous position. | 
|---|
| 60 |  | 
|---|
| 61 | SkPathBuilder& rLineTo(SkPoint pt); | 
|---|
| 62 | SkPathBuilder& rLineTo(SkScalar x, SkScalar y) { return this->rLineTo({x, y}); } | 
|---|
| 63 | SkPathBuilder& rQuadTo(SkPoint pt1, SkPoint pt2); | 
|---|
| 64 | SkPathBuilder& rQuadTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2) { | 
|---|
| 65 | return this->rQuadTo({x1, y1}, {x2, y2}); | 
|---|
| 66 | } | 
|---|
| 67 | SkPathBuilder& rConicTo(SkPoint p1, SkPoint p2, SkScalar w); | 
|---|
| 68 | SkPathBuilder& rConicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2, SkScalar w) { | 
|---|
| 69 | return this->rConicTo({x1, y1}, {x2, y2}, w); | 
|---|
| 70 | } | 
|---|
| 71 | SkPathBuilder& rCubicTo(SkPoint pt1, SkPoint pt2, SkPoint pt3); | 
|---|
| 72 | SkPathBuilder& rCubicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2, SkScalar x3, SkScalar y3) { | 
|---|
| 73 | return this->rCubicTo({x1, y1}, {x2, y2}, {x3, y3}); | 
|---|
| 74 | } | 
|---|
| 75 |  | 
|---|
| 76 | // Arcs | 
|---|
| 77 |  | 
|---|
| 78 | /** Appends arc to the builder. Arc added is part of ellipse | 
|---|
| 79 | bounded by oval, from startAngle through sweepAngle. Both startAngle and | 
|---|
| 80 | sweepAngle are measured in degrees, where zero degrees is aligned with the | 
|---|
| 81 | positive x-axis, and positive sweeps extends arc clockwise. | 
|---|
| 82 |  | 
|---|
| 83 | arcTo() adds line connecting the builder's last point to initial arc point if forceMoveTo | 
|---|
| 84 | is false and the builder is not empty. Otherwise, added contour begins with first point | 
|---|
| 85 | of arc. Angles greater than -360 and less than 360 are treated modulo 360. | 
|---|
| 86 |  | 
|---|
| 87 | @param oval          bounds of ellipse containing arc | 
|---|
| 88 | @param startAngleDeg starting angle of arc in degrees | 
|---|
| 89 | @param sweepAngleDeg sweep, in degrees. Positive is clockwise; treated modulo 360 | 
|---|
| 90 | @param forceMoveTo   true to start a new contour with arc | 
|---|
| 91 | @return              reference to the builder | 
|---|
| 92 | */ | 
|---|
| 93 | SkPathBuilder& arcTo(const SkRect& oval, SkScalar startAngleDeg, SkScalar sweepAngleDeg, | 
|---|
| 94 | bool forceMoveTo); | 
|---|
| 95 |  | 
|---|
| 96 | /** Appends arc to SkPath, after appending line if needed. Arc is implemented by conic | 
|---|
| 97 | weighted to describe part of circle. Arc is contained by tangent from | 
|---|
| 98 | last SkPath point to p1, and tangent from p1 to p2. Arc | 
|---|
| 99 | is part of circle sized to radius, positioned so it touches both tangent lines. | 
|---|
| 100 |  | 
|---|
| 101 | If last SkPath SkPoint does not start arc, arcTo() appends connecting line to SkPath. | 
|---|
| 102 | The length of vector from p1 to p2 does not affect arc. | 
|---|
| 103 |  | 
|---|
| 104 | Arc sweep is always less than 180 degrees. If radius is zero, or if | 
|---|
| 105 | tangents are nearly parallel, arcTo() appends line from last SkPath SkPoint to p1. | 
|---|
| 106 |  | 
|---|
| 107 | arcTo() appends at most one line and one conic. | 
|---|
| 108 | arcTo() implements the functionality of PostScript arct and HTML Canvas arcTo. | 
|---|
| 109 |  | 
|---|
| 110 | @param p1      SkPoint common to pair of tangents | 
|---|
| 111 | @param p2      end of second tangent | 
|---|
| 112 | @param radius  distance from arc to circle center | 
|---|
| 113 | @return        reference to SkPath | 
|---|
| 114 | */ | 
|---|
| 115 | SkPathBuilder& arcTo(SkPoint p1, SkPoint p2, SkScalar radius); | 
|---|
| 116 |  | 
|---|
| 117 | enum ArcSize { | 
|---|
| 118 | kSmall_ArcSize, //!< smaller of arc pair | 
|---|
| 119 | kLarge_ArcSize, //!< larger of arc pair | 
|---|
| 120 | }; | 
|---|
| 121 |  | 
|---|
| 122 | /** Appends arc to SkPath. Arc is implemented by one or more conic weighted to describe | 
|---|
| 123 | part of oval with radii (r.fX, r.fY) rotated by xAxisRotate degrees. Arc curves | 
|---|
| 124 | from last SkPath SkPoint to (xy.fX, xy.fY), choosing one of four possible routes: | 
|---|
| 125 | clockwise or counterclockwise, | 
|---|
| 126 | and smaller or larger. | 
|---|
| 127 |  | 
|---|
| 128 | Arc sweep is always less than 360 degrees. arcTo() appends line to xy if either | 
|---|
| 129 | radii are zero, or if last SkPath SkPoint equals (xy.fX, xy.fY). arcTo() scales radii r to | 
|---|
| 130 | fit last SkPath SkPoint and xy if both are greater than zero but too small to describe | 
|---|
| 131 | an arc. | 
|---|
| 132 |  | 
|---|
| 133 | arcTo() appends up to four conic curves. | 
|---|
| 134 | arcTo() implements the functionality of SVG arc, although SVG sweep-flag value is | 
|---|
| 135 | opposite the integer value of sweep; SVG sweep-flag uses 1 for clockwise, while | 
|---|
| 136 | kCW_Direction cast to int is zero. | 
|---|
| 137 |  | 
|---|
| 138 | @param r            radii on axes before x-axis rotation | 
|---|
| 139 | @param xAxisRotate  x-axis rotation in degrees; positive values are clockwise | 
|---|
| 140 | @param largeArc     chooses smaller or larger arc | 
|---|
| 141 | @param sweep        chooses clockwise or counterclockwise arc | 
|---|
| 142 | @param xy           end of arc | 
|---|
| 143 | @return             reference to SkPath | 
|---|
| 144 | */ | 
|---|
| 145 | SkPathBuilder& arcTo(SkPoint r, SkScalar xAxisRotate, ArcSize largeArc, SkPathDirection sweep, | 
|---|
| 146 | SkPoint xy); | 
|---|
| 147 |  | 
|---|
| 148 | /** Appends arc to the builder, as the start of new contour. Arc added is part of ellipse | 
|---|
| 149 | bounded by oval, from startAngle through sweepAngle. Both startAngle and | 
|---|
| 150 | sweepAngle are measured in degrees, where zero degrees is aligned with the | 
|---|
| 151 | positive x-axis, and positive sweeps extends arc clockwise. | 
|---|
| 152 |  | 
|---|
| 153 | If sweepAngle <= -360, or sweepAngle >= 360; and startAngle modulo 90 is nearly | 
|---|
| 154 | zero, append oval instead of arc. Otherwise, sweepAngle values are treated | 
|---|
| 155 | modulo 360, and arc may or may not draw depending on numeric rounding. | 
|---|
| 156 |  | 
|---|
| 157 | @param oval          bounds of ellipse containing arc | 
|---|
| 158 | @param startAngleDeg starting angle of arc in degrees | 
|---|
| 159 | @param sweepAngleDeg sweep, in degrees. Positive is clockwise; treated modulo 360 | 
|---|
| 160 | @return              reference to this builder | 
|---|
| 161 | */ | 
|---|
| 162 | SkPathBuilder& addArc(const SkRect& oval, SkScalar startAngleDeg, SkScalar sweepAngleDeg); | 
|---|
| 163 |  | 
|---|
| 164 | // Add a new contour | 
|---|
| 165 |  | 
|---|
| 166 | SkPathBuilder& addRect(const SkRect&, SkPathDirection, unsigned startIndex); | 
|---|
| 167 | SkPathBuilder& addOval(const SkRect&, SkPathDirection, unsigned startIndex); | 
|---|
| 168 | SkPathBuilder& addRRect(const SkRRect&, SkPathDirection, unsigned startIndex); | 
|---|
| 169 |  | 
|---|
| 170 | SkPathBuilder& addRect(const SkRect& rect, SkPathDirection dir = SkPathDirection::kCW) { | 
|---|
| 171 | return this->addRect(rect, dir, 0); | 
|---|
| 172 | } | 
|---|
| 173 | SkPathBuilder& addOval(const SkRect& rect, SkPathDirection dir = SkPathDirection::kCW) { | 
|---|
| 174 | // legacy start index: 1 | 
|---|
| 175 | return this->addOval(rect, dir, 1); | 
|---|
| 176 | } | 
|---|
| 177 | SkPathBuilder& addRRect(const SkRRect& rrect, SkPathDirection dir = SkPathDirection::kCW) { | 
|---|
| 178 | // legacy start indices: 6 (CW) and 7 (CCW) | 
|---|
| 179 | return this->addRRect(rrect, dir, dir == SkPathDirection::kCW ? 6 : 7); | 
|---|
| 180 | } | 
|---|
| 181 |  | 
|---|
| 182 | SkPathBuilder& addCircle(SkScalar center_x, SkScalar center_y, SkScalar radius, | 
|---|
| 183 | SkPathDirection dir = SkPathDirection::kCW); | 
|---|
| 184 |  | 
|---|
| 185 | SkPathBuilder& addPolygon(const SkPoint pts[], int count, bool isClosed); | 
|---|
| 186 | SkPathBuilder& addPolygon(const std::initializer_list<SkPoint>& list, bool isClosed) { | 
|---|
| 187 | return this->addPolygon(list.begin(), SkToInt(list.size()), isClosed); | 
|---|
| 188 | } | 
|---|
| 189 |  | 
|---|
| 190 | // Performance hint, to reserve extra storage for subsequent calls to lineTo, quadTo, etc. | 
|---|
| 191 |  | 
|---|
| 192 | void incReserve(int , int ); | 
|---|
| 193 | void incReserve(int ) { | 
|---|
| 194 | this->incReserve(extraPtCount, extraPtCount); | 
|---|
| 195 | } | 
|---|
| 196 |  | 
|---|
| 197 | private: | 
|---|
| 198 | SkTDArray<SkPoint>  fPts; | 
|---|
| 199 | SkTDArray<uint8_t>  fVerbs; | 
|---|
| 200 | SkTDArray<SkScalar> fConicWeights; | 
|---|
| 201 |  | 
|---|
| 202 | SkPathFillType      fFillType; | 
|---|
| 203 | bool                fIsVolatile; | 
|---|
| 204 |  | 
|---|
| 205 | unsigned    fSegmentMask; | 
|---|
| 206 | SkPoint     fLastMovePoint; | 
|---|
| 207 | bool        fNeedsMoveVerb; | 
|---|
| 208 |  | 
|---|
| 209 | enum IsA { | 
|---|
| 210 | kIsA_JustMoves,     // we only have 0 or more moves | 
|---|
| 211 | kIsA_MoreThanMoves, // we have verbs other than just move | 
|---|
| 212 | kIsA_Oval,          // we are 0 or more moves followed by an oval | 
|---|
| 213 | kIsA_RRect,         // we are 0 or more moves followed by a rrect | 
|---|
| 214 | }; | 
|---|
| 215 | IsA fIsA      = kIsA_JustMoves; | 
|---|
| 216 | int fIsAStart = -1;     // tracks direction iff fIsA is not unknown | 
|---|
| 217 | bool fIsACCW  = false;  // tracks direction iff fIsA is not unknown | 
|---|
| 218 |  | 
|---|
| 219 | int countVerbs() const { return fVerbs.count(); } | 
|---|
| 220 |  | 
|---|
| 221 | // called right before we add a (non-move) verb | 
|---|
| 222 | void ensureMove() { | 
|---|
| 223 | fIsA = kIsA_MoreThanMoves; | 
|---|
| 224 | if (fNeedsMoveVerb) { | 
|---|
| 225 | this->moveTo(fLastMovePoint); | 
|---|
| 226 | } | 
|---|
| 227 | } | 
|---|
| 228 |  | 
|---|
| 229 | SkPath make(sk_sp<SkPathRef>) const; | 
|---|
| 230 | }; | 
|---|
| 231 |  | 
|---|
| 232 | #endif | 
|---|
| 233 |  | 
|---|
| 234 |  | 
|---|