blob: f8435868c41cd2afe5d8e82c0f7a570db0b0855b [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
commit-bot@chromium.org4b681bc2013-09-13 12:40:02 +00008#include "SkBitmap.h"
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00009#include "SkBlurImageFilter.h"
tfarina@chromium.org8f6884a2014-01-24 20:56:26 +000010#include "SkCanvas.h"
11#include "SkColorFilterImageFilter.h"
12#include "SkColorMatrixFilter.h"
ajuma5788faa2015-02-13 09:05:47 -080013#include "SkComposeImageFilter.h"
senorblanco@chromium.org6776b822014-01-03 21:48:22 +000014#include "SkDisplacementMapEffect.h"
15#include "SkDropShadowImageFilter.h"
senorblanco@chromium.org97f5fc62014-05-30 20:50:56 +000016#include "SkFlattenableSerialization.h"
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +000017#include "SkGradientShader.h"
fmalita5598b632015-09-15 11:26:13 -070018#include "SkImage.h"
fmalitacd56f812015-09-14 13:31:18 -070019#include "SkImageSource.h"
commit-bot@chromium.org4b681bc2013-09-13 12:40:02 +000020#include "SkLightingImageFilter.h"
tfarina@chromium.org8f6884a2014-01-24 20:56:26 +000021#include "SkMatrixConvolutionImageFilter.h"
senorblanco@chromium.org6776b822014-01-03 21:48:22 +000022#include "SkMergeImageFilter.h"
23#include "SkMorphologyImageFilter.h"
senorblanco@chromium.org6776b822014-01-03 21:48:22 +000024#include "SkOffsetImageFilter.h"
ajuma77b6ba32016-01-08 14:58:35 -080025#include "SkPaintImageFilter.h"
senorblanco8f3937d2014-10-29 12:36:32 -070026#include "SkPerlinNoiseShader.h"
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +000027#include "SkPicture.h"
senorblanco@chromium.org910702b2014-05-30 20:36:15 +000028#include "SkPictureImageFilter.h"
robertphillips@google.com770963f2014-04-18 18:04:41 +000029#include "SkPictureRecorder.h"
robertphillips3d32d762015-07-13 13:16:44 -070030#include "SkPoint3.h"
halcanary97d2c0a2014-08-19 06:27:53 -070031#include "SkReadBuffer.h"
tfarina@chromium.org8f6884a2014-01-24 20:56:26 +000032#include "SkRect.h"
robertphillips4418dba2016-03-07 12:45:14 -080033#include "SkSpecialImage.h"
34#include "SkSpecialSurface.h"
fmalitacd56f812015-09-14 13:31:18 -070035#include "SkSurface.h"
senorblanco0abdf762015-08-20 11:10:41 -070036#include "SkTableColorFilter.h"
senorblanco@chromium.org6776b822014-01-03 21:48:22 +000037#include "SkTileImageFilter.h"
38#include "SkXfermodeImageFilter.h"
tfarina@chromium.org8f6884a2014-01-24 20:56:26 +000039#include "Test.h"
senorblanco@chromium.org194d7752013-07-24 22:19:24 +000040
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +000041#if SK_SUPPORT_GPU
kkinnunen15302832015-12-01 04:35:26 -080042#include "GrContext.h"
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +000043#endif
44
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +000045static const int kBitmapSize = 4;
commit-bot@chromium.org4b681bc2013-09-13 12:40:02 +000046
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +000047namespace {
48
49class MatrixTestImageFilter : public SkImageFilter {
50public:
robertphillips43c2ad42016-04-04 05:05:11 -070051 static sk_sp<SkImageFilter> Make(skiatest::Reporter* reporter,
52 const SkMatrix& expectedMatrix) {
53 return sk_sp<SkImageFilter>(new MatrixTestImageFilter(reporter, expectedMatrix));
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +000054 }
55
robertphillipsf3f5bad2014-12-19 13:49:15 -080056 SK_TO_STRING_OVERRIDE()
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +000057 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(MatrixTestImageFilter)
58
59protected:
robertphillips4ba94e22016-04-04 12:07:47 -070060 sk_sp<SkSpecialImage> onFilterImage(SkSpecialImage* source, const Context& ctx,
61 SkIPoint* offset) const override {
robertphillips43c2ad42016-04-04 05:05:11 -070062 REPORTER_ASSERT(fReporter, ctx.ctm() == fExpectedMatrix);
robertphillips4ba94e22016-04-04 12:07:47 -070063 offset->fX = offset->fY = 0;
64 return sk_ref_sp<SkSpecialImage>(source);
robertphillips43c2ad42016-04-04 05:05:11 -070065 }
Matt Sarett62745a82017-04-17 11:57:29 -040066 sk_sp<SkImageFilter> onMakeColorSpace(SkColorSpaceXformer*) const override {
67 return sk_ref_sp(const_cast<MatrixTestImageFilter*>(this));
68 }
robertphillips43c2ad42016-04-04 05:05:11 -070069
mtklein36352bf2015-03-25 18:17:31 -070070 void flatten(SkWriteBuffer& buffer) const override {
brianosman18f13f32016-05-02 07:51:08 -070071 SkDEBUGFAIL("Should never get here");
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +000072 }
73
74private:
robertphillips43c2ad42016-04-04 05:05:11 -070075 MatrixTestImageFilter(skiatest::Reporter* reporter, const SkMatrix& expectedMatrix)
76 : INHERITED(nullptr, 0, nullptr)
77 , fReporter(reporter)
78 , fExpectedMatrix(expectedMatrix) {
79 }
80
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +000081 skiatest::Reporter* fReporter;
82 SkMatrix fExpectedMatrix;
mtklein3f3b3d02014-12-01 11:47:08 -080083
reed9fa60da2014-08-21 07:59:51 -070084 typedef SkImageFilter INHERITED;
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +000085};
86
senorblanco6a93fa12016-04-05 04:43:45 -070087class FailImageFilter : public SkImageFilter {
88public:
robertphillips6b134732016-04-15 09:58:37 -070089 FailImageFilter() : SkImageFilter(nullptr, 0, nullptr) { }
senorblanco6a93fa12016-04-05 04:43:45 -070090
91 sk_sp<SkSpecialImage> onFilterImage(SkSpecialImage* source,
92 const Context& ctx,
93 SkIPoint* offset) const override {
94 return nullptr;
95 }
Matt Sarett62745a82017-04-17 11:57:29 -040096 sk_sp<SkImageFilter> onMakeColorSpace(SkColorSpaceXformer*) const override {
97 return nullptr;
98 }
senorblanco6a93fa12016-04-05 04:43:45 -070099
100 SK_TO_STRING_OVERRIDE()
101 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(FailImageFilter)
102
103private:
104 typedef SkImageFilter INHERITED;
105};
106
107sk_sp<SkFlattenable> FailImageFilter::CreateProc(SkReadBuffer& buffer) {
108 SK_IMAGEFILTER_UNFLATTEN_COMMON(common, 0);
109 return sk_sp<SkFlattenable>(new FailImageFilter());
110}
111
112#ifndef SK_IGNORE_TO_STRING
113void FailImageFilter::toString(SkString* str) const {
114 str->appendf("FailImageFilter: (");
115 str->append(")");
116}
117#endif
118
senorblanco297f7ce2016-03-23 13:44:26 -0700119void draw_gradient_circle(SkCanvas* canvas, int width, int height) {
120 SkScalar x = SkIntToScalar(width / 2);
121 SkScalar y = SkIntToScalar(height / 2);
122 SkScalar radius = SkMinScalar(x, y) * 0.8f;
123 canvas->clear(0x00000000);
124 SkColor colors[2];
125 colors[0] = SK_ColorWHITE;
126 colors[1] = SK_ColorBLACK;
127 sk_sp<SkShader> shader(
128 SkGradientShader::MakeRadial(SkPoint::Make(x, y), radius, colors, nullptr, 2,
129 SkShader::kClamp_TileMode)
130 );
131 SkPaint paint;
132 paint.setShader(shader);
133 canvas->drawCircle(x, y, radius, paint);
134}
135
136SkBitmap make_gradient_circle(int width, int height) {
137 SkBitmap bitmap;
138 bitmap.allocN32Pixels(width, height);
139 SkCanvas canvas(bitmap);
140 draw_gradient_circle(&canvas, width, height);
141 return bitmap;
142}
143
144class FilterList {
145public:
robertphillipsfc11b0a2016-04-05 09:09:36 -0700146 FilterList(sk_sp<SkImageFilter> input, const SkImageFilter::CropRect* cropRect = nullptr) {
senorblanco297f7ce2016-03-23 13:44:26 -0700147 SkPoint3 location = SkPoint3::Make(0, 0, SK_Scalar1);
senorblanco297f7ce2016-03-23 13:44:26 -0700148 const SkScalar five = SkIntToScalar(5);
149
robertphillips6e7025a2016-04-04 04:31:25 -0700150 {
151 sk_sp<SkColorFilter> cf(SkColorFilter::MakeModeFilter(SK_ColorRED,
Mike Reed7d954ad2016-10-28 15:42:34 -0400152 SkBlendMode::kSrcIn));
senorblanco297f7ce2016-03-23 13:44:26 -0700153
robertphillips6e7025a2016-04-04 04:31:25 -0700154 this->addFilter("color filter",
robertphillips12fa47d2016-04-08 16:28:09 -0700155 SkColorFilterImageFilter::Make(std::move(cf), input, cropRect));
robertphillips6e7025a2016-04-04 04:31:25 -0700156 }
senorblanco297f7ce2016-03-23 13:44:26 -0700157
robertphillips6e7025a2016-04-04 04:31:25 -0700158 {
159 sk_sp<SkImage> gradientImage(SkImage::MakeFromBitmap(make_gradient_circle(64, 64)));
160 sk_sp<SkImageFilter> gradientSource(SkImageSource::Make(std::move(gradientImage)));
senorblanco297f7ce2016-03-23 13:44:26 -0700161
liyuqianbfebe222016-11-14 11:17:16 -0800162 this->addFilter("displacement map",
robertphillipsbfe11fc2016-04-15 07:17:36 -0700163 SkDisplacementMapEffect::Make(SkDisplacementMapEffect::kR_ChannelSelectorType,
164 SkDisplacementMapEffect::kB_ChannelSelectorType,
165 20.0f,
166 std::move(gradientSource), input, cropRect));
robertphillips6e7025a2016-04-04 04:31:25 -0700167 }
senorblanco297f7ce2016-03-23 13:44:26 -0700168
robertphillips6e7025a2016-04-04 04:31:25 -0700169 this->addFilter("blur", SkBlurImageFilter::Make(SK_Scalar1,
170 SK_Scalar1,
robertphillipsfc11b0a2016-04-05 09:09:36 -0700171 input,
robertphillips12fa47d2016-04-08 16:28:09 -0700172 cropRect));
robertphillipsc4169122016-04-06 08:40:59 -0700173 this->addFilter("drop shadow", SkDropShadowImageFilter::Make(
senorblanco297f7ce2016-03-23 13:44:26 -0700174 SK_Scalar1, SK_Scalar1, SK_Scalar1, SK_Scalar1, SK_ColorGREEN,
robertphillipsfc11b0a2016-04-05 09:09:36 -0700175 SkDropShadowImageFilter::kDrawShadowAndForeground_ShadowMode,
robertphillips12fa47d2016-04-08 16:28:09 -0700176 input, cropRect));
177 this->addFilter("diffuse lighting",
178 SkLightingImageFilter::MakePointLitDiffuse(location, SK_ColorGREEN, 0, 0,
179 input, cropRect));
senorblanco297f7ce2016-03-23 13:44:26 -0700180 this->addFilter("specular lighting",
robertphillips12fa47d2016-04-08 16:28:09 -0700181 SkLightingImageFilter::MakePointLitSpecular(location, SK_ColorGREEN, 0, 0, 0,
182 input, cropRect));
183 {
184 SkScalar kernel[9] = {
185 SkIntToScalar(1), SkIntToScalar(1), SkIntToScalar(1),
186 SkIntToScalar(1), SkIntToScalar(-7), SkIntToScalar(1),
187 SkIntToScalar(1), SkIntToScalar(1), SkIntToScalar(1),
188 };
189 const SkISize kernelSize = SkISize::Make(3, 3);
190 const SkScalar gain = SK_Scalar1, bias = 0;
191
192 this->addFilter("matrix convolution",
robertphillipsef6a47b2016-04-08 08:01:20 -0700193 SkMatrixConvolutionImageFilter::Make(
senorblanco297f7ce2016-03-23 13:44:26 -0700194 kernelSize, kernel, gain, bias, SkIPoint::Make(1, 1),
robertphillipsfc11b0a2016-04-05 09:09:36 -0700195 SkMatrixConvolutionImageFilter::kRepeat_TileMode, false,
robertphillips12fa47d2016-04-08 16:28:09 -0700196 input, cropRect));
197 }
198
Mike Reed0bdaf052017-06-18 23:35:57 -0400199 this->addFilter("merge", SkMergeImageFilter::Make(input, input, cropRect));
robertphillips12fa47d2016-04-08 16:28:09 -0700200
robertphillips6e7025a2016-04-04 04:31:25 -0700201 {
202 SkPaint greenColorShaderPaint;
203 greenColorShaderPaint.setShader(SkShader::MakeColorShader(SK_ColorGREEN));
204
205 SkImageFilter::CropRect leftSideCropRect(SkRect::MakeXYWH(0, 0, 32, 64));
206 sk_sp<SkImageFilter> paintFilterLeft(SkPaintImageFilter::Make(greenColorShaderPaint,
207 &leftSideCropRect));
208 SkImageFilter::CropRect rightSideCropRect(SkRect::MakeXYWH(32, 0, 32, 64));
209 sk_sp<SkImageFilter> paintFilterRight(SkPaintImageFilter::Make(greenColorShaderPaint,
210 &rightSideCropRect));
211
212
213 this->addFilter("merge with disjoint inputs", SkMergeImageFilter::Make(
Mike Reed0bdaf052017-06-18 23:35:57 -0400214 std::move(paintFilterLeft), std::move(paintFilterRight), cropRect));
robertphillips6e7025a2016-04-04 04:31:25 -0700215 }
216
senorblanco297f7ce2016-03-23 13:44:26 -0700217 this->addFilter("offset",
robertphillipsfc11b0a2016-04-05 09:09:36 -0700218 SkOffsetImageFilter::Make(SK_Scalar1, SK_Scalar1, input,
robertphillips12fa47d2016-04-08 16:28:09 -0700219 cropRect));
220 this->addFilter("dilate", SkDilateImageFilter::Make(3, 2, input, cropRect));
221 this->addFilter("erode", SkErodeImageFilter::Make(2, 3, input, cropRect));
robertphillips534c2702016-04-15 07:57:40 -0700222 this->addFilter("tile", SkTileImageFilter::Make(
223 SkRect::MakeXYWH(0, 0, 50, 50),
224 cropRect ? cropRect->rect() : SkRect::MakeXYWH(0, 0, 100, 100),
225 input));
robertphillips6e7025a2016-04-04 04:31:25 -0700226
robertphillips12fa47d2016-04-08 16:28:09 -0700227 if (!cropRect) {
228 SkMatrix matrix;
229
230 matrix.setTranslate(SK_Scalar1, SK_Scalar1);
231 matrix.postRotate(SkIntToScalar(45), SK_Scalar1, SK_Scalar1);
232
233 this->addFilter("matrix",
234 SkImageFilter::MakeMatrixFilter(matrix, kLow_SkFilterQuality, input));
235 }
robertphillips6e7025a2016-04-04 04:31:25 -0700236 {
robertphillipsfc11b0a2016-04-05 09:09:36 -0700237 sk_sp<SkImageFilter> blur(SkBlurImageFilter::Make(five, five, input));
robertphillips6e7025a2016-04-04 04:31:25 -0700238
239 this->addFilter("blur and offset", SkOffsetImageFilter::Make(five, five,
240 std::move(blur),
robertphillips12fa47d2016-04-08 16:28:09 -0700241 cropRect));
robertphillips6e7025a2016-04-04 04:31:25 -0700242 }
243 {
robertphillips6e7025a2016-04-04 04:31:25 -0700244 SkPictureRecorder recorder;
Mike Klein26eb16f2017-04-10 09:50:25 -0400245 SkCanvas* recordingCanvas = recorder.beginRecording(64, 64);
robertphillips6e7025a2016-04-04 04:31:25 -0700246
247 SkPaint greenPaint;
248 greenPaint.setColor(SK_ColorGREEN);
249 recordingCanvas->drawRect(SkRect::Make(SkIRect::MakeXYWH(10, 10, 30, 20)), greenPaint);
250 sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture());
251 sk_sp<SkImageFilter> pictureFilter(SkPictureImageFilter::Make(std::move(picture)));
252
253 this->addFilter("picture and blur", SkBlurImageFilter::Make(five, five,
254 std::move(pictureFilter),
robertphillips12fa47d2016-04-08 16:28:09 -0700255 cropRect));
robertphillips6e7025a2016-04-04 04:31:25 -0700256 }
257 {
258 SkPaint paint;
259 paint.setShader(SkPerlinNoiseShader::MakeTurbulence(SK_Scalar1, SK_Scalar1, 1, 0));
260 sk_sp<SkImageFilter> paintFilter(SkPaintImageFilter::Make(paint));
261
262 this->addFilter("paint and blur", SkBlurImageFilter::Make(five, five,
263 std::move(paintFilter),
robertphillips12fa47d2016-04-08 16:28:09 -0700264 cropRect));
robertphillips6e7025a2016-04-04 04:31:25 -0700265 }
reed374772b2016-10-05 17:33:02 -0700266 this->addFilter("xfermode", SkXfermodeImageFilter::Make(SkBlendMode::kSrc, input, input,
267 cropRect));
senorblanco297f7ce2016-03-23 13:44:26 -0700268 }
269 int count() const { return fFilters.count(); }
270 SkImageFilter* getFilter(int index) const { return fFilters[index].fFilter.get(); }
271 const char* getName(int index) const { return fFilters[index].fName; }
272private:
273 struct Filter {
robertphillips12fa47d2016-04-08 16:28:09 -0700274 Filter() : fName(nullptr) {}
275 Filter(const char* name, sk_sp<SkImageFilter> filter)
276 : fName(name)
277 , fFilter(std::move(filter)) {
278 }
senorblanco297f7ce2016-03-23 13:44:26 -0700279 const char* fName;
280 sk_sp<SkImageFilter> fFilter;
281 };
robertphillips12fa47d2016-04-08 16:28:09 -0700282 void addFilter(const char* name, sk_sp<SkImageFilter> filter) {
283 fFilters.push_back(Filter(name, std::move(filter)));
senorblanco297f7ce2016-03-23 13:44:26 -0700284 }
285
286 SkTArray<Filter> fFilters;
287};
288
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +0000289}
290
reed60c9b582016-04-03 09:11:13 -0700291sk_sp<SkFlattenable> MatrixTestImageFilter::CreateProc(SkReadBuffer& buffer) {
brianosman18f13f32016-05-02 07:51:08 -0700292 SkDEBUGFAIL("Should never get here");
293 return nullptr;
reed9fa60da2014-08-21 07:59:51 -0700294}
295
robertphillipsf3f5bad2014-12-19 13:49:15 -0800296#ifndef SK_IGNORE_TO_STRING
297void MatrixTestImageFilter::toString(SkString* str) const {
298 str->appendf("MatrixTestImageFilter: (");
299 str->append(")");
300}
301#endif
302
reed9ce9d672016-03-17 10:51:11 -0700303static sk_sp<SkImage> make_small_image() {
reede8f30622016-03-23 18:59:25 -0700304 auto surface(SkSurface::MakeRasterN32Premul(kBitmapSize, kBitmapSize));
fmalita5598b632015-09-15 11:26:13 -0700305 SkCanvas* canvas = surface->getCanvas();
306 canvas->clear(0x00000000);
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000307 SkPaint darkPaint;
308 darkPaint.setColor(0xFF804020);
309 SkPaint lightPaint;
310 lightPaint.setColor(0xFF244484);
311 const int i = kBitmapSize / 4;
312 for (int y = 0; y < kBitmapSize; y += i) {
313 for (int x = 0; x < kBitmapSize; x += i) {
fmalita5598b632015-09-15 11:26:13 -0700314 canvas->save();
315 canvas->translate(SkIntToScalar(x), SkIntToScalar(y));
316 canvas->drawRect(SkRect::MakeXYWH(0, 0,
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000317 SkIntToScalar(i),
318 SkIntToScalar(i)), darkPaint);
fmalita5598b632015-09-15 11:26:13 -0700319 canvas->drawRect(SkRect::MakeXYWH(SkIntToScalar(i),
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000320 0,
321 SkIntToScalar(i),
322 SkIntToScalar(i)), lightPaint);
fmalita5598b632015-09-15 11:26:13 -0700323 canvas->drawRect(SkRect::MakeXYWH(0,
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000324 SkIntToScalar(i),
325 SkIntToScalar(i),
326 SkIntToScalar(i)), lightPaint);
fmalita5598b632015-09-15 11:26:13 -0700327 canvas->drawRect(SkRect::MakeXYWH(SkIntToScalar(i),
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000328 SkIntToScalar(i),
329 SkIntToScalar(i),
330 SkIntToScalar(i)), darkPaint);
fmalita5598b632015-09-15 11:26:13 -0700331 canvas->restore();
commit-bot@chromium.org4b681bc2013-09-13 12:40:02 +0000332 }
333 }
fmalita5598b632015-09-15 11:26:13 -0700334
reed9ce9d672016-03-17 10:51:11 -0700335 return surface->makeImageSnapshot();
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000336}
senorblanco@chromium.org194d7752013-07-24 22:19:24 +0000337
robertphillips5605b562016-04-05 11:50:42 -0700338static sk_sp<SkImageFilter> make_scale(float amount, sk_sp<SkImageFilter> input) {
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000339 SkScalar s = amount;
340 SkScalar matrix[20] = { s, 0, 0, 0, 0,
341 0, s, 0, 0, 0,
342 0, 0, s, 0, 0,
343 0, 0, 0, s, 0 };
robertphillips5605b562016-04-05 11:50:42 -0700344 sk_sp<SkColorFilter> filter(SkColorFilter::MakeMatrixFilterRowMajor255(matrix));
345 return SkColorFilterImageFilter::Make(std::move(filter), std::move(input));
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000346}
347
robertphillips5605b562016-04-05 11:50:42 -0700348static sk_sp<SkImageFilter> make_grayscale(sk_sp<SkImageFilter> input,
349 const SkImageFilter::CropRect* cropRect) {
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000350 SkScalar matrix[20];
351 memset(matrix, 0, 20 * sizeof(SkScalar));
352 matrix[0] = matrix[5] = matrix[10] = 0.2126f;
353 matrix[1] = matrix[6] = matrix[11] = 0.7152f;
354 matrix[2] = matrix[7] = matrix[12] = 0.0722f;
355 matrix[18] = 1.0f;
robertphillips5605b562016-04-05 11:50:42 -0700356 sk_sp<SkColorFilter> filter(SkColorFilter::MakeMatrixFilterRowMajor255(matrix));
357 return SkColorFilterImageFilter::Make(std::move(filter), std::move(input), cropRect);
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000358}
359
robertphillips5605b562016-04-05 11:50:42 -0700360static sk_sp<SkImageFilter> make_blue(sk_sp<SkImageFilter> input,
361 const SkImageFilter::CropRect* cropRect) {
362 sk_sp<SkColorFilter> filter(SkColorFilter::MakeModeFilter(SK_ColorBLUE,
Mike Reed7d954ad2016-10-28 15:42:34 -0400363 SkBlendMode::kSrcIn));
robertphillips5605b562016-04-05 11:50:42 -0700364 return SkColorFilterImageFilter::Make(std::move(filter), std::move(input), cropRect);
reedcedc36f2015-03-08 04:42:52 -0700365}
366
robertphillips3e302272016-04-20 11:48:36 -0700367static sk_sp<SkSpecialSurface> create_empty_special_surface(GrContext* context, int widthHeight) {
robertphillipsc91fd342016-04-25 12:32:54 -0700368#if SK_SUPPORT_GPU
robertphillips4418dba2016-03-07 12:45:14 -0800369 if (context) {
robertphillips4df16562016-04-28 15:09:34 -0700370 return SkSpecialSurface::MakeRenderTarget(context,
371 widthHeight, widthHeight,
Brian Osman777b5632016-10-14 09:16:21 -0400372 kRGBA_8888_GrPixelConfig, nullptr);
robertphillipsc91fd342016-04-25 12:32:54 -0700373 } else
374#endif
375 {
robertphillips4418dba2016-03-07 12:45:14 -0800376 const SkImageInfo info = SkImageInfo::MakeN32(widthHeight, widthHeight,
377 kOpaque_SkAlphaType);
robertphillips3e302272016-04-20 11:48:36 -0700378 return SkSpecialSurface::MakeRaster(info);
robertphillips4418dba2016-03-07 12:45:14 -0800379 }
senorblancobf680c32016-03-16 16:15:53 -0700380}
381
senorblanco5878dbd2016-05-19 14:50:29 -0700382static sk_sp<SkSurface> create_surface(GrContext* context, int width, int height) {
383 const SkImageInfo info = SkImageInfo::MakeN32(width, height, kOpaque_SkAlphaType);
384#if SK_SUPPORT_GPU
385 if (context) {
386 return SkSurface::MakeRenderTarget(context, SkBudgeted::kNo, info);
387 } else
388#endif
389 {
390 return SkSurface::MakeRaster(info);
391 }
392}
393
robertphillips3e302272016-04-20 11:48:36 -0700394static sk_sp<SkSpecialImage> create_empty_special_image(GrContext* context, int widthHeight) {
395 sk_sp<SkSpecialSurface> surf(create_empty_special_surface(context, widthHeight));
robertphillips4418dba2016-03-07 12:45:14 -0800396
397 SkASSERT(surf);
398
399 SkCanvas* canvas = surf->getCanvas();
400 SkASSERT(canvas);
401
402 canvas->clear(0x0);
403
robertphillips37bd7c32016-03-17 14:31:39 -0700404 return surf->makeImageSnapshot();
robertphillips4418dba2016-03-07 12:45:14 -0800405}
406
407
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000408DEF_TEST(ImageFilter, reporter) {
409 {
reedcedc36f2015-03-08 04:42:52 -0700410 // Check that two non-clipping color-matrice-filters concatenate into a single filter.
robertphillips5605b562016-04-05 11:50:42 -0700411 sk_sp<SkImageFilter> halfBrightness(make_scale(0.5f, nullptr));
412 sk_sp<SkImageFilter> quarterBrightness(make_scale(0.5f, std::move(halfBrightness)));
halcanary96fcdcc2015-08-27 07:41:13 -0700413 REPORTER_ASSERT(reporter, nullptr == quarterBrightness->getInput(0));
reedcedc36f2015-03-08 04:42:52 -0700414 SkColorFilter* cf;
415 REPORTER_ASSERT(reporter, quarterBrightness->asColorFilter(&cf));
halcanary96fcdcc2015-08-27 07:41:13 -0700416 REPORTER_ASSERT(reporter, cf->asColorMatrix(nullptr));
reedcedc36f2015-03-08 04:42:52 -0700417 cf->unref();
senorblanco@chromium.org194d7752013-07-24 22:19:24 +0000418 }
419
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000420 {
reedcedc36f2015-03-08 04:42:52 -0700421 // Check that a clipping color-matrice-filter followed by a color-matrice-filters
422 // concatenates into a single filter, but not a matrixfilter (due to clamping).
robertphillips5605b562016-04-05 11:50:42 -0700423 sk_sp<SkImageFilter> doubleBrightness(make_scale(2.0f, nullptr));
424 sk_sp<SkImageFilter> halfBrightness(make_scale(0.5f, std::move(doubleBrightness)));
halcanary96fcdcc2015-08-27 07:41:13 -0700425 REPORTER_ASSERT(reporter, nullptr == halfBrightness->getInput(0));
reedcedc36f2015-03-08 04:42:52 -0700426 SkColorFilter* cf;
427 REPORTER_ASSERT(reporter, halfBrightness->asColorFilter(&cf));
halcanary96fcdcc2015-08-27 07:41:13 -0700428 REPORTER_ASSERT(reporter, !cf->asColorMatrix(nullptr));
reedcedc36f2015-03-08 04:42:52 -0700429 cf->unref();
senorblanco@chromium.org194d7752013-07-24 22:19:24 +0000430 }
431
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000432 {
433 // Check that a color filter image filter without a crop rect can be
434 // expressed as a color filter.
robertphillips5605b562016-04-05 11:50:42 -0700435 sk_sp<SkImageFilter> gray(make_grayscale(nullptr, nullptr));
halcanary96fcdcc2015-08-27 07:41:13 -0700436 REPORTER_ASSERT(reporter, true == gray->asColorFilter(nullptr));
senorblanco@chromium.org194d7752013-07-24 22:19:24 +0000437 }
mtklein2afbe232016-02-07 12:23:10 -0800438
reedcedc36f2015-03-08 04:42:52 -0700439 {
440 // Check that a colorfilterimage filter without a crop rect but with an input
441 // that is another colorfilterimage can be expressed as a colorfilter (composed).
robertphillips5605b562016-04-05 11:50:42 -0700442 sk_sp<SkImageFilter> mode(make_blue(nullptr, nullptr));
443 sk_sp<SkImageFilter> gray(make_grayscale(std::move(mode), nullptr));
halcanary96fcdcc2015-08-27 07:41:13 -0700444 REPORTER_ASSERT(reporter, true == gray->asColorFilter(nullptr));
reedcedc36f2015-03-08 04:42:52 -0700445 }
446
447 {
448 // Test that if we exceed the limit of what ComposeColorFilter can combine, we still
449 // can build the DAG and won't assert if we call asColorFilter.
robertphillips5605b562016-04-05 11:50:42 -0700450 sk_sp<SkImageFilter> filter(make_blue(nullptr, nullptr));
reedcedc36f2015-03-08 04:42:52 -0700451 const int kWayTooManyForComposeColorFilter = 100;
452 for (int i = 0; i < kWayTooManyForComposeColorFilter; ++i) {
robertphillips5605b562016-04-05 11:50:42 -0700453 filter = make_blue(filter, nullptr);
reedcedc36f2015-03-08 04:42:52 -0700454 // the first few of these will succeed, but after we hit the internal limit,
455 // it will then return false.
halcanary96fcdcc2015-08-27 07:41:13 -0700456 (void)filter->asColorFilter(nullptr);
reedcedc36f2015-03-08 04:42:52 -0700457 }
458 }
reed5c518a82015-03-05 14:47:29 -0800459
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000460 {
461 // Check that a color filter image filter with a crop rect cannot
462 // be expressed as a color filter.
463 SkImageFilter::CropRect cropRect(SkRect::MakeXYWH(0, 0, 100, 100));
robertphillips5605b562016-04-05 11:50:42 -0700464 sk_sp<SkImageFilter> grayWithCrop(make_grayscale(nullptr, &cropRect));
halcanary96fcdcc2015-08-27 07:41:13 -0700465 REPORTER_ASSERT(reporter, false == grayWithCrop->asColorFilter(nullptr));
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000466 }
467
468 {
senorblanco3df05012014-07-03 11:13:09 -0700469 // Check that two non-commutative matrices are concatenated in
470 // the correct order.
471 SkScalar blueToRedMatrix[20] = { 0 };
472 blueToRedMatrix[2] = blueToRedMatrix[18] = SK_Scalar1;
473 SkScalar redToGreenMatrix[20] = { 0 };
474 redToGreenMatrix[5] = redToGreenMatrix[18] = SK_Scalar1;
robertphillips5605b562016-04-05 11:50:42 -0700475 sk_sp<SkColorFilter> blueToRed(SkColorFilter::MakeMatrixFilterRowMajor255(blueToRedMatrix));
476 sk_sp<SkImageFilter> filter1(SkColorFilterImageFilter::Make(std::move(blueToRed),
477 nullptr));
478 sk_sp<SkColorFilter> redToGreen(SkColorFilter::MakeMatrixFilterRowMajor255(redToGreenMatrix));
479 sk_sp<SkImageFilter> filter2(SkColorFilterImageFilter::Make(std::move(redToGreen),
480 std::move(filter1)));
senorblanco3df05012014-07-03 11:13:09 -0700481
482 SkBitmap result;
483 result.allocN32Pixels(kBitmapSize, kBitmapSize);
484
485 SkPaint paint;
486 paint.setColor(SK_ColorBLUE);
robertphillips5605b562016-04-05 11:50:42 -0700487 paint.setImageFilter(std::move(filter2));
senorblanco3df05012014-07-03 11:13:09 -0700488 SkCanvas canvas(result);
489 canvas.clear(0x0);
490 SkRect rect = SkRect::Make(SkIRect::MakeWH(kBitmapSize, kBitmapSize));
491 canvas.drawRect(rect, paint);
492 uint32_t pixel = *result.getAddr32(0, 0);
493 // The result here should be green, since we have effectively shifted blue to green.
494 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
495 }
496
497 {
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000498 // Tests pass by not asserting
reed9ce9d672016-03-17 10:51:11 -0700499 sk_sp<SkImage> image(make_small_image());
fmalita5598b632015-09-15 11:26:13 -0700500 SkBitmap result;
mike@reedtribe.orgdeee4962014-02-13 14:41:43 +0000501 result.allocN32Pixels(kBitmapSize, kBitmapSize);
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000502
senorblanco@chromium.org194d7752013-07-24 22:19:24 +0000503 {
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000504 // This tests for :
505 // 1 ) location at (0,0,1)
robertphillips3d32d762015-07-13 13:16:44 -0700506 SkPoint3 location = SkPoint3::Make(0, 0, SK_Scalar1);
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000507 // 2 ) location and target at same value
robertphillips3d32d762015-07-13 13:16:44 -0700508 SkPoint3 target = SkPoint3::Make(location.fX, location.fY, location.fZ);
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000509 // 3 ) large negative specular exponent value
510 SkScalar specularExponent = -1000;
511
robertphillips549c8992016-04-01 09:28:51 -0700512 sk_sp<SkImageFilter> bmSrc(SkImageSource::Make(std::move(image)));
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000513 SkPaint paint;
robertphillips12fa47d2016-04-08 16:28:09 -0700514 paint.setImageFilter(SkLightingImageFilter::MakeSpotLitSpecular(
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000515 location, target, specularExponent, 180,
516 0xFFFFFFFF, SK_Scalar1, SK_Scalar1, SK_Scalar1,
robertphillips12fa47d2016-04-08 16:28:09 -0700517 std::move(bmSrc)));
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000518 SkCanvas canvas(result);
519 SkRect r = SkRect::MakeWH(SkIntToScalar(kBitmapSize),
520 SkIntToScalar(kBitmapSize));
521 canvas.drawRect(r, paint);
senorblanco@chromium.org194d7752013-07-24 22:19:24 +0000522 }
senorblanco@chromium.org194d7752013-07-24 22:19:24 +0000523 }
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +0000524}
senorblanco@chromium.org6776b822014-01-03 21:48:22 +0000525
robertphillips3e302272016-04-20 11:48:36 -0700526static void test_crop_rects(skiatest::Reporter* reporter,
robertphillips4418dba2016-03-07 12:45:14 -0800527 GrContext* context) {
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +0000528 // Check that all filters offset to their absolute crop rect,
529 // unaffected by the input crop rect.
530 // Tests pass by not asserting.
robertphillips3e302272016-04-20 11:48:36 -0700531 sk_sp<SkSpecialImage> srcImg(create_empty_special_image(context, 100));
robertphillips4418dba2016-03-07 12:45:14 -0800532 SkASSERT(srcImg);
senorblanco@chromium.org6776b822014-01-03 21:48:22 +0000533
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +0000534 SkImageFilter::CropRect inputCropRect(SkRect::MakeXYWH(8, 13, 80, 80));
535 SkImageFilter::CropRect cropRect(SkRect::MakeXYWH(20, 30, 60, 60));
robertphillipsfc11b0a2016-04-05 09:09:36 -0700536 sk_sp<SkImageFilter> input(make_grayscale(nullptr, &inputCropRect));
senorblanco@chromium.org6776b822014-01-03 21:48:22 +0000537
robertphillipsfc11b0a2016-04-05 09:09:36 -0700538 FilterList filters(input, &cropRect);
senorblanco@chromium.org6776b822014-01-03 21:48:22 +0000539
senorblanco297f7ce2016-03-23 13:44:26 -0700540 for (int i = 0; i < filters.count(); ++i) {
541 SkImageFilter* filter = filters.getFilter(i);
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +0000542 SkIPoint offset;
brianosman2a75e5d2016-09-22 07:15:37 -0700543 SkImageFilter::OutputProperties noColorSpace(nullptr);
544 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeWH(100, 100), nullptr, noColorSpace);
robertphillips2302de92016-03-24 07:26:32 -0700545 sk_sp<SkSpecialImage> resultImg(filter->filterImage(srcImg.get(), ctx, &offset));
senorblanco297f7ce2016-03-23 13:44:26 -0700546 REPORTER_ASSERT_MESSAGE(reporter, resultImg, filters.getName(i));
547 REPORTER_ASSERT_MESSAGE(reporter, offset.fX == 20 && offset.fY == 30, filters.getName(i));
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +0000548 }
549}
550
robertphillips3e302272016-04-20 11:48:36 -0700551static void test_negative_blur_sigma(skiatest::Reporter* reporter,
robertphillips4418dba2016-03-07 12:45:14 -0800552 GrContext* context) {
senorblanco32673b92014-09-09 09:15:04 -0700553 // Check that SkBlurImageFilter will accept a negative sigma, either in
554 // the given arguments or after CTM application.
reed5ea95df2015-10-06 14:05:32 -0700555 const int width = 32, height = 32;
556 const SkScalar five = SkIntToScalar(5);
senorblanco32673b92014-09-09 09:15:04 -0700557
robertphillips6e7025a2016-04-04 04:31:25 -0700558 sk_sp<SkImageFilter> positiveFilter(SkBlurImageFilter::Make(five, five, nullptr));
559 sk_sp<SkImageFilter> negativeFilter(SkBlurImageFilter::Make(-five, five, nullptr));
senorblanco32673b92014-09-09 09:15:04 -0700560
561 SkBitmap gradient = make_gradient_circle(width, height);
robertphillips3e302272016-04-20 11:48:36 -0700562 sk_sp<SkSpecialImage> imgSrc(SkSpecialImage::MakeFromRaster(SkIRect::MakeWH(width, height),
robertphillips37bd7c32016-03-17 14:31:39 -0700563 gradient));
robertphillips4418dba2016-03-07 12:45:14 -0800564
senorblanco32673b92014-09-09 09:15:04 -0700565 SkIPoint offset;
brianosman2a75e5d2016-09-22 07:15:37 -0700566 SkImageFilter::OutputProperties noColorSpace(nullptr);
567 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeWH(32, 32), nullptr, noColorSpace);
robertphillips4418dba2016-03-07 12:45:14 -0800568
robertphillips2302de92016-03-24 07:26:32 -0700569 sk_sp<SkSpecialImage> positiveResult1(positiveFilter->filterImage(imgSrc.get(), ctx, &offset));
robertphillips4418dba2016-03-07 12:45:14 -0800570 REPORTER_ASSERT(reporter, positiveResult1);
571
robertphillips2302de92016-03-24 07:26:32 -0700572 sk_sp<SkSpecialImage> negativeResult1(negativeFilter->filterImage(imgSrc.get(), ctx, &offset));
robertphillips4418dba2016-03-07 12:45:14 -0800573 REPORTER_ASSERT(reporter, negativeResult1);
574
senorblanco32673b92014-09-09 09:15:04 -0700575 SkMatrix negativeScale;
576 negativeScale.setScale(-SK_Scalar1, SK_Scalar1);
brianosman2a75e5d2016-09-22 07:15:37 -0700577 SkImageFilter::Context negativeCTX(negativeScale, SkIRect::MakeWH(32, 32), nullptr,
578 noColorSpace);
robertphillips4418dba2016-03-07 12:45:14 -0800579
robertphillips2302de92016-03-24 07:26:32 -0700580 sk_sp<SkSpecialImage> negativeResult2(positiveFilter->filterImage(imgSrc.get(),
581 negativeCTX,
582 &offset));
robertphillips4418dba2016-03-07 12:45:14 -0800583 REPORTER_ASSERT(reporter, negativeResult2);
584
robertphillips2302de92016-03-24 07:26:32 -0700585 sk_sp<SkSpecialImage> positiveResult2(negativeFilter->filterImage(imgSrc.get(),
586 negativeCTX,
587 &offset));
robertphillips4418dba2016-03-07 12:45:14 -0800588 REPORTER_ASSERT(reporter, positiveResult2);
589
590
591 SkBitmap positiveResultBM1, positiveResultBM2;
592 SkBitmap negativeResultBM1, negativeResultBM2;
593
robertphillips64612512016-04-08 12:10:42 -0700594 REPORTER_ASSERT(reporter, positiveResult1->getROPixels(&positiveResultBM1));
595 REPORTER_ASSERT(reporter, positiveResult2->getROPixels(&positiveResultBM2));
596 REPORTER_ASSERT(reporter, negativeResult1->getROPixels(&negativeResultBM1));
597 REPORTER_ASSERT(reporter, negativeResult2->getROPixels(&negativeResultBM2));
robertphillips4418dba2016-03-07 12:45:14 -0800598
senorblanco32673b92014-09-09 09:15:04 -0700599 for (int y = 0; y < height; y++) {
robertphillips4418dba2016-03-07 12:45:14 -0800600 int diffs = memcmp(positiveResultBM1.getAddr32(0, y),
601 negativeResultBM1.getAddr32(0, y),
602 positiveResultBM1.rowBytes());
senorblanco32673b92014-09-09 09:15:04 -0700603 REPORTER_ASSERT(reporter, !diffs);
604 if (diffs) {
605 break;
606 }
robertphillips4418dba2016-03-07 12:45:14 -0800607 diffs = memcmp(positiveResultBM1.getAddr32(0, y),
608 negativeResultBM2.getAddr32(0, y),
609 positiveResultBM1.rowBytes());
senorblanco32673b92014-09-09 09:15:04 -0700610 REPORTER_ASSERT(reporter, !diffs);
611 if (diffs) {
612 break;
613 }
robertphillips4418dba2016-03-07 12:45:14 -0800614 diffs = memcmp(positiveResultBM1.getAddr32(0, y),
615 positiveResultBM2.getAddr32(0, y),
616 positiveResultBM1.rowBytes());
senorblanco32673b92014-09-09 09:15:04 -0700617 REPORTER_ASSERT(reporter, !diffs);
618 if (diffs) {
619 break;
620 }
621 }
622}
623
senorblanco21a465d2016-04-11 11:58:39 -0700624DEF_TEST(ImageFilterNegativeBlurSigma, reporter) {
robertphillips3e302272016-04-20 11:48:36 -0700625 test_negative_blur_sigma(reporter, nullptr);
robertphillips4418dba2016-03-07 12:45:14 -0800626}
627
628#if SK_SUPPORT_GPU
bsalomon68d91342016-04-12 09:59:58 -0700629DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterNegativeBlurSigma_Gpu, reporter, ctxInfo) {
bsalomon8b7451a2016-05-11 06:33:06 -0700630 test_negative_blur_sigma(reporter, ctxInfo.grContext());
robertphillips4418dba2016-03-07 12:45:14 -0800631}
632#endif
633
robertphillips3e302272016-04-20 11:48:36 -0700634static void test_zero_blur_sigma(skiatest::Reporter* reporter, GrContext* context) {
senorblancobf680c32016-03-16 16:15:53 -0700635 // Check that SkBlurImageFilter with a zero sigma and a non-zero srcOffset works correctly.
636 SkImageFilter::CropRect cropRect(SkRect::Make(SkIRect::MakeXYWH(5, 0, 5, 10)));
robertphillips51a315e2016-03-31 09:05:49 -0700637 sk_sp<SkImageFilter> input(SkOffsetImageFilter::Make(0, 0, nullptr, &cropRect));
robertphillips6e7025a2016-04-04 04:31:25 -0700638 sk_sp<SkImageFilter> filter(SkBlurImageFilter::Make(0, 0, std::move(input), &cropRect));
senorblancobf680c32016-03-16 16:15:53 -0700639
robertphillips3e302272016-04-20 11:48:36 -0700640 sk_sp<SkSpecialSurface> surf(create_empty_special_surface(context, 10));
senorblancobf680c32016-03-16 16:15:53 -0700641 surf->getCanvas()->clear(SK_ColorGREEN);
robertphillips37bd7c32016-03-17 14:31:39 -0700642 sk_sp<SkSpecialImage> image(surf->makeImageSnapshot());
senorblancobf680c32016-03-16 16:15:53 -0700643
644 SkIPoint offset;
brianosman2a75e5d2016-09-22 07:15:37 -0700645 SkImageFilter::OutputProperties noColorSpace(nullptr);
646 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeWH(32, 32), nullptr, noColorSpace);
senorblancobf680c32016-03-16 16:15:53 -0700647
robertphillips2302de92016-03-24 07:26:32 -0700648 sk_sp<SkSpecialImage> result(filter->filterImage(image.get(), ctx, &offset));
senorblancobf680c32016-03-16 16:15:53 -0700649 REPORTER_ASSERT(reporter, offset.fX == 5 && offset.fY == 0);
650 REPORTER_ASSERT(reporter, result);
651 REPORTER_ASSERT(reporter, result->width() == 5 && result->height() == 10);
652
653 SkBitmap resultBM;
654
robertphillips64612512016-04-08 12:10:42 -0700655 REPORTER_ASSERT(reporter, result->getROPixels(&resultBM));
senorblancobf680c32016-03-16 16:15:53 -0700656
senorblancobf680c32016-03-16 16:15:53 -0700657 for (int y = 0; y < resultBM.height(); y++) {
658 for (int x = 0; x < resultBM.width(); x++) {
659 bool diff = *resultBM.getAddr32(x, y) != SK_ColorGREEN;
660 REPORTER_ASSERT(reporter, !diff);
661 if (diff) {
662 break;
663 }
664 }
665 }
666}
667
senorblanco21a465d2016-04-11 11:58:39 -0700668DEF_TEST(ImageFilterZeroBlurSigma, reporter) {
robertphillips3e302272016-04-20 11:48:36 -0700669 test_zero_blur_sigma(reporter, nullptr);
senorblancobf680c32016-03-16 16:15:53 -0700670}
671
672#if SK_SUPPORT_GPU
bsalomon68d91342016-04-12 09:59:58 -0700673DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterZeroBlurSigma_Gpu, reporter, ctxInfo) {
bsalomon8b7451a2016-05-11 06:33:06 -0700674 test_zero_blur_sigma(reporter, ctxInfo.grContext());
senorblancobf680c32016-03-16 16:15:53 -0700675}
676#endif
677
senorblanco6a93fa12016-04-05 04:43:45 -0700678
679// Tests that, even when an upstream filter has returned null (due to failure or clipping), a
680// downstream filter that affects transparent black still does so even with a nullptr input.
robertphillips3e302272016-04-20 11:48:36 -0700681static void test_fail_affects_transparent_black(skiatest::Reporter* reporter, GrContext* context) {
senorblanco6a93fa12016-04-05 04:43:45 -0700682 sk_sp<FailImageFilter> failFilter(new FailImageFilter());
robertphillips3e302272016-04-20 11:48:36 -0700683 sk_sp<SkSpecialImage> source(create_empty_special_image(context, 5));
brianosman2a75e5d2016-09-22 07:15:37 -0700684 SkImageFilter::OutputProperties noColorSpace(nullptr);
685 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeXYWH(0, 0, 1, 1), nullptr, noColorSpace);
Mike Reed7d954ad2016-10-28 15:42:34 -0400686 sk_sp<SkColorFilter> green(SkColorFilter::MakeModeFilter(SK_ColorGREEN, SkBlendMode::kSrc));
senorblanco6a93fa12016-04-05 04:43:45 -0700687 SkASSERT(green->affectsTransparentBlack());
robertphillips5605b562016-04-05 11:50:42 -0700688 sk_sp<SkImageFilter> greenFilter(SkColorFilterImageFilter::Make(std::move(green),
689 std::move(failFilter)));
senorblanco6a93fa12016-04-05 04:43:45 -0700690 SkIPoint offset;
691 sk_sp<SkSpecialImage> result(greenFilter->filterImage(source.get(), ctx, &offset));
692 REPORTER_ASSERT(reporter, nullptr != result.get());
693 if (result.get()) {
694 SkBitmap resultBM;
robertphillips64612512016-04-08 12:10:42 -0700695 REPORTER_ASSERT(reporter, result->getROPixels(&resultBM));
senorblanco6a93fa12016-04-05 04:43:45 -0700696 REPORTER_ASSERT(reporter, *resultBM.getAddr32(0, 0) == SK_ColorGREEN);
697 }
698}
699
700DEF_TEST(ImageFilterFailAffectsTransparentBlack, reporter) {
robertphillips3e302272016-04-20 11:48:36 -0700701 test_fail_affects_transparent_black(reporter, nullptr);
senorblanco6a93fa12016-04-05 04:43:45 -0700702}
703
704#if SK_SUPPORT_GPU
bsalomon68d91342016-04-12 09:59:58 -0700705DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterFailAffectsTransparentBlack_Gpu, reporter, ctxInfo) {
bsalomon8b7451a2016-05-11 06:33:06 -0700706 test_fail_affects_transparent_black(reporter, ctxInfo.grContext());
senorblanco6a93fa12016-04-05 04:43:45 -0700707}
708#endif
709
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +0000710DEF_TEST(ImageFilterDrawTiled, reporter) {
711 // Check that all filters when drawn tiled (with subsequent clip rects) exactly
712 // match the same filters drawn with a single full-canvas bitmap draw.
713 // Tests pass by not asserting.
714
robertphillipsfc11b0a2016-04-05 09:09:36 -0700715 FilterList filters(nullptr);
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +0000716
717 SkBitmap untiledResult, tiledResult;
reed5ea95df2015-10-06 14:05:32 -0700718 const int width = 64, height = 64;
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +0000719 untiledResult.allocN32Pixels(width, height);
720 tiledResult.allocN32Pixels(width, height);
721 SkCanvas tiledCanvas(tiledResult);
722 SkCanvas untiledCanvas(untiledResult);
senorblanco@chromium.orgd4db6572014-05-07 20:00:04 +0000723 int tileSize = 8;
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +0000724
senorblanco@chromium.orgd4db6572014-05-07 20:00:04 +0000725 for (int scale = 1; scale <= 2; ++scale) {
senorblanco297f7ce2016-03-23 13:44:26 -0700726 for (int i = 0; i < filters.count(); ++i) {
senorblanco@chromium.orgd4db6572014-05-07 20:00:04 +0000727 tiledCanvas.clear(0);
728 untiledCanvas.clear(0);
729 SkPaint paint;
Mike Reed5e257172016-11-01 11:22:05 -0400730 paint.setImageFilter(sk_ref_sp(filters.getFilter(i)));
senorblanco@chromium.orgd4db6572014-05-07 20:00:04 +0000731 paint.setTextSize(SkIntToScalar(height));
732 paint.setColor(SK_ColorWHITE);
733 SkString str;
734 const char* text = "ABC";
735 SkScalar ypos = SkIntToScalar(height);
736 untiledCanvas.save();
737 untiledCanvas.scale(SkIntToScalar(scale), SkIntToScalar(scale));
Cary Clark2a475ea2017-04-28 15:35:12 -0400738 untiledCanvas.drawString(text, 0, ypos, paint);
senorblanco@chromium.orgd4db6572014-05-07 20:00:04 +0000739 untiledCanvas.restore();
740 for (int y = 0; y < height; y += tileSize) {
741 for (int x = 0; x < width; x += tileSize) {
742 tiledCanvas.save();
743 tiledCanvas.clipRect(SkRect::Make(SkIRect::MakeXYWH(x, y, tileSize, tileSize)));
744 tiledCanvas.scale(SkIntToScalar(scale), SkIntToScalar(scale));
Cary Clark2a475ea2017-04-28 15:35:12 -0400745 tiledCanvas.drawString(text, 0, ypos, paint);
senorblanco@chromium.orgd4db6572014-05-07 20:00:04 +0000746 tiledCanvas.restore();
747 }
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +0000748 }
senorblanco@chromium.orgd4db6572014-05-07 20:00:04 +0000749 untiledCanvas.flush();
750 tiledCanvas.flush();
751 for (int y = 0; y < height; y++) {
752 int diffs = memcmp(untiledResult.getAddr32(0, y), tiledResult.getAddr32(0, y), untiledResult.rowBytes());
senorblanco297f7ce2016-03-23 13:44:26 -0700753 REPORTER_ASSERT_MESSAGE(reporter, !diffs, filters.getName(i));
senorblanco@chromium.orgd4db6572014-05-07 20:00:04 +0000754 if (diffs) {
755 break;
756 }
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +0000757 }
758 }
759 }
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +0000760}
761
mtklein3f3b3d02014-12-01 11:47:08 -0800762static void draw_saveLayer_picture(int width, int height, int tileSize,
robertphillipsa8d7f0b2014-08-29 08:03:56 -0700763 SkBBHFactory* factory, SkBitmap* result) {
mtkleind910f542014-08-22 09:06:34 -0700764
765 SkMatrix matrix;
766 matrix.setTranslate(SkIntToScalar(50), 0);
767
Mike Reed7d954ad2016-10-28 15:42:34 -0400768 sk_sp<SkColorFilter> cf(SkColorFilter::MakeModeFilter(SK_ColorWHITE, SkBlendMode::kSrc));
robertphillips5605b562016-04-05 11:50:42 -0700769 sk_sp<SkImageFilter> cfif(SkColorFilterImageFilter::Make(std::move(cf), nullptr));
robertphillipsae8c9332016-04-05 15:09:00 -0700770 sk_sp<SkImageFilter> imageFilter(SkImageFilter::MakeMatrixFilter(matrix,
771 kNone_SkFilterQuality,
772 std::move(cfif)));
mtkleind910f542014-08-22 09:06:34 -0700773
774 SkPaint paint;
robertphillips5605b562016-04-05 11:50:42 -0700775 paint.setImageFilter(std::move(imageFilter));
mtkleind910f542014-08-22 09:06:34 -0700776 SkPictureRecorder recorder;
777 SkRect bounds = SkRect::Make(SkIRect::MakeXYWH(0, 0, 50, 50));
mtklein3f3b3d02014-12-01 11:47:08 -0800778 SkCanvas* recordingCanvas = recorder.beginRecording(SkIntToScalar(width),
779 SkIntToScalar(height),
robertphillipsa8d7f0b2014-08-29 08:03:56 -0700780 factory, 0);
mtkleind910f542014-08-22 09:06:34 -0700781 recordingCanvas->translate(-55, 0);
782 recordingCanvas->saveLayer(&bounds, &paint);
783 recordingCanvas->restore();
reedca2622b2016-03-18 07:25:55 -0700784 sk_sp<SkPicture> picture1(recorder.finishRecordingAsPicture());
mtkleind910f542014-08-22 09:06:34 -0700785
786 result->allocN32Pixels(width, height);
787 SkCanvas canvas(*result);
788 canvas.clear(0);
789 canvas.clipRect(SkRect::Make(SkIRect::MakeWH(tileSize, tileSize)));
790 canvas.drawPicture(picture1.get());
791}
792
793DEF_TEST(ImageFilterDrawMatrixBBH, reporter) {
794 // Check that matrix filter when drawn tiled with BBH exactly
795 // matches the same thing drawn without BBH.
796 // Tests pass by not asserting.
797
798 const int width = 200, height = 200;
799 const int tileSize = 100;
800 SkBitmap result1, result2;
801 SkRTreeFactory factory;
802
robertphillipsa8d7f0b2014-08-29 08:03:56 -0700803 draw_saveLayer_picture(width, height, tileSize, &factory, &result1);
halcanary96fcdcc2015-08-27 07:41:13 -0700804 draw_saveLayer_picture(width, height, tileSize, nullptr, &result2);
mtkleind910f542014-08-22 09:06:34 -0700805
806 for (int y = 0; y < height; y++) {
807 int diffs = memcmp(result1.getAddr32(0, y), result2.getAddr32(0, y), result1.rowBytes());
808 REPORTER_ASSERT(reporter, !diffs);
809 if (diffs) {
810 break;
811 }
812 }
813}
814
robertphillips6e7025a2016-04-04 04:31:25 -0700815static sk_sp<SkImageFilter> make_blur(sk_sp<SkImageFilter> input) {
816 return SkBlurImageFilter::Make(SK_Scalar1, SK_Scalar1, std::move(input));
senorblanco1150a6d2014-08-25 12:46:58 -0700817}
818
robertphillips6e7025a2016-04-04 04:31:25 -0700819static sk_sp<SkImageFilter> make_drop_shadow(sk_sp<SkImageFilter> input) {
robertphillipsc4169122016-04-06 08:40:59 -0700820 return SkDropShadowImageFilter::Make(
senorblanco1150a6d2014-08-25 12:46:58 -0700821 SkIntToScalar(100), SkIntToScalar(100),
822 SkIntToScalar(10), SkIntToScalar(10),
sugoi234f0362014-10-23 13:59:52 -0700823 SK_ColorBLUE, SkDropShadowImageFilter::kDrawShadowAndForeground_ShadowMode,
robertphillipsc4169122016-04-06 08:40:59 -0700824 std::move(input));
senorblanco1150a6d2014-08-25 12:46:58 -0700825}
826
827DEF_TEST(ImageFilterBlurThenShadowBounds, reporter) {
robertphillips6e7025a2016-04-04 04:31:25 -0700828 sk_sp<SkImageFilter> filter1(make_blur(nullptr));
829 sk_sp<SkImageFilter> filter2(make_drop_shadow(std::move(filter1)));
senorblanco1150a6d2014-08-25 12:46:58 -0700830
831 SkIRect bounds = SkIRect::MakeXYWH(0, 0, 100, 100);
832 SkIRect expectedBounds = SkIRect::MakeXYWH(-133, -133, 236, 236);
senorblancoe5e79842016-03-21 14:51:59 -0700833 bounds = filter2->filterBounds(bounds, SkMatrix::I());
senorblanco1150a6d2014-08-25 12:46:58 -0700834
835 REPORTER_ASSERT(reporter, bounds == expectedBounds);
836}
837
838DEF_TEST(ImageFilterShadowThenBlurBounds, reporter) {
robertphillips6e7025a2016-04-04 04:31:25 -0700839 sk_sp<SkImageFilter> filter1(make_drop_shadow(nullptr));
840 sk_sp<SkImageFilter> filter2(make_blur(std::move(filter1)));
senorblanco1150a6d2014-08-25 12:46:58 -0700841
842 SkIRect bounds = SkIRect::MakeXYWH(0, 0, 100, 100);
843 SkIRect expectedBounds = SkIRect::MakeXYWH(-133, -133, 236, 236);
senorblancoe5e79842016-03-21 14:51:59 -0700844 bounds = filter2->filterBounds(bounds, SkMatrix::I());
senorblanco1150a6d2014-08-25 12:46:58 -0700845
846 REPORTER_ASSERT(reporter, bounds == expectedBounds);
847}
848
849DEF_TEST(ImageFilterDilateThenBlurBounds, reporter) {
robertphillipsfc11b0a2016-04-05 09:09:36 -0700850 sk_sp<SkImageFilter> filter1(SkDilateImageFilter::Make(2, 2, nullptr));
robertphillips6e7025a2016-04-04 04:31:25 -0700851 sk_sp<SkImageFilter> filter2(make_drop_shadow(std::move(filter1)));
senorblanco1150a6d2014-08-25 12:46:58 -0700852
853 SkIRect bounds = SkIRect::MakeXYWH(0, 0, 100, 100);
854 SkIRect expectedBounds = SkIRect::MakeXYWH(-132, -132, 234, 234);
senorblancoe5e79842016-03-21 14:51:59 -0700855 bounds = filter2->filterBounds(bounds, SkMatrix::I());
senorblanco1150a6d2014-08-25 12:46:58 -0700856
857 REPORTER_ASSERT(reporter, bounds == expectedBounds);
858}
859
jbroman203a9932016-07-11 14:07:59 -0700860DEF_TEST(ImageFilterScaledBlurRadius, reporter) {
861 // Each blur should spread 3*sigma, so 3 for the blur and 30 for the shadow
862 // (before the CTM). Bounds should be computed correctly in the presence of
863 // a (possibly negative) scale.
864 sk_sp<SkImageFilter> blur(make_blur(nullptr));
865 sk_sp<SkImageFilter> dropShadow(make_drop_shadow(nullptr));
866 {
867 // Uniform scale by 2.
868 SkMatrix scaleMatrix;
869 scaleMatrix.setScale(2, 2);
870 SkIRect bounds = SkIRect::MakeLTRB(0, 0, 200, 200);
871
872 SkIRect expectedBlurBounds = SkIRect::MakeLTRB(-6, -6, 206, 206);
873 SkIRect blurBounds = blur->filterBounds(
874 bounds, scaleMatrix, SkImageFilter::kForward_MapDirection);
875 REPORTER_ASSERT(reporter, blurBounds == expectedBlurBounds);
876 SkIRect reverseBlurBounds = blur->filterBounds(
877 bounds, scaleMatrix, SkImageFilter::kReverse_MapDirection);
878 REPORTER_ASSERT(reporter, reverseBlurBounds == expectedBlurBounds);
879
880 SkIRect expectedShadowBounds = SkIRect::MakeLTRB(0, 0, 460, 460);
881 SkIRect shadowBounds = dropShadow->filterBounds(
882 bounds, scaleMatrix, SkImageFilter::kForward_MapDirection);
883 REPORTER_ASSERT(reporter, shadowBounds == expectedShadowBounds);
884 SkIRect expectedReverseShadowBounds =
885 SkIRect::MakeLTRB(-260, -260, 200, 200);
886 SkIRect reverseShadowBounds = dropShadow->filterBounds(
887 bounds, scaleMatrix, SkImageFilter::kReverse_MapDirection);
888 REPORTER_ASSERT(reporter,
889 reverseShadowBounds == expectedReverseShadowBounds);
890 }
891 {
892 // Vertical flip.
893 SkMatrix scaleMatrix;
894 scaleMatrix.setScale(1, -1);
895 SkIRect bounds = SkIRect::MakeLTRB(0, -100, 100, 0);
896
897 SkIRect expectedBlurBounds = SkIRect::MakeLTRB(-3, -103, 103, 3);
898 SkIRect blurBounds = blur->filterBounds(
899 bounds, scaleMatrix, SkImageFilter::kForward_MapDirection);
900 REPORTER_ASSERT(reporter, blurBounds == expectedBlurBounds);
901 SkIRect reverseBlurBounds = blur->filterBounds(
902 bounds, scaleMatrix, SkImageFilter::kReverse_MapDirection);
903 REPORTER_ASSERT(reporter, reverseBlurBounds == expectedBlurBounds);
904
905 SkIRect expectedShadowBounds = SkIRect::MakeLTRB(0, -230, 230, 0);
906 SkIRect shadowBounds = dropShadow->filterBounds(
907 bounds, scaleMatrix, SkImageFilter::kForward_MapDirection);
908 REPORTER_ASSERT(reporter, shadowBounds == expectedShadowBounds);
909 SkIRect expectedReverseShadowBounds =
910 SkIRect::MakeLTRB(-130, -100, 100, 130);
911 SkIRect reverseShadowBounds = dropShadow->filterBounds(
912 bounds, scaleMatrix, SkImageFilter::kReverse_MapDirection);
913 REPORTER_ASSERT(reporter,
914 reverseShadowBounds == expectedReverseShadowBounds);
915 }
916}
917
ajuma5788faa2015-02-13 09:05:47 -0800918DEF_TEST(ImageFilterComposedBlurFastBounds, reporter) {
robertphillips6e7025a2016-04-04 04:31:25 -0700919 sk_sp<SkImageFilter> filter1(make_blur(nullptr));
920 sk_sp<SkImageFilter> filter2(make_blur(nullptr));
robertphillips491fb172016-03-30 12:32:58 -0700921 sk_sp<SkImageFilter> composedFilter(SkComposeImageFilter::Make(std::move(filter1),
922 std::move(filter2)));
ajuma5788faa2015-02-13 09:05:47 -0800923
924 SkRect boundsSrc = SkRect::MakeWH(SkIntToScalar(100), SkIntToScalar(100));
925 SkRect expectedBounds = SkRect::MakeXYWH(
926 SkIntToScalar(-6), SkIntToScalar(-6), SkIntToScalar(112), SkIntToScalar(112));
senorblancoe5e79842016-03-21 14:51:59 -0700927 SkRect boundsDst = composedFilter->computeFastBounds(boundsSrc);
ajuma5788faa2015-02-13 09:05:47 -0800928
929 REPORTER_ASSERT(reporter, boundsDst == expectedBounds);
930}
931
jbroman0e3129d2016-03-17 12:24:23 -0700932DEF_TEST(ImageFilterUnionBounds, reporter) {
robertphillips51a315e2016-03-31 09:05:49 -0700933 sk_sp<SkImageFilter> offset(SkOffsetImageFilter::Make(50, 0, nullptr));
jbroman0e3129d2016-03-17 12:24:23 -0700934 // Regardless of which order they appear in, the image filter bounds should
935 // be combined correctly.
936 {
reed374772b2016-10-05 17:33:02 -0700937 sk_sp<SkImageFilter> composite(SkXfermodeImageFilter::Make(SkBlendMode::kSrcOver, offset));
jbroman0e3129d2016-03-17 12:24:23 -0700938 SkRect bounds = SkRect::MakeWH(100, 100);
939 // Intentionally aliasing here, as that's what the real callers do.
senorblancoe5e79842016-03-21 14:51:59 -0700940 bounds = composite->computeFastBounds(bounds);
jbroman0e3129d2016-03-17 12:24:23 -0700941 REPORTER_ASSERT(reporter, bounds == SkRect::MakeWH(150, 100));
942 }
943 {
reed374772b2016-10-05 17:33:02 -0700944 sk_sp<SkImageFilter> composite(SkXfermodeImageFilter::Make(SkBlendMode::kSrcOver, nullptr,
robertphillips8c0326d2016-04-05 12:48:34 -0700945 offset, nullptr));
jbroman0e3129d2016-03-17 12:24:23 -0700946 SkRect bounds = SkRect::MakeWH(100, 100);
947 // Intentionally aliasing here, as that's what the real callers do.
senorblancoe5e79842016-03-21 14:51:59 -0700948 bounds = composite->computeFastBounds(bounds);
jbroman0e3129d2016-03-17 12:24:23 -0700949 REPORTER_ASSERT(reporter, bounds == SkRect::MakeWH(150, 100));
950 }
951}
952
robertphillips3e302272016-04-20 11:48:36 -0700953static void test_imagefilter_merge_result_size(skiatest::Reporter* reporter, GrContext* context) {
senorblanco4a243982015-11-25 07:06:55 -0800954 SkBitmap greenBM;
955 greenBM.allocN32Pixels(20, 20);
956 greenBM.eraseColor(SK_ColorGREEN);
reed9ce9d672016-03-17 10:51:11 -0700957 sk_sp<SkImage> greenImage(SkImage::MakeFromBitmap(greenBM));
robertphillips549c8992016-04-01 09:28:51 -0700958 sk_sp<SkImageFilter> source(SkImageSource::Make(std::move(greenImage)));
Mike Reed0bdaf052017-06-18 23:35:57 -0400959 sk_sp<SkImageFilter> merge(SkMergeImageFilter::Make(source, source));
senorblanco4a243982015-11-25 07:06:55 -0800960
robertphillips3e302272016-04-20 11:48:36 -0700961 sk_sp<SkSpecialImage> srcImg(create_empty_special_image(context, 1));
robertphillips4418dba2016-03-07 12:45:14 -0800962
brianosman2a75e5d2016-09-22 07:15:37 -0700963 SkImageFilter::OutputProperties noColorSpace(nullptr);
964 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeXYWH(0, 0, 100, 100), nullptr,
965 noColorSpace);
senorblanco4a243982015-11-25 07:06:55 -0800966 SkIPoint offset;
robertphillips4418dba2016-03-07 12:45:14 -0800967
robertphillips2302de92016-03-24 07:26:32 -0700968 sk_sp<SkSpecialImage> resultImg(merge->filterImage(srcImg.get(), ctx, &offset));
robertphillips4418dba2016-03-07 12:45:14 -0800969 REPORTER_ASSERT(reporter, resultImg);
970
971 REPORTER_ASSERT(reporter, resultImg->width() == 20 && resultImg->height() == 20);
senorblanco4a243982015-11-25 07:06:55 -0800972}
973
robertphillips4418dba2016-03-07 12:45:14 -0800974DEF_TEST(ImageFilterMergeResultSize, reporter) {
robertphillips3e302272016-04-20 11:48:36 -0700975 test_imagefilter_merge_result_size(reporter, nullptr);
robertphillips4418dba2016-03-07 12:45:14 -0800976}
977
978#if SK_SUPPORT_GPU
egdanielab527a52016-06-28 08:07:26 -0700979DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterMergeResultSize_Gpu, reporter, ctxInfo) {
bsalomon8b7451a2016-05-11 06:33:06 -0700980 test_imagefilter_merge_result_size(reporter, ctxInfo.grContext());
robertphillips4418dba2016-03-07 12:45:14 -0800981}
982#endif
983
robertphillipsa8d7f0b2014-08-29 08:03:56 -0700984static void draw_blurred_rect(SkCanvas* canvas) {
senorblanco837f5322014-07-14 10:19:54 -0700985 SkPaint filterPaint;
986 filterPaint.setColor(SK_ColorWHITE);
robertphillips6e7025a2016-04-04 04:31:25 -0700987 filterPaint.setImageFilter(SkBlurImageFilter::Make(SkIntToScalar(8), 0, nullptr));
halcanary96fcdcc2015-08-27 07:41:13 -0700988 canvas->saveLayer(nullptr, &filterPaint);
senorblanco837f5322014-07-14 10:19:54 -0700989 SkPaint whitePaint;
990 whitePaint.setColor(SK_ColorWHITE);
991 canvas->drawRect(SkRect::Make(SkIRect::MakeWH(4, 4)), whitePaint);
992 canvas->restore();
993}
994
robertphillipsa8d7f0b2014-08-29 08:03:56 -0700995static void draw_picture_clipped(SkCanvas* canvas, const SkRect& clipRect, const SkPicture* picture) {
senorblanco837f5322014-07-14 10:19:54 -0700996 canvas->save();
997 canvas->clipRect(clipRect);
998 canvas->drawPicture(picture);
999 canvas->restore();
1000}
1001
1002DEF_TEST(ImageFilterDrawTiledBlurRTree, reporter) {
1003 // Check that the blur filter when recorded with RTree acceleration,
1004 // and drawn tiled (with subsequent clip rects) exactly
1005 // matches the same filter drawn with without RTree acceleration.
1006 // This tests that the "bleed" from the blur into the otherwise-blank
1007 // tiles is correctly rendered.
1008 // Tests pass by not asserting.
1009
1010 int width = 16, height = 8;
1011 SkBitmap result1, result2;
1012 result1.allocN32Pixels(width, height);
1013 result2.allocN32Pixels(width, height);
1014 SkCanvas canvas1(result1);
1015 SkCanvas canvas2(result2);
1016 int tileSize = 8;
1017
1018 canvas1.clear(0);
1019 canvas2.clear(0);
1020
1021 SkRTreeFactory factory;
1022
1023 SkPictureRecorder recorder1, recorder2;
1024 // The only difference between these two pictures is that one has RTree aceleration.
mtklein3f3b3d02014-12-01 11:47:08 -08001025 SkCanvas* recordingCanvas1 = recorder1.beginRecording(SkIntToScalar(width),
1026 SkIntToScalar(height),
halcanary96fcdcc2015-08-27 07:41:13 -07001027 nullptr, 0);
mtklein3f3b3d02014-12-01 11:47:08 -08001028 SkCanvas* recordingCanvas2 = recorder2.beginRecording(SkIntToScalar(width),
1029 SkIntToScalar(height),
robertphillipsa8d7f0b2014-08-29 08:03:56 -07001030 &factory, 0);
1031 draw_blurred_rect(recordingCanvas1);
1032 draw_blurred_rect(recordingCanvas2);
reedca2622b2016-03-18 07:25:55 -07001033 sk_sp<SkPicture> picture1(recorder1.finishRecordingAsPicture());
1034 sk_sp<SkPicture> picture2(recorder2.finishRecordingAsPicture());
senorblanco837f5322014-07-14 10:19:54 -07001035 for (int y = 0; y < height; y += tileSize) {
1036 for (int x = 0; x < width; x += tileSize) {
1037 SkRect tileRect = SkRect::Make(SkIRect::MakeXYWH(x, y, tileSize, tileSize));
reedca2622b2016-03-18 07:25:55 -07001038 draw_picture_clipped(&canvas1, tileRect, picture1.get());
1039 draw_picture_clipped(&canvas2, tileRect, picture2.get());
senorblanco837f5322014-07-14 10:19:54 -07001040 }
1041 }
1042 for (int y = 0; y < height; y++) {
1043 int diffs = memcmp(result1.getAddr32(0, y), result2.getAddr32(0, y), result1.rowBytes());
1044 REPORTER_ASSERT(reporter, !diffs);
1045 if (diffs) {
1046 break;
1047 }
1048 }
1049}
1050
senorblanco@chromium.org91957432014-05-01 14:03:41 +00001051DEF_TEST(ImageFilterMatrixConvolution, reporter) {
1052 // Check that a 1x3 filter does not cause a spurious assert.
1053 SkScalar kernel[3] = {
1054 SkIntToScalar( 1), SkIntToScalar( 1), SkIntToScalar( 1),
1055 };
1056 SkISize kernelSize = SkISize::Make(1, 3);
1057 SkScalar gain = SK_Scalar1, bias = 0;
1058 SkIPoint kernelOffset = SkIPoint::Make(0, 0);
1059
robertphillipsef6a47b2016-04-08 08:01:20 -07001060 sk_sp<SkImageFilter> filter(SkMatrixConvolutionImageFilter::Make(
1061 kernelSize, kernel,
1062 gain, bias, kernelOffset,
1063 SkMatrixConvolutionImageFilter::kRepeat_TileMode,
1064 false, nullptr));
senorblanco@chromium.org91957432014-05-01 14:03:41 +00001065
1066 SkBitmap result;
1067 int width = 16, height = 16;
1068 result.allocN32Pixels(width, height);
1069 SkCanvas canvas(result);
1070 canvas.clear(0);
1071
1072 SkPaint paint;
robertphillipsef6a47b2016-04-08 08:01:20 -07001073 paint.setImageFilter(std::move(filter));
senorblanco@chromium.org91957432014-05-01 14:03:41 +00001074 SkRect rect = SkRect::Make(SkIRect::MakeWH(width, height));
1075 canvas.drawRect(rect, paint);
1076}
1077
senorblanco@chromium.org8c7372b2014-05-02 19:13:11 +00001078DEF_TEST(ImageFilterMatrixConvolutionBorder, reporter) {
1079 // Check that a filter with borders outside the target bounds
1080 // does not crash.
1081 SkScalar kernel[3] = {
1082 0, 0, 0,
1083 };
1084 SkISize kernelSize = SkISize::Make(3, 1);
1085 SkScalar gain = SK_Scalar1, bias = 0;
1086 SkIPoint kernelOffset = SkIPoint::Make(2, 0);
1087
robertphillipsef6a47b2016-04-08 08:01:20 -07001088 sk_sp<SkImageFilter> filter(SkMatrixConvolutionImageFilter::Make(
1089 kernelSize, kernel, gain, bias, kernelOffset,
1090 SkMatrixConvolutionImageFilter::kClamp_TileMode,
1091 true, nullptr));
senorblanco@chromium.org8c7372b2014-05-02 19:13:11 +00001092
1093 SkBitmap result;
1094
1095 int width = 10, height = 10;
1096 result.allocN32Pixels(width, height);
1097 SkCanvas canvas(result);
1098 canvas.clear(0);
1099
1100 SkPaint filterPaint;
robertphillipsef6a47b2016-04-08 08:01:20 -07001101 filterPaint.setImageFilter(std::move(filter));
senorblanco@chromium.org8c7372b2014-05-02 19:13:11 +00001102 SkRect bounds = SkRect::MakeWH(1, 10);
1103 SkRect rect = SkRect::Make(SkIRect::MakeWH(width, height));
1104 SkPaint rectPaint;
1105 canvas.saveLayer(&bounds, &filterPaint);
1106 canvas.drawRect(rect, rectPaint);
1107 canvas.restore();
1108}
1109
robertphillips3e302272016-04-20 11:48:36 -07001110static void test_big_kernel(skiatest::Reporter* reporter, GrContext* context) {
robertphillipsdada4dd2016-04-13 04:54:36 -07001111 // Check that a kernel that is too big for the GPU still works
1112 SkScalar identityKernel[49] = {
1113 0, 0, 0, 0, 0, 0, 0,
1114 0, 0, 0, 0, 0, 0, 0,
1115 0, 0, 0, 0, 0, 0, 0,
1116 0, 0, 0, 1, 0, 0, 0,
1117 0, 0, 0, 0, 0, 0, 0,
1118 0, 0, 0, 0, 0, 0, 0,
1119 0, 0, 0, 0, 0, 0, 0
1120 };
1121 SkISize kernelSize = SkISize::Make(7, 7);
1122 SkScalar gain = SK_Scalar1, bias = 0;
1123 SkIPoint kernelOffset = SkIPoint::Make(0, 0);
1124
1125 sk_sp<SkImageFilter> filter(SkMatrixConvolutionImageFilter::Make(
1126 kernelSize, identityKernel, gain, bias, kernelOffset,
1127 SkMatrixConvolutionImageFilter::kClamp_TileMode,
1128 true, nullptr));
1129
robertphillips3e302272016-04-20 11:48:36 -07001130 sk_sp<SkSpecialImage> srcImg(create_empty_special_image(context, 100));
robertphillipsdada4dd2016-04-13 04:54:36 -07001131 SkASSERT(srcImg);
1132
1133 SkIPoint offset;
brianosman2a75e5d2016-09-22 07:15:37 -07001134 SkImageFilter::OutputProperties noColorSpace(nullptr);
1135 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeWH(100, 100), nullptr, noColorSpace);
robertphillipsdada4dd2016-04-13 04:54:36 -07001136 sk_sp<SkSpecialImage> resultImg(filter->filterImage(srcImg.get(), ctx, &offset));
1137 REPORTER_ASSERT(reporter, resultImg);
1138 REPORTER_ASSERT(reporter, SkToBool(context) == resultImg->isTextureBacked());
1139 REPORTER_ASSERT(reporter, resultImg->width() == 100 && resultImg->height() == 100);
1140 REPORTER_ASSERT(reporter, offset.fX == 0 && offset.fY == 0);
1141}
1142
1143DEF_TEST(ImageFilterMatrixConvolutionBigKernel, reporter) {
robertphillips3e302272016-04-20 11:48:36 -07001144 test_big_kernel(reporter, nullptr);
robertphillipsdada4dd2016-04-13 04:54:36 -07001145}
1146
1147#if SK_SUPPORT_GPU
egdanielab527a52016-06-28 08:07:26 -07001148DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterMatrixConvolutionBigKernel_Gpu,
1149 reporter, ctxInfo) {
bsalomon8b7451a2016-05-11 06:33:06 -07001150 test_big_kernel(reporter, ctxInfo.grContext());
robertphillipsdada4dd2016-04-13 04:54:36 -07001151}
1152#endif
1153
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +00001154DEF_TEST(ImageFilterCropRect, reporter) {
robertphillips3e302272016-04-20 11:48:36 -07001155 test_crop_rects(reporter, nullptr);
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +00001156}
1157
robertphillips4418dba2016-03-07 12:45:14 -08001158#if SK_SUPPORT_GPU
bsalomon68d91342016-04-12 09:59:58 -07001159DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterCropRect_Gpu, reporter, ctxInfo) {
bsalomon8b7451a2016-05-11 06:33:06 -07001160 test_crop_rects(reporter, ctxInfo.grContext());
robertphillips4418dba2016-03-07 12:45:14 -08001161}
1162#endif
1163
tfarina9ea53f92014-06-24 06:50:39 -07001164DEF_TEST(ImageFilterMatrix, reporter) {
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +00001165 SkBitmap temp;
mike@reedtribe.orgdeee4962014-02-13 14:41:43 +00001166 temp.allocN32Pixels(100, 100);
robertphillips9a53fd72015-06-22 09:46:59 -07001167 SkCanvas canvas(temp);
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +00001168 canvas.scale(SkIntToScalar(2), SkIntToScalar(2));
1169
1170 SkMatrix expectedMatrix = canvas.getTotalMatrix();
1171
commit-bot@chromium.org5fb2ce32014-04-17 23:35:06 +00001172 SkRTreeFactory factory;
1173 SkPictureRecorder recorder;
1174 SkCanvas* recordingCanvas = recorder.beginRecording(100, 100, &factory, 0);
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +00001175
1176 SkPaint paint;
robertphillips43c2ad42016-04-04 05:05:11 -07001177 paint.setImageFilter(MatrixTestImageFilter::Make(reporter, expectedMatrix));
halcanary96fcdcc2015-08-27 07:41:13 -07001178 recordingCanvas->saveLayer(nullptr, &paint);
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +00001179 SkPaint solidPaint;
1180 solidPaint.setColor(0xFFFFFFFF);
1181 recordingCanvas->save();
1182 recordingCanvas->scale(SkIntToScalar(10), SkIntToScalar(10));
1183 recordingCanvas->drawRect(SkRect::Make(SkIRect::MakeWH(100, 100)), solidPaint);
1184 recordingCanvas->restore(); // scale
1185 recordingCanvas->restore(); // saveLayer
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +00001186
reedca2622b2016-03-18 07:25:55 -07001187 canvas.drawPicture(recorder.finishRecordingAsPicture());
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +00001188}
1189
senorblanco3d822c22014-07-30 14:49:31 -07001190DEF_TEST(ImageFilterCrossProcessPictureImageFilter, reporter) {
senorblanco@chromium.org97f5fc62014-05-30 20:50:56 +00001191 SkRTreeFactory factory;
1192 SkPictureRecorder recorder;
1193 SkCanvas* recordingCanvas = recorder.beginRecording(1, 1, &factory, 0);
1194
1195 // Create an SkPicture which simply draws a green 1x1 rectangle.
1196 SkPaint greenPaint;
1197 greenPaint.setColor(SK_ColorGREEN);
1198 recordingCanvas->drawRect(SkRect::Make(SkIRect::MakeWH(1, 1)), greenPaint);
reedca2622b2016-03-18 07:25:55 -07001199 sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture());
senorblanco@chromium.org97f5fc62014-05-30 20:50:56 +00001200
1201 // Wrap that SkPicture in an SkPictureImageFilter.
robertphillips5ff17b12016-03-28 13:13:42 -07001202 sk_sp<SkImageFilter> imageFilter(SkPictureImageFilter::Make(picture));
senorblanco@chromium.org97f5fc62014-05-30 20:50:56 +00001203
1204 // Check that SkPictureImageFilter successfully serializes its contained
1205 // SkPicture when not in cross-process mode.
1206 SkPaint paint;
robertphillips5ff17b12016-03-28 13:13:42 -07001207 paint.setImageFilter(imageFilter);
senorblanco@chromium.org97f5fc62014-05-30 20:50:56 +00001208 SkPictureRecorder outerRecorder;
1209 SkCanvas* outerCanvas = outerRecorder.beginRecording(1, 1, &factory, 0);
1210 SkPaint redPaintWithFilter;
1211 redPaintWithFilter.setColor(SK_ColorRED);
robertphillips5ff17b12016-03-28 13:13:42 -07001212 redPaintWithFilter.setImageFilter(imageFilter);
senorblanco@chromium.org97f5fc62014-05-30 20:50:56 +00001213 outerCanvas->drawRect(SkRect::Make(SkIRect::MakeWH(1, 1)), redPaintWithFilter);
reedca2622b2016-03-18 07:25:55 -07001214 sk_sp<SkPicture> outerPicture(outerRecorder.finishRecordingAsPicture());
senorblanco@chromium.org97f5fc62014-05-30 20:50:56 +00001215
1216 SkBitmap bitmap;
1217 bitmap.allocN32Pixels(1, 1);
robertphillips9a53fd72015-06-22 09:46:59 -07001218 SkCanvas canvas(bitmap);
senorblanco@chromium.org97f5fc62014-05-30 20:50:56 +00001219
1220 // The result here should be green, since the filter replaces the primitive's red interior.
1221 canvas.clear(0x0);
robertphillips9b14f262014-06-04 05:40:44 -07001222 canvas.drawPicture(outerPicture);
senorblanco@chromium.org97f5fc62014-05-30 20:50:56 +00001223 uint32_t pixel = *bitmap.getAddr32(0, 0);
1224 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1225
1226 // Check that, for now, SkPictureImageFilter does not serialize or
1227 // deserialize its contained picture when the filter is serialized
1228 // cross-process. Do this by "laundering" it through SkValidatingReadBuffer.
robertphillips12fa47d2016-04-08 16:28:09 -07001229 sk_sp<SkData> data(SkValidatingSerializeFlattenable(imageFilter.get()));
Mike Reed5e257172016-11-01 11:22:05 -04001230 sk_sp<SkImageFilter> unflattenedFilter = SkValidatingDeserializeImageFilter(data->data(),
1231 data->size());
senorblanco@chromium.org97f5fc62014-05-30 20:50:56 +00001232
1233 redPaintWithFilter.setImageFilter(unflattenedFilter);
1234 SkPictureRecorder crossProcessRecorder;
1235 SkCanvas* crossProcessCanvas = crossProcessRecorder.beginRecording(1, 1, &factory, 0);
1236 crossProcessCanvas->drawRect(SkRect::Make(SkIRect::MakeWH(1, 1)), redPaintWithFilter);
reedca2622b2016-03-18 07:25:55 -07001237 sk_sp<SkPicture> crossProcessPicture(crossProcessRecorder.finishRecordingAsPicture());
senorblanco@chromium.org97f5fc62014-05-30 20:50:56 +00001238
1239 canvas.clear(0x0);
robertphillips9b14f262014-06-04 05:40:44 -07001240 canvas.drawPicture(crossProcessPicture);
senorblanco@chromium.org97f5fc62014-05-30 20:50:56 +00001241 pixel = *bitmap.getAddr32(0, 0);
hendrikw446ee672015-06-16 09:28:37 -07001242 // If the security precautions are enabled, the result here should not be green, since the
1243 // filter draws nothing.
mtklein2afbe232016-02-07 12:23:10 -08001244 REPORTER_ASSERT(reporter, SkPicture::PictureIOSecurityPrecautionsEnabled()
hendrikw446ee672015-06-16 09:28:37 -07001245 ? pixel != SK_ColorGREEN : pixel == SK_ColorGREEN);
senorblanco@chromium.org97f5fc62014-05-30 20:50:56 +00001246}
1247
robertphillips3e302272016-04-20 11:48:36 -07001248static void test_clipped_picture_imagefilter(skiatest::Reporter* reporter, GrContext* context) {
reedca2622b2016-03-18 07:25:55 -07001249 sk_sp<SkPicture> picture;
senorblanco3d822c22014-07-30 14:49:31 -07001250
robertphillips4418dba2016-03-07 12:45:14 -08001251 {
1252 SkRTreeFactory factory;
1253 SkPictureRecorder recorder;
1254 SkCanvas* recordingCanvas = recorder.beginRecording(1, 1, &factory, 0);
1255
1256 // Create an SkPicture which simply draws a green 1x1 rectangle.
1257 SkPaint greenPaint;
1258 greenPaint.setColor(SK_ColorGREEN);
1259 recordingCanvas->drawRect(SkRect::Make(SkIRect::MakeWH(1, 1)), greenPaint);
reedca2622b2016-03-18 07:25:55 -07001260 picture = recorder.finishRecordingAsPicture();
robertphillips4418dba2016-03-07 12:45:14 -08001261 }
1262
robertphillips3e302272016-04-20 11:48:36 -07001263 sk_sp<SkSpecialImage> srcImg(create_empty_special_image(context, 2));
senorblanco3d822c22014-07-30 14:49:31 -07001264
robertphillips5ff17b12016-03-28 13:13:42 -07001265 sk_sp<SkImageFilter> imageFilter(SkPictureImageFilter::Make(picture));
senorblanco3d822c22014-07-30 14:49:31 -07001266
senorblanco3d822c22014-07-30 14:49:31 -07001267 SkIPoint offset;
brianosman2a75e5d2016-09-22 07:15:37 -07001268 SkImageFilter::OutputProperties noColorSpace(nullptr);
1269 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeXYWH(1, 1, 1, 1), nullptr, noColorSpace);
robertphillips4418dba2016-03-07 12:45:14 -08001270
robertphillips2302de92016-03-24 07:26:32 -07001271 sk_sp<SkSpecialImage> resultImage(imageFilter->filterImage(srcImg.get(), ctx, &offset));
robertphillips4418dba2016-03-07 12:45:14 -08001272 REPORTER_ASSERT(reporter, !resultImage);
senorblanco3d822c22014-07-30 14:49:31 -07001273}
1274
robertphillips4418dba2016-03-07 12:45:14 -08001275DEF_TEST(ImageFilterClippedPictureImageFilter, reporter) {
robertphillips3e302272016-04-20 11:48:36 -07001276 test_clipped_picture_imagefilter(reporter, nullptr);
robertphillips4418dba2016-03-07 12:45:14 -08001277}
1278
1279#if SK_SUPPORT_GPU
bsalomon68d91342016-04-12 09:59:58 -07001280DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterClippedPictureImageFilter_Gpu, reporter, ctxInfo) {
bsalomon8b7451a2016-05-11 06:33:06 -07001281 test_clipped_picture_imagefilter(reporter, ctxInfo.grContext());
robertphillips4418dba2016-03-07 12:45:14 -08001282}
1283#endif
1284
tfarina9ea53f92014-06-24 06:50:39 -07001285DEF_TEST(ImageFilterEmptySaveLayer, reporter) {
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001286 // Even when there's an empty saveLayer()/restore(), ensure that an image
1287 // filter or color filter which affects transparent black still draws.
1288
1289 SkBitmap bitmap;
1290 bitmap.allocN32Pixels(10, 10);
robertphillips9a53fd72015-06-22 09:46:59 -07001291 SkCanvas canvas(bitmap);
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001292
1293 SkRTreeFactory factory;
1294 SkPictureRecorder recorder;
1295
robertphillips5605b562016-04-05 11:50:42 -07001296 sk_sp<SkColorFilter> green(SkColorFilter::MakeModeFilter(SK_ColorGREEN,
Mike Reed7d954ad2016-10-28 15:42:34 -04001297 SkBlendMode::kSrc));
robertphillips5605b562016-04-05 11:50:42 -07001298 sk_sp<SkImageFilter> imageFilter(SkColorFilterImageFilter::Make(green, nullptr));
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001299 SkPaint imageFilterPaint;
robertphillips5605b562016-04-05 11:50:42 -07001300 imageFilterPaint.setImageFilter(std::move(imageFilter));
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001301 SkPaint colorFilterPaint;
reedd053ce92016-03-22 10:17:23 -07001302 colorFilterPaint.setColorFilter(green);
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001303
1304 SkRect bounds = SkRect::MakeWH(10, 10);
1305
1306 SkCanvas* recordingCanvas = recorder.beginRecording(10, 10, &factory, 0);
1307 recordingCanvas->saveLayer(&bounds, &imageFilterPaint);
1308 recordingCanvas->restore();
reedca2622b2016-03-18 07:25:55 -07001309 sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture());
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001310
1311 canvas.clear(0);
robertphillips9b14f262014-06-04 05:40:44 -07001312 canvas.drawPicture(picture);
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001313 uint32_t pixel = *bitmap.getAddr32(0, 0);
1314 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1315
1316 recordingCanvas = recorder.beginRecording(10, 10, &factory, 0);
halcanary96fcdcc2015-08-27 07:41:13 -07001317 recordingCanvas->saveLayer(nullptr, &imageFilterPaint);
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001318 recordingCanvas->restore();
reedca2622b2016-03-18 07:25:55 -07001319 sk_sp<SkPicture> picture2(recorder.finishRecordingAsPicture());
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001320
1321 canvas.clear(0);
robertphillips9b14f262014-06-04 05:40:44 -07001322 canvas.drawPicture(picture2);
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001323 pixel = *bitmap.getAddr32(0, 0);
1324 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1325
1326 recordingCanvas = recorder.beginRecording(10, 10, &factory, 0);
1327 recordingCanvas->saveLayer(&bounds, &colorFilterPaint);
1328 recordingCanvas->restore();
reedca2622b2016-03-18 07:25:55 -07001329 sk_sp<SkPicture> picture3(recorder.finishRecordingAsPicture());
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001330
1331 canvas.clear(0);
robertphillips9b14f262014-06-04 05:40:44 -07001332 canvas.drawPicture(picture3);
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001333 pixel = *bitmap.getAddr32(0, 0);
1334 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1335}
1336
robertphillips9a53fd72015-06-22 09:46:59 -07001337static void test_huge_blur(SkCanvas* canvas, skiatest::Reporter* reporter) {
senorblanco@chromium.org09843fd2014-03-24 20:50:59 +00001338 SkBitmap bitmap;
1339 bitmap.allocN32Pixels(100, 100);
1340 bitmap.eraseARGB(0, 0, 0, 0);
1341
1342 // Check that a blur with an insane radius does not crash or assert.
senorblanco@chromium.org09843fd2014-03-24 20:50:59 +00001343 SkPaint paint;
robertphillips6e7025a2016-04-04 04:31:25 -07001344 paint.setImageFilter(SkBlurImageFilter::Make(SkIntToScalar(1<<30),
1345 SkIntToScalar(1<<30),
1346 nullptr));
reedda420b92015-12-16 08:38:15 -08001347 canvas->drawBitmap(bitmap, 0, 0, &paint);
senorblanco@chromium.org09843fd2014-03-24 20:50:59 +00001348}
1349
1350DEF_TEST(HugeBlurImageFilter, reporter) {
1351 SkBitmap temp;
1352 temp.allocN32Pixels(100, 100);
robertphillips9a53fd72015-06-22 09:46:59 -07001353 SkCanvas canvas(temp);
1354 test_huge_blur(&canvas, reporter);
senorblanco@chromium.org09843fd2014-03-24 20:50:59 +00001355}
1356
senorblanco21a465d2016-04-11 11:58:39 -07001357DEF_TEST(ImageFilterMatrixConvolutionSanityTest, reporter) {
senorblanco3a495202014-09-29 07:57:20 -07001358 SkScalar kernel[1] = { 0 };
1359 SkScalar gain = SK_Scalar1, bias = 0;
1360 SkIPoint kernelOffset = SkIPoint::Make(1, 1);
1361
halcanary96fcdcc2015-08-27 07:41:13 -07001362 // Check that an enormous (non-allocatable) kernel gives a nullptr filter.
robertphillipsef6a47b2016-04-08 08:01:20 -07001363 sk_sp<SkImageFilter> conv(SkMatrixConvolutionImageFilter::Make(
senorblanco3a495202014-09-29 07:57:20 -07001364 SkISize::Make(1<<30, 1<<30),
1365 kernel,
1366 gain,
1367 bias,
1368 kernelOffset,
1369 SkMatrixConvolutionImageFilter::kRepeat_TileMode,
robertphillipsef6a47b2016-04-08 08:01:20 -07001370 false,
1371 nullptr));
senorblanco3a495202014-09-29 07:57:20 -07001372
halcanary96fcdcc2015-08-27 07:41:13 -07001373 REPORTER_ASSERT(reporter, nullptr == conv.get());
senorblanco3a495202014-09-29 07:57:20 -07001374
halcanary96fcdcc2015-08-27 07:41:13 -07001375 // Check that a nullptr kernel gives a nullptr filter.
robertphillipsef6a47b2016-04-08 08:01:20 -07001376 conv = SkMatrixConvolutionImageFilter::Make(
senorblanco3a495202014-09-29 07:57:20 -07001377 SkISize::Make(1, 1),
halcanary96fcdcc2015-08-27 07:41:13 -07001378 nullptr,
senorblanco3a495202014-09-29 07:57:20 -07001379 gain,
1380 bias,
1381 kernelOffset,
1382 SkMatrixConvolutionImageFilter::kRepeat_TileMode,
robertphillipsef6a47b2016-04-08 08:01:20 -07001383 false,
1384 nullptr);
senorblanco3a495202014-09-29 07:57:20 -07001385
halcanary96fcdcc2015-08-27 07:41:13 -07001386 REPORTER_ASSERT(reporter, nullptr == conv.get());
senorblanco3a495202014-09-29 07:57:20 -07001387
halcanary96fcdcc2015-08-27 07:41:13 -07001388 // Check that a kernel width < 1 gives a nullptr filter.
robertphillipsef6a47b2016-04-08 08:01:20 -07001389 conv = SkMatrixConvolutionImageFilter::Make(
senorblanco3a495202014-09-29 07:57:20 -07001390 SkISize::Make(0, 1),
1391 kernel,
1392 gain,
1393 bias,
1394 kernelOffset,
1395 SkMatrixConvolutionImageFilter::kRepeat_TileMode,
robertphillipsef6a47b2016-04-08 08:01:20 -07001396 false,
1397 nullptr);
senorblanco3a495202014-09-29 07:57:20 -07001398
halcanary96fcdcc2015-08-27 07:41:13 -07001399 REPORTER_ASSERT(reporter, nullptr == conv.get());
senorblanco3a495202014-09-29 07:57:20 -07001400
halcanary96fcdcc2015-08-27 07:41:13 -07001401 // Check that kernel height < 1 gives a nullptr filter.
robertphillipsef6a47b2016-04-08 08:01:20 -07001402 conv = SkMatrixConvolutionImageFilter::Make(
senorblanco3a495202014-09-29 07:57:20 -07001403 SkISize::Make(1, -1),
1404 kernel,
1405 gain,
1406 bias,
1407 kernelOffset,
1408 SkMatrixConvolutionImageFilter::kRepeat_TileMode,
robertphillipsef6a47b2016-04-08 08:01:20 -07001409 false,
1410 nullptr);
senorblanco3a495202014-09-29 07:57:20 -07001411
halcanary96fcdcc2015-08-27 07:41:13 -07001412 REPORTER_ASSERT(reporter, nullptr == conv.get());
senorblanco3a495202014-09-29 07:57:20 -07001413}
1414
robertphillips9a53fd72015-06-22 09:46:59 -07001415static void test_xfermode_cropped_input(SkCanvas* canvas, skiatest::Reporter* reporter) {
1416 canvas->clear(0);
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001417
1418 SkBitmap bitmap;
1419 bitmap.allocN32Pixels(1, 1);
1420 bitmap.eraseARGB(255, 255, 255, 255);
1421
robertphillips5605b562016-04-05 11:50:42 -07001422 sk_sp<SkColorFilter> green(SkColorFilter::MakeModeFilter(SK_ColorGREEN,
Mike Reed7d954ad2016-10-28 15:42:34 -04001423 SkBlendMode::kSrcIn));
robertphillips5605b562016-04-05 11:50:42 -07001424 sk_sp<SkImageFilter> greenFilter(SkColorFilterImageFilter::Make(green, nullptr));
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001425 SkImageFilter::CropRect cropRect(SkRect::MakeEmpty());
robertphillips5605b562016-04-05 11:50:42 -07001426 sk_sp<SkImageFilter> croppedOut(SkColorFilterImageFilter::Make(green, nullptr, &cropRect));
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001427
1428 // Check that an xfermode image filter whose input has been cropped out still draws the other
1429 // input. Also check that drawing with both inputs cropped out doesn't cause a GPU warning.
reed374772b2016-10-05 17:33:02 -07001430 SkBlendMode mode = SkBlendMode::kSrcOver;
robertphillips8c0326d2016-04-05 12:48:34 -07001431 sk_sp<SkImageFilter> xfermodeNoFg(SkXfermodeImageFilter::Make(mode, greenFilter,
1432 croppedOut, nullptr));
1433 sk_sp<SkImageFilter> xfermodeNoBg(SkXfermodeImageFilter::Make(mode, croppedOut,
1434 greenFilter, nullptr));
1435 sk_sp<SkImageFilter> xfermodeNoFgNoBg(SkXfermodeImageFilter::Make(mode, croppedOut,
1436 croppedOut, nullptr));
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001437
1438 SkPaint paint;
robertphillips8c0326d2016-04-05 12:48:34 -07001439 paint.setImageFilter(std::move(xfermodeNoFg));
reedda420b92015-12-16 08:38:15 -08001440 canvas->drawBitmap(bitmap, 0, 0, &paint); // drawSprite
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001441
1442 uint32_t pixel;
kkinnunena9d9a392015-03-06 07:16:00 -08001443 SkImageInfo info = SkImageInfo::Make(1, 1, kBGRA_8888_SkColorType, kUnpremul_SkAlphaType);
robertphillips9a53fd72015-06-22 09:46:59 -07001444 canvas->readPixels(info, &pixel, 4, 0, 0);
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001445 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1446
robertphillips8c0326d2016-04-05 12:48:34 -07001447 paint.setImageFilter(std::move(xfermodeNoBg));
reedda420b92015-12-16 08:38:15 -08001448 canvas->drawBitmap(bitmap, 0, 0, &paint); // drawSprite
robertphillips9a53fd72015-06-22 09:46:59 -07001449 canvas->readPixels(info, &pixel, 4, 0, 0);
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001450 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1451
robertphillips8c0326d2016-04-05 12:48:34 -07001452 paint.setImageFilter(std::move(xfermodeNoFgNoBg));
reedda420b92015-12-16 08:38:15 -08001453 canvas->drawBitmap(bitmap, 0, 0, &paint); // drawSprite
robertphillips9a53fd72015-06-22 09:46:59 -07001454 canvas->readPixels(info, &pixel, 4, 0, 0);
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001455 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1456}
1457
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001458DEF_TEST(ImageFilterNestedSaveLayer, reporter) {
1459 SkBitmap temp;
1460 temp.allocN32Pixels(50, 50);
robertphillips9a53fd72015-06-22 09:46:59 -07001461 SkCanvas canvas(temp);
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001462 canvas.clear(0x0);
1463
1464 SkBitmap bitmap;
1465 bitmap.allocN32Pixels(10, 10);
1466 bitmap.eraseColor(SK_ColorGREEN);
1467
1468 SkMatrix matrix;
1469 matrix.setScale(SkIntToScalar(2), SkIntToScalar(2));
1470 matrix.postTranslate(SkIntToScalar(-20), SkIntToScalar(-20));
robertphillipsae8c9332016-04-05 15:09:00 -07001471 sk_sp<SkImageFilter> matrixFilter(
1472 SkImageFilter::MakeMatrixFilter(matrix, kLow_SkFilterQuality, nullptr));
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001473
1474 // Test that saveLayer() with a filter nested inside another saveLayer() applies the
1475 // correct offset to the filter matrix.
1476 SkRect bounds1 = SkRect::MakeXYWH(10, 10, 30, 30);
halcanary96fcdcc2015-08-27 07:41:13 -07001477 canvas.saveLayer(&bounds1, nullptr);
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001478 SkPaint filterPaint;
robertphillipsae8c9332016-04-05 15:09:00 -07001479 filterPaint.setImageFilter(std::move(matrixFilter));
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001480 SkRect bounds2 = SkRect::MakeXYWH(20, 20, 10, 10);
1481 canvas.saveLayer(&bounds2, &filterPaint);
1482 SkPaint greenPaint;
1483 greenPaint.setColor(SK_ColorGREEN);
1484 canvas.drawRect(bounds2, greenPaint);
1485 canvas.restore();
1486 canvas.restore();
1487 SkPaint strokePaint;
1488 strokePaint.setStyle(SkPaint::kStroke_Style);
1489 strokePaint.setColor(SK_ColorRED);
1490
kkinnunena9d9a392015-03-06 07:16:00 -08001491 SkImageInfo info = SkImageInfo::Make(1, 1, kBGRA_8888_SkColorType, kUnpremul_SkAlphaType);
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001492 uint32_t pixel;
1493 canvas.readPixels(info, &pixel, 4, 25, 25);
1494 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1495
1496 // Test that drawSprite() with a filter nested inside a saveLayer() applies the
1497 // correct offset to the filter matrix.
1498 canvas.clear(0x0);
1499 canvas.readPixels(info, &pixel, 4, 25, 25);
halcanary96fcdcc2015-08-27 07:41:13 -07001500 canvas.saveLayer(&bounds1, nullptr);
reedda420b92015-12-16 08:38:15 -08001501 canvas.drawBitmap(bitmap, 20, 20, &filterPaint); // drawSprite
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001502 canvas.restore();
1503
1504 canvas.readPixels(info, &pixel, 4, 25, 25);
1505 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1506}
1507
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001508DEF_TEST(XfermodeImageFilterCroppedInput, reporter) {
1509 SkBitmap temp;
1510 temp.allocN32Pixels(100, 100);
robertphillips9a53fd72015-06-22 09:46:59 -07001511 SkCanvas canvas(temp);
1512 test_xfermode_cropped_input(&canvas, reporter);
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001513}
senorblanco@chromium.org09843fd2014-03-24 20:50:59 +00001514
robertphillips3e302272016-04-20 11:48:36 -07001515static void test_composed_imagefilter_offset(skiatest::Reporter* reporter, GrContext* context) {
1516 sk_sp<SkSpecialImage> srcImg(create_empty_special_image(context, 100));
ajuma5788faa2015-02-13 09:05:47 -08001517
1518 SkImageFilter::CropRect cropRect(SkRect::MakeXYWH(1, 0, 20, 20));
robertphillips51a315e2016-03-31 09:05:49 -07001519 sk_sp<SkImageFilter> offsetFilter(SkOffsetImageFilter::Make(0, 0, nullptr, &cropRect));
robertphillips6e7025a2016-04-04 04:31:25 -07001520 sk_sp<SkImageFilter> blurFilter(SkBlurImageFilter::Make(SK_Scalar1, SK_Scalar1,
1521 nullptr, &cropRect));
robertphillips491fb172016-03-30 12:32:58 -07001522 sk_sp<SkImageFilter> composedFilter(SkComposeImageFilter::Make(std::move(blurFilter),
1523 std::move(offsetFilter)));
ajuma5788faa2015-02-13 09:05:47 -08001524 SkIPoint offset;
brianosman2a75e5d2016-09-22 07:15:37 -07001525 SkImageFilter::OutputProperties noColorSpace(nullptr);
1526 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeWH(100, 100), nullptr, noColorSpace);
robertphillips4418dba2016-03-07 12:45:14 -08001527
robertphillips2302de92016-03-24 07:26:32 -07001528 sk_sp<SkSpecialImage> resultImg(composedFilter->filterImage(srcImg.get(), ctx, &offset));
robertphillips4418dba2016-03-07 12:45:14 -08001529 REPORTER_ASSERT(reporter, resultImg);
ajuma5788faa2015-02-13 09:05:47 -08001530 REPORTER_ASSERT(reporter, offset.fX == 1 && offset.fY == 0);
1531}
1532
robertphillips4418dba2016-03-07 12:45:14 -08001533DEF_TEST(ComposedImageFilterOffset, reporter) {
robertphillips3e302272016-04-20 11:48:36 -07001534 test_composed_imagefilter_offset(reporter, nullptr);
robertphillips4418dba2016-03-07 12:45:14 -08001535}
1536
1537#if SK_SUPPORT_GPU
bsalomon68d91342016-04-12 09:59:58 -07001538DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ComposedImageFilterOffset_Gpu, reporter, ctxInfo) {
bsalomon8b7451a2016-05-11 06:33:06 -07001539 test_composed_imagefilter_offset(reporter, ctxInfo.grContext());
robertphillips4418dba2016-03-07 12:45:14 -08001540}
1541#endif
1542
robertphillips3e302272016-04-20 11:48:36 -07001543static void test_composed_imagefilter_bounds(skiatest::Reporter* reporter, GrContext* context) {
jbroman17a65202016-03-21 08:38:58 -07001544 // The bounds passed to the inner filter must be filtered by the outer
1545 // filter, so that the inner filter produces the pixels that the outer
1546 // filter requires as input. This matters if the outer filter moves pixels.
1547 // Here, accounting for the outer offset is necessary so that the green
1548 // pixels of the picture are not clipped.
1549
1550 SkPictureRecorder recorder;
1551 SkCanvas* recordingCanvas = recorder.beginRecording(SkRect::MakeWH(200, 100));
1552 recordingCanvas->clipRect(SkRect::MakeXYWH(100, 0, 100, 100));
1553 recordingCanvas->clear(SK_ColorGREEN);
robertphillips491fb172016-03-30 12:32:58 -07001554 sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture());
robertphillips5ff17b12016-03-28 13:13:42 -07001555 sk_sp<SkImageFilter> pictureFilter(SkPictureImageFilter::Make(picture));
jbroman17a65202016-03-21 08:38:58 -07001556 SkImageFilter::CropRect cropRect(SkRect::MakeWH(100, 100));
robertphillips51a315e2016-03-31 09:05:49 -07001557 sk_sp<SkImageFilter> offsetFilter(SkOffsetImageFilter::Make(-100, 0, nullptr, &cropRect));
robertphillips491fb172016-03-30 12:32:58 -07001558 sk_sp<SkImageFilter> composedFilter(SkComposeImageFilter::Make(std::move(offsetFilter),
1559 std::move(pictureFilter)));
jbroman17a65202016-03-21 08:38:58 -07001560
robertphillips3e302272016-04-20 11:48:36 -07001561 sk_sp<SkSpecialImage> sourceImage(create_empty_special_image(context, 100));
brianosman2a75e5d2016-09-22 07:15:37 -07001562 SkImageFilter::OutputProperties noColorSpace(nullptr);
1563 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeWH(100, 100), nullptr, noColorSpace);
jbroman17a65202016-03-21 08:38:58 -07001564 SkIPoint offset;
1565 sk_sp<SkSpecialImage> result(composedFilter->filterImage(sourceImage.get(), ctx, &offset));
1566 REPORTER_ASSERT(reporter, offset.isZero());
1567 REPORTER_ASSERT(reporter, result);
1568 REPORTER_ASSERT(reporter, result->subset().size() == SkISize::Make(100, 100));
1569
1570 SkBitmap resultBM;
robertphillips64612512016-04-08 12:10:42 -07001571 REPORTER_ASSERT(reporter, result->getROPixels(&resultBM));
jbroman17a65202016-03-21 08:38:58 -07001572 REPORTER_ASSERT(reporter, resultBM.getColor(50, 50) == SK_ColorGREEN);
1573}
1574
1575DEF_TEST(ComposedImageFilterBounds, reporter) {
robertphillips3e302272016-04-20 11:48:36 -07001576 test_composed_imagefilter_bounds(reporter, nullptr);
jbroman17a65202016-03-21 08:38:58 -07001577}
1578
1579#if SK_SUPPORT_GPU
egdanielab527a52016-06-28 08:07:26 -07001580DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ComposedImageFilterBounds_Gpu, reporter, ctxInfo) {
bsalomon8b7451a2016-05-11 06:33:06 -07001581 test_composed_imagefilter_bounds(reporter, ctxInfo.grContext());
jbroman17a65202016-03-21 08:38:58 -07001582}
1583#endif
1584
robertphillips3e302272016-04-20 11:48:36 -07001585static void test_partial_crop_rect(skiatest::Reporter* reporter, GrContext* context) {
1586 sk_sp<SkSpecialImage> srcImg(create_empty_special_image(context, 100));
senorblanco24d2a7b2015-07-13 10:27:05 -07001587
1588 SkImageFilter::CropRect cropRect(SkRect::MakeXYWH(100, 0, 20, 30),
senorblancoed7cf272015-07-16 15:19:11 -07001589 SkImageFilter::CropRect::kHasWidth_CropEdge | SkImageFilter::CropRect::kHasHeight_CropEdge);
robertphillips5605b562016-04-05 11:50:42 -07001590 sk_sp<SkImageFilter> filter(make_grayscale(nullptr, &cropRect));
senorblanco24d2a7b2015-07-13 10:27:05 -07001591 SkIPoint offset;
brianosman2a75e5d2016-09-22 07:15:37 -07001592 SkImageFilter::OutputProperties noColorSpace(nullptr);
1593 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeWH(100, 100), nullptr, noColorSpace);
robertphillips4418dba2016-03-07 12:45:14 -08001594
robertphillips2302de92016-03-24 07:26:32 -07001595 sk_sp<SkSpecialImage> resultImg(filter->filterImage(srcImg.get(), ctx, &offset));
robertphillips4418dba2016-03-07 12:45:14 -08001596 REPORTER_ASSERT(reporter, resultImg);
1597
senorblanco24d2a7b2015-07-13 10:27:05 -07001598 REPORTER_ASSERT(reporter, offset.fX == 0);
1599 REPORTER_ASSERT(reporter, offset.fY == 0);
robertphillips4418dba2016-03-07 12:45:14 -08001600 REPORTER_ASSERT(reporter, resultImg->width() == 20);
1601 REPORTER_ASSERT(reporter, resultImg->height() == 30);
senorblanco24d2a7b2015-07-13 10:27:05 -07001602}
1603
senorblanco21a465d2016-04-11 11:58:39 -07001604DEF_TEST(ImageFilterPartialCropRect, reporter) {
robertphillips3e302272016-04-20 11:48:36 -07001605 test_partial_crop_rect(reporter, nullptr);
robertphillips4418dba2016-03-07 12:45:14 -08001606}
1607
1608#if SK_SUPPORT_GPU
bsalomon68d91342016-04-12 09:59:58 -07001609DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterPartialCropRect_Gpu, reporter, ctxInfo) {
bsalomon8b7451a2016-05-11 06:33:06 -07001610 test_partial_crop_rect(reporter, ctxInfo.grContext());
robertphillips4418dba2016-03-07 12:45:14 -08001611}
1612#endif
1613
senorblanco0abdf762015-08-20 11:10:41 -07001614DEF_TEST(ImageFilterCanComputeFastBounds, reporter) {
1615
robertphillips12fa47d2016-04-08 16:28:09 -07001616 {
1617 SkPoint3 location = SkPoint3::Make(0, 0, SK_Scalar1);
1618 sk_sp<SkImageFilter> lighting(SkLightingImageFilter::MakePointLitDiffuse(location,
1619 SK_ColorGREEN,
1620 0, 0, nullptr));
1621 REPORTER_ASSERT(reporter, !lighting->canComputeFastBounds());
1622 }
senorblanco0abdf762015-08-20 11:10:41 -07001623
senorblanco0abdf762015-08-20 11:10:41 -07001624 {
robertphillips6e7025a2016-04-04 04:31:25 -07001625 sk_sp<SkImageFilter> gray(make_grayscale(nullptr, nullptr));
1626 REPORTER_ASSERT(reporter, gray->canComputeFastBounds());
1627 {
1628 SkColorFilter* grayCF;
1629 REPORTER_ASSERT(reporter, gray->asAColorFilter(&grayCF));
1630 REPORTER_ASSERT(reporter, !grayCF->affectsTransparentBlack());
1631 grayCF->unref();
1632 }
1633 REPORTER_ASSERT(reporter, gray->canComputeFastBounds());
1634
1635 sk_sp<SkImageFilter> grayBlur(SkBlurImageFilter::Make(SK_Scalar1, SK_Scalar1,
1636 std::move(gray)));
1637 REPORTER_ASSERT(reporter, grayBlur->canComputeFastBounds());
senorblanco0abdf762015-08-20 11:10:41 -07001638 }
senorblanco0abdf762015-08-20 11:10:41 -07001639
robertphillips6e7025a2016-04-04 04:31:25 -07001640 {
1641 SkScalar greenMatrix[20] = { 0, 0, 0, 0, 0,
1642 0, 0, 0, 0, 1,
1643 0, 0, 0, 0, 0,
1644 0, 0, 0, 0, 1 };
1645 sk_sp<SkColorFilter> greenCF(SkColorFilter::MakeMatrixFilterRowMajor255(greenMatrix));
robertphillips5605b562016-04-05 11:50:42 -07001646 sk_sp<SkImageFilter> green(SkColorFilterImageFilter::Make(greenCF, nullptr));
senorblanco0abdf762015-08-20 11:10:41 -07001647
robertphillips6e7025a2016-04-04 04:31:25 -07001648 REPORTER_ASSERT(reporter, greenCF->affectsTransparentBlack());
1649 REPORTER_ASSERT(reporter, !green->canComputeFastBounds());
senorblanco0abdf762015-08-20 11:10:41 -07001650
robertphillips6e7025a2016-04-04 04:31:25 -07001651 sk_sp<SkImageFilter> greenBlur(SkBlurImageFilter::Make(SK_Scalar1, SK_Scalar1,
1652 std::move(green)));
1653 REPORTER_ASSERT(reporter, !greenBlur->canComputeFastBounds());
1654 }
senorblanco0abdf762015-08-20 11:10:41 -07001655
1656 uint8_t allOne[256], identity[256];
1657 for (int i = 0; i < 256; ++i) {
1658 identity[i] = i;
1659 allOne[i] = 255;
1660 }
1661
robertphillips5605b562016-04-05 11:50:42 -07001662 sk_sp<SkColorFilter> identityCF(SkTableColorFilter::MakeARGB(identity, identity,
1663 identity, allOne));
1664 sk_sp<SkImageFilter> identityFilter(SkColorFilterImageFilter::Make(identityCF, nullptr));
senorblanco0abdf762015-08-20 11:10:41 -07001665 REPORTER_ASSERT(reporter, !identityCF->affectsTransparentBlack());
1666 REPORTER_ASSERT(reporter, identityFilter->canComputeFastBounds());
1667
robertphillips5605b562016-04-05 11:50:42 -07001668 sk_sp<SkColorFilter> forceOpaqueCF(SkTableColorFilter::MakeARGB(allOne, identity,
1669 identity, identity));
1670 sk_sp<SkImageFilter> forceOpaque(SkColorFilterImageFilter::Make(forceOpaqueCF, nullptr));
senorblanco0abdf762015-08-20 11:10:41 -07001671 REPORTER_ASSERT(reporter, forceOpaqueCF->affectsTransparentBlack());
1672 REPORTER_ASSERT(reporter, !forceOpaque->canComputeFastBounds());
1673}
1674
fmalitacd56f812015-09-14 13:31:18 -07001675// Verify that SkImageSource survives serialization
1676DEF_TEST(ImageFilterImageSourceSerialization, reporter) {
reede8f30622016-03-23 18:59:25 -07001677 auto surface(SkSurface::MakeRasterN32Premul(10, 10));
fmalitacd56f812015-09-14 13:31:18 -07001678 surface->getCanvas()->clear(SK_ColorGREEN);
reed9ce9d672016-03-17 10:51:11 -07001679 sk_sp<SkImage> image(surface->makeImageSnapshot());
robertphillips549c8992016-04-01 09:28:51 -07001680 sk_sp<SkImageFilter> filter(SkImageSource::Make(std::move(image)));
fmalitacd56f812015-09-14 13:31:18 -07001681
robertphillips549c8992016-04-01 09:28:51 -07001682 sk_sp<SkData> data(SkValidatingSerializeFlattenable(filter.get()));
Mike Reed5e257172016-11-01 11:22:05 -04001683 sk_sp<SkImageFilter> unflattenedFilter = SkValidatingDeserializeImageFilter(data->data(),
1684 data->size());
fmalitacd56f812015-09-14 13:31:18 -07001685 REPORTER_ASSERT(reporter, unflattenedFilter);
1686
1687 SkBitmap bm;
1688 bm.allocN32Pixels(10, 10);
fmalita23cb88c2015-09-15 06:56:23 -07001689 bm.eraseColor(SK_ColorBLUE);
fmalitacd56f812015-09-14 13:31:18 -07001690 SkPaint paint;
1691 paint.setColor(SK_ColorRED);
1692 paint.setImageFilter(unflattenedFilter);
1693
1694 SkCanvas canvas(bm);
1695 canvas.drawRect(SkRect::MakeWH(10, 10), paint);
1696 REPORTER_ASSERT(reporter, *bm.getAddr32(0, 0) == SkPreMultiplyColor(SK_ColorGREEN));
1697}
1698
bsalomon45eefcf2016-01-05 08:39:28 -08001699static void test_large_blur_input(skiatest::Reporter* reporter, SkCanvas* canvas) {
1700 SkBitmap largeBmp;
1701 int largeW = 5000;
1702 int largeH = 5000;
1703#if SK_SUPPORT_GPU
1704 // If we're GPU-backed make the bitmap too large to be converted into a texture.
1705 if (GrContext* ctx = canvas->getGrContext()) {
1706 largeW = ctx->caps()->maxTextureSize() + 1;
1707 }
1708#endif
1709
1710 largeBmp.allocN32Pixels(largeW, largeH);
mtklein2afbe232016-02-07 12:23:10 -08001711 largeBmp.eraseColor(0);
bsalomon45eefcf2016-01-05 08:39:28 -08001712 if (!largeBmp.getPixels()) {
1713 ERRORF(reporter, "Failed to allocate large bmp.");
1714 return;
1715 }
1716
reed9ce9d672016-03-17 10:51:11 -07001717 sk_sp<SkImage> largeImage(SkImage::MakeFromBitmap(largeBmp));
bsalomon45eefcf2016-01-05 08:39:28 -08001718 if (!largeImage) {
1719 ERRORF(reporter, "Failed to create large image.");
1720 return;
1721 }
1722
robertphillips549c8992016-04-01 09:28:51 -07001723 sk_sp<SkImageFilter> largeSource(SkImageSource::Make(std::move(largeImage)));
bsalomon45eefcf2016-01-05 08:39:28 -08001724 if (!largeSource) {
1725 ERRORF(reporter, "Failed to create large SkImageSource.");
1726 return;
1727 }
1728
robertphillips6e7025a2016-04-04 04:31:25 -07001729 sk_sp<SkImageFilter> blur(SkBlurImageFilter::Make(10.f, 10.f, std::move(largeSource)));
bsalomon45eefcf2016-01-05 08:39:28 -08001730 if (!blur) {
1731 ERRORF(reporter, "Failed to create SkBlurImageFilter.");
1732 return;
1733 }
1734
1735 SkPaint paint;
robertphillips549c8992016-04-01 09:28:51 -07001736 paint.setImageFilter(std::move(blur));
bsalomon45eefcf2016-01-05 08:39:28 -08001737
1738 // This should not crash (http://crbug.com/570479).
1739 canvas->drawRect(SkRect::MakeIWH(largeW, largeH), paint);
1740}
1741
senorblanco21a465d2016-04-11 11:58:39 -07001742DEF_TEST(ImageFilterBlurLargeImage, reporter) {
reede8f30622016-03-23 18:59:25 -07001743 auto surface(SkSurface::MakeRaster(SkImageInfo::MakeN32Premul(100, 100)));
bsalomon45eefcf2016-01-05 08:39:28 -08001744 test_large_blur_input(reporter, surface->getCanvas());
1745}
1746
senorblanco5878dbd2016-05-19 14:50:29 -07001747static void test_make_with_filter(skiatest::Reporter* reporter, GrContext* context) {
Robert Phillipsa5fdc972017-02-18 16:58:09 -05001748 sk_sp<SkSurface> surface(create_surface(context, 192, 128));
senorblanco5878dbd2016-05-19 14:50:29 -07001749 surface->getCanvas()->clear(SK_ColorRED);
1750 SkPaint bluePaint;
1751 bluePaint.setColor(SK_ColorBLUE);
1752 SkIRect subset = SkIRect::MakeXYWH(25, 20, 50, 50);
1753 surface->getCanvas()->drawRect(SkRect::Make(subset), bluePaint);
1754 sk_sp<SkImage> sourceImage = surface->makeImageSnapshot();
1755
1756 sk_sp<SkImageFilter> filter = make_grayscale(nullptr, nullptr);
1757 SkIRect clipBounds = SkIRect::MakeXYWH(30, 35, 100, 100);
1758 SkIRect outSubset;
1759 SkIPoint offset;
1760 sk_sp<SkImage> result;
1761
1762 result = sourceImage->makeWithFilter(nullptr, subset, clipBounds, &outSubset, &offset);
1763 REPORTER_ASSERT(reporter, !result);
1764
1765 result = sourceImage->makeWithFilter(filter.get(), subset, clipBounds, nullptr, &offset);
1766 REPORTER_ASSERT(reporter, !result);
1767
1768 result = sourceImage->makeWithFilter(filter.get(), subset, clipBounds, &outSubset, nullptr);
1769 REPORTER_ASSERT(reporter, !result);
1770
1771 SkIRect bigSubset = SkIRect::MakeXYWH(-10000, -10000, 20000, 20000);
1772 result = sourceImage->makeWithFilter(filter.get(), bigSubset, clipBounds, &outSubset, &offset);
1773 REPORTER_ASSERT(reporter, !result);
1774
1775 SkIRect empty = SkIRect::MakeEmpty();
1776 result = sourceImage->makeWithFilter(filter.get(), empty, clipBounds, &outSubset, &offset);
1777 REPORTER_ASSERT(reporter, !result);
1778
1779 result = sourceImage->makeWithFilter(filter.get(), subset, empty, &outSubset, &offset);
1780 REPORTER_ASSERT(reporter, !result);
1781
1782 SkIRect leftField = SkIRect::MakeXYWH(-1000, 0, 100, 100);
1783 result = sourceImage->makeWithFilter(filter.get(), subset, leftField, &outSubset, &offset);
1784 REPORTER_ASSERT(reporter, !result);
1785
1786 result = sourceImage->makeWithFilter(filter.get(), subset, clipBounds, &outSubset, &offset);
1787
1788 REPORTER_ASSERT(reporter, result);
1789 REPORTER_ASSERT(reporter, result->bounds().contains(outSubset));
1790 SkIRect destRect = SkIRect::MakeXYWH(offset.x(), offset.y(),
1791 outSubset.width(), outSubset.height());
1792 REPORTER_ASSERT(reporter, clipBounds.contains(destRect));
Robert Phillipsa5fdc972017-02-18 16:58:09 -05001793
1794 // In GPU-mode, this case creates a special image with a backing size that differs from
1795 // the content size
1796 {
1797 clipBounds.setXYWH(0, 0, 170, 100);
1798 subset.setXYWH(0, 0, 160, 90);
1799
1800 filter = SkXfermodeImageFilter::Make(SkBlendMode::kSrc, nullptr);
1801 result = sourceImage->makeWithFilter(filter.get(), subset, clipBounds, &outSubset, &offset);
1802 REPORTER_ASSERT(reporter, result);
1803 }
senorblanco5878dbd2016-05-19 14:50:29 -07001804}
1805
1806DEF_TEST(ImageFilterMakeWithFilter, reporter) {
1807 test_make_with_filter(reporter, nullptr);
1808}
1809
1810#if SK_SUPPORT_GPU
1811DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterMakeWithFilter_Gpu, reporter, ctxInfo) {
1812 test_make_with_filter(reporter, ctxInfo.grContext());
1813}
1814#endif
1815
senorblanco@chromium.org58d14662014-02-03 22:36:39 +00001816#if SK_SUPPORT_GPU
reed4a8126e2014-09-22 07:29:03 -07001817
bsalomon68d91342016-04-12 09:59:58 -07001818DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterHugeBlur_Gpu, reporter, ctxInfo) {
robertphillipsefbffed2015-06-22 12:06:08 -07001819
bsalomon8b7451a2016-05-11 06:33:06 -07001820 sk_sp<SkSurface> surf(SkSurface::MakeRenderTarget(ctxInfo.grContext(),
robertphillips3e302272016-04-20 11:48:36 -07001821 SkBudgeted::kNo,
1822 SkImageInfo::MakeN32Premul(100, 100)));
robertphillips9a53fd72015-06-22 09:46:59 -07001823
robertphillips3e302272016-04-20 11:48:36 -07001824
1825 SkCanvas* canvas = surf->getCanvas();
1826
1827 test_huge_blur(canvas, reporter);
senorblanco@chromium.org09843fd2014-03-24 20:50:59 +00001828}
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001829
egdanielab527a52016-06-28 08:07:26 -07001830DEF_GPUTEST_FOR_RENDERING_CONTEXTS(XfermodeImageFilterCroppedInput_Gpu, reporter, ctxInfo) {
Brian Salomon8996e182017-07-05 17:01:48 -04001831 sk_sp<SkSurface> surf(SkSurface::MakeRenderTarget(
1832 ctxInfo.grContext(),
1833 SkBudgeted::kNo,
1834 SkImageInfo::Make(1, 1, kRGBA_8888_SkColorType, kPremul_SkAlphaType)));
robertphillips3e302272016-04-20 11:48:36 -07001835
1836 SkCanvas* canvas = surf->getCanvas();
1837
1838 test_xfermode_cropped_input(canvas, reporter);
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001839}
senorblanco32673b92014-09-09 09:15:04 -07001840
egdanielab527a52016-06-28 08:07:26 -07001841DEF_GPUTEST_FOR_ALL_CONTEXTS(ImageFilterBlurLargeImage_Gpu, reporter, ctxInfo) {
Brian Salomon8996e182017-07-05 17:01:48 -04001842 auto surface(SkSurface::MakeRenderTarget(
1843 ctxInfo.grContext(), SkBudgeted::kYes,
1844 SkImageInfo::Make(100, 100, kRGBA_8888_SkColorType, kPremul_SkAlphaType)));
bsalomon45eefcf2016-01-05 08:39:28 -08001845 test_large_blur_input(reporter, surface->getCanvas());
1846}
senorblanco@chromium.org58d14662014-02-03 22:36:39 +00001847#endif
reedbb34a8a2016-04-23 15:19:07 -07001848
1849/*
1850 * Test that colorfilterimagefilter does not require its CTM to be decomposed when it has more
1851 * than just scale/translate, but that other filters do.
1852 */
reed96a04f32016-04-25 09:25:15 -07001853DEF_TEST(ImageFilterComplexCTM, reporter) {
reedbb34a8a2016-04-23 15:19:07 -07001854 // just need a colorfilter to exercise the corresponding imagefilter
Mike Reed7d954ad2016-10-28 15:42:34 -04001855 sk_sp<SkColorFilter> cf = SkColorFilter::MakeModeFilter(SK_ColorRED, SkBlendMode::kSrcATop);
reed96a04f32016-04-25 09:25:15 -07001856 sk_sp<SkImageFilter> cfif = SkColorFilterImageFilter::Make(cf, nullptr); // can handle
1857 sk_sp<SkImageFilter> blif = SkBlurImageFilter::Make(3, 3, nullptr); // cannot handle
reedbb34a8a2016-04-23 15:19:07 -07001858
1859 struct {
1860 sk_sp<SkImageFilter> fFilter;
1861 bool fExpectCanHandle;
1862 } recs[] = {
1863 { cfif, true },
1864 { SkColorFilterImageFilter::Make(cf, cfif), true },
Mike Reed0bdaf052017-06-18 23:35:57 -04001865 { SkMergeImageFilter::Make(cfif, cfif), true },
reed96a04f32016-04-25 09:25:15 -07001866 { SkComposeImageFilter::Make(cfif, cfif), true },
1867
reedbb34a8a2016-04-23 15:19:07 -07001868 { blif, false },
reed96a04f32016-04-25 09:25:15 -07001869 { SkBlurImageFilter::Make(3, 3, cfif), false },
reedbb34a8a2016-04-23 15:19:07 -07001870 { SkColorFilterImageFilter::Make(cf, blif), false },
Mike Reed0bdaf052017-06-18 23:35:57 -04001871 { SkMergeImageFilter::Make(cfif, blif), false },
reed96a04f32016-04-25 09:25:15 -07001872 { SkComposeImageFilter::Make(blif, cfif), false },
reedbb34a8a2016-04-23 15:19:07 -07001873 };
liyuqianbfebe222016-11-14 11:17:16 -08001874
reedbb34a8a2016-04-23 15:19:07 -07001875 for (const auto& rec : recs) {
reed96a04f32016-04-25 09:25:15 -07001876 const bool canHandle = rec.fFilter->canHandleComplexCTM();
reedbb34a8a2016-04-23 15:19:07 -07001877 REPORTER_ASSERT(reporter, canHandle == rec.fExpectCanHandle);
1878 }
1879}