blob: 0ae8d579f7e11eedd357ec4e7ed130a06f7851e4 [file] [log] [blame]
senorblanco@chromium.org194d7752013-07-24 22:19:24 +00001/*
2 * Copyright 2013 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
Xianzhu Wang0fa353c2017-08-25 16:27:04 -07008#include "SkArithmeticImageFilter.h"
commit-bot@chromium.org4b681bc2013-09-13 12:40:02 +00009#include "SkBitmap.h"
senorblanco@chromium.org6776b822014-01-03 21:48:22 +000010#include "SkBlurImageFilter.h"
tfarina@chromium.org8f6884a2014-01-24 20:56:26 +000011#include "SkCanvas.h"
12#include "SkColorFilterImageFilter.h"
13#include "SkColorMatrixFilter.h"
Florin Malita08252ec2017-07-06 12:48:15 -040014#include "SkColorSpaceXformer.h"
ajuma5788faa2015-02-13 09:05:47 -080015#include "SkComposeImageFilter.h"
senorblanco@chromium.org6776b822014-01-03 21:48:22 +000016#include "SkDisplacementMapEffect.h"
17#include "SkDropShadowImageFilter.h"
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +000018#include "SkGradientShader.h"
fmalita5598b632015-09-15 11:26:13 -070019#include "SkImage.h"
Cary Clark60aaeb22017-11-03 08:06:09 -040020#include "SkImageFilterPriv.h"
fmalitacd56f812015-09-14 13:31:18 -070021#include "SkImageSource.h"
commit-bot@chromium.org4b681bc2013-09-13 12:40:02 +000022#include "SkLightingImageFilter.h"
tfarina@chromium.org8f6884a2014-01-24 20:56:26 +000023#include "SkMatrixConvolutionImageFilter.h"
senorblanco@chromium.org6776b822014-01-03 21:48:22 +000024#include "SkMergeImageFilter.h"
25#include "SkMorphologyImageFilter.h"
senorblanco@chromium.org6776b822014-01-03 21:48:22 +000026#include "SkOffsetImageFilter.h"
ajuma77b6ba32016-01-08 14:58:35 -080027#include "SkPaintImageFilter.h"
senorblanco8f3937d2014-10-29 12:36:32 -070028#include "SkPerlinNoiseShader.h"
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +000029#include "SkPicture.h"
senorblanco@chromium.org910702b2014-05-30 20:36:15 +000030#include "SkPictureImageFilter.h"
robertphillips@google.com770963f2014-04-18 18:04:41 +000031#include "SkPictureRecorder.h"
robertphillips3d32d762015-07-13 13:16:44 -070032#include "SkPoint3.h"
halcanary97d2c0a2014-08-19 06:27:53 -070033#include "SkReadBuffer.h"
tfarina@chromium.org8f6884a2014-01-24 20:56:26 +000034#include "SkRect.h"
robertphillips4418dba2016-03-07 12:45:14 -080035#include "SkSpecialImage.h"
36#include "SkSpecialSurface.h"
fmalitacd56f812015-09-14 13:31:18 -070037#include "SkSurface.h"
senorblanco0abdf762015-08-20 11:10:41 -070038#include "SkTableColorFilter.h"
senorblanco@chromium.org6776b822014-01-03 21:48:22 +000039#include "SkTileImageFilter.h"
40#include "SkXfermodeImageFilter.h"
Leon Scroggins III4cdbf602017-09-28 14:33:57 -040041#include "Resources.h"
tfarina@chromium.org8f6884a2014-01-24 20:56:26 +000042#include "Test.h"
Mike Reed5a625e02017-08-08 15:48:54 -040043#include "sk_tool_utils.h"
senorblanco@chromium.org194d7752013-07-24 22:19:24 +000044
Brian Salomonc7fe0f72018-05-11 10:14:21 -040045#include "GrCaps.h"
kkinnunen15302832015-12-01 04:35:26 -080046#include "GrContext.h"
Brian Salomonc7fe0f72018-05-11 10:14:21 -040047#include "GrContextPriv.h"
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +000048
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +000049static const int kBitmapSize = 4;
commit-bot@chromium.org4b681bc2013-09-13 12:40:02 +000050
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +000051namespace {
52
53class MatrixTestImageFilter : public SkImageFilter {
54public:
robertphillips43c2ad42016-04-04 05:05:11 -070055 static sk_sp<SkImageFilter> Make(skiatest::Reporter* reporter,
56 const SkMatrix& expectedMatrix) {
57 return sk_sp<SkImageFilter>(new MatrixTestImageFilter(reporter, expectedMatrix));
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +000058 }
59
60 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(MatrixTestImageFilter)
61
62protected:
robertphillips4ba94e22016-04-04 12:07:47 -070063 sk_sp<SkSpecialImage> onFilterImage(SkSpecialImage* source, const Context& ctx,
64 SkIPoint* offset) const override {
robertphillips43c2ad42016-04-04 05:05:11 -070065 REPORTER_ASSERT(fReporter, ctx.ctm() == fExpectedMatrix);
robertphillips4ba94e22016-04-04 12:07:47 -070066 offset->fX = offset->fY = 0;
67 return sk_ref_sp<SkSpecialImage>(source);
robertphillips43c2ad42016-04-04 05:05:11 -070068 }
Matt Sarett62745a82017-04-17 11:57:29 -040069 sk_sp<SkImageFilter> onMakeColorSpace(SkColorSpaceXformer*) const override {
70 return sk_ref_sp(const_cast<MatrixTestImageFilter*>(this));
71 }
robertphillips43c2ad42016-04-04 05:05:11 -070072
mtklein36352bf2015-03-25 18:17:31 -070073 void flatten(SkWriteBuffer& buffer) const override {
brianosman18f13f32016-05-02 07:51:08 -070074 SkDEBUGFAIL("Should never get here");
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +000075 }
76
77private:
robertphillips43c2ad42016-04-04 05:05:11 -070078 MatrixTestImageFilter(skiatest::Reporter* reporter, const SkMatrix& expectedMatrix)
79 : INHERITED(nullptr, 0, nullptr)
80 , fReporter(reporter)
81 , fExpectedMatrix(expectedMatrix) {
82 }
83
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +000084 skiatest::Reporter* fReporter;
85 SkMatrix fExpectedMatrix;
mtklein3f3b3d02014-12-01 11:47:08 -080086
reed9fa60da2014-08-21 07:59:51 -070087 typedef SkImageFilter INHERITED;
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +000088};
89
senorblanco6a93fa12016-04-05 04:43:45 -070090class FailImageFilter : public SkImageFilter {
91public:
robertphillips6b134732016-04-15 09:58:37 -070092 FailImageFilter() : SkImageFilter(nullptr, 0, nullptr) { }
senorblanco6a93fa12016-04-05 04:43:45 -070093
94 sk_sp<SkSpecialImage> onFilterImage(SkSpecialImage* source,
95 const Context& ctx,
96 SkIPoint* offset) const override {
97 return nullptr;
98 }
Matt Sarett62745a82017-04-17 11:57:29 -040099 sk_sp<SkImageFilter> onMakeColorSpace(SkColorSpaceXformer*) const override {
100 return nullptr;
101 }
senorblanco6a93fa12016-04-05 04:43:45 -0700102
senorblanco6a93fa12016-04-05 04:43:45 -0700103 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(FailImageFilter)
104
105private:
106 typedef SkImageFilter INHERITED;
107};
108
109sk_sp<SkFlattenable> FailImageFilter::CreateProc(SkReadBuffer& buffer) {
110 SK_IMAGEFILTER_UNFLATTEN_COMMON(common, 0);
111 return sk_sp<SkFlattenable>(new FailImageFilter());
112}
113
senorblanco297f7ce2016-03-23 13:44:26 -0700114void draw_gradient_circle(SkCanvas* canvas, int width, int height) {
115 SkScalar x = SkIntToScalar(width / 2);
116 SkScalar y = SkIntToScalar(height / 2);
117 SkScalar radius = SkMinScalar(x, y) * 0.8f;
118 canvas->clear(0x00000000);
119 SkColor colors[2];
120 colors[0] = SK_ColorWHITE;
121 colors[1] = SK_ColorBLACK;
122 sk_sp<SkShader> shader(
123 SkGradientShader::MakeRadial(SkPoint::Make(x, y), radius, colors, nullptr, 2,
124 SkShader::kClamp_TileMode)
125 );
126 SkPaint paint;
127 paint.setShader(shader);
128 canvas->drawCircle(x, y, radius, paint);
129}
130
131SkBitmap make_gradient_circle(int width, int height) {
132 SkBitmap bitmap;
133 bitmap.allocN32Pixels(width, height);
134 SkCanvas canvas(bitmap);
135 draw_gradient_circle(&canvas, width, height);
136 return bitmap;
137}
138
139class FilterList {
140public:
robertphillipsfc11b0a2016-04-05 09:09:36 -0700141 FilterList(sk_sp<SkImageFilter> input, const SkImageFilter::CropRect* cropRect = nullptr) {
senorblanco297f7ce2016-03-23 13:44:26 -0700142 SkPoint3 location = SkPoint3::Make(0, 0, SK_Scalar1);
senorblanco297f7ce2016-03-23 13:44:26 -0700143 const SkScalar five = SkIntToScalar(5);
robertphillips6e7025a2016-04-04 04:31:25 -0700144 {
145 sk_sp<SkColorFilter> cf(SkColorFilter::MakeModeFilter(SK_ColorRED,
Mike Reed7d954ad2016-10-28 15:42:34 -0400146 SkBlendMode::kSrcIn));
senorblanco297f7ce2016-03-23 13:44:26 -0700147
robertphillips6e7025a2016-04-04 04:31:25 -0700148 this->addFilter("color filter",
robertphillips12fa47d2016-04-08 16:28:09 -0700149 SkColorFilterImageFilter::Make(std::move(cf), input, cropRect));
robertphillips6e7025a2016-04-04 04:31:25 -0700150 }
robertphillips6e7025a2016-04-04 04:31:25 -0700151 {
152 sk_sp<SkImage> gradientImage(SkImage::MakeFromBitmap(make_gradient_circle(64, 64)));
153 sk_sp<SkImageFilter> gradientSource(SkImageSource::Make(std::move(gradientImage)));
senorblanco297f7ce2016-03-23 13:44:26 -0700154
liyuqianbfebe222016-11-14 11:17:16 -0800155 this->addFilter("displacement map",
robertphillipsbfe11fc2016-04-15 07:17:36 -0700156 SkDisplacementMapEffect::Make(SkDisplacementMapEffect::kR_ChannelSelectorType,
157 SkDisplacementMapEffect::kB_ChannelSelectorType,
158 20.0f,
159 std::move(gradientSource), input, cropRect));
robertphillips6e7025a2016-04-04 04:31:25 -0700160 }
robertphillips6e7025a2016-04-04 04:31:25 -0700161 this->addFilter("blur", SkBlurImageFilter::Make(SK_Scalar1,
162 SK_Scalar1,
robertphillipsfc11b0a2016-04-05 09:09:36 -0700163 input,
robertphillips12fa47d2016-04-08 16:28:09 -0700164 cropRect));
robertphillipsc4169122016-04-06 08:40:59 -0700165 this->addFilter("drop shadow", SkDropShadowImageFilter::Make(
senorblanco297f7ce2016-03-23 13:44:26 -0700166 SK_Scalar1, SK_Scalar1, SK_Scalar1, SK_Scalar1, SK_ColorGREEN,
robertphillipsfc11b0a2016-04-05 09:09:36 -0700167 SkDropShadowImageFilter::kDrawShadowAndForeground_ShadowMode,
robertphillips12fa47d2016-04-08 16:28:09 -0700168 input, cropRect));
169 this->addFilter("diffuse lighting",
170 SkLightingImageFilter::MakePointLitDiffuse(location, SK_ColorGREEN, 0, 0,
171 input, cropRect));
senorblanco297f7ce2016-03-23 13:44:26 -0700172 this->addFilter("specular lighting",
robertphillips12fa47d2016-04-08 16:28:09 -0700173 SkLightingImageFilter::MakePointLitSpecular(location, SK_ColorGREEN, 0, 0, 0,
174 input, cropRect));
175 {
176 SkScalar kernel[9] = {
177 SkIntToScalar(1), SkIntToScalar(1), SkIntToScalar(1),
178 SkIntToScalar(1), SkIntToScalar(-7), SkIntToScalar(1),
179 SkIntToScalar(1), SkIntToScalar(1), SkIntToScalar(1),
180 };
181 const SkISize kernelSize = SkISize::Make(3, 3);
182 const SkScalar gain = SK_Scalar1, bias = 0;
183
Robert Phillips12078432018-05-17 11:17:39 -0400184 // This filter needs a saveLayer bc it is in repeat mode
robertphillips12fa47d2016-04-08 16:28:09 -0700185 this->addFilter("matrix convolution",
Robert Phillips12078432018-05-17 11:17:39 -0400186 SkMatrixConvolutionImageFilter::Make(
187 kernelSize, kernel, gain, bias, SkIPoint::Make(1, 1),
188 SkMatrixConvolutionImageFilter::kRepeat_TileMode, false,
189 input, cropRect),
190 true);
robertphillips12fa47d2016-04-08 16:28:09 -0700191 }
Mike Reed0bdaf052017-06-18 23:35:57 -0400192 this->addFilter("merge", SkMergeImageFilter::Make(input, input, cropRect));
robertphillips12fa47d2016-04-08 16:28:09 -0700193
robertphillips6e7025a2016-04-04 04:31:25 -0700194 {
195 SkPaint greenColorShaderPaint;
196 greenColorShaderPaint.setShader(SkShader::MakeColorShader(SK_ColorGREEN));
197
198 SkImageFilter::CropRect leftSideCropRect(SkRect::MakeXYWH(0, 0, 32, 64));
199 sk_sp<SkImageFilter> paintFilterLeft(SkPaintImageFilter::Make(greenColorShaderPaint,
200 &leftSideCropRect));
201 SkImageFilter::CropRect rightSideCropRect(SkRect::MakeXYWH(32, 0, 32, 64));
202 sk_sp<SkImageFilter> paintFilterRight(SkPaintImageFilter::Make(greenColorShaderPaint,
203 &rightSideCropRect));
204
205
206 this->addFilter("merge with disjoint inputs", SkMergeImageFilter::Make(
Mike Reed0bdaf052017-06-18 23:35:57 -0400207 std::move(paintFilterLeft), std::move(paintFilterRight), cropRect));
robertphillips6e7025a2016-04-04 04:31:25 -0700208 }
209
senorblanco297f7ce2016-03-23 13:44:26 -0700210 this->addFilter("offset",
robertphillipsfc11b0a2016-04-05 09:09:36 -0700211 SkOffsetImageFilter::Make(SK_Scalar1, SK_Scalar1, input,
robertphillips12fa47d2016-04-08 16:28:09 -0700212 cropRect));
213 this->addFilter("dilate", SkDilateImageFilter::Make(3, 2, input, cropRect));
214 this->addFilter("erode", SkErodeImageFilter::Make(2, 3, input, cropRect));
robertphillips534c2702016-04-15 07:57:40 -0700215 this->addFilter("tile", SkTileImageFilter::Make(
216 SkRect::MakeXYWH(0, 0, 50, 50),
217 cropRect ? cropRect->rect() : SkRect::MakeXYWH(0, 0, 100, 100),
218 input));
robertphillips6e7025a2016-04-04 04:31:25 -0700219
robertphillips12fa47d2016-04-08 16:28:09 -0700220 if (!cropRect) {
221 SkMatrix matrix;
222
223 matrix.setTranslate(SK_Scalar1, SK_Scalar1);
224 matrix.postRotate(SkIntToScalar(45), SK_Scalar1, SK_Scalar1);
225
226 this->addFilter("matrix",
227 SkImageFilter::MakeMatrixFilter(matrix, kLow_SkFilterQuality, input));
228 }
robertphillips6e7025a2016-04-04 04:31:25 -0700229 {
robertphillipsfc11b0a2016-04-05 09:09:36 -0700230 sk_sp<SkImageFilter> blur(SkBlurImageFilter::Make(five, five, input));
robertphillips6e7025a2016-04-04 04:31:25 -0700231
232 this->addFilter("blur and offset", SkOffsetImageFilter::Make(five, five,
233 std::move(blur),
robertphillips12fa47d2016-04-08 16:28:09 -0700234 cropRect));
robertphillips6e7025a2016-04-04 04:31:25 -0700235 }
236 {
robertphillips6e7025a2016-04-04 04:31:25 -0700237 SkPictureRecorder recorder;
Mike Klein26eb16f2017-04-10 09:50:25 -0400238 SkCanvas* recordingCanvas = recorder.beginRecording(64, 64);
robertphillips6e7025a2016-04-04 04:31:25 -0700239
240 SkPaint greenPaint;
241 greenPaint.setColor(SK_ColorGREEN);
242 recordingCanvas->drawRect(SkRect::Make(SkIRect::MakeXYWH(10, 10, 30, 20)), greenPaint);
243 sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture());
244 sk_sp<SkImageFilter> pictureFilter(SkPictureImageFilter::Make(std::move(picture)));
245
246 this->addFilter("picture and blur", SkBlurImageFilter::Make(five, five,
247 std::move(pictureFilter),
robertphillips12fa47d2016-04-08 16:28:09 -0700248 cropRect));
robertphillips6e7025a2016-04-04 04:31:25 -0700249 }
250 {
251 SkPaint paint;
252 paint.setShader(SkPerlinNoiseShader::MakeTurbulence(SK_Scalar1, SK_Scalar1, 1, 0));
253 sk_sp<SkImageFilter> paintFilter(SkPaintImageFilter::Make(paint));
254
255 this->addFilter("paint and blur", SkBlurImageFilter::Make(five, five,
256 std::move(paintFilter),
robertphillips12fa47d2016-04-08 16:28:09 -0700257 cropRect));
robertphillips6e7025a2016-04-04 04:31:25 -0700258 }
reed374772b2016-10-05 17:33:02 -0700259 this->addFilter("xfermode", SkXfermodeImageFilter::Make(SkBlendMode::kSrc, input, input,
260 cropRect));
senorblanco297f7ce2016-03-23 13:44:26 -0700261 }
262 int count() const { return fFilters.count(); }
263 SkImageFilter* getFilter(int index) const { return fFilters[index].fFilter.get(); }
264 const char* getName(int index) const { return fFilters[index].fName; }
Robert Phillips12078432018-05-17 11:17:39 -0400265 bool needsSaveLayer(int index) const { return fFilters[index].fNeedsSaveLayer; }
senorblanco297f7ce2016-03-23 13:44:26 -0700266private:
267 struct Filter {
Robert Phillips12078432018-05-17 11:17:39 -0400268 Filter() : fName(nullptr), fNeedsSaveLayer(false) {}
269 Filter(const char* name, sk_sp<SkImageFilter> filter, bool needsSaveLayer)
robertphillips12fa47d2016-04-08 16:28:09 -0700270 : fName(name)
Robert Phillips12078432018-05-17 11:17:39 -0400271 , fFilter(std::move(filter))
272 , fNeedsSaveLayer(needsSaveLayer) {
robertphillips12fa47d2016-04-08 16:28:09 -0700273 }
senorblanco297f7ce2016-03-23 13:44:26 -0700274 const char* fName;
275 sk_sp<SkImageFilter> fFilter;
Robert Phillips12078432018-05-17 11:17:39 -0400276 bool fNeedsSaveLayer;
senorblanco297f7ce2016-03-23 13:44:26 -0700277 };
Robert Phillips12078432018-05-17 11:17:39 -0400278 void addFilter(const char* name, sk_sp<SkImageFilter> filter, bool needsSaveLayer = false) {
279 fFilters.push_back(Filter(name, std::move(filter), needsSaveLayer));
senorblanco297f7ce2016-03-23 13:44:26 -0700280 }
281
282 SkTArray<Filter> fFilters;
283};
284
Xianzhu Wang0fa353c2017-08-25 16:27:04 -0700285class FixedBoundsImageFilter : public SkImageFilter {
286public:
287 FixedBoundsImageFilter(const SkIRect& bounds)
288 : SkImageFilter(nullptr, 0, nullptr), fBounds(bounds) {}
289
290private:
Xianzhu Wang0fa353c2017-08-25 16:27:04 -0700291 Factory getFactory() const override { return nullptr; }
292
293 sk_sp<SkSpecialImage> onFilterImage(SkSpecialImage* src, const Context&,
294 SkIPoint* offset) const override {
295 return nullptr;
296 }
297 sk_sp<SkImageFilter> onMakeColorSpace(SkColorSpaceXformer*) const override { return nullptr; }
298
Robert Phillips12078432018-05-17 11:17:39 -0400299 SkIRect onFilterBounds(const SkIRect&, const SkMatrix&,
300 MapDirection, const SkIRect*) const override {
Xianzhu Wang0fa353c2017-08-25 16:27:04 -0700301 return fBounds;
302 }
303
304 SkIRect fBounds;
305};
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +0000306}
307
reed60c9b582016-04-03 09:11:13 -0700308sk_sp<SkFlattenable> MatrixTestImageFilter::CreateProc(SkReadBuffer& buffer) {
brianosman18f13f32016-05-02 07:51:08 -0700309 SkDEBUGFAIL("Should never get here");
310 return nullptr;
reed9fa60da2014-08-21 07:59:51 -0700311}
312
reed9ce9d672016-03-17 10:51:11 -0700313static sk_sp<SkImage> make_small_image() {
reede8f30622016-03-23 18:59:25 -0700314 auto surface(SkSurface::MakeRasterN32Premul(kBitmapSize, kBitmapSize));
fmalita5598b632015-09-15 11:26:13 -0700315 SkCanvas* canvas = surface->getCanvas();
316 canvas->clear(0x00000000);
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000317 SkPaint darkPaint;
318 darkPaint.setColor(0xFF804020);
319 SkPaint lightPaint;
320 lightPaint.setColor(0xFF244484);
321 const int i = kBitmapSize / 4;
322 for (int y = 0; y < kBitmapSize; y += i) {
323 for (int x = 0; x < kBitmapSize; x += i) {
fmalita5598b632015-09-15 11:26:13 -0700324 canvas->save();
325 canvas->translate(SkIntToScalar(x), SkIntToScalar(y));
326 canvas->drawRect(SkRect::MakeXYWH(0, 0,
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000327 SkIntToScalar(i),
328 SkIntToScalar(i)), darkPaint);
fmalita5598b632015-09-15 11:26:13 -0700329 canvas->drawRect(SkRect::MakeXYWH(SkIntToScalar(i),
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000330 0,
331 SkIntToScalar(i),
332 SkIntToScalar(i)), lightPaint);
fmalita5598b632015-09-15 11:26:13 -0700333 canvas->drawRect(SkRect::MakeXYWH(0,
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000334 SkIntToScalar(i),
335 SkIntToScalar(i),
336 SkIntToScalar(i)), lightPaint);
fmalita5598b632015-09-15 11:26:13 -0700337 canvas->drawRect(SkRect::MakeXYWH(SkIntToScalar(i),
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000338 SkIntToScalar(i),
339 SkIntToScalar(i),
340 SkIntToScalar(i)), darkPaint);
fmalita5598b632015-09-15 11:26:13 -0700341 canvas->restore();
commit-bot@chromium.org4b681bc2013-09-13 12:40:02 +0000342 }
343 }
fmalita5598b632015-09-15 11:26:13 -0700344
reed9ce9d672016-03-17 10:51:11 -0700345 return surface->makeImageSnapshot();
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000346}
senorblanco@chromium.org194d7752013-07-24 22:19:24 +0000347
robertphillips5605b562016-04-05 11:50:42 -0700348static sk_sp<SkImageFilter> make_scale(float amount, sk_sp<SkImageFilter> input) {
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000349 SkScalar s = amount;
350 SkScalar matrix[20] = { s, 0, 0, 0, 0,
351 0, s, 0, 0, 0,
352 0, 0, s, 0, 0,
353 0, 0, 0, s, 0 };
robertphillips5605b562016-04-05 11:50:42 -0700354 sk_sp<SkColorFilter> filter(SkColorFilter::MakeMatrixFilterRowMajor255(matrix));
355 return SkColorFilterImageFilter::Make(std::move(filter), std::move(input));
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000356}
357
robertphillips5605b562016-04-05 11:50:42 -0700358static sk_sp<SkImageFilter> make_grayscale(sk_sp<SkImageFilter> input,
359 const SkImageFilter::CropRect* cropRect) {
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000360 SkScalar matrix[20];
361 memset(matrix, 0, 20 * sizeof(SkScalar));
362 matrix[0] = matrix[5] = matrix[10] = 0.2126f;
363 matrix[1] = matrix[6] = matrix[11] = 0.7152f;
364 matrix[2] = matrix[7] = matrix[12] = 0.0722f;
365 matrix[18] = 1.0f;
robertphillips5605b562016-04-05 11:50:42 -0700366 sk_sp<SkColorFilter> filter(SkColorFilter::MakeMatrixFilterRowMajor255(matrix));
367 return SkColorFilterImageFilter::Make(std::move(filter), std::move(input), cropRect);
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000368}
369
robertphillips5605b562016-04-05 11:50:42 -0700370static sk_sp<SkImageFilter> make_blue(sk_sp<SkImageFilter> input,
371 const SkImageFilter::CropRect* cropRect) {
372 sk_sp<SkColorFilter> filter(SkColorFilter::MakeModeFilter(SK_ColorBLUE,
Mike Reed7d954ad2016-10-28 15:42:34 -0400373 SkBlendMode::kSrcIn));
robertphillips5605b562016-04-05 11:50:42 -0700374 return SkColorFilterImageFilter::Make(std::move(filter), std::move(input), cropRect);
reedcedc36f2015-03-08 04:42:52 -0700375}
376
robertphillips3e302272016-04-20 11:48:36 -0700377static sk_sp<SkSpecialSurface> create_empty_special_surface(GrContext* context, int widthHeight) {
robertphillips4418dba2016-03-07 12:45:14 -0800378 if (context) {
robertphillips4df16562016-04-28 15:09:34 -0700379 return SkSpecialSurface::MakeRenderTarget(context,
380 widthHeight, widthHeight,
Brian Osman777b5632016-10-14 09:16:21 -0400381 kRGBA_8888_GrPixelConfig, nullptr);
Brian Osmanc7ad40f2018-05-31 14:27:17 -0400382 } else {
robertphillips4418dba2016-03-07 12:45:14 -0800383 const SkImageInfo info = SkImageInfo::MakeN32(widthHeight, widthHeight,
384 kOpaque_SkAlphaType);
robertphillips3e302272016-04-20 11:48:36 -0700385 return SkSpecialSurface::MakeRaster(info);
robertphillips4418dba2016-03-07 12:45:14 -0800386 }
senorblancobf680c32016-03-16 16:15:53 -0700387}
388
senorblanco5878dbd2016-05-19 14:50:29 -0700389static sk_sp<SkSurface> create_surface(GrContext* context, int width, int height) {
390 const SkImageInfo info = SkImageInfo::MakeN32(width, height, kOpaque_SkAlphaType);
senorblanco5878dbd2016-05-19 14:50:29 -0700391 if (context) {
392 return SkSurface::MakeRenderTarget(context, SkBudgeted::kNo, info);
Brian Osmanc7ad40f2018-05-31 14:27:17 -0400393 } else {
senorblanco5878dbd2016-05-19 14:50:29 -0700394 return SkSurface::MakeRaster(info);
395 }
396}
397
robertphillips3e302272016-04-20 11:48:36 -0700398static sk_sp<SkSpecialImage> create_empty_special_image(GrContext* context, int widthHeight) {
399 sk_sp<SkSpecialSurface> surf(create_empty_special_surface(context, widthHeight));
robertphillips4418dba2016-03-07 12:45:14 -0800400
401 SkASSERT(surf);
402
403 SkCanvas* canvas = surf->getCanvas();
404 SkASSERT(canvas);
405
406 canvas->clear(0x0);
407
robertphillips37bd7c32016-03-17 14:31:39 -0700408 return surf->makeImageSnapshot();
robertphillips4418dba2016-03-07 12:45:14 -0800409}
410
411
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000412DEF_TEST(ImageFilter, reporter) {
413 {
reedcedc36f2015-03-08 04:42:52 -0700414 // Check that two non-clipping color-matrice-filters concatenate into a single filter.
robertphillips5605b562016-04-05 11:50:42 -0700415 sk_sp<SkImageFilter> halfBrightness(make_scale(0.5f, nullptr));
416 sk_sp<SkImageFilter> quarterBrightness(make_scale(0.5f, std::move(halfBrightness)));
halcanary96fcdcc2015-08-27 07:41:13 -0700417 REPORTER_ASSERT(reporter, nullptr == quarterBrightness->getInput(0));
reedcedc36f2015-03-08 04:42:52 -0700418 SkColorFilter* cf;
419 REPORTER_ASSERT(reporter, quarterBrightness->asColorFilter(&cf));
halcanary96fcdcc2015-08-27 07:41:13 -0700420 REPORTER_ASSERT(reporter, cf->asColorMatrix(nullptr));
reedcedc36f2015-03-08 04:42:52 -0700421 cf->unref();
senorblanco@chromium.org194d7752013-07-24 22:19:24 +0000422 }
423
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000424 {
reedcedc36f2015-03-08 04:42:52 -0700425 // Check that a clipping color-matrice-filter followed by a color-matrice-filters
426 // concatenates into a single filter, but not a matrixfilter (due to clamping).
robertphillips5605b562016-04-05 11:50:42 -0700427 sk_sp<SkImageFilter> doubleBrightness(make_scale(2.0f, nullptr));
428 sk_sp<SkImageFilter> halfBrightness(make_scale(0.5f, std::move(doubleBrightness)));
halcanary96fcdcc2015-08-27 07:41:13 -0700429 REPORTER_ASSERT(reporter, nullptr == halfBrightness->getInput(0));
reedcedc36f2015-03-08 04:42:52 -0700430 SkColorFilter* cf;
431 REPORTER_ASSERT(reporter, halfBrightness->asColorFilter(&cf));
halcanary96fcdcc2015-08-27 07:41:13 -0700432 REPORTER_ASSERT(reporter, !cf->asColorMatrix(nullptr));
reedcedc36f2015-03-08 04:42:52 -0700433 cf->unref();
senorblanco@chromium.org194d7752013-07-24 22:19:24 +0000434 }
435
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000436 {
437 // Check that a color filter image filter without a crop rect can be
438 // expressed as a color filter.
robertphillips5605b562016-04-05 11:50:42 -0700439 sk_sp<SkImageFilter> gray(make_grayscale(nullptr, nullptr));
halcanary96fcdcc2015-08-27 07:41:13 -0700440 REPORTER_ASSERT(reporter, true == gray->asColorFilter(nullptr));
senorblanco@chromium.org194d7752013-07-24 22:19:24 +0000441 }
mtklein2afbe232016-02-07 12:23:10 -0800442
reedcedc36f2015-03-08 04:42:52 -0700443 {
444 // Check that a colorfilterimage filter without a crop rect but with an input
445 // that is another colorfilterimage can be expressed as a colorfilter (composed).
robertphillips5605b562016-04-05 11:50:42 -0700446 sk_sp<SkImageFilter> mode(make_blue(nullptr, nullptr));
447 sk_sp<SkImageFilter> gray(make_grayscale(std::move(mode), nullptr));
halcanary96fcdcc2015-08-27 07:41:13 -0700448 REPORTER_ASSERT(reporter, true == gray->asColorFilter(nullptr));
reedcedc36f2015-03-08 04:42:52 -0700449 }
450
451 {
452 // Test that if we exceed the limit of what ComposeColorFilter can combine, we still
453 // can build the DAG and won't assert if we call asColorFilter.
robertphillips5605b562016-04-05 11:50:42 -0700454 sk_sp<SkImageFilter> filter(make_blue(nullptr, nullptr));
reedcedc36f2015-03-08 04:42:52 -0700455 const int kWayTooManyForComposeColorFilter = 100;
456 for (int i = 0; i < kWayTooManyForComposeColorFilter; ++i) {
robertphillips5605b562016-04-05 11:50:42 -0700457 filter = make_blue(filter, nullptr);
reedcedc36f2015-03-08 04:42:52 -0700458 // the first few of these will succeed, but after we hit the internal limit,
459 // it will then return false.
halcanary96fcdcc2015-08-27 07:41:13 -0700460 (void)filter->asColorFilter(nullptr);
reedcedc36f2015-03-08 04:42:52 -0700461 }
462 }
reed5c518a82015-03-05 14:47:29 -0800463
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000464 {
465 // Check that a color filter image filter with a crop rect cannot
466 // be expressed as a color filter.
467 SkImageFilter::CropRect cropRect(SkRect::MakeXYWH(0, 0, 100, 100));
robertphillips5605b562016-04-05 11:50:42 -0700468 sk_sp<SkImageFilter> grayWithCrop(make_grayscale(nullptr, &cropRect));
halcanary96fcdcc2015-08-27 07:41:13 -0700469 REPORTER_ASSERT(reporter, false == grayWithCrop->asColorFilter(nullptr));
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000470 }
471
472 {
senorblanco3df05012014-07-03 11:13:09 -0700473 // Check that two non-commutative matrices are concatenated in
474 // the correct order.
475 SkScalar blueToRedMatrix[20] = { 0 };
476 blueToRedMatrix[2] = blueToRedMatrix[18] = SK_Scalar1;
477 SkScalar redToGreenMatrix[20] = { 0 };
478 redToGreenMatrix[5] = redToGreenMatrix[18] = SK_Scalar1;
robertphillips5605b562016-04-05 11:50:42 -0700479 sk_sp<SkColorFilter> blueToRed(SkColorFilter::MakeMatrixFilterRowMajor255(blueToRedMatrix));
480 sk_sp<SkImageFilter> filter1(SkColorFilterImageFilter::Make(std::move(blueToRed),
481 nullptr));
482 sk_sp<SkColorFilter> redToGreen(SkColorFilter::MakeMatrixFilterRowMajor255(redToGreenMatrix));
483 sk_sp<SkImageFilter> filter2(SkColorFilterImageFilter::Make(std::move(redToGreen),
484 std::move(filter1)));
senorblanco3df05012014-07-03 11:13:09 -0700485
486 SkBitmap result;
487 result.allocN32Pixels(kBitmapSize, kBitmapSize);
488
489 SkPaint paint;
490 paint.setColor(SK_ColorBLUE);
robertphillips5605b562016-04-05 11:50:42 -0700491 paint.setImageFilter(std::move(filter2));
senorblanco3df05012014-07-03 11:13:09 -0700492 SkCanvas canvas(result);
493 canvas.clear(0x0);
494 SkRect rect = SkRect::Make(SkIRect::MakeWH(kBitmapSize, kBitmapSize));
495 canvas.drawRect(rect, paint);
496 uint32_t pixel = *result.getAddr32(0, 0);
497 // The result here should be green, since we have effectively shifted blue to green.
498 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
499 }
500
501 {
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000502 // Tests pass by not asserting
reed9ce9d672016-03-17 10:51:11 -0700503 sk_sp<SkImage> image(make_small_image());
fmalita5598b632015-09-15 11:26:13 -0700504 SkBitmap result;
mike@reedtribe.orgdeee4962014-02-13 14:41:43 +0000505 result.allocN32Pixels(kBitmapSize, kBitmapSize);
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000506
senorblanco@chromium.org194d7752013-07-24 22:19:24 +0000507 {
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000508 // This tests for :
509 // 1 ) location at (0,0,1)
robertphillips3d32d762015-07-13 13:16:44 -0700510 SkPoint3 location = SkPoint3::Make(0, 0, SK_Scalar1);
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000511 // 2 ) location and target at same value
robertphillips3d32d762015-07-13 13:16:44 -0700512 SkPoint3 target = SkPoint3::Make(location.fX, location.fY, location.fZ);
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000513 // 3 ) large negative specular exponent value
514 SkScalar specularExponent = -1000;
515
robertphillips549c8992016-04-01 09:28:51 -0700516 sk_sp<SkImageFilter> bmSrc(SkImageSource::Make(std::move(image)));
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000517 SkPaint paint;
robertphillips12fa47d2016-04-08 16:28:09 -0700518 paint.setImageFilter(SkLightingImageFilter::MakeSpotLitSpecular(
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000519 location, target, specularExponent, 180,
520 0xFFFFFFFF, SK_Scalar1, SK_Scalar1, SK_Scalar1,
robertphillips12fa47d2016-04-08 16:28:09 -0700521 std::move(bmSrc)));
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000522 SkCanvas canvas(result);
523 SkRect r = SkRect::MakeWH(SkIntToScalar(kBitmapSize),
524 SkIntToScalar(kBitmapSize));
525 canvas.drawRect(r, paint);
senorblanco@chromium.org194d7752013-07-24 22:19:24 +0000526 }
senorblanco@chromium.org194d7752013-07-24 22:19:24 +0000527 }
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +0000528}
senorblanco@chromium.org6776b822014-01-03 21:48:22 +0000529
robertphillips3e302272016-04-20 11:48:36 -0700530static void test_crop_rects(skiatest::Reporter* reporter,
robertphillips4418dba2016-03-07 12:45:14 -0800531 GrContext* context) {
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +0000532 // Check that all filters offset to their absolute crop rect,
533 // unaffected by the input crop rect.
534 // Tests pass by not asserting.
robertphillips3e302272016-04-20 11:48:36 -0700535 sk_sp<SkSpecialImage> srcImg(create_empty_special_image(context, 100));
robertphillips4418dba2016-03-07 12:45:14 -0800536 SkASSERT(srcImg);
senorblanco@chromium.org6776b822014-01-03 21:48:22 +0000537
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +0000538 SkImageFilter::CropRect inputCropRect(SkRect::MakeXYWH(8, 13, 80, 80));
539 SkImageFilter::CropRect cropRect(SkRect::MakeXYWH(20, 30, 60, 60));
robertphillipsfc11b0a2016-04-05 09:09:36 -0700540 sk_sp<SkImageFilter> input(make_grayscale(nullptr, &inputCropRect));
senorblanco@chromium.org6776b822014-01-03 21:48:22 +0000541
robertphillipsfc11b0a2016-04-05 09:09:36 -0700542 FilterList filters(input, &cropRect);
senorblanco@chromium.org6776b822014-01-03 21:48:22 +0000543
senorblanco297f7ce2016-03-23 13:44:26 -0700544 for (int i = 0; i < filters.count(); ++i) {
545 SkImageFilter* filter = filters.getFilter(i);
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +0000546 SkIPoint offset;
Brian Osmana50205f2018-07-06 13:57:01 -0400547 SkImageFilter::OutputProperties noColorSpace(kN32_SkColorType, nullptr);
brianosman2a75e5d2016-09-22 07:15:37 -0700548 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeWH(100, 100), nullptr, noColorSpace);
robertphillips2302de92016-03-24 07:26:32 -0700549 sk_sp<SkSpecialImage> resultImg(filter->filterImage(srcImg.get(), ctx, &offset));
Brian Salomon1c80e992018-01-29 09:50:47 -0500550 REPORTER_ASSERT(reporter, resultImg, filters.getName(i));
551 REPORTER_ASSERT(reporter, offset.fX == 20 && offset.fY == 30, filters.getName(i));
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +0000552 }
553}
554
robertphillips3e302272016-04-20 11:48:36 -0700555static void test_negative_blur_sigma(skiatest::Reporter* reporter,
robertphillips4418dba2016-03-07 12:45:14 -0800556 GrContext* context) {
senorblanco32673b92014-09-09 09:15:04 -0700557 // Check that SkBlurImageFilter will accept a negative sigma, either in
558 // the given arguments or after CTM application.
reed5ea95df2015-10-06 14:05:32 -0700559 const int width = 32, height = 32;
560 const SkScalar five = SkIntToScalar(5);
senorblanco32673b92014-09-09 09:15:04 -0700561
robertphillips6e7025a2016-04-04 04:31:25 -0700562 sk_sp<SkImageFilter> positiveFilter(SkBlurImageFilter::Make(five, five, nullptr));
563 sk_sp<SkImageFilter> negativeFilter(SkBlurImageFilter::Make(-five, five, nullptr));
senorblanco32673b92014-09-09 09:15:04 -0700564
565 SkBitmap gradient = make_gradient_circle(width, height);
robertphillips3e302272016-04-20 11:48:36 -0700566 sk_sp<SkSpecialImage> imgSrc(SkSpecialImage::MakeFromRaster(SkIRect::MakeWH(width, height),
robertphillips37bd7c32016-03-17 14:31:39 -0700567 gradient));
robertphillips4418dba2016-03-07 12:45:14 -0800568
senorblanco32673b92014-09-09 09:15:04 -0700569 SkIPoint offset;
Brian Osmana50205f2018-07-06 13:57:01 -0400570 SkImageFilter::OutputProperties noColorSpace(kN32_SkColorType, nullptr);
brianosman2a75e5d2016-09-22 07:15:37 -0700571 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeWH(32, 32), nullptr, noColorSpace);
robertphillips4418dba2016-03-07 12:45:14 -0800572
robertphillips2302de92016-03-24 07:26:32 -0700573 sk_sp<SkSpecialImage> positiveResult1(positiveFilter->filterImage(imgSrc.get(), ctx, &offset));
robertphillips4418dba2016-03-07 12:45:14 -0800574 REPORTER_ASSERT(reporter, positiveResult1);
575
robertphillips2302de92016-03-24 07:26:32 -0700576 sk_sp<SkSpecialImage> negativeResult1(negativeFilter->filterImage(imgSrc.get(), ctx, &offset));
robertphillips4418dba2016-03-07 12:45:14 -0800577 REPORTER_ASSERT(reporter, negativeResult1);
578
senorblanco32673b92014-09-09 09:15:04 -0700579 SkMatrix negativeScale;
580 negativeScale.setScale(-SK_Scalar1, SK_Scalar1);
brianosman2a75e5d2016-09-22 07:15:37 -0700581 SkImageFilter::Context negativeCTX(negativeScale, SkIRect::MakeWH(32, 32), nullptr,
582 noColorSpace);
robertphillips4418dba2016-03-07 12:45:14 -0800583
robertphillips2302de92016-03-24 07:26:32 -0700584 sk_sp<SkSpecialImage> negativeResult2(positiveFilter->filterImage(imgSrc.get(),
585 negativeCTX,
586 &offset));
robertphillips4418dba2016-03-07 12:45:14 -0800587 REPORTER_ASSERT(reporter, negativeResult2);
588
robertphillips2302de92016-03-24 07:26:32 -0700589 sk_sp<SkSpecialImage> positiveResult2(negativeFilter->filterImage(imgSrc.get(),
590 negativeCTX,
591 &offset));
robertphillips4418dba2016-03-07 12:45:14 -0800592 REPORTER_ASSERT(reporter, positiveResult2);
593
594
595 SkBitmap positiveResultBM1, positiveResultBM2;
596 SkBitmap negativeResultBM1, negativeResultBM2;
597
robertphillips64612512016-04-08 12:10:42 -0700598 REPORTER_ASSERT(reporter, positiveResult1->getROPixels(&positiveResultBM1));
599 REPORTER_ASSERT(reporter, positiveResult2->getROPixels(&positiveResultBM2));
600 REPORTER_ASSERT(reporter, negativeResult1->getROPixels(&negativeResultBM1));
601 REPORTER_ASSERT(reporter, negativeResult2->getROPixels(&negativeResultBM2));
robertphillips4418dba2016-03-07 12:45:14 -0800602
senorblanco32673b92014-09-09 09:15:04 -0700603 for (int y = 0; y < height; y++) {
robertphillips4418dba2016-03-07 12:45:14 -0800604 int diffs = memcmp(positiveResultBM1.getAddr32(0, y),
605 negativeResultBM1.getAddr32(0, y),
606 positiveResultBM1.rowBytes());
senorblanco32673b92014-09-09 09:15:04 -0700607 REPORTER_ASSERT(reporter, !diffs);
608 if (diffs) {
609 break;
610 }
robertphillips4418dba2016-03-07 12:45:14 -0800611 diffs = memcmp(positiveResultBM1.getAddr32(0, y),
612 negativeResultBM2.getAddr32(0, y),
613 positiveResultBM1.rowBytes());
senorblanco32673b92014-09-09 09:15:04 -0700614 REPORTER_ASSERT(reporter, !diffs);
615 if (diffs) {
616 break;
617 }
robertphillips4418dba2016-03-07 12:45:14 -0800618 diffs = memcmp(positiveResultBM1.getAddr32(0, y),
619 positiveResultBM2.getAddr32(0, y),
620 positiveResultBM1.rowBytes());
senorblanco32673b92014-09-09 09:15:04 -0700621 REPORTER_ASSERT(reporter, !diffs);
622 if (diffs) {
623 break;
624 }
625 }
626}
627
senorblanco21a465d2016-04-11 11:58:39 -0700628DEF_TEST(ImageFilterNegativeBlurSigma, reporter) {
robertphillips3e302272016-04-20 11:48:36 -0700629 test_negative_blur_sigma(reporter, nullptr);
robertphillips4418dba2016-03-07 12:45:14 -0800630}
631
bsalomon68d91342016-04-12 09:59:58 -0700632DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterNegativeBlurSigma_Gpu, reporter, ctxInfo) {
bsalomon8b7451a2016-05-11 06:33:06 -0700633 test_negative_blur_sigma(reporter, ctxInfo.grContext());
robertphillips4418dba2016-03-07 12:45:14 -0800634}
robertphillips4418dba2016-03-07 12:45:14 -0800635
robertphillips3e302272016-04-20 11:48:36 -0700636static void test_zero_blur_sigma(skiatest::Reporter* reporter, GrContext* context) {
senorblancobf680c32016-03-16 16:15:53 -0700637 // Check that SkBlurImageFilter with a zero sigma and a non-zero srcOffset works correctly.
638 SkImageFilter::CropRect cropRect(SkRect::Make(SkIRect::MakeXYWH(5, 0, 5, 10)));
robertphillips51a315e2016-03-31 09:05:49 -0700639 sk_sp<SkImageFilter> input(SkOffsetImageFilter::Make(0, 0, nullptr, &cropRect));
robertphillips6e7025a2016-04-04 04:31:25 -0700640 sk_sp<SkImageFilter> filter(SkBlurImageFilter::Make(0, 0, std::move(input), &cropRect));
senorblancobf680c32016-03-16 16:15:53 -0700641
robertphillips3e302272016-04-20 11:48:36 -0700642 sk_sp<SkSpecialSurface> surf(create_empty_special_surface(context, 10));
senorblancobf680c32016-03-16 16:15:53 -0700643 surf->getCanvas()->clear(SK_ColorGREEN);
robertphillips37bd7c32016-03-17 14:31:39 -0700644 sk_sp<SkSpecialImage> image(surf->makeImageSnapshot());
senorblancobf680c32016-03-16 16:15:53 -0700645
646 SkIPoint offset;
Brian Osmana50205f2018-07-06 13:57:01 -0400647 SkImageFilter::OutputProperties noColorSpace(kN32_SkColorType, nullptr);
brianosman2a75e5d2016-09-22 07:15:37 -0700648 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeWH(32, 32), nullptr, noColorSpace);
senorblancobf680c32016-03-16 16:15:53 -0700649
robertphillips2302de92016-03-24 07:26:32 -0700650 sk_sp<SkSpecialImage> result(filter->filterImage(image.get(), ctx, &offset));
senorblancobf680c32016-03-16 16:15:53 -0700651 REPORTER_ASSERT(reporter, offset.fX == 5 && offset.fY == 0);
652 REPORTER_ASSERT(reporter, result);
653 REPORTER_ASSERT(reporter, result->width() == 5 && result->height() == 10);
654
655 SkBitmap resultBM;
656
robertphillips64612512016-04-08 12:10:42 -0700657 REPORTER_ASSERT(reporter, result->getROPixels(&resultBM));
senorblancobf680c32016-03-16 16:15:53 -0700658
senorblancobf680c32016-03-16 16:15:53 -0700659 for (int y = 0; y < resultBM.height(); y++) {
660 for (int x = 0; x < resultBM.width(); x++) {
661 bool diff = *resultBM.getAddr32(x, y) != SK_ColorGREEN;
662 REPORTER_ASSERT(reporter, !diff);
663 if (diff) {
664 break;
665 }
666 }
667 }
668}
669
senorblanco21a465d2016-04-11 11:58:39 -0700670DEF_TEST(ImageFilterZeroBlurSigma, reporter) {
robertphillips3e302272016-04-20 11:48:36 -0700671 test_zero_blur_sigma(reporter, nullptr);
senorblancobf680c32016-03-16 16:15:53 -0700672}
673
bsalomon68d91342016-04-12 09:59:58 -0700674DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterZeroBlurSigma_Gpu, reporter, ctxInfo) {
bsalomon8b7451a2016-05-11 06:33:06 -0700675 test_zero_blur_sigma(reporter, ctxInfo.grContext());
senorblancobf680c32016-03-16 16:15:53 -0700676}
senorblancobf680c32016-03-16 16:15:53 -0700677
senorblanco6a93fa12016-04-05 04:43:45 -0700678
679// Tests that, even when an upstream filter has returned null (due to failure or clipping), a
680// downstream filter that affects transparent black still does so even with a nullptr input.
robertphillips3e302272016-04-20 11:48:36 -0700681static void test_fail_affects_transparent_black(skiatest::Reporter* reporter, GrContext* context) {
senorblanco6a93fa12016-04-05 04:43:45 -0700682 sk_sp<FailImageFilter> failFilter(new FailImageFilter());
robertphillips3e302272016-04-20 11:48:36 -0700683 sk_sp<SkSpecialImage> source(create_empty_special_image(context, 5));
Brian Osmana50205f2018-07-06 13:57:01 -0400684 SkImageFilter::OutputProperties noColorSpace(kN32_SkColorType, nullptr);
brianosman2a75e5d2016-09-22 07:15:37 -0700685 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeXYWH(0, 0, 1, 1), nullptr, noColorSpace);
Mike Reed7d954ad2016-10-28 15:42:34 -0400686 sk_sp<SkColorFilter> green(SkColorFilter::MakeModeFilter(SK_ColorGREEN, SkBlendMode::kSrc));
senorblanco6a93fa12016-04-05 04:43:45 -0700687 SkASSERT(green->affectsTransparentBlack());
robertphillips5605b562016-04-05 11:50:42 -0700688 sk_sp<SkImageFilter> greenFilter(SkColorFilterImageFilter::Make(std::move(green),
689 std::move(failFilter)));
senorblanco6a93fa12016-04-05 04:43:45 -0700690 SkIPoint offset;
691 sk_sp<SkSpecialImage> result(greenFilter->filterImage(source.get(), ctx, &offset));
692 REPORTER_ASSERT(reporter, nullptr != result.get());
693 if (result.get()) {
694 SkBitmap resultBM;
robertphillips64612512016-04-08 12:10:42 -0700695 REPORTER_ASSERT(reporter, result->getROPixels(&resultBM));
senorblanco6a93fa12016-04-05 04:43:45 -0700696 REPORTER_ASSERT(reporter, *resultBM.getAddr32(0, 0) == SK_ColorGREEN);
697 }
698}
699
700DEF_TEST(ImageFilterFailAffectsTransparentBlack, reporter) {
robertphillips3e302272016-04-20 11:48:36 -0700701 test_fail_affects_transparent_black(reporter, nullptr);
senorblanco6a93fa12016-04-05 04:43:45 -0700702}
703
bsalomon68d91342016-04-12 09:59:58 -0700704DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterFailAffectsTransparentBlack_Gpu, reporter, ctxInfo) {
bsalomon8b7451a2016-05-11 06:33:06 -0700705 test_fail_affects_transparent_black(reporter, ctxInfo.grContext());
senorblanco6a93fa12016-04-05 04:43:45 -0700706}
senorblanco6a93fa12016-04-05 04:43:45 -0700707
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +0000708DEF_TEST(ImageFilterDrawTiled, reporter) {
709 // Check that all filters when drawn tiled (with subsequent clip rects) exactly
710 // match the same filters drawn with a single full-canvas bitmap draw.
711 // Tests pass by not asserting.
712
robertphillipsfc11b0a2016-04-05 09:09:36 -0700713 FilterList filters(nullptr);
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +0000714
715 SkBitmap untiledResult, tiledResult;
reed5ea95df2015-10-06 14:05:32 -0700716 const int width = 64, height = 64;
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +0000717 untiledResult.allocN32Pixels(width, height);
718 tiledResult.allocN32Pixels(width, height);
719 SkCanvas tiledCanvas(tiledResult);
720 SkCanvas untiledCanvas(untiledResult);
Robert Phillips12078432018-05-17 11:17:39 -0400721 const int tileSize = 8;
722
723 SkPaint textPaint;
Brian Osman2cbf12c2018-09-20 13:51:19 -0400724 sk_tool_utils::set_portable_typeface(&textPaint);
Robert Phillips12078432018-05-17 11:17:39 -0400725 textPaint.setTextSize(SkIntToScalar(height));
726 textPaint.setColor(SK_ColorWHITE);
727
728 const char* text = "ABC";
729 const SkScalar yPos = SkIntToScalar(height);
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +0000730
senorblanco@chromium.orgd4db6572014-05-07 20:00:04 +0000731 for (int scale = 1; scale <= 2; ++scale) {
senorblanco297f7ce2016-03-23 13:44:26 -0700732 for (int i = 0; i < filters.count(); ++i) {
Robert Phillips12078432018-05-17 11:17:39 -0400733 SkPaint combinedPaint;
Brian Osman2cbf12c2018-09-20 13:51:19 -0400734 sk_tool_utils::set_portable_typeface(&combinedPaint);
Robert Phillips12078432018-05-17 11:17:39 -0400735 combinedPaint.setTextSize(SkIntToScalar(height));
736 combinedPaint.setColor(SK_ColorWHITE);
737 combinedPaint.setImageFilter(sk_ref_sp(filters.getFilter(i)));
738
739 untiledCanvas.clear(SK_ColorTRANSPARENT);
senorblanco@chromium.orgd4db6572014-05-07 20:00:04 +0000740 untiledCanvas.save();
741 untiledCanvas.scale(SkIntToScalar(scale), SkIntToScalar(scale));
Robert Phillips12078432018-05-17 11:17:39 -0400742 untiledCanvas.drawString(text, 0, yPos, combinedPaint);
senorblanco@chromium.orgd4db6572014-05-07 20:00:04 +0000743 untiledCanvas.restore();
Robert Phillips12078432018-05-17 11:17:39 -0400744 untiledCanvas.flush();
745
746 tiledCanvas.clear(SK_ColorTRANSPARENT);
senorblanco@chromium.orgd4db6572014-05-07 20:00:04 +0000747 for (int y = 0; y < height; y += tileSize) {
748 for (int x = 0; x < width; x += tileSize) {
749 tiledCanvas.save();
Robert Phillips12078432018-05-17 11:17:39 -0400750 const SkRect clipRect = SkRect::MakeXYWH(x, y, tileSize, tileSize);
751 tiledCanvas.clipRect(clipRect);
752 if (filters.needsSaveLayer(i)) {
753 const SkRect layerBounds = SkRect::MakeWH(width, height);
754 tiledCanvas.saveLayer(&layerBounds, &combinedPaint);
755 tiledCanvas.scale(SkIntToScalar(scale), SkIntToScalar(scale));
756 tiledCanvas.drawString(text, 0, yPos, textPaint);
757 tiledCanvas.restore();
758 } else {
759 tiledCanvas.scale(SkIntToScalar(scale), SkIntToScalar(scale));
760 tiledCanvas.drawString(text, 0, yPos, combinedPaint);
761 }
762
senorblanco@chromium.orgd4db6572014-05-07 20:00:04 +0000763 tiledCanvas.restore();
764 }
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +0000765 }
senorblanco@chromium.orgd4db6572014-05-07 20:00:04 +0000766 tiledCanvas.flush();
Robert Phillips12078432018-05-17 11:17:39 -0400767
Brian Osman1b151982018-09-20 12:47:39 -0400768 if (!sk_tool_utils::equal_pixels(untiledResult, tiledResult)) {
Brian Salomon1c80e992018-01-29 09:50:47 -0500769 REPORTER_ASSERT(reporter, false, filters.getName(i));
Mike Reed5a625e02017-08-08 15:48:54 -0400770 break;
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +0000771 }
772 }
773 }
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +0000774}
775
mtklein3f3b3d02014-12-01 11:47:08 -0800776static void draw_saveLayer_picture(int width, int height, int tileSize,
robertphillipsa8d7f0b2014-08-29 08:03:56 -0700777 SkBBHFactory* factory, SkBitmap* result) {
mtkleind910f542014-08-22 09:06:34 -0700778
779 SkMatrix matrix;
780 matrix.setTranslate(SkIntToScalar(50), 0);
781
Mike Reed7d954ad2016-10-28 15:42:34 -0400782 sk_sp<SkColorFilter> cf(SkColorFilter::MakeModeFilter(SK_ColorWHITE, SkBlendMode::kSrc));
robertphillips5605b562016-04-05 11:50:42 -0700783 sk_sp<SkImageFilter> cfif(SkColorFilterImageFilter::Make(std::move(cf), nullptr));
robertphillipsae8c9332016-04-05 15:09:00 -0700784 sk_sp<SkImageFilter> imageFilter(SkImageFilter::MakeMatrixFilter(matrix,
785 kNone_SkFilterQuality,
786 std::move(cfif)));
mtkleind910f542014-08-22 09:06:34 -0700787
788 SkPaint paint;
robertphillips5605b562016-04-05 11:50:42 -0700789 paint.setImageFilter(std::move(imageFilter));
mtkleind910f542014-08-22 09:06:34 -0700790 SkPictureRecorder recorder;
791 SkRect bounds = SkRect::Make(SkIRect::MakeXYWH(0, 0, 50, 50));
mtklein3f3b3d02014-12-01 11:47:08 -0800792 SkCanvas* recordingCanvas = recorder.beginRecording(SkIntToScalar(width),
793 SkIntToScalar(height),
robertphillipsa8d7f0b2014-08-29 08:03:56 -0700794 factory, 0);
mtkleind910f542014-08-22 09:06:34 -0700795 recordingCanvas->translate(-55, 0);
796 recordingCanvas->saveLayer(&bounds, &paint);
797 recordingCanvas->restore();
reedca2622b2016-03-18 07:25:55 -0700798 sk_sp<SkPicture> picture1(recorder.finishRecordingAsPicture());
mtkleind910f542014-08-22 09:06:34 -0700799
800 result->allocN32Pixels(width, height);
801 SkCanvas canvas(*result);
802 canvas.clear(0);
803 canvas.clipRect(SkRect::Make(SkIRect::MakeWH(tileSize, tileSize)));
804 canvas.drawPicture(picture1.get());
805}
806
807DEF_TEST(ImageFilterDrawMatrixBBH, reporter) {
808 // Check that matrix filter when drawn tiled with BBH exactly
809 // matches the same thing drawn without BBH.
810 // Tests pass by not asserting.
811
812 const int width = 200, height = 200;
813 const int tileSize = 100;
814 SkBitmap result1, result2;
815 SkRTreeFactory factory;
816
robertphillipsa8d7f0b2014-08-29 08:03:56 -0700817 draw_saveLayer_picture(width, height, tileSize, &factory, &result1);
halcanary96fcdcc2015-08-27 07:41:13 -0700818 draw_saveLayer_picture(width, height, tileSize, nullptr, &result2);
mtkleind910f542014-08-22 09:06:34 -0700819
820 for (int y = 0; y < height; y++) {
821 int diffs = memcmp(result1.getAddr32(0, y), result2.getAddr32(0, y), result1.rowBytes());
822 REPORTER_ASSERT(reporter, !diffs);
823 if (diffs) {
824 break;
825 }
826 }
827}
828
robertphillips6e7025a2016-04-04 04:31:25 -0700829static sk_sp<SkImageFilter> make_blur(sk_sp<SkImageFilter> input) {
830 return SkBlurImageFilter::Make(SK_Scalar1, SK_Scalar1, std::move(input));
senorblanco1150a6d2014-08-25 12:46:58 -0700831}
832
robertphillips6e7025a2016-04-04 04:31:25 -0700833static sk_sp<SkImageFilter> make_drop_shadow(sk_sp<SkImageFilter> input) {
robertphillipsc4169122016-04-06 08:40:59 -0700834 return SkDropShadowImageFilter::Make(
senorblanco1150a6d2014-08-25 12:46:58 -0700835 SkIntToScalar(100), SkIntToScalar(100),
836 SkIntToScalar(10), SkIntToScalar(10),
sugoi234f0362014-10-23 13:59:52 -0700837 SK_ColorBLUE, SkDropShadowImageFilter::kDrawShadowAndForeground_ShadowMode,
robertphillipsc4169122016-04-06 08:40:59 -0700838 std::move(input));
senorblanco1150a6d2014-08-25 12:46:58 -0700839}
840
841DEF_TEST(ImageFilterBlurThenShadowBounds, reporter) {
robertphillips6e7025a2016-04-04 04:31:25 -0700842 sk_sp<SkImageFilter> filter1(make_blur(nullptr));
843 sk_sp<SkImageFilter> filter2(make_drop_shadow(std::move(filter1)));
senorblanco1150a6d2014-08-25 12:46:58 -0700844
845 SkIRect bounds = SkIRect::MakeXYWH(0, 0, 100, 100);
Herb Derby59f8f152017-10-17 22:27:23 +0000846 SkIRect expectedBounds = SkIRect::MakeXYWH(-133, -133, 236, 236);
Robert Phillips12078432018-05-17 11:17:39 -0400847 bounds = filter2->filterBounds(bounds, SkMatrix::I(),
848 SkImageFilter::kReverse_MapDirection, &bounds);
senorblanco1150a6d2014-08-25 12:46:58 -0700849
850 REPORTER_ASSERT(reporter, bounds == expectedBounds);
851}
852
853DEF_TEST(ImageFilterShadowThenBlurBounds, reporter) {
robertphillips6e7025a2016-04-04 04:31:25 -0700854 sk_sp<SkImageFilter> filter1(make_drop_shadow(nullptr));
855 sk_sp<SkImageFilter> filter2(make_blur(std::move(filter1)));
senorblanco1150a6d2014-08-25 12:46:58 -0700856
857 SkIRect bounds = SkIRect::MakeXYWH(0, 0, 100, 100);
Herb Derby59f8f152017-10-17 22:27:23 +0000858 SkIRect expectedBounds = SkIRect::MakeXYWH(-133, -133, 236, 236);
Robert Phillips12078432018-05-17 11:17:39 -0400859 bounds = filter2->filterBounds(bounds, SkMatrix::I(),
860 SkImageFilter::kReverse_MapDirection, &bounds);
senorblanco1150a6d2014-08-25 12:46:58 -0700861
862 REPORTER_ASSERT(reporter, bounds == expectedBounds);
863}
864
865DEF_TEST(ImageFilterDilateThenBlurBounds, reporter) {
robertphillipsfc11b0a2016-04-05 09:09:36 -0700866 sk_sp<SkImageFilter> filter1(SkDilateImageFilter::Make(2, 2, nullptr));
robertphillips6e7025a2016-04-04 04:31:25 -0700867 sk_sp<SkImageFilter> filter2(make_drop_shadow(std::move(filter1)));
senorblanco1150a6d2014-08-25 12:46:58 -0700868
869 SkIRect bounds = SkIRect::MakeXYWH(0, 0, 100, 100);
870 SkIRect expectedBounds = SkIRect::MakeXYWH(-132, -132, 234, 234);
Robert Phillips12078432018-05-17 11:17:39 -0400871 bounds = filter2->filterBounds(bounds, SkMatrix::I(),
872 SkImageFilter::kReverse_MapDirection, &bounds);
senorblanco1150a6d2014-08-25 12:46:58 -0700873
874 REPORTER_ASSERT(reporter, bounds == expectedBounds);
875}
876
jbroman203a9932016-07-11 14:07:59 -0700877DEF_TEST(ImageFilterScaledBlurRadius, reporter) {
878 // Each blur should spread 3*sigma, so 3 for the blur and 30 for the shadow
879 // (before the CTM). Bounds should be computed correctly in the presence of
880 // a (possibly negative) scale.
881 sk_sp<SkImageFilter> blur(make_blur(nullptr));
882 sk_sp<SkImageFilter> dropShadow(make_drop_shadow(nullptr));
883 {
884 // Uniform scale by 2.
885 SkMatrix scaleMatrix;
886 scaleMatrix.setScale(2, 2);
887 SkIRect bounds = SkIRect::MakeLTRB(0, 0, 200, 200);
888
Herb Derby59f8f152017-10-17 22:27:23 +0000889 SkIRect expectedBlurBounds = SkIRect::MakeLTRB(-6, -6, 206, 206);
jbroman203a9932016-07-11 14:07:59 -0700890 SkIRect blurBounds = blur->filterBounds(
Robert Phillips12078432018-05-17 11:17:39 -0400891 bounds, scaleMatrix, SkImageFilter::kForward_MapDirection, nullptr);
jbroman203a9932016-07-11 14:07:59 -0700892 REPORTER_ASSERT(reporter, blurBounds == expectedBlurBounds);
893 SkIRect reverseBlurBounds = blur->filterBounds(
Robert Phillips12078432018-05-17 11:17:39 -0400894 bounds, scaleMatrix, SkImageFilter::kReverse_MapDirection, &bounds);
jbroman203a9932016-07-11 14:07:59 -0700895 REPORTER_ASSERT(reporter, reverseBlurBounds == expectedBlurBounds);
896
897 SkIRect expectedShadowBounds = SkIRect::MakeLTRB(0, 0, 460, 460);
898 SkIRect shadowBounds = dropShadow->filterBounds(
Robert Phillips12078432018-05-17 11:17:39 -0400899 bounds, scaleMatrix, SkImageFilter::kForward_MapDirection, nullptr);
jbroman203a9932016-07-11 14:07:59 -0700900 REPORTER_ASSERT(reporter, shadowBounds == expectedShadowBounds);
901 SkIRect expectedReverseShadowBounds =
902 SkIRect::MakeLTRB(-260, -260, 200, 200);
903 SkIRect reverseShadowBounds = dropShadow->filterBounds(
Robert Phillips12078432018-05-17 11:17:39 -0400904 bounds, scaleMatrix, SkImageFilter::kReverse_MapDirection, &bounds);
jbroman203a9932016-07-11 14:07:59 -0700905 REPORTER_ASSERT(reporter,
906 reverseShadowBounds == expectedReverseShadowBounds);
907 }
908 {
909 // Vertical flip.
910 SkMatrix scaleMatrix;
911 scaleMatrix.setScale(1, -1);
912 SkIRect bounds = SkIRect::MakeLTRB(0, -100, 100, 0);
913
Herb Derby59f8f152017-10-17 22:27:23 +0000914 SkIRect expectedBlurBounds = SkIRect::MakeLTRB(-3, -103, 103, 3);
jbroman203a9932016-07-11 14:07:59 -0700915 SkIRect blurBounds = blur->filterBounds(
Robert Phillips12078432018-05-17 11:17:39 -0400916 bounds, scaleMatrix, SkImageFilter::kForward_MapDirection, nullptr);
jbroman203a9932016-07-11 14:07:59 -0700917 REPORTER_ASSERT(reporter, blurBounds == expectedBlurBounds);
918 SkIRect reverseBlurBounds = blur->filterBounds(
Robert Phillips12078432018-05-17 11:17:39 -0400919 bounds, scaleMatrix, SkImageFilter::kReverse_MapDirection, &bounds);
jbroman203a9932016-07-11 14:07:59 -0700920 REPORTER_ASSERT(reporter, reverseBlurBounds == expectedBlurBounds);
921
922 SkIRect expectedShadowBounds = SkIRect::MakeLTRB(0, -230, 230, 0);
923 SkIRect shadowBounds = dropShadow->filterBounds(
Robert Phillips12078432018-05-17 11:17:39 -0400924 bounds, scaleMatrix, SkImageFilter::kForward_MapDirection, nullptr);
jbroman203a9932016-07-11 14:07:59 -0700925 REPORTER_ASSERT(reporter, shadowBounds == expectedShadowBounds);
926 SkIRect expectedReverseShadowBounds =
927 SkIRect::MakeLTRB(-130, -100, 100, 130);
928 SkIRect reverseShadowBounds = dropShadow->filterBounds(
Robert Phillips12078432018-05-17 11:17:39 -0400929 bounds, scaleMatrix, SkImageFilter::kReverse_MapDirection, &bounds);
jbroman203a9932016-07-11 14:07:59 -0700930 REPORTER_ASSERT(reporter,
931 reverseShadowBounds == expectedReverseShadowBounds);
932 }
933}
934
ajuma5788faa2015-02-13 09:05:47 -0800935DEF_TEST(ImageFilterComposedBlurFastBounds, reporter) {
robertphillips6e7025a2016-04-04 04:31:25 -0700936 sk_sp<SkImageFilter> filter1(make_blur(nullptr));
937 sk_sp<SkImageFilter> filter2(make_blur(nullptr));
robertphillips491fb172016-03-30 12:32:58 -0700938 sk_sp<SkImageFilter> composedFilter(SkComposeImageFilter::Make(std::move(filter1),
939 std::move(filter2)));
ajuma5788faa2015-02-13 09:05:47 -0800940
941 SkRect boundsSrc = SkRect::MakeWH(SkIntToScalar(100), SkIntToScalar(100));
942 SkRect expectedBounds = SkRect::MakeXYWH(
Herb Derby59f8f152017-10-17 22:27:23 +0000943 SkIntToScalar(-6), SkIntToScalar(-6), SkIntToScalar(112), SkIntToScalar(112));
senorblancoe5e79842016-03-21 14:51:59 -0700944 SkRect boundsDst = composedFilter->computeFastBounds(boundsSrc);
ajuma5788faa2015-02-13 09:05:47 -0800945
946 REPORTER_ASSERT(reporter, boundsDst == expectedBounds);
947}
948
jbroman0e3129d2016-03-17 12:24:23 -0700949DEF_TEST(ImageFilterUnionBounds, reporter) {
robertphillips51a315e2016-03-31 09:05:49 -0700950 sk_sp<SkImageFilter> offset(SkOffsetImageFilter::Make(50, 0, nullptr));
jbroman0e3129d2016-03-17 12:24:23 -0700951 // Regardless of which order they appear in, the image filter bounds should
952 // be combined correctly.
953 {
reed374772b2016-10-05 17:33:02 -0700954 sk_sp<SkImageFilter> composite(SkXfermodeImageFilter::Make(SkBlendMode::kSrcOver, offset));
jbroman0e3129d2016-03-17 12:24:23 -0700955 SkRect bounds = SkRect::MakeWH(100, 100);
956 // Intentionally aliasing here, as that's what the real callers do.
senorblancoe5e79842016-03-21 14:51:59 -0700957 bounds = composite->computeFastBounds(bounds);
jbroman0e3129d2016-03-17 12:24:23 -0700958 REPORTER_ASSERT(reporter, bounds == SkRect::MakeWH(150, 100));
959 }
960 {
reed374772b2016-10-05 17:33:02 -0700961 sk_sp<SkImageFilter> composite(SkXfermodeImageFilter::Make(SkBlendMode::kSrcOver, nullptr,
robertphillips8c0326d2016-04-05 12:48:34 -0700962 offset, nullptr));
jbroman0e3129d2016-03-17 12:24:23 -0700963 SkRect bounds = SkRect::MakeWH(100, 100);
964 // Intentionally aliasing here, as that's what the real callers do.
senorblancoe5e79842016-03-21 14:51:59 -0700965 bounds = composite->computeFastBounds(bounds);
jbroman0e3129d2016-03-17 12:24:23 -0700966 REPORTER_ASSERT(reporter, bounds == SkRect::MakeWH(150, 100));
967 }
968}
969
robertphillips3e302272016-04-20 11:48:36 -0700970static void test_imagefilter_merge_result_size(skiatest::Reporter* reporter, GrContext* context) {
senorblanco4a243982015-11-25 07:06:55 -0800971 SkBitmap greenBM;
972 greenBM.allocN32Pixels(20, 20);
973 greenBM.eraseColor(SK_ColorGREEN);
reed9ce9d672016-03-17 10:51:11 -0700974 sk_sp<SkImage> greenImage(SkImage::MakeFromBitmap(greenBM));
robertphillips549c8992016-04-01 09:28:51 -0700975 sk_sp<SkImageFilter> source(SkImageSource::Make(std::move(greenImage)));
Mike Reed0bdaf052017-06-18 23:35:57 -0400976 sk_sp<SkImageFilter> merge(SkMergeImageFilter::Make(source, source));
senorblanco4a243982015-11-25 07:06:55 -0800977
robertphillips3e302272016-04-20 11:48:36 -0700978 sk_sp<SkSpecialImage> srcImg(create_empty_special_image(context, 1));
robertphillips4418dba2016-03-07 12:45:14 -0800979
Brian Osmana50205f2018-07-06 13:57:01 -0400980 SkImageFilter::OutputProperties noColorSpace(kN32_SkColorType, nullptr);
brianosman2a75e5d2016-09-22 07:15:37 -0700981 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeXYWH(0, 0, 100, 100), nullptr,
982 noColorSpace);
senorblanco4a243982015-11-25 07:06:55 -0800983 SkIPoint offset;
robertphillips4418dba2016-03-07 12:45:14 -0800984
robertphillips2302de92016-03-24 07:26:32 -0700985 sk_sp<SkSpecialImage> resultImg(merge->filterImage(srcImg.get(), ctx, &offset));
robertphillips4418dba2016-03-07 12:45:14 -0800986 REPORTER_ASSERT(reporter, resultImg);
987
988 REPORTER_ASSERT(reporter, resultImg->width() == 20 && resultImg->height() == 20);
senorblanco4a243982015-11-25 07:06:55 -0800989}
990
robertphillips4418dba2016-03-07 12:45:14 -0800991DEF_TEST(ImageFilterMergeResultSize, reporter) {
robertphillips3e302272016-04-20 11:48:36 -0700992 test_imagefilter_merge_result_size(reporter, nullptr);
robertphillips4418dba2016-03-07 12:45:14 -0800993}
994
egdanielab527a52016-06-28 08:07:26 -0700995DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterMergeResultSize_Gpu, reporter, ctxInfo) {
bsalomon8b7451a2016-05-11 06:33:06 -0700996 test_imagefilter_merge_result_size(reporter, ctxInfo.grContext());
robertphillips4418dba2016-03-07 12:45:14 -0800997}
robertphillips4418dba2016-03-07 12:45:14 -0800998
robertphillipsa8d7f0b2014-08-29 08:03:56 -0700999static void draw_blurred_rect(SkCanvas* canvas) {
senorblanco837f5322014-07-14 10:19:54 -07001000 SkPaint filterPaint;
1001 filterPaint.setColor(SK_ColorWHITE);
robertphillips6e7025a2016-04-04 04:31:25 -07001002 filterPaint.setImageFilter(SkBlurImageFilter::Make(SkIntToScalar(8), 0, nullptr));
halcanary96fcdcc2015-08-27 07:41:13 -07001003 canvas->saveLayer(nullptr, &filterPaint);
senorblanco837f5322014-07-14 10:19:54 -07001004 SkPaint whitePaint;
1005 whitePaint.setColor(SK_ColorWHITE);
1006 canvas->drawRect(SkRect::Make(SkIRect::MakeWH(4, 4)), whitePaint);
1007 canvas->restore();
1008}
1009
robertphillipsa8d7f0b2014-08-29 08:03:56 -07001010static void draw_picture_clipped(SkCanvas* canvas, const SkRect& clipRect, const SkPicture* picture) {
senorblanco837f5322014-07-14 10:19:54 -07001011 canvas->save();
1012 canvas->clipRect(clipRect);
1013 canvas->drawPicture(picture);
1014 canvas->restore();
1015}
1016
1017DEF_TEST(ImageFilterDrawTiledBlurRTree, reporter) {
1018 // Check that the blur filter when recorded with RTree acceleration,
1019 // and drawn tiled (with subsequent clip rects) exactly
1020 // matches the same filter drawn with without RTree acceleration.
1021 // This tests that the "bleed" from the blur into the otherwise-blank
1022 // tiles is correctly rendered.
1023 // Tests pass by not asserting.
1024
1025 int width = 16, height = 8;
1026 SkBitmap result1, result2;
1027 result1.allocN32Pixels(width, height);
1028 result2.allocN32Pixels(width, height);
1029 SkCanvas canvas1(result1);
1030 SkCanvas canvas2(result2);
1031 int tileSize = 8;
1032
1033 canvas1.clear(0);
1034 canvas2.clear(0);
1035
1036 SkRTreeFactory factory;
1037
1038 SkPictureRecorder recorder1, recorder2;
1039 // The only difference between these two pictures is that one has RTree aceleration.
mtklein3f3b3d02014-12-01 11:47:08 -08001040 SkCanvas* recordingCanvas1 = recorder1.beginRecording(SkIntToScalar(width),
1041 SkIntToScalar(height),
halcanary96fcdcc2015-08-27 07:41:13 -07001042 nullptr, 0);
mtklein3f3b3d02014-12-01 11:47:08 -08001043 SkCanvas* recordingCanvas2 = recorder2.beginRecording(SkIntToScalar(width),
1044 SkIntToScalar(height),
robertphillipsa8d7f0b2014-08-29 08:03:56 -07001045 &factory, 0);
1046 draw_blurred_rect(recordingCanvas1);
1047 draw_blurred_rect(recordingCanvas2);
reedca2622b2016-03-18 07:25:55 -07001048 sk_sp<SkPicture> picture1(recorder1.finishRecordingAsPicture());
1049 sk_sp<SkPicture> picture2(recorder2.finishRecordingAsPicture());
senorblanco837f5322014-07-14 10:19:54 -07001050 for (int y = 0; y < height; y += tileSize) {
1051 for (int x = 0; x < width; x += tileSize) {
1052 SkRect tileRect = SkRect::Make(SkIRect::MakeXYWH(x, y, tileSize, tileSize));
reedca2622b2016-03-18 07:25:55 -07001053 draw_picture_clipped(&canvas1, tileRect, picture1.get());
1054 draw_picture_clipped(&canvas2, tileRect, picture2.get());
senorblanco837f5322014-07-14 10:19:54 -07001055 }
1056 }
1057 for (int y = 0; y < height; y++) {
1058 int diffs = memcmp(result1.getAddr32(0, y), result2.getAddr32(0, y), result1.rowBytes());
1059 REPORTER_ASSERT(reporter, !diffs);
1060 if (diffs) {
1061 break;
1062 }
1063 }
1064}
1065
senorblanco@chromium.org91957432014-05-01 14:03:41 +00001066DEF_TEST(ImageFilterMatrixConvolution, reporter) {
1067 // Check that a 1x3 filter does not cause a spurious assert.
1068 SkScalar kernel[3] = {
1069 SkIntToScalar( 1), SkIntToScalar( 1), SkIntToScalar( 1),
1070 };
1071 SkISize kernelSize = SkISize::Make(1, 3);
1072 SkScalar gain = SK_Scalar1, bias = 0;
1073 SkIPoint kernelOffset = SkIPoint::Make(0, 0);
1074
robertphillipsef6a47b2016-04-08 08:01:20 -07001075 sk_sp<SkImageFilter> filter(SkMatrixConvolutionImageFilter::Make(
1076 kernelSize, kernel,
1077 gain, bias, kernelOffset,
1078 SkMatrixConvolutionImageFilter::kRepeat_TileMode,
1079 false, nullptr));
senorblanco@chromium.org91957432014-05-01 14:03:41 +00001080
1081 SkBitmap result;
1082 int width = 16, height = 16;
1083 result.allocN32Pixels(width, height);
1084 SkCanvas canvas(result);
1085 canvas.clear(0);
1086
1087 SkPaint paint;
robertphillipsef6a47b2016-04-08 08:01:20 -07001088 paint.setImageFilter(std::move(filter));
senorblanco@chromium.org91957432014-05-01 14:03:41 +00001089 SkRect rect = SkRect::Make(SkIRect::MakeWH(width, height));
1090 canvas.drawRect(rect, paint);
1091}
1092
senorblanco@chromium.org8c7372b2014-05-02 19:13:11 +00001093DEF_TEST(ImageFilterMatrixConvolutionBorder, reporter) {
1094 // Check that a filter with borders outside the target bounds
1095 // does not crash.
1096 SkScalar kernel[3] = {
1097 0, 0, 0,
1098 };
1099 SkISize kernelSize = SkISize::Make(3, 1);
1100 SkScalar gain = SK_Scalar1, bias = 0;
1101 SkIPoint kernelOffset = SkIPoint::Make(2, 0);
1102
robertphillipsef6a47b2016-04-08 08:01:20 -07001103 sk_sp<SkImageFilter> filter(SkMatrixConvolutionImageFilter::Make(
1104 kernelSize, kernel, gain, bias, kernelOffset,
1105 SkMatrixConvolutionImageFilter::kClamp_TileMode,
1106 true, nullptr));
senorblanco@chromium.org8c7372b2014-05-02 19:13:11 +00001107
1108 SkBitmap result;
1109
1110 int width = 10, height = 10;
1111 result.allocN32Pixels(width, height);
1112 SkCanvas canvas(result);
1113 canvas.clear(0);
1114
1115 SkPaint filterPaint;
robertphillipsef6a47b2016-04-08 08:01:20 -07001116 filterPaint.setImageFilter(std::move(filter));
senorblanco@chromium.org8c7372b2014-05-02 19:13:11 +00001117 SkRect bounds = SkRect::MakeWH(1, 10);
1118 SkRect rect = SkRect::Make(SkIRect::MakeWH(width, height));
1119 SkPaint rectPaint;
1120 canvas.saveLayer(&bounds, &filterPaint);
1121 canvas.drawRect(rect, rectPaint);
1122 canvas.restore();
1123}
1124
robertphillips3e302272016-04-20 11:48:36 -07001125static void test_big_kernel(skiatest::Reporter* reporter, GrContext* context) {
robertphillipsdada4dd2016-04-13 04:54:36 -07001126 // Check that a kernel that is too big for the GPU still works
1127 SkScalar identityKernel[49] = {
1128 0, 0, 0, 0, 0, 0, 0,
1129 0, 0, 0, 0, 0, 0, 0,
1130 0, 0, 0, 0, 0, 0, 0,
1131 0, 0, 0, 1, 0, 0, 0,
1132 0, 0, 0, 0, 0, 0, 0,
1133 0, 0, 0, 0, 0, 0, 0,
1134 0, 0, 0, 0, 0, 0, 0
1135 };
1136 SkISize kernelSize = SkISize::Make(7, 7);
1137 SkScalar gain = SK_Scalar1, bias = 0;
1138 SkIPoint kernelOffset = SkIPoint::Make(0, 0);
1139
1140 sk_sp<SkImageFilter> filter(SkMatrixConvolutionImageFilter::Make(
1141 kernelSize, identityKernel, gain, bias, kernelOffset,
1142 SkMatrixConvolutionImageFilter::kClamp_TileMode,
1143 true, nullptr));
1144
robertphillips3e302272016-04-20 11:48:36 -07001145 sk_sp<SkSpecialImage> srcImg(create_empty_special_image(context, 100));
robertphillipsdada4dd2016-04-13 04:54:36 -07001146 SkASSERT(srcImg);
1147
1148 SkIPoint offset;
Brian Osmana50205f2018-07-06 13:57:01 -04001149 SkImageFilter::OutputProperties noColorSpace(kN32_SkColorType, nullptr);
brianosman2a75e5d2016-09-22 07:15:37 -07001150 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeWH(100, 100), nullptr, noColorSpace);
robertphillipsdada4dd2016-04-13 04:54:36 -07001151 sk_sp<SkSpecialImage> resultImg(filter->filterImage(srcImg.get(), ctx, &offset));
1152 REPORTER_ASSERT(reporter, resultImg);
1153 REPORTER_ASSERT(reporter, SkToBool(context) == resultImg->isTextureBacked());
1154 REPORTER_ASSERT(reporter, resultImg->width() == 100 && resultImg->height() == 100);
1155 REPORTER_ASSERT(reporter, offset.fX == 0 && offset.fY == 0);
1156}
1157
1158DEF_TEST(ImageFilterMatrixConvolutionBigKernel, reporter) {
robertphillips3e302272016-04-20 11:48:36 -07001159 test_big_kernel(reporter, nullptr);
robertphillipsdada4dd2016-04-13 04:54:36 -07001160}
1161
egdanielab527a52016-06-28 08:07:26 -07001162DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterMatrixConvolutionBigKernel_Gpu,
1163 reporter, ctxInfo) {
bsalomon8b7451a2016-05-11 06:33:06 -07001164 test_big_kernel(reporter, ctxInfo.grContext());
robertphillipsdada4dd2016-04-13 04:54:36 -07001165}
robertphillipsdada4dd2016-04-13 04:54:36 -07001166
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +00001167DEF_TEST(ImageFilterCropRect, reporter) {
robertphillips3e302272016-04-20 11:48:36 -07001168 test_crop_rects(reporter, nullptr);
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +00001169}
1170
bsalomon68d91342016-04-12 09:59:58 -07001171DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterCropRect_Gpu, reporter, ctxInfo) {
bsalomon8b7451a2016-05-11 06:33:06 -07001172 test_crop_rects(reporter, ctxInfo.grContext());
robertphillips4418dba2016-03-07 12:45:14 -08001173}
robertphillips4418dba2016-03-07 12:45:14 -08001174
tfarina9ea53f92014-06-24 06:50:39 -07001175DEF_TEST(ImageFilterMatrix, reporter) {
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +00001176 SkBitmap temp;
mike@reedtribe.orgdeee4962014-02-13 14:41:43 +00001177 temp.allocN32Pixels(100, 100);
robertphillips9a53fd72015-06-22 09:46:59 -07001178 SkCanvas canvas(temp);
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +00001179 canvas.scale(SkIntToScalar(2), SkIntToScalar(2));
1180
1181 SkMatrix expectedMatrix = canvas.getTotalMatrix();
1182
commit-bot@chromium.org5fb2ce32014-04-17 23:35:06 +00001183 SkRTreeFactory factory;
1184 SkPictureRecorder recorder;
1185 SkCanvas* recordingCanvas = recorder.beginRecording(100, 100, &factory, 0);
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +00001186
1187 SkPaint paint;
robertphillips43c2ad42016-04-04 05:05:11 -07001188 paint.setImageFilter(MatrixTestImageFilter::Make(reporter, expectedMatrix));
halcanary96fcdcc2015-08-27 07:41:13 -07001189 recordingCanvas->saveLayer(nullptr, &paint);
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +00001190 SkPaint solidPaint;
1191 solidPaint.setColor(0xFFFFFFFF);
1192 recordingCanvas->save();
1193 recordingCanvas->scale(SkIntToScalar(10), SkIntToScalar(10));
1194 recordingCanvas->drawRect(SkRect::Make(SkIRect::MakeWH(100, 100)), solidPaint);
1195 recordingCanvas->restore(); // scale
1196 recordingCanvas->restore(); // saveLayer
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +00001197
reedca2622b2016-03-18 07:25:55 -07001198 canvas.drawPicture(recorder.finishRecordingAsPicture());
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +00001199}
1200
robertphillips3e302272016-04-20 11:48:36 -07001201static void test_clipped_picture_imagefilter(skiatest::Reporter* reporter, GrContext* context) {
reedca2622b2016-03-18 07:25:55 -07001202 sk_sp<SkPicture> picture;
senorblanco3d822c22014-07-30 14:49:31 -07001203
robertphillips4418dba2016-03-07 12:45:14 -08001204 {
1205 SkRTreeFactory factory;
1206 SkPictureRecorder recorder;
1207 SkCanvas* recordingCanvas = recorder.beginRecording(1, 1, &factory, 0);
1208
1209 // Create an SkPicture which simply draws a green 1x1 rectangle.
1210 SkPaint greenPaint;
1211 greenPaint.setColor(SK_ColorGREEN);
1212 recordingCanvas->drawRect(SkRect::Make(SkIRect::MakeWH(1, 1)), greenPaint);
reedca2622b2016-03-18 07:25:55 -07001213 picture = recorder.finishRecordingAsPicture();
robertphillips4418dba2016-03-07 12:45:14 -08001214 }
1215
robertphillips3e302272016-04-20 11:48:36 -07001216 sk_sp<SkSpecialImage> srcImg(create_empty_special_image(context, 2));
senorblanco3d822c22014-07-30 14:49:31 -07001217
robertphillips5ff17b12016-03-28 13:13:42 -07001218 sk_sp<SkImageFilter> imageFilter(SkPictureImageFilter::Make(picture));
senorblanco3d822c22014-07-30 14:49:31 -07001219
senorblanco3d822c22014-07-30 14:49:31 -07001220 SkIPoint offset;
Brian Osmana50205f2018-07-06 13:57:01 -04001221 SkImageFilter::OutputProperties noColorSpace(kN32_SkColorType, nullptr);
brianosman2a75e5d2016-09-22 07:15:37 -07001222 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeXYWH(1, 1, 1, 1), nullptr, noColorSpace);
robertphillips4418dba2016-03-07 12:45:14 -08001223
robertphillips2302de92016-03-24 07:26:32 -07001224 sk_sp<SkSpecialImage> resultImage(imageFilter->filterImage(srcImg.get(), ctx, &offset));
robertphillips4418dba2016-03-07 12:45:14 -08001225 REPORTER_ASSERT(reporter, !resultImage);
senorblanco3d822c22014-07-30 14:49:31 -07001226}
1227
robertphillips4418dba2016-03-07 12:45:14 -08001228DEF_TEST(ImageFilterClippedPictureImageFilter, reporter) {
robertphillips3e302272016-04-20 11:48:36 -07001229 test_clipped_picture_imagefilter(reporter, nullptr);
robertphillips4418dba2016-03-07 12:45:14 -08001230}
1231
bsalomon68d91342016-04-12 09:59:58 -07001232DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterClippedPictureImageFilter_Gpu, reporter, ctxInfo) {
bsalomon8b7451a2016-05-11 06:33:06 -07001233 test_clipped_picture_imagefilter(reporter, ctxInfo.grContext());
robertphillips4418dba2016-03-07 12:45:14 -08001234}
robertphillips4418dba2016-03-07 12:45:14 -08001235
tfarina9ea53f92014-06-24 06:50:39 -07001236DEF_TEST(ImageFilterEmptySaveLayer, reporter) {
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001237 // Even when there's an empty saveLayer()/restore(), ensure that an image
1238 // filter or color filter which affects transparent black still draws.
1239
1240 SkBitmap bitmap;
1241 bitmap.allocN32Pixels(10, 10);
robertphillips9a53fd72015-06-22 09:46:59 -07001242 SkCanvas canvas(bitmap);
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001243
1244 SkRTreeFactory factory;
1245 SkPictureRecorder recorder;
1246
robertphillips5605b562016-04-05 11:50:42 -07001247 sk_sp<SkColorFilter> green(SkColorFilter::MakeModeFilter(SK_ColorGREEN,
Mike Reed7d954ad2016-10-28 15:42:34 -04001248 SkBlendMode::kSrc));
robertphillips5605b562016-04-05 11:50:42 -07001249 sk_sp<SkImageFilter> imageFilter(SkColorFilterImageFilter::Make(green, nullptr));
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001250 SkPaint imageFilterPaint;
robertphillips5605b562016-04-05 11:50:42 -07001251 imageFilterPaint.setImageFilter(std::move(imageFilter));
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001252 SkPaint colorFilterPaint;
reedd053ce92016-03-22 10:17:23 -07001253 colorFilterPaint.setColorFilter(green);
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001254
1255 SkRect bounds = SkRect::MakeWH(10, 10);
1256
1257 SkCanvas* recordingCanvas = recorder.beginRecording(10, 10, &factory, 0);
1258 recordingCanvas->saveLayer(&bounds, &imageFilterPaint);
1259 recordingCanvas->restore();
reedca2622b2016-03-18 07:25:55 -07001260 sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture());
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001261
1262 canvas.clear(0);
robertphillips9b14f262014-06-04 05:40:44 -07001263 canvas.drawPicture(picture);
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001264 uint32_t pixel = *bitmap.getAddr32(0, 0);
1265 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1266
1267 recordingCanvas = recorder.beginRecording(10, 10, &factory, 0);
halcanary96fcdcc2015-08-27 07:41:13 -07001268 recordingCanvas->saveLayer(nullptr, &imageFilterPaint);
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001269 recordingCanvas->restore();
reedca2622b2016-03-18 07:25:55 -07001270 sk_sp<SkPicture> picture2(recorder.finishRecordingAsPicture());
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001271
1272 canvas.clear(0);
robertphillips9b14f262014-06-04 05:40:44 -07001273 canvas.drawPicture(picture2);
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001274 pixel = *bitmap.getAddr32(0, 0);
1275 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1276
1277 recordingCanvas = recorder.beginRecording(10, 10, &factory, 0);
1278 recordingCanvas->saveLayer(&bounds, &colorFilterPaint);
1279 recordingCanvas->restore();
reedca2622b2016-03-18 07:25:55 -07001280 sk_sp<SkPicture> picture3(recorder.finishRecordingAsPicture());
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001281
1282 canvas.clear(0);
robertphillips9b14f262014-06-04 05:40:44 -07001283 canvas.drawPicture(picture3);
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001284 pixel = *bitmap.getAddr32(0, 0);
1285 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1286}
1287
robertphillips9a53fd72015-06-22 09:46:59 -07001288static void test_huge_blur(SkCanvas* canvas, skiatest::Reporter* reporter) {
senorblanco@chromium.org09843fd2014-03-24 20:50:59 +00001289 SkBitmap bitmap;
1290 bitmap.allocN32Pixels(100, 100);
1291 bitmap.eraseARGB(0, 0, 0, 0);
1292
1293 // Check that a blur with an insane radius does not crash or assert.
senorblanco@chromium.org09843fd2014-03-24 20:50:59 +00001294 SkPaint paint;
robertphillips6e7025a2016-04-04 04:31:25 -07001295 paint.setImageFilter(SkBlurImageFilter::Make(SkIntToScalar(1<<30),
1296 SkIntToScalar(1<<30),
1297 nullptr));
reedda420b92015-12-16 08:38:15 -08001298 canvas->drawBitmap(bitmap, 0, 0, &paint);
senorblanco@chromium.org09843fd2014-03-24 20:50:59 +00001299}
1300
1301DEF_TEST(HugeBlurImageFilter, reporter) {
1302 SkBitmap temp;
1303 temp.allocN32Pixels(100, 100);
robertphillips9a53fd72015-06-22 09:46:59 -07001304 SkCanvas canvas(temp);
1305 test_huge_blur(&canvas, reporter);
senorblanco@chromium.org09843fd2014-03-24 20:50:59 +00001306}
1307
senorblanco21a465d2016-04-11 11:58:39 -07001308DEF_TEST(ImageFilterMatrixConvolutionSanityTest, reporter) {
senorblanco3a495202014-09-29 07:57:20 -07001309 SkScalar kernel[1] = { 0 };
1310 SkScalar gain = SK_Scalar1, bias = 0;
1311 SkIPoint kernelOffset = SkIPoint::Make(1, 1);
1312
halcanary96fcdcc2015-08-27 07:41:13 -07001313 // Check that an enormous (non-allocatable) kernel gives a nullptr filter.
robertphillipsef6a47b2016-04-08 08:01:20 -07001314 sk_sp<SkImageFilter> conv(SkMatrixConvolutionImageFilter::Make(
senorblanco3a495202014-09-29 07:57:20 -07001315 SkISize::Make(1<<30, 1<<30),
1316 kernel,
1317 gain,
1318 bias,
1319 kernelOffset,
1320 SkMatrixConvolutionImageFilter::kRepeat_TileMode,
robertphillipsef6a47b2016-04-08 08:01:20 -07001321 false,
1322 nullptr));
senorblanco3a495202014-09-29 07:57:20 -07001323
halcanary96fcdcc2015-08-27 07:41:13 -07001324 REPORTER_ASSERT(reporter, nullptr == conv.get());
senorblanco3a495202014-09-29 07:57:20 -07001325
halcanary96fcdcc2015-08-27 07:41:13 -07001326 // Check that a nullptr kernel gives a nullptr filter.
robertphillipsef6a47b2016-04-08 08:01:20 -07001327 conv = SkMatrixConvolutionImageFilter::Make(
senorblanco3a495202014-09-29 07:57:20 -07001328 SkISize::Make(1, 1),
halcanary96fcdcc2015-08-27 07:41:13 -07001329 nullptr,
senorblanco3a495202014-09-29 07:57:20 -07001330 gain,
1331 bias,
1332 kernelOffset,
1333 SkMatrixConvolutionImageFilter::kRepeat_TileMode,
robertphillipsef6a47b2016-04-08 08:01:20 -07001334 false,
1335 nullptr);
senorblanco3a495202014-09-29 07:57:20 -07001336
halcanary96fcdcc2015-08-27 07:41:13 -07001337 REPORTER_ASSERT(reporter, nullptr == conv.get());
senorblanco3a495202014-09-29 07:57:20 -07001338
halcanary96fcdcc2015-08-27 07:41:13 -07001339 // Check that a kernel width < 1 gives a nullptr filter.
robertphillipsef6a47b2016-04-08 08:01:20 -07001340 conv = SkMatrixConvolutionImageFilter::Make(
senorblanco3a495202014-09-29 07:57:20 -07001341 SkISize::Make(0, 1),
1342 kernel,
1343 gain,
1344 bias,
1345 kernelOffset,
1346 SkMatrixConvolutionImageFilter::kRepeat_TileMode,
robertphillipsef6a47b2016-04-08 08:01:20 -07001347 false,
1348 nullptr);
senorblanco3a495202014-09-29 07:57:20 -07001349
halcanary96fcdcc2015-08-27 07:41:13 -07001350 REPORTER_ASSERT(reporter, nullptr == conv.get());
senorblanco3a495202014-09-29 07:57:20 -07001351
halcanary96fcdcc2015-08-27 07:41:13 -07001352 // Check that kernel height < 1 gives a nullptr filter.
robertphillipsef6a47b2016-04-08 08:01:20 -07001353 conv = SkMatrixConvolutionImageFilter::Make(
senorblanco3a495202014-09-29 07:57:20 -07001354 SkISize::Make(1, -1),
1355 kernel,
1356 gain,
1357 bias,
1358 kernelOffset,
1359 SkMatrixConvolutionImageFilter::kRepeat_TileMode,
robertphillipsef6a47b2016-04-08 08:01:20 -07001360 false,
1361 nullptr);
senorblanco3a495202014-09-29 07:57:20 -07001362
halcanary96fcdcc2015-08-27 07:41:13 -07001363 REPORTER_ASSERT(reporter, nullptr == conv.get());
senorblanco3a495202014-09-29 07:57:20 -07001364}
1365
Mike Reedf1942192017-07-21 14:24:29 -04001366static void test_xfermode_cropped_input(SkSurface* surf, skiatest::Reporter* reporter) {
1367 auto canvas = surf->getCanvas();
robertphillips9a53fd72015-06-22 09:46:59 -07001368 canvas->clear(0);
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001369
1370 SkBitmap bitmap;
1371 bitmap.allocN32Pixels(1, 1);
1372 bitmap.eraseARGB(255, 255, 255, 255);
1373
robertphillips5605b562016-04-05 11:50:42 -07001374 sk_sp<SkColorFilter> green(SkColorFilter::MakeModeFilter(SK_ColorGREEN,
Mike Reed7d954ad2016-10-28 15:42:34 -04001375 SkBlendMode::kSrcIn));
robertphillips5605b562016-04-05 11:50:42 -07001376 sk_sp<SkImageFilter> greenFilter(SkColorFilterImageFilter::Make(green, nullptr));
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001377 SkImageFilter::CropRect cropRect(SkRect::MakeEmpty());
robertphillips5605b562016-04-05 11:50:42 -07001378 sk_sp<SkImageFilter> croppedOut(SkColorFilterImageFilter::Make(green, nullptr, &cropRect));
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001379
1380 // Check that an xfermode image filter whose input has been cropped out still draws the other
1381 // input. Also check that drawing with both inputs cropped out doesn't cause a GPU warning.
reed374772b2016-10-05 17:33:02 -07001382 SkBlendMode mode = SkBlendMode::kSrcOver;
robertphillips8c0326d2016-04-05 12:48:34 -07001383 sk_sp<SkImageFilter> xfermodeNoFg(SkXfermodeImageFilter::Make(mode, greenFilter,
1384 croppedOut, nullptr));
1385 sk_sp<SkImageFilter> xfermodeNoBg(SkXfermodeImageFilter::Make(mode, croppedOut,
1386 greenFilter, nullptr));
1387 sk_sp<SkImageFilter> xfermodeNoFgNoBg(SkXfermodeImageFilter::Make(mode, croppedOut,
1388 croppedOut, nullptr));
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001389
1390 SkPaint paint;
robertphillips8c0326d2016-04-05 12:48:34 -07001391 paint.setImageFilter(std::move(xfermodeNoFg));
reedda420b92015-12-16 08:38:15 -08001392 canvas->drawBitmap(bitmap, 0, 0, &paint); // drawSprite
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001393
1394 uint32_t pixel;
kkinnunena9d9a392015-03-06 07:16:00 -08001395 SkImageInfo info = SkImageInfo::Make(1, 1, kBGRA_8888_SkColorType, kUnpremul_SkAlphaType);
Mike Reedf1942192017-07-21 14:24:29 -04001396 surf->readPixels(info, &pixel, 4, 0, 0);
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001397 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1398
robertphillips8c0326d2016-04-05 12:48:34 -07001399 paint.setImageFilter(std::move(xfermodeNoBg));
reedda420b92015-12-16 08:38:15 -08001400 canvas->drawBitmap(bitmap, 0, 0, &paint); // drawSprite
Mike Reedf1942192017-07-21 14:24:29 -04001401 surf->readPixels(info, &pixel, 4, 0, 0);
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001402 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1403
robertphillips8c0326d2016-04-05 12:48:34 -07001404 paint.setImageFilter(std::move(xfermodeNoFgNoBg));
reedda420b92015-12-16 08:38:15 -08001405 canvas->drawBitmap(bitmap, 0, 0, &paint); // drawSprite
Mike Reedf1942192017-07-21 14:24:29 -04001406 surf->readPixels(info, &pixel, 4, 0, 0);
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001407 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1408}
1409
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001410DEF_TEST(ImageFilterNestedSaveLayer, reporter) {
1411 SkBitmap temp;
1412 temp.allocN32Pixels(50, 50);
robertphillips9a53fd72015-06-22 09:46:59 -07001413 SkCanvas canvas(temp);
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001414 canvas.clear(0x0);
1415
1416 SkBitmap bitmap;
1417 bitmap.allocN32Pixels(10, 10);
1418 bitmap.eraseColor(SK_ColorGREEN);
1419
1420 SkMatrix matrix;
1421 matrix.setScale(SkIntToScalar(2), SkIntToScalar(2));
1422 matrix.postTranslate(SkIntToScalar(-20), SkIntToScalar(-20));
robertphillipsae8c9332016-04-05 15:09:00 -07001423 sk_sp<SkImageFilter> matrixFilter(
1424 SkImageFilter::MakeMatrixFilter(matrix, kLow_SkFilterQuality, nullptr));
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001425
1426 // Test that saveLayer() with a filter nested inside another saveLayer() applies the
1427 // correct offset to the filter matrix.
1428 SkRect bounds1 = SkRect::MakeXYWH(10, 10, 30, 30);
halcanary96fcdcc2015-08-27 07:41:13 -07001429 canvas.saveLayer(&bounds1, nullptr);
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001430 SkPaint filterPaint;
robertphillipsae8c9332016-04-05 15:09:00 -07001431 filterPaint.setImageFilter(std::move(matrixFilter));
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001432 SkRect bounds2 = SkRect::MakeXYWH(20, 20, 10, 10);
1433 canvas.saveLayer(&bounds2, &filterPaint);
1434 SkPaint greenPaint;
1435 greenPaint.setColor(SK_ColorGREEN);
1436 canvas.drawRect(bounds2, greenPaint);
1437 canvas.restore();
1438 canvas.restore();
1439 SkPaint strokePaint;
1440 strokePaint.setStyle(SkPaint::kStroke_Style);
1441 strokePaint.setColor(SK_ColorRED);
1442
kkinnunena9d9a392015-03-06 07:16:00 -08001443 SkImageInfo info = SkImageInfo::Make(1, 1, kBGRA_8888_SkColorType, kUnpremul_SkAlphaType);
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001444 uint32_t pixel;
Mike Reedf1942192017-07-21 14:24:29 -04001445 temp.readPixels(info, &pixel, 4, 25, 25);
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001446 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1447
1448 // Test that drawSprite() with a filter nested inside a saveLayer() applies the
1449 // correct offset to the filter matrix.
1450 canvas.clear(0x0);
Mike Reedf1942192017-07-21 14:24:29 -04001451 temp.readPixels(info, &pixel, 4, 25, 25);
halcanary96fcdcc2015-08-27 07:41:13 -07001452 canvas.saveLayer(&bounds1, nullptr);
reedda420b92015-12-16 08:38:15 -08001453 canvas.drawBitmap(bitmap, 20, 20, &filterPaint); // drawSprite
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001454 canvas.restore();
1455
Mike Reedf1942192017-07-21 14:24:29 -04001456 temp.readPixels(info, &pixel, 4, 25, 25);
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001457 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1458}
1459
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001460DEF_TEST(XfermodeImageFilterCroppedInput, reporter) {
Mike Reedf1942192017-07-21 14:24:29 -04001461 test_xfermode_cropped_input(SkSurface::MakeRasterN32Premul(100, 100).get(), reporter);
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001462}
senorblanco@chromium.org09843fd2014-03-24 20:50:59 +00001463
robertphillips3e302272016-04-20 11:48:36 -07001464static void test_composed_imagefilter_offset(skiatest::Reporter* reporter, GrContext* context) {
1465 sk_sp<SkSpecialImage> srcImg(create_empty_special_image(context, 100));
ajuma5788faa2015-02-13 09:05:47 -08001466
1467 SkImageFilter::CropRect cropRect(SkRect::MakeXYWH(1, 0, 20, 20));
robertphillips51a315e2016-03-31 09:05:49 -07001468 sk_sp<SkImageFilter> offsetFilter(SkOffsetImageFilter::Make(0, 0, nullptr, &cropRect));
robertphillips6e7025a2016-04-04 04:31:25 -07001469 sk_sp<SkImageFilter> blurFilter(SkBlurImageFilter::Make(SK_Scalar1, SK_Scalar1,
1470 nullptr, &cropRect));
robertphillips491fb172016-03-30 12:32:58 -07001471 sk_sp<SkImageFilter> composedFilter(SkComposeImageFilter::Make(std::move(blurFilter),
1472 std::move(offsetFilter)));
ajuma5788faa2015-02-13 09:05:47 -08001473 SkIPoint offset;
Brian Osmana50205f2018-07-06 13:57:01 -04001474 SkImageFilter::OutputProperties noColorSpace(kN32_SkColorType, nullptr);
brianosman2a75e5d2016-09-22 07:15:37 -07001475 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeWH(100, 100), nullptr, noColorSpace);
robertphillips4418dba2016-03-07 12:45:14 -08001476
robertphillips2302de92016-03-24 07:26:32 -07001477 sk_sp<SkSpecialImage> resultImg(composedFilter->filterImage(srcImg.get(), ctx, &offset));
robertphillips4418dba2016-03-07 12:45:14 -08001478 REPORTER_ASSERT(reporter, resultImg);
ajuma5788faa2015-02-13 09:05:47 -08001479 REPORTER_ASSERT(reporter, offset.fX == 1 && offset.fY == 0);
1480}
1481
robertphillips4418dba2016-03-07 12:45:14 -08001482DEF_TEST(ComposedImageFilterOffset, reporter) {
robertphillips3e302272016-04-20 11:48:36 -07001483 test_composed_imagefilter_offset(reporter, nullptr);
robertphillips4418dba2016-03-07 12:45:14 -08001484}
1485
bsalomon68d91342016-04-12 09:59:58 -07001486DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ComposedImageFilterOffset_Gpu, reporter, ctxInfo) {
bsalomon8b7451a2016-05-11 06:33:06 -07001487 test_composed_imagefilter_offset(reporter, ctxInfo.grContext());
robertphillips4418dba2016-03-07 12:45:14 -08001488}
robertphillips4418dba2016-03-07 12:45:14 -08001489
robertphillips3e302272016-04-20 11:48:36 -07001490static void test_composed_imagefilter_bounds(skiatest::Reporter* reporter, GrContext* context) {
jbroman17a65202016-03-21 08:38:58 -07001491 // The bounds passed to the inner filter must be filtered by the outer
1492 // filter, so that the inner filter produces the pixels that the outer
1493 // filter requires as input. This matters if the outer filter moves pixels.
1494 // Here, accounting for the outer offset is necessary so that the green
1495 // pixels of the picture are not clipped.
1496
1497 SkPictureRecorder recorder;
1498 SkCanvas* recordingCanvas = recorder.beginRecording(SkRect::MakeWH(200, 100));
1499 recordingCanvas->clipRect(SkRect::MakeXYWH(100, 0, 100, 100));
1500 recordingCanvas->clear(SK_ColorGREEN);
robertphillips491fb172016-03-30 12:32:58 -07001501 sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture());
robertphillips5ff17b12016-03-28 13:13:42 -07001502 sk_sp<SkImageFilter> pictureFilter(SkPictureImageFilter::Make(picture));
jbroman17a65202016-03-21 08:38:58 -07001503 SkImageFilter::CropRect cropRect(SkRect::MakeWH(100, 100));
robertphillips51a315e2016-03-31 09:05:49 -07001504 sk_sp<SkImageFilter> offsetFilter(SkOffsetImageFilter::Make(-100, 0, nullptr, &cropRect));
robertphillips491fb172016-03-30 12:32:58 -07001505 sk_sp<SkImageFilter> composedFilter(SkComposeImageFilter::Make(std::move(offsetFilter),
1506 std::move(pictureFilter)));
jbroman17a65202016-03-21 08:38:58 -07001507
robertphillips3e302272016-04-20 11:48:36 -07001508 sk_sp<SkSpecialImage> sourceImage(create_empty_special_image(context, 100));
Brian Osmana50205f2018-07-06 13:57:01 -04001509 SkImageFilter::OutputProperties noColorSpace(kN32_SkColorType, nullptr);
brianosman2a75e5d2016-09-22 07:15:37 -07001510 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeWH(100, 100), nullptr, noColorSpace);
jbroman17a65202016-03-21 08:38:58 -07001511 SkIPoint offset;
1512 sk_sp<SkSpecialImage> result(composedFilter->filterImage(sourceImage.get(), ctx, &offset));
1513 REPORTER_ASSERT(reporter, offset.isZero());
1514 REPORTER_ASSERT(reporter, result);
1515 REPORTER_ASSERT(reporter, result->subset().size() == SkISize::Make(100, 100));
1516
1517 SkBitmap resultBM;
robertphillips64612512016-04-08 12:10:42 -07001518 REPORTER_ASSERT(reporter, result->getROPixels(&resultBM));
jbroman17a65202016-03-21 08:38:58 -07001519 REPORTER_ASSERT(reporter, resultBM.getColor(50, 50) == SK_ColorGREEN);
1520}
1521
1522DEF_TEST(ComposedImageFilterBounds, reporter) {
robertphillips3e302272016-04-20 11:48:36 -07001523 test_composed_imagefilter_bounds(reporter, nullptr);
jbroman17a65202016-03-21 08:38:58 -07001524}
1525
egdanielab527a52016-06-28 08:07:26 -07001526DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ComposedImageFilterBounds_Gpu, reporter, ctxInfo) {
bsalomon8b7451a2016-05-11 06:33:06 -07001527 test_composed_imagefilter_bounds(reporter, ctxInfo.grContext());
jbroman17a65202016-03-21 08:38:58 -07001528}
jbroman17a65202016-03-21 08:38:58 -07001529
robertphillips3e302272016-04-20 11:48:36 -07001530static void test_partial_crop_rect(skiatest::Reporter* reporter, GrContext* context) {
1531 sk_sp<SkSpecialImage> srcImg(create_empty_special_image(context, 100));
senorblanco24d2a7b2015-07-13 10:27:05 -07001532
1533 SkImageFilter::CropRect cropRect(SkRect::MakeXYWH(100, 0, 20, 30),
senorblancoed7cf272015-07-16 15:19:11 -07001534 SkImageFilter::CropRect::kHasWidth_CropEdge | SkImageFilter::CropRect::kHasHeight_CropEdge);
robertphillips5605b562016-04-05 11:50:42 -07001535 sk_sp<SkImageFilter> filter(make_grayscale(nullptr, &cropRect));
senorblanco24d2a7b2015-07-13 10:27:05 -07001536 SkIPoint offset;
Brian Osmana50205f2018-07-06 13:57:01 -04001537 SkImageFilter::OutputProperties noColorSpace(kN32_SkColorType, nullptr);
brianosman2a75e5d2016-09-22 07:15:37 -07001538 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeWH(100, 100), nullptr, noColorSpace);
robertphillips4418dba2016-03-07 12:45:14 -08001539
robertphillips2302de92016-03-24 07:26:32 -07001540 sk_sp<SkSpecialImage> resultImg(filter->filterImage(srcImg.get(), ctx, &offset));
robertphillips4418dba2016-03-07 12:45:14 -08001541 REPORTER_ASSERT(reporter, resultImg);
1542
senorblanco24d2a7b2015-07-13 10:27:05 -07001543 REPORTER_ASSERT(reporter, offset.fX == 0);
1544 REPORTER_ASSERT(reporter, offset.fY == 0);
robertphillips4418dba2016-03-07 12:45:14 -08001545 REPORTER_ASSERT(reporter, resultImg->width() == 20);
1546 REPORTER_ASSERT(reporter, resultImg->height() == 30);
senorblanco24d2a7b2015-07-13 10:27:05 -07001547}
1548
senorblanco21a465d2016-04-11 11:58:39 -07001549DEF_TEST(ImageFilterPartialCropRect, reporter) {
robertphillips3e302272016-04-20 11:48:36 -07001550 test_partial_crop_rect(reporter, nullptr);
robertphillips4418dba2016-03-07 12:45:14 -08001551}
1552
bsalomon68d91342016-04-12 09:59:58 -07001553DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterPartialCropRect_Gpu, reporter, ctxInfo) {
bsalomon8b7451a2016-05-11 06:33:06 -07001554 test_partial_crop_rect(reporter, ctxInfo.grContext());
robertphillips4418dba2016-03-07 12:45:14 -08001555}
robertphillips4418dba2016-03-07 12:45:14 -08001556
senorblanco0abdf762015-08-20 11:10:41 -07001557DEF_TEST(ImageFilterCanComputeFastBounds, reporter) {
1558
robertphillips12fa47d2016-04-08 16:28:09 -07001559 {
1560 SkPoint3 location = SkPoint3::Make(0, 0, SK_Scalar1);
1561 sk_sp<SkImageFilter> lighting(SkLightingImageFilter::MakePointLitDiffuse(location,
1562 SK_ColorGREEN,
1563 0, 0, nullptr));
1564 REPORTER_ASSERT(reporter, !lighting->canComputeFastBounds());
1565 }
senorblanco0abdf762015-08-20 11:10:41 -07001566
senorblanco0abdf762015-08-20 11:10:41 -07001567 {
robertphillips6e7025a2016-04-04 04:31:25 -07001568 sk_sp<SkImageFilter> gray(make_grayscale(nullptr, nullptr));
1569 REPORTER_ASSERT(reporter, gray->canComputeFastBounds());
1570 {
1571 SkColorFilter* grayCF;
1572 REPORTER_ASSERT(reporter, gray->asAColorFilter(&grayCF));
1573 REPORTER_ASSERT(reporter, !grayCF->affectsTransparentBlack());
1574 grayCF->unref();
1575 }
1576 REPORTER_ASSERT(reporter, gray->canComputeFastBounds());
1577
1578 sk_sp<SkImageFilter> grayBlur(SkBlurImageFilter::Make(SK_Scalar1, SK_Scalar1,
1579 std::move(gray)));
1580 REPORTER_ASSERT(reporter, grayBlur->canComputeFastBounds());
senorblanco0abdf762015-08-20 11:10:41 -07001581 }
senorblanco0abdf762015-08-20 11:10:41 -07001582
robertphillips6e7025a2016-04-04 04:31:25 -07001583 {
1584 SkScalar greenMatrix[20] = { 0, 0, 0, 0, 0,
1585 0, 0, 0, 0, 1,
1586 0, 0, 0, 0, 0,
1587 0, 0, 0, 0, 1 };
1588 sk_sp<SkColorFilter> greenCF(SkColorFilter::MakeMatrixFilterRowMajor255(greenMatrix));
robertphillips5605b562016-04-05 11:50:42 -07001589 sk_sp<SkImageFilter> green(SkColorFilterImageFilter::Make(greenCF, nullptr));
senorblanco0abdf762015-08-20 11:10:41 -07001590
robertphillips6e7025a2016-04-04 04:31:25 -07001591 REPORTER_ASSERT(reporter, greenCF->affectsTransparentBlack());
1592 REPORTER_ASSERT(reporter, !green->canComputeFastBounds());
senorblanco0abdf762015-08-20 11:10:41 -07001593
robertphillips6e7025a2016-04-04 04:31:25 -07001594 sk_sp<SkImageFilter> greenBlur(SkBlurImageFilter::Make(SK_Scalar1, SK_Scalar1,
1595 std::move(green)));
1596 REPORTER_ASSERT(reporter, !greenBlur->canComputeFastBounds());
1597 }
senorblanco0abdf762015-08-20 11:10:41 -07001598
1599 uint8_t allOne[256], identity[256];
1600 for (int i = 0; i < 256; ++i) {
1601 identity[i] = i;
1602 allOne[i] = 255;
1603 }
1604
robertphillips5605b562016-04-05 11:50:42 -07001605 sk_sp<SkColorFilter> identityCF(SkTableColorFilter::MakeARGB(identity, identity,
1606 identity, allOne));
1607 sk_sp<SkImageFilter> identityFilter(SkColorFilterImageFilter::Make(identityCF, nullptr));
senorblanco0abdf762015-08-20 11:10:41 -07001608 REPORTER_ASSERT(reporter, !identityCF->affectsTransparentBlack());
1609 REPORTER_ASSERT(reporter, identityFilter->canComputeFastBounds());
1610
robertphillips5605b562016-04-05 11:50:42 -07001611 sk_sp<SkColorFilter> forceOpaqueCF(SkTableColorFilter::MakeARGB(allOne, identity,
1612 identity, identity));
1613 sk_sp<SkImageFilter> forceOpaque(SkColorFilterImageFilter::Make(forceOpaqueCF, nullptr));
senorblanco0abdf762015-08-20 11:10:41 -07001614 REPORTER_ASSERT(reporter, forceOpaqueCF->affectsTransparentBlack());
1615 REPORTER_ASSERT(reporter, !forceOpaque->canComputeFastBounds());
1616}
1617
fmalitacd56f812015-09-14 13:31:18 -07001618// Verify that SkImageSource survives serialization
1619DEF_TEST(ImageFilterImageSourceSerialization, reporter) {
reede8f30622016-03-23 18:59:25 -07001620 auto surface(SkSurface::MakeRasterN32Premul(10, 10));
fmalitacd56f812015-09-14 13:31:18 -07001621 surface->getCanvas()->clear(SK_ColorGREEN);
reed9ce9d672016-03-17 10:51:11 -07001622 sk_sp<SkImage> image(surface->makeImageSnapshot());
robertphillips549c8992016-04-01 09:28:51 -07001623 sk_sp<SkImageFilter> filter(SkImageSource::Make(std::move(image)));
fmalitacd56f812015-09-14 13:31:18 -07001624
Mike Reed0331d372018-01-23 11:57:30 -05001625 sk_sp<SkData> data(filter->serialize());
1626 sk_sp<SkImageFilter> unflattenedFilter = SkImageFilter::Deserialize(data->data(), data->size());
fmalitacd56f812015-09-14 13:31:18 -07001627 REPORTER_ASSERT(reporter, unflattenedFilter);
1628
1629 SkBitmap bm;
1630 bm.allocN32Pixels(10, 10);
fmalita23cb88c2015-09-15 06:56:23 -07001631 bm.eraseColor(SK_ColorBLUE);
fmalitacd56f812015-09-14 13:31:18 -07001632 SkPaint paint;
1633 paint.setColor(SK_ColorRED);
1634 paint.setImageFilter(unflattenedFilter);
1635
1636 SkCanvas canvas(bm);
1637 canvas.drawRect(SkRect::MakeWH(10, 10), paint);
1638 REPORTER_ASSERT(reporter, *bm.getAddr32(0, 0) == SkPreMultiplyColor(SK_ColorGREEN));
1639}
1640
Leon Scroggins III4cdbf602017-09-28 14:33:57 -04001641DEF_TEST(ImageFilterImageSourceUninitialized, r) {
1642 sk_sp<SkData> data(GetResourceAsData("crbug769134.fil"));
1643 if (!data) {
1644 return;
1645 }
Mike Reed0331d372018-01-23 11:57:30 -05001646 sk_sp<SkImageFilter> unflattenedFilter = SkImageFilter::Deserialize(data->data(), data->size());
Leon Scroggins III4cdbf602017-09-28 14:33:57 -04001647 // This will fail. More importantly, msan will verify that we did not
1648 // compare against uninitialized memory.
1649 REPORTER_ASSERT(r, !unflattenedFilter);
1650}
1651
bsalomon45eefcf2016-01-05 08:39:28 -08001652static void test_large_blur_input(skiatest::Reporter* reporter, SkCanvas* canvas) {
1653 SkBitmap largeBmp;
1654 int largeW = 5000;
1655 int largeH = 5000;
bsalomon45eefcf2016-01-05 08:39:28 -08001656 // If we're GPU-backed make the bitmap too large to be converted into a texture.
1657 if (GrContext* ctx = canvas->getGrContext()) {
Brian Salomonc7fe0f72018-05-11 10:14:21 -04001658 largeW = ctx->contextPriv().caps()->maxTextureSize() + 1;
bsalomon45eefcf2016-01-05 08:39:28 -08001659 }
bsalomon45eefcf2016-01-05 08:39:28 -08001660
1661 largeBmp.allocN32Pixels(largeW, largeH);
mtklein2afbe232016-02-07 12:23:10 -08001662 largeBmp.eraseColor(0);
bsalomon45eefcf2016-01-05 08:39:28 -08001663 if (!largeBmp.getPixels()) {
1664 ERRORF(reporter, "Failed to allocate large bmp.");
1665 return;
1666 }
1667
reed9ce9d672016-03-17 10:51:11 -07001668 sk_sp<SkImage> largeImage(SkImage::MakeFromBitmap(largeBmp));
bsalomon45eefcf2016-01-05 08:39:28 -08001669 if (!largeImage) {
1670 ERRORF(reporter, "Failed to create large image.");
1671 return;
1672 }
1673
robertphillips549c8992016-04-01 09:28:51 -07001674 sk_sp<SkImageFilter> largeSource(SkImageSource::Make(std::move(largeImage)));
bsalomon45eefcf2016-01-05 08:39:28 -08001675 if (!largeSource) {
1676 ERRORF(reporter, "Failed to create large SkImageSource.");
1677 return;
1678 }
1679
robertphillips6e7025a2016-04-04 04:31:25 -07001680 sk_sp<SkImageFilter> blur(SkBlurImageFilter::Make(10.f, 10.f, std::move(largeSource)));
bsalomon45eefcf2016-01-05 08:39:28 -08001681 if (!blur) {
1682 ERRORF(reporter, "Failed to create SkBlurImageFilter.");
1683 return;
1684 }
1685
1686 SkPaint paint;
robertphillips549c8992016-04-01 09:28:51 -07001687 paint.setImageFilter(std::move(blur));
bsalomon45eefcf2016-01-05 08:39:28 -08001688
1689 // This should not crash (http://crbug.com/570479).
1690 canvas->drawRect(SkRect::MakeIWH(largeW, largeH), paint);
1691}
1692
senorblanco21a465d2016-04-11 11:58:39 -07001693DEF_TEST(ImageFilterBlurLargeImage, reporter) {
reede8f30622016-03-23 18:59:25 -07001694 auto surface(SkSurface::MakeRaster(SkImageInfo::MakeN32Premul(100, 100)));
bsalomon45eefcf2016-01-05 08:39:28 -08001695 test_large_blur_input(reporter, surface->getCanvas());
1696}
1697
senorblanco5878dbd2016-05-19 14:50:29 -07001698static void test_make_with_filter(skiatest::Reporter* reporter, GrContext* context) {
Robert Phillipsa5fdc972017-02-18 16:58:09 -05001699 sk_sp<SkSurface> surface(create_surface(context, 192, 128));
senorblanco5878dbd2016-05-19 14:50:29 -07001700 surface->getCanvas()->clear(SK_ColorRED);
1701 SkPaint bluePaint;
1702 bluePaint.setColor(SK_ColorBLUE);
1703 SkIRect subset = SkIRect::MakeXYWH(25, 20, 50, 50);
1704 surface->getCanvas()->drawRect(SkRect::Make(subset), bluePaint);
1705 sk_sp<SkImage> sourceImage = surface->makeImageSnapshot();
1706
1707 sk_sp<SkImageFilter> filter = make_grayscale(nullptr, nullptr);
1708 SkIRect clipBounds = SkIRect::MakeXYWH(30, 35, 100, 100);
1709 SkIRect outSubset;
1710 SkIPoint offset;
1711 sk_sp<SkImage> result;
1712
1713 result = sourceImage->makeWithFilter(nullptr, subset, clipBounds, &outSubset, &offset);
1714 REPORTER_ASSERT(reporter, !result);
1715
1716 result = sourceImage->makeWithFilter(filter.get(), subset, clipBounds, nullptr, &offset);
1717 REPORTER_ASSERT(reporter, !result);
1718
1719 result = sourceImage->makeWithFilter(filter.get(), subset, clipBounds, &outSubset, nullptr);
1720 REPORTER_ASSERT(reporter, !result);
1721
1722 SkIRect bigSubset = SkIRect::MakeXYWH(-10000, -10000, 20000, 20000);
1723 result = sourceImage->makeWithFilter(filter.get(), bigSubset, clipBounds, &outSubset, &offset);
1724 REPORTER_ASSERT(reporter, !result);
1725
1726 SkIRect empty = SkIRect::MakeEmpty();
1727 result = sourceImage->makeWithFilter(filter.get(), empty, clipBounds, &outSubset, &offset);
1728 REPORTER_ASSERT(reporter, !result);
1729
1730 result = sourceImage->makeWithFilter(filter.get(), subset, empty, &outSubset, &offset);
1731 REPORTER_ASSERT(reporter, !result);
1732
1733 SkIRect leftField = SkIRect::MakeXYWH(-1000, 0, 100, 100);
1734 result = sourceImage->makeWithFilter(filter.get(), subset, leftField, &outSubset, &offset);
1735 REPORTER_ASSERT(reporter, !result);
1736
1737 result = sourceImage->makeWithFilter(filter.get(), subset, clipBounds, &outSubset, &offset);
1738
1739 REPORTER_ASSERT(reporter, result);
1740 REPORTER_ASSERT(reporter, result->bounds().contains(outSubset));
1741 SkIRect destRect = SkIRect::MakeXYWH(offset.x(), offset.y(),
1742 outSubset.width(), outSubset.height());
1743 REPORTER_ASSERT(reporter, clipBounds.contains(destRect));
Robert Phillipsa5fdc972017-02-18 16:58:09 -05001744
1745 // In GPU-mode, this case creates a special image with a backing size that differs from
1746 // the content size
1747 {
1748 clipBounds.setXYWH(0, 0, 170, 100);
1749 subset.setXYWH(0, 0, 160, 90);
1750
1751 filter = SkXfermodeImageFilter::Make(SkBlendMode::kSrc, nullptr);
1752 result = sourceImage->makeWithFilter(filter.get(), subset, clipBounds, &outSubset, &offset);
1753 REPORTER_ASSERT(reporter, result);
1754 }
senorblanco5878dbd2016-05-19 14:50:29 -07001755}
1756
1757DEF_TEST(ImageFilterMakeWithFilter, reporter) {
1758 test_make_with_filter(reporter, nullptr);
1759}
1760
senorblanco5878dbd2016-05-19 14:50:29 -07001761DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterMakeWithFilter_Gpu, reporter, ctxInfo) {
1762 test_make_with_filter(reporter, ctxInfo.grContext());
1763}
reed4a8126e2014-09-22 07:29:03 -07001764
bsalomon68d91342016-04-12 09:59:58 -07001765DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterHugeBlur_Gpu, reporter, ctxInfo) {
robertphillipsefbffed2015-06-22 12:06:08 -07001766
bsalomon8b7451a2016-05-11 06:33:06 -07001767 sk_sp<SkSurface> surf(SkSurface::MakeRenderTarget(ctxInfo.grContext(),
robertphillips3e302272016-04-20 11:48:36 -07001768 SkBudgeted::kNo,
1769 SkImageInfo::MakeN32Premul(100, 100)));
robertphillips9a53fd72015-06-22 09:46:59 -07001770
robertphillips3e302272016-04-20 11:48:36 -07001771
1772 SkCanvas* canvas = surf->getCanvas();
1773
1774 test_huge_blur(canvas, reporter);
senorblanco@chromium.org09843fd2014-03-24 20:50:59 +00001775}
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001776
egdanielab527a52016-06-28 08:07:26 -07001777DEF_GPUTEST_FOR_RENDERING_CONTEXTS(XfermodeImageFilterCroppedInput_Gpu, reporter, ctxInfo) {
Brian Salomon8996e182017-07-05 17:01:48 -04001778 sk_sp<SkSurface> surf(SkSurface::MakeRenderTarget(
1779 ctxInfo.grContext(),
1780 SkBudgeted::kNo,
1781 SkImageInfo::Make(1, 1, kRGBA_8888_SkColorType, kPremul_SkAlphaType)));
robertphillips3e302272016-04-20 11:48:36 -07001782
Mike Reedf1942192017-07-21 14:24:29 -04001783 test_xfermode_cropped_input(surf.get(), reporter);
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001784}
senorblanco32673b92014-09-09 09:15:04 -07001785
egdanielab527a52016-06-28 08:07:26 -07001786DEF_GPUTEST_FOR_ALL_CONTEXTS(ImageFilterBlurLargeImage_Gpu, reporter, ctxInfo) {
Brian Salomon8996e182017-07-05 17:01:48 -04001787 auto surface(SkSurface::MakeRenderTarget(
1788 ctxInfo.grContext(), SkBudgeted::kYes,
1789 SkImageInfo::Make(100, 100, kRGBA_8888_SkColorType, kPremul_SkAlphaType)));
bsalomon45eefcf2016-01-05 08:39:28 -08001790 test_large_blur_input(reporter, surface->getCanvas());
1791}
reedbb34a8a2016-04-23 15:19:07 -07001792
1793/*
1794 * Test that colorfilterimagefilter does not require its CTM to be decomposed when it has more
1795 * than just scale/translate, but that other filters do.
1796 */
reed96a04f32016-04-25 09:25:15 -07001797DEF_TEST(ImageFilterComplexCTM, reporter) {
reedbb34a8a2016-04-23 15:19:07 -07001798 // just need a colorfilter to exercise the corresponding imagefilter
Mike Reed7d954ad2016-10-28 15:42:34 -04001799 sk_sp<SkColorFilter> cf = SkColorFilter::MakeModeFilter(SK_ColorRED, SkBlendMode::kSrcATop);
reed96a04f32016-04-25 09:25:15 -07001800 sk_sp<SkImageFilter> cfif = SkColorFilterImageFilter::Make(cf, nullptr); // can handle
1801 sk_sp<SkImageFilter> blif = SkBlurImageFilter::Make(3, 3, nullptr); // cannot handle
reedbb34a8a2016-04-23 15:19:07 -07001802
1803 struct {
1804 sk_sp<SkImageFilter> fFilter;
1805 bool fExpectCanHandle;
1806 } recs[] = {
1807 { cfif, true },
1808 { SkColorFilterImageFilter::Make(cf, cfif), true },
Mike Reed0bdaf052017-06-18 23:35:57 -04001809 { SkMergeImageFilter::Make(cfif, cfif), true },
reed96a04f32016-04-25 09:25:15 -07001810 { SkComposeImageFilter::Make(cfif, cfif), true },
1811
reedbb34a8a2016-04-23 15:19:07 -07001812 { blif, false },
reed96a04f32016-04-25 09:25:15 -07001813 { SkBlurImageFilter::Make(3, 3, cfif), false },
reedbb34a8a2016-04-23 15:19:07 -07001814 { SkColorFilterImageFilter::Make(cf, blif), false },
Mike Reed0bdaf052017-06-18 23:35:57 -04001815 { SkMergeImageFilter::Make(cfif, blif), false },
reed96a04f32016-04-25 09:25:15 -07001816 { SkComposeImageFilter::Make(blif, cfif), false },
reedbb34a8a2016-04-23 15:19:07 -07001817 };
liyuqianbfebe222016-11-14 11:17:16 -08001818
reedbb34a8a2016-04-23 15:19:07 -07001819 for (const auto& rec : recs) {
reed96a04f32016-04-25 09:25:15 -07001820 const bool canHandle = rec.fFilter->canHandleComplexCTM();
reedbb34a8a2016-04-23 15:19:07 -07001821 REPORTER_ASSERT(reporter, canHandle == rec.fExpectCanHandle);
1822 }
1823}
Florin Malita08252ec2017-07-06 12:48:15 -04001824
1825// Test that transforming the filter DAG doesn't clone shared nodes multiple times.
1826DEF_TEST(ImageFilterColorSpaceDAG, reporter) {
1827
1828 // Helper for counting makeColorSpace() clones.
1829 class TestFilter final : public SkImageFilter {
1830 public:
1831 TestFilter() : INHERITED(nullptr, 0, nullptr) {}
1832
Florin Malita08252ec2017-07-06 12:48:15 -04001833 Factory getFactory() const override { return nullptr; }
1834
1835 size_t cloneCount() const { return fCloneCount; }
1836
1837 protected:
1838 sk_sp<SkSpecialImage> onFilterImage(SkSpecialImage* src, const Context&,
1839 SkIPoint* offset) const override {
1840 return nullptr;
1841 }
1842 sk_sp<SkImageFilter> onMakeColorSpace(SkColorSpaceXformer*) const override {
1843 fCloneCount++;
1844 return sk_ref_sp(const_cast<TestFilter*>(this));
1845 }
1846
1847 private:
1848 typedef SkImageFilter INHERITED;
1849
1850 mutable size_t fCloneCount = 0;
1851 };
1852
1853 auto filter = sk_make_sp<TestFilter>();
1854 REPORTER_ASSERT(reporter, filter->cloneCount() == 0u);
1855
1856 // Build a DAG referencing the filter twice.
1857 auto complexFilter = SkMergeImageFilter::Make(filter, SkOffsetImageFilter::Make(1, 1, filter));
1858 REPORTER_ASSERT(reporter, filter->cloneCount() == 0u);
1859
1860 auto xformer = SkColorSpaceXformer::Make(SkColorSpace::MakeSRGB());
1861 auto xformedFilter = xformer->apply(complexFilter.get());
1862
Florin Malita39e08552017-07-06 14:16:18 -04001863 REPORTER_ASSERT(reporter, filter->cloneCount() == 1u);
Florin Malita08252ec2017-07-06 12:48:15 -04001864}
Xianzhu Wang0fa353c2017-08-25 16:27:04 -07001865
Xianzhu Wangb4496662017-09-25 10:26:40 -07001866// Test SkXfermodeImageFilter::filterBounds with different blending modes.
Xianzhu Wang0fa353c2017-08-25 16:27:04 -07001867DEF_TEST(XfermodeImageFilterBounds, reporter) {
1868 SkIRect background_rect = SkIRect::MakeXYWH(0, 0, 100, 100);
1869 SkIRect foreground_rect = SkIRect::MakeXYWH(50, 50, 100, 100);
1870 sk_sp<SkImageFilter> background(new FixedBoundsImageFilter(background_rect));
1871 sk_sp<SkImageFilter> foreground(new FixedBoundsImageFilter(foreground_rect));
1872
1873 const int kModeCount = static_cast<int>(SkBlendMode::kLastMode) + 1;
1874 SkIRect expectedBounds[kModeCount];
1875 // Expect union of input rects by default.
1876 for (int i = 0; i < kModeCount; ++i) {
1877 expectedBounds[i] = background_rect;
1878 expectedBounds[i].join(foreground_rect);
1879 }
1880
1881 SkIRect intersection = background_rect;
1882 intersection.intersect(foreground_rect);
1883 expectedBounds[static_cast<int>(SkBlendMode::kClear)] = SkIRect::MakeEmpty();
1884 expectedBounds[static_cast<int>(SkBlendMode::kSrc)] = foreground_rect;
1885 expectedBounds[static_cast<int>(SkBlendMode::kDst)] = background_rect;
1886 expectedBounds[static_cast<int>(SkBlendMode::kSrcIn)] = intersection;
1887 expectedBounds[static_cast<int>(SkBlendMode::kDstIn)] = intersection;
1888 expectedBounds[static_cast<int>(SkBlendMode::kSrcATop)] = background_rect;
1889 expectedBounds[static_cast<int>(SkBlendMode::kDstATop)] = foreground_rect;
1890
1891 // The value of this variable doesn't matter because we use inputs with fixed bounds.
1892 SkIRect src = SkIRect::MakeXYWH(11, 22, 33, 44);
1893 for (int i = 0; i < kModeCount; ++i) {
1894 sk_sp<SkImageFilter> xfermode(SkXfermodeImageFilter::Make(static_cast<SkBlendMode>(i),
1895 background, foreground, nullptr));
Robert Phillips12078432018-05-17 11:17:39 -04001896 auto bounds = xfermode->filterBounds(src, SkMatrix::I(),
1897 SkImageFilter::kForward_MapDirection, nullptr);
Xianzhu Wang0fa353c2017-08-25 16:27:04 -07001898 REPORTER_ASSERT(reporter, bounds == expectedBounds[i]);
1899 }
1900
1901 // Test empty intersection.
1902 sk_sp<SkImageFilter> background2(new FixedBoundsImageFilter(SkIRect::MakeXYWH(0, 0, 20, 20)));
1903 sk_sp<SkImageFilter> foreground2(new FixedBoundsImageFilter(SkIRect::MakeXYWH(40, 40, 50, 50)));
1904 sk_sp<SkImageFilter> xfermode(SkXfermodeImageFilter::Make(
1905 SkBlendMode::kSrcIn, std::move(background2), std::move(foreground2), nullptr));
Robert Phillips12078432018-05-17 11:17:39 -04001906 auto bounds = xfermode->filterBounds(src, SkMatrix::I(),
1907 SkImageFilter::kForward_MapDirection, nullptr);
Xianzhu Wang0fa353c2017-08-25 16:27:04 -07001908 REPORTER_ASSERT(reporter, bounds.isEmpty());
1909}
1910
Fredrik Söderquistb87f7982017-10-26 13:54:16 +02001911DEF_TEST(OffsetImageFilterBounds, reporter) {
1912 SkIRect src = SkIRect::MakeXYWH(0, 0, 100, 100);
1913 sk_sp<SkImageFilter> offset(SkOffsetImageFilter::Make(-50.5f, -50.5f, nullptr));
1914
1915 SkIRect expectedForward = SkIRect::MakeXYWH(-50, -50, 100, 100);
1916 SkIRect boundsForward = offset->filterBounds(src, SkMatrix::I(),
Robert Phillips12078432018-05-17 11:17:39 -04001917 SkImageFilter::kForward_MapDirection, nullptr);
Fredrik Söderquistb87f7982017-10-26 13:54:16 +02001918 REPORTER_ASSERT(reporter, boundsForward == expectedForward);
1919
1920 SkIRect expectedReverse = SkIRect::MakeXYWH(50, 50, 100, 100);
1921 SkIRect boundsReverse = offset->filterBounds(src, SkMatrix::I(),
Robert Phillips12078432018-05-17 11:17:39 -04001922 SkImageFilter::kReverse_MapDirection, &src);
Fredrik Söderquistb87f7982017-10-26 13:54:16 +02001923 REPORTER_ASSERT(reporter, boundsReverse == expectedReverse);
1924}
1925
Xianzhu Wang0fa353c2017-08-25 16:27:04 -07001926static void test_arithmetic_bounds(skiatest::Reporter* reporter, float k1, float k2, float k3,
1927 float k4, sk_sp<SkImageFilter> background,
1928 sk_sp<SkImageFilter> foreground,
1929 const SkImageFilter::CropRect* crop, const SkIRect& expected) {
1930 sk_sp<SkImageFilter> arithmetic(
1931 SkArithmeticImageFilter::Make(k1, k2, k3, k4, false, background, foreground, crop));
1932 // The value of the input rect doesn't matter because we use inputs with fixed bounds.
1933 SkIRect bounds = arithmetic->filterBounds(SkIRect::MakeXYWH(11, 22, 33, 44), SkMatrix::I(),
Robert Phillips12078432018-05-17 11:17:39 -04001934 SkImageFilter::kForward_MapDirection, nullptr);
Xianzhu Wang0fa353c2017-08-25 16:27:04 -07001935 REPORTER_ASSERT(reporter, expected == bounds);
1936}
1937
1938static void test_arithmetic_combinations(skiatest::Reporter* reporter, float v) {
1939 SkIRect background_rect = SkIRect::MakeXYWH(0, 0, 100, 100);
1940 SkIRect foreground_rect = SkIRect::MakeXYWH(50, 50, 100, 100);
1941 sk_sp<SkImageFilter> background(new FixedBoundsImageFilter(background_rect));
1942 sk_sp<SkImageFilter> foreground(new FixedBoundsImageFilter(foreground_rect));
1943
1944 SkIRect union_rect = background_rect;
1945 union_rect.join(foreground_rect);
1946 SkIRect intersection = background_rect;
1947 intersection.intersect(foreground_rect);
1948
1949 test_arithmetic_bounds(reporter, 0, 0, 0, 0, background, foreground, nullptr,
1950 SkIRect::MakeEmpty());
1951 test_arithmetic_bounds(reporter, 0, 0, 0, v, background, foreground, nullptr, union_rect);
1952 test_arithmetic_bounds(reporter, 0, 0, v, 0, background, foreground, nullptr, background_rect);
1953 test_arithmetic_bounds(reporter, 0, 0, v, v, background, foreground, nullptr, union_rect);
1954 test_arithmetic_bounds(reporter, 0, v, 0, 0, background, foreground, nullptr, foreground_rect);
1955 test_arithmetic_bounds(reporter, 0, v, 0, v, background, foreground, nullptr, union_rect);
1956 test_arithmetic_bounds(reporter, 0, v, v, 0, background, foreground, nullptr, union_rect);
1957 test_arithmetic_bounds(reporter, 0, v, v, v, background, foreground, nullptr, union_rect);
1958 test_arithmetic_bounds(reporter, v, 0, 0, 0, background, foreground, nullptr, intersection);
1959 test_arithmetic_bounds(reporter, v, 0, 0, v, background, foreground, nullptr, union_rect);
1960 test_arithmetic_bounds(reporter, v, 0, v, 0, background, foreground, nullptr, background_rect);
1961 test_arithmetic_bounds(reporter, v, 0, v, v, background, foreground, nullptr, union_rect);
1962 test_arithmetic_bounds(reporter, v, v, 0, 0, background, foreground, nullptr, foreground_rect);
1963 test_arithmetic_bounds(reporter, v, v, 0, v, background, foreground, nullptr, union_rect);
1964 test_arithmetic_bounds(reporter, v, v, v, 0, background, foreground, nullptr, union_rect);
1965 test_arithmetic_bounds(reporter, v, v, v, v, background, foreground, nullptr, union_rect);
1966
1967 // Test with crop. When k4 is non-zero, the result is expected to be crop_rect
1968 // regardless of inputs because the filter affects the whole crop area.
1969 SkIRect crop_rect = SkIRect::MakeXYWH(-111, -222, 333, 444);
1970 SkImageFilter::CropRect crop(SkRect::Make(crop_rect));
1971 test_arithmetic_bounds(reporter, 0, 0, 0, 0, background, foreground, &crop,
1972 SkIRect::MakeEmpty());
1973 test_arithmetic_bounds(reporter, 0, 0, 0, v, background, foreground, &crop, crop_rect);
1974 test_arithmetic_bounds(reporter, 0, 0, v, 0, background, foreground, &crop, background_rect);
1975 test_arithmetic_bounds(reporter, 0, 0, v, v, background, foreground, &crop, crop_rect);
1976 test_arithmetic_bounds(reporter, 0, v, 0, 0, background, foreground, &crop, foreground_rect);
1977 test_arithmetic_bounds(reporter, 0, v, 0, v, background, foreground, &crop, crop_rect);
1978 test_arithmetic_bounds(reporter, 0, v, v, 0, background, foreground, &crop, union_rect);
1979 test_arithmetic_bounds(reporter, 0, v, v, v, background, foreground, &crop, crop_rect);
1980 test_arithmetic_bounds(reporter, v, 0, 0, 0, background, foreground, &crop, intersection);
1981 test_arithmetic_bounds(reporter, v, 0, 0, v, background, foreground, &crop, crop_rect);
1982 test_arithmetic_bounds(reporter, v, 0, v, 0, background, foreground, &crop, background_rect);
1983 test_arithmetic_bounds(reporter, v, 0, v, v, background, foreground, &crop, crop_rect);
1984 test_arithmetic_bounds(reporter, v, v, 0, 0, background, foreground, &crop, foreground_rect);
1985 test_arithmetic_bounds(reporter, v, v, 0, v, background, foreground, &crop, crop_rect);
1986 test_arithmetic_bounds(reporter, v, v, v, 0, background, foreground, &crop, union_rect);
1987 test_arithmetic_bounds(reporter, v, v, v, v, background, foreground, &crop, crop_rect);
1988}
1989
Xianzhu Wangb4496662017-09-25 10:26:40 -07001990// Test SkArithmeticImageFilter::filterBounds with different blending modes.
Xianzhu Wang0fa353c2017-08-25 16:27:04 -07001991DEF_TEST(ArithmeticImageFilterBounds, reporter) {
1992 test_arithmetic_combinations(reporter, 1);
1993 test_arithmetic_combinations(reporter, 0.5);
1994}
Xianzhu Wangb4496662017-09-25 10:26:40 -07001995
1996// Test SkImageSource::filterBounds.
1997DEF_TEST(ImageSourceBounds, reporter) {
1998 sk_sp<SkImage> image(SkImage::MakeFromBitmap(make_gradient_circle(64, 64)));
1999 // Default src and dst rects.
2000 sk_sp<SkImageFilter> source1(SkImageSource::Make(image));
2001 SkIRect imageBounds = SkIRect::MakeWH(64, 64);
2002 SkIRect input(SkIRect::MakeXYWH(10, 20, 30, 40));
2003 REPORTER_ASSERT(reporter,
2004 imageBounds == source1->filterBounds(input, SkMatrix::I(),
Robert Phillips12078432018-05-17 11:17:39 -04002005 SkImageFilter::kForward_MapDirection,
2006 nullptr));
Xianzhu Wangb4496662017-09-25 10:26:40 -07002007 REPORTER_ASSERT(reporter,
2008 input == source1->filterBounds(input, SkMatrix::I(),
Robert Phillips12078432018-05-17 11:17:39 -04002009 SkImageFilter::kReverse_MapDirection, &input));
Xianzhu Wangb4496662017-09-25 10:26:40 -07002010 SkMatrix scale(SkMatrix::MakeScale(2));
2011 SkIRect scaledBounds = SkIRect::MakeWH(128, 128);
2012 REPORTER_ASSERT(reporter,
2013 scaledBounds == source1->filterBounds(input, scale,
Robert Phillips12078432018-05-17 11:17:39 -04002014 SkImageFilter::kForward_MapDirection,
2015 nullptr));
2016 REPORTER_ASSERT(reporter, input == source1->filterBounds(input, scale,
2017 SkImageFilter::kReverse_MapDirection,
2018 &input));
Xianzhu Wangb4496662017-09-25 10:26:40 -07002019
2020 // Specified src and dst rects.
2021 SkRect src(SkRect::MakeXYWH(0.5, 0.5, 100.5, 100.5));
2022 SkRect dst(SkRect::MakeXYWH(-10.5, -10.5, 120.5, 120.5));
2023 sk_sp<SkImageFilter> source2(SkImageSource::Make(image, src, dst, kMedium_SkFilterQuality));
2024 REPORTER_ASSERT(reporter,
2025 dst.roundOut() == source2->filterBounds(input, SkMatrix::I(),
Robert Phillips12078432018-05-17 11:17:39 -04002026 SkImageFilter::kForward_MapDirection,
2027 nullptr));
Xianzhu Wangb4496662017-09-25 10:26:40 -07002028 REPORTER_ASSERT(reporter,
2029 input == source2->filterBounds(input, SkMatrix::I(),
Robert Phillips12078432018-05-17 11:17:39 -04002030 SkImageFilter::kReverse_MapDirection, &input));
Xianzhu Wangb4496662017-09-25 10:26:40 -07002031 scale.mapRect(&dst);
2032 scale.mapRect(&src);
2033 REPORTER_ASSERT(reporter,
2034 dst.roundOut() == source2->filterBounds(input, scale,
Robert Phillips12078432018-05-17 11:17:39 -04002035 SkImageFilter::kForward_MapDirection,
2036 nullptr));
2037 REPORTER_ASSERT(reporter, input == source2->filterBounds(input, scale,
2038 SkImageFilter::kReverse_MapDirection,
2039 &input));
Xianzhu Wangb4496662017-09-25 10:26:40 -07002040}
Robert Phillips12078432018-05-17 11:17:39 -04002041