| Index: src/core/SkGeometry.cpp | 
| diff --git a/src/core/SkGeometry.cpp b/src/core/SkGeometry.cpp | 
| index aea1fe56654468a1d57430aaa3c21b0d1c8f32be..284f07e28586c3bf7594dbe974585b0b2ef50560 100644 | 
| --- a/src/core/SkGeometry.cpp | 
| +++ b/src/core/SkGeometry.cpp | 
| @@ -9,6 +9,33 @@ | 
| #include "SkMatrix.h" | 
| #include "Sk2x.h" | 
|  | 
| +static Sk2s from_point(const SkPoint& point) { | 
| +    return Sk2s::Load(&point.fX); | 
| +} | 
| + | 
| +static SkPoint to_point(const Sk2s& x) { | 
| +    SkPoint point; | 
| +    x.store(&point.fX); | 
| +    return point; | 
| +} | 
| + | 
| +static SkVector to_vector(const Sk2s& x) { | 
| +    SkVector vector; | 
| +    x.store(&vector.fX); | 
| +    return vector; | 
| +} | 
| + | 
| +#if 0 | 
| +static Sk2s divide(const Sk2s& numer, const Sk2s& denom) { | 
| +    SkScalar numerStorage[2], denomStorage[2]; | 
| +    numer.store(numerStorage); | 
| +    denom.store(denomStorage); | 
| +    numerStorage[0] /= denomStorage[0]; | 
| +    numerStorage[1] /= denomStorage[1]; | 
| +    return Sk2s::Load(numerStorage); | 
| +} | 
| +#endif | 
| + | 
| /** If defined, this makes eval_quad and eval_cubic do more setup (sometimes | 
| involving integer multiplies by 2 or 3, but fewer calls to SkScalarMul. | 
| May also introduce overflow of fixed when we compute our setup. | 
| @@ -92,6 +119,10 @@ int SkFindUnitQuadRoots(SkScalar A, SkScalar B, SkScalar C, SkScalar roots[2]) { | 
| /////////////////////////////////////////////////////////////////////////////// | 
| /////////////////////////////////////////////////////////////////////////////// | 
|  | 
| +static Sk2s quad_poly_eval(const Sk2s& A, const Sk2s& B, const Sk2s& C, const Sk2s& t) { | 
| +    return (A * t + B) * t + C; | 
| +} | 
| + | 
| static SkScalar eval_quad(const SkScalar src[], SkScalar t) { | 
| SkASSERT(src); | 
| SkASSERT(t >= 0 && t <= SK_Scalar1); | 
| @@ -132,35 +163,31 @@ SkPoint SkEvalQuadAt(const SkPoint src[3], SkScalar t) { | 
| SkASSERT(src); | 
| SkASSERT(t >= 0 && t <= SK_Scalar1); | 
|  | 
| -    const Sk2f t2(t); | 
| +    const Sk2s t2(t); | 
|  | 
| -    Sk2f P0 = Sk2f::Load(&src[0].fX); | 
| -    Sk2f P1 = Sk2f::Load(&src[1].fX); | 
| -    Sk2f P2 = Sk2f::Load(&src[2].fX); | 
| +    Sk2s P0 = from_point(src[0]); | 
| +    Sk2s P1 = from_point(src[1]); | 
| +    Sk2s P2 = from_point(src[2]); | 
|  | 
| -    Sk2f B = P1 - P0; | 
| -    Sk2f A = P2 - P1 - B; | 
| +    Sk2s B = P1 - P0; | 
| +    Sk2s A = P2 - P1 - B; | 
|  | 
| -    SkPoint result; | 
| -    ((A * t2 + B+B) * t2 + P0).store(&result.fX); | 
| -    return result; | 
| +    return to_point((A * t2 + B+B) * t2 + P0); | 
| } | 
|  | 
| SkVector SkEvalQuadTangentAt(const SkPoint src[3], SkScalar t) { | 
| SkASSERT(src); | 
| SkASSERT(t >= 0 && t <= SK_Scalar1); | 
|  | 
| -    Sk2f P0 = Sk2f::Load(&src[0].fX); | 
| -    Sk2f P1 = Sk2f::Load(&src[1].fX); | 
| -    Sk2f P2 = Sk2f::Load(&src[2].fX); | 
| +    Sk2s P0 = from_point(src[0]); | 
| +    Sk2s P1 = from_point(src[1]); | 
| +    Sk2s P2 = from_point(src[2]); | 
|  | 
| -    Sk2f B = P1 - P0; | 
| -    Sk2f A = P2 - P1 - B; | 
| -    Sk2f T = A * Sk2f(t) + B; | 
| +    Sk2s B = P1 - P0; | 
| +    Sk2s A = P2 - P1 - B; | 
| +    Sk2s T = A * Sk2s(t) + B; | 
|  | 
| -    SkVector result; | 
| -    (T + T).store(&result.fX); | 
| -    return result; | 
| +    return to_vector(T + T); | 
| } | 
|  | 
| static void interp_quad_coords(const SkScalar* src, SkScalar* dst, SkScalar t) { | 
| @@ -188,19 +215,19 @@ static inline Sk2s interp(const Sk2s& v0, const Sk2s& v1, const Sk2s& t) { | 
| void SkChopQuadAt2(const SkPoint src[3], SkPoint dst[5], SkScalar t) { | 
| SkASSERT(t > 0 && t < SK_Scalar1); | 
|  | 
| -    Sk2s p0 = Sk2f::Load(&src[0].fX); | 
| -    Sk2s p1 = Sk2f::Load(&src[1].fX); | 
| -    Sk2s p2 = Sk2f::Load(&src[2].fX); | 
| +    Sk2s p0 = from_point(src[0]); | 
| +    Sk2s p1 = from_point(src[1]); | 
| +    Sk2s p2 = from_point(src[2]); | 
| Sk2s tt = Sk2s(t); | 
|  | 
| Sk2s p01 = interp(p0, p1, tt); | 
| Sk2s p12 = interp(p1, p2, tt); | 
|  | 
| -    p0.store(&dst[0].fX); | 
| -    p01.store(&dst[1].fX); | 
| -    interp(p01, p12, tt).store(&dst[2].fX); | 
| -    p12.store(&dst[3].fX); | 
| -    p2.store(&dst[4].fX); | 
| +    dst[0] = to_point(p0); | 
| +    dst[1] = to_point(p01); | 
| +    dst[2] = to_point(interp(p01, p12, tt)); | 
| +    dst[3] = to_point(p12); | 
| +    dst[4] = to_point(p2); | 
| } | 
|  | 
| void SkChopQuadAtHalf(const SkPoint src[3], SkPoint dst[5]) { | 
| @@ -1251,6 +1278,65 @@ void SkConic::chopAt(SkScalar t, SkConic dst[2]) const { | 
| dst[1].fW = tmp2[2].fZ / root; | 
| } | 
|  | 
| +static Sk2s times_2(const Sk2s& value) { | 
| +    return value + value; | 
| +} | 
| + | 
| +SkPoint SkConic::evalAt(SkScalar t) const { | 
| +    Sk2s p0 = from_point(fPts[0]); | 
| +    Sk2s p1 = from_point(fPts[1]); | 
| +    Sk2s p2 = from_point(fPts[2]); | 
| +    Sk2s tt = Sk2s(t); | 
| +    Sk2s ww = Sk2s(fW); | 
| +    Sk2s one = Sk2s(1); | 
| + | 
| +    Sk2s p1w = p1 * ww; | 
| +    Sk2s C = p0; | 
| +    Sk2s A = p2 - times_2(p1w) + p0; | 
| +    Sk2s B = times_2(p1w - C); | 
| +    Sk2s numer = quad_poly_eval(A, B, C, tt); | 
| + | 
| +    B = times_2(ww - one); | 
| +    A = -B; | 
| +    Sk2s denom = quad_poly_eval(A, B, one, tt); | 
| + | 
| +    return to_point(numer / denom); | 
| +} | 
| + | 
| +SkVector SkConic::evalTangentAt(SkScalar t) const { | 
| +    Sk2s p0 = from_point(fPts[0]); | 
| +    Sk2s p1 = from_point(fPts[1]); | 
| +    Sk2s p2 = from_point(fPts[2]); | 
| +    Sk2s ww = Sk2s(fW); | 
| + | 
| +    Sk2s p20 = p2 - p0; | 
| +    Sk2s p10 = p1 - p0; | 
| + | 
| +    Sk2s C = ww * p10; | 
| +    Sk2s A = ww * p20 - p20; | 
| +    Sk2s B = p20 - C - C; | 
| + | 
| +    return to_vector(quad_poly_eval(A, B, C, Sk2s(t))); | 
| +#if 0 | 
| +    static void conic_deriv_coeff(const SkScalar src[], | 
| +                                  SkScalar w, | 
| +                                  SkScalar coeff[3]) { | 
| +        const SkScalar P20 = src[4] - src[0]; | 
| +        const SkScalar P10 = src[2] - src[0]; | 
| +        const SkScalar wP10 = w * P10; | 
| +        coeff[0] = w * P20 - P20; | 
| +        coeff[1] = P20 - 2 * wP10; | 
| +        coeff[2] = wP10; | 
| +    } | 
| + | 
| +    static SkScalar conic_eval_tan(const SkScalar coord[], SkScalar w, SkScalar t) { | 
| +        SkScalar coeff[3]; | 
| +        conic_deriv_coeff(coord, w, coeff); | 
| +        return t * (t * coeff[0] + coeff[1]) + coeff[2]; | 
| +    } | 
| +#endif | 
| +} | 
| + | 
| static SkScalar subdivide_w_value(SkScalar w) { | 
| return SkScalarSqrt(SK_ScalarHalf + w * SK_ScalarHalf); | 
| } | 
| @@ -1275,6 +1361,29 @@ void SkConic::chop(SkConic dst[2]) const { | 
| dst[0].fW = dst[1].fW = subdivide_w_value(fW); | 
| } | 
|  | 
| +void SkConic::chop2(SkConic * SK_RESTRICT dst) const { | 
| +    Sk2s scale(SkScalarInvert(SK_Scalar1 + fW)); | 
| +//    Sk2s scale = Sk2s(SK_Scalar1 + fW).invert(); | 
| +    SkScalar newW = subdivide_w_value(fW); | 
| + | 
| +    Sk2s p0 = from_point(fPts[0]); | 
| +    Sk2s p1 = from_point(fPts[1]); | 
| +    Sk2s p2 = from_point(fPts[2]); | 
| +    Sk2s ww = Sk2s(fW); | 
| +    Sk2s half = Sk2s(0.5f); | 
| + | 
| +    Sk2s wp1 = ww * p1; | 
| +    Sk2s m = ((p0 + wp1 + wp1 + p2) * half) * scale; | 
| + | 
| +    dst[0].fPts[0] = fPts[0]; | 
| +    dst[0].fPts[1] = to_point((p0 + wp1) * scale); | 
| +    dst[0].fPts[2] = dst[1].fPts[0] = to_point(m); | 
| +    dst[1].fPts[1] = to_point((wp1 + p2) * scale); | 
| +    dst[1].fPts[2] = fPts[2]; | 
| + | 
| +    dst[0].fW = dst[1].fW = newW; | 
| +} | 
| + | 
| /* | 
| *  "High order approximation of conic sections by quadratic splines" | 
| *      by Michael Floater, 1993 | 
|  |