| 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 | 
|  |