180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru/*
280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru * Copyright 2012 Google Inc.
380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru *
480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru * Use of this source code is governed by a BSD-style license that can be
580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru * found in the LICENSE file.
680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru */
780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru#include "SkTwoPointConicalGradient.h"
980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
1080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Querustatic int valid_divide(float numer, float denom, float* ratio) {
1180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    SkASSERT(ratio);
1280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    if (0 == denom) {
1380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        return 0;
1480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    }
1580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    *ratio = numer / denom;
1680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    return 1;
1780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru}
1880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
1980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru// Return the number of distinct real roots, and write them into roots[] in
2080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru// ascending order
2180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Querustatic int find_quad_roots(float A, float B, float C, float roots[2]) {
2280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    SkASSERT(roots);
2380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
2480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    if (A == 0) {
2580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        return valid_divide(-C, B, roots);
2680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    }
2780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
2880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    float R = B*B - 4*A*C;
2980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    if (R < 0) {
3080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        return 0;
3180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    }
3280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    R = sk_float_sqrt(R);
3380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
3480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru#if 1
3580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    float Q = B;
3680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    if (Q < 0) {
3780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        Q -= R;
3880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    } else {
3980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        Q += R;
4080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    }
4180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru#else
4280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    // on 10.6 this was much slower than the above branch :(
4380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    float Q = B + copysignf(R, B);
4480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru#endif
4580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    Q *= -0.5f;
4680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    if (0 == Q) {
4780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        roots[0] = 0;
4880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        return 1;
4980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    }
5080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
5180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    float r0 = Q / A;
5280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    float r1 = C / Q;
5380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    roots[0] = r0 < r1 ? r0 : r1;
5480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    roots[1] = r0 > r1 ? r0 : r1;
5580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    return 2;
5680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru}
5780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
5880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Querustatic float lerp(float x, float dx, float t) {
5980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    return x + t * dx;
6080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru}
6180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
6280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Querustatic float sqr(float x) { return x * x; }
6380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
6480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queruvoid TwoPtRadial::init(const SkPoint& center0, SkScalar rad0,
6580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                       const SkPoint& center1, SkScalar rad1) {
6680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    fCenterX = SkScalarToFloat(center0.fX);
6780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    fCenterY = SkScalarToFloat(center0.fY);
6880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    fDCenterX = SkScalarToFloat(center1.fX) - fCenterX;
6980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    fDCenterY = SkScalarToFloat(center1.fY) - fCenterY;
7080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    fRadius = SkScalarToFloat(rad0);
7180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    fDRadius = SkScalarToFloat(rad1) - fRadius;
7280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
7380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    fA = sqr(fDCenterX) + sqr(fDCenterY) - sqr(fDRadius);
7480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    fRadius2 = sqr(fRadius);
7580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    fRDR = fRadius * fDRadius;
7680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru}
7780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
7880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queruvoid TwoPtRadial::setup(SkScalar fx, SkScalar fy, SkScalar dfx, SkScalar dfy) {
7980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    fRelX = SkScalarToFloat(fx) - fCenterX;
8080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    fRelY = SkScalarToFloat(fy) - fCenterY;
8180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    fIncX = SkScalarToFloat(dfx);
8280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    fIncY = SkScalarToFloat(dfy);
8380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    fB = -2 * (fDCenterX * fRelX + fDCenterY * fRelY + fRDR);
8480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    fDB = -2 * (fDCenterX * fIncX + fDCenterY * fIncY);
8580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru}
8680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
8780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste QueruSkFixed TwoPtRadial::nextT() {
8880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    float roots[2];
8980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
9080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    float C = sqr(fRelX) + sqr(fRelY) - fRadius2;
9180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    int countRoots = find_quad_roots(fA, fB, C, roots);
9280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
9380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    fRelX += fIncX;
9480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    fRelY += fIncY;
9580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    fB += fDB;
9680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
9780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    if (0 == countRoots) {
9880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        return kDontDrawT;
9980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    }
10080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
10180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    // Prefer the bigger t value if both give a radius(t) > 0
10280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    // find_quad_roots returns the values sorted, so we start with the last
10380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    float t = roots[countRoots - 1];
10480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    float r = lerp(fRadius, fDRadius, t);
10580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    if (r <= 0) {
10680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        t = roots[0];   // might be the same as roots[countRoots-1]
10780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        r = lerp(fRadius, fDRadius, t);
10880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        if (r <= 0) {
10980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            return kDontDrawT;
11080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        }
11180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    }
11280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    return SkFloatToFixed(t);
11380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru}
11480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
115096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenbergertypedef void (*TwoPointConicalProc)(TwoPtRadial* rec, SkPMColor* dstC,
116096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger                                    const SkPMColor* cache, int toggle, int count);
11780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
11880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Querustatic void twopoint_clamp(TwoPtRadial* rec, SkPMColor* SK_RESTRICT dstC,
119096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger                           const SkPMColor* SK_RESTRICT cache, int toggle,
120096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger                           int count) {
12180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    for (; count > 0; --count) {
12280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        SkFixed t = rec->nextT();
12380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        if (TwoPtRadial::DontDrawT(t)) {
12480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            *dstC++ = 0;
12580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        } else {
12680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            SkFixed index = SkClampMax(t, 0xFFFF);
12780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            SkASSERT(index <= 0xFFFF);
128096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger            *dstC++ = cache[toggle +
129096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger                            (index >> SkGradientShaderBase::kCache32Shift)];
13080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        }
131096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger        toggle = next_dither_toggle(toggle);
13280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    }
13380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru}
13480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
13580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Querustatic void twopoint_repeat(TwoPtRadial* rec, SkPMColor* SK_RESTRICT dstC,
136096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger                            const SkPMColor* SK_RESTRICT cache, int toggle,
137096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger                            int count) {
13880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    for (; count > 0; --count) {
13980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        SkFixed t = rec->nextT();
14080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        if (TwoPtRadial::DontDrawT(t)) {
14180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            *dstC++ = 0;
14280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        } else {
14380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            SkFixed index = repeat_tileproc(t);
14480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            SkASSERT(index <= 0xFFFF);
145096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger            *dstC++ = cache[toggle +
146096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger                            (index >> SkGradientShaderBase::kCache32Shift)];
14780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        }
148096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger        toggle = next_dither_toggle(toggle);
14980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    }
15080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru}
15180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
15280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Querustatic void twopoint_mirror(TwoPtRadial* rec, SkPMColor* SK_RESTRICT dstC,
153096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger                            const SkPMColor* SK_RESTRICT cache, int toggle,
154096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger                            int count) {
15580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    for (; count > 0; --count) {
15680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        SkFixed t = rec->nextT();
15780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        if (TwoPtRadial::DontDrawT(t)) {
15880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            *dstC++ = 0;
15980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        } else {
16080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            SkFixed index = mirror_tileproc(t);
16180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            SkASSERT(index <= 0xFFFF);
162096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger            *dstC++ = cache[toggle +
163096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger                            (index >> SkGradientShaderBase::kCache32Shift)];
16480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        }
165096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger        toggle = next_dither_toggle(toggle);
16680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    }
16780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru}
16880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
16980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queruvoid SkTwoPointConicalGradient::init() {
17080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    fRec.init(fCenter1, fRadius1, fCenter2, fRadius2);
17180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    fPtsToUnit.reset();
17280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru}
17380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
17480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru/////////////////////////////////////////////////////////////////////
17580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
17680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste QueruSkTwoPointConicalGradient::SkTwoPointConicalGradient(
177779bf8a99dc7f03e5c43b26d4b85d7920ce89aeeDerek Sollenberger        const SkPoint& start, SkScalar startRadius,
178779bf8a99dc7f03e5c43b26d4b85d7920ce89aeeDerek Sollenberger        const SkPoint& end, SkScalar endRadius,
179779bf8a99dc7f03e5c43b26d4b85d7920ce89aeeDerek Sollenberger        const Descriptor& desc)
180779bf8a99dc7f03e5c43b26d4b85d7920ce89aeeDerek Sollenberger    : SkGradientShaderBase(desc),
18180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    fCenter1(start),
18280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    fCenter2(end),
18380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    fRadius1(startRadius),
18480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    fRadius2(endRadius) {
18580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    // this is degenerate, and should be caught by our caller
18680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    SkASSERT(fCenter1 != fCenter2 || fRadius1 != fRadius2);
18780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    this->init();
18880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru}
18980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
190096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenbergerbool SkTwoPointConicalGradient::isOpaque() const {
191096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger    // Because areas outside the cone are left untouched, we cannot treat the
192096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger    // shader as opaque even if the gradient itself is opaque.
193e2022cc36e47b9f0d219eb5cd24be61772c28d3bDerek Sollenberger    // TODO(junov): Compute whether the cone fills the plane crbug.com/222380
194096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger    return false;
195096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger}
196096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger
19780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queruvoid SkTwoPointConicalGradient::shadeSpan(int x, int y, SkPMColor* dstCParam,
19880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                                          int count) {
199096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger    int toggle = init_dither_toggle(x, y);
200096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger
20180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    SkASSERT(count > 0);
20280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
20380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    SkPMColor* SK_RESTRICT dstC = dstCParam;
20480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
20580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    SkMatrix::MapXYProc dstProc = fDstToIndexProc;
20680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
20780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    const SkPMColor* SK_RESTRICT cache = this->getCache32();
20880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
209096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger    TwoPointConicalProc shadeProc = twopoint_repeat;
21080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    if (SkShader::kClamp_TileMode == fTileMode) {
21180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        shadeProc = twopoint_clamp;
21280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    } else if (SkShader::kMirror_TileMode == fTileMode) {
21380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        shadeProc = twopoint_mirror;
21480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    } else {
21580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        SkASSERT(SkShader::kRepeat_TileMode == fTileMode);
21680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    }
21780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
21880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    if (fDstToIndexClass != kPerspective_MatrixClass) {
21980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        SkPoint srcPt;
22080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        dstProc(fDstToIndex, SkIntToScalar(x) + SK_ScalarHalf,
22180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                SkIntToScalar(y) + SK_ScalarHalf, &srcPt);
22280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        SkScalar dx, fx = srcPt.fX;
22380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        SkScalar dy, fy = srcPt.fY;
22480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
22580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        if (fDstToIndexClass == kFixedStepInX_MatrixClass) {
22680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            SkFixed fixedX, fixedY;
22780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            (void)fDstToIndex.fixedStepInX(SkIntToScalar(y), &fixedX, &fixedY);
22880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            dx = SkFixedToScalar(fixedX);
22980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            dy = SkFixedToScalar(fixedY);
23080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        } else {
23180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            SkASSERT(fDstToIndexClass == kLinear_MatrixClass);
23280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            dx = fDstToIndex.getScaleX();
23380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            dy = fDstToIndex.getSkewY();
23480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        }
23580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
23680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        fRec.setup(fx, fy, dx, dy);
237096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger        (*shadeProc)(&fRec, dstC, cache, toggle, count);
23880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    } else {    // perspective case
239910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger        SkScalar dstX = SkIntToScalar(x) + SK_ScalarHalf;
240910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger        SkScalar dstY = SkIntToScalar(y) + SK_ScalarHalf;
24180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        for (; count > 0; --count) {
24280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            SkPoint srcPt;
24380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            dstProc(fDstToIndex, dstX, dstY, &srcPt);
24480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            fRec.setup(srcPt.fX, srcPt.fY, 0, 0);
245096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger            (*shadeProc)(&fRec, dstC, cache, toggle, 1);
246910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger
247910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger            dstX += SK_Scalar1;
248096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger            toggle = next_dither_toggle(toggle);
249910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger            dstC += 1;
25080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        }
25180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    }
25280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru}
25380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
25480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Querubool SkTwoPointConicalGradient::setContext(const SkBitmap& device,
25580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                                           const SkPaint& paint,
25680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                                           const SkMatrix& matrix) {
25780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    if (!this->INHERITED::setContext(device, paint, matrix)) {
25880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        return false;
25980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    }
26080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
26180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    // we don't have a span16 proc
26280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    fFlags &= ~kHasSpan16_Flag;
26380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
26480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    // in general, we might discard based on computed-radius, so clear
26580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    // this flag (todo: sometimes we can detect that we never discard...)
26680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    fFlags &= ~kOpaqueAlpha_Flag;
26780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
26880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    return true;
26980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru}
27080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
27180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste QueruSkShader::BitmapType SkTwoPointConicalGradient::asABitmap(
27280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    SkBitmap* bitmap, SkMatrix* matrix, SkShader::TileMode* xy) const {
27380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    SkPoint diff = fCenter2 - fCenter1;
27480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    SkScalar diffLen = 0;
27580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
27680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    if (bitmap) {
27780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        this->getGradientTableBitmap(bitmap);
27880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    }
27980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    if (matrix) {
28080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        diffLen = diff.length();
28180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    }
28280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    if (matrix) {
28380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        if (diffLen) {
28480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            SkScalar invDiffLen = SkScalarInvert(diffLen);
28580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            // rotate to align circle centers with the x-axis
28680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            matrix->setSinCos(-SkScalarMul(invDiffLen, diff.fY),
28780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                              SkScalarMul(invDiffLen, diff.fX));
28880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        } else {
28980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            matrix->reset();
29080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        }
29180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        matrix->preTranslate(-fCenter1.fX, -fCenter1.fY);
29280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    }
29380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    if (xy) {
29480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        xy[0] = fTileMode;
29580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        xy[1] = kClamp_TileMode;
29680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    }
29780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    return kTwoPointConical_BitmapType;
29880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru}
29980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
30080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste QueruSkShader::GradientType SkTwoPointConicalGradient::asAGradient(
30180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    GradientInfo* info) const {
30280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    if (info) {
30380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        commonAsAGradient(info);
30480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        info->fPoint[0] = fCenter1;
30580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        info->fPoint[1] = fCenter2;
30680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        info->fRadius[0] = fRadius1;
30780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        info->fRadius[1] = fRadius2;
30880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    }
30980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    return kConical_GradientType;
31080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru}
31180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
31280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste QueruSkTwoPointConicalGradient::SkTwoPointConicalGradient(
31380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    SkFlattenableReadBuffer& buffer)
31480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    : INHERITED(buffer),
31580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    fCenter1(buffer.readPoint()),
31680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    fCenter2(buffer.readPoint()),
31780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    fRadius1(buffer.readScalar()),
31880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    fRadius2(buffer.readScalar()) {
31980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    this->init();
32080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru};
32180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
32280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queruvoid SkTwoPointConicalGradient::flatten(
32380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    SkFlattenableWriteBuffer& buffer) const {
32480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    this->INHERITED::flatten(buffer);
32580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    buffer.writePoint(fCenter1);
32680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    buffer.writePoint(fCenter2);
32780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    buffer.writeScalar(fRadius1);
32880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    buffer.writeScalar(fRadius2);
32980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru}
33080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
33180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru/////////////////////////////////////////////////////////////////////
33280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
33380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru#if SK_SUPPORT_GPU
33480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
335363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger#include "GrTBackendEffectFactory.h"
336363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger
33780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru// For brevity
33880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Querutypedef GrGLUniformManager::UniformHandle UniformHandle;
33980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
340363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenbergerclass GrGLConical2Gradient : public GrGLGradientEffect {
34180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Querupublic:
34280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
343e2022cc36e47b9f0d219eb5cd24be61772c28d3bDerek Sollenberger    GrGLConical2Gradient(const GrBackendEffectFactory& factory, const GrDrawEffect&);
34480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    virtual ~GrGLConical2Gradient() { }
34580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
346363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger    virtual void emitCode(GrGLShaderBuilder*,
347e2022cc36e47b9f0d219eb5cd24be61772c28d3bDerek Sollenberger                          const GrDrawEffect&,
348363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger                          EffectKey,
349363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger                          const char* outputColor,
350363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger                          const char* inputColor,
3510a657bbc2c6fc9daf699942e023050536d5ec95fDerek Sollenberger                          const TransformedCoordsArray&,
352363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger                          const TextureSamplerArray&) SK_OVERRIDE;
353e2022cc36e47b9f0d219eb5cd24be61772c28d3bDerek Sollenberger    virtual void setData(const GrGLUniformManager&, const GrDrawEffect&) SK_OVERRIDE;
35480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
355e2022cc36e47b9f0d219eb5cd24be61772c28d3bDerek Sollenberger    static EffectKey GenKey(const GrDrawEffect&, const GrGLCaps& caps);
35680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
35780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queruprotected:
35880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
3590a657bbc2c6fc9daf699942e023050536d5ec95fDerek Sollenberger    UniformHandle fParamUni;
36080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
36180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    const char* fVSVaryingName;
36280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    const char* fFSVaryingName;
36380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
36480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    bool fIsDegenerate;
36580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
36680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    // @{
36780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    /// Values last uploaded as uniforms
36880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
369363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger    SkScalar fCachedCenter;
370363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger    SkScalar fCachedRadius;
371363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger    SkScalar fCachedDiffRadius;
37280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
37380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    // @}
37480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
37580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queruprivate:
37680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
377363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger    typedef GrGLGradientEffect INHERITED;
37880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
37980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru};
38080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
38180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru/////////////////////////////////////////////////////////////////////
38280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
38380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queruclass GrConical2Gradient : public GrGradientEffect {
38480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Querupublic:
38580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
386d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger    static GrEffectRef* Create(GrContext* ctx,
387d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger                               const SkTwoPointConicalGradient& shader,
388d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger                               const SkMatrix& matrix,
389d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger                               SkShader::TileMode tm) {
390d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger        AutoEffectUnref effect(SkNEW_ARGS(GrConical2Gradient, (ctx, shader, matrix, tm)));
391d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger        return CreateEffectRef(effect);
392d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger    }
39380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
39480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    virtual ~GrConical2Gradient() { }
39580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
39680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    static const char* Name() { return "Two-Point Conical Gradient"; }
397363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger    virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE {
398363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger        return GrTBackendEffectFactory<GrConical2Gradient>::getInstance();
39980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    }
40080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
40180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    // The radial gradient parameters can collapse to a linear (instead of quadratic) equation.
40280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    bool isDegenerate() const { return SkScalarAbs(fDiffRadius) == SkScalarAbs(fCenterX1); }
403363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger    SkScalar center() const { return fCenterX1; }
404363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger    SkScalar diffRadius() const { return fDiffRadius; }
405363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger    SkScalar radius() const { return fRadius0; }
40680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
407363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger    typedef GrGLConical2Gradient GLEffect;
40880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
40980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queruprivate:
410d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger    virtual bool onIsEqual(const GrEffect& sBase) const SK_OVERRIDE {
411d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger        const GrConical2Gradient& s = CastEffect<GrConical2Gradient>(sBase);
412d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger        return (INHERITED::onIsEqual(sBase) &&
413d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger                this->fCenterX1 == s.fCenterX1 &&
414d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger                this->fRadius0 == s.fRadius0 &&
415d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger                this->fDiffRadius == s.fDiffRadius);
416d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger    }
417d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger
418d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger    GrConical2Gradient(GrContext* ctx,
419d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger                       const SkTwoPointConicalGradient& shader,
420d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger                       const SkMatrix& matrix,
421d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger                       SkShader::TileMode tm)
422d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger        : INHERITED(ctx, shader, matrix, tm)
423d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger        , fCenterX1(shader.getCenterX1())
424d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger        , fRadius0(shader.getStartRadius())
4250a657bbc2c6fc9daf699942e023050536d5ec95fDerek Sollenberger        , fDiffRadius(shader.getDiffRadius()) {
4260a657bbc2c6fc9daf699942e023050536d5ec95fDerek Sollenberger        // We pass the linear part of the quadratic as a varying.
4270a657bbc2c6fc9daf699942e023050536d5ec95fDerek Sollenberger        //    float b = -2.0 * (fCenterX1 * x + fRadius0 * fDiffRadius * z)
4280a657bbc2c6fc9daf699942e023050536d5ec95fDerek Sollenberger        fBTransform = this->getCoordTransform();
4290a657bbc2c6fc9daf699942e023050536d5ec95fDerek Sollenberger        SkMatrix& bMatrix = *fBTransform.accessMatrix();
4300a657bbc2c6fc9daf699942e023050536d5ec95fDerek Sollenberger        SkScalar r0dr = SkScalarMul(fRadius0, fDiffRadius);
4310a657bbc2c6fc9daf699942e023050536d5ec95fDerek Sollenberger        bMatrix[SkMatrix::kMScaleX] = -2 * (SkScalarMul(fCenterX1, bMatrix[SkMatrix::kMScaleX]) +
4320a657bbc2c6fc9daf699942e023050536d5ec95fDerek Sollenberger                                            SkScalarMul(r0dr, bMatrix[SkMatrix::kMPersp0]));
4330a657bbc2c6fc9daf699942e023050536d5ec95fDerek Sollenberger        bMatrix[SkMatrix::kMSkewX] = -2 * (SkScalarMul(fCenterX1, bMatrix[SkMatrix::kMSkewX]) +
4340a657bbc2c6fc9daf699942e023050536d5ec95fDerek Sollenberger                                           SkScalarMul(r0dr, bMatrix[SkMatrix::kMPersp1]));
4350a657bbc2c6fc9daf699942e023050536d5ec95fDerek Sollenberger        bMatrix[SkMatrix::kMTransX] = -2 * (SkScalarMul(fCenterX1, bMatrix[SkMatrix::kMTransX]) +
4360a657bbc2c6fc9daf699942e023050536d5ec95fDerek Sollenberger                                            SkScalarMul(r0dr, bMatrix[SkMatrix::kMPersp2]));
4370a657bbc2c6fc9daf699942e023050536d5ec95fDerek Sollenberger        this->addCoordTransform(&fBTransform);
4380a657bbc2c6fc9daf699942e023050536d5ec95fDerek Sollenberger    }
439d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger
440363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger    GR_DECLARE_EFFECT_TEST;
44180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
44280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    // @{
44380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    // Cache of values - these can change arbitrarily, EXCEPT
44480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    // we shouldn't change between degenerate and non-degenerate?!
44580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
4460a657bbc2c6fc9daf699942e023050536d5ec95fDerek Sollenberger    GrCoordTransform fBTransform;
4470a657bbc2c6fc9daf699942e023050536d5ec95fDerek Sollenberger    SkScalar         fCenterX1;
4480a657bbc2c6fc9daf699942e023050536d5ec95fDerek Sollenberger    SkScalar         fRadius0;
4490a657bbc2c6fc9daf699942e023050536d5ec95fDerek Sollenberger    SkScalar         fDiffRadius;
45080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
45180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    // @}
45280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
45380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    typedef GrGradientEffect INHERITED;
45480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru};
45580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
456363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek SollenbergerGR_DEFINE_EFFECT_TEST(GrConical2Gradient);
45780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
4580a657bbc2c6fc9daf699942e023050536d5ec95fDerek SollenbergerGrEffectRef* GrConical2Gradient::TestCreate(SkRandom* random,
459d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger                                            GrContext* context,
4607839ce1af63bf12fe7b3caa866970bbbb3afb13dDerek Sollenberger                                            const GrDrawTargetCaps&,
461d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger                                            GrTexture**) {
46280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    SkPoint center1 = {random->nextUScalar1(), random->nextUScalar1()};
46380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    SkScalar radius1 = random->nextUScalar1();
46480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    SkPoint center2;
46580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    SkScalar radius2;
46680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    do {
467363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger        center2.set(random->nextUScalar1(), random->nextUScalar1());
46880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        radius2 = random->nextUScalar1 ();
46980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        // If the circles are identical the factory will give us an empty shader.
47080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    } while (radius1 == radius2 && center1 == center2);
47180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
47280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    SkColor colors[kMaxRandomGradientColors];
47380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    SkScalar stopsArray[kMaxRandomGradientColors];
47480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    SkScalar* stops = stopsArray;
47580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    SkShader::TileMode tm;
47680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    int colorCount = RandomGradientParams(random, colors, &stops, &tm);
47780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    SkAutoTUnref<SkShader> shader(SkGradientShader::CreateTwoPointConical(center1, radius1,
47880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                                                                          center2, radius2,
47980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                                                                          colors, stops, colorCount,
48080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                                                                          tm));
481d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger    SkPaint paint;
482d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger    return shader->asNewEffect(context, paint);
48380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru}
48480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
48580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
48680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru/////////////////////////////////////////////////////////////////////
48780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
488d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek SollenbergerGrGLConical2Gradient::GrGLConical2Gradient(const GrBackendEffectFactory& factory,
489e2022cc36e47b9f0d219eb5cd24be61772c28d3bDerek Sollenberger                                           const GrDrawEffect& drawEffect)
49080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    : INHERITED(factory)
49180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    , fVSVaryingName(NULL)
49280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    , fFSVaryingName(NULL)
493363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger    , fCachedCenter(SK_ScalarMax)
494363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger    , fCachedRadius(-SK_ScalarMax)
495363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger    , fCachedDiffRadius(-SK_ScalarMax) {
49680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
497e2022cc36e47b9f0d219eb5cd24be61772c28d3bDerek Sollenberger    const GrConical2Gradient& data = drawEffect.castEffect<GrConical2Gradient>();
49880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    fIsDegenerate = data.isDegenerate();
49980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru}
50080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
501363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenbergervoid GrGLConical2Gradient::emitCode(GrGLShaderBuilder* builder,
502e2022cc36e47b9f0d219eb5cd24be61772c28d3bDerek Sollenberger                                    const GrDrawEffect&,
503363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger                                    EffectKey key,
504363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger                                    const char* outputColor,
505363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger                                    const char* inputColor,
5060a657bbc2c6fc9daf699942e023050536d5ec95fDerek Sollenberger                                    const TransformedCoordsArray& coords,
507363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger                                    const TextureSamplerArray& samplers) {
5080a657bbc2c6fc9daf699942e023050536d5ec95fDerek Sollenberger    this->emitUniforms(builder, key);
5090a657bbc2c6fc9daf699942e023050536d5ec95fDerek Sollenberger    fParamUni = builder->addUniformArray(GrGLShaderBuilder::kFragment_Visibility,
5100a657bbc2c6fc9daf699942e023050536d5ec95fDerek Sollenberger                                         kFloat_GrSLType, "Conical2FSParams", 6);
5110a657bbc2c6fc9daf699942e023050536d5ec95fDerek Sollenberger
5120a657bbc2c6fc9daf699942e023050536d5ec95fDerek Sollenberger    SkString cName("c");
5130a657bbc2c6fc9daf699942e023050536d5ec95fDerek Sollenberger    SkString ac4Name("ac4");
5140a657bbc2c6fc9daf699942e023050536d5ec95fDerek Sollenberger    SkString dName("d");
5150a657bbc2c6fc9daf699942e023050536d5ec95fDerek Sollenberger    SkString qName("q");
5160a657bbc2c6fc9daf699942e023050536d5ec95fDerek Sollenberger    SkString r0Name("r0");
5170a657bbc2c6fc9daf699942e023050536d5ec95fDerek Sollenberger    SkString r1Name("r1");
5180a657bbc2c6fc9daf699942e023050536d5ec95fDerek Sollenberger    SkString tName("t");
5190a657bbc2c6fc9daf699942e023050536d5ec95fDerek Sollenberger    SkString p0; // 4a
5200a657bbc2c6fc9daf699942e023050536d5ec95fDerek Sollenberger    SkString p1; // 1/a
5210a657bbc2c6fc9daf699942e023050536d5ec95fDerek Sollenberger    SkString p2; // distance between centers
5220a657bbc2c6fc9daf699942e023050536d5ec95fDerek Sollenberger    SkString p3; // start radius
5230a657bbc2c6fc9daf699942e023050536d5ec95fDerek Sollenberger    SkString p4; // start radius squared
5240a657bbc2c6fc9daf699942e023050536d5ec95fDerek Sollenberger    SkString p5; // difference in radii (r1 - r0)
5250a657bbc2c6fc9daf699942e023050536d5ec95fDerek Sollenberger
5260a657bbc2c6fc9daf699942e023050536d5ec95fDerek Sollenberger    builder->getUniformVariable(fParamUni).appendArrayAccess(0, &p0);
5270a657bbc2c6fc9daf699942e023050536d5ec95fDerek Sollenberger    builder->getUniformVariable(fParamUni).appendArrayAccess(1, &p1);
5280a657bbc2c6fc9daf699942e023050536d5ec95fDerek Sollenberger    builder->getUniformVariable(fParamUni).appendArrayAccess(2, &p2);
5290a657bbc2c6fc9daf699942e023050536d5ec95fDerek Sollenberger    builder->getUniformVariable(fParamUni).appendArrayAccess(3, &p3);
5300a657bbc2c6fc9daf699942e023050536d5ec95fDerek Sollenberger    builder->getUniformVariable(fParamUni).appendArrayAccess(4, &p4);
5310a657bbc2c6fc9daf699942e023050536d5ec95fDerek Sollenberger    builder->getUniformVariable(fParamUni).appendArrayAccess(5, &p5);
5320a657bbc2c6fc9daf699942e023050536d5ec95fDerek Sollenberger
5330a657bbc2c6fc9daf699942e023050536d5ec95fDerek Sollenberger    // We interpolate the linear component in coords[1].
5340a657bbc2c6fc9daf699942e023050536d5ec95fDerek Sollenberger    SkASSERT(coords[0].type() == coords[1].type());
5350a657bbc2c6fc9daf699942e023050536d5ec95fDerek Sollenberger    const char* coords2D;
5360a657bbc2c6fc9daf699942e023050536d5ec95fDerek Sollenberger    SkString bVar;
5370a657bbc2c6fc9daf699942e023050536d5ec95fDerek Sollenberger    if (kVec3f_GrSLType == coords[0].type()) {
5380a657bbc2c6fc9daf699942e023050536d5ec95fDerek Sollenberger        builder->fsCodeAppendf("\tvec3 interpolants = vec3(%s.xy, %s.x) / %s.z;\n",
5390a657bbc2c6fc9daf699942e023050536d5ec95fDerek Sollenberger                               coords[0].c_str(), coords[1].c_str(), coords[0].c_str());
5400a657bbc2c6fc9daf699942e023050536d5ec95fDerek Sollenberger        coords2D = "interpolants.xy";
5410a657bbc2c6fc9daf699942e023050536d5ec95fDerek Sollenberger        bVar = "interpolants.z";
5420a657bbc2c6fc9daf699942e023050536d5ec95fDerek Sollenberger    } else {
5430a657bbc2c6fc9daf699942e023050536d5ec95fDerek Sollenberger        coords2D = coords[0].c_str();
5440a657bbc2c6fc9daf699942e023050536d5ec95fDerek Sollenberger        bVar.printf("%s.x", coords[1].c_str());
54580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    }
54680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
5470a657bbc2c6fc9daf699942e023050536d5ec95fDerek Sollenberger    // output will default to transparent black (we simply won't write anything
5480a657bbc2c6fc9daf699942e023050536d5ec95fDerek Sollenberger    // else to it if invalid, instead of discarding or returning prematurely)
5490a657bbc2c6fc9daf699942e023050536d5ec95fDerek Sollenberger    builder->fsCodeAppendf("\t%s = vec4(0.0,0.0,0.0,0.0);\n", outputColor);
5500a657bbc2c6fc9daf699942e023050536d5ec95fDerek Sollenberger
5510a657bbc2c6fc9daf699942e023050536d5ec95fDerek Sollenberger    // c = (x^2)+(y^2) - params[4]
5520a657bbc2c6fc9daf699942e023050536d5ec95fDerek Sollenberger    builder->fsCodeAppendf("\tfloat %s = dot(%s, %s) - %s;\n",
5530a657bbc2c6fc9daf699942e023050536d5ec95fDerek Sollenberger                           cName.c_str(), coords2D, coords2D, p4.c_str());
5540a657bbc2c6fc9daf699942e023050536d5ec95fDerek Sollenberger
5550a657bbc2c6fc9daf699942e023050536d5ec95fDerek Sollenberger    // Non-degenerate case (quadratic)
5560a657bbc2c6fc9daf699942e023050536d5ec95fDerek Sollenberger    if (!fIsDegenerate) {
5570a657bbc2c6fc9daf699942e023050536d5ec95fDerek Sollenberger
5580a657bbc2c6fc9daf699942e023050536d5ec95fDerek Sollenberger        // ac4 = params[0] * c
5590a657bbc2c6fc9daf699942e023050536d5ec95fDerek Sollenberger        builder->fsCodeAppendf("\tfloat %s = %s * %s;\n", ac4Name.c_str(), p0.c_str(),
5600a657bbc2c6fc9daf699942e023050536d5ec95fDerek Sollenberger                               cName.c_str());
5610a657bbc2c6fc9daf699942e023050536d5ec95fDerek Sollenberger
5620a657bbc2c6fc9daf699942e023050536d5ec95fDerek Sollenberger        // d = b^2 - ac4
5630a657bbc2c6fc9daf699942e023050536d5ec95fDerek Sollenberger        builder->fsCodeAppendf("\tfloat %s = %s * %s - %s;\n", dName.c_str(),
5640a657bbc2c6fc9daf699942e023050536d5ec95fDerek Sollenberger                               bVar.c_str(), bVar.c_str(), ac4Name.c_str());
5650a657bbc2c6fc9daf699942e023050536d5ec95fDerek Sollenberger
5660a657bbc2c6fc9daf699942e023050536d5ec95fDerek Sollenberger        // only proceed if discriminant is >= 0
5670a657bbc2c6fc9daf699942e023050536d5ec95fDerek Sollenberger        builder->fsCodeAppendf("\tif (%s >= 0.0) {\n", dName.c_str());
5680a657bbc2c6fc9daf699942e023050536d5ec95fDerek Sollenberger
5690a657bbc2c6fc9daf699942e023050536d5ec95fDerek Sollenberger        // intermediate value we'll use to compute the roots
5700a657bbc2c6fc9daf699942e023050536d5ec95fDerek Sollenberger        // q = -0.5 * (b +/- sqrt(d))
5710a657bbc2c6fc9daf699942e023050536d5ec95fDerek Sollenberger        builder->fsCodeAppendf("\t\tfloat %s = -0.5 * (%s + (%s < 0.0 ? -1.0 : 1.0)"
5720a657bbc2c6fc9daf699942e023050536d5ec95fDerek Sollenberger                               " * sqrt(%s));\n", qName.c_str(), bVar.c_str(),
5730a657bbc2c6fc9daf699942e023050536d5ec95fDerek Sollenberger                               bVar.c_str(), dName.c_str());
5740a657bbc2c6fc9daf699942e023050536d5ec95fDerek Sollenberger
5750a657bbc2c6fc9daf699942e023050536d5ec95fDerek Sollenberger        // compute both roots
5760a657bbc2c6fc9daf699942e023050536d5ec95fDerek Sollenberger        // r0 = q * params[1]
5770a657bbc2c6fc9daf699942e023050536d5ec95fDerek Sollenberger        builder->fsCodeAppendf("\t\tfloat %s = %s * %s;\n", r0Name.c_str(),
5780a657bbc2c6fc9daf699942e023050536d5ec95fDerek Sollenberger                               qName.c_str(), p1.c_str());
5790a657bbc2c6fc9daf699942e023050536d5ec95fDerek Sollenberger        // r1 = c / q
5800a657bbc2c6fc9daf699942e023050536d5ec95fDerek Sollenberger        builder->fsCodeAppendf("\t\tfloat %s = %s / %s;\n", r1Name.c_str(),
5810a657bbc2c6fc9daf699942e023050536d5ec95fDerek Sollenberger                               cName.c_str(), qName.c_str());
5820a657bbc2c6fc9daf699942e023050536d5ec95fDerek Sollenberger
5830a657bbc2c6fc9daf699942e023050536d5ec95fDerek Sollenberger        // Note: If there are two roots that both generate radius(t) > 0, the
5840a657bbc2c6fc9daf699942e023050536d5ec95fDerek Sollenberger        // Canvas spec says to choose the larger t.
5850a657bbc2c6fc9daf699942e023050536d5ec95fDerek Sollenberger
5860a657bbc2c6fc9daf699942e023050536d5ec95fDerek Sollenberger        // so we'll look at the larger one first:
5870a657bbc2c6fc9daf699942e023050536d5ec95fDerek Sollenberger        builder->fsCodeAppendf("\t\tfloat %s = max(%s, %s);\n", tName.c_str(),
5880a657bbc2c6fc9daf699942e023050536d5ec95fDerek Sollenberger                               r0Name.c_str(), r1Name.c_str());
5890a657bbc2c6fc9daf699942e023050536d5ec95fDerek Sollenberger
5900a657bbc2c6fc9daf699942e023050536d5ec95fDerek Sollenberger        // if r(t) > 0, then we're done; t will be our x coordinate
5910a657bbc2c6fc9daf699942e023050536d5ec95fDerek Sollenberger        builder->fsCodeAppendf("\t\tif (%s * %s + %s > 0.0) {\n", tName.c_str(),
5920a657bbc2c6fc9daf699942e023050536d5ec95fDerek Sollenberger                               p5.c_str(), p3.c_str());
5930a657bbc2c6fc9daf699942e023050536d5ec95fDerek Sollenberger
5940a657bbc2c6fc9daf699942e023050536d5ec95fDerek Sollenberger        builder->fsCodeAppend("\t\t");
5950a657bbc2c6fc9daf699942e023050536d5ec95fDerek Sollenberger        this->emitColor(builder, tName.c_str(), key, outputColor, inputColor, samplers);
5960a657bbc2c6fc9daf699942e023050536d5ec95fDerek Sollenberger
5970a657bbc2c6fc9daf699942e023050536d5ec95fDerek Sollenberger        // otherwise, if r(t) for the larger root was <= 0, try the other root
5980a657bbc2c6fc9daf699942e023050536d5ec95fDerek Sollenberger        builder->fsCodeAppend("\t\t} else {\n");
5990a657bbc2c6fc9daf699942e023050536d5ec95fDerek Sollenberger        builder->fsCodeAppendf("\t\t\t%s = min(%s, %s);\n", tName.c_str(),
6000a657bbc2c6fc9daf699942e023050536d5ec95fDerek Sollenberger                               r0Name.c_str(), r1Name.c_str());
6010a657bbc2c6fc9daf699942e023050536d5ec95fDerek Sollenberger
6020a657bbc2c6fc9daf699942e023050536d5ec95fDerek Sollenberger        // if r(t) > 0 for the smaller root, then t will be our x coordinate
6030a657bbc2c6fc9daf699942e023050536d5ec95fDerek Sollenberger        builder->fsCodeAppendf("\t\t\tif (%s * %s + %s > 0.0) {\n",
6040a657bbc2c6fc9daf699942e023050536d5ec95fDerek Sollenberger                               tName.c_str(), p5.c_str(), p3.c_str());
6050a657bbc2c6fc9daf699942e023050536d5ec95fDerek Sollenberger
6060a657bbc2c6fc9daf699942e023050536d5ec95fDerek Sollenberger        builder->fsCodeAppend("\t\t\t");
6070a657bbc2c6fc9daf699942e023050536d5ec95fDerek Sollenberger        this->emitColor(builder, tName.c_str(), key, outputColor, inputColor, samplers);
6080a657bbc2c6fc9daf699942e023050536d5ec95fDerek Sollenberger
6090a657bbc2c6fc9daf699942e023050536d5ec95fDerek Sollenberger        // end if (r(t) > 0) for smaller root
6100a657bbc2c6fc9daf699942e023050536d5ec95fDerek Sollenberger        builder->fsCodeAppend("\t\t\t}\n");
6110a657bbc2c6fc9daf699942e023050536d5ec95fDerek Sollenberger        // end if (r(t) > 0), else, for larger root
6120a657bbc2c6fc9daf699942e023050536d5ec95fDerek Sollenberger        builder->fsCodeAppend("\t\t}\n");
6130a657bbc2c6fc9daf699942e023050536d5ec95fDerek Sollenberger        // end if (discriminant >= 0)
6140a657bbc2c6fc9daf699942e023050536d5ec95fDerek Sollenberger        builder->fsCodeAppend("\t}\n");
6150a657bbc2c6fc9daf699942e023050536d5ec95fDerek Sollenberger    } else {
61680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
6170a657bbc2c6fc9daf699942e023050536d5ec95fDerek Sollenberger        // linear case: t = -c/b
6180a657bbc2c6fc9daf699942e023050536d5ec95fDerek Sollenberger        builder->fsCodeAppendf("\tfloat %s = -(%s / %s);\n", tName.c_str(),
6190a657bbc2c6fc9daf699942e023050536d5ec95fDerek Sollenberger                               cName.c_str(), bVar.c_str());
62080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
6210a657bbc2c6fc9daf699942e023050536d5ec95fDerek Sollenberger        // if r(t) > 0, then t will be the x coordinate
6220a657bbc2c6fc9daf699942e023050536d5ec95fDerek Sollenberger        builder->fsCodeAppendf("\tif (%s * %s + %s > 0.0) {\n", tName.c_str(),
6230a657bbc2c6fc9daf699942e023050536d5ec95fDerek Sollenberger                               p5.c_str(), p3.c_str());
6240a657bbc2c6fc9daf699942e023050536d5ec95fDerek Sollenberger        builder->fsCodeAppend("\t");
6250a657bbc2c6fc9daf699942e023050536d5ec95fDerek Sollenberger        this->emitColor(builder, tName.c_str(), key, outputColor, inputColor, samplers);
6260a657bbc2c6fc9daf699942e023050536d5ec95fDerek Sollenberger        builder->fsCodeAppend("\t}\n");
62780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    }
62880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru}
62980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
630e2022cc36e47b9f0d219eb5cd24be61772c28d3bDerek Sollenbergervoid GrGLConical2Gradient::setData(const GrGLUniformManager& uman,
631e2022cc36e47b9f0d219eb5cd24be61772c28d3bDerek Sollenberger                                   const GrDrawEffect& drawEffect) {
632e2022cc36e47b9f0d219eb5cd24be61772c28d3bDerek Sollenberger    INHERITED::setData(uman, drawEffect);
633e2022cc36e47b9f0d219eb5cd24be61772c28d3bDerek Sollenberger    const GrConical2Gradient& data = drawEffect.castEffect<GrConical2Gradient>();
6340a657bbc2c6fc9daf699942e023050536d5ec95fDerek Sollenberger    SkASSERT(data.isDegenerate() == fIsDegenerate);
635363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger    SkScalar centerX1 = data.center();
636363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger    SkScalar radius0 = data.radius();
637363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger    SkScalar diffRadius = data.diffRadius();
63880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
63980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    if (fCachedCenter != centerX1 ||
64080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        fCachedRadius != radius0 ||
64180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        fCachedDiffRadius != diffRadius) {
64280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
643363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger        SkScalar a = SkScalarMul(centerX1, centerX1) - diffRadius * diffRadius;
64480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
64580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        // When we're in the degenerate (linear) case, the second
64680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        // value will be INF but the program doesn't read it. (We
64780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        // use the same 6 uniforms even though we don't need them
64880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        // all in the linear case just to keep the code complexity
64980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        // down).
65080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        float values[6] = {
651363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger            SkScalarToFloat(a * 4),
652363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger            1.f / (SkScalarToFloat(a)),
653363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger            SkScalarToFloat(centerX1),
654363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger            SkScalarToFloat(radius0),
655363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger            SkScalarToFloat(SkScalarMul(radius0, radius0)),
656363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger            SkScalarToFloat(diffRadius)
65780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        };
65880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
659910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger        uman.set1fv(fParamUni, 6, values);
66080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        fCachedCenter = centerX1;
66180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        fCachedRadius = radius0;
66280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        fCachedDiffRadius = diffRadius;
66380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    }
66480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru}
66580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
666e2022cc36e47b9f0d219eb5cd24be61772c28d3bDerek SollenbergerGrGLEffect::EffectKey GrGLConical2Gradient::GenKey(const GrDrawEffect& drawEffect,
667e2022cc36e47b9f0d219eb5cd24be61772c28d3bDerek Sollenberger                                                   const GrGLCaps&) {
668363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger    enum {
6690a657bbc2c6fc9daf699942e023050536d5ec95fDerek Sollenberger        kIsDegenerate = 1 << kBaseKeyBitCnt,
670363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger    };
671363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger
6720a657bbc2c6fc9daf699942e023050536d5ec95fDerek Sollenberger    EffectKey key = GenBaseGradientKey(drawEffect);
673e2022cc36e47b9f0d219eb5cd24be61772c28d3bDerek Sollenberger    if (drawEffect.castEffect<GrConical2Gradient>().isDegenerate()) {
674363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger        key |= kIsDegenerate;
675363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger    }
676363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger    return key;
67780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru}
67880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
67980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru/////////////////////////////////////////////////////////////////////
68080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
681d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek SollenbergerGrEffectRef* SkTwoPointConicalGradient::asNewEffect(GrContext* context, const SkPaint&) const {
682d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger    SkASSERT(NULL != context);
683363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger    SkASSERT(fPtsToUnit.isIdentity());
684363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger    // invert the localM, translate to center1, rotate so center2 is on x axis.
68580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    SkMatrix matrix;
686363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger    if (!this->getLocalMatrix().invert(&matrix)) {
687d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger        return NULL;
688363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger    }
689363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger    matrix.postTranslate(-fCenter1.fX, -fCenter1.fY);
690363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger
69180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    SkPoint diff = fCenter2 - fCenter1;
69280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    SkScalar diffLen = diff.length();
69380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    if (0 != diffLen) {
69480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        SkScalar invDiffLen = SkScalarInvert(diffLen);
695363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger        SkMatrix rot;
696363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger        rot.setSinCos(-SkScalarMul(invDiffLen, diff.fY),
697363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger                       SkScalarMul(invDiffLen, diff.fX));
698363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger        matrix.postConcat(rot);
69980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    }
70080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
701d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger    return GrConical2Gradient::Create(context, *this, matrix, fTileMode);
70280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru}
70380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
70480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru#else
70580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
706d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek SollenbergerGrEffectRef* SkTwoPointConicalGradient::asNewEffect(GrContext*, const SkPaint&) const {
70780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    SkDEBUGFAIL("Should not call in GPU-less build");
708d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger    return NULL;
70980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru}
71080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
71180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru#endif
712d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger
713d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger#ifdef SK_DEVELOPER
714d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenbergervoid SkTwoPointConicalGradient::toString(SkString* str) const {
715d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger    str->append("SkTwoPointConicalGradient: (");
716d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger
717d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger    str->append("center1: (");
718d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger    str->appendScalar(fCenter1.fX);
719d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger    str->append(", ");
720d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger    str->appendScalar(fCenter1.fY);
721d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger    str->append(") radius1: ");
722d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger    str->appendScalar(fRadius1);
723d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger    str->append(" ");
724d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger
725d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger    str->append("center2: (");
726d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger    str->appendScalar(fCenter2.fX);
727d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger    str->append(", ");
728d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger    str->appendScalar(fCenter2.fY);
729d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger    str->append(") radius2: ");
730d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger    str->appendScalar(fRadius2);
731d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger    str->append(" ");
732d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger
733d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger    this->INHERITED::toString(str);
734d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger
735d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger    str->append(")");
736d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger}
737d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger#endif
738