add asserts to point<-->verb helpers
patch from issue 16153005 BUG= Review URL: https://codereview.chromium.org/16195004 git-svn-id: http://skia.googlecode.com/svn/trunk@9344 2bbb7eff-a529-9590-31e7-b0007b416f81
This commit is contained in:
parent
a5d3e77420
commit
7950a9eba7
@ -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)],
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -40,6 +40,7 @@ private:
|
||||
|
||||
int fShiftUp;
|
||||
|
||||
public:
|
||||
void addLine(const SkPoint pts[]);
|
||||
void addQuad(const SkPoint pts[]);
|
||||
void addCubic(const SkPoint pts[]);
|
||||
|
@ -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;
|
||||
@ -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()) {
|
||||
|
@ -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);
|
||||
|
@ -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.
|
||||
};
|
||||
|
@ -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) {
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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];
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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()) {
|
||||
|
@ -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
|
||||
|
@ -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 {
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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:
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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),
|
||||
|
@ -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),
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user