From 0a5c233e3b911232c0d6f9a88ded99ecf88b8a97 Mon Sep 17 00:00:00 2001 From: "senorblanco@chromium.org" Date: Tue, 29 Apr 2014 15:20:39 +0000 Subject: 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 --- tests/ImageFilterTest.cpp | 111 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 111 insertions(+) (limited to 'tests') diff --git a/tests/ImageFilterTest.cpp b/tests/ImageFilterTest.cpp index f968a4e9c5..dac948ef40 100644 --- a/tests/ImageFilterTest.cpp +++ b/tests/ImageFilterTest.cpp @@ -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 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 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 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); -- cgit v1.2.3