blob: c6d184dfea27aaa78b2934f784143c4f7db50e22 [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"
Florin Malita08252ec2017-07-06 12:48:15 -040013#include "SkColorSpaceXformer.h"
ajuma5788faa2015-02-13 09:05:47 -080014#include "SkComposeImageFilter.h"
senorblanco@chromium.org6776b822014-01-03 21:48:22 +000015#include "SkDisplacementMapEffect.h"
16#include "SkDropShadowImageFilter.h"
senorblanco@chromium.org97f5fc62014-05-30 20:50:56 +000017#include "SkFlattenableSerialization.h"
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +000018#include "SkGradientShader.h"
fmalita5598b632015-09-15 11:26:13 -070019#include "SkImage.h"
fmalitacd56f812015-09-14 13:31:18 -070020#include "SkImageSource.h"
commit-bot@chromium.org4b681bc2013-09-13 12:40:02 +000021#include "SkLightingImageFilter.h"
tfarina@chromium.org8f6884a2014-01-24 20:56:26 +000022#include "SkMatrixConvolutionImageFilter.h"
senorblanco@chromium.org6776b822014-01-03 21:48:22 +000023#include "SkMergeImageFilter.h"
24#include "SkMorphologyImageFilter.h"
senorblanco@chromium.org6776b822014-01-03 21:48:22 +000025#include "SkOffsetImageFilter.h"
ajuma77b6ba32016-01-08 14:58:35 -080026#include "SkPaintImageFilter.h"
senorblanco8f3937d2014-10-29 12:36:32 -070027#include "SkPerlinNoiseShader.h"
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +000028#include "SkPicture.h"
senorblanco@chromium.org910702b2014-05-30 20:36:15 +000029#include "SkPictureImageFilter.h"
robertphillips@google.com770963f2014-04-18 18:04:41 +000030#include "SkPictureRecorder.h"
robertphillips3d32d762015-07-13 13:16:44 -070031#include "SkPoint3.h"
halcanary97d2c0a2014-08-19 06:27:53 -070032#include "SkReadBuffer.h"
tfarina@chromium.org8f6884a2014-01-24 20:56:26 +000033#include "SkRect.h"
robertphillips4418dba2016-03-07 12:45:14 -080034#include "SkSpecialImage.h"
35#include "SkSpecialSurface.h"
fmalitacd56f812015-09-14 13:31:18 -070036#include "SkSurface.h"
senorblanco0abdf762015-08-20 11:10:41 -070037#include "SkTableColorFilter.h"
senorblanco@chromium.org6776b822014-01-03 21:48:22 +000038#include "SkTileImageFilter.h"
39#include "SkXfermodeImageFilter.h"
tfarina@chromium.org8f6884a2014-01-24 20:56:26 +000040#include "Test.h"
senorblanco@chromium.org194d7752013-07-24 22:19:24 +000041
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +000042#if SK_SUPPORT_GPU
kkinnunen15302832015-12-01 04:35:26 -080043#include "GrContext.h"
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +000044#endif
45
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +000046static const int kBitmapSize = 4;
commit-bot@chromium.org4b681bc2013-09-13 12:40:02 +000047
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +000048namespace {
49
50class MatrixTestImageFilter : public SkImageFilter {
51public:
robertphillips43c2ad42016-04-04 05:05:11 -070052 static sk_sp<SkImageFilter> Make(skiatest::Reporter* reporter,
53 const SkMatrix& expectedMatrix) {
54 return sk_sp<SkImageFilter>(new MatrixTestImageFilter(reporter, expectedMatrix));
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +000055 }
56
robertphillipsf3f5bad2014-12-19 13:49:15 -080057 SK_TO_STRING_OVERRIDE()
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +000058 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(MatrixTestImageFilter)
59
60protected:
robertphillips4ba94e22016-04-04 12:07:47 -070061 sk_sp<SkSpecialImage> onFilterImage(SkSpecialImage* source, const Context& ctx,
62 SkIPoint* offset) const override {
robertphillips43c2ad42016-04-04 05:05:11 -070063 REPORTER_ASSERT(fReporter, ctx.ctm() == fExpectedMatrix);
robertphillips4ba94e22016-04-04 12:07:47 -070064 offset->fX = offset->fY = 0;
65 return sk_ref_sp<SkSpecialImage>(source);
robertphillips43c2ad42016-04-04 05:05:11 -070066 }
Matt Sarett62745a82017-04-17 11:57:29 -040067 sk_sp<SkImageFilter> onMakeColorSpace(SkColorSpaceXformer*) const override {
68 return sk_ref_sp(const_cast<MatrixTestImageFilter*>(this));
69 }
robertphillips43c2ad42016-04-04 05:05:11 -070070
mtklein36352bf2015-03-25 18:17:31 -070071 void flatten(SkWriteBuffer& buffer) const override {
brianosman18f13f32016-05-02 07:51:08 -070072 SkDEBUGFAIL("Should never get here");
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +000073 }
74
75private:
robertphillips43c2ad42016-04-04 05:05:11 -070076 MatrixTestImageFilter(skiatest::Reporter* reporter, const SkMatrix& expectedMatrix)
77 : INHERITED(nullptr, 0, nullptr)
78 , fReporter(reporter)
79 , fExpectedMatrix(expectedMatrix) {
80 }
81
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +000082 skiatest::Reporter* fReporter;
83 SkMatrix fExpectedMatrix;
mtklein3f3b3d02014-12-01 11:47:08 -080084
reed9fa60da2014-08-21 07:59:51 -070085 typedef SkImageFilter INHERITED;
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +000086};
87
senorblanco6a93fa12016-04-05 04:43:45 -070088class FailImageFilter : public SkImageFilter {
89public:
robertphillips6b134732016-04-15 09:58:37 -070090 FailImageFilter() : SkImageFilter(nullptr, 0, nullptr) { }
senorblanco6a93fa12016-04-05 04:43:45 -070091
92 sk_sp<SkSpecialImage> onFilterImage(SkSpecialImage* source,
93 const Context& ctx,
94 SkIPoint* offset) const override {
95 return nullptr;
96 }
Matt Sarett62745a82017-04-17 11:57:29 -040097 sk_sp<SkImageFilter> onMakeColorSpace(SkColorSpaceXformer*) const override {
98 return nullptr;
99 }
senorblanco6a93fa12016-04-05 04:43:45 -0700100
101 SK_TO_STRING_OVERRIDE()
102 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(FailImageFilter)
103
104private:
105 typedef SkImageFilter INHERITED;
106};
107
108sk_sp<SkFlattenable> FailImageFilter::CreateProc(SkReadBuffer& buffer) {
109 SK_IMAGEFILTER_UNFLATTEN_COMMON(common, 0);
110 return sk_sp<SkFlattenable>(new FailImageFilter());
111}
112
113#ifndef SK_IGNORE_TO_STRING
114void FailImageFilter::toString(SkString* str) const {
115 str->appendf("FailImageFilter: (");
116 str->append(")");
117}
118#endif
119
senorblanco297f7ce2016-03-23 13:44:26 -0700120void draw_gradient_circle(SkCanvas* canvas, int width, int height) {
121 SkScalar x = SkIntToScalar(width / 2);
122 SkScalar y = SkIntToScalar(height / 2);
123 SkScalar radius = SkMinScalar(x, y) * 0.8f;
124 canvas->clear(0x00000000);
125 SkColor colors[2];
126 colors[0] = SK_ColorWHITE;
127 colors[1] = SK_ColorBLACK;
128 sk_sp<SkShader> shader(
129 SkGradientShader::MakeRadial(SkPoint::Make(x, y), radius, colors, nullptr, 2,
130 SkShader::kClamp_TileMode)
131 );
132 SkPaint paint;
133 paint.setShader(shader);
134 canvas->drawCircle(x, y, radius, paint);
135}
136
137SkBitmap make_gradient_circle(int width, int height) {
138 SkBitmap bitmap;
139 bitmap.allocN32Pixels(width, height);
140 SkCanvas canvas(bitmap);
141 draw_gradient_circle(&canvas, width, height);
142 return bitmap;
143}
144
145class FilterList {
146public:
robertphillipsfc11b0a2016-04-05 09:09:36 -0700147 FilterList(sk_sp<SkImageFilter> input, const SkImageFilter::CropRect* cropRect = nullptr) {
senorblanco297f7ce2016-03-23 13:44:26 -0700148 SkPoint3 location = SkPoint3::Make(0, 0, SK_Scalar1);
senorblanco297f7ce2016-03-23 13:44:26 -0700149 const SkScalar five = SkIntToScalar(5);
150
robertphillips6e7025a2016-04-04 04:31:25 -0700151 {
152 sk_sp<SkColorFilter> cf(SkColorFilter::MakeModeFilter(SK_ColorRED,
Mike Reed7d954ad2016-10-28 15:42:34 -0400153 SkBlendMode::kSrcIn));
senorblanco297f7ce2016-03-23 13:44:26 -0700154
robertphillips6e7025a2016-04-04 04:31:25 -0700155 this->addFilter("color filter",
robertphillips12fa47d2016-04-08 16:28:09 -0700156 SkColorFilterImageFilter::Make(std::move(cf), input, cropRect));
robertphillips6e7025a2016-04-04 04:31:25 -0700157 }
senorblanco297f7ce2016-03-23 13:44:26 -0700158
robertphillips6e7025a2016-04-04 04:31:25 -0700159 {
160 sk_sp<SkImage> gradientImage(SkImage::MakeFromBitmap(make_gradient_circle(64, 64)));
161 sk_sp<SkImageFilter> gradientSource(SkImageSource::Make(std::move(gradientImage)));
senorblanco297f7ce2016-03-23 13:44:26 -0700162
liyuqianbfebe222016-11-14 11:17:16 -0800163 this->addFilter("displacement map",
robertphillipsbfe11fc2016-04-15 07:17:36 -0700164 SkDisplacementMapEffect::Make(SkDisplacementMapEffect::kR_ChannelSelectorType,
165 SkDisplacementMapEffect::kB_ChannelSelectorType,
166 20.0f,
167 std::move(gradientSource), input, cropRect));
robertphillips6e7025a2016-04-04 04:31:25 -0700168 }
senorblanco297f7ce2016-03-23 13:44:26 -0700169
robertphillips6e7025a2016-04-04 04:31:25 -0700170 this->addFilter("blur", SkBlurImageFilter::Make(SK_Scalar1,
171 SK_Scalar1,
robertphillipsfc11b0a2016-04-05 09:09:36 -0700172 input,
robertphillips12fa47d2016-04-08 16:28:09 -0700173 cropRect));
robertphillipsc4169122016-04-06 08:40:59 -0700174 this->addFilter("drop shadow", SkDropShadowImageFilter::Make(
senorblanco297f7ce2016-03-23 13:44:26 -0700175 SK_Scalar1, SK_Scalar1, SK_Scalar1, SK_Scalar1, SK_ColorGREEN,
robertphillipsfc11b0a2016-04-05 09:09:36 -0700176 SkDropShadowImageFilter::kDrawShadowAndForeground_ShadowMode,
robertphillips12fa47d2016-04-08 16:28:09 -0700177 input, cropRect));
178 this->addFilter("diffuse lighting",
179 SkLightingImageFilter::MakePointLitDiffuse(location, SK_ColorGREEN, 0, 0,
180 input, cropRect));
senorblanco297f7ce2016-03-23 13:44:26 -0700181 this->addFilter("specular lighting",
robertphillips12fa47d2016-04-08 16:28:09 -0700182 SkLightingImageFilter::MakePointLitSpecular(location, SK_ColorGREEN, 0, 0, 0,
183 input, cropRect));
184 {
185 SkScalar kernel[9] = {
186 SkIntToScalar(1), SkIntToScalar(1), SkIntToScalar(1),
187 SkIntToScalar(1), SkIntToScalar(-7), SkIntToScalar(1),
188 SkIntToScalar(1), SkIntToScalar(1), SkIntToScalar(1),
189 };
190 const SkISize kernelSize = SkISize::Make(3, 3);
191 const SkScalar gain = SK_Scalar1, bias = 0;
192
193 this->addFilter("matrix convolution",
robertphillipsef6a47b2016-04-08 08:01:20 -0700194 SkMatrixConvolutionImageFilter::Make(
senorblanco297f7ce2016-03-23 13:44:26 -0700195 kernelSize, kernel, gain, bias, SkIPoint::Make(1, 1),
robertphillipsfc11b0a2016-04-05 09:09:36 -0700196 SkMatrixConvolutionImageFilter::kRepeat_TileMode, false,
robertphillips12fa47d2016-04-08 16:28:09 -0700197 input, cropRect));
198 }
199
Mike Reed0bdaf052017-06-18 23:35:57 -0400200 this->addFilter("merge", SkMergeImageFilter::Make(input, input, cropRect));
robertphillips12fa47d2016-04-08 16:28:09 -0700201
robertphillips6e7025a2016-04-04 04:31:25 -0700202 {
203 SkPaint greenColorShaderPaint;
204 greenColorShaderPaint.setShader(SkShader::MakeColorShader(SK_ColorGREEN));
205
206 SkImageFilter::CropRect leftSideCropRect(SkRect::MakeXYWH(0, 0, 32, 64));
207 sk_sp<SkImageFilter> paintFilterLeft(SkPaintImageFilter::Make(greenColorShaderPaint,
208 &leftSideCropRect));
209 SkImageFilter::CropRect rightSideCropRect(SkRect::MakeXYWH(32, 0, 32, 64));
210 sk_sp<SkImageFilter> paintFilterRight(SkPaintImageFilter::Make(greenColorShaderPaint,
211 &rightSideCropRect));
212
213
214 this->addFilter("merge with disjoint inputs", SkMergeImageFilter::Make(
Mike Reed0bdaf052017-06-18 23:35:57 -0400215 std::move(paintFilterLeft), std::move(paintFilterRight), cropRect));
robertphillips6e7025a2016-04-04 04:31:25 -0700216 }
217
senorblanco297f7ce2016-03-23 13:44:26 -0700218 this->addFilter("offset",
robertphillipsfc11b0a2016-04-05 09:09:36 -0700219 SkOffsetImageFilter::Make(SK_Scalar1, SK_Scalar1, input,
robertphillips12fa47d2016-04-08 16:28:09 -0700220 cropRect));
221 this->addFilter("dilate", SkDilateImageFilter::Make(3, 2, input, cropRect));
222 this->addFilter("erode", SkErodeImageFilter::Make(2, 3, input, cropRect));
robertphillips534c2702016-04-15 07:57:40 -0700223 this->addFilter("tile", SkTileImageFilter::Make(
224 SkRect::MakeXYWH(0, 0, 50, 50),
225 cropRect ? cropRect->rect() : SkRect::MakeXYWH(0, 0, 100, 100),
226 input));
robertphillips6e7025a2016-04-04 04:31:25 -0700227
robertphillips12fa47d2016-04-08 16:28:09 -0700228 if (!cropRect) {
229 SkMatrix matrix;
230
231 matrix.setTranslate(SK_Scalar1, SK_Scalar1);
232 matrix.postRotate(SkIntToScalar(45), SK_Scalar1, SK_Scalar1);
233
234 this->addFilter("matrix",
235 SkImageFilter::MakeMatrixFilter(matrix, kLow_SkFilterQuality, input));
236 }
robertphillips6e7025a2016-04-04 04:31:25 -0700237 {
robertphillipsfc11b0a2016-04-05 09:09:36 -0700238 sk_sp<SkImageFilter> blur(SkBlurImageFilter::Make(five, five, input));
robertphillips6e7025a2016-04-04 04:31:25 -0700239
240 this->addFilter("blur and offset", SkOffsetImageFilter::Make(five, five,
241 std::move(blur),
robertphillips12fa47d2016-04-08 16:28:09 -0700242 cropRect));
robertphillips6e7025a2016-04-04 04:31:25 -0700243 }
244 {
robertphillips6e7025a2016-04-04 04:31:25 -0700245 SkPictureRecorder recorder;
Mike Klein26eb16f2017-04-10 09:50:25 -0400246 SkCanvas* recordingCanvas = recorder.beginRecording(64, 64);
robertphillips6e7025a2016-04-04 04:31:25 -0700247
248 SkPaint greenPaint;
249 greenPaint.setColor(SK_ColorGREEN);
250 recordingCanvas->drawRect(SkRect::Make(SkIRect::MakeXYWH(10, 10, 30, 20)), greenPaint);
251 sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture());
252 sk_sp<SkImageFilter> pictureFilter(SkPictureImageFilter::Make(std::move(picture)));
253
254 this->addFilter("picture and blur", SkBlurImageFilter::Make(five, five,
255 std::move(pictureFilter),
robertphillips12fa47d2016-04-08 16:28:09 -0700256 cropRect));
robertphillips6e7025a2016-04-04 04:31:25 -0700257 }
258 {
259 SkPaint paint;
260 paint.setShader(SkPerlinNoiseShader::MakeTurbulence(SK_Scalar1, SK_Scalar1, 1, 0));
261 sk_sp<SkImageFilter> paintFilter(SkPaintImageFilter::Make(paint));
262
263 this->addFilter("paint and blur", SkBlurImageFilter::Make(five, five,
264 std::move(paintFilter),
robertphillips12fa47d2016-04-08 16:28:09 -0700265 cropRect));
robertphillips6e7025a2016-04-04 04:31:25 -0700266 }
reed374772b2016-10-05 17:33:02 -0700267 this->addFilter("xfermode", SkXfermodeImageFilter::Make(SkBlendMode::kSrc, input, input,
268 cropRect));
senorblanco297f7ce2016-03-23 13:44:26 -0700269 }
270 int count() const { return fFilters.count(); }
271 SkImageFilter* getFilter(int index) const { return fFilters[index].fFilter.get(); }
272 const char* getName(int index) const { return fFilters[index].fName; }
273private:
274 struct Filter {
robertphillips12fa47d2016-04-08 16:28:09 -0700275 Filter() : fName(nullptr) {}
276 Filter(const char* name, sk_sp<SkImageFilter> filter)
277 : fName(name)
278 , fFilter(std::move(filter)) {
279 }
senorblanco297f7ce2016-03-23 13:44:26 -0700280 const char* fName;
281 sk_sp<SkImageFilter> fFilter;
282 };
robertphillips12fa47d2016-04-08 16:28:09 -0700283 void addFilter(const char* name, sk_sp<SkImageFilter> filter) {
284 fFilters.push_back(Filter(name, std::move(filter)));
senorblanco297f7ce2016-03-23 13:44:26 -0700285 }
286
287 SkTArray<Filter> fFilters;
288};
289
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +0000290}
291
reed60c9b582016-04-03 09:11:13 -0700292sk_sp<SkFlattenable> MatrixTestImageFilter::CreateProc(SkReadBuffer& buffer) {
brianosman18f13f32016-05-02 07:51:08 -0700293 SkDEBUGFAIL("Should never get here");
294 return nullptr;
reed9fa60da2014-08-21 07:59:51 -0700295}
296
robertphillipsf3f5bad2014-12-19 13:49:15 -0800297#ifndef SK_IGNORE_TO_STRING
298void MatrixTestImageFilter::toString(SkString* str) const {
299 str->appendf("MatrixTestImageFilter: (");
300 str->append(")");
301}
302#endif
303
reed9ce9d672016-03-17 10:51:11 -0700304static sk_sp<SkImage> make_small_image() {
reede8f30622016-03-23 18:59:25 -0700305 auto surface(SkSurface::MakeRasterN32Premul(kBitmapSize, kBitmapSize));
fmalita5598b632015-09-15 11:26:13 -0700306 SkCanvas* canvas = surface->getCanvas();
307 canvas->clear(0x00000000);
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000308 SkPaint darkPaint;
309 darkPaint.setColor(0xFF804020);
310 SkPaint lightPaint;
311 lightPaint.setColor(0xFF244484);
312 const int i = kBitmapSize / 4;
313 for (int y = 0; y < kBitmapSize; y += i) {
314 for (int x = 0; x < kBitmapSize; x += i) {
fmalita5598b632015-09-15 11:26:13 -0700315 canvas->save();
316 canvas->translate(SkIntToScalar(x), SkIntToScalar(y));
317 canvas->drawRect(SkRect::MakeXYWH(0, 0,
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000318 SkIntToScalar(i),
319 SkIntToScalar(i)), darkPaint);
fmalita5598b632015-09-15 11:26:13 -0700320 canvas->drawRect(SkRect::MakeXYWH(SkIntToScalar(i),
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000321 0,
322 SkIntToScalar(i),
323 SkIntToScalar(i)), lightPaint);
fmalita5598b632015-09-15 11:26:13 -0700324 canvas->drawRect(SkRect::MakeXYWH(0,
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000325 SkIntToScalar(i),
326 SkIntToScalar(i),
327 SkIntToScalar(i)), lightPaint);
fmalita5598b632015-09-15 11:26:13 -0700328 canvas->drawRect(SkRect::MakeXYWH(SkIntToScalar(i),
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000329 SkIntToScalar(i),
330 SkIntToScalar(i),
331 SkIntToScalar(i)), darkPaint);
fmalita5598b632015-09-15 11:26:13 -0700332 canvas->restore();
commit-bot@chromium.org4b681bc2013-09-13 12:40:02 +0000333 }
334 }
fmalita5598b632015-09-15 11:26:13 -0700335
reed9ce9d672016-03-17 10:51:11 -0700336 return surface->makeImageSnapshot();
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000337}
senorblanco@chromium.org194d7752013-07-24 22:19:24 +0000338
robertphillips5605b562016-04-05 11:50:42 -0700339static sk_sp<SkImageFilter> make_scale(float amount, sk_sp<SkImageFilter> input) {
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000340 SkScalar s = amount;
341 SkScalar matrix[20] = { s, 0, 0, 0, 0,
342 0, s, 0, 0, 0,
343 0, 0, s, 0, 0,
344 0, 0, 0, s, 0 };
robertphillips5605b562016-04-05 11:50:42 -0700345 sk_sp<SkColorFilter> filter(SkColorFilter::MakeMatrixFilterRowMajor255(matrix));
346 return SkColorFilterImageFilter::Make(std::move(filter), std::move(input));
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000347}
348
robertphillips5605b562016-04-05 11:50:42 -0700349static sk_sp<SkImageFilter> make_grayscale(sk_sp<SkImageFilter> input,
350 const SkImageFilter::CropRect* cropRect) {
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000351 SkScalar matrix[20];
352 memset(matrix, 0, 20 * sizeof(SkScalar));
353 matrix[0] = matrix[5] = matrix[10] = 0.2126f;
354 matrix[1] = matrix[6] = matrix[11] = 0.7152f;
355 matrix[2] = matrix[7] = matrix[12] = 0.0722f;
356 matrix[18] = 1.0f;
robertphillips5605b562016-04-05 11:50:42 -0700357 sk_sp<SkColorFilter> filter(SkColorFilter::MakeMatrixFilterRowMajor255(matrix));
358 return SkColorFilterImageFilter::Make(std::move(filter), std::move(input), cropRect);
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000359}
360
robertphillips5605b562016-04-05 11:50:42 -0700361static sk_sp<SkImageFilter> make_blue(sk_sp<SkImageFilter> input,
362 const SkImageFilter::CropRect* cropRect) {
363 sk_sp<SkColorFilter> filter(SkColorFilter::MakeModeFilter(SK_ColorBLUE,
Mike Reed7d954ad2016-10-28 15:42:34 -0400364 SkBlendMode::kSrcIn));
robertphillips5605b562016-04-05 11:50:42 -0700365 return SkColorFilterImageFilter::Make(std::move(filter), std::move(input), cropRect);
reedcedc36f2015-03-08 04:42:52 -0700366}
367
robertphillips3e302272016-04-20 11:48:36 -0700368static sk_sp<SkSpecialSurface> create_empty_special_surface(GrContext* context, int widthHeight) {
robertphillipsc91fd342016-04-25 12:32:54 -0700369#if SK_SUPPORT_GPU
robertphillips4418dba2016-03-07 12:45:14 -0800370 if (context) {
robertphillips4df16562016-04-28 15:09:34 -0700371 return SkSpecialSurface::MakeRenderTarget(context,
372 widthHeight, widthHeight,
Brian Osman777b5632016-10-14 09:16:21 -0400373 kRGBA_8888_GrPixelConfig, nullptr);
robertphillipsc91fd342016-04-25 12:32:54 -0700374 } else
375#endif
376 {
robertphillips4418dba2016-03-07 12:45:14 -0800377 const SkImageInfo info = SkImageInfo::MakeN32(widthHeight, widthHeight,
378 kOpaque_SkAlphaType);
robertphillips3e302272016-04-20 11:48:36 -0700379 return SkSpecialSurface::MakeRaster(info);
robertphillips4418dba2016-03-07 12:45:14 -0800380 }
senorblancobf680c32016-03-16 16:15:53 -0700381}
382
senorblanco5878dbd2016-05-19 14:50:29 -0700383static sk_sp<SkSurface> create_surface(GrContext* context, int width, int height) {
384 const SkImageInfo info = SkImageInfo::MakeN32(width, height, kOpaque_SkAlphaType);
385#if SK_SUPPORT_GPU
386 if (context) {
387 return SkSurface::MakeRenderTarget(context, SkBudgeted::kNo, info);
388 } else
389#endif
390 {
391 return SkSurface::MakeRaster(info);
392 }
393}
394
robertphillips3e302272016-04-20 11:48:36 -0700395static sk_sp<SkSpecialImage> create_empty_special_image(GrContext* context, int widthHeight) {
396 sk_sp<SkSpecialSurface> surf(create_empty_special_surface(context, widthHeight));
robertphillips4418dba2016-03-07 12:45:14 -0800397
398 SkASSERT(surf);
399
400 SkCanvas* canvas = surf->getCanvas();
401 SkASSERT(canvas);
402
403 canvas->clear(0x0);
404
robertphillips37bd7c32016-03-17 14:31:39 -0700405 return surf->makeImageSnapshot();
robertphillips4418dba2016-03-07 12:45:14 -0800406}
407
408
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000409DEF_TEST(ImageFilter, reporter) {
410 {
reedcedc36f2015-03-08 04:42:52 -0700411 // Check that two non-clipping color-matrice-filters concatenate into a single filter.
robertphillips5605b562016-04-05 11:50:42 -0700412 sk_sp<SkImageFilter> halfBrightness(make_scale(0.5f, nullptr));
413 sk_sp<SkImageFilter> quarterBrightness(make_scale(0.5f, std::move(halfBrightness)));
halcanary96fcdcc2015-08-27 07:41:13 -0700414 REPORTER_ASSERT(reporter, nullptr == quarterBrightness->getInput(0));
reedcedc36f2015-03-08 04:42:52 -0700415 SkColorFilter* cf;
416 REPORTER_ASSERT(reporter, quarterBrightness->asColorFilter(&cf));
halcanary96fcdcc2015-08-27 07:41:13 -0700417 REPORTER_ASSERT(reporter, cf->asColorMatrix(nullptr));
reedcedc36f2015-03-08 04:42:52 -0700418 cf->unref();
senorblanco@chromium.org194d7752013-07-24 22:19:24 +0000419 }
420
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000421 {
reedcedc36f2015-03-08 04:42:52 -0700422 // Check that a clipping color-matrice-filter followed by a color-matrice-filters
423 // concatenates into a single filter, but not a matrixfilter (due to clamping).
robertphillips5605b562016-04-05 11:50:42 -0700424 sk_sp<SkImageFilter> doubleBrightness(make_scale(2.0f, nullptr));
425 sk_sp<SkImageFilter> halfBrightness(make_scale(0.5f, std::move(doubleBrightness)));
halcanary96fcdcc2015-08-27 07:41:13 -0700426 REPORTER_ASSERT(reporter, nullptr == halfBrightness->getInput(0));
reedcedc36f2015-03-08 04:42:52 -0700427 SkColorFilter* cf;
428 REPORTER_ASSERT(reporter, halfBrightness->asColorFilter(&cf));
halcanary96fcdcc2015-08-27 07:41:13 -0700429 REPORTER_ASSERT(reporter, !cf->asColorMatrix(nullptr));
reedcedc36f2015-03-08 04:42:52 -0700430 cf->unref();
senorblanco@chromium.org194d7752013-07-24 22:19:24 +0000431 }
432
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000433 {
434 // Check that a color filter image filter without a crop rect can be
435 // expressed as a color filter.
robertphillips5605b562016-04-05 11:50:42 -0700436 sk_sp<SkImageFilter> gray(make_grayscale(nullptr, nullptr));
halcanary96fcdcc2015-08-27 07:41:13 -0700437 REPORTER_ASSERT(reporter, true == gray->asColorFilter(nullptr));
senorblanco@chromium.org194d7752013-07-24 22:19:24 +0000438 }
mtklein2afbe232016-02-07 12:23:10 -0800439
reedcedc36f2015-03-08 04:42:52 -0700440 {
441 // Check that a colorfilterimage filter without a crop rect but with an input
442 // that is another colorfilterimage can be expressed as a colorfilter (composed).
robertphillips5605b562016-04-05 11:50:42 -0700443 sk_sp<SkImageFilter> mode(make_blue(nullptr, nullptr));
444 sk_sp<SkImageFilter> gray(make_grayscale(std::move(mode), nullptr));
halcanary96fcdcc2015-08-27 07:41:13 -0700445 REPORTER_ASSERT(reporter, true == gray->asColorFilter(nullptr));
reedcedc36f2015-03-08 04:42:52 -0700446 }
447
448 {
449 // Test that if we exceed the limit of what ComposeColorFilter can combine, we still
450 // can build the DAG and won't assert if we call asColorFilter.
robertphillips5605b562016-04-05 11:50:42 -0700451 sk_sp<SkImageFilter> filter(make_blue(nullptr, nullptr));
reedcedc36f2015-03-08 04:42:52 -0700452 const int kWayTooManyForComposeColorFilter = 100;
453 for (int i = 0; i < kWayTooManyForComposeColorFilter; ++i) {
robertphillips5605b562016-04-05 11:50:42 -0700454 filter = make_blue(filter, nullptr);
reedcedc36f2015-03-08 04:42:52 -0700455 // the first few of these will succeed, but after we hit the internal limit,
456 // it will then return false.
halcanary96fcdcc2015-08-27 07:41:13 -0700457 (void)filter->asColorFilter(nullptr);
reedcedc36f2015-03-08 04:42:52 -0700458 }
459 }
reed5c518a82015-03-05 14:47:29 -0800460
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000461 {
462 // Check that a color filter image filter with a crop rect cannot
463 // be expressed as a color filter.
464 SkImageFilter::CropRect cropRect(SkRect::MakeXYWH(0, 0, 100, 100));
robertphillips5605b562016-04-05 11:50:42 -0700465 sk_sp<SkImageFilter> grayWithCrop(make_grayscale(nullptr, &cropRect));
halcanary96fcdcc2015-08-27 07:41:13 -0700466 REPORTER_ASSERT(reporter, false == grayWithCrop->asColorFilter(nullptr));
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000467 }
468
469 {
senorblanco3df05012014-07-03 11:13:09 -0700470 // Check that two non-commutative matrices are concatenated in
471 // the correct order.
472 SkScalar blueToRedMatrix[20] = { 0 };
473 blueToRedMatrix[2] = blueToRedMatrix[18] = SK_Scalar1;
474 SkScalar redToGreenMatrix[20] = { 0 };
475 redToGreenMatrix[5] = redToGreenMatrix[18] = SK_Scalar1;
robertphillips5605b562016-04-05 11:50:42 -0700476 sk_sp<SkColorFilter> blueToRed(SkColorFilter::MakeMatrixFilterRowMajor255(blueToRedMatrix));
477 sk_sp<SkImageFilter> filter1(SkColorFilterImageFilter::Make(std::move(blueToRed),
478 nullptr));
479 sk_sp<SkColorFilter> redToGreen(SkColorFilter::MakeMatrixFilterRowMajor255(redToGreenMatrix));
480 sk_sp<SkImageFilter> filter2(SkColorFilterImageFilter::Make(std::move(redToGreen),
481 std::move(filter1)));
senorblanco3df05012014-07-03 11:13:09 -0700482
483 SkBitmap result;
484 result.allocN32Pixels(kBitmapSize, kBitmapSize);
485
486 SkPaint paint;
487 paint.setColor(SK_ColorBLUE);
robertphillips5605b562016-04-05 11:50:42 -0700488 paint.setImageFilter(std::move(filter2));
senorblanco3df05012014-07-03 11:13:09 -0700489 SkCanvas canvas(result);
490 canvas.clear(0x0);
491 SkRect rect = SkRect::Make(SkIRect::MakeWH(kBitmapSize, kBitmapSize));
492 canvas.drawRect(rect, paint);
493 uint32_t pixel = *result.getAddr32(0, 0);
494 // The result here should be green, since we have effectively shifted blue to green.
495 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
496 }
497
498 {
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000499 // Tests pass by not asserting
reed9ce9d672016-03-17 10:51:11 -0700500 sk_sp<SkImage> image(make_small_image());
fmalita5598b632015-09-15 11:26:13 -0700501 SkBitmap result;
mike@reedtribe.orgdeee4962014-02-13 14:41:43 +0000502 result.allocN32Pixels(kBitmapSize, kBitmapSize);
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000503
senorblanco@chromium.org194d7752013-07-24 22:19:24 +0000504 {
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000505 // This tests for :
506 // 1 ) location at (0,0,1)
robertphillips3d32d762015-07-13 13:16:44 -0700507 SkPoint3 location = SkPoint3::Make(0, 0, SK_Scalar1);
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000508 // 2 ) location and target at same value
robertphillips3d32d762015-07-13 13:16:44 -0700509 SkPoint3 target = SkPoint3::Make(location.fX, location.fY, location.fZ);
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000510 // 3 ) large negative specular exponent value
511 SkScalar specularExponent = -1000;
512
robertphillips549c8992016-04-01 09:28:51 -0700513 sk_sp<SkImageFilter> bmSrc(SkImageSource::Make(std::move(image)));
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000514 SkPaint paint;
robertphillips12fa47d2016-04-08 16:28:09 -0700515 paint.setImageFilter(SkLightingImageFilter::MakeSpotLitSpecular(
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000516 location, target, specularExponent, 180,
517 0xFFFFFFFF, SK_Scalar1, SK_Scalar1, SK_Scalar1,
robertphillips12fa47d2016-04-08 16:28:09 -0700518 std::move(bmSrc)));
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000519 SkCanvas canvas(result);
520 SkRect r = SkRect::MakeWH(SkIntToScalar(kBitmapSize),
521 SkIntToScalar(kBitmapSize));
522 canvas.drawRect(r, paint);
senorblanco@chromium.org194d7752013-07-24 22:19:24 +0000523 }
senorblanco@chromium.org194d7752013-07-24 22:19:24 +0000524 }
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +0000525}
senorblanco@chromium.org6776b822014-01-03 21:48:22 +0000526
robertphillips3e302272016-04-20 11:48:36 -0700527static void test_crop_rects(skiatest::Reporter* reporter,
robertphillips4418dba2016-03-07 12:45:14 -0800528 GrContext* context) {
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +0000529 // Check that all filters offset to their absolute crop rect,
530 // unaffected by the input crop rect.
531 // Tests pass by not asserting.
robertphillips3e302272016-04-20 11:48:36 -0700532 sk_sp<SkSpecialImage> srcImg(create_empty_special_image(context, 100));
robertphillips4418dba2016-03-07 12:45:14 -0800533 SkASSERT(srcImg);
senorblanco@chromium.org6776b822014-01-03 21:48:22 +0000534
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +0000535 SkImageFilter::CropRect inputCropRect(SkRect::MakeXYWH(8, 13, 80, 80));
536 SkImageFilter::CropRect cropRect(SkRect::MakeXYWH(20, 30, 60, 60));
robertphillipsfc11b0a2016-04-05 09:09:36 -0700537 sk_sp<SkImageFilter> input(make_grayscale(nullptr, &inputCropRect));
senorblanco@chromium.org6776b822014-01-03 21:48:22 +0000538
robertphillipsfc11b0a2016-04-05 09:09:36 -0700539 FilterList filters(input, &cropRect);
senorblanco@chromium.org6776b822014-01-03 21:48:22 +0000540
senorblanco297f7ce2016-03-23 13:44:26 -0700541 for (int i = 0; i < filters.count(); ++i) {
542 SkImageFilter* filter = filters.getFilter(i);
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +0000543 SkIPoint offset;
brianosman2a75e5d2016-09-22 07:15:37 -0700544 SkImageFilter::OutputProperties noColorSpace(nullptr);
545 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeWH(100, 100), nullptr, noColorSpace);
robertphillips2302de92016-03-24 07:26:32 -0700546 sk_sp<SkSpecialImage> resultImg(filter->filterImage(srcImg.get(), ctx, &offset));
senorblanco297f7ce2016-03-23 13:44:26 -0700547 REPORTER_ASSERT_MESSAGE(reporter, resultImg, filters.getName(i));
548 REPORTER_ASSERT_MESSAGE(reporter, offset.fX == 20 && offset.fY == 30, filters.getName(i));
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +0000549 }
550}
551
robertphillips3e302272016-04-20 11:48:36 -0700552static void test_negative_blur_sigma(skiatest::Reporter* reporter,
robertphillips4418dba2016-03-07 12:45:14 -0800553 GrContext* context) {
senorblanco32673b92014-09-09 09:15:04 -0700554 // Check that SkBlurImageFilter will accept a negative sigma, either in
555 // the given arguments or after CTM application.
reed5ea95df2015-10-06 14:05:32 -0700556 const int width = 32, height = 32;
557 const SkScalar five = SkIntToScalar(5);
senorblanco32673b92014-09-09 09:15:04 -0700558
robertphillips6e7025a2016-04-04 04:31:25 -0700559 sk_sp<SkImageFilter> positiveFilter(SkBlurImageFilter::Make(five, five, nullptr));
560 sk_sp<SkImageFilter> negativeFilter(SkBlurImageFilter::Make(-five, five, nullptr));
senorblanco32673b92014-09-09 09:15:04 -0700561
562 SkBitmap gradient = make_gradient_circle(width, height);
robertphillips3e302272016-04-20 11:48:36 -0700563 sk_sp<SkSpecialImage> imgSrc(SkSpecialImage::MakeFromRaster(SkIRect::MakeWH(width, height),
robertphillips37bd7c32016-03-17 14:31:39 -0700564 gradient));
robertphillips4418dba2016-03-07 12:45:14 -0800565
senorblanco32673b92014-09-09 09:15:04 -0700566 SkIPoint offset;
brianosman2a75e5d2016-09-22 07:15:37 -0700567 SkImageFilter::OutputProperties noColorSpace(nullptr);
568 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeWH(32, 32), nullptr, noColorSpace);
robertphillips4418dba2016-03-07 12:45:14 -0800569
robertphillips2302de92016-03-24 07:26:32 -0700570 sk_sp<SkSpecialImage> positiveResult1(positiveFilter->filterImage(imgSrc.get(), ctx, &offset));
robertphillips4418dba2016-03-07 12:45:14 -0800571 REPORTER_ASSERT(reporter, positiveResult1);
572
robertphillips2302de92016-03-24 07:26:32 -0700573 sk_sp<SkSpecialImage> negativeResult1(negativeFilter->filterImage(imgSrc.get(), ctx, &offset));
robertphillips4418dba2016-03-07 12:45:14 -0800574 REPORTER_ASSERT(reporter, negativeResult1);
575
senorblanco32673b92014-09-09 09:15:04 -0700576 SkMatrix negativeScale;
577 negativeScale.setScale(-SK_Scalar1, SK_Scalar1);
brianosman2a75e5d2016-09-22 07:15:37 -0700578 SkImageFilter::Context negativeCTX(negativeScale, SkIRect::MakeWH(32, 32), nullptr,
579 noColorSpace);
robertphillips4418dba2016-03-07 12:45:14 -0800580
robertphillips2302de92016-03-24 07:26:32 -0700581 sk_sp<SkSpecialImage> negativeResult2(positiveFilter->filterImage(imgSrc.get(),
582 negativeCTX,
583 &offset));
robertphillips4418dba2016-03-07 12:45:14 -0800584 REPORTER_ASSERT(reporter, negativeResult2);
585
robertphillips2302de92016-03-24 07:26:32 -0700586 sk_sp<SkSpecialImage> positiveResult2(negativeFilter->filterImage(imgSrc.get(),
587 negativeCTX,
588 &offset));
robertphillips4418dba2016-03-07 12:45:14 -0800589 REPORTER_ASSERT(reporter, positiveResult2);
590
591
592 SkBitmap positiveResultBM1, positiveResultBM2;
593 SkBitmap negativeResultBM1, negativeResultBM2;
594
robertphillips64612512016-04-08 12:10:42 -0700595 REPORTER_ASSERT(reporter, positiveResult1->getROPixels(&positiveResultBM1));
596 REPORTER_ASSERT(reporter, positiveResult2->getROPixels(&positiveResultBM2));
597 REPORTER_ASSERT(reporter, negativeResult1->getROPixels(&negativeResultBM1));
598 REPORTER_ASSERT(reporter, negativeResult2->getROPixels(&negativeResultBM2));
robertphillips4418dba2016-03-07 12:45:14 -0800599
senorblanco32673b92014-09-09 09:15:04 -0700600 for (int y = 0; y < height; y++) {
robertphillips4418dba2016-03-07 12:45:14 -0800601 int diffs = memcmp(positiveResultBM1.getAddr32(0, y),
602 negativeResultBM1.getAddr32(0, y),
603 positiveResultBM1.rowBytes());
senorblanco32673b92014-09-09 09:15:04 -0700604 REPORTER_ASSERT(reporter, !diffs);
605 if (diffs) {
606 break;
607 }
robertphillips4418dba2016-03-07 12:45:14 -0800608 diffs = memcmp(positiveResultBM1.getAddr32(0, y),
609 negativeResultBM2.getAddr32(0, y),
610 positiveResultBM1.rowBytes());
senorblanco32673b92014-09-09 09:15:04 -0700611 REPORTER_ASSERT(reporter, !diffs);
612 if (diffs) {
613 break;
614 }
robertphillips4418dba2016-03-07 12:45:14 -0800615 diffs = memcmp(positiveResultBM1.getAddr32(0, y),
616 positiveResultBM2.getAddr32(0, y),
617 positiveResultBM1.rowBytes());
senorblanco32673b92014-09-09 09:15:04 -0700618 REPORTER_ASSERT(reporter, !diffs);
619 if (diffs) {
620 break;
621 }
622 }
623}
624
senorblanco21a465d2016-04-11 11:58:39 -0700625DEF_TEST(ImageFilterNegativeBlurSigma, reporter) {
robertphillips3e302272016-04-20 11:48:36 -0700626 test_negative_blur_sigma(reporter, nullptr);
robertphillips4418dba2016-03-07 12:45:14 -0800627}
628
629#if SK_SUPPORT_GPU
bsalomon68d91342016-04-12 09:59:58 -0700630DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterNegativeBlurSigma_Gpu, reporter, ctxInfo) {
bsalomon8b7451a2016-05-11 06:33:06 -0700631 test_negative_blur_sigma(reporter, ctxInfo.grContext());
robertphillips4418dba2016-03-07 12:45:14 -0800632}
633#endif
634
robertphillips3e302272016-04-20 11:48:36 -0700635static void test_zero_blur_sigma(skiatest::Reporter* reporter, GrContext* context) {
senorblancobf680c32016-03-16 16:15:53 -0700636 // Check that SkBlurImageFilter with a zero sigma and a non-zero srcOffset works correctly.
637 SkImageFilter::CropRect cropRect(SkRect::Make(SkIRect::MakeXYWH(5, 0, 5, 10)));
robertphillips51a315e2016-03-31 09:05:49 -0700638 sk_sp<SkImageFilter> input(SkOffsetImageFilter::Make(0, 0, nullptr, &cropRect));
robertphillips6e7025a2016-04-04 04:31:25 -0700639 sk_sp<SkImageFilter> filter(SkBlurImageFilter::Make(0, 0, std::move(input), &cropRect));
senorblancobf680c32016-03-16 16:15:53 -0700640
robertphillips3e302272016-04-20 11:48:36 -0700641 sk_sp<SkSpecialSurface> surf(create_empty_special_surface(context, 10));
senorblancobf680c32016-03-16 16:15:53 -0700642 surf->getCanvas()->clear(SK_ColorGREEN);
robertphillips37bd7c32016-03-17 14:31:39 -0700643 sk_sp<SkSpecialImage> image(surf->makeImageSnapshot());
senorblancobf680c32016-03-16 16:15:53 -0700644
645 SkIPoint offset;
brianosman2a75e5d2016-09-22 07:15:37 -0700646 SkImageFilter::OutputProperties noColorSpace(nullptr);
647 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeWH(32, 32), nullptr, noColorSpace);
senorblancobf680c32016-03-16 16:15:53 -0700648
robertphillips2302de92016-03-24 07:26:32 -0700649 sk_sp<SkSpecialImage> result(filter->filterImage(image.get(), ctx, &offset));
senorblancobf680c32016-03-16 16:15:53 -0700650 REPORTER_ASSERT(reporter, offset.fX == 5 && offset.fY == 0);
651 REPORTER_ASSERT(reporter, result);
652 REPORTER_ASSERT(reporter, result->width() == 5 && result->height() == 10);
653
654 SkBitmap resultBM;
655
robertphillips64612512016-04-08 12:10:42 -0700656 REPORTER_ASSERT(reporter, result->getROPixels(&resultBM));
senorblancobf680c32016-03-16 16:15:53 -0700657
senorblancobf680c32016-03-16 16:15:53 -0700658 for (int y = 0; y < resultBM.height(); y++) {
659 for (int x = 0; x < resultBM.width(); x++) {
660 bool diff = *resultBM.getAddr32(x, y) != SK_ColorGREEN;
661 REPORTER_ASSERT(reporter, !diff);
662 if (diff) {
663 break;
664 }
665 }
666 }
667}
668
senorblanco21a465d2016-04-11 11:58:39 -0700669DEF_TEST(ImageFilterZeroBlurSigma, reporter) {
robertphillips3e302272016-04-20 11:48:36 -0700670 test_zero_blur_sigma(reporter, nullptr);
senorblancobf680c32016-03-16 16:15:53 -0700671}
672
673#if SK_SUPPORT_GPU
bsalomon68d91342016-04-12 09:59:58 -0700674DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterZeroBlurSigma_Gpu, reporter, ctxInfo) {
bsalomon8b7451a2016-05-11 06:33:06 -0700675 test_zero_blur_sigma(reporter, ctxInfo.grContext());
senorblancobf680c32016-03-16 16:15:53 -0700676}
677#endif
678
senorblanco6a93fa12016-04-05 04:43:45 -0700679
680// Tests that, even when an upstream filter has returned null (due to failure or clipping), a
681// downstream filter that affects transparent black still does so even with a nullptr input.
robertphillips3e302272016-04-20 11:48:36 -0700682static void test_fail_affects_transparent_black(skiatest::Reporter* reporter, GrContext* context) {
senorblanco6a93fa12016-04-05 04:43:45 -0700683 sk_sp<FailImageFilter> failFilter(new FailImageFilter());
robertphillips3e302272016-04-20 11:48:36 -0700684 sk_sp<SkSpecialImage> source(create_empty_special_image(context, 5));
brianosman2a75e5d2016-09-22 07:15:37 -0700685 SkImageFilter::OutputProperties noColorSpace(nullptr);
686 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeXYWH(0, 0, 1, 1), nullptr, noColorSpace);
Mike Reed7d954ad2016-10-28 15:42:34 -0400687 sk_sp<SkColorFilter> green(SkColorFilter::MakeModeFilter(SK_ColorGREEN, SkBlendMode::kSrc));
senorblanco6a93fa12016-04-05 04:43:45 -0700688 SkASSERT(green->affectsTransparentBlack());
robertphillips5605b562016-04-05 11:50:42 -0700689 sk_sp<SkImageFilter> greenFilter(SkColorFilterImageFilter::Make(std::move(green),
690 std::move(failFilter)));
senorblanco6a93fa12016-04-05 04:43:45 -0700691 SkIPoint offset;
692 sk_sp<SkSpecialImage> result(greenFilter->filterImage(source.get(), ctx, &offset));
693 REPORTER_ASSERT(reporter, nullptr != result.get());
694 if (result.get()) {
695 SkBitmap resultBM;
robertphillips64612512016-04-08 12:10:42 -0700696 REPORTER_ASSERT(reporter, result->getROPixels(&resultBM));
senorblanco6a93fa12016-04-05 04:43:45 -0700697 REPORTER_ASSERT(reporter, *resultBM.getAddr32(0, 0) == SK_ColorGREEN);
698 }
699}
700
701DEF_TEST(ImageFilterFailAffectsTransparentBlack, reporter) {
robertphillips3e302272016-04-20 11:48:36 -0700702 test_fail_affects_transparent_black(reporter, nullptr);
senorblanco6a93fa12016-04-05 04:43:45 -0700703}
704
705#if SK_SUPPORT_GPU
bsalomon68d91342016-04-12 09:59:58 -0700706DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterFailAffectsTransparentBlack_Gpu, reporter, ctxInfo) {
bsalomon8b7451a2016-05-11 06:33:06 -0700707 test_fail_affects_transparent_black(reporter, ctxInfo.grContext());
senorblanco6a93fa12016-04-05 04:43:45 -0700708}
709#endif
710
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +0000711DEF_TEST(ImageFilterDrawTiled, reporter) {
712 // Check that all filters when drawn tiled (with subsequent clip rects) exactly
713 // match the same filters drawn with a single full-canvas bitmap draw.
714 // Tests pass by not asserting.
715
robertphillipsfc11b0a2016-04-05 09:09:36 -0700716 FilterList filters(nullptr);
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +0000717
718 SkBitmap untiledResult, tiledResult;
reed5ea95df2015-10-06 14:05:32 -0700719 const int width = 64, height = 64;
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +0000720 untiledResult.allocN32Pixels(width, height);
721 tiledResult.allocN32Pixels(width, height);
722 SkCanvas tiledCanvas(tiledResult);
723 SkCanvas untiledCanvas(untiledResult);
senorblanco@chromium.orgd4db6572014-05-07 20:00:04 +0000724 int tileSize = 8;
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +0000725
senorblanco@chromium.orgd4db6572014-05-07 20:00:04 +0000726 for (int scale = 1; scale <= 2; ++scale) {
senorblanco297f7ce2016-03-23 13:44:26 -0700727 for (int i = 0; i < filters.count(); ++i) {
senorblanco@chromium.orgd4db6572014-05-07 20:00:04 +0000728 tiledCanvas.clear(0);
729 untiledCanvas.clear(0);
730 SkPaint paint;
Mike Reed5e257172016-11-01 11:22:05 -0400731 paint.setImageFilter(sk_ref_sp(filters.getFilter(i)));
senorblanco@chromium.orgd4db6572014-05-07 20:00:04 +0000732 paint.setTextSize(SkIntToScalar(height));
733 paint.setColor(SK_ColorWHITE);
734 SkString str;
735 const char* text = "ABC";
736 SkScalar ypos = SkIntToScalar(height);
737 untiledCanvas.save();
738 untiledCanvas.scale(SkIntToScalar(scale), SkIntToScalar(scale));
Cary Clark2a475ea2017-04-28 15:35:12 -0400739 untiledCanvas.drawString(text, 0, ypos, paint);
senorblanco@chromium.orgd4db6572014-05-07 20:00:04 +0000740 untiledCanvas.restore();
741 for (int y = 0; y < height; y += tileSize) {
742 for (int x = 0; x < width; x += tileSize) {
743 tiledCanvas.save();
744 tiledCanvas.clipRect(SkRect::Make(SkIRect::MakeXYWH(x, y, tileSize, tileSize)));
745 tiledCanvas.scale(SkIntToScalar(scale), SkIntToScalar(scale));
Cary Clark2a475ea2017-04-28 15:35:12 -0400746 tiledCanvas.drawString(text, 0, ypos, paint);
senorblanco@chromium.orgd4db6572014-05-07 20:00:04 +0000747 tiledCanvas.restore();
748 }
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +0000749 }
senorblanco@chromium.orgd4db6572014-05-07 20:00:04 +0000750 untiledCanvas.flush();
751 tiledCanvas.flush();
752 for (int y = 0; y < height; y++) {
753 int diffs = memcmp(untiledResult.getAddr32(0, y), tiledResult.getAddr32(0, y), untiledResult.rowBytes());
senorblanco297f7ce2016-03-23 13:44:26 -0700754 REPORTER_ASSERT_MESSAGE(reporter, !diffs, filters.getName(i));
senorblanco@chromium.orgd4db6572014-05-07 20:00:04 +0000755 if (diffs) {
756 break;
757 }
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +0000758 }
759 }
760 }
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +0000761}
762
mtklein3f3b3d02014-12-01 11:47:08 -0800763static void draw_saveLayer_picture(int width, int height, int tileSize,
robertphillipsa8d7f0b2014-08-29 08:03:56 -0700764 SkBBHFactory* factory, SkBitmap* result) {
mtkleind910f542014-08-22 09:06:34 -0700765
766 SkMatrix matrix;
767 matrix.setTranslate(SkIntToScalar(50), 0);
768
Mike Reed7d954ad2016-10-28 15:42:34 -0400769 sk_sp<SkColorFilter> cf(SkColorFilter::MakeModeFilter(SK_ColorWHITE, SkBlendMode::kSrc));
robertphillips5605b562016-04-05 11:50:42 -0700770 sk_sp<SkImageFilter> cfif(SkColorFilterImageFilter::Make(std::move(cf), nullptr));
robertphillipsae8c9332016-04-05 15:09:00 -0700771 sk_sp<SkImageFilter> imageFilter(SkImageFilter::MakeMatrixFilter(matrix,
772 kNone_SkFilterQuality,
773 std::move(cfif)));
mtkleind910f542014-08-22 09:06:34 -0700774
775 SkPaint paint;
robertphillips5605b562016-04-05 11:50:42 -0700776 paint.setImageFilter(std::move(imageFilter));
mtkleind910f542014-08-22 09:06:34 -0700777 SkPictureRecorder recorder;
778 SkRect bounds = SkRect::Make(SkIRect::MakeXYWH(0, 0, 50, 50));
mtklein3f3b3d02014-12-01 11:47:08 -0800779 SkCanvas* recordingCanvas = recorder.beginRecording(SkIntToScalar(width),
780 SkIntToScalar(height),
robertphillipsa8d7f0b2014-08-29 08:03:56 -0700781 factory, 0);
mtkleind910f542014-08-22 09:06:34 -0700782 recordingCanvas->translate(-55, 0);
783 recordingCanvas->saveLayer(&bounds, &paint);
784 recordingCanvas->restore();
reedca2622b2016-03-18 07:25:55 -0700785 sk_sp<SkPicture> picture1(recorder.finishRecordingAsPicture());
mtkleind910f542014-08-22 09:06:34 -0700786
787 result->allocN32Pixels(width, height);
788 SkCanvas canvas(*result);
789 canvas.clear(0);
790 canvas.clipRect(SkRect::Make(SkIRect::MakeWH(tileSize, tileSize)));
791 canvas.drawPicture(picture1.get());
792}
793
794DEF_TEST(ImageFilterDrawMatrixBBH, reporter) {
795 // Check that matrix filter when drawn tiled with BBH exactly
796 // matches the same thing drawn without BBH.
797 // Tests pass by not asserting.
798
799 const int width = 200, height = 200;
800 const int tileSize = 100;
801 SkBitmap result1, result2;
802 SkRTreeFactory factory;
803
robertphillipsa8d7f0b2014-08-29 08:03:56 -0700804 draw_saveLayer_picture(width, height, tileSize, &factory, &result1);
halcanary96fcdcc2015-08-27 07:41:13 -0700805 draw_saveLayer_picture(width, height, tileSize, nullptr, &result2);
mtkleind910f542014-08-22 09:06:34 -0700806
807 for (int y = 0; y < height; y++) {
808 int diffs = memcmp(result1.getAddr32(0, y), result2.getAddr32(0, y), result1.rowBytes());
809 REPORTER_ASSERT(reporter, !diffs);
810 if (diffs) {
811 break;
812 }
813 }
814}
815
robertphillips6e7025a2016-04-04 04:31:25 -0700816static sk_sp<SkImageFilter> make_blur(sk_sp<SkImageFilter> input) {
817 return SkBlurImageFilter::Make(SK_Scalar1, SK_Scalar1, std::move(input));
senorblanco1150a6d2014-08-25 12:46:58 -0700818}
819
robertphillips6e7025a2016-04-04 04:31:25 -0700820static sk_sp<SkImageFilter> make_drop_shadow(sk_sp<SkImageFilter> input) {
robertphillipsc4169122016-04-06 08:40:59 -0700821 return SkDropShadowImageFilter::Make(
senorblanco1150a6d2014-08-25 12:46:58 -0700822 SkIntToScalar(100), SkIntToScalar(100),
823 SkIntToScalar(10), SkIntToScalar(10),
sugoi234f0362014-10-23 13:59:52 -0700824 SK_ColorBLUE, SkDropShadowImageFilter::kDrawShadowAndForeground_ShadowMode,
robertphillipsc4169122016-04-06 08:40:59 -0700825 std::move(input));
senorblanco1150a6d2014-08-25 12:46:58 -0700826}
827
828DEF_TEST(ImageFilterBlurThenShadowBounds, reporter) {
robertphillips6e7025a2016-04-04 04:31:25 -0700829 sk_sp<SkImageFilter> filter1(make_blur(nullptr));
830 sk_sp<SkImageFilter> filter2(make_drop_shadow(std::move(filter1)));
senorblanco1150a6d2014-08-25 12:46:58 -0700831
832 SkIRect bounds = SkIRect::MakeXYWH(0, 0, 100, 100);
833 SkIRect expectedBounds = SkIRect::MakeXYWH(-133, -133, 236, 236);
senorblancoe5e79842016-03-21 14:51:59 -0700834 bounds = filter2->filterBounds(bounds, SkMatrix::I());
senorblanco1150a6d2014-08-25 12:46:58 -0700835
836 REPORTER_ASSERT(reporter, bounds == expectedBounds);
837}
838
839DEF_TEST(ImageFilterShadowThenBlurBounds, reporter) {
robertphillips6e7025a2016-04-04 04:31:25 -0700840 sk_sp<SkImageFilter> filter1(make_drop_shadow(nullptr));
841 sk_sp<SkImageFilter> filter2(make_blur(std::move(filter1)));
senorblanco1150a6d2014-08-25 12:46:58 -0700842
843 SkIRect bounds = SkIRect::MakeXYWH(0, 0, 100, 100);
844 SkIRect expectedBounds = SkIRect::MakeXYWH(-133, -133, 236, 236);
senorblancoe5e79842016-03-21 14:51:59 -0700845 bounds = filter2->filterBounds(bounds, SkMatrix::I());
senorblanco1150a6d2014-08-25 12:46:58 -0700846
847 REPORTER_ASSERT(reporter, bounds == expectedBounds);
848}
849
850DEF_TEST(ImageFilterDilateThenBlurBounds, reporter) {
robertphillipsfc11b0a2016-04-05 09:09:36 -0700851 sk_sp<SkImageFilter> filter1(SkDilateImageFilter::Make(2, 2, nullptr));
robertphillips6e7025a2016-04-04 04:31:25 -0700852 sk_sp<SkImageFilter> filter2(make_drop_shadow(std::move(filter1)));
senorblanco1150a6d2014-08-25 12:46:58 -0700853
854 SkIRect bounds = SkIRect::MakeXYWH(0, 0, 100, 100);
855 SkIRect expectedBounds = SkIRect::MakeXYWH(-132, -132, 234, 234);
senorblancoe5e79842016-03-21 14:51:59 -0700856 bounds = filter2->filterBounds(bounds, SkMatrix::I());
senorblanco1150a6d2014-08-25 12:46:58 -0700857
858 REPORTER_ASSERT(reporter, bounds == expectedBounds);
859}
860
jbroman203a9932016-07-11 14:07:59 -0700861DEF_TEST(ImageFilterScaledBlurRadius, reporter) {
862 // Each blur should spread 3*sigma, so 3 for the blur and 30 for the shadow
863 // (before the CTM). Bounds should be computed correctly in the presence of
864 // a (possibly negative) scale.
865 sk_sp<SkImageFilter> blur(make_blur(nullptr));
866 sk_sp<SkImageFilter> dropShadow(make_drop_shadow(nullptr));
867 {
868 // Uniform scale by 2.
869 SkMatrix scaleMatrix;
870 scaleMatrix.setScale(2, 2);
871 SkIRect bounds = SkIRect::MakeLTRB(0, 0, 200, 200);
872
873 SkIRect expectedBlurBounds = SkIRect::MakeLTRB(-6, -6, 206, 206);
874 SkIRect blurBounds = blur->filterBounds(
875 bounds, scaleMatrix, SkImageFilter::kForward_MapDirection);
876 REPORTER_ASSERT(reporter, blurBounds == expectedBlurBounds);
877 SkIRect reverseBlurBounds = blur->filterBounds(
878 bounds, scaleMatrix, SkImageFilter::kReverse_MapDirection);
879 REPORTER_ASSERT(reporter, reverseBlurBounds == expectedBlurBounds);
880
881 SkIRect expectedShadowBounds = SkIRect::MakeLTRB(0, 0, 460, 460);
882 SkIRect shadowBounds = dropShadow->filterBounds(
883 bounds, scaleMatrix, SkImageFilter::kForward_MapDirection);
884 REPORTER_ASSERT(reporter, shadowBounds == expectedShadowBounds);
885 SkIRect expectedReverseShadowBounds =
886 SkIRect::MakeLTRB(-260, -260, 200, 200);
887 SkIRect reverseShadowBounds = dropShadow->filterBounds(
888 bounds, scaleMatrix, SkImageFilter::kReverse_MapDirection);
889 REPORTER_ASSERT(reporter,
890 reverseShadowBounds == expectedReverseShadowBounds);
891 }
892 {
893 // Vertical flip.
894 SkMatrix scaleMatrix;
895 scaleMatrix.setScale(1, -1);
896 SkIRect bounds = SkIRect::MakeLTRB(0, -100, 100, 0);
897
898 SkIRect expectedBlurBounds = SkIRect::MakeLTRB(-3, -103, 103, 3);
899 SkIRect blurBounds = blur->filterBounds(
900 bounds, scaleMatrix, SkImageFilter::kForward_MapDirection);
901 REPORTER_ASSERT(reporter, blurBounds == expectedBlurBounds);
902 SkIRect reverseBlurBounds = blur->filterBounds(
903 bounds, scaleMatrix, SkImageFilter::kReverse_MapDirection);
904 REPORTER_ASSERT(reporter, reverseBlurBounds == expectedBlurBounds);
905
906 SkIRect expectedShadowBounds = SkIRect::MakeLTRB(0, -230, 230, 0);
907 SkIRect shadowBounds = dropShadow->filterBounds(
908 bounds, scaleMatrix, SkImageFilter::kForward_MapDirection);
909 REPORTER_ASSERT(reporter, shadowBounds == expectedShadowBounds);
910 SkIRect expectedReverseShadowBounds =
911 SkIRect::MakeLTRB(-130, -100, 100, 130);
912 SkIRect reverseShadowBounds = dropShadow->filterBounds(
913 bounds, scaleMatrix, SkImageFilter::kReverse_MapDirection);
914 REPORTER_ASSERT(reporter,
915 reverseShadowBounds == expectedReverseShadowBounds);
916 }
917}
918
ajuma5788faa2015-02-13 09:05:47 -0800919DEF_TEST(ImageFilterComposedBlurFastBounds, reporter) {
robertphillips6e7025a2016-04-04 04:31:25 -0700920 sk_sp<SkImageFilter> filter1(make_blur(nullptr));
921 sk_sp<SkImageFilter> filter2(make_blur(nullptr));
robertphillips491fb172016-03-30 12:32:58 -0700922 sk_sp<SkImageFilter> composedFilter(SkComposeImageFilter::Make(std::move(filter1),
923 std::move(filter2)));
ajuma5788faa2015-02-13 09:05:47 -0800924
925 SkRect boundsSrc = SkRect::MakeWH(SkIntToScalar(100), SkIntToScalar(100));
926 SkRect expectedBounds = SkRect::MakeXYWH(
927 SkIntToScalar(-6), SkIntToScalar(-6), SkIntToScalar(112), SkIntToScalar(112));
senorblancoe5e79842016-03-21 14:51:59 -0700928 SkRect boundsDst = composedFilter->computeFastBounds(boundsSrc);
ajuma5788faa2015-02-13 09:05:47 -0800929
930 REPORTER_ASSERT(reporter, boundsDst == expectedBounds);
931}
932
jbroman0e3129d2016-03-17 12:24:23 -0700933DEF_TEST(ImageFilterUnionBounds, reporter) {
robertphillips51a315e2016-03-31 09:05:49 -0700934 sk_sp<SkImageFilter> offset(SkOffsetImageFilter::Make(50, 0, nullptr));
jbroman0e3129d2016-03-17 12:24:23 -0700935 // Regardless of which order they appear in, the image filter bounds should
936 // be combined correctly.
937 {
reed374772b2016-10-05 17:33:02 -0700938 sk_sp<SkImageFilter> composite(SkXfermodeImageFilter::Make(SkBlendMode::kSrcOver, offset));
jbroman0e3129d2016-03-17 12:24:23 -0700939 SkRect bounds = SkRect::MakeWH(100, 100);
940 // Intentionally aliasing here, as that's what the real callers do.
senorblancoe5e79842016-03-21 14:51:59 -0700941 bounds = composite->computeFastBounds(bounds);
jbroman0e3129d2016-03-17 12:24:23 -0700942 REPORTER_ASSERT(reporter, bounds == SkRect::MakeWH(150, 100));
943 }
944 {
reed374772b2016-10-05 17:33:02 -0700945 sk_sp<SkImageFilter> composite(SkXfermodeImageFilter::Make(SkBlendMode::kSrcOver, nullptr,
robertphillips8c0326d2016-04-05 12:48:34 -0700946 offset, nullptr));
jbroman0e3129d2016-03-17 12:24:23 -0700947 SkRect bounds = SkRect::MakeWH(100, 100);
948 // Intentionally aliasing here, as that's what the real callers do.
senorblancoe5e79842016-03-21 14:51:59 -0700949 bounds = composite->computeFastBounds(bounds);
jbroman0e3129d2016-03-17 12:24:23 -0700950 REPORTER_ASSERT(reporter, bounds == SkRect::MakeWH(150, 100));
951 }
952}
953
robertphillips3e302272016-04-20 11:48:36 -0700954static void test_imagefilter_merge_result_size(skiatest::Reporter* reporter, GrContext* context) {
senorblanco4a243982015-11-25 07:06:55 -0800955 SkBitmap greenBM;
956 greenBM.allocN32Pixels(20, 20);
957 greenBM.eraseColor(SK_ColorGREEN);
reed9ce9d672016-03-17 10:51:11 -0700958 sk_sp<SkImage> greenImage(SkImage::MakeFromBitmap(greenBM));
robertphillips549c8992016-04-01 09:28:51 -0700959 sk_sp<SkImageFilter> source(SkImageSource::Make(std::move(greenImage)));
Mike Reed0bdaf052017-06-18 23:35:57 -0400960 sk_sp<SkImageFilter> merge(SkMergeImageFilter::Make(source, source));
senorblanco4a243982015-11-25 07:06:55 -0800961
robertphillips3e302272016-04-20 11:48:36 -0700962 sk_sp<SkSpecialImage> srcImg(create_empty_special_image(context, 1));
robertphillips4418dba2016-03-07 12:45:14 -0800963
brianosman2a75e5d2016-09-22 07:15:37 -0700964 SkImageFilter::OutputProperties noColorSpace(nullptr);
965 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeXYWH(0, 0, 100, 100), nullptr,
966 noColorSpace);
senorblanco4a243982015-11-25 07:06:55 -0800967 SkIPoint offset;
robertphillips4418dba2016-03-07 12:45:14 -0800968
robertphillips2302de92016-03-24 07:26:32 -0700969 sk_sp<SkSpecialImage> resultImg(merge->filterImage(srcImg.get(), ctx, &offset));
robertphillips4418dba2016-03-07 12:45:14 -0800970 REPORTER_ASSERT(reporter, resultImg);
971
972 REPORTER_ASSERT(reporter, resultImg->width() == 20 && resultImg->height() == 20);
senorblanco4a243982015-11-25 07:06:55 -0800973}
974
robertphillips4418dba2016-03-07 12:45:14 -0800975DEF_TEST(ImageFilterMergeResultSize, reporter) {
robertphillips3e302272016-04-20 11:48:36 -0700976 test_imagefilter_merge_result_size(reporter, nullptr);
robertphillips4418dba2016-03-07 12:45:14 -0800977}
978
979#if SK_SUPPORT_GPU
egdanielab527a52016-06-28 08:07:26 -0700980DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterMergeResultSize_Gpu, reporter, ctxInfo) {
bsalomon8b7451a2016-05-11 06:33:06 -0700981 test_imagefilter_merge_result_size(reporter, ctxInfo.grContext());
robertphillips4418dba2016-03-07 12:45:14 -0800982}
983#endif
984
robertphillipsa8d7f0b2014-08-29 08:03:56 -0700985static void draw_blurred_rect(SkCanvas* canvas) {
senorblanco837f5322014-07-14 10:19:54 -0700986 SkPaint filterPaint;
987 filterPaint.setColor(SK_ColorWHITE);
robertphillips6e7025a2016-04-04 04:31:25 -0700988 filterPaint.setImageFilter(SkBlurImageFilter::Make(SkIntToScalar(8), 0, nullptr));
halcanary96fcdcc2015-08-27 07:41:13 -0700989 canvas->saveLayer(nullptr, &filterPaint);
senorblanco837f5322014-07-14 10:19:54 -0700990 SkPaint whitePaint;
991 whitePaint.setColor(SK_ColorWHITE);
992 canvas->drawRect(SkRect::Make(SkIRect::MakeWH(4, 4)), whitePaint);
993 canvas->restore();
994}
995
robertphillipsa8d7f0b2014-08-29 08:03:56 -0700996static void draw_picture_clipped(SkCanvas* canvas, const SkRect& clipRect, const SkPicture* picture) {
senorblanco837f5322014-07-14 10:19:54 -0700997 canvas->save();
998 canvas->clipRect(clipRect);
999 canvas->drawPicture(picture);
1000 canvas->restore();
1001}
1002
1003DEF_TEST(ImageFilterDrawTiledBlurRTree, reporter) {
1004 // Check that the blur filter when recorded with RTree acceleration,
1005 // and drawn tiled (with subsequent clip rects) exactly
1006 // matches the same filter drawn with without RTree acceleration.
1007 // This tests that the "bleed" from the blur into the otherwise-blank
1008 // tiles is correctly rendered.
1009 // Tests pass by not asserting.
1010
1011 int width = 16, height = 8;
1012 SkBitmap result1, result2;
1013 result1.allocN32Pixels(width, height);
1014 result2.allocN32Pixels(width, height);
1015 SkCanvas canvas1(result1);
1016 SkCanvas canvas2(result2);
1017 int tileSize = 8;
1018
1019 canvas1.clear(0);
1020 canvas2.clear(0);
1021
1022 SkRTreeFactory factory;
1023
1024 SkPictureRecorder recorder1, recorder2;
1025 // The only difference between these two pictures is that one has RTree aceleration.
mtklein3f3b3d02014-12-01 11:47:08 -08001026 SkCanvas* recordingCanvas1 = recorder1.beginRecording(SkIntToScalar(width),
1027 SkIntToScalar(height),
halcanary96fcdcc2015-08-27 07:41:13 -07001028 nullptr, 0);
mtklein3f3b3d02014-12-01 11:47:08 -08001029 SkCanvas* recordingCanvas2 = recorder2.beginRecording(SkIntToScalar(width),
1030 SkIntToScalar(height),
robertphillipsa8d7f0b2014-08-29 08:03:56 -07001031 &factory, 0);
1032 draw_blurred_rect(recordingCanvas1);
1033 draw_blurred_rect(recordingCanvas2);
reedca2622b2016-03-18 07:25:55 -07001034 sk_sp<SkPicture> picture1(recorder1.finishRecordingAsPicture());
1035 sk_sp<SkPicture> picture2(recorder2.finishRecordingAsPicture());
senorblanco837f5322014-07-14 10:19:54 -07001036 for (int y = 0; y < height; y += tileSize) {
1037 for (int x = 0; x < width; x += tileSize) {
1038 SkRect tileRect = SkRect::Make(SkIRect::MakeXYWH(x, y, tileSize, tileSize));
reedca2622b2016-03-18 07:25:55 -07001039 draw_picture_clipped(&canvas1, tileRect, picture1.get());
1040 draw_picture_clipped(&canvas2, tileRect, picture2.get());
senorblanco837f5322014-07-14 10:19:54 -07001041 }
1042 }
1043 for (int y = 0; y < height; y++) {
1044 int diffs = memcmp(result1.getAddr32(0, y), result2.getAddr32(0, y), result1.rowBytes());
1045 REPORTER_ASSERT(reporter, !diffs);
1046 if (diffs) {
1047 break;
1048 }
1049 }
1050}
1051
senorblanco@chromium.org91957432014-05-01 14:03:41 +00001052DEF_TEST(ImageFilterMatrixConvolution, reporter) {
1053 // Check that a 1x3 filter does not cause a spurious assert.
1054 SkScalar kernel[3] = {
1055 SkIntToScalar( 1), SkIntToScalar( 1), SkIntToScalar( 1),
1056 };
1057 SkISize kernelSize = SkISize::Make(1, 3);
1058 SkScalar gain = SK_Scalar1, bias = 0;
1059 SkIPoint kernelOffset = SkIPoint::Make(0, 0);
1060
robertphillipsef6a47b2016-04-08 08:01:20 -07001061 sk_sp<SkImageFilter> filter(SkMatrixConvolutionImageFilter::Make(
1062 kernelSize, kernel,
1063 gain, bias, kernelOffset,
1064 SkMatrixConvolutionImageFilter::kRepeat_TileMode,
1065 false, nullptr));
senorblanco@chromium.org91957432014-05-01 14:03:41 +00001066
1067 SkBitmap result;
1068 int width = 16, height = 16;
1069 result.allocN32Pixels(width, height);
1070 SkCanvas canvas(result);
1071 canvas.clear(0);
1072
1073 SkPaint paint;
robertphillipsef6a47b2016-04-08 08:01:20 -07001074 paint.setImageFilter(std::move(filter));
senorblanco@chromium.org91957432014-05-01 14:03:41 +00001075 SkRect rect = SkRect::Make(SkIRect::MakeWH(width, height));
1076 canvas.drawRect(rect, paint);
1077}
1078
senorblanco@chromium.org8c7372b2014-05-02 19:13:11 +00001079DEF_TEST(ImageFilterMatrixConvolutionBorder, reporter) {
1080 // Check that a filter with borders outside the target bounds
1081 // does not crash.
1082 SkScalar kernel[3] = {
1083 0, 0, 0,
1084 };
1085 SkISize kernelSize = SkISize::Make(3, 1);
1086 SkScalar gain = SK_Scalar1, bias = 0;
1087 SkIPoint kernelOffset = SkIPoint::Make(2, 0);
1088
robertphillipsef6a47b2016-04-08 08:01:20 -07001089 sk_sp<SkImageFilter> filter(SkMatrixConvolutionImageFilter::Make(
1090 kernelSize, kernel, gain, bias, kernelOffset,
1091 SkMatrixConvolutionImageFilter::kClamp_TileMode,
1092 true, nullptr));
senorblanco@chromium.org8c7372b2014-05-02 19:13:11 +00001093
1094 SkBitmap result;
1095
1096 int width = 10, height = 10;
1097 result.allocN32Pixels(width, height);
1098 SkCanvas canvas(result);
1099 canvas.clear(0);
1100
1101 SkPaint filterPaint;
robertphillipsef6a47b2016-04-08 08:01:20 -07001102 filterPaint.setImageFilter(std::move(filter));
senorblanco@chromium.org8c7372b2014-05-02 19:13:11 +00001103 SkRect bounds = SkRect::MakeWH(1, 10);
1104 SkRect rect = SkRect::Make(SkIRect::MakeWH(width, height));
1105 SkPaint rectPaint;
1106 canvas.saveLayer(&bounds, &filterPaint);
1107 canvas.drawRect(rect, rectPaint);
1108 canvas.restore();
1109}
1110
robertphillips3e302272016-04-20 11:48:36 -07001111static void test_big_kernel(skiatest::Reporter* reporter, GrContext* context) {
robertphillipsdada4dd2016-04-13 04:54:36 -07001112 // Check that a kernel that is too big for the GPU still works
1113 SkScalar identityKernel[49] = {
1114 0, 0, 0, 0, 0, 0, 0,
1115 0, 0, 0, 0, 0, 0, 0,
1116 0, 0, 0, 0, 0, 0, 0,
1117 0, 0, 0, 1, 0, 0, 0,
1118 0, 0, 0, 0, 0, 0, 0,
1119 0, 0, 0, 0, 0, 0, 0,
1120 0, 0, 0, 0, 0, 0, 0
1121 };
1122 SkISize kernelSize = SkISize::Make(7, 7);
1123 SkScalar gain = SK_Scalar1, bias = 0;
1124 SkIPoint kernelOffset = SkIPoint::Make(0, 0);
1125
1126 sk_sp<SkImageFilter> filter(SkMatrixConvolutionImageFilter::Make(
1127 kernelSize, identityKernel, gain, bias, kernelOffset,
1128 SkMatrixConvolutionImageFilter::kClamp_TileMode,
1129 true, nullptr));
1130
robertphillips3e302272016-04-20 11:48:36 -07001131 sk_sp<SkSpecialImage> srcImg(create_empty_special_image(context, 100));
robertphillipsdada4dd2016-04-13 04:54:36 -07001132 SkASSERT(srcImg);
1133
1134 SkIPoint offset;
brianosman2a75e5d2016-09-22 07:15:37 -07001135 SkImageFilter::OutputProperties noColorSpace(nullptr);
1136 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeWH(100, 100), nullptr, noColorSpace);
robertphillipsdada4dd2016-04-13 04:54:36 -07001137 sk_sp<SkSpecialImage> resultImg(filter->filterImage(srcImg.get(), ctx, &offset));
1138 REPORTER_ASSERT(reporter, resultImg);
1139 REPORTER_ASSERT(reporter, SkToBool(context) == resultImg->isTextureBacked());
1140 REPORTER_ASSERT(reporter, resultImg->width() == 100 && resultImg->height() == 100);
1141 REPORTER_ASSERT(reporter, offset.fX == 0 && offset.fY == 0);
1142}
1143
1144DEF_TEST(ImageFilterMatrixConvolutionBigKernel, reporter) {
robertphillips3e302272016-04-20 11:48:36 -07001145 test_big_kernel(reporter, nullptr);
robertphillipsdada4dd2016-04-13 04:54:36 -07001146}
1147
1148#if SK_SUPPORT_GPU
egdanielab527a52016-06-28 08:07:26 -07001149DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterMatrixConvolutionBigKernel_Gpu,
1150 reporter, ctxInfo) {
bsalomon8b7451a2016-05-11 06:33:06 -07001151 test_big_kernel(reporter, ctxInfo.grContext());
robertphillipsdada4dd2016-04-13 04:54:36 -07001152}
1153#endif
1154
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +00001155DEF_TEST(ImageFilterCropRect, reporter) {
robertphillips3e302272016-04-20 11:48:36 -07001156 test_crop_rects(reporter, nullptr);
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +00001157}
1158
robertphillips4418dba2016-03-07 12:45:14 -08001159#if SK_SUPPORT_GPU
bsalomon68d91342016-04-12 09:59:58 -07001160DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterCropRect_Gpu, reporter, ctxInfo) {
bsalomon8b7451a2016-05-11 06:33:06 -07001161 test_crop_rects(reporter, ctxInfo.grContext());
robertphillips4418dba2016-03-07 12:45:14 -08001162}
1163#endif
1164
tfarina9ea53f92014-06-24 06:50:39 -07001165DEF_TEST(ImageFilterMatrix, reporter) {
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +00001166 SkBitmap temp;
mike@reedtribe.orgdeee4962014-02-13 14:41:43 +00001167 temp.allocN32Pixels(100, 100);
robertphillips9a53fd72015-06-22 09:46:59 -07001168 SkCanvas canvas(temp);
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +00001169 canvas.scale(SkIntToScalar(2), SkIntToScalar(2));
1170
1171 SkMatrix expectedMatrix = canvas.getTotalMatrix();
1172
commit-bot@chromium.org5fb2ce32014-04-17 23:35:06 +00001173 SkRTreeFactory factory;
1174 SkPictureRecorder recorder;
1175 SkCanvas* recordingCanvas = recorder.beginRecording(100, 100, &factory, 0);
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +00001176
1177 SkPaint paint;
robertphillips43c2ad42016-04-04 05:05:11 -07001178 paint.setImageFilter(MatrixTestImageFilter::Make(reporter, expectedMatrix));
halcanary96fcdcc2015-08-27 07:41:13 -07001179 recordingCanvas->saveLayer(nullptr, &paint);
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +00001180 SkPaint solidPaint;
1181 solidPaint.setColor(0xFFFFFFFF);
1182 recordingCanvas->save();
1183 recordingCanvas->scale(SkIntToScalar(10), SkIntToScalar(10));
1184 recordingCanvas->drawRect(SkRect::Make(SkIRect::MakeWH(100, 100)), solidPaint);
1185 recordingCanvas->restore(); // scale
1186 recordingCanvas->restore(); // saveLayer
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +00001187
reedca2622b2016-03-18 07:25:55 -07001188 canvas.drawPicture(recorder.finishRecordingAsPicture());
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +00001189}
1190
senorblanco3d822c22014-07-30 14:49:31 -07001191DEF_TEST(ImageFilterCrossProcessPictureImageFilter, reporter) {
senorblanco@chromium.org97f5fc62014-05-30 20:50:56 +00001192 SkRTreeFactory factory;
1193 SkPictureRecorder recorder;
1194 SkCanvas* recordingCanvas = recorder.beginRecording(1, 1, &factory, 0);
1195
1196 // Create an SkPicture which simply draws a green 1x1 rectangle.
1197 SkPaint greenPaint;
1198 greenPaint.setColor(SK_ColorGREEN);
1199 recordingCanvas->drawRect(SkRect::Make(SkIRect::MakeWH(1, 1)), greenPaint);
reedca2622b2016-03-18 07:25:55 -07001200 sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture());
senorblanco@chromium.org97f5fc62014-05-30 20:50:56 +00001201
1202 // Wrap that SkPicture in an SkPictureImageFilter.
robertphillips5ff17b12016-03-28 13:13:42 -07001203 sk_sp<SkImageFilter> imageFilter(SkPictureImageFilter::Make(picture));
senorblanco@chromium.org97f5fc62014-05-30 20:50:56 +00001204
1205 // Check that SkPictureImageFilter successfully serializes its contained
1206 // SkPicture when not in cross-process mode.
1207 SkPaint paint;
robertphillips5ff17b12016-03-28 13:13:42 -07001208 paint.setImageFilter(imageFilter);
senorblanco@chromium.org97f5fc62014-05-30 20:50:56 +00001209 SkPictureRecorder outerRecorder;
1210 SkCanvas* outerCanvas = outerRecorder.beginRecording(1, 1, &factory, 0);
1211 SkPaint redPaintWithFilter;
1212 redPaintWithFilter.setColor(SK_ColorRED);
robertphillips5ff17b12016-03-28 13:13:42 -07001213 redPaintWithFilter.setImageFilter(imageFilter);
senorblanco@chromium.org97f5fc62014-05-30 20:50:56 +00001214 outerCanvas->drawRect(SkRect::Make(SkIRect::MakeWH(1, 1)), redPaintWithFilter);
reedca2622b2016-03-18 07:25:55 -07001215 sk_sp<SkPicture> outerPicture(outerRecorder.finishRecordingAsPicture());
senorblanco@chromium.org97f5fc62014-05-30 20:50:56 +00001216
1217 SkBitmap bitmap;
1218 bitmap.allocN32Pixels(1, 1);
robertphillips9a53fd72015-06-22 09:46:59 -07001219 SkCanvas canvas(bitmap);
senorblanco@chromium.org97f5fc62014-05-30 20:50:56 +00001220
1221 // The result here should be green, since the filter replaces the primitive's red interior.
1222 canvas.clear(0x0);
robertphillips9b14f262014-06-04 05:40:44 -07001223 canvas.drawPicture(outerPicture);
senorblanco@chromium.org97f5fc62014-05-30 20:50:56 +00001224 uint32_t pixel = *bitmap.getAddr32(0, 0);
1225 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1226
1227 // Check that, for now, SkPictureImageFilter does not serialize or
1228 // deserialize its contained picture when the filter is serialized
1229 // cross-process. Do this by "laundering" it through SkValidatingReadBuffer.
robertphillips12fa47d2016-04-08 16:28:09 -07001230 sk_sp<SkData> data(SkValidatingSerializeFlattenable(imageFilter.get()));
Mike Reed5e257172016-11-01 11:22:05 -04001231 sk_sp<SkImageFilter> unflattenedFilter = SkValidatingDeserializeImageFilter(data->data(),
1232 data->size());
senorblanco@chromium.org97f5fc62014-05-30 20:50:56 +00001233
1234 redPaintWithFilter.setImageFilter(unflattenedFilter);
1235 SkPictureRecorder crossProcessRecorder;
1236 SkCanvas* crossProcessCanvas = crossProcessRecorder.beginRecording(1, 1, &factory, 0);
1237 crossProcessCanvas->drawRect(SkRect::Make(SkIRect::MakeWH(1, 1)), redPaintWithFilter);
reedca2622b2016-03-18 07:25:55 -07001238 sk_sp<SkPicture> crossProcessPicture(crossProcessRecorder.finishRecordingAsPicture());
senorblanco@chromium.org97f5fc62014-05-30 20:50:56 +00001239
1240 canvas.clear(0x0);
robertphillips9b14f262014-06-04 05:40:44 -07001241 canvas.drawPicture(crossProcessPicture);
senorblanco@chromium.org97f5fc62014-05-30 20:50:56 +00001242 pixel = *bitmap.getAddr32(0, 0);
hendrikw446ee672015-06-16 09:28:37 -07001243 // If the security precautions are enabled, the result here should not be green, since the
1244 // filter draws nothing.
mtklein2afbe232016-02-07 12:23:10 -08001245 REPORTER_ASSERT(reporter, SkPicture::PictureIOSecurityPrecautionsEnabled()
hendrikw446ee672015-06-16 09:28:37 -07001246 ? pixel != SK_ColorGREEN : pixel == SK_ColorGREEN);
senorblanco@chromium.org97f5fc62014-05-30 20:50:56 +00001247}
1248
robertphillips3e302272016-04-20 11:48:36 -07001249static void test_clipped_picture_imagefilter(skiatest::Reporter* reporter, GrContext* context) {
reedca2622b2016-03-18 07:25:55 -07001250 sk_sp<SkPicture> picture;
senorblanco3d822c22014-07-30 14:49:31 -07001251
robertphillips4418dba2016-03-07 12:45:14 -08001252 {
1253 SkRTreeFactory factory;
1254 SkPictureRecorder recorder;
1255 SkCanvas* recordingCanvas = recorder.beginRecording(1, 1, &factory, 0);
1256
1257 // Create an SkPicture which simply draws a green 1x1 rectangle.
1258 SkPaint greenPaint;
1259 greenPaint.setColor(SK_ColorGREEN);
1260 recordingCanvas->drawRect(SkRect::Make(SkIRect::MakeWH(1, 1)), greenPaint);
reedca2622b2016-03-18 07:25:55 -07001261 picture = recorder.finishRecordingAsPicture();
robertphillips4418dba2016-03-07 12:45:14 -08001262 }
1263
robertphillips3e302272016-04-20 11:48:36 -07001264 sk_sp<SkSpecialImage> srcImg(create_empty_special_image(context, 2));
senorblanco3d822c22014-07-30 14:49:31 -07001265
robertphillips5ff17b12016-03-28 13:13:42 -07001266 sk_sp<SkImageFilter> imageFilter(SkPictureImageFilter::Make(picture));
senorblanco3d822c22014-07-30 14:49:31 -07001267
senorblanco3d822c22014-07-30 14:49:31 -07001268 SkIPoint offset;
brianosman2a75e5d2016-09-22 07:15:37 -07001269 SkImageFilter::OutputProperties noColorSpace(nullptr);
1270 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeXYWH(1, 1, 1, 1), nullptr, noColorSpace);
robertphillips4418dba2016-03-07 12:45:14 -08001271
robertphillips2302de92016-03-24 07:26:32 -07001272 sk_sp<SkSpecialImage> resultImage(imageFilter->filterImage(srcImg.get(), ctx, &offset));
robertphillips4418dba2016-03-07 12:45:14 -08001273 REPORTER_ASSERT(reporter, !resultImage);
senorblanco3d822c22014-07-30 14:49:31 -07001274}
1275
robertphillips4418dba2016-03-07 12:45:14 -08001276DEF_TEST(ImageFilterClippedPictureImageFilter, reporter) {
robertphillips3e302272016-04-20 11:48:36 -07001277 test_clipped_picture_imagefilter(reporter, nullptr);
robertphillips4418dba2016-03-07 12:45:14 -08001278}
1279
1280#if SK_SUPPORT_GPU
bsalomon68d91342016-04-12 09:59:58 -07001281DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterClippedPictureImageFilter_Gpu, reporter, ctxInfo) {
bsalomon8b7451a2016-05-11 06:33:06 -07001282 test_clipped_picture_imagefilter(reporter, ctxInfo.grContext());
robertphillips4418dba2016-03-07 12:45:14 -08001283}
1284#endif
1285
tfarina9ea53f92014-06-24 06:50:39 -07001286DEF_TEST(ImageFilterEmptySaveLayer, reporter) {
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001287 // Even when there's an empty saveLayer()/restore(), ensure that an image
1288 // filter or color filter which affects transparent black still draws.
1289
1290 SkBitmap bitmap;
1291 bitmap.allocN32Pixels(10, 10);
robertphillips9a53fd72015-06-22 09:46:59 -07001292 SkCanvas canvas(bitmap);
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001293
1294 SkRTreeFactory factory;
1295 SkPictureRecorder recorder;
1296
robertphillips5605b562016-04-05 11:50:42 -07001297 sk_sp<SkColorFilter> green(SkColorFilter::MakeModeFilter(SK_ColorGREEN,
Mike Reed7d954ad2016-10-28 15:42:34 -04001298 SkBlendMode::kSrc));
robertphillips5605b562016-04-05 11:50:42 -07001299 sk_sp<SkImageFilter> imageFilter(SkColorFilterImageFilter::Make(green, nullptr));
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001300 SkPaint imageFilterPaint;
robertphillips5605b562016-04-05 11:50:42 -07001301 imageFilterPaint.setImageFilter(std::move(imageFilter));
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001302 SkPaint colorFilterPaint;
reedd053ce92016-03-22 10:17:23 -07001303 colorFilterPaint.setColorFilter(green);
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001304
1305 SkRect bounds = SkRect::MakeWH(10, 10);
1306
1307 SkCanvas* recordingCanvas = recorder.beginRecording(10, 10, &factory, 0);
1308 recordingCanvas->saveLayer(&bounds, &imageFilterPaint);
1309 recordingCanvas->restore();
reedca2622b2016-03-18 07:25:55 -07001310 sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture());
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001311
1312 canvas.clear(0);
robertphillips9b14f262014-06-04 05:40:44 -07001313 canvas.drawPicture(picture);
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001314 uint32_t pixel = *bitmap.getAddr32(0, 0);
1315 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1316
1317 recordingCanvas = recorder.beginRecording(10, 10, &factory, 0);
halcanary96fcdcc2015-08-27 07:41:13 -07001318 recordingCanvas->saveLayer(nullptr, &imageFilterPaint);
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001319 recordingCanvas->restore();
reedca2622b2016-03-18 07:25:55 -07001320 sk_sp<SkPicture> picture2(recorder.finishRecordingAsPicture());
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001321
1322 canvas.clear(0);
robertphillips9b14f262014-06-04 05:40:44 -07001323 canvas.drawPicture(picture2);
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001324 pixel = *bitmap.getAddr32(0, 0);
1325 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1326
1327 recordingCanvas = recorder.beginRecording(10, 10, &factory, 0);
1328 recordingCanvas->saveLayer(&bounds, &colorFilterPaint);
1329 recordingCanvas->restore();
reedca2622b2016-03-18 07:25:55 -07001330 sk_sp<SkPicture> picture3(recorder.finishRecordingAsPicture());
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001331
1332 canvas.clear(0);
robertphillips9b14f262014-06-04 05:40:44 -07001333 canvas.drawPicture(picture3);
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001334 pixel = *bitmap.getAddr32(0, 0);
1335 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1336}
1337
robertphillips9a53fd72015-06-22 09:46:59 -07001338static void test_huge_blur(SkCanvas* canvas, skiatest::Reporter* reporter) {
senorblanco@chromium.org09843fd2014-03-24 20:50:59 +00001339 SkBitmap bitmap;
1340 bitmap.allocN32Pixels(100, 100);
1341 bitmap.eraseARGB(0, 0, 0, 0);
1342
1343 // Check that a blur with an insane radius does not crash or assert.
senorblanco@chromium.org09843fd2014-03-24 20:50:59 +00001344 SkPaint paint;
robertphillips6e7025a2016-04-04 04:31:25 -07001345 paint.setImageFilter(SkBlurImageFilter::Make(SkIntToScalar(1<<30),
1346 SkIntToScalar(1<<30),
1347 nullptr));
reedda420b92015-12-16 08:38:15 -08001348 canvas->drawBitmap(bitmap, 0, 0, &paint);
senorblanco@chromium.org09843fd2014-03-24 20:50:59 +00001349}
1350
1351DEF_TEST(HugeBlurImageFilter, reporter) {
1352 SkBitmap temp;
1353 temp.allocN32Pixels(100, 100);
robertphillips9a53fd72015-06-22 09:46:59 -07001354 SkCanvas canvas(temp);
1355 test_huge_blur(&canvas, reporter);
senorblanco@chromium.org09843fd2014-03-24 20:50:59 +00001356}
1357
senorblanco21a465d2016-04-11 11:58:39 -07001358DEF_TEST(ImageFilterMatrixConvolutionSanityTest, reporter) {
senorblanco3a495202014-09-29 07:57:20 -07001359 SkScalar kernel[1] = { 0 };
1360 SkScalar gain = SK_Scalar1, bias = 0;
1361 SkIPoint kernelOffset = SkIPoint::Make(1, 1);
1362
halcanary96fcdcc2015-08-27 07:41:13 -07001363 // Check that an enormous (non-allocatable) kernel gives a nullptr filter.
robertphillipsef6a47b2016-04-08 08:01:20 -07001364 sk_sp<SkImageFilter> conv(SkMatrixConvolutionImageFilter::Make(
senorblanco3a495202014-09-29 07:57:20 -07001365 SkISize::Make(1<<30, 1<<30),
1366 kernel,
1367 gain,
1368 bias,
1369 kernelOffset,
1370 SkMatrixConvolutionImageFilter::kRepeat_TileMode,
robertphillipsef6a47b2016-04-08 08:01:20 -07001371 false,
1372 nullptr));
senorblanco3a495202014-09-29 07:57:20 -07001373
halcanary96fcdcc2015-08-27 07:41:13 -07001374 REPORTER_ASSERT(reporter, nullptr == conv.get());
senorblanco3a495202014-09-29 07:57:20 -07001375
halcanary96fcdcc2015-08-27 07:41:13 -07001376 // Check that a nullptr kernel gives a nullptr filter.
robertphillipsef6a47b2016-04-08 08:01:20 -07001377 conv = SkMatrixConvolutionImageFilter::Make(
senorblanco3a495202014-09-29 07:57:20 -07001378 SkISize::Make(1, 1),
halcanary96fcdcc2015-08-27 07:41:13 -07001379 nullptr,
senorblanco3a495202014-09-29 07:57:20 -07001380 gain,
1381 bias,
1382 kernelOffset,
1383 SkMatrixConvolutionImageFilter::kRepeat_TileMode,
robertphillipsef6a47b2016-04-08 08:01:20 -07001384 false,
1385 nullptr);
senorblanco3a495202014-09-29 07:57:20 -07001386
halcanary96fcdcc2015-08-27 07:41:13 -07001387 REPORTER_ASSERT(reporter, nullptr == conv.get());
senorblanco3a495202014-09-29 07:57:20 -07001388
halcanary96fcdcc2015-08-27 07:41:13 -07001389 // Check that a kernel width < 1 gives a nullptr filter.
robertphillipsef6a47b2016-04-08 08:01:20 -07001390 conv = SkMatrixConvolutionImageFilter::Make(
senorblanco3a495202014-09-29 07:57:20 -07001391 SkISize::Make(0, 1),
1392 kernel,
1393 gain,
1394 bias,
1395 kernelOffset,
1396 SkMatrixConvolutionImageFilter::kRepeat_TileMode,
robertphillipsef6a47b2016-04-08 08:01:20 -07001397 false,
1398 nullptr);
senorblanco3a495202014-09-29 07:57:20 -07001399
halcanary96fcdcc2015-08-27 07:41:13 -07001400 REPORTER_ASSERT(reporter, nullptr == conv.get());
senorblanco3a495202014-09-29 07:57:20 -07001401
halcanary96fcdcc2015-08-27 07:41:13 -07001402 // Check that kernel height < 1 gives a nullptr filter.
robertphillipsef6a47b2016-04-08 08:01:20 -07001403 conv = SkMatrixConvolutionImageFilter::Make(
senorblanco3a495202014-09-29 07:57:20 -07001404 SkISize::Make(1, -1),
1405 kernel,
1406 gain,
1407 bias,
1408 kernelOffset,
1409 SkMatrixConvolutionImageFilter::kRepeat_TileMode,
robertphillipsef6a47b2016-04-08 08:01:20 -07001410 false,
1411 nullptr);
senorblanco3a495202014-09-29 07:57:20 -07001412
halcanary96fcdcc2015-08-27 07:41:13 -07001413 REPORTER_ASSERT(reporter, nullptr == conv.get());
senorblanco3a495202014-09-29 07:57:20 -07001414}
1415
robertphillips9a53fd72015-06-22 09:46:59 -07001416static void test_xfermode_cropped_input(SkCanvas* canvas, skiatest::Reporter* reporter) {
1417 canvas->clear(0);
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001418
1419 SkBitmap bitmap;
1420 bitmap.allocN32Pixels(1, 1);
1421 bitmap.eraseARGB(255, 255, 255, 255);
1422
robertphillips5605b562016-04-05 11:50:42 -07001423 sk_sp<SkColorFilter> green(SkColorFilter::MakeModeFilter(SK_ColorGREEN,
Mike Reed7d954ad2016-10-28 15:42:34 -04001424 SkBlendMode::kSrcIn));
robertphillips5605b562016-04-05 11:50:42 -07001425 sk_sp<SkImageFilter> greenFilter(SkColorFilterImageFilter::Make(green, nullptr));
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001426 SkImageFilter::CropRect cropRect(SkRect::MakeEmpty());
robertphillips5605b562016-04-05 11:50:42 -07001427 sk_sp<SkImageFilter> croppedOut(SkColorFilterImageFilter::Make(green, nullptr, &cropRect));
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001428
1429 // Check that an xfermode image filter whose input has been cropped out still draws the other
1430 // input. Also check that drawing with both inputs cropped out doesn't cause a GPU warning.
reed374772b2016-10-05 17:33:02 -07001431 SkBlendMode mode = SkBlendMode::kSrcOver;
robertphillips8c0326d2016-04-05 12:48:34 -07001432 sk_sp<SkImageFilter> xfermodeNoFg(SkXfermodeImageFilter::Make(mode, greenFilter,
1433 croppedOut, nullptr));
1434 sk_sp<SkImageFilter> xfermodeNoBg(SkXfermodeImageFilter::Make(mode, croppedOut,
1435 greenFilter, nullptr));
1436 sk_sp<SkImageFilter> xfermodeNoFgNoBg(SkXfermodeImageFilter::Make(mode, croppedOut,
1437 croppedOut, nullptr));
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001438
1439 SkPaint paint;
robertphillips8c0326d2016-04-05 12:48:34 -07001440 paint.setImageFilter(std::move(xfermodeNoFg));
reedda420b92015-12-16 08:38:15 -08001441 canvas->drawBitmap(bitmap, 0, 0, &paint); // drawSprite
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001442
1443 uint32_t pixel;
kkinnunena9d9a392015-03-06 07:16:00 -08001444 SkImageInfo info = SkImageInfo::Make(1, 1, kBGRA_8888_SkColorType, kUnpremul_SkAlphaType);
robertphillips9a53fd72015-06-22 09:46:59 -07001445 canvas->readPixels(info, &pixel, 4, 0, 0);
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001446 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1447
robertphillips8c0326d2016-04-05 12:48:34 -07001448 paint.setImageFilter(std::move(xfermodeNoBg));
reedda420b92015-12-16 08:38:15 -08001449 canvas->drawBitmap(bitmap, 0, 0, &paint); // drawSprite
robertphillips9a53fd72015-06-22 09:46:59 -07001450 canvas->readPixels(info, &pixel, 4, 0, 0);
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001451 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1452
robertphillips8c0326d2016-04-05 12:48:34 -07001453 paint.setImageFilter(std::move(xfermodeNoFgNoBg));
reedda420b92015-12-16 08:38:15 -08001454 canvas->drawBitmap(bitmap, 0, 0, &paint); // drawSprite
robertphillips9a53fd72015-06-22 09:46:59 -07001455 canvas->readPixels(info, &pixel, 4, 0, 0);
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001456 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1457}
1458
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001459DEF_TEST(ImageFilterNestedSaveLayer, reporter) {
1460 SkBitmap temp;
1461 temp.allocN32Pixels(50, 50);
robertphillips9a53fd72015-06-22 09:46:59 -07001462 SkCanvas canvas(temp);
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001463 canvas.clear(0x0);
1464
1465 SkBitmap bitmap;
1466 bitmap.allocN32Pixels(10, 10);
1467 bitmap.eraseColor(SK_ColorGREEN);
1468
1469 SkMatrix matrix;
1470 matrix.setScale(SkIntToScalar(2), SkIntToScalar(2));
1471 matrix.postTranslate(SkIntToScalar(-20), SkIntToScalar(-20));
robertphillipsae8c9332016-04-05 15:09:00 -07001472 sk_sp<SkImageFilter> matrixFilter(
1473 SkImageFilter::MakeMatrixFilter(matrix, kLow_SkFilterQuality, nullptr));
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001474
1475 // Test that saveLayer() with a filter nested inside another saveLayer() applies the
1476 // correct offset to the filter matrix.
1477 SkRect bounds1 = SkRect::MakeXYWH(10, 10, 30, 30);
halcanary96fcdcc2015-08-27 07:41:13 -07001478 canvas.saveLayer(&bounds1, nullptr);
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001479 SkPaint filterPaint;
robertphillipsae8c9332016-04-05 15:09:00 -07001480 filterPaint.setImageFilter(std::move(matrixFilter));
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001481 SkRect bounds2 = SkRect::MakeXYWH(20, 20, 10, 10);
1482 canvas.saveLayer(&bounds2, &filterPaint);
1483 SkPaint greenPaint;
1484 greenPaint.setColor(SK_ColorGREEN);
1485 canvas.drawRect(bounds2, greenPaint);
1486 canvas.restore();
1487 canvas.restore();
1488 SkPaint strokePaint;
1489 strokePaint.setStyle(SkPaint::kStroke_Style);
1490 strokePaint.setColor(SK_ColorRED);
1491
kkinnunena9d9a392015-03-06 07:16:00 -08001492 SkImageInfo info = SkImageInfo::Make(1, 1, kBGRA_8888_SkColorType, kUnpremul_SkAlphaType);
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001493 uint32_t pixel;
1494 canvas.readPixels(info, &pixel, 4, 25, 25);
1495 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1496
1497 // Test that drawSprite() with a filter nested inside a saveLayer() applies the
1498 // correct offset to the filter matrix.
1499 canvas.clear(0x0);
1500 canvas.readPixels(info, &pixel, 4, 25, 25);
halcanary96fcdcc2015-08-27 07:41:13 -07001501 canvas.saveLayer(&bounds1, nullptr);
reedda420b92015-12-16 08:38:15 -08001502 canvas.drawBitmap(bitmap, 20, 20, &filterPaint); // drawSprite
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001503 canvas.restore();
1504
1505 canvas.readPixels(info, &pixel, 4, 25, 25);
1506 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1507}
1508
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001509DEF_TEST(XfermodeImageFilterCroppedInput, reporter) {
1510 SkBitmap temp;
1511 temp.allocN32Pixels(100, 100);
robertphillips9a53fd72015-06-22 09:46:59 -07001512 SkCanvas canvas(temp);
1513 test_xfermode_cropped_input(&canvas, reporter);
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001514}
senorblanco@chromium.org09843fd2014-03-24 20:50:59 +00001515
robertphillips3e302272016-04-20 11:48:36 -07001516static void test_composed_imagefilter_offset(skiatest::Reporter* reporter, GrContext* context) {
1517 sk_sp<SkSpecialImage> srcImg(create_empty_special_image(context, 100));
ajuma5788faa2015-02-13 09:05:47 -08001518
1519 SkImageFilter::CropRect cropRect(SkRect::MakeXYWH(1, 0, 20, 20));
robertphillips51a315e2016-03-31 09:05:49 -07001520 sk_sp<SkImageFilter> offsetFilter(SkOffsetImageFilter::Make(0, 0, nullptr, &cropRect));
robertphillips6e7025a2016-04-04 04:31:25 -07001521 sk_sp<SkImageFilter> blurFilter(SkBlurImageFilter::Make(SK_Scalar1, SK_Scalar1,
1522 nullptr, &cropRect));
robertphillips491fb172016-03-30 12:32:58 -07001523 sk_sp<SkImageFilter> composedFilter(SkComposeImageFilter::Make(std::move(blurFilter),
1524 std::move(offsetFilter)));
ajuma5788faa2015-02-13 09:05:47 -08001525 SkIPoint offset;
brianosman2a75e5d2016-09-22 07:15:37 -07001526 SkImageFilter::OutputProperties noColorSpace(nullptr);
1527 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeWH(100, 100), nullptr, noColorSpace);
robertphillips4418dba2016-03-07 12:45:14 -08001528
robertphillips2302de92016-03-24 07:26:32 -07001529 sk_sp<SkSpecialImage> resultImg(composedFilter->filterImage(srcImg.get(), ctx, &offset));
robertphillips4418dba2016-03-07 12:45:14 -08001530 REPORTER_ASSERT(reporter, resultImg);
ajuma5788faa2015-02-13 09:05:47 -08001531 REPORTER_ASSERT(reporter, offset.fX == 1 && offset.fY == 0);
1532}
1533
robertphillips4418dba2016-03-07 12:45:14 -08001534DEF_TEST(ComposedImageFilterOffset, reporter) {
robertphillips3e302272016-04-20 11:48:36 -07001535 test_composed_imagefilter_offset(reporter, nullptr);
robertphillips4418dba2016-03-07 12:45:14 -08001536}
1537
1538#if SK_SUPPORT_GPU
bsalomon68d91342016-04-12 09:59:58 -07001539DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ComposedImageFilterOffset_Gpu, reporter, ctxInfo) {
bsalomon8b7451a2016-05-11 06:33:06 -07001540 test_composed_imagefilter_offset(reporter, ctxInfo.grContext());
robertphillips4418dba2016-03-07 12:45:14 -08001541}
1542#endif
1543
robertphillips3e302272016-04-20 11:48:36 -07001544static void test_composed_imagefilter_bounds(skiatest::Reporter* reporter, GrContext* context) {
jbroman17a65202016-03-21 08:38:58 -07001545 // The bounds passed to the inner filter must be filtered by the outer
1546 // filter, so that the inner filter produces the pixels that the outer
1547 // filter requires as input. This matters if the outer filter moves pixels.
1548 // Here, accounting for the outer offset is necessary so that the green
1549 // pixels of the picture are not clipped.
1550
1551 SkPictureRecorder recorder;
1552 SkCanvas* recordingCanvas = recorder.beginRecording(SkRect::MakeWH(200, 100));
1553 recordingCanvas->clipRect(SkRect::MakeXYWH(100, 0, 100, 100));
1554 recordingCanvas->clear(SK_ColorGREEN);
robertphillips491fb172016-03-30 12:32:58 -07001555 sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture());
robertphillips5ff17b12016-03-28 13:13:42 -07001556 sk_sp<SkImageFilter> pictureFilter(SkPictureImageFilter::Make(picture));
jbroman17a65202016-03-21 08:38:58 -07001557 SkImageFilter::CropRect cropRect(SkRect::MakeWH(100, 100));
robertphillips51a315e2016-03-31 09:05:49 -07001558 sk_sp<SkImageFilter> offsetFilter(SkOffsetImageFilter::Make(-100, 0, nullptr, &cropRect));
robertphillips491fb172016-03-30 12:32:58 -07001559 sk_sp<SkImageFilter> composedFilter(SkComposeImageFilter::Make(std::move(offsetFilter),
1560 std::move(pictureFilter)));
jbroman17a65202016-03-21 08:38:58 -07001561
robertphillips3e302272016-04-20 11:48:36 -07001562 sk_sp<SkSpecialImage> sourceImage(create_empty_special_image(context, 100));
brianosman2a75e5d2016-09-22 07:15:37 -07001563 SkImageFilter::OutputProperties noColorSpace(nullptr);
1564 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeWH(100, 100), nullptr, noColorSpace);
jbroman17a65202016-03-21 08:38:58 -07001565 SkIPoint offset;
1566 sk_sp<SkSpecialImage> result(composedFilter->filterImage(sourceImage.get(), ctx, &offset));
1567 REPORTER_ASSERT(reporter, offset.isZero());
1568 REPORTER_ASSERT(reporter, result);
1569 REPORTER_ASSERT(reporter, result->subset().size() == SkISize::Make(100, 100));
1570
1571 SkBitmap resultBM;
robertphillips64612512016-04-08 12:10:42 -07001572 REPORTER_ASSERT(reporter, result->getROPixels(&resultBM));
jbroman17a65202016-03-21 08:38:58 -07001573 REPORTER_ASSERT(reporter, resultBM.getColor(50, 50) == SK_ColorGREEN);
1574}
1575
1576DEF_TEST(ComposedImageFilterBounds, reporter) {
robertphillips3e302272016-04-20 11:48:36 -07001577 test_composed_imagefilter_bounds(reporter, nullptr);
jbroman17a65202016-03-21 08:38:58 -07001578}
1579
1580#if SK_SUPPORT_GPU
egdanielab527a52016-06-28 08:07:26 -07001581DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ComposedImageFilterBounds_Gpu, reporter, ctxInfo) {
bsalomon8b7451a2016-05-11 06:33:06 -07001582 test_composed_imagefilter_bounds(reporter, ctxInfo.grContext());
jbroman17a65202016-03-21 08:38:58 -07001583}
1584#endif
1585
robertphillips3e302272016-04-20 11:48:36 -07001586static void test_partial_crop_rect(skiatest::Reporter* reporter, GrContext* context) {
1587 sk_sp<SkSpecialImage> srcImg(create_empty_special_image(context, 100));
senorblanco24d2a7b2015-07-13 10:27:05 -07001588
1589 SkImageFilter::CropRect cropRect(SkRect::MakeXYWH(100, 0, 20, 30),
senorblancoed7cf272015-07-16 15:19:11 -07001590 SkImageFilter::CropRect::kHasWidth_CropEdge | SkImageFilter::CropRect::kHasHeight_CropEdge);
robertphillips5605b562016-04-05 11:50:42 -07001591 sk_sp<SkImageFilter> filter(make_grayscale(nullptr, &cropRect));
senorblanco24d2a7b2015-07-13 10:27:05 -07001592 SkIPoint offset;
brianosman2a75e5d2016-09-22 07:15:37 -07001593 SkImageFilter::OutputProperties noColorSpace(nullptr);
1594 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeWH(100, 100), nullptr, noColorSpace);
robertphillips4418dba2016-03-07 12:45:14 -08001595
robertphillips2302de92016-03-24 07:26:32 -07001596 sk_sp<SkSpecialImage> resultImg(filter->filterImage(srcImg.get(), ctx, &offset));
robertphillips4418dba2016-03-07 12:45:14 -08001597 REPORTER_ASSERT(reporter, resultImg);
1598
senorblanco24d2a7b2015-07-13 10:27:05 -07001599 REPORTER_ASSERT(reporter, offset.fX == 0);
1600 REPORTER_ASSERT(reporter, offset.fY == 0);
robertphillips4418dba2016-03-07 12:45:14 -08001601 REPORTER_ASSERT(reporter, resultImg->width() == 20);
1602 REPORTER_ASSERT(reporter, resultImg->height() == 30);
senorblanco24d2a7b2015-07-13 10:27:05 -07001603}
1604
senorblanco21a465d2016-04-11 11:58:39 -07001605DEF_TEST(ImageFilterPartialCropRect, reporter) {
robertphillips3e302272016-04-20 11:48:36 -07001606 test_partial_crop_rect(reporter, nullptr);
robertphillips4418dba2016-03-07 12:45:14 -08001607}
1608
1609#if SK_SUPPORT_GPU
bsalomon68d91342016-04-12 09:59:58 -07001610DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterPartialCropRect_Gpu, reporter, ctxInfo) {
bsalomon8b7451a2016-05-11 06:33:06 -07001611 test_partial_crop_rect(reporter, ctxInfo.grContext());
robertphillips4418dba2016-03-07 12:45:14 -08001612}
1613#endif
1614
senorblanco0abdf762015-08-20 11:10:41 -07001615DEF_TEST(ImageFilterCanComputeFastBounds, reporter) {
1616
robertphillips12fa47d2016-04-08 16:28:09 -07001617 {
1618 SkPoint3 location = SkPoint3::Make(0, 0, SK_Scalar1);
1619 sk_sp<SkImageFilter> lighting(SkLightingImageFilter::MakePointLitDiffuse(location,
1620 SK_ColorGREEN,
1621 0, 0, nullptr));
1622 REPORTER_ASSERT(reporter, !lighting->canComputeFastBounds());
1623 }
senorblanco0abdf762015-08-20 11:10:41 -07001624
senorblanco0abdf762015-08-20 11:10:41 -07001625 {
robertphillips6e7025a2016-04-04 04:31:25 -07001626 sk_sp<SkImageFilter> gray(make_grayscale(nullptr, nullptr));
1627 REPORTER_ASSERT(reporter, gray->canComputeFastBounds());
1628 {
1629 SkColorFilter* grayCF;
1630 REPORTER_ASSERT(reporter, gray->asAColorFilter(&grayCF));
1631 REPORTER_ASSERT(reporter, !grayCF->affectsTransparentBlack());
1632 grayCF->unref();
1633 }
1634 REPORTER_ASSERT(reporter, gray->canComputeFastBounds());
1635
1636 sk_sp<SkImageFilter> grayBlur(SkBlurImageFilter::Make(SK_Scalar1, SK_Scalar1,
1637 std::move(gray)));
1638 REPORTER_ASSERT(reporter, grayBlur->canComputeFastBounds());
senorblanco0abdf762015-08-20 11:10:41 -07001639 }
senorblanco0abdf762015-08-20 11:10:41 -07001640
robertphillips6e7025a2016-04-04 04:31:25 -07001641 {
1642 SkScalar greenMatrix[20] = { 0, 0, 0, 0, 0,
1643 0, 0, 0, 0, 1,
1644 0, 0, 0, 0, 0,
1645 0, 0, 0, 0, 1 };
1646 sk_sp<SkColorFilter> greenCF(SkColorFilter::MakeMatrixFilterRowMajor255(greenMatrix));
robertphillips5605b562016-04-05 11:50:42 -07001647 sk_sp<SkImageFilter> green(SkColorFilterImageFilter::Make(greenCF, nullptr));
senorblanco0abdf762015-08-20 11:10:41 -07001648
robertphillips6e7025a2016-04-04 04:31:25 -07001649 REPORTER_ASSERT(reporter, greenCF->affectsTransparentBlack());
1650 REPORTER_ASSERT(reporter, !green->canComputeFastBounds());
senorblanco0abdf762015-08-20 11:10:41 -07001651
robertphillips6e7025a2016-04-04 04:31:25 -07001652 sk_sp<SkImageFilter> greenBlur(SkBlurImageFilter::Make(SK_Scalar1, SK_Scalar1,
1653 std::move(green)));
1654 REPORTER_ASSERT(reporter, !greenBlur->canComputeFastBounds());
1655 }
senorblanco0abdf762015-08-20 11:10:41 -07001656
1657 uint8_t allOne[256], identity[256];
1658 for (int i = 0; i < 256; ++i) {
1659 identity[i] = i;
1660 allOne[i] = 255;
1661 }
1662
robertphillips5605b562016-04-05 11:50:42 -07001663 sk_sp<SkColorFilter> identityCF(SkTableColorFilter::MakeARGB(identity, identity,
1664 identity, allOne));
1665 sk_sp<SkImageFilter> identityFilter(SkColorFilterImageFilter::Make(identityCF, nullptr));
senorblanco0abdf762015-08-20 11:10:41 -07001666 REPORTER_ASSERT(reporter, !identityCF->affectsTransparentBlack());
1667 REPORTER_ASSERT(reporter, identityFilter->canComputeFastBounds());
1668
robertphillips5605b562016-04-05 11:50:42 -07001669 sk_sp<SkColorFilter> forceOpaqueCF(SkTableColorFilter::MakeARGB(allOne, identity,
1670 identity, identity));
1671 sk_sp<SkImageFilter> forceOpaque(SkColorFilterImageFilter::Make(forceOpaqueCF, nullptr));
senorblanco0abdf762015-08-20 11:10:41 -07001672 REPORTER_ASSERT(reporter, forceOpaqueCF->affectsTransparentBlack());
1673 REPORTER_ASSERT(reporter, !forceOpaque->canComputeFastBounds());
1674}
1675
fmalitacd56f812015-09-14 13:31:18 -07001676// Verify that SkImageSource survives serialization
1677DEF_TEST(ImageFilterImageSourceSerialization, reporter) {
reede8f30622016-03-23 18:59:25 -07001678 auto surface(SkSurface::MakeRasterN32Premul(10, 10));
fmalitacd56f812015-09-14 13:31:18 -07001679 surface->getCanvas()->clear(SK_ColorGREEN);
reed9ce9d672016-03-17 10:51:11 -07001680 sk_sp<SkImage> image(surface->makeImageSnapshot());
robertphillips549c8992016-04-01 09:28:51 -07001681 sk_sp<SkImageFilter> filter(SkImageSource::Make(std::move(image)));
fmalitacd56f812015-09-14 13:31:18 -07001682
robertphillips549c8992016-04-01 09:28:51 -07001683 sk_sp<SkData> data(SkValidatingSerializeFlattenable(filter.get()));
Mike Reed5e257172016-11-01 11:22:05 -04001684 sk_sp<SkImageFilter> unflattenedFilter = SkValidatingDeserializeImageFilter(data->data(),
1685 data->size());
fmalitacd56f812015-09-14 13:31:18 -07001686 REPORTER_ASSERT(reporter, unflattenedFilter);
1687
1688 SkBitmap bm;
1689 bm.allocN32Pixels(10, 10);
fmalita23cb88c2015-09-15 06:56:23 -07001690 bm.eraseColor(SK_ColorBLUE);
fmalitacd56f812015-09-14 13:31:18 -07001691 SkPaint paint;
1692 paint.setColor(SK_ColorRED);
1693 paint.setImageFilter(unflattenedFilter);
1694
1695 SkCanvas canvas(bm);
1696 canvas.drawRect(SkRect::MakeWH(10, 10), paint);
1697 REPORTER_ASSERT(reporter, *bm.getAddr32(0, 0) == SkPreMultiplyColor(SK_ColorGREEN));
1698}
1699
bsalomon45eefcf2016-01-05 08:39:28 -08001700static void test_large_blur_input(skiatest::Reporter* reporter, SkCanvas* canvas) {
1701 SkBitmap largeBmp;
1702 int largeW = 5000;
1703 int largeH = 5000;
1704#if SK_SUPPORT_GPU
1705 // If we're GPU-backed make the bitmap too large to be converted into a texture.
1706 if (GrContext* ctx = canvas->getGrContext()) {
1707 largeW = ctx->caps()->maxTextureSize() + 1;
1708 }
1709#endif
1710
1711 largeBmp.allocN32Pixels(largeW, largeH);
mtklein2afbe232016-02-07 12:23:10 -08001712 largeBmp.eraseColor(0);
bsalomon45eefcf2016-01-05 08:39:28 -08001713 if (!largeBmp.getPixels()) {
1714 ERRORF(reporter, "Failed to allocate large bmp.");
1715 return;
1716 }
1717
reed9ce9d672016-03-17 10:51:11 -07001718 sk_sp<SkImage> largeImage(SkImage::MakeFromBitmap(largeBmp));
bsalomon45eefcf2016-01-05 08:39:28 -08001719 if (!largeImage) {
1720 ERRORF(reporter, "Failed to create large image.");
1721 return;
1722 }
1723
robertphillips549c8992016-04-01 09:28:51 -07001724 sk_sp<SkImageFilter> largeSource(SkImageSource::Make(std::move(largeImage)));
bsalomon45eefcf2016-01-05 08:39:28 -08001725 if (!largeSource) {
1726 ERRORF(reporter, "Failed to create large SkImageSource.");
1727 return;
1728 }
1729
robertphillips6e7025a2016-04-04 04:31:25 -07001730 sk_sp<SkImageFilter> blur(SkBlurImageFilter::Make(10.f, 10.f, std::move(largeSource)));
bsalomon45eefcf2016-01-05 08:39:28 -08001731 if (!blur) {
1732 ERRORF(reporter, "Failed to create SkBlurImageFilter.");
1733 return;
1734 }
1735
1736 SkPaint paint;
robertphillips549c8992016-04-01 09:28:51 -07001737 paint.setImageFilter(std::move(blur));
bsalomon45eefcf2016-01-05 08:39:28 -08001738
1739 // This should not crash (http://crbug.com/570479).
1740 canvas->drawRect(SkRect::MakeIWH(largeW, largeH), paint);
1741}
1742
senorblanco21a465d2016-04-11 11:58:39 -07001743DEF_TEST(ImageFilterBlurLargeImage, reporter) {
reede8f30622016-03-23 18:59:25 -07001744 auto surface(SkSurface::MakeRaster(SkImageInfo::MakeN32Premul(100, 100)));
bsalomon45eefcf2016-01-05 08:39:28 -08001745 test_large_blur_input(reporter, surface->getCanvas());
1746}
1747
senorblanco5878dbd2016-05-19 14:50:29 -07001748static void test_make_with_filter(skiatest::Reporter* reporter, GrContext* context) {
Robert Phillipsa5fdc972017-02-18 16:58:09 -05001749 sk_sp<SkSurface> surface(create_surface(context, 192, 128));
senorblanco5878dbd2016-05-19 14:50:29 -07001750 surface->getCanvas()->clear(SK_ColorRED);
1751 SkPaint bluePaint;
1752 bluePaint.setColor(SK_ColorBLUE);
1753 SkIRect subset = SkIRect::MakeXYWH(25, 20, 50, 50);
1754 surface->getCanvas()->drawRect(SkRect::Make(subset), bluePaint);
1755 sk_sp<SkImage> sourceImage = surface->makeImageSnapshot();
1756
1757 sk_sp<SkImageFilter> filter = make_grayscale(nullptr, nullptr);
1758 SkIRect clipBounds = SkIRect::MakeXYWH(30, 35, 100, 100);
1759 SkIRect outSubset;
1760 SkIPoint offset;
1761 sk_sp<SkImage> result;
1762
1763 result = sourceImage->makeWithFilter(nullptr, subset, clipBounds, &outSubset, &offset);
1764 REPORTER_ASSERT(reporter, !result);
1765
1766 result = sourceImage->makeWithFilter(filter.get(), subset, clipBounds, nullptr, &offset);
1767 REPORTER_ASSERT(reporter, !result);
1768
1769 result = sourceImage->makeWithFilter(filter.get(), subset, clipBounds, &outSubset, nullptr);
1770 REPORTER_ASSERT(reporter, !result);
1771
1772 SkIRect bigSubset = SkIRect::MakeXYWH(-10000, -10000, 20000, 20000);
1773 result = sourceImage->makeWithFilter(filter.get(), bigSubset, clipBounds, &outSubset, &offset);
1774 REPORTER_ASSERT(reporter, !result);
1775
1776 SkIRect empty = SkIRect::MakeEmpty();
1777 result = sourceImage->makeWithFilter(filter.get(), empty, clipBounds, &outSubset, &offset);
1778 REPORTER_ASSERT(reporter, !result);
1779
1780 result = sourceImage->makeWithFilter(filter.get(), subset, empty, &outSubset, &offset);
1781 REPORTER_ASSERT(reporter, !result);
1782
1783 SkIRect leftField = SkIRect::MakeXYWH(-1000, 0, 100, 100);
1784 result = sourceImage->makeWithFilter(filter.get(), subset, leftField, &outSubset, &offset);
1785 REPORTER_ASSERT(reporter, !result);
1786
1787 result = sourceImage->makeWithFilter(filter.get(), subset, clipBounds, &outSubset, &offset);
1788
1789 REPORTER_ASSERT(reporter, result);
1790 REPORTER_ASSERT(reporter, result->bounds().contains(outSubset));
1791 SkIRect destRect = SkIRect::MakeXYWH(offset.x(), offset.y(),
1792 outSubset.width(), outSubset.height());
1793 REPORTER_ASSERT(reporter, clipBounds.contains(destRect));
Robert Phillipsa5fdc972017-02-18 16:58:09 -05001794
1795 // In GPU-mode, this case creates a special image with a backing size that differs from
1796 // the content size
1797 {
1798 clipBounds.setXYWH(0, 0, 170, 100);
1799 subset.setXYWH(0, 0, 160, 90);
1800
1801 filter = SkXfermodeImageFilter::Make(SkBlendMode::kSrc, nullptr);
1802 result = sourceImage->makeWithFilter(filter.get(), subset, clipBounds, &outSubset, &offset);
1803 REPORTER_ASSERT(reporter, result);
1804 }
senorblanco5878dbd2016-05-19 14:50:29 -07001805}
1806
1807DEF_TEST(ImageFilterMakeWithFilter, reporter) {
1808 test_make_with_filter(reporter, nullptr);
1809}
1810
1811#if SK_SUPPORT_GPU
1812DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterMakeWithFilter_Gpu, reporter, ctxInfo) {
1813 test_make_with_filter(reporter, ctxInfo.grContext());
1814}
1815#endif
1816
senorblanco@chromium.org58d14662014-02-03 22:36:39 +00001817#if SK_SUPPORT_GPU
reed4a8126e2014-09-22 07:29:03 -07001818
bsalomon68d91342016-04-12 09:59:58 -07001819DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterHugeBlur_Gpu, reporter, ctxInfo) {
robertphillipsefbffed2015-06-22 12:06:08 -07001820
bsalomon8b7451a2016-05-11 06:33:06 -07001821 sk_sp<SkSurface> surf(SkSurface::MakeRenderTarget(ctxInfo.grContext(),
robertphillips3e302272016-04-20 11:48:36 -07001822 SkBudgeted::kNo,
1823 SkImageInfo::MakeN32Premul(100, 100)));
robertphillips9a53fd72015-06-22 09:46:59 -07001824
robertphillips3e302272016-04-20 11:48:36 -07001825
1826 SkCanvas* canvas = surf->getCanvas();
1827
1828 test_huge_blur(canvas, reporter);
senorblanco@chromium.org09843fd2014-03-24 20:50:59 +00001829}
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001830
egdanielab527a52016-06-28 08:07:26 -07001831DEF_GPUTEST_FOR_RENDERING_CONTEXTS(XfermodeImageFilterCroppedInput_Gpu, reporter, ctxInfo) {
Brian Salomon8996e182017-07-05 17:01:48 -04001832 sk_sp<SkSurface> surf(SkSurface::MakeRenderTarget(
1833 ctxInfo.grContext(),
1834 SkBudgeted::kNo,
1835 SkImageInfo::Make(1, 1, kRGBA_8888_SkColorType, kPremul_SkAlphaType)));
robertphillips3e302272016-04-20 11:48:36 -07001836
1837 SkCanvas* canvas = surf->getCanvas();
1838
1839 test_xfermode_cropped_input(canvas, reporter);
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001840}
senorblanco32673b92014-09-09 09:15:04 -07001841
egdanielab527a52016-06-28 08:07:26 -07001842DEF_GPUTEST_FOR_ALL_CONTEXTS(ImageFilterBlurLargeImage_Gpu, reporter, ctxInfo) {
Brian Salomon8996e182017-07-05 17:01:48 -04001843 auto surface(SkSurface::MakeRenderTarget(
1844 ctxInfo.grContext(), SkBudgeted::kYes,
1845 SkImageInfo::Make(100, 100, kRGBA_8888_SkColorType, kPremul_SkAlphaType)));
bsalomon45eefcf2016-01-05 08:39:28 -08001846 test_large_blur_input(reporter, surface->getCanvas());
1847}
senorblanco@chromium.org58d14662014-02-03 22:36:39 +00001848#endif
reedbb34a8a2016-04-23 15:19:07 -07001849
1850/*
1851 * Test that colorfilterimagefilter does not require its CTM to be decomposed when it has more
1852 * than just scale/translate, but that other filters do.
1853 */
reed96a04f32016-04-25 09:25:15 -07001854DEF_TEST(ImageFilterComplexCTM, reporter) {
reedbb34a8a2016-04-23 15:19:07 -07001855 // just need a colorfilter to exercise the corresponding imagefilter
Mike Reed7d954ad2016-10-28 15:42:34 -04001856 sk_sp<SkColorFilter> cf = SkColorFilter::MakeModeFilter(SK_ColorRED, SkBlendMode::kSrcATop);
reed96a04f32016-04-25 09:25:15 -07001857 sk_sp<SkImageFilter> cfif = SkColorFilterImageFilter::Make(cf, nullptr); // can handle
1858 sk_sp<SkImageFilter> blif = SkBlurImageFilter::Make(3, 3, nullptr); // cannot handle
reedbb34a8a2016-04-23 15:19:07 -07001859
1860 struct {
1861 sk_sp<SkImageFilter> fFilter;
1862 bool fExpectCanHandle;
1863 } recs[] = {
1864 { cfif, true },
1865 { SkColorFilterImageFilter::Make(cf, cfif), true },
Mike Reed0bdaf052017-06-18 23:35:57 -04001866 { SkMergeImageFilter::Make(cfif, cfif), true },
reed96a04f32016-04-25 09:25:15 -07001867 { SkComposeImageFilter::Make(cfif, cfif), true },
1868
reedbb34a8a2016-04-23 15:19:07 -07001869 { blif, false },
reed96a04f32016-04-25 09:25:15 -07001870 { SkBlurImageFilter::Make(3, 3, cfif), false },
reedbb34a8a2016-04-23 15:19:07 -07001871 { SkColorFilterImageFilter::Make(cf, blif), false },
Mike Reed0bdaf052017-06-18 23:35:57 -04001872 { SkMergeImageFilter::Make(cfif, blif), false },
reed96a04f32016-04-25 09:25:15 -07001873 { SkComposeImageFilter::Make(blif, cfif), false },
reedbb34a8a2016-04-23 15:19:07 -07001874 };
liyuqianbfebe222016-11-14 11:17:16 -08001875
reedbb34a8a2016-04-23 15:19:07 -07001876 for (const auto& rec : recs) {
reed96a04f32016-04-25 09:25:15 -07001877 const bool canHandle = rec.fFilter->canHandleComplexCTM();
reedbb34a8a2016-04-23 15:19:07 -07001878 REPORTER_ASSERT(reporter, canHandle == rec.fExpectCanHandle);
1879 }
1880}
Florin Malita08252ec2017-07-06 12:48:15 -04001881
1882// Test that transforming the filter DAG doesn't clone shared nodes multiple times.
1883DEF_TEST(ImageFilterColorSpaceDAG, reporter) {
1884
1885 // Helper for counting makeColorSpace() clones.
1886 class TestFilter final : public SkImageFilter {
1887 public:
1888 TestFilter() : INHERITED(nullptr, 0, nullptr) {}
1889
1890#ifndef SK_IGNORE_TO_STRING
1891 void toString(SkString*) const override {}
1892#endif
1893 Factory getFactory() const override { return nullptr; }
1894
1895 size_t cloneCount() const { return fCloneCount; }
1896
1897 protected:
1898 sk_sp<SkSpecialImage> onFilterImage(SkSpecialImage* src, const Context&,
1899 SkIPoint* offset) const override {
1900 return nullptr;
1901 }
1902 sk_sp<SkImageFilter> onMakeColorSpace(SkColorSpaceXformer*) const override {
1903 fCloneCount++;
1904 return sk_ref_sp(const_cast<TestFilter*>(this));
1905 }
1906
1907 private:
1908 typedef SkImageFilter INHERITED;
1909
1910 mutable size_t fCloneCount = 0;
1911 };
1912
1913 auto filter = sk_make_sp<TestFilter>();
1914 REPORTER_ASSERT(reporter, filter->cloneCount() == 0u);
1915
1916 // Build a DAG referencing the filter twice.
1917 auto complexFilter = SkMergeImageFilter::Make(filter, SkOffsetImageFilter::Make(1, 1, filter));
1918 REPORTER_ASSERT(reporter, filter->cloneCount() == 0u);
1919
1920 auto xformer = SkColorSpaceXformer::Make(SkColorSpace::MakeSRGB());
1921 auto xformedFilter = xformer->apply(complexFilter.get());
1922
1923 // FIXME: clone count should be 1 at this point.
1924 REPORTER_ASSERT(reporter, filter->cloneCount() == 2u);
1925}