blob: e3c7e35e74e70bfb11363a2bee36f1b87e4b441b [file] [log] [blame]
senorblanco@chromium.org194d7752013-07-24 22:19:24 +00001/*
2 * Copyright 2013 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
Xianzhu Wang0fa353c2017-08-25 16:27:04 -07008#include "SkArithmeticImageFilter.h"
commit-bot@chromium.org4b681bc2013-09-13 12:40:02 +00009#include "SkBitmap.h"
senorblanco@chromium.org6776b822014-01-03 21:48:22 +000010#include "SkBlurImageFilter.h"
tfarina@chromium.org8f6884a2014-01-24 20:56:26 +000011#include "SkCanvas.h"
12#include "SkColorFilterImageFilter.h"
13#include "SkColorMatrixFilter.h"
Florin Malita08252ec2017-07-06 12:48:15 -040014#include "SkColorSpaceXformer.h"
ajuma5788faa2015-02-13 09:05:47 -080015#include "SkComposeImageFilter.h"
senorblanco@chromium.org6776b822014-01-03 21:48:22 +000016#include "SkDisplacementMapEffect.h"
17#include "SkDropShadowImageFilter.h"
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +000018#include "SkGradientShader.h"
fmalita5598b632015-09-15 11:26:13 -070019#include "SkImage.h"
Cary Clark60aaeb22017-11-03 08:06:09 -040020#include "SkImageFilterPriv.h"
fmalitacd56f812015-09-14 13:31:18 -070021#include "SkImageSource.h"
commit-bot@chromium.org4b681bc2013-09-13 12:40:02 +000022#include "SkLightingImageFilter.h"
tfarina@chromium.org8f6884a2014-01-24 20:56:26 +000023#include "SkMatrixConvolutionImageFilter.h"
senorblanco@chromium.org6776b822014-01-03 21:48:22 +000024#include "SkMergeImageFilter.h"
25#include "SkMorphologyImageFilter.h"
senorblanco@chromium.org6776b822014-01-03 21:48:22 +000026#include "SkOffsetImageFilter.h"
ajuma77b6ba32016-01-08 14:58:35 -080027#include "SkPaintImageFilter.h"
senorblanco8f3937d2014-10-29 12:36:32 -070028#include "SkPerlinNoiseShader.h"
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +000029#include "SkPicture.h"
senorblanco@chromium.org910702b2014-05-30 20:36:15 +000030#include "SkPictureImageFilter.h"
robertphillips@google.com770963f2014-04-18 18:04:41 +000031#include "SkPictureRecorder.h"
robertphillips3d32d762015-07-13 13:16:44 -070032#include "SkPoint3.h"
halcanary97d2c0a2014-08-19 06:27:53 -070033#include "SkReadBuffer.h"
tfarina@chromium.org8f6884a2014-01-24 20:56:26 +000034#include "SkRect.h"
robertphillips4418dba2016-03-07 12:45:14 -080035#include "SkSpecialImage.h"
36#include "SkSpecialSurface.h"
fmalitacd56f812015-09-14 13:31:18 -070037#include "SkSurface.h"
senorblanco0abdf762015-08-20 11:10:41 -070038#include "SkTableColorFilter.h"
senorblanco@chromium.org6776b822014-01-03 21:48:22 +000039#include "SkTileImageFilter.h"
40#include "SkXfermodeImageFilter.h"
Leon Scroggins III4cdbf602017-09-28 14:33:57 -040041#include "Resources.h"
tfarina@chromium.org8f6884a2014-01-24 20:56:26 +000042#include "Test.h"
Mike Reed5a625e02017-08-08 15:48:54 -040043#include "sk_tool_utils.h"
senorblanco@chromium.org194d7752013-07-24 22:19:24 +000044
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +000045#if SK_SUPPORT_GPU
Brian Salomonc7fe0f72018-05-11 10:14:21 -040046#include "GrCaps.h"
kkinnunen15302832015-12-01 04:35:26 -080047#include "GrContext.h"
Brian Salomonc7fe0f72018-05-11 10:14:21 -040048#include "GrContextPriv.h"
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +000049#endif
50
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +000051static const int kBitmapSize = 4;
commit-bot@chromium.org4b681bc2013-09-13 12:40:02 +000052
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +000053namespace {
54
55class MatrixTestImageFilter : public SkImageFilter {
56public:
robertphillips43c2ad42016-04-04 05:05:11 -070057 static sk_sp<SkImageFilter> Make(skiatest::Reporter* reporter,
58 const SkMatrix& expectedMatrix) {
59 return sk_sp<SkImageFilter>(new MatrixTestImageFilter(reporter, expectedMatrix));
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +000060 }
61
Cary Clark99885412018-04-05 13:09:58 -040062 void toString(SkString* str) const override;
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +000063 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(MatrixTestImageFilter)
64
65protected:
robertphillips4ba94e22016-04-04 12:07:47 -070066 sk_sp<SkSpecialImage> onFilterImage(SkSpecialImage* source, const Context& ctx,
67 SkIPoint* offset) const override {
robertphillips43c2ad42016-04-04 05:05:11 -070068 REPORTER_ASSERT(fReporter, ctx.ctm() == fExpectedMatrix);
robertphillips4ba94e22016-04-04 12:07:47 -070069 offset->fX = offset->fY = 0;
70 return sk_ref_sp<SkSpecialImage>(source);
robertphillips43c2ad42016-04-04 05:05:11 -070071 }
Matt Sarett62745a82017-04-17 11:57:29 -040072 sk_sp<SkImageFilter> onMakeColorSpace(SkColorSpaceXformer*) const override {
73 return sk_ref_sp(const_cast<MatrixTestImageFilter*>(this));
74 }
robertphillips43c2ad42016-04-04 05:05:11 -070075
mtklein36352bf2015-03-25 18:17:31 -070076 void flatten(SkWriteBuffer& buffer) const override {
brianosman18f13f32016-05-02 07:51:08 -070077 SkDEBUGFAIL("Should never get here");
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +000078 }
79
80private:
robertphillips43c2ad42016-04-04 05:05:11 -070081 MatrixTestImageFilter(skiatest::Reporter* reporter, const SkMatrix& expectedMatrix)
82 : INHERITED(nullptr, 0, nullptr)
83 , fReporter(reporter)
84 , fExpectedMatrix(expectedMatrix) {
85 }
86
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +000087 skiatest::Reporter* fReporter;
88 SkMatrix fExpectedMatrix;
mtklein3f3b3d02014-12-01 11:47:08 -080089
reed9fa60da2014-08-21 07:59:51 -070090 typedef SkImageFilter INHERITED;
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +000091};
92
senorblanco6a93fa12016-04-05 04:43:45 -070093class FailImageFilter : public SkImageFilter {
94public:
robertphillips6b134732016-04-15 09:58:37 -070095 FailImageFilter() : SkImageFilter(nullptr, 0, nullptr) { }
senorblanco6a93fa12016-04-05 04:43:45 -070096
97 sk_sp<SkSpecialImage> onFilterImage(SkSpecialImage* source,
98 const Context& ctx,
99 SkIPoint* offset) const override {
100 return nullptr;
101 }
Matt Sarett62745a82017-04-17 11:57:29 -0400102 sk_sp<SkImageFilter> onMakeColorSpace(SkColorSpaceXformer*) const override {
103 return nullptr;
104 }
senorblanco6a93fa12016-04-05 04:43:45 -0700105
Cary Clark99885412018-04-05 13:09:58 -0400106 void toString(SkString* str) const override;
senorblanco6a93fa12016-04-05 04:43:45 -0700107 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(FailImageFilter)
108
109private:
110 typedef SkImageFilter INHERITED;
111};
112
113sk_sp<SkFlattenable> FailImageFilter::CreateProc(SkReadBuffer& buffer) {
114 SK_IMAGEFILTER_UNFLATTEN_COMMON(common, 0);
115 return sk_sp<SkFlattenable>(new FailImageFilter());
116}
117
senorblanco6a93fa12016-04-05 04:43:45 -0700118void FailImageFilter::toString(SkString* str) const {
119 str->appendf("FailImageFilter: (");
120 str->append(")");
121}
senorblanco6a93fa12016-04-05 04:43:45 -0700122
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:
Xianzhu Wang0fa353c2017-08-25 16:27:04 -0700299 void toString(SkString*) const override {}
Xianzhu Wang0fa353c2017-08-25 16:27:04 -0700300 Factory getFactory() const override { return nullptr; }
301
302 sk_sp<SkSpecialImage> onFilterImage(SkSpecialImage* src, const Context&,
303 SkIPoint* offset) const override {
304 return nullptr;
305 }
306 sk_sp<SkImageFilter> onMakeColorSpace(SkColorSpaceXformer*) const override { return nullptr; }
307
308 SkIRect onFilterBounds(const SkIRect&, const SkMatrix&, MapDirection) const override {
309 return fBounds;
310 }
311
312 SkIRect fBounds;
313};
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +0000314}
315
reed60c9b582016-04-03 09:11:13 -0700316sk_sp<SkFlattenable> MatrixTestImageFilter::CreateProc(SkReadBuffer& buffer) {
brianosman18f13f32016-05-02 07:51:08 -0700317 SkDEBUGFAIL("Should never get here");
318 return nullptr;
reed9fa60da2014-08-21 07:59:51 -0700319}
320
robertphillipsf3f5bad2014-12-19 13:49:15 -0800321void MatrixTestImageFilter::toString(SkString* str) const {
322 str->appendf("MatrixTestImageFilter: (");
323 str->append(")");
324}
robertphillipsf3f5bad2014-12-19 13:49:15 -0800325
reed9ce9d672016-03-17 10:51:11 -0700326static sk_sp<SkImage> make_small_image() {
reede8f30622016-03-23 18:59:25 -0700327 auto surface(SkSurface::MakeRasterN32Premul(kBitmapSize, kBitmapSize));
fmalita5598b632015-09-15 11:26:13 -0700328 SkCanvas* canvas = surface->getCanvas();
329 canvas->clear(0x00000000);
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000330 SkPaint darkPaint;
331 darkPaint.setColor(0xFF804020);
332 SkPaint lightPaint;
333 lightPaint.setColor(0xFF244484);
334 const int i = kBitmapSize / 4;
335 for (int y = 0; y < kBitmapSize; y += i) {
336 for (int x = 0; x < kBitmapSize; x += i) {
fmalita5598b632015-09-15 11:26:13 -0700337 canvas->save();
338 canvas->translate(SkIntToScalar(x), SkIntToScalar(y));
339 canvas->drawRect(SkRect::MakeXYWH(0, 0,
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000340 SkIntToScalar(i),
341 SkIntToScalar(i)), darkPaint);
fmalita5598b632015-09-15 11:26:13 -0700342 canvas->drawRect(SkRect::MakeXYWH(SkIntToScalar(i),
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000343 0,
344 SkIntToScalar(i),
345 SkIntToScalar(i)), lightPaint);
fmalita5598b632015-09-15 11:26:13 -0700346 canvas->drawRect(SkRect::MakeXYWH(0,
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000347 SkIntToScalar(i),
348 SkIntToScalar(i),
349 SkIntToScalar(i)), lightPaint);
fmalita5598b632015-09-15 11:26:13 -0700350 canvas->drawRect(SkRect::MakeXYWH(SkIntToScalar(i),
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000351 SkIntToScalar(i),
352 SkIntToScalar(i),
353 SkIntToScalar(i)), darkPaint);
fmalita5598b632015-09-15 11:26:13 -0700354 canvas->restore();
commit-bot@chromium.org4b681bc2013-09-13 12:40:02 +0000355 }
356 }
fmalita5598b632015-09-15 11:26:13 -0700357
reed9ce9d672016-03-17 10:51:11 -0700358 return surface->makeImageSnapshot();
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000359}
senorblanco@chromium.org194d7752013-07-24 22:19:24 +0000360
robertphillips5605b562016-04-05 11:50:42 -0700361static sk_sp<SkImageFilter> make_scale(float amount, sk_sp<SkImageFilter> input) {
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000362 SkScalar s = amount;
363 SkScalar matrix[20] = { s, 0, 0, 0, 0,
364 0, s, 0, 0, 0,
365 0, 0, s, 0, 0,
366 0, 0, 0, s, 0 };
robertphillips5605b562016-04-05 11:50:42 -0700367 sk_sp<SkColorFilter> filter(SkColorFilter::MakeMatrixFilterRowMajor255(matrix));
368 return SkColorFilterImageFilter::Make(std::move(filter), std::move(input));
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000369}
370
robertphillips5605b562016-04-05 11:50:42 -0700371static sk_sp<SkImageFilter> make_grayscale(sk_sp<SkImageFilter> input,
372 const SkImageFilter::CropRect* cropRect) {
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000373 SkScalar matrix[20];
374 memset(matrix, 0, 20 * sizeof(SkScalar));
375 matrix[0] = matrix[5] = matrix[10] = 0.2126f;
376 matrix[1] = matrix[6] = matrix[11] = 0.7152f;
377 matrix[2] = matrix[7] = matrix[12] = 0.0722f;
378 matrix[18] = 1.0f;
robertphillips5605b562016-04-05 11:50:42 -0700379 sk_sp<SkColorFilter> filter(SkColorFilter::MakeMatrixFilterRowMajor255(matrix));
380 return SkColorFilterImageFilter::Make(std::move(filter), std::move(input), cropRect);
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000381}
382
robertphillips5605b562016-04-05 11:50:42 -0700383static sk_sp<SkImageFilter> make_blue(sk_sp<SkImageFilter> input,
384 const SkImageFilter::CropRect* cropRect) {
385 sk_sp<SkColorFilter> filter(SkColorFilter::MakeModeFilter(SK_ColorBLUE,
Mike Reed7d954ad2016-10-28 15:42:34 -0400386 SkBlendMode::kSrcIn));
robertphillips5605b562016-04-05 11:50:42 -0700387 return SkColorFilterImageFilter::Make(std::move(filter), std::move(input), cropRect);
reedcedc36f2015-03-08 04:42:52 -0700388}
389
robertphillips3e302272016-04-20 11:48:36 -0700390static sk_sp<SkSpecialSurface> create_empty_special_surface(GrContext* context, int widthHeight) {
robertphillipsc91fd342016-04-25 12:32:54 -0700391#if SK_SUPPORT_GPU
robertphillips4418dba2016-03-07 12:45:14 -0800392 if (context) {
robertphillips4df16562016-04-28 15:09:34 -0700393 return SkSpecialSurface::MakeRenderTarget(context,
394 widthHeight, widthHeight,
Brian Osman777b5632016-10-14 09:16:21 -0400395 kRGBA_8888_GrPixelConfig, nullptr);
robertphillipsc91fd342016-04-25 12:32:54 -0700396 } else
397#endif
398 {
robertphillips4418dba2016-03-07 12:45:14 -0800399 const SkImageInfo info = SkImageInfo::MakeN32(widthHeight, widthHeight,
400 kOpaque_SkAlphaType);
robertphillips3e302272016-04-20 11:48:36 -0700401 return SkSpecialSurface::MakeRaster(info);
robertphillips4418dba2016-03-07 12:45:14 -0800402 }
senorblancobf680c32016-03-16 16:15:53 -0700403}
404
senorblanco5878dbd2016-05-19 14:50:29 -0700405static sk_sp<SkSurface> create_surface(GrContext* context, int width, int height) {
406 const SkImageInfo info = SkImageInfo::MakeN32(width, height, kOpaque_SkAlphaType);
407#if SK_SUPPORT_GPU
408 if (context) {
409 return SkSurface::MakeRenderTarget(context, SkBudgeted::kNo, info);
410 } else
411#endif
412 {
413 return SkSurface::MakeRaster(info);
414 }
415}
416
robertphillips3e302272016-04-20 11:48:36 -0700417static sk_sp<SkSpecialImage> create_empty_special_image(GrContext* context, int widthHeight) {
418 sk_sp<SkSpecialSurface> surf(create_empty_special_surface(context, widthHeight));
robertphillips4418dba2016-03-07 12:45:14 -0800419
420 SkASSERT(surf);
421
422 SkCanvas* canvas = surf->getCanvas();
423 SkASSERT(canvas);
424
425 canvas->clear(0x0);
426
robertphillips37bd7c32016-03-17 14:31:39 -0700427 return surf->makeImageSnapshot();
robertphillips4418dba2016-03-07 12:45:14 -0800428}
429
430
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000431DEF_TEST(ImageFilter, reporter) {
432 {
reedcedc36f2015-03-08 04:42:52 -0700433 // Check that two non-clipping color-matrice-filters concatenate into a single filter.
robertphillips5605b562016-04-05 11:50:42 -0700434 sk_sp<SkImageFilter> halfBrightness(make_scale(0.5f, nullptr));
435 sk_sp<SkImageFilter> quarterBrightness(make_scale(0.5f, std::move(halfBrightness)));
halcanary96fcdcc2015-08-27 07:41:13 -0700436 REPORTER_ASSERT(reporter, nullptr == quarterBrightness->getInput(0));
reedcedc36f2015-03-08 04:42:52 -0700437 SkColorFilter* cf;
438 REPORTER_ASSERT(reporter, quarterBrightness->asColorFilter(&cf));
halcanary96fcdcc2015-08-27 07:41:13 -0700439 REPORTER_ASSERT(reporter, cf->asColorMatrix(nullptr));
reedcedc36f2015-03-08 04:42:52 -0700440 cf->unref();
senorblanco@chromium.org194d7752013-07-24 22:19:24 +0000441 }
442
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000443 {
reedcedc36f2015-03-08 04:42:52 -0700444 // Check that a clipping color-matrice-filter followed by a color-matrice-filters
445 // concatenates into a single filter, but not a matrixfilter (due to clamping).
robertphillips5605b562016-04-05 11:50:42 -0700446 sk_sp<SkImageFilter> doubleBrightness(make_scale(2.0f, nullptr));
447 sk_sp<SkImageFilter> halfBrightness(make_scale(0.5f, std::move(doubleBrightness)));
halcanary96fcdcc2015-08-27 07:41:13 -0700448 REPORTER_ASSERT(reporter, nullptr == halfBrightness->getInput(0));
reedcedc36f2015-03-08 04:42:52 -0700449 SkColorFilter* cf;
450 REPORTER_ASSERT(reporter, halfBrightness->asColorFilter(&cf));
halcanary96fcdcc2015-08-27 07:41:13 -0700451 REPORTER_ASSERT(reporter, !cf->asColorMatrix(nullptr));
reedcedc36f2015-03-08 04:42:52 -0700452 cf->unref();
senorblanco@chromium.org194d7752013-07-24 22:19:24 +0000453 }
454
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000455 {
456 // Check that a color filter image filter without a crop rect can be
457 // expressed as a color filter.
robertphillips5605b562016-04-05 11:50:42 -0700458 sk_sp<SkImageFilter> gray(make_grayscale(nullptr, nullptr));
halcanary96fcdcc2015-08-27 07:41:13 -0700459 REPORTER_ASSERT(reporter, true == gray->asColorFilter(nullptr));
senorblanco@chromium.org194d7752013-07-24 22:19:24 +0000460 }
mtklein2afbe232016-02-07 12:23:10 -0800461
reedcedc36f2015-03-08 04:42:52 -0700462 {
463 // Check that a colorfilterimage filter without a crop rect but with an input
464 // that is another colorfilterimage can be expressed as a colorfilter (composed).
robertphillips5605b562016-04-05 11:50:42 -0700465 sk_sp<SkImageFilter> mode(make_blue(nullptr, nullptr));
466 sk_sp<SkImageFilter> gray(make_grayscale(std::move(mode), nullptr));
halcanary96fcdcc2015-08-27 07:41:13 -0700467 REPORTER_ASSERT(reporter, true == gray->asColorFilter(nullptr));
reedcedc36f2015-03-08 04:42:52 -0700468 }
469
470 {
471 // Test that if we exceed the limit of what ComposeColorFilter can combine, we still
472 // can build the DAG and won't assert if we call asColorFilter.
robertphillips5605b562016-04-05 11:50:42 -0700473 sk_sp<SkImageFilter> filter(make_blue(nullptr, nullptr));
reedcedc36f2015-03-08 04:42:52 -0700474 const int kWayTooManyForComposeColorFilter = 100;
475 for (int i = 0; i < kWayTooManyForComposeColorFilter; ++i) {
robertphillips5605b562016-04-05 11:50:42 -0700476 filter = make_blue(filter, nullptr);
reedcedc36f2015-03-08 04:42:52 -0700477 // the first few of these will succeed, but after we hit the internal limit,
478 // it will then return false.
halcanary96fcdcc2015-08-27 07:41:13 -0700479 (void)filter->asColorFilter(nullptr);
reedcedc36f2015-03-08 04:42:52 -0700480 }
481 }
reed5c518a82015-03-05 14:47:29 -0800482
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000483 {
484 // Check that a color filter image filter with a crop rect cannot
485 // be expressed as a color filter.
486 SkImageFilter::CropRect cropRect(SkRect::MakeXYWH(0, 0, 100, 100));
robertphillips5605b562016-04-05 11:50:42 -0700487 sk_sp<SkImageFilter> grayWithCrop(make_grayscale(nullptr, &cropRect));
halcanary96fcdcc2015-08-27 07:41:13 -0700488 REPORTER_ASSERT(reporter, false == grayWithCrop->asColorFilter(nullptr));
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000489 }
490
491 {
senorblanco3df05012014-07-03 11:13:09 -0700492 // Check that two non-commutative matrices are concatenated in
493 // the correct order.
494 SkScalar blueToRedMatrix[20] = { 0 };
495 blueToRedMatrix[2] = blueToRedMatrix[18] = SK_Scalar1;
496 SkScalar redToGreenMatrix[20] = { 0 };
497 redToGreenMatrix[5] = redToGreenMatrix[18] = SK_Scalar1;
robertphillips5605b562016-04-05 11:50:42 -0700498 sk_sp<SkColorFilter> blueToRed(SkColorFilter::MakeMatrixFilterRowMajor255(blueToRedMatrix));
499 sk_sp<SkImageFilter> filter1(SkColorFilterImageFilter::Make(std::move(blueToRed),
500 nullptr));
501 sk_sp<SkColorFilter> redToGreen(SkColorFilter::MakeMatrixFilterRowMajor255(redToGreenMatrix));
502 sk_sp<SkImageFilter> filter2(SkColorFilterImageFilter::Make(std::move(redToGreen),
503 std::move(filter1)));
senorblanco3df05012014-07-03 11:13:09 -0700504
505 SkBitmap result;
506 result.allocN32Pixels(kBitmapSize, kBitmapSize);
507
508 SkPaint paint;
509 paint.setColor(SK_ColorBLUE);
robertphillips5605b562016-04-05 11:50:42 -0700510 paint.setImageFilter(std::move(filter2));
senorblanco3df05012014-07-03 11:13:09 -0700511 SkCanvas canvas(result);
512 canvas.clear(0x0);
513 SkRect rect = SkRect::Make(SkIRect::MakeWH(kBitmapSize, kBitmapSize));
514 canvas.drawRect(rect, paint);
515 uint32_t pixel = *result.getAddr32(0, 0);
516 // The result here should be green, since we have effectively shifted blue to green.
517 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
518 }
519
520 {
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000521 // Tests pass by not asserting
reed9ce9d672016-03-17 10:51:11 -0700522 sk_sp<SkImage> image(make_small_image());
fmalita5598b632015-09-15 11:26:13 -0700523 SkBitmap result;
mike@reedtribe.orgdeee4962014-02-13 14:41:43 +0000524 result.allocN32Pixels(kBitmapSize, kBitmapSize);
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000525
senorblanco@chromium.org194d7752013-07-24 22:19:24 +0000526 {
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000527 // This tests for :
528 // 1 ) location at (0,0,1)
robertphillips3d32d762015-07-13 13:16:44 -0700529 SkPoint3 location = SkPoint3::Make(0, 0, SK_Scalar1);
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000530 // 2 ) location and target at same value
robertphillips3d32d762015-07-13 13:16:44 -0700531 SkPoint3 target = SkPoint3::Make(location.fX, location.fY, location.fZ);
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000532 // 3 ) large negative specular exponent value
533 SkScalar specularExponent = -1000;
534
robertphillips549c8992016-04-01 09:28:51 -0700535 sk_sp<SkImageFilter> bmSrc(SkImageSource::Make(std::move(image)));
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000536 SkPaint paint;
robertphillips12fa47d2016-04-08 16:28:09 -0700537 paint.setImageFilter(SkLightingImageFilter::MakeSpotLitSpecular(
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000538 location, target, specularExponent, 180,
539 0xFFFFFFFF, SK_Scalar1, SK_Scalar1, SK_Scalar1,
robertphillips12fa47d2016-04-08 16:28:09 -0700540 std::move(bmSrc)));
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000541 SkCanvas canvas(result);
542 SkRect r = SkRect::MakeWH(SkIntToScalar(kBitmapSize),
543 SkIntToScalar(kBitmapSize));
544 canvas.drawRect(r, paint);
senorblanco@chromium.org194d7752013-07-24 22:19:24 +0000545 }
senorblanco@chromium.org194d7752013-07-24 22:19:24 +0000546 }
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +0000547}
senorblanco@chromium.org6776b822014-01-03 21:48:22 +0000548
robertphillips3e302272016-04-20 11:48:36 -0700549static void test_crop_rects(skiatest::Reporter* reporter,
robertphillips4418dba2016-03-07 12:45:14 -0800550 GrContext* context) {
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +0000551 // Check that all filters offset to their absolute crop rect,
552 // unaffected by the input crop rect.
553 // Tests pass by not asserting.
robertphillips3e302272016-04-20 11:48:36 -0700554 sk_sp<SkSpecialImage> srcImg(create_empty_special_image(context, 100));
robertphillips4418dba2016-03-07 12:45:14 -0800555 SkASSERT(srcImg);
senorblanco@chromium.org6776b822014-01-03 21:48:22 +0000556
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +0000557 SkImageFilter::CropRect inputCropRect(SkRect::MakeXYWH(8, 13, 80, 80));
558 SkImageFilter::CropRect cropRect(SkRect::MakeXYWH(20, 30, 60, 60));
robertphillipsfc11b0a2016-04-05 09:09:36 -0700559 sk_sp<SkImageFilter> input(make_grayscale(nullptr, &inputCropRect));
senorblanco@chromium.org6776b822014-01-03 21:48:22 +0000560
robertphillipsfc11b0a2016-04-05 09:09:36 -0700561 FilterList filters(input, &cropRect);
senorblanco@chromium.org6776b822014-01-03 21:48:22 +0000562
senorblanco297f7ce2016-03-23 13:44:26 -0700563 for (int i = 0; i < filters.count(); ++i) {
564 SkImageFilter* filter = filters.getFilter(i);
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +0000565 SkIPoint offset;
brianosman2a75e5d2016-09-22 07:15:37 -0700566 SkImageFilter::OutputProperties noColorSpace(nullptr);
567 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeWH(100, 100), nullptr, noColorSpace);
robertphillips2302de92016-03-24 07:26:32 -0700568 sk_sp<SkSpecialImage> resultImg(filter->filterImage(srcImg.get(), ctx, &offset));
Brian Salomon1c80e992018-01-29 09:50:47 -0500569 REPORTER_ASSERT(reporter, resultImg, filters.getName(i));
570 REPORTER_ASSERT(reporter, offset.fX == 20 && offset.fY == 30, filters.getName(i));
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +0000571 }
572}
573
robertphillips3e302272016-04-20 11:48:36 -0700574static void test_negative_blur_sigma(skiatest::Reporter* reporter,
robertphillips4418dba2016-03-07 12:45:14 -0800575 GrContext* context) {
senorblanco32673b92014-09-09 09:15:04 -0700576 // Check that SkBlurImageFilter will accept a negative sigma, either in
577 // the given arguments or after CTM application.
reed5ea95df2015-10-06 14:05:32 -0700578 const int width = 32, height = 32;
579 const SkScalar five = SkIntToScalar(5);
senorblanco32673b92014-09-09 09:15:04 -0700580
robertphillips6e7025a2016-04-04 04:31:25 -0700581 sk_sp<SkImageFilter> positiveFilter(SkBlurImageFilter::Make(five, five, nullptr));
582 sk_sp<SkImageFilter> negativeFilter(SkBlurImageFilter::Make(-five, five, nullptr));
senorblanco32673b92014-09-09 09:15:04 -0700583
584 SkBitmap gradient = make_gradient_circle(width, height);
robertphillips3e302272016-04-20 11:48:36 -0700585 sk_sp<SkSpecialImage> imgSrc(SkSpecialImage::MakeFromRaster(SkIRect::MakeWH(width, height),
robertphillips37bd7c32016-03-17 14:31:39 -0700586 gradient));
robertphillips4418dba2016-03-07 12:45:14 -0800587
senorblanco32673b92014-09-09 09:15:04 -0700588 SkIPoint offset;
brianosman2a75e5d2016-09-22 07:15:37 -0700589 SkImageFilter::OutputProperties noColorSpace(nullptr);
590 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeWH(32, 32), nullptr, noColorSpace);
robertphillips4418dba2016-03-07 12:45:14 -0800591
robertphillips2302de92016-03-24 07:26:32 -0700592 sk_sp<SkSpecialImage> positiveResult1(positiveFilter->filterImage(imgSrc.get(), ctx, &offset));
robertphillips4418dba2016-03-07 12:45:14 -0800593 REPORTER_ASSERT(reporter, positiveResult1);
594
robertphillips2302de92016-03-24 07:26:32 -0700595 sk_sp<SkSpecialImage> negativeResult1(negativeFilter->filterImage(imgSrc.get(), ctx, &offset));
robertphillips4418dba2016-03-07 12:45:14 -0800596 REPORTER_ASSERT(reporter, negativeResult1);
597
senorblanco32673b92014-09-09 09:15:04 -0700598 SkMatrix negativeScale;
599 negativeScale.setScale(-SK_Scalar1, SK_Scalar1);
brianosman2a75e5d2016-09-22 07:15:37 -0700600 SkImageFilter::Context negativeCTX(negativeScale, SkIRect::MakeWH(32, 32), nullptr,
601 noColorSpace);
robertphillips4418dba2016-03-07 12:45:14 -0800602
robertphillips2302de92016-03-24 07:26:32 -0700603 sk_sp<SkSpecialImage> negativeResult2(positiveFilter->filterImage(imgSrc.get(),
604 negativeCTX,
605 &offset));
robertphillips4418dba2016-03-07 12:45:14 -0800606 REPORTER_ASSERT(reporter, negativeResult2);
607
robertphillips2302de92016-03-24 07:26:32 -0700608 sk_sp<SkSpecialImage> positiveResult2(negativeFilter->filterImage(imgSrc.get(),
609 negativeCTX,
610 &offset));
robertphillips4418dba2016-03-07 12:45:14 -0800611 REPORTER_ASSERT(reporter, positiveResult2);
612
613
614 SkBitmap positiveResultBM1, positiveResultBM2;
615 SkBitmap negativeResultBM1, negativeResultBM2;
616
robertphillips64612512016-04-08 12:10:42 -0700617 REPORTER_ASSERT(reporter, positiveResult1->getROPixels(&positiveResultBM1));
618 REPORTER_ASSERT(reporter, positiveResult2->getROPixels(&positiveResultBM2));
619 REPORTER_ASSERT(reporter, negativeResult1->getROPixels(&negativeResultBM1));
620 REPORTER_ASSERT(reporter, negativeResult2->getROPixels(&negativeResultBM2));
robertphillips4418dba2016-03-07 12:45:14 -0800621
senorblanco32673b92014-09-09 09:15:04 -0700622 for (int y = 0; y < height; y++) {
robertphillips4418dba2016-03-07 12:45:14 -0800623 int diffs = memcmp(positiveResultBM1.getAddr32(0, y),
624 negativeResultBM1.getAddr32(0, y),
625 positiveResultBM1.rowBytes());
senorblanco32673b92014-09-09 09:15:04 -0700626 REPORTER_ASSERT(reporter, !diffs);
627 if (diffs) {
628 break;
629 }
robertphillips4418dba2016-03-07 12:45:14 -0800630 diffs = memcmp(positiveResultBM1.getAddr32(0, y),
631 negativeResultBM2.getAddr32(0, y),
632 positiveResultBM1.rowBytes());
senorblanco32673b92014-09-09 09:15:04 -0700633 REPORTER_ASSERT(reporter, !diffs);
634 if (diffs) {
635 break;
636 }
robertphillips4418dba2016-03-07 12:45:14 -0800637 diffs = memcmp(positiveResultBM1.getAddr32(0, y),
638 positiveResultBM2.getAddr32(0, y),
639 positiveResultBM1.rowBytes());
senorblanco32673b92014-09-09 09:15:04 -0700640 REPORTER_ASSERT(reporter, !diffs);
641 if (diffs) {
642 break;
643 }
644 }
645}
646
senorblanco21a465d2016-04-11 11:58:39 -0700647DEF_TEST(ImageFilterNegativeBlurSigma, reporter) {
robertphillips3e302272016-04-20 11:48:36 -0700648 test_negative_blur_sigma(reporter, nullptr);
robertphillips4418dba2016-03-07 12:45:14 -0800649}
650
651#if SK_SUPPORT_GPU
bsalomon68d91342016-04-12 09:59:58 -0700652DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterNegativeBlurSigma_Gpu, reporter, ctxInfo) {
bsalomon8b7451a2016-05-11 06:33:06 -0700653 test_negative_blur_sigma(reporter, ctxInfo.grContext());
robertphillips4418dba2016-03-07 12:45:14 -0800654}
655#endif
656
robertphillips3e302272016-04-20 11:48:36 -0700657static void test_zero_blur_sigma(skiatest::Reporter* reporter, GrContext* context) {
senorblancobf680c32016-03-16 16:15:53 -0700658 // Check that SkBlurImageFilter with a zero sigma and a non-zero srcOffset works correctly.
659 SkImageFilter::CropRect cropRect(SkRect::Make(SkIRect::MakeXYWH(5, 0, 5, 10)));
robertphillips51a315e2016-03-31 09:05:49 -0700660 sk_sp<SkImageFilter> input(SkOffsetImageFilter::Make(0, 0, nullptr, &cropRect));
robertphillips6e7025a2016-04-04 04:31:25 -0700661 sk_sp<SkImageFilter> filter(SkBlurImageFilter::Make(0, 0, std::move(input), &cropRect));
senorblancobf680c32016-03-16 16:15:53 -0700662
robertphillips3e302272016-04-20 11:48:36 -0700663 sk_sp<SkSpecialSurface> surf(create_empty_special_surface(context, 10));
senorblancobf680c32016-03-16 16:15:53 -0700664 surf->getCanvas()->clear(SK_ColorGREEN);
robertphillips37bd7c32016-03-17 14:31:39 -0700665 sk_sp<SkSpecialImage> image(surf->makeImageSnapshot());
senorblancobf680c32016-03-16 16:15:53 -0700666
667 SkIPoint offset;
brianosman2a75e5d2016-09-22 07:15:37 -0700668 SkImageFilter::OutputProperties noColorSpace(nullptr);
669 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeWH(32, 32), nullptr, noColorSpace);
senorblancobf680c32016-03-16 16:15:53 -0700670
robertphillips2302de92016-03-24 07:26:32 -0700671 sk_sp<SkSpecialImage> result(filter->filterImage(image.get(), ctx, &offset));
senorblancobf680c32016-03-16 16:15:53 -0700672 REPORTER_ASSERT(reporter, offset.fX == 5 && offset.fY == 0);
673 REPORTER_ASSERT(reporter, result);
674 REPORTER_ASSERT(reporter, result->width() == 5 && result->height() == 10);
675
676 SkBitmap resultBM;
677
robertphillips64612512016-04-08 12:10:42 -0700678 REPORTER_ASSERT(reporter, result->getROPixels(&resultBM));
senorblancobf680c32016-03-16 16:15:53 -0700679
senorblancobf680c32016-03-16 16:15:53 -0700680 for (int y = 0; y < resultBM.height(); y++) {
681 for (int x = 0; x < resultBM.width(); x++) {
682 bool diff = *resultBM.getAddr32(x, y) != SK_ColorGREEN;
683 REPORTER_ASSERT(reporter, !diff);
684 if (diff) {
685 break;
686 }
687 }
688 }
689}
690
senorblanco21a465d2016-04-11 11:58:39 -0700691DEF_TEST(ImageFilterZeroBlurSigma, reporter) {
robertphillips3e302272016-04-20 11:48:36 -0700692 test_zero_blur_sigma(reporter, nullptr);
senorblancobf680c32016-03-16 16:15:53 -0700693}
694
695#if SK_SUPPORT_GPU
bsalomon68d91342016-04-12 09:59:58 -0700696DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterZeroBlurSigma_Gpu, reporter, ctxInfo) {
bsalomon8b7451a2016-05-11 06:33:06 -0700697 test_zero_blur_sigma(reporter, ctxInfo.grContext());
senorblancobf680c32016-03-16 16:15:53 -0700698}
699#endif
700
senorblanco6a93fa12016-04-05 04:43:45 -0700701
702// Tests that, even when an upstream filter has returned null (due to failure or clipping), a
703// downstream filter that affects transparent black still does so even with a nullptr input.
robertphillips3e302272016-04-20 11:48:36 -0700704static void test_fail_affects_transparent_black(skiatest::Reporter* reporter, GrContext* context) {
senorblanco6a93fa12016-04-05 04:43:45 -0700705 sk_sp<FailImageFilter> failFilter(new FailImageFilter());
robertphillips3e302272016-04-20 11:48:36 -0700706 sk_sp<SkSpecialImage> source(create_empty_special_image(context, 5));
brianosman2a75e5d2016-09-22 07:15:37 -0700707 SkImageFilter::OutputProperties noColorSpace(nullptr);
708 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeXYWH(0, 0, 1, 1), nullptr, noColorSpace);
Mike Reed7d954ad2016-10-28 15:42:34 -0400709 sk_sp<SkColorFilter> green(SkColorFilter::MakeModeFilter(SK_ColorGREEN, SkBlendMode::kSrc));
senorblanco6a93fa12016-04-05 04:43:45 -0700710 SkASSERT(green->affectsTransparentBlack());
robertphillips5605b562016-04-05 11:50:42 -0700711 sk_sp<SkImageFilter> greenFilter(SkColorFilterImageFilter::Make(std::move(green),
712 std::move(failFilter)));
senorblanco6a93fa12016-04-05 04:43:45 -0700713 SkIPoint offset;
714 sk_sp<SkSpecialImage> result(greenFilter->filterImage(source.get(), ctx, &offset));
715 REPORTER_ASSERT(reporter, nullptr != result.get());
716 if (result.get()) {
717 SkBitmap resultBM;
robertphillips64612512016-04-08 12:10:42 -0700718 REPORTER_ASSERT(reporter, result->getROPixels(&resultBM));
senorblanco6a93fa12016-04-05 04:43:45 -0700719 REPORTER_ASSERT(reporter, *resultBM.getAddr32(0, 0) == SK_ColorGREEN);
720 }
721}
722
723DEF_TEST(ImageFilterFailAffectsTransparentBlack, reporter) {
robertphillips3e302272016-04-20 11:48:36 -0700724 test_fail_affects_transparent_black(reporter, nullptr);
senorblanco6a93fa12016-04-05 04:43:45 -0700725}
726
727#if SK_SUPPORT_GPU
bsalomon68d91342016-04-12 09:59:58 -0700728DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterFailAffectsTransparentBlack_Gpu, reporter, ctxInfo) {
bsalomon8b7451a2016-05-11 06:33:06 -0700729 test_fail_affects_transparent_black(reporter, ctxInfo.grContext());
senorblanco6a93fa12016-04-05 04:43:45 -0700730}
731#endif
732
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +0000733DEF_TEST(ImageFilterDrawTiled, reporter) {
734 // Check that all filters when drawn tiled (with subsequent clip rects) exactly
735 // match the same filters drawn with a single full-canvas bitmap draw.
736 // Tests pass by not asserting.
737
robertphillipsfc11b0a2016-04-05 09:09:36 -0700738 FilterList filters(nullptr);
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +0000739
740 SkBitmap untiledResult, tiledResult;
reed5ea95df2015-10-06 14:05:32 -0700741 const int width = 64, height = 64;
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +0000742 untiledResult.allocN32Pixels(width, height);
743 tiledResult.allocN32Pixels(width, height);
744 SkCanvas tiledCanvas(tiledResult);
745 SkCanvas untiledCanvas(untiledResult);
senorblanco@chromium.orgd4db6572014-05-07 20:00:04 +0000746 int tileSize = 8;
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +0000747
senorblanco@chromium.orgd4db6572014-05-07 20:00:04 +0000748 for (int scale = 1; scale <= 2; ++scale) {
senorblanco297f7ce2016-03-23 13:44:26 -0700749 for (int i = 0; i < filters.count(); ++i) {
senorblanco@chromium.orgd4db6572014-05-07 20:00:04 +0000750 tiledCanvas.clear(0);
751 untiledCanvas.clear(0);
752 SkPaint paint;
Mike Reed5e257172016-11-01 11:22:05 -0400753 paint.setImageFilter(sk_ref_sp(filters.getFilter(i)));
senorblanco@chromium.orgd4db6572014-05-07 20:00:04 +0000754 paint.setTextSize(SkIntToScalar(height));
755 paint.setColor(SK_ColorWHITE);
756 SkString str;
757 const char* text = "ABC";
758 SkScalar ypos = SkIntToScalar(height);
759 untiledCanvas.save();
760 untiledCanvas.scale(SkIntToScalar(scale), SkIntToScalar(scale));
Cary Clark2a475ea2017-04-28 15:35:12 -0400761 untiledCanvas.drawString(text, 0, ypos, paint);
senorblanco@chromium.orgd4db6572014-05-07 20:00:04 +0000762 untiledCanvas.restore();
763 for (int y = 0; y < height; y += tileSize) {
764 for (int x = 0; x < width; x += tileSize) {
765 tiledCanvas.save();
766 tiledCanvas.clipRect(SkRect::Make(SkIRect::MakeXYWH(x, y, tileSize, tileSize)));
767 tiledCanvas.scale(SkIntToScalar(scale), SkIntToScalar(scale));
Cary Clark2a475ea2017-04-28 15:35:12 -0400768 tiledCanvas.drawString(text, 0, ypos, paint);
senorblanco@chromium.orgd4db6572014-05-07 20:00:04 +0000769 tiledCanvas.restore();
770 }
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +0000771 }
senorblanco@chromium.orgd4db6572014-05-07 20:00:04 +0000772 untiledCanvas.flush();
773 tiledCanvas.flush();
Mike Reed34042072017-08-08 16:29:22 -0400774 if (!sk_tool_utils::equal_pixels(untiledResult, tiledResult, 1)) {
Brian Salomon1c80e992018-01-29 09:50:47 -0500775 REPORTER_ASSERT(reporter, false, filters.getName(i));
Mike Reed5a625e02017-08-08 15:48:54 -0400776 break;
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +0000777 }
778 }
779 }
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +0000780}
781
mtklein3f3b3d02014-12-01 11:47:08 -0800782static void draw_saveLayer_picture(int width, int height, int tileSize,
robertphillipsa8d7f0b2014-08-29 08:03:56 -0700783 SkBBHFactory* factory, SkBitmap* result) {
mtkleind910f542014-08-22 09:06:34 -0700784
785 SkMatrix matrix;
786 matrix.setTranslate(SkIntToScalar(50), 0);
787
Mike Reed7d954ad2016-10-28 15:42:34 -0400788 sk_sp<SkColorFilter> cf(SkColorFilter::MakeModeFilter(SK_ColorWHITE, SkBlendMode::kSrc));
robertphillips5605b562016-04-05 11:50:42 -0700789 sk_sp<SkImageFilter> cfif(SkColorFilterImageFilter::Make(std::move(cf), nullptr));
robertphillipsae8c9332016-04-05 15:09:00 -0700790 sk_sp<SkImageFilter> imageFilter(SkImageFilter::MakeMatrixFilter(matrix,
791 kNone_SkFilterQuality,
792 std::move(cfif)));
mtkleind910f542014-08-22 09:06:34 -0700793
794 SkPaint paint;
robertphillips5605b562016-04-05 11:50:42 -0700795 paint.setImageFilter(std::move(imageFilter));
mtkleind910f542014-08-22 09:06:34 -0700796 SkPictureRecorder recorder;
797 SkRect bounds = SkRect::Make(SkIRect::MakeXYWH(0, 0, 50, 50));
mtklein3f3b3d02014-12-01 11:47:08 -0800798 SkCanvas* recordingCanvas = recorder.beginRecording(SkIntToScalar(width),
799 SkIntToScalar(height),
robertphillipsa8d7f0b2014-08-29 08:03:56 -0700800 factory, 0);
mtkleind910f542014-08-22 09:06:34 -0700801 recordingCanvas->translate(-55, 0);
802 recordingCanvas->saveLayer(&bounds, &paint);
803 recordingCanvas->restore();
reedca2622b2016-03-18 07:25:55 -0700804 sk_sp<SkPicture> picture1(recorder.finishRecordingAsPicture());
mtkleind910f542014-08-22 09:06:34 -0700805
806 result->allocN32Pixels(width, height);
807 SkCanvas canvas(*result);
808 canvas.clear(0);
809 canvas.clipRect(SkRect::Make(SkIRect::MakeWH(tileSize, tileSize)));
810 canvas.drawPicture(picture1.get());
811}
812
813DEF_TEST(ImageFilterDrawMatrixBBH, reporter) {
814 // Check that matrix filter when drawn tiled with BBH exactly
815 // matches the same thing drawn without BBH.
816 // Tests pass by not asserting.
817
818 const int width = 200, height = 200;
819 const int tileSize = 100;
820 SkBitmap result1, result2;
821 SkRTreeFactory factory;
822
robertphillipsa8d7f0b2014-08-29 08:03:56 -0700823 draw_saveLayer_picture(width, height, tileSize, &factory, &result1);
halcanary96fcdcc2015-08-27 07:41:13 -0700824 draw_saveLayer_picture(width, height, tileSize, nullptr, &result2);
mtkleind910f542014-08-22 09:06:34 -0700825
826 for (int y = 0; y < height; y++) {
827 int diffs = memcmp(result1.getAddr32(0, y), result2.getAddr32(0, y), result1.rowBytes());
828 REPORTER_ASSERT(reporter, !diffs);
829 if (diffs) {
830 break;
831 }
832 }
833}
834
robertphillips6e7025a2016-04-04 04:31:25 -0700835static sk_sp<SkImageFilter> make_blur(sk_sp<SkImageFilter> input) {
836 return SkBlurImageFilter::Make(SK_Scalar1, SK_Scalar1, std::move(input));
senorblanco1150a6d2014-08-25 12:46:58 -0700837}
838
robertphillips6e7025a2016-04-04 04:31:25 -0700839static sk_sp<SkImageFilter> make_drop_shadow(sk_sp<SkImageFilter> input) {
robertphillipsc4169122016-04-06 08:40:59 -0700840 return SkDropShadowImageFilter::Make(
senorblanco1150a6d2014-08-25 12:46:58 -0700841 SkIntToScalar(100), SkIntToScalar(100),
842 SkIntToScalar(10), SkIntToScalar(10),
sugoi234f0362014-10-23 13:59:52 -0700843 SK_ColorBLUE, SkDropShadowImageFilter::kDrawShadowAndForeground_ShadowMode,
robertphillipsc4169122016-04-06 08:40:59 -0700844 std::move(input));
senorblanco1150a6d2014-08-25 12:46:58 -0700845}
846
847DEF_TEST(ImageFilterBlurThenShadowBounds, reporter) {
robertphillips6e7025a2016-04-04 04:31:25 -0700848 sk_sp<SkImageFilter> filter1(make_blur(nullptr));
849 sk_sp<SkImageFilter> filter2(make_drop_shadow(std::move(filter1)));
senorblanco1150a6d2014-08-25 12:46:58 -0700850
851 SkIRect bounds = SkIRect::MakeXYWH(0, 0, 100, 100);
Herb Derby59f8f152017-10-17 22:27:23 +0000852 SkIRect expectedBounds = SkIRect::MakeXYWH(-133, -133, 236, 236);
senorblancoe5e79842016-03-21 14:51:59 -0700853 bounds = filter2->filterBounds(bounds, SkMatrix::I());
senorblanco1150a6d2014-08-25 12:46:58 -0700854
855 REPORTER_ASSERT(reporter, bounds == expectedBounds);
856}
857
858DEF_TEST(ImageFilterShadowThenBlurBounds, reporter) {
robertphillips6e7025a2016-04-04 04:31:25 -0700859 sk_sp<SkImageFilter> filter1(make_drop_shadow(nullptr));
860 sk_sp<SkImageFilter> filter2(make_blur(std::move(filter1)));
senorblanco1150a6d2014-08-25 12:46:58 -0700861
862 SkIRect bounds = SkIRect::MakeXYWH(0, 0, 100, 100);
Herb Derby59f8f152017-10-17 22:27:23 +0000863 SkIRect expectedBounds = SkIRect::MakeXYWH(-133, -133, 236, 236);
senorblancoe5e79842016-03-21 14:51:59 -0700864 bounds = filter2->filterBounds(bounds, SkMatrix::I());
senorblanco1150a6d2014-08-25 12:46:58 -0700865
866 REPORTER_ASSERT(reporter, bounds == expectedBounds);
867}
868
869DEF_TEST(ImageFilterDilateThenBlurBounds, reporter) {
robertphillipsfc11b0a2016-04-05 09:09:36 -0700870 sk_sp<SkImageFilter> filter1(SkDilateImageFilter::Make(2, 2, nullptr));
robertphillips6e7025a2016-04-04 04:31:25 -0700871 sk_sp<SkImageFilter> filter2(make_drop_shadow(std::move(filter1)));
senorblanco1150a6d2014-08-25 12:46:58 -0700872
873 SkIRect bounds = SkIRect::MakeXYWH(0, 0, 100, 100);
874 SkIRect expectedBounds = SkIRect::MakeXYWH(-132, -132, 234, 234);
senorblancoe5e79842016-03-21 14:51:59 -0700875 bounds = filter2->filterBounds(bounds, SkMatrix::I());
senorblanco1150a6d2014-08-25 12:46:58 -0700876
877 REPORTER_ASSERT(reporter, bounds == expectedBounds);
878}
879
jbroman203a9932016-07-11 14:07:59 -0700880DEF_TEST(ImageFilterScaledBlurRadius, reporter) {
881 // Each blur should spread 3*sigma, so 3 for the blur and 30 for the shadow
882 // (before the CTM). Bounds should be computed correctly in the presence of
883 // a (possibly negative) scale.
884 sk_sp<SkImageFilter> blur(make_blur(nullptr));
885 sk_sp<SkImageFilter> dropShadow(make_drop_shadow(nullptr));
886 {
887 // Uniform scale by 2.
888 SkMatrix scaleMatrix;
889 scaleMatrix.setScale(2, 2);
890 SkIRect bounds = SkIRect::MakeLTRB(0, 0, 200, 200);
891
Herb Derby59f8f152017-10-17 22:27:23 +0000892 SkIRect expectedBlurBounds = SkIRect::MakeLTRB(-6, -6, 206, 206);
jbroman203a9932016-07-11 14:07:59 -0700893 SkIRect blurBounds = blur->filterBounds(
894 bounds, scaleMatrix, SkImageFilter::kForward_MapDirection);
895 REPORTER_ASSERT(reporter, blurBounds == expectedBlurBounds);
896 SkIRect reverseBlurBounds = blur->filterBounds(
897 bounds, scaleMatrix, SkImageFilter::kReverse_MapDirection);
898 REPORTER_ASSERT(reporter, reverseBlurBounds == expectedBlurBounds);
899
900 SkIRect expectedShadowBounds = SkIRect::MakeLTRB(0, 0, 460, 460);
901 SkIRect shadowBounds = dropShadow->filterBounds(
902 bounds, scaleMatrix, SkImageFilter::kForward_MapDirection);
903 REPORTER_ASSERT(reporter, shadowBounds == expectedShadowBounds);
904 SkIRect expectedReverseShadowBounds =
905 SkIRect::MakeLTRB(-260, -260, 200, 200);
906 SkIRect reverseShadowBounds = dropShadow->filterBounds(
907 bounds, scaleMatrix, SkImageFilter::kReverse_MapDirection);
908 REPORTER_ASSERT(reporter,
909 reverseShadowBounds == expectedReverseShadowBounds);
910 }
911 {
912 // Vertical flip.
913 SkMatrix scaleMatrix;
914 scaleMatrix.setScale(1, -1);
915 SkIRect bounds = SkIRect::MakeLTRB(0, -100, 100, 0);
916
Herb Derby59f8f152017-10-17 22:27:23 +0000917 SkIRect expectedBlurBounds = SkIRect::MakeLTRB(-3, -103, 103, 3);
jbroman203a9932016-07-11 14:07:59 -0700918 SkIRect blurBounds = blur->filterBounds(
919 bounds, scaleMatrix, SkImageFilter::kForward_MapDirection);
920 REPORTER_ASSERT(reporter, blurBounds == expectedBlurBounds);
921 SkIRect reverseBlurBounds = blur->filterBounds(
922 bounds, scaleMatrix, SkImageFilter::kReverse_MapDirection);
923 REPORTER_ASSERT(reporter, reverseBlurBounds == expectedBlurBounds);
924
925 SkIRect expectedShadowBounds = SkIRect::MakeLTRB(0, -230, 230, 0);
926 SkIRect shadowBounds = dropShadow->filterBounds(
927 bounds, scaleMatrix, SkImageFilter::kForward_MapDirection);
928 REPORTER_ASSERT(reporter, shadowBounds == expectedShadowBounds);
929 SkIRect expectedReverseShadowBounds =
930 SkIRect::MakeLTRB(-130, -100, 100, 130);
931 SkIRect reverseShadowBounds = dropShadow->filterBounds(
932 bounds, scaleMatrix, SkImageFilter::kReverse_MapDirection);
933 REPORTER_ASSERT(reporter,
934 reverseShadowBounds == expectedReverseShadowBounds);
935 }
936}
937
ajuma5788faa2015-02-13 09:05:47 -0800938DEF_TEST(ImageFilterComposedBlurFastBounds, reporter) {
robertphillips6e7025a2016-04-04 04:31:25 -0700939 sk_sp<SkImageFilter> filter1(make_blur(nullptr));
940 sk_sp<SkImageFilter> filter2(make_blur(nullptr));
robertphillips491fb172016-03-30 12:32:58 -0700941 sk_sp<SkImageFilter> composedFilter(SkComposeImageFilter::Make(std::move(filter1),
942 std::move(filter2)));
ajuma5788faa2015-02-13 09:05:47 -0800943
944 SkRect boundsSrc = SkRect::MakeWH(SkIntToScalar(100), SkIntToScalar(100));
945 SkRect expectedBounds = SkRect::MakeXYWH(
Herb Derby59f8f152017-10-17 22:27:23 +0000946 SkIntToScalar(-6), SkIntToScalar(-6), SkIntToScalar(112), SkIntToScalar(112));
senorblancoe5e79842016-03-21 14:51:59 -0700947 SkRect boundsDst = composedFilter->computeFastBounds(boundsSrc);
ajuma5788faa2015-02-13 09:05:47 -0800948
949 REPORTER_ASSERT(reporter, boundsDst == expectedBounds);
950}
951
jbroman0e3129d2016-03-17 12:24:23 -0700952DEF_TEST(ImageFilterUnionBounds, reporter) {
robertphillips51a315e2016-03-31 09:05:49 -0700953 sk_sp<SkImageFilter> offset(SkOffsetImageFilter::Make(50, 0, nullptr));
jbroman0e3129d2016-03-17 12:24:23 -0700954 // Regardless of which order they appear in, the image filter bounds should
955 // be combined correctly.
956 {
reed374772b2016-10-05 17:33:02 -0700957 sk_sp<SkImageFilter> composite(SkXfermodeImageFilter::Make(SkBlendMode::kSrcOver, offset));
jbroman0e3129d2016-03-17 12:24:23 -0700958 SkRect bounds = SkRect::MakeWH(100, 100);
959 // Intentionally aliasing here, as that's what the real callers do.
senorblancoe5e79842016-03-21 14:51:59 -0700960 bounds = composite->computeFastBounds(bounds);
jbroman0e3129d2016-03-17 12:24:23 -0700961 REPORTER_ASSERT(reporter, bounds == SkRect::MakeWH(150, 100));
962 }
963 {
reed374772b2016-10-05 17:33:02 -0700964 sk_sp<SkImageFilter> composite(SkXfermodeImageFilter::Make(SkBlendMode::kSrcOver, nullptr,
robertphillips8c0326d2016-04-05 12:48:34 -0700965 offset, nullptr));
jbroman0e3129d2016-03-17 12:24:23 -0700966 SkRect bounds = SkRect::MakeWH(100, 100);
967 // Intentionally aliasing here, as that's what the real callers do.
senorblancoe5e79842016-03-21 14:51:59 -0700968 bounds = composite->computeFastBounds(bounds);
jbroman0e3129d2016-03-17 12:24:23 -0700969 REPORTER_ASSERT(reporter, bounds == SkRect::MakeWH(150, 100));
970 }
971}
972
robertphillips3e302272016-04-20 11:48:36 -0700973static void test_imagefilter_merge_result_size(skiatest::Reporter* reporter, GrContext* context) {
senorblanco4a243982015-11-25 07:06:55 -0800974 SkBitmap greenBM;
975 greenBM.allocN32Pixels(20, 20);
976 greenBM.eraseColor(SK_ColorGREEN);
reed9ce9d672016-03-17 10:51:11 -0700977 sk_sp<SkImage> greenImage(SkImage::MakeFromBitmap(greenBM));
robertphillips549c8992016-04-01 09:28:51 -0700978 sk_sp<SkImageFilter> source(SkImageSource::Make(std::move(greenImage)));
Mike Reed0bdaf052017-06-18 23:35:57 -0400979 sk_sp<SkImageFilter> merge(SkMergeImageFilter::Make(source, source));
senorblanco4a243982015-11-25 07:06:55 -0800980
robertphillips3e302272016-04-20 11:48:36 -0700981 sk_sp<SkSpecialImage> srcImg(create_empty_special_image(context, 1));
robertphillips4418dba2016-03-07 12:45:14 -0800982
brianosman2a75e5d2016-09-22 07:15:37 -0700983 SkImageFilter::OutputProperties noColorSpace(nullptr);
984 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeXYWH(0, 0, 100, 100), nullptr,
985 noColorSpace);
senorblanco4a243982015-11-25 07:06:55 -0800986 SkIPoint offset;
robertphillips4418dba2016-03-07 12:45:14 -0800987
robertphillips2302de92016-03-24 07:26:32 -0700988 sk_sp<SkSpecialImage> resultImg(merge->filterImage(srcImg.get(), ctx, &offset));
robertphillips4418dba2016-03-07 12:45:14 -0800989 REPORTER_ASSERT(reporter, resultImg);
990
991 REPORTER_ASSERT(reporter, resultImg->width() == 20 && resultImg->height() == 20);
senorblanco4a243982015-11-25 07:06:55 -0800992}
993
robertphillips4418dba2016-03-07 12:45:14 -0800994DEF_TEST(ImageFilterMergeResultSize, reporter) {
robertphillips3e302272016-04-20 11:48:36 -0700995 test_imagefilter_merge_result_size(reporter, nullptr);
robertphillips4418dba2016-03-07 12:45:14 -0800996}
997
998#if SK_SUPPORT_GPU
egdanielab527a52016-06-28 08:07:26 -0700999DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterMergeResultSize_Gpu, reporter, ctxInfo) {
bsalomon8b7451a2016-05-11 06:33:06 -07001000 test_imagefilter_merge_result_size(reporter, ctxInfo.grContext());
robertphillips4418dba2016-03-07 12:45:14 -08001001}
1002#endif
1003
robertphillipsa8d7f0b2014-08-29 08:03:56 -07001004static void draw_blurred_rect(SkCanvas* canvas) {
senorblanco837f5322014-07-14 10:19:54 -07001005 SkPaint filterPaint;
1006 filterPaint.setColor(SK_ColorWHITE);
robertphillips6e7025a2016-04-04 04:31:25 -07001007 filterPaint.setImageFilter(SkBlurImageFilter::Make(SkIntToScalar(8), 0, nullptr));
halcanary96fcdcc2015-08-27 07:41:13 -07001008 canvas->saveLayer(nullptr, &filterPaint);
senorblanco837f5322014-07-14 10:19:54 -07001009 SkPaint whitePaint;
1010 whitePaint.setColor(SK_ColorWHITE);
1011 canvas->drawRect(SkRect::Make(SkIRect::MakeWH(4, 4)), whitePaint);
1012 canvas->restore();
1013}
1014
robertphillipsa8d7f0b2014-08-29 08:03:56 -07001015static void draw_picture_clipped(SkCanvas* canvas, const SkRect& clipRect, const SkPicture* picture) {
senorblanco837f5322014-07-14 10:19:54 -07001016 canvas->save();
1017 canvas->clipRect(clipRect);
1018 canvas->drawPicture(picture);
1019 canvas->restore();
1020}
1021
1022DEF_TEST(ImageFilterDrawTiledBlurRTree, reporter) {
1023 // Check that the blur filter when recorded with RTree acceleration,
1024 // and drawn tiled (with subsequent clip rects) exactly
1025 // matches the same filter drawn with without RTree acceleration.
1026 // This tests that the "bleed" from the blur into the otherwise-blank
1027 // tiles is correctly rendered.
1028 // Tests pass by not asserting.
1029
1030 int width = 16, height = 8;
1031 SkBitmap result1, result2;
1032 result1.allocN32Pixels(width, height);
1033 result2.allocN32Pixels(width, height);
1034 SkCanvas canvas1(result1);
1035 SkCanvas canvas2(result2);
1036 int tileSize = 8;
1037
1038 canvas1.clear(0);
1039 canvas2.clear(0);
1040
1041 SkRTreeFactory factory;
1042
1043 SkPictureRecorder recorder1, recorder2;
1044 // The only difference between these two pictures is that one has RTree aceleration.
mtklein3f3b3d02014-12-01 11:47:08 -08001045 SkCanvas* recordingCanvas1 = recorder1.beginRecording(SkIntToScalar(width),
1046 SkIntToScalar(height),
halcanary96fcdcc2015-08-27 07:41:13 -07001047 nullptr, 0);
mtklein3f3b3d02014-12-01 11:47:08 -08001048 SkCanvas* recordingCanvas2 = recorder2.beginRecording(SkIntToScalar(width),
1049 SkIntToScalar(height),
robertphillipsa8d7f0b2014-08-29 08:03:56 -07001050 &factory, 0);
1051 draw_blurred_rect(recordingCanvas1);
1052 draw_blurred_rect(recordingCanvas2);
reedca2622b2016-03-18 07:25:55 -07001053 sk_sp<SkPicture> picture1(recorder1.finishRecordingAsPicture());
1054 sk_sp<SkPicture> picture2(recorder2.finishRecordingAsPicture());
senorblanco837f5322014-07-14 10:19:54 -07001055 for (int y = 0; y < height; y += tileSize) {
1056 for (int x = 0; x < width; x += tileSize) {
1057 SkRect tileRect = SkRect::Make(SkIRect::MakeXYWH(x, y, tileSize, tileSize));
reedca2622b2016-03-18 07:25:55 -07001058 draw_picture_clipped(&canvas1, tileRect, picture1.get());
1059 draw_picture_clipped(&canvas2, tileRect, picture2.get());
senorblanco837f5322014-07-14 10:19:54 -07001060 }
1061 }
1062 for (int y = 0; y < height; y++) {
1063 int diffs = memcmp(result1.getAddr32(0, y), result2.getAddr32(0, y), result1.rowBytes());
1064 REPORTER_ASSERT(reporter, !diffs);
1065 if (diffs) {
1066 break;
1067 }
1068 }
1069}
1070
senorblanco@chromium.org91957432014-05-01 14:03:41 +00001071DEF_TEST(ImageFilterMatrixConvolution, reporter) {
1072 // Check that a 1x3 filter does not cause a spurious assert.
1073 SkScalar kernel[3] = {
1074 SkIntToScalar( 1), SkIntToScalar( 1), SkIntToScalar( 1),
1075 };
1076 SkISize kernelSize = SkISize::Make(1, 3);
1077 SkScalar gain = SK_Scalar1, bias = 0;
1078 SkIPoint kernelOffset = SkIPoint::Make(0, 0);
1079
robertphillipsef6a47b2016-04-08 08:01:20 -07001080 sk_sp<SkImageFilter> filter(SkMatrixConvolutionImageFilter::Make(
1081 kernelSize, kernel,
1082 gain, bias, kernelOffset,
1083 SkMatrixConvolutionImageFilter::kRepeat_TileMode,
1084 false, nullptr));
senorblanco@chromium.org91957432014-05-01 14:03:41 +00001085
1086 SkBitmap result;
1087 int width = 16, height = 16;
1088 result.allocN32Pixels(width, height);
1089 SkCanvas canvas(result);
1090 canvas.clear(0);
1091
1092 SkPaint paint;
robertphillipsef6a47b2016-04-08 08:01:20 -07001093 paint.setImageFilter(std::move(filter));
senorblanco@chromium.org91957432014-05-01 14:03:41 +00001094 SkRect rect = SkRect::Make(SkIRect::MakeWH(width, height));
1095 canvas.drawRect(rect, paint);
1096}
1097
senorblanco@chromium.org8c7372b2014-05-02 19:13:11 +00001098DEF_TEST(ImageFilterMatrixConvolutionBorder, reporter) {
1099 // Check that a filter with borders outside the target bounds
1100 // does not crash.
1101 SkScalar kernel[3] = {
1102 0, 0, 0,
1103 };
1104 SkISize kernelSize = SkISize::Make(3, 1);
1105 SkScalar gain = SK_Scalar1, bias = 0;
1106 SkIPoint kernelOffset = SkIPoint::Make(2, 0);
1107
robertphillipsef6a47b2016-04-08 08:01:20 -07001108 sk_sp<SkImageFilter> filter(SkMatrixConvolutionImageFilter::Make(
1109 kernelSize, kernel, gain, bias, kernelOffset,
1110 SkMatrixConvolutionImageFilter::kClamp_TileMode,
1111 true, nullptr));
senorblanco@chromium.org8c7372b2014-05-02 19:13:11 +00001112
1113 SkBitmap result;
1114
1115 int width = 10, height = 10;
1116 result.allocN32Pixels(width, height);
1117 SkCanvas canvas(result);
1118 canvas.clear(0);
1119
1120 SkPaint filterPaint;
robertphillipsef6a47b2016-04-08 08:01:20 -07001121 filterPaint.setImageFilter(std::move(filter));
senorblanco@chromium.org8c7372b2014-05-02 19:13:11 +00001122 SkRect bounds = SkRect::MakeWH(1, 10);
1123 SkRect rect = SkRect::Make(SkIRect::MakeWH(width, height));
1124 SkPaint rectPaint;
1125 canvas.saveLayer(&bounds, &filterPaint);
1126 canvas.drawRect(rect, rectPaint);
1127 canvas.restore();
1128}
1129
robertphillips3e302272016-04-20 11:48:36 -07001130static void test_big_kernel(skiatest::Reporter* reporter, GrContext* context) {
robertphillipsdada4dd2016-04-13 04:54:36 -07001131 // Check that a kernel that is too big for the GPU still works
1132 SkScalar identityKernel[49] = {
1133 0, 0, 0, 0, 0, 0, 0,
1134 0, 0, 0, 0, 0, 0, 0,
1135 0, 0, 0, 0, 0, 0, 0,
1136 0, 0, 0, 1, 0, 0, 0,
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 };
1141 SkISize kernelSize = SkISize::Make(7, 7);
1142 SkScalar gain = SK_Scalar1, bias = 0;
1143 SkIPoint kernelOffset = SkIPoint::Make(0, 0);
1144
1145 sk_sp<SkImageFilter> filter(SkMatrixConvolutionImageFilter::Make(
1146 kernelSize, identityKernel, gain, bias, kernelOffset,
1147 SkMatrixConvolutionImageFilter::kClamp_TileMode,
1148 true, nullptr));
1149
robertphillips3e302272016-04-20 11:48:36 -07001150 sk_sp<SkSpecialImage> srcImg(create_empty_special_image(context, 100));
robertphillipsdada4dd2016-04-13 04:54:36 -07001151 SkASSERT(srcImg);
1152
1153 SkIPoint offset;
brianosman2a75e5d2016-09-22 07:15:37 -07001154 SkImageFilter::OutputProperties noColorSpace(nullptr);
1155 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeWH(100, 100), nullptr, noColorSpace);
robertphillipsdada4dd2016-04-13 04:54:36 -07001156 sk_sp<SkSpecialImage> resultImg(filter->filterImage(srcImg.get(), ctx, &offset));
1157 REPORTER_ASSERT(reporter, resultImg);
1158 REPORTER_ASSERT(reporter, SkToBool(context) == resultImg->isTextureBacked());
1159 REPORTER_ASSERT(reporter, resultImg->width() == 100 && resultImg->height() == 100);
1160 REPORTER_ASSERT(reporter, offset.fX == 0 && offset.fY == 0);
1161}
1162
1163DEF_TEST(ImageFilterMatrixConvolutionBigKernel, reporter) {
robertphillips3e302272016-04-20 11:48:36 -07001164 test_big_kernel(reporter, nullptr);
robertphillipsdada4dd2016-04-13 04:54:36 -07001165}
1166
1167#if SK_SUPPORT_GPU
egdanielab527a52016-06-28 08:07:26 -07001168DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterMatrixConvolutionBigKernel_Gpu,
1169 reporter, ctxInfo) {
bsalomon8b7451a2016-05-11 06:33:06 -07001170 test_big_kernel(reporter, ctxInfo.grContext());
robertphillipsdada4dd2016-04-13 04:54:36 -07001171}
1172#endif
1173
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +00001174DEF_TEST(ImageFilterCropRect, reporter) {
robertphillips3e302272016-04-20 11:48:36 -07001175 test_crop_rects(reporter, nullptr);
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +00001176}
1177
robertphillips4418dba2016-03-07 12:45:14 -08001178#if SK_SUPPORT_GPU
bsalomon68d91342016-04-12 09:59:58 -07001179DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterCropRect_Gpu, reporter, ctxInfo) {
bsalomon8b7451a2016-05-11 06:33:06 -07001180 test_crop_rects(reporter, ctxInfo.grContext());
robertphillips4418dba2016-03-07 12:45:14 -08001181}
1182#endif
1183
tfarina9ea53f92014-06-24 06:50:39 -07001184DEF_TEST(ImageFilterMatrix, reporter) {
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +00001185 SkBitmap temp;
mike@reedtribe.orgdeee4962014-02-13 14:41:43 +00001186 temp.allocN32Pixels(100, 100);
robertphillips9a53fd72015-06-22 09:46:59 -07001187 SkCanvas canvas(temp);
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +00001188 canvas.scale(SkIntToScalar(2), SkIntToScalar(2));
1189
1190 SkMatrix expectedMatrix = canvas.getTotalMatrix();
1191
commit-bot@chromium.org5fb2ce32014-04-17 23:35:06 +00001192 SkRTreeFactory factory;
1193 SkPictureRecorder recorder;
1194 SkCanvas* recordingCanvas = recorder.beginRecording(100, 100, &factory, 0);
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +00001195
1196 SkPaint paint;
robertphillips43c2ad42016-04-04 05:05:11 -07001197 paint.setImageFilter(MatrixTestImageFilter::Make(reporter, expectedMatrix));
halcanary96fcdcc2015-08-27 07:41:13 -07001198 recordingCanvas->saveLayer(nullptr, &paint);
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +00001199 SkPaint solidPaint;
1200 solidPaint.setColor(0xFFFFFFFF);
1201 recordingCanvas->save();
1202 recordingCanvas->scale(SkIntToScalar(10), SkIntToScalar(10));
1203 recordingCanvas->drawRect(SkRect::Make(SkIRect::MakeWH(100, 100)), solidPaint);
1204 recordingCanvas->restore(); // scale
1205 recordingCanvas->restore(); // saveLayer
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +00001206
reedca2622b2016-03-18 07:25:55 -07001207 canvas.drawPicture(recorder.finishRecordingAsPicture());
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +00001208}
1209
robertphillips3e302272016-04-20 11:48:36 -07001210static void test_clipped_picture_imagefilter(skiatest::Reporter* reporter, GrContext* context) {
reedca2622b2016-03-18 07:25:55 -07001211 sk_sp<SkPicture> picture;
senorblanco3d822c22014-07-30 14:49:31 -07001212
robertphillips4418dba2016-03-07 12:45:14 -08001213 {
1214 SkRTreeFactory factory;
1215 SkPictureRecorder recorder;
1216 SkCanvas* recordingCanvas = recorder.beginRecording(1, 1, &factory, 0);
1217
1218 // Create an SkPicture which simply draws a green 1x1 rectangle.
1219 SkPaint greenPaint;
1220 greenPaint.setColor(SK_ColorGREEN);
1221 recordingCanvas->drawRect(SkRect::Make(SkIRect::MakeWH(1, 1)), greenPaint);
reedca2622b2016-03-18 07:25:55 -07001222 picture = recorder.finishRecordingAsPicture();
robertphillips4418dba2016-03-07 12:45:14 -08001223 }
1224
robertphillips3e302272016-04-20 11:48:36 -07001225 sk_sp<SkSpecialImage> srcImg(create_empty_special_image(context, 2));
senorblanco3d822c22014-07-30 14:49:31 -07001226
robertphillips5ff17b12016-03-28 13:13:42 -07001227 sk_sp<SkImageFilter> imageFilter(SkPictureImageFilter::Make(picture));
senorblanco3d822c22014-07-30 14:49:31 -07001228
senorblanco3d822c22014-07-30 14:49:31 -07001229 SkIPoint offset;
brianosman2a75e5d2016-09-22 07:15:37 -07001230 SkImageFilter::OutputProperties noColorSpace(nullptr);
1231 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeXYWH(1, 1, 1, 1), nullptr, noColorSpace);
robertphillips4418dba2016-03-07 12:45:14 -08001232
robertphillips2302de92016-03-24 07:26:32 -07001233 sk_sp<SkSpecialImage> resultImage(imageFilter->filterImage(srcImg.get(), ctx, &offset));
robertphillips4418dba2016-03-07 12:45:14 -08001234 REPORTER_ASSERT(reporter, !resultImage);
senorblanco3d822c22014-07-30 14:49:31 -07001235}
1236
robertphillips4418dba2016-03-07 12:45:14 -08001237DEF_TEST(ImageFilterClippedPictureImageFilter, reporter) {
robertphillips3e302272016-04-20 11:48:36 -07001238 test_clipped_picture_imagefilter(reporter, nullptr);
robertphillips4418dba2016-03-07 12:45:14 -08001239}
1240
1241#if SK_SUPPORT_GPU
bsalomon68d91342016-04-12 09:59:58 -07001242DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterClippedPictureImageFilter_Gpu, reporter, ctxInfo) {
bsalomon8b7451a2016-05-11 06:33:06 -07001243 test_clipped_picture_imagefilter(reporter, ctxInfo.grContext());
robertphillips4418dba2016-03-07 12:45:14 -08001244}
1245#endif
1246
tfarina9ea53f92014-06-24 06:50:39 -07001247DEF_TEST(ImageFilterEmptySaveLayer, reporter) {
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001248 // Even when there's an empty saveLayer()/restore(), ensure that an image
1249 // filter or color filter which affects transparent black still draws.
1250
1251 SkBitmap bitmap;
1252 bitmap.allocN32Pixels(10, 10);
robertphillips9a53fd72015-06-22 09:46:59 -07001253 SkCanvas canvas(bitmap);
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001254
1255 SkRTreeFactory factory;
1256 SkPictureRecorder recorder;
1257
robertphillips5605b562016-04-05 11:50:42 -07001258 sk_sp<SkColorFilter> green(SkColorFilter::MakeModeFilter(SK_ColorGREEN,
Mike Reed7d954ad2016-10-28 15:42:34 -04001259 SkBlendMode::kSrc));
robertphillips5605b562016-04-05 11:50:42 -07001260 sk_sp<SkImageFilter> imageFilter(SkColorFilterImageFilter::Make(green, nullptr));
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001261 SkPaint imageFilterPaint;
robertphillips5605b562016-04-05 11:50:42 -07001262 imageFilterPaint.setImageFilter(std::move(imageFilter));
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001263 SkPaint colorFilterPaint;
reedd053ce92016-03-22 10:17:23 -07001264 colorFilterPaint.setColorFilter(green);
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001265
1266 SkRect bounds = SkRect::MakeWH(10, 10);
1267
1268 SkCanvas* recordingCanvas = recorder.beginRecording(10, 10, &factory, 0);
1269 recordingCanvas->saveLayer(&bounds, &imageFilterPaint);
1270 recordingCanvas->restore();
reedca2622b2016-03-18 07:25:55 -07001271 sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture());
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001272
1273 canvas.clear(0);
robertphillips9b14f262014-06-04 05:40:44 -07001274 canvas.drawPicture(picture);
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001275 uint32_t pixel = *bitmap.getAddr32(0, 0);
1276 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1277
1278 recordingCanvas = recorder.beginRecording(10, 10, &factory, 0);
halcanary96fcdcc2015-08-27 07:41:13 -07001279 recordingCanvas->saveLayer(nullptr, &imageFilterPaint);
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001280 recordingCanvas->restore();
reedca2622b2016-03-18 07:25:55 -07001281 sk_sp<SkPicture> picture2(recorder.finishRecordingAsPicture());
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001282
1283 canvas.clear(0);
robertphillips9b14f262014-06-04 05:40:44 -07001284 canvas.drawPicture(picture2);
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001285 pixel = *bitmap.getAddr32(0, 0);
1286 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1287
1288 recordingCanvas = recorder.beginRecording(10, 10, &factory, 0);
1289 recordingCanvas->saveLayer(&bounds, &colorFilterPaint);
1290 recordingCanvas->restore();
reedca2622b2016-03-18 07:25:55 -07001291 sk_sp<SkPicture> picture3(recorder.finishRecordingAsPicture());
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001292
1293 canvas.clear(0);
robertphillips9b14f262014-06-04 05:40:44 -07001294 canvas.drawPicture(picture3);
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001295 pixel = *bitmap.getAddr32(0, 0);
1296 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1297}
1298
robertphillips9a53fd72015-06-22 09:46:59 -07001299static void test_huge_blur(SkCanvas* canvas, skiatest::Reporter* reporter) {
senorblanco@chromium.org09843fd2014-03-24 20:50:59 +00001300 SkBitmap bitmap;
1301 bitmap.allocN32Pixels(100, 100);
1302 bitmap.eraseARGB(0, 0, 0, 0);
1303
1304 // Check that a blur with an insane radius does not crash or assert.
senorblanco@chromium.org09843fd2014-03-24 20:50:59 +00001305 SkPaint paint;
robertphillips6e7025a2016-04-04 04:31:25 -07001306 paint.setImageFilter(SkBlurImageFilter::Make(SkIntToScalar(1<<30),
1307 SkIntToScalar(1<<30),
1308 nullptr));
reedda420b92015-12-16 08:38:15 -08001309 canvas->drawBitmap(bitmap, 0, 0, &paint);
senorblanco@chromium.org09843fd2014-03-24 20:50:59 +00001310}
1311
1312DEF_TEST(HugeBlurImageFilter, reporter) {
1313 SkBitmap temp;
1314 temp.allocN32Pixels(100, 100);
robertphillips9a53fd72015-06-22 09:46:59 -07001315 SkCanvas canvas(temp);
1316 test_huge_blur(&canvas, reporter);
senorblanco@chromium.org09843fd2014-03-24 20:50:59 +00001317}
1318
senorblanco21a465d2016-04-11 11:58:39 -07001319DEF_TEST(ImageFilterMatrixConvolutionSanityTest, reporter) {
senorblanco3a495202014-09-29 07:57:20 -07001320 SkScalar kernel[1] = { 0 };
1321 SkScalar gain = SK_Scalar1, bias = 0;
1322 SkIPoint kernelOffset = SkIPoint::Make(1, 1);
1323
halcanary96fcdcc2015-08-27 07:41:13 -07001324 // Check that an enormous (non-allocatable) kernel gives a nullptr filter.
robertphillipsef6a47b2016-04-08 08:01:20 -07001325 sk_sp<SkImageFilter> conv(SkMatrixConvolutionImageFilter::Make(
senorblanco3a495202014-09-29 07:57:20 -07001326 SkISize::Make(1<<30, 1<<30),
1327 kernel,
1328 gain,
1329 bias,
1330 kernelOffset,
1331 SkMatrixConvolutionImageFilter::kRepeat_TileMode,
robertphillipsef6a47b2016-04-08 08:01:20 -07001332 false,
1333 nullptr));
senorblanco3a495202014-09-29 07:57:20 -07001334
halcanary96fcdcc2015-08-27 07:41:13 -07001335 REPORTER_ASSERT(reporter, nullptr == conv.get());
senorblanco3a495202014-09-29 07:57:20 -07001336
halcanary96fcdcc2015-08-27 07:41:13 -07001337 // Check that a nullptr kernel gives a nullptr filter.
robertphillipsef6a47b2016-04-08 08:01:20 -07001338 conv = SkMatrixConvolutionImageFilter::Make(
senorblanco3a495202014-09-29 07:57:20 -07001339 SkISize::Make(1, 1),
halcanary96fcdcc2015-08-27 07:41:13 -07001340 nullptr,
senorblanco3a495202014-09-29 07:57:20 -07001341 gain,
1342 bias,
1343 kernelOffset,
1344 SkMatrixConvolutionImageFilter::kRepeat_TileMode,
robertphillipsef6a47b2016-04-08 08:01:20 -07001345 false,
1346 nullptr);
senorblanco3a495202014-09-29 07:57:20 -07001347
halcanary96fcdcc2015-08-27 07:41:13 -07001348 REPORTER_ASSERT(reporter, nullptr == conv.get());
senorblanco3a495202014-09-29 07:57:20 -07001349
halcanary96fcdcc2015-08-27 07:41:13 -07001350 // Check that a kernel width < 1 gives a nullptr filter.
robertphillipsef6a47b2016-04-08 08:01:20 -07001351 conv = SkMatrixConvolutionImageFilter::Make(
senorblanco3a495202014-09-29 07:57:20 -07001352 SkISize::Make(0, 1),
1353 kernel,
1354 gain,
1355 bias,
1356 kernelOffset,
1357 SkMatrixConvolutionImageFilter::kRepeat_TileMode,
robertphillipsef6a47b2016-04-08 08:01:20 -07001358 false,
1359 nullptr);
senorblanco3a495202014-09-29 07:57:20 -07001360
halcanary96fcdcc2015-08-27 07:41:13 -07001361 REPORTER_ASSERT(reporter, nullptr == conv.get());
senorblanco3a495202014-09-29 07:57:20 -07001362
halcanary96fcdcc2015-08-27 07:41:13 -07001363 // Check that kernel height < 1 gives a nullptr filter.
robertphillipsef6a47b2016-04-08 08:01:20 -07001364 conv = SkMatrixConvolutionImageFilter::Make(
senorblanco3a495202014-09-29 07:57:20 -07001365 SkISize::Make(1, -1),
1366 kernel,
1367 gain,
1368 bias,
1369 kernelOffset,
1370 SkMatrixConvolutionImageFilter::kRepeat_TileMode,
robertphillipsef6a47b2016-04-08 08:01:20 -07001371 false,
1372 nullptr);
senorblanco3a495202014-09-29 07:57:20 -07001373
halcanary96fcdcc2015-08-27 07:41:13 -07001374 REPORTER_ASSERT(reporter, nullptr == conv.get());
senorblanco3a495202014-09-29 07:57:20 -07001375}
1376
Mike Reedf1942192017-07-21 14:24:29 -04001377static void test_xfermode_cropped_input(SkSurface* surf, skiatest::Reporter* reporter) {
1378 auto canvas = surf->getCanvas();
robertphillips9a53fd72015-06-22 09:46:59 -07001379 canvas->clear(0);
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001380
1381 SkBitmap bitmap;
1382 bitmap.allocN32Pixels(1, 1);
1383 bitmap.eraseARGB(255, 255, 255, 255);
1384
robertphillips5605b562016-04-05 11:50:42 -07001385 sk_sp<SkColorFilter> green(SkColorFilter::MakeModeFilter(SK_ColorGREEN,
Mike Reed7d954ad2016-10-28 15:42:34 -04001386 SkBlendMode::kSrcIn));
robertphillips5605b562016-04-05 11:50:42 -07001387 sk_sp<SkImageFilter> greenFilter(SkColorFilterImageFilter::Make(green, nullptr));
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001388 SkImageFilter::CropRect cropRect(SkRect::MakeEmpty());
robertphillips5605b562016-04-05 11:50:42 -07001389 sk_sp<SkImageFilter> croppedOut(SkColorFilterImageFilter::Make(green, nullptr, &cropRect));
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001390
1391 // Check that an xfermode image filter whose input has been cropped out still draws the other
1392 // input. Also check that drawing with both inputs cropped out doesn't cause a GPU warning.
reed374772b2016-10-05 17:33:02 -07001393 SkBlendMode mode = SkBlendMode::kSrcOver;
robertphillips8c0326d2016-04-05 12:48:34 -07001394 sk_sp<SkImageFilter> xfermodeNoFg(SkXfermodeImageFilter::Make(mode, greenFilter,
1395 croppedOut, nullptr));
1396 sk_sp<SkImageFilter> xfermodeNoBg(SkXfermodeImageFilter::Make(mode, croppedOut,
1397 greenFilter, nullptr));
1398 sk_sp<SkImageFilter> xfermodeNoFgNoBg(SkXfermodeImageFilter::Make(mode, croppedOut,
1399 croppedOut, nullptr));
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001400
1401 SkPaint paint;
robertphillips8c0326d2016-04-05 12:48:34 -07001402 paint.setImageFilter(std::move(xfermodeNoFg));
reedda420b92015-12-16 08:38:15 -08001403 canvas->drawBitmap(bitmap, 0, 0, &paint); // drawSprite
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001404
1405 uint32_t pixel;
kkinnunena9d9a392015-03-06 07:16:00 -08001406 SkImageInfo info = SkImageInfo::Make(1, 1, kBGRA_8888_SkColorType, kUnpremul_SkAlphaType);
Mike Reedf1942192017-07-21 14:24:29 -04001407 surf->readPixels(info, &pixel, 4, 0, 0);
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001408 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1409
robertphillips8c0326d2016-04-05 12:48:34 -07001410 paint.setImageFilter(std::move(xfermodeNoBg));
reedda420b92015-12-16 08:38:15 -08001411 canvas->drawBitmap(bitmap, 0, 0, &paint); // drawSprite
Mike Reedf1942192017-07-21 14:24:29 -04001412 surf->readPixels(info, &pixel, 4, 0, 0);
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001413 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1414
robertphillips8c0326d2016-04-05 12:48:34 -07001415 paint.setImageFilter(std::move(xfermodeNoFgNoBg));
reedda420b92015-12-16 08:38:15 -08001416 canvas->drawBitmap(bitmap, 0, 0, &paint); // drawSprite
Mike Reedf1942192017-07-21 14:24:29 -04001417 surf->readPixels(info, &pixel, 4, 0, 0);
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001418 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1419}
1420
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001421DEF_TEST(ImageFilterNestedSaveLayer, reporter) {
1422 SkBitmap temp;
1423 temp.allocN32Pixels(50, 50);
robertphillips9a53fd72015-06-22 09:46:59 -07001424 SkCanvas canvas(temp);
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001425 canvas.clear(0x0);
1426
1427 SkBitmap bitmap;
1428 bitmap.allocN32Pixels(10, 10);
1429 bitmap.eraseColor(SK_ColorGREEN);
1430
1431 SkMatrix matrix;
1432 matrix.setScale(SkIntToScalar(2), SkIntToScalar(2));
1433 matrix.postTranslate(SkIntToScalar(-20), SkIntToScalar(-20));
robertphillipsae8c9332016-04-05 15:09:00 -07001434 sk_sp<SkImageFilter> matrixFilter(
1435 SkImageFilter::MakeMatrixFilter(matrix, kLow_SkFilterQuality, nullptr));
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001436
1437 // Test that saveLayer() with a filter nested inside another saveLayer() applies the
1438 // correct offset to the filter matrix.
1439 SkRect bounds1 = SkRect::MakeXYWH(10, 10, 30, 30);
halcanary96fcdcc2015-08-27 07:41:13 -07001440 canvas.saveLayer(&bounds1, nullptr);
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001441 SkPaint filterPaint;
robertphillipsae8c9332016-04-05 15:09:00 -07001442 filterPaint.setImageFilter(std::move(matrixFilter));
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001443 SkRect bounds2 = SkRect::MakeXYWH(20, 20, 10, 10);
1444 canvas.saveLayer(&bounds2, &filterPaint);
1445 SkPaint greenPaint;
1446 greenPaint.setColor(SK_ColorGREEN);
1447 canvas.drawRect(bounds2, greenPaint);
1448 canvas.restore();
1449 canvas.restore();
1450 SkPaint strokePaint;
1451 strokePaint.setStyle(SkPaint::kStroke_Style);
1452 strokePaint.setColor(SK_ColorRED);
1453
kkinnunena9d9a392015-03-06 07:16:00 -08001454 SkImageInfo info = SkImageInfo::Make(1, 1, kBGRA_8888_SkColorType, kUnpremul_SkAlphaType);
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001455 uint32_t pixel;
Mike Reedf1942192017-07-21 14:24:29 -04001456 temp.readPixels(info, &pixel, 4, 25, 25);
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001457 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1458
1459 // Test that drawSprite() with a filter nested inside a saveLayer() applies the
1460 // correct offset to the filter matrix.
1461 canvas.clear(0x0);
Mike Reedf1942192017-07-21 14:24:29 -04001462 temp.readPixels(info, &pixel, 4, 25, 25);
halcanary96fcdcc2015-08-27 07:41:13 -07001463 canvas.saveLayer(&bounds1, nullptr);
reedda420b92015-12-16 08:38:15 -08001464 canvas.drawBitmap(bitmap, 20, 20, &filterPaint); // drawSprite
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001465 canvas.restore();
1466
Mike Reedf1942192017-07-21 14:24:29 -04001467 temp.readPixels(info, &pixel, 4, 25, 25);
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001468 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1469}
1470
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001471DEF_TEST(XfermodeImageFilterCroppedInput, reporter) {
Mike Reedf1942192017-07-21 14:24:29 -04001472 test_xfermode_cropped_input(SkSurface::MakeRasterN32Premul(100, 100).get(), reporter);
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001473}
senorblanco@chromium.org09843fd2014-03-24 20:50:59 +00001474
robertphillips3e302272016-04-20 11:48:36 -07001475static void test_composed_imagefilter_offset(skiatest::Reporter* reporter, GrContext* context) {
1476 sk_sp<SkSpecialImage> srcImg(create_empty_special_image(context, 100));
ajuma5788faa2015-02-13 09:05:47 -08001477
1478 SkImageFilter::CropRect cropRect(SkRect::MakeXYWH(1, 0, 20, 20));
robertphillips51a315e2016-03-31 09:05:49 -07001479 sk_sp<SkImageFilter> offsetFilter(SkOffsetImageFilter::Make(0, 0, nullptr, &cropRect));
robertphillips6e7025a2016-04-04 04:31:25 -07001480 sk_sp<SkImageFilter> blurFilter(SkBlurImageFilter::Make(SK_Scalar1, SK_Scalar1,
1481 nullptr, &cropRect));
robertphillips491fb172016-03-30 12:32:58 -07001482 sk_sp<SkImageFilter> composedFilter(SkComposeImageFilter::Make(std::move(blurFilter),
1483 std::move(offsetFilter)));
ajuma5788faa2015-02-13 09:05:47 -08001484 SkIPoint offset;
brianosman2a75e5d2016-09-22 07:15:37 -07001485 SkImageFilter::OutputProperties noColorSpace(nullptr);
1486 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeWH(100, 100), nullptr, noColorSpace);
robertphillips4418dba2016-03-07 12:45:14 -08001487
robertphillips2302de92016-03-24 07:26:32 -07001488 sk_sp<SkSpecialImage> resultImg(composedFilter->filterImage(srcImg.get(), ctx, &offset));
robertphillips4418dba2016-03-07 12:45:14 -08001489 REPORTER_ASSERT(reporter, resultImg);
ajuma5788faa2015-02-13 09:05:47 -08001490 REPORTER_ASSERT(reporter, offset.fX == 1 && offset.fY == 0);
1491}
1492
robertphillips4418dba2016-03-07 12:45:14 -08001493DEF_TEST(ComposedImageFilterOffset, reporter) {
robertphillips3e302272016-04-20 11:48:36 -07001494 test_composed_imagefilter_offset(reporter, nullptr);
robertphillips4418dba2016-03-07 12:45:14 -08001495}
1496
1497#if SK_SUPPORT_GPU
bsalomon68d91342016-04-12 09:59:58 -07001498DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ComposedImageFilterOffset_Gpu, reporter, ctxInfo) {
bsalomon8b7451a2016-05-11 06:33:06 -07001499 test_composed_imagefilter_offset(reporter, ctxInfo.grContext());
robertphillips4418dba2016-03-07 12:45:14 -08001500}
1501#endif
1502
robertphillips3e302272016-04-20 11:48:36 -07001503static void test_composed_imagefilter_bounds(skiatest::Reporter* reporter, GrContext* context) {
jbroman17a65202016-03-21 08:38:58 -07001504 // The bounds passed to the inner filter must be filtered by the outer
1505 // filter, so that the inner filter produces the pixels that the outer
1506 // filter requires as input. This matters if the outer filter moves pixels.
1507 // Here, accounting for the outer offset is necessary so that the green
1508 // pixels of the picture are not clipped.
1509
1510 SkPictureRecorder recorder;
1511 SkCanvas* recordingCanvas = recorder.beginRecording(SkRect::MakeWH(200, 100));
1512 recordingCanvas->clipRect(SkRect::MakeXYWH(100, 0, 100, 100));
1513 recordingCanvas->clear(SK_ColorGREEN);
robertphillips491fb172016-03-30 12:32:58 -07001514 sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture());
robertphillips5ff17b12016-03-28 13:13:42 -07001515 sk_sp<SkImageFilter> pictureFilter(SkPictureImageFilter::Make(picture));
jbroman17a65202016-03-21 08:38:58 -07001516 SkImageFilter::CropRect cropRect(SkRect::MakeWH(100, 100));
robertphillips51a315e2016-03-31 09:05:49 -07001517 sk_sp<SkImageFilter> offsetFilter(SkOffsetImageFilter::Make(-100, 0, nullptr, &cropRect));
robertphillips491fb172016-03-30 12:32:58 -07001518 sk_sp<SkImageFilter> composedFilter(SkComposeImageFilter::Make(std::move(offsetFilter),
1519 std::move(pictureFilter)));
jbroman17a65202016-03-21 08:38:58 -07001520
robertphillips3e302272016-04-20 11:48:36 -07001521 sk_sp<SkSpecialImage> sourceImage(create_empty_special_image(context, 100));
brianosman2a75e5d2016-09-22 07:15:37 -07001522 SkImageFilter::OutputProperties noColorSpace(nullptr);
1523 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeWH(100, 100), nullptr, noColorSpace);
jbroman17a65202016-03-21 08:38:58 -07001524 SkIPoint offset;
1525 sk_sp<SkSpecialImage> result(composedFilter->filterImage(sourceImage.get(), ctx, &offset));
1526 REPORTER_ASSERT(reporter, offset.isZero());
1527 REPORTER_ASSERT(reporter, result);
1528 REPORTER_ASSERT(reporter, result->subset().size() == SkISize::Make(100, 100));
1529
1530 SkBitmap resultBM;
robertphillips64612512016-04-08 12:10:42 -07001531 REPORTER_ASSERT(reporter, result->getROPixels(&resultBM));
jbroman17a65202016-03-21 08:38:58 -07001532 REPORTER_ASSERT(reporter, resultBM.getColor(50, 50) == SK_ColorGREEN);
1533}
1534
1535DEF_TEST(ComposedImageFilterBounds, reporter) {
robertphillips3e302272016-04-20 11:48:36 -07001536 test_composed_imagefilter_bounds(reporter, nullptr);
jbroman17a65202016-03-21 08:38:58 -07001537}
1538
1539#if SK_SUPPORT_GPU
egdanielab527a52016-06-28 08:07:26 -07001540DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ComposedImageFilterBounds_Gpu, reporter, ctxInfo) {
bsalomon8b7451a2016-05-11 06:33:06 -07001541 test_composed_imagefilter_bounds(reporter, ctxInfo.grContext());
jbroman17a65202016-03-21 08:38:58 -07001542}
1543#endif
1544
robertphillips3e302272016-04-20 11:48:36 -07001545static void test_partial_crop_rect(skiatest::Reporter* reporter, GrContext* context) {
1546 sk_sp<SkSpecialImage> srcImg(create_empty_special_image(context, 100));
senorblanco24d2a7b2015-07-13 10:27:05 -07001547
1548 SkImageFilter::CropRect cropRect(SkRect::MakeXYWH(100, 0, 20, 30),
senorblancoed7cf272015-07-16 15:19:11 -07001549 SkImageFilter::CropRect::kHasWidth_CropEdge | SkImageFilter::CropRect::kHasHeight_CropEdge);
robertphillips5605b562016-04-05 11:50:42 -07001550 sk_sp<SkImageFilter> filter(make_grayscale(nullptr, &cropRect));
senorblanco24d2a7b2015-07-13 10:27:05 -07001551 SkIPoint offset;
brianosman2a75e5d2016-09-22 07:15:37 -07001552 SkImageFilter::OutputProperties noColorSpace(nullptr);
1553 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeWH(100, 100), nullptr, noColorSpace);
robertphillips4418dba2016-03-07 12:45:14 -08001554
robertphillips2302de92016-03-24 07:26:32 -07001555 sk_sp<SkSpecialImage> resultImg(filter->filterImage(srcImg.get(), ctx, &offset));
robertphillips4418dba2016-03-07 12:45:14 -08001556 REPORTER_ASSERT(reporter, resultImg);
1557
senorblanco24d2a7b2015-07-13 10:27:05 -07001558 REPORTER_ASSERT(reporter, offset.fX == 0);
1559 REPORTER_ASSERT(reporter, offset.fY == 0);
robertphillips4418dba2016-03-07 12:45:14 -08001560 REPORTER_ASSERT(reporter, resultImg->width() == 20);
1561 REPORTER_ASSERT(reporter, resultImg->height() == 30);
senorblanco24d2a7b2015-07-13 10:27:05 -07001562}
1563
senorblanco21a465d2016-04-11 11:58:39 -07001564DEF_TEST(ImageFilterPartialCropRect, reporter) {
robertphillips3e302272016-04-20 11:48:36 -07001565 test_partial_crop_rect(reporter, nullptr);
robertphillips4418dba2016-03-07 12:45:14 -08001566}
1567
1568#if SK_SUPPORT_GPU
bsalomon68d91342016-04-12 09:59:58 -07001569DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterPartialCropRect_Gpu, reporter, ctxInfo) {
bsalomon8b7451a2016-05-11 06:33:06 -07001570 test_partial_crop_rect(reporter, ctxInfo.grContext());
robertphillips4418dba2016-03-07 12:45:14 -08001571}
1572#endif
1573
senorblanco0abdf762015-08-20 11:10:41 -07001574DEF_TEST(ImageFilterCanComputeFastBounds, reporter) {
1575
robertphillips12fa47d2016-04-08 16:28:09 -07001576 {
1577 SkPoint3 location = SkPoint3::Make(0, 0, SK_Scalar1);
1578 sk_sp<SkImageFilter> lighting(SkLightingImageFilter::MakePointLitDiffuse(location,
1579 SK_ColorGREEN,
1580 0, 0, nullptr));
1581 REPORTER_ASSERT(reporter, !lighting->canComputeFastBounds());
1582 }
senorblanco0abdf762015-08-20 11:10:41 -07001583
senorblanco0abdf762015-08-20 11:10:41 -07001584 {
robertphillips6e7025a2016-04-04 04:31:25 -07001585 sk_sp<SkImageFilter> gray(make_grayscale(nullptr, nullptr));
1586 REPORTER_ASSERT(reporter, gray->canComputeFastBounds());
1587 {
1588 SkColorFilter* grayCF;
1589 REPORTER_ASSERT(reporter, gray->asAColorFilter(&grayCF));
1590 REPORTER_ASSERT(reporter, !grayCF->affectsTransparentBlack());
1591 grayCF->unref();
1592 }
1593 REPORTER_ASSERT(reporter, gray->canComputeFastBounds());
1594
1595 sk_sp<SkImageFilter> grayBlur(SkBlurImageFilter::Make(SK_Scalar1, SK_Scalar1,
1596 std::move(gray)));
1597 REPORTER_ASSERT(reporter, grayBlur->canComputeFastBounds());
senorblanco0abdf762015-08-20 11:10:41 -07001598 }
senorblanco0abdf762015-08-20 11:10:41 -07001599
robertphillips6e7025a2016-04-04 04:31:25 -07001600 {
1601 SkScalar greenMatrix[20] = { 0, 0, 0, 0, 0,
1602 0, 0, 0, 0, 1,
1603 0, 0, 0, 0, 0,
1604 0, 0, 0, 0, 1 };
1605 sk_sp<SkColorFilter> greenCF(SkColorFilter::MakeMatrixFilterRowMajor255(greenMatrix));
robertphillips5605b562016-04-05 11:50:42 -07001606 sk_sp<SkImageFilter> green(SkColorFilterImageFilter::Make(greenCF, nullptr));
senorblanco0abdf762015-08-20 11:10:41 -07001607
robertphillips6e7025a2016-04-04 04:31:25 -07001608 REPORTER_ASSERT(reporter, greenCF->affectsTransparentBlack());
1609 REPORTER_ASSERT(reporter, !green->canComputeFastBounds());
senorblanco0abdf762015-08-20 11:10:41 -07001610
robertphillips6e7025a2016-04-04 04:31:25 -07001611 sk_sp<SkImageFilter> greenBlur(SkBlurImageFilter::Make(SK_Scalar1, SK_Scalar1,
1612 std::move(green)));
1613 REPORTER_ASSERT(reporter, !greenBlur->canComputeFastBounds());
1614 }
senorblanco0abdf762015-08-20 11:10:41 -07001615
1616 uint8_t allOne[256], identity[256];
1617 for (int i = 0; i < 256; ++i) {
1618 identity[i] = i;
1619 allOne[i] = 255;
1620 }
1621
robertphillips5605b562016-04-05 11:50:42 -07001622 sk_sp<SkColorFilter> identityCF(SkTableColorFilter::MakeARGB(identity, identity,
1623 identity, allOne));
1624 sk_sp<SkImageFilter> identityFilter(SkColorFilterImageFilter::Make(identityCF, nullptr));
senorblanco0abdf762015-08-20 11:10:41 -07001625 REPORTER_ASSERT(reporter, !identityCF->affectsTransparentBlack());
1626 REPORTER_ASSERT(reporter, identityFilter->canComputeFastBounds());
1627
robertphillips5605b562016-04-05 11:50:42 -07001628 sk_sp<SkColorFilter> forceOpaqueCF(SkTableColorFilter::MakeARGB(allOne, identity,
1629 identity, identity));
1630 sk_sp<SkImageFilter> forceOpaque(SkColorFilterImageFilter::Make(forceOpaqueCF, nullptr));
senorblanco0abdf762015-08-20 11:10:41 -07001631 REPORTER_ASSERT(reporter, forceOpaqueCF->affectsTransparentBlack());
1632 REPORTER_ASSERT(reporter, !forceOpaque->canComputeFastBounds());
1633}
1634
fmalitacd56f812015-09-14 13:31:18 -07001635// Verify that SkImageSource survives serialization
1636DEF_TEST(ImageFilterImageSourceSerialization, reporter) {
reede8f30622016-03-23 18:59:25 -07001637 auto surface(SkSurface::MakeRasterN32Premul(10, 10));
fmalitacd56f812015-09-14 13:31:18 -07001638 surface->getCanvas()->clear(SK_ColorGREEN);
reed9ce9d672016-03-17 10:51:11 -07001639 sk_sp<SkImage> image(surface->makeImageSnapshot());
robertphillips549c8992016-04-01 09:28:51 -07001640 sk_sp<SkImageFilter> filter(SkImageSource::Make(std::move(image)));
fmalitacd56f812015-09-14 13:31:18 -07001641
Mike Reed0331d372018-01-23 11:57:30 -05001642 sk_sp<SkData> data(filter->serialize());
1643 sk_sp<SkImageFilter> unflattenedFilter = SkImageFilter::Deserialize(data->data(), data->size());
fmalitacd56f812015-09-14 13:31:18 -07001644 REPORTER_ASSERT(reporter, unflattenedFilter);
1645
1646 SkBitmap bm;
1647 bm.allocN32Pixels(10, 10);
fmalita23cb88c2015-09-15 06:56:23 -07001648 bm.eraseColor(SK_ColorBLUE);
fmalitacd56f812015-09-14 13:31:18 -07001649 SkPaint paint;
1650 paint.setColor(SK_ColorRED);
1651 paint.setImageFilter(unflattenedFilter);
1652
1653 SkCanvas canvas(bm);
1654 canvas.drawRect(SkRect::MakeWH(10, 10), paint);
1655 REPORTER_ASSERT(reporter, *bm.getAddr32(0, 0) == SkPreMultiplyColor(SK_ColorGREEN));
1656}
1657
Leon Scroggins III4cdbf602017-09-28 14:33:57 -04001658DEF_TEST(ImageFilterImageSourceUninitialized, r) {
1659 sk_sp<SkData> data(GetResourceAsData("crbug769134.fil"));
1660 if (!data) {
1661 return;
1662 }
Mike Reed0331d372018-01-23 11:57:30 -05001663 sk_sp<SkImageFilter> unflattenedFilter = SkImageFilter::Deserialize(data->data(), data->size());
Leon Scroggins III4cdbf602017-09-28 14:33:57 -04001664 // This will fail. More importantly, msan will verify that we did not
1665 // compare against uninitialized memory.
1666 REPORTER_ASSERT(r, !unflattenedFilter);
1667}
1668
bsalomon45eefcf2016-01-05 08:39:28 -08001669static void test_large_blur_input(skiatest::Reporter* reporter, SkCanvas* canvas) {
1670 SkBitmap largeBmp;
1671 int largeW = 5000;
1672 int largeH = 5000;
1673#if SK_SUPPORT_GPU
1674 // If we're GPU-backed make the bitmap too large to be converted into a texture.
1675 if (GrContext* ctx = canvas->getGrContext()) {
Brian Salomonc7fe0f72018-05-11 10:14:21 -04001676 largeW = ctx->contextPriv().caps()->maxTextureSize() + 1;
bsalomon45eefcf2016-01-05 08:39:28 -08001677 }
1678#endif
1679
1680 largeBmp.allocN32Pixels(largeW, largeH);
mtklein2afbe232016-02-07 12:23:10 -08001681 largeBmp.eraseColor(0);
bsalomon45eefcf2016-01-05 08:39:28 -08001682 if (!largeBmp.getPixels()) {
1683 ERRORF(reporter, "Failed to allocate large bmp.");
1684 return;
1685 }
1686
reed9ce9d672016-03-17 10:51:11 -07001687 sk_sp<SkImage> largeImage(SkImage::MakeFromBitmap(largeBmp));
bsalomon45eefcf2016-01-05 08:39:28 -08001688 if (!largeImage) {
1689 ERRORF(reporter, "Failed to create large image.");
1690 return;
1691 }
1692
robertphillips549c8992016-04-01 09:28:51 -07001693 sk_sp<SkImageFilter> largeSource(SkImageSource::Make(std::move(largeImage)));
bsalomon45eefcf2016-01-05 08:39:28 -08001694 if (!largeSource) {
1695 ERRORF(reporter, "Failed to create large SkImageSource.");
1696 return;
1697 }
1698
robertphillips6e7025a2016-04-04 04:31:25 -07001699 sk_sp<SkImageFilter> blur(SkBlurImageFilter::Make(10.f, 10.f, std::move(largeSource)));
bsalomon45eefcf2016-01-05 08:39:28 -08001700 if (!blur) {
1701 ERRORF(reporter, "Failed to create SkBlurImageFilter.");
1702 return;
1703 }
1704
1705 SkPaint paint;
robertphillips549c8992016-04-01 09:28:51 -07001706 paint.setImageFilter(std::move(blur));
bsalomon45eefcf2016-01-05 08:39:28 -08001707
1708 // This should not crash (http://crbug.com/570479).
1709 canvas->drawRect(SkRect::MakeIWH(largeW, largeH), paint);
1710}
1711
senorblanco21a465d2016-04-11 11:58:39 -07001712DEF_TEST(ImageFilterBlurLargeImage, reporter) {
reede8f30622016-03-23 18:59:25 -07001713 auto surface(SkSurface::MakeRaster(SkImageInfo::MakeN32Premul(100, 100)));
bsalomon45eefcf2016-01-05 08:39:28 -08001714 test_large_blur_input(reporter, surface->getCanvas());
1715}
1716
senorblanco5878dbd2016-05-19 14:50:29 -07001717static void test_make_with_filter(skiatest::Reporter* reporter, GrContext* context) {
Robert Phillipsa5fdc972017-02-18 16:58:09 -05001718 sk_sp<SkSurface> surface(create_surface(context, 192, 128));
senorblanco5878dbd2016-05-19 14:50:29 -07001719 surface->getCanvas()->clear(SK_ColorRED);
1720 SkPaint bluePaint;
1721 bluePaint.setColor(SK_ColorBLUE);
1722 SkIRect subset = SkIRect::MakeXYWH(25, 20, 50, 50);
1723 surface->getCanvas()->drawRect(SkRect::Make(subset), bluePaint);
1724 sk_sp<SkImage> sourceImage = surface->makeImageSnapshot();
1725
1726 sk_sp<SkImageFilter> filter = make_grayscale(nullptr, nullptr);
1727 SkIRect clipBounds = SkIRect::MakeXYWH(30, 35, 100, 100);
1728 SkIRect outSubset;
1729 SkIPoint offset;
1730 sk_sp<SkImage> result;
1731
1732 result = sourceImage->makeWithFilter(nullptr, subset, clipBounds, &outSubset, &offset);
1733 REPORTER_ASSERT(reporter, !result);
1734
1735 result = sourceImage->makeWithFilter(filter.get(), subset, clipBounds, nullptr, &offset);
1736 REPORTER_ASSERT(reporter, !result);
1737
1738 result = sourceImage->makeWithFilter(filter.get(), subset, clipBounds, &outSubset, nullptr);
1739 REPORTER_ASSERT(reporter, !result);
1740
1741 SkIRect bigSubset = SkIRect::MakeXYWH(-10000, -10000, 20000, 20000);
1742 result = sourceImage->makeWithFilter(filter.get(), bigSubset, clipBounds, &outSubset, &offset);
1743 REPORTER_ASSERT(reporter, !result);
1744
1745 SkIRect empty = SkIRect::MakeEmpty();
1746 result = sourceImage->makeWithFilter(filter.get(), empty, clipBounds, &outSubset, &offset);
1747 REPORTER_ASSERT(reporter, !result);
1748
1749 result = sourceImage->makeWithFilter(filter.get(), subset, empty, &outSubset, &offset);
1750 REPORTER_ASSERT(reporter, !result);
1751
1752 SkIRect leftField = SkIRect::MakeXYWH(-1000, 0, 100, 100);
1753 result = sourceImage->makeWithFilter(filter.get(), subset, leftField, &outSubset, &offset);
1754 REPORTER_ASSERT(reporter, !result);
1755
1756 result = sourceImage->makeWithFilter(filter.get(), subset, clipBounds, &outSubset, &offset);
1757
1758 REPORTER_ASSERT(reporter, result);
1759 REPORTER_ASSERT(reporter, result->bounds().contains(outSubset));
1760 SkIRect destRect = SkIRect::MakeXYWH(offset.x(), offset.y(),
1761 outSubset.width(), outSubset.height());
1762 REPORTER_ASSERT(reporter, clipBounds.contains(destRect));
Robert Phillipsa5fdc972017-02-18 16:58:09 -05001763
1764 // In GPU-mode, this case creates a special image with a backing size that differs from
1765 // the content size
1766 {
1767 clipBounds.setXYWH(0, 0, 170, 100);
1768 subset.setXYWH(0, 0, 160, 90);
1769
1770 filter = SkXfermodeImageFilter::Make(SkBlendMode::kSrc, nullptr);
1771 result = sourceImage->makeWithFilter(filter.get(), subset, clipBounds, &outSubset, &offset);
1772 REPORTER_ASSERT(reporter, result);
1773 }
senorblanco5878dbd2016-05-19 14:50:29 -07001774}
1775
1776DEF_TEST(ImageFilterMakeWithFilter, reporter) {
1777 test_make_with_filter(reporter, nullptr);
1778}
1779
1780#if SK_SUPPORT_GPU
1781DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterMakeWithFilter_Gpu, reporter, ctxInfo) {
1782 test_make_with_filter(reporter, ctxInfo.grContext());
1783}
1784#endif
1785
senorblanco@chromium.org58d14662014-02-03 22:36:39 +00001786#if SK_SUPPORT_GPU
reed4a8126e2014-09-22 07:29:03 -07001787
bsalomon68d91342016-04-12 09:59:58 -07001788DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterHugeBlur_Gpu, reporter, ctxInfo) {
robertphillipsefbffed2015-06-22 12:06:08 -07001789
bsalomon8b7451a2016-05-11 06:33:06 -07001790 sk_sp<SkSurface> surf(SkSurface::MakeRenderTarget(ctxInfo.grContext(),
robertphillips3e302272016-04-20 11:48:36 -07001791 SkBudgeted::kNo,
1792 SkImageInfo::MakeN32Premul(100, 100)));
robertphillips9a53fd72015-06-22 09:46:59 -07001793
robertphillips3e302272016-04-20 11:48:36 -07001794
1795 SkCanvas* canvas = surf->getCanvas();
1796
1797 test_huge_blur(canvas, reporter);
senorblanco@chromium.org09843fd2014-03-24 20:50:59 +00001798}
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001799
egdanielab527a52016-06-28 08:07:26 -07001800DEF_GPUTEST_FOR_RENDERING_CONTEXTS(XfermodeImageFilterCroppedInput_Gpu, reporter, ctxInfo) {
Brian Salomon8996e182017-07-05 17:01:48 -04001801 sk_sp<SkSurface> surf(SkSurface::MakeRenderTarget(
1802 ctxInfo.grContext(),
1803 SkBudgeted::kNo,
1804 SkImageInfo::Make(1, 1, kRGBA_8888_SkColorType, kPremul_SkAlphaType)));
robertphillips3e302272016-04-20 11:48:36 -07001805
Mike Reedf1942192017-07-21 14:24:29 -04001806 test_xfermode_cropped_input(surf.get(), reporter);
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001807}
senorblanco32673b92014-09-09 09:15:04 -07001808
egdanielab527a52016-06-28 08:07:26 -07001809DEF_GPUTEST_FOR_ALL_CONTEXTS(ImageFilterBlurLargeImage_Gpu, reporter, ctxInfo) {
Brian Salomon8996e182017-07-05 17:01:48 -04001810 auto surface(SkSurface::MakeRenderTarget(
1811 ctxInfo.grContext(), SkBudgeted::kYes,
1812 SkImageInfo::Make(100, 100, kRGBA_8888_SkColorType, kPremul_SkAlphaType)));
bsalomon45eefcf2016-01-05 08:39:28 -08001813 test_large_blur_input(reporter, surface->getCanvas());
1814}
senorblanco@chromium.org58d14662014-02-03 22:36:39 +00001815#endif
reedbb34a8a2016-04-23 15:19:07 -07001816
1817/*
1818 * Test that colorfilterimagefilter does not require its CTM to be decomposed when it has more
1819 * than just scale/translate, but that other filters do.
1820 */
reed96a04f32016-04-25 09:25:15 -07001821DEF_TEST(ImageFilterComplexCTM, reporter) {
reedbb34a8a2016-04-23 15:19:07 -07001822 // just need a colorfilter to exercise the corresponding imagefilter
Mike Reed7d954ad2016-10-28 15:42:34 -04001823 sk_sp<SkColorFilter> cf = SkColorFilter::MakeModeFilter(SK_ColorRED, SkBlendMode::kSrcATop);
reed96a04f32016-04-25 09:25:15 -07001824 sk_sp<SkImageFilter> cfif = SkColorFilterImageFilter::Make(cf, nullptr); // can handle
1825 sk_sp<SkImageFilter> blif = SkBlurImageFilter::Make(3, 3, nullptr); // cannot handle
reedbb34a8a2016-04-23 15:19:07 -07001826
1827 struct {
1828 sk_sp<SkImageFilter> fFilter;
1829 bool fExpectCanHandle;
1830 } recs[] = {
1831 { cfif, true },
1832 { SkColorFilterImageFilter::Make(cf, cfif), true },
Mike Reed0bdaf052017-06-18 23:35:57 -04001833 { SkMergeImageFilter::Make(cfif, cfif), true },
reed96a04f32016-04-25 09:25:15 -07001834 { SkComposeImageFilter::Make(cfif, cfif), true },
1835
reedbb34a8a2016-04-23 15:19:07 -07001836 { blif, false },
reed96a04f32016-04-25 09:25:15 -07001837 { SkBlurImageFilter::Make(3, 3, cfif), false },
reedbb34a8a2016-04-23 15:19:07 -07001838 { SkColorFilterImageFilter::Make(cf, blif), false },
Mike Reed0bdaf052017-06-18 23:35:57 -04001839 { SkMergeImageFilter::Make(cfif, blif), false },
reed96a04f32016-04-25 09:25:15 -07001840 { SkComposeImageFilter::Make(blif, cfif), false },
reedbb34a8a2016-04-23 15:19:07 -07001841 };
liyuqianbfebe222016-11-14 11:17:16 -08001842
reedbb34a8a2016-04-23 15:19:07 -07001843 for (const auto& rec : recs) {
reed96a04f32016-04-25 09:25:15 -07001844 const bool canHandle = rec.fFilter->canHandleComplexCTM();
reedbb34a8a2016-04-23 15:19:07 -07001845 REPORTER_ASSERT(reporter, canHandle == rec.fExpectCanHandle);
1846 }
1847}
Florin Malita08252ec2017-07-06 12:48:15 -04001848
1849// Test that transforming the filter DAG doesn't clone shared nodes multiple times.
1850DEF_TEST(ImageFilterColorSpaceDAG, reporter) {
1851
1852 // Helper for counting makeColorSpace() clones.
1853 class TestFilter final : public SkImageFilter {
1854 public:
1855 TestFilter() : INHERITED(nullptr, 0, nullptr) {}
1856
Florin Malita08252ec2017-07-06 12:48:15 -04001857 void toString(SkString*) const override {}
Cary Clark99885412018-04-05 13:09:58 -04001858
Florin Malita08252ec2017-07-06 12:48:15 -04001859 Factory getFactory() const override { return nullptr; }
1860
1861 size_t cloneCount() const { return fCloneCount; }
1862
1863 protected:
1864 sk_sp<SkSpecialImage> onFilterImage(SkSpecialImage* src, const Context&,
1865 SkIPoint* offset) const override {
1866 return nullptr;
1867 }
1868 sk_sp<SkImageFilter> onMakeColorSpace(SkColorSpaceXformer*) const override {
1869 fCloneCount++;
1870 return sk_ref_sp(const_cast<TestFilter*>(this));
1871 }
1872
1873 private:
1874 typedef SkImageFilter INHERITED;
1875
1876 mutable size_t fCloneCount = 0;
1877 };
1878
1879 auto filter = sk_make_sp<TestFilter>();
1880 REPORTER_ASSERT(reporter, filter->cloneCount() == 0u);
1881
1882 // Build a DAG referencing the filter twice.
1883 auto complexFilter = SkMergeImageFilter::Make(filter, SkOffsetImageFilter::Make(1, 1, filter));
1884 REPORTER_ASSERT(reporter, filter->cloneCount() == 0u);
1885
1886 auto xformer = SkColorSpaceXformer::Make(SkColorSpace::MakeSRGB());
1887 auto xformedFilter = xformer->apply(complexFilter.get());
1888
Florin Malita39e08552017-07-06 14:16:18 -04001889 REPORTER_ASSERT(reporter, filter->cloneCount() == 1u);
Florin Malita08252ec2017-07-06 12:48:15 -04001890}
Xianzhu Wang0fa353c2017-08-25 16:27:04 -07001891
Xianzhu Wangb4496662017-09-25 10:26:40 -07001892// Test SkXfermodeImageFilter::filterBounds with different blending modes.
Xianzhu Wang0fa353c2017-08-25 16:27:04 -07001893DEF_TEST(XfermodeImageFilterBounds, reporter) {
1894 SkIRect background_rect = SkIRect::MakeXYWH(0, 0, 100, 100);
1895 SkIRect foreground_rect = SkIRect::MakeXYWH(50, 50, 100, 100);
1896 sk_sp<SkImageFilter> background(new FixedBoundsImageFilter(background_rect));
1897 sk_sp<SkImageFilter> foreground(new FixedBoundsImageFilter(foreground_rect));
1898
1899 const int kModeCount = static_cast<int>(SkBlendMode::kLastMode) + 1;
1900 SkIRect expectedBounds[kModeCount];
1901 // Expect union of input rects by default.
1902 for (int i = 0; i < kModeCount; ++i) {
1903 expectedBounds[i] = background_rect;
1904 expectedBounds[i].join(foreground_rect);
1905 }
1906
1907 SkIRect intersection = background_rect;
1908 intersection.intersect(foreground_rect);
1909 expectedBounds[static_cast<int>(SkBlendMode::kClear)] = SkIRect::MakeEmpty();
1910 expectedBounds[static_cast<int>(SkBlendMode::kSrc)] = foreground_rect;
1911 expectedBounds[static_cast<int>(SkBlendMode::kDst)] = background_rect;
1912 expectedBounds[static_cast<int>(SkBlendMode::kSrcIn)] = intersection;
1913 expectedBounds[static_cast<int>(SkBlendMode::kDstIn)] = intersection;
1914 expectedBounds[static_cast<int>(SkBlendMode::kSrcATop)] = background_rect;
1915 expectedBounds[static_cast<int>(SkBlendMode::kDstATop)] = foreground_rect;
1916
1917 // The value of this variable doesn't matter because we use inputs with fixed bounds.
1918 SkIRect src = SkIRect::MakeXYWH(11, 22, 33, 44);
1919 for (int i = 0; i < kModeCount; ++i) {
1920 sk_sp<SkImageFilter> xfermode(SkXfermodeImageFilter::Make(static_cast<SkBlendMode>(i),
1921 background, foreground, nullptr));
1922 auto bounds =
1923 xfermode->filterBounds(src, SkMatrix::I(), SkImageFilter::kForward_MapDirection);
1924 REPORTER_ASSERT(reporter, bounds == expectedBounds[i]);
1925 }
1926
1927 // Test empty intersection.
1928 sk_sp<SkImageFilter> background2(new FixedBoundsImageFilter(SkIRect::MakeXYWH(0, 0, 20, 20)));
1929 sk_sp<SkImageFilter> foreground2(new FixedBoundsImageFilter(SkIRect::MakeXYWH(40, 40, 50, 50)));
1930 sk_sp<SkImageFilter> xfermode(SkXfermodeImageFilter::Make(
1931 SkBlendMode::kSrcIn, std::move(background2), std::move(foreground2), nullptr));
1932 auto bounds = xfermode->filterBounds(src, SkMatrix::I(), SkImageFilter::kForward_MapDirection);
1933 REPORTER_ASSERT(reporter, bounds.isEmpty());
1934}
1935
Fredrik Söderquistb87f7982017-10-26 13:54:16 +02001936DEF_TEST(OffsetImageFilterBounds, reporter) {
1937 SkIRect src = SkIRect::MakeXYWH(0, 0, 100, 100);
1938 sk_sp<SkImageFilter> offset(SkOffsetImageFilter::Make(-50.5f, -50.5f, nullptr));
1939
1940 SkIRect expectedForward = SkIRect::MakeXYWH(-50, -50, 100, 100);
1941 SkIRect boundsForward = offset->filterBounds(src, SkMatrix::I(),
1942 SkImageFilter::kForward_MapDirection);
1943 REPORTER_ASSERT(reporter, boundsForward == expectedForward);
1944
1945 SkIRect expectedReverse = SkIRect::MakeXYWH(50, 50, 100, 100);
1946 SkIRect boundsReverse = offset->filterBounds(src, SkMatrix::I(),
1947 SkImageFilter::kReverse_MapDirection);
1948 REPORTER_ASSERT(reporter, boundsReverse == expectedReverse);
1949}
1950
Xianzhu Wang0fa353c2017-08-25 16:27:04 -07001951static void test_arithmetic_bounds(skiatest::Reporter* reporter, float k1, float k2, float k3,
1952 float k4, sk_sp<SkImageFilter> background,
1953 sk_sp<SkImageFilter> foreground,
1954 const SkImageFilter::CropRect* crop, const SkIRect& expected) {
1955 sk_sp<SkImageFilter> arithmetic(
1956 SkArithmeticImageFilter::Make(k1, k2, k3, k4, false, background, foreground, crop));
1957 // The value of the input rect doesn't matter because we use inputs with fixed bounds.
1958 SkIRect bounds = arithmetic->filterBounds(SkIRect::MakeXYWH(11, 22, 33, 44), SkMatrix::I(),
1959 SkImageFilter::kForward_MapDirection);
1960 REPORTER_ASSERT(reporter, expected == bounds);
1961}
1962
1963static void test_arithmetic_combinations(skiatest::Reporter* reporter, float v) {
1964 SkIRect background_rect = SkIRect::MakeXYWH(0, 0, 100, 100);
1965 SkIRect foreground_rect = SkIRect::MakeXYWH(50, 50, 100, 100);
1966 sk_sp<SkImageFilter> background(new FixedBoundsImageFilter(background_rect));
1967 sk_sp<SkImageFilter> foreground(new FixedBoundsImageFilter(foreground_rect));
1968
1969 SkIRect union_rect = background_rect;
1970 union_rect.join(foreground_rect);
1971 SkIRect intersection = background_rect;
1972 intersection.intersect(foreground_rect);
1973
1974 test_arithmetic_bounds(reporter, 0, 0, 0, 0, background, foreground, nullptr,
1975 SkIRect::MakeEmpty());
1976 test_arithmetic_bounds(reporter, 0, 0, 0, v, background, foreground, nullptr, union_rect);
1977 test_arithmetic_bounds(reporter, 0, 0, v, 0, background, foreground, nullptr, background_rect);
1978 test_arithmetic_bounds(reporter, 0, 0, v, v, background, foreground, nullptr, union_rect);
1979 test_arithmetic_bounds(reporter, 0, v, 0, 0, background, foreground, nullptr, foreground_rect);
1980 test_arithmetic_bounds(reporter, 0, v, 0, v, background, foreground, nullptr, union_rect);
1981 test_arithmetic_bounds(reporter, 0, v, v, 0, background, foreground, nullptr, union_rect);
1982 test_arithmetic_bounds(reporter, 0, v, v, v, background, foreground, nullptr, union_rect);
1983 test_arithmetic_bounds(reporter, v, 0, 0, 0, background, foreground, nullptr, intersection);
1984 test_arithmetic_bounds(reporter, v, 0, 0, v, background, foreground, nullptr, union_rect);
1985 test_arithmetic_bounds(reporter, v, 0, v, 0, background, foreground, nullptr, background_rect);
1986 test_arithmetic_bounds(reporter, v, 0, v, v, background, foreground, nullptr, union_rect);
1987 test_arithmetic_bounds(reporter, v, v, 0, 0, background, foreground, nullptr, foreground_rect);
1988 test_arithmetic_bounds(reporter, v, v, 0, v, background, foreground, nullptr, union_rect);
1989 test_arithmetic_bounds(reporter, v, v, v, 0, background, foreground, nullptr, union_rect);
1990 test_arithmetic_bounds(reporter, v, v, v, v, background, foreground, nullptr, union_rect);
1991
1992 // Test with crop. When k4 is non-zero, the result is expected to be crop_rect
1993 // regardless of inputs because the filter affects the whole crop area.
1994 SkIRect crop_rect = SkIRect::MakeXYWH(-111, -222, 333, 444);
1995 SkImageFilter::CropRect crop(SkRect::Make(crop_rect));
1996 test_arithmetic_bounds(reporter, 0, 0, 0, 0, background, foreground, &crop,
1997 SkIRect::MakeEmpty());
1998 test_arithmetic_bounds(reporter, 0, 0, 0, v, background, foreground, &crop, crop_rect);
1999 test_arithmetic_bounds(reporter, 0, 0, v, 0, background, foreground, &crop, background_rect);
2000 test_arithmetic_bounds(reporter, 0, 0, v, v, background, foreground, &crop, crop_rect);
2001 test_arithmetic_bounds(reporter, 0, v, 0, 0, background, foreground, &crop, foreground_rect);
2002 test_arithmetic_bounds(reporter, 0, v, 0, v, background, foreground, &crop, crop_rect);
2003 test_arithmetic_bounds(reporter, 0, v, v, 0, background, foreground, &crop, union_rect);
2004 test_arithmetic_bounds(reporter, 0, v, v, v, background, foreground, &crop, crop_rect);
2005 test_arithmetic_bounds(reporter, v, 0, 0, 0, background, foreground, &crop, intersection);
2006 test_arithmetic_bounds(reporter, v, 0, 0, v, background, foreground, &crop, crop_rect);
2007 test_arithmetic_bounds(reporter, v, 0, v, 0, background, foreground, &crop, background_rect);
2008 test_arithmetic_bounds(reporter, v, 0, v, v, background, foreground, &crop, crop_rect);
2009 test_arithmetic_bounds(reporter, v, v, 0, 0, background, foreground, &crop, foreground_rect);
2010 test_arithmetic_bounds(reporter, v, v, 0, v, background, foreground, &crop, crop_rect);
2011 test_arithmetic_bounds(reporter, v, v, v, 0, background, foreground, &crop, union_rect);
2012 test_arithmetic_bounds(reporter, v, v, v, v, background, foreground, &crop, crop_rect);
2013}
2014
Xianzhu Wangb4496662017-09-25 10:26:40 -07002015// Test SkArithmeticImageFilter::filterBounds with different blending modes.
Xianzhu Wang0fa353c2017-08-25 16:27:04 -07002016DEF_TEST(ArithmeticImageFilterBounds, reporter) {
2017 test_arithmetic_combinations(reporter, 1);
2018 test_arithmetic_combinations(reporter, 0.5);
2019}
Xianzhu Wangb4496662017-09-25 10:26:40 -07002020
2021// Test SkImageSource::filterBounds.
2022DEF_TEST(ImageSourceBounds, reporter) {
2023 sk_sp<SkImage> image(SkImage::MakeFromBitmap(make_gradient_circle(64, 64)));
2024 // Default src and dst rects.
2025 sk_sp<SkImageFilter> source1(SkImageSource::Make(image));
2026 SkIRect imageBounds = SkIRect::MakeWH(64, 64);
2027 SkIRect input(SkIRect::MakeXYWH(10, 20, 30, 40));
2028 REPORTER_ASSERT(reporter,
2029 imageBounds == source1->filterBounds(input, SkMatrix::I(),
2030 SkImageFilter::kForward_MapDirection));
2031 REPORTER_ASSERT(reporter,
2032 input == source1->filterBounds(input, SkMatrix::I(),
2033 SkImageFilter::kReverse_MapDirection));
2034 SkMatrix scale(SkMatrix::MakeScale(2));
2035 SkIRect scaledBounds = SkIRect::MakeWH(128, 128);
2036 REPORTER_ASSERT(reporter,
2037 scaledBounds == source1->filterBounds(input, scale,
2038 SkImageFilter::kForward_MapDirection));
2039 REPORTER_ASSERT(
2040 reporter,
2041 input == source1->filterBounds(input, scale, SkImageFilter::kReverse_MapDirection));
2042
2043 // Specified src and dst rects.
2044 SkRect src(SkRect::MakeXYWH(0.5, 0.5, 100.5, 100.5));
2045 SkRect dst(SkRect::MakeXYWH(-10.5, -10.5, 120.5, 120.5));
2046 sk_sp<SkImageFilter> source2(SkImageSource::Make(image, src, dst, kMedium_SkFilterQuality));
2047 REPORTER_ASSERT(reporter,
2048 dst.roundOut() == source2->filterBounds(input, SkMatrix::I(),
2049 SkImageFilter::kForward_MapDirection));
2050 REPORTER_ASSERT(reporter,
2051 input == source2->filterBounds(input, SkMatrix::I(),
2052 SkImageFilter::kReverse_MapDirection));
2053 scale.mapRect(&dst);
2054 scale.mapRect(&src);
2055 REPORTER_ASSERT(reporter,
2056 dst.roundOut() == source2->filterBounds(input, scale,
2057 SkImageFilter::kForward_MapDirection));
2058 REPORTER_ASSERT(
2059 reporter,
2060 input == source2->filterBounds(input, scale, SkImageFilter::kReverse_MapDirection));
2061}