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
9589708bf7c706348b763e8277004cb160b202bdbrileya@google.com#include "SkRadialGradient.h"
10589708bf7c706348b763e8277004cb160b202bdbrileya@google.com#include "SkRadialGradient_Table.h"
11589708bf7c706348b763e8277004cb160b202bdbrileya@google.com
12589708bf7c706348b763e8277004cb160b202bdbrileya@google.com#define kSQRT_TABLE_BITS    11
13589708bf7c706348b763e8277004cb160b202bdbrileya@google.com#define kSQRT_TABLE_SIZE    (1 << kSQRT_TABLE_BITS)
14589708bf7c706348b763e8277004cb160b202bdbrileya@google.com
154ec5c95bc514e15f726ee5c3b83e1578e3d00d13reed@google.com#if 0
16589708bf7c706348b763e8277004cb160b202bdbrileya@google.com
17589708bf7c706348b763e8277004cb160b202bdbrileya@google.com#include <stdio.h>
18589708bf7c706348b763e8277004cb160b202bdbrileya@google.com
19589708bf7c706348b763e8277004cb160b202bdbrileya@google.comvoid SkRadialGradient_BuildTable() {
20589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    // build it 0..127 x 0..127, so we use 2^15 - 1 in the numerator for our "fixed" table
21589708bf7c706348b763e8277004cb160b202bdbrileya@google.com
22589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    FILE* file = ::fopen("SkRadialGradient_Table.h", "w");
23589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    SkASSERT(file);
24589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    ::fprintf(file, "static const uint8_t gSqrt8Table[] = {\n");
25589708bf7c706348b763e8277004cb160b202bdbrileya@google.com
26589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    for (int i = 0; i < kSQRT_TABLE_SIZE; i++) {
27589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        if ((i & 15) == 0) {
28589708bf7c706348b763e8277004cb160b202bdbrileya@google.com            ::fprintf(file, "\t");
29589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        }
30589708bf7c706348b763e8277004cb160b202bdbrileya@google.com
31589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        uint8_t value = SkToU8(SkFixedSqrt(i * SK_Fixed1 / kSQRT_TABLE_SIZE) >> 8);
32589708bf7c706348b763e8277004cb160b202bdbrileya@google.com
33589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        ::fprintf(file, "0x%02X", value);
34589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        if (i < kSQRT_TABLE_SIZE-1) {
35589708bf7c706348b763e8277004cb160b202bdbrileya@google.com            ::fprintf(file, ", ");
36589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        }
37589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        if ((i & 15) == 15) {
38589708bf7c706348b763e8277004cb160b202bdbrileya@google.com            ::fprintf(file, "\n");
39589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        }
40589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    }
41589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    ::fprintf(file, "};\n");
42589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    ::fclose(file);
43589708bf7c706348b763e8277004cb160b202bdbrileya@google.com}
44589708bf7c706348b763e8277004cb160b202bdbrileya@google.com
45589708bf7c706348b763e8277004cb160b202bdbrileya@google.com#endif
46589708bf7c706348b763e8277004cb160b202bdbrileya@google.com
47589708bf7c706348b763e8277004cb160b202bdbrileya@google.comnamespace {
48589708bf7c706348b763e8277004cb160b202bdbrileya@google.com
4934150b451da7d3c70a2d34e67b0285cb36932d45commit-bot@chromium.org// GCC doesn't like using static functions as template arguments.  So force these to be non-static.
5034150b451da7d3c70a2d34e67b0285cb36932d45commit-bot@chromium.orginline SkFixed mirror_tileproc_nonstatic(SkFixed x) {
5134150b451da7d3c70a2d34e67b0285cb36932d45commit-bot@chromium.org    return mirror_tileproc(x);
5234150b451da7d3c70a2d34e67b0285cb36932d45commit-bot@chromium.org}
5334150b451da7d3c70a2d34e67b0285cb36932d45commit-bot@chromium.org
5434150b451da7d3c70a2d34e67b0285cb36932d45commit-bot@chromium.orginline SkFixed repeat_tileproc_nonstatic(SkFixed x) {
5534150b451da7d3c70a2d34e67b0285cb36932d45commit-bot@chromium.org    return repeat_tileproc(x);
5634150b451da7d3c70a2d34e67b0285cb36932d45commit-bot@chromium.org}
5734150b451da7d3c70a2d34e67b0285cb36932d45commit-bot@chromium.org
58589708bf7c706348b763e8277004cb160b202bdbrileya@google.comvoid rad_to_unit_matrix(const SkPoint& center, SkScalar radius,
59589708bf7c706348b763e8277004cb160b202bdbrileya@google.com                               SkMatrix* matrix) {
60589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    SkScalar    inv = SkScalarInvert(radius);
61589708bf7c706348b763e8277004cb160b202bdbrileya@google.com
62589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    matrix->setTranslate(-center.fX, -center.fY);
63589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    matrix->postScale(inv, inv);
64589708bf7c706348b763e8277004cb160b202bdbrileya@google.com}
65589708bf7c706348b763e8277004cb160b202bdbrileya@google.com
66589708bf7c706348b763e8277004cb160b202bdbrileya@google.comtypedef void (* RadialShade16Proc)(SkScalar sfx, SkScalar sdx,
67589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        SkScalar sfy, SkScalar sdy,
68589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        uint16_t* dstC, const uint16_t* cache,
69589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        int toggle, int count);
70589708bf7c706348b763e8277004cb160b202bdbrileya@google.com
71589708bf7c706348b763e8277004cb160b202bdbrileya@google.comvoid shadeSpan16_radial_clamp(SkScalar sfx, SkScalar sdx,
72589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        SkScalar sfy, SkScalar sdy,
73589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        uint16_t* SK_RESTRICT dstC, const uint16_t* SK_RESTRICT cache,
74589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        int toggle, int count) {
75589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    const uint8_t* SK_RESTRICT sqrt_table = gSqrt8Table;
76589708bf7c706348b763e8277004cb160b202bdbrileya@google.com
77589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    /* knock these down so we can pin against +- 0x7FFF, which is an
78589708bf7c706348b763e8277004cb160b202bdbrileya@google.com       immediate load, rather than 0xFFFF which is slower. This is a
79589708bf7c706348b763e8277004cb160b202bdbrileya@google.com       compromise, since it reduces our precision, but that appears
80589708bf7c706348b763e8277004cb160b202bdbrileya@google.com       to be visually OK. If we decide this is OK for all of our cases,
81589708bf7c706348b763e8277004cb160b202bdbrileya@google.com       we could (it seems) put this scale-down into fDstToIndex,
82589708bf7c706348b763e8277004cb160b202bdbrileya@google.com       to avoid having to do these extra shifts each time.
83589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    */
84589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    SkFixed fx = SkScalarToFixed(sfx) >> 1;
85589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    SkFixed dx = SkScalarToFixed(sdx) >> 1;
86589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    SkFixed fy = SkScalarToFixed(sfy) >> 1;
87589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    SkFixed dy = SkScalarToFixed(sdy) >> 1;
88589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    // might perform this check for the other modes,
89589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    // but the win will be a smaller % of the total
90589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    if (dy == 0) {
91589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        fy = SkPin32(fy, -0xFFFF >> 1, 0xFFFF >> 1);
92589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        fy *= fy;
93589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        do {
94589708bf7c706348b763e8277004cb160b202bdbrileya@google.com            unsigned xx = SkPin32(fx, -0xFFFF >> 1, 0xFFFF >> 1);
95589708bf7c706348b763e8277004cb160b202bdbrileya@google.com            unsigned fi = (xx * xx + fy) >> (14 + 16 - kSQRT_TABLE_BITS);
96589708bf7c706348b763e8277004cb160b202bdbrileya@google.com            fi = SkFastMin32(fi, 0xFFFF >> (16 - kSQRT_TABLE_BITS));
97589708bf7c706348b763e8277004cb160b202bdbrileya@google.com            fx += dx;
98589708bf7c706348b763e8277004cb160b202bdbrileya@google.com            *dstC++ = cache[toggle +
99589708bf7c706348b763e8277004cb160b202bdbrileya@google.com                            (sqrt_table[fi] >> SkGradientShaderBase::kSqrt16Shift)];
10055853db3cce9539746fe202519a534c85ecdf62creed@google.com            toggle = next_dither_toggle16(toggle);
101589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        } while (--count != 0);
102589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    } else {
103589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        do {
104589708bf7c706348b763e8277004cb160b202bdbrileya@google.com            unsigned xx = SkPin32(fx, -0xFFFF >> 1, 0xFFFF >> 1);
105589708bf7c706348b763e8277004cb160b202bdbrileya@google.com            unsigned fi = SkPin32(fy, -0xFFFF >> 1, 0xFFFF >> 1);
106589708bf7c706348b763e8277004cb160b202bdbrileya@google.com            fi = (xx * xx + fi * fi) >> (14 + 16 - kSQRT_TABLE_BITS);
107589708bf7c706348b763e8277004cb160b202bdbrileya@google.com            fi = SkFastMin32(fi, 0xFFFF >> (16 - kSQRT_TABLE_BITS));
108589708bf7c706348b763e8277004cb160b202bdbrileya@google.com            fx += dx;
109589708bf7c706348b763e8277004cb160b202bdbrileya@google.com            fy += dy;
110589708bf7c706348b763e8277004cb160b202bdbrileya@google.com            *dstC++ = cache[toggle +
111589708bf7c706348b763e8277004cb160b202bdbrileya@google.com                            (sqrt_table[fi] >> SkGradientShaderBase::kSqrt16Shift)];
11255853db3cce9539746fe202519a534c85ecdf62creed@google.com            toggle = next_dither_toggle16(toggle);
113589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        } while (--count != 0);
114589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    }
115589708bf7c706348b763e8277004cb160b202bdbrileya@google.com}
116589708bf7c706348b763e8277004cb160b202bdbrileya@google.com
11734150b451da7d3c70a2d34e67b0285cb36932d45commit-bot@chromium.orgtemplate <SkFixed (*TileProc)(SkFixed)>
11834150b451da7d3c70a2d34e67b0285cb36932d45commit-bot@chromium.orgvoid shadeSpan16_radial(SkScalar fx, SkScalar dx, SkScalar fy, SkScalar dy,
11934150b451da7d3c70a2d34e67b0285cb36932d45commit-bot@chromium.org                        uint16_t* SK_RESTRICT dstC, const uint16_t* SK_RESTRICT cache,
12034150b451da7d3c70a2d34e67b0285cb36932d45commit-bot@chromium.org                        int toggle, int count) {
121589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    do {
12234150b451da7d3c70a2d34e67b0285cb36932d45commit-bot@chromium.org        const SkFixed dist = SkFloatToFixed(sk_float_sqrt(fx*fx + fy*fy));
12334150b451da7d3c70a2d34e67b0285cb36932d45commit-bot@chromium.org        const unsigned fi = TileProc(dist);
124589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        SkASSERT(fi <= 0xFFFF);
125589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        *dstC++ = cache[toggle + (fi >> SkGradientShaderBase::kCache16Shift)];
12655853db3cce9539746fe202519a534c85ecdf62creed@google.com        toggle = next_dither_toggle16(toggle);
127589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        fx += dx;
128589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        fy += dy;
129589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    } while (--count != 0);
130589708bf7c706348b763e8277004cb160b202bdbrileya@google.com}
131589708bf7c706348b763e8277004cb160b202bdbrileya@google.com
13234150b451da7d3c70a2d34e67b0285cb36932d45commit-bot@chromium.orgvoid shadeSpan16_radial_mirror(SkScalar fx, SkScalar dx, SkScalar fy, SkScalar dy,
13334150b451da7d3c70a2d34e67b0285cb36932d45commit-bot@chromium.org                               uint16_t* SK_RESTRICT dstC, const uint16_t* SK_RESTRICT cache,
13434150b451da7d3c70a2d34e67b0285cb36932d45commit-bot@chromium.org                               int toggle, int count) {
13534150b451da7d3c70a2d34e67b0285cb36932d45commit-bot@chromium.org    shadeSpan16_radial<mirror_tileproc_nonstatic>(fx, dx, fy, dy, dstC, cache, toggle, count);
13634150b451da7d3c70a2d34e67b0285cb36932d45commit-bot@chromium.org}
13734150b451da7d3c70a2d34e67b0285cb36932d45commit-bot@chromium.org
13834150b451da7d3c70a2d34e67b0285cb36932d45commit-bot@chromium.orgvoid shadeSpan16_radial_repeat(SkScalar fx, SkScalar dx, SkScalar fy, SkScalar dy,
13934150b451da7d3c70a2d34e67b0285cb36932d45commit-bot@chromium.org                               uint16_t* SK_RESTRICT dstC, const uint16_t* SK_RESTRICT cache,
14034150b451da7d3c70a2d34e67b0285cb36932d45commit-bot@chromium.org                               int toggle, int count) {
14134150b451da7d3c70a2d34e67b0285cb36932d45commit-bot@chromium.org    shadeSpan16_radial<repeat_tileproc_nonstatic>(fx, dx, fy, dy, dstC, cache, toggle, count);
142589708bf7c706348b763e8277004cb160b202bdbrileya@google.com}
143589708bf7c706348b763e8277004cb160b202bdbrileya@google.com
14434150b451da7d3c70a2d34e67b0285cb36932d45commit-bot@chromium.org}  // namespace
14534150b451da7d3c70a2d34e67b0285cb36932d45commit-bot@chromium.org
14698e8b6de04e4c20451fbe3353645e3e384a76550rileya@google.com/////////////////////////////////////////////////////////////////////
14798e8b6de04e4c20451fbe3353645e3e384a76550rileya@google.com
148589708bf7c706348b763e8277004cb160b202bdbrileya@google.comSkRadialGradient::SkRadialGradient(const SkPoint& center, SkScalar radius,
1499c9005a347e9996f357bd79591bd34f74f8bbc66commit-bot@chromium.org                                   const Descriptor& desc, const SkMatrix* localMatrix)
1509c9005a347e9996f357bd79591bd34f74f8bbc66commit-bot@chromium.org    : SkGradientShaderBase(desc, localMatrix),
151589708bf7c706348b763e8277004cb160b202bdbrileya@google.com      fCenter(center),
152589708bf7c706348b763e8277004cb160b202bdbrileya@google.com      fRadius(radius)
153589708bf7c706348b763e8277004cb160b202bdbrileya@google.com{
154589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    // make sure our table is insync with our current #define for kSQRT_TABLE_SIZE
155589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    SkASSERT(sizeof(gSqrt8Table) == kSQRT_TABLE_SIZE);
156589708bf7c706348b763e8277004cb160b202bdbrileya@google.com
157589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    rad_to_unit_matrix(center, radius, &fPtsToUnit);
158589708bf7c706348b763e8277004cb160b202bdbrileya@google.com}
159589708bf7c706348b763e8277004cb160b202bdbrileya@google.com
16087fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.orgsize_t SkRadialGradient::contextSize() const {
16187fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org    return sizeof(RadialGradientContext);
16287fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org}
16387fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org
164ce56d965069c1649afe14319cb239e6ad670682acommit-bot@chromium.orgSkShader::Context* SkRadialGradient::onCreateContext(const ContextRec& rec, void* storage) const {
165e901b6de3ef8dea842008a08fc81e92fb1478d61commit-bot@chromium.org    return SkNEW_PLACEMENT_ARGS(storage, RadialGradientContext, (*this, rec));
16687fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org}
16787fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org
16887fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.orgSkRadialGradient::RadialGradientContext::RadialGradientContext(
169e901b6de3ef8dea842008a08fc81e92fb1478d61commit-bot@chromium.org        const SkRadialGradient& shader, const ContextRec& rec)
170e901b6de3ef8dea842008a08fc81e92fb1478d61commit-bot@chromium.org    : INHERITED(shader, rec) {}
17187fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org
17287fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.orgvoid SkRadialGradient::RadialGradientContext::shadeSpan16(int x, int y, uint16_t* dstCParam,
17387fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org                                                          int count) {
174589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    SkASSERT(count > 0);
175589708bf7c706348b763e8277004cb160b202bdbrileya@google.com
17687fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org    const SkRadialGradient& radialGradient = static_cast<const SkRadialGradient&>(fShader);
17787fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org
178589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    uint16_t* SK_RESTRICT dstC = dstCParam;
179589708bf7c706348b763e8277004cb160b202bdbrileya@google.com
180589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    SkPoint             srcPt;
181589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    SkMatrix::MapXYProc dstProc = fDstToIndexProc;
18287fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org    TileProc            proc = radialGradient.fTileProc;
18387fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org    const uint16_t* SK_RESTRICT cache = fCache->getCache16();
18455853db3cce9539746fe202519a534c85ecdf62creed@google.com    int                 toggle = init_dither_toggle16(x, y);
185589708bf7c706348b763e8277004cb160b202bdbrileya@google.com
186589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    if (fDstToIndexClass != kPerspective_MatrixClass) {
187589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        dstProc(fDstToIndex, SkIntToScalar(x) + SK_ScalarHalf,
188589708bf7c706348b763e8277004cb160b202bdbrileya@google.com                             SkIntToScalar(y) + SK_ScalarHalf, &srcPt);
189589708bf7c706348b763e8277004cb160b202bdbrileya@google.com
190589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        SkScalar sdx = fDstToIndex.getScaleX();
191589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        SkScalar sdy = fDstToIndex.getSkewY();
192589708bf7c706348b763e8277004cb160b202bdbrileya@google.com
193589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        if (fDstToIndexClass == kFixedStepInX_MatrixClass) {
194589708bf7c706348b763e8277004cb160b202bdbrileya@google.com            SkFixed storage[2];
195589708bf7c706348b763e8277004cb160b202bdbrileya@google.com            (void)fDstToIndex.fixedStepInX(SkIntToScalar(y),
196589708bf7c706348b763e8277004cb160b202bdbrileya@google.com                                           &storage[0], &storage[1]);
197589708bf7c706348b763e8277004cb160b202bdbrileya@google.com            sdx = SkFixedToScalar(storage[0]);
198589708bf7c706348b763e8277004cb160b202bdbrileya@google.com            sdy = SkFixedToScalar(storage[1]);
199589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        } else {
200589708bf7c706348b763e8277004cb160b202bdbrileya@google.com            SkASSERT(fDstToIndexClass == kLinear_MatrixClass);
201589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        }
202589708bf7c706348b763e8277004cb160b202bdbrileya@google.com
203589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        RadialShade16Proc shadeProc = shadeSpan16_radial_repeat;
20487fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org        if (SkShader::kClamp_TileMode == radialGradient.fTileMode) {
205589708bf7c706348b763e8277004cb160b202bdbrileya@google.com            shadeProc = shadeSpan16_radial_clamp;
20687fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org        } else if (SkShader::kMirror_TileMode == radialGradient.fTileMode) {
207589708bf7c706348b763e8277004cb160b202bdbrileya@google.com            shadeProc = shadeSpan16_radial_mirror;
208589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        } else {
20987fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org            SkASSERT(SkShader::kRepeat_TileMode == radialGradient.fTileMode);
210589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        }
211589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        (*shadeProc)(srcPt.fX, sdx, srcPt.fY, sdy, dstC,
212589708bf7c706348b763e8277004cb160b202bdbrileya@google.com                     cache, toggle, count);
213589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    } else {    // perspective case
214589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        SkScalar dstX = SkIntToScalar(x);
215589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        SkScalar dstY = SkIntToScalar(y);
216589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        do {
217589708bf7c706348b763e8277004cb160b202bdbrileya@google.com            dstProc(fDstToIndex, dstX, dstY, &srcPt);
218589708bf7c706348b763e8277004cb160b202bdbrileya@google.com            unsigned fi = proc(SkScalarToFixed(srcPt.length()));
219589708bf7c706348b763e8277004cb160b202bdbrileya@google.com            SkASSERT(fi <= 0xFFFF);
220589708bf7c706348b763e8277004cb160b202bdbrileya@google.com
221589708bf7c706348b763e8277004cb160b202bdbrileya@google.com            int index = fi >> (16 - kCache16Bits);
222589708bf7c706348b763e8277004cb160b202bdbrileya@google.com            *dstC++ = cache[toggle + index];
22355853db3cce9539746fe202519a534c85ecdf62creed@google.com            toggle = next_dither_toggle16(toggle);
224589708bf7c706348b763e8277004cb160b202bdbrileya@google.com
225589708bf7c706348b763e8277004cb160b202bdbrileya@google.com            dstX += SK_Scalar1;
226589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        } while (--count != 0);
227589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    }
228589708bf7c706348b763e8277004cb160b202bdbrileya@google.com}
229589708bf7c706348b763e8277004cb160b202bdbrileya@google.com
230fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.comSkShader::BitmapType SkRadialGradient::asABitmap(SkBitmap* bitmap,
231589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    SkMatrix* matrix, SkShader::TileMode* xy) const {
232589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    if (bitmap) {
2331c6d64b78b24083ee9fd7411dac8a4a7e2d03a3crileya@google.com        this->getGradientTableBitmap(bitmap);
234589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    }
235589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    if (matrix) {
2363c2102c2d2cdad328a0d87329e1a973f12775836reed@google.com        matrix->setScale(SkIntToScalar(kCache32Count),
2373c2102c2d2cdad328a0d87329e1a973f12775836reed@google.com                         SkIntToScalar(kCache32Count));
238589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        matrix->preConcat(fPtsToUnit);
239589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    }
240589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    if (xy) {
241589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        xy[0] = fTileMode;
242589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        xy[1] = kClamp_TileMode;
243589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    }
244589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    return kRadial_BitmapType;
245589708bf7c706348b763e8277004cb160b202bdbrileya@google.com}
246589708bf7c706348b763e8277004cb160b202bdbrileya@google.com
247589708bf7c706348b763e8277004cb160b202bdbrileya@google.comSkShader::GradientType SkRadialGradient::asAGradient(GradientInfo* info) const {
248589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    if (info) {
249589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        commonAsAGradient(info);
250589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        info->fPoint[0] = fCenter;
251589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        info->fRadius[0] = fRadius;
252589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    }
253589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    return kRadial_GradientType;
254589708bf7c706348b763e8277004cb160b202bdbrileya@google.com}
255589708bf7c706348b763e8277004cb160b202bdbrileya@google.com
2568b0e8ac5f582de80356019406e2975079bf0829dcommit-bot@chromium.orgSkRadialGradient::SkRadialGradient(SkReadBuffer& buffer)
257589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    : INHERITED(buffer),
258589708bf7c706348b763e8277004cb160b202bdbrileya@google.com      fCenter(buffer.readPoint()),
259589708bf7c706348b763e8277004cb160b202bdbrileya@google.com      fRadius(buffer.readScalar()) {
260589708bf7c706348b763e8277004cb160b202bdbrileya@google.com}
261589708bf7c706348b763e8277004cb160b202bdbrileya@google.com
2628b0e8ac5f582de80356019406e2975079bf0829dcommit-bot@chromium.orgvoid SkRadialGradient::flatten(SkWriteBuffer& buffer) const {
263589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    this->INHERITED::flatten(buffer);
264589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    buffer.writePoint(fCenter);
265589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    buffer.writeScalar(fRadius);
266589708bf7c706348b763e8277004cb160b202bdbrileya@google.com}
267589708bf7c706348b763e8277004cb160b202bdbrileya@google.com
268589708bf7c706348b763e8277004cb160b202bdbrileya@google.comnamespace {
269589708bf7c706348b763e8277004cb160b202bdbrileya@google.com
270589708bf7c706348b763e8277004cb160b202bdbrileya@google.cominline bool radial_completely_pinned(int fx, int dx, int fy, int dy) {
271589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    // fast, overly-conservative test: checks unit square instead
272589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    // of unit circle
273589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    bool xClamped = (fx >= SK_FixedHalf && dx >= 0) ||
274589708bf7c706348b763e8277004cb160b202bdbrileya@google.com                    (fx <= -SK_FixedHalf && dx <= 0);
275589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    bool yClamped = (fy >= SK_FixedHalf && dy >= 0) ||
276589708bf7c706348b763e8277004cb160b202bdbrileya@google.com                    (fy <= -SK_FixedHalf && dy <= 0);
277589708bf7c706348b763e8277004cb160b202bdbrileya@google.com
278589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    return xClamped || yClamped;
279589708bf7c706348b763e8277004cb160b202bdbrileya@google.com}
280589708bf7c706348b763e8277004cb160b202bdbrileya@google.com
281589708bf7c706348b763e8277004cb160b202bdbrileya@google.com// Return true if (fx * fy) is always inside the unit circle
282589708bf7c706348b763e8277004cb160b202bdbrileya@google.com// SkPin32 is expensive, but so are all the SkFixedMul in this test,
283589708bf7c706348b763e8277004cb160b202bdbrileya@google.com// so it shouldn't be run if count is small.
284589708bf7c706348b763e8277004cb160b202bdbrileya@google.cominline bool no_need_for_radial_pin(int fx, int dx,
285589708bf7c706348b763e8277004cb160b202bdbrileya@google.com                                          int fy, int dy, int count) {
286589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    SkASSERT(count > 0);
287589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    if (SkAbs32(fx) > 0x7FFF || SkAbs32(fy) > 0x7FFF) {
288589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        return false;
289589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    }
290589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    if (fx*fx + fy*fy > 0x7FFF*0x7FFF) {
291589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        return false;
292589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    }
293589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    fx += (count - 1) * dx;
294589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    fy += (count - 1) * dy;
295589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    if (SkAbs32(fx) > 0x7FFF || SkAbs32(fy) > 0x7FFF) {
296589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        return false;
297589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    }
298589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    return fx*fx + fy*fy <= 0x7FFF*0x7FFF;
299589708bf7c706348b763e8277004cb160b202bdbrileya@google.com}
300589708bf7c706348b763e8277004cb160b202bdbrileya@google.com
301589708bf7c706348b763e8277004cb160b202bdbrileya@google.com#define UNPINNED_RADIAL_STEP \
302589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    fi = (fx * fx + fy * fy) >> (14 + 16 - kSQRT_TABLE_BITS); \
303589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    *dstC++ = cache[toggle + \
304589708bf7c706348b763e8277004cb160b202bdbrileya@google.com                    (sqrt_table[fi] >> SkGradientShaderBase::kSqrt32Shift)]; \
30555853db3cce9539746fe202519a534c85ecdf62creed@google.com    toggle = next_dither_toggle(toggle); \
306589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    fx += dx; \
307589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    fy += dy;
308589708bf7c706348b763e8277004cb160b202bdbrileya@google.com
309589708bf7c706348b763e8277004cb160b202bdbrileya@google.comtypedef void (* RadialShadeProc)(SkScalar sfx, SkScalar sdx,
310589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        SkScalar sfy, SkScalar sdy,
311589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        SkPMColor* dstC, const SkPMColor* cache,
312589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        int count, int toggle);
313589708bf7c706348b763e8277004cb160b202bdbrileya@google.com
314589708bf7c706348b763e8277004cb160b202bdbrileya@google.com// On Linux, this is faster with SkPMColor[] params than SkPMColor* SK_RESTRICT
315589708bf7c706348b763e8277004cb160b202bdbrileya@google.comvoid shadeSpan_radial_clamp(SkScalar sfx, SkScalar sdx,
316589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        SkScalar sfy, SkScalar sdy,
317589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        SkPMColor* SK_RESTRICT dstC, const SkPMColor* SK_RESTRICT cache,
318589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        int count, int toggle) {
319589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    // Floating point seems to be slower than fixed point,
320589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    // even when we have float hardware.
321589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    const uint8_t* SK_RESTRICT sqrt_table = gSqrt8Table;
322589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    SkFixed fx = SkScalarToFixed(sfx) >> 1;
323589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    SkFixed dx = SkScalarToFixed(sdx) >> 1;
324589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    SkFixed fy = SkScalarToFixed(sfy) >> 1;
325589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    SkFixed dy = SkScalarToFixed(sdy) >> 1;
326589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    if ((count > 4) && radial_completely_pinned(fx, dx, fy, dy)) {
3273c2102c2d2cdad328a0d87329e1a973f12775836reed@google.com        unsigned fi = SkGradientShaderBase::kCache32Count - 1;
328589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        sk_memset32_dither(dstC,
329589708bf7c706348b763e8277004cb160b202bdbrileya@google.com            cache[toggle + fi],
33055853db3cce9539746fe202519a534c85ecdf62creed@google.com            cache[next_dither_toggle(toggle) + fi],
331589708bf7c706348b763e8277004cb160b202bdbrileya@google.com            count);
332589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    } else if ((count > 4) &&
333589708bf7c706348b763e8277004cb160b202bdbrileya@google.com               no_need_for_radial_pin(fx, dx, fy, dy, count)) {
334589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        unsigned fi;
335589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        // 4x unroll appears to be no faster than 2x unroll on Linux
336589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        while (count > 1) {
337589708bf7c706348b763e8277004cb160b202bdbrileya@google.com            UNPINNED_RADIAL_STEP;
338589708bf7c706348b763e8277004cb160b202bdbrileya@google.com            UNPINNED_RADIAL_STEP;
339589708bf7c706348b763e8277004cb160b202bdbrileya@google.com            count -= 2;
340589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        }
341589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        if (count) {
342589708bf7c706348b763e8277004cb160b202bdbrileya@google.com            UNPINNED_RADIAL_STEP;
343589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        }
34460040292be58ac553298209fb2e0684a4cb17dccreed@google.com    } else  {
345589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        // Specializing for dy == 0 gains us 25% on Skia benchmarks
346589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        if (dy == 0) {
347589708bf7c706348b763e8277004cb160b202bdbrileya@google.com            unsigned yy = SkPin32(fy, -0xFFFF >> 1, 0xFFFF >> 1);
348589708bf7c706348b763e8277004cb160b202bdbrileya@google.com            yy *= yy;
349589708bf7c706348b763e8277004cb160b202bdbrileya@google.com            do {
350589708bf7c706348b763e8277004cb160b202bdbrileya@google.com                unsigned xx = SkPin32(fx, -0xFFFF >> 1, 0xFFFF >> 1);
351589708bf7c706348b763e8277004cb160b202bdbrileya@google.com                unsigned fi = (xx * xx + yy) >> (14 + 16 - kSQRT_TABLE_BITS);
352589708bf7c706348b763e8277004cb160b202bdbrileya@google.com                fi = SkFastMin32(fi, 0xFFFF >> (16 - kSQRT_TABLE_BITS));
353589708bf7c706348b763e8277004cb160b202bdbrileya@google.com                *dstC++ = cache[toggle + (sqrt_table[fi] >>
354589708bf7c706348b763e8277004cb160b202bdbrileya@google.com                    SkGradientShaderBase::kSqrt32Shift)];
35555853db3cce9539746fe202519a534c85ecdf62creed@google.com                toggle = next_dither_toggle(toggle);
356589708bf7c706348b763e8277004cb160b202bdbrileya@google.com                fx += dx;
357589708bf7c706348b763e8277004cb160b202bdbrileya@google.com            } while (--count != 0);
358589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        } else {
359589708bf7c706348b763e8277004cb160b202bdbrileya@google.com            do {
360589708bf7c706348b763e8277004cb160b202bdbrileya@google.com                unsigned xx = SkPin32(fx, -0xFFFF >> 1, 0xFFFF >> 1);
361589708bf7c706348b763e8277004cb160b202bdbrileya@google.com                unsigned fi = SkPin32(fy, -0xFFFF >> 1, 0xFFFF >> 1);
362589708bf7c706348b763e8277004cb160b202bdbrileya@google.com                fi = (xx * xx + fi * fi) >> (14 + 16 - kSQRT_TABLE_BITS);
363589708bf7c706348b763e8277004cb160b202bdbrileya@google.com                fi = SkFastMin32(fi, 0xFFFF >> (16 - kSQRT_TABLE_BITS));
364589708bf7c706348b763e8277004cb160b202bdbrileya@google.com                *dstC++ = cache[toggle + (sqrt_table[fi] >>
365589708bf7c706348b763e8277004cb160b202bdbrileya@google.com                    SkGradientShaderBase::kSqrt32Shift)];
36655853db3cce9539746fe202519a534c85ecdf62creed@google.com                toggle = next_dither_toggle(toggle);
367589708bf7c706348b763e8277004cb160b202bdbrileya@google.com                fx += dx;
368589708bf7c706348b763e8277004cb160b202bdbrileya@google.com                fy += dy;
369589708bf7c706348b763e8277004cb160b202bdbrileya@google.com            } while (--count != 0);
370589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        }
371589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    }
372589708bf7c706348b763e8277004cb160b202bdbrileya@google.com}
373589708bf7c706348b763e8277004cb160b202bdbrileya@google.com
374589708bf7c706348b763e8277004cb160b202bdbrileya@google.com// Unrolling this loop doesn't seem to help (when float); we're stalling to
375589708bf7c706348b763e8277004cb160b202bdbrileya@google.com// get the results of the sqrt (?), and don't have enough extra registers to
376589708bf7c706348b763e8277004cb160b202bdbrileya@google.com// have many in flight.
37734150b451da7d3c70a2d34e67b0285cb36932d45commit-bot@chromium.orgtemplate <SkFixed (*TileProc)(SkFixed)>
37834150b451da7d3c70a2d34e67b0285cb36932d45commit-bot@chromium.orgvoid shadeSpan_radial(SkScalar fx, SkScalar dx, SkScalar fy, SkScalar dy,
37934150b451da7d3c70a2d34e67b0285cb36932d45commit-bot@chromium.org                      SkPMColor* SK_RESTRICT dstC, const SkPMColor* SK_RESTRICT cache,
38034150b451da7d3c70a2d34e67b0285cb36932d45commit-bot@chromium.org                      int count, int toggle) {
381589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    do {
38234150b451da7d3c70a2d34e67b0285cb36932d45commit-bot@chromium.org        const SkFixed dist = SkFloatToFixed(sk_float_sqrt(fx*fx + fy*fy));
38334150b451da7d3c70a2d34e67b0285cb36932d45commit-bot@chromium.org        const unsigned fi = TileProc(dist);
384589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        SkASSERT(fi <= 0xFFFF);
385589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        *dstC++ = cache[toggle + (fi >> SkGradientShaderBase::kCache32Shift)];
38655853db3cce9539746fe202519a534c85ecdf62creed@google.com        toggle = next_dither_toggle(toggle);
387589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        fx += dx;
388589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        fy += dy;
389589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    } while (--count != 0);
390589708bf7c706348b763e8277004cb160b202bdbrileya@google.com}
39134150b451da7d3c70a2d34e67b0285cb36932d45commit-bot@chromium.org
39234150b451da7d3c70a2d34e67b0285cb36932d45commit-bot@chromium.orgvoid shadeSpan_radial_mirror(SkScalar fx, SkScalar dx, SkScalar fy, SkScalar dy,
39334150b451da7d3c70a2d34e67b0285cb36932d45commit-bot@chromium.org                             SkPMColor* SK_RESTRICT dstC, const SkPMColor* SK_RESTRICT cache,
39434150b451da7d3c70a2d34e67b0285cb36932d45commit-bot@chromium.org                             int count, int toggle) {
39534150b451da7d3c70a2d34e67b0285cb36932d45commit-bot@chromium.org    shadeSpan_radial<mirror_tileproc_nonstatic>(fx, dx, fy, dy, dstC, cache, count, toggle);
39634150b451da7d3c70a2d34e67b0285cb36932d45commit-bot@chromium.org}
39734150b451da7d3c70a2d34e67b0285cb36932d45commit-bot@chromium.org
39834150b451da7d3c70a2d34e67b0285cb36932d45commit-bot@chromium.orgvoid shadeSpan_radial_repeat(SkScalar fx, SkScalar dx, SkScalar fy, SkScalar dy,
39934150b451da7d3c70a2d34e67b0285cb36932d45commit-bot@chromium.org                             SkPMColor* SK_RESTRICT dstC, const SkPMColor* SK_RESTRICT cache,
40034150b451da7d3c70a2d34e67b0285cb36932d45commit-bot@chromium.org                             int count, int toggle) {
40134150b451da7d3c70a2d34e67b0285cb36932d45commit-bot@chromium.org    shadeSpan_radial<repeat_tileproc_nonstatic>(fx, dx, fy, dy, dstC, cache, count, toggle);
402589708bf7c706348b763e8277004cb160b202bdbrileya@google.com}
403589708bf7c706348b763e8277004cb160b202bdbrileya@google.com
40434150b451da7d3c70a2d34e67b0285cb36932d45commit-bot@chromium.org}  // namespace
40534150b451da7d3c70a2d34e67b0285cb36932d45commit-bot@chromium.org
40687fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.orgvoid SkRadialGradient::RadialGradientContext::shadeSpan(int x, int y,
40787fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org                                                        SkPMColor* SK_RESTRICT dstC, int count) {
408589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    SkASSERT(count > 0);
409589708bf7c706348b763e8277004cb160b202bdbrileya@google.com
41087fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org    const SkRadialGradient& radialGradient = static_cast<const SkRadialGradient&>(fShader);
41187fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org
412589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    SkPoint             srcPt;
413589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    SkMatrix::MapXYProc dstProc = fDstToIndexProc;
41487fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org    TileProc            proc = radialGradient.fTileProc;
41587fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org    const SkPMColor* SK_RESTRICT cache = fCache->getCache32();
41655853db3cce9539746fe202519a534c85ecdf62creed@google.com    int toggle = init_dither_toggle(x, y);
417589708bf7c706348b763e8277004cb160b202bdbrileya@google.com
418589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    if (fDstToIndexClass != kPerspective_MatrixClass) {
419589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        dstProc(fDstToIndex, SkIntToScalar(x) + SK_ScalarHalf,
420589708bf7c706348b763e8277004cb160b202bdbrileya@google.com                             SkIntToScalar(y) + SK_ScalarHalf, &srcPt);
421589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        SkScalar sdx = fDstToIndex.getScaleX();
422589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        SkScalar sdy = fDstToIndex.getSkewY();
423589708bf7c706348b763e8277004cb160b202bdbrileya@google.com
424589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        if (fDstToIndexClass == kFixedStepInX_MatrixClass) {
425589708bf7c706348b763e8277004cb160b202bdbrileya@google.com            SkFixed storage[2];
426589708bf7c706348b763e8277004cb160b202bdbrileya@google.com            (void)fDstToIndex.fixedStepInX(SkIntToScalar(y),
427589708bf7c706348b763e8277004cb160b202bdbrileya@google.com                                           &storage[0], &storage[1]);
428589708bf7c706348b763e8277004cb160b202bdbrileya@google.com            sdx = SkFixedToScalar(storage[0]);
429589708bf7c706348b763e8277004cb160b202bdbrileya@google.com            sdy = SkFixedToScalar(storage[1]);
430589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        } else {
431589708bf7c706348b763e8277004cb160b202bdbrileya@google.com            SkASSERT(fDstToIndexClass == kLinear_MatrixClass);
432589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        }
433589708bf7c706348b763e8277004cb160b202bdbrileya@google.com
434589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        RadialShadeProc shadeProc = shadeSpan_radial_repeat;
43587fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org        if (SkShader::kClamp_TileMode == radialGradient.fTileMode) {
436589708bf7c706348b763e8277004cb160b202bdbrileya@google.com            shadeProc = shadeSpan_radial_clamp;
43787fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org        } else if (SkShader::kMirror_TileMode == radialGradient.fTileMode) {
438589708bf7c706348b763e8277004cb160b202bdbrileya@google.com            shadeProc = shadeSpan_radial_mirror;
439589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        } else {
44087fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org            SkASSERT(SkShader::kRepeat_TileMode == radialGradient.fTileMode);
441589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        }
442589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        (*shadeProc)(srcPt.fX, sdx, srcPt.fY, sdy, dstC, cache, count, toggle);
443589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    } else {    // perspective case
444589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        SkScalar dstX = SkIntToScalar(x);
445589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        SkScalar dstY = SkIntToScalar(y);
446589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        do {
447589708bf7c706348b763e8277004cb160b202bdbrileya@google.com            dstProc(fDstToIndex, dstX, dstY, &srcPt);
448589708bf7c706348b763e8277004cb160b202bdbrileya@google.com            unsigned fi = proc(SkScalarToFixed(srcPt.length()));
449589708bf7c706348b763e8277004cb160b202bdbrileya@google.com            SkASSERT(fi <= 0xFFFF);
450589708bf7c706348b763e8277004cb160b202bdbrileya@google.com            *dstC++ = cache[fi >> SkGradientShaderBase::kCache32Shift];
451589708bf7c706348b763e8277004cb160b202bdbrileya@google.com            dstX += SK_Scalar1;
452589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        } while (--count != 0);
453589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    }
454589708bf7c706348b763e8277004cb160b202bdbrileya@google.com}
455589708bf7c706348b763e8277004cb160b202bdbrileya@google.com
456d7cc651b8da11d52ae90e910b948f5e2d15daaf9rileya@google.com/////////////////////////////////////////////////////////////////////
457d7cc651b8da11d52ae90e910b948f5e2d15daaf9rileya@google.com
458cf8fb1f6f03fc77f9927564f9ef9abeeeec508d2bsalomon@google.com#if SK_SUPPORT_GPU
459cf8fb1f6f03fc77f9927564f9ef9abeeeec508d2bsalomon@google.com
4602eaaefd7e6a58339b3f93333f1e9cc92252cc303bsalomon@google.com#include "GrTBackendEffectFactory.h"
4619de5b514d38c5b36066bcdc14fba2f7e5196d372dandov#include "SkGr.h"
4622eaaefd7e6a58339b3f93333f1e9cc92252cc303bsalomon@google.com
4630707c29413a5a3cc1c2d14b8c65b3692af5c7411bsalomon@google.comclass GrGLRadialGradient : public GrGLGradientEffect {
464d7cc651b8da11d52ae90e910b948f5e2d15daaf9rileya@google.compublic:
465d7cc651b8da11d52ae90e910b948f5e2d15daaf9rileya@google.com
466396e61fe440590744345e0c56970b26ab464591dbsalomon@google.com    GrGLRadialGradient(const GrBackendEffectFactory& factory,
467c78188896e28a4ae49e406a7422b345ae177dafebsalomon@google.com                       const GrDrawEffect&) : INHERITED (factory) { }
468d7cc651b8da11d52ae90e910b948f5e2d15daaf9rileya@google.com    virtual ~GrGLRadialGradient() { }
469d7cc651b8da11d52ae90e910b948f5e2d15daaf9rileya@google.com
470f78df33efc72167f94da1b0476c9a86ba18a5f2cbsalomon@google.com    virtual void emitCode(GrGLShaderBuilder*,
471c78188896e28a4ae49e406a7422b345ae177dafebsalomon@google.com                          const GrDrawEffect&,
472f78df33efc72167f94da1b0476c9a86ba18a5f2cbsalomon@google.com                          EffectKey,
473f78df33efc72167f94da1b0476c9a86ba18a5f2cbsalomon@google.com                          const char* outputColor,
474f78df33efc72167f94da1b0476c9a86ba18a5f2cbsalomon@google.com                          const char* inputColor,
47577af6805e5faea1e2a5c0220098aec9082f3a6e5bsalomon@google.com                          const TransformedCoordsArray&,
476f78df33efc72167f94da1b0476c9a86ba18a5f2cbsalomon@google.com                          const TextureSamplerArray&) SK_OVERRIDE;
477d7cc651b8da11d52ae90e910b948f5e2d15daaf9rileya@google.com
478c78188896e28a4ae49e406a7422b345ae177dafebsalomon@google.com    static EffectKey GenKey(const GrDrawEffect& drawEffect, const GrGLCaps&) {
47982d1223aece4703bc9f3a3612cbabaa8c2f2809bbsalomon@google.com        return GenBaseGradientKey(drawEffect);
480d8b5faca043100d7a1e4594b4d10e462532af390bsalomon@google.com    }
481d7cc651b8da11d52ae90e910b948f5e2d15daaf9rileya@google.com
482d7cc651b8da11d52ae90e910b948f5e2d15daaf9rileya@google.comprivate:
483d7cc651b8da11d52ae90e910b948f5e2d15daaf9rileya@google.com
4840707c29413a5a3cc1c2d14b8c65b3692af5c7411bsalomon@google.com    typedef GrGLGradientEffect INHERITED;
485d7cc651b8da11d52ae90e910b948f5e2d15daaf9rileya@google.com
486d7cc651b8da11d52ae90e910b948f5e2d15daaf9rileya@google.com};
487d7cc651b8da11d52ae90e910b948f5e2d15daaf9rileya@google.com
48898e8b6de04e4c20451fbe3353645e3e384a76550rileya@google.com/////////////////////////////////////////////////////////////////////
48998e8b6de04e4c20451fbe3353645e3e384a76550rileya@google.com
49098e8b6de04e4c20451fbe3353645e3e384a76550rileya@google.comclass GrRadialGradient : public GrGradientEffect {
49198e8b6de04e4c20451fbe3353645e3e384a76550rileya@google.compublic:
4920ac6af49975c54c2debf41e9200af416ecd2d973bsalomon@google.com    static GrEffectRef* Create(GrContext* ctx,
4930ac6af49975c54c2debf41e9200af416ecd2d973bsalomon@google.com                               const SkRadialGradient& shader,
4940ac6af49975c54c2debf41e9200af416ecd2d973bsalomon@google.com                               const SkMatrix& matrix,
4950ac6af49975c54c2debf41e9200af416ecd2d973bsalomon@google.com                               SkShader::TileMode tm) {
4966340a41108633ac1ce5941e5cd30538630c4c55bbsalomon@google.com        AutoEffectUnref effect(SkNEW_ARGS(GrRadialGradient, (ctx, shader, matrix, tm)));
497a1ebbe447d5eab098111eb83580e55f2f5f6facabsalomon@google.com        return CreateEffectRef(effect);
49898e8b6de04e4c20451fbe3353645e3e384a76550rileya@google.com    }
49998e8b6de04e4c20451fbe3353645e3e384a76550rileya@google.com
50098e8b6de04e4c20451fbe3353645e3e384a76550rileya@google.com    virtual ~GrRadialGradient() { }
50198e8b6de04e4c20451fbe3353645e3e384a76550rileya@google.com
50298e8b6de04e4c20451fbe3353645e3e384a76550rileya@google.com    static const char* Name() { return "Radial Gradient"; }
503396e61fe440590744345e0c56970b26ab464591dbsalomon@google.com    virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE {
504396e61fe440590744345e0c56970b26ab464591dbsalomon@google.com        return GrTBackendEffectFactory<GrRadialGradient>::getInstance();
50598e8b6de04e4c20451fbe3353645e3e384a76550rileya@google.com    }
50698e8b6de04e4c20451fbe3353645e3e384a76550rileya@google.com
507422e81aeb1f4078367c85efe591c7df8c33874ecbsalomon@google.com    typedef GrGLRadialGradient GLEffect;
50898e8b6de04e4c20451fbe3353645e3e384a76550rileya@google.com
50998e8b6de04e4c20451fbe3353645e3e384a76550rileya@google.comprivate:
5100ac6af49975c54c2debf41e9200af416ecd2d973bsalomon@google.com    GrRadialGradient(GrContext* ctx,
5110ac6af49975c54c2debf41e9200af416ecd2d973bsalomon@google.com                     const SkRadialGradient& shader,
5120ac6af49975c54c2debf41e9200af416ecd2d973bsalomon@google.com                     const SkMatrix& matrix,
5130ac6af49975c54c2debf41e9200af416ecd2d973bsalomon@google.com                     SkShader::TileMode tm)
5140ac6af49975c54c2debf41e9200af416ecd2d973bsalomon@google.com        : INHERITED(ctx, shader, matrix, tm) {
5150ac6af49975c54c2debf41e9200af416ecd2d973bsalomon@google.com    }
5160ac6af49975c54c2debf41e9200af416ecd2d973bsalomon@google.com
517f271cc7183fe48ac64d2d9a454eb013c91b42d53bsalomon@google.com    GR_DECLARE_EFFECT_TEST;
51898e8b6de04e4c20451fbe3353645e3e384a76550rileya@google.com
51998e8b6de04e4c20451fbe3353645e3e384a76550rileya@google.com    typedef GrGradientEffect INHERITED;
52098e8b6de04e4c20451fbe3353645e3e384a76550rileya@google.com};
52198e8b6de04e4c20451fbe3353645e3e384a76550rileya@google.com
52298e8b6de04e4c20451fbe3353645e3e384a76550rileya@google.com/////////////////////////////////////////////////////////////////////
52398e8b6de04e4c20451fbe3353645e3e384a76550rileya@google.com
524f271cc7183fe48ac64d2d9a454eb013c91b42d53bsalomon@google.comGR_DEFINE_EFFECT_TEST(GrRadialGradient);
525d472620458e2383e6dd949f4e1aaf61160717ffebsalomon@google.com
526e0e7cfe44bb9d66d76120a79e5275c294bacaa22commit-bot@chromium.orgGrEffectRef* GrRadialGradient::TestCreate(SkRandom* random,
5270ac6af49975c54c2debf41e9200af416ecd2d973bsalomon@google.com                                          GrContext* context,
528c26d94fd7dc0b00cd6d0e42d28285f4a38aff021bsalomon@google.com                                          const GrDrawTargetCaps&,
5290ac6af49975c54c2debf41e9200af416ecd2d973bsalomon@google.com                                          GrTexture**) {
530d472620458e2383e6dd949f4e1aaf61160717ffebsalomon@google.com    SkPoint center = {random->nextUScalar1(), random->nextUScalar1()};
531d472620458e2383e6dd949f4e1aaf61160717ffebsalomon@google.com    SkScalar radius = random->nextUScalar1();
532d472620458e2383e6dd949f4e1aaf61160717ffebsalomon@google.com
533d472620458e2383e6dd949f4e1aaf61160717ffebsalomon@google.com    SkColor colors[kMaxRandomGradientColors];
534d472620458e2383e6dd949f4e1aaf61160717ffebsalomon@google.com    SkScalar stopsArray[kMaxRandomGradientColors];
535d472620458e2383e6dd949f4e1aaf61160717ffebsalomon@google.com    SkScalar* stops = stopsArray;
536d472620458e2383e6dd949f4e1aaf61160717ffebsalomon@google.com    SkShader::TileMode tm;
537d472620458e2383e6dd949f4e1aaf61160717ffebsalomon@google.com    int colorCount = RandomGradientParams(random, colors, &stops, &tm);
538d472620458e2383e6dd949f4e1aaf61160717ffebsalomon@google.com    SkAutoTUnref<SkShader> shader(SkGradientShader::CreateRadial(center, radius,
539d472620458e2383e6dd949f4e1aaf61160717ffebsalomon@google.com                                                                 colors, stops, colorCount,
540d472620458e2383e6dd949f4e1aaf61160717ffebsalomon@google.com                                                                 tm));
541e197cbf9a3e66bab926bc5e51962752dad5221a0bsalomon@google.com    SkPaint paint;
5429de5b514d38c5b36066bcdc14fba2f7e5196d372dandov    GrColor grColor;
5439de5b514d38c5b36066bcdc14fba2f7e5196d372dandov    GrEffectRef* effect;
5449de5b514d38c5b36066bcdc14fba2f7e5196d372dandov    shader->asNewEffect(context, paint, NULL, &grColor, &effect);
5459de5b514d38c5b36066bcdc14fba2f7e5196d372dandov    return effect;
546d472620458e2383e6dd949f4e1aaf61160717ffebsalomon@google.com}
547d472620458e2383e6dd949f4e1aaf61160717ffebsalomon@google.com
548d472620458e2383e6dd949f4e1aaf61160717ffebsalomon@google.com/////////////////////////////////////////////////////////////////////
549d472620458e2383e6dd949f4e1aaf61160717ffebsalomon@google.com
550f78df33efc72167f94da1b0476c9a86ba18a5f2cbsalomon@google.comvoid GrGLRadialGradient::emitCode(GrGLShaderBuilder* builder,
551c78188896e28a4ae49e406a7422b345ae177dafebsalomon@google.com                                  const GrDrawEffect&,
552d8b5faca043100d7a1e4594b4d10e462532af390bsalomon@google.com                                  EffectKey key,
553f78df33efc72167f94da1b0476c9a86ba18a5f2cbsalomon@google.com                                  const char* outputColor,
554f78df33efc72167f94da1b0476c9a86ba18a5f2cbsalomon@google.com                                  const char* inputColor,
55577af6805e5faea1e2a5c0220098aec9082f3a6e5bsalomon@google.com                                  const TransformedCoordsArray& coords,
556f78df33efc72167f94da1b0476c9a86ba18a5f2cbsalomon@google.com                                  const TextureSamplerArray& samplers) {
55782d1223aece4703bc9f3a3612cbabaa8c2f2809bbsalomon@google.com    this->emitUniforms(builder, key);
558d8b5faca043100d7a1e4594b4d10e462532af390bsalomon@google.com    SkString t("length(");
55977af6805e5faea1e2a5c0220098aec9082f3a6e5bsalomon@google.com    t.append(builder->ensureFSCoords2D(coords, 0));
560d8b5faca043100d7a1e4594b4d10e462532af390bsalomon@google.com    t.append(")");
56182d1223aece4703bc9f3a3612cbabaa8c2f2809bbsalomon@google.com    this->emitColor(builder, t.c_str(), key, outputColor, inputColor, samplers);
562d7cc651b8da11d52ae90e910b948f5e2d15daaf9rileya@google.com}
563d7cc651b8da11d52ae90e910b948f5e2d15daaf9rileya@google.com
564d7cc651b8da11d52ae90e910b948f5e2d15daaf9rileya@google.com/////////////////////////////////////////////////////////////////////
565d7cc651b8da11d52ae90e910b948f5e2d15daaf9rileya@google.com
5669de5b514d38c5b36066bcdc14fba2f7e5196d372dandovbool SkRadialGradient::asNewEffect(GrContext* context, const SkPaint& paint,
5679de5b514d38c5b36066bcdc14fba2f7e5196d372dandov                                   const SkMatrix* localMatrix, GrColor* grColor,
5689de5b514d38c5b36066bcdc14fba2f7e5196d372dandov                                   GrEffectRef** grEffect) const {
56900835cc55046e66b5a33633ec045bc9aa0015ebdbsalomon@google.com    SkASSERT(NULL != context);
5709de5b514d38c5b36066bcdc14fba2f7e5196d372dandov
571dfdb7e5240276493077b7c6e1f3cc8b8a0e195babsalomon@google.com    SkMatrix matrix;
572f94b3a4cebd4adab09c40ebe23c02a615e10c394bsalomon@google.com    if (!this->getLocalMatrix().invert(&matrix)) {
5739de5b514d38c5b36066bcdc14fba2f7e5196d372dandov        return false;
574dfdb7e5240276493077b7c6e1f3cc8b8a0e195babsalomon@google.com    }
57596fb7489ba46909c3f81bb2d94755e7d4ccb5fadcommit-bot@chromium.org    if (localMatrix) {
57696fb7489ba46909c3f81bb2d94755e7d4ccb5fadcommit-bot@chromium.org        SkMatrix inv;
57796fb7489ba46909c3f81bb2d94755e7d4ccb5fadcommit-bot@chromium.org        if (!localMatrix->invert(&inv)) {
5789de5b514d38c5b36066bcdc14fba2f7e5196d372dandov            return false;
57996fb7489ba46909c3f81bb2d94755e7d4ccb5fadcommit-bot@chromium.org        }
58096fb7489ba46909c3f81bb2d94755e7d4ccb5fadcommit-bot@chromium.org        matrix.postConcat(inv);
58196fb7489ba46909c3f81bb2d94755e7d4ccb5fadcommit-bot@chromium.org    }
582f94b3a4cebd4adab09c40ebe23c02a615e10c394bsalomon@google.com    matrix.postConcat(fPtsToUnit);
5839de5b514d38c5b36066bcdc14fba2f7e5196d372dandov
5849de5b514d38c5b36066bcdc14fba2f7e5196d372dandov    *grColor = SkColor2GrColorJustAlpha(paint.getColor());
5859de5b514d38c5b36066bcdc14fba2f7e5196d372dandov    *grEffect = GrRadialGradient::Create(context, *this, matrix, fTileMode);
5869de5b514d38c5b36066bcdc14fba2f7e5196d372dandov
5879de5b514d38c5b36066bcdc14fba2f7e5196d372dandov    return true;
588d7cc651b8da11d52ae90e910b948f5e2d15daaf9rileya@google.com}
589d7cc651b8da11d52ae90e910b948f5e2d15daaf9rileya@google.com
590cf8fb1f6f03fc77f9927564f9ef9abeeeec508d2bsalomon@google.com#else
591cf8fb1f6f03fc77f9927564f9ef9abeeeec508d2bsalomon@google.com
5929de5b514d38c5b36066bcdc14fba2f7e5196d372dandovbool SkRadialGradient::asNewEffect(GrContext* context, const SkPaint& paint,
5939de5b514d38c5b36066bcdc14fba2f7e5196d372dandov                                   const SkMatrix* localMatrix, GrColor* grColor,
5949de5b514d38c5b36066bcdc14fba2f7e5196d372dandov                                   GrEffectRef** grEffect) const {
595cf8fb1f6f03fc77f9927564f9ef9abeeeec508d2bsalomon@google.com    SkDEBUGFAIL("Should not call in GPU-less build");
5969de5b514d38c5b36066bcdc14fba2f7e5196d372dandov    return false;
597cf8fb1f6f03fc77f9927564f9ef9abeeeec508d2bsalomon@google.com}
598cf8fb1f6f03fc77f9927564f9ef9abeeeec508d2bsalomon@google.com
599cf8fb1f6f03fc77f9927564f9ef9abeeeec508d2bsalomon@google.com#endif
60076f9e938df0b5826fd4c80b854ceafaf385cfbe1robertphillips@google.com
6010f10f7bf1fb43ca6346dc220a076773b1f19a367commit-bot@chromium.org#ifndef SK_IGNORE_TO_STRING
60276f9e938df0b5826fd4c80b854ceafaf385cfbe1robertphillips@google.comvoid SkRadialGradient::toString(SkString* str) const {
60376f9e938df0b5826fd4c80b854ceafaf385cfbe1robertphillips@google.com    str->append("SkRadialGradient: (");
604ff21c2e0ae23da0f4742b47d4d37969a2a18bd99skia.committer@gmail.com
60576f9e938df0b5826fd4c80b854ceafaf385cfbe1robertphillips@google.com    str->append("center: (");
60676f9e938df0b5826fd4c80b854ceafaf385cfbe1robertphillips@google.com    str->appendScalar(fCenter.fX);
60776f9e938df0b5826fd4c80b854ceafaf385cfbe1robertphillips@google.com    str->append(", ");
60876f9e938df0b5826fd4c80b854ceafaf385cfbe1robertphillips@google.com    str->appendScalar(fCenter.fY);
60976f9e938df0b5826fd4c80b854ceafaf385cfbe1robertphillips@google.com    str->append(") radius: ");
61076f9e938df0b5826fd4c80b854ceafaf385cfbe1robertphillips@google.com    str->appendScalar(fRadius);
61176f9e938df0b5826fd4c80b854ceafaf385cfbe1robertphillips@google.com    str->append(" ");
61276f9e938df0b5826fd4c80b854ceafaf385cfbe1robertphillips@google.com
61376f9e938df0b5826fd4c80b854ceafaf385cfbe1robertphillips@google.com    this->INHERITED::toString(str);
61476f9e938df0b5826fd4c80b854ceafaf385cfbe1robertphillips@google.com
61576f9e938df0b5826fd4c80b854ceafaf385cfbe1robertphillips@google.com    str->append(")");
61676f9e938df0b5826fd4c80b854ceafaf385cfbe1robertphillips@google.com}
61776f9e938df0b5826fd4c80b854ceafaf385cfbe1robertphillips@google.com#endif
618