diff options
Diffstat (limited to 'src/core')
-rw-r--r-- | src/core/SkPictureShader.cpp | 87 | ||||
-rw-r--r-- | src/core/SkPictureShader.h | 7 |
2 files changed, 57 insertions, 37 deletions
diff --git a/src/core/SkPictureShader.cpp b/src/core/SkPictureShader.cpp index cf0157c2a5..1453aee0a8 100644 --- a/src/core/SkPictureShader.cpp +++ b/src/core/SkPictureShader.cpp @@ -10,6 +10,7 @@ #include "SkBitmap.h" #include "SkBitmapProcShader.h" #include "SkCanvas.h" +#include "SkImageGenerator.h" #include "SkMatrixUtils.h" #include "SkPicture.h" #include "SkReadBuffer.h" @@ -22,6 +23,50 @@ namespace { static unsigned gBitmapSkaderKeyNamespaceLabel; +class PictureImageGenerator : public SkImageGenerator { +public: + PictureImageGenerator(const SkPicture* picture, + const SkRect& pictureTile, + const SkISize& tileSize) + : fPicture(SkRef(picture)) + , fPictureTile(pictureTile) + , fRasterTileInfo(SkImageInfo::MakeN32Premul(tileSize)) {} + +protected: + virtual bool onGetInfo(SkImageInfo *info) SK_OVERRIDE { + *info = fRasterTileInfo; + return true; + } + + virtual Result onGetPixels(const SkImageInfo& info, void *pixels, size_t rowBytes, + SkPMColor ctable[], int *ctableCount) SK_OVERRIDE { + if (info != fRasterTileInfo || SkToBool(ctable) || SkToBool(ctableCount)) { + return kInvalidConversion; + } + + SkSize tileScale = SkSize::Make(SkIntToScalar(info.width()) / fPictureTile.width(), + SkIntToScalar(info.height()) / fPictureTile.height()); + SkBitmap tileBitmap; + if (!tileBitmap.installPixels(info, pixels, rowBytes)) { + return kInvalidParameters; + } + tileBitmap.eraseColor(SK_ColorTRANSPARENT); + + // Always disable LCD text, since we can't assume our image will be opaque. + SkCanvas tileCanvas(tileBitmap, SkSurfaceProps(0, kUnknown_SkPixelGeometry)); + tileCanvas.scale(tileScale.width(), tileScale.height()); + tileCanvas.translate(-fPictureTile.x(), -fPictureTile.y()); + tileCanvas.drawPicture(fPicture); + + return kSuccess; + } + +private: + SkAutoTUnref<const SkPicture> fPicture; + const SkRect fPictureTile; + const SkImageInfo fRasterTileInfo; +}; + struct BitmapShaderKey : public SkResourceCache::Key { public: BitmapShaderKey(uint32_t pictureID, @@ -81,24 +126,12 @@ struct BitmapShaderRec : public SkResourceCache::Rec { result->reset(SkRef(rec.fShader.get())); - SkBitmap tile; - rec.fShader.get()->asABitmap(&tile, NULL, NULL); - // FIXME: this doesn't protect the pixels from being discarded as soon as we unlock. - // Should be handled via a pixel ref generator instead - // (https://code.google.com/p/skia/issues/detail?id=3220). - SkAutoLockPixels alp(tile, true); - return tile.getPixels() != NULL; + // The bitmap shader is backed by an image generator, thus it can always re-generate its + // pixels if discarded. + return true; } }; -static bool cache_try_alloc_pixels(SkBitmap* bitmap) { - SkBitmap::Allocator* allocator = SkResourceCache::GetAllocator(); - - return NULL != allocator - ? allocator->allocPixelRef(bitmap, NULL) - : bitmap->tryAllocPixels(); -} - } // namespace SkPictureShader::SkPictureShader(const SkPicture* picture, TileMode tmx, TileMode tmy, @@ -110,10 +143,6 @@ SkPictureShader::SkPictureShader(const SkPicture* picture, TileMode tmx, TileMod , fTmy(tmy) { } -SkPictureShader::~SkPictureShader() { - fPicture->unref(); -} - SkPictureShader* SkPictureShader::Create(const SkPicture* picture, TileMode tmx, TileMode tmy, const SkMatrix* localMatrix, const SkRect* tile) { if (!picture || picture->cullRect().isEmpty() || (tile && tile->isEmpty())) { @@ -188,18 +217,10 @@ SkShader* SkPictureShader::refBitmapShader(const SkMatrix& matrix, const SkMatri if (!SkResourceCache::Find(key, BitmapShaderRec::Visitor, &tileShader)) { SkBitmap bm; - bm.setInfo(SkImageInfo::MakeN32Premul(tileSize)); - if (!cache_try_alloc_pixels(&bm)) { + if (!SkInstallDiscardablePixelRef(SkNEW_ARGS(PictureImageGenerator, + (fPicture, fTile, tileSize)), &bm)) { return NULL; } - bm.eraseColor(SK_ColorTRANSPARENT); - - // Always disable LCD text, since we can't assume our image will be opaque. - SkCanvas canvas(bm, SkSurfaceProps(0, kUnknown_SkPixelGeometry)); - - canvas.scale(tileScale.width(), tileScale.height()); - canvas.translate(-fTile.x(), -fTile.y()); - canvas.drawPicture(fPicture); SkMatrix shaderMatrix = this->getLocalMatrix(); shaderMatrix.preScale(1 / tileScale.width(), 1 / tileScale.height()); @@ -280,10 +301,10 @@ void SkPictureShader::toString(SkString* str) const { }; str->appendf("PictureShader: [%f:%f:%f:%f] ", - fPicture ? fPicture->cullRect().fLeft : 0, - fPicture ? fPicture->cullRect().fTop : 0, - fPicture ? fPicture->cullRect().fRight : 0, - fPicture ? fPicture->cullRect().fBottom : 0); + fPicture->cullRect().fLeft, + fPicture->cullRect().fTop, + fPicture->cullRect().fRight, + fPicture->cullRect().fBottom); str->appendf("(%s, %s)", gTileModeName[fTmx], gTileModeName[fTmy]); diff --git a/src/core/SkPictureShader.h b/src/core/SkPictureShader.h index 8df9f539b8..3afe58f978 100644 --- a/src/core/SkPictureShader.h +++ b/src/core/SkPictureShader.h @@ -23,7 +23,6 @@ class SkPictureShader : public SkShader { public: static SkPictureShader* Create(const SkPicture*, TileMode, TileMode, const SkMatrix*, const SkRect*); - virtual ~SkPictureShader(); size_t contextSize() const SK_OVERRIDE; @@ -43,9 +42,9 @@ private: SkShader* refBitmapShader(const SkMatrix&, const SkMatrix* localMatrix) const; - const SkPicture* fPicture; - SkRect fTile; - TileMode fTmx, fTmy; + SkAutoTUnref<const SkPicture> fPicture; + SkRect fTile; + TileMode fTmx, fTmy; class PictureShaderContext : public SkShader::Context { public: |