blob: 778230b5d6a24d4b1e07faeac48fa5bbe7edce3d [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"
15#include "SkDeviceImageFilterProxy.h"
senorblanco@chromium.org6776b822014-01-03 21:48:22 +000016#include "SkDisplacementMapEffect.h"
17#include "SkDropShadowImageFilter.h"
senorblanco@chromium.org97f5fc62014-05-30 20:50:56 +000018#include "SkFlattenableSerialization.h"
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +000019#include "SkGradientShader.h"
commit-bot@chromium.org4b681bc2013-09-13 12:40:02 +000020#include "SkLightingImageFilter.h"
tfarina@chromium.org8f6884a2014-01-24 20:56:26 +000021#include "SkMatrixConvolutionImageFilter.h"
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +000022#include "SkMatrixImageFilter.h"
senorblanco@chromium.org6776b822014-01-03 21:48:22 +000023#include "SkMergeImageFilter.h"
24#include "SkMorphologyImageFilter.h"
senorblanco@chromium.org6776b822014-01-03 21:48:22 +000025#include "SkOffsetImageFilter.h"
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +000026#include "SkPicture.h"
senorblanco@chromium.org910702b2014-05-30 20:36:15 +000027#include "SkPictureImageFilter.h"
robertphillips@google.com770963f2014-04-18 18:04:41 +000028#include "SkPictureRecorder.h"
halcanary97d2c0a2014-08-19 06:27:53 -070029#include "SkReadBuffer.h"
tfarina@chromium.org8f6884a2014-01-24 20:56:26 +000030#include "SkRect.h"
senorblanco@chromium.org6776b822014-01-03 21:48:22 +000031#include "SkTileImageFilter.h"
32#include "SkXfermodeImageFilter.h"
tfarina@chromium.org8f6884a2014-01-24 20:56:26 +000033#include "Test.h"
senorblanco@chromium.org194d7752013-07-24 22:19:24 +000034
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +000035#if SK_SUPPORT_GPU
36#include "GrContextFactory.h"
37#include "SkGpuDevice.h"
38#endif
39
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +000040static const int kBitmapSize = 4;
commit-bot@chromium.org4b681bc2013-09-13 12:40:02 +000041
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +000042namespace {
43
44class MatrixTestImageFilter : public SkImageFilter {
45public:
46 MatrixTestImageFilter(skiatest::Reporter* reporter, const SkMatrix& expectedMatrix)
senorblanco9ea3d572014-07-08 09:16:22 -070047 : SkImageFilter(0, NULL), fReporter(reporter), fExpectedMatrix(expectedMatrix) {
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +000048 }
49
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +000050 virtual bool onFilterImage(Proxy*, const SkBitmap& src, const Context& ctx,
senorblanco@chromium.org09373352014-02-05 23:04:28 +000051 SkBitmap* result, SkIPoint* offset) const SK_OVERRIDE {
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +000052 REPORTER_ASSERT(fReporter, ctx.ctm() == fExpectedMatrix);
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +000053 return true;
54 }
55
56 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(MatrixTestImageFilter)
57
58protected:
reed9fa60da2014-08-21 07:59:51 -070059#ifdef SK_SUPPORT_LEGACY_DEEPFLATTENING
senorblanco9ea3d572014-07-08 09:16:22 -070060 explicit MatrixTestImageFilter(SkReadBuffer& buffer) : SkImageFilter(0, NULL) {
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +000061 fReporter = static_cast<skiatest::Reporter*>(buffer.readFunctionPtr());
62 buffer.readMatrix(&fExpectedMatrix);
63 }
reed9fa60da2014-08-21 07:59:51 -070064#endif
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +000065
66 virtual void flatten(SkWriteBuffer& buffer) const SK_OVERRIDE {
reed9fa60da2014-08-21 07:59:51 -070067 this->INHERITED::flatten(buffer);
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +000068 buffer.writeFunctionPtr(fReporter);
69 buffer.writeMatrix(fExpectedMatrix);
70 }
71
72private:
73 skiatest::Reporter* fReporter;
74 SkMatrix fExpectedMatrix;
reed9fa60da2014-08-21 07:59:51 -070075
76 typedef SkImageFilter INHERITED;
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +000077};
78
79}
80
reed9fa60da2014-08-21 07:59:51 -070081SkFlattenable* MatrixTestImageFilter::CreateProc(SkReadBuffer& buffer) {
82 SK_IMAGEFILTER_UNFLATTEN_COMMON(common, 1);
83 skiatest::Reporter* reporter = (skiatest::Reporter*)buffer.readFunctionPtr();
84 SkMatrix matrix;
85 buffer.readMatrix(&matrix);
86 return SkNEW_ARGS(MatrixTestImageFilter, (reporter, matrix));
87}
88
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +000089static void make_small_bitmap(SkBitmap& bitmap) {
mike@reedtribe.orgdeee4962014-02-13 14:41:43 +000090 bitmap.allocN32Pixels(kBitmapSize, kBitmapSize);
91 SkCanvas canvas(bitmap);
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +000092 canvas.clear(0x00000000);
93 SkPaint darkPaint;
94 darkPaint.setColor(0xFF804020);
95 SkPaint lightPaint;
96 lightPaint.setColor(0xFF244484);
97 const int i = kBitmapSize / 4;
98 for (int y = 0; y < kBitmapSize; y += i) {
99 for (int x = 0; x < kBitmapSize; x += i) {
100 canvas.save();
101 canvas.translate(SkIntToScalar(x), SkIntToScalar(y));
102 canvas.drawRect(SkRect::MakeXYWH(0, 0,
103 SkIntToScalar(i),
104 SkIntToScalar(i)), darkPaint);
105 canvas.drawRect(SkRect::MakeXYWH(SkIntToScalar(i),
106 0,
107 SkIntToScalar(i),
108 SkIntToScalar(i)), lightPaint);
109 canvas.drawRect(SkRect::MakeXYWH(0,
110 SkIntToScalar(i),
111 SkIntToScalar(i),
112 SkIntToScalar(i)), lightPaint);
113 canvas.drawRect(SkRect::MakeXYWH(SkIntToScalar(i),
114 SkIntToScalar(i),
115 SkIntToScalar(i),
116 SkIntToScalar(i)), darkPaint);
117 canvas.restore();
commit-bot@chromium.org4b681bc2013-09-13 12:40:02 +0000118 }
119 }
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000120}
senorblanco@chromium.org194d7752013-07-24 22:19:24 +0000121
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000122static SkImageFilter* make_scale(float amount, SkImageFilter* input = NULL) {
123 SkScalar s = amount;
124 SkScalar matrix[20] = { s, 0, 0, 0, 0,
125 0, s, 0, 0, 0,
126 0, 0, s, 0, 0,
127 0, 0, 0, s, 0 };
commit-bot@chromium.org727a3522014-02-21 18:46:30 +0000128 SkAutoTUnref<SkColorFilter> filter(SkColorMatrixFilter::Create(matrix));
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000129 return SkColorFilterImageFilter::Create(filter, input);
130}
131
132static SkImageFilter* make_grayscale(SkImageFilter* input = NULL, const SkImageFilter::CropRect* cropRect = NULL) {
133 SkScalar matrix[20];
134 memset(matrix, 0, 20 * sizeof(SkScalar));
135 matrix[0] = matrix[5] = matrix[10] = 0.2126f;
136 matrix[1] = matrix[6] = matrix[11] = 0.7152f;
137 matrix[2] = matrix[7] = matrix[12] = 0.0722f;
138 matrix[18] = 1.0f;
commit-bot@chromium.org727a3522014-02-21 18:46:30 +0000139 SkAutoTUnref<SkColorFilter> filter(SkColorMatrixFilter::Create(matrix));
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000140 return SkColorFilterImageFilter::Create(filter, input, cropRect);
141}
142
143DEF_TEST(ImageFilter, reporter) {
144 {
145 // Check that two non-clipping color matrices concatenate into a single filter.
146 SkAutoTUnref<SkImageFilter> halfBrightness(make_scale(0.5f));
147 SkAutoTUnref<SkImageFilter> quarterBrightness(make_scale(0.5f, halfBrightness));
148 REPORTER_ASSERT(reporter, NULL == quarterBrightness->getInput(0));
senorblanco@chromium.org194d7752013-07-24 22:19:24 +0000149 }
150
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000151 {
152 // Check that a clipping color matrix followed by a grayscale does not concatenate into a single filter.
153 SkAutoTUnref<SkImageFilter> doubleBrightness(make_scale(2.0f));
154 SkAutoTUnref<SkImageFilter> halfBrightness(make_scale(0.5f, doubleBrightness));
bsalomon49f085d2014-09-05 13:34:00 -0700155 REPORTER_ASSERT(reporter, halfBrightness->getInput(0));
senorblanco@chromium.org194d7752013-07-24 22:19:24 +0000156 }
157
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000158 {
159 // Check that a color filter image filter without a crop rect can be
160 // expressed as a color filter.
161 SkAutoTUnref<SkImageFilter> gray(make_grayscale());
162 REPORTER_ASSERT(reporter, true == gray->asColorFilter(NULL));
senorblanco@chromium.org194d7752013-07-24 22:19:24 +0000163 }
164
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000165 {
166 // Check that a color filter image filter with a crop rect cannot
167 // be expressed as a color filter.
168 SkImageFilter::CropRect cropRect(SkRect::MakeXYWH(0, 0, 100, 100));
169 SkAutoTUnref<SkImageFilter> grayWithCrop(make_grayscale(NULL, &cropRect));
170 REPORTER_ASSERT(reporter, false == grayWithCrop->asColorFilter(NULL));
171 }
172
173 {
senorblanco3df05012014-07-03 11:13:09 -0700174 // Check that two non-commutative matrices are concatenated in
175 // the correct order.
176 SkScalar blueToRedMatrix[20] = { 0 };
177 blueToRedMatrix[2] = blueToRedMatrix[18] = SK_Scalar1;
178 SkScalar redToGreenMatrix[20] = { 0 };
179 redToGreenMatrix[5] = redToGreenMatrix[18] = SK_Scalar1;
180 SkAutoTUnref<SkColorFilter> blueToRed(SkColorMatrixFilter::Create(blueToRedMatrix));
181 SkAutoTUnref<SkImageFilter> filter1(SkColorFilterImageFilter::Create(blueToRed.get()));
182 SkAutoTUnref<SkColorFilter> redToGreen(SkColorMatrixFilter::Create(redToGreenMatrix));
183 SkAutoTUnref<SkImageFilter> filter2(SkColorFilterImageFilter::Create(redToGreen.get(), filter1.get()));
184
185 SkBitmap result;
186 result.allocN32Pixels(kBitmapSize, kBitmapSize);
187
188 SkPaint paint;
189 paint.setColor(SK_ColorBLUE);
190 paint.setImageFilter(filter2.get());
191 SkCanvas canvas(result);
192 canvas.clear(0x0);
193 SkRect rect = SkRect::Make(SkIRect::MakeWH(kBitmapSize, kBitmapSize));
194 canvas.drawRect(rect, paint);
195 uint32_t pixel = *result.getAddr32(0, 0);
196 // The result here should be green, since we have effectively shifted blue to green.
197 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
198 }
199
200 {
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000201 // Tests pass by not asserting
202 SkBitmap bitmap, result;
203 make_small_bitmap(bitmap);
mike@reedtribe.orgdeee4962014-02-13 14:41:43 +0000204 result.allocN32Pixels(kBitmapSize, kBitmapSize);
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000205
senorblanco@chromium.org194d7752013-07-24 22:19:24 +0000206 {
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000207 // This tests for :
208 // 1 ) location at (0,0,1)
209 SkPoint3 location(0, 0, SK_Scalar1);
210 // 2 ) location and target at same value
211 SkPoint3 target(location.fX, location.fY, location.fZ);
212 // 3 ) large negative specular exponent value
213 SkScalar specularExponent = -1000;
214
commit-bot@chromium.orgcac5fd52014-03-10 10:51:58 +0000215 SkAutoTUnref<SkImageFilter> bmSrc(SkBitmapSource::Create(bitmap));
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000216 SkPaint paint;
217 paint.setImageFilter(SkLightingImageFilter::CreateSpotLitSpecular(
218 location, target, specularExponent, 180,
219 0xFFFFFFFF, SK_Scalar1, SK_Scalar1, SK_Scalar1,
220 bmSrc))->unref();
221 SkCanvas canvas(result);
222 SkRect r = SkRect::MakeWH(SkIntToScalar(kBitmapSize),
223 SkIntToScalar(kBitmapSize));
224 canvas.drawRect(r, paint);
senorblanco@chromium.org194d7752013-07-24 22:19:24 +0000225 }
senorblanco@chromium.org194d7752013-07-24 22:19:24 +0000226 }
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +0000227}
senorblanco@chromium.org6776b822014-01-03 21:48:22 +0000228
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +0000229static void test_crop_rects(SkBaseDevice* device, skiatest::Reporter* reporter) {
230 // Check that all filters offset to their absolute crop rect,
231 // unaffected by the input crop rect.
232 // Tests pass by not asserting.
233 SkBitmap bitmap;
mike@reedtribe.orgdeee4962014-02-13 14:41:43 +0000234 bitmap.allocN32Pixels(100, 100);
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +0000235 bitmap.eraseARGB(0, 0, 0, 0);
236 SkDeviceImageFilterProxy proxy(device);
senorblanco@chromium.org6776b822014-01-03 21:48:22 +0000237
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +0000238 SkImageFilter::CropRect inputCropRect(SkRect::MakeXYWH(8, 13, 80, 80));
239 SkImageFilter::CropRect cropRect(SkRect::MakeXYWH(20, 30, 60, 60));
240 SkAutoTUnref<SkImageFilter> input(make_grayscale(NULL, &inputCropRect));
senorblanco@chromium.org6776b822014-01-03 21:48:22 +0000241
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +0000242 SkAutoTUnref<SkColorFilter> cf(SkColorFilter::CreateModeFilter(SK_ColorRED, SkXfermode::kSrcIn_Mode));
243 SkPoint3 location(0, 0, SK_Scalar1);
244 SkPoint3 target(SK_Scalar1, SK_Scalar1, SK_Scalar1);
245 SkScalar kernel[9] = {
246 SkIntToScalar( 1), SkIntToScalar( 1), SkIntToScalar( 1),
247 SkIntToScalar( 1), SkIntToScalar(-7), SkIntToScalar( 1),
248 SkIntToScalar( 1), SkIntToScalar( 1), SkIntToScalar( 1),
249 };
250 SkISize kernelSize = SkISize::Make(3, 3);
251 SkScalar gain = SK_Scalar1, bias = 0;
senorblanco@chromium.org6776b822014-01-03 21:48:22 +0000252
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +0000253 SkImageFilter* filters[] = {
254 SkColorFilterImageFilter::Create(cf.get(), input.get(), &cropRect),
commit-bot@chromium.orgcac5fd52014-03-10 10:51:58 +0000255 SkDisplacementMapEffect::Create(SkDisplacementMapEffect::kR_ChannelSelectorType,
256 SkDisplacementMapEffect::kB_ChannelSelectorType,
257 40.0f, input.get(), input.get(), &cropRect),
258 SkBlurImageFilter::Create(SK_Scalar1, SK_Scalar1, input.get(), &cropRect),
sugoi234f0362014-10-23 13:59:52 -0700259 SkDropShadowImageFilter::Create(SK_Scalar1, SK_Scalar1, SK_Scalar1, SK_Scalar1,
260 SK_ColorGREEN, SkDropShadowImageFilter::kDrawShadowAndForeground_ShadowMode,
261 input.get(), &cropRect, 0),
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +0000262 SkLightingImageFilter::CreatePointLitDiffuse(location, SK_ColorGREEN, 0, 0, input.get(), &cropRect),
263 SkLightingImageFilter::CreatePointLitSpecular(location, SK_ColorGREEN, 0, 0, 0, input.get(), &cropRect),
commit-bot@chromium.orgcac5fd52014-03-10 10:51:58 +0000264 SkMatrixConvolutionImageFilter::Create(kernelSize, kernel, gain, bias, SkIPoint::Make(1, 1), SkMatrixConvolutionImageFilter::kRepeat_TileMode, false, input.get(), &cropRect),
265 SkMergeImageFilter::Create(input.get(), input.get(), SkXfermode::kSrcOver_Mode, &cropRect),
266 SkOffsetImageFilter::Create(SK_Scalar1, SK_Scalar1, input.get(), &cropRect),
267 SkOffsetImageFilter::Create(SK_Scalar1, SK_Scalar1, input.get(), &cropRect),
268 SkDilateImageFilter::Create(3, 2, input.get(), &cropRect),
269 SkErodeImageFilter::Create(2, 3, input.get(), &cropRect),
270 SkTileImageFilter::Create(inputCropRect.rect(), cropRect.rect(), input.get()),
271 SkXfermodeImageFilter::Create(SkXfermode::Create(SkXfermode::kSrcOver_Mode), input.get(), input.get(), &cropRect),
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +0000272 };
senorblanco@chromium.org6776b822014-01-03 21:48:22 +0000273
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +0000274 for (size_t i = 0; i < SK_ARRAY_COUNT(filters); ++i) {
275 SkImageFilter* filter = filters[i];
276 SkBitmap result;
277 SkIPoint offset;
278 SkString str;
senorblanco@chromium.orgf4e1a762014-02-04 00:28:46 +0000279 str.printf("filter %d", static_cast<int>(i));
senorblanco55b6d8b2014-07-30 11:26:46 -0700280 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeLargest(), NULL);
commit-bot@chromium.orgf7efa502014-04-11 18:57:00 +0000281 REPORTER_ASSERT_MESSAGE(reporter, filter->filterImage(&proxy, bitmap, ctx,
282 &result, &offset), str.c_str());
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +0000283 REPORTER_ASSERT_MESSAGE(reporter, offset.fX == 20 && offset.fY == 30, str.c_str());
senorblanco@chromium.org6776b822014-01-03 21:48:22 +0000284 }
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +0000285
286 for (size_t i = 0; i < SK_ARRAY_COUNT(filters); ++i) {
287 SkSafeUnref(filters[i]);
288 }
289}
290
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +0000291static SkBitmap make_gradient_circle(int width, int height) {
292 SkBitmap bitmap;
293 SkScalar x = SkIntToScalar(width / 2);
294 SkScalar y = SkIntToScalar(height / 2);
295 SkScalar radius = SkMinScalar(x, y) * 0.8f;
296 bitmap.allocN32Pixels(width, height);
297 SkCanvas canvas(bitmap);
298 canvas.clear(0x00000000);
299 SkColor colors[2];
300 colors[0] = SK_ColorWHITE;
301 colors[1] = SK_ColorBLACK;
302 SkAutoTUnref<SkShader> shader(
303 SkGradientShader::CreateRadial(SkPoint::Make(x, y), radius, colors, NULL, 2,
304 SkShader::kClamp_TileMode)
305 );
306 SkPaint paint;
307 paint.setShader(shader);
308 canvas.drawCircle(x, y, radius, paint);
309 return bitmap;
310}
311
senorblanco32673b92014-09-09 09:15:04 -0700312static void test_negative_blur_sigma(SkBaseDevice* device, skiatest::Reporter* reporter) {
313 // Check that SkBlurImageFilter will accept a negative sigma, either in
314 // the given arguments or after CTM application.
315 int width = 32, height = 32;
316 SkDeviceImageFilterProxy proxy(device);
317 SkScalar five = SkIntToScalar(5);
318
319 SkAutoTUnref<SkBlurImageFilter> positiveFilter(
320 SkBlurImageFilter::Create(five, five)
321 );
322
323 SkAutoTUnref<SkBlurImageFilter> negativeFilter(
324 SkBlurImageFilter::Create(-five, five)
325 );
326
327 SkBitmap gradient = make_gradient_circle(width, height);
328 SkBitmap positiveResult1, negativeResult1;
329 SkBitmap positiveResult2, negativeResult2;
330 SkIPoint offset;
331 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeLargest(), NULL);
332 positiveFilter->filterImage(&proxy, gradient, ctx, &positiveResult1, &offset);
333 negativeFilter->filterImage(&proxy, gradient, ctx, &negativeResult1, &offset);
334 SkMatrix negativeScale;
335 negativeScale.setScale(-SK_Scalar1, SK_Scalar1);
336 SkImageFilter::Context negativeCTX(negativeScale, SkIRect::MakeLargest(), NULL);
337 positiveFilter->filterImage(&proxy, gradient, negativeCTX, &negativeResult2, &offset);
338 negativeFilter->filterImage(&proxy, gradient, negativeCTX, &positiveResult2, &offset);
339 SkAutoLockPixels lockP1(positiveResult1);
340 SkAutoLockPixels lockP2(positiveResult2);
341 SkAutoLockPixels lockN1(negativeResult1);
342 SkAutoLockPixels lockN2(negativeResult2);
343 for (int y = 0; y < height; y++) {
344 int diffs = memcmp(positiveResult1.getAddr32(0, y), negativeResult1.getAddr32(0, y), positiveResult1.rowBytes());
345 REPORTER_ASSERT(reporter, !diffs);
346 if (diffs) {
347 break;
348 }
349 diffs = memcmp(positiveResult1.getAddr32(0, y), negativeResult2.getAddr32(0, y), positiveResult1.rowBytes());
350 REPORTER_ASSERT(reporter, !diffs);
351 if (diffs) {
352 break;
353 }
354 diffs = memcmp(positiveResult1.getAddr32(0, y), positiveResult2.getAddr32(0, y), positiveResult1.rowBytes());
355 REPORTER_ASSERT(reporter, !diffs);
356 if (diffs) {
357 break;
358 }
359 }
360}
361
362DEF_TEST(TestNegativeBlurSigma, reporter) {
363 SkBitmap temp;
364 temp.allocN32Pixels(100, 100);
365 SkBitmapDevice device(temp);
366 test_negative_blur_sigma(&device, reporter);
367}
368
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +0000369DEF_TEST(ImageFilterDrawTiled, reporter) {
370 // Check that all filters when drawn tiled (with subsequent clip rects) exactly
371 // match the same filters drawn with a single full-canvas bitmap draw.
372 // Tests pass by not asserting.
373
374 SkAutoTUnref<SkColorFilter> cf(SkColorFilter::CreateModeFilter(SK_ColorRED, SkXfermode::kSrcIn_Mode));
375 SkPoint3 location(0, 0, SK_Scalar1);
376 SkPoint3 target(SK_Scalar1, SK_Scalar1, SK_Scalar1);
377 SkScalar kernel[9] = {
378 SkIntToScalar( 1), SkIntToScalar( 1), SkIntToScalar( 1),
379 SkIntToScalar( 1), SkIntToScalar(-7), SkIntToScalar( 1),
380 SkIntToScalar( 1), SkIntToScalar( 1), SkIntToScalar( 1),
381 };
382 SkISize kernelSize = SkISize::Make(3, 3);
383 SkScalar gain = SK_Scalar1, bias = 0;
senorblanco@chromium.org29ac34e2014-05-28 19:29:25 +0000384 SkScalar five = SkIntToScalar(5);
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +0000385
386 SkAutoTUnref<SkImageFilter> gradient_source(SkBitmapSource::Create(make_gradient_circle(64, 64)));
senorblanco@chromium.org29ac34e2014-05-28 19:29:25 +0000387 SkAutoTUnref<SkImageFilter> blur(SkBlurImageFilter::Create(five, five));
senorblanco@chromium.orgba31f1d2014-05-07 20:56:08 +0000388 SkMatrix matrix;
senorblanco@chromium.org29ac34e2014-05-28 19:29:25 +0000389
senorblanco@chromium.orgba31f1d2014-05-07 20:56:08 +0000390 matrix.setTranslate(SK_Scalar1, SK_Scalar1);
391 matrix.postRotate(SkIntToScalar(45), SK_Scalar1, SK_Scalar1);
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +0000392
senorblanco@chromium.org910702b2014-05-30 20:36:15 +0000393 SkRTreeFactory factory;
394 SkPictureRecorder recorder;
395 SkCanvas* recordingCanvas = recorder.beginRecording(64, 64, &factory, 0);
396
397 SkPaint greenPaint;
398 greenPaint.setColor(SK_ColorGREEN);
399 recordingCanvas->drawRect(SkRect::Make(SkIRect::MakeXYWH(10, 10, 30, 20)), greenPaint);
400 SkAutoTUnref<SkPicture> picture(recorder.endRecording());
401 SkAutoTUnref<SkImageFilter> pictureFilter(SkPictureImageFilter::Create(picture.get()));
402
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +0000403 struct {
404 const char* fName;
405 SkImageFilter* fFilter;
406 } filters[] = {
407 { "color filter", SkColorFilterImageFilter::Create(cf.get()) },
408 { "displacement map", SkDisplacementMapEffect::Create(
409 SkDisplacementMapEffect::kR_ChannelSelectorType,
410 SkDisplacementMapEffect::kB_ChannelSelectorType,
senorblanco@chromium.orgd4db6572014-05-07 20:00:04 +0000411 20.0f, gradient_source.get()) },
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +0000412 { "blur", SkBlurImageFilter::Create(SK_Scalar1, SK_Scalar1) },
413 { "drop shadow", SkDropShadowImageFilter::Create(
sugoi234f0362014-10-23 13:59:52 -0700414 SK_Scalar1, SK_Scalar1, SK_Scalar1, SK_Scalar1, SK_ColorGREEN,
415 SkDropShadowImageFilter::kDrawShadowAndForeground_ShadowMode) },
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +0000416 { "diffuse lighting", SkLightingImageFilter::CreatePointLitDiffuse(
417 location, SK_ColorGREEN, 0, 0) },
418 { "specular lighting",
419 SkLightingImageFilter::CreatePointLitSpecular(location, SK_ColorGREEN, 0, 0, 0) },
420 { "matrix convolution",
421 SkMatrixConvolutionImageFilter::Create(
422 kernelSize, kernel, gain, bias, SkIPoint::Make(1, 1),
423 SkMatrixConvolutionImageFilter::kRepeat_TileMode, false) },
424 { "merge", SkMergeImageFilter::Create(NULL, NULL, SkXfermode::kSrcOver_Mode) },
425 { "offset", SkOffsetImageFilter::Create(SK_Scalar1, SK_Scalar1) },
426 { "dilate", SkDilateImageFilter::Create(3, 2) },
427 { "erode", SkErodeImageFilter::Create(2, 3) },
428 { "tile", SkTileImageFilter::Create(SkRect::MakeXYWH(0, 0, 50, 50),
429 SkRect::MakeXYWH(0, 0, 100, 100), NULL) },
senorblanco@chromium.orgba31f1d2014-05-07 20:56:08 +0000430 { "matrix", SkMatrixImageFilter::Create(matrix, SkPaint::kLow_FilterLevel) },
senorblanco@chromium.org29ac34e2014-05-28 19:29:25 +0000431 { "blur and offset", SkOffsetImageFilter::Create(five, five, blur.get()) },
senorblanco@chromium.org910702b2014-05-30 20:36:15 +0000432 { "picture and blur", SkBlurImageFilter::Create(five, five, pictureFilter.get()) },
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +0000433 };
434
435 SkBitmap untiledResult, tiledResult;
436 int width = 64, height = 64;
437 untiledResult.allocN32Pixels(width, height);
438 tiledResult.allocN32Pixels(width, height);
439 SkCanvas tiledCanvas(tiledResult);
440 SkCanvas untiledCanvas(untiledResult);
senorblanco@chromium.orgd4db6572014-05-07 20:00:04 +0000441 int tileSize = 8;
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +0000442
senorblanco@chromium.orgd4db6572014-05-07 20:00:04 +0000443 for (int scale = 1; scale <= 2; ++scale) {
444 for (size_t i = 0; i < SK_ARRAY_COUNT(filters); ++i) {
445 tiledCanvas.clear(0);
446 untiledCanvas.clear(0);
447 SkPaint paint;
448 paint.setImageFilter(filters[i].fFilter);
449 paint.setTextSize(SkIntToScalar(height));
450 paint.setColor(SK_ColorWHITE);
451 SkString str;
452 const char* text = "ABC";
453 SkScalar ypos = SkIntToScalar(height);
454 untiledCanvas.save();
455 untiledCanvas.scale(SkIntToScalar(scale), SkIntToScalar(scale));
456 untiledCanvas.drawText(text, strlen(text), 0, ypos, paint);
457 untiledCanvas.restore();
458 for (int y = 0; y < height; y += tileSize) {
459 for (int x = 0; x < width; x += tileSize) {
460 tiledCanvas.save();
461 tiledCanvas.clipRect(SkRect::Make(SkIRect::MakeXYWH(x, y, tileSize, tileSize)));
462 tiledCanvas.scale(SkIntToScalar(scale), SkIntToScalar(scale));
463 tiledCanvas.drawText(text, strlen(text), 0, ypos, paint);
464 tiledCanvas.restore();
465 }
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +0000466 }
senorblanco@chromium.orgd4db6572014-05-07 20:00:04 +0000467 untiledCanvas.flush();
468 tiledCanvas.flush();
469 for (int y = 0; y < height; y++) {
470 int diffs = memcmp(untiledResult.getAddr32(0, y), tiledResult.getAddr32(0, y), untiledResult.rowBytes());
471 REPORTER_ASSERT_MESSAGE(reporter, !diffs, filters[i].fName);
472 if (diffs) {
473 break;
474 }
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +0000475 }
476 }
477 }
478
479 for (size_t i = 0; i < SK_ARRAY_COUNT(filters); ++i) {
480 SkSafeUnref(filters[i].fFilter);
481 }
482}
483
robertphillipsa8d7f0b2014-08-29 08:03:56 -0700484static void draw_saveLayer_picture(int width, int height, int tileSize,
485 SkBBHFactory* factory, SkBitmap* result) {
mtkleind910f542014-08-22 09:06:34 -0700486
487 SkMatrix matrix;
488 matrix.setTranslate(SkIntToScalar(50), 0);
489
490 SkAutoTUnref<SkColorFilter> cf(SkColorFilter::CreateModeFilter(SK_ColorWHITE, SkXfermode::kSrc_Mode));
491 SkAutoTUnref<SkImageFilter> cfif(SkColorFilterImageFilter::Create(cf.get()));
492 SkAutoTUnref<SkImageFilter> imageFilter(SkMatrixImageFilter::Create(matrix, SkPaint::kNone_FilterLevel, cfif.get()));
493
494 SkPaint paint;
495 paint.setImageFilter(imageFilter.get());
496 SkPictureRecorder recorder;
497 SkRect bounds = SkRect::Make(SkIRect::MakeXYWH(0, 0, 50, 50));
robertphillipsa8d7f0b2014-08-29 08:03:56 -0700498 SkCanvas* recordingCanvas = recorder.beginRecording(SkIntToScalar(width),
499 SkIntToScalar(height),
500 factory, 0);
mtkleind910f542014-08-22 09:06:34 -0700501 recordingCanvas->translate(-55, 0);
502 recordingCanvas->saveLayer(&bounds, &paint);
503 recordingCanvas->restore();
504 SkAutoTUnref<SkPicture> picture1(recorder.endRecording());
505
506 result->allocN32Pixels(width, height);
507 SkCanvas canvas(*result);
508 canvas.clear(0);
509 canvas.clipRect(SkRect::Make(SkIRect::MakeWH(tileSize, tileSize)));
510 canvas.drawPicture(picture1.get());
511}
512
513DEF_TEST(ImageFilterDrawMatrixBBH, reporter) {
514 // Check that matrix filter when drawn tiled with BBH exactly
515 // matches the same thing drawn without BBH.
516 // Tests pass by not asserting.
517
518 const int width = 200, height = 200;
519 const int tileSize = 100;
520 SkBitmap result1, result2;
521 SkRTreeFactory factory;
522
robertphillipsa8d7f0b2014-08-29 08:03:56 -0700523 draw_saveLayer_picture(width, height, tileSize, &factory, &result1);
524 draw_saveLayer_picture(width, height, tileSize, NULL, &result2);
mtkleind910f542014-08-22 09:06:34 -0700525
526 for (int y = 0; y < height; y++) {
527 int diffs = memcmp(result1.getAddr32(0, y), result2.getAddr32(0, y), result1.rowBytes());
528 REPORTER_ASSERT(reporter, !diffs);
529 if (diffs) {
530 break;
531 }
532 }
533}
534
senorblanco1150a6d2014-08-25 12:46:58 -0700535static SkImageFilter* makeBlur(SkImageFilter* input = NULL) {
536 return SkBlurImageFilter::Create(SK_Scalar1, SK_Scalar1, input);
537}
538
539static SkImageFilter* makeDropShadow(SkImageFilter* input = NULL) {
540 return SkDropShadowImageFilter::Create(
541 SkIntToScalar(100), SkIntToScalar(100),
542 SkIntToScalar(10), SkIntToScalar(10),
sugoi234f0362014-10-23 13:59:52 -0700543 SK_ColorBLUE, SkDropShadowImageFilter::kDrawShadowAndForeground_ShadowMode,
544 input, NULL, 0);
senorblanco1150a6d2014-08-25 12:46:58 -0700545}
546
547DEF_TEST(ImageFilterBlurThenShadowBounds, reporter) {
548 SkAutoTUnref<SkImageFilter> filter1(makeBlur());
549 SkAutoTUnref<SkImageFilter> filter2(makeDropShadow(filter1.get()));
550
551 SkIRect bounds = SkIRect::MakeXYWH(0, 0, 100, 100);
552 SkIRect expectedBounds = SkIRect::MakeXYWH(-133, -133, 236, 236);
553 filter2->filterBounds(bounds, SkMatrix::I(), &bounds);
554
555 REPORTER_ASSERT(reporter, bounds == expectedBounds);
556}
557
558DEF_TEST(ImageFilterShadowThenBlurBounds, reporter) {
559 SkAutoTUnref<SkImageFilter> filter1(makeDropShadow());
560 SkAutoTUnref<SkImageFilter> filter2(makeBlur(filter1.get()));
561
562 SkIRect bounds = SkIRect::MakeXYWH(0, 0, 100, 100);
563 SkIRect expectedBounds = SkIRect::MakeXYWH(-133, -133, 236, 236);
564 filter2->filterBounds(bounds, SkMatrix::I(), &bounds);
565
566 REPORTER_ASSERT(reporter, bounds == expectedBounds);
567}
568
569DEF_TEST(ImageFilterDilateThenBlurBounds, reporter) {
570 SkAutoTUnref<SkImageFilter> filter1(SkDilateImageFilter::Create(2, 2));
571 SkAutoTUnref<SkImageFilter> filter2(makeDropShadow(filter1.get()));
572
573 SkIRect bounds = SkIRect::MakeXYWH(0, 0, 100, 100);
574 SkIRect expectedBounds = SkIRect::MakeXYWH(-132, -132, 234, 234);
575 filter2->filterBounds(bounds, SkMatrix::I(), &bounds);
576
577 REPORTER_ASSERT(reporter, bounds == expectedBounds);
578}
579
robertphillipsa8d7f0b2014-08-29 08:03:56 -0700580static void draw_blurred_rect(SkCanvas* canvas) {
senorblanco837f5322014-07-14 10:19:54 -0700581 SkAutoTUnref<SkImageFilter> filter(SkBlurImageFilter::Create(SkIntToScalar(8), 0));
582 SkPaint filterPaint;
583 filterPaint.setColor(SK_ColorWHITE);
584 filterPaint.setImageFilter(filter);
585 canvas->saveLayer(NULL, &filterPaint);
586 SkPaint whitePaint;
587 whitePaint.setColor(SK_ColorWHITE);
588 canvas->drawRect(SkRect::Make(SkIRect::MakeWH(4, 4)), whitePaint);
589 canvas->restore();
590}
591
robertphillipsa8d7f0b2014-08-29 08:03:56 -0700592static void draw_picture_clipped(SkCanvas* canvas, const SkRect& clipRect, const SkPicture* picture) {
senorblanco837f5322014-07-14 10:19:54 -0700593 canvas->save();
594 canvas->clipRect(clipRect);
595 canvas->drawPicture(picture);
596 canvas->restore();
597}
598
599DEF_TEST(ImageFilterDrawTiledBlurRTree, reporter) {
600 // Check that the blur filter when recorded with RTree acceleration,
601 // and drawn tiled (with subsequent clip rects) exactly
602 // matches the same filter drawn with without RTree acceleration.
603 // This tests that the "bleed" from the blur into the otherwise-blank
604 // tiles is correctly rendered.
605 // Tests pass by not asserting.
606
607 int width = 16, height = 8;
608 SkBitmap result1, result2;
609 result1.allocN32Pixels(width, height);
610 result2.allocN32Pixels(width, height);
611 SkCanvas canvas1(result1);
612 SkCanvas canvas2(result2);
613 int tileSize = 8;
614
615 canvas1.clear(0);
616 canvas2.clear(0);
617
618 SkRTreeFactory factory;
619
620 SkPictureRecorder recorder1, recorder2;
621 // The only difference between these two pictures is that one has RTree aceleration.
robertphillipsa8d7f0b2014-08-29 08:03:56 -0700622 SkCanvas* recordingCanvas1 = recorder1.beginRecording(SkIntToScalar(width),
623 SkIntToScalar(height),
624 NULL, 0);
625 SkCanvas* recordingCanvas2 = recorder2.beginRecording(SkIntToScalar(width),
626 SkIntToScalar(height),
627 &factory, 0);
628 draw_blurred_rect(recordingCanvas1);
629 draw_blurred_rect(recordingCanvas2);
senorblanco837f5322014-07-14 10:19:54 -0700630 SkAutoTUnref<SkPicture> picture1(recorder1.endRecording());
631 SkAutoTUnref<SkPicture> picture2(recorder2.endRecording());
632 for (int y = 0; y < height; y += tileSize) {
633 for (int x = 0; x < width; x += tileSize) {
634 SkRect tileRect = SkRect::Make(SkIRect::MakeXYWH(x, y, tileSize, tileSize));
robertphillipsa8d7f0b2014-08-29 08:03:56 -0700635 draw_picture_clipped(&canvas1, tileRect, picture1);
636 draw_picture_clipped(&canvas2, tileRect, picture2);
senorblanco837f5322014-07-14 10:19:54 -0700637 }
638 }
639 for (int y = 0; y < height; y++) {
640 int diffs = memcmp(result1.getAddr32(0, y), result2.getAddr32(0, y), result1.rowBytes());
641 REPORTER_ASSERT(reporter, !diffs);
642 if (diffs) {
643 break;
644 }
645 }
646}
647
senorblanco@chromium.org91957432014-05-01 14:03:41 +0000648DEF_TEST(ImageFilterMatrixConvolution, reporter) {
649 // Check that a 1x3 filter does not cause a spurious assert.
650 SkScalar kernel[3] = {
651 SkIntToScalar( 1), SkIntToScalar( 1), SkIntToScalar( 1),
652 };
653 SkISize kernelSize = SkISize::Make(1, 3);
654 SkScalar gain = SK_Scalar1, bias = 0;
655 SkIPoint kernelOffset = SkIPoint::Make(0, 0);
656
657 SkAutoTUnref<SkImageFilter> filter(
658 SkMatrixConvolutionImageFilter::Create(
659 kernelSize, kernel, gain, bias, kernelOffset,
660 SkMatrixConvolutionImageFilter::kRepeat_TileMode, false));
661
662 SkBitmap result;
663 int width = 16, height = 16;
664 result.allocN32Pixels(width, height);
665 SkCanvas canvas(result);
666 canvas.clear(0);
667
668 SkPaint paint;
669 paint.setImageFilter(filter);
670 SkRect rect = SkRect::Make(SkIRect::MakeWH(width, height));
671 canvas.drawRect(rect, paint);
672}
673
senorblanco@chromium.org8c7372b2014-05-02 19:13:11 +0000674DEF_TEST(ImageFilterMatrixConvolutionBorder, reporter) {
675 // Check that a filter with borders outside the target bounds
676 // does not crash.
677 SkScalar kernel[3] = {
678 0, 0, 0,
679 };
680 SkISize kernelSize = SkISize::Make(3, 1);
681 SkScalar gain = SK_Scalar1, bias = 0;
682 SkIPoint kernelOffset = SkIPoint::Make(2, 0);
683
684 SkAutoTUnref<SkImageFilter> filter(
685 SkMatrixConvolutionImageFilter::Create(
686 kernelSize, kernel, gain, bias, kernelOffset,
687 SkMatrixConvolutionImageFilter::kClamp_TileMode, true));
688
689 SkBitmap result;
690
691 int width = 10, height = 10;
692 result.allocN32Pixels(width, height);
693 SkCanvas canvas(result);
694 canvas.clear(0);
695
696 SkPaint filterPaint;
697 filterPaint.setImageFilter(filter);
698 SkRect bounds = SkRect::MakeWH(1, 10);
699 SkRect rect = SkRect::Make(SkIRect::MakeWH(width, height));
700 SkPaint rectPaint;
701 canvas.saveLayer(&bounds, &filterPaint);
702 canvas.drawRect(rect, rectPaint);
703 canvas.restore();
704}
705
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +0000706DEF_TEST(ImageFilterCropRect, reporter) {
707 SkBitmap temp;
mike@reedtribe.orgdeee4962014-02-13 14:41:43 +0000708 temp.allocN32Pixels(100, 100);
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +0000709 SkBitmapDevice device(temp);
710 test_crop_rects(&device, reporter);
711}
712
tfarina9ea53f92014-06-24 06:50:39 -0700713DEF_TEST(ImageFilterMatrix, reporter) {
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +0000714 SkBitmap temp;
mike@reedtribe.orgdeee4962014-02-13 14:41:43 +0000715 temp.allocN32Pixels(100, 100);
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +0000716 SkBitmapDevice device(temp);
717 SkCanvas canvas(&device);
718 canvas.scale(SkIntToScalar(2), SkIntToScalar(2));
719
720 SkMatrix expectedMatrix = canvas.getTotalMatrix();
721
commit-bot@chromium.org5fb2ce32014-04-17 23:35:06 +0000722 SkRTreeFactory factory;
723 SkPictureRecorder recorder;
724 SkCanvas* recordingCanvas = recorder.beginRecording(100, 100, &factory, 0);
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +0000725
726 SkPaint paint;
727 SkAutoTUnref<MatrixTestImageFilter> imageFilter(
728 new MatrixTestImageFilter(reporter, expectedMatrix));
729 paint.setImageFilter(imageFilter.get());
commit-bot@chromium.org091a5942014-04-18 14:19:31 +0000730 recordingCanvas->saveLayer(NULL, &paint);
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +0000731 SkPaint solidPaint;
732 solidPaint.setColor(0xFFFFFFFF);
733 recordingCanvas->save();
734 recordingCanvas->scale(SkIntToScalar(10), SkIntToScalar(10));
735 recordingCanvas->drawRect(SkRect::Make(SkIRect::MakeWH(100, 100)), solidPaint);
736 recordingCanvas->restore(); // scale
737 recordingCanvas->restore(); // saveLayer
robertphillips@google.com84b18c72014-04-13 19:09:42 +0000738 SkAutoTUnref<SkPicture> picture(recorder.endRecording());
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +0000739
robertphillips9b14f262014-06-04 05:40:44 -0700740 canvas.drawPicture(picture);
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +0000741}
742
senorblanco3d822c22014-07-30 14:49:31 -0700743DEF_TEST(ImageFilterCrossProcessPictureImageFilter, reporter) {
senorblanco@chromium.org97f5fc62014-05-30 20:50:56 +0000744 SkRTreeFactory factory;
745 SkPictureRecorder recorder;
746 SkCanvas* recordingCanvas = recorder.beginRecording(1, 1, &factory, 0);
747
748 // Create an SkPicture which simply draws a green 1x1 rectangle.
749 SkPaint greenPaint;
750 greenPaint.setColor(SK_ColorGREEN);
751 recordingCanvas->drawRect(SkRect::Make(SkIRect::MakeWH(1, 1)), greenPaint);
752 SkAutoTUnref<SkPicture> picture(recorder.endRecording());
753
754 // Wrap that SkPicture in an SkPictureImageFilter.
755 SkAutoTUnref<SkImageFilter> imageFilter(
756 SkPictureImageFilter::Create(picture.get()));
757
758 // Check that SkPictureImageFilter successfully serializes its contained
759 // SkPicture when not in cross-process mode.
760 SkPaint paint;
761 paint.setImageFilter(imageFilter.get());
762 SkPictureRecorder outerRecorder;
763 SkCanvas* outerCanvas = outerRecorder.beginRecording(1, 1, &factory, 0);
764 SkPaint redPaintWithFilter;
765 redPaintWithFilter.setColor(SK_ColorRED);
766 redPaintWithFilter.setImageFilter(imageFilter.get());
767 outerCanvas->drawRect(SkRect::Make(SkIRect::MakeWH(1, 1)), redPaintWithFilter);
768 SkAutoTUnref<SkPicture> outerPicture(outerRecorder.endRecording());
769
770 SkBitmap bitmap;
771 bitmap.allocN32Pixels(1, 1);
772 SkBitmapDevice device(bitmap);
773 SkCanvas canvas(&device);
774
775 // The result here should be green, since the filter replaces the primitive's red interior.
776 canvas.clear(0x0);
robertphillips9b14f262014-06-04 05:40:44 -0700777 canvas.drawPicture(outerPicture);
senorblanco@chromium.org97f5fc62014-05-30 20:50:56 +0000778 uint32_t pixel = *bitmap.getAddr32(0, 0);
779 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
780
781 // Check that, for now, SkPictureImageFilter does not serialize or
782 // deserialize its contained picture when the filter is serialized
783 // cross-process. Do this by "laundering" it through SkValidatingReadBuffer.
784 SkAutoTUnref<SkData> data(SkValidatingSerializeFlattenable(imageFilter.get()));
785 SkAutoTUnref<SkFlattenable> flattenable(SkValidatingDeserializeFlattenable(
786 data->data(), data->size(), SkImageFilter::GetFlattenableType()));
787 SkImageFilter* unflattenedFilter = static_cast<SkImageFilter*>(flattenable.get());
788
789 redPaintWithFilter.setImageFilter(unflattenedFilter);
790 SkPictureRecorder crossProcessRecorder;
791 SkCanvas* crossProcessCanvas = crossProcessRecorder.beginRecording(1, 1, &factory, 0);
792 crossProcessCanvas->drawRect(SkRect::Make(SkIRect::MakeWH(1, 1)), redPaintWithFilter);
793 SkAutoTUnref<SkPicture> crossProcessPicture(crossProcessRecorder.endRecording());
794
795 canvas.clear(0x0);
robertphillips9b14f262014-06-04 05:40:44 -0700796 canvas.drawPicture(crossProcessPicture);
senorblanco@chromium.org97f5fc62014-05-30 20:50:56 +0000797 pixel = *bitmap.getAddr32(0, 0);
798 // The result here should not be green, since the filter draws nothing.
799 REPORTER_ASSERT(reporter, pixel != SK_ColorGREEN);
800}
801
senorblanco3d822c22014-07-30 14:49:31 -0700802DEF_TEST(ImageFilterClippedPictureImageFilter, reporter) {
803 SkRTreeFactory factory;
804 SkPictureRecorder recorder;
805 SkCanvas* recordingCanvas = recorder.beginRecording(1, 1, &factory, 0);
806
807 // Create an SkPicture which simply draws a green 1x1 rectangle.
808 SkPaint greenPaint;
809 greenPaint.setColor(SK_ColorGREEN);
810 recordingCanvas->drawRect(SkRect::Make(SkIRect::MakeWH(1, 1)), greenPaint);
811 SkAutoTUnref<SkPicture> picture(recorder.endRecording());
812
813 SkAutoTUnref<SkImageFilter> imageFilter(
814 SkPictureImageFilter::Create(picture.get()));
815
816 SkBitmap result;
817 SkIPoint offset;
818 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeXYWH(1, 1, 1, 1), NULL);
819 SkBitmap bitmap;
820 bitmap.allocN32Pixels(2, 2);
821 SkBitmapDevice device(bitmap);
822 SkDeviceImageFilterProxy proxy(&device);
823 REPORTER_ASSERT(reporter, !imageFilter->filterImage(&proxy, bitmap, ctx, &result, &offset));
824}
825
tfarina9ea53f92014-06-24 06:50:39 -0700826DEF_TEST(ImageFilterEmptySaveLayer, reporter) {
senorblanco@chromium.org68250c82014-05-06 22:52:55 +0000827 // Even when there's an empty saveLayer()/restore(), ensure that an image
828 // filter or color filter which affects transparent black still draws.
829
830 SkBitmap bitmap;
831 bitmap.allocN32Pixels(10, 10);
832 SkBitmapDevice device(bitmap);
833 SkCanvas canvas(&device);
834
835 SkRTreeFactory factory;
836 SkPictureRecorder recorder;
837
838 SkAutoTUnref<SkColorFilter> green(
839 SkColorFilter::CreateModeFilter(SK_ColorGREEN, SkXfermode::kSrc_Mode));
840 SkAutoTUnref<SkColorFilterImageFilter> imageFilter(
841 SkColorFilterImageFilter::Create(green.get()));
842 SkPaint imageFilterPaint;
843 imageFilterPaint.setImageFilter(imageFilter.get());
844 SkPaint colorFilterPaint;
845 colorFilterPaint.setColorFilter(green.get());
846
847 SkRect bounds = SkRect::MakeWH(10, 10);
848
849 SkCanvas* recordingCanvas = recorder.beginRecording(10, 10, &factory, 0);
850 recordingCanvas->saveLayer(&bounds, &imageFilterPaint);
851 recordingCanvas->restore();
852 SkAutoTUnref<SkPicture> picture(recorder.endRecording());
853
854 canvas.clear(0);
robertphillips9b14f262014-06-04 05:40:44 -0700855 canvas.drawPicture(picture);
senorblanco@chromium.org68250c82014-05-06 22:52:55 +0000856 uint32_t pixel = *bitmap.getAddr32(0, 0);
857 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
858
859 recordingCanvas = recorder.beginRecording(10, 10, &factory, 0);
860 recordingCanvas->saveLayer(NULL, &imageFilterPaint);
861 recordingCanvas->restore();
862 SkAutoTUnref<SkPicture> picture2(recorder.endRecording());
863
864 canvas.clear(0);
robertphillips9b14f262014-06-04 05:40:44 -0700865 canvas.drawPicture(picture2);
senorblanco@chromium.org68250c82014-05-06 22:52:55 +0000866 pixel = *bitmap.getAddr32(0, 0);
867 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
868
869 recordingCanvas = recorder.beginRecording(10, 10, &factory, 0);
870 recordingCanvas->saveLayer(&bounds, &colorFilterPaint);
871 recordingCanvas->restore();
872 SkAutoTUnref<SkPicture> picture3(recorder.endRecording());
873
874 canvas.clear(0);
robertphillips9b14f262014-06-04 05:40:44 -0700875 canvas.drawPicture(picture3);
senorblanco@chromium.org68250c82014-05-06 22:52:55 +0000876 pixel = *bitmap.getAddr32(0, 0);
877 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
878}
879
senorblanco@chromium.org28ae55d2014-03-24 21:32:28 +0000880static void test_huge_blur(SkBaseDevice* device, skiatest::Reporter* reporter) {
senorblanco@chromium.org09843fd2014-03-24 20:50:59 +0000881 SkCanvas canvas(device);
882
883 SkBitmap bitmap;
884 bitmap.allocN32Pixels(100, 100);
885 bitmap.eraseARGB(0, 0, 0, 0);
886
887 // Check that a blur with an insane radius does not crash or assert.
888 SkAutoTUnref<SkImageFilter> blur(SkBlurImageFilter::Create(SkIntToScalar(1<<30), SkIntToScalar(1<<30)));
889
890 SkPaint paint;
891 paint.setImageFilter(blur);
892 canvas.drawSprite(bitmap, 0, 0, &paint);
893}
894
895DEF_TEST(HugeBlurImageFilter, reporter) {
896 SkBitmap temp;
897 temp.allocN32Pixels(100, 100);
898 SkBitmapDevice device(temp);
899 test_huge_blur(&device, reporter);
900}
901
senorblanco3a495202014-09-29 07:57:20 -0700902DEF_TEST(MatrixConvolutionSanityTest, reporter) {
903 SkScalar kernel[1] = { 0 };
904 SkScalar gain = SK_Scalar1, bias = 0;
905 SkIPoint kernelOffset = SkIPoint::Make(1, 1);
906
907 // Check that an enormous (non-allocatable) kernel gives a NULL filter.
908 SkAutoTUnref<SkImageFilter> conv(SkMatrixConvolutionImageFilter::Create(
909 SkISize::Make(1<<30, 1<<30),
910 kernel,
911 gain,
912 bias,
913 kernelOffset,
914 SkMatrixConvolutionImageFilter::kRepeat_TileMode,
915 false));
916
917 REPORTER_ASSERT(reporter, NULL == conv.get());
918
919 // Check that a NULL kernel gives a NULL filter.
920 conv.reset(SkMatrixConvolutionImageFilter::Create(
921 SkISize::Make(1, 1),
922 NULL,
923 gain,
924 bias,
925 kernelOffset,
926 SkMatrixConvolutionImageFilter::kRepeat_TileMode,
927 false));
928
929 REPORTER_ASSERT(reporter, NULL == conv.get());
930
931 // Check that a kernel width < 1 gives a NULL filter.
932 conv.reset(SkMatrixConvolutionImageFilter::Create(
933 SkISize::Make(0, 1),
934 kernel,
935 gain,
936 bias,
937 kernelOffset,
938 SkMatrixConvolutionImageFilter::kRepeat_TileMode,
939 false));
940
941 REPORTER_ASSERT(reporter, NULL == conv.get());
942
943 // Check that kernel height < 1 gives a NULL filter.
944 conv.reset(SkMatrixConvolutionImageFilter::Create(
945 SkISize::Make(1, -1),
946 kernel,
947 gain,
948 bias,
949 kernelOffset,
950 SkMatrixConvolutionImageFilter::kRepeat_TileMode,
951 false));
952
953 REPORTER_ASSERT(reporter, NULL == conv.get());
954}
955
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +0000956static void test_xfermode_cropped_input(SkBaseDevice* device, skiatest::Reporter* reporter) {
957 SkCanvas canvas(device);
958 canvas.clear(0);
959
960 SkBitmap bitmap;
961 bitmap.allocN32Pixels(1, 1);
962 bitmap.eraseARGB(255, 255, 255, 255);
963
964 SkAutoTUnref<SkColorFilter> green(
965 SkColorFilter::CreateModeFilter(SK_ColorGREEN, SkXfermode::kSrcIn_Mode));
966 SkAutoTUnref<SkColorFilterImageFilter> greenFilter(
967 SkColorFilterImageFilter::Create(green.get()));
968 SkImageFilter::CropRect cropRect(SkRect::MakeEmpty());
969 SkAutoTUnref<SkColorFilterImageFilter> croppedOut(
970 SkColorFilterImageFilter::Create(green.get(), NULL, &cropRect));
971
972 // Check that an xfermode image filter whose input has been cropped out still draws the other
973 // input. Also check that drawing with both inputs cropped out doesn't cause a GPU warning.
974 SkXfermode* mode = SkXfermode::Create(SkXfermode::kSrcOver_Mode);
975 SkAutoTUnref<SkImageFilter> xfermodeNoFg(
976 SkXfermodeImageFilter::Create(mode, greenFilter, croppedOut));
977 SkAutoTUnref<SkImageFilter> xfermodeNoBg(
978 SkXfermodeImageFilter::Create(mode, croppedOut, greenFilter));
979 SkAutoTUnref<SkImageFilter> xfermodeNoFgNoBg(
980 SkXfermodeImageFilter::Create(mode, croppedOut, croppedOut));
981
982 SkPaint paint;
983 paint.setImageFilter(xfermodeNoFg);
984 canvas.drawSprite(bitmap, 0, 0, &paint);
985
986 uint32_t pixel;
987 SkImageInfo info = SkImageInfo::MakeN32Premul(1, 1);
988 canvas.readPixels(info, &pixel, 4, 0, 0);
989 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
990
991 paint.setImageFilter(xfermodeNoBg);
992 canvas.drawSprite(bitmap, 0, 0, &paint);
993 canvas.readPixels(info, &pixel, 4, 0, 0);
994 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
995
996 paint.setImageFilter(xfermodeNoFgNoBg);
997 canvas.drawSprite(bitmap, 0, 0, &paint);
998 canvas.readPixels(info, &pixel, 4, 0, 0);
999 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1000}
1001
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001002DEF_TEST(ImageFilterNestedSaveLayer, reporter) {
1003 SkBitmap temp;
1004 temp.allocN32Pixels(50, 50);
1005 SkBitmapDevice device(temp);
1006 SkCanvas canvas(&device);
1007 canvas.clear(0x0);
1008
1009 SkBitmap bitmap;
1010 bitmap.allocN32Pixels(10, 10);
1011 bitmap.eraseColor(SK_ColorGREEN);
1012
1013 SkMatrix matrix;
1014 matrix.setScale(SkIntToScalar(2), SkIntToScalar(2));
1015 matrix.postTranslate(SkIntToScalar(-20), SkIntToScalar(-20));
1016 SkAutoTUnref<SkImageFilter> matrixFilter(
1017 SkMatrixImageFilter::Create(matrix, SkPaint::kLow_FilterLevel));
1018
1019 // Test that saveLayer() with a filter nested inside another saveLayer() applies the
1020 // correct offset to the filter matrix.
1021 SkRect bounds1 = SkRect::MakeXYWH(10, 10, 30, 30);
1022 canvas.saveLayer(&bounds1, NULL);
1023 SkPaint filterPaint;
1024 filterPaint.setImageFilter(matrixFilter);
1025 SkRect bounds2 = SkRect::MakeXYWH(20, 20, 10, 10);
1026 canvas.saveLayer(&bounds2, &filterPaint);
1027 SkPaint greenPaint;
1028 greenPaint.setColor(SK_ColorGREEN);
1029 canvas.drawRect(bounds2, greenPaint);
1030 canvas.restore();
1031 canvas.restore();
1032 SkPaint strokePaint;
1033 strokePaint.setStyle(SkPaint::kStroke_Style);
1034 strokePaint.setColor(SK_ColorRED);
1035
1036 SkImageInfo info = SkImageInfo::MakeN32Premul(1, 1);
1037 uint32_t pixel;
1038 canvas.readPixels(info, &pixel, 4, 25, 25);
1039 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1040
1041 // Test that drawSprite() with a filter nested inside a saveLayer() applies the
1042 // correct offset to the filter matrix.
1043 canvas.clear(0x0);
1044 canvas.readPixels(info, &pixel, 4, 25, 25);
1045 canvas.saveLayer(&bounds1, NULL);
1046 canvas.drawSprite(bitmap, 20, 20, &filterPaint);
1047 canvas.restore();
1048
1049 canvas.readPixels(info, &pixel, 4, 25, 25);
1050 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1051}
1052
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001053DEF_TEST(XfermodeImageFilterCroppedInput, reporter) {
1054 SkBitmap temp;
1055 temp.allocN32Pixels(100, 100);
1056 SkBitmapDevice device(temp);
1057 test_xfermode_cropped_input(&device, reporter);
1058}
senorblanco@chromium.org09843fd2014-03-24 20:50:59 +00001059
senorblanco@chromium.org58d14662014-02-03 22:36:39 +00001060#if SK_SUPPORT_GPU
reed4a8126e2014-09-22 07:29:03 -07001061const SkSurfaceProps gProps = SkSurfaceProps(SkSurfaceProps::kLegacyFontHost_InitType);
1062
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +00001063DEF_GPUTEST(ImageFilterCropRectGPU, reporter, factory) {
1064 GrContext* context = factory->get(static_cast<GrContextFactory::GLContextType>(0));
commit-bot@chromium.org15a14052014-02-16 00:59:25 +00001065 SkAutoTUnref<SkGpuDevice> device(SkGpuDevice::Create(context,
1066 SkImageInfo::MakeN32Premul(100, 100),
reed4a8126e2014-09-22 07:29:03 -07001067 gProps,
commit-bot@chromium.org15a14052014-02-16 00:59:25 +00001068 0));
1069 test_crop_rects(device, reporter);
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +00001070}
senorblanco@chromium.org09843fd2014-03-24 20:50:59 +00001071
1072DEF_GPUTEST(HugeBlurImageFilterGPU, reporter, factory) {
1073 GrContext* context = factory->get(static_cast<GrContextFactory::GLContextType>(0));
1074 SkAutoTUnref<SkGpuDevice> device(SkGpuDevice::Create(context,
1075 SkImageInfo::MakeN32Premul(100, 100),
reed4a8126e2014-09-22 07:29:03 -07001076 gProps,
senorblanco@chromium.org09843fd2014-03-24 20:50:59 +00001077 0));
1078 test_huge_blur(device, reporter);
1079}
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001080
1081DEF_GPUTEST(XfermodeImageFilterCroppedInputGPU, reporter, factory) {
1082 GrContext* context = factory->get(static_cast<GrContextFactory::GLContextType>(0));
1083 SkAutoTUnref<SkGpuDevice> device(SkGpuDevice::Create(context,
1084 SkImageInfo::MakeN32Premul(1, 1),
reed4a8126e2014-09-22 07:29:03 -07001085 gProps,
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001086 0));
1087 test_xfermode_cropped_input(device, reporter);
1088}
senorblanco32673b92014-09-09 09:15:04 -07001089
1090DEF_GPUTEST(TestNegativeBlurSigmaGPU, reporter, factory) {
1091 GrContext* context = factory->get(static_cast<GrContextFactory::GLContextType>(0));
1092 SkAutoTUnref<SkGpuDevice> device(SkGpuDevice::Create(context,
1093 SkImageInfo::MakeN32Premul(1, 1),
reed4a8126e2014-09-22 07:29:03 -07001094 gProps,
senorblanco32673b92014-09-09 09:15:04 -07001095 0));
1096 test_negative_blur_sigma(device, reporter);
1097}
senorblanco@chromium.org58d14662014-02-03 22:36:39 +00001098#endif