| Index: src/core/SkStroke.cpp
|
| diff --git a/src/core/SkStroke.cpp b/src/core/SkStroke.cpp
|
| index 20bd286316d9b33f3f705bd3c69a1cb26a5dbb48..0f02a9449a5c13b3665faf900dd5d07260b46443 100644
|
| --- a/src/core/SkStroke.cpp
|
| +++ b/src/core/SkStroke.cpp
|
| @@ -173,7 +173,6 @@ private:
|
| kSplit_ResultType, // the caller should split the quad stroke in two
|
| kDegenerate_ResultType, // the caller should add a line
|
| kQuad_ResultType, // the caller should (continue to try to) add a quad stroke
|
| - kNormalError_ResultType, // the cubic's normal couldn't be computed -- abort
|
| };
|
|
|
| enum ReductionType {
|
| @@ -207,10 +206,10 @@ private:
|
| void conicQuadEnds(const SkConic& , SkQuadConstruct* ) const;
|
| bool conicStroke(const SkConic& , SkQuadConstruct* );
|
| bool cubicMidOnLine(const SkPoint cubic[4], const SkQuadConstruct* ) const;
|
| - bool cubicPerpRay(const SkPoint cubic[4], SkScalar t, SkPoint* tPt, SkPoint* onPt,
|
| + void cubicPerpRay(const SkPoint cubic[4], SkScalar t, SkPoint* tPt, SkPoint* onPt,
|
| SkPoint* tangent) const;
|
| - bool cubicQuadEnds(const SkPoint cubic[4], SkQuadConstruct* );
|
| - bool cubicQuadMid(const SkPoint cubic[4], const SkQuadConstruct* , SkPoint* mid) const;
|
| + void cubicQuadEnds(const SkPoint cubic[4], SkQuadConstruct* );
|
| + void cubicQuadMid(const SkPoint cubic[4], const SkQuadConstruct* , SkPoint* mid) const;
|
| bool cubicStroke(const SkPoint cubic[4], SkQuadConstruct* );
|
| void init(StrokeType strokeType, SkQuadConstruct* , SkScalar tStart, SkScalar tEnd);
|
| ResultType intersectRay(SkQuadConstruct* , IntersectRayType STROKER_DEBUG_PARAMS(int) ) const;
|
| @@ -786,52 +785,54 @@ void SkPathStroker::conicQuadEnds(const SkConic& conic, SkQuadConstruct* quadPts
|
|
|
|
|
| // Given a cubic and t, return the point on curve, its perpendicular, and the perpendicular tangent.
|
| -// Returns false if the perpendicular could not be computed (because the derivative collapsed to 0)
|
| -bool SkPathStroker::cubicPerpRay(const SkPoint cubic[4], SkScalar t, SkPoint* tPt, SkPoint* onPt,
|
| +void SkPathStroker::cubicPerpRay(const SkPoint cubic[4], SkScalar t, SkPoint* tPt, SkPoint* onPt,
|
| SkPoint* tangent) const {
|
| SkVector dxy;
|
| + SkPoint chopped[7];
|
| SkEvalCubicAt(cubic, t, tPt, &dxy, nullptr);
|
| if (dxy.fX == 0 && dxy.fY == 0) {
|
| + const SkPoint* cPts = cubic;
|
| if (SkScalarNearlyZero(t)) {
|
| dxy = cubic[2] - cubic[0];
|
| } else if (SkScalarNearlyZero(1 - t)) {
|
| dxy = cubic[3] - cubic[1];
|
| } else {
|
| - return false;
|
| + // If the cubic inflection falls on the cusp, subdivide the cubic
|
| + // to find the tangent at that point.
|
| + SkChopCubicAt(cubic, chopped, t);
|
| + dxy = chopped[3] - chopped[2];
|
| + if (dxy.fX == 0 && dxy.fY == 0) {
|
| + dxy = chopped[3] - chopped[1];
|
| + cPts = chopped;
|
| + }
|
| }
|
| if (dxy.fX == 0 && dxy.fY == 0) {
|
| - dxy = cubic[3] - cubic[0];
|
| + dxy = cPts[3] - cPts[0];
|
| }
|
| }
|
| setRayPts(*tPt, &dxy, onPt, tangent);
|
| - return true;
|
| }
|
|
|
| // Given a cubic and a t range, find the start and end if they haven't been found already.
|
| -bool SkPathStroker::cubicQuadEnds(const SkPoint cubic[4], SkQuadConstruct* quadPts) {
|
| +void SkPathStroker::cubicQuadEnds(const SkPoint cubic[4], SkQuadConstruct* quadPts) {
|
| if (!quadPts->fStartSet) {
|
| SkPoint cubicStartPt;
|
| - if (!this->cubicPerpRay(cubic, quadPts->fStartT, &cubicStartPt, &quadPts->fQuad[0],
|
| - &quadPts->fTangentStart)) {
|
| - return false;
|
| - }
|
| + this->cubicPerpRay(cubic, quadPts->fStartT, &cubicStartPt, &quadPts->fQuad[0],
|
| + &quadPts->fTangentStart);
|
| quadPts->fStartSet = true;
|
| }
|
| if (!quadPts->fEndSet) {
|
| SkPoint cubicEndPt;
|
| - if (!this->cubicPerpRay(cubic, quadPts->fEndT, &cubicEndPt, &quadPts->fQuad[2],
|
| - &quadPts->fTangentEnd)) {
|
| - return false;
|
| - }
|
| + this->cubicPerpRay(cubic, quadPts->fEndT, &cubicEndPt, &quadPts->fQuad[2],
|
| + &quadPts->fTangentEnd);
|
| quadPts->fEndSet = true;
|
| }
|
| - return true;
|
| }
|
|
|
| -bool SkPathStroker::cubicQuadMid(const SkPoint cubic[4], const SkQuadConstruct* quadPts,
|
| +void SkPathStroker::cubicQuadMid(const SkPoint cubic[4], const SkQuadConstruct* quadPts,
|
| SkPoint* mid) const {
|
| SkPoint cubicMidPt;
|
| - return this->cubicPerpRay(cubic, quadPts->fMidT, &cubicMidPt, mid, nullptr);
|
| + this->cubicPerpRay(cubic, quadPts->fMidT, &cubicMidPt, mid, nullptr);
|
| }
|
|
|
| // Given a quad and t, return the point on curve, its perpendicular, and the perpendicular tangent.
|
| @@ -905,9 +906,7 @@ SkPathStroker::ResultType SkPathStroker::intersectRay(SkQuadConstruct* quadPts,
|
| // Given a cubic and a t-range, determine if the stroke can be described by a quadratic.
|
| SkPathStroker::ResultType SkPathStroker::tangentsMeet(const SkPoint cubic[4],
|
| SkQuadConstruct* quadPts) {
|
| - if (!this->cubicQuadEnds(cubic, quadPts)) {
|
| - return kNormalError_ResultType;
|
| - }
|
| + this->cubicQuadEnds(cubic, quadPts);
|
| return this->intersectRay(quadPts, kResultType_RayType STROKER_DEBUG_PARAMS(fRecursionDepth));
|
| }
|
|
|
| @@ -1019,9 +1018,7 @@ SkPathStroker::ResultType SkPathStroker::strokeCloseEnough(const SkPoint stroke[
|
| SkPathStroker::ResultType SkPathStroker::compareQuadCubic(const SkPoint cubic[4],
|
| SkQuadConstruct* quadPts) {
|
| // get the quadratic approximation of the stroke
|
| - if (!this->cubicQuadEnds(cubic, quadPts)) {
|
| - return kNormalError_ResultType;
|
| - }
|
| + this->cubicQuadEnds(cubic, quadPts);
|
| ResultType resultType = this->intersectRay(quadPts, kCtrlPt_RayType
|
| STROKER_DEBUG_PARAMS(fRecursionDepth) );
|
| if (resultType != kQuad_ResultType) {
|
| @@ -1029,9 +1026,7 @@ SkPathStroker::ResultType SkPathStroker::compareQuadCubic(const SkPoint cubic[4]
|
| }
|
| // project a ray from the curve to the stroke
|
| SkPoint ray[2]; // points near midpoint on quad, midpoint on cubic
|
| - if (!this->cubicPerpRay(cubic, quadPts->fMidT, &ray[1], &ray[0], nullptr)) {
|
| - return kNormalError_ResultType;
|
| - }
|
| + this->cubicPerpRay(cubic, quadPts->fMidT, &ray[1], &ray[0], nullptr);
|
| return this->strokeCloseEnough(quadPts->fQuad, ray, quadPts
|
| STROKER_DEBUG_PARAMS(fRecursionDepth));
|
| }
|
| @@ -1087,9 +1082,7 @@ void SkPathStroker::addDegenerateLine(const SkQuadConstruct* quadPts) {
|
|
|
| bool SkPathStroker::cubicMidOnLine(const SkPoint cubic[4], const SkQuadConstruct* quadPts) const {
|
| SkPoint strokeMid;
|
| - if (!cubicQuadMid(cubic, quadPts, &strokeMid)) {
|
| - return false;
|
| - }
|
| + this->cubicQuadMid(cubic, quadPts, &strokeMid);
|
| SkScalar dist = pt_to_line(strokeMid, quadPts->fQuad[0], quadPts->fQuad[2]);
|
| return dist < fInvResScaleSquared;
|
| }
|
| @@ -1098,9 +1091,6 @@ bool SkPathStroker::cubicStroke(const SkPoint cubic[4], SkQuadConstruct* quadPts
|
| if (!fFoundTangents) {
|
| ResultType resultType = this->tangentsMeet(cubic, quadPts);
|
| if (kQuad_ResultType != resultType) {
|
| - if (kNormalError_ResultType == resultType) {
|
| - return false;
|
| - }
|
| if ((kDegenerate_ResultType == resultType
|
| || points_within_dist(quadPts->fQuad[0], quadPts->fQuad[2],
|
| fInvResScale)) && cubicMidOnLine(cubic, quadPts)) {
|
| @@ -1125,9 +1115,6 @@ bool SkPathStroker::cubicStroke(const SkPoint cubic[4], SkQuadConstruct* quadPts
|
| return true;
|
| }
|
| }
|
| - if (kNormalError_ResultType == resultType) {
|
| - return false;
|
| - }
|
| }
|
| if (!SkScalarIsFinite(quadPts->fQuad[2].fX) || !SkScalarIsFinite(quadPts->fQuad[2].fY)) {
|
| return false; // just abort if projected quad isn't representable
|
|
|