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
148addf2edf3da20f053daa3897cfe2c52d7369a7b1reedSkRadialGradient::SkRadialGradient(const SkPoint& center, SkScalar radius, const Descriptor& desc)
149addf2edf3da20f053daa3897cfe2c52d7369a7b1reed    : SkGradientShaderBase(desc)
150addf2edf3da20f053daa3897cfe2c52d7369a7b1reed    , fCenter(center)
151addf2edf3da20f053daa3897cfe2c52d7369a7b1reed    , fRadius(radius)
152589708bf7c706348b763e8277004cb160b202bdbrileya@google.com{
153589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    // make sure our table is insync with our current #define for kSQRT_TABLE_SIZE
154589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    SkASSERT(sizeof(gSqrt8Table) == kSQRT_TABLE_SIZE);
155589708bf7c706348b763e8277004cb160b202bdbrileya@google.com
156589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    rad_to_unit_matrix(center, radius, &fPtsToUnit);
157589708bf7c706348b763e8277004cb160b202bdbrileya@google.com}
158589708bf7c706348b763e8277004cb160b202bdbrileya@google.com
15987fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.orgsize_t SkRadialGradient::contextSize() const {
16087fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org    return sizeof(RadialGradientContext);
16187fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org}
16287fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org
163ce56d965069c1649afe14319cb239e6ad670682acommit-bot@chromium.orgSkShader::Context* SkRadialGradient::onCreateContext(const ContextRec& rec, void* storage) const {
164e901b6de3ef8dea842008a08fc81e92fb1478d61commit-bot@chromium.org    return SkNEW_PLACEMENT_ARGS(storage, RadialGradientContext, (*this, rec));
16587fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org}
16687fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org
16787fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.orgSkRadialGradient::RadialGradientContext::RadialGradientContext(
168e901b6de3ef8dea842008a08fc81e92fb1478d61commit-bot@chromium.org        const SkRadialGradient& shader, const ContextRec& rec)
169e901b6de3ef8dea842008a08fc81e92fb1478d61commit-bot@chromium.org    : INHERITED(shader, rec) {}
17087fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org
17187fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.orgvoid SkRadialGradient::RadialGradientContext::shadeSpan16(int x, int y, uint16_t* dstCParam,
17287fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org                                                          int count) {
173589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    SkASSERT(count > 0);
174589708bf7c706348b763e8277004cb160b202bdbrileya@google.com
17587fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org    const SkRadialGradient& radialGradient = static_cast<const SkRadialGradient&>(fShader);
17687fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org
177589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    uint16_t* SK_RESTRICT dstC = dstCParam;
178589708bf7c706348b763e8277004cb160b202bdbrileya@google.com
179589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    SkPoint             srcPt;
180589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    SkMatrix::MapXYProc dstProc = fDstToIndexProc;
18187fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org    TileProc            proc = radialGradient.fTileProc;
18287fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org    const uint16_t* SK_RESTRICT cache = fCache->getCache16();
18355853db3cce9539746fe202519a534c85ecdf62creed@google.com    int                 toggle = init_dither_toggle16(x, y);
184589708bf7c706348b763e8277004cb160b202bdbrileya@google.com
185589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    if (fDstToIndexClass != kPerspective_MatrixClass) {
186589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        dstProc(fDstToIndex, SkIntToScalar(x) + SK_ScalarHalf,
187589708bf7c706348b763e8277004cb160b202bdbrileya@google.com                             SkIntToScalar(y) + SK_ScalarHalf, &srcPt);
188589708bf7c706348b763e8277004cb160b202bdbrileya@google.com
189589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        SkScalar sdx = fDstToIndex.getScaleX();
190589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        SkScalar sdy = fDstToIndex.getSkewY();
191589708bf7c706348b763e8277004cb160b202bdbrileya@google.com
192589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        if (fDstToIndexClass == kFixedStepInX_MatrixClass) {
193589708bf7c706348b763e8277004cb160b202bdbrileya@google.com            SkFixed storage[2];
194589708bf7c706348b763e8277004cb160b202bdbrileya@google.com            (void)fDstToIndex.fixedStepInX(SkIntToScalar(y),
195589708bf7c706348b763e8277004cb160b202bdbrileya@google.com                                           &storage[0], &storage[1]);
196589708bf7c706348b763e8277004cb160b202bdbrileya@google.com            sdx = SkFixedToScalar(storage[0]);
197589708bf7c706348b763e8277004cb160b202bdbrileya@google.com            sdy = SkFixedToScalar(storage[1]);
198589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        } else {
199589708bf7c706348b763e8277004cb160b202bdbrileya@google.com            SkASSERT(fDstToIndexClass == kLinear_MatrixClass);
200589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        }
201589708bf7c706348b763e8277004cb160b202bdbrileya@google.com
202589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        RadialShade16Proc shadeProc = shadeSpan16_radial_repeat;
20387fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org        if (SkShader::kClamp_TileMode == radialGradient.fTileMode) {
204589708bf7c706348b763e8277004cb160b202bdbrileya@google.com            shadeProc = shadeSpan16_radial_clamp;
20587fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org        } else if (SkShader::kMirror_TileMode == radialGradient.fTileMode) {
206589708bf7c706348b763e8277004cb160b202bdbrileya@google.com            shadeProc = shadeSpan16_radial_mirror;
207589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        } else {
20887fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org            SkASSERT(SkShader::kRepeat_TileMode == radialGradient.fTileMode);
209589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        }
210589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        (*shadeProc)(srcPt.fX, sdx, srcPt.fY, sdy, dstC,
211589708bf7c706348b763e8277004cb160b202bdbrileya@google.com                     cache, toggle, count);
212589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    } else {    // perspective case
213589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        SkScalar dstX = SkIntToScalar(x);
214589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        SkScalar dstY = SkIntToScalar(y);
215589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        do {
216589708bf7c706348b763e8277004cb160b202bdbrileya@google.com            dstProc(fDstToIndex, dstX, dstY, &srcPt);
217589708bf7c706348b763e8277004cb160b202bdbrileya@google.com            unsigned fi = proc(SkScalarToFixed(srcPt.length()));
218589708bf7c706348b763e8277004cb160b202bdbrileya@google.com            SkASSERT(fi <= 0xFFFF);
219589708bf7c706348b763e8277004cb160b202bdbrileya@google.com
220589708bf7c706348b763e8277004cb160b202bdbrileya@google.com            int index = fi >> (16 - kCache16Bits);
221589708bf7c706348b763e8277004cb160b202bdbrileya@google.com            *dstC++ = cache[toggle + index];
22255853db3cce9539746fe202519a534c85ecdf62creed@google.com            toggle = next_dither_toggle16(toggle);
223589708bf7c706348b763e8277004cb160b202bdbrileya@google.com
224589708bf7c706348b763e8277004cb160b202bdbrileya@google.com            dstX += SK_Scalar1;
225589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        } while (--count != 0);
226589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    }
227589708bf7c706348b763e8277004cb160b202bdbrileya@google.com}
228589708bf7c706348b763e8277004cb160b202bdbrileya@google.com
229fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.comSkShader::BitmapType SkRadialGradient::asABitmap(SkBitmap* bitmap,
230589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    SkMatrix* matrix, SkShader::TileMode* xy) const {
231589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    if (bitmap) {
2321c6d64b78b24083ee9fd7411dac8a4a7e2d03a3crileya@google.com        this->getGradientTableBitmap(bitmap);
233589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    }
234589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    if (matrix) {
2353c2102c2d2cdad328a0d87329e1a973f12775836reed@google.com        matrix->setScale(SkIntToScalar(kCache32Count),
2363c2102c2d2cdad328a0d87329e1a973f12775836reed@google.com                         SkIntToScalar(kCache32Count));
237589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        matrix->preConcat(fPtsToUnit);
238589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    }
239589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    if (xy) {
240589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        xy[0] = fTileMode;
241589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        xy[1] = kClamp_TileMode;
242589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    }
243589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    return kRadial_BitmapType;
244589708bf7c706348b763e8277004cb160b202bdbrileya@google.com}
245589708bf7c706348b763e8277004cb160b202bdbrileya@google.com
246589708bf7c706348b763e8277004cb160b202bdbrileya@google.comSkShader::GradientType SkRadialGradient::asAGradient(GradientInfo* info) const {
247589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    if (info) {
248589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        commonAsAGradient(info);
249589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        info->fPoint[0] = fCenter;
250589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        info->fRadius[0] = fRadius;
251589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    }
252589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    return kRadial_GradientType;
253589708bf7c706348b763e8277004cb160b202bdbrileya@google.com}
254589708bf7c706348b763e8277004cb160b202bdbrileya@google.com
2559fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed#ifdef SK_SUPPORT_LEGACY_DEEPFLATTENING
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}
2619fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed#endif
2629fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed
2639fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reedSkFlattenable* SkRadialGradient::CreateProc(SkReadBuffer& buffer) {
2649fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed    DescriptorScope desc;
2659fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed    if (!desc.unflatten(buffer)) {
2669fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed        return NULL;
2679fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed    }
2689fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed    const SkPoint center = buffer.readPoint();
2699fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed    const SkScalar radius = buffer.readScalar();
2709fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed    return SkGradientShader::CreateRadial(center, radius, desc.fColors, desc.fPos, desc.fCount,
2719fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed                                          desc.fTileMode, desc.fGradFlags, desc.fLocalMatrix);
2729fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed}
273589708bf7c706348b763e8277004cb160b202bdbrileya@google.com
2748b0e8ac5f582de80356019406e2975079bf0829dcommit-bot@chromium.orgvoid SkRadialGradient::flatten(SkWriteBuffer& buffer) const {
275589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    this->INHERITED::flatten(buffer);
276589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    buffer.writePoint(fCenter);
277589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    buffer.writeScalar(fRadius);
278589708bf7c706348b763e8277004cb160b202bdbrileya@google.com}
279589708bf7c706348b763e8277004cb160b202bdbrileya@google.com
280589708bf7c706348b763e8277004cb160b202bdbrileya@google.comnamespace {
281589708bf7c706348b763e8277004cb160b202bdbrileya@google.com
282589708bf7c706348b763e8277004cb160b202bdbrileya@google.cominline bool radial_completely_pinned(int fx, int dx, int fy, int dy) {
283589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    // fast, overly-conservative test: checks unit square instead
284589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    // of unit circle
285589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    bool xClamped = (fx >= SK_FixedHalf && dx >= 0) ||
286589708bf7c706348b763e8277004cb160b202bdbrileya@google.com                    (fx <= -SK_FixedHalf && dx <= 0);
287589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    bool yClamped = (fy >= SK_FixedHalf && dy >= 0) ||
288589708bf7c706348b763e8277004cb160b202bdbrileya@google.com                    (fy <= -SK_FixedHalf && dy <= 0);
289589708bf7c706348b763e8277004cb160b202bdbrileya@google.com
290589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    return xClamped || yClamped;
291589708bf7c706348b763e8277004cb160b202bdbrileya@google.com}
292589708bf7c706348b763e8277004cb160b202bdbrileya@google.com
293589708bf7c706348b763e8277004cb160b202bdbrileya@google.com// Return true if (fx * fy) is always inside the unit circle
294589708bf7c706348b763e8277004cb160b202bdbrileya@google.com// SkPin32 is expensive, but so are all the SkFixedMul in this test,
295589708bf7c706348b763e8277004cb160b202bdbrileya@google.com// so it shouldn't be run if count is small.
296589708bf7c706348b763e8277004cb160b202bdbrileya@google.cominline bool no_need_for_radial_pin(int fx, int dx,
297589708bf7c706348b763e8277004cb160b202bdbrileya@google.com                                          int fy, int dy, int count) {
298589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    SkASSERT(count > 0);
299589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    if (SkAbs32(fx) > 0x7FFF || SkAbs32(fy) > 0x7FFF) {
300589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        return false;
301589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    }
302589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    if (fx*fx + fy*fy > 0x7FFF*0x7FFF) {
303589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        return false;
304589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    }
305589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    fx += (count - 1) * dx;
306589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    fy += (count - 1) * dy;
307589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    if (SkAbs32(fx) > 0x7FFF || SkAbs32(fy) > 0x7FFF) {
308589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        return false;
309589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    }
310589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    return fx*fx + fy*fy <= 0x7FFF*0x7FFF;
311589708bf7c706348b763e8277004cb160b202bdbrileya@google.com}
312589708bf7c706348b763e8277004cb160b202bdbrileya@google.com
313589708bf7c706348b763e8277004cb160b202bdbrileya@google.com#define UNPINNED_RADIAL_STEP \
314589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    fi = (fx * fx + fy * fy) >> (14 + 16 - kSQRT_TABLE_BITS); \
315589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    *dstC++ = cache[toggle + \
316589708bf7c706348b763e8277004cb160b202bdbrileya@google.com                    (sqrt_table[fi] >> SkGradientShaderBase::kSqrt32Shift)]; \
31755853db3cce9539746fe202519a534c85ecdf62creed@google.com    toggle = next_dither_toggle(toggle); \
318589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    fx += dx; \
319589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    fy += dy;
320589708bf7c706348b763e8277004cb160b202bdbrileya@google.com
321589708bf7c706348b763e8277004cb160b202bdbrileya@google.comtypedef void (* RadialShadeProc)(SkScalar sfx, SkScalar sdx,
322589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        SkScalar sfy, SkScalar sdy,
323589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        SkPMColor* dstC, const SkPMColor* cache,
324589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        int count, int toggle);
325589708bf7c706348b763e8277004cb160b202bdbrileya@google.com
326589708bf7c706348b763e8277004cb160b202bdbrileya@google.com// On Linux, this is faster with SkPMColor[] params than SkPMColor* SK_RESTRICT
327589708bf7c706348b763e8277004cb160b202bdbrileya@google.comvoid shadeSpan_radial_clamp(SkScalar sfx, SkScalar sdx,
328589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        SkScalar sfy, SkScalar sdy,
329589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        SkPMColor* SK_RESTRICT dstC, const SkPMColor* SK_RESTRICT cache,
330589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        int count, int toggle) {
331589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    // Floating point seems to be slower than fixed point,
332589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    // even when we have float hardware.
333589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    const uint8_t* SK_RESTRICT sqrt_table = gSqrt8Table;
334589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    SkFixed fx = SkScalarToFixed(sfx) >> 1;
335589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    SkFixed dx = SkScalarToFixed(sdx) >> 1;
336589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    SkFixed fy = SkScalarToFixed(sfy) >> 1;
337589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    SkFixed dy = SkScalarToFixed(sdy) >> 1;
338589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    if ((count > 4) && radial_completely_pinned(fx, dx, fy, dy)) {
3393c2102c2d2cdad328a0d87329e1a973f12775836reed@google.com        unsigned fi = SkGradientShaderBase::kCache32Count - 1;
340589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        sk_memset32_dither(dstC,
341589708bf7c706348b763e8277004cb160b202bdbrileya@google.com            cache[toggle + fi],
34255853db3cce9539746fe202519a534c85ecdf62creed@google.com            cache[next_dither_toggle(toggle) + fi],
343589708bf7c706348b763e8277004cb160b202bdbrileya@google.com            count);
344589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    } else if ((count > 4) &&
345589708bf7c706348b763e8277004cb160b202bdbrileya@google.com               no_need_for_radial_pin(fx, dx, fy, dy, count)) {
346589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        unsigned fi;
347589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        // 4x unroll appears to be no faster than 2x unroll on Linux
348589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        while (count > 1) {
349589708bf7c706348b763e8277004cb160b202bdbrileya@google.com            UNPINNED_RADIAL_STEP;
350589708bf7c706348b763e8277004cb160b202bdbrileya@google.com            UNPINNED_RADIAL_STEP;
351589708bf7c706348b763e8277004cb160b202bdbrileya@google.com            count -= 2;
352589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        }
353589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        if (count) {
354589708bf7c706348b763e8277004cb160b202bdbrileya@google.com            UNPINNED_RADIAL_STEP;
355589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        }
35660040292be58ac553298209fb2e0684a4cb17dccreed@google.com    } else  {
357589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        // Specializing for dy == 0 gains us 25% on Skia benchmarks
358589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        if (dy == 0) {
359589708bf7c706348b763e8277004cb160b202bdbrileya@google.com            unsigned yy = SkPin32(fy, -0xFFFF >> 1, 0xFFFF >> 1);
360589708bf7c706348b763e8277004cb160b202bdbrileya@google.com            yy *= yy;
361589708bf7c706348b763e8277004cb160b202bdbrileya@google.com            do {
362589708bf7c706348b763e8277004cb160b202bdbrileya@google.com                unsigned xx = SkPin32(fx, -0xFFFF >> 1, 0xFFFF >> 1);
363589708bf7c706348b763e8277004cb160b202bdbrileya@google.com                unsigned fi = (xx * xx + yy) >> (14 + 16 - kSQRT_TABLE_BITS);
364589708bf7c706348b763e8277004cb160b202bdbrileya@google.com                fi = SkFastMin32(fi, 0xFFFF >> (16 - kSQRT_TABLE_BITS));
365589708bf7c706348b763e8277004cb160b202bdbrileya@google.com                *dstC++ = cache[toggle + (sqrt_table[fi] >>
366589708bf7c706348b763e8277004cb160b202bdbrileya@google.com                    SkGradientShaderBase::kSqrt32Shift)];
36755853db3cce9539746fe202519a534c85ecdf62creed@google.com                toggle = next_dither_toggle(toggle);
368589708bf7c706348b763e8277004cb160b202bdbrileya@google.com                fx += dx;
369589708bf7c706348b763e8277004cb160b202bdbrileya@google.com            } while (--count != 0);
370589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        } else {
371589708bf7c706348b763e8277004cb160b202bdbrileya@google.com            do {
372589708bf7c706348b763e8277004cb160b202bdbrileya@google.com                unsigned xx = SkPin32(fx, -0xFFFF >> 1, 0xFFFF >> 1);
373589708bf7c706348b763e8277004cb160b202bdbrileya@google.com                unsigned fi = SkPin32(fy, -0xFFFF >> 1, 0xFFFF >> 1);
374589708bf7c706348b763e8277004cb160b202bdbrileya@google.com                fi = (xx * xx + fi * fi) >> (14 + 16 - kSQRT_TABLE_BITS);
375589708bf7c706348b763e8277004cb160b202bdbrileya@google.com                fi = SkFastMin32(fi, 0xFFFF >> (16 - kSQRT_TABLE_BITS));
376589708bf7c706348b763e8277004cb160b202bdbrileya@google.com                *dstC++ = cache[toggle + (sqrt_table[fi] >>
377589708bf7c706348b763e8277004cb160b202bdbrileya@google.com                    SkGradientShaderBase::kSqrt32Shift)];
37855853db3cce9539746fe202519a534c85ecdf62creed@google.com                toggle = next_dither_toggle(toggle);
379589708bf7c706348b763e8277004cb160b202bdbrileya@google.com                fx += dx;
380589708bf7c706348b763e8277004cb160b202bdbrileya@google.com                fy += dy;
381589708bf7c706348b763e8277004cb160b202bdbrileya@google.com            } while (--count != 0);
382589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        }
383589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    }
384589708bf7c706348b763e8277004cb160b202bdbrileya@google.com}
385589708bf7c706348b763e8277004cb160b202bdbrileya@google.com
386589708bf7c706348b763e8277004cb160b202bdbrileya@google.com// Unrolling this loop doesn't seem to help (when float); we're stalling to
387589708bf7c706348b763e8277004cb160b202bdbrileya@google.com// get the results of the sqrt (?), and don't have enough extra registers to
388589708bf7c706348b763e8277004cb160b202bdbrileya@google.com// have many in flight.
38934150b451da7d3c70a2d34e67b0285cb36932d45commit-bot@chromium.orgtemplate <SkFixed (*TileProc)(SkFixed)>
39034150b451da7d3c70a2d34e67b0285cb36932d45commit-bot@chromium.orgvoid shadeSpan_radial(SkScalar fx, SkScalar dx, SkScalar fy, SkScalar dy,
39134150b451da7d3c70a2d34e67b0285cb36932d45commit-bot@chromium.org                      SkPMColor* SK_RESTRICT dstC, const SkPMColor* SK_RESTRICT cache,
39234150b451da7d3c70a2d34e67b0285cb36932d45commit-bot@chromium.org                      int count, int toggle) {
393589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    do {
39434150b451da7d3c70a2d34e67b0285cb36932d45commit-bot@chromium.org        const SkFixed dist = SkFloatToFixed(sk_float_sqrt(fx*fx + fy*fy));
39534150b451da7d3c70a2d34e67b0285cb36932d45commit-bot@chromium.org        const unsigned fi = TileProc(dist);
396589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        SkASSERT(fi <= 0xFFFF);
397589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        *dstC++ = cache[toggle + (fi >> SkGradientShaderBase::kCache32Shift)];
39855853db3cce9539746fe202519a534c85ecdf62creed@google.com        toggle = next_dither_toggle(toggle);
399589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        fx += dx;
400589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        fy += dy;
401589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    } while (--count != 0);
402589708bf7c706348b763e8277004cb160b202bdbrileya@google.com}
40334150b451da7d3c70a2d34e67b0285cb36932d45commit-bot@chromium.org
40434150b451da7d3c70a2d34e67b0285cb36932d45commit-bot@chromium.orgvoid shadeSpan_radial_mirror(SkScalar fx, SkScalar dx, SkScalar fy, SkScalar dy,
40534150b451da7d3c70a2d34e67b0285cb36932d45commit-bot@chromium.org                             SkPMColor* SK_RESTRICT dstC, const SkPMColor* SK_RESTRICT cache,
40634150b451da7d3c70a2d34e67b0285cb36932d45commit-bot@chromium.org                             int count, int toggle) {
40734150b451da7d3c70a2d34e67b0285cb36932d45commit-bot@chromium.org    shadeSpan_radial<mirror_tileproc_nonstatic>(fx, dx, fy, dy, dstC, cache, count, toggle);
40834150b451da7d3c70a2d34e67b0285cb36932d45commit-bot@chromium.org}
40934150b451da7d3c70a2d34e67b0285cb36932d45commit-bot@chromium.org
41034150b451da7d3c70a2d34e67b0285cb36932d45commit-bot@chromium.orgvoid shadeSpan_radial_repeat(SkScalar fx, SkScalar dx, SkScalar fy, SkScalar dy,
41134150b451da7d3c70a2d34e67b0285cb36932d45commit-bot@chromium.org                             SkPMColor* SK_RESTRICT dstC, const SkPMColor* SK_RESTRICT cache,
41234150b451da7d3c70a2d34e67b0285cb36932d45commit-bot@chromium.org                             int count, int toggle) {
41334150b451da7d3c70a2d34e67b0285cb36932d45commit-bot@chromium.org    shadeSpan_radial<repeat_tileproc_nonstatic>(fx, dx, fy, dy, dstC, cache, count, toggle);
414589708bf7c706348b763e8277004cb160b202bdbrileya@google.com}
415589708bf7c706348b763e8277004cb160b202bdbrileya@google.com
41634150b451da7d3c70a2d34e67b0285cb36932d45commit-bot@chromium.org}  // namespace
41734150b451da7d3c70a2d34e67b0285cb36932d45commit-bot@chromium.org
41887fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.orgvoid SkRadialGradient::RadialGradientContext::shadeSpan(int x, int y,
41987fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org                                                        SkPMColor* SK_RESTRICT dstC, int count) {
420589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    SkASSERT(count > 0);
421589708bf7c706348b763e8277004cb160b202bdbrileya@google.com
42287fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org    const SkRadialGradient& radialGradient = static_cast<const SkRadialGradient&>(fShader);
42387fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org
424589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    SkPoint             srcPt;
425589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    SkMatrix::MapXYProc dstProc = fDstToIndexProc;
42687fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org    TileProc            proc = radialGradient.fTileProc;
42787fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org    const SkPMColor* SK_RESTRICT cache = fCache->getCache32();
42855853db3cce9539746fe202519a534c85ecdf62creed@google.com    int toggle = init_dither_toggle(x, y);
429589708bf7c706348b763e8277004cb160b202bdbrileya@google.com
430589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    if (fDstToIndexClass != kPerspective_MatrixClass) {
431589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        dstProc(fDstToIndex, SkIntToScalar(x) + SK_ScalarHalf,
432589708bf7c706348b763e8277004cb160b202bdbrileya@google.com                             SkIntToScalar(y) + SK_ScalarHalf, &srcPt);
433589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        SkScalar sdx = fDstToIndex.getScaleX();
434589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        SkScalar sdy = fDstToIndex.getSkewY();
435589708bf7c706348b763e8277004cb160b202bdbrileya@google.com
436589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        if (fDstToIndexClass == kFixedStepInX_MatrixClass) {
437589708bf7c706348b763e8277004cb160b202bdbrileya@google.com            SkFixed storage[2];
438589708bf7c706348b763e8277004cb160b202bdbrileya@google.com            (void)fDstToIndex.fixedStepInX(SkIntToScalar(y),
439589708bf7c706348b763e8277004cb160b202bdbrileya@google.com                                           &storage[0], &storage[1]);
440589708bf7c706348b763e8277004cb160b202bdbrileya@google.com            sdx = SkFixedToScalar(storage[0]);
441589708bf7c706348b763e8277004cb160b202bdbrileya@google.com            sdy = SkFixedToScalar(storage[1]);
442589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        } else {
443589708bf7c706348b763e8277004cb160b202bdbrileya@google.com            SkASSERT(fDstToIndexClass == kLinear_MatrixClass);
444589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        }
445589708bf7c706348b763e8277004cb160b202bdbrileya@google.com
446589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        RadialShadeProc shadeProc = shadeSpan_radial_repeat;
44787fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org        if (SkShader::kClamp_TileMode == radialGradient.fTileMode) {
448589708bf7c706348b763e8277004cb160b202bdbrileya@google.com            shadeProc = shadeSpan_radial_clamp;
44987fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org        } else if (SkShader::kMirror_TileMode == radialGradient.fTileMode) {
450589708bf7c706348b763e8277004cb160b202bdbrileya@google.com            shadeProc = shadeSpan_radial_mirror;
451589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        } else {
45287fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org            SkASSERT(SkShader::kRepeat_TileMode == radialGradient.fTileMode);
453589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        }
454589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        (*shadeProc)(srcPt.fX, sdx, srcPt.fY, sdy, dstC, cache, count, toggle);
455589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    } else {    // perspective case
456589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        SkScalar dstX = SkIntToScalar(x);
457589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        SkScalar dstY = SkIntToScalar(y);
458589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        do {
459589708bf7c706348b763e8277004cb160b202bdbrileya@google.com            dstProc(fDstToIndex, dstX, dstY, &srcPt);
460589708bf7c706348b763e8277004cb160b202bdbrileya@google.com            unsigned fi = proc(SkScalarToFixed(srcPt.length()));
461589708bf7c706348b763e8277004cb160b202bdbrileya@google.com            SkASSERT(fi <= 0xFFFF);
462589708bf7c706348b763e8277004cb160b202bdbrileya@google.com            *dstC++ = cache[fi >> SkGradientShaderBase::kCache32Shift];
463589708bf7c706348b763e8277004cb160b202bdbrileya@google.com            dstX += SK_Scalar1;
464589708bf7c706348b763e8277004cb160b202bdbrileya@google.com        } while (--count != 0);
465589708bf7c706348b763e8277004cb160b202bdbrileya@google.com    }
466589708bf7c706348b763e8277004cb160b202bdbrileya@google.com}
467589708bf7c706348b763e8277004cb160b202bdbrileya@google.com
468d7cc651b8da11d52ae90e910b948f5e2d15daaf9rileya@google.com/////////////////////////////////////////////////////////////////////
469d7cc651b8da11d52ae90e910b948f5e2d15daaf9rileya@google.com
470cf8fb1f6f03fc77f9927564f9ef9abeeeec508d2bsalomon@google.com#if SK_SUPPORT_GPU
471cf8fb1f6f03fc77f9927564f9ef9abeeeec508d2bsalomon@google.com
472b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt#include "GrTBackendProcessorFactory.h"
47330ba436f04e61d4505fb854d5fc56079636e0788joshualitt#include "gl/builders/GrGLProgramBuilder.h"
4749de5b514d38c5b36066bcdc14fba2f7e5196d372dandov#include "SkGr.h"
4752eaaefd7e6a58339b3f93333f1e9cc92252cc303bsalomon@google.com
4760707c29413a5a3cc1c2d14b8c65b3692af5c7411bsalomon@google.comclass GrGLRadialGradient : public GrGLGradientEffect {
477d7cc651b8da11d52ae90e910b948f5e2d15daaf9rileya@google.compublic:
478d7cc651b8da11d52ae90e910b948f5e2d15daaf9rileya@google.com
479b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt    GrGLRadialGradient(const GrBackendProcessorFactory& factory,
480b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt                       const GrProcessor&) : INHERITED (factory) { }
481d7cc651b8da11d52ae90e910b948f5e2d15daaf9rileya@google.com    virtual ~GrGLRadialGradient() { }
482d7cc651b8da11d52ae90e910b948f5e2d15daaf9rileya@google.com
48330ba436f04e61d4505fb854d5fc56079636e0788joshualitt    virtual void emitCode(GrGLProgramBuilder*,
484b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt                          const GrFragmentProcessor&,
485b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt                          const GrProcessorKey&,
486f78df33efc72167f94da1b0476c9a86ba18a5f2cbsalomon@google.com                          const char* outputColor,
487f78df33efc72167f94da1b0476c9a86ba18a5f2cbsalomon@google.com                          const char* inputColor,
48877af6805e5faea1e2a5c0220098aec9082f3a6e5bsalomon@google.com                          const TransformedCoordsArray&,
489f78df33efc72167f94da1b0476c9a86ba18a5f2cbsalomon@google.com                          const TextureSamplerArray&) SK_OVERRIDE;
490d7cc651b8da11d52ae90e910b948f5e2d15daaf9rileya@google.com
491b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt    static void GenKey(const GrProcessor& processor, const GrGLCaps&, GrProcessorKeyBuilder* b) {
492b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt        b->add32(GenBaseGradientKey(processor));
493d8b5faca043100d7a1e4594b4d10e462532af390bsalomon@google.com    }
494d7cc651b8da11d52ae90e910b948f5e2d15daaf9rileya@google.com
495d7cc651b8da11d52ae90e910b948f5e2d15daaf9rileya@google.comprivate:
496d7cc651b8da11d52ae90e910b948f5e2d15daaf9rileya@google.com
4970707c29413a5a3cc1c2d14b8c65b3692af5c7411bsalomon@google.com    typedef GrGLGradientEffect INHERITED;
498d7cc651b8da11d52ae90e910b948f5e2d15daaf9rileya@google.com
499d7cc651b8da11d52ae90e910b948f5e2d15daaf9rileya@google.com};
500d7cc651b8da11d52ae90e910b948f5e2d15daaf9rileya@google.com
50198e8b6de04e4c20451fbe3353645e3e384a76550rileya@google.com/////////////////////////////////////////////////////////////////////
50298e8b6de04e4c20451fbe3353645e3e384a76550rileya@google.com
50398e8b6de04e4c20451fbe3353645e3e384a76550rileya@google.comclass GrRadialGradient : public GrGradientEffect {
50498e8b6de04e4c20451fbe3353645e3e384a76550rileya@google.compublic:
505b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt    static GrFragmentProcessor* Create(GrContext* ctx,
506b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt                                       const SkRadialGradient& shader,
507b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt                                       const SkMatrix& matrix,
508b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt                                       SkShader::TileMode tm) {
50955fad7af61c21d502acb9891d631e8aa29e3628cbsalomon        return SkNEW_ARGS(GrRadialGradient, (ctx, shader, matrix, tm));
51098e8b6de04e4c20451fbe3353645e3e384a76550rileya@google.com    }
51198e8b6de04e4c20451fbe3353645e3e384a76550rileya@google.com
51298e8b6de04e4c20451fbe3353645e3e384a76550rileya@google.com    virtual ~GrRadialGradient() { }
51398e8b6de04e4c20451fbe3353645e3e384a76550rileya@google.com
51498e8b6de04e4c20451fbe3353645e3e384a76550rileya@google.com    static const char* Name() { return "Radial Gradient"; }
515b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt    virtual const GrBackendFragmentProcessorFactory& getFactory() const SK_OVERRIDE {
516b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt        return GrTBackendFragmentProcessorFactory<GrRadialGradient>::getInstance();
51798e8b6de04e4c20451fbe3353645e3e384a76550rileya@google.com    }
51898e8b6de04e4c20451fbe3353645e3e384a76550rileya@google.com
519b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt    typedef GrGLRadialGradient GLProcessor;
52098e8b6de04e4c20451fbe3353645e3e384a76550rileya@google.com
52198e8b6de04e4c20451fbe3353645e3e384a76550rileya@google.comprivate:
5220ac6af49975c54c2debf41e9200af416ecd2d973bsalomon@google.com    GrRadialGradient(GrContext* ctx,
5230ac6af49975c54c2debf41e9200af416ecd2d973bsalomon@google.com                     const SkRadialGradient& shader,
5240ac6af49975c54c2debf41e9200af416ecd2d973bsalomon@google.com                     const SkMatrix& matrix,
5250ac6af49975c54c2debf41e9200af416ecd2d973bsalomon@google.com                     SkShader::TileMode tm)
5260ac6af49975c54c2debf41e9200af416ecd2d973bsalomon@google.com        : INHERITED(ctx, shader, matrix, tm) {
5270ac6af49975c54c2debf41e9200af416ecd2d973bsalomon@google.com    }
5280ac6af49975c54c2debf41e9200af416ecd2d973bsalomon@google.com
529b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt    GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
53098e8b6de04e4c20451fbe3353645e3e384a76550rileya@google.com
53198e8b6de04e4c20451fbe3353645e3e384a76550rileya@google.com    typedef GrGradientEffect INHERITED;
53298e8b6de04e4c20451fbe3353645e3e384a76550rileya@google.com};
53398e8b6de04e4c20451fbe3353645e3e384a76550rileya@google.com
53498e8b6de04e4c20451fbe3353645e3e384a76550rileya@google.com/////////////////////////////////////////////////////////////////////
53598e8b6de04e4c20451fbe3353645e3e384a76550rileya@google.com
536b0a8a377f832c59cee939ad721e1f87d378b7142joshualittGR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrRadialGradient);
537d472620458e2383e6dd949f4e1aaf61160717ffebsalomon@google.com
538b0a8a377f832c59cee939ad721e1f87d378b7142joshualittGrFragmentProcessor* GrRadialGradient::TestCreate(SkRandom* random,
539b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt                                                  GrContext* context,
540b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt                                                  const GrDrawTargetCaps&,
541b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt                                                  GrTexture**) {
542d472620458e2383e6dd949f4e1aaf61160717ffebsalomon@google.com    SkPoint center = {random->nextUScalar1(), random->nextUScalar1()};
543d472620458e2383e6dd949f4e1aaf61160717ffebsalomon@google.com    SkScalar radius = random->nextUScalar1();
544d472620458e2383e6dd949f4e1aaf61160717ffebsalomon@google.com
545d472620458e2383e6dd949f4e1aaf61160717ffebsalomon@google.com    SkColor colors[kMaxRandomGradientColors];
546d472620458e2383e6dd949f4e1aaf61160717ffebsalomon@google.com    SkScalar stopsArray[kMaxRandomGradientColors];
547d472620458e2383e6dd949f4e1aaf61160717ffebsalomon@google.com    SkScalar* stops = stopsArray;
548d472620458e2383e6dd949f4e1aaf61160717ffebsalomon@google.com    SkShader::TileMode tm;
549d472620458e2383e6dd949f4e1aaf61160717ffebsalomon@google.com    int colorCount = RandomGradientParams(random, colors, &stops, &tm);
550d472620458e2383e6dd949f4e1aaf61160717ffebsalomon@google.com    SkAutoTUnref<SkShader> shader(SkGradientShader::CreateRadial(center, radius,
551d472620458e2383e6dd949f4e1aaf61160717ffebsalomon@google.com                                                                 colors, stops, colorCount,
552d472620458e2383e6dd949f4e1aaf61160717ffebsalomon@google.com                                                                 tm));
553e197cbf9a3e66bab926bc5e51962752dad5221a0bsalomon@google.com    SkPaint paint;
55483d081ae1d731b5039e99823620f5e287542ee39bsalomon    GrColor paintColor;
555b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt    GrFragmentProcessor* fp;
556b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt    SkAssertResult(shader->asFragmentProcessor(context, paint, NULL, &paintColor, &fp));
557b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt    return fp;
558d472620458e2383e6dd949f4e1aaf61160717ffebsalomon@google.com}
559d472620458e2383e6dd949f4e1aaf61160717ffebsalomon@google.com
560d472620458e2383e6dd949f4e1aaf61160717ffebsalomon@google.com/////////////////////////////////////////////////////////////////////
561d472620458e2383e6dd949f4e1aaf61160717ffebsalomon@google.com
56230ba436f04e61d4505fb854d5fc56079636e0788joshualittvoid GrGLRadialGradient::emitCode(GrGLProgramBuilder* builder,
563b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt                                  const GrFragmentProcessor&,
564b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt                                  const GrProcessorKey& key,
565f78df33efc72167f94da1b0476c9a86ba18a5f2cbsalomon@google.com                                  const char* outputColor,
566f78df33efc72167f94da1b0476c9a86ba18a5f2cbsalomon@google.com                                  const char* inputColor,
56777af6805e5faea1e2a5c0220098aec9082f3a6e5bsalomon@google.com                                  const TransformedCoordsArray& coords,
568f78df33efc72167f94da1b0476c9a86ba18a5f2cbsalomon@google.com                                  const TextureSamplerArray& samplers) {
56963e99f7a03b2ac90ae7a00232674fd39c0bdcc68bsalomon    uint32_t baseKey = key.get32(0);
57063e99f7a03b2ac90ae7a00232674fd39c0bdcc68bsalomon    this->emitUniforms(builder, baseKey);
571d8b5faca043100d7a1e4594b4d10e462532af390bsalomon@google.com    SkString t("length(");
57230ba436f04e61d4505fb854d5fc56079636e0788joshualitt    t.append(builder->getFragmentShaderBuilder()->ensureFSCoords2D(coords, 0));
573d8b5faca043100d7a1e4594b4d10e462532af390bsalomon@google.com    t.append(")");
57463e99f7a03b2ac90ae7a00232674fd39c0bdcc68bsalomon    this->emitColor(builder, t.c_str(), baseKey, outputColor, inputColor, samplers);
575d7cc651b8da11d52ae90e910b948f5e2d15daaf9rileya@google.com}
576d7cc651b8da11d52ae90e910b948f5e2d15daaf9rileya@google.com
577d7cc651b8da11d52ae90e910b948f5e2d15daaf9rileya@google.com/////////////////////////////////////////////////////////////////////
578d7cc651b8da11d52ae90e910b948f5e2d15daaf9rileya@google.com
579b0a8a377f832c59cee939ad721e1f87d378b7142joshualittbool SkRadialGradient::asFragmentProcessor(GrContext* context, const SkPaint& paint,
580b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt                                           const SkMatrix* localMatrix, GrColor* paintColor,
581b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt                                           GrFragmentProcessor** fp) const {
58249f085dddff10473b6ebf832a974288300224e60bsalomon    SkASSERT(context);
5839de5b514d38c5b36066bcdc14fba2f7e5196d372dandov
584dfdb7e5240276493077b7c6e1f3cc8b8a0e195babsalomon@google.com    SkMatrix matrix;
585f94b3a4cebd4adab09c40ebe23c02a615e10c394bsalomon@google.com    if (!this->getLocalMatrix().invert(&matrix)) {
5869de5b514d38c5b36066bcdc14fba2f7e5196d372dandov        return false;
587dfdb7e5240276493077b7c6e1f3cc8b8a0e195babsalomon@google.com    }
58896fb7489ba46909c3f81bb2d94755e7d4ccb5fadcommit-bot@chromium.org    if (localMatrix) {
58996fb7489ba46909c3f81bb2d94755e7d4ccb5fadcommit-bot@chromium.org        SkMatrix inv;
59096fb7489ba46909c3f81bb2d94755e7d4ccb5fadcommit-bot@chromium.org        if (!localMatrix->invert(&inv)) {
5919de5b514d38c5b36066bcdc14fba2f7e5196d372dandov            return false;
59296fb7489ba46909c3f81bb2d94755e7d4ccb5fadcommit-bot@chromium.org        }
59396fb7489ba46909c3f81bb2d94755e7d4ccb5fadcommit-bot@chromium.org        matrix.postConcat(inv);
59496fb7489ba46909c3f81bb2d94755e7d4ccb5fadcommit-bot@chromium.org    }
595f94b3a4cebd4adab09c40ebe23c02a615e10c394bsalomon@google.com    matrix.postConcat(fPtsToUnit);
5969de5b514d38c5b36066bcdc14fba2f7e5196d372dandov
59783d081ae1d731b5039e99823620f5e287542ee39bsalomon    *paintColor = SkColor2GrColorJustAlpha(paint.getColor());
598b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt    *fp = GrRadialGradient::Create(context, *this, matrix, fTileMode);
5999de5b514d38c5b36066bcdc14fba2f7e5196d372dandov
6009de5b514d38c5b36066bcdc14fba2f7e5196d372dandov    return true;
601d7cc651b8da11d52ae90e910b948f5e2d15daaf9rileya@google.com}
602d7cc651b8da11d52ae90e910b948f5e2d15daaf9rileya@google.com
603cf8fb1f6f03fc77f9927564f9ef9abeeeec508d2bsalomon@google.com#else
604cf8fb1f6f03fc77f9927564f9ef9abeeeec508d2bsalomon@google.com
605b0a8a377f832c59cee939ad721e1f87d378b7142joshualittbool SkRadialGradient::asFragmentProcessor(GrContext*, const SkPaint&, const SkMatrix*, GrColor*,
606b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt                                           GrFragmentProcessor**) const {
607cf8fb1f6f03fc77f9927564f9ef9abeeeec508d2bsalomon@google.com    SkDEBUGFAIL("Should not call in GPU-less build");
6089de5b514d38c5b36066bcdc14fba2f7e5196d372dandov    return false;
609cf8fb1f6f03fc77f9927564f9ef9abeeeec508d2bsalomon@google.com}
610cf8fb1f6f03fc77f9927564f9ef9abeeeec508d2bsalomon@google.com
611cf8fb1f6f03fc77f9927564f9ef9abeeeec508d2bsalomon@google.com#endif
61276f9e938df0b5826fd4c80b854ceafaf385cfbe1robertphillips@google.com
6130f10f7bf1fb43ca6346dc220a076773b1f19a367commit-bot@chromium.org#ifndef SK_IGNORE_TO_STRING
61476f9e938df0b5826fd4c80b854ceafaf385cfbe1robertphillips@google.comvoid SkRadialGradient::toString(SkString* str) const {
61576f9e938df0b5826fd4c80b854ceafaf385cfbe1robertphillips@google.com    str->append("SkRadialGradient: (");
616ff21c2e0ae23da0f4742b47d4d37969a2a18bd99skia.committer@gmail.com
61776f9e938df0b5826fd4c80b854ceafaf385cfbe1robertphillips@google.com    str->append("center: (");
61876f9e938df0b5826fd4c80b854ceafaf385cfbe1robertphillips@google.com    str->appendScalar(fCenter.fX);
61976f9e938df0b5826fd4c80b854ceafaf385cfbe1robertphillips@google.com    str->append(", ");
62076f9e938df0b5826fd4c80b854ceafaf385cfbe1robertphillips@google.com    str->appendScalar(fCenter.fY);
62176f9e938df0b5826fd4c80b854ceafaf385cfbe1robertphillips@google.com    str->append(") radius: ");
62276f9e938df0b5826fd4c80b854ceafaf385cfbe1robertphillips@google.com    str->appendScalar(fRadius);
62376f9e938df0b5826fd4c80b854ceafaf385cfbe1robertphillips@google.com    str->append(" ");
62476f9e938df0b5826fd4c80b854ceafaf385cfbe1robertphillips@google.com
62576f9e938df0b5826fd4c80b854ceafaf385cfbe1robertphillips@google.com    this->INHERITED::toString(str);
62676f9e938df0b5826fd4c80b854ceafaf385cfbe1robertphillips@google.com
62776f9e938df0b5826fd4c80b854ceafaf385cfbe1robertphillips@google.com    str->append(")");
62876f9e938df0b5826fd4c80b854ceafaf385cfbe1robertphillips@google.com}
62976f9e938df0b5826fd4c80b854ceafaf385cfbe1robertphillips@google.com#endif
630