blob: 430481fcc6eda17fcfecff5281a4836fd4df9e2f [file] [log] [blame]
senorblanco@chromium.org194d7752013-07-24 22:19:24 +00001/*
2 * Copyright 2013 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
commit-bot@chromium.org4b681bc2013-09-13 12:40:02 +00008#include "SkBitmap.h"
9#include "SkBitmapDevice.h"
10#include "SkBitmapSource.h"
senorblanco@chromium.org6776b822014-01-03 21:48:22 +000011#include "SkBlurImageFilter.h"
tfarina@chromium.org8f6884a2014-01-24 20:56:26 +000012#include "SkCanvas.h"
13#include "SkColorFilterImageFilter.h"
14#include "SkColorMatrixFilter.h"
ajuma5788faa2015-02-13 09:05:47 -080015#include "SkComposeImageFilter.h"
tfarina@chromium.org8f6884a2014-01-24 20:56:26 +000016#include "SkDeviceImageFilterProxy.h"
senorblanco@chromium.org6776b822014-01-03 21:48:22 +000017#include "SkDisplacementMapEffect.h"
18#include "SkDropShadowImageFilter.h"
senorblanco@chromium.org97f5fc62014-05-30 20:50:56 +000019#include "SkFlattenableSerialization.h"
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +000020#include "SkGradientShader.h"
commit-bot@chromium.org4b681bc2013-09-13 12:40:02 +000021#include "SkLightingImageFilter.h"
tfarina@chromium.org8f6884a2014-01-24 20:56:26 +000022#include "SkMatrixConvolutionImageFilter.h"
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +000023#include "SkMatrixImageFilter.h"
senorblanco@chromium.org6776b822014-01-03 21:48:22 +000024#include "SkMergeImageFilter.h"
25#include "SkMorphologyImageFilter.h"
senorblanco@chromium.org6776b822014-01-03 21:48:22 +000026#include "SkOffsetImageFilter.h"
senorblanco8f3937d2014-10-29 12:36:32 -070027#include "SkPerlinNoiseShader.h"
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +000028#include "SkPicture.h"
senorblanco@chromium.org910702b2014-05-30 20:36:15 +000029#include "SkPictureImageFilter.h"
robertphillips@google.com770963f2014-04-18 18:04:41 +000030#include "SkPictureRecorder.h"
halcanary97d2c0a2014-08-19 06:27:53 -070031#include "SkReadBuffer.h"
tfarina@chromium.org8f6884a2014-01-24 20:56:26 +000032#include "SkRect.h"
senorblanco8f3937d2014-10-29 12:36:32 -070033#include "SkRectShaderImageFilter.h"
senorblanco@chromium.org6776b822014-01-03 21:48:22 +000034#include "SkTileImageFilter.h"
35#include "SkXfermodeImageFilter.h"
tfarina@chromium.org8f6884a2014-01-24 20:56:26 +000036#include "Test.h"
senorblanco@chromium.org194d7752013-07-24 22:19:24 +000037
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +000038#if SK_SUPPORT_GPU
39#include "GrContextFactory.h"
40#include "SkGpuDevice.h"
41#endif
42
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +000043static const int kBitmapSize = 4;
commit-bot@chromium.org4b681bc2013-09-13 12:40:02 +000044
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +000045namespace {
46
47class MatrixTestImageFilter : public SkImageFilter {
48public:
49 MatrixTestImageFilter(skiatest::Reporter* reporter, const SkMatrix& expectedMatrix)
senorblanco9ea3d572014-07-08 09:16:22 -070050 : SkImageFilter(0, NULL), fReporter(reporter), fExpectedMatrix(expectedMatrix) {
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +000051 }
52
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +000053 virtual bool onFilterImage(Proxy*, const SkBitmap& src, const Context& ctx,
senorblanco@chromium.org09373352014-02-05 23:04:28 +000054 SkBitmap* result, SkIPoint* offset) const SK_OVERRIDE {
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +000055 REPORTER_ASSERT(fReporter, ctx.ctm() == fExpectedMatrix);
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +000056 return true;
57 }
58
robertphillipsf3f5bad2014-12-19 13:49:15 -080059 SK_TO_STRING_OVERRIDE()
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +000060 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(MatrixTestImageFilter)
61
62protected:
mtklein72c9faa2015-01-09 10:06:39 -080063 void flatten(SkWriteBuffer& buffer) const SK_OVERRIDE {
reed9fa60da2014-08-21 07:59:51 -070064 this->INHERITED::flatten(buffer);
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +000065 buffer.writeFunctionPtr(fReporter);
66 buffer.writeMatrix(fExpectedMatrix);
67 }
68
69private:
70 skiatest::Reporter* fReporter;
71 SkMatrix fExpectedMatrix;
mtklein3f3b3d02014-12-01 11:47:08 -080072
reed9fa60da2014-08-21 07:59:51 -070073 typedef SkImageFilter INHERITED;
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +000074};
75
76}
77
reed9fa60da2014-08-21 07:59:51 -070078SkFlattenable* MatrixTestImageFilter::CreateProc(SkReadBuffer& buffer) {
79 SK_IMAGEFILTER_UNFLATTEN_COMMON(common, 1);
80 skiatest::Reporter* reporter = (skiatest::Reporter*)buffer.readFunctionPtr();
81 SkMatrix matrix;
82 buffer.readMatrix(&matrix);
83 return SkNEW_ARGS(MatrixTestImageFilter, (reporter, matrix));
84}
85
robertphillipsf3f5bad2014-12-19 13:49:15 -080086#ifndef SK_IGNORE_TO_STRING
87void MatrixTestImageFilter::toString(SkString* str) const {
88 str->appendf("MatrixTestImageFilter: (");
89 str->append(")");
90}
91#endif
92
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +000093static void make_small_bitmap(SkBitmap& bitmap) {
mike@reedtribe.orgdeee4962014-02-13 14:41:43 +000094 bitmap.allocN32Pixels(kBitmapSize, kBitmapSize);
95 SkCanvas canvas(bitmap);
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +000096 canvas.clear(0x00000000);
97 SkPaint darkPaint;
98 darkPaint.setColor(0xFF804020);
99 SkPaint lightPaint;
100 lightPaint.setColor(0xFF244484);
101 const int i = kBitmapSize / 4;
102 for (int y = 0; y < kBitmapSize; y += i) {
103 for (int x = 0; x < kBitmapSize; x += i) {
104 canvas.save();
105 canvas.translate(SkIntToScalar(x), SkIntToScalar(y));
106 canvas.drawRect(SkRect::MakeXYWH(0, 0,
107 SkIntToScalar(i),
108 SkIntToScalar(i)), darkPaint);
109 canvas.drawRect(SkRect::MakeXYWH(SkIntToScalar(i),
110 0,
111 SkIntToScalar(i),
112 SkIntToScalar(i)), lightPaint);
113 canvas.drawRect(SkRect::MakeXYWH(0,
114 SkIntToScalar(i),
115 SkIntToScalar(i),
116 SkIntToScalar(i)), lightPaint);
117 canvas.drawRect(SkRect::MakeXYWH(SkIntToScalar(i),
118 SkIntToScalar(i),
119 SkIntToScalar(i),
120 SkIntToScalar(i)), darkPaint);
121 canvas.restore();
commit-bot@chromium.org4b681bc2013-09-13 12:40:02 +0000122 }
123 }
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000124}
senorblanco@chromium.org194d7752013-07-24 22:19:24 +0000125
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000126static SkImageFilter* make_scale(float amount, SkImageFilter* input = NULL) {
127 SkScalar s = amount;
128 SkScalar matrix[20] = { s, 0, 0, 0, 0,
129 0, s, 0, 0, 0,
130 0, 0, s, 0, 0,
131 0, 0, 0, s, 0 };
commit-bot@chromium.org727a3522014-02-21 18:46:30 +0000132 SkAutoTUnref<SkColorFilter> filter(SkColorMatrixFilter::Create(matrix));
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000133 return SkColorFilterImageFilter::Create(filter, input);
134}
135
reed5c518a82015-03-05 14:47:29 -0800136static SkImageFilter* make_grayscale(SkImageFilter* input = NULL, const SkImageFilter::CropRect* cropRect = NULL) {
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000137 SkScalar matrix[20];
138 memset(matrix, 0, 20 * sizeof(SkScalar));
139 matrix[0] = matrix[5] = matrix[10] = 0.2126f;
140 matrix[1] = matrix[6] = matrix[11] = 0.7152f;
141 matrix[2] = matrix[7] = matrix[12] = 0.0722f;
142 matrix[18] = 1.0f;
commit-bot@chromium.org727a3522014-02-21 18:46:30 +0000143 SkAutoTUnref<SkColorFilter> filter(SkColorMatrixFilter::Create(matrix));
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000144 return SkColorFilterImageFilter::Create(filter, input, cropRect);
145}
146
147DEF_TEST(ImageFilter, reporter) {
148 {
reed5c518a82015-03-05 14:47:29 -0800149 // Check that two non-clipping color matrices concatenate into a single filter.
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000150 SkAutoTUnref<SkImageFilter> halfBrightness(make_scale(0.5f));
151 SkAutoTUnref<SkImageFilter> quarterBrightness(make_scale(0.5f, halfBrightness));
152 REPORTER_ASSERT(reporter, NULL == quarterBrightness->getInput(0));
senorblanco@chromium.org194d7752013-07-24 22:19:24 +0000153 }
154
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000155 {
reed5c518a82015-03-05 14:47:29 -0800156 // Check that a clipping color matrix followed by a grayscale does not concatenate into a single filter.
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000157 SkAutoTUnref<SkImageFilter> doubleBrightness(make_scale(2.0f));
158 SkAutoTUnref<SkImageFilter> halfBrightness(make_scale(0.5f, doubleBrightness));
reed5c518a82015-03-05 14:47:29 -0800159 REPORTER_ASSERT(reporter, halfBrightness->getInput(0));
senorblanco@chromium.org194d7752013-07-24 22:19:24 +0000160 }
161
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000162 {
163 // Check that a color filter image filter without a crop rect can be
164 // expressed as a color filter.
reed5c518a82015-03-05 14:47:29 -0800165 SkAutoTUnref<SkImageFilter> gray(make_grayscale());
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000166 REPORTER_ASSERT(reporter, true == gray->asColorFilter(NULL));
senorblanco@chromium.org194d7752013-07-24 22:19:24 +0000167 }
reed5c518a82015-03-05 14:47:29 -0800168
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000169 {
170 // Check that a color filter image filter with a crop rect cannot
171 // be expressed as a color filter.
172 SkImageFilter::CropRect cropRect(SkRect::MakeXYWH(0, 0, 100, 100));
173 SkAutoTUnref<SkImageFilter> grayWithCrop(make_grayscale(NULL, &cropRect));
174 REPORTER_ASSERT(reporter, false == grayWithCrop->asColorFilter(NULL));
175 }
176
177 {
senorblanco3df05012014-07-03 11:13:09 -0700178 // Check that two non-commutative matrices are concatenated in
179 // the correct order.
180 SkScalar blueToRedMatrix[20] = { 0 };
181 blueToRedMatrix[2] = blueToRedMatrix[18] = SK_Scalar1;
182 SkScalar redToGreenMatrix[20] = { 0 };
183 redToGreenMatrix[5] = redToGreenMatrix[18] = SK_Scalar1;
184 SkAutoTUnref<SkColorFilter> blueToRed(SkColorMatrixFilter::Create(blueToRedMatrix));
185 SkAutoTUnref<SkImageFilter> filter1(SkColorFilterImageFilter::Create(blueToRed.get()));
186 SkAutoTUnref<SkColorFilter> redToGreen(SkColorMatrixFilter::Create(redToGreenMatrix));
187 SkAutoTUnref<SkImageFilter> filter2(SkColorFilterImageFilter::Create(redToGreen.get(), filter1.get()));
188
189 SkBitmap result;
190 result.allocN32Pixels(kBitmapSize, kBitmapSize);
191
192 SkPaint paint;
193 paint.setColor(SK_ColorBLUE);
194 paint.setImageFilter(filter2.get());
195 SkCanvas canvas(result);
196 canvas.clear(0x0);
197 SkRect rect = SkRect::Make(SkIRect::MakeWH(kBitmapSize, kBitmapSize));
198 canvas.drawRect(rect, paint);
199 uint32_t pixel = *result.getAddr32(0, 0);
200 // The result here should be green, since we have effectively shifted blue to green.
201 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
202 }
203
204 {
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000205 // Tests pass by not asserting
206 SkBitmap bitmap, result;
207 make_small_bitmap(bitmap);
mike@reedtribe.orgdeee4962014-02-13 14:41:43 +0000208 result.allocN32Pixels(kBitmapSize, kBitmapSize);
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000209
senorblanco@chromium.org194d7752013-07-24 22:19:24 +0000210 {
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000211 // This tests for :
212 // 1 ) location at (0,0,1)
213 SkPoint3 location(0, 0, SK_Scalar1);
214 // 2 ) location and target at same value
215 SkPoint3 target(location.fX, location.fY, location.fZ);
216 // 3 ) large negative specular exponent value
217 SkScalar specularExponent = -1000;
218
commit-bot@chromium.orgcac5fd52014-03-10 10:51:58 +0000219 SkAutoTUnref<SkImageFilter> bmSrc(SkBitmapSource::Create(bitmap));
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000220 SkPaint paint;
221 paint.setImageFilter(SkLightingImageFilter::CreateSpotLitSpecular(
222 location, target, specularExponent, 180,
223 0xFFFFFFFF, SK_Scalar1, SK_Scalar1, SK_Scalar1,
224 bmSrc))->unref();
225 SkCanvas canvas(result);
226 SkRect r = SkRect::MakeWH(SkIntToScalar(kBitmapSize),
227 SkIntToScalar(kBitmapSize));
228 canvas.drawRect(r, paint);
senorblanco@chromium.org194d7752013-07-24 22:19:24 +0000229 }
senorblanco@chromium.org194d7752013-07-24 22:19:24 +0000230 }
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +0000231}
senorblanco@chromium.org6776b822014-01-03 21:48:22 +0000232
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +0000233static void test_crop_rects(SkBaseDevice* device, skiatest::Reporter* reporter) {
234 // Check that all filters offset to their absolute crop rect,
235 // unaffected by the input crop rect.
236 // Tests pass by not asserting.
237 SkBitmap bitmap;
mike@reedtribe.orgdeee4962014-02-13 14:41:43 +0000238 bitmap.allocN32Pixels(100, 100);
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +0000239 bitmap.eraseARGB(0, 0, 0, 0);
fmalita2d97bc12014-11-20 10:44:58 -0800240 SkDeviceImageFilterProxy proxy(device, SkSurfaceProps(SkSurfaceProps::kLegacyFontHost_InitType));
senorblanco@chromium.org6776b822014-01-03 21:48:22 +0000241
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +0000242 SkImageFilter::CropRect inputCropRect(SkRect::MakeXYWH(8, 13, 80, 80));
243 SkImageFilter::CropRect cropRect(SkRect::MakeXYWH(20, 30, 60, 60));
244 SkAutoTUnref<SkImageFilter> input(make_grayscale(NULL, &inputCropRect));
senorblanco@chromium.org6776b822014-01-03 21:48:22 +0000245
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +0000246 SkAutoTUnref<SkColorFilter> cf(SkColorFilter::CreateModeFilter(SK_ColorRED, SkXfermode::kSrcIn_Mode));
247 SkPoint3 location(0, 0, SK_Scalar1);
248 SkPoint3 target(SK_Scalar1, SK_Scalar1, SK_Scalar1);
249 SkScalar kernel[9] = {
250 SkIntToScalar( 1), SkIntToScalar( 1), SkIntToScalar( 1),
251 SkIntToScalar( 1), SkIntToScalar(-7), SkIntToScalar( 1),
252 SkIntToScalar( 1), SkIntToScalar( 1), SkIntToScalar( 1),
253 };
254 SkISize kernelSize = SkISize::Make(3, 3);
255 SkScalar gain = SK_Scalar1, bias = 0;
senorblanco@chromium.org6776b822014-01-03 21:48:22 +0000256
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +0000257 SkImageFilter* filters[] = {
258 SkColorFilterImageFilter::Create(cf.get(), input.get(), &cropRect),
commit-bot@chromium.orgcac5fd52014-03-10 10:51:58 +0000259 SkDisplacementMapEffect::Create(SkDisplacementMapEffect::kR_ChannelSelectorType,
260 SkDisplacementMapEffect::kB_ChannelSelectorType,
261 40.0f, input.get(), input.get(), &cropRect),
262 SkBlurImageFilter::Create(SK_Scalar1, SK_Scalar1, input.get(), &cropRect),
sugoi234f0362014-10-23 13:59:52 -0700263 SkDropShadowImageFilter::Create(SK_Scalar1, SK_Scalar1, SK_Scalar1, SK_Scalar1,
264 SK_ColorGREEN, SkDropShadowImageFilter::kDrawShadowAndForeground_ShadowMode,
265 input.get(), &cropRect, 0),
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +0000266 SkLightingImageFilter::CreatePointLitDiffuse(location, SK_ColorGREEN, 0, 0, input.get(), &cropRect),
267 SkLightingImageFilter::CreatePointLitSpecular(location, SK_ColorGREEN, 0, 0, 0, input.get(), &cropRect),
commit-bot@chromium.orgcac5fd52014-03-10 10:51:58 +0000268 SkMatrixConvolutionImageFilter::Create(kernelSize, kernel, gain, bias, SkIPoint::Make(1, 1), SkMatrixConvolutionImageFilter::kRepeat_TileMode, false, input.get(), &cropRect),
269 SkMergeImageFilter::Create(input.get(), input.get(), SkXfermode::kSrcOver_Mode, &cropRect),
270 SkOffsetImageFilter::Create(SK_Scalar1, SK_Scalar1, input.get(), &cropRect),
271 SkOffsetImageFilter::Create(SK_Scalar1, SK_Scalar1, input.get(), &cropRect),
272 SkDilateImageFilter::Create(3, 2, input.get(), &cropRect),
273 SkErodeImageFilter::Create(2, 3, input.get(), &cropRect),
274 SkTileImageFilter::Create(inputCropRect.rect(), cropRect.rect(), input.get()),
275 SkXfermodeImageFilter::Create(SkXfermode::Create(SkXfermode::kSrcOver_Mode), input.get(), input.get(), &cropRect),
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +0000276 };
senorblanco@chromium.org6776b822014-01-03 21:48:22 +0000277
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +0000278 for (size_t i = 0; i < SK_ARRAY_COUNT(filters); ++i) {
279 SkImageFilter* filter = filters[i];
280 SkBitmap result;
281 SkIPoint offset;
282 SkString str;
senorblanco@chromium.orgf4e1a762014-02-04 00:28:46 +0000283 str.printf("filter %d", static_cast<int>(i));
senorblanco55b6d8b2014-07-30 11:26:46 -0700284 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeLargest(), NULL);
commit-bot@chromium.orgf7efa502014-04-11 18:57:00 +0000285 REPORTER_ASSERT_MESSAGE(reporter, filter->filterImage(&proxy, bitmap, ctx,
286 &result, &offset), str.c_str());
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +0000287 REPORTER_ASSERT_MESSAGE(reporter, offset.fX == 20 && offset.fY == 30, str.c_str());
senorblanco@chromium.org6776b822014-01-03 21:48:22 +0000288 }
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +0000289
290 for (size_t i = 0; i < SK_ARRAY_COUNT(filters); ++i) {
291 SkSafeUnref(filters[i]);
292 }
293}
294
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +0000295static SkBitmap make_gradient_circle(int width, int height) {
296 SkBitmap bitmap;
297 SkScalar x = SkIntToScalar(width / 2);
298 SkScalar y = SkIntToScalar(height / 2);
299 SkScalar radius = SkMinScalar(x, y) * 0.8f;
300 bitmap.allocN32Pixels(width, height);
301 SkCanvas canvas(bitmap);
302 canvas.clear(0x00000000);
303 SkColor colors[2];
304 colors[0] = SK_ColorWHITE;
305 colors[1] = SK_ColorBLACK;
306 SkAutoTUnref<SkShader> shader(
307 SkGradientShader::CreateRadial(SkPoint::Make(x, y), radius, colors, NULL, 2,
308 SkShader::kClamp_TileMode)
309 );
310 SkPaint paint;
311 paint.setShader(shader);
312 canvas.drawCircle(x, y, radius, paint);
313 return bitmap;
314}
315
senorblanco32673b92014-09-09 09:15:04 -0700316static void test_negative_blur_sigma(SkBaseDevice* device, skiatest::Reporter* reporter) {
317 // Check that SkBlurImageFilter will accept a negative sigma, either in
318 // the given arguments or after CTM application.
319 int width = 32, height = 32;
fmalita2d97bc12014-11-20 10:44:58 -0800320 SkDeviceImageFilterProxy proxy(device, SkSurfaceProps(SkSurfaceProps::kLegacyFontHost_InitType));
senorblanco32673b92014-09-09 09:15:04 -0700321 SkScalar five = SkIntToScalar(5);
322
323 SkAutoTUnref<SkBlurImageFilter> positiveFilter(
324 SkBlurImageFilter::Create(five, five)
325 );
326
327 SkAutoTUnref<SkBlurImageFilter> negativeFilter(
328 SkBlurImageFilter::Create(-five, five)
329 );
330
331 SkBitmap gradient = make_gradient_circle(width, height);
332 SkBitmap positiveResult1, negativeResult1;
333 SkBitmap positiveResult2, negativeResult2;
334 SkIPoint offset;
335 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeLargest(), NULL);
336 positiveFilter->filterImage(&proxy, gradient, ctx, &positiveResult1, &offset);
337 negativeFilter->filterImage(&proxy, gradient, ctx, &negativeResult1, &offset);
338 SkMatrix negativeScale;
339 negativeScale.setScale(-SK_Scalar1, SK_Scalar1);
340 SkImageFilter::Context negativeCTX(negativeScale, SkIRect::MakeLargest(), NULL);
341 positiveFilter->filterImage(&proxy, gradient, negativeCTX, &negativeResult2, &offset);
342 negativeFilter->filterImage(&proxy, gradient, negativeCTX, &positiveResult2, &offset);
343 SkAutoLockPixels lockP1(positiveResult1);
344 SkAutoLockPixels lockP2(positiveResult2);
345 SkAutoLockPixels lockN1(negativeResult1);
346 SkAutoLockPixels lockN2(negativeResult2);
347 for (int y = 0; y < height; y++) {
348 int diffs = memcmp(positiveResult1.getAddr32(0, y), negativeResult1.getAddr32(0, y), positiveResult1.rowBytes());
349 REPORTER_ASSERT(reporter, !diffs);
350 if (diffs) {
351 break;
352 }
353 diffs = memcmp(positiveResult1.getAddr32(0, y), negativeResult2.getAddr32(0, y), positiveResult1.rowBytes());
354 REPORTER_ASSERT(reporter, !diffs);
355 if (diffs) {
356 break;
357 }
358 diffs = memcmp(positiveResult1.getAddr32(0, y), positiveResult2.getAddr32(0, y), positiveResult1.rowBytes());
359 REPORTER_ASSERT(reporter, !diffs);
360 if (diffs) {
361 break;
362 }
363 }
364}
365
366DEF_TEST(TestNegativeBlurSigma, reporter) {
367 SkBitmap temp;
368 temp.allocN32Pixels(100, 100);
369 SkBitmapDevice device(temp);
370 test_negative_blur_sigma(&device, reporter);
371}
372
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +0000373DEF_TEST(ImageFilterDrawTiled, reporter) {
374 // Check that all filters when drawn tiled (with subsequent clip rects) exactly
375 // match the same filters drawn with a single full-canvas bitmap draw.
376 // Tests pass by not asserting.
377
378 SkAutoTUnref<SkColorFilter> cf(SkColorFilter::CreateModeFilter(SK_ColorRED, SkXfermode::kSrcIn_Mode));
379 SkPoint3 location(0, 0, SK_Scalar1);
380 SkPoint3 target(SK_Scalar1, SK_Scalar1, SK_Scalar1);
381 SkScalar kernel[9] = {
382 SkIntToScalar( 1), SkIntToScalar( 1), SkIntToScalar( 1),
383 SkIntToScalar( 1), SkIntToScalar(-7), SkIntToScalar( 1),
384 SkIntToScalar( 1), SkIntToScalar( 1), SkIntToScalar( 1),
385 };
386 SkISize kernelSize = SkISize::Make(3, 3);
387 SkScalar gain = SK_Scalar1, bias = 0;
senorblanco@chromium.org29ac34e2014-05-28 19:29:25 +0000388 SkScalar five = SkIntToScalar(5);
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +0000389
390 SkAutoTUnref<SkImageFilter> gradient_source(SkBitmapSource::Create(make_gradient_circle(64, 64)));
senorblanco@chromium.org29ac34e2014-05-28 19:29:25 +0000391 SkAutoTUnref<SkImageFilter> blur(SkBlurImageFilter::Create(five, five));
senorblanco@chromium.orgba31f1d2014-05-07 20:56:08 +0000392 SkMatrix matrix;
senorblanco@chromium.org29ac34e2014-05-28 19:29:25 +0000393
senorblanco@chromium.orgba31f1d2014-05-07 20:56:08 +0000394 matrix.setTranslate(SK_Scalar1, SK_Scalar1);
395 matrix.postRotate(SkIntToScalar(45), SK_Scalar1, SK_Scalar1);
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +0000396
senorblanco@chromium.org910702b2014-05-30 20:36:15 +0000397 SkRTreeFactory factory;
398 SkPictureRecorder recorder;
399 SkCanvas* recordingCanvas = recorder.beginRecording(64, 64, &factory, 0);
400
401 SkPaint greenPaint;
402 greenPaint.setColor(SK_ColorGREEN);
403 recordingCanvas->drawRect(SkRect::Make(SkIRect::MakeXYWH(10, 10, 30, 20)), greenPaint);
404 SkAutoTUnref<SkPicture> picture(recorder.endRecording());
405 SkAutoTUnref<SkImageFilter> pictureFilter(SkPictureImageFilter::Create(picture.get()));
senorblanco8f3937d2014-10-29 12:36:32 -0700406 SkAutoTUnref<SkShader> shader(SkPerlinNoiseShader::CreateTurbulence(SK_Scalar1, SK_Scalar1, 1, 0));
407
408 SkAutoTUnref<SkImageFilter> rectShaderFilter(SkRectShaderImageFilter::Create(shader.get()));
senorblanco@chromium.org910702b2014-05-30 20:36:15 +0000409
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +0000410 struct {
411 const char* fName;
412 SkImageFilter* fFilter;
413 } filters[] = {
414 { "color filter", SkColorFilterImageFilter::Create(cf.get()) },
415 { "displacement map", SkDisplacementMapEffect::Create(
416 SkDisplacementMapEffect::kR_ChannelSelectorType,
417 SkDisplacementMapEffect::kB_ChannelSelectorType,
senorblanco@chromium.orgd4db6572014-05-07 20:00:04 +0000418 20.0f, gradient_source.get()) },
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +0000419 { "blur", SkBlurImageFilter::Create(SK_Scalar1, SK_Scalar1) },
420 { "drop shadow", SkDropShadowImageFilter::Create(
sugoi234f0362014-10-23 13:59:52 -0700421 SK_Scalar1, SK_Scalar1, SK_Scalar1, SK_Scalar1, SK_ColorGREEN,
422 SkDropShadowImageFilter::kDrawShadowAndForeground_ShadowMode) },
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +0000423 { "diffuse lighting", SkLightingImageFilter::CreatePointLitDiffuse(
424 location, SK_ColorGREEN, 0, 0) },
425 { "specular lighting",
426 SkLightingImageFilter::CreatePointLitSpecular(location, SK_ColorGREEN, 0, 0, 0) },
427 { "matrix convolution",
428 SkMatrixConvolutionImageFilter::Create(
429 kernelSize, kernel, gain, bias, SkIPoint::Make(1, 1),
430 SkMatrixConvolutionImageFilter::kRepeat_TileMode, false) },
431 { "merge", SkMergeImageFilter::Create(NULL, NULL, SkXfermode::kSrcOver_Mode) },
432 { "offset", SkOffsetImageFilter::Create(SK_Scalar1, SK_Scalar1) },
433 { "dilate", SkDilateImageFilter::Create(3, 2) },
434 { "erode", SkErodeImageFilter::Create(2, 3) },
435 { "tile", SkTileImageFilter::Create(SkRect::MakeXYWH(0, 0, 50, 50),
436 SkRect::MakeXYWH(0, 0, 100, 100), NULL) },
senorblanco@chromium.orgba31f1d2014-05-07 20:56:08 +0000437 { "matrix", SkMatrixImageFilter::Create(matrix, SkPaint::kLow_FilterLevel) },
senorblanco@chromium.org29ac34e2014-05-28 19:29:25 +0000438 { "blur and offset", SkOffsetImageFilter::Create(five, five, blur.get()) },
senorblanco@chromium.org910702b2014-05-30 20:36:15 +0000439 { "picture and blur", SkBlurImageFilter::Create(five, five, pictureFilter.get()) },
senorblanco8f3937d2014-10-29 12:36:32 -0700440 { "rect shader and blur", SkBlurImageFilter::Create(five, five, rectShaderFilter.get()) },
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +0000441 };
442
443 SkBitmap untiledResult, tiledResult;
444 int width = 64, height = 64;
445 untiledResult.allocN32Pixels(width, height);
446 tiledResult.allocN32Pixels(width, height);
447 SkCanvas tiledCanvas(tiledResult);
448 SkCanvas untiledCanvas(untiledResult);
senorblanco@chromium.orgd4db6572014-05-07 20:00:04 +0000449 int tileSize = 8;
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +0000450
senorblanco@chromium.orgd4db6572014-05-07 20:00:04 +0000451 for (int scale = 1; scale <= 2; ++scale) {
452 for (size_t i = 0; i < SK_ARRAY_COUNT(filters); ++i) {
453 tiledCanvas.clear(0);
454 untiledCanvas.clear(0);
455 SkPaint paint;
456 paint.setImageFilter(filters[i].fFilter);
457 paint.setTextSize(SkIntToScalar(height));
458 paint.setColor(SK_ColorWHITE);
459 SkString str;
460 const char* text = "ABC";
461 SkScalar ypos = SkIntToScalar(height);
462 untiledCanvas.save();
463 untiledCanvas.scale(SkIntToScalar(scale), SkIntToScalar(scale));
464 untiledCanvas.drawText(text, strlen(text), 0, ypos, paint);
465 untiledCanvas.restore();
466 for (int y = 0; y < height; y += tileSize) {
467 for (int x = 0; x < width; x += tileSize) {
468 tiledCanvas.save();
469 tiledCanvas.clipRect(SkRect::Make(SkIRect::MakeXYWH(x, y, tileSize, tileSize)));
470 tiledCanvas.scale(SkIntToScalar(scale), SkIntToScalar(scale));
471 tiledCanvas.drawText(text, strlen(text), 0, ypos, paint);
472 tiledCanvas.restore();
473 }
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +0000474 }
senorblanco@chromium.orgd4db6572014-05-07 20:00:04 +0000475 untiledCanvas.flush();
476 tiledCanvas.flush();
477 for (int y = 0; y < height; y++) {
478 int diffs = memcmp(untiledResult.getAddr32(0, y), tiledResult.getAddr32(0, y), untiledResult.rowBytes());
479 REPORTER_ASSERT_MESSAGE(reporter, !diffs, filters[i].fName);
480 if (diffs) {
481 break;
482 }
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +0000483 }
484 }
485 }
486
487 for (size_t i = 0; i < SK_ARRAY_COUNT(filters); ++i) {
488 SkSafeUnref(filters[i].fFilter);
489 }
490}
491
mtklein3f3b3d02014-12-01 11:47:08 -0800492static void draw_saveLayer_picture(int width, int height, int tileSize,
robertphillipsa8d7f0b2014-08-29 08:03:56 -0700493 SkBBHFactory* factory, SkBitmap* result) {
mtkleind910f542014-08-22 09:06:34 -0700494
495 SkMatrix matrix;
496 matrix.setTranslate(SkIntToScalar(50), 0);
497
498 SkAutoTUnref<SkColorFilter> cf(SkColorFilter::CreateModeFilter(SK_ColorWHITE, SkXfermode::kSrc_Mode));
499 SkAutoTUnref<SkImageFilter> cfif(SkColorFilterImageFilter::Create(cf.get()));
500 SkAutoTUnref<SkImageFilter> imageFilter(SkMatrixImageFilter::Create(matrix, SkPaint::kNone_FilterLevel, cfif.get()));
501
502 SkPaint paint;
503 paint.setImageFilter(imageFilter.get());
504 SkPictureRecorder recorder;
505 SkRect bounds = SkRect::Make(SkIRect::MakeXYWH(0, 0, 50, 50));
mtklein3f3b3d02014-12-01 11:47:08 -0800506 SkCanvas* recordingCanvas = recorder.beginRecording(SkIntToScalar(width),
507 SkIntToScalar(height),
robertphillipsa8d7f0b2014-08-29 08:03:56 -0700508 factory, 0);
mtkleind910f542014-08-22 09:06:34 -0700509 recordingCanvas->translate(-55, 0);
510 recordingCanvas->saveLayer(&bounds, &paint);
511 recordingCanvas->restore();
512 SkAutoTUnref<SkPicture> picture1(recorder.endRecording());
513
514 result->allocN32Pixels(width, height);
515 SkCanvas canvas(*result);
516 canvas.clear(0);
517 canvas.clipRect(SkRect::Make(SkIRect::MakeWH(tileSize, tileSize)));
518 canvas.drawPicture(picture1.get());
519}
520
521DEF_TEST(ImageFilterDrawMatrixBBH, reporter) {
522 // Check that matrix filter when drawn tiled with BBH exactly
523 // matches the same thing drawn without BBH.
524 // Tests pass by not asserting.
525
526 const int width = 200, height = 200;
527 const int tileSize = 100;
528 SkBitmap result1, result2;
529 SkRTreeFactory factory;
530
robertphillipsa8d7f0b2014-08-29 08:03:56 -0700531 draw_saveLayer_picture(width, height, tileSize, &factory, &result1);
532 draw_saveLayer_picture(width, height, tileSize, NULL, &result2);
mtkleind910f542014-08-22 09:06:34 -0700533
534 for (int y = 0; y < height; y++) {
535 int diffs = memcmp(result1.getAddr32(0, y), result2.getAddr32(0, y), result1.rowBytes());
536 REPORTER_ASSERT(reporter, !diffs);
537 if (diffs) {
538 break;
539 }
540 }
541}
542
senorblanco1150a6d2014-08-25 12:46:58 -0700543static SkImageFilter* makeBlur(SkImageFilter* input = NULL) {
544 return SkBlurImageFilter::Create(SK_Scalar1, SK_Scalar1, input);
545}
546
547static SkImageFilter* makeDropShadow(SkImageFilter* input = NULL) {
548 return SkDropShadowImageFilter::Create(
549 SkIntToScalar(100), SkIntToScalar(100),
550 SkIntToScalar(10), SkIntToScalar(10),
sugoi234f0362014-10-23 13:59:52 -0700551 SK_ColorBLUE, SkDropShadowImageFilter::kDrawShadowAndForeground_ShadowMode,
552 input, NULL, 0);
senorblanco1150a6d2014-08-25 12:46:58 -0700553}
554
555DEF_TEST(ImageFilterBlurThenShadowBounds, reporter) {
556 SkAutoTUnref<SkImageFilter> filter1(makeBlur());
557 SkAutoTUnref<SkImageFilter> filter2(makeDropShadow(filter1.get()));
558
559 SkIRect bounds = SkIRect::MakeXYWH(0, 0, 100, 100);
560 SkIRect expectedBounds = SkIRect::MakeXYWH(-133, -133, 236, 236);
561 filter2->filterBounds(bounds, SkMatrix::I(), &bounds);
562
563 REPORTER_ASSERT(reporter, bounds == expectedBounds);
564}
565
566DEF_TEST(ImageFilterShadowThenBlurBounds, reporter) {
567 SkAutoTUnref<SkImageFilter> filter1(makeDropShadow());
568 SkAutoTUnref<SkImageFilter> filter2(makeBlur(filter1.get()));
569
570 SkIRect bounds = SkIRect::MakeXYWH(0, 0, 100, 100);
571 SkIRect expectedBounds = SkIRect::MakeXYWH(-133, -133, 236, 236);
572 filter2->filterBounds(bounds, SkMatrix::I(), &bounds);
573
574 REPORTER_ASSERT(reporter, bounds == expectedBounds);
575}
576
577DEF_TEST(ImageFilterDilateThenBlurBounds, reporter) {
578 SkAutoTUnref<SkImageFilter> filter1(SkDilateImageFilter::Create(2, 2));
579 SkAutoTUnref<SkImageFilter> filter2(makeDropShadow(filter1.get()));
580
581 SkIRect bounds = SkIRect::MakeXYWH(0, 0, 100, 100);
582 SkIRect expectedBounds = SkIRect::MakeXYWH(-132, -132, 234, 234);
583 filter2->filterBounds(bounds, SkMatrix::I(), &bounds);
584
585 REPORTER_ASSERT(reporter, bounds == expectedBounds);
586}
587
ajuma5788faa2015-02-13 09:05:47 -0800588DEF_TEST(ImageFilterComposedBlurFastBounds, reporter) {
589 SkAutoTUnref<SkImageFilter> filter1(makeBlur());
590 SkAutoTUnref<SkImageFilter> filter2(makeBlur());
591 SkAutoTUnref<SkImageFilter> composedFilter(SkComposeImageFilter::Create(filter1.get(), filter2.get()));
592
593 SkRect boundsSrc = SkRect::MakeWH(SkIntToScalar(100), SkIntToScalar(100));
594 SkRect expectedBounds = SkRect::MakeXYWH(
595 SkIntToScalar(-6), SkIntToScalar(-6), SkIntToScalar(112), SkIntToScalar(112));
596 SkRect boundsDst = SkRect::MakeEmpty();
597 composedFilter->computeFastBounds(boundsSrc, &boundsDst);
598
599 REPORTER_ASSERT(reporter, boundsDst == expectedBounds);
600}
601
robertphillipsa8d7f0b2014-08-29 08:03:56 -0700602static void draw_blurred_rect(SkCanvas* canvas) {
senorblanco837f5322014-07-14 10:19:54 -0700603 SkAutoTUnref<SkImageFilter> filter(SkBlurImageFilter::Create(SkIntToScalar(8), 0));
604 SkPaint filterPaint;
605 filterPaint.setColor(SK_ColorWHITE);
606 filterPaint.setImageFilter(filter);
607 canvas->saveLayer(NULL, &filterPaint);
608 SkPaint whitePaint;
609 whitePaint.setColor(SK_ColorWHITE);
610 canvas->drawRect(SkRect::Make(SkIRect::MakeWH(4, 4)), whitePaint);
611 canvas->restore();
612}
613
robertphillipsa8d7f0b2014-08-29 08:03:56 -0700614static void draw_picture_clipped(SkCanvas* canvas, const SkRect& clipRect, const SkPicture* picture) {
senorblanco837f5322014-07-14 10:19:54 -0700615 canvas->save();
616 canvas->clipRect(clipRect);
617 canvas->drawPicture(picture);
618 canvas->restore();
619}
620
621DEF_TEST(ImageFilterDrawTiledBlurRTree, reporter) {
622 // Check that the blur filter when recorded with RTree acceleration,
623 // and drawn tiled (with subsequent clip rects) exactly
624 // matches the same filter drawn with without RTree acceleration.
625 // This tests that the "bleed" from the blur into the otherwise-blank
626 // tiles is correctly rendered.
627 // Tests pass by not asserting.
628
629 int width = 16, height = 8;
630 SkBitmap result1, result2;
631 result1.allocN32Pixels(width, height);
632 result2.allocN32Pixels(width, height);
633 SkCanvas canvas1(result1);
634 SkCanvas canvas2(result2);
635 int tileSize = 8;
636
637 canvas1.clear(0);
638 canvas2.clear(0);
639
640 SkRTreeFactory factory;
641
642 SkPictureRecorder recorder1, recorder2;
643 // The only difference between these two pictures is that one has RTree aceleration.
mtklein3f3b3d02014-12-01 11:47:08 -0800644 SkCanvas* recordingCanvas1 = recorder1.beginRecording(SkIntToScalar(width),
645 SkIntToScalar(height),
robertphillipsa8d7f0b2014-08-29 08:03:56 -0700646 NULL, 0);
mtklein3f3b3d02014-12-01 11:47:08 -0800647 SkCanvas* recordingCanvas2 = recorder2.beginRecording(SkIntToScalar(width),
648 SkIntToScalar(height),
robertphillipsa8d7f0b2014-08-29 08:03:56 -0700649 &factory, 0);
650 draw_blurred_rect(recordingCanvas1);
651 draw_blurred_rect(recordingCanvas2);
senorblanco837f5322014-07-14 10:19:54 -0700652 SkAutoTUnref<SkPicture> picture1(recorder1.endRecording());
653 SkAutoTUnref<SkPicture> picture2(recorder2.endRecording());
654 for (int y = 0; y < height; y += tileSize) {
655 for (int x = 0; x < width; x += tileSize) {
656 SkRect tileRect = SkRect::Make(SkIRect::MakeXYWH(x, y, tileSize, tileSize));
robertphillipsa8d7f0b2014-08-29 08:03:56 -0700657 draw_picture_clipped(&canvas1, tileRect, picture1);
658 draw_picture_clipped(&canvas2, tileRect, picture2);
senorblanco837f5322014-07-14 10:19:54 -0700659 }
660 }
661 for (int y = 0; y < height; y++) {
662 int diffs = memcmp(result1.getAddr32(0, y), result2.getAddr32(0, y), result1.rowBytes());
663 REPORTER_ASSERT(reporter, !diffs);
664 if (diffs) {
665 break;
666 }
667 }
668}
669
senorblanco@chromium.org91957432014-05-01 14:03:41 +0000670DEF_TEST(ImageFilterMatrixConvolution, reporter) {
671 // Check that a 1x3 filter does not cause a spurious assert.
672 SkScalar kernel[3] = {
673 SkIntToScalar( 1), SkIntToScalar( 1), SkIntToScalar( 1),
674 };
675 SkISize kernelSize = SkISize::Make(1, 3);
676 SkScalar gain = SK_Scalar1, bias = 0;
677 SkIPoint kernelOffset = SkIPoint::Make(0, 0);
678
679 SkAutoTUnref<SkImageFilter> filter(
680 SkMatrixConvolutionImageFilter::Create(
681 kernelSize, kernel, gain, bias, kernelOffset,
682 SkMatrixConvolutionImageFilter::kRepeat_TileMode, false));
683
684 SkBitmap result;
685 int width = 16, height = 16;
686 result.allocN32Pixels(width, height);
687 SkCanvas canvas(result);
688 canvas.clear(0);
689
690 SkPaint paint;
691 paint.setImageFilter(filter);
692 SkRect rect = SkRect::Make(SkIRect::MakeWH(width, height));
693 canvas.drawRect(rect, paint);
694}
695
senorblanco@chromium.org8c7372b2014-05-02 19:13:11 +0000696DEF_TEST(ImageFilterMatrixConvolutionBorder, reporter) {
697 // Check that a filter with borders outside the target bounds
698 // does not crash.
699 SkScalar kernel[3] = {
700 0, 0, 0,
701 };
702 SkISize kernelSize = SkISize::Make(3, 1);
703 SkScalar gain = SK_Scalar1, bias = 0;
704 SkIPoint kernelOffset = SkIPoint::Make(2, 0);
705
706 SkAutoTUnref<SkImageFilter> filter(
707 SkMatrixConvolutionImageFilter::Create(
708 kernelSize, kernel, gain, bias, kernelOffset,
709 SkMatrixConvolutionImageFilter::kClamp_TileMode, true));
710
711 SkBitmap result;
712
713 int width = 10, height = 10;
714 result.allocN32Pixels(width, height);
715 SkCanvas canvas(result);
716 canvas.clear(0);
717
718 SkPaint filterPaint;
719 filterPaint.setImageFilter(filter);
720 SkRect bounds = SkRect::MakeWH(1, 10);
721 SkRect rect = SkRect::Make(SkIRect::MakeWH(width, height));
722 SkPaint rectPaint;
723 canvas.saveLayer(&bounds, &filterPaint);
724 canvas.drawRect(rect, rectPaint);
725 canvas.restore();
726}
727
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +0000728DEF_TEST(ImageFilterCropRect, reporter) {
729 SkBitmap temp;
mike@reedtribe.orgdeee4962014-02-13 14:41:43 +0000730 temp.allocN32Pixels(100, 100);
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +0000731 SkBitmapDevice device(temp);
732 test_crop_rects(&device, reporter);
733}
734
tfarina9ea53f92014-06-24 06:50:39 -0700735DEF_TEST(ImageFilterMatrix, reporter) {
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +0000736 SkBitmap temp;
mike@reedtribe.orgdeee4962014-02-13 14:41:43 +0000737 temp.allocN32Pixels(100, 100);
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +0000738 SkBitmapDevice device(temp);
739 SkCanvas canvas(&device);
740 canvas.scale(SkIntToScalar(2), SkIntToScalar(2));
741
742 SkMatrix expectedMatrix = canvas.getTotalMatrix();
743
commit-bot@chromium.org5fb2ce32014-04-17 23:35:06 +0000744 SkRTreeFactory factory;
745 SkPictureRecorder recorder;
746 SkCanvas* recordingCanvas = recorder.beginRecording(100, 100, &factory, 0);
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +0000747
748 SkPaint paint;
749 SkAutoTUnref<MatrixTestImageFilter> imageFilter(
750 new MatrixTestImageFilter(reporter, expectedMatrix));
751 paint.setImageFilter(imageFilter.get());
commit-bot@chromium.org091a5942014-04-18 14:19:31 +0000752 recordingCanvas->saveLayer(NULL, &paint);
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +0000753 SkPaint solidPaint;
754 solidPaint.setColor(0xFFFFFFFF);
755 recordingCanvas->save();
756 recordingCanvas->scale(SkIntToScalar(10), SkIntToScalar(10));
757 recordingCanvas->drawRect(SkRect::Make(SkIRect::MakeWH(100, 100)), solidPaint);
758 recordingCanvas->restore(); // scale
759 recordingCanvas->restore(); // saveLayer
robertphillips@google.com84b18c72014-04-13 19:09:42 +0000760 SkAutoTUnref<SkPicture> picture(recorder.endRecording());
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +0000761
robertphillips9b14f262014-06-04 05:40:44 -0700762 canvas.drawPicture(picture);
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +0000763}
764
senorblanco3d822c22014-07-30 14:49:31 -0700765DEF_TEST(ImageFilterCrossProcessPictureImageFilter, reporter) {
senorblanco@chromium.org97f5fc62014-05-30 20:50:56 +0000766 SkRTreeFactory factory;
767 SkPictureRecorder recorder;
768 SkCanvas* recordingCanvas = recorder.beginRecording(1, 1, &factory, 0);
769
770 // Create an SkPicture which simply draws a green 1x1 rectangle.
771 SkPaint greenPaint;
772 greenPaint.setColor(SK_ColorGREEN);
773 recordingCanvas->drawRect(SkRect::Make(SkIRect::MakeWH(1, 1)), greenPaint);
774 SkAutoTUnref<SkPicture> picture(recorder.endRecording());
775
776 // Wrap that SkPicture in an SkPictureImageFilter.
777 SkAutoTUnref<SkImageFilter> imageFilter(
778 SkPictureImageFilter::Create(picture.get()));
779
780 // Check that SkPictureImageFilter successfully serializes its contained
781 // SkPicture when not in cross-process mode.
782 SkPaint paint;
783 paint.setImageFilter(imageFilter.get());
784 SkPictureRecorder outerRecorder;
785 SkCanvas* outerCanvas = outerRecorder.beginRecording(1, 1, &factory, 0);
786 SkPaint redPaintWithFilter;
787 redPaintWithFilter.setColor(SK_ColorRED);
788 redPaintWithFilter.setImageFilter(imageFilter.get());
789 outerCanvas->drawRect(SkRect::Make(SkIRect::MakeWH(1, 1)), redPaintWithFilter);
790 SkAutoTUnref<SkPicture> outerPicture(outerRecorder.endRecording());
791
792 SkBitmap bitmap;
793 bitmap.allocN32Pixels(1, 1);
794 SkBitmapDevice device(bitmap);
795 SkCanvas canvas(&device);
796
797 // The result here should be green, since the filter replaces the primitive's red interior.
798 canvas.clear(0x0);
robertphillips9b14f262014-06-04 05:40:44 -0700799 canvas.drawPicture(outerPicture);
senorblanco@chromium.org97f5fc62014-05-30 20:50:56 +0000800 uint32_t pixel = *bitmap.getAddr32(0, 0);
801 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
802
803 // Check that, for now, SkPictureImageFilter does not serialize or
804 // deserialize its contained picture when the filter is serialized
805 // cross-process. Do this by "laundering" it through SkValidatingReadBuffer.
806 SkAutoTUnref<SkData> data(SkValidatingSerializeFlattenable(imageFilter.get()));
807 SkAutoTUnref<SkFlattenable> flattenable(SkValidatingDeserializeFlattenable(
808 data->data(), data->size(), SkImageFilter::GetFlattenableType()));
809 SkImageFilter* unflattenedFilter = static_cast<SkImageFilter*>(flattenable.get());
810
811 redPaintWithFilter.setImageFilter(unflattenedFilter);
812 SkPictureRecorder crossProcessRecorder;
813 SkCanvas* crossProcessCanvas = crossProcessRecorder.beginRecording(1, 1, &factory, 0);
814 crossProcessCanvas->drawRect(SkRect::Make(SkIRect::MakeWH(1, 1)), redPaintWithFilter);
815 SkAutoTUnref<SkPicture> crossProcessPicture(crossProcessRecorder.endRecording());
816
817 canvas.clear(0x0);
robertphillips9b14f262014-06-04 05:40:44 -0700818 canvas.drawPicture(crossProcessPicture);
senorblanco@chromium.org97f5fc62014-05-30 20:50:56 +0000819 pixel = *bitmap.getAddr32(0, 0);
robertphillipsc4bd39c2015-01-06 09:17:02 -0800820#ifdef SK_DISALLOW_CROSSPROCESS_PICTUREIMAGEFILTERS
senorblanco@chromium.org97f5fc62014-05-30 20:50:56 +0000821 // The result here should not be green, since the filter draws nothing.
822 REPORTER_ASSERT(reporter, pixel != SK_ColorGREEN);
robertphillipsc4bd39c2015-01-06 09:17:02 -0800823#else
824 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
825#endif
senorblanco@chromium.org97f5fc62014-05-30 20:50:56 +0000826}
827
senorblanco3d822c22014-07-30 14:49:31 -0700828DEF_TEST(ImageFilterClippedPictureImageFilter, reporter) {
829 SkRTreeFactory factory;
830 SkPictureRecorder recorder;
831 SkCanvas* recordingCanvas = recorder.beginRecording(1, 1, &factory, 0);
832
833 // Create an SkPicture which simply draws a green 1x1 rectangle.
834 SkPaint greenPaint;
835 greenPaint.setColor(SK_ColorGREEN);
836 recordingCanvas->drawRect(SkRect::Make(SkIRect::MakeWH(1, 1)), greenPaint);
837 SkAutoTUnref<SkPicture> picture(recorder.endRecording());
838
839 SkAutoTUnref<SkImageFilter> imageFilter(
840 SkPictureImageFilter::Create(picture.get()));
841
842 SkBitmap result;
843 SkIPoint offset;
844 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeXYWH(1, 1, 1, 1), NULL);
845 SkBitmap bitmap;
846 bitmap.allocN32Pixels(2, 2);
847 SkBitmapDevice device(bitmap);
fmalita2d97bc12014-11-20 10:44:58 -0800848 SkDeviceImageFilterProxy proxy(&device, SkSurfaceProps(SkSurfaceProps::kLegacyFontHost_InitType));
senorblanco3d822c22014-07-30 14:49:31 -0700849 REPORTER_ASSERT(reporter, !imageFilter->filterImage(&proxy, bitmap, ctx, &result, &offset));
850}
851
tfarina9ea53f92014-06-24 06:50:39 -0700852DEF_TEST(ImageFilterEmptySaveLayer, reporter) {
senorblanco@chromium.org68250c82014-05-06 22:52:55 +0000853 // Even when there's an empty saveLayer()/restore(), ensure that an image
854 // filter or color filter which affects transparent black still draws.
855
856 SkBitmap bitmap;
857 bitmap.allocN32Pixels(10, 10);
858 SkBitmapDevice device(bitmap);
859 SkCanvas canvas(&device);
860
861 SkRTreeFactory factory;
862 SkPictureRecorder recorder;
863
864 SkAutoTUnref<SkColorFilter> green(
865 SkColorFilter::CreateModeFilter(SK_ColorGREEN, SkXfermode::kSrc_Mode));
866 SkAutoTUnref<SkColorFilterImageFilter> imageFilter(
867 SkColorFilterImageFilter::Create(green.get()));
868 SkPaint imageFilterPaint;
869 imageFilterPaint.setImageFilter(imageFilter.get());
870 SkPaint colorFilterPaint;
871 colorFilterPaint.setColorFilter(green.get());
872
873 SkRect bounds = SkRect::MakeWH(10, 10);
874
875 SkCanvas* recordingCanvas = recorder.beginRecording(10, 10, &factory, 0);
876 recordingCanvas->saveLayer(&bounds, &imageFilterPaint);
877 recordingCanvas->restore();
878 SkAutoTUnref<SkPicture> picture(recorder.endRecording());
879
880 canvas.clear(0);
robertphillips9b14f262014-06-04 05:40:44 -0700881 canvas.drawPicture(picture);
senorblanco@chromium.org68250c82014-05-06 22:52:55 +0000882 uint32_t pixel = *bitmap.getAddr32(0, 0);
883 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
884
885 recordingCanvas = recorder.beginRecording(10, 10, &factory, 0);
886 recordingCanvas->saveLayer(NULL, &imageFilterPaint);
887 recordingCanvas->restore();
888 SkAutoTUnref<SkPicture> picture2(recorder.endRecording());
889
890 canvas.clear(0);
robertphillips9b14f262014-06-04 05:40:44 -0700891 canvas.drawPicture(picture2);
senorblanco@chromium.org68250c82014-05-06 22:52:55 +0000892 pixel = *bitmap.getAddr32(0, 0);
893 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
894
895 recordingCanvas = recorder.beginRecording(10, 10, &factory, 0);
896 recordingCanvas->saveLayer(&bounds, &colorFilterPaint);
897 recordingCanvas->restore();
898 SkAutoTUnref<SkPicture> picture3(recorder.endRecording());
899
900 canvas.clear(0);
robertphillips9b14f262014-06-04 05:40:44 -0700901 canvas.drawPicture(picture3);
senorblanco@chromium.org68250c82014-05-06 22:52:55 +0000902 pixel = *bitmap.getAddr32(0, 0);
903 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
904}
905
senorblanco@chromium.org28ae55d2014-03-24 21:32:28 +0000906static void test_huge_blur(SkBaseDevice* device, skiatest::Reporter* reporter) {
senorblanco@chromium.org09843fd2014-03-24 20:50:59 +0000907 SkCanvas canvas(device);
908
909 SkBitmap bitmap;
910 bitmap.allocN32Pixels(100, 100);
911 bitmap.eraseARGB(0, 0, 0, 0);
912
913 // Check that a blur with an insane radius does not crash or assert.
914 SkAutoTUnref<SkImageFilter> blur(SkBlurImageFilter::Create(SkIntToScalar(1<<30), SkIntToScalar(1<<30)));
915
916 SkPaint paint;
917 paint.setImageFilter(blur);
918 canvas.drawSprite(bitmap, 0, 0, &paint);
919}
920
921DEF_TEST(HugeBlurImageFilter, reporter) {
922 SkBitmap temp;
923 temp.allocN32Pixels(100, 100);
924 SkBitmapDevice device(temp);
925 test_huge_blur(&device, reporter);
926}
927
senorblanco3a495202014-09-29 07:57:20 -0700928DEF_TEST(MatrixConvolutionSanityTest, reporter) {
929 SkScalar kernel[1] = { 0 };
930 SkScalar gain = SK_Scalar1, bias = 0;
931 SkIPoint kernelOffset = SkIPoint::Make(1, 1);
932
933 // Check that an enormous (non-allocatable) kernel gives a NULL filter.
934 SkAutoTUnref<SkImageFilter> conv(SkMatrixConvolutionImageFilter::Create(
935 SkISize::Make(1<<30, 1<<30),
936 kernel,
937 gain,
938 bias,
939 kernelOffset,
940 SkMatrixConvolutionImageFilter::kRepeat_TileMode,
941 false));
942
943 REPORTER_ASSERT(reporter, NULL == conv.get());
944
945 // Check that a NULL kernel gives a NULL filter.
946 conv.reset(SkMatrixConvolutionImageFilter::Create(
947 SkISize::Make(1, 1),
948 NULL,
949 gain,
950 bias,
951 kernelOffset,
952 SkMatrixConvolutionImageFilter::kRepeat_TileMode,
953 false));
954
955 REPORTER_ASSERT(reporter, NULL == conv.get());
956
957 // Check that a kernel width < 1 gives a NULL filter.
958 conv.reset(SkMatrixConvolutionImageFilter::Create(
959 SkISize::Make(0, 1),
960 kernel,
961 gain,
962 bias,
963 kernelOffset,
964 SkMatrixConvolutionImageFilter::kRepeat_TileMode,
965 false));
966
967 REPORTER_ASSERT(reporter, NULL == conv.get());
968
969 // Check that kernel height < 1 gives a NULL filter.
970 conv.reset(SkMatrixConvolutionImageFilter::Create(
971 SkISize::Make(1, -1),
972 kernel,
973 gain,
974 bias,
975 kernelOffset,
976 SkMatrixConvolutionImageFilter::kRepeat_TileMode,
977 false));
978
979 REPORTER_ASSERT(reporter, NULL == conv.get());
980}
981
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +0000982static void test_xfermode_cropped_input(SkBaseDevice* device, skiatest::Reporter* reporter) {
983 SkCanvas canvas(device);
984 canvas.clear(0);
985
986 SkBitmap bitmap;
987 bitmap.allocN32Pixels(1, 1);
988 bitmap.eraseARGB(255, 255, 255, 255);
989
990 SkAutoTUnref<SkColorFilter> green(
991 SkColorFilter::CreateModeFilter(SK_ColorGREEN, SkXfermode::kSrcIn_Mode));
992 SkAutoTUnref<SkColorFilterImageFilter> greenFilter(
993 SkColorFilterImageFilter::Create(green.get()));
994 SkImageFilter::CropRect cropRect(SkRect::MakeEmpty());
995 SkAutoTUnref<SkColorFilterImageFilter> croppedOut(
996 SkColorFilterImageFilter::Create(green.get(), NULL, &cropRect));
997
998 // Check that an xfermode image filter whose input has been cropped out still draws the other
999 // input. Also check that drawing with both inputs cropped out doesn't cause a GPU warning.
1000 SkXfermode* mode = SkXfermode::Create(SkXfermode::kSrcOver_Mode);
1001 SkAutoTUnref<SkImageFilter> xfermodeNoFg(
1002 SkXfermodeImageFilter::Create(mode, greenFilter, croppedOut));
1003 SkAutoTUnref<SkImageFilter> xfermodeNoBg(
1004 SkXfermodeImageFilter::Create(mode, croppedOut, greenFilter));
1005 SkAutoTUnref<SkImageFilter> xfermodeNoFgNoBg(
1006 SkXfermodeImageFilter::Create(mode, croppedOut, croppedOut));
1007
1008 SkPaint paint;
1009 paint.setImageFilter(xfermodeNoFg);
1010 canvas.drawSprite(bitmap, 0, 0, &paint);
1011
1012 uint32_t pixel;
kkinnunena9d9a392015-03-06 07:16:00 -08001013 SkImageInfo info = SkImageInfo::Make(1, 1, kBGRA_8888_SkColorType, kUnpremul_SkAlphaType);
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001014 canvas.readPixels(info, &pixel, 4, 0, 0);
1015 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1016
1017 paint.setImageFilter(xfermodeNoBg);
1018 canvas.drawSprite(bitmap, 0, 0, &paint);
1019 canvas.readPixels(info, &pixel, 4, 0, 0);
1020 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1021
1022 paint.setImageFilter(xfermodeNoFgNoBg);
1023 canvas.drawSprite(bitmap, 0, 0, &paint);
1024 canvas.readPixels(info, &pixel, 4, 0, 0);
1025 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1026}
1027
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001028DEF_TEST(ImageFilterNestedSaveLayer, reporter) {
1029 SkBitmap temp;
1030 temp.allocN32Pixels(50, 50);
1031 SkBitmapDevice device(temp);
1032 SkCanvas canvas(&device);
1033 canvas.clear(0x0);
1034
1035 SkBitmap bitmap;
1036 bitmap.allocN32Pixels(10, 10);
1037 bitmap.eraseColor(SK_ColorGREEN);
1038
1039 SkMatrix matrix;
1040 matrix.setScale(SkIntToScalar(2), SkIntToScalar(2));
1041 matrix.postTranslate(SkIntToScalar(-20), SkIntToScalar(-20));
1042 SkAutoTUnref<SkImageFilter> matrixFilter(
1043 SkMatrixImageFilter::Create(matrix, SkPaint::kLow_FilterLevel));
1044
1045 // Test that saveLayer() with a filter nested inside another saveLayer() applies the
1046 // correct offset to the filter matrix.
1047 SkRect bounds1 = SkRect::MakeXYWH(10, 10, 30, 30);
1048 canvas.saveLayer(&bounds1, NULL);
1049 SkPaint filterPaint;
1050 filterPaint.setImageFilter(matrixFilter);
1051 SkRect bounds2 = SkRect::MakeXYWH(20, 20, 10, 10);
1052 canvas.saveLayer(&bounds2, &filterPaint);
1053 SkPaint greenPaint;
1054 greenPaint.setColor(SK_ColorGREEN);
1055 canvas.drawRect(bounds2, greenPaint);
1056 canvas.restore();
1057 canvas.restore();
1058 SkPaint strokePaint;
1059 strokePaint.setStyle(SkPaint::kStroke_Style);
1060 strokePaint.setColor(SK_ColorRED);
1061
kkinnunena9d9a392015-03-06 07:16:00 -08001062 SkImageInfo info = SkImageInfo::Make(1, 1, kBGRA_8888_SkColorType, kUnpremul_SkAlphaType);
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001063 uint32_t pixel;
1064 canvas.readPixels(info, &pixel, 4, 25, 25);
1065 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1066
1067 // Test that drawSprite() with a filter nested inside a saveLayer() applies the
1068 // correct offset to the filter matrix.
1069 canvas.clear(0x0);
1070 canvas.readPixels(info, &pixel, 4, 25, 25);
1071 canvas.saveLayer(&bounds1, NULL);
1072 canvas.drawSprite(bitmap, 20, 20, &filterPaint);
1073 canvas.restore();
1074
1075 canvas.readPixels(info, &pixel, 4, 25, 25);
1076 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1077}
1078
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001079DEF_TEST(XfermodeImageFilterCroppedInput, reporter) {
1080 SkBitmap temp;
1081 temp.allocN32Pixels(100, 100);
1082 SkBitmapDevice device(temp);
1083 test_xfermode_cropped_input(&device, reporter);
1084}
senorblanco@chromium.org09843fd2014-03-24 20:50:59 +00001085
ajuma5788faa2015-02-13 09:05:47 -08001086DEF_TEST(ComposedImageFilterOffset, reporter) {
1087 SkBitmap bitmap;
1088 bitmap.allocN32Pixels(100, 100);
1089 bitmap.eraseARGB(0, 0, 0, 0);
1090 SkBitmapDevice device(bitmap);
1091 SkDeviceImageFilterProxy proxy(&device, SkSurfaceProps(SkSurfaceProps::kLegacyFontHost_InitType));
1092
1093 SkImageFilter::CropRect cropRect(SkRect::MakeXYWH(1, 0, 20, 20));
1094 SkAutoTUnref<SkImageFilter> offsetFilter(SkOffsetImageFilter::Create(0, 0, NULL, &cropRect));
ajuma8e8c9402015-02-13 10:15:46 -08001095 SkAutoTUnref<SkImageFilter> blurFilter(makeBlur());
1096 SkAutoTUnref<SkImageFilter> composedFilter(SkComposeImageFilter::Create(blurFilter, offsetFilter.get()));
ajuma5788faa2015-02-13 09:05:47 -08001097 SkBitmap result;
1098 SkIPoint offset;
1099 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeLargest(), NULL);
1100 REPORTER_ASSERT(reporter, composedFilter->filterImage(&proxy, bitmap, ctx, &result, &offset));
1101 REPORTER_ASSERT(reporter, offset.fX == 1 && offset.fY == 0);
1102}
1103
senorblanco@chromium.org58d14662014-02-03 22:36:39 +00001104#if SK_SUPPORT_GPU
reed4a8126e2014-09-22 07:29:03 -07001105const SkSurfaceProps gProps = SkSurfaceProps(SkSurfaceProps::kLegacyFontHost_InitType);
1106
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +00001107DEF_GPUTEST(ImageFilterCropRectGPU, reporter, factory) {
1108 GrContext* context = factory->get(static_cast<GrContextFactory::GLContextType>(0));
commit-bot@chromium.org15a14052014-02-16 00:59:25 +00001109 SkAutoTUnref<SkGpuDevice> device(SkGpuDevice::Create(context,
bsalomonafe30052015-01-16 07:32:33 -08001110 SkSurface::kNo_Budgeted,
commit-bot@chromium.org15a14052014-02-16 00:59:25 +00001111 SkImageInfo::MakeN32Premul(100, 100),
bsalomonafe30052015-01-16 07:32:33 -08001112 0,
1113 &gProps));
commit-bot@chromium.org15a14052014-02-16 00:59:25 +00001114 test_crop_rects(device, reporter);
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +00001115}
senorblanco@chromium.org09843fd2014-03-24 20:50:59 +00001116
1117DEF_GPUTEST(HugeBlurImageFilterGPU, reporter, factory) {
1118 GrContext* context = factory->get(static_cast<GrContextFactory::GLContextType>(0));
1119 SkAutoTUnref<SkGpuDevice> device(SkGpuDevice::Create(context,
bsalomonafe30052015-01-16 07:32:33 -08001120 SkSurface::kNo_Budgeted,
senorblanco@chromium.org09843fd2014-03-24 20:50:59 +00001121 SkImageInfo::MakeN32Premul(100, 100),
bsalomonafe30052015-01-16 07:32:33 -08001122 0,
1123 &gProps));
senorblanco@chromium.org09843fd2014-03-24 20:50:59 +00001124 test_huge_blur(device, reporter);
1125}
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001126
1127DEF_GPUTEST(XfermodeImageFilterCroppedInputGPU, reporter, factory) {
1128 GrContext* context = factory->get(static_cast<GrContextFactory::GLContextType>(0));
1129 SkAutoTUnref<SkGpuDevice> device(SkGpuDevice::Create(context,
bsalomonafe30052015-01-16 07:32:33 -08001130 SkSurface::kNo_Budgeted,
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001131 SkImageInfo::MakeN32Premul(1, 1),
bsalomonafe30052015-01-16 07:32:33 -08001132 0,
1133 &gProps));
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001134 test_xfermode_cropped_input(device, reporter);
1135}
senorblanco32673b92014-09-09 09:15:04 -07001136
1137DEF_GPUTEST(TestNegativeBlurSigmaGPU, reporter, factory) {
1138 GrContext* context = factory->get(static_cast<GrContextFactory::GLContextType>(0));
1139 SkAutoTUnref<SkGpuDevice> device(SkGpuDevice::Create(context,
bsalomonafe30052015-01-16 07:32:33 -08001140 SkSurface::kNo_Budgeted,
senorblanco32673b92014-09-09 09:15:04 -07001141 SkImageInfo::MakeN32Premul(1, 1),
bsalomonafe30052015-01-16 07:32:33 -08001142 0,
1143 &gProps));
senorblanco32673b92014-09-09 09:15:04 -07001144 test_negative_blur_sigma(device, reporter);
1145}
senorblanco@chromium.org58d14662014-02-03 22:36:39 +00001146#endif