blob: 59f0f2853bc5b359fb61aae06ee324cbe13d0934 [file] [log] [blame]
senorblanco@chromium.org194d7752013-07-24 22:19:24 +00001/*
2 * Copyright 2013 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
Xianzhu Wang0fa353c2017-08-25 16:27:04 -07008#include "SkArithmeticImageFilter.h"
commit-bot@chromium.org4b681bc2013-09-13 12:40:02 +00009#include "SkBitmap.h"
senorblanco@chromium.org6776b822014-01-03 21:48:22 +000010#include "SkBlurImageFilter.h"
tfarina@chromium.org8f6884a2014-01-24 20:56:26 +000011#include "SkCanvas.h"
12#include "SkColorFilterImageFilter.h"
13#include "SkColorMatrixFilter.h"
Florin Malita08252ec2017-07-06 12:48:15 -040014#include "SkColorSpaceXformer.h"
ajuma5788faa2015-02-13 09:05:47 -080015#include "SkComposeImageFilter.h"
senorblanco@chromium.org6776b822014-01-03 21:48:22 +000016#include "SkDisplacementMapEffect.h"
17#include "SkDropShadowImageFilter.h"
senorblanco@chromium.org97f5fc62014-05-30 20:50:56 +000018#include "SkFlattenableSerialization.h"
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +000019#include "SkGradientShader.h"
fmalita5598b632015-09-15 11:26:13 -070020#include "SkImage.h"
fmalitacd56f812015-09-14 13:31:18 -070021#include "SkImageSource.h"
commit-bot@chromium.org4b681bc2013-09-13 12:40:02 +000022#include "SkLightingImageFilter.h"
tfarina@chromium.org8f6884a2014-01-24 20:56:26 +000023#include "SkMatrixConvolutionImageFilter.h"
senorblanco@chromium.org6776b822014-01-03 21:48:22 +000024#include "SkMergeImageFilter.h"
25#include "SkMorphologyImageFilter.h"
senorblanco@chromium.org6776b822014-01-03 21:48:22 +000026#include "SkOffsetImageFilter.h"
ajuma77b6ba32016-01-08 14:58:35 -080027#include "SkPaintImageFilter.h"
senorblanco8f3937d2014-10-29 12:36:32 -070028#include "SkPerlinNoiseShader.h"
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +000029#include "SkPicture.h"
senorblanco@chromium.org910702b2014-05-30 20:36:15 +000030#include "SkPictureImageFilter.h"
robertphillips@google.com770963f2014-04-18 18:04:41 +000031#include "SkPictureRecorder.h"
robertphillips3d32d762015-07-13 13:16:44 -070032#include "SkPoint3.h"
halcanary97d2c0a2014-08-19 06:27:53 -070033#include "SkReadBuffer.h"
tfarina@chromium.org8f6884a2014-01-24 20:56:26 +000034#include "SkRect.h"
robertphillips4418dba2016-03-07 12:45:14 -080035#include "SkSpecialImage.h"
36#include "SkSpecialSurface.h"
fmalitacd56f812015-09-14 13:31:18 -070037#include "SkSurface.h"
senorblanco0abdf762015-08-20 11:10:41 -070038#include "SkTableColorFilter.h"
senorblanco@chromium.org6776b822014-01-03 21:48:22 +000039#include "SkTileImageFilter.h"
40#include "SkXfermodeImageFilter.h"
Leon Scroggins III4cdbf602017-09-28 14:33:57 -040041#include "Resources.h"
tfarina@chromium.org8f6884a2014-01-24 20:56:26 +000042#include "Test.h"
Mike Reed5a625e02017-08-08 15:48:54 -040043#include "sk_tool_utils.h"
senorblanco@chromium.org194d7752013-07-24 22:19:24 +000044
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +000045#if SK_SUPPORT_GPU
kkinnunen15302832015-12-01 04:35:26 -080046#include "GrContext.h"
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +000047#endif
48
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +000049static const int kBitmapSize = 4;
commit-bot@chromium.org4b681bc2013-09-13 12:40:02 +000050
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +000051namespace {
52
53class MatrixTestImageFilter : public SkImageFilter {
54public:
robertphillips43c2ad42016-04-04 05:05:11 -070055 static sk_sp<SkImageFilter> Make(skiatest::Reporter* reporter,
56 const SkMatrix& expectedMatrix) {
57 return sk_sp<SkImageFilter>(new MatrixTestImageFilter(reporter, expectedMatrix));
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +000058 }
59
robertphillipsf3f5bad2014-12-19 13:49:15 -080060 SK_TO_STRING_OVERRIDE()
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +000061 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(MatrixTestImageFilter)
62
63protected:
robertphillips4ba94e22016-04-04 12:07:47 -070064 sk_sp<SkSpecialImage> onFilterImage(SkSpecialImage* source, const Context& ctx,
65 SkIPoint* offset) const override {
robertphillips43c2ad42016-04-04 05:05:11 -070066 REPORTER_ASSERT(fReporter, ctx.ctm() == fExpectedMatrix);
robertphillips4ba94e22016-04-04 12:07:47 -070067 offset->fX = offset->fY = 0;
68 return sk_ref_sp<SkSpecialImage>(source);
robertphillips43c2ad42016-04-04 05:05:11 -070069 }
Matt Sarett62745a82017-04-17 11:57:29 -040070 sk_sp<SkImageFilter> onMakeColorSpace(SkColorSpaceXformer*) const override {
71 return sk_ref_sp(const_cast<MatrixTestImageFilter*>(this));
72 }
robertphillips43c2ad42016-04-04 05:05:11 -070073
mtklein36352bf2015-03-25 18:17:31 -070074 void flatten(SkWriteBuffer& buffer) const override {
brianosman18f13f32016-05-02 07:51:08 -070075 SkDEBUGFAIL("Should never get here");
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +000076 }
77
78private:
robertphillips43c2ad42016-04-04 05:05:11 -070079 MatrixTestImageFilter(skiatest::Reporter* reporter, const SkMatrix& expectedMatrix)
80 : INHERITED(nullptr, 0, nullptr)
81 , fReporter(reporter)
82 , fExpectedMatrix(expectedMatrix) {
83 }
84
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +000085 skiatest::Reporter* fReporter;
86 SkMatrix fExpectedMatrix;
mtklein3f3b3d02014-12-01 11:47:08 -080087
reed9fa60da2014-08-21 07:59:51 -070088 typedef SkImageFilter INHERITED;
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +000089};
90
senorblanco6a93fa12016-04-05 04:43:45 -070091class FailImageFilter : public SkImageFilter {
92public:
robertphillips6b134732016-04-15 09:58:37 -070093 FailImageFilter() : SkImageFilter(nullptr, 0, nullptr) { }
senorblanco6a93fa12016-04-05 04:43:45 -070094
95 sk_sp<SkSpecialImage> onFilterImage(SkSpecialImage* source,
96 const Context& ctx,
97 SkIPoint* offset) const override {
98 return nullptr;
99 }
Matt Sarett62745a82017-04-17 11:57:29 -0400100 sk_sp<SkImageFilter> onMakeColorSpace(SkColorSpaceXformer*) const override {
101 return nullptr;
102 }
senorblanco6a93fa12016-04-05 04:43:45 -0700103
104 SK_TO_STRING_OVERRIDE()
105 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(FailImageFilter)
106
107private:
108 typedef SkImageFilter INHERITED;
109};
110
111sk_sp<SkFlattenable> FailImageFilter::CreateProc(SkReadBuffer& buffer) {
112 SK_IMAGEFILTER_UNFLATTEN_COMMON(common, 0);
113 return sk_sp<SkFlattenable>(new FailImageFilter());
114}
115
116#ifndef SK_IGNORE_TO_STRING
117void FailImageFilter::toString(SkString* str) const {
118 str->appendf("FailImageFilter: (");
119 str->append(")");
120}
121#endif
122
senorblanco297f7ce2016-03-23 13:44:26 -0700123void draw_gradient_circle(SkCanvas* canvas, int width, int height) {
124 SkScalar x = SkIntToScalar(width / 2);
125 SkScalar y = SkIntToScalar(height / 2);
126 SkScalar radius = SkMinScalar(x, y) * 0.8f;
127 canvas->clear(0x00000000);
128 SkColor colors[2];
129 colors[0] = SK_ColorWHITE;
130 colors[1] = SK_ColorBLACK;
131 sk_sp<SkShader> shader(
132 SkGradientShader::MakeRadial(SkPoint::Make(x, y), radius, colors, nullptr, 2,
133 SkShader::kClamp_TileMode)
134 );
135 SkPaint paint;
136 paint.setShader(shader);
137 canvas->drawCircle(x, y, radius, paint);
138}
139
140SkBitmap make_gradient_circle(int width, int height) {
141 SkBitmap bitmap;
142 bitmap.allocN32Pixels(width, height);
143 SkCanvas canvas(bitmap);
144 draw_gradient_circle(&canvas, width, height);
145 return bitmap;
146}
147
148class FilterList {
149public:
robertphillipsfc11b0a2016-04-05 09:09:36 -0700150 FilterList(sk_sp<SkImageFilter> input, const SkImageFilter::CropRect* cropRect = nullptr) {
senorblanco297f7ce2016-03-23 13:44:26 -0700151 SkPoint3 location = SkPoint3::Make(0, 0, SK_Scalar1);
senorblanco297f7ce2016-03-23 13:44:26 -0700152 const SkScalar five = SkIntToScalar(5);
153
robertphillips6e7025a2016-04-04 04:31:25 -0700154 {
155 sk_sp<SkColorFilter> cf(SkColorFilter::MakeModeFilter(SK_ColorRED,
Mike Reed7d954ad2016-10-28 15:42:34 -0400156 SkBlendMode::kSrcIn));
senorblanco297f7ce2016-03-23 13:44:26 -0700157
robertphillips6e7025a2016-04-04 04:31:25 -0700158 this->addFilter("color filter",
robertphillips12fa47d2016-04-08 16:28:09 -0700159 SkColorFilterImageFilter::Make(std::move(cf), input, cropRect));
robertphillips6e7025a2016-04-04 04:31:25 -0700160 }
senorblanco297f7ce2016-03-23 13:44:26 -0700161
robertphillips6e7025a2016-04-04 04:31:25 -0700162 {
163 sk_sp<SkImage> gradientImage(SkImage::MakeFromBitmap(make_gradient_circle(64, 64)));
164 sk_sp<SkImageFilter> gradientSource(SkImageSource::Make(std::move(gradientImage)));
senorblanco297f7ce2016-03-23 13:44:26 -0700165
liyuqianbfebe222016-11-14 11:17:16 -0800166 this->addFilter("displacement map",
robertphillipsbfe11fc2016-04-15 07:17:36 -0700167 SkDisplacementMapEffect::Make(SkDisplacementMapEffect::kR_ChannelSelectorType,
168 SkDisplacementMapEffect::kB_ChannelSelectorType,
169 20.0f,
170 std::move(gradientSource), input, cropRect));
robertphillips6e7025a2016-04-04 04:31:25 -0700171 }
senorblanco297f7ce2016-03-23 13:44:26 -0700172
robertphillips6e7025a2016-04-04 04:31:25 -0700173 this->addFilter("blur", SkBlurImageFilter::Make(SK_Scalar1,
174 SK_Scalar1,
robertphillipsfc11b0a2016-04-05 09:09:36 -0700175 input,
robertphillips12fa47d2016-04-08 16:28:09 -0700176 cropRect));
robertphillipsc4169122016-04-06 08:40:59 -0700177 this->addFilter("drop shadow", SkDropShadowImageFilter::Make(
senorblanco297f7ce2016-03-23 13:44:26 -0700178 SK_Scalar1, SK_Scalar1, SK_Scalar1, SK_Scalar1, SK_ColorGREEN,
robertphillipsfc11b0a2016-04-05 09:09:36 -0700179 SkDropShadowImageFilter::kDrawShadowAndForeground_ShadowMode,
robertphillips12fa47d2016-04-08 16:28:09 -0700180 input, cropRect));
181 this->addFilter("diffuse lighting",
182 SkLightingImageFilter::MakePointLitDiffuse(location, SK_ColorGREEN, 0, 0,
183 input, cropRect));
senorblanco297f7ce2016-03-23 13:44:26 -0700184 this->addFilter("specular lighting",
robertphillips12fa47d2016-04-08 16:28:09 -0700185 SkLightingImageFilter::MakePointLitSpecular(location, SK_ColorGREEN, 0, 0, 0,
186 input, cropRect));
187 {
188 SkScalar kernel[9] = {
189 SkIntToScalar(1), SkIntToScalar(1), SkIntToScalar(1),
190 SkIntToScalar(1), SkIntToScalar(-7), SkIntToScalar(1),
191 SkIntToScalar(1), SkIntToScalar(1), SkIntToScalar(1),
192 };
193 const SkISize kernelSize = SkISize::Make(3, 3);
194 const SkScalar gain = SK_Scalar1, bias = 0;
195
196 this->addFilter("matrix convolution",
robertphillipsef6a47b2016-04-08 08:01:20 -0700197 SkMatrixConvolutionImageFilter::Make(
senorblanco297f7ce2016-03-23 13:44:26 -0700198 kernelSize, kernel, gain, bias, SkIPoint::Make(1, 1),
robertphillipsfc11b0a2016-04-05 09:09:36 -0700199 SkMatrixConvolutionImageFilter::kRepeat_TileMode, false,
robertphillips12fa47d2016-04-08 16:28:09 -0700200 input, cropRect));
201 }
202
Mike Reed0bdaf052017-06-18 23:35:57 -0400203 this->addFilter("merge", SkMergeImageFilter::Make(input, input, cropRect));
robertphillips12fa47d2016-04-08 16:28:09 -0700204
robertphillips6e7025a2016-04-04 04:31:25 -0700205 {
206 SkPaint greenColorShaderPaint;
207 greenColorShaderPaint.setShader(SkShader::MakeColorShader(SK_ColorGREEN));
208
209 SkImageFilter::CropRect leftSideCropRect(SkRect::MakeXYWH(0, 0, 32, 64));
210 sk_sp<SkImageFilter> paintFilterLeft(SkPaintImageFilter::Make(greenColorShaderPaint,
211 &leftSideCropRect));
212 SkImageFilter::CropRect rightSideCropRect(SkRect::MakeXYWH(32, 0, 32, 64));
213 sk_sp<SkImageFilter> paintFilterRight(SkPaintImageFilter::Make(greenColorShaderPaint,
214 &rightSideCropRect));
215
216
217 this->addFilter("merge with disjoint inputs", SkMergeImageFilter::Make(
Mike Reed0bdaf052017-06-18 23:35:57 -0400218 std::move(paintFilterLeft), std::move(paintFilterRight), cropRect));
robertphillips6e7025a2016-04-04 04:31:25 -0700219 }
220
senorblanco297f7ce2016-03-23 13:44:26 -0700221 this->addFilter("offset",
robertphillipsfc11b0a2016-04-05 09:09:36 -0700222 SkOffsetImageFilter::Make(SK_Scalar1, SK_Scalar1, input,
robertphillips12fa47d2016-04-08 16:28:09 -0700223 cropRect));
224 this->addFilter("dilate", SkDilateImageFilter::Make(3, 2, input, cropRect));
225 this->addFilter("erode", SkErodeImageFilter::Make(2, 3, input, cropRect));
robertphillips534c2702016-04-15 07:57:40 -0700226 this->addFilter("tile", SkTileImageFilter::Make(
227 SkRect::MakeXYWH(0, 0, 50, 50),
228 cropRect ? cropRect->rect() : SkRect::MakeXYWH(0, 0, 100, 100),
229 input));
robertphillips6e7025a2016-04-04 04:31:25 -0700230
robertphillips12fa47d2016-04-08 16:28:09 -0700231 if (!cropRect) {
232 SkMatrix matrix;
233
234 matrix.setTranslate(SK_Scalar1, SK_Scalar1);
235 matrix.postRotate(SkIntToScalar(45), SK_Scalar1, SK_Scalar1);
236
237 this->addFilter("matrix",
238 SkImageFilter::MakeMatrixFilter(matrix, kLow_SkFilterQuality, input));
239 }
robertphillips6e7025a2016-04-04 04:31:25 -0700240 {
robertphillipsfc11b0a2016-04-05 09:09:36 -0700241 sk_sp<SkImageFilter> blur(SkBlurImageFilter::Make(five, five, input));
robertphillips6e7025a2016-04-04 04:31:25 -0700242
243 this->addFilter("blur and offset", SkOffsetImageFilter::Make(five, five,
244 std::move(blur),
robertphillips12fa47d2016-04-08 16:28:09 -0700245 cropRect));
robertphillips6e7025a2016-04-04 04:31:25 -0700246 }
247 {
robertphillips6e7025a2016-04-04 04:31:25 -0700248 SkPictureRecorder recorder;
Mike Klein26eb16f2017-04-10 09:50:25 -0400249 SkCanvas* recordingCanvas = recorder.beginRecording(64, 64);
robertphillips6e7025a2016-04-04 04:31:25 -0700250
251 SkPaint greenPaint;
252 greenPaint.setColor(SK_ColorGREEN);
253 recordingCanvas->drawRect(SkRect::Make(SkIRect::MakeXYWH(10, 10, 30, 20)), greenPaint);
254 sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture());
255 sk_sp<SkImageFilter> pictureFilter(SkPictureImageFilter::Make(std::move(picture)));
256
257 this->addFilter("picture and blur", SkBlurImageFilter::Make(five, five,
258 std::move(pictureFilter),
robertphillips12fa47d2016-04-08 16:28:09 -0700259 cropRect));
robertphillips6e7025a2016-04-04 04:31:25 -0700260 }
261 {
262 SkPaint paint;
263 paint.setShader(SkPerlinNoiseShader::MakeTurbulence(SK_Scalar1, SK_Scalar1, 1, 0));
264 sk_sp<SkImageFilter> paintFilter(SkPaintImageFilter::Make(paint));
265
266 this->addFilter("paint and blur", SkBlurImageFilter::Make(five, five,
267 std::move(paintFilter),
robertphillips12fa47d2016-04-08 16:28:09 -0700268 cropRect));
robertphillips6e7025a2016-04-04 04:31:25 -0700269 }
reed374772b2016-10-05 17:33:02 -0700270 this->addFilter("xfermode", SkXfermodeImageFilter::Make(SkBlendMode::kSrc, input, input,
271 cropRect));
senorblanco297f7ce2016-03-23 13:44:26 -0700272 }
273 int count() const { return fFilters.count(); }
274 SkImageFilter* getFilter(int index) const { return fFilters[index].fFilter.get(); }
275 const char* getName(int index) const { return fFilters[index].fName; }
276private:
277 struct Filter {
robertphillips12fa47d2016-04-08 16:28:09 -0700278 Filter() : fName(nullptr) {}
279 Filter(const char* name, sk_sp<SkImageFilter> filter)
280 : fName(name)
281 , fFilter(std::move(filter)) {
282 }
senorblanco297f7ce2016-03-23 13:44:26 -0700283 const char* fName;
284 sk_sp<SkImageFilter> fFilter;
285 };
robertphillips12fa47d2016-04-08 16:28:09 -0700286 void addFilter(const char* name, sk_sp<SkImageFilter> filter) {
287 fFilters.push_back(Filter(name, std::move(filter)));
senorblanco297f7ce2016-03-23 13:44:26 -0700288 }
289
290 SkTArray<Filter> fFilters;
291};
292
Xianzhu Wang0fa353c2017-08-25 16:27:04 -0700293class FixedBoundsImageFilter : public SkImageFilter {
294public:
295 FixedBoundsImageFilter(const SkIRect& bounds)
296 : SkImageFilter(nullptr, 0, nullptr), fBounds(bounds) {}
297
298private:
299#ifndef SK_IGNORE_TO_STRING
300 void toString(SkString*) const override {}
301#endif
302 Factory getFactory() const override { return nullptr; }
303
304 sk_sp<SkSpecialImage> onFilterImage(SkSpecialImage* src, const Context&,
305 SkIPoint* offset) const override {
306 return nullptr;
307 }
308 sk_sp<SkImageFilter> onMakeColorSpace(SkColorSpaceXformer*) const override { return nullptr; }
309
310 SkIRect onFilterBounds(const SkIRect&, const SkMatrix&, MapDirection) const override {
311 return fBounds;
312 }
313
314 SkIRect fBounds;
315};
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +0000316}
317
reed60c9b582016-04-03 09:11:13 -0700318sk_sp<SkFlattenable> MatrixTestImageFilter::CreateProc(SkReadBuffer& buffer) {
brianosman18f13f32016-05-02 07:51:08 -0700319 SkDEBUGFAIL("Should never get here");
320 return nullptr;
reed9fa60da2014-08-21 07:59:51 -0700321}
322
robertphillipsf3f5bad2014-12-19 13:49:15 -0800323#ifndef SK_IGNORE_TO_STRING
324void MatrixTestImageFilter::toString(SkString* str) const {
325 str->appendf("MatrixTestImageFilter: (");
326 str->append(")");
327}
328#endif
329
reed9ce9d672016-03-17 10:51:11 -0700330static sk_sp<SkImage> make_small_image() {
reede8f30622016-03-23 18:59:25 -0700331 auto surface(SkSurface::MakeRasterN32Premul(kBitmapSize, kBitmapSize));
fmalita5598b632015-09-15 11:26:13 -0700332 SkCanvas* canvas = surface->getCanvas();
333 canvas->clear(0x00000000);
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000334 SkPaint darkPaint;
335 darkPaint.setColor(0xFF804020);
336 SkPaint lightPaint;
337 lightPaint.setColor(0xFF244484);
338 const int i = kBitmapSize / 4;
339 for (int y = 0; y < kBitmapSize; y += i) {
340 for (int x = 0; x < kBitmapSize; x += i) {
fmalita5598b632015-09-15 11:26:13 -0700341 canvas->save();
342 canvas->translate(SkIntToScalar(x), SkIntToScalar(y));
343 canvas->drawRect(SkRect::MakeXYWH(0, 0,
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000344 SkIntToScalar(i),
345 SkIntToScalar(i)), darkPaint);
fmalita5598b632015-09-15 11:26:13 -0700346 canvas->drawRect(SkRect::MakeXYWH(SkIntToScalar(i),
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000347 0,
348 SkIntToScalar(i),
349 SkIntToScalar(i)), lightPaint);
fmalita5598b632015-09-15 11:26:13 -0700350 canvas->drawRect(SkRect::MakeXYWH(0,
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000351 SkIntToScalar(i),
352 SkIntToScalar(i),
353 SkIntToScalar(i)), lightPaint);
fmalita5598b632015-09-15 11:26:13 -0700354 canvas->drawRect(SkRect::MakeXYWH(SkIntToScalar(i),
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000355 SkIntToScalar(i),
356 SkIntToScalar(i),
357 SkIntToScalar(i)), darkPaint);
fmalita5598b632015-09-15 11:26:13 -0700358 canvas->restore();
commit-bot@chromium.org4b681bc2013-09-13 12:40:02 +0000359 }
360 }
fmalita5598b632015-09-15 11:26:13 -0700361
reed9ce9d672016-03-17 10:51:11 -0700362 return surface->makeImageSnapshot();
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000363}
senorblanco@chromium.org194d7752013-07-24 22:19:24 +0000364
robertphillips5605b562016-04-05 11:50:42 -0700365static sk_sp<SkImageFilter> make_scale(float amount, sk_sp<SkImageFilter> input) {
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000366 SkScalar s = amount;
367 SkScalar matrix[20] = { s, 0, 0, 0, 0,
368 0, s, 0, 0, 0,
369 0, 0, s, 0, 0,
370 0, 0, 0, s, 0 };
robertphillips5605b562016-04-05 11:50:42 -0700371 sk_sp<SkColorFilter> filter(SkColorFilter::MakeMatrixFilterRowMajor255(matrix));
372 return SkColorFilterImageFilter::Make(std::move(filter), std::move(input));
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000373}
374
robertphillips5605b562016-04-05 11:50:42 -0700375static sk_sp<SkImageFilter> make_grayscale(sk_sp<SkImageFilter> input,
376 const SkImageFilter::CropRect* cropRect) {
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000377 SkScalar matrix[20];
378 memset(matrix, 0, 20 * sizeof(SkScalar));
379 matrix[0] = matrix[5] = matrix[10] = 0.2126f;
380 matrix[1] = matrix[6] = matrix[11] = 0.7152f;
381 matrix[2] = matrix[7] = matrix[12] = 0.0722f;
382 matrix[18] = 1.0f;
robertphillips5605b562016-04-05 11:50:42 -0700383 sk_sp<SkColorFilter> filter(SkColorFilter::MakeMatrixFilterRowMajor255(matrix));
384 return SkColorFilterImageFilter::Make(std::move(filter), std::move(input), cropRect);
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000385}
386
robertphillips5605b562016-04-05 11:50:42 -0700387static sk_sp<SkImageFilter> make_blue(sk_sp<SkImageFilter> input,
388 const SkImageFilter::CropRect* cropRect) {
389 sk_sp<SkColorFilter> filter(SkColorFilter::MakeModeFilter(SK_ColorBLUE,
Mike Reed7d954ad2016-10-28 15:42:34 -0400390 SkBlendMode::kSrcIn));
robertphillips5605b562016-04-05 11:50:42 -0700391 return SkColorFilterImageFilter::Make(std::move(filter), std::move(input), cropRect);
reedcedc36f2015-03-08 04:42:52 -0700392}
393
robertphillips3e302272016-04-20 11:48:36 -0700394static sk_sp<SkSpecialSurface> create_empty_special_surface(GrContext* context, int widthHeight) {
robertphillipsc91fd342016-04-25 12:32:54 -0700395#if SK_SUPPORT_GPU
robertphillips4418dba2016-03-07 12:45:14 -0800396 if (context) {
robertphillips4df16562016-04-28 15:09:34 -0700397 return SkSpecialSurface::MakeRenderTarget(context,
398 widthHeight, widthHeight,
Brian Osman777b5632016-10-14 09:16:21 -0400399 kRGBA_8888_GrPixelConfig, nullptr);
robertphillipsc91fd342016-04-25 12:32:54 -0700400 } else
401#endif
402 {
robertphillips4418dba2016-03-07 12:45:14 -0800403 const SkImageInfo info = SkImageInfo::MakeN32(widthHeight, widthHeight,
404 kOpaque_SkAlphaType);
robertphillips3e302272016-04-20 11:48:36 -0700405 return SkSpecialSurface::MakeRaster(info);
robertphillips4418dba2016-03-07 12:45:14 -0800406 }
senorblancobf680c32016-03-16 16:15:53 -0700407}
408
senorblanco5878dbd2016-05-19 14:50:29 -0700409static sk_sp<SkSurface> create_surface(GrContext* context, int width, int height) {
410 const SkImageInfo info = SkImageInfo::MakeN32(width, height, kOpaque_SkAlphaType);
411#if SK_SUPPORT_GPU
412 if (context) {
413 return SkSurface::MakeRenderTarget(context, SkBudgeted::kNo, info);
414 } else
415#endif
416 {
417 return SkSurface::MakeRaster(info);
418 }
419}
420
robertphillips3e302272016-04-20 11:48:36 -0700421static sk_sp<SkSpecialImage> create_empty_special_image(GrContext* context, int widthHeight) {
422 sk_sp<SkSpecialSurface> surf(create_empty_special_surface(context, widthHeight));
robertphillips4418dba2016-03-07 12:45:14 -0800423
424 SkASSERT(surf);
425
426 SkCanvas* canvas = surf->getCanvas();
427 SkASSERT(canvas);
428
429 canvas->clear(0x0);
430
robertphillips37bd7c32016-03-17 14:31:39 -0700431 return surf->makeImageSnapshot();
robertphillips4418dba2016-03-07 12:45:14 -0800432}
433
434
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000435DEF_TEST(ImageFilter, reporter) {
436 {
reedcedc36f2015-03-08 04:42:52 -0700437 // Check that two non-clipping color-matrice-filters concatenate into a single filter.
robertphillips5605b562016-04-05 11:50:42 -0700438 sk_sp<SkImageFilter> halfBrightness(make_scale(0.5f, nullptr));
439 sk_sp<SkImageFilter> quarterBrightness(make_scale(0.5f, std::move(halfBrightness)));
halcanary96fcdcc2015-08-27 07:41:13 -0700440 REPORTER_ASSERT(reporter, nullptr == quarterBrightness->getInput(0));
reedcedc36f2015-03-08 04:42:52 -0700441 SkColorFilter* cf;
442 REPORTER_ASSERT(reporter, quarterBrightness->asColorFilter(&cf));
halcanary96fcdcc2015-08-27 07:41:13 -0700443 REPORTER_ASSERT(reporter, cf->asColorMatrix(nullptr));
reedcedc36f2015-03-08 04:42:52 -0700444 cf->unref();
senorblanco@chromium.org194d7752013-07-24 22:19:24 +0000445 }
446
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000447 {
reedcedc36f2015-03-08 04:42:52 -0700448 // Check that a clipping color-matrice-filter followed by a color-matrice-filters
449 // concatenates into a single filter, but not a matrixfilter (due to clamping).
robertphillips5605b562016-04-05 11:50:42 -0700450 sk_sp<SkImageFilter> doubleBrightness(make_scale(2.0f, nullptr));
451 sk_sp<SkImageFilter> halfBrightness(make_scale(0.5f, std::move(doubleBrightness)));
halcanary96fcdcc2015-08-27 07:41:13 -0700452 REPORTER_ASSERT(reporter, nullptr == halfBrightness->getInput(0));
reedcedc36f2015-03-08 04:42:52 -0700453 SkColorFilter* cf;
454 REPORTER_ASSERT(reporter, halfBrightness->asColorFilter(&cf));
halcanary96fcdcc2015-08-27 07:41:13 -0700455 REPORTER_ASSERT(reporter, !cf->asColorMatrix(nullptr));
reedcedc36f2015-03-08 04:42:52 -0700456 cf->unref();
senorblanco@chromium.org194d7752013-07-24 22:19:24 +0000457 }
458
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000459 {
460 // Check that a color filter image filter without a crop rect can be
461 // expressed as a color filter.
robertphillips5605b562016-04-05 11:50:42 -0700462 sk_sp<SkImageFilter> gray(make_grayscale(nullptr, nullptr));
halcanary96fcdcc2015-08-27 07:41:13 -0700463 REPORTER_ASSERT(reporter, true == gray->asColorFilter(nullptr));
senorblanco@chromium.org194d7752013-07-24 22:19:24 +0000464 }
mtklein2afbe232016-02-07 12:23:10 -0800465
reedcedc36f2015-03-08 04:42:52 -0700466 {
467 // Check that a colorfilterimage filter without a crop rect but with an input
468 // that is another colorfilterimage can be expressed as a colorfilter (composed).
robertphillips5605b562016-04-05 11:50:42 -0700469 sk_sp<SkImageFilter> mode(make_blue(nullptr, nullptr));
470 sk_sp<SkImageFilter> gray(make_grayscale(std::move(mode), nullptr));
halcanary96fcdcc2015-08-27 07:41:13 -0700471 REPORTER_ASSERT(reporter, true == gray->asColorFilter(nullptr));
reedcedc36f2015-03-08 04:42:52 -0700472 }
473
474 {
475 // Test that if we exceed the limit of what ComposeColorFilter can combine, we still
476 // can build the DAG and won't assert if we call asColorFilter.
robertphillips5605b562016-04-05 11:50:42 -0700477 sk_sp<SkImageFilter> filter(make_blue(nullptr, nullptr));
reedcedc36f2015-03-08 04:42:52 -0700478 const int kWayTooManyForComposeColorFilter = 100;
479 for (int i = 0; i < kWayTooManyForComposeColorFilter; ++i) {
robertphillips5605b562016-04-05 11:50:42 -0700480 filter = make_blue(filter, nullptr);
reedcedc36f2015-03-08 04:42:52 -0700481 // the first few of these will succeed, but after we hit the internal limit,
482 // it will then return false.
halcanary96fcdcc2015-08-27 07:41:13 -0700483 (void)filter->asColorFilter(nullptr);
reedcedc36f2015-03-08 04:42:52 -0700484 }
485 }
reed5c518a82015-03-05 14:47:29 -0800486
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000487 {
488 // Check that a color filter image filter with a crop rect cannot
489 // be expressed as a color filter.
490 SkImageFilter::CropRect cropRect(SkRect::MakeXYWH(0, 0, 100, 100));
robertphillips5605b562016-04-05 11:50:42 -0700491 sk_sp<SkImageFilter> grayWithCrop(make_grayscale(nullptr, &cropRect));
halcanary96fcdcc2015-08-27 07:41:13 -0700492 REPORTER_ASSERT(reporter, false == grayWithCrop->asColorFilter(nullptr));
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000493 }
494
495 {
senorblanco3df05012014-07-03 11:13:09 -0700496 // Check that two non-commutative matrices are concatenated in
497 // the correct order.
498 SkScalar blueToRedMatrix[20] = { 0 };
499 blueToRedMatrix[2] = blueToRedMatrix[18] = SK_Scalar1;
500 SkScalar redToGreenMatrix[20] = { 0 };
501 redToGreenMatrix[5] = redToGreenMatrix[18] = SK_Scalar1;
robertphillips5605b562016-04-05 11:50:42 -0700502 sk_sp<SkColorFilter> blueToRed(SkColorFilter::MakeMatrixFilterRowMajor255(blueToRedMatrix));
503 sk_sp<SkImageFilter> filter1(SkColorFilterImageFilter::Make(std::move(blueToRed),
504 nullptr));
505 sk_sp<SkColorFilter> redToGreen(SkColorFilter::MakeMatrixFilterRowMajor255(redToGreenMatrix));
506 sk_sp<SkImageFilter> filter2(SkColorFilterImageFilter::Make(std::move(redToGreen),
507 std::move(filter1)));
senorblanco3df05012014-07-03 11:13:09 -0700508
509 SkBitmap result;
510 result.allocN32Pixels(kBitmapSize, kBitmapSize);
511
512 SkPaint paint;
513 paint.setColor(SK_ColorBLUE);
robertphillips5605b562016-04-05 11:50:42 -0700514 paint.setImageFilter(std::move(filter2));
senorblanco3df05012014-07-03 11:13:09 -0700515 SkCanvas canvas(result);
516 canvas.clear(0x0);
517 SkRect rect = SkRect::Make(SkIRect::MakeWH(kBitmapSize, kBitmapSize));
518 canvas.drawRect(rect, paint);
519 uint32_t pixel = *result.getAddr32(0, 0);
520 // The result here should be green, since we have effectively shifted blue to green.
521 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
522 }
523
524 {
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000525 // Tests pass by not asserting
reed9ce9d672016-03-17 10:51:11 -0700526 sk_sp<SkImage> image(make_small_image());
fmalita5598b632015-09-15 11:26:13 -0700527 SkBitmap result;
mike@reedtribe.orgdeee4962014-02-13 14:41:43 +0000528 result.allocN32Pixels(kBitmapSize, kBitmapSize);
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000529
senorblanco@chromium.org194d7752013-07-24 22:19:24 +0000530 {
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000531 // This tests for :
532 // 1 ) location at (0,0,1)
robertphillips3d32d762015-07-13 13:16:44 -0700533 SkPoint3 location = SkPoint3::Make(0, 0, SK_Scalar1);
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000534 // 2 ) location and target at same value
robertphillips3d32d762015-07-13 13:16:44 -0700535 SkPoint3 target = SkPoint3::Make(location.fX, location.fY, location.fZ);
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000536 // 3 ) large negative specular exponent value
537 SkScalar specularExponent = -1000;
538
robertphillips549c8992016-04-01 09:28:51 -0700539 sk_sp<SkImageFilter> bmSrc(SkImageSource::Make(std::move(image)));
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000540 SkPaint paint;
robertphillips12fa47d2016-04-08 16:28:09 -0700541 paint.setImageFilter(SkLightingImageFilter::MakeSpotLitSpecular(
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000542 location, target, specularExponent, 180,
543 0xFFFFFFFF, SK_Scalar1, SK_Scalar1, SK_Scalar1,
robertphillips12fa47d2016-04-08 16:28:09 -0700544 std::move(bmSrc)));
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000545 SkCanvas canvas(result);
546 SkRect r = SkRect::MakeWH(SkIntToScalar(kBitmapSize),
547 SkIntToScalar(kBitmapSize));
548 canvas.drawRect(r, paint);
senorblanco@chromium.org194d7752013-07-24 22:19:24 +0000549 }
senorblanco@chromium.org194d7752013-07-24 22:19:24 +0000550 }
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +0000551}
senorblanco@chromium.org6776b822014-01-03 21:48:22 +0000552
robertphillips3e302272016-04-20 11:48:36 -0700553static void test_crop_rects(skiatest::Reporter* reporter,
robertphillips4418dba2016-03-07 12:45:14 -0800554 GrContext* context) {
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +0000555 // Check that all filters offset to their absolute crop rect,
556 // unaffected by the input crop rect.
557 // Tests pass by not asserting.
robertphillips3e302272016-04-20 11:48:36 -0700558 sk_sp<SkSpecialImage> srcImg(create_empty_special_image(context, 100));
robertphillips4418dba2016-03-07 12:45:14 -0800559 SkASSERT(srcImg);
senorblanco@chromium.org6776b822014-01-03 21:48:22 +0000560
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +0000561 SkImageFilter::CropRect inputCropRect(SkRect::MakeXYWH(8, 13, 80, 80));
562 SkImageFilter::CropRect cropRect(SkRect::MakeXYWH(20, 30, 60, 60));
robertphillipsfc11b0a2016-04-05 09:09:36 -0700563 sk_sp<SkImageFilter> input(make_grayscale(nullptr, &inputCropRect));
senorblanco@chromium.org6776b822014-01-03 21:48:22 +0000564
robertphillipsfc11b0a2016-04-05 09:09:36 -0700565 FilterList filters(input, &cropRect);
senorblanco@chromium.org6776b822014-01-03 21:48:22 +0000566
senorblanco297f7ce2016-03-23 13:44:26 -0700567 for (int i = 0; i < filters.count(); ++i) {
568 SkImageFilter* filter = filters.getFilter(i);
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +0000569 SkIPoint offset;
brianosman2a75e5d2016-09-22 07:15:37 -0700570 SkImageFilter::OutputProperties noColorSpace(nullptr);
571 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeWH(100, 100), nullptr, noColorSpace);
robertphillips2302de92016-03-24 07:26:32 -0700572 sk_sp<SkSpecialImage> resultImg(filter->filterImage(srcImg.get(), ctx, &offset));
senorblanco297f7ce2016-03-23 13:44:26 -0700573 REPORTER_ASSERT_MESSAGE(reporter, resultImg, filters.getName(i));
574 REPORTER_ASSERT_MESSAGE(reporter, offset.fX == 20 && offset.fY == 30, filters.getName(i));
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +0000575 }
576}
577
robertphillips3e302272016-04-20 11:48:36 -0700578static void test_negative_blur_sigma(skiatest::Reporter* reporter,
robertphillips4418dba2016-03-07 12:45:14 -0800579 GrContext* context) {
senorblanco32673b92014-09-09 09:15:04 -0700580 // Check that SkBlurImageFilter will accept a negative sigma, either in
581 // the given arguments or after CTM application.
reed5ea95df2015-10-06 14:05:32 -0700582 const int width = 32, height = 32;
583 const SkScalar five = SkIntToScalar(5);
senorblanco32673b92014-09-09 09:15:04 -0700584
robertphillips6e7025a2016-04-04 04:31:25 -0700585 sk_sp<SkImageFilter> positiveFilter(SkBlurImageFilter::Make(five, five, nullptr));
586 sk_sp<SkImageFilter> negativeFilter(SkBlurImageFilter::Make(-five, five, nullptr));
senorblanco32673b92014-09-09 09:15:04 -0700587
588 SkBitmap gradient = make_gradient_circle(width, height);
robertphillips3e302272016-04-20 11:48:36 -0700589 sk_sp<SkSpecialImage> imgSrc(SkSpecialImage::MakeFromRaster(SkIRect::MakeWH(width, height),
robertphillips37bd7c32016-03-17 14:31:39 -0700590 gradient));
robertphillips4418dba2016-03-07 12:45:14 -0800591
senorblanco32673b92014-09-09 09:15:04 -0700592 SkIPoint offset;
brianosman2a75e5d2016-09-22 07:15:37 -0700593 SkImageFilter::OutputProperties noColorSpace(nullptr);
594 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeWH(32, 32), nullptr, noColorSpace);
robertphillips4418dba2016-03-07 12:45:14 -0800595
robertphillips2302de92016-03-24 07:26:32 -0700596 sk_sp<SkSpecialImage> positiveResult1(positiveFilter->filterImage(imgSrc.get(), ctx, &offset));
robertphillips4418dba2016-03-07 12:45:14 -0800597 REPORTER_ASSERT(reporter, positiveResult1);
598
robertphillips2302de92016-03-24 07:26:32 -0700599 sk_sp<SkSpecialImage> negativeResult1(negativeFilter->filterImage(imgSrc.get(), ctx, &offset));
robertphillips4418dba2016-03-07 12:45:14 -0800600 REPORTER_ASSERT(reporter, negativeResult1);
601
senorblanco32673b92014-09-09 09:15:04 -0700602 SkMatrix negativeScale;
603 negativeScale.setScale(-SK_Scalar1, SK_Scalar1);
brianosman2a75e5d2016-09-22 07:15:37 -0700604 SkImageFilter::Context negativeCTX(negativeScale, SkIRect::MakeWH(32, 32), nullptr,
605 noColorSpace);
robertphillips4418dba2016-03-07 12:45:14 -0800606
robertphillips2302de92016-03-24 07:26:32 -0700607 sk_sp<SkSpecialImage> negativeResult2(positiveFilter->filterImage(imgSrc.get(),
608 negativeCTX,
609 &offset));
robertphillips4418dba2016-03-07 12:45:14 -0800610 REPORTER_ASSERT(reporter, negativeResult2);
611
robertphillips2302de92016-03-24 07:26:32 -0700612 sk_sp<SkSpecialImage> positiveResult2(negativeFilter->filterImage(imgSrc.get(),
613 negativeCTX,
614 &offset));
robertphillips4418dba2016-03-07 12:45:14 -0800615 REPORTER_ASSERT(reporter, positiveResult2);
616
617
618 SkBitmap positiveResultBM1, positiveResultBM2;
619 SkBitmap negativeResultBM1, negativeResultBM2;
620
robertphillips64612512016-04-08 12:10:42 -0700621 REPORTER_ASSERT(reporter, positiveResult1->getROPixels(&positiveResultBM1));
622 REPORTER_ASSERT(reporter, positiveResult2->getROPixels(&positiveResultBM2));
623 REPORTER_ASSERT(reporter, negativeResult1->getROPixels(&negativeResultBM1));
624 REPORTER_ASSERT(reporter, negativeResult2->getROPixels(&negativeResultBM2));
robertphillips4418dba2016-03-07 12:45:14 -0800625
senorblanco32673b92014-09-09 09:15:04 -0700626 for (int y = 0; y < height; y++) {
robertphillips4418dba2016-03-07 12:45:14 -0800627 int diffs = memcmp(positiveResultBM1.getAddr32(0, y),
628 negativeResultBM1.getAddr32(0, y),
629 positiveResultBM1.rowBytes());
senorblanco32673b92014-09-09 09:15:04 -0700630 REPORTER_ASSERT(reporter, !diffs);
631 if (diffs) {
632 break;
633 }
robertphillips4418dba2016-03-07 12:45:14 -0800634 diffs = memcmp(positiveResultBM1.getAddr32(0, y),
635 negativeResultBM2.getAddr32(0, y),
636 positiveResultBM1.rowBytes());
senorblanco32673b92014-09-09 09:15:04 -0700637 REPORTER_ASSERT(reporter, !diffs);
638 if (diffs) {
639 break;
640 }
robertphillips4418dba2016-03-07 12:45:14 -0800641 diffs = memcmp(positiveResultBM1.getAddr32(0, y),
642 positiveResultBM2.getAddr32(0, y),
643 positiveResultBM1.rowBytes());
senorblanco32673b92014-09-09 09:15:04 -0700644 REPORTER_ASSERT(reporter, !diffs);
645 if (diffs) {
646 break;
647 }
648 }
649}
650
senorblanco21a465d2016-04-11 11:58:39 -0700651DEF_TEST(ImageFilterNegativeBlurSigma, reporter) {
robertphillips3e302272016-04-20 11:48:36 -0700652 test_negative_blur_sigma(reporter, nullptr);
robertphillips4418dba2016-03-07 12:45:14 -0800653}
654
655#if SK_SUPPORT_GPU
bsalomon68d91342016-04-12 09:59:58 -0700656DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterNegativeBlurSigma_Gpu, reporter, ctxInfo) {
bsalomon8b7451a2016-05-11 06:33:06 -0700657 test_negative_blur_sigma(reporter, ctxInfo.grContext());
robertphillips4418dba2016-03-07 12:45:14 -0800658}
659#endif
660
robertphillips3e302272016-04-20 11:48:36 -0700661static void test_zero_blur_sigma(skiatest::Reporter* reporter, GrContext* context) {
senorblancobf680c32016-03-16 16:15:53 -0700662 // Check that SkBlurImageFilter with a zero sigma and a non-zero srcOffset works correctly.
663 SkImageFilter::CropRect cropRect(SkRect::Make(SkIRect::MakeXYWH(5, 0, 5, 10)));
robertphillips51a315e2016-03-31 09:05:49 -0700664 sk_sp<SkImageFilter> input(SkOffsetImageFilter::Make(0, 0, nullptr, &cropRect));
robertphillips6e7025a2016-04-04 04:31:25 -0700665 sk_sp<SkImageFilter> filter(SkBlurImageFilter::Make(0, 0, std::move(input), &cropRect));
senorblancobf680c32016-03-16 16:15:53 -0700666
robertphillips3e302272016-04-20 11:48:36 -0700667 sk_sp<SkSpecialSurface> surf(create_empty_special_surface(context, 10));
senorblancobf680c32016-03-16 16:15:53 -0700668 surf->getCanvas()->clear(SK_ColorGREEN);
robertphillips37bd7c32016-03-17 14:31:39 -0700669 sk_sp<SkSpecialImage> image(surf->makeImageSnapshot());
senorblancobf680c32016-03-16 16:15:53 -0700670
671 SkIPoint offset;
brianosman2a75e5d2016-09-22 07:15:37 -0700672 SkImageFilter::OutputProperties noColorSpace(nullptr);
673 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeWH(32, 32), nullptr, noColorSpace);
senorblancobf680c32016-03-16 16:15:53 -0700674
robertphillips2302de92016-03-24 07:26:32 -0700675 sk_sp<SkSpecialImage> result(filter->filterImage(image.get(), ctx, &offset));
senorblancobf680c32016-03-16 16:15:53 -0700676 REPORTER_ASSERT(reporter, offset.fX == 5 && offset.fY == 0);
677 REPORTER_ASSERT(reporter, result);
678 REPORTER_ASSERT(reporter, result->width() == 5 && result->height() == 10);
679
680 SkBitmap resultBM;
681
robertphillips64612512016-04-08 12:10:42 -0700682 REPORTER_ASSERT(reporter, result->getROPixels(&resultBM));
senorblancobf680c32016-03-16 16:15:53 -0700683
senorblancobf680c32016-03-16 16:15:53 -0700684 for (int y = 0; y < resultBM.height(); y++) {
685 for (int x = 0; x < resultBM.width(); x++) {
686 bool diff = *resultBM.getAddr32(x, y) != SK_ColorGREEN;
687 REPORTER_ASSERT(reporter, !diff);
688 if (diff) {
689 break;
690 }
691 }
692 }
693}
694
senorblanco21a465d2016-04-11 11:58:39 -0700695DEF_TEST(ImageFilterZeroBlurSigma, reporter) {
robertphillips3e302272016-04-20 11:48:36 -0700696 test_zero_blur_sigma(reporter, nullptr);
senorblancobf680c32016-03-16 16:15:53 -0700697}
698
699#if SK_SUPPORT_GPU
bsalomon68d91342016-04-12 09:59:58 -0700700DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterZeroBlurSigma_Gpu, reporter, ctxInfo) {
bsalomon8b7451a2016-05-11 06:33:06 -0700701 test_zero_blur_sigma(reporter, ctxInfo.grContext());
senorblancobf680c32016-03-16 16:15:53 -0700702}
703#endif
704
senorblanco6a93fa12016-04-05 04:43:45 -0700705
706// Tests that, even when an upstream filter has returned null (due to failure or clipping), a
707// downstream filter that affects transparent black still does so even with a nullptr input.
robertphillips3e302272016-04-20 11:48:36 -0700708static void test_fail_affects_transparent_black(skiatest::Reporter* reporter, GrContext* context) {
senorblanco6a93fa12016-04-05 04:43:45 -0700709 sk_sp<FailImageFilter> failFilter(new FailImageFilter());
robertphillips3e302272016-04-20 11:48:36 -0700710 sk_sp<SkSpecialImage> source(create_empty_special_image(context, 5));
brianosman2a75e5d2016-09-22 07:15:37 -0700711 SkImageFilter::OutputProperties noColorSpace(nullptr);
712 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeXYWH(0, 0, 1, 1), nullptr, noColorSpace);
Mike Reed7d954ad2016-10-28 15:42:34 -0400713 sk_sp<SkColorFilter> green(SkColorFilter::MakeModeFilter(SK_ColorGREEN, SkBlendMode::kSrc));
senorblanco6a93fa12016-04-05 04:43:45 -0700714 SkASSERT(green->affectsTransparentBlack());
robertphillips5605b562016-04-05 11:50:42 -0700715 sk_sp<SkImageFilter> greenFilter(SkColorFilterImageFilter::Make(std::move(green),
716 std::move(failFilter)));
senorblanco6a93fa12016-04-05 04:43:45 -0700717 SkIPoint offset;
718 sk_sp<SkSpecialImage> result(greenFilter->filterImage(source.get(), ctx, &offset));
719 REPORTER_ASSERT(reporter, nullptr != result.get());
720 if (result.get()) {
721 SkBitmap resultBM;
robertphillips64612512016-04-08 12:10:42 -0700722 REPORTER_ASSERT(reporter, result->getROPixels(&resultBM));
senorblanco6a93fa12016-04-05 04:43:45 -0700723 REPORTER_ASSERT(reporter, *resultBM.getAddr32(0, 0) == SK_ColorGREEN);
724 }
725}
726
727DEF_TEST(ImageFilterFailAffectsTransparentBlack, reporter) {
robertphillips3e302272016-04-20 11:48:36 -0700728 test_fail_affects_transparent_black(reporter, nullptr);
senorblanco6a93fa12016-04-05 04:43:45 -0700729}
730
731#if SK_SUPPORT_GPU
bsalomon68d91342016-04-12 09:59:58 -0700732DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterFailAffectsTransparentBlack_Gpu, reporter, ctxInfo) {
bsalomon8b7451a2016-05-11 06:33:06 -0700733 test_fail_affects_transparent_black(reporter, ctxInfo.grContext());
senorblanco6a93fa12016-04-05 04:43:45 -0700734}
735#endif
736
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +0000737DEF_TEST(ImageFilterDrawTiled, reporter) {
738 // Check that all filters when drawn tiled (with subsequent clip rects) exactly
739 // match the same filters drawn with a single full-canvas bitmap draw.
740 // Tests pass by not asserting.
741
robertphillipsfc11b0a2016-04-05 09:09:36 -0700742 FilterList filters(nullptr);
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +0000743
744 SkBitmap untiledResult, tiledResult;
reed5ea95df2015-10-06 14:05:32 -0700745 const int width = 64, height = 64;
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +0000746 untiledResult.allocN32Pixels(width, height);
747 tiledResult.allocN32Pixels(width, height);
748 SkCanvas tiledCanvas(tiledResult);
749 SkCanvas untiledCanvas(untiledResult);
senorblanco@chromium.orgd4db6572014-05-07 20:00:04 +0000750 int tileSize = 8;
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +0000751
senorblanco@chromium.orgd4db6572014-05-07 20:00:04 +0000752 for (int scale = 1; scale <= 2; ++scale) {
senorblanco297f7ce2016-03-23 13:44:26 -0700753 for (int i = 0; i < filters.count(); ++i) {
senorblanco@chromium.orgd4db6572014-05-07 20:00:04 +0000754 tiledCanvas.clear(0);
755 untiledCanvas.clear(0);
756 SkPaint paint;
Mike Reed5e257172016-11-01 11:22:05 -0400757 paint.setImageFilter(sk_ref_sp(filters.getFilter(i)));
senorblanco@chromium.orgd4db6572014-05-07 20:00:04 +0000758 paint.setTextSize(SkIntToScalar(height));
759 paint.setColor(SK_ColorWHITE);
760 SkString str;
761 const char* text = "ABC";
762 SkScalar ypos = SkIntToScalar(height);
763 untiledCanvas.save();
764 untiledCanvas.scale(SkIntToScalar(scale), SkIntToScalar(scale));
Cary Clark2a475ea2017-04-28 15:35:12 -0400765 untiledCanvas.drawString(text, 0, ypos, paint);
senorblanco@chromium.orgd4db6572014-05-07 20:00:04 +0000766 untiledCanvas.restore();
767 for (int y = 0; y < height; y += tileSize) {
768 for (int x = 0; x < width; x += tileSize) {
769 tiledCanvas.save();
770 tiledCanvas.clipRect(SkRect::Make(SkIRect::MakeXYWH(x, y, tileSize, tileSize)));
771 tiledCanvas.scale(SkIntToScalar(scale), SkIntToScalar(scale));
Cary Clark2a475ea2017-04-28 15:35:12 -0400772 tiledCanvas.drawString(text, 0, ypos, paint);
senorblanco@chromium.orgd4db6572014-05-07 20:00:04 +0000773 tiledCanvas.restore();
774 }
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +0000775 }
senorblanco@chromium.orgd4db6572014-05-07 20:00:04 +0000776 untiledCanvas.flush();
777 tiledCanvas.flush();
Mike Reed34042072017-08-08 16:29:22 -0400778 if (!sk_tool_utils::equal_pixels(untiledResult, tiledResult, 1)) {
Mike Reed5a625e02017-08-08 15:48:54 -0400779 REPORTER_ASSERT_MESSAGE(reporter, false, filters.getName(i));
780 break;
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +0000781 }
782 }
783 }
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +0000784}
785
mtklein3f3b3d02014-12-01 11:47:08 -0800786static void draw_saveLayer_picture(int width, int height, int tileSize,
robertphillipsa8d7f0b2014-08-29 08:03:56 -0700787 SkBBHFactory* factory, SkBitmap* result) {
mtkleind910f542014-08-22 09:06:34 -0700788
789 SkMatrix matrix;
790 matrix.setTranslate(SkIntToScalar(50), 0);
791
Mike Reed7d954ad2016-10-28 15:42:34 -0400792 sk_sp<SkColorFilter> cf(SkColorFilter::MakeModeFilter(SK_ColorWHITE, SkBlendMode::kSrc));
robertphillips5605b562016-04-05 11:50:42 -0700793 sk_sp<SkImageFilter> cfif(SkColorFilterImageFilter::Make(std::move(cf), nullptr));
robertphillipsae8c9332016-04-05 15:09:00 -0700794 sk_sp<SkImageFilter> imageFilter(SkImageFilter::MakeMatrixFilter(matrix,
795 kNone_SkFilterQuality,
796 std::move(cfif)));
mtkleind910f542014-08-22 09:06:34 -0700797
798 SkPaint paint;
robertphillips5605b562016-04-05 11:50:42 -0700799 paint.setImageFilter(std::move(imageFilter));
mtkleind910f542014-08-22 09:06:34 -0700800 SkPictureRecorder recorder;
801 SkRect bounds = SkRect::Make(SkIRect::MakeXYWH(0, 0, 50, 50));
mtklein3f3b3d02014-12-01 11:47:08 -0800802 SkCanvas* recordingCanvas = recorder.beginRecording(SkIntToScalar(width),
803 SkIntToScalar(height),
robertphillipsa8d7f0b2014-08-29 08:03:56 -0700804 factory, 0);
mtkleind910f542014-08-22 09:06:34 -0700805 recordingCanvas->translate(-55, 0);
806 recordingCanvas->saveLayer(&bounds, &paint);
807 recordingCanvas->restore();
reedca2622b2016-03-18 07:25:55 -0700808 sk_sp<SkPicture> picture1(recorder.finishRecordingAsPicture());
mtkleind910f542014-08-22 09:06:34 -0700809
810 result->allocN32Pixels(width, height);
811 SkCanvas canvas(*result);
812 canvas.clear(0);
813 canvas.clipRect(SkRect::Make(SkIRect::MakeWH(tileSize, tileSize)));
814 canvas.drawPicture(picture1.get());
815}
816
817DEF_TEST(ImageFilterDrawMatrixBBH, reporter) {
818 // Check that matrix filter when drawn tiled with BBH exactly
819 // matches the same thing drawn without BBH.
820 // Tests pass by not asserting.
821
822 const int width = 200, height = 200;
823 const int tileSize = 100;
824 SkBitmap result1, result2;
825 SkRTreeFactory factory;
826
robertphillipsa8d7f0b2014-08-29 08:03:56 -0700827 draw_saveLayer_picture(width, height, tileSize, &factory, &result1);
halcanary96fcdcc2015-08-27 07:41:13 -0700828 draw_saveLayer_picture(width, height, tileSize, nullptr, &result2);
mtkleind910f542014-08-22 09:06:34 -0700829
830 for (int y = 0; y < height; y++) {
831 int diffs = memcmp(result1.getAddr32(0, y), result2.getAddr32(0, y), result1.rowBytes());
832 REPORTER_ASSERT(reporter, !diffs);
833 if (diffs) {
834 break;
835 }
836 }
837}
838
robertphillips6e7025a2016-04-04 04:31:25 -0700839static sk_sp<SkImageFilter> make_blur(sk_sp<SkImageFilter> input) {
840 return SkBlurImageFilter::Make(SK_Scalar1, SK_Scalar1, std::move(input));
senorblanco1150a6d2014-08-25 12:46:58 -0700841}
842
robertphillips6e7025a2016-04-04 04:31:25 -0700843static sk_sp<SkImageFilter> make_drop_shadow(sk_sp<SkImageFilter> input) {
robertphillipsc4169122016-04-06 08:40:59 -0700844 return SkDropShadowImageFilter::Make(
senorblanco1150a6d2014-08-25 12:46:58 -0700845 SkIntToScalar(100), SkIntToScalar(100),
846 SkIntToScalar(10), SkIntToScalar(10),
sugoi234f0362014-10-23 13:59:52 -0700847 SK_ColorBLUE, SkDropShadowImageFilter::kDrawShadowAndForeground_ShadowMode,
robertphillipsc4169122016-04-06 08:40:59 -0700848 std::move(input));
senorblanco1150a6d2014-08-25 12:46:58 -0700849}
850
851DEF_TEST(ImageFilterBlurThenShadowBounds, reporter) {
robertphillips6e7025a2016-04-04 04:31:25 -0700852 sk_sp<SkImageFilter> filter1(make_blur(nullptr));
853 sk_sp<SkImageFilter> filter2(make_drop_shadow(std::move(filter1)));
senorblanco1150a6d2014-08-25 12:46:58 -0700854
855 SkIRect bounds = SkIRect::MakeXYWH(0, 0, 100, 100);
Herb Derby59f8f152017-10-17 22:27:23 +0000856 SkIRect expectedBounds = SkIRect::MakeXYWH(-133, -133, 236, 236);
senorblancoe5e79842016-03-21 14:51:59 -0700857 bounds = filter2->filterBounds(bounds, SkMatrix::I());
senorblanco1150a6d2014-08-25 12:46:58 -0700858
859 REPORTER_ASSERT(reporter, bounds == expectedBounds);
860}
861
862DEF_TEST(ImageFilterShadowThenBlurBounds, reporter) {
robertphillips6e7025a2016-04-04 04:31:25 -0700863 sk_sp<SkImageFilter> filter1(make_drop_shadow(nullptr));
864 sk_sp<SkImageFilter> filter2(make_blur(std::move(filter1)));
senorblanco1150a6d2014-08-25 12:46:58 -0700865
866 SkIRect bounds = SkIRect::MakeXYWH(0, 0, 100, 100);
Herb Derby59f8f152017-10-17 22:27:23 +0000867 SkIRect expectedBounds = SkIRect::MakeXYWH(-133, -133, 236, 236);
senorblancoe5e79842016-03-21 14:51:59 -0700868 bounds = filter2->filterBounds(bounds, SkMatrix::I());
senorblanco1150a6d2014-08-25 12:46:58 -0700869
870 REPORTER_ASSERT(reporter, bounds == expectedBounds);
871}
872
873DEF_TEST(ImageFilterDilateThenBlurBounds, reporter) {
robertphillipsfc11b0a2016-04-05 09:09:36 -0700874 sk_sp<SkImageFilter> filter1(SkDilateImageFilter::Make(2, 2, nullptr));
robertphillips6e7025a2016-04-04 04:31:25 -0700875 sk_sp<SkImageFilter> filter2(make_drop_shadow(std::move(filter1)));
senorblanco1150a6d2014-08-25 12:46:58 -0700876
877 SkIRect bounds = SkIRect::MakeXYWH(0, 0, 100, 100);
878 SkIRect expectedBounds = SkIRect::MakeXYWH(-132, -132, 234, 234);
senorblancoe5e79842016-03-21 14:51:59 -0700879 bounds = filter2->filterBounds(bounds, SkMatrix::I());
senorblanco1150a6d2014-08-25 12:46:58 -0700880
881 REPORTER_ASSERT(reporter, bounds == expectedBounds);
882}
883
jbroman203a9932016-07-11 14:07:59 -0700884DEF_TEST(ImageFilterScaledBlurRadius, reporter) {
885 // Each blur should spread 3*sigma, so 3 for the blur and 30 for the shadow
886 // (before the CTM). Bounds should be computed correctly in the presence of
887 // a (possibly negative) scale.
888 sk_sp<SkImageFilter> blur(make_blur(nullptr));
889 sk_sp<SkImageFilter> dropShadow(make_drop_shadow(nullptr));
890 {
891 // Uniform scale by 2.
892 SkMatrix scaleMatrix;
893 scaleMatrix.setScale(2, 2);
894 SkIRect bounds = SkIRect::MakeLTRB(0, 0, 200, 200);
895
Herb Derby59f8f152017-10-17 22:27:23 +0000896 SkIRect expectedBlurBounds = SkIRect::MakeLTRB(-6, -6, 206, 206);
jbroman203a9932016-07-11 14:07:59 -0700897 SkIRect blurBounds = blur->filterBounds(
898 bounds, scaleMatrix, SkImageFilter::kForward_MapDirection);
899 REPORTER_ASSERT(reporter, blurBounds == expectedBlurBounds);
900 SkIRect reverseBlurBounds = blur->filterBounds(
901 bounds, scaleMatrix, SkImageFilter::kReverse_MapDirection);
902 REPORTER_ASSERT(reporter, reverseBlurBounds == expectedBlurBounds);
903
904 SkIRect expectedShadowBounds = SkIRect::MakeLTRB(0, 0, 460, 460);
905 SkIRect shadowBounds = dropShadow->filterBounds(
906 bounds, scaleMatrix, SkImageFilter::kForward_MapDirection);
907 REPORTER_ASSERT(reporter, shadowBounds == expectedShadowBounds);
908 SkIRect expectedReverseShadowBounds =
909 SkIRect::MakeLTRB(-260, -260, 200, 200);
910 SkIRect reverseShadowBounds = dropShadow->filterBounds(
911 bounds, scaleMatrix, SkImageFilter::kReverse_MapDirection);
912 REPORTER_ASSERT(reporter,
913 reverseShadowBounds == expectedReverseShadowBounds);
914 }
915 {
916 // Vertical flip.
917 SkMatrix scaleMatrix;
918 scaleMatrix.setScale(1, -1);
919 SkIRect bounds = SkIRect::MakeLTRB(0, -100, 100, 0);
920
Herb Derby59f8f152017-10-17 22:27:23 +0000921 SkIRect expectedBlurBounds = SkIRect::MakeLTRB(-3, -103, 103, 3);
jbroman203a9932016-07-11 14:07:59 -0700922 SkIRect blurBounds = blur->filterBounds(
923 bounds, scaleMatrix, SkImageFilter::kForward_MapDirection);
924 REPORTER_ASSERT(reporter, blurBounds == expectedBlurBounds);
925 SkIRect reverseBlurBounds = blur->filterBounds(
926 bounds, scaleMatrix, SkImageFilter::kReverse_MapDirection);
927 REPORTER_ASSERT(reporter, reverseBlurBounds == expectedBlurBounds);
928
929 SkIRect expectedShadowBounds = SkIRect::MakeLTRB(0, -230, 230, 0);
930 SkIRect shadowBounds = dropShadow->filterBounds(
931 bounds, scaleMatrix, SkImageFilter::kForward_MapDirection);
932 REPORTER_ASSERT(reporter, shadowBounds == expectedShadowBounds);
933 SkIRect expectedReverseShadowBounds =
934 SkIRect::MakeLTRB(-130, -100, 100, 130);
935 SkIRect reverseShadowBounds = dropShadow->filterBounds(
936 bounds, scaleMatrix, SkImageFilter::kReverse_MapDirection);
937 REPORTER_ASSERT(reporter,
938 reverseShadowBounds == expectedReverseShadowBounds);
939 }
940}
941
ajuma5788faa2015-02-13 09:05:47 -0800942DEF_TEST(ImageFilterComposedBlurFastBounds, reporter) {
robertphillips6e7025a2016-04-04 04:31:25 -0700943 sk_sp<SkImageFilter> filter1(make_blur(nullptr));
944 sk_sp<SkImageFilter> filter2(make_blur(nullptr));
robertphillips491fb172016-03-30 12:32:58 -0700945 sk_sp<SkImageFilter> composedFilter(SkComposeImageFilter::Make(std::move(filter1),
946 std::move(filter2)));
ajuma5788faa2015-02-13 09:05:47 -0800947
948 SkRect boundsSrc = SkRect::MakeWH(SkIntToScalar(100), SkIntToScalar(100));
949 SkRect expectedBounds = SkRect::MakeXYWH(
Herb Derby59f8f152017-10-17 22:27:23 +0000950 SkIntToScalar(-6), SkIntToScalar(-6), SkIntToScalar(112), SkIntToScalar(112));
senorblancoe5e79842016-03-21 14:51:59 -0700951 SkRect boundsDst = composedFilter->computeFastBounds(boundsSrc);
ajuma5788faa2015-02-13 09:05:47 -0800952
953 REPORTER_ASSERT(reporter, boundsDst == expectedBounds);
954}
955
jbroman0e3129d2016-03-17 12:24:23 -0700956DEF_TEST(ImageFilterUnionBounds, reporter) {
robertphillips51a315e2016-03-31 09:05:49 -0700957 sk_sp<SkImageFilter> offset(SkOffsetImageFilter::Make(50, 0, nullptr));
jbroman0e3129d2016-03-17 12:24:23 -0700958 // Regardless of which order they appear in, the image filter bounds should
959 // be combined correctly.
960 {
reed374772b2016-10-05 17:33:02 -0700961 sk_sp<SkImageFilter> composite(SkXfermodeImageFilter::Make(SkBlendMode::kSrcOver, offset));
jbroman0e3129d2016-03-17 12:24:23 -0700962 SkRect bounds = SkRect::MakeWH(100, 100);
963 // Intentionally aliasing here, as that's what the real callers do.
senorblancoe5e79842016-03-21 14:51:59 -0700964 bounds = composite->computeFastBounds(bounds);
jbroman0e3129d2016-03-17 12:24:23 -0700965 REPORTER_ASSERT(reporter, bounds == SkRect::MakeWH(150, 100));
966 }
967 {
reed374772b2016-10-05 17:33:02 -0700968 sk_sp<SkImageFilter> composite(SkXfermodeImageFilter::Make(SkBlendMode::kSrcOver, nullptr,
robertphillips8c0326d2016-04-05 12:48:34 -0700969 offset, nullptr));
jbroman0e3129d2016-03-17 12:24:23 -0700970 SkRect bounds = SkRect::MakeWH(100, 100);
971 // Intentionally aliasing here, as that's what the real callers do.
senorblancoe5e79842016-03-21 14:51:59 -0700972 bounds = composite->computeFastBounds(bounds);
jbroman0e3129d2016-03-17 12:24:23 -0700973 REPORTER_ASSERT(reporter, bounds == SkRect::MakeWH(150, 100));
974 }
975}
976
robertphillips3e302272016-04-20 11:48:36 -0700977static void test_imagefilter_merge_result_size(skiatest::Reporter* reporter, GrContext* context) {
senorblanco4a243982015-11-25 07:06:55 -0800978 SkBitmap greenBM;
979 greenBM.allocN32Pixels(20, 20);
980 greenBM.eraseColor(SK_ColorGREEN);
reed9ce9d672016-03-17 10:51:11 -0700981 sk_sp<SkImage> greenImage(SkImage::MakeFromBitmap(greenBM));
robertphillips549c8992016-04-01 09:28:51 -0700982 sk_sp<SkImageFilter> source(SkImageSource::Make(std::move(greenImage)));
Mike Reed0bdaf052017-06-18 23:35:57 -0400983 sk_sp<SkImageFilter> merge(SkMergeImageFilter::Make(source, source));
senorblanco4a243982015-11-25 07:06:55 -0800984
robertphillips3e302272016-04-20 11:48:36 -0700985 sk_sp<SkSpecialImage> srcImg(create_empty_special_image(context, 1));
robertphillips4418dba2016-03-07 12:45:14 -0800986
brianosman2a75e5d2016-09-22 07:15:37 -0700987 SkImageFilter::OutputProperties noColorSpace(nullptr);
988 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeXYWH(0, 0, 100, 100), nullptr,
989 noColorSpace);
senorblanco4a243982015-11-25 07:06:55 -0800990 SkIPoint offset;
robertphillips4418dba2016-03-07 12:45:14 -0800991
robertphillips2302de92016-03-24 07:26:32 -0700992 sk_sp<SkSpecialImage> resultImg(merge->filterImage(srcImg.get(), ctx, &offset));
robertphillips4418dba2016-03-07 12:45:14 -0800993 REPORTER_ASSERT(reporter, resultImg);
994
995 REPORTER_ASSERT(reporter, resultImg->width() == 20 && resultImg->height() == 20);
senorblanco4a243982015-11-25 07:06:55 -0800996}
997
robertphillips4418dba2016-03-07 12:45:14 -0800998DEF_TEST(ImageFilterMergeResultSize, reporter) {
robertphillips3e302272016-04-20 11:48:36 -0700999 test_imagefilter_merge_result_size(reporter, nullptr);
robertphillips4418dba2016-03-07 12:45:14 -08001000}
1001
1002#if SK_SUPPORT_GPU
egdanielab527a52016-06-28 08:07:26 -07001003DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterMergeResultSize_Gpu, reporter, ctxInfo) {
bsalomon8b7451a2016-05-11 06:33:06 -07001004 test_imagefilter_merge_result_size(reporter, ctxInfo.grContext());
robertphillips4418dba2016-03-07 12:45:14 -08001005}
1006#endif
1007
robertphillipsa8d7f0b2014-08-29 08:03:56 -07001008static void draw_blurred_rect(SkCanvas* canvas) {
senorblanco837f5322014-07-14 10:19:54 -07001009 SkPaint filterPaint;
1010 filterPaint.setColor(SK_ColorWHITE);
robertphillips6e7025a2016-04-04 04:31:25 -07001011 filterPaint.setImageFilter(SkBlurImageFilter::Make(SkIntToScalar(8), 0, nullptr));
halcanary96fcdcc2015-08-27 07:41:13 -07001012 canvas->saveLayer(nullptr, &filterPaint);
senorblanco837f5322014-07-14 10:19:54 -07001013 SkPaint whitePaint;
1014 whitePaint.setColor(SK_ColorWHITE);
1015 canvas->drawRect(SkRect::Make(SkIRect::MakeWH(4, 4)), whitePaint);
1016 canvas->restore();
1017}
1018
robertphillipsa8d7f0b2014-08-29 08:03:56 -07001019static void draw_picture_clipped(SkCanvas* canvas, const SkRect& clipRect, const SkPicture* picture) {
senorblanco837f5322014-07-14 10:19:54 -07001020 canvas->save();
1021 canvas->clipRect(clipRect);
1022 canvas->drawPicture(picture);
1023 canvas->restore();
1024}
1025
1026DEF_TEST(ImageFilterDrawTiledBlurRTree, reporter) {
1027 // Check that the blur filter when recorded with RTree acceleration,
1028 // and drawn tiled (with subsequent clip rects) exactly
1029 // matches the same filter drawn with without RTree acceleration.
1030 // This tests that the "bleed" from the blur into the otherwise-blank
1031 // tiles is correctly rendered.
1032 // Tests pass by not asserting.
1033
1034 int width = 16, height = 8;
1035 SkBitmap result1, result2;
1036 result1.allocN32Pixels(width, height);
1037 result2.allocN32Pixels(width, height);
1038 SkCanvas canvas1(result1);
1039 SkCanvas canvas2(result2);
1040 int tileSize = 8;
1041
1042 canvas1.clear(0);
1043 canvas2.clear(0);
1044
1045 SkRTreeFactory factory;
1046
1047 SkPictureRecorder recorder1, recorder2;
1048 // The only difference between these two pictures is that one has RTree aceleration.
mtklein3f3b3d02014-12-01 11:47:08 -08001049 SkCanvas* recordingCanvas1 = recorder1.beginRecording(SkIntToScalar(width),
1050 SkIntToScalar(height),
halcanary96fcdcc2015-08-27 07:41:13 -07001051 nullptr, 0);
mtklein3f3b3d02014-12-01 11:47:08 -08001052 SkCanvas* recordingCanvas2 = recorder2.beginRecording(SkIntToScalar(width),
1053 SkIntToScalar(height),
robertphillipsa8d7f0b2014-08-29 08:03:56 -07001054 &factory, 0);
1055 draw_blurred_rect(recordingCanvas1);
1056 draw_blurred_rect(recordingCanvas2);
reedca2622b2016-03-18 07:25:55 -07001057 sk_sp<SkPicture> picture1(recorder1.finishRecordingAsPicture());
1058 sk_sp<SkPicture> picture2(recorder2.finishRecordingAsPicture());
senorblanco837f5322014-07-14 10:19:54 -07001059 for (int y = 0; y < height; y += tileSize) {
1060 for (int x = 0; x < width; x += tileSize) {
1061 SkRect tileRect = SkRect::Make(SkIRect::MakeXYWH(x, y, tileSize, tileSize));
reedca2622b2016-03-18 07:25:55 -07001062 draw_picture_clipped(&canvas1, tileRect, picture1.get());
1063 draw_picture_clipped(&canvas2, tileRect, picture2.get());
senorblanco837f5322014-07-14 10:19:54 -07001064 }
1065 }
1066 for (int y = 0; y < height; y++) {
1067 int diffs = memcmp(result1.getAddr32(0, y), result2.getAddr32(0, y), result1.rowBytes());
1068 REPORTER_ASSERT(reporter, !diffs);
1069 if (diffs) {
1070 break;
1071 }
1072 }
1073}
1074
senorblanco@chromium.org91957432014-05-01 14:03:41 +00001075DEF_TEST(ImageFilterMatrixConvolution, reporter) {
1076 // Check that a 1x3 filter does not cause a spurious assert.
1077 SkScalar kernel[3] = {
1078 SkIntToScalar( 1), SkIntToScalar( 1), SkIntToScalar( 1),
1079 };
1080 SkISize kernelSize = SkISize::Make(1, 3);
1081 SkScalar gain = SK_Scalar1, bias = 0;
1082 SkIPoint kernelOffset = SkIPoint::Make(0, 0);
1083
robertphillipsef6a47b2016-04-08 08:01:20 -07001084 sk_sp<SkImageFilter> filter(SkMatrixConvolutionImageFilter::Make(
1085 kernelSize, kernel,
1086 gain, bias, kernelOffset,
1087 SkMatrixConvolutionImageFilter::kRepeat_TileMode,
1088 false, nullptr));
senorblanco@chromium.org91957432014-05-01 14:03:41 +00001089
1090 SkBitmap result;
1091 int width = 16, height = 16;
1092 result.allocN32Pixels(width, height);
1093 SkCanvas canvas(result);
1094 canvas.clear(0);
1095
1096 SkPaint paint;
robertphillipsef6a47b2016-04-08 08:01:20 -07001097 paint.setImageFilter(std::move(filter));
senorblanco@chromium.org91957432014-05-01 14:03:41 +00001098 SkRect rect = SkRect::Make(SkIRect::MakeWH(width, height));
1099 canvas.drawRect(rect, paint);
1100}
1101
senorblanco@chromium.org8c7372b2014-05-02 19:13:11 +00001102DEF_TEST(ImageFilterMatrixConvolutionBorder, reporter) {
1103 // Check that a filter with borders outside the target bounds
1104 // does not crash.
1105 SkScalar kernel[3] = {
1106 0, 0, 0,
1107 };
1108 SkISize kernelSize = SkISize::Make(3, 1);
1109 SkScalar gain = SK_Scalar1, bias = 0;
1110 SkIPoint kernelOffset = SkIPoint::Make(2, 0);
1111
robertphillipsef6a47b2016-04-08 08:01:20 -07001112 sk_sp<SkImageFilter> filter(SkMatrixConvolutionImageFilter::Make(
1113 kernelSize, kernel, gain, bias, kernelOffset,
1114 SkMatrixConvolutionImageFilter::kClamp_TileMode,
1115 true, nullptr));
senorblanco@chromium.org8c7372b2014-05-02 19:13:11 +00001116
1117 SkBitmap result;
1118
1119 int width = 10, height = 10;
1120 result.allocN32Pixels(width, height);
1121 SkCanvas canvas(result);
1122 canvas.clear(0);
1123
1124 SkPaint filterPaint;
robertphillipsef6a47b2016-04-08 08:01:20 -07001125 filterPaint.setImageFilter(std::move(filter));
senorblanco@chromium.org8c7372b2014-05-02 19:13:11 +00001126 SkRect bounds = SkRect::MakeWH(1, 10);
1127 SkRect rect = SkRect::Make(SkIRect::MakeWH(width, height));
1128 SkPaint rectPaint;
1129 canvas.saveLayer(&bounds, &filterPaint);
1130 canvas.drawRect(rect, rectPaint);
1131 canvas.restore();
1132}
1133
robertphillips3e302272016-04-20 11:48:36 -07001134static void test_big_kernel(skiatest::Reporter* reporter, GrContext* context) {
robertphillipsdada4dd2016-04-13 04:54:36 -07001135 // Check that a kernel that is too big for the GPU still works
1136 SkScalar identityKernel[49] = {
1137 0, 0, 0, 0, 0, 0, 0,
1138 0, 0, 0, 0, 0, 0, 0,
1139 0, 0, 0, 0, 0, 0, 0,
1140 0, 0, 0, 1, 0, 0, 0,
1141 0, 0, 0, 0, 0, 0, 0,
1142 0, 0, 0, 0, 0, 0, 0,
1143 0, 0, 0, 0, 0, 0, 0
1144 };
1145 SkISize kernelSize = SkISize::Make(7, 7);
1146 SkScalar gain = SK_Scalar1, bias = 0;
1147 SkIPoint kernelOffset = SkIPoint::Make(0, 0);
1148
1149 sk_sp<SkImageFilter> filter(SkMatrixConvolutionImageFilter::Make(
1150 kernelSize, identityKernel, gain, bias, kernelOffset,
1151 SkMatrixConvolutionImageFilter::kClamp_TileMode,
1152 true, nullptr));
1153
robertphillips3e302272016-04-20 11:48:36 -07001154 sk_sp<SkSpecialImage> srcImg(create_empty_special_image(context, 100));
robertphillipsdada4dd2016-04-13 04:54:36 -07001155 SkASSERT(srcImg);
1156
1157 SkIPoint offset;
brianosman2a75e5d2016-09-22 07:15:37 -07001158 SkImageFilter::OutputProperties noColorSpace(nullptr);
1159 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeWH(100, 100), nullptr, noColorSpace);
robertphillipsdada4dd2016-04-13 04:54:36 -07001160 sk_sp<SkSpecialImage> resultImg(filter->filterImage(srcImg.get(), ctx, &offset));
1161 REPORTER_ASSERT(reporter, resultImg);
1162 REPORTER_ASSERT(reporter, SkToBool(context) == resultImg->isTextureBacked());
1163 REPORTER_ASSERT(reporter, resultImg->width() == 100 && resultImg->height() == 100);
1164 REPORTER_ASSERT(reporter, offset.fX == 0 && offset.fY == 0);
1165}
1166
1167DEF_TEST(ImageFilterMatrixConvolutionBigKernel, reporter) {
robertphillips3e302272016-04-20 11:48:36 -07001168 test_big_kernel(reporter, nullptr);
robertphillipsdada4dd2016-04-13 04:54:36 -07001169}
1170
1171#if SK_SUPPORT_GPU
egdanielab527a52016-06-28 08:07:26 -07001172DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterMatrixConvolutionBigKernel_Gpu,
1173 reporter, ctxInfo) {
bsalomon8b7451a2016-05-11 06:33:06 -07001174 test_big_kernel(reporter, ctxInfo.grContext());
robertphillipsdada4dd2016-04-13 04:54:36 -07001175}
1176#endif
1177
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +00001178DEF_TEST(ImageFilterCropRect, reporter) {
robertphillips3e302272016-04-20 11:48:36 -07001179 test_crop_rects(reporter, nullptr);
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +00001180}
1181
robertphillips4418dba2016-03-07 12:45:14 -08001182#if SK_SUPPORT_GPU
bsalomon68d91342016-04-12 09:59:58 -07001183DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterCropRect_Gpu, reporter, ctxInfo) {
bsalomon8b7451a2016-05-11 06:33:06 -07001184 test_crop_rects(reporter, ctxInfo.grContext());
robertphillips4418dba2016-03-07 12:45:14 -08001185}
1186#endif
1187
tfarina9ea53f92014-06-24 06:50:39 -07001188DEF_TEST(ImageFilterMatrix, reporter) {
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +00001189 SkBitmap temp;
mike@reedtribe.orgdeee4962014-02-13 14:41:43 +00001190 temp.allocN32Pixels(100, 100);
robertphillips9a53fd72015-06-22 09:46:59 -07001191 SkCanvas canvas(temp);
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +00001192 canvas.scale(SkIntToScalar(2), SkIntToScalar(2));
1193
1194 SkMatrix expectedMatrix = canvas.getTotalMatrix();
1195
commit-bot@chromium.org5fb2ce32014-04-17 23:35:06 +00001196 SkRTreeFactory factory;
1197 SkPictureRecorder recorder;
1198 SkCanvas* recordingCanvas = recorder.beginRecording(100, 100, &factory, 0);
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +00001199
1200 SkPaint paint;
robertphillips43c2ad42016-04-04 05:05:11 -07001201 paint.setImageFilter(MatrixTestImageFilter::Make(reporter, expectedMatrix));
halcanary96fcdcc2015-08-27 07:41:13 -07001202 recordingCanvas->saveLayer(nullptr, &paint);
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +00001203 SkPaint solidPaint;
1204 solidPaint.setColor(0xFFFFFFFF);
1205 recordingCanvas->save();
1206 recordingCanvas->scale(SkIntToScalar(10), SkIntToScalar(10));
1207 recordingCanvas->drawRect(SkRect::Make(SkIRect::MakeWH(100, 100)), solidPaint);
1208 recordingCanvas->restore(); // scale
1209 recordingCanvas->restore(); // saveLayer
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +00001210
reedca2622b2016-03-18 07:25:55 -07001211 canvas.drawPicture(recorder.finishRecordingAsPicture());
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +00001212}
1213
senorblanco3d822c22014-07-30 14:49:31 -07001214DEF_TEST(ImageFilterCrossProcessPictureImageFilter, reporter) {
senorblanco@chromium.org97f5fc62014-05-30 20:50:56 +00001215 SkRTreeFactory factory;
1216 SkPictureRecorder recorder;
1217 SkCanvas* recordingCanvas = recorder.beginRecording(1, 1, &factory, 0);
1218
1219 // Create an SkPicture which simply draws a green 1x1 rectangle.
1220 SkPaint greenPaint;
1221 greenPaint.setColor(SK_ColorGREEN);
1222 recordingCanvas->drawRect(SkRect::Make(SkIRect::MakeWH(1, 1)), greenPaint);
reedca2622b2016-03-18 07:25:55 -07001223 sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture());
senorblanco@chromium.org97f5fc62014-05-30 20:50:56 +00001224
1225 // Wrap that SkPicture in an SkPictureImageFilter.
robertphillips5ff17b12016-03-28 13:13:42 -07001226 sk_sp<SkImageFilter> imageFilter(SkPictureImageFilter::Make(picture));
senorblanco@chromium.org97f5fc62014-05-30 20:50:56 +00001227
1228 // Check that SkPictureImageFilter successfully serializes its contained
1229 // SkPicture when not in cross-process mode.
1230 SkPaint paint;
robertphillips5ff17b12016-03-28 13:13:42 -07001231 paint.setImageFilter(imageFilter);
senorblanco@chromium.org97f5fc62014-05-30 20:50:56 +00001232 SkPictureRecorder outerRecorder;
1233 SkCanvas* outerCanvas = outerRecorder.beginRecording(1, 1, &factory, 0);
1234 SkPaint redPaintWithFilter;
1235 redPaintWithFilter.setColor(SK_ColorRED);
robertphillips5ff17b12016-03-28 13:13:42 -07001236 redPaintWithFilter.setImageFilter(imageFilter);
senorblanco@chromium.org97f5fc62014-05-30 20:50:56 +00001237 outerCanvas->drawRect(SkRect::Make(SkIRect::MakeWH(1, 1)), redPaintWithFilter);
reedca2622b2016-03-18 07:25:55 -07001238 sk_sp<SkPicture> outerPicture(outerRecorder.finishRecordingAsPicture());
senorblanco@chromium.org97f5fc62014-05-30 20:50:56 +00001239
1240 SkBitmap bitmap;
1241 bitmap.allocN32Pixels(1, 1);
robertphillips9a53fd72015-06-22 09:46:59 -07001242 SkCanvas canvas(bitmap);
senorblanco@chromium.org97f5fc62014-05-30 20:50:56 +00001243
1244 // The result here should be green, since the filter replaces the primitive's red interior.
1245 canvas.clear(0x0);
robertphillips9b14f262014-06-04 05:40:44 -07001246 canvas.drawPicture(outerPicture);
senorblanco@chromium.org97f5fc62014-05-30 20:50:56 +00001247 uint32_t pixel = *bitmap.getAddr32(0, 0);
1248 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1249
1250 // Check that, for now, SkPictureImageFilter does not serialize or
1251 // deserialize its contained picture when the filter is serialized
1252 // cross-process. Do this by "laundering" it through SkValidatingReadBuffer.
robertphillips12fa47d2016-04-08 16:28:09 -07001253 sk_sp<SkData> data(SkValidatingSerializeFlattenable(imageFilter.get()));
Mike Reed5e257172016-11-01 11:22:05 -04001254 sk_sp<SkImageFilter> unflattenedFilter = SkValidatingDeserializeImageFilter(data->data(),
1255 data->size());
senorblanco@chromium.org97f5fc62014-05-30 20:50:56 +00001256
1257 redPaintWithFilter.setImageFilter(unflattenedFilter);
1258 SkPictureRecorder crossProcessRecorder;
1259 SkCanvas* crossProcessCanvas = crossProcessRecorder.beginRecording(1, 1, &factory, 0);
1260 crossProcessCanvas->drawRect(SkRect::Make(SkIRect::MakeWH(1, 1)), redPaintWithFilter);
reedca2622b2016-03-18 07:25:55 -07001261 sk_sp<SkPicture> crossProcessPicture(crossProcessRecorder.finishRecordingAsPicture());
senorblanco@chromium.org97f5fc62014-05-30 20:50:56 +00001262
1263 canvas.clear(0x0);
robertphillips9b14f262014-06-04 05:40:44 -07001264 canvas.drawPicture(crossProcessPicture);
senorblanco@chromium.org97f5fc62014-05-30 20:50:56 +00001265 pixel = *bitmap.getAddr32(0, 0);
hendrikw446ee672015-06-16 09:28:37 -07001266 // If the security precautions are enabled, the result here should not be green, since the
1267 // filter draws nothing.
mtklein2afbe232016-02-07 12:23:10 -08001268 REPORTER_ASSERT(reporter, SkPicture::PictureIOSecurityPrecautionsEnabled()
hendrikw446ee672015-06-16 09:28:37 -07001269 ? pixel != SK_ColorGREEN : pixel == SK_ColorGREEN);
senorblanco@chromium.org97f5fc62014-05-30 20:50:56 +00001270}
1271
robertphillips3e302272016-04-20 11:48:36 -07001272static void test_clipped_picture_imagefilter(skiatest::Reporter* reporter, GrContext* context) {
reedca2622b2016-03-18 07:25:55 -07001273 sk_sp<SkPicture> picture;
senorblanco3d822c22014-07-30 14:49:31 -07001274
robertphillips4418dba2016-03-07 12:45:14 -08001275 {
1276 SkRTreeFactory factory;
1277 SkPictureRecorder recorder;
1278 SkCanvas* recordingCanvas = recorder.beginRecording(1, 1, &factory, 0);
1279
1280 // Create an SkPicture which simply draws a green 1x1 rectangle.
1281 SkPaint greenPaint;
1282 greenPaint.setColor(SK_ColorGREEN);
1283 recordingCanvas->drawRect(SkRect::Make(SkIRect::MakeWH(1, 1)), greenPaint);
reedca2622b2016-03-18 07:25:55 -07001284 picture = recorder.finishRecordingAsPicture();
robertphillips4418dba2016-03-07 12:45:14 -08001285 }
1286
robertphillips3e302272016-04-20 11:48:36 -07001287 sk_sp<SkSpecialImage> srcImg(create_empty_special_image(context, 2));
senorblanco3d822c22014-07-30 14:49:31 -07001288
robertphillips5ff17b12016-03-28 13:13:42 -07001289 sk_sp<SkImageFilter> imageFilter(SkPictureImageFilter::Make(picture));
senorblanco3d822c22014-07-30 14:49:31 -07001290
senorblanco3d822c22014-07-30 14:49:31 -07001291 SkIPoint offset;
brianosman2a75e5d2016-09-22 07:15:37 -07001292 SkImageFilter::OutputProperties noColorSpace(nullptr);
1293 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeXYWH(1, 1, 1, 1), nullptr, noColorSpace);
robertphillips4418dba2016-03-07 12:45:14 -08001294
robertphillips2302de92016-03-24 07:26:32 -07001295 sk_sp<SkSpecialImage> resultImage(imageFilter->filterImage(srcImg.get(), ctx, &offset));
robertphillips4418dba2016-03-07 12:45:14 -08001296 REPORTER_ASSERT(reporter, !resultImage);
senorblanco3d822c22014-07-30 14:49:31 -07001297}
1298
robertphillips4418dba2016-03-07 12:45:14 -08001299DEF_TEST(ImageFilterClippedPictureImageFilter, reporter) {
robertphillips3e302272016-04-20 11:48:36 -07001300 test_clipped_picture_imagefilter(reporter, nullptr);
robertphillips4418dba2016-03-07 12:45:14 -08001301}
1302
1303#if SK_SUPPORT_GPU
bsalomon68d91342016-04-12 09:59:58 -07001304DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterClippedPictureImageFilter_Gpu, reporter, ctxInfo) {
bsalomon8b7451a2016-05-11 06:33:06 -07001305 test_clipped_picture_imagefilter(reporter, ctxInfo.grContext());
robertphillips4418dba2016-03-07 12:45:14 -08001306}
1307#endif
1308
tfarina9ea53f92014-06-24 06:50:39 -07001309DEF_TEST(ImageFilterEmptySaveLayer, reporter) {
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001310 // Even when there's an empty saveLayer()/restore(), ensure that an image
1311 // filter or color filter which affects transparent black still draws.
1312
1313 SkBitmap bitmap;
1314 bitmap.allocN32Pixels(10, 10);
robertphillips9a53fd72015-06-22 09:46:59 -07001315 SkCanvas canvas(bitmap);
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001316
1317 SkRTreeFactory factory;
1318 SkPictureRecorder recorder;
1319
robertphillips5605b562016-04-05 11:50:42 -07001320 sk_sp<SkColorFilter> green(SkColorFilter::MakeModeFilter(SK_ColorGREEN,
Mike Reed7d954ad2016-10-28 15:42:34 -04001321 SkBlendMode::kSrc));
robertphillips5605b562016-04-05 11:50:42 -07001322 sk_sp<SkImageFilter> imageFilter(SkColorFilterImageFilter::Make(green, nullptr));
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001323 SkPaint imageFilterPaint;
robertphillips5605b562016-04-05 11:50:42 -07001324 imageFilterPaint.setImageFilter(std::move(imageFilter));
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001325 SkPaint colorFilterPaint;
reedd053ce92016-03-22 10:17:23 -07001326 colorFilterPaint.setColorFilter(green);
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001327
1328 SkRect bounds = SkRect::MakeWH(10, 10);
1329
1330 SkCanvas* recordingCanvas = recorder.beginRecording(10, 10, &factory, 0);
1331 recordingCanvas->saveLayer(&bounds, &imageFilterPaint);
1332 recordingCanvas->restore();
reedca2622b2016-03-18 07:25:55 -07001333 sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture());
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001334
1335 canvas.clear(0);
robertphillips9b14f262014-06-04 05:40:44 -07001336 canvas.drawPicture(picture);
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001337 uint32_t pixel = *bitmap.getAddr32(0, 0);
1338 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1339
1340 recordingCanvas = recorder.beginRecording(10, 10, &factory, 0);
halcanary96fcdcc2015-08-27 07:41:13 -07001341 recordingCanvas->saveLayer(nullptr, &imageFilterPaint);
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001342 recordingCanvas->restore();
reedca2622b2016-03-18 07:25:55 -07001343 sk_sp<SkPicture> picture2(recorder.finishRecordingAsPicture());
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001344
1345 canvas.clear(0);
robertphillips9b14f262014-06-04 05:40:44 -07001346 canvas.drawPicture(picture2);
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001347 pixel = *bitmap.getAddr32(0, 0);
1348 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1349
1350 recordingCanvas = recorder.beginRecording(10, 10, &factory, 0);
1351 recordingCanvas->saveLayer(&bounds, &colorFilterPaint);
1352 recordingCanvas->restore();
reedca2622b2016-03-18 07:25:55 -07001353 sk_sp<SkPicture> picture3(recorder.finishRecordingAsPicture());
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001354
1355 canvas.clear(0);
robertphillips9b14f262014-06-04 05:40:44 -07001356 canvas.drawPicture(picture3);
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001357 pixel = *bitmap.getAddr32(0, 0);
1358 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1359}
1360
robertphillips9a53fd72015-06-22 09:46:59 -07001361static void test_huge_blur(SkCanvas* canvas, skiatest::Reporter* reporter) {
senorblanco@chromium.org09843fd2014-03-24 20:50:59 +00001362 SkBitmap bitmap;
1363 bitmap.allocN32Pixels(100, 100);
1364 bitmap.eraseARGB(0, 0, 0, 0);
1365
1366 // Check that a blur with an insane radius does not crash or assert.
senorblanco@chromium.org09843fd2014-03-24 20:50:59 +00001367 SkPaint paint;
robertphillips6e7025a2016-04-04 04:31:25 -07001368 paint.setImageFilter(SkBlurImageFilter::Make(SkIntToScalar(1<<30),
1369 SkIntToScalar(1<<30),
1370 nullptr));
reedda420b92015-12-16 08:38:15 -08001371 canvas->drawBitmap(bitmap, 0, 0, &paint);
senorblanco@chromium.org09843fd2014-03-24 20:50:59 +00001372}
1373
1374DEF_TEST(HugeBlurImageFilter, reporter) {
1375 SkBitmap temp;
1376 temp.allocN32Pixels(100, 100);
robertphillips9a53fd72015-06-22 09:46:59 -07001377 SkCanvas canvas(temp);
1378 test_huge_blur(&canvas, reporter);
senorblanco@chromium.org09843fd2014-03-24 20:50:59 +00001379}
1380
senorblanco21a465d2016-04-11 11:58:39 -07001381DEF_TEST(ImageFilterMatrixConvolutionSanityTest, reporter) {
senorblanco3a495202014-09-29 07:57:20 -07001382 SkScalar kernel[1] = { 0 };
1383 SkScalar gain = SK_Scalar1, bias = 0;
1384 SkIPoint kernelOffset = SkIPoint::Make(1, 1);
1385
halcanary96fcdcc2015-08-27 07:41:13 -07001386 // Check that an enormous (non-allocatable) kernel gives a nullptr filter.
robertphillipsef6a47b2016-04-08 08:01:20 -07001387 sk_sp<SkImageFilter> conv(SkMatrixConvolutionImageFilter::Make(
senorblanco3a495202014-09-29 07:57:20 -07001388 SkISize::Make(1<<30, 1<<30),
1389 kernel,
1390 gain,
1391 bias,
1392 kernelOffset,
1393 SkMatrixConvolutionImageFilter::kRepeat_TileMode,
robertphillipsef6a47b2016-04-08 08:01:20 -07001394 false,
1395 nullptr));
senorblanco3a495202014-09-29 07:57:20 -07001396
halcanary96fcdcc2015-08-27 07:41:13 -07001397 REPORTER_ASSERT(reporter, nullptr == conv.get());
senorblanco3a495202014-09-29 07:57:20 -07001398
halcanary96fcdcc2015-08-27 07:41:13 -07001399 // Check that a nullptr kernel gives a nullptr filter.
robertphillipsef6a47b2016-04-08 08:01:20 -07001400 conv = SkMatrixConvolutionImageFilter::Make(
senorblanco3a495202014-09-29 07:57:20 -07001401 SkISize::Make(1, 1),
halcanary96fcdcc2015-08-27 07:41:13 -07001402 nullptr,
senorblanco3a495202014-09-29 07:57:20 -07001403 gain,
1404 bias,
1405 kernelOffset,
1406 SkMatrixConvolutionImageFilter::kRepeat_TileMode,
robertphillipsef6a47b2016-04-08 08:01:20 -07001407 false,
1408 nullptr);
senorblanco3a495202014-09-29 07:57:20 -07001409
halcanary96fcdcc2015-08-27 07:41:13 -07001410 REPORTER_ASSERT(reporter, nullptr == conv.get());
senorblanco3a495202014-09-29 07:57:20 -07001411
halcanary96fcdcc2015-08-27 07:41:13 -07001412 // Check that a kernel width < 1 gives a nullptr filter.
robertphillipsef6a47b2016-04-08 08:01:20 -07001413 conv = SkMatrixConvolutionImageFilter::Make(
senorblanco3a495202014-09-29 07:57:20 -07001414 SkISize::Make(0, 1),
1415 kernel,
1416 gain,
1417 bias,
1418 kernelOffset,
1419 SkMatrixConvolutionImageFilter::kRepeat_TileMode,
robertphillipsef6a47b2016-04-08 08:01:20 -07001420 false,
1421 nullptr);
senorblanco3a495202014-09-29 07:57:20 -07001422
halcanary96fcdcc2015-08-27 07:41:13 -07001423 REPORTER_ASSERT(reporter, nullptr == conv.get());
senorblanco3a495202014-09-29 07:57:20 -07001424
halcanary96fcdcc2015-08-27 07:41:13 -07001425 // Check that kernel height < 1 gives a nullptr filter.
robertphillipsef6a47b2016-04-08 08:01:20 -07001426 conv = SkMatrixConvolutionImageFilter::Make(
senorblanco3a495202014-09-29 07:57:20 -07001427 SkISize::Make(1, -1),
1428 kernel,
1429 gain,
1430 bias,
1431 kernelOffset,
1432 SkMatrixConvolutionImageFilter::kRepeat_TileMode,
robertphillipsef6a47b2016-04-08 08:01:20 -07001433 false,
1434 nullptr);
senorblanco3a495202014-09-29 07:57:20 -07001435
halcanary96fcdcc2015-08-27 07:41:13 -07001436 REPORTER_ASSERT(reporter, nullptr == conv.get());
senorblanco3a495202014-09-29 07:57:20 -07001437}
1438
Mike Reedf1942192017-07-21 14:24:29 -04001439static void test_xfermode_cropped_input(SkSurface* surf, skiatest::Reporter* reporter) {
1440 auto canvas = surf->getCanvas();
robertphillips9a53fd72015-06-22 09:46:59 -07001441 canvas->clear(0);
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001442
1443 SkBitmap bitmap;
1444 bitmap.allocN32Pixels(1, 1);
1445 bitmap.eraseARGB(255, 255, 255, 255);
1446
robertphillips5605b562016-04-05 11:50:42 -07001447 sk_sp<SkColorFilter> green(SkColorFilter::MakeModeFilter(SK_ColorGREEN,
Mike Reed7d954ad2016-10-28 15:42:34 -04001448 SkBlendMode::kSrcIn));
robertphillips5605b562016-04-05 11:50:42 -07001449 sk_sp<SkImageFilter> greenFilter(SkColorFilterImageFilter::Make(green, nullptr));
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001450 SkImageFilter::CropRect cropRect(SkRect::MakeEmpty());
robertphillips5605b562016-04-05 11:50:42 -07001451 sk_sp<SkImageFilter> croppedOut(SkColorFilterImageFilter::Make(green, nullptr, &cropRect));
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001452
1453 // Check that an xfermode image filter whose input has been cropped out still draws the other
1454 // input. Also check that drawing with both inputs cropped out doesn't cause a GPU warning.
reed374772b2016-10-05 17:33:02 -07001455 SkBlendMode mode = SkBlendMode::kSrcOver;
robertphillips8c0326d2016-04-05 12:48:34 -07001456 sk_sp<SkImageFilter> xfermodeNoFg(SkXfermodeImageFilter::Make(mode, greenFilter,
1457 croppedOut, nullptr));
1458 sk_sp<SkImageFilter> xfermodeNoBg(SkXfermodeImageFilter::Make(mode, croppedOut,
1459 greenFilter, nullptr));
1460 sk_sp<SkImageFilter> xfermodeNoFgNoBg(SkXfermodeImageFilter::Make(mode, croppedOut,
1461 croppedOut, nullptr));
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001462
1463 SkPaint paint;
robertphillips8c0326d2016-04-05 12:48:34 -07001464 paint.setImageFilter(std::move(xfermodeNoFg));
reedda420b92015-12-16 08:38:15 -08001465 canvas->drawBitmap(bitmap, 0, 0, &paint); // drawSprite
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001466
1467 uint32_t pixel;
kkinnunena9d9a392015-03-06 07:16:00 -08001468 SkImageInfo info = SkImageInfo::Make(1, 1, kBGRA_8888_SkColorType, kUnpremul_SkAlphaType);
Mike Reedf1942192017-07-21 14:24:29 -04001469 surf->readPixels(info, &pixel, 4, 0, 0);
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001470 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1471
robertphillips8c0326d2016-04-05 12:48:34 -07001472 paint.setImageFilter(std::move(xfermodeNoBg));
reedda420b92015-12-16 08:38:15 -08001473 canvas->drawBitmap(bitmap, 0, 0, &paint); // drawSprite
Mike Reedf1942192017-07-21 14:24:29 -04001474 surf->readPixels(info, &pixel, 4, 0, 0);
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001475 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1476
robertphillips8c0326d2016-04-05 12:48:34 -07001477 paint.setImageFilter(std::move(xfermodeNoFgNoBg));
reedda420b92015-12-16 08:38:15 -08001478 canvas->drawBitmap(bitmap, 0, 0, &paint); // drawSprite
Mike Reedf1942192017-07-21 14:24:29 -04001479 surf->readPixels(info, &pixel, 4, 0, 0);
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001480 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1481}
1482
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001483DEF_TEST(ImageFilterNestedSaveLayer, reporter) {
1484 SkBitmap temp;
1485 temp.allocN32Pixels(50, 50);
robertphillips9a53fd72015-06-22 09:46:59 -07001486 SkCanvas canvas(temp);
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001487 canvas.clear(0x0);
1488
1489 SkBitmap bitmap;
1490 bitmap.allocN32Pixels(10, 10);
1491 bitmap.eraseColor(SK_ColorGREEN);
1492
1493 SkMatrix matrix;
1494 matrix.setScale(SkIntToScalar(2), SkIntToScalar(2));
1495 matrix.postTranslate(SkIntToScalar(-20), SkIntToScalar(-20));
robertphillipsae8c9332016-04-05 15:09:00 -07001496 sk_sp<SkImageFilter> matrixFilter(
1497 SkImageFilter::MakeMatrixFilter(matrix, kLow_SkFilterQuality, nullptr));
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001498
1499 // Test that saveLayer() with a filter nested inside another saveLayer() applies the
1500 // correct offset to the filter matrix.
1501 SkRect bounds1 = SkRect::MakeXYWH(10, 10, 30, 30);
halcanary96fcdcc2015-08-27 07:41:13 -07001502 canvas.saveLayer(&bounds1, nullptr);
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001503 SkPaint filterPaint;
robertphillipsae8c9332016-04-05 15:09:00 -07001504 filterPaint.setImageFilter(std::move(matrixFilter));
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001505 SkRect bounds2 = SkRect::MakeXYWH(20, 20, 10, 10);
1506 canvas.saveLayer(&bounds2, &filterPaint);
1507 SkPaint greenPaint;
1508 greenPaint.setColor(SK_ColorGREEN);
1509 canvas.drawRect(bounds2, greenPaint);
1510 canvas.restore();
1511 canvas.restore();
1512 SkPaint strokePaint;
1513 strokePaint.setStyle(SkPaint::kStroke_Style);
1514 strokePaint.setColor(SK_ColorRED);
1515
kkinnunena9d9a392015-03-06 07:16:00 -08001516 SkImageInfo info = SkImageInfo::Make(1, 1, kBGRA_8888_SkColorType, kUnpremul_SkAlphaType);
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001517 uint32_t pixel;
Mike Reedf1942192017-07-21 14:24:29 -04001518 temp.readPixels(info, &pixel, 4, 25, 25);
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001519 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1520
1521 // Test that drawSprite() with a filter nested inside a saveLayer() applies the
1522 // correct offset to the filter matrix.
1523 canvas.clear(0x0);
Mike Reedf1942192017-07-21 14:24:29 -04001524 temp.readPixels(info, &pixel, 4, 25, 25);
halcanary96fcdcc2015-08-27 07:41:13 -07001525 canvas.saveLayer(&bounds1, nullptr);
reedda420b92015-12-16 08:38:15 -08001526 canvas.drawBitmap(bitmap, 20, 20, &filterPaint); // drawSprite
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001527 canvas.restore();
1528
Mike Reedf1942192017-07-21 14:24:29 -04001529 temp.readPixels(info, &pixel, 4, 25, 25);
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001530 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1531}
1532
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001533DEF_TEST(XfermodeImageFilterCroppedInput, reporter) {
Mike Reedf1942192017-07-21 14:24:29 -04001534 test_xfermode_cropped_input(SkSurface::MakeRasterN32Premul(100, 100).get(), reporter);
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001535}
senorblanco@chromium.org09843fd2014-03-24 20:50:59 +00001536
robertphillips3e302272016-04-20 11:48:36 -07001537static void test_composed_imagefilter_offset(skiatest::Reporter* reporter, GrContext* context) {
1538 sk_sp<SkSpecialImage> srcImg(create_empty_special_image(context, 100));
ajuma5788faa2015-02-13 09:05:47 -08001539
1540 SkImageFilter::CropRect cropRect(SkRect::MakeXYWH(1, 0, 20, 20));
robertphillips51a315e2016-03-31 09:05:49 -07001541 sk_sp<SkImageFilter> offsetFilter(SkOffsetImageFilter::Make(0, 0, nullptr, &cropRect));
robertphillips6e7025a2016-04-04 04:31:25 -07001542 sk_sp<SkImageFilter> blurFilter(SkBlurImageFilter::Make(SK_Scalar1, SK_Scalar1,
1543 nullptr, &cropRect));
robertphillips491fb172016-03-30 12:32:58 -07001544 sk_sp<SkImageFilter> composedFilter(SkComposeImageFilter::Make(std::move(blurFilter),
1545 std::move(offsetFilter)));
ajuma5788faa2015-02-13 09:05:47 -08001546 SkIPoint offset;
brianosman2a75e5d2016-09-22 07:15:37 -07001547 SkImageFilter::OutputProperties noColorSpace(nullptr);
1548 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeWH(100, 100), nullptr, noColorSpace);
robertphillips4418dba2016-03-07 12:45:14 -08001549
robertphillips2302de92016-03-24 07:26:32 -07001550 sk_sp<SkSpecialImage> resultImg(composedFilter->filterImage(srcImg.get(), ctx, &offset));
robertphillips4418dba2016-03-07 12:45:14 -08001551 REPORTER_ASSERT(reporter, resultImg);
ajuma5788faa2015-02-13 09:05:47 -08001552 REPORTER_ASSERT(reporter, offset.fX == 1 && offset.fY == 0);
1553}
1554
robertphillips4418dba2016-03-07 12:45:14 -08001555DEF_TEST(ComposedImageFilterOffset, reporter) {
robertphillips3e302272016-04-20 11:48:36 -07001556 test_composed_imagefilter_offset(reporter, nullptr);
robertphillips4418dba2016-03-07 12:45:14 -08001557}
1558
1559#if SK_SUPPORT_GPU
bsalomon68d91342016-04-12 09:59:58 -07001560DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ComposedImageFilterOffset_Gpu, reporter, ctxInfo) {
bsalomon8b7451a2016-05-11 06:33:06 -07001561 test_composed_imagefilter_offset(reporter, ctxInfo.grContext());
robertphillips4418dba2016-03-07 12:45:14 -08001562}
1563#endif
1564
robertphillips3e302272016-04-20 11:48:36 -07001565static void test_composed_imagefilter_bounds(skiatest::Reporter* reporter, GrContext* context) {
jbroman17a65202016-03-21 08:38:58 -07001566 // The bounds passed to the inner filter must be filtered by the outer
1567 // filter, so that the inner filter produces the pixels that the outer
1568 // filter requires as input. This matters if the outer filter moves pixels.
1569 // Here, accounting for the outer offset is necessary so that the green
1570 // pixels of the picture are not clipped.
1571
1572 SkPictureRecorder recorder;
1573 SkCanvas* recordingCanvas = recorder.beginRecording(SkRect::MakeWH(200, 100));
1574 recordingCanvas->clipRect(SkRect::MakeXYWH(100, 0, 100, 100));
1575 recordingCanvas->clear(SK_ColorGREEN);
robertphillips491fb172016-03-30 12:32:58 -07001576 sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture());
robertphillips5ff17b12016-03-28 13:13:42 -07001577 sk_sp<SkImageFilter> pictureFilter(SkPictureImageFilter::Make(picture));
jbroman17a65202016-03-21 08:38:58 -07001578 SkImageFilter::CropRect cropRect(SkRect::MakeWH(100, 100));
robertphillips51a315e2016-03-31 09:05:49 -07001579 sk_sp<SkImageFilter> offsetFilter(SkOffsetImageFilter::Make(-100, 0, nullptr, &cropRect));
robertphillips491fb172016-03-30 12:32:58 -07001580 sk_sp<SkImageFilter> composedFilter(SkComposeImageFilter::Make(std::move(offsetFilter),
1581 std::move(pictureFilter)));
jbroman17a65202016-03-21 08:38:58 -07001582
robertphillips3e302272016-04-20 11:48:36 -07001583 sk_sp<SkSpecialImage> sourceImage(create_empty_special_image(context, 100));
brianosman2a75e5d2016-09-22 07:15:37 -07001584 SkImageFilter::OutputProperties noColorSpace(nullptr);
1585 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeWH(100, 100), nullptr, noColorSpace);
jbroman17a65202016-03-21 08:38:58 -07001586 SkIPoint offset;
1587 sk_sp<SkSpecialImage> result(composedFilter->filterImage(sourceImage.get(), ctx, &offset));
1588 REPORTER_ASSERT(reporter, offset.isZero());
1589 REPORTER_ASSERT(reporter, result);
1590 REPORTER_ASSERT(reporter, result->subset().size() == SkISize::Make(100, 100));
1591
1592 SkBitmap resultBM;
robertphillips64612512016-04-08 12:10:42 -07001593 REPORTER_ASSERT(reporter, result->getROPixels(&resultBM));
jbroman17a65202016-03-21 08:38:58 -07001594 REPORTER_ASSERT(reporter, resultBM.getColor(50, 50) == SK_ColorGREEN);
1595}
1596
1597DEF_TEST(ComposedImageFilterBounds, reporter) {
robertphillips3e302272016-04-20 11:48:36 -07001598 test_composed_imagefilter_bounds(reporter, nullptr);
jbroman17a65202016-03-21 08:38:58 -07001599}
1600
1601#if SK_SUPPORT_GPU
egdanielab527a52016-06-28 08:07:26 -07001602DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ComposedImageFilterBounds_Gpu, reporter, ctxInfo) {
bsalomon8b7451a2016-05-11 06:33:06 -07001603 test_composed_imagefilter_bounds(reporter, ctxInfo.grContext());
jbroman17a65202016-03-21 08:38:58 -07001604}
1605#endif
1606
robertphillips3e302272016-04-20 11:48:36 -07001607static void test_partial_crop_rect(skiatest::Reporter* reporter, GrContext* context) {
1608 sk_sp<SkSpecialImage> srcImg(create_empty_special_image(context, 100));
senorblanco24d2a7b2015-07-13 10:27:05 -07001609
1610 SkImageFilter::CropRect cropRect(SkRect::MakeXYWH(100, 0, 20, 30),
senorblancoed7cf272015-07-16 15:19:11 -07001611 SkImageFilter::CropRect::kHasWidth_CropEdge | SkImageFilter::CropRect::kHasHeight_CropEdge);
robertphillips5605b562016-04-05 11:50:42 -07001612 sk_sp<SkImageFilter> filter(make_grayscale(nullptr, &cropRect));
senorblanco24d2a7b2015-07-13 10:27:05 -07001613 SkIPoint offset;
brianosman2a75e5d2016-09-22 07:15:37 -07001614 SkImageFilter::OutputProperties noColorSpace(nullptr);
1615 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeWH(100, 100), nullptr, noColorSpace);
robertphillips4418dba2016-03-07 12:45:14 -08001616
robertphillips2302de92016-03-24 07:26:32 -07001617 sk_sp<SkSpecialImage> resultImg(filter->filterImage(srcImg.get(), ctx, &offset));
robertphillips4418dba2016-03-07 12:45:14 -08001618 REPORTER_ASSERT(reporter, resultImg);
1619
senorblanco24d2a7b2015-07-13 10:27:05 -07001620 REPORTER_ASSERT(reporter, offset.fX == 0);
1621 REPORTER_ASSERT(reporter, offset.fY == 0);
robertphillips4418dba2016-03-07 12:45:14 -08001622 REPORTER_ASSERT(reporter, resultImg->width() == 20);
1623 REPORTER_ASSERT(reporter, resultImg->height() == 30);
senorblanco24d2a7b2015-07-13 10:27:05 -07001624}
1625
senorblanco21a465d2016-04-11 11:58:39 -07001626DEF_TEST(ImageFilterPartialCropRect, reporter) {
robertphillips3e302272016-04-20 11:48:36 -07001627 test_partial_crop_rect(reporter, nullptr);
robertphillips4418dba2016-03-07 12:45:14 -08001628}
1629
1630#if SK_SUPPORT_GPU
bsalomon68d91342016-04-12 09:59:58 -07001631DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterPartialCropRect_Gpu, reporter, ctxInfo) {
bsalomon8b7451a2016-05-11 06:33:06 -07001632 test_partial_crop_rect(reporter, ctxInfo.grContext());
robertphillips4418dba2016-03-07 12:45:14 -08001633}
1634#endif
1635
senorblanco0abdf762015-08-20 11:10:41 -07001636DEF_TEST(ImageFilterCanComputeFastBounds, reporter) {
1637
robertphillips12fa47d2016-04-08 16:28:09 -07001638 {
1639 SkPoint3 location = SkPoint3::Make(0, 0, SK_Scalar1);
1640 sk_sp<SkImageFilter> lighting(SkLightingImageFilter::MakePointLitDiffuse(location,
1641 SK_ColorGREEN,
1642 0, 0, nullptr));
1643 REPORTER_ASSERT(reporter, !lighting->canComputeFastBounds());
1644 }
senorblanco0abdf762015-08-20 11:10:41 -07001645
senorblanco0abdf762015-08-20 11:10:41 -07001646 {
robertphillips6e7025a2016-04-04 04:31:25 -07001647 sk_sp<SkImageFilter> gray(make_grayscale(nullptr, nullptr));
1648 REPORTER_ASSERT(reporter, gray->canComputeFastBounds());
1649 {
1650 SkColorFilter* grayCF;
1651 REPORTER_ASSERT(reporter, gray->asAColorFilter(&grayCF));
1652 REPORTER_ASSERT(reporter, !grayCF->affectsTransparentBlack());
1653 grayCF->unref();
1654 }
1655 REPORTER_ASSERT(reporter, gray->canComputeFastBounds());
1656
1657 sk_sp<SkImageFilter> grayBlur(SkBlurImageFilter::Make(SK_Scalar1, SK_Scalar1,
1658 std::move(gray)));
1659 REPORTER_ASSERT(reporter, grayBlur->canComputeFastBounds());
senorblanco0abdf762015-08-20 11:10:41 -07001660 }
senorblanco0abdf762015-08-20 11:10:41 -07001661
robertphillips6e7025a2016-04-04 04:31:25 -07001662 {
1663 SkScalar greenMatrix[20] = { 0, 0, 0, 0, 0,
1664 0, 0, 0, 0, 1,
1665 0, 0, 0, 0, 0,
1666 0, 0, 0, 0, 1 };
1667 sk_sp<SkColorFilter> greenCF(SkColorFilter::MakeMatrixFilterRowMajor255(greenMatrix));
robertphillips5605b562016-04-05 11:50:42 -07001668 sk_sp<SkImageFilter> green(SkColorFilterImageFilter::Make(greenCF, nullptr));
senorblanco0abdf762015-08-20 11:10:41 -07001669
robertphillips6e7025a2016-04-04 04:31:25 -07001670 REPORTER_ASSERT(reporter, greenCF->affectsTransparentBlack());
1671 REPORTER_ASSERT(reporter, !green->canComputeFastBounds());
senorblanco0abdf762015-08-20 11:10:41 -07001672
robertphillips6e7025a2016-04-04 04:31:25 -07001673 sk_sp<SkImageFilter> greenBlur(SkBlurImageFilter::Make(SK_Scalar1, SK_Scalar1,
1674 std::move(green)));
1675 REPORTER_ASSERT(reporter, !greenBlur->canComputeFastBounds());
1676 }
senorblanco0abdf762015-08-20 11:10:41 -07001677
1678 uint8_t allOne[256], identity[256];
1679 for (int i = 0; i < 256; ++i) {
1680 identity[i] = i;
1681 allOne[i] = 255;
1682 }
1683
robertphillips5605b562016-04-05 11:50:42 -07001684 sk_sp<SkColorFilter> identityCF(SkTableColorFilter::MakeARGB(identity, identity,
1685 identity, allOne));
1686 sk_sp<SkImageFilter> identityFilter(SkColorFilterImageFilter::Make(identityCF, nullptr));
senorblanco0abdf762015-08-20 11:10:41 -07001687 REPORTER_ASSERT(reporter, !identityCF->affectsTransparentBlack());
1688 REPORTER_ASSERT(reporter, identityFilter->canComputeFastBounds());
1689
robertphillips5605b562016-04-05 11:50:42 -07001690 sk_sp<SkColorFilter> forceOpaqueCF(SkTableColorFilter::MakeARGB(allOne, identity,
1691 identity, identity));
1692 sk_sp<SkImageFilter> forceOpaque(SkColorFilterImageFilter::Make(forceOpaqueCF, nullptr));
senorblanco0abdf762015-08-20 11:10:41 -07001693 REPORTER_ASSERT(reporter, forceOpaqueCF->affectsTransparentBlack());
1694 REPORTER_ASSERT(reporter, !forceOpaque->canComputeFastBounds());
1695}
1696
fmalitacd56f812015-09-14 13:31:18 -07001697// Verify that SkImageSource survives serialization
1698DEF_TEST(ImageFilterImageSourceSerialization, reporter) {
reede8f30622016-03-23 18:59:25 -07001699 auto surface(SkSurface::MakeRasterN32Premul(10, 10));
fmalitacd56f812015-09-14 13:31:18 -07001700 surface->getCanvas()->clear(SK_ColorGREEN);
reed9ce9d672016-03-17 10:51:11 -07001701 sk_sp<SkImage> image(surface->makeImageSnapshot());
robertphillips549c8992016-04-01 09:28:51 -07001702 sk_sp<SkImageFilter> filter(SkImageSource::Make(std::move(image)));
fmalitacd56f812015-09-14 13:31:18 -07001703
robertphillips549c8992016-04-01 09:28:51 -07001704 sk_sp<SkData> data(SkValidatingSerializeFlattenable(filter.get()));
Mike Reed5e257172016-11-01 11:22:05 -04001705 sk_sp<SkImageFilter> unflattenedFilter = SkValidatingDeserializeImageFilter(data->data(),
1706 data->size());
fmalitacd56f812015-09-14 13:31:18 -07001707 REPORTER_ASSERT(reporter, unflattenedFilter);
1708
1709 SkBitmap bm;
1710 bm.allocN32Pixels(10, 10);
fmalita23cb88c2015-09-15 06:56:23 -07001711 bm.eraseColor(SK_ColorBLUE);
fmalitacd56f812015-09-14 13:31:18 -07001712 SkPaint paint;
1713 paint.setColor(SK_ColorRED);
1714 paint.setImageFilter(unflattenedFilter);
1715
1716 SkCanvas canvas(bm);
1717 canvas.drawRect(SkRect::MakeWH(10, 10), paint);
1718 REPORTER_ASSERT(reporter, *bm.getAddr32(0, 0) == SkPreMultiplyColor(SK_ColorGREEN));
1719}
1720
Leon Scroggins III4cdbf602017-09-28 14:33:57 -04001721DEF_TEST(ImageFilterImageSourceUninitialized, r) {
1722 sk_sp<SkData> data(GetResourceAsData("crbug769134.fil"));
1723 if (!data) {
1724 return;
1725 }
1726 sk_sp<SkImageFilter> unflattenedFilter = SkValidatingDeserializeImageFilter(data->data(),
1727 data->size());
1728 // This will fail. More importantly, msan will verify that we did not
1729 // compare against uninitialized memory.
1730 REPORTER_ASSERT(r, !unflattenedFilter);
1731}
1732
bsalomon45eefcf2016-01-05 08:39:28 -08001733static void test_large_blur_input(skiatest::Reporter* reporter, SkCanvas* canvas) {
1734 SkBitmap largeBmp;
1735 int largeW = 5000;
1736 int largeH = 5000;
1737#if SK_SUPPORT_GPU
1738 // If we're GPU-backed make the bitmap too large to be converted into a texture.
1739 if (GrContext* ctx = canvas->getGrContext()) {
1740 largeW = ctx->caps()->maxTextureSize() + 1;
1741 }
1742#endif
1743
1744 largeBmp.allocN32Pixels(largeW, largeH);
mtklein2afbe232016-02-07 12:23:10 -08001745 largeBmp.eraseColor(0);
bsalomon45eefcf2016-01-05 08:39:28 -08001746 if (!largeBmp.getPixels()) {
1747 ERRORF(reporter, "Failed to allocate large bmp.");
1748 return;
1749 }
1750
reed9ce9d672016-03-17 10:51:11 -07001751 sk_sp<SkImage> largeImage(SkImage::MakeFromBitmap(largeBmp));
bsalomon45eefcf2016-01-05 08:39:28 -08001752 if (!largeImage) {
1753 ERRORF(reporter, "Failed to create large image.");
1754 return;
1755 }
1756
robertphillips549c8992016-04-01 09:28:51 -07001757 sk_sp<SkImageFilter> largeSource(SkImageSource::Make(std::move(largeImage)));
bsalomon45eefcf2016-01-05 08:39:28 -08001758 if (!largeSource) {
1759 ERRORF(reporter, "Failed to create large SkImageSource.");
1760 return;
1761 }
1762
robertphillips6e7025a2016-04-04 04:31:25 -07001763 sk_sp<SkImageFilter> blur(SkBlurImageFilter::Make(10.f, 10.f, std::move(largeSource)));
bsalomon45eefcf2016-01-05 08:39:28 -08001764 if (!blur) {
1765 ERRORF(reporter, "Failed to create SkBlurImageFilter.");
1766 return;
1767 }
1768
1769 SkPaint paint;
robertphillips549c8992016-04-01 09:28:51 -07001770 paint.setImageFilter(std::move(blur));
bsalomon45eefcf2016-01-05 08:39:28 -08001771
1772 // This should not crash (http://crbug.com/570479).
1773 canvas->drawRect(SkRect::MakeIWH(largeW, largeH), paint);
1774}
1775
senorblanco21a465d2016-04-11 11:58:39 -07001776DEF_TEST(ImageFilterBlurLargeImage, reporter) {
reede8f30622016-03-23 18:59:25 -07001777 auto surface(SkSurface::MakeRaster(SkImageInfo::MakeN32Premul(100, 100)));
bsalomon45eefcf2016-01-05 08:39:28 -08001778 test_large_blur_input(reporter, surface->getCanvas());
1779}
1780
senorblanco5878dbd2016-05-19 14:50:29 -07001781static void test_make_with_filter(skiatest::Reporter* reporter, GrContext* context) {
Robert Phillipsa5fdc972017-02-18 16:58:09 -05001782 sk_sp<SkSurface> surface(create_surface(context, 192, 128));
senorblanco5878dbd2016-05-19 14:50:29 -07001783 surface->getCanvas()->clear(SK_ColorRED);
1784 SkPaint bluePaint;
1785 bluePaint.setColor(SK_ColorBLUE);
1786 SkIRect subset = SkIRect::MakeXYWH(25, 20, 50, 50);
1787 surface->getCanvas()->drawRect(SkRect::Make(subset), bluePaint);
1788 sk_sp<SkImage> sourceImage = surface->makeImageSnapshot();
1789
1790 sk_sp<SkImageFilter> filter = make_grayscale(nullptr, nullptr);
1791 SkIRect clipBounds = SkIRect::MakeXYWH(30, 35, 100, 100);
1792 SkIRect outSubset;
1793 SkIPoint offset;
1794 sk_sp<SkImage> result;
1795
1796 result = sourceImage->makeWithFilter(nullptr, subset, clipBounds, &outSubset, &offset);
1797 REPORTER_ASSERT(reporter, !result);
1798
1799 result = sourceImage->makeWithFilter(filter.get(), subset, clipBounds, nullptr, &offset);
1800 REPORTER_ASSERT(reporter, !result);
1801
1802 result = sourceImage->makeWithFilter(filter.get(), subset, clipBounds, &outSubset, nullptr);
1803 REPORTER_ASSERT(reporter, !result);
1804
1805 SkIRect bigSubset = SkIRect::MakeXYWH(-10000, -10000, 20000, 20000);
1806 result = sourceImage->makeWithFilter(filter.get(), bigSubset, clipBounds, &outSubset, &offset);
1807 REPORTER_ASSERT(reporter, !result);
1808
1809 SkIRect empty = SkIRect::MakeEmpty();
1810 result = sourceImage->makeWithFilter(filter.get(), empty, clipBounds, &outSubset, &offset);
1811 REPORTER_ASSERT(reporter, !result);
1812
1813 result = sourceImage->makeWithFilter(filter.get(), subset, empty, &outSubset, &offset);
1814 REPORTER_ASSERT(reporter, !result);
1815
1816 SkIRect leftField = SkIRect::MakeXYWH(-1000, 0, 100, 100);
1817 result = sourceImage->makeWithFilter(filter.get(), subset, leftField, &outSubset, &offset);
1818 REPORTER_ASSERT(reporter, !result);
1819
1820 result = sourceImage->makeWithFilter(filter.get(), subset, clipBounds, &outSubset, &offset);
1821
1822 REPORTER_ASSERT(reporter, result);
1823 REPORTER_ASSERT(reporter, result->bounds().contains(outSubset));
1824 SkIRect destRect = SkIRect::MakeXYWH(offset.x(), offset.y(),
1825 outSubset.width(), outSubset.height());
1826 REPORTER_ASSERT(reporter, clipBounds.contains(destRect));
Robert Phillipsa5fdc972017-02-18 16:58:09 -05001827
1828 // In GPU-mode, this case creates a special image with a backing size that differs from
1829 // the content size
1830 {
1831 clipBounds.setXYWH(0, 0, 170, 100);
1832 subset.setXYWH(0, 0, 160, 90);
1833
1834 filter = SkXfermodeImageFilter::Make(SkBlendMode::kSrc, nullptr);
1835 result = sourceImage->makeWithFilter(filter.get(), subset, clipBounds, &outSubset, &offset);
1836 REPORTER_ASSERT(reporter, result);
1837 }
senorblanco5878dbd2016-05-19 14:50:29 -07001838}
1839
1840DEF_TEST(ImageFilterMakeWithFilter, reporter) {
1841 test_make_with_filter(reporter, nullptr);
1842}
1843
1844#if SK_SUPPORT_GPU
1845DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterMakeWithFilter_Gpu, reporter, ctxInfo) {
1846 test_make_with_filter(reporter, ctxInfo.grContext());
1847}
1848#endif
1849
senorblanco@chromium.org58d14662014-02-03 22:36:39 +00001850#if SK_SUPPORT_GPU
reed4a8126e2014-09-22 07:29:03 -07001851
bsalomon68d91342016-04-12 09:59:58 -07001852DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterHugeBlur_Gpu, reporter, ctxInfo) {
robertphillipsefbffed2015-06-22 12:06:08 -07001853
bsalomon8b7451a2016-05-11 06:33:06 -07001854 sk_sp<SkSurface> surf(SkSurface::MakeRenderTarget(ctxInfo.grContext(),
robertphillips3e302272016-04-20 11:48:36 -07001855 SkBudgeted::kNo,
1856 SkImageInfo::MakeN32Premul(100, 100)));
robertphillips9a53fd72015-06-22 09:46:59 -07001857
robertphillips3e302272016-04-20 11:48:36 -07001858
1859 SkCanvas* canvas = surf->getCanvas();
1860
1861 test_huge_blur(canvas, reporter);
senorblanco@chromium.org09843fd2014-03-24 20:50:59 +00001862}
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001863
egdanielab527a52016-06-28 08:07:26 -07001864DEF_GPUTEST_FOR_RENDERING_CONTEXTS(XfermodeImageFilterCroppedInput_Gpu, reporter, ctxInfo) {
Brian Salomon8996e182017-07-05 17:01:48 -04001865 sk_sp<SkSurface> surf(SkSurface::MakeRenderTarget(
1866 ctxInfo.grContext(),
1867 SkBudgeted::kNo,
1868 SkImageInfo::Make(1, 1, kRGBA_8888_SkColorType, kPremul_SkAlphaType)));
robertphillips3e302272016-04-20 11:48:36 -07001869
Mike Reedf1942192017-07-21 14:24:29 -04001870 test_xfermode_cropped_input(surf.get(), reporter);
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001871}
senorblanco32673b92014-09-09 09:15:04 -07001872
egdanielab527a52016-06-28 08:07:26 -07001873DEF_GPUTEST_FOR_ALL_CONTEXTS(ImageFilterBlurLargeImage_Gpu, reporter, ctxInfo) {
Brian Salomon8996e182017-07-05 17:01:48 -04001874 auto surface(SkSurface::MakeRenderTarget(
1875 ctxInfo.grContext(), SkBudgeted::kYes,
1876 SkImageInfo::Make(100, 100, kRGBA_8888_SkColorType, kPremul_SkAlphaType)));
bsalomon45eefcf2016-01-05 08:39:28 -08001877 test_large_blur_input(reporter, surface->getCanvas());
1878}
senorblanco@chromium.org58d14662014-02-03 22:36:39 +00001879#endif
reedbb34a8a2016-04-23 15:19:07 -07001880
1881/*
1882 * Test that colorfilterimagefilter does not require its CTM to be decomposed when it has more
1883 * than just scale/translate, but that other filters do.
1884 */
reed96a04f32016-04-25 09:25:15 -07001885DEF_TEST(ImageFilterComplexCTM, reporter) {
reedbb34a8a2016-04-23 15:19:07 -07001886 // just need a colorfilter to exercise the corresponding imagefilter
Mike Reed7d954ad2016-10-28 15:42:34 -04001887 sk_sp<SkColorFilter> cf = SkColorFilter::MakeModeFilter(SK_ColorRED, SkBlendMode::kSrcATop);
reed96a04f32016-04-25 09:25:15 -07001888 sk_sp<SkImageFilter> cfif = SkColorFilterImageFilter::Make(cf, nullptr); // can handle
1889 sk_sp<SkImageFilter> blif = SkBlurImageFilter::Make(3, 3, nullptr); // cannot handle
reedbb34a8a2016-04-23 15:19:07 -07001890
1891 struct {
1892 sk_sp<SkImageFilter> fFilter;
1893 bool fExpectCanHandle;
1894 } recs[] = {
1895 { cfif, true },
1896 { SkColorFilterImageFilter::Make(cf, cfif), true },
Mike Reed0bdaf052017-06-18 23:35:57 -04001897 { SkMergeImageFilter::Make(cfif, cfif), true },
reed96a04f32016-04-25 09:25:15 -07001898 { SkComposeImageFilter::Make(cfif, cfif), true },
1899
reedbb34a8a2016-04-23 15:19:07 -07001900 { blif, false },
reed96a04f32016-04-25 09:25:15 -07001901 { SkBlurImageFilter::Make(3, 3, cfif), false },
reedbb34a8a2016-04-23 15:19:07 -07001902 { SkColorFilterImageFilter::Make(cf, blif), false },
Mike Reed0bdaf052017-06-18 23:35:57 -04001903 { SkMergeImageFilter::Make(cfif, blif), false },
reed96a04f32016-04-25 09:25:15 -07001904 { SkComposeImageFilter::Make(blif, cfif), false },
reedbb34a8a2016-04-23 15:19:07 -07001905 };
liyuqianbfebe222016-11-14 11:17:16 -08001906
reedbb34a8a2016-04-23 15:19:07 -07001907 for (const auto& rec : recs) {
reed96a04f32016-04-25 09:25:15 -07001908 const bool canHandle = rec.fFilter->canHandleComplexCTM();
reedbb34a8a2016-04-23 15:19:07 -07001909 REPORTER_ASSERT(reporter, canHandle == rec.fExpectCanHandle);
1910 }
1911}
Florin Malita08252ec2017-07-06 12:48:15 -04001912
1913// Test that transforming the filter DAG doesn't clone shared nodes multiple times.
1914DEF_TEST(ImageFilterColorSpaceDAG, reporter) {
1915
1916 // Helper for counting makeColorSpace() clones.
1917 class TestFilter final : public SkImageFilter {
1918 public:
1919 TestFilter() : INHERITED(nullptr, 0, nullptr) {}
1920
1921#ifndef SK_IGNORE_TO_STRING
1922 void toString(SkString*) const override {}
1923#endif
1924 Factory getFactory() const override { return nullptr; }
1925
1926 size_t cloneCount() const { return fCloneCount; }
1927
1928 protected:
1929 sk_sp<SkSpecialImage> onFilterImage(SkSpecialImage* src, const Context&,
1930 SkIPoint* offset) const override {
1931 return nullptr;
1932 }
1933 sk_sp<SkImageFilter> onMakeColorSpace(SkColorSpaceXformer*) const override {
1934 fCloneCount++;
1935 return sk_ref_sp(const_cast<TestFilter*>(this));
1936 }
1937
1938 private:
1939 typedef SkImageFilter INHERITED;
1940
1941 mutable size_t fCloneCount = 0;
1942 };
1943
1944 auto filter = sk_make_sp<TestFilter>();
1945 REPORTER_ASSERT(reporter, filter->cloneCount() == 0u);
1946
1947 // Build a DAG referencing the filter twice.
1948 auto complexFilter = SkMergeImageFilter::Make(filter, SkOffsetImageFilter::Make(1, 1, filter));
1949 REPORTER_ASSERT(reporter, filter->cloneCount() == 0u);
1950
1951 auto xformer = SkColorSpaceXformer::Make(SkColorSpace::MakeSRGB());
1952 auto xformedFilter = xformer->apply(complexFilter.get());
1953
Florin Malita39e08552017-07-06 14:16:18 -04001954 REPORTER_ASSERT(reporter, filter->cloneCount() == 1u);
Florin Malita08252ec2017-07-06 12:48:15 -04001955}
Xianzhu Wang0fa353c2017-08-25 16:27:04 -07001956
Xianzhu Wangb4496662017-09-25 10:26:40 -07001957// Test SkXfermodeImageFilter::filterBounds with different blending modes.
Xianzhu Wang0fa353c2017-08-25 16:27:04 -07001958DEF_TEST(XfermodeImageFilterBounds, reporter) {
1959 SkIRect background_rect = SkIRect::MakeXYWH(0, 0, 100, 100);
1960 SkIRect foreground_rect = SkIRect::MakeXYWH(50, 50, 100, 100);
1961 sk_sp<SkImageFilter> background(new FixedBoundsImageFilter(background_rect));
1962 sk_sp<SkImageFilter> foreground(new FixedBoundsImageFilter(foreground_rect));
1963
1964 const int kModeCount = static_cast<int>(SkBlendMode::kLastMode) + 1;
1965 SkIRect expectedBounds[kModeCount];
1966 // Expect union of input rects by default.
1967 for (int i = 0; i < kModeCount; ++i) {
1968 expectedBounds[i] = background_rect;
1969 expectedBounds[i].join(foreground_rect);
1970 }
1971
1972 SkIRect intersection = background_rect;
1973 intersection.intersect(foreground_rect);
1974 expectedBounds[static_cast<int>(SkBlendMode::kClear)] = SkIRect::MakeEmpty();
1975 expectedBounds[static_cast<int>(SkBlendMode::kSrc)] = foreground_rect;
1976 expectedBounds[static_cast<int>(SkBlendMode::kDst)] = background_rect;
1977 expectedBounds[static_cast<int>(SkBlendMode::kSrcIn)] = intersection;
1978 expectedBounds[static_cast<int>(SkBlendMode::kDstIn)] = intersection;
1979 expectedBounds[static_cast<int>(SkBlendMode::kSrcATop)] = background_rect;
1980 expectedBounds[static_cast<int>(SkBlendMode::kDstATop)] = foreground_rect;
1981
1982 // The value of this variable doesn't matter because we use inputs with fixed bounds.
1983 SkIRect src = SkIRect::MakeXYWH(11, 22, 33, 44);
1984 for (int i = 0; i < kModeCount; ++i) {
1985 sk_sp<SkImageFilter> xfermode(SkXfermodeImageFilter::Make(static_cast<SkBlendMode>(i),
1986 background, foreground, nullptr));
1987 auto bounds =
1988 xfermode->filterBounds(src, SkMatrix::I(), SkImageFilter::kForward_MapDirection);
1989 REPORTER_ASSERT(reporter, bounds == expectedBounds[i]);
1990 }
1991
1992 // Test empty intersection.
1993 sk_sp<SkImageFilter> background2(new FixedBoundsImageFilter(SkIRect::MakeXYWH(0, 0, 20, 20)));
1994 sk_sp<SkImageFilter> foreground2(new FixedBoundsImageFilter(SkIRect::MakeXYWH(40, 40, 50, 50)));
1995 sk_sp<SkImageFilter> xfermode(SkXfermodeImageFilter::Make(
1996 SkBlendMode::kSrcIn, std::move(background2), std::move(foreground2), nullptr));
1997 auto bounds = xfermode->filterBounds(src, SkMatrix::I(), SkImageFilter::kForward_MapDirection);
1998 REPORTER_ASSERT(reporter, bounds.isEmpty());
1999}
2000
Fredrik Söderquistb87f7982017-10-26 13:54:16 +02002001DEF_TEST(OffsetImageFilterBounds, reporter) {
2002 SkIRect src = SkIRect::MakeXYWH(0, 0, 100, 100);
2003 sk_sp<SkImageFilter> offset(SkOffsetImageFilter::Make(-50.5f, -50.5f, nullptr));
2004
2005 SkIRect expectedForward = SkIRect::MakeXYWH(-50, -50, 100, 100);
2006 SkIRect boundsForward = offset->filterBounds(src, SkMatrix::I(),
2007 SkImageFilter::kForward_MapDirection);
2008 REPORTER_ASSERT(reporter, boundsForward == expectedForward);
2009
2010 SkIRect expectedReverse = SkIRect::MakeXYWH(50, 50, 100, 100);
2011 SkIRect boundsReverse = offset->filterBounds(src, SkMatrix::I(),
2012 SkImageFilter::kReverse_MapDirection);
2013 REPORTER_ASSERT(reporter, boundsReverse == expectedReverse);
2014}
2015
Xianzhu Wang0fa353c2017-08-25 16:27:04 -07002016static void test_arithmetic_bounds(skiatest::Reporter* reporter, float k1, float k2, float k3,
2017 float k4, sk_sp<SkImageFilter> background,
2018 sk_sp<SkImageFilter> foreground,
2019 const SkImageFilter::CropRect* crop, const SkIRect& expected) {
2020 sk_sp<SkImageFilter> arithmetic(
2021 SkArithmeticImageFilter::Make(k1, k2, k3, k4, false, background, foreground, crop));
2022 // The value of the input rect doesn't matter because we use inputs with fixed bounds.
2023 SkIRect bounds = arithmetic->filterBounds(SkIRect::MakeXYWH(11, 22, 33, 44), SkMatrix::I(),
2024 SkImageFilter::kForward_MapDirection);
2025 REPORTER_ASSERT(reporter, expected == bounds);
2026}
2027
2028static void test_arithmetic_combinations(skiatest::Reporter* reporter, float v) {
2029 SkIRect background_rect = SkIRect::MakeXYWH(0, 0, 100, 100);
2030 SkIRect foreground_rect = SkIRect::MakeXYWH(50, 50, 100, 100);
2031 sk_sp<SkImageFilter> background(new FixedBoundsImageFilter(background_rect));
2032 sk_sp<SkImageFilter> foreground(new FixedBoundsImageFilter(foreground_rect));
2033
2034 SkIRect union_rect = background_rect;
2035 union_rect.join(foreground_rect);
2036 SkIRect intersection = background_rect;
2037 intersection.intersect(foreground_rect);
2038
2039 test_arithmetic_bounds(reporter, 0, 0, 0, 0, background, foreground, nullptr,
2040 SkIRect::MakeEmpty());
2041 test_arithmetic_bounds(reporter, 0, 0, 0, v, background, foreground, nullptr, union_rect);
2042 test_arithmetic_bounds(reporter, 0, 0, v, 0, background, foreground, nullptr, background_rect);
2043 test_arithmetic_bounds(reporter, 0, 0, v, v, background, foreground, nullptr, union_rect);
2044 test_arithmetic_bounds(reporter, 0, v, 0, 0, background, foreground, nullptr, foreground_rect);
2045 test_arithmetic_bounds(reporter, 0, v, 0, v, background, foreground, nullptr, union_rect);
2046 test_arithmetic_bounds(reporter, 0, v, v, 0, background, foreground, nullptr, union_rect);
2047 test_arithmetic_bounds(reporter, 0, v, v, v, background, foreground, nullptr, union_rect);
2048 test_arithmetic_bounds(reporter, v, 0, 0, 0, background, foreground, nullptr, intersection);
2049 test_arithmetic_bounds(reporter, v, 0, 0, v, background, foreground, nullptr, union_rect);
2050 test_arithmetic_bounds(reporter, v, 0, v, 0, background, foreground, nullptr, background_rect);
2051 test_arithmetic_bounds(reporter, v, 0, v, v, background, foreground, nullptr, union_rect);
2052 test_arithmetic_bounds(reporter, v, v, 0, 0, background, foreground, nullptr, foreground_rect);
2053 test_arithmetic_bounds(reporter, v, v, 0, v, background, foreground, nullptr, union_rect);
2054 test_arithmetic_bounds(reporter, v, v, v, 0, background, foreground, nullptr, union_rect);
2055 test_arithmetic_bounds(reporter, v, v, v, v, background, foreground, nullptr, union_rect);
2056
2057 // Test with crop. When k4 is non-zero, the result is expected to be crop_rect
2058 // regardless of inputs because the filter affects the whole crop area.
2059 SkIRect crop_rect = SkIRect::MakeXYWH(-111, -222, 333, 444);
2060 SkImageFilter::CropRect crop(SkRect::Make(crop_rect));
2061 test_arithmetic_bounds(reporter, 0, 0, 0, 0, background, foreground, &crop,
2062 SkIRect::MakeEmpty());
2063 test_arithmetic_bounds(reporter, 0, 0, 0, v, background, foreground, &crop, crop_rect);
2064 test_arithmetic_bounds(reporter, 0, 0, v, 0, background, foreground, &crop, background_rect);
2065 test_arithmetic_bounds(reporter, 0, 0, v, v, background, foreground, &crop, crop_rect);
2066 test_arithmetic_bounds(reporter, 0, v, 0, 0, background, foreground, &crop, foreground_rect);
2067 test_arithmetic_bounds(reporter, 0, v, 0, v, background, foreground, &crop, crop_rect);
2068 test_arithmetic_bounds(reporter, 0, v, v, 0, background, foreground, &crop, union_rect);
2069 test_arithmetic_bounds(reporter, 0, v, v, v, background, foreground, &crop, crop_rect);
2070 test_arithmetic_bounds(reporter, v, 0, 0, 0, background, foreground, &crop, intersection);
2071 test_arithmetic_bounds(reporter, v, 0, 0, v, background, foreground, &crop, crop_rect);
2072 test_arithmetic_bounds(reporter, v, 0, v, 0, background, foreground, &crop, background_rect);
2073 test_arithmetic_bounds(reporter, v, 0, v, v, background, foreground, &crop, crop_rect);
2074 test_arithmetic_bounds(reporter, v, v, 0, 0, background, foreground, &crop, foreground_rect);
2075 test_arithmetic_bounds(reporter, v, v, 0, v, background, foreground, &crop, crop_rect);
2076 test_arithmetic_bounds(reporter, v, v, v, 0, background, foreground, &crop, union_rect);
2077 test_arithmetic_bounds(reporter, v, v, v, v, background, foreground, &crop, crop_rect);
2078}
2079
Xianzhu Wangb4496662017-09-25 10:26:40 -07002080// Test SkArithmeticImageFilter::filterBounds with different blending modes.
Xianzhu Wang0fa353c2017-08-25 16:27:04 -07002081DEF_TEST(ArithmeticImageFilterBounds, reporter) {
2082 test_arithmetic_combinations(reporter, 1);
2083 test_arithmetic_combinations(reporter, 0.5);
2084}
Xianzhu Wangb4496662017-09-25 10:26:40 -07002085
2086// Test SkImageSource::filterBounds.
2087DEF_TEST(ImageSourceBounds, reporter) {
2088 sk_sp<SkImage> image(SkImage::MakeFromBitmap(make_gradient_circle(64, 64)));
2089 // Default src and dst rects.
2090 sk_sp<SkImageFilter> source1(SkImageSource::Make(image));
2091 SkIRect imageBounds = SkIRect::MakeWH(64, 64);
2092 SkIRect input(SkIRect::MakeXYWH(10, 20, 30, 40));
2093 REPORTER_ASSERT(reporter,
2094 imageBounds == source1->filterBounds(input, SkMatrix::I(),
2095 SkImageFilter::kForward_MapDirection));
2096 REPORTER_ASSERT(reporter,
2097 input == source1->filterBounds(input, SkMatrix::I(),
2098 SkImageFilter::kReverse_MapDirection));
2099 SkMatrix scale(SkMatrix::MakeScale(2));
2100 SkIRect scaledBounds = SkIRect::MakeWH(128, 128);
2101 REPORTER_ASSERT(reporter,
2102 scaledBounds == source1->filterBounds(input, scale,
2103 SkImageFilter::kForward_MapDirection));
2104 REPORTER_ASSERT(
2105 reporter,
2106 input == source1->filterBounds(input, scale, SkImageFilter::kReverse_MapDirection));
2107
2108 // Specified src and dst rects.
2109 SkRect src(SkRect::MakeXYWH(0.5, 0.5, 100.5, 100.5));
2110 SkRect dst(SkRect::MakeXYWH(-10.5, -10.5, 120.5, 120.5));
2111 sk_sp<SkImageFilter> source2(SkImageSource::Make(image, src, dst, kMedium_SkFilterQuality));
2112 REPORTER_ASSERT(reporter,
2113 dst.roundOut() == source2->filterBounds(input, SkMatrix::I(),
2114 SkImageFilter::kForward_MapDirection));
2115 REPORTER_ASSERT(reporter,
2116 input == source2->filterBounds(input, SkMatrix::I(),
2117 SkImageFilter::kReverse_MapDirection));
2118 scale.mapRect(&dst);
2119 scale.mapRect(&src);
2120 REPORTER_ASSERT(reporter,
2121 dst.roundOut() == source2->filterBounds(input, scale,
2122 SkImageFilter::kForward_MapDirection));
2123 REPORTER_ASSERT(
2124 reporter,
2125 input == source2->filterBounds(input, scale, SkImageFilter::kReverse_MapDirection));
2126}