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
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++) {
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) {
canvas->saveLayer(&dstRect, &paint);
canvas->drawImage(fBitmap, 0, 0);
canvas->restore();
+ canvas->drawRect(srcRect, red);
+ canvas->drawRect(dstRect, blue);
canvas->restore();
}
private:
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.
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.
///////////////////////////////////////////////////////////////////////////////////////////////////
-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*/);
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()) {
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);