aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar senorblanco <senorblanco@chromium.org>2016-01-11 14:09:09 -0800
committerGravatar Commit bot <commit-bot@chromium.org>2016-01-11 14:09:09 -0800
commita9fbd1676cf8bd0078c5be1f1c4abd4c76ea60ad (patch)
tree1b596c1acd49d4a1201f9ebacc8934e07b52ea9d
parentbad23dc9ed2e00f2a066db01ab88e4c4adcecfc6 (diff)
Fix SkTileImageFilter when srcRect is a superset of bitmap bounds.
If the input bitmap passed to SkTileImageFilter does not fill the srcRect, we were tiling this incorrectly (see the first sample from tileimage filter -- it draws from a srcRect of 12,12 50x50 to a dstRect of 0,0 50x50. There should be no tiling at all in this case!) In order to fix this, we need to pad the bitmap out to srcRect, and tile with that. In order to tile correctly in the GPU case, we need to request a tileable texture. NOTE: this will change the results of the tileimagefilter GM (correctness, and added src / dest rects). BUG=skia:4774 GOLD_TRYBOT_URL= https://gold.skia.org/search2?unt=true&query=source_type%3Dgm&master=false&issue=1570133003 Review URL: https://codereview.chromium.org/1570133003
-rw-r--r--gm/tileimagefilter.cpp10
-rw-r--r--include/core/SkImageFilter.h11
-rw-r--r--src/core/SkImageFilter.cpp5
-rw-r--r--src/effects/SkTileImageFilter.cpp32
4 files changed, 44 insertions, 14 deletions
diff --git a/gm/tileimagefilter.cpp b/gm/tileimagefilter.cpp
index 10086c9c17..eb0ad09f4b 100644
--- a/gm/tileimagefilter.cpp
+++ b/gm/tileimagefilter.cpp
@@ -47,6 +47,12 @@ protected:
void onDraw(SkCanvas* canvas) override {
canvas->clear(SK_ColorBLACK);
+ SkPaint red;
+ red.setColor(SK_ColorRED);
+ red.setStyle(SkPaint::kStroke_Style);
+ SkPaint blue;
+ blue.setColor(SK_ColorBLUE);
+ blue.setStyle(SkPaint::kStroke_Style);
int x = 0, y = 0;
for (size_t i = 0; i < 4; i++) {
@@ -67,6 +73,8 @@ protected:
SkPaint paint;
paint.setImageFilter(filter);
canvas->drawImage(fBitmap, 0, 0, &paint);
+ canvas->drawRect(srcRect, red);
+ canvas->drawRect(dstRect, blue);
canvas->restore();
x += image->width() + MARGIN;
if (x + image->width() > WIDTH) {
@@ -96,6 +104,8 @@ protected:
canvas->saveLayer(&dstRect, &paint);
canvas->drawImage(fBitmap, 0, 0);
canvas->restore();
+ canvas->drawRect(srcRect, red);
+ canvas->drawRect(dstRect, blue);
canvas->restore();
}
private:
diff --git a/include/core/SkImageFilter.h b/include/core/SkImageFilter.h
index 13fe6530c7..eb5d2a1b06 100644
--- a/include/core/SkImageFilter.h
+++ b/include/core/SkImageFilter.h
@@ -98,11 +98,17 @@ public:
uint32_t fFlags;
};
+ enum TileUsage {
+ kPossible_TileUsage, //!< the created device may be drawn tiled
+ kNever_TileUsage, //!< the created device will never be drawn tiled
+ };
+
class Proxy {
public:
virtual ~Proxy() {}
- virtual SkBaseDevice* createDevice(int width, int height) = 0;
+ virtual SkBaseDevice* createDevice(int width, int height,
+ TileUsage usage = kNever_TileUsage) = 0;
// Returns true if the proxy handled the filter itself. If this returns
// false then the filter's code will be called.
@@ -115,7 +121,8 @@ public:
public:
DeviceProxy(SkBaseDevice* device) : fDevice(device) {}
- SkBaseDevice* createDevice(int width, int height) override;
+ SkBaseDevice* createDevice(int width, int height,
+ TileUsage usage = kNever_TileUsage) override;
// Returns true if the proxy handled the filter itself. If this returns
// false then the filter's code will be called.
diff --git a/src/core/SkImageFilter.cpp b/src/core/SkImageFilter.cpp
index e64cf7200a..b068644d55 100644
--- a/src/core/SkImageFilter.cpp
+++ b/src/core/SkImageFilter.cpp
@@ -663,9 +663,10 @@ void SkImageFilter::PurgeCache() {
///////////////////////////////////////////////////////////////////////////////////////////////////
-SkBaseDevice* SkImageFilter::DeviceProxy::createDevice(int w, int h) {
+SkBaseDevice* SkImageFilter::DeviceProxy::createDevice(int w, int h, TileUsage usage) {
SkBaseDevice::CreateInfo cinfo(SkImageInfo::MakeN32Premul(w, h),
- SkBaseDevice::kNever_TileUsage,
+ kPossible_TileUsage == usage ? SkBaseDevice::kPossible_TileUsage
+ : SkBaseDevice::kNever_TileUsage,
kUnknown_SkPixelGeometry,
false, /* preserveLCDText */
true /*forImageFilter*/);
diff --git a/src/effects/SkTileImageFilter.cpp b/src/effects/SkTileImageFilter.cpp
index 8d15801387..ca4c15d419 100644
--- a/src/effects/SkTileImageFilter.cpp
+++ b/src/effects/SkTileImageFilter.cpp
@@ -54,15 +54,31 @@ bool SkTileImageFilter::onFilterImage(Proxy* proxy, const SkBitmap& src,
srcRect.roundOut(&srcIRect);
srcIRect.offset(-srcOffset);
SkBitmap subset;
- SkIRect bounds;
- source.getBounds(&bounds);
+ SkIRect srcBounds;
+ source.getBounds(&srcBounds);
- if (!srcIRect.intersect(bounds)) {
+ if (!SkIRect::Intersects(srcIRect, srcBounds)) {
offset->fX = offset->fY = 0;
return true;
- } else if (!source.extractSubset(&subset, srcIRect)) {
- return false;
}
+ if (srcBounds.contains(srcIRect)) {
+ if (!source.extractSubset(&subset, srcIRect)) {
+ return false;
+ }
+ } else {
+ SkAutoTUnref<SkBaseDevice> device(proxy->createDevice(srcIRect.width(),
+ srcIRect.height(),
+ kPossible_TileUsage));
+ if (!device) {
+ return false;
+ }
+ SkCanvas canvas(device);
+ canvas.drawBitmap(src, SkIntToScalar(srcOffset.x()),
+ SkIntToScalar(srcOffset.y()));
+ subset = device->accessBitmap(false);
+ }
+ SkASSERT(subset.width() == srcIRect.width());
+ SkASSERT(subset.height() == srcIRect.height());
SkAutoTUnref<SkBaseDevice> device(proxy->createDevice(w, h));
if (nullptr == device.get()) {
@@ -72,12 +88,8 @@ bool SkTileImageFilter::onFilterImage(Proxy* proxy, const SkBitmap& src,
SkPaint paint;
paint.setXfermodeMode(SkXfermode::kSrc_Mode);
- SkMatrix shaderMatrix;
- shaderMatrix.setTranslate(SkIntToScalar(srcOffset.fX),
- SkIntToScalar(srcOffset.fY));
SkAutoTUnref<SkShader> shader(SkShader::CreateBitmapShader(subset,
- SkShader::kRepeat_TileMode, SkShader::kRepeat_TileMode,
- &shaderMatrix));
+ SkShader::kRepeat_TileMode, SkShader::kRepeat_TileMode));
paint.setShader(shader);
canvas.translate(-dstRect.fLeft, -dstRect.fTop);
canvas.drawRect(dstRect, paint);