aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--include/core/SkShader.h17
-rw-r--r--src/core/SkBitmapProcShader.cpp2
-rw-r--r--src/image/SkImageShader.cpp30
-rw-r--r--src/image/SkImageShader.h2
-rw-r--r--src/image/SkImage_Base.h2
-rw-r--r--src/image/SkImage_Raster.cpp2
-rw-r--r--src/pdf/SkPDFShader.cpp5
-rw-r--r--tests/ShaderTest.cpp60
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);
+}