blob: ac847ce7cf8eb995542c886c5a33f6f28631881c [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
Xianzhu Wang0fa353c2017-08-25 16:27:04 -07008#include "SkArithmeticImageFilter.h"
commit-bot@chromium.org4b681bc2013-09-13 12:40:02 +00009#include "SkBitmap.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"
Florin Malita08252ec2017-07-06 12:48:15 -040014#include "SkColorSpaceXformer.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"
fmalita5598b632015-09-15 11:26:13 -070020#include "SkImage.h"
fmalitacd56f812015-09-14 13:31:18 -070021#include "SkImageSource.h"
commit-bot@chromium.org4b681bc2013-09-13 12:40:02 +000022#include "SkLightingImageFilter.h"
tfarina@chromium.org8f6884a2014-01-24 20:56:26 +000023#include "SkMatrixConvolutionImageFilter.h"
senorblanco@chromium.org6776b822014-01-03 21:48:22 +000024#include "SkMergeImageFilter.h"
25#include "SkMorphologyImageFilter.h"
senorblanco@chromium.org6776b822014-01-03 21:48:22 +000026#include "SkOffsetImageFilter.h"
ajuma77b6ba32016-01-08 14:58:35 -080027#include "SkPaintImageFilter.h"
senorblanco8f3937d2014-10-29 12:36:32 -070028#include "SkPerlinNoiseShader.h"
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +000029#include "SkPicture.h"
senorblanco@chromium.org910702b2014-05-30 20:36:15 +000030#include "SkPictureImageFilter.h"
robertphillips@google.com770963f2014-04-18 18:04:41 +000031#include "SkPictureRecorder.h"
robertphillips3d32d762015-07-13 13:16:44 -070032#include "SkPoint3.h"
halcanary97d2c0a2014-08-19 06:27:53 -070033#include "SkReadBuffer.h"
tfarina@chromium.org8f6884a2014-01-24 20:56:26 +000034#include "SkRect.h"
robertphillips4418dba2016-03-07 12:45:14 -080035#include "SkSpecialImage.h"
36#include "SkSpecialSurface.h"
fmalitacd56f812015-09-14 13:31:18 -070037#include "SkSurface.h"
senorblanco0abdf762015-08-20 11:10:41 -070038#include "SkTableColorFilter.h"
senorblanco@chromium.org6776b822014-01-03 21:48:22 +000039#include "SkTileImageFilter.h"
40#include "SkXfermodeImageFilter.h"
Leon Scroggins III4cdbf602017-09-28 14:33:57 -040041#include "Resources.h"
tfarina@chromium.org8f6884a2014-01-24 20:56:26 +000042#include "Test.h"
Mike Reed5a625e02017-08-08 15:48:54 -040043#include "sk_tool_utils.h"
senorblanco@chromium.org194d7752013-07-24 22:19:24 +000044
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +000045#if SK_SUPPORT_GPU
kkinnunen15302832015-12-01 04:35:26 -080046#include "GrContext.h"
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +000047#endif
48
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +000049static const int kBitmapSize = 4;
commit-bot@chromium.org4b681bc2013-09-13 12:40:02 +000050
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +000051namespace {
52
53class MatrixTestImageFilter : public SkImageFilter {
54public:
robertphillips43c2ad42016-04-04 05:05:11 -070055 static sk_sp<SkImageFilter> Make(skiatest::Reporter* reporter,
56 const SkMatrix& expectedMatrix) {
57 return sk_sp<SkImageFilter>(new MatrixTestImageFilter(reporter, expectedMatrix));
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +000058 }
59
robertphillipsf3f5bad2014-12-19 13:49:15 -080060 SK_TO_STRING_OVERRIDE()
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +000061 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(MatrixTestImageFilter)
62
63protected:
robertphillips4ba94e22016-04-04 12:07:47 -070064 sk_sp<SkSpecialImage> onFilterImage(SkSpecialImage* source, const Context& ctx,
65 SkIPoint* offset) const override {
robertphillips43c2ad42016-04-04 05:05:11 -070066 REPORTER_ASSERT(fReporter, ctx.ctm() == fExpectedMatrix);
robertphillips4ba94e22016-04-04 12:07:47 -070067 offset->fX = offset->fY = 0;
68 return sk_ref_sp<SkSpecialImage>(source);
robertphillips43c2ad42016-04-04 05:05:11 -070069 }
Matt Sarett62745a82017-04-17 11:57:29 -040070 sk_sp<SkImageFilter> onMakeColorSpace(SkColorSpaceXformer*) const override {
71 return sk_ref_sp(const_cast<MatrixTestImageFilter*>(this));
72 }
robertphillips43c2ad42016-04-04 05:05:11 -070073
mtklein36352bf2015-03-25 18:17:31 -070074 void flatten(SkWriteBuffer& buffer) const override {
brianosman18f13f32016-05-02 07:51:08 -070075 SkDEBUGFAIL("Should never get here");
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +000076 }
77
78private:
robertphillips43c2ad42016-04-04 05:05:11 -070079 MatrixTestImageFilter(skiatest::Reporter* reporter, const SkMatrix& expectedMatrix)
80 : INHERITED(nullptr, 0, nullptr)
81 , fReporter(reporter)
82 , fExpectedMatrix(expectedMatrix) {
83 }
84
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +000085 skiatest::Reporter* fReporter;
86 SkMatrix fExpectedMatrix;
mtklein3f3b3d02014-12-01 11:47:08 -080087
reed9fa60da2014-08-21 07:59:51 -070088 typedef SkImageFilter INHERITED;
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +000089};
90
senorblanco6a93fa12016-04-05 04:43:45 -070091class FailImageFilter : public SkImageFilter {
92public:
robertphillips6b134732016-04-15 09:58:37 -070093 FailImageFilter() : SkImageFilter(nullptr, 0, nullptr) { }
senorblanco6a93fa12016-04-05 04:43:45 -070094
95 sk_sp<SkSpecialImage> onFilterImage(SkSpecialImage* source,
96 const Context& ctx,
97 SkIPoint* offset) const override {
98 return nullptr;
99 }
Matt Sarett62745a82017-04-17 11:57:29 -0400100 sk_sp<SkImageFilter> onMakeColorSpace(SkColorSpaceXformer*) const override {
101 return nullptr;
102 }
senorblanco6a93fa12016-04-05 04:43:45 -0700103
104 SK_TO_STRING_OVERRIDE()
105 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(FailImageFilter)
106
107private:
108 typedef SkImageFilter INHERITED;
109};
110
111sk_sp<SkFlattenable> FailImageFilter::CreateProc(SkReadBuffer& buffer) {
112 SK_IMAGEFILTER_UNFLATTEN_COMMON(common, 0);
113 return sk_sp<SkFlattenable>(new FailImageFilter());
114}
115
116#ifndef SK_IGNORE_TO_STRING
117void FailImageFilter::toString(SkString* str) const {
118 str->appendf("FailImageFilter: (");
119 str->append(")");
120}
121#endif
122
senorblanco297f7ce2016-03-23 13:44:26 -0700123void draw_gradient_circle(SkCanvas* canvas, int width, int height) {
124 SkScalar x = SkIntToScalar(width / 2);
125 SkScalar y = SkIntToScalar(height / 2);
126 SkScalar radius = SkMinScalar(x, y) * 0.8f;
127 canvas->clear(0x00000000);
128 SkColor colors[2];
129 colors[0] = SK_ColorWHITE;
130 colors[1] = SK_ColorBLACK;
131 sk_sp<SkShader> shader(
132 SkGradientShader::MakeRadial(SkPoint::Make(x, y), radius, colors, nullptr, 2,
133 SkShader::kClamp_TileMode)
134 );
135 SkPaint paint;
136 paint.setShader(shader);
137 canvas->drawCircle(x, y, radius, paint);
138}
139
140SkBitmap make_gradient_circle(int width, int height) {
141 SkBitmap bitmap;
142 bitmap.allocN32Pixels(width, height);
143 SkCanvas canvas(bitmap);
144 draw_gradient_circle(&canvas, width, height);
145 return bitmap;
146}
147
148class FilterList {
149public:
robertphillipsfc11b0a2016-04-05 09:09:36 -0700150 FilterList(sk_sp<SkImageFilter> input, const SkImageFilter::CropRect* cropRect = nullptr) {
senorblanco297f7ce2016-03-23 13:44:26 -0700151 SkPoint3 location = SkPoint3::Make(0, 0, SK_Scalar1);
senorblanco297f7ce2016-03-23 13:44:26 -0700152 const SkScalar five = SkIntToScalar(5);
153
robertphillips6e7025a2016-04-04 04:31:25 -0700154 {
155 sk_sp<SkColorFilter> cf(SkColorFilter::MakeModeFilter(SK_ColorRED,
Mike Reed7d954ad2016-10-28 15:42:34 -0400156 SkBlendMode::kSrcIn));
senorblanco297f7ce2016-03-23 13:44:26 -0700157
robertphillips6e7025a2016-04-04 04:31:25 -0700158 this->addFilter("color filter",
robertphillips12fa47d2016-04-08 16:28:09 -0700159 SkColorFilterImageFilter::Make(std::move(cf), input, cropRect));
robertphillips6e7025a2016-04-04 04:31:25 -0700160 }
senorblanco297f7ce2016-03-23 13:44:26 -0700161
robertphillips6e7025a2016-04-04 04:31:25 -0700162 {
163 sk_sp<SkImage> gradientImage(SkImage::MakeFromBitmap(make_gradient_circle(64, 64)));
164 sk_sp<SkImageFilter> gradientSource(SkImageSource::Make(std::move(gradientImage)));
senorblanco297f7ce2016-03-23 13:44:26 -0700165
liyuqianbfebe222016-11-14 11:17:16 -0800166 this->addFilter("displacement map",
robertphillipsbfe11fc2016-04-15 07:17:36 -0700167 SkDisplacementMapEffect::Make(SkDisplacementMapEffect::kR_ChannelSelectorType,
168 SkDisplacementMapEffect::kB_ChannelSelectorType,
169 20.0f,
170 std::move(gradientSource), input, cropRect));
robertphillips6e7025a2016-04-04 04:31:25 -0700171 }
senorblanco297f7ce2016-03-23 13:44:26 -0700172
robertphillips6e7025a2016-04-04 04:31:25 -0700173 this->addFilter("blur", SkBlurImageFilter::Make(SK_Scalar1,
174 SK_Scalar1,
robertphillipsfc11b0a2016-04-05 09:09:36 -0700175 input,
robertphillips12fa47d2016-04-08 16:28:09 -0700176 cropRect));
robertphillipsc4169122016-04-06 08:40:59 -0700177 this->addFilter("drop shadow", SkDropShadowImageFilter::Make(
senorblanco297f7ce2016-03-23 13:44:26 -0700178 SK_Scalar1, SK_Scalar1, SK_Scalar1, SK_Scalar1, SK_ColorGREEN,
robertphillipsfc11b0a2016-04-05 09:09:36 -0700179 SkDropShadowImageFilter::kDrawShadowAndForeground_ShadowMode,
robertphillips12fa47d2016-04-08 16:28:09 -0700180 input, cropRect));
181 this->addFilter("diffuse lighting",
182 SkLightingImageFilter::MakePointLitDiffuse(location, SK_ColorGREEN, 0, 0,
183 input, cropRect));
senorblanco297f7ce2016-03-23 13:44:26 -0700184 this->addFilter("specular lighting",
robertphillips12fa47d2016-04-08 16:28:09 -0700185 SkLightingImageFilter::MakePointLitSpecular(location, SK_ColorGREEN, 0, 0, 0,
186 input, cropRect));
187 {
188 SkScalar kernel[9] = {
189 SkIntToScalar(1), SkIntToScalar(1), SkIntToScalar(1),
190 SkIntToScalar(1), SkIntToScalar(-7), SkIntToScalar(1),
191 SkIntToScalar(1), SkIntToScalar(1), SkIntToScalar(1),
192 };
193 const SkISize kernelSize = SkISize::Make(3, 3);
194 const SkScalar gain = SK_Scalar1, bias = 0;
195
196 this->addFilter("matrix convolution",
robertphillipsef6a47b2016-04-08 08:01:20 -0700197 SkMatrixConvolutionImageFilter::Make(
senorblanco297f7ce2016-03-23 13:44:26 -0700198 kernelSize, kernel, gain, bias, SkIPoint::Make(1, 1),
robertphillipsfc11b0a2016-04-05 09:09:36 -0700199 SkMatrixConvolutionImageFilter::kRepeat_TileMode, false,
robertphillips12fa47d2016-04-08 16:28:09 -0700200 input, cropRect));
201 }
202
Mike Reed0bdaf052017-06-18 23:35:57 -0400203 this->addFilter("merge", SkMergeImageFilter::Make(input, input, cropRect));
robertphillips12fa47d2016-04-08 16:28:09 -0700204
robertphillips6e7025a2016-04-04 04:31:25 -0700205 {
206 SkPaint greenColorShaderPaint;
207 greenColorShaderPaint.setShader(SkShader::MakeColorShader(SK_ColorGREEN));
208
209 SkImageFilter::CropRect leftSideCropRect(SkRect::MakeXYWH(0, 0, 32, 64));
210 sk_sp<SkImageFilter> paintFilterLeft(SkPaintImageFilter::Make(greenColorShaderPaint,
211 &leftSideCropRect));
212 SkImageFilter::CropRect rightSideCropRect(SkRect::MakeXYWH(32, 0, 32, 64));
213 sk_sp<SkImageFilter> paintFilterRight(SkPaintImageFilter::Make(greenColorShaderPaint,
214 &rightSideCropRect));
215
216
217 this->addFilter("merge with disjoint inputs", SkMergeImageFilter::Make(
Mike Reed0bdaf052017-06-18 23:35:57 -0400218 std::move(paintFilterLeft), std::move(paintFilterRight), cropRect));
robertphillips6e7025a2016-04-04 04:31:25 -0700219 }
220
senorblanco297f7ce2016-03-23 13:44:26 -0700221 this->addFilter("offset",
robertphillipsfc11b0a2016-04-05 09:09:36 -0700222 SkOffsetImageFilter::Make(SK_Scalar1, SK_Scalar1, input,
robertphillips12fa47d2016-04-08 16:28:09 -0700223 cropRect));
224 this->addFilter("dilate", SkDilateImageFilter::Make(3, 2, input, cropRect));
225 this->addFilter("erode", SkErodeImageFilter::Make(2, 3, input, cropRect));
robertphillips534c2702016-04-15 07:57:40 -0700226 this->addFilter("tile", SkTileImageFilter::Make(
227 SkRect::MakeXYWH(0, 0, 50, 50),
228 cropRect ? cropRect->rect() : SkRect::MakeXYWH(0, 0, 100, 100),
229 input));
robertphillips6e7025a2016-04-04 04:31:25 -0700230
robertphillips12fa47d2016-04-08 16:28:09 -0700231 if (!cropRect) {
232 SkMatrix matrix;
233
234 matrix.setTranslate(SK_Scalar1, SK_Scalar1);
235 matrix.postRotate(SkIntToScalar(45), SK_Scalar1, SK_Scalar1);
236
237 this->addFilter("matrix",
238 SkImageFilter::MakeMatrixFilter(matrix, kLow_SkFilterQuality, input));
239 }
robertphillips6e7025a2016-04-04 04:31:25 -0700240 {
robertphillipsfc11b0a2016-04-05 09:09:36 -0700241 sk_sp<SkImageFilter> blur(SkBlurImageFilter::Make(five, five, input));
robertphillips6e7025a2016-04-04 04:31:25 -0700242
243 this->addFilter("blur and offset", SkOffsetImageFilter::Make(five, five,
244 std::move(blur),
robertphillips12fa47d2016-04-08 16:28:09 -0700245 cropRect));
robertphillips6e7025a2016-04-04 04:31:25 -0700246 }
247 {
robertphillips6e7025a2016-04-04 04:31:25 -0700248 SkPictureRecorder recorder;
Mike Klein26eb16f2017-04-10 09:50:25 -0400249 SkCanvas* recordingCanvas = recorder.beginRecording(64, 64);
robertphillips6e7025a2016-04-04 04:31:25 -0700250
251 SkPaint greenPaint;
252 greenPaint.setColor(SK_ColorGREEN);
253 recordingCanvas->drawRect(SkRect::Make(SkIRect::MakeXYWH(10, 10, 30, 20)), greenPaint);
254 sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture());
255 sk_sp<SkImageFilter> pictureFilter(SkPictureImageFilter::Make(std::move(picture)));
256
257 this->addFilter("picture and blur", SkBlurImageFilter::Make(five, five,
258 std::move(pictureFilter),
robertphillips12fa47d2016-04-08 16:28:09 -0700259 cropRect));
robertphillips6e7025a2016-04-04 04:31:25 -0700260 }
261 {
262 SkPaint paint;
263 paint.setShader(SkPerlinNoiseShader::MakeTurbulence(SK_Scalar1, SK_Scalar1, 1, 0));
264 sk_sp<SkImageFilter> paintFilter(SkPaintImageFilter::Make(paint));
265
266 this->addFilter("paint and blur", SkBlurImageFilter::Make(five, five,
267 std::move(paintFilter),
robertphillips12fa47d2016-04-08 16:28:09 -0700268 cropRect));
robertphillips6e7025a2016-04-04 04:31:25 -0700269 }
reed374772b2016-10-05 17:33:02 -0700270 this->addFilter("xfermode", SkXfermodeImageFilter::Make(SkBlendMode::kSrc, input, input,
271 cropRect));
senorblanco297f7ce2016-03-23 13:44:26 -0700272 }
273 int count() const { return fFilters.count(); }
274 SkImageFilter* getFilter(int index) const { return fFilters[index].fFilter.get(); }
275 const char* getName(int index) const { return fFilters[index].fName; }
276private:
277 struct Filter {
robertphillips12fa47d2016-04-08 16:28:09 -0700278 Filter() : fName(nullptr) {}
279 Filter(const char* name, sk_sp<SkImageFilter> filter)
280 : fName(name)
281 , fFilter(std::move(filter)) {
282 }
senorblanco297f7ce2016-03-23 13:44:26 -0700283 const char* fName;
284 sk_sp<SkImageFilter> fFilter;
285 };
robertphillips12fa47d2016-04-08 16:28:09 -0700286 void addFilter(const char* name, sk_sp<SkImageFilter> filter) {
287 fFilters.push_back(Filter(name, std::move(filter)));
senorblanco297f7ce2016-03-23 13:44:26 -0700288 }
289
290 SkTArray<Filter> fFilters;
291};
292
Xianzhu Wang0fa353c2017-08-25 16:27:04 -0700293class FixedBoundsImageFilter : public SkImageFilter {
294public:
295 FixedBoundsImageFilter(const SkIRect& bounds)
296 : SkImageFilter(nullptr, 0, nullptr), fBounds(bounds) {}
297
298private:
299#ifndef SK_IGNORE_TO_STRING
300 void toString(SkString*) const override {}
301#endif
302 Factory getFactory() const override { return nullptr; }
303
304 sk_sp<SkSpecialImage> onFilterImage(SkSpecialImage* src, const Context&,
305 SkIPoint* offset) const override {
306 return nullptr;
307 }
308 sk_sp<SkImageFilter> onMakeColorSpace(SkColorSpaceXformer*) const override { return nullptr; }
309
310 SkIRect onFilterBounds(const SkIRect&, const SkMatrix&, MapDirection) const override {
311 return fBounds;
312 }
313
314 SkIRect fBounds;
315};
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +0000316}
317
reed60c9b582016-04-03 09:11:13 -0700318sk_sp<SkFlattenable> MatrixTestImageFilter::CreateProc(SkReadBuffer& buffer) {
brianosman18f13f32016-05-02 07:51:08 -0700319 SkDEBUGFAIL("Should never get here");
320 return nullptr;
reed9fa60da2014-08-21 07:59:51 -0700321}
322
robertphillipsf3f5bad2014-12-19 13:49:15 -0800323#ifndef SK_IGNORE_TO_STRING
324void MatrixTestImageFilter::toString(SkString* str) const {
325 str->appendf("MatrixTestImageFilter: (");
326 str->append(")");
327}
328#endif
329
reed9ce9d672016-03-17 10:51:11 -0700330static sk_sp<SkImage> make_small_image() {
reede8f30622016-03-23 18:59:25 -0700331 auto surface(SkSurface::MakeRasterN32Premul(kBitmapSize, kBitmapSize));
fmalita5598b632015-09-15 11:26:13 -0700332 SkCanvas* canvas = surface->getCanvas();
333 canvas->clear(0x00000000);
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000334 SkPaint darkPaint;
335 darkPaint.setColor(0xFF804020);
336 SkPaint lightPaint;
337 lightPaint.setColor(0xFF244484);
338 const int i = kBitmapSize / 4;
339 for (int y = 0; y < kBitmapSize; y += i) {
340 for (int x = 0; x < kBitmapSize; x += i) {
fmalita5598b632015-09-15 11:26:13 -0700341 canvas->save();
342 canvas->translate(SkIntToScalar(x), SkIntToScalar(y));
343 canvas->drawRect(SkRect::MakeXYWH(0, 0,
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000344 SkIntToScalar(i),
345 SkIntToScalar(i)), darkPaint);
fmalita5598b632015-09-15 11:26:13 -0700346 canvas->drawRect(SkRect::MakeXYWH(SkIntToScalar(i),
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000347 0,
348 SkIntToScalar(i),
349 SkIntToScalar(i)), lightPaint);
fmalita5598b632015-09-15 11:26:13 -0700350 canvas->drawRect(SkRect::MakeXYWH(0,
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000351 SkIntToScalar(i),
352 SkIntToScalar(i),
353 SkIntToScalar(i)), lightPaint);
fmalita5598b632015-09-15 11:26:13 -0700354 canvas->drawRect(SkRect::MakeXYWH(SkIntToScalar(i),
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000355 SkIntToScalar(i),
356 SkIntToScalar(i),
357 SkIntToScalar(i)), darkPaint);
fmalita5598b632015-09-15 11:26:13 -0700358 canvas->restore();
commit-bot@chromium.org4b681bc2013-09-13 12:40:02 +0000359 }
360 }
fmalita5598b632015-09-15 11:26:13 -0700361
reed9ce9d672016-03-17 10:51:11 -0700362 return surface->makeImageSnapshot();
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000363}
senorblanco@chromium.org194d7752013-07-24 22:19:24 +0000364
robertphillips5605b562016-04-05 11:50:42 -0700365static sk_sp<SkImageFilter> make_scale(float amount, sk_sp<SkImageFilter> input) {
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000366 SkScalar s = amount;
367 SkScalar matrix[20] = { s, 0, 0, 0, 0,
368 0, s, 0, 0, 0,
369 0, 0, s, 0, 0,
370 0, 0, 0, s, 0 };
robertphillips5605b562016-04-05 11:50:42 -0700371 sk_sp<SkColorFilter> filter(SkColorFilter::MakeMatrixFilterRowMajor255(matrix));
372 return SkColorFilterImageFilter::Make(std::move(filter), std::move(input));
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000373}
374
robertphillips5605b562016-04-05 11:50:42 -0700375static sk_sp<SkImageFilter> make_grayscale(sk_sp<SkImageFilter> input,
376 const SkImageFilter::CropRect* cropRect) {
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000377 SkScalar matrix[20];
378 memset(matrix, 0, 20 * sizeof(SkScalar));
379 matrix[0] = matrix[5] = matrix[10] = 0.2126f;
380 matrix[1] = matrix[6] = matrix[11] = 0.7152f;
381 matrix[2] = matrix[7] = matrix[12] = 0.0722f;
382 matrix[18] = 1.0f;
robertphillips5605b562016-04-05 11:50:42 -0700383 sk_sp<SkColorFilter> filter(SkColorFilter::MakeMatrixFilterRowMajor255(matrix));
384 return SkColorFilterImageFilter::Make(std::move(filter), std::move(input), cropRect);
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000385}
386
robertphillips5605b562016-04-05 11:50:42 -0700387static sk_sp<SkImageFilter> make_blue(sk_sp<SkImageFilter> input,
388 const SkImageFilter::CropRect* cropRect) {
389 sk_sp<SkColorFilter> filter(SkColorFilter::MakeModeFilter(SK_ColorBLUE,
Mike Reed7d954ad2016-10-28 15:42:34 -0400390 SkBlendMode::kSrcIn));
robertphillips5605b562016-04-05 11:50:42 -0700391 return SkColorFilterImageFilter::Make(std::move(filter), std::move(input), cropRect);
reedcedc36f2015-03-08 04:42:52 -0700392}
393
robertphillips3e302272016-04-20 11:48:36 -0700394static sk_sp<SkSpecialSurface> create_empty_special_surface(GrContext* context, int widthHeight) {
robertphillipsc91fd342016-04-25 12:32:54 -0700395#if SK_SUPPORT_GPU
robertphillips4418dba2016-03-07 12:45:14 -0800396 if (context) {
robertphillips4df16562016-04-28 15:09:34 -0700397 return SkSpecialSurface::MakeRenderTarget(context,
398 widthHeight, widthHeight,
Brian Osman777b5632016-10-14 09:16:21 -0400399 kRGBA_8888_GrPixelConfig, nullptr);
robertphillipsc91fd342016-04-25 12:32:54 -0700400 } else
401#endif
402 {
robertphillips4418dba2016-03-07 12:45:14 -0800403 const SkImageInfo info = SkImageInfo::MakeN32(widthHeight, widthHeight,
404 kOpaque_SkAlphaType);
robertphillips3e302272016-04-20 11:48:36 -0700405 return SkSpecialSurface::MakeRaster(info);
robertphillips4418dba2016-03-07 12:45:14 -0800406 }
senorblancobf680c32016-03-16 16:15:53 -0700407}
408
senorblanco5878dbd2016-05-19 14:50:29 -0700409static sk_sp<SkSurface> create_surface(GrContext* context, int width, int height) {
410 const SkImageInfo info = SkImageInfo::MakeN32(width, height, kOpaque_SkAlphaType);
411#if SK_SUPPORT_GPU
412 if (context) {
413 return SkSurface::MakeRenderTarget(context, SkBudgeted::kNo, info);
414 } else
415#endif
416 {
417 return SkSurface::MakeRaster(info);
418 }
419}
420
robertphillips3e302272016-04-20 11:48:36 -0700421static sk_sp<SkSpecialImage> create_empty_special_image(GrContext* context, int widthHeight) {
422 sk_sp<SkSpecialSurface> surf(create_empty_special_surface(context, widthHeight));
robertphillips4418dba2016-03-07 12:45:14 -0800423
424 SkASSERT(surf);
425
426 SkCanvas* canvas = surf->getCanvas();
427 SkASSERT(canvas);
428
429 canvas->clear(0x0);
430
robertphillips37bd7c32016-03-17 14:31:39 -0700431 return surf->makeImageSnapshot();
robertphillips4418dba2016-03-07 12:45:14 -0800432}
433
434
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000435DEF_TEST(ImageFilter, reporter) {
436 {
reedcedc36f2015-03-08 04:42:52 -0700437 // Check that two non-clipping color-matrice-filters concatenate into a single filter.
robertphillips5605b562016-04-05 11:50:42 -0700438 sk_sp<SkImageFilter> halfBrightness(make_scale(0.5f, nullptr));
439 sk_sp<SkImageFilter> quarterBrightness(make_scale(0.5f, std::move(halfBrightness)));
halcanary96fcdcc2015-08-27 07:41:13 -0700440 REPORTER_ASSERT(reporter, nullptr == quarterBrightness->getInput(0));
reedcedc36f2015-03-08 04:42:52 -0700441 SkColorFilter* cf;
442 REPORTER_ASSERT(reporter, quarterBrightness->asColorFilter(&cf));
halcanary96fcdcc2015-08-27 07:41:13 -0700443 REPORTER_ASSERT(reporter, cf->asColorMatrix(nullptr));
reedcedc36f2015-03-08 04:42:52 -0700444 cf->unref();
senorblanco@chromium.org194d7752013-07-24 22:19:24 +0000445 }
446
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000447 {
reedcedc36f2015-03-08 04:42:52 -0700448 // Check that a clipping color-matrice-filter followed by a color-matrice-filters
449 // concatenates into a single filter, but not a matrixfilter (due to clamping).
robertphillips5605b562016-04-05 11:50:42 -0700450 sk_sp<SkImageFilter> doubleBrightness(make_scale(2.0f, nullptr));
451 sk_sp<SkImageFilter> halfBrightness(make_scale(0.5f, std::move(doubleBrightness)));
halcanary96fcdcc2015-08-27 07:41:13 -0700452 REPORTER_ASSERT(reporter, nullptr == halfBrightness->getInput(0));
reedcedc36f2015-03-08 04:42:52 -0700453 SkColorFilter* cf;
454 REPORTER_ASSERT(reporter, halfBrightness->asColorFilter(&cf));
halcanary96fcdcc2015-08-27 07:41:13 -0700455 REPORTER_ASSERT(reporter, !cf->asColorMatrix(nullptr));
reedcedc36f2015-03-08 04:42:52 -0700456 cf->unref();
senorblanco@chromium.org194d7752013-07-24 22:19:24 +0000457 }
458
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000459 {
460 // Check that a color filter image filter without a crop rect can be
461 // expressed as a color filter.
robertphillips5605b562016-04-05 11:50:42 -0700462 sk_sp<SkImageFilter> gray(make_grayscale(nullptr, nullptr));
halcanary96fcdcc2015-08-27 07:41:13 -0700463 REPORTER_ASSERT(reporter, true == gray->asColorFilter(nullptr));
senorblanco@chromium.org194d7752013-07-24 22:19:24 +0000464 }
mtklein2afbe232016-02-07 12:23:10 -0800465
reedcedc36f2015-03-08 04:42:52 -0700466 {
467 // Check that a colorfilterimage filter without a crop rect but with an input
468 // that is another colorfilterimage can be expressed as a colorfilter (composed).
robertphillips5605b562016-04-05 11:50:42 -0700469 sk_sp<SkImageFilter> mode(make_blue(nullptr, nullptr));
470 sk_sp<SkImageFilter> gray(make_grayscale(std::move(mode), nullptr));
halcanary96fcdcc2015-08-27 07:41:13 -0700471 REPORTER_ASSERT(reporter, true == gray->asColorFilter(nullptr));
reedcedc36f2015-03-08 04:42:52 -0700472 }
473
474 {
475 // Test that if we exceed the limit of what ComposeColorFilter can combine, we still
476 // can build the DAG and won't assert if we call asColorFilter.
robertphillips5605b562016-04-05 11:50:42 -0700477 sk_sp<SkImageFilter> filter(make_blue(nullptr, nullptr));
reedcedc36f2015-03-08 04:42:52 -0700478 const int kWayTooManyForComposeColorFilter = 100;
479 for (int i = 0; i < kWayTooManyForComposeColorFilter; ++i) {
robertphillips5605b562016-04-05 11:50:42 -0700480 filter = make_blue(filter, nullptr);
reedcedc36f2015-03-08 04:42:52 -0700481 // the first few of these will succeed, but after we hit the internal limit,
482 // it will then return false.
halcanary96fcdcc2015-08-27 07:41:13 -0700483 (void)filter->asColorFilter(nullptr);
reedcedc36f2015-03-08 04:42:52 -0700484 }
485 }
reed5c518a82015-03-05 14:47:29 -0800486
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000487 {
488 // Check that a color filter image filter with a crop rect cannot
489 // be expressed as a color filter.
490 SkImageFilter::CropRect cropRect(SkRect::MakeXYWH(0, 0, 100, 100));
robertphillips5605b562016-04-05 11:50:42 -0700491 sk_sp<SkImageFilter> grayWithCrop(make_grayscale(nullptr, &cropRect));
halcanary96fcdcc2015-08-27 07:41:13 -0700492 REPORTER_ASSERT(reporter, false == grayWithCrop->asColorFilter(nullptr));
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000493 }
494
495 {
senorblanco3df05012014-07-03 11:13:09 -0700496 // Check that two non-commutative matrices are concatenated in
497 // the correct order.
498 SkScalar blueToRedMatrix[20] = { 0 };
499 blueToRedMatrix[2] = blueToRedMatrix[18] = SK_Scalar1;
500 SkScalar redToGreenMatrix[20] = { 0 };
501 redToGreenMatrix[5] = redToGreenMatrix[18] = SK_Scalar1;
robertphillips5605b562016-04-05 11:50:42 -0700502 sk_sp<SkColorFilter> blueToRed(SkColorFilter::MakeMatrixFilterRowMajor255(blueToRedMatrix));
503 sk_sp<SkImageFilter> filter1(SkColorFilterImageFilter::Make(std::move(blueToRed),
504 nullptr));
505 sk_sp<SkColorFilter> redToGreen(SkColorFilter::MakeMatrixFilterRowMajor255(redToGreenMatrix));
506 sk_sp<SkImageFilter> filter2(SkColorFilterImageFilter::Make(std::move(redToGreen),
507 std::move(filter1)));
senorblanco3df05012014-07-03 11:13:09 -0700508
509 SkBitmap result;
510 result.allocN32Pixels(kBitmapSize, kBitmapSize);
511
512 SkPaint paint;
513 paint.setColor(SK_ColorBLUE);
robertphillips5605b562016-04-05 11:50:42 -0700514 paint.setImageFilter(std::move(filter2));
senorblanco3df05012014-07-03 11:13:09 -0700515 SkCanvas canvas(result);
516 canvas.clear(0x0);
517 SkRect rect = SkRect::Make(SkIRect::MakeWH(kBitmapSize, kBitmapSize));
518 canvas.drawRect(rect, paint);
519 uint32_t pixel = *result.getAddr32(0, 0);
520 // The result here should be green, since we have effectively shifted blue to green.
521 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
522 }
523
524 {
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000525 // Tests pass by not asserting
reed9ce9d672016-03-17 10:51:11 -0700526 sk_sp<SkImage> image(make_small_image());
fmalita5598b632015-09-15 11:26:13 -0700527 SkBitmap result;
mike@reedtribe.orgdeee4962014-02-13 14:41:43 +0000528 result.allocN32Pixels(kBitmapSize, kBitmapSize);
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000529
senorblanco@chromium.org194d7752013-07-24 22:19:24 +0000530 {
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000531 // This tests for :
532 // 1 ) location at (0,0,1)
robertphillips3d32d762015-07-13 13:16:44 -0700533 SkPoint3 location = SkPoint3::Make(0, 0, SK_Scalar1);
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000534 // 2 ) location and target at same value
robertphillips3d32d762015-07-13 13:16:44 -0700535 SkPoint3 target = SkPoint3::Make(location.fX, location.fY, location.fZ);
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000536 // 3 ) large negative specular exponent value
537 SkScalar specularExponent = -1000;
538
robertphillips549c8992016-04-01 09:28:51 -0700539 sk_sp<SkImageFilter> bmSrc(SkImageSource::Make(std::move(image)));
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000540 SkPaint paint;
robertphillips12fa47d2016-04-08 16:28:09 -0700541 paint.setImageFilter(SkLightingImageFilter::MakeSpotLitSpecular(
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000542 location, target, specularExponent, 180,
543 0xFFFFFFFF, SK_Scalar1, SK_Scalar1, SK_Scalar1,
robertphillips12fa47d2016-04-08 16:28:09 -0700544 std::move(bmSrc)));
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000545 SkCanvas canvas(result);
546 SkRect r = SkRect::MakeWH(SkIntToScalar(kBitmapSize),
547 SkIntToScalar(kBitmapSize));
548 canvas.drawRect(r, paint);
senorblanco@chromium.org194d7752013-07-24 22:19:24 +0000549 }
senorblanco@chromium.org194d7752013-07-24 22:19:24 +0000550 }
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +0000551}
senorblanco@chromium.org6776b822014-01-03 21:48:22 +0000552
robertphillips3e302272016-04-20 11:48:36 -0700553static void test_crop_rects(skiatest::Reporter* reporter,
robertphillips4418dba2016-03-07 12:45:14 -0800554 GrContext* context) {
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +0000555 // Check that all filters offset to their absolute crop rect,
556 // unaffected by the input crop rect.
557 // Tests pass by not asserting.
robertphillips3e302272016-04-20 11:48:36 -0700558 sk_sp<SkSpecialImage> srcImg(create_empty_special_image(context, 100));
robertphillips4418dba2016-03-07 12:45:14 -0800559 SkASSERT(srcImg);
senorblanco@chromium.org6776b822014-01-03 21:48:22 +0000560
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +0000561 SkImageFilter::CropRect inputCropRect(SkRect::MakeXYWH(8, 13, 80, 80));
562 SkImageFilter::CropRect cropRect(SkRect::MakeXYWH(20, 30, 60, 60));
robertphillipsfc11b0a2016-04-05 09:09:36 -0700563 sk_sp<SkImageFilter> input(make_grayscale(nullptr, &inputCropRect));
senorblanco@chromium.org6776b822014-01-03 21:48:22 +0000564
robertphillipsfc11b0a2016-04-05 09:09:36 -0700565 FilterList filters(input, &cropRect);
senorblanco@chromium.org6776b822014-01-03 21:48:22 +0000566
senorblanco297f7ce2016-03-23 13:44:26 -0700567 for (int i = 0; i < filters.count(); ++i) {
568 SkImageFilter* filter = filters.getFilter(i);
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +0000569 SkIPoint offset;
brianosman2a75e5d2016-09-22 07:15:37 -0700570 SkImageFilter::OutputProperties noColorSpace(nullptr);
571 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeWH(100, 100), nullptr, noColorSpace);
robertphillips2302de92016-03-24 07:26:32 -0700572 sk_sp<SkSpecialImage> resultImg(filter->filterImage(srcImg.get(), ctx, &offset));
senorblanco297f7ce2016-03-23 13:44:26 -0700573 REPORTER_ASSERT_MESSAGE(reporter, resultImg, filters.getName(i));
574 REPORTER_ASSERT_MESSAGE(reporter, offset.fX == 20 && offset.fY == 30, filters.getName(i));
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +0000575 }
576}
577
robertphillips3e302272016-04-20 11:48:36 -0700578static void test_negative_blur_sigma(skiatest::Reporter* reporter,
robertphillips4418dba2016-03-07 12:45:14 -0800579 GrContext* context) {
senorblanco32673b92014-09-09 09:15:04 -0700580 // Check that SkBlurImageFilter will accept a negative sigma, either in
581 // the given arguments or after CTM application.
reed5ea95df2015-10-06 14:05:32 -0700582 const int width = 32, height = 32;
583 const SkScalar five = SkIntToScalar(5);
senorblanco32673b92014-09-09 09:15:04 -0700584
robertphillips6e7025a2016-04-04 04:31:25 -0700585 sk_sp<SkImageFilter> positiveFilter(SkBlurImageFilter::Make(five, five, nullptr));
586 sk_sp<SkImageFilter> negativeFilter(SkBlurImageFilter::Make(-five, five, nullptr));
senorblanco32673b92014-09-09 09:15:04 -0700587
588 SkBitmap gradient = make_gradient_circle(width, height);
robertphillips3e302272016-04-20 11:48:36 -0700589 sk_sp<SkSpecialImage> imgSrc(SkSpecialImage::MakeFromRaster(SkIRect::MakeWH(width, height),
robertphillips37bd7c32016-03-17 14:31:39 -0700590 gradient));
robertphillips4418dba2016-03-07 12:45:14 -0800591
senorblanco32673b92014-09-09 09:15:04 -0700592 SkIPoint offset;
brianosman2a75e5d2016-09-22 07:15:37 -0700593 SkImageFilter::OutputProperties noColorSpace(nullptr);
594 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeWH(32, 32), nullptr, noColorSpace);
robertphillips4418dba2016-03-07 12:45:14 -0800595
robertphillips2302de92016-03-24 07:26:32 -0700596 sk_sp<SkSpecialImage> positiveResult1(positiveFilter->filterImage(imgSrc.get(), ctx, &offset));
robertphillips4418dba2016-03-07 12:45:14 -0800597 REPORTER_ASSERT(reporter, positiveResult1);
598
robertphillips2302de92016-03-24 07:26:32 -0700599 sk_sp<SkSpecialImage> negativeResult1(negativeFilter->filterImage(imgSrc.get(), ctx, &offset));
robertphillips4418dba2016-03-07 12:45:14 -0800600 REPORTER_ASSERT(reporter, negativeResult1);
601
senorblanco32673b92014-09-09 09:15:04 -0700602 SkMatrix negativeScale;
603 negativeScale.setScale(-SK_Scalar1, SK_Scalar1);
brianosman2a75e5d2016-09-22 07:15:37 -0700604 SkImageFilter::Context negativeCTX(negativeScale, SkIRect::MakeWH(32, 32), nullptr,
605 noColorSpace);
robertphillips4418dba2016-03-07 12:45:14 -0800606
robertphillips2302de92016-03-24 07:26:32 -0700607 sk_sp<SkSpecialImage> negativeResult2(positiveFilter->filterImage(imgSrc.get(),
608 negativeCTX,
609 &offset));
robertphillips4418dba2016-03-07 12:45:14 -0800610 REPORTER_ASSERT(reporter, negativeResult2);
611
robertphillips2302de92016-03-24 07:26:32 -0700612 sk_sp<SkSpecialImage> positiveResult2(negativeFilter->filterImage(imgSrc.get(),
613 negativeCTX,
614 &offset));
robertphillips4418dba2016-03-07 12:45:14 -0800615 REPORTER_ASSERT(reporter, positiveResult2);
616
617
618 SkBitmap positiveResultBM1, positiveResultBM2;
619 SkBitmap negativeResultBM1, negativeResultBM2;
620
robertphillips64612512016-04-08 12:10:42 -0700621 REPORTER_ASSERT(reporter, positiveResult1->getROPixels(&positiveResultBM1));
622 REPORTER_ASSERT(reporter, positiveResult2->getROPixels(&positiveResultBM2));
623 REPORTER_ASSERT(reporter, negativeResult1->getROPixels(&negativeResultBM1));
624 REPORTER_ASSERT(reporter, negativeResult2->getROPixels(&negativeResultBM2));
robertphillips4418dba2016-03-07 12:45:14 -0800625
senorblanco32673b92014-09-09 09:15:04 -0700626 for (int y = 0; y < height; y++) {
robertphillips4418dba2016-03-07 12:45:14 -0800627 int diffs = memcmp(positiveResultBM1.getAddr32(0, y),
628 negativeResultBM1.getAddr32(0, y),
629 positiveResultBM1.rowBytes());
senorblanco32673b92014-09-09 09:15:04 -0700630 REPORTER_ASSERT(reporter, !diffs);
631 if (diffs) {
632 break;
633 }
robertphillips4418dba2016-03-07 12:45:14 -0800634 diffs = memcmp(positiveResultBM1.getAddr32(0, y),
635 negativeResultBM2.getAddr32(0, y),
636 positiveResultBM1.rowBytes());
senorblanco32673b92014-09-09 09:15:04 -0700637 REPORTER_ASSERT(reporter, !diffs);
638 if (diffs) {
639 break;
640 }
robertphillips4418dba2016-03-07 12:45:14 -0800641 diffs = memcmp(positiveResultBM1.getAddr32(0, y),
642 positiveResultBM2.getAddr32(0, y),
643 positiveResultBM1.rowBytes());
senorblanco32673b92014-09-09 09:15:04 -0700644 REPORTER_ASSERT(reporter, !diffs);
645 if (diffs) {
646 break;
647 }
648 }
649}
650
senorblanco21a465d2016-04-11 11:58:39 -0700651DEF_TEST(ImageFilterNegativeBlurSigma, reporter) {
robertphillips3e302272016-04-20 11:48:36 -0700652 test_negative_blur_sigma(reporter, nullptr);
robertphillips4418dba2016-03-07 12:45:14 -0800653}
654
655#if SK_SUPPORT_GPU
bsalomon68d91342016-04-12 09:59:58 -0700656DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterNegativeBlurSigma_Gpu, reporter, ctxInfo) {
bsalomon8b7451a2016-05-11 06:33:06 -0700657 test_negative_blur_sigma(reporter, ctxInfo.grContext());
robertphillips4418dba2016-03-07 12:45:14 -0800658}
659#endif
660
robertphillips3e302272016-04-20 11:48:36 -0700661static void test_zero_blur_sigma(skiatest::Reporter* reporter, GrContext* context) {
senorblancobf680c32016-03-16 16:15:53 -0700662 // Check that SkBlurImageFilter with a zero sigma and a non-zero srcOffset works correctly.
663 SkImageFilter::CropRect cropRect(SkRect::Make(SkIRect::MakeXYWH(5, 0, 5, 10)));
robertphillips51a315e2016-03-31 09:05:49 -0700664 sk_sp<SkImageFilter> input(SkOffsetImageFilter::Make(0, 0, nullptr, &cropRect));
robertphillips6e7025a2016-04-04 04:31:25 -0700665 sk_sp<SkImageFilter> filter(SkBlurImageFilter::Make(0, 0, std::move(input), &cropRect));
senorblancobf680c32016-03-16 16:15:53 -0700666
robertphillips3e302272016-04-20 11:48:36 -0700667 sk_sp<SkSpecialSurface> surf(create_empty_special_surface(context, 10));
senorblancobf680c32016-03-16 16:15:53 -0700668 surf->getCanvas()->clear(SK_ColorGREEN);
robertphillips37bd7c32016-03-17 14:31:39 -0700669 sk_sp<SkSpecialImage> image(surf->makeImageSnapshot());
senorblancobf680c32016-03-16 16:15:53 -0700670
671 SkIPoint offset;
brianosman2a75e5d2016-09-22 07:15:37 -0700672 SkImageFilter::OutputProperties noColorSpace(nullptr);
673 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeWH(32, 32), nullptr, noColorSpace);
senorblancobf680c32016-03-16 16:15:53 -0700674
robertphillips2302de92016-03-24 07:26:32 -0700675 sk_sp<SkSpecialImage> result(filter->filterImage(image.get(), ctx, &offset));
senorblancobf680c32016-03-16 16:15:53 -0700676 REPORTER_ASSERT(reporter, offset.fX == 5 && offset.fY == 0);
677 REPORTER_ASSERT(reporter, result);
678 REPORTER_ASSERT(reporter, result->width() == 5 && result->height() == 10);
679
680 SkBitmap resultBM;
681
robertphillips64612512016-04-08 12:10:42 -0700682 REPORTER_ASSERT(reporter, result->getROPixels(&resultBM));
senorblancobf680c32016-03-16 16:15:53 -0700683
senorblancobf680c32016-03-16 16:15:53 -0700684 for (int y = 0; y < resultBM.height(); y++) {
685 for (int x = 0; x < resultBM.width(); x++) {
686 bool diff = *resultBM.getAddr32(x, y) != SK_ColorGREEN;
687 REPORTER_ASSERT(reporter, !diff);
688 if (diff) {
689 break;
690 }
691 }
692 }
693}
694
senorblanco21a465d2016-04-11 11:58:39 -0700695DEF_TEST(ImageFilterZeroBlurSigma, reporter) {
robertphillips3e302272016-04-20 11:48:36 -0700696 test_zero_blur_sigma(reporter, nullptr);
senorblancobf680c32016-03-16 16:15:53 -0700697}
698
699#if SK_SUPPORT_GPU
bsalomon68d91342016-04-12 09:59:58 -0700700DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterZeroBlurSigma_Gpu, reporter, ctxInfo) {
bsalomon8b7451a2016-05-11 06:33:06 -0700701 test_zero_blur_sigma(reporter, ctxInfo.grContext());
senorblancobf680c32016-03-16 16:15:53 -0700702}
703#endif
704
senorblanco6a93fa12016-04-05 04:43:45 -0700705
706// Tests that, even when an upstream filter has returned null (due to failure or clipping), a
707// downstream filter that affects transparent black still does so even with a nullptr input.
robertphillips3e302272016-04-20 11:48:36 -0700708static void test_fail_affects_transparent_black(skiatest::Reporter* reporter, GrContext* context) {
senorblanco6a93fa12016-04-05 04:43:45 -0700709 sk_sp<FailImageFilter> failFilter(new FailImageFilter());
robertphillips3e302272016-04-20 11:48:36 -0700710 sk_sp<SkSpecialImage> source(create_empty_special_image(context, 5));
brianosman2a75e5d2016-09-22 07:15:37 -0700711 SkImageFilter::OutputProperties noColorSpace(nullptr);
712 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeXYWH(0, 0, 1, 1), nullptr, noColorSpace);
Mike Reed7d954ad2016-10-28 15:42:34 -0400713 sk_sp<SkColorFilter> green(SkColorFilter::MakeModeFilter(SK_ColorGREEN, SkBlendMode::kSrc));
senorblanco6a93fa12016-04-05 04:43:45 -0700714 SkASSERT(green->affectsTransparentBlack());
robertphillips5605b562016-04-05 11:50:42 -0700715 sk_sp<SkImageFilter> greenFilter(SkColorFilterImageFilter::Make(std::move(green),
716 std::move(failFilter)));
senorblanco6a93fa12016-04-05 04:43:45 -0700717 SkIPoint offset;
718 sk_sp<SkSpecialImage> result(greenFilter->filterImage(source.get(), ctx, &offset));
719 REPORTER_ASSERT(reporter, nullptr != result.get());
720 if (result.get()) {
721 SkBitmap resultBM;
robertphillips64612512016-04-08 12:10:42 -0700722 REPORTER_ASSERT(reporter, result->getROPixels(&resultBM));
senorblanco6a93fa12016-04-05 04:43:45 -0700723 REPORTER_ASSERT(reporter, *resultBM.getAddr32(0, 0) == SK_ColorGREEN);
724 }
725}
726
727DEF_TEST(ImageFilterFailAffectsTransparentBlack, reporter) {
robertphillips3e302272016-04-20 11:48:36 -0700728 test_fail_affects_transparent_black(reporter, nullptr);
senorblanco6a93fa12016-04-05 04:43:45 -0700729}
730
731#if SK_SUPPORT_GPU
bsalomon68d91342016-04-12 09:59:58 -0700732DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterFailAffectsTransparentBlack_Gpu, reporter, ctxInfo) {
bsalomon8b7451a2016-05-11 06:33:06 -0700733 test_fail_affects_transparent_black(reporter, ctxInfo.grContext());
senorblanco6a93fa12016-04-05 04:43:45 -0700734}
735#endif
736
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +0000737DEF_TEST(ImageFilterDrawTiled, reporter) {
738 // Check that all filters when drawn tiled (with subsequent clip rects) exactly
739 // match the same filters drawn with a single full-canvas bitmap draw.
740 // Tests pass by not asserting.
741
robertphillipsfc11b0a2016-04-05 09:09:36 -0700742 FilterList filters(nullptr);
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +0000743
744 SkBitmap untiledResult, tiledResult;
reed5ea95df2015-10-06 14:05:32 -0700745 const int width = 64, height = 64;
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +0000746 untiledResult.allocN32Pixels(width, height);
747 tiledResult.allocN32Pixels(width, height);
748 SkCanvas tiledCanvas(tiledResult);
749 SkCanvas untiledCanvas(untiledResult);
senorblanco@chromium.orgd4db6572014-05-07 20:00:04 +0000750 int tileSize = 8;
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +0000751
senorblanco@chromium.orgd4db6572014-05-07 20:00:04 +0000752 for (int scale = 1; scale <= 2; ++scale) {
senorblanco297f7ce2016-03-23 13:44:26 -0700753 for (int i = 0; i < filters.count(); ++i) {
senorblanco@chromium.orgd4db6572014-05-07 20:00:04 +0000754 tiledCanvas.clear(0);
755 untiledCanvas.clear(0);
756 SkPaint paint;
Mike Reed5e257172016-11-01 11:22:05 -0400757 paint.setImageFilter(sk_ref_sp(filters.getFilter(i)));
senorblanco@chromium.orgd4db6572014-05-07 20:00:04 +0000758 paint.setTextSize(SkIntToScalar(height));
759 paint.setColor(SK_ColorWHITE);
760 SkString str;
761 const char* text = "ABC";
762 SkScalar ypos = SkIntToScalar(height);
763 untiledCanvas.save();
764 untiledCanvas.scale(SkIntToScalar(scale), SkIntToScalar(scale));
Cary Clark2a475ea2017-04-28 15:35:12 -0400765 untiledCanvas.drawString(text, 0, ypos, paint);
senorblanco@chromium.orgd4db6572014-05-07 20:00:04 +0000766 untiledCanvas.restore();
767 for (int y = 0; y < height; y += tileSize) {
768 for (int x = 0; x < width; x += tileSize) {
769 tiledCanvas.save();
770 tiledCanvas.clipRect(SkRect::Make(SkIRect::MakeXYWH(x, y, tileSize, tileSize)));
771 tiledCanvas.scale(SkIntToScalar(scale), SkIntToScalar(scale));
Cary Clark2a475ea2017-04-28 15:35:12 -0400772 tiledCanvas.drawString(text, 0, ypos, paint);
senorblanco@chromium.orgd4db6572014-05-07 20:00:04 +0000773 tiledCanvas.restore();
774 }
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +0000775 }
senorblanco@chromium.orgd4db6572014-05-07 20:00:04 +0000776 untiledCanvas.flush();
777 tiledCanvas.flush();
Mike Reed34042072017-08-08 16:29:22 -0400778 if (!sk_tool_utils::equal_pixels(untiledResult, tiledResult, 1)) {
Mike Reed5a625e02017-08-08 15:48:54 -0400779 REPORTER_ASSERT_MESSAGE(reporter, false, filters.getName(i));
780 break;
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +0000781 }
782 }
783 }
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +0000784}
785
mtklein3f3b3d02014-12-01 11:47:08 -0800786static void draw_saveLayer_picture(int width, int height, int tileSize,
robertphillipsa8d7f0b2014-08-29 08:03:56 -0700787 SkBBHFactory* factory, SkBitmap* result) {
mtkleind910f542014-08-22 09:06:34 -0700788
789 SkMatrix matrix;
790 matrix.setTranslate(SkIntToScalar(50), 0);
791
Mike Reed7d954ad2016-10-28 15:42:34 -0400792 sk_sp<SkColorFilter> cf(SkColorFilter::MakeModeFilter(SK_ColorWHITE, SkBlendMode::kSrc));
robertphillips5605b562016-04-05 11:50:42 -0700793 sk_sp<SkImageFilter> cfif(SkColorFilterImageFilter::Make(std::move(cf), nullptr));
robertphillipsae8c9332016-04-05 15:09:00 -0700794 sk_sp<SkImageFilter> imageFilter(SkImageFilter::MakeMatrixFilter(matrix,
795 kNone_SkFilterQuality,
796 std::move(cfif)));
mtkleind910f542014-08-22 09:06:34 -0700797
798 SkPaint paint;
robertphillips5605b562016-04-05 11:50:42 -0700799 paint.setImageFilter(std::move(imageFilter));
mtkleind910f542014-08-22 09:06:34 -0700800 SkPictureRecorder recorder;
801 SkRect bounds = SkRect::Make(SkIRect::MakeXYWH(0, 0, 50, 50));
mtklein3f3b3d02014-12-01 11:47:08 -0800802 SkCanvas* recordingCanvas = recorder.beginRecording(SkIntToScalar(width),
803 SkIntToScalar(height),
robertphillipsa8d7f0b2014-08-29 08:03:56 -0700804 factory, 0);
mtkleind910f542014-08-22 09:06:34 -0700805 recordingCanvas->translate(-55, 0);
806 recordingCanvas->saveLayer(&bounds, &paint);
807 recordingCanvas->restore();
reedca2622b2016-03-18 07:25:55 -0700808 sk_sp<SkPicture> picture1(recorder.finishRecordingAsPicture());
mtkleind910f542014-08-22 09:06:34 -0700809
810 result->allocN32Pixels(width, height);
811 SkCanvas canvas(*result);
812 canvas.clear(0);
813 canvas.clipRect(SkRect::Make(SkIRect::MakeWH(tileSize, tileSize)));
814 canvas.drawPicture(picture1.get());
815}
816
817DEF_TEST(ImageFilterDrawMatrixBBH, reporter) {
818 // Check that matrix filter when drawn tiled with BBH exactly
819 // matches the same thing drawn without BBH.
820 // Tests pass by not asserting.
821
822 const int width = 200, height = 200;
823 const int tileSize = 100;
824 SkBitmap result1, result2;
825 SkRTreeFactory factory;
826
robertphillipsa8d7f0b2014-08-29 08:03:56 -0700827 draw_saveLayer_picture(width, height, tileSize, &factory, &result1);
halcanary96fcdcc2015-08-27 07:41:13 -0700828 draw_saveLayer_picture(width, height, tileSize, nullptr, &result2);
mtkleind910f542014-08-22 09:06:34 -0700829
830 for (int y = 0; y < height; y++) {
831 int diffs = memcmp(result1.getAddr32(0, y), result2.getAddr32(0, y), result1.rowBytes());
832 REPORTER_ASSERT(reporter, !diffs);
833 if (diffs) {
834 break;
835 }
836 }
837}
838
Herb Derbya0020f92017-10-17 15:21:22 -0400839#if !defined(SK_SUPPORT_LEGACY_BLUR_IMAGE)
840
robertphillips6e7025a2016-04-04 04:31:25 -0700841static sk_sp<SkImageFilter> make_blur(sk_sp<SkImageFilter> input) {
842 return SkBlurImageFilter::Make(SK_Scalar1, SK_Scalar1, std::move(input));
senorblanco1150a6d2014-08-25 12:46:58 -0700843}
844
robertphillips6e7025a2016-04-04 04:31:25 -0700845static sk_sp<SkImageFilter> make_drop_shadow(sk_sp<SkImageFilter> input) {
robertphillipsc4169122016-04-06 08:40:59 -0700846 return SkDropShadowImageFilter::Make(
senorblanco1150a6d2014-08-25 12:46:58 -0700847 SkIntToScalar(100), SkIntToScalar(100),
848 SkIntToScalar(10), SkIntToScalar(10),
sugoi234f0362014-10-23 13:59:52 -0700849 SK_ColorBLUE, SkDropShadowImageFilter::kDrawShadowAndForeground_ShadowMode,
robertphillipsc4169122016-04-06 08:40:59 -0700850 std::move(input));
senorblanco1150a6d2014-08-25 12:46:58 -0700851}
852
853DEF_TEST(ImageFilterBlurThenShadowBounds, reporter) {
robertphillips6e7025a2016-04-04 04:31:25 -0700854 sk_sp<SkImageFilter> filter1(make_blur(nullptr));
855 sk_sp<SkImageFilter> filter2(make_drop_shadow(std::move(filter1)));
senorblanco1150a6d2014-08-25 12:46:58 -0700856
857 SkIRect bounds = SkIRect::MakeXYWH(0, 0, 100, 100);
Herb Derby59f8f152017-10-17 22:27:23 +0000858 SkIRect expectedBounds = SkIRect::MakeXYWH(-133, -133, 236, 236);
senorblancoe5e79842016-03-21 14:51:59 -0700859 bounds = filter2->filterBounds(bounds, SkMatrix::I());
senorblanco1150a6d2014-08-25 12:46:58 -0700860
861 REPORTER_ASSERT(reporter, bounds == expectedBounds);
862}
863
864DEF_TEST(ImageFilterShadowThenBlurBounds, reporter) {
robertphillips6e7025a2016-04-04 04:31:25 -0700865 sk_sp<SkImageFilter> filter1(make_drop_shadow(nullptr));
866 sk_sp<SkImageFilter> filter2(make_blur(std::move(filter1)));
senorblanco1150a6d2014-08-25 12:46:58 -0700867
868 SkIRect bounds = SkIRect::MakeXYWH(0, 0, 100, 100);
Herb Derby59f8f152017-10-17 22:27:23 +0000869 SkIRect expectedBounds = SkIRect::MakeXYWH(-133, -133, 236, 236);
senorblancoe5e79842016-03-21 14:51:59 -0700870 bounds = filter2->filterBounds(bounds, SkMatrix::I());
senorblanco1150a6d2014-08-25 12:46:58 -0700871
872 REPORTER_ASSERT(reporter, bounds == expectedBounds);
873}
874
875DEF_TEST(ImageFilterDilateThenBlurBounds, reporter) {
robertphillipsfc11b0a2016-04-05 09:09:36 -0700876 sk_sp<SkImageFilter> filter1(SkDilateImageFilter::Make(2, 2, nullptr));
robertphillips6e7025a2016-04-04 04:31:25 -0700877 sk_sp<SkImageFilter> filter2(make_drop_shadow(std::move(filter1)));
senorblanco1150a6d2014-08-25 12:46:58 -0700878
879 SkIRect bounds = SkIRect::MakeXYWH(0, 0, 100, 100);
880 SkIRect expectedBounds = SkIRect::MakeXYWH(-132, -132, 234, 234);
senorblancoe5e79842016-03-21 14:51:59 -0700881 bounds = filter2->filterBounds(bounds, SkMatrix::I());
senorblanco1150a6d2014-08-25 12:46:58 -0700882
883 REPORTER_ASSERT(reporter, bounds == expectedBounds);
884}
885
jbroman203a9932016-07-11 14:07:59 -0700886DEF_TEST(ImageFilterScaledBlurRadius, reporter) {
887 // Each blur should spread 3*sigma, so 3 for the blur and 30 for the shadow
888 // (before the CTM). Bounds should be computed correctly in the presence of
889 // a (possibly negative) scale.
890 sk_sp<SkImageFilter> blur(make_blur(nullptr));
891 sk_sp<SkImageFilter> dropShadow(make_drop_shadow(nullptr));
892 {
893 // Uniform scale by 2.
894 SkMatrix scaleMatrix;
895 scaleMatrix.setScale(2, 2);
896 SkIRect bounds = SkIRect::MakeLTRB(0, 0, 200, 200);
897
Herb Derby59f8f152017-10-17 22:27:23 +0000898 SkIRect expectedBlurBounds = SkIRect::MakeLTRB(-6, -6, 206, 206);
jbroman203a9932016-07-11 14:07:59 -0700899 SkIRect blurBounds = blur->filterBounds(
900 bounds, scaleMatrix, SkImageFilter::kForward_MapDirection);
901 REPORTER_ASSERT(reporter, blurBounds == expectedBlurBounds);
902 SkIRect reverseBlurBounds = blur->filterBounds(
903 bounds, scaleMatrix, SkImageFilter::kReverse_MapDirection);
904 REPORTER_ASSERT(reporter, reverseBlurBounds == expectedBlurBounds);
905
906 SkIRect expectedShadowBounds = SkIRect::MakeLTRB(0, 0, 460, 460);
907 SkIRect shadowBounds = dropShadow->filterBounds(
908 bounds, scaleMatrix, SkImageFilter::kForward_MapDirection);
909 REPORTER_ASSERT(reporter, shadowBounds == expectedShadowBounds);
910 SkIRect expectedReverseShadowBounds =
911 SkIRect::MakeLTRB(-260, -260, 200, 200);
912 SkIRect reverseShadowBounds = dropShadow->filterBounds(
913 bounds, scaleMatrix, SkImageFilter::kReverse_MapDirection);
914 REPORTER_ASSERT(reporter,
915 reverseShadowBounds == expectedReverseShadowBounds);
916 }
917 {
918 // Vertical flip.
919 SkMatrix scaleMatrix;
920 scaleMatrix.setScale(1, -1);
921 SkIRect bounds = SkIRect::MakeLTRB(0, -100, 100, 0);
922
Herb Derby59f8f152017-10-17 22:27:23 +0000923 SkIRect expectedBlurBounds = SkIRect::MakeLTRB(-3, -103, 103, 3);
jbroman203a9932016-07-11 14:07:59 -0700924 SkIRect blurBounds = blur->filterBounds(
925 bounds, scaleMatrix, SkImageFilter::kForward_MapDirection);
926 REPORTER_ASSERT(reporter, blurBounds == expectedBlurBounds);
927 SkIRect reverseBlurBounds = blur->filterBounds(
928 bounds, scaleMatrix, SkImageFilter::kReverse_MapDirection);
929 REPORTER_ASSERT(reporter, reverseBlurBounds == expectedBlurBounds);
930
931 SkIRect expectedShadowBounds = SkIRect::MakeLTRB(0, -230, 230, 0);
932 SkIRect shadowBounds = dropShadow->filterBounds(
933 bounds, scaleMatrix, SkImageFilter::kForward_MapDirection);
934 REPORTER_ASSERT(reporter, shadowBounds == expectedShadowBounds);
935 SkIRect expectedReverseShadowBounds =
936 SkIRect::MakeLTRB(-130, -100, 100, 130);
937 SkIRect reverseShadowBounds = dropShadow->filterBounds(
938 bounds, scaleMatrix, SkImageFilter::kReverse_MapDirection);
939 REPORTER_ASSERT(reporter,
940 reverseShadowBounds == expectedReverseShadowBounds);
941 }
942}
943
ajuma5788faa2015-02-13 09:05:47 -0800944DEF_TEST(ImageFilterComposedBlurFastBounds, reporter) {
robertphillips6e7025a2016-04-04 04:31:25 -0700945 sk_sp<SkImageFilter> filter1(make_blur(nullptr));
946 sk_sp<SkImageFilter> filter2(make_blur(nullptr));
robertphillips491fb172016-03-30 12:32:58 -0700947 sk_sp<SkImageFilter> composedFilter(SkComposeImageFilter::Make(std::move(filter1),
948 std::move(filter2)));
ajuma5788faa2015-02-13 09:05:47 -0800949
950 SkRect boundsSrc = SkRect::MakeWH(SkIntToScalar(100), SkIntToScalar(100));
951 SkRect expectedBounds = SkRect::MakeXYWH(
Herb Derby59f8f152017-10-17 22:27:23 +0000952 SkIntToScalar(-6), SkIntToScalar(-6), SkIntToScalar(112), SkIntToScalar(112));
senorblancoe5e79842016-03-21 14:51:59 -0700953 SkRect boundsDst = composedFilter->computeFastBounds(boundsSrc);
ajuma5788faa2015-02-13 09:05:47 -0800954
955 REPORTER_ASSERT(reporter, boundsDst == expectedBounds);
956}
957
Herb Derbya0020f92017-10-17 15:21:22 -0400958#endif
959
jbroman0e3129d2016-03-17 12:24:23 -0700960DEF_TEST(ImageFilterUnionBounds, reporter) {
robertphillips51a315e2016-03-31 09:05:49 -0700961 sk_sp<SkImageFilter> offset(SkOffsetImageFilter::Make(50, 0, nullptr));
jbroman0e3129d2016-03-17 12:24:23 -0700962 // Regardless of which order they appear in, the image filter bounds should
963 // be combined correctly.
964 {
reed374772b2016-10-05 17:33:02 -0700965 sk_sp<SkImageFilter> composite(SkXfermodeImageFilter::Make(SkBlendMode::kSrcOver, offset));
jbroman0e3129d2016-03-17 12:24:23 -0700966 SkRect bounds = SkRect::MakeWH(100, 100);
967 // Intentionally aliasing here, as that's what the real callers do.
senorblancoe5e79842016-03-21 14:51:59 -0700968 bounds = composite->computeFastBounds(bounds);
jbroman0e3129d2016-03-17 12:24:23 -0700969 REPORTER_ASSERT(reporter, bounds == SkRect::MakeWH(150, 100));
970 }
971 {
reed374772b2016-10-05 17:33:02 -0700972 sk_sp<SkImageFilter> composite(SkXfermodeImageFilter::Make(SkBlendMode::kSrcOver, nullptr,
robertphillips8c0326d2016-04-05 12:48:34 -0700973 offset, nullptr));
jbroman0e3129d2016-03-17 12:24:23 -0700974 SkRect bounds = SkRect::MakeWH(100, 100);
975 // Intentionally aliasing here, as that's what the real callers do.
senorblancoe5e79842016-03-21 14:51:59 -0700976 bounds = composite->computeFastBounds(bounds);
jbroman0e3129d2016-03-17 12:24:23 -0700977 REPORTER_ASSERT(reporter, bounds == SkRect::MakeWH(150, 100));
978 }
979}
980
robertphillips3e302272016-04-20 11:48:36 -0700981static void test_imagefilter_merge_result_size(skiatest::Reporter* reporter, GrContext* context) {
senorblanco4a243982015-11-25 07:06:55 -0800982 SkBitmap greenBM;
983 greenBM.allocN32Pixels(20, 20);
984 greenBM.eraseColor(SK_ColorGREEN);
reed9ce9d672016-03-17 10:51:11 -0700985 sk_sp<SkImage> greenImage(SkImage::MakeFromBitmap(greenBM));
robertphillips549c8992016-04-01 09:28:51 -0700986 sk_sp<SkImageFilter> source(SkImageSource::Make(std::move(greenImage)));
Mike Reed0bdaf052017-06-18 23:35:57 -0400987 sk_sp<SkImageFilter> merge(SkMergeImageFilter::Make(source, source));
senorblanco4a243982015-11-25 07:06:55 -0800988
robertphillips3e302272016-04-20 11:48:36 -0700989 sk_sp<SkSpecialImage> srcImg(create_empty_special_image(context, 1));
robertphillips4418dba2016-03-07 12:45:14 -0800990
brianosman2a75e5d2016-09-22 07:15:37 -0700991 SkImageFilter::OutputProperties noColorSpace(nullptr);
992 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeXYWH(0, 0, 100, 100), nullptr,
993 noColorSpace);
senorblanco4a243982015-11-25 07:06:55 -0800994 SkIPoint offset;
robertphillips4418dba2016-03-07 12:45:14 -0800995
robertphillips2302de92016-03-24 07:26:32 -0700996 sk_sp<SkSpecialImage> resultImg(merge->filterImage(srcImg.get(), ctx, &offset));
robertphillips4418dba2016-03-07 12:45:14 -0800997 REPORTER_ASSERT(reporter, resultImg);
998
999 REPORTER_ASSERT(reporter, resultImg->width() == 20 && resultImg->height() == 20);
senorblanco4a243982015-11-25 07:06:55 -08001000}
1001
robertphillips4418dba2016-03-07 12:45:14 -08001002DEF_TEST(ImageFilterMergeResultSize, reporter) {
robertphillips3e302272016-04-20 11:48:36 -07001003 test_imagefilter_merge_result_size(reporter, nullptr);
robertphillips4418dba2016-03-07 12:45:14 -08001004}
1005
1006#if SK_SUPPORT_GPU
egdanielab527a52016-06-28 08:07:26 -07001007DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterMergeResultSize_Gpu, reporter, ctxInfo) {
bsalomon8b7451a2016-05-11 06:33:06 -07001008 test_imagefilter_merge_result_size(reporter, ctxInfo.grContext());
robertphillips4418dba2016-03-07 12:45:14 -08001009}
1010#endif
1011
robertphillipsa8d7f0b2014-08-29 08:03:56 -07001012static void draw_blurred_rect(SkCanvas* canvas) {
senorblanco837f5322014-07-14 10:19:54 -07001013 SkPaint filterPaint;
1014 filterPaint.setColor(SK_ColorWHITE);
robertphillips6e7025a2016-04-04 04:31:25 -07001015 filterPaint.setImageFilter(SkBlurImageFilter::Make(SkIntToScalar(8), 0, nullptr));
halcanary96fcdcc2015-08-27 07:41:13 -07001016 canvas->saveLayer(nullptr, &filterPaint);
senorblanco837f5322014-07-14 10:19:54 -07001017 SkPaint whitePaint;
1018 whitePaint.setColor(SK_ColorWHITE);
1019 canvas->drawRect(SkRect::Make(SkIRect::MakeWH(4, 4)), whitePaint);
1020 canvas->restore();
1021}
1022
robertphillipsa8d7f0b2014-08-29 08:03:56 -07001023static void draw_picture_clipped(SkCanvas* canvas, const SkRect& clipRect, const SkPicture* picture) {
senorblanco837f5322014-07-14 10:19:54 -07001024 canvas->save();
1025 canvas->clipRect(clipRect);
1026 canvas->drawPicture(picture);
1027 canvas->restore();
1028}
1029
1030DEF_TEST(ImageFilterDrawTiledBlurRTree, reporter) {
1031 // Check that the blur filter when recorded with RTree acceleration,
1032 // and drawn tiled (with subsequent clip rects) exactly
1033 // matches the same filter drawn with without RTree acceleration.
1034 // This tests that the "bleed" from the blur into the otherwise-blank
1035 // tiles is correctly rendered.
1036 // Tests pass by not asserting.
1037
1038 int width = 16, height = 8;
1039 SkBitmap result1, result2;
1040 result1.allocN32Pixels(width, height);
1041 result2.allocN32Pixels(width, height);
1042 SkCanvas canvas1(result1);
1043 SkCanvas canvas2(result2);
1044 int tileSize = 8;
1045
1046 canvas1.clear(0);
1047 canvas2.clear(0);
1048
1049 SkRTreeFactory factory;
1050
1051 SkPictureRecorder recorder1, recorder2;
1052 // The only difference between these two pictures is that one has RTree aceleration.
mtklein3f3b3d02014-12-01 11:47:08 -08001053 SkCanvas* recordingCanvas1 = recorder1.beginRecording(SkIntToScalar(width),
1054 SkIntToScalar(height),
halcanary96fcdcc2015-08-27 07:41:13 -07001055 nullptr, 0);
mtklein3f3b3d02014-12-01 11:47:08 -08001056 SkCanvas* recordingCanvas2 = recorder2.beginRecording(SkIntToScalar(width),
1057 SkIntToScalar(height),
robertphillipsa8d7f0b2014-08-29 08:03:56 -07001058 &factory, 0);
1059 draw_blurred_rect(recordingCanvas1);
1060 draw_blurred_rect(recordingCanvas2);
reedca2622b2016-03-18 07:25:55 -07001061 sk_sp<SkPicture> picture1(recorder1.finishRecordingAsPicture());
1062 sk_sp<SkPicture> picture2(recorder2.finishRecordingAsPicture());
senorblanco837f5322014-07-14 10:19:54 -07001063 for (int y = 0; y < height; y += tileSize) {
1064 for (int x = 0; x < width; x += tileSize) {
1065 SkRect tileRect = SkRect::Make(SkIRect::MakeXYWH(x, y, tileSize, tileSize));
reedca2622b2016-03-18 07:25:55 -07001066 draw_picture_clipped(&canvas1, tileRect, picture1.get());
1067 draw_picture_clipped(&canvas2, tileRect, picture2.get());
senorblanco837f5322014-07-14 10:19:54 -07001068 }
1069 }
1070 for (int y = 0; y < height; y++) {
1071 int diffs = memcmp(result1.getAddr32(0, y), result2.getAddr32(0, y), result1.rowBytes());
1072 REPORTER_ASSERT(reporter, !diffs);
1073 if (diffs) {
1074 break;
1075 }
1076 }
1077}
1078
senorblanco@chromium.org91957432014-05-01 14:03:41 +00001079DEF_TEST(ImageFilterMatrixConvolution, reporter) {
1080 // Check that a 1x3 filter does not cause a spurious assert.
1081 SkScalar kernel[3] = {
1082 SkIntToScalar( 1), SkIntToScalar( 1), SkIntToScalar( 1),
1083 };
1084 SkISize kernelSize = SkISize::Make(1, 3);
1085 SkScalar gain = SK_Scalar1, bias = 0;
1086 SkIPoint kernelOffset = SkIPoint::Make(0, 0);
1087
robertphillipsef6a47b2016-04-08 08:01:20 -07001088 sk_sp<SkImageFilter> filter(SkMatrixConvolutionImageFilter::Make(
1089 kernelSize, kernel,
1090 gain, bias, kernelOffset,
1091 SkMatrixConvolutionImageFilter::kRepeat_TileMode,
1092 false, nullptr));
senorblanco@chromium.org91957432014-05-01 14:03:41 +00001093
1094 SkBitmap result;
1095 int width = 16, height = 16;
1096 result.allocN32Pixels(width, height);
1097 SkCanvas canvas(result);
1098 canvas.clear(0);
1099
1100 SkPaint paint;
robertphillipsef6a47b2016-04-08 08:01:20 -07001101 paint.setImageFilter(std::move(filter));
senorblanco@chromium.org91957432014-05-01 14:03:41 +00001102 SkRect rect = SkRect::Make(SkIRect::MakeWH(width, height));
1103 canvas.drawRect(rect, paint);
1104}
1105
senorblanco@chromium.org8c7372b2014-05-02 19:13:11 +00001106DEF_TEST(ImageFilterMatrixConvolutionBorder, reporter) {
1107 // Check that a filter with borders outside the target bounds
1108 // does not crash.
1109 SkScalar kernel[3] = {
1110 0, 0, 0,
1111 };
1112 SkISize kernelSize = SkISize::Make(3, 1);
1113 SkScalar gain = SK_Scalar1, bias = 0;
1114 SkIPoint kernelOffset = SkIPoint::Make(2, 0);
1115
robertphillipsef6a47b2016-04-08 08:01:20 -07001116 sk_sp<SkImageFilter> filter(SkMatrixConvolutionImageFilter::Make(
1117 kernelSize, kernel, gain, bias, kernelOffset,
1118 SkMatrixConvolutionImageFilter::kClamp_TileMode,
1119 true, nullptr));
senorblanco@chromium.org8c7372b2014-05-02 19:13:11 +00001120
1121 SkBitmap result;
1122
1123 int width = 10, height = 10;
1124 result.allocN32Pixels(width, height);
1125 SkCanvas canvas(result);
1126 canvas.clear(0);
1127
1128 SkPaint filterPaint;
robertphillipsef6a47b2016-04-08 08:01:20 -07001129 filterPaint.setImageFilter(std::move(filter));
senorblanco@chromium.org8c7372b2014-05-02 19:13:11 +00001130 SkRect bounds = SkRect::MakeWH(1, 10);
1131 SkRect rect = SkRect::Make(SkIRect::MakeWH(width, height));
1132 SkPaint rectPaint;
1133 canvas.saveLayer(&bounds, &filterPaint);
1134 canvas.drawRect(rect, rectPaint);
1135 canvas.restore();
1136}
1137
robertphillips3e302272016-04-20 11:48:36 -07001138static void test_big_kernel(skiatest::Reporter* reporter, GrContext* context) {
robertphillipsdada4dd2016-04-13 04:54:36 -07001139 // Check that a kernel that is too big for the GPU still works
1140 SkScalar identityKernel[49] = {
1141 0, 0, 0, 0, 0, 0, 0,
1142 0, 0, 0, 0, 0, 0, 0,
1143 0, 0, 0, 0, 0, 0, 0,
1144 0, 0, 0, 1, 0, 0, 0,
1145 0, 0, 0, 0, 0, 0, 0,
1146 0, 0, 0, 0, 0, 0, 0,
1147 0, 0, 0, 0, 0, 0, 0
1148 };
1149 SkISize kernelSize = SkISize::Make(7, 7);
1150 SkScalar gain = SK_Scalar1, bias = 0;
1151 SkIPoint kernelOffset = SkIPoint::Make(0, 0);
1152
1153 sk_sp<SkImageFilter> filter(SkMatrixConvolutionImageFilter::Make(
1154 kernelSize, identityKernel, gain, bias, kernelOffset,
1155 SkMatrixConvolutionImageFilter::kClamp_TileMode,
1156 true, nullptr));
1157
robertphillips3e302272016-04-20 11:48:36 -07001158 sk_sp<SkSpecialImage> srcImg(create_empty_special_image(context, 100));
robertphillipsdada4dd2016-04-13 04:54:36 -07001159 SkASSERT(srcImg);
1160
1161 SkIPoint offset;
brianosman2a75e5d2016-09-22 07:15:37 -07001162 SkImageFilter::OutputProperties noColorSpace(nullptr);
1163 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeWH(100, 100), nullptr, noColorSpace);
robertphillipsdada4dd2016-04-13 04:54:36 -07001164 sk_sp<SkSpecialImage> resultImg(filter->filterImage(srcImg.get(), ctx, &offset));
1165 REPORTER_ASSERT(reporter, resultImg);
1166 REPORTER_ASSERT(reporter, SkToBool(context) == resultImg->isTextureBacked());
1167 REPORTER_ASSERT(reporter, resultImg->width() == 100 && resultImg->height() == 100);
1168 REPORTER_ASSERT(reporter, offset.fX == 0 && offset.fY == 0);
1169}
1170
1171DEF_TEST(ImageFilterMatrixConvolutionBigKernel, reporter) {
robertphillips3e302272016-04-20 11:48:36 -07001172 test_big_kernel(reporter, nullptr);
robertphillipsdada4dd2016-04-13 04:54:36 -07001173}
1174
1175#if SK_SUPPORT_GPU
egdanielab527a52016-06-28 08:07:26 -07001176DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterMatrixConvolutionBigKernel_Gpu,
1177 reporter, ctxInfo) {
bsalomon8b7451a2016-05-11 06:33:06 -07001178 test_big_kernel(reporter, ctxInfo.grContext());
robertphillipsdada4dd2016-04-13 04:54:36 -07001179}
1180#endif
1181
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +00001182DEF_TEST(ImageFilterCropRect, reporter) {
robertphillips3e302272016-04-20 11:48:36 -07001183 test_crop_rects(reporter, nullptr);
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +00001184}
1185
robertphillips4418dba2016-03-07 12:45:14 -08001186#if SK_SUPPORT_GPU
bsalomon68d91342016-04-12 09:59:58 -07001187DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterCropRect_Gpu, reporter, ctxInfo) {
bsalomon8b7451a2016-05-11 06:33:06 -07001188 test_crop_rects(reporter, ctxInfo.grContext());
robertphillips4418dba2016-03-07 12:45:14 -08001189}
1190#endif
1191
tfarina9ea53f92014-06-24 06:50:39 -07001192DEF_TEST(ImageFilterMatrix, reporter) {
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +00001193 SkBitmap temp;
mike@reedtribe.orgdeee4962014-02-13 14:41:43 +00001194 temp.allocN32Pixels(100, 100);
robertphillips9a53fd72015-06-22 09:46:59 -07001195 SkCanvas canvas(temp);
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +00001196 canvas.scale(SkIntToScalar(2), SkIntToScalar(2));
1197
1198 SkMatrix expectedMatrix = canvas.getTotalMatrix();
1199
commit-bot@chromium.org5fb2ce32014-04-17 23:35:06 +00001200 SkRTreeFactory factory;
1201 SkPictureRecorder recorder;
1202 SkCanvas* recordingCanvas = recorder.beginRecording(100, 100, &factory, 0);
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +00001203
1204 SkPaint paint;
robertphillips43c2ad42016-04-04 05:05:11 -07001205 paint.setImageFilter(MatrixTestImageFilter::Make(reporter, expectedMatrix));
halcanary96fcdcc2015-08-27 07:41:13 -07001206 recordingCanvas->saveLayer(nullptr, &paint);
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +00001207 SkPaint solidPaint;
1208 solidPaint.setColor(0xFFFFFFFF);
1209 recordingCanvas->save();
1210 recordingCanvas->scale(SkIntToScalar(10), SkIntToScalar(10));
1211 recordingCanvas->drawRect(SkRect::Make(SkIRect::MakeWH(100, 100)), solidPaint);
1212 recordingCanvas->restore(); // scale
1213 recordingCanvas->restore(); // saveLayer
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +00001214
reedca2622b2016-03-18 07:25:55 -07001215 canvas.drawPicture(recorder.finishRecordingAsPicture());
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +00001216}
1217
senorblanco3d822c22014-07-30 14:49:31 -07001218DEF_TEST(ImageFilterCrossProcessPictureImageFilter, reporter) {
senorblanco@chromium.org97f5fc62014-05-30 20:50:56 +00001219 SkRTreeFactory factory;
1220 SkPictureRecorder recorder;
1221 SkCanvas* recordingCanvas = recorder.beginRecording(1, 1, &factory, 0);
1222
1223 // Create an SkPicture which simply draws a green 1x1 rectangle.
1224 SkPaint greenPaint;
1225 greenPaint.setColor(SK_ColorGREEN);
1226 recordingCanvas->drawRect(SkRect::Make(SkIRect::MakeWH(1, 1)), greenPaint);
reedca2622b2016-03-18 07:25:55 -07001227 sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture());
senorblanco@chromium.org97f5fc62014-05-30 20:50:56 +00001228
1229 // Wrap that SkPicture in an SkPictureImageFilter.
robertphillips5ff17b12016-03-28 13:13:42 -07001230 sk_sp<SkImageFilter> imageFilter(SkPictureImageFilter::Make(picture));
senorblanco@chromium.org97f5fc62014-05-30 20:50:56 +00001231
1232 // Check that SkPictureImageFilter successfully serializes its contained
1233 // SkPicture when not in cross-process mode.
1234 SkPaint paint;
robertphillips5ff17b12016-03-28 13:13:42 -07001235 paint.setImageFilter(imageFilter);
senorblanco@chromium.org97f5fc62014-05-30 20:50:56 +00001236 SkPictureRecorder outerRecorder;
1237 SkCanvas* outerCanvas = outerRecorder.beginRecording(1, 1, &factory, 0);
1238 SkPaint redPaintWithFilter;
1239 redPaintWithFilter.setColor(SK_ColorRED);
robertphillips5ff17b12016-03-28 13:13:42 -07001240 redPaintWithFilter.setImageFilter(imageFilter);
senorblanco@chromium.org97f5fc62014-05-30 20:50:56 +00001241 outerCanvas->drawRect(SkRect::Make(SkIRect::MakeWH(1, 1)), redPaintWithFilter);
reedca2622b2016-03-18 07:25:55 -07001242 sk_sp<SkPicture> outerPicture(outerRecorder.finishRecordingAsPicture());
senorblanco@chromium.org97f5fc62014-05-30 20:50:56 +00001243
1244 SkBitmap bitmap;
1245 bitmap.allocN32Pixels(1, 1);
robertphillips9a53fd72015-06-22 09:46:59 -07001246 SkCanvas canvas(bitmap);
senorblanco@chromium.org97f5fc62014-05-30 20:50:56 +00001247
1248 // The result here should be green, since the filter replaces the primitive's red interior.
1249 canvas.clear(0x0);
robertphillips9b14f262014-06-04 05:40:44 -07001250 canvas.drawPicture(outerPicture);
senorblanco@chromium.org97f5fc62014-05-30 20:50:56 +00001251 uint32_t pixel = *bitmap.getAddr32(0, 0);
1252 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1253
1254 // Check that, for now, SkPictureImageFilter does not serialize or
1255 // deserialize its contained picture when the filter is serialized
1256 // cross-process. Do this by "laundering" it through SkValidatingReadBuffer.
robertphillips12fa47d2016-04-08 16:28:09 -07001257 sk_sp<SkData> data(SkValidatingSerializeFlattenable(imageFilter.get()));
Mike Reed5e257172016-11-01 11:22:05 -04001258 sk_sp<SkImageFilter> unflattenedFilter = SkValidatingDeserializeImageFilter(data->data(),
1259 data->size());
senorblanco@chromium.org97f5fc62014-05-30 20:50:56 +00001260
1261 redPaintWithFilter.setImageFilter(unflattenedFilter);
1262 SkPictureRecorder crossProcessRecorder;
1263 SkCanvas* crossProcessCanvas = crossProcessRecorder.beginRecording(1, 1, &factory, 0);
1264 crossProcessCanvas->drawRect(SkRect::Make(SkIRect::MakeWH(1, 1)), redPaintWithFilter);
reedca2622b2016-03-18 07:25:55 -07001265 sk_sp<SkPicture> crossProcessPicture(crossProcessRecorder.finishRecordingAsPicture());
senorblanco@chromium.org97f5fc62014-05-30 20:50:56 +00001266
1267 canvas.clear(0x0);
robertphillips9b14f262014-06-04 05:40:44 -07001268 canvas.drawPicture(crossProcessPicture);
senorblanco@chromium.org97f5fc62014-05-30 20:50:56 +00001269 pixel = *bitmap.getAddr32(0, 0);
hendrikw446ee672015-06-16 09:28:37 -07001270 // If the security precautions are enabled, the result here should not be green, since the
1271 // filter draws nothing.
mtklein2afbe232016-02-07 12:23:10 -08001272 REPORTER_ASSERT(reporter, SkPicture::PictureIOSecurityPrecautionsEnabled()
hendrikw446ee672015-06-16 09:28:37 -07001273 ? pixel != SK_ColorGREEN : pixel == SK_ColorGREEN);
senorblanco@chromium.org97f5fc62014-05-30 20:50:56 +00001274}
1275
robertphillips3e302272016-04-20 11:48:36 -07001276static void test_clipped_picture_imagefilter(skiatest::Reporter* reporter, GrContext* context) {
reedca2622b2016-03-18 07:25:55 -07001277 sk_sp<SkPicture> picture;
senorblanco3d822c22014-07-30 14:49:31 -07001278
robertphillips4418dba2016-03-07 12:45:14 -08001279 {
1280 SkRTreeFactory factory;
1281 SkPictureRecorder recorder;
1282 SkCanvas* recordingCanvas = recorder.beginRecording(1, 1, &factory, 0);
1283
1284 // Create an SkPicture which simply draws a green 1x1 rectangle.
1285 SkPaint greenPaint;
1286 greenPaint.setColor(SK_ColorGREEN);
1287 recordingCanvas->drawRect(SkRect::Make(SkIRect::MakeWH(1, 1)), greenPaint);
reedca2622b2016-03-18 07:25:55 -07001288 picture = recorder.finishRecordingAsPicture();
robertphillips4418dba2016-03-07 12:45:14 -08001289 }
1290
robertphillips3e302272016-04-20 11:48:36 -07001291 sk_sp<SkSpecialImage> srcImg(create_empty_special_image(context, 2));
senorblanco3d822c22014-07-30 14:49:31 -07001292
robertphillips5ff17b12016-03-28 13:13:42 -07001293 sk_sp<SkImageFilter> imageFilter(SkPictureImageFilter::Make(picture));
senorblanco3d822c22014-07-30 14:49:31 -07001294
senorblanco3d822c22014-07-30 14:49:31 -07001295 SkIPoint offset;
brianosman2a75e5d2016-09-22 07:15:37 -07001296 SkImageFilter::OutputProperties noColorSpace(nullptr);
1297 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeXYWH(1, 1, 1, 1), nullptr, noColorSpace);
robertphillips4418dba2016-03-07 12:45:14 -08001298
robertphillips2302de92016-03-24 07:26:32 -07001299 sk_sp<SkSpecialImage> resultImage(imageFilter->filterImage(srcImg.get(), ctx, &offset));
robertphillips4418dba2016-03-07 12:45:14 -08001300 REPORTER_ASSERT(reporter, !resultImage);
senorblanco3d822c22014-07-30 14:49:31 -07001301}
1302
robertphillips4418dba2016-03-07 12:45:14 -08001303DEF_TEST(ImageFilterClippedPictureImageFilter, reporter) {
robertphillips3e302272016-04-20 11:48:36 -07001304 test_clipped_picture_imagefilter(reporter, nullptr);
robertphillips4418dba2016-03-07 12:45:14 -08001305}
1306
1307#if SK_SUPPORT_GPU
bsalomon68d91342016-04-12 09:59:58 -07001308DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterClippedPictureImageFilter_Gpu, reporter, ctxInfo) {
bsalomon8b7451a2016-05-11 06:33:06 -07001309 test_clipped_picture_imagefilter(reporter, ctxInfo.grContext());
robertphillips4418dba2016-03-07 12:45:14 -08001310}
1311#endif
1312
tfarina9ea53f92014-06-24 06:50:39 -07001313DEF_TEST(ImageFilterEmptySaveLayer, reporter) {
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001314 // Even when there's an empty saveLayer()/restore(), ensure that an image
1315 // filter or color filter which affects transparent black still draws.
1316
1317 SkBitmap bitmap;
1318 bitmap.allocN32Pixels(10, 10);
robertphillips9a53fd72015-06-22 09:46:59 -07001319 SkCanvas canvas(bitmap);
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001320
1321 SkRTreeFactory factory;
1322 SkPictureRecorder recorder;
1323
robertphillips5605b562016-04-05 11:50:42 -07001324 sk_sp<SkColorFilter> green(SkColorFilter::MakeModeFilter(SK_ColorGREEN,
Mike Reed7d954ad2016-10-28 15:42:34 -04001325 SkBlendMode::kSrc));
robertphillips5605b562016-04-05 11:50:42 -07001326 sk_sp<SkImageFilter> imageFilter(SkColorFilterImageFilter::Make(green, nullptr));
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001327 SkPaint imageFilterPaint;
robertphillips5605b562016-04-05 11:50:42 -07001328 imageFilterPaint.setImageFilter(std::move(imageFilter));
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001329 SkPaint colorFilterPaint;
reedd053ce92016-03-22 10:17:23 -07001330 colorFilterPaint.setColorFilter(green);
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001331
1332 SkRect bounds = SkRect::MakeWH(10, 10);
1333
1334 SkCanvas* recordingCanvas = recorder.beginRecording(10, 10, &factory, 0);
1335 recordingCanvas->saveLayer(&bounds, &imageFilterPaint);
1336 recordingCanvas->restore();
reedca2622b2016-03-18 07:25:55 -07001337 sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture());
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001338
1339 canvas.clear(0);
robertphillips9b14f262014-06-04 05:40:44 -07001340 canvas.drawPicture(picture);
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001341 uint32_t pixel = *bitmap.getAddr32(0, 0);
1342 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1343
1344 recordingCanvas = recorder.beginRecording(10, 10, &factory, 0);
halcanary96fcdcc2015-08-27 07:41:13 -07001345 recordingCanvas->saveLayer(nullptr, &imageFilterPaint);
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001346 recordingCanvas->restore();
reedca2622b2016-03-18 07:25:55 -07001347 sk_sp<SkPicture> picture2(recorder.finishRecordingAsPicture());
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001348
1349 canvas.clear(0);
robertphillips9b14f262014-06-04 05:40:44 -07001350 canvas.drawPicture(picture2);
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001351 pixel = *bitmap.getAddr32(0, 0);
1352 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1353
1354 recordingCanvas = recorder.beginRecording(10, 10, &factory, 0);
1355 recordingCanvas->saveLayer(&bounds, &colorFilterPaint);
1356 recordingCanvas->restore();
reedca2622b2016-03-18 07:25:55 -07001357 sk_sp<SkPicture> picture3(recorder.finishRecordingAsPicture());
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001358
1359 canvas.clear(0);
robertphillips9b14f262014-06-04 05:40:44 -07001360 canvas.drawPicture(picture3);
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001361 pixel = *bitmap.getAddr32(0, 0);
1362 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1363}
1364
robertphillips9a53fd72015-06-22 09:46:59 -07001365static void test_huge_blur(SkCanvas* canvas, skiatest::Reporter* reporter) {
senorblanco@chromium.org09843fd2014-03-24 20:50:59 +00001366 SkBitmap bitmap;
1367 bitmap.allocN32Pixels(100, 100);
1368 bitmap.eraseARGB(0, 0, 0, 0);
1369
1370 // Check that a blur with an insane radius does not crash or assert.
senorblanco@chromium.org09843fd2014-03-24 20:50:59 +00001371 SkPaint paint;
robertphillips6e7025a2016-04-04 04:31:25 -07001372 paint.setImageFilter(SkBlurImageFilter::Make(SkIntToScalar(1<<30),
1373 SkIntToScalar(1<<30),
1374 nullptr));
reedda420b92015-12-16 08:38:15 -08001375 canvas->drawBitmap(bitmap, 0, 0, &paint);
senorblanco@chromium.org09843fd2014-03-24 20:50:59 +00001376}
1377
1378DEF_TEST(HugeBlurImageFilter, reporter) {
1379 SkBitmap temp;
1380 temp.allocN32Pixels(100, 100);
robertphillips9a53fd72015-06-22 09:46:59 -07001381 SkCanvas canvas(temp);
1382 test_huge_blur(&canvas, reporter);
senorblanco@chromium.org09843fd2014-03-24 20:50:59 +00001383}
1384
senorblanco21a465d2016-04-11 11:58:39 -07001385DEF_TEST(ImageFilterMatrixConvolutionSanityTest, reporter) {
senorblanco3a495202014-09-29 07:57:20 -07001386 SkScalar kernel[1] = { 0 };
1387 SkScalar gain = SK_Scalar1, bias = 0;
1388 SkIPoint kernelOffset = SkIPoint::Make(1, 1);
1389
halcanary96fcdcc2015-08-27 07:41:13 -07001390 // Check that an enormous (non-allocatable) kernel gives a nullptr filter.
robertphillipsef6a47b2016-04-08 08:01:20 -07001391 sk_sp<SkImageFilter> conv(SkMatrixConvolutionImageFilter::Make(
senorblanco3a495202014-09-29 07:57:20 -07001392 SkISize::Make(1<<30, 1<<30),
1393 kernel,
1394 gain,
1395 bias,
1396 kernelOffset,
1397 SkMatrixConvolutionImageFilter::kRepeat_TileMode,
robertphillipsef6a47b2016-04-08 08:01:20 -07001398 false,
1399 nullptr));
senorblanco3a495202014-09-29 07:57:20 -07001400
halcanary96fcdcc2015-08-27 07:41:13 -07001401 REPORTER_ASSERT(reporter, nullptr == conv.get());
senorblanco3a495202014-09-29 07:57:20 -07001402
halcanary96fcdcc2015-08-27 07:41:13 -07001403 // Check that a nullptr kernel gives a nullptr filter.
robertphillipsef6a47b2016-04-08 08:01:20 -07001404 conv = SkMatrixConvolutionImageFilter::Make(
senorblanco3a495202014-09-29 07:57:20 -07001405 SkISize::Make(1, 1),
halcanary96fcdcc2015-08-27 07:41:13 -07001406 nullptr,
senorblanco3a495202014-09-29 07:57:20 -07001407 gain,
1408 bias,
1409 kernelOffset,
1410 SkMatrixConvolutionImageFilter::kRepeat_TileMode,
robertphillipsef6a47b2016-04-08 08:01:20 -07001411 false,
1412 nullptr);
senorblanco3a495202014-09-29 07:57:20 -07001413
halcanary96fcdcc2015-08-27 07:41:13 -07001414 REPORTER_ASSERT(reporter, nullptr == conv.get());
senorblanco3a495202014-09-29 07:57:20 -07001415
halcanary96fcdcc2015-08-27 07:41:13 -07001416 // Check that a kernel width < 1 gives a nullptr filter.
robertphillipsef6a47b2016-04-08 08:01:20 -07001417 conv = SkMatrixConvolutionImageFilter::Make(
senorblanco3a495202014-09-29 07:57:20 -07001418 SkISize::Make(0, 1),
1419 kernel,
1420 gain,
1421 bias,
1422 kernelOffset,
1423 SkMatrixConvolutionImageFilter::kRepeat_TileMode,
robertphillipsef6a47b2016-04-08 08:01:20 -07001424 false,
1425 nullptr);
senorblanco3a495202014-09-29 07:57:20 -07001426
halcanary96fcdcc2015-08-27 07:41:13 -07001427 REPORTER_ASSERT(reporter, nullptr == conv.get());
senorblanco3a495202014-09-29 07:57:20 -07001428
halcanary96fcdcc2015-08-27 07:41:13 -07001429 // Check that kernel height < 1 gives a nullptr filter.
robertphillipsef6a47b2016-04-08 08:01:20 -07001430 conv = SkMatrixConvolutionImageFilter::Make(
senorblanco3a495202014-09-29 07:57:20 -07001431 SkISize::Make(1, -1),
1432 kernel,
1433 gain,
1434 bias,
1435 kernelOffset,
1436 SkMatrixConvolutionImageFilter::kRepeat_TileMode,
robertphillipsef6a47b2016-04-08 08:01:20 -07001437 false,
1438 nullptr);
senorblanco3a495202014-09-29 07:57:20 -07001439
halcanary96fcdcc2015-08-27 07:41:13 -07001440 REPORTER_ASSERT(reporter, nullptr == conv.get());
senorblanco3a495202014-09-29 07:57:20 -07001441}
1442
Mike Reedf1942192017-07-21 14:24:29 -04001443static void test_xfermode_cropped_input(SkSurface* surf, skiatest::Reporter* reporter) {
1444 auto canvas = surf->getCanvas();
robertphillips9a53fd72015-06-22 09:46:59 -07001445 canvas->clear(0);
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001446
1447 SkBitmap bitmap;
1448 bitmap.allocN32Pixels(1, 1);
1449 bitmap.eraseARGB(255, 255, 255, 255);
1450
robertphillips5605b562016-04-05 11:50:42 -07001451 sk_sp<SkColorFilter> green(SkColorFilter::MakeModeFilter(SK_ColorGREEN,
Mike Reed7d954ad2016-10-28 15:42:34 -04001452 SkBlendMode::kSrcIn));
robertphillips5605b562016-04-05 11:50:42 -07001453 sk_sp<SkImageFilter> greenFilter(SkColorFilterImageFilter::Make(green, nullptr));
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001454 SkImageFilter::CropRect cropRect(SkRect::MakeEmpty());
robertphillips5605b562016-04-05 11:50:42 -07001455 sk_sp<SkImageFilter> croppedOut(SkColorFilterImageFilter::Make(green, nullptr, &cropRect));
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001456
1457 // Check that an xfermode image filter whose input has been cropped out still draws the other
1458 // input. Also check that drawing with both inputs cropped out doesn't cause a GPU warning.
reed374772b2016-10-05 17:33:02 -07001459 SkBlendMode mode = SkBlendMode::kSrcOver;
robertphillips8c0326d2016-04-05 12:48:34 -07001460 sk_sp<SkImageFilter> xfermodeNoFg(SkXfermodeImageFilter::Make(mode, greenFilter,
1461 croppedOut, nullptr));
1462 sk_sp<SkImageFilter> xfermodeNoBg(SkXfermodeImageFilter::Make(mode, croppedOut,
1463 greenFilter, nullptr));
1464 sk_sp<SkImageFilter> xfermodeNoFgNoBg(SkXfermodeImageFilter::Make(mode, croppedOut,
1465 croppedOut, nullptr));
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001466
1467 SkPaint paint;
robertphillips8c0326d2016-04-05 12:48:34 -07001468 paint.setImageFilter(std::move(xfermodeNoFg));
reedda420b92015-12-16 08:38:15 -08001469 canvas->drawBitmap(bitmap, 0, 0, &paint); // drawSprite
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001470
1471 uint32_t pixel;
kkinnunena9d9a392015-03-06 07:16:00 -08001472 SkImageInfo info = SkImageInfo::Make(1, 1, kBGRA_8888_SkColorType, kUnpremul_SkAlphaType);
Mike Reedf1942192017-07-21 14:24:29 -04001473 surf->readPixels(info, &pixel, 4, 0, 0);
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001474 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1475
robertphillips8c0326d2016-04-05 12:48:34 -07001476 paint.setImageFilter(std::move(xfermodeNoBg));
reedda420b92015-12-16 08:38:15 -08001477 canvas->drawBitmap(bitmap, 0, 0, &paint); // drawSprite
Mike Reedf1942192017-07-21 14:24:29 -04001478 surf->readPixels(info, &pixel, 4, 0, 0);
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001479 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1480
robertphillips8c0326d2016-04-05 12:48:34 -07001481 paint.setImageFilter(std::move(xfermodeNoFgNoBg));
reedda420b92015-12-16 08:38:15 -08001482 canvas->drawBitmap(bitmap, 0, 0, &paint); // drawSprite
Mike Reedf1942192017-07-21 14:24:29 -04001483 surf->readPixels(info, &pixel, 4, 0, 0);
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001484 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1485}
1486
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001487DEF_TEST(ImageFilterNestedSaveLayer, reporter) {
1488 SkBitmap temp;
1489 temp.allocN32Pixels(50, 50);
robertphillips9a53fd72015-06-22 09:46:59 -07001490 SkCanvas canvas(temp);
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001491 canvas.clear(0x0);
1492
1493 SkBitmap bitmap;
1494 bitmap.allocN32Pixels(10, 10);
1495 bitmap.eraseColor(SK_ColorGREEN);
1496
1497 SkMatrix matrix;
1498 matrix.setScale(SkIntToScalar(2), SkIntToScalar(2));
1499 matrix.postTranslate(SkIntToScalar(-20), SkIntToScalar(-20));
robertphillipsae8c9332016-04-05 15:09:00 -07001500 sk_sp<SkImageFilter> matrixFilter(
1501 SkImageFilter::MakeMatrixFilter(matrix, kLow_SkFilterQuality, nullptr));
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001502
1503 // Test that saveLayer() with a filter nested inside another saveLayer() applies the
1504 // correct offset to the filter matrix.
1505 SkRect bounds1 = SkRect::MakeXYWH(10, 10, 30, 30);
halcanary96fcdcc2015-08-27 07:41:13 -07001506 canvas.saveLayer(&bounds1, nullptr);
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001507 SkPaint filterPaint;
robertphillipsae8c9332016-04-05 15:09:00 -07001508 filterPaint.setImageFilter(std::move(matrixFilter));
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001509 SkRect bounds2 = SkRect::MakeXYWH(20, 20, 10, 10);
1510 canvas.saveLayer(&bounds2, &filterPaint);
1511 SkPaint greenPaint;
1512 greenPaint.setColor(SK_ColorGREEN);
1513 canvas.drawRect(bounds2, greenPaint);
1514 canvas.restore();
1515 canvas.restore();
1516 SkPaint strokePaint;
1517 strokePaint.setStyle(SkPaint::kStroke_Style);
1518 strokePaint.setColor(SK_ColorRED);
1519
kkinnunena9d9a392015-03-06 07:16:00 -08001520 SkImageInfo info = SkImageInfo::Make(1, 1, kBGRA_8888_SkColorType, kUnpremul_SkAlphaType);
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001521 uint32_t pixel;
Mike Reedf1942192017-07-21 14:24:29 -04001522 temp.readPixels(info, &pixel, 4, 25, 25);
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001523 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1524
1525 // Test that drawSprite() with a filter nested inside a saveLayer() applies the
1526 // correct offset to the filter matrix.
1527 canvas.clear(0x0);
Mike Reedf1942192017-07-21 14:24:29 -04001528 temp.readPixels(info, &pixel, 4, 25, 25);
halcanary96fcdcc2015-08-27 07:41:13 -07001529 canvas.saveLayer(&bounds1, nullptr);
reedda420b92015-12-16 08:38:15 -08001530 canvas.drawBitmap(bitmap, 20, 20, &filterPaint); // drawSprite
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001531 canvas.restore();
1532
Mike Reedf1942192017-07-21 14:24:29 -04001533 temp.readPixels(info, &pixel, 4, 25, 25);
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001534 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1535}
1536
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001537DEF_TEST(XfermodeImageFilterCroppedInput, reporter) {
Mike Reedf1942192017-07-21 14:24:29 -04001538 test_xfermode_cropped_input(SkSurface::MakeRasterN32Premul(100, 100).get(), reporter);
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001539}
senorblanco@chromium.org09843fd2014-03-24 20:50:59 +00001540
robertphillips3e302272016-04-20 11:48:36 -07001541static void test_composed_imagefilter_offset(skiatest::Reporter* reporter, GrContext* context) {
1542 sk_sp<SkSpecialImage> srcImg(create_empty_special_image(context, 100));
ajuma5788faa2015-02-13 09:05:47 -08001543
1544 SkImageFilter::CropRect cropRect(SkRect::MakeXYWH(1, 0, 20, 20));
robertphillips51a315e2016-03-31 09:05:49 -07001545 sk_sp<SkImageFilter> offsetFilter(SkOffsetImageFilter::Make(0, 0, nullptr, &cropRect));
robertphillips6e7025a2016-04-04 04:31:25 -07001546 sk_sp<SkImageFilter> blurFilter(SkBlurImageFilter::Make(SK_Scalar1, SK_Scalar1,
1547 nullptr, &cropRect));
robertphillips491fb172016-03-30 12:32:58 -07001548 sk_sp<SkImageFilter> composedFilter(SkComposeImageFilter::Make(std::move(blurFilter),
1549 std::move(offsetFilter)));
ajuma5788faa2015-02-13 09:05:47 -08001550 SkIPoint offset;
brianosman2a75e5d2016-09-22 07:15:37 -07001551 SkImageFilter::OutputProperties noColorSpace(nullptr);
1552 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeWH(100, 100), nullptr, noColorSpace);
robertphillips4418dba2016-03-07 12:45:14 -08001553
robertphillips2302de92016-03-24 07:26:32 -07001554 sk_sp<SkSpecialImage> resultImg(composedFilter->filterImage(srcImg.get(), ctx, &offset));
robertphillips4418dba2016-03-07 12:45:14 -08001555 REPORTER_ASSERT(reporter, resultImg);
ajuma5788faa2015-02-13 09:05:47 -08001556 REPORTER_ASSERT(reporter, offset.fX == 1 && offset.fY == 0);
1557}
1558
robertphillips4418dba2016-03-07 12:45:14 -08001559DEF_TEST(ComposedImageFilterOffset, reporter) {
robertphillips3e302272016-04-20 11:48:36 -07001560 test_composed_imagefilter_offset(reporter, nullptr);
robertphillips4418dba2016-03-07 12:45:14 -08001561}
1562
1563#if SK_SUPPORT_GPU
bsalomon68d91342016-04-12 09:59:58 -07001564DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ComposedImageFilterOffset_Gpu, reporter, ctxInfo) {
bsalomon8b7451a2016-05-11 06:33:06 -07001565 test_composed_imagefilter_offset(reporter, ctxInfo.grContext());
robertphillips4418dba2016-03-07 12:45:14 -08001566}
1567#endif
1568
robertphillips3e302272016-04-20 11:48:36 -07001569static void test_composed_imagefilter_bounds(skiatest::Reporter* reporter, GrContext* context) {
jbroman17a65202016-03-21 08:38:58 -07001570 // The bounds passed to the inner filter must be filtered by the outer
1571 // filter, so that the inner filter produces the pixels that the outer
1572 // filter requires as input. This matters if the outer filter moves pixels.
1573 // Here, accounting for the outer offset is necessary so that the green
1574 // pixels of the picture are not clipped.
1575
1576 SkPictureRecorder recorder;
1577 SkCanvas* recordingCanvas = recorder.beginRecording(SkRect::MakeWH(200, 100));
1578 recordingCanvas->clipRect(SkRect::MakeXYWH(100, 0, 100, 100));
1579 recordingCanvas->clear(SK_ColorGREEN);
robertphillips491fb172016-03-30 12:32:58 -07001580 sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture());
robertphillips5ff17b12016-03-28 13:13:42 -07001581 sk_sp<SkImageFilter> pictureFilter(SkPictureImageFilter::Make(picture));
jbroman17a65202016-03-21 08:38:58 -07001582 SkImageFilter::CropRect cropRect(SkRect::MakeWH(100, 100));
robertphillips51a315e2016-03-31 09:05:49 -07001583 sk_sp<SkImageFilter> offsetFilter(SkOffsetImageFilter::Make(-100, 0, nullptr, &cropRect));
robertphillips491fb172016-03-30 12:32:58 -07001584 sk_sp<SkImageFilter> composedFilter(SkComposeImageFilter::Make(std::move(offsetFilter),
1585 std::move(pictureFilter)));
jbroman17a65202016-03-21 08:38:58 -07001586
robertphillips3e302272016-04-20 11:48:36 -07001587 sk_sp<SkSpecialImage> sourceImage(create_empty_special_image(context, 100));
brianosman2a75e5d2016-09-22 07:15:37 -07001588 SkImageFilter::OutputProperties noColorSpace(nullptr);
1589 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeWH(100, 100), nullptr, noColorSpace);
jbroman17a65202016-03-21 08:38:58 -07001590 SkIPoint offset;
1591 sk_sp<SkSpecialImage> result(composedFilter->filterImage(sourceImage.get(), ctx, &offset));
1592 REPORTER_ASSERT(reporter, offset.isZero());
1593 REPORTER_ASSERT(reporter, result);
1594 REPORTER_ASSERT(reporter, result->subset().size() == SkISize::Make(100, 100));
1595
1596 SkBitmap resultBM;
robertphillips64612512016-04-08 12:10:42 -07001597 REPORTER_ASSERT(reporter, result->getROPixels(&resultBM));
jbroman17a65202016-03-21 08:38:58 -07001598 REPORTER_ASSERT(reporter, resultBM.getColor(50, 50) == SK_ColorGREEN);
1599}
1600
1601DEF_TEST(ComposedImageFilterBounds, reporter) {
robertphillips3e302272016-04-20 11:48:36 -07001602 test_composed_imagefilter_bounds(reporter, nullptr);
jbroman17a65202016-03-21 08:38:58 -07001603}
1604
1605#if SK_SUPPORT_GPU
egdanielab527a52016-06-28 08:07:26 -07001606DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ComposedImageFilterBounds_Gpu, reporter, ctxInfo) {
bsalomon8b7451a2016-05-11 06:33:06 -07001607 test_composed_imagefilter_bounds(reporter, ctxInfo.grContext());
jbroman17a65202016-03-21 08:38:58 -07001608}
1609#endif
1610
robertphillips3e302272016-04-20 11:48:36 -07001611static void test_partial_crop_rect(skiatest::Reporter* reporter, GrContext* context) {
1612 sk_sp<SkSpecialImage> srcImg(create_empty_special_image(context, 100));
senorblanco24d2a7b2015-07-13 10:27:05 -07001613
1614 SkImageFilter::CropRect cropRect(SkRect::MakeXYWH(100, 0, 20, 30),
senorblancoed7cf272015-07-16 15:19:11 -07001615 SkImageFilter::CropRect::kHasWidth_CropEdge | SkImageFilter::CropRect::kHasHeight_CropEdge);
robertphillips5605b562016-04-05 11:50:42 -07001616 sk_sp<SkImageFilter> filter(make_grayscale(nullptr, &cropRect));
senorblanco24d2a7b2015-07-13 10:27:05 -07001617 SkIPoint offset;
brianosman2a75e5d2016-09-22 07:15:37 -07001618 SkImageFilter::OutputProperties noColorSpace(nullptr);
1619 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeWH(100, 100), nullptr, noColorSpace);
robertphillips4418dba2016-03-07 12:45:14 -08001620
robertphillips2302de92016-03-24 07:26:32 -07001621 sk_sp<SkSpecialImage> resultImg(filter->filterImage(srcImg.get(), ctx, &offset));
robertphillips4418dba2016-03-07 12:45:14 -08001622 REPORTER_ASSERT(reporter, resultImg);
1623
senorblanco24d2a7b2015-07-13 10:27:05 -07001624 REPORTER_ASSERT(reporter, offset.fX == 0);
1625 REPORTER_ASSERT(reporter, offset.fY == 0);
robertphillips4418dba2016-03-07 12:45:14 -08001626 REPORTER_ASSERT(reporter, resultImg->width() == 20);
1627 REPORTER_ASSERT(reporter, resultImg->height() == 30);
senorblanco24d2a7b2015-07-13 10:27:05 -07001628}
1629
senorblanco21a465d2016-04-11 11:58:39 -07001630DEF_TEST(ImageFilterPartialCropRect, reporter) {
robertphillips3e302272016-04-20 11:48:36 -07001631 test_partial_crop_rect(reporter, nullptr);
robertphillips4418dba2016-03-07 12:45:14 -08001632}
1633
1634#if SK_SUPPORT_GPU
bsalomon68d91342016-04-12 09:59:58 -07001635DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterPartialCropRect_Gpu, reporter, ctxInfo) {
bsalomon8b7451a2016-05-11 06:33:06 -07001636 test_partial_crop_rect(reporter, ctxInfo.grContext());
robertphillips4418dba2016-03-07 12:45:14 -08001637}
1638#endif
1639
senorblanco0abdf762015-08-20 11:10:41 -07001640DEF_TEST(ImageFilterCanComputeFastBounds, reporter) {
1641
robertphillips12fa47d2016-04-08 16:28:09 -07001642 {
1643 SkPoint3 location = SkPoint3::Make(0, 0, SK_Scalar1);
1644 sk_sp<SkImageFilter> lighting(SkLightingImageFilter::MakePointLitDiffuse(location,
1645 SK_ColorGREEN,
1646 0, 0, nullptr));
1647 REPORTER_ASSERT(reporter, !lighting->canComputeFastBounds());
1648 }
senorblanco0abdf762015-08-20 11:10:41 -07001649
senorblanco0abdf762015-08-20 11:10:41 -07001650 {
robertphillips6e7025a2016-04-04 04:31:25 -07001651 sk_sp<SkImageFilter> gray(make_grayscale(nullptr, nullptr));
1652 REPORTER_ASSERT(reporter, gray->canComputeFastBounds());
1653 {
1654 SkColorFilter* grayCF;
1655 REPORTER_ASSERT(reporter, gray->asAColorFilter(&grayCF));
1656 REPORTER_ASSERT(reporter, !grayCF->affectsTransparentBlack());
1657 grayCF->unref();
1658 }
1659 REPORTER_ASSERT(reporter, gray->canComputeFastBounds());
1660
1661 sk_sp<SkImageFilter> grayBlur(SkBlurImageFilter::Make(SK_Scalar1, SK_Scalar1,
1662 std::move(gray)));
1663 REPORTER_ASSERT(reporter, grayBlur->canComputeFastBounds());
senorblanco0abdf762015-08-20 11:10:41 -07001664 }
senorblanco0abdf762015-08-20 11:10:41 -07001665
robertphillips6e7025a2016-04-04 04:31:25 -07001666 {
1667 SkScalar greenMatrix[20] = { 0, 0, 0, 0, 0,
1668 0, 0, 0, 0, 1,
1669 0, 0, 0, 0, 0,
1670 0, 0, 0, 0, 1 };
1671 sk_sp<SkColorFilter> greenCF(SkColorFilter::MakeMatrixFilterRowMajor255(greenMatrix));
robertphillips5605b562016-04-05 11:50:42 -07001672 sk_sp<SkImageFilter> green(SkColorFilterImageFilter::Make(greenCF, nullptr));
senorblanco0abdf762015-08-20 11:10:41 -07001673
robertphillips6e7025a2016-04-04 04:31:25 -07001674 REPORTER_ASSERT(reporter, greenCF->affectsTransparentBlack());
1675 REPORTER_ASSERT(reporter, !green->canComputeFastBounds());
senorblanco0abdf762015-08-20 11:10:41 -07001676
robertphillips6e7025a2016-04-04 04:31:25 -07001677 sk_sp<SkImageFilter> greenBlur(SkBlurImageFilter::Make(SK_Scalar1, SK_Scalar1,
1678 std::move(green)));
1679 REPORTER_ASSERT(reporter, !greenBlur->canComputeFastBounds());
1680 }
senorblanco0abdf762015-08-20 11:10:41 -07001681
1682 uint8_t allOne[256], identity[256];
1683 for (int i = 0; i < 256; ++i) {
1684 identity[i] = i;
1685 allOne[i] = 255;
1686 }
1687
robertphillips5605b562016-04-05 11:50:42 -07001688 sk_sp<SkColorFilter> identityCF(SkTableColorFilter::MakeARGB(identity, identity,
1689 identity, allOne));
1690 sk_sp<SkImageFilter> identityFilter(SkColorFilterImageFilter::Make(identityCF, nullptr));
senorblanco0abdf762015-08-20 11:10:41 -07001691 REPORTER_ASSERT(reporter, !identityCF->affectsTransparentBlack());
1692 REPORTER_ASSERT(reporter, identityFilter->canComputeFastBounds());
1693
robertphillips5605b562016-04-05 11:50:42 -07001694 sk_sp<SkColorFilter> forceOpaqueCF(SkTableColorFilter::MakeARGB(allOne, identity,
1695 identity, identity));
1696 sk_sp<SkImageFilter> forceOpaque(SkColorFilterImageFilter::Make(forceOpaqueCF, nullptr));
senorblanco0abdf762015-08-20 11:10:41 -07001697 REPORTER_ASSERT(reporter, forceOpaqueCF->affectsTransparentBlack());
1698 REPORTER_ASSERT(reporter, !forceOpaque->canComputeFastBounds());
1699}
1700
fmalitacd56f812015-09-14 13:31:18 -07001701// Verify that SkImageSource survives serialization
1702DEF_TEST(ImageFilterImageSourceSerialization, reporter) {
reede8f30622016-03-23 18:59:25 -07001703 auto surface(SkSurface::MakeRasterN32Premul(10, 10));
fmalitacd56f812015-09-14 13:31:18 -07001704 surface->getCanvas()->clear(SK_ColorGREEN);
reed9ce9d672016-03-17 10:51:11 -07001705 sk_sp<SkImage> image(surface->makeImageSnapshot());
robertphillips549c8992016-04-01 09:28:51 -07001706 sk_sp<SkImageFilter> filter(SkImageSource::Make(std::move(image)));
fmalitacd56f812015-09-14 13:31:18 -07001707
robertphillips549c8992016-04-01 09:28:51 -07001708 sk_sp<SkData> data(SkValidatingSerializeFlattenable(filter.get()));
Mike Reed5e257172016-11-01 11:22:05 -04001709 sk_sp<SkImageFilter> unflattenedFilter = SkValidatingDeserializeImageFilter(data->data(),
1710 data->size());
fmalitacd56f812015-09-14 13:31:18 -07001711 REPORTER_ASSERT(reporter, unflattenedFilter);
1712
1713 SkBitmap bm;
1714 bm.allocN32Pixels(10, 10);
fmalita23cb88c2015-09-15 06:56:23 -07001715 bm.eraseColor(SK_ColorBLUE);
fmalitacd56f812015-09-14 13:31:18 -07001716 SkPaint paint;
1717 paint.setColor(SK_ColorRED);
1718 paint.setImageFilter(unflattenedFilter);
1719
1720 SkCanvas canvas(bm);
1721 canvas.drawRect(SkRect::MakeWH(10, 10), paint);
1722 REPORTER_ASSERT(reporter, *bm.getAddr32(0, 0) == SkPreMultiplyColor(SK_ColorGREEN));
1723}
1724
Leon Scroggins III4cdbf602017-09-28 14:33:57 -04001725DEF_TEST(ImageFilterImageSourceUninitialized, r) {
1726 sk_sp<SkData> data(GetResourceAsData("crbug769134.fil"));
1727 if (!data) {
1728 return;
1729 }
1730 sk_sp<SkImageFilter> unflattenedFilter = SkValidatingDeserializeImageFilter(data->data(),
1731 data->size());
1732 // This will fail. More importantly, msan will verify that we did not
1733 // compare against uninitialized memory.
1734 REPORTER_ASSERT(r, !unflattenedFilter);
1735}
1736
bsalomon45eefcf2016-01-05 08:39:28 -08001737static void test_large_blur_input(skiatest::Reporter* reporter, SkCanvas* canvas) {
1738 SkBitmap largeBmp;
1739 int largeW = 5000;
1740 int largeH = 5000;
1741#if SK_SUPPORT_GPU
1742 // If we're GPU-backed make the bitmap too large to be converted into a texture.
1743 if (GrContext* ctx = canvas->getGrContext()) {
1744 largeW = ctx->caps()->maxTextureSize() + 1;
1745 }
1746#endif
1747
1748 largeBmp.allocN32Pixels(largeW, largeH);
mtklein2afbe232016-02-07 12:23:10 -08001749 largeBmp.eraseColor(0);
bsalomon45eefcf2016-01-05 08:39:28 -08001750 if (!largeBmp.getPixels()) {
1751 ERRORF(reporter, "Failed to allocate large bmp.");
1752 return;
1753 }
1754
reed9ce9d672016-03-17 10:51:11 -07001755 sk_sp<SkImage> largeImage(SkImage::MakeFromBitmap(largeBmp));
bsalomon45eefcf2016-01-05 08:39:28 -08001756 if (!largeImage) {
1757 ERRORF(reporter, "Failed to create large image.");
1758 return;
1759 }
1760
robertphillips549c8992016-04-01 09:28:51 -07001761 sk_sp<SkImageFilter> largeSource(SkImageSource::Make(std::move(largeImage)));
bsalomon45eefcf2016-01-05 08:39:28 -08001762 if (!largeSource) {
1763 ERRORF(reporter, "Failed to create large SkImageSource.");
1764 return;
1765 }
1766
robertphillips6e7025a2016-04-04 04:31:25 -07001767 sk_sp<SkImageFilter> blur(SkBlurImageFilter::Make(10.f, 10.f, std::move(largeSource)));
bsalomon45eefcf2016-01-05 08:39:28 -08001768 if (!blur) {
1769 ERRORF(reporter, "Failed to create SkBlurImageFilter.");
1770 return;
1771 }
1772
1773 SkPaint paint;
robertphillips549c8992016-04-01 09:28:51 -07001774 paint.setImageFilter(std::move(blur));
bsalomon45eefcf2016-01-05 08:39:28 -08001775
1776 // This should not crash (http://crbug.com/570479).
1777 canvas->drawRect(SkRect::MakeIWH(largeW, largeH), paint);
1778}
1779
senorblanco21a465d2016-04-11 11:58:39 -07001780DEF_TEST(ImageFilterBlurLargeImage, reporter) {
reede8f30622016-03-23 18:59:25 -07001781 auto surface(SkSurface::MakeRaster(SkImageInfo::MakeN32Premul(100, 100)));
bsalomon45eefcf2016-01-05 08:39:28 -08001782 test_large_blur_input(reporter, surface->getCanvas());
1783}
1784
senorblanco5878dbd2016-05-19 14:50:29 -07001785static void test_make_with_filter(skiatest::Reporter* reporter, GrContext* context) {
Robert Phillipsa5fdc972017-02-18 16:58:09 -05001786 sk_sp<SkSurface> surface(create_surface(context, 192, 128));
senorblanco5878dbd2016-05-19 14:50:29 -07001787 surface->getCanvas()->clear(SK_ColorRED);
1788 SkPaint bluePaint;
1789 bluePaint.setColor(SK_ColorBLUE);
1790 SkIRect subset = SkIRect::MakeXYWH(25, 20, 50, 50);
1791 surface->getCanvas()->drawRect(SkRect::Make(subset), bluePaint);
1792 sk_sp<SkImage> sourceImage = surface->makeImageSnapshot();
1793
1794 sk_sp<SkImageFilter> filter = make_grayscale(nullptr, nullptr);
1795 SkIRect clipBounds = SkIRect::MakeXYWH(30, 35, 100, 100);
1796 SkIRect outSubset;
1797 SkIPoint offset;
1798 sk_sp<SkImage> result;
1799
1800 result = sourceImage->makeWithFilter(nullptr, subset, clipBounds, &outSubset, &offset);
1801 REPORTER_ASSERT(reporter, !result);
1802
1803 result = sourceImage->makeWithFilter(filter.get(), subset, clipBounds, nullptr, &offset);
1804 REPORTER_ASSERT(reporter, !result);
1805
1806 result = sourceImage->makeWithFilter(filter.get(), subset, clipBounds, &outSubset, nullptr);
1807 REPORTER_ASSERT(reporter, !result);
1808
1809 SkIRect bigSubset = SkIRect::MakeXYWH(-10000, -10000, 20000, 20000);
1810 result = sourceImage->makeWithFilter(filter.get(), bigSubset, clipBounds, &outSubset, &offset);
1811 REPORTER_ASSERT(reporter, !result);
1812
1813 SkIRect empty = SkIRect::MakeEmpty();
1814 result = sourceImage->makeWithFilter(filter.get(), empty, clipBounds, &outSubset, &offset);
1815 REPORTER_ASSERT(reporter, !result);
1816
1817 result = sourceImage->makeWithFilter(filter.get(), subset, empty, &outSubset, &offset);
1818 REPORTER_ASSERT(reporter, !result);
1819
1820 SkIRect leftField = SkIRect::MakeXYWH(-1000, 0, 100, 100);
1821 result = sourceImage->makeWithFilter(filter.get(), subset, leftField, &outSubset, &offset);
1822 REPORTER_ASSERT(reporter, !result);
1823
1824 result = sourceImage->makeWithFilter(filter.get(), subset, clipBounds, &outSubset, &offset);
1825
1826 REPORTER_ASSERT(reporter, result);
1827 REPORTER_ASSERT(reporter, result->bounds().contains(outSubset));
1828 SkIRect destRect = SkIRect::MakeXYWH(offset.x(), offset.y(),
1829 outSubset.width(), outSubset.height());
1830 REPORTER_ASSERT(reporter, clipBounds.contains(destRect));
Robert Phillipsa5fdc972017-02-18 16:58:09 -05001831
1832 // In GPU-mode, this case creates a special image with a backing size that differs from
1833 // the content size
1834 {
1835 clipBounds.setXYWH(0, 0, 170, 100);
1836 subset.setXYWH(0, 0, 160, 90);
1837
1838 filter = SkXfermodeImageFilter::Make(SkBlendMode::kSrc, nullptr);
1839 result = sourceImage->makeWithFilter(filter.get(), subset, clipBounds, &outSubset, &offset);
1840 REPORTER_ASSERT(reporter, result);
1841 }
senorblanco5878dbd2016-05-19 14:50:29 -07001842}
1843
1844DEF_TEST(ImageFilterMakeWithFilter, reporter) {
1845 test_make_with_filter(reporter, nullptr);
1846}
1847
1848#if SK_SUPPORT_GPU
1849DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterMakeWithFilter_Gpu, reporter, ctxInfo) {
1850 test_make_with_filter(reporter, ctxInfo.grContext());
1851}
1852#endif
1853
senorblanco@chromium.org58d14662014-02-03 22:36:39 +00001854#if SK_SUPPORT_GPU
reed4a8126e2014-09-22 07:29:03 -07001855
bsalomon68d91342016-04-12 09:59:58 -07001856DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterHugeBlur_Gpu, reporter, ctxInfo) {
robertphillipsefbffed2015-06-22 12:06:08 -07001857
bsalomon8b7451a2016-05-11 06:33:06 -07001858 sk_sp<SkSurface> surf(SkSurface::MakeRenderTarget(ctxInfo.grContext(),
robertphillips3e302272016-04-20 11:48:36 -07001859 SkBudgeted::kNo,
1860 SkImageInfo::MakeN32Premul(100, 100)));
robertphillips9a53fd72015-06-22 09:46:59 -07001861
robertphillips3e302272016-04-20 11:48:36 -07001862
1863 SkCanvas* canvas = surf->getCanvas();
1864
1865 test_huge_blur(canvas, reporter);
senorblanco@chromium.org09843fd2014-03-24 20:50:59 +00001866}
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001867
egdanielab527a52016-06-28 08:07:26 -07001868DEF_GPUTEST_FOR_RENDERING_CONTEXTS(XfermodeImageFilterCroppedInput_Gpu, reporter, ctxInfo) {
Brian Salomon8996e182017-07-05 17:01:48 -04001869 sk_sp<SkSurface> surf(SkSurface::MakeRenderTarget(
1870 ctxInfo.grContext(),
1871 SkBudgeted::kNo,
1872 SkImageInfo::Make(1, 1, kRGBA_8888_SkColorType, kPremul_SkAlphaType)));
robertphillips3e302272016-04-20 11:48:36 -07001873
Mike Reedf1942192017-07-21 14:24:29 -04001874 test_xfermode_cropped_input(surf.get(), reporter);
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001875}
senorblanco32673b92014-09-09 09:15:04 -07001876
egdanielab527a52016-06-28 08:07:26 -07001877DEF_GPUTEST_FOR_ALL_CONTEXTS(ImageFilterBlurLargeImage_Gpu, reporter, ctxInfo) {
Brian Salomon8996e182017-07-05 17:01:48 -04001878 auto surface(SkSurface::MakeRenderTarget(
1879 ctxInfo.grContext(), SkBudgeted::kYes,
1880 SkImageInfo::Make(100, 100, kRGBA_8888_SkColorType, kPremul_SkAlphaType)));
bsalomon45eefcf2016-01-05 08:39:28 -08001881 test_large_blur_input(reporter, surface->getCanvas());
1882}
senorblanco@chromium.org58d14662014-02-03 22:36:39 +00001883#endif
reedbb34a8a2016-04-23 15:19:07 -07001884
1885/*
1886 * Test that colorfilterimagefilter does not require its CTM to be decomposed when it has more
1887 * than just scale/translate, but that other filters do.
1888 */
reed96a04f32016-04-25 09:25:15 -07001889DEF_TEST(ImageFilterComplexCTM, reporter) {
reedbb34a8a2016-04-23 15:19:07 -07001890 // just need a colorfilter to exercise the corresponding imagefilter
Mike Reed7d954ad2016-10-28 15:42:34 -04001891 sk_sp<SkColorFilter> cf = SkColorFilter::MakeModeFilter(SK_ColorRED, SkBlendMode::kSrcATop);
reed96a04f32016-04-25 09:25:15 -07001892 sk_sp<SkImageFilter> cfif = SkColorFilterImageFilter::Make(cf, nullptr); // can handle
1893 sk_sp<SkImageFilter> blif = SkBlurImageFilter::Make(3, 3, nullptr); // cannot handle
reedbb34a8a2016-04-23 15:19:07 -07001894
1895 struct {
1896 sk_sp<SkImageFilter> fFilter;
1897 bool fExpectCanHandle;
1898 } recs[] = {
1899 { cfif, true },
1900 { SkColorFilterImageFilter::Make(cf, cfif), true },
Mike Reed0bdaf052017-06-18 23:35:57 -04001901 { SkMergeImageFilter::Make(cfif, cfif), true },
reed96a04f32016-04-25 09:25:15 -07001902 { SkComposeImageFilter::Make(cfif, cfif), true },
1903
reedbb34a8a2016-04-23 15:19:07 -07001904 { blif, false },
reed96a04f32016-04-25 09:25:15 -07001905 { SkBlurImageFilter::Make(3, 3, cfif), false },
reedbb34a8a2016-04-23 15:19:07 -07001906 { SkColorFilterImageFilter::Make(cf, blif), false },
Mike Reed0bdaf052017-06-18 23:35:57 -04001907 { SkMergeImageFilter::Make(cfif, blif), false },
reed96a04f32016-04-25 09:25:15 -07001908 { SkComposeImageFilter::Make(blif, cfif), false },
reedbb34a8a2016-04-23 15:19:07 -07001909 };
liyuqianbfebe222016-11-14 11:17:16 -08001910
reedbb34a8a2016-04-23 15:19:07 -07001911 for (const auto& rec : recs) {
reed96a04f32016-04-25 09:25:15 -07001912 const bool canHandle = rec.fFilter->canHandleComplexCTM();
reedbb34a8a2016-04-23 15:19:07 -07001913 REPORTER_ASSERT(reporter, canHandle == rec.fExpectCanHandle);
1914 }
1915}
Florin Malita08252ec2017-07-06 12:48:15 -04001916
1917// Test that transforming the filter DAG doesn't clone shared nodes multiple times.
1918DEF_TEST(ImageFilterColorSpaceDAG, reporter) {
1919
1920 // Helper for counting makeColorSpace() clones.
1921 class TestFilter final : public SkImageFilter {
1922 public:
1923 TestFilter() : INHERITED(nullptr, 0, nullptr) {}
1924
1925#ifndef SK_IGNORE_TO_STRING
1926 void toString(SkString*) const override {}
1927#endif
1928 Factory getFactory() const override { return nullptr; }
1929
1930 size_t cloneCount() const { return fCloneCount; }
1931
1932 protected:
1933 sk_sp<SkSpecialImage> onFilterImage(SkSpecialImage* src, const Context&,
1934 SkIPoint* offset) const override {
1935 return nullptr;
1936 }
1937 sk_sp<SkImageFilter> onMakeColorSpace(SkColorSpaceXformer*) const override {
1938 fCloneCount++;
1939 return sk_ref_sp(const_cast<TestFilter*>(this));
1940 }
1941
1942 private:
1943 typedef SkImageFilter INHERITED;
1944
1945 mutable size_t fCloneCount = 0;
1946 };
1947
1948 auto filter = sk_make_sp<TestFilter>();
1949 REPORTER_ASSERT(reporter, filter->cloneCount() == 0u);
1950
1951 // Build a DAG referencing the filter twice.
1952 auto complexFilter = SkMergeImageFilter::Make(filter, SkOffsetImageFilter::Make(1, 1, filter));
1953 REPORTER_ASSERT(reporter, filter->cloneCount() == 0u);
1954
1955 auto xformer = SkColorSpaceXformer::Make(SkColorSpace::MakeSRGB());
1956 auto xformedFilter = xformer->apply(complexFilter.get());
1957
Florin Malita39e08552017-07-06 14:16:18 -04001958 REPORTER_ASSERT(reporter, filter->cloneCount() == 1u);
Florin Malita08252ec2017-07-06 12:48:15 -04001959}
Xianzhu Wang0fa353c2017-08-25 16:27:04 -07001960
Xianzhu Wangb4496662017-09-25 10:26:40 -07001961// Test SkXfermodeImageFilter::filterBounds with different blending modes.
Xianzhu Wang0fa353c2017-08-25 16:27:04 -07001962DEF_TEST(XfermodeImageFilterBounds, reporter) {
1963 SkIRect background_rect = SkIRect::MakeXYWH(0, 0, 100, 100);
1964 SkIRect foreground_rect = SkIRect::MakeXYWH(50, 50, 100, 100);
1965 sk_sp<SkImageFilter> background(new FixedBoundsImageFilter(background_rect));
1966 sk_sp<SkImageFilter> foreground(new FixedBoundsImageFilter(foreground_rect));
1967
1968 const int kModeCount = static_cast<int>(SkBlendMode::kLastMode) + 1;
1969 SkIRect expectedBounds[kModeCount];
1970 // Expect union of input rects by default.
1971 for (int i = 0; i < kModeCount; ++i) {
1972 expectedBounds[i] = background_rect;
1973 expectedBounds[i].join(foreground_rect);
1974 }
1975
1976 SkIRect intersection = background_rect;
1977 intersection.intersect(foreground_rect);
1978 expectedBounds[static_cast<int>(SkBlendMode::kClear)] = SkIRect::MakeEmpty();
1979 expectedBounds[static_cast<int>(SkBlendMode::kSrc)] = foreground_rect;
1980 expectedBounds[static_cast<int>(SkBlendMode::kDst)] = background_rect;
1981 expectedBounds[static_cast<int>(SkBlendMode::kSrcIn)] = intersection;
1982 expectedBounds[static_cast<int>(SkBlendMode::kDstIn)] = intersection;
1983 expectedBounds[static_cast<int>(SkBlendMode::kSrcATop)] = background_rect;
1984 expectedBounds[static_cast<int>(SkBlendMode::kDstATop)] = foreground_rect;
1985
1986 // The value of this variable doesn't matter because we use inputs with fixed bounds.
1987 SkIRect src = SkIRect::MakeXYWH(11, 22, 33, 44);
1988 for (int i = 0; i < kModeCount; ++i) {
1989 sk_sp<SkImageFilter> xfermode(SkXfermodeImageFilter::Make(static_cast<SkBlendMode>(i),
1990 background, foreground, nullptr));
1991 auto bounds =
1992 xfermode->filterBounds(src, SkMatrix::I(), SkImageFilter::kForward_MapDirection);
1993 REPORTER_ASSERT(reporter, bounds == expectedBounds[i]);
1994 }
1995
1996 // Test empty intersection.
1997 sk_sp<SkImageFilter> background2(new FixedBoundsImageFilter(SkIRect::MakeXYWH(0, 0, 20, 20)));
1998 sk_sp<SkImageFilter> foreground2(new FixedBoundsImageFilter(SkIRect::MakeXYWH(40, 40, 50, 50)));
1999 sk_sp<SkImageFilter> xfermode(SkXfermodeImageFilter::Make(
2000 SkBlendMode::kSrcIn, std::move(background2), std::move(foreground2), nullptr));
2001 auto bounds = xfermode->filterBounds(src, SkMatrix::I(), SkImageFilter::kForward_MapDirection);
2002 REPORTER_ASSERT(reporter, bounds.isEmpty());
2003}
2004
2005static void test_arithmetic_bounds(skiatest::Reporter* reporter, float k1, float k2, float k3,
2006 float k4, sk_sp<SkImageFilter> background,
2007 sk_sp<SkImageFilter> foreground,
2008 const SkImageFilter::CropRect* crop, const SkIRect& expected) {
2009 sk_sp<SkImageFilter> arithmetic(
2010 SkArithmeticImageFilter::Make(k1, k2, k3, k4, false, background, foreground, crop));
2011 // The value of the input rect doesn't matter because we use inputs with fixed bounds.
2012 SkIRect bounds = arithmetic->filterBounds(SkIRect::MakeXYWH(11, 22, 33, 44), SkMatrix::I(),
2013 SkImageFilter::kForward_MapDirection);
2014 REPORTER_ASSERT(reporter, expected == bounds);
2015}
2016
2017static void test_arithmetic_combinations(skiatest::Reporter* reporter, float v) {
2018 SkIRect background_rect = SkIRect::MakeXYWH(0, 0, 100, 100);
2019 SkIRect foreground_rect = SkIRect::MakeXYWH(50, 50, 100, 100);
2020 sk_sp<SkImageFilter> background(new FixedBoundsImageFilter(background_rect));
2021 sk_sp<SkImageFilter> foreground(new FixedBoundsImageFilter(foreground_rect));
2022
2023 SkIRect union_rect = background_rect;
2024 union_rect.join(foreground_rect);
2025 SkIRect intersection = background_rect;
2026 intersection.intersect(foreground_rect);
2027
2028 test_arithmetic_bounds(reporter, 0, 0, 0, 0, background, foreground, nullptr,
2029 SkIRect::MakeEmpty());
2030 test_arithmetic_bounds(reporter, 0, 0, 0, v, background, foreground, nullptr, union_rect);
2031 test_arithmetic_bounds(reporter, 0, 0, v, 0, background, foreground, nullptr, background_rect);
2032 test_arithmetic_bounds(reporter, 0, 0, v, v, background, foreground, nullptr, union_rect);
2033 test_arithmetic_bounds(reporter, 0, v, 0, 0, background, foreground, nullptr, foreground_rect);
2034 test_arithmetic_bounds(reporter, 0, v, 0, v, background, foreground, nullptr, union_rect);
2035 test_arithmetic_bounds(reporter, 0, v, v, 0, background, foreground, nullptr, union_rect);
2036 test_arithmetic_bounds(reporter, 0, v, v, v, background, foreground, nullptr, union_rect);
2037 test_arithmetic_bounds(reporter, v, 0, 0, 0, background, foreground, nullptr, intersection);
2038 test_arithmetic_bounds(reporter, v, 0, 0, v, background, foreground, nullptr, union_rect);
2039 test_arithmetic_bounds(reporter, v, 0, v, 0, background, foreground, nullptr, background_rect);
2040 test_arithmetic_bounds(reporter, v, 0, v, v, background, foreground, nullptr, union_rect);
2041 test_arithmetic_bounds(reporter, v, v, 0, 0, background, foreground, nullptr, foreground_rect);
2042 test_arithmetic_bounds(reporter, v, v, 0, v, background, foreground, nullptr, union_rect);
2043 test_arithmetic_bounds(reporter, v, v, v, 0, background, foreground, nullptr, union_rect);
2044 test_arithmetic_bounds(reporter, v, v, v, v, background, foreground, nullptr, union_rect);
2045
2046 // Test with crop. When k4 is non-zero, the result is expected to be crop_rect
2047 // regardless of inputs because the filter affects the whole crop area.
2048 SkIRect crop_rect = SkIRect::MakeXYWH(-111, -222, 333, 444);
2049 SkImageFilter::CropRect crop(SkRect::Make(crop_rect));
2050 test_arithmetic_bounds(reporter, 0, 0, 0, 0, background, foreground, &crop,
2051 SkIRect::MakeEmpty());
2052 test_arithmetic_bounds(reporter, 0, 0, 0, v, background, foreground, &crop, crop_rect);
2053 test_arithmetic_bounds(reporter, 0, 0, v, 0, background, foreground, &crop, background_rect);
2054 test_arithmetic_bounds(reporter, 0, 0, v, v, background, foreground, &crop, crop_rect);
2055 test_arithmetic_bounds(reporter, 0, v, 0, 0, background, foreground, &crop, foreground_rect);
2056 test_arithmetic_bounds(reporter, 0, v, 0, v, background, foreground, &crop, crop_rect);
2057 test_arithmetic_bounds(reporter, 0, v, v, 0, background, foreground, &crop, union_rect);
2058 test_arithmetic_bounds(reporter, 0, v, v, v, background, foreground, &crop, crop_rect);
2059 test_arithmetic_bounds(reporter, v, 0, 0, 0, background, foreground, &crop, intersection);
2060 test_arithmetic_bounds(reporter, v, 0, 0, v, background, foreground, &crop, crop_rect);
2061 test_arithmetic_bounds(reporter, v, 0, v, 0, background, foreground, &crop, background_rect);
2062 test_arithmetic_bounds(reporter, v, 0, v, v, background, foreground, &crop, crop_rect);
2063 test_arithmetic_bounds(reporter, v, v, 0, 0, background, foreground, &crop, foreground_rect);
2064 test_arithmetic_bounds(reporter, v, v, 0, v, background, foreground, &crop, crop_rect);
2065 test_arithmetic_bounds(reporter, v, v, v, 0, background, foreground, &crop, union_rect);
2066 test_arithmetic_bounds(reporter, v, v, v, v, background, foreground, &crop, crop_rect);
2067}
2068
Xianzhu Wangb4496662017-09-25 10:26:40 -07002069// Test SkArithmeticImageFilter::filterBounds with different blending modes.
Xianzhu Wang0fa353c2017-08-25 16:27:04 -07002070DEF_TEST(ArithmeticImageFilterBounds, reporter) {
2071 test_arithmetic_combinations(reporter, 1);
2072 test_arithmetic_combinations(reporter, 0.5);
2073}
Xianzhu Wangb4496662017-09-25 10:26:40 -07002074
2075// Test SkImageSource::filterBounds.
2076DEF_TEST(ImageSourceBounds, reporter) {
2077 sk_sp<SkImage> image(SkImage::MakeFromBitmap(make_gradient_circle(64, 64)));
2078 // Default src and dst rects.
2079 sk_sp<SkImageFilter> source1(SkImageSource::Make(image));
2080 SkIRect imageBounds = SkIRect::MakeWH(64, 64);
2081 SkIRect input(SkIRect::MakeXYWH(10, 20, 30, 40));
2082 REPORTER_ASSERT(reporter,
2083 imageBounds == source1->filterBounds(input, SkMatrix::I(),
2084 SkImageFilter::kForward_MapDirection));
2085 REPORTER_ASSERT(reporter,
2086 input == source1->filterBounds(input, SkMatrix::I(),
2087 SkImageFilter::kReverse_MapDirection));
2088 SkMatrix scale(SkMatrix::MakeScale(2));
2089 SkIRect scaledBounds = SkIRect::MakeWH(128, 128);
2090 REPORTER_ASSERT(reporter,
2091 scaledBounds == source1->filterBounds(input, scale,
2092 SkImageFilter::kForward_MapDirection));
2093 REPORTER_ASSERT(
2094 reporter,
2095 input == source1->filterBounds(input, scale, SkImageFilter::kReverse_MapDirection));
2096
2097 // Specified src and dst rects.
2098 SkRect src(SkRect::MakeXYWH(0.5, 0.5, 100.5, 100.5));
2099 SkRect dst(SkRect::MakeXYWH(-10.5, -10.5, 120.5, 120.5));
2100 sk_sp<SkImageFilter> source2(SkImageSource::Make(image, src, dst, kMedium_SkFilterQuality));
2101 REPORTER_ASSERT(reporter,
2102 dst.roundOut() == source2->filterBounds(input, SkMatrix::I(),
2103 SkImageFilter::kForward_MapDirection));
2104 REPORTER_ASSERT(reporter,
2105 input == source2->filterBounds(input, SkMatrix::I(),
2106 SkImageFilter::kReverse_MapDirection));
2107 scale.mapRect(&dst);
2108 scale.mapRect(&src);
2109 REPORTER_ASSERT(reporter,
2110 dst.roundOut() == source2->filterBounds(input, scale,
2111 SkImageFilter::kForward_MapDirection));
2112 REPORTER_ASSERT(
2113 reporter,
2114 input == source2->filterBounds(input, scale, SkImageFilter::kReverse_MapDirection));
2115}