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]); |