1589708bf7c706348b763e8277004cb160b202bdbrileya@google.com/* 2589708bf7c706348b763e8277004cb160b202bdbrileya@google.com * Copyright 2012 Google Inc. 3589708bf7c706348b763e8277004cb160b202bdbrileya@google.com * 4589708bf7c706348b763e8277004cb160b202bdbrileya@google.com * Use of this source code is governed by a BSD-style license that can be 5589708bf7c706348b763e8277004cb160b202bdbrileya@google.com * found in the LICENSE file. 6589708bf7c706348b763e8277004cb160b202bdbrileya@google.com */ 7589708bf7c706348b763e8277004cb160b202bdbrileya@google.com 8589708bf7c706348b763e8277004cb160b202bdbrileya@google.com#include "SkTwoPointConicalGradient.h" 9aa64fbfd349789f27b3cc35c1968d9dc0612cf8ecommit-bot@chromium.org#include "SkTwoPointConicalGradient_gpu.h" 10aa64fbfd349789f27b3cc35c1968d9dc0612cf8ecommit-bot@chromium.org 1187fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.orgstruct TwoPtRadialContext { 1287fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org const TwoPtRadial& fRec; 1387fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org float fRelX, fRelY; 1487fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org const float fIncX, fIncY; 1587fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org float fB; 1687fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org const float fDB; 1787fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org 1887fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org TwoPtRadialContext(const TwoPtRadial& rec, SkScalar fx, SkScalar fy, 1987fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org SkScalar dfx, SkScalar dfy); 2087fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org SkFixed nextT(); 2187fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org}; 2287fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org 23589708bf7c706348b763e8277004cb160b202bdbrileya@google.comstatic int valid_divide(float numer, float denom, float* ratio) { 24589708bf7c706348b763e8277004cb160b202bdbrileya@google.com SkASSERT(ratio); 25589708bf7c706348b763e8277004cb160b202bdbrileya@google.com if (0 == denom) { 26589708bf7c706348b763e8277004cb160b202bdbrileya@google.com return 0; 27589708bf7c706348b763e8277004cb160b202bdbrileya@google.com } 28589708bf7c706348b763e8277004cb160b202bdbrileya@google.com *ratio = numer / denom; 29589708bf7c706348b763e8277004cb160b202bdbrileya@google.com return 1; 30589708bf7c706348b763e8277004cb160b202bdbrileya@google.com} 31589708bf7c706348b763e8277004cb160b202bdbrileya@google.com 32589708bf7c706348b763e8277004cb160b202bdbrileya@google.com// Return the number of distinct real roots, and write them into roots[] in 33589708bf7c706348b763e8277004cb160b202bdbrileya@google.com// ascending order 3444d83c1e81b0555efa94f78e2a53b862208cdd06commit-bot@chromium.orgstatic int find_quad_roots(float A, float B, float C, float roots[2], bool descendingOrder = false) { 35589708bf7c706348b763e8277004cb160b202bdbrileya@google.com SkASSERT(roots); 36fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com 37589708bf7c706348b763e8277004cb160b202bdbrileya@google.com if (A == 0) { 38589708bf7c706348b763e8277004cb160b202bdbrileya@google.com return valid_divide(-C, B, roots); 39589708bf7c706348b763e8277004cb160b202bdbrileya@google.com } 40fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com 41589708bf7c706348b763e8277004cb160b202bdbrileya@google.com float R = B*B - 4*A*C; 42589708bf7c706348b763e8277004cb160b202bdbrileya@google.com if (R < 0) { 43589708bf7c706348b763e8277004cb160b202bdbrileya@google.com return 0; 44589708bf7c706348b763e8277004cb160b202bdbrileya@google.com } 45589708bf7c706348b763e8277004cb160b202bdbrileya@google.com R = sk_float_sqrt(R); 46589708bf7c706348b763e8277004cb160b202bdbrileya@google.com 47589708bf7c706348b763e8277004cb160b202bdbrileya@google.com#if 1 48589708bf7c706348b763e8277004cb160b202bdbrileya@google.com float Q = B; 49589708bf7c706348b763e8277004cb160b202bdbrileya@google.com if (Q < 0) { 50589708bf7c706348b763e8277004cb160b202bdbrileya@google.com Q -= R; 51589708bf7c706348b763e8277004cb160b202bdbrileya@google.com } else { 52589708bf7c706348b763e8277004cb160b202bdbrileya@google.com Q += R; 53589708bf7c706348b763e8277004cb160b202bdbrileya@google.com } 54589708bf7c706348b763e8277004cb160b202bdbrileya@google.com#else 55589708bf7c706348b763e8277004cb160b202bdbrileya@google.com // on 10.6 this was much slower than the above branch :( 56589708bf7c706348b763e8277004cb160b202bdbrileya@google.com float Q = B + copysignf(R, B); 57589708bf7c706348b763e8277004cb160b202bdbrileya@google.com#endif 58589708bf7c706348b763e8277004cb160b202bdbrileya@google.com Q *= -0.5f; 59589708bf7c706348b763e8277004cb160b202bdbrileya@google.com if (0 == Q) { 60589708bf7c706348b763e8277004cb160b202bdbrileya@google.com roots[0] = 0; 61589708bf7c706348b763e8277004cb160b202bdbrileya@google.com return 1; 62589708bf7c706348b763e8277004cb160b202bdbrileya@google.com } 63589708bf7c706348b763e8277004cb160b202bdbrileya@google.com 64589708bf7c706348b763e8277004cb160b202bdbrileya@google.com float r0 = Q / A; 65589708bf7c706348b763e8277004cb160b202bdbrileya@google.com float r1 = C / Q; 66589708bf7c706348b763e8277004cb160b202bdbrileya@google.com roots[0] = r0 < r1 ? r0 : r1; 67589708bf7c706348b763e8277004cb160b202bdbrileya@google.com roots[1] = r0 > r1 ? r0 : r1; 6844d83c1e81b0555efa94f78e2a53b862208cdd06commit-bot@chromium.org if (descendingOrder) { 6944d83c1e81b0555efa94f78e2a53b862208cdd06commit-bot@chromium.org SkTSwap(roots[0], roots[1]); 7044d83c1e81b0555efa94f78e2a53b862208cdd06commit-bot@chromium.org } 71589708bf7c706348b763e8277004cb160b202bdbrileya@google.com return 2; 72589708bf7c706348b763e8277004cb160b202bdbrileya@google.com} 73589708bf7c706348b763e8277004cb160b202bdbrileya@google.com 74589708bf7c706348b763e8277004cb160b202bdbrileya@google.comstatic float lerp(float x, float dx, float t) { 75589708bf7c706348b763e8277004cb160b202bdbrileya@google.com return x + t * dx; 76589708bf7c706348b763e8277004cb160b202bdbrileya@google.com} 77589708bf7c706348b763e8277004cb160b202bdbrileya@google.com 78589708bf7c706348b763e8277004cb160b202bdbrileya@google.comstatic float sqr(float x) { return x * x; } 79589708bf7c706348b763e8277004cb160b202bdbrileya@google.com 80589708bf7c706348b763e8277004cb160b202bdbrileya@google.comvoid TwoPtRadial::init(const SkPoint& center0, SkScalar rad0, 8144d83c1e81b0555efa94f78e2a53b862208cdd06commit-bot@chromium.org const SkPoint& center1, SkScalar rad1, 8244d83c1e81b0555efa94f78e2a53b862208cdd06commit-bot@chromium.org bool flipped) { 83589708bf7c706348b763e8277004cb160b202bdbrileya@google.com fCenterX = SkScalarToFloat(center0.fX); 84589708bf7c706348b763e8277004cb160b202bdbrileya@google.com fCenterY = SkScalarToFloat(center0.fY); 85589708bf7c706348b763e8277004cb160b202bdbrileya@google.com fDCenterX = SkScalarToFloat(center1.fX) - fCenterX; 86589708bf7c706348b763e8277004cb160b202bdbrileya@google.com fDCenterY = SkScalarToFloat(center1.fY) - fCenterY; 87589708bf7c706348b763e8277004cb160b202bdbrileya@google.com fRadius = SkScalarToFloat(rad0); 88589708bf7c706348b763e8277004cb160b202bdbrileya@google.com fDRadius = SkScalarToFloat(rad1) - fRadius; 89589708bf7c706348b763e8277004cb160b202bdbrileya@google.com 90589708bf7c706348b763e8277004cb160b202bdbrileya@google.com fA = sqr(fDCenterX) + sqr(fDCenterY) - sqr(fDRadius); 91589708bf7c706348b763e8277004cb160b202bdbrileya@google.com fRadius2 = sqr(fRadius); 92589708bf7c706348b763e8277004cb160b202bdbrileya@google.com fRDR = fRadius * fDRadius; 9344d83c1e81b0555efa94f78e2a53b862208cdd06commit-bot@chromium.org 9444d83c1e81b0555efa94f78e2a53b862208cdd06commit-bot@chromium.org fFlipped = flipped; 95589708bf7c706348b763e8277004cb160b202bdbrileya@google.com} 96589708bf7c706348b763e8277004cb160b202bdbrileya@google.com 9787fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.orgTwoPtRadialContext::TwoPtRadialContext(const TwoPtRadial& rec, SkScalar fx, SkScalar fy, 9887fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org SkScalar dfx, SkScalar dfy) 9987fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org : fRec(rec) 10087fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org , fRelX(SkScalarToFloat(fx) - rec.fCenterX) 10187fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org , fRelY(SkScalarToFloat(fy) - rec.fCenterY) 10287fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org , fIncX(SkScalarToFloat(dfx)) 10387fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org , fIncY(SkScalarToFloat(dfy)) 10487fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org , fB(-2 * (rec.fDCenterX * fRelX + rec.fDCenterY * fRelY + rec.fRDR)) 10587fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org , fDB(-2 * (rec.fDCenterX * fIncX + rec.fDCenterY * fIncY)) {} 10687fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org 10787fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.orgSkFixed TwoPtRadialContext::nextT() { 108589708bf7c706348b763e8277004cb160b202bdbrileya@google.com float roots[2]; 109fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com 11087fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org float C = sqr(fRelX) + sqr(fRelY) - fRec.fRadius2; 11187fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org int countRoots = find_quad_roots(fRec.fA, fB, C, roots, fRec.fFlipped); 112589708bf7c706348b763e8277004cb160b202bdbrileya@google.com 113589708bf7c706348b763e8277004cb160b202bdbrileya@google.com fRelX += fIncX; 114589708bf7c706348b763e8277004cb160b202bdbrileya@google.com fRelY += fIncY; 115589708bf7c706348b763e8277004cb160b202bdbrileya@google.com fB += fDB; 116589708bf7c706348b763e8277004cb160b202bdbrileya@google.com 117589708bf7c706348b763e8277004cb160b202bdbrileya@google.com if (0 == countRoots) { 11887fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org return TwoPtRadial::kDontDrawT; 119589708bf7c706348b763e8277004cb160b202bdbrileya@google.com } 120589708bf7c706348b763e8277004cb160b202bdbrileya@google.com 121589708bf7c706348b763e8277004cb160b202bdbrileya@google.com // Prefer the bigger t value if both give a radius(t) > 0 122589708bf7c706348b763e8277004cb160b202bdbrileya@google.com // find_quad_roots returns the values sorted, so we start with the last 123589708bf7c706348b763e8277004cb160b202bdbrileya@google.com float t = roots[countRoots - 1]; 12487fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org float r = lerp(fRec.fRadius, fRec.fDRadius, t); 125589708bf7c706348b763e8277004cb160b202bdbrileya@google.com if (r <= 0) { 126589708bf7c706348b763e8277004cb160b202bdbrileya@google.com t = roots[0]; // might be the same as roots[countRoots-1] 12787fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org r = lerp(fRec.fRadius, fRec.fDRadius, t); 128589708bf7c706348b763e8277004cb160b202bdbrileya@google.com if (r <= 0) { 12987fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org return TwoPtRadial::kDontDrawT; 130589708bf7c706348b763e8277004cb160b202bdbrileya@google.com } 131589708bf7c706348b763e8277004cb160b202bdbrileya@google.com } 132589708bf7c706348b763e8277004cb160b202bdbrileya@google.com return SkFloatToFixed(t); 133589708bf7c706348b763e8277004cb160b202bdbrileya@google.com} 134589708bf7c706348b763e8277004cb160b202bdbrileya@google.com 13587fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.orgtypedef void (*TwoPointConicalProc)(TwoPtRadialContext* rec, SkPMColor* dstC, 13660040292be58ac553298209fb2e0684a4cb17dccreed@google.com const SkPMColor* cache, int toggle, int count); 137589708bf7c706348b763e8277004cb160b202bdbrileya@google.com 13887fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.orgstatic void twopoint_clamp(TwoPtRadialContext* rec, SkPMColor* SK_RESTRICT dstC, 13960040292be58ac553298209fb2e0684a4cb17dccreed@google.com const SkPMColor* SK_RESTRICT cache, int toggle, 14060040292be58ac553298209fb2e0684a4cb17dccreed@google.com int count) { 141589708bf7c706348b763e8277004cb160b202bdbrileya@google.com for (; count > 0; --count) { 142589708bf7c706348b763e8277004cb160b202bdbrileya@google.com SkFixed t = rec->nextT(); 143589708bf7c706348b763e8277004cb160b202bdbrileya@google.com if (TwoPtRadial::DontDrawT(t)) { 144589708bf7c706348b763e8277004cb160b202bdbrileya@google.com *dstC++ = 0; 145589708bf7c706348b763e8277004cb160b202bdbrileya@google.com } else { 146589708bf7c706348b763e8277004cb160b202bdbrileya@google.com SkFixed index = SkClampMax(t, 0xFFFF); 147589708bf7c706348b763e8277004cb160b202bdbrileya@google.com SkASSERT(index <= 0xFFFF); 14860040292be58ac553298209fb2e0684a4cb17dccreed@google.com *dstC++ = cache[toggle + 14960040292be58ac553298209fb2e0684a4cb17dccreed@google.com (index >> SkGradientShaderBase::kCache32Shift)]; 150589708bf7c706348b763e8277004cb160b202bdbrileya@google.com } 15160040292be58ac553298209fb2e0684a4cb17dccreed@google.com toggle = next_dither_toggle(toggle); 152589708bf7c706348b763e8277004cb160b202bdbrileya@google.com } 153589708bf7c706348b763e8277004cb160b202bdbrileya@google.com} 154589708bf7c706348b763e8277004cb160b202bdbrileya@google.com 15587fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.orgstatic void twopoint_repeat(TwoPtRadialContext* rec, SkPMColor* SK_RESTRICT dstC, 15660040292be58ac553298209fb2e0684a4cb17dccreed@google.com const SkPMColor* SK_RESTRICT cache, int toggle, 15760040292be58ac553298209fb2e0684a4cb17dccreed@google.com int count) { 158589708bf7c706348b763e8277004cb160b202bdbrileya@google.com for (; count > 0; --count) { 159589708bf7c706348b763e8277004cb160b202bdbrileya@google.com SkFixed t = rec->nextT(); 160589708bf7c706348b763e8277004cb160b202bdbrileya@google.com if (TwoPtRadial::DontDrawT(t)) { 161589708bf7c706348b763e8277004cb160b202bdbrileya@google.com *dstC++ = 0; 162589708bf7c706348b763e8277004cb160b202bdbrileya@google.com } else { 163589708bf7c706348b763e8277004cb160b202bdbrileya@google.com SkFixed index = repeat_tileproc(t); 164589708bf7c706348b763e8277004cb160b202bdbrileya@google.com SkASSERT(index <= 0xFFFF); 16560040292be58ac553298209fb2e0684a4cb17dccreed@google.com *dstC++ = cache[toggle + 16660040292be58ac553298209fb2e0684a4cb17dccreed@google.com (index >> SkGradientShaderBase::kCache32Shift)]; 167589708bf7c706348b763e8277004cb160b202bdbrileya@google.com } 16860040292be58ac553298209fb2e0684a4cb17dccreed@google.com toggle = next_dither_toggle(toggle); 169589708bf7c706348b763e8277004cb160b202bdbrileya@google.com } 170589708bf7c706348b763e8277004cb160b202bdbrileya@google.com} 171589708bf7c706348b763e8277004cb160b202bdbrileya@google.com 17287fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.orgstatic void twopoint_mirror(TwoPtRadialContext* rec, SkPMColor* SK_RESTRICT dstC, 17360040292be58ac553298209fb2e0684a4cb17dccreed@google.com const SkPMColor* SK_RESTRICT cache, int toggle, 17460040292be58ac553298209fb2e0684a4cb17dccreed@google.com int count) { 175589708bf7c706348b763e8277004cb160b202bdbrileya@google.com for (; count > 0; --count) { 176589708bf7c706348b763e8277004cb160b202bdbrileya@google.com SkFixed t = rec->nextT(); 177589708bf7c706348b763e8277004cb160b202bdbrileya@google.com if (TwoPtRadial::DontDrawT(t)) { 178589708bf7c706348b763e8277004cb160b202bdbrileya@google.com *dstC++ = 0; 179589708bf7c706348b763e8277004cb160b202bdbrileya@google.com } else { 180589708bf7c706348b763e8277004cb160b202bdbrileya@google.com SkFixed index = mirror_tileproc(t); 181589708bf7c706348b763e8277004cb160b202bdbrileya@google.com SkASSERT(index <= 0xFFFF); 18260040292be58ac553298209fb2e0684a4cb17dccreed@google.com *dstC++ = cache[toggle + 18360040292be58ac553298209fb2e0684a4cb17dccreed@google.com (index >> SkGradientShaderBase::kCache32Shift)]; 184589708bf7c706348b763e8277004cb160b202bdbrileya@google.com } 18560040292be58ac553298209fb2e0684a4cb17dccreed@google.com toggle = next_dither_toggle(toggle); 186589708bf7c706348b763e8277004cb160b202bdbrileya@google.com } 187589708bf7c706348b763e8277004cb160b202bdbrileya@google.com} 188589708bf7c706348b763e8277004cb160b202bdbrileya@google.com 18998e8b6de04e4c20451fbe3353645e3e384a76550rileya@google.com///////////////////////////////////////////////////////////////////// 19098e8b6de04e4c20451fbe3353645e3e384a76550rileya@google.com 191589708bf7c706348b763e8277004cb160b202bdbrileya@google.comSkTwoPointConicalGradient::SkTwoPointConicalGradient( 1923d3a860d0ba878adb905512a45c500a67532b0a3reed@google.com const SkPoint& start, SkScalar startRadius, 1933d3a860d0ba878adb905512a45c500a67532b0a3reed@google.com const SkPoint& end, SkScalar endRadius, 194addf2edf3da20f053daa3897cfe2c52d7369a7b1reed bool flippedGrad, const Descriptor& desc) 195cc695fee81613dc92746c1c6bb27f45cfc6ce73emtklein : SkGradientShaderBase(desc, SkMatrix::I()) 196addf2edf3da20f053daa3897cfe2c52d7369a7b1reed , fCenter1(start) 197addf2edf3da20f053daa3897cfe2c52d7369a7b1reed , fCenter2(end) 198addf2edf3da20f053daa3897cfe2c52d7369a7b1reed , fRadius1(startRadius) 199addf2edf3da20f053daa3897cfe2c52d7369a7b1reed , fRadius2(endRadius) 200addf2edf3da20f053daa3897cfe2c52d7369a7b1reed , fFlippedGrad(flippedGrad) 201addf2edf3da20f053daa3897cfe2c52d7369a7b1reed{ 202589708bf7c706348b763e8277004cb160b202bdbrileya@google.com // this is degenerate, and should be caught by our caller 203589708bf7c706348b763e8277004cb160b202bdbrileya@google.com SkASSERT(fCenter1 != fCenter2 || fRadius1 != fRadius2); 204cc695fee81613dc92746c1c6bb27f45cfc6ce73emtklein fRec.init(fCenter1, fRadius1, fCenter2, fRadius2, fFlippedGrad); 205589708bf7c706348b763e8277004cb160b202bdbrileya@google.com} 206589708bf7c706348b763e8277004cb160b202bdbrileya@google.com 2073fbab82bd30158ccabc708a20419025923e08655commit-bot@chromium.orgbool SkTwoPointConicalGradient::isOpaque() const { 208cb6d97ca718c0335dde678bb64169f6de70b62d6robertphillips@google.com // Because areas outside the cone are left untouched, we cannot treat the 209cb6d97ca718c0335dde678bb64169f6de70b62d6robertphillips@google.com // shader as opaque even if the gradient itself is opaque. 210cb6d97ca718c0335dde678bb64169f6de70b62d6robertphillips@google.com // TODO(junov): Compute whether the cone fills the plane crbug.com/222380 211cb6d97ca718c0335dde678bb64169f6de70b62d6robertphillips@google.com return false; 2123fbab82bd30158ccabc708a20419025923e08655commit-bot@chromium.org} 2133fbab82bd30158ccabc708a20419025923e08655commit-bot@chromium.org 21487fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.orgsize_t SkTwoPointConicalGradient::contextSize() const { 21587fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org return sizeof(TwoPointConicalGradientContext); 21687fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org} 21787fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org 218ce56d965069c1649afe14319cb239e6ad670682acommit-bot@chromium.orgSkShader::Context* SkTwoPointConicalGradient::onCreateContext(const ContextRec& rec, 219ce56d965069c1649afe14319cb239e6ad670682acommit-bot@chromium.org void* storage) const { 220e901b6de3ef8dea842008a08fc81e92fb1478d61commit-bot@chromium.org return SkNEW_PLACEMENT_ARGS(storage, TwoPointConicalGradientContext, (*this, rec)); 22187fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org} 22287fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org 22387fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.orgSkTwoPointConicalGradient::TwoPointConicalGradientContext::TwoPointConicalGradientContext( 224e901b6de3ef8dea842008a08fc81e92fb1478d61commit-bot@chromium.org const SkTwoPointConicalGradient& shader, const ContextRec& rec) 225e901b6de3ef8dea842008a08fc81e92fb1478d61commit-bot@chromium.org : INHERITED(shader, rec) 22687fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org{ 22787fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org // we don't have a span16 proc 22887fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org fFlags &= ~kHasSpan16_Flag; 22987fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org 23087fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org // in general, we might discard based on computed-radius, so clear 23187fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org // this flag (todo: sometimes we can detect that we never discard...) 23287fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org fFlags &= ~kOpaqueAlpha_Flag; 23387fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org} 23487fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org 23587fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.orgvoid SkTwoPointConicalGradient::TwoPointConicalGradientContext::shadeSpan( 23687fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org int x, int y, SkPMColor* dstCParam, int count) { 23787fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org const SkTwoPointConicalGradient& twoPointConicalGradient = 23887fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org static_cast<const SkTwoPointConicalGradient&>(fShader); 23987fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org 24060040292be58ac553298209fb2e0684a4cb17dccreed@google.com int toggle = init_dither_toggle(x, y); 24160040292be58ac553298209fb2e0684a4cb17dccreed@google.com 242589708bf7c706348b763e8277004cb160b202bdbrileya@google.com SkASSERT(count > 0); 243fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com 244589708bf7c706348b763e8277004cb160b202bdbrileya@google.com SkPMColor* SK_RESTRICT dstC = dstCParam; 245fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com 246589708bf7c706348b763e8277004cb160b202bdbrileya@google.com SkMatrix::MapXYProc dstProc = fDstToIndexProc; 247100abf49e10544bc4f436bf1f38e6929779621f4bsalomon@google.com 24887fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org const SkPMColor* SK_RESTRICT cache = fCache->getCache32(); 249589708bf7c706348b763e8277004cb160b202bdbrileya@google.com 25060040292be58ac553298209fb2e0684a4cb17dccreed@google.com TwoPointConicalProc shadeProc = twopoint_repeat; 25187fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org if (SkShader::kClamp_TileMode == twoPointConicalGradient.fTileMode) { 252589708bf7c706348b763e8277004cb160b202bdbrileya@google.com shadeProc = twopoint_clamp; 25387fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org } else if (SkShader::kMirror_TileMode == twoPointConicalGradient.fTileMode) { 254589708bf7c706348b763e8277004cb160b202bdbrileya@google.com shadeProc = twopoint_mirror; 255589708bf7c706348b763e8277004cb160b202bdbrileya@google.com } else { 25687fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org SkASSERT(SkShader::kRepeat_TileMode == twoPointConicalGradient.fTileMode); 257589708bf7c706348b763e8277004cb160b202bdbrileya@google.com } 258fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com 259589708bf7c706348b763e8277004cb160b202bdbrileya@google.com if (fDstToIndexClass != kPerspective_MatrixClass) { 260589708bf7c706348b763e8277004cb160b202bdbrileya@google.com SkPoint srcPt; 261589708bf7c706348b763e8277004cb160b202bdbrileya@google.com dstProc(fDstToIndex, SkIntToScalar(x) + SK_ScalarHalf, 262589708bf7c706348b763e8277004cb160b202bdbrileya@google.com SkIntToScalar(y) + SK_ScalarHalf, &srcPt); 263589708bf7c706348b763e8277004cb160b202bdbrileya@google.com SkScalar dx, fx = srcPt.fX; 264589708bf7c706348b763e8277004cb160b202bdbrileya@google.com SkScalar dy, fy = srcPt.fY; 265fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com 266589708bf7c706348b763e8277004cb160b202bdbrileya@google.com if (fDstToIndexClass == kFixedStepInX_MatrixClass) { 267589708bf7c706348b763e8277004cb160b202bdbrileya@google.com SkFixed fixedX, fixedY; 268589708bf7c706348b763e8277004cb160b202bdbrileya@google.com (void)fDstToIndex.fixedStepInX(SkIntToScalar(y), &fixedX, &fixedY); 269589708bf7c706348b763e8277004cb160b202bdbrileya@google.com dx = SkFixedToScalar(fixedX); 270589708bf7c706348b763e8277004cb160b202bdbrileya@google.com dy = SkFixedToScalar(fixedY); 271589708bf7c706348b763e8277004cb160b202bdbrileya@google.com } else { 272589708bf7c706348b763e8277004cb160b202bdbrileya@google.com SkASSERT(fDstToIndexClass == kLinear_MatrixClass); 273589708bf7c706348b763e8277004cb160b202bdbrileya@google.com dx = fDstToIndex.getScaleX(); 274589708bf7c706348b763e8277004cb160b202bdbrileya@google.com dy = fDstToIndex.getSkewY(); 275589708bf7c706348b763e8277004cb160b202bdbrileya@google.com } 276589708bf7c706348b763e8277004cb160b202bdbrileya@google.com 27787fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org TwoPtRadialContext rec(twoPointConicalGradient.fRec, fx, fy, dx, dy); 27887fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org (*shadeProc)(&rec, dstC, cache, toggle, count); 279589708bf7c706348b763e8277004cb160b202bdbrileya@google.com } else { // perspective case 280139a2359abdeedca1ff836aa24c1a6943d9274f8mike@reedtribe.org SkScalar dstX = SkIntToScalar(x) + SK_ScalarHalf; 281139a2359abdeedca1ff836aa24c1a6943d9274f8mike@reedtribe.org SkScalar dstY = SkIntToScalar(y) + SK_ScalarHalf; 282589708bf7c706348b763e8277004cb160b202bdbrileya@google.com for (; count > 0; --count) { 283589708bf7c706348b763e8277004cb160b202bdbrileya@google.com SkPoint srcPt; 284589708bf7c706348b763e8277004cb160b202bdbrileya@google.com dstProc(fDstToIndex, dstX, dstY, &srcPt); 28587fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org TwoPtRadialContext rec(twoPointConicalGradient.fRec, srcPt.fX, srcPt.fY, 0, 0); 28687fcd950198a16211b3988610beebb5ca5bcf323commit-bot@chromium.org (*shadeProc)(&rec, dstC, cache, toggle, 1); 287139a2359abdeedca1ff836aa24c1a6943d9274f8mike@reedtribe.org 288139a2359abdeedca1ff836aa24c1a6943d9274f8mike@reedtribe.org dstX += SK_Scalar1; 28960040292be58ac553298209fb2e0684a4cb17dccreed@google.com toggle = next_dither_toggle(toggle); 290139a2359abdeedca1ff836aa24c1a6943d9274f8mike@reedtribe.org dstC += 1; 291589708bf7c706348b763e8277004cb160b202bdbrileya@google.com } 292589708bf7c706348b763e8277004cb160b202bdbrileya@google.com } 293589708bf7c706348b763e8277004cb160b202bdbrileya@google.com} 294589708bf7c706348b763e8277004cb160b202bdbrileya@google.com 295589708bf7c706348b763e8277004cb160b202bdbrileya@google.comSkShader::BitmapType SkTwoPointConicalGradient::asABitmap( 296589708bf7c706348b763e8277004cb160b202bdbrileya@google.com SkBitmap* bitmap, SkMatrix* matrix, SkShader::TileMode* xy) const { 297589708bf7c706348b763e8277004cb160b202bdbrileya@google.com SkPoint diff = fCenter2 - fCenter1; 298589708bf7c706348b763e8277004cb160b202bdbrileya@google.com SkScalar diffLen = 0; 299589708bf7c706348b763e8277004cb160b202bdbrileya@google.com 300589708bf7c706348b763e8277004cb160b202bdbrileya@google.com if (bitmap) { 3011c6d64b78b24083ee9fd7411dac8a4a7e2d03a3crileya@google.com this->getGradientTableBitmap(bitmap); 302589708bf7c706348b763e8277004cb160b202bdbrileya@google.com } 303589708bf7c706348b763e8277004cb160b202bdbrileya@google.com if (matrix) { 304589708bf7c706348b763e8277004cb160b202bdbrileya@google.com diffLen = diff.length(); 305589708bf7c706348b763e8277004cb160b202bdbrileya@google.com } 306589708bf7c706348b763e8277004cb160b202bdbrileya@google.com if (matrix) { 307589708bf7c706348b763e8277004cb160b202bdbrileya@google.com if (diffLen) { 308589708bf7c706348b763e8277004cb160b202bdbrileya@google.com SkScalar invDiffLen = SkScalarInvert(diffLen); 309589708bf7c706348b763e8277004cb160b202bdbrileya@google.com // rotate to align circle centers with the x-axis 310589708bf7c706348b763e8277004cb160b202bdbrileya@google.com matrix->setSinCos(-SkScalarMul(invDiffLen, diff.fY), 311589708bf7c706348b763e8277004cb160b202bdbrileya@google.com SkScalarMul(invDiffLen, diff.fX)); 312589708bf7c706348b763e8277004cb160b202bdbrileya@google.com } else { 313589708bf7c706348b763e8277004cb160b202bdbrileya@google.com matrix->reset(); 314589708bf7c706348b763e8277004cb160b202bdbrileya@google.com } 315589708bf7c706348b763e8277004cb160b202bdbrileya@google.com matrix->preTranslate(-fCenter1.fX, -fCenter1.fY); 316589708bf7c706348b763e8277004cb160b202bdbrileya@google.com } 317589708bf7c706348b763e8277004cb160b202bdbrileya@google.com if (xy) { 318589708bf7c706348b763e8277004cb160b202bdbrileya@google.com xy[0] = fTileMode; 319589708bf7c706348b763e8277004cb160b202bdbrileya@google.com xy[1] = kClamp_TileMode; 320589708bf7c706348b763e8277004cb160b202bdbrileya@google.com } 321589708bf7c706348b763e8277004cb160b202bdbrileya@google.com return kTwoPointConical_BitmapType; 322589708bf7c706348b763e8277004cb160b202bdbrileya@google.com} 323589708bf7c706348b763e8277004cb160b202bdbrileya@google.com 32444d83c1e81b0555efa94f78e2a53b862208cdd06commit-bot@chromium.org// Returns the original non-sorted version of the gradient 325589708bf7c706348b763e8277004cb160b202bdbrileya@google.comSkShader::GradientType SkTwoPointConicalGradient::asAGradient( 326589708bf7c706348b763e8277004cb160b202bdbrileya@google.com GradientInfo* info) const { 327589708bf7c706348b763e8277004cb160b202bdbrileya@google.com if (info) { 32844d83c1e81b0555efa94f78e2a53b862208cdd06commit-bot@chromium.org commonAsAGradient(info, fFlippedGrad); 329589708bf7c706348b763e8277004cb160b202bdbrileya@google.com info->fPoint[0] = fCenter1; 330589708bf7c706348b763e8277004cb160b202bdbrileya@google.com info->fPoint[1] = fCenter2; 331589708bf7c706348b763e8277004cb160b202bdbrileya@google.com info->fRadius[0] = fRadius1; 332589708bf7c706348b763e8277004cb160b202bdbrileya@google.com info->fRadius[1] = fRadius2; 33344d83c1e81b0555efa94f78e2a53b862208cdd06commit-bot@chromium.org if (fFlippedGrad) { 33444d83c1e81b0555efa94f78e2a53b862208cdd06commit-bot@chromium.org SkTSwap(info->fPoint[0], info->fPoint[1]); 33544d83c1e81b0555efa94f78e2a53b862208cdd06commit-bot@chromium.org SkTSwap(info->fRadius[0], info->fRadius[1]); 33644d83c1e81b0555efa94f78e2a53b862208cdd06commit-bot@chromium.org } 337589708bf7c706348b763e8277004cb160b202bdbrileya@google.com } 338589708bf7c706348b763e8277004cb160b202bdbrileya@google.com return kConical_GradientType; 339589708bf7c706348b763e8277004cb160b202bdbrileya@google.com} 340589708bf7c706348b763e8277004cb160b202bdbrileya@google.com 3419fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reedSkFlattenable* SkTwoPointConicalGradient::CreateProc(SkReadBuffer& buffer) { 3429fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed DescriptorScope desc; 3439fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed if (!desc.unflatten(buffer)) { 3449fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed return NULL; 3459fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed } 3469fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed SkPoint c1 = buffer.readPoint(); 3479fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed SkPoint c2 = buffer.readPoint(); 3489fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed SkScalar r1 = buffer.readScalar(); 3499fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed SkScalar r2 = buffer.readScalar(); 3509fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed 3519fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed if (buffer.readBool()) { // flipped 3529fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed SkTSwap(c1, c2); 3539fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed SkTSwap(r1, r2); 3549fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed 3559fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed SkColor* colors = desc.mutableColors(); 3569fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed SkScalar* pos = desc.mutablePos(); 3579fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed const int last = desc.fCount - 1; 3589fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed const int half = desc.fCount >> 1; 3599fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed for (int i = 0; i < half; ++i) { 3609fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed SkTSwap(colors[i], colors[last - i]); 3619fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed if (pos) { 3629fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed SkScalar tmp = pos[i]; 3639fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed pos[i] = SK_Scalar1 - pos[last - i]; 3649fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed pos[last - i] = SK_Scalar1 - tmp; 3659fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed } 3669fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed } 3679fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed if (pos) { 3689fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed if (desc.fCount & 1) { 3699fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed pos[half] = SK_Scalar1 - pos[half]; 3709fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed } 3719fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed } 3729fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed } 3739fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed 3749fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed return SkGradientShader::CreateTwoPointConical(c1, r1, c2, r2, desc.fColors, desc.fPos, 3759fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed desc.fCount, desc.fTileMode, desc.fGradFlags, 3769fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed desc.fLocalMatrix); 3779fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed} 378589708bf7c706348b763e8277004cb160b202bdbrileya@google.com 3799fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reedvoid SkTwoPointConicalGradient::flatten(SkWriteBuffer& buffer) const { 380589708bf7c706348b763e8277004cb160b202bdbrileya@google.com this->INHERITED::flatten(buffer); 381589708bf7c706348b763e8277004cb160b202bdbrileya@google.com buffer.writePoint(fCenter1); 382589708bf7c706348b763e8277004cb160b202bdbrileya@google.com buffer.writePoint(fCenter2); 383589708bf7c706348b763e8277004cb160b202bdbrileya@google.com buffer.writeScalar(fRadius1); 384589708bf7c706348b763e8277004cb160b202bdbrileya@google.com buffer.writeScalar(fRadius2); 38544d83c1e81b0555efa94f78e2a53b862208cdd06commit-bot@chromium.org buffer.writeBool(fFlippedGrad); 386589708bf7c706348b763e8277004cb160b202bdbrileya@google.com} 387589708bf7c706348b763e8277004cb160b202bdbrileya@google.com 388cf8fb1f6f03fc77f9927564f9ef9abeeeec508d2bsalomon@google.com#if SK_SUPPORT_GPU 389cf8fb1f6f03fc77f9927564f9ef9abeeeec508d2bsalomon@google.com 3909de5b514d38c5b36066bcdc14fba2f7e5196d372dandov#include "SkGr.h" 3919de5b514d38c5b36066bcdc14fba2f7e5196d372dandov 392b0a8a377f832c59cee939ad721e1f87d378b7142joshualittbool SkTwoPointConicalGradient::asFragmentProcessor(GrContext* context, 393b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt const SkPaint& paint, 3945531d51ce7426bdae7563547326fcf0bf926a083joshualitt const SkMatrix& viewM, 395b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt const SkMatrix* localMatrix, 396b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt GrColor* paintColor, 397b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt GrFragmentProcessor** fp) const { 39849f085dddff10473b6ebf832a974288300224e60bsalomon SkASSERT(context); 399f94b3a4cebd4adab09c40ebe23c02a615e10c394bsalomon@google.com SkASSERT(fPtsToUnit.isIdentity()); 400dfdb7e5240276493077b7c6e1f3cc8b8a0e195babsalomon@google.com 401b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt *fp = Gr2PtConicalGradientEffect::Create(context, *this, fTileMode, localMatrix); 40283d081ae1d731b5039e99823620f5e287542ee39bsalomon *paintColor = SkColor2GrColorJustAlpha(paint.getColor()); 4039de5b514d38c5b36066bcdc14fba2f7e5196d372dandov return true; 404d7cc651b8da11d52ae90e910b948f5e2d15daaf9rileya@google.com} 405d7cc651b8da11d52ae90e910b948f5e2d15daaf9rileya@google.com 406cf8fb1f6f03fc77f9927564f9ef9abeeeec508d2bsalomon@google.com#else 407cf8fb1f6f03fc77f9927564f9ef9abeeeec508d2bsalomon@google.com 4085531d51ce7426bdae7563547326fcf0bf926a083joshualittbool SkTwoPointConicalGradient::asFragmentProcessor(GrContext*, const SkPaint&, 4095531d51ce7426bdae7563547326fcf0bf926a083joshualitt const SkMatrix&, const SkMatrix*, 410b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt GrColor*, GrFragmentProcessor**) const { 411cf8fb1f6f03fc77f9927564f9ef9abeeeec508d2bsalomon@google.com SkDEBUGFAIL("Should not call in GPU-less build"); 4129de5b514d38c5b36066bcdc14fba2f7e5196d372dandov return false; 413cf8fb1f6f03fc77f9927564f9ef9abeeeec508d2bsalomon@google.com} 414cf8fb1f6f03fc77f9927564f9ef9abeeeec508d2bsalomon@google.com 415a5e65ec434fed44dc616e4f64950b835b541181btwiz@google.com#endif 41676f9e938df0b5826fd4c80b854ceafaf385cfbe1robertphillips@google.com 4170f10f7bf1fb43ca6346dc220a076773b1f19a367commit-bot@chromium.org#ifndef SK_IGNORE_TO_STRING 41876f9e938df0b5826fd4c80b854ceafaf385cfbe1robertphillips@google.comvoid SkTwoPointConicalGradient::toString(SkString* str) const { 41976f9e938df0b5826fd4c80b854ceafaf385cfbe1robertphillips@google.com str->append("SkTwoPointConicalGradient: ("); 42076f9e938df0b5826fd4c80b854ceafaf385cfbe1robertphillips@google.com 42176f9e938df0b5826fd4c80b854ceafaf385cfbe1robertphillips@google.com str->append("center1: ("); 42276f9e938df0b5826fd4c80b854ceafaf385cfbe1robertphillips@google.com str->appendScalar(fCenter1.fX); 42376f9e938df0b5826fd4c80b854ceafaf385cfbe1robertphillips@google.com str->append(", "); 42476f9e938df0b5826fd4c80b854ceafaf385cfbe1robertphillips@google.com str->appendScalar(fCenter1.fY); 42576f9e938df0b5826fd4c80b854ceafaf385cfbe1robertphillips@google.com str->append(") radius1: "); 42676f9e938df0b5826fd4c80b854ceafaf385cfbe1robertphillips@google.com str->appendScalar(fRadius1); 42776f9e938df0b5826fd4c80b854ceafaf385cfbe1robertphillips@google.com str->append(" "); 42876f9e938df0b5826fd4c80b854ceafaf385cfbe1robertphillips@google.com 42976f9e938df0b5826fd4c80b854ceafaf385cfbe1robertphillips@google.com str->append("center2: ("); 43076f9e938df0b5826fd4c80b854ceafaf385cfbe1robertphillips@google.com str->appendScalar(fCenter2.fX); 43176f9e938df0b5826fd4c80b854ceafaf385cfbe1robertphillips@google.com str->append(", "); 43276f9e938df0b5826fd4c80b854ceafaf385cfbe1robertphillips@google.com str->appendScalar(fCenter2.fY); 43376f9e938df0b5826fd4c80b854ceafaf385cfbe1robertphillips@google.com str->append(") radius2: "); 43476f9e938df0b5826fd4c80b854ceafaf385cfbe1robertphillips@google.com str->appendScalar(fRadius2); 43576f9e938df0b5826fd4c80b854ceafaf385cfbe1robertphillips@google.com str->append(" "); 43676f9e938df0b5826fd4c80b854ceafaf385cfbe1robertphillips@google.com 43776f9e938df0b5826fd4c80b854ceafaf385cfbe1robertphillips@google.com this->INHERITED::toString(str); 43876f9e938df0b5826fd4c80b854ceafaf385cfbe1robertphillips@google.com 43976f9e938df0b5826fd4c80b854ceafaf385cfbe1robertphillips@google.com str->append(")"); 44076f9e938df0b5826fd4c80b854ceafaf385cfbe1robertphillips@google.com} 44176f9e938df0b5826fd4c80b854ceafaf385cfbe1robertphillips@google.com#endif 442