180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru/*
380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru * Copyright 2012 Google Inc.
480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru *
580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru * Use of this source code is governed by a BSD-style license that can be
680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru * found in the LICENSE file.
780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru */
880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru#include "SkLinearGradient.h"
1080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
1180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Querustatic inline int repeat_bits(int x, const int bits) {
1280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    return x & ((1 << bits) - 1);
1380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru}
1480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
1580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Querustatic inline int repeat_8bits(int x) {
1680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    return x & 0xFF;
1780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru}
1880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
1980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru// Visual Studio 2010 (MSC_VER=1600) optimizes bit-shift code incorrectly.
2080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru// See http://code.google.com/p/skia/issues/detail?id=472
2180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru#if defined(_MSC_VER) && (_MSC_VER >= 1600)
2280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru#pragma optimize("", off)
2380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru#endif
2480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
2580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Querustatic inline int mirror_bits(int x, const int bits) {
2680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru#ifdef SK_CPU_HAS_CONDITIONAL_INSTR
2780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    if (x & (1 << bits))
2880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        x = ~x;
2980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    return x & ((1 << bits) - 1);
3080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru#else
3180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    int s = x << (31 - bits) >> 31;
3280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    return (x ^ s) & ((1 << bits) - 1);
3380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru#endif
3480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru}
3580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
3680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Querustatic inline int mirror_8bits(int x) {
3780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru#ifdef SK_CPU_HAS_CONDITIONAL_INSTR
3880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    if (x & 256) {
3980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        x = ~x;
4080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    }
4180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    return x & 255;
4280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru#else
4380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    int s = x << 23 >> 31;
4480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    return (x ^ s) & 0xFF;
4580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru#endif
4680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru}
4780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
4880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru#if defined(_MSC_VER) && (_MSC_VER >= 1600)
4980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru#pragma optimize("", on)
5080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru#endif
5180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
5280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Querustatic void pts_to_unit_matrix(const SkPoint pts[2], SkMatrix* matrix) {
5380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    SkVector    vec = pts[1] - pts[0];
5480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    SkScalar    mag = vec.length();
5580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    SkScalar    inv = mag ? SkScalarInvert(mag) : 0;
5680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
5780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    vec.scale(inv);
5880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    matrix->setSinCos(-vec.fY, vec.fX, pts[0].fX, pts[0].fY);
5980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    matrix->postTranslate(-pts[0].fX, -pts[0].fY);
6080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    matrix->postScale(inv, inv);
6180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru}
6280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
6380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru///////////////////////////////////////////////////////////////////////////////
6480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
6580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste QueruSkLinearGradient::SkLinearGradient(const SkPoint pts[2],
6680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                                   const SkColor colors[],
6780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                                   const SkScalar pos[],
6880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                                   int colorCount,
6980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                                   SkShader::TileMode mode,
7080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                                   SkUnitMapper* mapper)
7180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    : SkGradientShaderBase(colors, pos, colorCount, mode, mapper)
7280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    , fStart(pts[0])
7380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    , fEnd(pts[1]) {
7480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    pts_to_unit_matrix(pts, &fPtsToUnit);
7580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru}
7680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
7780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste QueruSkLinearGradient::SkLinearGradient(SkFlattenableReadBuffer& buffer)
7880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    : INHERITED(buffer)
7980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    , fStart(buffer.readPoint())
8080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    , fEnd(buffer.readPoint()) {
8180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru}
8280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
8380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queruvoid SkLinearGradient::flatten(SkFlattenableWriteBuffer& buffer) const {
8480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    this->INHERITED::flatten(buffer);
8580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    buffer.writePoint(fStart);
8680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    buffer.writePoint(fEnd);
8780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru}
8880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
8980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Querubool SkLinearGradient::setContext(const SkBitmap& device, const SkPaint& paint,
9080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                                 const SkMatrix& matrix) {
9180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    if (!this->INHERITED::setContext(device, paint, matrix)) {
9280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        return false;
9380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    }
9480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
9580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    unsigned mask = SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask;
9680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    if ((fDstToIndex.getType() & ~mask) == 0) {
9780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        fFlags |= SkShader::kConstInY32_Flag;
9880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        if ((fFlags & SkShader::kHasSpan16_Flag) && !paint.isDither()) {
9980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            // only claim this if we do have a 16bit mode (i.e. none of our
10080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            // colors have alpha), and if we are not dithering (which obviously
10180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            // is not const in Y).
10280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            fFlags |= SkShader::kConstInY16_Flag;
10380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        }
10480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    }
10580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    return true;
10680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru}
10780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
10880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru#define NO_CHECK_ITER               \
10980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    do {                            \
11080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    unsigned fi = fx >> SkGradientShaderBase::kCache32Shift; \
11180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    SkASSERT(fi <= 0xFF);           \
11280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    fx += dx;                       \
11380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    *dstC++ = cache[toggle + fi];   \
114d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger    toggle = next_dither_toggle(toggle); \
11580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    } while (0)
11680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
11780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Querunamespace {
11880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
11980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Querutypedef void (*LinearShadeProc)(TileProc proc, SkFixed dx, SkFixed fx,
12080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                                SkPMColor* dstC, const SkPMColor* cache,
12180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                                int toggle, int count);
12280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
12380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru// Linear interpolation (lerp) is unnecessary if there are no sharp
12480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru// discontinuities in the gradient - which must be true if there are
12580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru// only 2 colors - but it's cheap.
12680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queruvoid shadeSpan_linear_vertical_lerp(TileProc proc, SkFixed dx, SkFixed fx,
12780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                                    SkPMColor* SK_RESTRICT dstC,
12880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                                    const SkPMColor* SK_RESTRICT cache,
12980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                                    int toggle, int count) {
13080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    // We're a vertical gradient, so no change in a span.
13180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    // If colors change sharply across the gradient, dithering is
13280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    // insufficient (it subsamples the color space) and we need to lerp.
13380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    unsigned fullIndex = proc(fx);
134d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger    unsigned fi = fullIndex >> SkGradientShaderBase::kCache32Shift;
135d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger    unsigned remainder = fullIndex & ((1 << SkGradientShaderBase::kCache32Shift) - 1);
136d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger
137d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger    int index0 = fi + toggle;
138d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger    int index1 = index0;
139d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger    if (fi < SkGradientShaderBase::kCache32Count - 1) {
140d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger        index1 += 1;
141d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger    }
142d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger    SkPMColor lerp = SkFastFourByteInterp(cache[index1], cache[index0], remainder);
143d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger    index0 ^= SkGradientShaderBase::kDitherStride32;
144d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger    index1 ^= SkGradientShaderBase::kDitherStride32;
145d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger    SkPMColor dlerp = SkFastFourByteInterp(cache[index1], cache[index0], remainder);
14680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    sk_memset32_dither(dstC, lerp, dlerp, count);
14780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru}
14880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
14980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queruvoid shadeSpan_linear_clamp(TileProc proc, SkFixed dx, SkFixed fx,
15080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                            SkPMColor* SK_RESTRICT dstC,
15180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                            const SkPMColor* SK_RESTRICT cache,
15280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                            int toggle, int count) {
15380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    SkClampRange range;
154d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger    range.init(fx, dx, count, 0, SkGradientShaderBase::kCache32Count - 1);
15580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
15680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    if ((count = range.fCount0) > 0) {
15780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        sk_memset32_dither(dstC,
15880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            cache[toggle + range.fV0],
159d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger            cache[next_dither_toggle(toggle) + range.fV0],
16080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            count);
16180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        dstC += count;
16280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    }
16380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    if ((count = range.fCount1) > 0) {
16480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        int unroll = count >> 3;
16580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        fx = range.fFx1;
16680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        for (int i = 0; i < unroll; i++) {
16780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            NO_CHECK_ITER;  NO_CHECK_ITER;
16880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            NO_CHECK_ITER;  NO_CHECK_ITER;
16980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            NO_CHECK_ITER;  NO_CHECK_ITER;
17080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            NO_CHECK_ITER;  NO_CHECK_ITER;
17180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        }
17280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        if ((count &= 7) > 0) {
17380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            do {
17480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                NO_CHECK_ITER;
17580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            } while (--count != 0);
17680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        }
17780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    }
17880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    if ((count = range.fCount2) > 0) {
17980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        sk_memset32_dither(dstC,
18080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            cache[toggle + range.fV1],
181d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger            cache[next_dither_toggle(toggle) + range.fV1],
18280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            count);
18380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    }
18480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru}
18580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
18680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queruvoid shadeSpan_linear_mirror(TileProc proc, SkFixed dx, SkFixed fx,
18780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                             SkPMColor* SK_RESTRICT dstC,
18880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                             const SkPMColor* SK_RESTRICT cache,
18980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                             int toggle, int count) {
19080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    do {
19180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        unsigned fi = mirror_8bits(fx >> 8);
19280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        SkASSERT(fi <= 0xFF);
19380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        fx += dx;
19480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        *dstC++ = cache[toggle + fi];
195d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger        toggle = next_dither_toggle(toggle);
19680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    } while (--count != 0);
19780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru}
19880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
19980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queruvoid shadeSpan_linear_repeat(TileProc proc, SkFixed dx, SkFixed fx,
20080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        SkPMColor* SK_RESTRICT dstC,
20180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        const SkPMColor* SK_RESTRICT cache,
20280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        int toggle, int count) {
20380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    do {
20480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        unsigned fi = repeat_8bits(fx >> 8);
20580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        SkASSERT(fi <= 0xFF);
20680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        fx += dx;
20780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        *dstC++ = cache[toggle + fi];
208d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger        toggle = next_dither_toggle(toggle);
20980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    } while (--count != 0);
21080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru}
21180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
21280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru}
21380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
21480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queruvoid SkLinearGradient::shadeSpan(int x, int y, SkPMColor* SK_RESTRICT dstC,
21580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                                int count) {
21680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    SkASSERT(count > 0);
21780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
21880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    SkPoint             srcPt;
21980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    SkMatrix::MapXYProc dstProc = fDstToIndexProc;
22080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    TileProc            proc = fTileProc;
22180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    const SkPMColor* SK_RESTRICT cache = this->getCache32();
22280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru#ifdef USE_DITHER_32BIT_GRADIENT
223d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger    int                 toggle = init_dither_toggle(x, y);
22480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru#else
22580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    int toggle = 0;
22680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru#endif
22780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
22880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    if (fDstToIndexClass != kPerspective_MatrixClass) {
22980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        dstProc(fDstToIndex, SkIntToScalar(x) + SK_ScalarHalf,
23080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                             SkIntToScalar(y) + SK_ScalarHalf, &srcPt);
23180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        SkFixed dx, fx = SkScalarToFixed(srcPt.fX);
23280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
23380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        if (fDstToIndexClass == kFixedStepInX_MatrixClass) {
23480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            SkFixed dxStorage[1];
23580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            (void)fDstToIndex.fixedStepInX(SkIntToScalar(y), dxStorage, NULL);
23680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            dx = dxStorage[0];
23780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        } else {
23880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            SkASSERT(fDstToIndexClass == kLinear_MatrixClass);
23980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            dx = SkScalarToFixed(fDstToIndex.getScaleX());
24080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        }
24180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
24280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        LinearShadeProc shadeProc = shadeSpan_linear_repeat;
2436699e7ea2e981dccc2f3c41b5dcf1c860b11558dJean-Baptiste Queru        if (SkFixedNearlyZero(dx, (SK_Fixed1 >> 14))) {
24480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            shadeProc = shadeSpan_linear_vertical_lerp;
24580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        } else if (SkShader::kClamp_TileMode == fTileMode) {
24680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            shadeProc = shadeSpan_linear_clamp;
24780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        } else if (SkShader::kMirror_TileMode == fTileMode) {
24880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            shadeProc = shadeSpan_linear_mirror;
24980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        } else {
25080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            SkASSERT(SkShader::kRepeat_TileMode == fTileMode);
25180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        }
25280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        (*shadeProc)(proc, dx, fx, dstC, cache, toggle, count);
25380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    } else {
25480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        SkScalar    dstX = SkIntToScalar(x);
25580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        SkScalar    dstY = SkIntToScalar(y);
25680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        do {
25780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            dstProc(fDstToIndex, dstX, dstY, &srcPt);
25880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            unsigned fi = proc(SkScalarToFixed(srcPt.fX));
25980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            SkASSERT(fi <= 0xFFFF);
26080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            *dstC++ = cache[toggle + (fi >> kCache32Shift)];
261d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger            toggle = next_dither_toggle(toggle);
26280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            dstX += SK_Scalar1;
26380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        } while (--count != 0);
26480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    }
26580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru}
26680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
26780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste QueruSkShader::BitmapType SkLinearGradient::asABitmap(SkBitmap* bitmap,
26880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                                                SkMatrix* matrix,
26980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                                                TileMode xy[]) const {
27080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    if (bitmap) {
27180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        this->getGradientTableBitmap(bitmap);
27280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    }
27380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    if (matrix) {
27480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        matrix->preConcat(fPtsToUnit);
27580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    }
27680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    if (xy) {
27780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        xy[0] = fTileMode;
27880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        xy[1] = kClamp_TileMode;
27980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    }
28080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    return kLinear_BitmapType;
28180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru}
28280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
28380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste QueruSkShader::GradientType SkLinearGradient::asAGradient(GradientInfo* info) const {
28480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    if (info) {
28580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        commonAsAGradient(info);
28680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        info->fPoint[0] = fStart;
28780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        info->fPoint[1] = fEnd;
28880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    }
28980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    return kLinear_GradientType;
29080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru}
29180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
29280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Querustatic void dither_memset16(uint16_t dst[], uint16_t value, uint16_t other,
29380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                            int count) {
29480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    if (reinterpret_cast<uintptr_t>(dst) & 2) {
29580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        *dst++ = value;
29680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        count -= 1;
29780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        SkTSwap(value, other);
29880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    }
29980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
30080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    sk_memset32((uint32_t*)dst, (value << 16) | other, count >> 1);
30180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
30280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    if (count & 1) {
30380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        dst[count - 1] = value;
30480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    }
30580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru}
30680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
30780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru#define NO_CHECK_ITER_16                \
30880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    do {                                \
30980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    unsigned fi = fx >> SkGradientShaderBase::kCache16Shift;  \
31080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    SkASSERT(fi < SkGradientShaderBase::kCache16Count);       \
31180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    fx += dx;                           \
31280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    *dstC++ = cache[toggle + fi];       \
313d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger    toggle = next_dither_toggle16(toggle);            \
31480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    } while (0)
31580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
31680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Querunamespace {
31780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
31880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Querutypedef void (*LinearShade16Proc)(TileProc proc, SkFixed dx, SkFixed fx,
31980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                                  uint16_t* dstC, const uint16_t* cache,
32080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                                  int toggle, int count);
32180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
32280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queruvoid shadeSpan16_linear_vertical(TileProc proc, SkFixed dx, SkFixed fx,
32380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                                 uint16_t* SK_RESTRICT dstC,
32480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                                 const uint16_t* SK_RESTRICT cache,
32580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                                 int toggle, int count) {
32680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    // we're a vertical gradient, so no change in a span
32780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    unsigned fi = proc(fx) >> SkGradientShaderBase::kCache16Shift;
32880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    SkASSERT(fi < SkGradientShaderBase::kCache16Count);
32980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    dither_memset16(dstC, cache[toggle + fi],
330d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger        cache[next_dither_toggle16(toggle) + fi], count);
33180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
33280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru}
33380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
33480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queruvoid shadeSpan16_linear_clamp(TileProc proc, SkFixed dx, SkFixed fx,
33580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                              uint16_t* SK_RESTRICT dstC,
33680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                              const uint16_t* SK_RESTRICT cache,
33780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                              int toggle, int count) {
33880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    SkClampRange range;
339d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger    range.init(fx, dx, count, 0, SkGradientShaderBase::kCache32Count - 1);
34080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
34180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    if ((count = range.fCount0) > 0) {
34280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        dither_memset16(dstC,
34380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            cache[toggle + range.fV0],
344d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger            cache[next_dither_toggle16(toggle) + range.fV0],
34580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            count);
34680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        dstC += count;
34780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    }
34880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    if ((count = range.fCount1) > 0) {
34980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        int unroll = count >> 3;
35080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        fx = range.fFx1;
35180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        for (int i = 0; i < unroll; i++) {
35280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            NO_CHECK_ITER_16;  NO_CHECK_ITER_16;
35380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            NO_CHECK_ITER_16;  NO_CHECK_ITER_16;
35480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            NO_CHECK_ITER_16;  NO_CHECK_ITER_16;
35580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            NO_CHECK_ITER_16;  NO_CHECK_ITER_16;
35680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        }
35780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        if ((count &= 7) > 0) {
35880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            do {
35980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                NO_CHECK_ITER_16;
36080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            } while (--count != 0);
36180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        }
36280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    }
36380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    if ((count = range.fCount2) > 0) {
36480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        dither_memset16(dstC,
36580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            cache[toggle + range.fV1],
366d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger            cache[next_dither_toggle16(toggle) + range.fV1],
36780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            count);
36880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    }
36980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru}
37080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
37180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queruvoid shadeSpan16_linear_mirror(TileProc proc, SkFixed dx, SkFixed fx,
37280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                               uint16_t* SK_RESTRICT dstC,
37380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                               const uint16_t* SK_RESTRICT cache,
37480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                               int toggle, int count) {
37580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    do {
37680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        unsigned fi = mirror_bits(fx >> SkGradientShaderBase::kCache16Shift,
37780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                                        SkGradientShaderBase::kCache16Bits);
37880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        SkASSERT(fi < SkGradientShaderBase::kCache16Count);
37980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        fx += dx;
38080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        *dstC++ = cache[toggle + fi];
381d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger        toggle = next_dither_toggle16(toggle);
38280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    } while (--count != 0);
38380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru}
38480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
38580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queruvoid shadeSpan16_linear_repeat(TileProc proc, SkFixed dx, SkFixed fx,
38680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                               uint16_t* SK_RESTRICT dstC,
38780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                               const uint16_t* SK_RESTRICT cache,
38880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                               int toggle, int count) {
38980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    do {
39080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        unsigned fi = repeat_bits(fx >> SkGradientShaderBase::kCache16Shift,
39180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                                  SkGradientShaderBase::kCache16Bits);
39280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        SkASSERT(fi < SkGradientShaderBase::kCache16Count);
39380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        fx += dx;
39480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        *dstC++ = cache[toggle + fi];
395d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger        toggle = next_dither_toggle16(toggle);
39680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    } while (--count != 0);
39780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru}
39880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru}
39980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
40080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queruvoid SkLinearGradient::shadeSpan16(int x, int y,
40180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                                  uint16_t* SK_RESTRICT dstC, int count) {
40280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    SkASSERT(count > 0);
40380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
40480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    SkPoint             srcPt;
40580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    SkMatrix::MapXYProc dstProc = fDstToIndexProc;
40680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    TileProc            proc = fTileProc;
40780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    const uint16_t* SK_RESTRICT cache = this->getCache16();
408d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger    int                 toggle = init_dither_toggle16(x, y);
40980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
41080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    if (fDstToIndexClass != kPerspective_MatrixClass) {
41180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        dstProc(fDstToIndex, SkIntToScalar(x) + SK_ScalarHalf,
41280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                             SkIntToScalar(y) + SK_ScalarHalf, &srcPt);
41380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        SkFixed dx, fx = SkScalarToFixed(srcPt.fX);
41480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
41580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        if (fDstToIndexClass == kFixedStepInX_MatrixClass) {
41680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            SkFixed dxStorage[1];
41780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            (void)fDstToIndex.fixedStepInX(SkIntToScalar(y), dxStorage, NULL);
41880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            dx = dxStorage[0];
41980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        } else {
42080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            SkASSERT(fDstToIndexClass == kLinear_MatrixClass);
42180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            dx = SkScalarToFixed(fDstToIndex.getScaleX());
42280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        }
42380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
42480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        LinearShade16Proc shadeProc = shadeSpan16_linear_repeat;
42580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        if (SkFixedNearlyZero(dx)) {
42680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            shadeProc = shadeSpan16_linear_vertical;
42780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        } else if (SkShader::kClamp_TileMode == fTileMode) {
42880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            shadeProc = shadeSpan16_linear_clamp;
42980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        } else if (SkShader::kMirror_TileMode == fTileMode) {
43080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            shadeProc = shadeSpan16_linear_mirror;
43180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        } else {
43280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            SkASSERT(SkShader::kRepeat_TileMode == fTileMode);
43380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        }
43480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        (*shadeProc)(proc, dx, fx, dstC, cache, toggle, count);
43580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    } else {
43680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        SkScalar    dstX = SkIntToScalar(x);
43780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        SkScalar    dstY = SkIntToScalar(y);
43880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        do {
43980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            dstProc(fDstToIndex, dstX, dstY, &srcPt);
44080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            unsigned fi = proc(SkScalarToFixed(srcPt.fX));
44180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            SkASSERT(fi <= 0xFFFF);
44280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
44380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            int index = fi >> kCache16Shift;
44480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            *dstC++ = cache[toggle + index];
445d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger            toggle = next_dither_toggle16(toggle);
44680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
44780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            dstX += SK_Scalar1;
44880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        } while (--count != 0);
44980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    }
45080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru}
45180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
45280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru#if SK_SUPPORT_GPU
45380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
454363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger#include "GrTBackendEffectFactory.h"
455363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger
45680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru/////////////////////////////////////////////////////////////////////
45780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
458363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenbergerclass GrGLLinearGradient : public GrGLGradientEffect {
45980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Querupublic:
46080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
461d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger    GrGLLinearGradient(const GrBackendEffectFactory& factory, const GrEffectRef&)
46280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                       : INHERITED (factory) { }
46380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
46480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    virtual ~GrGLLinearGradient() { }
46580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
466363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger    virtual void emitCode(GrGLShaderBuilder*,
467363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger                          const GrEffectStage&,
468363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger                          EffectKey,
469363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger                          const char* vertexCoords,
470363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger                          const char* outputColor,
471363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger                          const char* inputColor,
472363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger                          const TextureSamplerArray&) SK_OVERRIDE;
473363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger
474363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger    static EffectKey GenKey(const GrEffectStage& stage, const GrGLCaps&) {
475363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger        return GenMatrixKey(stage);
476363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger    }
47780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
47880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queruprivate:
47980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
480363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger    typedef GrGLGradientEffect INHERITED;
48180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru};
48280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
48380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru/////////////////////////////////////////////////////////////////////
48480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
48580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queruclass GrLinearGradient : public GrGradientEffect {
48680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Querupublic:
48780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
488d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger    static GrEffectRef* Create(GrContext* ctx,
489d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger                               const SkLinearGradient& shader,
490d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger                               const SkMatrix& matrix,
491d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger                               SkShader::TileMode tm) {
492d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger        AutoEffectUnref effect(SkNEW_ARGS(GrLinearGradient, (ctx, shader, matrix, tm)));
493d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger        return CreateEffectRef(effect);
494d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger    }
495d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger
49680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    virtual ~GrLinearGradient() { }
49780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
49880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    static const char* Name() { return "Linear Gradient"; }
499363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger    const GrBackendEffectFactory& getFactory() const SK_OVERRIDE {
500363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger        return GrTBackendEffectFactory<GrLinearGradient>::getInstance();
50180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    }
50280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
503363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger    typedef GrGLLinearGradient GLEffect;
50480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
50580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queruprivate:
506d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger    GrLinearGradient(GrContext* ctx,
507d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger                     const SkLinearGradient& shader,
508d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger                     const SkMatrix& matrix,
509d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger                     SkShader::TileMode tm)
510d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger        : INHERITED(ctx, shader, matrix, tm) { }
511363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger    GR_DECLARE_EFFECT_TEST;
51280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
51380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    typedef GrGradientEffect INHERITED;
51480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru};
51580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
51680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru/////////////////////////////////////////////////////////////////////
51780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
518363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek SollenbergerGR_DEFINE_EFFECT_TEST(GrLinearGradient);
51980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
520d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek SollenbergerGrEffectRef* GrLinearGradient::TestCreate(SkRandom* random,
521d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger                                          GrContext* context,
522d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger                                          GrTexture**) {
52380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    SkPoint points[] = {{random->nextUScalar1(), random->nextUScalar1()},
52480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                        {random->nextUScalar1(), random->nextUScalar1()}};
52580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
52680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    SkColor colors[kMaxRandomGradientColors];
52780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    SkScalar stopsArray[kMaxRandomGradientColors];
52880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    SkScalar* stops = stopsArray;
52980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    SkShader::TileMode tm;
53080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    int colorCount = RandomGradientParams(random, colors, &stops, &tm);
53180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    SkAutoTUnref<SkShader> shader(SkGradientShader::CreateLinear(points,
53280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                                                                 colors, stops, colorCount,
53380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                                                                 tm));
534d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger    SkPaint paint;
535d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger    return shader->asNewEffect(context, paint);
53680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru}
53780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
53880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru/////////////////////////////////////////////////////////////////////
53980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
540363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenbergervoid GrGLLinearGradient::emitCode(GrGLShaderBuilder* builder,
541363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger                                  const GrEffectStage& stage,
542363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger                                  EffectKey key,
543363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger                                  const char* vertexCoords,
544363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger                                  const char* outputColor,
545363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger                                  const char* inputColor,
546363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger                                  const TextureSamplerArray& samplers) {
547363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger    this->emitYCoordUniform(builder);
548363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger    const char* coords;
549363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger    this->setupMatrix(builder, key, vertexCoords, &coords);
55080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    SkString t;
551363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger    t.append(coords);
552363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger    t.append(".x");
55380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    this->emitColorLookup(builder, t.c_str(), outputColor, inputColor, samplers[0]);
55480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru}
55580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
55680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru/////////////////////////////////////////////////////////////////////
55780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
558d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek SollenbergerGrEffectRef* SkLinearGradient::asNewEffect(GrContext* context, const SkPaint&) const {
559d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger    SkASSERT(NULL != context);
56080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    SkMatrix matrix;
561363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger    if (!this->getLocalMatrix().invert(&matrix)) {
562d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger        return NULL;
56380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    }
564363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger    matrix.postConcat(fPtsToUnit);
565d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger    return GrLinearGradient::Create(context, *this, matrix, fTileMode);
56680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru}
56780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
56880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru#else
56980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
570d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek SollenbergerGrEffectRef* SkLinearGradient::asNewEffect(GrContext*, const SkPaint&) const {
57180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    SkDEBUGFAIL("Should not call in GPU-less build");
572d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger    return NULL;
57380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru}
57480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
57580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru#endif
576d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger
577d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger#ifdef SK_DEVELOPER
578d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenbergervoid SkLinearGradient::toString(SkString* str) const {
579d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger    str->append("SkLinearGradient (");
580d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger
581d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger    str->appendf("start: (%f, %f)", fStart.fX, fStart.fY);
582d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger    str->appendf(" end: (%f, %f) ", fEnd.fX, fEnd.fY);
583d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger
584d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger    this->INHERITED::toString(str);
585d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger
586d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger    str->append(")");
587d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger}
588d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger#endif
589