Add image as a draw type that can be filtered

Add image as a draw type that can be filtered.

This is needed when SkImage is added as an object to be drawn so that
the draw is forwarded to SkBaseDevice. This would be used in making
filters use SkImages.

BUG=skia:3388

Review URL: https://codereview.chromium.org/960783003
This commit is contained in:
kkinnunen 2015-03-05 00:39:45 -08:00 committed by Commit bot
parent c877a71b35
commit fa77eb1e51
4 changed files with 203 additions and 4 deletions

View File

@ -35,10 +35,11 @@ public:
kOval_Type,
kPath_Type,
kText_Type,
kImage_Type,
};
enum {
kTypeCount = kText_Type + 1
kTypeCount = kImage_Type + 1
};
/**

View File

@ -1848,15 +1848,64 @@ void SkCanvas::onDrawPath(const SkPath& path, const SkPaint& paint) {
LOOPER_END
}
void SkCanvas::onDrawImage(const SkImage* image, SkScalar dx, SkScalar dy, const SkPaint* paint) {
void SkCanvas::onDrawImage(const SkImage* image, SkScalar dx, SkScalar dy,
const SkPaint* paint) {
TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImage()");
image->draw(this, dx, dy, paint);
SkRect bounds = SkRect::MakeXYWH(dx, dy, image->width(), image->height());
if (NULL == paint || paint->canComputeFastBounds()) {
if (NULL != paint) {
paint->computeFastBounds(bounds, &bounds);
}
if (this->quickReject(bounds)) {
return;
}
}
SkLazyPaint lazy;
if (NULL == paint) {
paint = lazy.init();
}
LOOPER_BEGIN(*paint, SkDrawFilter::kImage_Type, &bounds)
while (iter.next()) {
SkPaint p = looper.paint();
p.setLooper(NULL);
image->draw(this, dx, dy, &p);
}
LOOPER_END
}
void SkCanvas::onDrawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
const SkPaint* paint) {
TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImageRect()");
image->drawRect(this, src, dst, paint);
SkRect storage;
const SkRect* bounds = &dst;
if (NULL == paint || paint->canComputeFastBounds()) {
if (NULL != paint) {
bounds = &paint->computeFastBounds(dst, &storage);
}
if (this->quickReject(*bounds)) {
return;
}
}
SkLazyPaint lazy;
if (NULL == paint) {
paint = lazy.init();
}
LOOPER_BEGIN(*paint, SkDrawFilter::kImage_Type, bounds)
while (iter.next()) {
SkPaint p = looper.paint();
p.setLooper(NULL);
image->drawRect(this, src, dst, &p);
}
LOOPER_END
}
void SkCanvas::onDrawBitmap(const SkBitmap& bitmap, SkScalar x, SkScalar y, const SkPaint* paint) {

View File

@ -6,6 +6,8 @@
*/
#include "SkBitmapDevice.h"
#include "SkColor.h"
#include "SkDrawFilter.h"
#include "SkImagePriv.h"
#include "Test.h"
@ -47,3 +49,145 @@ DEF_TEST(SkImageFromBitmap_extractSubset, reporter) {
canvas.readPixels(info, &pixel, 4, gWidth - 5, gWidth - 5);
REPORTER_ASSERT(reporter, pixel == SK_ColorTRANSPARENT);
}
namespace {
class TestDrawFilterImage : public SkDrawFilter {
public:
TestDrawFilterImage()
: fFilteredImage(0)
, fFilteredOthers(0)
, fPreventImages(true)
, fPreventOthers(true) {
}
bool filter(SkPaint*, Type type) SK_OVERRIDE {
if (type == SkDrawFilter::kImage_Type) {
if (fPreventImages) {
fFilteredImage++;
return false;
}
return true;
}
if (fPreventOthers) {
fFilteredOthers++;
return false;
}
return true;
}
int fFilteredImage;
int fFilteredOthers;
bool fPreventImages;
bool fPreventOthers;
};
}
DEF_TEST(SkCanvas_test_draw_filter_image, reporter) {
SkBitmap bitmap;
bitmap.allocN32Pixels(1, 1);
bitmap.eraseColor(SK_ColorTRANSPARENT);
TestDrawFilterImage drawFilter;
SkCanvas canvas(bitmap);
SkBitmap imageBitmap;
imageBitmap.allocN32Pixels(1, 1);
imageBitmap.eraseColor(SK_ColorGREEN);
SkAutoTUnref<SkImage> image(SkNewImageFromBitmap(imageBitmap, true, NULL));
canvas.drawImage(image, 0, 0);
uint32_t pixel;
SkImageInfo info = SkImageInfo::MakeN32Premul(1, 1);
canvas.readPixels(info, &pixel, 4, 0, 0);
REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
canvas.setDrawFilter(&drawFilter);
imageBitmap.eraseColor(SK_ColorRED);
image.reset(SkNewImageFromBitmap(imageBitmap, true, NULL));
canvas.drawImage(image, 0, 0);
canvas.readPixels(info, &pixel, 4, 0, 0);
REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
REPORTER_ASSERT(reporter, drawFilter.fFilteredImage == 1);
REPORTER_ASSERT(reporter, drawFilter.fFilteredOthers == 0);
// Document a strange case: filtering everything but the images does not work as
// expected. Images go through, but no pixels appear. (This due to SkCanvas::drawImage() using
// SkCanvas::drawBitmap() instead of non-existing SkBaseDevice::drawImage()).
drawFilter.fFilteredImage = 0;
drawFilter.fPreventImages = false;
canvas.drawImage(image, 0, 0);
canvas.readPixels(info, &pixel, 4, 0, 0);
REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
REPORTER_ASSERT(reporter, drawFilter.fFilteredImage == 0);
REPORTER_ASSERT(reporter, drawFilter.fFilteredOthers == 1);
}
namespace {
/*
* Subclass of looper that just draws once with one pixel offset.
*/
class OnceTestLooper : public SkDrawLooper {
public:
OnceTestLooper() { }
SkDrawLooper::Context* createContext(SkCanvas*, void* storage) const SK_OVERRIDE {
return SkNEW_PLACEMENT(storage, OnceTestLooperContext());
}
size_t contextSize() const SK_OVERRIDE { return sizeof(OnceTestLooperContext); }
#ifndef SK_IGNORE_TO_STRING
void toString(SkString* str) const SK_OVERRIDE {
str->append("OnceTestLooper:");
}
#endif
SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(OnceTestLooper);
private:
class OnceTestLooperContext : public SkDrawLooper::Context {
public:
OnceTestLooperContext() : fCount(0) {}
virtual ~OnceTestLooperContext() {}
bool next(SkCanvas* canvas, SkPaint*) SK_OVERRIDE {
SkASSERT(fCount <= 1);
canvas->translate(0, 1);
return fCount++ < 1;
}
private:
unsigned fCount;
};
};
SkFlattenable* OnceTestLooper::CreateProc(SkReadBuffer&) { return SkNEW(OnceTestLooper); }
}
DEF_TEST(SkCanvas_test_draw_looper_image, reporter) {
// Test that drawImage loops with the looper the correct way. At the time of writing, this was
// tricky because drawImage was implemented with drawBitmap. The drawBitmap uses applies the
// looper.
SkBitmap bitmap;
bitmap.allocN32Pixels(10, 10);
bitmap.eraseColor(SK_ColorRED);
OnceTestLooper drawLooper;
SkCanvas canvas(bitmap);
SkBitmap imageBitmap;
imageBitmap.allocN32Pixels(1, 1);
imageBitmap.eraseColor(SK_ColorGREEN);
SkAutoTUnref<SkImage> image(SkNewImageFromBitmap(imageBitmap, true, NULL));
SkPaint p;
p.setLooper(&drawLooper);
canvas.drawImage(image, 0, 0, &p);
uint32_t pixel;
SkImageInfo info = SkImageInfo::MakeN32Premul(1, 1);
canvas.readPixels(info, &pixel, 4, 0, 1);
REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
canvas.readPixels(info, &pixel, 4, 0, 0);
REPORTER_ASSERT(reporter, pixel == SK_ColorRED);
canvas.readPixels(info, &pixel, 4, 0, 2);
REPORTER_ASSERT(reporter, pixel == SK_ColorRED);
}

View File

@ -75,14 +75,19 @@ static char const * const gFilterTypes[] = {
"line",
"bitmap",
"rect",
"rrect",
"oval",
"path",
"text",
"image",
"all",
};
static const size_t kFilterTypesCount = sizeof(gFilterTypes) / sizeof(gFilterTypes[0]);
SK_COMPILE_ASSERT(kFilterTypesCount - 1u == SkDrawFilter::kTypeCount,
filter_types_list_is_not_exact);
static char const * const gFilterFlags[] = {
"antiAlias",
"filterBitmap",