16c432337818ff15e553c957d466a67e54684f97brileya@google.com/*
26c432337818ff15e553c957d466a67e54684f97brileya@google.com * Copyright 2012 Google Inc.
36c432337818ff15e553c957d466a67e54684f97brileya@google.com *
46c432337818ff15e553c957d466a67e54684f97brileya@google.com * Use of this source code is governed by a BSD-style license that can be
56c432337818ff15e553c957d466a67e54684f97brileya@google.com * found in the LICENSE file.
66c432337818ff15e553c957d466a67e54684f97brileya@google.com */
76c432337818ff15e553c957d466a67e54684f97brileya@google.com
86c432337818ff15e553c957d466a67e54684f97brileya@google.com#include "SkTwoPointConicalGradient.h"
96c432337818ff15e553c957d466a67e54684f97brileya@google.com
106c432337818ff15e553c957d466a67e54684f97brileya@google.comstatic int valid_divide(float numer, float denom, float* ratio) {
116c432337818ff15e553c957d466a67e54684f97brileya@google.com    SkASSERT(ratio);
126c432337818ff15e553c957d466a67e54684f97brileya@google.com    if (0 == denom) {
136c432337818ff15e553c957d466a67e54684f97brileya@google.com        return 0;
146c432337818ff15e553c957d466a67e54684f97brileya@google.com    }
156c432337818ff15e553c957d466a67e54684f97brileya@google.com    *ratio = numer / denom;
166c432337818ff15e553c957d466a67e54684f97brileya@google.com    return 1;
176c432337818ff15e553c957d466a67e54684f97brileya@google.com}
186c432337818ff15e553c957d466a67e54684f97brileya@google.com
196c432337818ff15e553c957d466a67e54684f97brileya@google.com// Return the number of distinct real roots, and write them into roots[] in
206c432337818ff15e553c957d466a67e54684f97brileya@google.com// ascending order
216c432337818ff15e553c957d466a67e54684f97brileya@google.comstatic int find_quad_roots(float A, float B, float C, float roots[2]) {
226c432337818ff15e553c957d466a67e54684f97brileya@google.com    SkASSERT(roots);
23935e9f4fafdfc64130e6be9ea2bb30e3bafd852armistry@google.com
246c432337818ff15e553c957d466a67e54684f97brileya@google.com    if (A == 0) {
256c432337818ff15e553c957d466a67e54684f97brileya@google.com        return valid_divide(-C, B, roots);
266c432337818ff15e553c957d466a67e54684f97brileya@google.com    }
27935e9f4fafdfc64130e6be9ea2bb30e3bafd852armistry@google.com
286c432337818ff15e553c957d466a67e54684f97brileya@google.com    float R = B*B - 4*A*C;
296c432337818ff15e553c957d466a67e54684f97brileya@google.com    if (R < 0) {
306c432337818ff15e553c957d466a67e54684f97brileya@google.com        return 0;
316c432337818ff15e553c957d466a67e54684f97brileya@google.com    }
326c432337818ff15e553c957d466a67e54684f97brileya@google.com    R = sk_float_sqrt(R);
336c432337818ff15e553c957d466a67e54684f97brileya@google.com
346c432337818ff15e553c957d466a67e54684f97brileya@google.com#if 1
356c432337818ff15e553c957d466a67e54684f97brileya@google.com    float Q = B;
366c432337818ff15e553c957d466a67e54684f97brileya@google.com    if (Q < 0) {
376c432337818ff15e553c957d466a67e54684f97brileya@google.com        Q -= R;
386c432337818ff15e553c957d466a67e54684f97brileya@google.com    } else {
396c432337818ff15e553c957d466a67e54684f97brileya@google.com        Q += R;
406c432337818ff15e553c957d466a67e54684f97brileya@google.com    }
416c432337818ff15e553c957d466a67e54684f97brileya@google.com#else
426c432337818ff15e553c957d466a67e54684f97brileya@google.com    // on 10.6 this was much slower than the above branch :(
436c432337818ff15e553c957d466a67e54684f97brileya@google.com    float Q = B + copysignf(R, B);
446c432337818ff15e553c957d466a67e54684f97brileya@google.com#endif
456c432337818ff15e553c957d466a67e54684f97brileya@google.com    Q *= -0.5f;
466c432337818ff15e553c957d466a67e54684f97brileya@google.com    if (0 == Q) {
476c432337818ff15e553c957d466a67e54684f97brileya@google.com        roots[0] = 0;
486c432337818ff15e553c957d466a67e54684f97brileya@google.com        return 1;
496c432337818ff15e553c957d466a67e54684f97brileya@google.com    }
506c432337818ff15e553c957d466a67e54684f97brileya@google.com
516c432337818ff15e553c957d466a67e54684f97brileya@google.com    float r0 = Q / A;
526c432337818ff15e553c957d466a67e54684f97brileya@google.com    float r1 = C / Q;
536c432337818ff15e553c957d466a67e54684f97brileya@google.com    roots[0] = r0 < r1 ? r0 : r1;
546c432337818ff15e553c957d466a67e54684f97brileya@google.com    roots[1] = r0 > r1 ? r0 : r1;
556c432337818ff15e553c957d466a67e54684f97brileya@google.com    return 2;
566c432337818ff15e553c957d466a67e54684f97brileya@google.com}
576c432337818ff15e553c957d466a67e54684f97brileya@google.com
586c432337818ff15e553c957d466a67e54684f97brileya@google.comstatic float lerp(float x, float dx, float t) {
596c432337818ff15e553c957d466a67e54684f97brileya@google.com    return x + t * dx;
606c432337818ff15e553c957d466a67e54684f97brileya@google.com}
616c432337818ff15e553c957d466a67e54684f97brileya@google.com
626c432337818ff15e553c957d466a67e54684f97brileya@google.comstatic float sqr(float x) { return x * x; }
636c432337818ff15e553c957d466a67e54684f97brileya@google.com
646c432337818ff15e553c957d466a67e54684f97brileya@google.comvoid TwoPtRadial::init(const SkPoint& center0, SkScalar rad0,
656c432337818ff15e553c957d466a67e54684f97brileya@google.com                       const SkPoint& center1, SkScalar rad1) {
666c432337818ff15e553c957d466a67e54684f97brileya@google.com    fCenterX = SkScalarToFloat(center0.fX);
676c432337818ff15e553c957d466a67e54684f97brileya@google.com    fCenterY = SkScalarToFloat(center0.fY);
686c432337818ff15e553c957d466a67e54684f97brileya@google.com    fDCenterX = SkScalarToFloat(center1.fX) - fCenterX;
696c432337818ff15e553c957d466a67e54684f97brileya@google.com    fDCenterY = SkScalarToFloat(center1.fY) - fCenterY;
706c432337818ff15e553c957d466a67e54684f97brileya@google.com    fRadius = SkScalarToFloat(rad0);
716c432337818ff15e553c957d466a67e54684f97brileya@google.com    fDRadius = SkScalarToFloat(rad1) - fRadius;
726c432337818ff15e553c957d466a67e54684f97brileya@google.com
736c432337818ff15e553c957d466a67e54684f97brileya@google.com    fA = sqr(fDCenterX) + sqr(fDCenterY) - sqr(fDRadius);
746c432337818ff15e553c957d466a67e54684f97brileya@google.com    fRadius2 = sqr(fRadius);
756c432337818ff15e553c957d466a67e54684f97brileya@google.com    fRDR = fRadius * fDRadius;
766c432337818ff15e553c957d466a67e54684f97brileya@google.com}
776c432337818ff15e553c957d466a67e54684f97brileya@google.com
786c432337818ff15e553c957d466a67e54684f97brileya@google.comvoid TwoPtRadial::setup(SkScalar fx, SkScalar fy, SkScalar dfx, SkScalar dfy) {
796c432337818ff15e553c957d466a67e54684f97brileya@google.com    fRelX = SkScalarToFloat(fx) - fCenterX;
806c432337818ff15e553c957d466a67e54684f97brileya@google.com    fRelY = SkScalarToFloat(fy) - fCenterY;
816c432337818ff15e553c957d466a67e54684f97brileya@google.com    fIncX = SkScalarToFloat(dfx);
826c432337818ff15e553c957d466a67e54684f97brileya@google.com    fIncY = SkScalarToFloat(dfy);
836c432337818ff15e553c957d466a67e54684f97brileya@google.com    fB = -2 * (fDCenterX * fRelX + fDCenterY * fRelY + fRDR);
846c432337818ff15e553c957d466a67e54684f97brileya@google.com    fDB = -2 * (fDCenterX * fIncX + fDCenterY * fIncY);
856c432337818ff15e553c957d466a67e54684f97brileya@google.com}
866c432337818ff15e553c957d466a67e54684f97brileya@google.com
876c432337818ff15e553c957d466a67e54684f97brileya@google.comSkFixed TwoPtRadial::nextT() {
886c432337818ff15e553c957d466a67e54684f97brileya@google.com    float roots[2];
89935e9f4fafdfc64130e6be9ea2bb30e3bafd852armistry@google.com
906c432337818ff15e553c957d466a67e54684f97brileya@google.com    float C = sqr(fRelX) + sqr(fRelY) - fRadius2;
916c432337818ff15e553c957d466a67e54684f97brileya@google.com    int countRoots = find_quad_roots(fA, fB, C, roots);
926c432337818ff15e553c957d466a67e54684f97brileya@google.com
936c432337818ff15e553c957d466a67e54684f97brileya@google.com    fRelX += fIncX;
946c432337818ff15e553c957d466a67e54684f97brileya@google.com    fRelY += fIncY;
956c432337818ff15e553c957d466a67e54684f97brileya@google.com    fB += fDB;
966c432337818ff15e553c957d466a67e54684f97brileya@google.com
976c432337818ff15e553c957d466a67e54684f97brileya@google.com    if (0 == countRoots) {
986c432337818ff15e553c957d466a67e54684f97brileya@google.com        return kDontDrawT;
996c432337818ff15e553c957d466a67e54684f97brileya@google.com    }
1006c432337818ff15e553c957d466a67e54684f97brileya@google.com
1016c432337818ff15e553c957d466a67e54684f97brileya@google.com    // Prefer the bigger t value if both give a radius(t) > 0
1026c432337818ff15e553c957d466a67e54684f97brileya@google.com    // find_quad_roots returns the values sorted, so we start with the last
1036c432337818ff15e553c957d466a67e54684f97brileya@google.com    float t = roots[countRoots - 1];
1046c432337818ff15e553c957d466a67e54684f97brileya@google.com    float r = lerp(fRadius, fDRadius, t);
1056c432337818ff15e553c957d466a67e54684f97brileya@google.com    if (r <= 0) {
1066c432337818ff15e553c957d466a67e54684f97brileya@google.com        t = roots[0];   // might be the same as roots[countRoots-1]
1076c432337818ff15e553c957d466a67e54684f97brileya@google.com        r = lerp(fRadius, fDRadius, t);
1086c432337818ff15e553c957d466a67e54684f97brileya@google.com        if (r <= 0) {
1096c432337818ff15e553c957d466a67e54684f97brileya@google.com            return kDontDrawT;
1106c432337818ff15e553c957d466a67e54684f97brileya@google.com        }
1116c432337818ff15e553c957d466a67e54684f97brileya@google.com    }
1126c432337818ff15e553c957d466a67e54684f97brileya@google.com    return SkFloatToFixed(t);
1136c432337818ff15e553c957d466a67e54684f97brileya@google.com}
1146c432337818ff15e553c957d466a67e54684f97brileya@google.com
115b0f31cddaad4252e3d5f841b2010c7d1d026e5a2reed@google.comtypedef void (*TwoPointConicalProc)(TwoPtRadial* rec, SkPMColor* dstC,
116b0f31cddaad4252e3d5f841b2010c7d1d026e5a2reed@google.com                                    const SkPMColor* cache, int toggle, int count);
1176c432337818ff15e553c957d466a67e54684f97brileya@google.com
1186c432337818ff15e553c957d466a67e54684f97brileya@google.comstatic void twopoint_clamp(TwoPtRadial* rec, SkPMColor* SK_RESTRICT dstC,
119b0f31cddaad4252e3d5f841b2010c7d1d026e5a2reed@google.com                           const SkPMColor* SK_RESTRICT cache, int toggle,
120b0f31cddaad4252e3d5f841b2010c7d1d026e5a2reed@google.com                           int count) {
1216c432337818ff15e553c957d466a67e54684f97brileya@google.com    for (; count > 0; --count) {
1226c432337818ff15e553c957d466a67e54684f97brileya@google.com        SkFixed t = rec->nextT();
1236c432337818ff15e553c957d466a67e54684f97brileya@google.com        if (TwoPtRadial::DontDrawT(t)) {
1246c432337818ff15e553c957d466a67e54684f97brileya@google.com            *dstC++ = 0;
1256c432337818ff15e553c957d466a67e54684f97brileya@google.com        } else {
1266c432337818ff15e553c957d466a67e54684f97brileya@google.com            SkFixed index = SkClampMax(t, 0xFFFF);
1276c432337818ff15e553c957d466a67e54684f97brileya@google.com            SkASSERT(index <= 0xFFFF);
128b0f31cddaad4252e3d5f841b2010c7d1d026e5a2reed@google.com            *dstC++ = cache[toggle +
129b0f31cddaad4252e3d5f841b2010c7d1d026e5a2reed@google.com                            (index >> SkGradientShaderBase::kCache32Shift)];
1306c432337818ff15e553c957d466a67e54684f97brileya@google.com        }
131b0f31cddaad4252e3d5f841b2010c7d1d026e5a2reed@google.com        toggle = next_dither_toggle(toggle);
1326c432337818ff15e553c957d466a67e54684f97brileya@google.com    }
1336c432337818ff15e553c957d466a67e54684f97brileya@google.com}
1346c432337818ff15e553c957d466a67e54684f97brileya@google.com
1356c432337818ff15e553c957d466a67e54684f97brileya@google.comstatic void twopoint_repeat(TwoPtRadial* rec, SkPMColor* SK_RESTRICT dstC,
136b0f31cddaad4252e3d5f841b2010c7d1d026e5a2reed@google.com                            const SkPMColor* SK_RESTRICT cache, int toggle,
137b0f31cddaad4252e3d5f841b2010c7d1d026e5a2reed@google.com                            int count) {
1386c432337818ff15e553c957d466a67e54684f97brileya@google.com    for (; count > 0; --count) {
1396c432337818ff15e553c957d466a67e54684f97brileya@google.com        SkFixed t = rec->nextT();
1406c432337818ff15e553c957d466a67e54684f97brileya@google.com        if (TwoPtRadial::DontDrawT(t)) {
1416c432337818ff15e553c957d466a67e54684f97brileya@google.com            *dstC++ = 0;
1426c432337818ff15e553c957d466a67e54684f97brileya@google.com        } else {
1436c432337818ff15e553c957d466a67e54684f97brileya@google.com            SkFixed index = repeat_tileproc(t);
1446c432337818ff15e553c957d466a67e54684f97brileya@google.com            SkASSERT(index <= 0xFFFF);
145b0f31cddaad4252e3d5f841b2010c7d1d026e5a2reed@google.com            *dstC++ = cache[toggle +
146b0f31cddaad4252e3d5f841b2010c7d1d026e5a2reed@google.com                            (index >> SkGradientShaderBase::kCache32Shift)];
1476c432337818ff15e553c957d466a67e54684f97brileya@google.com        }
148b0f31cddaad4252e3d5f841b2010c7d1d026e5a2reed@google.com        toggle = next_dither_toggle(toggle);
1496c432337818ff15e553c957d466a67e54684f97brileya@google.com    }
1506c432337818ff15e553c957d466a67e54684f97brileya@google.com}
1516c432337818ff15e553c957d466a67e54684f97brileya@google.com
1526c432337818ff15e553c957d466a67e54684f97brileya@google.comstatic void twopoint_mirror(TwoPtRadial* rec, SkPMColor* SK_RESTRICT dstC,
153b0f31cddaad4252e3d5f841b2010c7d1d026e5a2reed@google.com                            const SkPMColor* SK_RESTRICT cache, int toggle,
154b0f31cddaad4252e3d5f841b2010c7d1d026e5a2reed@google.com                            int count) {
1556c432337818ff15e553c957d466a67e54684f97brileya@google.com    for (; count > 0; --count) {
1566c432337818ff15e553c957d466a67e54684f97brileya@google.com        SkFixed t = rec->nextT();
1576c432337818ff15e553c957d466a67e54684f97brileya@google.com        if (TwoPtRadial::DontDrawT(t)) {
1586c432337818ff15e553c957d466a67e54684f97brileya@google.com            *dstC++ = 0;
1596c432337818ff15e553c957d466a67e54684f97brileya@google.com        } else {
1606c432337818ff15e553c957d466a67e54684f97brileya@google.com            SkFixed index = mirror_tileproc(t);
1616c432337818ff15e553c957d466a67e54684f97brileya@google.com            SkASSERT(index <= 0xFFFF);
162b0f31cddaad4252e3d5f841b2010c7d1d026e5a2reed@google.com            *dstC++ = cache[toggle +
163b0f31cddaad4252e3d5f841b2010c7d1d026e5a2reed@google.com                            (index >> SkGradientShaderBase::kCache32Shift)];
1646c432337818ff15e553c957d466a67e54684f97brileya@google.com        }
165b0f31cddaad4252e3d5f841b2010c7d1d026e5a2reed@google.com        toggle = next_dither_toggle(toggle);
1666c432337818ff15e553c957d466a67e54684f97brileya@google.com    }
1676c432337818ff15e553c957d466a67e54684f97brileya@google.com}
1686c432337818ff15e553c957d466a67e54684f97brileya@google.com
1696c432337818ff15e553c957d466a67e54684f97brileya@google.comvoid SkTwoPointConicalGradient::init() {
1706c432337818ff15e553c957d466a67e54684f97brileya@google.com    fRec.init(fCenter1, fRadius1, fCenter2, fRadius2);
1716c432337818ff15e553c957d466a67e54684f97brileya@google.com    fPtsToUnit.reset();
1726c432337818ff15e553c957d466a67e54684f97brileya@google.com}
1736c432337818ff15e553c957d466a67e54684f97brileya@google.com
174eec72870460a4d1c624307d8ff5aaddbbe0dd25drileya@google.com/////////////////////////////////////////////////////////////////////
175eec72870460a4d1c624307d8ff5aaddbbe0dd25drileya@google.com
1766c432337818ff15e553c957d466a67e54684f97brileya@google.comSkTwoPointConicalGradient::SkTwoPointConicalGradient(
1772d5eaf20bb39e7f90e0294eccf2a598135c7b570reed@google.com        const SkPoint& start, SkScalar startRadius,
1782d5eaf20bb39e7f90e0294eccf2a598135c7b570reed@google.com        const SkPoint& end, SkScalar endRadius,
1792d5eaf20bb39e7f90e0294eccf2a598135c7b570reed@google.com        const Descriptor& desc)
18052d6fb7020e41328b86785a5ea12d42f44f36b8creed@google.com    : SkGradientShaderBase(desc),
1816c432337818ff15e553c957d466a67e54684f97brileya@google.com    fCenter1(start),
1826c432337818ff15e553c957d466a67e54684f97brileya@google.com    fCenter2(end),
1836c432337818ff15e553c957d466a67e54684f97brileya@google.com    fRadius1(startRadius),
1846c432337818ff15e553c957d466a67e54684f97brileya@google.com    fRadius2(endRadius) {
1856c432337818ff15e553c957d466a67e54684f97brileya@google.com    // this is degenerate, and should be caught by our caller
1866c432337818ff15e553c957d466a67e54684f97brileya@google.com    SkASSERT(fCenter1 != fCenter2 || fRadius1 != fRadius2);
1876c432337818ff15e553c957d466a67e54684f97brileya@google.com    this->init();
1886c432337818ff15e553c957d466a67e54684f97brileya@google.com}
1896c432337818ff15e553c957d466a67e54684f97brileya@google.com
190f999f59dac04f742f6c45c2c029d563538e97620commit-bot@chromium.orgbool SkTwoPointConicalGradient::isOpaque() const {
191e3199a12d2e9a33609d9fd25b8d3a09265d055cfrobertphillips@google.com    // Because areas outside the cone are left untouched, we cannot treat the
192e3199a12d2e9a33609d9fd25b8d3a09265d055cfrobertphillips@google.com    // shader as opaque even if the gradient itself is opaque.
193e3199a12d2e9a33609d9fd25b8d3a09265d055cfrobertphillips@google.com    // TODO(junov): Compute whether the cone fills the plane crbug.com/222380
194e3199a12d2e9a33609d9fd25b8d3a09265d055cfrobertphillips@google.com    return false;
195f999f59dac04f742f6c45c2c029d563538e97620commit-bot@chromium.org}
196f999f59dac04f742f6c45c2c029d563538e97620commit-bot@chromium.org
1976c432337818ff15e553c957d466a67e54684f97brileya@google.comvoid SkTwoPointConicalGradient::shadeSpan(int x, int y, SkPMColor* dstCParam,
1986c432337818ff15e553c957d466a67e54684f97brileya@google.com                                          int count) {
199b0f31cddaad4252e3d5f841b2010c7d1d026e5a2reed@google.com    int toggle = init_dither_toggle(x, y);
200b0f31cddaad4252e3d5f841b2010c7d1d026e5a2reed@google.com
2016c432337818ff15e553c957d466a67e54684f97brileya@google.com    SkASSERT(count > 0);
202935e9f4fafdfc64130e6be9ea2bb30e3bafd852armistry@google.com
2036c432337818ff15e553c957d466a67e54684f97brileya@google.com    SkPMColor* SK_RESTRICT dstC = dstCParam;
204935e9f4fafdfc64130e6be9ea2bb30e3bafd852armistry@google.com
2056c432337818ff15e553c957d466a67e54684f97brileya@google.com    SkMatrix::MapXYProc dstProc = fDstToIndexProc;
2069b2cc2b61fa225ce9f0295d5c62140334bb74d17bsalomon@google.com
2076c432337818ff15e553c957d466a67e54684f97brileya@google.com    const SkPMColor* SK_RESTRICT cache = this->getCache32();
2086c432337818ff15e553c957d466a67e54684f97brileya@google.com
209b0f31cddaad4252e3d5f841b2010c7d1d026e5a2reed@google.com    TwoPointConicalProc shadeProc = twopoint_repeat;
2106c432337818ff15e553c957d466a67e54684f97brileya@google.com    if (SkShader::kClamp_TileMode == fTileMode) {
2116c432337818ff15e553c957d466a67e54684f97brileya@google.com        shadeProc = twopoint_clamp;
2126c432337818ff15e553c957d466a67e54684f97brileya@google.com    } else if (SkShader::kMirror_TileMode == fTileMode) {
2136c432337818ff15e553c957d466a67e54684f97brileya@google.com        shadeProc = twopoint_mirror;
2146c432337818ff15e553c957d466a67e54684f97brileya@google.com    } else {
2156c432337818ff15e553c957d466a67e54684f97brileya@google.com        SkASSERT(SkShader::kRepeat_TileMode == fTileMode);
2166c432337818ff15e553c957d466a67e54684f97brileya@google.com    }
217935e9f4fafdfc64130e6be9ea2bb30e3bafd852armistry@google.com
2186c432337818ff15e553c957d466a67e54684f97brileya@google.com    if (fDstToIndexClass != kPerspective_MatrixClass) {
2196c432337818ff15e553c957d466a67e54684f97brileya@google.com        SkPoint srcPt;
2206c432337818ff15e553c957d466a67e54684f97brileya@google.com        dstProc(fDstToIndex, SkIntToScalar(x) + SK_ScalarHalf,
2216c432337818ff15e553c957d466a67e54684f97brileya@google.com                SkIntToScalar(y) + SK_ScalarHalf, &srcPt);
2226c432337818ff15e553c957d466a67e54684f97brileya@google.com        SkScalar dx, fx = srcPt.fX;
2236c432337818ff15e553c957d466a67e54684f97brileya@google.com        SkScalar dy, fy = srcPt.fY;
224935e9f4fafdfc64130e6be9ea2bb30e3bafd852armistry@google.com
2256c432337818ff15e553c957d466a67e54684f97brileya@google.com        if (fDstToIndexClass == kFixedStepInX_MatrixClass) {
2266c432337818ff15e553c957d466a67e54684f97brileya@google.com            SkFixed fixedX, fixedY;
2276c432337818ff15e553c957d466a67e54684f97brileya@google.com            (void)fDstToIndex.fixedStepInX(SkIntToScalar(y), &fixedX, &fixedY);
2286c432337818ff15e553c957d466a67e54684f97brileya@google.com            dx = SkFixedToScalar(fixedX);
2296c432337818ff15e553c957d466a67e54684f97brileya@google.com            dy = SkFixedToScalar(fixedY);
2306c432337818ff15e553c957d466a67e54684f97brileya@google.com        } else {
2316c432337818ff15e553c957d466a67e54684f97brileya@google.com            SkASSERT(fDstToIndexClass == kLinear_MatrixClass);
2326c432337818ff15e553c957d466a67e54684f97brileya@google.com            dx = fDstToIndex.getScaleX();
2336c432337818ff15e553c957d466a67e54684f97brileya@google.com            dy = fDstToIndex.getSkewY();
2346c432337818ff15e553c957d466a67e54684f97brileya@google.com        }
2356c432337818ff15e553c957d466a67e54684f97brileya@google.com
2366c432337818ff15e553c957d466a67e54684f97brileya@google.com        fRec.setup(fx, fy, dx, dy);
237b0f31cddaad4252e3d5f841b2010c7d1d026e5a2reed@google.com        (*shadeProc)(&fRec, dstC, cache, toggle, count);
2386c432337818ff15e553c957d466a67e54684f97brileya@google.com    } else {    // perspective case
239b941e5c71e30ef9150a9dff80de5e393d68dde07mike@reedtribe.org        SkScalar dstX = SkIntToScalar(x) + SK_ScalarHalf;
240b941e5c71e30ef9150a9dff80de5e393d68dde07mike@reedtribe.org        SkScalar dstY = SkIntToScalar(y) + SK_ScalarHalf;
2416c432337818ff15e553c957d466a67e54684f97brileya@google.com        for (; count > 0; --count) {
2426c432337818ff15e553c957d466a67e54684f97brileya@google.com            SkPoint srcPt;
2436c432337818ff15e553c957d466a67e54684f97brileya@google.com            dstProc(fDstToIndex, dstX, dstY, &srcPt);
2446c432337818ff15e553c957d466a67e54684f97brileya@google.com            fRec.setup(srcPt.fX, srcPt.fY, 0, 0);
245b0f31cddaad4252e3d5f841b2010c7d1d026e5a2reed@google.com            (*shadeProc)(&fRec, dstC, cache, toggle, 1);
246b941e5c71e30ef9150a9dff80de5e393d68dde07mike@reedtribe.org
247b941e5c71e30ef9150a9dff80de5e393d68dde07mike@reedtribe.org            dstX += SK_Scalar1;
248b0f31cddaad4252e3d5f841b2010c7d1d026e5a2reed@google.com            toggle = next_dither_toggle(toggle);
249b941e5c71e30ef9150a9dff80de5e393d68dde07mike@reedtribe.org            dstC += 1;
2506c432337818ff15e553c957d466a67e54684f97brileya@google.com        }
2516c432337818ff15e553c957d466a67e54684f97brileya@google.com    }
2526c432337818ff15e553c957d466a67e54684f97brileya@google.com}
2536c432337818ff15e553c957d466a67e54684f97brileya@google.com
2546c432337818ff15e553c957d466a67e54684f97brileya@google.combool SkTwoPointConicalGradient::setContext(const SkBitmap& device,
2556c432337818ff15e553c957d466a67e54684f97brileya@google.com                                           const SkPaint& paint,
2566c432337818ff15e553c957d466a67e54684f97brileya@google.com                                           const SkMatrix& matrix) {
2576c432337818ff15e553c957d466a67e54684f97brileya@google.com    if (!this->INHERITED::setContext(device, paint, matrix)) {
2586c432337818ff15e553c957d466a67e54684f97brileya@google.com        return false;
2596c432337818ff15e553c957d466a67e54684f97brileya@google.com    }
260935e9f4fafdfc64130e6be9ea2bb30e3bafd852armistry@google.com
2616c432337818ff15e553c957d466a67e54684f97brileya@google.com    // we don't have a span16 proc
2626c432337818ff15e553c957d466a67e54684f97brileya@google.com    fFlags &= ~kHasSpan16_Flag;
263935e9f4fafdfc64130e6be9ea2bb30e3bafd852armistry@google.com
2646c432337818ff15e553c957d466a67e54684f97brileya@google.com    // in general, we might discard based on computed-radius, so clear
2656c432337818ff15e553c957d466a67e54684f97brileya@google.com    // this flag (todo: sometimes we can detect that we never discard...)
2666c432337818ff15e553c957d466a67e54684f97brileya@google.com    fFlags &= ~kOpaqueAlpha_Flag;
2676c432337818ff15e553c957d466a67e54684f97brileya@google.com
2686c432337818ff15e553c957d466a67e54684f97brileya@google.com    return true;
2696c432337818ff15e553c957d466a67e54684f97brileya@google.com}
2706c432337818ff15e553c957d466a67e54684f97brileya@google.com
2716c432337818ff15e553c957d466a67e54684f97brileya@google.comSkShader::BitmapType SkTwoPointConicalGradient::asABitmap(
2726c432337818ff15e553c957d466a67e54684f97brileya@google.com    SkBitmap* bitmap, SkMatrix* matrix, SkShader::TileMode* xy) const {
2736c432337818ff15e553c957d466a67e54684f97brileya@google.com    SkPoint diff = fCenter2 - fCenter1;
2746c432337818ff15e553c957d466a67e54684f97brileya@google.com    SkScalar diffLen = 0;
2756c432337818ff15e553c957d466a67e54684f97brileya@google.com
2766c432337818ff15e553c957d466a67e54684f97brileya@google.com    if (bitmap) {
27724a508e688b595f3381afc9a0e9d069e483fa360rileya@google.com        this->getGradientTableBitmap(bitmap);
2786c432337818ff15e553c957d466a67e54684f97brileya@google.com    }
2796c432337818ff15e553c957d466a67e54684f97brileya@google.com    if (matrix) {
2806c432337818ff15e553c957d466a67e54684f97brileya@google.com        diffLen = diff.length();
2816c432337818ff15e553c957d466a67e54684f97brileya@google.com    }
2826c432337818ff15e553c957d466a67e54684f97brileya@google.com    if (matrix) {
2836c432337818ff15e553c957d466a67e54684f97brileya@google.com        if (diffLen) {
2846c432337818ff15e553c957d466a67e54684f97brileya@google.com            SkScalar invDiffLen = SkScalarInvert(diffLen);
2856c432337818ff15e553c957d466a67e54684f97brileya@google.com            // rotate to align circle centers with the x-axis
2866c432337818ff15e553c957d466a67e54684f97brileya@google.com            matrix->setSinCos(-SkScalarMul(invDiffLen, diff.fY),
2876c432337818ff15e553c957d466a67e54684f97brileya@google.com                              SkScalarMul(invDiffLen, diff.fX));
2886c432337818ff15e553c957d466a67e54684f97brileya@google.com        } else {
2896c432337818ff15e553c957d466a67e54684f97brileya@google.com            matrix->reset();
2906c432337818ff15e553c957d466a67e54684f97brileya@google.com        }
2916c432337818ff15e553c957d466a67e54684f97brileya@google.com        matrix->preTranslate(-fCenter1.fX, -fCenter1.fY);
2926c432337818ff15e553c957d466a67e54684f97brileya@google.com    }
2936c432337818ff15e553c957d466a67e54684f97brileya@google.com    if (xy) {
2946c432337818ff15e553c957d466a67e54684f97brileya@google.com        xy[0] = fTileMode;
2956c432337818ff15e553c957d466a67e54684f97brileya@google.com        xy[1] = kClamp_TileMode;
2966c432337818ff15e553c957d466a67e54684f97brileya@google.com    }
2976c432337818ff15e553c957d466a67e54684f97brileya@google.com    return kTwoPointConical_BitmapType;
2986c432337818ff15e553c957d466a67e54684f97brileya@google.com}
2996c432337818ff15e553c957d466a67e54684f97brileya@google.com
3006c432337818ff15e553c957d466a67e54684f97brileya@google.comSkShader::GradientType SkTwoPointConicalGradient::asAGradient(
3016c432337818ff15e553c957d466a67e54684f97brileya@google.com    GradientInfo* info) const {
3026c432337818ff15e553c957d466a67e54684f97brileya@google.com    if (info) {
3036c432337818ff15e553c957d466a67e54684f97brileya@google.com        commonAsAGradient(info);
3046c432337818ff15e553c957d466a67e54684f97brileya@google.com        info->fPoint[0] = fCenter1;
3056c432337818ff15e553c957d466a67e54684f97brileya@google.com        info->fPoint[1] = fCenter2;
3066c432337818ff15e553c957d466a67e54684f97brileya@google.com        info->fRadius[0] = fRadius1;
3076c432337818ff15e553c957d466a67e54684f97brileya@google.com        info->fRadius[1] = fRadius2;
3086c432337818ff15e553c957d466a67e54684f97brileya@google.com    }
3096c432337818ff15e553c957d466a67e54684f97brileya@google.com    return kConical_GradientType;
3106c432337818ff15e553c957d466a67e54684f97brileya@google.com}
3116c432337818ff15e553c957d466a67e54684f97brileya@google.com
3126c432337818ff15e553c957d466a67e54684f97brileya@google.comSkTwoPointConicalGradient::SkTwoPointConicalGradient(
3136c432337818ff15e553c957d466a67e54684f97brileya@google.com    SkFlattenableReadBuffer& buffer)
3146c432337818ff15e553c957d466a67e54684f97brileya@google.com    : INHERITED(buffer),
3156c432337818ff15e553c957d466a67e54684f97brileya@google.com    fCenter1(buffer.readPoint()),
3166c432337818ff15e553c957d466a67e54684f97brileya@google.com    fCenter2(buffer.readPoint()),
3176c432337818ff15e553c957d466a67e54684f97brileya@google.com    fRadius1(buffer.readScalar()),
3186c432337818ff15e553c957d466a67e54684f97brileya@google.com    fRadius2(buffer.readScalar()) {
3196c432337818ff15e553c957d466a67e54684f97brileya@google.com    this->init();
3206c432337818ff15e553c957d466a67e54684f97brileya@google.com};
3216c432337818ff15e553c957d466a67e54684f97brileya@google.com
3226c432337818ff15e553c957d466a67e54684f97brileya@google.comvoid SkTwoPointConicalGradient::flatten(
3236c432337818ff15e553c957d466a67e54684f97brileya@google.com    SkFlattenableWriteBuffer& buffer) const {
3246c432337818ff15e553c957d466a67e54684f97brileya@google.com    this->INHERITED::flatten(buffer);
3256c432337818ff15e553c957d466a67e54684f97brileya@google.com    buffer.writePoint(fCenter1);
3266c432337818ff15e553c957d466a67e54684f97brileya@google.com    buffer.writePoint(fCenter2);
3276c432337818ff15e553c957d466a67e54684f97brileya@google.com    buffer.writeScalar(fRadius1);
3286c432337818ff15e553c957d466a67e54684f97brileya@google.com    buffer.writeScalar(fRadius2);
3296c432337818ff15e553c957d466a67e54684f97brileya@google.com}
3306c432337818ff15e553c957d466a67e54684f97brileya@google.com
3315cf85cab5c294cf70d0d3b52f383de3f9daa4697rileya@google.com/////////////////////////////////////////////////////////////////////
3325cf85cab5c294cf70d0d3b52f383de3f9daa4697rileya@google.com
3333515569a78b58fbb57f20ec909fffde8f945c19cbsalomon@google.com#if SK_SUPPORT_GPU
3343515569a78b58fbb57f20ec909fffde8f945c19cbsalomon@google.com
3358780f037626b5196962a39ab76afd51f094a7765bsalomon@google.com#include "GrTBackendEffectFactory.h"
3368780f037626b5196962a39ab76afd51f094a7765bsalomon@google.com
3375cf85cab5c294cf70d0d3b52f383de3f9daa4697rileya@google.com// For brevity
3385cf85cab5c294cf70d0d3b52f383de3f9daa4697rileya@google.comtypedef GrGLUniformManager::UniformHandle UniformHandle;
3395cf85cab5c294cf70d0d3b52f383de3f9daa4697rileya@google.com
340f30e9eedfba04f5dd131efed491e3a6afd7a3119bsalomon@google.comclass GrGLConical2Gradient : public GrGLGradientEffect {
3415cf85cab5c294cf70d0d3b52f383de3f9daa4697rileya@google.compublic:
3425cf85cab5c294cf70d0d3b52f383de3f9daa4697rileya@google.com
3438bc9236bf27d711cc7fe5cd618b02d29d7c59881bsalomon@google.com    GrGLConical2Gradient(const GrBackendEffectFactory& factory, const GrDrawEffect&);
3445cf85cab5c294cf70d0d3b52f383de3f9daa4697rileya@google.com    virtual ~GrGLConical2Gradient() { }
3455cf85cab5c294cf70d0d3b52f383de3f9daa4697rileya@google.com
3468780f037626b5196962a39ab76afd51f094a7765bsalomon@google.com    virtual void emitCode(GrGLShaderBuilder*,
3478bc9236bf27d711cc7fe5cd618b02d29d7c59881bsalomon@google.com                          const GrDrawEffect&,
3488780f037626b5196962a39ab76afd51f094a7765bsalomon@google.com                          EffectKey,
3498780f037626b5196962a39ab76afd51f094a7765bsalomon@google.com                          const char* outputColor,
3508780f037626b5196962a39ab76afd51f094a7765bsalomon@google.com                          const char* inputColor,
3510a42d756187a602db0d7455bf08fe9b1ced08854bsalomon@google.com                          const TransformedCoordsArray&,
3528780f037626b5196962a39ab76afd51f094a7765bsalomon@google.com                          const TextureSamplerArray&) SK_OVERRIDE;
3538bc9236bf27d711cc7fe5cd618b02d29d7c59881bsalomon@google.com    virtual void setData(const GrGLUniformManager&, const GrDrawEffect&) SK_OVERRIDE;
3545cf85cab5c294cf70d0d3b52f383de3f9daa4697rileya@google.com
3558bc9236bf27d711cc7fe5cd618b02d29d7c59881bsalomon@google.com    static EffectKey GenKey(const GrDrawEffect&, const GrGLCaps& caps);
3565cf85cab5c294cf70d0d3b52f383de3f9daa4697rileya@google.com
3575cf85cab5c294cf70d0d3b52f383de3f9daa4697rileya@google.comprotected:
3585cf85cab5c294cf70d0d3b52f383de3f9daa4697rileya@google.com
359ccebafa609c7f2b789cb329ef293ccbece6ee34acommit-bot@chromium.org    UniformHandle fParamUni;
3605cf85cab5c294cf70d0d3b52f383de3f9daa4697rileya@google.com
3615cf85cab5c294cf70d0d3b52f383de3f9daa4697rileya@google.com    const char* fVSVaryingName;
3625cf85cab5c294cf70d0d3b52f383de3f9daa4697rileya@google.com    const char* fFSVaryingName;
3635cf85cab5c294cf70d0d3b52f383de3f9daa4697rileya@google.com
3645cf85cab5c294cf70d0d3b52f383de3f9daa4697rileya@google.com    bool fIsDegenerate;
3655cf85cab5c294cf70d0d3b52f383de3f9daa4697rileya@google.com
3665cf85cab5c294cf70d0d3b52f383de3f9daa4697rileya@google.com    // @{
3675cf85cab5c294cf70d0d3b52f383de3f9daa4697rileya@google.com    /// Values last uploaded as uniforms
3685cf85cab5c294cf70d0d3b52f383de3f9daa4697rileya@google.com
3693a729be1ae6a0bdfb6a8745f1859e8cb7f23baddbsalomon@google.com    SkScalar fCachedCenter;
3703a729be1ae6a0bdfb6a8745f1859e8cb7f23baddbsalomon@google.com    SkScalar fCachedRadius;
3713a729be1ae6a0bdfb6a8745f1859e8cb7f23baddbsalomon@google.com    SkScalar fCachedDiffRadius;
3725cf85cab5c294cf70d0d3b52f383de3f9daa4697rileya@google.com
3735cf85cab5c294cf70d0d3b52f383de3f9daa4697rileya@google.com    // @}
3745cf85cab5c294cf70d0d3b52f383de3f9daa4697rileya@google.com
3755cf85cab5c294cf70d0d3b52f383de3f9daa4697rileya@google.comprivate:
3765cf85cab5c294cf70d0d3b52f383de3f9daa4697rileya@google.com
377f30e9eedfba04f5dd131efed491e3a6afd7a3119bsalomon@google.com    typedef GrGLGradientEffect INHERITED;
3785cf85cab5c294cf70d0d3b52f383de3f9daa4697rileya@google.com
3795cf85cab5c294cf70d0d3b52f383de3f9daa4697rileya@google.com};
3805cf85cab5c294cf70d0d3b52f383de3f9daa4697rileya@google.com
381eec72870460a4d1c624307d8ff5aaddbbe0dd25drileya@google.com/////////////////////////////////////////////////////////////////////
382eec72870460a4d1c624307d8ff5aaddbbe0dd25drileya@google.com
383eec72870460a4d1c624307d8ff5aaddbbe0dd25drileya@google.comclass GrConical2Gradient : public GrGradientEffect {
384eec72870460a4d1c624307d8ff5aaddbbe0dd25drileya@google.compublic:
385eec72870460a4d1c624307d8ff5aaddbbe0dd25drileya@google.com
38638b58f31a3070ea9254d55894a59528270ac67ddbsalomon@google.com    static GrEffectRef* Create(GrContext* ctx,
38738b58f31a3070ea9254d55894a59528270ac67ddbsalomon@google.com                               const SkTwoPointConicalGradient& shader,
38838b58f31a3070ea9254d55894a59528270ac67ddbsalomon@google.com                               const SkMatrix& matrix,
38938b58f31a3070ea9254d55894a59528270ac67ddbsalomon@google.com                               SkShader::TileMode tm) {
390ba8399f132a172950b49dec019e910ff681928f6bsalomon@google.com        AutoEffectUnref effect(SkNEW_ARGS(GrConical2Gradient, (ctx, shader, matrix, tm)));
39186e2faff92b4e897e1e38e8728f098a5d9d22034bsalomon@google.com        return CreateEffectRef(effect);
39238b58f31a3070ea9254d55894a59528270ac67ddbsalomon@google.com    }
393eec72870460a4d1c624307d8ff5aaddbbe0dd25drileya@google.com
394eec72870460a4d1c624307d8ff5aaddbbe0dd25drileya@google.com    virtual ~GrConical2Gradient() { }
395eec72870460a4d1c624307d8ff5aaddbbe0dd25drileya@google.com
396eec72870460a4d1c624307d8ff5aaddbbe0dd25drileya@google.com    static const char* Name() { return "Two-Point Conical Gradient"; }
3971f64de790a624dc250d3da0789b3ada6251facb7bsalomon@google.com    virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE {
3981f64de790a624dc250d3da0789b3ada6251facb7bsalomon@google.com        return GrTBackendEffectFactory<GrConical2Gradient>::getInstance();
399eec72870460a4d1c624307d8ff5aaddbbe0dd25drileya@google.com    }
400eec72870460a4d1c624307d8ff5aaddbbe0dd25drileya@google.com
401eec72870460a4d1c624307d8ff5aaddbbe0dd25drileya@google.com    // The radial gradient parameters can collapse to a linear (instead of quadratic) equation.
402eec72870460a4d1c624307d8ff5aaddbbe0dd25drileya@google.com    bool isDegenerate() const { return SkScalarAbs(fDiffRadius) == SkScalarAbs(fCenterX1); }
4033a729be1ae6a0bdfb6a8745f1859e8cb7f23baddbsalomon@google.com    SkScalar center() const { return fCenterX1; }
4043a729be1ae6a0bdfb6a8745f1859e8cb7f23baddbsalomon@google.com    SkScalar diffRadius() const { return fDiffRadius; }
4053a729be1ae6a0bdfb6a8745f1859e8cb7f23baddbsalomon@google.com    SkScalar radius() const { return fRadius0; }
406eec72870460a4d1c624307d8ff5aaddbbe0dd25drileya@google.com
407ca5e87e973b87209b5ffa298b8bc6ce0c512a204bsalomon@google.com    typedef GrGLConical2Gradient GLEffect;
408eec72870460a4d1c624307d8ff5aaddbbe0dd25drileya@google.com
409eec72870460a4d1c624307d8ff5aaddbbe0dd25drileya@google.comprivate:
4106a2cef0e27af0600fe1afcc0fcda2f3011371be9bsalomon@google.com    virtual bool onIsEqual(const GrEffect& sBase) const SK_OVERRIDE {
411ba8399f132a172950b49dec019e910ff681928f6bsalomon@google.com        const GrConical2Gradient& s = CastEffect<GrConical2Gradient>(sBase);
412c230a788e0c4339ca1638b79c493055d75ceefc5bsalomon@google.com        return (INHERITED::onIsEqual(sBase) &&
413c230a788e0c4339ca1638b79c493055d75ceefc5bsalomon@google.com                this->fCenterX1 == s.fCenterX1 &&
414c230a788e0c4339ca1638b79c493055d75ceefc5bsalomon@google.com                this->fRadius0 == s.fRadius0 &&
415c230a788e0c4339ca1638b79c493055d75ceefc5bsalomon@google.com                this->fDiffRadius == s.fDiffRadius);
416c230a788e0c4339ca1638b79c493055d75ceefc5bsalomon@google.com    }
417c230a788e0c4339ca1638b79c493055d75ceefc5bsalomon@google.com
41838b58f31a3070ea9254d55894a59528270ac67ddbsalomon@google.com    GrConical2Gradient(GrContext* ctx,
41938b58f31a3070ea9254d55894a59528270ac67ddbsalomon@google.com                       const SkTwoPointConicalGradient& shader,
42038b58f31a3070ea9254d55894a59528270ac67ddbsalomon@google.com                       const SkMatrix& matrix,
42138b58f31a3070ea9254d55894a59528270ac67ddbsalomon@google.com                       SkShader::TileMode tm)
42238b58f31a3070ea9254d55894a59528270ac67ddbsalomon@google.com        : INHERITED(ctx, shader, matrix, tm)
42338b58f31a3070ea9254d55894a59528270ac67ddbsalomon@google.com        , fCenterX1(shader.getCenterX1())
42438b58f31a3070ea9254d55894a59528270ac67ddbsalomon@google.com        , fRadius0(shader.getStartRadius())
425ccebafa609c7f2b789cb329ef293ccbece6ee34acommit-bot@chromium.org        , fDiffRadius(shader.getDiffRadius()) {
426ccebafa609c7f2b789cb329ef293ccbece6ee34acommit-bot@chromium.org        // We pass the linear part of the quadratic as a varying.
427ccebafa609c7f2b789cb329ef293ccbece6ee34acommit-bot@chromium.org        //    float b = -2.0 * (fCenterX1 * x + fRadius0 * fDiffRadius * z)
428ccebafa609c7f2b789cb329ef293ccbece6ee34acommit-bot@chromium.org        fBTransform = this->getCoordTransform();
429ccebafa609c7f2b789cb329ef293ccbece6ee34acommit-bot@chromium.org        SkMatrix& bMatrix = *fBTransform.accessMatrix();
430ccebafa609c7f2b789cb329ef293ccbece6ee34acommit-bot@chromium.org        SkScalar r0dr = SkScalarMul(fRadius0, fDiffRadius);
431ccebafa609c7f2b789cb329ef293ccbece6ee34acommit-bot@chromium.org        bMatrix[SkMatrix::kMScaleX] = -2 * (SkScalarMul(fCenterX1, bMatrix[SkMatrix::kMScaleX]) +
432ccebafa609c7f2b789cb329ef293ccbece6ee34acommit-bot@chromium.org                                            SkScalarMul(r0dr, bMatrix[SkMatrix::kMPersp0]));
433ccebafa609c7f2b789cb329ef293ccbece6ee34acommit-bot@chromium.org        bMatrix[SkMatrix::kMSkewX] = -2 * (SkScalarMul(fCenterX1, bMatrix[SkMatrix::kMSkewX]) +
434ccebafa609c7f2b789cb329ef293ccbece6ee34acommit-bot@chromium.org                                           SkScalarMul(r0dr, bMatrix[SkMatrix::kMPersp1]));
435ccebafa609c7f2b789cb329ef293ccbece6ee34acommit-bot@chromium.org        bMatrix[SkMatrix::kMTransX] = -2 * (SkScalarMul(fCenterX1, bMatrix[SkMatrix::kMTransX]) +
436ccebafa609c7f2b789cb329ef293ccbece6ee34acommit-bot@chromium.org                                            SkScalarMul(r0dr, bMatrix[SkMatrix::kMPersp2]));
437ccebafa609c7f2b789cb329ef293ccbece6ee34acommit-bot@chromium.org        this->addCoordTransform(&fBTransform);
438ccebafa609c7f2b789cb329ef293ccbece6ee34acommit-bot@chromium.org    }
43938b58f31a3070ea9254d55894a59528270ac67ddbsalomon@google.com
4407e0b48a766909be86a2923d909b85c111de4d237bsalomon@google.com    GR_DECLARE_EFFECT_TEST;
441eec72870460a4d1c624307d8ff5aaddbbe0dd25drileya@google.com
442eec72870460a4d1c624307d8ff5aaddbbe0dd25drileya@google.com    // @{
443eec72870460a4d1c624307d8ff5aaddbbe0dd25drileya@google.com    // Cache of values - these can change arbitrarily, EXCEPT
444eec72870460a4d1c624307d8ff5aaddbbe0dd25drileya@google.com    // we shouldn't change between degenerate and non-degenerate?!
445eec72870460a4d1c624307d8ff5aaddbbe0dd25drileya@google.com
446ccebafa609c7f2b789cb329ef293ccbece6ee34acommit-bot@chromium.org    GrCoordTransform fBTransform;
447ccebafa609c7f2b789cb329ef293ccbece6ee34acommit-bot@chromium.org    SkScalar         fCenterX1;
448ccebafa609c7f2b789cb329ef293ccbece6ee34acommit-bot@chromium.org    SkScalar         fRadius0;
449ccebafa609c7f2b789cb329ef293ccbece6ee34acommit-bot@chromium.org    SkScalar         fDiffRadius;
450eec72870460a4d1c624307d8ff5aaddbbe0dd25drileya@google.com
451eec72870460a4d1c624307d8ff5aaddbbe0dd25drileya@google.com    // @}
452eec72870460a4d1c624307d8ff5aaddbbe0dd25drileya@google.com
453eec72870460a4d1c624307d8ff5aaddbbe0dd25drileya@google.com    typedef GrGradientEffect INHERITED;
454eec72870460a4d1c624307d8ff5aaddbbe0dd25drileya@google.com};
455eec72870460a4d1c624307d8ff5aaddbbe0dd25drileya@google.com
4567e0b48a766909be86a2923d909b85c111de4d237bsalomon@google.comGR_DEFINE_EFFECT_TEST(GrConical2Gradient);
45778ab92aa5c32b094205df9565e492d56ddce13cbbsalomon@google.com
458680372190ee596c7485dcf2974c824fcf6a355dccommit-bot@chromium.orgGrEffectRef* GrConical2Gradient::TestCreate(SkRandom* random,
45938b58f31a3070ea9254d55894a59528270ac67ddbsalomon@google.com                                            GrContext* context,
460516b4c312ba95ab60863c325482ee6c36618f706bsalomon@google.com                                            const GrDrawTargetCaps&,
46138b58f31a3070ea9254d55894a59528270ac67ddbsalomon@google.com                                            GrTexture**) {
46278ab92aa5c32b094205df9565e492d56ddce13cbbsalomon@google.com    SkPoint center1 = {random->nextUScalar1(), random->nextUScalar1()};
46378ab92aa5c32b094205df9565e492d56ddce13cbbsalomon@google.com    SkScalar radius1 = random->nextUScalar1();
46478ab92aa5c32b094205df9565e492d56ddce13cbbsalomon@google.com    SkPoint center2;
46578ab92aa5c32b094205df9565e492d56ddce13cbbsalomon@google.com    SkScalar radius2;
46678ab92aa5c32b094205df9565e492d56ddce13cbbsalomon@google.com    do {
4678ab9c69d0b75ef66106bf255c853740d72f65776bsalomon@google.com        center2.set(random->nextUScalar1(), random->nextUScalar1());
46878ab92aa5c32b094205df9565e492d56ddce13cbbsalomon@google.com        radius2 = random->nextUScalar1 ();
46978ab92aa5c32b094205df9565e492d56ddce13cbbsalomon@google.com        // If the circles are identical the factory will give us an empty shader.
47078ab92aa5c32b094205df9565e492d56ddce13cbbsalomon@google.com    } while (radius1 == radius2 && center1 == center2);
471935e9f4fafdfc64130e6be9ea2bb30e3bafd852armistry@google.com
47278ab92aa5c32b094205df9565e492d56ddce13cbbsalomon@google.com    SkColor colors[kMaxRandomGradientColors];
47378ab92aa5c32b094205df9565e492d56ddce13cbbsalomon@google.com    SkScalar stopsArray[kMaxRandomGradientColors];
47478ab92aa5c32b094205df9565e492d56ddce13cbbsalomon@google.com    SkScalar* stops = stopsArray;
47578ab92aa5c32b094205df9565e492d56ddce13cbbsalomon@google.com    SkShader::TileMode tm;
47678ab92aa5c32b094205df9565e492d56ddce13cbbsalomon@google.com    int colorCount = RandomGradientParams(random, colors, &stops, &tm);
47778ab92aa5c32b094205df9565e492d56ddce13cbbsalomon@google.com    SkAutoTUnref<SkShader> shader(SkGradientShader::CreateTwoPointConical(center1, radius1,
47878ab92aa5c32b094205df9565e492d56ddce13cbbsalomon@google.com                                                                          center2, radius2,
47978ab92aa5c32b094205df9565e492d56ddce13cbbsalomon@google.com                                                                          colors, stops, colorCount,
48078ab92aa5c32b094205df9565e492d56ddce13cbbsalomon@google.com                                                                          tm));
48105614588d877c5112445a5a0478619b187c2dbc4bsalomon@google.com    SkPaint paint;
48205614588d877c5112445a5a0478619b187c2dbc4bsalomon@google.com    return shader->asNewEffect(context, paint);
48378ab92aa5c32b094205df9565e492d56ddce13cbbsalomon@google.com}
48478ab92aa5c32b094205df9565e492d56ddce13cbbsalomon@google.com
48578ab92aa5c32b094205df9565e492d56ddce13cbbsalomon@google.com
486eec72870460a4d1c624307d8ff5aaddbbe0dd25drileya@google.com/////////////////////////////////////////////////////////////////////
487eec72870460a4d1c624307d8ff5aaddbbe0dd25drileya@google.com
488ba8399f132a172950b49dec019e910ff681928f6bsalomon@google.comGrGLConical2Gradient::GrGLConical2Gradient(const GrBackendEffectFactory& factory,
4898bc9236bf27d711cc7fe5cd618b02d29d7c59881bsalomon@google.com                                           const GrDrawEffect& drawEffect)
4905cf85cab5c294cf70d0d3b52f383de3f9daa4697rileya@google.com    : INHERITED(factory)
4915cf85cab5c294cf70d0d3b52f383de3f9daa4697rileya@google.com    , fVSVaryingName(NULL)
4925cf85cab5c294cf70d0d3b52f383de3f9daa4697rileya@google.com    , fFSVaryingName(NULL)
4933a729be1ae6a0bdfb6a8745f1859e8cb7f23baddbsalomon@google.com    , fCachedCenter(SK_ScalarMax)
4943a729be1ae6a0bdfb6a8745f1859e8cb7f23baddbsalomon@google.com    , fCachedRadius(-SK_ScalarMax)
4953a729be1ae6a0bdfb6a8745f1859e8cb7f23baddbsalomon@google.com    , fCachedDiffRadius(-SK_ScalarMax) {
4965cf85cab5c294cf70d0d3b52f383de3f9daa4697rileya@google.com
4978bc9236bf27d711cc7fe5cd618b02d29d7c59881bsalomon@google.com    const GrConical2Gradient& data = drawEffect.castEffect<GrConical2Gradient>();
4985cf85cab5c294cf70d0d3b52f383de3f9daa4697rileya@google.com    fIsDegenerate = data.isDegenerate();
4995cf85cab5c294cf70d0d3b52f383de3f9daa4697rileya@google.com}
5005cf85cab5c294cf70d0d3b52f383de3f9daa4697rileya@google.com
5018780f037626b5196962a39ab76afd51f094a7765bsalomon@google.comvoid GrGLConical2Gradient::emitCode(GrGLShaderBuilder* builder,
5028bc9236bf27d711cc7fe5cd618b02d29d7c59881bsalomon@google.com                                    const GrDrawEffect&,
503d2a97043a9a9a8a389afc7c551e76586a3cc93afbsalomon@google.com                                    EffectKey key,
5048780f037626b5196962a39ab76afd51f094a7765bsalomon@google.com                                    const char* outputColor,
5058780f037626b5196962a39ab76afd51f094a7765bsalomon@google.com                                    const char* inputColor,
5060a42d756187a602db0d7455bf08fe9b1ced08854bsalomon@google.com                                    const TransformedCoordsArray& coords,
5078780f037626b5196962a39ab76afd51f094a7765bsalomon@google.com                                    const TextureSamplerArray& samplers) {
508f813e7169d80b7ba2ecd4b2994391202d977db35bsalomon@google.com    this->emitUniforms(builder, key);
509ccebafa609c7f2b789cb329ef293ccbece6ee34acommit-bot@chromium.org    fParamUni = builder->addUniformArray(GrGLShaderBuilder::kFragment_Visibility,
510ccebafa609c7f2b789cb329ef293ccbece6ee34acommit-bot@chromium.org                                         kFloat_GrSLType, "Conical2FSParams", 6);
511ccebafa609c7f2b789cb329ef293ccbece6ee34acommit-bot@chromium.org
512ccebafa609c7f2b789cb329ef293ccbece6ee34acommit-bot@chromium.org    SkString cName("c");
513ccebafa609c7f2b789cb329ef293ccbece6ee34acommit-bot@chromium.org    SkString ac4Name("ac4");
514ccebafa609c7f2b789cb329ef293ccbece6ee34acommit-bot@chromium.org    SkString dName("d");
515ccebafa609c7f2b789cb329ef293ccbece6ee34acommit-bot@chromium.org    SkString qName("q");
516ccebafa609c7f2b789cb329ef293ccbece6ee34acommit-bot@chromium.org    SkString r0Name("r0");
517ccebafa609c7f2b789cb329ef293ccbece6ee34acommit-bot@chromium.org    SkString r1Name("r1");
518ccebafa609c7f2b789cb329ef293ccbece6ee34acommit-bot@chromium.org    SkString tName("t");
519ccebafa609c7f2b789cb329ef293ccbece6ee34acommit-bot@chromium.org    SkString p0; // 4a
520ccebafa609c7f2b789cb329ef293ccbece6ee34acommit-bot@chromium.org    SkString p1; // 1/a
521ccebafa609c7f2b789cb329ef293ccbece6ee34acommit-bot@chromium.org    SkString p2; // distance between centers
522ccebafa609c7f2b789cb329ef293ccbece6ee34acommit-bot@chromium.org    SkString p3; // start radius
523ccebafa609c7f2b789cb329ef293ccbece6ee34acommit-bot@chromium.org    SkString p4; // start radius squared
524ccebafa609c7f2b789cb329ef293ccbece6ee34acommit-bot@chromium.org    SkString p5; // difference in radii (r1 - r0)
525ccebafa609c7f2b789cb329ef293ccbece6ee34acommit-bot@chromium.org
526ccebafa609c7f2b789cb329ef293ccbece6ee34acommit-bot@chromium.org    builder->getUniformVariable(fParamUni).appendArrayAccess(0, &p0);
527ccebafa609c7f2b789cb329ef293ccbece6ee34acommit-bot@chromium.org    builder->getUniformVariable(fParamUni).appendArrayAccess(1, &p1);
528ccebafa609c7f2b789cb329ef293ccbece6ee34acommit-bot@chromium.org    builder->getUniformVariable(fParamUni).appendArrayAccess(2, &p2);
529ccebafa609c7f2b789cb329ef293ccbece6ee34acommit-bot@chromium.org    builder->getUniformVariable(fParamUni).appendArrayAccess(3, &p3);
530ccebafa609c7f2b789cb329ef293ccbece6ee34acommit-bot@chromium.org    builder->getUniformVariable(fParamUni).appendArrayAccess(4, &p4);
531ccebafa609c7f2b789cb329ef293ccbece6ee34acommit-bot@chromium.org    builder->getUniformVariable(fParamUni).appendArrayAccess(5, &p5);
532ccebafa609c7f2b789cb329ef293ccbece6ee34acommit-bot@chromium.org
533ccebafa609c7f2b789cb329ef293ccbece6ee34acommit-bot@chromium.org    // We interpolate the linear component in coords[1].
534ccebafa609c7f2b789cb329ef293ccbece6ee34acommit-bot@chromium.org    SkASSERT(coords[0].type() == coords[1].type());
535ccebafa609c7f2b789cb329ef293ccbece6ee34acommit-bot@chromium.org    const char* coords2D;
536ccebafa609c7f2b789cb329ef293ccbece6ee34acommit-bot@chromium.org    SkString bVar;
537ccebafa609c7f2b789cb329ef293ccbece6ee34acommit-bot@chromium.org    if (kVec3f_GrSLType == coords[0].type()) {
538ccebafa609c7f2b789cb329ef293ccbece6ee34acommit-bot@chromium.org        builder->fsCodeAppendf("\tvec3 interpolants = vec3(%s.xy, %s.x) / %s.z;\n",
539ccebafa609c7f2b789cb329ef293ccbece6ee34acommit-bot@chromium.org                               coords[0].c_str(), coords[1].c_str(), coords[0].c_str());
540ccebafa609c7f2b789cb329ef293ccbece6ee34acommit-bot@chromium.org        coords2D = "interpolants.xy";
541ccebafa609c7f2b789cb329ef293ccbece6ee34acommit-bot@chromium.org        bVar = "interpolants.z";
542ccebafa609c7f2b789cb329ef293ccbece6ee34acommit-bot@chromium.org    } else {
543ccebafa609c7f2b789cb329ef293ccbece6ee34acommit-bot@chromium.org        coords2D = coords[0].c_str();
544ccebafa609c7f2b789cb329ef293ccbece6ee34acommit-bot@chromium.org        bVar.printf("%s.x", coords[1].c_str());
5455cf85cab5c294cf70d0d3b52f383de3f9daa4697rileya@google.com    }
5465cf85cab5c294cf70d0d3b52f383de3f9daa4697rileya@google.com
547ccebafa609c7f2b789cb329ef293ccbece6ee34acommit-bot@chromium.org    // output will default to transparent black (we simply won't write anything
548ccebafa609c7f2b789cb329ef293ccbece6ee34acommit-bot@chromium.org    // else to it if invalid, instead of discarding or returning prematurely)
549ccebafa609c7f2b789cb329ef293ccbece6ee34acommit-bot@chromium.org    builder->fsCodeAppendf("\t%s = vec4(0.0,0.0,0.0,0.0);\n", outputColor);
550ccebafa609c7f2b789cb329ef293ccbece6ee34acommit-bot@chromium.org
551ccebafa609c7f2b789cb329ef293ccbece6ee34acommit-bot@chromium.org    // c = (x^2)+(y^2) - params[4]
552ccebafa609c7f2b789cb329ef293ccbece6ee34acommit-bot@chromium.org    builder->fsCodeAppendf("\tfloat %s = dot(%s, %s) - %s;\n",
553ccebafa609c7f2b789cb329ef293ccbece6ee34acommit-bot@chromium.org                           cName.c_str(), coords2D, coords2D, p4.c_str());
554ccebafa609c7f2b789cb329ef293ccbece6ee34acommit-bot@chromium.org
555ccebafa609c7f2b789cb329ef293ccbece6ee34acommit-bot@chromium.org    // Non-degenerate case (quadratic)
556ccebafa609c7f2b789cb329ef293ccbece6ee34acommit-bot@chromium.org    if (!fIsDegenerate) {
557ccebafa609c7f2b789cb329ef293ccbece6ee34acommit-bot@chromium.org
558ccebafa609c7f2b789cb329ef293ccbece6ee34acommit-bot@chromium.org        // ac4 = params[0] * c
559ccebafa609c7f2b789cb329ef293ccbece6ee34acommit-bot@chromium.org        builder->fsCodeAppendf("\tfloat %s = %s * %s;\n", ac4Name.c_str(), p0.c_str(),
560ccebafa609c7f2b789cb329ef293ccbece6ee34acommit-bot@chromium.org                               cName.c_str());
561ccebafa609c7f2b789cb329ef293ccbece6ee34acommit-bot@chromium.org
562ccebafa609c7f2b789cb329ef293ccbece6ee34acommit-bot@chromium.org        // d = b^2 - ac4
563ccebafa609c7f2b789cb329ef293ccbece6ee34acommit-bot@chromium.org        builder->fsCodeAppendf("\tfloat %s = %s * %s - %s;\n", dName.c_str(),
564ccebafa609c7f2b789cb329ef293ccbece6ee34acommit-bot@chromium.org                               bVar.c_str(), bVar.c_str(), ac4Name.c_str());
565ccebafa609c7f2b789cb329ef293ccbece6ee34acommit-bot@chromium.org
566ccebafa609c7f2b789cb329ef293ccbece6ee34acommit-bot@chromium.org        // only proceed if discriminant is >= 0
567ccebafa609c7f2b789cb329ef293ccbece6ee34acommit-bot@chromium.org        builder->fsCodeAppendf("\tif (%s >= 0.0) {\n", dName.c_str());
568ccebafa609c7f2b789cb329ef293ccbece6ee34acommit-bot@chromium.org
569ccebafa609c7f2b789cb329ef293ccbece6ee34acommit-bot@chromium.org        // intermediate value we'll use to compute the roots
570ccebafa609c7f2b789cb329ef293ccbece6ee34acommit-bot@chromium.org        // q = -0.5 * (b +/- sqrt(d))
571ccebafa609c7f2b789cb329ef293ccbece6ee34acommit-bot@chromium.org        builder->fsCodeAppendf("\t\tfloat %s = -0.5 * (%s + (%s < 0.0 ? -1.0 : 1.0)"
572ccebafa609c7f2b789cb329ef293ccbece6ee34acommit-bot@chromium.org                               " * sqrt(%s));\n", qName.c_str(), bVar.c_str(),
573ccebafa609c7f2b789cb329ef293ccbece6ee34acommit-bot@chromium.org                               bVar.c_str(), dName.c_str());
574ccebafa609c7f2b789cb329ef293ccbece6ee34acommit-bot@chromium.org
575ccebafa609c7f2b789cb329ef293ccbece6ee34acommit-bot@chromium.org        // compute both roots
576ccebafa609c7f2b789cb329ef293ccbece6ee34acommit-bot@chromium.org        // r0 = q * params[1]
577ccebafa609c7f2b789cb329ef293ccbece6ee34acommit-bot@chromium.org        builder->fsCodeAppendf("\t\tfloat %s = %s * %s;\n", r0Name.c_str(),
578ccebafa609c7f2b789cb329ef293ccbece6ee34acommit-bot@chromium.org                               qName.c_str(), p1.c_str());
579ccebafa609c7f2b789cb329ef293ccbece6ee34acommit-bot@chromium.org        // r1 = c / q
580ccebafa609c7f2b789cb329ef293ccbece6ee34acommit-bot@chromium.org        builder->fsCodeAppendf("\t\tfloat %s = %s / %s;\n", r1Name.c_str(),
581ccebafa609c7f2b789cb329ef293ccbece6ee34acommit-bot@chromium.org                               cName.c_str(), qName.c_str());
582ccebafa609c7f2b789cb329ef293ccbece6ee34acommit-bot@chromium.org
583ccebafa609c7f2b789cb329ef293ccbece6ee34acommit-bot@chromium.org        // Note: If there are two roots that both generate radius(t) > 0, the
584ccebafa609c7f2b789cb329ef293ccbece6ee34acommit-bot@chromium.org        // Canvas spec says to choose the larger t.
585ccebafa609c7f2b789cb329ef293ccbece6ee34acommit-bot@chromium.org
586ccebafa609c7f2b789cb329ef293ccbece6ee34acommit-bot@chromium.org        // so we'll look at the larger one first:
587ccebafa609c7f2b789cb329ef293ccbece6ee34acommit-bot@chromium.org        builder->fsCodeAppendf("\t\tfloat %s = max(%s, %s);\n", tName.c_str(),
588ccebafa609c7f2b789cb329ef293ccbece6ee34acommit-bot@chromium.org                               r0Name.c_str(), r1Name.c_str());
589ccebafa609c7f2b789cb329ef293ccbece6ee34acommit-bot@chromium.org
590ccebafa609c7f2b789cb329ef293ccbece6ee34acommit-bot@chromium.org        // if r(t) > 0, then we're done; t will be our x coordinate
591ccebafa609c7f2b789cb329ef293ccbece6ee34acommit-bot@chromium.org        builder->fsCodeAppendf("\t\tif (%s * %s + %s > 0.0) {\n", tName.c_str(),
592ccebafa609c7f2b789cb329ef293ccbece6ee34acommit-bot@chromium.org                               p5.c_str(), p3.c_str());
593ccebafa609c7f2b789cb329ef293ccbece6ee34acommit-bot@chromium.org
594ccebafa609c7f2b789cb329ef293ccbece6ee34acommit-bot@chromium.org        builder->fsCodeAppend("\t\t");
595ccebafa609c7f2b789cb329ef293ccbece6ee34acommit-bot@chromium.org        this->emitColor(builder, tName.c_str(), key, outputColor, inputColor, samplers);
596ccebafa609c7f2b789cb329ef293ccbece6ee34acommit-bot@chromium.org
597ccebafa609c7f2b789cb329ef293ccbece6ee34acommit-bot@chromium.org        // otherwise, if r(t) for the larger root was <= 0, try the other root
598ccebafa609c7f2b789cb329ef293ccbece6ee34acommit-bot@chromium.org        builder->fsCodeAppend("\t\t} else {\n");
599ccebafa609c7f2b789cb329ef293ccbece6ee34acommit-bot@chromium.org        builder->fsCodeAppendf("\t\t\t%s = min(%s, %s);\n", tName.c_str(),
600ccebafa609c7f2b789cb329ef293ccbece6ee34acommit-bot@chromium.org                               r0Name.c_str(), r1Name.c_str());
601ccebafa609c7f2b789cb329ef293ccbece6ee34acommit-bot@chromium.org
602ccebafa609c7f2b789cb329ef293ccbece6ee34acommit-bot@chromium.org        // if r(t) > 0 for the smaller root, then t will be our x coordinate
603ccebafa609c7f2b789cb329ef293ccbece6ee34acommit-bot@chromium.org        builder->fsCodeAppendf("\t\t\tif (%s * %s + %s > 0.0) {\n",
604ccebafa609c7f2b789cb329ef293ccbece6ee34acommit-bot@chromium.org                               tName.c_str(), p5.c_str(), p3.c_str());
605ccebafa609c7f2b789cb329ef293ccbece6ee34acommit-bot@chromium.org
606ccebafa609c7f2b789cb329ef293ccbece6ee34acommit-bot@chromium.org        builder->fsCodeAppend("\t\t\t");
607ccebafa609c7f2b789cb329ef293ccbece6ee34acommit-bot@chromium.org        this->emitColor(builder, tName.c_str(), key, outputColor, inputColor, samplers);
608ccebafa609c7f2b789cb329ef293ccbece6ee34acommit-bot@chromium.org
609ccebafa609c7f2b789cb329ef293ccbece6ee34acommit-bot@chromium.org        // end if (r(t) > 0) for smaller root
610ccebafa609c7f2b789cb329ef293ccbece6ee34acommit-bot@chromium.org        builder->fsCodeAppend("\t\t\t}\n");
611ccebafa609c7f2b789cb329ef293ccbece6ee34acommit-bot@chromium.org        // end if (r(t) > 0), else, for larger root
612ccebafa609c7f2b789cb329ef293ccbece6ee34acommit-bot@chromium.org        builder->fsCodeAppend("\t\t}\n");
613ccebafa609c7f2b789cb329ef293ccbece6ee34acommit-bot@chromium.org        // end if (discriminant >= 0)
614ccebafa609c7f2b789cb329ef293ccbece6ee34acommit-bot@chromium.org        builder->fsCodeAppend("\t}\n");
615ccebafa609c7f2b789cb329ef293ccbece6ee34acommit-bot@chromium.org    } else {
6165cf85cab5c294cf70d0d3b52f383de3f9daa4697rileya@google.com
617ccebafa609c7f2b789cb329ef293ccbece6ee34acommit-bot@chromium.org        // linear case: t = -c/b
618ccebafa609c7f2b789cb329ef293ccbece6ee34acommit-bot@chromium.org        builder->fsCodeAppendf("\tfloat %s = -(%s / %s);\n", tName.c_str(),
619ccebafa609c7f2b789cb329ef293ccbece6ee34acommit-bot@chromium.org                               cName.c_str(), bVar.c_str());
6205cf85cab5c294cf70d0d3b52f383de3f9daa4697rileya@google.com
621ccebafa609c7f2b789cb329ef293ccbece6ee34acommit-bot@chromium.org        // if r(t) > 0, then t will be the x coordinate
622ccebafa609c7f2b789cb329ef293ccbece6ee34acommit-bot@chromium.org        builder->fsCodeAppendf("\tif (%s * %s + %s > 0.0) {\n", tName.c_str(),
623ccebafa609c7f2b789cb329ef293ccbece6ee34acommit-bot@chromium.org                               p5.c_str(), p3.c_str());
624ccebafa609c7f2b789cb329ef293ccbece6ee34acommit-bot@chromium.org        builder->fsCodeAppend("\t");
625ccebafa609c7f2b789cb329ef293ccbece6ee34acommit-bot@chromium.org        this->emitColor(builder, tName.c_str(), key, outputColor, inputColor, samplers);
626ccebafa609c7f2b789cb329ef293ccbece6ee34acommit-bot@chromium.org        builder->fsCodeAppend("\t}\n");
6275cf85cab5c294cf70d0d3b52f383de3f9daa4697rileya@google.com    }
6285cf85cab5c294cf70d0d3b52f383de3f9daa4697rileya@google.com}
6295cf85cab5c294cf70d0d3b52f383de3f9daa4697rileya@google.com
6308bc9236bf27d711cc7fe5cd618b02d29d7c59881bsalomon@google.comvoid GrGLConical2Gradient::setData(const GrGLUniformManager& uman,
6318bc9236bf27d711cc7fe5cd618b02d29d7c59881bsalomon@google.com                                   const GrDrawEffect& drawEffect) {
6328bc9236bf27d711cc7fe5cd618b02d29d7c59881bsalomon@google.com    INHERITED::setData(uman, drawEffect);
6338bc9236bf27d711cc7fe5cd618b02d29d7c59881bsalomon@google.com    const GrConical2Gradient& data = drawEffect.castEffect<GrConical2Gradient>();
634c0b28fb2217fefe54708b591b5aa202a5615f551commit-bot@chromium.org    SkASSERT(data.isDegenerate() == fIsDegenerate);
6353a729be1ae6a0bdfb6a8745f1859e8cb7f23baddbsalomon@google.com    SkScalar centerX1 = data.center();
6363a729be1ae6a0bdfb6a8745f1859e8cb7f23baddbsalomon@google.com    SkScalar radius0 = data.radius();
6373a729be1ae6a0bdfb6a8745f1859e8cb7f23baddbsalomon@google.com    SkScalar diffRadius = data.diffRadius();
6385cf85cab5c294cf70d0d3b52f383de3f9daa4697rileya@google.com
6395cf85cab5c294cf70d0d3b52f383de3f9daa4697rileya@google.com    if (fCachedCenter != centerX1 ||
6405cf85cab5c294cf70d0d3b52f383de3f9daa4697rileya@google.com        fCachedRadius != radius0 ||
6415cf85cab5c294cf70d0d3b52f383de3f9daa4697rileya@google.com        fCachedDiffRadius != diffRadius) {
6425cf85cab5c294cf70d0d3b52f383de3f9daa4697rileya@google.com
6433a729be1ae6a0bdfb6a8745f1859e8cb7f23baddbsalomon@google.com        SkScalar a = SkScalarMul(centerX1, centerX1) - diffRadius * diffRadius;
6445cf85cab5c294cf70d0d3b52f383de3f9daa4697rileya@google.com
6455cf85cab5c294cf70d0d3b52f383de3f9daa4697rileya@google.com        // When we're in the degenerate (linear) case, the second
6465cf85cab5c294cf70d0d3b52f383de3f9daa4697rileya@google.com        // value will be INF but the program doesn't read it. (We
6475cf85cab5c294cf70d0d3b52f383de3f9daa4697rileya@google.com        // use the same 6 uniforms even though we don't need them
6485cf85cab5c294cf70d0d3b52f383de3f9daa4697rileya@google.com        // all in the linear case just to keep the code complexity
6495cf85cab5c294cf70d0d3b52f383de3f9daa4697rileya@google.com        // down).
6505cf85cab5c294cf70d0d3b52f383de3f9daa4697rileya@google.com        float values[6] = {
6513a729be1ae6a0bdfb6a8745f1859e8cb7f23baddbsalomon@google.com            SkScalarToFloat(a * 4),
6523a729be1ae6a0bdfb6a8745f1859e8cb7f23baddbsalomon@google.com            1.f / (SkScalarToFloat(a)),
6533a729be1ae6a0bdfb6a8745f1859e8cb7f23baddbsalomon@google.com            SkScalarToFloat(centerX1),
6543a729be1ae6a0bdfb6a8745f1859e8cb7f23baddbsalomon@google.com            SkScalarToFloat(radius0),
6553a729be1ae6a0bdfb6a8745f1859e8cb7f23baddbsalomon@google.com            SkScalarToFloat(SkScalarMul(radius0, radius0)),
6563a729be1ae6a0bdfb6a8745f1859e8cb7f23baddbsalomon@google.com            SkScalarToFloat(diffRadius)
6575cf85cab5c294cf70d0d3b52f383de3f9daa4697rileya@google.com        };
6585cf85cab5c294cf70d0d3b52f383de3f9daa4697rileya@google.com
65922fedc5d469a05bf11cc6d798529f07899402ecacommit-bot@chromium.org        uman.set1fv(fParamUni, 6, values);
6605cf85cab5c294cf70d0d3b52f383de3f9daa4697rileya@google.com        fCachedCenter = centerX1;
6615cf85cab5c294cf70d0d3b52f383de3f9daa4697rileya@google.com        fCachedRadius = radius0;
6625cf85cab5c294cf70d0d3b52f383de3f9daa4697rileya@google.com        fCachedDiffRadius = diffRadius;
6635cf85cab5c294cf70d0d3b52f383de3f9daa4697rileya@google.com    }
6645cf85cab5c294cf70d0d3b52f383de3f9daa4697rileya@google.com}
6655cf85cab5c294cf70d0d3b52f383de3f9daa4697rileya@google.com
6668bc9236bf27d711cc7fe5cd618b02d29d7c59881bsalomon@google.comGrGLEffect::EffectKey GrGLConical2Gradient::GenKey(const GrDrawEffect& drawEffect,
6678bc9236bf27d711cc7fe5cd618b02d29d7c59881bsalomon@google.com                                                   const GrGLCaps&) {
668d2a97043a9a9a8a389afc7c551e76586a3cc93afbsalomon@google.com    enum {
669f813e7169d80b7ba2ecd4b2994391202d977db35bsalomon@google.com        kIsDegenerate = 1 << kBaseKeyBitCnt,
670d2a97043a9a9a8a389afc7c551e76586a3cc93afbsalomon@google.com    };
671d2a97043a9a9a8a389afc7c551e76586a3cc93afbsalomon@google.com
672f813e7169d80b7ba2ecd4b2994391202d977db35bsalomon@google.com    EffectKey key = GenBaseGradientKey(drawEffect);
6738bc9236bf27d711cc7fe5cd618b02d29d7c59881bsalomon@google.com    if (drawEffect.castEffect<GrConical2Gradient>().isDegenerate()) {
674d2a97043a9a9a8a389afc7c551e76586a3cc93afbsalomon@google.com        key |= kIsDegenerate;
675d2a97043a9a9a8a389afc7c551e76586a3cc93afbsalomon@google.com    }
676d2a97043a9a9a8a389afc7c551e76586a3cc93afbsalomon@google.com    return key;
6775cf85cab5c294cf70d0d3b52f383de3f9daa4697rileya@google.com}
6785cf85cab5c294cf70d0d3b52f383de3f9daa4697rileya@google.com
679eec72870460a4d1c624307d8ff5aaddbbe0dd25drileya@google.com/////////////////////////////////////////////////////////////////////
6805cf85cab5c294cf70d0d3b52f383de3f9daa4697rileya@google.com
68138b58f31a3070ea9254d55894a59528270ac67ddbsalomon@google.comGrEffectRef* SkTwoPointConicalGradient::asNewEffect(GrContext* context, const SkPaint&) const {
682f40b3ce485ed2e115920f5d9f7898da18d6ba7cebsalomon@google.com    SkASSERT(NULL != context);
683b6fb9ce9ba1cc23ecb656cfeb76b8e1fe9792adcbsalomon@google.com    SkASSERT(fPtsToUnit.isIdentity());
684b6fb9ce9ba1cc23ecb656cfeb76b8e1fe9792adcbsalomon@google.com    // invert the localM, translate to center1, rotate so center2 is on x axis.
68507d48f7919dea4b366b76b1f40319141051eb816bsalomon@google.com    SkMatrix matrix;
686b6fb9ce9ba1cc23ecb656cfeb76b8e1fe9792adcbsalomon@google.com    if (!this->getLocalMatrix().invert(&matrix)) {
687f03531dacf0572e4d2c544c8b3a56178ad2a7d36humper@google.com        return NULL;
688b6fb9ce9ba1cc23ecb656cfeb76b8e1fe9792adcbsalomon@google.com    }
689b6fb9ce9ba1cc23ecb656cfeb76b8e1fe9792adcbsalomon@google.com    matrix.postTranslate(-fCenter1.fX, -fCenter1.fY);
690b6fb9ce9ba1cc23ecb656cfeb76b8e1fe9792adcbsalomon@google.com
691eec72870460a4d1c624307d8ff5aaddbbe0dd25drileya@google.com    SkPoint diff = fCenter2 - fCenter1;
692eec72870460a4d1c624307d8ff5aaddbbe0dd25drileya@google.com    SkScalar diffLen = diff.length();
693eec72870460a4d1c624307d8ff5aaddbbe0dd25drileya@google.com    if (0 != diffLen) {
694eec72870460a4d1c624307d8ff5aaddbbe0dd25drileya@google.com        SkScalar invDiffLen = SkScalarInvert(diffLen);
695b6fb9ce9ba1cc23ecb656cfeb76b8e1fe9792adcbsalomon@google.com        SkMatrix rot;
696b6fb9ce9ba1cc23ecb656cfeb76b8e1fe9792adcbsalomon@google.com        rot.setSinCos(-SkScalarMul(invDiffLen, diff.fY),
697b6fb9ce9ba1cc23ecb656cfeb76b8e1fe9792adcbsalomon@google.com                       SkScalarMul(invDiffLen, diff.fX));
698b6fb9ce9ba1cc23ecb656cfeb76b8e1fe9792adcbsalomon@google.com        matrix.postConcat(rot);
699eec72870460a4d1c624307d8ff5aaddbbe0dd25drileya@google.com    }
70007d48f7919dea4b366b76b1f40319141051eb816bsalomon@google.com
70138b58f31a3070ea9254d55894a59528270ac67ddbsalomon@google.com    return GrConical2Gradient::Create(context, *this, matrix, fTileMode);
7025cf85cab5c294cf70d0d3b52f383de3f9daa4697rileya@google.com}
7035cf85cab5c294cf70d0d3b52f383de3f9daa4697rileya@google.com
7043515569a78b58fbb57f20ec909fffde8f945c19cbsalomon@google.com#else
7053515569a78b58fbb57f20ec909fffde8f945c19cbsalomon@google.com
70659d9bca234df359715bcfc1d2046315c94c3e23dbsalomon@google.comGrEffectRef* SkTwoPointConicalGradient::asNewEffect(GrContext*, const SkPaint&) const {
7073515569a78b58fbb57f20ec909fffde8f945c19cbsalomon@google.com    SkDEBUGFAIL("Should not call in GPU-less build");
70805614588d877c5112445a5a0478619b187c2dbc4bsalomon@google.com    return NULL;
7093515569a78b58fbb57f20ec909fffde8f945c19cbsalomon@google.com}
7103515569a78b58fbb57f20ec909fffde8f945c19cbsalomon@google.com
711069700aef2be72c711e7f665e2250c41a83bd6datwiz@google.com#endif
712bc0c7b3fc892adc21eeac2d56b02a525ee811fdbrobertphillips@google.com
713bc0c7b3fc892adc21eeac2d56b02a525ee811fdbrobertphillips@google.com#ifdef SK_DEVELOPER
714bc0c7b3fc892adc21eeac2d56b02a525ee811fdbrobertphillips@google.comvoid SkTwoPointConicalGradient::toString(SkString* str) const {
715bc0c7b3fc892adc21eeac2d56b02a525ee811fdbrobertphillips@google.com    str->append("SkTwoPointConicalGradient: (");
716bc0c7b3fc892adc21eeac2d56b02a525ee811fdbrobertphillips@google.com
717bc0c7b3fc892adc21eeac2d56b02a525ee811fdbrobertphillips@google.com    str->append("center1: (");
718bc0c7b3fc892adc21eeac2d56b02a525ee811fdbrobertphillips@google.com    str->appendScalar(fCenter1.fX);
719bc0c7b3fc892adc21eeac2d56b02a525ee811fdbrobertphillips@google.com    str->append(", ");
720bc0c7b3fc892adc21eeac2d56b02a525ee811fdbrobertphillips@google.com    str->appendScalar(fCenter1.fY);
721bc0c7b3fc892adc21eeac2d56b02a525ee811fdbrobertphillips@google.com    str->append(") radius1: ");
722bc0c7b3fc892adc21eeac2d56b02a525ee811fdbrobertphillips@google.com    str->appendScalar(fRadius1);
723bc0c7b3fc892adc21eeac2d56b02a525ee811fdbrobertphillips@google.com    str->append(" ");
724bc0c7b3fc892adc21eeac2d56b02a525ee811fdbrobertphillips@google.com
725bc0c7b3fc892adc21eeac2d56b02a525ee811fdbrobertphillips@google.com    str->append("center2: (");
726bc0c7b3fc892adc21eeac2d56b02a525ee811fdbrobertphillips@google.com    str->appendScalar(fCenter2.fX);
727bc0c7b3fc892adc21eeac2d56b02a525ee811fdbrobertphillips@google.com    str->append(", ");
728bc0c7b3fc892adc21eeac2d56b02a525ee811fdbrobertphillips@google.com    str->appendScalar(fCenter2.fY);
729bc0c7b3fc892adc21eeac2d56b02a525ee811fdbrobertphillips@google.com    str->append(") radius2: ");
730bc0c7b3fc892adc21eeac2d56b02a525ee811fdbrobertphillips@google.com    str->appendScalar(fRadius2);
731bc0c7b3fc892adc21eeac2d56b02a525ee811fdbrobertphillips@google.com    str->append(" ");
732bc0c7b3fc892adc21eeac2d56b02a525ee811fdbrobertphillips@google.com
733bc0c7b3fc892adc21eeac2d56b02a525ee811fdbrobertphillips@google.com    this->INHERITED::toString(str);
734bc0c7b3fc892adc21eeac2d56b02a525ee811fdbrobertphillips@google.com
735bc0c7b3fc892adc21eeac2d56b02a525ee811fdbrobertphillips@google.com    str->append(")");
736bc0c7b3fc892adc21eeac2d56b02a525ee811fdbrobertphillips@google.com}
737bc0c7b3fc892adc21eeac2d56b02a525ee811fdbrobertphillips@google.com#endif
738