blob: 8a19a226c6df74f25eff0e5324ce8d14420c511a [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
robertphillipsfc11b0a2016-04-05 09:09:36 -0700199 this->addFilter("merge", SkMergeImageFilter::Make(input, input,
Mike Reed7d954ad2016-10-28 15:42:34 -0400200 SkBlendMode::kSrcOver,
robertphillips12fa47d2016-04-08 16:28:09 -0700201 cropRect));
202
robertphillips6e7025a2016-04-04 04:31:25 -0700203 {
204 SkPaint greenColorShaderPaint;
205 greenColorShaderPaint.setShader(SkShader::MakeColorShader(SK_ColorGREEN));
206
207 SkImageFilter::CropRect leftSideCropRect(SkRect::MakeXYWH(0, 0, 32, 64));
208 sk_sp<SkImageFilter> paintFilterLeft(SkPaintImageFilter::Make(greenColorShaderPaint,
209 &leftSideCropRect));
210 SkImageFilter::CropRect rightSideCropRect(SkRect::MakeXYWH(32, 0, 32, 64));
211 sk_sp<SkImageFilter> paintFilterRight(SkPaintImageFilter::Make(greenColorShaderPaint,
212 &rightSideCropRect));
213
214
215 this->addFilter("merge with disjoint inputs", SkMergeImageFilter::Make(
robertphillips2238c9d2016-03-30 13:34:16 -0700216 std::move(paintFilterLeft), std::move(paintFilterRight),
Mike Reed7d954ad2016-10-28 15:42:34 -0400217 SkBlendMode::kSrcOver, cropRect));
robertphillips6e7025a2016-04-04 04:31:25 -0700218 }
219
senorblanco297f7ce2016-03-23 13:44:26 -0700220 this->addFilter("offset",
robertphillipsfc11b0a2016-04-05 09:09:36 -0700221 SkOffsetImageFilter::Make(SK_Scalar1, SK_Scalar1, input,
robertphillips12fa47d2016-04-08 16:28:09 -0700222 cropRect));
223 this->addFilter("dilate", SkDilateImageFilter::Make(3, 2, input, cropRect));
224 this->addFilter("erode", SkErodeImageFilter::Make(2, 3, input, cropRect));
robertphillips534c2702016-04-15 07:57:40 -0700225 this->addFilter("tile", SkTileImageFilter::Make(
226 SkRect::MakeXYWH(0, 0, 50, 50),
227 cropRect ? cropRect->rect() : SkRect::MakeXYWH(0, 0, 100, 100),
228 input));
robertphillips6e7025a2016-04-04 04:31:25 -0700229
robertphillips12fa47d2016-04-08 16:28:09 -0700230 if (!cropRect) {
231 SkMatrix matrix;
232
233 matrix.setTranslate(SK_Scalar1, SK_Scalar1);
234 matrix.postRotate(SkIntToScalar(45), SK_Scalar1, SK_Scalar1);
235
236 this->addFilter("matrix",
237 SkImageFilter::MakeMatrixFilter(matrix, kLow_SkFilterQuality, input));
238 }
robertphillips6e7025a2016-04-04 04:31:25 -0700239 {
robertphillipsfc11b0a2016-04-05 09:09:36 -0700240 sk_sp<SkImageFilter> blur(SkBlurImageFilter::Make(five, five, input));
robertphillips6e7025a2016-04-04 04:31:25 -0700241
242 this->addFilter("blur and offset", SkOffsetImageFilter::Make(five, five,
243 std::move(blur),
robertphillips12fa47d2016-04-08 16:28:09 -0700244 cropRect));
robertphillips6e7025a2016-04-04 04:31:25 -0700245 }
246 {
robertphillips6e7025a2016-04-04 04:31:25 -0700247 SkPictureRecorder recorder;
Mike Klein26eb16f2017-04-10 09:50:25 -0400248 SkCanvas* recordingCanvas = recorder.beginRecording(64, 64);
robertphillips6e7025a2016-04-04 04:31:25 -0700249
250 SkPaint greenPaint;
251 greenPaint.setColor(SK_ColorGREEN);
252 recordingCanvas->drawRect(SkRect::Make(SkIRect::MakeXYWH(10, 10, 30, 20)), greenPaint);
253 sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture());
254 sk_sp<SkImageFilter> pictureFilter(SkPictureImageFilter::Make(std::move(picture)));
255
256 this->addFilter("picture and blur", SkBlurImageFilter::Make(five, five,
257 std::move(pictureFilter),
robertphillips12fa47d2016-04-08 16:28:09 -0700258 cropRect));
robertphillips6e7025a2016-04-04 04:31:25 -0700259 }
260 {
261 SkPaint paint;
262 paint.setShader(SkPerlinNoiseShader::MakeTurbulence(SK_Scalar1, SK_Scalar1, 1, 0));
263 sk_sp<SkImageFilter> paintFilter(SkPaintImageFilter::Make(paint));
264
265 this->addFilter("paint and blur", SkBlurImageFilter::Make(five, five,
266 std::move(paintFilter),
robertphillips12fa47d2016-04-08 16:28:09 -0700267 cropRect));
robertphillips6e7025a2016-04-04 04:31:25 -0700268 }
reed374772b2016-10-05 17:33:02 -0700269 this->addFilter("xfermode", SkXfermodeImageFilter::Make(SkBlendMode::kSrc, input, input,
270 cropRect));
senorblanco297f7ce2016-03-23 13:44:26 -0700271 }
272 int count() const { return fFilters.count(); }
273 SkImageFilter* getFilter(int index) const { return fFilters[index].fFilter.get(); }
274 const char* getName(int index) const { return fFilters[index].fName; }
275private:
276 struct Filter {
robertphillips12fa47d2016-04-08 16:28:09 -0700277 Filter() : fName(nullptr) {}
278 Filter(const char* name, sk_sp<SkImageFilter> filter)
279 : fName(name)
280 , fFilter(std::move(filter)) {
281 }
senorblanco297f7ce2016-03-23 13:44:26 -0700282 const char* fName;
283 sk_sp<SkImageFilter> fFilter;
284 };
robertphillips12fa47d2016-04-08 16:28:09 -0700285 void addFilter(const char* name, sk_sp<SkImageFilter> filter) {
286 fFilters.push_back(Filter(name, std::move(filter)));
senorblanco297f7ce2016-03-23 13:44:26 -0700287 }
288
289 SkTArray<Filter> fFilters;
290};
291
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +0000292}
293
reed60c9b582016-04-03 09:11:13 -0700294sk_sp<SkFlattenable> MatrixTestImageFilter::CreateProc(SkReadBuffer& buffer) {
brianosman18f13f32016-05-02 07:51:08 -0700295 SkDEBUGFAIL("Should never get here");
296 return nullptr;
reed9fa60da2014-08-21 07:59:51 -0700297}
298
robertphillipsf3f5bad2014-12-19 13:49:15 -0800299#ifndef SK_IGNORE_TO_STRING
300void MatrixTestImageFilter::toString(SkString* str) const {
301 str->appendf("MatrixTestImageFilter: (");
302 str->append(")");
303}
304#endif
305
reed9ce9d672016-03-17 10:51:11 -0700306static sk_sp<SkImage> make_small_image() {
reede8f30622016-03-23 18:59:25 -0700307 auto surface(SkSurface::MakeRasterN32Premul(kBitmapSize, kBitmapSize));
fmalita5598b632015-09-15 11:26:13 -0700308 SkCanvas* canvas = surface->getCanvas();
309 canvas->clear(0x00000000);
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000310 SkPaint darkPaint;
311 darkPaint.setColor(0xFF804020);
312 SkPaint lightPaint;
313 lightPaint.setColor(0xFF244484);
314 const int i = kBitmapSize / 4;
315 for (int y = 0; y < kBitmapSize; y += i) {
316 for (int x = 0; x < kBitmapSize; x += i) {
fmalita5598b632015-09-15 11:26:13 -0700317 canvas->save();
318 canvas->translate(SkIntToScalar(x), SkIntToScalar(y));
319 canvas->drawRect(SkRect::MakeXYWH(0, 0,
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000320 SkIntToScalar(i),
321 SkIntToScalar(i)), darkPaint);
fmalita5598b632015-09-15 11:26:13 -0700322 canvas->drawRect(SkRect::MakeXYWH(SkIntToScalar(i),
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000323 0,
324 SkIntToScalar(i),
325 SkIntToScalar(i)), lightPaint);
fmalita5598b632015-09-15 11:26:13 -0700326 canvas->drawRect(SkRect::MakeXYWH(0,
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000327 SkIntToScalar(i),
328 SkIntToScalar(i),
329 SkIntToScalar(i)), lightPaint);
fmalita5598b632015-09-15 11:26:13 -0700330 canvas->drawRect(SkRect::MakeXYWH(SkIntToScalar(i),
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000331 SkIntToScalar(i),
332 SkIntToScalar(i),
333 SkIntToScalar(i)), darkPaint);
fmalita5598b632015-09-15 11:26:13 -0700334 canvas->restore();
commit-bot@chromium.org4b681bc2013-09-13 12:40:02 +0000335 }
336 }
fmalita5598b632015-09-15 11:26:13 -0700337
reed9ce9d672016-03-17 10:51:11 -0700338 return surface->makeImageSnapshot();
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000339}
senorblanco@chromium.org194d7752013-07-24 22:19:24 +0000340
robertphillips5605b562016-04-05 11:50:42 -0700341static sk_sp<SkImageFilter> make_scale(float amount, sk_sp<SkImageFilter> input) {
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000342 SkScalar s = amount;
343 SkScalar matrix[20] = { s, 0, 0, 0, 0,
344 0, s, 0, 0, 0,
345 0, 0, s, 0, 0,
346 0, 0, 0, s, 0 };
robertphillips5605b562016-04-05 11:50:42 -0700347 sk_sp<SkColorFilter> filter(SkColorFilter::MakeMatrixFilterRowMajor255(matrix));
348 return SkColorFilterImageFilter::Make(std::move(filter), std::move(input));
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000349}
350
robertphillips5605b562016-04-05 11:50:42 -0700351static sk_sp<SkImageFilter> make_grayscale(sk_sp<SkImageFilter> input,
352 const SkImageFilter::CropRect* cropRect) {
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000353 SkScalar matrix[20];
354 memset(matrix, 0, 20 * sizeof(SkScalar));
355 matrix[0] = matrix[5] = matrix[10] = 0.2126f;
356 matrix[1] = matrix[6] = matrix[11] = 0.7152f;
357 matrix[2] = matrix[7] = matrix[12] = 0.0722f;
358 matrix[18] = 1.0f;
robertphillips5605b562016-04-05 11:50:42 -0700359 sk_sp<SkColorFilter> filter(SkColorFilter::MakeMatrixFilterRowMajor255(matrix));
360 return SkColorFilterImageFilter::Make(std::move(filter), std::move(input), cropRect);
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000361}
362
robertphillips5605b562016-04-05 11:50:42 -0700363static sk_sp<SkImageFilter> make_blue(sk_sp<SkImageFilter> input,
364 const SkImageFilter::CropRect* cropRect) {
365 sk_sp<SkColorFilter> filter(SkColorFilter::MakeModeFilter(SK_ColorBLUE,
Mike Reed7d954ad2016-10-28 15:42:34 -0400366 SkBlendMode::kSrcIn));
robertphillips5605b562016-04-05 11:50:42 -0700367 return SkColorFilterImageFilter::Make(std::move(filter), std::move(input), cropRect);
reedcedc36f2015-03-08 04:42:52 -0700368}
369
robertphillips3e302272016-04-20 11:48:36 -0700370static sk_sp<SkSpecialSurface> create_empty_special_surface(GrContext* context, int widthHeight) {
robertphillipsc91fd342016-04-25 12:32:54 -0700371#if SK_SUPPORT_GPU
robertphillips4418dba2016-03-07 12:45:14 -0800372 if (context) {
robertphillips4df16562016-04-28 15:09:34 -0700373 return SkSpecialSurface::MakeRenderTarget(context,
374 widthHeight, widthHeight,
Brian Osman777b5632016-10-14 09:16:21 -0400375 kRGBA_8888_GrPixelConfig, nullptr);
robertphillipsc91fd342016-04-25 12:32:54 -0700376 } else
377#endif
378 {
robertphillips4418dba2016-03-07 12:45:14 -0800379 const SkImageInfo info = SkImageInfo::MakeN32(widthHeight, widthHeight,
380 kOpaque_SkAlphaType);
robertphillips3e302272016-04-20 11:48:36 -0700381 return SkSpecialSurface::MakeRaster(info);
robertphillips4418dba2016-03-07 12:45:14 -0800382 }
senorblancobf680c32016-03-16 16:15:53 -0700383}
384
senorblanco5878dbd2016-05-19 14:50:29 -0700385static sk_sp<SkSurface> create_surface(GrContext* context, int width, int height) {
386 const SkImageInfo info = SkImageInfo::MakeN32(width, height, kOpaque_SkAlphaType);
387#if SK_SUPPORT_GPU
388 if (context) {
389 return SkSurface::MakeRenderTarget(context, SkBudgeted::kNo, info);
390 } else
391#endif
392 {
393 return SkSurface::MakeRaster(info);
394 }
395}
396
robertphillips3e302272016-04-20 11:48:36 -0700397static sk_sp<SkSpecialImage> create_empty_special_image(GrContext* context, int widthHeight) {
398 sk_sp<SkSpecialSurface> surf(create_empty_special_surface(context, widthHeight));
robertphillips4418dba2016-03-07 12:45:14 -0800399
400 SkASSERT(surf);
401
402 SkCanvas* canvas = surf->getCanvas();
403 SkASSERT(canvas);
404
405 canvas->clear(0x0);
406
robertphillips37bd7c32016-03-17 14:31:39 -0700407 return surf->makeImageSnapshot();
robertphillips4418dba2016-03-07 12:45:14 -0800408}
409
410
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000411DEF_TEST(ImageFilter, reporter) {
412 {
reedcedc36f2015-03-08 04:42:52 -0700413 // Check that two non-clipping color-matrice-filters concatenate into a single filter.
robertphillips5605b562016-04-05 11:50:42 -0700414 sk_sp<SkImageFilter> halfBrightness(make_scale(0.5f, nullptr));
415 sk_sp<SkImageFilter> quarterBrightness(make_scale(0.5f, std::move(halfBrightness)));
halcanary96fcdcc2015-08-27 07:41:13 -0700416 REPORTER_ASSERT(reporter, nullptr == quarterBrightness->getInput(0));
reedcedc36f2015-03-08 04:42:52 -0700417 SkColorFilter* cf;
418 REPORTER_ASSERT(reporter, quarterBrightness->asColorFilter(&cf));
halcanary96fcdcc2015-08-27 07:41:13 -0700419 REPORTER_ASSERT(reporter, cf->asColorMatrix(nullptr));
reedcedc36f2015-03-08 04:42:52 -0700420 cf->unref();
senorblanco@chromium.org194d7752013-07-24 22:19:24 +0000421 }
422
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000423 {
reedcedc36f2015-03-08 04:42:52 -0700424 // Check that a clipping color-matrice-filter followed by a color-matrice-filters
425 // concatenates into a single filter, but not a matrixfilter (due to clamping).
robertphillips5605b562016-04-05 11:50:42 -0700426 sk_sp<SkImageFilter> doubleBrightness(make_scale(2.0f, nullptr));
427 sk_sp<SkImageFilter> halfBrightness(make_scale(0.5f, std::move(doubleBrightness)));
halcanary96fcdcc2015-08-27 07:41:13 -0700428 REPORTER_ASSERT(reporter, nullptr == halfBrightness->getInput(0));
reedcedc36f2015-03-08 04:42:52 -0700429 SkColorFilter* cf;
430 REPORTER_ASSERT(reporter, halfBrightness->asColorFilter(&cf));
halcanary96fcdcc2015-08-27 07:41:13 -0700431 REPORTER_ASSERT(reporter, !cf->asColorMatrix(nullptr));
reedcedc36f2015-03-08 04:42:52 -0700432 cf->unref();
senorblanco@chromium.org194d7752013-07-24 22:19:24 +0000433 }
434
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000435 {
436 // Check that a color filter image filter without a crop rect can be
437 // expressed as a color filter.
robertphillips5605b562016-04-05 11:50:42 -0700438 sk_sp<SkImageFilter> gray(make_grayscale(nullptr, nullptr));
halcanary96fcdcc2015-08-27 07:41:13 -0700439 REPORTER_ASSERT(reporter, true == gray->asColorFilter(nullptr));
senorblanco@chromium.org194d7752013-07-24 22:19:24 +0000440 }
mtklein2afbe232016-02-07 12:23:10 -0800441
reedcedc36f2015-03-08 04:42:52 -0700442 {
443 // Check that a colorfilterimage filter without a crop rect but with an input
444 // that is another colorfilterimage can be expressed as a colorfilter (composed).
robertphillips5605b562016-04-05 11:50:42 -0700445 sk_sp<SkImageFilter> mode(make_blue(nullptr, nullptr));
446 sk_sp<SkImageFilter> gray(make_grayscale(std::move(mode), nullptr));
halcanary96fcdcc2015-08-27 07:41:13 -0700447 REPORTER_ASSERT(reporter, true == gray->asColorFilter(nullptr));
reedcedc36f2015-03-08 04:42:52 -0700448 }
449
450 {
451 // Test that if we exceed the limit of what ComposeColorFilter can combine, we still
452 // can build the DAG and won't assert if we call asColorFilter.
robertphillips5605b562016-04-05 11:50:42 -0700453 sk_sp<SkImageFilter> filter(make_blue(nullptr, nullptr));
reedcedc36f2015-03-08 04:42:52 -0700454 const int kWayTooManyForComposeColorFilter = 100;
455 for (int i = 0; i < kWayTooManyForComposeColorFilter; ++i) {
robertphillips5605b562016-04-05 11:50:42 -0700456 filter = make_blue(filter, nullptr);
reedcedc36f2015-03-08 04:42:52 -0700457 // the first few of these will succeed, but after we hit the internal limit,
458 // it will then return false.
halcanary96fcdcc2015-08-27 07:41:13 -0700459 (void)filter->asColorFilter(nullptr);
reedcedc36f2015-03-08 04:42:52 -0700460 }
461 }
reed5c518a82015-03-05 14:47:29 -0800462
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000463 {
464 // Check that a color filter image filter with a crop rect cannot
465 // be expressed as a color filter.
466 SkImageFilter::CropRect cropRect(SkRect::MakeXYWH(0, 0, 100, 100));
robertphillips5605b562016-04-05 11:50:42 -0700467 sk_sp<SkImageFilter> grayWithCrop(make_grayscale(nullptr, &cropRect));
halcanary96fcdcc2015-08-27 07:41:13 -0700468 REPORTER_ASSERT(reporter, false == grayWithCrop->asColorFilter(nullptr));
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000469 }
470
471 {
senorblanco3df05012014-07-03 11:13:09 -0700472 // Check that two non-commutative matrices are concatenated in
473 // the correct order.
474 SkScalar blueToRedMatrix[20] = { 0 };
475 blueToRedMatrix[2] = blueToRedMatrix[18] = SK_Scalar1;
476 SkScalar redToGreenMatrix[20] = { 0 };
477 redToGreenMatrix[5] = redToGreenMatrix[18] = SK_Scalar1;
robertphillips5605b562016-04-05 11:50:42 -0700478 sk_sp<SkColorFilter> blueToRed(SkColorFilter::MakeMatrixFilterRowMajor255(blueToRedMatrix));
479 sk_sp<SkImageFilter> filter1(SkColorFilterImageFilter::Make(std::move(blueToRed),
480 nullptr));
481 sk_sp<SkColorFilter> redToGreen(SkColorFilter::MakeMatrixFilterRowMajor255(redToGreenMatrix));
482 sk_sp<SkImageFilter> filter2(SkColorFilterImageFilter::Make(std::move(redToGreen),
483 std::move(filter1)));
senorblanco3df05012014-07-03 11:13:09 -0700484
485 SkBitmap result;
486 result.allocN32Pixels(kBitmapSize, kBitmapSize);
487
488 SkPaint paint;
489 paint.setColor(SK_ColorBLUE);
robertphillips5605b562016-04-05 11:50:42 -0700490 paint.setImageFilter(std::move(filter2));
senorblanco3df05012014-07-03 11:13:09 -0700491 SkCanvas canvas(result);
492 canvas.clear(0x0);
493 SkRect rect = SkRect::Make(SkIRect::MakeWH(kBitmapSize, kBitmapSize));
494 canvas.drawRect(rect, paint);
495 uint32_t pixel = *result.getAddr32(0, 0);
496 // The result here should be green, since we have effectively shifted blue to green.
497 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
498 }
499
500 {
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000501 // Tests pass by not asserting
reed9ce9d672016-03-17 10:51:11 -0700502 sk_sp<SkImage> image(make_small_image());
fmalita5598b632015-09-15 11:26:13 -0700503 SkBitmap result;
mike@reedtribe.orgdeee4962014-02-13 14:41:43 +0000504 result.allocN32Pixels(kBitmapSize, kBitmapSize);
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000505
senorblanco@chromium.org194d7752013-07-24 22:19:24 +0000506 {
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000507 // This tests for :
508 // 1 ) location at (0,0,1)
robertphillips3d32d762015-07-13 13:16:44 -0700509 SkPoint3 location = SkPoint3::Make(0, 0, SK_Scalar1);
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000510 // 2 ) location and target at same value
robertphillips3d32d762015-07-13 13:16:44 -0700511 SkPoint3 target = SkPoint3::Make(location.fX, location.fY, location.fZ);
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000512 // 3 ) large negative specular exponent value
513 SkScalar specularExponent = -1000;
514
robertphillips549c8992016-04-01 09:28:51 -0700515 sk_sp<SkImageFilter> bmSrc(SkImageSource::Make(std::move(image)));
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000516 SkPaint paint;
robertphillips12fa47d2016-04-08 16:28:09 -0700517 paint.setImageFilter(SkLightingImageFilter::MakeSpotLitSpecular(
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000518 location, target, specularExponent, 180,
519 0xFFFFFFFF, SK_Scalar1, SK_Scalar1, SK_Scalar1,
robertphillips12fa47d2016-04-08 16:28:09 -0700520 std::move(bmSrc)));
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000521 SkCanvas canvas(result);
522 SkRect r = SkRect::MakeWH(SkIntToScalar(kBitmapSize),
523 SkIntToScalar(kBitmapSize));
524 canvas.drawRect(r, paint);
senorblanco@chromium.org194d7752013-07-24 22:19:24 +0000525 }
senorblanco@chromium.org194d7752013-07-24 22:19:24 +0000526 }
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +0000527}
senorblanco@chromium.org6776b822014-01-03 21:48:22 +0000528
robertphillips3e302272016-04-20 11:48:36 -0700529static void test_crop_rects(skiatest::Reporter* reporter,
robertphillips4418dba2016-03-07 12:45:14 -0800530 GrContext* context) {
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +0000531 // Check that all filters offset to their absolute crop rect,
532 // unaffected by the input crop rect.
533 // Tests pass by not asserting.
robertphillips3e302272016-04-20 11:48:36 -0700534 sk_sp<SkSpecialImage> srcImg(create_empty_special_image(context, 100));
robertphillips4418dba2016-03-07 12:45:14 -0800535 SkASSERT(srcImg);
senorblanco@chromium.org6776b822014-01-03 21:48:22 +0000536
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +0000537 SkImageFilter::CropRect inputCropRect(SkRect::MakeXYWH(8, 13, 80, 80));
538 SkImageFilter::CropRect cropRect(SkRect::MakeXYWH(20, 30, 60, 60));
robertphillipsfc11b0a2016-04-05 09:09:36 -0700539 sk_sp<SkImageFilter> input(make_grayscale(nullptr, &inputCropRect));
senorblanco@chromium.org6776b822014-01-03 21:48:22 +0000540
robertphillipsfc11b0a2016-04-05 09:09:36 -0700541 FilterList filters(input, &cropRect);
senorblanco@chromium.org6776b822014-01-03 21:48:22 +0000542
senorblanco297f7ce2016-03-23 13:44:26 -0700543 for (int i = 0; i < filters.count(); ++i) {
544 SkImageFilter* filter = filters.getFilter(i);
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +0000545 SkIPoint offset;
brianosman2a75e5d2016-09-22 07:15:37 -0700546 SkImageFilter::OutputProperties noColorSpace(nullptr);
547 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeWH(100, 100), nullptr, noColorSpace);
robertphillips2302de92016-03-24 07:26:32 -0700548 sk_sp<SkSpecialImage> resultImg(filter->filterImage(srcImg.get(), ctx, &offset));
senorblanco297f7ce2016-03-23 13:44:26 -0700549 REPORTER_ASSERT_MESSAGE(reporter, resultImg, filters.getName(i));
550 REPORTER_ASSERT_MESSAGE(reporter, offset.fX == 20 && offset.fY == 30, filters.getName(i));
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +0000551 }
552}
553
robertphillips3e302272016-04-20 11:48:36 -0700554static void test_negative_blur_sigma(skiatest::Reporter* reporter,
robertphillips4418dba2016-03-07 12:45:14 -0800555 GrContext* context) {
senorblanco32673b92014-09-09 09:15:04 -0700556 // Check that SkBlurImageFilter will accept a negative sigma, either in
557 // the given arguments or after CTM application.
reed5ea95df2015-10-06 14:05:32 -0700558 const int width = 32, height = 32;
559 const SkScalar five = SkIntToScalar(5);
senorblanco32673b92014-09-09 09:15:04 -0700560
robertphillips6e7025a2016-04-04 04:31:25 -0700561 sk_sp<SkImageFilter> positiveFilter(SkBlurImageFilter::Make(five, five, nullptr));
562 sk_sp<SkImageFilter> negativeFilter(SkBlurImageFilter::Make(-five, five, nullptr));
senorblanco32673b92014-09-09 09:15:04 -0700563
564 SkBitmap gradient = make_gradient_circle(width, height);
robertphillips3e302272016-04-20 11:48:36 -0700565 sk_sp<SkSpecialImage> imgSrc(SkSpecialImage::MakeFromRaster(SkIRect::MakeWH(width, height),
robertphillips37bd7c32016-03-17 14:31:39 -0700566 gradient));
robertphillips4418dba2016-03-07 12:45:14 -0800567
senorblanco32673b92014-09-09 09:15:04 -0700568 SkIPoint offset;
brianosman2a75e5d2016-09-22 07:15:37 -0700569 SkImageFilter::OutputProperties noColorSpace(nullptr);
570 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeWH(32, 32), nullptr, noColorSpace);
robertphillips4418dba2016-03-07 12:45:14 -0800571
robertphillips2302de92016-03-24 07:26:32 -0700572 sk_sp<SkSpecialImage> positiveResult1(positiveFilter->filterImage(imgSrc.get(), ctx, &offset));
robertphillips4418dba2016-03-07 12:45:14 -0800573 REPORTER_ASSERT(reporter, positiveResult1);
574
robertphillips2302de92016-03-24 07:26:32 -0700575 sk_sp<SkSpecialImage> negativeResult1(negativeFilter->filterImage(imgSrc.get(), ctx, &offset));
robertphillips4418dba2016-03-07 12:45:14 -0800576 REPORTER_ASSERT(reporter, negativeResult1);
577
senorblanco32673b92014-09-09 09:15:04 -0700578 SkMatrix negativeScale;
579 negativeScale.setScale(-SK_Scalar1, SK_Scalar1);
brianosman2a75e5d2016-09-22 07:15:37 -0700580 SkImageFilter::Context negativeCTX(negativeScale, SkIRect::MakeWH(32, 32), nullptr,
581 noColorSpace);
robertphillips4418dba2016-03-07 12:45:14 -0800582
robertphillips2302de92016-03-24 07:26:32 -0700583 sk_sp<SkSpecialImage> negativeResult2(positiveFilter->filterImage(imgSrc.get(),
584 negativeCTX,
585 &offset));
robertphillips4418dba2016-03-07 12:45:14 -0800586 REPORTER_ASSERT(reporter, negativeResult2);
587
robertphillips2302de92016-03-24 07:26:32 -0700588 sk_sp<SkSpecialImage> positiveResult2(negativeFilter->filterImage(imgSrc.get(),
589 negativeCTX,
590 &offset));
robertphillips4418dba2016-03-07 12:45:14 -0800591 REPORTER_ASSERT(reporter, positiveResult2);
592
593
594 SkBitmap positiveResultBM1, positiveResultBM2;
595 SkBitmap negativeResultBM1, negativeResultBM2;
596
robertphillips64612512016-04-08 12:10:42 -0700597 REPORTER_ASSERT(reporter, positiveResult1->getROPixels(&positiveResultBM1));
598 REPORTER_ASSERT(reporter, positiveResult2->getROPixels(&positiveResultBM2));
599 REPORTER_ASSERT(reporter, negativeResult1->getROPixels(&negativeResultBM1));
600 REPORTER_ASSERT(reporter, negativeResult2->getROPixels(&negativeResultBM2));
robertphillips4418dba2016-03-07 12:45:14 -0800601
senorblanco32673b92014-09-09 09:15:04 -0700602 for (int y = 0; y < height; y++) {
robertphillips4418dba2016-03-07 12:45:14 -0800603 int diffs = memcmp(positiveResultBM1.getAddr32(0, y),
604 negativeResultBM1.getAddr32(0, y),
605 positiveResultBM1.rowBytes());
senorblanco32673b92014-09-09 09:15:04 -0700606 REPORTER_ASSERT(reporter, !diffs);
607 if (diffs) {
608 break;
609 }
robertphillips4418dba2016-03-07 12:45:14 -0800610 diffs = memcmp(positiveResultBM1.getAddr32(0, y),
611 negativeResultBM2.getAddr32(0, y),
612 positiveResultBM1.rowBytes());
senorblanco32673b92014-09-09 09:15:04 -0700613 REPORTER_ASSERT(reporter, !diffs);
614 if (diffs) {
615 break;
616 }
robertphillips4418dba2016-03-07 12:45:14 -0800617 diffs = memcmp(positiveResultBM1.getAddr32(0, y),
618 positiveResultBM2.getAddr32(0, y),
619 positiveResultBM1.rowBytes());
senorblanco32673b92014-09-09 09:15:04 -0700620 REPORTER_ASSERT(reporter, !diffs);
621 if (diffs) {
622 break;
623 }
624 }
625}
626
senorblanco21a465d2016-04-11 11:58:39 -0700627DEF_TEST(ImageFilterNegativeBlurSigma, reporter) {
robertphillips3e302272016-04-20 11:48:36 -0700628 test_negative_blur_sigma(reporter, nullptr);
robertphillips4418dba2016-03-07 12:45:14 -0800629}
630
631#if SK_SUPPORT_GPU
bsalomon68d91342016-04-12 09:59:58 -0700632DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterNegativeBlurSigma_Gpu, reporter, ctxInfo) {
bsalomon8b7451a2016-05-11 06:33:06 -0700633 test_negative_blur_sigma(reporter, ctxInfo.grContext());
robertphillips4418dba2016-03-07 12:45:14 -0800634}
635#endif
636
robertphillips3e302272016-04-20 11:48:36 -0700637static void test_zero_blur_sigma(skiatest::Reporter* reporter, GrContext* context) {
senorblancobf680c32016-03-16 16:15:53 -0700638 // Check that SkBlurImageFilter with a zero sigma and a non-zero srcOffset works correctly.
639 SkImageFilter::CropRect cropRect(SkRect::Make(SkIRect::MakeXYWH(5, 0, 5, 10)));
robertphillips51a315e2016-03-31 09:05:49 -0700640 sk_sp<SkImageFilter> input(SkOffsetImageFilter::Make(0, 0, nullptr, &cropRect));
robertphillips6e7025a2016-04-04 04:31:25 -0700641 sk_sp<SkImageFilter> filter(SkBlurImageFilter::Make(0, 0, std::move(input), &cropRect));
senorblancobf680c32016-03-16 16:15:53 -0700642
robertphillips3e302272016-04-20 11:48:36 -0700643 sk_sp<SkSpecialSurface> surf(create_empty_special_surface(context, 10));
senorblancobf680c32016-03-16 16:15:53 -0700644 surf->getCanvas()->clear(SK_ColorGREEN);
robertphillips37bd7c32016-03-17 14:31:39 -0700645 sk_sp<SkSpecialImage> image(surf->makeImageSnapshot());
senorblancobf680c32016-03-16 16:15:53 -0700646
647 SkIPoint offset;
brianosman2a75e5d2016-09-22 07:15:37 -0700648 SkImageFilter::OutputProperties noColorSpace(nullptr);
649 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeWH(32, 32), nullptr, noColorSpace);
senorblancobf680c32016-03-16 16:15:53 -0700650
robertphillips2302de92016-03-24 07:26:32 -0700651 sk_sp<SkSpecialImage> result(filter->filterImage(image.get(), ctx, &offset));
senorblancobf680c32016-03-16 16:15:53 -0700652 REPORTER_ASSERT(reporter, offset.fX == 5 && offset.fY == 0);
653 REPORTER_ASSERT(reporter, result);
654 REPORTER_ASSERT(reporter, result->width() == 5 && result->height() == 10);
655
656 SkBitmap resultBM;
657
robertphillips64612512016-04-08 12:10:42 -0700658 REPORTER_ASSERT(reporter, result->getROPixels(&resultBM));
senorblancobf680c32016-03-16 16:15:53 -0700659
senorblancobf680c32016-03-16 16:15:53 -0700660 for (int y = 0; y < resultBM.height(); y++) {
661 for (int x = 0; x < resultBM.width(); x++) {
662 bool diff = *resultBM.getAddr32(x, y) != SK_ColorGREEN;
663 REPORTER_ASSERT(reporter, !diff);
664 if (diff) {
665 break;
666 }
667 }
668 }
669}
670
senorblanco21a465d2016-04-11 11:58:39 -0700671DEF_TEST(ImageFilterZeroBlurSigma, reporter) {
robertphillips3e302272016-04-20 11:48:36 -0700672 test_zero_blur_sigma(reporter, nullptr);
senorblancobf680c32016-03-16 16:15:53 -0700673}
674
675#if SK_SUPPORT_GPU
bsalomon68d91342016-04-12 09:59:58 -0700676DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterZeroBlurSigma_Gpu, reporter, ctxInfo) {
bsalomon8b7451a2016-05-11 06:33:06 -0700677 test_zero_blur_sigma(reporter, ctxInfo.grContext());
senorblancobf680c32016-03-16 16:15:53 -0700678}
679#endif
680
senorblanco6a93fa12016-04-05 04:43:45 -0700681
682// Tests that, even when an upstream filter has returned null (due to failure or clipping), a
683// downstream filter that affects transparent black still does so even with a nullptr input.
robertphillips3e302272016-04-20 11:48:36 -0700684static void test_fail_affects_transparent_black(skiatest::Reporter* reporter, GrContext* context) {
senorblanco6a93fa12016-04-05 04:43:45 -0700685 sk_sp<FailImageFilter> failFilter(new FailImageFilter());
robertphillips3e302272016-04-20 11:48:36 -0700686 sk_sp<SkSpecialImage> source(create_empty_special_image(context, 5));
brianosman2a75e5d2016-09-22 07:15:37 -0700687 SkImageFilter::OutputProperties noColorSpace(nullptr);
688 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeXYWH(0, 0, 1, 1), nullptr, noColorSpace);
Mike Reed7d954ad2016-10-28 15:42:34 -0400689 sk_sp<SkColorFilter> green(SkColorFilter::MakeModeFilter(SK_ColorGREEN, SkBlendMode::kSrc));
senorblanco6a93fa12016-04-05 04:43:45 -0700690 SkASSERT(green->affectsTransparentBlack());
robertphillips5605b562016-04-05 11:50:42 -0700691 sk_sp<SkImageFilter> greenFilter(SkColorFilterImageFilter::Make(std::move(green),
692 std::move(failFilter)));
senorblanco6a93fa12016-04-05 04:43:45 -0700693 SkIPoint offset;
694 sk_sp<SkSpecialImage> result(greenFilter->filterImage(source.get(), ctx, &offset));
695 REPORTER_ASSERT(reporter, nullptr != result.get());
696 if (result.get()) {
697 SkBitmap resultBM;
robertphillips64612512016-04-08 12:10:42 -0700698 REPORTER_ASSERT(reporter, result->getROPixels(&resultBM));
senorblanco6a93fa12016-04-05 04:43:45 -0700699 REPORTER_ASSERT(reporter, *resultBM.getAddr32(0, 0) == SK_ColorGREEN);
700 }
701}
702
703DEF_TEST(ImageFilterFailAffectsTransparentBlack, reporter) {
robertphillips3e302272016-04-20 11:48:36 -0700704 test_fail_affects_transparent_black(reporter, nullptr);
senorblanco6a93fa12016-04-05 04:43:45 -0700705}
706
707#if SK_SUPPORT_GPU
bsalomon68d91342016-04-12 09:59:58 -0700708DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterFailAffectsTransparentBlack_Gpu, reporter, ctxInfo) {
bsalomon8b7451a2016-05-11 06:33:06 -0700709 test_fail_affects_transparent_black(reporter, ctxInfo.grContext());
senorblanco6a93fa12016-04-05 04:43:45 -0700710}
711#endif
712
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +0000713DEF_TEST(ImageFilterDrawTiled, reporter) {
714 // Check that all filters when drawn tiled (with subsequent clip rects) exactly
715 // match the same filters drawn with a single full-canvas bitmap draw.
716 // Tests pass by not asserting.
717
robertphillipsfc11b0a2016-04-05 09:09:36 -0700718 FilterList filters(nullptr);
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +0000719
720 SkBitmap untiledResult, tiledResult;
reed5ea95df2015-10-06 14:05:32 -0700721 const int width = 64, height = 64;
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +0000722 untiledResult.allocN32Pixels(width, height);
723 tiledResult.allocN32Pixels(width, height);
724 SkCanvas tiledCanvas(tiledResult);
725 SkCanvas untiledCanvas(untiledResult);
senorblanco@chromium.orgd4db6572014-05-07 20:00:04 +0000726 int tileSize = 8;
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +0000727
senorblanco@chromium.orgd4db6572014-05-07 20:00:04 +0000728 for (int scale = 1; scale <= 2; ++scale) {
senorblanco297f7ce2016-03-23 13:44:26 -0700729 for (int i = 0; i < filters.count(); ++i) {
senorblanco@chromium.orgd4db6572014-05-07 20:00:04 +0000730 tiledCanvas.clear(0);
731 untiledCanvas.clear(0);
732 SkPaint paint;
Mike Reed5e257172016-11-01 11:22:05 -0400733 paint.setImageFilter(sk_ref_sp(filters.getFilter(i)));
senorblanco@chromium.orgd4db6572014-05-07 20:00:04 +0000734 paint.setTextSize(SkIntToScalar(height));
735 paint.setColor(SK_ColorWHITE);
736 SkString str;
737 const char* text = "ABC";
738 SkScalar ypos = SkIntToScalar(height);
739 untiledCanvas.save();
740 untiledCanvas.scale(SkIntToScalar(scale), SkIntToScalar(scale));
741 untiledCanvas.drawText(text, strlen(text), 0, ypos, paint);
742 untiledCanvas.restore();
743 for (int y = 0; y < height; y += tileSize) {
744 for (int x = 0; x < width; x += tileSize) {
745 tiledCanvas.save();
746 tiledCanvas.clipRect(SkRect::Make(SkIRect::MakeXYWH(x, y, tileSize, tileSize)));
747 tiledCanvas.scale(SkIntToScalar(scale), SkIntToScalar(scale));
748 tiledCanvas.drawText(text, strlen(text), 0, ypos, paint);
749 tiledCanvas.restore();
750 }
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +0000751 }
senorblanco@chromium.orgd4db6572014-05-07 20:00:04 +0000752 untiledCanvas.flush();
753 tiledCanvas.flush();
754 for (int y = 0; y < height; y++) {
755 int diffs = memcmp(untiledResult.getAddr32(0, y), tiledResult.getAddr32(0, y), untiledResult.rowBytes());
senorblanco297f7ce2016-03-23 13:44:26 -0700756 REPORTER_ASSERT_MESSAGE(reporter, !diffs, filters.getName(i));
senorblanco@chromium.orgd4db6572014-05-07 20:00:04 +0000757 if (diffs) {
758 break;
759 }
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +0000760 }
761 }
762 }
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +0000763}
764
mtklein3f3b3d02014-12-01 11:47:08 -0800765static void draw_saveLayer_picture(int width, int height, int tileSize,
robertphillipsa8d7f0b2014-08-29 08:03:56 -0700766 SkBBHFactory* factory, SkBitmap* result) {
mtkleind910f542014-08-22 09:06:34 -0700767
768 SkMatrix matrix;
769 matrix.setTranslate(SkIntToScalar(50), 0);
770
Mike Reed7d954ad2016-10-28 15:42:34 -0400771 sk_sp<SkColorFilter> cf(SkColorFilter::MakeModeFilter(SK_ColorWHITE, SkBlendMode::kSrc));
robertphillips5605b562016-04-05 11:50:42 -0700772 sk_sp<SkImageFilter> cfif(SkColorFilterImageFilter::Make(std::move(cf), nullptr));
robertphillipsae8c9332016-04-05 15:09:00 -0700773 sk_sp<SkImageFilter> imageFilter(SkImageFilter::MakeMatrixFilter(matrix,
774 kNone_SkFilterQuality,
775 std::move(cfif)));
mtkleind910f542014-08-22 09:06:34 -0700776
777 SkPaint paint;
robertphillips5605b562016-04-05 11:50:42 -0700778 paint.setImageFilter(std::move(imageFilter));
mtkleind910f542014-08-22 09:06:34 -0700779 SkPictureRecorder recorder;
780 SkRect bounds = SkRect::Make(SkIRect::MakeXYWH(0, 0, 50, 50));
mtklein3f3b3d02014-12-01 11:47:08 -0800781 SkCanvas* recordingCanvas = recorder.beginRecording(SkIntToScalar(width),
782 SkIntToScalar(height),
robertphillipsa8d7f0b2014-08-29 08:03:56 -0700783 factory, 0);
mtkleind910f542014-08-22 09:06:34 -0700784 recordingCanvas->translate(-55, 0);
785 recordingCanvas->saveLayer(&bounds, &paint);
786 recordingCanvas->restore();
reedca2622b2016-03-18 07:25:55 -0700787 sk_sp<SkPicture> picture1(recorder.finishRecordingAsPicture());
mtkleind910f542014-08-22 09:06:34 -0700788
789 result->allocN32Pixels(width, height);
790 SkCanvas canvas(*result);
791 canvas.clear(0);
792 canvas.clipRect(SkRect::Make(SkIRect::MakeWH(tileSize, tileSize)));
793 canvas.drawPicture(picture1.get());
794}
795
796DEF_TEST(ImageFilterDrawMatrixBBH, reporter) {
797 // Check that matrix filter when drawn tiled with BBH exactly
798 // matches the same thing drawn without BBH.
799 // Tests pass by not asserting.
800
801 const int width = 200, height = 200;
802 const int tileSize = 100;
803 SkBitmap result1, result2;
804 SkRTreeFactory factory;
805
robertphillipsa8d7f0b2014-08-29 08:03:56 -0700806 draw_saveLayer_picture(width, height, tileSize, &factory, &result1);
halcanary96fcdcc2015-08-27 07:41:13 -0700807 draw_saveLayer_picture(width, height, tileSize, nullptr, &result2);
mtkleind910f542014-08-22 09:06:34 -0700808
809 for (int y = 0; y < height; y++) {
810 int diffs = memcmp(result1.getAddr32(0, y), result2.getAddr32(0, y), result1.rowBytes());
811 REPORTER_ASSERT(reporter, !diffs);
812 if (diffs) {
813 break;
814 }
815 }
816}
817
robertphillips6e7025a2016-04-04 04:31:25 -0700818static sk_sp<SkImageFilter> make_blur(sk_sp<SkImageFilter> input) {
819 return SkBlurImageFilter::Make(SK_Scalar1, SK_Scalar1, std::move(input));
senorblanco1150a6d2014-08-25 12:46:58 -0700820}
821
robertphillips6e7025a2016-04-04 04:31:25 -0700822static sk_sp<SkImageFilter> make_drop_shadow(sk_sp<SkImageFilter> input) {
robertphillipsc4169122016-04-06 08:40:59 -0700823 return SkDropShadowImageFilter::Make(
senorblanco1150a6d2014-08-25 12:46:58 -0700824 SkIntToScalar(100), SkIntToScalar(100),
825 SkIntToScalar(10), SkIntToScalar(10),
sugoi234f0362014-10-23 13:59:52 -0700826 SK_ColorBLUE, SkDropShadowImageFilter::kDrawShadowAndForeground_ShadowMode,
robertphillipsc4169122016-04-06 08:40:59 -0700827 std::move(input));
senorblanco1150a6d2014-08-25 12:46:58 -0700828}
829
830DEF_TEST(ImageFilterBlurThenShadowBounds, reporter) {
robertphillips6e7025a2016-04-04 04:31:25 -0700831 sk_sp<SkImageFilter> filter1(make_blur(nullptr));
832 sk_sp<SkImageFilter> filter2(make_drop_shadow(std::move(filter1)));
senorblanco1150a6d2014-08-25 12:46:58 -0700833
834 SkIRect bounds = SkIRect::MakeXYWH(0, 0, 100, 100);
835 SkIRect expectedBounds = SkIRect::MakeXYWH(-133, -133, 236, 236);
senorblancoe5e79842016-03-21 14:51:59 -0700836 bounds = filter2->filterBounds(bounds, SkMatrix::I());
senorblanco1150a6d2014-08-25 12:46:58 -0700837
838 REPORTER_ASSERT(reporter, bounds == expectedBounds);
839}
840
841DEF_TEST(ImageFilterShadowThenBlurBounds, reporter) {
robertphillips6e7025a2016-04-04 04:31:25 -0700842 sk_sp<SkImageFilter> filter1(make_drop_shadow(nullptr));
843 sk_sp<SkImageFilter> filter2(make_blur(std::move(filter1)));
senorblanco1150a6d2014-08-25 12:46:58 -0700844
845 SkIRect bounds = SkIRect::MakeXYWH(0, 0, 100, 100);
846 SkIRect expectedBounds = SkIRect::MakeXYWH(-133, -133, 236, 236);
senorblancoe5e79842016-03-21 14:51:59 -0700847 bounds = filter2->filterBounds(bounds, SkMatrix::I());
senorblanco1150a6d2014-08-25 12:46:58 -0700848
849 REPORTER_ASSERT(reporter, bounds == expectedBounds);
850}
851
852DEF_TEST(ImageFilterDilateThenBlurBounds, reporter) {
robertphillipsfc11b0a2016-04-05 09:09:36 -0700853 sk_sp<SkImageFilter> filter1(SkDilateImageFilter::Make(2, 2, nullptr));
robertphillips6e7025a2016-04-04 04:31:25 -0700854 sk_sp<SkImageFilter> filter2(make_drop_shadow(std::move(filter1)));
senorblanco1150a6d2014-08-25 12:46:58 -0700855
856 SkIRect bounds = SkIRect::MakeXYWH(0, 0, 100, 100);
857 SkIRect expectedBounds = SkIRect::MakeXYWH(-132, -132, 234, 234);
senorblancoe5e79842016-03-21 14:51:59 -0700858 bounds = filter2->filterBounds(bounds, SkMatrix::I());
senorblanco1150a6d2014-08-25 12:46:58 -0700859
860 REPORTER_ASSERT(reporter, bounds == expectedBounds);
861}
862
jbroman203a9932016-07-11 14:07:59 -0700863DEF_TEST(ImageFilterScaledBlurRadius, reporter) {
864 // Each blur should spread 3*sigma, so 3 for the blur and 30 for the shadow
865 // (before the CTM). Bounds should be computed correctly in the presence of
866 // a (possibly negative) scale.
867 sk_sp<SkImageFilter> blur(make_blur(nullptr));
868 sk_sp<SkImageFilter> dropShadow(make_drop_shadow(nullptr));
869 {
870 // Uniform scale by 2.
871 SkMatrix scaleMatrix;
872 scaleMatrix.setScale(2, 2);
873 SkIRect bounds = SkIRect::MakeLTRB(0, 0, 200, 200);
874
875 SkIRect expectedBlurBounds = SkIRect::MakeLTRB(-6, -6, 206, 206);
876 SkIRect blurBounds = blur->filterBounds(
877 bounds, scaleMatrix, SkImageFilter::kForward_MapDirection);
878 REPORTER_ASSERT(reporter, blurBounds == expectedBlurBounds);
879 SkIRect reverseBlurBounds = blur->filterBounds(
880 bounds, scaleMatrix, SkImageFilter::kReverse_MapDirection);
881 REPORTER_ASSERT(reporter, reverseBlurBounds == expectedBlurBounds);
882
883 SkIRect expectedShadowBounds = SkIRect::MakeLTRB(0, 0, 460, 460);
884 SkIRect shadowBounds = dropShadow->filterBounds(
885 bounds, scaleMatrix, SkImageFilter::kForward_MapDirection);
886 REPORTER_ASSERT(reporter, shadowBounds == expectedShadowBounds);
887 SkIRect expectedReverseShadowBounds =
888 SkIRect::MakeLTRB(-260, -260, 200, 200);
889 SkIRect reverseShadowBounds = dropShadow->filterBounds(
890 bounds, scaleMatrix, SkImageFilter::kReverse_MapDirection);
891 REPORTER_ASSERT(reporter,
892 reverseShadowBounds == expectedReverseShadowBounds);
893 }
894 {
895 // Vertical flip.
896 SkMatrix scaleMatrix;
897 scaleMatrix.setScale(1, -1);
898 SkIRect bounds = SkIRect::MakeLTRB(0, -100, 100, 0);
899
900 SkIRect expectedBlurBounds = SkIRect::MakeLTRB(-3, -103, 103, 3);
901 SkIRect blurBounds = blur->filterBounds(
902 bounds, scaleMatrix, SkImageFilter::kForward_MapDirection);
903 REPORTER_ASSERT(reporter, blurBounds == expectedBlurBounds);
904 SkIRect reverseBlurBounds = blur->filterBounds(
905 bounds, scaleMatrix, SkImageFilter::kReverse_MapDirection);
906 REPORTER_ASSERT(reporter, reverseBlurBounds == expectedBlurBounds);
907
908 SkIRect expectedShadowBounds = SkIRect::MakeLTRB(0, -230, 230, 0);
909 SkIRect shadowBounds = dropShadow->filterBounds(
910 bounds, scaleMatrix, SkImageFilter::kForward_MapDirection);
911 REPORTER_ASSERT(reporter, shadowBounds == expectedShadowBounds);
912 SkIRect expectedReverseShadowBounds =
913 SkIRect::MakeLTRB(-130, -100, 100, 130);
914 SkIRect reverseShadowBounds = dropShadow->filterBounds(
915 bounds, scaleMatrix, SkImageFilter::kReverse_MapDirection);
916 REPORTER_ASSERT(reporter,
917 reverseShadowBounds == expectedReverseShadowBounds);
918 }
919}
920
ajuma5788faa2015-02-13 09:05:47 -0800921DEF_TEST(ImageFilterComposedBlurFastBounds, reporter) {
robertphillips6e7025a2016-04-04 04:31:25 -0700922 sk_sp<SkImageFilter> filter1(make_blur(nullptr));
923 sk_sp<SkImageFilter> filter2(make_blur(nullptr));
robertphillips491fb172016-03-30 12:32:58 -0700924 sk_sp<SkImageFilter> composedFilter(SkComposeImageFilter::Make(std::move(filter1),
925 std::move(filter2)));
ajuma5788faa2015-02-13 09:05:47 -0800926
927 SkRect boundsSrc = SkRect::MakeWH(SkIntToScalar(100), SkIntToScalar(100));
928 SkRect expectedBounds = SkRect::MakeXYWH(
929 SkIntToScalar(-6), SkIntToScalar(-6), SkIntToScalar(112), SkIntToScalar(112));
senorblancoe5e79842016-03-21 14:51:59 -0700930 SkRect boundsDst = composedFilter->computeFastBounds(boundsSrc);
ajuma5788faa2015-02-13 09:05:47 -0800931
932 REPORTER_ASSERT(reporter, boundsDst == expectedBounds);
933}
934
jbroman0e3129d2016-03-17 12:24:23 -0700935DEF_TEST(ImageFilterUnionBounds, reporter) {
robertphillips51a315e2016-03-31 09:05:49 -0700936 sk_sp<SkImageFilter> offset(SkOffsetImageFilter::Make(50, 0, nullptr));
jbroman0e3129d2016-03-17 12:24:23 -0700937 // Regardless of which order they appear in, the image filter bounds should
938 // be combined correctly.
939 {
reed374772b2016-10-05 17:33:02 -0700940 sk_sp<SkImageFilter> composite(SkXfermodeImageFilter::Make(SkBlendMode::kSrcOver, offset));
jbroman0e3129d2016-03-17 12:24:23 -0700941 SkRect bounds = SkRect::MakeWH(100, 100);
942 // Intentionally aliasing here, as that's what the real callers do.
senorblancoe5e79842016-03-21 14:51:59 -0700943 bounds = composite->computeFastBounds(bounds);
jbroman0e3129d2016-03-17 12:24:23 -0700944 REPORTER_ASSERT(reporter, bounds == SkRect::MakeWH(150, 100));
945 }
946 {
reed374772b2016-10-05 17:33:02 -0700947 sk_sp<SkImageFilter> composite(SkXfermodeImageFilter::Make(SkBlendMode::kSrcOver, nullptr,
robertphillips8c0326d2016-04-05 12:48:34 -0700948 offset, nullptr));
jbroman0e3129d2016-03-17 12:24:23 -0700949 SkRect bounds = SkRect::MakeWH(100, 100);
950 // Intentionally aliasing here, as that's what the real callers do.
senorblancoe5e79842016-03-21 14:51:59 -0700951 bounds = composite->computeFastBounds(bounds);
jbroman0e3129d2016-03-17 12:24:23 -0700952 REPORTER_ASSERT(reporter, bounds == SkRect::MakeWH(150, 100));
953 }
954}
955
robertphillips3e302272016-04-20 11:48:36 -0700956static void test_imagefilter_merge_result_size(skiatest::Reporter* reporter, GrContext* context) {
senorblanco4a243982015-11-25 07:06:55 -0800957 SkBitmap greenBM;
958 greenBM.allocN32Pixels(20, 20);
959 greenBM.eraseColor(SK_ColorGREEN);
reed9ce9d672016-03-17 10:51:11 -0700960 sk_sp<SkImage> greenImage(SkImage::MakeFromBitmap(greenBM));
robertphillips549c8992016-04-01 09:28:51 -0700961 sk_sp<SkImageFilter> source(SkImageSource::Make(std::move(greenImage)));
Mike Reed7d954ad2016-10-28 15:42:34 -0400962 sk_sp<SkImageFilter> merge(SkMergeImageFilter::Make(source, source, SkBlendMode::kSrcOver));
senorblanco4a243982015-11-25 07:06:55 -0800963
robertphillips3e302272016-04-20 11:48:36 -0700964 sk_sp<SkSpecialImage> srcImg(create_empty_special_image(context, 1));
robertphillips4418dba2016-03-07 12:45:14 -0800965
brianosman2a75e5d2016-09-22 07:15:37 -0700966 SkImageFilter::OutputProperties noColorSpace(nullptr);
967 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeXYWH(0, 0, 100, 100), nullptr,
968 noColorSpace);
senorblanco4a243982015-11-25 07:06:55 -0800969 SkIPoint offset;
robertphillips4418dba2016-03-07 12:45:14 -0800970
robertphillips2302de92016-03-24 07:26:32 -0700971 sk_sp<SkSpecialImage> resultImg(merge->filterImage(srcImg.get(), ctx, &offset));
robertphillips4418dba2016-03-07 12:45:14 -0800972 REPORTER_ASSERT(reporter, resultImg);
973
974 REPORTER_ASSERT(reporter, resultImg->width() == 20 && resultImg->height() == 20);
senorblanco4a243982015-11-25 07:06:55 -0800975}
976
robertphillips4418dba2016-03-07 12:45:14 -0800977DEF_TEST(ImageFilterMergeResultSize, reporter) {
robertphillips3e302272016-04-20 11:48:36 -0700978 test_imagefilter_merge_result_size(reporter, nullptr);
robertphillips4418dba2016-03-07 12:45:14 -0800979}
980
981#if SK_SUPPORT_GPU
egdanielab527a52016-06-28 08:07:26 -0700982DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterMergeResultSize_Gpu, reporter, ctxInfo) {
bsalomon8b7451a2016-05-11 06:33:06 -0700983 test_imagefilter_merge_result_size(reporter, ctxInfo.grContext());
robertphillips4418dba2016-03-07 12:45:14 -0800984}
985#endif
986
robertphillipsa8d7f0b2014-08-29 08:03:56 -0700987static void draw_blurred_rect(SkCanvas* canvas) {
senorblanco837f5322014-07-14 10:19:54 -0700988 SkPaint filterPaint;
989 filterPaint.setColor(SK_ColorWHITE);
robertphillips6e7025a2016-04-04 04:31:25 -0700990 filterPaint.setImageFilter(SkBlurImageFilter::Make(SkIntToScalar(8), 0, nullptr));
halcanary96fcdcc2015-08-27 07:41:13 -0700991 canvas->saveLayer(nullptr, &filterPaint);
senorblanco837f5322014-07-14 10:19:54 -0700992 SkPaint whitePaint;
993 whitePaint.setColor(SK_ColorWHITE);
994 canvas->drawRect(SkRect::Make(SkIRect::MakeWH(4, 4)), whitePaint);
995 canvas->restore();
996}
997
robertphillipsa8d7f0b2014-08-29 08:03:56 -0700998static void draw_picture_clipped(SkCanvas* canvas, const SkRect& clipRect, const SkPicture* picture) {
senorblanco837f5322014-07-14 10:19:54 -0700999 canvas->save();
1000 canvas->clipRect(clipRect);
1001 canvas->drawPicture(picture);
1002 canvas->restore();
1003}
1004
1005DEF_TEST(ImageFilterDrawTiledBlurRTree, reporter) {
1006 // Check that the blur filter when recorded with RTree acceleration,
1007 // and drawn tiled (with subsequent clip rects) exactly
1008 // matches the same filter drawn with without RTree acceleration.
1009 // This tests that the "bleed" from the blur into the otherwise-blank
1010 // tiles is correctly rendered.
1011 // Tests pass by not asserting.
1012
1013 int width = 16, height = 8;
1014 SkBitmap result1, result2;
1015 result1.allocN32Pixels(width, height);
1016 result2.allocN32Pixels(width, height);
1017 SkCanvas canvas1(result1);
1018 SkCanvas canvas2(result2);
1019 int tileSize = 8;
1020
1021 canvas1.clear(0);
1022 canvas2.clear(0);
1023
1024 SkRTreeFactory factory;
1025
1026 SkPictureRecorder recorder1, recorder2;
1027 // The only difference between these two pictures is that one has RTree aceleration.
mtklein3f3b3d02014-12-01 11:47:08 -08001028 SkCanvas* recordingCanvas1 = recorder1.beginRecording(SkIntToScalar(width),
1029 SkIntToScalar(height),
halcanary96fcdcc2015-08-27 07:41:13 -07001030 nullptr, 0);
mtklein3f3b3d02014-12-01 11:47:08 -08001031 SkCanvas* recordingCanvas2 = recorder2.beginRecording(SkIntToScalar(width),
1032 SkIntToScalar(height),
robertphillipsa8d7f0b2014-08-29 08:03:56 -07001033 &factory, 0);
1034 draw_blurred_rect(recordingCanvas1);
1035 draw_blurred_rect(recordingCanvas2);
reedca2622b2016-03-18 07:25:55 -07001036 sk_sp<SkPicture> picture1(recorder1.finishRecordingAsPicture());
1037 sk_sp<SkPicture> picture2(recorder2.finishRecordingAsPicture());
senorblanco837f5322014-07-14 10:19:54 -07001038 for (int y = 0; y < height; y += tileSize) {
1039 for (int x = 0; x < width; x += tileSize) {
1040 SkRect tileRect = SkRect::Make(SkIRect::MakeXYWH(x, y, tileSize, tileSize));
reedca2622b2016-03-18 07:25:55 -07001041 draw_picture_clipped(&canvas1, tileRect, picture1.get());
1042 draw_picture_clipped(&canvas2, tileRect, picture2.get());
senorblanco837f5322014-07-14 10:19:54 -07001043 }
1044 }
1045 for (int y = 0; y < height; y++) {
1046 int diffs = memcmp(result1.getAddr32(0, y), result2.getAddr32(0, y), result1.rowBytes());
1047 REPORTER_ASSERT(reporter, !diffs);
1048 if (diffs) {
1049 break;
1050 }
1051 }
1052}
1053
senorblanco@chromium.org91957432014-05-01 14:03:41 +00001054DEF_TEST(ImageFilterMatrixConvolution, reporter) {
1055 // Check that a 1x3 filter does not cause a spurious assert.
1056 SkScalar kernel[3] = {
1057 SkIntToScalar( 1), SkIntToScalar( 1), SkIntToScalar( 1),
1058 };
1059 SkISize kernelSize = SkISize::Make(1, 3);
1060 SkScalar gain = SK_Scalar1, bias = 0;
1061 SkIPoint kernelOffset = SkIPoint::Make(0, 0);
1062
robertphillipsef6a47b2016-04-08 08:01:20 -07001063 sk_sp<SkImageFilter> filter(SkMatrixConvolutionImageFilter::Make(
1064 kernelSize, kernel,
1065 gain, bias, kernelOffset,
1066 SkMatrixConvolutionImageFilter::kRepeat_TileMode,
1067 false, nullptr));
senorblanco@chromium.org91957432014-05-01 14:03:41 +00001068
1069 SkBitmap result;
1070 int width = 16, height = 16;
1071 result.allocN32Pixels(width, height);
1072 SkCanvas canvas(result);
1073 canvas.clear(0);
1074
1075 SkPaint paint;
robertphillipsef6a47b2016-04-08 08:01:20 -07001076 paint.setImageFilter(std::move(filter));
senorblanco@chromium.org91957432014-05-01 14:03:41 +00001077 SkRect rect = SkRect::Make(SkIRect::MakeWH(width, height));
1078 canvas.drawRect(rect, paint);
1079}
1080
senorblanco@chromium.org8c7372b2014-05-02 19:13:11 +00001081DEF_TEST(ImageFilterMatrixConvolutionBorder, reporter) {
1082 // Check that a filter with borders outside the target bounds
1083 // does not crash.
1084 SkScalar kernel[3] = {
1085 0, 0, 0,
1086 };
1087 SkISize kernelSize = SkISize::Make(3, 1);
1088 SkScalar gain = SK_Scalar1, bias = 0;
1089 SkIPoint kernelOffset = SkIPoint::Make(2, 0);
1090
robertphillipsef6a47b2016-04-08 08:01:20 -07001091 sk_sp<SkImageFilter> filter(SkMatrixConvolutionImageFilter::Make(
1092 kernelSize, kernel, gain, bias, kernelOffset,
1093 SkMatrixConvolutionImageFilter::kClamp_TileMode,
1094 true, nullptr));
senorblanco@chromium.org8c7372b2014-05-02 19:13:11 +00001095
1096 SkBitmap result;
1097
1098 int width = 10, height = 10;
1099 result.allocN32Pixels(width, height);
1100 SkCanvas canvas(result);
1101 canvas.clear(0);
1102
1103 SkPaint filterPaint;
robertphillipsef6a47b2016-04-08 08:01:20 -07001104 filterPaint.setImageFilter(std::move(filter));
senorblanco@chromium.org8c7372b2014-05-02 19:13:11 +00001105 SkRect bounds = SkRect::MakeWH(1, 10);
1106 SkRect rect = SkRect::Make(SkIRect::MakeWH(width, height));
1107 SkPaint rectPaint;
1108 canvas.saveLayer(&bounds, &filterPaint);
1109 canvas.drawRect(rect, rectPaint);
1110 canvas.restore();
1111}
1112
robertphillips3e302272016-04-20 11:48:36 -07001113static void test_big_kernel(skiatest::Reporter* reporter, GrContext* context) {
robertphillipsdada4dd2016-04-13 04:54:36 -07001114 // Check that a kernel that is too big for the GPU still works
1115 SkScalar identityKernel[49] = {
1116 0, 0, 0, 0, 0, 0, 0,
1117 0, 0, 0, 0, 0, 0, 0,
1118 0, 0, 0, 0, 0, 0, 0,
1119 0, 0, 0, 1, 0, 0, 0,
1120 0, 0, 0, 0, 0, 0, 0,
1121 0, 0, 0, 0, 0, 0, 0,
1122 0, 0, 0, 0, 0, 0, 0
1123 };
1124 SkISize kernelSize = SkISize::Make(7, 7);
1125 SkScalar gain = SK_Scalar1, bias = 0;
1126 SkIPoint kernelOffset = SkIPoint::Make(0, 0);
1127
1128 sk_sp<SkImageFilter> filter(SkMatrixConvolutionImageFilter::Make(
1129 kernelSize, identityKernel, gain, bias, kernelOffset,
1130 SkMatrixConvolutionImageFilter::kClamp_TileMode,
1131 true, nullptr));
1132
robertphillips3e302272016-04-20 11:48:36 -07001133 sk_sp<SkSpecialImage> srcImg(create_empty_special_image(context, 100));
robertphillipsdada4dd2016-04-13 04:54:36 -07001134 SkASSERT(srcImg);
1135
1136 SkIPoint offset;
brianosman2a75e5d2016-09-22 07:15:37 -07001137 SkImageFilter::OutputProperties noColorSpace(nullptr);
1138 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeWH(100, 100), nullptr, noColorSpace);
robertphillipsdada4dd2016-04-13 04:54:36 -07001139 sk_sp<SkSpecialImage> resultImg(filter->filterImage(srcImg.get(), ctx, &offset));
1140 REPORTER_ASSERT(reporter, resultImg);
1141 REPORTER_ASSERT(reporter, SkToBool(context) == resultImg->isTextureBacked());
1142 REPORTER_ASSERT(reporter, resultImg->width() == 100 && resultImg->height() == 100);
1143 REPORTER_ASSERT(reporter, offset.fX == 0 && offset.fY == 0);
1144}
1145
1146DEF_TEST(ImageFilterMatrixConvolutionBigKernel, reporter) {
robertphillips3e302272016-04-20 11:48:36 -07001147 test_big_kernel(reporter, nullptr);
robertphillipsdada4dd2016-04-13 04:54:36 -07001148}
1149
1150#if SK_SUPPORT_GPU
egdanielab527a52016-06-28 08:07:26 -07001151DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterMatrixConvolutionBigKernel_Gpu,
1152 reporter, ctxInfo) {
bsalomon8b7451a2016-05-11 06:33:06 -07001153 test_big_kernel(reporter, ctxInfo.grContext());
robertphillipsdada4dd2016-04-13 04:54:36 -07001154}
1155#endif
1156
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +00001157DEF_TEST(ImageFilterCropRect, reporter) {
robertphillips3e302272016-04-20 11:48:36 -07001158 test_crop_rects(reporter, nullptr);
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +00001159}
1160
robertphillips4418dba2016-03-07 12:45:14 -08001161#if SK_SUPPORT_GPU
bsalomon68d91342016-04-12 09:59:58 -07001162DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterCropRect_Gpu, reporter, ctxInfo) {
bsalomon8b7451a2016-05-11 06:33:06 -07001163 test_crop_rects(reporter, ctxInfo.grContext());
robertphillips4418dba2016-03-07 12:45:14 -08001164}
1165#endif
1166
tfarina9ea53f92014-06-24 06:50:39 -07001167DEF_TEST(ImageFilterMatrix, reporter) {
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +00001168 SkBitmap temp;
mike@reedtribe.orgdeee4962014-02-13 14:41:43 +00001169 temp.allocN32Pixels(100, 100);
robertphillips9a53fd72015-06-22 09:46:59 -07001170 SkCanvas canvas(temp);
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +00001171 canvas.scale(SkIntToScalar(2), SkIntToScalar(2));
1172
1173 SkMatrix expectedMatrix = canvas.getTotalMatrix();
1174
commit-bot@chromium.org5fb2ce32014-04-17 23:35:06 +00001175 SkRTreeFactory factory;
1176 SkPictureRecorder recorder;
1177 SkCanvas* recordingCanvas = recorder.beginRecording(100, 100, &factory, 0);
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +00001178
1179 SkPaint paint;
robertphillips43c2ad42016-04-04 05:05:11 -07001180 paint.setImageFilter(MatrixTestImageFilter::Make(reporter, expectedMatrix));
halcanary96fcdcc2015-08-27 07:41:13 -07001181 recordingCanvas->saveLayer(nullptr, &paint);
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +00001182 SkPaint solidPaint;
1183 solidPaint.setColor(0xFFFFFFFF);
1184 recordingCanvas->save();
1185 recordingCanvas->scale(SkIntToScalar(10), SkIntToScalar(10));
1186 recordingCanvas->drawRect(SkRect::Make(SkIRect::MakeWH(100, 100)), solidPaint);
1187 recordingCanvas->restore(); // scale
1188 recordingCanvas->restore(); // saveLayer
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +00001189
reedca2622b2016-03-18 07:25:55 -07001190 canvas.drawPicture(recorder.finishRecordingAsPicture());
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +00001191}
1192
senorblanco3d822c22014-07-30 14:49:31 -07001193DEF_TEST(ImageFilterCrossProcessPictureImageFilter, reporter) {
senorblanco@chromium.org97f5fc62014-05-30 20:50:56 +00001194 SkRTreeFactory factory;
1195 SkPictureRecorder recorder;
1196 SkCanvas* recordingCanvas = recorder.beginRecording(1, 1, &factory, 0);
1197
1198 // Create an SkPicture which simply draws a green 1x1 rectangle.
1199 SkPaint greenPaint;
1200 greenPaint.setColor(SK_ColorGREEN);
1201 recordingCanvas->drawRect(SkRect::Make(SkIRect::MakeWH(1, 1)), greenPaint);
reedca2622b2016-03-18 07:25:55 -07001202 sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture());
senorblanco@chromium.org97f5fc62014-05-30 20:50:56 +00001203
1204 // Wrap that SkPicture in an SkPictureImageFilter.
robertphillips5ff17b12016-03-28 13:13:42 -07001205 sk_sp<SkImageFilter> imageFilter(SkPictureImageFilter::Make(picture));
senorblanco@chromium.org97f5fc62014-05-30 20:50:56 +00001206
1207 // Check that SkPictureImageFilter successfully serializes its contained
1208 // SkPicture when not in cross-process mode.
1209 SkPaint paint;
robertphillips5ff17b12016-03-28 13:13:42 -07001210 paint.setImageFilter(imageFilter);
senorblanco@chromium.org97f5fc62014-05-30 20:50:56 +00001211 SkPictureRecorder outerRecorder;
1212 SkCanvas* outerCanvas = outerRecorder.beginRecording(1, 1, &factory, 0);
1213 SkPaint redPaintWithFilter;
1214 redPaintWithFilter.setColor(SK_ColorRED);
robertphillips5ff17b12016-03-28 13:13:42 -07001215 redPaintWithFilter.setImageFilter(imageFilter);
senorblanco@chromium.org97f5fc62014-05-30 20:50:56 +00001216 outerCanvas->drawRect(SkRect::Make(SkIRect::MakeWH(1, 1)), redPaintWithFilter);
reedca2622b2016-03-18 07:25:55 -07001217 sk_sp<SkPicture> outerPicture(outerRecorder.finishRecordingAsPicture());
senorblanco@chromium.org97f5fc62014-05-30 20:50:56 +00001218
1219 SkBitmap bitmap;
1220 bitmap.allocN32Pixels(1, 1);
robertphillips9a53fd72015-06-22 09:46:59 -07001221 SkCanvas canvas(bitmap);
senorblanco@chromium.org97f5fc62014-05-30 20:50:56 +00001222
1223 // The result here should be green, since the filter replaces the primitive's red interior.
1224 canvas.clear(0x0);
robertphillips9b14f262014-06-04 05:40:44 -07001225 canvas.drawPicture(outerPicture);
senorblanco@chromium.org97f5fc62014-05-30 20:50:56 +00001226 uint32_t pixel = *bitmap.getAddr32(0, 0);
1227 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1228
1229 // Check that, for now, SkPictureImageFilter does not serialize or
1230 // deserialize its contained picture when the filter is serialized
1231 // cross-process. Do this by "laundering" it through SkValidatingReadBuffer.
robertphillips12fa47d2016-04-08 16:28:09 -07001232 sk_sp<SkData> data(SkValidatingSerializeFlattenable(imageFilter.get()));
Mike Reed5e257172016-11-01 11:22:05 -04001233 sk_sp<SkImageFilter> unflattenedFilter = SkValidatingDeserializeImageFilter(data->data(),
1234 data->size());
senorblanco@chromium.org97f5fc62014-05-30 20:50:56 +00001235
1236 redPaintWithFilter.setImageFilter(unflattenedFilter);
1237 SkPictureRecorder crossProcessRecorder;
1238 SkCanvas* crossProcessCanvas = crossProcessRecorder.beginRecording(1, 1, &factory, 0);
1239 crossProcessCanvas->drawRect(SkRect::Make(SkIRect::MakeWH(1, 1)), redPaintWithFilter);
reedca2622b2016-03-18 07:25:55 -07001240 sk_sp<SkPicture> crossProcessPicture(crossProcessRecorder.finishRecordingAsPicture());
senorblanco@chromium.org97f5fc62014-05-30 20:50:56 +00001241
1242 canvas.clear(0x0);
robertphillips9b14f262014-06-04 05:40:44 -07001243 canvas.drawPicture(crossProcessPicture);
senorblanco@chromium.org97f5fc62014-05-30 20:50:56 +00001244 pixel = *bitmap.getAddr32(0, 0);
hendrikw446ee672015-06-16 09:28:37 -07001245 // If the security precautions are enabled, the result here should not be green, since the
1246 // filter draws nothing.
mtklein2afbe232016-02-07 12:23:10 -08001247 REPORTER_ASSERT(reporter, SkPicture::PictureIOSecurityPrecautionsEnabled()
hendrikw446ee672015-06-16 09:28:37 -07001248 ? pixel != SK_ColorGREEN : pixel == SK_ColorGREEN);
senorblanco@chromium.org97f5fc62014-05-30 20:50:56 +00001249}
1250
robertphillips3e302272016-04-20 11:48:36 -07001251static void test_clipped_picture_imagefilter(skiatest::Reporter* reporter, GrContext* context) {
reedca2622b2016-03-18 07:25:55 -07001252 sk_sp<SkPicture> picture;
senorblanco3d822c22014-07-30 14:49:31 -07001253
robertphillips4418dba2016-03-07 12:45:14 -08001254 {
1255 SkRTreeFactory factory;
1256 SkPictureRecorder recorder;
1257 SkCanvas* recordingCanvas = recorder.beginRecording(1, 1, &factory, 0);
1258
1259 // Create an SkPicture which simply draws a green 1x1 rectangle.
1260 SkPaint greenPaint;
1261 greenPaint.setColor(SK_ColorGREEN);
1262 recordingCanvas->drawRect(SkRect::Make(SkIRect::MakeWH(1, 1)), greenPaint);
reedca2622b2016-03-18 07:25:55 -07001263 picture = recorder.finishRecordingAsPicture();
robertphillips4418dba2016-03-07 12:45:14 -08001264 }
1265
robertphillips3e302272016-04-20 11:48:36 -07001266 sk_sp<SkSpecialImage> srcImg(create_empty_special_image(context, 2));
senorblanco3d822c22014-07-30 14:49:31 -07001267
robertphillips5ff17b12016-03-28 13:13:42 -07001268 sk_sp<SkImageFilter> imageFilter(SkPictureImageFilter::Make(picture));
senorblanco3d822c22014-07-30 14:49:31 -07001269
senorblanco3d822c22014-07-30 14:49:31 -07001270 SkIPoint offset;
brianosman2a75e5d2016-09-22 07:15:37 -07001271 SkImageFilter::OutputProperties noColorSpace(nullptr);
1272 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeXYWH(1, 1, 1, 1), nullptr, noColorSpace);
robertphillips4418dba2016-03-07 12:45:14 -08001273
robertphillips2302de92016-03-24 07:26:32 -07001274 sk_sp<SkSpecialImage> resultImage(imageFilter->filterImage(srcImg.get(), ctx, &offset));
robertphillips4418dba2016-03-07 12:45:14 -08001275 REPORTER_ASSERT(reporter, !resultImage);
senorblanco3d822c22014-07-30 14:49:31 -07001276}
1277
robertphillips4418dba2016-03-07 12:45:14 -08001278DEF_TEST(ImageFilterClippedPictureImageFilter, reporter) {
robertphillips3e302272016-04-20 11:48:36 -07001279 test_clipped_picture_imagefilter(reporter, nullptr);
robertphillips4418dba2016-03-07 12:45:14 -08001280}
1281
1282#if SK_SUPPORT_GPU
bsalomon68d91342016-04-12 09:59:58 -07001283DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterClippedPictureImageFilter_Gpu, reporter, ctxInfo) {
bsalomon8b7451a2016-05-11 06:33:06 -07001284 test_clipped_picture_imagefilter(reporter, ctxInfo.grContext());
robertphillips4418dba2016-03-07 12:45:14 -08001285}
1286#endif
1287
tfarina9ea53f92014-06-24 06:50:39 -07001288DEF_TEST(ImageFilterEmptySaveLayer, reporter) {
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001289 // Even when there's an empty saveLayer()/restore(), ensure that an image
1290 // filter or color filter which affects transparent black still draws.
1291
1292 SkBitmap bitmap;
1293 bitmap.allocN32Pixels(10, 10);
robertphillips9a53fd72015-06-22 09:46:59 -07001294 SkCanvas canvas(bitmap);
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001295
1296 SkRTreeFactory factory;
1297 SkPictureRecorder recorder;
1298
robertphillips5605b562016-04-05 11:50:42 -07001299 sk_sp<SkColorFilter> green(SkColorFilter::MakeModeFilter(SK_ColorGREEN,
Mike Reed7d954ad2016-10-28 15:42:34 -04001300 SkBlendMode::kSrc));
robertphillips5605b562016-04-05 11:50:42 -07001301 sk_sp<SkImageFilter> imageFilter(SkColorFilterImageFilter::Make(green, nullptr));
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001302 SkPaint imageFilterPaint;
robertphillips5605b562016-04-05 11:50:42 -07001303 imageFilterPaint.setImageFilter(std::move(imageFilter));
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001304 SkPaint colorFilterPaint;
reedd053ce92016-03-22 10:17:23 -07001305 colorFilterPaint.setColorFilter(green);
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001306
1307 SkRect bounds = SkRect::MakeWH(10, 10);
1308
1309 SkCanvas* recordingCanvas = recorder.beginRecording(10, 10, &factory, 0);
1310 recordingCanvas->saveLayer(&bounds, &imageFilterPaint);
1311 recordingCanvas->restore();
reedca2622b2016-03-18 07:25:55 -07001312 sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture());
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001313
1314 canvas.clear(0);
robertphillips9b14f262014-06-04 05:40:44 -07001315 canvas.drawPicture(picture);
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001316 uint32_t pixel = *bitmap.getAddr32(0, 0);
1317 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1318
1319 recordingCanvas = recorder.beginRecording(10, 10, &factory, 0);
halcanary96fcdcc2015-08-27 07:41:13 -07001320 recordingCanvas->saveLayer(nullptr, &imageFilterPaint);
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001321 recordingCanvas->restore();
reedca2622b2016-03-18 07:25:55 -07001322 sk_sp<SkPicture> picture2(recorder.finishRecordingAsPicture());
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001323
1324 canvas.clear(0);
robertphillips9b14f262014-06-04 05:40:44 -07001325 canvas.drawPicture(picture2);
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001326 pixel = *bitmap.getAddr32(0, 0);
1327 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1328
1329 recordingCanvas = recorder.beginRecording(10, 10, &factory, 0);
1330 recordingCanvas->saveLayer(&bounds, &colorFilterPaint);
1331 recordingCanvas->restore();
reedca2622b2016-03-18 07:25:55 -07001332 sk_sp<SkPicture> picture3(recorder.finishRecordingAsPicture());
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001333
1334 canvas.clear(0);
robertphillips9b14f262014-06-04 05:40:44 -07001335 canvas.drawPicture(picture3);
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001336 pixel = *bitmap.getAddr32(0, 0);
1337 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1338}
1339
robertphillips9a53fd72015-06-22 09:46:59 -07001340static void test_huge_blur(SkCanvas* canvas, skiatest::Reporter* reporter) {
senorblanco@chromium.org09843fd2014-03-24 20:50:59 +00001341 SkBitmap bitmap;
1342 bitmap.allocN32Pixels(100, 100);
1343 bitmap.eraseARGB(0, 0, 0, 0);
1344
1345 // Check that a blur with an insane radius does not crash or assert.
senorblanco@chromium.org09843fd2014-03-24 20:50:59 +00001346 SkPaint paint;
robertphillips6e7025a2016-04-04 04:31:25 -07001347 paint.setImageFilter(SkBlurImageFilter::Make(SkIntToScalar(1<<30),
1348 SkIntToScalar(1<<30),
1349 nullptr));
reedda420b92015-12-16 08:38:15 -08001350 canvas->drawBitmap(bitmap, 0, 0, &paint);
senorblanco@chromium.org09843fd2014-03-24 20:50:59 +00001351}
1352
1353DEF_TEST(HugeBlurImageFilter, reporter) {
1354 SkBitmap temp;
1355 temp.allocN32Pixels(100, 100);
robertphillips9a53fd72015-06-22 09:46:59 -07001356 SkCanvas canvas(temp);
1357 test_huge_blur(&canvas, reporter);
senorblanco@chromium.org09843fd2014-03-24 20:50:59 +00001358}
1359
senorblanco21a465d2016-04-11 11:58:39 -07001360DEF_TEST(ImageFilterMatrixConvolutionSanityTest, reporter) {
senorblanco3a495202014-09-29 07:57:20 -07001361 SkScalar kernel[1] = { 0 };
1362 SkScalar gain = SK_Scalar1, bias = 0;
1363 SkIPoint kernelOffset = SkIPoint::Make(1, 1);
1364
halcanary96fcdcc2015-08-27 07:41:13 -07001365 // Check that an enormous (non-allocatable) kernel gives a nullptr filter.
robertphillipsef6a47b2016-04-08 08:01:20 -07001366 sk_sp<SkImageFilter> conv(SkMatrixConvolutionImageFilter::Make(
senorblanco3a495202014-09-29 07:57:20 -07001367 SkISize::Make(1<<30, 1<<30),
1368 kernel,
1369 gain,
1370 bias,
1371 kernelOffset,
1372 SkMatrixConvolutionImageFilter::kRepeat_TileMode,
robertphillipsef6a47b2016-04-08 08:01:20 -07001373 false,
1374 nullptr));
senorblanco3a495202014-09-29 07:57:20 -07001375
halcanary96fcdcc2015-08-27 07:41:13 -07001376 REPORTER_ASSERT(reporter, nullptr == conv.get());
senorblanco3a495202014-09-29 07:57:20 -07001377
halcanary96fcdcc2015-08-27 07:41:13 -07001378 // Check that a nullptr kernel gives a nullptr filter.
robertphillipsef6a47b2016-04-08 08:01:20 -07001379 conv = SkMatrixConvolutionImageFilter::Make(
senorblanco3a495202014-09-29 07:57:20 -07001380 SkISize::Make(1, 1),
halcanary96fcdcc2015-08-27 07:41:13 -07001381 nullptr,
senorblanco3a495202014-09-29 07:57:20 -07001382 gain,
1383 bias,
1384 kernelOffset,
1385 SkMatrixConvolutionImageFilter::kRepeat_TileMode,
robertphillipsef6a47b2016-04-08 08:01:20 -07001386 false,
1387 nullptr);
senorblanco3a495202014-09-29 07:57:20 -07001388
halcanary96fcdcc2015-08-27 07:41:13 -07001389 REPORTER_ASSERT(reporter, nullptr == conv.get());
senorblanco3a495202014-09-29 07:57:20 -07001390
halcanary96fcdcc2015-08-27 07:41:13 -07001391 // Check that a kernel width < 1 gives a nullptr filter.
robertphillipsef6a47b2016-04-08 08:01:20 -07001392 conv = SkMatrixConvolutionImageFilter::Make(
senorblanco3a495202014-09-29 07:57:20 -07001393 SkISize::Make(0, 1),
1394 kernel,
1395 gain,
1396 bias,
1397 kernelOffset,
1398 SkMatrixConvolutionImageFilter::kRepeat_TileMode,
robertphillipsef6a47b2016-04-08 08:01:20 -07001399 false,
1400 nullptr);
senorblanco3a495202014-09-29 07:57:20 -07001401
halcanary96fcdcc2015-08-27 07:41:13 -07001402 REPORTER_ASSERT(reporter, nullptr == conv.get());
senorblanco3a495202014-09-29 07:57:20 -07001403
halcanary96fcdcc2015-08-27 07:41:13 -07001404 // Check that kernel height < 1 gives a nullptr filter.
robertphillipsef6a47b2016-04-08 08:01:20 -07001405 conv = SkMatrixConvolutionImageFilter::Make(
senorblanco3a495202014-09-29 07:57:20 -07001406 SkISize::Make(1, -1),
1407 kernel,
1408 gain,
1409 bias,
1410 kernelOffset,
1411 SkMatrixConvolutionImageFilter::kRepeat_TileMode,
robertphillipsef6a47b2016-04-08 08:01:20 -07001412 false,
1413 nullptr);
senorblanco3a495202014-09-29 07:57:20 -07001414
halcanary96fcdcc2015-08-27 07:41:13 -07001415 REPORTER_ASSERT(reporter, nullptr == conv.get());
senorblanco3a495202014-09-29 07:57:20 -07001416}
1417
robertphillips9a53fd72015-06-22 09:46:59 -07001418static void test_xfermode_cropped_input(SkCanvas* canvas, skiatest::Reporter* reporter) {
1419 canvas->clear(0);
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001420
1421 SkBitmap bitmap;
1422 bitmap.allocN32Pixels(1, 1);
1423 bitmap.eraseARGB(255, 255, 255, 255);
1424
robertphillips5605b562016-04-05 11:50:42 -07001425 sk_sp<SkColorFilter> green(SkColorFilter::MakeModeFilter(SK_ColorGREEN,
Mike Reed7d954ad2016-10-28 15:42:34 -04001426 SkBlendMode::kSrcIn));
robertphillips5605b562016-04-05 11:50:42 -07001427 sk_sp<SkImageFilter> greenFilter(SkColorFilterImageFilter::Make(green, nullptr));
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001428 SkImageFilter::CropRect cropRect(SkRect::MakeEmpty());
robertphillips5605b562016-04-05 11:50:42 -07001429 sk_sp<SkImageFilter> croppedOut(SkColorFilterImageFilter::Make(green, nullptr, &cropRect));
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001430
1431 // Check that an xfermode image filter whose input has been cropped out still draws the other
1432 // input. Also check that drawing with both inputs cropped out doesn't cause a GPU warning.
reed374772b2016-10-05 17:33:02 -07001433 SkBlendMode mode = SkBlendMode::kSrcOver;
robertphillips8c0326d2016-04-05 12:48:34 -07001434 sk_sp<SkImageFilter> xfermodeNoFg(SkXfermodeImageFilter::Make(mode, greenFilter,
1435 croppedOut, nullptr));
1436 sk_sp<SkImageFilter> xfermodeNoBg(SkXfermodeImageFilter::Make(mode, croppedOut,
1437 greenFilter, nullptr));
1438 sk_sp<SkImageFilter> xfermodeNoFgNoBg(SkXfermodeImageFilter::Make(mode, croppedOut,
1439 croppedOut, nullptr));
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001440
1441 SkPaint paint;
robertphillips8c0326d2016-04-05 12:48:34 -07001442 paint.setImageFilter(std::move(xfermodeNoFg));
reedda420b92015-12-16 08:38:15 -08001443 canvas->drawBitmap(bitmap, 0, 0, &paint); // drawSprite
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001444
1445 uint32_t pixel;
kkinnunena9d9a392015-03-06 07:16:00 -08001446 SkImageInfo info = SkImageInfo::Make(1, 1, kBGRA_8888_SkColorType, kUnpremul_SkAlphaType);
robertphillips9a53fd72015-06-22 09:46:59 -07001447 canvas->readPixels(info, &pixel, 4, 0, 0);
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001448 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1449
robertphillips8c0326d2016-04-05 12:48:34 -07001450 paint.setImageFilter(std::move(xfermodeNoBg));
reedda420b92015-12-16 08:38:15 -08001451 canvas->drawBitmap(bitmap, 0, 0, &paint); // drawSprite
robertphillips9a53fd72015-06-22 09:46:59 -07001452 canvas->readPixels(info, &pixel, 4, 0, 0);
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001453 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1454
robertphillips8c0326d2016-04-05 12:48:34 -07001455 paint.setImageFilter(std::move(xfermodeNoFgNoBg));
reedda420b92015-12-16 08:38:15 -08001456 canvas->drawBitmap(bitmap, 0, 0, &paint); // drawSprite
robertphillips9a53fd72015-06-22 09:46:59 -07001457 canvas->readPixels(info, &pixel, 4, 0, 0);
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001458 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1459}
1460
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001461DEF_TEST(ImageFilterNestedSaveLayer, reporter) {
1462 SkBitmap temp;
1463 temp.allocN32Pixels(50, 50);
robertphillips9a53fd72015-06-22 09:46:59 -07001464 SkCanvas canvas(temp);
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001465 canvas.clear(0x0);
1466
1467 SkBitmap bitmap;
1468 bitmap.allocN32Pixels(10, 10);
1469 bitmap.eraseColor(SK_ColorGREEN);
1470
1471 SkMatrix matrix;
1472 matrix.setScale(SkIntToScalar(2), SkIntToScalar(2));
1473 matrix.postTranslate(SkIntToScalar(-20), SkIntToScalar(-20));
robertphillipsae8c9332016-04-05 15:09:00 -07001474 sk_sp<SkImageFilter> matrixFilter(
1475 SkImageFilter::MakeMatrixFilter(matrix, kLow_SkFilterQuality, nullptr));
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001476
1477 // Test that saveLayer() with a filter nested inside another saveLayer() applies the
1478 // correct offset to the filter matrix.
1479 SkRect bounds1 = SkRect::MakeXYWH(10, 10, 30, 30);
halcanary96fcdcc2015-08-27 07:41:13 -07001480 canvas.saveLayer(&bounds1, nullptr);
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001481 SkPaint filterPaint;
robertphillipsae8c9332016-04-05 15:09:00 -07001482 filterPaint.setImageFilter(std::move(matrixFilter));
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001483 SkRect bounds2 = SkRect::MakeXYWH(20, 20, 10, 10);
1484 canvas.saveLayer(&bounds2, &filterPaint);
1485 SkPaint greenPaint;
1486 greenPaint.setColor(SK_ColorGREEN);
1487 canvas.drawRect(bounds2, greenPaint);
1488 canvas.restore();
1489 canvas.restore();
1490 SkPaint strokePaint;
1491 strokePaint.setStyle(SkPaint::kStroke_Style);
1492 strokePaint.setColor(SK_ColorRED);
1493
kkinnunena9d9a392015-03-06 07:16:00 -08001494 SkImageInfo info = SkImageInfo::Make(1, 1, kBGRA_8888_SkColorType, kUnpremul_SkAlphaType);
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001495 uint32_t pixel;
1496 canvas.readPixels(info, &pixel, 4, 25, 25);
1497 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1498
1499 // Test that drawSprite() with a filter nested inside a saveLayer() applies the
1500 // correct offset to the filter matrix.
1501 canvas.clear(0x0);
1502 canvas.readPixels(info, &pixel, 4, 25, 25);
halcanary96fcdcc2015-08-27 07:41:13 -07001503 canvas.saveLayer(&bounds1, nullptr);
reedda420b92015-12-16 08:38:15 -08001504 canvas.drawBitmap(bitmap, 20, 20, &filterPaint); // drawSprite
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001505 canvas.restore();
1506
1507 canvas.readPixels(info, &pixel, 4, 25, 25);
1508 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1509}
1510
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001511DEF_TEST(XfermodeImageFilterCroppedInput, reporter) {
1512 SkBitmap temp;
1513 temp.allocN32Pixels(100, 100);
robertphillips9a53fd72015-06-22 09:46:59 -07001514 SkCanvas canvas(temp);
1515 test_xfermode_cropped_input(&canvas, reporter);
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001516}
senorblanco@chromium.org09843fd2014-03-24 20:50:59 +00001517
robertphillips3e302272016-04-20 11:48:36 -07001518static void test_composed_imagefilter_offset(skiatest::Reporter* reporter, GrContext* context) {
1519 sk_sp<SkSpecialImage> srcImg(create_empty_special_image(context, 100));
ajuma5788faa2015-02-13 09:05:47 -08001520
1521 SkImageFilter::CropRect cropRect(SkRect::MakeXYWH(1, 0, 20, 20));
robertphillips51a315e2016-03-31 09:05:49 -07001522 sk_sp<SkImageFilter> offsetFilter(SkOffsetImageFilter::Make(0, 0, nullptr, &cropRect));
robertphillips6e7025a2016-04-04 04:31:25 -07001523 sk_sp<SkImageFilter> blurFilter(SkBlurImageFilter::Make(SK_Scalar1, SK_Scalar1,
1524 nullptr, &cropRect));
robertphillips491fb172016-03-30 12:32:58 -07001525 sk_sp<SkImageFilter> composedFilter(SkComposeImageFilter::Make(std::move(blurFilter),
1526 std::move(offsetFilter)));
ajuma5788faa2015-02-13 09:05:47 -08001527 SkIPoint offset;
brianosman2a75e5d2016-09-22 07:15:37 -07001528 SkImageFilter::OutputProperties noColorSpace(nullptr);
1529 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeWH(100, 100), nullptr, noColorSpace);
robertphillips4418dba2016-03-07 12:45:14 -08001530
robertphillips2302de92016-03-24 07:26:32 -07001531 sk_sp<SkSpecialImage> resultImg(composedFilter->filterImage(srcImg.get(), ctx, &offset));
robertphillips4418dba2016-03-07 12:45:14 -08001532 REPORTER_ASSERT(reporter, resultImg);
ajuma5788faa2015-02-13 09:05:47 -08001533 REPORTER_ASSERT(reporter, offset.fX == 1 && offset.fY == 0);
1534}
1535
robertphillips4418dba2016-03-07 12:45:14 -08001536DEF_TEST(ComposedImageFilterOffset, reporter) {
robertphillips3e302272016-04-20 11:48:36 -07001537 test_composed_imagefilter_offset(reporter, nullptr);
robertphillips4418dba2016-03-07 12:45:14 -08001538}
1539
1540#if SK_SUPPORT_GPU
bsalomon68d91342016-04-12 09:59:58 -07001541DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ComposedImageFilterOffset_Gpu, reporter, ctxInfo) {
bsalomon8b7451a2016-05-11 06:33:06 -07001542 test_composed_imagefilter_offset(reporter, ctxInfo.grContext());
robertphillips4418dba2016-03-07 12:45:14 -08001543}
1544#endif
1545
robertphillips3e302272016-04-20 11:48:36 -07001546static void test_composed_imagefilter_bounds(skiatest::Reporter* reporter, GrContext* context) {
jbroman17a65202016-03-21 08:38:58 -07001547 // The bounds passed to the inner filter must be filtered by the outer
1548 // filter, so that the inner filter produces the pixels that the outer
1549 // filter requires as input. This matters if the outer filter moves pixels.
1550 // Here, accounting for the outer offset is necessary so that the green
1551 // pixels of the picture are not clipped.
1552
1553 SkPictureRecorder recorder;
1554 SkCanvas* recordingCanvas = recorder.beginRecording(SkRect::MakeWH(200, 100));
1555 recordingCanvas->clipRect(SkRect::MakeXYWH(100, 0, 100, 100));
1556 recordingCanvas->clear(SK_ColorGREEN);
robertphillips491fb172016-03-30 12:32:58 -07001557 sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture());
robertphillips5ff17b12016-03-28 13:13:42 -07001558 sk_sp<SkImageFilter> pictureFilter(SkPictureImageFilter::Make(picture));
jbroman17a65202016-03-21 08:38:58 -07001559 SkImageFilter::CropRect cropRect(SkRect::MakeWH(100, 100));
robertphillips51a315e2016-03-31 09:05:49 -07001560 sk_sp<SkImageFilter> offsetFilter(SkOffsetImageFilter::Make(-100, 0, nullptr, &cropRect));
robertphillips491fb172016-03-30 12:32:58 -07001561 sk_sp<SkImageFilter> composedFilter(SkComposeImageFilter::Make(std::move(offsetFilter),
1562 std::move(pictureFilter)));
jbroman17a65202016-03-21 08:38:58 -07001563
robertphillips3e302272016-04-20 11:48:36 -07001564 sk_sp<SkSpecialImage> sourceImage(create_empty_special_image(context, 100));
brianosman2a75e5d2016-09-22 07:15:37 -07001565 SkImageFilter::OutputProperties noColorSpace(nullptr);
1566 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeWH(100, 100), nullptr, noColorSpace);
jbroman17a65202016-03-21 08:38:58 -07001567 SkIPoint offset;
1568 sk_sp<SkSpecialImage> result(composedFilter->filterImage(sourceImage.get(), ctx, &offset));
1569 REPORTER_ASSERT(reporter, offset.isZero());
1570 REPORTER_ASSERT(reporter, result);
1571 REPORTER_ASSERT(reporter, result->subset().size() == SkISize::Make(100, 100));
1572
1573 SkBitmap resultBM;
robertphillips64612512016-04-08 12:10:42 -07001574 REPORTER_ASSERT(reporter, result->getROPixels(&resultBM));
jbroman17a65202016-03-21 08:38:58 -07001575 REPORTER_ASSERT(reporter, resultBM.getColor(50, 50) == SK_ColorGREEN);
1576}
1577
1578DEF_TEST(ComposedImageFilterBounds, reporter) {
robertphillips3e302272016-04-20 11:48:36 -07001579 test_composed_imagefilter_bounds(reporter, nullptr);
jbroman17a65202016-03-21 08:38:58 -07001580}
1581
1582#if SK_SUPPORT_GPU
egdanielab527a52016-06-28 08:07:26 -07001583DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ComposedImageFilterBounds_Gpu, reporter, ctxInfo) {
bsalomon8b7451a2016-05-11 06:33:06 -07001584 test_composed_imagefilter_bounds(reporter, ctxInfo.grContext());
jbroman17a65202016-03-21 08:38:58 -07001585}
1586#endif
1587
robertphillips3e302272016-04-20 11:48:36 -07001588static void test_partial_crop_rect(skiatest::Reporter* reporter, GrContext* context) {
1589 sk_sp<SkSpecialImage> srcImg(create_empty_special_image(context, 100));
senorblanco24d2a7b2015-07-13 10:27:05 -07001590
1591 SkImageFilter::CropRect cropRect(SkRect::MakeXYWH(100, 0, 20, 30),
senorblancoed7cf272015-07-16 15:19:11 -07001592 SkImageFilter::CropRect::kHasWidth_CropEdge | SkImageFilter::CropRect::kHasHeight_CropEdge);
robertphillips5605b562016-04-05 11:50:42 -07001593 sk_sp<SkImageFilter> filter(make_grayscale(nullptr, &cropRect));
senorblanco24d2a7b2015-07-13 10:27:05 -07001594 SkIPoint offset;
brianosman2a75e5d2016-09-22 07:15:37 -07001595 SkImageFilter::OutputProperties noColorSpace(nullptr);
1596 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeWH(100, 100), nullptr, noColorSpace);
robertphillips4418dba2016-03-07 12:45:14 -08001597
robertphillips2302de92016-03-24 07:26:32 -07001598 sk_sp<SkSpecialImage> resultImg(filter->filterImage(srcImg.get(), ctx, &offset));
robertphillips4418dba2016-03-07 12:45:14 -08001599 REPORTER_ASSERT(reporter, resultImg);
1600
senorblanco24d2a7b2015-07-13 10:27:05 -07001601 REPORTER_ASSERT(reporter, offset.fX == 0);
1602 REPORTER_ASSERT(reporter, offset.fY == 0);
robertphillips4418dba2016-03-07 12:45:14 -08001603 REPORTER_ASSERT(reporter, resultImg->width() == 20);
1604 REPORTER_ASSERT(reporter, resultImg->height() == 30);
senorblanco24d2a7b2015-07-13 10:27:05 -07001605}
1606
senorblanco21a465d2016-04-11 11:58:39 -07001607DEF_TEST(ImageFilterPartialCropRect, reporter) {
robertphillips3e302272016-04-20 11:48:36 -07001608 test_partial_crop_rect(reporter, nullptr);
robertphillips4418dba2016-03-07 12:45:14 -08001609}
1610
1611#if SK_SUPPORT_GPU
bsalomon68d91342016-04-12 09:59:58 -07001612DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterPartialCropRect_Gpu, reporter, ctxInfo) {
bsalomon8b7451a2016-05-11 06:33:06 -07001613 test_partial_crop_rect(reporter, ctxInfo.grContext());
robertphillips4418dba2016-03-07 12:45:14 -08001614}
1615#endif
1616
senorblanco0abdf762015-08-20 11:10:41 -07001617DEF_TEST(ImageFilterCanComputeFastBounds, reporter) {
1618
robertphillips12fa47d2016-04-08 16:28:09 -07001619 {
1620 SkPoint3 location = SkPoint3::Make(0, 0, SK_Scalar1);
1621 sk_sp<SkImageFilter> lighting(SkLightingImageFilter::MakePointLitDiffuse(location,
1622 SK_ColorGREEN,
1623 0, 0, nullptr));
1624 REPORTER_ASSERT(reporter, !lighting->canComputeFastBounds());
1625 }
senorblanco0abdf762015-08-20 11:10:41 -07001626
senorblanco0abdf762015-08-20 11:10:41 -07001627 {
robertphillips6e7025a2016-04-04 04:31:25 -07001628 sk_sp<SkImageFilter> gray(make_grayscale(nullptr, nullptr));
1629 REPORTER_ASSERT(reporter, gray->canComputeFastBounds());
1630 {
1631 SkColorFilter* grayCF;
1632 REPORTER_ASSERT(reporter, gray->asAColorFilter(&grayCF));
1633 REPORTER_ASSERT(reporter, !grayCF->affectsTransparentBlack());
1634 grayCF->unref();
1635 }
1636 REPORTER_ASSERT(reporter, gray->canComputeFastBounds());
1637
1638 sk_sp<SkImageFilter> grayBlur(SkBlurImageFilter::Make(SK_Scalar1, SK_Scalar1,
1639 std::move(gray)));
1640 REPORTER_ASSERT(reporter, grayBlur->canComputeFastBounds());
senorblanco0abdf762015-08-20 11:10:41 -07001641 }
senorblanco0abdf762015-08-20 11:10:41 -07001642
robertphillips6e7025a2016-04-04 04:31:25 -07001643 {
1644 SkScalar greenMatrix[20] = { 0, 0, 0, 0, 0,
1645 0, 0, 0, 0, 1,
1646 0, 0, 0, 0, 0,
1647 0, 0, 0, 0, 1 };
1648 sk_sp<SkColorFilter> greenCF(SkColorFilter::MakeMatrixFilterRowMajor255(greenMatrix));
robertphillips5605b562016-04-05 11:50:42 -07001649 sk_sp<SkImageFilter> green(SkColorFilterImageFilter::Make(greenCF, nullptr));
senorblanco0abdf762015-08-20 11:10:41 -07001650
robertphillips6e7025a2016-04-04 04:31:25 -07001651 REPORTER_ASSERT(reporter, greenCF->affectsTransparentBlack());
1652 REPORTER_ASSERT(reporter, !green->canComputeFastBounds());
senorblanco0abdf762015-08-20 11:10:41 -07001653
robertphillips6e7025a2016-04-04 04:31:25 -07001654 sk_sp<SkImageFilter> greenBlur(SkBlurImageFilter::Make(SK_Scalar1, SK_Scalar1,
1655 std::move(green)));
1656 REPORTER_ASSERT(reporter, !greenBlur->canComputeFastBounds());
1657 }
senorblanco0abdf762015-08-20 11:10:41 -07001658
1659 uint8_t allOne[256], identity[256];
1660 for (int i = 0; i < 256; ++i) {
1661 identity[i] = i;
1662 allOne[i] = 255;
1663 }
1664
robertphillips5605b562016-04-05 11:50:42 -07001665 sk_sp<SkColorFilter> identityCF(SkTableColorFilter::MakeARGB(identity, identity,
1666 identity, allOne));
1667 sk_sp<SkImageFilter> identityFilter(SkColorFilterImageFilter::Make(identityCF, nullptr));
senorblanco0abdf762015-08-20 11:10:41 -07001668 REPORTER_ASSERT(reporter, !identityCF->affectsTransparentBlack());
1669 REPORTER_ASSERT(reporter, identityFilter->canComputeFastBounds());
1670
robertphillips5605b562016-04-05 11:50:42 -07001671 sk_sp<SkColorFilter> forceOpaqueCF(SkTableColorFilter::MakeARGB(allOne, identity,
1672 identity, identity));
1673 sk_sp<SkImageFilter> forceOpaque(SkColorFilterImageFilter::Make(forceOpaqueCF, nullptr));
senorblanco0abdf762015-08-20 11:10:41 -07001674 REPORTER_ASSERT(reporter, forceOpaqueCF->affectsTransparentBlack());
1675 REPORTER_ASSERT(reporter, !forceOpaque->canComputeFastBounds());
1676}
1677
fmalitacd56f812015-09-14 13:31:18 -07001678// Verify that SkImageSource survives serialization
1679DEF_TEST(ImageFilterImageSourceSerialization, reporter) {
reede8f30622016-03-23 18:59:25 -07001680 auto surface(SkSurface::MakeRasterN32Premul(10, 10));
fmalitacd56f812015-09-14 13:31:18 -07001681 surface->getCanvas()->clear(SK_ColorGREEN);
reed9ce9d672016-03-17 10:51:11 -07001682 sk_sp<SkImage> image(surface->makeImageSnapshot());
robertphillips549c8992016-04-01 09:28:51 -07001683 sk_sp<SkImageFilter> filter(SkImageSource::Make(std::move(image)));
fmalitacd56f812015-09-14 13:31:18 -07001684
robertphillips549c8992016-04-01 09:28:51 -07001685 sk_sp<SkData> data(SkValidatingSerializeFlattenable(filter.get()));
Mike Reed5e257172016-11-01 11:22:05 -04001686 sk_sp<SkImageFilter> unflattenedFilter = SkValidatingDeserializeImageFilter(data->data(),
1687 data->size());
fmalitacd56f812015-09-14 13:31:18 -07001688 REPORTER_ASSERT(reporter, unflattenedFilter);
1689
1690 SkBitmap bm;
1691 bm.allocN32Pixels(10, 10);
fmalita23cb88c2015-09-15 06:56:23 -07001692 bm.eraseColor(SK_ColorBLUE);
fmalitacd56f812015-09-14 13:31:18 -07001693 SkPaint paint;
1694 paint.setColor(SK_ColorRED);
1695 paint.setImageFilter(unflattenedFilter);
1696
1697 SkCanvas canvas(bm);
1698 canvas.drawRect(SkRect::MakeWH(10, 10), paint);
1699 REPORTER_ASSERT(reporter, *bm.getAddr32(0, 0) == SkPreMultiplyColor(SK_ColorGREEN));
1700}
1701
bsalomon45eefcf2016-01-05 08:39:28 -08001702static void test_large_blur_input(skiatest::Reporter* reporter, SkCanvas* canvas) {
1703 SkBitmap largeBmp;
1704 int largeW = 5000;
1705 int largeH = 5000;
1706#if SK_SUPPORT_GPU
1707 // If we're GPU-backed make the bitmap too large to be converted into a texture.
1708 if (GrContext* ctx = canvas->getGrContext()) {
1709 largeW = ctx->caps()->maxTextureSize() + 1;
1710 }
1711#endif
1712
1713 largeBmp.allocN32Pixels(largeW, largeH);
mtklein2afbe232016-02-07 12:23:10 -08001714 largeBmp.eraseColor(0);
bsalomon45eefcf2016-01-05 08:39:28 -08001715 if (!largeBmp.getPixels()) {
1716 ERRORF(reporter, "Failed to allocate large bmp.");
1717 return;
1718 }
1719
reed9ce9d672016-03-17 10:51:11 -07001720 sk_sp<SkImage> largeImage(SkImage::MakeFromBitmap(largeBmp));
bsalomon45eefcf2016-01-05 08:39:28 -08001721 if (!largeImage) {
1722 ERRORF(reporter, "Failed to create large image.");
1723 return;
1724 }
1725
robertphillips549c8992016-04-01 09:28:51 -07001726 sk_sp<SkImageFilter> largeSource(SkImageSource::Make(std::move(largeImage)));
bsalomon45eefcf2016-01-05 08:39:28 -08001727 if (!largeSource) {
1728 ERRORF(reporter, "Failed to create large SkImageSource.");
1729 return;
1730 }
1731
robertphillips6e7025a2016-04-04 04:31:25 -07001732 sk_sp<SkImageFilter> blur(SkBlurImageFilter::Make(10.f, 10.f, std::move(largeSource)));
bsalomon45eefcf2016-01-05 08:39:28 -08001733 if (!blur) {
1734 ERRORF(reporter, "Failed to create SkBlurImageFilter.");
1735 return;
1736 }
1737
1738 SkPaint paint;
robertphillips549c8992016-04-01 09:28:51 -07001739 paint.setImageFilter(std::move(blur));
bsalomon45eefcf2016-01-05 08:39:28 -08001740
1741 // This should not crash (http://crbug.com/570479).
1742 canvas->drawRect(SkRect::MakeIWH(largeW, largeH), paint);
1743}
1744
senorblanco21a465d2016-04-11 11:58:39 -07001745DEF_TEST(ImageFilterBlurLargeImage, reporter) {
reede8f30622016-03-23 18:59:25 -07001746 auto surface(SkSurface::MakeRaster(SkImageInfo::MakeN32Premul(100, 100)));
bsalomon45eefcf2016-01-05 08:39:28 -08001747 test_large_blur_input(reporter, surface->getCanvas());
1748}
1749
senorblanco5878dbd2016-05-19 14:50:29 -07001750static void test_make_with_filter(skiatest::Reporter* reporter, GrContext* context) {
Robert Phillipsa5fdc972017-02-18 16:58:09 -05001751 sk_sp<SkSurface> surface(create_surface(context, 192, 128));
senorblanco5878dbd2016-05-19 14:50:29 -07001752 surface->getCanvas()->clear(SK_ColorRED);
1753 SkPaint bluePaint;
1754 bluePaint.setColor(SK_ColorBLUE);
1755 SkIRect subset = SkIRect::MakeXYWH(25, 20, 50, 50);
1756 surface->getCanvas()->drawRect(SkRect::Make(subset), bluePaint);
1757 sk_sp<SkImage> sourceImage = surface->makeImageSnapshot();
1758
1759 sk_sp<SkImageFilter> filter = make_grayscale(nullptr, nullptr);
1760 SkIRect clipBounds = SkIRect::MakeXYWH(30, 35, 100, 100);
1761 SkIRect outSubset;
1762 SkIPoint offset;
1763 sk_sp<SkImage> result;
1764
1765 result = sourceImage->makeWithFilter(nullptr, subset, clipBounds, &outSubset, &offset);
1766 REPORTER_ASSERT(reporter, !result);
1767
1768 result = sourceImage->makeWithFilter(filter.get(), subset, clipBounds, nullptr, &offset);
1769 REPORTER_ASSERT(reporter, !result);
1770
1771 result = sourceImage->makeWithFilter(filter.get(), subset, clipBounds, &outSubset, nullptr);
1772 REPORTER_ASSERT(reporter, !result);
1773
1774 SkIRect bigSubset = SkIRect::MakeXYWH(-10000, -10000, 20000, 20000);
1775 result = sourceImage->makeWithFilter(filter.get(), bigSubset, clipBounds, &outSubset, &offset);
1776 REPORTER_ASSERT(reporter, !result);
1777
1778 SkIRect empty = SkIRect::MakeEmpty();
1779 result = sourceImage->makeWithFilter(filter.get(), empty, clipBounds, &outSubset, &offset);
1780 REPORTER_ASSERT(reporter, !result);
1781
1782 result = sourceImage->makeWithFilter(filter.get(), subset, empty, &outSubset, &offset);
1783 REPORTER_ASSERT(reporter, !result);
1784
1785 SkIRect leftField = SkIRect::MakeXYWH(-1000, 0, 100, 100);
1786 result = sourceImage->makeWithFilter(filter.get(), subset, leftField, &outSubset, &offset);
1787 REPORTER_ASSERT(reporter, !result);
1788
1789 result = sourceImage->makeWithFilter(filter.get(), subset, clipBounds, &outSubset, &offset);
1790
1791 REPORTER_ASSERT(reporter, result);
1792 REPORTER_ASSERT(reporter, result->bounds().contains(outSubset));
1793 SkIRect destRect = SkIRect::MakeXYWH(offset.x(), offset.y(),
1794 outSubset.width(), outSubset.height());
1795 REPORTER_ASSERT(reporter, clipBounds.contains(destRect));
Robert Phillipsa5fdc972017-02-18 16:58:09 -05001796
1797 // In GPU-mode, this case creates a special image with a backing size that differs from
1798 // the content size
1799 {
1800 clipBounds.setXYWH(0, 0, 170, 100);
1801 subset.setXYWH(0, 0, 160, 90);
1802
1803 filter = SkXfermodeImageFilter::Make(SkBlendMode::kSrc, nullptr);
1804 result = sourceImage->makeWithFilter(filter.get(), subset, clipBounds, &outSubset, &offset);
1805 REPORTER_ASSERT(reporter, result);
1806 }
senorblanco5878dbd2016-05-19 14:50:29 -07001807}
1808
1809DEF_TEST(ImageFilterMakeWithFilter, reporter) {
1810 test_make_with_filter(reporter, nullptr);
1811}
1812
1813#if SK_SUPPORT_GPU
1814DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterMakeWithFilter_Gpu, reporter, ctxInfo) {
1815 test_make_with_filter(reporter, ctxInfo.grContext());
1816}
1817#endif
1818
senorblanco@chromium.org58d14662014-02-03 22:36:39 +00001819#if SK_SUPPORT_GPU
reed4a8126e2014-09-22 07:29:03 -07001820
bsalomon68d91342016-04-12 09:59:58 -07001821DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterHugeBlur_Gpu, reporter, ctxInfo) {
robertphillipsefbffed2015-06-22 12:06:08 -07001822
bsalomon8b7451a2016-05-11 06:33:06 -07001823 sk_sp<SkSurface> surf(SkSurface::MakeRenderTarget(ctxInfo.grContext(),
robertphillips3e302272016-04-20 11:48:36 -07001824 SkBudgeted::kNo,
1825 SkImageInfo::MakeN32Premul(100, 100)));
robertphillips9a53fd72015-06-22 09:46:59 -07001826
robertphillips3e302272016-04-20 11:48:36 -07001827
1828 SkCanvas* canvas = surf->getCanvas();
1829
1830 test_huge_blur(canvas, reporter);
senorblanco@chromium.org09843fd2014-03-24 20:50:59 +00001831}
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001832
egdanielab527a52016-06-28 08:07:26 -07001833DEF_GPUTEST_FOR_RENDERING_CONTEXTS(XfermodeImageFilterCroppedInput_Gpu, reporter, ctxInfo) {
robertphillipsefbffed2015-06-22 12:06:08 -07001834
bsalomon8b7451a2016-05-11 06:33:06 -07001835 sk_sp<SkSurface> surf(SkSurface::MakeRenderTarget(ctxInfo.grContext(),
robertphillips3e302272016-04-20 11:48:36 -07001836 SkBudgeted::kNo,
1837 SkImageInfo::MakeN32Premul(1, 1)));
robertphillips9a53fd72015-06-22 09:46:59 -07001838
robertphillips3e302272016-04-20 11:48:36 -07001839
1840 SkCanvas* canvas = surf->getCanvas();
1841
1842 test_xfermode_cropped_input(canvas, reporter);
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001843}
senorblanco32673b92014-09-09 09:15:04 -07001844
egdanielab527a52016-06-28 08:07:26 -07001845DEF_GPUTEST_FOR_ALL_CONTEXTS(ImageFilterBlurLargeImage_Gpu, reporter, ctxInfo) {
bsalomon8b7451a2016-05-11 06:33:06 -07001846 auto surface(SkSurface::MakeRenderTarget(ctxInfo.grContext(), SkBudgeted::kYes,
reede8f30622016-03-23 18:59:25 -07001847 SkImageInfo::MakeN32Premul(100, 100)));
bsalomon45eefcf2016-01-05 08:39:28 -08001848 test_large_blur_input(reporter, surface->getCanvas());
1849}
senorblanco@chromium.org58d14662014-02-03 22:36:39 +00001850#endif
reedbb34a8a2016-04-23 15:19:07 -07001851
1852/*
1853 * Test that colorfilterimagefilter does not require its CTM to be decomposed when it has more
1854 * than just scale/translate, but that other filters do.
1855 */
reed96a04f32016-04-25 09:25:15 -07001856DEF_TEST(ImageFilterComplexCTM, reporter) {
reedbb34a8a2016-04-23 15:19:07 -07001857 // just need a colorfilter to exercise the corresponding imagefilter
Mike Reed7d954ad2016-10-28 15:42:34 -04001858 sk_sp<SkColorFilter> cf = SkColorFilter::MakeModeFilter(SK_ColorRED, SkBlendMode::kSrcATop);
reed96a04f32016-04-25 09:25:15 -07001859 sk_sp<SkImageFilter> cfif = SkColorFilterImageFilter::Make(cf, nullptr); // can handle
1860 sk_sp<SkImageFilter> blif = SkBlurImageFilter::Make(3, 3, nullptr); // cannot handle
reedbb34a8a2016-04-23 15:19:07 -07001861
1862 struct {
1863 sk_sp<SkImageFilter> fFilter;
1864 bool fExpectCanHandle;
1865 } recs[] = {
1866 { cfif, true },
1867 { SkColorFilterImageFilter::Make(cf, cfif), true },
Mike Reed7d954ad2016-10-28 15:42:34 -04001868 { SkMergeImageFilter::Make(cfif, cfif, SkBlendMode::kSrcOver), true },
reed96a04f32016-04-25 09:25:15 -07001869 { SkComposeImageFilter::Make(cfif, cfif), true },
1870
reedbb34a8a2016-04-23 15:19:07 -07001871 { blif, false },
reed96a04f32016-04-25 09:25:15 -07001872 { SkBlurImageFilter::Make(3, 3, cfif), false },
reedbb34a8a2016-04-23 15:19:07 -07001873 { SkColorFilterImageFilter::Make(cf, blif), false },
Mike Reed7d954ad2016-10-28 15:42:34 -04001874 { SkMergeImageFilter::Make(cfif, blif, SkBlendMode::kSrcOver), false },
reed96a04f32016-04-25 09:25:15 -07001875 { SkComposeImageFilter::Make(blif, cfif), false },
reedbb34a8a2016-04-23 15:19:07 -07001876 };
liyuqianbfebe222016-11-14 11:17:16 -08001877
reedbb34a8a2016-04-23 15:19:07 -07001878 for (const auto& rec : recs) {
reed96a04f32016-04-25 09:25:15 -07001879 const bool canHandle = rec.fFilter->canHandleComplexCTM();
reedbb34a8a2016-04-23 15:19:07 -07001880 REPORTER_ASSERT(reporter, canHandle == rec.fExpectCanHandle);
1881 }
1882}