aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--bench/PathBench.cpp6
-rw-r--r--include/core/SkGeometry.h9
-rw-r--r--include/core/SkPath.h26
-rw-r--r--include/core/SkPicture.h3
-rw-r--r--src/core/SkEdgeBuilder.cpp51
-rw-r--r--src/core/SkEdgeBuilder.h1
-rw-r--r--src/core/SkPath.cpp162
-rw-r--r--src/core/SkPathMeasure.cpp3
-rw-r--r--src/core/SkPathRef.h88
-rw-r--r--src/core/SkRegion_path.cpp17
-rw-r--r--src/effects/SkCornerPathEffect.cpp3
-rw-r--r--src/gpu/GrAAHairLinePathRenderer.cpp5
-rw-r--r--src/gpu/GrDefaultPathRenderer.cpp3
-rw-r--r--src/gpu/gl/GrGLPath.cpp10
-rw-r--r--src/pathops/SkOpAngle.cpp16
-rw-r--r--src/pathops/SkOpContour.h4
-rw-r--r--src/pathops/SkOpEdgeBuilder.cpp12
-rw-r--r--src/pathops/SkOpSegment.cpp38
-rw-r--r--src/pathops/SkOpSegment.h6
-rw-r--r--src/pathops/SkPathOpsTypes.h44
-rw-r--r--src/pathops/SkReduceOrder.cpp4
-rw-r--r--src/utils/SkDumpCanvas.cpp3
-rw-r--r--src/utils/SkParsePath.cpp5
-rw-r--r--tests/PathOpsAngleTest.cpp110
-rw-r--r--tests/PathOpsOpTest.cpp169
-rw-r--r--tests/PathOpsSimplifyTest.cpp2
-rw-r--r--tests/PathTest.cpp23
27 files changed, 673 insertions, 150 deletions
diff --git a/bench/PathBench.cpp b/bench/PathBench.cpp
index 5fe002541a..057a2b028c 100644
--- a/bench/PathBench.cpp
+++ b/bench/PathBench.cpp
@@ -275,6 +275,12 @@ protected:
fPoints[(fCurrPoint + 1) & (kNumPoints - 1)]);
fCurrPoint += 2;
break;
+ case SkPath::kConic_Verb:
+ path->conicTo(fPoints[(fCurrPoint + 0) & (kNumPoints - 1)],
+ fPoints[(fCurrPoint + 1) & (kNumPoints - 1)],
+ SK_ScalarHalf);
+ fCurrPoint += 2;
+ break;
case SkPath::kCubic_Verb:
path->cubicTo(fPoints[(fCurrPoint + 0) & (kNumPoints - 1)],
fPoints[(fCurrPoint + 1) & (kNumPoints - 1)],
diff --git a/include/core/SkGeometry.h b/include/core/SkGeometry.h
index 6218ed1843..2c37fff3e4 100644
--- a/include/core/SkGeometry.h
+++ b/include/core/SkGeometry.h
@@ -230,7 +230,16 @@ struct SkConic {
void computeAsQuadError(SkVector* err) const;
bool asQuadTol(SkScalar tol) const;
+ /**
+ * return the power-of-2 number of quads needed to approximate this conic
+ * with a sequence of quads. Will be >= 0.
+ */
int computeQuadPOW2(SkScalar tol) const;
+
+ /**
+ * Chop this conic into N quads, stored continguously in pts[], where
+ * N = 1 << pow2. The amount of storage needed is (1 + 2 * N)
+ */
int chopIntoQuadsPOW2(SkPoint pts[], int pow2) const;
bool findXExtrema(SkScalar* t) const;
diff --git a/include/core/SkPath.h b/include/core/SkPath.h
index 65612cbc93..9300863c80 100644
--- a/include/core/SkPath.h
+++ b/include/core/SkPath.h
@@ -413,6 +413,14 @@ public:
*/
void rQuadTo(SkScalar dx1, SkScalar dy1, SkScalar dx2, SkScalar dy2);
+ void conicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2,
+ SkScalar w);
+ void conicTo(const SkPoint& p1, const SkPoint& p2, SkScalar w) {
+ this->conicTo(p1.fX, p1.fY, p2.fX, p2.fY, w);
+ }
+ void rConicTo(SkScalar dx1, SkScalar dy1, SkScalar dx2, SkScalar dy2,
+ SkScalar w);
+
/** Add a cubic bezier from the last point, approaching control points
(x1,y1) and (x2,y2), and ending at (x3,y3). If no moveTo() call has been
made for this contour, the first point is automatically set to (0,0).
@@ -779,7 +787,8 @@ public:
enum SegmentMask {
kLine_SegmentMask = 1 << 0,
kQuad_SegmentMask = 1 << 1,
- kCubic_SegmentMask = 1 << 2
+ kConic_SegmentMask = 1 << 2,
+ kCubic_SegmentMask = 1 << 3,
};
/**
@@ -793,9 +802,10 @@ public:
kMove_Verb, //!< iter.next returns 1 point
kLine_Verb, //!< iter.next returns 2 points
kQuad_Verb, //!< iter.next returns 3 points
+ kConic_Verb, //!< iter.next returns 3 points + iter.conicWeight()
kCubic_Verb, //!< iter.next returns 4 points
kClose_Verb, //!< iter.next returns 1 point (contour's moveTo pt)
- kDone_Verb //!< iter.next returns 0 points
+ kDone_Verb, //!< iter.next returns 0 points
};
/** Iterate through all of the segments (lines, quadratics, cubics) of
@@ -829,6 +839,12 @@ public:
return this->doNext(pts);
}
+ /**
+ * Return the weight for the current conic. Only valid if the current
+ * segment return by next() was a conic.
+ */
+ SkScalar conicWeight() const { return *fConicWeights; }
+
/** If next() returns kLine_Verb, then this query returns true if the
line was the result of a close() command (i.e. the end point is the
initial moveto for this contour). If next() returned a different
@@ -848,6 +864,7 @@ public:
const SkPoint* fPts;
const uint8_t* fVerbs;
const uint8_t* fVerbStop;
+ const SkScalar* fConicWeights;
SkPoint fMoveTo;
SkPoint fLastPt;
SkBool8 fForceClose;
@@ -879,10 +896,13 @@ public:
*/
Verb next(SkPoint pts[4]);
+ SkScalar conicWeight() const { return *fConicWeights; }
+
private:
const SkPoint* fPts;
const uint8_t* fVerbs;
const uint8_t* fVerbStop;
+ const SkScalar* fConicWeights;
SkPoint fMoveTo;
SkPoint fLastPt;
};
@@ -922,7 +942,7 @@ private:
kIsOval_SerializationShift = 24, // requires 1 bit
kConvexity_SerializationShift = 16, // requires 2 bits
kFillType_SerializationShift = 8, // requires 2 bits
- kSegmentMask_SerializationShift = 0 // requires 3 bits
+ kSegmentMask_SerializationShift = 0 // requires 4 bits
};
#if SK_DEBUG_PATH_REF
diff --git a/include/core/SkPicture.h b/include/core/SkPicture.h
index aea8fc726d..d01cadce89 100644
--- a/include/core/SkPicture.h
+++ b/include/core/SkPicture.h
@@ -210,7 +210,8 @@ protected:
// SK_SUPPORT_HINTING_SCALE_FACTOR
// V10: add drawRRect, drawOval, clipRRect
// V11: modify how readBitmap and writeBitmap store their info.
- static const uint32_t PICTURE_VERSION = 11;
+ // V12: add conics to SkPath, use new SkPathRef flattening
+ static const uint32_t PICTURE_VERSION = 12;
// fPlayback, fRecord, fWidth & fHeight are protected to allow derived classes to
// install their own SkPicturePlayback-derived players,SkPictureRecord-derived
diff --git a/src/core/SkEdgeBuilder.cpp b/src/core/SkEdgeBuilder.cpp
index 608a83c7c7..9ac4e97443 100644
--- a/src/core/SkEdgeBuilder.cpp
+++ b/src/core/SkEdgeBuilder.cpp
@@ -153,12 +153,22 @@ int SkEdgeBuilder::buildPoly(const SkPath& path, const SkIRect* iclip,
return edgePtr - fEdgeList;
}
+static void handle_quad(SkEdgeBuilder* builder, const SkPoint pts[3]) {
+ SkPoint monoX[5];
+ int n = SkChopQuadAtYExtrema(pts, monoX);
+ for (int i = 0; i <= n; i++) {
+ builder->addQuad(&monoX[i * 2]);
+ }
+}
+
int SkEdgeBuilder::build(const SkPath& path, const SkIRect* iclip,
int shiftUp) {
fAlloc.reset();
fList.reset();
fShiftUp = shiftUp;
+ SkScalar conicTol = SK_ScalarHalf * (1 << shiftUp);
+
if (SkPath::kLine_SegmentMask == path.getSegmentMasks()) {
return this->buildPoly(path, iclip, shiftUp);
}
@@ -192,6 +202,24 @@ int SkEdgeBuilder::build(const SkPath& path, const SkIRect* iclip,
this->addClipper(&clipper);
}
break;
+ case SkPath::kConic_Verb: {
+ const int MAX_POW2 = 4;
+ const int MAX_QUADS = 1 << MAX_POW2;
+ const int MAX_QUAD_PTS = 1 + 2 * MAX_QUADS;
+ SkPoint storage[MAX_QUAD_PTS];
+
+ SkConic conic;
+ conic.set(pts, iter.conicWeight());
+ int pow2 = conic.computeQuadPOW2(conicTol);
+ pow2 = SkMin32(pow2, MAX_POW2);
+ int quadCount = conic.chopIntoQuadsPOW2(storage, pow2);
+ SkASSERT(quadCount <= MAX_QUADS);
+ for (int i = 0; i < quadCount; ++i) {
+ if (clipper.clipQuad(&storage[i * 2], clip)) {
+ this->addClipper(&clipper);
+ }
+ }
+ } break;
case SkPath::kCubic_Verb:
if (clipper.clipCubic(pts, clip)) {
this->addClipper(&clipper);
@@ -214,13 +242,26 @@ int SkEdgeBuilder::build(const SkPath& path, const SkIRect* iclip,
this->addLine(pts);
break;
case SkPath::kQuad_Verb: {
- SkPoint monoX[5];
- int n = SkChopQuadAtYExtrema(pts, monoX);
- for (int i = 0; i <= n; i++) {
- this->addQuad(&monoX[i * 2]);
- }
+ handle_quad(this, pts);
break;
}
+ case SkPath::kConic_Verb: {
+ const int MAX_POW2 = 4;
+ const int MAX_QUADS = 1 << MAX_POW2;
+ const int MAX_QUAD_PTS = 1 + 2 * MAX_QUADS;
+ SkPoint storage[MAX_QUAD_PTS];
+
+ SkConic conic;
+ conic.set(pts, iter.conicWeight());
+ int pow2 = conic.computeQuadPOW2(conicTol);
+ pow2 = SkMin32(pow2, MAX_POW2);
+ int quadCount = conic.chopIntoQuadsPOW2(storage, pow2);
+ SkASSERT(quadCount <= MAX_QUADS);
+ SkDebugf("--- quadCount = %d\n", quadCount);
+ for (int i = 0; i < quadCount; ++i) {
+ handle_quad(this, &storage[i * 2]);
+ }
+ } break;
case SkPath::kCubic_Verb: {
SkPoint monoY[10];
int n = SkChopCubicAtYExtrema(pts, monoY);
diff --git a/src/core/SkEdgeBuilder.h b/src/core/SkEdgeBuilder.h
index b296f773c1..f9e5976e17 100644
--- a/src/core/SkEdgeBuilder.h
+++ b/src/core/SkEdgeBuilder.h
@@ -40,6 +40,7 @@ private:
int fShiftUp;
+public:
void addLine(const SkPoint pts[]);
void addQuad(const SkPoint pts[]);
void addCubic(const SkPoint pts[]);
diff --git a/src/core/SkPath.cpp b/src/core/SkPath.cpp
index 95cd9fe938..7485c0b4ff 100644
--- a/src/core/SkPath.cpp
+++ b/src/core/SkPath.cpp
@@ -369,6 +369,7 @@ bool SkPath::conservativelyContainsRect(const SkRect& rect) const {
SkASSERT(moveCnt);
break;
case kQuad_Verb:
+ case kConic_Verb:
SkASSERT(moveCnt);
nextPt = 2;
break;
@@ -558,12 +559,16 @@ bool SkPath::isRectContour(bool allowPartial, int* currVerb, const SkPoint** pts
break;
}
case kQuad_Verb:
+ case kConic_Verb:
case kCubic_Verb:
return false; // quadratic, cubic not allowed
case kMove_Verb:
last = *pts++;
closedOrMoved = true;
break;
+ default:
+ SkASSERT(!"unexpected verb");
+ break;
}
*currVerb += 1;
lastDirection = nextDirection;
@@ -805,15 +810,15 @@ void SkPath::rLineTo(SkScalar x, SkScalar y) {
void SkPath::quadTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2) {
SkDEBUGCODE(this->validate();)
-
+
this->injectMoveToIfNeeded();
-
+
SkPathRef::Editor ed(&fPathRef);
SkPoint* pts = ed.growForVerb(kQuad_Verb);
pts[0].set(x1, y1);
pts[1].set(x2, y2);
fSegmentMask |= kQuad_SegmentMask;
-
+
GEN_ID_INC;
DIRTY_AFTER_EDIT;
}
@@ -824,6 +829,39 @@ void SkPath::rQuadTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2) {
this->quadTo(pt.fX + x1, pt.fY + y1, pt.fX + x2, pt.fY + y2);
}
+void SkPath::conicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2,
+ SkScalar w) {
+ // check for <= 0 or NaN with this test
+ if (!(w > 0)) {
+ this->lineTo(x2, y2);
+ } else if (!SkScalarIsFinite(w)) {
+ this->lineTo(x1, y1);
+ this->lineTo(x2, y2);
+ } else if (SK_Scalar1 == w) {
+ this->quadTo(x1, y1, x2, y2);
+ } else {
+ SkDEBUGCODE(this->validate();)
+
+ this->injectMoveToIfNeeded();
+
+ SkPathRef::Editor ed(&fPathRef);
+ SkPoint* pts = ed.growForConic(w);
+ pts[0].set(x1, y1);
+ pts[1].set(x2, y2);
+ fSegmentMask |= kConic_SegmentMask;
+
+ GEN_ID_INC;
+ DIRTY_AFTER_EDIT;
+ }
+}
+
+void SkPath::rConicTo(SkScalar dx1, SkScalar dy1, SkScalar dx2, SkScalar dy2,
+ SkScalar w) {
+ SkPoint pt;
+ this->getLastPt(&pt);
+ this->conicTo(pt.fX + dx1, pt.fY + dy1, pt.fX + dx2, pt.fY + dy2, w);
+}
+
void SkPath::cubicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2,
SkScalar x3, SkScalar y3) {
SkDEBUGCODE(this->validate();)
@@ -857,6 +895,7 @@ void SkPath::close() {
switch (fPathRef->atVerb(count - 1)) {
case kLine_Verb:
case kQuad_Verb:
+ case kConic_Verb:
case kCubic_Verb:
case kMove_Verb: {
SkPathRef::Editor ed(&fPathRef);
@@ -864,9 +903,12 @@ void SkPath::close() {
GEN_ID_INC;
break;
}
- default:
+ case kClose_Verb:
// don't add a close if it's the first verb or a repeat
break;
+ default:
+ SkASSERT(!"unexpected verb");
+ break;
}
}
@@ -1430,6 +1472,10 @@ void SkPath::addPath(const SkPath& path, const SkMatrix& matrix) {
proc(matrix, &pts[1], &pts[1], 2);
this->quadTo(pts[1], pts[2]);
break;
+ case kConic_Verb:
+ proc(matrix, &pts[1], &pts[1], 2);
+ this->conicTo(pts[1], pts[2], iter.conicWeight());
+ break;
case kCubic_Verb:
proc(matrix, &pts[1], &pts[1], 3);
this->cubicTo(pts[1], pts[2], pts[3]);
@@ -1445,14 +1491,20 @@ void SkPath::addPath(const SkPath& path, const SkMatrix& matrix) {
///////////////////////////////////////////////////////////////////////////////
-static const uint8_t gPtsInVerb[] = {
- 1, // kMove
- 1, // kLine
- 2, // kQuad
- 3, // kCubic
- 0, // kClose
- 0 // kDone
-};
+static int pts_in_verb(unsigned verb) {
+ static const uint8_t gPtsInVerb[] = {
+ 1, // kMove
+ 1, // kLine
+ 2, // kQuad
+ 2, // kConic
+ 3, // kCubic
+ 0, // kClose
+ 0 // kDone
+ };
+
+ SkASSERT(verb < SK_ARRAY_COUNT(gPtsInVerb));
+ return gPtsInVerb[verb];
+}
// ignore the initial moveto, and stop when the 1st contour ends
void SkPath::pathTo(const SkPath& path) {
@@ -1469,6 +1521,7 @@ void SkPath::pathTo(const SkPath& path) {
const uint8_t* verbs = path.fPathRef->verbs();
// skip the initial moveTo
const SkPoint* pts = path.fPathRef->points() + 1;
+ const SkScalar* conicWeight = path.fPathRef->conicWeights();
SkASSERT(verbs[~0] == kMove_Verb);
for (i = 1; i < vcount; i++) {
@@ -1479,13 +1532,16 @@ void SkPath::pathTo(const SkPath& path) {
case kQuad_Verb:
this->quadTo(pts[0].fX, pts[0].fY, pts[1].fX, pts[1].fY);
break;
+ case kConic_Verb:
+ this->conicTo(pts[0], pts[1], *conicWeight++);
+ break;
case kCubic_Verb:
this->cubicTo(pts[0].fX, pts[0].fY, pts[1].fX, pts[1].fY, pts[2].fX, pts[2].fY);
break;
case kClose_Verb:
return;
}
- pts += gPtsInVerb[verbs[~i]];
+ pts += pts_in_verb(verbs[~i]);
}
}
@@ -1503,14 +1559,17 @@ void SkPath::reversePathTo(const SkPath& path) {
const uint8_t* verbs = path.fPathRef->verbs();
const SkPoint* pts = path.fPathRef->points();
+ const SkScalar* conicWeights = path.fPathRef->conicWeights();
SkASSERT(verbs[~0] == kMove_Verb);
for (i = 1; i < vcount; ++i) {
- int n = gPtsInVerb[verbs[~i]];
+ unsigned v = verbs[~i];
+ int n = pts_in_verb(v);
if (n == 0) {
break;
}
pts += n;
+ conicWeights += (SkPath::kConic_Verb == v);
}
while (--i > 0) {
@@ -1521,6 +1580,9 @@ void SkPath::reversePathTo(const SkPath& path) {
case kQuad_Verb:
this->quadTo(pts[-1].fX, pts[-1].fY, pts[-2].fX, pts[-2].fY);
break;
+ case kConic_Verb:
+ this->conicTo(pts[-1], pts[-2], *--conicWeights);
+ break;
case kCubic_Verb:
this->cubicTo(pts[-1].fX, pts[-1].fY, pts[-2].fX, pts[-2].fY,
pts[-3].fX, pts[-3].fY);
@@ -1529,7 +1591,7 @@ void SkPath::reversePathTo(const SkPath& path) {
SkDEBUGFAIL("bad verb");
break;
}
- pts -= gPtsInVerb[verbs[~i]];
+ pts -= pts_in_verb(verbs[~i]);
}
}
@@ -1540,6 +1602,7 @@ void SkPath::reverseAddPath(const SkPath& src) {
// we will iterator through src's verbs backwards
const uint8_t* verbs = src.fPathRef->verbsMemBegin(); // points at the last verb
const uint8_t* verbsEnd = src.fPathRef->verbs(); // points just past the first verb
+ const SkScalar* conicWeights = src.fPathRef->conicWeightsEnd();
fIsOval = false;
@@ -1547,7 +1610,7 @@ void SkPath::reverseAddPath(const SkPath& src) {
bool needClose = false;
while (verbs < verbsEnd) {
uint8_t v = *(verbs++);
- int n = gPtsInVerb[v];
+ int n = pts_in_verb(v);
if (needMove) {
--pts;
@@ -1570,6 +1633,9 @@ void SkPath::reverseAddPath(const SkPath& src) {
case kQuad_Verb:
this->quadTo(pts[1], pts[0]);
break;
+ case kConic_Verb:
+ this->conicTo(pts[1], pts[0], *--conicWeights);
+ break;
case kCubic_Verb:
this->cubicTo(pts[2], pts[1], pts[0]);
break;
@@ -1644,6 +1710,10 @@ void SkPath::transform(const SkMatrix& matrix, SkPath* dst) const {
case kQuad_Verb:
subdivide_quad_to(&tmp, pts);
break;
+ case kConic_Verb:
+ SkASSERT(!"TODO: compute new weight");
+ tmp.conicTo(pts[1], pts[2], iter.conicWeight());
+ break;
case kCubic_Verb:
subdivide_cubic_to(&tmp, pts);
break;
@@ -1741,6 +1811,7 @@ enum SegmentState {
SkPath::Iter::Iter() {
#ifdef SK_DEBUG
fPts = NULL;
+ fConicWeights = NULL;
fMoveTo.fX = fMoveTo.fY = fLastPt.fX = fLastPt.fY = 0;
fForceClose = fCloseLine = false;
fSegmentState = kEmptyContour_SegmentState;
@@ -1759,6 +1830,7 @@ void SkPath::Iter::setPath(const SkPath& path, bool forceClose) {
fPts = path.fPathRef->points();
fVerbs = path.fPathRef->verbs();
fVerbStop = path.fPathRef->verbsMemBegin();
+ fConicWeights = path.fPathRef->conicWeights() - 1; // begin one behind
fLastPt.fX = fLastPt.fY = 0;
fMoveTo.fX = fMoveTo.fY = 0;
fForceClose = SkToU8(forceClose);
@@ -1870,6 +1942,7 @@ void SkPath::Iter::consumeDegenerateSegments() {
fPts++;
break;
+ case kConic_Verb:
case kQuad_Verb:
if (!IsQuadDegenerate(lastPt, fPts[0], fPts[1])) {
if (lastMoveVerb) {
@@ -1882,6 +1955,7 @@ void SkPath::Iter::consumeDegenerateSegments() {
// Ignore this line and continue
fVerbs--;
fPts += 2;
+ fConicWeights += (kConic_Verb == verb);
break;
case kCubic_Verb:
@@ -1951,6 +2025,9 @@ SkPath::Verb SkPath::Iter::doNext(SkPoint ptsParam[4]) {
fCloseLine = false;
srcPts += 1;
break;
+ case kConic_Verb:
+ fConicWeights += 1;
+ // fall-through
case kQuad_Verb:
pts[0] = this->cons_moveTo();
memcpy(&pts[1], srcPts, 2 * sizeof(SkPoint));
@@ -1983,6 +2060,7 @@ SkPath::Verb SkPath::Iter::doNext(SkPoint ptsParam[4]) {
SkPath::RawIter::RawIter() {
#ifdef SK_DEBUG
fPts = NULL;
+ fConicWeights = NULL;
fMoveTo.fX = fMoveTo.fY = fLastPt.fX = fLastPt.fY = 0;
#endif
// need to init enough to make next() harmlessly return kDone_Verb
@@ -1998,6 +2076,7 @@ void SkPath::RawIter::setPath(const SkPath& path) {
fPts = path.fPathRef->points();
fVerbs = path.fPathRef->verbs();
fVerbStop = path.fPathRef->verbsMemBegin();
+ fConicWeights = path.fPathRef->conicWeights() - 1; // begin one behind
fMoveTo.fX = fMoveTo.fY = 0;
fLastPt.fX = fLastPt.fY = 0;
}
@@ -2025,6 +2104,9 @@ SkPath::Verb SkPath::RawIter::next(SkPoint pts[4]) {
fLastPt = srcPts[0];
srcPts += 1;
break;
+ case kConic_Verb:
+ fConicWeights += 1;
+ // fall-through
case kQuad_Verb:
pts[0] = fLastPt;
memcpy(&pts[1], srcPts, 2 * sizeof(SkPoint));
@@ -2057,22 +2139,12 @@ uint32_t SkPath::writeToMemory(void* storage) const {
if (NULL == storage) {
const int byteCount = sizeof(int32_t)
-#if NEW_PICTURE_FORMAT
+ fPathRef->writeSize()
-#else
- + 2 * sizeof(int32_t)
- + sizeof(SkPoint) * fPathRef->countPoints()
- + sizeof(uint8_t) * fPathRef->countVerbs()
-#endif
+ sizeof(SkRect);
return SkAlign4(byteCount);
}
SkWBuffer buffer(storage);
-#if !NEW_PICTURE_FORMAT
- buffer.write32(fPathRef->countPoints());
- buffer.write32(fPathRef->countVerbs());
-#endif
// Call getBounds() to ensure (as a side-effect) that fBounds
// and fIsFinite are computed.
@@ -2098,24 +2170,16 @@ uint32_t SkPath::writeToMemory(void* storage) const {
uint32_t SkPath::readFromMemory(const void* storage) {
SkRBuffer buffer(storage);
-#if !NEW_PICTURE_FORMAT
- int32_t pcount = buffer.readS32();
- int32_t vcount = buffer.readS32();
-#endif
uint32_t packed = buffer.readS32();
fIsFinite = (packed >> kIsFinite_SerializationShift) & 1;
fIsOval = (packed >> kIsOval_SerializationShift) & 1;
fConvexity = (packed >> kConvexity_SerializationShift) & 0xFF;
fFillType = (packed >> kFillType_SerializationShift) & 0xFF;
- fSegmentMask = (packed >> kSegmentMask_SerializationShift) & 0x7;
+ fSegmentMask = (packed >> kSegmentMask_SerializationShift) & 0xF;
fDirection = (packed >> kDirection_SerializationShift) & 0x3;
-#if NEW_PICTURE_FORMAT
fPathRef.reset(SkPathRef::CreateFromBuffer(&buffer));
-#else
- fPathRef.reset(SkPathRef::CreateFromBuffer(vcount, pcount, &buffer));
-#endif
buffer.read(&fBounds, sizeof(fBounds));
fBoundsIsDirty = false;
@@ -2142,7 +2206,7 @@ static void append_scalar(SkString* str, SkScalar value) {
}
static void append_params(SkString* str, const char label[], const SkPoint pts[],
- int count) {
+ int count, SkScalar conicWeight = -1) {
str->append(label);
str->append("(");
@@ -2155,6 +2219,10 @@ static void append_params(SkString* str, const char label[], const SkPoint pts[]
str->append(", ");
}
}
+ if (conicWeight >= 0) {
+ str->append(", ");
+ append_scalar(str, conicWeight);
+ }
str->append(");\n");
}
@@ -2180,6 +2248,9 @@ void SkPath::dump(bool forceClose, const char title[]) const {
case kQuad_Verb:
append_params(&builder, "path.quadTo", &pts[1], 2);
break;
+ case kConic_Verb:
+ append_params(&builder, "path.conicTo", &pts[1], 2, iter.conicWeight());
+ break;
case kCubic_Verb:
append_params(&builder, "path.cubicTo", &pts[1], 3);
break;
@@ -2239,6 +2310,9 @@ void SkPath::validate() const {
case kQuad_Verb:
mask |= kQuad_SegmentMask;
break;
+ case kConic_Verb:
+ mask |= kConic_SegmentMask;
+ break;
case kCubic_Verb:
mask |= kCubic_SegmentMask;
case kMove_Verb: // these verbs aren't included in the segment mask.
@@ -2379,6 +2453,7 @@ SkPath::Convexity SkPath::internalGetConvexity() const {
break;
case kLine_Verb: count = 1; break;
case kQuad_Verb: count = 2; break;
+ case kConic_Verb: count = 2; break;
case kCubic_Verb: count = 3; break;
case kClose_Verb:
state.close();
@@ -2423,6 +2498,7 @@ private:
const SkPoint* fCurrPt;
const uint8_t* fCurrVerb;
const uint8_t* fStopVerbs;
+ const SkScalar* fCurrConicWeight;
bool fDone;
SkDEBUGCODE(int fContourCounter;)
};
@@ -2432,6 +2508,7 @@ ContourIter::ContourIter(const SkPathRef& pathRef) {
fDone = false;
fCurrPt = pathRef.points();
fCurrVerb = pathRef.verbs();
+ fCurrConicWeight = pathRef.conicWeights();
fCurrPtCount = 0;
SkDEBUGCODE(fContourCounter = 0;)
this->next();
@@ -2459,13 +2536,19 @@ void ContourIter::next() {
case SkPath::kLine_Verb:
ptCount += 1;
break;
+ case SkPath::kConic_Verb:
+ fCurrConicWeight += 1;
+ // fall-through
case SkPath::kQuad_Verb:
ptCount += 2;
break;
case SkPath::kCubic_Verb:
ptCount += 3;
break;
- default: // kClose_Verb, just keep going
+ case SkPath::kClose_Verb:
+ break;
+ default:
+ SkASSERT(!"unexpected verb");
break;
}
}
@@ -2957,13 +3040,16 @@ bool SkPath::contains(SkScalar x, SkScalar y) const {
case SkPath::kQuad_Verb:
w += winding_quad(pts, x, y);
break;
+ case SkPath::kConic_Verb:
+ SkASSERT(0);
+ break;
case SkPath::kCubic_Verb:
w += winding_cubic(pts, x, y);
break;
case SkPath::kDone_Verb:
done = true;
break;
- }
+ }
} while (!done);
switch (this->getFillType()) {
diff --git a/src/core/SkPathMeasure.cpp b/src/core/SkPathMeasure.cpp
index af2579fff1..c519f93dce 100644
--- a/src/core/SkPathMeasure.cpp
+++ b/src/core/SkPathMeasure.cpp
@@ -152,6 +152,9 @@ void SkPathMeasure::buildSegments() {
bool done = false;
do {
switch (fIter.next(pts)) {
+ case SkPath::kConic_Verb:
+ SkASSERT(0);
+ break;
case SkPath::kMove_Verb:
ptIndex += 1;
fPts.append(1, pts);
diff --git a/src/core/SkPathRef.h b/src/core/SkPathRef.h
index 5f85b7b896..b670039291 100644
--- a/src/core/SkPathRef.h
+++ b/src/core/SkPathRef.h
@@ -12,12 +12,6 @@
#include "SkRefCnt.h"
#include <stddef.h> // ptrdiff_t
-// When we're ready to break the picture format. Changes:
-// * Write genID.
-// * SkPathRef read/write counts (which will change the field order)
-// * SkPathRef reads/writes verbs backwards.
-#define NEW_PICTURE_FORMAT 0
-
/**
* Holds the path verbs and points. It is versioned by a generation ID. None of its public methods
* modify the contents. To modify or append to the verbs/points wrap the SkPathRef in an
@@ -109,6 +103,13 @@ public:
return fPathRef->growForVerb(verb);
}
+ SkPoint* growForConic(SkScalar w) {
+ fPathRef->validate();
+ SkPoint* pts = fPathRef->growForVerb(SkPath::kConic_Verb);
+ *fPathRef->fConicWeights.append() = w;
+ return pts;
+ }
+
/**
* Allocates space for additional verbs and points and returns pointers to the new verbs and
* points. verbs will point one beyond the first new verb (index it using [~<i>]). pts points
@@ -131,8 +132,8 @@ public:
* Resets the path ref to a new verb and point count. The new verbs and points are
* uninitialized.
*/
- void resetToSize(int newVerbCnt, int newPointCnt) {
- fPathRef->resetToSize(newVerbCnt, newPointCnt);
+ void resetToSize(int newVerbCnt, int newPointCnt, int newConicCount) {
+ fPathRef->resetToSize(newVerbCnt, newPointCnt, newConicCount);
}
/**
* Gets the path ref that is wrapped in the Editor.
@@ -202,40 +203,29 @@ public:
} else if (rcnt > 1) {
dst->reset(SkNEW(SkPathRef));
}
- (*dst)->resetToSize(src.fVerbCnt, src.fPointCnt);
+ (*dst)->resetToSize(src.fVerbCnt, src.fPointCnt, src.fConicWeights.count());
memcpy((*dst)->verbsMemWritable(), src.verbsMemBegin(), src.fVerbCnt * sizeof(uint8_t));
matrix.mapPoints((*dst)->fPoints, src.points(), src.fPointCnt);
+ (*dst)->fConicWeights = src.fConicWeights;
(*dst)->validate();
}
-#if NEW_PICTURE_FORMAT
static SkPathRef* CreateFromBuffer(SkRBuffer* buffer) {
SkPathRef* ref = SkNEW(SkPathRef);
ref->fGenerationID = buffer->readU32();
int32_t verbCount = buffer->readS32();
int32_t pointCount = buffer->readS32();
- ref->resetToSize(verbCount, pointCount);
+ int32_t conicCount = buffer->readS32();
+ ref->resetToSize(verbCount, pointCount, conicCount);
SkASSERT(verbCount == ref->countVerbs());
SkASSERT(pointCount == ref->countPoints());
+ SkASSERT(conicCount == ref->fConicWeights.count());
buffer->read(ref->verbsMemWritable(), verbCount * sizeof(uint8_t));
buffer->read(ref->fPoints, pointCount * sizeof(SkPoint));
+ buffer->read(ref->fConicWeights.begin(), conicCount * sizeof(SkScalar));
return ref;
}
-#else
- static SkPathRef* CreateFromBuffer(int verbCount, int pointCount, SkRBuffer* buffer) {
- SkPathRef* ref = SkNEW(SkPathRef);
-
- ref->resetToSize(verbCount, pointCount);
- SkASSERT(verbCount == ref->countVerbs());
- SkASSERT(pointCount == ref->countPoints());
- buffer->read(ref->fPoints, pointCount * sizeof(SkPoint));
- for (int i = 0; i < verbCount; ++i) {
- ref->fVerbs[~i] = buffer->readU8();
- }
- return ref;
- }
-#endif
/**
* Rollsback a path ref to zero verbs and points with the assumption that the path ref will be
@@ -249,12 +239,13 @@ public:
(*pathRef)->fPointCnt = 0;
(*pathRef)->fFreeSpace = (*pathRef)->currSize();
(*pathRef)->fGenerationID = 0;
+ (*pathRef)->fConicWeights.rewind();
(*pathRef)->validate();
} else {
int oldVCnt = (*pathRef)->countVerbs();
int oldPCnt = (*pathRef)->countPoints();
pathRef->reset(SkNEW(SkPathRef));
- (*pathRef)->resetToSize(0, 0, oldVCnt, oldPCnt);
+ (*pathRef)->resetToSize(0, 0, 0, oldVCnt, oldPCnt);
}
}
@@ -299,6 +290,9 @@ public:
*/
const SkPoint* pointsEnd() const { return this->points() + this->countPoints(); }
+ const SkScalar* conicWeights() const { this->validate(); return fConicWeights.begin(); }
+ const SkScalar* conicWeightsEnd() const { this->validate(); return fConicWeights.end(); }
+
/**
* Convenience methods for getting to a verb or point by index.
*/
@@ -337,6 +331,10 @@ public:
SkASSERT(!genIDMatch);
return false;
}
+ if (fConicWeights != ref.fConicWeights) {
+ SkASSERT(!genIDMatch);
+ return false;
+ }
// We've done the work to determine that these are equal. If either has a zero genID, copy
// the other's. If both are 0 then genID() will compute the next ID.
if (0 == fGenerationID) {
@@ -350,7 +348,6 @@ public:
/**
* Writes the path points and verbs to a buffer.
*/
-#if NEW_PICTURE_FORMAT
void writeToBuffer(SkWBuffer* buffer) {
this->validate();
SkDEBUGCODE_X(size_t beforePos = buffer->pos();)
@@ -358,10 +355,12 @@ public:
// TODO: write gen ID here. Problem: We don't know if we're cross process or not from
// SkWBuffer. Until this is fixed we write 0.
buffer->write32(0);
- buffer->write32(this->fVerbCnt);
- buffer->write32(this->fPointCnt);
- buffer->write(this->verbsMemBegin(), fVerbCnt * sizeof(uint8_t));
+ buffer->write32(fVerbCnt);
+ buffer->write32(fPointCnt);
+ buffer->write32(fConicWeights.count());
+ buffer->write(verbsMemBegin(), fVerbCnt * sizeof(uint8_t));
buffer->write(fPoints, fPointCnt * sizeof(SkPoint));
+ buffer->write(fConicWeights.begin(), fConicWeights.bytes());
SkASSERT(buffer->pos() - beforePos == (size_t) this->writeSize());
}
@@ -370,17 +369,11 @@ public:
* Gets the number of bytes that would be written in writeBuffer()
*/
uint32_t writeSize() {
- return 3 * sizeof(uint32_t) + fVerbCnt * sizeof(uint8_t) + fPointCnt * sizeof(SkPoint);
+ return 4 * sizeof(uint32_t) +
+ fVerbCnt * sizeof(uint8_t) +
+ fPointCnt * sizeof(SkPoint) +
+ fConicWeights.bytes();
}
-#else
- void writeToBuffer(SkWBuffer* buffer) {
- this->validate();
- buffer->write(fPoints, fPointCnt * sizeof(SkPoint));
- for (int i = 0; i < fVerbCnt; ++i) {
- buffer->write8(fVerbs[~i]);
- }
- }
-#endif
private:
SkPathRef() {
@@ -396,10 +389,11 @@ private:
void copy(const SkPathRef& ref, int additionalReserveVerbs, int additionalReservePoints) {
this->validate();
- this->resetToSize(ref.fVerbCnt, ref.fPointCnt,
+ this->resetToSize(ref.fVerbCnt, ref.fPointCnt, ref.fConicWeights.count(),
additionalReserveVerbs, additionalReservePoints);
memcpy(this->verbsMemWritable(), ref.verbsMemBegin(), ref.fVerbCnt * sizeof(uint8_t));
memcpy(this->fPoints, ref.fPoints, ref.fPointCnt * sizeof(SkPoint));
+ fConicWeights = ref.fConicWeights;
// We could call genID() here to force a real ID (instead of 0). However, if we're making
// a copy then presumably we intend to make a modification immediately afterwards.
fGenerationID = ref.fGenerationID;
@@ -416,7 +410,8 @@ private:
/** Resets the path ref with verbCount verbs and pointCount points, all unitialized. Also
* allocates space for reserveVerb additional verbs and reservePoints additional points.*/
- void resetToSize(int verbCount, int pointCount, int reserveVerbs = 0, int reservePoints = 0) {
+ void resetToSize(int verbCount, int pointCount, int conicCount,
+ int reserveVerbs = 0, int reservePoints = 0) {
this->validate();
fGenerationID = 0;
@@ -442,6 +437,7 @@ private:
fVerbCnt = verbCount;
fFreeSpace = this->currSize() - minSize;
}
+ fConicWeights.setCount(conicCount);
this->validate();
}
@@ -474,13 +470,17 @@ private:
case SkPath::kLine_Verb:
pCnt = 1;
break;
+ case SkPath::kConic_Verb:
case SkPath::kQuad_Verb:
pCnt = 2;
break;
case SkPath::kCubic_Verb:
pCnt = 3;
break;
- default:
+ case SkPath::kDone_Verb:
+ SkASSERT(!"growForVerb called for kDone");
+ // fall through
+ case SkPath::kClose_Verb:
pCnt = 0;
}
size_t space = sizeof(uint8_t) + pCnt * sizeof (SkPoint);
@@ -588,6 +588,8 @@ private:
int fVerbCnt;
int fPointCnt;
size_t fFreeSpace; // redundant but saves computation
+ SkTDArray<SkScalar> fConicWeights;
+
enum {
kEmptyGenID = 1, // GenID reserved for path ref with zero points and zero verbs.
};
diff --git a/src/core/SkRegion_path.cpp b/src/core/SkRegion_path.cpp
index 80149a3836..0a5a401809 100644
--- a/src/core/SkRegion_path.cpp
+++ b/src/core/SkRegion_path.cpp
@@ -216,25 +216,36 @@ void SkRgnBuilder::copyToRgn(SkRegion::RunType runs[]) const {
*runs = SkRegion::kRunTypeSentinel;
}
-static int count_path_runtype_values(const SkPath& path, int* itop, int* ibot) {
+static unsigned verb_to_initial_last_index(unsigned verb) {
static const uint8_t gPathVerbToInitialLastIndex[] = {
0, // kMove_Verb
1, // kLine_Verb
2, // kQuad_Verb
+ 2, // kConic_Verb
3, // kCubic_Verb
0, // kClose_Verb
0 // kDone_Verb
};
+ SkASSERT((unsigned)verb < SK_ARRAY_COUNT(gPathVerbToInitialLastIndex));
+ return gPathVerbToInitialLastIndex[verb];
+}
+static unsigned verb_to_max_edges(unsigned verb) {
static const uint8_t gPathVerbToMaxEdges[] = {
0, // kMove_Verb
1, // kLine_Verb
2, // kQuad_VerbB
+ 2, // kConic_VerbB
3, // kCubic_Verb
0, // kClose_Verb
0 // kDone_Verb
};
+ SkASSERT((unsigned)verb < SK_ARRAY_COUNT(gPathVerbToMaxEdges));
+ return gPathVerbToMaxEdges[verb];
+}
+
+static int count_path_runtype_values(const SkPath& path, int* itop, int* ibot) {
SkPath::Iter iter(path, true);
SkPoint pts[4];
SkPath::Verb verb;
@@ -244,9 +255,9 @@ static int count_path_runtype_values(const SkPath& path, int* itop, int* ibot) {
SkScalar bot = SkIntToScalar(SK_MinS16);
while ((verb = iter.next(pts, false)) != SkPath::kDone_Verb) {
- maxEdges += gPathVerbToMaxEdges[verb];
+ maxEdges += verb_to_max_edges(verb);
- int lastIndex = gPathVerbToInitialLastIndex[verb];
+ int lastIndex = verb_to_initial_last_index(verb);
if (lastIndex > 0) {
for (int i = 1; i <= lastIndex; i++) {
if (top > pts[i].fY) {
diff --git a/src/effects/SkCornerPathEffect.cpp b/src/effects/SkCornerPathEffect.cpp
index 1cf797a249..f4c3147301 100644
--- a/src/effects/SkCornerPathEffect.cpp
+++ b/src/effects/SkCornerPathEffect.cpp
@@ -111,6 +111,9 @@ bool SkCornerPathEffect::filterPath(SkPath* dst, const SkPath& src,
}
dst->close();
break;
+ case SkPath::kConic_Verb:
+ SkASSERT(0);
+ break;
case SkPath::kDone_Verb:
goto DONE;
}
diff --git a/src/gpu/GrAAHairLinePathRenderer.cpp b/src/gpu/GrAAHairLinePathRenderer.cpp
index 1a1552130e..bed931c034 100644
--- a/src/gpu/GrAAHairLinePathRenderer.cpp
+++ b/src/gpu/GrAAHairLinePathRenderer.cpp
@@ -221,7 +221,10 @@ int generate_lines_and_quads(const SkPath& path,
GrPoint devPts[4];
SkPath::Verb verb = iter.next(pathPts);
switch (verb) {
- case SkPath::kMove_Verb:
+ case SkPath::kConic_Verb:
+ SkASSERT(0);
+ break;
+ case SkPath::kMove_Verb:
break;
case SkPath::kLine_Verb:
m.mapPoints(devPts, pathPts, 2);
diff --git a/src/gpu/GrDefaultPathRenderer.cpp b/src/gpu/GrDefaultPathRenderer.cpp
index 13bfe9233f..19fd2beff8 100644
--- a/src/gpu/GrDefaultPathRenderer.cpp
+++ b/src/gpu/GrDefaultPathRenderer.cpp
@@ -255,6 +255,9 @@ bool GrDefaultPathRenderer::createGeom(const SkPath& path,
for (;;) {
SkPath::Verb verb = iter.next(pts);
switch (verb) {
+ case SkPath::kConic_Verb:
+ SkASSERT(0);
+ break;
case SkPath::kMove_Verb:
if (!first) {
uint16_t currIdx = (uint16_t) (vert - base);
diff --git a/src/gpu/gl/GrGLPath.cpp b/src/gpu/gl/GrGLPath.cpp
index 8c6e11e667..63c2fa107c 100644
--- a/src/gpu/gl/GrGLPath.cpp
+++ b/src/gpu/gl/GrGLPath.cpp
@@ -20,14 +20,15 @@ inline GrGLubyte verb_to_gl_path_cmd(const SkPath::Verb verb) {
GR_GL_MOVE_TO,
GR_GL_LINE_TO,
GR_GL_QUADRATIC_CURVE_TO,
+ 0xFF, // conic
GR_GL_CUBIC_CURVE_TO,
GR_GL_CLOSE_PATH,
};
GR_STATIC_ASSERT(0 == SkPath::kMove_Verb);
GR_STATIC_ASSERT(1 == SkPath::kLine_Verb);
GR_STATIC_ASSERT(2 == SkPath::kQuad_Verb);
- GR_STATIC_ASSERT(3 == SkPath::kCubic_Verb);
- GR_STATIC_ASSERT(4 == SkPath::kClose_Verb);
+ GR_STATIC_ASSERT(4 == SkPath::kCubic_Verb);
+ GR_STATIC_ASSERT(5 == SkPath::kClose_Verb);
GrAssert(verb >= 0 && (size_t)verb < GR_ARRAY_COUNT(gTable));
return gTable[verb];
@@ -39,14 +40,15 @@ inline int num_pts(const SkPath::Verb verb) {
1, // move
1, // line
2, // quad
+ 2, // conic
3, // cubic
0, // close
};
GR_STATIC_ASSERT(0 == SkPath::kMove_Verb);
GR_STATIC_ASSERT(1 == SkPath::kLine_Verb);
GR_STATIC_ASSERT(2 == SkPath::kQuad_Verb);
- GR_STATIC_ASSERT(3 == SkPath::kCubic_Verb);
- GR_STATIC_ASSERT(4 == SkPath::kClose_Verb);
+ GR_STATIC_ASSERT(4 == SkPath::kCubic_Verb);
+ GR_STATIC_ASSERT(5 == SkPath::kClose_Verb);
GrAssert(verb >= 0 && (size_t)verb < GR_ARRAY_COUNT(gTable));
return gTable[verb];
diff --git a/src/pathops/SkOpAngle.cpp b/src/pathops/SkOpAngle.cpp
index aa72394043..dee2906b7f 100644
--- a/src/pathops/SkOpAngle.cpp
+++ b/src/pathops/SkOpAngle.cpp
@@ -113,11 +113,11 @@ bool SkOpAngle::operator<(const SkOpAngle& rh) const {
SkPath::Verb partVerb = useThis ? fVerb : rh.fVerb;
ray[0] = partVerb == SkPath::kCubic_Verb && part[0].approximatelyEqual(part[1]) ?
part[2] : part[1];
- ray[1].fX = (part[0].fX + part[partVerb].fX) / 2;
- ray[1].fY = (part[0].fY + part[partVerb].fY) / 2;
+ ray[1].fX = (part[0].fX + part[SkPathOpsVerbToPoints(partVerb)].fX) / 2;
+ ray[1].fY = (part[0].fY + part[SkPathOpsVerbToPoints(partVerb)].fY) / 2;
SkASSERT(ray[0] != ray[1]);
- roots = (i.*CurveRay[fVerb])(fPts, ray);
- rroots = (ri.*CurveRay[rh.fVerb])(rh.fPts, ray);
+ roots = (i.*CurveRay[SkPathOpsVerbToPoints(fVerb)])(fPts, ray);
+ rroots = (ri.*CurveRay[SkPathOpsVerbToPoints(rh.fVerb)])(rh.fPts, ray);
} while ((roots == 0 || rroots == 0) && (flip ^= true));
if (roots == 0 || rroots == 0) {
// FIXME: we don't have a solution in this case. The interim solution
@@ -314,8 +314,8 @@ void SkOpAngle::setSpans() {
fUnsortable = step > 0 ? thisSpan.fUnsortableStart : nextSpan.fUnsortableEnd;
#if DEBUG_UNSORTABLE
if (fUnsortable) {
- SkPoint iPt = (*CurvePointAtT[fVerb])(fPts, thisSpan.fT);
- SkPoint ePt = (*CurvePointAtT[fVerb])(fPts, nextSpan.fT);
+ SkPoint iPt = (*CurvePointAtT[SkPathOpsVerbToPoints(fVerb)])(fPts, thisSpan.fT);
+ SkPoint ePt = (*CurvePointAtT[SkPathOpsVerbToPoints(fVerb)])(fPts, nextSpan.fT);
SkDebugf("%s unsortable [%d] (%1.9g,%1.9g) [%d] (%1.9g,%1.9g)\n", __FUNCTION__,
index, iPt.fX, iPt.fY, fEnd, ePt.fX, ePt.fY);
}
@@ -330,8 +330,8 @@ void SkOpAngle::setSpans() {
}
#if 1
#if DEBUG_UNSORTABLE
- SkPoint iPt = (*CurvePointAtT[fVerb])(fPts, startT);
- SkPoint ePt = (*CurvePointAtT[fVerb])(fPts, endT);
+ SkPoint iPt = (*CurvePointAtT[SkPathOpsVerbToPoints(fVerb)])(fPts, startT);
+ SkPoint ePt = (*CurvePointAtT[SkPathOpsVerbToPoints(fVerb)])(fPts, endT);
SkDebugf("%s all tiny unsortable [%d] (%1.9g,%1.9g) [%d] (%1.9g,%1.9g)\n", __FUNCTION__,
fStart, iPt.fX, iPt.fY, fEnd, ePt.fX, ePt.fY);
#endif
diff --git a/src/pathops/SkOpContour.h b/src/pathops/SkOpContour.h
index c90c218344..c57fbac6ca 100644
--- a/src/pathops/SkOpContour.h
+++ b/src/pathops/SkOpContour.h
@@ -114,7 +114,7 @@ public:
const SkPoint& end() const {
const SkOpSegment& segment = fSegments.back();
- return segment.pts()[segment.verb()];
+ return segment.pts()[SkPathOpsVerbToPoints(segment.verb())];
}
void findTooCloseToCall() {
@@ -195,7 +195,7 @@ public:
int updateSegment(int index, const SkPoint* pts) {
SkOpSegment& segment = fSegments[index];
segment.updatePts(pts);
- return segment.verb() + 1;
+ return SkPathOpsVerbToPoints(segment.verb()) + 1;
}
#if DEBUG_TEST
diff --git a/src/pathops/SkOpEdgeBuilder.cpp b/src/pathops/SkOpEdgeBuilder.cpp
index 57e3b41912..5803afa11c 100644
--- a/src/pathops/SkOpEdgeBuilder.cpp
+++ b/src/pathops/SkOpEdgeBuilder.cpp
@@ -76,7 +76,7 @@ int SkOpEdgeBuilder::preFetch() {
if (verb == SkPath::kMove_Verb) {
*fPathPts.append() = pts[0];
} else if (verb >= SkPath::kLine_Verb && verb <= SkPath::kCubic_Verb) {
- fPathPts.append(verb, &pts[1]);
+ fPathPts.append(SkPathOpsVerbToPoints(verb), &pts[1]);
}
} while (verb != SkPath::kDone_Verb);
return fPathVerbs.count() - 1;
@@ -137,7 +137,7 @@ bool SkOpEdgeBuilder::walk() {
if (reducedVerb == 0) {
break; // skip degenerate points
}
- if (reducedVerb == 1) {
+ if (reducedVerb == SkPath::kLine_Verb) {
const SkPoint* lineStart = fReducePts.end() - 2;
*fExtra.append() = fCurrentContour->addLine(lineStart);
break;
@@ -150,12 +150,12 @@ bool SkOpEdgeBuilder::walk() {
if (reducedVerb == 0) {
break; // skip degenerate points
}
- if (reducedVerb == 1) {
+ if (reducedVerb == SkPath::kLine_Verb) {
const SkPoint* lineStart = fReducePts.end() - 2;
*fExtra.append() = fCurrentContour->addLine(lineStart);
break;
}
- if (reducedVerb == 2) {
+ if (reducedVerb == SkPath::kQuad_Verb) {
const SkPoint* quadStart = fReducePts.end() - 3;
*fExtra.append() = fCurrentContour->addQuad(quadStart);
break;
@@ -172,8 +172,8 @@ bool SkOpEdgeBuilder::walk() {
SkDEBUGFAIL("bad verb");
return false;
}
- fFinalCurveStart = &pointsPtr[verb - 1];
- pointsPtr += verb;
+ fFinalCurveStart = &pointsPtr[SkPathOpsVerbToPoints(verb) - 1];
+ pointsPtr += SkPathOpsVerbToPoints(verb);
SkASSERT(fCurrentContour);
}
if (fCurrentContour && !fAllowOpenContours && !close()) {
diff --git a/src/pathops/SkOpSegment.cpp b/src/pathops/SkOpSegment.cpp
index bcefd71d60..817732e0e5 100644
--- a/src/pathops/SkOpSegment.cpp
+++ b/src/pathops/SkOpSegment.cpp
@@ -133,7 +133,7 @@ SkPoint SkOpSegment::activeLeftTop(bool onlySortable, int* firstT) const {
}
}
if (fVerb != SkPath::kLine_Verb && !lastDone) {
- SkPoint curveTop = (*CurveTop[fVerb])(fPts, lastT, span.fT);
+ SkPoint curveTop = (*CurveTop[SkPathOpsVerbToPoints(fVerb)])(fPts, lastT, span.fT);
if (topPt.fY > curveTop.fY || (topPt.fY == curveTop.fY
&& topPt.fX > curveTop.fX)) {
topPt = curveTop;
@@ -210,9 +210,9 @@ void SkOpSegment::addAngle(SkTDArray<SkOpAngle>* anglesPtr, int start, int end)
#if DEBUG_ANGLE
SkTDArray<SkOpAngle>& angles = *anglesPtr;
if (angles.count() > 1 && !fTs[start].fTiny) {
- SkPoint angle0Pt = (*CurvePointAtT[angles[0].verb()])(angles[0].pts(),
+ SkPoint angle0Pt = (*CurvePointAtT[SkPathOpsVerbToPoints(angles[0].verb())])(angles[0].pts(),
(*angles[0].spans())[angles[0].start()].fT);
- SkPoint newPt = (*CurvePointAtT[fVerb])(fPts, fTs[start].fT);
+ SkPoint newPt = (*CurvePointAtT[SkPathOpsVerbToPoints(fVerb)])(fPts, fTs[start].fT);
bool match = AlmostEqualUlps(angle0Pt.fX, newPt.fX);
match &= AlmostEqualUlps(angle0Pt.fY, newPt.fY);
if (!match) {
@@ -354,7 +354,7 @@ void SkOpSegment::addCurveTo(int start, int end, SkPathWriter* path, bool active
if (active) {
bool reverse = ePtr == fPts && start != 0;
if (reverse) {
- path->deferredMoveLine(ePtr[fVerb]);
+ path->deferredMoveLine(ePtr[SkPathOpsVerbToPoints(fVerb)]);
switch (fVerb) {
case SkPath::kLine_Verb:
path->deferredLine(ePtr[0]);
@@ -386,7 +386,7 @@ void SkOpSegment::addCurveTo(int start, int end, SkPathWriter* path, bool active
}
}
}
- // return ePtr[fVerb];
+ // return ePtr[SkPathOpsVerbToPoints(fVerb)];
}
void SkOpSegment::addLine(const SkPoint pts[2], bool operand, bool evenOdd) {
@@ -979,7 +979,7 @@ int SkOpSegment::crossedSpanY(const SkPoint& basePt, SkScalar* bestY, double* hi
SkIntersections intersections;
// OPTIMIZE: use specialty function that intersects ray with curve,
// returning t values only for curve (we don't care about t on ray)
- int pts = (intersections.*CurveVertical[fVerb])(fPts, top, bottom, basePt.fX, false);
+ int pts = (intersections.*CurveVertical[SkPathOpsVerbToPoints(fVerb)])(fPts, top, bottom, basePt.fX, false);
if (pts == 0 || (current && pts == 1)) {
return bestTIndex;
}
@@ -1003,7 +1003,7 @@ int SkOpSegment::crossedSpanY(const SkPoint& basePt, SkScalar* bestY, double* hi
|| approximately_greater_than_one(foundT)) {
continue;
}
- SkScalar testY = (*CurvePointAtT[fVerb])(fPts, foundT).fY;
+ SkScalar testY = (*CurvePointAtT[SkPathOpsVerbToPoints(fVerb)])(fPts, foundT).fY;
if (approximately_negative(testY - *bestY)
|| approximately_negative(basePt.fY - testY)) {
continue;
@@ -1012,7 +1012,7 @@ int SkOpSegment::crossedSpanY(const SkPoint& basePt, SkScalar* bestY, double* hi
return SK_MinS32; // if the intersection is edge on, wait for another one
}
if (fVerb > SkPath::kLine_Verb) {
- SkScalar dx = (*CurveSlopeAtT[fVerb])(fPts, foundT).fX;
+ SkScalar dx = (*CurveSlopeAtT[SkPathOpsVerbToPoints(fVerb)])(fPts, foundT).fX;
if (approximately_zero(dx)) {
return SK_MinS32; // hit vertical, wait for another one
}
@@ -1738,7 +1738,7 @@ the same winding is shared by both.
void SkOpSegment::initWinding(int start, int end, double tHit, int winding, SkScalar hitDx,
int oppWind, SkScalar hitOppDx) {
SkASSERT(hitDx || !winding);
- SkScalar dx = (*CurveSlopeAtT[fVerb])(fPts, tHit).fX;
+ SkScalar dx = (*CurveSlopeAtT[SkPathOpsVerbToPoints(fVerb)])(fPts, tHit).fX;
SkASSERT(dx);
int windVal = windValue(SkMin32(start, end));
#if DEBUG_WINDING_AT_T
@@ -2081,7 +2081,7 @@ bool SkOpSegment::clockwise(int tStart, int tEnd) const {
SkASSERT(fVerb != SkPath::kLine_Verb);
SkPoint edge[4];
subDivide(tStart, tEnd, edge);
- double sum = (edge[0].fX - edge[fVerb].fX) * (edge[0].fY + edge[fVerb].fY);
+ double sum = (edge[0].fX - edge[SkPathOpsVerbToPoints(fVerb)].fX) * (edge[0].fY + edge[SkPathOpsVerbToPoints(fVerb)].fY);
if (fVerb == SkPath::kCubic_Verb) {
SkScalar lesser = SkTMin<SkScalar>(edge[0].fY, edge[3].fY);
if (edge[1].fY < lesser && edge[2].fY < lesser) {
@@ -2095,7 +2095,7 @@ bool SkOpSegment::clockwise(int tStart, int tEnd) const {
}
}
}
- for (int idx = 0; idx < fVerb; ++idx){
+ for (int idx = 0; idx < SkPathOpsVerbToPoints(fVerb); ++idx){
sum += (edge[idx + 1].fX - edge[idx].fX) * (edge[idx + 1].fY + edge[idx].fY);
}
return sum <= 0;
@@ -2365,9 +2365,9 @@ bool SkOpSegment::SortAngles(const SkTDArray<SkOpAngle>& angles,
void SkOpSegment::subDivide(int start, int end, SkPoint edge[4]) const {
edge[0] = fTs[start].fPt;
- edge[fVerb] = fTs[end].fPt;
+ edge[SkPathOpsVerbToPoints(fVerb)] = fTs[end].fPt;
if (fVerb == SkPath::kQuad_Verb || fVerb == SkPath::kCubic_Verb) {
- SkDPoint sub[2] = {{ edge[0].fX, edge[0].fY}, {edge[fVerb].fX, edge[fVerb].fY }};
+ SkDPoint sub[2] = {{ edge[0].fX, edge[0].fY}, {edge[SkPathOpsVerbToPoints(fVerb)].fX, edge[SkPathOpsVerbToPoints(fVerb)].fY }};
if (fVerb == SkPath::kQuad_Verb) {
edge[1] = SkDQuad::SubDivide(fPts, sub[0], sub[1], fTs[start].fT,
fTs[end].fT).asSkPoint();
@@ -2382,7 +2382,7 @@ void SkOpSegment::subDivide(int start, int end, SkPoint edge[4]) const {
void SkOpSegment::subDivideBounds(int start, int end, SkPathOpsBounds* bounds) const {
SkPoint edge[4];
subDivide(start, end, edge);
- (bounds->*SetCurveBounds[fVerb])(edge);
+ (bounds->*SetCurveBounds[SkPathOpsVerbToPoints(fVerb)])(edge);
}
bool SkOpSegment::tiny(const SkOpAngle* angle) const {
@@ -2473,7 +2473,7 @@ int SkOpSegment::windingAtT(double tHit, int tIndex, bool crossOpp, SkScalar* dx
SkDebugf("%s oldWinding=%d windValue=%d", __FUNCTION__, winding, windVal);
#endif
// see if a + change in T results in a +/- change in X (compute x'(T))
- *dx = (*CurveSlopeAtT[fVerb])(fPts, tHit).fX;
+ *dx = (*CurveSlopeAtT[SkPathOpsVerbToPoints(fVerb)])(fPts, tHit).fX;
if (fVerb > SkPath::kLine_Verb && approximately_zero(*dx)) {
*dx = fPts[2].fX - fPts[1].fX - *dx;
}
@@ -2611,7 +2611,7 @@ void SkOpSegment::debugShowActiveSpans() const {
#endif
SkDebugf("%s id=%d", __FUNCTION__, fID);
SkDebugf(" (%1.9g,%1.9g", fPts[0].fX, fPts[0].fY);
- for (int vIndex = 1; vIndex <= fVerb; ++vIndex) {
+ for (int vIndex = 1; vIndex <= SkPathOpsVerbToPoints(fVerb); ++vIndex) {
SkDebugf(" %1.9g,%1.9g", fPts[vIndex].fX, fPts[vIndex].fY);
}
const SkOpSpan* span = &fTs[i];
@@ -2640,7 +2640,7 @@ void SkOpSegment::debugShowNewWinding(const char* fun, const SkOpSpan& span, int
const SkPoint& pt = xyAtT(&span);
SkDebugf("%s id=%d", fun, fID);
SkDebugf(" (%1.9g,%1.9g", fPts[0].fX, fPts[0].fY);
- for (int vIndex = 1; vIndex <= fVerb; ++vIndex) {
+ for (int vIndex = 1; vIndex <= SkPathOpsVerbToPoints(fVerb); ++vIndex) {
SkDebugf(" %1.9g,%1.9g", fPts[vIndex].fX, fPts[vIndex].fY);
}
SkASSERT(&span == &span.fOther->fTs[span.fOtherIndex].fOther->
@@ -2661,7 +2661,7 @@ void SkOpSegment::debugShowNewWinding(const char* fun, const SkOpSpan& span, int
const SkPoint& pt = xyAtT(&span);
SkDebugf("%s id=%d", fun, fID);
SkDebugf(" (%1.9g,%1.9g", fPts[0].fX, fPts[0].fY);
- for (int vIndex = 1; vIndex <= fVerb; ++vIndex) {
+ for (int vIndex = 1; vIndex <= SkPathOpsVerbToPoints(fVerb); ++vIndex) {
SkDebugf(" %1.9g,%1.9g", fPts[vIndex].fX, fPts[vIndex].fY);
}
SkASSERT(&span == &span.fOther->fTs[span.fOtherIndex].fOther->
@@ -2737,7 +2737,7 @@ void SkOpSegment::debugShowSort(const char* fun, const SkTDArray<SkOpAngle*>& an
angle.unsortable() ? "*** UNSORTABLE *** " : "");
#if COMPACT_DEBUG_SORT
SkDebugf("id=%d %s start=%d (%1.9g,%,1.9g) end=%d (%1.9g,%,1.9g)",
- segment.fID, kLVerbStr[segment.fVerb],
+ segment.fID, kLVerbStr[SkPathOpsVerbToPoints(segment.fVerb)],
start, segment.xAtT(&sSpan), segment.yAtT(&sSpan), end,
segment.xAtT(&eSpan), segment.yAtT(&eSpan));
#else
diff --git a/src/pathops/SkOpSegment.h b/src/pathops/SkOpSegment.h
index d2322c8be1..e489acfb02 100644
--- a/src/pathops/SkOpSegment.h
+++ b/src/pathops/SkOpSegment.h
@@ -54,7 +54,7 @@ public:
}
SkVector dxdy(int index) const {
- return (*CurveSlopeAtT[fVerb])(fPts, fTs[index].fT);
+ return (*CurveSlopeAtT[SkPathOpsVerbToPoints(fVerb)])(fPts, fTs[index].fT);
}
SkScalar dy(int index) const {
@@ -82,7 +82,7 @@ public:
}
bool isVertical(int start, int end) const {
- return (*CurveIsVertical[fVerb])(fPts, start, end);
+ return (*CurveIsVertical[SkPathOpsVerbToPoints(fVerb)])(fPts, start, end);
}
bool operand() const {
@@ -206,7 +206,7 @@ public:
// used only by right angle winding finding
SkPoint xyAtT(double mid) const {
- return (*CurvePointAtT[fVerb])(fPts, mid);
+ return (*CurvePointAtT[SkPathOpsVerbToPoints(fVerb)])(fPts, mid);
}
const SkPoint& xyAtT(int index) const {
diff --git a/src/pathops/SkPathOpsTypes.h b/src/pathops/SkPathOpsTypes.h
index 5a5394a0e7..0f689d818e 100644
--- a/src/pathops/SkPathOpsTypes.h
+++ b/src/pathops/SkPathOpsTypes.h
@@ -7,10 +7,13 @@
#ifndef SkPathOpsTypes_DEFINED
#define SkPathOpsTypes_DEFINED
+#define SK_CONIC_SUPPORT_ENABLED 1
+
#include <float.h> // for FLT_EPSILON
#include <math.h> // for fabs, sqrt
#include "SkFloatingPoint.h"
+#include "SkPath.h"
#include "SkPathOps.h"
#include "SkPathOpsDebug.h"
#include "SkScalar.h"
@@ -189,6 +192,47 @@ struct SkDTriangle;
struct SkDCubic;
struct SkDRect;
+#if SK_CONIC_SUPPORT_ENABLED
+
+inline SkPath::Verb SkPathOpsPointsToVerb(int points) {
+ int verb = (1 << points) >> 1;
+#ifdef SK_DEBUG
+ switch (points) {
+ case 0: SkASSERT(SkPath::kMove_Verb == verb); break;
+ case 1: SkASSERT(SkPath::kLine_Verb == verb); break;
+ case 2: SkASSERT(SkPath::kQuad_Verb == verb); break;
+ case 3: SkASSERT(SkPath::kCubic_Verb == verb); break;
+ default: SkASSERT(!"should not be here");
+ }
+#endif
+ return (SkPath::Verb)verb;
+}
+
+inline int SkPathOpsVerbToPoints(SkPath::Verb verb) {
+ int points = (int) verb - ((int) verb >> 2);
+#ifdef SK_DEBUG
+ switch (verb) {
+ case SkPath::kLine_Verb: SkASSERT(1 == points); break;
+ case SkPath::kQuad_Verb: SkASSERT(2 == points); break;
+ case SkPath::kCubic_Verb: SkASSERT(3 == points); break;
+ default: SkASSERT(!"should not get here");
+ }
+#endif
+ return points;
+}
+
+#else
+
+inline SkPath::Verb SkOpPointsToVerb(int points) {
+ return (SkPath::Verb) (points);
+}
+
+inline SkPath::Verb SkOpVerbToPoints(SkPath::Verb verb) {
+ return (int) verb ;
+}
+
+#endif
+
inline double SkDInterp(double A, double B, double t) {
return A + (B - A) * t;
}
diff --git a/src/pathops/SkReduceOrder.cpp b/src/pathops/SkReduceOrder.cpp
index 5410d35ec9..6d2339c276 100644
--- a/src/pathops/SkReduceOrder.cpp
+++ b/src/pathops/SkReduceOrder.cpp
@@ -437,7 +437,7 @@ SkPath::Verb SkReduceOrder::Quad(const SkPoint a[3], SkTDArray<SkPoint>* reduceP
pt->fY = SkDoubleToScalar(reducer.fLine[index].fY);
}
}
- return (SkPath::Verb) (order - 1);
+ return SkPathOpsPointsToVerb(order - 1);
}
SkPath::Verb SkReduceOrder::Cubic(const SkPoint a[4], SkTDArray<SkPoint>* reducePts) {
@@ -452,5 +452,5 @@ SkPath::Verb SkReduceOrder::Cubic(const SkPoint a[4], SkTDArray<SkPoint>* reduce
pt->fY = SkDoubleToScalar(reducer.fQuad[index].fY);
}
}
- return (SkPath::Verb) (order - 1);
+ return SkPathOpsPointsToVerb(order - 1);
}
diff --git a/src/utils/SkDumpCanvas.cpp b/src/utils/SkDumpCanvas.cpp
index 87ddd3153d..593ad0cfb7 100644
--- a/src/utils/SkDumpCanvas.cpp
+++ b/src/utils/SkDumpCanvas.cpp
@@ -84,6 +84,9 @@ static void dumpVerbs(const SkPath& path, SkString* str) {
break;
case SkPath::kDone_Verb:
return;
+ case SkPath::kConic_Verb:
+ SkASSERT(0);
+ break;
}
}
}
diff --git a/src/utils/SkParsePath.cpp b/src/utils/SkParsePath.cpp
index 8c7a4d0df8..4c9923f49f 100644
--- a/src/utils/SkParsePath.cpp
+++ b/src/utils/SkParsePath.cpp
@@ -221,7 +221,10 @@ void SkParsePath::ToSVGString(const SkPath& path, SkString* str) {
for (;;) {
switch (iter.next(pts, false)) {
- case SkPath::kMove_Verb:
+ case SkPath::kConic_Verb:
+ SkASSERT(0);
+ break;
+ case SkPath::kMove_Verb:
append_scalars(&stream, 'M', &pts[0].fX, 2);
break;
case SkPath::kLine_Verb:
diff --git a/tests/PathOpsAngleTest.cpp b/tests/PathOpsAngleTest.cpp
index e0331ec60f..003b8c8317 100644
--- a/tests/PathOpsAngleTest.cpp
+++ b/tests/PathOpsAngleTest.cpp
@@ -8,16 +8,38 @@
#include "Test.h"
static const SkPoint cubics[][4] = {
- {{0, 1}, {2, 6}, {4, 2}, {5, 3}},
- {{10, 234}, {10, 229.581726f}, {13.5817204f, 226}, {18, 226}},
+/* 0 */ {{0, 1}, {2, 6}, {4, 2}, {5, 3}},
+/* 1 */ {{10, 234}, {10, 229.581726f}, {13.5817204f, 226}, {18, 226}},
+/* 2 */ {{132, 11419}, {130.89543151855469f, 11419}, {130, 11418.1044921875f}, {130, 11417}},
+/* 3 */ {{130.04275512695312f, 11417.4130859375f}, {130.23307800292969f, 11418.3193359375f},
+ {131.03709411621094f, 11419}, {132, 11419}},
+/* 4 */ {{0,1}, {0,5}, {4,1}, {6,4}},
+/* 5 */ {{1,5}, {4,6}, {1,0}, {4,0}},
+/* 6 */ {{0,1}, {0,4}, {5,1}, {6,4}},
+/* 7 */ {{0,1}, {1,2}, {1,0}, {6,1}},
+/* 8 */ {{0,3}, {0,1}, {2,0}, {1,0}},
+/* 9 */ {{189,7}, {189,5.3431458473205566f}, {190.3431396484375f,4}, {192,4}},
+/* 10 */ {{0,1}, {1,3}, {1,0}, {6,4}},
+/* 11 */ {{0,1}, {2,3}, {2,1}, {4,3}},
+/* 12 */ {{1,2}, {3,4}, {1,0}, {3,2}},
};
static const SkPoint quads[][3] = {
- {{12.3423996f, 228.342407f}, {10, 230.686295f}, {10, 234}},
+/* 0 */ {{12.3423996f, 228.342407f}, {10, 230.686295f}, {10, 234}},
+/* 1 */ {{304.24319458007812f,591.75677490234375f}, {306,593.51470947265625f}, {306,596}},
};
static const SkPoint lines[][2] = {
- {{6, 2}, {2, 4}},
+/* 0 */ {{6, 2}, {2, 4}},
+/* 1 */ {{306,617}, {306,590}},
+/* 2 */ {{306,596}, {306,617}},
+/* 3 */ {{6,4}, {0,1}},
+/* 4 */ {{6,1}, {0,1}},
+/* 5 */ {{1,0}, {0,3}},
+/* 6 */ {{246,4}, {189,4}},
+/* 7 */ {{192,4}, {243,4}},
+/* 8 */ {{4,3}, {0,1}},
+/* 9 */ {{3,2}, {1,2}},
};
struct SortSet {
@@ -46,14 +68,86 @@ static const SortSet set3[] = {
{quads[0], 3, 1, 0},
};
+static const SortSet set4[] = {
+ {cubics[2], 4, 0.812114222, 1},
+ {cubics[3], 4, 0.0684734759, 0},
+};
+
+static const SortSet set5[] = {
+ {lines[1], 2, 0.777777778, 1},
+ {quads[1], 3, 1, 4.34137342e-06},
+ {lines[2], 2, 0, 1},
+};
+
+static const SortSet set6[] = {
+ {lines[3], 2, 0.407407407, 0.554627832},
+ {cubics[4], 4, 0.666666667, 0.548022446},
+ {lines[3], 2, 0.407407407, 0},
+ {cubics[4], 4, 0.666666667, 1},
+};
+
+static const SortSet set7[] = {
+ {cubics[5], 4, 0.545233342, 0.545454545},
+ {cubics[6], 4, 0.484938134, 0.484805744},
+ {cubics[5], 4, 0.545233342, 0},
+ {cubics[6], 4, 0.484938134, 0.545454545},
+};
+
+static const SortSet set8[] = {
+ {cubics[7], 4, 0.5, 0.522986744 },
+ {lines[4], 2, 0.75, 1},
+ {cubics[7], 4, 0.5, 0},
+ {lines[4], 2, 0.75, 0.737654321},
+};
+
+static const SortSet set9[] = {
+ {cubics[8], 4, 0.4, 1},
+ {lines[5], 2, 0.36, 0},
+ {cubics[8], 4, 0.4, 0.394675838},
+ {lines[5], 2, 0.36, 0.363999782},
+};
+
+static const SortSet set10[] = {
+ {lines[6], 2, 0.947368421, 1},
+ {cubics[9], 4, 1, 0.500000357},
+ {lines[7], 2, 0, 1},
+};
+
+static const SortSet set11[] = {
+ {lines[3], 2, 0.75, 1},
+ {cubics[10], 4, 0.5, 0.228744269},
+ {lines[3], 2, 0.75, 0.627112191},
+ {cubics[10], 4, 0.5, 0.6339746},
+};
+
+static const SortSet set12[] = {
+ {cubics[12], 4, 0.5, 1},
+ {lines[8], 2, 0.5, 1},
+ {cubics[11], 4, 0.5, 0},
+ {lines[9], 2, 0.5, 1},
+ {cubics[12], 4, 0.5, 0},
+ {lines[8], 2, 0.5, 0},
+ {cubics[11], 4, 0.5, 1},
+ {lines[9], 2, 0.5, 0},
+};
+
struct SortSetTests {
const SortSet* set;
size_t count;
};
static const SortSetTests tests[] = {
- { set3, SK_ARRAY_COUNT(set3) },
+ { set12, SK_ARRAY_COUNT(set12) },
+ { set11, SK_ARRAY_COUNT(set11) },
+ { set10, SK_ARRAY_COUNT(set10) },
+ { set9, SK_ARRAY_COUNT(set9) },
+ { set8, SK_ARRAY_COUNT(set8) },
+ { set7, SK_ARRAY_COUNT(set7) },
+ { set6, SK_ARRAY_COUNT(set6) },
{ set2, SK_ARRAY_COUNT(set2) },
+ { set5, SK_ARRAY_COUNT(set5) },
+ { set4, SK_ARRAY_COUNT(set4) },
+ { set3, SK_ARRAY_COUNT(set3) },
{ set1, SK_ARRAY_COUNT(set1) },
};
@@ -122,16 +216,18 @@ static void PathOpsAngleTest(skiatest::Reporter* reporter) {
size_t idxG = idxL + 1;
setup(set, idxG, &greaterData, &greater, greaterTs);
SkOpAngle first, second;
- first.set(lesserData, (SkPath::Verb) (set[idxL].ptCount - 1), &lesser,
+ first.set(lesserData, SkPathOpsPointsToVerb(set[idxL].ptCount - 1), &lesser,
lesserTs[0], lesserTs[1], lesser.spans());
- second.set(greaterData, (SkPath::Verb) (set[idxG].ptCount - 1), &greater,
+ second.set(greaterData, SkPathOpsPointsToVerb(set[idxG].ptCount - 1), &greater,
greaterTs[0], greaterTs[1], greater.spans());
bool compare = first < second;
if (!compare) {
SkDebugf("%s test[%d]: lesser[%d] > greater[%d]\n", __FUNCTION__,
index, idxL, idxG);
+ compare = first < second;
}
REPORTER_ASSERT(reporter, compare);
+ reporter->bumpTestCount();
}
}
}
diff --git a/tests/PathOpsOpTest.cpp b/tests/PathOpsOpTest.cpp
index 08dff90c29..48ed866a90 100644
--- a/tests/PathOpsOpTest.cpp
+++ b/tests/PathOpsOpTest.cpp
@@ -1144,6 +1144,7 @@ static void cubicOp69d(skiatest::Reporter* reporter) {
testPathOp(reporter, path, pathB, kDifference_PathOp);
}
+
SkPathOp ops[] = {
kUnion_PathOp,
kXOR_PathOp,
@@ -1343,9 +1344,175 @@ static void cubicOp70d(skiatest::Reporter* reporter) {
testPathOp(reporter, path, pathB, kDifference_PathOp);
}
-static void (*firstTest)(skiatest::Reporter* ) = 0;
+static void cubicOp71d(skiatest::Reporter* reporter) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(0,1);
+ path.cubicTo(0,5, 4,1, 6,4);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(1,4);
+ pathB.cubicTo(4,6, 1,0, 5,0);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kDifference_PathOp);
+}
+
+static void cubicOp72i(skiatest::Reporter* reporter) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(0,1);
+ path.cubicTo(0,5, 5,2, 5,4);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(2,5);
+ pathB.cubicTo(4,5, 1,0, 5,0);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_PathOp);
+}
+
+static void cubicOp73d(skiatest::Reporter* reporter) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(0,1);
+ path.cubicTo(3,4, 4,0, 6,4);
+ path.lineTo(0,1);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(0,4);
+ pathB.cubicTo(4,6, 1,0, 4,3);
+ pathB.lineTo(0,4);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kDifference_PathOp);
+}
+
+static void cubicOp75d(skiatest::Reporter* reporter) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(0,1);
+ path.cubicTo(0,4, 5,1, 6,4);
+ path.lineTo(0,1);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(1,5);
+ pathB.cubicTo(4,6, 1,0, 4,0);
+ pathB.lineTo(1,5);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kDifference_PathOp);
+}
+
+static void cubicOp77i(skiatest::Reporter* reporter) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(0,1);
+ path.cubicTo(1,3, 2,0, 3,2);
+ path.lineTo(0,1);
+ path.close();
+ pathB.setFillType(SkPath::kEvenOdd_FillType);
+ pathB.moveTo(0,2);
+ pathB.cubicTo(2,3, 1,0, 3,1);
+ pathB.lineTo(0,2);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_PathOp);
+}
+
+static void cubicOp78u(skiatest::Reporter* reporter) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(1,6);
+ path.cubicTo(1,6, 5,0, 6,1);
+ path.lineTo(1,6);
+ path.close();
+ pathB.setFillType(SkPath::kEvenOdd_FillType);
+ pathB.moveTo(0,5);
+ pathB.cubicTo(1,6, 6,1, 6,1);
+ pathB.lineTo(0,5);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kUnion_PathOp);
+}
+
+static void cubicOp79d(skiatest::Reporter* reporter) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(0,2);
+ path.cubicTo(0,1, 3,-0.1f, 1,0);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(0,3);
+ pathB.cubicTo(0,1, 2,0, 1,0);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kDifference_PathOp);
+}
+
+static void cubicOp79u(skiatest::Reporter* reporter) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(0,1);
+ path.cubicTo(1,3, 1,0, 6,4);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(0,1);
+ pathB.cubicTo(4,6, 1,0, 3,1);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_PathOp);
+}
+
+static void cubicOp80i(skiatest::Reporter* reporter) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(0,1);
+ path.cubicTo(2,3, 2,1, 4,3);
+ path.lineTo(0,1);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(1,2);
+ pathB.cubicTo(3,4, 1,0, 3,2);
+ pathB.lineTo(1,2);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_PathOp);
+}
+
+static void cubicOp82i(skiatest::Reporter* reporter) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ path.moveTo(0,1);
+ path.cubicTo(2,3, 5,2, 3,0);
+ path.lineTo(0,1);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(2,5);
+ pathB.cubicTo(0,3, 1,0, 3,2);
+ pathB.lineTo(2,5);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_PathOp);
+}
+
+static void cubicOp81d(skiatest::Reporter* reporter) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(0,1);
+ path.cubicTo(4,6, 4,3, 5,4);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(3,4);
+ pathB.cubicTo(4,5, 1,0, 6,4);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kDifference_PathOp);
+}
+
+static void (*firstTest)(skiatest::Reporter* ) = cubicOp81d;
static struct TestDesc tests[] = {
+ TEST(cubicOp82i),
+ TEST(cubicOp81d),
+ TEST(cubicOp80i),
+ TEST(cubicOp79u),
+ TEST(cubicOp79d),
+ TEST(cubicOp78u),
+ TEST(cubicOp77i),
+ TEST(cubicOp75d),
+ TEST(cubicOp73d),
+ TEST(cubicOp72i),
+ TEST(cubicOp71d),
TEST(skp5),
TEST(skp4),
TEST(skp3),
diff --git a/tests/PathOpsSimplifyTest.cpp b/tests/PathOpsSimplifyTest.cpp
index ce2c89bf7a..f4a332e231 100644
--- a/tests/PathOpsSimplifyTest.cpp
+++ b/tests/PathOpsSimplifyTest.cpp
@@ -3772,7 +3772,7 @@ static void testQuad7(skiatest::Reporter* reporter) {
testSimplify(reporter, path);
}
-static void (*firstTest)(skiatest::Reporter* ) = 0;
+static void (*firstTest)(skiatest::Reporter* ) = testQuadratic85;
static TestDesc tests[] = {
TEST(testQuad7),
diff --git a/tests/PathTest.cpp b/tests/PathTest.cpp
index fa95a35efd..0f59aebe88 100644
--- a/tests/PathTest.cpp
+++ b/tests/PathTest.cpp
@@ -470,6 +470,9 @@ static void test_poly(skiatest::Reporter* reporter, const SkPath& path,
case SkPath::kQuad_Verb:
REPORTER_ASSERT(reporter, !"unexpected quad verb");
break;
+ case SkPath::kConic_Verb:
+ REPORTER_ASSERT(reporter, !"unexpected conic verb");
+ break;
case SkPath::kCubic_Verb:
REPORTER_ASSERT(reporter, !"unexpected cubic verb");
break;
@@ -1969,6 +1972,19 @@ static void test_raw_iter(skiatest::Reporter* reporter) {
numPoints += 2;
lastWasClose = false;
break;
+ case SkPath::kConic_Verb:
+ if (!haveMoveTo) {
+ expectedPts[numPoints++] = lastMoveToPt;
+ expectedVerbs[numIterVerbs++] = SkPath::kMove_Verb;
+ haveMoveTo = true;
+ }
+ expectedPts[numPoints] = randomPts[(rand.nextU() >> 16) % 25];
+ expectedPts[numPoints + 1] = randomPts[(rand.nextU() >> 16) % 25];
+ p.conicTo(expectedPts[numPoints], expectedPts[numPoints + 1],
+ rand.nextUScalar1() * 4);
+ numPoints += 2;
+ lastWasClose = false;
+ break;
case SkPath::kCubic_Verb:
if (!haveMoveTo) {
expectedPts[numPoints++] = lastMoveToPt;
@@ -1988,7 +2004,8 @@ static void test_raw_iter(skiatest::Reporter* reporter) {
haveMoveTo = false;
lastWasClose = true;
break;
- default:;
+ default:
+ SkASSERT(!"unexpected verb");
}
expectedVerbs[numIterVerbs++] = nextVerb;
}
@@ -2019,6 +2036,7 @@ static void test_raw_iter(skiatest::Reporter* reporter) {
numIterPts += 1;
break;
case SkPath::kQuad_Verb:
+ case SkPath::kConic_Verb:
REPORTER_ASSERT(reporter, numIterPts < numPoints + 2);
REPORTER_ASSERT(reporter, pts[0] == lastPt);
REPORTER_ASSERT(reporter, pts[1] == expectedPts[numIterPts]);
@@ -2039,7 +2057,8 @@ static void test_raw_iter(skiatest::Reporter* reporter) {
REPORTER_ASSERT(reporter, pts[0] == lastMoveTo);
lastPt = lastMoveTo;
break;
- default:;
+ default:
+ SkASSERT(!"unexpected verb");
}
}
REPORTER_ASSERT(reporter, numIterPts == numPoints);