blob: c15d719a64212dc8a552dbd485e0d8a76dcd837a [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"
robertphillips3d32d762015-07-13 13:16:44 -070029#include "SkPoint3.h"
halcanary97d2c0a2014-08-19 06:27:53 -070030#include "SkReadBuffer.h"
tfarina@chromium.org8f6884a2014-01-24 20:56:26 +000031#include "SkRect.h"
senorblanco8f3937d2014-10-29 12:36:32 -070032#include "SkRectShaderImageFilter.h"
senorblanco0abdf762015-08-20 11:10:41 -070033#include "SkTableColorFilter.h"
senorblanco@chromium.org6776b822014-01-03 21:48:22 +000034#include "SkTileImageFilter.h"
35#include "SkXfermodeImageFilter.h"
tfarina@chromium.org8f6884a2014-01-24 20:56:26 +000036#include "Test.h"
senorblanco@chromium.org194d7752013-07-24 22:19:24 +000037
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +000038#if SK_SUPPORT_GPU
39#include "GrContextFactory.h"
40#include "SkGpuDevice.h"
41#endif
42
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +000043static const int kBitmapSize = 4;
commit-bot@chromium.org4b681bc2013-09-13 12:40:02 +000044
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +000045namespace {
46
47class MatrixTestImageFilter : public SkImageFilter {
48public:
49 MatrixTestImageFilter(skiatest::Reporter* reporter, const SkMatrix& expectedMatrix)
senorblanco9ea3d572014-07-08 09:16:22 -070050 : SkImageFilter(0, NULL), fReporter(reporter), fExpectedMatrix(expectedMatrix) {
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +000051 }
52
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +000053 virtual bool onFilterImage(Proxy*, const SkBitmap& src, const Context& ctx,
mtklein36352bf2015-03-25 18:17:31 -070054 SkBitmap* result, SkIPoint* offset) const override {
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +000055 REPORTER_ASSERT(fReporter, ctx.ctm() == fExpectedMatrix);
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +000056 return true;
57 }
58
robertphillipsf3f5bad2014-12-19 13:49:15 -080059 SK_TO_STRING_OVERRIDE()
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +000060 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(MatrixTestImageFilter)
61
62protected:
mtklein36352bf2015-03-25 18:17:31 -070063 void flatten(SkWriteBuffer& buffer) const override {
reed9fa60da2014-08-21 07:59:51 -070064 this->INHERITED::flatten(buffer);
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +000065 buffer.writeFunctionPtr(fReporter);
66 buffer.writeMatrix(fExpectedMatrix);
67 }
68
69private:
70 skiatest::Reporter* fReporter;
71 SkMatrix fExpectedMatrix;
mtklein3f3b3d02014-12-01 11:47:08 -080072
reed9fa60da2014-08-21 07:59:51 -070073 typedef SkImageFilter INHERITED;
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +000074};
75
76}
77
reed9fa60da2014-08-21 07:59:51 -070078SkFlattenable* MatrixTestImageFilter::CreateProc(SkReadBuffer& buffer) {
79 SK_IMAGEFILTER_UNFLATTEN_COMMON(common, 1);
80 skiatest::Reporter* reporter = (skiatest::Reporter*)buffer.readFunctionPtr();
81 SkMatrix matrix;
82 buffer.readMatrix(&matrix);
83 return SkNEW_ARGS(MatrixTestImageFilter, (reporter, matrix));
84}
85
robertphillipsf3f5bad2014-12-19 13:49:15 -080086#ifndef SK_IGNORE_TO_STRING
87void MatrixTestImageFilter::toString(SkString* str) const {
88 str->appendf("MatrixTestImageFilter: (");
89 str->append(")");
90}
91#endif
92
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +000093static void make_small_bitmap(SkBitmap& bitmap) {
mike@reedtribe.orgdeee4962014-02-13 14:41:43 +000094 bitmap.allocN32Pixels(kBitmapSize, kBitmapSize);
95 SkCanvas canvas(bitmap);
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +000096 canvas.clear(0x00000000);
97 SkPaint darkPaint;
98 darkPaint.setColor(0xFF804020);
99 SkPaint lightPaint;
100 lightPaint.setColor(0xFF244484);
101 const int i = kBitmapSize / 4;
102 for (int y = 0; y < kBitmapSize; y += i) {
103 for (int x = 0; x < kBitmapSize; x += i) {
104 canvas.save();
105 canvas.translate(SkIntToScalar(x), SkIntToScalar(y));
106 canvas.drawRect(SkRect::MakeXYWH(0, 0,
107 SkIntToScalar(i),
108 SkIntToScalar(i)), darkPaint);
109 canvas.drawRect(SkRect::MakeXYWH(SkIntToScalar(i),
110 0,
111 SkIntToScalar(i),
112 SkIntToScalar(i)), lightPaint);
113 canvas.drawRect(SkRect::MakeXYWH(0,
114 SkIntToScalar(i),
115 SkIntToScalar(i),
116 SkIntToScalar(i)), lightPaint);
117 canvas.drawRect(SkRect::MakeXYWH(SkIntToScalar(i),
118 SkIntToScalar(i),
119 SkIntToScalar(i),
120 SkIntToScalar(i)), darkPaint);
121 canvas.restore();
commit-bot@chromium.org4b681bc2013-09-13 12:40:02 +0000122 }
123 }
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000124}
senorblanco@chromium.org194d7752013-07-24 22:19:24 +0000125
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000126static SkImageFilter* make_scale(float amount, SkImageFilter* input = NULL) {
127 SkScalar s = amount;
128 SkScalar matrix[20] = { s, 0, 0, 0, 0,
129 0, s, 0, 0, 0,
130 0, 0, s, 0, 0,
131 0, 0, 0, s, 0 };
commit-bot@chromium.org727a3522014-02-21 18:46:30 +0000132 SkAutoTUnref<SkColorFilter> filter(SkColorMatrixFilter::Create(matrix));
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000133 return SkColorFilterImageFilter::Create(filter, input);
134}
135
reedcedc36f2015-03-08 04:42:52 -0700136static SkImageFilter* make_grayscale(SkImageFilter* input, const SkImageFilter::CropRect* cropRect) {
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000137 SkScalar matrix[20];
138 memset(matrix, 0, 20 * sizeof(SkScalar));
139 matrix[0] = matrix[5] = matrix[10] = 0.2126f;
140 matrix[1] = matrix[6] = matrix[11] = 0.7152f;
141 matrix[2] = matrix[7] = matrix[12] = 0.0722f;
142 matrix[18] = 1.0f;
commit-bot@chromium.org727a3522014-02-21 18:46:30 +0000143 SkAutoTUnref<SkColorFilter> filter(SkColorMatrixFilter::Create(matrix));
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000144 return SkColorFilterImageFilter::Create(filter, input, cropRect);
145}
146
reedcedc36f2015-03-08 04:42:52 -0700147static SkImageFilter* make_blue(SkImageFilter* input, const SkImageFilter::CropRect* cropRect) {
148 SkAutoTUnref<SkColorFilter> filter(SkColorFilter::CreateModeFilter(SK_ColorBLUE,
149 SkXfermode::kSrcIn_Mode));
150 return SkColorFilterImageFilter::Create(filter, input, cropRect);
151}
152
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000153DEF_TEST(ImageFilter, reporter) {
154 {
reedcedc36f2015-03-08 04:42:52 -0700155 // Check that two non-clipping color-matrice-filters concatenate into a single filter.
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000156 SkAutoTUnref<SkImageFilter> halfBrightness(make_scale(0.5f));
157 SkAutoTUnref<SkImageFilter> quarterBrightness(make_scale(0.5f, halfBrightness));
158 REPORTER_ASSERT(reporter, NULL == quarterBrightness->getInput(0));
reedcedc36f2015-03-08 04:42:52 -0700159 SkColorFilter* cf;
160 REPORTER_ASSERT(reporter, quarterBrightness->asColorFilter(&cf));
161 REPORTER_ASSERT(reporter, cf->asColorMatrix(NULL));
162 cf->unref();
senorblanco@chromium.org194d7752013-07-24 22:19:24 +0000163 }
164
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000165 {
reedcedc36f2015-03-08 04:42:52 -0700166 // Check that a clipping color-matrice-filter followed by a color-matrice-filters
167 // concatenates into a single filter, but not a matrixfilter (due to clamping).
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000168 SkAutoTUnref<SkImageFilter> doubleBrightness(make_scale(2.0f));
169 SkAutoTUnref<SkImageFilter> halfBrightness(make_scale(0.5f, doubleBrightness));
reedcedc36f2015-03-08 04:42:52 -0700170 REPORTER_ASSERT(reporter, NULL == halfBrightness->getInput(0));
171 SkColorFilter* cf;
172 REPORTER_ASSERT(reporter, halfBrightness->asColorFilter(&cf));
173 REPORTER_ASSERT(reporter, !cf->asColorMatrix(NULL));
174 cf->unref();
senorblanco@chromium.org194d7752013-07-24 22:19:24 +0000175 }
176
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000177 {
178 // Check that a color filter image filter without a crop rect can be
179 // expressed as a color filter.
reedcedc36f2015-03-08 04:42:52 -0700180 SkAutoTUnref<SkImageFilter> gray(make_grayscale(NULL, NULL));
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000181 REPORTER_ASSERT(reporter, true == gray->asColorFilter(NULL));
senorblanco@chromium.org194d7752013-07-24 22:19:24 +0000182 }
reedcedc36f2015-03-08 04:42:52 -0700183
184 {
185 // Check that a colorfilterimage filter without a crop rect but with an input
186 // that is another colorfilterimage can be expressed as a colorfilter (composed).
187 SkAutoTUnref<SkImageFilter> mode(make_blue(NULL, NULL));
188 SkAutoTUnref<SkImageFilter> gray(make_grayscale(mode, NULL));
189 REPORTER_ASSERT(reporter, true == gray->asColorFilter(NULL));
190 }
191
192 {
193 // Test that if we exceed the limit of what ComposeColorFilter can combine, we still
194 // can build the DAG and won't assert if we call asColorFilter.
195 SkAutoTUnref<SkImageFilter> filter(make_blue(NULL, NULL));
196 const int kWayTooManyForComposeColorFilter = 100;
197 for (int i = 0; i < kWayTooManyForComposeColorFilter; ++i) {
198 filter.reset(make_blue(filter, NULL));
199 // the first few of these will succeed, but after we hit the internal limit,
200 // it will then return false.
201 (void)filter->asColorFilter(NULL);
202 }
203 }
reed5c518a82015-03-05 14:47:29 -0800204
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000205 {
206 // Check that a color filter image filter with a crop rect cannot
207 // be expressed as a color filter.
208 SkImageFilter::CropRect cropRect(SkRect::MakeXYWH(0, 0, 100, 100));
209 SkAutoTUnref<SkImageFilter> grayWithCrop(make_grayscale(NULL, &cropRect));
210 REPORTER_ASSERT(reporter, false == grayWithCrop->asColorFilter(NULL));
211 }
212
213 {
senorblanco3df05012014-07-03 11:13:09 -0700214 // Check that two non-commutative matrices are concatenated in
215 // the correct order.
216 SkScalar blueToRedMatrix[20] = { 0 };
217 blueToRedMatrix[2] = blueToRedMatrix[18] = SK_Scalar1;
218 SkScalar redToGreenMatrix[20] = { 0 };
219 redToGreenMatrix[5] = redToGreenMatrix[18] = SK_Scalar1;
220 SkAutoTUnref<SkColorFilter> blueToRed(SkColorMatrixFilter::Create(blueToRedMatrix));
221 SkAutoTUnref<SkImageFilter> filter1(SkColorFilterImageFilter::Create(blueToRed.get()));
222 SkAutoTUnref<SkColorFilter> redToGreen(SkColorMatrixFilter::Create(redToGreenMatrix));
223 SkAutoTUnref<SkImageFilter> filter2(SkColorFilterImageFilter::Create(redToGreen.get(), filter1.get()));
224
225 SkBitmap result;
226 result.allocN32Pixels(kBitmapSize, kBitmapSize);
227
228 SkPaint paint;
229 paint.setColor(SK_ColorBLUE);
230 paint.setImageFilter(filter2.get());
231 SkCanvas canvas(result);
232 canvas.clear(0x0);
233 SkRect rect = SkRect::Make(SkIRect::MakeWH(kBitmapSize, kBitmapSize));
234 canvas.drawRect(rect, paint);
235 uint32_t pixel = *result.getAddr32(0, 0);
236 // The result here should be green, since we have effectively shifted blue to green.
237 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
238 }
239
240 {
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000241 // Tests pass by not asserting
242 SkBitmap bitmap, result;
243 make_small_bitmap(bitmap);
mike@reedtribe.orgdeee4962014-02-13 14:41:43 +0000244 result.allocN32Pixels(kBitmapSize, kBitmapSize);
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000245
senorblanco@chromium.org194d7752013-07-24 22:19:24 +0000246 {
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000247 // This tests for :
248 // 1 ) location at (0,0,1)
robertphillips3d32d762015-07-13 13:16:44 -0700249 SkPoint3 location = SkPoint3::Make(0, 0, SK_Scalar1);
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000250 // 2 ) location and target at same value
robertphillips3d32d762015-07-13 13:16:44 -0700251 SkPoint3 target = SkPoint3::Make(location.fX, location.fY, location.fZ);
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000252 // 3 ) large negative specular exponent value
253 SkScalar specularExponent = -1000;
254
commit-bot@chromium.orgcac5fd52014-03-10 10:51:58 +0000255 SkAutoTUnref<SkImageFilter> bmSrc(SkBitmapSource::Create(bitmap));
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000256 SkPaint paint;
257 paint.setImageFilter(SkLightingImageFilter::CreateSpotLitSpecular(
258 location, target, specularExponent, 180,
259 0xFFFFFFFF, SK_Scalar1, SK_Scalar1, SK_Scalar1,
260 bmSrc))->unref();
261 SkCanvas canvas(result);
262 SkRect r = SkRect::MakeWH(SkIntToScalar(kBitmapSize),
263 SkIntToScalar(kBitmapSize));
264 canvas.drawRect(r, paint);
senorblanco@chromium.org194d7752013-07-24 22:19:24 +0000265 }
senorblanco@chromium.org194d7752013-07-24 22:19:24 +0000266 }
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +0000267}
senorblanco@chromium.org6776b822014-01-03 21:48:22 +0000268
robertphillips9a53fd72015-06-22 09:46:59 -0700269static void test_crop_rects(SkImageFilter::Proxy* proxy, skiatest::Reporter* reporter) {
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +0000270 // Check that all filters offset to their absolute crop rect,
271 // unaffected by the input crop rect.
272 // Tests pass by not asserting.
273 SkBitmap bitmap;
mike@reedtribe.orgdeee4962014-02-13 14:41:43 +0000274 bitmap.allocN32Pixels(100, 100);
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +0000275 bitmap.eraseARGB(0, 0, 0, 0);
senorblanco@chromium.org6776b822014-01-03 21:48:22 +0000276
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +0000277 SkImageFilter::CropRect inputCropRect(SkRect::MakeXYWH(8, 13, 80, 80));
278 SkImageFilter::CropRect cropRect(SkRect::MakeXYWH(20, 30, 60, 60));
279 SkAutoTUnref<SkImageFilter> input(make_grayscale(NULL, &inputCropRect));
senorblanco@chromium.org6776b822014-01-03 21:48:22 +0000280
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +0000281 SkAutoTUnref<SkColorFilter> cf(SkColorFilter::CreateModeFilter(SK_ColorRED, SkXfermode::kSrcIn_Mode));
robertphillips3d32d762015-07-13 13:16:44 -0700282 SkPoint3 location = SkPoint3::Make(0, 0, SK_Scalar1);
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +0000283 SkScalar kernel[9] = {
284 SkIntToScalar( 1), SkIntToScalar( 1), SkIntToScalar( 1),
285 SkIntToScalar( 1), SkIntToScalar(-7), SkIntToScalar( 1),
286 SkIntToScalar( 1), SkIntToScalar( 1), SkIntToScalar( 1),
287 };
288 SkISize kernelSize = SkISize::Make(3, 3);
289 SkScalar gain = SK_Scalar1, bias = 0;
senorblanco@chromium.org6776b822014-01-03 21:48:22 +0000290
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +0000291 SkImageFilter* filters[] = {
292 SkColorFilterImageFilter::Create(cf.get(), input.get(), &cropRect),
commit-bot@chromium.orgcac5fd52014-03-10 10:51:58 +0000293 SkDisplacementMapEffect::Create(SkDisplacementMapEffect::kR_ChannelSelectorType,
294 SkDisplacementMapEffect::kB_ChannelSelectorType,
295 40.0f, input.get(), input.get(), &cropRect),
296 SkBlurImageFilter::Create(SK_Scalar1, SK_Scalar1, input.get(), &cropRect),
sugoi234f0362014-10-23 13:59:52 -0700297 SkDropShadowImageFilter::Create(SK_Scalar1, SK_Scalar1, SK_Scalar1, SK_Scalar1,
298 SK_ColorGREEN, SkDropShadowImageFilter::kDrawShadowAndForeground_ShadowMode,
senorblanco24e06d52015-03-18 12:11:33 -0700299 input.get(), &cropRect),
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +0000300 SkLightingImageFilter::CreatePointLitDiffuse(location, SK_ColorGREEN, 0, 0, input.get(), &cropRect),
301 SkLightingImageFilter::CreatePointLitSpecular(location, SK_ColorGREEN, 0, 0, 0, input.get(), &cropRect),
commit-bot@chromium.orgcac5fd52014-03-10 10:51:58 +0000302 SkMatrixConvolutionImageFilter::Create(kernelSize, kernel, gain, bias, SkIPoint::Make(1, 1), SkMatrixConvolutionImageFilter::kRepeat_TileMode, false, input.get(), &cropRect),
303 SkMergeImageFilter::Create(input.get(), input.get(), SkXfermode::kSrcOver_Mode, &cropRect),
304 SkOffsetImageFilter::Create(SK_Scalar1, SK_Scalar1, input.get(), &cropRect),
305 SkOffsetImageFilter::Create(SK_Scalar1, SK_Scalar1, input.get(), &cropRect),
306 SkDilateImageFilter::Create(3, 2, input.get(), &cropRect),
307 SkErodeImageFilter::Create(2, 3, input.get(), &cropRect),
308 SkTileImageFilter::Create(inputCropRect.rect(), cropRect.rect(), input.get()),
309 SkXfermodeImageFilter::Create(SkXfermode::Create(SkXfermode::kSrcOver_Mode), input.get(), input.get(), &cropRect),
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +0000310 };
senorblanco@chromium.org6776b822014-01-03 21:48:22 +0000311
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +0000312 for (size_t i = 0; i < SK_ARRAY_COUNT(filters); ++i) {
313 SkImageFilter* filter = filters[i];
314 SkBitmap result;
315 SkIPoint offset;
316 SkString str;
senorblanco@chromium.orgf4e1a762014-02-04 00:28:46 +0000317 str.printf("filter %d", static_cast<int>(i));
senorblanco55b6d8b2014-07-30 11:26:46 -0700318 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeLargest(), NULL);
robertphillips9a53fd72015-06-22 09:46:59 -0700319 REPORTER_ASSERT_MESSAGE(reporter, filter->filterImage(proxy, bitmap, ctx,
commit-bot@chromium.orgf7efa502014-04-11 18:57:00 +0000320 &result, &offset), str.c_str());
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +0000321 REPORTER_ASSERT_MESSAGE(reporter, offset.fX == 20 && offset.fY == 30, str.c_str());
senorblanco@chromium.org6776b822014-01-03 21:48:22 +0000322 }
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +0000323
324 for (size_t i = 0; i < SK_ARRAY_COUNT(filters); ++i) {
325 SkSafeUnref(filters[i]);
326 }
327}
328
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +0000329static SkBitmap make_gradient_circle(int width, int height) {
330 SkBitmap bitmap;
331 SkScalar x = SkIntToScalar(width / 2);
332 SkScalar y = SkIntToScalar(height / 2);
333 SkScalar radius = SkMinScalar(x, y) * 0.8f;
334 bitmap.allocN32Pixels(width, height);
335 SkCanvas canvas(bitmap);
336 canvas.clear(0x00000000);
337 SkColor colors[2];
338 colors[0] = SK_ColorWHITE;
339 colors[1] = SK_ColorBLACK;
340 SkAutoTUnref<SkShader> shader(
341 SkGradientShader::CreateRadial(SkPoint::Make(x, y), radius, colors, NULL, 2,
342 SkShader::kClamp_TileMode)
343 );
344 SkPaint paint;
345 paint.setShader(shader);
346 canvas.drawCircle(x, y, radius, paint);
347 return bitmap;
348}
349
robertphillips9a53fd72015-06-22 09:46:59 -0700350static void test_negative_blur_sigma(SkImageFilter::Proxy* proxy, skiatest::Reporter* reporter) {
senorblanco32673b92014-09-09 09:15:04 -0700351 // Check that SkBlurImageFilter will accept a negative sigma, either in
352 // the given arguments or after CTM application.
353 int width = 32, height = 32;
senorblanco32673b92014-09-09 09:15:04 -0700354 SkScalar five = SkIntToScalar(5);
355
356 SkAutoTUnref<SkBlurImageFilter> positiveFilter(
357 SkBlurImageFilter::Create(five, five)
358 );
359
360 SkAutoTUnref<SkBlurImageFilter> negativeFilter(
361 SkBlurImageFilter::Create(-five, five)
362 );
363
364 SkBitmap gradient = make_gradient_circle(width, height);
365 SkBitmap positiveResult1, negativeResult1;
366 SkBitmap positiveResult2, negativeResult2;
367 SkIPoint offset;
368 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeLargest(), NULL);
robertphillips9a53fd72015-06-22 09:46:59 -0700369 positiveFilter->filterImage(proxy, gradient, ctx, &positiveResult1, &offset);
370 negativeFilter->filterImage(proxy, gradient, ctx, &negativeResult1, &offset);
senorblanco32673b92014-09-09 09:15:04 -0700371 SkMatrix negativeScale;
372 negativeScale.setScale(-SK_Scalar1, SK_Scalar1);
373 SkImageFilter::Context negativeCTX(negativeScale, SkIRect::MakeLargest(), NULL);
robertphillips9a53fd72015-06-22 09:46:59 -0700374 positiveFilter->filterImage(proxy, gradient, negativeCTX, &negativeResult2, &offset);
375 negativeFilter->filterImage(proxy, gradient, negativeCTX, &positiveResult2, &offset);
senorblanco32673b92014-09-09 09:15:04 -0700376 SkAutoLockPixels lockP1(positiveResult1);
377 SkAutoLockPixels lockP2(positiveResult2);
378 SkAutoLockPixels lockN1(negativeResult1);
379 SkAutoLockPixels lockN2(negativeResult2);
380 for (int y = 0; y < height; y++) {
381 int diffs = memcmp(positiveResult1.getAddr32(0, y), negativeResult1.getAddr32(0, y), positiveResult1.rowBytes());
382 REPORTER_ASSERT(reporter, !diffs);
383 if (diffs) {
384 break;
385 }
386 diffs = memcmp(positiveResult1.getAddr32(0, y), negativeResult2.getAddr32(0, y), positiveResult1.rowBytes());
387 REPORTER_ASSERT(reporter, !diffs);
388 if (diffs) {
389 break;
390 }
391 diffs = memcmp(positiveResult1.getAddr32(0, y), positiveResult2.getAddr32(0, y), positiveResult1.rowBytes());
392 REPORTER_ASSERT(reporter, !diffs);
393 if (diffs) {
394 break;
395 }
396 }
397}
398
399DEF_TEST(TestNegativeBlurSigma, reporter) {
robertphillips9a53fd72015-06-22 09:46:59 -0700400 const SkImageInfo info = SkImageInfo::MakeN32Premul(100, 100);
401 const SkSurfaceProps props(SkSurfaceProps::kLegacyFontHost_InitType);
402
403 SkAutoTUnref<SkBaseDevice> device(SkBitmapDevice::Create(info, props));
robertphillipsefbffed2015-06-22 12:06:08 -0700404 SkImageFilter::Proxy proxy(device);
robertphillips9a53fd72015-06-22 09:46:59 -0700405
406 test_negative_blur_sigma(&proxy, reporter);
senorblanco32673b92014-09-09 09:15:04 -0700407}
408
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +0000409DEF_TEST(ImageFilterDrawTiled, reporter) {
410 // Check that all filters when drawn tiled (with subsequent clip rects) exactly
411 // match the same filters drawn with a single full-canvas bitmap draw.
412 // Tests pass by not asserting.
413
414 SkAutoTUnref<SkColorFilter> cf(SkColorFilter::CreateModeFilter(SK_ColorRED, SkXfermode::kSrcIn_Mode));
robertphillips3d32d762015-07-13 13:16:44 -0700415 SkPoint3 location = SkPoint3::Make(0, 0, SK_Scalar1);
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +0000416 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),
senorblancoed7cf272015-07-16 15:19:11 -07001151 SkImageFilter::CropRect::kHasWidth_CropEdge | SkImageFilter::CropRect::kHasHeight_CropEdge);
senorblanco24d2a7b2015-07-13 10:27:05 -07001152 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
senorblanco0abdf762015-08-20 11:10:41 -07001163DEF_TEST(ImageFilterCanComputeFastBounds, reporter) {
1164
1165 SkPoint3 location = SkPoint3::Make(0, 0, SK_Scalar1);
1166 SkAutoTUnref<SkImageFilter> lighting(SkLightingImageFilter::CreatePointLitDiffuse(
1167 location, SK_ColorGREEN, 0, 0));
1168 REPORTER_ASSERT(reporter, !lighting->canComputeFastBounds());
1169
1170 SkAutoTUnref<SkImageFilter> gray(make_grayscale(nullptr, nullptr));
1171 REPORTER_ASSERT(reporter, gray->canComputeFastBounds());
1172 {
1173 SkColorFilter* grayCF;
1174 REPORTER_ASSERT(reporter, gray->asAColorFilter(&grayCF));
1175 REPORTER_ASSERT(reporter, !grayCF->affectsTransparentBlack());
1176 grayCF->unref();
1177 }
1178 REPORTER_ASSERT(reporter, gray->canComputeFastBounds());
1179
1180 SkAutoTUnref<SkImageFilter> grayBlur(SkBlurImageFilter::Create(SK_Scalar1, SK_Scalar1, gray.get()));
1181 REPORTER_ASSERT(reporter, grayBlur->canComputeFastBounds());
1182
1183 SkScalar greenMatrix[20] = { 0, 0, 0, 0, 0,
1184 0, 0, 0, 0, 1,
1185 0, 0, 0, 0, 0,
1186 0, 0, 0, 0, 1 };
1187 SkAutoTUnref<SkColorFilter> greenCF(SkColorMatrixFilter::Create(greenMatrix));
1188 SkAutoTUnref<SkImageFilter> green(SkColorFilterImageFilter::Create(greenCF));
1189
1190 REPORTER_ASSERT(reporter, greenCF->affectsTransparentBlack());
1191 REPORTER_ASSERT(reporter, !green->canComputeFastBounds());
1192
1193 SkAutoTUnref<SkImageFilter> greenBlur(SkBlurImageFilter::Create(SK_Scalar1, SK_Scalar1, green.get()));
1194 REPORTER_ASSERT(reporter, !greenBlur->canComputeFastBounds());
1195
1196 uint8_t allOne[256], identity[256];
1197 for (int i = 0; i < 256; ++i) {
1198 identity[i] = i;
1199 allOne[i] = 255;
1200 }
1201
1202 SkAutoTUnref<SkColorFilter> identityCF(
1203 SkTableColorFilter::CreateARGB(identity, identity, identity, allOne));
1204 SkAutoTUnref<SkImageFilter> identityFilter(SkColorFilterImageFilter::Create(identityCF.get()));
1205 REPORTER_ASSERT(reporter, !identityCF->affectsTransparentBlack());
1206 REPORTER_ASSERT(reporter, identityFilter->canComputeFastBounds());
1207
1208 SkAutoTUnref<SkColorFilter> forceOpaqueCF(
1209 SkTableColorFilter::CreateARGB(allOne, identity, identity, identity));
1210 SkAutoTUnref<SkImageFilter> forceOpaque(SkColorFilterImageFilter::Create(forceOpaqueCF.get()));
1211 REPORTER_ASSERT(reporter, forceOpaqueCF->affectsTransparentBlack());
1212 REPORTER_ASSERT(reporter, !forceOpaque->canComputeFastBounds());
1213}
1214
senorblanco@chromium.org58d14662014-02-03 22:36:39 +00001215#if SK_SUPPORT_GPU
reed4a8126e2014-09-22 07:29:03 -07001216
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +00001217DEF_GPUTEST(ImageFilterCropRectGPU, reporter, factory) {
1218 GrContext* context = factory->get(static_cast<GrContextFactory::GLContextType>(0));
senorblancoc8e93402015-04-21 07:20:36 -07001219 if (NULL == context) {
1220 return;
1221 }
robertphillipsefbffed2015-06-22 12:06:08 -07001222 const SkSurfaceProps props(SkSurfaceProps::kLegacyFontHost_InitType);
1223
commit-bot@chromium.org15a14052014-02-16 00:59:25 +00001224 SkAutoTUnref<SkGpuDevice> device(SkGpuDevice::Create(context,
bsalomonafe30052015-01-16 07:32:33 -08001225 SkSurface::kNo_Budgeted,
commit-bot@chromium.org15a14052014-02-16 00:59:25 +00001226 SkImageInfo::MakeN32Premul(100, 100),
bsalomonafe30052015-01-16 07:32:33 -08001227 0,
bsalomon74f681d2015-06-23 14:38:48 -07001228 &props,
1229 SkGpuDevice::kUninit_InitContents));
robertphillipsefbffed2015-06-22 12:06:08 -07001230 SkImageFilter::Proxy proxy(device);
robertphillips9a53fd72015-06-22 09:46:59 -07001231
1232 test_crop_rects(&proxy, reporter);
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +00001233}
senorblanco@chromium.org09843fd2014-03-24 20:50:59 +00001234
1235DEF_GPUTEST(HugeBlurImageFilterGPU, reporter, factory) {
1236 GrContext* context = factory->get(static_cast<GrContextFactory::GLContextType>(0));
senorblancoc8e93402015-04-21 07:20:36 -07001237 if (NULL == context) {
1238 return;
1239 }
robertphillipsefbffed2015-06-22 12:06:08 -07001240 const SkSurfaceProps props(SkSurfaceProps::kLegacyFontHost_InitType);
1241
senorblanco@chromium.org09843fd2014-03-24 20:50:59 +00001242 SkAutoTUnref<SkGpuDevice> device(SkGpuDevice::Create(context,
bsalomonafe30052015-01-16 07:32:33 -08001243 SkSurface::kNo_Budgeted,
senorblanco@chromium.org09843fd2014-03-24 20:50:59 +00001244 SkImageInfo::MakeN32Premul(100, 100),
bsalomonafe30052015-01-16 07:32:33 -08001245 0,
bsalomon74f681d2015-06-23 14:38:48 -07001246 &props,
1247 SkGpuDevice::kUninit_InitContents));
robertphillips9a53fd72015-06-22 09:46:59 -07001248 SkCanvas canvas(device);
1249
1250 test_huge_blur(&canvas, reporter);
senorblanco@chromium.org09843fd2014-03-24 20:50:59 +00001251}
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001252
1253DEF_GPUTEST(XfermodeImageFilterCroppedInputGPU, reporter, factory) {
1254 GrContext* context = factory->get(static_cast<GrContextFactory::GLContextType>(0));
senorblancoc8e93402015-04-21 07:20:36 -07001255 if (NULL == context) {
1256 return;
1257 }
robertphillipsefbffed2015-06-22 12:06:08 -07001258 const SkSurfaceProps props(SkSurfaceProps::kLegacyFontHost_InitType);
1259
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001260 SkAutoTUnref<SkGpuDevice> device(SkGpuDevice::Create(context,
bsalomonafe30052015-01-16 07:32:33 -08001261 SkSurface::kNo_Budgeted,
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001262 SkImageInfo::MakeN32Premul(1, 1),
bsalomonafe30052015-01-16 07:32:33 -08001263 0,
bsalomon74f681d2015-06-23 14:38:48 -07001264 &props,
1265 SkGpuDevice::kUninit_InitContents));
robertphillips9a53fd72015-06-22 09:46:59 -07001266 SkCanvas canvas(device);
1267
1268 test_xfermode_cropped_input(&canvas, reporter);
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001269}
senorblanco32673b92014-09-09 09:15:04 -07001270
1271DEF_GPUTEST(TestNegativeBlurSigmaGPU, reporter, factory) {
1272 GrContext* context = factory->get(static_cast<GrContextFactory::GLContextType>(0));
senorblancoc8e93402015-04-21 07:20:36 -07001273 if (NULL == context) {
1274 return;
1275 }
robertphillipsefbffed2015-06-22 12:06:08 -07001276 const SkSurfaceProps props(SkSurfaceProps::kLegacyFontHost_InitType);
1277
senorblanco32673b92014-09-09 09:15:04 -07001278 SkAutoTUnref<SkGpuDevice> device(SkGpuDevice::Create(context,
bsalomonafe30052015-01-16 07:32:33 -08001279 SkSurface::kNo_Budgeted,
senorblanco32673b92014-09-09 09:15:04 -07001280 SkImageInfo::MakeN32Premul(1, 1),
bsalomonafe30052015-01-16 07:32:33 -08001281 0,
bsalomon74f681d2015-06-23 14:38:48 -07001282 &props,
1283 SkGpuDevice::kUninit_InitContents));
robertphillipsefbffed2015-06-22 12:06:08 -07001284 SkImageFilter::Proxy proxy(device);
robertphillips9a53fd72015-06-22 09:46:59 -07001285
1286 test_negative_blur_sigma(&proxy, reporter);
senorblanco32673b92014-09-09 09:15:04 -07001287}
senorblanco@chromium.org58d14662014-02-03 22:36:39 +00001288#endif