Commit 0a5c233e authored by senorblanco@chromium.org's avatar senorblanco@chromium.org
Browse files

Implement bounds traversals for tile and matrix convolution filters.

Add a new GM that exercises tiled drawing all pixel-moving filters
(and some non-pixel-moving ones) and compares it against non-tiled
drawing of the same filters. Fixing this test revealed that tile and
matrix convolution filters had no onFilterBounds() traversals
(test-driven development FTW). Tile requires (conservatively) the
bounds to include the whole source rect, since it may end up in the
result. Matrix convolution requires the bounds to be offset by the
kernel size and target.

R=reed@google.com
BUG=skia:

Review URL: https://codereview.chromium.org/258243005

git-svn-id: http://skia.googlecode.com/svn/trunk@14432 2bbb7eff-a529-9590-31e7-b0007b416f81
parent daaafa6e
......@@ -60,3 +60,7 @@ peekpixels
# humper: https://codereview.chromium.org/248613004/
# Changed the test in a few ways, will need rebaselining.
simpleblurroundrect
# senorblanco: http://YOUR_CODE_REVIEW_HERE/
# Added a new test case; reduced the text bitmap size
tileimagefilter
......@@ -6,6 +6,8 @@
*/
#include "gm.h"
#include "SkColorMatrixFilter.h"
#include "SkColorFilterImageFilter.h"
#include "SkTileImageFilter.h"
#include "SkBitmapSource.h"
......@@ -27,15 +29,15 @@ protected:
}
void make_bitmap() {
fBitmap.allocN32Pixels(80, 80);
fBitmap.allocN32Pixels(50, 50);
SkCanvas canvas(fBitmap);
canvas.clear(0xFF000000);
SkPaint paint;
paint.setAntiAlias(true);
paint.setColor(0xD000D000);
paint.setTextSize(SkIntToScalar(96));
paint.setTextSize(SkIntToScalar(50));
const char* str = "e";
canvas.drawText(str, strlen(str), SkIntToScalar(15), SkIntToScalar(65), paint);
canvas.drawText(str, strlen(str), SkIntToScalar(10), SkIntToScalar(45), paint);
}
void make_checkerboard() {
......@@ -70,7 +72,6 @@ protected:
fInitialized = true;
}
canvas->clear(0x00000000);
SkPaint paint;
int x = 0, y = 0;
for (size_t i = 0; i < 4; i++) {
......@@ -88,6 +89,7 @@ protected:
SkTileImageFilter::Create(srcRect, dstRect, tileInput));
canvas->save();
canvas->translate(SkIntToScalar(x), SkIntToScalar(y));
SkPaint paint;
paint.setImageFilter(filter);
canvas->drawBitmap(fBitmap, 0, 0, &paint);
canvas->restore();
......@@ -97,6 +99,29 @@ protected:
y += bitmap->height() + MARGIN;
}
}
SkScalar matrix[20] = { SK_Scalar1, 0, 0, 0, 0,
0, SK_Scalar1, 0, 0, 0,
0, 0, SK_Scalar1, 0, 0,
0, 0, 0, SK_Scalar1, 0 };
SkRect srcRect = SkRect::MakeWH(SkIntToScalar(fBitmap.width()),
SkIntToScalar(fBitmap.height()));
SkRect dstRect = SkRect::MakeWH(SkIntToScalar(fBitmap.width() * 2),
SkIntToScalar(fBitmap.height() * 2));
SkAutoTUnref<SkImageFilter> tile(SkTileImageFilter::Create(srcRect, dstRect, NULL));
SkAutoTUnref<SkColorFilter> cf(SkColorMatrixFilter::Create(matrix));
SkAutoTUnref<SkImageFilter> cfif(SkColorFilterImageFilter::Create(cf, tile.get()));
SkPaint paint;
paint.setImageFilter(cfif);
canvas->save();
canvas->translate(SkIntToScalar(x), SkIntToScalar(y));
canvas->clipRect(dstRect);
canvas->saveLayer(&dstRect, &paint);
canvas->drawBitmap(fBitmap, 0, 0);
canvas->restore();
canvas->restore();
}
private:
typedef GM INHERITED;
......
......@@ -73,6 +73,8 @@ protected:
virtual bool onFilterImage(Proxy*, const SkBitmap& src, const Context&,
SkBitmap* result, SkIPoint* loc) const SK_OVERRIDE;
virtual bool onFilterBounds(const SkIRect&, const SkMatrix&, SkIRect*) const SK_OVERRIDE;
#if SK_SUPPORT_GPU
virtual bool asNewEffect(GrEffectRef** effect,
......
......@@ -26,6 +26,8 @@ public:
virtual bool onFilterImage(Proxy* proxy, const SkBitmap& src, const Context& ctx,
SkBitmap* dst, SkIPoint* offset) const SK_OVERRIDE;
virtual bool onFilterBounds(const SkIRect& src, const SkMatrix&,
SkIRect* dst) const SK_OVERRIDE;
SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkTileImageFilter)
......
......@@ -306,6 +306,19 @@ bool SkMatrixConvolutionImageFilter::onFilterImage(Proxy* proxy,
return true;
}
bool SkMatrixConvolutionImageFilter::onFilterBounds(const SkIRect& src, const SkMatrix& ctm,
SkIRect* dst) const {
SkIRect bounds = src;
bounds.fRight += fKernelSize.width() - 1;
bounds.fBottom += fKernelSize.height() - 1;
bounds.offset(-fKernelOffset);
if (getInput(0) && !getInput(0)->filterBounds(bounds, ctm, &bounds)) {
return false;
}
*dst = bounds;
return true;
}
#if SK_SUPPORT_GPU
///////////////////////////////////////////////////////////////////////////////
......
......@@ -75,6 +75,17 @@ bool SkTileImageFilter::onFilterImage(Proxy* proxy, const SkBitmap& src,
return true;
}
bool SkTileImageFilter::onFilterBounds(const SkIRect& src, const SkMatrix& ctm,
SkIRect* dst) const {
SkRect srcRect;
ctm.mapRect(&srcRect, fSrcRect);
SkIRect srcIRect;
srcRect.roundOut(&srcIRect);
srcIRect.join(src);
*dst = srcIRect;
return true;
}
SkTileImageFilter::SkTileImageFilter(SkReadBuffer& buffer)
: INHERITED(1, buffer) {
buffer.readRect(&fSrcRect);
......
......@@ -17,6 +17,7 @@
#include "SkDisplacementMapEffect.h"
#include "SkDropShadowImageFilter.h"
#include "SkFlattenableBuffers.h"
#include "SkGradientShader.h"
#include "SkLightingImageFilter.h"
#include "SkMatrixConvolutionImageFilter.h"
#include "SkMatrixImageFilter.h"
......@@ -261,6 +262,116 @@ static void test_crop_rects(SkBaseDevice* device, skiatest::Reporter* reporter)
}
}
static SkBitmap make_gradient_circle(int width, int height) {
SkBitmap bitmap;
SkScalar x = SkIntToScalar(width / 2);
SkScalar y = SkIntToScalar(height / 2);
SkScalar radius = SkMinScalar(x, y) * 0.8f;
bitmap.allocN32Pixels(width, height);
SkCanvas canvas(bitmap);
canvas.clear(0x00000000);
SkColor colors[2];
colors[0] = SK_ColorWHITE;
colors[1] = SK_ColorBLACK;
SkAutoTUnref<SkShader> shader(
SkGradientShader::CreateRadial(SkPoint::Make(x, y), radius, colors, NULL, 2,
SkShader::kClamp_TileMode)
);
SkPaint paint;
paint.setShader(shader);
canvas.drawCircle(x, y, radius, paint);
return bitmap;
}
DEF_TEST(ImageFilterDrawTiled, reporter) {
// Check that all filters when drawn tiled (with subsequent clip rects) exactly
// match the same filters drawn with a single full-canvas bitmap draw.
// Tests pass by not asserting.
SkAutoTUnref<SkColorFilter> cf(SkColorFilter::CreateModeFilter(SK_ColorRED, SkXfermode::kSrcIn_Mode));
SkPoint3 location(0, 0, SK_Scalar1);
SkPoint3 target(SK_Scalar1, SK_Scalar1, SK_Scalar1);
SkScalar kernel[9] = {
SkIntToScalar( 1), SkIntToScalar( 1), SkIntToScalar( 1),
SkIntToScalar( 1), SkIntToScalar(-7), SkIntToScalar( 1),
SkIntToScalar( 1), SkIntToScalar( 1), SkIntToScalar( 1),
};
SkISize kernelSize = SkISize::Make(3, 3);
SkScalar gain = SK_Scalar1, bias = 0;
SkAutoTUnref<SkImageFilter> gradient_source(SkBitmapSource::Create(make_gradient_circle(64, 64)));
struct {
const char* fName;
SkImageFilter* fFilter;
} filters[] = {
{ "color filter", SkColorFilterImageFilter::Create(cf.get()) },
{ "displacement map", SkDisplacementMapEffect::Create(
SkDisplacementMapEffect::kR_ChannelSelectorType,
SkDisplacementMapEffect::kB_ChannelSelectorType,
40.0f, gradient_source.get()) },
{ "blur", SkBlurImageFilter::Create(SK_Scalar1, SK_Scalar1) },
{ "drop shadow", SkDropShadowImageFilter::Create(
SK_Scalar1, SK_Scalar1, SK_Scalar1, SK_Scalar1, SK_ColorGREEN) },
{ "diffuse lighting", SkLightingImageFilter::CreatePointLitDiffuse(
location, SK_ColorGREEN, 0, 0) },
{ "specular lighting",
SkLightingImageFilter::CreatePointLitSpecular(location, SK_ColorGREEN, 0, 0, 0) },
{ "matrix convolution",
SkMatrixConvolutionImageFilter::Create(
kernelSize, kernel, gain, bias, SkIPoint::Make(1, 1),
SkMatrixConvolutionImageFilter::kRepeat_TileMode, false) },
{ "merge", SkMergeImageFilter::Create(NULL, NULL, SkXfermode::kSrcOver_Mode) },
{ "offset", SkOffsetImageFilter::Create(SK_Scalar1, SK_Scalar1) },
{ "dilate", SkDilateImageFilter::Create(3, 2) },
{ "erode", SkErodeImageFilter::Create(2, 3) },
{ "tile", SkTileImageFilter::Create(SkRect::MakeXYWH(0, 0, 50, 50),
SkRect::MakeXYWH(0, 0, 100, 100), NULL) },
};
SkBitmap untiledResult, tiledResult;
int width = 64, height = 64;
untiledResult.allocN32Pixels(width, height);
tiledResult.allocN32Pixels(width, height);
SkCanvas tiledCanvas(tiledResult);
SkCanvas untiledCanvas(untiledResult);
tiledCanvas.clear(0);
untiledCanvas.clear(0);
int tileSize = 16;
for (size_t i = 0; i < SK_ARRAY_COUNT(filters); ++i) {
SkPaint paint;
paint.setImageFilter(filters[i].fFilter);
paint.setTextSize(SkIntToScalar(height));
paint.setColor(SK_ColorWHITE);
SkString str;
const char* text = "ABC";
SkScalar ypos = SkIntToScalar(height);
untiledCanvas.drawText(text, strlen(text), 0, ypos, paint);
for (int y = 0; y < height; y += tileSize) {
for (int x = 0; x < width; x += tileSize) {
tiledCanvas.save();
tiledCanvas.clipRect(SkRect::Make(SkIRect::MakeXYWH(x, y, tileSize, tileSize)));
tiledCanvas.drawText(text, strlen(text), 0, ypos, paint);
tiledCanvas.restore();
}
}
untiledCanvas.flush();
tiledCanvas.flush();
for (int y = 0; y < height; y++) {
int diffs = memcmp(untiledResult.getAddr32(0, y), tiledResult.getAddr32(0, y), untiledResult.rowBytes());
REPORTER_ASSERT_MESSAGE(reporter, !diffs, filters[i].fName);
if (diffs) {
break;
}
}
}
for (size_t i = 0; i < SK_ARRAY_COUNT(filters); ++i) {
SkSafeUnref(filters[i].fFilter);
}
}
DEF_TEST(ImageFilterCropRect, reporter) {
SkBitmap temp;
temp.allocN32Pixels(100, 100);
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment