| Index: src/core/SkPictureShader.cpp
|
| diff --git a/src/core/SkPictureShader.cpp b/src/core/SkPictureShader.cpp
|
| index cf0157c2a59fd880b4f9f3fe65bfd25a0b8e25cc..1453aee0a8658fb34a2d4351da2f7fb1f3d974b0 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]);
|
|
|
|
|