| Index: src/core/SkPictureShader.cpp
|
| diff --git a/src/core/SkPictureShader.cpp b/src/core/SkPictureShader.cpp
|
| index bf312851ab3bb33b81d4a0b116d1549f96eea352..dc5c90b62e8ec7eb14fc31413f2f3d78ec1afabe 100644
|
| --- a/src/core/SkPictureShader.cpp
|
| +++ b/src/core/SkPictureShader.cpp
|
| @@ -49,7 +49,7 @@ void SkPictureShader::flatten(SkWriteBuffer& buffer) const {
|
| fPicture->flatten(buffer);
|
| }
|
|
|
| -bool SkPictureShader::buildBitmapShader(const SkMatrix& matrix) const {
|
| +SkShader* SkPictureShader::refBitmapShader(const SkMatrix& matrix) const {
|
| SkASSERT(fPicture && fPicture->width() > 0 && fPicture->height() > 0);
|
|
|
| SkMatrix m;
|
| @@ -70,17 +70,20 @@ bool SkPictureShader::buildBitmapShader(const SkMatrix& matrix) const {
|
|
|
| SkISize tileSize = scaledSize.toRound();
|
| if (tileSize.isEmpty()) {
|
| - return false;
|
| + return NULL;
|
| }
|
|
|
| // The actual scale, compensating for rounding.
|
| SkSize tileScale = SkSize::Make(SkIntToScalar(tileSize.width()) / fPicture->width(),
|
| SkIntToScalar(tileSize.height()) / fPicture->height());
|
|
|
| - if (!fCachedShader || tileScale != fCachedTileScale) {
|
| + SkAutoMutexAcquire ama(fCachedBitmapShaderMutex);
|
| +
|
| + if (!fCachedBitmapShader || tileScale != fCachedTileScale ||
|
| + this->getLocalMatrix() != fCachedLocalMatrix) {
|
| SkBitmap bm;
|
| if (!bm.allocN32Pixels(tileSize.width(), tileSize.height())) {
|
| - return false;
|
| + return NULL;
|
| }
|
| bm.eraseColor(SK_ColorTRANSPARENT);
|
|
|
| @@ -88,66 +91,91 @@ bool SkPictureShader::buildBitmapShader(const SkMatrix& matrix) const {
|
| canvas.scale(tileScale.width(), tileScale.height());
|
| canvas.drawPicture(*fPicture);
|
|
|
| - fCachedShader.reset(CreateBitmapShader(bm, fTmx, fTmy));
|
| + fCachedBitmapShader.reset(CreateBitmapShader(bm, fTmx, fTmy));
|
| fCachedTileScale = tileScale;
|
| - }
|
| + fCachedLocalMatrix = this->getLocalMatrix();
|
|
|
| - SkMatrix shaderMatrix = this->getLocalMatrix();
|
| - shaderMatrix.preScale(1 / tileScale.width(), 1 / tileScale.height());
|
| - fCachedShader->setLocalMatrix(shaderMatrix);
|
| + SkMatrix shaderMatrix = this->getLocalMatrix();
|
| + shaderMatrix.preScale(1 / tileScale.width(), 1 / tileScale.height());
|
| + fCachedBitmapShader->setLocalMatrix(shaderMatrix);
|
| + }
|
|
|
| - return true;
|
| + // 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.
|
| + fCachedBitmapShader.get()->ref();
|
| + return fCachedBitmapShader;
|
| }
|
|
|
| -bool SkPictureShader::setContext(const SkBitmap& device,
|
| - const SkPaint& paint,
|
| - const SkMatrix& matrix) {
|
| - if (!this->buildBitmapShader(matrix)) {
|
| - return false;
|
| +SkShader* SkPictureShader::validInternal(const SkBitmap& device, const SkPaint& paint,
|
| + const SkMatrix& matrix, SkMatrix* totalInverse) const {
|
| + if (!this->INHERITED::validContext(device, paint, matrix, totalInverse)) {
|
| + return NULL;
|
| }
|
|
|
| - if (!this->INHERITED::setContext(device, paint, matrix)) {
|
| - return false;
|
| + SkAutoTUnref<SkShader> bitmapShader(this->refBitmapShader(matrix));
|
| + if (!bitmapShader || !bitmapShader->validContext(device, paint, matrix)) {
|
| + return NULL;
|
| }
|
|
|
| - SkASSERT(fCachedShader);
|
| - if (!fCachedShader->setContext(device, paint, matrix)) {
|
| - this->INHERITED::endContext();
|
| - return false;
|
| + return bitmapShader.detach();
|
| +}
|
| +
|
| +bool SkPictureShader::validContext(const SkBitmap& device, const SkPaint& paint,
|
| + const SkMatrix& matrix, SkMatrix* totalInverse) const {
|
| + SkAutoTUnref<SkShader> shader(this->validInternal(device, paint, matrix, totalInverse));
|
| + return shader != NULL;
|
| +}
|
| +
|
| +SkShader::Context* SkPictureShader::createContext(const SkBitmap& device, const SkPaint& paint,
|
| + const SkMatrix& matrix, void* storage) const {
|
| + SkAutoTUnref<SkShader> bitmapShader(this->validInternal(device, paint, matrix, NULL));
|
| + if (!bitmapShader) {
|
| + return NULL;
|
| }
|
|
|
| - return true;
|
| + return SkNEW_PLACEMENT_ARGS(storage, PictureShaderContext,
|
| + (*this, device, paint, matrix, bitmapShader.detach()));
|
| +}
|
| +
|
| +size_t SkPictureShader::contextSize() const {
|
| + return sizeof(PictureShaderContext);
|
| }
|
|
|
| -void SkPictureShader::endContext() {
|
| - SkASSERT(fCachedShader);
|
| - fCachedShader->endContext();
|
| +SkPictureShader::PictureShaderContext::PictureShaderContext(
|
| + const SkPictureShader& shader, const SkBitmap& device,
|
| + const SkPaint& paint, const SkMatrix& matrix, SkShader* bitmapShader)
|
| + : INHERITED(shader, device, paint, matrix)
|
| + , fBitmapShader(bitmapShader)
|
| +{
|
| + SkASSERT(fBitmapShader);
|
| + fBitmapShaderContextStorage = sk_malloc_throw(fBitmapShader->contextSize());
|
| + fBitmapShaderContext = fBitmapShader->createContext(
|
| + device, paint, matrix, fBitmapShaderContextStorage);
|
| + SkASSERT(fBitmapShaderContext);
|
| +}
|
|
|
| - this->INHERITED::endContext();
|
| +SkPictureShader::PictureShaderContext::~PictureShaderContext() {
|
| + fBitmapShaderContext->~Context();
|
| + sk_free(fBitmapShaderContextStorage);
|
| }
|
|
|
| -uint32_t SkPictureShader::getFlags() {
|
| - if (NULL != fCachedShader) {
|
| - return fCachedShader->getFlags();
|
| - }
|
| - return 0;
|
| +uint32_t SkPictureShader::PictureShaderContext::getFlags() const {
|
| + return fBitmapShaderContext->getFlags();
|
| }
|
|
|
| -SkShader::ShadeProc SkPictureShader::asAShadeProc(void** ctx) {
|
| - if (fCachedShader) {
|
| - return fCachedShader->asAShadeProc(ctx);
|
| - }
|
| - return NULL;
|
| +SkShader::Context::ShadeProc SkPictureShader::PictureShaderContext::asAShadeProc(void** ctx) {
|
| + return fBitmapShaderContext->asAShadeProc(ctx);
|
| }
|
|
|
| -void SkPictureShader::shadeSpan(int x, int y, SkPMColor dstC[], int count) {
|
| - SkASSERT(fCachedShader);
|
| - fCachedShader->shadeSpan(x, y, dstC, count);
|
| +void SkPictureShader::PictureShaderContext::shadeSpan(int x, int y, SkPMColor dstC[], int count) {
|
| + SkASSERT(fBitmapShaderContext);
|
| + fBitmapShaderContext->shadeSpan(x, y, dstC, count);
|
| }
|
|
|
| -void SkPictureShader::shadeSpan16(int x, int y, uint16_t dstC[], int count) {
|
| - SkASSERT(fCachedShader);
|
| - fCachedShader->shadeSpan16(x, y, dstC, count);
|
| +void SkPictureShader::PictureShaderContext::shadeSpan16(int x, int y, uint16_t dstC[], int count) {
|
| + SkASSERT(fBitmapShaderContext);
|
| + fBitmapShaderContext->shadeSpan16(x, y, dstC, count);
|
| }
|
|
|
| #ifndef SK_IGNORE_TO_STRING
|
| @@ -168,10 +196,10 @@ void SkPictureShader::toString(SkString* str) const {
|
|
|
| #if SK_SUPPORT_GPU
|
| GrEffectRef* SkPictureShader::asNewEffect(GrContext* context, const SkPaint& paint) const {
|
| - if (!this->buildBitmapShader(context->getMatrix())) {
|
| + SkAutoTUnref<SkShader> bitmapShader(this->refBitmapShader(context->getMatrix()));
|
| + if (!bitmapShader) {
|
| return NULL;
|
| }
|
| - SkASSERT(fCachedShader);
|
| - return fCachedShader->asNewEffect(context, paint);
|
| + return bitmapShader->asNewEffect(context, paint);
|
| }
|
| #endif
|
|
|