Simplify firstdirection

Change-Id: I30d3056dc97a16c08b85fd77120485ef07b18d96
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/314037
Reviewed-by: Mike Reed <reed@google.com>
Commit-Queue: Mike Reed <reed@google.com>
This commit is contained in:
Mike Reed 2020-08-30 10:32:06 -04:00 committed by Skia Commit-Bot
parent 3872c98951
commit 85f51b2a40
11 changed files with 63 additions and 81 deletions

View File

@ -258,8 +258,7 @@ protected:
// of the GMs rows.
SkASSERT(path.isConvex());
SkASSERT(SkPath::kLine_SegmentMask == path.getSegmentMasks());
SkPathFirstDirection actualDir;
SkASSERT(SkPathPriv::CheapComputeFirstDirection(path, &actualDir));
SkPathFirstDirection actualDir = SkPathPriv::ComputeFirstDirection(path);
SkASSERT(SkPathPriv::AsFirstDirection(dir) == actualDir);
SkRect bounds = path.getBounds();
SkASSERT(SkScalarNearlyEqual(bounds.centerX(), 0.0f));

View File

@ -303,12 +303,12 @@ DEF_SIMPLE_GM_BG_NAME(strokefill, canvas, 640, 480, SK_ColorWHITE,
path2.reset();
path2.addCircle(x + SkIntToScalar(240), y + SkIntToScalar(200), SkIntToScalar(50), SkPathDirection::kCCW);
canvas->drawPath(path2, paint);
SkASSERT(SkPathPriv::CheapIsFirstDirection(path2, SkPathFirstDirection::kCCW));
SkASSERT(SkPathPriv::ComputeFirstDirection(path2) == SkPathFirstDirection::kCCW);
path2.reset();
SkASSERT(!SkPathPriv::CheapComputeFirstDirection(path2, nullptr));
SkASSERT(SkPathPriv::ComputeFirstDirection(path2) == SkPathFirstDirection::kUnknown);
path2.addCircle(x + SkIntToScalar(360), y + SkIntToScalar(200), SkIntToScalar(50), SkPathDirection::kCW);
SkASSERT(SkPathPriv::CheapIsFirstDirection(path2, SkPathFirstDirection::kCW));
SkASSERT(SkPathPriv::ComputeFirstDirection(path2) == SkPathFirstDirection::kCW);
canvas->drawPath(path2, paint);
SkRect r = SkRect::MakeXYWH(x - SkIntToScalar(50), y + SkIntToScalar(280),
@ -332,18 +332,18 @@ DEF_SIMPLE_GM_BG_NAME(strokefill, canvas, 640, 480, SK_ColorWHITE,
r = SkRect::MakeXYWH(x + SkIntToScalar(190), y + SkIntToScalar(280),
SkIntToScalar(100), SkIntToScalar(100));
path4.reset();
SkASSERT(!SkPathPriv::CheapComputeFirstDirection(path4, nullptr));
SkASSERT(SkPathPriv::ComputeFirstDirection(path4) == SkPathFirstDirection::kUnknown);
path4.addRect(r, SkPathDirection::kCCW);
SkASSERT(SkPathPriv::CheapIsFirstDirection(path4, SkPathFirstDirection::kCCW));
SkASSERT(SkPathPriv::ComputeFirstDirection(path4) == SkPathFirstDirection::kCCW);
path4.moveTo(0, 0); // test for crbug.com/247770
canvas->drawPath(path4, paint);
r = SkRect::MakeXYWH(x + SkIntToScalar(310), y + SkIntToScalar(280),
SkIntToScalar(100), SkIntToScalar(100));
path4.reset();
SkASSERT(!SkPathPriv::CheapComputeFirstDirection(path4, nullptr));
SkASSERT(SkPathPriv::ComputeFirstDirection(path4) == SkPathFirstDirection::kUnknown);
path4.addRect(r, SkPathDirection::kCW);
SkASSERT(SkPathPriv::CheapIsFirstDirection(path4, SkPathFirstDirection::kCW));
SkASSERT(SkPathPriv::ComputeFirstDirection(path4) == SkPathFirstDirection::kCW);
path4.moveTo(0, 0); // test for crbug.com/247770
canvas->drawPath(path4, paint);
}

View File

@ -290,8 +290,8 @@ bool SkPath::conservativelyContainsRect(const SkRect& rect) const {
return false;
}
SkPathFirstDirection direction;
if (!SkPathPriv::CheapComputeFirstDirection(*this, &direction)) {
SkPathFirstDirection direction = SkPathPriv::ComputeFirstDirection(*this);
if (direction == SkPathFirstDirection::kUnknown) {
return false;
}
@ -2443,8 +2443,8 @@ static int find_min_max_x_at_y(const SkPoint pts[], int index, int n,
return minIndex;
}
static void crossToDir(SkScalar cross, SkPathFirstDirection* dir) {
*dir = cross > 0 ? SkPathFirstDirection::kCW : SkPathFirstDirection::kCCW;
static SkPathFirstDirection crossToDir(SkScalar cross) {
return cross > 0 ? SkPathFirstDirection::kCW : SkPathFirstDirection::kCCW;
}
/*
@ -2455,19 +2455,17 @@ static void crossToDir(SkScalar cross, SkPathFirstDirection* dir) {
* that is outer most (or at least has the global y-max) before we can consider
* its cross product.
*/
bool SkPathPriv::CheapComputeFirstDirection(const SkPath& path, SkPathFirstDirection* dir) {
SkPathFirstDirection SkPathPriv::ComputeFirstDirection(const SkPath& path) {
auto d = path.getFirstDirection();
if (d != SkPathFirstDirection::kUnknown) {
*dir = d;
return true;
return d;
}
// We don't want to pay the cost for computing convexity if it is unknown,
// so we call getConvexityOrUnknown() instead of isConvex().
if (path.getConvexityOrUnknown() == SkPathConvexity::kConvex) {
SkASSERT(path.getFirstDirection() == SkPathFirstDirection::kUnknown);
*dir = path.getFirstDirection();
return false;
SkASSERT(d == SkPathFirstDirection::kUnknown);
return d;
}
ContourIter iter(*path.fPathRef);
@ -2538,12 +2536,10 @@ bool SkPathPriv::CheapComputeFirstDirection(const SkPath& path, SkPathFirstDirec
}
}
if (ymaxCross) {
crossToDir(ymaxCross, dir);
path.setFirstDirection(*dir);
return true;
} else {
return false;
d = crossToDir(ymaxCross);
path.setFirstDirection(d);
}
return d; // may still be kUnknown
}
///////////////////////////////////////////////////////////////////////////////

View File

@ -44,25 +44,12 @@ public:
}
/**
* Tries to quickly compute the direction of the first non-degenerate
* contour. If it can be computed, return true and set dir to that
* direction. If it cannot be (quickly) determined, return false and ignore
* the dir parameter. If the direction was determined, it is cached to make
* subsequent calls return quickly.
* Tries to compute the direction of the outer-most non-degenerate
* contour. If it can be computed, return that direction. If it cannot be determined,
* or the contour is known to be convex, return kUnknown. If the direction was determined,
* it is cached to make subsequent calls return quickly.
*/
static bool CheapComputeFirstDirection(const SkPath&, SkPathFirstDirection* dir);
/**
* Returns true if the path's direction can be computed via
* cheapComputDirection() and if that computed direction matches the
* specified direction. If dir is kUnknown, returns true if the direction
* cannot be computed.
*/
static bool CheapIsFirstDirection(const SkPath& path, SkPathFirstDirection dir) {
SkPathFirstDirection computedDir = SkPathFirstDirection::kUnknown;
(void)CheapComputeFirstDirection(path, &computedDir);
return computedDir == dir;
}
static SkPathFirstDirection ComputeFirstDirection(const SkPath&);
static bool IsClosedSingleContour(const SkPath& path) {
int verbCount = path.countVerbs();

View File

@ -1504,7 +1504,7 @@ DONE:
stroker.done(dst, lastSegment == SkPath::kLine_Verb);
if (fDoFill && !ignoreCenter) {
if (SkPathPriv::CheapIsFirstDirection(src, SkPathFirstDirection::kCCW)) {
if (SkPathPriv::ComputeFirstDirection(src) == SkPathFirstDirection::kCCW) {
dst->reverseAddPath(src);
} else {
dst->addPath(src);

View File

@ -134,10 +134,8 @@ sk_sp<SkPathEffect> SkStrokeAndFillPathEffect::Make() {
void SkStrokeAndFillPE::flatten(SkWriteBuffer&) const {}
static bool known_to_be_opposite_directions(const SkPath& a, const SkPath& b) {
auto a_dir = SkPathFirstDirection::kUnknown,
b_dir = SkPathFirstDirection::kUnknown;
(void)SkPathPriv::CheapComputeFirstDirection(a, &a_dir);
(void)SkPathPriv::CheapComputeFirstDirection(b, &b_dir);
auto a_dir = SkPathPriv::ComputeFirstDirection(a),
b_dir = SkPathPriv::ComputeFirstDirection(b);
return (a_dir == SkPathFirstDirection::kCCW &&
b_dir == SkPathFirstDirection::kCW)

View File

@ -97,11 +97,11 @@ GrFPResult GrConvexPolyEffect::Make(std::unique_ptr<GrFragmentProcessor> inputFP
return GrFPFailure(std::move(inputFP));
}
SkPathFirstDirection dir;
SkPathFirstDirection dir = SkPathPriv::ComputeFirstDirection(path);
// The only way this should fail is if the clip is effectively a infinitely thin line. In that
// case nothing is inside the clip. It'd be nice to detect this at a higher level and either
// skip the draw or omit the clip element.
if (!SkPathPriv::CheapComputeFirstDirection(path, &dir)) {
if (dir == SkPathFirstDirection::kUnknown) {
if (GrProcessorEdgeTypeIsInverseFill(type)) {
return GrFPSuccess(
GrFragmentProcessor::ModulateRGBA(std::move(inputFP), SK_PMColor4fWHITE));

View File

@ -178,7 +178,7 @@ public:
// Assuming this is called after knownToBeConvex(), this should just be relying on
// cached convexity and direction and will be cheap.
return !fShape.isPath() ||
!SkPathPriv::CheapIsFirstDirection(fShape.path(), SkPathFirstDirection::kUnknown);
SkPathPriv::ComputeFirstDirection(fShape.path()) != SkPathFirstDirection::kUnknown;
}
/** Is the pre-styled geometry inverse filled? */

View File

@ -228,7 +228,8 @@ static inline bool get_direction(const SkPath& path, const SkMatrix& m,
// direction could be determined, so this should just be fetching the cached direction.
// However, if perspective is involved, we're operating on a transformed path, which may no
// longer have a computable direction.
if (!SkPathPriv::CheapComputeFirstDirection(path, dir)) {
*dir = SkPathPriv::ComputeFirstDirection(path);
if (*dir == SkPathFirstDirection::kUnknown) {
return false;
}

View File

@ -42,13 +42,15 @@ bool SkOpBuilder::FixWinding(SkPath* path) {
} else if (fillType == SkPathFillType::kEvenOdd) {
fillType = SkPathFillType::kWinding;
}
SkPathFirstDirection dir;
if (one_contour(*path) && SkPathPriv::CheapComputeFirstDirection(*path, &dir)) {
if (dir != SkPathFirstDirection::kCCW) {
ReversePath(path);
if (one_contour(*path)) {
SkPathFirstDirection dir = SkPathPriv::ComputeFirstDirection(*path);
if (dir != SkPathFirstDirection::kUnknown) {
if (dir == SkPathFirstDirection::kCW) {
ReversePath(path);
}
path->setFillType(fillType);
return true;
}
path->setFillType(fillType);
return true;
}
SkSTArenaAlloc<4096> allocator;
SkOpContourHead contourHead;
@ -136,8 +138,8 @@ bool SkOpBuilder::resolve(SkPath* result) {
}
// If all paths are convex, track direction, reversing as needed.
if (test->isConvex()) {
SkPathFirstDirection dir;
if (!SkPathPriv::CheapComputeFirstDirection(*test, &dir)) {
SkPathFirstDirection dir = SkPathPriv::ComputeFirstDirection(*test);
if (dir == SkPathFirstDirection::kUnknown) {
allUnion = false;
break;
}

View File

@ -1059,21 +1059,17 @@ static void check_direction(skiatest::Reporter* reporter, const SkPath& path,
// We make a copy so that we don't cache the result on the passed in path.
SkPath copy(path); // NOLINT(performance-unnecessary-copy-initialization)
SkPathFirstDirection dir;
if (SkPathPriv::CheapComputeFirstDirection(copy, &dir)) {
SkPathFirstDirection dir = SkPathPriv::ComputeFirstDirection(copy);
if (dir != SkPathFirstDirection::kUnknown) {
REPORTER_ASSERT(reporter, dir == expected);
} else {
REPORTER_ASSERT(reporter, SkPathFirstDirection::kUnknown == expected);
}
}
static void test_direction(skiatest::Reporter* reporter) {
size_t i;
SkPath path;
REPORTER_ASSERT(reporter, !SkPathPriv::CheapComputeFirstDirection(path, nullptr));
REPORTER_ASSERT(reporter, !SkPathPriv::CheapIsFirstDirection(path, SkPathFirstDirection::kCW));
REPORTER_ASSERT(reporter, !SkPathPriv::CheapIsFirstDirection(path, SkPathFirstDirection::kCCW));
REPORTER_ASSERT(reporter, SkPathPriv::CheapIsFirstDirection(path, SkPathFirstDirection::kUnknown));
REPORTER_ASSERT(reporter,
SkPathPriv::ComputeFirstDirection(path) == SkPathFirstDirection::kUnknown);
static const char* gDegen[] = {
"M 10 10",
@ -1087,7 +1083,8 @@ static void test_direction(skiatest::Reporter* reporter) {
path.reset();
bool valid = SkParsePath::FromSVGString(gDegen[i], &path);
REPORTER_ASSERT(reporter, valid);
REPORTER_ASSERT(reporter, !SkPathPriv::CheapComputeFirstDirection(path, nullptr));
REPORTER_ASSERT(reporter,
SkPathPriv::ComputeFirstDirection(path) == SkPathFirstDirection::kUnknown);
}
static const char* gCW[] = {
@ -1588,12 +1585,12 @@ static void test_convexity(skiatest::Reporter* reporter) {
path.reset();
path.addRect(0, 0, SkIntToScalar(10), SkIntToScalar(10), SkPathDirection::kCCW);
check_convexity(reporter, path, true);
REPORTER_ASSERT(reporter, SkPathPriv::CheapIsFirstDirection(path, SkPathFirstDirection::kCCW));
REPORTER_ASSERT(reporter, SkPathPriv::ComputeFirstDirection(path) == SkPathFirstDirection::kCCW);
path.reset();
path.addRect(0, 0, SkIntToScalar(10), SkIntToScalar(10), SkPathDirection::kCW);
check_convexity(reporter, path, true);
REPORTER_ASSERT(reporter, SkPathPriv::CheapIsFirstDirection(path, SkPathFirstDirection::kCW));
REPORTER_ASSERT(reporter, SkPathPriv::ComputeFirstDirection(path) == SkPathFirstDirection::kCW);
path.reset();
path.quadTo(100, 100, 50, 50); // This from GM:convexpaths
@ -1623,8 +1620,8 @@ static void test_convexity(skiatest::Reporter* reporter) {
if (kDontCheckDir != gRec[i].fExpectedDirection) {
// We make a copy so that we don't cache the result on the passed in path.
SkPath copy(path); // NOLINT(performance-unnecessary-copy-initialization)
SkPathFirstDirection dir;
bool foundDir = SkPathPriv::CheapComputeFirstDirection(copy, &dir);
SkPathFirstDirection dir = SkPathPriv::ComputeFirstDirection(copy);
bool foundDir = dir != SkPathFirstDirection::kUnknown;
REPORTER_ASSERT(reporter, (gRec[i].fExpectedDirection == SkPathFirstDirection::kUnknown)
^ foundDir);
REPORTER_ASSERT(reporter, !foundDir || gRec[i].fExpectedDirection == dir);
@ -2154,10 +2151,10 @@ static void test_isRect(skiatest::Reporter* reporter) {
SkRect computed, expected;
bool isClosed;
SkPathDirection direction;
SkPathFirstDirection cheapDirection;
int pointCount = tests[testIndex].fPointCount - (d2 == tests[testIndex].fPoints);
expected.setBounds(tests[testIndex].fPoints, pointCount);
REPORTER_ASSERT(reporter, SkPathPriv::CheapComputeFirstDirection(path, &cheapDirection));
SkPathFirstDirection cheapDirection = SkPathPriv::ComputeFirstDirection(path);
REPORTER_ASSERT(reporter, cheapDirection != SkPathFirstDirection::kUnknown);
REPORTER_ASSERT(reporter, path.isRect(&computed, &isClosed, &direction));
REPORTER_ASSERT(reporter, expected == computed);
REPORTER_ASSERT(reporter, isClosed == tests[testIndex].fClose);
@ -2758,7 +2755,7 @@ static void test_transform(skiatest::Reporter* reporter) {
p1.moveTo(SkPoint::Make(0, 0));
p.transform(matrix, &p1);
REPORTER_ASSERT(reporter, SkPathPriv::CheapIsFirstDirection(p1, SkPathFirstDirection::kCW));
REPORTER_ASSERT(reporter, SkPathPriv::ComputeFirstDirection(p1) == SkPathFirstDirection::kCW);
}
@ -2770,7 +2767,7 @@ static void test_transform(skiatest::Reporter* reporter) {
p1.moveTo(SkPoint::Make(0, 0)); // Make p1 unique (i.e., not empty path)
p.transform(matrix, &p1);
REPORTER_ASSERT(reporter, SkPathPriv::CheapIsFirstDirection(p1, SkPathFirstDirection::kCCW));
REPORTER_ASSERT(reporter, SkPathPriv::ComputeFirstDirection(p1) == SkPathFirstDirection::kCCW);
}
{
@ -2780,7 +2777,7 @@ static void test_transform(skiatest::Reporter* reporter) {
p1.moveTo(SkPoint::Make(0, 0)); // Make p1 unique (i.e., not empty path)
p.transform(matrix, &p1);
REPORTER_ASSERT(reporter, SkPathPriv::CheapIsFirstDirection(p1, SkPathFirstDirection::kUnknown));
REPORTER_ASSERT(reporter, SkPathPriv::ComputeFirstDirection(p1) == SkPathFirstDirection::kUnknown);
}
{
@ -3315,7 +3312,7 @@ static void check_for_circle(skiatest::Reporter* reporter,
tmpPath.addOval(rect, isOvalDir, isOvalStart);
REPORTER_ASSERT(reporter, path == tmpPath);
}
REPORTER_ASSERT(reporter, SkPathPriv::CheapIsFirstDirection(path, expectedDir));
REPORTER_ASSERT(reporter, SkPathPriv::ComputeFirstDirection(path) == expectedDir);
}
static void test_circle_skew(skiatest::Reporter* reporter,
@ -3613,7 +3610,8 @@ static void test_empty(skiatest::Reporter* reporter, const SkPath& p) {
static void test_rrect_is_convex(skiatest::Reporter* reporter, SkPath* path,
SkPathDirection dir) {
REPORTER_ASSERT(reporter, path->isConvex());
REPORTER_ASSERT(reporter, SkPathPriv::CheapIsFirstDirection(*path, SkPathPriv::AsFirstDirection(dir)));
REPORTER_ASSERT(reporter,
SkPathPriv::ComputeFirstDirection(*path) == SkPathPriv::AsFirstDirection(dir));
SkPathPriv::ForceComputeConvexity(*path);
REPORTER_ASSERT(reporter, path->isConvex());
path->reset();
@ -3622,7 +3620,8 @@ static void test_rrect_is_convex(skiatest::Reporter* reporter, SkPath* path,
static void test_rrect_convexity_is_unknown(skiatest::Reporter* reporter, SkPath* path,
SkPathDirection dir) {
REPORTER_ASSERT(reporter, path->isConvex());
REPORTER_ASSERT(reporter, SkPathPriv::CheapIsFirstDirection(*path, SkPathPriv::AsFirstDirection(dir)));
REPORTER_ASSERT(reporter,
SkPathPriv::ComputeFirstDirection(*path) == SkPathPriv::AsFirstDirection(dir));
SkPathPriv::ForceComputeConvexity(*path);
REPORTER_ASSERT(reporter, !path->isConvex());
path->reset();
@ -3725,7 +3724,7 @@ static void test_arc(skiatest::Reporter* reporter) {
// TODO: one way to keep it concave would be to introduce interpolated on curve points
// between control points and computing the on curve point at scan conversion time
REPORTER_ASSERT(reporter, p.isConvex());
REPORTER_ASSERT(reporter, SkPathPriv::CheapIsFirstDirection(p, SkPathFirstDirection::kCW));
REPORTER_ASSERT(reporter, SkPathPriv::ComputeFirstDirection(p) == SkPathFirstDirection::kCW);
SkPathPriv::ForceComputeConvexity(p);
REPORTER_ASSERT(reporter, p.isConvex());
}