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