1589708bf7c706348b763e8277004cb160b202bdbrileya@google.com
2589708bf7c706348b763e8277004cb160b202bdbrileya@google.com/*
3589708bf7c706348b763e8277004cb160b202bdbrileya@google.com * Copyright 2012 Google Inc.
4589708bf7c706348b763e8277004cb160b202bdbrileya@google.com *
5589708bf7c706348b763e8277004cb160b202bdbrileya@google.com * Use of this source code is governed by a BSD-style license that can be
6589708bf7c706348b763e8277004cb160b202bdbrileya@google.com * found in the LICENSE file.
7589708bf7c706348b763e8277004cb160b202bdbrileya@google.com */
8589708bf7c706348b763e8277004cb160b202bdbrileya@google.com
99de5b514d38c5b36066bcdc14fba2f7e5196d372dandov#include "SkTwoPointRadialGradient.h"
10589708bf7c706348b763e8277004cb160b202bdbrileya@google.com
11589708bf7c706348b763e8277004cb160b202bdbrileya@google.com/* Two-point radial gradients are specified by two circles, each with a center
12589708bf7c706348b763e8277004cb160b202bdbrileya@google.com   point and radius.  The gradient can be considered to be a series of
13589708bf7c706348b763e8277004cb160b202bdbrileya@google.com   concentric circles, with the color interpolated from the start circle
14589708bf7c706348b763e8277004cb160b202bdbrileya@google.com   (at t=0) to the end circle (at t=1).
15589708bf7c706348b763e8277004cb160b202bdbrileya@google.com
16589708bf7c706348b763e8277004cb160b202bdbrileya@google.com   For each point (x, y) in the span, we want to find the
17589708bf7c706348b763e8277004cb160b202bdbrileya@google.com   interpolated circle that intersects that point.  The center
18589708bf7c706348b763e8277004cb160b202bdbrileya@google.com   of the desired circle (Cx, Cy) falls at some distance t
19589708bf7c706348b763e8277004cb160b202bdbrileya@google.com   along the line segment between the start point (Sx, Sy) and
20589708bf7c706348b763e8277004cb160b202bdbrileya@google.com   end point (Ex, Ey):
21589708bf7c706348b763e8277004cb160b202bdbrileya@google.com
22589708bf7c706348b763e8277004cb160b202bdbrileya@google.com      Cx = (1 - t) * Sx + t * Ex        (0 <= t <= 1)
23589708bf7c706348b763e8277004cb160b202bdbrileya@google.com      Cy = (1 - t) * Sy + t * Ey
24589708bf7c706348b763e8277004cb160b202bdbrileya@google.com
25589708bf7c706348b763e8277004cb160b202bdbrileya@google.com   The radius of the desired circle (r) is also a linear interpolation t
26589708bf7c706348b763e8277004cb160b202bdbrileya@google.com   between the start and end radii (Sr and Er):
27589708bf7c706348b763e8277004cb160b202bdbrileya@google.com
28589708bf7c706348b763e8277004cb160b202bdbrileya@google.com      r = (1 - t) * Sr + t * Er
29589708bf7c706348b763e8277004cb160b202bdbrileya@google.com
30589708bf7c706348b763e8277004cb160b202bdbrileya@google.com   But
31589708bf7c706348b763e8277004cb160b202bdbrileya@google.com
32589708bf7c706348b763e8277004cb160b202bdbrileya@google.com      (x - Cx)^2 + (y - Cy)^2 = r^2
33589708bf7c706348b763e8277004cb160b202bdbrileya@google.com
34589708bf7c706348b763e8277004cb160b202bdbrileya@google.com   so
35589708bf7c706348b763e8277004cb160b202bdbrileya@google.com
36589708bf7c706348b763e8277004cb160b202bdbrileya@google.com     (x - ((1 - t) * Sx + t * Ex))^2
37589708bf7c706348b763e8277004cb160b202bdbrileya@google.com   + (y - ((1 - t) * Sy + t * Ey))^2
38589708bf7c706348b763e8277004cb160b202bdbrileya@google.com   = ((1 - t) * Sr + t * Er)^2
39589708bf7c706348b763e8277004cb160b202bdbrileya@google.com
40589708bf7c706348b763e8277004cb160b202bdbrileya@google.com   Solving for t yields
41589708bf7c706348b763e8277004cb160b202bdbrileya@google.com
42589708bf7c706348b763e8277004cb160b202bdbrileya@google.com     [(Sx - Ex)^2 + (Sy - Ey)^2 - (Er - Sr)^2)] * t^2
43589708bf7c706348b763e8277004cb160b202bdbrileya@google.com   + [2 * (Sx - Ex)(x - Sx) + 2 * (Sy - Ey)(y - Sy) - 2 * (Er - Sr) * Sr] * t
44589708bf7c706348b763e8277004cb160b202bdbrileya@google.com   + [(x - Sx)^2 + (y - Sy)^2 - Sr^2] = 0
45589708bf7c706348b763e8277004cb160b202bdbrileya@google.com
46589708bf7c706348b763e8277004cb160b202bdbrileya@google.com   To simplify, let Dx = Sx - Ex, Dy = Sy - Ey, Dr = Er - Sr, dx = x - Sx, dy = y - Sy
47589708bf7c706348b763e8277004cb160b202bdbrileya@google.com
48589708bf7c706348b763e8277004cb160b202bdbrileya@google.com     [Dx^2 + Dy^2 - Dr^2)] * t^2
49589708bf7c706348b763e8277004cb160b202bdbrileya@google.com   + 2 * [Dx * dx + Dy * dy - Dr * Sr] * t
50589708bf7c706348b763e8277004cb160b202bdbrileya@google.com   + [dx^2 + dy^2 - Sr^2] = 0
51589708bf7c706348b763e8277004cb160b202bdbrileya@google.com
52589708bf7c706348b763e8277004cb160b202bdbrileya@google.com   A quadratic in t.  The two roots of the quadratic reflect the two
53589708bf7c706348b763e8277004cb160b202bdbrileya@google.com   possible circles on which the point may fall.  Solving for t yields
54589708bf7c706348b763e8277004cb160b202bdbrileya@google.com   the gradient value to use.
55589708bf7c706348b763e8277004cb160b202bdbrileya@google.com
56589708bf7c706348b763e8277004cb160b202bdbrileya@google.com   If a<0, the start circle is entirely contained in the
57589708bf7c706348b763e8277004cb160b202bdbrileya@google.com   end circle, and one of the roots will be <0 or >1 (off the line
58589708bf7c706348b763e8277004cb160b202bdbrileya@google.com   segment).  If a>0, the start circle falls at least partially
59589708bf7c706348b763e8277004cb160b202bdbrileya@google.com   outside the end circle (or vice versa), and the gradient
60589708bf7c706348b763e8277004cb160b202bdbrileya@google.com   defines a "tube" where a point may be on one circle (on the
61589708bf7c706348b763e8277004cb160b202bdbrileya@google.com   inside of the tube) or the other (outside of the tube).  We choose
62589708bf7c706348b763e8277004cb160b202bdbrileya@google.com   one arbitrarily.
63589708bf7c706348b763e8277004cb160b202bdbrileya@google.com
64589708bf7c706348b763e8277004cb160b202bdbrileya@google.com   In order to keep the math to within the limits of fixed point,
65589708bf7c706348b763e8277004cb160b202bdbrileya@google.com   we divide the entire quadratic by Dr^2, and replace
66589708bf7c706348b763e8277004cb160b202bdbrileya@google.com   (x - Sx)/Dr with x' and (y - Sy)/Dr with y', giving
67589708bf7c706348b763e8277004cb160b202bdbrileya@google.com
68589708bf7c706348b763e8277004cb160b202bdbrileya@google.com   [Dx^2 / Dr^2 + Dy^2 / Dr^2 - 1)] * t^2
69589708bf7c706348b763e8277004cb160b202bdbrileya@google.com   + 2 * [x' * Dx / Dr + y' * Dy / Dr - Sr / Dr] * t
70589708bf7c706348b763e8277004cb160b202bdbrileya@google.com   + [x'^2 + y'^2 - Sr^2/Dr^2] = 0
71589708bf7c706348b763e8277004cb160b202bdbrileya@google.com
72589708bf7c706348b763e8277004cb160b202bdbrileya@google.com   (x' and y' are computed by appending the subtract and scale to the
73589708bf7c706348b763e8277004cb160b202bdbrileya@google.com   fDstToIndex matrix in the constructor).
74589708bf7c706348b763e8277004cb160b202bdbrileya@google.com
75589708bf7c706348b763e8277004cb160b202bdbrileya@google.com   Since the 'A' component of the quadratic is independent of x' and y', it
76589708bf7c706348b763e8277004cb160b202bdbrileya@google.com   is precomputed in the constructor.  Since the 'B' component is linear in
77589708bf7c706348b763e8277004cb160b202bdbrileya@google.com   x' and y', if x and y are linear in the span, 'B' can be computed
78589708bf7c706348b763e8277004cb160b202bdbrileya@google.com   incrementally with a simple delta (db below).  If it is not (e.g.,
79589708bf7c706348b763e8277004cb160b202bdbrileya@google.com   a perspective projection), it must be computed in the loop.
80589708bf7c706348b763e8277004cb160b202bdbrileya@google.com
81589708bf7c706348b763e8277004cb160b202bdbrileya@google.com*/
82589708bf7c706348b763e8277004cb160b202bdbrileya@google.com
83589708bf7c706348b763e8277004cb160b202bdbrileya@google.comnamespace {
84589708bf7c706348b763e8277004cb160b202bdbrileya@google.com
85589708bf7c706348b763e8277004cb160b202bdbrileya@google.cominline SkFixed two_point_radial(SkScalar b, SkScalar fx, SkScalar fy,
86589708bf7c706348b763e8277004cb160b202bdbrileya@google.com                                SkScalar sr2d2, SkScalar foura,
87589708bf7c706348b763e8277004cb160b202bdbrileya@google.com                                SkScalar oneOverTwoA, bool posRoot) {
88589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    SkScalar c = SkScalarSquare(fx) + SkScalarSquare(fy) - sr2d2;
89589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    if (0 == foura) {
90589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        return SkScalarToFixed(SkScalarDiv(-c, b));
91589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    }
92589708bf7c706348b763e8277004cb160b202bdbrileya@google.com
93589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    SkScalar discrim = SkScalarSquare(b) - SkScalarMul(foura, c);
94589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    if (discrim < 0) {
95589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        discrim = -discrim;
96589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    }
97589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    SkScalar rootDiscrim = SkScalarSqrt(discrim);
98589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    SkScalar result;
99589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    if (posRoot) {
100589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        result = SkScalarMul(-b + rootDiscrim, oneOverTwoA);
101589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    } else {
102589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        result = SkScalarMul(-b - rootDiscrim, oneOverTwoA);
103589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    }
104589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    return SkScalarToFixed(result);
105589708bf7c706348b763e8277004cb160b202bdbrileya@google.com}
106589708bf7c706348b763e8277004cb160b202bdbrileya@google.com
107589708bf7c706348b763e8277004cb160b202bdbrileya@google.comtypedef void (* TwoPointRadialShadeProc)(SkScalar fx, SkScalar dx,
108589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        SkScalar fy, SkScalar dy,
109589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        SkScalar b, SkScalar db,
110589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        SkScalar fSr2D2, SkScalar foura, SkScalar fOneOverTwoA, bool posRoot,
111589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        SkPMColor* SK_RESTRICT dstC, const SkPMColor* SK_RESTRICT cache,
112589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        int count);
113589708bf7c706348b763e8277004cb160b202bdbrileya@google.com
114589708bf7c706348b763e8277004cb160b202bdbrileya@google.comvoid shadeSpan_twopoint_clamp(SkScalar fx, SkScalar dx,
115589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        SkScalar fy, SkScalar dy,
116589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        SkScalar b, SkScalar db,
117589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        SkScalar fSr2D2, SkScalar foura, SkScalar fOneOverTwoA, bool posRoot,
118589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        SkPMColor* SK_RESTRICT dstC, const SkPMColor* SK_RESTRICT cache,
119589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        int count) {
120589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    for (; count > 0; --count) {
121589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        SkFixed t = two_point_radial(b, fx, fy, fSr2D2, foura,
122589708bf7c706348b763e8277004cb160b202bdbrileya@google.com                                     fOneOverTwoA, posRoot);
123589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        SkFixed index = SkClampMax(t, 0xFFFF);
124589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        SkASSERT(index <= 0xFFFF);
125589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        *dstC++ = cache[index >> SkGradientShaderBase::kCache32Shift];
126589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        fx += dx;
127589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        fy += dy;
128589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        b += db;
129589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    }
130589708bf7c706348b763e8277004cb160b202bdbrileya@google.com}
131589708bf7c706348b763e8277004cb160b202bdbrileya@google.comvoid shadeSpan_twopoint_mirror(SkScalar fx, SkScalar dx,
132589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        SkScalar fy, SkScalar dy,
133589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        SkScalar b, SkScalar db,
134589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        SkScalar fSr2D2, SkScalar foura, SkScalar fOneOverTwoA, bool posRoot,
135589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        SkPMColor* SK_RESTRICT dstC, const SkPMColor* SK_RESTRICT cache,
136589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        int count) {
137589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    for (; count > 0; --count) {
138589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        SkFixed t = two_point_radial(b, fx, fy, fSr2D2, foura,
139589708bf7c706348b763e8277004cb160b202bdbrileya@google.com                                     fOneOverTwoA, posRoot);
140589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        SkFixed index = mirror_tileproc(t);
141589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        SkASSERT(index <= 0xFFFF);
142589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        *dstC++ = cache[index >> SkGradientShaderBase::kCache32Shift];
143589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        fx += dx;
144589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        fy += dy;
145589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        b += db;
146589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    }
147589708bf7c706348b763e8277004cb160b202bdbrileya@google.com}
148589708bf7c706348b763e8277004cb160b202bdbrileya@google.com
149589708bf7c706348b763e8277004cb160b202bdbrileya@google.comvoid shadeSpan_twopoint_repeat(SkScalar fx, SkScalar dx,
150589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        SkScalar fy, SkScalar dy,
151589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        SkScalar b, SkScalar db,
152589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        SkScalar fSr2D2, SkScalar foura, SkScalar fOneOverTwoA, bool posRoot,
153589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        SkPMColor* SK_RESTRICT dstC, const SkPMColor* SK_RESTRICT cache,
154589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        int count) {
155589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    for (; count > 0; --count) {
156589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        SkFixed t = two_point_radial(b, fx, fy, fSr2D2, foura,
157589708bf7c706348b763e8277004cb160b202bdbrileya@google.com                                     fOneOverTwoA, posRoot);
158589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        SkFixed index = repeat_tileproc(t);
159589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        SkASSERT(index <= 0xFFFF);
160589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        *dstC++ = cache[index >> SkGradientShaderBase::kCache32Shift];
161589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        fx += dx;
162589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        fy += dy;
163589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        b += db;
164589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    }
165589708bf7c706348b763e8277004cb160b202bdbrileya@google.com}
166589708bf7c706348b763e8277004cb160b202bdbrileya@google.com}
167589708bf7c706348b763e8277004cb160b202bdbrileya@google.com
16898e8b6de04e4c20451fbe3353645e3e384a76550rileya@google.com/////////////////////////////////////////////////////////////////////
16998e8b6de04e4c20451fbe3353645e3e384a76550rileya@google.com
170addf2edf3da20f053daa3897cfe2c52d7369a7b1reedSkTwoPointRadialGradient::SkTwoPointRadialGradient(const SkPoint& start, SkScalar startRadius,
171addf2edf3da20f053daa3897cfe2c52d7369a7b1reed                                                   const SkPoint& end, SkScalar endRadius,
172addf2edf3da20f053daa3897cfe2c52d7369a7b1reed                                                   const Descriptor& desc)
173addf2edf3da20f053daa3897cfe2c52d7369a7b1reed    : SkGradientShaderBase(desc)
174addf2edf3da20f053daa3897cfe2c52d7369a7b1reed    , fCenter1(start)
175addf2edf3da20f053daa3897cfe2c52d7369a7b1reed    , fCenter2(end)
176addf2edf3da20f053daa3897cfe2c52d7369a7b1reed    , fRadius1(startRadius)
177addf2edf3da20f053daa3897cfe2c52d7369a7b1reed    , fRadius2(endRadius)
178addf2edf3da20f053daa3897cfe2c52d7369a7b1reed{
179589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    init();
180589708bf7c706348b763e8277004cb160b202bdbrileya@google.com}
181589708bf7c706348b763e8277004cb160b202bdbrileya@google.com
182589708bf7c706348b763e8277004cb160b202bdbrileya@google.comSkShader::BitmapType SkTwoPointRadialGradient::asABitmap(
183589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    SkBitmap* bitmap,
184589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    SkMatrix* matrix,
185589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    SkShader::TileMode* xy) const {
186589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    if (bitmap) {
1871c6d64b78b24083ee9fd7411dac8a4a7e2d03a3crileya@google.com        this->getGradientTableBitmap(bitmap);
188589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    }
189589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    SkScalar diffL = 0; // just to avoid gcc warning
190589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    if (matrix) {
191589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        diffL = SkScalarSqrt(SkScalarSquare(fDiff.fX) +
192589708bf7c706348b763e8277004cb160b202bdbrileya@google.com                             SkScalarSquare(fDiff.fY));
193589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    }
194589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    if (matrix) {
195589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        if (diffL) {
196589708bf7c706348b763e8277004cb160b202bdbrileya@google.com            SkScalar invDiffL = SkScalarInvert(diffL);
197589708bf7c706348b763e8277004cb160b202bdbrileya@google.com            matrix->setSinCos(-SkScalarMul(invDiffL, fDiff.fY),
198589708bf7c706348b763e8277004cb160b202bdbrileya@google.com                              SkScalarMul(invDiffL, fDiff.fX));
199589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        } else {
200589708bf7c706348b763e8277004cb160b202bdbrileya@google.com            matrix->reset();
201589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        }
202589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        matrix->preConcat(fPtsToUnit);
203589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    }
204589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    if (xy) {
205589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        xy[0] = fTileMode;
206589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        xy[1] = kClamp_TileMode;
207589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    }
208589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    return kTwoPointRadial_BitmapType;
209589708bf7c706348b763e8277004cb160b202bdbrileya@google.com}
210589708bf7c706348b763e8277004cb160b202bdbrileya@google.com
211589708bf7c706348b763e8277004cb160b202bdbrileya@google.comSkShader::GradientType SkTwoPointRadialGradient::asAGradient(
212589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    SkShader::GradientInfo* info) const {
213589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    if (info) {
214589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        commonAsAGradient(info);
215589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        info->fPoint[0] = fCenter1;
216589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        info->fPoint[1] = fCenter2;
217589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        info->fRadius[0] = fRadius1;
218589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        info->fRadius[1] = fRadius2;
219589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    }
220589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    return kRadial2_GradientType;
221589708bf7c706348b763e8277004cb160b202bdbrileya@google.com}
222589708bf7c706348b763e8277004cb160b202bdbrileya@google.com
22387fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.orgsize_t SkTwoPointRadialGradient::contextSize() const {
22487fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org    return sizeof(TwoPointRadialGradientContext);
22587fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org}
22687fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org
227ce56d965069c1649afe14319cb239e6ad670682acommit-bot@chromium.orgSkShader::Context* SkTwoPointRadialGradient::onCreateContext(const ContextRec& rec,
228ce56d965069c1649afe14319cb239e6ad670682acommit-bot@chromium.org                                                             void* storage) const {
22987fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org    // For now, we might have divided by zero, so detect that.
23087fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org    if (0 == fDiffRadius) {
23187fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org        return NULL;
23287fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org    }
233e901b6de3ef8dea842008a08fc81e92fb1478d61commit-bot@chromium.org    return SkNEW_PLACEMENT_ARGS(storage, TwoPointRadialGradientContext, (*this, rec));
23487fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org}
23587fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org
23687fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.orgSkTwoPointRadialGradient::TwoPointRadialGradientContext::TwoPointRadialGradientContext(
237e901b6de3ef8dea842008a08fc81e92fb1478d61commit-bot@chromium.org        const SkTwoPointRadialGradient& shader, const ContextRec& rec)
238e901b6de3ef8dea842008a08fc81e92fb1478d61commit-bot@chromium.org    : INHERITED(shader, rec)
23987fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org{
24087fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org    // we don't have a span16 proc
24187fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org    fFlags &= ~kHasSpan16_Flag;
24287fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org}
24387fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org
24487fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.orgvoid SkTwoPointRadialGradient::TwoPointRadialGradientContext::shadeSpan(
24587fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org        int x, int y, SkPMColor* dstCParam, int count) {
246589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    SkASSERT(count > 0);
247589708bf7c706348b763e8277004cb160b202bdbrileya@google.com
24887fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org    const SkTwoPointRadialGradient& twoPointRadialGradient =
24987fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org            static_cast<const SkTwoPointRadialGradient&>(fShader);
25087fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org
251589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    SkPMColor* SK_RESTRICT dstC = dstCParam;
252589708bf7c706348b763e8277004cb160b202bdbrileya@google.com
253589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    // Zero difference between radii:  fill with transparent black.
25487fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org    if (twoPointRadialGradient.fDiffRadius == 0) {
255589708bf7c706348b763e8277004cb160b202bdbrileya@google.com      sk_bzero(dstC, count * sizeof(*dstC));
256589708bf7c706348b763e8277004cb160b202bdbrileya@google.com      return;
257589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    }
258589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    SkMatrix::MapXYProc dstProc = fDstToIndexProc;
25987fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org    TileProc            proc = twoPointRadialGradient.fTileProc;
26087fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org    const SkPMColor* SK_RESTRICT cache = fCache->getCache32();
261589708bf7c706348b763e8277004cb160b202bdbrileya@google.com
26287fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org    SkScalar foura = twoPointRadialGradient.fA * 4;
26387fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org    bool posRoot = twoPointRadialGradient.fDiffRadius < 0;
264589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    if (fDstToIndexClass != kPerspective_MatrixClass) {
265589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        SkPoint srcPt;
266589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        dstProc(fDstToIndex, SkIntToScalar(x) + SK_ScalarHalf,
267589708bf7c706348b763e8277004cb160b202bdbrileya@google.com                             SkIntToScalar(y) + SK_ScalarHalf, &srcPt);
268589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        SkScalar dx, fx = srcPt.fX;
269589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        SkScalar dy, fy = srcPt.fY;
270589708bf7c706348b763e8277004cb160b202bdbrileya@google.com
271589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        if (fDstToIndexClass == kFixedStepInX_MatrixClass) {
272589708bf7c706348b763e8277004cb160b202bdbrileya@google.com            SkFixed fixedX, fixedY;
273589708bf7c706348b763e8277004cb160b202bdbrileya@google.com            (void)fDstToIndex.fixedStepInX(SkIntToScalar(y), &fixedX, &fixedY);
274589708bf7c706348b763e8277004cb160b202bdbrileya@google.com            dx = SkFixedToScalar(fixedX);
275589708bf7c706348b763e8277004cb160b202bdbrileya@google.com            dy = SkFixedToScalar(fixedY);
276589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        } else {
277589708bf7c706348b763e8277004cb160b202bdbrileya@google.com            SkASSERT(fDstToIndexClass == kLinear_MatrixClass);
278589708bf7c706348b763e8277004cb160b202bdbrileya@google.com            dx = fDstToIndex.getScaleX();
279589708bf7c706348b763e8277004cb160b202bdbrileya@google.com            dy = fDstToIndex.getSkewY();
280589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        }
28187fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org        SkScalar b = (SkScalarMul(twoPointRadialGradient.fDiff.fX, fx) +
28287fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org                     SkScalarMul(twoPointRadialGradient.fDiff.fY, fy) -
28387fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org                     twoPointRadialGradient.fStartRadius) * 2;
28487fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org        SkScalar db = (SkScalarMul(twoPointRadialGradient.fDiff.fX, dx) +
28587fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org                      SkScalarMul(twoPointRadialGradient.fDiff.fY, dy)) * 2;
286589708bf7c706348b763e8277004cb160b202bdbrileya@google.com
287589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        TwoPointRadialShadeProc shadeProc = shadeSpan_twopoint_repeat;
28887fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org        if (SkShader::kClamp_TileMode == twoPointRadialGradient.fTileMode) {
289589708bf7c706348b763e8277004cb160b202bdbrileya@google.com            shadeProc = shadeSpan_twopoint_clamp;
29087fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org        } else if (SkShader::kMirror_TileMode == twoPointRadialGradient.fTileMode) {
291589708bf7c706348b763e8277004cb160b202bdbrileya@google.com            shadeProc = shadeSpan_twopoint_mirror;
292589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        } else {
29387fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org            SkASSERT(SkShader::kRepeat_TileMode == twoPointRadialGradient.fTileMode);
294589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        }
295589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        (*shadeProc)(fx, dx, fy, dy, b, db,
29687fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org                     twoPointRadialGradient.fSr2D2, foura,
29787fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org                     twoPointRadialGradient.fOneOverTwoA, posRoot,
298589708bf7c706348b763e8277004cb160b202bdbrileya@google.com                     dstC, cache, count);
299589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    } else {    // perspective case
300589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        SkScalar dstX = SkIntToScalar(x);
301589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        SkScalar dstY = SkIntToScalar(y);
302589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        for (; count > 0; --count) {
303589708bf7c706348b763e8277004cb160b202bdbrileya@google.com            SkPoint             srcPt;
304589708bf7c706348b763e8277004cb160b202bdbrileya@google.com            dstProc(fDstToIndex, dstX, dstY, &srcPt);
305589708bf7c706348b763e8277004cb160b202bdbrileya@google.com            SkScalar fx = srcPt.fX;
306589708bf7c706348b763e8277004cb160b202bdbrileya@google.com            SkScalar fy = srcPt.fY;
30787fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org            SkScalar b = (SkScalarMul(twoPointRadialGradient.fDiff.fX, fx) +
30887fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org                         SkScalarMul(twoPointRadialGradient.fDiff.fY, fy) -
30987fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org                         twoPointRadialGradient.fStartRadius) * 2;
31087fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org            SkFixed t = two_point_radial(b, fx, fy, twoPointRadialGradient.fSr2D2, foura,
31187fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org                                         twoPointRadialGradient.fOneOverTwoA, posRoot);
312589708bf7c706348b763e8277004cb160b202bdbrileya@google.com            SkFixed index = proc(t);
313589708bf7c706348b763e8277004cb160b202bdbrileya@google.com            SkASSERT(index <= 0xFFFF);
314589708bf7c706348b763e8277004cb160b202bdbrileya@google.com            *dstC++ = cache[index >> SkGradientShaderBase::kCache32Shift];
315589708bf7c706348b763e8277004cb160b202bdbrileya@google.com            dstX += SK_Scalar1;
316589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        }
317589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    }
318589708bf7c706348b763e8277004cb160b202bdbrileya@google.com}
319589708bf7c706348b763e8277004cb160b202bdbrileya@google.com
3200f10f7bf1fb43ca6346dc220a076773b1f19a367commit-bot@chromium.org#ifndef SK_IGNORE_TO_STRING
32176f9e938df0b5826fd4c80b854ceafaf385cfbe1robertphillips@google.comvoid SkTwoPointRadialGradient::toString(SkString* str) const {
32276f9e938df0b5826fd4c80b854ceafaf385cfbe1robertphillips@google.com    str->append("SkTwoPointRadialGradient: (");
32376f9e938df0b5826fd4c80b854ceafaf385cfbe1robertphillips@google.com
32476f9e938df0b5826fd4c80b854ceafaf385cfbe1robertphillips@google.com    str->append("center1: (");
32576f9e938df0b5826fd4c80b854ceafaf385cfbe1robertphillips@google.com    str->appendScalar(fCenter1.fX);
32676f9e938df0b5826fd4c80b854ceafaf385cfbe1robertphillips@google.com    str->append(", ");
32776f9e938df0b5826fd4c80b854ceafaf385cfbe1robertphillips@google.com    str->appendScalar(fCenter1.fY);
32876f9e938df0b5826fd4c80b854ceafaf385cfbe1robertphillips@google.com    str->append(") radius1: ");
32976f9e938df0b5826fd4c80b854ceafaf385cfbe1robertphillips@google.com    str->appendScalar(fRadius1);
33076f9e938df0b5826fd4c80b854ceafaf385cfbe1robertphillips@google.com    str->append(" ");
33176f9e938df0b5826fd4c80b854ceafaf385cfbe1robertphillips@google.com
33276f9e938df0b5826fd4c80b854ceafaf385cfbe1robertphillips@google.com    str->append("center2: (");
33376f9e938df0b5826fd4c80b854ceafaf385cfbe1robertphillips@google.com    str->appendScalar(fCenter2.fX);
33476f9e938df0b5826fd4c80b854ceafaf385cfbe1robertphillips@google.com    str->append(", ");
33576f9e938df0b5826fd4c80b854ceafaf385cfbe1robertphillips@google.com    str->appendScalar(fCenter2.fY);
33676f9e938df0b5826fd4c80b854ceafaf385cfbe1robertphillips@google.com    str->append(") radius2: ");
33776f9e938df0b5826fd4c80b854ceafaf385cfbe1robertphillips@google.com    str->appendScalar(fRadius2);
33876f9e938df0b5826fd4c80b854ceafaf385cfbe1robertphillips@google.com    str->append(" ");
33976f9e938df0b5826fd4c80b854ceafaf385cfbe1robertphillips@google.com
34076f9e938df0b5826fd4c80b854ceafaf385cfbe1robertphillips@google.com    this->INHERITED::toString(str);
34176f9e938df0b5826fd4c80b854ceafaf385cfbe1robertphillips@google.com
34276f9e938df0b5826fd4c80b854ceafaf385cfbe1robertphillips@google.com    str->append(")");
34376f9e938df0b5826fd4c80b854ceafaf385cfbe1robertphillips@google.com}
34476f9e938df0b5826fd4c80b854ceafaf385cfbe1robertphillips@google.com#endif
34576f9e938df0b5826fd4c80b854ceafaf385cfbe1robertphillips@google.com
3469fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed#ifdef SK_SUPPORT_LEGACY_DEEPFLATTENING
3479fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reedSkTwoPointRadialGradient::SkTwoPointRadialGradient(SkReadBuffer& buffer)
348589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    : INHERITED(buffer),
349589708bf7c706348b763e8277004cb160b202bdbrileya@google.com      fCenter1(buffer.readPoint()),
350589708bf7c706348b763e8277004cb160b202bdbrileya@google.com      fCenter2(buffer.readPoint()),
351589708bf7c706348b763e8277004cb160b202bdbrileya@google.com      fRadius1(buffer.readScalar()),
352589708bf7c706348b763e8277004cb160b202bdbrileya@google.com      fRadius2(buffer.readScalar()) {
353589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    init();
354589708bf7c706348b763e8277004cb160b202bdbrileya@google.com};
3559fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed#endif
3569fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed
3579fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reedSkFlattenable* SkTwoPointRadialGradient::CreateProc(SkReadBuffer& buffer) {
3589fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed    DescriptorScope desc;
3599fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed    if (!desc.unflatten(buffer)) {
3609fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed        return NULL;
3619fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed    }
3629fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed    const SkPoint c1 = buffer.readPoint();
3639fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed    const SkPoint c2 = buffer.readPoint();
3649fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed    const SkScalar r1 = buffer.readScalar();
3659fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed    const SkScalar r2 = buffer.readScalar();
3669fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed    return SkGradientShader::CreateTwoPointRadial(c1, r1, c2, r2, desc.fColors, desc.fPos,
3679fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed                                                  desc.fCount, desc.fTileMode, desc.fGradFlags,
3689fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed                                                  desc.fLocalMatrix);
3699fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed}
370589708bf7c706348b763e8277004cb160b202bdbrileya@google.com
371589708bf7c706348b763e8277004cb160b202bdbrileya@google.comvoid SkTwoPointRadialGradient::flatten(
3728b0e8ac5f582de80356019406e2975079bf0829dcommit-bot@chromium.org    SkWriteBuffer& buffer) const {
373589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    this->INHERITED::flatten(buffer);
374589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    buffer.writePoint(fCenter1);
375589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    buffer.writePoint(fCenter2);
376589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    buffer.writeScalar(fRadius1);
377589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    buffer.writeScalar(fRadius2);
378589708bf7c706348b763e8277004cb160b202bdbrileya@google.com}
379589708bf7c706348b763e8277004cb160b202bdbrileya@google.com
380589708bf7c706348b763e8277004cb160b202bdbrileya@google.comvoid SkTwoPointRadialGradient::init() {
381589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    fDiff = fCenter1 - fCenter2;
382589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    fDiffRadius = fRadius2 - fRadius1;
383589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    // hack to avoid zero-divide for now
384589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    SkScalar inv = fDiffRadius ? SkScalarInvert(fDiffRadius) : 0;
385589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    fDiff.fX = SkScalarMul(fDiff.fX, inv);
386589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    fDiff.fY = SkScalarMul(fDiff.fY, inv);
387589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    fStartRadius = SkScalarMul(fRadius1, inv);
388589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    fSr2D2 = SkScalarSquare(fStartRadius);
389589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    fA = SkScalarSquare(fDiff.fX) + SkScalarSquare(fDiff.fY) - SK_Scalar1;
390589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    fOneOverTwoA = fA ? SkScalarInvert(fA * 2) : 0;
391589708bf7c706348b763e8277004cb160b202bdbrileya@google.com
392589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    fPtsToUnit.setTranslate(-fCenter1.fX, -fCenter1.fY);
393589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    fPtsToUnit.postScale(inv, inv);
394589708bf7c706348b763e8277004cb160b202bdbrileya@google.com}
395589708bf7c706348b763e8277004cb160b202bdbrileya@google.com
396d7cc651b8da11d52ae90e910b948f5e2d15daaf9rileya@google.com/////////////////////////////////////////////////////////////////////
397d7cc651b8da11d52ae90e910b948f5e2d15daaf9rileya@google.com
398cf8fb1f6f03fc77f9927564f9ef9abeeeec508d2bsalomon@google.com#if SK_SUPPORT_GPU
399cf8fb1f6f03fc77f9927564f9ef9abeeeec508d2bsalomon@google.com
400b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt#include "GrTBackendProcessorFactory.h"
40130ba436f04e61d4505fb854d5fc56079636e0788joshualitt#include "gl/builders/GrGLProgramBuilder.h"
4029de5b514d38c5b36066bcdc14fba2f7e5196d372dandov#include "SkGr.h"
4032eaaefd7e6a58339b3f93333f1e9cc92252cc303bsalomon@google.com
404d7cc651b8da11d52ae90e910b948f5e2d15daaf9rileya@google.com// For brevity
4057510b224e52b9518a8ddf7418db0e9c258f79539kkinnunentypedef GrGLProgramDataManager::UniformHandle UniformHandle;
406d7cc651b8da11d52ae90e910b948f5e2d15daaf9rileya@google.com
4070707c29413a5a3cc1c2d14b8c65b3692af5c7411bsalomon@google.comclass GrGLRadial2Gradient : public GrGLGradientEffect {
408d7cc651b8da11d52ae90e910b948f5e2d15daaf9rileya@google.com
409d7cc651b8da11d52ae90e910b948f5e2d15daaf9rileya@google.compublic:
410d7cc651b8da11d52ae90e910b948f5e2d15daaf9rileya@google.com
411b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt    GrGLRadial2Gradient(const GrBackendProcessorFactory& factory, const GrProcessor&);
412d7cc651b8da11d52ae90e910b948f5e2d15daaf9rileya@google.com    virtual ~GrGLRadial2Gradient() { }
413d7cc651b8da11d52ae90e910b948f5e2d15daaf9rileya@google.com
41430ba436f04e61d4505fb854d5fc56079636e0788joshualitt    virtual void emitCode(GrGLProgramBuilder*,
415b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt                          const GrFragmentProcessor&,
416b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt                          const GrProcessorKey&,
417f78df33efc72167f94da1b0476c9a86ba18a5f2cbsalomon@google.com                          const char* outputColor,
418f78df33efc72167f94da1b0476c9a86ba18a5f2cbsalomon@google.com                          const char* inputColor,
41977af6805e5faea1e2a5c0220098aec9082f3a6e5bsalomon@google.com                          const TransformedCoordsArray&,
420f78df33efc72167f94da1b0476c9a86ba18a5f2cbsalomon@google.com                          const TextureSamplerArray&) SK_OVERRIDE;
421b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt    virtual void setData(const GrGLProgramDataManager&, const GrProcessor&) SK_OVERRIDE;
422d7cc651b8da11d52ae90e910b948f5e2d15daaf9rileya@google.com
423b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt    static void GenKey(const GrProcessor&, const GrGLCaps& caps, GrProcessorKeyBuilder* b);
424d7cc651b8da11d52ae90e910b948f5e2d15daaf9rileya@google.com
425d7cc651b8da11d52ae90e910b948f5e2d15daaf9rileya@google.comprotected:
426d7cc651b8da11d52ae90e910b948f5e2d15daaf9rileya@google.com
4275fd7d5c20a15094da3fb6dc1d59955fd8f3217d7commit-bot@chromium.org    UniformHandle fParamUni;
428d7cc651b8da11d52ae90e910b948f5e2d15daaf9rileya@google.com
429d7cc651b8da11d52ae90e910b948f5e2d15daaf9rileya@google.com    const char* fVSVaryingName;
430d7cc651b8da11d52ae90e910b948f5e2d15daaf9rileya@google.com    const char* fFSVaryingName;
431d7cc651b8da11d52ae90e910b948f5e2d15daaf9rileya@google.com
432d7cc651b8da11d52ae90e910b948f5e2d15daaf9rileya@google.com    bool fIsDegenerate;
433d7cc651b8da11d52ae90e910b948f5e2d15daaf9rileya@google.com
434d7cc651b8da11d52ae90e910b948f5e2d15daaf9rileya@google.com    // @{
435d7cc651b8da11d52ae90e910b948f5e2d15daaf9rileya@google.com    /// Values last uploaded as uniforms
436d7cc651b8da11d52ae90e910b948f5e2d15daaf9rileya@google.com
43781712883419f76e25d2ffec38a9438284a45a48dbsalomon@google.com    SkScalar fCachedCenter;
43881712883419f76e25d2ffec38a9438284a45a48dbsalomon@google.com    SkScalar fCachedRadius;
439d7cc651b8da11d52ae90e910b948f5e2d15daaf9rileya@google.com    bool     fCachedPosRoot;
440d7cc651b8da11d52ae90e910b948f5e2d15daaf9rileya@google.com
441d7cc651b8da11d52ae90e910b948f5e2d15daaf9rileya@google.com    // @}
442d7cc651b8da11d52ae90e910b948f5e2d15daaf9rileya@google.com
443d7cc651b8da11d52ae90e910b948f5e2d15daaf9rileya@google.comprivate:
444d7cc651b8da11d52ae90e910b948f5e2d15daaf9rileya@google.com
4450707c29413a5a3cc1c2d14b8c65b3692af5c7411bsalomon@google.com    typedef GrGLGradientEffect INHERITED;
446d7cc651b8da11d52ae90e910b948f5e2d15daaf9rileya@google.com
447d7cc651b8da11d52ae90e910b948f5e2d15daaf9rileya@google.com};
448d7cc651b8da11d52ae90e910b948f5e2d15daaf9rileya@google.com
44998e8b6de04e4c20451fbe3353645e3e384a76550rileya@google.com/////////////////////////////////////////////////////////////////////
45098e8b6de04e4c20451fbe3353645e3e384a76550rileya@google.com
45198e8b6de04e4c20451fbe3353645e3e384a76550rileya@google.comclass GrRadial2Gradient : public GrGradientEffect {
45298e8b6de04e4c20451fbe3353645e3e384a76550rileya@google.compublic:
453b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt    static GrFragmentProcessor* Create(GrContext* ctx,
454b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt                                       const SkTwoPointRadialGradient& shader,
455b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt                                       const SkMatrix& matrix,
456b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt                                       SkShader::TileMode tm) {
45755fad7af61c21d502acb9891d631e8aa29e3628cbsalomon        return SkNEW_ARGS(GrRadial2Gradient, (ctx, shader, matrix, tm));
4580ac6af49975c54c2debf41e9200af416ecd2d973bsalomon@google.com    }
45998e8b6de04e4c20451fbe3353645e3e384a76550rileya@google.com
46098e8b6de04e4c20451fbe3353645e3e384a76550rileya@google.com    virtual ~GrRadial2Gradient() { }
46198e8b6de04e4c20451fbe3353645e3e384a76550rileya@google.com
46298e8b6de04e4c20451fbe3353645e3e384a76550rileya@google.com    static const char* Name() { return "Two-Point Radial Gradient"; }
463b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt    virtual const GrBackendFragmentProcessorFactory& getFactory() const SK_OVERRIDE {
464b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt        return GrTBackendFragmentProcessorFactory<GrRadial2Gradient>::getInstance();
46598e8b6de04e4c20451fbe3353645e3e384a76550rileya@google.com    }
46698e8b6de04e4c20451fbe3353645e3e384a76550rileya@google.com
46798e8b6de04e4c20451fbe3353645e3e384a76550rileya@google.com    // The radial gradient parameters can collapse to a linear (instead of quadratic) equation.
46881712883419f76e25d2ffec38a9438284a45a48dbsalomon@google.com    bool isDegenerate() const { return SK_Scalar1 == fCenterX1; }
46981712883419f76e25d2ffec38a9438284a45a48dbsalomon@google.com    SkScalar center() const { return fCenterX1; }
47081712883419f76e25d2ffec38a9438284a45a48dbsalomon@google.com    SkScalar radius() const { return fRadius0; }
47198e8b6de04e4c20451fbe3353645e3e384a76550rileya@google.com    bool isPosRoot() const { return SkToBool(fPosRoot); }
47298e8b6de04e4c20451fbe3353645e3e384a76550rileya@google.com
473b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt    typedef GrGLRadial2Gradient GLProcessor;
47498e8b6de04e4c20451fbe3353645e3e384a76550rileya@google.com
47598e8b6de04e4c20451fbe3353645e3e384a76550rileya@google.comprivate:
476b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt    virtual bool onIsEqual(const GrProcessor& sBase) const SK_OVERRIDE {
47749586bec7383d4ccb81f85f8e2dc4162e2d4f6a8joshualitt        const GrRadial2Gradient& s = sBase.cast<GrRadial2Gradient>();
47870db51fc09464fe8014516561c47aa6fb1a1ed2absalomon@google.com        return (INHERITED::onIsEqual(sBase) &&
47968b58c95384dd6c2fd389a5b4bbf8fc468819454bsalomon@google.com                this->fCenterX1 == s.fCenterX1 &&
48068b58c95384dd6c2fd389a5b4bbf8fc468819454bsalomon@google.com                this->fRadius0 == s.fRadius0 &&
48168b58c95384dd6c2fd389a5b4bbf8fc468819454bsalomon@google.com                this->fPosRoot == s.fPosRoot);
48268b58c95384dd6c2fd389a5b4bbf8fc468819454bsalomon@google.com    }
48368b58c95384dd6c2fd389a5b4bbf8fc468819454bsalomon@google.com
4840ac6af49975c54c2debf41e9200af416ecd2d973bsalomon@google.com    GrRadial2Gradient(GrContext* ctx,
4850ac6af49975c54c2debf41e9200af416ecd2d973bsalomon@google.com                      const SkTwoPointRadialGradient& shader,
4860ac6af49975c54c2debf41e9200af416ecd2d973bsalomon@google.com                      const SkMatrix& matrix,
4870ac6af49975c54c2debf41e9200af416ecd2d973bsalomon@google.com                      SkShader::TileMode tm)
4880ac6af49975c54c2debf41e9200af416ecd2d973bsalomon@google.com        : INHERITED(ctx, shader, matrix, tm)
4890ac6af49975c54c2debf41e9200af416ecd2d973bsalomon@google.com        , fCenterX1(shader.getCenterX1())
4900ac6af49975c54c2debf41e9200af416ecd2d973bsalomon@google.com        , fRadius0(shader.getStartRadius())
4915fd7d5c20a15094da3fb6dc1d59955fd8f3217d7commit-bot@chromium.org        , fPosRoot(shader.getDiffRadius() < 0) {
4925fd7d5c20a15094da3fb6dc1d59955fd8f3217d7commit-bot@chromium.org        // We pass the linear part of the quadratic as a varying.
4935fd7d5c20a15094da3fb6dc1d59955fd8f3217d7commit-bot@chromium.org        //    float b = 2.0 * (fCenterX1 * x - fRadius0 * z)
4945fd7d5c20a15094da3fb6dc1d59955fd8f3217d7commit-bot@chromium.org        fBTransform = this->getCoordTransform();
4955fd7d5c20a15094da3fb6dc1d59955fd8f3217d7commit-bot@chromium.org        SkMatrix& bMatrix = *fBTransform.accessMatrix();
4965fd7d5c20a15094da3fb6dc1d59955fd8f3217d7commit-bot@chromium.org        bMatrix[SkMatrix::kMScaleX] = 2 * (SkScalarMul(fCenterX1, bMatrix[SkMatrix::kMScaleX]) -
4975fd7d5c20a15094da3fb6dc1d59955fd8f3217d7commit-bot@chromium.org                                           SkScalarMul(fRadius0, bMatrix[SkMatrix::kMPersp0]));
4985fd7d5c20a15094da3fb6dc1d59955fd8f3217d7commit-bot@chromium.org        bMatrix[SkMatrix::kMSkewX] = 2 * (SkScalarMul(fCenterX1, bMatrix[SkMatrix::kMSkewX]) -
4995fd7d5c20a15094da3fb6dc1d59955fd8f3217d7commit-bot@chromium.org                                          SkScalarMul(fRadius0, bMatrix[SkMatrix::kMPersp1]));
5005fd7d5c20a15094da3fb6dc1d59955fd8f3217d7commit-bot@chromium.org        bMatrix[SkMatrix::kMTransX] = 2 * (SkScalarMul(fCenterX1, bMatrix[SkMatrix::kMTransX]) -
5015fd7d5c20a15094da3fb6dc1d59955fd8f3217d7commit-bot@chromium.org                                           SkScalarMul(fRadius0, bMatrix[SkMatrix::kMPersp2]));
5025fd7d5c20a15094da3fb6dc1d59955fd8f3217d7commit-bot@chromium.org        this->addCoordTransform(&fBTransform);
5035fd7d5c20a15094da3fb6dc1d59955fd8f3217d7commit-bot@chromium.org    }
5040ac6af49975c54c2debf41e9200af416ecd2d973bsalomon@google.com
505b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt    GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
50698e8b6de04e4c20451fbe3353645e3e384a76550rileya@google.com
50798e8b6de04e4c20451fbe3353645e3e384a76550rileya@google.com    // @{
50898e8b6de04e4c20451fbe3353645e3e384a76550rileya@google.com    // Cache of values - these can change arbitrarily, EXCEPT
50998e8b6de04e4c20451fbe3353645e3e384a76550rileya@google.com    // we shouldn't change between degenerate and non-degenerate?!
51098e8b6de04e4c20451fbe3353645e3e384a76550rileya@google.com
5115fd7d5c20a15094da3fb6dc1d59955fd8f3217d7commit-bot@chromium.org    GrCoordTransform fBTransform;
5125fd7d5c20a15094da3fb6dc1d59955fd8f3217d7commit-bot@chromium.org    SkScalar         fCenterX1;
5135fd7d5c20a15094da3fb6dc1d59955fd8f3217d7commit-bot@chromium.org    SkScalar         fRadius0;
5145fd7d5c20a15094da3fb6dc1d59955fd8f3217d7commit-bot@chromium.org    SkBool8          fPosRoot;
51598e8b6de04e4c20451fbe3353645e3e384a76550rileya@google.com
51698e8b6de04e4c20451fbe3353645e3e384a76550rileya@google.com    // @}
51798e8b6de04e4c20451fbe3353645e3e384a76550rileya@google.com
51898e8b6de04e4c20451fbe3353645e3e384a76550rileya@google.com    typedef GrGradientEffect INHERITED;
51998e8b6de04e4c20451fbe3353645e3e384a76550rileya@google.com};
52098e8b6de04e4c20451fbe3353645e3e384a76550rileya@google.com
52198e8b6de04e4c20451fbe3353645e3e384a76550rileya@google.com/////////////////////////////////////////////////////////////////////
52298e8b6de04e4c20451fbe3353645e3e384a76550rileya@google.com
523b0a8a377f832c59cee939ad721e1f87d378b7142joshualittGR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrRadial2Gradient);
524d472620458e2383e6dd949f4e1aaf61160717ffebsalomon@google.com
525b0a8a377f832c59cee939ad721e1f87d378b7142joshualittGrFragmentProcessor* GrRadial2Gradient::TestCreate(SkRandom* random,
526b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt                                                   GrContext* context,
527b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt                                                   const GrDrawTargetCaps&,
528b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt                                                   GrTexture**) {
529d472620458e2383e6dd949f4e1aaf61160717ffebsalomon@google.com    SkPoint center1 = {random->nextUScalar1(), random->nextUScalar1()};
530d472620458e2383e6dd949f4e1aaf61160717ffebsalomon@google.com    SkScalar radius1 = random->nextUScalar1();
531d472620458e2383e6dd949f4e1aaf61160717ffebsalomon@google.com    SkPoint center2;
532d472620458e2383e6dd949f4e1aaf61160717ffebsalomon@google.com    SkScalar radius2;
533d472620458e2383e6dd949f4e1aaf61160717ffebsalomon@google.com    do {
534fb883bf80422c4763921b3d6e2a9ac81596e77bfbsalomon@google.com        center2.set(random->nextUScalar1(), random->nextUScalar1());
535d472620458e2383e6dd949f4e1aaf61160717ffebsalomon@google.com        radius2 = random->nextUScalar1 ();
536e197cbf9a3e66bab926bc5e51962752dad5221a0bsalomon@google.com        // There is a bug in two point radial gradients with identical radii
537d472620458e2383e6dd949f4e1aaf61160717ffebsalomon@google.com    } while (radius1 == radius2);
538d472620458e2383e6dd949f4e1aaf61160717ffebsalomon@google.com
539d472620458e2383e6dd949f4e1aaf61160717ffebsalomon@google.com    SkColor colors[kMaxRandomGradientColors];
540d472620458e2383e6dd949f4e1aaf61160717ffebsalomon@google.com    SkScalar stopsArray[kMaxRandomGradientColors];
541d472620458e2383e6dd949f4e1aaf61160717ffebsalomon@google.com    SkScalar* stops = stopsArray;
542d472620458e2383e6dd949f4e1aaf61160717ffebsalomon@google.com    SkShader::TileMode tm;
543d472620458e2383e6dd949f4e1aaf61160717ffebsalomon@google.com    int colorCount = RandomGradientParams(random, colors, &stops, &tm);
544d472620458e2383e6dd949f4e1aaf61160717ffebsalomon@google.com    SkAutoTUnref<SkShader> shader(SkGradientShader::CreateTwoPointRadial(center1, radius1,
545d472620458e2383e6dd949f4e1aaf61160717ffebsalomon@google.com                                                                         center2, radius2,
546d472620458e2383e6dd949f4e1aaf61160717ffebsalomon@google.com                                                                         colors, stops, colorCount,
547d472620458e2383e6dd949f4e1aaf61160717ffebsalomon@google.com                                                                         tm));
548e197cbf9a3e66bab926bc5e51962752dad5221a0bsalomon@google.com    SkPaint paint;
549b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt    GrFragmentProcessor* fp;
55083d081ae1d731b5039e99823620f5e287542ee39bsalomon    GrColor paintColor;
551b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt    SkAssertResult(shader->asFragmentProcessor(context, paint, NULL, &paintColor, &fp));
552b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt    return fp;
553d472620458e2383e6dd949f4e1aaf61160717ffebsalomon@google.com}
554d472620458e2383e6dd949f4e1aaf61160717ffebsalomon@google.com
555d472620458e2383e6dd949f4e1aaf61160717ffebsalomon@google.com/////////////////////////////////////////////////////////////////////
556d472620458e2383e6dd949f4e1aaf61160717ffebsalomon@google.com
557b0a8a377f832c59cee939ad721e1f87d378b7142joshualittGrGLRadial2Gradient::GrGLRadial2Gradient(const GrBackendProcessorFactory& factory,
558b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt                                         const GrProcessor& processor)
559d7cc651b8da11d52ae90e910b948f5e2d15daaf9rileya@google.com    : INHERITED(factory)
560d7cc651b8da11d52ae90e910b948f5e2d15daaf9rileya@google.com    , fVSVaryingName(NULL)
561d7cc651b8da11d52ae90e910b948f5e2d15daaf9rileya@google.com    , fFSVaryingName(NULL)
56281712883419f76e25d2ffec38a9438284a45a48dbsalomon@google.com    , fCachedCenter(SK_ScalarMax)
56381712883419f76e25d2ffec38a9438284a45a48dbsalomon@google.com    , fCachedRadius(-SK_ScalarMax)
564d7cc651b8da11d52ae90e910b948f5e2d15daaf9rileya@google.com    , fCachedPosRoot(0) {
565d7cc651b8da11d52ae90e910b948f5e2d15daaf9rileya@google.com
566b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt    const GrRadial2Gradient& data = processor.cast<GrRadial2Gradient>();
567d7cc651b8da11d52ae90e910b948f5e2d15daaf9rileya@google.com    fIsDegenerate = data.isDegenerate();
568d7cc651b8da11d52ae90e910b948f5e2d15daaf9rileya@google.com}
569d7cc651b8da11d52ae90e910b948f5e2d15daaf9rileya@google.com
57030ba436f04e61d4505fb854d5fc56079636e0788joshualittvoid GrGLRadial2Gradient::emitCode(GrGLProgramBuilder* builder,
571b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt                                   const GrFragmentProcessor&,
572b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt                                   const GrProcessorKey& key,
573f78df33efc72167f94da1b0476c9a86ba18a5f2cbsalomon@google.com                                   const char* outputColor,
574f78df33efc72167f94da1b0476c9a86ba18a5f2cbsalomon@google.com                                   const char* inputColor,
57577af6805e5faea1e2a5c0220098aec9082f3a6e5bsalomon@google.com                                   const TransformedCoordsArray& coords,
576f78df33efc72167f94da1b0476c9a86ba18a5f2cbsalomon@google.com                                   const TextureSamplerArray& samplers) {
57763e99f7a03b2ac90ae7a00232674fd39c0bdcc68bsalomon    uint32_t baseKey = key.get32(0);
57863e99f7a03b2ac90ae7a00232674fd39c0bdcc68bsalomon    this->emitUniforms(builder, baseKey);
57930ba436f04e61d4505fb854d5fc56079636e0788joshualitt    fParamUni = builder->addUniformArray(GrGLProgramBuilder::kFragment_Visibility,
5805fd7d5c20a15094da3fb6dc1d59955fd8f3217d7commit-bot@chromium.org                                         kFloat_GrSLType, "Radial2FSParams", 6);
5815fd7d5c20a15094da3fb6dc1d59955fd8f3217d7commit-bot@chromium.org
5825fd7d5c20a15094da3fb6dc1d59955fd8f3217d7commit-bot@chromium.org    SkString cName("c");
5835fd7d5c20a15094da3fb6dc1d59955fd8f3217d7commit-bot@chromium.org    SkString ac4Name("ac4");
5845fd7d5c20a15094da3fb6dc1d59955fd8f3217d7commit-bot@chromium.org    SkString rootName("root");
5855fd7d5c20a15094da3fb6dc1d59955fd8f3217d7commit-bot@chromium.org    SkString t;
5865fd7d5c20a15094da3fb6dc1d59955fd8f3217d7commit-bot@chromium.org    SkString p0;
5875fd7d5c20a15094da3fb6dc1d59955fd8f3217d7commit-bot@chromium.org    SkString p1;
5885fd7d5c20a15094da3fb6dc1d59955fd8f3217d7commit-bot@chromium.org    SkString p2;
5895fd7d5c20a15094da3fb6dc1d59955fd8f3217d7commit-bot@chromium.org    SkString p3;
5905fd7d5c20a15094da3fb6dc1d59955fd8f3217d7commit-bot@chromium.org    SkString p4;
5915fd7d5c20a15094da3fb6dc1d59955fd8f3217d7commit-bot@chromium.org    SkString p5;
5925fd7d5c20a15094da3fb6dc1d59955fd8f3217d7commit-bot@chromium.org    builder->getUniformVariable(fParamUni).appendArrayAccess(0, &p0);
5935fd7d5c20a15094da3fb6dc1d59955fd8f3217d7commit-bot@chromium.org    builder->getUniformVariable(fParamUni).appendArrayAccess(1, &p1);
5945fd7d5c20a15094da3fb6dc1d59955fd8f3217d7commit-bot@chromium.org    builder->getUniformVariable(fParamUni).appendArrayAccess(2, &p2);
5955fd7d5c20a15094da3fb6dc1d59955fd8f3217d7commit-bot@chromium.org    builder->getUniformVariable(fParamUni).appendArrayAccess(3, &p3);
5965fd7d5c20a15094da3fb6dc1d59955fd8f3217d7commit-bot@chromium.org    builder->getUniformVariable(fParamUni).appendArrayAccess(4, &p4);
5975fd7d5c20a15094da3fb6dc1d59955fd8f3217d7commit-bot@chromium.org    builder->getUniformVariable(fParamUni).appendArrayAccess(5, &p5);
5985fd7d5c20a15094da3fb6dc1d59955fd8f3217d7commit-bot@chromium.org
59930ba436f04e61d4505fb854d5fc56079636e0788joshualitt    GrGLFragmentShaderBuilder* fsBuilder = builder->getFragmentShaderBuilder();
6005fd7d5c20a15094da3fb6dc1d59955fd8f3217d7commit-bot@chromium.org    // We interpolate the linear component in coords[1].
60123e280d1f227d94f6b3dfd0b47359cca1569e1b4joshualitt    SkASSERT(coords[0].getType() == coords[1].getType());
6025fd7d5c20a15094da3fb6dc1d59955fd8f3217d7commit-bot@chromium.org    const char* coords2D;
6035fd7d5c20a15094da3fb6dc1d59955fd8f3217d7commit-bot@chromium.org    SkString bVar;
60423e280d1f227d94f6b3dfd0b47359cca1569e1b4joshualitt    if (kVec3f_GrSLType == coords[0].getType()) {
60530ba436f04e61d4505fb854d5fc56079636e0788joshualitt        fsBuilder->codeAppendf("\tvec3 interpolants = vec3(%s.xy, %s.x) / %s.z;\n",
6065fd7d5c20a15094da3fb6dc1d59955fd8f3217d7commit-bot@chromium.org                               coords[0].c_str(), coords[1].c_str(), coords[0].c_str());
6075fd7d5c20a15094da3fb6dc1d59955fd8f3217d7commit-bot@chromium.org        coords2D = "interpolants.xy";
6085fd7d5c20a15094da3fb6dc1d59955fd8f3217d7commit-bot@chromium.org        bVar = "interpolants.z";
6095fd7d5c20a15094da3fb6dc1d59955fd8f3217d7commit-bot@chromium.org    } else {
6105fd7d5c20a15094da3fb6dc1d59955fd8f3217d7commit-bot@chromium.org        coords2D = coords[0].c_str();
6115fd7d5c20a15094da3fb6dc1d59955fd8f3217d7commit-bot@chromium.org        bVar.printf("%s.x", coords[1].c_str());
612d7cc651b8da11d52ae90e910b948f5e2d15daaf9rileya@google.com    }
613d7cc651b8da11d52ae90e910b948f5e2d15daaf9rileya@google.com
6145fd7d5c20a15094da3fb6dc1d59955fd8f3217d7commit-bot@chromium.org    // c = (x^2)+(y^2) - params[4]
61530ba436f04e61d4505fb854d5fc56079636e0788joshualitt    fsBuilder->codeAppendf("\tfloat %s = dot(%s, %s) - %s;\n",
6165fd7d5c20a15094da3fb6dc1d59955fd8f3217d7commit-bot@chromium.org                           cName.c_str(), coords2D, coords2D, p4.c_str());
617d7cc651b8da11d52ae90e910b948f5e2d15daaf9rileya@google.com
6185fd7d5c20a15094da3fb6dc1d59955fd8f3217d7commit-bot@chromium.org    // If we aren't degenerate, emit some extra code, and accept a slightly
6195fd7d5c20a15094da3fb6dc1d59955fd8f3217d7commit-bot@chromium.org    // more complex coord.
6205fd7d5c20a15094da3fb6dc1d59955fd8f3217d7commit-bot@chromium.org    if (!fIsDegenerate) {
621d7cc651b8da11d52ae90e910b948f5e2d15daaf9rileya@google.com
6225fd7d5c20a15094da3fb6dc1d59955fd8f3217d7commit-bot@chromium.org        // ac4 = 4.0 * params[0] * c
62330ba436f04e61d4505fb854d5fc56079636e0788joshualitt        fsBuilder->codeAppendf("\tfloat %s = %s * 4.0 * %s;\n",
6245fd7d5c20a15094da3fb6dc1d59955fd8f3217d7commit-bot@chromium.org                               ac4Name.c_str(), p0.c_str(),
6255fd7d5c20a15094da3fb6dc1d59955fd8f3217d7commit-bot@chromium.org                               cName.c_str());
6265fd7d5c20a15094da3fb6dc1d59955fd8f3217d7commit-bot@chromium.org
6275fd7d5c20a15094da3fb6dc1d59955fd8f3217d7commit-bot@chromium.org        // root = sqrt(b^2-4ac)
6285fd7d5c20a15094da3fb6dc1d59955fd8f3217d7commit-bot@chromium.org        // (abs to avoid exception due to fp precision)
62930ba436f04e61d4505fb854d5fc56079636e0788joshualitt        fsBuilder->codeAppendf("\tfloat %s = sqrt(abs(%s*%s - %s));\n",
6305fd7d5c20a15094da3fb6dc1d59955fd8f3217d7commit-bot@chromium.org                               rootName.c_str(), bVar.c_str(), bVar.c_str(),
6315fd7d5c20a15094da3fb6dc1d59955fd8f3217d7commit-bot@chromium.org                               ac4Name.c_str());
632d7cc651b8da11d52ae90e910b948f5e2d15daaf9rileya@google.com
6335fd7d5c20a15094da3fb6dc1d59955fd8f3217d7commit-bot@chromium.org        // t is: (-b + params[5] * sqrt(b^2-4ac)) * params[1]
6345fd7d5c20a15094da3fb6dc1d59955fd8f3217d7commit-bot@chromium.org        t.printf("(-%s + %s * %s) * %s", bVar.c_str(), p5.c_str(),
6355fd7d5c20a15094da3fb6dc1d59955fd8f3217d7commit-bot@chromium.org                 rootName.c_str(), p1.c_str());
6365fd7d5c20a15094da3fb6dc1d59955fd8f3217d7commit-bot@chromium.org    } else {
6375fd7d5c20a15094da3fb6dc1d59955fd8f3217d7commit-bot@chromium.org        // t is: -c/b
6385fd7d5c20a15094da3fb6dc1d59955fd8f3217d7commit-bot@chromium.org        t.printf("-%s / %s", cName.c_str(), bVar.c_str());
639f78df33efc72167f94da1b0476c9a86ba18a5f2cbsalomon@google.com    }
6405fd7d5c20a15094da3fb6dc1d59955fd8f3217d7commit-bot@chromium.org
64163e99f7a03b2ac90ae7a00232674fd39c0bdcc68bsalomon    this->emitColor(builder, t.c_str(), baseKey, outputColor, inputColor, samplers);
642d7cc651b8da11d52ae90e910b948f5e2d15daaf9rileya@google.com}
643d7cc651b8da11d52ae90e910b948f5e2d15daaf9rileya@google.com
6447510b224e52b9518a8ddf7418db0e9c258f79539kkinnunenvoid GrGLRadial2Gradient::setData(const GrGLProgramDataManager& pdman,
645b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt                                  const GrProcessor& processor) {
646b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt    INHERITED::setData(pdman, processor);
647b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt    const GrRadial2Gradient& data = processor.cast<GrRadial2Gradient>();
64896ae688f03f05a53c2ae6e66a431e180b90be9cdcommit-bot@chromium.org    SkASSERT(data.isDegenerate() == fIsDegenerate);
64981712883419f76e25d2ffec38a9438284a45a48dbsalomon@google.com    SkScalar centerX1 = data.center();
65081712883419f76e25d2ffec38a9438284a45a48dbsalomon@google.com    SkScalar radius0 = data.radius();
651d7cc651b8da11d52ae90e910b948f5e2d15daaf9rileya@google.com    if (fCachedCenter != centerX1 ||
652d7cc651b8da11d52ae90e910b948f5e2d15daaf9rileya@google.com        fCachedRadius != radius0 ||
653d7cc651b8da11d52ae90e910b948f5e2d15daaf9rileya@google.com        fCachedPosRoot != data.isPosRoot()) {
654d7cc651b8da11d52ae90e910b948f5e2d15daaf9rileya@google.com
65581712883419f76e25d2ffec38a9438284a45a48dbsalomon@google.com        SkScalar a = SkScalarMul(centerX1, centerX1) - SK_Scalar1;
656d7cc651b8da11d52ae90e910b948f5e2d15daaf9rileya@google.com
657d7cc651b8da11d52ae90e910b948f5e2d15daaf9rileya@google.com        // When we're in the degenerate (linear) case, the second
658d7cc651b8da11d52ae90e910b948f5e2d15daaf9rileya@google.com        // value will be INF but the program doesn't read it. (We
659d7cc651b8da11d52ae90e910b948f5e2d15daaf9rileya@google.com        // use the same 6 uniforms even though we don't need them
660d7cc651b8da11d52ae90e910b948f5e2d15daaf9rileya@google.com        // all in the linear case just to keep the code complexity
661d7cc651b8da11d52ae90e910b948f5e2d15daaf9rileya@google.com        // down).
662d7cc651b8da11d52ae90e910b948f5e2d15daaf9rileya@google.com        float values[6] = {
66381712883419f76e25d2ffec38a9438284a45a48dbsalomon@google.com            SkScalarToFloat(a),
66481712883419f76e25d2ffec38a9438284a45a48dbsalomon@google.com            1 / (2.f * SkScalarToFloat(a)),
66581712883419f76e25d2ffec38a9438284a45a48dbsalomon@google.com            SkScalarToFloat(centerX1),
66681712883419f76e25d2ffec38a9438284a45a48dbsalomon@google.com            SkScalarToFloat(radius0),
66781712883419f76e25d2ffec38a9438284a45a48dbsalomon@google.com            SkScalarToFloat(SkScalarMul(radius0, radius0)),
668d7cc651b8da11d52ae90e910b948f5e2d15daaf9rileya@google.com            data.isPosRoot() ? 1.f : -1.f
669d7cc651b8da11d52ae90e910b948f5e2d15daaf9rileya@google.com        };
670d7cc651b8da11d52ae90e910b948f5e2d15daaf9rileya@google.com
6717510b224e52b9518a8ddf7418db0e9c258f79539kkinnunen        pdman.set1fv(fParamUni, 6, values);
672d7cc651b8da11d52ae90e910b948f5e2d15daaf9rileya@google.com        fCachedCenter = centerX1;
673d7cc651b8da11d52ae90e910b948f5e2d15daaf9rileya@google.com        fCachedRadius = radius0;
674d7cc651b8da11d52ae90e910b948f5e2d15daaf9rileya@google.com        fCachedPosRoot = data.isPosRoot();
675d7cc651b8da11d52ae90e910b948f5e2d15daaf9rileya@google.com    }
676d7cc651b8da11d52ae90e910b948f5e2d15daaf9rileya@google.com}
677d7cc651b8da11d52ae90e910b948f5e2d15daaf9rileya@google.com
678b0a8a377f832c59cee939ad721e1f87d378b7142joshualittvoid GrGLRadial2Gradient::GenKey(const GrProcessor& processor,
679b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt                                 const GrGLCaps&, GrProcessorKeyBuilder* b) {
68063e99f7a03b2ac90ae7a00232674fd39c0bdcc68bsalomon    uint32_t* key = b->add32n(2);
681b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt    key[0] = GenBaseGradientKey(processor);
682b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt    key[1] = processor.cast<GrRadial2Gradient>().isDegenerate();
683d7cc651b8da11d52ae90e910b948f5e2d15daaf9rileya@google.com}
684d7cc651b8da11d52ae90e910b948f5e2d15daaf9rileya@google.com
68598e8b6de04e4c20451fbe3353645e3e384a76550rileya@google.com/////////////////////////////////////////////////////////////////////
6861c6d64b78b24083ee9fd7411dac8a4a7e2d03a3crileya@google.com
687b0a8a377f832c59cee939ad721e1f87d378b7142joshualittbool SkTwoPointRadialGradient::asFragmentProcessor(GrContext* context, const SkPaint& paint,
688b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt                                                   const SkMatrix* localMatrix, GrColor* paintColor,
689b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt                                                   GrFragmentProcessor** fp)  const {
69049f085dddff10473b6ebf832a974288300224e60bsalomon    SkASSERT(context);
6919de5b514d38c5b36066bcdc14fba2f7e5196d372dandov
692f94b3a4cebd4adab09c40ebe23c02a615e10c394bsalomon@google.com    // invert the localM, translate to center1 (fPtsToUni), rotate so center2 is on x axis.
693dfdb7e5240276493077b7c6e1f3cc8b8a0e195babsalomon@google.com    SkMatrix matrix;
694f94b3a4cebd4adab09c40ebe23c02a615e10c394bsalomon@google.com    if (!this->getLocalMatrix().invert(&matrix)) {
6959de5b514d38c5b36066bcdc14fba2f7e5196d372dandov        return false;
69698e8b6de04e4c20451fbe3353645e3e384a76550rileya@google.com    }
69796fb7489ba46909c3f81bb2d94755e7d4ccb5fadcommit-bot@chromium.org    if (localMatrix) {
69896fb7489ba46909c3f81bb2d94755e7d4ccb5fadcommit-bot@chromium.org        SkMatrix inv;
69996fb7489ba46909c3f81bb2d94755e7d4ccb5fadcommit-bot@chromium.org        if (!localMatrix->invert(&inv)) {
7009de5b514d38c5b36066bcdc14fba2f7e5196d372dandov            return false;
70196fb7489ba46909c3f81bb2d94755e7d4ccb5fadcommit-bot@chromium.org        }
70296fb7489ba46909c3f81bb2d94755e7d4ccb5fadcommit-bot@chromium.org        matrix.postConcat(inv);
70396fb7489ba46909c3f81bb2d94755e7d4ccb5fadcommit-bot@chromium.org    }
704f94b3a4cebd4adab09c40ebe23c02a615e10c394bsalomon@google.com    matrix.postConcat(fPtsToUnit);
70520c301bd1aa4578c6d0abb23ac2c72b5fbb436dbskia.committer@gmail.com
706f94b3a4cebd4adab09c40ebe23c02a615e10c394bsalomon@google.com    SkScalar diffLen = fDiff.length();
707f94b3a4cebd4adab09c40ebe23c02a615e10c394bsalomon@google.com    if (0 != diffLen) {
708f94b3a4cebd4adab09c40ebe23c02a615e10c394bsalomon@google.com        SkScalar invDiffLen = SkScalarInvert(diffLen);
709f94b3a4cebd4adab09c40ebe23c02a615e10c394bsalomon@google.com        SkMatrix rot;
710f94b3a4cebd4adab09c40ebe23c02a615e10c394bsalomon@google.com        rot.setSinCos(-SkScalarMul(invDiffLen, fDiff.fY),
711f94b3a4cebd4adab09c40ebe23c02a615e10c394bsalomon@google.com                       SkScalarMul(invDiffLen, fDiff.fX));
712f94b3a4cebd4adab09c40ebe23c02a615e10c394bsalomon@google.com        matrix.postConcat(rot);
713dfdb7e5240276493077b7c6e1f3cc8b8a0e195babsalomon@google.com    }
714dfdb7e5240276493077b7c6e1f3cc8b8a0e195babsalomon@google.com
71583d081ae1d731b5039e99823620f5e287542ee39bsalomon    *paintColor = SkColor2GrColorJustAlpha(paint.getColor());
716b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt    *fp = GrRadial2Gradient::Create(context, *this, matrix, fTileMode);
7179de5b514d38c5b36066bcdc14fba2f7e5196d372dandov
7189de5b514d38c5b36066bcdc14fba2f7e5196d372dandov    return true;
719d7cc651b8da11d52ae90e910b948f5e2d15daaf9rileya@google.com}
720d7cc651b8da11d52ae90e910b948f5e2d15daaf9rileya@google.com
721cf8fb1f6f03fc77f9927564f9ef9abeeeec508d2bsalomon@google.com#else
722cf8fb1f6f03fc77f9927564f9ef9abeeeec508d2bsalomon@google.com
723b0a8a377f832c59cee939ad721e1f87d378b7142joshualittbool SkTwoPointRadialGradient::asFragmentProcessor(GrContext*, const SkPaint&, const SkMatrix*,
724b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt                                                   GrColor*, GrFragmentProcessor**)  const {
725cf8fb1f6f03fc77f9927564f9ef9abeeeec508d2bsalomon@google.com    SkDEBUGFAIL("Should not call in GPU-less build");
7269de5b514d38c5b36066bcdc14fba2f7e5196d372dandov    return false;
727cf8fb1f6f03fc77f9927564f9ef9abeeeec508d2bsalomon@google.com}
728cf8fb1f6f03fc77f9927564f9ef9abeeeec508d2bsalomon@google.com
729cf8fb1f6f03fc77f9927564f9ef9abeeeec508d2bsalomon@google.com#endif
730