Home | History | Annotate | Download | only in gradients
      1 
      2 /*
      3  * Copyright 2012 Google Inc.
      4  *
      5  * Use of this source code is governed by a BSD-style license that can be
      6  * found in the LICENSE file.
      7  */
      8 
      9 #include "SkRadialGradient.h"
     10 #include "SkRadialGradient_Table.h"
     11 
     12 #define kSQRT_TABLE_BITS    11
     13 #define kSQRT_TABLE_SIZE    (1 << kSQRT_TABLE_BITS)
     14 
     15 #if defined(SK_BUILD_FOR_WIN32) && defined(SK_DEBUG)
     16 
     17 #include <stdio.h>
     18 
     19 void SkRadialGradient_BuildTable() {
     20     // build it 0..127 x 0..127, so we use 2^15 - 1 in the numerator for our "fixed" table
     21 
     22     FILE* file = ::fopen("SkRadialGradient_Table.h", "w");
     23     SkASSERT(file);
     24     ::fprintf(file, "static const uint8_t gSqrt8Table[] = {\n");
     25 
     26     for (int i = 0; i < kSQRT_TABLE_SIZE; i++) {
     27         if ((i & 15) == 0) {
     28             ::fprintf(file, "\t");
     29         }
     30 
     31         uint8_t value = SkToU8(SkFixedSqrt(i * SK_Fixed1 / kSQRT_TABLE_SIZE) >> 8);
     32 
     33         ::fprintf(file, "0x%02X", value);
     34         if (i < kSQRT_TABLE_SIZE-1) {
     35             ::fprintf(file, ", ");
     36         }
     37         if ((i & 15) == 15) {
     38             ::fprintf(file, "\n");
     39         }
     40     }
     41     ::fprintf(file, "};\n");
     42     ::fclose(file);
     43 }
     44 
     45 #endif
     46 
     47 namespace {
     48 
     49 void rad_to_unit_matrix(const SkPoint& center, SkScalar radius,
     50                                SkMatrix* matrix) {
     51     SkScalar    inv = SkScalarInvert(radius);
     52 
     53     matrix->setTranslate(-center.fX, -center.fY);
     54     matrix->postScale(inv, inv);
     55 }
     56 
     57 typedef void (* RadialShade16Proc)(SkScalar sfx, SkScalar sdx,
     58         SkScalar sfy, SkScalar sdy,
     59         uint16_t* dstC, const uint16_t* cache,
     60         int toggle, int count);
     61 
     62 void shadeSpan16_radial_clamp(SkScalar sfx, SkScalar sdx,
     63         SkScalar sfy, SkScalar sdy,
     64         uint16_t* SK_RESTRICT dstC, const uint16_t* SK_RESTRICT cache,
     65         int toggle, int count) {
     66     const uint8_t* SK_RESTRICT sqrt_table = gSqrt8Table;
     67 
     68     /* knock these down so we can pin against +- 0x7FFF, which is an
     69        immediate load, rather than 0xFFFF which is slower. This is a
     70        compromise, since it reduces our precision, but that appears
     71        to be visually OK. If we decide this is OK for all of our cases,
     72        we could (it seems) put this scale-down into fDstToIndex,
     73        to avoid having to do these extra shifts each time.
     74     */
     75     SkFixed fx = SkScalarToFixed(sfx) >> 1;
     76     SkFixed dx = SkScalarToFixed(sdx) >> 1;
     77     SkFixed fy = SkScalarToFixed(sfy) >> 1;
     78     SkFixed dy = SkScalarToFixed(sdy) >> 1;
     79     // might perform this check for the other modes,
     80     // but the win will be a smaller % of the total
     81     if (dy == 0) {
     82         fy = SkPin32(fy, -0xFFFF >> 1, 0xFFFF >> 1);
     83         fy *= fy;
     84         do {
     85             unsigned xx = SkPin32(fx, -0xFFFF >> 1, 0xFFFF >> 1);
     86             unsigned fi = (xx * xx + fy) >> (14 + 16 - kSQRT_TABLE_BITS);
     87             fi = SkFastMin32(fi, 0xFFFF >> (16 - kSQRT_TABLE_BITS));
     88             fx += dx;
     89             *dstC++ = cache[toggle +
     90                             (sqrt_table[fi] >> SkGradientShaderBase::kSqrt16Shift)];
     91             toggle = next_dither_toggle16(toggle);
     92         } while (--count != 0);
     93     } else {
     94         do {
     95             unsigned xx = SkPin32(fx, -0xFFFF >> 1, 0xFFFF >> 1);
     96             unsigned fi = SkPin32(fy, -0xFFFF >> 1, 0xFFFF >> 1);
     97             fi = (xx * xx + fi * fi) >> (14 + 16 - kSQRT_TABLE_BITS);
     98             fi = SkFastMin32(fi, 0xFFFF >> (16 - kSQRT_TABLE_BITS));
     99             fx += dx;
    100             fy += dy;
    101             *dstC++ = cache[toggle +
    102                             (sqrt_table[fi] >> SkGradientShaderBase::kSqrt16Shift)];
    103             toggle = next_dither_toggle16(toggle);
    104         } while (--count != 0);
    105     }
    106 }
    107 
    108 void shadeSpan16_radial_mirror(SkScalar sfx, SkScalar sdx,
    109         SkScalar sfy, SkScalar sdy,
    110         uint16_t* SK_RESTRICT dstC, const uint16_t* SK_RESTRICT cache,
    111         int toggle, int count) {
    112     do {
    113 #ifdef SK_SCALAR_IS_FLOAT
    114         float fdist = sk_float_sqrt(sfx*sfx + sfy*sfy);
    115         SkFixed dist = SkFloatToFixed(fdist);
    116 #else
    117         SkFixed magnitudeSquared = SkFixedSquare(sfx) +
    118             SkFixedSquare(sfy);
    119         if (magnitudeSquared < 0) // Overflow.
    120             magnitudeSquared = SK_FixedMax;
    121         SkFixed dist = SkFixedSqrt(magnitudeSquared);
    122 #endif
    123         unsigned fi = mirror_tileproc(dist);
    124         SkASSERT(fi <= 0xFFFF);
    125         *dstC++ = cache[toggle + (fi >> SkGradientShaderBase::kCache16Shift)];
    126         toggle = next_dither_toggle16(toggle);
    127         sfx += sdx;
    128         sfy += sdy;
    129     } while (--count != 0);
    130 }
    131 
    132 void shadeSpan16_radial_repeat(SkScalar sfx, SkScalar sdx,
    133         SkScalar sfy, SkScalar sdy,
    134         uint16_t* SK_RESTRICT dstC, const uint16_t* SK_RESTRICT cache,
    135         int toggle, int count) {
    136     SkFixed fx = SkScalarToFixed(sfx);
    137     SkFixed dx = SkScalarToFixed(sdx);
    138     SkFixed fy = SkScalarToFixed(sfy);
    139     SkFixed dy = SkScalarToFixed(sdy);
    140     do {
    141         SkFixed dist = SkFixedSqrt(SkFixedSquare(fx) + SkFixedSquare(fy));
    142         unsigned fi = repeat_tileproc(dist);
    143         SkASSERT(fi <= 0xFFFF);
    144         fx += dx;
    145         fy += dy;
    146         *dstC++ = cache[toggle + (fi >> SkGradientShaderBase::kCache16Shift)];
    147         toggle = next_dither_toggle16(toggle);
    148     } while (--count != 0);
    149 }
    150 
    151 }
    152 
    153 /////////////////////////////////////////////////////////////////////
    154 
    155 SkRadialGradient::SkRadialGradient(const SkPoint& center, SkScalar radius,
    156                 const SkColor colors[], const SkScalar pos[], int colorCount,
    157                 SkShader::TileMode mode, SkUnitMapper* mapper)
    158     : SkGradientShaderBase(colors, pos, colorCount, mode, mapper),
    159       fCenter(center),
    160       fRadius(radius)
    161 {
    162     // make sure our table is insync with our current #define for kSQRT_TABLE_SIZE
    163     SkASSERT(sizeof(gSqrt8Table) == kSQRT_TABLE_SIZE);
    164 
    165     rad_to_unit_matrix(center, radius, &fPtsToUnit);
    166 }
    167 
    168 void SkRadialGradient::shadeSpan16(int x, int y, uint16_t* dstCParam,
    169                          int count) {
    170     SkASSERT(count > 0);
    171 
    172     uint16_t* SK_RESTRICT dstC = dstCParam;
    173 
    174     SkPoint             srcPt;
    175     SkMatrix::MapXYProc dstProc = fDstToIndexProc;
    176     TileProc            proc = fTileProc;
    177     const uint16_t* SK_RESTRICT cache = this->getCache16();
    178     int                 toggle = init_dither_toggle16(x, y);
    179 
    180     if (fDstToIndexClass != kPerspective_MatrixClass) {
    181         dstProc(fDstToIndex, SkIntToScalar(x) + SK_ScalarHalf,
    182                              SkIntToScalar(y) + SK_ScalarHalf, &srcPt);
    183 
    184         SkScalar sdx = fDstToIndex.getScaleX();
    185         SkScalar sdy = fDstToIndex.getSkewY();
    186 
    187         if (fDstToIndexClass == kFixedStepInX_MatrixClass) {
    188             SkFixed storage[2];
    189             (void)fDstToIndex.fixedStepInX(SkIntToScalar(y),
    190                                            &storage[0], &storage[1]);
    191             sdx = SkFixedToScalar(storage[0]);
    192             sdy = SkFixedToScalar(storage[1]);
    193         } else {
    194             SkASSERT(fDstToIndexClass == kLinear_MatrixClass);
    195         }
    196 
    197         RadialShade16Proc shadeProc = shadeSpan16_radial_repeat;
    198         if (SkShader::kClamp_TileMode == fTileMode) {
    199             shadeProc = shadeSpan16_radial_clamp;
    200         } else if (SkShader::kMirror_TileMode == fTileMode) {
    201             shadeProc = shadeSpan16_radial_mirror;
    202         } else {
    203             SkASSERT(SkShader::kRepeat_TileMode == fTileMode);
    204         }
    205         (*shadeProc)(srcPt.fX, sdx, srcPt.fY, sdy, dstC,
    206                      cache, toggle, count);
    207     } else {    // perspective case
    208         SkScalar dstX = SkIntToScalar(x);
    209         SkScalar dstY = SkIntToScalar(y);
    210         do {
    211             dstProc(fDstToIndex, dstX, dstY, &srcPt);
    212             unsigned fi = proc(SkScalarToFixed(srcPt.length()));
    213             SkASSERT(fi <= 0xFFFF);
    214 
    215             int index = fi >> (16 - kCache16Bits);
    216             *dstC++ = cache[toggle + index];
    217             toggle = next_dither_toggle16(toggle);
    218 
    219             dstX += SK_Scalar1;
    220         } while (--count != 0);
    221     }
    222 }
    223 
    224 SkShader::BitmapType SkRadialGradient::asABitmap(SkBitmap* bitmap,
    225     SkMatrix* matrix, SkShader::TileMode* xy) const {
    226     if (bitmap) {
    227         this->getGradientTableBitmap(bitmap);
    228     }
    229     if (matrix) {
    230         matrix->setScale(SkIntToScalar(kCache32Count),
    231                          SkIntToScalar(kCache32Count));
    232         matrix->preConcat(fPtsToUnit);
    233     }
    234     if (xy) {
    235         xy[0] = fTileMode;
    236         xy[1] = kClamp_TileMode;
    237     }
    238     return kRadial_BitmapType;
    239 }
    240 
    241 SkShader::GradientType SkRadialGradient::asAGradient(GradientInfo* info) const {
    242     if (info) {
    243         commonAsAGradient(info);
    244         info->fPoint[0] = fCenter;
    245         info->fRadius[0] = fRadius;
    246     }
    247     return kRadial_GradientType;
    248 }
    249 
    250 SkRadialGradient::SkRadialGradient(SkFlattenableReadBuffer& buffer)
    251     : INHERITED(buffer),
    252       fCenter(buffer.readPoint()),
    253       fRadius(buffer.readScalar()) {
    254 }
    255 
    256 void SkRadialGradient::flatten(SkFlattenableWriteBuffer& buffer) const {
    257     this->INHERITED::flatten(buffer);
    258     buffer.writePoint(fCenter);
    259     buffer.writeScalar(fRadius);
    260 }
    261 
    262 namespace {
    263 
    264 inline bool radial_completely_pinned(int fx, int dx, int fy, int dy) {
    265     // fast, overly-conservative test: checks unit square instead
    266     // of unit circle
    267     bool xClamped = (fx >= SK_FixedHalf && dx >= 0) ||
    268                     (fx <= -SK_FixedHalf && dx <= 0);
    269     bool yClamped = (fy >= SK_FixedHalf && dy >= 0) ||
    270                     (fy <= -SK_FixedHalf && dy <= 0);
    271 
    272     return xClamped || yClamped;
    273 }
    274 
    275 // Return true if (fx * fy) is always inside the unit circle
    276 // SkPin32 is expensive, but so are all the SkFixedMul in this test,
    277 // so it shouldn't be run if count is small.
    278 inline bool no_need_for_radial_pin(int fx, int dx,
    279                                           int fy, int dy, int count) {
    280     SkASSERT(count > 0);
    281     if (SkAbs32(fx) > 0x7FFF || SkAbs32(fy) > 0x7FFF) {
    282         return false;
    283     }
    284     if (fx*fx + fy*fy > 0x7FFF*0x7FFF) {
    285         return false;
    286     }
    287     fx += (count - 1) * dx;
    288     fy += (count - 1) * dy;
    289     if (SkAbs32(fx) > 0x7FFF || SkAbs32(fy) > 0x7FFF) {
    290         return false;
    291     }
    292     return fx*fx + fy*fy <= 0x7FFF*0x7FFF;
    293 }
    294 
    295 #define UNPINNED_RADIAL_STEP \
    296     fi = (fx * fx + fy * fy) >> (14 + 16 - kSQRT_TABLE_BITS); \
    297     *dstC++ = cache[toggle + \
    298                     (sqrt_table[fi] >> SkGradientShaderBase::kSqrt32Shift)]; \
    299     toggle = next_dither_toggle(toggle); \
    300     fx += dx; \
    301     fy += dy;
    302 
    303 typedef void (* RadialShadeProc)(SkScalar sfx, SkScalar sdx,
    304         SkScalar sfy, SkScalar sdy,
    305         SkPMColor* dstC, const SkPMColor* cache,
    306         int count, int toggle);
    307 
    308 // On Linux, this is faster with SkPMColor[] params than SkPMColor* SK_RESTRICT
    309 void shadeSpan_radial_clamp(SkScalar sfx, SkScalar sdx,
    310         SkScalar sfy, SkScalar sdy,
    311         SkPMColor* SK_RESTRICT dstC, const SkPMColor* SK_RESTRICT cache,
    312         int count, int toggle) {
    313     // Floating point seems to be slower than fixed point,
    314     // even when we have float hardware.
    315     const uint8_t* SK_RESTRICT sqrt_table = gSqrt8Table;
    316     SkFixed fx = SkScalarToFixed(sfx) >> 1;
    317     SkFixed dx = SkScalarToFixed(sdx) >> 1;
    318     SkFixed fy = SkScalarToFixed(sfy) >> 1;
    319     SkFixed dy = SkScalarToFixed(sdy) >> 1;
    320     if ((count > 4) && radial_completely_pinned(fx, dx, fy, dy)) {
    321         unsigned fi = SkGradientShaderBase::kCache32Count - 1;
    322         sk_memset32_dither(dstC,
    323             cache[toggle + fi],
    324             cache[next_dither_toggle(toggle) + fi],
    325             count);
    326     } else if ((count > 4) &&
    327                no_need_for_radial_pin(fx, dx, fy, dy, count)) {
    328         unsigned fi;
    329         // 4x unroll appears to be no faster than 2x unroll on Linux
    330         while (count > 1) {
    331             UNPINNED_RADIAL_STEP;
    332             UNPINNED_RADIAL_STEP;
    333             count -= 2;
    334         }
    335         if (count) {
    336             UNPINNED_RADIAL_STEP;
    337         }
    338     }
    339     else  {
    340         // Specializing for dy == 0 gains us 25% on Skia benchmarks
    341         if (dy == 0) {
    342             unsigned yy = SkPin32(fy, -0xFFFF >> 1, 0xFFFF >> 1);
    343             yy *= yy;
    344             do {
    345                 unsigned xx = SkPin32(fx, -0xFFFF >> 1, 0xFFFF >> 1);
    346                 unsigned fi = (xx * xx + yy) >> (14 + 16 - kSQRT_TABLE_BITS);
    347                 fi = SkFastMin32(fi, 0xFFFF >> (16 - kSQRT_TABLE_BITS));
    348                 *dstC++ = cache[toggle + (sqrt_table[fi] >>
    349                     SkGradientShaderBase::kSqrt32Shift)];
    350                 toggle = next_dither_toggle(toggle);
    351                 fx += dx;
    352             } while (--count != 0);
    353         } else {
    354             do {
    355                 unsigned xx = SkPin32(fx, -0xFFFF >> 1, 0xFFFF >> 1);
    356                 unsigned fi = SkPin32(fy, -0xFFFF >> 1, 0xFFFF >> 1);
    357                 fi = (xx * xx + fi * fi) >> (14 + 16 - kSQRT_TABLE_BITS);
    358                 fi = SkFastMin32(fi, 0xFFFF >> (16 - kSQRT_TABLE_BITS));
    359                 *dstC++ = cache[toggle + (sqrt_table[fi] >>
    360                     SkGradientShaderBase::kSqrt32Shift)];
    361                 toggle = next_dither_toggle(toggle);
    362                 fx += dx;
    363                 fy += dy;
    364             } while (--count != 0);
    365         }
    366     }
    367 }
    368 
    369 // Unrolling this loop doesn't seem to help (when float); we're stalling to
    370 // get the results of the sqrt (?), and don't have enough extra registers to
    371 // have many in flight.
    372 void shadeSpan_radial_mirror(SkScalar sfx, SkScalar sdx,
    373         SkScalar sfy, SkScalar sdy,
    374         SkPMColor* SK_RESTRICT dstC, const SkPMColor* SK_RESTRICT cache,
    375         int count, int toggle) {
    376     do {
    377 #ifdef SK_SCALAR_IS_FLOAT
    378         float fdist = sk_float_sqrt(sfx*sfx + sfy*sfy);
    379         SkFixed dist = SkFloatToFixed(fdist);
    380 #else
    381         SkFixed magnitudeSquared = SkFixedSquare(sfx) +
    382             SkFixedSquare(sfy);
    383         if (magnitudeSquared < 0) // Overflow.
    384             magnitudeSquared = SK_FixedMax;
    385         SkFixed dist = SkFixedSqrt(magnitudeSquared);
    386 #endif
    387         unsigned fi = mirror_tileproc(dist);
    388         SkASSERT(fi <= 0xFFFF);
    389         *dstC++ = cache[toggle + (fi >> SkGradientShaderBase::kCache32Shift)];
    390         toggle = next_dither_toggle(toggle);
    391         sfx += sdx;
    392         sfy += sdy;
    393     } while (--count != 0);
    394 }
    395 
    396 void shadeSpan_radial_repeat(SkScalar sfx, SkScalar sdx,
    397         SkScalar sfy, SkScalar sdy,
    398         SkPMColor* SK_RESTRICT dstC, const SkPMColor* SK_RESTRICT cache,
    399         int count, int toggle) {
    400     SkFixed fx = SkScalarToFixed(sfx);
    401     SkFixed dx = SkScalarToFixed(sdx);
    402     SkFixed fy = SkScalarToFixed(sfy);
    403     SkFixed dy = SkScalarToFixed(sdy);
    404     do {
    405         SkFixed magnitudeSquared = SkFixedSquare(fx) +
    406             SkFixedSquare(fy);
    407         if (magnitudeSquared < 0) // Overflow.
    408             magnitudeSquared = SK_FixedMax;
    409         SkFixed dist = SkFixedSqrt(magnitudeSquared);
    410         unsigned fi = repeat_tileproc(dist);
    411         SkASSERT(fi <= 0xFFFF);
    412         *dstC++ = cache[toggle + (fi >> SkGradientShaderBase::kCache32Shift)];
    413         toggle = next_dither_toggle(toggle);
    414         fx += dx;
    415         fy += dy;
    416     } while (--count != 0);
    417 }
    418 }
    419 
    420 void SkRadialGradient::shadeSpan(int x, int y,
    421                                 SkPMColor* SK_RESTRICT dstC, int count) {
    422     SkASSERT(count > 0);
    423 
    424     SkPoint             srcPt;
    425     SkMatrix::MapXYProc dstProc = fDstToIndexProc;
    426     TileProc            proc = fTileProc;
    427     const SkPMColor* SK_RESTRICT cache = this->getCache32();
    428 #ifdef USE_DITHER_32BIT_GRADIENT
    429     int toggle = init_dither_toggle(x, y);
    430 #else
    431     int toggle = 0;
    432 #endif
    433 
    434     if (fDstToIndexClass != kPerspective_MatrixClass) {
    435         dstProc(fDstToIndex, SkIntToScalar(x) + SK_ScalarHalf,
    436                              SkIntToScalar(y) + SK_ScalarHalf, &srcPt);
    437         SkScalar sdx = fDstToIndex.getScaleX();
    438         SkScalar sdy = fDstToIndex.getSkewY();
    439 
    440         if (fDstToIndexClass == kFixedStepInX_MatrixClass) {
    441             SkFixed storage[2];
    442             (void)fDstToIndex.fixedStepInX(SkIntToScalar(y),
    443                                            &storage[0], &storage[1]);
    444             sdx = SkFixedToScalar(storage[0]);
    445             sdy = SkFixedToScalar(storage[1]);
    446         } else {
    447             SkASSERT(fDstToIndexClass == kLinear_MatrixClass);
    448         }
    449 
    450         RadialShadeProc shadeProc = shadeSpan_radial_repeat;
    451         if (SkShader::kClamp_TileMode == fTileMode) {
    452             shadeProc = shadeSpan_radial_clamp;
    453         } else if (SkShader::kMirror_TileMode == fTileMode) {
    454             shadeProc = shadeSpan_radial_mirror;
    455         } else {
    456             SkASSERT(SkShader::kRepeat_TileMode == fTileMode);
    457         }
    458         (*shadeProc)(srcPt.fX, sdx, srcPt.fY, sdy, dstC, cache, count, toggle);
    459     } else {    // perspective case
    460         SkScalar dstX = SkIntToScalar(x);
    461         SkScalar dstY = SkIntToScalar(y);
    462         do {
    463             dstProc(fDstToIndex, dstX, dstY, &srcPt);
    464             unsigned fi = proc(SkScalarToFixed(srcPt.length()));
    465             SkASSERT(fi <= 0xFFFF);
    466             *dstC++ = cache[fi >> SkGradientShaderBase::kCache32Shift];
    467             dstX += SK_Scalar1;
    468         } while (--count != 0);
    469     }
    470 }
    471 
    472 /////////////////////////////////////////////////////////////////////
    473 
    474 #if SK_SUPPORT_GPU
    475 
    476 #include "GrTBackendEffectFactory.h"
    477 
    478 class GrGLRadialGradient : public GrGLGradientEffect {
    479 public:
    480 
    481     GrGLRadialGradient(const GrBackendEffectFactory& factory,
    482                        const GrEffectRef&) : INHERITED (factory) { }
    483     virtual ~GrGLRadialGradient() { }
    484 
    485     virtual void emitCode(GrGLShaderBuilder*,
    486                           const GrEffectStage&,
    487                           EffectKey,
    488                           const char* vertexCoords,
    489                           const char* outputColor,
    490                           const char* inputColor,
    491                           const TextureSamplerArray&) SK_OVERRIDE;
    492 
    493     static EffectKey GenKey(const GrEffectStage& stage, const GrGLCaps&) {
    494         return GenMatrixKey(stage);
    495     }
    496 
    497 private:
    498 
    499     typedef GrGLGradientEffect INHERITED;
    500 
    501 };
    502 
    503 /////////////////////////////////////////////////////////////////////
    504 
    505 class GrRadialGradient : public GrGradientEffect {
    506 public:
    507     static GrEffectRef* Create(GrContext* ctx,
    508                                const SkRadialGradient& shader,
    509                                const SkMatrix& matrix,
    510                                SkShader::TileMode tm) {
    511         AutoEffectUnref effect(SkNEW_ARGS(GrRadialGradient, (ctx, shader, matrix, tm)));
    512         return CreateEffectRef(effect);
    513     }
    514 
    515     virtual ~GrRadialGradient() { }
    516 
    517     static const char* Name() { return "Radial Gradient"; }
    518     virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE {
    519         return GrTBackendEffectFactory<GrRadialGradient>::getInstance();
    520     }
    521 
    522     typedef GrGLRadialGradient GLEffect;
    523 
    524 private:
    525     GrRadialGradient(GrContext* ctx,
    526                      const SkRadialGradient& shader,
    527                      const SkMatrix& matrix,
    528                      SkShader::TileMode tm)
    529         : INHERITED(ctx, shader, matrix, tm) {
    530     }
    531 
    532     GR_DECLARE_EFFECT_TEST;
    533 
    534     typedef GrGradientEffect INHERITED;
    535 };
    536 
    537 /////////////////////////////////////////////////////////////////////
    538 
    539 GR_DEFINE_EFFECT_TEST(GrRadialGradient);
    540 
    541 GrEffectRef* GrRadialGradient::TestCreate(SkRandom* random,
    542                                           GrContext* context,
    543                                           GrTexture**) {
    544     SkPoint center = {random->nextUScalar1(), random->nextUScalar1()};
    545     SkScalar radius = random->nextUScalar1();
    546 
    547     SkColor colors[kMaxRandomGradientColors];
    548     SkScalar stopsArray[kMaxRandomGradientColors];
    549     SkScalar* stops = stopsArray;
    550     SkShader::TileMode tm;
    551     int colorCount = RandomGradientParams(random, colors, &stops, &tm);
    552     SkAutoTUnref<SkShader> shader(SkGradientShader::CreateRadial(center, radius,
    553                                                                  colors, stops, colorCount,
    554                                                                  tm));
    555     SkPaint paint;
    556     return shader->asNewEffect(context, paint);
    557 }
    558 
    559 /////////////////////////////////////////////////////////////////////
    560 
    561 void GrGLRadialGradient::emitCode(GrGLShaderBuilder* builder,
    562                                   const GrEffectStage& stage,
    563                                   EffectKey key,
    564                                   const char* vertexCoords,
    565                                   const char* outputColor,
    566                                   const char* inputColor,
    567                                   const TextureSamplerArray& samplers) {
    568     this->emitYCoordUniform(builder);
    569     const char* coords;
    570     this->setupMatrix(builder, key, vertexCoords, &coords);
    571     SkString t("length(");
    572     t.append(coords);
    573     t.append(")");
    574     this->emitColorLookup(builder, t.c_str(), outputColor, inputColor, samplers[0]);
    575 }
    576 
    577 /////////////////////////////////////////////////////////////////////
    578 
    579 GrEffectRef* SkRadialGradient::asNewEffect(GrContext* context, const SkPaint&) const {
    580     SkASSERT(NULL != context);
    581 
    582     SkMatrix matrix;
    583     if (!this->getLocalMatrix().invert(&matrix)) {
    584         return NULL;
    585     }
    586     matrix.postConcat(fPtsToUnit);
    587     return GrRadialGradient::Create(context, *this, matrix, fTileMode);
    588 }
    589 
    590 #else
    591 
    592 GrEffectRef* SkRadialGradient::asNewEffect(GrContext*, const SkPaint&) const {
    593     SkDEBUGFAIL("Should not call in GPU-less build");
    594     return NULL;
    595 }
    596 
    597 #endif
    598 
    599 #ifdef SK_DEVELOPER
    600 void SkRadialGradient::toString(SkString* str) const {
    601     str->append("SkRadialGradient: (");
    602 
    603     str->append("center: (");
    604     str->appendScalar(fCenter.fX);
    605     str->append(", ");
    606     str->appendScalar(fCenter.fY);
    607     str->append(") radius: ");
    608     str->appendScalar(fRadius);
    609     str->append(" ");
    610 
    611     this->INHERITED::toString(str);
    612 
    613     str->append(")");
    614 }
    615 #endif
    616