blob: f38b71496a7a8842eb653ad60f31ed293fcd9138 [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
60 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(MatrixTestImageFilter)
61
62protected:
robertphillips4ba94e22016-04-04 12:07:47 -070063 sk_sp<SkSpecialImage> onFilterImage(SkSpecialImage* source, const Context& ctx,
64 SkIPoint* offset) const override {
robertphillips43c2ad42016-04-04 05:05:11 -070065 REPORTER_ASSERT(fReporter, ctx.ctm() == fExpectedMatrix);
robertphillips4ba94e22016-04-04 12:07:47 -070066 offset->fX = offset->fY = 0;
67 return sk_ref_sp<SkSpecialImage>(source);
robertphillips43c2ad42016-04-04 05:05:11 -070068 }
Matt Sarett62745a82017-04-17 11:57:29 -040069 sk_sp<SkImageFilter> onMakeColorSpace(SkColorSpaceXformer*) const override {
70 return sk_ref_sp(const_cast<MatrixTestImageFilter*>(this));
71 }
robertphillips43c2ad42016-04-04 05:05:11 -070072
mtklein36352bf2015-03-25 18:17:31 -070073 void flatten(SkWriteBuffer& buffer) const override {
brianosman18f13f32016-05-02 07:51:08 -070074 SkDEBUGFAIL("Should never get here");
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +000075 }
76
77private:
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
senorblanco6a93fa12016-04-05 04:43:45 -0700103 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(FailImageFilter)
104
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; }
292
293 sk_sp<SkSpecialImage> onFilterImage(SkSpecialImage* src, const Context&,
294 SkIPoint* offset) const override {
295 return nullptr;
296 }
297 sk_sp<SkImageFilter> onMakeColorSpace(SkColorSpaceXformer*) const override { return nullptr; }
298
Robert Phillips12078432018-05-17 11:17:39 -0400299 SkIRect onFilterBounds(const SkIRect&, const SkMatrix&,
300 MapDirection, const SkIRect*) const override {
Xianzhu Wang0fa353c2017-08-25 16:27:04 -0700301 return fBounds;
302 }
303
304 SkIRect fBounds;
305};
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +0000306}
307
reed60c9b582016-04-03 09:11:13 -0700308sk_sp<SkFlattenable> MatrixTestImageFilter::CreateProc(SkReadBuffer& buffer) {
brianosman18f13f32016-05-02 07:51:08 -0700309 SkDEBUGFAIL("Should never get here");
310 return nullptr;
reed9fa60da2014-08-21 07:59:51 -0700311}
312
reed9ce9d672016-03-17 10:51:11 -0700313static sk_sp<SkImage> make_small_image() {
reede8f30622016-03-23 18:59:25 -0700314 auto surface(SkSurface::MakeRasterN32Premul(kBitmapSize, kBitmapSize));
fmalita5598b632015-09-15 11:26:13 -0700315 SkCanvas* canvas = surface->getCanvas();
316 canvas->clear(0x00000000);
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000317 SkPaint darkPaint;
318 darkPaint.setColor(0xFF804020);
319 SkPaint lightPaint;
320 lightPaint.setColor(0xFF244484);
321 const int i = kBitmapSize / 4;
322 for (int y = 0; y < kBitmapSize; y += i) {
323 for (int x = 0; x < kBitmapSize; x += i) {
fmalita5598b632015-09-15 11:26:13 -0700324 canvas->save();
325 canvas->translate(SkIntToScalar(x), SkIntToScalar(y));
326 canvas->drawRect(SkRect::MakeXYWH(0, 0,
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000327 SkIntToScalar(i),
328 SkIntToScalar(i)), darkPaint);
fmalita5598b632015-09-15 11:26:13 -0700329 canvas->drawRect(SkRect::MakeXYWH(SkIntToScalar(i),
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000330 0,
331 SkIntToScalar(i),
332 SkIntToScalar(i)), lightPaint);
fmalita5598b632015-09-15 11:26:13 -0700333 canvas->drawRect(SkRect::MakeXYWH(0,
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000334 SkIntToScalar(i),
335 SkIntToScalar(i),
336 SkIntToScalar(i)), lightPaint);
fmalita5598b632015-09-15 11:26:13 -0700337 canvas->drawRect(SkRect::MakeXYWH(SkIntToScalar(i),
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000338 SkIntToScalar(i),
339 SkIntToScalar(i),
340 SkIntToScalar(i)), darkPaint);
fmalita5598b632015-09-15 11:26:13 -0700341 canvas->restore();
commit-bot@chromium.org4b681bc2013-09-13 12:40:02 +0000342 }
343 }
fmalita5598b632015-09-15 11:26:13 -0700344
reed9ce9d672016-03-17 10:51:11 -0700345 return surface->makeImageSnapshot();
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000346}
senorblanco@chromium.org194d7752013-07-24 22:19:24 +0000347
robertphillips5605b562016-04-05 11:50:42 -0700348static sk_sp<SkImageFilter> make_scale(float amount, sk_sp<SkImageFilter> input) {
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000349 SkScalar s = amount;
350 SkScalar matrix[20] = { s, 0, 0, 0, 0,
351 0, s, 0, 0, 0,
352 0, 0, s, 0, 0,
353 0, 0, 0, s, 0 };
robertphillips5605b562016-04-05 11:50:42 -0700354 sk_sp<SkColorFilter> filter(SkColorFilter::MakeMatrixFilterRowMajor255(matrix));
355 return SkColorFilterImageFilter::Make(std::move(filter), std::move(input));
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000356}
357
robertphillips5605b562016-04-05 11:50:42 -0700358static sk_sp<SkImageFilter> make_grayscale(sk_sp<SkImageFilter> input,
359 const SkImageFilter::CropRect* cropRect) {
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000360 SkScalar matrix[20];
361 memset(matrix, 0, 20 * sizeof(SkScalar));
362 matrix[0] = matrix[5] = matrix[10] = 0.2126f;
363 matrix[1] = matrix[6] = matrix[11] = 0.7152f;
364 matrix[2] = matrix[7] = matrix[12] = 0.0722f;
365 matrix[18] = 1.0f;
robertphillips5605b562016-04-05 11:50:42 -0700366 sk_sp<SkColorFilter> filter(SkColorFilter::MakeMatrixFilterRowMajor255(matrix));
367 return SkColorFilterImageFilter::Make(std::move(filter), std::move(input), cropRect);
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000368}
369
robertphillips5605b562016-04-05 11:50:42 -0700370static sk_sp<SkImageFilter> make_blue(sk_sp<SkImageFilter> input,
371 const SkImageFilter::CropRect* cropRect) {
372 sk_sp<SkColorFilter> filter(SkColorFilter::MakeModeFilter(SK_ColorBLUE,
Mike Reed7d954ad2016-10-28 15:42:34 -0400373 SkBlendMode::kSrcIn));
robertphillips5605b562016-04-05 11:50:42 -0700374 return SkColorFilterImageFilter::Make(std::move(filter), std::move(input), cropRect);
reedcedc36f2015-03-08 04:42:52 -0700375}
376
robertphillips3e302272016-04-20 11:48:36 -0700377static sk_sp<SkSpecialSurface> create_empty_special_surface(GrContext* context, int widthHeight) {
robertphillips4418dba2016-03-07 12:45:14 -0800378 if (context) {
robertphillips4df16562016-04-28 15:09:34 -0700379 return SkSpecialSurface::MakeRenderTarget(context,
380 widthHeight, widthHeight,
Brian Osman777b5632016-10-14 09:16:21 -0400381 kRGBA_8888_GrPixelConfig, nullptr);
Brian Osmanc7ad40f2018-05-31 14:27:17 -0400382 } else {
robertphillips4418dba2016-03-07 12:45:14 -0800383 const SkImageInfo info = SkImageInfo::MakeN32(widthHeight, widthHeight,
384 kOpaque_SkAlphaType);
robertphillips3e302272016-04-20 11:48:36 -0700385 return SkSpecialSurface::MakeRaster(info);
robertphillips4418dba2016-03-07 12:45:14 -0800386 }
senorblancobf680c32016-03-16 16:15:53 -0700387}
388
senorblanco5878dbd2016-05-19 14:50:29 -0700389static sk_sp<SkSurface> create_surface(GrContext* context, int width, int height) {
390 const SkImageInfo info = SkImageInfo::MakeN32(width, height, kOpaque_SkAlphaType);
senorblanco5878dbd2016-05-19 14:50:29 -0700391 if (context) {
392 return SkSurface::MakeRenderTarget(context, SkBudgeted::kNo, info);
Brian Osmanc7ad40f2018-05-31 14:27:17 -0400393 } else {
senorblanco5878dbd2016-05-19 14:50:29 -0700394 return SkSurface::MakeRaster(info);
395 }
396}
397
robertphillips3e302272016-04-20 11:48:36 -0700398static sk_sp<SkSpecialImage> create_empty_special_image(GrContext* context, int widthHeight) {
399 sk_sp<SkSpecialSurface> surf(create_empty_special_surface(context, widthHeight));
robertphillips4418dba2016-03-07 12:45:14 -0800400
401 SkASSERT(surf);
402
403 SkCanvas* canvas = surf->getCanvas();
404 SkASSERT(canvas);
405
406 canvas->clear(0x0);
407
robertphillips37bd7c32016-03-17 14:31:39 -0700408 return surf->makeImageSnapshot();
robertphillips4418dba2016-03-07 12:45:14 -0800409}
410
411
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000412DEF_TEST(ImageFilter, reporter) {
413 {
reedcedc36f2015-03-08 04:42:52 -0700414 // Check that two non-clipping color-matrice-filters concatenate into a single filter.
robertphillips5605b562016-04-05 11:50:42 -0700415 sk_sp<SkImageFilter> halfBrightness(make_scale(0.5f, nullptr));
416 sk_sp<SkImageFilter> quarterBrightness(make_scale(0.5f, std::move(halfBrightness)));
halcanary96fcdcc2015-08-27 07:41:13 -0700417 REPORTER_ASSERT(reporter, nullptr == quarterBrightness->getInput(0));
reedcedc36f2015-03-08 04:42:52 -0700418 SkColorFilter* cf;
419 REPORTER_ASSERT(reporter, quarterBrightness->asColorFilter(&cf));
halcanary96fcdcc2015-08-27 07:41:13 -0700420 REPORTER_ASSERT(reporter, cf->asColorMatrix(nullptr));
reedcedc36f2015-03-08 04:42:52 -0700421 cf->unref();
senorblanco@chromium.org194d7752013-07-24 22:19:24 +0000422 }
423
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000424 {
reedcedc36f2015-03-08 04:42:52 -0700425 // Check that a clipping color-matrice-filter followed by a color-matrice-filters
426 // concatenates into a single filter, but not a matrixfilter (due to clamping).
robertphillips5605b562016-04-05 11:50:42 -0700427 sk_sp<SkImageFilter> doubleBrightness(make_scale(2.0f, nullptr));
428 sk_sp<SkImageFilter> halfBrightness(make_scale(0.5f, std::move(doubleBrightness)));
halcanary96fcdcc2015-08-27 07:41:13 -0700429 REPORTER_ASSERT(reporter, nullptr == halfBrightness->getInput(0));
reedcedc36f2015-03-08 04:42:52 -0700430 SkColorFilter* cf;
431 REPORTER_ASSERT(reporter, halfBrightness->asColorFilter(&cf));
halcanary96fcdcc2015-08-27 07:41:13 -0700432 REPORTER_ASSERT(reporter, !cf->asColorMatrix(nullptr));
reedcedc36f2015-03-08 04:42:52 -0700433 cf->unref();
senorblanco@chromium.org194d7752013-07-24 22:19:24 +0000434 }
435
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000436 {
437 // Check that a color filter image filter without a crop rect can be
438 // expressed as a color filter.
robertphillips5605b562016-04-05 11:50:42 -0700439 sk_sp<SkImageFilter> gray(make_grayscale(nullptr, nullptr));
halcanary96fcdcc2015-08-27 07:41:13 -0700440 REPORTER_ASSERT(reporter, true == gray->asColorFilter(nullptr));
senorblanco@chromium.org194d7752013-07-24 22:19:24 +0000441 }
mtklein2afbe232016-02-07 12:23:10 -0800442
reedcedc36f2015-03-08 04:42:52 -0700443 {
444 // Check that a colorfilterimage filter without a crop rect but with an input
445 // that is another colorfilterimage can be expressed as a colorfilter (composed).
robertphillips5605b562016-04-05 11:50:42 -0700446 sk_sp<SkImageFilter> mode(make_blue(nullptr, nullptr));
447 sk_sp<SkImageFilter> gray(make_grayscale(std::move(mode), nullptr));
halcanary96fcdcc2015-08-27 07:41:13 -0700448 REPORTER_ASSERT(reporter, true == gray->asColorFilter(nullptr));
reedcedc36f2015-03-08 04:42:52 -0700449 }
450
451 {
452 // Test that if we exceed the limit of what ComposeColorFilter can combine, we still
453 // can build the DAG and won't assert if we call asColorFilter.
robertphillips5605b562016-04-05 11:50:42 -0700454 sk_sp<SkImageFilter> filter(make_blue(nullptr, nullptr));
reedcedc36f2015-03-08 04:42:52 -0700455 const int kWayTooManyForComposeColorFilter = 100;
456 for (int i = 0; i < kWayTooManyForComposeColorFilter; ++i) {
robertphillips5605b562016-04-05 11:50:42 -0700457 filter = make_blue(filter, nullptr);
reedcedc36f2015-03-08 04:42:52 -0700458 // the first few of these will succeed, but after we hit the internal limit,
459 // it will then return false.
halcanary96fcdcc2015-08-27 07:41:13 -0700460 (void)filter->asColorFilter(nullptr);
reedcedc36f2015-03-08 04:42:52 -0700461 }
462 }
reed5c518a82015-03-05 14:47:29 -0800463
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000464 {
465 // Check that a color filter image filter with a crop rect cannot
466 // be expressed as a color filter.
467 SkImageFilter::CropRect cropRect(SkRect::MakeXYWH(0, 0, 100, 100));
robertphillips5605b562016-04-05 11:50:42 -0700468 sk_sp<SkImageFilter> grayWithCrop(make_grayscale(nullptr, &cropRect));
halcanary96fcdcc2015-08-27 07:41:13 -0700469 REPORTER_ASSERT(reporter, false == grayWithCrop->asColorFilter(nullptr));
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000470 }
471
472 {
senorblanco3df05012014-07-03 11:13:09 -0700473 // Check that two non-commutative matrices are concatenated in
474 // the correct order.
475 SkScalar blueToRedMatrix[20] = { 0 };
476 blueToRedMatrix[2] = blueToRedMatrix[18] = SK_Scalar1;
477 SkScalar redToGreenMatrix[20] = { 0 };
478 redToGreenMatrix[5] = redToGreenMatrix[18] = SK_Scalar1;
robertphillips5605b562016-04-05 11:50:42 -0700479 sk_sp<SkColorFilter> blueToRed(SkColorFilter::MakeMatrixFilterRowMajor255(blueToRedMatrix));
480 sk_sp<SkImageFilter> filter1(SkColorFilterImageFilter::Make(std::move(blueToRed),
481 nullptr));
482 sk_sp<SkColorFilter> redToGreen(SkColorFilter::MakeMatrixFilterRowMajor255(redToGreenMatrix));
483 sk_sp<SkImageFilter> filter2(SkColorFilterImageFilter::Make(std::move(redToGreen),
484 std::move(filter1)));
senorblanco3df05012014-07-03 11:13:09 -0700485
486 SkBitmap result;
487 result.allocN32Pixels(kBitmapSize, kBitmapSize);
488
489 SkPaint paint;
490 paint.setColor(SK_ColorBLUE);
robertphillips5605b562016-04-05 11:50:42 -0700491 paint.setImageFilter(std::move(filter2));
senorblanco3df05012014-07-03 11:13:09 -0700492 SkCanvas canvas(result);
493 canvas.clear(0x0);
494 SkRect rect = SkRect::Make(SkIRect::MakeWH(kBitmapSize, kBitmapSize));
495 canvas.drawRect(rect, paint);
496 uint32_t pixel = *result.getAddr32(0, 0);
497 // The result here should be green, since we have effectively shifted blue to green.
498 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
499 }
500
501 {
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000502 // Tests pass by not asserting
reed9ce9d672016-03-17 10:51:11 -0700503 sk_sp<SkImage> image(make_small_image());
fmalita5598b632015-09-15 11:26:13 -0700504 SkBitmap result;
mike@reedtribe.orgdeee4962014-02-13 14:41:43 +0000505 result.allocN32Pixels(kBitmapSize, kBitmapSize);
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000506
senorblanco@chromium.org194d7752013-07-24 22:19:24 +0000507 {
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000508 // This tests for :
509 // 1 ) location at (0,0,1)
robertphillips3d32d762015-07-13 13:16:44 -0700510 SkPoint3 location = SkPoint3::Make(0, 0, SK_Scalar1);
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000511 // 2 ) location and target at same value
robertphillips3d32d762015-07-13 13:16:44 -0700512 SkPoint3 target = SkPoint3::Make(location.fX, location.fY, location.fZ);
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000513 // 3 ) large negative specular exponent value
514 SkScalar specularExponent = -1000;
515
robertphillips549c8992016-04-01 09:28:51 -0700516 sk_sp<SkImageFilter> bmSrc(SkImageSource::Make(std::move(image)));
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000517 SkPaint paint;
robertphillips12fa47d2016-04-08 16:28:09 -0700518 paint.setImageFilter(SkLightingImageFilter::MakeSpotLitSpecular(
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000519 location, target, specularExponent, 180,
520 0xFFFFFFFF, SK_Scalar1, SK_Scalar1, SK_Scalar1,
robertphillips12fa47d2016-04-08 16:28:09 -0700521 std::move(bmSrc)));
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000522 SkCanvas canvas(result);
523 SkRect r = SkRect::MakeWH(SkIntToScalar(kBitmapSize),
524 SkIntToScalar(kBitmapSize));
525 canvas.drawRect(r, paint);
senorblanco@chromium.org194d7752013-07-24 22:19:24 +0000526 }
senorblanco@chromium.org194d7752013-07-24 22:19:24 +0000527 }
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +0000528}
senorblanco@chromium.org6776b822014-01-03 21:48:22 +0000529
robertphillips3e302272016-04-20 11:48:36 -0700530static void test_crop_rects(skiatest::Reporter* reporter,
robertphillips4418dba2016-03-07 12:45:14 -0800531 GrContext* context) {
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +0000532 // Check that all filters offset to their absolute crop rect,
533 // unaffected by the input crop rect.
534 // Tests pass by not asserting.
robertphillips3e302272016-04-20 11:48:36 -0700535 sk_sp<SkSpecialImage> srcImg(create_empty_special_image(context, 100));
robertphillips4418dba2016-03-07 12:45:14 -0800536 SkASSERT(srcImg);
senorblanco@chromium.org6776b822014-01-03 21:48:22 +0000537
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +0000538 SkImageFilter::CropRect inputCropRect(SkRect::MakeXYWH(8, 13, 80, 80));
539 SkImageFilter::CropRect cropRect(SkRect::MakeXYWH(20, 30, 60, 60));
robertphillipsfc11b0a2016-04-05 09:09:36 -0700540 sk_sp<SkImageFilter> input(make_grayscale(nullptr, &inputCropRect));
senorblanco@chromium.org6776b822014-01-03 21:48:22 +0000541
robertphillipsfc11b0a2016-04-05 09:09:36 -0700542 FilterList filters(input, &cropRect);
senorblanco@chromium.org6776b822014-01-03 21:48:22 +0000543
senorblanco297f7ce2016-03-23 13:44:26 -0700544 for (int i = 0; i < filters.count(); ++i) {
545 SkImageFilter* filter = filters.getFilter(i);
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +0000546 SkIPoint offset;
brianosman2a75e5d2016-09-22 07:15:37 -0700547 SkImageFilter::OutputProperties noColorSpace(nullptr);
548 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeWH(100, 100), nullptr, noColorSpace);
robertphillips2302de92016-03-24 07:26:32 -0700549 sk_sp<SkSpecialImage> resultImg(filter->filterImage(srcImg.get(), ctx, &offset));
Brian Salomon1c80e992018-01-29 09:50:47 -0500550 REPORTER_ASSERT(reporter, resultImg, filters.getName(i));
551 REPORTER_ASSERT(reporter, offset.fX == 20 && offset.fY == 30, filters.getName(i));
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +0000552 }
553}
554
robertphillips3e302272016-04-20 11:48:36 -0700555static void test_negative_blur_sigma(skiatest::Reporter* reporter,
robertphillips4418dba2016-03-07 12:45:14 -0800556 GrContext* context) {
senorblanco32673b92014-09-09 09:15:04 -0700557 // Check that SkBlurImageFilter will accept a negative sigma, either in
558 // the given arguments or after CTM application.
reed5ea95df2015-10-06 14:05:32 -0700559 const int width = 32, height = 32;
560 const SkScalar five = SkIntToScalar(5);
senorblanco32673b92014-09-09 09:15:04 -0700561
robertphillips6e7025a2016-04-04 04:31:25 -0700562 sk_sp<SkImageFilter> positiveFilter(SkBlurImageFilter::Make(five, five, nullptr));
563 sk_sp<SkImageFilter> negativeFilter(SkBlurImageFilter::Make(-five, five, nullptr));
senorblanco32673b92014-09-09 09:15:04 -0700564
565 SkBitmap gradient = make_gradient_circle(width, height);
robertphillips3e302272016-04-20 11:48:36 -0700566 sk_sp<SkSpecialImage> imgSrc(SkSpecialImage::MakeFromRaster(SkIRect::MakeWH(width, height),
robertphillips37bd7c32016-03-17 14:31:39 -0700567 gradient));
robertphillips4418dba2016-03-07 12:45:14 -0800568
senorblanco32673b92014-09-09 09:15:04 -0700569 SkIPoint offset;
brianosman2a75e5d2016-09-22 07:15:37 -0700570 SkImageFilter::OutputProperties noColorSpace(nullptr);
571 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeWH(32, 32), nullptr, noColorSpace);
robertphillips4418dba2016-03-07 12:45:14 -0800572
robertphillips2302de92016-03-24 07:26:32 -0700573 sk_sp<SkSpecialImage> positiveResult1(positiveFilter->filterImage(imgSrc.get(), ctx, &offset));
robertphillips4418dba2016-03-07 12:45:14 -0800574 REPORTER_ASSERT(reporter, positiveResult1);
575
robertphillips2302de92016-03-24 07:26:32 -0700576 sk_sp<SkSpecialImage> negativeResult1(negativeFilter->filterImage(imgSrc.get(), ctx, &offset));
robertphillips4418dba2016-03-07 12:45:14 -0800577 REPORTER_ASSERT(reporter, negativeResult1);
578
senorblanco32673b92014-09-09 09:15:04 -0700579 SkMatrix negativeScale;
580 negativeScale.setScale(-SK_Scalar1, SK_Scalar1);
brianosman2a75e5d2016-09-22 07:15:37 -0700581 SkImageFilter::Context negativeCTX(negativeScale, SkIRect::MakeWH(32, 32), nullptr,
582 noColorSpace);
robertphillips4418dba2016-03-07 12:45:14 -0800583
robertphillips2302de92016-03-24 07:26:32 -0700584 sk_sp<SkSpecialImage> negativeResult2(positiveFilter->filterImage(imgSrc.get(),
585 negativeCTX,
586 &offset));
robertphillips4418dba2016-03-07 12:45:14 -0800587 REPORTER_ASSERT(reporter, negativeResult2);
588
robertphillips2302de92016-03-24 07:26:32 -0700589 sk_sp<SkSpecialImage> positiveResult2(negativeFilter->filterImage(imgSrc.get(),
590 negativeCTX,
591 &offset));
robertphillips4418dba2016-03-07 12:45:14 -0800592 REPORTER_ASSERT(reporter, positiveResult2);
593
594
595 SkBitmap positiveResultBM1, positiveResultBM2;
596 SkBitmap negativeResultBM1, negativeResultBM2;
597
robertphillips64612512016-04-08 12:10:42 -0700598 REPORTER_ASSERT(reporter, positiveResult1->getROPixels(&positiveResultBM1));
599 REPORTER_ASSERT(reporter, positiveResult2->getROPixels(&positiveResultBM2));
600 REPORTER_ASSERT(reporter, negativeResult1->getROPixels(&negativeResultBM1));
601 REPORTER_ASSERT(reporter, negativeResult2->getROPixels(&negativeResultBM2));
robertphillips4418dba2016-03-07 12:45:14 -0800602
senorblanco32673b92014-09-09 09:15:04 -0700603 for (int y = 0; y < height; y++) {
robertphillips4418dba2016-03-07 12:45:14 -0800604 int diffs = memcmp(positiveResultBM1.getAddr32(0, y),
605 negativeResultBM1.getAddr32(0, y),
606 positiveResultBM1.rowBytes());
senorblanco32673b92014-09-09 09:15:04 -0700607 REPORTER_ASSERT(reporter, !diffs);
608 if (diffs) {
609 break;
610 }
robertphillips4418dba2016-03-07 12:45:14 -0800611 diffs = memcmp(positiveResultBM1.getAddr32(0, y),
612 negativeResultBM2.getAddr32(0, y),
613 positiveResultBM1.rowBytes());
senorblanco32673b92014-09-09 09:15:04 -0700614 REPORTER_ASSERT(reporter, !diffs);
615 if (diffs) {
616 break;
617 }
robertphillips4418dba2016-03-07 12:45:14 -0800618 diffs = memcmp(positiveResultBM1.getAddr32(0, y),
619 positiveResultBM2.getAddr32(0, y),
620 positiveResultBM1.rowBytes());
senorblanco32673b92014-09-09 09:15:04 -0700621 REPORTER_ASSERT(reporter, !diffs);
622 if (diffs) {
623 break;
624 }
625 }
626}
627
senorblanco21a465d2016-04-11 11:58:39 -0700628DEF_TEST(ImageFilterNegativeBlurSigma, reporter) {
robertphillips3e302272016-04-20 11:48:36 -0700629 test_negative_blur_sigma(reporter, nullptr);
robertphillips4418dba2016-03-07 12:45:14 -0800630}
631
bsalomon68d91342016-04-12 09:59:58 -0700632DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterNegativeBlurSigma_Gpu, reporter, ctxInfo) {
bsalomon8b7451a2016-05-11 06:33:06 -0700633 test_negative_blur_sigma(reporter, ctxInfo.grContext());
robertphillips4418dba2016-03-07 12:45:14 -0800634}
robertphillips4418dba2016-03-07 12:45:14 -0800635
robertphillips3e302272016-04-20 11:48:36 -0700636static void test_zero_blur_sigma(skiatest::Reporter* reporter, GrContext* context) {
senorblancobf680c32016-03-16 16:15:53 -0700637 // Check that SkBlurImageFilter with a zero sigma and a non-zero srcOffset works correctly.
638 SkImageFilter::CropRect cropRect(SkRect::Make(SkIRect::MakeXYWH(5, 0, 5, 10)));
robertphillips51a315e2016-03-31 09:05:49 -0700639 sk_sp<SkImageFilter> input(SkOffsetImageFilter::Make(0, 0, nullptr, &cropRect));
robertphillips6e7025a2016-04-04 04:31:25 -0700640 sk_sp<SkImageFilter> filter(SkBlurImageFilter::Make(0, 0, std::move(input), &cropRect));
senorblancobf680c32016-03-16 16:15:53 -0700641
robertphillips3e302272016-04-20 11:48:36 -0700642 sk_sp<SkSpecialSurface> surf(create_empty_special_surface(context, 10));
senorblancobf680c32016-03-16 16:15:53 -0700643 surf->getCanvas()->clear(SK_ColorGREEN);
robertphillips37bd7c32016-03-17 14:31:39 -0700644 sk_sp<SkSpecialImage> image(surf->makeImageSnapshot());
senorblancobf680c32016-03-16 16:15:53 -0700645
646 SkIPoint offset;
brianosman2a75e5d2016-09-22 07:15:37 -0700647 SkImageFilter::OutputProperties noColorSpace(nullptr);
648 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeWH(32, 32), nullptr, noColorSpace);
senorblancobf680c32016-03-16 16:15:53 -0700649
robertphillips2302de92016-03-24 07:26:32 -0700650 sk_sp<SkSpecialImage> result(filter->filterImage(image.get(), ctx, &offset));
senorblancobf680c32016-03-16 16:15:53 -0700651 REPORTER_ASSERT(reporter, offset.fX == 5 && offset.fY == 0);
652 REPORTER_ASSERT(reporter, result);
653 REPORTER_ASSERT(reporter, result->width() == 5 && result->height() == 10);
654
655 SkBitmap resultBM;
656
robertphillips64612512016-04-08 12:10:42 -0700657 REPORTER_ASSERT(reporter, result->getROPixels(&resultBM));
senorblancobf680c32016-03-16 16:15:53 -0700658
senorblancobf680c32016-03-16 16:15:53 -0700659 for (int y = 0; y < resultBM.height(); y++) {
660 for (int x = 0; x < resultBM.width(); x++) {
661 bool diff = *resultBM.getAddr32(x, y) != SK_ColorGREEN;
662 REPORTER_ASSERT(reporter, !diff);
663 if (diff) {
664 break;
665 }
666 }
667 }
668}
669
senorblanco21a465d2016-04-11 11:58:39 -0700670DEF_TEST(ImageFilterZeroBlurSigma, reporter) {
robertphillips3e302272016-04-20 11:48:36 -0700671 test_zero_blur_sigma(reporter, nullptr);
senorblancobf680c32016-03-16 16:15:53 -0700672}
673
bsalomon68d91342016-04-12 09:59:58 -0700674DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterZeroBlurSigma_Gpu, reporter, ctxInfo) {
bsalomon8b7451a2016-05-11 06:33:06 -0700675 test_zero_blur_sigma(reporter, ctxInfo.grContext());
senorblancobf680c32016-03-16 16:15:53 -0700676}
senorblancobf680c32016-03-16 16:15:53 -0700677
senorblanco6a93fa12016-04-05 04:43:45 -0700678
679// Tests that, even when an upstream filter has returned null (due to failure or clipping), a
680// downstream filter that affects transparent black still does so even with a nullptr input.
robertphillips3e302272016-04-20 11:48:36 -0700681static void test_fail_affects_transparent_black(skiatest::Reporter* reporter, GrContext* context) {
senorblanco6a93fa12016-04-05 04:43:45 -0700682 sk_sp<FailImageFilter> failFilter(new FailImageFilter());
robertphillips3e302272016-04-20 11:48:36 -0700683 sk_sp<SkSpecialImage> source(create_empty_special_image(context, 5));
brianosman2a75e5d2016-09-22 07:15:37 -0700684 SkImageFilter::OutputProperties noColorSpace(nullptr);
685 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeXYWH(0, 0, 1, 1), nullptr, noColorSpace);
Mike Reed7d954ad2016-10-28 15:42:34 -0400686 sk_sp<SkColorFilter> green(SkColorFilter::MakeModeFilter(SK_ColorGREEN, SkBlendMode::kSrc));
senorblanco6a93fa12016-04-05 04:43:45 -0700687 SkASSERT(green->affectsTransparentBlack());
robertphillips5605b562016-04-05 11:50:42 -0700688 sk_sp<SkImageFilter> greenFilter(SkColorFilterImageFilter::Make(std::move(green),
689 std::move(failFilter)));
senorblanco6a93fa12016-04-05 04:43:45 -0700690 SkIPoint offset;
691 sk_sp<SkSpecialImage> result(greenFilter->filterImage(source.get(), ctx, &offset));
692 REPORTER_ASSERT(reporter, nullptr != result.get());
693 if (result.get()) {
694 SkBitmap resultBM;
robertphillips64612512016-04-08 12:10:42 -0700695 REPORTER_ASSERT(reporter, result->getROPixels(&resultBM));
senorblanco6a93fa12016-04-05 04:43:45 -0700696 REPORTER_ASSERT(reporter, *resultBM.getAddr32(0, 0) == SK_ColorGREEN);
697 }
698}
699
700DEF_TEST(ImageFilterFailAffectsTransparentBlack, reporter) {
robertphillips3e302272016-04-20 11:48:36 -0700701 test_fail_affects_transparent_black(reporter, nullptr);
senorblanco6a93fa12016-04-05 04:43:45 -0700702}
703
bsalomon68d91342016-04-12 09:59:58 -0700704DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterFailAffectsTransparentBlack_Gpu, reporter, ctxInfo) {
bsalomon8b7451a2016-05-11 06:33:06 -0700705 test_fail_affects_transparent_black(reporter, ctxInfo.grContext());
senorblanco6a93fa12016-04-05 04:43:45 -0700706}
senorblanco6a93fa12016-04-05 04:43:45 -0700707
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +0000708DEF_TEST(ImageFilterDrawTiled, reporter) {
709 // Check that all filters when drawn tiled (with subsequent clip rects) exactly
710 // match the same filters drawn with a single full-canvas bitmap draw.
711 // Tests pass by not asserting.
712
robertphillipsfc11b0a2016-04-05 09:09:36 -0700713 FilterList filters(nullptr);
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +0000714
715 SkBitmap untiledResult, tiledResult;
reed5ea95df2015-10-06 14:05:32 -0700716 const int width = 64, height = 64;
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +0000717 untiledResult.allocN32Pixels(width, height);
718 tiledResult.allocN32Pixels(width, height);
719 SkCanvas tiledCanvas(tiledResult);
720 SkCanvas untiledCanvas(untiledResult);
Robert Phillips12078432018-05-17 11:17:39 -0400721 const int tileSize = 8;
722
723 SkPaint textPaint;
724 textPaint.setTextSize(SkIntToScalar(height));
725 textPaint.setColor(SK_ColorWHITE);
726
727 const char* text = "ABC";
728 const SkScalar yPos = SkIntToScalar(height);
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +0000729
senorblanco@chromium.orgd4db6572014-05-07 20:00:04 +0000730 for (int scale = 1; scale <= 2; ++scale) {
senorblanco297f7ce2016-03-23 13:44:26 -0700731 for (int i = 0; i < filters.count(); ++i) {
Robert Phillips12078432018-05-17 11:17:39 -0400732 SkPaint combinedPaint;
733 combinedPaint.setTextSize(SkIntToScalar(height));
734 combinedPaint.setColor(SK_ColorWHITE);
735 combinedPaint.setImageFilter(sk_ref_sp(filters.getFilter(i)));
736
737 untiledCanvas.clear(SK_ColorTRANSPARENT);
senorblanco@chromium.orgd4db6572014-05-07 20:00:04 +0000738 untiledCanvas.save();
739 untiledCanvas.scale(SkIntToScalar(scale), SkIntToScalar(scale));
Robert Phillips12078432018-05-17 11:17:39 -0400740 untiledCanvas.drawString(text, 0, yPos, combinedPaint);
senorblanco@chromium.orgd4db6572014-05-07 20:00:04 +0000741 untiledCanvas.restore();
Robert Phillips12078432018-05-17 11:17:39 -0400742 untiledCanvas.flush();
743
744 tiledCanvas.clear(SK_ColorTRANSPARENT);
senorblanco@chromium.orgd4db6572014-05-07 20:00:04 +0000745 for (int y = 0; y < height; y += tileSize) {
746 for (int x = 0; x < width; x += tileSize) {
747 tiledCanvas.save();
Robert Phillips12078432018-05-17 11:17:39 -0400748 const SkRect clipRect = SkRect::MakeXYWH(x, y, tileSize, tileSize);
749 tiledCanvas.clipRect(clipRect);
750 if (filters.needsSaveLayer(i)) {
751 const SkRect layerBounds = SkRect::MakeWH(width, height);
752 tiledCanvas.saveLayer(&layerBounds, &combinedPaint);
753 tiledCanvas.scale(SkIntToScalar(scale), SkIntToScalar(scale));
754 tiledCanvas.drawString(text, 0, yPos, textPaint);
755 tiledCanvas.restore();
756 } else {
757 tiledCanvas.scale(SkIntToScalar(scale), SkIntToScalar(scale));
758 tiledCanvas.drawString(text, 0, yPos, combinedPaint);
759 }
760
senorblanco@chromium.orgd4db6572014-05-07 20:00:04 +0000761 tiledCanvas.restore();
762 }
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +0000763 }
senorblanco@chromium.orgd4db6572014-05-07 20:00:04 +0000764 tiledCanvas.flush();
Robert Phillips12078432018-05-17 11:17:39 -0400765
Mike Reed34042072017-08-08 16:29:22 -0400766 if (!sk_tool_utils::equal_pixels(untiledResult, tiledResult, 1)) {
Brian Salomon1c80e992018-01-29 09:50:47 -0500767 REPORTER_ASSERT(reporter, false, filters.getName(i));
Mike Reed5a625e02017-08-08 15:48:54 -0400768 break;
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +0000769 }
770 }
771 }
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +0000772}
773
mtklein3f3b3d02014-12-01 11:47:08 -0800774static void draw_saveLayer_picture(int width, int height, int tileSize,
robertphillipsa8d7f0b2014-08-29 08:03:56 -0700775 SkBBHFactory* factory, SkBitmap* result) {
mtkleind910f542014-08-22 09:06:34 -0700776
777 SkMatrix matrix;
778 matrix.setTranslate(SkIntToScalar(50), 0);
779
Mike Reed7d954ad2016-10-28 15:42:34 -0400780 sk_sp<SkColorFilter> cf(SkColorFilter::MakeModeFilter(SK_ColorWHITE, SkBlendMode::kSrc));
robertphillips5605b562016-04-05 11:50:42 -0700781 sk_sp<SkImageFilter> cfif(SkColorFilterImageFilter::Make(std::move(cf), nullptr));
robertphillipsae8c9332016-04-05 15:09:00 -0700782 sk_sp<SkImageFilter> imageFilter(SkImageFilter::MakeMatrixFilter(matrix,
783 kNone_SkFilterQuality,
784 std::move(cfif)));
mtkleind910f542014-08-22 09:06:34 -0700785
786 SkPaint paint;
robertphillips5605b562016-04-05 11:50:42 -0700787 paint.setImageFilter(std::move(imageFilter));
mtkleind910f542014-08-22 09:06:34 -0700788 SkPictureRecorder recorder;
789 SkRect bounds = SkRect::Make(SkIRect::MakeXYWH(0, 0, 50, 50));
mtklein3f3b3d02014-12-01 11:47:08 -0800790 SkCanvas* recordingCanvas = recorder.beginRecording(SkIntToScalar(width),
791 SkIntToScalar(height),
robertphillipsa8d7f0b2014-08-29 08:03:56 -0700792 factory, 0);
mtkleind910f542014-08-22 09:06:34 -0700793 recordingCanvas->translate(-55, 0);
794 recordingCanvas->saveLayer(&bounds, &paint);
795 recordingCanvas->restore();
reedca2622b2016-03-18 07:25:55 -0700796 sk_sp<SkPicture> picture1(recorder.finishRecordingAsPicture());
mtkleind910f542014-08-22 09:06:34 -0700797
798 result->allocN32Pixels(width, height);
799 SkCanvas canvas(*result);
800 canvas.clear(0);
801 canvas.clipRect(SkRect::Make(SkIRect::MakeWH(tileSize, tileSize)));
802 canvas.drawPicture(picture1.get());
803}
804
805DEF_TEST(ImageFilterDrawMatrixBBH, reporter) {
806 // Check that matrix filter when drawn tiled with BBH exactly
807 // matches the same thing drawn without BBH.
808 // Tests pass by not asserting.
809
810 const int width = 200, height = 200;
811 const int tileSize = 100;
812 SkBitmap result1, result2;
813 SkRTreeFactory factory;
814
robertphillipsa8d7f0b2014-08-29 08:03:56 -0700815 draw_saveLayer_picture(width, height, tileSize, &factory, &result1);
halcanary96fcdcc2015-08-27 07:41:13 -0700816 draw_saveLayer_picture(width, height, tileSize, nullptr, &result2);
mtkleind910f542014-08-22 09:06:34 -0700817
818 for (int y = 0; y < height; y++) {
819 int diffs = memcmp(result1.getAddr32(0, y), result2.getAddr32(0, y), result1.rowBytes());
820 REPORTER_ASSERT(reporter, !diffs);
821 if (diffs) {
822 break;
823 }
824 }
825}
826
robertphillips6e7025a2016-04-04 04:31:25 -0700827static sk_sp<SkImageFilter> make_blur(sk_sp<SkImageFilter> input) {
828 return SkBlurImageFilter::Make(SK_Scalar1, SK_Scalar1, std::move(input));
senorblanco1150a6d2014-08-25 12:46:58 -0700829}
830
robertphillips6e7025a2016-04-04 04:31:25 -0700831static sk_sp<SkImageFilter> make_drop_shadow(sk_sp<SkImageFilter> input) {
robertphillipsc4169122016-04-06 08:40:59 -0700832 return SkDropShadowImageFilter::Make(
senorblanco1150a6d2014-08-25 12:46:58 -0700833 SkIntToScalar(100), SkIntToScalar(100),
834 SkIntToScalar(10), SkIntToScalar(10),
sugoi234f0362014-10-23 13:59:52 -0700835 SK_ColorBLUE, SkDropShadowImageFilter::kDrawShadowAndForeground_ShadowMode,
robertphillipsc4169122016-04-06 08:40:59 -0700836 std::move(input));
senorblanco1150a6d2014-08-25 12:46:58 -0700837}
838
839DEF_TEST(ImageFilterBlurThenShadowBounds, reporter) {
robertphillips6e7025a2016-04-04 04:31:25 -0700840 sk_sp<SkImageFilter> filter1(make_blur(nullptr));
841 sk_sp<SkImageFilter> filter2(make_drop_shadow(std::move(filter1)));
senorblanco1150a6d2014-08-25 12:46:58 -0700842
843 SkIRect bounds = SkIRect::MakeXYWH(0, 0, 100, 100);
Herb Derby59f8f152017-10-17 22:27:23 +0000844 SkIRect expectedBounds = SkIRect::MakeXYWH(-133, -133, 236, 236);
Robert Phillips12078432018-05-17 11:17:39 -0400845 bounds = filter2->filterBounds(bounds, SkMatrix::I(),
846 SkImageFilter::kReverse_MapDirection, &bounds);
senorblanco1150a6d2014-08-25 12:46:58 -0700847
848 REPORTER_ASSERT(reporter, bounds == expectedBounds);
849}
850
851DEF_TEST(ImageFilterShadowThenBlurBounds, reporter) {
robertphillips6e7025a2016-04-04 04:31:25 -0700852 sk_sp<SkImageFilter> filter1(make_drop_shadow(nullptr));
853 sk_sp<SkImageFilter> filter2(make_blur(std::move(filter1)));
senorblanco1150a6d2014-08-25 12:46:58 -0700854
855 SkIRect bounds = SkIRect::MakeXYWH(0, 0, 100, 100);
Herb Derby59f8f152017-10-17 22:27:23 +0000856 SkIRect expectedBounds = SkIRect::MakeXYWH(-133, -133, 236, 236);
Robert Phillips12078432018-05-17 11:17:39 -0400857 bounds = filter2->filterBounds(bounds, SkMatrix::I(),
858 SkImageFilter::kReverse_MapDirection, &bounds);
senorblanco1150a6d2014-08-25 12:46:58 -0700859
860 REPORTER_ASSERT(reporter, bounds == expectedBounds);
861}
862
863DEF_TEST(ImageFilterDilateThenBlurBounds, reporter) {
robertphillipsfc11b0a2016-04-05 09:09:36 -0700864 sk_sp<SkImageFilter> filter1(SkDilateImageFilter::Make(2, 2, nullptr));
robertphillips6e7025a2016-04-04 04:31:25 -0700865 sk_sp<SkImageFilter> filter2(make_drop_shadow(std::move(filter1)));
senorblanco1150a6d2014-08-25 12:46:58 -0700866
867 SkIRect bounds = SkIRect::MakeXYWH(0, 0, 100, 100);
868 SkIRect expectedBounds = SkIRect::MakeXYWH(-132, -132, 234, 234);
Robert Phillips12078432018-05-17 11:17:39 -0400869 bounds = filter2->filterBounds(bounds, SkMatrix::I(),
870 SkImageFilter::kReverse_MapDirection, &bounds);
senorblanco1150a6d2014-08-25 12:46:58 -0700871
872 REPORTER_ASSERT(reporter, bounds == expectedBounds);
873}
874
jbroman203a9932016-07-11 14:07:59 -0700875DEF_TEST(ImageFilterScaledBlurRadius, reporter) {
876 // Each blur should spread 3*sigma, so 3 for the blur and 30 for the shadow
877 // (before the CTM). Bounds should be computed correctly in the presence of
878 // a (possibly negative) scale.
879 sk_sp<SkImageFilter> blur(make_blur(nullptr));
880 sk_sp<SkImageFilter> dropShadow(make_drop_shadow(nullptr));
881 {
882 // Uniform scale by 2.
883 SkMatrix scaleMatrix;
884 scaleMatrix.setScale(2, 2);
885 SkIRect bounds = SkIRect::MakeLTRB(0, 0, 200, 200);
886
Herb Derby59f8f152017-10-17 22:27:23 +0000887 SkIRect expectedBlurBounds = SkIRect::MakeLTRB(-6, -6, 206, 206);
jbroman203a9932016-07-11 14:07:59 -0700888 SkIRect blurBounds = blur->filterBounds(
Robert Phillips12078432018-05-17 11:17:39 -0400889 bounds, scaleMatrix, SkImageFilter::kForward_MapDirection, nullptr);
jbroman203a9932016-07-11 14:07:59 -0700890 REPORTER_ASSERT(reporter, blurBounds == expectedBlurBounds);
891 SkIRect reverseBlurBounds = blur->filterBounds(
Robert Phillips12078432018-05-17 11:17:39 -0400892 bounds, scaleMatrix, SkImageFilter::kReverse_MapDirection, &bounds);
jbroman203a9932016-07-11 14:07:59 -0700893 REPORTER_ASSERT(reporter, reverseBlurBounds == expectedBlurBounds);
894
895 SkIRect expectedShadowBounds = SkIRect::MakeLTRB(0, 0, 460, 460);
896 SkIRect shadowBounds = dropShadow->filterBounds(
Robert Phillips12078432018-05-17 11:17:39 -0400897 bounds, scaleMatrix, SkImageFilter::kForward_MapDirection, nullptr);
jbroman203a9932016-07-11 14:07:59 -0700898 REPORTER_ASSERT(reporter, shadowBounds == expectedShadowBounds);
899 SkIRect expectedReverseShadowBounds =
900 SkIRect::MakeLTRB(-260, -260, 200, 200);
901 SkIRect reverseShadowBounds = dropShadow->filterBounds(
Robert Phillips12078432018-05-17 11:17:39 -0400902 bounds, scaleMatrix, SkImageFilter::kReverse_MapDirection, &bounds);
jbroman203a9932016-07-11 14:07:59 -0700903 REPORTER_ASSERT(reporter,
904 reverseShadowBounds == expectedReverseShadowBounds);
905 }
906 {
907 // Vertical flip.
908 SkMatrix scaleMatrix;
909 scaleMatrix.setScale(1, -1);
910 SkIRect bounds = SkIRect::MakeLTRB(0, -100, 100, 0);
911
Herb Derby59f8f152017-10-17 22:27:23 +0000912 SkIRect expectedBlurBounds = SkIRect::MakeLTRB(-3, -103, 103, 3);
jbroman203a9932016-07-11 14:07:59 -0700913 SkIRect blurBounds = blur->filterBounds(
Robert Phillips12078432018-05-17 11:17:39 -0400914 bounds, scaleMatrix, SkImageFilter::kForward_MapDirection, nullptr);
jbroman203a9932016-07-11 14:07:59 -0700915 REPORTER_ASSERT(reporter, blurBounds == expectedBlurBounds);
916 SkIRect reverseBlurBounds = blur->filterBounds(
Robert Phillips12078432018-05-17 11:17:39 -0400917 bounds, scaleMatrix, SkImageFilter::kReverse_MapDirection, &bounds);
jbroman203a9932016-07-11 14:07:59 -0700918 REPORTER_ASSERT(reporter, reverseBlurBounds == expectedBlurBounds);
919
920 SkIRect expectedShadowBounds = SkIRect::MakeLTRB(0, -230, 230, 0);
921 SkIRect shadowBounds = dropShadow->filterBounds(
Robert Phillips12078432018-05-17 11:17:39 -0400922 bounds, scaleMatrix, SkImageFilter::kForward_MapDirection, nullptr);
jbroman203a9932016-07-11 14:07:59 -0700923 REPORTER_ASSERT(reporter, shadowBounds == expectedShadowBounds);
924 SkIRect expectedReverseShadowBounds =
925 SkIRect::MakeLTRB(-130, -100, 100, 130);
926 SkIRect reverseShadowBounds = dropShadow->filterBounds(
Robert Phillips12078432018-05-17 11:17:39 -0400927 bounds, scaleMatrix, SkImageFilter::kReverse_MapDirection, &bounds);
jbroman203a9932016-07-11 14:07:59 -0700928 REPORTER_ASSERT(reporter,
929 reverseShadowBounds == expectedReverseShadowBounds);
930 }
931}
932
ajuma5788faa2015-02-13 09:05:47 -0800933DEF_TEST(ImageFilterComposedBlurFastBounds, reporter) {
robertphillips6e7025a2016-04-04 04:31:25 -0700934 sk_sp<SkImageFilter> filter1(make_blur(nullptr));
935 sk_sp<SkImageFilter> filter2(make_blur(nullptr));
robertphillips491fb172016-03-30 12:32:58 -0700936 sk_sp<SkImageFilter> composedFilter(SkComposeImageFilter::Make(std::move(filter1),
937 std::move(filter2)));
ajuma5788faa2015-02-13 09:05:47 -0800938
939 SkRect boundsSrc = SkRect::MakeWH(SkIntToScalar(100), SkIntToScalar(100));
940 SkRect expectedBounds = SkRect::MakeXYWH(
Herb Derby59f8f152017-10-17 22:27:23 +0000941 SkIntToScalar(-6), SkIntToScalar(-6), SkIntToScalar(112), SkIntToScalar(112));
senorblancoe5e79842016-03-21 14:51:59 -0700942 SkRect boundsDst = composedFilter->computeFastBounds(boundsSrc);
ajuma5788faa2015-02-13 09:05:47 -0800943
944 REPORTER_ASSERT(reporter, boundsDst == expectedBounds);
945}
946
jbroman0e3129d2016-03-17 12:24:23 -0700947DEF_TEST(ImageFilterUnionBounds, reporter) {
robertphillips51a315e2016-03-31 09:05:49 -0700948 sk_sp<SkImageFilter> offset(SkOffsetImageFilter::Make(50, 0, nullptr));
jbroman0e3129d2016-03-17 12:24:23 -0700949 // Regardless of which order they appear in, the image filter bounds should
950 // be combined correctly.
951 {
reed374772b2016-10-05 17:33:02 -0700952 sk_sp<SkImageFilter> composite(SkXfermodeImageFilter::Make(SkBlendMode::kSrcOver, offset));
jbroman0e3129d2016-03-17 12:24:23 -0700953 SkRect bounds = SkRect::MakeWH(100, 100);
954 // Intentionally aliasing here, as that's what the real callers do.
senorblancoe5e79842016-03-21 14:51:59 -0700955 bounds = composite->computeFastBounds(bounds);
jbroman0e3129d2016-03-17 12:24:23 -0700956 REPORTER_ASSERT(reporter, bounds == SkRect::MakeWH(150, 100));
957 }
958 {
reed374772b2016-10-05 17:33:02 -0700959 sk_sp<SkImageFilter> composite(SkXfermodeImageFilter::Make(SkBlendMode::kSrcOver, nullptr,
robertphillips8c0326d2016-04-05 12:48:34 -0700960 offset, nullptr));
jbroman0e3129d2016-03-17 12:24:23 -0700961 SkRect bounds = SkRect::MakeWH(100, 100);
962 // Intentionally aliasing here, as that's what the real callers do.
senorblancoe5e79842016-03-21 14:51:59 -0700963 bounds = composite->computeFastBounds(bounds);
jbroman0e3129d2016-03-17 12:24:23 -0700964 REPORTER_ASSERT(reporter, bounds == SkRect::MakeWH(150, 100));
965 }
966}
967
robertphillips3e302272016-04-20 11:48:36 -0700968static void test_imagefilter_merge_result_size(skiatest::Reporter* reporter, GrContext* context) {
senorblanco4a243982015-11-25 07:06:55 -0800969 SkBitmap greenBM;
970 greenBM.allocN32Pixels(20, 20);
971 greenBM.eraseColor(SK_ColorGREEN);
reed9ce9d672016-03-17 10:51:11 -0700972 sk_sp<SkImage> greenImage(SkImage::MakeFromBitmap(greenBM));
robertphillips549c8992016-04-01 09:28:51 -0700973 sk_sp<SkImageFilter> source(SkImageSource::Make(std::move(greenImage)));
Mike Reed0bdaf052017-06-18 23:35:57 -0400974 sk_sp<SkImageFilter> merge(SkMergeImageFilter::Make(source, source));
senorblanco4a243982015-11-25 07:06:55 -0800975
robertphillips3e302272016-04-20 11:48:36 -0700976 sk_sp<SkSpecialImage> srcImg(create_empty_special_image(context, 1));
robertphillips4418dba2016-03-07 12:45:14 -0800977
brianosman2a75e5d2016-09-22 07:15:37 -0700978 SkImageFilter::OutputProperties noColorSpace(nullptr);
979 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeXYWH(0, 0, 100, 100), nullptr,
980 noColorSpace);
senorblanco4a243982015-11-25 07:06:55 -0800981 SkIPoint offset;
robertphillips4418dba2016-03-07 12:45:14 -0800982
robertphillips2302de92016-03-24 07:26:32 -0700983 sk_sp<SkSpecialImage> resultImg(merge->filterImage(srcImg.get(), ctx, &offset));
robertphillips4418dba2016-03-07 12:45:14 -0800984 REPORTER_ASSERT(reporter, resultImg);
985
986 REPORTER_ASSERT(reporter, resultImg->width() == 20 && resultImg->height() == 20);
senorblanco4a243982015-11-25 07:06:55 -0800987}
988
robertphillips4418dba2016-03-07 12:45:14 -0800989DEF_TEST(ImageFilterMergeResultSize, reporter) {
robertphillips3e302272016-04-20 11:48:36 -0700990 test_imagefilter_merge_result_size(reporter, nullptr);
robertphillips4418dba2016-03-07 12:45:14 -0800991}
992
egdanielab527a52016-06-28 08:07:26 -0700993DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterMergeResultSize_Gpu, reporter, ctxInfo) {
bsalomon8b7451a2016-05-11 06:33:06 -0700994 test_imagefilter_merge_result_size(reporter, ctxInfo.grContext());
robertphillips4418dba2016-03-07 12:45:14 -0800995}
robertphillips4418dba2016-03-07 12:45:14 -0800996
robertphillipsa8d7f0b2014-08-29 08:03:56 -0700997static void draw_blurred_rect(SkCanvas* canvas) {
senorblanco837f5322014-07-14 10:19:54 -0700998 SkPaint filterPaint;
999 filterPaint.setColor(SK_ColorWHITE);
robertphillips6e7025a2016-04-04 04:31:25 -07001000 filterPaint.setImageFilter(SkBlurImageFilter::Make(SkIntToScalar(8), 0, nullptr));
halcanary96fcdcc2015-08-27 07:41:13 -07001001 canvas->saveLayer(nullptr, &filterPaint);
senorblanco837f5322014-07-14 10:19:54 -07001002 SkPaint whitePaint;
1003 whitePaint.setColor(SK_ColorWHITE);
1004 canvas->drawRect(SkRect::Make(SkIRect::MakeWH(4, 4)), whitePaint);
1005 canvas->restore();
1006}
1007
robertphillipsa8d7f0b2014-08-29 08:03:56 -07001008static void draw_picture_clipped(SkCanvas* canvas, const SkRect& clipRect, const SkPicture* picture) {
senorblanco837f5322014-07-14 10:19:54 -07001009 canvas->save();
1010 canvas->clipRect(clipRect);
1011 canvas->drawPicture(picture);
1012 canvas->restore();
1013}
1014
1015DEF_TEST(ImageFilterDrawTiledBlurRTree, reporter) {
1016 // Check that the blur filter when recorded with RTree acceleration,
1017 // and drawn tiled (with subsequent clip rects) exactly
1018 // matches the same filter drawn with without RTree acceleration.
1019 // This tests that the "bleed" from the blur into the otherwise-blank
1020 // tiles is correctly rendered.
1021 // Tests pass by not asserting.
1022
1023 int width = 16, height = 8;
1024 SkBitmap result1, result2;
1025 result1.allocN32Pixels(width, height);
1026 result2.allocN32Pixels(width, height);
1027 SkCanvas canvas1(result1);
1028 SkCanvas canvas2(result2);
1029 int tileSize = 8;
1030
1031 canvas1.clear(0);
1032 canvas2.clear(0);
1033
1034 SkRTreeFactory factory;
1035
1036 SkPictureRecorder recorder1, recorder2;
1037 // The only difference between these two pictures is that one has RTree aceleration.
mtklein3f3b3d02014-12-01 11:47:08 -08001038 SkCanvas* recordingCanvas1 = recorder1.beginRecording(SkIntToScalar(width),
1039 SkIntToScalar(height),
halcanary96fcdcc2015-08-27 07:41:13 -07001040 nullptr, 0);
mtklein3f3b3d02014-12-01 11:47:08 -08001041 SkCanvas* recordingCanvas2 = recorder2.beginRecording(SkIntToScalar(width),
1042 SkIntToScalar(height),
robertphillipsa8d7f0b2014-08-29 08:03:56 -07001043 &factory, 0);
1044 draw_blurred_rect(recordingCanvas1);
1045 draw_blurred_rect(recordingCanvas2);
reedca2622b2016-03-18 07:25:55 -07001046 sk_sp<SkPicture> picture1(recorder1.finishRecordingAsPicture());
1047 sk_sp<SkPicture> picture2(recorder2.finishRecordingAsPicture());
senorblanco837f5322014-07-14 10:19:54 -07001048 for (int y = 0; y < height; y += tileSize) {
1049 for (int x = 0; x < width; x += tileSize) {
1050 SkRect tileRect = SkRect::Make(SkIRect::MakeXYWH(x, y, tileSize, tileSize));
reedca2622b2016-03-18 07:25:55 -07001051 draw_picture_clipped(&canvas1, tileRect, picture1.get());
1052 draw_picture_clipped(&canvas2, tileRect, picture2.get());
senorblanco837f5322014-07-14 10:19:54 -07001053 }
1054 }
1055 for (int y = 0; y < height; y++) {
1056 int diffs = memcmp(result1.getAddr32(0, y), result2.getAddr32(0, y), result1.rowBytes());
1057 REPORTER_ASSERT(reporter, !diffs);
1058 if (diffs) {
1059 break;
1060 }
1061 }
1062}
1063
senorblanco@chromium.org91957432014-05-01 14:03:41 +00001064DEF_TEST(ImageFilterMatrixConvolution, reporter) {
1065 // Check that a 1x3 filter does not cause a spurious assert.
1066 SkScalar kernel[3] = {
1067 SkIntToScalar( 1), SkIntToScalar( 1), SkIntToScalar( 1),
1068 };
1069 SkISize kernelSize = SkISize::Make(1, 3);
1070 SkScalar gain = SK_Scalar1, bias = 0;
1071 SkIPoint kernelOffset = SkIPoint::Make(0, 0);
1072
robertphillipsef6a47b2016-04-08 08:01:20 -07001073 sk_sp<SkImageFilter> filter(SkMatrixConvolutionImageFilter::Make(
1074 kernelSize, kernel,
1075 gain, bias, kernelOffset,
1076 SkMatrixConvolutionImageFilter::kRepeat_TileMode,
1077 false, nullptr));
senorblanco@chromium.org91957432014-05-01 14:03:41 +00001078
1079 SkBitmap result;
1080 int width = 16, height = 16;
1081 result.allocN32Pixels(width, height);
1082 SkCanvas canvas(result);
1083 canvas.clear(0);
1084
1085 SkPaint paint;
robertphillipsef6a47b2016-04-08 08:01:20 -07001086 paint.setImageFilter(std::move(filter));
senorblanco@chromium.org91957432014-05-01 14:03:41 +00001087 SkRect rect = SkRect::Make(SkIRect::MakeWH(width, height));
1088 canvas.drawRect(rect, paint);
1089}
1090
senorblanco@chromium.org8c7372b2014-05-02 19:13:11 +00001091DEF_TEST(ImageFilterMatrixConvolutionBorder, reporter) {
1092 // Check that a filter with borders outside the target bounds
1093 // does not crash.
1094 SkScalar kernel[3] = {
1095 0, 0, 0,
1096 };
1097 SkISize kernelSize = SkISize::Make(3, 1);
1098 SkScalar gain = SK_Scalar1, bias = 0;
1099 SkIPoint kernelOffset = SkIPoint::Make(2, 0);
1100
robertphillipsef6a47b2016-04-08 08:01:20 -07001101 sk_sp<SkImageFilter> filter(SkMatrixConvolutionImageFilter::Make(
1102 kernelSize, kernel, gain, bias, kernelOffset,
1103 SkMatrixConvolutionImageFilter::kClamp_TileMode,
1104 true, nullptr));
senorblanco@chromium.org8c7372b2014-05-02 19:13:11 +00001105
1106 SkBitmap result;
1107
1108 int width = 10, height = 10;
1109 result.allocN32Pixels(width, height);
1110 SkCanvas canvas(result);
1111 canvas.clear(0);
1112
1113 SkPaint filterPaint;
robertphillipsef6a47b2016-04-08 08:01:20 -07001114 filterPaint.setImageFilter(std::move(filter));
senorblanco@chromium.org8c7372b2014-05-02 19:13:11 +00001115 SkRect bounds = SkRect::MakeWH(1, 10);
1116 SkRect rect = SkRect::Make(SkIRect::MakeWH(width, height));
1117 SkPaint rectPaint;
1118 canvas.saveLayer(&bounds, &filterPaint);
1119 canvas.drawRect(rect, rectPaint);
1120 canvas.restore();
1121}
1122
robertphillips3e302272016-04-20 11:48:36 -07001123static void test_big_kernel(skiatest::Reporter* reporter, GrContext* context) {
robertphillipsdada4dd2016-04-13 04:54:36 -07001124 // Check that a kernel that is too big for the GPU still works
1125 SkScalar identityKernel[49] = {
1126 0, 0, 0, 0, 0, 0, 0,
1127 0, 0, 0, 0, 0, 0, 0,
1128 0, 0, 0, 0, 0, 0, 0,
1129 0, 0, 0, 1, 0, 0, 0,
1130 0, 0, 0, 0, 0, 0, 0,
1131 0, 0, 0, 0, 0, 0, 0,
1132 0, 0, 0, 0, 0, 0, 0
1133 };
1134 SkISize kernelSize = SkISize::Make(7, 7);
1135 SkScalar gain = SK_Scalar1, bias = 0;
1136 SkIPoint kernelOffset = SkIPoint::Make(0, 0);
1137
1138 sk_sp<SkImageFilter> filter(SkMatrixConvolutionImageFilter::Make(
1139 kernelSize, identityKernel, gain, bias, kernelOffset,
1140 SkMatrixConvolutionImageFilter::kClamp_TileMode,
1141 true, nullptr));
1142
robertphillips3e302272016-04-20 11:48:36 -07001143 sk_sp<SkSpecialImage> srcImg(create_empty_special_image(context, 100));
robertphillipsdada4dd2016-04-13 04:54:36 -07001144 SkASSERT(srcImg);
1145
1146 SkIPoint offset;
brianosman2a75e5d2016-09-22 07:15:37 -07001147 SkImageFilter::OutputProperties noColorSpace(nullptr);
1148 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeWH(100, 100), nullptr, noColorSpace);
robertphillipsdada4dd2016-04-13 04:54:36 -07001149 sk_sp<SkSpecialImage> resultImg(filter->filterImage(srcImg.get(), ctx, &offset));
1150 REPORTER_ASSERT(reporter, resultImg);
1151 REPORTER_ASSERT(reporter, SkToBool(context) == resultImg->isTextureBacked());
1152 REPORTER_ASSERT(reporter, resultImg->width() == 100 && resultImg->height() == 100);
1153 REPORTER_ASSERT(reporter, offset.fX == 0 && offset.fY == 0);
1154}
1155
1156DEF_TEST(ImageFilterMatrixConvolutionBigKernel, reporter) {
robertphillips3e302272016-04-20 11:48:36 -07001157 test_big_kernel(reporter, nullptr);
robertphillipsdada4dd2016-04-13 04:54:36 -07001158}
1159
egdanielab527a52016-06-28 08:07:26 -07001160DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterMatrixConvolutionBigKernel_Gpu,
1161 reporter, ctxInfo) {
bsalomon8b7451a2016-05-11 06:33:06 -07001162 test_big_kernel(reporter, ctxInfo.grContext());
robertphillipsdada4dd2016-04-13 04:54:36 -07001163}
robertphillipsdada4dd2016-04-13 04:54:36 -07001164
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +00001165DEF_TEST(ImageFilterCropRect, reporter) {
robertphillips3e302272016-04-20 11:48:36 -07001166 test_crop_rects(reporter, nullptr);
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +00001167}
1168
bsalomon68d91342016-04-12 09:59:58 -07001169DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterCropRect_Gpu, reporter, ctxInfo) {
bsalomon8b7451a2016-05-11 06:33:06 -07001170 test_crop_rects(reporter, ctxInfo.grContext());
robertphillips4418dba2016-03-07 12:45:14 -08001171}
robertphillips4418dba2016-03-07 12:45:14 -08001172
tfarina9ea53f92014-06-24 06:50:39 -07001173DEF_TEST(ImageFilterMatrix, reporter) {
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +00001174 SkBitmap temp;
mike@reedtribe.orgdeee4962014-02-13 14:41:43 +00001175 temp.allocN32Pixels(100, 100);
robertphillips9a53fd72015-06-22 09:46:59 -07001176 SkCanvas canvas(temp);
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +00001177 canvas.scale(SkIntToScalar(2), SkIntToScalar(2));
1178
1179 SkMatrix expectedMatrix = canvas.getTotalMatrix();
1180
commit-bot@chromium.org5fb2ce32014-04-17 23:35:06 +00001181 SkRTreeFactory factory;
1182 SkPictureRecorder recorder;
1183 SkCanvas* recordingCanvas = recorder.beginRecording(100, 100, &factory, 0);
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +00001184
1185 SkPaint paint;
robertphillips43c2ad42016-04-04 05:05:11 -07001186 paint.setImageFilter(MatrixTestImageFilter::Make(reporter, expectedMatrix));
halcanary96fcdcc2015-08-27 07:41:13 -07001187 recordingCanvas->saveLayer(nullptr, &paint);
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +00001188 SkPaint solidPaint;
1189 solidPaint.setColor(0xFFFFFFFF);
1190 recordingCanvas->save();
1191 recordingCanvas->scale(SkIntToScalar(10), SkIntToScalar(10));
1192 recordingCanvas->drawRect(SkRect::Make(SkIRect::MakeWH(100, 100)), solidPaint);
1193 recordingCanvas->restore(); // scale
1194 recordingCanvas->restore(); // saveLayer
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +00001195
reedca2622b2016-03-18 07:25:55 -07001196 canvas.drawPicture(recorder.finishRecordingAsPicture());
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +00001197}
1198
robertphillips3e302272016-04-20 11:48:36 -07001199static void test_clipped_picture_imagefilter(skiatest::Reporter* reporter, GrContext* context) {
reedca2622b2016-03-18 07:25:55 -07001200 sk_sp<SkPicture> picture;
senorblanco3d822c22014-07-30 14:49:31 -07001201
robertphillips4418dba2016-03-07 12:45:14 -08001202 {
1203 SkRTreeFactory factory;
1204 SkPictureRecorder recorder;
1205 SkCanvas* recordingCanvas = recorder.beginRecording(1, 1, &factory, 0);
1206
1207 // Create an SkPicture which simply draws a green 1x1 rectangle.
1208 SkPaint greenPaint;
1209 greenPaint.setColor(SK_ColorGREEN);
1210 recordingCanvas->drawRect(SkRect::Make(SkIRect::MakeWH(1, 1)), greenPaint);
reedca2622b2016-03-18 07:25:55 -07001211 picture = recorder.finishRecordingAsPicture();
robertphillips4418dba2016-03-07 12:45:14 -08001212 }
1213
robertphillips3e302272016-04-20 11:48:36 -07001214 sk_sp<SkSpecialImage> srcImg(create_empty_special_image(context, 2));
senorblanco3d822c22014-07-30 14:49:31 -07001215
robertphillips5ff17b12016-03-28 13:13:42 -07001216 sk_sp<SkImageFilter> imageFilter(SkPictureImageFilter::Make(picture));
senorblanco3d822c22014-07-30 14:49:31 -07001217
senorblanco3d822c22014-07-30 14:49:31 -07001218 SkIPoint offset;
brianosman2a75e5d2016-09-22 07:15:37 -07001219 SkImageFilter::OutputProperties noColorSpace(nullptr);
1220 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeXYWH(1, 1, 1, 1), nullptr, noColorSpace);
robertphillips4418dba2016-03-07 12:45:14 -08001221
robertphillips2302de92016-03-24 07:26:32 -07001222 sk_sp<SkSpecialImage> resultImage(imageFilter->filterImage(srcImg.get(), ctx, &offset));
robertphillips4418dba2016-03-07 12:45:14 -08001223 REPORTER_ASSERT(reporter, !resultImage);
senorblanco3d822c22014-07-30 14:49:31 -07001224}
1225
robertphillips4418dba2016-03-07 12:45:14 -08001226DEF_TEST(ImageFilterClippedPictureImageFilter, reporter) {
robertphillips3e302272016-04-20 11:48:36 -07001227 test_clipped_picture_imagefilter(reporter, nullptr);
robertphillips4418dba2016-03-07 12:45:14 -08001228}
1229
bsalomon68d91342016-04-12 09:59:58 -07001230DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterClippedPictureImageFilter_Gpu, reporter, ctxInfo) {
bsalomon8b7451a2016-05-11 06:33:06 -07001231 test_clipped_picture_imagefilter(reporter, ctxInfo.grContext());
robertphillips4418dba2016-03-07 12:45:14 -08001232}
robertphillips4418dba2016-03-07 12:45:14 -08001233
tfarina9ea53f92014-06-24 06:50:39 -07001234DEF_TEST(ImageFilterEmptySaveLayer, reporter) {
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001235 // Even when there's an empty saveLayer()/restore(), ensure that an image
1236 // filter or color filter which affects transparent black still draws.
1237
1238 SkBitmap bitmap;
1239 bitmap.allocN32Pixels(10, 10);
robertphillips9a53fd72015-06-22 09:46:59 -07001240 SkCanvas canvas(bitmap);
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001241
1242 SkRTreeFactory factory;
1243 SkPictureRecorder recorder;
1244
robertphillips5605b562016-04-05 11:50:42 -07001245 sk_sp<SkColorFilter> green(SkColorFilter::MakeModeFilter(SK_ColorGREEN,
Mike Reed7d954ad2016-10-28 15:42:34 -04001246 SkBlendMode::kSrc));
robertphillips5605b562016-04-05 11:50:42 -07001247 sk_sp<SkImageFilter> imageFilter(SkColorFilterImageFilter::Make(green, nullptr));
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001248 SkPaint imageFilterPaint;
robertphillips5605b562016-04-05 11:50:42 -07001249 imageFilterPaint.setImageFilter(std::move(imageFilter));
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001250 SkPaint colorFilterPaint;
reedd053ce92016-03-22 10:17:23 -07001251 colorFilterPaint.setColorFilter(green);
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001252
1253 SkRect bounds = SkRect::MakeWH(10, 10);
1254
1255 SkCanvas* recordingCanvas = recorder.beginRecording(10, 10, &factory, 0);
1256 recordingCanvas->saveLayer(&bounds, &imageFilterPaint);
1257 recordingCanvas->restore();
reedca2622b2016-03-18 07:25:55 -07001258 sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture());
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001259
1260 canvas.clear(0);
robertphillips9b14f262014-06-04 05:40:44 -07001261 canvas.drawPicture(picture);
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001262 uint32_t pixel = *bitmap.getAddr32(0, 0);
1263 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1264
1265 recordingCanvas = recorder.beginRecording(10, 10, &factory, 0);
halcanary96fcdcc2015-08-27 07:41:13 -07001266 recordingCanvas->saveLayer(nullptr, &imageFilterPaint);
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001267 recordingCanvas->restore();
reedca2622b2016-03-18 07:25:55 -07001268 sk_sp<SkPicture> picture2(recorder.finishRecordingAsPicture());
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001269
1270 canvas.clear(0);
robertphillips9b14f262014-06-04 05:40:44 -07001271 canvas.drawPicture(picture2);
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001272 pixel = *bitmap.getAddr32(0, 0);
1273 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1274
1275 recordingCanvas = recorder.beginRecording(10, 10, &factory, 0);
1276 recordingCanvas->saveLayer(&bounds, &colorFilterPaint);
1277 recordingCanvas->restore();
reedca2622b2016-03-18 07:25:55 -07001278 sk_sp<SkPicture> picture3(recorder.finishRecordingAsPicture());
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001279
1280 canvas.clear(0);
robertphillips9b14f262014-06-04 05:40:44 -07001281 canvas.drawPicture(picture3);
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001282 pixel = *bitmap.getAddr32(0, 0);
1283 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1284}
1285
robertphillips9a53fd72015-06-22 09:46:59 -07001286static void test_huge_blur(SkCanvas* canvas, skiatest::Reporter* reporter) {
senorblanco@chromium.org09843fd2014-03-24 20:50:59 +00001287 SkBitmap bitmap;
1288 bitmap.allocN32Pixels(100, 100);
1289 bitmap.eraseARGB(0, 0, 0, 0);
1290
1291 // Check that a blur with an insane radius does not crash or assert.
senorblanco@chromium.org09843fd2014-03-24 20:50:59 +00001292 SkPaint paint;
robertphillips6e7025a2016-04-04 04:31:25 -07001293 paint.setImageFilter(SkBlurImageFilter::Make(SkIntToScalar(1<<30),
1294 SkIntToScalar(1<<30),
1295 nullptr));
reedda420b92015-12-16 08:38:15 -08001296 canvas->drawBitmap(bitmap, 0, 0, &paint);
senorblanco@chromium.org09843fd2014-03-24 20:50:59 +00001297}
1298
1299DEF_TEST(HugeBlurImageFilter, reporter) {
1300 SkBitmap temp;
1301 temp.allocN32Pixels(100, 100);
robertphillips9a53fd72015-06-22 09:46:59 -07001302 SkCanvas canvas(temp);
1303 test_huge_blur(&canvas, reporter);
senorblanco@chromium.org09843fd2014-03-24 20:50:59 +00001304}
1305
senorblanco21a465d2016-04-11 11:58:39 -07001306DEF_TEST(ImageFilterMatrixConvolutionSanityTest, reporter) {
senorblanco3a495202014-09-29 07:57:20 -07001307 SkScalar kernel[1] = { 0 };
1308 SkScalar gain = SK_Scalar1, bias = 0;
1309 SkIPoint kernelOffset = SkIPoint::Make(1, 1);
1310
halcanary96fcdcc2015-08-27 07:41:13 -07001311 // Check that an enormous (non-allocatable) kernel gives a nullptr filter.
robertphillipsef6a47b2016-04-08 08:01:20 -07001312 sk_sp<SkImageFilter> conv(SkMatrixConvolutionImageFilter::Make(
senorblanco3a495202014-09-29 07:57:20 -07001313 SkISize::Make(1<<30, 1<<30),
1314 kernel,
1315 gain,
1316 bias,
1317 kernelOffset,
1318 SkMatrixConvolutionImageFilter::kRepeat_TileMode,
robertphillipsef6a47b2016-04-08 08:01:20 -07001319 false,
1320 nullptr));
senorblanco3a495202014-09-29 07:57:20 -07001321
halcanary96fcdcc2015-08-27 07:41:13 -07001322 REPORTER_ASSERT(reporter, nullptr == conv.get());
senorblanco3a495202014-09-29 07:57:20 -07001323
halcanary96fcdcc2015-08-27 07:41:13 -07001324 // Check that a nullptr kernel gives a nullptr filter.
robertphillipsef6a47b2016-04-08 08:01:20 -07001325 conv = SkMatrixConvolutionImageFilter::Make(
senorblanco3a495202014-09-29 07:57:20 -07001326 SkISize::Make(1, 1),
halcanary96fcdcc2015-08-27 07:41:13 -07001327 nullptr,
senorblanco3a495202014-09-29 07:57:20 -07001328 gain,
1329 bias,
1330 kernelOffset,
1331 SkMatrixConvolutionImageFilter::kRepeat_TileMode,
robertphillipsef6a47b2016-04-08 08:01:20 -07001332 false,
1333 nullptr);
senorblanco3a495202014-09-29 07:57:20 -07001334
halcanary96fcdcc2015-08-27 07:41:13 -07001335 REPORTER_ASSERT(reporter, nullptr == conv.get());
senorblanco3a495202014-09-29 07:57:20 -07001336
halcanary96fcdcc2015-08-27 07:41:13 -07001337 // Check that a kernel width < 1 gives a nullptr filter.
robertphillipsef6a47b2016-04-08 08:01:20 -07001338 conv = SkMatrixConvolutionImageFilter::Make(
senorblanco3a495202014-09-29 07:57:20 -07001339 SkISize::Make(0, 1),
1340 kernel,
1341 gain,
1342 bias,
1343 kernelOffset,
1344 SkMatrixConvolutionImageFilter::kRepeat_TileMode,
robertphillipsef6a47b2016-04-08 08:01:20 -07001345 false,
1346 nullptr);
senorblanco3a495202014-09-29 07:57:20 -07001347
halcanary96fcdcc2015-08-27 07:41:13 -07001348 REPORTER_ASSERT(reporter, nullptr == conv.get());
senorblanco3a495202014-09-29 07:57:20 -07001349
halcanary96fcdcc2015-08-27 07:41:13 -07001350 // Check that kernel height < 1 gives a nullptr filter.
robertphillipsef6a47b2016-04-08 08:01:20 -07001351 conv = SkMatrixConvolutionImageFilter::Make(
senorblanco3a495202014-09-29 07:57:20 -07001352 SkISize::Make(1, -1),
1353 kernel,
1354 gain,
1355 bias,
1356 kernelOffset,
1357 SkMatrixConvolutionImageFilter::kRepeat_TileMode,
robertphillipsef6a47b2016-04-08 08:01:20 -07001358 false,
1359 nullptr);
senorblanco3a495202014-09-29 07:57:20 -07001360
halcanary96fcdcc2015-08-27 07:41:13 -07001361 REPORTER_ASSERT(reporter, nullptr == conv.get());
senorblanco3a495202014-09-29 07:57:20 -07001362}
1363
Mike Reedf1942192017-07-21 14:24:29 -04001364static void test_xfermode_cropped_input(SkSurface* surf, skiatest::Reporter* reporter) {
1365 auto canvas = surf->getCanvas();
robertphillips9a53fd72015-06-22 09:46:59 -07001366 canvas->clear(0);
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001367
1368 SkBitmap bitmap;
1369 bitmap.allocN32Pixels(1, 1);
1370 bitmap.eraseARGB(255, 255, 255, 255);
1371
robertphillips5605b562016-04-05 11:50:42 -07001372 sk_sp<SkColorFilter> green(SkColorFilter::MakeModeFilter(SK_ColorGREEN,
Mike Reed7d954ad2016-10-28 15:42:34 -04001373 SkBlendMode::kSrcIn));
robertphillips5605b562016-04-05 11:50:42 -07001374 sk_sp<SkImageFilter> greenFilter(SkColorFilterImageFilter::Make(green, nullptr));
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001375 SkImageFilter::CropRect cropRect(SkRect::MakeEmpty());
robertphillips5605b562016-04-05 11:50:42 -07001376 sk_sp<SkImageFilter> croppedOut(SkColorFilterImageFilter::Make(green, nullptr, &cropRect));
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001377
1378 // Check that an xfermode image filter whose input has been cropped out still draws the other
1379 // input. Also check that drawing with both inputs cropped out doesn't cause a GPU warning.
reed374772b2016-10-05 17:33:02 -07001380 SkBlendMode mode = SkBlendMode::kSrcOver;
robertphillips8c0326d2016-04-05 12:48:34 -07001381 sk_sp<SkImageFilter> xfermodeNoFg(SkXfermodeImageFilter::Make(mode, greenFilter,
1382 croppedOut, nullptr));
1383 sk_sp<SkImageFilter> xfermodeNoBg(SkXfermodeImageFilter::Make(mode, croppedOut,
1384 greenFilter, nullptr));
1385 sk_sp<SkImageFilter> xfermodeNoFgNoBg(SkXfermodeImageFilter::Make(mode, croppedOut,
1386 croppedOut, nullptr));
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001387
1388 SkPaint paint;
robertphillips8c0326d2016-04-05 12:48:34 -07001389 paint.setImageFilter(std::move(xfermodeNoFg));
reedda420b92015-12-16 08:38:15 -08001390 canvas->drawBitmap(bitmap, 0, 0, &paint); // drawSprite
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001391
1392 uint32_t pixel;
kkinnunena9d9a392015-03-06 07:16:00 -08001393 SkImageInfo info = SkImageInfo::Make(1, 1, kBGRA_8888_SkColorType, kUnpremul_SkAlphaType);
Mike Reedf1942192017-07-21 14:24:29 -04001394 surf->readPixels(info, &pixel, 4, 0, 0);
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001395 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1396
robertphillips8c0326d2016-04-05 12:48:34 -07001397 paint.setImageFilter(std::move(xfermodeNoBg));
reedda420b92015-12-16 08:38:15 -08001398 canvas->drawBitmap(bitmap, 0, 0, &paint); // drawSprite
Mike Reedf1942192017-07-21 14:24:29 -04001399 surf->readPixels(info, &pixel, 4, 0, 0);
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001400 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1401
robertphillips8c0326d2016-04-05 12:48:34 -07001402 paint.setImageFilter(std::move(xfermodeNoFgNoBg));
reedda420b92015-12-16 08:38:15 -08001403 canvas->drawBitmap(bitmap, 0, 0, &paint); // drawSprite
Mike Reedf1942192017-07-21 14:24:29 -04001404 surf->readPixels(info, &pixel, 4, 0, 0);
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001405 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1406}
1407
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001408DEF_TEST(ImageFilterNestedSaveLayer, reporter) {
1409 SkBitmap temp;
1410 temp.allocN32Pixels(50, 50);
robertphillips9a53fd72015-06-22 09:46:59 -07001411 SkCanvas canvas(temp);
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001412 canvas.clear(0x0);
1413
1414 SkBitmap bitmap;
1415 bitmap.allocN32Pixels(10, 10);
1416 bitmap.eraseColor(SK_ColorGREEN);
1417
1418 SkMatrix matrix;
1419 matrix.setScale(SkIntToScalar(2), SkIntToScalar(2));
1420 matrix.postTranslate(SkIntToScalar(-20), SkIntToScalar(-20));
robertphillipsae8c9332016-04-05 15:09:00 -07001421 sk_sp<SkImageFilter> matrixFilter(
1422 SkImageFilter::MakeMatrixFilter(matrix, kLow_SkFilterQuality, nullptr));
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001423
1424 // Test that saveLayer() with a filter nested inside another saveLayer() applies the
1425 // correct offset to the filter matrix.
1426 SkRect bounds1 = SkRect::MakeXYWH(10, 10, 30, 30);
halcanary96fcdcc2015-08-27 07:41:13 -07001427 canvas.saveLayer(&bounds1, nullptr);
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001428 SkPaint filterPaint;
robertphillipsae8c9332016-04-05 15:09:00 -07001429 filterPaint.setImageFilter(std::move(matrixFilter));
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001430 SkRect bounds2 = SkRect::MakeXYWH(20, 20, 10, 10);
1431 canvas.saveLayer(&bounds2, &filterPaint);
1432 SkPaint greenPaint;
1433 greenPaint.setColor(SK_ColorGREEN);
1434 canvas.drawRect(bounds2, greenPaint);
1435 canvas.restore();
1436 canvas.restore();
1437 SkPaint strokePaint;
1438 strokePaint.setStyle(SkPaint::kStroke_Style);
1439 strokePaint.setColor(SK_ColorRED);
1440
kkinnunena9d9a392015-03-06 07:16:00 -08001441 SkImageInfo info = SkImageInfo::Make(1, 1, kBGRA_8888_SkColorType, kUnpremul_SkAlphaType);
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001442 uint32_t pixel;
Mike Reedf1942192017-07-21 14:24:29 -04001443 temp.readPixels(info, &pixel, 4, 25, 25);
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001444 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1445
1446 // Test that drawSprite() with a filter nested inside a saveLayer() applies the
1447 // correct offset to the filter matrix.
1448 canvas.clear(0x0);
Mike Reedf1942192017-07-21 14:24:29 -04001449 temp.readPixels(info, &pixel, 4, 25, 25);
halcanary96fcdcc2015-08-27 07:41:13 -07001450 canvas.saveLayer(&bounds1, nullptr);
reedda420b92015-12-16 08:38:15 -08001451 canvas.drawBitmap(bitmap, 20, 20, &filterPaint); // drawSprite
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001452 canvas.restore();
1453
Mike Reedf1942192017-07-21 14:24:29 -04001454 temp.readPixels(info, &pixel, 4, 25, 25);
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001455 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1456}
1457
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001458DEF_TEST(XfermodeImageFilterCroppedInput, reporter) {
Mike Reedf1942192017-07-21 14:24:29 -04001459 test_xfermode_cropped_input(SkSurface::MakeRasterN32Premul(100, 100).get(), reporter);
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001460}
senorblanco@chromium.org09843fd2014-03-24 20:50:59 +00001461
robertphillips3e302272016-04-20 11:48:36 -07001462static void test_composed_imagefilter_offset(skiatest::Reporter* reporter, GrContext* context) {
1463 sk_sp<SkSpecialImage> srcImg(create_empty_special_image(context, 100));
ajuma5788faa2015-02-13 09:05:47 -08001464
1465 SkImageFilter::CropRect cropRect(SkRect::MakeXYWH(1, 0, 20, 20));
robertphillips51a315e2016-03-31 09:05:49 -07001466 sk_sp<SkImageFilter> offsetFilter(SkOffsetImageFilter::Make(0, 0, nullptr, &cropRect));
robertphillips6e7025a2016-04-04 04:31:25 -07001467 sk_sp<SkImageFilter> blurFilter(SkBlurImageFilter::Make(SK_Scalar1, SK_Scalar1,
1468 nullptr, &cropRect));
robertphillips491fb172016-03-30 12:32:58 -07001469 sk_sp<SkImageFilter> composedFilter(SkComposeImageFilter::Make(std::move(blurFilter),
1470 std::move(offsetFilter)));
ajuma5788faa2015-02-13 09:05:47 -08001471 SkIPoint offset;
brianosman2a75e5d2016-09-22 07:15:37 -07001472 SkImageFilter::OutputProperties noColorSpace(nullptr);
1473 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeWH(100, 100), nullptr, noColorSpace);
robertphillips4418dba2016-03-07 12:45:14 -08001474
robertphillips2302de92016-03-24 07:26:32 -07001475 sk_sp<SkSpecialImage> resultImg(composedFilter->filterImage(srcImg.get(), ctx, &offset));
robertphillips4418dba2016-03-07 12:45:14 -08001476 REPORTER_ASSERT(reporter, resultImg);
ajuma5788faa2015-02-13 09:05:47 -08001477 REPORTER_ASSERT(reporter, offset.fX == 1 && offset.fY == 0);
1478}
1479
robertphillips4418dba2016-03-07 12:45:14 -08001480DEF_TEST(ComposedImageFilterOffset, reporter) {
robertphillips3e302272016-04-20 11:48:36 -07001481 test_composed_imagefilter_offset(reporter, nullptr);
robertphillips4418dba2016-03-07 12:45:14 -08001482}
1483
bsalomon68d91342016-04-12 09:59:58 -07001484DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ComposedImageFilterOffset_Gpu, reporter, ctxInfo) {
bsalomon8b7451a2016-05-11 06:33:06 -07001485 test_composed_imagefilter_offset(reporter, ctxInfo.grContext());
robertphillips4418dba2016-03-07 12:45:14 -08001486}
robertphillips4418dba2016-03-07 12:45:14 -08001487
robertphillips3e302272016-04-20 11:48:36 -07001488static void test_composed_imagefilter_bounds(skiatest::Reporter* reporter, GrContext* context) {
jbroman17a65202016-03-21 08:38:58 -07001489 // The bounds passed to the inner filter must be filtered by the outer
1490 // filter, so that the inner filter produces the pixels that the outer
1491 // filter requires as input. This matters if the outer filter moves pixels.
1492 // Here, accounting for the outer offset is necessary so that the green
1493 // pixels of the picture are not clipped.
1494
1495 SkPictureRecorder recorder;
1496 SkCanvas* recordingCanvas = recorder.beginRecording(SkRect::MakeWH(200, 100));
1497 recordingCanvas->clipRect(SkRect::MakeXYWH(100, 0, 100, 100));
1498 recordingCanvas->clear(SK_ColorGREEN);
robertphillips491fb172016-03-30 12:32:58 -07001499 sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture());
robertphillips5ff17b12016-03-28 13:13:42 -07001500 sk_sp<SkImageFilter> pictureFilter(SkPictureImageFilter::Make(picture));
jbroman17a65202016-03-21 08:38:58 -07001501 SkImageFilter::CropRect cropRect(SkRect::MakeWH(100, 100));
robertphillips51a315e2016-03-31 09:05:49 -07001502 sk_sp<SkImageFilter> offsetFilter(SkOffsetImageFilter::Make(-100, 0, nullptr, &cropRect));
robertphillips491fb172016-03-30 12:32:58 -07001503 sk_sp<SkImageFilter> composedFilter(SkComposeImageFilter::Make(std::move(offsetFilter),
1504 std::move(pictureFilter)));
jbroman17a65202016-03-21 08:38:58 -07001505
robertphillips3e302272016-04-20 11:48:36 -07001506 sk_sp<SkSpecialImage> sourceImage(create_empty_special_image(context, 100));
brianosman2a75e5d2016-09-22 07:15:37 -07001507 SkImageFilter::OutputProperties noColorSpace(nullptr);
1508 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeWH(100, 100), nullptr, noColorSpace);
jbroman17a65202016-03-21 08:38:58 -07001509 SkIPoint offset;
1510 sk_sp<SkSpecialImage> result(composedFilter->filterImage(sourceImage.get(), ctx, &offset));
1511 REPORTER_ASSERT(reporter, offset.isZero());
1512 REPORTER_ASSERT(reporter, result);
1513 REPORTER_ASSERT(reporter, result->subset().size() == SkISize::Make(100, 100));
1514
1515 SkBitmap resultBM;
robertphillips64612512016-04-08 12:10:42 -07001516 REPORTER_ASSERT(reporter, result->getROPixels(&resultBM));
jbroman17a65202016-03-21 08:38:58 -07001517 REPORTER_ASSERT(reporter, resultBM.getColor(50, 50) == SK_ColorGREEN);
1518}
1519
1520DEF_TEST(ComposedImageFilterBounds, reporter) {
robertphillips3e302272016-04-20 11:48:36 -07001521 test_composed_imagefilter_bounds(reporter, nullptr);
jbroman17a65202016-03-21 08:38:58 -07001522}
1523
egdanielab527a52016-06-28 08:07:26 -07001524DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ComposedImageFilterBounds_Gpu, reporter, ctxInfo) {
bsalomon8b7451a2016-05-11 06:33:06 -07001525 test_composed_imagefilter_bounds(reporter, ctxInfo.grContext());
jbroman17a65202016-03-21 08:38:58 -07001526}
jbroman17a65202016-03-21 08:38:58 -07001527
robertphillips3e302272016-04-20 11:48:36 -07001528static void test_partial_crop_rect(skiatest::Reporter* reporter, GrContext* context) {
1529 sk_sp<SkSpecialImage> srcImg(create_empty_special_image(context, 100));
senorblanco24d2a7b2015-07-13 10:27:05 -07001530
1531 SkImageFilter::CropRect cropRect(SkRect::MakeXYWH(100, 0, 20, 30),
senorblancoed7cf272015-07-16 15:19:11 -07001532 SkImageFilter::CropRect::kHasWidth_CropEdge | SkImageFilter::CropRect::kHasHeight_CropEdge);
robertphillips5605b562016-04-05 11:50:42 -07001533 sk_sp<SkImageFilter> filter(make_grayscale(nullptr, &cropRect));
senorblanco24d2a7b2015-07-13 10:27:05 -07001534 SkIPoint offset;
brianosman2a75e5d2016-09-22 07:15:37 -07001535 SkImageFilter::OutputProperties noColorSpace(nullptr);
1536 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeWH(100, 100), nullptr, noColorSpace);
robertphillips4418dba2016-03-07 12:45:14 -08001537
robertphillips2302de92016-03-24 07:26:32 -07001538 sk_sp<SkSpecialImage> resultImg(filter->filterImage(srcImg.get(), ctx, &offset));
robertphillips4418dba2016-03-07 12:45:14 -08001539 REPORTER_ASSERT(reporter, resultImg);
1540
senorblanco24d2a7b2015-07-13 10:27:05 -07001541 REPORTER_ASSERT(reporter, offset.fX == 0);
1542 REPORTER_ASSERT(reporter, offset.fY == 0);
robertphillips4418dba2016-03-07 12:45:14 -08001543 REPORTER_ASSERT(reporter, resultImg->width() == 20);
1544 REPORTER_ASSERT(reporter, resultImg->height() == 30);
senorblanco24d2a7b2015-07-13 10:27:05 -07001545}
1546
senorblanco21a465d2016-04-11 11:58:39 -07001547DEF_TEST(ImageFilterPartialCropRect, reporter) {
robertphillips3e302272016-04-20 11:48:36 -07001548 test_partial_crop_rect(reporter, nullptr);
robertphillips4418dba2016-03-07 12:45:14 -08001549}
1550
bsalomon68d91342016-04-12 09:59:58 -07001551DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterPartialCropRect_Gpu, reporter, ctxInfo) {
bsalomon8b7451a2016-05-11 06:33:06 -07001552 test_partial_crop_rect(reporter, ctxInfo.grContext());
robertphillips4418dba2016-03-07 12:45:14 -08001553}
robertphillips4418dba2016-03-07 12:45:14 -08001554
senorblanco0abdf762015-08-20 11:10:41 -07001555DEF_TEST(ImageFilterCanComputeFastBounds, reporter) {
1556
robertphillips12fa47d2016-04-08 16:28:09 -07001557 {
1558 SkPoint3 location = SkPoint3::Make(0, 0, SK_Scalar1);
1559 sk_sp<SkImageFilter> lighting(SkLightingImageFilter::MakePointLitDiffuse(location,
1560 SK_ColorGREEN,
1561 0, 0, nullptr));
1562 REPORTER_ASSERT(reporter, !lighting->canComputeFastBounds());
1563 }
senorblanco0abdf762015-08-20 11:10:41 -07001564
senorblanco0abdf762015-08-20 11:10:41 -07001565 {
robertphillips6e7025a2016-04-04 04:31:25 -07001566 sk_sp<SkImageFilter> gray(make_grayscale(nullptr, nullptr));
1567 REPORTER_ASSERT(reporter, gray->canComputeFastBounds());
1568 {
1569 SkColorFilter* grayCF;
1570 REPORTER_ASSERT(reporter, gray->asAColorFilter(&grayCF));
1571 REPORTER_ASSERT(reporter, !grayCF->affectsTransparentBlack());
1572 grayCF->unref();
1573 }
1574 REPORTER_ASSERT(reporter, gray->canComputeFastBounds());
1575
1576 sk_sp<SkImageFilter> grayBlur(SkBlurImageFilter::Make(SK_Scalar1, SK_Scalar1,
1577 std::move(gray)));
1578 REPORTER_ASSERT(reporter, grayBlur->canComputeFastBounds());
senorblanco0abdf762015-08-20 11:10:41 -07001579 }
senorblanco0abdf762015-08-20 11:10:41 -07001580
robertphillips6e7025a2016-04-04 04:31:25 -07001581 {
1582 SkScalar greenMatrix[20] = { 0, 0, 0, 0, 0,
1583 0, 0, 0, 0, 1,
1584 0, 0, 0, 0, 0,
1585 0, 0, 0, 0, 1 };
1586 sk_sp<SkColorFilter> greenCF(SkColorFilter::MakeMatrixFilterRowMajor255(greenMatrix));
robertphillips5605b562016-04-05 11:50:42 -07001587 sk_sp<SkImageFilter> green(SkColorFilterImageFilter::Make(greenCF, nullptr));
senorblanco0abdf762015-08-20 11:10:41 -07001588
robertphillips6e7025a2016-04-04 04:31:25 -07001589 REPORTER_ASSERT(reporter, greenCF->affectsTransparentBlack());
1590 REPORTER_ASSERT(reporter, !green->canComputeFastBounds());
senorblanco0abdf762015-08-20 11:10:41 -07001591
robertphillips6e7025a2016-04-04 04:31:25 -07001592 sk_sp<SkImageFilter> greenBlur(SkBlurImageFilter::Make(SK_Scalar1, SK_Scalar1,
1593 std::move(green)));
1594 REPORTER_ASSERT(reporter, !greenBlur->canComputeFastBounds());
1595 }
senorblanco0abdf762015-08-20 11:10:41 -07001596
1597 uint8_t allOne[256], identity[256];
1598 for (int i = 0; i < 256; ++i) {
1599 identity[i] = i;
1600 allOne[i] = 255;
1601 }
1602
robertphillips5605b562016-04-05 11:50:42 -07001603 sk_sp<SkColorFilter> identityCF(SkTableColorFilter::MakeARGB(identity, identity,
1604 identity, allOne));
1605 sk_sp<SkImageFilter> identityFilter(SkColorFilterImageFilter::Make(identityCF, nullptr));
senorblanco0abdf762015-08-20 11:10:41 -07001606 REPORTER_ASSERT(reporter, !identityCF->affectsTransparentBlack());
1607 REPORTER_ASSERT(reporter, identityFilter->canComputeFastBounds());
1608
robertphillips5605b562016-04-05 11:50:42 -07001609 sk_sp<SkColorFilter> forceOpaqueCF(SkTableColorFilter::MakeARGB(allOne, identity,
1610 identity, identity));
1611 sk_sp<SkImageFilter> forceOpaque(SkColorFilterImageFilter::Make(forceOpaqueCF, nullptr));
senorblanco0abdf762015-08-20 11:10:41 -07001612 REPORTER_ASSERT(reporter, forceOpaqueCF->affectsTransparentBlack());
1613 REPORTER_ASSERT(reporter, !forceOpaque->canComputeFastBounds());
1614}
1615
fmalitacd56f812015-09-14 13:31:18 -07001616// Verify that SkImageSource survives serialization
1617DEF_TEST(ImageFilterImageSourceSerialization, reporter) {
reede8f30622016-03-23 18:59:25 -07001618 auto surface(SkSurface::MakeRasterN32Premul(10, 10));
fmalitacd56f812015-09-14 13:31:18 -07001619 surface->getCanvas()->clear(SK_ColorGREEN);
reed9ce9d672016-03-17 10:51:11 -07001620 sk_sp<SkImage> image(surface->makeImageSnapshot());
robertphillips549c8992016-04-01 09:28:51 -07001621 sk_sp<SkImageFilter> filter(SkImageSource::Make(std::move(image)));
fmalitacd56f812015-09-14 13:31:18 -07001622
Mike Reed0331d372018-01-23 11:57:30 -05001623 sk_sp<SkData> data(filter->serialize());
1624 sk_sp<SkImageFilter> unflattenedFilter = SkImageFilter::Deserialize(data->data(), data->size());
fmalitacd56f812015-09-14 13:31:18 -07001625 REPORTER_ASSERT(reporter, unflattenedFilter);
1626
1627 SkBitmap bm;
1628 bm.allocN32Pixels(10, 10);
fmalita23cb88c2015-09-15 06:56:23 -07001629 bm.eraseColor(SK_ColorBLUE);
fmalitacd56f812015-09-14 13:31:18 -07001630 SkPaint paint;
1631 paint.setColor(SK_ColorRED);
1632 paint.setImageFilter(unflattenedFilter);
1633
1634 SkCanvas canvas(bm);
1635 canvas.drawRect(SkRect::MakeWH(10, 10), paint);
1636 REPORTER_ASSERT(reporter, *bm.getAddr32(0, 0) == SkPreMultiplyColor(SK_ColorGREEN));
1637}
1638
Leon Scroggins III4cdbf602017-09-28 14:33:57 -04001639DEF_TEST(ImageFilterImageSourceUninitialized, r) {
1640 sk_sp<SkData> data(GetResourceAsData("crbug769134.fil"));
1641 if (!data) {
1642 return;
1643 }
Mike Reed0331d372018-01-23 11:57:30 -05001644 sk_sp<SkImageFilter> unflattenedFilter = SkImageFilter::Deserialize(data->data(), data->size());
Leon Scroggins III4cdbf602017-09-28 14:33:57 -04001645 // This will fail. More importantly, msan will verify that we did not
1646 // compare against uninitialized memory.
1647 REPORTER_ASSERT(r, !unflattenedFilter);
1648}
1649
bsalomon45eefcf2016-01-05 08:39:28 -08001650static void test_large_blur_input(skiatest::Reporter* reporter, SkCanvas* canvas) {
1651 SkBitmap largeBmp;
1652 int largeW = 5000;
1653 int largeH = 5000;
bsalomon45eefcf2016-01-05 08:39:28 -08001654 // If we're GPU-backed make the bitmap too large to be converted into a texture.
1655 if (GrContext* ctx = canvas->getGrContext()) {
Brian Salomonc7fe0f72018-05-11 10:14:21 -04001656 largeW = ctx->contextPriv().caps()->maxTextureSize() + 1;
bsalomon45eefcf2016-01-05 08:39:28 -08001657 }
bsalomon45eefcf2016-01-05 08:39:28 -08001658
1659 largeBmp.allocN32Pixels(largeW, largeH);
mtklein2afbe232016-02-07 12:23:10 -08001660 largeBmp.eraseColor(0);
bsalomon45eefcf2016-01-05 08:39:28 -08001661 if (!largeBmp.getPixels()) {
1662 ERRORF(reporter, "Failed to allocate large bmp.");
1663 return;
1664 }
1665
reed9ce9d672016-03-17 10:51:11 -07001666 sk_sp<SkImage> largeImage(SkImage::MakeFromBitmap(largeBmp));
bsalomon45eefcf2016-01-05 08:39:28 -08001667 if (!largeImage) {
1668 ERRORF(reporter, "Failed to create large image.");
1669 return;
1670 }
1671
robertphillips549c8992016-04-01 09:28:51 -07001672 sk_sp<SkImageFilter> largeSource(SkImageSource::Make(std::move(largeImage)));
bsalomon45eefcf2016-01-05 08:39:28 -08001673 if (!largeSource) {
1674 ERRORF(reporter, "Failed to create large SkImageSource.");
1675 return;
1676 }
1677
robertphillips6e7025a2016-04-04 04:31:25 -07001678 sk_sp<SkImageFilter> blur(SkBlurImageFilter::Make(10.f, 10.f, std::move(largeSource)));
bsalomon45eefcf2016-01-05 08:39:28 -08001679 if (!blur) {
1680 ERRORF(reporter, "Failed to create SkBlurImageFilter.");
1681 return;
1682 }
1683
1684 SkPaint paint;
robertphillips549c8992016-04-01 09:28:51 -07001685 paint.setImageFilter(std::move(blur));
bsalomon45eefcf2016-01-05 08:39:28 -08001686
1687 // This should not crash (http://crbug.com/570479).
1688 canvas->drawRect(SkRect::MakeIWH(largeW, largeH), paint);
1689}
1690
senorblanco21a465d2016-04-11 11:58:39 -07001691DEF_TEST(ImageFilterBlurLargeImage, reporter) {
reede8f30622016-03-23 18:59:25 -07001692 auto surface(SkSurface::MakeRaster(SkImageInfo::MakeN32Premul(100, 100)));
bsalomon45eefcf2016-01-05 08:39:28 -08001693 test_large_blur_input(reporter, surface->getCanvas());
1694}
1695
senorblanco5878dbd2016-05-19 14:50:29 -07001696static void test_make_with_filter(skiatest::Reporter* reporter, GrContext* context) {
Robert Phillipsa5fdc972017-02-18 16:58:09 -05001697 sk_sp<SkSurface> surface(create_surface(context, 192, 128));
senorblanco5878dbd2016-05-19 14:50:29 -07001698 surface->getCanvas()->clear(SK_ColorRED);
1699 SkPaint bluePaint;
1700 bluePaint.setColor(SK_ColorBLUE);
1701 SkIRect subset = SkIRect::MakeXYWH(25, 20, 50, 50);
1702 surface->getCanvas()->drawRect(SkRect::Make(subset), bluePaint);
1703 sk_sp<SkImage> sourceImage = surface->makeImageSnapshot();
1704
1705 sk_sp<SkImageFilter> filter = make_grayscale(nullptr, nullptr);
1706 SkIRect clipBounds = SkIRect::MakeXYWH(30, 35, 100, 100);
1707 SkIRect outSubset;
1708 SkIPoint offset;
1709 sk_sp<SkImage> result;
1710
1711 result = sourceImage->makeWithFilter(nullptr, subset, clipBounds, &outSubset, &offset);
1712 REPORTER_ASSERT(reporter, !result);
1713
1714 result = sourceImage->makeWithFilter(filter.get(), subset, clipBounds, nullptr, &offset);
1715 REPORTER_ASSERT(reporter, !result);
1716
1717 result = sourceImage->makeWithFilter(filter.get(), subset, clipBounds, &outSubset, nullptr);
1718 REPORTER_ASSERT(reporter, !result);
1719
1720 SkIRect bigSubset = SkIRect::MakeXYWH(-10000, -10000, 20000, 20000);
1721 result = sourceImage->makeWithFilter(filter.get(), bigSubset, clipBounds, &outSubset, &offset);
1722 REPORTER_ASSERT(reporter, !result);
1723
1724 SkIRect empty = SkIRect::MakeEmpty();
1725 result = sourceImage->makeWithFilter(filter.get(), empty, clipBounds, &outSubset, &offset);
1726 REPORTER_ASSERT(reporter, !result);
1727
1728 result = sourceImage->makeWithFilter(filter.get(), subset, empty, &outSubset, &offset);
1729 REPORTER_ASSERT(reporter, !result);
1730
1731 SkIRect leftField = SkIRect::MakeXYWH(-1000, 0, 100, 100);
1732 result = sourceImage->makeWithFilter(filter.get(), subset, leftField, &outSubset, &offset);
1733 REPORTER_ASSERT(reporter, !result);
1734
1735 result = sourceImage->makeWithFilter(filter.get(), subset, clipBounds, &outSubset, &offset);
1736
1737 REPORTER_ASSERT(reporter, result);
1738 REPORTER_ASSERT(reporter, result->bounds().contains(outSubset));
1739 SkIRect destRect = SkIRect::MakeXYWH(offset.x(), offset.y(),
1740 outSubset.width(), outSubset.height());
1741 REPORTER_ASSERT(reporter, clipBounds.contains(destRect));
Robert Phillipsa5fdc972017-02-18 16:58:09 -05001742
1743 // In GPU-mode, this case creates a special image with a backing size that differs from
1744 // the content size
1745 {
1746 clipBounds.setXYWH(0, 0, 170, 100);
1747 subset.setXYWH(0, 0, 160, 90);
1748
1749 filter = SkXfermodeImageFilter::Make(SkBlendMode::kSrc, nullptr);
1750 result = sourceImage->makeWithFilter(filter.get(), subset, clipBounds, &outSubset, &offset);
1751 REPORTER_ASSERT(reporter, result);
1752 }
senorblanco5878dbd2016-05-19 14:50:29 -07001753}
1754
1755DEF_TEST(ImageFilterMakeWithFilter, reporter) {
1756 test_make_with_filter(reporter, nullptr);
1757}
1758
senorblanco5878dbd2016-05-19 14:50:29 -07001759DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterMakeWithFilter_Gpu, reporter, ctxInfo) {
1760 test_make_with_filter(reporter, ctxInfo.grContext());
1761}
reed4a8126e2014-09-22 07:29:03 -07001762
bsalomon68d91342016-04-12 09:59:58 -07001763DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterHugeBlur_Gpu, reporter, ctxInfo) {
robertphillipsefbffed2015-06-22 12:06:08 -07001764
bsalomon8b7451a2016-05-11 06:33:06 -07001765 sk_sp<SkSurface> surf(SkSurface::MakeRenderTarget(ctxInfo.grContext(),
robertphillips3e302272016-04-20 11:48:36 -07001766 SkBudgeted::kNo,
1767 SkImageInfo::MakeN32Premul(100, 100)));
robertphillips9a53fd72015-06-22 09:46:59 -07001768
robertphillips3e302272016-04-20 11:48:36 -07001769
1770 SkCanvas* canvas = surf->getCanvas();
1771
1772 test_huge_blur(canvas, reporter);
senorblanco@chromium.org09843fd2014-03-24 20:50:59 +00001773}
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001774
egdanielab527a52016-06-28 08:07:26 -07001775DEF_GPUTEST_FOR_RENDERING_CONTEXTS(XfermodeImageFilterCroppedInput_Gpu, reporter, ctxInfo) {
Brian Salomon8996e182017-07-05 17:01:48 -04001776 sk_sp<SkSurface> surf(SkSurface::MakeRenderTarget(
1777 ctxInfo.grContext(),
1778 SkBudgeted::kNo,
1779 SkImageInfo::Make(1, 1, kRGBA_8888_SkColorType, kPremul_SkAlphaType)));
robertphillips3e302272016-04-20 11:48:36 -07001780
Mike Reedf1942192017-07-21 14:24:29 -04001781 test_xfermode_cropped_input(surf.get(), reporter);
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001782}
senorblanco32673b92014-09-09 09:15:04 -07001783
egdanielab527a52016-06-28 08:07:26 -07001784DEF_GPUTEST_FOR_ALL_CONTEXTS(ImageFilterBlurLargeImage_Gpu, reporter, ctxInfo) {
Brian Salomon8996e182017-07-05 17:01:48 -04001785 auto surface(SkSurface::MakeRenderTarget(
1786 ctxInfo.grContext(), SkBudgeted::kYes,
1787 SkImageInfo::Make(100, 100, kRGBA_8888_SkColorType, kPremul_SkAlphaType)));
bsalomon45eefcf2016-01-05 08:39:28 -08001788 test_large_blur_input(reporter, surface->getCanvas());
1789}
reedbb34a8a2016-04-23 15:19:07 -07001790
1791/*
1792 * Test that colorfilterimagefilter does not require its CTM to be decomposed when it has more
1793 * than just scale/translate, but that other filters do.
1794 */
reed96a04f32016-04-25 09:25:15 -07001795DEF_TEST(ImageFilterComplexCTM, reporter) {
reedbb34a8a2016-04-23 15:19:07 -07001796 // just need a colorfilter to exercise the corresponding imagefilter
Mike Reed7d954ad2016-10-28 15:42:34 -04001797 sk_sp<SkColorFilter> cf = SkColorFilter::MakeModeFilter(SK_ColorRED, SkBlendMode::kSrcATop);
reed96a04f32016-04-25 09:25:15 -07001798 sk_sp<SkImageFilter> cfif = SkColorFilterImageFilter::Make(cf, nullptr); // can handle
1799 sk_sp<SkImageFilter> blif = SkBlurImageFilter::Make(3, 3, nullptr); // cannot handle
reedbb34a8a2016-04-23 15:19:07 -07001800
1801 struct {
1802 sk_sp<SkImageFilter> fFilter;
1803 bool fExpectCanHandle;
1804 } recs[] = {
1805 { cfif, true },
1806 { SkColorFilterImageFilter::Make(cf, cfif), true },
Mike Reed0bdaf052017-06-18 23:35:57 -04001807 { SkMergeImageFilter::Make(cfif, cfif), true },
reed96a04f32016-04-25 09:25:15 -07001808 { SkComposeImageFilter::Make(cfif, cfif), true },
1809
reedbb34a8a2016-04-23 15:19:07 -07001810 { blif, false },
reed96a04f32016-04-25 09:25:15 -07001811 { SkBlurImageFilter::Make(3, 3, cfif), false },
reedbb34a8a2016-04-23 15:19:07 -07001812 { SkColorFilterImageFilter::Make(cf, blif), false },
Mike Reed0bdaf052017-06-18 23:35:57 -04001813 { SkMergeImageFilter::Make(cfif, blif), false },
reed96a04f32016-04-25 09:25:15 -07001814 { SkComposeImageFilter::Make(blif, cfif), false },
reedbb34a8a2016-04-23 15:19:07 -07001815 };
liyuqianbfebe222016-11-14 11:17:16 -08001816
reedbb34a8a2016-04-23 15:19:07 -07001817 for (const auto& rec : recs) {
reed96a04f32016-04-25 09:25:15 -07001818 const bool canHandle = rec.fFilter->canHandleComplexCTM();
reedbb34a8a2016-04-23 15:19:07 -07001819 REPORTER_ASSERT(reporter, canHandle == rec.fExpectCanHandle);
1820 }
1821}
Florin Malita08252ec2017-07-06 12:48:15 -04001822
1823// Test that transforming the filter DAG doesn't clone shared nodes multiple times.
1824DEF_TEST(ImageFilterColorSpaceDAG, reporter) {
1825
1826 // Helper for counting makeColorSpace() clones.
1827 class TestFilter final : public SkImageFilter {
1828 public:
1829 TestFilter() : INHERITED(nullptr, 0, nullptr) {}
1830
Florin Malita08252ec2017-07-06 12:48:15 -04001831 Factory getFactory() const override { return nullptr; }
1832
1833 size_t cloneCount() const { return fCloneCount; }
1834
1835 protected:
1836 sk_sp<SkSpecialImage> onFilterImage(SkSpecialImage* src, const Context&,
1837 SkIPoint* offset) const override {
1838 return nullptr;
1839 }
1840 sk_sp<SkImageFilter> onMakeColorSpace(SkColorSpaceXformer*) const override {
1841 fCloneCount++;
1842 return sk_ref_sp(const_cast<TestFilter*>(this));
1843 }
1844
1845 private:
1846 typedef SkImageFilter INHERITED;
1847
1848 mutable size_t fCloneCount = 0;
1849 };
1850
1851 auto filter = sk_make_sp<TestFilter>();
1852 REPORTER_ASSERT(reporter, filter->cloneCount() == 0u);
1853
1854 // Build a DAG referencing the filter twice.
1855 auto complexFilter = SkMergeImageFilter::Make(filter, SkOffsetImageFilter::Make(1, 1, filter));
1856 REPORTER_ASSERT(reporter, filter->cloneCount() == 0u);
1857
1858 auto xformer = SkColorSpaceXformer::Make(SkColorSpace::MakeSRGB());
1859 auto xformedFilter = xformer->apply(complexFilter.get());
1860
Florin Malita39e08552017-07-06 14:16:18 -04001861 REPORTER_ASSERT(reporter, filter->cloneCount() == 1u);
Florin Malita08252ec2017-07-06 12:48:15 -04001862}
Xianzhu Wang0fa353c2017-08-25 16:27:04 -07001863
Xianzhu Wangb4496662017-09-25 10:26:40 -07001864// Test SkXfermodeImageFilter::filterBounds with different blending modes.
Xianzhu Wang0fa353c2017-08-25 16:27:04 -07001865DEF_TEST(XfermodeImageFilterBounds, reporter) {
1866 SkIRect background_rect = SkIRect::MakeXYWH(0, 0, 100, 100);
1867 SkIRect foreground_rect = SkIRect::MakeXYWH(50, 50, 100, 100);
1868 sk_sp<SkImageFilter> background(new FixedBoundsImageFilter(background_rect));
1869 sk_sp<SkImageFilter> foreground(new FixedBoundsImageFilter(foreground_rect));
1870
1871 const int kModeCount = static_cast<int>(SkBlendMode::kLastMode) + 1;
1872 SkIRect expectedBounds[kModeCount];
1873 // Expect union of input rects by default.
1874 for (int i = 0; i < kModeCount; ++i) {
1875 expectedBounds[i] = background_rect;
1876 expectedBounds[i].join(foreground_rect);
1877 }
1878
1879 SkIRect intersection = background_rect;
1880 intersection.intersect(foreground_rect);
1881 expectedBounds[static_cast<int>(SkBlendMode::kClear)] = SkIRect::MakeEmpty();
1882 expectedBounds[static_cast<int>(SkBlendMode::kSrc)] = foreground_rect;
1883 expectedBounds[static_cast<int>(SkBlendMode::kDst)] = background_rect;
1884 expectedBounds[static_cast<int>(SkBlendMode::kSrcIn)] = intersection;
1885 expectedBounds[static_cast<int>(SkBlendMode::kDstIn)] = intersection;
1886 expectedBounds[static_cast<int>(SkBlendMode::kSrcATop)] = background_rect;
1887 expectedBounds[static_cast<int>(SkBlendMode::kDstATop)] = foreground_rect;
1888
1889 // The value of this variable doesn't matter because we use inputs with fixed bounds.
1890 SkIRect src = SkIRect::MakeXYWH(11, 22, 33, 44);
1891 for (int i = 0; i < kModeCount; ++i) {
1892 sk_sp<SkImageFilter> xfermode(SkXfermodeImageFilter::Make(static_cast<SkBlendMode>(i),
1893 background, foreground, nullptr));
Robert Phillips12078432018-05-17 11:17:39 -04001894 auto bounds = xfermode->filterBounds(src, SkMatrix::I(),
1895 SkImageFilter::kForward_MapDirection, nullptr);
Xianzhu Wang0fa353c2017-08-25 16:27:04 -07001896 REPORTER_ASSERT(reporter, bounds == expectedBounds[i]);
1897 }
1898
1899 // Test empty intersection.
1900 sk_sp<SkImageFilter> background2(new FixedBoundsImageFilter(SkIRect::MakeXYWH(0, 0, 20, 20)));
1901 sk_sp<SkImageFilter> foreground2(new FixedBoundsImageFilter(SkIRect::MakeXYWH(40, 40, 50, 50)));
1902 sk_sp<SkImageFilter> xfermode(SkXfermodeImageFilter::Make(
1903 SkBlendMode::kSrcIn, std::move(background2), std::move(foreground2), nullptr));
Robert Phillips12078432018-05-17 11:17:39 -04001904 auto bounds = xfermode->filterBounds(src, SkMatrix::I(),
1905 SkImageFilter::kForward_MapDirection, nullptr);
Xianzhu Wang0fa353c2017-08-25 16:27:04 -07001906 REPORTER_ASSERT(reporter, bounds.isEmpty());
1907}
1908
Fredrik Söderquistb87f7982017-10-26 13:54:16 +02001909DEF_TEST(OffsetImageFilterBounds, reporter) {
1910 SkIRect src = SkIRect::MakeXYWH(0, 0, 100, 100);
1911 sk_sp<SkImageFilter> offset(SkOffsetImageFilter::Make(-50.5f, -50.5f, nullptr));
1912
1913 SkIRect expectedForward = SkIRect::MakeXYWH(-50, -50, 100, 100);
1914 SkIRect boundsForward = offset->filterBounds(src, SkMatrix::I(),
Robert Phillips12078432018-05-17 11:17:39 -04001915 SkImageFilter::kForward_MapDirection, nullptr);
Fredrik Söderquistb87f7982017-10-26 13:54:16 +02001916 REPORTER_ASSERT(reporter, boundsForward == expectedForward);
1917
1918 SkIRect expectedReverse = SkIRect::MakeXYWH(50, 50, 100, 100);
1919 SkIRect boundsReverse = offset->filterBounds(src, SkMatrix::I(),
Robert Phillips12078432018-05-17 11:17:39 -04001920 SkImageFilter::kReverse_MapDirection, &src);
Fredrik Söderquistb87f7982017-10-26 13:54:16 +02001921 REPORTER_ASSERT(reporter, boundsReverse == expectedReverse);
1922}
1923
Xianzhu Wang0fa353c2017-08-25 16:27:04 -07001924static void test_arithmetic_bounds(skiatest::Reporter* reporter, float k1, float k2, float k3,
1925 float k4, sk_sp<SkImageFilter> background,
1926 sk_sp<SkImageFilter> foreground,
1927 const SkImageFilter::CropRect* crop, const SkIRect& expected) {
1928 sk_sp<SkImageFilter> arithmetic(
1929 SkArithmeticImageFilter::Make(k1, k2, k3, k4, false, background, foreground, crop));
1930 // The value of the input rect doesn't matter because we use inputs with fixed bounds.
1931 SkIRect bounds = arithmetic->filterBounds(SkIRect::MakeXYWH(11, 22, 33, 44), SkMatrix::I(),
Robert Phillips12078432018-05-17 11:17:39 -04001932 SkImageFilter::kForward_MapDirection, nullptr);
Xianzhu Wang0fa353c2017-08-25 16:27:04 -07001933 REPORTER_ASSERT(reporter, expected == bounds);
1934}
1935
1936static void test_arithmetic_combinations(skiatest::Reporter* reporter, float v) {
1937 SkIRect background_rect = SkIRect::MakeXYWH(0, 0, 100, 100);
1938 SkIRect foreground_rect = SkIRect::MakeXYWH(50, 50, 100, 100);
1939 sk_sp<SkImageFilter> background(new FixedBoundsImageFilter(background_rect));
1940 sk_sp<SkImageFilter> foreground(new FixedBoundsImageFilter(foreground_rect));
1941
1942 SkIRect union_rect = background_rect;
1943 union_rect.join(foreground_rect);
1944 SkIRect intersection = background_rect;
1945 intersection.intersect(foreground_rect);
1946
1947 test_arithmetic_bounds(reporter, 0, 0, 0, 0, background, foreground, nullptr,
1948 SkIRect::MakeEmpty());
1949 test_arithmetic_bounds(reporter, 0, 0, 0, v, background, foreground, nullptr, union_rect);
1950 test_arithmetic_bounds(reporter, 0, 0, v, 0, background, foreground, nullptr, background_rect);
1951 test_arithmetic_bounds(reporter, 0, 0, v, v, background, foreground, nullptr, union_rect);
1952 test_arithmetic_bounds(reporter, 0, v, 0, 0, background, foreground, nullptr, foreground_rect);
1953 test_arithmetic_bounds(reporter, 0, v, 0, v, background, foreground, nullptr, union_rect);
1954 test_arithmetic_bounds(reporter, 0, v, v, 0, background, foreground, nullptr, union_rect);
1955 test_arithmetic_bounds(reporter, 0, v, v, v, background, foreground, nullptr, union_rect);
1956 test_arithmetic_bounds(reporter, v, 0, 0, 0, background, foreground, nullptr, intersection);
1957 test_arithmetic_bounds(reporter, v, 0, 0, v, background, foreground, nullptr, union_rect);
1958 test_arithmetic_bounds(reporter, v, 0, v, 0, background, foreground, nullptr, background_rect);
1959 test_arithmetic_bounds(reporter, v, 0, v, v, background, foreground, nullptr, union_rect);
1960 test_arithmetic_bounds(reporter, v, v, 0, 0, background, foreground, nullptr, foreground_rect);
1961 test_arithmetic_bounds(reporter, v, v, 0, v, background, foreground, nullptr, union_rect);
1962 test_arithmetic_bounds(reporter, v, v, v, 0, background, foreground, nullptr, union_rect);
1963 test_arithmetic_bounds(reporter, v, v, v, v, background, foreground, nullptr, union_rect);
1964
1965 // Test with crop. When k4 is non-zero, the result is expected to be crop_rect
1966 // regardless of inputs because the filter affects the whole crop area.
1967 SkIRect crop_rect = SkIRect::MakeXYWH(-111, -222, 333, 444);
1968 SkImageFilter::CropRect crop(SkRect::Make(crop_rect));
1969 test_arithmetic_bounds(reporter, 0, 0, 0, 0, background, foreground, &crop,
1970 SkIRect::MakeEmpty());
1971 test_arithmetic_bounds(reporter, 0, 0, 0, v, background, foreground, &crop, crop_rect);
1972 test_arithmetic_bounds(reporter, 0, 0, v, 0, background, foreground, &crop, background_rect);
1973 test_arithmetic_bounds(reporter, 0, 0, v, v, background, foreground, &crop, crop_rect);
1974 test_arithmetic_bounds(reporter, 0, v, 0, 0, background, foreground, &crop, foreground_rect);
1975 test_arithmetic_bounds(reporter, 0, v, 0, v, background, foreground, &crop, crop_rect);
1976 test_arithmetic_bounds(reporter, 0, v, v, 0, background, foreground, &crop, union_rect);
1977 test_arithmetic_bounds(reporter, 0, v, v, v, background, foreground, &crop, crop_rect);
1978 test_arithmetic_bounds(reporter, v, 0, 0, 0, background, foreground, &crop, intersection);
1979 test_arithmetic_bounds(reporter, v, 0, 0, v, background, foreground, &crop, crop_rect);
1980 test_arithmetic_bounds(reporter, v, 0, v, 0, background, foreground, &crop, background_rect);
1981 test_arithmetic_bounds(reporter, v, 0, v, v, background, foreground, &crop, crop_rect);
1982 test_arithmetic_bounds(reporter, v, v, 0, 0, background, foreground, &crop, foreground_rect);
1983 test_arithmetic_bounds(reporter, v, v, 0, v, background, foreground, &crop, crop_rect);
1984 test_arithmetic_bounds(reporter, v, v, v, 0, background, foreground, &crop, union_rect);
1985 test_arithmetic_bounds(reporter, v, v, v, v, background, foreground, &crop, crop_rect);
1986}
1987
Xianzhu Wangb4496662017-09-25 10:26:40 -07001988// Test SkArithmeticImageFilter::filterBounds with different blending modes.
Xianzhu Wang0fa353c2017-08-25 16:27:04 -07001989DEF_TEST(ArithmeticImageFilterBounds, reporter) {
1990 test_arithmetic_combinations(reporter, 1);
1991 test_arithmetic_combinations(reporter, 0.5);
1992}
Xianzhu Wangb4496662017-09-25 10:26:40 -07001993
1994// Test SkImageSource::filterBounds.
1995DEF_TEST(ImageSourceBounds, reporter) {
1996 sk_sp<SkImage> image(SkImage::MakeFromBitmap(make_gradient_circle(64, 64)));
1997 // Default src and dst rects.
1998 sk_sp<SkImageFilter> source1(SkImageSource::Make(image));
1999 SkIRect imageBounds = SkIRect::MakeWH(64, 64);
2000 SkIRect input(SkIRect::MakeXYWH(10, 20, 30, 40));
2001 REPORTER_ASSERT(reporter,
2002 imageBounds == source1->filterBounds(input, SkMatrix::I(),
Robert Phillips12078432018-05-17 11:17:39 -04002003 SkImageFilter::kForward_MapDirection,
2004 nullptr));
Xianzhu Wangb4496662017-09-25 10:26:40 -07002005 REPORTER_ASSERT(reporter,
2006 input == source1->filterBounds(input, SkMatrix::I(),
Robert Phillips12078432018-05-17 11:17:39 -04002007 SkImageFilter::kReverse_MapDirection, &input));
Xianzhu Wangb4496662017-09-25 10:26:40 -07002008 SkMatrix scale(SkMatrix::MakeScale(2));
2009 SkIRect scaledBounds = SkIRect::MakeWH(128, 128);
2010 REPORTER_ASSERT(reporter,
2011 scaledBounds == source1->filterBounds(input, scale,
Robert Phillips12078432018-05-17 11:17:39 -04002012 SkImageFilter::kForward_MapDirection,
2013 nullptr));
2014 REPORTER_ASSERT(reporter, input == source1->filterBounds(input, scale,
2015 SkImageFilter::kReverse_MapDirection,
2016 &input));
Xianzhu Wangb4496662017-09-25 10:26:40 -07002017
2018 // Specified src and dst rects.
2019 SkRect src(SkRect::MakeXYWH(0.5, 0.5, 100.5, 100.5));
2020 SkRect dst(SkRect::MakeXYWH(-10.5, -10.5, 120.5, 120.5));
2021 sk_sp<SkImageFilter> source2(SkImageSource::Make(image, src, dst, kMedium_SkFilterQuality));
2022 REPORTER_ASSERT(reporter,
2023 dst.roundOut() == source2->filterBounds(input, SkMatrix::I(),
Robert Phillips12078432018-05-17 11:17:39 -04002024 SkImageFilter::kForward_MapDirection,
2025 nullptr));
Xianzhu Wangb4496662017-09-25 10:26:40 -07002026 REPORTER_ASSERT(reporter,
2027 input == source2->filterBounds(input, SkMatrix::I(),
Robert Phillips12078432018-05-17 11:17:39 -04002028 SkImageFilter::kReverse_MapDirection, &input));
Xianzhu Wangb4496662017-09-25 10:26:40 -07002029 scale.mapRect(&dst);
2030 scale.mapRect(&src);
2031 REPORTER_ASSERT(reporter,
2032 dst.roundOut() == source2->filterBounds(input, scale,
Robert Phillips12078432018-05-17 11:17:39 -04002033 SkImageFilter::kForward_MapDirection,
2034 nullptr));
2035 REPORTER_ASSERT(reporter, input == source2->filterBounds(input, scale,
2036 SkImageFilter::kReverse_MapDirection,
2037 &input));
Xianzhu Wangb4496662017-09-25 10:26:40 -07002038}
Robert Phillips12078432018-05-17 11:17:39 -04002039