Add a fast codepath for SkPath.addPath(kAppend)
Change-Id: I49469f29cc10032d687b938ded379ef7e2f52da2
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/269190
Reviewed-by: Brian Salomon <bsalomon@google.com>
Commit-Queue: Chris Dalton <csmartdalton@google.com>
diff --git a/include/private/SkPathRef.h b/include/private/SkPathRef.h
index 4775ad0..ab476cc 100644
--- a/include/private/SkPathRef.h
+++ b/include/private/SkPathRef.h
@@ -84,6 +84,17 @@
}
/**
+ * Concatenates all verbs from 'path' onto the pathRef's verbs array. Increases the point
+ * count by the number of points in 'path', and the conic weight count by the number of
+ * conics in 'path'.
+ *
+ * Returns pointers to the uninitialized points and conic weights data.
+ */
+ std::tuple<SkPoint*, SkScalar*> growForVerbsInPath(const SkPathRef& path) {
+ return fPathRef->growForVerbsInPath(path);
+ }
+
+ /**
* Resets the path ref to a new verb and point count. The new verbs and points are
* uninitialized.
*/
@@ -417,6 +428,14 @@
SkPoint* growForVerb(int /*SkPath::Verb*/ verb, SkScalar weight);
/**
+ * Concatenates all verbs from 'path' onto our own verbs array. Increases the point count by the
+ * number of points in 'path', and the conic weight count by the number of conics in 'path'.
+ *
+ * Returns pointers to the uninitialized points and conic weights data.
+ */
+ std::tuple<SkPoint*, SkScalar*> growForVerbsInPath(const SkPathRef& path);
+
+ /**
* Private, non-const-ptr version of the public function verbsMemBegin().
*/
uint8_t* verbsBeginWritable() { return fVerbs.begin(); }
diff --git a/src/core/SkPath.cpp b/src/core/SkPath.cpp
index a6b39c2..4074d6a 100644
--- a/src/core/SkPath.cpp
+++ b/src/core/SkPath.cpp
@@ -1343,6 +1343,10 @@
}
SkPath& SkPath::addPath(const SkPath& srcPath, const SkMatrix& matrix, AddPathMode mode) {
+ if (srcPath.isEmpty()) {
+ return *this;
+ }
+
// Detect if we're trying to add ourself
const SkPath* src = &srcPath;
SkTLazy<SkPath> tmp;
@@ -1350,6 +1354,19 @@
src = tmp.set(srcPath);
}
+ if (kAppend_AddPathMode == mode && !matrix.hasPerspective()) {
+ if (src->fLastMoveToIndex >= 0) {
+ fLastMoveToIndex = this->countPoints() + src->fLastMoveToIndex;
+ }
+ SkPathRef::Editor ed(&fPathRef);
+ auto [newPts, newWeights] = ed.growForVerbsInPath(*src->fPathRef);
+ matrix.mapPoints(newPts, src->fPathRef->points(), src->countPoints());
+ if (int numWeights = src->fPathRef->countWeights()) {
+ memcpy(newWeights, src->fPathRef->conicWeights(), numWeights * sizeof(newWeights[0]));
+ }
+ return this->dirtyAfterEdit();
+ }
+
SkPathRef::Editor(&fPathRef, src->countVerbs(), src->countPoints());
RawIter iter(*src);
@@ -1362,7 +1379,8 @@
switch (verb) {
case kMove_Verb:
proc(matrix, &pts[0], &pts[0], 1);
- if (firstVerb && mode == kExtend_AddPathMode && !isEmpty()) {
+ if (firstVerb && !isEmpty()) {
+ SkASSERT(mode == kExtend_AddPathMode);
injectMoveToIfNeeded(); // In case last contour is closed
SkPoint lastPt;
// don't add lineTo if it is degenerate
diff --git a/src/core/SkPathRef.cpp b/src/core/SkPathRef.cpp
index 75086a0..f665625 100644
--- a/src/core/SkPathRef.cpp
+++ b/src/core/SkPathRef.cpp
@@ -332,6 +332,32 @@
out->fIsRRect = false;
}
+std::tuple<SkPoint*, SkScalar*> SkPathRef::growForVerbsInPath(const SkPathRef& path) {
+ SkDEBUGCODE(this->validate();)
+
+ fSegmentMask |= path.fSegmentMask;
+ fBoundsIsDirty = true; // this also invalidates fIsFinite
+ fIsOval = false;
+ fIsRRect = false;
+
+ if (int numVerbs = path.countVerbs()) {
+ memcpy(fVerbs.append(numVerbs), path.fVerbs.begin(), numVerbs * sizeof(fVerbs[0]));
+ }
+
+ SkPoint* pts = nullptr;
+ if (int numPts = path.countPoints()) {
+ pts = fPoints.append(numPts);
+ }
+
+ SkScalar* weights = nullptr;
+ if (int numConics = path.countWeights()) {
+ weights = fConicWeights.append(numConics);
+ }
+
+ SkDEBUGCODE(this->validate();)
+ return {pts, weights};
+}
+
SkPoint* SkPathRef::growForRepeatedVerb(int /*SkPath::Verb*/ verb,
int numVbs,
SkScalar** weights) {