11cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger
21cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger/*
31cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger * Copyright 2006 The Android Open Source Project
41cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger *
51cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger * Use of this source code is governed by a BSD-style license that can be
61cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger * found in the LICENSE file.
71cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger */
81cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger
90910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
100910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#include "SkGradientShader.h"
111cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger#include "SkClampRange.h"
120910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#include "SkColorPriv.h"
1340528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger#include "SkMallocPixelRef.h"
140910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#include "SkUnitMapper.h"
150910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#include "SkUtils.h"
1640528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger#include "SkTemplates.h"
1740528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger#include "SkBitmapCache.h"
1840528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger
1940528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger#ifndef SK_DISABLE_DITHER_32BIT_GRADIENT
2040528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger    #define USE_DITHER_32BIT_GRADIENT
2140528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger#endif
220910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
2335e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenbergerstatic void sk_memset32_dither(uint32_t dst[], uint32_t v0, uint32_t v1,
2435e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger                               int count) {
2535e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger    if (count > 0) {
2635e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger        if (v0 == v1) {
2735e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger            sk_memset32(dst, v0, count);
2835e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger        } else {
2935e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger            int pairs = count >> 1;
3035e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger            for (int i = 0; i < pairs; i++) {
3135e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger                *dst++ = v0;
3235e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger                *dst++ = v1;
3335e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger            }
3435e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger            if (count & 1) {
3535e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger                *dst = v0;
3635e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger            }
3735e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger        }
3835e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger    }
3935e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger}
4035e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger
4135e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger///////////////////////////////////////////////////////////////////////////////
4235e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger// Can't use a two-argument function with side effects like this in a
4335e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger// constructor's initializer's argument list because the order of
4435e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger// evaluations in that context is undefined (and backwards on linux/gcc).
4535e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenbergerstatic SkPoint unflatten_point(SkReader32& buffer) {
4635e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger    SkPoint retval;
4735e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger    retval.fX = buffer.readScalar();
4835e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger    retval.fY = buffer.readScalar();
4935e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger    return retval;
5035e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger}
5135e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger
524f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger//  Clamp
530910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
54dba38ba49760ccfd15b2f257f4345e1670f8398aMike Reedstatic SkFixed clamp_tileproc(SkFixed x) {
550910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    return SkClampMax(x, 0xFFFF);
560910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
570910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
584f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger// Repeat
594f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger
60dba38ba49760ccfd15b2f257f4345e1670f8398aMike Reedstatic SkFixed repeat_tileproc(SkFixed x) {
610910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    return x & 0xFFFF;
620910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
630910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
644f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenbergerstatic inline int repeat_bits(int x, const int bits) {
654f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger    return x & ((1 << bits) - 1);
660910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
670910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
684f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenbergerstatic inline int repeat_8bits(int x) {
694f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger    return x & 0xFF;
704f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger}
710910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
724f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger// Mirror
730910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
744f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger// Visual Studio 2010 (MSC_VER=1600) optimizes bit-shift code incorrectly.
754f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger// See http://code.google.com/p/skia/issues/detail?id=472
764f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger#if defined(_MSC_VER) && (_MSC_VER >= 1600)
774f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger#pragma optimize("", off)
784f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger#endif
794f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger
804f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenbergerstatic inline SkFixed mirror_tileproc(SkFixed x) {
814f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger    int s = x << 15 >> 31;
824f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger    return (x ^ s) & 0xFFFF;
830910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
840910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
8593d11b5b461a8677a8e3ffa94260f4f9897070acMike Reedstatic inline int mirror_bits(int x, const int bits) {
860910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#ifdef SK_CPU_HAS_CONDITIONAL_INSTR
8793d11b5b461a8677a8e3ffa94260f4f9897070acMike Reed    if (x & (1 << bits))
880910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        x = ~x;
8993d11b5b461a8677a8e3ffa94260f4f9897070acMike Reed    return x & ((1 << bits) - 1);
900910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#else
9193d11b5b461a8677a8e3ffa94260f4f9897070acMike Reed    int s = x << (31 - bits) >> 31;
9293d11b5b461a8677a8e3ffa94260f4f9897070acMike Reed    return (x ^ s) & ((1 << bits) - 1);
930910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#endif
940910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
950910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
96dba38ba49760ccfd15b2f257f4345e1670f8398aMike Reedstatic inline int mirror_8bits(int x) {
970910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#ifdef SK_CPU_HAS_CONDITIONAL_INSTR
98dba38ba49760ccfd15b2f257f4345e1670f8398aMike Reed    if (x & 256) {
990910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        x = ~x;
100dba38ba49760ccfd15b2f257f4345e1670f8398aMike Reed    }
1010910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    return x & 255;
1020910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#else
1030910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    int s = x << 23 >> 31;
1040910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    return (x ^ s) & 0xFF;
1050910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#endif
1060910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
1070910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
1084f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger#if defined(_MSC_VER) && (_MSC_VER >= 1600)
1094f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger#pragma optimize("", on)
1104f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger#endif
1114f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger
1124f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger///////////////////////////////////////////////////////////////////////////////
1134f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger
1144f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenbergertypedef SkFixed (*TileProc)(SkFixed);
1154f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger
1164f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenbergerstatic const TileProc gTileProcs[] = {
1174f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger    clamp_tileproc,
1184f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger    repeat_tileproc,
1194f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger    mirror_tileproc
1204f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger};
1214f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger
1224f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger///////////////////////////////////////////////////////////////////////////////
12335e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger///////////////////////////////////////////////////////////////////////////////
1240910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
1250910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectclass Gradient_Shader : public SkShader {
1260910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectpublic:
1270910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    Gradient_Shader(const SkColor colors[], const SkScalar pos[],
128dba38ba49760ccfd15b2f257f4345e1670f8398aMike Reed                int colorCount, SkShader::TileMode mode, SkUnitMapper* mapper);
1290910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    virtual ~Gradient_Shader();
1300910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
1310910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    // overrides
1321cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    virtual bool setContext(const SkBitmap&, const SkPaint&, const SkMatrix&) SK_OVERRIDE;
1331cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    virtual uint32_t getFlags() SK_OVERRIDE { return fFlags; }
1341cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    virtual bool isOpaque() const SK_OVERRIDE;
1351cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger
1361cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    enum {
1374f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger        /// Seems like enough for visual accuracy. TODO: if pos[] deserves
1384f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger        /// it, use a larger cache.
1394f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger        kCache16Bits    = 8,
1404f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger        kGradient16Length = (1 << kCache16Bits),
1414f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger        /// Each cache gets 1 extra entry at the end so we don't have to
1424f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger        /// test for end-of-cache in lerps. This is also the value used
1434f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger        /// to stride *writes* into the dither cache; it must not be zero.
1444f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger        /// Total space for a cache is 2x kCache16Count entries: one
1454f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger        /// regular cache, one for dithering.
1464f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger        kCache16Count   = kGradient16Length + 1,
1471cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        kCache16Shift   = 16 - kCache16Bits,
1481cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        kSqrt16Shift    = 8 - kCache16Bits,
1491cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger
1504f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger        /// Seems like enough for visual accuracy. TODO: if pos[] deserves
1514f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger        /// it, use a larger cache.
1524f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger        kCache32Bits    = 8,
1534f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger        kGradient32Length = (1 << kCache32Bits),
1544f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger        /// Each cache gets 1 extra entry at the end so we don't have to
1554f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger        /// test for end-of-cache in lerps. This is also the value used
1564f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger        /// to stride *writes* into the dither cache; it must not be zero.
1574f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger        /// Total space for a cache is 2x kCache32Count entries: one
1584f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger        /// regular cache, one for dithering.
1594f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger        kCache32Count   = kGradient32Length + 1,
1601cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        kCache32Shift   = 16 - kCache32Bits,
1611cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        kSqrt32Shift    = 8 - kCache32Bits,
1624f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger
1634f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger        /// This value is used to *read* the dither cache; it may be 0
1644f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger        /// if dithering is disabled.
1651cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger#ifdef USE_DITHER_32BIT_GRADIENT
1664f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger        kDitherStride32 = kCache32Count,
1671cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger#else
1684f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger        kDitherStride32 = 0,
1691cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger#endif
1704f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger        kDitherStride16 = kCache16Count,
1714f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger        kLerpRemainderMask32 = (1 << (16 - kCache32Bits)) - 1
1721cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    };
1731cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger
1740910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
1750910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectprotected:
1760910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    Gradient_Shader(SkFlattenableReadBuffer& );
1770910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkUnitMapper* fMapper;
1780910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkMatrix    fPtsToUnit;     // set by subclass
1790910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkMatrix    fDstToIndex;
1800910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkMatrix::MapXYProc fDstToIndexProc;
1810910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    TileMode    fTileMode;
1820910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    TileProc    fTileProc;
183dba38ba49760ccfd15b2f257f4345e1670f8398aMike Reed    int         fColorCount;
1840910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    uint8_t     fDstToIndexClass;
1850910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    uint8_t     fFlags;
1860910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
1870910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    struct Rec {
1880910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        SkFixed     fPos;   // 0...1
1890910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        uint32_t    fScale; // (1 << 24) / range
1900910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    };
1910910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    Rec*        fRecs;
1920910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
1930910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    virtual void flatten(SkFlattenableWriteBuffer& );
19405b6b4d746867a9fb02e14edfe1bf3685abeb813Derek Sollenberger    const uint16_t*     getCache16() const;
19505b6b4d746867a9fb02e14edfe1bf3685abeb813Derek Sollenberger    const SkPMColor*    getCache32() const;
1960910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
19705b6b4d746867a9fb02e14edfe1bf3685abeb813Derek Sollenberger    void commonAsABitmap(SkBitmap*) const;
19805b6b4d746867a9fb02e14edfe1bf3685abeb813Derek Sollenberger    void commonAsAGradient(GradientInfo*) const;
19979377cbceeea970b663e7934d7cb1f27bb223d98Mike Reed
2000910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectprivate:
2010910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    enum {
2020910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        kColorStorageCount = 4, // more than this many colors, and we'll use sk_malloc for the space
2030910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
204fadb93e0b43c7451032c46f3c58a1effa9d681b3Mike Reed        kStorageSize = kColorStorageCount * (sizeof(SkColor) + sizeof(Rec))
2050910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    };
2060910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkColor     fStorage[(kStorageSize + 3) >> 2];
2071cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    SkColor*    fOrigColors; // original colors, before modulation by paint in setContext
2081cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    bool        fColorsAreOpaque;
2090910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
21005b6b4d746867a9fb02e14edfe1bf3685abeb813Derek Sollenberger    mutable uint16_t*   fCache16;   // working ptr. If this is NULL, we need to recompute the cache values
21105b6b4d746867a9fb02e14edfe1bf3685abeb813Derek Sollenberger    mutable SkPMColor*  fCache32;   // working ptr. If this is NULL, we need to recompute the cache values
2120910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
21305b6b4d746867a9fb02e14edfe1bf3685abeb813Derek Sollenberger    mutable uint16_t*   fCache16Storage;    // storage for fCache16, allocated on demand
21405b6b4d746867a9fb02e14edfe1bf3685abeb813Derek Sollenberger    mutable SkMallocPixelRef* fCache32PixelRef;
2151cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    mutable unsigned    fCacheAlpha;        // the alpha value we used when we computed the cache. larger than 8bits so we can store uninitialized value
2160910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
21793d11b5b461a8677a8e3ffa94260f4f9897070acMike Reed    static void Build16bitCache(uint16_t[], SkColor c0, SkColor c1, int count);
21840528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger    static void Build32bitCache(SkPMColor[], SkColor c0, SkColor c1, int count,
21940528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger                                U8CPU alpha);
2201cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    void setCacheAlpha(U8CPU alpha) const;
2211cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    void initCommon();
22293d11b5b461a8677a8e3ffa94260f4f9897070acMike Reed
2230910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    typedef SkShader INHERITED;
2240910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project};
2250910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
226dba38ba49760ccfd15b2f257f4345e1670f8398aMike Reedstatic inline unsigned scalarToU16(SkScalar x) {
2270910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkASSERT(x >= 0 && x <= SK_Scalar1);
2280910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
2290910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#ifdef SK_SCALAR_IS_FLOAT
2300910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    return (unsigned)(x * 0xFFFF);
2310910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#else
2320910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    return x - (x >> 16);   // probably should be x - (x > 0x7FFF) but that is slower
2330910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#endif
2340910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
2350910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
236dba38ba49760ccfd15b2f257f4345e1670f8398aMike ReedGradient_Shader::Gradient_Shader(const SkColor colors[], const SkScalar pos[],
237dba38ba49760ccfd15b2f257f4345e1670f8398aMike Reed             int colorCount, SkShader::TileMode mode, SkUnitMapper* mapper) {
2380910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkASSERT(colorCount > 1);
2390910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
2400910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    fCacheAlpha = 256;  // init to a value that paint.getAlpha() can't return
2410910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
2420910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    fMapper = mapper;
24340528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger    SkSafeRef(mapper);
2440910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
2450910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkASSERT((unsigned)mode < SkShader::kTileModeCount);
2460910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkASSERT(SkShader::kTileModeCount == SK_ARRAY_COUNT(gTileProcs));
2470910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    fTileMode = mode;
2480910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    fTileProc = gTileProcs[mode];
24940528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger
250dba38ba49760ccfd15b2f257f4345e1670f8398aMike Reed    fCache16 = fCache16Storage = NULL;
25140528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger    fCache32 = NULL;
25240528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger    fCache32PixelRef = NULL;
2530910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
254dba38ba49760ccfd15b2f257f4345e1670f8398aMike Reed    /*  Note: we let the caller skip the first and/or last position.
255dba38ba49760ccfd15b2f257f4345e1670f8398aMike Reed        i.e. pos[0] = 0.3, pos[1] = 0.7
256dba38ba49760ccfd15b2f257f4345e1670f8398aMike Reed        In these cases, we insert dummy entries to ensure that the final data
257dba38ba49760ccfd15b2f257f4345e1670f8398aMike Reed        will be bracketed by [0, 1].
258dba38ba49760ccfd15b2f257f4345e1670f8398aMike Reed        i.e. our_pos[0] = 0, our_pos[1] = 0.3, our_pos[2] = 0.7, our_pos[3] = 1
259dba38ba49760ccfd15b2f257f4345e1670f8398aMike Reed
260dba38ba49760ccfd15b2f257f4345e1670f8398aMike Reed        Thus colorCount (the caller's value, and fColorCount (our value) may
261dba38ba49760ccfd15b2f257f4345e1670f8398aMike Reed        differ by up to 2. In the above example:
262dba38ba49760ccfd15b2f257f4345e1670f8398aMike Reed            colorCount = 2
263dba38ba49760ccfd15b2f257f4345e1670f8398aMike Reed            fColorCount = 4
264dba38ba49760ccfd15b2f257f4345e1670f8398aMike Reed     */
265dba38ba49760ccfd15b2f257f4345e1670f8398aMike Reed    fColorCount = colorCount;
266dba38ba49760ccfd15b2f257f4345e1670f8398aMike Reed    // check if we need to add in dummy start and/or end position/colors
267dba38ba49760ccfd15b2f257f4345e1670f8398aMike Reed    bool dummyFirst = false;
268dba38ba49760ccfd15b2f257f4345e1670f8398aMike Reed    bool dummyLast = false;
269dba38ba49760ccfd15b2f257f4345e1670f8398aMike Reed    if (pos) {
270dba38ba49760ccfd15b2f257f4345e1670f8398aMike Reed        dummyFirst = pos[0] != 0;
271dba38ba49760ccfd15b2f257f4345e1670f8398aMike Reed        dummyLast = pos[colorCount - 1] != SK_Scalar1;
272dba38ba49760ccfd15b2f257f4345e1670f8398aMike Reed        fColorCount += dummyFirst + dummyLast;
273dba38ba49760ccfd15b2f257f4345e1670f8398aMike Reed    }
274dba38ba49760ccfd15b2f257f4345e1670f8398aMike Reed
275dba38ba49760ccfd15b2f257f4345e1670f8398aMike Reed    if (fColorCount > kColorStorageCount) {
276fadb93e0b43c7451032c46f3c58a1effa9d681b3Mike Reed        size_t size = sizeof(SkColor) + sizeof(Rec);
277dba38ba49760ccfd15b2f257f4345e1670f8398aMike Reed        fOrigColors = reinterpret_cast<SkColor*>(
278dba38ba49760ccfd15b2f257f4345e1670f8398aMike Reed                                        sk_malloc_throw(size * fColorCount));
279dba38ba49760ccfd15b2f257f4345e1670f8398aMike Reed    }
280dba38ba49760ccfd15b2f257f4345e1670f8398aMike Reed    else {
281dba38ba49760ccfd15b2f257f4345e1670f8398aMike Reed        fOrigColors = fStorage;
282dba38ba49760ccfd15b2f257f4345e1670f8398aMike Reed    }
283dba38ba49760ccfd15b2f257f4345e1670f8398aMike Reed
284dba38ba49760ccfd15b2f257f4345e1670f8398aMike Reed    // Now copy over the colors, adding the dummies as needed
2850910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    {
286dba38ba49760ccfd15b2f257f4345e1670f8398aMike Reed        SkColor* origColors = fOrigColors;
287dba38ba49760ccfd15b2f257f4345e1670f8398aMike Reed        if (dummyFirst) {
288dba38ba49760ccfd15b2f257f4345e1670f8398aMike Reed            *origColors++ = colors[0];
289dba38ba49760ccfd15b2f257f4345e1670f8398aMike Reed        }
290dba38ba49760ccfd15b2f257f4345e1670f8398aMike Reed        memcpy(origColors, colors, colorCount * sizeof(SkColor));
291dba38ba49760ccfd15b2f257f4345e1670f8398aMike Reed        if (dummyLast) {
292dba38ba49760ccfd15b2f257f4345e1670f8398aMike Reed            origColors += colorCount;
293dba38ba49760ccfd15b2f257f4345e1670f8398aMike Reed            *origColors = colors[colorCount - 1];
294dba38ba49760ccfd15b2f257f4345e1670f8398aMike Reed        }
295dba38ba49760ccfd15b2f257f4345e1670f8398aMike Reed    }
2960910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
297fadb93e0b43c7451032c46f3c58a1effa9d681b3Mike Reed    fRecs = (Rec*)(fOrigColors + fColorCount);
298dba38ba49760ccfd15b2f257f4345e1670f8398aMike Reed    if (fColorCount > 2) {
299dba38ba49760ccfd15b2f257f4345e1670f8398aMike Reed        Rec* recs = fRecs;
300dba38ba49760ccfd15b2f257f4345e1670f8398aMike Reed        recs->fPos = 0;
301dba38ba49760ccfd15b2f257f4345e1670f8398aMike Reed        //  recs->fScale = 0; // unused;
302dba38ba49760ccfd15b2f257f4345e1670f8398aMike Reed        recs += 1;
303dba38ba49760ccfd15b2f257f4345e1670f8398aMike Reed        if (pos) {
3040910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            /*  We need to convert the user's array of relative positions into
3050910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                fixed-point positions and scale factors. We need these results
3060910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                to be strictly monotonic (no two values equal or out of order).
3070910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                Hence this complex loop that just jams a zero for the scale
3080910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                value if it sees a segment out of order, and it assures that
3090910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                we start at 0 and end at 1.0
3100910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            */
3110910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            SkFixed prev = 0;
312dba38ba49760ccfd15b2f257f4345e1670f8398aMike Reed            int startIndex = dummyFirst ? 0 : 1;
313dba38ba49760ccfd15b2f257f4345e1670f8398aMike Reed            int count = colorCount + dummyLast;
314dba38ba49760ccfd15b2f257f4345e1670f8398aMike Reed            for (int i = startIndex; i < count; i++) {
3150910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                // force the last value to be 1.0
3160910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                SkFixed curr;
317dba38ba49760ccfd15b2f257f4345e1670f8398aMike Reed                if (i == colorCount) {  // we're really at the dummyLast
3180910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                    curr = SK_Fixed1;
319dba38ba49760ccfd15b2f257f4345e1670f8398aMike Reed                } else {
3200910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                    curr = SkScalarToFixed(pos[i]);
3210910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                }
322dba38ba49760ccfd15b2f257f4345e1670f8398aMike Reed                // pin curr withing range
323dba38ba49760ccfd15b2f257f4345e1670f8398aMike Reed                if (curr < 0) {
324dba38ba49760ccfd15b2f257f4345e1670f8398aMike Reed                    curr = 0;
325dba38ba49760ccfd15b2f257f4345e1670f8398aMike Reed                } else if (curr > SK_Fixed1) {
326dba38ba49760ccfd15b2f257f4345e1670f8398aMike Reed                    curr = SK_Fixed1;
327dba38ba49760ccfd15b2f257f4345e1670f8398aMike Reed                }
328dba38ba49760ccfd15b2f257f4345e1670f8398aMike Reed                recs->fPos = curr;
329dba38ba49760ccfd15b2f257f4345e1670f8398aMike Reed                if (curr > prev) {
330dba38ba49760ccfd15b2f257f4345e1670f8398aMike Reed                    recs->fScale = (1 << 24) / (curr - prev);
331dba38ba49760ccfd15b2f257f4345e1670f8398aMike Reed                } else {
332dba38ba49760ccfd15b2f257f4345e1670f8398aMike Reed                    recs->fScale = 0; // ignore this segment
333dba38ba49760ccfd15b2f257f4345e1670f8398aMike Reed                }
3340910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                // get ready for the next value
3350910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                prev = curr;
336dba38ba49760ccfd15b2f257f4345e1670f8398aMike Reed                recs += 1;
3370910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            }
338dba38ba49760ccfd15b2f257f4345e1670f8398aMike Reed        } else {    // assume even distribution
3390910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            SkFixed dp = SK_Fixed1 / (colorCount - 1);
3400910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            SkFixed p = dp;
3410910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            SkFixed scale = (colorCount - 1) << 8;  // (1 << 24) / dp
342dba38ba49760ccfd15b2f257f4345e1670f8398aMike Reed            for (int i = 1; i < colorCount; i++) {
343dba38ba49760ccfd15b2f257f4345e1670f8398aMike Reed                recs->fPos   = p;
344dba38ba49760ccfd15b2f257f4345e1670f8398aMike Reed                recs->fScale = scale;
345dba38ba49760ccfd15b2f257f4345e1670f8398aMike Reed                recs += 1;
3460910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                p += dp;
3470910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            }
3480910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        }
3490910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
3501cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    this->initCommon();
3510910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
3520910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
3530910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source ProjectGradient_Shader::Gradient_Shader(SkFlattenableReadBuffer& buffer) :
354dba38ba49760ccfd15b2f257f4345e1670f8398aMike Reed    INHERITED(buffer) {
3550910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    fCacheAlpha = 256;
3560910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
3570910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    fMapper = static_cast<SkUnitMapper*>(buffer.readFlattenable());
3580910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
3590910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    fCache16 = fCache16Storage = NULL;
36040528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger    fCache32 = NULL;
36140528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger    fCache32PixelRef = NULL;
3620910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
363dba38ba49760ccfd15b2f257f4345e1670f8398aMike Reed    int colorCount = fColorCount = buffer.readU32();
364dba38ba49760ccfd15b2f257f4345e1670f8398aMike Reed    if (colorCount > kColorStorageCount) {
365dba38ba49760ccfd15b2f257f4345e1670f8398aMike Reed        size_t size = sizeof(SkColor) + sizeof(SkPMColor) + sizeof(Rec);
366dba38ba49760ccfd15b2f257f4345e1670f8398aMike Reed        fOrigColors = (SkColor*)sk_malloc_throw(size * colorCount);
367dba38ba49760ccfd15b2f257f4345e1670f8398aMike Reed    } else {
3680910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        fOrigColors = fStorage;
369dba38ba49760ccfd15b2f257f4345e1670f8398aMike Reed    }
3700910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    buffer.read(fOrigColors, colorCount * sizeof(SkColor));
3710910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
3720910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    fTileMode = (TileMode)buffer.readU8();
3730910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    fTileProc = gTileProcs[fTileMode];
374fadb93e0b43c7451032c46f3c58a1effa9d681b3Mike Reed    fRecs = (Rec*)(fOrigColors + colorCount);
3750910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    if (colorCount > 2) {
3760910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        Rec* recs = fRecs;
3770910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        recs[0].fPos = 0;
3780910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        for (int i = 1; i < colorCount; i++) {
3790910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            recs[i].fPos = buffer.readS32();
3800910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            recs[i].fScale = buffer.readU32();
3810910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        }
3820910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
38335e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger    SkReadMatrix(&buffer, &fPtsToUnit);
3841cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    this->initCommon();
3850910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
3860910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
387dba38ba49760ccfd15b2f257f4345e1670f8398aMike ReedGradient_Shader::~Gradient_Shader() {
388dba38ba49760ccfd15b2f257f4345e1670f8398aMike Reed    if (fCache16Storage) {
3890910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        sk_free(fCache16Storage);
390dba38ba49760ccfd15b2f257f4345e1670f8398aMike Reed    }
39140528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger    SkSafeUnref(fCache32PixelRef);
392dba38ba49760ccfd15b2f257f4345e1670f8398aMike Reed    if (fOrigColors != fStorage) {
3930910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        sk_free(fOrigColors);
394dba38ba49760ccfd15b2f257f4345e1670f8398aMike Reed    }
39540528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger    SkSafeUnref(fMapper);
3960910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
3970910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
3981cab2921ab279367f8206cdadc9259d12e603548Derek Sollenbergervoid Gradient_Shader::initCommon() {
3991cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    fFlags = 0;
4001cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    unsigned colorAlpha = 0xFF;
4011cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    for (int i = 0; i < fColorCount; i++) {
4021cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        colorAlpha &= SkColorGetA(fOrigColors[i]);
4031cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    }
4041cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    fColorsAreOpaque = colorAlpha == 0xFF;
4051cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger}
4061cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger
407dba38ba49760ccfd15b2f257f4345e1670f8398aMike Reedvoid Gradient_Shader::flatten(SkFlattenableWriteBuffer& buffer) {
4080910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    this->INHERITED::flatten(buffer);
4090910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    buffer.writeFlattenable(fMapper);
410dba38ba49760ccfd15b2f257f4345e1670f8398aMike Reed    buffer.write32(fColorCount);
4110910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    buffer.writeMul4(fOrigColors, fColorCount * sizeof(SkColor));
4120910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    buffer.write8(fTileMode);
4130910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    if (fColorCount > 2) {
4140910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        Rec* recs = fRecs;
4150910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        for (int i = 1; i < fColorCount; i++) {
4160910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            buffer.write32(recs[i].fPos);
4170910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            buffer.write32(recs[i].fScale);
4180910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        }
4190910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
42035e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger    SkWriteMatrix(&buffer, fPtsToUnit);
4210910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
4220910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
4231cab2921ab279367f8206cdadc9259d12e603548Derek Sollenbergerbool Gradient_Shader::isOpaque() const {
4241cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    return fColorsAreOpaque;
4251cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger}
4261cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger
4270910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectbool Gradient_Shader::setContext(const SkBitmap& device,
4280910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                                 const SkPaint& paint,
429dba38ba49760ccfd15b2f257f4345e1670f8398aMike Reed                                 const SkMatrix& matrix) {
430dba38ba49760ccfd15b2f257f4345e1670f8398aMike Reed    if (!this->INHERITED::setContext(device, paint, matrix)) {
4310910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        return false;
432dba38ba49760ccfd15b2f257f4345e1670f8398aMike Reed    }
4330910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
4340910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    const SkMatrix& inverse = this->getTotalInverse();
4350910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
4360910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    if (!fDstToIndex.setConcat(fPtsToUnit, inverse)) {
4370910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        return false;
4380910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
4390910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
4400910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    fDstToIndexProc = fDstToIndex.getMapXYProc();
4410910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    fDstToIndexClass = (uint8_t)SkShader::ComputeMatrixClass(fDstToIndex);
4420910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
4430910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    // now convert our colors in to PMColors
4440910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    unsigned paintAlpha = this->getPaintAlpha();
4450910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
4460910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    fFlags = this->INHERITED::getFlags();
4471cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    if (fColorsAreOpaque && paintAlpha == 0xFF) {
4480910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        fFlags |= kOpaqueAlpha_Flag;
4490910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
4500910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    // we can do span16 as long as our individual colors are opaque,
4510910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    // regardless of the paint's alpha
4521cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    if (fColorsAreOpaque) {
4530910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        fFlags |= kHasSpan16_Flag;
4540910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
4550910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
4561cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    this->setCacheAlpha(paintAlpha);
4571cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    return true;
4581cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger}
4591cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger
4601cab2921ab279367f8206cdadc9259d12e603548Derek Sollenbergervoid Gradient_Shader::setCacheAlpha(U8CPU alpha) const {
4610910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    // if the new alpha differs from the previous time we were called, inval our cache
4620910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    // this will trigger the cache to be rebuilt.
4630910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    // we don't care about the first time, since the cache ptrs will already be NULL
4641cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    if (fCacheAlpha != alpha) {
4651cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        fCache16 = NULL;            // inval the cache
4661cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        fCache32 = NULL;            // inval the cache
4671cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        fCacheAlpha = alpha;        // record the new alpha
46879377cbceeea970b663e7934d7cb1f27bb223d98Mike Reed        // inform our subclasses
46940528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger        if (fCache32PixelRef) {
47040528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger            fCache32PixelRef->notifyPixelsChanged();
47140528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger        }
4720910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
4730910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
4740910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
475dba38ba49760ccfd15b2f257f4345e1670f8398aMike Reedstatic inline int blend8(int a, int b, int scale) {
4760910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkASSERT(a == SkToU8(a));
4770910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkASSERT(b == SkToU8(b));
4780910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkASSERT(scale >= 0 && scale <= 256);
4790910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    return a + ((b - a) * scale >> 8);
4800910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
4810910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
482dba38ba49760ccfd15b2f257f4345e1670f8398aMike Reedstatic inline uint32_t dot8_blend_packed32(uint32_t s0, uint32_t s1,
483dba38ba49760ccfd15b2f257f4345e1670f8398aMike Reed                                           int blend) {
4840910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#if 0
4850910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    int a = blend8(SkGetPackedA32(s0), SkGetPackedA32(s1), blend);
4860910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    int r = blend8(SkGetPackedR32(s0), SkGetPackedR32(s1), blend);
4870910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    int g = blend8(SkGetPackedG32(s0), SkGetPackedG32(s1), blend);
4880910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    int b = blend8(SkGetPackedB32(s0), SkGetPackedB32(s1), blend);
4890910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
4900910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    return SkPackARGB32(a, r, g, b);
4910910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#else
4920910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    int otherBlend = 256 - blend;
4930910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
4940910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#if 0
4950910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    U32 t0 = (((s0 & 0xFF00FF) * blend + (s1 & 0xFF00FF) * otherBlend) >> 8) & 0xFF00FF;
4960910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    U32 t1 = (((s0 >> 8) & 0xFF00FF) * blend + ((s1 >> 8) & 0xFF00FF) * otherBlend) & 0xFF00FF00;
4970910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkASSERT((t0 & t1) == 0);
4980910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    return t0 | t1;
4990910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#else
5000910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    return  ((((s0 & 0xFF00FF) * blend + (s1 & 0xFF00FF) * otherBlend) >> 8) & 0xFF00FF) |
5010910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            ((((s0 >> 8) & 0xFF00FF) * blend + ((s1 >> 8) & 0xFF00FF) * otherBlend) & 0xFF00FF00);
5020910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#endif
5030910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
5040910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#endif
5050910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
5060910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
5070910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#define Fixed_To_Dot8(x)        (((x) + 0x80) >> 8)
5080910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
509dba38ba49760ccfd15b2f257f4345e1670f8398aMike Reed/** We take the original colors, not our premultiplied PMColors, since we can
510dba38ba49760ccfd15b2f257f4345e1670f8398aMike Reed    build a 16bit table as long as the original colors are opaque, even if the
511dba38ba49760ccfd15b2f257f4345e1670f8398aMike Reed    paint specifies a non-opaque alpha.
5120910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project*/
51393d11b5b461a8677a8e3ffa94260f4f9897070acMike Reedvoid Gradient_Shader::Build16bitCache(uint16_t cache[], SkColor c0, SkColor c1,
51493d11b5b461a8677a8e3ffa94260f4f9897070acMike Reed                                      int count) {
5150910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkASSERT(count > 1);
5160910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkASSERT(SkColorGetA(c0) == 0xFF);
5170910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkASSERT(SkColorGetA(c1) == 0xFF);
5180910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
5190910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkFixed r = SkColorGetR(c0);
5200910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkFixed g = SkColorGetG(c0);
5210910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkFixed b = SkColorGetB(c0);
5220910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
5230910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkFixed dr = SkIntToFixed(SkColorGetR(c1) - r) / (count - 1);
5240910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkFixed dg = SkIntToFixed(SkColorGetG(c1) - g) / (count - 1);
5250910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkFixed db = SkIntToFixed(SkColorGetB(c1) - b) / (count - 1);
5260910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
5270910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    r = SkIntToFixed(r) + 0x8000;
5280910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    g = SkIntToFixed(g) + 0x8000;
5290910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    b = SkIntToFixed(b) + 0x8000;
5300910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
5310910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    do {
5320910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        unsigned rr = r >> 16;
5330910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        unsigned gg = g >> 16;
5340910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        unsigned bb = b >> 16;
5350910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        cache[0] = SkPackRGB16(SkR32ToR16(rr), SkG32ToG16(gg), SkB32ToB16(bb));
53693d11b5b461a8677a8e3ffa94260f4f9897070acMike Reed        cache[kCache16Count] = SkDitherPack888ToRGB16(rr, gg, bb);
5370910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        cache += 1;
5380910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        r += dr;
5390910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        g += dg;
5400910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        b += db;
5410910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    } while (--count != 0);
5420910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
5430910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
54440528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger/*
54540528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger *  2x2 dither a fixed-point color component (8.16) down to 8, matching the
54640528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger *  semantics of how we 2x2 dither 32->16
54740528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger */
54840528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenbergerstatic inline U8CPU dither_fixed_to_8(SkFixed n) {
54940528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger    n >>= 8;
55040528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger    return ((n << 1) - ((n >> 8 << 8) | (n >> 8))) >> 8;
55140528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger}
55240528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger
55340528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger/*
55440528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger *  For dithering with premultiply, we want to ceiling the alpha component,
55540528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger *  to ensure that it is always >= any color component.
55640528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger */
55740528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenbergerstatic inline U8CPU dither_ceil_fixed_to_8(SkFixed n) {
55840528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger    n >>= 8;
55940528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger    return ((n << 1) - (n | (n >> 8))) >> 8;
56040528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger}
56140528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger
56240528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenbergervoid Gradient_Shader::Build32bitCache(SkPMColor cache[], SkColor c0, SkColor c1,
56340528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger                                      int count, U8CPU paintAlpha) {
5640910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkASSERT(count > 1);
5650910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
566fadb93e0b43c7451032c46f3c58a1effa9d681b3Mike Reed    // need to apply paintAlpha to our two endpoints
567fadb93e0b43c7451032c46f3c58a1effa9d681b3Mike Reed    SkFixed a = SkMulDiv255Round(SkColorGetA(c0), paintAlpha);
568fadb93e0b43c7451032c46f3c58a1effa9d681b3Mike Reed    SkFixed da;
569fadb93e0b43c7451032c46f3c58a1effa9d681b3Mike Reed    {
570fadb93e0b43c7451032c46f3c58a1effa9d681b3Mike Reed        int tmp = SkMulDiv255Round(SkColorGetA(c1), paintAlpha);
571fadb93e0b43c7451032c46f3c58a1effa9d681b3Mike Reed        da = SkIntToFixed(tmp - a) / (count - 1);
572fadb93e0b43c7451032c46f3c58a1effa9d681b3Mike Reed    }
5730910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
574fadb93e0b43c7451032c46f3c58a1effa9d681b3Mike Reed    SkFixed r = SkColorGetR(c0);
575fadb93e0b43c7451032c46f3c58a1effa9d681b3Mike Reed    SkFixed g = SkColorGetG(c0);
576fadb93e0b43c7451032c46f3c58a1effa9d681b3Mike Reed    SkFixed b = SkColorGetB(c0);
577fadb93e0b43c7451032c46f3c58a1effa9d681b3Mike Reed    SkFixed dr = SkIntToFixed(SkColorGetR(c1) - r) / (count - 1);
578fadb93e0b43c7451032c46f3c58a1effa9d681b3Mike Reed    SkFixed dg = SkIntToFixed(SkColorGetG(c1) - g) / (count - 1);
579fadb93e0b43c7451032c46f3c58a1effa9d681b3Mike Reed    SkFixed db = SkIntToFixed(SkColorGetB(c1) - b) / (count - 1);
5800910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
5810910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    a = SkIntToFixed(a) + 0x8000;
5820910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    r = SkIntToFixed(r) + 0x8000;
5830910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    g = SkIntToFixed(g) + 0x8000;
5840910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    b = SkIntToFixed(b) + 0x8000;
5850910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
5860910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    do {
5871cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        cache[0] = SkPremultiplyARGBInline(a >> 16, r >> 16, g >> 16, b >> 16);
5884f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger        cache[kCache32Count] =
5894f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger            SkPremultiplyARGBInline(dither_ceil_fixed_to_8(a),
5904f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger                                    dither_fixed_to_8(r),
5914f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger                                    dither_fixed_to_8(g),
5924f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger                                    dither_fixed_to_8(b));
59340528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger        cache += 1;
5940910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        a += da;
5950910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        r += dr;
5960910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        g += dg;
5970910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        b += db;
5980910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    } while (--count != 0);
5990910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
6000910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
601dba38ba49760ccfd15b2f257f4345e1670f8398aMike Reedstatic inline int SkFixedToFFFF(SkFixed x) {
6020910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkASSERT((unsigned)x <= SK_Fixed1);
6030910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    return x - (x >> 16);
6040910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
6050910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
60693d11b5b461a8677a8e3ffa94260f4f9897070acMike Reedstatic inline U16CPU bitsTo16(unsigned x, const unsigned bits) {
6072c497e64d20a73267eb92ae88fdc51ba2a356b55Mike Reed    SkASSERT(x < (1U << bits));
60893d11b5b461a8677a8e3ffa94260f4f9897070acMike Reed    if (6 == bits) {
60993d11b5b461a8677a8e3ffa94260f4f9897070acMike Reed        return (x << 10) | (x << 4) | (x >> 2);
61093d11b5b461a8677a8e3ffa94260f4f9897070acMike Reed    }
61193d11b5b461a8677a8e3ffa94260f4f9897070acMike Reed    if (8 == bits) {
61293d11b5b461a8677a8e3ffa94260f4f9897070acMike Reed        return (x << 8) | x;
61393d11b5b461a8677a8e3ffa94260f4f9897070acMike Reed    }
61493d11b5b461a8677a8e3ffa94260f4f9897070acMike Reed    sk_throw();
61593d11b5b461a8677a8e3ffa94260f4f9897070acMike Reed    return 0;
6160910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
6170910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
6184f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger/** We duplicate the last value in each half of the cache so that
6194f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger    interpolation doesn't have to special-case being at the last point.
6204f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger*/
6214f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenbergerstatic void complete_16bit_cache(uint16_t* cache, int stride) {
6224f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger    cache[stride - 1] = cache[stride - 2];
6234f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger    cache[2 * stride - 1] = cache[2 * stride - 2];
6244f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger}
6254f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger
62605b6b4d746867a9fb02e14edfe1bf3685abeb813Derek Sollenbergerconst uint16_t* Gradient_Shader::getCache16() const {
627dba38ba49760ccfd15b2f257f4345e1670f8398aMike Reed    if (fCache16 == NULL) {
62840528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger        // double the count for dither entries
62940528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger        const int entryCount = kCache16Count * 2;
63040528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger        const size_t allocSize = sizeof(uint16_t) * entryCount;
63140528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger
6322e8fbf0f64801962778aa2d0e0177a8be4c03d89Mike Reed        if (fCache16Storage == NULL) { // set the storage and our working ptr
63340528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger            fCache16Storage = (uint16_t*)sk_malloc_throw(allocSize);
6342e8fbf0f64801962778aa2d0e0177a8be4c03d89Mike Reed        }
6350910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        fCache16 = fCache16Storage;
636dba38ba49760ccfd15b2f257f4345e1670f8398aMike Reed        if (fColorCount == 2) {
6374f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger            Build16bitCache(fCache16, fOrigColors[0], fOrigColors[1],
6384f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger                            kGradient16Length);
639dba38ba49760ccfd15b2f257f4345e1670f8398aMike Reed        } else {
6400910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            Rec* rec = fRecs;
6410910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            int prevIndex = 0;
642dba38ba49760ccfd15b2f257f4345e1670f8398aMike Reed            for (int i = 1; i < fColorCount; i++) {
64393d11b5b461a8677a8e3ffa94260f4f9897070acMike Reed                int nextIndex = SkFixedToFFFF(rec[i].fPos) >> kCache16Shift;
6440910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                SkASSERT(nextIndex < kCache16Count);
6450910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
6460910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                if (nextIndex > prevIndex)
64793d11b5b461a8677a8e3ffa94260f4f9897070acMike Reed                    Build16bitCache(fCache16 + prevIndex, fOrigColors[i-1], fOrigColors[i], nextIndex - prevIndex + 1);
6480910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                prevIndex = nextIndex;
6490910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            }
6504f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger            // one extra space left over at the end for complete_16bit_cache()
6514f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger            SkASSERT(prevIndex == kGradient16Length - 1);
6520910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        }
6530910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
654dba38ba49760ccfd15b2f257f4345e1670f8398aMike Reed        if (fMapper) {
65540528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger            fCache16Storage = (uint16_t*)sk_malloc_throw(allocSize);
6560910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            uint16_t* linear = fCache16;         // just computed linear data
6570910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            uint16_t* mapped = fCache16Storage;  // storage for mapped data
6580910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            SkUnitMapper* map = fMapper;
6594f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger            for (int i = 0; i < kGradient16Length; i++) {
66093d11b5b461a8677a8e3ffa94260f4f9897070acMike Reed                int index = map->mapUnit16(bitsTo16(i, kCache16Bits)) >> kCache16Shift;
6610910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                mapped[i] = linear[index];
66293d11b5b461a8677a8e3ffa94260f4f9897070acMike Reed                mapped[i + kCache16Count] = linear[index + kCache16Count];
6630910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            }
6640910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            sk_free(fCache16);
6650910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            fCache16 = fCache16Storage;
6660910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        }
6674f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger        complete_16bit_cache(fCache16, kCache16Count);
6680910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
6690910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    return fCache16;
6700910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
6710910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
6724f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger/** We duplicate the last value in each half of the cache so that
6734f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger    interpolation doesn't have to special-case being at the last point.
6744f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger*/
6754f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenbergerstatic void complete_32bit_cache(SkPMColor* cache, int stride) {
6764f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger    cache[stride - 1] = cache[stride - 2];
6774f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger    cache[2 * stride - 1] = cache[2 * stride - 2];
6784f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger}
6794f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger
68005b6b4d746867a9fb02e14edfe1bf3685abeb813Derek Sollenbergerconst SkPMColor* Gradient_Shader::getCache32() const {
681dba38ba49760ccfd15b2f257f4345e1670f8398aMike Reed    if (fCache32 == NULL) {
68240528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger        // double the count for dither entries
68340528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger        const int entryCount = kCache32Count * 2;
68440528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger        const size_t allocSize = sizeof(SkPMColor) * entryCount;
6850910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
68640528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger        if (NULL == fCache32PixelRef) {
68740528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger            fCache32PixelRef = SkNEW_ARGS(SkMallocPixelRef,
68840528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger                                          (NULL, allocSize, NULL));
68940528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger        }
69040528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger        fCache32 = (SkPMColor*)fCache32PixelRef->getAddr();
691dba38ba49760ccfd15b2f257f4345e1670f8398aMike Reed        if (fColorCount == 2) {
69240528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger            Build32bitCache(fCache32, fOrigColors[0], fOrigColors[1],
6934f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger                            kGradient32Length, fCacheAlpha);
694dba38ba49760ccfd15b2f257f4345e1670f8398aMike Reed        } else {
6950910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            Rec* rec = fRecs;
6960910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            int prevIndex = 0;
697dba38ba49760ccfd15b2f257f4345e1670f8398aMike Reed            for (int i = 1; i < fColorCount; i++) {
6981cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                int nextIndex = SkFixedToFFFF(rec[i].fPos) >> kCache32Shift;
6994f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger                SkASSERT(nextIndex < kGradient32Length);
7000910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
7010910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                if (nextIndex > prevIndex)
70240528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger                    Build32bitCache(fCache32 + prevIndex, fOrigColors[i-1],
70340528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger                                    fOrigColors[i],
70440528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger                                    nextIndex - prevIndex + 1, fCacheAlpha);
7050910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                prevIndex = nextIndex;
7060910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            }
7074f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger            SkASSERT(prevIndex == kGradient32Length - 1);
7080910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        }
7090910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
710dba38ba49760ccfd15b2f257f4345e1670f8398aMike Reed        if (fMapper) {
71140528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger            SkMallocPixelRef* newPR = SkNEW_ARGS(SkMallocPixelRef,
71240528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger                                                 (NULL, allocSize, NULL));
7130910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            SkPMColor* linear = fCache32;           // just computed linear data
71440528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger            SkPMColor* mapped = (SkPMColor*)newPR->getAddr();    // storage for mapped data
7150910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            SkUnitMapper* map = fMapper;
7164f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger            for (int i = 0; i < kGradient32Length; i++) {
71740528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger                int index = map->mapUnit16((i << 8) | i) >> 8;
71840528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger                mapped[i] = linear[index];
71940528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger                mapped[i + kCache32Count] = linear[index + kCache32Count];
720dba38ba49760ccfd15b2f257f4345e1670f8398aMike Reed            }
72140528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger            fCache32PixelRef->unref();
72240528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger            fCache32PixelRef = newPR;
72340528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger            fCache32 = (SkPMColor*)newPR->getAddr();
7240910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        }
7254f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger        complete_32bit_cache(fCache32, kCache32Count);
7260910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
7270910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    return fCache32;
7280910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
7290910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
73040528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger/*
73140528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger *  Because our caller might rebuild the same (logically the same) gradient
73240528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger *  over and over, we'd like to return exactly the same "bitmap" if possible,
73340528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger *  allowing the client to utilize a cache of our bitmap (e.g. with a GPU).
73440528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger *  To do that, we maintain a private cache of built-bitmaps, based on our
73540528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger *  colors and positions. Note: we don't try to flatten the fMapper, so if one
73640528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger *  is present, we skip the cache for now.
73740528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger */
73805b6b4d746867a9fb02e14edfe1bf3685abeb813Derek Sollenbergervoid Gradient_Shader::commonAsABitmap(SkBitmap* bitmap) const {
7391cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    // our caller assumes no external alpha, so we ensure that our cache is
7401cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    // built with 0xFF
7411cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    this->setCacheAlpha(0xFF);
7421cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger
74340528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger    // don't have a way to put the mapper into our cache-key yet
74440528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger    if (fMapper) {
74540528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger        // force our cahce32pixelref to be built
74640528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger        (void)this->getCache32();
7474f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger        bitmap->setConfig(SkBitmap::kARGB_8888_Config, kGradient32Length, 1);
74840528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger        bitmap->setPixelRef(fCache32PixelRef);
74940528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger        return;
75040528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger    }
75140528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger
75240528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger    // build our key: [numColors + colors[] + {positions[]} ]
75340528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger    int count = 1 + fColorCount;
75440528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger    if (fColorCount > 2) {
75540528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger        count += fColorCount - 1;    // fRecs[].fPos
75640528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger    }
75740528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger
75840528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger    SkAutoSTMalloc<16, int32_t> storage(count);
75940528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger    int32_t* buffer = storage.get();
76040528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger
76140528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger    *buffer++ = fColorCount;
76240528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger    memcpy(buffer, fOrigColors, fColorCount * sizeof(SkColor));
76340528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger    buffer += fColorCount;
76440528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger    if (fColorCount > 2) {
76540528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger        for (int i = 1; i < fColorCount; i++) {
76640528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger            *buffer++ = fRecs[i].fPos;
76740528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger        }
76840528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger    }
76940528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger    SkASSERT(buffer - storage.get() == count);
77040528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger
77140528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger    ///////////////////////////////////
77240528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger
7734f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger    SK_DECLARE_STATIC_MUTEX(gMutex);
77440528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger    static SkBitmapCache* gCache;
77540528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger    // each cache cost 1K of RAM, since each bitmap will be 1x256 at 32bpp
77640528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger    static const int MAX_NUM_CACHED_GRADIENT_BITMAPS = 32;
77740528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger    SkAutoMutexAcquire ama(gMutex);
77840528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger
77940528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger    if (NULL == gCache) {
78040528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger        gCache = new SkBitmapCache(MAX_NUM_CACHED_GRADIENT_BITMAPS);
78140528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger    }
78240528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger    size_t size = count * sizeof(int32_t);
78340528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger
78440528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger    if (!gCache->find(storage.get(), size, bitmap)) {
78540528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger        // force our cahce32pixelref to be built
78640528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger        (void)this->getCache32();
7874f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger        // Only expose the linear section of the cache; don't let the caller
7884f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger        // know about the padding at the end to make interpolation faster.
7894f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger        bitmap->setConfig(SkBitmap::kARGB_8888_Config, kGradient32Length, 1);
79040528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger        bitmap->setPixelRef(fCache32PixelRef);
79140528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger
79240528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger        gCache->add(storage.get(), size, *bitmap);
79340528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger    }
79440528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger}
79540528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger
79605b6b4d746867a9fb02e14edfe1bf3685abeb813Derek Sollenbergervoid Gradient_Shader::commonAsAGradient(GradientInfo* info) const {
79705b6b4d746867a9fb02e14edfe1bf3685abeb813Derek Sollenberger    if (info) {
79805b6b4d746867a9fb02e14edfe1bf3685abeb813Derek Sollenberger        if (info->fColorCount >= fColorCount) {
79905b6b4d746867a9fb02e14edfe1bf3685abeb813Derek Sollenberger            if (info->fColors) {
80005b6b4d746867a9fb02e14edfe1bf3685abeb813Derek Sollenberger                memcpy(info->fColors, fOrigColors,
80105b6b4d746867a9fb02e14edfe1bf3685abeb813Derek Sollenberger                       fColorCount * sizeof(SkColor));
80205b6b4d746867a9fb02e14edfe1bf3685abeb813Derek Sollenberger            }
80305b6b4d746867a9fb02e14edfe1bf3685abeb813Derek Sollenberger            if (info->fColorOffsets) {
80405b6b4d746867a9fb02e14edfe1bf3685abeb813Derek Sollenberger                if (fColorCount == 2) {
80505b6b4d746867a9fb02e14edfe1bf3685abeb813Derek Sollenberger                    info->fColorOffsets[0] = 0;
80605b6b4d746867a9fb02e14edfe1bf3685abeb813Derek Sollenberger                    info->fColorOffsets[1] = SK_Scalar1;
80705b6b4d746867a9fb02e14edfe1bf3685abeb813Derek Sollenberger                } else if (fColorCount > 2) {
80805b6b4d746867a9fb02e14edfe1bf3685abeb813Derek Sollenberger                    for (int i = 0; i < fColorCount; i++)
80905b6b4d746867a9fb02e14edfe1bf3685abeb813Derek Sollenberger                        info->fColorOffsets[i] = SkFixedToScalar(fRecs[i].fPos);
81005b6b4d746867a9fb02e14edfe1bf3685abeb813Derek Sollenberger                }
81105b6b4d746867a9fb02e14edfe1bf3685abeb813Derek Sollenberger            }
81205b6b4d746867a9fb02e14edfe1bf3685abeb813Derek Sollenberger        }
81305b6b4d746867a9fb02e14edfe1bf3685abeb813Derek Sollenberger        info->fColorCount = fColorCount;
81405b6b4d746867a9fb02e14edfe1bf3685abeb813Derek Sollenberger        info->fTileMode = fTileMode;
81505b6b4d746867a9fb02e14edfe1bf3685abeb813Derek Sollenberger    }
81605b6b4d746867a9fb02e14edfe1bf3685abeb813Derek Sollenberger}
81705b6b4d746867a9fb02e14edfe1bf3685abeb813Derek Sollenberger
81835e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger///////////////////////////////////////////////////////////////////////////////
8190910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
820dba38ba49760ccfd15b2f257f4345e1670f8398aMike Reedstatic void pts_to_unit_matrix(const SkPoint pts[2], SkMatrix* matrix) {
8210910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkVector    vec = pts[1] - pts[0];
8220910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkScalar    mag = vec.length();
8230910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkScalar    inv = mag ? SkScalarInvert(mag) : 0;
8240910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
8250910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    vec.scale(inv);
8260910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    matrix->setSinCos(-vec.fY, vec.fX, pts[0].fX, pts[0].fY);
8270910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    matrix->postTranslate(-pts[0].fX, -pts[0].fY);
8280910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    matrix->postScale(inv, inv);
8290910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
8300910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
8310910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project///////////////////////////////////////////////////////////////////////////////
8320910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
8330910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectclass Linear_Gradient : public Gradient_Shader {
8340910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectpublic:
8350910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    Linear_Gradient(const SkPoint pts[2],
8360910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                    const SkColor colors[], const SkScalar pos[], int colorCount,
8370910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                    SkShader::TileMode mode, SkUnitMapper* mapper)
83805b6b4d746867a9fb02e14edfe1bf3685abeb813Derek Sollenberger        : Gradient_Shader(colors, pos, colorCount, mode, mapper),
83905b6b4d746867a9fb02e14edfe1bf3685abeb813Derek Sollenberger          fStart(pts[0]),
84005b6b4d746867a9fb02e14edfe1bf3685abeb813Derek Sollenberger          fEnd(pts[1])
8410910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    {
8420910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        pts_to_unit_matrix(pts, &fPtsToUnit);
8430910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
84479377cbceeea970b663e7934d7cb1f27bb223d98Mike Reed
8451cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    virtual bool setContext(const SkBitmap&, const SkPaint&, const SkMatrix&) SK_OVERRIDE;
8461cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    virtual void shadeSpan(int x, int y, SkPMColor dstC[], int count) SK_OVERRIDE;
8471cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    virtual void shadeSpan16(int x, int y, uint16_t dstC[], int count) SK_OVERRIDE;
8481cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    virtual BitmapType asABitmap(SkBitmap*, SkMatrix*, TileMode*,
8491cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                             SkScalar* twoPointRadialParams) const SK_OVERRIDE;
8501cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    virtual GradientType asAGradient(GradientInfo* info) const SK_OVERRIDE;
8510910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
85240528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger    static SkFlattenable* CreateProc(SkFlattenableReadBuffer& buffer) {
8530910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        return SkNEW_ARGS(Linear_Gradient, (buffer));
8540910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
8550910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
8561cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    virtual void flatten(SkFlattenableWriteBuffer& buffer) SK_OVERRIDE {
85705b6b4d746867a9fb02e14edfe1bf3685abeb813Derek Sollenberger        this->INHERITED::flatten(buffer);
85805b6b4d746867a9fb02e14edfe1bf3685abeb813Derek Sollenberger        buffer.writeScalar(fStart.fX);
85905b6b4d746867a9fb02e14edfe1bf3685abeb813Derek Sollenberger        buffer.writeScalar(fStart.fY);
86005b6b4d746867a9fb02e14edfe1bf3685abeb813Derek Sollenberger        buffer.writeScalar(fEnd.fX);
86105b6b4d746867a9fb02e14edfe1bf3685abeb813Derek Sollenberger        buffer.writeScalar(fEnd.fY);
86205b6b4d746867a9fb02e14edfe1bf3685abeb813Derek Sollenberger    }
86305b6b4d746867a9fb02e14edfe1bf3685abeb813Derek Sollenberger
8641cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    SK_DECLARE_FLATTENABLE_REGISTRAR()
8651cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger
8660910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectprotected:
86705b6b4d746867a9fb02e14edfe1bf3685abeb813Derek Sollenberger    Linear_Gradient(SkFlattenableReadBuffer& buffer)
86805b6b4d746867a9fb02e14edfe1bf3685abeb813Derek Sollenberger        : Gradient_Shader(buffer),
86935e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger          fStart(unflatten_point(buffer)),
87035e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger          fEnd(unflatten_point(buffer)) {
87105b6b4d746867a9fb02e14edfe1bf3685abeb813Derek Sollenberger    }
8721cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    virtual Factory getFactory() SK_OVERRIDE { return CreateProc; }
8730910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
8740910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectprivate:
8750910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    typedef Gradient_Shader INHERITED;
87605b6b4d746867a9fb02e14edfe1bf3685abeb813Derek Sollenberger    const SkPoint fStart;
87705b6b4d746867a9fb02e14edfe1bf3685abeb813Derek Sollenberger    const SkPoint fEnd;
8780910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project};
8790910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
880f294d10d594ac335ea3bd09caec89004d41edc5cMike Reedbool Linear_Gradient::setContext(const SkBitmap& device, const SkPaint& paint,
881f294d10d594ac335ea3bd09caec89004d41edc5cMike Reed                                 const SkMatrix& matrix) {
882f294d10d594ac335ea3bd09caec89004d41edc5cMike Reed    if (!this->INHERITED::setContext(device, paint, matrix)) {
883f294d10d594ac335ea3bd09caec89004d41edc5cMike Reed        return false;
884f294d10d594ac335ea3bd09caec89004d41edc5cMike Reed    }
885f294d10d594ac335ea3bd09caec89004d41edc5cMike Reed
886f294d10d594ac335ea3bd09caec89004d41edc5cMike Reed    unsigned mask = SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask;
887f294d10d594ac335ea3bd09caec89004d41edc5cMike Reed    if ((fDstToIndex.getType() & ~mask) == 0) {
8882e8fbf0f64801962778aa2d0e0177a8be4c03d89Mike Reed        fFlags |= SkShader::kConstInY32_Flag;
8892e8fbf0f64801962778aa2d0e0177a8be4c03d89Mike Reed        if ((fFlags & SkShader::kHasSpan16_Flag) && !paint.isDither()) {
8902e8fbf0f64801962778aa2d0e0177a8be4c03d89Mike Reed            // only claim this if we do have a 16bit mode (i.e. none of our
8912e8fbf0f64801962778aa2d0e0177a8be4c03d89Mike Reed            // colors have alpha), and if we are not dithering (which obviously
8922e8fbf0f64801962778aa2d0e0177a8be4c03d89Mike Reed            // is not const in Y).
8932e8fbf0f64801962778aa2d0e0177a8be4c03d89Mike Reed            fFlags |= SkShader::kConstInY16_Flag;
8942e8fbf0f64801962778aa2d0e0177a8be4c03d89Mike Reed        }
895f294d10d594ac335ea3bd09caec89004d41edc5cMike Reed    }
896f294d10d594ac335ea3bd09caec89004d41edc5cMike Reed    return true;
897f294d10d594ac335ea3bd09caec89004d41edc5cMike Reed}
898f294d10d594ac335ea3bd09caec89004d41edc5cMike Reed
89935e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger#define NO_CHECK_ITER               \
90035e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger    do {                            \
9011cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    unsigned fi = fx >> Gradient_Shader::kCache32Shift; \
90235e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger    SkASSERT(fi <= 0xFF);           \
90335e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger    fx += dx;                       \
90435e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger    *dstC++ = cache[toggle + fi];   \
9054f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger    toggle ^= Gradient_Shader::kDitherStride32; \
90635e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger    } while (0)
90735e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger
9081cab2921ab279367f8206cdadc9259d12e603548Derek Sollenbergernamespace {
9091cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger
9101cab2921ab279367f8206cdadc9259d12e603548Derek Sollenbergertypedef void (*LinearShadeProc)(TileProc proc, SkFixed dx, SkFixed fx,
9114f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger                                SkPMColor* dstC, const SkPMColor* cache,
9121cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                                int toggle, int count);
9131cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger
9144f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger// This function is deprecated, and will be replaced by
9154f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger// shadeSpan_linear_vertical_lerp() once Chrome has been weaned off of it.
9161cab2921ab279367f8206cdadc9259d12e603548Derek Sollenbergervoid shadeSpan_linear_vertical(TileProc proc, SkFixed dx, SkFixed fx,
9171cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                               SkPMColor* SK_RESTRICT dstC,
9181cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                               const SkPMColor* SK_RESTRICT cache,
9191cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                               int toggle, int count) {
9204f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger    // We're a vertical gradient, so no change in a span.
9214f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger    // If colors change sharply across the gradient, dithering is
9224f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger    // insufficient (it subsamples the color space) and we need to lerp.
9234f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger    unsigned fullIndex = proc(fx);
9244f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger    unsigned fi = fullIndex >> (16 - Gradient_Shader::kCache32Bits);
9254f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger    sk_memset32_dither(dstC,
9264f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger            cache[toggle + fi],
9274f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger            cache[(toggle ^ Gradient_Shader::kDitherStride32) + fi],
9284f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger            count);
9294f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger}
9301cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger
9314f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger// Linear interpolation (lerp) is unnecessary if there are no sharp
9324f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger// discontinuities in the gradient - which must be true if there are
9334f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger// only 2 colors - but it's cheap.
9344f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenbergervoid shadeSpan_linear_vertical_lerp(TileProc proc, SkFixed dx, SkFixed fx,
9354f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger                                    SkPMColor* SK_RESTRICT dstC,
9364f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger                                    const SkPMColor* SK_RESTRICT cache,
9374f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger                                    int toggle, int count) {
9384f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger    // We're a vertical gradient, so no change in a span.
9394f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger    // If colors change sharply across the gradient, dithering is
9404f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger    // insufficient (it subsamples the color space) and we need to lerp.
9414f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger    unsigned fullIndex = proc(fx);
9424f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger    unsigned fi = fullIndex >> (16 - Gradient_Shader::kCache32Bits);
9434f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger    unsigned remainder = fullIndex & Gradient_Shader::kLerpRemainderMask32;
9444f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger    SkPMColor lerp =
9454f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger        SkFastFourByteInterp(
9464f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger            cache[toggle + fi + 1],
9474f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger            cache[toggle + fi], remainder);
9484f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger    SkPMColor dlerp =
9494f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger        SkFastFourByteInterp(
9504f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger            cache[(toggle ^ Gradient_Shader::kDitherStride32) + fi + 1],
9514f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger            cache[(toggle ^ Gradient_Shader::kDitherStride32) + fi], remainder);
9524f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger    sk_memset32_dither(dstC, lerp, dlerp, count);
9531cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger}
9541cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger
9551cab2921ab279367f8206cdadc9259d12e603548Derek Sollenbergervoid shadeSpan_linear_clamp(TileProc proc, SkFixed dx, SkFixed fx,
9561cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                            SkPMColor* SK_RESTRICT dstC,
9571cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                            const SkPMColor* SK_RESTRICT cache,
9581cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                            int toggle, int count) {
9591cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    SkClampRange range;
9604f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger    range.init(fx, dx, count, 0, Gradient_Shader::kGradient32Length);
9611cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger
9621cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    if ((count = range.fCount0) > 0) {
9631cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        sk_memset32_dither(dstC,
9641cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger            cache[toggle + range.fV0],
9654f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger            cache[(toggle ^ Gradient_Shader::kDitherStride32) + range.fV0],
9661cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger            count);
9671cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        dstC += count;
9681cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    }
9691cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    if ((count = range.fCount1) > 0) {
9701cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        int unroll = count >> 3;
9711cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        fx = range.fFx1;
9721cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        for (int i = 0; i < unroll; i++) {
9731cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger            NO_CHECK_ITER;  NO_CHECK_ITER;
9741cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger            NO_CHECK_ITER;  NO_CHECK_ITER;
9751cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger            NO_CHECK_ITER;  NO_CHECK_ITER;
9761cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger            NO_CHECK_ITER;  NO_CHECK_ITER;
9771cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        }
9781cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        if ((count &= 7) > 0) {
9791cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger            do {
9801cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                NO_CHECK_ITER;
9811cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger            } while (--count != 0);
9821cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        }
9831cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    }
9841cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    if ((count = range.fCount2) > 0) {
9851cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        sk_memset32_dither(dstC,
9861cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger            cache[toggle + range.fV1],
9874f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger            cache[(toggle ^ Gradient_Shader::kDitherStride32) + range.fV1],
9881cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger            count);
9891cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    }
9901cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger}
9911cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger
9921cab2921ab279367f8206cdadc9259d12e603548Derek Sollenbergervoid shadeSpan_linear_mirror(TileProc proc, SkFixed dx, SkFixed fx,
9931cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                             SkPMColor* SK_RESTRICT dstC,
9941cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                             const SkPMColor* SK_RESTRICT cache,
9951cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                             int toggle, int count) {
9961cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    do {
9971cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        unsigned fi = mirror_8bits(fx >> 8);
9981cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        SkASSERT(fi <= 0xFF);
9991cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        fx += dx;
10001cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        *dstC++ = cache[toggle + fi];
10014f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger        toggle ^= Gradient_Shader::kDitherStride32;
10021cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    } while (--count != 0);
10031cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger}
100435e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger
10051cab2921ab279367f8206cdadc9259d12e603548Derek Sollenbergervoid shadeSpan_linear_repeat(TileProc proc, SkFixed dx, SkFixed fx,
10061cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        SkPMColor* SK_RESTRICT dstC,
10071cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        const SkPMColor* SK_RESTRICT cache,
10081cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        int toggle, int count) {
10091cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    do {
10101cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        unsigned fi = repeat_8bits(fx >> 8);
10111cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        SkASSERT(fi <= 0xFF);
10121cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        fx += dx;
10131cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        *dstC++ = cache[toggle + fi];
10144f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger        toggle ^= Gradient_Shader::kDitherStride32;
10151cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    } while (--count != 0);
10161cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger}
10174f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger
10181cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger}
10191cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger
10201cab2921ab279367f8206cdadc9259d12e603548Derek Sollenbergervoid Linear_Gradient::shadeSpan(int x, int y, SkPMColor* SK_RESTRICT dstC,
10211cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                                int count) {
10220910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkASSERT(count > 0);
10230910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
10240910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkPoint             srcPt;
10250910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkMatrix::MapXYProc dstProc = fDstToIndexProc;
10260910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    TileProc            proc = fTileProc;
10271cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    const SkPMColor* SK_RESTRICT cache = this->getCache32();
102840528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger#ifdef USE_DITHER_32BIT_GRADIENT
10294f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger    int                 toggle = ((x ^ y) & 1) * kDitherStride32;
103040528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger#else
103140528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger    int toggle = 0;
103240528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger#endif
10330910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
1034f294d10d594ac335ea3bd09caec89004d41edc5cMike Reed    if (fDstToIndexClass != kPerspective_MatrixClass) {
103540528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger        dstProc(fDstToIndex, SkIntToScalar(x) + SK_ScalarHalf,
103640528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger                             SkIntToScalar(y) + SK_ScalarHalf, &srcPt);
10370910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        SkFixed dx, fx = SkScalarToFixed(srcPt.fX);
10380910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
1039f294d10d594ac335ea3bd09caec89004d41edc5cMike Reed        if (fDstToIndexClass == kFixedStepInX_MatrixClass) {
10400910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            SkFixed dxStorage[1];
10410910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            (void)fDstToIndex.fixedStepInX(SkIntToScalar(y), dxStorage, NULL);
10420910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            dx = dxStorage[0];
1043f294d10d594ac335ea3bd09caec89004d41edc5cMike Reed        } else {
10440910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            SkASSERT(fDstToIndexClass == kLinear_MatrixClass);
10450910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            dx = SkScalarToFixed(fDstToIndex.getScaleX());
10460910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        }
10470910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
10481cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        LinearShadeProc shadeProc = shadeSpan_linear_repeat;
1049faa8dc5be4452ffc0e189e44734c075652158d7dDerek Sollenberger        // We really should check the endpoint colors, but short of that change
1050faa8dc5be4452ffc0e189e44734c075652158d7dDerek Sollenberger        // we reduce the tolerance of SkFixedNearlyZero to be more restrictive.
1051faa8dc5be4452ffc0e189e44734c075652158d7dDerek Sollenberger        if (SkFixedNearlyZero(dx, (SK_Fixed1 >> 14))) {
10524f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger#ifdef SK_SIMPLE_TWOCOLOR_VERTICAL_GRADIENTS
10534f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger            if (fColorCount > 2) {
10544f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger                shadeProc = shadeSpan_linear_vertical_lerp;
10554f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger            } else {
10564f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger                shadeProc = shadeSpan_linear_vertical;
10574f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger            }
10584f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger#else
10594f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger            shadeProc = shadeSpan_linear_vertical_lerp;
10604f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger#endif
1061f294d10d594ac335ea3bd09caec89004d41edc5cMike Reed        } else if (proc == clamp_tileproc) {
10621cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger            shadeProc = shadeSpan_linear_clamp;
1063f294d10d594ac335ea3bd09caec89004d41edc5cMike Reed        } else if (proc == mirror_tileproc) {
10641cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger            shadeProc = shadeSpan_linear_mirror;
1065f294d10d594ac335ea3bd09caec89004d41edc5cMike Reed        } else {
10660910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            SkASSERT(proc == repeat_tileproc);
10670910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        }
10681cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        (*shadeProc)(proc, dx, fx, dstC, cache, toggle, count);
1069f294d10d594ac335ea3bd09caec89004d41edc5cMike Reed    } else {
10700910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        SkScalar    dstX = SkIntToScalar(x);
10710910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        SkScalar    dstY = SkIntToScalar(y);
10720910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        do {
10730910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            dstProc(fDstToIndex, dstX, dstY, &srcPt);
10740910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            unsigned fi = proc(SkScalarToFixed(srcPt.fX));
10750910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            SkASSERT(fi <= 0xFFFF);
10761cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger            *dstC++ = cache[toggle + (fi >> kCache32Shift)];
10774f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger            toggle ^= Gradient_Shader::kDitherStride32;
10780910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            dstX += SK_Scalar1;
10790910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        } while (--count != 0);
10800910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
10810910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
10820910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
108340528743dbb9ce7f39f093e0cdc47849ac8887cfDerek SollenbergerSkShader::BitmapType Linear_Gradient::asABitmap(SkBitmap* bitmap,
108440528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger                                                SkMatrix* matrix,
108540528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger                                                TileMode xy[],
108605b6b4d746867a9fb02e14edfe1bf3685abeb813Derek Sollenberger                                        SkScalar* twoPointRadialParams) const {
10870910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    if (bitmap) {
108840528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger        this->commonAsABitmap(bitmap);
10890910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
10900910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    if (matrix) {
10914f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger        matrix->setScale(SkIntToScalar(kGradient32Length), SK_Scalar1);
10920910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        matrix->preConcat(fPtsToUnit);
10930910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
10940910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    if (xy) {
10950910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        xy[0] = fTileMode;
10960910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        xy[1] = kClamp_TileMode;
10970910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
109840528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger    return kDefault_BitmapType;
10990910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
11000910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
110105b6b4d746867a9fb02e14edfe1bf3685abeb813Derek SollenbergerSkShader::GradientType Linear_Gradient::asAGradient(GradientInfo* info) const {
110205b6b4d746867a9fb02e14edfe1bf3685abeb813Derek Sollenberger    if (info) {
110305b6b4d746867a9fb02e14edfe1bf3685abeb813Derek Sollenberger        commonAsAGradient(info);
110405b6b4d746867a9fb02e14edfe1bf3685abeb813Derek Sollenberger        info->fPoint[0] = fStart;
110505b6b4d746867a9fb02e14edfe1bf3685abeb813Derek Sollenberger        info->fPoint[1] = fEnd;
110605b6b4d746867a9fb02e14edfe1bf3685abeb813Derek Sollenberger    }
110705b6b4d746867a9fb02e14edfe1bf3685abeb813Derek Sollenberger    return kLinear_GradientType;
110805b6b4d746867a9fb02e14edfe1bf3685abeb813Derek Sollenberger}
110905b6b4d746867a9fb02e14edfe1bf3685abeb813Derek Sollenberger
11102e8fbf0f64801962778aa2d0e0177a8be4c03d89Mike Reedstatic void dither_memset16(uint16_t dst[], uint16_t value, uint16_t other,
11112e8fbf0f64801962778aa2d0e0177a8be4c03d89Mike Reed                            int count) {
11122e8fbf0f64801962778aa2d0e0177a8be4c03d89Mike Reed    if (reinterpret_cast<uintptr_t>(dst) & 2) {
11130910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        *dst++ = value;
11140910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        count -= 1;
11150910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        SkTSwap(value, other);
11160910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
11170910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
11180910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    sk_memset32((uint32_t*)dst, (value << 16) | other, count >> 1);
111940528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger
11202e8fbf0f64801962778aa2d0e0177a8be4c03d89Mike Reed    if (count & 1) {
11210910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        dst[count - 1] = value;
11222e8fbf0f64801962778aa2d0e0177a8be4c03d89Mike Reed    }
11230910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
11240910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
112535e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger#define NO_CHECK_ITER_16                \
112635e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger    do {                                \
11271cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    unsigned fi = fx >> Gradient_Shader::kCache16Shift;  \
11284f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger    SkASSERT(fi < Gradient_Shader::kCache16Count);       \
112935e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger    fx += dx;                           \
113035e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger    *dstC++ = cache[toggle + fi];       \
11314f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger    toggle ^= Gradient_Shader::kDitherStride16;            \
113235e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger    } while (0)
113335e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger
11341cab2921ab279367f8206cdadc9259d12e603548Derek Sollenbergernamespace {
11351cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger
11361cab2921ab279367f8206cdadc9259d12e603548Derek Sollenbergertypedef void (*LinearShade16Proc)(TileProc proc, SkFixed dx, SkFixed fx,
11374f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger                                  uint16_t* dstC, const uint16_t* cache,
11381cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                                  int toggle, int count);
11391cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger
11401cab2921ab279367f8206cdadc9259d12e603548Derek Sollenbergervoid shadeSpan16_linear_vertical(TileProc proc, SkFixed dx, SkFixed fx,
11411cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                                 uint16_t* SK_RESTRICT dstC,
11421cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                                 const uint16_t* SK_RESTRICT cache,
11431cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                                 int toggle, int count) {
11441cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    // we're a vertical gradient, so no change in a span
11451cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    unsigned fi = proc(fx) >> Gradient_Shader::kCache16Shift;
11464f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger    SkASSERT(fi < Gradient_Shader::kCache16Count);
11471cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    dither_memset16(dstC, cache[toggle + fi],
11484f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger        cache[(toggle ^ Gradient_Shader::kDitherStride16) + fi], count);
11491cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger
11501cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger}
11511cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger
11521cab2921ab279367f8206cdadc9259d12e603548Derek Sollenbergervoid shadeSpan16_linear_clamp(TileProc proc, SkFixed dx, SkFixed fx,
11531cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                              uint16_t* SK_RESTRICT dstC,
11541cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                              const uint16_t* SK_RESTRICT cache,
11551cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                              int toggle, int count) {
11561cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    SkClampRange range;
11574f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger    range.init(fx, dx, count, 0, Gradient_Shader::kGradient16Length);
11581cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger
11591cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    if ((count = range.fCount0) > 0) {
11601cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        dither_memset16(dstC,
11611cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger            cache[toggle + range.fV0],
11624f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger            cache[(toggle ^ Gradient_Shader::kDitherStride16) + range.fV0],
11631cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger            count);
11641cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        dstC += count;
11651cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    }
11661cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    if ((count = range.fCount1) > 0) {
11671cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        int unroll = count >> 3;
11681cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        fx = range.fFx1;
11691cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        for (int i = 0; i < unroll; i++) {
11701cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger            NO_CHECK_ITER_16;  NO_CHECK_ITER_16;
11711cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger            NO_CHECK_ITER_16;  NO_CHECK_ITER_16;
11721cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger            NO_CHECK_ITER_16;  NO_CHECK_ITER_16;
11731cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger            NO_CHECK_ITER_16;  NO_CHECK_ITER_16;
11741cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        }
11751cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        if ((count &= 7) > 0) {
11761cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger            do {
11771cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                NO_CHECK_ITER_16;
11781cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger            } while (--count != 0);
11791cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        }
11801cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    }
11811cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    if ((count = range.fCount2) > 0) {
11821cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        dither_memset16(dstC,
11831cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger            cache[toggle + range.fV1],
11844f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger            cache[(toggle ^ Gradient_Shader::kDitherStride16) + range.fV1],
11851cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger            count);
11861cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    }
11871cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger}
11881cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger
11891cab2921ab279367f8206cdadc9259d12e603548Derek Sollenbergervoid shadeSpan16_linear_mirror(TileProc proc, SkFixed dx, SkFixed fx,
11901cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                               uint16_t* SK_RESTRICT dstC,
11911cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                               const uint16_t* SK_RESTRICT cache,
11921cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                               int toggle, int count) {
11931cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    do {
11941cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        unsigned fi = mirror_bits(fx >> Gradient_Shader::kCache16Shift,
11951cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                                        Gradient_Shader::kCache16Bits);
11964f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger        SkASSERT(fi < Gradient_Shader::kCache16Count);
11971cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        fx += dx;
11981cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        *dstC++ = cache[toggle + fi];
11994f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger        toggle ^= Gradient_Shader::kDitherStride16;
12001cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    } while (--count != 0);
12011cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger}
12021cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger
12031cab2921ab279367f8206cdadc9259d12e603548Derek Sollenbergervoid shadeSpan16_linear_repeat(TileProc proc, SkFixed dx, SkFixed fx,
12041cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                               uint16_t* SK_RESTRICT dstC,
12051cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                               const uint16_t* SK_RESTRICT cache,
12061cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                               int toggle, int count) {
12071cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    SkASSERT(proc == repeat_tileproc);
12081cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    do {
12091cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        unsigned fi = repeat_bits(fx >> Gradient_Shader::kCache16Shift,
12101cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                                  Gradient_Shader::kCache16Bits);
12114f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger        SkASSERT(fi < Gradient_Shader::kCache16Count);
12121cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        fx += dx;
12131cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        *dstC++ = cache[toggle + fi];
12144f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger        toggle ^= Gradient_Shader::kDitherStride16;
12151cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    } while (--count != 0);
12161cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger}
12171cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger}
121835e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger
12191cab2921ab279367f8206cdadc9259d12e603548Derek Sollenbergervoid Linear_Gradient::shadeSpan16(int x, int y,
12201cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                                  uint16_t* SK_RESTRICT dstC, int count) {
12210910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkASSERT(count > 0);
12220910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
12230910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkPoint             srcPt;
12240910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkMatrix::MapXYProc dstProc = fDstToIndexProc;
12250910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    TileProc            proc = fTileProc;
12261cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    const uint16_t* SK_RESTRICT cache = this->getCache16();
12274f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger    int                 toggle = ((x ^ y) & 1) * kDitherStride16;
12280910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
1229f294d10d594ac335ea3bd09caec89004d41edc5cMike Reed    if (fDstToIndexClass != kPerspective_MatrixClass) {
123040528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger        dstProc(fDstToIndex, SkIntToScalar(x) + SK_ScalarHalf,
123140528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger                             SkIntToScalar(y) + SK_ScalarHalf, &srcPt);
12320910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        SkFixed dx, fx = SkScalarToFixed(srcPt.fX);
12330910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
1234f294d10d594ac335ea3bd09caec89004d41edc5cMike Reed        if (fDstToIndexClass == kFixedStepInX_MatrixClass) {
12350910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            SkFixed dxStorage[1];
12360910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            (void)fDstToIndex.fixedStepInX(SkIntToScalar(y), dxStorage, NULL);
12370910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            dx = dxStorage[0];
1238f294d10d594ac335ea3bd09caec89004d41edc5cMike Reed        } else {
12390910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            SkASSERT(fDstToIndexClass == kLinear_MatrixClass);
12400910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            dx = SkScalarToFixed(fDstToIndex.getScaleX());
12410910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        }
12420910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
12431cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        LinearShade16Proc shadeProc = shadeSpan16_linear_repeat;
1244f294d10d594ac335ea3bd09caec89004d41edc5cMike Reed        if (SkFixedNearlyZero(dx)) {
12451cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger            shadeProc = shadeSpan16_linear_vertical;
1246f294d10d594ac335ea3bd09caec89004d41edc5cMike Reed        } else if (proc == clamp_tileproc) {
12471cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger            shadeProc = shadeSpan16_linear_clamp;
1248f294d10d594ac335ea3bd09caec89004d41edc5cMike Reed        } else if (proc == mirror_tileproc) {
12491cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger            shadeProc = shadeSpan16_linear_mirror;
1250f294d10d594ac335ea3bd09caec89004d41edc5cMike Reed        } else {
12510910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            SkASSERT(proc == repeat_tileproc);
12520910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        }
12531cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        (*shadeProc)(proc, dx, fx, dstC, cache, toggle, count);
1254f294d10d594ac335ea3bd09caec89004d41edc5cMike Reed    } else {
12550910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        SkScalar    dstX = SkIntToScalar(x);
12560910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        SkScalar    dstY = SkIntToScalar(y);
12570910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        do {
12580910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            dstProc(fDstToIndex, dstX, dstY, &srcPt);
12590910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            unsigned fi = proc(SkScalarToFixed(srcPt.fX));
12600910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            SkASSERT(fi <= 0xFFFF);
12610910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
126293d11b5b461a8677a8e3ffa94260f4f9897070acMike Reed            int index = fi >> kCache16Shift;
12630910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            *dstC++ = cache[toggle + index];
12644f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger            toggle ^= Gradient_Shader::kDitherStride16;
12650910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
12660910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            dstX += SK_Scalar1;
12670910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        } while (--count != 0);
12680910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
12690910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
12700910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
12710910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project///////////////////////////////////////////////////////////////////////////////
12720910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
12730910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#define kSQRT_TABLE_BITS    11
12740910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#define kSQRT_TABLE_SIZE    (1 << kSQRT_TABLE_BITS)
12750910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
12760910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#include "SkRadialGradient_Table.h"
12770910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
12780910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#if defined(SK_BUILD_FOR_WIN32) && defined(SK_DEBUG)
12790910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
12800910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#include <stdio.h>
12810910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
128235e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenbergervoid SkRadialGradient_BuildTable() {
12830910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    // build it 0..127 x 0..127, so we use 2^15 - 1 in the numerator for our "fixed" table
12840910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
12850910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    FILE* file = ::fopen("SkRadialGradient_Table.h", "w");
12860910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkASSERT(file);
12870910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    ::fprintf(file, "static const uint8_t gSqrt8Table[] = {\n");
12880910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
128935e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger    for (int i = 0; i < kSQRT_TABLE_SIZE; i++) {
129035e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger        if ((i & 15) == 0) {
12910910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            ::fprintf(file, "\t");
129235e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger        }
12930910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
12940910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        uint8_t value = SkToU8(SkFixedSqrt(i * SK_Fixed1 / kSQRT_TABLE_SIZE) >> 8);
12950910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
12960910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        ::fprintf(file, "0x%02X", value);
129735e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger        if (i < kSQRT_TABLE_SIZE-1) {
12980910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            ::fprintf(file, ", ");
129935e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger        }
130035e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger        if ((i & 15) == 15) {
13010910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            ::fprintf(file, "\n");
130235e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger        }
13030910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
13040910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    ::fprintf(file, "};\n");
13050910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    ::fclose(file);
13060910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
13070910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
13080910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#endif
13090910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
13100910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
131135e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenbergerstatic void rad_to_unit_matrix(const SkPoint& center, SkScalar radius,
131235e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger                               SkMatrix* matrix) {
13130910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkScalar    inv = SkScalarInvert(radius);
13140910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
13150910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    matrix->setTranslate(-center.fX, -center.fY);
13160910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    matrix->postScale(inv, inv);
13170910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
13180910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
13191cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger
13201cab2921ab279367f8206cdadc9259d12e603548Derek Sollenbergernamespace {
13211cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger
13224f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenbergertypedef void (* RadialShade16Proc)(SkScalar sfx, SkScalar sdx,
13234f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger        SkScalar sfy, SkScalar sdy,
13244f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger        uint16_t* dstC, const uint16_t* cache,
13251cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        int toggle, int count);
13261cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger
13274f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenbergervoid shadeSpan16_radial_clamp(SkScalar sfx, SkScalar sdx,
13284f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger        SkScalar sfy, SkScalar sdy,
13294f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger        uint16_t* SK_RESTRICT dstC, const uint16_t* SK_RESTRICT cache,
13301cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        int toggle, int count) {
13311cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    const uint8_t* SK_RESTRICT sqrt_table = gSqrt8Table;
13321cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger
13331cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    /* knock these down so we can pin against +- 0x7FFF, which is an
13341cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger       immediate load, rather than 0xFFFF which is slower. This is a
13351cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger       compromise, since it reduces our precision, but that appears
13361cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger       to be visually OK. If we decide this is OK for all of our cases,
13371cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger       we could (it seems) put this scale-down into fDstToIndex,
13381cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger       to avoid having to do these extra shifts each time.
13391cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    */
13404f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger    SkFixed fx = SkScalarToFixed(sfx) >> 1;
13414f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger    SkFixed dx = SkScalarToFixed(sdx) >> 1;
13424f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger    SkFixed fy = SkScalarToFixed(sfy) >> 1;
13434f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger    SkFixed dy = SkScalarToFixed(sdy) >> 1;
13441cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    // might perform this check for the other modes,
13451cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    // but the win will be a smaller % of the total
13461cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    if (dy == 0) {
13471cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        fy = SkPin32(fy, -0xFFFF >> 1, 0xFFFF >> 1);
13481cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        fy *= fy;
13491cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        do {
13501cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger            unsigned xx = SkPin32(fx, -0xFFFF >> 1, 0xFFFF >> 1);
13511cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger            unsigned fi = (xx * xx + fy) >> (14 + 16 - kSQRT_TABLE_BITS);
13521cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger            fi = SkFastMin32(fi, 0xFFFF >> (16 - kSQRT_TABLE_BITS));
13531cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger            fx += dx;
13541cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger            *dstC++ = cache[toggle +
13551cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                            (sqrt_table[fi] >> Gradient_Shader::kSqrt16Shift)];
13564f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger            toggle ^= Gradient_Shader::kDitherStride16;
13571cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        } while (--count != 0);
13581cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    } else {
13591cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        do {
13601cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger            unsigned xx = SkPin32(fx, -0xFFFF >> 1, 0xFFFF >> 1);
13611cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger            unsigned fi = SkPin32(fy, -0xFFFF >> 1, 0xFFFF >> 1);
13621cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger            fi = (xx * xx + fi * fi) >> (14 + 16 - kSQRT_TABLE_BITS);
13631cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger            fi = SkFastMin32(fi, 0xFFFF >> (16 - kSQRT_TABLE_BITS));
13641cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger            fx += dx;
13651cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger            fy += dy;
13661cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger            *dstC++ = cache[toggle +
13671cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                            (sqrt_table[fi] >> Gradient_Shader::kSqrt16Shift)];
13684f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger            toggle ^= Gradient_Shader::kDitherStride16;
13691cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        } while (--count != 0);
13701cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    }
13711cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger}
13721cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger
13734f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenbergervoid shadeSpan16_radial_mirror(SkScalar sfx, SkScalar sdx,
13744f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger        SkScalar sfy, SkScalar sdy,
13754f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger        uint16_t* SK_RESTRICT dstC, const uint16_t* SK_RESTRICT cache,
13761cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        int toggle, int count) {
13771cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    do {
13784f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger#ifdef SK_SCALAR_IS_FLOAT
13794f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger        float fdist = sk_float_sqrt(sfx*sfx + sfy*sfy);
13804f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger        SkFixed dist = SkFloatToFixed(fdist);
13814f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger#else
13824f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger        SkFixed magnitudeSquared = SkFixedSquare(sfx) +
13834f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger            SkFixedSquare(sfy);
13844f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger        if (magnitudeSquared < 0) // Overflow.
13854f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger            magnitudeSquared = SK_FixedMax;
13864f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger        SkFixed dist = SkFixedSqrt(magnitudeSquared);
13874f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger#endif
13881cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        unsigned fi = mirror_tileproc(dist);
13891cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        SkASSERT(fi <= 0xFFFF);
13901cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        *dstC++ = cache[toggle + (fi >> Gradient_Shader::kCache16Shift)];
13914f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger        toggle ^= Gradient_Shader::kDitherStride16;
13924f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger        sfx += sdx;
13934f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger        sfy += sdy;
13941cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    } while (--count != 0);
13951cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger}
13961cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger
13974f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenbergervoid shadeSpan16_radial_repeat(SkScalar sfx, SkScalar sdx,
13984f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger        SkScalar sfy, SkScalar sdy,
13994f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger        uint16_t* SK_RESTRICT dstC, const uint16_t* SK_RESTRICT cache,
14001cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        int toggle, int count) {
14014f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger    SkFixed fx = SkScalarToFixed(sfx);
14024f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger    SkFixed dx = SkScalarToFixed(sdx);
14034f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger    SkFixed fy = SkScalarToFixed(sfy);
14044f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger    SkFixed dy = SkScalarToFixed(sdy);
14051cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    do {
14061cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        SkFixed dist = SkFixedSqrt(SkFixedSquare(fx) + SkFixedSquare(fy));
14071cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        unsigned fi = repeat_tileproc(dist);
14081cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        SkASSERT(fi <= 0xFFFF);
14091cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        fx += dx;
14101cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        fy += dy;
14111cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        *dstC++ = cache[toggle + (fi >> Gradient_Shader::kCache16Shift)];
14124f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger        toggle ^= Gradient_Shader::kDitherStride16;
14131cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    } while (--count != 0);
14141cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger}
14151cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger
14161cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger}
14171cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger
14180910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectclass Radial_Gradient : public Gradient_Shader {
14190910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectpublic:
14200910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    Radial_Gradient(const SkPoint& center, SkScalar radius,
14210910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                    const SkColor colors[], const SkScalar pos[], int colorCount,
14220910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                    SkShader::TileMode mode, SkUnitMapper* mapper)
142305b6b4d746867a9fb02e14edfe1bf3685abeb813Derek Sollenberger        : Gradient_Shader(colors, pos, colorCount, mode, mapper),
142405b6b4d746867a9fb02e14edfe1bf3685abeb813Derek Sollenberger          fCenter(center),
142505b6b4d746867a9fb02e14edfe1bf3685abeb813Derek Sollenberger          fRadius(radius)
14260910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    {
14270910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        // make sure our table is insync with our current #define for kSQRT_TABLE_SIZE
14280910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        SkASSERT(sizeof(gSqrt8Table) == kSQRT_TABLE_SIZE);
14290910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
14300910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        rad_to_unit_matrix(center, radius, &fPtsToUnit);
14310910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
143235e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger
14334f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger    virtual void shadeSpan(int x, int y, SkPMColor* dstC, int count)
14344f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger        SK_OVERRIDE;
14354f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger    virtual void shadeSpan16(int x, int y, uint16_t* SK_RESTRICT dstC,
14364f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger                             int count) SK_OVERRIDE {
14370910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        SkASSERT(count > 0);
14380910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
14390910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        SkPoint             srcPt;
14400910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        SkMatrix::MapXYProc dstProc = fDstToIndexProc;
14410910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        TileProc            proc = fTileProc;
14421cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        const uint16_t* SK_RESTRICT cache = this->getCache16();
14434f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger        int                 toggle = ((x ^ y) & 1) * kDitherStride16;
14440910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
14452e8fbf0f64801962778aa2d0e0177a8be4c03d89Mike Reed        if (fDstToIndexClass != kPerspective_MatrixClass) {
144640528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger            dstProc(fDstToIndex, SkIntToScalar(x) + SK_ScalarHalf,
144740528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger                                 SkIntToScalar(y) + SK_ScalarHalf, &srcPt);
14484f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger
14494f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger            SkScalar sdx = fDstToIndex.getScaleX();
14504f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger            SkScalar sdy = fDstToIndex.getSkewY();
14510910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
14522e8fbf0f64801962778aa2d0e0177a8be4c03d89Mike Reed            if (fDstToIndexClass == kFixedStepInX_MatrixClass) {
14530910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                SkFixed storage[2];
14544f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger                (void)fDstToIndex.fixedStepInX(SkIntToScalar(y),
14554f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger                                               &storage[0], &storage[1]);
14564f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger                sdx = SkFixedToScalar(storage[0]);
14574f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger                sdy = SkFixedToScalar(storage[1]);
14582e8fbf0f64801962778aa2d0e0177a8be4c03d89Mike Reed            } else {
14590910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                SkASSERT(fDstToIndexClass == kLinear_MatrixClass);
14600910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            }
14610910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
14621cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger            RadialShade16Proc shadeProc = shadeSpan16_radial_repeat;
14632e8fbf0f64801962778aa2d0e0177a8be4c03d89Mike Reed            if (proc == clamp_tileproc) {
14641cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                shadeProc = shadeSpan16_radial_clamp;
14652e8fbf0f64801962778aa2d0e0177a8be4c03d89Mike Reed            } else if (proc == mirror_tileproc) {
14661cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                shadeProc = shadeSpan16_radial_mirror;
14672e8fbf0f64801962778aa2d0e0177a8be4c03d89Mike Reed            } else {
14680910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                SkASSERT(proc == repeat_tileproc);
14690910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            }
14704f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger            (*shadeProc)(srcPt.fX, sdx, srcPt.fY, sdy, dstC,
14714f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger                         cache, toggle, count);
14722e8fbf0f64801962778aa2d0e0177a8be4c03d89Mike Reed        } else {    // perspective case
14730910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            SkScalar dstX = SkIntToScalar(x);
14740910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            SkScalar dstY = SkIntToScalar(y);
14750910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            do {
14760910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                dstProc(fDstToIndex, dstX, dstY, &srcPt);
14770910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                unsigned fi = proc(SkScalarToFixed(srcPt.length()));
14780910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                SkASSERT(fi <= 0xFFFF);
14790910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
14800910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                int index = fi >> (16 - kCache16Bits);
14810910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                *dstC++ = cache[toggle + index];
14824f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger                toggle ^= kDitherStride16;
14830910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
14840910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                dstX += SK_Scalar1;
14850910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            } while (--count != 0);
14860910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        }
14870910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
14880910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
148940528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger    virtual BitmapType asABitmap(SkBitmap* bitmap,
149040528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger                                 SkMatrix* matrix,
149140528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger                                 TileMode* xy,
14921cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                                 SkScalar* twoPointRadialParams)
14931cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger            const SK_OVERRIDE {
149440528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger        if (bitmap) {
149540528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger            this->commonAsABitmap(bitmap);
149640528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger        }
149740528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger        if (matrix) {
14984f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger            matrix->setScale(SkIntToScalar(kGradient32Length),
14994f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger                             SkIntToScalar(kGradient32Length));
150040528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger            matrix->preConcat(fPtsToUnit);
150140528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger        }
150240528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger        if (xy) {
150340528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger            xy[0] = fTileMode;
150440528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger            xy[1] = kClamp_TileMode;
150540528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger        }
150640528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger        return kRadial_BitmapType;
150740528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger    }
15081cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    virtual GradientType asAGradient(GradientInfo* info) const SK_OVERRIDE {
150905b6b4d746867a9fb02e14edfe1bf3685abeb813Derek Sollenberger        if (info) {
151005b6b4d746867a9fb02e14edfe1bf3685abeb813Derek Sollenberger            commonAsAGradient(info);
151105b6b4d746867a9fb02e14edfe1bf3685abeb813Derek Sollenberger            info->fPoint[0] = fCenter;
151205b6b4d746867a9fb02e14edfe1bf3685abeb813Derek Sollenberger            info->fRadius[0] = fRadius;
151305b6b4d746867a9fb02e14edfe1bf3685abeb813Derek Sollenberger        }
151405b6b4d746867a9fb02e14edfe1bf3685abeb813Derek Sollenberger        return kRadial_GradientType;
151505b6b4d746867a9fb02e14edfe1bf3685abeb813Derek Sollenberger    }
151640528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger
151740528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger    static SkFlattenable* CreateProc(SkFlattenableReadBuffer& buffer) {
15180910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        return SkNEW_ARGS(Radial_Gradient, (buffer));
15190910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
15200910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
15211cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    virtual void flatten(SkFlattenableWriteBuffer& buffer) SK_OVERRIDE {
152205b6b4d746867a9fb02e14edfe1bf3685abeb813Derek Sollenberger        this->INHERITED::flatten(buffer);
152305b6b4d746867a9fb02e14edfe1bf3685abeb813Derek Sollenberger        buffer.writeScalar(fCenter.fX);
152405b6b4d746867a9fb02e14edfe1bf3685abeb813Derek Sollenberger        buffer.writeScalar(fCenter.fY);
152505b6b4d746867a9fb02e14edfe1bf3685abeb813Derek Sollenberger        buffer.writeScalar(fRadius);
152605b6b4d746867a9fb02e14edfe1bf3685abeb813Derek Sollenberger    }
152705b6b4d746867a9fb02e14edfe1bf3685abeb813Derek Sollenberger
15280910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectprotected:
152905b6b4d746867a9fb02e14edfe1bf3685abeb813Derek Sollenberger    Radial_Gradient(SkFlattenableReadBuffer& buffer)
153005b6b4d746867a9fb02e14edfe1bf3685abeb813Derek Sollenberger        : Gradient_Shader(buffer),
153135e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger          fCenter(unflatten_point(buffer)),
153205b6b4d746867a9fb02e14edfe1bf3685abeb813Derek Sollenberger          fRadius(buffer.readScalar()) {
153305b6b4d746867a9fb02e14edfe1bf3685abeb813Derek Sollenberger    }
15341cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    virtual Factory getFactory() SK_OVERRIDE { return CreateProc; }
15350910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
15360910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectprivate:
15370910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    typedef Gradient_Shader INHERITED;
153805b6b4d746867a9fb02e14edfe1bf3685abeb813Derek Sollenberger    const SkPoint fCenter;
153905b6b4d746867a9fb02e14edfe1bf3685abeb813Derek Sollenberger    const SkScalar fRadius;
15400910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project};
15410910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
15421cab2921ab279367f8206cdadc9259d12e603548Derek Sollenbergernamespace {
15431cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger
15441cab2921ab279367f8206cdadc9259d12e603548Derek Sollenbergerinline bool radial_completely_pinned(int fx, int dx, int fy, int dy) {
15451cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    // fast, overly-conservative test: checks unit square instead
15461cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    // of unit circle
15471cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    bool xClamped = (fx >= SK_FixedHalf && dx >= 0) ||
15481cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                    (fx <= -SK_FixedHalf && dx <= 0);
15491cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    bool yClamped = (fy >= SK_FixedHalf && dy >= 0) ||
15501cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                    (fy <= -SK_FixedHalf && dy <= 0);
15511cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger
15521cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    return xClamped || yClamped;
15531cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger}
15541cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger
15551cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger// Return true if (fx * fy) is always inside the unit circle
15561cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger// SkPin32 is expensive, but so are all the SkFixedMul in this test,
15571cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger// so it shouldn't be run if count is small.
15581cab2921ab279367f8206cdadc9259d12e603548Derek Sollenbergerinline bool no_need_for_radial_pin(int fx, int dx,
15591cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                                          int fy, int dy, int count) {
15601cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    SkASSERT(count > 0);
15611cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    if (SkAbs32(fx) > 0x7FFF || SkAbs32(fy) > 0x7FFF) {
15621cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        return false;
15631cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    }
15641cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    if (fx*fx + fy*fy > 0x7FFF*0x7FFF) {
15651cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        return false;
15661cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    }
15671cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    fx += (count - 1) * dx;
15681cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    fy += (count - 1) * dy;
15691cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    if (SkAbs32(fx) > 0x7FFF || SkAbs32(fy) > 0x7FFF) {
15701cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        return false;
15711cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    }
15721cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    return fx*fx + fy*fy <= 0x7FFF*0x7FFF;
15731cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger}
15741cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger
15751cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger#define UNPINNED_RADIAL_STEP \
15761cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    fi = (fx * fx + fy * fy) >> (14 + 16 - kSQRT_TABLE_BITS); \
15774f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger    *dstC++ = cache[toggle + \
15784f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger                    (sqrt_table[fi] >> Gradient_Shader::kSqrt32Shift)]; \
15794f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger    toggle ^= Gradient_Shader::kDitherStride32; \
15801cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    fx += dx; \
15811cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    fy += dy;
15821cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger
15834f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenbergertypedef void (* RadialShadeProc)(SkScalar sfx, SkScalar sdx,
15844f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger        SkScalar sfy, SkScalar sdy,
15854f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger        SkPMColor* dstC, const SkPMColor* cache,
15864f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger        int count, int toggle);
15871cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger
15881cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger// On Linux, this is faster with SkPMColor[] params than SkPMColor* SK_RESTRICT
15894f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenbergervoid shadeSpan_radial_clamp(SkScalar sfx, SkScalar sdx,
15904f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger        SkScalar sfy, SkScalar sdy,
15911cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        SkPMColor* SK_RESTRICT dstC, const SkPMColor* SK_RESTRICT cache,
15924f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger        int count, int toggle) {
15931cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    // Floating point seems to be slower than fixed point,
15941cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    // even when we have float hardware.
15951cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    const uint8_t* SK_RESTRICT sqrt_table = gSqrt8Table;
15964f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger    SkFixed fx = SkScalarToFixed(sfx) >> 1;
15974f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger    SkFixed dx = SkScalarToFixed(sdx) >> 1;
15984f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger    SkFixed fy = SkScalarToFixed(sfy) >> 1;
15994f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger    SkFixed dy = SkScalarToFixed(sdy) >> 1;
16001cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    if ((count > 4) && radial_completely_pinned(fx, dx, fy, dy)) {
16014f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger        unsigned fi = Gradient_Shader::kGradient32Length;
16024f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger        sk_memset32_dither(dstC,
16034f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger            cache[toggle + fi],
16044f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger            cache[(toggle ^ Gradient_Shader::kDitherStride32) + fi],
16054f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger            count);
16061cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    } else if ((count > 4) &&
16071cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger               no_need_for_radial_pin(fx, dx, fy, dy, count)) {
16081cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        unsigned fi;
16091cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        // 4x unroll appears to be no faster than 2x unroll on Linux
16101cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        while (count > 1) {
16111cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger            UNPINNED_RADIAL_STEP;
16121cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger            UNPINNED_RADIAL_STEP;
16131cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger            count -= 2;
16141cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        }
16151cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        if (count) {
16161cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger            UNPINNED_RADIAL_STEP;
16171cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        }
16181cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    }
16191cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    else  {
16204f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger        // Specializing for dy == 0 gains us 25% on Skia benchmarks
16214f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger        if (dy == 0) {
16224f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger            unsigned yy = SkPin32(fy, -0xFFFF >> 1, 0xFFFF >> 1);
16234f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger            yy *= yy;
16244f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger            do {
16254f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger                unsigned xx = SkPin32(fx, -0xFFFF >> 1, 0xFFFF >> 1);
16264f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger                unsigned fi = (xx * xx + yy) >> (14 + 16 - kSQRT_TABLE_BITS);
16274f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger                fi = SkFastMin32(fi, 0xFFFF >> (16 - kSQRT_TABLE_BITS));
16284f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger                *dstC++ = cache[toggle + (sqrt_table[fi] >>
16294f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger                    Gradient_Shader::kSqrt32Shift)];
16304f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger                toggle ^= Gradient_Shader::kDitherStride32;
16314f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger                fx += dx;
16324f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger            } while (--count != 0);
16334f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger        } else {
16344f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger            do {
16354f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger                unsigned xx = SkPin32(fx, -0xFFFF >> 1, 0xFFFF >> 1);
16364f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger                unsigned fi = SkPin32(fy, -0xFFFF >> 1, 0xFFFF >> 1);
16374f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger                fi = (xx * xx + fi * fi) >> (14 + 16 - kSQRT_TABLE_BITS);
16384f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger                fi = SkFastMin32(fi, 0xFFFF >> (16 - kSQRT_TABLE_BITS));
16394f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger                *dstC++ = cache[toggle + (sqrt_table[fi] >>
16404f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger                    Gradient_Shader::kSqrt32Shift)];
16414f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger                toggle ^= Gradient_Shader::kDitherStride32;
16424f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger                fx += dx;
16434f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger                fy += dy;
16444f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger            } while (--count != 0);
16454f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger        }
16461cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    }
16471cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger}
16481cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger
16494f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger// Unrolling this loop doesn't seem to help (when float); we're stalling to
16504f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger// get the results of the sqrt (?), and don't have enough extra registers to
16514f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger// have many in flight.
16524f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenbergervoid shadeSpan_radial_mirror(SkScalar sfx, SkScalar sdx,
16534f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger        SkScalar sfy, SkScalar sdy,
16541cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        SkPMColor* SK_RESTRICT dstC, const SkPMColor* SK_RESTRICT cache,
16554f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger        int count, int toggle) {
16561cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    do {
16574f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger#ifdef SK_SCALAR_IS_FLOAT
16584f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger        float fdist = sk_float_sqrt(sfx*sfx + sfy*sfy);
16594f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger        SkFixed dist = SkFloatToFixed(fdist);
16601cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger#else
16614f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger        SkFixed magnitudeSquared = SkFixedSquare(sfx) +
16624f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger            SkFixedSquare(sfy);
16631cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        if (magnitudeSquared < 0) // Overflow.
16641cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger            magnitudeSquared = SK_FixedMax;
16651cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        SkFixed dist = SkFixedSqrt(magnitudeSquared);
16664f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger#endif
16671cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        unsigned fi = mirror_tileproc(dist);
16681cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        SkASSERT(fi <= 0xFFFF);
16694f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger        *dstC++ = cache[toggle + (fi >> Gradient_Shader::kCache32Shift)];
16704f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger        toggle ^= Gradient_Shader::kDitherStride32;
16714f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger        sfx += sdx;
16724f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger        sfy += sdy;
16731cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    } while (--count != 0);
16741cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger}
16751cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger
16764f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenbergervoid shadeSpan_radial_repeat(SkScalar sfx, SkScalar sdx,
16774f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger        SkScalar sfy, SkScalar sdy,
16781cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        SkPMColor* SK_RESTRICT dstC, const SkPMColor* SK_RESTRICT cache,
16794f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger        int count, int toggle) {
16804f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger    SkFixed fx = SkScalarToFixed(sfx);
16814f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger    SkFixed dx = SkScalarToFixed(sdx);
16824f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger    SkFixed fy = SkScalarToFixed(sfy);
16834f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger    SkFixed dy = SkScalarToFixed(sdy);
16841cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    do {
16851cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        SkFixed magnitudeSquared = SkFixedSquare(fx) +
16861cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger            SkFixedSquare(fy);
16871cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        if (magnitudeSquared < 0) // Overflow.
16881cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger            magnitudeSquared = SK_FixedMax;
16891cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        SkFixed dist = SkFixedSqrt(magnitudeSquared);
16901cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        unsigned fi = repeat_tileproc(dist);
16911cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        SkASSERT(fi <= 0xFFFF);
16924f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger        *dstC++ = cache[toggle + (fi >> Gradient_Shader::kCache32Shift)];
16934f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger        toggle ^= Gradient_Shader::kDitherStride32;
16941cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        fx += dx;
16951cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        fy += dy;
16961cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    } while (--count != 0);
16971cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger}
16981cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger}
16991cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger
17001cab2921ab279367f8206cdadc9259d12e603548Derek Sollenbergervoid Radial_Gradient::shadeSpan(int x, int y,
17011cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                                SkPMColor* SK_RESTRICT dstC, int count) {
17021cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    SkASSERT(count > 0);
17031cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger
17041cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    SkPoint             srcPt;
17051cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    SkMatrix::MapXYProc dstProc = fDstToIndexProc;
17061cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    TileProc            proc = fTileProc;
17071cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    const SkPMColor* SK_RESTRICT cache = this->getCache32();
17084f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger#ifdef USE_DITHER_32BIT_GRADIENT
17094f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger    int toggle = ((x ^ y) & 1) * Gradient_Shader::kDitherStride32;
17104f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger#else
17114f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger    int toggle = 0;
17124f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger#endif
17131cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger
17141cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    if (fDstToIndexClass != kPerspective_MatrixClass) {
17151cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        dstProc(fDstToIndex, SkIntToScalar(x) + SK_ScalarHalf,
17161cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                             SkIntToScalar(y) + SK_ScalarHalf, &srcPt);
17174f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger        SkScalar sdx = fDstToIndex.getScaleX();
17184f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger        SkScalar sdy = fDstToIndex.getSkewY();
17191cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger
17201cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        if (fDstToIndexClass == kFixedStepInX_MatrixClass) {
17211cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger            SkFixed storage[2];
17224f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger            (void)fDstToIndex.fixedStepInX(SkIntToScalar(y),
17234f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger                                           &storage[0], &storage[1]);
17244f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger            sdx = SkFixedToScalar(storage[0]);
17254f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger            sdy = SkFixedToScalar(storage[1]);
17261cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        } else {
17271cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger            SkASSERT(fDstToIndexClass == kLinear_MatrixClass);
17281cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        }
17291cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger
17301cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        RadialShadeProc shadeProc = shadeSpan_radial_repeat;
17311cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        if (proc == clamp_tileproc) {
17321cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger            shadeProc = shadeSpan_radial_clamp;
17331cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        } else if (proc == mirror_tileproc) {
17341cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger            shadeProc = shadeSpan_radial_mirror;
17351cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        } else {
17361cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger            SkASSERT(proc == repeat_tileproc);
17371cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        }
17384f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger        (*shadeProc)(srcPt.fX, sdx, srcPt.fY, sdy, dstC, cache, count, toggle);
17391cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    } else {    // perspective case
17401cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        SkScalar dstX = SkIntToScalar(x);
17411cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        SkScalar dstY = SkIntToScalar(y);
17421cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        do {
17431cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger            dstProc(fDstToIndex, dstX, dstY, &srcPt);
17441cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger            unsigned fi = proc(SkScalarToFixed(srcPt.length()));
17451cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger            SkASSERT(fi <= 0xFFFF);
17461cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger            *dstC++ = cache[fi >> Gradient_Shader::kCache32Shift];
17471cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger            dstX += SK_Scalar1;
17481cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        } while (--count != 0);
17491cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    }
17501cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger}
17511cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger
1752924f59d3627a697f2b0df3299915e814e160f981Mike Reed/* Two-point radial gradients are specified by two circles, each with a center
1753924f59d3627a697f2b0df3299915e814e160f981Mike Reed   point and radius.  The gradient can be considered to be a series of
1754924f59d3627a697f2b0df3299915e814e160f981Mike Reed   concentric circles, with the color interpolated from the start circle
1755924f59d3627a697f2b0df3299915e814e160f981Mike Reed   (at t=0) to the end circle (at t=1).
1756924f59d3627a697f2b0df3299915e814e160f981Mike Reed
1757924f59d3627a697f2b0df3299915e814e160f981Mike Reed   For each point (x, y) in the span, we want to find the
1758924f59d3627a697f2b0df3299915e814e160f981Mike Reed   interpolated circle that intersects that point.  The center
1759924f59d3627a697f2b0df3299915e814e160f981Mike Reed   of the desired circle (Cx, Cy) falls at some distance t
1760924f59d3627a697f2b0df3299915e814e160f981Mike Reed   along the line segment between the start point (Sx, Sy) and
1761924f59d3627a697f2b0df3299915e814e160f981Mike Reed   end point (Ex, Ey):
176240528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger
1763924f59d3627a697f2b0df3299915e814e160f981Mike Reed      Cx = (1 - t) * Sx + t * Ex        (0 <= t <= 1)
1764924f59d3627a697f2b0df3299915e814e160f981Mike Reed      Cy = (1 - t) * Sy + t * Ey
176540528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger
1766924f59d3627a697f2b0df3299915e814e160f981Mike Reed   The radius of the desired circle (r) is also a linear interpolation t
1767924f59d3627a697f2b0df3299915e814e160f981Mike Reed   between the start and end radii (Sr and Er):
176840528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger
1769924f59d3627a697f2b0df3299915e814e160f981Mike Reed      r = (1 - t) * Sr + t * Er
177040528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger
1771924f59d3627a697f2b0df3299915e814e160f981Mike Reed   But
177240528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger
1773924f59d3627a697f2b0df3299915e814e160f981Mike Reed      (x - Cx)^2 + (y - Cy)^2 = r^2
177440528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger
1775924f59d3627a697f2b0df3299915e814e160f981Mike Reed   so
177640528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger
1777924f59d3627a697f2b0df3299915e814e160f981Mike Reed     (x - ((1 - t) * Sx + t * Ex))^2
1778924f59d3627a697f2b0df3299915e814e160f981Mike Reed   + (y - ((1 - t) * Sy + t * Ey))^2
1779924f59d3627a697f2b0df3299915e814e160f981Mike Reed   = ((1 - t) * Sr + t * Er)^2
178040528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger
1781924f59d3627a697f2b0df3299915e814e160f981Mike Reed   Solving for t yields
178240528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger
1783924f59d3627a697f2b0df3299915e814e160f981Mike Reed     [(Sx - Ex)^2 + (Sy - Ey)^2 - (Er - Sr)^2)] * t^2
1784924f59d3627a697f2b0df3299915e814e160f981Mike Reed   + [2 * (Sx - Ex)(x - Sx) + 2 * (Sy - Ey)(y - Sy) - 2 * (Er - Sr) * Sr] * t
1785924f59d3627a697f2b0df3299915e814e160f981Mike Reed   + [(x - Sx)^2 + (y - Sy)^2 - Sr^2] = 0
178640528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger
1787924f59d3627a697f2b0df3299915e814e160f981Mike Reed   To simplify, let Dx = Sx - Ex, Dy = Sy - Ey, Dr = Er - Sr, dx = x - Sx, dy = y - Sy
1788924f59d3627a697f2b0df3299915e814e160f981Mike Reed
1789924f59d3627a697f2b0df3299915e814e160f981Mike Reed     [Dx^2 + Dy^2 - Dr^2)] * t^2
1790924f59d3627a697f2b0df3299915e814e160f981Mike Reed   + 2 * [Dx * dx + Dy * dy - Dr * Sr] * t
1791924f59d3627a697f2b0df3299915e814e160f981Mike Reed   + [dx^2 + dy^2 - Sr^2] = 0
179240528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger
179340528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger   A quadratic in t.  The two roots of the quadratic reflect the two
1794924f59d3627a697f2b0df3299915e814e160f981Mike Reed   possible circles on which the point may fall.  Solving for t yields
1795924f59d3627a697f2b0df3299915e814e160f981Mike Reed   the gradient value to use.
179640528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger
1797924f59d3627a697f2b0df3299915e814e160f981Mike Reed   If a<0, the start circle is entirely contained in the
1798924f59d3627a697f2b0df3299915e814e160f981Mike Reed   end circle, and one of the roots will be <0 or >1 (off the line
1799924f59d3627a697f2b0df3299915e814e160f981Mike Reed   segment).  If a>0, the start circle falls at least partially
1800924f59d3627a697f2b0df3299915e814e160f981Mike Reed   outside the end circle (or vice versa), and the gradient
1801924f59d3627a697f2b0df3299915e814e160f981Mike Reed   defines a "tube" where a point may be on one circle (on the
1802924f59d3627a697f2b0df3299915e814e160f981Mike Reed   inside of the tube) or the other (outside of the tube).  We choose
1803924f59d3627a697f2b0df3299915e814e160f981Mike Reed   one arbitrarily.
180440528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger
1805924f59d3627a697f2b0df3299915e814e160f981Mike Reed   In order to keep the math to within the limits of fixed point,
1806924f59d3627a697f2b0df3299915e814e160f981Mike Reed   we divide the entire quadratic by Dr^2, and replace
1807924f59d3627a697f2b0df3299915e814e160f981Mike Reed   (x - Sx)/Dr with x' and (y - Sy)/Dr with y', giving
180840528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger
1809924f59d3627a697f2b0df3299915e814e160f981Mike Reed   [Dx^2 / Dr^2 + Dy^2 / Dr^2 - 1)] * t^2
1810924f59d3627a697f2b0df3299915e814e160f981Mike Reed   + 2 * [x' * Dx / Dr + y' * Dy / Dr - Sr / Dr] * t
1811924f59d3627a697f2b0df3299915e814e160f981Mike Reed   + [x'^2 + y'^2 - Sr^2/Dr^2] = 0
181240528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger
1813924f59d3627a697f2b0df3299915e814e160f981Mike Reed   (x' and y' are computed by appending the subtract and scale to the
1814924f59d3627a697f2b0df3299915e814e160f981Mike Reed   fDstToIndex matrix in the constructor).
1815924f59d3627a697f2b0df3299915e814e160f981Mike Reed
1816924f59d3627a697f2b0df3299915e814e160f981Mike Reed   Since the 'A' component of the quadratic is independent of x' and y', it
1817924f59d3627a697f2b0df3299915e814e160f981Mike Reed   is precomputed in the constructor.  Since the 'B' component is linear in
1818924f59d3627a697f2b0df3299915e814e160f981Mike Reed   x' and y', if x and y are linear in the span, 'B' can be computed
181940528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger   incrementally with a simple delta (db below).  If it is not (e.g.,
1820924f59d3627a697f2b0df3299915e814e160f981Mike Reed   a perspective projection), it must be computed in the loop.
1821924f59d3627a697f2b0df3299915e814e160f981Mike Reed
1822924f59d3627a697f2b0df3299915e814e160f981Mike Reed*/
1823924f59d3627a697f2b0df3299915e814e160f981Mike Reed
18241cab2921ab279367f8206cdadc9259d12e603548Derek Sollenbergernamespace {
18251cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger
18261cab2921ab279367f8206cdadc9259d12e603548Derek Sollenbergerinline SkFixed two_point_radial(SkScalar b, SkScalar fx, SkScalar fy,
18271cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                                SkScalar sr2d2, SkScalar foura,
18281cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                                SkScalar oneOverTwoA, bool posRoot) {
182935e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger    SkScalar c = SkScalarSquare(fx) + SkScalarSquare(fy) - sr2d2;
18301cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    if (0 == foura) {
18311cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        return SkScalarToFixed(SkScalarDiv(-c, b));
18321cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    }
18331cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger
183435e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger    SkScalar discrim = SkScalarSquare(b) - SkScalarMul(foura, c);
183535e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger    if (discrim < 0) {
183635e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger        discrim = -discrim;
183735e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger    }
183835e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger    SkScalar rootDiscrim = SkScalarSqrt(discrim);
183935e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger    SkScalar result;
184035e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger    if (posRoot) {
184135e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger        result = SkScalarMul(-b + rootDiscrim, oneOverTwoA);
184235e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger    } else {
184335e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger        result = SkScalarMul(-b - rootDiscrim, oneOverTwoA);
184435e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger    }
184535e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger    return SkScalarToFixed(result);
184635e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger}
18471cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger
18481cab2921ab279367f8206cdadc9259d12e603548Derek Sollenbergertypedef void (* TwoPointRadialShadeProc)(SkScalar fx, SkScalar dx,
18491cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        SkScalar fy, SkScalar dy,
18501cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        SkScalar b, SkScalar db,
18511cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        SkScalar fSr2D2, SkScalar foura, SkScalar fOneOverTwoA, bool posRoot,
18524f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger        SkPMColor* SK_RESTRICT dstC, const SkPMColor* SK_RESTRICT cache,
18531cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        int count);
18541cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger
18551cab2921ab279367f8206cdadc9259d12e603548Derek Sollenbergervoid shadeSpan_twopoint_clamp(SkScalar fx, SkScalar dx,
18561cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        SkScalar fy, SkScalar dy,
18571cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        SkScalar b, SkScalar db,
18581cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        SkScalar fSr2D2, SkScalar foura, SkScalar fOneOverTwoA, bool posRoot,
18594f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger        SkPMColor* SK_RESTRICT dstC, const SkPMColor* SK_RESTRICT cache,
18601cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        int count) {
18611cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    for (; count > 0; --count) {
18621cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        SkFixed t = two_point_radial(b, fx, fy, fSr2D2, foura,
18631cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                                     fOneOverTwoA, posRoot);
18641cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        SkFixed index = SkClampMax(t, 0xFFFF);
18651cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        SkASSERT(index <= 0xFFFF);
18661cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        *dstC++ = cache[index >> Gradient_Shader::kCache32Shift];
18671cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        fx += dx;
18681cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        fy += dy;
18691cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        b += db;
18701cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    }
18711cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger}
18721cab2921ab279367f8206cdadc9259d12e603548Derek Sollenbergervoid shadeSpan_twopoint_mirror(SkScalar fx, SkScalar dx,
18731cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        SkScalar fy, SkScalar dy,
18741cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        SkScalar b, SkScalar db,
18751cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        SkScalar fSr2D2, SkScalar foura, SkScalar fOneOverTwoA, bool posRoot,
18764f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger        SkPMColor* SK_RESTRICT dstC, const SkPMColor* SK_RESTRICT cache,
18771cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        int count) {
18781cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    for (; count > 0; --count) {
18791cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        SkFixed t = two_point_radial(b, fx, fy, fSr2D2, foura,
18801cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                                     fOneOverTwoA, posRoot);
18811cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        SkFixed index = mirror_tileproc(t);
18821cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        SkASSERT(index <= 0xFFFF);
18831cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        *dstC++ = cache[index >> Gradient_Shader::kCache32Shift];
18841cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        fx += dx;
18851cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        fy += dy;
18861cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        b += db;
18871cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    }
18881cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger}
18891cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger
18901cab2921ab279367f8206cdadc9259d12e603548Derek Sollenbergervoid shadeSpan_twopoint_repeat(SkScalar fx, SkScalar dx,
18911cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        SkScalar fy, SkScalar dy,
18921cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        SkScalar b, SkScalar db,
18931cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        SkScalar fSr2D2, SkScalar foura, SkScalar fOneOverTwoA, bool posRoot,
18944f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger        SkPMColor* SK_RESTRICT dstC, const SkPMColor* SK_RESTRICT cache,
18951cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        int count) {
18961cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    for (; count > 0; --count) {
18971cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        SkFixed t = two_point_radial(b, fx, fy, fSr2D2, foura,
18981cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                                     fOneOverTwoA, posRoot);
18991cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        SkFixed index = repeat_tileproc(t);
19001cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        SkASSERT(index <= 0xFFFF);
19011cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        *dstC++ = cache[index >> Gradient_Shader::kCache32Shift];
19021cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        fx += dx;
19031cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        fy += dy;
19041cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        b += db;
19051cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    }
19061cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger}
19071cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger
19081cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger
19091cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger
19101cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger}
1911924f59d3627a697f2b0df3299915e814e160f981Mike Reed
1912924f59d3627a697f2b0df3299915e814e160f981Mike Reedclass Two_Point_Radial_Gradient : public Gradient_Shader {
1913924f59d3627a697f2b0df3299915e814e160f981Mike Reedpublic:
1914924f59d3627a697f2b0df3299915e814e160f981Mike Reed    Two_Point_Radial_Gradient(const SkPoint& start, SkScalar startRadius,
1915924f59d3627a697f2b0df3299915e814e160f981Mike Reed                              const SkPoint& end, SkScalar endRadius,
1916924f59d3627a697f2b0df3299915e814e160f981Mike Reed                              const SkColor colors[], const SkScalar pos[],
1917924f59d3627a697f2b0df3299915e814e160f981Mike Reed                              int colorCount, SkShader::TileMode mode,
1918924f59d3627a697f2b0df3299915e814e160f981Mike Reed                              SkUnitMapper* mapper)
191905b6b4d746867a9fb02e14edfe1bf3685abeb813Derek Sollenberger            : Gradient_Shader(colors, pos, colorCount, mode, mapper),
192005b6b4d746867a9fb02e14edfe1bf3685abeb813Derek Sollenberger              fCenter1(start),
192105b6b4d746867a9fb02e14edfe1bf3685abeb813Derek Sollenberger              fCenter2(end),
192205b6b4d746867a9fb02e14edfe1bf3685abeb813Derek Sollenberger              fRadius1(startRadius),
192305b6b4d746867a9fb02e14edfe1bf3685abeb813Derek Sollenberger              fRadius2(endRadius) {
192405b6b4d746867a9fb02e14edfe1bf3685abeb813Derek Sollenberger        init();
1925924f59d3627a697f2b0df3299915e814e160f981Mike Reed    }
192640528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger
192740528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger    virtual BitmapType asABitmap(SkBitmap* bitmap,
192840528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger                                 SkMatrix* matrix,
192940528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger                                 TileMode* xy,
193005b6b4d746867a9fb02e14edfe1bf3685abeb813Derek Sollenberger                                 SkScalar* twoPointRadialParams) const {
193140528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger        if (bitmap) {
193240528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger            this->commonAsABitmap(bitmap);
193340528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger        }
193440528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger        SkScalar diffL = 0; // just to avoid gcc warning
193540528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger        if (matrix || twoPointRadialParams) {
193640528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger            diffL = SkScalarSqrt(SkScalarSquare(fDiff.fX) +
193740528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger                                 SkScalarSquare(fDiff.fY));
193840528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger        }
193940528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger        if (matrix) {
194087b8e645865f9633f410c02252a0fd3feb18f09bDerek Sollenberger            if (diffL) {
194187b8e645865f9633f410c02252a0fd3feb18f09bDerek Sollenberger                SkScalar invDiffL = SkScalarInvert(diffL);
194287b8e645865f9633f410c02252a0fd3feb18f09bDerek Sollenberger                matrix->setSinCos(-SkScalarMul(invDiffL, fDiff.fY),
194387b8e645865f9633f410c02252a0fd3feb18f09bDerek Sollenberger                                  SkScalarMul(invDiffL, fDiff.fX));
194487b8e645865f9633f410c02252a0fd3feb18f09bDerek Sollenberger            } else {
194587b8e645865f9633f410c02252a0fd3feb18f09bDerek Sollenberger                matrix->reset();
194687b8e645865f9633f410c02252a0fd3feb18f09bDerek Sollenberger            }
194740528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger            matrix->preConcat(fPtsToUnit);
194840528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger        }
194940528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger        if (xy) {
195040528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger            xy[0] = fTileMode;
195140528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger            xy[1] = kClamp_TileMode;
195240528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger        }
195340528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger        if (NULL != twoPointRadialParams) {
195440528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger            twoPointRadialParams[0] = diffL;
195540528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger            twoPointRadialParams[1] = fStartRadius;
195640528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger            twoPointRadialParams[2] = fDiffRadius;
195740528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger        }
195840528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger        return kTwoPointRadial_BitmapType;
195940528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger    }
196040528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger
19611cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    virtual GradientType asAGradient(GradientInfo* info) const SK_OVERRIDE {
196205b6b4d746867a9fb02e14edfe1bf3685abeb813Derek Sollenberger        if (info) {
196305b6b4d746867a9fb02e14edfe1bf3685abeb813Derek Sollenberger            commonAsAGradient(info);
196405b6b4d746867a9fb02e14edfe1bf3685abeb813Derek Sollenberger            info->fPoint[0] = fCenter1;
196505b6b4d746867a9fb02e14edfe1bf3685abeb813Derek Sollenberger            info->fPoint[1] = fCenter2;
196605b6b4d746867a9fb02e14edfe1bf3685abeb813Derek Sollenberger            info->fRadius[0] = fRadius1;
196705b6b4d746867a9fb02e14edfe1bf3685abeb813Derek Sollenberger            info->fRadius[1] = fRadius2;
196805b6b4d746867a9fb02e14edfe1bf3685abeb813Derek Sollenberger        }
196905b6b4d746867a9fb02e14edfe1bf3685abeb813Derek Sollenberger        return kRadial2_GradientType;
197005b6b4d746867a9fb02e14edfe1bf3685abeb813Derek Sollenberger    }
197105b6b4d746867a9fb02e14edfe1bf3685abeb813Derek Sollenberger
19721cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    virtual void shadeSpan(int x, int y, SkPMColor* SK_RESTRICT dstC,
19731cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                           int count) SK_OVERRIDE {
197435e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger        SkASSERT(count > 0);
197535e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger
197635e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger        // Zero difference between radii:  fill with transparent black.
197735e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger        if (fDiffRadius == 0) {
197835e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger          sk_bzero(dstC, count * sizeof(*dstC));
197935e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger          return;
198035e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger        }
198135e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger        SkMatrix::MapXYProc dstProc = fDstToIndexProc;
198235e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger        TileProc            proc = fTileProc;
19831cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        const SkPMColor* SK_RESTRICT cache = this->getCache32();
198435e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger
198535e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger        SkScalar foura = fA * 4;
198635e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger        bool posRoot = fDiffRadius < 0;
198735e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger        if (fDstToIndexClass != kPerspective_MatrixClass) {
198835e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger            SkPoint srcPt;
198935e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger            dstProc(fDstToIndex, SkIntToScalar(x) + SK_ScalarHalf,
199035e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger                                 SkIntToScalar(y) + SK_ScalarHalf, &srcPt);
199135e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger            SkScalar dx, fx = srcPt.fX;
199235e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger            SkScalar dy, fy = srcPt.fY;
199335e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger
199435e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger            if (fDstToIndexClass == kFixedStepInX_MatrixClass) {
199535e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger                SkFixed fixedX, fixedY;
199635e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger                (void)fDstToIndex.fixedStepInX(SkIntToScalar(y), &fixedX, &fixedY);
199735e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger                dx = SkFixedToScalar(fixedX);
199835e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger                dy = SkFixedToScalar(fixedY);
199935e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger            } else {
200035e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger                SkASSERT(fDstToIndexClass == kLinear_MatrixClass);
200135e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger                dx = fDstToIndex.getScaleX();
200235e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger                dy = fDstToIndex.getSkewY();
200335e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger            }
200435e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger            SkScalar b = (SkScalarMul(fDiff.fX, fx) +
200535e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger                         SkScalarMul(fDiff.fY, fy) - fStartRadius) * 2;
200635e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger            SkScalar db = (SkScalarMul(fDiff.fX, dx) +
200735e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger                          SkScalarMul(fDiff.fY, dy)) * 2;
20081cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger
20091cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger            TwoPointRadialShadeProc shadeProc = shadeSpan_twopoint_repeat;
201035e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger            if (proc == clamp_tileproc) {
20111cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                shadeProc = shadeSpan_twopoint_clamp;
201235e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger            } else if (proc == mirror_tileproc) {
20131cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                shadeProc = shadeSpan_twopoint_mirror;
201435e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger            } else {
201535e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger                SkASSERT(proc == repeat_tileproc);
201635e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger            }
20171cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger            (*shadeProc)(fx, dx, fy, dy, b, db,
20181cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                         fSr2D2, foura, fOneOverTwoA, posRoot,
20191cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                         dstC, cache, count);
202035e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger        } else {    // perspective case
202135e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger            SkScalar dstX = SkIntToScalar(x);
202235e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger            SkScalar dstY = SkIntToScalar(y);
202335e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger            for (; count > 0; --count) {
202435e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger                SkPoint             srcPt;
202535e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger                dstProc(fDstToIndex, dstX, dstY, &srcPt);
202635e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger                SkScalar fx = srcPt.fX;
202735e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger                SkScalar fy = srcPt.fY;
202835e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger                SkScalar b = (SkScalarMul(fDiff.fX, fx) +
202935e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger                             SkScalarMul(fDiff.fY, fy) - fStartRadius) * 2;
20301cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                SkFixed t = two_point_radial(b, fx, fy, fSr2D2, foura,
20311cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                                             fOneOverTwoA, posRoot);
203235e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger                SkFixed index = proc(t);
203335e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger                SkASSERT(index <= 0xFFFF);
20341cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                *dstC++ = cache[index >> Gradient_Shader::kCache32Shift];
203535e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger                dstX += SK_Scalar1;
203635e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger            }
203735e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger        }
203835e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger    }
2039924f59d3627a697f2b0df3299915e814e160f981Mike Reed
2040924f59d3627a697f2b0df3299915e814e160f981Mike Reed    virtual bool setContext(const SkBitmap& device,
2041924f59d3627a697f2b0df3299915e814e160f981Mike Reed                            const SkPaint& paint,
20421cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                            const SkMatrix& matrix) SK_OVERRIDE {
2043924f59d3627a697f2b0df3299915e814e160f981Mike Reed        if (!this->INHERITED::setContext(device, paint, matrix)) {
2044924f59d3627a697f2b0df3299915e814e160f981Mike Reed            return false;
2045924f59d3627a697f2b0df3299915e814e160f981Mike Reed        }
2046924f59d3627a697f2b0df3299915e814e160f981Mike Reed
2047924f59d3627a697f2b0df3299915e814e160f981Mike Reed        // we don't have a span16 proc
2048924f59d3627a697f2b0df3299915e814e160f981Mike Reed        fFlags &= ~kHasSpan16_Flag;
2049924f59d3627a697f2b0df3299915e814e160f981Mike Reed        return true;
2050924f59d3627a697f2b0df3299915e814e160f981Mike Reed    }
2051924f59d3627a697f2b0df3299915e814e160f981Mike Reed
205240528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger    static SkFlattenable* CreateProc(SkFlattenableReadBuffer& buffer) {
2053924f59d3627a697f2b0df3299915e814e160f981Mike Reed        return SkNEW_ARGS(Two_Point_Radial_Gradient, (buffer));
2054924f59d3627a697f2b0df3299915e814e160f981Mike Reed    }
2055924f59d3627a697f2b0df3299915e814e160f981Mike Reed
20561cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    virtual void flatten(SkFlattenableWriteBuffer& buffer) SK_OVERRIDE {
205724fb8c7cc7b76134a25914d8f6346c89c359c621Mike Reed        this->INHERITED::flatten(buffer);
205805b6b4d746867a9fb02e14edfe1bf3685abeb813Derek Sollenberger        buffer.writeScalar(fCenter1.fX);
205905b6b4d746867a9fb02e14edfe1bf3685abeb813Derek Sollenberger        buffer.writeScalar(fCenter1.fY);
206005b6b4d746867a9fb02e14edfe1bf3685abeb813Derek Sollenberger        buffer.writeScalar(fCenter2.fX);
206105b6b4d746867a9fb02e14edfe1bf3685abeb813Derek Sollenberger        buffer.writeScalar(fCenter2.fY);
206205b6b4d746867a9fb02e14edfe1bf3685abeb813Derek Sollenberger        buffer.writeScalar(fRadius1);
206305b6b4d746867a9fb02e14edfe1bf3685abeb813Derek Sollenberger        buffer.writeScalar(fRadius2);
206424fb8c7cc7b76134a25914d8f6346c89c359c621Mike Reed    }
206540528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger
2066924f59d3627a697f2b0df3299915e814e160f981Mike Reedprotected:
206724fb8c7cc7b76134a25914d8f6346c89c359c621Mike Reed    Two_Point_Radial_Gradient(SkFlattenableReadBuffer& buffer)
206805b6b4d746867a9fb02e14edfe1bf3685abeb813Derek Sollenberger            : Gradient_Shader(buffer),
206935e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger              fCenter1(unflatten_point(buffer)),
207035e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger              fCenter2(unflatten_point(buffer)),
207105b6b4d746867a9fb02e14edfe1bf3685abeb813Derek Sollenberger              fRadius1(buffer.readScalar()),
207205b6b4d746867a9fb02e14edfe1bf3685abeb813Derek Sollenberger              fRadius2(buffer.readScalar()) {
207305b6b4d746867a9fb02e14edfe1bf3685abeb813Derek Sollenberger        init();
207424fb8c7cc7b76134a25914d8f6346c89c359c621Mike Reed    };
20751cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    virtual Factory getFactory() SK_OVERRIDE { return CreateProc; }
2076924f59d3627a697f2b0df3299915e814e160f981Mike Reed
2077924f59d3627a697f2b0df3299915e814e160f981Mike Reedprivate:
2078924f59d3627a697f2b0df3299915e814e160f981Mike Reed    typedef Gradient_Shader INHERITED;
207905b6b4d746867a9fb02e14edfe1bf3685abeb813Derek Sollenberger    const SkPoint fCenter1;
208005b6b4d746867a9fb02e14edfe1bf3685abeb813Derek Sollenberger    const SkPoint fCenter2;
208105b6b4d746867a9fb02e14edfe1bf3685abeb813Derek Sollenberger    const SkScalar fRadius1;
208205b6b4d746867a9fb02e14edfe1bf3685abeb813Derek Sollenberger    const SkScalar fRadius2;
2083924f59d3627a697f2b0df3299915e814e160f981Mike Reed    SkPoint fDiff;
2084924f59d3627a697f2b0df3299915e814e160f981Mike Reed    SkScalar fStartRadius, fDiffRadius, fSr2D2, fA, fOneOverTwoA;
208505b6b4d746867a9fb02e14edfe1bf3685abeb813Derek Sollenberger
208605b6b4d746867a9fb02e14edfe1bf3685abeb813Derek Sollenberger    void init() {
208705b6b4d746867a9fb02e14edfe1bf3685abeb813Derek Sollenberger        fDiff = fCenter1 - fCenter2;
208805b6b4d746867a9fb02e14edfe1bf3685abeb813Derek Sollenberger        fDiffRadius = fRadius2 - fRadius1;
208905b6b4d746867a9fb02e14edfe1bf3685abeb813Derek Sollenberger        SkScalar inv = SkScalarInvert(fDiffRadius);
209005b6b4d746867a9fb02e14edfe1bf3685abeb813Derek Sollenberger        fDiff.fX = SkScalarMul(fDiff.fX, inv);
209105b6b4d746867a9fb02e14edfe1bf3685abeb813Derek Sollenberger        fDiff.fY = SkScalarMul(fDiff.fY, inv);
209205b6b4d746867a9fb02e14edfe1bf3685abeb813Derek Sollenberger        fStartRadius = SkScalarMul(fRadius1, inv);
209305b6b4d746867a9fb02e14edfe1bf3685abeb813Derek Sollenberger        fSr2D2 = SkScalarSquare(fStartRadius);
209405b6b4d746867a9fb02e14edfe1bf3685abeb813Derek Sollenberger        fA = SkScalarSquare(fDiff.fX) + SkScalarSquare(fDiff.fY) - SK_Scalar1;
20951cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        fOneOverTwoA = fA ? SkScalarInvert(fA * 2) : 0;
209605b6b4d746867a9fb02e14edfe1bf3685abeb813Derek Sollenberger
209705b6b4d746867a9fb02e14edfe1bf3685abeb813Derek Sollenberger        fPtsToUnit.setTranslate(-fCenter1.fX, -fCenter1.fY);
209805b6b4d746867a9fb02e14edfe1bf3685abeb813Derek Sollenberger        fPtsToUnit.postScale(inv, inv);
209905b6b4d746867a9fb02e14edfe1bf3685abeb813Derek Sollenberger    }
2100924f59d3627a697f2b0df3299915e814e160f981Mike Reed};
2101924f59d3627a697f2b0df3299915e814e160f981Mike Reed
21020910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project///////////////////////////////////////////////////////////////////////////////
21030910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
21040910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectclass Sweep_Gradient : public Gradient_Shader {
21050910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectpublic:
21060910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    Sweep_Gradient(SkScalar cx, SkScalar cy, const SkColor colors[],
21070910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                   const SkScalar pos[], int count, SkUnitMapper* mapper)
210805b6b4d746867a9fb02e14edfe1bf3685abeb813Derek Sollenberger    : Gradient_Shader(colors, pos, count, SkShader::kClamp_TileMode, mapper),
210905b6b4d746867a9fb02e14edfe1bf3685abeb813Derek Sollenberger      fCenter(SkPoint::Make(cx, cy))
21100910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    {
21110910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        fPtsToUnit.setTranslate(-cx, -cy);
21120910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
21131cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    virtual void shadeSpan(int x, int y, SkPMColor dstC[], int count) SK_OVERRIDE;
21141cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    virtual void shadeSpan16(int x, int y, uint16_t dstC[], int count) SK_OVERRIDE;
211540528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger
211640528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger    virtual BitmapType asABitmap(SkBitmap* bitmap,
211740528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger                                 SkMatrix* matrix,
211840528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger                                 TileMode* xy,
21191cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                                 SkScalar* twoPointRadialParams) const SK_OVERRIDE {
212040528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger        if (bitmap) {
212140528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger            this->commonAsABitmap(bitmap);
212240528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger        }
212340528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger        if (matrix) {
212440528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger            *matrix = fPtsToUnit;
212540528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger        }
212640528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger        if (xy) {
212740528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger            xy[0] = fTileMode;
212840528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger            xy[1] = kClamp_TileMode;
212940528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger        }
213040528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger        return kSweep_BitmapType;
213140528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger    }
213240528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger
21331cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    virtual GradientType asAGradient(GradientInfo* info) const SK_OVERRIDE {
213405b6b4d746867a9fb02e14edfe1bf3685abeb813Derek Sollenberger        if (info) {
213505b6b4d746867a9fb02e14edfe1bf3685abeb813Derek Sollenberger            commonAsAGradient(info);
213605b6b4d746867a9fb02e14edfe1bf3685abeb813Derek Sollenberger            info->fPoint[0] = fCenter;
213705b6b4d746867a9fb02e14edfe1bf3685abeb813Derek Sollenberger        }
213805b6b4d746867a9fb02e14edfe1bf3685abeb813Derek Sollenberger        return kSweep_GradientType;
213905b6b4d746867a9fb02e14edfe1bf3685abeb813Derek Sollenberger    }
214005b6b4d746867a9fb02e14edfe1bf3685abeb813Derek Sollenberger
21410910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    static SkFlattenable* CreateProc(SkFlattenableReadBuffer& buffer) {
21420910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        return SkNEW_ARGS(Sweep_Gradient, (buffer));
21430910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
21440910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
21451cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    virtual void flatten(SkFlattenableWriteBuffer& buffer) SK_OVERRIDE {
214605b6b4d746867a9fb02e14edfe1bf3685abeb813Derek Sollenberger        this->INHERITED::flatten(buffer);
214705b6b4d746867a9fb02e14edfe1bf3685abeb813Derek Sollenberger        buffer.writeScalar(fCenter.fX);
214805b6b4d746867a9fb02e14edfe1bf3685abeb813Derek Sollenberger        buffer.writeScalar(fCenter.fY);
214905b6b4d746867a9fb02e14edfe1bf3685abeb813Derek Sollenberger    }
215005b6b4d746867a9fb02e14edfe1bf3685abeb813Derek Sollenberger
21510910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectprotected:
215205b6b4d746867a9fb02e14edfe1bf3685abeb813Derek Sollenberger    Sweep_Gradient(SkFlattenableReadBuffer& buffer)
215305b6b4d746867a9fb02e14edfe1bf3685abeb813Derek Sollenberger        : Gradient_Shader(buffer),
215435e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger          fCenter(unflatten_point(buffer)) {
215505b6b4d746867a9fb02e14edfe1bf3685abeb813Derek Sollenberger    }
215605b6b4d746867a9fb02e14edfe1bf3685abeb813Derek Sollenberger
21571cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    virtual Factory getFactory() SK_OVERRIDE { return CreateProc; }
21580910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
21590910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectprivate:
21600910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    typedef Gradient_Shader INHERITED;
216105b6b4d746867a9fb02e14edfe1bf3685abeb813Derek Sollenberger    const SkPoint fCenter;
21620910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project};
21630910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
21640910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#ifdef COMPUTE_SWEEP_TABLE
21650910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#define PI  3.14159265
21660910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectstatic bool gSweepTableReady;
21670910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectstatic uint8_t gSweepTable[65];
21680910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
21690910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project/*  Our table stores precomputed values for atan: [0...1] -> [0..PI/4]
21700910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    We scale the results to [0..32]
21710910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project*/
217235e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenbergerstatic const uint8_t* build_sweep_table() {
217335e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger    if (!gSweepTableReady) {
21740910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        const int N = 65;
21750910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        const double DENOM = N - 1;
217640528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger
21770910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        for (int i = 0; i < N; i++)
21780910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        {
21790910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            double arg = i / DENOM;
21800910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            double v = atan(arg);
21810910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            int iv = (int)round(v * DENOM * 2 / PI);
21820910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project//            printf("[%d] atan(%g) = %g %d\n", i, arg, v, iv);
21830910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            printf("%d, ", iv);
21840910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            gSweepTable[i] = iv;
21850910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        }
21860910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        gSweepTableReady = true;
21870910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
21880910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    return gSweepTable;
21890910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
21900910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#else
21910910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectstatic const uint8_t gSweepTable[] = {
21920910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    0, 1, 1, 2, 3, 3, 4, 4, 5, 6, 6, 7, 8, 8, 9, 9,
21930910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    10, 11, 11, 12, 12, 13, 13, 14, 15, 15, 16, 16, 17, 17, 18, 18,
21940910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    19, 19, 20, 20, 21, 21, 22, 22, 23, 23, 24, 24, 25, 25, 25, 26,
21950910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    26, 27, 27, 27, 28, 28, 29, 29, 29, 30, 30, 30, 31, 31, 31, 32,
21960910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    32
21970910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project};
21980910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectstatic const uint8_t* build_sweep_table() { return gSweepTable; }
21990910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#endif
22000910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
22010910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project// divide numer/denom, with a bias of 6bits. Assumes numer <= denom
22020910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project// and denom != 0. Since our table is 6bits big (+1), this is a nice fit.
22030910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project// Same as (but faster than) SkFixedDiv(numer, denom) >> 10
22040910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
22050910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project//unsigned div_64(int numer, int denom);
220635e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenbergerstatic unsigned div_64(int numer, int denom) {
22070910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkASSERT(numer <= denom);
22080910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkASSERT(numer > 0);
22090910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkASSERT(denom > 0);
221040528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger
22110910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    int nbits = SkCLZ(numer);
22120910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    int dbits = SkCLZ(denom);
22130910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    int bits = 6 - nbits + dbits;
22140910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkASSERT(bits <= 6);
221540528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger
221635e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger    if (bits < 0) {  // detect underflow
22170910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        return 0;
221835e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger    }
22190910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
22200910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    denom <<= dbits - 1;
22210910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    numer <<= nbits - 1;
22220910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
22230910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    unsigned result = 0;
22240910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
22250910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    // do the first one
222635e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger    if ((numer -= denom) >= 0) {
22270910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        result = 1;
222835e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger    } else {
22290910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        numer += denom;
223035e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger    }
223140528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger
22320910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    // Now fall into our switch statement if there are more bits to compute
223335e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger    if (bits > 0) {
22340910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        // make room for the rest of the answer bits
22350910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        result <<= bits;
22360910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        switch (bits) {
22370910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        case 6:
22380910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            if ((numer = (numer << 1) - denom) >= 0)
22390910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                result |= 32;
22400910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            else
22410910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                numer += denom;
22420910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        case 5:
22430910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            if ((numer = (numer << 1) - denom) >= 0)
22440910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                result |= 16;
22450910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            else
22460910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                numer += denom;
22470910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        case 4:
22480910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            if ((numer = (numer << 1) - denom) >= 0)
22490910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                result |= 8;
22500910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            else
22510910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                numer += denom;
22520910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        case 3:
22530910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            if ((numer = (numer << 1) - denom) >= 0)
22540910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                result |= 4;
22550910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            else
22560910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                numer += denom;
22570910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        case 2:
22580910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            if ((numer = (numer << 1) - denom) >= 0)
22590910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                result |= 2;
22600910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            else
22610910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                numer += denom;
22620910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        case 1:
22630910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        default:    // not strictly need, but makes GCC make better ARM code
22640910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            if ((numer = (numer << 1) - denom) >= 0)
22650910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                result |= 1;
22660910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            else
22670910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                numer += denom;
22680910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        }
22690910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
22700910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    return result;
22710910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
22720910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
22730910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project// Given x,y in the first quadrant, return 0..63 for the angle [0..90]
227435e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenbergerstatic unsigned atan_0_90(SkFixed y, SkFixed x) {
22750910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#ifdef SK_DEBUG
22760910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    {
22770910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        static bool gOnce;
227835e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger        if (!gOnce) {
22790910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            gOnce = true;
22800910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            SkASSERT(div_64(55, 55) == 64);
22810910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            SkASSERT(div_64(128, 256) == 32);
22820910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            SkASSERT(div_64(2326528, 4685824) == 31);
22830910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            SkASSERT(div_64(753664, 5210112) == 9);
22840910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            SkASSERT(div_64(229376, 4882432) == 3);
22850910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            SkASSERT(div_64(2, 64) == 2);
22860910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            SkASSERT(div_64(1, 64) == 1);
22870910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            // test that we handle underflow correctly
22880910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            SkASSERT(div_64(12345, 0x54321234) == 0);
22890910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        }
22900910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
22910910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#endif
22920910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
22930910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkASSERT(y > 0 && x > 0);
22940910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    const uint8_t* table = build_sweep_table();
22950910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
22960910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    unsigned result;
22970910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    bool swap = (x < y);
229835e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger    if (swap) {
22990910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        // first part of the atan(v) = PI/2 - atan(1/v) identity
23000910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        // since our div_64 and table want v <= 1, where v = y/x
23010910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        SkTSwap<SkFixed>(x, y);
23020910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
23030910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
23040910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    result = div_64(y, x);
230540528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger
23060910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#ifdef SK_DEBUG
23070910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    {
23080910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        unsigned result2 = SkDivBits(y, x, 6);
23090910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        SkASSERT(result2 == result ||
23100910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                 (result == 1 && result2 == 0));
23110910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
23120910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#endif
23130910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
23140910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkASSERT(result < SK_ARRAY_COUNT(gSweepTable));
23150910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    result = table[result];
23160910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
231735e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger    if (swap) {
23180910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        // complete the atan(v) = PI/2 - atan(1/v) identity
23190910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        result = 64 - result;
23200910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        // pin to 63
23210910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        result -= result >> 6;
23220910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
23230910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
23240910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkASSERT(result <= 63);
23250910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    return result;
23260910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
23270910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
23280910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project//  returns angle in a circle [0..2PI) -> [0..255]
23291cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger#ifdef SK_SCALAR_IS_FLOAT
23301cab2921ab279367f8206cdadc9259d12e603548Derek Sollenbergerstatic unsigned SkATan2_255(float y, float x) {
23311cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    //    static const float g255Over2PI = 255 / (2 * SK_ScalarPI);
23321cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    static const float g255Over2PI = 40.584510488433314f;
23331cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger
23341cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    float result = sk_float_atan2(y, x);
23351cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    if (result < 0) {
23361cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        result += 2 * SK_ScalarPI;
23371cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    }
23381cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    SkASSERT(result >= 0);
23391cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    // since our value is always >= 0, we can cast to int, which is faster than
23401cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    // calling floorf()
23411cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    int ir = (int)(result * g255Over2PI);
23421cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    SkASSERT(ir >= 0 && ir <= 255);
23431cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    return ir;
23441cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger}
23451cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger#else
234635e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenbergerstatic unsigned SkATan2_255(SkFixed y, SkFixed x) {
234735e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger    if (x == 0) {
234835e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger        if (y == 0) {
23490910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            return 0;
235035e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger        }
23510910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        return y < 0 ? 192 : 64;
23520910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
235335e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger    if (y == 0) {
23540910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        return x < 0 ? 128 : 0;
235535e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger    }
235640528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger
23570910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    /*  Find the right quadrant for x,y
23580910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        Since atan_0_90 only handles the first quadrant, we rotate x,y
23590910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        appropriately before calling it, and then add the right amount
23600910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        to account for the real quadrant.
23610910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        quadrant 0 : add 0                  | x > 0 && y > 0
23620910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        quadrant 1 : add 64 (90 degrees)    | x < 0 && y > 0
23630910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        quadrant 2 : add 128 (180 degrees)  | x < 0 && y < 0
23640910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        quadrant 3 : add 192 (270 degrees)  | x > 0 && y < 0
236540528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger
23660910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        map x<0 to (1 << 6)
23670910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        map y<0 to (3 << 6)
23680910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        add = map_x ^ map_y
23690910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    */
23700910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    int xsign = x >> 31;
23710910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    int ysign = y >> 31;
23720910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    int add = ((-xsign) ^ (ysign & 3)) << 6;
23730910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
23740910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#ifdef SK_DEBUG
23750910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    if (0 == add)
23760910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        SkASSERT(x > 0 && y > 0);
23770910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    else if (64 == add)
23780910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        SkASSERT(x < 0 && y > 0);
23790910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    else if (128 == add)
23800910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        SkASSERT(x < 0 && y < 0);
23810910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    else if (192 == add)
23820910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        SkASSERT(x > 0 && y < 0);
23830910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    else
23841cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        SkDEBUGFAIL("bad value for add");
23850910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#endif
238640528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger
23870910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    /*  This ^ trick makes x, y positive, and the swap<> handles quadrants
23880910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        where we need to rotate x,y by 90 or -90
23890910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    */
23900910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    x = (x ^ xsign) - xsign;
23910910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    y = (y ^ ysign) - ysign;
239235e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger    if (add & 64) {             // quads 1 or 3 need to swap x,y
23930910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        SkTSwap<SkFixed>(x, y);
239435e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger    }
23950910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
23960910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    unsigned result = add + atan_0_90(y, x);
23970910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkASSERT(result < 256);
23980910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    return result;
23990910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
24001cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger#endif
24010910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
24024f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenbergervoid Sweep_Gradient::shadeSpan(int x, int y, SkPMColor* SK_RESTRICT dstC,
24034f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger                               int count) {
24040910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkMatrix::MapXYProc proc = fDstToIndexProc;
24050910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    const SkMatrix&     matrix = fDstToIndex;
24061cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    const SkPMColor* SK_RESTRICT cache = this->getCache32();
24070910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkPoint             srcPt;
240840528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger
240935e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger    if (fDstToIndexClass != kPerspective_MatrixClass) {
24100910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        proc(matrix, SkIntToScalar(x) + SK_ScalarHalf,
24110910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                     SkIntToScalar(y) + SK_ScalarHalf, &srcPt);
24121cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        SkScalar dx, fx = srcPt.fX;
24131cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        SkScalar dy, fy = srcPt.fY;
241440528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger
241535e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger        if (fDstToIndexClass == kFixedStepInX_MatrixClass) {
24160910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            SkFixed storage[2];
24170910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            (void)matrix.fixedStepInX(SkIntToScalar(y) + SK_ScalarHalf,
24180910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                                      &storage[0], &storage[1]);
24191cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger            dx = SkFixedToScalar(storage[0]);
24201cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger            dy = SkFixedToScalar(storage[1]);
242135e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger        } else {
24220910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            SkASSERT(fDstToIndexClass == kLinear_MatrixClass);
24231cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger            dx = matrix.getScaleX();
24241cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger            dy = matrix.getSkewY();
24250910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        }
242640528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger
242735e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger        for (; count > 0; --count) {
24280910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            *dstC++ = cache[SkATan2_255(fy, fx)];
24290910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            fx += dx;
24300910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            fy += dy;
24310910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        }
243235e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger    } else {  // perspective case
243335e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger        for (int stop = x + count; x < stop; x++) {
24340910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            proc(matrix, SkIntToScalar(x) + SK_ScalarHalf,
24351cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                         SkIntToScalar(y) + SK_ScalarHalf, &srcPt);
24361cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger            *dstC++ = cache[SkATan2_255(srcPt.fY, srcPt.fX)];
24370910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        }
24380910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
24390910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
24400910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
24414f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenbergervoid Sweep_Gradient::shadeSpan16(int x, int y, uint16_t* SK_RESTRICT dstC,
24424f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger                                 int count) {
24430910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkMatrix::MapXYProc proc = fDstToIndexProc;
24440910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    const SkMatrix&     matrix = fDstToIndex;
24451cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    const uint16_t* SK_RESTRICT cache = this->getCache16();
24464f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger    int                 toggle = ((x ^ y) & 1) * kDitherStride16;
24470910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkPoint             srcPt;
24480910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
244935e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger    if (fDstToIndexClass != kPerspective_MatrixClass) {
24500910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        proc(matrix, SkIntToScalar(x) + SK_ScalarHalf,
24510910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                     SkIntToScalar(y) + SK_ScalarHalf, &srcPt);
24521cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        SkScalar dx, fx = srcPt.fX;
24531cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        SkScalar dy, fy = srcPt.fY;
245440528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger
245535e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger        if (fDstToIndexClass == kFixedStepInX_MatrixClass) {
24560910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            SkFixed storage[2];
24570910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            (void)matrix.fixedStepInX(SkIntToScalar(y) + SK_ScalarHalf,
24580910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                                      &storage[0], &storage[1]);
24591cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger            dx = SkFixedToScalar(storage[0]);
24601cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger            dy = SkFixedToScalar(storage[1]);
246135e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger        } else {
24620910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            SkASSERT(fDstToIndexClass == kLinear_MatrixClass);
24631cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger            dx = matrix.getScaleX();
24641cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger            dy = matrix.getSkewY();
24650910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        }
246640528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger
246735e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger        for (; count > 0; --count) {
24680910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            int index = SkATan2_255(fy, fx) >> (8 - kCache16Bits);
24690910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            *dstC++ = cache[toggle + index];
24704f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger            toggle ^= kDitherStride16;
24710910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            fx += dx;
24720910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            fy += dy;
24730910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        }
247435e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger    } else {  // perspective case
247535e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger        for (int stop = x + count; x < stop; x++) {
24760910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            proc(matrix, SkIntToScalar(x) + SK_ScalarHalf,
24770910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                         SkIntToScalar(y) + SK_ScalarHalf, &srcPt);
247840528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger
24791cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger            int index = SkATan2_255(srcPt.fY, srcPt.fX);
24800910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            index >>= (8 - kCache16Bits);
24810910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            *dstC++ = cache[toggle + index];
24824f1dae40e24d57d647db01443b8bf2410514b8b5Derek Sollenberger            toggle ^= kDitherStride16;
24830910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        }
24840910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
24850910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
24860910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
248735e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger///////////////////////////////////////////////////////////////////////////////
248835e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger///////////////////////////////////////////////////////////////////////////////
24890910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
24900910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project// assumes colors is SkColor* and pos is SkScalar*
24910910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#define EXPAND_1_COLOR(count)               \
24920910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkColor tmp[2];                         \
24930910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    do {                                    \
24940910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        if (1 == count) {                   \
24950910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            tmp[0] = tmp[1] = colors[0];    \
24960910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            colors = tmp;                   \
24970910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            pos = NULL;                     \
24980910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            count = 2;                      \
24990910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        }                                   \
25000910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    } while (0)
25010910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
250235e2e62b55598210f6999fc2ea26ff8f41446ffeDerek SollenbergerSkShader* SkGradientShader::CreateLinear(const SkPoint pts[2],
250335e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger                                         const SkColor colors[],
250435e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger                                         const SkScalar pos[], int colorCount,
250535e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger                                         SkShader::TileMode mode,
250635e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger                                         SkUnitMapper* mapper) {
25070910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    if (NULL == pts || NULL == colors || colorCount < 1) {
25080910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        return NULL;
25090910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
25100910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    EXPAND_1_COLOR(colorCount);
25110910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
2512fadb93e0b43c7451032c46f3c58a1effa9d681b3Mike Reed    return SkNEW_ARGS(Linear_Gradient,
2513fadb93e0b43c7451032c46f3c58a1effa9d681b3Mike Reed                      (pts, colors, pos, colorCount, mode, mapper));
25140910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
25150910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
251635e2e62b55598210f6999fc2ea26ff8f41446ffeDerek SollenbergerSkShader* SkGradientShader::CreateRadial(const SkPoint& center, SkScalar radius,
251735e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger                                         const SkColor colors[],
251835e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger                                         const SkScalar pos[], int colorCount,
251935e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger                                         SkShader::TileMode mode,
252035e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger                                         SkUnitMapper* mapper) {
25210910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    if (radius <= 0 || NULL == colors || colorCount < 1) {
25220910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        return NULL;
25230910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
25240910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    EXPAND_1_COLOR(colorCount);
25250910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
2526fadb93e0b43c7451032c46f3c58a1effa9d681b3Mike Reed    return SkNEW_ARGS(Radial_Gradient,
2527fadb93e0b43c7451032c46f3c58a1effa9d681b3Mike Reed                      (center, radius, colors, pos, colorCount, mode, mapper));
25280910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
25290910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
2530924f59d3627a697f2b0df3299915e814e160f981Mike ReedSkShader* SkGradientShader::CreateTwoPointRadial(const SkPoint& start,
2531924f59d3627a697f2b0df3299915e814e160f981Mike Reed                                                 SkScalar startRadius,
2532924f59d3627a697f2b0df3299915e814e160f981Mike Reed                                                 const SkPoint& end,
2533924f59d3627a697f2b0df3299915e814e160f981Mike Reed                                                 SkScalar endRadius,
2534924f59d3627a697f2b0df3299915e814e160f981Mike Reed                                                 const SkColor colors[],
2535924f59d3627a697f2b0df3299915e814e160f981Mike Reed                                                 const SkScalar pos[],
2536924f59d3627a697f2b0df3299915e814e160f981Mike Reed                                                 int colorCount,
2537924f59d3627a697f2b0df3299915e814e160f981Mike Reed                                                 SkShader::TileMode mode,
253835e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger                                                 SkUnitMapper* mapper) {
2539924f59d3627a697f2b0df3299915e814e160f981Mike Reed    if (startRadius < 0 || endRadius < 0 || NULL == colors || colorCount < 1) {
2540924f59d3627a697f2b0df3299915e814e160f981Mike Reed        return NULL;
2541924f59d3627a697f2b0df3299915e814e160f981Mike Reed    }
2542924f59d3627a697f2b0df3299915e814e160f981Mike Reed    EXPAND_1_COLOR(colorCount);
2543924f59d3627a697f2b0df3299915e814e160f981Mike Reed
2544924f59d3627a697f2b0df3299915e814e160f981Mike Reed    return SkNEW_ARGS(Two_Point_Radial_Gradient,
254535e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger                      (start, startRadius, end, endRadius, colors, pos,
254635e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger                       colorCount, mode, mapper));
2547924f59d3627a697f2b0df3299915e814e160f981Mike Reed}
2548924f59d3627a697f2b0df3299915e814e160f981Mike Reed
25490910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source ProjectSkShader* SkGradientShader::CreateSweep(SkScalar cx, SkScalar cy,
25500910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                                        const SkColor colors[],
25510910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                                        const SkScalar pos[],
255235e2e62b55598210f6999fc2ea26ff8f41446ffeDerek Sollenberger                                        int count, SkUnitMapper* mapper) {
25530910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    if (NULL == colors || count < 1) {
25540910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        return NULL;
25550910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
25560910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    EXPAND_1_COLOR(count);
25570910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
25580910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    return SkNEW_ARGS(Sweep_Gradient, (cx, cy, colors, pos, count, mapper));
25590910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
25600910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
25611cab2921ab279367f8206cdadc9259d12e603548Derek SollenbergerSK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkGradientShader)
25621cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(Linear_Gradient)
25631cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(Radial_Gradient)
25640910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
25651cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(Sweep_Gradient)
25660910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
25671cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(Two_Point_Radial_Gradient)
25681cab2921ab279367f8206cdadc9259d12e603548Derek SollenbergerSK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END
2569