blob: ecf8847e229f6b811e407887d0452aa0ab4beef8 [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.org0a5c2332014-04-29 15:20:39 +000018#include "SkGradientShader.h"
fmalita5598b632015-09-15 11:26:13 -070019#include "SkImage.h"
Cary Clark60aaeb22017-11-03 08:06:09 -040020#include "SkImageFilterPriv.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
Brian Salomonc7fe0f72018-05-11 10:14:21 -040045#include "GrCaps.h"
kkinnunen15302832015-12-01 04:35:26 -080046#include "GrContext.h"
Brian Salomonc7fe0f72018-05-11 10:14:21 -040047#include "GrContextPriv.h"
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +000048
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
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +000060protected:
robertphillips4ba94e22016-04-04 12:07:47 -070061 sk_sp<SkSpecialImage> onFilterImage(SkSpecialImage* source, const Context& ctx,
62 SkIPoint* offset) const override {
robertphillips43c2ad42016-04-04 05:05:11 -070063 REPORTER_ASSERT(fReporter, ctx.ctm() == fExpectedMatrix);
robertphillips4ba94e22016-04-04 12:07:47 -070064 offset->fX = offset->fY = 0;
65 return sk_ref_sp<SkSpecialImage>(source);
robertphillips43c2ad42016-04-04 05:05:11 -070066 }
Matt Sarett62745a82017-04-17 11:57:29 -040067 sk_sp<SkImageFilter> onMakeColorSpace(SkColorSpaceXformer*) const override {
68 return sk_ref_sp(const_cast<MatrixTestImageFilter*>(this));
69 }
robertphillips43c2ad42016-04-04 05:05:11 -070070
mtklein36352bf2015-03-25 18:17:31 -070071 void flatten(SkWriteBuffer& buffer) const override {
brianosman18f13f32016-05-02 07:51:08 -070072 SkDEBUGFAIL("Should never get here");
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +000073 }
74
75private:
Mike Klein4fee3232018-10-18 17:27:16 -040076 SK_FLATTENABLE_HOOKS(MatrixTestImageFilter)
77
robertphillips43c2ad42016-04-04 05:05:11 -070078 MatrixTestImageFilter(skiatest::Reporter* reporter, const SkMatrix& expectedMatrix)
79 : INHERITED(nullptr, 0, nullptr)
80 , fReporter(reporter)
81 , fExpectedMatrix(expectedMatrix) {
82 }
83
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +000084 skiatest::Reporter* fReporter;
85 SkMatrix fExpectedMatrix;
mtklein3f3b3d02014-12-01 11:47:08 -080086
reed9fa60da2014-08-21 07:59:51 -070087 typedef SkImageFilter INHERITED;
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +000088};
89
senorblanco6a93fa12016-04-05 04:43:45 -070090class FailImageFilter : public SkImageFilter {
91public:
robertphillips6b134732016-04-15 09:58:37 -070092 FailImageFilter() : SkImageFilter(nullptr, 0, nullptr) { }
senorblanco6a93fa12016-04-05 04:43:45 -070093
94 sk_sp<SkSpecialImage> onFilterImage(SkSpecialImage* source,
95 const Context& ctx,
96 SkIPoint* offset) const override {
97 return nullptr;
98 }
Matt Sarett62745a82017-04-17 11:57:29 -040099 sk_sp<SkImageFilter> onMakeColorSpace(SkColorSpaceXformer*) const override {
100 return nullptr;
101 }
senorblanco6a93fa12016-04-05 04:43:45 -0700102
Mike Klein4fee3232018-10-18 17:27:16 -0400103 SK_FLATTENABLE_HOOKS(FailImageFilter)
senorblanco6a93fa12016-04-05 04:43:45 -0700104
105private:
106 typedef SkImageFilter INHERITED;
107};
108
109sk_sp<SkFlattenable> FailImageFilter::CreateProc(SkReadBuffer& buffer) {
110 SK_IMAGEFILTER_UNFLATTEN_COMMON(common, 0);
111 return sk_sp<SkFlattenable>(new FailImageFilter());
112}
113
senorblanco297f7ce2016-03-23 13:44:26 -0700114void draw_gradient_circle(SkCanvas* canvas, int width, int height) {
115 SkScalar x = SkIntToScalar(width / 2);
116 SkScalar y = SkIntToScalar(height / 2);
117 SkScalar radius = SkMinScalar(x, y) * 0.8f;
118 canvas->clear(0x00000000);
119 SkColor colors[2];
120 colors[0] = SK_ColorWHITE;
121 colors[1] = SK_ColorBLACK;
122 sk_sp<SkShader> shader(
123 SkGradientShader::MakeRadial(SkPoint::Make(x, y), radius, colors, nullptr, 2,
124 SkShader::kClamp_TileMode)
125 );
126 SkPaint paint;
127 paint.setShader(shader);
128 canvas->drawCircle(x, y, radius, paint);
129}
130
131SkBitmap make_gradient_circle(int width, int height) {
132 SkBitmap bitmap;
133 bitmap.allocN32Pixels(width, height);
134 SkCanvas canvas(bitmap);
135 draw_gradient_circle(&canvas, width, height);
136 return bitmap;
137}
138
139class FilterList {
140public:
robertphillipsfc11b0a2016-04-05 09:09:36 -0700141 FilterList(sk_sp<SkImageFilter> input, const SkImageFilter::CropRect* cropRect = nullptr) {
senorblanco297f7ce2016-03-23 13:44:26 -0700142 SkPoint3 location = SkPoint3::Make(0, 0, SK_Scalar1);
senorblanco297f7ce2016-03-23 13:44:26 -0700143 const SkScalar five = SkIntToScalar(5);
robertphillips6e7025a2016-04-04 04:31:25 -0700144 {
145 sk_sp<SkColorFilter> cf(SkColorFilter::MakeModeFilter(SK_ColorRED,
Mike Reed7d954ad2016-10-28 15:42:34 -0400146 SkBlendMode::kSrcIn));
senorblanco297f7ce2016-03-23 13:44:26 -0700147
robertphillips6e7025a2016-04-04 04:31:25 -0700148 this->addFilter("color filter",
robertphillips12fa47d2016-04-08 16:28:09 -0700149 SkColorFilterImageFilter::Make(std::move(cf), input, cropRect));
robertphillips6e7025a2016-04-04 04:31:25 -0700150 }
robertphillips6e7025a2016-04-04 04:31:25 -0700151 {
152 sk_sp<SkImage> gradientImage(SkImage::MakeFromBitmap(make_gradient_circle(64, 64)));
153 sk_sp<SkImageFilter> gradientSource(SkImageSource::Make(std::move(gradientImage)));
senorblanco297f7ce2016-03-23 13:44:26 -0700154
liyuqianbfebe222016-11-14 11:17:16 -0800155 this->addFilter("displacement map",
robertphillipsbfe11fc2016-04-15 07:17:36 -0700156 SkDisplacementMapEffect::Make(SkDisplacementMapEffect::kR_ChannelSelectorType,
157 SkDisplacementMapEffect::kB_ChannelSelectorType,
158 20.0f,
159 std::move(gradientSource), input, cropRect));
robertphillips6e7025a2016-04-04 04:31:25 -0700160 }
robertphillips6e7025a2016-04-04 04:31:25 -0700161 this->addFilter("blur", SkBlurImageFilter::Make(SK_Scalar1,
162 SK_Scalar1,
robertphillipsfc11b0a2016-04-05 09:09:36 -0700163 input,
robertphillips12fa47d2016-04-08 16:28:09 -0700164 cropRect));
robertphillipsc4169122016-04-06 08:40:59 -0700165 this->addFilter("drop shadow", SkDropShadowImageFilter::Make(
senorblanco297f7ce2016-03-23 13:44:26 -0700166 SK_Scalar1, SK_Scalar1, SK_Scalar1, SK_Scalar1, SK_ColorGREEN,
robertphillipsfc11b0a2016-04-05 09:09:36 -0700167 SkDropShadowImageFilter::kDrawShadowAndForeground_ShadowMode,
robertphillips12fa47d2016-04-08 16:28:09 -0700168 input, cropRect));
169 this->addFilter("diffuse lighting",
170 SkLightingImageFilter::MakePointLitDiffuse(location, SK_ColorGREEN, 0, 0,
171 input, cropRect));
senorblanco297f7ce2016-03-23 13:44:26 -0700172 this->addFilter("specular lighting",
robertphillips12fa47d2016-04-08 16:28:09 -0700173 SkLightingImageFilter::MakePointLitSpecular(location, SK_ColorGREEN, 0, 0, 0,
174 input, cropRect));
175 {
176 SkScalar kernel[9] = {
177 SkIntToScalar(1), SkIntToScalar(1), SkIntToScalar(1),
178 SkIntToScalar(1), SkIntToScalar(-7), SkIntToScalar(1),
179 SkIntToScalar(1), SkIntToScalar(1), SkIntToScalar(1),
180 };
181 const SkISize kernelSize = SkISize::Make(3, 3);
182 const SkScalar gain = SK_Scalar1, bias = 0;
183
Robert Phillips12078432018-05-17 11:17:39 -0400184 // This filter needs a saveLayer bc it is in repeat mode
robertphillips12fa47d2016-04-08 16:28:09 -0700185 this->addFilter("matrix convolution",
Robert Phillips12078432018-05-17 11:17:39 -0400186 SkMatrixConvolutionImageFilter::Make(
187 kernelSize, kernel, gain, bias, SkIPoint::Make(1, 1),
188 SkMatrixConvolutionImageFilter::kRepeat_TileMode, false,
189 input, cropRect),
190 true);
robertphillips12fa47d2016-04-08 16:28:09 -0700191 }
Mike Reed0bdaf052017-06-18 23:35:57 -0400192 this->addFilter("merge", SkMergeImageFilter::Make(input, input, cropRect));
robertphillips12fa47d2016-04-08 16:28:09 -0700193
robertphillips6e7025a2016-04-04 04:31:25 -0700194 {
195 SkPaint greenColorShaderPaint;
196 greenColorShaderPaint.setShader(SkShader::MakeColorShader(SK_ColorGREEN));
197
198 SkImageFilter::CropRect leftSideCropRect(SkRect::MakeXYWH(0, 0, 32, 64));
199 sk_sp<SkImageFilter> paintFilterLeft(SkPaintImageFilter::Make(greenColorShaderPaint,
200 &leftSideCropRect));
201 SkImageFilter::CropRect rightSideCropRect(SkRect::MakeXYWH(32, 0, 32, 64));
202 sk_sp<SkImageFilter> paintFilterRight(SkPaintImageFilter::Make(greenColorShaderPaint,
203 &rightSideCropRect));
204
205
206 this->addFilter("merge with disjoint inputs", SkMergeImageFilter::Make(
Mike Reed0bdaf052017-06-18 23:35:57 -0400207 std::move(paintFilterLeft), std::move(paintFilterRight), cropRect));
robertphillips6e7025a2016-04-04 04:31:25 -0700208 }
209
senorblanco297f7ce2016-03-23 13:44:26 -0700210 this->addFilter("offset",
robertphillipsfc11b0a2016-04-05 09:09:36 -0700211 SkOffsetImageFilter::Make(SK_Scalar1, SK_Scalar1, input,
robertphillips12fa47d2016-04-08 16:28:09 -0700212 cropRect));
213 this->addFilter("dilate", SkDilateImageFilter::Make(3, 2, input, cropRect));
214 this->addFilter("erode", SkErodeImageFilter::Make(2, 3, input, cropRect));
robertphillips534c2702016-04-15 07:57:40 -0700215 this->addFilter("tile", SkTileImageFilter::Make(
216 SkRect::MakeXYWH(0, 0, 50, 50),
217 cropRect ? cropRect->rect() : SkRect::MakeXYWH(0, 0, 100, 100),
218 input));
robertphillips6e7025a2016-04-04 04:31:25 -0700219
robertphillips12fa47d2016-04-08 16:28:09 -0700220 if (!cropRect) {
221 SkMatrix matrix;
222
223 matrix.setTranslate(SK_Scalar1, SK_Scalar1);
224 matrix.postRotate(SkIntToScalar(45), SK_Scalar1, SK_Scalar1);
225
226 this->addFilter("matrix",
227 SkImageFilter::MakeMatrixFilter(matrix, kLow_SkFilterQuality, input));
228 }
robertphillips6e7025a2016-04-04 04:31:25 -0700229 {
robertphillipsfc11b0a2016-04-05 09:09:36 -0700230 sk_sp<SkImageFilter> blur(SkBlurImageFilter::Make(five, five, input));
robertphillips6e7025a2016-04-04 04:31:25 -0700231
232 this->addFilter("blur and offset", SkOffsetImageFilter::Make(five, five,
233 std::move(blur),
robertphillips12fa47d2016-04-08 16:28:09 -0700234 cropRect));
robertphillips6e7025a2016-04-04 04:31:25 -0700235 }
236 {
robertphillips6e7025a2016-04-04 04:31:25 -0700237 SkPictureRecorder recorder;
Mike Klein26eb16f2017-04-10 09:50:25 -0400238 SkCanvas* recordingCanvas = recorder.beginRecording(64, 64);
robertphillips6e7025a2016-04-04 04:31:25 -0700239
240 SkPaint greenPaint;
241 greenPaint.setColor(SK_ColorGREEN);
242 recordingCanvas->drawRect(SkRect::Make(SkIRect::MakeXYWH(10, 10, 30, 20)), greenPaint);
243 sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture());
244 sk_sp<SkImageFilter> pictureFilter(SkPictureImageFilter::Make(std::move(picture)));
245
246 this->addFilter("picture and blur", SkBlurImageFilter::Make(five, five,
247 std::move(pictureFilter),
robertphillips12fa47d2016-04-08 16:28:09 -0700248 cropRect));
robertphillips6e7025a2016-04-04 04:31:25 -0700249 }
250 {
251 SkPaint paint;
252 paint.setShader(SkPerlinNoiseShader::MakeTurbulence(SK_Scalar1, SK_Scalar1, 1, 0));
253 sk_sp<SkImageFilter> paintFilter(SkPaintImageFilter::Make(paint));
254
255 this->addFilter("paint and blur", SkBlurImageFilter::Make(five, five,
256 std::move(paintFilter),
robertphillips12fa47d2016-04-08 16:28:09 -0700257 cropRect));
robertphillips6e7025a2016-04-04 04:31:25 -0700258 }
reed374772b2016-10-05 17:33:02 -0700259 this->addFilter("xfermode", SkXfermodeImageFilter::Make(SkBlendMode::kSrc, input, input,
260 cropRect));
senorblanco297f7ce2016-03-23 13:44:26 -0700261 }
262 int count() const { return fFilters.count(); }
263 SkImageFilter* getFilter(int index) const { return fFilters[index].fFilter.get(); }
264 const char* getName(int index) const { return fFilters[index].fName; }
Robert Phillips12078432018-05-17 11:17:39 -0400265 bool needsSaveLayer(int index) const { return fFilters[index].fNeedsSaveLayer; }
senorblanco297f7ce2016-03-23 13:44:26 -0700266private:
267 struct Filter {
Robert Phillips12078432018-05-17 11:17:39 -0400268 Filter() : fName(nullptr), fNeedsSaveLayer(false) {}
269 Filter(const char* name, sk_sp<SkImageFilter> filter, bool needsSaveLayer)
robertphillips12fa47d2016-04-08 16:28:09 -0700270 : fName(name)
Robert Phillips12078432018-05-17 11:17:39 -0400271 , fFilter(std::move(filter))
272 , fNeedsSaveLayer(needsSaveLayer) {
robertphillips12fa47d2016-04-08 16:28:09 -0700273 }
senorblanco297f7ce2016-03-23 13:44:26 -0700274 const char* fName;
275 sk_sp<SkImageFilter> fFilter;
Robert Phillips12078432018-05-17 11:17:39 -0400276 bool fNeedsSaveLayer;
senorblanco297f7ce2016-03-23 13:44:26 -0700277 };
Robert Phillips12078432018-05-17 11:17:39 -0400278 void addFilter(const char* name, sk_sp<SkImageFilter> filter, bool needsSaveLayer = false) {
279 fFilters.push_back(Filter(name, std::move(filter), needsSaveLayer));
senorblanco297f7ce2016-03-23 13:44:26 -0700280 }
281
282 SkTArray<Filter> fFilters;
283};
284
Xianzhu Wang0fa353c2017-08-25 16:27:04 -0700285class FixedBoundsImageFilter : public SkImageFilter {
286public:
287 FixedBoundsImageFilter(const SkIRect& bounds)
288 : SkImageFilter(nullptr, 0, nullptr), fBounds(bounds) {}
289
290private:
Xianzhu Wang0fa353c2017-08-25 16:27:04 -0700291 Factory getFactory() const override { return nullptr; }
Mike Klein4fee3232018-10-18 17:27:16 -0400292 const char* getTypeName() const override { return nullptr; }
Xianzhu Wang0fa353c2017-08-25 16:27:04 -0700293
294 sk_sp<SkSpecialImage> onFilterImage(SkSpecialImage* src, const Context&,
295 SkIPoint* offset) const override {
296 return nullptr;
297 }
298 sk_sp<SkImageFilter> onMakeColorSpace(SkColorSpaceXformer*) const override { return nullptr; }
299
Robert Phillips12078432018-05-17 11:17:39 -0400300 SkIRect onFilterBounds(const SkIRect&, const SkMatrix&,
301 MapDirection, const SkIRect*) const override {
Xianzhu Wang0fa353c2017-08-25 16:27:04 -0700302 return fBounds;
303 }
304
305 SkIRect fBounds;
306};
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +0000307}
308
reed60c9b582016-04-03 09:11:13 -0700309sk_sp<SkFlattenable> MatrixTestImageFilter::CreateProc(SkReadBuffer& buffer) {
brianosman18f13f32016-05-02 07:51:08 -0700310 SkDEBUGFAIL("Should never get here");
311 return nullptr;
reed9fa60da2014-08-21 07:59:51 -0700312}
313
reed9ce9d672016-03-17 10:51:11 -0700314static sk_sp<SkImage> make_small_image() {
reede8f30622016-03-23 18:59:25 -0700315 auto surface(SkSurface::MakeRasterN32Premul(kBitmapSize, kBitmapSize));
fmalita5598b632015-09-15 11:26:13 -0700316 SkCanvas* canvas = surface->getCanvas();
317 canvas->clear(0x00000000);
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000318 SkPaint darkPaint;
319 darkPaint.setColor(0xFF804020);
320 SkPaint lightPaint;
321 lightPaint.setColor(0xFF244484);
322 const int i = kBitmapSize / 4;
323 for (int y = 0; y < kBitmapSize; y += i) {
324 for (int x = 0; x < kBitmapSize; x += i) {
fmalita5598b632015-09-15 11:26:13 -0700325 canvas->save();
326 canvas->translate(SkIntToScalar(x), SkIntToScalar(y));
327 canvas->drawRect(SkRect::MakeXYWH(0, 0,
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000328 SkIntToScalar(i),
329 SkIntToScalar(i)), darkPaint);
fmalita5598b632015-09-15 11:26:13 -0700330 canvas->drawRect(SkRect::MakeXYWH(SkIntToScalar(i),
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000331 0,
332 SkIntToScalar(i),
333 SkIntToScalar(i)), lightPaint);
fmalita5598b632015-09-15 11:26:13 -0700334 canvas->drawRect(SkRect::MakeXYWH(0,
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000335 SkIntToScalar(i),
336 SkIntToScalar(i),
337 SkIntToScalar(i)), lightPaint);
fmalita5598b632015-09-15 11:26:13 -0700338 canvas->drawRect(SkRect::MakeXYWH(SkIntToScalar(i),
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000339 SkIntToScalar(i),
340 SkIntToScalar(i),
341 SkIntToScalar(i)), darkPaint);
fmalita5598b632015-09-15 11:26:13 -0700342 canvas->restore();
commit-bot@chromium.org4b681bc2013-09-13 12:40:02 +0000343 }
344 }
fmalita5598b632015-09-15 11:26:13 -0700345
reed9ce9d672016-03-17 10:51:11 -0700346 return surface->makeImageSnapshot();
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000347}
senorblanco@chromium.org194d7752013-07-24 22:19:24 +0000348
robertphillips5605b562016-04-05 11:50:42 -0700349static sk_sp<SkImageFilter> make_scale(float amount, sk_sp<SkImageFilter> input) {
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000350 SkScalar s = amount;
351 SkScalar matrix[20] = { s, 0, 0, 0, 0,
352 0, s, 0, 0, 0,
353 0, 0, s, 0, 0,
354 0, 0, 0, s, 0 };
robertphillips5605b562016-04-05 11:50:42 -0700355 sk_sp<SkColorFilter> filter(SkColorFilter::MakeMatrixFilterRowMajor255(matrix));
356 return SkColorFilterImageFilter::Make(std::move(filter), std::move(input));
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000357}
358
robertphillips5605b562016-04-05 11:50:42 -0700359static sk_sp<SkImageFilter> make_grayscale(sk_sp<SkImageFilter> input,
360 const SkImageFilter::CropRect* cropRect) {
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000361 SkScalar matrix[20];
362 memset(matrix, 0, 20 * sizeof(SkScalar));
363 matrix[0] = matrix[5] = matrix[10] = 0.2126f;
364 matrix[1] = matrix[6] = matrix[11] = 0.7152f;
365 matrix[2] = matrix[7] = matrix[12] = 0.0722f;
366 matrix[18] = 1.0f;
robertphillips5605b562016-04-05 11:50:42 -0700367 sk_sp<SkColorFilter> filter(SkColorFilter::MakeMatrixFilterRowMajor255(matrix));
368 return SkColorFilterImageFilter::Make(std::move(filter), std::move(input), cropRect);
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000369}
370
robertphillips5605b562016-04-05 11:50:42 -0700371static sk_sp<SkImageFilter> make_blue(sk_sp<SkImageFilter> input,
372 const SkImageFilter::CropRect* cropRect) {
373 sk_sp<SkColorFilter> filter(SkColorFilter::MakeModeFilter(SK_ColorBLUE,
Mike Reed7d954ad2016-10-28 15:42:34 -0400374 SkBlendMode::kSrcIn));
robertphillips5605b562016-04-05 11:50:42 -0700375 return SkColorFilterImageFilter::Make(std::move(filter), std::move(input), cropRect);
reedcedc36f2015-03-08 04:42:52 -0700376}
377
robertphillips3e302272016-04-20 11:48:36 -0700378static sk_sp<SkSpecialSurface> create_empty_special_surface(GrContext* context, int widthHeight) {
robertphillips4418dba2016-03-07 12:45:14 -0800379 if (context) {
Greg Daniel4065d452018-11-16 15:43:41 -0500380 GrBackendFormat format =
381 context->contextPriv().caps()->getBackendFormatFromColorType(kRGBA_8888_SkColorType);
382 return SkSpecialSurface::MakeRenderTarget(context, format,
robertphillips4df16562016-04-28 15:09:34 -0700383 widthHeight, widthHeight,
Brian Osman777b5632016-10-14 09:16:21 -0400384 kRGBA_8888_GrPixelConfig, nullptr);
Brian Osmanc7ad40f2018-05-31 14:27:17 -0400385 } else {
robertphillips4418dba2016-03-07 12:45:14 -0800386 const SkImageInfo info = SkImageInfo::MakeN32(widthHeight, widthHeight,
387 kOpaque_SkAlphaType);
robertphillips3e302272016-04-20 11:48:36 -0700388 return SkSpecialSurface::MakeRaster(info);
robertphillips4418dba2016-03-07 12:45:14 -0800389 }
senorblancobf680c32016-03-16 16:15:53 -0700390}
391
senorblanco5878dbd2016-05-19 14:50:29 -0700392static sk_sp<SkSurface> create_surface(GrContext* context, int width, int height) {
393 const SkImageInfo info = SkImageInfo::MakeN32(width, height, kOpaque_SkAlphaType);
senorblanco5878dbd2016-05-19 14:50:29 -0700394 if (context) {
395 return SkSurface::MakeRenderTarget(context, SkBudgeted::kNo, info);
Brian Osmanc7ad40f2018-05-31 14:27:17 -0400396 } else {
senorblanco5878dbd2016-05-19 14:50:29 -0700397 return SkSurface::MakeRaster(info);
398 }
399}
400
robertphillips3e302272016-04-20 11:48:36 -0700401static sk_sp<SkSpecialImage> create_empty_special_image(GrContext* context, int widthHeight) {
402 sk_sp<SkSpecialSurface> surf(create_empty_special_surface(context, widthHeight));
robertphillips4418dba2016-03-07 12:45:14 -0800403
404 SkASSERT(surf);
405
406 SkCanvas* canvas = surf->getCanvas();
407 SkASSERT(canvas);
408
409 canvas->clear(0x0);
410
robertphillips37bd7c32016-03-17 14:31:39 -0700411 return surf->makeImageSnapshot();
robertphillips4418dba2016-03-07 12:45:14 -0800412}
413
414
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000415DEF_TEST(ImageFilter, reporter) {
416 {
reedcedc36f2015-03-08 04:42:52 -0700417 // Check that two non-clipping color-matrice-filters concatenate into a single filter.
robertphillips5605b562016-04-05 11:50:42 -0700418 sk_sp<SkImageFilter> halfBrightness(make_scale(0.5f, nullptr));
419 sk_sp<SkImageFilter> quarterBrightness(make_scale(0.5f, std::move(halfBrightness)));
halcanary96fcdcc2015-08-27 07:41:13 -0700420 REPORTER_ASSERT(reporter, nullptr == quarterBrightness->getInput(0));
reedcedc36f2015-03-08 04:42:52 -0700421 SkColorFilter* cf;
422 REPORTER_ASSERT(reporter, quarterBrightness->asColorFilter(&cf));
halcanary96fcdcc2015-08-27 07:41:13 -0700423 REPORTER_ASSERT(reporter, cf->asColorMatrix(nullptr));
reedcedc36f2015-03-08 04:42:52 -0700424 cf->unref();
senorblanco@chromium.org194d7752013-07-24 22:19:24 +0000425 }
426
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000427 {
reedcedc36f2015-03-08 04:42:52 -0700428 // Check that a clipping color-matrice-filter followed by a color-matrice-filters
429 // concatenates into a single filter, but not a matrixfilter (due to clamping).
robertphillips5605b562016-04-05 11:50:42 -0700430 sk_sp<SkImageFilter> doubleBrightness(make_scale(2.0f, nullptr));
431 sk_sp<SkImageFilter> halfBrightness(make_scale(0.5f, std::move(doubleBrightness)));
halcanary96fcdcc2015-08-27 07:41:13 -0700432 REPORTER_ASSERT(reporter, nullptr == halfBrightness->getInput(0));
reedcedc36f2015-03-08 04:42:52 -0700433 SkColorFilter* cf;
434 REPORTER_ASSERT(reporter, halfBrightness->asColorFilter(&cf));
halcanary96fcdcc2015-08-27 07:41:13 -0700435 REPORTER_ASSERT(reporter, !cf->asColorMatrix(nullptr));
reedcedc36f2015-03-08 04:42:52 -0700436 cf->unref();
senorblanco@chromium.org194d7752013-07-24 22:19:24 +0000437 }
438
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000439 {
440 // Check that a color filter image filter without a crop rect can be
441 // expressed as a color filter.
robertphillips5605b562016-04-05 11:50:42 -0700442 sk_sp<SkImageFilter> gray(make_grayscale(nullptr, nullptr));
halcanary96fcdcc2015-08-27 07:41:13 -0700443 REPORTER_ASSERT(reporter, true == gray->asColorFilter(nullptr));
senorblanco@chromium.org194d7752013-07-24 22:19:24 +0000444 }
mtklein2afbe232016-02-07 12:23:10 -0800445
reedcedc36f2015-03-08 04:42:52 -0700446 {
447 // Check that a colorfilterimage filter without a crop rect but with an input
448 // that is another colorfilterimage can be expressed as a colorfilter (composed).
robertphillips5605b562016-04-05 11:50:42 -0700449 sk_sp<SkImageFilter> mode(make_blue(nullptr, nullptr));
450 sk_sp<SkImageFilter> gray(make_grayscale(std::move(mode), nullptr));
halcanary96fcdcc2015-08-27 07:41:13 -0700451 REPORTER_ASSERT(reporter, true == gray->asColorFilter(nullptr));
reedcedc36f2015-03-08 04:42:52 -0700452 }
453
454 {
455 // Test that if we exceed the limit of what ComposeColorFilter can combine, we still
456 // can build the DAG and won't assert if we call asColorFilter.
robertphillips5605b562016-04-05 11:50:42 -0700457 sk_sp<SkImageFilter> filter(make_blue(nullptr, nullptr));
reedcedc36f2015-03-08 04:42:52 -0700458 const int kWayTooManyForComposeColorFilter = 100;
459 for (int i = 0; i < kWayTooManyForComposeColorFilter; ++i) {
robertphillips5605b562016-04-05 11:50:42 -0700460 filter = make_blue(filter, nullptr);
reedcedc36f2015-03-08 04:42:52 -0700461 // the first few of these will succeed, but after we hit the internal limit,
462 // it will then return false.
halcanary96fcdcc2015-08-27 07:41:13 -0700463 (void)filter->asColorFilter(nullptr);
reedcedc36f2015-03-08 04:42:52 -0700464 }
465 }
reed5c518a82015-03-05 14:47:29 -0800466
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000467 {
468 // Check that a color filter image filter with a crop rect cannot
469 // be expressed as a color filter.
470 SkImageFilter::CropRect cropRect(SkRect::MakeXYWH(0, 0, 100, 100));
robertphillips5605b562016-04-05 11:50:42 -0700471 sk_sp<SkImageFilter> grayWithCrop(make_grayscale(nullptr, &cropRect));
halcanary96fcdcc2015-08-27 07:41:13 -0700472 REPORTER_ASSERT(reporter, false == grayWithCrop->asColorFilter(nullptr));
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000473 }
474
475 {
senorblanco3df05012014-07-03 11:13:09 -0700476 // Check that two non-commutative matrices are concatenated in
477 // the correct order.
478 SkScalar blueToRedMatrix[20] = { 0 };
479 blueToRedMatrix[2] = blueToRedMatrix[18] = SK_Scalar1;
480 SkScalar redToGreenMatrix[20] = { 0 };
481 redToGreenMatrix[5] = redToGreenMatrix[18] = SK_Scalar1;
robertphillips5605b562016-04-05 11:50:42 -0700482 sk_sp<SkColorFilter> blueToRed(SkColorFilter::MakeMatrixFilterRowMajor255(blueToRedMatrix));
483 sk_sp<SkImageFilter> filter1(SkColorFilterImageFilter::Make(std::move(blueToRed),
484 nullptr));
485 sk_sp<SkColorFilter> redToGreen(SkColorFilter::MakeMatrixFilterRowMajor255(redToGreenMatrix));
486 sk_sp<SkImageFilter> filter2(SkColorFilterImageFilter::Make(std::move(redToGreen),
487 std::move(filter1)));
senorblanco3df05012014-07-03 11:13:09 -0700488
489 SkBitmap result;
490 result.allocN32Pixels(kBitmapSize, kBitmapSize);
491
492 SkPaint paint;
493 paint.setColor(SK_ColorBLUE);
robertphillips5605b562016-04-05 11:50:42 -0700494 paint.setImageFilter(std::move(filter2));
senorblanco3df05012014-07-03 11:13:09 -0700495 SkCanvas canvas(result);
496 canvas.clear(0x0);
497 SkRect rect = SkRect::Make(SkIRect::MakeWH(kBitmapSize, kBitmapSize));
498 canvas.drawRect(rect, paint);
499 uint32_t pixel = *result.getAddr32(0, 0);
500 // The result here should be green, since we have effectively shifted blue to green.
501 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
502 }
503
504 {
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000505 // Tests pass by not asserting
reed9ce9d672016-03-17 10:51:11 -0700506 sk_sp<SkImage> image(make_small_image());
fmalita5598b632015-09-15 11:26:13 -0700507 SkBitmap result;
mike@reedtribe.orgdeee4962014-02-13 14:41:43 +0000508 result.allocN32Pixels(kBitmapSize, kBitmapSize);
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000509
senorblanco@chromium.org194d7752013-07-24 22:19:24 +0000510 {
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000511 // This tests for :
512 // 1 ) location at (0,0,1)
robertphillips3d32d762015-07-13 13:16:44 -0700513 SkPoint3 location = SkPoint3::Make(0, 0, SK_Scalar1);
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000514 // 2 ) location and target at same value
robertphillips3d32d762015-07-13 13:16:44 -0700515 SkPoint3 target = SkPoint3::Make(location.fX, location.fY, location.fZ);
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000516 // 3 ) large negative specular exponent value
517 SkScalar specularExponent = -1000;
518
robertphillips549c8992016-04-01 09:28:51 -0700519 sk_sp<SkImageFilter> bmSrc(SkImageSource::Make(std::move(image)));
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000520 SkPaint paint;
robertphillips12fa47d2016-04-08 16:28:09 -0700521 paint.setImageFilter(SkLightingImageFilter::MakeSpotLitSpecular(
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000522 location, target, specularExponent, 180,
523 0xFFFFFFFF, SK_Scalar1, SK_Scalar1, SK_Scalar1,
robertphillips12fa47d2016-04-08 16:28:09 -0700524 std::move(bmSrc)));
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000525 SkCanvas canvas(result);
526 SkRect r = SkRect::MakeWH(SkIntToScalar(kBitmapSize),
527 SkIntToScalar(kBitmapSize));
528 canvas.drawRect(r, paint);
senorblanco@chromium.org194d7752013-07-24 22:19:24 +0000529 }
senorblanco@chromium.org194d7752013-07-24 22:19:24 +0000530 }
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +0000531}
senorblanco@chromium.org6776b822014-01-03 21:48:22 +0000532
robertphillips3e302272016-04-20 11:48:36 -0700533static void test_crop_rects(skiatest::Reporter* reporter,
robertphillips4418dba2016-03-07 12:45:14 -0800534 GrContext* context) {
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +0000535 // Check that all filters offset to their absolute crop rect,
536 // unaffected by the input crop rect.
537 // Tests pass by not asserting.
robertphillips3e302272016-04-20 11:48:36 -0700538 sk_sp<SkSpecialImage> srcImg(create_empty_special_image(context, 100));
robertphillips4418dba2016-03-07 12:45:14 -0800539 SkASSERT(srcImg);
senorblanco@chromium.org6776b822014-01-03 21:48:22 +0000540
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +0000541 SkImageFilter::CropRect inputCropRect(SkRect::MakeXYWH(8, 13, 80, 80));
542 SkImageFilter::CropRect cropRect(SkRect::MakeXYWH(20, 30, 60, 60));
robertphillipsfc11b0a2016-04-05 09:09:36 -0700543 sk_sp<SkImageFilter> input(make_grayscale(nullptr, &inputCropRect));
senorblanco@chromium.org6776b822014-01-03 21:48:22 +0000544
robertphillipsfc11b0a2016-04-05 09:09:36 -0700545 FilterList filters(input, &cropRect);
senorblanco@chromium.org6776b822014-01-03 21:48:22 +0000546
senorblanco297f7ce2016-03-23 13:44:26 -0700547 for (int i = 0; i < filters.count(); ++i) {
548 SkImageFilter* filter = filters.getFilter(i);
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +0000549 SkIPoint offset;
Brian Osmana50205f2018-07-06 13:57:01 -0400550 SkImageFilter::OutputProperties noColorSpace(kN32_SkColorType, nullptr);
brianosman2a75e5d2016-09-22 07:15:37 -0700551 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeWH(100, 100), nullptr, noColorSpace);
robertphillips2302de92016-03-24 07:26:32 -0700552 sk_sp<SkSpecialImage> resultImg(filter->filterImage(srcImg.get(), ctx, &offset));
Brian Salomon1c80e992018-01-29 09:50:47 -0500553 REPORTER_ASSERT(reporter, resultImg, filters.getName(i));
554 REPORTER_ASSERT(reporter, offset.fX == 20 && offset.fY == 30, filters.getName(i));
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +0000555 }
556}
557
robertphillips3e302272016-04-20 11:48:36 -0700558static void test_negative_blur_sigma(skiatest::Reporter* reporter,
robertphillips4418dba2016-03-07 12:45:14 -0800559 GrContext* context) {
senorblanco32673b92014-09-09 09:15:04 -0700560 // Check that SkBlurImageFilter will accept a negative sigma, either in
561 // the given arguments or after CTM application.
reed5ea95df2015-10-06 14:05:32 -0700562 const int width = 32, height = 32;
563 const SkScalar five = SkIntToScalar(5);
senorblanco32673b92014-09-09 09:15:04 -0700564
robertphillips6e7025a2016-04-04 04:31:25 -0700565 sk_sp<SkImageFilter> positiveFilter(SkBlurImageFilter::Make(five, five, nullptr));
566 sk_sp<SkImageFilter> negativeFilter(SkBlurImageFilter::Make(-five, five, nullptr));
senorblanco32673b92014-09-09 09:15:04 -0700567
568 SkBitmap gradient = make_gradient_circle(width, height);
robertphillips3e302272016-04-20 11:48:36 -0700569 sk_sp<SkSpecialImage> imgSrc(SkSpecialImage::MakeFromRaster(SkIRect::MakeWH(width, height),
robertphillips37bd7c32016-03-17 14:31:39 -0700570 gradient));
robertphillips4418dba2016-03-07 12:45:14 -0800571
senorblanco32673b92014-09-09 09:15:04 -0700572 SkIPoint offset;
Brian Osmana50205f2018-07-06 13:57:01 -0400573 SkImageFilter::OutputProperties noColorSpace(kN32_SkColorType, nullptr);
brianosman2a75e5d2016-09-22 07:15:37 -0700574 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeWH(32, 32), nullptr, noColorSpace);
robertphillips4418dba2016-03-07 12:45:14 -0800575
robertphillips2302de92016-03-24 07:26:32 -0700576 sk_sp<SkSpecialImage> positiveResult1(positiveFilter->filterImage(imgSrc.get(), ctx, &offset));
robertphillips4418dba2016-03-07 12:45:14 -0800577 REPORTER_ASSERT(reporter, positiveResult1);
578
robertphillips2302de92016-03-24 07:26:32 -0700579 sk_sp<SkSpecialImage> negativeResult1(negativeFilter->filterImage(imgSrc.get(), ctx, &offset));
robertphillips4418dba2016-03-07 12:45:14 -0800580 REPORTER_ASSERT(reporter, negativeResult1);
581
senorblanco32673b92014-09-09 09:15:04 -0700582 SkMatrix negativeScale;
583 negativeScale.setScale(-SK_Scalar1, SK_Scalar1);
brianosman2a75e5d2016-09-22 07:15:37 -0700584 SkImageFilter::Context negativeCTX(negativeScale, SkIRect::MakeWH(32, 32), nullptr,
585 noColorSpace);
robertphillips4418dba2016-03-07 12:45:14 -0800586
robertphillips2302de92016-03-24 07:26:32 -0700587 sk_sp<SkSpecialImage> negativeResult2(positiveFilter->filterImage(imgSrc.get(),
588 negativeCTX,
589 &offset));
robertphillips4418dba2016-03-07 12:45:14 -0800590 REPORTER_ASSERT(reporter, negativeResult2);
591
robertphillips2302de92016-03-24 07:26:32 -0700592 sk_sp<SkSpecialImage> positiveResult2(negativeFilter->filterImage(imgSrc.get(),
593 negativeCTX,
594 &offset));
robertphillips4418dba2016-03-07 12:45:14 -0800595 REPORTER_ASSERT(reporter, positiveResult2);
596
597
598 SkBitmap positiveResultBM1, positiveResultBM2;
599 SkBitmap negativeResultBM1, negativeResultBM2;
600
robertphillips64612512016-04-08 12:10:42 -0700601 REPORTER_ASSERT(reporter, positiveResult1->getROPixels(&positiveResultBM1));
602 REPORTER_ASSERT(reporter, positiveResult2->getROPixels(&positiveResultBM2));
603 REPORTER_ASSERT(reporter, negativeResult1->getROPixels(&negativeResultBM1));
604 REPORTER_ASSERT(reporter, negativeResult2->getROPixels(&negativeResultBM2));
robertphillips4418dba2016-03-07 12:45:14 -0800605
senorblanco32673b92014-09-09 09:15:04 -0700606 for (int y = 0; y < height; y++) {
robertphillips4418dba2016-03-07 12:45:14 -0800607 int diffs = memcmp(positiveResultBM1.getAddr32(0, y),
608 negativeResultBM1.getAddr32(0, y),
609 positiveResultBM1.rowBytes());
senorblanco32673b92014-09-09 09:15:04 -0700610 REPORTER_ASSERT(reporter, !diffs);
611 if (diffs) {
612 break;
613 }
robertphillips4418dba2016-03-07 12:45:14 -0800614 diffs = memcmp(positiveResultBM1.getAddr32(0, y),
615 negativeResultBM2.getAddr32(0, y),
616 positiveResultBM1.rowBytes());
senorblanco32673b92014-09-09 09:15:04 -0700617 REPORTER_ASSERT(reporter, !diffs);
618 if (diffs) {
619 break;
620 }
robertphillips4418dba2016-03-07 12:45:14 -0800621 diffs = memcmp(positiveResultBM1.getAddr32(0, y),
622 positiveResultBM2.getAddr32(0, y),
623 positiveResultBM1.rowBytes());
senorblanco32673b92014-09-09 09:15:04 -0700624 REPORTER_ASSERT(reporter, !diffs);
625 if (diffs) {
626 break;
627 }
628 }
629}
630
senorblanco21a465d2016-04-11 11:58:39 -0700631DEF_TEST(ImageFilterNegativeBlurSigma, reporter) {
robertphillips3e302272016-04-20 11:48:36 -0700632 test_negative_blur_sigma(reporter, nullptr);
robertphillips4418dba2016-03-07 12:45:14 -0800633}
634
bsalomon68d91342016-04-12 09:59:58 -0700635DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterNegativeBlurSigma_Gpu, reporter, ctxInfo) {
bsalomon8b7451a2016-05-11 06:33:06 -0700636 test_negative_blur_sigma(reporter, ctxInfo.grContext());
robertphillips4418dba2016-03-07 12:45:14 -0800637}
robertphillips4418dba2016-03-07 12:45:14 -0800638
robertphillips3e302272016-04-20 11:48:36 -0700639static void test_zero_blur_sigma(skiatest::Reporter* reporter, GrContext* context) {
senorblancobf680c32016-03-16 16:15:53 -0700640 // Check that SkBlurImageFilter with a zero sigma and a non-zero srcOffset works correctly.
641 SkImageFilter::CropRect cropRect(SkRect::Make(SkIRect::MakeXYWH(5, 0, 5, 10)));
robertphillips51a315e2016-03-31 09:05:49 -0700642 sk_sp<SkImageFilter> input(SkOffsetImageFilter::Make(0, 0, nullptr, &cropRect));
robertphillips6e7025a2016-04-04 04:31:25 -0700643 sk_sp<SkImageFilter> filter(SkBlurImageFilter::Make(0, 0, std::move(input), &cropRect));
senorblancobf680c32016-03-16 16:15:53 -0700644
robertphillips3e302272016-04-20 11:48:36 -0700645 sk_sp<SkSpecialSurface> surf(create_empty_special_surface(context, 10));
senorblancobf680c32016-03-16 16:15:53 -0700646 surf->getCanvas()->clear(SK_ColorGREEN);
robertphillips37bd7c32016-03-17 14:31:39 -0700647 sk_sp<SkSpecialImage> image(surf->makeImageSnapshot());
senorblancobf680c32016-03-16 16:15:53 -0700648
649 SkIPoint offset;
Brian Osmana50205f2018-07-06 13:57:01 -0400650 SkImageFilter::OutputProperties noColorSpace(kN32_SkColorType, nullptr);
brianosman2a75e5d2016-09-22 07:15:37 -0700651 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeWH(32, 32), nullptr, noColorSpace);
senorblancobf680c32016-03-16 16:15:53 -0700652
robertphillips2302de92016-03-24 07:26:32 -0700653 sk_sp<SkSpecialImage> result(filter->filterImage(image.get(), ctx, &offset));
senorblancobf680c32016-03-16 16:15:53 -0700654 REPORTER_ASSERT(reporter, offset.fX == 5 && offset.fY == 0);
655 REPORTER_ASSERT(reporter, result);
656 REPORTER_ASSERT(reporter, result->width() == 5 && result->height() == 10);
657
658 SkBitmap resultBM;
659
robertphillips64612512016-04-08 12:10:42 -0700660 REPORTER_ASSERT(reporter, result->getROPixels(&resultBM));
senorblancobf680c32016-03-16 16:15:53 -0700661
senorblancobf680c32016-03-16 16:15:53 -0700662 for (int y = 0; y < resultBM.height(); y++) {
663 for (int x = 0; x < resultBM.width(); x++) {
664 bool diff = *resultBM.getAddr32(x, y) != SK_ColorGREEN;
665 REPORTER_ASSERT(reporter, !diff);
666 if (diff) {
667 break;
668 }
669 }
670 }
671}
672
senorblanco21a465d2016-04-11 11:58:39 -0700673DEF_TEST(ImageFilterZeroBlurSigma, reporter) {
robertphillips3e302272016-04-20 11:48:36 -0700674 test_zero_blur_sigma(reporter, nullptr);
senorblancobf680c32016-03-16 16:15:53 -0700675}
676
bsalomon68d91342016-04-12 09:59:58 -0700677DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterZeroBlurSigma_Gpu, reporter, ctxInfo) {
bsalomon8b7451a2016-05-11 06:33:06 -0700678 test_zero_blur_sigma(reporter, ctxInfo.grContext());
senorblancobf680c32016-03-16 16:15:53 -0700679}
senorblancobf680c32016-03-16 16:15:53 -0700680
senorblanco6a93fa12016-04-05 04:43:45 -0700681
682// Tests that, even when an upstream filter has returned null (due to failure or clipping), a
683// downstream filter that affects transparent black still does so even with a nullptr input.
robertphillips3e302272016-04-20 11:48:36 -0700684static void test_fail_affects_transparent_black(skiatest::Reporter* reporter, GrContext* context) {
senorblanco6a93fa12016-04-05 04:43:45 -0700685 sk_sp<FailImageFilter> failFilter(new FailImageFilter());
robertphillips3e302272016-04-20 11:48:36 -0700686 sk_sp<SkSpecialImage> source(create_empty_special_image(context, 5));
Brian Osmana50205f2018-07-06 13:57:01 -0400687 SkImageFilter::OutputProperties noColorSpace(kN32_SkColorType, nullptr);
brianosman2a75e5d2016-09-22 07:15:37 -0700688 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeXYWH(0, 0, 1, 1), nullptr, noColorSpace);
Mike Reed7d954ad2016-10-28 15:42:34 -0400689 sk_sp<SkColorFilter> green(SkColorFilter::MakeModeFilter(SK_ColorGREEN, SkBlendMode::kSrc));
senorblanco6a93fa12016-04-05 04:43:45 -0700690 SkASSERT(green->affectsTransparentBlack());
robertphillips5605b562016-04-05 11:50:42 -0700691 sk_sp<SkImageFilter> greenFilter(SkColorFilterImageFilter::Make(std::move(green),
692 std::move(failFilter)));
senorblanco6a93fa12016-04-05 04:43:45 -0700693 SkIPoint offset;
694 sk_sp<SkSpecialImage> result(greenFilter->filterImage(source.get(), ctx, &offset));
695 REPORTER_ASSERT(reporter, nullptr != result.get());
696 if (result.get()) {
697 SkBitmap resultBM;
robertphillips64612512016-04-08 12:10:42 -0700698 REPORTER_ASSERT(reporter, result->getROPixels(&resultBM));
senorblanco6a93fa12016-04-05 04:43:45 -0700699 REPORTER_ASSERT(reporter, *resultBM.getAddr32(0, 0) == SK_ColorGREEN);
700 }
701}
702
703DEF_TEST(ImageFilterFailAffectsTransparentBlack, reporter) {
robertphillips3e302272016-04-20 11:48:36 -0700704 test_fail_affects_transparent_black(reporter, nullptr);
senorblanco6a93fa12016-04-05 04:43:45 -0700705}
706
bsalomon68d91342016-04-12 09:59:58 -0700707DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterFailAffectsTransparentBlack_Gpu, reporter, ctxInfo) {
bsalomon8b7451a2016-05-11 06:33:06 -0700708 test_fail_affects_transparent_black(reporter, ctxInfo.grContext());
senorblanco6a93fa12016-04-05 04:43:45 -0700709}
senorblanco6a93fa12016-04-05 04:43:45 -0700710
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +0000711DEF_TEST(ImageFilterDrawTiled, reporter) {
712 // Check that all filters when drawn tiled (with subsequent clip rects) exactly
713 // match the same filters drawn with a single full-canvas bitmap draw.
714 // Tests pass by not asserting.
715
robertphillipsfc11b0a2016-04-05 09:09:36 -0700716 FilterList filters(nullptr);
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +0000717
718 SkBitmap untiledResult, tiledResult;
reed5ea95df2015-10-06 14:05:32 -0700719 const int width = 64, height = 64;
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +0000720 untiledResult.allocN32Pixels(width, height);
721 tiledResult.allocN32Pixels(width, height);
722 SkCanvas tiledCanvas(tiledResult);
723 SkCanvas untiledCanvas(untiledResult);
Robert Phillips12078432018-05-17 11:17:39 -0400724 const int tileSize = 8;
725
726 SkPaint textPaint;
Robert Phillips12078432018-05-17 11:17:39 -0400727 textPaint.setColor(SK_ColorWHITE);
Mike Reed1af9b482019-01-07 11:01:57 -0500728 SkFont font(sk_tool_utils::create_portable_typeface(), height);
Robert Phillips12078432018-05-17 11:17:39 -0400729
730 const char* text = "ABC";
731 const SkScalar yPos = SkIntToScalar(height);
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +0000732
senorblanco@chromium.orgd4db6572014-05-07 20:00:04 +0000733 for (int scale = 1; scale <= 2; ++scale) {
senorblanco297f7ce2016-03-23 13:44:26 -0700734 for (int i = 0; i < filters.count(); ++i) {
Robert Phillips12078432018-05-17 11:17:39 -0400735 SkPaint combinedPaint;
Robert Phillips12078432018-05-17 11:17:39 -0400736 combinedPaint.setColor(SK_ColorWHITE);
737 combinedPaint.setImageFilter(sk_ref_sp(filters.getFilter(i)));
738
739 untiledCanvas.clear(SK_ColorTRANSPARENT);
senorblanco@chromium.orgd4db6572014-05-07 20:00:04 +0000740 untiledCanvas.save();
741 untiledCanvas.scale(SkIntToScalar(scale), SkIntToScalar(scale));
Mike Reed1af9b482019-01-07 11:01:57 -0500742 untiledCanvas.drawString(text, 0, yPos, font, combinedPaint);
senorblanco@chromium.orgd4db6572014-05-07 20:00:04 +0000743 untiledCanvas.restore();
Robert Phillips12078432018-05-17 11:17:39 -0400744 untiledCanvas.flush();
745
746 tiledCanvas.clear(SK_ColorTRANSPARENT);
senorblanco@chromium.orgd4db6572014-05-07 20:00:04 +0000747 for (int y = 0; y < height; y += tileSize) {
748 for (int x = 0; x < width; x += tileSize) {
749 tiledCanvas.save();
Robert Phillips12078432018-05-17 11:17:39 -0400750 const SkRect clipRect = SkRect::MakeXYWH(x, y, tileSize, tileSize);
751 tiledCanvas.clipRect(clipRect);
752 if (filters.needsSaveLayer(i)) {
753 const SkRect layerBounds = SkRect::MakeWH(width, height);
754 tiledCanvas.saveLayer(&layerBounds, &combinedPaint);
755 tiledCanvas.scale(SkIntToScalar(scale), SkIntToScalar(scale));
Mike Reed1af9b482019-01-07 11:01:57 -0500756 tiledCanvas.drawString(text, 0, yPos, font, textPaint);
Robert Phillips12078432018-05-17 11:17:39 -0400757 tiledCanvas.restore();
758 } else {
759 tiledCanvas.scale(SkIntToScalar(scale), SkIntToScalar(scale));
Mike Reed1af9b482019-01-07 11:01:57 -0500760 tiledCanvas.drawString(text, 0, yPos, font, combinedPaint);
Robert Phillips12078432018-05-17 11:17:39 -0400761 }
762
senorblanco@chromium.orgd4db6572014-05-07 20:00:04 +0000763 tiledCanvas.restore();
764 }
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +0000765 }
senorblanco@chromium.orgd4db6572014-05-07 20:00:04 +0000766 tiledCanvas.flush();
Robert Phillips12078432018-05-17 11:17:39 -0400767
Brian Osman1b151982018-09-20 12:47:39 -0400768 if (!sk_tool_utils::equal_pixels(untiledResult, tiledResult)) {
Brian Salomon1c80e992018-01-29 09:50:47 -0500769 REPORTER_ASSERT(reporter, false, filters.getName(i));
Mike Reed5a625e02017-08-08 15:48:54 -0400770 break;
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +0000771 }
772 }
773 }
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +0000774}
775
mtklein3f3b3d02014-12-01 11:47:08 -0800776static void draw_saveLayer_picture(int width, int height, int tileSize,
robertphillipsa8d7f0b2014-08-29 08:03:56 -0700777 SkBBHFactory* factory, SkBitmap* result) {
mtkleind910f542014-08-22 09:06:34 -0700778
779 SkMatrix matrix;
780 matrix.setTranslate(SkIntToScalar(50), 0);
781
Mike Reed7d954ad2016-10-28 15:42:34 -0400782 sk_sp<SkColorFilter> cf(SkColorFilter::MakeModeFilter(SK_ColorWHITE, SkBlendMode::kSrc));
robertphillips5605b562016-04-05 11:50:42 -0700783 sk_sp<SkImageFilter> cfif(SkColorFilterImageFilter::Make(std::move(cf), nullptr));
robertphillipsae8c9332016-04-05 15:09:00 -0700784 sk_sp<SkImageFilter> imageFilter(SkImageFilter::MakeMatrixFilter(matrix,
785 kNone_SkFilterQuality,
786 std::move(cfif)));
mtkleind910f542014-08-22 09:06:34 -0700787
788 SkPaint paint;
robertphillips5605b562016-04-05 11:50:42 -0700789 paint.setImageFilter(std::move(imageFilter));
mtkleind910f542014-08-22 09:06:34 -0700790 SkPictureRecorder recorder;
791 SkRect bounds = SkRect::Make(SkIRect::MakeXYWH(0, 0, 50, 50));
mtklein3f3b3d02014-12-01 11:47:08 -0800792 SkCanvas* recordingCanvas = recorder.beginRecording(SkIntToScalar(width),
793 SkIntToScalar(height),
robertphillipsa8d7f0b2014-08-29 08:03:56 -0700794 factory, 0);
mtkleind910f542014-08-22 09:06:34 -0700795 recordingCanvas->translate(-55, 0);
796 recordingCanvas->saveLayer(&bounds, &paint);
797 recordingCanvas->restore();
reedca2622b2016-03-18 07:25:55 -0700798 sk_sp<SkPicture> picture1(recorder.finishRecordingAsPicture());
mtkleind910f542014-08-22 09:06:34 -0700799
800 result->allocN32Pixels(width, height);
801 SkCanvas canvas(*result);
802 canvas.clear(0);
803 canvas.clipRect(SkRect::Make(SkIRect::MakeWH(tileSize, tileSize)));
804 canvas.drawPicture(picture1.get());
805}
806
807DEF_TEST(ImageFilterDrawMatrixBBH, reporter) {
808 // Check that matrix filter when drawn tiled with BBH exactly
809 // matches the same thing drawn without BBH.
810 // Tests pass by not asserting.
811
812 const int width = 200, height = 200;
813 const int tileSize = 100;
814 SkBitmap result1, result2;
815 SkRTreeFactory factory;
816
robertphillipsa8d7f0b2014-08-29 08:03:56 -0700817 draw_saveLayer_picture(width, height, tileSize, &factory, &result1);
halcanary96fcdcc2015-08-27 07:41:13 -0700818 draw_saveLayer_picture(width, height, tileSize, nullptr, &result2);
mtkleind910f542014-08-22 09:06:34 -0700819
820 for (int y = 0; y < height; y++) {
821 int diffs = memcmp(result1.getAddr32(0, y), result2.getAddr32(0, y), result1.rowBytes());
822 REPORTER_ASSERT(reporter, !diffs);
823 if (diffs) {
824 break;
825 }
826 }
827}
828
robertphillips6e7025a2016-04-04 04:31:25 -0700829static sk_sp<SkImageFilter> make_blur(sk_sp<SkImageFilter> input) {
830 return SkBlurImageFilter::Make(SK_Scalar1, SK_Scalar1, std::move(input));
senorblanco1150a6d2014-08-25 12:46:58 -0700831}
832
robertphillips6e7025a2016-04-04 04:31:25 -0700833static sk_sp<SkImageFilter> make_drop_shadow(sk_sp<SkImageFilter> input) {
robertphillipsc4169122016-04-06 08:40:59 -0700834 return SkDropShadowImageFilter::Make(
senorblanco1150a6d2014-08-25 12:46:58 -0700835 SkIntToScalar(100), SkIntToScalar(100),
836 SkIntToScalar(10), SkIntToScalar(10),
sugoi234f0362014-10-23 13:59:52 -0700837 SK_ColorBLUE, SkDropShadowImageFilter::kDrawShadowAndForeground_ShadowMode,
robertphillipsc4169122016-04-06 08:40:59 -0700838 std::move(input));
senorblanco1150a6d2014-08-25 12:46:58 -0700839}
840
841DEF_TEST(ImageFilterBlurThenShadowBounds, reporter) {
robertphillips6e7025a2016-04-04 04:31:25 -0700842 sk_sp<SkImageFilter> filter1(make_blur(nullptr));
843 sk_sp<SkImageFilter> filter2(make_drop_shadow(std::move(filter1)));
senorblanco1150a6d2014-08-25 12:46:58 -0700844
845 SkIRect bounds = SkIRect::MakeXYWH(0, 0, 100, 100);
Herb Derby59f8f152017-10-17 22:27:23 +0000846 SkIRect expectedBounds = SkIRect::MakeXYWH(-133, -133, 236, 236);
Robert Phillips12078432018-05-17 11:17:39 -0400847 bounds = filter2->filterBounds(bounds, SkMatrix::I(),
848 SkImageFilter::kReverse_MapDirection, &bounds);
senorblanco1150a6d2014-08-25 12:46:58 -0700849
850 REPORTER_ASSERT(reporter, bounds == expectedBounds);
851}
852
853DEF_TEST(ImageFilterShadowThenBlurBounds, reporter) {
robertphillips6e7025a2016-04-04 04:31:25 -0700854 sk_sp<SkImageFilter> filter1(make_drop_shadow(nullptr));
855 sk_sp<SkImageFilter> filter2(make_blur(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);
Robert Phillips12078432018-05-17 11:17:39 -0400859 bounds = filter2->filterBounds(bounds, SkMatrix::I(),
860 SkImageFilter::kReverse_MapDirection, &bounds);
senorblanco1150a6d2014-08-25 12:46:58 -0700861
862 REPORTER_ASSERT(reporter, bounds == expectedBounds);
863}
864
865DEF_TEST(ImageFilterDilateThenBlurBounds, reporter) {
robertphillipsfc11b0a2016-04-05 09:09:36 -0700866 sk_sp<SkImageFilter> filter1(SkDilateImageFilter::Make(2, 2, nullptr));
robertphillips6e7025a2016-04-04 04:31:25 -0700867 sk_sp<SkImageFilter> filter2(make_drop_shadow(std::move(filter1)));
senorblanco1150a6d2014-08-25 12:46:58 -0700868
869 SkIRect bounds = SkIRect::MakeXYWH(0, 0, 100, 100);
870 SkIRect expectedBounds = SkIRect::MakeXYWH(-132, -132, 234, 234);
Robert Phillips12078432018-05-17 11:17:39 -0400871 bounds = filter2->filterBounds(bounds, SkMatrix::I(),
872 SkImageFilter::kReverse_MapDirection, &bounds);
senorblanco1150a6d2014-08-25 12:46:58 -0700873
874 REPORTER_ASSERT(reporter, bounds == expectedBounds);
875}
876
jbroman203a9932016-07-11 14:07:59 -0700877DEF_TEST(ImageFilterScaledBlurRadius, reporter) {
878 // Each blur should spread 3*sigma, so 3 for the blur and 30 for the shadow
879 // (before the CTM). Bounds should be computed correctly in the presence of
880 // a (possibly negative) scale.
881 sk_sp<SkImageFilter> blur(make_blur(nullptr));
882 sk_sp<SkImageFilter> dropShadow(make_drop_shadow(nullptr));
883 {
884 // Uniform scale by 2.
885 SkMatrix scaleMatrix;
886 scaleMatrix.setScale(2, 2);
887 SkIRect bounds = SkIRect::MakeLTRB(0, 0, 200, 200);
888
Herb Derby59f8f152017-10-17 22:27:23 +0000889 SkIRect expectedBlurBounds = SkIRect::MakeLTRB(-6, -6, 206, 206);
jbroman203a9932016-07-11 14:07:59 -0700890 SkIRect blurBounds = blur->filterBounds(
Robert Phillips12078432018-05-17 11:17:39 -0400891 bounds, scaleMatrix, SkImageFilter::kForward_MapDirection, nullptr);
jbroman203a9932016-07-11 14:07:59 -0700892 REPORTER_ASSERT(reporter, blurBounds == expectedBlurBounds);
893 SkIRect reverseBlurBounds = blur->filterBounds(
Robert Phillips12078432018-05-17 11:17:39 -0400894 bounds, scaleMatrix, SkImageFilter::kReverse_MapDirection, &bounds);
jbroman203a9932016-07-11 14:07:59 -0700895 REPORTER_ASSERT(reporter, reverseBlurBounds == expectedBlurBounds);
896
897 SkIRect expectedShadowBounds = SkIRect::MakeLTRB(0, 0, 460, 460);
898 SkIRect shadowBounds = dropShadow->filterBounds(
Robert Phillips12078432018-05-17 11:17:39 -0400899 bounds, scaleMatrix, SkImageFilter::kForward_MapDirection, nullptr);
jbroman203a9932016-07-11 14:07:59 -0700900 REPORTER_ASSERT(reporter, shadowBounds == expectedShadowBounds);
901 SkIRect expectedReverseShadowBounds =
902 SkIRect::MakeLTRB(-260, -260, 200, 200);
903 SkIRect reverseShadowBounds = dropShadow->filterBounds(
Robert Phillips12078432018-05-17 11:17:39 -0400904 bounds, scaleMatrix, SkImageFilter::kReverse_MapDirection, &bounds);
jbroman203a9932016-07-11 14:07:59 -0700905 REPORTER_ASSERT(reporter,
906 reverseShadowBounds == expectedReverseShadowBounds);
907 }
908 {
909 // Vertical flip.
910 SkMatrix scaleMatrix;
911 scaleMatrix.setScale(1, -1);
912 SkIRect bounds = SkIRect::MakeLTRB(0, -100, 100, 0);
913
Herb Derby59f8f152017-10-17 22:27:23 +0000914 SkIRect expectedBlurBounds = SkIRect::MakeLTRB(-3, -103, 103, 3);
jbroman203a9932016-07-11 14:07:59 -0700915 SkIRect blurBounds = blur->filterBounds(
Robert Phillips12078432018-05-17 11:17:39 -0400916 bounds, scaleMatrix, SkImageFilter::kForward_MapDirection, nullptr);
jbroman203a9932016-07-11 14:07:59 -0700917 REPORTER_ASSERT(reporter, blurBounds == expectedBlurBounds);
918 SkIRect reverseBlurBounds = blur->filterBounds(
Robert Phillips12078432018-05-17 11:17:39 -0400919 bounds, scaleMatrix, SkImageFilter::kReverse_MapDirection, &bounds);
jbroman203a9932016-07-11 14:07:59 -0700920 REPORTER_ASSERT(reporter, reverseBlurBounds == expectedBlurBounds);
921
922 SkIRect expectedShadowBounds = SkIRect::MakeLTRB(0, -230, 230, 0);
923 SkIRect shadowBounds = dropShadow->filterBounds(
Robert Phillips12078432018-05-17 11:17:39 -0400924 bounds, scaleMatrix, SkImageFilter::kForward_MapDirection, nullptr);
jbroman203a9932016-07-11 14:07:59 -0700925 REPORTER_ASSERT(reporter, shadowBounds == expectedShadowBounds);
926 SkIRect expectedReverseShadowBounds =
927 SkIRect::MakeLTRB(-130, -100, 100, 130);
928 SkIRect reverseShadowBounds = dropShadow->filterBounds(
Robert Phillips12078432018-05-17 11:17:39 -0400929 bounds, scaleMatrix, SkImageFilter::kReverse_MapDirection, &bounds);
jbroman203a9932016-07-11 14:07:59 -0700930 REPORTER_ASSERT(reporter,
931 reverseShadowBounds == expectedReverseShadowBounds);
932 }
933}
934
ajuma5788faa2015-02-13 09:05:47 -0800935DEF_TEST(ImageFilterComposedBlurFastBounds, reporter) {
robertphillips6e7025a2016-04-04 04:31:25 -0700936 sk_sp<SkImageFilter> filter1(make_blur(nullptr));
937 sk_sp<SkImageFilter> filter2(make_blur(nullptr));
robertphillips491fb172016-03-30 12:32:58 -0700938 sk_sp<SkImageFilter> composedFilter(SkComposeImageFilter::Make(std::move(filter1),
939 std::move(filter2)));
ajuma5788faa2015-02-13 09:05:47 -0800940
941 SkRect boundsSrc = SkRect::MakeWH(SkIntToScalar(100), SkIntToScalar(100));
942 SkRect expectedBounds = SkRect::MakeXYWH(
Herb Derby59f8f152017-10-17 22:27:23 +0000943 SkIntToScalar(-6), SkIntToScalar(-6), SkIntToScalar(112), SkIntToScalar(112));
senorblancoe5e79842016-03-21 14:51:59 -0700944 SkRect boundsDst = composedFilter->computeFastBounds(boundsSrc);
ajuma5788faa2015-02-13 09:05:47 -0800945
946 REPORTER_ASSERT(reporter, boundsDst == expectedBounds);
947}
948
jbroman0e3129d2016-03-17 12:24:23 -0700949DEF_TEST(ImageFilterUnionBounds, reporter) {
robertphillips51a315e2016-03-31 09:05:49 -0700950 sk_sp<SkImageFilter> offset(SkOffsetImageFilter::Make(50, 0, nullptr));
jbroman0e3129d2016-03-17 12:24:23 -0700951 // Regardless of which order they appear in, the image filter bounds should
952 // be combined correctly.
953 {
reed374772b2016-10-05 17:33:02 -0700954 sk_sp<SkImageFilter> composite(SkXfermodeImageFilter::Make(SkBlendMode::kSrcOver, offset));
jbroman0e3129d2016-03-17 12:24:23 -0700955 SkRect bounds = SkRect::MakeWH(100, 100);
956 // Intentionally aliasing here, as that's what the real callers do.
senorblancoe5e79842016-03-21 14:51:59 -0700957 bounds = composite->computeFastBounds(bounds);
jbroman0e3129d2016-03-17 12:24:23 -0700958 REPORTER_ASSERT(reporter, bounds == SkRect::MakeWH(150, 100));
959 }
960 {
reed374772b2016-10-05 17:33:02 -0700961 sk_sp<SkImageFilter> composite(SkXfermodeImageFilter::Make(SkBlendMode::kSrcOver, nullptr,
robertphillips8c0326d2016-04-05 12:48:34 -0700962 offset, nullptr));
jbroman0e3129d2016-03-17 12:24:23 -0700963 SkRect bounds = SkRect::MakeWH(100, 100);
964 // Intentionally aliasing here, as that's what the real callers do.
senorblancoe5e79842016-03-21 14:51:59 -0700965 bounds = composite->computeFastBounds(bounds);
jbroman0e3129d2016-03-17 12:24:23 -0700966 REPORTER_ASSERT(reporter, bounds == SkRect::MakeWH(150, 100));
967 }
968}
969
robertphillips3e302272016-04-20 11:48:36 -0700970static void test_imagefilter_merge_result_size(skiatest::Reporter* reporter, GrContext* context) {
senorblanco4a243982015-11-25 07:06:55 -0800971 SkBitmap greenBM;
972 greenBM.allocN32Pixels(20, 20);
973 greenBM.eraseColor(SK_ColorGREEN);
reed9ce9d672016-03-17 10:51:11 -0700974 sk_sp<SkImage> greenImage(SkImage::MakeFromBitmap(greenBM));
robertphillips549c8992016-04-01 09:28:51 -0700975 sk_sp<SkImageFilter> source(SkImageSource::Make(std::move(greenImage)));
Mike Reed0bdaf052017-06-18 23:35:57 -0400976 sk_sp<SkImageFilter> merge(SkMergeImageFilter::Make(source, source));
senorblanco4a243982015-11-25 07:06:55 -0800977
robertphillips3e302272016-04-20 11:48:36 -0700978 sk_sp<SkSpecialImage> srcImg(create_empty_special_image(context, 1));
robertphillips4418dba2016-03-07 12:45:14 -0800979
Brian Osmana50205f2018-07-06 13:57:01 -0400980 SkImageFilter::OutputProperties noColorSpace(kN32_SkColorType, nullptr);
brianosman2a75e5d2016-09-22 07:15:37 -0700981 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeXYWH(0, 0, 100, 100), nullptr,
982 noColorSpace);
senorblanco4a243982015-11-25 07:06:55 -0800983 SkIPoint offset;
robertphillips4418dba2016-03-07 12:45:14 -0800984
robertphillips2302de92016-03-24 07:26:32 -0700985 sk_sp<SkSpecialImage> resultImg(merge->filterImage(srcImg.get(), ctx, &offset));
robertphillips4418dba2016-03-07 12:45:14 -0800986 REPORTER_ASSERT(reporter, resultImg);
987
988 REPORTER_ASSERT(reporter, resultImg->width() == 20 && resultImg->height() == 20);
senorblanco4a243982015-11-25 07:06:55 -0800989}
990
robertphillips4418dba2016-03-07 12:45:14 -0800991DEF_TEST(ImageFilterMergeResultSize, reporter) {
robertphillips3e302272016-04-20 11:48:36 -0700992 test_imagefilter_merge_result_size(reporter, nullptr);
robertphillips4418dba2016-03-07 12:45:14 -0800993}
994
egdanielab527a52016-06-28 08:07:26 -0700995DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterMergeResultSize_Gpu, reporter, ctxInfo) {
bsalomon8b7451a2016-05-11 06:33:06 -0700996 test_imagefilter_merge_result_size(reporter, ctxInfo.grContext());
robertphillips4418dba2016-03-07 12:45:14 -0800997}
robertphillips4418dba2016-03-07 12:45:14 -0800998
robertphillipsa8d7f0b2014-08-29 08:03:56 -0700999static void draw_blurred_rect(SkCanvas* canvas) {
senorblanco837f5322014-07-14 10:19:54 -07001000 SkPaint filterPaint;
1001 filterPaint.setColor(SK_ColorWHITE);
robertphillips6e7025a2016-04-04 04:31:25 -07001002 filterPaint.setImageFilter(SkBlurImageFilter::Make(SkIntToScalar(8), 0, nullptr));
halcanary96fcdcc2015-08-27 07:41:13 -07001003 canvas->saveLayer(nullptr, &filterPaint);
senorblanco837f5322014-07-14 10:19:54 -07001004 SkPaint whitePaint;
1005 whitePaint.setColor(SK_ColorWHITE);
1006 canvas->drawRect(SkRect::Make(SkIRect::MakeWH(4, 4)), whitePaint);
1007 canvas->restore();
1008}
1009
robertphillipsa8d7f0b2014-08-29 08:03:56 -07001010static void draw_picture_clipped(SkCanvas* canvas, const SkRect& clipRect, const SkPicture* picture) {
senorblanco837f5322014-07-14 10:19:54 -07001011 canvas->save();
1012 canvas->clipRect(clipRect);
1013 canvas->drawPicture(picture);
1014 canvas->restore();
1015}
1016
1017DEF_TEST(ImageFilterDrawTiledBlurRTree, reporter) {
1018 // Check that the blur filter when recorded with RTree acceleration,
1019 // and drawn tiled (with subsequent clip rects) exactly
1020 // matches the same filter drawn with without RTree acceleration.
1021 // This tests that the "bleed" from the blur into the otherwise-blank
1022 // tiles is correctly rendered.
1023 // Tests pass by not asserting.
1024
1025 int width = 16, height = 8;
1026 SkBitmap result1, result2;
1027 result1.allocN32Pixels(width, height);
1028 result2.allocN32Pixels(width, height);
1029 SkCanvas canvas1(result1);
1030 SkCanvas canvas2(result2);
1031 int tileSize = 8;
1032
1033 canvas1.clear(0);
1034 canvas2.clear(0);
1035
1036 SkRTreeFactory factory;
1037
1038 SkPictureRecorder recorder1, recorder2;
1039 // The only difference between these two pictures is that one has RTree aceleration.
mtklein3f3b3d02014-12-01 11:47:08 -08001040 SkCanvas* recordingCanvas1 = recorder1.beginRecording(SkIntToScalar(width),
1041 SkIntToScalar(height),
halcanary96fcdcc2015-08-27 07:41:13 -07001042 nullptr, 0);
mtklein3f3b3d02014-12-01 11:47:08 -08001043 SkCanvas* recordingCanvas2 = recorder2.beginRecording(SkIntToScalar(width),
1044 SkIntToScalar(height),
robertphillipsa8d7f0b2014-08-29 08:03:56 -07001045 &factory, 0);
1046 draw_blurred_rect(recordingCanvas1);
1047 draw_blurred_rect(recordingCanvas2);
reedca2622b2016-03-18 07:25:55 -07001048 sk_sp<SkPicture> picture1(recorder1.finishRecordingAsPicture());
1049 sk_sp<SkPicture> picture2(recorder2.finishRecordingAsPicture());
senorblanco837f5322014-07-14 10:19:54 -07001050 for (int y = 0; y < height; y += tileSize) {
1051 for (int x = 0; x < width; x += tileSize) {
1052 SkRect tileRect = SkRect::Make(SkIRect::MakeXYWH(x, y, tileSize, tileSize));
reedca2622b2016-03-18 07:25:55 -07001053 draw_picture_clipped(&canvas1, tileRect, picture1.get());
1054 draw_picture_clipped(&canvas2, tileRect, picture2.get());
senorblanco837f5322014-07-14 10:19:54 -07001055 }
1056 }
1057 for (int y = 0; y < height; y++) {
1058 int diffs = memcmp(result1.getAddr32(0, y), result2.getAddr32(0, y), result1.rowBytes());
1059 REPORTER_ASSERT(reporter, !diffs);
1060 if (diffs) {
1061 break;
1062 }
1063 }
1064}
1065
senorblanco@chromium.org91957432014-05-01 14:03:41 +00001066DEF_TEST(ImageFilterMatrixConvolution, reporter) {
1067 // Check that a 1x3 filter does not cause a spurious assert.
1068 SkScalar kernel[3] = {
1069 SkIntToScalar( 1), SkIntToScalar( 1), SkIntToScalar( 1),
1070 };
1071 SkISize kernelSize = SkISize::Make(1, 3);
1072 SkScalar gain = SK_Scalar1, bias = 0;
1073 SkIPoint kernelOffset = SkIPoint::Make(0, 0);
1074
robertphillipsef6a47b2016-04-08 08:01:20 -07001075 sk_sp<SkImageFilter> filter(SkMatrixConvolutionImageFilter::Make(
1076 kernelSize, kernel,
1077 gain, bias, kernelOffset,
1078 SkMatrixConvolutionImageFilter::kRepeat_TileMode,
1079 false, nullptr));
senorblanco@chromium.org91957432014-05-01 14:03:41 +00001080
1081 SkBitmap result;
1082 int width = 16, height = 16;
1083 result.allocN32Pixels(width, height);
1084 SkCanvas canvas(result);
1085 canvas.clear(0);
1086
1087 SkPaint paint;
robertphillipsef6a47b2016-04-08 08:01:20 -07001088 paint.setImageFilter(std::move(filter));
senorblanco@chromium.org91957432014-05-01 14:03:41 +00001089 SkRect rect = SkRect::Make(SkIRect::MakeWH(width, height));
1090 canvas.drawRect(rect, paint);
1091}
1092
senorblanco@chromium.org8c7372b2014-05-02 19:13:11 +00001093DEF_TEST(ImageFilterMatrixConvolutionBorder, reporter) {
1094 // Check that a filter with borders outside the target bounds
1095 // does not crash.
1096 SkScalar kernel[3] = {
1097 0, 0, 0,
1098 };
1099 SkISize kernelSize = SkISize::Make(3, 1);
1100 SkScalar gain = SK_Scalar1, bias = 0;
1101 SkIPoint kernelOffset = SkIPoint::Make(2, 0);
1102
robertphillipsef6a47b2016-04-08 08:01:20 -07001103 sk_sp<SkImageFilter> filter(SkMatrixConvolutionImageFilter::Make(
1104 kernelSize, kernel, gain, bias, kernelOffset,
1105 SkMatrixConvolutionImageFilter::kClamp_TileMode,
1106 true, nullptr));
senorblanco@chromium.org8c7372b2014-05-02 19:13:11 +00001107
1108 SkBitmap result;
1109
1110 int width = 10, height = 10;
1111 result.allocN32Pixels(width, height);
1112 SkCanvas canvas(result);
1113 canvas.clear(0);
1114
1115 SkPaint filterPaint;
robertphillipsef6a47b2016-04-08 08:01:20 -07001116 filterPaint.setImageFilter(std::move(filter));
senorblanco@chromium.org8c7372b2014-05-02 19:13:11 +00001117 SkRect bounds = SkRect::MakeWH(1, 10);
1118 SkRect rect = SkRect::Make(SkIRect::MakeWH(width, height));
1119 SkPaint rectPaint;
1120 canvas.saveLayer(&bounds, &filterPaint);
1121 canvas.drawRect(rect, rectPaint);
1122 canvas.restore();
1123}
1124
robertphillips3e302272016-04-20 11:48:36 -07001125static void test_big_kernel(skiatest::Reporter* reporter, GrContext* context) {
robertphillipsdada4dd2016-04-13 04:54:36 -07001126 // Check that a kernel that is too big for the GPU still works
1127 SkScalar identityKernel[49] = {
1128 0, 0, 0, 0, 0, 0, 0,
1129 0, 0, 0, 0, 0, 0, 0,
1130 0, 0, 0, 0, 0, 0, 0,
1131 0, 0, 0, 1, 0, 0, 0,
1132 0, 0, 0, 0, 0, 0, 0,
1133 0, 0, 0, 0, 0, 0, 0,
1134 0, 0, 0, 0, 0, 0, 0
1135 };
1136 SkISize kernelSize = SkISize::Make(7, 7);
1137 SkScalar gain = SK_Scalar1, bias = 0;
1138 SkIPoint kernelOffset = SkIPoint::Make(0, 0);
1139
1140 sk_sp<SkImageFilter> filter(SkMatrixConvolutionImageFilter::Make(
1141 kernelSize, identityKernel, gain, bias, kernelOffset,
1142 SkMatrixConvolutionImageFilter::kClamp_TileMode,
1143 true, nullptr));
1144
robertphillips3e302272016-04-20 11:48:36 -07001145 sk_sp<SkSpecialImage> srcImg(create_empty_special_image(context, 100));
robertphillipsdada4dd2016-04-13 04:54:36 -07001146 SkASSERT(srcImg);
1147
1148 SkIPoint offset;
Brian Osmana50205f2018-07-06 13:57:01 -04001149 SkImageFilter::OutputProperties noColorSpace(kN32_SkColorType, nullptr);
brianosman2a75e5d2016-09-22 07:15:37 -07001150 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeWH(100, 100), nullptr, noColorSpace);
robertphillipsdada4dd2016-04-13 04:54:36 -07001151 sk_sp<SkSpecialImage> resultImg(filter->filterImage(srcImg.get(), ctx, &offset));
1152 REPORTER_ASSERT(reporter, resultImg);
1153 REPORTER_ASSERT(reporter, SkToBool(context) == resultImg->isTextureBacked());
1154 REPORTER_ASSERT(reporter, resultImg->width() == 100 && resultImg->height() == 100);
1155 REPORTER_ASSERT(reporter, offset.fX == 0 && offset.fY == 0);
1156}
1157
1158DEF_TEST(ImageFilterMatrixConvolutionBigKernel, reporter) {
robertphillips3e302272016-04-20 11:48:36 -07001159 test_big_kernel(reporter, nullptr);
robertphillipsdada4dd2016-04-13 04:54:36 -07001160}
1161
egdanielab527a52016-06-28 08:07:26 -07001162DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterMatrixConvolutionBigKernel_Gpu,
1163 reporter, ctxInfo) {
bsalomon8b7451a2016-05-11 06:33:06 -07001164 test_big_kernel(reporter, ctxInfo.grContext());
robertphillipsdada4dd2016-04-13 04:54:36 -07001165}
robertphillipsdada4dd2016-04-13 04:54:36 -07001166
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +00001167DEF_TEST(ImageFilterCropRect, reporter) {
robertphillips3e302272016-04-20 11:48:36 -07001168 test_crop_rects(reporter, nullptr);
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +00001169}
1170
bsalomon68d91342016-04-12 09:59:58 -07001171DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterCropRect_Gpu, reporter, ctxInfo) {
bsalomon8b7451a2016-05-11 06:33:06 -07001172 test_crop_rects(reporter, ctxInfo.grContext());
robertphillips4418dba2016-03-07 12:45:14 -08001173}
robertphillips4418dba2016-03-07 12:45:14 -08001174
tfarina9ea53f92014-06-24 06:50:39 -07001175DEF_TEST(ImageFilterMatrix, reporter) {
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +00001176 SkBitmap temp;
mike@reedtribe.orgdeee4962014-02-13 14:41:43 +00001177 temp.allocN32Pixels(100, 100);
robertphillips9a53fd72015-06-22 09:46:59 -07001178 SkCanvas canvas(temp);
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +00001179 canvas.scale(SkIntToScalar(2), SkIntToScalar(2));
1180
1181 SkMatrix expectedMatrix = canvas.getTotalMatrix();
1182
commit-bot@chromium.org5fb2ce32014-04-17 23:35:06 +00001183 SkRTreeFactory factory;
1184 SkPictureRecorder recorder;
1185 SkCanvas* recordingCanvas = recorder.beginRecording(100, 100, &factory, 0);
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +00001186
1187 SkPaint paint;
robertphillips43c2ad42016-04-04 05:05:11 -07001188 paint.setImageFilter(MatrixTestImageFilter::Make(reporter, expectedMatrix));
halcanary96fcdcc2015-08-27 07:41:13 -07001189 recordingCanvas->saveLayer(nullptr, &paint);
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +00001190 SkPaint solidPaint;
1191 solidPaint.setColor(0xFFFFFFFF);
1192 recordingCanvas->save();
1193 recordingCanvas->scale(SkIntToScalar(10), SkIntToScalar(10));
1194 recordingCanvas->drawRect(SkRect::Make(SkIRect::MakeWH(100, 100)), solidPaint);
1195 recordingCanvas->restore(); // scale
1196 recordingCanvas->restore(); // saveLayer
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +00001197
reedca2622b2016-03-18 07:25:55 -07001198 canvas.drawPicture(recorder.finishRecordingAsPicture());
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +00001199}
1200
robertphillips3e302272016-04-20 11:48:36 -07001201static void test_clipped_picture_imagefilter(skiatest::Reporter* reporter, GrContext* context) {
reedca2622b2016-03-18 07:25:55 -07001202 sk_sp<SkPicture> picture;
senorblanco3d822c22014-07-30 14:49:31 -07001203
robertphillips4418dba2016-03-07 12:45:14 -08001204 {
1205 SkRTreeFactory factory;
1206 SkPictureRecorder recorder;
1207 SkCanvas* recordingCanvas = recorder.beginRecording(1, 1, &factory, 0);
1208
1209 // Create an SkPicture which simply draws a green 1x1 rectangle.
1210 SkPaint greenPaint;
1211 greenPaint.setColor(SK_ColorGREEN);
1212 recordingCanvas->drawRect(SkRect::Make(SkIRect::MakeWH(1, 1)), greenPaint);
reedca2622b2016-03-18 07:25:55 -07001213 picture = recorder.finishRecordingAsPicture();
robertphillips4418dba2016-03-07 12:45:14 -08001214 }
1215
robertphillips3e302272016-04-20 11:48:36 -07001216 sk_sp<SkSpecialImage> srcImg(create_empty_special_image(context, 2));
senorblanco3d822c22014-07-30 14:49:31 -07001217
robertphillips5ff17b12016-03-28 13:13:42 -07001218 sk_sp<SkImageFilter> imageFilter(SkPictureImageFilter::Make(picture));
senorblanco3d822c22014-07-30 14:49:31 -07001219
senorblanco3d822c22014-07-30 14:49:31 -07001220 SkIPoint offset;
Brian Osmana50205f2018-07-06 13:57:01 -04001221 SkImageFilter::OutputProperties noColorSpace(kN32_SkColorType, nullptr);
brianosman2a75e5d2016-09-22 07:15:37 -07001222 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeXYWH(1, 1, 1, 1), nullptr, noColorSpace);
robertphillips4418dba2016-03-07 12:45:14 -08001223
robertphillips2302de92016-03-24 07:26:32 -07001224 sk_sp<SkSpecialImage> resultImage(imageFilter->filterImage(srcImg.get(), ctx, &offset));
robertphillips4418dba2016-03-07 12:45:14 -08001225 REPORTER_ASSERT(reporter, !resultImage);
senorblanco3d822c22014-07-30 14:49:31 -07001226}
1227
robertphillips4418dba2016-03-07 12:45:14 -08001228DEF_TEST(ImageFilterClippedPictureImageFilter, reporter) {
robertphillips3e302272016-04-20 11:48:36 -07001229 test_clipped_picture_imagefilter(reporter, nullptr);
robertphillips4418dba2016-03-07 12:45:14 -08001230}
1231
bsalomon68d91342016-04-12 09:59:58 -07001232DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterClippedPictureImageFilter_Gpu, reporter, ctxInfo) {
bsalomon8b7451a2016-05-11 06:33:06 -07001233 test_clipped_picture_imagefilter(reporter, ctxInfo.grContext());
robertphillips4418dba2016-03-07 12:45:14 -08001234}
robertphillips4418dba2016-03-07 12:45:14 -08001235
tfarina9ea53f92014-06-24 06:50:39 -07001236DEF_TEST(ImageFilterEmptySaveLayer, reporter) {
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001237 // Even when there's an empty saveLayer()/restore(), ensure that an image
1238 // filter or color filter which affects transparent black still draws.
1239
1240 SkBitmap bitmap;
1241 bitmap.allocN32Pixels(10, 10);
robertphillips9a53fd72015-06-22 09:46:59 -07001242 SkCanvas canvas(bitmap);
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001243
1244 SkRTreeFactory factory;
1245 SkPictureRecorder recorder;
1246
robertphillips5605b562016-04-05 11:50:42 -07001247 sk_sp<SkColorFilter> green(SkColorFilter::MakeModeFilter(SK_ColorGREEN,
Mike Reed7d954ad2016-10-28 15:42:34 -04001248 SkBlendMode::kSrc));
robertphillips5605b562016-04-05 11:50:42 -07001249 sk_sp<SkImageFilter> imageFilter(SkColorFilterImageFilter::Make(green, nullptr));
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001250 SkPaint imageFilterPaint;
robertphillips5605b562016-04-05 11:50:42 -07001251 imageFilterPaint.setImageFilter(std::move(imageFilter));
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001252 SkPaint colorFilterPaint;
reedd053ce92016-03-22 10:17:23 -07001253 colorFilterPaint.setColorFilter(green);
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001254
1255 SkRect bounds = SkRect::MakeWH(10, 10);
1256
1257 SkCanvas* recordingCanvas = recorder.beginRecording(10, 10, &factory, 0);
1258 recordingCanvas->saveLayer(&bounds, &imageFilterPaint);
1259 recordingCanvas->restore();
reedca2622b2016-03-18 07:25:55 -07001260 sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture());
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001261
1262 canvas.clear(0);
robertphillips9b14f262014-06-04 05:40:44 -07001263 canvas.drawPicture(picture);
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001264 uint32_t pixel = *bitmap.getAddr32(0, 0);
1265 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1266
1267 recordingCanvas = recorder.beginRecording(10, 10, &factory, 0);
halcanary96fcdcc2015-08-27 07:41:13 -07001268 recordingCanvas->saveLayer(nullptr, &imageFilterPaint);
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001269 recordingCanvas->restore();
reedca2622b2016-03-18 07:25:55 -07001270 sk_sp<SkPicture> picture2(recorder.finishRecordingAsPicture());
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001271
1272 canvas.clear(0);
robertphillips9b14f262014-06-04 05:40:44 -07001273 canvas.drawPicture(picture2);
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001274 pixel = *bitmap.getAddr32(0, 0);
1275 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1276
1277 recordingCanvas = recorder.beginRecording(10, 10, &factory, 0);
1278 recordingCanvas->saveLayer(&bounds, &colorFilterPaint);
1279 recordingCanvas->restore();
reedca2622b2016-03-18 07:25:55 -07001280 sk_sp<SkPicture> picture3(recorder.finishRecordingAsPicture());
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001281
1282 canvas.clear(0);
robertphillips9b14f262014-06-04 05:40:44 -07001283 canvas.drawPicture(picture3);
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001284 pixel = *bitmap.getAddr32(0, 0);
1285 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1286}
1287
robertphillips9a53fd72015-06-22 09:46:59 -07001288static void test_huge_blur(SkCanvas* canvas, skiatest::Reporter* reporter) {
senorblanco@chromium.org09843fd2014-03-24 20:50:59 +00001289 SkBitmap bitmap;
1290 bitmap.allocN32Pixels(100, 100);
1291 bitmap.eraseARGB(0, 0, 0, 0);
1292
1293 // Check that a blur with an insane radius does not crash or assert.
senorblanco@chromium.org09843fd2014-03-24 20:50:59 +00001294 SkPaint paint;
robertphillips6e7025a2016-04-04 04:31:25 -07001295 paint.setImageFilter(SkBlurImageFilter::Make(SkIntToScalar(1<<30),
1296 SkIntToScalar(1<<30),
1297 nullptr));
reedda420b92015-12-16 08:38:15 -08001298 canvas->drawBitmap(bitmap, 0, 0, &paint);
senorblanco@chromium.org09843fd2014-03-24 20:50:59 +00001299}
1300
1301DEF_TEST(HugeBlurImageFilter, reporter) {
1302 SkBitmap temp;
1303 temp.allocN32Pixels(100, 100);
robertphillips9a53fd72015-06-22 09:46:59 -07001304 SkCanvas canvas(temp);
1305 test_huge_blur(&canvas, reporter);
senorblanco@chromium.org09843fd2014-03-24 20:50:59 +00001306}
1307
senorblanco21a465d2016-04-11 11:58:39 -07001308DEF_TEST(ImageFilterMatrixConvolutionSanityTest, reporter) {
senorblanco3a495202014-09-29 07:57:20 -07001309 SkScalar kernel[1] = { 0 };
1310 SkScalar gain = SK_Scalar1, bias = 0;
1311 SkIPoint kernelOffset = SkIPoint::Make(1, 1);
1312
halcanary96fcdcc2015-08-27 07:41:13 -07001313 // Check that an enormous (non-allocatable) kernel gives a nullptr filter.
robertphillipsef6a47b2016-04-08 08:01:20 -07001314 sk_sp<SkImageFilter> conv(SkMatrixConvolutionImageFilter::Make(
senorblanco3a495202014-09-29 07:57:20 -07001315 SkISize::Make(1<<30, 1<<30),
1316 kernel,
1317 gain,
1318 bias,
1319 kernelOffset,
1320 SkMatrixConvolutionImageFilter::kRepeat_TileMode,
robertphillipsef6a47b2016-04-08 08:01:20 -07001321 false,
1322 nullptr));
senorblanco3a495202014-09-29 07:57:20 -07001323
halcanary96fcdcc2015-08-27 07:41:13 -07001324 REPORTER_ASSERT(reporter, nullptr == conv.get());
senorblanco3a495202014-09-29 07:57:20 -07001325
halcanary96fcdcc2015-08-27 07:41:13 -07001326 // Check that a nullptr kernel gives a nullptr filter.
robertphillipsef6a47b2016-04-08 08:01:20 -07001327 conv = SkMatrixConvolutionImageFilter::Make(
senorblanco3a495202014-09-29 07:57:20 -07001328 SkISize::Make(1, 1),
halcanary96fcdcc2015-08-27 07:41:13 -07001329 nullptr,
senorblanco3a495202014-09-29 07:57:20 -07001330 gain,
1331 bias,
1332 kernelOffset,
1333 SkMatrixConvolutionImageFilter::kRepeat_TileMode,
robertphillipsef6a47b2016-04-08 08:01:20 -07001334 false,
1335 nullptr);
senorblanco3a495202014-09-29 07:57:20 -07001336
halcanary96fcdcc2015-08-27 07:41:13 -07001337 REPORTER_ASSERT(reporter, nullptr == conv.get());
senorblanco3a495202014-09-29 07:57:20 -07001338
halcanary96fcdcc2015-08-27 07:41:13 -07001339 // Check that a kernel width < 1 gives a nullptr filter.
robertphillipsef6a47b2016-04-08 08:01:20 -07001340 conv = SkMatrixConvolutionImageFilter::Make(
senorblanco3a495202014-09-29 07:57:20 -07001341 SkISize::Make(0, 1),
1342 kernel,
1343 gain,
1344 bias,
1345 kernelOffset,
1346 SkMatrixConvolutionImageFilter::kRepeat_TileMode,
robertphillipsef6a47b2016-04-08 08:01:20 -07001347 false,
1348 nullptr);
senorblanco3a495202014-09-29 07:57:20 -07001349
halcanary96fcdcc2015-08-27 07:41:13 -07001350 REPORTER_ASSERT(reporter, nullptr == conv.get());
senorblanco3a495202014-09-29 07:57:20 -07001351
halcanary96fcdcc2015-08-27 07:41:13 -07001352 // Check that kernel height < 1 gives a nullptr filter.
robertphillipsef6a47b2016-04-08 08:01:20 -07001353 conv = SkMatrixConvolutionImageFilter::Make(
senorblanco3a495202014-09-29 07:57:20 -07001354 SkISize::Make(1, -1),
1355 kernel,
1356 gain,
1357 bias,
1358 kernelOffset,
1359 SkMatrixConvolutionImageFilter::kRepeat_TileMode,
robertphillipsef6a47b2016-04-08 08:01:20 -07001360 false,
1361 nullptr);
senorblanco3a495202014-09-29 07:57:20 -07001362
halcanary96fcdcc2015-08-27 07:41:13 -07001363 REPORTER_ASSERT(reporter, nullptr == conv.get());
senorblanco3a495202014-09-29 07:57:20 -07001364}
1365
Mike Reedf1942192017-07-21 14:24:29 -04001366static void test_xfermode_cropped_input(SkSurface* surf, skiatest::Reporter* reporter) {
1367 auto canvas = surf->getCanvas();
robertphillips9a53fd72015-06-22 09:46:59 -07001368 canvas->clear(0);
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001369
1370 SkBitmap bitmap;
1371 bitmap.allocN32Pixels(1, 1);
1372 bitmap.eraseARGB(255, 255, 255, 255);
1373
robertphillips5605b562016-04-05 11:50:42 -07001374 sk_sp<SkColorFilter> green(SkColorFilter::MakeModeFilter(SK_ColorGREEN,
Mike Reed7d954ad2016-10-28 15:42:34 -04001375 SkBlendMode::kSrcIn));
robertphillips5605b562016-04-05 11:50:42 -07001376 sk_sp<SkImageFilter> greenFilter(SkColorFilterImageFilter::Make(green, nullptr));
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001377 SkImageFilter::CropRect cropRect(SkRect::MakeEmpty());
robertphillips5605b562016-04-05 11:50:42 -07001378 sk_sp<SkImageFilter> croppedOut(SkColorFilterImageFilter::Make(green, nullptr, &cropRect));
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001379
1380 // Check that an xfermode image filter whose input has been cropped out still draws the other
1381 // input. Also check that drawing with both inputs cropped out doesn't cause a GPU warning.
reed374772b2016-10-05 17:33:02 -07001382 SkBlendMode mode = SkBlendMode::kSrcOver;
robertphillips8c0326d2016-04-05 12:48:34 -07001383 sk_sp<SkImageFilter> xfermodeNoFg(SkXfermodeImageFilter::Make(mode, greenFilter,
1384 croppedOut, nullptr));
1385 sk_sp<SkImageFilter> xfermodeNoBg(SkXfermodeImageFilter::Make(mode, croppedOut,
1386 greenFilter, nullptr));
1387 sk_sp<SkImageFilter> xfermodeNoFgNoBg(SkXfermodeImageFilter::Make(mode, croppedOut,
1388 croppedOut, nullptr));
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001389
1390 SkPaint paint;
robertphillips8c0326d2016-04-05 12:48:34 -07001391 paint.setImageFilter(std::move(xfermodeNoFg));
reedda420b92015-12-16 08:38:15 -08001392 canvas->drawBitmap(bitmap, 0, 0, &paint); // drawSprite
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001393
1394 uint32_t pixel;
kkinnunena9d9a392015-03-06 07:16:00 -08001395 SkImageInfo info = SkImageInfo::Make(1, 1, kBGRA_8888_SkColorType, kUnpremul_SkAlphaType);
Mike Reedf1942192017-07-21 14:24:29 -04001396 surf->readPixels(info, &pixel, 4, 0, 0);
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001397 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1398
robertphillips8c0326d2016-04-05 12:48:34 -07001399 paint.setImageFilter(std::move(xfermodeNoBg));
reedda420b92015-12-16 08:38:15 -08001400 canvas->drawBitmap(bitmap, 0, 0, &paint); // drawSprite
Mike Reedf1942192017-07-21 14:24:29 -04001401 surf->readPixels(info, &pixel, 4, 0, 0);
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001402 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1403
robertphillips8c0326d2016-04-05 12:48:34 -07001404 paint.setImageFilter(std::move(xfermodeNoFgNoBg));
reedda420b92015-12-16 08:38:15 -08001405 canvas->drawBitmap(bitmap, 0, 0, &paint); // drawSprite
Mike Reedf1942192017-07-21 14:24:29 -04001406 surf->readPixels(info, &pixel, 4, 0, 0);
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001407 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1408}
1409
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001410DEF_TEST(ImageFilterNestedSaveLayer, reporter) {
1411 SkBitmap temp;
1412 temp.allocN32Pixels(50, 50);
robertphillips9a53fd72015-06-22 09:46:59 -07001413 SkCanvas canvas(temp);
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001414 canvas.clear(0x0);
1415
1416 SkBitmap bitmap;
1417 bitmap.allocN32Pixels(10, 10);
1418 bitmap.eraseColor(SK_ColorGREEN);
1419
1420 SkMatrix matrix;
1421 matrix.setScale(SkIntToScalar(2), SkIntToScalar(2));
1422 matrix.postTranslate(SkIntToScalar(-20), SkIntToScalar(-20));
robertphillipsae8c9332016-04-05 15:09:00 -07001423 sk_sp<SkImageFilter> matrixFilter(
1424 SkImageFilter::MakeMatrixFilter(matrix, kLow_SkFilterQuality, nullptr));
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001425
1426 // Test that saveLayer() with a filter nested inside another saveLayer() applies the
1427 // correct offset to the filter matrix.
1428 SkRect bounds1 = SkRect::MakeXYWH(10, 10, 30, 30);
halcanary96fcdcc2015-08-27 07:41:13 -07001429 canvas.saveLayer(&bounds1, nullptr);
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001430 SkPaint filterPaint;
robertphillipsae8c9332016-04-05 15:09:00 -07001431 filterPaint.setImageFilter(std::move(matrixFilter));
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001432 SkRect bounds2 = SkRect::MakeXYWH(20, 20, 10, 10);
1433 canvas.saveLayer(&bounds2, &filterPaint);
1434 SkPaint greenPaint;
1435 greenPaint.setColor(SK_ColorGREEN);
1436 canvas.drawRect(bounds2, greenPaint);
1437 canvas.restore();
1438 canvas.restore();
1439 SkPaint strokePaint;
1440 strokePaint.setStyle(SkPaint::kStroke_Style);
1441 strokePaint.setColor(SK_ColorRED);
1442
kkinnunena9d9a392015-03-06 07:16:00 -08001443 SkImageInfo info = SkImageInfo::Make(1, 1, kBGRA_8888_SkColorType, kUnpremul_SkAlphaType);
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001444 uint32_t pixel;
Mike Reedf1942192017-07-21 14:24:29 -04001445 temp.readPixels(info, &pixel, 4, 25, 25);
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001446 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1447
1448 // Test that drawSprite() with a filter nested inside a saveLayer() applies the
1449 // correct offset to the filter matrix.
1450 canvas.clear(0x0);
Mike Reedf1942192017-07-21 14:24:29 -04001451 temp.readPixels(info, &pixel, 4, 25, 25);
halcanary96fcdcc2015-08-27 07:41:13 -07001452 canvas.saveLayer(&bounds1, nullptr);
reedda420b92015-12-16 08:38:15 -08001453 canvas.drawBitmap(bitmap, 20, 20, &filterPaint); // drawSprite
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001454 canvas.restore();
1455
Mike Reedf1942192017-07-21 14:24:29 -04001456 temp.readPixels(info, &pixel, 4, 25, 25);
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001457 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1458}
1459
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001460DEF_TEST(XfermodeImageFilterCroppedInput, reporter) {
Mike Reedf1942192017-07-21 14:24:29 -04001461 test_xfermode_cropped_input(SkSurface::MakeRasterN32Premul(100, 100).get(), reporter);
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001462}
senorblanco@chromium.org09843fd2014-03-24 20:50:59 +00001463
robertphillips3e302272016-04-20 11:48:36 -07001464static void test_composed_imagefilter_offset(skiatest::Reporter* reporter, GrContext* context) {
1465 sk_sp<SkSpecialImage> srcImg(create_empty_special_image(context, 100));
ajuma5788faa2015-02-13 09:05:47 -08001466
1467 SkImageFilter::CropRect cropRect(SkRect::MakeXYWH(1, 0, 20, 20));
robertphillips51a315e2016-03-31 09:05:49 -07001468 sk_sp<SkImageFilter> offsetFilter(SkOffsetImageFilter::Make(0, 0, nullptr, &cropRect));
robertphillips6e7025a2016-04-04 04:31:25 -07001469 sk_sp<SkImageFilter> blurFilter(SkBlurImageFilter::Make(SK_Scalar1, SK_Scalar1,
1470 nullptr, &cropRect));
robertphillips491fb172016-03-30 12:32:58 -07001471 sk_sp<SkImageFilter> composedFilter(SkComposeImageFilter::Make(std::move(blurFilter),
1472 std::move(offsetFilter)));
ajuma5788faa2015-02-13 09:05:47 -08001473 SkIPoint offset;
Brian Osmana50205f2018-07-06 13:57:01 -04001474 SkImageFilter::OutputProperties noColorSpace(kN32_SkColorType, nullptr);
brianosman2a75e5d2016-09-22 07:15:37 -07001475 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeWH(100, 100), nullptr, noColorSpace);
robertphillips4418dba2016-03-07 12:45:14 -08001476
robertphillips2302de92016-03-24 07:26:32 -07001477 sk_sp<SkSpecialImage> resultImg(composedFilter->filterImage(srcImg.get(), ctx, &offset));
robertphillips4418dba2016-03-07 12:45:14 -08001478 REPORTER_ASSERT(reporter, resultImg);
ajuma5788faa2015-02-13 09:05:47 -08001479 REPORTER_ASSERT(reporter, offset.fX == 1 && offset.fY == 0);
1480}
1481
robertphillips4418dba2016-03-07 12:45:14 -08001482DEF_TEST(ComposedImageFilterOffset, reporter) {
robertphillips3e302272016-04-20 11:48:36 -07001483 test_composed_imagefilter_offset(reporter, nullptr);
robertphillips4418dba2016-03-07 12:45:14 -08001484}
1485
bsalomon68d91342016-04-12 09:59:58 -07001486DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ComposedImageFilterOffset_Gpu, reporter, ctxInfo) {
bsalomon8b7451a2016-05-11 06:33:06 -07001487 test_composed_imagefilter_offset(reporter, ctxInfo.grContext());
robertphillips4418dba2016-03-07 12:45:14 -08001488}
robertphillips4418dba2016-03-07 12:45:14 -08001489
robertphillips3e302272016-04-20 11:48:36 -07001490static void test_composed_imagefilter_bounds(skiatest::Reporter* reporter, GrContext* context) {
jbroman17a65202016-03-21 08:38:58 -07001491 // The bounds passed to the inner filter must be filtered by the outer
1492 // filter, so that the inner filter produces the pixels that the outer
1493 // filter requires as input. This matters if the outer filter moves pixels.
1494 // Here, accounting for the outer offset is necessary so that the green
1495 // pixels of the picture are not clipped.
1496
1497 SkPictureRecorder recorder;
1498 SkCanvas* recordingCanvas = recorder.beginRecording(SkRect::MakeWH(200, 100));
1499 recordingCanvas->clipRect(SkRect::MakeXYWH(100, 0, 100, 100));
1500 recordingCanvas->clear(SK_ColorGREEN);
robertphillips491fb172016-03-30 12:32:58 -07001501 sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture());
robertphillips5ff17b12016-03-28 13:13:42 -07001502 sk_sp<SkImageFilter> pictureFilter(SkPictureImageFilter::Make(picture));
jbroman17a65202016-03-21 08:38:58 -07001503 SkImageFilter::CropRect cropRect(SkRect::MakeWH(100, 100));
robertphillips51a315e2016-03-31 09:05:49 -07001504 sk_sp<SkImageFilter> offsetFilter(SkOffsetImageFilter::Make(-100, 0, nullptr, &cropRect));
robertphillips491fb172016-03-30 12:32:58 -07001505 sk_sp<SkImageFilter> composedFilter(SkComposeImageFilter::Make(std::move(offsetFilter),
1506 std::move(pictureFilter)));
jbroman17a65202016-03-21 08:38:58 -07001507
robertphillips3e302272016-04-20 11:48:36 -07001508 sk_sp<SkSpecialImage> sourceImage(create_empty_special_image(context, 100));
Brian Osmana50205f2018-07-06 13:57:01 -04001509 SkImageFilter::OutputProperties noColorSpace(kN32_SkColorType, nullptr);
brianosman2a75e5d2016-09-22 07:15:37 -07001510 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeWH(100, 100), nullptr, noColorSpace);
jbroman17a65202016-03-21 08:38:58 -07001511 SkIPoint offset;
1512 sk_sp<SkSpecialImage> result(composedFilter->filterImage(sourceImage.get(), ctx, &offset));
1513 REPORTER_ASSERT(reporter, offset.isZero());
1514 REPORTER_ASSERT(reporter, result);
1515 REPORTER_ASSERT(reporter, result->subset().size() == SkISize::Make(100, 100));
1516
1517 SkBitmap resultBM;
robertphillips64612512016-04-08 12:10:42 -07001518 REPORTER_ASSERT(reporter, result->getROPixels(&resultBM));
jbroman17a65202016-03-21 08:38:58 -07001519 REPORTER_ASSERT(reporter, resultBM.getColor(50, 50) == SK_ColorGREEN);
1520}
1521
1522DEF_TEST(ComposedImageFilterBounds, reporter) {
robertphillips3e302272016-04-20 11:48:36 -07001523 test_composed_imagefilter_bounds(reporter, nullptr);
jbroman17a65202016-03-21 08:38:58 -07001524}
1525
egdanielab527a52016-06-28 08:07:26 -07001526DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ComposedImageFilterBounds_Gpu, reporter, ctxInfo) {
bsalomon8b7451a2016-05-11 06:33:06 -07001527 test_composed_imagefilter_bounds(reporter, ctxInfo.grContext());
jbroman17a65202016-03-21 08:38:58 -07001528}
jbroman17a65202016-03-21 08:38:58 -07001529
robertphillips3e302272016-04-20 11:48:36 -07001530static void test_partial_crop_rect(skiatest::Reporter* reporter, GrContext* context) {
1531 sk_sp<SkSpecialImage> srcImg(create_empty_special_image(context, 100));
senorblanco24d2a7b2015-07-13 10:27:05 -07001532
1533 SkImageFilter::CropRect cropRect(SkRect::MakeXYWH(100, 0, 20, 30),
senorblancoed7cf272015-07-16 15:19:11 -07001534 SkImageFilter::CropRect::kHasWidth_CropEdge | SkImageFilter::CropRect::kHasHeight_CropEdge);
robertphillips5605b562016-04-05 11:50:42 -07001535 sk_sp<SkImageFilter> filter(make_grayscale(nullptr, &cropRect));
senorblanco24d2a7b2015-07-13 10:27:05 -07001536 SkIPoint offset;
Brian Osmana50205f2018-07-06 13:57:01 -04001537 SkImageFilter::OutputProperties noColorSpace(kN32_SkColorType, nullptr);
brianosman2a75e5d2016-09-22 07:15:37 -07001538 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeWH(100, 100), nullptr, noColorSpace);
robertphillips4418dba2016-03-07 12:45:14 -08001539
robertphillips2302de92016-03-24 07:26:32 -07001540 sk_sp<SkSpecialImage> resultImg(filter->filterImage(srcImg.get(), ctx, &offset));
robertphillips4418dba2016-03-07 12:45:14 -08001541 REPORTER_ASSERT(reporter, resultImg);
1542
senorblanco24d2a7b2015-07-13 10:27:05 -07001543 REPORTER_ASSERT(reporter, offset.fX == 0);
1544 REPORTER_ASSERT(reporter, offset.fY == 0);
robertphillips4418dba2016-03-07 12:45:14 -08001545 REPORTER_ASSERT(reporter, resultImg->width() == 20);
1546 REPORTER_ASSERT(reporter, resultImg->height() == 30);
senorblanco24d2a7b2015-07-13 10:27:05 -07001547}
1548
senorblanco21a465d2016-04-11 11:58:39 -07001549DEF_TEST(ImageFilterPartialCropRect, reporter) {
robertphillips3e302272016-04-20 11:48:36 -07001550 test_partial_crop_rect(reporter, nullptr);
robertphillips4418dba2016-03-07 12:45:14 -08001551}
1552
bsalomon68d91342016-04-12 09:59:58 -07001553DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterPartialCropRect_Gpu, reporter, ctxInfo) {
bsalomon8b7451a2016-05-11 06:33:06 -07001554 test_partial_crop_rect(reporter, ctxInfo.grContext());
robertphillips4418dba2016-03-07 12:45:14 -08001555}
robertphillips4418dba2016-03-07 12:45:14 -08001556
senorblanco0abdf762015-08-20 11:10:41 -07001557DEF_TEST(ImageFilterCanComputeFastBounds, reporter) {
1558
robertphillips12fa47d2016-04-08 16:28:09 -07001559 {
1560 SkPoint3 location = SkPoint3::Make(0, 0, SK_Scalar1);
1561 sk_sp<SkImageFilter> lighting(SkLightingImageFilter::MakePointLitDiffuse(location,
1562 SK_ColorGREEN,
1563 0, 0, nullptr));
1564 REPORTER_ASSERT(reporter, !lighting->canComputeFastBounds());
1565 }
senorblanco0abdf762015-08-20 11:10:41 -07001566
senorblanco0abdf762015-08-20 11:10:41 -07001567 {
robertphillips6e7025a2016-04-04 04:31:25 -07001568 sk_sp<SkImageFilter> gray(make_grayscale(nullptr, nullptr));
1569 REPORTER_ASSERT(reporter, gray->canComputeFastBounds());
1570 {
1571 SkColorFilter* grayCF;
1572 REPORTER_ASSERT(reporter, gray->asAColorFilter(&grayCF));
1573 REPORTER_ASSERT(reporter, !grayCF->affectsTransparentBlack());
1574 grayCF->unref();
1575 }
1576 REPORTER_ASSERT(reporter, gray->canComputeFastBounds());
1577
1578 sk_sp<SkImageFilter> grayBlur(SkBlurImageFilter::Make(SK_Scalar1, SK_Scalar1,
1579 std::move(gray)));
1580 REPORTER_ASSERT(reporter, grayBlur->canComputeFastBounds());
senorblanco0abdf762015-08-20 11:10:41 -07001581 }
senorblanco0abdf762015-08-20 11:10:41 -07001582
robertphillips6e7025a2016-04-04 04:31:25 -07001583 {
1584 SkScalar greenMatrix[20] = { 0, 0, 0, 0, 0,
1585 0, 0, 0, 0, 1,
1586 0, 0, 0, 0, 0,
1587 0, 0, 0, 0, 1 };
1588 sk_sp<SkColorFilter> greenCF(SkColorFilter::MakeMatrixFilterRowMajor255(greenMatrix));
robertphillips5605b562016-04-05 11:50:42 -07001589 sk_sp<SkImageFilter> green(SkColorFilterImageFilter::Make(greenCF, nullptr));
senorblanco0abdf762015-08-20 11:10:41 -07001590
robertphillips6e7025a2016-04-04 04:31:25 -07001591 REPORTER_ASSERT(reporter, greenCF->affectsTransparentBlack());
1592 REPORTER_ASSERT(reporter, !green->canComputeFastBounds());
senorblanco0abdf762015-08-20 11:10:41 -07001593
robertphillips6e7025a2016-04-04 04:31:25 -07001594 sk_sp<SkImageFilter> greenBlur(SkBlurImageFilter::Make(SK_Scalar1, SK_Scalar1,
1595 std::move(green)));
1596 REPORTER_ASSERT(reporter, !greenBlur->canComputeFastBounds());
1597 }
senorblanco0abdf762015-08-20 11:10:41 -07001598
1599 uint8_t allOne[256], identity[256];
1600 for (int i = 0; i < 256; ++i) {
1601 identity[i] = i;
1602 allOne[i] = 255;
1603 }
1604
robertphillips5605b562016-04-05 11:50:42 -07001605 sk_sp<SkColorFilter> identityCF(SkTableColorFilter::MakeARGB(identity, identity,
1606 identity, allOne));
1607 sk_sp<SkImageFilter> identityFilter(SkColorFilterImageFilter::Make(identityCF, nullptr));
senorblanco0abdf762015-08-20 11:10:41 -07001608 REPORTER_ASSERT(reporter, !identityCF->affectsTransparentBlack());
1609 REPORTER_ASSERT(reporter, identityFilter->canComputeFastBounds());
1610
robertphillips5605b562016-04-05 11:50:42 -07001611 sk_sp<SkColorFilter> forceOpaqueCF(SkTableColorFilter::MakeARGB(allOne, identity,
1612 identity, identity));
1613 sk_sp<SkImageFilter> forceOpaque(SkColorFilterImageFilter::Make(forceOpaqueCF, nullptr));
senorblanco0abdf762015-08-20 11:10:41 -07001614 REPORTER_ASSERT(reporter, forceOpaqueCF->affectsTransparentBlack());
1615 REPORTER_ASSERT(reporter, !forceOpaque->canComputeFastBounds());
1616}
1617
fmalitacd56f812015-09-14 13:31:18 -07001618// Verify that SkImageSource survives serialization
1619DEF_TEST(ImageFilterImageSourceSerialization, reporter) {
reede8f30622016-03-23 18:59:25 -07001620 auto surface(SkSurface::MakeRasterN32Premul(10, 10));
fmalitacd56f812015-09-14 13:31:18 -07001621 surface->getCanvas()->clear(SK_ColorGREEN);
reed9ce9d672016-03-17 10:51:11 -07001622 sk_sp<SkImage> image(surface->makeImageSnapshot());
robertphillips549c8992016-04-01 09:28:51 -07001623 sk_sp<SkImageFilter> filter(SkImageSource::Make(std::move(image)));
fmalitacd56f812015-09-14 13:31:18 -07001624
Mike Reed0331d372018-01-23 11:57:30 -05001625 sk_sp<SkData> data(filter->serialize());
1626 sk_sp<SkImageFilter> unflattenedFilter = SkImageFilter::Deserialize(data->data(), data->size());
fmalitacd56f812015-09-14 13:31:18 -07001627 REPORTER_ASSERT(reporter, unflattenedFilter);
1628
1629 SkBitmap bm;
1630 bm.allocN32Pixels(10, 10);
fmalita23cb88c2015-09-15 06:56:23 -07001631 bm.eraseColor(SK_ColorBLUE);
fmalitacd56f812015-09-14 13:31:18 -07001632 SkPaint paint;
1633 paint.setColor(SK_ColorRED);
1634 paint.setImageFilter(unflattenedFilter);
1635
1636 SkCanvas canvas(bm);
1637 canvas.drawRect(SkRect::MakeWH(10, 10), paint);
1638 REPORTER_ASSERT(reporter, *bm.getAddr32(0, 0) == SkPreMultiplyColor(SK_ColorGREEN));
1639}
1640
Leon Scroggins III4cdbf602017-09-28 14:33:57 -04001641DEF_TEST(ImageFilterImageSourceUninitialized, r) {
1642 sk_sp<SkData> data(GetResourceAsData("crbug769134.fil"));
1643 if (!data) {
1644 return;
1645 }
Mike Reed0331d372018-01-23 11:57:30 -05001646 sk_sp<SkImageFilter> unflattenedFilter = SkImageFilter::Deserialize(data->data(), data->size());
Leon Scroggins III4cdbf602017-09-28 14:33:57 -04001647 // This will fail. More importantly, msan will verify that we did not
1648 // compare against uninitialized memory.
1649 REPORTER_ASSERT(r, !unflattenedFilter);
1650}
1651
bsalomon45eefcf2016-01-05 08:39:28 -08001652static void test_large_blur_input(skiatest::Reporter* reporter, SkCanvas* canvas) {
1653 SkBitmap largeBmp;
1654 int largeW = 5000;
1655 int largeH = 5000;
bsalomon45eefcf2016-01-05 08:39:28 -08001656 // If we're GPU-backed make the bitmap too large to be converted into a texture.
1657 if (GrContext* ctx = canvas->getGrContext()) {
Brian Salomonc7fe0f72018-05-11 10:14:21 -04001658 largeW = ctx->contextPriv().caps()->maxTextureSize() + 1;
bsalomon45eefcf2016-01-05 08:39:28 -08001659 }
bsalomon45eefcf2016-01-05 08:39:28 -08001660
1661 largeBmp.allocN32Pixels(largeW, largeH);
mtklein2afbe232016-02-07 12:23:10 -08001662 largeBmp.eraseColor(0);
bsalomon45eefcf2016-01-05 08:39:28 -08001663 if (!largeBmp.getPixels()) {
1664 ERRORF(reporter, "Failed to allocate large bmp.");
1665 return;
1666 }
1667
reed9ce9d672016-03-17 10:51:11 -07001668 sk_sp<SkImage> largeImage(SkImage::MakeFromBitmap(largeBmp));
bsalomon45eefcf2016-01-05 08:39:28 -08001669 if (!largeImage) {
1670 ERRORF(reporter, "Failed to create large image.");
1671 return;
1672 }
1673
robertphillips549c8992016-04-01 09:28:51 -07001674 sk_sp<SkImageFilter> largeSource(SkImageSource::Make(std::move(largeImage)));
bsalomon45eefcf2016-01-05 08:39:28 -08001675 if (!largeSource) {
1676 ERRORF(reporter, "Failed to create large SkImageSource.");
1677 return;
1678 }
1679
robertphillips6e7025a2016-04-04 04:31:25 -07001680 sk_sp<SkImageFilter> blur(SkBlurImageFilter::Make(10.f, 10.f, std::move(largeSource)));
bsalomon45eefcf2016-01-05 08:39:28 -08001681 if (!blur) {
1682 ERRORF(reporter, "Failed to create SkBlurImageFilter.");
1683 return;
1684 }
1685
1686 SkPaint paint;
robertphillips549c8992016-04-01 09:28:51 -07001687 paint.setImageFilter(std::move(blur));
bsalomon45eefcf2016-01-05 08:39:28 -08001688
1689 // This should not crash (http://crbug.com/570479).
1690 canvas->drawRect(SkRect::MakeIWH(largeW, largeH), paint);
1691}
1692
senorblanco21a465d2016-04-11 11:58:39 -07001693DEF_TEST(ImageFilterBlurLargeImage, reporter) {
reede8f30622016-03-23 18:59:25 -07001694 auto surface(SkSurface::MakeRaster(SkImageInfo::MakeN32Premul(100, 100)));
bsalomon45eefcf2016-01-05 08:39:28 -08001695 test_large_blur_input(reporter, surface->getCanvas());
1696}
1697
senorblanco5878dbd2016-05-19 14:50:29 -07001698static void test_make_with_filter(skiatest::Reporter* reporter, GrContext* context) {
Robert Phillipsa5fdc972017-02-18 16:58:09 -05001699 sk_sp<SkSurface> surface(create_surface(context, 192, 128));
senorblanco5878dbd2016-05-19 14:50:29 -07001700 surface->getCanvas()->clear(SK_ColorRED);
1701 SkPaint bluePaint;
1702 bluePaint.setColor(SK_ColorBLUE);
1703 SkIRect subset = SkIRect::MakeXYWH(25, 20, 50, 50);
1704 surface->getCanvas()->drawRect(SkRect::Make(subset), bluePaint);
1705 sk_sp<SkImage> sourceImage = surface->makeImageSnapshot();
1706
1707 sk_sp<SkImageFilter> filter = make_grayscale(nullptr, nullptr);
1708 SkIRect clipBounds = SkIRect::MakeXYWH(30, 35, 100, 100);
1709 SkIRect outSubset;
1710 SkIPoint offset;
1711 sk_sp<SkImage> result;
1712
1713 result = sourceImage->makeWithFilter(nullptr, subset, clipBounds, &outSubset, &offset);
1714 REPORTER_ASSERT(reporter, !result);
1715
1716 result = sourceImage->makeWithFilter(filter.get(), subset, clipBounds, nullptr, &offset);
1717 REPORTER_ASSERT(reporter, !result);
1718
1719 result = sourceImage->makeWithFilter(filter.get(), subset, clipBounds, &outSubset, nullptr);
1720 REPORTER_ASSERT(reporter, !result);
1721
1722 SkIRect bigSubset = SkIRect::MakeXYWH(-10000, -10000, 20000, 20000);
1723 result = sourceImage->makeWithFilter(filter.get(), bigSubset, clipBounds, &outSubset, &offset);
1724 REPORTER_ASSERT(reporter, !result);
1725
1726 SkIRect empty = SkIRect::MakeEmpty();
1727 result = sourceImage->makeWithFilter(filter.get(), empty, clipBounds, &outSubset, &offset);
1728 REPORTER_ASSERT(reporter, !result);
1729
1730 result = sourceImage->makeWithFilter(filter.get(), subset, empty, &outSubset, &offset);
1731 REPORTER_ASSERT(reporter, !result);
1732
1733 SkIRect leftField = SkIRect::MakeXYWH(-1000, 0, 100, 100);
1734 result = sourceImage->makeWithFilter(filter.get(), subset, leftField, &outSubset, &offset);
1735 REPORTER_ASSERT(reporter, !result);
1736
1737 result = sourceImage->makeWithFilter(filter.get(), subset, clipBounds, &outSubset, &offset);
1738
1739 REPORTER_ASSERT(reporter, result);
1740 REPORTER_ASSERT(reporter, result->bounds().contains(outSubset));
1741 SkIRect destRect = SkIRect::MakeXYWH(offset.x(), offset.y(),
1742 outSubset.width(), outSubset.height());
1743 REPORTER_ASSERT(reporter, clipBounds.contains(destRect));
Robert Phillipsa5fdc972017-02-18 16:58:09 -05001744
1745 // In GPU-mode, this case creates a special image with a backing size that differs from
1746 // the content size
1747 {
1748 clipBounds.setXYWH(0, 0, 170, 100);
1749 subset.setXYWH(0, 0, 160, 90);
1750
1751 filter = SkXfermodeImageFilter::Make(SkBlendMode::kSrc, nullptr);
1752 result = sourceImage->makeWithFilter(filter.get(), subset, clipBounds, &outSubset, &offset);
1753 REPORTER_ASSERT(reporter, result);
1754 }
senorblanco5878dbd2016-05-19 14:50:29 -07001755}
1756
1757DEF_TEST(ImageFilterMakeWithFilter, reporter) {
1758 test_make_with_filter(reporter, nullptr);
1759}
1760
senorblanco5878dbd2016-05-19 14:50:29 -07001761DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterMakeWithFilter_Gpu, reporter, ctxInfo) {
1762 test_make_with_filter(reporter, ctxInfo.grContext());
1763}
reed4a8126e2014-09-22 07:29:03 -07001764
bsalomon68d91342016-04-12 09:59:58 -07001765DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterHugeBlur_Gpu, reporter, ctxInfo) {
robertphillipsefbffed2015-06-22 12:06:08 -07001766
bsalomon8b7451a2016-05-11 06:33:06 -07001767 sk_sp<SkSurface> surf(SkSurface::MakeRenderTarget(ctxInfo.grContext(),
robertphillips3e302272016-04-20 11:48:36 -07001768 SkBudgeted::kNo,
1769 SkImageInfo::MakeN32Premul(100, 100)));
robertphillips9a53fd72015-06-22 09:46:59 -07001770
robertphillips3e302272016-04-20 11:48:36 -07001771
1772 SkCanvas* canvas = surf->getCanvas();
1773
1774 test_huge_blur(canvas, reporter);
senorblanco@chromium.org09843fd2014-03-24 20:50:59 +00001775}
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001776
egdanielab527a52016-06-28 08:07:26 -07001777DEF_GPUTEST_FOR_RENDERING_CONTEXTS(XfermodeImageFilterCroppedInput_Gpu, reporter, ctxInfo) {
Brian Salomon8996e182017-07-05 17:01:48 -04001778 sk_sp<SkSurface> surf(SkSurface::MakeRenderTarget(
1779 ctxInfo.grContext(),
1780 SkBudgeted::kNo,
1781 SkImageInfo::Make(1, 1, kRGBA_8888_SkColorType, kPremul_SkAlphaType)));
robertphillips3e302272016-04-20 11:48:36 -07001782
Mike Reedf1942192017-07-21 14:24:29 -04001783 test_xfermode_cropped_input(surf.get(), reporter);
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001784}
senorblanco32673b92014-09-09 09:15:04 -07001785
egdanielab527a52016-06-28 08:07:26 -07001786DEF_GPUTEST_FOR_ALL_CONTEXTS(ImageFilterBlurLargeImage_Gpu, reporter, ctxInfo) {
Brian Salomon8996e182017-07-05 17:01:48 -04001787 auto surface(SkSurface::MakeRenderTarget(
1788 ctxInfo.grContext(), SkBudgeted::kYes,
1789 SkImageInfo::Make(100, 100, kRGBA_8888_SkColorType, kPremul_SkAlphaType)));
bsalomon45eefcf2016-01-05 08:39:28 -08001790 test_large_blur_input(reporter, surface->getCanvas());
1791}
reedbb34a8a2016-04-23 15:19:07 -07001792
1793/*
1794 * Test that colorfilterimagefilter does not require its CTM to be decomposed when it has more
1795 * than just scale/translate, but that other filters do.
1796 */
reed96a04f32016-04-25 09:25:15 -07001797DEF_TEST(ImageFilterComplexCTM, reporter) {
reedbb34a8a2016-04-23 15:19:07 -07001798 // just need a colorfilter to exercise the corresponding imagefilter
Mike Reed7d954ad2016-10-28 15:42:34 -04001799 sk_sp<SkColorFilter> cf = SkColorFilter::MakeModeFilter(SK_ColorRED, SkBlendMode::kSrcATop);
reed96a04f32016-04-25 09:25:15 -07001800 sk_sp<SkImageFilter> cfif = SkColorFilterImageFilter::Make(cf, nullptr); // can handle
1801 sk_sp<SkImageFilter> blif = SkBlurImageFilter::Make(3, 3, nullptr); // cannot handle
reedbb34a8a2016-04-23 15:19:07 -07001802
1803 struct {
1804 sk_sp<SkImageFilter> fFilter;
1805 bool fExpectCanHandle;
1806 } recs[] = {
1807 { cfif, true },
1808 { SkColorFilterImageFilter::Make(cf, cfif), true },
Mike Reed0bdaf052017-06-18 23:35:57 -04001809 { SkMergeImageFilter::Make(cfif, cfif), true },
reed96a04f32016-04-25 09:25:15 -07001810 { SkComposeImageFilter::Make(cfif, cfif), true },
1811
reedbb34a8a2016-04-23 15:19:07 -07001812 { blif, false },
reed96a04f32016-04-25 09:25:15 -07001813 { SkBlurImageFilter::Make(3, 3, cfif), false },
reedbb34a8a2016-04-23 15:19:07 -07001814 { SkColorFilterImageFilter::Make(cf, blif), false },
Mike Reed0bdaf052017-06-18 23:35:57 -04001815 { SkMergeImageFilter::Make(cfif, blif), false },
reed96a04f32016-04-25 09:25:15 -07001816 { SkComposeImageFilter::Make(blif, cfif), false },
reedbb34a8a2016-04-23 15:19:07 -07001817 };
liyuqianbfebe222016-11-14 11:17:16 -08001818
reedbb34a8a2016-04-23 15:19:07 -07001819 for (const auto& rec : recs) {
reed96a04f32016-04-25 09:25:15 -07001820 const bool canHandle = rec.fFilter->canHandleComplexCTM();
reedbb34a8a2016-04-23 15:19:07 -07001821 REPORTER_ASSERT(reporter, canHandle == rec.fExpectCanHandle);
1822 }
1823}
Florin Malita08252ec2017-07-06 12:48:15 -04001824
1825// Test that transforming the filter DAG doesn't clone shared nodes multiple times.
1826DEF_TEST(ImageFilterColorSpaceDAG, reporter) {
1827
1828 // Helper for counting makeColorSpace() clones.
1829 class TestFilter final : public SkImageFilter {
1830 public:
1831 TestFilter() : INHERITED(nullptr, 0, nullptr) {}
1832
Florin Malita08252ec2017-07-06 12:48:15 -04001833 Factory getFactory() const override { return nullptr; }
Mike Klein4fee3232018-10-18 17:27:16 -04001834 const char* getTypeName() const override { return nullptr; }
Florin Malita08252ec2017-07-06 12:48:15 -04001835
1836 size_t cloneCount() const { return fCloneCount; }
1837
1838 protected:
1839 sk_sp<SkSpecialImage> onFilterImage(SkSpecialImage* src, const Context&,
1840 SkIPoint* offset) const override {
1841 return nullptr;
1842 }
1843 sk_sp<SkImageFilter> onMakeColorSpace(SkColorSpaceXformer*) const override {
1844 fCloneCount++;
1845 return sk_ref_sp(const_cast<TestFilter*>(this));
1846 }
1847
1848 private:
1849 typedef SkImageFilter INHERITED;
1850
1851 mutable size_t fCloneCount = 0;
1852 };
1853
1854 auto filter = sk_make_sp<TestFilter>();
1855 REPORTER_ASSERT(reporter, filter->cloneCount() == 0u);
1856
1857 // Build a DAG referencing the filter twice.
1858 auto complexFilter = SkMergeImageFilter::Make(filter, SkOffsetImageFilter::Make(1, 1, filter));
1859 REPORTER_ASSERT(reporter, filter->cloneCount() == 0u);
1860
1861 auto xformer = SkColorSpaceXformer::Make(SkColorSpace::MakeSRGB());
1862 auto xformedFilter = xformer->apply(complexFilter.get());
1863
Florin Malita39e08552017-07-06 14:16:18 -04001864 REPORTER_ASSERT(reporter, filter->cloneCount() == 1u);
Florin Malita08252ec2017-07-06 12:48:15 -04001865}
Xianzhu Wang0fa353c2017-08-25 16:27:04 -07001866
Xianzhu Wangb4496662017-09-25 10:26:40 -07001867// Test SkXfermodeImageFilter::filterBounds with different blending modes.
Xianzhu Wang0fa353c2017-08-25 16:27:04 -07001868DEF_TEST(XfermodeImageFilterBounds, reporter) {
1869 SkIRect background_rect = SkIRect::MakeXYWH(0, 0, 100, 100);
1870 SkIRect foreground_rect = SkIRect::MakeXYWH(50, 50, 100, 100);
1871 sk_sp<SkImageFilter> background(new FixedBoundsImageFilter(background_rect));
1872 sk_sp<SkImageFilter> foreground(new FixedBoundsImageFilter(foreground_rect));
1873
1874 const int kModeCount = static_cast<int>(SkBlendMode::kLastMode) + 1;
1875 SkIRect expectedBounds[kModeCount];
1876 // Expect union of input rects by default.
1877 for (int i = 0; i < kModeCount; ++i) {
1878 expectedBounds[i] = background_rect;
1879 expectedBounds[i].join(foreground_rect);
1880 }
1881
1882 SkIRect intersection = background_rect;
1883 intersection.intersect(foreground_rect);
1884 expectedBounds[static_cast<int>(SkBlendMode::kClear)] = SkIRect::MakeEmpty();
1885 expectedBounds[static_cast<int>(SkBlendMode::kSrc)] = foreground_rect;
1886 expectedBounds[static_cast<int>(SkBlendMode::kDst)] = background_rect;
1887 expectedBounds[static_cast<int>(SkBlendMode::kSrcIn)] = intersection;
1888 expectedBounds[static_cast<int>(SkBlendMode::kDstIn)] = intersection;
1889 expectedBounds[static_cast<int>(SkBlendMode::kSrcATop)] = background_rect;
1890 expectedBounds[static_cast<int>(SkBlendMode::kDstATop)] = foreground_rect;
1891
1892 // The value of this variable doesn't matter because we use inputs with fixed bounds.
1893 SkIRect src = SkIRect::MakeXYWH(11, 22, 33, 44);
1894 for (int i = 0; i < kModeCount; ++i) {
1895 sk_sp<SkImageFilter> xfermode(SkXfermodeImageFilter::Make(static_cast<SkBlendMode>(i),
1896 background, foreground, nullptr));
Robert Phillips12078432018-05-17 11:17:39 -04001897 auto bounds = xfermode->filterBounds(src, SkMatrix::I(),
1898 SkImageFilter::kForward_MapDirection, nullptr);
Xianzhu Wang0fa353c2017-08-25 16:27:04 -07001899 REPORTER_ASSERT(reporter, bounds == expectedBounds[i]);
1900 }
1901
1902 // Test empty intersection.
1903 sk_sp<SkImageFilter> background2(new FixedBoundsImageFilter(SkIRect::MakeXYWH(0, 0, 20, 20)));
1904 sk_sp<SkImageFilter> foreground2(new FixedBoundsImageFilter(SkIRect::MakeXYWH(40, 40, 50, 50)));
1905 sk_sp<SkImageFilter> xfermode(SkXfermodeImageFilter::Make(
1906 SkBlendMode::kSrcIn, std::move(background2), std::move(foreground2), nullptr));
Robert Phillips12078432018-05-17 11:17:39 -04001907 auto bounds = xfermode->filterBounds(src, SkMatrix::I(),
1908 SkImageFilter::kForward_MapDirection, nullptr);
Xianzhu Wang0fa353c2017-08-25 16:27:04 -07001909 REPORTER_ASSERT(reporter, bounds.isEmpty());
1910}
1911
Fredrik Söderquistb87f7982017-10-26 13:54:16 +02001912DEF_TEST(OffsetImageFilterBounds, reporter) {
1913 SkIRect src = SkIRect::MakeXYWH(0, 0, 100, 100);
1914 sk_sp<SkImageFilter> offset(SkOffsetImageFilter::Make(-50.5f, -50.5f, nullptr));
1915
1916 SkIRect expectedForward = SkIRect::MakeXYWH(-50, -50, 100, 100);
1917 SkIRect boundsForward = offset->filterBounds(src, SkMatrix::I(),
Robert Phillips12078432018-05-17 11:17:39 -04001918 SkImageFilter::kForward_MapDirection, nullptr);
Fredrik Söderquistb87f7982017-10-26 13:54:16 +02001919 REPORTER_ASSERT(reporter, boundsForward == expectedForward);
1920
1921 SkIRect expectedReverse = SkIRect::MakeXYWH(50, 50, 100, 100);
1922 SkIRect boundsReverse = offset->filterBounds(src, SkMatrix::I(),
Robert Phillips12078432018-05-17 11:17:39 -04001923 SkImageFilter::kReverse_MapDirection, &src);
Fredrik Söderquistb87f7982017-10-26 13:54:16 +02001924 REPORTER_ASSERT(reporter, boundsReverse == expectedReverse);
1925}
1926
Xianzhu Wang0fa353c2017-08-25 16:27:04 -07001927static void test_arithmetic_bounds(skiatest::Reporter* reporter, float k1, float k2, float k3,
1928 float k4, sk_sp<SkImageFilter> background,
1929 sk_sp<SkImageFilter> foreground,
1930 const SkImageFilter::CropRect* crop, const SkIRect& expected) {
1931 sk_sp<SkImageFilter> arithmetic(
1932 SkArithmeticImageFilter::Make(k1, k2, k3, k4, false, background, foreground, crop));
1933 // The value of the input rect doesn't matter because we use inputs with fixed bounds.
1934 SkIRect bounds = arithmetic->filterBounds(SkIRect::MakeXYWH(11, 22, 33, 44), SkMatrix::I(),
Robert Phillips12078432018-05-17 11:17:39 -04001935 SkImageFilter::kForward_MapDirection, nullptr);
Xianzhu Wang0fa353c2017-08-25 16:27:04 -07001936 REPORTER_ASSERT(reporter, expected == bounds);
1937}
1938
1939static void test_arithmetic_combinations(skiatest::Reporter* reporter, float v) {
1940 SkIRect background_rect = SkIRect::MakeXYWH(0, 0, 100, 100);
1941 SkIRect foreground_rect = SkIRect::MakeXYWH(50, 50, 100, 100);
1942 sk_sp<SkImageFilter> background(new FixedBoundsImageFilter(background_rect));
1943 sk_sp<SkImageFilter> foreground(new FixedBoundsImageFilter(foreground_rect));
1944
1945 SkIRect union_rect = background_rect;
1946 union_rect.join(foreground_rect);
1947 SkIRect intersection = background_rect;
1948 intersection.intersect(foreground_rect);
1949
1950 test_arithmetic_bounds(reporter, 0, 0, 0, 0, background, foreground, nullptr,
1951 SkIRect::MakeEmpty());
1952 test_arithmetic_bounds(reporter, 0, 0, 0, v, background, foreground, nullptr, union_rect);
1953 test_arithmetic_bounds(reporter, 0, 0, v, 0, background, foreground, nullptr, background_rect);
1954 test_arithmetic_bounds(reporter, 0, 0, v, v, background, foreground, nullptr, union_rect);
1955 test_arithmetic_bounds(reporter, 0, v, 0, 0, background, foreground, nullptr, foreground_rect);
1956 test_arithmetic_bounds(reporter, 0, v, 0, v, background, foreground, nullptr, union_rect);
1957 test_arithmetic_bounds(reporter, 0, v, v, 0, background, foreground, nullptr, union_rect);
1958 test_arithmetic_bounds(reporter, 0, v, v, v, background, foreground, nullptr, union_rect);
1959 test_arithmetic_bounds(reporter, v, 0, 0, 0, background, foreground, nullptr, intersection);
1960 test_arithmetic_bounds(reporter, v, 0, 0, v, background, foreground, nullptr, union_rect);
1961 test_arithmetic_bounds(reporter, v, 0, v, 0, background, foreground, nullptr, background_rect);
1962 test_arithmetic_bounds(reporter, v, 0, v, v, background, foreground, nullptr, union_rect);
1963 test_arithmetic_bounds(reporter, v, v, 0, 0, background, foreground, nullptr, foreground_rect);
1964 test_arithmetic_bounds(reporter, v, v, 0, v, background, foreground, nullptr, union_rect);
1965 test_arithmetic_bounds(reporter, v, v, v, 0, background, foreground, nullptr, union_rect);
1966 test_arithmetic_bounds(reporter, v, v, v, v, background, foreground, nullptr, union_rect);
1967
1968 // Test with crop. When k4 is non-zero, the result is expected to be crop_rect
1969 // regardless of inputs because the filter affects the whole crop area.
1970 SkIRect crop_rect = SkIRect::MakeXYWH(-111, -222, 333, 444);
1971 SkImageFilter::CropRect crop(SkRect::Make(crop_rect));
1972 test_arithmetic_bounds(reporter, 0, 0, 0, 0, background, foreground, &crop,
1973 SkIRect::MakeEmpty());
1974 test_arithmetic_bounds(reporter, 0, 0, 0, v, background, foreground, &crop, crop_rect);
1975 test_arithmetic_bounds(reporter, 0, 0, v, 0, background, foreground, &crop, background_rect);
1976 test_arithmetic_bounds(reporter, 0, 0, v, v, background, foreground, &crop, crop_rect);
1977 test_arithmetic_bounds(reporter, 0, v, 0, 0, background, foreground, &crop, foreground_rect);
1978 test_arithmetic_bounds(reporter, 0, v, 0, v, background, foreground, &crop, crop_rect);
1979 test_arithmetic_bounds(reporter, 0, v, v, 0, background, foreground, &crop, union_rect);
1980 test_arithmetic_bounds(reporter, 0, v, v, v, background, foreground, &crop, crop_rect);
1981 test_arithmetic_bounds(reporter, v, 0, 0, 0, background, foreground, &crop, intersection);
1982 test_arithmetic_bounds(reporter, v, 0, 0, v, background, foreground, &crop, crop_rect);
1983 test_arithmetic_bounds(reporter, v, 0, v, 0, background, foreground, &crop, background_rect);
1984 test_arithmetic_bounds(reporter, v, 0, v, v, background, foreground, &crop, crop_rect);
1985 test_arithmetic_bounds(reporter, v, v, 0, 0, background, foreground, &crop, foreground_rect);
1986 test_arithmetic_bounds(reporter, v, v, 0, v, background, foreground, &crop, crop_rect);
1987 test_arithmetic_bounds(reporter, v, v, v, 0, background, foreground, &crop, union_rect);
1988 test_arithmetic_bounds(reporter, v, v, v, v, background, foreground, &crop, crop_rect);
1989}
1990
Xianzhu Wangb4496662017-09-25 10:26:40 -07001991// Test SkArithmeticImageFilter::filterBounds with different blending modes.
Xianzhu Wang0fa353c2017-08-25 16:27:04 -07001992DEF_TEST(ArithmeticImageFilterBounds, reporter) {
1993 test_arithmetic_combinations(reporter, 1);
1994 test_arithmetic_combinations(reporter, 0.5);
1995}
Xianzhu Wangb4496662017-09-25 10:26:40 -07001996
1997// Test SkImageSource::filterBounds.
1998DEF_TEST(ImageSourceBounds, reporter) {
1999 sk_sp<SkImage> image(SkImage::MakeFromBitmap(make_gradient_circle(64, 64)));
2000 // Default src and dst rects.
2001 sk_sp<SkImageFilter> source1(SkImageSource::Make(image));
2002 SkIRect imageBounds = SkIRect::MakeWH(64, 64);
2003 SkIRect input(SkIRect::MakeXYWH(10, 20, 30, 40));
2004 REPORTER_ASSERT(reporter,
2005 imageBounds == source1->filterBounds(input, SkMatrix::I(),
Robert Phillips12078432018-05-17 11:17:39 -04002006 SkImageFilter::kForward_MapDirection,
2007 nullptr));
Xianzhu Wangb4496662017-09-25 10:26:40 -07002008 REPORTER_ASSERT(reporter,
2009 input == source1->filterBounds(input, SkMatrix::I(),
Robert Phillips12078432018-05-17 11:17:39 -04002010 SkImageFilter::kReverse_MapDirection, &input));
Xianzhu Wangb4496662017-09-25 10:26:40 -07002011 SkMatrix scale(SkMatrix::MakeScale(2));
2012 SkIRect scaledBounds = SkIRect::MakeWH(128, 128);
2013 REPORTER_ASSERT(reporter,
2014 scaledBounds == source1->filterBounds(input, scale,
Robert Phillips12078432018-05-17 11:17:39 -04002015 SkImageFilter::kForward_MapDirection,
2016 nullptr));
2017 REPORTER_ASSERT(reporter, input == source1->filterBounds(input, scale,
2018 SkImageFilter::kReverse_MapDirection,
2019 &input));
Xianzhu Wangb4496662017-09-25 10:26:40 -07002020
2021 // Specified src and dst rects.
2022 SkRect src(SkRect::MakeXYWH(0.5, 0.5, 100.5, 100.5));
2023 SkRect dst(SkRect::MakeXYWH(-10.5, -10.5, 120.5, 120.5));
2024 sk_sp<SkImageFilter> source2(SkImageSource::Make(image, src, dst, kMedium_SkFilterQuality));
2025 REPORTER_ASSERT(reporter,
2026 dst.roundOut() == source2->filterBounds(input, SkMatrix::I(),
Robert Phillips12078432018-05-17 11:17:39 -04002027 SkImageFilter::kForward_MapDirection,
2028 nullptr));
Xianzhu Wangb4496662017-09-25 10:26:40 -07002029 REPORTER_ASSERT(reporter,
2030 input == source2->filterBounds(input, SkMatrix::I(),
Robert Phillips12078432018-05-17 11:17:39 -04002031 SkImageFilter::kReverse_MapDirection, &input));
Xianzhu Wangb4496662017-09-25 10:26:40 -07002032 scale.mapRect(&dst);
2033 scale.mapRect(&src);
2034 REPORTER_ASSERT(reporter,
2035 dst.roundOut() == source2->filterBounds(input, scale,
Robert Phillips12078432018-05-17 11:17:39 -04002036 SkImageFilter::kForward_MapDirection,
2037 nullptr));
2038 REPORTER_ASSERT(reporter, input == source2->filterBounds(input, scale,
2039 SkImageFilter::kReverse_MapDirection,
2040 &input));
Xianzhu Wangb4496662017-09-25 10:26:40 -07002041}
Robert Phillips12078432018-05-17 11:17:39 -04002042