diff options
-rw-r--r-- | include/core/SkShader.h | 17 | ||||
-rw-r--r-- | src/core/SkBitmapProcShader.cpp | 2 | ||||
-rw-r--r-- | src/image/SkImageShader.cpp | 30 | ||||
-rw-r--r-- | src/image/SkImageShader.h | 2 | ||||
-rw-r--r-- | src/image/SkImage_Base.h | 2 | ||||
-rw-r--r-- | src/image/SkImage_Raster.cpp | 2 | ||||
-rw-r--r-- | src/pdf/SkPDFShader.cpp | 5 | ||||
-rw-r--r-- | tests/ShaderTest.cpp | 60 |
8 files changed, 115 insertions, 5 deletions
diff --git a/include/core/SkShader.h b/include/core/SkShader.h index 69037d95f6..c442fae4fd 100644 --- a/include/core/SkShader.h +++ b/include/core/SkShader.h @@ -18,6 +18,7 @@ class SkColorFilter; class SkColorSpace; +class SkImage; class SkPath; class SkPicture; class SkXfermode; @@ -242,6 +243,18 @@ public: } /** + * Iff this shader is backed by a single SkImage, return its ptr (the caller must ref this + * if they want to keep it longer than the lifetime of the shader). If not, return nullptr. + */ + SkImage* isAImage(SkMatrix* localMatrix, TileMode xy[2]) const { + return this->onIsAImage(localMatrix, xy); + } + + bool isAImage() const { + return this->isAImage(nullptr, nullptr) != nullptr; + } + + /** * If the shader subclass can be represented as a gradient, asAGradient * returns the matching GradientType enum (or kNone_GradientType if it * cannot). Also, if info is not null, asAGradient populates info with @@ -512,6 +525,10 @@ protected: return false; } + virtual SkImage* onIsAImage(SkMatrix*, TileMode[2]) const { + return nullptr; + } + private: // This is essentially const, but not officially so it can be modified in // constructors. diff --git a/src/core/SkBitmapProcShader.cpp b/src/core/SkBitmapProcShader.cpp index 006fedf626..3ad9d5a626 100644 --- a/src/core/SkBitmapProcShader.cpp +++ b/src/core/SkBitmapProcShader.cpp @@ -272,7 +272,7 @@ bool SkBitmapProcShader::onIsABitmap(SkBitmap* texture, SkMatrix* texM, TileMode *texture = fRawBitmap; } if (texM) { - texM->reset(); + *texM = this->getLocalMatrix(); } if (xy) { xy[0] = (TileMode)fTileModeX; diff --git a/src/image/SkImageShader.cpp b/src/image/SkImageShader.cpp index e7a8433fe2..12caa7a3d2 100644 --- a/src/image/SkImageShader.cpp +++ b/src/image/SkImageShader.cpp @@ -51,6 +51,36 @@ SkShader::Context* SkImageShader::onCreateContext(const ContextRec& rec, void* s SkBitmapProvider(fImage), rec, storage); } +SkImage* SkImageShader::onIsAImage(SkMatrix* texM, TileMode xy[]) const { + if (texM) { + *texM = this->getLocalMatrix(); + } + if (xy) { + xy[0] = (TileMode)fTileModeX; + xy[1] = (TileMode)fTileModeY; + } + return const_cast<SkImage*>(fImage.get()); +} + +bool SkImageShader::onIsABitmap(SkBitmap* texture, SkMatrix* texM, TileMode xy[]) const { + const SkBitmap* bm = as_IB(fImage)->onPeekBitmap(); + if (!bm) { + return false; + } + + if (texture) { + *texture = *bm; + } + if (texM) { + *texM = this->getLocalMatrix(); + } + if (xy) { + xy[0] = (TileMode)fTileModeX; + xy[1] = (TileMode)fTileModeY; + } + return true; +} + sk_sp<SkShader> SkImageShader::Make(const SkImage* image, TileMode tx, TileMode ty, const SkMatrix* localMatrix) { if (!image) { diff --git a/src/image/SkImageShader.h b/src/image/SkImageShader.h index 10200e97d5..160de7ac9c 100644 --- a/src/image/SkImageShader.h +++ b/src/image/SkImageShader.h @@ -29,6 +29,8 @@ protected: void flatten(SkWriteBuffer&) const override; size_t onContextSize(const ContextRec&) const override; Context* onCreateContext(const ContextRec&, void* storage) const override; + bool onIsABitmap(SkBitmap*, SkMatrix*, TileMode*) const override; + SkImage* onIsAImage(SkMatrix*, TileMode*) const override; SkAutoTUnref<const SkImage> fImage; const TileMode fTileModeX; diff --git a/src/image/SkImage_Base.h b/src/image/SkImage_Base.h index f1b902bd84..1cfb7daad6 100644 --- a/src/image/SkImage_Base.h +++ b/src/image/SkImage_Base.h @@ -33,6 +33,8 @@ public: virtual bool onPeekPixels(SkPixmap*) const { return false; } + virtual const SkBitmap* onPeekBitmap() const { return nullptr; } + // Default impl calls onDraw virtual bool onReadPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRowBytes, int srcX, int srcY, CachingHint) const; diff --git a/src/image/SkImage_Raster.cpp b/src/image/SkImage_Raster.cpp index df82c3f302..3282e7b7ed 100644 --- a/src/image/SkImage_Raster.cpp +++ b/src/image/SkImage_Raster.cpp @@ -80,6 +80,8 @@ public: bool onReadPixels(const SkImageInfo&, void*, size_t, int srcX, int srcY, CachingHint) const override; bool onPeekPixels(SkPixmap*) const override; + const SkBitmap* onPeekBitmap() const override { return &fBitmap; } + SkData* onRefEncoded(GrContext*) const override; bool getROPixels(SkBitmap*, CachingHint) const override; GrTexture* asTextureRef(GrContext*, const GrTextureParams&, diff --git a/src/pdf/SkPDFShader.cpp b/src/pdf/SkPDFShader.cpp index 31af569fe9..885b7e6049 100644 --- a/src/pdf/SkPDFShader.cpp +++ b/src/pdf/SkPDFShader.cpp @@ -1289,10 +1289,7 @@ SkPDFShader::State::State(SkShader* shader, const SkMatrix& canvasTransform, fType = shader->asAGradient(&fInfo); if (fType == SkShader::kNone_GradientType) { - SkMatrix matrix; - if (shader->isABitmap(&fImage, &matrix, fImageTileModes)) { - SkASSERT(matrix.isIdentity()); - } else { + if (!shader->isABitmap(&fImage, nullptr, fImageTileModes)) { // Generic fallback for unsupported shaders: // * allocate a bbox-sized bitmap // * shade the whole area diff --git a/tests/ShaderTest.cpp b/tests/ShaderTest.cpp new file mode 100644 index 0000000000..d3f74ffb3d --- /dev/null +++ b/tests/ShaderTest.cpp @@ -0,0 +1,60 @@ +/* + * Copyright 2016 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "Test.h" +#include "SkBitmap.h" +#include "SkImage.h" +#include "SkShader.h" +#include "SkSurface.h" +#include "SkData.h" + +static void check_isabitmap(skiatest::Reporter* reporter, SkShader* shader, + int expectedW, int expectedH, + SkShader::TileMode expectedX, SkShader::TileMode expectedY, + const SkMatrix& expectedM, + bool expectedImage) { + SkBitmap bm; + SkShader::TileMode tileModes[2]; + SkMatrix localM; + REPORTER_ASSERT(reporter, shader->isABitmap(&bm, &localM, tileModes)); + REPORTER_ASSERT(reporter, bm.width() == expectedW); + REPORTER_ASSERT(reporter, bm.height() == expectedH); + REPORTER_ASSERT(reporter, localM == expectedM); + REPORTER_ASSERT(reporter, tileModes[0] == expectedX); + REPORTER_ASSERT(reporter, tileModes[1] == expectedY); + + // wack these so we don't get a false positive + localM.setScale(9999, -9999); + tileModes[0] = tileModes[1] = (SkShader::TileMode)99; + + SkImage* image = shader->isAImage(&localM, tileModes); + REPORTER_ASSERT(reporter, (image != nullptr) == expectedImage); + if (image) { + REPORTER_ASSERT(reporter, image->width() == expectedW); + REPORTER_ASSERT(reporter, image->height() == expectedH); + REPORTER_ASSERT(reporter, localM == expectedM); + REPORTER_ASSERT(reporter, tileModes[0] == expectedX); + REPORTER_ASSERT(reporter, tileModes[1] == expectedY); + } +} + +DEF_TEST(Shader_isABitmap, reporter) { + const int W = 100; + const int H = 100; + SkBitmap bm; + bm.allocN32Pixels(W, H); + auto img = SkImage::MakeFromBitmap(bm); + const SkMatrix localM = SkMatrix::MakeScale(2, 3); + const SkShader::TileMode tmx = SkShader::kRepeat_TileMode; + const SkShader::TileMode tmy = SkShader::kMirror_TileMode; + + auto shader0 = SkShader::MakeBitmapShader(bm, tmx, tmy, &localM); + auto shader1 = SkImage::MakeFromBitmap(bm)->makeShader(tmx, tmy, &localM); + + check_isabitmap(reporter, shader0.get(), W, H, tmx, tmy, localM, false); + check_isabitmap(reporter, shader1.get(), W, H, tmx, tmy, localM, true); +} |