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:
parent
c37d551167
commit
ad5494d1d9
@ -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:
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
});
|
||||
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -244,6 +244,8 @@ private:
|
||||
|
||||
SkPath make(sk_sp<SkPathRef>) const;
|
||||
|
||||
SkPathBuilder& privateReverseAddPath(const SkPath&);
|
||||
|
||||
// For testing
|
||||
void privateSetConvexityType(SkPathConvexityType c) { fConvexity = c; }
|
||||
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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).
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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()));
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user