Index: src/effects/gradients/SkGradientShader.cpp |
diff --git a/src/effects/gradients/SkGradientShader.cpp b/src/effects/gradients/SkGradientShader.cpp |
index 666204e0aed451ad0f236c4cb72c26a7fa7945be..2ebb9c71d9bdc8cafc169fc6fbb3e5e079c226bc 100644 |
--- a/src/effects/gradients/SkGradientShader.cpp |
+++ b/src/effects/gradients/SkGradientShader.cpp |
@@ -15,6 +15,8 @@ |
SkGradientShaderBase::SkGradientShaderBase(const Descriptor& desc) { |
SkASSERT(desc.fCount > 1); |
+ fCacheAlpha = 256; // init to a value that paint.getAlpha() can't return |
+ |
fMapper = desc.fMapper; |
SkSafeRef(fMapper); |
fGradFlags = SkToU8(desc.fFlags); |
@@ -23,6 +25,10 @@ |
SkASSERT(SkShader::kTileModeCount == SK_ARRAY_COUNT(gTileProcs)); |
fTileMode = desc.fTileMode; |
fTileProc = gTileProcs[desc.fTileMode]; |
+ |
+ fCache16 = fCache16Storage = NULL; |
+ fCache32 = NULL; |
+ fCache32PixelRef = NULL; |
/* Note: we let the caller skip the first and/or last position. |
i.e. pos[0] = 0.3, pos[1] = 0.7 |
@@ -138,7 +144,13 @@ |
} |
SkGradientShaderBase::SkGradientShaderBase(SkReadBuffer& buffer) : INHERITED(buffer) { |
+ fCacheAlpha = 256; |
+ |
fMapper = buffer.readUnitMapper(); |
+ |
+ fCache16 = fCache16Storage = NULL; |
+ fCache32 = NULL; |
+ fCache32PixelRef = NULL; |
int colorCount = fColorCount = buffer.getArrayCount(); |
if (colorCount > kColorStorageCount) { |
@@ -174,6 +186,10 @@ |
} |
SkGradientShaderBase::~SkGradientShaderBase() { |
+ if (fCache16Storage) { |
+ sk_free(fCache16Storage); |
+ } |
+ SkSafeUnref(fCache32PixelRef); |
if (fOrigColors != fStorage) { |
sk_free(fOrigColors); |
} |
@@ -181,6 +197,7 @@ |
} |
void SkGradientShaderBase::initCommon() { |
+ fFlags = 0; |
unsigned colorAlpha = 0xFF; |
for (int i = 0; i < fColorCount; i++) { |
colorAlpha &= SkColorGetA(fOrigColors[i]); |
@@ -207,50 +224,49 @@ |
return fColorsAreOpaque; |
} |
-SkGradientShaderBase::GradientShaderBaseContext::GradientShaderBaseContext( |
- const SkGradientShaderBase& shader, const SkBitmap& device, |
- const SkPaint& paint, const SkMatrix& matrix) |
- : INHERITED(shader, device, paint, matrix) |
- , fCache(shader.getCache(getPaintAlpha())) |
-{ |
+bool SkGradientShaderBase::setContext(const SkBitmap& device, |
+ const SkPaint& paint, |
+ const SkMatrix& matrix) { |
+ if (!this->INHERITED::setContext(device, paint, matrix)) { |
+ return false; |
+ } |
+ |
const SkMatrix& inverse = this->getTotalInverse(); |
- fDstToIndex.setConcat(shader.fPtsToUnit, inverse); |
- |
+ fDstToIndex.setConcat(fPtsToUnit, inverse); |
fDstToIndexProc = fDstToIndex.getMapXYProc(); |
- fDstToIndexClass = (uint8_t)SkShader::Context::ComputeMatrixClass(fDstToIndex); |
+ fDstToIndexClass = (uint8_t)SkShader::ComputeMatrixClass(fDstToIndex); |
// now convert our colors in to PMColors |
unsigned paintAlpha = this->getPaintAlpha(); |
fFlags = this->INHERITED::getFlags(); |
- if (shader.fColorsAreOpaque && paintAlpha == 0xFF) { |
+ if (fColorsAreOpaque && paintAlpha == 0xFF) { |
fFlags |= kOpaqueAlpha_Flag; |
} |
// we can do span16 as long as our individual colors are opaque, |
// regardless of the paint's alpha |
- if (shader.fColorsAreOpaque) { |
+ if (fColorsAreOpaque) { |
fFlags |= kHasSpan16_Flag; |
} |
-} |
- |
-SkGradientShaderBase::GradientShaderCache::GradientShaderCache( |
- U8CPU alpha, const SkGradientShaderBase& shader) |
- : fCacheAlpha(alpha) |
- , fShader(shader) |
- , fCache16Inited(false) |
- , fCache32Inited(false) |
-{ |
- // Only initialize the cache in getCache16/32. |
- fCache16 = NULL; |
- fCache32 = NULL; |
- fCache16Storage = NULL; |
- fCache32PixelRef = NULL; |
-} |
- |
-SkGradientShaderBase::GradientShaderCache::~GradientShaderCache() { |
- sk_free(fCache16Storage); |
- SkSafeUnref(fCache32PixelRef); |
+ |
+ this->setCacheAlpha(paintAlpha); |
+ return true; |
+} |
+ |
+void SkGradientShaderBase::setCacheAlpha(U8CPU alpha) const { |
+ // if the new alpha differs from the previous time we were called, inval our cache |
+ // this will trigger the cache to be rebuilt. |
+ // we don't care about the first time, since the cache ptrs will already be NULL |
+ if (fCacheAlpha != alpha) { |
+ fCache16 = NULL; // inval the cache |
+ fCache32 = NULL; // inval the cache |
+ fCacheAlpha = alpha; // record the new alpha |
+ // inform our subclasses |
+ if (fCache32PixelRef) { |
+ fCache32PixelRef->notifyPixelsChanged(); |
+ } |
+ } |
} |
#define Fixed_To_Dot8(x) (((x) + 0x80) >> 8) |
@@ -259,8 +275,8 @@ |
build a 16bit table as long as the original colors are opaque, even if the |
paint specifies a non-opaque alpha. |
*/ |
-void SkGradientShaderBase::GradientShaderCache::Build16bitCache( |
- uint16_t cache[], SkColor c0, SkColor c1, int count) { |
+void SkGradientShaderBase::Build16bitCache(uint16_t cache[], SkColor c0, SkColor c1, |
+ int count) { |
SkASSERT(count > 1); |
SkASSERT(SkColorGetA(c0) == 0xFF); |
SkASSERT(SkColorGetA(c1) == 0xFF); |
@@ -308,9 +324,8 @@ |
*/ |
typedef uint32_t SkUFixed; |
-void SkGradientShaderBase::GradientShaderCache::Build32bitCache( |
- SkPMColor cache[], SkColor c0, SkColor c1, |
- int count, U8CPU paintAlpha, uint32_t gradFlags) { |
+void SkGradientShaderBase::Build32bitCache(SkPMColor cache[], SkColor c0, SkColor c1, |
+ int count, U8CPU paintAlpha, uint32_t gradFlags) { |
SkASSERT(count > 1); |
// need to apply paintAlpha to our two endpoints |
@@ -453,121 +468,97 @@ |
return 0; |
} |
-const uint16_t* SkGradientShaderBase::GradientShaderCache::getCache16() { |
- SkOnce(&fCache16Inited, &fCache16Mutex, SkGradientShaderBase::GradientShaderCache::initCache16, |
- this); |
- SkASSERT(fCache16); |
+const uint16_t* SkGradientShaderBase::getCache16() const { |
+ if (fCache16 == NULL) { |
+ // double the count for dither entries |
+ const int entryCount = kCache16Count * 2; |
+ const size_t allocSize = sizeof(uint16_t) * entryCount; |
+ |
+ if (fCache16Storage == NULL) { // set the storage and our working ptr |
+ fCache16Storage = (uint16_t*)sk_malloc_throw(allocSize); |
+ } |
+ fCache16 = fCache16Storage; |
+ if (fColorCount == 2) { |
+ Build16bitCache(fCache16, fOrigColors[0], fOrigColors[1], |
+ kCache16Count); |
+ } else { |
+ Rec* rec = fRecs; |
+ int prevIndex = 0; |
+ for (int i = 1; i < fColorCount; i++) { |
+ int nextIndex = SkFixedToFFFF(rec[i].fPos) >> kCache16Shift; |
+ SkASSERT(nextIndex < kCache16Count); |
+ |
+ if (nextIndex > prevIndex) |
+ Build16bitCache(fCache16 + prevIndex, fOrigColors[i-1], fOrigColors[i], nextIndex - prevIndex + 1); |
+ prevIndex = nextIndex; |
+ } |
+ } |
+ |
+ if (fMapper) { |
+ fCache16Storage = (uint16_t*)sk_malloc_throw(allocSize); |
+ uint16_t* linear = fCache16; // just computed linear data |
+ uint16_t* mapped = fCache16Storage; // storage for mapped data |
+ SkUnitMapper* map = fMapper; |
+ for (int i = 0; i < kCache16Count; i++) { |
+ int index = map->mapUnit16(bitsTo16(i, kCache16Bits)) >> kCache16Shift; |
+ mapped[i] = linear[index]; |
+ mapped[i + kCache16Count] = linear[index + kCache16Count]; |
+ } |
+ sk_free(fCache16); |
+ fCache16 = fCache16Storage; |
+ } |
+ } |
return fCache16; |
} |
-void SkGradientShaderBase::GradientShaderCache::initCache16(GradientShaderCache* cache) { |
- // double the count for dither entries |
- const int entryCount = kCache16Count * 2; |
- const size_t allocSize = sizeof(uint16_t) * entryCount; |
- |
- SkASSERT(NULL == cache->fCache16Storage); |
- cache->fCache16Storage = (uint16_t*)sk_malloc_throw(allocSize); |
- cache->fCache16 = cache->fCache16Storage; |
- if (cache->fShader.fColorCount == 2) { |
- Build16bitCache(cache->fCache16, cache->fShader.fOrigColors[0], |
- cache->fShader.fOrigColors[1], kCache16Count); |
- } else { |
- Rec* rec = cache->fShader.fRecs; |
- int prevIndex = 0; |
- for (int i = 1; i < cache->fShader.fColorCount; i++) { |
- int nextIndex = SkFixedToFFFF(rec[i].fPos) >> kCache16Shift; |
- SkASSERT(nextIndex < kCache16Count); |
- |
- if (nextIndex > prevIndex) |
- Build16bitCache(cache->fCache16 + prevIndex, cache->fShader.fOrigColors[i-1], |
- cache->fShader.fOrigColors[i], nextIndex - prevIndex + 1); |
- prevIndex = nextIndex; |
- } |
- } |
- |
- if (cache->fShader.fMapper) { |
- cache->fCache16Storage = (uint16_t*)sk_malloc_throw(allocSize); |
- uint16_t* linear = cache->fCache16; // just computed linear data |
- uint16_t* mapped = cache->fCache16Storage; // storage for mapped data |
- SkUnitMapper* map = cache->fShader.fMapper; |
- for (int i = 0; i < kCache16Count; i++) { |
- int index = map->mapUnit16(bitsTo16(i, kCache16Bits)) >> kCache16Shift; |
- mapped[i] = linear[index]; |
- mapped[i + kCache16Count] = linear[index + kCache16Count]; |
- } |
- sk_free(cache->fCache16); |
- cache->fCache16 = cache->fCache16Storage; |
- } |
-} |
- |
-const SkPMColor* SkGradientShaderBase::GradientShaderCache::getCache32() { |
- SkOnce(&fCache32Inited, &fCache32Mutex, SkGradientShaderBase::GradientShaderCache::initCache32, |
- this); |
- SkASSERT(fCache32); |
+const SkPMColor* SkGradientShaderBase::getCache32() const { |
+ if (fCache32 == NULL) { |
+ SkImageInfo info; |
+ info.fWidth = kCache32Count; |
+ info.fHeight = 4; // for our 4 dither rows |
+ info.fAlphaType = kPremul_SkAlphaType; |
+ info.fColorType = kN32_SkColorType; |
+ |
+ if (NULL == fCache32PixelRef) { |
+ fCache32PixelRef = SkMallocPixelRef::NewAllocate(info, 0, NULL); |
+ } |
+ fCache32 = (SkPMColor*)fCache32PixelRef->getAddr(); |
+ if (fColorCount == 2) { |
+ Build32bitCache(fCache32, fOrigColors[0], fOrigColors[1], |
+ kCache32Count, fCacheAlpha, fGradFlags); |
+ } else { |
+ Rec* rec = fRecs; |
+ int prevIndex = 0; |
+ for (int i = 1; i < fColorCount; i++) { |
+ int nextIndex = SkFixedToFFFF(rec[i].fPos) >> kCache32Shift; |
+ SkASSERT(nextIndex < kCache32Count); |
+ |
+ if (nextIndex > prevIndex) |
+ Build32bitCache(fCache32 + prevIndex, fOrigColors[i-1], |
+ fOrigColors[i], nextIndex - prevIndex + 1, |
+ fCacheAlpha, fGradFlags); |
+ prevIndex = nextIndex; |
+ } |
+ } |
+ |
+ if (fMapper) { |
+ SkMallocPixelRef* newPR = SkMallocPixelRef::NewAllocate(info, 0, NULL); |
+ SkPMColor* linear = fCache32; // just computed linear data |
+ SkPMColor* mapped = (SkPMColor*)newPR->getAddr(); // storage for mapped data |
+ SkUnitMapper* map = fMapper; |
+ for (int i = 0; i < kCache32Count; i++) { |
+ int index = map->mapUnit16((i << 8) | i) >> 8; |
+ mapped[i + kCache32Count*0] = linear[index + kCache32Count*0]; |
+ mapped[i + kCache32Count*1] = linear[index + kCache32Count*1]; |
+ mapped[i + kCache32Count*2] = linear[index + kCache32Count*2]; |
+ mapped[i + kCache32Count*3] = linear[index + kCache32Count*3]; |
+ } |
+ fCache32PixelRef->unref(); |
+ fCache32PixelRef = newPR; |
+ fCache32 = (SkPMColor*)newPR->getAddr(); |
+ } |
+ } |
return fCache32; |
-} |
- |
-void SkGradientShaderBase::GradientShaderCache::initCache32(GradientShaderCache* cache) { |
- SkImageInfo info; |
- info.fWidth = kCache32Count; |
- info.fHeight = 4; // for our 4 dither rows |
- info.fAlphaType = kPremul_SkAlphaType; |
- info.fColorType = kN32_SkColorType; |
- |
- SkASSERT(NULL == cache->fCache32PixelRef); |
- cache->fCache32PixelRef = SkMallocPixelRef::NewAllocate(info, 0, NULL); |
- cache->fCache32 = (SkPMColor*)cache->fCache32PixelRef->getAddr(); |
- if (cache->fShader.fColorCount == 2) { |
- Build32bitCache(cache->fCache32, cache->fShader.fOrigColors[0], |
- cache->fShader.fOrigColors[1], kCache32Count, cache->fCacheAlpha, |
- cache->fShader.fGradFlags); |
- } else { |
- Rec* rec = cache->fShader.fRecs; |
- int prevIndex = 0; |
- for (int i = 1; i < cache->fShader.fColorCount; i++) { |
- int nextIndex = SkFixedToFFFF(rec[i].fPos) >> kCache32Shift; |
- SkASSERT(nextIndex < kCache32Count); |
- |
- if (nextIndex > prevIndex) |
- Build32bitCache(cache->fCache32 + prevIndex, cache->fShader.fOrigColors[i-1], |
- cache->fShader.fOrigColors[i], nextIndex - prevIndex + 1, |
- cache->fCacheAlpha, cache->fShader.fGradFlags); |
- prevIndex = nextIndex; |
- } |
- } |
- |
- if (cache->fShader.fMapper) { |
- SkMallocPixelRef* newPR = SkMallocPixelRef::NewAllocate(info, 0, NULL); |
- SkPMColor* linear = cache->fCache32; // just computed linear data |
- SkPMColor* mapped = (SkPMColor*)newPR->getAddr(); // storage for mapped data |
- SkUnitMapper* map = cache->fShader.fMapper; |
- for (int i = 0; i < kCache32Count; i++) { |
- int index = map->mapUnit16((i << 8) | i) >> 8; |
- mapped[i + kCache32Count*0] = linear[index + kCache32Count*0]; |
- mapped[i + kCache32Count*1] = linear[index + kCache32Count*1]; |
- mapped[i + kCache32Count*2] = linear[index + kCache32Count*2]; |
- mapped[i + kCache32Count*3] = linear[index + kCache32Count*3]; |
- } |
- cache->fCache32PixelRef->unref(); |
- cache->fCache32PixelRef = newPR; |
- cache->fCache32 = (SkPMColor*)newPR->getAddr(); |
- } |
-} |
- |
-/* |
- * The gradient holds a cache for the most recent value of alpha. Successive |
- * callers with the same alpha value will share the same cache. |
- */ |
-SkGradientShaderBase::GradientShaderCache* SkGradientShaderBase::getCache(U8CPU alpha) const { |
- SkAutoMutexAcquire ama(fCacheMutex); |
- if (!fCache || fCache->getAlpha() != alpha) { |
- fCache.reset(SkNEW_ARGS(GradientShaderCache, (alpha, *this))); |
- } |
- // Increment the ref counter inside the mutex to ensure the returned pointer is still valid. |
- // Otherwise, the pointer may have been overwritten on a different thread before the object's |
- // ref count was incremented. |
- fCache.get()->ref(); |
- return fCache; |
} |
/* |
@@ -581,14 +572,14 @@ |
void SkGradientShaderBase::getGradientTableBitmap(SkBitmap* bitmap) const { |
// our caller assumes no external alpha, so we ensure that our cache is |
// built with 0xFF |
- GradientShaderCache* cache = this->getCache(0xFF); |
+ this->setCacheAlpha(0xFF); |
// don't have a way to put the mapper into our cache-key yet |
if (fMapper) { |
- // force our cache32pixelref to be built |
- (void)cache->getCache32(); |
+ // force our cahce32pixelref to be built |
+ (void)this->getCache32(); |
bitmap->setConfig(SkImageInfo::MakeN32Premul(kCache32Count, 1)); |
- bitmap->setPixelRef(cache->getCache32PixelRef()); |
+ bitmap->setPixelRef(fCache32PixelRef); |
return; |
} |
@@ -627,9 +618,9 @@ |
if (!gCache->find(storage.get(), size, bitmap)) { |
// force our cahce32pixelref to be built |
- (void)cache->getCache32(); |
+ (void)this->getCache32(); |
bitmap->setConfig(SkImageInfo::MakeN32Premul(kCache32Count, 1)); |
- bitmap->setPixelRef(cache->getCache32PixelRef()); |
+ bitmap->setPixelRef(fCache32PixelRef); |
gCache->add(storage.get(), size, *bitmap); |
} |