blob: a0618e5893e1c8d4ba6889c8dc3ea621b310dbc7 [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"
Mike Reed5a625e02017-08-08 15:48:54 -040041#include "sk_tool_utils.h"
senorblanco@chromium.org194d7752013-07-24 22:19:24 +000042
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +000043#if SK_SUPPORT_GPU
kkinnunen15302832015-12-01 04:35:26 -080044#include "GrContext.h"
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +000045#endif
46
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +000047static const int kBitmapSize = 4;
commit-bot@chromium.org4b681bc2013-09-13 12:40:02 +000048
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +000049namespace {
50
51class MatrixTestImageFilter : public SkImageFilter {
52public:
robertphillips43c2ad42016-04-04 05:05:11 -070053 static sk_sp<SkImageFilter> Make(skiatest::Reporter* reporter,
54 const SkMatrix& expectedMatrix) {
55 return sk_sp<SkImageFilter>(new MatrixTestImageFilter(reporter, expectedMatrix));
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +000056 }
57
robertphillipsf3f5bad2014-12-19 13:49:15 -080058 SK_TO_STRING_OVERRIDE()
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +000059 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(MatrixTestImageFilter)
60
61protected:
robertphillips4ba94e22016-04-04 12:07:47 -070062 sk_sp<SkSpecialImage> onFilterImage(SkSpecialImage* source, const Context& ctx,
63 SkIPoint* offset) const override {
robertphillips43c2ad42016-04-04 05:05:11 -070064 REPORTER_ASSERT(fReporter, ctx.ctm() == fExpectedMatrix);
robertphillips4ba94e22016-04-04 12:07:47 -070065 offset->fX = offset->fY = 0;
66 return sk_ref_sp<SkSpecialImage>(source);
robertphillips43c2ad42016-04-04 05:05:11 -070067 }
Matt Sarett62745a82017-04-17 11:57:29 -040068 sk_sp<SkImageFilter> onMakeColorSpace(SkColorSpaceXformer*) const override {
69 return sk_ref_sp(const_cast<MatrixTestImageFilter*>(this));
70 }
robertphillips43c2ad42016-04-04 05:05:11 -070071
mtklein36352bf2015-03-25 18:17:31 -070072 void flatten(SkWriteBuffer& buffer) const override {
brianosman18f13f32016-05-02 07:51:08 -070073 SkDEBUGFAIL("Should never get here");
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +000074 }
75
76private:
robertphillips43c2ad42016-04-04 05:05:11 -070077 MatrixTestImageFilter(skiatest::Reporter* reporter, const SkMatrix& expectedMatrix)
78 : INHERITED(nullptr, 0, nullptr)
79 , fReporter(reporter)
80 , fExpectedMatrix(expectedMatrix) {
81 }
82
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +000083 skiatest::Reporter* fReporter;
84 SkMatrix fExpectedMatrix;
mtklein3f3b3d02014-12-01 11:47:08 -080085
reed9fa60da2014-08-21 07:59:51 -070086 typedef SkImageFilter INHERITED;
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +000087};
88
senorblanco6a93fa12016-04-05 04:43:45 -070089class FailImageFilter : public SkImageFilter {
90public:
robertphillips6b134732016-04-15 09:58:37 -070091 FailImageFilter() : SkImageFilter(nullptr, 0, nullptr) { }
senorblanco6a93fa12016-04-05 04:43:45 -070092
93 sk_sp<SkSpecialImage> onFilterImage(SkSpecialImage* source,
94 const Context& ctx,
95 SkIPoint* offset) const override {
96 return nullptr;
97 }
Matt Sarett62745a82017-04-17 11:57:29 -040098 sk_sp<SkImageFilter> onMakeColorSpace(SkColorSpaceXformer*) const override {
99 return nullptr;
100 }
senorblanco6a93fa12016-04-05 04:43:45 -0700101
102 SK_TO_STRING_OVERRIDE()
103 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(FailImageFilter)
104
105private:
106 typedef SkImageFilter INHERITED;
107};
108
109sk_sp<SkFlattenable> FailImageFilter::CreateProc(SkReadBuffer& buffer) {
110 SK_IMAGEFILTER_UNFLATTEN_COMMON(common, 0);
111 return sk_sp<SkFlattenable>(new FailImageFilter());
112}
113
114#ifndef SK_IGNORE_TO_STRING
115void FailImageFilter::toString(SkString* str) const {
116 str->appendf("FailImageFilter: (");
117 str->append(")");
118}
119#endif
120
senorblanco297f7ce2016-03-23 13:44:26 -0700121void draw_gradient_circle(SkCanvas* canvas, int width, int height) {
122 SkScalar x = SkIntToScalar(width / 2);
123 SkScalar y = SkIntToScalar(height / 2);
124 SkScalar radius = SkMinScalar(x, y) * 0.8f;
125 canvas->clear(0x00000000);
126 SkColor colors[2];
127 colors[0] = SK_ColorWHITE;
128 colors[1] = SK_ColorBLACK;
129 sk_sp<SkShader> shader(
130 SkGradientShader::MakeRadial(SkPoint::Make(x, y), radius, colors, nullptr, 2,
131 SkShader::kClamp_TileMode)
132 );
133 SkPaint paint;
134 paint.setShader(shader);
135 canvas->drawCircle(x, y, radius, paint);
136}
137
138SkBitmap make_gradient_circle(int width, int height) {
139 SkBitmap bitmap;
140 bitmap.allocN32Pixels(width, height);
141 SkCanvas canvas(bitmap);
142 draw_gradient_circle(&canvas, width, height);
143 return bitmap;
144}
145
146class FilterList {
147public:
robertphillipsfc11b0a2016-04-05 09:09:36 -0700148 FilterList(sk_sp<SkImageFilter> input, const SkImageFilter::CropRect* cropRect = nullptr) {
senorblanco297f7ce2016-03-23 13:44:26 -0700149 SkPoint3 location = SkPoint3::Make(0, 0, SK_Scalar1);
senorblanco297f7ce2016-03-23 13:44:26 -0700150 const SkScalar five = SkIntToScalar(5);
151
robertphillips6e7025a2016-04-04 04:31:25 -0700152 {
153 sk_sp<SkColorFilter> cf(SkColorFilter::MakeModeFilter(SK_ColorRED,
Mike Reed7d954ad2016-10-28 15:42:34 -0400154 SkBlendMode::kSrcIn));
senorblanco297f7ce2016-03-23 13:44:26 -0700155
robertphillips6e7025a2016-04-04 04:31:25 -0700156 this->addFilter("color filter",
robertphillips12fa47d2016-04-08 16:28:09 -0700157 SkColorFilterImageFilter::Make(std::move(cf), input, cropRect));
robertphillips6e7025a2016-04-04 04:31:25 -0700158 }
senorblanco297f7ce2016-03-23 13:44:26 -0700159
robertphillips6e7025a2016-04-04 04:31:25 -0700160 {
161 sk_sp<SkImage> gradientImage(SkImage::MakeFromBitmap(make_gradient_circle(64, 64)));
162 sk_sp<SkImageFilter> gradientSource(SkImageSource::Make(std::move(gradientImage)));
senorblanco297f7ce2016-03-23 13:44:26 -0700163
liyuqianbfebe222016-11-14 11:17:16 -0800164 this->addFilter("displacement map",
robertphillipsbfe11fc2016-04-15 07:17:36 -0700165 SkDisplacementMapEffect::Make(SkDisplacementMapEffect::kR_ChannelSelectorType,
166 SkDisplacementMapEffect::kB_ChannelSelectorType,
167 20.0f,
168 std::move(gradientSource), input, cropRect));
robertphillips6e7025a2016-04-04 04:31:25 -0700169 }
senorblanco297f7ce2016-03-23 13:44:26 -0700170
robertphillips6e7025a2016-04-04 04:31:25 -0700171 this->addFilter("blur", SkBlurImageFilter::Make(SK_Scalar1,
172 SK_Scalar1,
robertphillipsfc11b0a2016-04-05 09:09:36 -0700173 input,
robertphillips12fa47d2016-04-08 16:28:09 -0700174 cropRect));
robertphillipsc4169122016-04-06 08:40:59 -0700175 this->addFilter("drop shadow", SkDropShadowImageFilter::Make(
senorblanco297f7ce2016-03-23 13:44:26 -0700176 SK_Scalar1, SK_Scalar1, SK_Scalar1, SK_Scalar1, SK_ColorGREEN,
robertphillipsfc11b0a2016-04-05 09:09:36 -0700177 SkDropShadowImageFilter::kDrawShadowAndForeground_ShadowMode,
robertphillips12fa47d2016-04-08 16:28:09 -0700178 input, cropRect));
179 this->addFilter("diffuse lighting",
180 SkLightingImageFilter::MakePointLitDiffuse(location, SK_ColorGREEN, 0, 0,
181 input, cropRect));
senorblanco297f7ce2016-03-23 13:44:26 -0700182 this->addFilter("specular lighting",
robertphillips12fa47d2016-04-08 16:28:09 -0700183 SkLightingImageFilter::MakePointLitSpecular(location, SK_ColorGREEN, 0, 0, 0,
184 input, cropRect));
185 {
186 SkScalar kernel[9] = {
187 SkIntToScalar(1), SkIntToScalar(1), SkIntToScalar(1),
188 SkIntToScalar(1), SkIntToScalar(-7), SkIntToScalar(1),
189 SkIntToScalar(1), SkIntToScalar(1), SkIntToScalar(1),
190 };
191 const SkISize kernelSize = SkISize::Make(3, 3);
192 const SkScalar gain = SK_Scalar1, bias = 0;
193
194 this->addFilter("matrix convolution",
robertphillipsef6a47b2016-04-08 08:01:20 -0700195 SkMatrixConvolutionImageFilter::Make(
senorblanco297f7ce2016-03-23 13:44:26 -0700196 kernelSize, kernel, gain, bias, SkIPoint::Make(1, 1),
robertphillipsfc11b0a2016-04-05 09:09:36 -0700197 SkMatrixConvolutionImageFilter::kRepeat_TileMode, false,
robertphillips12fa47d2016-04-08 16:28:09 -0700198 input, cropRect));
199 }
200
Mike Reed0bdaf052017-06-18 23:35:57 -0400201 this->addFilter("merge", SkMergeImageFilter::Make(input, input, cropRect));
robertphillips12fa47d2016-04-08 16:28:09 -0700202
robertphillips6e7025a2016-04-04 04:31:25 -0700203 {
204 SkPaint greenColorShaderPaint;
205 greenColorShaderPaint.setShader(SkShader::MakeColorShader(SK_ColorGREEN));
206
207 SkImageFilter::CropRect leftSideCropRect(SkRect::MakeXYWH(0, 0, 32, 64));
208 sk_sp<SkImageFilter> paintFilterLeft(SkPaintImageFilter::Make(greenColorShaderPaint,
209 &leftSideCropRect));
210 SkImageFilter::CropRect rightSideCropRect(SkRect::MakeXYWH(32, 0, 32, 64));
211 sk_sp<SkImageFilter> paintFilterRight(SkPaintImageFilter::Make(greenColorShaderPaint,
212 &rightSideCropRect));
213
214
215 this->addFilter("merge with disjoint inputs", SkMergeImageFilter::Make(
Mike Reed0bdaf052017-06-18 23:35:57 -0400216 std::move(paintFilterLeft), std::move(paintFilterRight), cropRect));
robertphillips6e7025a2016-04-04 04:31:25 -0700217 }
218
senorblanco297f7ce2016-03-23 13:44:26 -0700219 this->addFilter("offset",
robertphillipsfc11b0a2016-04-05 09:09:36 -0700220 SkOffsetImageFilter::Make(SK_Scalar1, SK_Scalar1, input,
robertphillips12fa47d2016-04-08 16:28:09 -0700221 cropRect));
222 this->addFilter("dilate", SkDilateImageFilter::Make(3, 2, input, cropRect));
223 this->addFilter("erode", SkErodeImageFilter::Make(2, 3, input, cropRect));
robertphillips534c2702016-04-15 07:57:40 -0700224 this->addFilter("tile", SkTileImageFilter::Make(
225 SkRect::MakeXYWH(0, 0, 50, 50),
226 cropRect ? cropRect->rect() : SkRect::MakeXYWH(0, 0, 100, 100),
227 input));
robertphillips6e7025a2016-04-04 04:31:25 -0700228
robertphillips12fa47d2016-04-08 16:28:09 -0700229 if (!cropRect) {
230 SkMatrix matrix;
231
232 matrix.setTranslate(SK_Scalar1, SK_Scalar1);
233 matrix.postRotate(SkIntToScalar(45), SK_Scalar1, SK_Scalar1);
234
235 this->addFilter("matrix",
236 SkImageFilter::MakeMatrixFilter(matrix, kLow_SkFilterQuality, input));
237 }
robertphillips6e7025a2016-04-04 04:31:25 -0700238 {
robertphillipsfc11b0a2016-04-05 09:09:36 -0700239 sk_sp<SkImageFilter> blur(SkBlurImageFilter::Make(five, five, input));
robertphillips6e7025a2016-04-04 04:31:25 -0700240
241 this->addFilter("blur and offset", SkOffsetImageFilter::Make(five, five,
242 std::move(blur),
robertphillips12fa47d2016-04-08 16:28:09 -0700243 cropRect));
robertphillips6e7025a2016-04-04 04:31:25 -0700244 }
245 {
robertphillips6e7025a2016-04-04 04:31:25 -0700246 SkPictureRecorder recorder;
Mike Klein26eb16f2017-04-10 09:50:25 -0400247 SkCanvas* recordingCanvas = recorder.beginRecording(64, 64);
robertphillips6e7025a2016-04-04 04:31:25 -0700248
249 SkPaint greenPaint;
250 greenPaint.setColor(SK_ColorGREEN);
251 recordingCanvas->drawRect(SkRect::Make(SkIRect::MakeXYWH(10, 10, 30, 20)), greenPaint);
252 sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture());
253 sk_sp<SkImageFilter> pictureFilter(SkPictureImageFilter::Make(std::move(picture)));
254
255 this->addFilter("picture and blur", SkBlurImageFilter::Make(five, five,
256 std::move(pictureFilter),
robertphillips12fa47d2016-04-08 16:28:09 -0700257 cropRect));
robertphillips6e7025a2016-04-04 04:31:25 -0700258 }
259 {
260 SkPaint paint;
261 paint.setShader(SkPerlinNoiseShader::MakeTurbulence(SK_Scalar1, SK_Scalar1, 1, 0));
262 sk_sp<SkImageFilter> paintFilter(SkPaintImageFilter::Make(paint));
263
264 this->addFilter("paint and blur", SkBlurImageFilter::Make(five, five,
265 std::move(paintFilter),
robertphillips12fa47d2016-04-08 16:28:09 -0700266 cropRect));
robertphillips6e7025a2016-04-04 04:31:25 -0700267 }
reed374772b2016-10-05 17:33:02 -0700268 this->addFilter("xfermode", SkXfermodeImageFilter::Make(SkBlendMode::kSrc, input, input,
269 cropRect));
senorblanco297f7ce2016-03-23 13:44:26 -0700270 }
271 int count() const { return fFilters.count(); }
272 SkImageFilter* getFilter(int index) const { return fFilters[index].fFilter.get(); }
273 const char* getName(int index) const { return fFilters[index].fName; }
274private:
275 struct Filter {
robertphillips12fa47d2016-04-08 16:28:09 -0700276 Filter() : fName(nullptr) {}
277 Filter(const char* name, sk_sp<SkImageFilter> filter)
278 : fName(name)
279 , fFilter(std::move(filter)) {
280 }
senorblanco297f7ce2016-03-23 13:44:26 -0700281 const char* fName;
282 sk_sp<SkImageFilter> fFilter;
283 };
robertphillips12fa47d2016-04-08 16:28:09 -0700284 void addFilter(const char* name, sk_sp<SkImageFilter> filter) {
285 fFilters.push_back(Filter(name, std::move(filter)));
senorblanco297f7ce2016-03-23 13:44:26 -0700286 }
287
288 SkTArray<Filter> fFilters;
289};
290
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +0000291}
292
reed60c9b582016-04-03 09:11:13 -0700293sk_sp<SkFlattenable> MatrixTestImageFilter::CreateProc(SkReadBuffer& buffer) {
brianosman18f13f32016-05-02 07:51:08 -0700294 SkDEBUGFAIL("Should never get here");
295 return nullptr;
reed9fa60da2014-08-21 07:59:51 -0700296}
297
robertphillipsf3f5bad2014-12-19 13:49:15 -0800298#ifndef SK_IGNORE_TO_STRING
299void MatrixTestImageFilter::toString(SkString* str) const {
300 str->appendf("MatrixTestImageFilter: (");
301 str->append(")");
302}
303#endif
304
reed9ce9d672016-03-17 10:51:11 -0700305static sk_sp<SkImage> make_small_image() {
reede8f30622016-03-23 18:59:25 -0700306 auto surface(SkSurface::MakeRasterN32Premul(kBitmapSize, kBitmapSize));
fmalita5598b632015-09-15 11:26:13 -0700307 SkCanvas* canvas = surface->getCanvas();
308 canvas->clear(0x00000000);
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000309 SkPaint darkPaint;
310 darkPaint.setColor(0xFF804020);
311 SkPaint lightPaint;
312 lightPaint.setColor(0xFF244484);
313 const int i = kBitmapSize / 4;
314 for (int y = 0; y < kBitmapSize; y += i) {
315 for (int x = 0; x < kBitmapSize; x += i) {
fmalita5598b632015-09-15 11:26:13 -0700316 canvas->save();
317 canvas->translate(SkIntToScalar(x), SkIntToScalar(y));
318 canvas->drawRect(SkRect::MakeXYWH(0, 0,
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000319 SkIntToScalar(i),
320 SkIntToScalar(i)), darkPaint);
fmalita5598b632015-09-15 11:26:13 -0700321 canvas->drawRect(SkRect::MakeXYWH(SkIntToScalar(i),
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000322 0,
323 SkIntToScalar(i),
324 SkIntToScalar(i)), lightPaint);
fmalita5598b632015-09-15 11:26:13 -0700325 canvas->drawRect(SkRect::MakeXYWH(0,
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000326 SkIntToScalar(i),
327 SkIntToScalar(i),
328 SkIntToScalar(i)), lightPaint);
fmalita5598b632015-09-15 11:26:13 -0700329 canvas->drawRect(SkRect::MakeXYWH(SkIntToScalar(i),
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000330 SkIntToScalar(i),
331 SkIntToScalar(i),
332 SkIntToScalar(i)), darkPaint);
fmalita5598b632015-09-15 11:26:13 -0700333 canvas->restore();
commit-bot@chromium.org4b681bc2013-09-13 12:40:02 +0000334 }
335 }
fmalita5598b632015-09-15 11:26:13 -0700336
reed9ce9d672016-03-17 10:51:11 -0700337 return surface->makeImageSnapshot();
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000338}
senorblanco@chromium.org194d7752013-07-24 22:19:24 +0000339
robertphillips5605b562016-04-05 11:50:42 -0700340static sk_sp<SkImageFilter> make_scale(float amount, sk_sp<SkImageFilter> input) {
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000341 SkScalar s = amount;
342 SkScalar matrix[20] = { s, 0, 0, 0, 0,
343 0, s, 0, 0, 0,
344 0, 0, s, 0, 0,
345 0, 0, 0, s, 0 };
robertphillips5605b562016-04-05 11:50:42 -0700346 sk_sp<SkColorFilter> filter(SkColorFilter::MakeMatrixFilterRowMajor255(matrix));
347 return SkColorFilterImageFilter::Make(std::move(filter), std::move(input));
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000348}
349
robertphillips5605b562016-04-05 11:50:42 -0700350static sk_sp<SkImageFilter> make_grayscale(sk_sp<SkImageFilter> input,
351 const SkImageFilter::CropRect* cropRect) {
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000352 SkScalar matrix[20];
353 memset(matrix, 0, 20 * sizeof(SkScalar));
354 matrix[0] = matrix[5] = matrix[10] = 0.2126f;
355 matrix[1] = matrix[6] = matrix[11] = 0.7152f;
356 matrix[2] = matrix[7] = matrix[12] = 0.0722f;
357 matrix[18] = 1.0f;
robertphillips5605b562016-04-05 11:50:42 -0700358 sk_sp<SkColorFilter> filter(SkColorFilter::MakeMatrixFilterRowMajor255(matrix));
359 return SkColorFilterImageFilter::Make(std::move(filter), std::move(input), cropRect);
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000360}
361
robertphillips5605b562016-04-05 11:50:42 -0700362static sk_sp<SkImageFilter> make_blue(sk_sp<SkImageFilter> input,
363 const SkImageFilter::CropRect* cropRect) {
364 sk_sp<SkColorFilter> filter(SkColorFilter::MakeModeFilter(SK_ColorBLUE,
Mike Reed7d954ad2016-10-28 15:42:34 -0400365 SkBlendMode::kSrcIn));
robertphillips5605b562016-04-05 11:50:42 -0700366 return SkColorFilterImageFilter::Make(std::move(filter), std::move(input), cropRect);
reedcedc36f2015-03-08 04:42:52 -0700367}
368
robertphillips3e302272016-04-20 11:48:36 -0700369static sk_sp<SkSpecialSurface> create_empty_special_surface(GrContext* context, int widthHeight) {
robertphillipsc91fd342016-04-25 12:32:54 -0700370#if SK_SUPPORT_GPU
robertphillips4418dba2016-03-07 12:45:14 -0800371 if (context) {
robertphillips4df16562016-04-28 15:09:34 -0700372 return SkSpecialSurface::MakeRenderTarget(context,
373 widthHeight, widthHeight,
Brian Osman777b5632016-10-14 09:16:21 -0400374 kRGBA_8888_GrPixelConfig, nullptr);
robertphillipsc91fd342016-04-25 12:32:54 -0700375 } else
376#endif
377 {
robertphillips4418dba2016-03-07 12:45:14 -0800378 const SkImageInfo info = SkImageInfo::MakeN32(widthHeight, widthHeight,
379 kOpaque_SkAlphaType);
robertphillips3e302272016-04-20 11:48:36 -0700380 return SkSpecialSurface::MakeRaster(info);
robertphillips4418dba2016-03-07 12:45:14 -0800381 }
senorblancobf680c32016-03-16 16:15:53 -0700382}
383
senorblanco5878dbd2016-05-19 14:50:29 -0700384static sk_sp<SkSurface> create_surface(GrContext* context, int width, int height) {
385 const SkImageInfo info = SkImageInfo::MakeN32(width, height, kOpaque_SkAlphaType);
386#if SK_SUPPORT_GPU
387 if (context) {
388 return SkSurface::MakeRenderTarget(context, SkBudgeted::kNo, info);
389 } else
390#endif
391 {
392 return SkSurface::MakeRaster(info);
393 }
394}
395
robertphillips3e302272016-04-20 11:48:36 -0700396static sk_sp<SkSpecialImage> create_empty_special_image(GrContext* context, int widthHeight) {
397 sk_sp<SkSpecialSurface> surf(create_empty_special_surface(context, widthHeight));
robertphillips4418dba2016-03-07 12:45:14 -0800398
399 SkASSERT(surf);
400
401 SkCanvas* canvas = surf->getCanvas();
402 SkASSERT(canvas);
403
404 canvas->clear(0x0);
405
robertphillips37bd7c32016-03-17 14:31:39 -0700406 return surf->makeImageSnapshot();
robertphillips4418dba2016-03-07 12:45:14 -0800407}
408
409
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000410DEF_TEST(ImageFilter, reporter) {
411 {
reedcedc36f2015-03-08 04:42:52 -0700412 // Check that two non-clipping color-matrice-filters concatenate into a single filter.
robertphillips5605b562016-04-05 11:50:42 -0700413 sk_sp<SkImageFilter> halfBrightness(make_scale(0.5f, nullptr));
414 sk_sp<SkImageFilter> quarterBrightness(make_scale(0.5f, std::move(halfBrightness)));
halcanary96fcdcc2015-08-27 07:41:13 -0700415 REPORTER_ASSERT(reporter, nullptr == quarterBrightness->getInput(0));
reedcedc36f2015-03-08 04:42:52 -0700416 SkColorFilter* cf;
417 REPORTER_ASSERT(reporter, quarterBrightness->asColorFilter(&cf));
halcanary96fcdcc2015-08-27 07:41:13 -0700418 REPORTER_ASSERT(reporter, cf->asColorMatrix(nullptr));
reedcedc36f2015-03-08 04:42:52 -0700419 cf->unref();
senorblanco@chromium.org194d7752013-07-24 22:19:24 +0000420 }
421
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000422 {
reedcedc36f2015-03-08 04:42:52 -0700423 // Check that a clipping color-matrice-filter followed by a color-matrice-filters
424 // concatenates into a single filter, but not a matrixfilter (due to clamping).
robertphillips5605b562016-04-05 11:50:42 -0700425 sk_sp<SkImageFilter> doubleBrightness(make_scale(2.0f, nullptr));
426 sk_sp<SkImageFilter> halfBrightness(make_scale(0.5f, std::move(doubleBrightness)));
halcanary96fcdcc2015-08-27 07:41:13 -0700427 REPORTER_ASSERT(reporter, nullptr == halfBrightness->getInput(0));
reedcedc36f2015-03-08 04:42:52 -0700428 SkColorFilter* cf;
429 REPORTER_ASSERT(reporter, halfBrightness->asColorFilter(&cf));
halcanary96fcdcc2015-08-27 07:41:13 -0700430 REPORTER_ASSERT(reporter, !cf->asColorMatrix(nullptr));
reedcedc36f2015-03-08 04:42:52 -0700431 cf->unref();
senorblanco@chromium.org194d7752013-07-24 22:19:24 +0000432 }
433
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000434 {
435 // Check that a color filter image filter without a crop rect can be
436 // expressed as a color filter.
robertphillips5605b562016-04-05 11:50:42 -0700437 sk_sp<SkImageFilter> gray(make_grayscale(nullptr, nullptr));
halcanary96fcdcc2015-08-27 07:41:13 -0700438 REPORTER_ASSERT(reporter, true == gray->asColorFilter(nullptr));
senorblanco@chromium.org194d7752013-07-24 22:19:24 +0000439 }
mtklein2afbe232016-02-07 12:23:10 -0800440
reedcedc36f2015-03-08 04:42:52 -0700441 {
442 // Check that a colorfilterimage filter without a crop rect but with an input
443 // that is another colorfilterimage can be expressed as a colorfilter (composed).
robertphillips5605b562016-04-05 11:50:42 -0700444 sk_sp<SkImageFilter> mode(make_blue(nullptr, nullptr));
445 sk_sp<SkImageFilter> gray(make_grayscale(std::move(mode), nullptr));
halcanary96fcdcc2015-08-27 07:41:13 -0700446 REPORTER_ASSERT(reporter, true == gray->asColorFilter(nullptr));
reedcedc36f2015-03-08 04:42:52 -0700447 }
448
449 {
450 // Test that if we exceed the limit of what ComposeColorFilter can combine, we still
451 // can build the DAG and won't assert if we call asColorFilter.
robertphillips5605b562016-04-05 11:50:42 -0700452 sk_sp<SkImageFilter> filter(make_blue(nullptr, nullptr));
reedcedc36f2015-03-08 04:42:52 -0700453 const int kWayTooManyForComposeColorFilter = 100;
454 for (int i = 0; i < kWayTooManyForComposeColorFilter; ++i) {
robertphillips5605b562016-04-05 11:50:42 -0700455 filter = make_blue(filter, nullptr);
reedcedc36f2015-03-08 04:42:52 -0700456 // the first few of these will succeed, but after we hit the internal limit,
457 // it will then return false.
halcanary96fcdcc2015-08-27 07:41:13 -0700458 (void)filter->asColorFilter(nullptr);
reedcedc36f2015-03-08 04:42:52 -0700459 }
460 }
reed5c518a82015-03-05 14:47:29 -0800461
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000462 {
463 // Check that a color filter image filter with a crop rect cannot
464 // be expressed as a color filter.
465 SkImageFilter::CropRect cropRect(SkRect::MakeXYWH(0, 0, 100, 100));
robertphillips5605b562016-04-05 11:50:42 -0700466 sk_sp<SkImageFilter> grayWithCrop(make_grayscale(nullptr, &cropRect));
halcanary96fcdcc2015-08-27 07:41:13 -0700467 REPORTER_ASSERT(reporter, false == grayWithCrop->asColorFilter(nullptr));
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000468 }
469
470 {
senorblanco3df05012014-07-03 11:13:09 -0700471 // Check that two non-commutative matrices are concatenated in
472 // the correct order.
473 SkScalar blueToRedMatrix[20] = { 0 };
474 blueToRedMatrix[2] = blueToRedMatrix[18] = SK_Scalar1;
475 SkScalar redToGreenMatrix[20] = { 0 };
476 redToGreenMatrix[5] = redToGreenMatrix[18] = SK_Scalar1;
robertphillips5605b562016-04-05 11:50:42 -0700477 sk_sp<SkColorFilter> blueToRed(SkColorFilter::MakeMatrixFilterRowMajor255(blueToRedMatrix));
478 sk_sp<SkImageFilter> filter1(SkColorFilterImageFilter::Make(std::move(blueToRed),
479 nullptr));
480 sk_sp<SkColorFilter> redToGreen(SkColorFilter::MakeMatrixFilterRowMajor255(redToGreenMatrix));
481 sk_sp<SkImageFilter> filter2(SkColorFilterImageFilter::Make(std::move(redToGreen),
482 std::move(filter1)));
senorblanco3df05012014-07-03 11:13:09 -0700483
484 SkBitmap result;
485 result.allocN32Pixels(kBitmapSize, kBitmapSize);
486
487 SkPaint paint;
488 paint.setColor(SK_ColorBLUE);
robertphillips5605b562016-04-05 11:50:42 -0700489 paint.setImageFilter(std::move(filter2));
senorblanco3df05012014-07-03 11:13:09 -0700490 SkCanvas canvas(result);
491 canvas.clear(0x0);
492 SkRect rect = SkRect::Make(SkIRect::MakeWH(kBitmapSize, kBitmapSize));
493 canvas.drawRect(rect, paint);
494 uint32_t pixel = *result.getAddr32(0, 0);
495 // The result here should be green, since we have effectively shifted blue to green.
496 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
497 }
498
499 {
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000500 // Tests pass by not asserting
reed9ce9d672016-03-17 10:51:11 -0700501 sk_sp<SkImage> image(make_small_image());
fmalita5598b632015-09-15 11:26:13 -0700502 SkBitmap result;
mike@reedtribe.orgdeee4962014-02-13 14:41:43 +0000503 result.allocN32Pixels(kBitmapSize, kBitmapSize);
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000504
senorblanco@chromium.org194d7752013-07-24 22:19:24 +0000505 {
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000506 // This tests for :
507 // 1 ) location at (0,0,1)
robertphillips3d32d762015-07-13 13:16:44 -0700508 SkPoint3 location = SkPoint3::Make(0, 0, SK_Scalar1);
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000509 // 2 ) location and target at same value
robertphillips3d32d762015-07-13 13:16:44 -0700510 SkPoint3 target = SkPoint3::Make(location.fX, location.fY, location.fZ);
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000511 // 3 ) large negative specular exponent value
512 SkScalar specularExponent = -1000;
513
robertphillips549c8992016-04-01 09:28:51 -0700514 sk_sp<SkImageFilter> bmSrc(SkImageSource::Make(std::move(image)));
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000515 SkPaint paint;
robertphillips12fa47d2016-04-08 16:28:09 -0700516 paint.setImageFilter(SkLightingImageFilter::MakeSpotLitSpecular(
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000517 location, target, specularExponent, 180,
518 0xFFFFFFFF, SK_Scalar1, SK_Scalar1, SK_Scalar1,
robertphillips12fa47d2016-04-08 16:28:09 -0700519 std::move(bmSrc)));
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000520 SkCanvas canvas(result);
521 SkRect r = SkRect::MakeWH(SkIntToScalar(kBitmapSize),
522 SkIntToScalar(kBitmapSize));
523 canvas.drawRect(r, paint);
senorblanco@chromium.org194d7752013-07-24 22:19:24 +0000524 }
senorblanco@chromium.org194d7752013-07-24 22:19:24 +0000525 }
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +0000526}
senorblanco@chromium.org6776b822014-01-03 21:48:22 +0000527
robertphillips3e302272016-04-20 11:48:36 -0700528static void test_crop_rects(skiatest::Reporter* reporter,
robertphillips4418dba2016-03-07 12:45:14 -0800529 GrContext* context) {
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +0000530 // Check that all filters offset to their absolute crop rect,
531 // unaffected by the input crop rect.
532 // Tests pass by not asserting.
robertphillips3e302272016-04-20 11:48:36 -0700533 sk_sp<SkSpecialImage> srcImg(create_empty_special_image(context, 100));
robertphillips4418dba2016-03-07 12:45:14 -0800534 SkASSERT(srcImg);
senorblanco@chromium.org6776b822014-01-03 21:48:22 +0000535
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +0000536 SkImageFilter::CropRect inputCropRect(SkRect::MakeXYWH(8, 13, 80, 80));
537 SkImageFilter::CropRect cropRect(SkRect::MakeXYWH(20, 30, 60, 60));
robertphillipsfc11b0a2016-04-05 09:09:36 -0700538 sk_sp<SkImageFilter> input(make_grayscale(nullptr, &inputCropRect));
senorblanco@chromium.org6776b822014-01-03 21:48:22 +0000539
robertphillipsfc11b0a2016-04-05 09:09:36 -0700540 FilterList filters(input, &cropRect);
senorblanco@chromium.org6776b822014-01-03 21:48:22 +0000541
senorblanco297f7ce2016-03-23 13:44:26 -0700542 for (int i = 0; i < filters.count(); ++i) {
543 SkImageFilter* filter = filters.getFilter(i);
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +0000544 SkIPoint offset;
brianosman2a75e5d2016-09-22 07:15:37 -0700545 SkImageFilter::OutputProperties noColorSpace(nullptr);
546 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeWH(100, 100), nullptr, noColorSpace);
robertphillips2302de92016-03-24 07:26:32 -0700547 sk_sp<SkSpecialImage> resultImg(filter->filterImage(srcImg.get(), ctx, &offset));
senorblanco297f7ce2016-03-23 13:44:26 -0700548 REPORTER_ASSERT_MESSAGE(reporter, resultImg, filters.getName(i));
549 REPORTER_ASSERT_MESSAGE(reporter, offset.fX == 20 && offset.fY == 30, filters.getName(i));
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +0000550 }
551}
552
robertphillips3e302272016-04-20 11:48:36 -0700553static void test_negative_blur_sigma(skiatest::Reporter* reporter,
robertphillips4418dba2016-03-07 12:45:14 -0800554 GrContext* context) {
senorblanco32673b92014-09-09 09:15:04 -0700555 // Check that SkBlurImageFilter will accept a negative sigma, either in
556 // the given arguments or after CTM application.
reed5ea95df2015-10-06 14:05:32 -0700557 const int width = 32, height = 32;
558 const SkScalar five = SkIntToScalar(5);
senorblanco32673b92014-09-09 09:15:04 -0700559
robertphillips6e7025a2016-04-04 04:31:25 -0700560 sk_sp<SkImageFilter> positiveFilter(SkBlurImageFilter::Make(five, five, nullptr));
561 sk_sp<SkImageFilter> negativeFilter(SkBlurImageFilter::Make(-five, five, nullptr));
senorblanco32673b92014-09-09 09:15:04 -0700562
563 SkBitmap gradient = make_gradient_circle(width, height);
robertphillips3e302272016-04-20 11:48:36 -0700564 sk_sp<SkSpecialImage> imgSrc(SkSpecialImage::MakeFromRaster(SkIRect::MakeWH(width, height),
robertphillips37bd7c32016-03-17 14:31:39 -0700565 gradient));
robertphillips4418dba2016-03-07 12:45:14 -0800566
senorblanco32673b92014-09-09 09:15:04 -0700567 SkIPoint offset;
brianosman2a75e5d2016-09-22 07:15:37 -0700568 SkImageFilter::OutputProperties noColorSpace(nullptr);
569 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeWH(32, 32), nullptr, noColorSpace);
robertphillips4418dba2016-03-07 12:45:14 -0800570
robertphillips2302de92016-03-24 07:26:32 -0700571 sk_sp<SkSpecialImage> positiveResult1(positiveFilter->filterImage(imgSrc.get(), ctx, &offset));
robertphillips4418dba2016-03-07 12:45:14 -0800572 REPORTER_ASSERT(reporter, positiveResult1);
573
robertphillips2302de92016-03-24 07:26:32 -0700574 sk_sp<SkSpecialImage> negativeResult1(negativeFilter->filterImage(imgSrc.get(), ctx, &offset));
robertphillips4418dba2016-03-07 12:45:14 -0800575 REPORTER_ASSERT(reporter, negativeResult1);
576
senorblanco32673b92014-09-09 09:15:04 -0700577 SkMatrix negativeScale;
578 negativeScale.setScale(-SK_Scalar1, SK_Scalar1);
brianosman2a75e5d2016-09-22 07:15:37 -0700579 SkImageFilter::Context negativeCTX(negativeScale, SkIRect::MakeWH(32, 32), nullptr,
580 noColorSpace);
robertphillips4418dba2016-03-07 12:45:14 -0800581
robertphillips2302de92016-03-24 07:26:32 -0700582 sk_sp<SkSpecialImage> negativeResult2(positiveFilter->filterImage(imgSrc.get(),
583 negativeCTX,
584 &offset));
robertphillips4418dba2016-03-07 12:45:14 -0800585 REPORTER_ASSERT(reporter, negativeResult2);
586
robertphillips2302de92016-03-24 07:26:32 -0700587 sk_sp<SkSpecialImage> positiveResult2(negativeFilter->filterImage(imgSrc.get(),
588 negativeCTX,
589 &offset));
robertphillips4418dba2016-03-07 12:45:14 -0800590 REPORTER_ASSERT(reporter, positiveResult2);
591
592
593 SkBitmap positiveResultBM1, positiveResultBM2;
594 SkBitmap negativeResultBM1, negativeResultBM2;
595
robertphillips64612512016-04-08 12:10:42 -0700596 REPORTER_ASSERT(reporter, positiveResult1->getROPixels(&positiveResultBM1));
597 REPORTER_ASSERT(reporter, positiveResult2->getROPixels(&positiveResultBM2));
598 REPORTER_ASSERT(reporter, negativeResult1->getROPixels(&negativeResultBM1));
599 REPORTER_ASSERT(reporter, negativeResult2->getROPixels(&negativeResultBM2));
robertphillips4418dba2016-03-07 12:45:14 -0800600
senorblanco32673b92014-09-09 09:15:04 -0700601 for (int y = 0; y < height; y++) {
robertphillips4418dba2016-03-07 12:45:14 -0800602 int diffs = memcmp(positiveResultBM1.getAddr32(0, y),
603 negativeResultBM1.getAddr32(0, y),
604 positiveResultBM1.rowBytes());
senorblanco32673b92014-09-09 09:15:04 -0700605 REPORTER_ASSERT(reporter, !diffs);
606 if (diffs) {
607 break;
608 }
robertphillips4418dba2016-03-07 12:45:14 -0800609 diffs = memcmp(positiveResultBM1.getAddr32(0, y),
610 negativeResultBM2.getAddr32(0, y),
611 positiveResultBM1.rowBytes());
senorblanco32673b92014-09-09 09:15:04 -0700612 REPORTER_ASSERT(reporter, !diffs);
613 if (diffs) {
614 break;
615 }
robertphillips4418dba2016-03-07 12:45:14 -0800616 diffs = memcmp(positiveResultBM1.getAddr32(0, y),
617 positiveResultBM2.getAddr32(0, y),
618 positiveResultBM1.rowBytes());
senorblanco32673b92014-09-09 09:15:04 -0700619 REPORTER_ASSERT(reporter, !diffs);
620 if (diffs) {
621 break;
622 }
623 }
624}
625
senorblanco21a465d2016-04-11 11:58:39 -0700626DEF_TEST(ImageFilterNegativeBlurSigma, reporter) {
robertphillips3e302272016-04-20 11:48:36 -0700627 test_negative_blur_sigma(reporter, nullptr);
robertphillips4418dba2016-03-07 12:45:14 -0800628}
629
630#if SK_SUPPORT_GPU
bsalomon68d91342016-04-12 09:59:58 -0700631DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterNegativeBlurSigma_Gpu, reporter, ctxInfo) {
bsalomon8b7451a2016-05-11 06:33:06 -0700632 test_negative_blur_sigma(reporter, ctxInfo.grContext());
robertphillips4418dba2016-03-07 12:45:14 -0800633}
634#endif
635
robertphillips3e302272016-04-20 11:48:36 -0700636static void test_zero_blur_sigma(skiatest::Reporter* reporter, GrContext* context) {
senorblancobf680c32016-03-16 16:15:53 -0700637 // Check that SkBlurImageFilter with a zero sigma and a non-zero srcOffset works correctly.
638 SkImageFilter::CropRect cropRect(SkRect::Make(SkIRect::MakeXYWH(5, 0, 5, 10)));
robertphillips51a315e2016-03-31 09:05:49 -0700639 sk_sp<SkImageFilter> input(SkOffsetImageFilter::Make(0, 0, nullptr, &cropRect));
robertphillips6e7025a2016-04-04 04:31:25 -0700640 sk_sp<SkImageFilter> filter(SkBlurImageFilter::Make(0, 0, std::move(input), &cropRect));
senorblancobf680c32016-03-16 16:15:53 -0700641
robertphillips3e302272016-04-20 11:48:36 -0700642 sk_sp<SkSpecialSurface> surf(create_empty_special_surface(context, 10));
senorblancobf680c32016-03-16 16:15:53 -0700643 surf->getCanvas()->clear(SK_ColorGREEN);
robertphillips37bd7c32016-03-17 14:31:39 -0700644 sk_sp<SkSpecialImage> image(surf->makeImageSnapshot());
senorblancobf680c32016-03-16 16:15:53 -0700645
646 SkIPoint offset;
brianosman2a75e5d2016-09-22 07:15:37 -0700647 SkImageFilter::OutputProperties noColorSpace(nullptr);
648 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeWH(32, 32), nullptr, noColorSpace);
senorblancobf680c32016-03-16 16:15:53 -0700649
robertphillips2302de92016-03-24 07:26:32 -0700650 sk_sp<SkSpecialImage> result(filter->filterImage(image.get(), ctx, &offset));
senorblancobf680c32016-03-16 16:15:53 -0700651 REPORTER_ASSERT(reporter, offset.fX == 5 && offset.fY == 0);
652 REPORTER_ASSERT(reporter, result);
653 REPORTER_ASSERT(reporter, result->width() == 5 && result->height() == 10);
654
655 SkBitmap resultBM;
656
robertphillips64612512016-04-08 12:10:42 -0700657 REPORTER_ASSERT(reporter, result->getROPixels(&resultBM));
senorblancobf680c32016-03-16 16:15:53 -0700658
senorblancobf680c32016-03-16 16:15:53 -0700659 for (int y = 0; y < resultBM.height(); y++) {
660 for (int x = 0; x < resultBM.width(); x++) {
661 bool diff = *resultBM.getAddr32(x, y) != SK_ColorGREEN;
662 REPORTER_ASSERT(reporter, !diff);
663 if (diff) {
664 break;
665 }
666 }
667 }
668}
669
senorblanco21a465d2016-04-11 11:58:39 -0700670DEF_TEST(ImageFilterZeroBlurSigma, reporter) {
robertphillips3e302272016-04-20 11:48:36 -0700671 test_zero_blur_sigma(reporter, nullptr);
senorblancobf680c32016-03-16 16:15:53 -0700672}
673
674#if SK_SUPPORT_GPU
bsalomon68d91342016-04-12 09:59:58 -0700675DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterZeroBlurSigma_Gpu, reporter, ctxInfo) {
bsalomon8b7451a2016-05-11 06:33:06 -0700676 test_zero_blur_sigma(reporter, ctxInfo.grContext());
senorblancobf680c32016-03-16 16:15:53 -0700677}
678#endif
679
senorblanco6a93fa12016-04-05 04:43:45 -0700680
681// Tests that, even when an upstream filter has returned null (due to failure or clipping), a
682// downstream filter that affects transparent black still does so even with a nullptr input.
robertphillips3e302272016-04-20 11:48:36 -0700683static void test_fail_affects_transparent_black(skiatest::Reporter* reporter, GrContext* context) {
senorblanco6a93fa12016-04-05 04:43:45 -0700684 sk_sp<FailImageFilter> failFilter(new FailImageFilter());
robertphillips3e302272016-04-20 11:48:36 -0700685 sk_sp<SkSpecialImage> source(create_empty_special_image(context, 5));
brianosman2a75e5d2016-09-22 07:15:37 -0700686 SkImageFilter::OutputProperties noColorSpace(nullptr);
687 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeXYWH(0, 0, 1, 1), nullptr, noColorSpace);
Mike Reed7d954ad2016-10-28 15:42:34 -0400688 sk_sp<SkColorFilter> green(SkColorFilter::MakeModeFilter(SK_ColorGREEN, SkBlendMode::kSrc));
senorblanco6a93fa12016-04-05 04:43:45 -0700689 SkASSERT(green->affectsTransparentBlack());
robertphillips5605b562016-04-05 11:50:42 -0700690 sk_sp<SkImageFilter> greenFilter(SkColorFilterImageFilter::Make(std::move(green),
691 std::move(failFilter)));
senorblanco6a93fa12016-04-05 04:43:45 -0700692 SkIPoint offset;
693 sk_sp<SkSpecialImage> result(greenFilter->filterImage(source.get(), ctx, &offset));
694 REPORTER_ASSERT(reporter, nullptr != result.get());
695 if (result.get()) {
696 SkBitmap resultBM;
robertphillips64612512016-04-08 12:10:42 -0700697 REPORTER_ASSERT(reporter, result->getROPixels(&resultBM));
senorblanco6a93fa12016-04-05 04:43:45 -0700698 REPORTER_ASSERT(reporter, *resultBM.getAddr32(0, 0) == SK_ColorGREEN);
699 }
700}
701
702DEF_TEST(ImageFilterFailAffectsTransparentBlack, reporter) {
robertphillips3e302272016-04-20 11:48:36 -0700703 test_fail_affects_transparent_black(reporter, nullptr);
senorblanco6a93fa12016-04-05 04:43:45 -0700704}
705
706#if SK_SUPPORT_GPU
bsalomon68d91342016-04-12 09:59:58 -0700707DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterFailAffectsTransparentBlack_Gpu, reporter, ctxInfo) {
bsalomon8b7451a2016-05-11 06:33:06 -0700708 test_fail_affects_transparent_black(reporter, ctxInfo.grContext());
senorblanco6a93fa12016-04-05 04:43:45 -0700709}
710#endif
711
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +0000712DEF_TEST(ImageFilterDrawTiled, reporter) {
713 // Check that all filters when drawn tiled (with subsequent clip rects) exactly
714 // match the same filters drawn with a single full-canvas bitmap draw.
715 // Tests pass by not asserting.
716
robertphillipsfc11b0a2016-04-05 09:09:36 -0700717 FilterList filters(nullptr);
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +0000718
719 SkBitmap untiledResult, tiledResult;
reed5ea95df2015-10-06 14:05:32 -0700720 const int width = 64, height = 64;
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +0000721 untiledResult.allocN32Pixels(width, height);
722 tiledResult.allocN32Pixels(width, height);
723 SkCanvas tiledCanvas(tiledResult);
724 SkCanvas untiledCanvas(untiledResult);
senorblanco@chromium.orgd4db6572014-05-07 20:00:04 +0000725 int tileSize = 8;
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +0000726
senorblanco@chromium.orgd4db6572014-05-07 20:00:04 +0000727 for (int scale = 1; scale <= 2; ++scale) {
senorblanco297f7ce2016-03-23 13:44:26 -0700728 for (int i = 0; i < filters.count(); ++i) {
senorblanco@chromium.orgd4db6572014-05-07 20:00:04 +0000729 tiledCanvas.clear(0);
730 untiledCanvas.clear(0);
731 SkPaint paint;
Mike Reed5e257172016-11-01 11:22:05 -0400732 paint.setImageFilter(sk_ref_sp(filters.getFilter(i)));
senorblanco@chromium.orgd4db6572014-05-07 20:00:04 +0000733 paint.setTextSize(SkIntToScalar(height));
734 paint.setColor(SK_ColorWHITE);
735 SkString str;
736 const char* text = "ABC";
737 SkScalar ypos = SkIntToScalar(height);
738 untiledCanvas.save();
739 untiledCanvas.scale(SkIntToScalar(scale), SkIntToScalar(scale));
Cary Clark2a475ea2017-04-28 15:35:12 -0400740 untiledCanvas.drawString(text, 0, ypos, paint);
senorblanco@chromium.orgd4db6572014-05-07 20:00:04 +0000741 untiledCanvas.restore();
742 for (int y = 0; y < height; y += tileSize) {
743 for (int x = 0; x < width; x += tileSize) {
744 tiledCanvas.save();
745 tiledCanvas.clipRect(SkRect::Make(SkIRect::MakeXYWH(x, y, tileSize, tileSize)));
746 tiledCanvas.scale(SkIntToScalar(scale), SkIntToScalar(scale));
Cary Clark2a475ea2017-04-28 15:35:12 -0400747 tiledCanvas.drawString(text, 0, ypos, paint);
senorblanco@chromium.orgd4db6572014-05-07 20:00:04 +0000748 tiledCanvas.restore();
749 }
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +0000750 }
senorblanco@chromium.orgd4db6572014-05-07 20:00:04 +0000751 untiledCanvas.flush();
752 tiledCanvas.flush();
Mike Reed34042072017-08-08 16:29:22 -0400753 if (!sk_tool_utils::equal_pixels(untiledResult, tiledResult, 1)) {
Mike Reed5a625e02017-08-08 15:48:54 -0400754 REPORTER_ASSERT_MESSAGE(reporter, false, filters.getName(i));
755 break;
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +0000756 }
757 }
758 }
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +0000759}
760
mtklein3f3b3d02014-12-01 11:47:08 -0800761static void draw_saveLayer_picture(int width, int height, int tileSize,
robertphillipsa8d7f0b2014-08-29 08:03:56 -0700762 SkBBHFactory* factory, SkBitmap* result) {
mtkleind910f542014-08-22 09:06:34 -0700763
764 SkMatrix matrix;
765 matrix.setTranslate(SkIntToScalar(50), 0);
766
Mike Reed7d954ad2016-10-28 15:42:34 -0400767 sk_sp<SkColorFilter> cf(SkColorFilter::MakeModeFilter(SK_ColorWHITE, SkBlendMode::kSrc));
robertphillips5605b562016-04-05 11:50:42 -0700768 sk_sp<SkImageFilter> cfif(SkColorFilterImageFilter::Make(std::move(cf), nullptr));
robertphillipsae8c9332016-04-05 15:09:00 -0700769 sk_sp<SkImageFilter> imageFilter(SkImageFilter::MakeMatrixFilter(matrix,
770 kNone_SkFilterQuality,
771 std::move(cfif)));
mtkleind910f542014-08-22 09:06:34 -0700772
773 SkPaint paint;
robertphillips5605b562016-04-05 11:50:42 -0700774 paint.setImageFilter(std::move(imageFilter));
mtkleind910f542014-08-22 09:06:34 -0700775 SkPictureRecorder recorder;
776 SkRect bounds = SkRect::Make(SkIRect::MakeXYWH(0, 0, 50, 50));
mtklein3f3b3d02014-12-01 11:47:08 -0800777 SkCanvas* recordingCanvas = recorder.beginRecording(SkIntToScalar(width),
778 SkIntToScalar(height),
robertphillipsa8d7f0b2014-08-29 08:03:56 -0700779 factory, 0);
mtkleind910f542014-08-22 09:06:34 -0700780 recordingCanvas->translate(-55, 0);
781 recordingCanvas->saveLayer(&bounds, &paint);
782 recordingCanvas->restore();
reedca2622b2016-03-18 07:25:55 -0700783 sk_sp<SkPicture> picture1(recorder.finishRecordingAsPicture());
mtkleind910f542014-08-22 09:06:34 -0700784
785 result->allocN32Pixels(width, height);
786 SkCanvas canvas(*result);
787 canvas.clear(0);
788 canvas.clipRect(SkRect::Make(SkIRect::MakeWH(tileSize, tileSize)));
789 canvas.drawPicture(picture1.get());
790}
791
792DEF_TEST(ImageFilterDrawMatrixBBH, reporter) {
793 // Check that matrix filter when drawn tiled with BBH exactly
794 // matches the same thing drawn without BBH.
795 // Tests pass by not asserting.
796
797 const int width = 200, height = 200;
798 const int tileSize = 100;
799 SkBitmap result1, result2;
800 SkRTreeFactory factory;
801
robertphillipsa8d7f0b2014-08-29 08:03:56 -0700802 draw_saveLayer_picture(width, height, tileSize, &factory, &result1);
halcanary96fcdcc2015-08-27 07:41:13 -0700803 draw_saveLayer_picture(width, height, tileSize, nullptr, &result2);
mtkleind910f542014-08-22 09:06:34 -0700804
805 for (int y = 0; y < height; y++) {
806 int diffs = memcmp(result1.getAddr32(0, y), result2.getAddr32(0, y), result1.rowBytes());
807 REPORTER_ASSERT(reporter, !diffs);
808 if (diffs) {
809 break;
810 }
811 }
812}
813
robertphillips6e7025a2016-04-04 04:31:25 -0700814static sk_sp<SkImageFilter> make_blur(sk_sp<SkImageFilter> input) {
815 return SkBlurImageFilter::Make(SK_Scalar1, SK_Scalar1, std::move(input));
senorblanco1150a6d2014-08-25 12:46:58 -0700816}
817
robertphillips6e7025a2016-04-04 04:31:25 -0700818static sk_sp<SkImageFilter> make_drop_shadow(sk_sp<SkImageFilter> input) {
robertphillipsc4169122016-04-06 08:40:59 -0700819 return SkDropShadowImageFilter::Make(
senorblanco1150a6d2014-08-25 12:46:58 -0700820 SkIntToScalar(100), SkIntToScalar(100),
821 SkIntToScalar(10), SkIntToScalar(10),
sugoi234f0362014-10-23 13:59:52 -0700822 SK_ColorBLUE, SkDropShadowImageFilter::kDrawShadowAndForeground_ShadowMode,
robertphillipsc4169122016-04-06 08:40:59 -0700823 std::move(input));
senorblanco1150a6d2014-08-25 12:46:58 -0700824}
825
826DEF_TEST(ImageFilterBlurThenShadowBounds, reporter) {
robertphillips6e7025a2016-04-04 04:31:25 -0700827 sk_sp<SkImageFilter> filter1(make_blur(nullptr));
828 sk_sp<SkImageFilter> filter2(make_drop_shadow(std::move(filter1)));
senorblanco1150a6d2014-08-25 12:46:58 -0700829
830 SkIRect bounds = SkIRect::MakeXYWH(0, 0, 100, 100);
831 SkIRect expectedBounds = SkIRect::MakeXYWH(-133, -133, 236, 236);
senorblancoe5e79842016-03-21 14:51:59 -0700832 bounds = filter2->filterBounds(bounds, SkMatrix::I());
senorblanco1150a6d2014-08-25 12:46:58 -0700833
834 REPORTER_ASSERT(reporter, bounds == expectedBounds);
835}
836
837DEF_TEST(ImageFilterShadowThenBlurBounds, reporter) {
robertphillips6e7025a2016-04-04 04:31:25 -0700838 sk_sp<SkImageFilter> filter1(make_drop_shadow(nullptr));
839 sk_sp<SkImageFilter> filter2(make_blur(std::move(filter1)));
senorblanco1150a6d2014-08-25 12:46:58 -0700840
841 SkIRect bounds = SkIRect::MakeXYWH(0, 0, 100, 100);
842 SkIRect expectedBounds = SkIRect::MakeXYWH(-133, -133, 236, 236);
senorblancoe5e79842016-03-21 14:51:59 -0700843 bounds = filter2->filterBounds(bounds, SkMatrix::I());
senorblanco1150a6d2014-08-25 12:46:58 -0700844
845 REPORTER_ASSERT(reporter, bounds == expectedBounds);
846}
847
848DEF_TEST(ImageFilterDilateThenBlurBounds, reporter) {
robertphillipsfc11b0a2016-04-05 09:09:36 -0700849 sk_sp<SkImageFilter> filter1(SkDilateImageFilter::Make(2, 2, nullptr));
robertphillips6e7025a2016-04-04 04:31:25 -0700850 sk_sp<SkImageFilter> filter2(make_drop_shadow(std::move(filter1)));
senorblanco1150a6d2014-08-25 12:46:58 -0700851
852 SkIRect bounds = SkIRect::MakeXYWH(0, 0, 100, 100);
853 SkIRect expectedBounds = SkIRect::MakeXYWH(-132, -132, 234, 234);
senorblancoe5e79842016-03-21 14:51:59 -0700854 bounds = filter2->filterBounds(bounds, SkMatrix::I());
senorblanco1150a6d2014-08-25 12:46:58 -0700855
856 REPORTER_ASSERT(reporter, bounds == expectedBounds);
857}
858
jbroman203a9932016-07-11 14:07:59 -0700859DEF_TEST(ImageFilterScaledBlurRadius, reporter) {
860 // Each blur should spread 3*sigma, so 3 for the blur and 30 for the shadow
861 // (before the CTM). Bounds should be computed correctly in the presence of
862 // a (possibly negative) scale.
863 sk_sp<SkImageFilter> blur(make_blur(nullptr));
864 sk_sp<SkImageFilter> dropShadow(make_drop_shadow(nullptr));
865 {
866 // Uniform scale by 2.
867 SkMatrix scaleMatrix;
868 scaleMatrix.setScale(2, 2);
869 SkIRect bounds = SkIRect::MakeLTRB(0, 0, 200, 200);
870
871 SkIRect expectedBlurBounds = SkIRect::MakeLTRB(-6, -6, 206, 206);
872 SkIRect blurBounds = blur->filterBounds(
873 bounds, scaleMatrix, SkImageFilter::kForward_MapDirection);
874 REPORTER_ASSERT(reporter, blurBounds == expectedBlurBounds);
875 SkIRect reverseBlurBounds = blur->filterBounds(
876 bounds, scaleMatrix, SkImageFilter::kReverse_MapDirection);
877 REPORTER_ASSERT(reporter, reverseBlurBounds == expectedBlurBounds);
878
879 SkIRect expectedShadowBounds = SkIRect::MakeLTRB(0, 0, 460, 460);
880 SkIRect shadowBounds = dropShadow->filterBounds(
881 bounds, scaleMatrix, SkImageFilter::kForward_MapDirection);
882 REPORTER_ASSERT(reporter, shadowBounds == expectedShadowBounds);
883 SkIRect expectedReverseShadowBounds =
884 SkIRect::MakeLTRB(-260, -260, 200, 200);
885 SkIRect reverseShadowBounds = dropShadow->filterBounds(
886 bounds, scaleMatrix, SkImageFilter::kReverse_MapDirection);
887 REPORTER_ASSERT(reporter,
888 reverseShadowBounds == expectedReverseShadowBounds);
889 }
890 {
891 // Vertical flip.
892 SkMatrix scaleMatrix;
893 scaleMatrix.setScale(1, -1);
894 SkIRect bounds = SkIRect::MakeLTRB(0, -100, 100, 0);
895
896 SkIRect expectedBlurBounds = SkIRect::MakeLTRB(-3, -103, 103, 3);
897 SkIRect blurBounds = blur->filterBounds(
898 bounds, scaleMatrix, SkImageFilter::kForward_MapDirection);
899 REPORTER_ASSERT(reporter, blurBounds == expectedBlurBounds);
900 SkIRect reverseBlurBounds = blur->filterBounds(
901 bounds, scaleMatrix, SkImageFilter::kReverse_MapDirection);
902 REPORTER_ASSERT(reporter, reverseBlurBounds == expectedBlurBounds);
903
904 SkIRect expectedShadowBounds = SkIRect::MakeLTRB(0, -230, 230, 0);
905 SkIRect shadowBounds = dropShadow->filterBounds(
906 bounds, scaleMatrix, SkImageFilter::kForward_MapDirection);
907 REPORTER_ASSERT(reporter, shadowBounds == expectedShadowBounds);
908 SkIRect expectedReverseShadowBounds =
909 SkIRect::MakeLTRB(-130, -100, 100, 130);
910 SkIRect reverseShadowBounds = dropShadow->filterBounds(
911 bounds, scaleMatrix, SkImageFilter::kReverse_MapDirection);
912 REPORTER_ASSERT(reporter,
913 reverseShadowBounds == expectedReverseShadowBounds);
914 }
915}
916
ajuma5788faa2015-02-13 09:05:47 -0800917DEF_TEST(ImageFilterComposedBlurFastBounds, reporter) {
robertphillips6e7025a2016-04-04 04:31:25 -0700918 sk_sp<SkImageFilter> filter1(make_blur(nullptr));
919 sk_sp<SkImageFilter> filter2(make_blur(nullptr));
robertphillips491fb172016-03-30 12:32:58 -0700920 sk_sp<SkImageFilter> composedFilter(SkComposeImageFilter::Make(std::move(filter1),
921 std::move(filter2)));
ajuma5788faa2015-02-13 09:05:47 -0800922
923 SkRect boundsSrc = SkRect::MakeWH(SkIntToScalar(100), SkIntToScalar(100));
924 SkRect expectedBounds = SkRect::MakeXYWH(
925 SkIntToScalar(-6), SkIntToScalar(-6), SkIntToScalar(112), SkIntToScalar(112));
senorblancoe5e79842016-03-21 14:51:59 -0700926 SkRect boundsDst = composedFilter->computeFastBounds(boundsSrc);
ajuma5788faa2015-02-13 09:05:47 -0800927
928 REPORTER_ASSERT(reporter, boundsDst == expectedBounds);
929}
930
jbroman0e3129d2016-03-17 12:24:23 -0700931DEF_TEST(ImageFilterUnionBounds, reporter) {
robertphillips51a315e2016-03-31 09:05:49 -0700932 sk_sp<SkImageFilter> offset(SkOffsetImageFilter::Make(50, 0, nullptr));
jbroman0e3129d2016-03-17 12:24:23 -0700933 // Regardless of which order they appear in, the image filter bounds should
934 // be combined correctly.
935 {
reed374772b2016-10-05 17:33:02 -0700936 sk_sp<SkImageFilter> composite(SkXfermodeImageFilter::Make(SkBlendMode::kSrcOver, offset));
jbroman0e3129d2016-03-17 12:24:23 -0700937 SkRect bounds = SkRect::MakeWH(100, 100);
938 // Intentionally aliasing here, as that's what the real callers do.
senorblancoe5e79842016-03-21 14:51:59 -0700939 bounds = composite->computeFastBounds(bounds);
jbroman0e3129d2016-03-17 12:24:23 -0700940 REPORTER_ASSERT(reporter, bounds == SkRect::MakeWH(150, 100));
941 }
942 {
reed374772b2016-10-05 17:33:02 -0700943 sk_sp<SkImageFilter> composite(SkXfermodeImageFilter::Make(SkBlendMode::kSrcOver, nullptr,
robertphillips8c0326d2016-04-05 12:48:34 -0700944 offset, nullptr));
jbroman0e3129d2016-03-17 12:24:23 -0700945 SkRect bounds = SkRect::MakeWH(100, 100);
946 // Intentionally aliasing here, as that's what the real callers do.
senorblancoe5e79842016-03-21 14:51:59 -0700947 bounds = composite->computeFastBounds(bounds);
jbroman0e3129d2016-03-17 12:24:23 -0700948 REPORTER_ASSERT(reporter, bounds == SkRect::MakeWH(150, 100));
949 }
950}
951
robertphillips3e302272016-04-20 11:48:36 -0700952static void test_imagefilter_merge_result_size(skiatest::Reporter* reporter, GrContext* context) {
senorblanco4a243982015-11-25 07:06:55 -0800953 SkBitmap greenBM;
954 greenBM.allocN32Pixels(20, 20);
955 greenBM.eraseColor(SK_ColorGREEN);
reed9ce9d672016-03-17 10:51:11 -0700956 sk_sp<SkImage> greenImage(SkImage::MakeFromBitmap(greenBM));
robertphillips549c8992016-04-01 09:28:51 -0700957 sk_sp<SkImageFilter> source(SkImageSource::Make(std::move(greenImage)));
Mike Reed0bdaf052017-06-18 23:35:57 -0400958 sk_sp<SkImageFilter> merge(SkMergeImageFilter::Make(source, source));
senorblanco4a243982015-11-25 07:06:55 -0800959
robertphillips3e302272016-04-20 11:48:36 -0700960 sk_sp<SkSpecialImage> srcImg(create_empty_special_image(context, 1));
robertphillips4418dba2016-03-07 12:45:14 -0800961
brianosman2a75e5d2016-09-22 07:15:37 -0700962 SkImageFilter::OutputProperties noColorSpace(nullptr);
963 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeXYWH(0, 0, 100, 100), nullptr,
964 noColorSpace);
senorblanco4a243982015-11-25 07:06:55 -0800965 SkIPoint offset;
robertphillips4418dba2016-03-07 12:45:14 -0800966
robertphillips2302de92016-03-24 07:26:32 -0700967 sk_sp<SkSpecialImage> resultImg(merge->filterImage(srcImg.get(), ctx, &offset));
robertphillips4418dba2016-03-07 12:45:14 -0800968 REPORTER_ASSERT(reporter, resultImg);
969
970 REPORTER_ASSERT(reporter, resultImg->width() == 20 && resultImg->height() == 20);
senorblanco4a243982015-11-25 07:06:55 -0800971}
972
robertphillips4418dba2016-03-07 12:45:14 -0800973DEF_TEST(ImageFilterMergeResultSize, reporter) {
robertphillips3e302272016-04-20 11:48:36 -0700974 test_imagefilter_merge_result_size(reporter, nullptr);
robertphillips4418dba2016-03-07 12:45:14 -0800975}
976
977#if SK_SUPPORT_GPU
egdanielab527a52016-06-28 08:07:26 -0700978DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterMergeResultSize_Gpu, reporter, ctxInfo) {
bsalomon8b7451a2016-05-11 06:33:06 -0700979 test_imagefilter_merge_result_size(reporter, ctxInfo.grContext());
robertphillips4418dba2016-03-07 12:45:14 -0800980}
981#endif
982
robertphillipsa8d7f0b2014-08-29 08:03:56 -0700983static void draw_blurred_rect(SkCanvas* canvas) {
senorblanco837f5322014-07-14 10:19:54 -0700984 SkPaint filterPaint;
985 filterPaint.setColor(SK_ColorWHITE);
robertphillips6e7025a2016-04-04 04:31:25 -0700986 filterPaint.setImageFilter(SkBlurImageFilter::Make(SkIntToScalar(8), 0, nullptr));
halcanary96fcdcc2015-08-27 07:41:13 -0700987 canvas->saveLayer(nullptr, &filterPaint);
senorblanco837f5322014-07-14 10:19:54 -0700988 SkPaint whitePaint;
989 whitePaint.setColor(SK_ColorWHITE);
990 canvas->drawRect(SkRect::Make(SkIRect::MakeWH(4, 4)), whitePaint);
991 canvas->restore();
992}
993
robertphillipsa8d7f0b2014-08-29 08:03:56 -0700994static void draw_picture_clipped(SkCanvas* canvas, const SkRect& clipRect, const SkPicture* picture) {
senorblanco837f5322014-07-14 10:19:54 -0700995 canvas->save();
996 canvas->clipRect(clipRect);
997 canvas->drawPicture(picture);
998 canvas->restore();
999}
1000
1001DEF_TEST(ImageFilterDrawTiledBlurRTree, reporter) {
1002 // Check that the blur filter when recorded with RTree acceleration,
1003 // and drawn tiled (with subsequent clip rects) exactly
1004 // matches the same filter drawn with without RTree acceleration.
1005 // This tests that the "bleed" from the blur into the otherwise-blank
1006 // tiles is correctly rendered.
1007 // Tests pass by not asserting.
1008
1009 int width = 16, height = 8;
1010 SkBitmap result1, result2;
1011 result1.allocN32Pixels(width, height);
1012 result2.allocN32Pixels(width, height);
1013 SkCanvas canvas1(result1);
1014 SkCanvas canvas2(result2);
1015 int tileSize = 8;
1016
1017 canvas1.clear(0);
1018 canvas2.clear(0);
1019
1020 SkRTreeFactory factory;
1021
1022 SkPictureRecorder recorder1, recorder2;
1023 // The only difference between these two pictures is that one has RTree aceleration.
mtklein3f3b3d02014-12-01 11:47:08 -08001024 SkCanvas* recordingCanvas1 = recorder1.beginRecording(SkIntToScalar(width),
1025 SkIntToScalar(height),
halcanary96fcdcc2015-08-27 07:41:13 -07001026 nullptr, 0);
mtklein3f3b3d02014-12-01 11:47:08 -08001027 SkCanvas* recordingCanvas2 = recorder2.beginRecording(SkIntToScalar(width),
1028 SkIntToScalar(height),
robertphillipsa8d7f0b2014-08-29 08:03:56 -07001029 &factory, 0);
1030 draw_blurred_rect(recordingCanvas1);
1031 draw_blurred_rect(recordingCanvas2);
reedca2622b2016-03-18 07:25:55 -07001032 sk_sp<SkPicture> picture1(recorder1.finishRecordingAsPicture());
1033 sk_sp<SkPicture> picture2(recorder2.finishRecordingAsPicture());
senorblanco837f5322014-07-14 10:19:54 -07001034 for (int y = 0; y < height; y += tileSize) {
1035 for (int x = 0; x < width; x += tileSize) {
1036 SkRect tileRect = SkRect::Make(SkIRect::MakeXYWH(x, y, tileSize, tileSize));
reedca2622b2016-03-18 07:25:55 -07001037 draw_picture_clipped(&canvas1, tileRect, picture1.get());
1038 draw_picture_clipped(&canvas2, tileRect, picture2.get());
senorblanco837f5322014-07-14 10:19:54 -07001039 }
1040 }
1041 for (int y = 0; y < height; y++) {
1042 int diffs = memcmp(result1.getAddr32(0, y), result2.getAddr32(0, y), result1.rowBytes());
1043 REPORTER_ASSERT(reporter, !diffs);
1044 if (diffs) {
1045 break;
1046 }
1047 }
1048}
1049
senorblanco@chromium.org91957432014-05-01 14:03:41 +00001050DEF_TEST(ImageFilterMatrixConvolution, reporter) {
1051 // Check that a 1x3 filter does not cause a spurious assert.
1052 SkScalar kernel[3] = {
1053 SkIntToScalar( 1), SkIntToScalar( 1), SkIntToScalar( 1),
1054 };
1055 SkISize kernelSize = SkISize::Make(1, 3);
1056 SkScalar gain = SK_Scalar1, bias = 0;
1057 SkIPoint kernelOffset = SkIPoint::Make(0, 0);
1058
robertphillipsef6a47b2016-04-08 08:01:20 -07001059 sk_sp<SkImageFilter> filter(SkMatrixConvolutionImageFilter::Make(
1060 kernelSize, kernel,
1061 gain, bias, kernelOffset,
1062 SkMatrixConvolutionImageFilter::kRepeat_TileMode,
1063 false, nullptr));
senorblanco@chromium.org91957432014-05-01 14:03:41 +00001064
1065 SkBitmap result;
1066 int width = 16, height = 16;
1067 result.allocN32Pixels(width, height);
1068 SkCanvas canvas(result);
1069 canvas.clear(0);
1070
1071 SkPaint paint;
robertphillipsef6a47b2016-04-08 08:01:20 -07001072 paint.setImageFilter(std::move(filter));
senorblanco@chromium.org91957432014-05-01 14:03:41 +00001073 SkRect rect = SkRect::Make(SkIRect::MakeWH(width, height));
1074 canvas.drawRect(rect, paint);
1075}
1076
senorblanco@chromium.org8c7372b2014-05-02 19:13:11 +00001077DEF_TEST(ImageFilterMatrixConvolutionBorder, reporter) {
1078 // Check that a filter with borders outside the target bounds
1079 // does not crash.
1080 SkScalar kernel[3] = {
1081 0, 0, 0,
1082 };
1083 SkISize kernelSize = SkISize::Make(3, 1);
1084 SkScalar gain = SK_Scalar1, bias = 0;
1085 SkIPoint kernelOffset = SkIPoint::Make(2, 0);
1086
robertphillipsef6a47b2016-04-08 08:01:20 -07001087 sk_sp<SkImageFilter> filter(SkMatrixConvolutionImageFilter::Make(
1088 kernelSize, kernel, gain, bias, kernelOffset,
1089 SkMatrixConvolutionImageFilter::kClamp_TileMode,
1090 true, nullptr));
senorblanco@chromium.org8c7372b2014-05-02 19:13:11 +00001091
1092 SkBitmap result;
1093
1094 int width = 10, height = 10;
1095 result.allocN32Pixels(width, height);
1096 SkCanvas canvas(result);
1097 canvas.clear(0);
1098
1099 SkPaint filterPaint;
robertphillipsef6a47b2016-04-08 08:01:20 -07001100 filterPaint.setImageFilter(std::move(filter));
senorblanco@chromium.org8c7372b2014-05-02 19:13:11 +00001101 SkRect bounds = SkRect::MakeWH(1, 10);
1102 SkRect rect = SkRect::Make(SkIRect::MakeWH(width, height));
1103 SkPaint rectPaint;
1104 canvas.saveLayer(&bounds, &filterPaint);
1105 canvas.drawRect(rect, rectPaint);
1106 canvas.restore();
1107}
1108
robertphillips3e302272016-04-20 11:48:36 -07001109static void test_big_kernel(skiatest::Reporter* reporter, GrContext* context) {
robertphillipsdada4dd2016-04-13 04:54:36 -07001110 // Check that a kernel that is too big for the GPU still works
1111 SkScalar identityKernel[49] = {
1112 0, 0, 0, 0, 0, 0, 0,
1113 0, 0, 0, 0, 0, 0, 0,
1114 0, 0, 0, 0, 0, 0, 0,
1115 0, 0, 0, 1, 0, 0, 0,
1116 0, 0, 0, 0, 0, 0, 0,
1117 0, 0, 0, 0, 0, 0, 0,
1118 0, 0, 0, 0, 0, 0, 0
1119 };
1120 SkISize kernelSize = SkISize::Make(7, 7);
1121 SkScalar gain = SK_Scalar1, bias = 0;
1122 SkIPoint kernelOffset = SkIPoint::Make(0, 0);
1123
1124 sk_sp<SkImageFilter> filter(SkMatrixConvolutionImageFilter::Make(
1125 kernelSize, identityKernel, gain, bias, kernelOffset,
1126 SkMatrixConvolutionImageFilter::kClamp_TileMode,
1127 true, nullptr));
1128
robertphillips3e302272016-04-20 11:48:36 -07001129 sk_sp<SkSpecialImage> srcImg(create_empty_special_image(context, 100));
robertphillipsdada4dd2016-04-13 04:54:36 -07001130 SkASSERT(srcImg);
1131
1132 SkIPoint offset;
brianosman2a75e5d2016-09-22 07:15:37 -07001133 SkImageFilter::OutputProperties noColorSpace(nullptr);
1134 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeWH(100, 100), nullptr, noColorSpace);
robertphillipsdada4dd2016-04-13 04:54:36 -07001135 sk_sp<SkSpecialImage> resultImg(filter->filterImage(srcImg.get(), ctx, &offset));
1136 REPORTER_ASSERT(reporter, resultImg);
1137 REPORTER_ASSERT(reporter, SkToBool(context) == resultImg->isTextureBacked());
1138 REPORTER_ASSERT(reporter, resultImg->width() == 100 && resultImg->height() == 100);
1139 REPORTER_ASSERT(reporter, offset.fX == 0 && offset.fY == 0);
1140}
1141
1142DEF_TEST(ImageFilterMatrixConvolutionBigKernel, reporter) {
robertphillips3e302272016-04-20 11:48:36 -07001143 test_big_kernel(reporter, nullptr);
robertphillipsdada4dd2016-04-13 04:54:36 -07001144}
1145
1146#if SK_SUPPORT_GPU
egdanielab527a52016-06-28 08:07:26 -07001147DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterMatrixConvolutionBigKernel_Gpu,
1148 reporter, ctxInfo) {
bsalomon8b7451a2016-05-11 06:33:06 -07001149 test_big_kernel(reporter, ctxInfo.grContext());
robertphillipsdada4dd2016-04-13 04:54:36 -07001150}
1151#endif
1152
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +00001153DEF_TEST(ImageFilterCropRect, reporter) {
robertphillips3e302272016-04-20 11:48:36 -07001154 test_crop_rects(reporter, nullptr);
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +00001155}
1156
robertphillips4418dba2016-03-07 12:45:14 -08001157#if SK_SUPPORT_GPU
bsalomon68d91342016-04-12 09:59:58 -07001158DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterCropRect_Gpu, reporter, ctxInfo) {
bsalomon8b7451a2016-05-11 06:33:06 -07001159 test_crop_rects(reporter, ctxInfo.grContext());
robertphillips4418dba2016-03-07 12:45:14 -08001160}
1161#endif
1162
tfarina9ea53f92014-06-24 06:50:39 -07001163DEF_TEST(ImageFilterMatrix, reporter) {
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +00001164 SkBitmap temp;
mike@reedtribe.orgdeee4962014-02-13 14:41:43 +00001165 temp.allocN32Pixels(100, 100);
robertphillips9a53fd72015-06-22 09:46:59 -07001166 SkCanvas canvas(temp);
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +00001167 canvas.scale(SkIntToScalar(2), SkIntToScalar(2));
1168
1169 SkMatrix expectedMatrix = canvas.getTotalMatrix();
1170
commit-bot@chromium.org5fb2ce32014-04-17 23:35:06 +00001171 SkRTreeFactory factory;
1172 SkPictureRecorder recorder;
1173 SkCanvas* recordingCanvas = recorder.beginRecording(100, 100, &factory, 0);
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +00001174
1175 SkPaint paint;
robertphillips43c2ad42016-04-04 05:05:11 -07001176 paint.setImageFilter(MatrixTestImageFilter::Make(reporter, expectedMatrix));
halcanary96fcdcc2015-08-27 07:41:13 -07001177 recordingCanvas->saveLayer(nullptr, &paint);
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +00001178 SkPaint solidPaint;
1179 solidPaint.setColor(0xFFFFFFFF);
1180 recordingCanvas->save();
1181 recordingCanvas->scale(SkIntToScalar(10), SkIntToScalar(10));
1182 recordingCanvas->drawRect(SkRect::Make(SkIRect::MakeWH(100, 100)), solidPaint);
1183 recordingCanvas->restore(); // scale
1184 recordingCanvas->restore(); // saveLayer
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +00001185
reedca2622b2016-03-18 07:25:55 -07001186 canvas.drawPicture(recorder.finishRecordingAsPicture());
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +00001187}
1188
senorblanco3d822c22014-07-30 14:49:31 -07001189DEF_TEST(ImageFilterCrossProcessPictureImageFilter, reporter) {
senorblanco@chromium.org97f5fc62014-05-30 20:50:56 +00001190 SkRTreeFactory factory;
1191 SkPictureRecorder recorder;
1192 SkCanvas* recordingCanvas = recorder.beginRecording(1, 1, &factory, 0);
1193
1194 // Create an SkPicture which simply draws a green 1x1 rectangle.
1195 SkPaint greenPaint;
1196 greenPaint.setColor(SK_ColorGREEN);
1197 recordingCanvas->drawRect(SkRect::Make(SkIRect::MakeWH(1, 1)), greenPaint);
reedca2622b2016-03-18 07:25:55 -07001198 sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture());
senorblanco@chromium.org97f5fc62014-05-30 20:50:56 +00001199
1200 // Wrap that SkPicture in an SkPictureImageFilter.
robertphillips5ff17b12016-03-28 13:13:42 -07001201 sk_sp<SkImageFilter> imageFilter(SkPictureImageFilter::Make(picture));
senorblanco@chromium.org97f5fc62014-05-30 20:50:56 +00001202
1203 // Check that SkPictureImageFilter successfully serializes its contained
1204 // SkPicture when not in cross-process mode.
1205 SkPaint paint;
robertphillips5ff17b12016-03-28 13:13:42 -07001206 paint.setImageFilter(imageFilter);
senorblanco@chromium.org97f5fc62014-05-30 20:50:56 +00001207 SkPictureRecorder outerRecorder;
1208 SkCanvas* outerCanvas = outerRecorder.beginRecording(1, 1, &factory, 0);
1209 SkPaint redPaintWithFilter;
1210 redPaintWithFilter.setColor(SK_ColorRED);
robertphillips5ff17b12016-03-28 13:13:42 -07001211 redPaintWithFilter.setImageFilter(imageFilter);
senorblanco@chromium.org97f5fc62014-05-30 20:50:56 +00001212 outerCanvas->drawRect(SkRect::Make(SkIRect::MakeWH(1, 1)), redPaintWithFilter);
reedca2622b2016-03-18 07:25:55 -07001213 sk_sp<SkPicture> outerPicture(outerRecorder.finishRecordingAsPicture());
senorblanco@chromium.org97f5fc62014-05-30 20:50:56 +00001214
1215 SkBitmap bitmap;
1216 bitmap.allocN32Pixels(1, 1);
robertphillips9a53fd72015-06-22 09:46:59 -07001217 SkCanvas canvas(bitmap);
senorblanco@chromium.org97f5fc62014-05-30 20:50:56 +00001218
1219 // The result here should be green, since the filter replaces the primitive's red interior.
1220 canvas.clear(0x0);
robertphillips9b14f262014-06-04 05:40:44 -07001221 canvas.drawPicture(outerPicture);
senorblanco@chromium.org97f5fc62014-05-30 20:50:56 +00001222 uint32_t pixel = *bitmap.getAddr32(0, 0);
1223 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1224
1225 // Check that, for now, SkPictureImageFilter does not serialize or
1226 // deserialize its contained picture when the filter is serialized
1227 // cross-process. Do this by "laundering" it through SkValidatingReadBuffer.
robertphillips12fa47d2016-04-08 16:28:09 -07001228 sk_sp<SkData> data(SkValidatingSerializeFlattenable(imageFilter.get()));
Mike Reed5e257172016-11-01 11:22:05 -04001229 sk_sp<SkImageFilter> unflattenedFilter = SkValidatingDeserializeImageFilter(data->data(),
1230 data->size());
senorblanco@chromium.org97f5fc62014-05-30 20:50:56 +00001231
1232 redPaintWithFilter.setImageFilter(unflattenedFilter);
1233 SkPictureRecorder crossProcessRecorder;
1234 SkCanvas* crossProcessCanvas = crossProcessRecorder.beginRecording(1, 1, &factory, 0);
1235 crossProcessCanvas->drawRect(SkRect::Make(SkIRect::MakeWH(1, 1)), redPaintWithFilter);
reedca2622b2016-03-18 07:25:55 -07001236 sk_sp<SkPicture> crossProcessPicture(crossProcessRecorder.finishRecordingAsPicture());
senorblanco@chromium.org97f5fc62014-05-30 20:50:56 +00001237
1238 canvas.clear(0x0);
robertphillips9b14f262014-06-04 05:40:44 -07001239 canvas.drawPicture(crossProcessPicture);
senorblanco@chromium.org97f5fc62014-05-30 20:50:56 +00001240 pixel = *bitmap.getAddr32(0, 0);
hendrikw446ee672015-06-16 09:28:37 -07001241 // If the security precautions are enabled, the result here should not be green, since the
1242 // filter draws nothing.
mtklein2afbe232016-02-07 12:23:10 -08001243 REPORTER_ASSERT(reporter, SkPicture::PictureIOSecurityPrecautionsEnabled()
hendrikw446ee672015-06-16 09:28:37 -07001244 ? pixel != SK_ColorGREEN : pixel == SK_ColorGREEN);
senorblanco@chromium.org97f5fc62014-05-30 20:50:56 +00001245}
1246
robertphillips3e302272016-04-20 11:48:36 -07001247static void test_clipped_picture_imagefilter(skiatest::Reporter* reporter, GrContext* context) {
reedca2622b2016-03-18 07:25:55 -07001248 sk_sp<SkPicture> picture;
senorblanco3d822c22014-07-30 14:49:31 -07001249
robertphillips4418dba2016-03-07 12:45:14 -08001250 {
1251 SkRTreeFactory factory;
1252 SkPictureRecorder recorder;
1253 SkCanvas* recordingCanvas = recorder.beginRecording(1, 1, &factory, 0);
1254
1255 // Create an SkPicture which simply draws a green 1x1 rectangle.
1256 SkPaint greenPaint;
1257 greenPaint.setColor(SK_ColorGREEN);
1258 recordingCanvas->drawRect(SkRect::Make(SkIRect::MakeWH(1, 1)), greenPaint);
reedca2622b2016-03-18 07:25:55 -07001259 picture = recorder.finishRecordingAsPicture();
robertphillips4418dba2016-03-07 12:45:14 -08001260 }
1261
robertphillips3e302272016-04-20 11:48:36 -07001262 sk_sp<SkSpecialImage> srcImg(create_empty_special_image(context, 2));
senorblanco3d822c22014-07-30 14:49:31 -07001263
robertphillips5ff17b12016-03-28 13:13:42 -07001264 sk_sp<SkImageFilter> imageFilter(SkPictureImageFilter::Make(picture));
senorblanco3d822c22014-07-30 14:49:31 -07001265
senorblanco3d822c22014-07-30 14:49:31 -07001266 SkIPoint offset;
brianosman2a75e5d2016-09-22 07:15:37 -07001267 SkImageFilter::OutputProperties noColorSpace(nullptr);
1268 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeXYWH(1, 1, 1, 1), nullptr, noColorSpace);
robertphillips4418dba2016-03-07 12:45:14 -08001269
robertphillips2302de92016-03-24 07:26:32 -07001270 sk_sp<SkSpecialImage> resultImage(imageFilter->filterImage(srcImg.get(), ctx, &offset));
robertphillips4418dba2016-03-07 12:45:14 -08001271 REPORTER_ASSERT(reporter, !resultImage);
senorblanco3d822c22014-07-30 14:49:31 -07001272}
1273
robertphillips4418dba2016-03-07 12:45:14 -08001274DEF_TEST(ImageFilterClippedPictureImageFilter, reporter) {
robertphillips3e302272016-04-20 11:48:36 -07001275 test_clipped_picture_imagefilter(reporter, nullptr);
robertphillips4418dba2016-03-07 12:45:14 -08001276}
1277
1278#if SK_SUPPORT_GPU
bsalomon68d91342016-04-12 09:59:58 -07001279DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterClippedPictureImageFilter_Gpu, reporter, ctxInfo) {
bsalomon8b7451a2016-05-11 06:33:06 -07001280 test_clipped_picture_imagefilter(reporter, ctxInfo.grContext());
robertphillips4418dba2016-03-07 12:45:14 -08001281}
1282#endif
1283
tfarina9ea53f92014-06-24 06:50:39 -07001284DEF_TEST(ImageFilterEmptySaveLayer, reporter) {
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001285 // Even when there's an empty saveLayer()/restore(), ensure that an image
1286 // filter or color filter which affects transparent black still draws.
1287
1288 SkBitmap bitmap;
1289 bitmap.allocN32Pixels(10, 10);
robertphillips9a53fd72015-06-22 09:46:59 -07001290 SkCanvas canvas(bitmap);
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001291
1292 SkRTreeFactory factory;
1293 SkPictureRecorder recorder;
1294
robertphillips5605b562016-04-05 11:50:42 -07001295 sk_sp<SkColorFilter> green(SkColorFilter::MakeModeFilter(SK_ColorGREEN,
Mike Reed7d954ad2016-10-28 15:42:34 -04001296 SkBlendMode::kSrc));
robertphillips5605b562016-04-05 11:50:42 -07001297 sk_sp<SkImageFilter> imageFilter(SkColorFilterImageFilter::Make(green, nullptr));
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001298 SkPaint imageFilterPaint;
robertphillips5605b562016-04-05 11:50:42 -07001299 imageFilterPaint.setImageFilter(std::move(imageFilter));
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001300 SkPaint colorFilterPaint;
reedd053ce92016-03-22 10:17:23 -07001301 colorFilterPaint.setColorFilter(green);
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001302
1303 SkRect bounds = SkRect::MakeWH(10, 10);
1304
1305 SkCanvas* recordingCanvas = recorder.beginRecording(10, 10, &factory, 0);
1306 recordingCanvas->saveLayer(&bounds, &imageFilterPaint);
1307 recordingCanvas->restore();
reedca2622b2016-03-18 07:25:55 -07001308 sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture());
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001309
1310 canvas.clear(0);
robertphillips9b14f262014-06-04 05:40:44 -07001311 canvas.drawPicture(picture);
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001312 uint32_t pixel = *bitmap.getAddr32(0, 0);
1313 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1314
1315 recordingCanvas = recorder.beginRecording(10, 10, &factory, 0);
halcanary96fcdcc2015-08-27 07:41:13 -07001316 recordingCanvas->saveLayer(nullptr, &imageFilterPaint);
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001317 recordingCanvas->restore();
reedca2622b2016-03-18 07:25:55 -07001318 sk_sp<SkPicture> picture2(recorder.finishRecordingAsPicture());
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001319
1320 canvas.clear(0);
robertphillips9b14f262014-06-04 05:40:44 -07001321 canvas.drawPicture(picture2);
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001322 pixel = *bitmap.getAddr32(0, 0);
1323 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1324
1325 recordingCanvas = recorder.beginRecording(10, 10, &factory, 0);
1326 recordingCanvas->saveLayer(&bounds, &colorFilterPaint);
1327 recordingCanvas->restore();
reedca2622b2016-03-18 07:25:55 -07001328 sk_sp<SkPicture> picture3(recorder.finishRecordingAsPicture());
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001329
1330 canvas.clear(0);
robertphillips9b14f262014-06-04 05:40:44 -07001331 canvas.drawPicture(picture3);
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001332 pixel = *bitmap.getAddr32(0, 0);
1333 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1334}
1335
robertphillips9a53fd72015-06-22 09:46:59 -07001336static void test_huge_blur(SkCanvas* canvas, skiatest::Reporter* reporter) {
senorblanco@chromium.org09843fd2014-03-24 20:50:59 +00001337 SkBitmap bitmap;
1338 bitmap.allocN32Pixels(100, 100);
1339 bitmap.eraseARGB(0, 0, 0, 0);
1340
1341 // Check that a blur with an insane radius does not crash or assert.
senorblanco@chromium.org09843fd2014-03-24 20:50:59 +00001342 SkPaint paint;
robertphillips6e7025a2016-04-04 04:31:25 -07001343 paint.setImageFilter(SkBlurImageFilter::Make(SkIntToScalar(1<<30),
1344 SkIntToScalar(1<<30),
1345 nullptr));
reedda420b92015-12-16 08:38:15 -08001346 canvas->drawBitmap(bitmap, 0, 0, &paint);
senorblanco@chromium.org09843fd2014-03-24 20:50:59 +00001347}
1348
1349DEF_TEST(HugeBlurImageFilter, reporter) {
1350 SkBitmap temp;
1351 temp.allocN32Pixels(100, 100);
robertphillips9a53fd72015-06-22 09:46:59 -07001352 SkCanvas canvas(temp);
1353 test_huge_blur(&canvas, reporter);
senorblanco@chromium.org09843fd2014-03-24 20:50:59 +00001354}
1355
senorblanco21a465d2016-04-11 11:58:39 -07001356DEF_TEST(ImageFilterMatrixConvolutionSanityTest, reporter) {
senorblanco3a495202014-09-29 07:57:20 -07001357 SkScalar kernel[1] = { 0 };
1358 SkScalar gain = SK_Scalar1, bias = 0;
1359 SkIPoint kernelOffset = SkIPoint::Make(1, 1);
1360
halcanary96fcdcc2015-08-27 07:41:13 -07001361 // Check that an enormous (non-allocatable) kernel gives a nullptr filter.
robertphillipsef6a47b2016-04-08 08:01:20 -07001362 sk_sp<SkImageFilter> conv(SkMatrixConvolutionImageFilter::Make(
senorblanco3a495202014-09-29 07:57:20 -07001363 SkISize::Make(1<<30, 1<<30),
1364 kernel,
1365 gain,
1366 bias,
1367 kernelOffset,
1368 SkMatrixConvolutionImageFilter::kRepeat_TileMode,
robertphillipsef6a47b2016-04-08 08:01:20 -07001369 false,
1370 nullptr));
senorblanco3a495202014-09-29 07:57:20 -07001371
halcanary96fcdcc2015-08-27 07:41:13 -07001372 REPORTER_ASSERT(reporter, nullptr == conv.get());
senorblanco3a495202014-09-29 07:57:20 -07001373
halcanary96fcdcc2015-08-27 07:41:13 -07001374 // Check that a nullptr kernel gives a nullptr filter.
robertphillipsef6a47b2016-04-08 08:01:20 -07001375 conv = SkMatrixConvolutionImageFilter::Make(
senorblanco3a495202014-09-29 07:57:20 -07001376 SkISize::Make(1, 1),
halcanary96fcdcc2015-08-27 07:41:13 -07001377 nullptr,
senorblanco3a495202014-09-29 07:57:20 -07001378 gain,
1379 bias,
1380 kernelOffset,
1381 SkMatrixConvolutionImageFilter::kRepeat_TileMode,
robertphillipsef6a47b2016-04-08 08:01:20 -07001382 false,
1383 nullptr);
senorblanco3a495202014-09-29 07:57:20 -07001384
halcanary96fcdcc2015-08-27 07:41:13 -07001385 REPORTER_ASSERT(reporter, nullptr == conv.get());
senorblanco3a495202014-09-29 07:57:20 -07001386
halcanary96fcdcc2015-08-27 07:41:13 -07001387 // Check that a kernel width < 1 gives a nullptr filter.
robertphillipsef6a47b2016-04-08 08:01:20 -07001388 conv = SkMatrixConvolutionImageFilter::Make(
senorblanco3a495202014-09-29 07:57:20 -07001389 SkISize::Make(0, 1),
1390 kernel,
1391 gain,
1392 bias,
1393 kernelOffset,
1394 SkMatrixConvolutionImageFilter::kRepeat_TileMode,
robertphillipsef6a47b2016-04-08 08:01:20 -07001395 false,
1396 nullptr);
senorblanco3a495202014-09-29 07:57:20 -07001397
halcanary96fcdcc2015-08-27 07:41:13 -07001398 REPORTER_ASSERT(reporter, nullptr == conv.get());
senorblanco3a495202014-09-29 07:57:20 -07001399
halcanary96fcdcc2015-08-27 07:41:13 -07001400 // Check that kernel height < 1 gives a nullptr filter.
robertphillipsef6a47b2016-04-08 08:01:20 -07001401 conv = SkMatrixConvolutionImageFilter::Make(
senorblanco3a495202014-09-29 07:57:20 -07001402 SkISize::Make(1, -1),
1403 kernel,
1404 gain,
1405 bias,
1406 kernelOffset,
1407 SkMatrixConvolutionImageFilter::kRepeat_TileMode,
robertphillipsef6a47b2016-04-08 08:01:20 -07001408 false,
1409 nullptr);
senorblanco3a495202014-09-29 07:57:20 -07001410
halcanary96fcdcc2015-08-27 07:41:13 -07001411 REPORTER_ASSERT(reporter, nullptr == conv.get());
senorblanco3a495202014-09-29 07:57:20 -07001412}
1413
Mike Reedf1942192017-07-21 14:24:29 -04001414static void test_xfermode_cropped_input(SkSurface* surf, skiatest::Reporter* reporter) {
1415 auto canvas = surf->getCanvas();
robertphillips9a53fd72015-06-22 09:46:59 -07001416 canvas->clear(0);
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001417
1418 SkBitmap bitmap;
1419 bitmap.allocN32Pixels(1, 1);
1420 bitmap.eraseARGB(255, 255, 255, 255);
1421
robertphillips5605b562016-04-05 11:50:42 -07001422 sk_sp<SkColorFilter> green(SkColorFilter::MakeModeFilter(SK_ColorGREEN,
Mike Reed7d954ad2016-10-28 15:42:34 -04001423 SkBlendMode::kSrcIn));
robertphillips5605b562016-04-05 11:50:42 -07001424 sk_sp<SkImageFilter> greenFilter(SkColorFilterImageFilter::Make(green, nullptr));
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001425 SkImageFilter::CropRect cropRect(SkRect::MakeEmpty());
robertphillips5605b562016-04-05 11:50:42 -07001426 sk_sp<SkImageFilter> croppedOut(SkColorFilterImageFilter::Make(green, nullptr, &cropRect));
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001427
1428 // Check that an xfermode image filter whose input has been cropped out still draws the other
1429 // input. Also check that drawing with both inputs cropped out doesn't cause a GPU warning.
reed374772b2016-10-05 17:33:02 -07001430 SkBlendMode mode = SkBlendMode::kSrcOver;
robertphillips8c0326d2016-04-05 12:48:34 -07001431 sk_sp<SkImageFilter> xfermodeNoFg(SkXfermodeImageFilter::Make(mode, greenFilter,
1432 croppedOut, nullptr));
1433 sk_sp<SkImageFilter> xfermodeNoBg(SkXfermodeImageFilter::Make(mode, croppedOut,
1434 greenFilter, nullptr));
1435 sk_sp<SkImageFilter> xfermodeNoFgNoBg(SkXfermodeImageFilter::Make(mode, croppedOut,
1436 croppedOut, nullptr));
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001437
1438 SkPaint paint;
robertphillips8c0326d2016-04-05 12:48:34 -07001439 paint.setImageFilter(std::move(xfermodeNoFg));
reedda420b92015-12-16 08:38:15 -08001440 canvas->drawBitmap(bitmap, 0, 0, &paint); // drawSprite
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001441
1442 uint32_t pixel;
kkinnunena9d9a392015-03-06 07:16:00 -08001443 SkImageInfo info = SkImageInfo::Make(1, 1, kBGRA_8888_SkColorType, kUnpremul_SkAlphaType);
Mike Reedf1942192017-07-21 14:24:29 -04001444 surf->readPixels(info, &pixel, 4, 0, 0);
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001445 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1446
robertphillips8c0326d2016-04-05 12:48:34 -07001447 paint.setImageFilter(std::move(xfermodeNoBg));
reedda420b92015-12-16 08:38:15 -08001448 canvas->drawBitmap(bitmap, 0, 0, &paint); // drawSprite
Mike Reedf1942192017-07-21 14:24:29 -04001449 surf->readPixels(info, &pixel, 4, 0, 0);
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001450 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1451
robertphillips8c0326d2016-04-05 12:48:34 -07001452 paint.setImageFilter(std::move(xfermodeNoFgNoBg));
reedda420b92015-12-16 08:38:15 -08001453 canvas->drawBitmap(bitmap, 0, 0, &paint); // drawSprite
Mike Reedf1942192017-07-21 14:24:29 -04001454 surf->readPixels(info, &pixel, 4, 0, 0);
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001455 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1456}
1457
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001458DEF_TEST(ImageFilterNestedSaveLayer, reporter) {
1459 SkBitmap temp;
1460 temp.allocN32Pixels(50, 50);
robertphillips9a53fd72015-06-22 09:46:59 -07001461 SkCanvas canvas(temp);
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001462 canvas.clear(0x0);
1463
1464 SkBitmap bitmap;
1465 bitmap.allocN32Pixels(10, 10);
1466 bitmap.eraseColor(SK_ColorGREEN);
1467
1468 SkMatrix matrix;
1469 matrix.setScale(SkIntToScalar(2), SkIntToScalar(2));
1470 matrix.postTranslate(SkIntToScalar(-20), SkIntToScalar(-20));
robertphillipsae8c9332016-04-05 15:09:00 -07001471 sk_sp<SkImageFilter> matrixFilter(
1472 SkImageFilter::MakeMatrixFilter(matrix, kLow_SkFilterQuality, nullptr));
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001473
1474 // Test that saveLayer() with a filter nested inside another saveLayer() applies the
1475 // correct offset to the filter matrix.
1476 SkRect bounds1 = SkRect::MakeXYWH(10, 10, 30, 30);
halcanary96fcdcc2015-08-27 07:41:13 -07001477 canvas.saveLayer(&bounds1, nullptr);
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001478 SkPaint filterPaint;
robertphillipsae8c9332016-04-05 15:09:00 -07001479 filterPaint.setImageFilter(std::move(matrixFilter));
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001480 SkRect bounds2 = SkRect::MakeXYWH(20, 20, 10, 10);
1481 canvas.saveLayer(&bounds2, &filterPaint);
1482 SkPaint greenPaint;
1483 greenPaint.setColor(SK_ColorGREEN);
1484 canvas.drawRect(bounds2, greenPaint);
1485 canvas.restore();
1486 canvas.restore();
1487 SkPaint strokePaint;
1488 strokePaint.setStyle(SkPaint::kStroke_Style);
1489 strokePaint.setColor(SK_ColorRED);
1490
kkinnunena9d9a392015-03-06 07:16:00 -08001491 SkImageInfo info = SkImageInfo::Make(1, 1, kBGRA_8888_SkColorType, kUnpremul_SkAlphaType);
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001492 uint32_t pixel;
Mike Reedf1942192017-07-21 14:24:29 -04001493 temp.readPixels(info, &pixel, 4, 25, 25);
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001494 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1495
1496 // Test that drawSprite() with a filter nested inside a saveLayer() applies the
1497 // correct offset to the filter matrix.
1498 canvas.clear(0x0);
Mike Reedf1942192017-07-21 14:24:29 -04001499 temp.readPixels(info, &pixel, 4, 25, 25);
halcanary96fcdcc2015-08-27 07:41:13 -07001500 canvas.saveLayer(&bounds1, nullptr);
reedda420b92015-12-16 08:38:15 -08001501 canvas.drawBitmap(bitmap, 20, 20, &filterPaint); // drawSprite
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001502 canvas.restore();
1503
Mike Reedf1942192017-07-21 14:24:29 -04001504 temp.readPixels(info, &pixel, 4, 25, 25);
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001505 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1506}
1507
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001508DEF_TEST(XfermodeImageFilterCroppedInput, reporter) {
Mike Reedf1942192017-07-21 14:24:29 -04001509 test_xfermode_cropped_input(SkSurface::MakeRasterN32Premul(100, 100).get(), reporter);
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001510}
senorblanco@chromium.org09843fd2014-03-24 20:50:59 +00001511
robertphillips3e302272016-04-20 11:48:36 -07001512static void test_composed_imagefilter_offset(skiatest::Reporter* reporter, GrContext* context) {
1513 sk_sp<SkSpecialImage> srcImg(create_empty_special_image(context, 100));
ajuma5788faa2015-02-13 09:05:47 -08001514
1515 SkImageFilter::CropRect cropRect(SkRect::MakeXYWH(1, 0, 20, 20));
robertphillips51a315e2016-03-31 09:05:49 -07001516 sk_sp<SkImageFilter> offsetFilter(SkOffsetImageFilter::Make(0, 0, nullptr, &cropRect));
robertphillips6e7025a2016-04-04 04:31:25 -07001517 sk_sp<SkImageFilter> blurFilter(SkBlurImageFilter::Make(SK_Scalar1, SK_Scalar1,
1518 nullptr, &cropRect));
robertphillips491fb172016-03-30 12:32:58 -07001519 sk_sp<SkImageFilter> composedFilter(SkComposeImageFilter::Make(std::move(blurFilter),
1520 std::move(offsetFilter)));
ajuma5788faa2015-02-13 09:05:47 -08001521 SkIPoint offset;
brianosman2a75e5d2016-09-22 07:15:37 -07001522 SkImageFilter::OutputProperties noColorSpace(nullptr);
1523 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeWH(100, 100), nullptr, noColorSpace);
robertphillips4418dba2016-03-07 12:45:14 -08001524
robertphillips2302de92016-03-24 07:26:32 -07001525 sk_sp<SkSpecialImage> resultImg(composedFilter->filterImage(srcImg.get(), ctx, &offset));
robertphillips4418dba2016-03-07 12:45:14 -08001526 REPORTER_ASSERT(reporter, resultImg);
ajuma5788faa2015-02-13 09:05:47 -08001527 REPORTER_ASSERT(reporter, offset.fX == 1 && offset.fY == 0);
1528}
1529
robertphillips4418dba2016-03-07 12:45:14 -08001530DEF_TEST(ComposedImageFilterOffset, reporter) {
robertphillips3e302272016-04-20 11:48:36 -07001531 test_composed_imagefilter_offset(reporter, nullptr);
robertphillips4418dba2016-03-07 12:45:14 -08001532}
1533
1534#if SK_SUPPORT_GPU
bsalomon68d91342016-04-12 09:59:58 -07001535DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ComposedImageFilterOffset_Gpu, reporter, ctxInfo) {
bsalomon8b7451a2016-05-11 06:33:06 -07001536 test_composed_imagefilter_offset(reporter, ctxInfo.grContext());
robertphillips4418dba2016-03-07 12:45:14 -08001537}
1538#endif
1539
robertphillips3e302272016-04-20 11:48:36 -07001540static void test_composed_imagefilter_bounds(skiatest::Reporter* reporter, GrContext* context) {
jbroman17a65202016-03-21 08:38:58 -07001541 // The bounds passed to the inner filter must be filtered by the outer
1542 // filter, so that the inner filter produces the pixels that the outer
1543 // filter requires as input. This matters if the outer filter moves pixels.
1544 // Here, accounting for the outer offset is necessary so that the green
1545 // pixels of the picture are not clipped.
1546
1547 SkPictureRecorder recorder;
1548 SkCanvas* recordingCanvas = recorder.beginRecording(SkRect::MakeWH(200, 100));
1549 recordingCanvas->clipRect(SkRect::MakeXYWH(100, 0, 100, 100));
1550 recordingCanvas->clear(SK_ColorGREEN);
robertphillips491fb172016-03-30 12:32:58 -07001551 sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture());
robertphillips5ff17b12016-03-28 13:13:42 -07001552 sk_sp<SkImageFilter> pictureFilter(SkPictureImageFilter::Make(picture));
jbroman17a65202016-03-21 08:38:58 -07001553 SkImageFilter::CropRect cropRect(SkRect::MakeWH(100, 100));
robertphillips51a315e2016-03-31 09:05:49 -07001554 sk_sp<SkImageFilter> offsetFilter(SkOffsetImageFilter::Make(-100, 0, nullptr, &cropRect));
robertphillips491fb172016-03-30 12:32:58 -07001555 sk_sp<SkImageFilter> composedFilter(SkComposeImageFilter::Make(std::move(offsetFilter),
1556 std::move(pictureFilter)));
jbroman17a65202016-03-21 08:38:58 -07001557
robertphillips3e302272016-04-20 11:48:36 -07001558 sk_sp<SkSpecialImage> sourceImage(create_empty_special_image(context, 100));
brianosman2a75e5d2016-09-22 07:15:37 -07001559 SkImageFilter::OutputProperties noColorSpace(nullptr);
1560 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeWH(100, 100), nullptr, noColorSpace);
jbroman17a65202016-03-21 08:38:58 -07001561 SkIPoint offset;
1562 sk_sp<SkSpecialImage> result(composedFilter->filterImage(sourceImage.get(), ctx, &offset));
1563 REPORTER_ASSERT(reporter, offset.isZero());
1564 REPORTER_ASSERT(reporter, result);
1565 REPORTER_ASSERT(reporter, result->subset().size() == SkISize::Make(100, 100));
1566
1567 SkBitmap resultBM;
robertphillips64612512016-04-08 12:10:42 -07001568 REPORTER_ASSERT(reporter, result->getROPixels(&resultBM));
jbroman17a65202016-03-21 08:38:58 -07001569 REPORTER_ASSERT(reporter, resultBM.getColor(50, 50) == SK_ColorGREEN);
1570}
1571
1572DEF_TEST(ComposedImageFilterBounds, reporter) {
robertphillips3e302272016-04-20 11:48:36 -07001573 test_composed_imagefilter_bounds(reporter, nullptr);
jbroman17a65202016-03-21 08:38:58 -07001574}
1575
1576#if SK_SUPPORT_GPU
egdanielab527a52016-06-28 08:07:26 -07001577DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ComposedImageFilterBounds_Gpu, reporter, ctxInfo) {
bsalomon8b7451a2016-05-11 06:33:06 -07001578 test_composed_imagefilter_bounds(reporter, ctxInfo.grContext());
jbroman17a65202016-03-21 08:38:58 -07001579}
1580#endif
1581
robertphillips3e302272016-04-20 11:48:36 -07001582static void test_partial_crop_rect(skiatest::Reporter* reporter, GrContext* context) {
1583 sk_sp<SkSpecialImage> srcImg(create_empty_special_image(context, 100));
senorblanco24d2a7b2015-07-13 10:27:05 -07001584
1585 SkImageFilter::CropRect cropRect(SkRect::MakeXYWH(100, 0, 20, 30),
senorblancoed7cf272015-07-16 15:19:11 -07001586 SkImageFilter::CropRect::kHasWidth_CropEdge | SkImageFilter::CropRect::kHasHeight_CropEdge);
robertphillips5605b562016-04-05 11:50:42 -07001587 sk_sp<SkImageFilter> filter(make_grayscale(nullptr, &cropRect));
senorblanco24d2a7b2015-07-13 10:27:05 -07001588 SkIPoint offset;
brianosman2a75e5d2016-09-22 07:15:37 -07001589 SkImageFilter::OutputProperties noColorSpace(nullptr);
1590 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeWH(100, 100), nullptr, noColorSpace);
robertphillips4418dba2016-03-07 12:45:14 -08001591
robertphillips2302de92016-03-24 07:26:32 -07001592 sk_sp<SkSpecialImage> resultImg(filter->filterImage(srcImg.get(), ctx, &offset));
robertphillips4418dba2016-03-07 12:45:14 -08001593 REPORTER_ASSERT(reporter, resultImg);
1594
senorblanco24d2a7b2015-07-13 10:27:05 -07001595 REPORTER_ASSERT(reporter, offset.fX == 0);
1596 REPORTER_ASSERT(reporter, offset.fY == 0);
robertphillips4418dba2016-03-07 12:45:14 -08001597 REPORTER_ASSERT(reporter, resultImg->width() == 20);
1598 REPORTER_ASSERT(reporter, resultImg->height() == 30);
senorblanco24d2a7b2015-07-13 10:27:05 -07001599}
1600
senorblanco21a465d2016-04-11 11:58:39 -07001601DEF_TEST(ImageFilterPartialCropRect, reporter) {
robertphillips3e302272016-04-20 11:48:36 -07001602 test_partial_crop_rect(reporter, nullptr);
robertphillips4418dba2016-03-07 12:45:14 -08001603}
1604
1605#if SK_SUPPORT_GPU
bsalomon68d91342016-04-12 09:59:58 -07001606DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterPartialCropRect_Gpu, reporter, ctxInfo) {
bsalomon8b7451a2016-05-11 06:33:06 -07001607 test_partial_crop_rect(reporter, ctxInfo.grContext());
robertphillips4418dba2016-03-07 12:45:14 -08001608}
1609#endif
1610
senorblanco0abdf762015-08-20 11:10:41 -07001611DEF_TEST(ImageFilterCanComputeFastBounds, reporter) {
1612
robertphillips12fa47d2016-04-08 16:28:09 -07001613 {
1614 SkPoint3 location = SkPoint3::Make(0, 0, SK_Scalar1);
1615 sk_sp<SkImageFilter> lighting(SkLightingImageFilter::MakePointLitDiffuse(location,
1616 SK_ColorGREEN,
1617 0, 0, nullptr));
1618 REPORTER_ASSERT(reporter, !lighting->canComputeFastBounds());
1619 }
senorblanco0abdf762015-08-20 11:10:41 -07001620
senorblanco0abdf762015-08-20 11:10:41 -07001621 {
robertphillips6e7025a2016-04-04 04:31:25 -07001622 sk_sp<SkImageFilter> gray(make_grayscale(nullptr, nullptr));
1623 REPORTER_ASSERT(reporter, gray->canComputeFastBounds());
1624 {
1625 SkColorFilter* grayCF;
1626 REPORTER_ASSERT(reporter, gray->asAColorFilter(&grayCF));
1627 REPORTER_ASSERT(reporter, !grayCF->affectsTransparentBlack());
1628 grayCF->unref();
1629 }
1630 REPORTER_ASSERT(reporter, gray->canComputeFastBounds());
1631
1632 sk_sp<SkImageFilter> grayBlur(SkBlurImageFilter::Make(SK_Scalar1, SK_Scalar1,
1633 std::move(gray)));
1634 REPORTER_ASSERT(reporter, grayBlur->canComputeFastBounds());
senorblanco0abdf762015-08-20 11:10:41 -07001635 }
senorblanco0abdf762015-08-20 11:10:41 -07001636
robertphillips6e7025a2016-04-04 04:31:25 -07001637 {
1638 SkScalar greenMatrix[20] = { 0, 0, 0, 0, 0,
1639 0, 0, 0, 0, 1,
1640 0, 0, 0, 0, 0,
1641 0, 0, 0, 0, 1 };
1642 sk_sp<SkColorFilter> greenCF(SkColorFilter::MakeMatrixFilterRowMajor255(greenMatrix));
robertphillips5605b562016-04-05 11:50:42 -07001643 sk_sp<SkImageFilter> green(SkColorFilterImageFilter::Make(greenCF, nullptr));
senorblanco0abdf762015-08-20 11:10:41 -07001644
robertphillips6e7025a2016-04-04 04:31:25 -07001645 REPORTER_ASSERT(reporter, greenCF->affectsTransparentBlack());
1646 REPORTER_ASSERT(reporter, !green->canComputeFastBounds());
senorblanco0abdf762015-08-20 11:10:41 -07001647
robertphillips6e7025a2016-04-04 04:31:25 -07001648 sk_sp<SkImageFilter> greenBlur(SkBlurImageFilter::Make(SK_Scalar1, SK_Scalar1,
1649 std::move(green)));
1650 REPORTER_ASSERT(reporter, !greenBlur->canComputeFastBounds());
1651 }
senorblanco0abdf762015-08-20 11:10:41 -07001652
1653 uint8_t allOne[256], identity[256];
1654 for (int i = 0; i < 256; ++i) {
1655 identity[i] = i;
1656 allOne[i] = 255;
1657 }
1658
robertphillips5605b562016-04-05 11:50:42 -07001659 sk_sp<SkColorFilter> identityCF(SkTableColorFilter::MakeARGB(identity, identity,
1660 identity, allOne));
1661 sk_sp<SkImageFilter> identityFilter(SkColorFilterImageFilter::Make(identityCF, nullptr));
senorblanco0abdf762015-08-20 11:10:41 -07001662 REPORTER_ASSERT(reporter, !identityCF->affectsTransparentBlack());
1663 REPORTER_ASSERT(reporter, identityFilter->canComputeFastBounds());
1664
robertphillips5605b562016-04-05 11:50:42 -07001665 sk_sp<SkColorFilter> forceOpaqueCF(SkTableColorFilter::MakeARGB(allOne, identity,
1666 identity, identity));
1667 sk_sp<SkImageFilter> forceOpaque(SkColorFilterImageFilter::Make(forceOpaqueCF, nullptr));
senorblanco0abdf762015-08-20 11:10:41 -07001668 REPORTER_ASSERT(reporter, forceOpaqueCF->affectsTransparentBlack());
1669 REPORTER_ASSERT(reporter, !forceOpaque->canComputeFastBounds());
1670}
1671
fmalitacd56f812015-09-14 13:31:18 -07001672// Verify that SkImageSource survives serialization
1673DEF_TEST(ImageFilterImageSourceSerialization, reporter) {
reede8f30622016-03-23 18:59:25 -07001674 auto surface(SkSurface::MakeRasterN32Premul(10, 10));
fmalitacd56f812015-09-14 13:31:18 -07001675 surface->getCanvas()->clear(SK_ColorGREEN);
reed9ce9d672016-03-17 10:51:11 -07001676 sk_sp<SkImage> image(surface->makeImageSnapshot());
robertphillips549c8992016-04-01 09:28:51 -07001677 sk_sp<SkImageFilter> filter(SkImageSource::Make(std::move(image)));
fmalitacd56f812015-09-14 13:31:18 -07001678
robertphillips549c8992016-04-01 09:28:51 -07001679 sk_sp<SkData> data(SkValidatingSerializeFlattenable(filter.get()));
Mike Reed5e257172016-11-01 11:22:05 -04001680 sk_sp<SkImageFilter> unflattenedFilter = SkValidatingDeserializeImageFilter(data->data(),
1681 data->size());
fmalitacd56f812015-09-14 13:31:18 -07001682 REPORTER_ASSERT(reporter, unflattenedFilter);
1683
1684 SkBitmap bm;
1685 bm.allocN32Pixels(10, 10);
fmalita23cb88c2015-09-15 06:56:23 -07001686 bm.eraseColor(SK_ColorBLUE);
fmalitacd56f812015-09-14 13:31:18 -07001687 SkPaint paint;
1688 paint.setColor(SK_ColorRED);
1689 paint.setImageFilter(unflattenedFilter);
1690
1691 SkCanvas canvas(bm);
1692 canvas.drawRect(SkRect::MakeWH(10, 10), paint);
1693 REPORTER_ASSERT(reporter, *bm.getAddr32(0, 0) == SkPreMultiplyColor(SK_ColorGREEN));
1694}
1695
bsalomon45eefcf2016-01-05 08:39:28 -08001696static void test_large_blur_input(skiatest::Reporter* reporter, SkCanvas* canvas) {
1697 SkBitmap largeBmp;
1698 int largeW = 5000;
1699 int largeH = 5000;
1700#if SK_SUPPORT_GPU
1701 // If we're GPU-backed make the bitmap too large to be converted into a texture.
1702 if (GrContext* ctx = canvas->getGrContext()) {
1703 largeW = ctx->caps()->maxTextureSize() + 1;
1704 }
1705#endif
1706
1707 largeBmp.allocN32Pixels(largeW, largeH);
mtklein2afbe232016-02-07 12:23:10 -08001708 largeBmp.eraseColor(0);
bsalomon45eefcf2016-01-05 08:39:28 -08001709 if (!largeBmp.getPixels()) {
1710 ERRORF(reporter, "Failed to allocate large bmp.");
1711 return;
1712 }
1713
reed9ce9d672016-03-17 10:51:11 -07001714 sk_sp<SkImage> largeImage(SkImage::MakeFromBitmap(largeBmp));
bsalomon45eefcf2016-01-05 08:39:28 -08001715 if (!largeImage) {
1716 ERRORF(reporter, "Failed to create large image.");
1717 return;
1718 }
1719
robertphillips549c8992016-04-01 09:28:51 -07001720 sk_sp<SkImageFilter> largeSource(SkImageSource::Make(std::move(largeImage)));
bsalomon45eefcf2016-01-05 08:39:28 -08001721 if (!largeSource) {
1722 ERRORF(reporter, "Failed to create large SkImageSource.");
1723 return;
1724 }
1725
robertphillips6e7025a2016-04-04 04:31:25 -07001726 sk_sp<SkImageFilter> blur(SkBlurImageFilter::Make(10.f, 10.f, std::move(largeSource)));
bsalomon45eefcf2016-01-05 08:39:28 -08001727 if (!blur) {
1728 ERRORF(reporter, "Failed to create SkBlurImageFilter.");
1729 return;
1730 }
1731
1732 SkPaint paint;
robertphillips549c8992016-04-01 09:28:51 -07001733 paint.setImageFilter(std::move(blur));
bsalomon45eefcf2016-01-05 08:39:28 -08001734
1735 // This should not crash (http://crbug.com/570479).
1736 canvas->drawRect(SkRect::MakeIWH(largeW, largeH), paint);
1737}
1738
senorblanco21a465d2016-04-11 11:58:39 -07001739DEF_TEST(ImageFilterBlurLargeImage, reporter) {
reede8f30622016-03-23 18:59:25 -07001740 auto surface(SkSurface::MakeRaster(SkImageInfo::MakeN32Premul(100, 100)));
bsalomon45eefcf2016-01-05 08:39:28 -08001741 test_large_blur_input(reporter, surface->getCanvas());
1742}
1743
senorblanco5878dbd2016-05-19 14:50:29 -07001744static void test_make_with_filter(skiatest::Reporter* reporter, GrContext* context) {
Robert Phillipsa5fdc972017-02-18 16:58:09 -05001745 sk_sp<SkSurface> surface(create_surface(context, 192, 128));
senorblanco5878dbd2016-05-19 14:50:29 -07001746 surface->getCanvas()->clear(SK_ColorRED);
1747 SkPaint bluePaint;
1748 bluePaint.setColor(SK_ColorBLUE);
1749 SkIRect subset = SkIRect::MakeXYWH(25, 20, 50, 50);
1750 surface->getCanvas()->drawRect(SkRect::Make(subset), bluePaint);
1751 sk_sp<SkImage> sourceImage = surface->makeImageSnapshot();
1752
1753 sk_sp<SkImageFilter> filter = make_grayscale(nullptr, nullptr);
1754 SkIRect clipBounds = SkIRect::MakeXYWH(30, 35, 100, 100);
1755 SkIRect outSubset;
1756 SkIPoint offset;
1757 sk_sp<SkImage> result;
1758
1759 result = sourceImage->makeWithFilter(nullptr, subset, clipBounds, &outSubset, &offset);
1760 REPORTER_ASSERT(reporter, !result);
1761
1762 result = sourceImage->makeWithFilter(filter.get(), subset, clipBounds, nullptr, &offset);
1763 REPORTER_ASSERT(reporter, !result);
1764
1765 result = sourceImage->makeWithFilter(filter.get(), subset, clipBounds, &outSubset, nullptr);
1766 REPORTER_ASSERT(reporter, !result);
1767
1768 SkIRect bigSubset = SkIRect::MakeXYWH(-10000, -10000, 20000, 20000);
1769 result = sourceImage->makeWithFilter(filter.get(), bigSubset, clipBounds, &outSubset, &offset);
1770 REPORTER_ASSERT(reporter, !result);
1771
1772 SkIRect empty = SkIRect::MakeEmpty();
1773 result = sourceImage->makeWithFilter(filter.get(), empty, clipBounds, &outSubset, &offset);
1774 REPORTER_ASSERT(reporter, !result);
1775
1776 result = sourceImage->makeWithFilter(filter.get(), subset, empty, &outSubset, &offset);
1777 REPORTER_ASSERT(reporter, !result);
1778
1779 SkIRect leftField = SkIRect::MakeXYWH(-1000, 0, 100, 100);
1780 result = sourceImage->makeWithFilter(filter.get(), subset, leftField, &outSubset, &offset);
1781 REPORTER_ASSERT(reporter, !result);
1782
1783 result = sourceImage->makeWithFilter(filter.get(), subset, clipBounds, &outSubset, &offset);
1784
1785 REPORTER_ASSERT(reporter, result);
1786 REPORTER_ASSERT(reporter, result->bounds().contains(outSubset));
1787 SkIRect destRect = SkIRect::MakeXYWH(offset.x(), offset.y(),
1788 outSubset.width(), outSubset.height());
1789 REPORTER_ASSERT(reporter, clipBounds.contains(destRect));
Robert Phillipsa5fdc972017-02-18 16:58:09 -05001790
1791 // In GPU-mode, this case creates a special image with a backing size that differs from
1792 // the content size
1793 {
1794 clipBounds.setXYWH(0, 0, 170, 100);
1795 subset.setXYWH(0, 0, 160, 90);
1796
1797 filter = SkXfermodeImageFilter::Make(SkBlendMode::kSrc, nullptr);
1798 result = sourceImage->makeWithFilter(filter.get(), subset, clipBounds, &outSubset, &offset);
1799 REPORTER_ASSERT(reporter, result);
1800 }
senorblanco5878dbd2016-05-19 14:50:29 -07001801}
1802
1803DEF_TEST(ImageFilterMakeWithFilter, reporter) {
1804 test_make_with_filter(reporter, nullptr);
1805}
1806
1807#if SK_SUPPORT_GPU
1808DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterMakeWithFilter_Gpu, reporter, ctxInfo) {
1809 test_make_with_filter(reporter, ctxInfo.grContext());
1810}
1811#endif
1812
senorblanco@chromium.org58d14662014-02-03 22:36:39 +00001813#if SK_SUPPORT_GPU
reed4a8126e2014-09-22 07:29:03 -07001814
bsalomon68d91342016-04-12 09:59:58 -07001815DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterHugeBlur_Gpu, reporter, ctxInfo) {
robertphillipsefbffed2015-06-22 12:06:08 -07001816
bsalomon8b7451a2016-05-11 06:33:06 -07001817 sk_sp<SkSurface> surf(SkSurface::MakeRenderTarget(ctxInfo.grContext(),
robertphillips3e302272016-04-20 11:48:36 -07001818 SkBudgeted::kNo,
1819 SkImageInfo::MakeN32Premul(100, 100)));
robertphillips9a53fd72015-06-22 09:46:59 -07001820
robertphillips3e302272016-04-20 11:48:36 -07001821
1822 SkCanvas* canvas = surf->getCanvas();
1823
1824 test_huge_blur(canvas, reporter);
senorblanco@chromium.org09843fd2014-03-24 20:50:59 +00001825}
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001826
egdanielab527a52016-06-28 08:07:26 -07001827DEF_GPUTEST_FOR_RENDERING_CONTEXTS(XfermodeImageFilterCroppedInput_Gpu, reporter, ctxInfo) {
Brian Salomon8996e182017-07-05 17:01:48 -04001828 sk_sp<SkSurface> surf(SkSurface::MakeRenderTarget(
1829 ctxInfo.grContext(),
1830 SkBudgeted::kNo,
1831 SkImageInfo::Make(1, 1, kRGBA_8888_SkColorType, kPremul_SkAlphaType)));
robertphillips3e302272016-04-20 11:48:36 -07001832
Mike Reedf1942192017-07-21 14:24:29 -04001833 test_xfermode_cropped_input(surf.get(), reporter);
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001834}
senorblanco32673b92014-09-09 09:15:04 -07001835
egdanielab527a52016-06-28 08:07:26 -07001836DEF_GPUTEST_FOR_ALL_CONTEXTS(ImageFilterBlurLargeImage_Gpu, reporter, ctxInfo) {
Brian Salomon8996e182017-07-05 17:01:48 -04001837 auto surface(SkSurface::MakeRenderTarget(
1838 ctxInfo.grContext(), SkBudgeted::kYes,
1839 SkImageInfo::Make(100, 100, kRGBA_8888_SkColorType, kPremul_SkAlphaType)));
bsalomon45eefcf2016-01-05 08:39:28 -08001840 test_large_blur_input(reporter, surface->getCanvas());
1841}
senorblanco@chromium.org58d14662014-02-03 22:36:39 +00001842#endif
reedbb34a8a2016-04-23 15:19:07 -07001843
1844/*
1845 * Test that colorfilterimagefilter does not require its CTM to be decomposed when it has more
1846 * than just scale/translate, but that other filters do.
1847 */
reed96a04f32016-04-25 09:25:15 -07001848DEF_TEST(ImageFilterComplexCTM, reporter) {
reedbb34a8a2016-04-23 15:19:07 -07001849 // just need a colorfilter to exercise the corresponding imagefilter
Mike Reed7d954ad2016-10-28 15:42:34 -04001850 sk_sp<SkColorFilter> cf = SkColorFilter::MakeModeFilter(SK_ColorRED, SkBlendMode::kSrcATop);
reed96a04f32016-04-25 09:25:15 -07001851 sk_sp<SkImageFilter> cfif = SkColorFilterImageFilter::Make(cf, nullptr); // can handle
1852 sk_sp<SkImageFilter> blif = SkBlurImageFilter::Make(3, 3, nullptr); // cannot handle
reedbb34a8a2016-04-23 15:19:07 -07001853
1854 struct {
1855 sk_sp<SkImageFilter> fFilter;
1856 bool fExpectCanHandle;
1857 } recs[] = {
1858 { cfif, true },
1859 { SkColorFilterImageFilter::Make(cf, cfif), true },
Mike Reed0bdaf052017-06-18 23:35:57 -04001860 { SkMergeImageFilter::Make(cfif, cfif), true },
reed96a04f32016-04-25 09:25:15 -07001861 { SkComposeImageFilter::Make(cfif, cfif), true },
1862
reedbb34a8a2016-04-23 15:19:07 -07001863 { blif, false },
reed96a04f32016-04-25 09:25:15 -07001864 { SkBlurImageFilter::Make(3, 3, cfif), false },
reedbb34a8a2016-04-23 15:19:07 -07001865 { SkColorFilterImageFilter::Make(cf, blif), false },
Mike Reed0bdaf052017-06-18 23:35:57 -04001866 { SkMergeImageFilter::Make(cfif, blif), false },
reed96a04f32016-04-25 09:25:15 -07001867 { SkComposeImageFilter::Make(blif, cfif), false },
reedbb34a8a2016-04-23 15:19:07 -07001868 };
liyuqianbfebe222016-11-14 11:17:16 -08001869
reedbb34a8a2016-04-23 15:19:07 -07001870 for (const auto& rec : recs) {
reed96a04f32016-04-25 09:25:15 -07001871 const bool canHandle = rec.fFilter->canHandleComplexCTM();
reedbb34a8a2016-04-23 15:19:07 -07001872 REPORTER_ASSERT(reporter, canHandle == rec.fExpectCanHandle);
1873 }
1874}
Florin Malita08252ec2017-07-06 12:48:15 -04001875
1876// Test that transforming the filter DAG doesn't clone shared nodes multiple times.
1877DEF_TEST(ImageFilterColorSpaceDAG, reporter) {
1878
1879 // Helper for counting makeColorSpace() clones.
1880 class TestFilter final : public SkImageFilter {
1881 public:
1882 TestFilter() : INHERITED(nullptr, 0, nullptr) {}
1883
1884#ifndef SK_IGNORE_TO_STRING
1885 void toString(SkString*) const override {}
1886#endif
1887 Factory getFactory() const override { return nullptr; }
1888
1889 size_t cloneCount() const { return fCloneCount; }
1890
1891 protected:
1892 sk_sp<SkSpecialImage> onFilterImage(SkSpecialImage* src, const Context&,
1893 SkIPoint* offset) const override {
1894 return nullptr;
1895 }
1896 sk_sp<SkImageFilter> onMakeColorSpace(SkColorSpaceXformer*) const override {
1897 fCloneCount++;
1898 return sk_ref_sp(const_cast<TestFilter*>(this));
1899 }
1900
1901 private:
1902 typedef SkImageFilter INHERITED;
1903
1904 mutable size_t fCloneCount = 0;
1905 };
1906
1907 auto filter = sk_make_sp<TestFilter>();
1908 REPORTER_ASSERT(reporter, filter->cloneCount() == 0u);
1909
1910 // Build a DAG referencing the filter twice.
1911 auto complexFilter = SkMergeImageFilter::Make(filter, SkOffsetImageFilter::Make(1, 1, filter));
1912 REPORTER_ASSERT(reporter, filter->cloneCount() == 0u);
1913
1914 auto xformer = SkColorSpaceXformer::Make(SkColorSpace::MakeSRGB());
1915 auto xformedFilter = xformer->apply(complexFilter.get());
1916
Florin Malita39e08552017-07-06 14:16:18 -04001917 REPORTER_ASSERT(reporter, filter->cloneCount() == 1u);
Florin Malita08252ec2017-07-06 12:48:15 -04001918}