aboutsummaryrefslogtreecommitdiffstats
path: root/src/effects/SkGradientShader.cpp
diff options
context:
space:
mode:
authorMike Reed <>2009-04-03 06:34:07 -0700
committerThe Android Open Source Project <initial-contribution@android.com>2009-04-03 06:34:07 -0700
commitdba38ba49760ccfd15b2f257f4345e1670f8398a (patch)
tree40240c56ece6b7957b3dbecc6366bfb369edb866 /src/effects/SkGradientShader.cpp
parentda3b8b285a5e3e6f344461d67e3370b27701756d (diff)
downloadexternal_skia-dba38ba49760ccfd15b2f257f4345e1670f8398a.zip
external_skia-dba38ba49760ccfd15b2f257f4345e1670f8398a.tar.gz
external_skia-dba38ba49760ccfd15b2f257f4345e1670f8398a.tar.bz2
AI 144443: Change how skia handles gradient stops that are missing either pos=0 or pos=1. Instead of ignoring the first and last pos, and assuming they were 0,1, now we insert in the missing values. This matches webkit's expectations, and seems fine for skia clients as well.
On the webkit side, call Gradient::getColor() before we sniff the stops-array. This has the side-effect of sorting the stops, which we need for skia. BUG=1688373 Automated import of CL 144443
Diffstat (limited to 'src/effects/SkGradientShader.cpp')
-rw-r--r--src/effects/SkGradientShader.cpp270
1 files changed, 146 insertions, 124 deletions
diff --git a/src/effects/SkGradientShader.cpp b/src/effects/SkGradientShader.cpp
index 9b5d922..df46a8f 100644
--- a/src/effects/SkGradientShader.cpp
+++ b/src/effects/SkGradientShader.cpp
@@ -36,18 +36,15 @@
typedef SkFixed (*TileProc)(SkFixed);
-static SkFixed clamp_tileproc(SkFixed x)
-{
+static SkFixed clamp_tileproc(SkFixed x) {
return SkClampMax(x, 0xFFFF);
}
-static SkFixed repeat_tileproc(SkFixed x)
-{
+static SkFixed repeat_tileproc(SkFixed x) {
return x & 0xFFFF;
}
-static inline SkFixed mirror_tileproc(SkFixed x)
-{
+static inline SkFixed mirror_tileproc(SkFixed x) {
int s = x << 15 >> 31;
return (x ^ s) & 0xFFFF;
}
@@ -60,13 +57,11 @@ static const TileProc gTileProcs[] = {
//////////////////////////////////////////////////////////////////////////////
-static inline int repeat_6bits(int x)
-{
+static inline int repeat_6bits(int x) {
return x & 63;
}
-static inline int mirror_6bits(int x)
-{
+static inline int mirror_6bits(int x) {
#ifdef SK_CPU_HAS_CONDITIONAL_INSTR
if (x & 64)
x = ~x;
@@ -77,16 +72,15 @@ static inline int mirror_6bits(int x)
#endif
}
-static inline int repeat_8bits(int x)
-{
+static inline int repeat_8bits(int x) {
return x & 0xFF;
}
-static inline int mirror_8bits(int x)
-{
+static inline int mirror_8bits(int x) {
#ifdef SK_CPU_HAS_CONDITIONAL_INSTR
- if (x & 256)
+ if (x & 256) {
x = ~x;
+ }
return x & 255;
#else
int s = x << 23 >> 31;
@@ -99,7 +93,7 @@ static inline int mirror_8bits(int x)
class Gradient_Shader : public SkShader {
public:
Gradient_Shader(const SkColor colors[], const SkScalar pos[],
- int colorCount, SkShader::TileMode mode, SkUnitMapper* mapper);
+ int colorCount, SkShader::TileMode mode, SkUnitMapper* mapper);
virtual ~Gradient_Shader();
// overrides
@@ -115,7 +109,7 @@ protected:
SkPMColor* fARGB32;
TileMode fTileMode;
TileProc fTileProc;
- uint16_t fColorCount;
+ int fColorCount;
uint8_t fDstToIndexClass;
uint8_t fFlags;
@@ -154,8 +148,7 @@ private:
typedef SkShader INHERITED;
};
-static inline unsigned scalarToU16(SkScalar x)
-{
+static inline unsigned scalarToU16(SkScalar x) {
SkASSERT(x >= 0 && x <= SK_Scalar1);
#ifdef SK_SCALAR_IS_FLOAT
@@ -165,9 +158,8 @@ static inline unsigned scalarToU16(SkScalar x)
#endif
}
-Gradient_Shader::Gradient_Shader(const SkColor colors[], const SkScalar pos[], int colorCount,
- SkShader::TileMode mode, SkUnitMapper* mapper)
-{
+Gradient_Shader::Gradient_Shader(const SkColor colors[], const SkScalar pos[],
+ int colorCount, SkShader::TileMode mode, SkUnitMapper* mapper) {
SkASSERT(colorCount > 1);
fCacheAlpha = 256; // init to a value that paint.getAlpha() can't return
@@ -175,33 +167,67 @@ Gradient_Shader::Gradient_Shader(const SkColor colors[], const SkScalar pos[], i
fMapper = mapper;
mapper->safeRef();
- fCache16 = fCache16Storage = NULL;
- fCache32 = fCache32Storage = NULL;
-
- fColorCount = SkToU16(colorCount);
- if (colorCount > kColorStorageCount)
- fOrigColors = (SkColor*)sk_malloc_throw((sizeof(SkColor) + sizeof(SkPMColor) + sizeof(Rec)) * colorCount);
- else
- fOrigColors = fStorage;
- memcpy(fOrigColors, colors, colorCount * sizeof(SkColor));
- // our premul colors point to the 2nd half of the array
- // these are assigned each time in setContext
- fARGB32 = fOrigColors + colorCount;
-
SkASSERT((unsigned)mode < SkShader::kTileModeCount);
SkASSERT(SkShader::kTileModeCount == SK_ARRAY_COUNT(gTileProcs));
fTileMode = mode;
fTileProc = gTileProcs[mode];
+
+ fCache16 = fCache16Storage = NULL;
+ fCache32 = fCache32Storage = NULL;
- fRecs = (Rec*)(fARGB32 + colorCount);
- if (colorCount > 2)
+ /* Note: we let the caller skip the first and/or last position.
+ i.e. pos[0] = 0.3, pos[1] = 0.7
+ In these cases, we insert dummy entries to ensure that the final data
+ will be bracketed by [0, 1].
+ i.e. our_pos[0] = 0, our_pos[1] = 0.3, our_pos[2] = 0.7, our_pos[3] = 1
+
+ Thus colorCount (the caller's value, and fColorCount (our value) may
+ differ by up to 2. In the above example:
+ colorCount = 2
+ fColorCount = 4
+ */
+ fColorCount = colorCount;
+ // check if we need to add in dummy start and/or end position/colors
+ bool dummyFirst = false;
+ bool dummyLast = false;
+ if (pos) {
+ dummyFirst = pos[0] != 0;
+ dummyLast = pos[colorCount - 1] != SK_Scalar1;
+ fColorCount += dummyFirst + dummyLast;
+ }
+
+ if (fColorCount > kColorStorageCount) {
+ size_t size = sizeof(SkColor) + sizeof(SkPMColor) + sizeof(Rec);
+ fOrigColors = reinterpret_cast<SkColor*>(
+ sk_malloc_throw(size * fColorCount));
+ }
+ else {
+ fOrigColors = fStorage;
+ }
+
+ // Now copy over the colors, adding the dummies as needed
{
- Rec* recs = fRecs;
+ SkColor* origColors = fOrigColors;
+ if (dummyFirst) {
+ *origColors++ = colors[0];
+ }
+ memcpy(origColors, colors, colorCount * sizeof(SkColor));
+ if (dummyLast) {
+ origColors += colorCount;
+ *origColors = colors[colorCount - 1];
+ }
+ }
- recs[0].fPos = 0;
- // recs[0].fScale = 0; // unused;
- if (pos)
- {
+ // our premul colors point to the 2nd half of the array
+ // these are assigned each time in setContext
+ fARGB32 = fOrigColors + fColorCount;
+ fRecs = (Rec*)(fARGB32 + fColorCount);
+ if (fColorCount > 2) {
+ Rec* recs = fRecs;
+ recs->fPos = 0;
+ // recs->fScale = 0; // unused;
+ recs += 1;
+ if (pos) {
/* We need to convert the user's array of relative positions into
fixed-point positions and scale factors. We need these results
to be strictly monotonic (no two values equal or out of order).
@@ -210,39 +236,40 @@ Gradient_Shader::Gradient_Shader(const SkColor colors[], const SkScalar pos[], i
we start at 0 and end at 1.0
*/
SkFixed prev = 0;
- for (int i = 1; i < colorCount; i++)
- {
+ int startIndex = dummyFirst ? 0 : 1;
+ int count = colorCount + dummyLast;
+ for (int i = startIndex; i < count; i++) {
// force the last value to be 1.0
SkFixed curr;
- if (i == colorCount - 1)
+ if (i == colorCount) { // we're really at the dummyLast
curr = SK_Fixed1;
- else
- {
+ } else {
curr = SkScalarToFixed(pos[i]);
- // pin curr withing range
- if (curr < 0)
- curr = 0;
- else if (curr > SK_Fixed1)
- curr = SK_Fixed1;
}
- recs[i].fPos = curr;
- if (curr > prev)
- recs[i].fScale = (1 << 24) / (curr - prev);
- else
- recs[i].fScale = 0; // ignore this segment
+ // pin curr withing range
+ if (curr < 0) {
+ curr = 0;
+ } else if (curr > SK_Fixed1) {
+ curr = SK_Fixed1;
+ }
+ recs->fPos = curr;
+ if (curr > prev) {
+ recs->fScale = (1 << 24) / (curr - prev);
+ } else {
+ recs->fScale = 0; // ignore this segment
+ }
// get ready for the next value
prev = curr;
+ recs += 1;
}
- }
- else // assume even distribution
- {
+ } else { // assume even distribution
SkFixed dp = SK_Fixed1 / (colorCount - 1);
SkFixed p = dp;
SkFixed scale = (colorCount - 1) << 8; // (1 << 24) / dp
- for (int i = 1; i < colorCount; i++)
- {
- recs[i].fPos = p;
- recs[i].fScale = scale;
+ for (int i = 1; i < colorCount; i++) {
+ recs->fPos = p;
+ recs->fScale = scale;
+ recs += 1;
p += dp;
}
}
@@ -250,8 +277,7 @@ Gradient_Shader::Gradient_Shader(const SkColor colors[], const SkScalar pos[], i
}
Gradient_Shader::Gradient_Shader(SkFlattenableReadBuffer& buffer) :
- INHERITED(buffer)
-{
+ INHERITED(buffer) {
fCacheAlpha = 256;
fMapper = static_cast<SkUnitMapper*>(buffer.readFlattenable());
@@ -259,11 +285,13 @@ Gradient_Shader::Gradient_Shader(SkFlattenableReadBuffer& buffer) :
fCache16 = fCache16Storage = NULL;
fCache32 = fCache32Storage = NULL;
- int colorCount = fColorCount = buffer.readU16();
- if (colorCount > kColorStorageCount)
- fOrigColors = (SkColor*)sk_malloc_throw((sizeof(SkColor) + sizeof(SkPMColor) + sizeof(Rec)) * colorCount);
- else
+ int colorCount = fColorCount = buffer.readU32();
+ if (colorCount > kColorStorageCount) {
+ size_t size = sizeof(SkColor) + sizeof(SkPMColor) + sizeof(Rec);
+ fOrigColors = (SkColor*)sk_malloc_throw(size * colorCount);
+ } else {
fOrigColors = fStorage;
+ }
buffer.read(fOrigColors, colorCount * sizeof(SkColor));
fARGB32 = fOrigColors + colorCount;
@@ -281,22 +309,23 @@ Gradient_Shader::Gradient_Shader(SkFlattenableReadBuffer& buffer) :
buffer.read(&fPtsToUnit, sizeof(SkMatrix));
}
-Gradient_Shader::~Gradient_Shader()
-{
- if (fCache16Storage)
+Gradient_Shader::~Gradient_Shader() {
+ if (fCache16Storage) {
sk_free(fCache16Storage);
- if (fCache32Storage)
+ }
+ if (fCache32Storage) {
sk_free(fCache32Storage);
- if (fOrigColors != fStorage)
+ }
+ if (fOrigColors != fStorage) {
sk_free(fOrigColors);
+ }
fMapper->safeUnref();
}
-void Gradient_Shader::flatten(SkFlattenableWriteBuffer& buffer)
-{
+void Gradient_Shader::flatten(SkFlattenableWriteBuffer& buffer) {
this->INHERITED::flatten(buffer);
buffer.writeFlattenable(fMapper);
- buffer.write16(fColorCount);
+ buffer.write32(fColorCount);
buffer.writeMul4(fOrigColors, fColorCount * sizeof(SkColor));
buffer.write8(fTileMode);
if (fColorCount > 2) {
@@ -311,10 +340,10 @@ void Gradient_Shader::flatten(SkFlattenableWriteBuffer& buffer)
bool Gradient_Shader::setContext(const SkBitmap& device,
const SkPaint& paint,
- const SkMatrix& matrix)
-{
- if (!this->INHERITED::setContext(device, paint, matrix))
+ const SkMatrix& matrix) {
+ if (!this->INHERITED::setContext(device, paint, matrix)) {
return false;
+ }
const SkMatrix& inverse = this->getTotalInverse();
@@ -329,7 +358,7 @@ bool Gradient_Shader::setContext(const SkBitmap& device,
unsigned paintAlpha = this->getPaintAlpha();
unsigned colorAlpha = 0xFF;
- for (unsigned i = 0; i < fColorCount; i++) {
+ for (int i = 0; i < fColorCount; i++) {
SkColor src = fOrigColors[i];
unsigned sa = SkColorGetA(src);
colorAlpha &= sa;
@@ -361,17 +390,15 @@ bool Gradient_Shader::setContext(const SkBitmap& device,
return true;
}
-static inline int blend8(int a, int b, int scale)
-{
+static inline int blend8(int a, int b, int scale) {
SkASSERT(a == SkToU8(a));
SkASSERT(b == SkToU8(b));
SkASSERT(scale >= 0 && scale <= 256);
-
return a + ((b - a) * scale >> 8);
}
-static inline uint32_t dot8_blend_packed32(uint32_t s0, uint32_t s1, int blend)
-{
+static inline uint32_t dot8_blend_packed32(uint32_t s0, uint32_t s1,
+ int blend) {
#if 0
int a = blend8(SkGetPackedA32(s0), SkGetPackedA32(s1), blend);
int r = blend8(SkGetPackedR32(s0), SkGetPackedR32(s1), blend);
@@ -397,11 +424,12 @@ static inline uint32_t dot8_blend_packed32(uint32_t s0, uint32_t s1, int blend)
#define Fixed_To_Dot8(x) (((x) + 0x80) >> 8)
-/** We take the original colors, not our premultiplied PMColors, since we can build a 16bit table
- as long as the original colors are opaque, even if the paint specifies a non-opaque alpha.
+/** We take the original colors, not our premultiplied PMColors, since we can
+ build a 16bit table as long as the original colors are opaque, even if the
+ paint specifies a non-opaque alpha.
*/
-static void build_16bit_cache(uint16_t cache[], SkColor c0, SkColor c1, int count)
-{
+static void build_16bit_cache(uint16_t cache[], SkColor c0, SkColor c1,
+ int count) {
SkASSERT(count > 1);
SkASSERT(SkColorGetA(c0) == 0xFF);
SkASSERT(SkColorGetA(c1) == 0xFF);
@@ -431,8 +459,8 @@ static void build_16bit_cache(uint16_t cache[], SkColor c0, SkColor c1, int coun
} while (--count != 0);
}
-static void build_32bit_cache(SkPMColor cache[], SkPMColor c0, SkPMColor c1, int count)
-{
+static void build_32bit_cache(SkPMColor cache[], SkPMColor c0, SkPMColor c1,
+ int count) {
SkASSERT(count > 1);
SkFixed a = SkGetPackedA32(c0);
@@ -459,22 +487,18 @@ static void build_32bit_cache(SkPMColor cache[], SkPMColor c0, SkPMColor c1, int
} while (--count != 0);
}
-static inline int SkFixedToFFFF(SkFixed x)
-{
+static inline int SkFixedToFFFF(SkFixed x) {
SkASSERT((unsigned)x <= SK_Fixed1);
return x - (x >> 16);
}
-static inline U16CPU dot6to16(unsigned x)
-{
+static inline U16CPU dot6to16(unsigned x) {
SkASSERT(x < 64);
return (x << 10) | (x << 4) | (x >> 2);
}
-const uint16_t* Gradient_Shader::getCache16()
-{
- if (fCache16 == NULL)
- {
+const uint16_t* Gradient_Shader::getCache16() {
+ if (fCache16 == NULL) {
if (fCache16Storage == NULL) // set the storage and our working ptr
#ifdef TEST_GRADIENT_DITHER
fCache16Storage = (uint16_t*)sk_malloc_throw(sizeof(uint16_t) * kCache16Count * 2);
@@ -482,14 +506,12 @@ const uint16_t* Gradient_Shader::getCache16()
fCache16Storage = (uint16_t*)sk_malloc_throw(sizeof(uint16_t) * kCache16Count);
#endif
fCache16 = fCache16Storage;
- if (fColorCount == 2)
+ if (fColorCount == 2) {
build_16bit_cache(fCache16, fOrigColors[0], fOrigColors[1], kCache16Count);
- else
- {
+ } else {
Rec* rec = fRecs;
int prevIndex = 0;
- for (unsigned i = 1; i < fColorCount; i++)
- {
+ for (int i = 1; i < fColorCount; i++) {
int nextIndex = SkFixedToFFFF(rec[i].fPos) >> (16 - kCache16Bits);
SkASSERT(nextIndex < kCache16Count);
@@ -500,8 +522,7 @@ const uint16_t* Gradient_Shader::getCache16()
SkASSERT(prevIndex == kCache16Count - 1);
}
- if (fMapper)
- {
+ if (fMapper) {
#ifdef TEST_GRADIENT_DITHER
fCache16Storage = (uint16_t*)sk_malloc_throw(sizeof(uint16_t) * kCache16Count * 2);
#else
@@ -510,8 +531,7 @@ const uint16_t* Gradient_Shader::getCache16()
uint16_t* linear = fCache16; // just computed linear data
uint16_t* mapped = fCache16Storage; // storage for mapped data
SkUnitMapper* map = fMapper;
- for (int i = 0; i < 64; i++)
- {
+ for (int i = 0; i < 64; i++) {
int index = map->mapUnit16(dot6to16(i)) >> 10;
mapped[i] = linear[index];
#ifdef TEST_GRADIENT_DITHER
@@ -525,22 +545,18 @@ const uint16_t* Gradient_Shader::getCache16()
return fCache16;
}
-const SkPMColor* Gradient_Shader::getCache32()
-{
- if (fCache32 == NULL)
- {
+const SkPMColor* Gradient_Shader::getCache32() {
+ if (fCache32 == NULL) {
if (fCache32Storage == NULL) // set the storage and our working ptr
fCache32Storage = (SkPMColor*)sk_malloc_throw(sizeof(SkPMColor) * kCache32Count);
fCache32 = fCache32Storage;
- if (fColorCount == 2)
+ if (fColorCount == 2) {
build_32bit_cache(fCache32, fARGB32[0], fARGB32[1], kCache32Count);
- else
- {
+ } else {
Rec* rec = fRecs;
int prevIndex = 0;
- for (unsigned i = 1; i < fColorCount; i++)
- {
+ for (int i = 1; i < fColorCount; i++) {
int nextIndex = SkFixedToFFFF(rec[i].fPos) >> (16 - kCache32Bits);
SkASSERT(nextIndex < kCache32Count);
@@ -551,14 +567,14 @@ const SkPMColor* Gradient_Shader::getCache32()
SkASSERT(prevIndex == kCache32Count - 1);
}
- if (fMapper)
- {
+ if (fMapper) {
fCache32Storage = (SkPMColor*)sk_malloc_throw(sizeof(SkPMColor) * kCache32Count);
SkPMColor* linear = fCache32; // just computed linear data
SkPMColor* mapped = fCache32Storage; // storage for mapped data
SkUnitMapper* map = fMapper;
- for (int i = 0; i < 256; i++)
+ for (int i = 0; i < 256; i++) {
mapped[i] = linear[map->mapUnit16((i << 8) | i) >> 8];
+ }
sk_free(fCache32);
fCache32 = fCache32Storage;
}
@@ -568,8 +584,7 @@ const SkPMColor* Gradient_Shader::getCache32()
///////////////////////////////////////////////////////////////////////////
-static void pts_to_unit_matrix(const SkPoint pts[2], SkMatrix* matrix)
-{
+static void pts_to_unit_matrix(const SkPoint pts[2], SkMatrix* matrix) {
SkVector vec = pts[1] - pts[0];
SkScalar mag = vec.length();
SkScalar inv = mag ? SkScalarInvert(mag) : 0;
@@ -1523,6 +1538,13 @@ SkShader* SkGradientShader::CreateLinear( const SkPoint pts[2],
}
EXPAND_1_COLOR(colorCount);
+ SkScalar posStorage[2];
+ if (colorCount == 2 && pos == NULL) {
+ posStorage[0] = SK_Scalar1/4;
+ posStorage[1] = 3*SK_Scalar1/4;
+ pos = posStorage;
+ }
+
return SkNEW_ARGS(Linear_Gradient, (pts, colors, pos, colorCount, mode, mapper));
}