use pathbuilder

Change-Id: I11c18d4ff0e60cc33d742cf49359039395abc6b4
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/313256
Reviewed-by: Mike Reed <reed@google.com>
Commit-Queue: Mike Reed <reed@google.com>
This commit is contained in:
Mike Reed 2020-08-25 17:36:28 -04:00 committed by Skia Commit-Bot
parent c37d551167
commit ad5494d1d9
10 changed files with 135 additions and 81 deletions

View File

@ -11,7 +11,7 @@
#include "include/core/SkColor.h"
#include "include/core/SkMatrix.h"
#include "include/core/SkPaint.h"
#include "include/core/SkPath.h"
#include "include/core/SkPathBuilder.h"
#include "include/core/SkRect.h"
#include "include/core/SkScalar.h"
#include "include/core/SkSize.h"
@ -225,12 +225,13 @@ class ClipCubicGM : public skiagm::GM {
SkPath fVPath, fHPath;
public:
ClipCubicGM() {
fVPath.moveTo(W, 0);
fVPath.cubicTo(W, H-10, 0, 10, 0, H);
fVPath = SkPathBuilder().moveTo(W, 0)
.cubicTo(W, H-10, 0, 10, 0, H)
.detach();
SkMatrix pivot;
pivot.setRotate(90, W/2, H/2);
fVPath.transform(pivot, &fHPath);
fHPath = fVPath.makeTransform(pivot);
}
protected:

View File

@ -10,7 +10,7 @@
#include "include/core/SkColor.h"
#include "include/core/SkFont.h"
#include "include/core/SkPaint.h"
#include "include/core/SkPath.h"
#include "include/core/SkPathBuilder.h"
#include "include/core/SkPoint.h"
#include "include/core/SkRect.h"
#include "include/core/SkScalar.h"
@ -125,30 +125,35 @@ static constexpr SkPoint kPts[kPtsCount] = {
{120, 40},
};
static void make_path_move(SkPath* path) {
static SkPath make_path_move() {
SkPathBuilder builder;
for (SkPoint p : kPts) {
path->moveTo(p);
builder.moveTo(p);
}
return builder.detach();
}
static void make_path_move_close(SkPath* path) {
static SkPath make_path_move_close() {
SkPathBuilder builder;
for (SkPoint p : kPts) {
path->moveTo(p);
path->close();
builder.moveTo(p).close();
}
return builder.detach();
}
static void make_path_move_line(SkPath* path) {
static SkPath make_path_move_line() {
SkPathBuilder builder;
for (SkPoint p : kPts) {
path->moveTo(p);
path->lineTo(p);
builder.moveTo(p).lineTo(p);
}
return builder.detach();
}
static void make_path_move_mix(SkPath* path) {
path->moveTo(kPts[0]);
path->moveTo(kPts[1]); path->close();
path->moveTo(kPts[2]); path->lineTo(kPts[2]);
static SkPath make_path_move_mix() {
return SkPathBuilder().moveTo(kPts[0])
.moveTo(kPts[1]).close()
.moveTo(kPts[2]).lineTo(kPts[2])
.detach();
}
class EmptyStrokeGM : public GM {
@ -157,7 +162,7 @@ class EmptyStrokeGM : public GM {
SkISize onISize() override { return {200, 240}; }
void onDraw(SkCanvas* canvas) override {
static constexpr void (*kProcs[])(SkPath*) = {
static constexpr SkPath (*kProcs[])() = {
make_path_move, // expect red red red
make_path_move_close, // expect black black black
make_path_move_line, // expect black black black
@ -175,10 +180,8 @@ class EmptyStrokeGM : public GM {
dotPaint.setStrokeWidth(7);
for (auto proc : kProcs) {
SkPath path;
proc(&path);
canvas->drawPoints(SkCanvas::kPoints_PointMode, kPtsCount, kPts, dotPaint);
canvas->drawPath(path, strokePaint);
canvas->drawPath(proc(), strokePaint);
canvas->translate(0, 40);
}
}

View File

@ -60,37 +60,26 @@ protected:
});
drawDirs(canvas, [](const SkRect& rect, SkPathDirection dir, unsigned startIndex) {
SkPath path;
path.addOval(rect, dir, startIndex);
return path;
return SkPath::Oval(rect, dir, startIndex);
});
drawDirs(canvas, [](const SkRect& rect, SkPathDirection dir, unsigned startIndex) {
SkRRect rrect;
const SkVector radii[4] = { {15, 15}, {15, 15}, {15, 15}, {15, 15}};
rrect.setRectRadii(rect, radii);
SkPath path;
path.addRRect(rrect, dir, startIndex);
return path;
return SkPath::RRect(rrect, dir, startIndex);
});
drawDirs(canvas, [](const SkRect& rect, SkPathDirection dir, unsigned startIndex) {
SkRRect rrect;
rrect.setRect(rect);
SkPath path;
path.addRRect(rrect, dir, startIndex);
return path;
return SkPath::RRect(rrect, dir, startIndex);
});
drawDirs(canvas, [](const SkRect& rect, SkPathDirection dir, unsigned startIndex) {
SkRRect rrect;
rrect.setOval(rect);
SkPath path;
path.addRRect(rrect, dir, startIndex);
return path;
return SkPath::RRect(rrect, dir, startIndex);
});
}

View File

@ -71,6 +71,7 @@ public:
static SkPath Rect(const SkRect&, SkPathDirection = SkPathDirection::kCW,
unsigned startIndex = 0);
static SkPath Oval(const SkRect&, SkPathDirection = SkPathDirection::kCW);
static SkPath Oval(const SkRect&, SkPathDirection, unsigned startIndex);
static SkPath Circle(SkScalar center_x, SkScalar center_y, SkScalar radius,
SkPathDirection dir = SkPathDirection::kCW);
static SkPath RRect(const SkRRect&, SkPathDirection dir = SkPathDirection::kCW);

View File

@ -244,6 +244,8 @@ private:
SkPath make(sk_sp<SkPathRef>) const;
SkPathBuilder& privateReverseAddPath(const SkPath&);
// For testing
void privateSetConvexityType(SkPathConvexityType c) { fConvexity = c; }

View File

@ -1436,21 +1436,6 @@ SkPath& SkPath::addPath(const SkPath& srcPath, const SkMatrix& matrix, AddPathMo
///////////////////////////////////////////////////////////////////////////////
static int pts_in_verb(unsigned verb) {
static const uint8_t gPtsInVerb[] = {
1, // kMove
1, // kLine
2, // kQuad
2, // kConic
3, // kCubic
0, // kClose
0 // kDone
};
SkASSERT(verb < SK_ARRAY_COUNT(gPtsInVerb));
return gPtsInVerb[verb];
}
// ignore the last point of the 1st contour
SkPath& SkPath::reversePathTo(const SkPath& path) {
if (path.fPathRef->fVerbs.count() == 0) {
@ -1465,7 +1450,7 @@ SkPath& SkPath::reversePathTo(const SkPath& path) {
while (verbs > verbsBegin) {
uint8_t v = *--verbs;
pts -= pts_in_verb(v);
pts -= SkPathPriv::PtsInVerb(v);
switch (v) {
case kMove_Verb:
// if the path has multiple contours, stop after reversing the last
@ -1509,7 +1494,7 @@ SkPath& SkPath::reverseAddPath(const SkPath& srcPath) {
bool needClose = false;
while (verbs > verbsBegin) {
uint8_t v = *--verbs;
int n = pts_in_verb(v);
int n = SkPathPriv::PtsInVerb(v);
if (needMove) {
--pts;
@ -3413,6 +3398,10 @@ SkPath SkPath::Oval(const SkRect& r, SkPathDirection dir) {
return SkPathBuilder().addOval(r, dir).detach();
}
SkPath SkPath::Oval(const SkRect& r, SkPathDirection dir, unsigned startIndex) {
return SkPathBuilder().addOval(r, dir, startIndex).detach();
}
SkPath SkPath::Circle(SkScalar x, SkScalar y, SkScalar r, SkPathDirection dir) {
return SkPathBuilder().addCircle(x, y, r, dir).detach();
}

View File

@ -10,6 +10,7 @@
#include "include/private/SkPathRef.h"
#include "include/private/SkSafe32.h"
#include "src/core/SkGeometry.h"
#include "src/core/SkPathPriv.h"
// need SkDVector
#include "src/pathops/SkPathOpsPoint.h"
@ -108,12 +109,14 @@ SkPathBuilder& SkPathBuilder::cubicTo(SkPoint pt1, SkPoint pt2, SkPoint pt3) {
}
SkPathBuilder& SkPathBuilder::close() {
this->ensureMove();
if (fVerbs.count() > 0) {
this->ensureMove();
fVerbs.push_back((uint8_t)SkPathVerb::kClose);
fVerbs.push_back((uint8_t)SkPathVerb::kClose);
// fLastMovePoint stays where it is -- the previous moveTo
fNeedsMoveVerb = true;
// fLastMovePoint stays where it is -- the previous moveTo
fNeedsMoveVerb = true;
}
return *this;
}
@ -719,3 +722,53 @@ SkPathBuilder& SkPathBuilder::offset(SkScalar dx, SkScalar dy) {
}
return *this;
}
SkPathBuilder& SkPathBuilder::privateReverseAddPath(const SkPath& src) {
const uint8_t* verbsBegin = src.fPathRef->verbsBegin();
const uint8_t* verbs = src.fPathRef->verbsEnd();
const SkPoint* pts = src.fPathRef->pointsEnd();
const SkScalar* conicWeights = src.fPathRef->conicWeightsEnd();
bool needMove = true;
bool needClose = false;
while (verbs > verbsBegin) {
uint8_t v = *--verbs;
int n = SkPathPriv::PtsInVerb(v);
if (needMove) {
--pts;
this->moveTo(pts->fX, pts->fY);
needMove = false;
}
pts -= n;
switch ((SkPathVerb)v) {
case SkPathVerb::kMove:
if (needClose) {
this->close();
needClose = false;
}
needMove = true;
pts += 1; // so we see the point in "if (needMove)" above
break;
case SkPathVerb::kLine:
this->lineTo(pts[0]);
break;
case SkPathVerb::kQuad:
this->quadTo(pts[1], pts[0]);
break;
case SkPathVerb::kConic:
this->conicTo(pts[1], pts[0], *--conicWeights);
break;
case SkPathVerb::kCubic:
this->cubicTo(pts[2], pts[1], pts[0]);
break;
case SkPathVerb::kClose:
needClose = true;
break;
default:
SkDEBUGFAIL("unexpected verb");
}
}
return *this;
}

View File

@ -317,6 +317,23 @@ public:
return gPtsInVerb[verb];
}
// Returns number of valid points for each verb, not including the "starter"
// point that the Iterator adds for line/quad/conic/cubic
static int PtsInVerb(unsigned verb) {
static const uint8_t gPtsInVerb[] = {
1, // kMove pts[0]
1, // kLine pts[0..1]
2, // kQuad pts[0..2]
2, // kConic pts[0..2]
3, // kCubic pts[0..3]
0, // kClose
0 // kDone
};
SkASSERT(verb < SK_ARRAY_COUNT(gPtsInVerb));
return gPtsInVerb[verb];
}
static bool IsAxisAligned(const SkPath& path) {
SkRect tmp;
return (path.fPathRef->fIsRRect | path.fPathRef->fIsOval) || path.isRect(&tmp);
@ -396,6 +413,10 @@ public:
static void SetConvexityType(SkPathBuilder* builder, SkPathConvexityType c) {
builder->privateSetConvexityType(c);
}
static void ReverseAddPath(SkPathBuilder* builder, const SkPath& reverseMe) {
builder->privateReverseAddPath(reverseMe);
}
};
// Lightweight variant of SkPath::Iter that only returns segments (e.g. lines/conics).

View File

@ -321,13 +321,16 @@ public:
return reversed;
}
void reverseMarkedContours(vector<Contour>& contours, SkPath* result) {
SkPath reverseMarkedContours(vector<Contour>& contours, SkPathFillType fillType) {
SkPathPriv::Iterate iterate(fPath);
auto iter = iterate.begin();
int verbCount = 0;
SkPathBuilder result;
result.setFillType(fillType);
for (const Contour& contour : contours) {
SkPath reverse;
SkPath* temp = contour.fReverse ? &reverse : result;
SkPathBuilder reverse;
SkPathBuilder* temp = contour.fReverse ? &reverse : &result;
for (; iter != iterate.end() && verbCount < contour.fVerbEnd; ++iter, ++verbCount) {
auto [verb, pts, w] = *iter;
switch (verb) {
@ -352,9 +355,11 @@ public:
}
}
if (contour.fReverse) {
result->reverseAddPath(reverse);
SkASSERT(temp == &reverse);
SkPathPriv::ReverseAddPath(&result, reverse.detach());
}
}
return result.detach();
}
private:
@ -413,9 +418,6 @@ bool AsWinding(const SkPath& path, SkPath* result) {
if (!reversed) {
return set_result_path(result, path, fillType);
}
SkPath temp;
temp.setFillType(fillType);
winder.reverseMarkedContours(contours, &temp);
result->swap(temp);
*result = winder.reverseMarkedContours(contours, fillType);
return true;
}

View File

@ -8,52 +8,45 @@
#include "tests/Test.h"
DEF_TEST(IsClosedSingleContourTest, reporter) {
SkPath p;
REPORTER_ASSERT(reporter, !SkPathPriv::IsClosedSingleContour(p));
SkPathBuilder p;
REPORTER_ASSERT(reporter, !SkPathPriv::IsClosedSingleContour(p.detach()));
p.reset();
p.close();
REPORTER_ASSERT(reporter, !SkPathPriv::IsClosedSingleContour(p));
REPORTER_ASSERT(reporter, !SkPathPriv::IsClosedSingleContour(p.detach()));
p.reset();
p.moveTo(10, 10);
p.close();
REPORTER_ASSERT(reporter, SkPathPriv::IsClosedSingleContour(p));
REPORTER_ASSERT(reporter, SkPathPriv::IsClosedSingleContour(p.detach()));
p.reset();
p.moveTo(10, 10);
p.lineTo(20, 20);
p.close();
REPORTER_ASSERT(reporter, SkPathPriv::IsClosedSingleContour(p));
REPORTER_ASSERT(reporter, SkPathPriv::IsClosedSingleContour(p.detach()));
p.reset();
p.moveTo(10, 10);
p.lineTo(20, 20);
p.quadTo(30, 30, 40, 40);
p.cubicTo(50, 50, 60, 60, 70, 70);
p.conicTo(30, 30, 40, 40, 0.5);
p.close();
REPORTER_ASSERT(reporter, SkPathPriv::IsClosedSingleContour(p));
REPORTER_ASSERT(reporter, SkPathPriv::IsClosedSingleContour(p.detach()));
p.reset();
p.moveTo(10, 10);
p.lineTo(20, 20);
p.lineTo(20, 30);
REPORTER_ASSERT(reporter, !SkPathPriv::IsClosedSingleContour(p));
REPORTER_ASSERT(reporter, !SkPathPriv::IsClosedSingleContour(p.detach()));
p.reset();
p.moveTo(10, 10);
p.lineTo(20, 20);
p.moveTo(10, 10);
p.lineTo(20, 30);
p.close();
REPORTER_ASSERT(reporter, !SkPathPriv::IsClosedSingleContour(p));
REPORTER_ASSERT(reporter, !SkPathPriv::IsClosedSingleContour(p.detach()));
p.reset();
p.moveTo(10, 10);
p.lineTo(20, 20);
p.close();
p.lineTo(20, 30);
p.close();
REPORTER_ASSERT(reporter, !SkPathPriv::IsClosedSingleContour(p));
REPORTER_ASSERT(reporter, !SkPathPriv::IsClosedSingleContour(p.detach()));
}