blob: dc3533259390457157ff4199ce64a055c02d784e [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"
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.org6776b822014-01-03 21:48:22 +000022#include "SkMergeImageFilter.h"
23#include "SkMorphologyImageFilter.h"
senorblanco@chromium.org6776b822014-01-03 21:48:22 +000024#include "SkOffsetImageFilter.h"
senorblanco8f3937d2014-10-29 12:36:32 -070025#include "SkPerlinNoiseShader.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"
senorblanco8f3937d2014-10-29 12:36:32 -070031#include "SkRectShaderImageFilter.h"
senorblanco@chromium.org6776b822014-01-03 21:48:22 +000032#include "SkTileImageFilter.h"
33#include "SkXfermodeImageFilter.h"
tfarina@chromium.org8f6884a2014-01-24 20:56:26 +000034#include "Test.h"
senorblanco@chromium.org194d7752013-07-24 22:19:24 +000035
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +000036#if SK_SUPPORT_GPU
37#include "GrContextFactory.h"
38#include "SkGpuDevice.h"
39#endif
40
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +000041static const int kBitmapSize = 4;
commit-bot@chromium.org4b681bc2013-09-13 12:40:02 +000042
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +000043namespace {
44
45class MatrixTestImageFilter : public SkImageFilter {
46public:
47 MatrixTestImageFilter(skiatest::Reporter* reporter, const SkMatrix& expectedMatrix)
senorblanco9ea3d572014-07-08 09:16:22 -070048 : SkImageFilter(0, NULL), fReporter(reporter), fExpectedMatrix(expectedMatrix) {
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +000049 }
50
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +000051 virtual bool onFilterImage(Proxy*, const SkBitmap& src, const Context& ctx,
mtklein36352bf2015-03-25 18:17:31 -070052 SkBitmap* result, SkIPoint* offset) const override {
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +000053 REPORTER_ASSERT(fReporter, ctx.ctm() == fExpectedMatrix);
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +000054 return true;
55 }
56
robertphillipsf3f5bad2014-12-19 13:49:15 -080057 SK_TO_STRING_OVERRIDE()
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +000058 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(MatrixTestImageFilter)
59
60protected:
mtklein36352bf2015-03-25 18:17:31 -070061 void flatten(SkWriteBuffer& buffer) const override {
reed9fa60da2014-08-21 07:59:51 -070062 this->INHERITED::flatten(buffer);
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +000063 buffer.writeFunctionPtr(fReporter);
64 buffer.writeMatrix(fExpectedMatrix);
65 }
66
67private:
68 skiatest::Reporter* fReporter;
69 SkMatrix fExpectedMatrix;
mtklein3f3b3d02014-12-01 11:47:08 -080070
reed9fa60da2014-08-21 07:59:51 -070071 typedef SkImageFilter INHERITED;
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +000072};
73
74}
75
reed9fa60da2014-08-21 07:59:51 -070076SkFlattenable* MatrixTestImageFilter::CreateProc(SkReadBuffer& buffer) {
77 SK_IMAGEFILTER_UNFLATTEN_COMMON(common, 1);
78 skiatest::Reporter* reporter = (skiatest::Reporter*)buffer.readFunctionPtr();
79 SkMatrix matrix;
80 buffer.readMatrix(&matrix);
81 return SkNEW_ARGS(MatrixTestImageFilter, (reporter, matrix));
82}
83
robertphillipsf3f5bad2014-12-19 13:49:15 -080084#ifndef SK_IGNORE_TO_STRING
85void MatrixTestImageFilter::toString(SkString* str) const {
86 str->appendf("MatrixTestImageFilter: (");
87 str->append(")");
88}
89#endif
90
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +000091static void make_small_bitmap(SkBitmap& bitmap) {
mike@reedtribe.orgdeee4962014-02-13 14:41:43 +000092 bitmap.allocN32Pixels(kBitmapSize, kBitmapSize);
93 SkCanvas canvas(bitmap);
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +000094 canvas.clear(0x00000000);
95 SkPaint darkPaint;
96 darkPaint.setColor(0xFF804020);
97 SkPaint lightPaint;
98 lightPaint.setColor(0xFF244484);
99 const int i = kBitmapSize / 4;
100 for (int y = 0; y < kBitmapSize; y += i) {
101 for (int x = 0; x < kBitmapSize; x += i) {
102 canvas.save();
103 canvas.translate(SkIntToScalar(x), SkIntToScalar(y));
104 canvas.drawRect(SkRect::MakeXYWH(0, 0,
105 SkIntToScalar(i),
106 SkIntToScalar(i)), darkPaint);
107 canvas.drawRect(SkRect::MakeXYWH(SkIntToScalar(i),
108 0,
109 SkIntToScalar(i),
110 SkIntToScalar(i)), lightPaint);
111 canvas.drawRect(SkRect::MakeXYWH(0,
112 SkIntToScalar(i),
113 SkIntToScalar(i),
114 SkIntToScalar(i)), lightPaint);
115 canvas.drawRect(SkRect::MakeXYWH(SkIntToScalar(i),
116 SkIntToScalar(i),
117 SkIntToScalar(i),
118 SkIntToScalar(i)), darkPaint);
119 canvas.restore();
commit-bot@chromium.org4b681bc2013-09-13 12:40:02 +0000120 }
121 }
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000122}
senorblanco@chromium.org194d7752013-07-24 22:19:24 +0000123
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000124static SkImageFilter* make_scale(float amount, SkImageFilter* input = NULL) {
125 SkScalar s = amount;
126 SkScalar matrix[20] = { s, 0, 0, 0, 0,
127 0, s, 0, 0, 0,
128 0, 0, s, 0, 0,
129 0, 0, 0, s, 0 };
commit-bot@chromium.org727a3522014-02-21 18:46:30 +0000130 SkAutoTUnref<SkColorFilter> filter(SkColorMatrixFilter::Create(matrix));
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000131 return SkColorFilterImageFilter::Create(filter, input);
132}
133
reedcedc36f2015-03-08 04:42:52 -0700134static SkImageFilter* make_grayscale(SkImageFilter* input, const SkImageFilter::CropRect* cropRect) {
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000135 SkScalar matrix[20];
136 memset(matrix, 0, 20 * sizeof(SkScalar));
137 matrix[0] = matrix[5] = matrix[10] = 0.2126f;
138 matrix[1] = matrix[6] = matrix[11] = 0.7152f;
139 matrix[2] = matrix[7] = matrix[12] = 0.0722f;
140 matrix[18] = 1.0f;
commit-bot@chromium.org727a3522014-02-21 18:46:30 +0000141 SkAutoTUnref<SkColorFilter> filter(SkColorMatrixFilter::Create(matrix));
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000142 return SkColorFilterImageFilter::Create(filter, input, cropRect);
143}
144
reedcedc36f2015-03-08 04:42:52 -0700145static SkImageFilter* make_blue(SkImageFilter* input, const SkImageFilter::CropRect* cropRect) {
146 SkAutoTUnref<SkColorFilter> filter(SkColorFilter::CreateModeFilter(SK_ColorBLUE,
147 SkXfermode::kSrcIn_Mode));
148 return SkColorFilterImageFilter::Create(filter, input, cropRect);
149}
150
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000151DEF_TEST(ImageFilter, reporter) {
152 {
reedcedc36f2015-03-08 04:42:52 -0700153 // Check that two non-clipping color-matrice-filters concatenate into a single filter.
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000154 SkAutoTUnref<SkImageFilter> halfBrightness(make_scale(0.5f));
155 SkAutoTUnref<SkImageFilter> quarterBrightness(make_scale(0.5f, halfBrightness));
156 REPORTER_ASSERT(reporter, NULL == quarterBrightness->getInput(0));
reedcedc36f2015-03-08 04:42:52 -0700157 SkColorFilter* cf;
158 REPORTER_ASSERT(reporter, quarterBrightness->asColorFilter(&cf));
159 REPORTER_ASSERT(reporter, cf->asColorMatrix(NULL));
160 cf->unref();
senorblanco@chromium.org194d7752013-07-24 22:19:24 +0000161 }
162
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000163 {
reedcedc36f2015-03-08 04:42:52 -0700164 // Check that a clipping color-matrice-filter followed by a color-matrice-filters
165 // concatenates into a single filter, but not a matrixfilter (due to clamping).
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000166 SkAutoTUnref<SkImageFilter> doubleBrightness(make_scale(2.0f));
167 SkAutoTUnref<SkImageFilter> halfBrightness(make_scale(0.5f, doubleBrightness));
reedcedc36f2015-03-08 04:42:52 -0700168 REPORTER_ASSERT(reporter, NULL == halfBrightness->getInput(0));
169 SkColorFilter* cf;
170 REPORTER_ASSERT(reporter, halfBrightness->asColorFilter(&cf));
171 REPORTER_ASSERT(reporter, !cf->asColorMatrix(NULL));
172 cf->unref();
senorblanco@chromium.org194d7752013-07-24 22:19:24 +0000173 }
174
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000175 {
176 // Check that a color filter image filter without a crop rect can be
177 // expressed as a color filter.
reedcedc36f2015-03-08 04:42:52 -0700178 SkAutoTUnref<SkImageFilter> gray(make_grayscale(NULL, NULL));
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000179 REPORTER_ASSERT(reporter, true == gray->asColorFilter(NULL));
senorblanco@chromium.org194d7752013-07-24 22:19:24 +0000180 }
reedcedc36f2015-03-08 04:42:52 -0700181
182 {
183 // Check that a colorfilterimage filter without a crop rect but with an input
184 // that is another colorfilterimage can be expressed as a colorfilter (composed).
185 SkAutoTUnref<SkImageFilter> mode(make_blue(NULL, NULL));
186 SkAutoTUnref<SkImageFilter> gray(make_grayscale(mode, NULL));
187 REPORTER_ASSERT(reporter, true == gray->asColorFilter(NULL));
188 }
189
190 {
191 // Test that if we exceed the limit of what ComposeColorFilter can combine, we still
192 // can build the DAG and won't assert if we call asColorFilter.
193 SkAutoTUnref<SkImageFilter> filter(make_blue(NULL, NULL));
194 const int kWayTooManyForComposeColorFilter = 100;
195 for (int i = 0; i < kWayTooManyForComposeColorFilter; ++i) {
196 filter.reset(make_blue(filter, NULL));
197 // the first few of these will succeed, but after we hit the internal limit,
198 // it will then return false.
199 (void)filter->asColorFilter(NULL);
200 }
201 }
reed5c518a82015-03-05 14:47:29 -0800202
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000203 {
204 // Check that a color filter image filter with a crop rect cannot
205 // be expressed as a color filter.
206 SkImageFilter::CropRect cropRect(SkRect::MakeXYWH(0, 0, 100, 100));
207 SkAutoTUnref<SkImageFilter> grayWithCrop(make_grayscale(NULL, &cropRect));
208 REPORTER_ASSERT(reporter, false == grayWithCrop->asColorFilter(NULL));
209 }
210
211 {
senorblanco3df05012014-07-03 11:13:09 -0700212 // Check that two non-commutative matrices are concatenated in
213 // the correct order.
214 SkScalar blueToRedMatrix[20] = { 0 };
215 blueToRedMatrix[2] = blueToRedMatrix[18] = SK_Scalar1;
216 SkScalar redToGreenMatrix[20] = { 0 };
217 redToGreenMatrix[5] = redToGreenMatrix[18] = SK_Scalar1;
218 SkAutoTUnref<SkColorFilter> blueToRed(SkColorMatrixFilter::Create(blueToRedMatrix));
219 SkAutoTUnref<SkImageFilter> filter1(SkColorFilterImageFilter::Create(blueToRed.get()));
220 SkAutoTUnref<SkColorFilter> redToGreen(SkColorMatrixFilter::Create(redToGreenMatrix));
221 SkAutoTUnref<SkImageFilter> filter2(SkColorFilterImageFilter::Create(redToGreen.get(), filter1.get()));
222
223 SkBitmap result;
224 result.allocN32Pixels(kBitmapSize, kBitmapSize);
225
226 SkPaint paint;
227 paint.setColor(SK_ColorBLUE);
228 paint.setImageFilter(filter2.get());
229 SkCanvas canvas(result);
230 canvas.clear(0x0);
231 SkRect rect = SkRect::Make(SkIRect::MakeWH(kBitmapSize, kBitmapSize));
232 canvas.drawRect(rect, paint);
233 uint32_t pixel = *result.getAddr32(0, 0);
234 // The result here should be green, since we have effectively shifted blue to green.
235 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
236 }
237
238 {
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000239 // Tests pass by not asserting
240 SkBitmap bitmap, result;
241 make_small_bitmap(bitmap);
mike@reedtribe.orgdeee4962014-02-13 14:41:43 +0000242 result.allocN32Pixels(kBitmapSize, kBitmapSize);
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000243
senorblanco@chromium.org194d7752013-07-24 22:19:24 +0000244 {
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000245 // This tests for :
246 // 1 ) location at (0,0,1)
247 SkPoint3 location(0, 0, SK_Scalar1);
248 // 2 ) location and target at same value
249 SkPoint3 target(location.fX, location.fY, location.fZ);
250 // 3 ) large negative specular exponent value
251 SkScalar specularExponent = -1000;
252
commit-bot@chromium.orgcac5fd52014-03-10 10:51:58 +0000253 SkAutoTUnref<SkImageFilter> bmSrc(SkBitmapSource::Create(bitmap));
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000254 SkPaint paint;
255 paint.setImageFilter(SkLightingImageFilter::CreateSpotLitSpecular(
256 location, target, specularExponent, 180,
257 0xFFFFFFFF, SK_Scalar1, SK_Scalar1, SK_Scalar1,
258 bmSrc))->unref();
259 SkCanvas canvas(result);
260 SkRect r = SkRect::MakeWH(SkIntToScalar(kBitmapSize),
261 SkIntToScalar(kBitmapSize));
262 canvas.drawRect(r, paint);
senorblanco@chromium.org194d7752013-07-24 22:19:24 +0000263 }
senorblanco@chromium.org194d7752013-07-24 22:19:24 +0000264 }
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +0000265}
senorblanco@chromium.org6776b822014-01-03 21:48:22 +0000266
robertphillips9a53fd72015-06-22 09:46:59 -0700267static void test_crop_rects(SkImageFilter::Proxy* proxy, skiatest::Reporter* reporter) {
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +0000268 // Check that all filters offset to their absolute crop rect,
269 // unaffected by the input crop rect.
270 // Tests pass by not asserting.
271 SkBitmap bitmap;
mike@reedtribe.orgdeee4962014-02-13 14:41:43 +0000272 bitmap.allocN32Pixels(100, 100);
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +0000273 bitmap.eraseARGB(0, 0, 0, 0);
senorblanco@chromium.org6776b822014-01-03 21:48:22 +0000274
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +0000275 SkImageFilter::CropRect inputCropRect(SkRect::MakeXYWH(8, 13, 80, 80));
276 SkImageFilter::CropRect cropRect(SkRect::MakeXYWH(20, 30, 60, 60));
277 SkAutoTUnref<SkImageFilter> input(make_grayscale(NULL, &inputCropRect));
senorblanco@chromium.org6776b822014-01-03 21:48:22 +0000278
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +0000279 SkAutoTUnref<SkColorFilter> cf(SkColorFilter::CreateModeFilter(SK_ColorRED, SkXfermode::kSrcIn_Mode));
280 SkPoint3 location(0, 0, SK_Scalar1);
281 SkPoint3 target(SK_Scalar1, SK_Scalar1, SK_Scalar1);
282 SkScalar kernel[9] = {
283 SkIntToScalar( 1), SkIntToScalar( 1), SkIntToScalar( 1),
284 SkIntToScalar( 1), SkIntToScalar(-7), SkIntToScalar( 1),
285 SkIntToScalar( 1), SkIntToScalar( 1), SkIntToScalar( 1),
286 };
287 SkISize kernelSize = SkISize::Make(3, 3);
288 SkScalar gain = SK_Scalar1, bias = 0;
senorblanco@chromium.org6776b822014-01-03 21:48:22 +0000289
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +0000290 SkImageFilter* filters[] = {
291 SkColorFilterImageFilter::Create(cf.get(), input.get(), &cropRect),
commit-bot@chromium.orgcac5fd52014-03-10 10:51:58 +0000292 SkDisplacementMapEffect::Create(SkDisplacementMapEffect::kR_ChannelSelectorType,
293 SkDisplacementMapEffect::kB_ChannelSelectorType,
294 40.0f, input.get(), input.get(), &cropRect),
295 SkBlurImageFilter::Create(SK_Scalar1, SK_Scalar1, input.get(), &cropRect),
sugoi234f0362014-10-23 13:59:52 -0700296 SkDropShadowImageFilter::Create(SK_Scalar1, SK_Scalar1, SK_Scalar1, SK_Scalar1,
297 SK_ColorGREEN, SkDropShadowImageFilter::kDrawShadowAndForeground_ShadowMode,
senorblanco24e06d52015-03-18 12:11:33 -0700298 input.get(), &cropRect),
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +0000299 SkLightingImageFilter::CreatePointLitDiffuse(location, SK_ColorGREEN, 0, 0, input.get(), &cropRect),
300 SkLightingImageFilter::CreatePointLitSpecular(location, SK_ColorGREEN, 0, 0, 0, input.get(), &cropRect),
commit-bot@chromium.orgcac5fd52014-03-10 10:51:58 +0000301 SkMatrixConvolutionImageFilter::Create(kernelSize, kernel, gain, bias, SkIPoint::Make(1, 1), SkMatrixConvolutionImageFilter::kRepeat_TileMode, false, input.get(), &cropRect),
302 SkMergeImageFilter::Create(input.get(), input.get(), SkXfermode::kSrcOver_Mode, &cropRect),
303 SkOffsetImageFilter::Create(SK_Scalar1, SK_Scalar1, input.get(), &cropRect),
304 SkOffsetImageFilter::Create(SK_Scalar1, SK_Scalar1, input.get(), &cropRect),
305 SkDilateImageFilter::Create(3, 2, input.get(), &cropRect),
306 SkErodeImageFilter::Create(2, 3, input.get(), &cropRect),
307 SkTileImageFilter::Create(inputCropRect.rect(), cropRect.rect(), input.get()),
308 SkXfermodeImageFilter::Create(SkXfermode::Create(SkXfermode::kSrcOver_Mode), input.get(), input.get(), &cropRect),
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +0000309 };
senorblanco@chromium.org6776b822014-01-03 21:48:22 +0000310
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +0000311 for (size_t i = 0; i < SK_ARRAY_COUNT(filters); ++i) {
312 SkImageFilter* filter = filters[i];
313 SkBitmap result;
314 SkIPoint offset;
315 SkString str;
senorblanco@chromium.orgf4e1a762014-02-04 00:28:46 +0000316 str.printf("filter %d", static_cast<int>(i));
senorblanco55b6d8b2014-07-30 11:26:46 -0700317 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeLargest(), NULL);
robertphillips9a53fd72015-06-22 09:46:59 -0700318 REPORTER_ASSERT_MESSAGE(reporter, filter->filterImage(proxy, bitmap, ctx,
commit-bot@chromium.orgf7efa502014-04-11 18:57:00 +0000319 &result, &offset), str.c_str());
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +0000320 REPORTER_ASSERT_MESSAGE(reporter, offset.fX == 20 && offset.fY == 30, str.c_str());
senorblanco@chromium.org6776b822014-01-03 21:48:22 +0000321 }
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +0000322
323 for (size_t i = 0; i < SK_ARRAY_COUNT(filters); ++i) {
324 SkSafeUnref(filters[i]);
325 }
326}
327
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +0000328static SkBitmap make_gradient_circle(int width, int height) {
329 SkBitmap bitmap;
330 SkScalar x = SkIntToScalar(width / 2);
331 SkScalar y = SkIntToScalar(height / 2);
332 SkScalar radius = SkMinScalar(x, y) * 0.8f;
333 bitmap.allocN32Pixels(width, height);
334 SkCanvas canvas(bitmap);
335 canvas.clear(0x00000000);
336 SkColor colors[2];
337 colors[0] = SK_ColorWHITE;
338 colors[1] = SK_ColorBLACK;
339 SkAutoTUnref<SkShader> shader(
340 SkGradientShader::CreateRadial(SkPoint::Make(x, y), radius, colors, NULL, 2,
341 SkShader::kClamp_TileMode)
342 );
343 SkPaint paint;
344 paint.setShader(shader);
345 canvas.drawCircle(x, y, radius, paint);
346 return bitmap;
347}
348
robertphillips9a53fd72015-06-22 09:46:59 -0700349static void test_negative_blur_sigma(SkImageFilter::Proxy* proxy, skiatest::Reporter* reporter) {
senorblanco32673b92014-09-09 09:15:04 -0700350 // Check that SkBlurImageFilter will accept a negative sigma, either in
351 // the given arguments or after CTM application.
352 int width = 32, height = 32;
senorblanco32673b92014-09-09 09:15:04 -0700353 SkScalar five = SkIntToScalar(5);
354
355 SkAutoTUnref<SkBlurImageFilter> positiveFilter(
356 SkBlurImageFilter::Create(five, five)
357 );
358
359 SkAutoTUnref<SkBlurImageFilter> negativeFilter(
360 SkBlurImageFilter::Create(-five, five)
361 );
362
363 SkBitmap gradient = make_gradient_circle(width, height);
364 SkBitmap positiveResult1, negativeResult1;
365 SkBitmap positiveResult2, negativeResult2;
366 SkIPoint offset;
367 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeLargest(), NULL);
robertphillips9a53fd72015-06-22 09:46:59 -0700368 positiveFilter->filterImage(proxy, gradient, ctx, &positiveResult1, &offset);
369 negativeFilter->filterImage(proxy, gradient, ctx, &negativeResult1, &offset);
senorblanco32673b92014-09-09 09:15:04 -0700370 SkMatrix negativeScale;
371 negativeScale.setScale(-SK_Scalar1, SK_Scalar1);
372 SkImageFilter::Context negativeCTX(negativeScale, SkIRect::MakeLargest(), NULL);
robertphillips9a53fd72015-06-22 09:46:59 -0700373 positiveFilter->filterImage(proxy, gradient, negativeCTX, &negativeResult2, &offset);
374 negativeFilter->filterImage(proxy, gradient, negativeCTX, &positiveResult2, &offset);
senorblanco32673b92014-09-09 09:15:04 -0700375 SkAutoLockPixels lockP1(positiveResult1);
376 SkAutoLockPixels lockP2(positiveResult2);
377 SkAutoLockPixels lockN1(negativeResult1);
378 SkAutoLockPixels lockN2(negativeResult2);
379 for (int y = 0; y < height; y++) {
380 int diffs = memcmp(positiveResult1.getAddr32(0, y), negativeResult1.getAddr32(0, y), positiveResult1.rowBytes());
381 REPORTER_ASSERT(reporter, !diffs);
382 if (diffs) {
383 break;
384 }
385 diffs = memcmp(positiveResult1.getAddr32(0, y), negativeResult2.getAddr32(0, y), positiveResult1.rowBytes());
386 REPORTER_ASSERT(reporter, !diffs);
387 if (diffs) {
388 break;
389 }
390 diffs = memcmp(positiveResult1.getAddr32(0, y), positiveResult2.getAddr32(0, y), positiveResult1.rowBytes());
391 REPORTER_ASSERT(reporter, !diffs);
392 if (diffs) {
393 break;
394 }
395 }
396}
397
398DEF_TEST(TestNegativeBlurSigma, reporter) {
robertphillips9a53fd72015-06-22 09:46:59 -0700399 const SkImageInfo info = SkImageInfo::MakeN32Premul(100, 100);
400 const SkSurfaceProps props(SkSurfaceProps::kLegacyFontHost_InitType);
401
402 SkAutoTUnref<SkBaseDevice> device(SkBitmapDevice::Create(info, props));
robertphillipsefbffed2015-06-22 12:06:08 -0700403 SkImageFilter::Proxy proxy(device);
robertphillips9a53fd72015-06-22 09:46:59 -0700404
405 test_negative_blur_sigma(&proxy, reporter);
senorblanco32673b92014-09-09 09:15:04 -0700406}
407
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +0000408DEF_TEST(ImageFilterDrawTiled, reporter) {
409 // Check that all filters when drawn tiled (with subsequent clip rects) exactly
410 // match the same filters drawn with a single full-canvas bitmap draw.
411 // Tests pass by not asserting.
412
413 SkAutoTUnref<SkColorFilter> cf(SkColorFilter::CreateModeFilter(SK_ColorRED, SkXfermode::kSrcIn_Mode));
414 SkPoint3 location(0, 0, SK_Scalar1);
415 SkPoint3 target(SK_Scalar1, SK_Scalar1, SK_Scalar1);
416 SkScalar kernel[9] = {
417 SkIntToScalar( 1), SkIntToScalar( 1), SkIntToScalar( 1),
418 SkIntToScalar( 1), SkIntToScalar(-7), SkIntToScalar( 1),
419 SkIntToScalar( 1), SkIntToScalar( 1), SkIntToScalar( 1),
420 };
421 SkISize kernelSize = SkISize::Make(3, 3);
422 SkScalar gain = SK_Scalar1, bias = 0;
senorblanco@chromium.org29ac34e2014-05-28 19:29:25 +0000423 SkScalar five = SkIntToScalar(5);
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +0000424
425 SkAutoTUnref<SkImageFilter> gradient_source(SkBitmapSource::Create(make_gradient_circle(64, 64)));
senorblanco@chromium.org29ac34e2014-05-28 19:29:25 +0000426 SkAutoTUnref<SkImageFilter> blur(SkBlurImageFilter::Create(five, five));
senorblanco@chromium.orgba31f1d2014-05-07 20:56:08 +0000427 SkMatrix matrix;
senorblanco@chromium.org29ac34e2014-05-28 19:29:25 +0000428
senorblanco@chromium.orgba31f1d2014-05-07 20:56:08 +0000429 matrix.setTranslate(SK_Scalar1, SK_Scalar1);
430 matrix.postRotate(SkIntToScalar(45), SK_Scalar1, SK_Scalar1);
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +0000431
senorblanco@chromium.org910702b2014-05-30 20:36:15 +0000432 SkRTreeFactory factory;
433 SkPictureRecorder recorder;
434 SkCanvas* recordingCanvas = recorder.beginRecording(64, 64, &factory, 0);
435
436 SkPaint greenPaint;
437 greenPaint.setColor(SK_ColorGREEN);
438 recordingCanvas->drawRect(SkRect::Make(SkIRect::MakeXYWH(10, 10, 30, 20)), greenPaint);
439 SkAutoTUnref<SkPicture> picture(recorder.endRecording());
440 SkAutoTUnref<SkImageFilter> pictureFilter(SkPictureImageFilter::Create(picture.get()));
senorblanco8f3937d2014-10-29 12:36:32 -0700441 SkAutoTUnref<SkShader> shader(SkPerlinNoiseShader::CreateTurbulence(SK_Scalar1, SK_Scalar1, 1, 0));
442
443 SkAutoTUnref<SkImageFilter> rectShaderFilter(SkRectShaderImageFilter::Create(shader.get()));
senorblanco@chromium.org910702b2014-05-30 20:36:15 +0000444
fsd8b57712015-05-20 00:52:17 -0700445 SkAutoTUnref<SkShader> greenColorShader(SkShader::CreateColorShader(SK_ColorGREEN));
446 SkImageFilter::CropRect leftSideCropRect(SkRect::MakeXYWH(0, 0, 32, 64));
447 SkAutoTUnref<SkImageFilter> rectShaderFilterLeft(SkRectShaderImageFilter::Create(greenColorShader.get(), &leftSideCropRect));
448 SkImageFilter::CropRect rightSideCropRect(SkRect::MakeXYWH(32, 0, 32, 64));
449 SkAutoTUnref<SkImageFilter> rectShaderFilterRight(SkRectShaderImageFilter::Create(greenColorShader.get(), &rightSideCropRect));
450
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +0000451 struct {
452 const char* fName;
453 SkImageFilter* fFilter;
454 } filters[] = {
455 { "color filter", SkColorFilterImageFilter::Create(cf.get()) },
456 { "displacement map", SkDisplacementMapEffect::Create(
457 SkDisplacementMapEffect::kR_ChannelSelectorType,
458 SkDisplacementMapEffect::kB_ChannelSelectorType,
senorblanco@chromium.orgd4db6572014-05-07 20:00:04 +0000459 20.0f, gradient_source.get()) },
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +0000460 { "blur", SkBlurImageFilter::Create(SK_Scalar1, SK_Scalar1) },
461 { "drop shadow", SkDropShadowImageFilter::Create(
sugoi234f0362014-10-23 13:59:52 -0700462 SK_Scalar1, SK_Scalar1, SK_Scalar1, SK_Scalar1, SK_ColorGREEN,
463 SkDropShadowImageFilter::kDrawShadowAndForeground_ShadowMode) },
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +0000464 { "diffuse lighting", SkLightingImageFilter::CreatePointLitDiffuse(
465 location, SK_ColorGREEN, 0, 0) },
466 { "specular lighting",
467 SkLightingImageFilter::CreatePointLitSpecular(location, SK_ColorGREEN, 0, 0, 0) },
468 { "matrix convolution",
469 SkMatrixConvolutionImageFilter::Create(
470 kernelSize, kernel, gain, bias, SkIPoint::Make(1, 1),
471 SkMatrixConvolutionImageFilter::kRepeat_TileMode, false) },
472 { "merge", SkMergeImageFilter::Create(NULL, NULL, SkXfermode::kSrcOver_Mode) },
fsd8b57712015-05-20 00:52:17 -0700473 { "merge with disjoint inputs", SkMergeImageFilter::Create(
474 rectShaderFilterLeft, rectShaderFilterRight, SkXfermode::kSrcOver_Mode) },
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +0000475 { "offset", SkOffsetImageFilter::Create(SK_Scalar1, SK_Scalar1) },
476 { "dilate", SkDilateImageFilter::Create(3, 2) },
477 { "erode", SkErodeImageFilter::Create(2, 3) },
478 { "tile", SkTileImageFilter::Create(SkRect::MakeXYWH(0, 0, 50, 50),
479 SkRect::MakeXYWH(0, 0, 100, 100), NULL) },
senorblanco8c874ee2015-03-20 06:38:17 -0700480 { "matrix", SkImageFilter::CreateMatrixFilter(matrix, kLow_SkFilterQuality) },
senorblanco@chromium.org29ac34e2014-05-28 19:29:25 +0000481 { "blur and offset", SkOffsetImageFilter::Create(five, five, blur.get()) },
senorblanco@chromium.org910702b2014-05-30 20:36:15 +0000482 { "picture and blur", SkBlurImageFilter::Create(five, five, pictureFilter.get()) },
senorblanco8f3937d2014-10-29 12:36:32 -0700483 { "rect shader and blur", SkBlurImageFilter::Create(five, five, rectShaderFilter.get()) },
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +0000484 };
485
486 SkBitmap untiledResult, tiledResult;
487 int width = 64, height = 64;
488 untiledResult.allocN32Pixels(width, height);
489 tiledResult.allocN32Pixels(width, height);
490 SkCanvas tiledCanvas(tiledResult);
491 SkCanvas untiledCanvas(untiledResult);
senorblanco@chromium.orgd4db6572014-05-07 20:00:04 +0000492 int tileSize = 8;
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +0000493
senorblanco@chromium.orgd4db6572014-05-07 20:00:04 +0000494 for (int scale = 1; scale <= 2; ++scale) {
495 for (size_t i = 0; i < SK_ARRAY_COUNT(filters); ++i) {
496 tiledCanvas.clear(0);
497 untiledCanvas.clear(0);
498 SkPaint paint;
499 paint.setImageFilter(filters[i].fFilter);
500 paint.setTextSize(SkIntToScalar(height));
501 paint.setColor(SK_ColorWHITE);
502 SkString str;
503 const char* text = "ABC";
504 SkScalar ypos = SkIntToScalar(height);
505 untiledCanvas.save();
506 untiledCanvas.scale(SkIntToScalar(scale), SkIntToScalar(scale));
507 untiledCanvas.drawText(text, strlen(text), 0, ypos, paint);
508 untiledCanvas.restore();
509 for (int y = 0; y < height; y += tileSize) {
510 for (int x = 0; x < width; x += tileSize) {
511 tiledCanvas.save();
512 tiledCanvas.clipRect(SkRect::Make(SkIRect::MakeXYWH(x, y, tileSize, tileSize)));
513 tiledCanvas.scale(SkIntToScalar(scale), SkIntToScalar(scale));
514 tiledCanvas.drawText(text, strlen(text), 0, ypos, paint);
515 tiledCanvas.restore();
516 }
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +0000517 }
senorblanco@chromium.orgd4db6572014-05-07 20:00:04 +0000518 untiledCanvas.flush();
519 tiledCanvas.flush();
520 for (int y = 0; y < height; y++) {
521 int diffs = memcmp(untiledResult.getAddr32(0, y), tiledResult.getAddr32(0, y), untiledResult.rowBytes());
522 REPORTER_ASSERT_MESSAGE(reporter, !diffs, filters[i].fName);
523 if (diffs) {
524 break;
525 }
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +0000526 }
527 }
528 }
529
530 for (size_t i = 0; i < SK_ARRAY_COUNT(filters); ++i) {
531 SkSafeUnref(filters[i].fFilter);
532 }
533}
534
mtklein3f3b3d02014-12-01 11:47:08 -0800535static void draw_saveLayer_picture(int width, int height, int tileSize,
robertphillipsa8d7f0b2014-08-29 08:03:56 -0700536 SkBBHFactory* factory, SkBitmap* result) {
mtkleind910f542014-08-22 09:06:34 -0700537
538 SkMatrix matrix;
539 matrix.setTranslate(SkIntToScalar(50), 0);
540
541 SkAutoTUnref<SkColorFilter> cf(SkColorFilter::CreateModeFilter(SK_ColorWHITE, SkXfermode::kSrc_Mode));
542 SkAutoTUnref<SkImageFilter> cfif(SkColorFilterImageFilter::Create(cf.get()));
senorblanco8c874ee2015-03-20 06:38:17 -0700543 SkAutoTUnref<SkImageFilter> imageFilter(SkImageFilter::CreateMatrixFilter(matrix, kNone_SkFilterQuality, cfif.get()));
mtkleind910f542014-08-22 09:06:34 -0700544
545 SkPaint paint;
546 paint.setImageFilter(imageFilter.get());
547 SkPictureRecorder recorder;
548 SkRect bounds = SkRect::Make(SkIRect::MakeXYWH(0, 0, 50, 50));
mtklein3f3b3d02014-12-01 11:47:08 -0800549 SkCanvas* recordingCanvas = recorder.beginRecording(SkIntToScalar(width),
550 SkIntToScalar(height),
robertphillipsa8d7f0b2014-08-29 08:03:56 -0700551 factory, 0);
mtkleind910f542014-08-22 09:06:34 -0700552 recordingCanvas->translate(-55, 0);
553 recordingCanvas->saveLayer(&bounds, &paint);
554 recordingCanvas->restore();
555 SkAutoTUnref<SkPicture> picture1(recorder.endRecording());
556
557 result->allocN32Pixels(width, height);
558 SkCanvas canvas(*result);
559 canvas.clear(0);
560 canvas.clipRect(SkRect::Make(SkIRect::MakeWH(tileSize, tileSize)));
561 canvas.drawPicture(picture1.get());
562}
563
564DEF_TEST(ImageFilterDrawMatrixBBH, reporter) {
565 // Check that matrix filter when drawn tiled with BBH exactly
566 // matches the same thing drawn without BBH.
567 // Tests pass by not asserting.
568
569 const int width = 200, height = 200;
570 const int tileSize = 100;
571 SkBitmap result1, result2;
572 SkRTreeFactory factory;
573
robertphillipsa8d7f0b2014-08-29 08:03:56 -0700574 draw_saveLayer_picture(width, height, tileSize, &factory, &result1);
575 draw_saveLayer_picture(width, height, tileSize, NULL, &result2);
mtkleind910f542014-08-22 09:06:34 -0700576
577 for (int y = 0; y < height; y++) {
578 int diffs = memcmp(result1.getAddr32(0, y), result2.getAddr32(0, y), result1.rowBytes());
579 REPORTER_ASSERT(reporter, !diffs);
580 if (diffs) {
581 break;
582 }
583 }
584}
585
senorblanco1150a6d2014-08-25 12:46:58 -0700586static SkImageFilter* makeBlur(SkImageFilter* input = NULL) {
587 return SkBlurImageFilter::Create(SK_Scalar1, SK_Scalar1, input);
588}
589
590static SkImageFilter* makeDropShadow(SkImageFilter* input = NULL) {
591 return SkDropShadowImageFilter::Create(
592 SkIntToScalar(100), SkIntToScalar(100),
593 SkIntToScalar(10), SkIntToScalar(10),
sugoi234f0362014-10-23 13:59:52 -0700594 SK_ColorBLUE, SkDropShadowImageFilter::kDrawShadowAndForeground_ShadowMode,
senorblanco24e06d52015-03-18 12:11:33 -0700595 input, NULL);
senorblanco1150a6d2014-08-25 12:46:58 -0700596}
597
598DEF_TEST(ImageFilterBlurThenShadowBounds, reporter) {
599 SkAutoTUnref<SkImageFilter> filter1(makeBlur());
600 SkAutoTUnref<SkImageFilter> filter2(makeDropShadow(filter1.get()));
601
602 SkIRect bounds = SkIRect::MakeXYWH(0, 0, 100, 100);
603 SkIRect expectedBounds = SkIRect::MakeXYWH(-133, -133, 236, 236);
604 filter2->filterBounds(bounds, SkMatrix::I(), &bounds);
605
606 REPORTER_ASSERT(reporter, bounds == expectedBounds);
607}
608
609DEF_TEST(ImageFilterShadowThenBlurBounds, reporter) {
610 SkAutoTUnref<SkImageFilter> filter1(makeDropShadow());
611 SkAutoTUnref<SkImageFilter> filter2(makeBlur(filter1.get()));
612
613 SkIRect bounds = SkIRect::MakeXYWH(0, 0, 100, 100);
614 SkIRect expectedBounds = SkIRect::MakeXYWH(-133, -133, 236, 236);
615 filter2->filterBounds(bounds, SkMatrix::I(), &bounds);
616
617 REPORTER_ASSERT(reporter, bounds == expectedBounds);
618}
619
620DEF_TEST(ImageFilterDilateThenBlurBounds, reporter) {
621 SkAutoTUnref<SkImageFilter> filter1(SkDilateImageFilter::Create(2, 2));
622 SkAutoTUnref<SkImageFilter> filter2(makeDropShadow(filter1.get()));
623
624 SkIRect bounds = SkIRect::MakeXYWH(0, 0, 100, 100);
625 SkIRect expectedBounds = SkIRect::MakeXYWH(-132, -132, 234, 234);
626 filter2->filterBounds(bounds, SkMatrix::I(), &bounds);
627
628 REPORTER_ASSERT(reporter, bounds == expectedBounds);
629}
630
ajuma5788faa2015-02-13 09:05:47 -0800631DEF_TEST(ImageFilterComposedBlurFastBounds, reporter) {
632 SkAutoTUnref<SkImageFilter> filter1(makeBlur());
633 SkAutoTUnref<SkImageFilter> filter2(makeBlur());
634 SkAutoTUnref<SkImageFilter> composedFilter(SkComposeImageFilter::Create(filter1.get(), filter2.get()));
635
636 SkRect boundsSrc = SkRect::MakeWH(SkIntToScalar(100), SkIntToScalar(100));
637 SkRect expectedBounds = SkRect::MakeXYWH(
638 SkIntToScalar(-6), SkIntToScalar(-6), SkIntToScalar(112), SkIntToScalar(112));
639 SkRect boundsDst = SkRect::MakeEmpty();
640 composedFilter->computeFastBounds(boundsSrc, &boundsDst);
641
642 REPORTER_ASSERT(reporter, boundsDst == expectedBounds);
643}
644
robertphillipsa8d7f0b2014-08-29 08:03:56 -0700645static void draw_blurred_rect(SkCanvas* canvas) {
senorblanco837f5322014-07-14 10:19:54 -0700646 SkAutoTUnref<SkImageFilter> filter(SkBlurImageFilter::Create(SkIntToScalar(8), 0));
647 SkPaint filterPaint;
648 filterPaint.setColor(SK_ColorWHITE);
649 filterPaint.setImageFilter(filter);
650 canvas->saveLayer(NULL, &filterPaint);
651 SkPaint whitePaint;
652 whitePaint.setColor(SK_ColorWHITE);
653 canvas->drawRect(SkRect::Make(SkIRect::MakeWH(4, 4)), whitePaint);
654 canvas->restore();
655}
656
robertphillipsa8d7f0b2014-08-29 08:03:56 -0700657static void draw_picture_clipped(SkCanvas* canvas, const SkRect& clipRect, const SkPicture* picture) {
senorblanco837f5322014-07-14 10:19:54 -0700658 canvas->save();
659 canvas->clipRect(clipRect);
660 canvas->drawPicture(picture);
661 canvas->restore();
662}
663
664DEF_TEST(ImageFilterDrawTiledBlurRTree, reporter) {
665 // Check that the blur filter when recorded with RTree acceleration,
666 // and drawn tiled (with subsequent clip rects) exactly
667 // matches the same filter drawn with without RTree acceleration.
668 // This tests that the "bleed" from the blur into the otherwise-blank
669 // tiles is correctly rendered.
670 // Tests pass by not asserting.
671
672 int width = 16, height = 8;
673 SkBitmap result1, result2;
674 result1.allocN32Pixels(width, height);
675 result2.allocN32Pixels(width, height);
676 SkCanvas canvas1(result1);
677 SkCanvas canvas2(result2);
678 int tileSize = 8;
679
680 canvas1.clear(0);
681 canvas2.clear(0);
682
683 SkRTreeFactory factory;
684
685 SkPictureRecorder recorder1, recorder2;
686 // The only difference between these two pictures is that one has RTree aceleration.
mtklein3f3b3d02014-12-01 11:47:08 -0800687 SkCanvas* recordingCanvas1 = recorder1.beginRecording(SkIntToScalar(width),
688 SkIntToScalar(height),
robertphillipsa8d7f0b2014-08-29 08:03:56 -0700689 NULL, 0);
mtklein3f3b3d02014-12-01 11:47:08 -0800690 SkCanvas* recordingCanvas2 = recorder2.beginRecording(SkIntToScalar(width),
691 SkIntToScalar(height),
robertphillipsa8d7f0b2014-08-29 08:03:56 -0700692 &factory, 0);
693 draw_blurred_rect(recordingCanvas1);
694 draw_blurred_rect(recordingCanvas2);
senorblanco837f5322014-07-14 10:19:54 -0700695 SkAutoTUnref<SkPicture> picture1(recorder1.endRecording());
696 SkAutoTUnref<SkPicture> picture2(recorder2.endRecording());
697 for (int y = 0; y < height; y += tileSize) {
698 for (int x = 0; x < width; x += tileSize) {
699 SkRect tileRect = SkRect::Make(SkIRect::MakeXYWH(x, y, tileSize, tileSize));
robertphillipsa8d7f0b2014-08-29 08:03:56 -0700700 draw_picture_clipped(&canvas1, tileRect, picture1);
701 draw_picture_clipped(&canvas2, tileRect, picture2);
senorblanco837f5322014-07-14 10:19:54 -0700702 }
703 }
704 for (int y = 0; y < height; y++) {
705 int diffs = memcmp(result1.getAddr32(0, y), result2.getAddr32(0, y), result1.rowBytes());
706 REPORTER_ASSERT(reporter, !diffs);
707 if (diffs) {
708 break;
709 }
710 }
711}
712
senorblanco@chromium.org91957432014-05-01 14:03:41 +0000713DEF_TEST(ImageFilterMatrixConvolution, reporter) {
714 // Check that a 1x3 filter does not cause a spurious assert.
715 SkScalar kernel[3] = {
716 SkIntToScalar( 1), SkIntToScalar( 1), SkIntToScalar( 1),
717 };
718 SkISize kernelSize = SkISize::Make(1, 3);
719 SkScalar gain = SK_Scalar1, bias = 0;
720 SkIPoint kernelOffset = SkIPoint::Make(0, 0);
721
722 SkAutoTUnref<SkImageFilter> filter(
723 SkMatrixConvolutionImageFilter::Create(
724 kernelSize, kernel, gain, bias, kernelOffset,
725 SkMatrixConvolutionImageFilter::kRepeat_TileMode, false));
726
727 SkBitmap result;
728 int width = 16, height = 16;
729 result.allocN32Pixels(width, height);
730 SkCanvas canvas(result);
731 canvas.clear(0);
732
733 SkPaint paint;
734 paint.setImageFilter(filter);
735 SkRect rect = SkRect::Make(SkIRect::MakeWH(width, height));
736 canvas.drawRect(rect, paint);
737}
738
senorblanco@chromium.org8c7372b2014-05-02 19:13:11 +0000739DEF_TEST(ImageFilterMatrixConvolutionBorder, reporter) {
740 // Check that a filter with borders outside the target bounds
741 // does not crash.
742 SkScalar kernel[3] = {
743 0, 0, 0,
744 };
745 SkISize kernelSize = SkISize::Make(3, 1);
746 SkScalar gain = SK_Scalar1, bias = 0;
747 SkIPoint kernelOffset = SkIPoint::Make(2, 0);
748
749 SkAutoTUnref<SkImageFilter> filter(
750 SkMatrixConvolutionImageFilter::Create(
751 kernelSize, kernel, gain, bias, kernelOffset,
752 SkMatrixConvolutionImageFilter::kClamp_TileMode, true));
753
754 SkBitmap result;
755
756 int width = 10, height = 10;
757 result.allocN32Pixels(width, height);
758 SkCanvas canvas(result);
759 canvas.clear(0);
760
761 SkPaint filterPaint;
762 filterPaint.setImageFilter(filter);
763 SkRect bounds = SkRect::MakeWH(1, 10);
764 SkRect rect = SkRect::Make(SkIRect::MakeWH(width, height));
765 SkPaint rectPaint;
766 canvas.saveLayer(&bounds, &filterPaint);
767 canvas.drawRect(rect, rectPaint);
768 canvas.restore();
769}
770
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +0000771DEF_TEST(ImageFilterCropRect, reporter) {
robertphillips9a53fd72015-06-22 09:46:59 -0700772 const SkImageInfo info = SkImageInfo::MakeN32Premul(100, 100);
773 const SkSurfaceProps props(SkSurfaceProps::kLegacyFontHost_InitType);
774
775 SkAutoTUnref<SkBaseDevice> device(SkBitmapDevice::Create(info, props));
robertphillipsefbffed2015-06-22 12:06:08 -0700776 SkImageFilter::Proxy proxy(device);
robertphillips9a53fd72015-06-22 09:46:59 -0700777
778 test_crop_rects(&proxy, reporter);
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +0000779}
780
tfarina9ea53f92014-06-24 06:50:39 -0700781DEF_TEST(ImageFilterMatrix, reporter) {
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +0000782 SkBitmap temp;
mike@reedtribe.orgdeee4962014-02-13 14:41:43 +0000783 temp.allocN32Pixels(100, 100);
robertphillips9a53fd72015-06-22 09:46:59 -0700784 SkCanvas canvas(temp);
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +0000785 canvas.scale(SkIntToScalar(2), SkIntToScalar(2));
786
787 SkMatrix expectedMatrix = canvas.getTotalMatrix();
788
commit-bot@chromium.org5fb2ce32014-04-17 23:35:06 +0000789 SkRTreeFactory factory;
790 SkPictureRecorder recorder;
791 SkCanvas* recordingCanvas = recorder.beginRecording(100, 100, &factory, 0);
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +0000792
793 SkPaint paint;
794 SkAutoTUnref<MatrixTestImageFilter> imageFilter(
795 new MatrixTestImageFilter(reporter, expectedMatrix));
796 paint.setImageFilter(imageFilter.get());
commit-bot@chromium.org091a5942014-04-18 14:19:31 +0000797 recordingCanvas->saveLayer(NULL, &paint);
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +0000798 SkPaint solidPaint;
799 solidPaint.setColor(0xFFFFFFFF);
800 recordingCanvas->save();
801 recordingCanvas->scale(SkIntToScalar(10), SkIntToScalar(10));
802 recordingCanvas->drawRect(SkRect::Make(SkIRect::MakeWH(100, 100)), solidPaint);
803 recordingCanvas->restore(); // scale
804 recordingCanvas->restore(); // saveLayer
robertphillips@google.com84b18c72014-04-13 19:09:42 +0000805 SkAutoTUnref<SkPicture> picture(recorder.endRecording());
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +0000806
robertphillips9b14f262014-06-04 05:40:44 -0700807 canvas.drawPicture(picture);
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +0000808}
809
senorblanco3d822c22014-07-30 14:49:31 -0700810DEF_TEST(ImageFilterCrossProcessPictureImageFilter, reporter) {
senorblanco@chromium.org97f5fc62014-05-30 20:50:56 +0000811 SkRTreeFactory factory;
812 SkPictureRecorder recorder;
813 SkCanvas* recordingCanvas = recorder.beginRecording(1, 1, &factory, 0);
814
815 // Create an SkPicture which simply draws a green 1x1 rectangle.
816 SkPaint greenPaint;
817 greenPaint.setColor(SK_ColorGREEN);
818 recordingCanvas->drawRect(SkRect::Make(SkIRect::MakeWH(1, 1)), greenPaint);
819 SkAutoTUnref<SkPicture> picture(recorder.endRecording());
820
821 // Wrap that SkPicture in an SkPictureImageFilter.
822 SkAutoTUnref<SkImageFilter> imageFilter(
823 SkPictureImageFilter::Create(picture.get()));
824
825 // Check that SkPictureImageFilter successfully serializes its contained
826 // SkPicture when not in cross-process mode.
827 SkPaint paint;
828 paint.setImageFilter(imageFilter.get());
829 SkPictureRecorder outerRecorder;
830 SkCanvas* outerCanvas = outerRecorder.beginRecording(1, 1, &factory, 0);
831 SkPaint redPaintWithFilter;
832 redPaintWithFilter.setColor(SK_ColorRED);
833 redPaintWithFilter.setImageFilter(imageFilter.get());
834 outerCanvas->drawRect(SkRect::Make(SkIRect::MakeWH(1, 1)), redPaintWithFilter);
835 SkAutoTUnref<SkPicture> outerPicture(outerRecorder.endRecording());
836
837 SkBitmap bitmap;
838 bitmap.allocN32Pixels(1, 1);
robertphillips9a53fd72015-06-22 09:46:59 -0700839 SkCanvas canvas(bitmap);
senorblanco@chromium.org97f5fc62014-05-30 20:50:56 +0000840
841 // The result here should be green, since the filter replaces the primitive's red interior.
842 canvas.clear(0x0);
robertphillips9b14f262014-06-04 05:40:44 -0700843 canvas.drawPicture(outerPicture);
senorblanco@chromium.org97f5fc62014-05-30 20:50:56 +0000844 uint32_t pixel = *bitmap.getAddr32(0, 0);
845 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
846
847 // Check that, for now, SkPictureImageFilter does not serialize or
848 // deserialize its contained picture when the filter is serialized
849 // cross-process. Do this by "laundering" it through SkValidatingReadBuffer.
850 SkAutoTUnref<SkData> data(SkValidatingSerializeFlattenable(imageFilter.get()));
851 SkAutoTUnref<SkFlattenable> flattenable(SkValidatingDeserializeFlattenable(
852 data->data(), data->size(), SkImageFilter::GetFlattenableType()));
853 SkImageFilter* unflattenedFilter = static_cast<SkImageFilter*>(flattenable.get());
854
855 redPaintWithFilter.setImageFilter(unflattenedFilter);
856 SkPictureRecorder crossProcessRecorder;
857 SkCanvas* crossProcessCanvas = crossProcessRecorder.beginRecording(1, 1, &factory, 0);
858 crossProcessCanvas->drawRect(SkRect::Make(SkIRect::MakeWH(1, 1)), redPaintWithFilter);
859 SkAutoTUnref<SkPicture> crossProcessPicture(crossProcessRecorder.endRecording());
860
861 canvas.clear(0x0);
robertphillips9b14f262014-06-04 05:40:44 -0700862 canvas.drawPicture(crossProcessPicture);
senorblanco@chromium.org97f5fc62014-05-30 20:50:56 +0000863 pixel = *bitmap.getAddr32(0, 0);
hendrikw446ee672015-06-16 09:28:37 -0700864 // If the security precautions are enabled, the result here should not be green, since the
865 // filter draws nothing.
866 REPORTER_ASSERT(reporter, SkPicture::PictureIOSecurityPrecautionsEnabled()
867 ? pixel != SK_ColorGREEN : pixel == SK_ColorGREEN);
senorblanco@chromium.org97f5fc62014-05-30 20:50:56 +0000868}
869
senorblanco3d822c22014-07-30 14:49:31 -0700870DEF_TEST(ImageFilterClippedPictureImageFilter, reporter) {
871 SkRTreeFactory factory;
872 SkPictureRecorder recorder;
873 SkCanvas* recordingCanvas = recorder.beginRecording(1, 1, &factory, 0);
874
875 // Create an SkPicture which simply draws a green 1x1 rectangle.
876 SkPaint greenPaint;
877 greenPaint.setColor(SK_ColorGREEN);
878 recordingCanvas->drawRect(SkRect::Make(SkIRect::MakeWH(1, 1)), greenPaint);
879 SkAutoTUnref<SkPicture> picture(recorder.endRecording());
880
robertphillips9a53fd72015-06-22 09:46:59 -0700881 SkAutoTUnref<SkImageFilter> imageFilter(SkPictureImageFilter::Create(picture.get()));
senorblanco3d822c22014-07-30 14:49:31 -0700882
883 SkBitmap result;
884 SkIPoint offset;
885 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeXYWH(1, 1, 1, 1), NULL);
886 SkBitmap bitmap;
887 bitmap.allocN32Pixels(2, 2);
robertphillipsefbffed2015-06-22 12:06:08 -0700888 const SkSurfaceProps props(SkSurfaceProps::kLegacyFontHost_InitType);
889 SkBitmapDevice device(bitmap, props);
890 SkImageFilter::Proxy proxy(&device);
senorblanco3d822c22014-07-30 14:49:31 -0700891 REPORTER_ASSERT(reporter, !imageFilter->filterImage(&proxy, bitmap, ctx, &result, &offset));
892}
893
tfarina9ea53f92014-06-24 06:50:39 -0700894DEF_TEST(ImageFilterEmptySaveLayer, reporter) {
senorblanco@chromium.org68250c82014-05-06 22:52:55 +0000895 // Even when there's an empty saveLayer()/restore(), ensure that an image
896 // filter or color filter which affects transparent black still draws.
897
898 SkBitmap bitmap;
899 bitmap.allocN32Pixels(10, 10);
robertphillips9a53fd72015-06-22 09:46:59 -0700900 SkCanvas canvas(bitmap);
senorblanco@chromium.org68250c82014-05-06 22:52:55 +0000901
902 SkRTreeFactory factory;
903 SkPictureRecorder recorder;
904
905 SkAutoTUnref<SkColorFilter> green(
906 SkColorFilter::CreateModeFilter(SK_ColorGREEN, SkXfermode::kSrc_Mode));
907 SkAutoTUnref<SkColorFilterImageFilter> imageFilter(
908 SkColorFilterImageFilter::Create(green.get()));
909 SkPaint imageFilterPaint;
910 imageFilterPaint.setImageFilter(imageFilter.get());
911 SkPaint colorFilterPaint;
912 colorFilterPaint.setColorFilter(green.get());
913
914 SkRect bounds = SkRect::MakeWH(10, 10);
915
916 SkCanvas* recordingCanvas = recorder.beginRecording(10, 10, &factory, 0);
917 recordingCanvas->saveLayer(&bounds, &imageFilterPaint);
918 recordingCanvas->restore();
919 SkAutoTUnref<SkPicture> picture(recorder.endRecording());
920
921 canvas.clear(0);
robertphillips9b14f262014-06-04 05:40:44 -0700922 canvas.drawPicture(picture);
senorblanco@chromium.org68250c82014-05-06 22:52:55 +0000923 uint32_t pixel = *bitmap.getAddr32(0, 0);
924 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
925
926 recordingCanvas = recorder.beginRecording(10, 10, &factory, 0);
927 recordingCanvas->saveLayer(NULL, &imageFilterPaint);
928 recordingCanvas->restore();
929 SkAutoTUnref<SkPicture> picture2(recorder.endRecording());
930
931 canvas.clear(0);
robertphillips9b14f262014-06-04 05:40:44 -0700932 canvas.drawPicture(picture2);
senorblanco@chromium.org68250c82014-05-06 22:52:55 +0000933 pixel = *bitmap.getAddr32(0, 0);
934 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
935
936 recordingCanvas = recorder.beginRecording(10, 10, &factory, 0);
937 recordingCanvas->saveLayer(&bounds, &colorFilterPaint);
938 recordingCanvas->restore();
939 SkAutoTUnref<SkPicture> picture3(recorder.endRecording());
940
941 canvas.clear(0);
robertphillips9b14f262014-06-04 05:40:44 -0700942 canvas.drawPicture(picture3);
senorblanco@chromium.org68250c82014-05-06 22:52:55 +0000943 pixel = *bitmap.getAddr32(0, 0);
944 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
945}
946
robertphillips9a53fd72015-06-22 09:46:59 -0700947static void test_huge_blur(SkCanvas* canvas, skiatest::Reporter* reporter) {
senorblanco@chromium.org09843fd2014-03-24 20:50:59 +0000948 SkBitmap bitmap;
949 bitmap.allocN32Pixels(100, 100);
950 bitmap.eraseARGB(0, 0, 0, 0);
951
952 // Check that a blur with an insane radius does not crash or assert.
953 SkAutoTUnref<SkImageFilter> blur(SkBlurImageFilter::Create(SkIntToScalar(1<<30), SkIntToScalar(1<<30)));
954
955 SkPaint paint;
956 paint.setImageFilter(blur);
robertphillips9a53fd72015-06-22 09:46:59 -0700957 canvas->drawSprite(bitmap, 0, 0, &paint);
senorblanco@chromium.org09843fd2014-03-24 20:50:59 +0000958}
959
960DEF_TEST(HugeBlurImageFilter, reporter) {
961 SkBitmap temp;
962 temp.allocN32Pixels(100, 100);
robertphillips9a53fd72015-06-22 09:46:59 -0700963 SkCanvas canvas(temp);
964 test_huge_blur(&canvas, reporter);
senorblanco@chromium.org09843fd2014-03-24 20:50:59 +0000965}
966
senorblanco3a495202014-09-29 07:57:20 -0700967DEF_TEST(MatrixConvolutionSanityTest, reporter) {
968 SkScalar kernel[1] = { 0 };
969 SkScalar gain = SK_Scalar1, bias = 0;
970 SkIPoint kernelOffset = SkIPoint::Make(1, 1);
971
972 // Check that an enormous (non-allocatable) kernel gives a NULL filter.
973 SkAutoTUnref<SkImageFilter> conv(SkMatrixConvolutionImageFilter::Create(
974 SkISize::Make(1<<30, 1<<30),
975 kernel,
976 gain,
977 bias,
978 kernelOffset,
979 SkMatrixConvolutionImageFilter::kRepeat_TileMode,
980 false));
981
982 REPORTER_ASSERT(reporter, NULL == conv.get());
983
984 // Check that a NULL kernel gives a NULL filter.
985 conv.reset(SkMatrixConvolutionImageFilter::Create(
986 SkISize::Make(1, 1),
987 NULL,
988 gain,
989 bias,
990 kernelOffset,
991 SkMatrixConvolutionImageFilter::kRepeat_TileMode,
992 false));
993
994 REPORTER_ASSERT(reporter, NULL == conv.get());
995
996 // Check that a kernel width < 1 gives a NULL filter.
997 conv.reset(SkMatrixConvolutionImageFilter::Create(
998 SkISize::Make(0, 1),
999 kernel,
1000 gain,
1001 bias,
1002 kernelOffset,
1003 SkMatrixConvolutionImageFilter::kRepeat_TileMode,
1004 false));
1005
1006 REPORTER_ASSERT(reporter, NULL == conv.get());
1007
1008 // Check that kernel height < 1 gives a NULL filter.
1009 conv.reset(SkMatrixConvolutionImageFilter::Create(
1010 SkISize::Make(1, -1),
1011 kernel,
1012 gain,
1013 bias,
1014 kernelOffset,
1015 SkMatrixConvolutionImageFilter::kRepeat_TileMode,
1016 false));
1017
1018 REPORTER_ASSERT(reporter, NULL == conv.get());
1019}
1020
robertphillips9a53fd72015-06-22 09:46:59 -07001021static void test_xfermode_cropped_input(SkCanvas* canvas, skiatest::Reporter* reporter) {
1022 canvas->clear(0);
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001023
1024 SkBitmap bitmap;
1025 bitmap.allocN32Pixels(1, 1);
1026 bitmap.eraseARGB(255, 255, 255, 255);
1027
1028 SkAutoTUnref<SkColorFilter> green(
1029 SkColorFilter::CreateModeFilter(SK_ColorGREEN, SkXfermode::kSrcIn_Mode));
1030 SkAutoTUnref<SkColorFilterImageFilter> greenFilter(
1031 SkColorFilterImageFilter::Create(green.get()));
1032 SkImageFilter::CropRect cropRect(SkRect::MakeEmpty());
1033 SkAutoTUnref<SkColorFilterImageFilter> croppedOut(
1034 SkColorFilterImageFilter::Create(green.get(), NULL, &cropRect));
1035
1036 // Check that an xfermode image filter whose input has been cropped out still draws the other
1037 // input. Also check that drawing with both inputs cropped out doesn't cause a GPU warning.
1038 SkXfermode* mode = SkXfermode::Create(SkXfermode::kSrcOver_Mode);
1039 SkAutoTUnref<SkImageFilter> xfermodeNoFg(
1040 SkXfermodeImageFilter::Create(mode, greenFilter, croppedOut));
1041 SkAutoTUnref<SkImageFilter> xfermodeNoBg(
1042 SkXfermodeImageFilter::Create(mode, croppedOut, greenFilter));
1043 SkAutoTUnref<SkImageFilter> xfermodeNoFgNoBg(
1044 SkXfermodeImageFilter::Create(mode, croppedOut, croppedOut));
1045
1046 SkPaint paint;
1047 paint.setImageFilter(xfermodeNoFg);
robertphillips9a53fd72015-06-22 09:46:59 -07001048 canvas->drawSprite(bitmap, 0, 0, &paint);
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001049
1050 uint32_t pixel;
kkinnunena9d9a392015-03-06 07:16:00 -08001051 SkImageInfo info = SkImageInfo::Make(1, 1, kBGRA_8888_SkColorType, kUnpremul_SkAlphaType);
robertphillips9a53fd72015-06-22 09:46:59 -07001052 canvas->readPixels(info, &pixel, 4, 0, 0);
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001053 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1054
1055 paint.setImageFilter(xfermodeNoBg);
robertphillips9a53fd72015-06-22 09:46:59 -07001056 canvas->drawSprite(bitmap, 0, 0, &paint);
1057 canvas->readPixels(info, &pixel, 4, 0, 0);
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001058 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1059
1060 paint.setImageFilter(xfermodeNoFgNoBg);
robertphillips9a53fd72015-06-22 09:46:59 -07001061 canvas->drawSprite(bitmap, 0, 0, &paint);
1062 canvas->readPixels(info, &pixel, 4, 0, 0);
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001063 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1064}
1065
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001066DEF_TEST(ImageFilterNestedSaveLayer, reporter) {
1067 SkBitmap temp;
1068 temp.allocN32Pixels(50, 50);
robertphillips9a53fd72015-06-22 09:46:59 -07001069 SkCanvas canvas(temp);
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001070 canvas.clear(0x0);
1071
1072 SkBitmap bitmap;
1073 bitmap.allocN32Pixels(10, 10);
1074 bitmap.eraseColor(SK_ColorGREEN);
1075
1076 SkMatrix matrix;
1077 matrix.setScale(SkIntToScalar(2), SkIntToScalar(2));
1078 matrix.postTranslate(SkIntToScalar(-20), SkIntToScalar(-20));
1079 SkAutoTUnref<SkImageFilter> matrixFilter(
senorblanco8c874ee2015-03-20 06:38:17 -07001080 SkImageFilter::CreateMatrixFilter(matrix, kLow_SkFilterQuality));
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001081
1082 // Test that saveLayer() with a filter nested inside another saveLayer() applies the
1083 // correct offset to the filter matrix.
1084 SkRect bounds1 = SkRect::MakeXYWH(10, 10, 30, 30);
1085 canvas.saveLayer(&bounds1, NULL);
1086 SkPaint filterPaint;
1087 filterPaint.setImageFilter(matrixFilter);
1088 SkRect bounds2 = SkRect::MakeXYWH(20, 20, 10, 10);
1089 canvas.saveLayer(&bounds2, &filterPaint);
1090 SkPaint greenPaint;
1091 greenPaint.setColor(SK_ColorGREEN);
1092 canvas.drawRect(bounds2, greenPaint);
1093 canvas.restore();
1094 canvas.restore();
1095 SkPaint strokePaint;
1096 strokePaint.setStyle(SkPaint::kStroke_Style);
1097 strokePaint.setColor(SK_ColorRED);
1098
kkinnunena9d9a392015-03-06 07:16:00 -08001099 SkImageInfo info = SkImageInfo::Make(1, 1, kBGRA_8888_SkColorType, kUnpremul_SkAlphaType);
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001100 uint32_t pixel;
1101 canvas.readPixels(info, &pixel, 4, 25, 25);
1102 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1103
1104 // Test that drawSprite() with a filter nested inside a saveLayer() applies the
1105 // correct offset to the filter matrix.
1106 canvas.clear(0x0);
1107 canvas.readPixels(info, &pixel, 4, 25, 25);
1108 canvas.saveLayer(&bounds1, NULL);
1109 canvas.drawSprite(bitmap, 20, 20, &filterPaint);
1110 canvas.restore();
1111
1112 canvas.readPixels(info, &pixel, 4, 25, 25);
1113 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1114}
1115
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001116DEF_TEST(XfermodeImageFilterCroppedInput, reporter) {
1117 SkBitmap temp;
1118 temp.allocN32Pixels(100, 100);
robertphillips9a53fd72015-06-22 09:46:59 -07001119 SkCanvas canvas(temp);
1120 test_xfermode_cropped_input(&canvas, reporter);
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001121}
senorblanco@chromium.org09843fd2014-03-24 20:50:59 +00001122
ajuma5788faa2015-02-13 09:05:47 -08001123DEF_TEST(ComposedImageFilterOffset, reporter) {
1124 SkBitmap bitmap;
1125 bitmap.allocN32Pixels(100, 100);
1126 bitmap.eraseARGB(0, 0, 0, 0);
robertphillipsefbffed2015-06-22 12:06:08 -07001127 const SkSurfaceProps props(SkSurfaceProps::kLegacyFontHost_InitType);
1128 SkBitmapDevice device(bitmap, props);
1129 SkImageFilter::Proxy proxy(&device);
ajuma5788faa2015-02-13 09:05:47 -08001130
1131 SkImageFilter::CropRect cropRect(SkRect::MakeXYWH(1, 0, 20, 20));
1132 SkAutoTUnref<SkImageFilter> offsetFilter(SkOffsetImageFilter::Create(0, 0, NULL, &cropRect));
ajuma8e8c9402015-02-13 10:15:46 -08001133 SkAutoTUnref<SkImageFilter> blurFilter(makeBlur());
1134 SkAutoTUnref<SkImageFilter> composedFilter(SkComposeImageFilter::Create(blurFilter, offsetFilter.get()));
ajuma5788faa2015-02-13 09:05:47 -08001135 SkBitmap result;
1136 SkIPoint offset;
1137 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeLargest(), NULL);
1138 REPORTER_ASSERT(reporter, composedFilter->filterImage(&proxy, bitmap, ctx, &result, &offset));
1139 REPORTER_ASSERT(reporter, offset.fX == 1 && offset.fY == 0);
1140}
1141
senorblanco24d2a7b2015-07-13 10:27:05 -07001142DEF_TEST(PartialCropRect, reporter) {
1143 SkBitmap bitmap;
1144 bitmap.allocN32Pixels(100, 100);
1145 bitmap.eraseARGB(0, 0, 0, 0);
1146 const SkSurfaceProps props(SkSurfaceProps::kLegacyFontHost_InitType);
1147 SkBitmapDevice device(bitmap, props);
1148 SkImageFilter::Proxy proxy(&device);
1149
1150 SkImageFilter::CropRect cropRect(SkRect::MakeXYWH(100, 0, 20, 30),
1151 SkImageFilter::CropRect::kHasRight_CropEdge | SkImageFilter::CropRect::kHasBottom_CropEdge);
1152 SkAutoTUnref<SkImageFilter> filter(make_grayscale(NULL, &cropRect));
1153 SkBitmap result;
1154 SkIPoint offset;
1155 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeLargest(), NULL);
1156 REPORTER_ASSERT(reporter, filter->filterImage(&proxy, bitmap, ctx, &result, &offset));
1157 REPORTER_ASSERT(reporter, offset.fX == 0);
1158 REPORTER_ASSERT(reporter, offset.fY == 0);
1159 REPORTER_ASSERT(reporter, result.width() == 20);
1160 REPORTER_ASSERT(reporter, result.height() == 30);
1161}
1162
senorblanco@chromium.org58d14662014-02-03 22:36:39 +00001163#if SK_SUPPORT_GPU
reed4a8126e2014-09-22 07:29:03 -07001164
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +00001165DEF_GPUTEST(ImageFilterCropRectGPU, reporter, factory) {
1166 GrContext* context = factory->get(static_cast<GrContextFactory::GLContextType>(0));
senorblancoc8e93402015-04-21 07:20:36 -07001167 if (NULL == context) {
1168 return;
1169 }
robertphillipsefbffed2015-06-22 12:06:08 -07001170 const SkSurfaceProps props(SkSurfaceProps::kLegacyFontHost_InitType);
1171
commit-bot@chromium.org15a14052014-02-16 00:59:25 +00001172 SkAutoTUnref<SkGpuDevice> device(SkGpuDevice::Create(context,
bsalomonafe30052015-01-16 07:32:33 -08001173 SkSurface::kNo_Budgeted,
commit-bot@chromium.org15a14052014-02-16 00:59:25 +00001174 SkImageInfo::MakeN32Premul(100, 100),
bsalomonafe30052015-01-16 07:32:33 -08001175 0,
bsalomon74f681d2015-06-23 14:38:48 -07001176 &props,
1177 SkGpuDevice::kUninit_InitContents));
robertphillipsefbffed2015-06-22 12:06:08 -07001178 SkImageFilter::Proxy proxy(device);
robertphillips9a53fd72015-06-22 09:46:59 -07001179
1180 test_crop_rects(&proxy, reporter);
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +00001181}
senorblanco@chromium.org09843fd2014-03-24 20:50:59 +00001182
1183DEF_GPUTEST(HugeBlurImageFilterGPU, reporter, factory) {
1184 GrContext* context = factory->get(static_cast<GrContextFactory::GLContextType>(0));
senorblancoc8e93402015-04-21 07:20:36 -07001185 if (NULL == context) {
1186 return;
1187 }
robertphillipsefbffed2015-06-22 12:06:08 -07001188 const SkSurfaceProps props(SkSurfaceProps::kLegacyFontHost_InitType);
1189
senorblanco@chromium.org09843fd2014-03-24 20:50:59 +00001190 SkAutoTUnref<SkGpuDevice> device(SkGpuDevice::Create(context,
bsalomonafe30052015-01-16 07:32:33 -08001191 SkSurface::kNo_Budgeted,
senorblanco@chromium.org09843fd2014-03-24 20:50:59 +00001192 SkImageInfo::MakeN32Premul(100, 100),
bsalomonafe30052015-01-16 07:32:33 -08001193 0,
bsalomon74f681d2015-06-23 14:38:48 -07001194 &props,
1195 SkGpuDevice::kUninit_InitContents));
robertphillips9a53fd72015-06-22 09:46:59 -07001196 SkCanvas canvas(device);
1197
1198 test_huge_blur(&canvas, reporter);
senorblanco@chromium.org09843fd2014-03-24 20:50:59 +00001199}
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001200
1201DEF_GPUTEST(XfermodeImageFilterCroppedInputGPU, reporter, factory) {
1202 GrContext* context = factory->get(static_cast<GrContextFactory::GLContextType>(0));
senorblancoc8e93402015-04-21 07:20:36 -07001203 if (NULL == context) {
1204 return;
1205 }
robertphillipsefbffed2015-06-22 12:06:08 -07001206 const SkSurfaceProps props(SkSurfaceProps::kLegacyFontHost_InitType);
1207
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001208 SkAutoTUnref<SkGpuDevice> device(SkGpuDevice::Create(context,
bsalomonafe30052015-01-16 07:32:33 -08001209 SkSurface::kNo_Budgeted,
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001210 SkImageInfo::MakeN32Premul(1, 1),
bsalomonafe30052015-01-16 07:32:33 -08001211 0,
bsalomon74f681d2015-06-23 14:38:48 -07001212 &props,
1213 SkGpuDevice::kUninit_InitContents));
robertphillips9a53fd72015-06-22 09:46:59 -07001214 SkCanvas canvas(device);
1215
1216 test_xfermode_cropped_input(&canvas, reporter);
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001217}
senorblanco32673b92014-09-09 09:15:04 -07001218
1219DEF_GPUTEST(TestNegativeBlurSigmaGPU, reporter, factory) {
1220 GrContext* context = factory->get(static_cast<GrContextFactory::GLContextType>(0));
senorblancoc8e93402015-04-21 07:20:36 -07001221 if (NULL == context) {
1222 return;
1223 }
robertphillipsefbffed2015-06-22 12:06:08 -07001224 const SkSurfaceProps props(SkSurfaceProps::kLegacyFontHost_InitType);
1225
senorblanco32673b92014-09-09 09:15:04 -07001226 SkAutoTUnref<SkGpuDevice> device(SkGpuDevice::Create(context,
bsalomonafe30052015-01-16 07:32:33 -08001227 SkSurface::kNo_Budgeted,
senorblanco32673b92014-09-09 09:15:04 -07001228 SkImageInfo::MakeN32Premul(1, 1),
bsalomonafe30052015-01-16 07:32:33 -08001229 0,
bsalomon74f681d2015-06-23 14:38:48 -07001230 &props,
1231 SkGpuDevice::kUninit_InitContents));
robertphillipsefbffed2015-06-22 12:06:08 -07001232 SkImageFilter::Proxy proxy(device);
robertphillips9a53fd72015-06-22 09:46:59 -07001233
1234 test_negative_blur_sigma(&proxy, reporter);
senorblanco32673b92014-09-09 09:15:04 -07001235}
senorblanco@chromium.org58d14662014-02-03 22:36:39 +00001236#endif