return this from maker calls, so we can chain the calls

Bug: skia:
Change-Id: Id62eda9dab9399ce1183a959438db7dde59889d8
Reviewed-on: https://skia-review.googlesource.com/147113
Commit-Queue: Mike Reed <reed@google.com>
Reviewed-by: Kevin Lubick <kjlubick@google.com>
This commit is contained in:
Mike Reed 2018-08-15 10:23:39 -04:00 committed by Skia Commit-Bot
parent 31a0944bb3
commit b631742f0b
6 changed files with 261 additions and 256 deletions

View File

@ -14,10 +14,10 @@ namespace {
void test_concave(SkCanvas* canvas, const SkPaint& paint) {
SkPath path;
canvas->translate(0, 0);
path.moveTo(SkIntToScalar(20), SkIntToScalar(20));
path.lineTo(SkIntToScalar(80), SkIntToScalar(20));
path.lineTo(SkIntToScalar(30), SkIntToScalar(30));
path.lineTo(SkIntToScalar(20), SkIntToScalar(80));
path.moveTo(SkIntToScalar(20), SkIntToScalar(20))
.lineTo(SkIntToScalar(80), SkIntToScalar(20))
.lineTo(SkIntToScalar(30), SkIntToScalar(30))
.lineTo(SkIntToScalar(20), SkIntToScalar(80));
canvas->drawPath(path, paint);
}
@ -26,10 +26,10 @@ void test_reverse_concave(SkCanvas* canvas, const SkPaint& paint) {
SkPath path;
canvas->save();
canvas->translate(100, 0);
path.moveTo(SkIntToScalar(20), SkIntToScalar(20));
path.lineTo(SkIntToScalar(20), SkIntToScalar(80));
path.lineTo(SkIntToScalar(30), SkIntToScalar(30));
path.lineTo(SkIntToScalar(80), SkIntToScalar(20));
path.moveTo(SkIntToScalar(20), SkIntToScalar(20))
.lineTo(SkIntToScalar(20), SkIntToScalar(80))
.lineTo(SkIntToScalar(30), SkIntToScalar(30))
.lineTo(SkIntToScalar(80), SkIntToScalar(20));
canvas->drawPath(path, paint);
canvas->restore();
}
@ -39,10 +39,10 @@ void test_bowtie(SkCanvas* canvas, const SkPaint& paint) {
SkPath path;
canvas->save();
canvas->translate(200, 0);
path.moveTo(SkIntToScalar(20), SkIntToScalar(20));
path.lineTo(SkIntToScalar(80), SkIntToScalar(80));
path.lineTo(SkIntToScalar(80), SkIntToScalar(20));
path.lineTo(SkIntToScalar(20), SkIntToScalar(80));
path.moveTo(SkIntToScalar(20), SkIntToScalar(20))
.lineTo(SkIntToScalar(80), SkIntToScalar(80))
.lineTo(SkIntToScalar(80), SkIntToScalar(20))
.lineTo(SkIntToScalar(20), SkIntToScalar(80));
canvas->drawPath(path, paint);
canvas->restore();
}
@ -52,12 +52,12 @@ void test_fake_bowtie(SkCanvas* canvas, const SkPaint& paint) {
SkPath path;
canvas->save();
canvas->translate(300, 0);
path.moveTo(SkIntToScalar(20), SkIntToScalar(20));
path.lineTo(SkIntToScalar(50), SkIntToScalar(40));
path.lineTo(SkIntToScalar(80), SkIntToScalar(20));
path.lineTo(SkIntToScalar(80), SkIntToScalar(80));
path.lineTo(SkIntToScalar(50), SkIntToScalar(60));
path.lineTo(SkIntToScalar(20), SkIntToScalar(80));
path.moveTo(SkIntToScalar(20), SkIntToScalar(20))
.lineTo(SkIntToScalar(50), SkIntToScalar(40))
.lineTo(SkIntToScalar(80), SkIntToScalar(20))
.lineTo(SkIntToScalar(80), SkIntToScalar(80))
.lineTo(SkIntToScalar(50), SkIntToScalar(60))
.lineTo(SkIntToScalar(20), SkIntToScalar(80));
canvas->drawPath(path, paint);
canvas->restore();
}
@ -69,12 +69,12 @@ void test_intruding_vertex(SkCanvas* canvas, const SkPaint& paint) {
canvas->save();
canvas->translate(400, 0);
path.setIsVolatile(true);
path.moveTo(20, 20);
path.lineTo(50, 50);
path.lineTo(68, 20);
path.lineTo(68, 80);
path.lineTo(50, 50);
path.lineTo(20, 80);
path.moveTo(20, 20)
.lineTo(50, 50)
.lineTo(68, 20)
.lineTo(68, 80)
.lineTo(50, 50)
.lineTo(20, 80);
canvas->drawPath(path, paint);
canvas->restore();
}
@ -86,12 +86,12 @@ void test_inversion_repeat_vertex(SkCanvas* canvas, const SkPaint& paint) {
canvas->save();
canvas->translate(400, 100);
path.setIsVolatile(true);
path.moveTo(80, 50);
path.lineTo(40, 80);
path.lineTo(60, 20);
path.lineTo(20, 20);
path.lineTo(39.99f, 80);
path.lineTo(80, 50);
path.moveTo(80, 50)
.lineTo(40, 80)
.lineTo(60, 20)
.lineTo(20, 20)
.lineTo(39.99f, 80)
.lineTo(80, 50);
canvas->drawPath(path, paint);
canvas->restore();
}
@ -101,12 +101,12 @@ void test_fish(SkCanvas* canvas, const SkPaint& paint) {
SkPath path;
canvas->save();
canvas->translate(0, 100);
path.moveTo(SkIntToScalar(20), SkIntToScalar(20));
path.lineTo(SkIntToScalar(80), SkIntToScalar(80));
path.lineTo(SkIntToScalar(70), SkIntToScalar(50));
path.lineTo(SkIntToScalar(80), SkIntToScalar(20));
path.lineTo(SkIntToScalar(20), SkIntToScalar(80));
path.lineTo(SkIntToScalar(0), SkIntToScalar(50));
path.moveTo(SkIntToScalar(20), SkIntToScalar(20))
.lineTo(SkIntToScalar(80), SkIntToScalar(80))
.lineTo(SkIntToScalar(70), SkIntToScalar(50))
.lineTo(SkIntToScalar(80), SkIntToScalar(20))
.lineTo(SkIntToScalar(20), SkIntToScalar(80))
.lineTo(SkIntToScalar(0), SkIntToScalar(50));
canvas->drawPath(path, paint);
canvas->restore();
}
@ -117,12 +117,12 @@ void test_fast_forward(SkCanvas* canvas, const SkPaint& paint) {
SkPath path;
canvas->save();
canvas->translate(100, 100);
path.moveTo(SkIntToScalar(20), SkIntToScalar(20));
path.lineTo(SkIntToScalar(60), SkIntToScalar(50));
path.lineTo(SkIntToScalar(20), SkIntToScalar(80));
path.moveTo(SkIntToScalar(40), SkIntToScalar(20));
path.lineTo(SkIntToScalar(40), SkIntToScalar(80));
path.lineTo(SkIntToScalar(80), SkIntToScalar(50));
path.moveTo(SkIntToScalar(20), SkIntToScalar(20))
.lineTo(SkIntToScalar(60), SkIntToScalar(50))
.lineTo(SkIntToScalar(20), SkIntToScalar(80))
.moveTo(SkIntToScalar(40), SkIntToScalar(20))
.lineTo(SkIntToScalar(40), SkIntToScalar(80))
.lineTo(SkIntToScalar(80), SkIntToScalar(50));
canvas->drawPath(path, paint);
canvas->restore();
}
@ -132,30 +132,18 @@ void test_hole(SkCanvas* canvas, const SkPaint& paint) {
SkPath path;
canvas->save();
canvas->translate(200, 100);
path.moveTo(SkIntToScalar(20), SkIntToScalar(20));
path.lineTo(SkIntToScalar(80), SkIntToScalar(20));
path.lineTo(SkIntToScalar(80), SkIntToScalar(80));
path.lineTo(SkIntToScalar(20), SkIntToScalar(80));
path.moveTo(SkIntToScalar(30), SkIntToScalar(30));
path.lineTo(SkIntToScalar(30), SkIntToScalar(70));
path.lineTo(SkIntToScalar(70), SkIntToScalar(70));
path.lineTo(SkIntToScalar(70), SkIntToScalar(30));
path.addPoly({{20,20}, {80,20}, {80,80}, {20,80}}, false)
.addPoly({{30,30}, {30,70}, {70,70}, {70,30}}, false);
canvas->drawPath(path, paint);
canvas->restore();
}
// Star test (self-intersecting)
void test_star(SkCanvas* canvas, const SkPaint& paint) {
SkPath path;
canvas->save();
canvas->translate(300, 100);
path.moveTo(30, 20);
path.lineTo(50, 80);
path.lineTo(70, 20);
path.lineTo(20, 57);
path.lineTo(80, 57);
path.close();
canvas->drawPath(path, paint);
canvas->drawPath(SkPath().addPoly({{30,20}, {50,80}, {70,20}, {20,57}, {80,57}}, false),
paint);
canvas->restore();
}

View File

@ -21,6 +21,7 @@
#include "SkMatrix.h"
#include "../private/SkPathRef.h"
#include "../private/SkTo.h"
#include <initializer_list>
class SkAutoPathBoundsUpdate;
class SkData;
@ -301,7 +302,7 @@ public:
Removes verb array, SkPoint array, and weights, and sets FillType to kWinding_FillType.
Internal storage associated with SkPath is released.
*/
void reset();
SkPath& reset();
/** Sets SkPath to its initial state, preserving internal storage.
Removes verb array, SkPoint array, and weights, and sets FillType to kWinding_FillType.
@ -310,7 +311,7 @@ public:
Use rewind() instead of reset() if SkPath storage will be reused and performance
is critical.
*/
void rewind();
SkPath& rewind();
/** Returns if SkPath is empty.
Empty SkPath may have FillType but has no SkPoint, SkPath::Verb, or conic weight.
@ -548,15 +549,16 @@ public:
@param x x-axis value of contour start
@param y y-axis value of contour start
@return this path
*/
void moveTo(SkScalar x, SkScalar y);
SkPath& moveTo(SkScalar x, SkScalar y);
/** Adds beginning of contour at SkPoint p.
@param p contour start
*/
void moveTo(const SkPoint& p) {
this->moveTo(p.fX, p.fY);
SkPath& moveTo(const SkPoint& p) {
return this->moveTo(p.fX, p.fY);
}
/** Adds beginning of contour relative to last point.
@ -567,7 +569,7 @@ public:
@param dx offset from last point to contour start on x-axis
@param dy offset from last point to contour start on y-axis
*/
void rMoveTo(SkScalar dx, SkScalar dy);
SkPath& rMoveTo(SkScalar dx, SkScalar dy);
/** Adds line from last point to (x, y). If SkPath is empty, or last SkPath::Verb is
kClose_Verb, last point is set to (0, 0) before adding line.
@ -578,7 +580,7 @@ public:
@param x end of added line in x
@param y end of added line in y
*/
void lineTo(SkScalar x, SkScalar y);
SkPath& lineTo(SkScalar x, SkScalar y);
/** Adds line from last point to SkPoint p. If SkPath is empty, or last SkPath::Verb is
kClose_Verb, last point is set to (0, 0) before adding line.
@ -588,8 +590,8 @@ public:
@param p end SkPoint of added line
*/
void lineTo(const SkPoint& p) {
this->lineTo(p.fX, p.fY);
SkPath& lineTo(const SkPoint& p) {
return this->lineTo(p.fX, p.fY);
}
/** Adds line from last point to vector (dx, dy). If SkPath is empty, or last SkPath::Verb is
@ -603,7 +605,7 @@ public:
@param dx offset from last point to line end on x-axis
@param dy offset from last point to line end on y-axis
*/
void rLineTo(SkScalar dx, SkScalar dy);
SkPath& rLineTo(SkScalar dx, SkScalar dy);
/** 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)
@ -618,7 +620,7 @@ public:
@param x2 end SkPoint of quad in x
@param y2 end SkPoint of quad in y
*/
void quadTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2);
SkPath& quadTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2);
/** Adds quad from last point towards SkPoint p1, to SkPoint p2.
If SkPath is empty, or last SkPath::Verb is kClose_Verb, last point is set to (0, 0)
@ -631,8 +633,8 @@ public:
@param p1 control SkPoint of added quad
@param p2 end SkPoint of added quad
*/
void quadTo(const SkPoint& p1, const SkPoint& p2) {
this->quadTo(p1.fX, p1.fY, p2.fX, p2.fY);
SkPath& quadTo(const SkPoint& p1, const SkPoint& p2) {
return this->quadTo(p1.fX, p1.fY, p2.fX, p2.fY);
}
/** Adds quad from last point towards vector (dx1, dy1), to vector (dx2, dy2).
@ -651,7 +653,7 @@ public:
@param dx2 offset from last point to quad end on x-axis
@param dy2 offset from last point to quad end on y-axis
*/
void rQuadTo(SkScalar dx1, SkScalar dy1, SkScalar dx2, SkScalar dy2);
SkPath& rQuadTo(SkScalar dx1, SkScalar dy1, SkScalar dx2, SkScalar dy2);
/** Adds conic from last point towards (x1, y1), to (x2, y2), weighted by w.
If SkPath is empty, or last SkPath::Verb is kClose_Verb, last point is set to (0, 0)
@ -674,8 +676,8 @@ public:
@param y2 end SkPoint of conic in y
@param w weight of added conic
*/
void conicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2,
SkScalar w);
SkPath& conicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2,
SkScalar w);
/** Adds conic from last point towards SkPoint p1, to SkPoint p2, weighted by w.
If SkPath is empty, or last SkPath::Verb is kClose_Verb, last point is set to (0, 0)
@ -696,8 +698,8 @@ public:
@param p2 end SkPoint of added conic
@param w weight of added conic
*/
void conicTo(const SkPoint& p1, const SkPoint& p2, SkScalar w) {
this->conicTo(p1.fX, p1.fY, p2.fX, p2.fY, w);
SkPath& conicTo(const SkPoint& p1, const SkPoint& p2, SkScalar w) {
return this->conicTo(p1.fX, p1.fY, p2.fX, p2.fY, w);
}
/** Adds conic from last point towards vector (dx1, dy1), to vector (dx2, dy2),
@ -724,8 +726,8 @@ public:
@param dy2 offset from last point to conic end on y-axis
@param w weight of added conic
*/
void rConicTo(SkScalar dx1, SkScalar dy1, SkScalar dx2, SkScalar dy2,
SkScalar w);
SkPath& rConicTo(SkScalar dx1, SkScalar dy1, SkScalar dx2, SkScalar dy2,
SkScalar w);
/** Adds cubic from last point towards (x1, y1), then towards (x2, y2), ending at
(x3, y3). If SkPath is empty, or last SkPath::Verb is kClose_Verb, last point is set to
@ -742,8 +744,8 @@ public:
@param x3 end SkPoint of cubic in x
@param y3 end SkPoint of cubic in y
*/
void cubicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2,
SkScalar x3, SkScalar y3);
SkPath& cubicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2,
SkScalar x3, SkScalar y3);
/** Adds cubic from last point towards SkPoint p1, then towards SkPoint p2, ending at
SkPoint p3. If SkPath is empty, or last SkPath::Verb is kClose_Verb, last point is set to
@ -757,8 +759,8 @@ public:
@param p2 second control SkPoint of cubic
@param p3 end SkPoint of cubic
*/
void cubicTo(const SkPoint& p1, const SkPoint& p2, const SkPoint& p3) {
this->cubicTo(p1.fX, p1.fY, p2.fX, p2.fY, p3.fX, p3.fY);
SkPath& cubicTo(const SkPoint& p1, const SkPoint& p2, const SkPoint& p3) {
return this->cubicTo(p1.fX, p1.fY, p2.fX, p2.fY, p3.fX, p3.fY);
}
/** Adds cubic from last point towards vector (dx1, dy1), then towards
@ -780,8 +782,8 @@ public:
@param x3 offset from last point to cubic end on x-axis
@param y3 offset from last point to cubic end on y-axis
*/
void rCubicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2,
SkScalar x3, SkScalar y3);
SkPath& rCubicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2,
SkScalar x3, SkScalar y3);
/** Appends arc to SkPath. Arc added is part of ellipse
bounded by oval, from startAngle through sweepAngle. Both startAngle and
@ -797,7 +799,7 @@ public:
@param sweepAngle sweep, in degrees. Positive is clockwise; treated modulo 360
@param forceMoveTo true to start a new contour with arc
*/
void arcTo(const SkRect& oval, SkScalar startAngle, SkScalar sweepAngle, bool forceMoveTo);
SkPath& arcTo(const SkRect& oval, SkScalar startAngle, SkScalar sweepAngle, 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
@ -810,7 +812,7 @@ public:
@param y2 y-axis value end of second tangent
@param radius distance from arc to circle center
*/
void arcTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2, SkScalar radius);
SkPath& arcTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2, SkScalar radius);
/** 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
@ -830,8 +832,8 @@ public:
@param p2 end of second tangent
@param radius distance from arc to circle center
*/
void arcTo(const SkPoint p1, const SkPoint p2, SkScalar radius) {
this->arcTo(p1.fX, p1.fY, p2.fX, p2.fY, radius);
SkPath& arcTo(const SkPoint p1, const SkPoint p2, SkScalar radius) {
return this->arcTo(p1.fX, p1.fY, p2.fX, p2.fY, radius);
}
/** \enum SkPath::ArcSize
@ -866,8 +868,8 @@ public:
@param x end of arc
@param y end of arc
*/
void arcTo(SkScalar rx, SkScalar ry, SkScalar xAxisRotate, ArcSize largeArc,
Direction sweep, SkScalar x, SkScalar y);
SkPath& arcTo(SkScalar rx, SkScalar ry, SkScalar xAxisRotate, ArcSize largeArc,
Direction sweep, SkScalar x, SkScalar y);
/** 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
@ -889,9 +891,9 @@ public:
@param sweep chooses clockwise or counterclockwise arc
@param xy end of arc
*/
void arcTo(const SkPoint r, SkScalar xAxisRotate, ArcSize largeArc, Direction sweep,
SkPath& arcTo(const SkPoint r, SkScalar xAxisRotate, ArcSize largeArc, Direction sweep,
const SkPoint xy) {
this->arcTo(r.fX, r.fY, xAxisRotate, largeArc, sweep, xy.fX, xy.fY);
return this->arcTo(r.fX, r.fY, xAxisRotate, largeArc, sweep, xy.fX, xy.fY);
}
/** Appends arc to SkPath, relative to last SkPath SkPoint. Arc is implemented by one or
@ -919,8 +921,8 @@ public:
@param dx x-axis offset end of arc from last SkPath SkPoint
@param dy y-axis offset end of arc from last SkPath SkPoint
*/
void rArcTo(SkScalar rx, SkScalar ry, SkScalar xAxisRotate, ArcSize largeArc,
Direction sweep, SkScalar dx, SkScalar dy);
SkPath& rArcTo(SkScalar rx, SkScalar ry, SkScalar xAxisRotate, ArcSize largeArc,
Direction sweep, SkScalar dx, SkScalar dy);
/** Appends kClose_Verb to SkPath. A closed contour connects the first and last SkPoint
with line, forming a continuous loop. Open and closed contour draw the same
@ -930,7 +932,7 @@ public:
close() has no effect if SkPath is empty or last SkPath SkPath::Verb is kClose_Verb.
*/
void close();
SkPath& close();
/** Returns true if fill is inverted and SkPath with fill represents area outside
of its geometric bounds.
@ -1025,7 +1027,7 @@ public:
@param rect SkRect to add as a closed contour
@param dir SkPath::Direction to wind added contour
*/
void addRect(const SkRect& rect, Direction dir = kCW_Direction);
SkPath& addRect(const SkRect& rect, Direction dir = kCW_Direction);
/** Adds SkRect to SkPath, appending kMove_Verb, three kLine_Verb, and kClose_Verb.
If dir is kCW_Direction, SkRect corners are added clockwise; if dir is
@ -1036,7 +1038,7 @@ public:
@param dir SkPath::Direction to wind added contour
@param start initial corner of SkRect to add
*/
void addRect(const SkRect& rect, Direction dir, unsigned start);
SkPath& addRect(const SkRect& rect, Direction dir, unsigned start);
/** Adds SkRect (left, top, right, bottom) to SkPath,
appending kMove_Verb, three kLine_Verb, and kClose_Verb,
@ -1050,8 +1052,8 @@ public:
@param bottom larger y-axis value of SkRect
@param dir SkPath::Direction to wind added contour
*/
void addRect(SkScalar left, SkScalar top, SkScalar right, SkScalar bottom,
Direction dir = kCW_Direction);
SkPath& addRect(SkScalar left, SkScalar top, SkScalar right, SkScalar bottom,
Direction dir = kCW_Direction);
/** Adds oval to path, appending kMove_Verb, four kConic_Verb, and kClose_Verb.
Oval is upright ellipse bounded by SkRect oval with radii equal to half oval width
@ -1061,7 +1063,7 @@ public:
@param oval bounds of ellipse added
@param dir SkPath::Direction to wind ellipse
*/
void addOval(const SkRect& oval, Direction dir = kCW_Direction);
SkPath& addOval(const SkRect& oval, Direction dir = kCW_Direction);
/** Adds oval to SkPath, appending kMove_Verb, four kConic_Verb, and kClose_Verb.
Oval is upright ellipse bounded by SkRect oval with radii equal to half oval width
@ -1072,7 +1074,7 @@ public:
@param dir SkPath::Direction to wind ellipse
@param start index of initial point of ellipse
*/
void addOval(const SkRect& oval, Direction dir, unsigned start);
SkPath& addOval(const SkRect& oval, Direction dir, unsigned start);
/** Adds circle centered at (x, y) of size radius to SkPath, appending kMove_Verb,
four kConic_Verb, and kClose_Verb. Circle begins at: (x + radius, y), continuing
@ -1085,8 +1087,8 @@ public:
@param radius distance from center to edge
@param dir SkPath::Direction to wind circle
*/
void addCircle(SkScalar x, SkScalar y, SkScalar radius,
Direction dir = kCW_Direction);
SkPath& addCircle(SkScalar x, SkScalar y, SkScalar radius,
Direction dir = kCW_Direction);
/** Appends arc to SkPath, as the start of new contour. Arc added is part of ellipse
bounded by oval, from startAngle through sweepAngle. Both startAngle and
@ -1101,7 +1103,7 @@ public:
@param startAngle starting angle of arc in degrees
@param sweepAngle sweep, in degrees. Positive is clockwise; treated modulo 360
*/
void addArc(const SkRect& oval, SkScalar startAngle, SkScalar sweepAngle);
SkPath& addArc(const SkRect& oval, SkScalar startAngle, SkScalar sweepAngle);
/** Appends SkRRect to SkPath, creating a new closed contour. SkRRect has bounds
equal to rect; each corner is 90 degrees of an ellipse with radii (rx, ry). If
@ -1120,8 +1122,8 @@ public:
@param ry y-axis radius of rounded corners on the SkRRect
@param dir SkPath::Direction to wind SkRRect
*/
void addRoundRect(const SkRect& rect, SkScalar rx, SkScalar ry,
Direction dir = kCW_Direction);
SkPath& addRoundRect(const SkRect& rect, SkScalar rx, SkScalar ry,
Direction dir = kCW_Direction);
/** Appends SkRRect to SkPath, creating a new closed contour. SkRRect has bounds
equal to rect; each corner is 90 degrees of an ellipse with radii from the
@ -1131,8 +1133,8 @@ public:
@param radii array of 8 SkScalar values, a radius pair for each corner
@param dir SkPath::Direction to wind SkRRect
*/
void addRoundRect(const SkRect& rect, const SkScalar radii[],
Direction dir = kCW_Direction);
SkPath& addRoundRect(const SkRect& rect, const SkScalar radii[],
Direction dir = kCW_Direction);
/** Adds rrect to SkPath, creating a new closed contour. If
dir is kCW_Direction, rrect starts at top-left of the lower-left corner and
@ -1144,7 +1146,7 @@ public:
@param rrect bounds and radii of rounded rectangle
@param dir SkPath::Direction to wind SkRRect
*/
void addRRect(const SkRRect& rrect, Direction dir = kCW_Direction);
SkPath& addRRect(const SkRRect& rrect, Direction dir = kCW_Direction);
/** Adds rrect to SkPath, creating a new closed contour. If dir is kCW_Direction, rrect
winds clockwise; if dir is kCCW_Direction, rrect winds counterclockwise.
@ -1154,7 +1156,7 @@ public:
@param dir SkPath::Direction to wind SkRRect
@param start index of initial point of SkRRect
*/
void addRRect(const SkRRect& rrect, Direction dir, unsigned start);
SkPath& addRRect(const SkRRect& rrect, Direction dir, unsigned start);
/** Adds contour created from line array, adding (count - 1) line segments.
Contour added starts at pts[0], then adds a line for every additional SkPoint
@ -1168,7 +1170,11 @@ public:
@param count length of SkPoint array
@param close true to add line connecting contour end and start
*/
void addPoly(const SkPoint pts[], int count, bool close);
SkPath& addPoly(const SkPoint pts[], int count, bool close);
SkPath& addPoly(const std::initializer_list<SkPoint>& list, bool close) {
return this->addPoly(list.begin(), SkToInt(list.size()), close);
}
/** \enum SkPath::AddPathMode
AddPathMode chooses how addPath() appends. Adding one SkPath to another can extend
@ -1190,8 +1196,8 @@ public:
@param dy offset added to src SkPoint array y-axis coordinates
@param mode kAppend_AddPathMode or kExtend_AddPathMode
*/
void addPath(const SkPath& src, SkScalar dx, SkScalar dy,
AddPathMode mode = kAppend_AddPathMode);
SkPath& addPath(const SkPath& src, SkScalar dx, SkScalar dy,
AddPathMode mode = kAppend_AddPathMode);
/** Appends src to SkPath.
@ -1202,10 +1208,10 @@ public:
@param src SkPath verbs, SkPoint, and conic weights to add
@param mode kAppend_AddPathMode or kExtend_AddPathMode
*/
void addPath(const SkPath& src, AddPathMode mode = kAppend_AddPathMode) {
SkPath& addPath(const SkPath& src, AddPathMode mode = kAppend_AddPathMode) {
SkMatrix m;
m.reset();
this->addPath(src, m, mode);
return this->addPath(src, m, mode);
}
/** Appends src to SkPath, transformed by matrix. Transformed curves may have different
@ -1219,14 +1225,15 @@ public:
@param matrix transform applied to src
@param mode kAppend_AddPathMode or kExtend_AddPathMode
*/
void addPath(const SkPath& src, const SkMatrix& matrix, AddPathMode mode = kAppend_AddPathMode);
SkPath& addPath(const SkPath& src, const SkMatrix& matrix,
AddPathMode mode = kAppend_AddPathMode);
/** Appends src to SkPath, from back to front.
Reversed src always appends a new contour to SkPath.
@param src SkPath verbs, SkPoint, and conic weights to add
*/
void reverseAddPath(const SkPath& src);
SkPath& reverseAddPath(const SkPath& src);
/** Offsets SkPoint array by (dx, dy). Offset SkPath replaces dst.
If dst is nullptr, SkPath is replaced by offset data.
@ -1642,7 +1649,7 @@ private:
last point. If no moveTo() call has been made for this contour, the
first point is automatically set to (0,0).
*/
void reversePathTo(const SkPath&);
SkPath& reversePathTo(const SkPath&);
// called before we add points for lineTo, quadTo, cubicTo, checking to see
// if we need to inject a leading moveTo first

View File

@ -364,18 +364,20 @@ uint32_t SkPath::getGenerationID() const {
return genID;
}
void SkPath::reset() {
SkPath& SkPath::reset() {
SkDEBUGCODE(this->validate();)
fPathRef.reset(SkPathRef::CreateEmpty());
this->resetFields();
return *this;
}
void SkPath::rewind() {
SkPath& SkPath::rewind() {
SkDEBUGCODE(this->validate();)
SkPathRef::Rewind(&fPathRef);
this->resetFields();
return *this;
}
bool SkPath::isLastContourClosed() const {
@ -746,7 +748,7 @@ void SkPath::incReserve(U16CPU inc) {
SkDEBUGCODE(this->validate();)
}
void SkPath::moveTo(SkScalar x, SkScalar y) {
SkPath& SkPath::moveTo(SkScalar x, SkScalar y) {
SkDEBUGCODE(this->validate();)
SkPathRef::Editor ed(&fPathRef);
@ -757,12 +759,13 @@ void SkPath::moveTo(SkScalar x, SkScalar y) {
ed.growForVerb(kMove_Verb)->set(x, y);
DIRTY_AFTER_EDIT;
return *this;
}
void SkPath::rMoveTo(SkScalar x, SkScalar y) {
SkPath& SkPath::rMoveTo(SkScalar x, SkScalar y) {
SkPoint pt;
this->getLastPt(&pt);
this->moveTo(pt.fX + x, pt.fY + y);
return this->moveTo(pt.fX + x, pt.fY + y);
}
void SkPath::injectMoveToIfNeeded() {
@ -779,7 +782,7 @@ void SkPath::injectMoveToIfNeeded() {
}
}
void SkPath::lineTo(SkScalar x, SkScalar y) {
SkPath& SkPath::lineTo(SkScalar x, SkScalar y) {
SkDEBUGCODE(this->validate();)
this->injectMoveToIfNeeded();
@ -788,16 +791,17 @@ void SkPath::lineTo(SkScalar x, SkScalar y) {
ed.growForVerb(kLine_Verb)->set(x, y);
DIRTY_AFTER_EDIT;
return *this;
}
void SkPath::rLineTo(SkScalar x, SkScalar y) {
SkPath& SkPath::rLineTo(SkScalar x, SkScalar y) {
this->injectMoveToIfNeeded(); // This can change the result of this->getLastPt().
SkPoint pt;
this->getLastPt(&pt);
this->lineTo(pt.fX + x, pt.fY + y);
return this->lineTo(pt.fX + x, pt.fY + y);
}
void SkPath::quadTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2) {
SkPath& SkPath::quadTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2) {
SkDEBUGCODE(this->validate();)
this->injectMoveToIfNeeded();
@ -808,17 +812,18 @@ void SkPath::quadTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2) {
pts[1].set(x2, y2);
DIRTY_AFTER_EDIT;
return *this;
}
void SkPath::rQuadTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2) {
SkPath& SkPath::rQuadTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2) {
this->injectMoveToIfNeeded(); // This can change the result of this->getLastPt().
SkPoint pt;
this->getLastPt(&pt);
this->quadTo(pt.fX + x1, pt.fY + y1, pt.fX + x2, pt.fY + y2);
return this->quadTo(pt.fX + x1, pt.fY + y1, pt.fX + x2, pt.fY + y2);
}
void SkPath::conicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2,
SkScalar w) {
SkPath& SkPath::conicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2,
SkScalar w) {
// check for <= 0 or NaN with this test
if (!(w > 0)) {
this->lineTo(x2, y2);
@ -839,18 +844,19 @@ void SkPath::conicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2,
DIRTY_AFTER_EDIT;
}
return *this;
}
void SkPath::rConicTo(SkScalar dx1, SkScalar dy1, SkScalar dx2, SkScalar dy2,
SkScalar w) {
SkPath& SkPath::rConicTo(SkScalar dx1, SkScalar dy1, SkScalar dx2, SkScalar dy2,
SkScalar w) {
this->injectMoveToIfNeeded(); // This can change the result of this->getLastPt().
SkPoint pt;
this->getLastPt(&pt);
this->conicTo(pt.fX + dx1, pt.fY + dy1, pt.fX + dx2, pt.fY + dy2, w);
return this->conicTo(pt.fX + dx1, pt.fY + dy1, pt.fX + dx2, pt.fY + dy2, w);
}
void SkPath::cubicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2,
SkScalar x3, SkScalar y3) {
SkPath& SkPath::cubicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2,
SkScalar x3, SkScalar y3) {
SkDEBUGCODE(this->validate();)
this->injectMoveToIfNeeded();
@ -862,18 +868,19 @@ void SkPath::cubicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2,
pts[2].set(x3, y3);
DIRTY_AFTER_EDIT;
return *this;
}
void SkPath::rCubicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2,
SkScalar x3, SkScalar y3) {
SkPath& SkPath::rCubicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2,
SkScalar x3, SkScalar y3) {
this->injectMoveToIfNeeded(); // This can change the result of this->getLastPt().
SkPoint pt;
this->getLastPt(&pt);
this->cubicTo(pt.fX + x1, pt.fY + y1, pt.fX + x2, pt.fY + y2,
pt.fX + x3, pt.fY + y3);
return this->cubicTo(pt.fX + x1, pt.fY + y1, pt.fX + x2, pt.fY + y2,
pt.fX + x3, pt.fY + y3);
}
void SkPath::close() {
SkPath& SkPath::close() {
SkDEBUGCODE(this->validate();)
int count = fPathRef->countVerbs();
@ -905,6 +912,7 @@ void SkPath::close() {
#else
fLastMoveToIndex ^= ~fLastMoveToIndex >> (8 * sizeof(fLastMoveToIndex) - 1);
#endif
return *this;
}
///////////////////////////////////////////////////////////////////////////////
@ -991,16 +999,16 @@ static void assert_known_direction(int dir) {
SkASSERT(SkPath::kCW_Direction == dir || SkPath::kCCW_Direction == dir);
}
void SkPath::addRect(const SkRect& rect, Direction dir) {
this->addRect(rect, dir, 0);
SkPath& SkPath::addRect(const SkRect& rect, Direction dir) {
return this->addRect(rect, dir, 0);
}
void SkPath::addRect(SkScalar left, SkScalar top, SkScalar right,
SkPath& SkPath::addRect(SkScalar left, SkScalar top, SkScalar right,
SkScalar bottom, Direction dir) {
this->addRect(SkRect::MakeLTRB(left, top, right, bottom), dir, 0);
return this->addRect(SkRect::MakeLTRB(left, top, right, bottom), dir, 0);
}
void SkPath::addRect(const SkRect &rect, Direction dir, unsigned startIndex) {
SkPath& SkPath::addRect(const SkRect &rect, Direction dir, unsigned startIndex) {
assert_known_direction(dir);
fFirstDirection = this->hasOnlyMoveTos() ?
(SkPathPriv::FirstDirection)dir : SkPathPriv::kUnknown_FirstDirection;
@ -1021,12 +1029,13 @@ void SkPath::addRect(const SkRect &rect, Direction dir, unsigned startIndex) {
this->close();
SkASSERT(this->countVerbs() == initialVerbCount + kVerbs);
return *this;
}
void SkPath::addPoly(const SkPoint pts[], int count, bool close) {
SkPath& SkPath::addPoly(const SkPoint pts[], int count, bool close) {
SkDEBUGCODE(this->validate();)
if (count <= 0) {
return;
return *this;
}
fLastMoveToIndex = fPathRef->countPoints();
@ -1047,6 +1056,7 @@ void SkPath::addPoly(const SkPoint pts[], int count, bool close) {
DIRTY_AFTER_EDIT;
SkDEBUGCODE(this->validate();)
return *this;
}
#include "SkGeometry.h"
@ -1122,76 +1132,77 @@ static int build_arc_conics(const SkRect& oval, const SkVector& start, const SkV
return count;
}
void SkPath::addRoundRect(const SkRect& rect, const SkScalar radii[],
SkPath& SkPath::addRoundRect(const SkRect& rect, const SkScalar radii[],
Direction dir) {
SkRRect rrect;
rrect.setRectRadii(rect, (const SkVector*) radii);
this->addRRect(rrect, dir);
return this->addRRect(rrect, dir);
}
void SkPath::addRRect(const SkRRect& rrect, Direction dir) {
SkPath& SkPath::addRRect(const SkRRect& rrect, Direction dir) {
// legacy start indices: 6 (CW) and 7(CCW)
this->addRRect(rrect, dir, dir == kCW_Direction ? 6 : 7);
return this->addRRect(rrect, dir, dir == kCW_Direction ? 6 : 7);
}
void SkPath::addRRect(const SkRRect &rrect, Direction dir, unsigned startIndex) {
assert_known_direction(dir);
SkPath& SkPath::addRRect(const SkRRect &rrect, Direction dir, unsigned startIndex) {
assert_known_direction(dir);
bool isRRect = hasOnlyMoveTos();
const SkRect& bounds = rrect.getBounds();
bool isRRect = hasOnlyMoveTos();
const SkRect& bounds = rrect.getBounds();
if (rrect.isRect() || rrect.isEmpty()) {
// degenerate(rect) => radii points are collapsing
this->addRect(bounds, dir, (startIndex + 1) / 2);
} else if (rrect.isOval()) {
// degenerate(oval) => line points are collapsing
this->addOval(bounds, dir, startIndex / 2);
} else {
fFirstDirection = this->hasOnlyMoveTos() ?
(SkPathPriv::FirstDirection)dir : SkPathPriv::kUnknown_FirstDirection;
if (rrect.isRect() || rrect.isEmpty()) {
// degenerate(rect) => radii points are collapsing
this->addRect(bounds, dir, (startIndex + 1) / 2);
} else if (rrect.isOval()) {
// degenerate(oval) => line points are collapsing
this->addOval(bounds, dir, startIndex / 2);
} else {
fFirstDirection = this->hasOnlyMoveTos() ?
(SkPathPriv::FirstDirection)dir : SkPathPriv::kUnknown_FirstDirection;
SkAutoPathBoundsUpdate apbu(this, bounds);
SkAutoDisableDirectionCheck addc(this);
SkAutoPathBoundsUpdate apbu(this, bounds);
SkAutoDisableDirectionCheck addc(this);
// we start with a conic on odd indices when moving CW vs. even indices when moving CCW
const bool startsWithConic = ((startIndex & 1) == (dir == kCW_Direction));
const SkScalar weight = SK_ScalarRoot2Over2;
// we start with a conic on odd indices when moving CW vs. even indices when moving CCW
const bool startsWithConic = ((startIndex & 1) == (dir == kCW_Direction));
const SkScalar weight = SK_ScalarRoot2Over2;
SkDEBUGCODE(int initialVerbCount = this->countVerbs());
const int kVerbs = startsWithConic
? 9 // moveTo + 4x conicTo + 3x lineTo + close
: 10; // moveTo + 4x lineTo + 4x conicTo + close
this->incReserve(kVerbs);
SkDEBUGCODE(int initialVerbCount = this->countVerbs());
const int kVerbs = startsWithConic
? 9 // moveTo + 4x conicTo + 3x lineTo + close
: 10; // moveTo + 4x lineTo + 4x conicTo + close
this->incReserve(kVerbs);
RRectPointIterator rrectIter(rrect, dir, startIndex);
// Corner iterator indices follow the collapsed radii model,
// adjusted such that the start pt is "behind" the radii start pt.
const unsigned rectStartIndex = startIndex / 2 + (dir == kCW_Direction ? 0 : 1);
RectPointIterator rectIter(bounds, dir, rectStartIndex);
RRectPointIterator rrectIter(rrect, dir, startIndex);
// Corner iterator indices follow the collapsed radii model,
// adjusted such that the start pt is "behind" the radii start pt.
const unsigned rectStartIndex = startIndex / 2 + (dir == kCW_Direction ? 0 : 1);
RectPointIterator rectIter(bounds, dir, rectStartIndex);
this->moveTo(rrectIter.current());
if (startsWithConic) {
for (unsigned i = 0; i < 3; ++i) {
this->conicTo(rectIter.next(), rrectIter.next(), weight);
this->lineTo(rrectIter.next());
}
this->moveTo(rrectIter.current());
if (startsWithConic) {
for (unsigned i = 0; i < 3; ++i) {
this->conicTo(rectIter.next(), rrectIter.next(), weight);
this->lineTo(rrectIter.next());
}
this->conicTo(rectIter.next(), rrectIter.next(), weight);
// final lineTo handled by close().
} else {
for (unsigned i = 0; i < 4; ++i) {
this->lineTo(rrectIter.next());
this->conicTo(rectIter.next(), rrectIter.next(), weight);
// final lineTo handled by close().
} else {
for (unsigned i = 0; i < 4; ++i) {
this->lineTo(rrectIter.next());
this->conicTo(rectIter.next(), rrectIter.next(), weight);
}
}
this->close();
SkPathRef::Editor ed(&fPathRef);
ed.setIsRRect(isRRect, dir, startIndex % 8);
SkASSERT(this->countVerbs() == initialVerbCount + kVerbs);
}
this->close();
SkDEBUGCODE(fPathRef->validate();)
SkPathRef::Editor ed(&fPathRef);
ed.setIsRRect(isRRect, dir, startIndex % 8);
SkASSERT(this->countVerbs() == initialVerbCount + kVerbs);
}
SkDEBUGCODE(fPathRef->validate();)
return *this;
}
bool SkPath::hasOnlyMoveTos() const {
@ -1224,25 +1235,25 @@ bool SkPath::isZeroLengthSincePoint(int startPtIndex) const {
return true;
}
void SkPath::addRoundRect(const SkRect& rect, SkScalar rx, SkScalar ry,
Direction dir) {
SkPath& SkPath::addRoundRect(const SkRect& rect, SkScalar rx, SkScalar ry,
Direction dir) {
assert_known_direction(dir);
if (rx < 0 || ry < 0) {
return;
return *this;
}
SkRRect rrect;
rrect.setRectXY(rect, rx, ry);
this->addRRect(rrect, dir);
return this->addRRect(rrect, dir);
}
void SkPath::addOval(const SkRect& oval, Direction dir) {
SkPath& SkPath::addOval(const SkRect& oval, Direction dir) {
// legacy start index: 1
this->addOval(oval, dir, 1);
return this->addOval(oval, dir, 1);
}
void SkPath::addOval(const SkRect &oval, Direction dir, unsigned startPointIndex) {
SkPath& SkPath::addOval(const SkRect &oval, Direction dir, unsigned startPointIndex) {
assert_known_direction(dir);
/* If addOval() is called after previous moveTo(),
@ -1281,18 +1292,20 @@ void SkPath::addOval(const SkRect &oval, Direction dir, unsigned startPointIndex
SkPathRef::Editor ed(&fPathRef);
ed.setIsOval(isOval, kCCW_Direction == dir, startPointIndex % 4);
return *this;
}
void SkPath::addCircle(SkScalar x, SkScalar y, SkScalar r, Direction dir) {
SkPath& SkPath::addCircle(SkScalar x, SkScalar y, SkScalar r, Direction dir) {
if (r > 0) {
this->addOval(SkRect::MakeLTRB(x - r, y - r, x + r, y + r), dir);
}
return *this;
}
void SkPath::arcTo(const SkRect& oval, SkScalar startAngle, SkScalar sweepAngle,
bool forceMoveTo) {
SkPath& SkPath::arcTo(const SkRect& oval, SkScalar startAngle, SkScalar sweepAngle,
bool forceMoveTo) {
if (oval.width() < 0 || oval.height() < 0) {
return;
return *this;
}
if (fPathRef->countVerbs() == 0) {
@ -1301,8 +1314,7 @@ void SkPath::arcTo(const SkRect& oval, SkScalar startAngle, SkScalar sweepAngle,
SkPoint lonePt;
if (arc_is_lone_point(oval, startAngle, sweepAngle, &lonePt)) {
forceMoveTo ? this->moveTo(lonePt) : this->lineTo(lonePt);
return;
return forceMoveTo ? this->moveTo(lonePt) : this->lineTo(lonePt);
}
SkVector startV, stopV;
@ -1340,7 +1352,7 @@ void SkPath::arcTo(const SkRect& oval, SkScalar startAngle, SkScalar sweepAngle,
singlePt.set(oval.centerX() + radiusX * sk_float_cos(endAngle),
oval.centerY() + radiusY * sk_float_sin(endAngle));
addPt(singlePt);
return;
return *this;
}
SkConic conics[SkConic::kMaxConicsForArc];
@ -1355,6 +1367,7 @@ void SkPath::arcTo(const SkRect& oval, SkScalar startAngle, SkScalar sweepAngle,
} else {
addPt(singlePt);
}
return *this;
}
// This converts the SVG arc to conics.
@ -1363,8 +1376,8 @@ void SkPath::arcTo(const SkRect& oval, SkScalar startAngle, SkScalar sweepAngle,
// See also SVG implementation notes:
// http://www.w3.org/TR/SVG/implnote.html#ArcConversionEndpointToCenter
// Note that arcSweep bool value is flipped from the original implementation.
void SkPath::arcTo(SkScalar rx, SkScalar ry, SkScalar angle, SkPath::ArcSize arcLarge,
SkPath::Direction arcSweep, SkScalar x, SkScalar y) {
SkPath& SkPath::arcTo(SkScalar rx, SkScalar ry, SkScalar angle, SkPath::ArcSize arcLarge,
SkPath::Direction arcSweep, SkScalar x, SkScalar y) {
this->injectMoveToIfNeeded();
SkPoint srcPts[2];
this->getLastPt(&srcPts[0]);
@ -1372,15 +1385,13 @@ void SkPath::arcTo(SkScalar rx, SkScalar ry, SkScalar angle, SkPath::ArcSize arc
// joining the endpoints.
// http://www.w3.org/TR/SVG/implnote.html#ArcOutOfRangeParameters
if (!rx || !ry) {
this->lineTo(x, y);
return;
return this->lineTo(x, y);
}
// If the current point and target point for the arc are identical, it should be treated as a
// zero length path. This ensures continuity in animations.
srcPts[1].set(x, y);
if (srcPts[0] == srcPts[1]) {
this->lineTo(x, y);
return;
return this->lineTo(x, y);
}
rx = SkScalarAbs(rx);
ry = SkScalarAbs(ry);
@ -1446,7 +1457,7 @@ void SkPath::arcTo(SkScalar rx, SkScalar ry, SkScalar angle, SkPath::ArcSize arc
SkScalar thetaWidth = thetaArc / segments;
SkScalar t = SkScalarTan(0.5f * thetaWidth);
if (!SkScalarIsFinite(t)) {
return;
return *this;
}
SkScalar startTheta = theta1;
SkScalar w = SkScalarSqrt(SK_ScalarHalf + SkScalarCos(thetaWidth) * SK_ScalarHalf);
@ -1484,18 +1495,20 @@ void SkPath::arcTo(SkScalar rx, SkScalar ry, SkScalar angle, SkPath::ArcSize arc
this->conicTo(mapped[0], mapped[1], w);
startTheta = endTheta;
}
return *this;
}
void SkPath::rArcTo(SkScalar rx, SkScalar ry, SkScalar xAxisRotate, SkPath::ArcSize largeArc,
SkPath::Direction sweep, SkScalar dx, SkScalar dy) {
SkPath& SkPath::rArcTo(SkScalar rx, SkScalar ry, SkScalar xAxisRotate, SkPath::ArcSize largeArc,
SkPath::Direction sweep, SkScalar dx, SkScalar dy) {
SkPoint currentPoint;
this->getLastPt(&currentPoint);
this->arcTo(rx, ry, xAxisRotate, largeArc, sweep, currentPoint.fX + dx, currentPoint.fY + dy);
return this->arcTo(rx, ry, xAxisRotate, largeArc, sweep,
currentPoint.fX + dx, currentPoint.fY + dy);
}
void SkPath::addArc(const SkRect& oval, SkScalar startAngle, SkScalar sweepAngle) {
SkPath& SkPath::addArc(const SkRect& oval, SkScalar startAngle, SkScalar sweepAngle) {
if (oval.isEmpty() || 0 == sweepAngle) {
return;
return *this;
}
const SkScalar kFullCircleAngle = SkIntToScalar(360);
@ -1510,22 +1523,20 @@ void SkPath::addArc(const SkRect& oval, SkScalar startAngle, SkScalar sweepAngle
// Index 1 is at startAngle == 0.
SkScalar startIndex = std::fmod(startOver90I + 1.f, 4.f);
startIndex = startIndex < 0 ? startIndex + 4.f : startIndex;
this->addOval(oval, sweepAngle > 0 ? kCW_Direction : kCCW_Direction,
(unsigned) startIndex);
return;
return this->addOval(oval, sweepAngle > 0 ? kCW_Direction : kCCW_Direction,
(unsigned) startIndex);
}
}
this->arcTo(oval, startAngle, sweepAngle, true);
return this->arcTo(oval, startAngle, sweepAngle, true);
}
/*
Need to handle the case when the angle is sharp, and our computed end-points
for the arc go behind pt1 and/or p2...
*/
void SkPath::arcTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2, SkScalar radius) {
SkPath& SkPath::arcTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2, SkScalar radius) {
if (radius == 0) {
this->lineTo(x1, y1);
return;
return this->lineTo(x1, y1);
}
SkVector before, after;
@ -1544,8 +1555,7 @@ void SkPath::arcTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2, SkScalar
SkScalar sinh = SkPoint::CrossProduct(before, after);
if (SkScalarNearlyZero(sinh)) { // angle is too tight
this->lineTo(x1, y1);
return;
return this->lineTo(x1, y1);
}
SkScalar dist = SkScalarAbs(radius * (1 - cosh) / sinh);
@ -1555,19 +1565,19 @@ void SkPath::arcTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2, SkScalar
after.setLength(dist);
this->lineTo(xx, yy);
SkScalar weight = SkScalarSqrt(SK_ScalarHalf + cosh * SK_ScalarHalf);
this->conicTo(x1, y1, x1 + after.fX, y1 + after.fY, weight);
return this->conicTo(x1, y1, x1 + after.fX, y1 + after.fY, weight);
}
///////////////////////////////////////////////////////////////////////////////
void SkPath::addPath(const SkPath& path, SkScalar dx, SkScalar dy, AddPathMode mode) {
SkPath& SkPath::addPath(const SkPath& path, SkScalar dx, SkScalar dy, AddPathMode mode) {
SkMatrix matrix;
matrix.setTranslate(dx, dy);
this->addPath(path, matrix, mode);
return this->addPath(path, matrix, mode);
}
void SkPath::addPath(const SkPath& path, const SkMatrix& matrix, AddPathMode mode) {
SkPath& SkPath::addPath(const SkPath& path, const SkMatrix& matrix, AddPathMode mode) {
SkPathRef::Editor(&fPathRef, path.countVerbs(), path.countPoints());
RawIter iter(path);
@ -1611,6 +1621,7 @@ void SkPath::addPath(const SkPath& path, const SkMatrix& matrix, AddPathMode mod
}
firstVerb = false;
}
return *this;
}
///////////////////////////////////////////////////////////////////////////////
@ -1631,10 +1642,10 @@ static int pts_in_verb(unsigned verb) {
}
// ignore the last point of the 1st contour
void SkPath::reversePathTo(const SkPath& path) {
SkPath& SkPath::reversePathTo(const SkPath& path) {
const uint8_t* verbs = path.fPathRef->verbsMemBegin(); // points at the last verb
if (!verbs) { // empty path returns nullptr
return;
return *this;
}
const uint8_t* verbsEnd = path.fPathRef->verbs() - 1; // points just past the first verb
SkASSERT(verbsEnd[0] == kMove_Verb);
@ -1647,7 +1658,7 @@ void SkPath::reversePathTo(const SkPath& path) {
switch (v) {
case kMove_Verb:
// if the path has multiple contours, stop after reversing the last
return;
return *this;
case kLine_Verb:
this->lineTo(pts[0]);
break;
@ -1668,9 +1679,10 @@ void SkPath::reversePathTo(const SkPath& path) {
break;
}
}
return *this;
}
void SkPath::reverseAddPath(const SkPath& src) {
SkPath& SkPath::reverseAddPath(const SkPath& src) {
SkPathRef::Editor ed(&fPathRef, src.fPathRef->countPoints(), src.fPathRef->countVerbs());
const SkPoint* pts = src.fPathRef->pointsEnd();
@ -1719,6 +1731,7 @@ void SkPath::reverseAddPath(const SkPath& src) {
SkDEBUGFAIL("unexpected verb");
}
}
return *this;
}
///////////////////////////////////////////////////////////////////////////////

View File

@ -121,12 +121,9 @@ static void test_crbug_140803() {
bm.allocN32Pixels(2700, 30*1024);
SkCanvas canvas(bm);
SkPath path;
path.moveTo(2762, 20);
path.quadTo(11, 21702, 10, 21706);
SkPaint paint;
paint.setAntiAlias(true);
canvas.drawPath(path, paint);
canvas.drawPath(SkPath().moveTo(2762, 20).quadTo(11, 21702, 10, 21706), paint);
}
// Need to exercise drawing an inverse-path whose bounds intersect the clip,

View File

@ -106,11 +106,11 @@ static void iter_paint(skiatest::Reporter* reporter, const SkPath& path, bool sh
static void make_empty(SkPath*) {}
static void make_M(SkPath* path) { path->moveTo(CX, CY); }
static void make_MM(SkPath* path) { path->moveTo(CX, CY); path->moveTo(CX, CY); }
static void make_MZM(SkPath* path) { path->moveTo(CX, CY); path->close(); path->moveTo(CX, CY); }
static void make_L(SkPath* path) { path->moveTo(CX, CY); path->lineTo(CX, CY); }
static void make_Q(SkPath* path) { path->moveTo(CX, CY); path->quadTo(CX, CY, CX, CY); }
static void make_C(SkPath* path) { path->moveTo(CX, CY); path->cubicTo(CX, CY, CX, CY, CX, CY); }
static void make_MM(SkPath* path) { path->moveTo(CX, CY).moveTo(CX, CY); }
static void make_MZM(SkPath* path) { path->moveTo(CX, CY).close().moveTo(CX, CY); }
static void make_L(SkPath* path) { path->moveTo(CX, CY).lineTo(CX, CY); }
static void make_Q(SkPath* path) { path->moveTo(CX, CY).quadTo(CX, CY, CX, CY); }
static void make_C(SkPath* path) { path->moveTo(CX, CY).cubicTo(CX, CY, CX, CY, CX, CY); }
/* Two invariants are tested: How does an empty/degenerate path draw?
* - if the path is drawn inverse, it should draw everywhere

View File

@ -37,11 +37,11 @@ DEF_TEST(FillPathInverse, reporter) {
int width = 200;
int expected_lines = 5;
clip.set(0, height - expected_lines, width, height);
path.moveTo(0.0f, 0.0f);
path.quadTo(SkIntToScalar(width/2), SkIntToScalar(height),
SkIntToScalar(width), 0.0f);
path.close();
path.setFillType(SkPath::kInverseWinding_FillType);
path.moveTo(0.0f, 0.0f)
.quadTo(SkIntToScalar(width/2), SkIntToScalar(height),
SkIntToScalar(width), 0.0f)
.close()
.setFillType(SkPath::kInverseWinding_FillType);
SkScan::FillPath(path, clip, &blitter);
REPORTER_ASSERT(reporter, blitter.m_blitCount == expected_lines);