From 92c33f329a56057dd0a4afa5e1336203e7ac3073 Mon Sep 17 00:00:00 2001 From: Mike Reed Date: Thu, 2 Jul 2020 09:14:20 -0400 Subject: [PATCH] document Make for paths, and move from pathbuilder into path Change-Id: I812b5315e06e38ec2c812c76634fe07227a30b39 Reviewed-on: https://skia-review.googlesource.com/c/skia/+/300356 Reviewed-by: Mike Reed Commit-Queue: Mike Reed --- bench/PathOpsBench.cpp | 6 +-- include/core/SkPath.h | 23 +++++++++++ include/core/SkPathBuilder.h | 5 --- src/core/SkPath.cpp | 74 +++++++++++++++++++++++++++++++++++ src/core/SkPathBuilder.cpp | 75 ------------------------------------ tests/PathBuilderTest.cpp | 2 +- 6 files changed, 101 insertions(+), 84 deletions(-) diff --git a/bench/PathOpsBench.cpp b/bench/PathOpsBench.cpp index 9d86c2b898..b683ad17be 100644 --- a/bench/PathOpsBench.cpp +++ b/bench/PathOpsBench.cpp @@ -188,9 +188,9 @@ protected: case MakeType::kArray: { // ArrayPath arrays; // run_builder(arrays, false, N); - return SkPathBuilder::Make(fArrays.fPts, fArrays.fPIndex, - fArrays.fVbs, fArrays.fVIndex, - nullptr, 0, SkPathFillType::kWinding); + return SkPath::Make(fArrays.fPts, fArrays.fPIndex, + fArrays.fVbs, fArrays.fVIndex, + nullptr, 0, SkPathFillType::kWinding); } } return SkPath(); diff --git a/include/core/SkPath.h b/include/core/SkPath.h index a2e7c34ed7..b2bf355df2 100644 --- a/include/core/SkPath.h +++ b/include/core/SkPath.h @@ -40,6 +40,29 @@ class SkWStream; */ class SK_API SkPath { public: + /** + * Create a new path with the specified segments. + * + * The points and weights arrays are read in order, based on the sequence of verbs. + * + * Move 1 point + * Line 1 point + * Quad 2 points + * Conic 2 points and 1 weight + * Cubic 3 points + * Close 0 points + * + * If an illegal sequence of verbs is encountered, or the specified number of points + * or weights is not sufficient given the verbs, an empty Path is returned. + * + * A legal sequence of verbs consists of any number of Contours. A contour always begins + * with a Move verb, followed by 0 or more segments: Line, Quad, Conic, Cubic, followed + * by an optional Close. + */ + static SkPath Make(const SkPoint[], int pointCount, + const uint8_t[], int verbCount, + const SkScalar[], int conicWeightCount, + SkPathFillType, bool isVolatile = false); /** Constructs an empty SkPath. By default, SkPath has no verbs, no SkPoint, and no weights. FillType is set to kWinding. diff --git a/include/core/SkPathBuilder.h b/include/core/SkPathBuilder.h index 3269f49e2f..6e911289aa 100644 --- a/include/core/SkPathBuilder.h +++ b/include/core/SkPathBuilder.h @@ -71,11 +71,6 @@ public: this->incReserve(extraPtCount, extraPtCount); } - static SkPath Make(const SkPoint[], int pointCount, - const uint8_t[], int verbCount, - const SkScalar[], int conicWeightCount, - SkPathFillType, bool isVolatile = false); - private: SkTDArray fPts; SkTDArray fVerbs; diff --git a/src/core/SkPath.cpp b/src/core/SkPath.cpp index 95bb11b57c..0122601937 100644 --- a/src/core/SkPath.cpp +++ b/src/core/SkPath.cpp @@ -3332,6 +3332,80 @@ bool SkPath::IsCubicDegenerate(const SkPoint& p1, const SkPoint& p2, ////////////////////////////////////////////////////////////////////////////////////////////////// +struct PathInfo { + bool valid; + int points, weights; + unsigned segmentMask; +}; + +static PathInfo validate_verbs(const uint8_t vbs[], int verbCount) { + PathInfo info = {false, 0, 0, 0}; + + bool needMove = true; + bool invalid = false; + for (int i = 0; i < verbCount; ++i) { + switch ((SkPathVerb)vbs[i]) { + case SkPathVerb::kMove: + needMove = false; + info.points += 1; + break; + case SkPathVerb::kLine: + invalid |= needMove; + info.segmentMask |= kLine_SkPathSegmentMask; + info.points += 1; + break; + case SkPathVerb::kQuad: + invalid |= needMove; + info.segmentMask |= kQuad_SkPathSegmentMask; + info.points += 2; + break; + case SkPathVerb::kConic: + invalid |= needMove; + info.segmentMask |= kConic_SkPathSegmentMask; + info.points += 2; + info.weights += 1; + break; + case SkPathVerb::kCubic: + invalid |= needMove; + info.segmentMask |= kCubic_SkPathSegmentMask; + info.points += 3; + break; + case SkPathVerb::kClose: + invalid |= needMove; + needMove = true; + break; + default: + invalid = true; + break; + } + } + info.valid = !invalid; + return info; +} + +SkPath SkPath::Make(const SkPoint pts[], int pointCount, + const uint8_t vbs[], int verbCount, + const SkScalar ws[], int wCount, + SkPathFillType ft, bool isVolatile) { + if (verbCount <= 0) { + return SkPath(); + } + + const auto info = validate_verbs(vbs, verbCount); + if (!info.valid || info.points > pointCount || info.weights > wCount) { + SkDEBUGFAIL("invalid verbs and number of points/weights"); + return SkPath(); + } + + return SkPath(sk_sp(new SkPathRef(SkTDArray(pts, info.points), + SkTDArray(vbs, verbCount), + SkTDArray(ws, info.weights), + info.segmentMask)), + ft, isVolatile); +} + +////////////////////////////////////////////////////////////////////////////////////////////////// + bool SkPathPriv::IsRectContour(const SkPath& path, bool allowPartial, int* currVerb, const SkPoint** ptsPtr, bool* isClosed, SkPathDirection* direction, SkRect* rect) { diff --git a/src/core/SkPathBuilder.cpp b/src/core/SkPathBuilder.cpp index d5b2147268..c13af425bd 100644 --- a/src/core/SkPathBuilder.cpp +++ b/src/core/SkPathBuilder.cpp @@ -281,78 +281,3 @@ SkPathBuilder& SkPathBuilder::addRRect(const SkRRect& rrect, SkPathDirection dir } return *this; } - -////////////////////////////////////////////////////////////////////////////////////////////////// - -struct PathInfo { - bool valid; - int points, weights; - unsigned segmentMask; -}; - -static PathInfo validate_verbs(const uint8_t vbs[], int verbCount) { - PathInfo info = {false, 0, 0, 0}; - - bool needMove = true; - bool invalid = false; - for (int i = 0; i < verbCount; ++i) { - switch ((SkPathVerb)vbs[i]) { - case SkPathVerb::kMove: - needMove = false; - info.points += 1; - break; - case SkPathVerb::kLine: - invalid |= needMove; - info.segmentMask |= kLine_SkPathSegmentMask; - info.points += 1; - break; - case SkPathVerb::kQuad: - invalid |= needMove; - info.segmentMask |= kQuad_SkPathSegmentMask; - info.points += 2; - break; - case SkPathVerb::kConic: - invalid |= needMove; - info.segmentMask |= kConic_SkPathSegmentMask; - info.points += 2; - info.weights += 1; - break; - case SkPathVerb::kCubic: - invalid |= needMove; - info.segmentMask |= kCubic_SkPathSegmentMask; - info.points += 3; - break; - case SkPathVerb::kClose: - invalid |= needMove; - needMove = true; - break; - default: - invalid = true; - break; - } - } - info.valid = !invalid; - return info; -} - -SkPath SkPathBuilder::Make(const SkPoint pts[], int pointCount, - const uint8_t vbs[], int verbCount, - const SkScalar ws[], int wCount, - SkPathFillType ft, bool isVolatile) { - if (verbCount <= 0) { - return SkPath(); - } - - const auto info = validate_verbs(vbs, verbCount); - if (!info.valid || info.points > pointCount || info.weights > wCount) { - SkDEBUGFAIL("invalid verbs and number of points/weights"); - return SkPath(); - } - - return SkPath(sk_sp(new SkPathRef(SkTDArray(pts, info.points), - SkTDArray(vbs, verbCount), - SkTDArray(ws, info.weights), - info.segmentMask)), - ft, isVolatile); -} - diff --git a/tests/PathBuilderTest.cpp b/tests/PathBuilderTest.cpp index cc298da772..505b564962 100644 --- a/tests/PathBuilderTest.cpp +++ b/tests/PathBuilderTest.cpp @@ -163,6 +163,6 @@ DEF_TEST(pathbuilder_make, reporter) { pts[i] = {x, y}; vbs[i] = (uint8_t)SkPathVerb::kLine; } auto p0 = b.detach(); - auto p1 = SkPathBuilder::Make(pts, N, vbs, N, nullptr, 0, p0.getFillType()); + auto p1 = SkPath::Make(pts, N, vbs, N, nullptr, 0, p0.getFillType()); REPORTER_ASSERT(reporter, p0 == p1); }