blob: 0433d0167c2fbe23f7070b251567f847fc871add [file] [log] [blame]
senorblanco@chromium.org194d7752013-07-24 22:19:24 +00001/*
2 * Copyright 2013 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
Xianzhu Wang0fa353c2017-08-25 16:27:04 -07008#include "SkArithmeticImageFilter.h"
commit-bot@chromium.org4b681bc2013-09-13 12:40:02 +00009#include "SkBitmap.h"
senorblanco@chromium.org6776b822014-01-03 21:48:22 +000010#include "SkBlurImageFilter.h"
tfarina@chromium.org8f6884a2014-01-24 20:56:26 +000011#include "SkCanvas.h"
12#include "SkColorFilterImageFilter.h"
13#include "SkColorMatrixFilter.h"
Florin Malita08252ec2017-07-06 12:48:15 -040014#include "SkColorSpaceXformer.h"
ajuma5788faa2015-02-13 09:05:47 -080015#include "SkComposeImageFilter.h"
senorblanco@chromium.org6776b822014-01-03 21:48:22 +000016#include "SkDisplacementMapEffect.h"
17#include "SkDropShadowImageFilter.h"
senorblanco@chromium.org97f5fc62014-05-30 20:50:56 +000018#include "SkFlattenableSerialization.h"
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +000019#include "SkGradientShader.h"
fmalita5598b632015-09-15 11:26:13 -070020#include "SkImage.h"
Cary Clark60aaeb22017-11-03 08:06:09 -040021#include "SkImageFilterPriv.h"
fmalitacd56f812015-09-14 13:31:18 -070022#include "SkImageSource.h"
commit-bot@chromium.org4b681bc2013-09-13 12:40:02 +000023#include "SkLightingImageFilter.h"
tfarina@chromium.org8f6884a2014-01-24 20:56:26 +000024#include "SkMatrixConvolutionImageFilter.h"
senorblanco@chromium.org6776b822014-01-03 21:48:22 +000025#include "SkMergeImageFilter.h"
26#include "SkMorphologyImageFilter.h"
senorblanco@chromium.org6776b822014-01-03 21:48:22 +000027#include "SkOffsetImageFilter.h"
ajuma77b6ba32016-01-08 14:58:35 -080028#include "SkPaintImageFilter.h"
senorblanco8f3937d2014-10-29 12:36:32 -070029#include "SkPerlinNoiseShader.h"
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +000030#include "SkPicture.h"
senorblanco@chromium.org910702b2014-05-30 20:36:15 +000031#include "SkPictureImageFilter.h"
robertphillips@google.com770963f2014-04-18 18:04:41 +000032#include "SkPictureRecorder.h"
robertphillips3d32d762015-07-13 13:16:44 -070033#include "SkPoint3.h"
halcanary97d2c0a2014-08-19 06:27:53 -070034#include "SkReadBuffer.h"
tfarina@chromium.org8f6884a2014-01-24 20:56:26 +000035#include "SkRect.h"
robertphillips4418dba2016-03-07 12:45:14 -080036#include "SkSpecialImage.h"
37#include "SkSpecialSurface.h"
fmalitacd56f812015-09-14 13:31:18 -070038#include "SkSurface.h"
senorblanco0abdf762015-08-20 11:10:41 -070039#include "SkTableColorFilter.h"
senorblanco@chromium.org6776b822014-01-03 21:48:22 +000040#include "SkTileImageFilter.h"
41#include "SkXfermodeImageFilter.h"
Leon Scroggins III4cdbf602017-09-28 14:33:57 -040042#include "Resources.h"
tfarina@chromium.org8f6884a2014-01-24 20:56:26 +000043#include "Test.h"
Mike Reed5a625e02017-08-08 15:48:54 -040044#include "sk_tool_utils.h"
senorblanco@chromium.org194d7752013-07-24 22:19:24 +000045
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +000046#if SK_SUPPORT_GPU
kkinnunen15302832015-12-01 04:35:26 -080047#include "GrContext.h"
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +000048#endif
49
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +000050static const int kBitmapSize = 4;
commit-bot@chromium.org4b681bc2013-09-13 12:40:02 +000051
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +000052namespace {
53
54class MatrixTestImageFilter : public SkImageFilter {
55public:
robertphillips43c2ad42016-04-04 05:05:11 -070056 static sk_sp<SkImageFilter> Make(skiatest::Reporter* reporter,
57 const SkMatrix& expectedMatrix) {
58 return sk_sp<SkImageFilter>(new MatrixTestImageFilter(reporter, expectedMatrix));
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +000059 }
60
robertphillipsf3f5bad2014-12-19 13:49:15 -080061 SK_TO_STRING_OVERRIDE()
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +000062 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(MatrixTestImageFilter)
63
64protected:
robertphillips4ba94e22016-04-04 12:07:47 -070065 sk_sp<SkSpecialImage> onFilterImage(SkSpecialImage* source, const Context& ctx,
66 SkIPoint* offset) const override {
robertphillips43c2ad42016-04-04 05:05:11 -070067 REPORTER_ASSERT(fReporter, ctx.ctm() == fExpectedMatrix);
robertphillips4ba94e22016-04-04 12:07:47 -070068 offset->fX = offset->fY = 0;
69 return sk_ref_sp<SkSpecialImage>(source);
robertphillips43c2ad42016-04-04 05:05:11 -070070 }
Matt Sarett62745a82017-04-17 11:57:29 -040071 sk_sp<SkImageFilter> onMakeColorSpace(SkColorSpaceXformer*) const override {
72 return sk_ref_sp(const_cast<MatrixTestImageFilter*>(this));
73 }
robertphillips43c2ad42016-04-04 05:05:11 -070074
mtklein36352bf2015-03-25 18:17:31 -070075 void flatten(SkWriteBuffer& buffer) const override {
brianosman18f13f32016-05-02 07:51:08 -070076 SkDEBUGFAIL("Should never get here");
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +000077 }
78
79private:
robertphillips43c2ad42016-04-04 05:05:11 -070080 MatrixTestImageFilter(skiatest::Reporter* reporter, const SkMatrix& expectedMatrix)
81 : INHERITED(nullptr, 0, nullptr)
82 , fReporter(reporter)
83 , fExpectedMatrix(expectedMatrix) {
84 }
85
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +000086 skiatest::Reporter* fReporter;
87 SkMatrix fExpectedMatrix;
mtklein3f3b3d02014-12-01 11:47:08 -080088
reed9fa60da2014-08-21 07:59:51 -070089 typedef SkImageFilter INHERITED;
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +000090};
91
senorblanco6a93fa12016-04-05 04:43:45 -070092class FailImageFilter : public SkImageFilter {
93public:
robertphillips6b134732016-04-15 09:58:37 -070094 FailImageFilter() : SkImageFilter(nullptr, 0, nullptr) { }
senorblanco6a93fa12016-04-05 04:43:45 -070095
96 sk_sp<SkSpecialImage> onFilterImage(SkSpecialImage* source,
97 const Context& ctx,
98 SkIPoint* offset) const override {
99 return nullptr;
100 }
Matt Sarett62745a82017-04-17 11:57:29 -0400101 sk_sp<SkImageFilter> onMakeColorSpace(SkColorSpaceXformer*) const override {
102 return nullptr;
103 }
senorblanco6a93fa12016-04-05 04:43:45 -0700104
105 SK_TO_STRING_OVERRIDE()
106 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(FailImageFilter)
107
108private:
109 typedef SkImageFilter INHERITED;
110};
111
112sk_sp<SkFlattenable> FailImageFilter::CreateProc(SkReadBuffer& buffer) {
113 SK_IMAGEFILTER_UNFLATTEN_COMMON(common, 0);
114 return sk_sp<SkFlattenable>(new FailImageFilter());
115}
116
117#ifndef SK_IGNORE_TO_STRING
118void FailImageFilter::toString(SkString* str) const {
119 str->appendf("FailImageFilter: (");
120 str->append(")");
121}
122#endif
123
senorblanco297f7ce2016-03-23 13:44:26 -0700124void draw_gradient_circle(SkCanvas* canvas, int width, int height) {
125 SkScalar x = SkIntToScalar(width / 2);
126 SkScalar y = SkIntToScalar(height / 2);
127 SkScalar radius = SkMinScalar(x, y) * 0.8f;
128 canvas->clear(0x00000000);
129 SkColor colors[2];
130 colors[0] = SK_ColorWHITE;
131 colors[1] = SK_ColorBLACK;
132 sk_sp<SkShader> shader(
133 SkGradientShader::MakeRadial(SkPoint::Make(x, y), radius, colors, nullptr, 2,
134 SkShader::kClamp_TileMode)
135 );
136 SkPaint paint;
137 paint.setShader(shader);
138 canvas->drawCircle(x, y, radius, paint);
139}
140
141SkBitmap make_gradient_circle(int width, int height) {
142 SkBitmap bitmap;
143 bitmap.allocN32Pixels(width, height);
144 SkCanvas canvas(bitmap);
145 draw_gradient_circle(&canvas, width, height);
146 return bitmap;
147}
148
149class FilterList {
150public:
robertphillipsfc11b0a2016-04-05 09:09:36 -0700151 FilterList(sk_sp<SkImageFilter> input, const SkImageFilter::CropRect* cropRect = nullptr) {
senorblanco297f7ce2016-03-23 13:44:26 -0700152 SkPoint3 location = SkPoint3::Make(0, 0, SK_Scalar1);
senorblanco297f7ce2016-03-23 13:44:26 -0700153 const SkScalar five = SkIntToScalar(5);
154
robertphillips6e7025a2016-04-04 04:31:25 -0700155 {
156 sk_sp<SkColorFilter> cf(SkColorFilter::MakeModeFilter(SK_ColorRED,
Mike Reed7d954ad2016-10-28 15:42:34 -0400157 SkBlendMode::kSrcIn));
senorblanco297f7ce2016-03-23 13:44:26 -0700158
robertphillips6e7025a2016-04-04 04:31:25 -0700159 this->addFilter("color filter",
robertphillips12fa47d2016-04-08 16:28:09 -0700160 SkColorFilterImageFilter::Make(std::move(cf), input, cropRect));
robertphillips6e7025a2016-04-04 04:31:25 -0700161 }
senorblanco297f7ce2016-03-23 13:44:26 -0700162
robertphillips6e7025a2016-04-04 04:31:25 -0700163 {
164 sk_sp<SkImage> gradientImage(SkImage::MakeFromBitmap(make_gradient_circle(64, 64)));
165 sk_sp<SkImageFilter> gradientSource(SkImageSource::Make(std::move(gradientImage)));
senorblanco297f7ce2016-03-23 13:44:26 -0700166
liyuqianbfebe222016-11-14 11:17:16 -0800167 this->addFilter("displacement map",
robertphillipsbfe11fc2016-04-15 07:17:36 -0700168 SkDisplacementMapEffect::Make(SkDisplacementMapEffect::kR_ChannelSelectorType,
169 SkDisplacementMapEffect::kB_ChannelSelectorType,
170 20.0f,
171 std::move(gradientSource), input, cropRect));
robertphillips6e7025a2016-04-04 04:31:25 -0700172 }
senorblanco297f7ce2016-03-23 13:44:26 -0700173
robertphillips6e7025a2016-04-04 04:31:25 -0700174 this->addFilter("blur", SkBlurImageFilter::Make(SK_Scalar1,
175 SK_Scalar1,
robertphillipsfc11b0a2016-04-05 09:09:36 -0700176 input,
robertphillips12fa47d2016-04-08 16:28:09 -0700177 cropRect));
robertphillipsc4169122016-04-06 08:40:59 -0700178 this->addFilter("drop shadow", SkDropShadowImageFilter::Make(
senorblanco297f7ce2016-03-23 13:44:26 -0700179 SK_Scalar1, SK_Scalar1, SK_Scalar1, SK_Scalar1, SK_ColorGREEN,
robertphillipsfc11b0a2016-04-05 09:09:36 -0700180 SkDropShadowImageFilter::kDrawShadowAndForeground_ShadowMode,
robertphillips12fa47d2016-04-08 16:28:09 -0700181 input, cropRect));
182 this->addFilter("diffuse lighting",
183 SkLightingImageFilter::MakePointLitDiffuse(location, SK_ColorGREEN, 0, 0,
184 input, cropRect));
senorblanco297f7ce2016-03-23 13:44:26 -0700185 this->addFilter("specular lighting",
robertphillips12fa47d2016-04-08 16:28:09 -0700186 SkLightingImageFilter::MakePointLitSpecular(location, SK_ColorGREEN, 0, 0, 0,
187 input, cropRect));
188 {
189 SkScalar kernel[9] = {
190 SkIntToScalar(1), SkIntToScalar(1), SkIntToScalar(1),
191 SkIntToScalar(1), SkIntToScalar(-7), SkIntToScalar(1),
192 SkIntToScalar(1), SkIntToScalar(1), SkIntToScalar(1),
193 };
194 const SkISize kernelSize = SkISize::Make(3, 3);
195 const SkScalar gain = SK_Scalar1, bias = 0;
196
197 this->addFilter("matrix convolution",
robertphillipsef6a47b2016-04-08 08:01:20 -0700198 SkMatrixConvolutionImageFilter::Make(
senorblanco297f7ce2016-03-23 13:44:26 -0700199 kernelSize, kernel, gain, bias, SkIPoint::Make(1, 1),
robertphillipsfc11b0a2016-04-05 09:09:36 -0700200 SkMatrixConvolutionImageFilter::kRepeat_TileMode, false,
robertphillips12fa47d2016-04-08 16:28:09 -0700201 input, cropRect));
202 }
203
Mike Reed0bdaf052017-06-18 23:35:57 -0400204 this->addFilter("merge", SkMergeImageFilter::Make(input, input, cropRect));
robertphillips12fa47d2016-04-08 16:28:09 -0700205
robertphillips6e7025a2016-04-04 04:31:25 -0700206 {
207 SkPaint greenColorShaderPaint;
208 greenColorShaderPaint.setShader(SkShader::MakeColorShader(SK_ColorGREEN));
209
210 SkImageFilter::CropRect leftSideCropRect(SkRect::MakeXYWH(0, 0, 32, 64));
211 sk_sp<SkImageFilter> paintFilterLeft(SkPaintImageFilter::Make(greenColorShaderPaint,
212 &leftSideCropRect));
213 SkImageFilter::CropRect rightSideCropRect(SkRect::MakeXYWH(32, 0, 32, 64));
214 sk_sp<SkImageFilter> paintFilterRight(SkPaintImageFilter::Make(greenColorShaderPaint,
215 &rightSideCropRect));
216
217
218 this->addFilter("merge with disjoint inputs", SkMergeImageFilter::Make(
Mike Reed0bdaf052017-06-18 23:35:57 -0400219 std::move(paintFilterLeft), std::move(paintFilterRight), cropRect));
robertphillips6e7025a2016-04-04 04:31:25 -0700220 }
221
senorblanco297f7ce2016-03-23 13:44:26 -0700222 this->addFilter("offset",
robertphillipsfc11b0a2016-04-05 09:09:36 -0700223 SkOffsetImageFilter::Make(SK_Scalar1, SK_Scalar1, input,
robertphillips12fa47d2016-04-08 16:28:09 -0700224 cropRect));
225 this->addFilter("dilate", SkDilateImageFilter::Make(3, 2, input, cropRect));
226 this->addFilter("erode", SkErodeImageFilter::Make(2, 3, input, cropRect));
robertphillips534c2702016-04-15 07:57:40 -0700227 this->addFilter("tile", SkTileImageFilter::Make(
228 SkRect::MakeXYWH(0, 0, 50, 50),
229 cropRect ? cropRect->rect() : SkRect::MakeXYWH(0, 0, 100, 100),
230 input));
robertphillips6e7025a2016-04-04 04:31:25 -0700231
robertphillips12fa47d2016-04-08 16:28:09 -0700232 if (!cropRect) {
233 SkMatrix matrix;
234
235 matrix.setTranslate(SK_Scalar1, SK_Scalar1);
236 matrix.postRotate(SkIntToScalar(45), SK_Scalar1, SK_Scalar1);
237
238 this->addFilter("matrix",
239 SkImageFilter::MakeMatrixFilter(matrix, kLow_SkFilterQuality, input));
240 }
robertphillips6e7025a2016-04-04 04:31:25 -0700241 {
robertphillipsfc11b0a2016-04-05 09:09:36 -0700242 sk_sp<SkImageFilter> blur(SkBlurImageFilter::Make(five, five, input));
robertphillips6e7025a2016-04-04 04:31:25 -0700243
244 this->addFilter("blur and offset", SkOffsetImageFilter::Make(five, five,
245 std::move(blur),
robertphillips12fa47d2016-04-08 16:28:09 -0700246 cropRect));
robertphillips6e7025a2016-04-04 04:31:25 -0700247 }
248 {
robertphillips6e7025a2016-04-04 04:31:25 -0700249 SkPictureRecorder recorder;
Mike Klein26eb16f2017-04-10 09:50:25 -0400250 SkCanvas* recordingCanvas = recorder.beginRecording(64, 64);
robertphillips6e7025a2016-04-04 04:31:25 -0700251
252 SkPaint greenPaint;
253 greenPaint.setColor(SK_ColorGREEN);
254 recordingCanvas->drawRect(SkRect::Make(SkIRect::MakeXYWH(10, 10, 30, 20)), greenPaint);
255 sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture());
256 sk_sp<SkImageFilter> pictureFilter(SkPictureImageFilter::Make(std::move(picture)));
257
258 this->addFilter("picture and blur", SkBlurImageFilter::Make(five, five,
259 std::move(pictureFilter),
robertphillips12fa47d2016-04-08 16:28:09 -0700260 cropRect));
robertphillips6e7025a2016-04-04 04:31:25 -0700261 }
262 {
263 SkPaint paint;
264 paint.setShader(SkPerlinNoiseShader::MakeTurbulence(SK_Scalar1, SK_Scalar1, 1, 0));
265 sk_sp<SkImageFilter> paintFilter(SkPaintImageFilter::Make(paint));
266
267 this->addFilter("paint and blur", SkBlurImageFilter::Make(five, five,
268 std::move(paintFilter),
robertphillips12fa47d2016-04-08 16:28:09 -0700269 cropRect));
robertphillips6e7025a2016-04-04 04:31:25 -0700270 }
reed374772b2016-10-05 17:33:02 -0700271 this->addFilter("xfermode", SkXfermodeImageFilter::Make(SkBlendMode::kSrc, input, input,
272 cropRect));
senorblanco297f7ce2016-03-23 13:44:26 -0700273 }
274 int count() const { return fFilters.count(); }
275 SkImageFilter* getFilter(int index) const { return fFilters[index].fFilter.get(); }
276 const char* getName(int index) const { return fFilters[index].fName; }
277private:
278 struct Filter {
robertphillips12fa47d2016-04-08 16:28:09 -0700279 Filter() : fName(nullptr) {}
280 Filter(const char* name, sk_sp<SkImageFilter> filter)
281 : fName(name)
282 , fFilter(std::move(filter)) {
283 }
senorblanco297f7ce2016-03-23 13:44:26 -0700284 const char* fName;
285 sk_sp<SkImageFilter> fFilter;
286 };
robertphillips12fa47d2016-04-08 16:28:09 -0700287 void addFilter(const char* name, sk_sp<SkImageFilter> filter) {
288 fFilters.push_back(Filter(name, std::move(filter)));
senorblanco297f7ce2016-03-23 13:44:26 -0700289 }
290
291 SkTArray<Filter> fFilters;
292};
293
Xianzhu Wang0fa353c2017-08-25 16:27:04 -0700294class FixedBoundsImageFilter : public SkImageFilter {
295public:
296 FixedBoundsImageFilter(const SkIRect& bounds)
297 : SkImageFilter(nullptr, 0, nullptr), fBounds(bounds) {}
298
299private:
300#ifndef SK_IGNORE_TO_STRING
301 void toString(SkString*) const override {}
302#endif
303 Factory getFactory() const override { return nullptr; }
304
305 sk_sp<SkSpecialImage> onFilterImage(SkSpecialImage* src, const Context&,
306 SkIPoint* offset) const override {
307 return nullptr;
308 }
309 sk_sp<SkImageFilter> onMakeColorSpace(SkColorSpaceXformer*) const override { return nullptr; }
310
311 SkIRect onFilterBounds(const SkIRect&, const SkMatrix&, MapDirection) const override {
312 return fBounds;
313 }
314
315 SkIRect fBounds;
316};
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +0000317}
318
reed60c9b582016-04-03 09:11:13 -0700319sk_sp<SkFlattenable> MatrixTestImageFilter::CreateProc(SkReadBuffer& buffer) {
brianosman18f13f32016-05-02 07:51:08 -0700320 SkDEBUGFAIL("Should never get here");
321 return nullptr;
reed9fa60da2014-08-21 07:59:51 -0700322}
323
robertphillipsf3f5bad2014-12-19 13:49:15 -0800324#ifndef SK_IGNORE_TO_STRING
325void MatrixTestImageFilter::toString(SkString* str) const {
326 str->appendf("MatrixTestImageFilter: (");
327 str->append(")");
328}
329#endif
330
reed9ce9d672016-03-17 10:51:11 -0700331static sk_sp<SkImage> make_small_image() {
reede8f30622016-03-23 18:59:25 -0700332 auto surface(SkSurface::MakeRasterN32Premul(kBitmapSize, kBitmapSize));
fmalita5598b632015-09-15 11:26:13 -0700333 SkCanvas* canvas = surface->getCanvas();
334 canvas->clear(0x00000000);
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000335 SkPaint darkPaint;
336 darkPaint.setColor(0xFF804020);
337 SkPaint lightPaint;
338 lightPaint.setColor(0xFF244484);
339 const int i = kBitmapSize / 4;
340 for (int y = 0; y < kBitmapSize; y += i) {
341 for (int x = 0; x < kBitmapSize; x += i) {
fmalita5598b632015-09-15 11:26:13 -0700342 canvas->save();
343 canvas->translate(SkIntToScalar(x), SkIntToScalar(y));
344 canvas->drawRect(SkRect::MakeXYWH(0, 0,
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000345 SkIntToScalar(i),
346 SkIntToScalar(i)), darkPaint);
fmalita5598b632015-09-15 11:26:13 -0700347 canvas->drawRect(SkRect::MakeXYWH(SkIntToScalar(i),
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000348 0,
349 SkIntToScalar(i),
350 SkIntToScalar(i)), lightPaint);
fmalita5598b632015-09-15 11:26:13 -0700351 canvas->drawRect(SkRect::MakeXYWH(0,
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000352 SkIntToScalar(i),
353 SkIntToScalar(i),
354 SkIntToScalar(i)), lightPaint);
fmalita5598b632015-09-15 11:26:13 -0700355 canvas->drawRect(SkRect::MakeXYWH(SkIntToScalar(i),
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000356 SkIntToScalar(i),
357 SkIntToScalar(i),
358 SkIntToScalar(i)), darkPaint);
fmalita5598b632015-09-15 11:26:13 -0700359 canvas->restore();
commit-bot@chromium.org4b681bc2013-09-13 12:40:02 +0000360 }
361 }
fmalita5598b632015-09-15 11:26:13 -0700362
reed9ce9d672016-03-17 10:51:11 -0700363 return surface->makeImageSnapshot();
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000364}
senorblanco@chromium.org194d7752013-07-24 22:19:24 +0000365
robertphillips5605b562016-04-05 11:50:42 -0700366static sk_sp<SkImageFilter> make_scale(float amount, sk_sp<SkImageFilter> input) {
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000367 SkScalar s = amount;
368 SkScalar matrix[20] = { s, 0, 0, 0, 0,
369 0, s, 0, 0, 0,
370 0, 0, s, 0, 0,
371 0, 0, 0, s, 0 };
robertphillips5605b562016-04-05 11:50:42 -0700372 sk_sp<SkColorFilter> filter(SkColorFilter::MakeMatrixFilterRowMajor255(matrix));
373 return SkColorFilterImageFilter::Make(std::move(filter), std::move(input));
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000374}
375
robertphillips5605b562016-04-05 11:50:42 -0700376static sk_sp<SkImageFilter> make_grayscale(sk_sp<SkImageFilter> input,
377 const SkImageFilter::CropRect* cropRect) {
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000378 SkScalar matrix[20];
379 memset(matrix, 0, 20 * sizeof(SkScalar));
380 matrix[0] = matrix[5] = matrix[10] = 0.2126f;
381 matrix[1] = matrix[6] = matrix[11] = 0.7152f;
382 matrix[2] = matrix[7] = matrix[12] = 0.0722f;
383 matrix[18] = 1.0f;
robertphillips5605b562016-04-05 11:50:42 -0700384 sk_sp<SkColorFilter> filter(SkColorFilter::MakeMatrixFilterRowMajor255(matrix));
385 return SkColorFilterImageFilter::Make(std::move(filter), std::move(input), cropRect);
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000386}
387
robertphillips5605b562016-04-05 11:50:42 -0700388static sk_sp<SkImageFilter> make_blue(sk_sp<SkImageFilter> input,
389 const SkImageFilter::CropRect* cropRect) {
390 sk_sp<SkColorFilter> filter(SkColorFilter::MakeModeFilter(SK_ColorBLUE,
Mike Reed7d954ad2016-10-28 15:42:34 -0400391 SkBlendMode::kSrcIn));
robertphillips5605b562016-04-05 11:50:42 -0700392 return SkColorFilterImageFilter::Make(std::move(filter), std::move(input), cropRect);
reedcedc36f2015-03-08 04:42:52 -0700393}
394
robertphillips3e302272016-04-20 11:48:36 -0700395static sk_sp<SkSpecialSurface> create_empty_special_surface(GrContext* context, int widthHeight) {
robertphillipsc91fd342016-04-25 12:32:54 -0700396#if SK_SUPPORT_GPU
robertphillips4418dba2016-03-07 12:45:14 -0800397 if (context) {
robertphillips4df16562016-04-28 15:09:34 -0700398 return SkSpecialSurface::MakeRenderTarget(context,
399 widthHeight, widthHeight,
Brian Osman777b5632016-10-14 09:16:21 -0400400 kRGBA_8888_GrPixelConfig, nullptr);
robertphillipsc91fd342016-04-25 12:32:54 -0700401 } else
402#endif
403 {
robertphillips4418dba2016-03-07 12:45:14 -0800404 const SkImageInfo info = SkImageInfo::MakeN32(widthHeight, widthHeight,
405 kOpaque_SkAlphaType);
robertphillips3e302272016-04-20 11:48:36 -0700406 return SkSpecialSurface::MakeRaster(info);
robertphillips4418dba2016-03-07 12:45:14 -0800407 }
senorblancobf680c32016-03-16 16:15:53 -0700408}
409
senorblanco5878dbd2016-05-19 14:50:29 -0700410static sk_sp<SkSurface> create_surface(GrContext* context, int width, int height) {
411 const SkImageInfo info = SkImageInfo::MakeN32(width, height, kOpaque_SkAlphaType);
412#if SK_SUPPORT_GPU
413 if (context) {
414 return SkSurface::MakeRenderTarget(context, SkBudgeted::kNo, info);
415 } else
416#endif
417 {
418 return SkSurface::MakeRaster(info);
419 }
420}
421
robertphillips3e302272016-04-20 11:48:36 -0700422static sk_sp<SkSpecialImage> create_empty_special_image(GrContext* context, int widthHeight) {
423 sk_sp<SkSpecialSurface> surf(create_empty_special_surface(context, widthHeight));
robertphillips4418dba2016-03-07 12:45:14 -0800424
425 SkASSERT(surf);
426
427 SkCanvas* canvas = surf->getCanvas();
428 SkASSERT(canvas);
429
430 canvas->clear(0x0);
431
robertphillips37bd7c32016-03-17 14:31:39 -0700432 return surf->makeImageSnapshot();
robertphillips4418dba2016-03-07 12:45:14 -0800433}
434
435
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000436DEF_TEST(ImageFilter, reporter) {
437 {
reedcedc36f2015-03-08 04:42:52 -0700438 // Check that two non-clipping color-matrice-filters concatenate into a single filter.
robertphillips5605b562016-04-05 11:50:42 -0700439 sk_sp<SkImageFilter> halfBrightness(make_scale(0.5f, nullptr));
440 sk_sp<SkImageFilter> quarterBrightness(make_scale(0.5f, std::move(halfBrightness)));
halcanary96fcdcc2015-08-27 07:41:13 -0700441 REPORTER_ASSERT(reporter, nullptr == quarterBrightness->getInput(0));
reedcedc36f2015-03-08 04:42:52 -0700442 SkColorFilter* cf;
443 REPORTER_ASSERT(reporter, quarterBrightness->asColorFilter(&cf));
halcanary96fcdcc2015-08-27 07:41:13 -0700444 REPORTER_ASSERT(reporter, cf->asColorMatrix(nullptr));
reedcedc36f2015-03-08 04:42:52 -0700445 cf->unref();
senorblanco@chromium.org194d7752013-07-24 22:19:24 +0000446 }
447
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000448 {
reedcedc36f2015-03-08 04:42:52 -0700449 // Check that a clipping color-matrice-filter followed by a color-matrice-filters
450 // concatenates into a single filter, but not a matrixfilter (due to clamping).
robertphillips5605b562016-04-05 11:50:42 -0700451 sk_sp<SkImageFilter> doubleBrightness(make_scale(2.0f, nullptr));
452 sk_sp<SkImageFilter> halfBrightness(make_scale(0.5f, std::move(doubleBrightness)));
halcanary96fcdcc2015-08-27 07:41:13 -0700453 REPORTER_ASSERT(reporter, nullptr == halfBrightness->getInput(0));
reedcedc36f2015-03-08 04:42:52 -0700454 SkColorFilter* cf;
455 REPORTER_ASSERT(reporter, halfBrightness->asColorFilter(&cf));
halcanary96fcdcc2015-08-27 07:41:13 -0700456 REPORTER_ASSERT(reporter, !cf->asColorMatrix(nullptr));
reedcedc36f2015-03-08 04:42:52 -0700457 cf->unref();
senorblanco@chromium.org194d7752013-07-24 22:19:24 +0000458 }
459
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000460 {
461 // Check that a color filter image filter without a crop rect can be
462 // expressed as a color filter.
robertphillips5605b562016-04-05 11:50:42 -0700463 sk_sp<SkImageFilter> gray(make_grayscale(nullptr, nullptr));
halcanary96fcdcc2015-08-27 07:41:13 -0700464 REPORTER_ASSERT(reporter, true == gray->asColorFilter(nullptr));
senorblanco@chromium.org194d7752013-07-24 22:19:24 +0000465 }
mtklein2afbe232016-02-07 12:23:10 -0800466
reedcedc36f2015-03-08 04:42:52 -0700467 {
468 // Check that a colorfilterimage filter without a crop rect but with an input
469 // that is another colorfilterimage can be expressed as a colorfilter (composed).
robertphillips5605b562016-04-05 11:50:42 -0700470 sk_sp<SkImageFilter> mode(make_blue(nullptr, nullptr));
471 sk_sp<SkImageFilter> gray(make_grayscale(std::move(mode), nullptr));
halcanary96fcdcc2015-08-27 07:41:13 -0700472 REPORTER_ASSERT(reporter, true == gray->asColorFilter(nullptr));
reedcedc36f2015-03-08 04:42:52 -0700473 }
474
475 {
476 // Test that if we exceed the limit of what ComposeColorFilter can combine, we still
477 // can build the DAG and won't assert if we call asColorFilter.
robertphillips5605b562016-04-05 11:50:42 -0700478 sk_sp<SkImageFilter> filter(make_blue(nullptr, nullptr));
reedcedc36f2015-03-08 04:42:52 -0700479 const int kWayTooManyForComposeColorFilter = 100;
480 for (int i = 0; i < kWayTooManyForComposeColorFilter; ++i) {
robertphillips5605b562016-04-05 11:50:42 -0700481 filter = make_blue(filter, nullptr);
reedcedc36f2015-03-08 04:42:52 -0700482 // the first few of these will succeed, but after we hit the internal limit,
483 // it will then return false.
halcanary96fcdcc2015-08-27 07:41:13 -0700484 (void)filter->asColorFilter(nullptr);
reedcedc36f2015-03-08 04:42:52 -0700485 }
486 }
reed5c518a82015-03-05 14:47:29 -0800487
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000488 {
489 // Check that a color filter image filter with a crop rect cannot
490 // be expressed as a color filter.
491 SkImageFilter::CropRect cropRect(SkRect::MakeXYWH(0, 0, 100, 100));
robertphillips5605b562016-04-05 11:50:42 -0700492 sk_sp<SkImageFilter> grayWithCrop(make_grayscale(nullptr, &cropRect));
halcanary96fcdcc2015-08-27 07:41:13 -0700493 REPORTER_ASSERT(reporter, false == grayWithCrop->asColorFilter(nullptr));
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000494 }
495
496 {
senorblanco3df05012014-07-03 11:13:09 -0700497 // Check that two non-commutative matrices are concatenated in
498 // the correct order.
499 SkScalar blueToRedMatrix[20] = { 0 };
500 blueToRedMatrix[2] = blueToRedMatrix[18] = SK_Scalar1;
501 SkScalar redToGreenMatrix[20] = { 0 };
502 redToGreenMatrix[5] = redToGreenMatrix[18] = SK_Scalar1;
robertphillips5605b562016-04-05 11:50:42 -0700503 sk_sp<SkColorFilter> blueToRed(SkColorFilter::MakeMatrixFilterRowMajor255(blueToRedMatrix));
504 sk_sp<SkImageFilter> filter1(SkColorFilterImageFilter::Make(std::move(blueToRed),
505 nullptr));
506 sk_sp<SkColorFilter> redToGreen(SkColorFilter::MakeMatrixFilterRowMajor255(redToGreenMatrix));
507 sk_sp<SkImageFilter> filter2(SkColorFilterImageFilter::Make(std::move(redToGreen),
508 std::move(filter1)));
senorblanco3df05012014-07-03 11:13:09 -0700509
510 SkBitmap result;
511 result.allocN32Pixels(kBitmapSize, kBitmapSize);
512
513 SkPaint paint;
514 paint.setColor(SK_ColorBLUE);
robertphillips5605b562016-04-05 11:50:42 -0700515 paint.setImageFilter(std::move(filter2));
senorblanco3df05012014-07-03 11:13:09 -0700516 SkCanvas canvas(result);
517 canvas.clear(0x0);
518 SkRect rect = SkRect::Make(SkIRect::MakeWH(kBitmapSize, kBitmapSize));
519 canvas.drawRect(rect, paint);
520 uint32_t pixel = *result.getAddr32(0, 0);
521 // The result here should be green, since we have effectively shifted blue to green.
522 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
523 }
524
525 {
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000526 // Tests pass by not asserting
reed9ce9d672016-03-17 10:51:11 -0700527 sk_sp<SkImage> image(make_small_image());
fmalita5598b632015-09-15 11:26:13 -0700528 SkBitmap result;
mike@reedtribe.orgdeee4962014-02-13 14:41:43 +0000529 result.allocN32Pixels(kBitmapSize, kBitmapSize);
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000530
senorblanco@chromium.org194d7752013-07-24 22:19:24 +0000531 {
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000532 // This tests for :
533 // 1 ) location at (0,0,1)
robertphillips3d32d762015-07-13 13:16:44 -0700534 SkPoint3 location = SkPoint3::Make(0, 0, SK_Scalar1);
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000535 // 2 ) location and target at same value
robertphillips3d32d762015-07-13 13:16:44 -0700536 SkPoint3 target = SkPoint3::Make(location.fX, location.fY, location.fZ);
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000537 // 3 ) large negative specular exponent value
538 SkScalar specularExponent = -1000;
539
robertphillips549c8992016-04-01 09:28:51 -0700540 sk_sp<SkImageFilter> bmSrc(SkImageSource::Make(std::move(image)));
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000541 SkPaint paint;
robertphillips12fa47d2016-04-08 16:28:09 -0700542 paint.setImageFilter(SkLightingImageFilter::MakeSpotLitSpecular(
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000543 location, target, specularExponent, 180,
544 0xFFFFFFFF, SK_Scalar1, SK_Scalar1, SK_Scalar1,
robertphillips12fa47d2016-04-08 16:28:09 -0700545 std::move(bmSrc)));
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000546 SkCanvas canvas(result);
547 SkRect r = SkRect::MakeWH(SkIntToScalar(kBitmapSize),
548 SkIntToScalar(kBitmapSize));
549 canvas.drawRect(r, paint);
senorblanco@chromium.org194d7752013-07-24 22:19:24 +0000550 }
senorblanco@chromium.org194d7752013-07-24 22:19:24 +0000551 }
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +0000552}
senorblanco@chromium.org6776b822014-01-03 21:48:22 +0000553
robertphillips3e302272016-04-20 11:48:36 -0700554static void test_crop_rects(skiatest::Reporter* reporter,
robertphillips4418dba2016-03-07 12:45:14 -0800555 GrContext* context) {
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +0000556 // Check that all filters offset to their absolute crop rect,
557 // unaffected by the input crop rect.
558 // Tests pass by not asserting.
robertphillips3e302272016-04-20 11:48:36 -0700559 sk_sp<SkSpecialImage> srcImg(create_empty_special_image(context, 100));
robertphillips4418dba2016-03-07 12:45:14 -0800560 SkASSERT(srcImg);
senorblanco@chromium.org6776b822014-01-03 21:48:22 +0000561
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +0000562 SkImageFilter::CropRect inputCropRect(SkRect::MakeXYWH(8, 13, 80, 80));
563 SkImageFilter::CropRect cropRect(SkRect::MakeXYWH(20, 30, 60, 60));
robertphillipsfc11b0a2016-04-05 09:09:36 -0700564 sk_sp<SkImageFilter> input(make_grayscale(nullptr, &inputCropRect));
senorblanco@chromium.org6776b822014-01-03 21:48:22 +0000565
robertphillipsfc11b0a2016-04-05 09:09:36 -0700566 FilterList filters(input, &cropRect);
senorblanco@chromium.org6776b822014-01-03 21:48:22 +0000567
senorblanco297f7ce2016-03-23 13:44:26 -0700568 for (int i = 0; i < filters.count(); ++i) {
569 SkImageFilter* filter = filters.getFilter(i);
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +0000570 SkIPoint offset;
brianosman2a75e5d2016-09-22 07:15:37 -0700571 SkImageFilter::OutputProperties noColorSpace(nullptr);
572 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeWH(100, 100), nullptr, noColorSpace);
robertphillips2302de92016-03-24 07:26:32 -0700573 sk_sp<SkSpecialImage> resultImg(filter->filterImage(srcImg.get(), ctx, &offset));
senorblanco297f7ce2016-03-23 13:44:26 -0700574 REPORTER_ASSERT_MESSAGE(reporter, resultImg, filters.getName(i));
575 REPORTER_ASSERT_MESSAGE(reporter, offset.fX == 20 && offset.fY == 30, filters.getName(i));
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +0000576 }
577}
578
robertphillips3e302272016-04-20 11:48:36 -0700579static void test_negative_blur_sigma(skiatest::Reporter* reporter,
robertphillips4418dba2016-03-07 12:45:14 -0800580 GrContext* context) {
senorblanco32673b92014-09-09 09:15:04 -0700581 // Check that SkBlurImageFilter will accept a negative sigma, either in
582 // the given arguments or after CTM application.
reed5ea95df2015-10-06 14:05:32 -0700583 const int width = 32, height = 32;
584 const SkScalar five = SkIntToScalar(5);
senorblanco32673b92014-09-09 09:15:04 -0700585
robertphillips6e7025a2016-04-04 04:31:25 -0700586 sk_sp<SkImageFilter> positiveFilter(SkBlurImageFilter::Make(five, five, nullptr));
587 sk_sp<SkImageFilter> negativeFilter(SkBlurImageFilter::Make(-five, five, nullptr));
senorblanco32673b92014-09-09 09:15:04 -0700588
589 SkBitmap gradient = make_gradient_circle(width, height);
robertphillips3e302272016-04-20 11:48:36 -0700590 sk_sp<SkSpecialImage> imgSrc(SkSpecialImage::MakeFromRaster(SkIRect::MakeWH(width, height),
robertphillips37bd7c32016-03-17 14:31:39 -0700591 gradient));
robertphillips4418dba2016-03-07 12:45:14 -0800592
senorblanco32673b92014-09-09 09:15:04 -0700593 SkIPoint offset;
brianosman2a75e5d2016-09-22 07:15:37 -0700594 SkImageFilter::OutputProperties noColorSpace(nullptr);
595 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeWH(32, 32), nullptr, noColorSpace);
robertphillips4418dba2016-03-07 12:45:14 -0800596
robertphillips2302de92016-03-24 07:26:32 -0700597 sk_sp<SkSpecialImage> positiveResult1(positiveFilter->filterImage(imgSrc.get(), ctx, &offset));
robertphillips4418dba2016-03-07 12:45:14 -0800598 REPORTER_ASSERT(reporter, positiveResult1);
599
robertphillips2302de92016-03-24 07:26:32 -0700600 sk_sp<SkSpecialImage> negativeResult1(negativeFilter->filterImage(imgSrc.get(), ctx, &offset));
robertphillips4418dba2016-03-07 12:45:14 -0800601 REPORTER_ASSERT(reporter, negativeResult1);
602
senorblanco32673b92014-09-09 09:15:04 -0700603 SkMatrix negativeScale;
604 negativeScale.setScale(-SK_Scalar1, SK_Scalar1);
brianosman2a75e5d2016-09-22 07:15:37 -0700605 SkImageFilter::Context negativeCTX(negativeScale, SkIRect::MakeWH(32, 32), nullptr,
606 noColorSpace);
robertphillips4418dba2016-03-07 12:45:14 -0800607
robertphillips2302de92016-03-24 07:26:32 -0700608 sk_sp<SkSpecialImage> negativeResult2(positiveFilter->filterImage(imgSrc.get(),
609 negativeCTX,
610 &offset));
robertphillips4418dba2016-03-07 12:45:14 -0800611 REPORTER_ASSERT(reporter, negativeResult2);
612
robertphillips2302de92016-03-24 07:26:32 -0700613 sk_sp<SkSpecialImage> positiveResult2(negativeFilter->filterImage(imgSrc.get(),
614 negativeCTX,
615 &offset));
robertphillips4418dba2016-03-07 12:45:14 -0800616 REPORTER_ASSERT(reporter, positiveResult2);
617
618
619 SkBitmap positiveResultBM1, positiveResultBM2;
620 SkBitmap negativeResultBM1, negativeResultBM2;
621
robertphillips64612512016-04-08 12:10:42 -0700622 REPORTER_ASSERT(reporter, positiveResult1->getROPixels(&positiveResultBM1));
623 REPORTER_ASSERT(reporter, positiveResult2->getROPixels(&positiveResultBM2));
624 REPORTER_ASSERT(reporter, negativeResult1->getROPixels(&negativeResultBM1));
625 REPORTER_ASSERT(reporter, negativeResult2->getROPixels(&negativeResultBM2));
robertphillips4418dba2016-03-07 12:45:14 -0800626
senorblanco32673b92014-09-09 09:15:04 -0700627 for (int y = 0; y < height; y++) {
robertphillips4418dba2016-03-07 12:45:14 -0800628 int diffs = memcmp(positiveResultBM1.getAddr32(0, y),
629 negativeResultBM1.getAddr32(0, y),
630 positiveResultBM1.rowBytes());
senorblanco32673b92014-09-09 09:15:04 -0700631 REPORTER_ASSERT(reporter, !diffs);
632 if (diffs) {
633 break;
634 }
robertphillips4418dba2016-03-07 12:45:14 -0800635 diffs = memcmp(positiveResultBM1.getAddr32(0, y),
636 negativeResultBM2.getAddr32(0, y),
637 positiveResultBM1.rowBytes());
senorblanco32673b92014-09-09 09:15:04 -0700638 REPORTER_ASSERT(reporter, !diffs);
639 if (diffs) {
640 break;
641 }
robertphillips4418dba2016-03-07 12:45:14 -0800642 diffs = memcmp(positiveResultBM1.getAddr32(0, y),
643 positiveResultBM2.getAddr32(0, y),
644 positiveResultBM1.rowBytes());
senorblanco32673b92014-09-09 09:15:04 -0700645 REPORTER_ASSERT(reporter, !diffs);
646 if (diffs) {
647 break;
648 }
649 }
650}
651
senorblanco21a465d2016-04-11 11:58:39 -0700652DEF_TEST(ImageFilterNegativeBlurSigma, reporter) {
robertphillips3e302272016-04-20 11:48:36 -0700653 test_negative_blur_sigma(reporter, nullptr);
robertphillips4418dba2016-03-07 12:45:14 -0800654}
655
656#if SK_SUPPORT_GPU
bsalomon68d91342016-04-12 09:59:58 -0700657DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterNegativeBlurSigma_Gpu, reporter, ctxInfo) {
bsalomon8b7451a2016-05-11 06:33:06 -0700658 test_negative_blur_sigma(reporter, ctxInfo.grContext());
robertphillips4418dba2016-03-07 12:45:14 -0800659}
660#endif
661
robertphillips3e302272016-04-20 11:48:36 -0700662static void test_zero_blur_sigma(skiatest::Reporter* reporter, GrContext* context) {
senorblancobf680c32016-03-16 16:15:53 -0700663 // Check that SkBlurImageFilter with a zero sigma and a non-zero srcOffset works correctly.
664 SkImageFilter::CropRect cropRect(SkRect::Make(SkIRect::MakeXYWH(5, 0, 5, 10)));
robertphillips51a315e2016-03-31 09:05:49 -0700665 sk_sp<SkImageFilter> input(SkOffsetImageFilter::Make(0, 0, nullptr, &cropRect));
robertphillips6e7025a2016-04-04 04:31:25 -0700666 sk_sp<SkImageFilter> filter(SkBlurImageFilter::Make(0, 0, std::move(input), &cropRect));
senorblancobf680c32016-03-16 16:15:53 -0700667
robertphillips3e302272016-04-20 11:48:36 -0700668 sk_sp<SkSpecialSurface> surf(create_empty_special_surface(context, 10));
senorblancobf680c32016-03-16 16:15:53 -0700669 surf->getCanvas()->clear(SK_ColorGREEN);
robertphillips37bd7c32016-03-17 14:31:39 -0700670 sk_sp<SkSpecialImage> image(surf->makeImageSnapshot());
senorblancobf680c32016-03-16 16:15:53 -0700671
672 SkIPoint offset;
brianosman2a75e5d2016-09-22 07:15:37 -0700673 SkImageFilter::OutputProperties noColorSpace(nullptr);
674 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeWH(32, 32), nullptr, noColorSpace);
senorblancobf680c32016-03-16 16:15:53 -0700675
robertphillips2302de92016-03-24 07:26:32 -0700676 sk_sp<SkSpecialImage> result(filter->filterImage(image.get(), ctx, &offset));
senorblancobf680c32016-03-16 16:15:53 -0700677 REPORTER_ASSERT(reporter, offset.fX == 5 && offset.fY == 0);
678 REPORTER_ASSERT(reporter, result);
679 REPORTER_ASSERT(reporter, result->width() == 5 && result->height() == 10);
680
681 SkBitmap resultBM;
682
robertphillips64612512016-04-08 12:10:42 -0700683 REPORTER_ASSERT(reporter, result->getROPixels(&resultBM));
senorblancobf680c32016-03-16 16:15:53 -0700684
senorblancobf680c32016-03-16 16:15:53 -0700685 for (int y = 0; y < resultBM.height(); y++) {
686 for (int x = 0; x < resultBM.width(); x++) {
687 bool diff = *resultBM.getAddr32(x, y) != SK_ColorGREEN;
688 REPORTER_ASSERT(reporter, !diff);
689 if (diff) {
690 break;
691 }
692 }
693 }
694}
695
senorblanco21a465d2016-04-11 11:58:39 -0700696DEF_TEST(ImageFilterZeroBlurSigma, reporter) {
robertphillips3e302272016-04-20 11:48:36 -0700697 test_zero_blur_sigma(reporter, nullptr);
senorblancobf680c32016-03-16 16:15:53 -0700698}
699
700#if SK_SUPPORT_GPU
bsalomon68d91342016-04-12 09:59:58 -0700701DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterZeroBlurSigma_Gpu, reporter, ctxInfo) {
bsalomon8b7451a2016-05-11 06:33:06 -0700702 test_zero_blur_sigma(reporter, ctxInfo.grContext());
senorblancobf680c32016-03-16 16:15:53 -0700703}
704#endif
705
senorblanco6a93fa12016-04-05 04:43:45 -0700706
707// Tests that, even when an upstream filter has returned null (due to failure or clipping), a
708// downstream filter that affects transparent black still does so even with a nullptr input.
robertphillips3e302272016-04-20 11:48:36 -0700709static void test_fail_affects_transparent_black(skiatest::Reporter* reporter, GrContext* context) {
senorblanco6a93fa12016-04-05 04:43:45 -0700710 sk_sp<FailImageFilter> failFilter(new FailImageFilter());
robertphillips3e302272016-04-20 11:48:36 -0700711 sk_sp<SkSpecialImage> source(create_empty_special_image(context, 5));
brianosman2a75e5d2016-09-22 07:15:37 -0700712 SkImageFilter::OutputProperties noColorSpace(nullptr);
713 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeXYWH(0, 0, 1, 1), nullptr, noColorSpace);
Mike Reed7d954ad2016-10-28 15:42:34 -0400714 sk_sp<SkColorFilter> green(SkColorFilter::MakeModeFilter(SK_ColorGREEN, SkBlendMode::kSrc));
senorblanco6a93fa12016-04-05 04:43:45 -0700715 SkASSERT(green->affectsTransparentBlack());
robertphillips5605b562016-04-05 11:50:42 -0700716 sk_sp<SkImageFilter> greenFilter(SkColorFilterImageFilter::Make(std::move(green),
717 std::move(failFilter)));
senorblanco6a93fa12016-04-05 04:43:45 -0700718 SkIPoint offset;
719 sk_sp<SkSpecialImage> result(greenFilter->filterImage(source.get(), ctx, &offset));
720 REPORTER_ASSERT(reporter, nullptr != result.get());
721 if (result.get()) {
722 SkBitmap resultBM;
robertphillips64612512016-04-08 12:10:42 -0700723 REPORTER_ASSERT(reporter, result->getROPixels(&resultBM));
senorblanco6a93fa12016-04-05 04:43:45 -0700724 REPORTER_ASSERT(reporter, *resultBM.getAddr32(0, 0) == SK_ColorGREEN);
725 }
726}
727
728DEF_TEST(ImageFilterFailAffectsTransparentBlack, reporter) {
robertphillips3e302272016-04-20 11:48:36 -0700729 test_fail_affects_transparent_black(reporter, nullptr);
senorblanco6a93fa12016-04-05 04:43:45 -0700730}
731
732#if SK_SUPPORT_GPU
bsalomon68d91342016-04-12 09:59:58 -0700733DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterFailAffectsTransparentBlack_Gpu, reporter, ctxInfo) {
bsalomon8b7451a2016-05-11 06:33:06 -0700734 test_fail_affects_transparent_black(reporter, ctxInfo.grContext());
senorblanco6a93fa12016-04-05 04:43:45 -0700735}
736#endif
737
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +0000738DEF_TEST(ImageFilterDrawTiled, reporter) {
739 // Check that all filters when drawn tiled (with subsequent clip rects) exactly
740 // match the same filters drawn with a single full-canvas bitmap draw.
741 // Tests pass by not asserting.
742
robertphillipsfc11b0a2016-04-05 09:09:36 -0700743 FilterList filters(nullptr);
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +0000744
745 SkBitmap untiledResult, tiledResult;
reed5ea95df2015-10-06 14:05:32 -0700746 const int width = 64, height = 64;
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +0000747 untiledResult.allocN32Pixels(width, height);
748 tiledResult.allocN32Pixels(width, height);
749 SkCanvas tiledCanvas(tiledResult);
750 SkCanvas untiledCanvas(untiledResult);
senorblanco@chromium.orgd4db6572014-05-07 20:00:04 +0000751 int tileSize = 8;
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +0000752
senorblanco@chromium.orgd4db6572014-05-07 20:00:04 +0000753 for (int scale = 1; scale <= 2; ++scale) {
senorblanco297f7ce2016-03-23 13:44:26 -0700754 for (int i = 0; i < filters.count(); ++i) {
senorblanco@chromium.orgd4db6572014-05-07 20:00:04 +0000755 tiledCanvas.clear(0);
756 untiledCanvas.clear(0);
757 SkPaint paint;
Mike Reed5e257172016-11-01 11:22:05 -0400758 paint.setImageFilter(sk_ref_sp(filters.getFilter(i)));
senorblanco@chromium.orgd4db6572014-05-07 20:00:04 +0000759 paint.setTextSize(SkIntToScalar(height));
760 paint.setColor(SK_ColorWHITE);
761 SkString str;
762 const char* text = "ABC";
763 SkScalar ypos = SkIntToScalar(height);
764 untiledCanvas.save();
765 untiledCanvas.scale(SkIntToScalar(scale), SkIntToScalar(scale));
Cary Clark2a475ea2017-04-28 15:35:12 -0400766 untiledCanvas.drawString(text, 0, ypos, paint);
senorblanco@chromium.orgd4db6572014-05-07 20:00:04 +0000767 untiledCanvas.restore();
768 for (int y = 0; y < height; y += tileSize) {
769 for (int x = 0; x < width; x += tileSize) {
770 tiledCanvas.save();
771 tiledCanvas.clipRect(SkRect::Make(SkIRect::MakeXYWH(x, y, tileSize, tileSize)));
772 tiledCanvas.scale(SkIntToScalar(scale), SkIntToScalar(scale));
Cary Clark2a475ea2017-04-28 15:35:12 -0400773 tiledCanvas.drawString(text, 0, ypos, paint);
senorblanco@chromium.orgd4db6572014-05-07 20:00:04 +0000774 tiledCanvas.restore();
775 }
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +0000776 }
senorblanco@chromium.orgd4db6572014-05-07 20:00:04 +0000777 untiledCanvas.flush();
778 tiledCanvas.flush();
Mike Reed34042072017-08-08 16:29:22 -0400779 if (!sk_tool_utils::equal_pixels(untiledResult, tiledResult, 1)) {
Mike Reed5a625e02017-08-08 15:48:54 -0400780 REPORTER_ASSERT_MESSAGE(reporter, false, filters.getName(i));
781 break;
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +0000782 }
783 }
784 }
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +0000785}
786
mtklein3f3b3d02014-12-01 11:47:08 -0800787static void draw_saveLayer_picture(int width, int height, int tileSize,
robertphillipsa8d7f0b2014-08-29 08:03:56 -0700788 SkBBHFactory* factory, SkBitmap* result) {
mtkleind910f542014-08-22 09:06:34 -0700789
790 SkMatrix matrix;
791 matrix.setTranslate(SkIntToScalar(50), 0);
792
Mike Reed7d954ad2016-10-28 15:42:34 -0400793 sk_sp<SkColorFilter> cf(SkColorFilter::MakeModeFilter(SK_ColorWHITE, SkBlendMode::kSrc));
robertphillips5605b562016-04-05 11:50:42 -0700794 sk_sp<SkImageFilter> cfif(SkColorFilterImageFilter::Make(std::move(cf), nullptr));
robertphillipsae8c9332016-04-05 15:09:00 -0700795 sk_sp<SkImageFilter> imageFilter(SkImageFilter::MakeMatrixFilter(matrix,
796 kNone_SkFilterQuality,
797 std::move(cfif)));
mtkleind910f542014-08-22 09:06:34 -0700798
799 SkPaint paint;
robertphillips5605b562016-04-05 11:50:42 -0700800 paint.setImageFilter(std::move(imageFilter));
mtkleind910f542014-08-22 09:06:34 -0700801 SkPictureRecorder recorder;
802 SkRect bounds = SkRect::Make(SkIRect::MakeXYWH(0, 0, 50, 50));
mtklein3f3b3d02014-12-01 11:47:08 -0800803 SkCanvas* recordingCanvas = recorder.beginRecording(SkIntToScalar(width),
804 SkIntToScalar(height),
robertphillipsa8d7f0b2014-08-29 08:03:56 -0700805 factory, 0);
mtkleind910f542014-08-22 09:06:34 -0700806 recordingCanvas->translate(-55, 0);
807 recordingCanvas->saveLayer(&bounds, &paint);
808 recordingCanvas->restore();
reedca2622b2016-03-18 07:25:55 -0700809 sk_sp<SkPicture> picture1(recorder.finishRecordingAsPicture());
mtkleind910f542014-08-22 09:06:34 -0700810
811 result->allocN32Pixels(width, height);
812 SkCanvas canvas(*result);
813 canvas.clear(0);
814 canvas.clipRect(SkRect::Make(SkIRect::MakeWH(tileSize, tileSize)));
815 canvas.drawPicture(picture1.get());
816}
817
818DEF_TEST(ImageFilterDrawMatrixBBH, reporter) {
819 // Check that matrix filter when drawn tiled with BBH exactly
820 // matches the same thing drawn without BBH.
821 // Tests pass by not asserting.
822
823 const int width = 200, height = 200;
824 const int tileSize = 100;
825 SkBitmap result1, result2;
826 SkRTreeFactory factory;
827
robertphillipsa8d7f0b2014-08-29 08:03:56 -0700828 draw_saveLayer_picture(width, height, tileSize, &factory, &result1);
halcanary96fcdcc2015-08-27 07:41:13 -0700829 draw_saveLayer_picture(width, height, tileSize, nullptr, &result2);
mtkleind910f542014-08-22 09:06:34 -0700830
831 for (int y = 0; y < height; y++) {
832 int diffs = memcmp(result1.getAddr32(0, y), result2.getAddr32(0, y), result1.rowBytes());
833 REPORTER_ASSERT(reporter, !diffs);
834 if (diffs) {
835 break;
836 }
837 }
838}
839
robertphillips6e7025a2016-04-04 04:31:25 -0700840static sk_sp<SkImageFilter> make_blur(sk_sp<SkImageFilter> input) {
841 return SkBlurImageFilter::Make(SK_Scalar1, SK_Scalar1, std::move(input));
senorblanco1150a6d2014-08-25 12:46:58 -0700842}
843
robertphillips6e7025a2016-04-04 04:31:25 -0700844static sk_sp<SkImageFilter> make_drop_shadow(sk_sp<SkImageFilter> input) {
robertphillipsc4169122016-04-06 08:40:59 -0700845 return SkDropShadowImageFilter::Make(
senorblanco1150a6d2014-08-25 12:46:58 -0700846 SkIntToScalar(100), SkIntToScalar(100),
847 SkIntToScalar(10), SkIntToScalar(10),
sugoi234f0362014-10-23 13:59:52 -0700848 SK_ColorBLUE, SkDropShadowImageFilter::kDrawShadowAndForeground_ShadowMode,
robertphillipsc4169122016-04-06 08:40:59 -0700849 std::move(input));
senorblanco1150a6d2014-08-25 12:46:58 -0700850}
851
852DEF_TEST(ImageFilterBlurThenShadowBounds, reporter) {
robertphillips6e7025a2016-04-04 04:31:25 -0700853 sk_sp<SkImageFilter> filter1(make_blur(nullptr));
854 sk_sp<SkImageFilter> filter2(make_drop_shadow(std::move(filter1)));
senorblanco1150a6d2014-08-25 12:46:58 -0700855
856 SkIRect bounds = SkIRect::MakeXYWH(0, 0, 100, 100);
Herb Derby59f8f152017-10-17 22:27:23 +0000857 SkIRect expectedBounds = SkIRect::MakeXYWH(-133, -133, 236, 236);
senorblancoe5e79842016-03-21 14:51:59 -0700858 bounds = filter2->filterBounds(bounds, SkMatrix::I());
senorblanco1150a6d2014-08-25 12:46:58 -0700859
860 REPORTER_ASSERT(reporter, bounds == expectedBounds);
861}
862
863DEF_TEST(ImageFilterShadowThenBlurBounds, reporter) {
robertphillips6e7025a2016-04-04 04:31:25 -0700864 sk_sp<SkImageFilter> filter1(make_drop_shadow(nullptr));
865 sk_sp<SkImageFilter> filter2(make_blur(std::move(filter1)));
senorblanco1150a6d2014-08-25 12:46:58 -0700866
867 SkIRect bounds = SkIRect::MakeXYWH(0, 0, 100, 100);
Herb Derby59f8f152017-10-17 22:27:23 +0000868 SkIRect expectedBounds = SkIRect::MakeXYWH(-133, -133, 236, 236);
senorblancoe5e79842016-03-21 14:51:59 -0700869 bounds = filter2->filterBounds(bounds, SkMatrix::I());
senorblanco1150a6d2014-08-25 12:46:58 -0700870
871 REPORTER_ASSERT(reporter, bounds == expectedBounds);
872}
873
874DEF_TEST(ImageFilterDilateThenBlurBounds, reporter) {
robertphillipsfc11b0a2016-04-05 09:09:36 -0700875 sk_sp<SkImageFilter> filter1(SkDilateImageFilter::Make(2, 2, nullptr));
robertphillips6e7025a2016-04-04 04:31:25 -0700876 sk_sp<SkImageFilter> filter2(make_drop_shadow(std::move(filter1)));
senorblanco1150a6d2014-08-25 12:46:58 -0700877
878 SkIRect bounds = SkIRect::MakeXYWH(0, 0, 100, 100);
879 SkIRect expectedBounds = SkIRect::MakeXYWH(-132, -132, 234, 234);
senorblancoe5e79842016-03-21 14:51:59 -0700880 bounds = filter2->filterBounds(bounds, SkMatrix::I());
senorblanco1150a6d2014-08-25 12:46:58 -0700881
882 REPORTER_ASSERT(reporter, bounds == expectedBounds);
883}
884
jbroman203a9932016-07-11 14:07:59 -0700885DEF_TEST(ImageFilterScaledBlurRadius, reporter) {
886 // Each blur should spread 3*sigma, so 3 for the blur and 30 for the shadow
887 // (before the CTM). Bounds should be computed correctly in the presence of
888 // a (possibly negative) scale.
889 sk_sp<SkImageFilter> blur(make_blur(nullptr));
890 sk_sp<SkImageFilter> dropShadow(make_drop_shadow(nullptr));
891 {
892 // Uniform scale by 2.
893 SkMatrix scaleMatrix;
894 scaleMatrix.setScale(2, 2);
895 SkIRect bounds = SkIRect::MakeLTRB(0, 0, 200, 200);
896
Herb Derby59f8f152017-10-17 22:27:23 +0000897 SkIRect expectedBlurBounds = SkIRect::MakeLTRB(-6, -6, 206, 206);
jbroman203a9932016-07-11 14:07:59 -0700898 SkIRect blurBounds = blur->filterBounds(
899 bounds, scaleMatrix, SkImageFilter::kForward_MapDirection);
900 REPORTER_ASSERT(reporter, blurBounds == expectedBlurBounds);
901 SkIRect reverseBlurBounds = blur->filterBounds(
902 bounds, scaleMatrix, SkImageFilter::kReverse_MapDirection);
903 REPORTER_ASSERT(reporter, reverseBlurBounds == expectedBlurBounds);
904
905 SkIRect expectedShadowBounds = SkIRect::MakeLTRB(0, 0, 460, 460);
906 SkIRect shadowBounds = dropShadow->filterBounds(
907 bounds, scaleMatrix, SkImageFilter::kForward_MapDirection);
908 REPORTER_ASSERT(reporter, shadowBounds == expectedShadowBounds);
909 SkIRect expectedReverseShadowBounds =
910 SkIRect::MakeLTRB(-260, -260, 200, 200);
911 SkIRect reverseShadowBounds = dropShadow->filterBounds(
912 bounds, scaleMatrix, SkImageFilter::kReverse_MapDirection);
913 REPORTER_ASSERT(reporter,
914 reverseShadowBounds == expectedReverseShadowBounds);
915 }
916 {
917 // Vertical flip.
918 SkMatrix scaleMatrix;
919 scaleMatrix.setScale(1, -1);
920 SkIRect bounds = SkIRect::MakeLTRB(0, -100, 100, 0);
921
Herb Derby59f8f152017-10-17 22:27:23 +0000922 SkIRect expectedBlurBounds = SkIRect::MakeLTRB(-3, -103, 103, 3);
jbroman203a9932016-07-11 14:07:59 -0700923 SkIRect blurBounds = blur->filterBounds(
924 bounds, scaleMatrix, SkImageFilter::kForward_MapDirection);
925 REPORTER_ASSERT(reporter, blurBounds == expectedBlurBounds);
926 SkIRect reverseBlurBounds = blur->filterBounds(
927 bounds, scaleMatrix, SkImageFilter::kReverse_MapDirection);
928 REPORTER_ASSERT(reporter, reverseBlurBounds == expectedBlurBounds);
929
930 SkIRect expectedShadowBounds = SkIRect::MakeLTRB(0, -230, 230, 0);
931 SkIRect shadowBounds = dropShadow->filterBounds(
932 bounds, scaleMatrix, SkImageFilter::kForward_MapDirection);
933 REPORTER_ASSERT(reporter, shadowBounds == expectedShadowBounds);
934 SkIRect expectedReverseShadowBounds =
935 SkIRect::MakeLTRB(-130, -100, 100, 130);
936 SkIRect reverseShadowBounds = dropShadow->filterBounds(
937 bounds, scaleMatrix, SkImageFilter::kReverse_MapDirection);
938 REPORTER_ASSERT(reporter,
939 reverseShadowBounds == expectedReverseShadowBounds);
940 }
941}
942
ajuma5788faa2015-02-13 09:05:47 -0800943DEF_TEST(ImageFilterComposedBlurFastBounds, reporter) {
robertphillips6e7025a2016-04-04 04:31:25 -0700944 sk_sp<SkImageFilter> filter1(make_blur(nullptr));
945 sk_sp<SkImageFilter> filter2(make_blur(nullptr));
robertphillips491fb172016-03-30 12:32:58 -0700946 sk_sp<SkImageFilter> composedFilter(SkComposeImageFilter::Make(std::move(filter1),
947 std::move(filter2)));
ajuma5788faa2015-02-13 09:05:47 -0800948
949 SkRect boundsSrc = SkRect::MakeWH(SkIntToScalar(100), SkIntToScalar(100));
950 SkRect expectedBounds = SkRect::MakeXYWH(
Herb Derby59f8f152017-10-17 22:27:23 +0000951 SkIntToScalar(-6), SkIntToScalar(-6), SkIntToScalar(112), SkIntToScalar(112));
senorblancoe5e79842016-03-21 14:51:59 -0700952 SkRect boundsDst = composedFilter->computeFastBounds(boundsSrc);
ajuma5788faa2015-02-13 09:05:47 -0800953
954 REPORTER_ASSERT(reporter, boundsDst == expectedBounds);
955}
956
jbroman0e3129d2016-03-17 12:24:23 -0700957DEF_TEST(ImageFilterUnionBounds, reporter) {
robertphillips51a315e2016-03-31 09:05:49 -0700958 sk_sp<SkImageFilter> offset(SkOffsetImageFilter::Make(50, 0, nullptr));
jbroman0e3129d2016-03-17 12:24:23 -0700959 // Regardless of which order they appear in, the image filter bounds should
960 // be combined correctly.
961 {
reed374772b2016-10-05 17:33:02 -0700962 sk_sp<SkImageFilter> composite(SkXfermodeImageFilter::Make(SkBlendMode::kSrcOver, offset));
jbroman0e3129d2016-03-17 12:24:23 -0700963 SkRect bounds = SkRect::MakeWH(100, 100);
964 // Intentionally aliasing here, as that's what the real callers do.
senorblancoe5e79842016-03-21 14:51:59 -0700965 bounds = composite->computeFastBounds(bounds);
jbroman0e3129d2016-03-17 12:24:23 -0700966 REPORTER_ASSERT(reporter, bounds == SkRect::MakeWH(150, 100));
967 }
968 {
reed374772b2016-10-05 17:33:02 -0700969 sk_sp<SkImageFilter> composite(SkXfermodeImageFilter::Make(SkBlendMode::kSrcOver, nullptr,
robertphillips8c0326d2016-04-05 12:48:34 -0700970 offset, nullptr));
jbroman0e3129d2016-03-17 12:24:23 -0700971 SkRect bounds = SkRect::MakeWH(100, 100);
972 // Intentionally aliasing here, as that's what the real callers do.
senorblancoe5e79842016-03-21 14:51:59 -0700973 bounds = composite->computeFastBounds(bounds);
jbroman0e3129d2016-03-17 12:24:23 -0700974 REPORTER_ASSERT(reporter, bounds == SkRect::MakeWH(150, 100));
975 }
976}
977
robertphillips3e302272016-04-20 11:48:36 -0700978static void test_imagefilter_merge_result_size(skiatest::Reporter* reporter, GrContext* context) {
senorblanco4a243982015-11-25 07:06:55 -0800979 SkBitmap greenBM;
980 greenBM.allocN32Pixels(20, 20);
981 greenBM.eraseColor(SK_ColorGREEN);
reed9ce9d672016-03-17 10:51:11 -0700982 sk_sp<SkImage> greenImage(SkImage::MakeFromBitmap(greenBM));
robertphillips549c8992016-04-01 09:28:51 -0700983 sk_sp<SkImageFilter> source(SkImageSource::Make(std::move(greenImage)));
Mike Reed0bdaf052017-06-18 23:35:57 -0400984 sk_sp<SkImageFilter> merge(SkMergeImageFilter::Make(source, source));
senorblanco4a243982015-11-25 07:06:55 -0800985
robertphillips3e302272016-04-20 11:48:36 -0700986 sk_sp<SkSpecialImage> srcImg(create_empty_special_image(context, 1));
robertphillips4418dba2016-03-07 12:45:14 -0800987
brianosman2a75e5d2016-09-22 07:15:37 -0700988 SkImageFilter::OutputProperties noColorSpace(nullptr);
989 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeXYWH(0, 0, 100, 100), nullptr,
990 noColorSpace);
senorblanco4a243982015-11-25 07:06:55 -0800991 SkIPoint offset;
robertphillips4418dba2016-03-07 12:45:14 -0800992
robertphillips2302de92016-03-24 07:26:32 -0700993 sk_sp<SkSpecialImage> resultImg(merge->filterImage(srcImg.get(), ctx, &offset));
robertphillips4418dba2016-03-07 12:45:14 -0800994 REPORTER_ASSERT(reporter, resultImg);
995
996 REPORTER_ASSERT(reporter, resultImg->width() == 20 && resultImg->height() == 20);
senorblanco4a243982015-11-25 07:06:55 -0800997}
998
robertphillips4418dba2016-03-07 12:45:14 -0800999DEF_TEST(ImageFilterMergeResultSize, reporter) {
robertphillips3e302272016-04-20 11:48:36 -07001000 test_imagefilter_merge_result_size(reporter, nullptr);
robertphillips4418dba2016-03-07 12:45:14 -08001001}
1002
1003#if SK_SUPPORT_GPU
egdanielab527a52016-06-28 08:07:26 -07001004DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterMergeResultSize_Gpu, reporter, ctxInfo) {
bsalomon8b7451a2016-05-11 06:33:06 -07001005 test_imagefilter_merge_result_size(reporter, ctxInfo.grContext());
robertphillips4418dba2016-03-07 12:45:14 -08001006}
1007#endif
1008
robertphillipsa8d7f0b2014-08-29 08:03:56 -07001009static void draw_blurred_rect(SkCanvas* canvas) {
senorblanco837f5322014-07-14 10:19:54 -07001010 SkPaint filterPaint;
1011 filterPaint.setColor(SK_ColorWHITE);
robertphillips6e7025a2016-04-04 04:31:25 -07001012 filterPaint.setImageFilter(SkBlurImageFilter::Make(SkIntToScalar(8), 0, nullptr));
halcanary96fcdcc2015-08-27 07:41:13 -07001013 canvas->saveLayer(nullptr, &filterPaint);
senorblanco837f5322014-07-14 10:19:54 -07001014 SkPaint whitePaint;
1015 whitePaint.setColor(SK_ColorWHITE);
1016 canvas->drawRect(SkRect::Make(SkIRect::MakeWH(4, 4)), whitePaint);
1017 canvas->restore();
1018}
1019
robertphillipsa8d7f0b2014-08-29 08:03:56 -07001020static void draw_picture_clipped(SkCanvas* canvas, const SkRect& clipRect, const SkPicture* picture) {
senorblanco837f5322014-07-14 10:19:54 -07001021 canvas->save();
1022 canvas->clipRect(clipRect);
1023 canvas->drawPicture(picture);
1024 canvas->restore();
1025}
1026
1027DEF_TEST(ImageFilterDrawTiledBlurRTree, reporter) {
1028 // Check that the blur filter when recorded with RTree acceleration,
1029 // and drawn tiled (with subsequent clip rects) exactly
1030 // matches the same filter drawn with without RTree acceleration.
1031 // This tests that the "bleed" from the blur into the otherwise-blank
1032 // tiles is correctly rendered.
1033 // Tests pass by not asserting.
1034
1035 int width = 16, height = 8;
1036 SkBitmap result1, result2;
1037 result1.allocN32Pixels(width, height);
1038 result2.allocN32Pixels(width, height);
1039 SkCanvas canvas1(result1);
1040 SkCanvas canvas2(result2);
1041 int tileSize = 8;
1042
1043 canvas1.clear(0);
1044 canvas2.clear(0);
1045
1046 SkRTreeFactory factory;
1047
1048 SkPictureRecorder recorder1, recorder2;
1049 // The only difference between these two pictures is that one has RTree aceleration.
mtklein3f3b3d02014-12-01 11:47:08 -08001050 SkCanvas* recordingCanvas1 = recorder1.beginRecording(SkIntToScalar(width),
1051 SkIntToScalar(height),
halcanary96fcdcc2015-08-27 07:41:13 -07001052 nullptr, 0);
mtklein3f3b3d02014-12-01 11:47:08 -08001053 SkCanvas* recordingCanvas2 = recorder2.beginRecording(SkIntToScalar(width),
1054 SkIntToScalar(height),
robertphillipsa8d7f0b2014-08-29 08:03:56 -07001055 &factory, 0);
1056 draw_blurred_rect(recordingCanvas1);
1057 draw_blurred_rect(recordingCanvas2);
reedca2622b2016-03-18 07:25:55 -07001058 sk_sp<SkPicture> picture1(recorder1.finishRecordingAsPicture());
1059 sk_sp<SkPicture> picture2(recorder2.finishRecordingAsPicture());
senorblanco837f5322014-07-14 10:19:54 -07001060 for (int y = 0; y < height; y += tileSize) {
1061 for (int x = 0; x < width; x += tileSize) {
1062 SkRect tileRect = SkRect::Make(SkIRect::MakeXYWH(x, y, tileSize, tileSize));
reedca2622b2016-03-18 07:25:55 -07001063 draw_picture_clipped(&canvas1, tileRect, picture1.get());
1064 draw_picture_clipped(&canvas2, tileRect, picture2.get());
senorblanco837f5322014-07-14 10:19:54 -07001065 }
1066 }
1067 for (int y = 0; y < height; y++) {
1068 int diffs = memcmp(result1.getAddr32(0, y), result2.getAddr32(0, y), result1.rowBytes());
1069 REPORTER_ASSERT(reporter, !diffs);
1070 if (diffs) {
1071 break;
1072 }
1073 }
1074}
1075
senorblanco@chromium.org91957432014-05-01 14:03:41 +00001076DEF_TEST(ImageFilterMatrixConvolution, reporter) {
1077 // Check that a 1x3 filter does not cause a spurious assert.
1078 SkScalar kernel[3] = {
1079 SkIntToScalar( 1), SkIntToScalar( 1), SkIntToScalar( 1),
1080 };
1081 SkISize kernelSize = SkISize::Make(1, 3);
1082 SkScalar gain = SK_Scalar1, bias = 0;
1083 SkIPoint kernelOffset = SkIPoint::Make(0, 0);
1084
robertphillipsef6a47b2016-04-08 08:01:20 -07001085 sk_sp<SkImageFilter> filter(SkMatrixConvolutionImageFilter::Make(
1086 kernelSize, kernel,
1087 gain, bias, kernelOffset,
1088 SkMatrixConvolutionImageFilter::kRepeat_TileMode,
1089 false, nullptr));
senorblanco@chromium.org91957432014-05-01 14:03:41 +00001090
1091 SkBitmap result;
1092 int width = 16, height = 16;
1093 result.allocN32Pixels(width, height);
1094 SkCanvas canvas(result);
1095 canvas.clear(0);
1096
1097 SkPaint paint;
robertphillipsef6a47b2016-04-08 08:01:20 -07001098 paint.setImageFilter(std::move(filter));
senorblanco@chromium.org91957432014-05-01 14:03:41 +00001099 SkRect rect = SkRect::Make(SkIRect::MakeWH(width, height));
1100 canvas.drawRect(rect, paint);
1101}
1102
senorblanco@chromium.org8c7372b2014-05-02 19:13:11 +00001103DEF_TEST(ImageFilterMatrixConvolutionBorder, reporter) {
1104 // Check that a filter with borders outside the target bounds
1105 // does not crash.
1106 SkScalar kernel[3] = {
1107 0, 0, 0,
1108 };
1109 SkISize kernelSize = SkISize::Make(3, 1);
1110 SkScalar gain = SK_Scalar1, bias = 0;
1111 SkIPoint kernelOffset = SkIPoint::Make(2, 0);
1112
robertphillipsef6a47b2016-04-08 08:01:20 -07001113 sk_sp<SkImageFilter> filter(SkMatrixConvolutionImageFilter::Make(
1114 kernelSize, kernel, gain, bias, kernelOffset,
1115 SkMatrixConvolutionImageFilter::kClamp_TileMode,
1116 true, nullptr));
senorblanco@chromium.org8c7372b2014-05-02 19:13:11 +00001117
1118 SkBitmap result;
1119
1120 int width = 10, height = 10;
1121 result.allocN32Pixels(width, height);
1122 SkCanvas canvas(result);
1123 canvas.clear(0);
1124
1125 SkPaint filterPaint;
robertphillipsef6a47b2016-04-08 08:01:20 -07001126 filterPaint.setImageFilter(std::move(filter));
senorblanco@chromium.org8c7372b2014-05-02 19:13:11 +00001127 SkRect bounds = SkRect::MakeWH(1, 10);
1128 SkRect rect = SkRect::Make(SkIRect::MakeWH(width, height));
1129 SkPaint rectPaint;
1130 canvas.saveLayer(&bounds, &filterPaint);
1131 canvas.drawRect(rect, rectPaint);
1132 canvas.restore();
1133}
1134
robertphillips3e302272016-04-20 11:48:36 -07001135static void test_big_kernel(skiatest::Reporter* reporter, GrContext* context) {
robertphillipsdada4dd2016-04-13 04:54:36 -07001136 // Check that a kernel that is too big for the GPU still works
1137 SkScalar identityKernel[49] = {
1138 0, 0, 0, 0, 0, 0, 0,
1139 0, 0, 0, 0, 0, 0, 0,
1140 0, 0, 0, 0, 0, 0, 0,
1141 0, 0, 0, 1, 0, 0, 0,
1142 0, 0, 0, 0, 0, 0, 0,
1143 0, 0, 0, 0, 0, 0, 0,
1144 0, 0, 0, 0, 0, 0, 0
1145 };
1146 SkISize kernelSize = SkISize::Make(7, 7);
1147 SkScalar gain = SK_Scalar1, bias = 0;
1148 SkIPoint kernelOffset = SkIPoint::Make(0, 0);
1149
1150 sk_sp<SkImageFilter> filter(SkMatrixConvolutionImageFilter::Make(
1151 kernelSize, identityKernel, gain, bias, kernelOffset,
1152 SkMatrixConvolutionImageFilter::kClamp_TileMode,
1153 true, nullptr));
1154
robertphillips3e302272016-04-20 11:48:36 -07001155 sk_sp<SkSpecialImage> srcImg(create_empty_special_image(context, 100));
robertphillipsdada4dd2016-04-13 04:54:36 -07001156 SkASSERT(srcImg);
1157
1158 SkIPoint offset;
brianosman2a75e5d2016-09-22 07:15:37 -07001159 SkImageFilter::OutputProperties noColorSpace(nullptr);
1160 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeWH(100, 100), nullptr, noColorSpace);
robertphillipsdada4dd2016-04-13 04:54:36 -07001161 sk_sp<SkSpecialImage> resultImg(filter->filterImage(srcImg.get(), ctx, &offset));
1162 REPORTER_ASSERT(reporter, resultImg);
1163 REPORTER_ASSERT(reporter, SkToBool(context) == resultImg->isTextureBacked());
1164 REPORTER_ASSERT(reporter, resultImg->width() == 100 && resultImg->height() == 100);
1165 REPORTER_ASSERT(reporter, offset.fX == 0 && offset.fY == 0);
1166}
1167
1168DEF_TEST(ImageFilterMatrixConvolutionBigKernel, reporter) {
robertphillips3e302272016-04-20 11:48:36 -07001169 test_big_kernel(reporter, nullptr);
robertphillipsdada4dd2016-04-13 04:54:36 -07001170}
1171
1172#if SK_SUPPORT_GPU
egdanielab527a52016-06-28 08:07:26 -07001173DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterMatrixConvolutionBigKernel_Gpu,
1174 reporter, ctxInfo) {
bsalomon8b7451a2016-05-11 06:33:06 -07001175 test_big_kernel(reporter, ctxInfo.grContext());
robertphillipsdada4dd2016-04-13 04:54:36 -07001176}
1177#endif
1178
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +00001179DEF_TEST(ImageFilterCropRect, reporter) {
robertphillips3e302272016-04-20 11:48:36 -07001180 test_crop_rects(reporter, nullptr);
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +00001181}
1182
robertphillips4418dba2016-03-07 12:45:14 -08001183#if SK_SUPPORT_GPU
bsalomon68d91342016-04-12 09:59:58 -07001184DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterCropRect_Gpu, reporter, ctxInfo) {
bsalomon8b7451a2016-05-11 06:33:06 -07001185 test_crop_rects(reporter, ctxInfo.grContext());
robertphillips4418dba2016-03-07 12:45:14 -08001186}
1187#endif
1188
tfarina9ea53f92014-06-24 06:50:39 -07001189DEF_TEST(ImageFilterMatrix, reporter) {
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +00001190 SkBitmap temp;
mike@reedtribe.orgdeee4962014-02-13 14:41:43 +00001191 temp.allocN32Pixels(100, 100);
robertphillips9a53fd72015-06-22 09:46:59 -07001192 SkCanvas canvas(temp);
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +00001193 canvas.scale(SkIntToScalar(2), SkIntToScalar(2));
1194
1195 SkMatrix expectedMatrix = canvas.getTotalMatrix();
1196
commit-bot@chromium.org5fb2ce32014-04-17 23:35:06 +00001197 SkRTreeFactory factory;
1198 SkPictureRecorder recorder;
1199 SkCanvas* recordingCanvas = recorder.beginRecording(100, 100, &factory, 0);
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +00001200
1201 SkPaint paint;
robertphillips43c2ad42016-04-04 05:05:11 -07001202 paint.setImageFilter(MatrixTestImageFilter::Make(reporter, expectedMatrix));
halcanary96fcdcc2015-08-27 07:41:13 -07001203 recordingCanvas->saveLayer(nullptr, &paint);
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +00001204 SkPaint solidPaint;
1205 solidPaint.setColor(0xFFFFFFFF);
1206 recordingCanvas->save();
1207 recordingCanvas->scale(SkIntToScalar(10), SkIntToScalar(10));
1208 recordingCanvas->drawRect(SkRect::Make(SkIRect::MakeWH(100, 100)), solidPaint);
1209 recordingCanvas->restore(); // scale
1210 recordingCanvas->restore(); // saveLayer
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +00001211
reedca2622b2016-03-18 07:25:55 -07001212 canvas.drawPicture(recorder.finishRecordingAsPicture());
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +00001213}
1214
senorblanco3d822c22014-07-30 14:49:31 -07001215DEF_TEST(ImageFilterCrossProcessPictureImageFilter, reporter) {
senorblanco@chromium.org97f5fc62014-05-30 20:50:56 +00001216 SkRTreeFactory factory;
1217 SkPictureRecorder recorder;
1218 SkCanvas* recordingCanvas = recorder.beginRecording(1, 1, &factory, 0);
1219
1220 // Create an SkPicture which simply draws a green 1x1 rectangle.
1221 SkPaint greenPaint;
1222 greenPaint.setColor(SK_ColorGREEN);
1223 recordingCanvas->drawRect(SkRect::Make(SkIRect::MakeWH(1, 1)), greenPaint);
reedca2622b2016-03-18 07:25:55 -07001224 sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture());
senorblanco@chromium.org97f5fc62014-05-30 20:50:56 +00001225
1226 // Wrap that SkPicture in an SkPictureImageFilter.
robertphillips5ff17b12016-03-28 13:13:42 -07001227 sk_sp<SkImageFilter> imageFilter(SkPictureImageFilter::Make(picture));
senorblanco@chromium.org97f5fc62014-05-30 20:50:56 +00001228
1229 // Check that SkPictureImageFilter successfully serializes its contained
1230 // SkPicture when not in cross-process mode.
1231 SkPaint paint;
robertphillips5ff17b12016-03-28 13:13:42 -07001232 paint.setImageFilter(imageFilter);
senorblanco@chromium.org97f5fc62014-05-30 20:50:56 +00001233 SkPictureRecorder outerRecorder;
1234 SkCanvas* outerCanvas = outerRecorder.beginRecording(1, 1, &factory, 0);
1235 SkPaint redPaintWithFilter;
1236 redPaintWithFilter.setColor(SK_ColorRED);
robertphillips5ff17b12016-03-28 13:13:42 -07001237 redPaintWithFilter.setImageFilter(imageFilter);
senorblanco@chromium.org97f5fc62014-05-30 20:50:56 +00001238 outerCanvas->drawRect(SkRect::Make(SkIRect::MakeWH(1, 1)), redPaintWithFilter);
reedca2622b2016-03-18 07:25:55 -07001239 sk_sp<SkPicture> outerPicture(outerRecorder.finishRecordingAsPicture());
senorblanco@chromium.org97f5fc62014-05-30 20:50:56 +00001240
1241 SkBitmap bitmap;
1242 bitmap.allocN32Pixels(1, 1);
robertphillips9a53fd72015-06-22 09:46:59 -07001243 SkCanvas canvas(bitmap);
senorblanco@chromium.org97f5fc62014-05-30 20:50:56 +00001244
1245 // The result here should be green, since the filter replaces the primitive's red interior.
1246 canvas.clear(0x0);
robertphillips9b14f262014-06-04 05:40:44 -07001247 canvas.drawPicture(outerPicture);
senorblanco@chromium.org97f5fc62014-05-30 20:50:56 +00001248 uint32_t pixel = *bitmap.getAddr32(0, 0);
1249 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1250
1251 // Check that, for now, SkPictureImageFilter does not serialize or
1252 // deserialize its contained picture when the filter is serialized
1253 // cross-process. Do this by "laundering" it through SkValidatingReadBuffer.
robertphillips12fa47d2016-04-08 16:28:09 -07001254 sk_sp<SkData> data(SkValidatingSerializeFlattenable(imageFilter.get()));
Mike Reed5e257172016-11-01 11:22:05 -04001255 sk_sp<SkImageFilter> unflattenedFilter = SkValidatingDeserializeImageFilter(data->data(),
1256 data->size());
senorblanco@chromium.org97f5fc62014-05-30 20:50:56 +00001257
1258 redPaintWithFilter.setImageFilter(unflattenedFilter);
1259 SkPictureRecorder crossProcessRecorder;
1260 SkCanvas* crossProcessCanvas = crossProcessRecorder.beginRecording(1, 1, &factory, 0);
1261 crossProcessCanvas->drawRect(SkRect::Make(SkIRect::MakeWH(1, 1)), redPaintWithFilter);
reedca2622b2016-03-18 07:25:55 -07001262 sk_sp<SkPicture> crossProcessPicture(crossProcessRecorder.finishRecordingAsPicture());
senorblanco@chromium.org97f5fc62014-05-30 20:50:56 +00001263
1264 canvas.clear(0x0);
robertphillips9b14f262014-06-04 05:40:44 -07001265 canvas.drawPicture(crossProcessPicture);
senorblanco@chromium.org97f5fc62014-05-30 20:50:56 +00001266 pixel = *bitmap.getAddr32(0, 0);
hendrikw446ee672015-06-16 09:28:37 -07001267 // If the security precautions are enabled, the result here should not be green, since the
1268 // filter draws nothing.
mtklein2afbe232016-02-07 12:23:10 -08001269 REPORTER_ASSERT(reporter, SkPicture::PictureIOSecurityPrecautionsEnabled()
hendrikw446ee672015-06-16 09:28:37 -07001270 ? pixel != SK_ColorGREEN : pixel == SK_ColorGREEN);
senorblanco@chromium.org97f5fc62014-05-30 20:50:56 +00001271}
1272
robertphillips3e302272016-04-20 11:48:36 -07001273static void test_clipped_picture_imagefilter(skiatest::Reporter* reporter, GrContext* context) {
reedca2622b2016-03-18 07:25:55 -07001274 sk_sp<SkPicture> picture;
senorblanco3d822c22014-07-30 14:49:31 -07001275
robertphillips4418dba2016-03-07 12:45:14 -08001276 {
1277 SkRTreeFactory factory;
1278 SkPictureRecorder recorder;
1279 SkCanvas* recordingCanvas = recorder.beginRecording(1, 1, &factory, 0);
1280
1281 // Create an SkPicture which simply draws a green 1x1 rectangle.
1282 SkPaint greenPaint;
1283 greenPaint.setColor(SK_ColorGREEN);
1284 recordingCanvas->drawRect(SkRect::Make(SkIRect::MakeWH(1, 1)), greenPaint);
reedca2622b2016-03-18 07:25:55 -07001285 picture = recorder.finishRecordingAsPicture();
robertphillips4418dba2016-03-07 12:45:14 -08001286 }
1287
robertphillips3e302272016-04-20 11:48:36 -07001288 sk_sp<SkSpecialImage> srcImg(create_empty_special_image(context, 2));
senorblanco3d822c22014-07-30 14:49:31 -07001289
robertphillips5ff17b12016-03-28 13:13:42 -07001290 sk_sp<SkImageFilter> imageFilter(SkPictureImageFilter::Make(picture));
senorblanco3d822c22014-07-30 14:49:31 -07001291
senorblanco3d822c22014-07-30 14:49:31 -07001292 SkIPoint offset;
brianosman2a75e5d2016-09-22 07:15:37 -07001293 SkImageFilter::OutputProperties noColorSpace(nullptr);
1294 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeXYWH(1, 1, 1, 1), nullptr, noColorSpace);
robertphillips4418dba2016-03-07 12:45:14 -08001295
robertphillips2302de92016-03-24 07:26:32 -07001296 sk_sp<SkSpecialImage> resultImage(imageFilter->filterImage(srcImg.get(), ctx, &offset));
robertphillips4418dba2016-03-07 12:45:14 -08001297 REPORTER_ASSERT(reporter, !resultImage);
senorblanco3d822c22014-07-30 14:49:31 -07001298}
1299
robertphillips4418dba2016-03-07 12:45:14 -08001300DEF_TEST(ImageFilterClippedPictureImageFilter, reporter) {
robertphillips3e302272016-04-20 11:48:36 -07001301 test_clipped_picture_imagefilter(reporter, nullptr);
robertphillips4418dba2016-03-07 12:45:14 -08001302}
1303
1304#if SK_SUPPORT_GPU
bsalomon68d91342016-04-12 09:59:58 -07001305DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterClippedPictureImageFilter_Gpu, reporter, ctxInfo) {
bsalomon8b7451a2016-05-11 06:33:06 -07001306 test_clipped_picture_imagefilter(reporter, ctxInfo.grContext());
robertphillips4418dba2016-03-07 12:45:14 -08001307}
1308#endif
1309
tfarina9ea53f92014-06-24 06:50:39 -07001310DEF_TEST(ImageFilterEmptySaveLayer, reporter) {
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001311 // Even when there's an empty saveLayer()/restore(), ensure that an image
1312 // filter or color filter which affects transparent black still draws.
1313
1314 SkBitmap bitmap;
1315 bitmap.allocN32Pixels(10, 10);
robertphillips9a53fd72015-06-22 09:46:59 -07001316 SkCanvas canvas(bitmap);
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001317
1318 SkRTreeFactory factory;
1319 SkPictureRecorder recorder;
1320
robertphillips5605b562016-04-05 11:50:42 -07001321 sk_sp<SkColorFilter> green(SkColorFilter::MakeModeFilter(SK_ColorGREEN,
Mike Reed7d954ad2016-10-28 15:42:34 -04001322 SkBlendMode::kSrc));
robertphillips5605b562016-04-05 11:50:42 -07001323 sk_sp<SkImageFilter> imageFilter(SkColorFilterImageFilter::Make(green, nullptr));
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001324 SkPaint imageFilterPaint;
robertphillips5605b562016-04-05 11:50:42 -07001325 imageFilterPaint.setImageFilter(std::move(imageFilter));
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001326 SkPaint colorFilterPaint;
reedd053ce92016-03-22 10:17:23 -07001327 colorFilterPaint.setColorFilter(green);
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001328
1329 SkRect bounds = SkRect::MakeWH(10, 10);
1330
1331 SkCanvas* recordingCanvas = recorder.beginRecording(10, 10, &factory, 0);
1332 recordingCanvas->saveLayer(&bounds, &imageFilterPaint);
1333 recordingCanvas->restore();
reedca2622b2016-03-18 07:25:55 -07001334 sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture());
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001335
1336 canvas.clear(0);
robertphillips9b14f262014-06-04 05:40:44 -07001337 canvas.drawPicture(picture);
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001338 uint32_t pixel = *bitmap.getAddr32(0, 0);
1339 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1340
1341 recordingCanvas = recorder.beginRecording(10, 10, &factory, 0);
halcanary96fcdcc2015-08-27 07:41:13 -07001342 recordingCanvas->saveLayer(nullptr, &imageFilterPaint);
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001343 recordingCanvas->restore();
reedca2622b2016-03-18 07:25:55 -07001344 sk_sp<SkPicture> picture2(recorder.finishRecordingAsPicture());
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001345
1346 canvas.clear(0);
robertphillips9b14f262014-06-04 05:40:44 -07001347 canvas.drawPicture(picture2);
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001348 pixel = *bitmap.getAddr32(0, 0);
1349 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1350
1351 recordingCanvas = recorder.beginRecording(10, 10, &factory, 0);
1352 recordingCanvas->saveLayer(&bounds, &colorFilterPaint);
1353 recordingCanvas->restore();
reedca2622b2016-03-18 07:25:55 -07001354 sk_sp<SkPicture> picture3(recorder.finishRecordingAsPicture());
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001355
1356 canvas.clear(0);
robertphillips9b14f262014-06-04 05:40:44 -07001357 canvas.drawPicture(picture3);
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001358 pixel = *bitmap.getAddr32(0, 0);
1359 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1360}
1361
robertphillips9a53fd72015-06-22 09:46:59 -07001362static void test_huge_blur(SkCanvas* canvas, skiatest::Reporter* reporter) {
senorblanco@chromium.org09843fd2014-03-24 20:50:59 +00001363 SkBitmap bitmap;
1364 bitmap.allocN32Pixels(100, 100);
1365 bitmap.eraseARGB(0, 0, 0, 0);
1366
1367 // Check that a blur with an insane radius does not crash or assert.
senorblanco@chromium.org09843fd2014-03-24 20:50:59 +00001368 SkPaint paint;
robertphillips6e7025a2016-04-04 04:31:25 -07001369 paint.setImageFilter(SkBlurImageFilter::Make(SkIntToScalar(1<<30),
1370 SkIntToScalar(1<<30),
1371 nullptr));
reedda420b92015-12-16 08:38:15 -08001372 canvas->drawBitmap(bitmap, 0, 0, &paint);
senorblanco@chromium.org09843fd2014-03-24 20:50:59 +00001373}
1374
1375DEF_TEST(HugeBlurImageFilter, reporter) {
1376 SkBitmap temp;
1377 temp.allocN32Pixels(100, 100);
robertphillips9a53fd72015-06-22 09:46:59 -07001378 SkCanvas canvas(temp);
1379 test_huge_blur(&canvas, reporter);
senorblanco@chromium.org09843fd2014-03-24 20:50:59 +00001380}
1381
senorblanco21a465d2016-04-11 11:58:39 -07001382DEF_TEST(ImageFilterMatrixConvolutionSanityTest, reporter) {
senorblanco3a495202014-09-29 07:57:20 -07001383 SkScalar kernel[1] = { 0 };
1384 SkScalar gain = SK_Scalar1, bias = 0;
1385 SkIPoint kernelOffset = SkIPoint::Make(1, 1);
1386
halcanary96fcdcc2015-08-27 07:41:13 -07001387 // Check that an enormous (non-allocatable) kernel gives a nullptr filter.
robertphillipsef6a47b2016-04-08 08:01:20 -07001388 sk_sp<SkImageFilter> conv(SkMatrixConvolutionImageFilter::Make(
senorblanco3a495202014-09-29 07:57:20 -07001389 SkISize::Make(1<<30, 1<<30),
1390 kernel,
1391 gain,
1392 bias,
1393 kernelOffset,
1394 SkMatrixConvolutionImageFilter::kRepeat_TileMode,
robertphillipsef6a47b2016-04-08 08:01:20 -07001395 false,
1396 nullptr));
senorblanco3a495202014-09-29 07:57:20 -07001397
halcanary96fcdcc2015-08-27 07:41:13 -07001398 REPORTER_ASSERT(reporter, nullptr == conv.get());
senorblanco3a495202014-09-29 07:57:20 -07001399
halcanary96fcdcc2015-08-27 07:41:13 -07001400 // Check that a nullptr kernel gives a nullptr filter.
robertphillipsef6a47b2016-04-08 08:01:20 -07001401 conv = SkMatrixConvolutionImageFilter::Make(
senorblanco3a495202014-09-29 07:57:20 -07001402 SkISize::Make(1, 1),
halcanary96fcdcc2015-08-27 07:41:13 -07001403 nullptr,
senorblanco3a495202014-09-29 07:57:20 -07001404 gain,
1405 bias,
1406 kernelOffset,
1407 SkMatrixConvolutionImageFilter::kRepeat_TileMode,
robertphillipsef6a47b2016-04-08 08:01:20 -07001408 false,
1409 nullptr);
senorblanco3a495202014-09-29 07:57:20 -07001410
halcanary96fcdcc2015-08-27 07:41:13 -07001411 REPORTER_ASSERT(reporter, nullptr == conv.get());
senorblanco3a495202014-09-29 07:57:20 -07001412
halcanary96fcdcc2015-08-27 07:41:13 -07001413 // Check that a kernel width < 1 gives a nullptr filter.
robertphillipsef6a47b2016-04-08 08:01:20 -07001414 conv = SkMatrixConvolutionImageFilter::Make(
senorblanco3a495202014-09-29 07:57:20 -07001415 SkISize::Make(0, 1),
1416 kernel,
1417 gain,
1418 bias,
1419 kernelOffset,
1420 SkMatrixConvolutionImageFilter::kRepeat_TileMode,
robertphillipsef6a47b2016-04-08 08:01:20 -07001421 false,
1422 nullptr);
senorblanco3a495202014-09-29 07:57:20 -07001423
halcanary96fcdcc2015-08-27 07:41:13 -07001424 REPORTER_ASSERT(reporter, nullptr == conv.get());
senorblanco3a495202014-09-29 07:57:20 -07001425
halcanary96fcdcc2015-08-27 07:41:13 -07001426 // Check that kernel height < 1 gives a nullptr filter.
robertphillipsef6a47b2016-04-08 08:01:20 -07001427 conv = SkMatrixConvolutionImageFilter::Make(
senorblanco3a495202014-09-29 07:57:20 -07001428 SkISize::Make(1, -1),
1429 kernel,
1430 gain,
1431 bias,
1432 kernelOffset,
1433 SkMatrixConvolutionImageFilter::kRepeat_TileMode,
robertphillipsef6a47b2016-04-08 08:01:20 -07001434 false,
1435 nullptr);
senorblanco3a495202014-09-29 07:57:20 -07001436
halcanary96fcdcc2015-08-27 07:41:13 -07001437 REPORTER_ASSERT(reporter, nullptr == conv.get());
senorblanco3a495202014-09-29 07:57:20 -07001438}
1439
Mike Reedf1942192017-07-21 14:24:29 -04001440static void test_xfermode_cropped_input(SkSurface* surf, skiatest::Reporter* reporter) {
1441 auto canvas = surf->getCanvas();
robertphillips9a53fd72015-06-22 09:46:59 -07001442 canvas->clear(0);
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001443
1444 SkBitmap bitmap;
1445 bitmap.allocN32Pixels(1, 1);
1446 bitmap.eraseARGB(255, 255, 255, 255);
1447
robertphillips5605b562016-04-05 11:50:42 -07001448 sk_sp<SkColorFilter> green(SkColorFilter::MakeModeFilter(SK_ColorGREEN,
Mike Reed7d954ad2016-10-28 15:42:34 -04001449 SkBlendMode::kSrcIn));
robertphillips5605b562016-04-05 11:50:42 -07001450 sk_sp<SkImageFilter> greenFilter(SkColorFilterImageFilter::Make(green, nullptr));
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001451 SkImageFilter::CropRect cropRect(SkRect::MakeEmpty());
robertphillips5605b562016-04-05 11:50:42 -07001452 sk_sp<SkImageFilter> croppedOut(SkColorFilterImageFilter::Make(green, nullptr, &cropRect));
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001453
1454 // Check that an xfermode image filter whose input has been cropped out still draws the other
1455 // input. Also check that drawing with both inputs cropped out doesn't cause a GPU warning.
reed374772b2016-10-05 17:33:02 -07001456 SkBlendMode mode = SkBlendMode::kSrcOver;
robertphillips8c0326d2016-04-05 12:48:34 -07001457 sk_sp<SkImageFilter> xfermodeNoFg(SkXfermodeImageFilter::Make(mode, greenFilter,
1458 croppedOut, nullptr));
1459 sk_sp<SkImageFilter> xfermodeNoBg(SkXfermodeImageFilter::Make(mode, croppedOut,
1460 greenFilter, nullptr));
1461 sk_sp<SkImageFilter> xfermodeNoFgNoBg(SkXfermodeImageFilter::Make(mode, croppedOut,
1462 croppedOut, nullptr));
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001463
1464 SkPaint paint;
robertphillips8c0326d2016-04-05 12:48:34 -07001465 paint.setImageFilter(std::move(xfermodeNoFg));
reedda420b92015-12-16 08:38:15 -08001466 canvas->drawBitmap(bitmap, 0, 0, &paint); // drawSprite
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001467
1468 uint32_t pixel;
kkinnunena9d9a392015-03-06 07:16:00 -08001469 SkImageInfo info = SkImageInfo::Make(1, 1, kBGRA_8888_SkColorType, kUnpremul_SkAlphaType);
Mike Reedf1942192017-07-21 14:24:29 -04001470 surf->readPixels(info, &pixel, 4, 0, 0);
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001471 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1472
robertphillips8c0326d2016-04-05 12:48:34 -07001473 paint.setImageFilter(std::move(xfermodeNoBg));
reedda420b92015-12-16 08:38:15 -08001474 canvas->drawBitmap(bitmap, 0, 0, &paint); // drawSprite
Mike Reedf1942192017-07-21 14:24:29 -04001475 surf->readPixels(info, &pixel, 4, 0, 0);
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001476 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1477
robertphillips8c0326d2016-04-05 12:48:34 -07001478 paint.setImageFilter(std::move(xfermodeNoFgNoBg));
reedda420b92015-12-16 08:38:15 -08001479 canvas->drawBitmap(bitmap, 0, 0, &paint); // drawSprite
Mike Reedf1942192017-07-21 14:24:29 -04001480 surf->readPixels(info, &pixel, 4, 0, 0);
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001481 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1482}
1483
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001484DEF_TEST(ImageFilterNestedSaveLayer, reporter) {
1485 SkBitmap temp;
1486 temp.allocN32Pixels(50, 50);
robertphillips9a53fd72015-06-22 09:46:59 -07001487 SkCanvas canvas(temp);
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001488 canvas.clear(0x0);
1489
1490 SkBitmap bitmap;
1491 bitmap.allocN32Pixels(10, 10);
1492 bitmap.eraseColor(SK_ColorGREEN);
1493
1494 SkMatrix matrix;
1495 matrix.setScale(SkIntToScalar(2), SkIntToScalar(2));
1496 matrix.postTranslate(SkIntToScalar(-20), SkIntToScalar(-20));
robertphillipsae8c9332016-04-05 15:09:00 -07001497 sk_sp<SkImageFilter> matrixFilter(
1498 SkImageFilter::MakeMatrixFilter(matrix, kLow_SkFilterQuality, nullptr));
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001499
1500 // Test that saveLayer() with a filter nested inside another saveLayer() applies the
1501 // correct offset to the filter matrix.
1502 SkRect bounds1 = SkRect::MakeXYWH(10, 10, 30, 30);
halcanary96fcdcc2015-08-27 07:41:13 -07001503 canvas.saveLayer(&bounds1, nullptr);
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001504 SkPaint filterPaint;
robertphillipsae8c9332016-04-05 15:09:00 -07001505 filterPaint.setImageFilter(std::move(matrixFilter));
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001506 SkRect bounds2 = SkRect::MakeXYWH(20, 20, 10, 10);
1507 canvas.saveLayer(&bounds2, &filterPaint);
1508 SkPaint greenPaint;
1509 greenPaint.setColor(SK_ColorGREEN);
1510 canvas.drawRect(bounds2, greenPaint);
1511 canvas.restore();
1512 canvas.restore();
1513 SkPaint strokePaint;
1514 strokePaint.setStyle(SkPaint::kStroke_Style);
1515 strokePaint.setColor(SK_ColorRED);
1516
kkinnunena9d9a392015-03-06 07:16:00 -08001517 SkImageInfo info = SkImageInfo::Make(1, 1, kBGRA_8888_SkColorType, kUnpremul_SkAlphaType);
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001518 uint32_t pixel;
Mike Reedf1942192017-07-21 14:24:29 -04001519 temp.readPixels(info, &pixel, 4, 25, 25);
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001520 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1521
1522 // Test that drawSprite() with a filter nested inside a saveLayer() applies the
1523 // correct offset to the filter matrix.
1524 canvas.clear(0x0);
Mike Reedf1942192017-07-21 14:24:29 -04001525 temp.readPixels(info, &pixel, 4, 25, 25);
halcanary96fcdcc2015-08-27 07:41:13 -07001526 canvas.saveLayer(&bounds1, nullptr);
reedda420b92015-12-16 08:38:15 -08001527 canvas.drawBitmap(bitmap, 20, 20, &filterPaint); // drawSprite
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001528 canvas.restore();
1529
Mike Reedf1942192017-07-21 14:24:29 -04001530 temp.readPixels(info, &pixel, 4, 25, 25);
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001531 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1532}
1533
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001534DEF_TEST(XfermodeImageFilterCroppedInput, reporter) {
Mike Reedf1942192017-07-21 14:24:29 -04001535 test_xfermode_cropped_input(SkSurface::MakeRasterN32Premul(100, 100).get(), reporter);
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001536}
senorblanco@chromium.org09843fd2014-03-24 20:50:59 +00001537
robertphillips3e302272016-04-20 11:48:36 -07001538static void test_composed_imagefilter_offset(skiatest::Reporter* reporter, GrContext* context) {
1539 sk_sp<SkSpecialImage> srcImg(create_empty_special_image(context, 100));
ajuma5788faa2015-02-13 09:05:47 -08001540
1541 SkImageFilter::CropRect cropRect(SkRect::MakeXYWH(1, 0, 20, 20));
robertphillips51a315e2016-03-31 09:05:49 -07001542 sk_sp<SkImageFilter> offsetFilter(SkOffsetImageFilter::Make(0, 0, nullptr, &cropRect));
robertphillips6e7025a2016-04-04 04:31:25 -07001543 sk_sp<SkImageFilter> blurFilter(SkBlurImageFilter::Make(SK_Scalar1, SK_Scalar1,
1544 nullptr, &cropRect));
robertphillips491fb172016-03-30 12:32:58 -07001545 sk_sp<SkImageFilter> composedFilter(SkComposeImageFilter::Make(std::move(blurFilter),
1546 std::move(offsetFilter)));
ajuma5788faa2015-02-13 09:05:47 -08001547 SkIPoint offset;
brianosman2a75e5d2016-09-22 07:15:37 -07001548 SkImageFilter::OutputProperties noColorSpace(nullptr);
1549 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeWH(100, 100), nullptr, noColorSpace);
robertphillips4418dba2016-03-07 12:45:14 -08001550
robertphillips2302de92016-03-24 07:26:32 -07001551 sk_sp<SkSpecialImage> resultImg(composedFilter->filterImage(srcImg.get(), ctx, &offset));
robertphillips4418dba2016-03-07 12:45:14 -08001552 REPORTER_ASSERT(reporter, resultImg);
ajuma5788faa2015-02-13 09:05:47 -08001553 REPORTER_ASSERT(reporter, offset.fX == 1 && offset.fY == 0);
1554}
1555
robertphillips4418dba2016-03-07 12:45:14 -08001556DEF_TEST(ComposedImageFilterOffset, reporter) {
robertphillips3e302272016-04-20 11:48:36 -07001557 test_composed_imagefilter_offset(reporter, nullptr);
robertphillips4418dba2016-03-07 12:45:14 -08001558}
1559
1560#if SK_SUPPORT_GPU
bsalomon68d91342016-04-12 09:59:58 -07001561DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ComposedImageFilterOffset_Gpu, reporter, ctxInfo) {
bsalomon8b7451a2016-05-11 06:33:06 -07001562 test_composed_imagefilter_offset(reporter, ctxInfo.grContext());
robertphillips4418dba2016-03-07 12:45:14 -08001563}
1564#endif
1565
robertphillips3e302272016-04-20 11:48:36 -07001566static void test_composed_imagefilter_bounds(skiatest::Reporter* reporter, GrContext* context) {
jbroman17a65202016-03-21 08:38:58 -07001567 // The bounds passed to the inner filter must be filtered by the outer
1568 // filter, so that the inner filter produces the pixels that the outer
1569 // filter requires as input. This matters if the outer filter moves pixels.
1570 // Here, accounting for the outer offset is necessary so that the green
1571 // pixels of the picture are not clipped.
1572
1573 SkPictureRecorder recorder;
1574 SkCanvas* recordingCanvas = recorder.beginRecording(SkRect::MakeWH(200, 100));
1575 recordingCanvas->clipRect(SkRect::MakeXYWH(100, 0, 100, 100));
1576 recordingCanvas->clear(SK_ColorGREEN);
robertphillips491fb172016-03-30 12:32:58 -07001577 sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture());
robertphillips5ff17b12016-03-28 13:13:42 -07001578 sk_sp<SkImageFilter> pictureFilter(SkPictureImageFilter::Make(picture));
jbroman17a65202016-03-21 08:38:58 -07001579 SkImageFilter::CropRect cropRect(SkRect::MakeWH(100, 100));
robertphillips51a315e2016-03-31 09:05:49 -07001580 sk_sp<SkImageFilter> offsetFilter(SkOffsetImageFilter::Make(-100, 0, nullptr, &cropRect));
robertphillips491fb172016-03-30 12:32:58 -07001581 sk_sp<SkImageFilter> composedFilter(SkComposeImageFilter::Make(std::move(offsetFilter),
1582 std::move(pictureFilter)));
jbroman17a65202016-03-21 08:38:58 -07001583
robertphillips3e302272016-04-20 11:48:36 -07001584 sk_sp<SkSpecialImage> sourceImage(create_empty_special_image(context, 100));
brianosman2a75e5d2016-09-22 07:15:37 -07001585 SkImageFilter::OutputProperties noColorSpace(nullptr);
1586 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeWH(100, 100), nullptr, noColorSpace);
jbroman17a65202016-03-21 08:38:58 -07001587 SkIPoint offset;
1588 sk_sp<SkSpecialImage> result(composedFilter->filterImage(sourceImage.get(), ctx, &offset));
1589 REPORTER_ASSERT(reporter, offset.isZero());
1590 REPORTER_ASSERT(reporter, result);
1591 REPORTER_ASSERT(reporter, result->subset().size() == SkISize::Make(100, 100));
1592
1593 SkBitmap resultBM;
robertphillips64612512016-04-08 12:10:42 -07001594 REPORTER_ASSERT(reporter, result->getROPixels(&resultBM));
jbroman17a65202016-03-21 08:38:58 -07001595 REPORTER_ASSERT(reporter, resultBM.getColor(50, 50) == SK_ColorGREEN);
1596}
1597
1598DEF_TEST(ComposedImageFilterBounds, reporter) {
robertphillips3e302272016-04-20 11:48:36 -07001599 test_composed_imagefilter_bounds(reporter, nullptr);
jbroman17a65202016-03-21 08:38:58 -07001600}
1601
1602#if SK_SUPPORT_GPU
egdanielab527a52016-06-28 08:07:26 -07001603DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ComposedImageFilterBounds_Gpu, reporter, ctxInfo) {
bsalomon8b7451a2016-05-11 06:33:06 -07001604 test_composed_imagefilter_bounds(reporter, ctxInfo.grContext());
jbroman17a65202016-03-21 08:38:58 -07001605}
1606#endif
1607
robertphillips3e302272016-04-20 11:48:36 -07001608static void test_partial_crop_rect(skiatest::Reporter* reporter, GrContext* context) {
1609 sk_sp<SkSpecialImage> srcImg(create_empty_special_image(context, 100));
senorblanco24d2a7b2015-07-13 10:27:05 -07001610
1611 SkImageFilter::CropRect cropRect(SkRect::MakeXYWH(100, 0, 20, 30),
senorblancoed7cf272015-07-16 15:19:11 -07001612 SkImageFilter::CropRect::kHasWidth_CropEdge | SkImageFilter::CropRect::kHasHeight_CropEdge);
robertphillips5605b562016-04-05 11:50:42 -07001613 sk_sp<SkImageFilter> filter(make_grayscale(nullptr, &cropRect));
senorblanco24d2a7b2015-07-13 10:27:05 -07001614 SkIPoint offset;
brianosman2a75e5d2016-09-22 07:15:37 -07001615 SkImageFilter::OutputProperties noColorSpace(nullptr);
1616 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeWH(100, 100), nullptr, noColorSpace);
robertphillips4418dba2016-03-07 12:45:14 -08001617
robertphillips2302de92016-03-24 07:26:32 -07001618 sk_sp<SkSpecialImage> resultImg(filter->filterImage(srcImg.get(), ctx, &offset));
robertphillips4418dba2016-03-07 12:45:14 -08001619 REPORTER_ASSERT(reporter, resultImg);
1620
senorblanco24d2a7b2015-07-13 10:27:05 -07001621 REPORTER_ASSERT(reporter, offset.fX == 0);
1622 REPORTER_ASSERT(reporter, offset.fY == 0);
robertphillips4418dba2016-03-07 12:45:14 -08001623 REPORTER_ASSERT(reporter, resultImg->width() == 20);
1624 REPORTER_ASSERT(reporter, resultImg->height() == 30);
senorblanco24d2a7b2015-07-13 10:27:05 -07001625}
1626
senorblanco21a465d2016-04-11 11:58:39 -07001627DEF_TEST(ImageFilterPartialCropRect, reporter) {
robertphillips3e302272016-04-20 11:48:36 -07001628 test_partial_crop_rect(reporter, nullptr);
robertphillips4418dba2016-03-07 12:45:14 -08001629}
1630
1631#if SK_SUPPORT_GPU
bsalomon68d91342016-04-12 09:59:58 -07001632DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterPartialCropRect_Gpu, reporter, ctxInfo) {
bsalomon8b7451a2016-05-11 06:33:06 -07001633 test_partial_crop_rect(reporter, ctxInfo.grContext());
robertphillips4418dba2016-03-07 12:45:14 -08001634}
1635#endif
1636
senorblanco0abdf762015-08-20 11:10:41 -07001637DEF_TEST(ImageFilterCanComputeFastBounds, reporter) {
1638
robertphillips12fa47d2016-04-08 16:28:09 -07001639 {
1640 SkPoint3 location = SkPoint3::Make(0, 0, SK_Scalar1);
1641 sk_sp<SkImageFilter> lighting(SkLightingImageFilter::MakePointLitDiffuse(location,
1642 SK_ColorGREEN,
1643 0, 0, nullptr));
1644 REPORTER_ASSERT(reporter, !lighting->canComputeFastBounds());
1645 }
senorblanco0abdf762015-08-20 11:10:41 -07001646
senorblanco0abdf762015-08-20 11:10:41 -07001647 {
robertphillips6e7025a2016-04-04 04:31:25 -07001648 sk_sp<SkImageFilter> gray(make_grayscale(nullptr, nullptr));
1649 REPORTER_ASSERT(reporter, gray->canComputeFastBounds());
1650 {
1651 SkColorFilter* grayCF;
1652 REPORTER_ASSERT(reporter, gray->asAColorFilter(&grayCF));
1653 REPORTER_ASSERT(reporter, !grayCF->affectsTransparentBlack());
1654 grayCF->unref();
1655 }
1656 REPORTER_ASSERT(reporter, gray->canComputeFastBounds());
1657
1658 sk_sp<SkImageFilter> grayBlur(SkBlurImageFilter::Make(SK_Scalar1, SK_Scalar1,
1659 std::move(gray)));
1660 REPORTER_ASSERT(reporter, grayBlur->canComputeFastBounds());
senorblanco0abdf762015-08-20 11:10:41 -07001661 }
senorblanco0abdf762015-08-20 11:10:41 -07001662
robertphillips6e7025a2016-04-04 04:31:25 -07001663 {
1664 SkScalar greenMatrix[20] = { 0, 0, 0, 0, 0,
1665 0, 0, 0, 0, 1,
1666 0, 0, 0, 0, 0,
1667 0, 0, 0, 0, 1 };
1668 sk_sp<SkColorFilter> greenCF(SkColorFilter::MakeMatrixFilterRowMajor255(greenMatrix));
robertphillips5605b562016-04-05 11:50:42 -07001669 sk_sp<SkImageFilter> green(SkColorFilterImageFilter::Make(greenCF, nullptr));
senorblanco0abdf762015-08-20 11:10:41 -07001670
robertphillips6e7025a2016-04-04 04:31:25 -07001671 REPORTER_ASSERT(reporter, greenCF->affectsTransparentBlack());
1672 REPORTER_ASSERT(reporter, !green->canComputeFastBounds());
senorblanco0abdf762015-08-20 11:10:41 -07001673
robertphillips6e7025a2016-04-04 04:31:25 -07001674 sk_sp<SkImageFilter> greenBlur(SkBlurImageFilter::Make(SK_Scalar1, SK_Scalar1,
1675 std::move(green)));
1676 REPORTER_ASSERT(reporter, !greenBlur->canComputeFastBounds());
1677 }
senorblanco0abdf762015-08-20 11:10:41 -07001678
1679 uint8_t allOne[256], identity[256];
1680 for (int i = 0; i < 256; ++i) {
1681 identity[i] = i;
1682 allOne[i] = 255;
1683 }
1684
robertphillips5605b562016-04-05 11:50:42 -07001685 sk_sp<SkColorFilter> identityCF(SkTableColorFilter::MakeARGB(identity, identity,
1686 identity, allOne));
1687 sk_sp<SkImageFilter> identityFilter(SkColorFilterImageFilter::Make(identityCF, nullptr));
senorblanco0abdf762015-08-20 11:10:41 -07001688 REPORTER_ASSERT(reporter, !identityCF->affectsTransparentBlack());
1689 REPORTER_ASSERT(reporter, identityFilter->canComputeFastBounds());
1690
robertphillips5605b562016-04-05 11:50:42 -07001691 sk_sp<SkColorFilter> forceOpaqueCF(SkTableColorFilter::MakeARGB(allOne, identity,
1692 identity, identity));
1693 sk_sp<SkImageFilter> forceOpaque(SkColorFilterImageFilter::Make(forceOpaqueCF, nullptr));
senorblanco0abdf762015-08-20 11:10:41 -07001694 REPORTER_ASSERT(reporter, forceOpaqueCF->affectsTransparentBlack());
1695 REPORTER_ASSERT(reporter, !forceOpaque->canComputeFastBounds());
1696}
1697
fmalitacd56f812015-09-14 13:31:18 -07001698// Verify that SkImageSource survives serialization
1699DEF_TEST(ImageFilterImageSourceSerialization, reporter) {
reede8f30622016-03-23 18:59:25 -07001700 auto surface(SkSurface::MakeRasterN32Premul(10, 10));
fmalitacd56f812015-09-14 13:31:18 -07001701 surface->getCanvas()->clear(SK_ColorGREEN);
reed9ce9d672016-03-17 10:51:11 -07001702 sk_sp<SkImage> image(surface->makeImageSnapshot());
robertphillips549c8992016-04-01 09:28:51 -07001703 sk_sp<SkImageFilter> filter(SkImageSource::Make(std::move(image)));
fmalitacd56f812015-09-14 13:31:18 -07001704
robertphillips549c8992016-04-01 09:28:51 -07001705 sk_sp<SkData> data(SkValidatingSerializeFlattenable(filter.get()));
Mike Reed5e257172016-11-01 11:22:05 -04001706 sk_sp<SkImageFilter> unflattenedFilter = SkValidatingDeserializeImageFilter(data->data(),
1707 data->size());
fmalitacd56f812015-09-14 13:31:18 -07001708 REPORTER_ASSERT(reporter, unflattenedFilter);
1709
1710 SkBitmap bm;
1711 bm.allocN32Pixels(10, 10);
fmalita23cb88c2015-09-15 06:56:23 -07001712 bm.eraseColor(SK_ColorBLUE);
fmalitacd56f812015-09-14 13:31:18 -07001713 SkPaint paint;
1714 paint.setColor(SK_ColorRED);
1715 paint.setImageFilter(unflattenedFilter);
1716
1717 SkCanvas canvas(bm);
1718 canvas.drawRect(SkRect::MakeWH(10, 10), paint);
1719 REPORTER_ASSERT(reporter, *bm.getAddr32(0, 0) == SkPreMultiplyColor(SK_ColorGREEN));
1720}
1721
Leon Scroggins III4cdbf602017-09-28 14:33:57 -04001722DEF_TEST(ImageFilterImageSourceUninitialized, r) {
1723 sk_sp<SkData> data(GetResourceAsData("crbug769134.fil"));
1724 if (!data) {
1725 return;
1726 }
1727 sk_sp<SkImageFilter> unflattenedFilter = SkValidatingDeserializeImageFilter(data->data(),
1728 data->size());
1729 // This will fail. More importantly, msan will verify that we did not
1730 // compare against uninitialized memory.
1731 REPORTER_ASSERT(r, !unflattenedFilter);
1732}
1733
bsalomon45eefcf2016-01-05 08:39:28 -08001734static void test_large_blur_input(skiatest::Reporter* reporter, SkCanvas* canvas) {
1735 SkBitmap largeBmp;
1736 int largeW = 5000;
1737 int largeH = 5000;
1738#if SK_SUPPORT_GPU
1739 // If we're GPU-backed make the bitmap too large to be converted into a texture.
1740 if (GrContext* ctx = canvas->getGrContext()) {
1741 largeW = ctx->caps()->maxTextureSize() + 1;
1742 }
1743#endif
1744
1745 largeBmp.allocN32Pixels(largeW, largeH);
mtklein2afbe232016-02-07 12:23:10 -08001746 largeBmp.eraseColor(0);
bsalomon45eefcf2016-01-05 08:39:28 -08001747 if (!largeBmp.getPixels()) {
1748 ERRORF(reporter, "Failed to allocate large bmp.");
1749 return;
1750 }
1751
reed9ce9d672016-03-17 10:51:11 -07001752 sk_sp<SkImage> largeImage(SkImage::MakeFromBitmap(largeBmp));
bsalomon45eefcf2016-01-05 08:39:28 -08001753 if (!largeImage) {
1754 ERRORF(reporter, "Failed to create large image.");
1755 return;
1756 }
1757
robertphillips549c8992016-04-01 09:28:51 -07001758 sk_sp<SkImageFilter> largeSource(SkImageSource::Make(std::move(largeImage)));
bsalomon45eefcf2016-01-05 08:39:28 -08001759 if (!largeSource) {
1760 ERRORF(reporter, "Failed to create large SkImageSource.");
1761 return;
1762 }
1763
robertphillips6e7025a2016-04-04 04:31:25 -07001764 sk_sp<SkImageFilter> blur(SkBlurImageFilter::Make(10.f, 10.f, std::move(largeSource)));
bsalomon45eefcf2016-01-05 08:39:28 -08001765 if (!blur) {
1766 ERRORF(reporter, "Failed to create SkBlurImageFilter.");
1767 return;
1768 }
1769
1770 SkPaint paint;
robertphillips549c8992016-04-01 09:28:51 -07001771 paint.setImageFilter(std::move(blur));
bsalomon45eefcf2016-01-05 08:39:28 -08001772
1773 // This should not crash (http://crbug.com/570479).
1774 canvas->drawRect(SkRect::MakeIWH(largeW, largeH), paint);
1775}
1776
senorblanco21a465d2016-04-11 11:58:39 -07001777DEF_TEST(ImageFilterBlurLargeImage, reporter) {
reede8f30622016-03-23 18:59:25 -07001778 auto surface(SkSurface::MakeRaster(SkImageInfo::MakeN32Premul(100, 100)));
bsalomon45eefcf2016-01-05 08:39:28 -08001779 test_large_blur_input(reporter, surface->getCanvas());
1780}
1781
senorblanco5878dbd2016-05-19 14:50:29 -07001782static void test_make_with_filter(skiatest::Reporter* reporter, GrContext* context) {
Robert Phillipsa5fdc972017-02-18 16:58:09 -05001783 sk_sp<SkSurface> surface(create_surface(context, 192, 128));
senorblanco5878dbd2016-05-19 14:50:29 -07001784 surface->getCanvas()->clear(SK_ColorRED);
1785 SkPaint bluePaint;
1786 bluePaint.setColor(SK_ColorBLUE);
1787 SkIRect subset = SkIRect::MakeXYWH(25, 20, 50, 50);
1788 surface->getCanvas()->drawRect(SkRect::Make(subset), bluePaint);
1789 sk_sp<SkImage> sourceImage = surface->makeImageSnapshot();
1790
1791 sk_sp<SkImageFilter> filter = make_grayscale(nullptr, nullptr);
1792 SkIRect clipBounds = SkIRect::MakeXYWH(30, 35, 100, 100);
1793 SkIRect outSubset;
1794 SkIPoint offset;
1795 sk_sp<SkImage> result;
1796
1797 result = sourceImage->makeWithFilter(nullptr, subset, clipBounds, &outSubset, &offset);
1798 REPORTER_ASSERT(reporter, !result);
1799
1800 result = sourceImage->makeWithFilter(filter.get(), subset, clipBounds, nullptr, &offset);
1801 REPORTER_ASSERT(reporter, !result);
1802
1803 result = sourceImage->makeWithFilter(filter.get(), subset, clipBounds, &outSubset, nullptr);
1804 REPORTER_ASSERT(reporter, !result);
1805
1806 SkIRect bigSubset = SkIRect::MakeXYWH(-10000, -10000, 20000, 20000);
1807 result = sourceImage->makeWithFilter(filter.get(), bigSubset, clipBounds, &outSubset, &offset);
1808 REPORTER_ASSERT(reporter, !result);
1809
1810 SkIRect empty = SkIRect::MakeEmpty();
1811 result = sourceImage->makeWithFilter(filter.get(), empty, clipBounds, &outSubset, &offset);
1812 REPORTER_ASSERT(reporter, !result);
1813
1814 result = sourceImage->makeWithFilter(filter.get(), subset, empty, &outSubset, &offset);
1815 REPORTER_ASSERT(reporter, !result);
1816
1817 SkIRect leftField = SkIRect::MakeXYWH(-1000, 0, 100, 100);
1818 result = sourceImage->makeWithFilter(filter.get(), subset, leftField, &outSubset, &offset);
1819 REPORTER_ASSERT(reporter, !result);
1820
1821 result = sourceImage->makeWithFilter(filter.get(), subset, clipBounds, &outSubset, &offset);
1822
1823 REPORTER_ASSERT(reporter, result);
1824 REPORTER_ASSERT(reporter, result->bounds().contains(outSubset));
1825 SkIRect destRect = SkIRect::MakeXYWH(offset.x(), offset.y(),
1826 outSubset.width(), outSubset.height());
1827 REPORTER_ASSERT(reporter, clipBounds.contains(destRect));
Robert Phillipsa5fdc972017-02-18 16:58:09 -05001828
1829 // In GPU-mode, this case creates a special image with a backing size that differs from
1830 // the content size
1831 {
1832 clipBounds.setXYWH(0, 0, 170, 100);
1833 subset.setXYWH(0, 0, 160, 90);
1834
1835 filter = SkXfermodeImageFilter::Make(SkBlendMode::kSrc, nullptr);
1836 result = sourceImage->makeWithFilter(filter.get(), subset, clipBounds, &outSubset, &offset);
1837 REPORTER_ASSERT(reporter, result);
1838 }
senorblanco5878dbd2016-05-19 14:50:29 -07001839}
1840
1841DEF_TEST(ImageFilterMakeWithFilter, reporter) {
1842 test_make_with_filter(reporter, nullptr);
1843}
1844
1845#if SK_SUPPORT_GPU
1846DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterMakeWithFilter_Gpu, reporter, ctxInfo) {
1847 test_make_with_filter(reporter, ctxInfo.grContext());
1848}
1849#endif
1850
senorblanco@chromium.org58d14662014-02-03 22:36:39 +00001851#if SK_SUPPORT_GPU
reed4a8126e2014-09-22 07:29:03 -07001852
bsalomon68d91342016-04-12 09:59:58 -07001853DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterHugeBlur_Gpu, reporter, ctxInfo) {
robertphillipsefbffed2015-06-22 12:06:08 -07001854
bsalomon8b7451a2016-05-11 06:33:06 -07001855 sk_sp<SkSurface> surf(SkSurface::MakeRenderTarget(ctxInfo.grContext(),
robertphillips3e302272016-04-20 11:48:36 -07001856 SkBudgeted::kNo,
1857 SkImageInfo::MakeN32Premul(100, 100)));
robertphillips9a53fd72015-06-22 09:46:59 -07001858
robertphillips3e302272016-04-20 11:48:36 -07001859
1860 SkCanvas* canvas = surf->getCanvas();
1861
1862 test_huge_blur(canvas, reporter);
senorblanco@chromium.org09843fd2014-03-24 20:50:59 +00001863}
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001864
egdanielab527a52016-06-28 08:07:26 -07001865DEF_GPUTEST_FOR_RENDERING_CONTEXTS(XfermodeImageFilterCroppedInput_Gpu, reporter, ctxInfo) {
Brian Salomon8996e182017-07-05 17:01:48 -04001866 sk_sp<SkSurface> surf(SkSurface::MakeRenderTarget(
1867 ctxInfo.grContext(),
1868 SkBudgeted::kNo,
1869 SkImageInfo::Make(1, 1, kRGBA_8888_SkColorType, kPremul_SkAlphaType)));
robertphillips3e302272016-04-20 11:48:36 -07001870
Mike Reedf1942192017-07-21 14:24:29 -04001871 test_xfermode_cropped_input(surf.get(), reporter);
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001872}
senorblanco32673b92014-09-09 09:15:04 -07001873
egdanielab527a52016-06-28 08:07:26 -07001874DEF_GPUTEST_FOR_ALL_CONTEXTS(ImageFilterBlurLargeImage_Gpu, reporter, ctxInfo) {
Brian Salomon8996e182017-07-05 17:01:48 -04001875 auto surface(SkSurface::MakeRenderTarget(
1876 ctxInfo.grContext(), SkBudgeted::kYes,
1877 SkImageInfo::Make(100, 100, kRGBA_8888_SkColorType, kPremul_SkAlphaType)));
bsalomon45eefcf2016-01-05 08:39:28 -08001878 test_large_blur_input(reporter, surface->getCanvas());
1879}
senorblanco@chromium.org58d14662014-02-03 22:36:39 +00001880#endif
reedbb34a8a2016-04-23 15:19:07 -07001881
1882/*
1883 * Test that colorfilterimagefilter does not require its CTM to be decomposed when it has more
1884 * than just scale/translate, but that other filters do.
1885 */
reed96a04f32016-04-25 09:25:15 -07001886DEF_TEST(ImageFilterComplexCTM, reporter) {
reedbb34a8a2016-04-23 15:19:07 -07001887 // just need a colorfilter to exercise the corresponding imagefilter
Mike Reed7d954ad2016-10-28 15:42:34 -04001888 sk_sp<SkColorFilter> cf = SkColorFilter::MakeModeFilter(SK_ColorRED, SkBlendMode::kSrcATop);
reed96a04f32016-04-25 09:25:15 -07001889 sk_sp<SkImageFilter> cfif = SkColorFilterImageFilter::Make(cf, nullptr); // can handle
1890 sk_sp<SkImageFilter> blif = SkBlurImageFilter::Make(3, 3, nullptr); // cannot handle
reedbb34a8a2016-04-23 15:19:07 -07001891
1892 struct {
1893 sk_sp<SkImageFilter> fFilter;
1894 bool fExpectCanHandle;
1895 } recs[] = {
1896 { cfif, true },
1897 { SkColorFilterImageFilter::Make(cf, cfif), true },
Mike Reed0bdaf052017-06-18 23:35:57 -04001898 { SkMergeImageFilter::Make(cfif, cfif), true },
reed96a04f32016-04-25 09:25:15 -07001899 { SkComposeImageFilter::Make(cfif, cfif), true },
1900
reedbb34a8a2016-04-23 15:19:07 -07001901 { blif, false },
reed96a04f32016-04-25 09:25:15 -07001902 { SkBlurImageFilter::Make(3, 3, cfif), false },
reedbb34a8a2016-04-23 15:19:07 -07001903 { SkColorFilterImageFilter::Make(cf, blif), false },
Mike Reed0bdaf052017-06-18 23:35:57 -04001904 { SkMergeImageFilter::Make(cfif, blif), false },
reed96a04f32016-04-25 09:25:15 -07001905 { SkComposeImageFilter::Make(blif, cfif), false },
reedbb34a8a2016-04-23 15:19:07 -07001906 };
liyuqianbfebe222016-11-14 11:17:16 -08001907
reedbb34a8a2016-04-23 15:19:07 -07001908 for (const auto& rec : recs) {
reed96a04f32016-04-25 09:25:15 -07001909 const bool canHandle = rec.fFilter->canHandleComplexCTM();
reedbb34a8a2016-04-23 15:19:07 -07001910 REPORTER_ASSERT(reporter, canHandle == rec.fExpectCanHandle);
1911 }
1912}
Florin Malita08252ec2017-07-06 12:48:15 -04001913
1914// Test that transforming the filter DAG doesn't clone shared nodes multiple times.
1915DEF_TEST(ImageFilterColorSpaceDAG, reporter) {
1916
1917 // Helper for counting makeColorSpace() clones.
1918 class TestFilter final : public SkImageFilter {
1919 public:
1920 TestFilter() : INHERITED(nullptr, 0, nullptr) {}
1921
1922#ifndef SK_IGNORE_TO_STRING
1923 void toString(SkString*) const override {}
1924#endif
1925 Factory getFactory() const override { return nullptr; }
1926
1927 size_t cloneCount() const { return fCloneCount; }
1928
1929 protected:
1930 sk_sp<SkSpecialImage> onFilterImage(SkSpecialImage* src, const Context&,
1931 SkIPoint* offset) const override {
1932 return nullptr;
1933 }
1934 sk_sp<SkImageFilter> onMakeColorSpace(SkColorSpaceXformer*) const override {
1935 fCloneCount++;
1936 return sk_ref_sp(const_cast<TestFilter*>(this));
1937 }
1938
1939 private:
1940 typedef SkImageFilter INHERITED;
1941
1942 mutable size_t fCloneCount = 0;
1943 };
1944
1945 auto filter = sk_make_sp<TestFilter>();
1946 REPORTER_ASSERT(reporter, filter->cloneCount() == 0u);
1947
1948 // Build a DAG referencing the filter twice.
1949 auto complexFilter = SkMergeImageFilter::Make(filter, SkOffsetImageFilter::Make(1, 1, filter));
1950 REPORTER_ASSERT(reporter, filter->cloneCount() == 0u);
1951
1952 auto xformer = SkColorSpaceXformer::Make(SkColorSpace::MakeSRGB());
1953 auto xformedFilter = xformer->apply(complexFilter.get());
1954
Florin Malita39e08552017-07-06 14:16:18 -04001955 REPORTER_ASSERT(reporter, filter->cloneCount() == 1u);
Florin Malita08252ec2017-07-06 12:48:15 -04001956}
Xianzhu Wang0fa353c2017-08-25 16:27:04 -07001957
Xianzhu Wangb4496662017-09-25 10:26:40 -07001958// Test SkXfermodeImageFilter::filterBounds with different blending modes.
Xianzhu Wang0fa353c2017-08-25 16:27:04 -07001959DEF_TEST(XfermodeImageFilterBounds, reporter) {
1960 SkIRect background_rect = SkIRect::MakeXYWH(0, 0, 100, 100);
1961 SkIRect foreground_rect = SkIRect::MakeXYWH(50, 50, 100, 100);
1962 sk_sp<SkImageFilter> background(new FixedBoundsImageFilter(background_rect));
1963 sk_sp<SkImageFilter> foreground(new FixedBoundsImageFilter(foreground_rect));
1964
1965 const int kModeCount = static_cast<int>(SkBlendMode::kLastMode) + 1;
1966 SkIRect expectedBounds[kModeCount];
1967 // Expect union of input rects by default.
1968 for (int i = 0; i < kModeCount; ++i) {
1969 expectedBounds[i] = background_rect;
1970 expectedBounds[i].join(foreground_rect);
1971 }
1972
1973 SkIRect intersection = background_rect;
1974 intersection.intersect(foreground_rect);
1975 expectedBounds[static_cast<int>(SkBlendMode::kClear)] = SkIRect::MakeEmpty();
1976 expectedBounds[static_cast<int>(SkBlendMode::kSrc)] = foreground_rect;
1977 expectedBounds[static_cast<int>(SkBlendMode::kDst)] = background_rect;
1978 expectedBounds[static_cast<int>(SkBlendMode::kSrcIn)] = intersection;
1979 expectedBounds[static_cast<int>(SkBlendMode::kDstIn)] = intersection;
1980 expectedBounds[static_cast<int>(SkBlendMode::kSrcATop)] = background_rect;
1981 expectedBounds[static_cast<int>(SkBlendMode::kDstATop)] = foreground_rect;
1982
1983 // The value of this variable doesn't matter because we use inputs with fixed bounds.
1984 SkIRect src = SkIRect::MakeXYWH(11, 22, 33, 44);
1985 for (int i = 0; i < kModeCount; ++i) {
1986 sk_sp<SkImageFilter> xfermode(SkXfermodeImageFilter::Make(static_cast<SkBlendMode>(i),
1987 background, foreground, nullptr));
1988 auto bounds =
1989 xfermode->filterBounds(src, SkMatrix::I(), SkImageFilter::kForward_MapDirection);
1990 REPORTER_ASSERT(reporter, bounds == expectedBounds[i]);
1991 }
1992
1993 // Test empty intersection.
1994 sk_sp<SkImageFilter> background2(new FixedBoundsImageFilter(SkIRect::MakeXYWH(0, 0, 20, 20)));
1995 sk_sp<SkImageFilter> foreground2(new FixedBoundsImageFilter(SkIRect::MakeXYWH(40, 40, 50, 50)));
1996 sk_sp<SkImageFilter> xfermode(SkXfermodeImageFilter::Make(
1997 SkBlendMode::kSrcIn, std::move(background2), std::move(foreground2), nullptr));
1998 auto bounds = xfermode->filterBounds(src, SkMatrix::I(), SkImageFilter::kForward_MapDirection);
1999 REPORTER_ASSERT(reporter, bounds.isEmpty());
2000}
2001
Fredrik Söderquistb87f7982017-10-26 13:54:16 +02002002DEF_TEST(OffsetImageFilterBounds, reporter) {
2003 SkIRect src = SkIRect::MakeXYWH(0, 0, 100, 100);
2004 sk_sp<SkImageFilter> offset(SkOffsetImageFilter::Make(-50.5f, -50.5f, nullptr));
2005
2006 SkIRect expectedForward = SkIRect::MakeXYWH(-50, -50, 100, 100);
2007 SkIRect boundsForward = offset->filterBounds(src, SkMatrix::I(),
2008 SkImageFilter::kForward_MapDirection);
2009 REPORTER_ASSERT(reporter, boundsForward == expectedForward);
2010
2011 SkIRect expectedReverse = SkIRect::MakeXYWH(50, 50, 100, 100);
2012 SkIRect boundsReverse = offset->filterBounds(src, SkMatrix::I(),
2013 SkImageFilter::kReverse_MapDirection);
2014 REPORTER_ASSERT(reporter, boundsReverse == expectedReverse);
2015}
2016
Xianzhu Wang0fa353c2017-08-25 16:27:04 -07002017static void test_arithmetic_bounds(skiatest::Reporter* reporter, float k1, float k2, float k3,
2018 float k4, sk_sp<SkImageFilter> background,
2019 sk_sp<SkImageFilter> foreground,
2020 const SkImageFilter::CropRect* crop, const SkIRect& expected) {
2021 sk_sp<SkImageFilter> arithmetic(
2022 SkArithmeticImageFilter::Make(k1, k2, k3, k4, false, background, foreground, crop));
2023 // The value of the input rect doesn't matter because we use inputs with fixed bounds.
2024 SkIRect bounds = arithmetic->filterBounds(SkIRect::MakeXYWH(11, 22, 33, 44), SkMatrix::I(),
2025 SkImageFilter::kForward_MapDirection);
2026 REPORTER_ASSERT(reporter, expected == bounds);
2027}
2028
2029static void test_arithmetic_combinations(skiatest::Reporter* reporter, float v) {
2030 SkIRect background_rect = SkIRect::MakeXYWH(0, 0, 100, 100);
2031 SkIRect foreground_rect = SkIRect::MakeXYWH(50, 50, 100, 100);
2032 sk_sp<SkImageFilter> background(new FixedBoundsImageFilter(background_rect));
2033 sk_sp<SkImageFilter> foreground(new FixedBoundsImageFilter(foreground_rect));
2034
2035 SkIRect union_rect = background_rect;
2036 union_rect.join(foreground_rect);
2037 SkIRect intersection = background_rect;
2038 intersection.intersect(foreground_rect);
2039
2040 test_arithmetic_bounds(reporter, 0, 0, 0, 0, background, foreground, nullptr,
2041 SkIRect::MakeEmpty());
2042 test_arithmetic_bounds(reporter, 0, 0, 0, v, background, foreground, nullptr, union_rect);
2043 test_arithmetic_bounds(reporter, 0, 0, v, 0, background, foreground, nullptr, background_rect);
2044 test_arithmetic_bounds(reporter, 0, 0, v, v, background, foreground, nullptr, union_rect);
2045 test_arithmetic_bounds(reporter, 0, v, 0, 0, background, foreground, nullptr, foreground_rect);
2046 test_arithmetic_bounds(reporter, 0, v, 0, v, background, foreground, nullptr, union_rect);
2047 test_arithmetic_bounds(reporter, 0, v, v, 0, background, foreground, nullptr, union_rect);
2048 test_arithmetic_bounds(reporter, 0, v, v, v, background, foreground, nullptr, union_rect);
2049 test_arithmetic_bounds(reporter, v, 0, 0, 0, background, foreground, nullptr, intersection);
2050 test_arithmetic_bounds(reporter, v, 0, 0, v, background, foreground, nullptr, union_rect);
2051 test_arithmetic_bounds(reporter, v, 0, v, 0, background, foreground, nullptr, background_rect);
2052 test_arithmetic_bounds(reporter, v, 0, v, v, background, foreground, nullptr, union_rect);
2053 test_arithmetic_bounds(reporter, v, v, 0, 0, background, foreground, nullptr, foreground_rect);
2054 test_arithmetic_bounds(reporter, v, v, 0, v, background, foreground, nullptr, union_rect);
2055 test_arithmetic_bounds(reporter, v, v, v, 0, background, foreground, nullptr, union_rect);
2056 test_arithmetic_bounds(reporter, v, v, v, v, background, foreground, nullptr, union_rect);
2057
2058 // Test with crop. When k4 is non-zero, the result is expected to be crop_rect
2059 // regardless of inputs because the filter affects the whole crop area.
2060 SkIRect crop_rect = SkIRect::MakeXYWH(-111, -222, 333, 444);
2061 SkImageFilter::CropRect crop(SkRect::Make(crop_rect));
2062 test_arithmetic_bounds(reporter, 0, 0, 0, 0, background, foreground, &crop,
2063 SkIRect::MakeEmpty());
2064 test_arithmetic_bounds(reporter, 0, 0, 0, v, background, foreground, &crop, crop_rect);
2065 test_arithmetic_bounds(reporter, 0, 0, v, 0, background, foreground, &crop, background_rect);
2066 test_arithmetic_bounds(reporter, 0, 0, v, v, background, foreground, &crop, crop_rect);
2067 test_arithmetic_bounds(reporter, 0, v, 0, 0, background, foreground, &crop, foreground_rect);
2068 test_arithmetic_bounds(reporter, 0, v, 0, v, background, foreground, &crop, crop_rect);
2069 test_arithmetic_bounds(reporter, 0, v, v, 0, background, foreground, &crop, union_rect);
2070 test_arithmetic_bounds(reporter, 0, v, v, v, background, foreground, &crop, crop_rect);
2071 test_arithmetic_bounds(reporter, v, 0, 0, 0, background, foreground, &crop, intersection);
2072 test_arithmetic_bounds(reporter, v, 0, 0, v, background, foreground, &crop, crop_rect);
2073 test_arithmetic_bounds(reporter, v, 0, v, 0, background, foreground, &crop, background_rect);
2074 test_arithmetic_bounds(reporter, v, 0, v, v, background, foreground, &crop, crop_rect);
2075 test_arithmetic_bounds(reporter, v, v, 0, 0, background, foreground, &crop, foreground_rect);
2076 test_arithmetic_bounds(reporter, v, v, 0, v, background, foreground, &crop, crop_rect);
2077 test_arithmetic_bounds(reporter, v, v, v, 0, background, foreground, &crop, union_rect);
2078 test_arithmetic_bounds(reporter, v, v, v, v, background, foreground, &crop, crop_rect);
2079}
2080
Xianzhu Wangb4496662017-09-25 10:26:40 -07002081// Test SkArithmeticImageFilter::filterBounds with different blending modes.
Xianzhu Wang0fa353c2017-08-25 16:27:04 -07002082DEF_TEST(ArithmeticImageFilterBounds, reporter) {
2083 test_arithmetic_combinations(reporter, 1);
2084 test_arithmetic_combinations(reporter, 0.5);
2085}
Xianzhu Wangb4496662017-09-25 10:26:40 -07002086
2087// Test SkImageSource::filterBounds.
2088DEF_TEST(ImageSourceBounds, reporter) {
2089 sk_sp<SkImage> image(SkImage::MakeFromBitmap(make_gradient_circle(64, 64)));
2090 // Default src and dst rects.
2091 sk_sp<SkImageFilter> source1(SkImageSource::Make(image));
2092 SkIRect imageBounds = SkIRect::MakeWH(64, 64);
2093 SkIRect input(SkIRect::MakeXYWH(10, 20, 30, 40));
2094 REPORTER_ASSERT(reporter,
2095 imageBounds == source1->filterBounds(input, SkMatrix::I(),
2096 SkImageFilter::kForward_MapDirection));
2097 REPORTER_ASSERT(reporter,
2098 input == source1->filterBounds(input, SkMatrix::I(),
2099 SkImageFilter::kReverse_MapDirection));
2100 SkMatrix scale(SkMatrix::MakeScale(2));
2101 SkIRect scaledBounds = SkIRect::MakeWH(128, 128);
2102 REPORTER_ASSERT(reporter,
2103 scaledBounds == source1->filterBounds(input, scale,
2104 SkImageFilter::kForward_MapDirection));
2105 REPORTER_ASSERT(
2106 reporter,
2107 input == source1->filterBounds(input, scale, SkImageFilter::kReverse_MapDirection));
2108
2109 // Specified src and dst rects.
2110 SkRect src(SkRect::MakeXYWH(0.5, 0.5, 100.5, 100.5));
2111 SkRect dst(SkRect::MakeXYWH(-10.5, -10.5, 120.5, 120.5));
2112 sk_sp<SkImageFilter> source2(SkImageSource::Make(image, src, dst, kMedium_SkFilterQuality));
2113 REPORTER_ASSERT(reporter,
2114 dst.roundOut() == source2->filterBounds(input, SkMatrix::I(),
2115 SkImageFilter::kForward_MapDirection));
2116 REPORTER_ASSERT(reporter,
2117 input == source2->filterBounds(input, SkMatrix::I(),
2118 SkImageFilter::kReverse_MapDirection));
2119 scale.mapRect(&dst);
2120 scale.mapRect(&src);
2121 REPORTER_ASSERT(reporter,
2122 dst.roundOut() == source2->filterBounds(input, scale,
2123 SkImageFilter::kForward_MapDirection));
2124 REPORTER_ASSERT(
2125 reporter,
2126 input == source2->filterBounds(input, scale, SkImageFilter::kReverse_MapDirection));
2127}