serious SkEdgeBuilder refactoring
This splits the three logical types of SkEdgeBuilders
into distinct C++ types, with some shared logic.
Looks like this cuts another 10K off Flutter,
including that 8K table.
Change-Id: I0c901de8b0bb70b9a9dce07683110177a287b0ee
Reviewed-on: https://skia-review.googlesource.com/c/164626
Commit-Queue: Mike Reed <reed@google.com>
Auto-Submit: Mike Klein <mtklein@google.com>
Reviewed-by: Mike Reed <reed@google.com>
diff --git a/src/core/SkEdgeBuilder.cpp b/src/core/SkEdgeBuilder.cpp
index a3d27da..c1a0235 100644
--- a/src/core/SkEdgeBuilder.cpp
+++ b/src/core/SkEdgeBuilder.cpp
@@ -5,10 +5,9 @@
* found in the LICENSE file.
*/
-#include "SkEdgeBuilder.h"
-
#include "SkAnalyticEdge.h"
#include "SkEdge.h"
+#include "SkEdgeBuilder.h"
#include "SkEdgeClipper.h"
#include "SkGeometry.h"
#include "SkLineClipper.h"
@@ -17,15 +16,7 @@
#include "SkSafeMath.h"
#include "SkTo.h"
-///////////////////////////////////////////////////////////////////////////////
-
-SkEdgeBuilder::SkEdgeBuilder(EdgeType type, int shiftEdgesUp)
- : fEdgeList(nullptr)
- , fEdgeType(type)
- , fShiftUp(shiftEdgesUp)
- , fIsFinite(true) {}
-
-SkEdgeBuilder::Combine SkEdgeBuilder::combineVertical(const SkEdge* edge, SkEdge* last) {
+SkEdgeBuilder::Combine SkBasicEdgeBuilder::combineVertical(const SkEdge* edge, SkEdge* last) {
if (last->fCurveCount || last->fDX || edge->fX != last->fX) {
return kNo_Combine;
}
@@ -66,13 +57,12 @@
return kNo_Combine;
}
-static inline bool approximately_equal(SkFixed a, SkFixed b) {
- return SkAbs32(a - b) < 0x100;
-}
+SkEdgeBuilder::Combine SkAnalyticEdgeBuilder::combineVertical(const SkAnalyticEdge* edge,
+ SkAnalyticEdge* last) {
+ auto approximately_equal = [](SkFixed a, SkFixed b) {
+ return SkAbs32(a - b) < 0x100;
+ };
-SkEdgeBuilder::Combine SkEdgeBuilder::combineVertical(
- const SkAnalyticEdge* edge, SkAnalyticEdge* last) {
- SkASSERT(fEdgeType == kAnalyticEdge);
if (last->fCurveCount || last->fDX || edge->fX != last->fX) {
return kNo_Combine;
}
@@ -117,180 +107,152 @@
return kNo_Combine;
}
-bool SkEdgeBuilder::verticalLine(const SkEdge* edge) {
- return !edge->fDX && !edge->fCurveCount;
+template <typename Edge>
+static bool is_vertical(const Edge* edge) {
+ return edge->fDX == 0
+ && edge->fCurveCount == 0;
}
-bool SkEdgeBuilder::verticalLine(const SkAnalyticEdge* edge) {
- SkASSERT(fEdgeType == kAnalyticEdge);
- return !edge->fDX && !edge->fCurveCount;
-}
+// TODO: we can deallocate the edge if edge->setFoo() fails
+// or when we don't use it (kPartial_Combine or kTotal_Combine).
-void SkEdgeBuilder::addLine(const SkPoint pts[]) {
- if (fEdgeType == kBezier) {
- SkLine* line = fAlloc.make<SkLine>();
- if (line->set(pts)) {
- fList.push_back(line);
- }
- } else if (fEdgeType == kAnalyticEdge) {
- SkAnalyticEdge* edge = fAlloc.make<SkAnalyticEdge>();
- if (edge->setLine(pts[0], pts[1])) {
- if (this->verticalLine(edge) && fList.count()) {
- Combine combine = this->combineVertical(edge, (SkAnalyticEdge*)*(fList.end() - 1));
- if (kNo_Combine != combine) {
- if (kTotal_Combine == combine) {
- fList.pop();
- }
- goto unallocate_analytic_edge;
- }
- }
- fList.push_back(edge);
- } else {
-unallocate_analytic_edge:
- ;
- // TODO: unallocate edge from storage...
- }
- } else {
- SkEdge* edge = fAlloc.make<SkEdge>();
- if (edge->setLine(pts[0], pts[1], fShiftUp)) {
- if (this->verticalLine(edge) && fList.count()) {
- Combine combine = this->combineVertical(edge, (SkEdge*)*(fList.end() - 1));
- if (kNo_Combine != combine) {
- if (kTotal_Combine == combine) {
- fList.pop();
- }
- goto unallocate_edge;
- }
- }
- fList.push_back(edge);
- } else {
-unallocate_edge:
- ;
- // TODO: unallocate edge from storage...
+void SkBasicEdgeBuilder::addLine(const SkPoint pts[]) {
+ SkEdge* edge = fAlloc.make<SkEdge>();
+ if (edge->setLine(pts[0], pts[1], fClipShift)) {
+ Combine combine = is_vertical(edge) && !fList.empty()
+ ? this->combineVertical(edge, (SkEdge*)fList.top())
+ : kNo_Combine;
+
+ switch (combine) {
+ case kTotal_Combine: fList.pop(); break;
+ case kPartial_Combine: break;
+ case kNo_Combine: fList.push_back(edge); break;
}
}
}
-void SkEdgeBuilder::addPolyLine(SkPoint pts[],
- char* &edge,
- size_t edgeSize,
- char** &edgePtr) {
- if (fEdgeType == kBezier) {
- if (((SkLine*)edge)->set(pts)) {
- *edgePtr++ = edge;
- edge += edgeSize;
- }
- return;
- }
- bool analyticAA = fEdgeType == kAnalyticEdge;
- bool setLineResult = analyticAA ?
- ((SkAnalyticEdge*)edge)->setLine(pts[0], pts[1]) :
- ((SkEdge*)edge)->setLine(pts[0], pts[1], fShiftUp);
- if (setLineResult) {
- Combine combine = analyticAA ?
- checkVertical((SkAnalyticEdge*)edge, (SkAnalyticEdge**)edgePtr) :
- checkVertical((SkEdge*)edge, (SkEdge**)edgePtr);
- if (kNo_Combine == combine) {
- *edgePtr++ = edge;
- edge += edgeSize;
- } else if (kTotal_Combine == combine) {
- --edgePtr;
+void SkAnalyticEdgeBuilder::addLine(const SkPoint pts[]) {
+ SkAnalyticEdge* edge = fAlloc.make<SkAnalyticEdge>();
+ if (edge->setLine(pts[0], pts[1])) {
+
+ Combine combine = is_vertical(edge) && !fList.empty()
+ ? this->combineVertical(edge, (SkAnalyticEdge*)fList.top())
+ : kNo_Combine;
+
+ switch (combine) {
+ case kTotal_Combine: fList.pop(); break;
+ case kPartial_Combine: break;
+ case kNo_Combine: fList.push_back(edge); break;
}
}
}
-
-void SkEdgeBuilder::addQuad(const SkPoint pts[]) {
- if (fEdgeType == kBezier) {
- SkQuad* quad = fAlloc.make<SkQuad>();
- if (quad->set(pts)) {
- fList.push_back(quad);
- }
- } else if (fEdgeType == kAnalyticEdge) {
- SkAnalyticQuadraticEdge* edge = fAlloc.make<SkAnalyticQuadraticEdge>();
- if (edge->setQuadratic(pts)) {
- fList.push_back(edge);
- } else {
- // TODO: unallocate edge from storage...
- }
- } else {
- SkQuadraticEdge* edge = fAlloc.make<SkQuadraticEdge>();
- if (edge->setQuadratic(pts, fShiftUp)) {
- fList.push_back(edge);
- } else {
- // TODO: unallocate edge from storage...
- }
+void SkBezierEdgeBuilder::addLine(const SkPoint pts[]) {
+ SkLine* line = fAlloc.make<SkLine>();
+ if (line->set(pts)) {
+ fList.push_back(line);
}
}
-void SkEdgeBuilder::addCubic(const SkPoint pts[]) {
- if (fEdgeType == kBezier) {
- SkCubic* cubic = fAlloc.make<SkCubic>();
- if (cubic->set(pts)) {
- fList.push_back(cubic);
- }
- } else if (fEdgeType == kAnalyticEdge) {
- SkAnalyticCubicEdge* edge = fAlloc.make<SkAnalyticCubicEdge>();
- if (edge->setCubic(pts)) {
- fList.push_back(edge);
- } else {
- // TODO: unallocate edge from storage...
- }
- } else {
- SkCubicEdge* edge = fAlloc.make<SkCubicEdge>();
- if (edge->setCubic(pts, fShiftUp)) {
- fList.push_back(edge);
- } else {
- // TODO: unallocate edge from storage...
- }
+void SkBasicEdgeBuilder::addQuad(const SkPoint pts[]) {
+ SkQuadraticEdge* edge = fAlloc.make<SkQuadraticEdge>();
+ if (edge->setQuadratic(pts, fClipShift)) {
+ fList.push_back(edge);
+ }
+}
+void SkAnalyticEdgeBuilder::addQuad(const SkPoint pts[]) {
+ SkAnalyticQuadraticEdge* edge = fAlloc.make<SkAnalyticQuadraticEdge>();
+ if (edge->setQuadratic(pts)) {
+ fList.push_back(edge);
+ }
+}
+void SkBezierEdgeBuilder::addQuad(const SkPoint pts[]) {
+ SkQuad* quad = fAlloc.make<SkQuad>();
+ if (quad->set(pts)) {
+ fList.push_back(quad);
}
}
-void SkEdgeBuilder::addClipper(SkEdgeClipper* clipper) {
- SkPoint pts[4];
- SkPath::Verb verb;
-
- while ((verb = clipper->next(pts)) != SkPath::kDone_Verb) {
- const int count = SkPathPriv::PtsInIter(verb);
- if (!SkScalarsAreFinite(&pts[0].fX, count*2)) {
- fIsFinite = false;
- return;
- }
- switch (verb) {
- case SkPath::kLine_Verb:
- this->addLine(pts);
- break;
- case SkPath::kQuad_Verb:
- this->addQuad(pts);
- break;
- case SkPath::kCubic_Verb:
- this->addCubic(pts);
- break;
- default:
- break;
- }
+void SkBasicEdgeBuilder::addCubic(const SkPoint pts[]) {
+ SkCubicEdge* edge = fAlloc.make<SkCubicEdge>();
+ if (edge->setCubic(pts, fClipShift)) {
+ fList.push_back(edge);
+ }
+}
+void SkAnalyticEdgeBuilder::addCubic(const SkPoint pts[]) {
+ SkAnalyticCubicEdge* edge = fAlloc.make<SkAnalyticCubicEdge>();
+ if (edge->setCubic(pts)) {
+ fList.push_back(edge);
+ }
+}
+void SkBezierEdgeBuilder::addCubic(const SkPoint pts[]) {
+ SkCubic* cubic = fAlloc.make<SkCubic>();
+ if (cubic->set(pts)) {
+ fList.push_back(cubic);
}
}
-///////////////////////////////////////////////////////////////////////////////
+// TODO: merge addLine() and addPolyLine()?
-static void set_shifted_clip(SkRect* dst, const SkIRect& src, int shift) {
- dst->set(SkIntToScalar(src.fLeft >> shift),
- SkIntToScalar(src.fTop >> shift),
- SkIntToScalar(src.fRight >> shift),
- SkIntToScalar(src.fBottom >> shift));
+SkEdgeBuilder::Combine SkBasicEdgeBuilder::addPolyLine(SkPoint pts[],
+ char* arg_edge, char** arg_edgePtr) {
+ auto edge = (SkEdge*) arg_edge;
+ auto edgePtr = (SkEdge**)arg_edgePtr;
+
+ if (edge->setLine(pts[0], pts[1], fClipShift)) {
+ return is_vertical(edge) && edgePtr > (SkEdge**)fEdgeList
+ ? this->combineVertical(edge, edgePtr[-1])
+ : kNo_Combine;
+ }
+ return SkEdgeBuilder::kPartial_Combine; // A convenient lie. Same do-nothing behavior.
+}
+SkEdgeBuilder::Combine SkAnalyticEdgeBuilder::addPolyLine(SkPoint pts[],
+ char* arg_edge, char** arg_edgePtr) {
+ auto edge = (SkAnalyticEdge*) arg_edge;
+ auto edgePtr = (SkAnalyticEdge**)arg_edgePtr;
+
+ if (edge->setLine(pts[0], pts[1])) {
+ return is_vertical(edge) && edgePtr > (SkAnalyticEdge**)fEdgeList
+ ? this->combineVertical(edge, edgePtr[-1])
+ : kNo_Combine;
+ }
+ return SkEdgeBuilder::kPartial_Combine; // As above.
+}
+SkEdgeBuilder::Combine SkBezierEdgeBuilder::addPolyLine(SkPoint pts[],
+ char* arg_edge, char** arg_edgePtr) {
+ auto edge = (SkLine*)arg_edge;
+
+ if (edge->set(pts)) {
+ return kNo_Combine;
+ }
+ return SkEdgeBuilder::kPartial_Combine; // As above.
}
-SkEdgeBuilder::Combine SkEdgeBuilder::checkVertical(const SkEdge* edge, SkEdge** edgePtr) {
- return !this->verticalLine(edge) || edgePtr <= (SkEdge**)fEdgeList ? kNo_Combine :
- this->combineVertical(edge, edgePtr[-1]);
+SkRect SkBasicEdgeBuilder::recoverClip(const SkIRect& src) const {
+ return { SkIntToScalar(src.fLeft >> fClipShift),
+ SkIntToScalar(src.fTop >> fClipShift),
+ SkIntToScalar(src.fRight >> fClipShift),
+ SkIntToScalar(src.fBottom >> fClipShift), };
+}
+SkRect SkAnalyticEdgeBuilder::recoverClip(const SkIRect& src) const {
+ return SkRect::Make(src);
+}
+SkRect SkBezierEdgeBuilder::recoverClip(const SkIRect& src) const {
+ return SkRect::Make(src);
}
-SkEdgeBuilder::Combine SkEdgeBuilder::checkVertical(const SkAnalyticEdge* edge,
- SkAnalyticEdge** edgePtr) {
- SkASSERT(fEdgeType == kAnalyticEdge);
- return !this->verticalLine(edge) || edgePtr <= (SkAnalyticEdge**)fEdgeList ? kNo_Combine :
- this->combineVertical(edge, edgePtr[-1]);
+char* SkBasicEdgeBuilder::allocEdges(size_t n, size_t* size) {
+ *size = sizeof(SkEdge);
+ return (char*)fAlloc.makeArrayDefault<SkEdge>(n);
+}
+char* SkAnalyticEdgeBuilder::allocEdges(size_t n, size_t* size) {
+ *size = sizeof(SkAnalyticEdge);
+ return (char*)fAlloc.makeArrayDefault<SkAnalyticEdge>(n);
+}
+char* SkBezierEdgeBuilder::allocEdges(size_t n, size_t* size) {
+ *size = sizeof(SkLine);
+ return (char*)fAlloc.makeArrayDefault<SkLine>(n);
}
+// TODO: maybe get rid of buildPoly() entirely?
int SkEdgeBuilder::buildPoly(const SkPath& path, const SkIRect* iclip, bool canCullToTheRight) {
SkPath::Iter iter(path, true);
SkPoint pts[4];
@@ -309,29 +271,14 @@
}
size_t edgeSize;
- char* edge;
- switch (fEdgeType) {
- case kEdge:
- edgeSize = sizeof(SkEdge);
- edge = (char*)fAlloc.makeArrayDefault<SkEdge>(maxEdgeCount);
- break;
- case kAnalyticEdge:
- edgeSize = sizeof(SkAnalyticEdge);
- edge = (char*)fAlloc.makeArrayDefault<SkAnalyticEdge>(maxEdgeCount);
- break;
- case kBezier:
- edgeSize = sizeof(SkLine);
- edge = (char*)fAlloc.makeArrayDefault<SkLine>(maxEdgeCount);
- break;
- }
+ char* edge = this->allocEdges(maxEdgeCount, &edgeSize);
SkDEBUGCODE(char* edgeStart = edge);
char** edgePtr = fAlloc.makeArrayDefault<char*>(maxEdgeCount);
fEdgeList = (void**)edgePtr;
if (iclip) {
- SkRect clip;
- set_shifted_clip(&clip, *iclip, fShiftUp);
+ SkRect clip = this->recoverClip(*iclip);
while ((verb = iter.next(pts, false)) != SkPath::kDone_Verb) {
switch (verb) {
@@ -345,7 +292,12 @@
int lineCount = SkLineClipper::ClipLine(pts, clip, lines, canCullToTheRight);
SkASSERT(lineCount <= SkLineClipper::kMaxClippedLineSegments);
for (int i = 0; i < lineCount; i++) {
- this->addPolyLine(lines + i, edge, edgeSize, edgePtr);
+ switch( this->addPolyLine(lines + i, edge, edgePtr) ) {
+ case kTotal_Combine: edgePtr--; break;
+ case kPartial_Combine: break;
+ case kNo_Combine: *edgePtr++ = edge;
+ edge += edgeSize;
+ }
}
break;
}
@@ -363,7 +315,12 @@
// the corresponding line/quad/cubic verbs
break;
case SkPath::kLine_Verb: {
- this->addPolyLine(pts, edge, edgeSize, edgePtr);
+ switch( this->addPolyLine(pts, edge, edgePtr) ) {
+ case kTotal_Combine: edgePtr--; break;
+ case kPartial_Combine: break;
+ case kNo_Combine: *edgePtr++ = edge;
+ edge += edgeSize;
+ }
break;
}
default:
@@ -374,17 +331,10 @@
}
SkASSERT((size_t)(edge - edgeStart) <= maxEdgeCount * edgeSize);
SkASSERT((size_t)(edgePtr - (char**)fEdgeList) <= maxEdgeCount);
- return fIsFinite ? SkToInt(edgePtr - (char**)fEdgeList) : 0;
+ return SkToInt(edgePtr - (char**)fEdgeList);
}
int SkEdgeBuilder::build(const SkPath& path, const SkIRect* iclip, bool canCullToTheRight) {
- fAlloc.reset();
- fList.reset();
-
- if (SkPath::kLine_SegmentMask == path.getSegmentMasks()) {
- return this->buildPoly(path, iclip, canCullToTheRight);
- }
-
SkAutoConicToQuads quadder;
const SkScalar conicTol = SK_Scalar1 / 4;
@@ -392,11 +342,31 @@
SkPoint pts[4];
SkPath::Verb verb;
+ bool is_finite = true;
+
if (iclip) {
- SkRect clip;
- set_shifted_clip(&clip, *iclip, fShiftUp);
+ SkRect clip = this->recoverClip(*iclip);
SkEdgeClipper clipper(canCullToTheRight);
+ auto apply_clipper = [this, &clipper, &is_finite] {
+ SkPoint pts[4];
+ SkPath::Verb verb;
+
+ while ((verb = clipper.next(pts)) != SkPath::kDone_Verb) {
+ const int count = SkPathPriv::PtsInIter(verb);
+ if (!SkScalarsAreFinite(&pts[0].fX, count*2)) {
+ is_finite = false;
+ return;
+ }
+ switch (verb) {
+ case SkPath::kLine_Verb: this->addLine (pts); break;
+ case SkPath::kQuad_Verb: this->addQuad (pts); break;
+ case SkPath::kCubic_Verb: this->addCubic(pts); break;
+ default: break;
+ }
+ }
+ };
+
while ((verb = iter.next(pts, false)) != SkPath::kDone_Verb) {
switch (verb) {
case SkPath::kMove_Verb:
@@ -406,12 +376,12 @@
break;
case SkPath::kLine_Verb:
if (clipper.clipLine(pts[0], pts[1], clip)) {
- this->addClipper(&clipper);
+ apply_clipper();
}
break;
case SkPath::kQuad_Verb:
if (clipper.clipQuad(pts, clip)) {
- this->addClipper(&clipper);
+ apply_clipper();
}
break;
case SkPath::kConic_Verb: {
@@ -419,14 +389,14 @@
pts, iter.conicWeight(), conicTol);
for (int i = 0; i < quadder.countQuads(); ++i) {
if (clipper.clipQuad(quadPts, clip)) {
- this->addClipper(&clipper);
+ apply_clipper();
}
quadPts += 2;
}
} break;
case SkPath::kCubic_Verb:
if (clipper.clipCubic(pts, clip)) {
- this->addClipper(&clipper);
+ apply_clipper();
}
break;
default:
@@ -466,7 +436,7 @@
}
} break;
case SkPath::kCubic_Verb: {
- if (fEdgeType == kBezier) {
+ if (!this->chopCubics()) {
this->addCubic(pts);
break;
}
@@ -484,23 +454,28 @@
}
}
fEdgeList = fList.begin();
- return fIsFinite ? fList.count() : 0;
+ return is_finite ? fList.count() : 0;
}
int SkEdgeBuilder::buildEdges(const SkPath& path,
- const SkIRect* shiftedClip,
- bool pathContainedInClip) {
- // If we're convex, then we need both edges, even the right edge is past the clip
+ const SkIRect* shiftedClip) {
+ // If we're convex, then we need both edges, even if the right edge is past the clip.
const bool canCullToTheRight = !path.isConvex();
- const SkIRect* builderClip = pathContainedInClip ? nullptr : shiftedClip;
- int count = this->build(path, builderClip, canCullToTheRight);
+ // We can use our buildPoly() optimization if all the segments are lines.
+ // (Edges are homogenous and stored contiguously in memory, no need for indirection.)
+ const int count = SkPath::kLine_SegmentMask == path.getSegmentMasks()
+ ? this->buildPoly(path, shiftedClip, canCullToTheRight)
+ : this->build (path, shiftedClip, canCullToTheRight);
+
SkASSERT(count >= 0);
- // canCullToRight == false should imply count != 1 if fEdgeType != kBezier.
- // If fEdgeType == kBezier (DAA), we don't chop edges at y extrema so count == 1 is valid.
+ // If we can't cull to the right, we should have count > 1 (or 0),
+ // unless we're in DAA which doesn't need to chop edges at y extrema.
// For example, a single cubic edge with a valley shape \_/ is fine for DAA.
- SkASSERT(fEdgeType == kBezier || canCullToTheRight || count != 1);
+ if (!canCullToTheRight && count == 1) {
+ SkASSERT(!this->chopCubics());
+ }
- return fIsFinite ? count : 0;
+ return count;
}
diff --git a/src/core/SkEdgeBuilder.h b/src/core/SkEdgeBuilder.h
index 3795138..cf662d5 100644
--- a/src/core/SkEdgeBuilder.h
+++ b/src/core/SkEdgeBuilder.h
@@ -7,80 +7,104 @@
#ifndef SkEdgeBuilder_DEFINED
#define SkEdgeBuilder_DEFINED
+#include "SkAnalyticEdge.h"
#include "SkArenaAlloc.h"
+#include "SkEdge.h"
#include "SkRect.h"
#include "SkTDArray.h"
-#include "SkEdge.h"
-#include "SkAnalyticEdge.h"
-struct SkEdge;
-struct SkAnalyticEdge;
-class SkEdgeClipper;
class SkPath;
class SkEdgeBuilder {
public:
- enum EdgeType {
- // Used in supersampling or non-AA scan coverter; it stores only integral y coordinates.
- kEdge,
-
- // Used in Analytic AA scan converter; it uses SkFixed to store fractional y.
- kAnalyticEdge,
-
- // Used in Delta AA scan converter; it's a super-light wrapper of SkPoint, which can then be
- // used to construct SkAnalyticEdge (kAnalyticEdge) later. We use kBezier to save the memory
- // allocation time (a SkBezier is much lighter than SkAnalyticEdge or SkEdge). Note that
- // Delta AA only has to deal with one SkAnalyticEdge at a time (whereas Analytic AA has to
- // deal with all SkAnalyticEdges at the same time). Thus for Delta AA, we only need to
- // allocate memory for n SkBeziers and 1 SkAnalyticEdge. (Analytic AA need to allocate
- // memory for n SkAnalyticEdges.)
- kBezier
- };
-
- SkEdgeBuilder(EdgeType, int shiftEdgesUp);
-
int buildEdges(const SkPath& path,
- const SkIRect* shiftedClip,
- bool pathContainedInClip);
+ const SkIRect* shiftedClip);
- SkEdge** edgeList() { return (SkEdge**)fEdgeList; }
- SkAnalyticEdge** analyticEdgeList() { return (SkAnalyticEdge**)fEdgeList; }
- SkBezier** bezierList() { return (SkBezier**)fEdgeList; }
+protected:
+ SkEdgeBuilder() = default;
+ virtual ~SkEdgeBuilder() = default;
-private:
+ // In general mode we allocate pointers in fList and fEdgeList points to its head.
+ // In polygon mode we preallocated edges contiguously in fAlloc and fEdgeList points there.
+ void** fEdgeList = nullptr;
+ SkTDArray<void*> fList;
+ SkSTArenaAlloc<512> fAlloc;
+
enum Combine {
kNo_Combine,
kPartial_Combine,
kTotal_Combine
};
+private:
int build (const SkPath& path, const SkIRect* clip, bool clipToTheRight);
int buildPoly(const SkPath& path, const SkIRect* clip, bool clipToTheRight);
+ virtual char* allocEdges(size_t n, size_t* sizeof_edge) = 0;
+ virtual SkRect recoverClip(const SkIRect&) const = 0;
+ virtual bool chopCubics() const = 0;
+
+ virtual void addLine (const SkPoint pts[]) = 0;
+ virtual void addQuad (const SkPoint pts[]) = 0;
+ virtual void addCubic(const SkPoint pts[]) = 0;
+ virtual Combine addPolyLine(SkPoint pts[], char* edge, char** edgePtr) = 0;
+};
+
+class SkBasicEdgeBuilder final : public SkEdgeBuilder {
+public:
+ explicit SkBasicEdgeBuilder(int clipShift) : fClipShift(clipShift) {}
+
+ SkEdge** edgeList() { return (SkEdge**)fEdgeList; }
+
+private:
Combine combineVertical(const SkEdge* edge, SkEdge* last);
- Combine checkVertical(const SkEdge* edge, SkEdge** edgePtr);
- bool verticalLine(const SkEdge* edge);
+ char* allocEdges(size_t, size_t*) override;
+ SkRect recoverClip(const SkIRect&) const override;
+ bool chopCubics() const override { return true; }
+
+ void addLine (const SkPoint pts[]) override;
+ void addQuad (const SkPoint pts[]) override;
+ void addCubic(const SkPoint pts[]) override;
+ Combine addPolyLine(SkPoint pts[], char* edge, char** edgePtr) override;
+
+ const int fClipShift;
+};
+
+class SkAnalyticEdgeBuilder final : public SkEdgeBuilder {
+public:
+ SkAnalyticEdgeBuilder() {}
+
+ SkAnalyticEdge** analyticEdgeList() { return (SkAnalyticEdge**)fEdgeList; }
+
+private:
Combine combineVertical(const SkAnalyticEdge* edge, SkAnalyticEdge* last);
- Combine checkVertical(const SkAnalyticEdge* edge, SkAnalyticEdge** edgePtr);
- bool verticalLine(const SkAnalyticEdge* edge);
- void addLine(const SkPoint pts[]);
- void addQuad(const SkPoint pts[]);
- void addCubic(const SkPoint pts[]);
- void addClipper(SkEdgeClipper*);
- void addPolyLine(SkPoint pts[], char* &edge, size_t edgeSize, char** &edgePtr);
+ char* allocEdges(size_t, size_t*) override;
+ SkRect recoverClip(const SkIRect&) const override;
+ bool chopCubics() const override { return true; }
+ void addLine (const SkPoint pts[]) override;
+ void addQuad (const SkPoint pts[]) override;
+ void addCubic(const SkPoint pts[]) override;
+ Combine addPolyLine(SkPoint pts[], char* edge, char** edgePtr) override;
+};
- // In general mode we allocate pointers in fList and this points to its head.
- // In polygon mode we preallocated pointers in fAlloc and this points there.
- void** fEdgeList;
- SkSTArenaAlloc<512> fAlloc;
- SkTDArray<void*> fList;
+class SkBezierEdgeBuilder final : public SkEdgeBuilder {
+public:
+ SkBezierEdgeBuilder() {}
- const EdgeType fEdgeType;
- const int fShiftUp;
- bool fIsFinite;
+ SkBezier** bezierList() { return (SkBezier**)fEdgeList; }
+
+private:
+ char* allocEdges(size_t, size_t*) override;
+ SkRect recoverClip(const SkIRect&) const override;
+ bool chopCubics() const override { return false; }
+
+ void addLine (const SkPoint pts[]) override;
+ void addQuad (const SkPoint pts[]) override;
+ void addCubic(const SkPoint pts[]) override;
+ Combine addPolyLine(SkPoint pts[], char* edge, char** edgePtr) override;
};
#endif
diff --git a/src/core/SkScan_AAAPath.cpp b/src/core/SkScan_AAAPath.cpp
index ee0ec60..4f98073 100644
--- a/src/core/SkScan_AAAPath.cpp
+++ b/src/core/SkScan_AAAPath.cpp
@@ -1594,8 +1594,8 @@
bool isUsingMask, bool forceRLE) { // forceRLE implies that SkAAClip is calling us
SkASSERT(blitter);
- SkEdgeBuilder builder(SkEdgeBuilder::kAnalyticEdge, 0);
- int count = builder.buildEdges(path, &clipRect, pathContainedInClip);
+ SkAnalyticEdgeBuilder builder;
+ int count = builder.buildEdges(path, pathContainedInClip ? nullptr : &clipRect);
SkAnalyticEdge** list = builder.analyticEdgeList();
SkIRect rect = clipRect;
diff --git a/src/core/SkScan_DAAPath.cpp b/src/core/SkScan_DAAPath.cpp
index b3bbd97..53da58a 100644
--- a/src/core/SkScan_DAAPath.cpp
+++ b/src/core/SkScan_DAAPath.cpp
@@ -160,10 +160,10 @@
void gen_alpha_deltas(const SkPath& path, const SkIRect& clippedIR, const SkIRect& clipBounds,
Deltas& result, SkBlitter* blitter, bool skipRect, bool pathContainedInClip) {
// 1. Build edges
- SkEdgeBuilder builder(SkEdgeBuilder::kBezier, 0);
+ SkBezierEdgeBuilder builder;
// We have to use clipBounds instead of clippedIR to build edges because of "canCullToTheRight":
// if the builder finds a right edge past the right clip, it won't build that right edge.
- int count = builder.buildEdges(path, &clipBounds, pathContainedInClip);
+ int count = builder.buildEdges(path, pathContainedInClip ? nullptr : &clipBounds);
if (count == 0) {
return;
diff --git a/src/core/SkScan_Path.cpp b/src/core/SkScan_Path.cpp
index acac0c0..f14559a 100644
--- a/src/core/SkScan_Path.cpp
+++ b/src/core/SkScan_Path.cpp
@@ -406,8 +406,8 @@
shiftedClip.fTop = SkLeftShift(shiftedClip.fTop, shiftEdgesUp);
shiftedClip.fBottom = SkLeftShift(shiftedClip.fBottom, shiftEdgesUp);
- SkEdgeBuilder builder(SkEdgeBuilder::kEdge, shiftEdgesUp);
- int count = builder.buildEdges(path, &shiftedClip, pathContainedInClip);
+ SkBasicEdgeBuilder builder(shiftEdgesUp);
+ int count = builder.buildEdges(path, pathContainedInClip ? nullptr : &shiftedClip);
SkEdge** list = builder.edgeList();
if (0 == count) {