blob: 8444bd38c327d7a0a6e46eabc4bcff282799643f [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"
fmalitacd56f812015-09-14 13:31:18 -070020#include "SkImageSource.h"
commit-bot@chromium.org4b681bc2013-09-13 12:40:02 +000021#include "SkLightingImageFilter.h"
tfarina@chromium.org8f6884a2014-01-24 20:56:26 +000022#include "SkMatrixConvolutionImageFilter.h"
senorblanco@chromium.org6776b822014-01-03 21:48:22 +000023#include "SkMergeImageFilter.h"
24#include "SkMorphologyImageFilter.h"
senorblanco@chromium.org6776b822014-01-03 21:48:22 +000025#include "SkOffsetImageFilter.h"
senorblanco8f3937d2014-10-29 12:36:32 -070026#include "SkPerlinNoiseShader.h"
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +000027#include "SkPicture.h"
senorblanco@chromium.org910702b2014-05-30 20:36:15 +000028#include "SkPictureImageFilter.h"
robertphillips@google.com770963f2014-04-18 18:04:41 +000029#include "SkPictureRecorder.h"
robertphillips3d32d762015-07-13 13:16:44 -070030#include "SkPoint3.h"
halcanary97d2c0a2014-08-19 06:27:53 -070031#include "SkReadBuffer.h"
tfarina@chromium.org8f6884a2014-01-24 20:56:26 +000032#include "SkRect.h"
senorblanco8f3937d2014-10-29 12:36:32 -070033#include "SkRectShaderImageFilter.h"
fmalitacd56f812015-09-14 13:31:18 -070034#include "SkSurface.h"
senorblanco0abdf762015-08-20 11:10:41 -070035#include "SkTableColorFilter.h"
senorblanco@chromium.org6776b822014-01-03 21:48:22 +000036#include "SkTileImageFilter.h"
37#include "SkXfermodeImageFilter.h"
tfarina@chromium.org8f6884a2014-01-24 20:56:26 +000038#include "Test.h"
senorblanco@chromium.org194d7752013-07-24 22:19:24 +000039
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +000040#if SK_SUPPORT_GPU
41#include "GrContextFactory.h"
42#include "SkGpuDevice.h"
43#endif
44
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +000045static const int kBitmapSize = 4;
commit-bot@chromium.org4b681bc2013-09-13 12:40:02 +000046
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +000047namespace {
48
49class MatrixTestImageFilter : public SkImageFilter {
50public:
51 MatrixTestImageFilter(skiatest::Reporter* reporter, const SkMatrix& expectedMatrix)
halcanary96fcdcc2015-08-27 07:41:13 -070052 : SkImageFilter(0, nullptr), fReporter(reporter), fExpectedMatrix(expectedMatrix) {
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +000053 }
54
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +000055 virtual bool onFilterImage(Proxy*, const SkBitmap& src, const Context& ctx,
mtklein36352bf2015-03-25 18:17:31 -070056 SkBitmap* result, SkIPoint* offset) const override {
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +000057 REPORTER_ASSERT(fReporter, ctx.ctm() == fExpectedMatrix);
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +000058 return true;
59 }
60
robertphillipsf3f5bad2014-12-19 13:49:15 -080061 SK_TO_STRING_OVERRIDE()
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +000062 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(MatrixTestImageFilter)
63
64protected:
mtklein36352bf2015-03-25 18:17:31 -070065 void flatten(SkWriteBuffer& buffer) const override {
reed9fa60da2014-08-21 07:59:51 -070066 this->INHERITED::flatten(buffer);
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +000067 buffer.writeFunctionPtr(fReporter);
68 buffer.writeMatrix(fExpectedMatrix);
69 }
70
71private:
72 skiatest::Reporter* fReporter;
73 SkMatrix fExpectedMatrix;
mtklein3f3b3d02014-12-01 11:47:08 -080074
reed9fa60da2014-08-21 07:59:51 -070075 typedef SkImageFilter INHERITED;
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +000076};
77
78}
79
reed9fa60da2014-08-21 07:59:51 -070080SkFlattenable* MatrixTestImageFilter::CreateProc(SkReadBuffer& buffer) {
81 SK_IMAGEFILTER_UNFLATTEN_COMMON(common, 1);
82 skiatest::Reporter* reporter = (skiatest::Reporter*)buffer.readFunctionPtr();
83 SkMatrix matrix;
84 buffer.readMatrix(&matrix);
halcanary385fe4d2015-08-26 13:07:48 -070085 return new MatrixTestImageFilter(reporter, matrix);
reed9fa60da2014-08-21 07:59:51 -070086}
87
robertphillipsf3f5bad2014-12-19 13:49:15 -080088#ifndef SK_IGNORE_TO_STRING
89void MatrixTestImageFilter::toString(SkString* str) const {
90 str->appendf("MatrixTestImageFilter: (");
91 str->append(")");
92}
93#endif
94
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +000095static void make_small_bitmap(SkBitmap& bitmap) {
mike@reedtribe.orgdeee4962014-02-13 14:41:43 +000096 bitmap.allocN32Pixels(kBitmapSize, kBitmapSize);
97 SkCanvas canvas(bitmap);
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +000098 canvas.clear(0x00000000);
99 SkPaint darkPaint;
100 darkPaint.setColor(0xFF804020);
101 SkPaint lightPaint;
102 lightPaint.setColor(0xFF244484);
103 const int i = kBitmapSize / 4;
104 for (int y = 0; y < kBitmapSize; y += i) {
105 for (int x = 0; x < kBitmapSize; x += i) {
106 canvas.save();
107 canvas.translate(SkIntToScalar(x), SkIntToScalar(y));
108 canvas.drawRect(SkRect::MakeXYWH(0, 0,
109 SkIntToScalar(i),
110 SkIntToScalar(i)), darkPaint);
111 canvas.drawRect(SkRect::MakeXYWH(SkIntToScalar(i),
112 0,
113 SkIntToScalar(i),
114 SkIntToScalar(i)), lightPaint);
115 canvas.drawRect(SkRect::MakeXYWH(0,
116 SkIntToScalar(i),
117 SkIntToScalar(i),
118 SkIntToScalar(i)), lightPaint);
119 canvas.drawRect(SkRect::MakeXYWH(SkIntToScalar(i),
120 SkIntToScalar(i),
121 SkIntToScalar(i),
122 SkIntToScalar(i)), darkPaint);
123 canvas.restore();
commit-bot@chromium.org4b681bc2013-09-13 12:40:02 +0000124 }
125 }
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000126}
senorblanco@chromium.org194d7752013-07-24 22:19:24 +0000127
halcanary96fcdcc2015-08-27 07:41:13 -0700128static SkImageFilter* make_scale(float amount, SkImageFilter* input = nullptr) {
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000129 SkScalar s = amount;
130 SkScalar matrix[20] = { s, 0, 0, 0, 0,
131 0, s, 0, 0, 0,
132 0, 0, s, 0, 0,
133 0, 0, 0, s, 0 };
commit-bot@chromium.org727a3522014-02-21 18:46:30 +0000134 SkAutoTUnref<SkColorFilter> filter(SkColorMatrixFilter::Create(matrix));
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000135 return SkColorFilterImageFilter::Create(filter, input);
136}
137
reedcedc36f2015-03-08 04:42:52 -0700138static SkImageFilter* make_grayscale(SkImageFilter* input, const SkImageFilter::CropRect* cropRect) {
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000139 SkScalar matrix[20];
140 memset(matrix, 0, 20 * sizeof(SkScalar));
141 matrix[0] = matrix[5] = matrix[10] = 0.2126f;
142 matrix[1] = matrix[6] = matrix[11] = 0.7152f;
143 matrix[2] = matrix[7] = matrix[12] = 0.0722f;
144 matrix[18] = 1.0f;
commit-bot@chromium.org727a3522014-02-21 18:46:30 +0000145 SkAutoTUnref<SkColorFilter> filter(SkColorMatrixFilter::Create(matrix));
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000146 return SkColorFilterImageFilter::Create(filter, input, cropRect);
147}
148
reedcedc36f2015-03-08 04:42:52 -0700149static SkImageFilter* make_blue(SkImageFilter* input, const SkImageFilter::CropRect* cropRect) {
150 SkAutoTUnref<SkColorFilter> filter(SkColorFilter::CreateModeFilter(SK_ColorBLUE,
151 SkXfermode::kSrcIn_Mode));
152 return SkColorFilterImageFilter::Create(filter, input, cropRect);
153}
154
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000155DEF_TEST(ImageFilter, reporter) {
156 {
reedcedc36f2015-03-08 04:42:52 -0700157 // Check that two non-clipping color-matrice-filters concatenate into a single filter.
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000158 SkAutoTUnref<SkImageFilter> halfBrightness(make_scale(0.5f));
159 SkAutoTUnref<SkImageFilter> quarterBrightness(make_scale(0.5f, halfBrightness));
halcanary96fcdcc2015-08-27 07:41:13 -0700160 REPORTER_ASSERT(reporter, nullptr == quarterBrightness->getInput(0));
reedcedc36f2015-03-08 04:42:52 -0700161 SkColorFilter* cf;
162 REPORTER_ASSERT(reporter, quarterBrightness->asColorFilter(&cf));
halcanary96fcdcc2015-08-27 07:41:13 -0700163 REPORTER_ASSERT(reporter, cf->asColorMatrix(nullptr));
reedcedc36f2015-03-08 04:42:52 -0700164 cf->unref();
senorblanco@chromium.org194d7752013-07-24 22:19:24 +0000165 }
166
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000167 {
reedcedc36f2015-03-08 04:42:52 -0700168 // Check that a clipping color-matrice-filter followed by a color-matrice-filters
169 // concatenates into a single filter, but not a matrixfilter (due to clamping).
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000170 SkAutoTUnref<SkImageFilter> doubleBrightness(make_scale(2.0f));
171 SkAutoTUnref<SkImageFilter> halfBrightness(make_scale(0.5f, doubleBrightness));
halcanary96fcdcc2015-08-27 07:41:13 -0700172 REPORTER_ASSERT(reporter, nullptr == halfBrightness->getInput(0));
reedcedc36f2015-03-08 04:42:52 -0700173 SkColorFilter* cf;
174 REPORTER_ASSERT(reporter, halfBrightness->asColorFilter(&cf));
halcanary96fcdcc2015-08-27 07:41:13 -0700175 REPORTER_ASSERT(reporter, !cf->asColorMatrix(nullptr));
reedcedc36f2015-03-08 04:42:52 -0700176 cf->unref();
senorblanco@chromium.org194d7752013-07-24 22:19:24 +0000177 }
178
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000179 {
180 // Check that a color filter image filter without a crop rect can be
181 // expressed as a color filter.
halcanary96fcdcc2015-08-27 07:41:13 -0700182 SkAutoTUnref<SkImageFilter> gray(make_grayscale(nullptr, nullptr));
183 REPORTER_ASSERT(reporter, true == gray->asColorFilter(nullptr));
senorblanco@chromium.org194d7752013-07-24 22:19:24 +0000184 }
reedcedc36f2015-03-08 04:42:52 -0700185
186 {
187 // Check that a colorfilterimage filter without a crop rect but with an input
188 // that is another colorfilterimage can be expressed as a colorfilter (composed).
halcanary96fcdcc2015-08-27 07:41:13 -0700189 SkAutoTUnref<SkImageFilter> mode(make_blue(nullptr, nullptr));
190 SkAutoTUnref<SkImageFilter> gray(make_grayscale(mode, nullptr));
191 REPORTER_ASSERT(reporter, true == gray->asColorFilter(nullptr));
reedcedc36f2015-03-08 04:42:52 -0700192 }
193
194 {
195 // Test that if we exceed the limit of what ComposeColorFilter can combine, we still
196 // can build the DAG and won't assert if we call asColorFilter.
halcanary96fcdcc2015-08-27 07:41:13 -0700197 SkAutoTUnref<SkImageFilter> filter(make_blue(nullptr, nullptr));
reedcedc36f2015-03-08 04:42:52 -0700198 const int kWayTooManyForComposeColorFilter = 100;
199 for (int i = 0; i < kWayTooManyForComposeColorFilter; ++i) {
halcanary96fcdcc2015-08-27 07:41:13 -0700200 filter.reset(make_blue(filter, nullptr));
reedcedc36f2015-03-08 04:42:52 -0700201 // the first few of these will succeed, but after we hit the internal limit,
202 // it will then return false.
halcanary96fcdcc2015-08-27 07:41:13 -0700203 (void)filter->asColorFilter(nullptr);
reedcedc36f2015-03-08 04:42:52 -0700204 }
205 }
reed5c518a82015-03-05 14:47:29 -0800206
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000207 {
208 // Check that a color filter image filter with a crop rect cannot
209 // be expressed as a color filter.
210 SkImageFilter::CropRect cropRect(SkRect::MakeXYWH(0, 0, 100, 100));
halcanary96fcdcc2015-08-27 07:41:13 -0700211 SkAutoTUnref<SkImageFilter> grayWithCrop(make_grayscale(nullptr, &cropRect));
212 REPORTER_ASSERT(reporter, false == grayWithCrop->asColorFilter(nullptr));
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000213 }
214
215 {
senorblanco3df05012014-07-03 11:13:09 -0700216 // Check that two non-commutative matrices are concatenated in
217 // the correct order.
218 SkScalar blueToRedMatrix[20] = { 0 };
219 blueToRedMatrix[2] = blueToRedMatrix[18] = SK_Scalar1;
220 SkScalar redToGreenMatrix[20] = { 0 };
221 redToGreenMatrix[5] = redToGreenMatrix[18] = SK_Scalar1;
222 SkAutoTUnref<SkColorFilter> blueToRed(SkColorMatrixFilter::Create(blueToRedMatrix));
223 SkAutoTUnref<SkImageFilter> filter1(SkColorFilterImageFilter::Create(blueToRed.get()));
224 SkAutoTUnref<SkColorFilter> redToGreen(SkColorMatrixFilter::Create(redToGreenMatrix));
225 SkAutoTUnref<SkImageFilter> filter2(SkColorFilterImageFilter::Create(redToGreen.get(), filter1.get()));
226
227 SkBitmap result;
228 result.allocN32Pixels(kBitmapSize, kBitmapSize);
229
230 SkPaint paint;
231 paint.setColor(SK_ColorBLUE);
232 paint.setImageFilter(filter2.get());
233 SkCanvas canvas(result);
234 canvas.clear(0x0);
235 SkRect rect = SkRect::Make(SkIRect::MakeWH(kBitmapSize, kBitmapSize));
236 canvas.drawRect(rect, paint);
237 uint32_t pixel = *result.getAddr32(0, 0);
238 // The result here should be green, since we have effectively shifted blue to green.
239 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
240 }
241
242 {
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000243 // Tests pass by not asserting
244 SkBitmap bitmap, result;
245 make_small_bitmap(bitmap);
mike@reedtribe.orgdeee4962014-02-13 14:41:43 +0000246 result.allocN32Pixels(kBitmapSize, kBitmapSize);
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000247
senorblanco@chromium.org194d7752013-07-24 22:19:24 +0000248 {
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000249 // This tests for :
250 // 1 ) location at (0,0,1)
robertphillips3d32d762015-07-13 13:16:44 -0700251 SkPoint3 location = SkPoint3::Make(0, 0, SK_Scalar1);
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000252 // 2 ) location and target at same value
robertphillips3d32d762015-07-13 13:16:44 -0700253 SkPoint3 target = SkPoint3::Make(location.fX, location.fY, location.fZ);
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000254 // 3 ) large negative specular exponent value
255 SkScalar specularExponent = -1000;
256
commit-bot@chromium.orgcac5fd52014-03-10 10:51:58 +0000257 SkAutoTUnref<SkImageFilter> bmSrc(SkBitmapSource::Create(bitmap));
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000258 SkPaint paint;
259 paint.setImageFilter(SkLightingImageFilter::CreateSpotLitSpecular(
260 location, target, specularExponent, 180,
261 0xFFFFFFFF, SK_Scalar1, SK_Scalar1, SK_Scalar1,
262 bmSrc))->unref();
263 SkCanvas canvas(result);
264 SkRect r = SkRect::MakeWH(SkIntToScalar(kBitmapSize),
265 SkIntToScalar(kBitmapSize));
266 canvas.drawRect(r, paint);
senorblanco@chromium.org194d7752013-07-24 22:19:24 +0000267 }
senorblanco@chromium.org194d7752013-07-24 22:19:24 +0000268 }
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +0000269}
senorblanco@chromium.org6776b822014-01-03 21:48:22 +0000270
robertphillips9a53fd72015-06-22 09:46:59 -0700271static void test_crop_rects(SkImageFilter::Proxy* proxy, skiatest::Reporter* reporter) {
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +0000272 // Check that all filters offset to their absolute crop rect,
273 // unaffected by the input crop rect.
274 // Tests pass by not asserting.
275 SkBitmap bitmap;
mike@reedtribe.orgdeee4962014-02-13 14:41:43 +0000276 bitmap.allocN32Pixels(100, 100);
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +0000277 bitmap.eraseARGB(0, 0, 0, 0);
senorblanco@chromium.org6776b822014-01-03 21:48:22 +0000278
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +0000279 SkImageFilter::CropRect inputCropRect(SkRect::MakeXYWH(8, 13, 80, 80));
280 SkImageFilter::CropRect cropRect(SkRect::MakeXYWH(20, 30, 60, 60));
halcanary96fcdcc2015-08-27 07:41:13 -0700281 SkAutoTUnref<SkImageFilter> input(make_grayscale(nullptr, &inputCropRect));
senorblanco@chromium.org6776b822014-01-03 21:48:22 +0000282
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +0000283 SkAutoTUnref<SkColorFilter> cf(SkColorFilter::CreateModeFilter(SK_ColorRED, SkXfermode::kSrcIn_Mode));
robertphillips3d32d762015-07-13 13:16:44 -0700284 SkPoint3 location = SkPoint3::Make(0, 0, SK_Scalar1);
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +0000285 SkScalar kernel[9] = {
286 SkIntToScalar( 1), SkIntToScalar( 1), SkIntToScalar( 1),
287 SkIntToScalar( 1), SkIntToScalar(-7), SkIntToScalar( 1),
288 SkIntToScalar( 1), SkIntToScalar( 1), SkIntToScalar( 1),
289 };
290 SkISize kernelSize = SkISize::Make(3, 3);
291 SkScalar gain = SK_Scalar1, bias = 0;
senorblanco@chromium.org6776b822014-01-03 21:48:22 +0000292
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +0000293 SkImageFilter* filters[] = {
294 SkColorFilterImageFilter::Create(cf.get(), input.get(), &cropRect),
commit-bot@chromium.orgcac5fd52014-03-10 10:51:58 +0000295 SkDisplacementMapEffect::Create(SkDisplacementMapEffect::kR_ChannelSelectorType,
296 SkDisplacementMapEffect::kB_ChannelSelectorType,
297 40.0f, input.get(), input.get(), &cropRect),
298 SkBlurImageFilter::Create(SK_Scalar1, SK_Scalar1, input.get(), &cropRect),
sugoi234f0362014-10-23 13:59:52 -0700299 SkDropShadowImageFilter::Create(SK_Scalar1, SK_Scalar1, SK_Scalar1, SK_Scalar1,
300 SK_ColorGREEN, SkDropShadowImageFilter::kDrawShadowAndForeground_ShadowMode,
senorblanco24e06d52015-03-18 12:11:33 -0700301 input.get(), &cropRect),
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +0000302 SkLightingImageFilter::CreatePointLitDiffuse(location, SK_ColorGREEN, 0, 0, input.get(), &cropRect),
303 SkLightingImageFilter::CreatePointLitSpecular(location, SK_ColorGREEN, 0, 0, 0, input.get(), &cropRect),
commit-bot@chromium.orgcac5fd52014-03-10 10:51:58 +0000304 SkMatrixConvolutionImageFilter::Create(kernelSize, kernel, gain, bias, SkIPoint::Make(1, 1), SkMatrixConvolutionImageFilter::kRepeat_TileMode, false, input.get(), &cropRect),
305 SkMergeImageFilter::Create(input.get(), input.get(), SkXfermode::kSrcOver_Mode, &cropRect),
306 SkOffsetImageFilter::Create(SK_Scalar1, SK_Scalar1, input.get(), &cropRect),
307 SkOffsetImageFilter::Create(SK_Scalar1, SK_Scalar1, input.get(), &cropRect),
308 SkDilateImageFilter::Create(3, 2, input.get(), &cropRect),
309 SkErodeImageFilter::Create(2, 3, input.get(), &cropRect),
310 SkTileImageFilter::Create(inputCropRect.rect(), cropRect.rect(), input.get()),
311 SkXfermodeImageFilter::Create(SkXfermode::Create(SkXfermode::kSrcOver_Mode), input.get(), input.get(), &cropRect),
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +0000312 };
senorblanco@chromium.org6776b822014-01-03 21:48:22 +0000313
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +0000314 for (size_t i = 0; i < SK_ARRAY_COUNT(filters); ++i) {
315 SkImageFilter* filter = filters[i];
316 SkBitmap result;
317 SkIPoint offset;
318 SkString str;
senorblanco@chromium.orgf4e1a762014-02-04 00:28:46 +0000319 str.printf("filter %d", static_cast<int>(i));
halcanary96fcdcc2015-08-27 07:41:13 -0700320 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeLargest(), nullptr);
robertphillips9a53fd72015-06-22 09:46:59 -0700321 REPORTER_ASSERT_MESSAGE(reporter, filter->filterImage(proxy, bitmap, ctx,
commit-bot@chromium.orgf7efa502014-04-11 18:57:00 +0000322 &result, &offset), str.c_str());
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +0000323 REPORTER_ASSERT_MESSAGE(reporter, offset.fX == 20 && offset.fY == 30, str.c_str());
senorblanco@chromium.org6776b822014-01-03 21:48:22 +0000324 }
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +0000325
326 for (size_t i = 0; i < SK_ARRAY_COUNT(filters); ++i) {
327 SkSafeUnref(filters[i]);
328 }
329}
330
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +0000331static SkBitmap make_gradient_circle(int width, int height) {
332 SkBitmap bitmap;
333 SkScalar x = SkIntToScalar(width / 2);
334 SkScalar y = SkIntToScalar(height / 2);
335 SkScalar radius = SkMinScalar(x, y) * 0.8f;
336 bitmap.allocN32Pixels(width, height);
337 SkCanvas canvas(bitmap);
338 canvas.clear(0x00000000);
339 SkColor colors[2];
340 colors[0] = SK_ColorWHITE;
341 colors[1] = SK_ColorBLACK;
342 SkAutoTUnref<SkShader> shader(
halcanary96fcdcc2015-08-27 07:41:13 -0700343 SkGradientShader::CreateRadial(SkPoint::Make(x, y), radius, colors, nullptr, 2,
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +0000344 SkShader::kClamp_TileMode)
345 );
346 SkPaint paint;
347 paint.setShader(shader);
348 canvas.drawCircle(x, y, radius, paint);
349 return bitmap;
350}
351
robertphillips9a53fd72015-06-22 09:46:59 -0700352static void test_negative_blur_sigma(SkImageFilter::Proxy* proxy, skiatest::Reporter* reporter) {
senorblanco32673b92014-09-09 09:15:04 -0700353 // Check that SkBlurImageFilter will accept a negative sigma, either in
354 // the given arguments or after CTM application.
355 int width = 32, height = 32;
senorblanco32673b92014-09-09 09:15:04 -0700356 SkScalar five = SkIntToScalar(5);
357
358 SkAutoTUnref<SkBlurImageFilter> positiveFilter(
359 SkBlurImageFilter::Create(five, five)
360 );
361
362 SkAutoTUnref<SkBlurImageFilter> negativeFilter(
363 SkBlurImageFilter::Create(-five, five)
364 );
365
366 SkBitmap gradient = make_gradient_circle(width, height);
367 SkBitmap positiveResult1, negativeResult1;
368 SkBitmap positiveResult2, negativeResult2;
369 SkIPoint offset;
halcanary96fcdcc2015-08-27 07:41:13 -0700370 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeLargest(), nullptr);
robertphillips9a53fd72015-06-22 09:46:59 -0700371 positiveFilter->filterImage(proxy, gradient, ctx, &positiveResult1, &offset);
372 negativeFilter->filterImage(proxy, gradient, ctx, &negativeResult1, &offset);
senorblanco32673b92014-09-09 09:15:04 -0700373 SkMatrix negativeScale;
374 negativeScale.setScale(-SK_Scalar1, SK_Scalar1);
halcanary96fcdcc2015-08-27 07:41:13 -0700375 SkImageFilter::Context negativeCTX(negativeScale, SkIRect::MakeLargest(), nullptr);
robertphillips9a53fd72015-06-22 09:46:59 -0700376 positiveFilter->filterImage(proxy, gradient, negativeCTX, &negativeResult2, &offset);
377 negativeFilter->filterImage(proxy, gradient, negativeCTX, &positiveResult2, &offset);
senorblanco32673b92014-09-09 09:15:04 -0700378 SkAutoLockPixels lockP1(positiveResult1);
379 SkAutoLockPixels lockP2(positiveResult2);
380 SkAutoLockPixels lockN1(negativeResult1);
381 SkAutoLockPixels lockN2(negativeResult2);
382 for (int y = 0; y < height; y++) {
383 int diffs = memcmp(positiveResult1.getAddr32(0, y), negativeResult1.getAddr32(0, y), positiveResult1.rowBytes());
384 REPORTER_ASSERT(reporter, !diffs);
385 if (diffs) {
386 break;
387 }
388 diffs = memcmp(positiveResult1.getAddr32(0, y), negativeResult2.getAddr32(0, y), positiveResult1.rowBytes());
389 REPORTER_ASSERT(reporter, !diffs);
390 if (diffs) {
391 break;
392 }
393 diffs = memcmp(positiveResult1.getAddr32(0, y), positiveResult2.getAddr32(0, y), positiveResult1.rowBytes());
394 REPORTER_ASSERT(reporter, !diffs);
395 if (diffs) {
396 break;
397 }
398 }
399}
400
401DEF_TEST(TestNegativeBlurSigma, reporter) {
robertphillips9a53fd72015-06-22 09:46:59 -0700402 const SkImageInfo info = SkImageInfo::MakeN32Premul(100, 100);
403 const SkSurfaceProps props(SkSurfaceProps::kLegacyFontHost_InitType);
404
405 SkAutoTUnref<SkBaseDevice> device(SkBitmapDevice::Create(info, props));
robertphillipsefbffed2015-06-22 12:06:08 -0700406 SkImageFilter::Proxy proxy(device);
robertphillips9a53fd72015-06-22 09:46:59 -0700407
408 test_negative_blur_sigma(&proxy, reporter);
senorblanco32673b92014-09-09 09:15:04 -0700409}
410
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +0000411DEF_TEST(ImageFilterDrawTiled, reporter) {
412 // Check that all filters when drawn tiled (with subsequent clip rects) exactly
413 // match the same filters drawn with a single full-canvas bitmap draw.
414 // Tests pass by not asserting.
415
416 SkAutoTUnref<SkColorFilter> cf(SkColorFilter::CreateModeFilter(SK_ColorRED, SkXfermode::kSrcIn_Mode));
robertphillips3d32d762015-07-13 13:16:44 -0700417 SkPoint3 location = SkPoint3::Make(0, 0, SK_Scalar1);
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +0000418 SkScalar kernel[9] = {
419 SkIntToScalar( 1), SkIntToScalar( 1), SkIntToScalar( 1),
420 SkIntToScalar( 1), SkIntToScalar(-7), SkIntToScalar( 1),
421 SkIntToScalar( 1), SkIntToScalar( 1), SkIntToScalar( 1),
422 };
423 SkISize kernelSize = SkISize::Make(3, 3);
424 SkScalar gain = SK_Scalar1, bias = 0;
senorblanco@chromium.org29ac34e2014-05-28 19:29:25 +0000425 SkScalar five = SkIntToScalar(5);
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +0000426
427 SkAutoTUnref<SkImageFilter> gradient_source(SkBitmapSource::Create(make_gradient_circle(64, 64)));
senorblanco@chromium.org29ac34e2014-05-28 19:29:25 +0000428 SkAutoTUnref<SkImageFilter> blur(SkBlurImageFilter::Create(five, five));
senorblanco@chromium.orgba31f1d2014-05-07 20:56:08 +0000429 SkMatrix matrix;
senorblanco@chromium.org29ac34e2014-05-28 19:29:25 +0000430
senorblanco@chromium.orgba31f1d2014-05-07 20:56:08 +0000431 matrix.setTranslate(SK_Scalar1, SK_Scalar1);
432 matrix.postRotate(SkIntToScalar(45), SK_Scalar1, SK_Scalar1);
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +0000433
senorblanco@chromium.org910702b2014-05-30 20:36:15 +0000434 SkRTreeFactory factory;
435 SkPictureRecorder recorder;
436 SkCanvas* recordingCanvas = recorder.beginRecording(64, 64, &factory, 0);
437
438 SkPaint greenPaint;
439 greenPaint.setColor(SK_ColorGREEN);
440 recordingCanvas->drawRect(SkRect::Make(SkIRect::MakeXYWH(10, 10, 30, 20)), greenPaint);
441 SkAutoTUnref<SkPicture> picture(recorder.endRecording());
442 SkAutoTUnref<SkImageFilter> pictureFilter(SkPictureImageFilter::Create(picture.get()));
senorblanco8f3937d2014-10-29 12:36:32 -0700443 SkAutoTUnref<SkShader> shader(SkPerlinNoiseShader::CreateTurbulence(SK_Scalar1, SK_Scalar1, 1, 0));
444
445 SkAutoTUnref<SkImageFilter> rectShaderFilter(SkRectShaderImageFilter::Create(shader.get()));
senorblanco@chromium.org910702b2014-05-30 20:36:15 +0000446
fsd8b57712015-05-20 00:52:17 -0700447 SkAutoTUnref<SkShader> greenColorShader(SkShader::CreateColorShader(SK_ColorGREEN));
448 SkImageFilter::CropRect leftSideCropRect(SkRect::MakeXYWH(0, 0, 32, 64));
449 SkAutoTUnref<SkImageFilter> rectShaderFilterLeft(SkRectShaderImageFilter::Create(greenColorShader.get(), &leftSideCropRect));
450 SkImageFilter::CropRect rightSideCropRect(SkRect::MakeXYWH(32, 0, 32, 64));
451 SkAutoTUnref<SkImageFilter> rectShaderFilterRight(SkRectShaderImageFilter::Create(greenColorShader.get(), &rightSideCropRect));
452
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +0000453 struct {
454 const char* fName;
455 SkImageFilter* fFilter;
456 } filters[] = {
457 { "color filter", SkColorFilterImageFilter::Create(cf.get()) },
458 { "displacement map", SkDisplacementMapEffect::Create(
459 SkDisplacementMapEffect::kR_ChannelSelectorType,
460 SkDisplacementMapEffect::kB_ChannelSelectorType,
senorblanco@chromium.orgd4db6572014-05-07 20:00:04 +0000461 20.0f, gradient_source.get()) },
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +0000462 { "blur", SkBlurImageFilter::Create(SK_Scalar1, SK_Scalar1) },
463 { "drop shadow", SkDropShadowImageFilter::Create(
sugoi234f0362014-10-23 13:59:52 -0700464 SK_Scalar1, SK_Scalar1, SK_Scalar1, SK_Scalar1, SK_ColorGREEN,
465 SkDropShadowImageFilter::kDrawShadowAndForeground_ShadowMode) },
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +0000466 { "diffuse lighting", SkLightingImageFilter::CreatePointLitDiffuse(
467 location, SK_ColorGREEN, 0, 0) },
468 { "specular lighting",
469 SkLightingImageFilter::CreatePointLitSpecular(location, SK_ColorGREEN, 0, 0, 0) },
470 { "matrix convolution",
471 SkMatrixConvolutionImageFilter::Create(
472 kernelSize, kernel, gain, bias, SkIPoint::Make(1, 1),
473 SkMatrixConvolutionImageFilter::kRepeat_TileMode, false) },
halcanary96fcdcc2015-08-27 07:41:13 -0700474 { "merge", SkMergeImageFilter::Create(nullptr, nullptr, SkXfermode::kSrcOver_Mode) },
fsd8b57712015-05-20 00:52:17 -0700475 { "merge with disjoint inputs", SkMergeImageFilter::Create(
476 rectShaderFilterLeft, rectShaderFilterRight, SkXfermode::kSrcOver_Mode) },
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +0000477 { "offset", SkOffsetImageFilter::Create(SK_Scalar1, SK_Scalar1) },
478 { "dilate", SkDilateImageFilter::Create(3, 2) },
479 { "erode", SkErodeImageFilter::Create(2, 3) },
480 { "tile", SkTileImageFilter::Create(SkRect::MakeXYWH(0, 0, 50, 50),
halcanary96fcdcc2015-08-27 07:41:13 -0700481 SkRect::MakeXYWH(0, 0, 100, 100), nullptr) },
senorblanco8c874ee2015-03-20 06:38:17 -0700482 { "matrix", SkImageFilter::CreateMatrixFilter(matrix, kLow_SkFilterQuality) },
senorblanco@chromium.org29ac34e2014-05-28 19:29:25 +0000483 { "blur and offset", SkOffsetImageFilter::Create(five, five, blur.get()) },
senorblanco@chromium.org910702b2014-05-30 20:36:15 +0000484 { "picture and blur", SkBlurImageFilter::Create(five, five, pictureFilter.get()) },
senorblanco8f3937d2014-10-29 12:36:32 -0700485 { "rect shader and blur", SkBlurImageFilter::Create(five, five, rectShaderFilter.get()) },
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +0000486 };
487
488 SkBitmap untiledResult, tiledResult;
489 int width = 64, height = 64;
490 untiledResult.allocN32Pixels(width, height);
491 tiledResult.allocN32Pixels(width, height);
492 SkCanvas tiledCanvas(tiledResult);
493 SkCanvas untiledCanvas(untiledResult);
senorblanco@chromium.orgd4db6572014-05-07 20:00:04 +0000494 int tileSize = 8;
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +0000495
senorblanco@chromium.orgd4db6572014-05-07 20:00:04 +0000496 for (int scale = 1; scale <= 2; ++scale) {
497 for (size_t i = 0; i < SK_ARRAY_COUNT(filters); ++i) {
498 tiledCanvas.clear(0);
499 untiledCanvas.clear(0);
500 SkPaint paint;
501 paint.setImageFilter(filters[i].fFilter);
502 paint.setTextSize(SkIntToScalar(height));
503 paint.setColor(SK_ColorWHITE);
504 SkString str;
505 const char* text = "ABC";
506 SkScalar ypos = SkIntToScalar(height);
507 untiledCanvas.save();
508 untiledCanvas.scale(SkIntToScalar(scale), SkIntToScalar(scale));
509 untiledCanvas.drawText(text, strlen(text), 0, ypos, paint);
510 untiledCanvas.restore();
511 for (int y = 0; y < height; y += tileSize) {
512 for (int x = 0; x < width; x += tileSize) {
513 tiledCanvas.save();
514 tiledCanvas.clipRect(SkRect::Make(SkIRect::MakeXYWH(x, y, tileSize, tileSize)));
515 tiledCanvas.scale(SkIntToScalar(scale), SkIntToScalar(scale));
516 tiledCanvas.drawText(text, strlen(text), 0, ypos, paint);
517 tiledCanvas.restore();
518 }
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +0000519 }
senorblanco@chromium.orgd4db6572014-05-07 20:00:04 +0000520 untiledCanvas.flush();
521 tiledCanvas.flush();
522 for (int y = 0; y < height; y++) {
523 int diffs = memcmp(untiledResult.getAddr32(0, y), tiledResult.getAddr32(0, y), untiledResult.rowBytes());
524 REPORTER_ASSERT_MESSAGE(reporter, !diffs, filters[i].fName);
525 if (diffs) {
526 break;
527 }
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +0000528 }
529 }
530 }
531
532 for (size_t i = 0; i < SK_ARRAY_COUNT(filters); ++i) {
533 SkSafeUnref(filters[i].fFilter);
534 }
535}
536
mtklein3f3b3d02014-12-01 11:47:08 -0800537static void draw_saveLayer_picture(int width, int height, int tileSize,
robertphillipsa8d7f0b2014-08-29 08:03:56 -0700538 SkBBHFactory* factory, SkBitmap* result) {
mtkleind910f542014-08-22 09:06:34 -0700539
540 SkMatrix matrix;
541 matrix.setTranslate(SkIntToScalar(50), 0);
542
543 SkAutoTUnref<SkColorFilter> cf(SkColorFilter::CreateModeFilter(SK_ColorWHITE, SkXfermode::kSrc_Mode));
544 SkAutoTUnref<SkImageFilter> cfif(SkColorFilterImageFilter::Create(cf.get()));
senorblanco8c874ee2015-03-20 06:38:17 -0700545 SkAutoTUnref<SkImageFilter> imageFilter(SkImageFilter::CreateMatrixFilter(matrix, kNone_SkFilterQuality, cfif.get()));
mtkleind910f542014-08-22 09:06:34 -0700546
547 SkPaint paint;
548 paint.setImageFilter(imageFilter.get());
549 SkPictureRecorder recorder;
550 SkRect bounds = SkRect::Make(SkIRect::MakeXYWH(0, 0, 50, 50));
mtklein3f3b3d02014-12-01 11:47:08 -0800551 SkCanvas* recordingCanvas = recorder.beginRecording(SkIntToScalar(width),
552 SkIntToScalar(height),
robertphillipsa8d7f0b2014-08-29 08:03:56 -0700553 factory, 0);
mtkleind910f542014-08-22 09:06:34 -0700554 recordingCanvas->translate(-55, 0);
555 recordingCanvas->saveLayer(&bounds, &paint);
556 recordingCanvas->restore();
557 SkAutoTUnref<SkPicture> picture1(recorder.endRecording());
558
559 result->allocN32Pixels(width, height);
560 SkCanvas canvas(*result);
561 canvas.clear(0);
562 canvas.clipRect(SkRect::Make(SkIRect::MakeWH(tileSize, tileSize)));
563 canvas.drawPicture(picture1.get());
564}
565
566DEF_TEST(ImageFilterDrawMatrixBBH, reporter) {
567 // Check that matrix filter when drawn tiled with BBH exactly
568 // matches the same thing drawn without BBH.
569 // Tests pass by not asserting.
570
571 const int width = 200, height = 200;
572 const int tileSize = 100;
573 SkBitmap result1, result2;
574 SkRTreeFactory factory;
575
robertphillipsa8d7f0b2014-08-29 08:03:56 -0700576 draw_saveLayer_picture(width, height, tileSize, &factory, &result1);
halcanary96fcdcc2015-08-27 07:41:13 -0700577 draw_saveLayer_picture(width, height, tileSize, nullptr, &result2);
mtkleind910f542014-08-22 09:06:34 -0700578
579 for (int y = 0; y < height; y++) {
580 int diffs = memcmp(result1.getAddr32(0, y), result2.getAddr32(0, y), result1.rowBytes());
581 REPORTER_ASSERT(reporter, !diffs);
582 if (diffs) {
583 break;
584 }
585 }
586}
587
halcanary96fcdcc2015-08-27 07:41:13 -0700588static SkImageFilter* makeBlur(SkImageFilter* input = nullptr) {
senorblanco1150a6d2014-08-25 12:46:58 -0700589 return SkBlurImageFilter::Create(SK_Scalar1, SK_Scalar1, input);
590}
591
halcanary96fcdcc2015-08-27 07:41:13 -0700592static SkImageFilter* makeDropShadow(SkImageFilter* input = nullptr) {
senorblanco1150a6d2014-08-25 12:46:58 -0700593 return SkDropShadowImageFilter::Create(
594 SkIntToScalar(100), SkIntToScalar(100),
595 SkIntToScalar(10), SkIntToScalar(10),
sugoi234f0362014-10-23 13:59:52 -0700596 SK_ColorBLUE, SkDropShadowImageFilter::kDrawShadowAndForeground_ShadowMode,
halcanary96fcdcc2015-08-27 07:41:13 -0700597 input, nullptr);
senorblanco1150a6d2014-08-25 12:46:58 -0700598}
599
600DEF_TEST(ImageFilterBlurThenShadowBounds, reporter) {
601 SkAutoTUnref<SkImageFilter> filter1(makeBlur());
602 SkAutoTUnref<SkImageFilter> filter2(makeDropShadow(filter1.get()));
603
604 SkIRect bounds = SkIRect::MakeXYWH(0, 0, 100, 100);
605 SkIRect expectedBounds = SkIRect::MakeXYWH(-133, -133, 236, 236);
606 filter2->filterBounds(bounds, SkMatrix::I(), &bounds);
607
608 REPORTER_ASSERT(reporter, bounds == expectedBounds);
609}
610
611DEF_TEST(ImageFilterShadowThenBlurBounds, reporter) {
612 SkAutoTUnref<SkImageFilter> filter1(makeDropShadow());
613 SkAutoTUnref<SkImageFilter> filter2(makeBlur(filter1.get()));
614
615 SkIRect bounds = SkIRect::MakeXYWH(0, 0, 100, 100);
616 SkIRect expectedBounds = SkIRect::MakeXYWH(-133, -133, 236, 236);
617 filter2->filterBounds(bounds, SkMatrix::I(), &bounds);
618
619 REPORTER_ASSERT(reporter, bounds == expectedBounds);
620}
621
622DEF_TEST(ImageFilterDilateThenBlurBounds, reporter) {
623 SkAutoTUnref<SkImageFilter> filter1(SkDilateImageFilter::Create(2, 2));
624 SkAutoTUnref<SkImageFilter> filter2(makeDropShadow(filter1.get()));
625
626 SkIRect bounds = SkIRect::MakeXYWH(0, 0, 100, 100);
627 SkIRect expectedBounds = SkIRect::MakeXYWH(-132, -132, 234, 234);
628 filter2->filterBounds(bounds, SkMatrix::I(), &bounds);
629
630 REPORTER_ASSERT(reporter, bounds == expectedBounds);
631}
632
ajuma5788faa2015-02-13 09:05:47 -0800633DEF_TEST(ImageFilterComposedBlurFastBounds, reporter) {
634 SkAutoTUnref<SkImageFilter> filter1(makeBlur());
635 SkAutoTUnref<SkImageFilter> filter2(makeBlur());
636 SkAutoTUnref<SkImageFilter> composedFilter(SkComposeImageFilter::Create(filter1.get(), filter2.get()));
637
638 SkRect boundsSrc = SkRect::MakeWH(SkIntToScalar(100), SkIntToScalar(100));
639 SkRect expectedBounds = SkRect::MakeXYWH(
640 SkIntToScalar(-6), SkIntToScalar(-6), SkIntToScalar(112), SkIntToScalar(112));
641 SkRect boundsDst = SkRect::MakeEmpty();
642 composedFilter->computeFastBounds(boundsSrc, &boundsDst);
643
644 REPORTER_ASSERT(reporter, boundsDst == expectedBounds);
645}
646
robertphillipsa8d7f0b2014-08-29 08:03:56 -0700647static void draw_blurred_rect(SkCanvas* canvas) {
senorblanco837f5322014-07-14 10:19:54 -0700648 SkAutoTUnref<SkImageFilter> filter(SkBlurImageFilter::Create(SkIntToScalar(8), 0));
649 SkPaint filterPaint;
650 filterPaint.setColor(SK_ColorWHITE);
651 filterPaint.setImageFilter(filter);
halcanary96fcdcc2015-08-27 07:41:13 -0700652 canvas->saveLayer(nullptr, &filterPaint);
senorblanco837f5322014-07-14 10:19:54 -0700653 SkPaint whitePaint;
654 whitePaint.setColor(SK_ColorWHITE);
655 canvas->drawRect(SkRect::Make(SkIRect::MakeWH(4, 4)), whitePaint);
656 canvas->restore();
657}
658
robertphillipsa8d7f0b2014-08-29 08:03:56 -0700659static void draw_picture_clipped(SkCanvas* canvas, const SkRect& clipRect, const SkPicture* picture) {
senorblanco837f5322014-07-14 10:19:54 -0700660 canvas->save();
661 canvas->clipRect(clipRect);
662 canvas->drawPicture(picture);
663 canvas->restore();
664}
665
666DEF_TEST(ImageFilterDrawTiledBlurRTree, reporter) {
667 // Check that the blur filter when recorded with RTree acceleration,
668 // and drawn tiled (with subsequent clip rects) exactly
669 // matches the same filter drawn with without RTree acceleration.
670 // This tests that the "bleed" from the blur into the otherwise-blank
671 // tiles is correctly rendered.
672 // Tests pass by not asserting.
673
674 int width = 16, height = 8;
675 SkBitmap result1, result2;
676 result1.allocN32Pixels(width, height);
677 result2.allocN32Pixels(width, height);
678 SkCanvas canvas1(result1);
679 SkCanvas canvas2(result2);
680 int tileSize = 8;
681
682 canvas1.clear(0);
683 canvas2.clear(0);
684
685 SkRTreeFactory factory;
686
687 SkPictureRecorder recorder1, recorder2;
688 // The only difference between these two pictures is that one has RTree aceleration.
mtklein3f3b3d02014-12-01 11:47:08 -0800689 SkCanvas* recordingCanvas1 = recorder1.beginRecording(SkIntToScalar(width),
690 SkIntToScalar(height),
halcanary96fcdcc2015-08-27 07:41:13 -0700691 nullptr, 0);
mtklein3f3b3d02014-12-01 11:47:08 -0800692 SkCanvas* recordingCanvas2 = recorder2.beginRecording(SkIntToScalar(width),
693 SkIntToScalar(height),
robertphillipsa8d7f0b2014-08-29 08:03:56 -0700694 &factory, 0);
695 draw_blurred_rect(recordingCanvas1);
696 draw_blurred_rect(recordingCanvas2);
senorblanco837f5322014-07-14 10:19:54 -0700697 SkAutoTUnref<SkPicture> picture1(recorder1.endRecording());
698 SkAutoTUnref<SkPicture> picture2(recorder2.endRecording());
699 for (int y = 0; y < height; y += tileSize) {
700 for (int x = 0; x < width; x += tileSize) {
701 SkRect tileRect = SkRect::Make(SkIRect::MakeXYWH(x, y, tileSize, tileSize));
robertphillipsa8d7f0b2014-08-29 08:03:56 -0700702 draw_picture_clipped(&canvas1, tileRect, picture1);
703 draw_picture_clipped(&canvas2, tileRect, picture2);
senorblanco837f5322014-07-14 10:19:54 -0700704 }
705 }
706 for (int y = 0; y < height; y++) {
707 int diffs = memcmp(result1.getAddr32(0, y), result2.getAddr32(0, y), result1.rowBytes());
708 REPORTER_ASSERT(reporter, !diffs);
709 if (diffs) {
710 break;
711 }
712 }
713}
714
senorblanco@chromium.org91957432014-05-01 14:03:41 +0000715DEF_TEST(ImageFilterMatrixConvolution, reporter) {
716 // Check that a 1x3 filter does not cause a spurious assert.
717 SkScalar kernel[3] = {
718 SkIntToScalar( 1), SkIntToScalar( 1), SkIntToScalar( 1),
719 };
720 SkISize kernelSize = SkISize::Make(1, 3);
721 SkScalar gain = SK_Scalar1, bias = 0;
722 SkIPoint kernelOffset = SkIPoint::Make(0, 0);
723
724 SkAutoTUnref<SkImageFilter> filter(
725 SkMatrixConvolutionImageFilter::Create(
726 kernelSize, kernel, gain, bias, kernelOffset,
727 SkMatrixConvolutionImageFilter::kRepeat_TileMode, false));
728
729 SkBitmap result;
730 int width = 16, height = 16;
731 result.allocN32Pixels(width, height);
732 SkCanvas canvas(result);
733 canvas.clear(0);
734
735 SkPaint paint;
736 paint.setImageFilter(filter);
737 SkRect rect = SkRect::Make(SkIRect::MakeWH(width, height));
738 canvas.drawRect(rect, paint);
739}
740
senorblanco@chromium.org8c7372b2014-05-02 19:13:11 +0000741DEF_TEST(ImageFilterMatrixConvolutionBorder, reporter) {
742 // Check that a filter with borders outside the target bounds
743 // does not crash.
744 SkScalar kernel[3] = {
745 0, 0, 0,
746 };
747 SkISize kernelSize = SkISize::Make(3, 1);
748 SkScalar gain = SK_Scalar1, bias = 0;
749 SkIPoint kernelOffset = SkIPoint::Make(2, 0);
750
751 SkAutoTUnref<SkImageFilter> filter(
752 SkMatrixConvolutionImageFilter::Create(
753 kernelSize, kernel, gain, bias, kernelOffset,
754 SkMatrixConvolutionImageFilter::kClamp_TileMode, true));
755
756 SkBitmap result;
757
758 int width = 10, height = 10;
759 result.allocN32Pixels(width, height);
760 SkCanvas canvas(result);
761 canvas.clear(0);
762
763 SkPaint filterPaint;
764 filterPaint.setImageFilter(filter);
765 SkRect bounds = SkRect::MakeWH(1, 10);
766 SkRect rect = SkRect::Make(SkIRect::MakeWH(width, height));
767 SkPaint rectPaint;
768 canvas.saveLayer(&bounds, &filterPaint);
769 canvas.drawRect(rect, rectPaint);
770 canvas.restore();
771}
772
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +0000773DEF_TEST(ImageFilterCropRect, reporter) {
robertphillips9a53fd72015-06-22 09:46:59 -0700774 const SkImageInfo info = SkImageInfo::MakeN32Premul(100, 100);
775 const SkSurfaceProps props(SkSurfaceProps::kLegacyFontHost_InitType);
776
777 SkAutoTUnref<SkBaseDevice> device(SkBitmapDevice::Create(info, props));
robertphillipsefbffed2015-06-22 12:06:08 -0700778 SkImageFilter::Proxy proxy(device);
robertphillips9a53fd72015-06-22 09:46:59 -0700779
780 test_crop_rects(&proxy, reporter);
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +0000781}
782
tfarina9ea53f92014-06-24 06:50:39 -0700783DEF_TEST(ImageFilterMatrix, reporter) {
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +0000784 SkBitmap temp;
mike@reedtribe.orgdeee4962014-02-13 14:41:43 +0000785 temp.allocN32Pixels(100, 100);
robertphillips9a53fd72015-06-22 09:46:59 -0700786 SkCanvas canvas(temp);
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +0000787 canvas.scale(SkIntToScalar(2), SkIntToScalar(2));
788
789 SkMatrix expectedMatrix = canvas.getTotalMatrix();
790
commit-bot@chromium.org5fb2ce32014-04-17 23:35:06 +0000791 SkRTreeFactory factory;
792 SkPictureRecorder recorder;
793 SkCanvas* recordingCanvas = recorder.beginRecording(100, 100, &factory, 0);
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +0000794
795 SkPaint paint;
796 SkAutoTUnref<MatrixTestImageFilter> imageFilter(
797 new MatrixTestImageFilter(reporter, expectedMatrix));
798 paint.setImageFilter(imageFilter.get());
halcanary96fcdcc2015-08-27 07:41:13 -0700799 recordingCanvas->saveLayer(nullptr, &paint);
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +0000800 SkPaint solidPaint;
801 solidPaint.setColor(0xFFFFFFFF);
802 recordingCanvas->save();
803 recordingCanvas->scale(SkIntToScalar(10), SkIntToScalar(10));
804 recordingCanvas->drawRect(SkRect::Make(SkIRect::MakeWH(100, 100)), solidPaint);
805 recordingCanvas->restore(); // scale
806 recordingCanvas->restore(); // saveLayer
robertphillips@google.com84b18c72014-04-13 19:09:42 +0000807 SkAutoTUnref<SkPicture> picture(recorder.endRecording());
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +0000808
robertphillips9b14f262014-06-04 05:40:44 -0700809 canvas.drawPicture(picture);
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +0000810}
811
senorblanco3d822c22014-07-30 14:49:31 -0700812DEF_TEST(ImageFilterCrossProcessPictureImageFilter, reporter) {
senorblanco@chromium.org97f5fc62014-05-30 20:50:56 +0000813 SkRTreeFactory factory;
814 SkPictureRecorder recorder;
815 SkCanvas* recordingCanvas = recorder.beginRecording(1, 1, &factory, 0);
816
817 // Create an SkPicture which simply draws a green 1x1 rectangle.
818 SkPaint greenPaint;
819 greenPaint.setColor(SK_ColorGREEN);
820 recordingCanvas->drawRect(SkRect::Make(SkIRect::MakeWH(1, 1)), greenPaint);
821 SkAutoTUnref<SkPicture> picture(recorder.endRecording());
822
823 // Wrap that SkPicture in an SkPictureImageFilter.
824 SkAutoTUnref<SkImageFilter> imageFilter(
825 SkPictureImageFilter::Create(picture.get()));
826
827 // Check that SkPictureImageFilter successfully serializes its contained
828 // SkPicture when not in cross-process mode.
829 SkPaint paint;
830 paint.setImageFilter(imageFilter.get());
831 SkPictureRecorder outerRecorder;
832 SkCanvas* outerCanvas = outerRecorder.beginRecording(1, 1, &factory, 0);
833 SkPaint redPaintWithFilter;
834 redPaintWithFilter.setColor(SK_ColorRED);
835 redPaintWithFilter.setImageFilter(imageFilter.get());
836 outerCanvas->drawRect(SkRect::Make(SkIRect::MakeWH(1, 1)), redPaintWithFilter);
837 SkAutoTUnref<SkPicture> outerPicture(outerRecorder.endRecording());
838
839 SkBitmap bitmap;
840 bitmap.allocN32Pixels(1, 1);
robertphillips9a53fd72015-06-22 09:46:59 -0700841 SkCanvas canvas(bitmap);
senorblanco@chromium.org97f5fc62014-05-30 20:50:56 +0000842
843 // The result here should be green, since the filter replaces the primitive's red interior.
844 canvas.clear(0x0);
robertphillips9b14f262014-06-04 05:40:44 -0700845 canvas.drawPicture(outerPicture);
senorblanco@chromium.org97f5fc62014-05-30 20:50:56 +0000846 uint32_t pixel = *bitmap.getAddr32(0, 0);
847 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
848
849 // Check that, for now, SkPictureImageFilter does not serialize or
850 // deserialize its contained picture when the filter is serialized
851 // cross-process. Do this by "laundering" it through SkValidatingReadBuffer.
852 SkAutoTUnref<SkData> data(SkValidatingSerializeFlattenable(imageFilter.get()));
853 SkAutoTUnref<SkFlattenable> flattenable(SkValidatingDeserializeFlattenable(
854 data->data(), data->size(), SkImageFilter::GetFlattenableType()));
855 SkImageFilter* unflattenedFilter = static_cast<SkImageFilter*>(flattenable.get());
856
857 redPaintWithFilter.setImageFilter(unflattenedFilter);
858 SkPictureRecorder crossProcessRecorder;
859 SkCanvas* crossProcessCanvas = crossProcessRecorder.beginRecording(1, 1, &factory, 0);
860 crossProcessCanvas->drawRect(SkRect::Make(SkIRect::MakeWH(1, 1)), redPaintWithFilter);
861 SkAutoTUnref<SkPicture> crossProcessPicture(crossProcessRecorder.endRecording());
862
863 canvas.clear(0x0);
robertphillips9b14f262014-06-04 05:40:44 -0700864 canvas.drawPicture(crossProcessPicture);
senorblanco@chromium.org97f5fc62014-05-30 20:50:56 +0000865 pixel = *bitmap.getAddr32(0, 0);
hendrikw446ee672015-06-16 09:28:37 -0700866 // If the security precautions are enabled, the result here should not be green, since the
867 // filter draws nothing.
868 REPORTER_ASSERT(reporter, SkPicture::PictureIOSecurityPrecautionsEnabled()
869 ? pixel != SK_ColorGREEN : pixel == SK_ColorGREEN);
senorblanco@chromium.org97f5fc62014-05-30 20:50:56 +0000870}
871
senorblanco3d822c22014-07-30 14:49:31 -0700872DEF_TEST(ImageFilterClippedPictureImageFilter, reporter) {
873 SkRTreeFactory factory;
874 SkPictureRecorder recorder;
875 SkCanvas* recordingCanvas = recorder.beginRecording(1, 1, &factory, 0);
876
877 // Create an SkPicture which simply draws a green 1x1 rectangle.
878 SkPaint greenPaint;
879 greenPaint.setColor(SK_ColorGREEN);
880 recordingCanvas->drawRect(SkRect::Make(SkIRect::MakeWH(1, 1)), greenPaint);
881 SkAutoTUnref<SkPicture> picture(recorder.endRecording());
882
robertphillips9a53fd72015-06-22 09:46:59 -0700883 SkAutoTUnref<SkImageFilter> imageFilter(SkPictureImageFilter::Create(picture.get()));
senorblanco3d822c22014-07-30 14:49:31 -0700884
885 SkBitmap result;
886 SkIPoint offset;
halcanary96fcdcc2015-08-27 07:41:13 -0700887 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeXYWH(1, 1, 1, 1), nullptr);
senorblanco3d822c22014-07-30 14:49:31 -0700888 SkBitmap bitmap;
889 bitmap.allocN32Pixels(2, 2);
robertphillipsefbffed2015-06-22 12:06:08 -0700890 const SkSurfaceProps props(SkSurfaceProps::kLegacyFontHost_InitType);
891 SkBitmapDevice device(bitmap, props);
892 SkImageFilter::Proxy proxy(&device);
senorblanco3d822c22014-07-30 14:49:31 -0700893 REPORTER_ASSERT(reporter, !imageFilter->filterImage(&proxy, bitmap, ctx, &result, &offset));
894}
895
tfarina9ea53f92014-06-24 06:50:39 -0700896DEF_TEST(ImageFilterEmptySaveLayer, reporter) {
senorblanco@chromium.org68250c82014-05-06 22:52:55 +0000897 // Even when there's an empty saveLayer()/restore(), ensure that an image
898 // filter or color filter which affects transparent black still draws.
899
900 SkBitmap bitmap;
901 bitmap.allocN32Pixels(10, 10);
robertphillips9a53fd72015-06-22 09:46:59 -0700902 SkCanvas canvas(bitmap);
senorblanco@chromium.org68250c82014-05-06 22:52:55 +0000903
904 SkRTreeFactory factory;
905 SkPictureRecorder recorder;
906
907 SkAutoTUnref<SkColorFilter> green(
908 SkColorFilter::CreateModeFilter(SK_ColorGREEN, SkXfermode::kSrc_Mode));
909 SkAutoTUnref<SkColorFilterImageFilter> imageFilter(
910 SkColorFilterImageFilter::Create(green.get()));
911 SkPaint imageFilterPaint;
912 imageFilterPaint.setImageFilter(imageFilter.get());
913 SkPaint colorFilterPaint;
914 colorFilterPaint.setColorFilter(green.get());
915
916 SkRect bounds = SkRect::MakeWH(10, 10);
917
918 SkCanvas* recordingCanvas = recorder.beginRecording(10, 10, &factory, 0);
919 recordingCanvas->saveLayer(&bounds, &imageFilterPaint);
920 recordingCanvas->restore();
921 SkAutoTUnref<SkPicture> picture(recorder.endRecording());
922
923 canvas.clear(0);
robertphillips9b14f262014-06-04 05:40:44 -0700924 canvas.drawPicture(picture);
senorblanco@chromium.org68250c82014-05-06 22:52:55 +0000925 uint32_t pixel = *bitmap.getAddr32(0, 0);
926 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
927
928 recordingCanvas = recorder.beginRecording(10, 10, &factory, 0);
halcanary96fcdcc2015-08-27 07:41:13 -0700929 recordingCanvas->saveLayer(nullptr, &imageFilterPaint);
senorblanco@chromium.org68250c82014-05-06 22:52:55 +0000930 recordingCanvas->restore();
931 SkAutoTUnref<SkPicture> picture2(recorder.endRecording());
932
933 canvas.clear(0);
robertphillips9b14f262014-06-04 05:40:44 -0700934 canvas.drawPicture(picture2);
senorblanco@chromium.org68250c82014-05-06 22:52:55 +0000935 pixel = *bitmap.getAddr32(0, 0);
936 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
937
938 recordingCanvas = recorder.beginRecording(10, 10, &factory, 0);
939 recordingCanvas->saveLayer(&bounds, &colorFilterPaint);
940 recordingCanvas->restore();
941 SkAutoTUnref<SkPicture> picture3(recorder.endRecording());
942
943 canvas.clear(0);
robertphillips9b14f262014-06-04 05:40:44 -0700944 canvas.drawPicture(picture3);
senorblanco@chromium.org68250c82014-05-06 22:52:55 +0000945 pixel = *bitmap.getAddr32(0, 0);
946 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
947}
948
robertphillips9a53fd72015-06-22 09:46:59 -0700949static void test_huge_blur(SkCanvas* canvas, skiatest::Reporter* reporter) {
senorblanco@chromium.org09843fd2014-03-24 20:50:59 +0000950 SkBitmap bitmap;
951 bitmap.allocN32Pixels(100, 100);
952 bitmap.eraseARGB(0, 0, 0, 0);
953
954 // Check that a blur with an insane radius does not crash or assert.
955 SkAutoTUnref<SkImageFilter> blur(SkBlurImageFilter::Create(SkIntToScalar(1<<30), SkIntToScalar(1<<30)));
956
957 SkPaint paint;
958 paint.setImageFilter(blur);
robertphillips9a53fd72015-06-22 09:46:59 -0700959 canvas->drawSprite(bitmap, 0, 0, &paint);
senorblanco@chromium.org09843fd2014-03-24 20:50:59 +0000960}
961
962DEF_TEST(HugeBlurImageFilter, reporter) {
963 SkBitmap temp;
964 temp.allocN32Pixels(100, 100);
robertphillips9a53fd72015-06-22 09:46:59 -0700965 SkCanvas canvas(temp);
966 test_huge_blur(&canvas, reporter);
senorblanco@chromium.org09843fd2014-03-24 20:50:59 +0000967}
968
senorblanco3a495202014-09-29 07:57:20 -0700969DEF_TEST(MatrixConvolutionSanityTest, reporter) {
970 SkScalar kernel[1] = { 0 };
971 SkScalar gain = SK_Scalar1, bias = 0;
972 SkIPoint kernelOffset = SkIPoint::Make(1, 1);
973
halcanary96fcdcc2015-08-27 07:41:13 -0700974 // Check that an enormous (non-allocatable) kernel gives a nullptr filter.
senorblanco3a495202014-09-29 07:57:20 -0700975 SkAutoTUnref<SkImageFilter> conv(SkMatrixConvolutionImageFilter::Create(
976 SkISize::Make(1<<30, 1<<30),
977 kernel,
978 gain,
979 bias,
980 kernelOffset,
981 SkMatrixConvolutionImageFilter::kRepeat_TileMode,
982 false));
983
halcanary96fcdcc2015-08-27 07:41:13 -0700984 REPORTER_ASSERT(reporter, nullptr == conv.get());
senorblanco3a495202014-09-29 07:57:20 -0700985
halcanary96fcdcc2015-08-27 07:41:13 -0700986 // Check that a nullptr kernel gives a nullptr filter.
senorblanco3a495202014-09-29 07:57:20 -0700987 conv.reset(SkMatrixConvolutionImageFilter::Create(
988 SkISize::Make(1, 1),
halcanary96fcdcc2015-08-27 07:41:13 -0700989 nullptr,
senorblanco3a495202014-09-29 07:57:20 -0700990 gain,
991 bias,
992 kernelOffset,
993 SkMatrixConvolutionImageFilter::kRepeat_TileMode,
994 false));
995
halcanary96fcdcc2015-08-27 07:41:13 -0700996 REPORTER_ASSERT(reporter, nullptr == conv.get());
senorblanco3a495202014-09-29 07:57:20 -0700997
halcanary96fcdcc2015-08-27 07:41:13 -0700998 // Check that a kernel width < 1 gives a nullptr filter.
senorblanco3a495202014-09-29 07:57:20 -0700999 conv.reset(SkMatrixConvolutionImageFilter::Create(
1000 SkISize::Make(0, 1),
1001 kernel,
1002 gain,
1003 bias,
1004 kernelOffset,
1005 SkMatrixConvolutionImageFilter::kRepeat_TileMode,
1006 false));
1007
halcanary96fcdcc2015-08-27 07:41:13 -07001008 REPORTER_ASSERT(reporter, nullptr == conv.get());
senorblanco3a495202014-09-29 07:57:20 -07001009
halcanary96fcdcc2015-08-27 07:41:13 -07001010 // Check that kernel height < 1 gives a nullptr filter.
senorblanco3a495202014-09-29 07:57:20 -07001011 conv.reset(SkMatrixConvolutionImageFilter::Create(
1012 SkISize::Make(1, -1),
1013 kernel,
1014 gain,
1015 bias,
1016 kernelOffset,
1017 SkMatrixConvolutionImageFilter::kRepeat_TileMode,
1018 false));
1019
halcanary96fcdcc2015-08-27 07:41:13 -07001020 REPORTER_ASSERT(reporter, nullptr == conv.get());
senorblanco3a495202014-09-29 07:57:20 -07001021}
1022
robertphillips9a53fd72015-06-22 09:46:59 -07001023static void test_xfermode_cropped_input(SkCanvas* canvas, skiatest::Reporter* reporter) {
1024 canvas->clear(0);
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001025
1026 SkBitmap bitmap;
1027 bitmap.allocN32Pixels(1, 1);
1028 bitmap.eraseARGB(255, 255, 255, 255);
1029
1030 SkAutoTUnref<SkColorFilter> green(
1031 SkColorFilter::CreateModeFilter(SK_ColorGREEN, SkXfermode::kSrcIn_Mode));
1032 SkAutoTUnref<SkColorFilterImageFilter> greenFilter(
1033 SkColorFilterImageFilter::Create(green.get()));
1034 SkImageFilter::CropRect cropRect(SkRect::MakeEmpty());
1035 SkAutoTUnref<SkColorFilterImageFilter> croppedOut(
halcanary96fcdcc2015-08-27 07:41:13 -07001036 SkColorFilterImageFilter::Create(green.get(), nullptr, &cropRect));
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001037
1038 // Check that an xfermode image filter whose input has been cropped out still draws the other
1039 // input. Also check that drawing with both inputs cropped out doesn't cause a GPU warning.
1040 SkXfermode* mode = SkXfermode::Create(SkXfermode::kSrcOver_Mode);
1041 SkAutoTUnref<SkImageFilter> xfermodeNoFg(
1042 SkXfermodeImageFilter::Create(mode, greenFilter, croppedOut));
1043 SkAutoTUnref<SkImageFilter> xfermodeNoBg(
1044 SkXfermodeImageFilter::Create(mode, croppedOut, greenFilter));
1045 SkAutoTUnref<SkImageFilter> xfermodeNoFgNoBg(
1046 SkXfermodeImageFilter::Create(mode, croppedOut, croppedOut));
1047
1048 SkPaint paint;
1049 paint.setImageFilter(xfermodeNoFg);
robertphillips9a53fd72015-06-22 09:46:59 -07001050 canvas->drawSprite(bitmap, 0, 0, &paint);
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001051
1052 uint32_t pixel;
kkinnunena9d9a392015-03-06 07:16:00 -08001053 SkImageInfo info = SkImageInfo::Make(1, 1, kBGRA_8888_SkColorType, kUnpremul_SkAlphaType);
robertphillips9a53fd72015-06-22 09:46:59 -07001054 canvas->readPixels(info, &pixel, 4, 0, 0);
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001055 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1056
1057 paint.setImageFilter(xfermodeNoBg);
robertphillips9a53fd72015-06-22 09:46:59 -07001058 canvas->drawSprite(bitmap, 0, 0, &paint);
1059 canvas->readPixels(info, &pixel, 4, 0, 0);
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001060 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1061
1062 paint.setImageFilter(xfermodeNoFgNoBg);
robertphillips9a53fd72015-06-22 09:46:59 -07001063 canvas->drawSprite(bitmap, 0, 0, &paint);
1064 canvas->readPixels(info, &pixel, 4, 0, 0);
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001065 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1066}
1067
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001068DEF_TEST(ImageFilterNestedSaveLayer, reporter) {
1069 SkBitmap temp;
1070 temp.allocN32Pixels(50, 50);
robertphillips9a53fd72015-06-22 09:46:59 -07001071 SkCanvas canvas(temp);
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001072 canvas.clear(0x0);
1073
1074 SkBitmap bitmap;
1075 bitmap.allocN32Pixels(10, 10);
1076 bitmap.eraseColor(SK_ColorGREEN);
1077
1078 SkMatrix matrix;
1079 matrix.setScale(SkIntToScalar(2), SkIntToScalar(2));
1080 matrix.postTranslate(SkIntToScalar(-20), SkIntToScalar(-20));
1081 SkAutoTUnref<SkImageFilter> matrixFilter(
senorblanco8c874ee2015-03-20 06:38:17 -07001082 SkImageFilter::CreateMatrixFilter(matrix, kLow_SkFilterQuality));
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001083
1084 // Test that saveLayer() with a filter nested inside another saveLayer() applies the
1085 // correct offset to the filter matrix.
1086 SkRect bounds1 = SkRect::MakeXYWH(10, 10, 30, 30);
halcanary96fcdcc2015-08-27 07:41:13 -07001087 canvas.saveLayer(&bounds1, nullptr);
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001088 SkPaint filterPaint;
1089 filterPaint.setImageFilter(matrixFilter);
1090 SkRect bounds2 = SkRect::MakeXYWH(20, 20, 10, 10);
1091 canvas.saveLayer(&bounds2, &filterPaint);
1092 SkPaint greenPaint;
1093 greenPaint.setColor(SK_ColorGREEN);
1094 canvas.drawRect(bounds2, greenPaint);
1095 canvas.restore();
1096 canvas.restore();
1097 SkPaint strokePaint;
1098 strokePaint.setStyle(SkPaint::kStroke_Style);
1099 strokePaint.setColor(SK_ColorRED);
1100
kkinnunena9d9a392015-03-06 07:16:00 -08001101 SkImageInfo info = SkImageInfo::Make(1, 1, kBGRA_8888_SkColorType, kUnpremul_SkAlphaType);
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001102 uint32_t pixel;
1103 canvas.readPixels(info, &pixel, 4, 25, 25);
1104 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1105
1106 // Test that drawSprite() with a filter nested inside a saveLayer() applies the
1107 // correct offset to the filter matrix.
1108 canvas.clear(0x0);
1109 canvas.readPixels(info, &pixel, 4, 25, 25);
halcanary96fcdcc2015-08-27 07:41:13 -07001110 canvas.saveLayer(&bounds1, nullptr);
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001111 canvas.drawSprite(bitmap, 20, 20, &filterPaint);
1112 canvas.restore();
1113
1114 canvas.readPixels(info, &pixel, 4, 25, 25);
1115 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1116}
1117
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001118DEF_TEST(XfermodeImageFilterCroppedInput, reporter) {
1119 SkBitmap temp;
1120 temp.allocN32Pixels(100, 100);
robertphillips9a53fd72015-06-22 09:46:59 -07001121 SkCanvas canvas(temp);
1122 test_xfermode_cropped_input(&canvas, reporter);
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001123}
senorblanco@chromium.org09843fd2014-03-24 20:50:59 +00001124
ajuma5788faa2015-02-13 09:05:47 -08001125DEF_TEST(ComposedImageFilterOffset, reporter) {
1126 SkBitmap bitmap;
1127 bitmap.allocN32Pixels(100, 100);
1128 bitmap.eraseARGB(0, 0, 0, 0);
robertphillipsefbffed2015-06-22 12:06:08 -07001129 const SkSurfaceProps props(SkSurfaceProps::kLegacyFontHost_InitType);
1130 SkBitmapDevice device(bitmap, props);
1131 SkImageFilter::Proxy proxy(&device);
ajuma5788faa2015-02-13 09:05:47 -08001132
1133 SkImageFilter::CropRect cropRect(SkRect::MakeXYWH(1, 0, 20, 20));
halcanary96fcdcc2015-08-27 07:41:13 -07001134 SkAutoTUnref<SkImageFilter> offsetFilter(SkOffsetImageFilter::Create(0, 0, nullptr, &cropRect));
ajuma8e8c9402015-02-13 10:15:46 -08001135 SkAutoTUnref<SkImageFilter> blurFilter(makeBlur());
1136 SkAutoTUnref<SkImageFilter> composedFilter(SkComposeImageFilter::Create(blurFilter, offsetFilter.get()));
ajuma5788faa2015-02-13 09:05:47 -08001137 SkBitmap result;
1138 SkIPoint offset;
halcanary96fcdcc2015-08-27 07:41:13 -07001139 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeLargest(), nullptr);
ajuma5788faa2015-02-13 09:05:47 -08001140 REPORTER_ASSERT(reporter, composedFilter->filterImage(&proxy, bitmap, ctx, &result, &offset));
1141 REPORTER_ASSERT(reporter, offset.fX == 1 && offset.fY == 0);
1142}
1143
senorblanco24d2a7b2015-07-13 10:27:05 -07001144DEF_TEST(PartialCropRect, reporter) {
1145 SkBitmap bitmap;
1146 bitmap.allocN32Pixels(100, 100);
1147 bitmap.eraseARGB(0, 0, 0, 0);
1148 const SkSurfaceProps props(SkSurfaceProps::kLegacyFontHost_InitType);
1149 SkBitmapDevice device(bitmap, props);
1150 SkImageFilter::Proxy proxy(&device);
1151
1152 SkImageFilter::CropRect cropRect(SkRect::MakeXYWH(100, 0, 20, 30),
senorblancoed7cf272015-07-16 15:19:11 -07001153 SkImageFilter::CropRect::kHasWidth_CropEdge | SkImageFilter::CropRect::kHasHeight_CropEdge);
halcanary96fcdcc2015-08-27 07:41:13 -07001154 SkAutoTUnref<SkImageFilter> filter(make_grayscale(nullptr, &cropRect));
senorblanco24d2a7b2015-07-13 10:27:05 -07001155 SkBitmap result;
1156 SkIPoint offset;
halcanary96fcdcc2015-08-27 07:41:13 -07001157 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeLargest(), nullptr);
senorblanco24d2a7b2015-07-13 10:27:05 -07001158 REPORTER_ASSERT(reporter, filter->filterImage(&proxy, bitmap, ctx, &result, &offset));
1159 REPORTER_ASSERT(reporter, offset.fX == 0);
1160 REPORTER_ASSERT(reporter, offset.fY == 0);
1161 REPORTER_ASSERT(reporter, result.width() == 20);
1162 REPORTER_ASSERT(reporter, result.height() == 30);
1163}
1164
senorblanco0abdf762015-08-20 11:10:41 -07001165DEF_TEST(ImageFilterCanComputeFastBounds, reporter) {
1166
1167 SkPoint3 location = SkPoint3::Make(0, 0, SK_Scalar1);
1168 SkAutoTUnref<SkImageFilter> lighting(SkLightingImageFilter::CreatePointLitDiffuse(
1169 location, SK_ColorGREEN, 0, 0));
1170 REPORTER_ASSERT(reporter, !lighting->canComputeFastBounds());
1171
1172 SkAutoTUnref<SkImageFilter> gray(make_grayscale(nullptr, nullptr));
1173 REPORTER_ASSERT(reporter, gray->canComputeFastBounds());
1174 {
1175 SkColorFilter* grayCF;
1176 REPORTER_ASSERT(reporter, gray->asAColorFilter(&grayCF));
1177 REPORTER_ASSERT(reporter, !grayCF->affectsTransparentBlack());
1178 grayCF->unref();
1179 }
1180 REPORTER_ASSERT(reporter, gray->canComputeFastBounds());
1181
1182 SkAutoTUnref<SkImageFilter> grayBlur(SkBlurImageFilter::Create(SK_Scalar1, SK_Scalar1, gray.get()));
1183 REPORTER_ASSERT(reporter, grayBlur->canComputeFastBounds());
1184
1185 SkScalar greenMatrix[20] = { 0, 0, 0, 0, 0,
1186 0, 0, 0, 0, 1,
1187 0, 0, 0, 0, 0,
1188 0, 0, 0, 0, 1 };
1189 SkAutoTUnref<SkColorFilter> greenCF(SkColorMatrixFilter::Create(greenMatrix));
1190 SkAutoTUnref<SkImageFilter> green(SkColorFilterImageFilter::Create(greenCF));
1191
1192 REPORTER_ASSERT(reporter, greenCF->affectsTransparentBlack());
1193 REPORTER_ASSERT(reporter, !green->canComputeFastBounds());
1194
1195 SkAutoTUnref<SkImageFilter> greenBlur(SkBlurImageFilter::Create(SK_Scalar1, SK_Scalar1, green.get()));
1196 REPORTER_ASSERT(reporter, !greenBlur->canComputeFastBounds());
1197
1198 uint8_t allOne[256], identity[256];
1199 for (int i = 0; i < 256; ++i) {
1200 identity[i] = i;
1201 allOne[i] = 255;
1202 }
1203
1204 SkAutoTUnref<SkColorFilter> identityCF(
1205 SkTableColorFilter::CreateARGB(identity, identity, identity, allOne));
1206 SkAutoTUnref<SkImageFilter> identityFilter(SkColorFilterImageFilter::Create(identityCF.get()));
1207 REPORTER_ASSERT(reporter, !identityCF->affectsTransparentBlack());
1208 REPORTER_ASSERT(reporter, identityFilter->canComputeFastBounds());
1209
1210 SkAutoTUnref<SkColorFilter> forceOpaqueCF(
1211 SkTableColorFilter::CreateARGB(allOne, identity, identity, identity));
1212 SkAutoTUnref<SkImageFilter> forceOpaque(SkColorFilterImageFilter::Create(forceOpaqueCF.get()));
1213 REPORTER_ASSERT(reporter, forceOpaqueCF->affectsTransparentBlack());
1214 REPORTER_ASSERT(reporter, !forceOpaque->canComputeFastBounds());
1215}
1216
fmalitacd56f812015-09-14 13:31:18 -07001217// Verify that SkImageSource survives serialization
1218DEF_TEST(ImageFilterImageSourceSerialization, reporter) {
1219 SkAutoTUnref<SkSurface> surface(SkSurface::NewRasterN32Premul(10, 10));
1220 surface->getCanvas()->clear(SK_ColorGREEN);
1221 SkAutoTUnref<SkImage> image(surface->newImageSnapshot());
1222 SkAutoTUnref<SkImageFilter> filter(SkImageSource::Create(image));
1223
1224 SkAutoTUnref<SkData> data(SkValidatingSerializeFlattenable(filter));
1225 SkAutoTUnref<SkFlattenable> flattenable(SkValidatingDeserializeFlattenable(
1226 data->data(), data->size(), SkImageFilter::GetFlattenableType()));
1227 SkImageFilter* unflattenedFilter = static_cast<SkImageFilter*>(flattenable.get());
1228 REPORTER_ASSERT(reporter, unflattenedFilter);
1229
1230 SkBitmap bm;
1231 bm.allocN32Pixels(10, 10);
1232 SkPaint paint;
1233 paint.setColor(SK_ColorRED);
1234 paint.setImageFilter(unflattenedFilter);
1235
1236 SkCanvas canvas(bm);
1237 canvas.drawRect(SkRect::MakeWH(10, 10), paint);
1238 REPORTER_ASSERT(reporter, *bm.getAddr32(0, 0) == SkPreMultiplyColor(SK_ColorGREEN));
1239}
1240
senorblanco@chromium.org58d14662014-02-03 22:36:39 +00001241#if SK_SUPPORT_GPU
reed4a8126e2014-09-22 07:29:03 -07001242
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +00001243DEF_GPUTEST(ImageFilterCropRectGPU, reporter, factory) {
1244 GrContext* context = factory->get(static_cast<GrContextFactory::GLContextType>(0));
halcanary96fcdcc2015-08-27 07:41:13 -07001245 if (nullptr == context) {
senorblancoc8e93402015-04-21 07:20:36 -07001246 return;
1247 }
robertphillipsefbffed2015-06-22 12:06:08 -07001248 const SkSurfaceProps props(SkSurfaceProps::kLegacyFontHost_InitType);
1249
commit-bot@chromium.org15a14052014-02-16 00:59:25 +00001250 SkAutoTUnref<SkGpuDevice> device(SkGpuDevice::Create(context,
bsalomonafe30052015-01-16 07:32:33 -08001251 SkSurface::kNo_Budgeted,
commit-bot@chromium.org15a14052014-02-16 00:59:25 +00001252 SkImageInfo::MakeN32Premul(100, 100),
bsalomonafe30052015-01-16 07:32:33 -08001253 0,
bsalomon74f681d2015-06-23 14:38:48 -07001254 &props,
1255 SkGpuDevice::kUninit_InitContents));
robertphillipsefbffed2015-06-22 12:06:08 -07001256 SkImageFilter::Proxy proxy(device);
robertphillips9a53fd72015-06-22 09:46:59 -07001257
1258 test_crop_rects(&proxy, reporter);
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +00001259}
senorblanco@chromium.org09843fd2014-03-24 20:50:59 +00001260
1261DEF_GPUTEST(HugeBlurImageFilterGPU, reporter, factory) {
1262 GrContext* context = factory->get(static_cast<GrContextFactory::GLContextType>(0));
halcanary96fcdcc2015-08-27 07:41:13 -07001263 if (nullptr == context) {
senorblancoc8e93402015-04-21 07:20:36 -07001264 return;
1265 }
robertphillipsefbffed2015-06-22 12:06:08 -07001266 const SkSurfaceProps props(SkSurfaceProps::kLegacyFontHost_InitType);
1267
senorblanco@chromium.org09843fd2014-03-24 20:50:59 +00001268 SkAutoTUnref<SkGpuDevice> device(SkGpuDevice::Create(context,
bsalomonafe30052015-01-16 07:32:33 -08001269 SkSurface::kNo_Budgeted,
senorblanco@chromium.org09843fd2014-03-24 20:50:59 +00001270 SkImageInfo::MakeN32Premul(100, 100),
bsalomonafe30052015-01-16 07:32:33 -08001271 0,
bsalomon74f681d2015-06-23 14:38:48 -07001272 &props,
1273 SkGpuDevice::kUninit_InitContents));
robertphillips9a53fd72015-06-22 09:46:59 -07001274 SkCanvas canvas(device);
1275
1276 test_huge_blur(&canvas, reporter);
senorblanco@chromium.org09843fd2014-03-24 20:50:59 +00001277}
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001278
1279DEF_GPUTEST(XfermodeImageFilterCroppedInputGPU, reporter, factory) {
1280 GrContext* context = factory->get(static_cast<GrContextFactory::GLContextType>(0));
halcanary96fcdcc2015-08-27 07:41:13 -07001281 if (nullptr == context) {
senorblancoc8e93402015-04-21 07:20:36 -07001282 return;
1283 }
robertphillipsefbffed2015-06-22 12:06:08 -07001284 const SkSurfaceProps props(SkSurfaceProps::kLegacyFontHost_InitType);
1285
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001286 SkAutoTUnref<SkGpuDevice> device(SkGpuDevice::Create(context,
bsalomonafe30052015-01-16 07:32:33 -08001287 SkSurface::kNo_Budgeted,
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001288 SkImageInfo::MakeN32Premul(1, 1),
bsalomonafe30052015-01-16 07:32:33 -08001289 0,
bsalomon74f681d2015-06-23 14:38:48 -07001290 &props,
1291 SkGpuDevice::kUninit_InitContents));
robertphillips9a53fd72015-06-22 09:46:59 -07001292 SkCanvas canvas(device);
1293
1294 test_xfermode_cropped_input(&canvas, reporter);
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001295}
senorblanco32673b92014-09-09 09:15:04 -07001296
1297DEF_GPUTEST(TestNegativeBlurSigmaGPU, reporter, factory) {
1298 GrContext* context = factory->get(static_cast<GrContextFactory::GLContextType>(0));
halcanary96fcdcc2015-08-27 07:41:13 -07001299 if (nullptr == context) {
senorblancoc8e93402015-04-21 07:20:36 -07001300 return;
1301 }
robertphillipsefbffed2015-06-22 12:06:08 -07001302 const SkSurfaceProps props(SkSurfaceProps::kLegacyFontHost_InitType);
1303
senorblanco32673b92014-09-09 09:15:04 -07001304 SkAutoTUnref<SkGpuDevice> device(SkGpuDevice::Create(context,
bsalomonafe30052015-01-16 07:32:33 -08001305 SkSurface::kNo_Budgeted,
senorblanco32673b92014-09-09 09:15:04 -07001306 SkImageInfo::MakeN32Premul(1, 1),
bsalomonafe30052015-01-16 07:32:33 -08001307 0,
bsalomon74f681d2015-06-23 14:38:48 -07001308 &props,
1309 SkGpuDevice::kUninit_InitContents));
robertphillipsefbffed2015-06-22 12:06:08 -07001310 SkImageFilter::Proxy proxy(device);
robertphillips9a53fd72015-06-22 09:46:59 -07001311
1312 test_negative_blur_sigma(&proxy, reporter);
senorblanco32673b92014-09-09 09:15:04 -07001313}
senorblanco@chromium.org58d14662014-02-03 22:36:39 +00001314#endif