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 <reed@google.com>
Commit-Queue: Mike Reed <reed@google.com>
This commit is contained in:
Mike Reed 2020-07-02 09:14:20 -04:00 committed by Skia Commit-Bot
parent ad0b2b8dd1
commit 92c33f329a
6 changed files with 101 additions and 84 deletions

View File

@ -188,7 +188,7 @@ protected:
case MakeType::kArray: { case MakeType::kArray: {
// ArrayPath<N*12> arrays; // ArrayPath<N*12> arrays;
// run_builder(arrays, false, N); // run_builder(arrays, false, N);
return SkPathBuilder::Make(fArrays.fPts, fArrays.fPIndex, return SkPath::Make(fArrays.fPts, fArrays.fPIndex,
fArrays.fVbs, fArrays.fVIndex, fArrays.fVbs, fArrays.fVIndex,
nullptr, 0, SkPathFillType::kWinding); nullptr, 0, SkPathFillType::kWinding);
} }

View File

@ -40,6 +40,29 @@ class SkWStream;
*/ */
class SK_API SkPath { class SK_API SkPath {
public: 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. /** Constructs an empty SkPath. By default, SkPath has no verbs, no SkPoint, and no weights.
FillType is set to kWinding. FillType is set to kWinding.

View File

@ -71,11 +71,6 @@ public:
this->incReserve(extraPtCount, extraPtCount); 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: private:
SkTDArray<SkPoint> fPts; SkTDArray<SkPoint> fPts;
SkTDArray<uint8_t> fVerbs; SkTDArray<uint8_t> fVerbs;

View File

@ -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<SkPathRef>(new SkPathRef(SkTDArray<SkPoint>(pts, info.points),
SkTDArray<uint8_t>(vbs, verbCount),
SkTDArray<SkScalar>(ws, info.weights),
info.segmentMask)),
ft, isVolatile);
}
//////////////////////////////////////////////////////////////////////////////////////////////////
bool SkPathPriv::IsRectContour(const SkPath& path, bool allowPartial, int* currVerb, bool SkPathPriv::IsRectContour(const SkPath& path, bool allowPartial, int* currVerb,
const SkPoint** ptsPtr, bool* isClosed, SkPathDirection* direction, const SkPoint** ptsPtr, bool* isClosed, SkPathDirection* direction,
SkRect* rect) { SkRect* rect) {

View File

@ -281,78 +281,3 @@ SkPathBuilder& SkPathBuilder::addRRect(const SkRRect& rrect, SkPathDirection dir
} }
return *this; 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<SkPathRef>(new SkPathRef(SkTDArray<SkPoint>(pts, info.points),
SkTDArray<uint8_t>(vbs, verbCount),
SkTDArray<SkScalar>(ws, info.weights),
info.segmentMask)),
ft, isVolatile);
}

View File

@ -163,6 +163,6 @@ DEF_TEST(pathbuilder_make, reporter) {
pts[i] = {x, y}; vbs[i] = (uint8_t)SkPathVerb::kLine; pts[i] = {x, y}; vbs[i] = (uint8_t)SkPathVerb::kLine;
} }
auto p0 = b.detach(); 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); REPORTER_ASSERT(reporter, p0 == p1);
} }