blob: 3f60286e39d6da3b3369bbc22f21c65fa407030b [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"
senorblanco@chromium.org6776b822014-01-03 21:48:22 +000010#include "SkBlurImageFilter.h"
tfarina@chromium.org8f6884a2014-01-24 20:56:26 +000011#include "SkCanvas.h"
12#include "SkColorFilterImageFilter.h"
13#include "SkColorMatrixFilter.h"
ajuma5788faa2015-02-13 09:05:47 -080014#include "SkComposeImageFilter.h"
senorblanco@chromium.org6776b822014-01-03 21:48:22 +000015#include "SkDisplacementMapEffect.h"
16#include "SkDropShadowImageFilter.h"
senorblanco@chromium.org97f5fc62014-05-30 20:50:56 +000017#include "SkFlattenableSerialization.h"
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +000018#include "SkGradientShader.h"
fmalita5598b632015-09-15 11:26:13 -070019#include "SkImage.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"
ajuma77b6ba32016-01-08 14:58:35 -080026#include "SkPaintImageFilter.h"
senorblanco8f3937d2014-10-29 12:36:32 -070027#include "SkPerlinNoiseShader.h"
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +000028#include "SkPicture.h"
senorblanco@chromium.org910702b2014-05-30 20:36:15 +000029#include "SkPictureImageFilter.h"
robertphillips@google.com770963f2014-04-18 18:04:41 +000030#include "SkPictureRecorder.h"
robertphillips3d32d762015-07-13 13:16:44 -070031#include "SkPoint3.h"
halcanary97d2c0a2014-08-19 06:27:53 -070032#include "SkReadBuffer.h"
tfarina@chromium.org8f6884a2014-01-24 20:56:26 +000033#include "SkRect.h"
robertphillips4418dba2016-03-07 12:45:14 -080034#include "SkSpecialImage.h"
35#include "SkSpecialSurface.h"
fmalitacd56f812015-09-14 13:31:18 -070036#include "SkSurface.h"
senorblanco0abdf762015-08-20 11:10:41 -070037#include "SkTableColorFilter.h"
senorblanco@chromium.org6776b822014-01-03 21:48:22 +000038#include "SkTileImageFilter.h"
39#include "SkXfermodeImageFilter.h"
tfarina@chromium.org8f6884a2014-01-24 20:56:26 +000040#include "Test.h"
robertphillips4418dba2016-03-07 12:45:14 -080041#include "TestingSpecialImageAccess.h"
senorblanco@chromium.org194d7752013-07-24 22:19:24 +000042
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +000043#if SK_SUPPORT_GPU
kkinnunen15302832015-12-01 04:35:26 -080044#include "GrContext.h"
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +000045#include "SkGpuDevice.h"
46#endif
47
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +000048static const int kBitmapSize = 4;
commit-bot@chromium.org4b681bc2013-09-13 12:40:02 +000049
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +000050namespace {
51
52class MatrixTestImageFilter : public SkImageFilter {
53public:
54 MatrixTestImageFilter(skiatest::Reporter* reporter, const SkMatrix& expectedMatrix)
halcanary96fcdcc2015-08-27 07:41:13 -070055 : SkImageFilter(0, nullptr), fReporter(reporter), fExpectedMatrix(expectedMatrix) {
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +000056 }
57
robertphillips48e78462016-02-17 13:57:16 -080058 bool onFilterImageDeprecated(Proxy*, const SkBitmap& src, const Context& ctx,
59 SkBitmap* result, SkIPoint* offset) const override {
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +000060 REPORTER_ASSERT(fReporter, ctx.ctm() == fExpectedMatrix);
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +000061 return true;
62 }
63
robertphillipsf3f5bad2014-12-19 13:49:15 -080064 SK_TO_STRING_OVERRIDE()
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +000065 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(MatrixTestImageFilter)
66
67protected:
mtklein36352bf2015-03-25 18:17:31 -070068 void flatten(SkWriteBuffer& buffer) const override {
reed9fa60da2014-08-21 07:59:51 -070069 this->INHERITED::flatten(buffer);
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +000070 buffer.writeFunctionPtr(fReporter);
71 buffer.writeMatrix(fExpectedMatrix);
72 }
73
74private:
75 skiatest::Reporter* fReporter;
76 SkMatrix fExpectedMatrix;
mtklein3f3b3d02014-12-01 11:47:08 -080077
reed9fa60da2014-08-21 07:59:51 -070078 typedef SkImageFilter INHERITED;
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +000079};
80
senorblanco297f7ce2016-03-23 13:44:26 -070081void draw_gradient_circle(SkCanvas* canvas, int width, int height) {
82 SkScalar x = SkIntToScalar(width / 2);
83 SkScalar y = SkIntToScalar(height / 2);
84 SkScalar radius = SkMinScalar(x, y) * 0.8f;
85 canvas->clear(0x00000000);
86 SkColor colors[2];
87 colors[0] = SK_ColorWHITE;
88 colors[1] = SK_ColorBLACK;
89 sk_sp<SkShader> shader(
90 SkGradientShader::MakeRadial(SkPoint::Make(x, y), radius, colors, nullptr, 2,
91 SkShader::kClamp_TileMode)
92 );
93 SkPaint paint;
94 paint.setShader(shader);
95 canvas->drawCircle(x, y, radius, paint);
96}
97
98SkBitmap make_gradient_circle(int width, int height) {
99 SkBitmap bitmap;
100 bitmap.allocN32Pixels(width, height);
101 SkCanvas canvas(bitmap);
102 draw_gradient_circle(&canvas, width, height);
103 return bitmap;
104}
105
106class FilterList {
107public:
108 FilterList(SkImageFilter* input = nullptr, const SkImageFilter::CropRect* cropRect = nullptr) {
109 auto cf(SkColorFilter::MakeModeFilter(SK_ColorRED, SkXfermode::kSrcIn_Mode));
110 SkPoint3 location = SkPoint3::Make(0, 0, SK_Scalar1);
111 SkScalar kernel[9] = {
112 SkIntToScalar( 1), SkIntToScalar( 1), SkIntToScalar( 1),
113 SkIntToScalar( 1), SkIntToScalar(-7), SkIntToScalar( 1),
114 SkIntToScalar( 1), SkIntToScalar( 1), SkIntToScalar( 1),
115 };
116 const SkISize kernelSize = SkISize::Make(3, 3);
117 const SkScalar gain = SK_Scalar1, bias = 0;
118 const SkScalar five = SkIntToScalar(5);
119
120 sk_sp<SkImage> gradientImage(SkImage::MakeFromBitmap(make_gradient_circle(64, 64)));
robertphillips549c8992016-04-01 09:28:51 -0700121 sk_sp<SkImageFilter> gradientSource(SkImageSource::Make(std::move(gradientImage)));
robertphillips51a315e2016-03-31 09:05:49 -0700122 sk_sp<SkImageFilter> blur(SkBlurImageFilter::Create(five, five, input));
senorblanco297f7ce2016-03-23 13:44:26 -0700123 SkMatrix matrix;
124
125 matrix.setTranslate(SK_Scalar1, SK_Scalar1);
126 matrix.postRotate(SkIntToScalar(45), SK_Scalar1, SK_Scalar1);
127
128 SkRTreeFactory factory;
129 SkPictureRecorder recorder;
130 SkCanvas* recordingCanvas = recorder.beginRecording(64, 64, &factory, 0);
131
132 SkPaint greenPaint;
133 greenPaint.setColor(SK_ColorGREEN);
134 recordingCanvas->drawRect(SkRect::Make(SkIRect::MakeXYWH(10, 10, 30, 20)), greenPaint);
135 sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture());
robertphillips5ff17b12016-03-28 13:13:42 -0700136 sk_sp<SkImageFilter> pictureFilter(SkPictureImageFilter::Make(picture));
reedfe630452016-03-25 09:08:00 -0700137 sk_sp<SkShader> shader(SkPerlinNoiseShader::MakeTurbulence(SK_Scalar1, SK_Scalar1, 1, 0));
senorblanco297f7ce2016-03-23 13:44:26 -0700138
139 SkPaint paint;
140 paint.setShader(shader);
robertphillips372177e2016-03-30 07:32:28 -0700141 sk_sp<SkImageFilter> paintFilter(SkPaintImageFilter::Make(paint));
senorblanco297f7ce2016-03-23 13:44:26 -0700142
143 sk_sp<SkShader> greenColorShader(SkShader::MakeColorShader(SK_ColorGREEN));
144 SkPaint greenColorShaderPaint;
145 greenColorShaderPaint.setShader(greenColorShader);
146 SkImageFilter::CropRect leftSideCropRect(SkRect::MakeXYWH(0, 0, 32, 64));
robertphillips372177e2016-03-30 07:32:28 -0700147 sk_sp<SkImageFilter> paintFilterLeft(SkPaintImageFilter::Make(greenColorShaderPaint,
148 &leftSideCropRect));
senorblanco297f7ce2016-03-23 13:44:26 -0700149 SkImageFilter::CropRect rightSideCropRect(SkRect::MakeXYWH(32, 0, 32, 64));
robertphillips372177e2016-03-30 07:32:28 -0700150 sk_sp<SkImageFilter> paintFilterRight(SkPaintImageFilter::Make(greenColorShaderPaint,
151 &rightSideCropRect));
senorblanco297f7ce2016-03-23 13:44:26 -0700152
153 this->addFilter("color filter",
154 SkColorFilterImageFilter::Create(cf.get(), input, cropRect));
155 this->addFilter("displacement map", SkDisplacementMapEffect::Create(
156 SkDisplacementMapEffect::kR_ChannelSelectorType,
157 SkDisplacementMapEffect::kB_ChannelSelectorType,
158 20.0f, gradientSource.get(), input, cropRect));
159 this->addFilter("blur", SkBlurImageFilter::Create(SK_Scalar1, SK_Scalar1, input, cropRect));
160 this->addFilter("drop shadow", SkDropShadowImageFilter::Create(
161 SK_Scalar1, SK_Scalar1, SK_Scalar1, SK_Scalar1, SK_ColorGREEN,
162 SkDropShadowImageFilter::kDrawShadowAndForeground_ShadowMode, input, cropRect));
163 this->addFilter("diffuse lighting", SkLightingImageFilter::CreatePointLitDiffuse(
164 location, SK_ColorGREEN, 0, 0, input, cropRect));
165 this->addFilter("specular lighting",
166 SkLightingImageFilter::CreatePointLitSpecular(location, SK_ColorGREEN, 0, 0, 0,
167 input, cropRect));
168 this->addFilter("matrix convolution",
169 SkMatrixConvolutionImageFilter::Create(
170 kernelSize, kernel, gain, bias, SkIPoint::Make(1, 1),
171 SkMatrixConvolutionImageFilter::kRepeat_TileMode, false, input, cropRect));
robertphillips2238c9d2016-03-30 13:34:16 -0700172 this->addFilter("merge", SkMergeImageFilter::Make(sk_ref_sp<SkImageFilter>(input),
173 sk_ref_sp<SkImageFilter>(input),
174 SkXfermode::kSrcOver_Mode,
175 cropRect).release());
176 this->addFilter("merge with disjoint inputs", SkMergeImageFilter::Make(
177 std::move(paintFilterLeft), std::move(paintFilterRight),
178 SkXfermode::kSrcOver_Mode, cropRect).release());
senorblanco297f7ce2016-03-23 13:44:26 -0700179 this->addFilter("offset",
robertphillips51a315e2016-03-31 09:05:49 -0700180 SkOffsetImageFilter::Make(SK_Scalar1, SK_Scalar1,
181 sk_ref_sp<SkImageFilter>(input),
182 cropRect).release());
senorblanco297f7ce2016-03-23 13:44:26 -0700183 this->addFilter("dilate", SkDilateImageFilter::Create(3, 2, input, cropRect));
184 this->addFilter("erode", SkErodeImageFilter::Create(2, 3, input, cropRect));
185 this->addFilter("tile", SkTileImageFilter::Create(
186 SkRect::MakeXYWH(0, 0, 50, 50),
187 cropRect ? cropRect->rect() : SkRect::MakeXYWH(0, 0, 100, 100),
188 input));
189 if (!cropRect) {
190 this->addFilter("matrix", SkImageFilter::CreateMatrixFilter(
191 matrix, kLow_SkFilterQuality, input));
192 }
robertphillips51a315e2016-03-31 09:05:49 -0700193 this->addFilter("blur and offset",
194 SkOffsetImageFilter::Make(five, five, blur,
195 cropRect).release());
senorblanco297f7ce2016-03-23 13:44:26 -0700196 this->addFilter("picture and blur", SkBlurImageFilter::Create(
197 five, five, pictureFilter.get(), cropRect));
198 this->addFilter("paint and blur", SkBlurImageFilter::Create(
199 five, five, paintFilter.get(), cropRect));
reedcfb6bdf2016-03-29 11:32:50 -0700200 this->addFilter("xfermode", SkXfermodeImageFilter::Make(
201 SkXfermode::Make(SkXfermode::kSrc_Mode), input, input, cropRect).release());
senorblanco297f7ce2016-03-23 13:44:26 -0700202 }
203 int count() const { return fFilters.count(); }
204 SkImageFilter* getFilter(int index) const { return fFilters[index].fFilter.get(); }
205 const char* getName(int index) const { return fFilters[index].fName; }
206private:
207 struct Filter {
208 Filter() : fName(nullptr), fFilter(nullptr) {}
209 Filter(const char* name, SkImageFilter* filter) : fName(name), fFilter(filter) {}
210 const char* fName;
211 sk_sp<SkImageFilter> fFilter;
212 };
213 void addFilter(const char* name, SkImageFilter* filter) {
214 fFilters.push_back(Filter(name, filter));
215 }
216
217 SkTArray<Filter> fFilters;
218};
219
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +0000220}
221
reed60c9b582016-04-03 09:11:13 -0700222sk_sp<SkFlattenable> MatrixTestImageFilter::CreateProc(SkReadBuffer& buffer) {
reed9fa60da2014-08-21 07:59:51 -0700223 SK_IMAGEFILTER_UNFLATTEN_COMMON(common, 1);
224 skiatest::Reporter* reporter = (skiatest::Reporter*)buffer.readFunctionPtr();
225 SkMatrix matrix;
226 buffer.readMatrix(&matrix);
reed60c9b582016-04-03 09:11:13 -0700227 return sk_make_sp<MatrixTestImageFilter>(reporter, matrix);
reed9fa60da2014-08-21 07:59:51 -0700228}
229
robertphillipsf3f5bad2014-12-19 13:49:15 -0800230#ifndef SK_IGNORE_TO_STRING
231void MatrixTestImageFilter::toString(SkString* str) const {
232 str->appendf("MatrixTestImageFilter: (");
233 str->append(")");
234}
235#endif
236
reed9ce9d672016-03-17 10:51:11 -0700237static sk_sp<SkImage> make_small_image() {
reede8f30622016-03-23 18:59:25 -0700238 auto surface(SkSurface::MakeRasterN32Premul(kBitmapSize, kBitmapSize));
fmalita5598b632015-09-15 11:26:13 -0700239 SkCanvas* canvas = surface->getCanvas();
240 canvas->clear(0x00000000);
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000241 SkPaint darkPaint;
242 darkPaint.setColor(0xFF804020);
243 SkPaint lightPaint;
244 lightPaint.setColor(0xFF244484);
245 const int i = kBitmapSize / 4;
246 for (int y = 0; y < kBitmapSize; y += i) {
247 for (int x = 0; x < kBitmapSize; x += i) {
fmalita5598b632015-09-15 11:26:13 -0700248 canvas->save();
249 canvas->translate(SkIntToScalar(x), SkIntToScalar(y));
250 canvas->drawRect(SkRect::MakeXYWH(0, 0,
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000251 SkIntToScalar(i),
252 SkIntToScalar(i)), darkPaint);
fmalita5598b632015-09-15 11:26:13 -0700253 canvas->drawRect(SkRect::MakeXYWH(SkIntToScalar(i),
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000254 0,
255 SkIntToScalar(i),
256 SkIntToScalar(i)), lightPaint);
fmalita5598b632015-09-15 11:26:13 -0700257 canvas->drawRect(SkRect::MakeXYWH(0,
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000258 SkIntToScalar(i),
259 SkIntToScalar(i),
260 SkIntToScalar(i)), lightPaint);
fmalita5598b632015-09-15 11:26:13 -0700261 canvas->drawRect(SkRect::MakeXYWH(SkIntToScalar(i),
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000262 SkIntToScalar(i),
263 SkIntToScalar(i),
264 SkIntToScalar(i)), darkPaint);
fmalita5598b632015-09-15 11:26:13 -0700265 canvas->restore();
commit-bot@chromium.org4b681bc2013-09-13 12:40:02 +0000266 }
267 }
fmalita5598b632015-09-15 11:26:13 -0700268
reed9ce9d672016-03-17 10:51:11 -0700269 return surface->makeImageSnapshot();
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000270}
senorblanco@chromium.org194d7752013-07-24 22:19:24 +0000271
halcanary96fcdcc2015-08-27 07:41:13 -0700272static SkImageFilter* make_scale(float amount, SkImageFilter* input = nullptr) {
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000273 SkScalar s = amount;
274 SkScalar matrix[20] = { s, 0, 0, 0, 0,
275 0, s, 0, 0, 0,
276 0, 0, s, 0, 0,
277 0, 0, 0, s, 0 };
reedd053ce92016-03-22 10:17:23 -0700278 auto filter(SkColorFilter::MakeMatrixFilterRowMajor255(matrix));
279 return SkColorFilterImageFilter::Create(filter.get(), input);
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000280}
281
reedcedc36f2015-03-08 04:42:52 -0700282static SkImageFilter* make_grayscale(SkImageFilter* input, const SkImageFilter::CropRect* cropRect) {
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000283 SkScalar matrix[20];
284 memset(matrix, 0, 20 * sizeof(SkScalar));
285 matrix[0] = matrix[5] = matrix[10] = 0.2126f;
286 matrix[1] = matrix[6] = matrix[11] = 0.7152f;
287 matrix[2] = matrix[7] = matrix[12] = 0.0722f;
288 matrix[18] = 1.0f;
reedd053ce92016-03-22 10:17:23 -0700289 auto filter(SkColorFilter::MakeMatrixFilterRowMajor255(matrix));
290 return SkColorFilterImageFilter::Create(filter.get(), input, cropRect);
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000291}
292
reedcedc36f2015-03-08 04:42:52 -0700293static SkImageFilter* make_blue(SkImageFilter* input, const SkImageFilter::CropRect* cropRect) {
reedd053ce92016-03-22 10:17:23 -0700294 auto filter(SkColorFilter::MakeModeFilter(SK_ColorBLUE, SkXfermode::kSrcIn_Mode));
295 return SkColorFilterImageFilter::Create(filter.get(), input, cropRect);
reedcedc36f2015-03-08 04:42:52 -0700296}
297
robertphillips37bd7c32016-03-17 14:31:39 -0700298static sk_sp<SkSpecialSurface> create_empty_special_surface(GrContext* context,
299 SkImageFilter::Proxy* proxy,
300 int widthHeight) {
robertphillips4418dba2016-03-07 12:45:14 -0800301 if (context) {
302 GrSurfaceDesc desc;
303 desc.fConfig = kSkia8888_GrPixelConfig;
304 desc.fFlags = kRenderTarget_GrSurfaceFlag;
305 desc.fWidth = widthHeight;
306 desc.fHeight = widthHeight;
robertphillips37bd7c32016-03-17 14:31:39 -0700307 return SkSpecialSurface::MakeRenderTarget(proxy, context, desc);
robertphillips4418dba2016-03-07 12:45:14 -0800308 } else {
309 const SkImageInfo info = SkImageInfo::MakeN32(widthHeight, widthHeight,
310 kOpaque_SkAlphaType);
robertphillips37bd7c32016-03-17 14:31:39 -0700311 return SkSpecialSurface::MakeRaster(proxy, info);
robertphillips4418dba2016-03-07 12:45:14 -0800312 }
senorblancobf680c32016-03-16 16:15:53 -0700313}
314
robertphillips37bd7c32016-03-17 14:31:39 -0700315static sk_sp<SkSpecialImage> create_empty_special_image(GrContext* context,
316 SkImageFilter::Proxy* proxy,
317 int widthHeight) {
318 sk_sp<SkSpecialSurface> surf(create_empty_special_surface(context, proxy, widthHeight));
robertphillips4418dba2016-03-07 12:45:14 -0800319
320 SkASSERT(surf);
321
322 SkCanvas* canvas = surf->getCanvas();
323 SkASSERT(canvas);
324
325 canvas->clear(0x0);
326
robertphillips37bd7c32016-03-17 14:31:39 -0700327 return surf->makeImageSnapshot();
robertphillips4418dba2016-03-07 12:45:14 -0800328}
329
330
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000331DEF_TEST(ImageFilter, reporter) {
332 {
reedcedc36f2015-03-08 04:42:52 -0700333 // Check that two non-clipping color-matrice-filters concatenate into a single filter.
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000334 SkAutoTUnref<SkImageFilter> halfBrightness(make_scale(0.5f));
335 SkAutoTUnref<SkImageFilter> quarterBrightness(make_scale(0.5f, halfBrightness));
halcanary96fcdcc2015-08-27 07:41:13 -0700336 REPORTER_ASSERT(reporter, nullptr == quarterBrightness->getInput(0));
reedcedc36f2015-03-08 04:42:52 -0700337 SkColorFilter* cf;
338 REPORTER_ASSERT(reporter, quarterBrightness->asColorFilter(&cf));
halcanary96fcdcc2015-08-27 07:41:13 -0700339 REPORTER_ASSERT(reporter, cf->asColorMatrix(nullptr));
reedcedc36f2015-03-08 04:42:52 -0700340 cf->unref();
senorblanco@chromium.org194d7752013-07-24 22:19:24 +0000341 }
342
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000343 {
reedcedc36f2015-03-08 04:42:52 -0700344 // Check that a clipping color-matrice-filter followed by a color-matrice-filters
345 // concatenates into a single filter, but not a matrixfilter (due to clamping).
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000346 SkAutoTUnref<SkImageFilter> doubleBrightness(make_scale(2.0f));
347 SkAutoTUnref<SkImageFilter> halfBrightness(make_scale(0.5f, doubleBrightness));
halcanary96fcdcc2015-08-27 07:41:13 -0700348 REPORTER_ASSERT(reporter, nullptr == halfBrightness->getInput(0));
reedcedc36f2015-03-08 04:42:52 -0700349 SkColorFilter* cf;
350 REPORTER_ASSERT(reporter, halfBrightness->asColorFilter(&cf));
halcanary96fcdcc2015-08-27 07:41:13 -0700351 REPORTER_ASSERT(reporter, !cf->asColorMatrix(nullptr));
reedcedc36f2015-03-08 04:42:52 -0700352 cf->unref();
senorblanco@chromium.org194d7752013-07-24 22:19:24 +0000353 }
354
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000355 {
356 // Check that a color filter image filter without a crop rect can be
357 // expressed as a color filter.
halcanary96fcdcc2015-08-27 07:41:13 -0700358 SkAutoTUnref<SkImageFilter> gray(make_grayscale(nullptr, nullptr));
359 REPORTER_ASSERT(reporter, true == gray->asColorFilter(nullptr));
senorblanco@chromium.org194d7752013-07-24 22:19:24 +0000360 }
mtklein2afbe232016-02-07 12:23:10 -0800361
reedcedc36f2015-03-08 04:42:52 -0700362 {
363 // Check that a colorfilterimage filter without a crop rect but with an input
364 // that is another colorfilterimage can be expressed as a colorfilter (composed).
halcanary96fcdcc2015-08-27 07:41:13 -0700365 SkAutoTUnref<SkImageFilter> mode(make_blue(nullptr, nullptr));
366 SkAutoTUnref<SkImageFilter> gray(make_grayscale(mode, nullptr));
367 REPORTER_ASSERT(reporter, true == gray->asColorFilter(nullptr));
reedcedc36f2015-03-08 04:42:52 -0700368 }
369
370 {
371 // Test that if we exceed the limit of what ComposeColorFilter can combine, we still
372 // can build the DAG and won't assert if we call asColorFilter.
halcanary96fcdcc2015-08-27 07:41:13 -0700373 SkAutoTUnref<SkImageFilter> filter(make_blue(nullptr, nullptr));
reedcedc36f2015-03-08 04:42:52 -0700374 const int kWayTooManyForComposeColorFilter = 100;
375 for (int i = 0; i < kWayTooManyForComposeColorFilter; ++i) {
halcanary96fcdcc2015-08-27 07:41:13 -0700376 filter.reset(make_blue(filter, nullptr));
reedcedc36f2015-03-08 04:42:52 -0700377 // the first few of these will succeed, but after we hit the internal limit,
378 // it will then return false.
halcanary96fcdcc2015-08-27 07:41:13 -0700379 (void)filter->asColorFilter(nullptr);
reedcedc36f2015-03-08 04:42:52 -0700380 }
381 }
reed5c518a82015-03-05 14:47:29 -0800382
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000383 {
384 // Check that a color filter image filter with a crop rect cannot
385 // be expressed as a color filter.
386 SkImageFilter::CropRect cropRect(SkRect::MakeXYWH(0, 0, 100, 100));
halcanary96fcdcc2015-08-27 07:41:13 -0700387 SkAutoTUnref<SkImageFilter> grayWithCrop(make_grayscale(nullptr, &cropRect));
388 REPORTER_ASSERT(reporter, false == grayWithCrop->asColorFilter(nullptr));
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000389 }
390
391 {
senorblanco3df05012014-07-03 11:13:09 -0700392 // Check that two non-commutative matrices are concatenated in
393 // the correct order.
394 SkScalar blueToRedMatrix[20] = { 0 };
395 blueToRedMatrix[2] = blueToRedMatrix[18] = SK_Scalar1;
396 SkScalar redToGreenMatrix[20] = { 0 };
397 redToGreenMatrix[5] = redToGreenMatrix[18] = SK_Scalar1;
reedd053ce92016-03-22 10:17:23 -0700398 auto blueToRed(SkColorFilter::MakeMatrixFilterRowMajor255(blueToRedMatrix));
senorblanco3df05012014-07-03 11:13:09 -0700399 SkAutoTUnref<SkImageFilter> filter1(SkColorFilterImageFilter::Create(blueToRed.get()));
reedd053ce92016-03-22 10:17:23 -0700400 auto redToGreen(SkColorFilter::MakeMatrixFilterRowMajor255(redToGreenMatrix));
senorblanco3df05012014-07-03 11:13:09 -0700401 SkAutoTUnref<SkImageFilter> filter2(SkColorFilterImageFilter::Create(redToGreen.get(), filter1.get()));
402
403 SkBitmap result;
404 result.allocN32Pixels(kBitmapSize, kBitmapSize);
405
406 SkPaint paint;
407 paint.setColor(SK_ColorBLUE);
408 paint.setImageFilter(filter2.get());
409 SkCanvas canvas(result);
410 canvas.clear(0x0);
411 SkRect rect = SkRect::Make(SkIRect::MakeWH(kBitmapSize, kBitmapSize));
412 canvas.drawRect(rect, paint);
413 uint32_t pixel = *result.getAddr32(0, 0);
414 // The result here should be green, since we have effectively shifted blue to green.
415 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
416 }
417
418 {
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000419 // Tests pass by not asserting
reed9ce9d672016-03-17 10:51:11 -0700420 sk_sp<SkImage> image(make_small_image());
fmalita5598b632015-09-15 11:26:13 -0700421 SkBitmap result;
mike@reedtribe.orgdeee4962014-02-13 14:41:43 +0000422 result.allocN32Pixels(kBitmapSize, kBitmapSize);
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000423
senorblanco@chromium.org194d7752013-07-24 22:19:24 +0000424 {
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000425 // This tests for :
426 // 1 ) location at (0,0,1)
robertphillips3d32d762015-07-13 13:16:44 -0700427 SkPoint3 location = SkPoint3::Make(0, 0, SK_Scalar1);
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000428 // 2 ) location and target at same value
robertphillips3d32d762015-07-13 13:16:44 -0700429 SkPoint3 target = SkPoint3::Make(location.fX, location.fY, location.fZ);
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000430 // 3 ) large negative specular exponent value
431 SkScalar specularExponent = -1000;
432
robertphillips549c8992016-04-01 09:28:51 -0700433 sk_sp<SkImageFilter> bmSrc(SkImageSource::Make(std::move(image)));
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000434 SkPaint paint;
435 paint.setImageFilter(SkLightingImageFilter::CreateSpotLitSpecular(
436 location, target, specularExponent, 180,
437 0xFFFFFFFF, SK_Scalar1, SK_Scalar1, SK_Scalar1,
robertphillips549c8992016-04-01 09:28:51 -0700438 bmSrc.get()))->unref();
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000439 SkCanvas canvas(result);
440 SkRect r = SkRect::MakeWH(SkIntToScalar(kBitmapSize),
441 SkIntToScalar(kBitmapSize));
442 canvas.drawRect(r, paint);
senorblanco@chromium.org194d7752013-07-24 22:19:24 +0000443 }
senorblanco@chromium.org194d7752013-07-24 22:19:24 +0000444 }
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +0000445}
senorblanco@chromium.org6776b822014-01-03 21:48:22 +0000446
robertphillips4418dba2016-03-07 12:45:14 -0800447static void test_crop_rects(SkImageFilter::Proxy* proxy,
448 skiatest::Reporter* reporter,
449 GrContext* context) {
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +0000450 // Check that all filters offset to their absolute crop rect,
451 // unaffected by the input crop rect.
452 // Tests pass by not asserting.
robertphillips37bd7c32016-03-17 14:31:39 -0700453 sk_sp<SkSpecialImage> srcImg(create_empty_special_image(context, proxy, 100));
robertphillips4418dba2016-03-07 12:45:14 -0800454 SkASSERT(srcImg);
senorblanco@chromium.org6776b822014-01-03 21:48:22 +0000455
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +0000456 SkImageFilter::CropRect inputCropRect(SkRect::MakeXYWH(8, 13, 80, 80));
457 SkImageFilter::CropRect cropRect(SkRect::MakeXYWH(20, 30, 60, 60));
halcanary96fcdcc2015-08-27 07:41:13 -0700458 SkAutoTUnref<SkImageFilter> input(make_grayscale(nullptr, &inputCropRect));
senorblanco@chromium.org6776b822014-01-03 21:48:22 +0000459
senorblanco297f7ce2016-03-23 13:44:26 -0700460 FilterList filters(input.get(), &cropRect);
senorblanco@chromium.org6776b822014-01-03 21:48:22 +0000461
senorblanco297f7ce2016-03-23 13:44:26 -0700462 for (int i = 0; i < filters.count(); ++i) {
463 SkImageFilter* filter = filters.getFilter(i);
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +0000464 SkIPoint offset;
reed4e23cda2016-01-11 10:56:59 -0800465 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeWH(100, 100), nullptr);
robertphillips2302de92016-03-24 07:26:32 -0700466 sk_sp<SkSpecialImage> resultImg(filter->filterImage(srcImg.get(), ctx, &offset));
senorblanco297f7ce2016-03-23 13:44:26 -0700467 REPORTER_ASSERT_MESSAGE(reporter, resultImg, filters.getName(i));
468 REPORTER_ASSERT_MESSAGE(reporter, offset.fX == 20 && offset.fY == 30, filters.getName(i));
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +0000469 }
470}
471
robertphillips4418dba2016-03-07 12:45:14 -0800472static void test_negative_blur_sigma(SkImageFilter::Proxy* proxy,
473 skiatest::Reporter* reporter,
474 GrContext* context) {
senorblanco32673b92014-09-09 09:15:04 -0700475 // Check that SkBlurImageFilter will accept a negative sigma, either in
476 // the given arguments or after CTM application.
reed5ea95df2015-10-06 14:05:32 -0700477 const int width = 32, height = 32;
478 const SkScalar five = SkIntToScalar(5);
senorblanco32673b92014-09-09 09:15:04 -0700479
reed5ea95df2015-10-06 14:05:32 -0700480 SkAutoTUnref<SkImageFilter> positiveFilter(SkBlurImageFilter::Create(five, five));
481 SkAutoTUnref<SkImageFilter> negativeFilter(SkBlurImageFilter::Create(-five, five));
senorblanco32673b92014-09-09 09:15:04 -0700482
483 SkBitmap gradient = make_gradient_circle(width, height);
robertphillips37bd7c32016-03-17 14:31:39 -0700484 sk_sp<SkSpecialImage> imgSrc(SkSpecialImage::MakeFromRaster(proxy,
485 SkIRect::MakeWH(width, height),
486 gradient));
robertphillips4418dba2016-03-07 12:45:14 -0800487
senorblanco32673b92014-09-09 09:15:04 -0700488 SkIPoint offset;
reed4e23cda2016-01-11 10:56:59 -0800489 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeWH(32, 32), nullptr);
robertphillips4418dba2016-03-07 12:45:14 -0800490
robertphillips2302de92016-03-24 07:26:32 -0700491 sk_sp<SkSpecialImage> positiveResult1(positiveFilter->filterImage(imgSrc.get(), ctx, &offset));
robertphillips4418dba2016-03-07 12:45:14 -0800492 REPORTER_ASSERT(reporter, positiveResult1);
493
robertphillips2302de92016-03-24 07:26:32 -0700494 sk_sp<SkSpecialImage> negativeResult1(negativeFilter->filterImage(imgSrc.get(), ctx, &offset));
robertphillips4418dba2016-03-07 12:45:14 -0800495 REPORTER_ASSERT(reporter, negativeResult1);
496
senorblanco32673b92014-09-09 09:15:04 -0700497 SkMatrix negativeScale;
498 negativeScale.setScale(-SK_Scalar1, SK_Scalar1);
reed4e23cda2016-01-11 10:56:59 -0800499 SkImageFilter::Context negativeCTX(negativeScale, SkIRect::MakeWH(32, 32), nullptr);
robertphillips4418dba2016-03-07 12:45:14 -0800500
robertphillips2302de92016-03-24 07:26:32 -0700501 sk_sp<SkSpecialImage> negativeResult2(positiveFilter->filterImage(imgSrc.get(),
502 negativeCTX,
503 &offset));
robertphillips4418dba2016-03-07 12:45:14 -0800504 REPORTER_ASSERT(reporter, negativeResult2);
505
robertphillips2302de92016-03-24 07:26:32 -0700506 sk_sp<SkSpecialImage> positiveResult2(negativeFilter->filterImage(imgSrc.get(),
507 negativeCTX,
508 &offset));
robertphillips4418dba2016-03-07 12:45:14 -0800509 REPORTER_ASSERT(reporter, positiveResult2);
510
511
512 SkBitmap positiveResultBM1, positiveResultBM2;
513 SkBitmap negativeResultBM1, negativeResultBM2;
514
robertphillips2302de92016-03-24 07:26:32 -0700515 TestingSpecialImageAccess::GetROPixels(positiveResult1.get(), &positiveResultBM1);
516 TestingSpecialImageAccess::GetROPixels(positiveResult2.get(), &positiveResultBM2);
517 TestingSpecialImageAccess::GetROPixels(negativeResult1.get(), &negativeResultBM1);
518 TestingSpecialImageAccess::GetROPixels(negativeResult2.get(), &negativeResultBM2);
robertphillips4418dba2016-03-07 12:45:14 -0800519
520 SkAutoLockPixels lockP1(positiveResultBM1);
521 SkAutoLockPixels lockP2(positiveResultBM2);
522 SkAutoLockPixels lockN1(negativeResultBM1);
523 SkAutoLockPixels lockN2(negativeResultBM2);
senorblanco32673b92014-09-09 09:15:04 -0700524 for (int y = 0; y < height; y++) {
robertphillips4418dba2016-03-07 12:45:14 -0800525 int diffs = memcmp(positiveResultBM1.getAddr32(0, y),
526 negativeResultBM1.getAddr32(0, y),
527 positiveResultBM1.rowBytes());
senorblanco32673b92014-09-09 09:15:04 -0700528 REPORTER_ASSERT(reporter, !diffs);
529 if (diffs) {
530 break;
531 }
robertphillips4418dba2016-03-07 12:45:14 -0800532 diffs = memcmp(positiveResultBM1.getAddr32(0, y),
533 negativeResultBM2.getAddr32(0, y),
534 positiveResultBM1.rowBytes());
senorblanco32673b92014-09-09 09:15:04 -0700535 REPORTER_ASSERT(reporter, !diffs);
536 if (diffs) {
537 break;
538 }
robertphillips4418dba2016-03-07 12:45:14 -0800539 diffs = memcmp(positiveResultBM1.getAddr32(0, y),
540 positiveResultBM2.getAddr32(0, y),
541 positiveResultBM1.rowBytes());
senorblanco32673b92014-09-09 09:15:04 -0700542 REPORTER_ASSERT(reporter, !diffs);
543 if (diffs) {
544 break;
545 }
546 }
547}
548
robertphillips4418dba2016-03-07 12:45:14 -0800549typedef void (*PFTest)(SkImageFilter::Proxy* proxy,
550 skiatest::Reporter* reporter,
551 GrContext* context);
552
553static void run_raster_test(skiatest::Reporter* reporter,
554 int widthHeight,
555 PFTest test) {
robertphillips9a53fd72015-06-22 09:46:59 -0700556 const SkSurfaceProps props(SkSurfaceProps::kLegacyFontHost_InitType);
557
robertphillips4418dba2016-03-07 12:45:14 -0800558 const SkImageInfo info = SkImageInfo::MakeN32Premul(widthHeight, widthHeight);
559
robertphillips9a53fd72015-06-22 09:46:59 -0700560 SkAutoTUnref<SkBaseDevice> device(SkBitmapDevice::Create(info, props));
reed88d064d2015-10-12 11:30:02 -0700561 SkImageFilter::DeviceProxy proxy(device);
robertphillips9a53fd72015-06-22 09:46:59 -0700562
robertphillips4418dba2016-03-07 12:45:14 -0800563 (*test)(&proxy, reporter, nullptr);
senorblanco32673b92014-09-09 09:15:04 -0700564}
565
robertphillips4418dba2016-03-07 12:45:14 -0800566#if SK_SUPPORT_GPU
567static void run_gpu_test(skiatest::Reporter* reporter,
568 GrContext* context,
569 int widthHeight,
570 PFTest test) {
571 const SkSurfaceProps props(SkSurfaceProps::kLegacyFontHost_InitType);
572
573 SkAutoTUnref<SkGpuDevice> device(SkGpuDevice::Create(context,
574 SkBudgeted::kNo,
halcanary9d524f22016-03-29 09:03:52 -0700575 SkImageInfo::MakeN32Premul(widthHeight,
robertphillips4418dba2016-03-07 12:45:14 -0800576 widthHeight),
577 0,
578 &props,
579 SkGpuDevice::kUninit_InitContents));
580 SkImageFilter::DeviceProxy proxy(device);
581
582 (*test)(&proxy, reporter, context);
583}
584#endif
585
586DEF_TEST(TestNegativeBlurSigma, reporter) {
587 run_raster_test(reporter, 100, test_negative_blur_sigma);
588}
589
590#if SK_SUPPORT_GPU
591DEF_GPUTEST_FOR_NATIVE_CONTEXT(TestNegativeBlurSigma_Gpu, reporter, context) {
592 run_gpu_test(reporter, context, 100, test_negative_blur_sigma);
593}
594#endif
595
senorblancobf680c32016-03-16 16:15:53 -0700596static void test_zero_blur_sigma(SkImageFilter::Proxy* proxy,
597 skiatest::Reporter* reporter,
598 GrContext* context) {
599 // Check that SkBlurImageFilter with a zero sigma and a non-zero srcOffset works correctly.
600 SkImageFilter::CropRect cropRect(SkRect::Make(SkIRect::MakeXYWH(5, 0, 5, 10)));
robertphillips51a315e2016-03-31 09:05:49 -0700601 sk_sp<SkImageFilter> input(SkOffsetImageFilter::Make(0, 0, nullptr, &cropRect));
602 sk_sp<SkImageFilter> filter(SkBlurImageFilter::Create(0, 0, input.get(), &cropRect));
senorblancobf680c32016-03-16 16:15:53 -0700603
robertphillips37bd7c32016-03-17 14:31:39 -0700604 sk_sp<SkSpecialSurface> surf(create_empty_special_surface(context, proxy, 10));
senorblancobf680c32016-03-16 16:15:53 -0700605 surf->getCanvas()->clear(SK_ColorGREEN);
robertphillips37bd7c32016-03-17 14:31:39 -0700606 sk_sp<SkSpecialImage> image(surf->makeImageSnapshot());
senorblancobf680c32016-03-16 16:15:53 -0700607
608 SkIPoint offset;
609 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeWH(32, 32), nullptr);
610
robertphillips2302de92016-03-24 07:26:32 -0700611 sk_sp<SkSpecialImage> result(filter->filterImage(image.get(), ctx, &offset));
senorblancobf680c32016-03-16 16:15:53 -0700612 REPORTER_ASSERT(reporter, offset.fX == 5 && offset.fY == 0);
613 REPORTER_ASSERT(reporter, result);
614 REPORTER_ASSERT(reporter, result->width() == 5 && result->height() == 10);
615
616 SkBitmap resultBM;
617
robertphillips2302de92016-03-24 07:26:32 -0700618 TestingSpecialImageAccess::GetROPixels(result.get(), &resultBM);
senorblancobf680c32016-03-16 16:15:53 -0700619
620 SkAutoLockPixels lock(resultBM);
621 for (int y = 0; y < resultBM.height(); y++) {
622 for (int x = 0; x < resultBM.width(); x++) {
623 bool diff = *resultBM.getAddr32(x, y) != SK_ColorGREEN;
624 REPORTER_ASSERT(reporter, !diff);
625 if (diff) {
626 break;
627 }
628 }
629 }
630}
631
632DEF_TEST(TestZeroBlurSigma, reporter) {
633 run_raster_test(reporter, 100, test_zero_blur_sigma);
634}
635
636#if SK_SUPPORT_GPU
637DEF_GPUTEST_FOR_NATIVE_CONTEXT(TestZeroBlurSigma_Gpu, reporter, context) {
638 run_gpu_test(reporter, context, 100, test_zero_blur_sigma);
639}
640#endif
641
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +0000642DEF_TEST(ImageFilterDrawTiled, reporter) {
643 // Check that all filters when drawn tiled (with subsequent clip rects) exactly
644 // match the same filters drawn with a single full-canvas bitmap draw.
645 // Tests pass by not asserting.
646
senorblanco297f7ce2016-03-23 13:44:26 -0700647 FilterList filters;
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +0000648
649 SkBitmap untiledResult, tiledResult;
reed5ea95df2015-10-06 14:05:32 -0700650 const int width = 64, height = 64;
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +0000651 untiledResult.allocN32Pixels(width, height);
652 tiledResult.allocN32Pixels(width, height);
653 SkCanvas tiledCanvas(tiledResult);
654 SkCanvas untiledCanvas(untiledResult);
senorblanco@chromium.orgd4db6572014-05-07 20:00:04 +0000655 int tileSize = 8;
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +0000656
senorblanco@chromium.orgd4db6572014-05-07 20:00:04 +0000657 for (int scale = 1; scale <= 2; ++scale) {
senorblanco297f7ce2016-03-23 13:44:26 -0700658 for (int i = 0; i < filters.count(); ++i) {
senorblanco@chromium.orgd4db6572014-05-07 20:00:04 +0000659 tiledCanvas.clear(0);
660 untiledCanvas.clear(0);
661 SkPaint paint;
senorblanco297f7ce2016-03-23 13:44:26 -0700662 paint.setImageFilter(filters.getFilter(i));
senorblanco@chromium.orgd4db6572014-05-07 20:00:04 +0000663 paint.setTextSize(SkIntToScalar(height));
664 paint.setColor(SK_ColorWHITE);
665 SkString str;
666 const char* text = "ABC";
667 SkScalar ypos = SkIntToScalar(height);
668 untiledCanvas.save();
669 untiledCanvas.scale(SkIntToScalar(scale), SkIntToScalar(scale));
670 untiledCanvas.drawText(text, strlen(text), 0, ypos, paint);
671 untiledCanvas.restore();
672 for (int y = 0; y < height; y += tileSize) {
673 for (int x = 0; x < width; x += tileSize) {
674 tiledCanvas.save();
675 tiledCanvas.clipRect(SkRect::Make(SkIRect::MakeXYWH(x, y, tileSize, tileSize)));
676 tiledCanvas.scale(SkIntToScalar(scale), SkIntToScalar(scale));
677 tiledCanvas.drawText(text, strlen(text), 0, ypos, paint);
678 tiledCanvas.restore();
679 }
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +0000680 }
senorblanco@chromium.orgd4db6572014-05-07 20:00:04 +0000681 untiledCanvas.flush();
682 tiledCanvas.flush();
683 for (int y = 0; y < height; y++) {
684 int diffs = memcmp(untiledResult.getAddr32(0, y), tiledResult.getAddr32(0, y), untiledResult.rowBytes());
senorblanco297f7ce2016-03-23 13:44:26 -0700685 REPORTER_ASSERT_MESSAGE(reporter, !diffs, filters.getName(i));
senorblanco@chromium.orgd4db6572014-05-07 20:00:04 +0000686 if (diffs) {
687 break;
688 }
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +0000689 }
690 }
691 }
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +0000692}
693
mtklein3f3b3d02014-12-01 11:47:08 -0800694static void draw_saveLayer_picture(int width, int height, int tileSize,
robertphillipsa8d7f0b2014-08-29 08:03:56 -0700695 SkBBHFactory* factory, SkBitmap* result) {
mtkleind910f542014-08-22 09:06:34 -0700696
697 SkMatrix matrix;
698 matrix.setTranslate(SkIntToScalar(50), 0);
699
reedd053ce92016-03-22 10:17:23 -0700700 auto cf(SkColorFilter::MakeModeFilter(SK_ColorWHITE, SkXfermode::kSrc_Mode));
mtkleind910f542014-08-22 09:06:34 -0700701 SkAutoTUnref<SkImageFilter> cfif(SkColorFilterImageFilter::Create(cf.get()));
senorblanco8c874ee2015-03-20 06:38:17 -0700702 SkAutoTUnref<SkImageFilter> imageFilter(SkImageFilter::CreateMatrixFilter(matrix, kNone_SkFilterQuality, cfif.get()));
mtkleind910f542014-08-22 09:06:34 -0700703
704 SkPaint paint;
705 paint.setImageFilter(imageFilter.get());
706 SkPictureRecorder recorder;
707 SkRect bounds = SkRect::Make(SkIRect::MakeXYWH(0, 0, 50, 50));
mtklein3f3b3d02014-12-01 11:47:08 -0800708 SkCanvas* recordingCanvas = recorder.beginRecording(SkIntToScalar(width),
709 SkIntToScalar(height),
robertphillipsa8d7f0b2014-08-29 08:03:56 -0700710 factory, 0);
mtkleind910f542014-08-22 09:06:34 -0700711 recordingCanvas->translate(-55, 0);
712 recordingCanvas->saveLayer(&bounds, &paint);
713 recordingCanvas->restore();
reedca2622b2016-03-18 07:25:55 -0700714 sk_sp<SkPicture> picture1(recorder.finishRecordingAsPicture());
mtkleind910f542014-08-22 09:06:34 -0700715
716 result->allocN32Pixels(width, height);
717 SkCanvas canvas(*result);
718 canvas.clear(0);
719 canvas.clipRect(SkRect::Make(SkIRect::MakeWH(tileSize, tileSize)));
720 canvas.drawPicture(picture1.get());
721}
722
723DEF_TEST(ImageFilterDrawMatrixBBH, reporter) {
724 // Check that matrix filter when drawn tiled with BBH exactly
725 // matches the same thing drawn without BBH.
726 // Tests pass by not asserting.
727
728 const int width = 200, height = 200;
729 const int tileSize = 100;
730 SkBitmap result1, result2;
731 SkRTreeFactory factory;
732
robertphillipsa8d7f0b2014-08-29 08:03:56 -0700733 draw_saveLayer_picture(width, height, tileSize, &factory, &result1);
halcanary96fcdcc2015-08-27 07:41:13 -0700734 draw_saveLayer_picture(width, height, tileSize, nullptr, &result2);
mtkleind910f542014-08-22 09:06:34 -0700735
736 for (int y = 0; y < height; y++) {
737 int diffs = memcmp(result1.getAddr32(0, y), result2.getAddr32(0, y), result1.rowBytes());
738 REPORTER_ASSERT(reporter, !diffs);
739 if (diffs) {
740 break;
741 }
742 }
743}
744
halcanary96fcdcc2015-08-27 07:41:13 -0700745static SkImageFilter* makeBlur(SkImageFilter* input = nullptr) {
senorblanco1150a6d2014-08-25 12:46:58 -0700746 return SkBlurImageFilter::Create(SK_Scalar1, SK_Scalar1, input);
747}
748
halcanary96fcdcc2015-08-27 07:41:13 -0700749static SkImageFilter* makeDropShadow(SkImageFilter* input = nullptr) {
senorblanco1150a6d2014-08-25 12:46:58 -0700750 return SkDropShadowImageFilter::Create(
751 SkIntToScalar(100), SkIntToScalar(100),
752 SkIntToScalar(10), SkIntToScalar(10),
sugoi234f0362014-10-23 13:59:52 -0700753 SK_ColorBLUE, SkDropShadowImageFilter::kDrawShadowAndForeground_ShadowMode,
halcanary96fcdcc2015-08-27 07:41:13 -0700754 input, nullptr);
senorblanco1150a6d2014-08-25 12:46:58 -0700755}
756
757DEF_TEST(ImageFilterBlurThenShadowBounds, reporter) {
758 SkAutoTUnref<SkImageFilter> filter1(makeBlur());
759 SkAutoTUnref<SkImageFilter> filter2(makeDropShadow(filter1.get()));
760
761 SkIRect bounds = SkIRect::MakeXYWH(0, 0, 100, 100);
762 SkIRect expectedBounds = SkIRect::MakeXYWH(-133, -133, 236, 236);
senorblancoe5e79842016-03-21 14:51:59 -0700763 bounds = filter2->filterBounds(bounds, SkMatrix::I());
senorblanco1150a6d2014-08-25 12:46:58 -0700764
765 REPORTER_ASSERT(reporter, bounds == expectedBounds);
766}
767
768DEF_TEST(ImageFilterShadowThenBlurBounds, reporter) {
769 SkAutoTUnref<SkImageFilter> filter1(makeDropShadow());
770 SkAutoTUnref<SkImageFilter> filter2(makeBlur(filter1.get()));
771
772 SkIRect bounds = SkIRect::MakeXYWH(0, 0, 100, 100);
773 SkIRect expectedBounds = SkIRect::MakeXYWH(-133, -133, 236, 236);
senorblancoe5e79842016-03-21 14:51:59 -0700774 bounds = filter2->filterBounds(bounds, SkMatrix::I());
senorblanco1150a6d2014-08-25 12:46:58 -0700775
776 REPORTER_ASSERT(reporter, bounds == expectedBounds);
777}
778
779DEF_TEST(ImageFilterDilateThenBlurBounds, reporter) {
780 SkAutoTUnref<SkImageFilter> filter1(SkDilateImageFilter::Create(2, 2));
781 SkAutoTUnref<SkImageFilter> filter2(makeDropShadow(filter1.get()));
782
783 SkIRect bounds = SkIRect::MakeXYWH(0, 0, 100, 100);
784 SkIRect expectedBounds = SkIRect::MakeXYWH(-132, -132, 234, 234);
senorblancoe5e79842016-03-21 14:51:59 -0700785 bounds = filter2->filterBounds(bounds, SkMatrix::I());
senorblanco1150a6d2014-08-25 12:46:58 -0700786
787 REPORTER_ASSERT(reporter, bounds == expectedBounds);
788}
789
ajuma5788faa2015-02-13 09:05:47 -0800790DEF_TEST(ImageFilterComposedBlurFastBounds, reporter) {
robertphillips491fb172016-03-30 12:32:58 -0700791 sk_sp<SkImageFilter> filter1(makeBlur());
792 sk_sp<SkImageFilter> filter2(makeBlur());
793 sk_sp<SkImageFilter> composedFilter(SkComposeImageFilter::Make(std::move(filter1),
794 std::move(filter2)));
ajuma5788faa2015-02-13 09:05:47 -0800795
796 SkRect boundsSrc = SkRect::MakeWH(SkIntToScalar(100), SkIntToScalar(100));
797 SkRect expectedBounds = SkRect::MakeXYWH(
798 SkIntToScalar(-6), SkIntToScalar(-6), SkIntToScalar(112), SkIntToScalar(112));
senorblancoe5e79842016-03-21 14:51:59 -0700799 SkRect boundsDst = composedFilter->computeFastBounds(boundsSrc);
ajuma5788faa2015-02-13 09:05:47 -0800800
801 REPORTER_ASSERT(reporter, boundsDst == expectedBounds);
802}
803
jbroman0e3129d2016-03-17 12:24:23 -0700804DEF_TEST(ImageFilterUnionBounds, reporter) {
robertphillips51a315e2016-03-31 09:05:49 -0700805 sk_sp<SkImageFilter> offset(SkOffsetImageFilter::Make(50, 0, nullptr));
jbroman0e3129d2016-03-17 12:24:23 -0700806 // Regardless of which order they appear in, the image filter bounds should
807 // be combined correctly.
808 {
reedcfb6bdf2016-03-29 11:32:50 -0700809 sk_sp<SkImageFilter> composite(SkXfermodeImageFilter::Make(nullptr, offset.get()));
jbroman0e3129d2016-03-17 12:24:23 -0700810 SkRect bounds = SkRect::MakeWH(100, 100);
811 // Intentionally aliasing here, as that's what the real callers do.
senorblancoe5e79842016-03-21 14:51:59 -0700812 bounds = composite->computeFastBounds(bounds);
jbroman0e3129d2016-03-17 12:24:23 -0700813 REPORTER_ASSERT(reporter, bounds == SkRect::MakeWH(150, 100));
814 }
815 {
reedcfb6bdf2016-03-29 11:32:50 -0700816 sk_sp<SkImageFilter> composite(SkXfermodeImageFilter::Make(nullptr, nullptr,
817 offset.get(), nullptr));
jbroman0e3129d2016-03-17 12:24:23 -0700818 SkRect bounds = SkRect::MakeWH(100, 100);
819 // Intentionally aliasing here, as that's what the real callers do.
senorblancoe5e79842016-03-21 14:51:59 -0700820 bounds = composite->computeFastBounds(bounds);
jbroman0e3129d2016-03-17 12:24:23 -0700821 REPORTER_ASSERT(reporter, bounds == SkRect::MakeWH(150, 100));
822 }
823}
824
robertphillips4418dba2016-03-07 12:45:14 -0800825static void test_imagefilter_merge_result_size(SkImageFilter::Proxy* proxy,
826 skiatest::Reporter* reporter,
827 GrContext* context) {
senorblanco4a243982015-11-25 07:06:55 -0800828 SkBitmap greenBM;
829 greenBM.allocN32Pixels(20, 20);
830 greenBM.eraseColor(SK_ColorGREEN);
reed9ce9d672016-03-17 10:51:11 -0700831 sk_sp<SkImage> greenImage(SkImage::MakeFromBitmap(greenBM));
robertphillips549c8992016-04-01 09:28:51 -0700832 sk_sp<SkImageFilter> source(SkImageSource::Make(std::move(greenImage)));
robertphillips2238c9d2016-03-30 13:34:16 -0700833 sk_sp<SkImageFilter> merge(SkMergeImageFilter::Make(source, source));
senorblanco4a243982015-11-25 07:06:55 -0800834
robertphillips37bd7c32016-03-17 14:31:39 -0700835 sk_sp<SkSpecialImage> srcImg(create_empty_special_image(context, proxy, 1));
robertphillips4418dba2016-03-07 12:45:14 -0800836
reed4e23cda2016-01-11 10:56:59 -0800837 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeXYWH(0, 0, 100, 100), nullptr);
senorblanco4a243982015-11-25 07:06:55 -0800838 SkIPoint offset;
robertphillips4418dba2016-03-07 12:45:14 -0800839
robertphillips2302de92016-03-24 07:26:32 -0700840 sk_sp<SkSpecialImage> resultImg(merge->filterImage(srcImg.get(), ctx, &offset));
robertphillips4418dba2016-03-07 12:45:14 -0800841 REPORTER_ASSERT(reporter, resultImg);
842
843 REPORTER_ASSERT(reporter, resultImg->width() == 20 && resultImg->height() == 20);
senorblanco4a243982015-11-25 07:06:55 -0800844}
845
robertphillips4418dba2016-03-07 12:45:14 -0800846DEF_TEST(ImageFilterMergeResultSize, reporter) {
847 run_raster_test(reporter, 100, test_imagefilter_merge_result_size);
848}
849
850#if SK_SUPPORT_GPU
851DEF_GPUTEST_FOR_NATIVE_CONTEXT(ImageFilterMergeResultSize_Gpu, reporter, context) {
852 run_gpu_test(reporter, context, 100, test_imagefilter_merge_result_size);
853}
854#endif
855
robertphillipsa8d7f0b2014-08-29 08:03:56 -0700856static void draw_blurred_rect(SkCanvas* canvas) {
senorblanco837f5322014-07-14 10:19:54 -0700857 SkAutoTUnref<SkImageFilter> filter(SkBlurImageFilter::Create(SkIntToScalar(8), 0));
858 SkPaint filterPaint;
859 filterPaint.setColor(SK_ColorWHITE);
860 filterPaint.setImageFilter(filter);
halcanary96fcdcc2015-08-27 07:41:13 -0700861 canvas->saveLayer(nullptr, &filterPaint);
senorblanco837f5322014-07-14 10:19:54 -0700862 SkPaint whitePaint;
863 whitePaint.setColor(SK_ColorWHITE);
864 canvas->drawRect(SkRect::Make(SkIRect::MakeWH(4, 4)), whitePaint);
865 canvas->restore();
866}
867
robertphillipsa8d7f0b2014-08-29 08:03:56 -0700868static void draw_picture_clipped(SkCanvas* canvas, const SkRect& clipRect, const SkPicture* picture) {
senorblanco837f5322014-07-14 10:19:54 -0700869 canvas->save();
870 canvas->clipRect(clipRect);
871 canvas->drawPicture(picture);
872 canvas->restore();
873}
874
875DEF_TEST(ImageFilterDrawTiledBlurRTree, reporter) {
876 // Check that the blur filter when recorded with RTree acceleration,
877 // and drawn tiled (with subsequent clip rects) exactly
878 // matches the same filter drawn with without RTree acceleration.
879 // This tests that the "bleed" from the blur into the otherwise-blank
880 // tiles is correctly rendered.
881 // Tests pass by not asserting.
882
883 int width = 16, height = 8;
884 SkBitmap result1, result2;
885 result1.allocN32Pixels(width, height);
886 result2.allocN32Pixels(width, height);
887 SkCanvas canvas1(result1);
888 SkCanvas canvas2(result2);
889 int tileSize = 8;
890
891 canvas1.clear(0);
892 canvas2.clear(0);
893
894 SkRTreeFactory factory;
895
896 SkPictureRecorder recorder1, recorder2;
897 // The only difference between these two pictures is that one has RTree aceleration.
mtklein3f3b3d02014-12-01 11:47:08 -0800898 SkCanvas* recordingCanvas1 = recorder1.beginRecording(SkIntToScalar(width),
899 SkIntToScalar(height),
halcanary96fcdcc2015-08-27 07:41:13 -0700900 nullptr, 0);
mtklein3f3b3d02014-12-01 11:47:08 -0800901 SkCanvas* recordingCanvas2 = recorder2.beginRecording(SkIntToScalar(width),
902 SkIntToScalar(height),
robertphillipsa8d7f0b2014-08-29 08:03:56 -0700903 &factory, 0);
904 draw_blurred_rect(recordingCanvas1);
905 draw_blurred_rect(recordingCanvas2);
reedca2622b2016-03-18 07:25:55 -0700906 sk_sp<SkPicture> picture1(recorder1.finishRecordingAsPicture());
907 sk_sp<SkPicture> picture2(recorder2.finishRecordingAsPicture());
senorblanco837f5322014-07-14 10:19:54 -0700908 for (int y = 0; y < height; y += tileSize) {
909 for (int x = 0; x < width; x += tileSize) {
910 SkRect tileRect = SkRect::Make(SkIRect::MakeXYWH(x, y, tileSize, tileSize));
reedca2622b2016-03-18 07:25:55 -0700911 draw_picture_clipped(&canvas1, tileRect, picture1.get());
912 draw_picture_clipped(&canvas2, tileRect, picture2.get());
senorblanco837f5322014-07-14 10:19:54 -0700913 }
914 }
915 for (int y = 0; y < height; y++) {
916 int diffs = memcmp(result1.getAddr32(0, y), result2.getAddr32(0, y), result1.rowBytes());
917 REPORTER_ASSERT(reporter, !diffs);
918 if (diffs) {
919 break;
920 }
921 }
922}
923
senorblanco@chromium.org91957432014-05-01 14:03:41 +0000924DEF_TEST(ImageFilterMatrixConvolution, reporter) {
925 // Check that a 1x3 filter does not cause a spurious assert.
926 SkScalar kernel[3] = {
927 SkIntToScalar( 1), SkIntToScalar( 1), SkIntToScalar( 1),
928 };
929 SkISize kernelSize = SkISize::Make(1, 3);
930 SkScalar gain = SK_Scalar1, bias = 0;
931 SkIPoint kernelOffset = SkIPoint::Make(0, 0);
932
933 SkAutoTUnref<SkImageFilter> filter(
934 SkMatrixConvolutionImageFilter::Create(
935 kernelSize, kernel, gain, bias, kernelOffset,
936 SkMatrixConvolutionImageFilter::kRepeat_TileMode, false));
937
938 SkBitmap result;
939 int width = 16, height = 16;
940 result.allocN32Pixels(width, height);
941 SkCanvas canvas(result);
942 canvas.clear(0);
943
944 SkPaint paint;
945 paint.setImageFilter(filter);
946 SkRect rect = SkRect::Make(SkIRect::MakeWH(width, height));
947 canvas.drawRect(rect, paint);
948}
949
senorblanco@chromium.org8c7372b2014-05-02 19:13:11 +0000950DEF_TEST(ImageFilterMatrixConvolutionBorder, reporter) {
951 // Check that a filter with borders outside the target bounds
952 // does not crash.
953 SkScalar kernel[3] = {
954 0, 0, 0,
955 };
956 SkISize kernelSize = SkISize::Make(3, 1);
957 SkScalar gain = SK_Scalar1, bias = 0;
958 SkIPoint kernelOffset = SkIPoint::Make(2, 0);
959
960 SkAutoTUnref<SkImageFilter> filter(
961 SkMatrixConvolutionImageFilter::Create(
962 kernelSize, kernel, gain, bias, kernelOffset,
963 SkMatrixConvolutionImageFilter::kClamp_TileMode, true));
964
965 SkBitmap result;
966
967 int width = 10, height = 10;
968 result.allocN32Pixels(width, height);
969 SkCanvas canvas(result);
970 canvas.clear(0);
971
972 SkPaint filterPaint;
973 filterPaint.setImageFilter(filter);
974 SkRect bounds = SkRect::MakeWH(1, 10);
975 SkRect rect = SkRect::Make(SkIRect::MakeWH(width, height));
976 SkPaint rectPaint;
977 canvas.saveLayer(&bounds, &filterPaint);
978 canvas.drawRect(rect, rectPaint);
979 canvas.restore();
980}
981
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +0000982DEF_TEST(ImageFilterCropRect, reporter) {
robertphillips4418dba2016-03-07 12:45:14 -0800983 run_raster_test(reporter, 100, test_crop_rects);
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +0000984}
985
robertphillips4418dba2016-03-07 12:45:14 -0800986#if SK_SUPPORT_GPU
987DEF_GPUTEST_FOR_NATIVE_CONTEXT(ImageFilterCropRect_Gpu, reporter, context) {
988 run_gpu_test(reporter, context, 100, test_crop_rects);
989}
990#endif
991
tfarina9ea53f92014-06-24 06:50:39 -0700992DEF_TEST(ImageFilterMatrix, reporter) {
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +0000993 SkBitmap temp;
mike@reedtribe.orgdeee4962014-02-13 14:41:43 +0000994 temp.allocN32Pixels(100, 100);
robertphillips9a53fd72015-06-22 09:46:59 -0700995 SkCanvas canvas(temp);
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +0000996 canvas.scale(SkIntToScalar(2), SkIntToScalar(2));
997
998 SkMatrix expectedMatrix = canvas.getTotalMatrix();
999
commit-bot@chromium.org5fb2ce32014-04-17 23:35:06 +00001000 SkRTreeFactory factory;
1001 SkPictureRecorder recorder;
1002 SkCanvas* recordingCanvas = recorder.beginRecording(100, 100, &factory, 0);
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +00001003
1004 SkPaint paint;
1005 SkAutoTUnref<MatrixTestImageFilter> imageFilter(
1006 new MatrixTestImageFilter(reporter, expectedMatrix));
1007 paint.setImageFilter(imageFilter.get());
halcanary96fcdcc2015-08-27 07:41:13 -07001008 recordingCanvas->saveLayer(nullptr, &paint);
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +00001009 SkPaint solidPaint;
1010 solidPaint.setColor(0xFFFFFFFF);
1011 recordingCanvas->save();
1012 recordingCanvas->scale(SkIntToScalar(10), SkIntToScalar(10));
1013 recordingCanvas->drawRect(SkRect::Make(SkIRect::MakeWH(100, 100)), solidPaint);
1014 recordingCanvas->restore(); // scale
1015 recordingCanvas->restore(); // saveLayer
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +00001016
reedca2622b2016-03-18 07:25:55 -07001017 canvas.drawPicture(recorder.finishRecordingAsPicture());
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +00001018}
1019
senorblanco3d822c22014-07-30 14:49:31 -07001020DEF_TEST(ImageFilterCrossProcessPictureImageFilter, reporter) {
senorblanco@chromium.org97f5fc62014-05-30 20:50:56 +00001021 SkRTreeFactory factory;
1022 SkPictureRecorder recorder;
1023 SkCanvas* recordingCanvas = recorder.beginRecording(1, 1, &factory, 0);
1024
1025 // Create an SkPicture which simply draws a green 1x1 rectangle.
1026 SkPaint greenPaint;
1027 greenPaint.setColor(SK_ColorGREEN);
1028 recordingCanvas->drawRect(SkRect::Make(SkIRect::MakeWH(1, 1)), greenPaint);
reedca2622b2016-03-18 07:25:55 -07001029 sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture());
senorblanco@chromium.org97f5fc62014-05-30 20:50:56 +00001030
1031 // Wrap that SkPicture in an SkPictureImageFilter.
robertphillips5ff17b12016-03-28 13:13:42 -07001032 sk_sp<SkImageFilter> imageFilter(SkPictureImageFilter::Make(picture));
senorblanco@chromium.org97f5fc62014-05-30 20:50:56 +00001033
1034 // Check that SkPictureImageFilter successfully serializes its contained
1035 // SkPicture when not in cross-process mode.
1036 SkPaint paint;
robertphillips5ff17b12016-03-28 13:13:42 -07001037 paint.setImageFilter(imageFilter);
senorblanco@chromium.org97f5fc62014-05-30 20:50:56 +00001038 SkPictureRecorder outerRecorder;
1039 SkCanvas* outerCanvas = outerRecorder.beginRecording(1, 1, &factory, 0);
1040 SkPaint redPaintWithFilter;
1041 redPaintWithFilter.setColor(SK_ColorRED);
robertphillips5ff17b12016-03-28 13:13:42 -07001042 redPaintWithFilter.setImageFilter(imageFilter);
senorblanco@chromium.org97f5fc62014-05-30 20:50:56 +00001043 outerCanvas->drawRect(SkRect::Make(SkIRect::MakeWH(1, 1)), redPaintWithFilter);
reedca2622b2016-03-18 07:25:55 -07001044 sk_sp<SkPicture> outerPicture(outerRecorder.finishRecordingAsPicture());
senorblanco@chromium.org97f5fc62014-05-30 20:50:56 +00001045
1046 SkBitmap bitmap;
1047 bitmap.allocN32Pixels(1, 1);
robertphillips9a53fd72015-06-22 09:46:59 -07001048 SkCanvas canvas(bitmap);
senorblanco@chromium.org97f5fc62014-05-30 20:50:56 +00001049
1050 // The result here should be green, since the filter replaces the primitive's red interior.
1051 canvas.clear(0x0);
robertphillips9b14f262014-06-04 05:40:44 -07001052 canvas.drawPicture(outerPicture);
senorblanco@chromium.org97f5fc62014-05-30 20:50:56 +00001053 uint32_t pixel = *bitmap.getAddr32(0, 0);
1054 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1055
1056 // Check that, for now, SkPictureImageFilter does not serialize or
1057 // deserialize its contained picture when the filter is serialized
1058 // cross-process. Do this by "laundering" it through SkValidatingReadBuffer.
1059 SkAutoTUnref<SkData> data(SkValidatingSerializeFlattenable(imageFilter.get()));
1060 SkAutoTUnref<SkFlattenable> flattenable(SkValidatingDeserializeFlattenable(
1061 data->data(), data->size(), SkImageFilter::GetFlattenableType()));
1062 SkImageFilter* unflattenedFilter = static_cast<SkImageFilter*>(flattenable.get());
1063
1064 redPaintWithFilter.setImageFilter(unflattenedFilter);
1065 SkPictureRecorder crossProcessRecorder;
1066 SkCanvas* crossProcessCanvas = crossProcessRecorder.beginRecording(1, 1, &factory, 0);
1067 crossProcessCanvas->drawRect(SkRect::Make(SkIRect::MakeWH(1, 1)), redPaintWithFilter);
reedca2622b2016-03-18 07:25:55 -07001068 sk_sp<SkPicture> crossProcessPicture(crossProcessRecorder.finishRecordingAsPicture());
senorblanco@chromium.org97f5fc62014-05-30 20:50:56 +00001069
1070 canvas.clear(0x0);
robertphillips9b14f262014-06-04 05:40:44 -07001071 canvas.drawPicture(crossProcessPicture);
senorblanco@chromium.org97f5fc62014-05-30 20:50:56 +00001072 pixel = *bitmap.getAddr32(0, 0);
hendrikw446ee672015-06-16 09:28:37 -07001073 // If the security precautions are enabled, the result here should not be green, since the
1074 // filter draws nothing.
mtklein2afbe232016-02-07 12:23:10 -08001075 REPORTER_ASSERT(reporter, SkPicture::PictureIOSecurityPrecautionsEnabled()
hendrikw446ee672015-06-16 09:28:37 -07001076 ? pixel != SK_ColorGREEN : pixel == SK_ColorGREEN);
senorblanco@chromium.org97f5fc62014-05-30 20:50:56 +00001077}
1078
robertphillips4418dba2016-03-07 12:45:14 -08001079static void test_clipped_picture_imagefilter(SkImageFilter::Proxy* proxy,
1080 skiatest::Reporter* reporter,
1081 GrContext* context) {
reedca2622b2016-03-18 07:25:55 -07001082 sk_sp<SkPicture> picture;
senorblanco3d822c22014-07-30 14:49:31 -07001083
robertphillips4418dba2016-03-07 12:45:14 -08001084 {
1085 SkRTreeFactory factory;
1086 SkPictureRecorder recorder;
1087 SkCanvas* recordingCanvas = recorder.beginRecording(1, 1, &factory, 0);
1088
1089 // Create an SkPicture which simply draws a green 1x1 rectangle.
1090 SkPaint greenPaint;
1091 greenPaint.setColor(SK_ColorGREEN);
1092 recordingCanvas->drawRect(SkRect::Make(SkIRect::MakeWH(1, 1)), greenPaint);
reedca2622b2016-03-18 07:25:55 -07001093 picture = recorder.finishRecordingAsPicture();
robertphillips4418dba2016-03-07 12:45:14 -08001094 }
1095
robertphillips37bd7c32016-03-17 14:31:39 -07001096 sk_sp<SkSpecialImage> srcImg(create_empty_special_image(context, proxy, 2));
senorblanco3d822c22014-07-30 14:49:31 -07001097
robertphillips5ff17b12016-03-28 13:13:42 -07001098 sk_sp<SkImageFilter> imageFilter(SkPictureImageFilter::Make(picture));
senorblanco3d822c22014-07-30 14:49:31 -07001099
senorblanco3d822c22014-07-30 14:49:31 -07001100 SkIPoint offset;
reed4e23cda2016-01-11 10:56:59 -08001101 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeXYWH(1, 1, 1, 1), nullptr);
robertphillips4418dba2016-03-07 12:45:14 -08001102
robertphillips2302de92016-03-24 07:26:32 -07001103 sk_sp<SkSpecialImage> resultImage(imageFilter->filterImage(srcImg.get(), ctx, &offset));
robertphillips4418dba2016-03-07 12:45:14 -08001104 REPORTER_ASSERT(reporter, !resultImage);
senorblanco3d822c22014-07-30 14:49:31 -07001105}
1106
robertphillips4418dba2016-03-07 12:45:14 -08001107DEF_TEST(ImageFilterClippedPictureImageFilter, reporter) {
1108 run_raster_test(reporter, 2, test_clipped_picture_imagefilter);
1109}
1110
1111#if SK_SUPPORT_GPU
1112DEF_GPUTEST_FOR_NATIVE_CONTEXT(ImageFilterClippedPictureImageFilter_Gpu, reporter, context) {
1113 run_gpu_test(reporter, context, 2, test_clipped_picture_imagefilter);
1114}
1115#endif
1116
tfarina9ea53f92014-06-24 06:50:39 -07001117DEF_TEST(ImageFilterEmptySaveLayer, reporter) {
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001118 // Even when there's an empty saveLayer()/restore(), ensure that an image
1119 // filter or color filter which affects transparent black still draws.
1120
1121 SkBitmap bitmap;
1122 bitmap.allocN32Pixels(10, 10);
robertphillips9a53fd72015-06-22 09:46:59 -07001123 SkCanvas canvas(bitmap);
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001124
1125 SkRTreeFactory factory;
1126 SkPictureRecorder recorder;
1127
reedd053ce92016-03-22 10:17:23 -07001128 auto green(SkColorFilter::MakeModeFilter(SK_ColorGREEN, SkXfermode::kSrc_Mode));
reedf0280032015-10-12 11:10:10 -07001129 SkAutoTUnref<SkImageFilter> imageFilter(
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001130 SkColorFilterImageFilter::Create(green.get()));
1131 SkPaint imageFilterPaint;
1132 imageFilterPaint.setImageFilter(imageFilter.get());
1133 SkPaint colorFilterPaint;
reedd053ce92016-03-22 10:17:23 -07001134 colorFilterPaint.setColorFilter(green);
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001135
1136 SkRect bounds = SkRect::MakeWH(10, 10);
1137
1138 SkCanvas* recordingCanvas = recorder.beginRecording(10, 10, &factory, 0);
1139 recordingCanvas->saveLayer(&bounds, &imageFilterPaint);
1140 recordingCanvas->restore();
reedca2622b2016-03-18 07:25:55 -07001141 sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture());
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001142
1143 canvas.clear(0);
robertphillips9b14f262014-06-04 05:40:44 -07001144 canvas.drawPicture(picture);
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001145 uint32_t pixel = *bitmap.getAddr32(0, 0);
1146 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1147
1148 recordingCanvas = recorder.beginRecording(10, 10, &factory, 0);
halcanary96fcdcc2015-08-27 07:41:13 -07001149 recordingCanvas->saveLayer(nullptr, &imageFilterPaint);
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001150 recordingCanvas->restore();
reedca2622b2016-03-18 07:25:55 -07001151 sk_sp<SkPicture> picture2(recorder.finishRecordingAsPicture());
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001152
1153 canvas.clear(0);
robertphillips9b14f262014-06-04 05:40:44 -07001154 canvas.drawPicture(picture2);
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001155 pixel = *bitmap.getAddr32(0, 0);
1156 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1157
1158 recordingCanvas = recorder.beginRecording(10, 10, &factory, 0);
1159 recordingCanvas->saveLayer(&bounds, &colorFilterPaint);
1160 recordingCanvas->restore();
reedca2622b2016-03-18 07:25:55 -07001161 sk_sp<SkPicture> picture3(recorder.finishRecordingAsPicture());
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001162
1163 canvas.clear(0);
robertphillips9b14f262014-06-04 05:40:44 -07001164 canvas.drawPicture(picture3);
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001165 pixel = *bitmap.getAddr32(0, 0);
1166 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1167}
1168
robertphillips9a53fd72015-06-22 09:46:59 -07001169static void test_huge_blur(SkCanvas* canvas, skiatest::Reporter* reporter) {
senorblanco@chromium.org09843fd2014-03-24 20:50:59 +00001170 SkBitmap bitmap;
1171 bitmap.allocN32Pixels(100, 100);
1172 bitmap.eraseARGB(0, 0, 0, 0);
1173
1174 // Check that a blur with an insane radius does not crash or assert.
1175 SkAutoTUnref<SkImageFilter> blur(SkBlurImageFilter::Create(SkIntToScalar(1<<30), SkIntToScalar(1<<30)));
1176
1177 SkPaint paint;
1178 paint.setImageFilter(blur);
reedda420b92015-12-16 08:38:15 -08001179 canvas->drawBitmap(bitmap, 0, 0, &paint);
senorblanco@chromium.org09843fd2014-03-24 20:50:59 +00001180}
1181
1182DEF_TEST(HugeBlurImageFilter, reporter) {
1183 SkBitmap temp;
1184 temp.allocN32Pixels(100, 100);
robertphillips9a53fd72015-06-22 09:46:59 -07001185 SkCanvas canvas(temp);
1186 test_huge_blur(&canvas, reporter);
senorblanco@chromium.org09843fd2014-03-24 20:50:59 +00001187}
1188
senorblanco3a495202014-09-29 07:57:20 -07001189DEF_TEST(MatrixConvolutionSanityTest, reporter) {
1190 SkScalar kernel[1] = { 0 };
1191 SkScalar gain = SK_Scalar1, bias = 0;
1192 SkIPoint kernelOffset = SkIPoint::Make(1, 1);
1193
halcanary96fcdcc2015-08-27 07:41:13 -07001194 // Check that an enormous (non-allocatable) kernel gives a nullptr filter.
senorblanco3a495202014-09-29 07:57:20 -07001195 SkAutoTUnref<SkImageFilter> conv(SkMatrixConvolutionImageFilter::Create(
1196 SkISize::Make(1<<30, 1<<30),
1197 kernel,
1198 gain,
1199 bias,
1200 kernelOffset,
1201 SkMatrixConvolutionImageFilter::kRepeat_TileMode,
1202 false));
1203
halcanary96fcdcc2015-08-27 07:41:13 -07001204 REPORTER_ASSERT(reporter, nullptr == conv.get());
senorblanco3a495202014-09-29 07:57:20 -07001205
halcanary96fcdcc2015-08-27 07:41:13 -07001206 // Check that a nullptr kernel gives a nullptr filter.
senorblanco3a495202014-09-29 07:57:20 -07001207 conv.reset(SkMatrixConvolutionImageFilter::Create(
1208 SkISize::Make(1, 1),
halcanary96fcdcc2015-08-27 07:41:13 -07001209 nullptr,
senorblanco3a495202014-09-29 07:57:20 -07001210 gain,
1211 bias,
1212 kernelOffset,
1213 SkMatrixConvolutionImageFilter::kRepeat_TileMode,
1214 false));
1215
halcanary96fcdcc2015-08-27 07:41:13 -07001216 REPORTER_ASSERT(reporter, nullptr == conv.get());
senorblanco3a495202014-09-29 07:57:20 -07001217
halcanary96fcdcc2015-08-27 07:41:13 -07001218 // Check that a kernel width < 1 gives a nullptr filter.
senorblanco3a495202014-09-29 07:57:20 -07001219 conv.reset(SkMatrixConvolutionImageFilter::Create(
1220 SkISize::Make(0, 1),
1221 kernel,
1222 gain,
1223 bias,
1224 kernelOffset,
1225 SkMatrixConvolutionImageFilter::kRepeat_TileMode,
1226 false));
1227
halcanary96fcdcc2015-08-27 07:41:13 -07001228 REPORTER_ASSERT(reporter, nullptr == conv.get());
senorblanco3a495202014-09-29 07:57:20 -07001229
halcanary96fcdcc2015-08-27 07:41:13 -07001230 // Check that kernel height < 1 gives a nullptr filter.
senorblanco3a495202014-09-29 07:57:20 -07001231 conv.reset(SkMatrixConvolutionImageFilter::Create(
1232 SkISize::Make(1, -1),
1233 kernel,
1234 gain,
1235 bias,
1236 kernelOffset,
1237 SkMatrixConvolutionImageFilter::kRepeat_TileMode,
1238 false));
1239
halcanary96fcdcc2015-08-27 07:41:13 -07001240 REPORTER_ASSERT(reporter, nullptr == conv.get());
senorblanco3a495202014-09-29 07:57:20 -07001241}
1242
robertphillips9a53fd72015-06-22 09:46:59 -07001243static void test_xfermode_cropped_input(SkCanvas* canvas, skiatest::Reporter* reporter) {
1244 canvas->clear(0);
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001245
1246 SkBitmap bitmap;
1247 bitmap.allocN32Pixels(1, 1);
1248 bitmap.eraseARGB(255, 255, 255, 255);
1249
reedd053ce92016-03-22 10:17:23 -07001250 auto green(SkColorFilter::MakeModeFilter(SK_ColorGREEN, SkXfermode::kSrcIn_Mode));
reedf0280032015-10-12 11:10:10 -07001251 SkAutoTUnref<SkImageFilter> greenFilter(SkColorFilterImageFilter::Create(green.get()));
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001252 SkImageFilter::CropRect cropRect(SkRect::MakeEmpty());
reedf0280032015-10-12 11:10:10 -07001253 SkAutoTUnref<SkImageFilter> croppedOut(
halcanary96fcdcc2015-08-27 07:41:13 -07001254 SkColorFilterImageFilter::Create(green.get(), nullptr, &cropRect));
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001255
1256 // Check that an xfermode image filter whose input has been cropped out still draws the other
1257 // input. Also check that drawing with both inputs cropped out doesn't cause a GPU warning.
reedcfb6bdf2016-03-29 11:32:50 -07001258 auto mode = SkXfermode::Make(SkXfermode::kSrcOver_Mode);
1259 auto xfermodeNoFg(SkXfermodeImageFilter::Make(mode, greenFilter, croppedOut, nullptr));
1260 auto xfermodeNoBg(SkXfermodeImageFilter::Make(mode, croppedOut, greenFilter, nullptr));
1261 auto xfermodeNoFgNoBg(SkXfermodeImageFilter::Make(mode, croppedOut, croppedOut, nullptr));
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001262
1263 SkPaint paint;
1264 paint.setImageFilter(xfermodeNoFg);
reedda420b92015-12-16 08:38:15 -08001265 canvas->drawBitmap(bitmap, 0, 0, &paint); // drawSprite
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001266
1267 uint32_t pixel;
kkinnunena9d9a392015-03-06 07:16:00 -08001268 SkImageInfo info = SkImageInfo::Make(1, 1, kBGRA_8888_SkColorType, kUnpremul_SkAlphaType);
robertphillips9a53fd72015-06-22 09:46:59 -07001269 canvas->readPixels(info, &pixel, 4, 0, 0);
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001270 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1271
1272 paint.setImageFilter(xfermodeNoBg);
reedda420b92015-12-16 08:38:15 -08001273 canvas->drawBitmap(bitmap, 0, 0, &paint); // drawSprite
robertphillips9a53fd72015-06-22 09:46:59 -07001274 canvas->readPixels(info, &pixel, 4, 0, 0);
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001275 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1276
1277 paint.setImageFilter(xfermodeNoFgNoBg);
reedda420b92015-12-16 08:38:15 -08001278 canvas->drawBitmap(bitmap, 0, 0, &paint); // drawSprite
robertphillips9a53fd72015-06-22 09:46:59 -07001279 canvas->readPixels(info, &pixel, 4, 0, 0);
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001280 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1281}
1282
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001283DEF_TEST(ImageFilterNestedSaveLayer, reporter) {
1284 SkBitmap temp;
1285 temp.allocN32Pixels(50, 50);
robertphillips9a53fd72015-06-22 09:46:59 -07001286 SkCanvas canvas(temp);
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001287 canvas.clear(0x0);
1288
1289 SkBitmap bitmap;
1290 bitmap.allocN32Pixels(10, 10);
1291 bitmap.eraseColor(SK_ColorGREEN);
1292
1293 SkMatrix matrix;
1294 matrix.setScale(SkIntToScalar(2), SkIntToScalar(2));
1295 matrix.postTranslate(SkIntToScalar(-20), SkIntToScalar(-20));
1296 SkAutoTUnref<SkImageFilter> matrixFilter(
senorblanco8c874ee2015-03-20 06:38:17 -07001297 SkImageFilter::CreateMatrixFilter(matrix, kLow_SkFilterQuality));
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001298
1299 // Test that saveLayer() with a filter nested inside another saveLayer() applies the
1300 // correct offset to the filter matrix.
1301 SkRect bounds1 = SkRect::MakeXYWH(10, 10, 30, 30);
halcanary96fcdcc2015-08-27 07:41:13 -07001302 canvas.saveLayer(&bounds1, nullptr);
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001303 SkPaint filterPaint;
1304 filterPaint.setImageFilter(matrixFilter);
1305 SkRect bounds2 = SkRect::MakeXYWH(20, 20, 10, 10);
1306 canvas.saveLayer(&bounds2, &filterPaint);
1307 SkPaint greenPaint;
1308 greenPaint.setColor(SK_ColorGREEN);
1309 canvas.drawRect(bounds2, greenPaint);
1310 canvas.restore();
1311 canvas.restore();
1312 SkPaint strokePaint;
1313 strokePaint.setStyle(SkPaint::kStroke_Style);
1314 strokePaint.setColor(SK_ColorRED);
1315
kkinnunena9d9a392015-03-06 07:16:00 -08001316 SkImageInfo info = SkImageInfo::Make(1, 1, kBGRA_8888_SkColorType, kUnpremul_SkAlphaType);
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001317 uint32_t pixel;
1318 canvas.readPixels(info, &pixel, 4, 25, 25);
1319 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1320
1321 // Test that drawSprite() with a filter nested inside a saveLayer() applies the
1322 // correct offset to the filter matrix.
1323 canvas.clear(0x0);
1324 canvas.readPixels(info, &pixel, 4, 25, 25);
halcanary96fcdcc2015-08-27 07:41:13 -07001325 canvas.saveLayer(&bounds1, nullptr);
reedda420b92015-12-16 08:38:15 -08001326 canvas.drawBitmap(bitmap, 20, 20, &filterPaint); // drawSprite
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001327 canvas.restore();
1328
1329 canvas.readPixels(info, &pixel, 4, 25, 25);
1330 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1331}
1332
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001333DEF_TEST(XfermodeImageFilterCroppedInput, reporter) {
1334 SkBitmap temp;
1335 temp.allocN32Pixels(100, 100);
robertphillips9a53fd72015-06-22 09:46:59 -07001336 SkCanvas canvas(temp);
1337 test_xfermode_cropped_input(&canvas, reporter);
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001338}
senorblanco@chromium.org09843fd2014-03-24 20:50:59 +00001339
robertphillips4418dba2016-03-07 12:45:14 -08001340static void test_composed_imagefilter_offset(SkImageFilter::Proxy* proxy,
1341 skiatest::Reporter* reporter,
1342 GrContext* context) {
robertphillips37bd7c32016-03-17 14:31:39 -07001343 sk_sp<SkSpecialImage> srcImg(create_empty_special_image(context, proxy, 100));
ajuma5788faa2015-02-13 09:05:47 -08001344
1345 SkImageFilter::CropRect cropRect(SkRect::MakeXYWH(1, 0, 20, 20));
robertphillips51a315e2016-03-31 09:05:49 -07001346 sk_sp<SkImageFilter> offsetFilter(SkOffsetImageFilter::Make(0, 0, nullptr, &cropRect));
robertphillips491fb172016-03-30 12:32:58 -07001347 sk_sp<SkImageFilter> blurFilter(SkBlurImageFilter::Create(SK_Scalar1, SK_Scalar1,
1348 nullptr, &cropRect));
1349 sk_sp<SkImageFilter> composedFilter(SkComposeImageFilter::Make(std::move(blurFilter),
1350 std::move(offsetFilter)));
ajuma5788faa2015-02-13 09:05:47 -08001351 SkIPoint offset;
reed4e23cda2016-01-11 10:56:59 -08001352 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeWH(100, 100), nullptr);
robertphillips4418dba2016-03-07 12:45:14 -08001353
robertphillips2302de92016-03-24 07:26:32 -07001354 sk_sp<SkSpecialImage> resultImg(composedFilter->filterImage(srcImg.get(), ctx, &offset));
robertphillips4418dba2016-03-07 12:45:14 -08001355 REPORTER_ASSERT(reporter, resultImg);
ajuma5788faa2015-02-13 09:05:47 -08001356 REPORTER_ASSERT(reporter, offset.fX == 1 && offset.fY == 0);
1357}
1358
robertphillips4418dba2016-03-07 12:45:14 -08001359DEF_TEST(ComposedImageFilterOffset, reporter) {
1360 run_raster_test(reporter, 100, test_composed_imagefilter_offset);
1361}
1362
1363#if SK_SUPPORT_GPU
1364DEF_GPUTEST_FOR_NATIVE_CONTEXT(ComposedImageFilterOffset_Gpu, reporter, context) {
1365 run_gpu_test(reporter, context, 100, test_composed_imagefilter_offset);
1366}
1367#endif
1368
jbroman17a65202016-03-21 08:38:58 -07001369static void test_composed_imagefilter_bounds(SkImageFilter::Proxy* proxy,
1370 skiatest::Reporter* reporter,
1371 GrContext* context) {
1372 // The bounds passed to the inner filter must be filtered by the outer
1373 // filter, so that the inner filter produces the pixels that the outer
1374 // filter requires as input. This matters if the outer filter moves pixels.
1375 // Here, accounting for the outer offset is necessary so that the green
1376 // pixels of the picture are not clipped.
1377
1378 SkPictureRecorder recorder;
1379 SkCanvas* recordingCanvas = recorder.beginRecording(SkRect::MakeWH(200, 100));
1380 recordingCanvas->clipRect(SkRect::MakeXYWH(100, 0, 100, 100));
1381 recordingCanvas->clear(SK_ColorGREEN);
robertphillips491fb172016-03-30 12:32:58 -07001382 sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture());
robertphillips5ff17b12016-03-28 13:13:42 -07001383 sk_sp<SkImageFilter> pictureFilter(SkPictureImageFilter::Make(picture));
jbroman17a65202016-03-21 08:38:58 -07001384 SkImageFilter::CropRect cropRect(SkRect::MakeWH(100, 100));
robertphillips51a315e2016-03-31 09:05:49 -07001385 sk_sp<SkImageFilter> offsetFilter(SkOffsetImageFilter::Make(-100, 0, nullptr, &cropRect));
robertphillips491fb172016-03-30 12:32:58 -07001386 sk_sp<SkImageFilter> composedFilter(SkComposeImageFilter::Make(std::move(offsetFilter),
1387 std::move(pictureFilter)));
jbroman17a65202016-03-21 08:38:58 -07001388
1389 sk_sp<SkSpecialImage> sourceImage(create_empty_special_image(context, proxy, 100));
1390 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeWH(100, 100), nullptr);
1391 SkIPoint offset;
1392 sk_sp<SkSpecialImage> result(composedFilter->filterImage(sourceImage.get(), ctx, &offset));
1393 REPORTER_ASSERT(reporter, offset.isZero());
1394 REPORTER_ASSERT(reporter, result);
1395 REPORTER_ASSERT(reporter, result->subset().size() == SkISize::Make(100, 100));
1396
1397 SkBitmap resultBM;
1398 TestingSpecialImageAccess::GetROPixels(result.get(), &resultBM);
1399 SkAutoLockPixels lock(resultBM);
1400 REPORTER_ASSERT(reporter, resultBM.getColor(50, 50) == SK_ColorGREEN);
1401}
1402
1403DEF_TEST(ComposedImageFilterBounds, reporter) {
1404 run_raster_test(reporter, 100, test_composed_imagefilter_bounds);
1405}
1406
1407#if SK_SUPPORT_GPU
1408DEF_GPUTEST_FOR_NATIVE_CONTEXT(ComposedImageFilterBounds_Gpu, reporter, context) {
1409 run_gpu_test(reporter, context, 100, test_composed_imagefilter_bounds);
1410}
1411#endif
1412
robertphillips4418dba2016-03-07 12:45:14 -08001413static void test_partial_crop_rect(SkImageFilter::Proxy* proxy,
1414 skiatest::Reporter* reporter,
1415 GrContext* context) {
robertphillips37bd7c32016-03-17 14:31:39 -07001416 sk_sp<SkSpecialImage> srcImg(create_empty_special_image(context, proxy, 100));
senorblanco24d2a7b2015-07-13 10:27:05 -07001417
1418 SkImageFilter::CropRect cropRect(SkRect::MakeXYWH(100, 0, 20, 30),
senorblancoed7cf272015-07-16 15:19:11 -07001419 SkImageFilter::CropRect::kHasWidth_CropEdge | SkImageFilter::CropRect::kHasHeight_CropEdge);
halcanary96fcdcc2015-08-27 07:41:13 -07001420 SkAutoTUnref<SkImageFilter> filter(make_grayscale(nullptr, &cropRect));
senorblanco24d2a7b2015-07-13 10:27:05 -07001421 SkIPoint offset;
reed4e23cda2016-01-11 10:56:59 -08001422 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeWH(100, 100), nullptr);
robertphillips4418dba2016-03-07 12:45:14 -08001423
robertphillips2302de92016-03-24 07:26:32 -07001424 sk_sp<SkSpecialImage> resultImg(filter->filterImage(srcImg.get(), ctx, &offset));
robertphillips4418dba2016-03-07 12:45:14 -08001425 REPORTER_ASSERT(reporter, resultImg);
1426
senorblanco24d2a7b2015-07-13 10:27:05 -07001427 REPORTER_ASSERT(reporter, offset.fX == 0);
1428 REPORTER_ASSERT(reporter, offset.fY == 0);
robertphillips4418dba2016-03-07 12:45:14 -08001429 REPORTER_ASSERT(reporter, resultImg->width() == 20);
1430 REPORTER_ASSERT(reporter, resultImg->height() == 30);
senorblanco24d2a7b2015-07-13 10:27:05 -07001431}
1432
robertphillips4418dba2016-03-07 12:45:14 -08001433DEF_TEST(PartialCropRect, reporter) {
1434 run_raster_test(reporter, 100, test_partial_crop_rect);
1435}
1436
1437#if SK_SUPPORT_GPU
1438DEF_GPUTEST_FOR_NATIVE_CONTEXT(PartialCropRect_Gpu, reporter, context) {
1439 run_gpu_test(reporter, context, 100, test_partial_crop_rect);
1440}
1441#endif
1442
senorblanco0abdf762015-08-20 11:10:41 -07001443DEF_TEST(ImageFilterCanComputeFastBounds, reporter) {
1444
1445 SkPoint3 location = SkPoint3::Make(0, 0, SK_Scalar1);
1446 SkAutoTUnref<SkImageFilter> lighting(SkLightingImageFilter::CreatePointLitDiffuse(
1447 location, SK_ColorGREEN, 0, 0));
1448 REPORTER_ASSERT(reporter, !lighting->canComputeFastBounds());
1449
1450 SkAutoTUnref<SkImageFilter> gray(make_grayscale(nullptr, nullptr));
1451 REPORTER_ASSERT(reporter, gray->canComputeFastBounds());
1452 {
1453 SkColorFilter* grayCF;
1454 REPORTER_ASSERT(reporter, gray->asAColorFilter(&grayCF));
1455 REPORTER_ASSERT(reporter, !grayCF->affectsTransparentBlack());
1456 grayCF->unref();
1457 }
1458 REPORTER_ASSERT(reporter, gray->canComputeFastBounds());
1459
1460 SkAutoTUnref<SkImageFilter> grayBlur(SkBlurImageFilter::Create(SK_Scalar1, SK_Scalar1, gray.get()));
1461 REPORTER_ASSERT(reporter, grayBlur->canComputeFastBounds());
1462
1463 SkScalar greenMatrix[20] = { 0, 0, 0, 0, 0,
1464 0, 0, 0, 0, 1,
1465 0, 0, 0, 0, 0,
1466 0, 0, 0, 0, 1 };
reedd053ce92016-03-22 10:17:23 -07001467 auto greenCF(SkColorFilter::MakeMatrixFilterRowMajor255(greenMatrix));
1468 SkAutoTUnref<SkImageFilter> green(SkColorFilterImageFilter::Create(greenCF.get()));
senorblanco0abdf762015-08-20 11:10:41 -07001469
1470 REPORTER_ASSERT(reporter, greenCF->affectsTransparentBlack());
1471 REPORTER_ASSERT(reporter, !green->canComputeFastBounds());
1472
1473 SkAutoTUnref<SkImageFilter> greenBlur(SkBlurImageFilter::Create(SK_Scalar1, SK_Scalar1, green.get()));
1474 REPORTER_ASSERT(reporter, !greenBlur->canComputeFastBounds());
1475
1476 uint8_t allOne[256], identity[256];
1477 for (int i = 0; i < 256; ++i) {
1478 identity[i] = i;
1479 allOne[i] = 255;
1480 }
1481
reedd053ce92016-03-22 10:17:23 -07001482 auto identityCF(SkTableColorFilter::MakeARGB(identity, identity, identity, allOne));
senorblanco0abdf762015-08-20 11:10:41 -07001483 SkAutoTUnref<SkImageFilter> identityFilter(SkColorFilterImageFilter::Create(identityCF.get()));
1484 REPORTER_ASSERT(reporter, !identityCF->affectsTransparentBlack());
1485 REPORTER_ASSERT(reporter, identityFilter->canComputeFastBounds());
1486
reedd053ce92016-03-22 10:17:23 -07001487 auto forceOpaqueCF(SkTableColorFilter::MakeARGB(allOne, identity, identity, identity));
senorblanco0abdf762015-08-20 11:10:41 -07001488 SkAutoTUnref<SkImageFilter> forceOpaque(SkColorFilterImageFilter::Create(forceOpaqueCF.get()));
1489 REPORTER_ASSERT(reporter, forceOpaqueCF->affectsTransparentBlack());
1490 REPORTER_ASSERT(reporter, !forceOpaque->canComputeFastBounds());
1491}
1492
fmalitacd56f812015-09-14 13:31:18 -07001493// Verify that SkImageSource survives serialization
1494DEF_TEST(ImageFilterImageSourceSerialization, reporter) {
reede8f30622016-03-23 18:59:25 -07001495 auto surface(SkSurface::MakeRasterN32Premul(10, 10));
fmalitacd56f812015-09-14 13:31:18 -07001496 surface->getCanvas()->clear(SK_ColorGREEN);
reed9ce9d672016-03-17 10:51:11 -07001497 sk_sp<SkImage> image(surface->makeImageSnapshot());
robertphillips549c8992016-04-01 09:28:51 -07001498 sk_sp<SkImageFilter> filter(SkImageSource::Make(std::move(image)));
fmalitacd56f812015-09-14 13:31:18 -07001499
robertphillips549c8992016-04-01 09:28:51 -07001500 sk_sp<SkData> data(SkValidatingSerializeFlattenable(filter.get()));
1501 sk_sp<SkFlattenable> flattenable(SkValidatingDeserializeFlattenable(
fmalitacd56f812015-09-14 13:31:18 -07001502 data->data(), data->size(), SkImageFilter::GetFlattenableType()));
1503 SkImageFilter* unflattenedFilter = static_cast<SkImageFilter*>(flattenable.get());
1504 REPORTER_ASSERT(reporter, unflattenedFilter);
1505
1506 SkBitmap bm;
1507 bm.allocN32Pixels(10, 10);
fmalita23cb88c2015-09-15 06:56:23 -07001508 bm.eraseColor(SK_ColorBLUE);
fmalitacd56f812015-09-14 13:31:18 -07001509 SkPaint paint;
1510 paint.setColor(SK_ColorRED);
1511 paint.setImageFilter(unflattenedFilter);
1512
1513 SkCanvas canvas(bm);
1514 canvas.drawRect(SkRect::MakeWH(10, 10), paint);
1515 REPORTER_ASSERT(reporter, *bm.getAddr32(0, 0) == SkPreMultiplyColor(SK_ColorGREEN));
1516}
1517
bsalomon45eefcf2016-01-05 08:39:28 -08001518static void test_large_blur_input(skiatest::Reporter* reporter, SkCanvas* canvas) {
1519 SkBitmap largeBmp;
1520 int largeW = 5000;
1521 int largeH = 5000;
1522#if SK_SUPPORT_GPU
1523 // If we're GPU-backed make the bitmap too large to be converted into a texture.
1524 if (GrContext* ctx = canvas->getGrContext()) {
1525 largeW = ctx->caps()->maxTextureSize() + 1;
1526 }
1527#endif
1528
1529 largeBmp.allocN32Pixels(largeW, largeH);
mtklein2afbe232016-02-07 12:23:10 -08001530 largeBmp.eraseColor(0);
bsalomon45eefcf2016-01-05 08:39:28 -08001531 if (!largeBmp.getPixels()) {
1532 ERRORF(reporter, "Failed to allocate large bmp.");
1533 return;
1534 }
1535
reed9ce9d672016-03-17 10:51:11 -07001536 sk_sp<SkImage> largeImage(SkImage::MakeFromBitmap(largeBmp));
bsalomon45eefcf2016-01-05 08:39:28 -08001537 if (!largeImage) {
1538 ERRORF(reporter, "Failed to create large image.");
1539 return;
1540 }
1541
robertphillips549c8992016-04-01 09:28:51 -07001542 sk_sp<SkImageFilter> largeSource(SkImageSource::Make(std::move(largeImage)));
bsalomon45eefcf2016-01-05 08:39:28 -08001543 if (!largeSource) {
1544 ERRORF(reporter, "Failed to create large SkImageSource.");
1545 return;
1546 }
1547
robertphillips549c8992016-04-01 09:28:51 -07001548 sk_sp<SkImageFilter> blur(SkBlurImageFilter::Create(10.f, 10.f, largeSource.get()));
bsalomon45eefcf2016-01-05 08:39:28 -08001549 if (!blur) {
1550 ERRORF(reporter, "Failed to create SkBlurImageFilter.");
1551 return;
1552 }
1553
1554 SkPaint paint;
robertphillips549c8992016-04-01 09:28:51 -07001555 paint.setImageFilter(std::move(blur));
bsalomon45eefcf2016-01-05 08:39:28 -08001556
1557 // This should not crash (http://crbug.com/570479).
1558 canvas->drawRect(SkRect::MakeIWH(largeW, largeH), paint);
1559}
1560
1561DEF_TEST(BlurLargeImage, reporter) {
reede8f30622016-03-23 18:59:25 -07001562 auto surface(SkSurface::MakeRaster(SkImageInfo::MakeN32Premul(100, 100)));
bsalomon45eefcf2016-01-05 08:39:28 -08001563 test_large_blur_input(reporter, surface->getCanvas());
1564}
1565
senorblanco@chromium.org58d14662014-02-03 22:36:39 +00001566#if SK_SUPPORT_GPU
reed4a8126e2014-09-22 07:29:03 -07001567
kkinnunen15302832015-12-01 04:35:26 -08001568DEF_GPUTEST_FOR_NATIVE_CONTEXT(HugeBlurImageFilter_Gpu, reporter, context) {
robertphillipsefbffed2015-06-22 12:06:08 -07001569 const SkSurfaceProps props(SkSurfaceProps::kLegacyFontHost_InitType);
1570
senorblanco@chromium.org09843fd2014-03-24 20:50:59 +00001571 SkAutoTUnref<SkGpuDevice> device(SkGpuDevice::Create(context,
bsalomon5ec26ae2016-02-25 08:33:02 -08001572 SkBudgeted::kNo,
senorblanco@chromium.org09843fd2014-03-24 20:50:59 +00001573 SkImageInfo::MakeN32Premul(100, 100),
bsalomonafe30052015-01-16 07:32:33 -08001574 0,
bsalomon74f681d2015-06-23 14:38:48 -07001575 &props,
1576 SkGpuDevice::kUninit_InitContents));
robertphillips9a53fd72015-06-22 09:46:59 -07001577 SkCanvas canvas(device);
1578
1579 test_huge_blur(&canvas, reporter);
senorblanco@chromium.org09843fd2014-03-24 20:50:59 +00001580}
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001581
kkinnunen15302832015-12-01 04:35:26 -08001582DEF_GPUTEST_FOR_NATIVE_CONTEXT(XfermodeImageFilterCroppedInput_Gpu, reporter, context) {
robertphillipsefbffed2015-06-22 12:06:08 -07001583 const SkSurfaceProps props(SkSurfaceProps::kLegacyFontHost_InitType);
1584
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001585 SkAutoTUnref<SkGpuDevice> device(SkGpuDevice::Create(context,
bsalomon5ec26ae2016-02-25 08:33:02 -08001586 SkBudgeted::kNo,
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001587 SkImageInfo::MakeN32Premul(1, 1),
bsalomonafe30052015-01-16 07:32:33 -08001588 0,
bsalomon74f681d2015-06-23 14:38:48 -07001589 &props,
1590 SkGpuDevice::kUninit_InitContents));
robertphillips9a53fd72015-06-22 09:46:59 -07001591 SkCanvas canvas(device);
1592
1593 test_xfermode_cropped_input(&canvas, reporter);
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001594}
senorblanco32673b92014-09-09 09:15:04 -07001595
bsalomon45eefcf2016-01-05 08:39:28 -08001596DEF_GPUTEST_FOR_ALL_CONTEXTS(BlurLargeImage_Gpu, reporter, context) {
reede8f30622016-03-23 18:59:25 -07001597 auto surface(SkSurface::MakeRenderTarget(context, SkBudgeted::kYes,
1598 SkImageInfo::MakeN32Premul(100, 100)));
bsalomon45eefcf2016-01-05 08:39:28 -08001599 test_large_blur_input(reporter, surface->getCanvas());
1600}
senorblanco@chromium.org58d14662014-02-03 22:36:39 +00001601#endif