blob: dd0824551b157342e0791c9cd537bedc1812de45 [file] [log] [blame]
senorblanco@chromium.org194d7752013-07-24 22:19:24 +00001/*
2 * Copyright 2013 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
commit-bot@chromium.org4b681bc2013-09-13 12:40:02 +00008#include "SkBitmap.h"
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00009#include "SkBlurImageFilter.h"
tfarina@chromium.org8f6884a2014-01-24 20:56:26 +000010#include "SkCanvas.h"
11#include "SkColorFilterImageFilter.h"
12#include "SkColorMatrixFilter.h"
ajuma5788faa2015-02-13 09:05:47 -080013#include "SkComposeImageFilter.h"
senorblanco@chromium.org6776b822014-01-03 21:48:22 +000014#include "SkDisplacementMapEffect.h"
15#include "SkDropShadowImageFilter.h"
senorblanco@chromium.org97f5fc62014-05-30 20:50:56 +000016#include "SkFlattenableSerialization.h"
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +000017#include "SkGradientShader.h"
fmalita5598b632015-09-15 11:26:13 -070018#include "SkImage.h"
fmalitacd56f812015-09-14 13:31:18 -070019#include "SkImageSource.h"
commit-bot@chromium.org4b681bc2013-09-13 12:40:02 +000020#include "SkLightingImageFilter.h"
tfarina@chromium.org8f6884a2014-01-24 20:56:26 +000021#include "SkMatrixConvolutionImageFilter.h"
senorblanco@chromium.org6776b822014-01-03 21:48:22 +000022#include "SkMergeImageFilter.h"
23#include "SkMorphologyImageFilter.h"
senorblanco@chromium.org6776b822014-01-03 21:48:22 +000024#include "SkOffsetImageFilter.h"
ajuma77b6ba32016-01-08 14:58:35 -080025#include "SkPaintImageFilter.h"
senorblanco8f3937d2014-10-29 12:36:32 -070026#include "SkPerlinNoiseShader.h"
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +000027#include "SkPicture.h"
senorblanco@chromium.org910702b2014-05-30 20:36:15 +000028#include "SkPictureImageFilter.h"
robertphillips@google.com770963f2014-04-18 18:04:41 +000029#include "SkPictureRecorder.h"
robertphillips3d32d762015-07-13 13:16:44 -070030#include "SkPoint3.h"
halcanary97d2c0a2014-08-19 06:27:53 -070031#include "SkReadBuffer.h"
tfarina@chromium.org8f6884a2014-01-24 20:56:26 +000032#include "SkRect.h"
robertphillips4418dba2016-03-07 12:45:14 -080033#include "SkSpecialImage.h"
34#include "SkSpecialSurface.h"
fmalitacd56f812015-09-14 13:31:18 -070035#include "SkSurface.h"
senorblanco0abdf762015-08-20 11:10:41 -070036#include "SkTableColorFilter.h"
senorblanco@chromium.org6776b822014-01-03 21:48:22 +000037#include "SkTileImageFilter.h"
38#include "SkXfermodeImageFilter.h"
tfarina@chromium.org8f6884a2014-01-24 20:56:26 +000039#include "Test.h"
senorblanco@chromium.org194d7752013-07-24 22:19:24 +000040
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +000041#if SK_SUPPORT_GPU
kkinnunen15302832015-12-01 04:35:26 -080042#include "GrContext.h"
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +000043#endif
44
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +000045static const int kBitmapSize = 4;
commit-bot@chromium.org4b681bc2013-09-13 12:40:02 +000046
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +000047namespace {
48
49class MatrixTestImageFilter : public SkImageFilter {
50public:
robertphillips43c2ad42016-04-04 05:05:11 -070051 static sk_sp<SkImageFilter> Make(skiatest::Reporter* reporter,
52 const SkMatrix& expectedMatrix) {
53 return sk_sp<SkImageFilter>(new MatrixTestImageFilter(reporter, expectedMatrix));
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +000054 }
55
robertphillipsf3f5bad2014-12-19 13:49:15 -080056 SK_TO_STRING_OVERRIDE()
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +000057 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(MatrixTestImageFilter)
58
59protected:
robertphillips4ba94e22016-04-04 12:07:47 -070060 sk_sp<SkSpecialImage> onFilterImage(SkSpecialImage* source, const Context& ctx,
61 SkIPoint* offset) const override {
robertphillips43c2ad42016-04-04 05:05:11 -070062 REPORTER_ASSERT(fReporter, ctx.ctm() == fExpectedMatrix);
robertphillips4ba94e22016-04-04 12:07:47 -070063 offset->fX = offset->fY = 0;
64 return sk_ref_sp<SkSpecialImage>(source);
robertphillips43c2ad42016-04-04 05:05:11 -070065 }
66
mtklein36352bf2015-03-25 18:17:31 -070067 void flatten(SkWriteBuffer& buffer) const override {
brianosman18f13f32016-05-02 07:51:08 -070068 SkDEBUGFAIL("Should never get here");
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +000069 }
70
71private:
robertphillips43c2ad42016-04-04 05:05:11 -070072 MatrixTestImageFilter(skiatest::Reporter* reporter, const SkMatrix& expectedMatrix)
73 : INHERITED(nullptr, 0, nullptr)
74 , fReporter(reporter)
75 , fExpectedMatrix(expectedMatrix) {
76 }
77
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +000078 skiatest::Reporter* fReporter;
79 SkMatrix fExpectedMatrix;
mtklein3f3b3d02014-12-01 11:47:08 -080080
reed9fa60da2014-08-21 07:59:51 -070081 typedef SkImageFilter INHERITED;
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +000082};
83
senorblanco6a93fa12016-04-05 04:43:45 -070084class FailImageFilter : public SkImageFilter {
85public:
robertphillips6b134732016-04-15 09:58:37 -070086 FailImageFilter() : SkImageFilter(nullptr, 0, nullptr) { }
senorblanco6a93fa12016-04-05 04:43:45 -070087
88 sk_sp<SkSpecialImage> onFilterImage(SkSpecialImage* source,
89 const Context& ctx,
90 SkIPoint* offset) const override {
91 return nullptr;
92 }
93
94 SK_TO_STRING_OVERRIDE()
95 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(FailImageFilter)
96
97private:
98 typedef SkImageFilter INHERITED;
99};
100
101sk_sp<SkFlattenable> FailImageFilter::CreateProc(SkReadBuffer& buffer) {
102 SK_IMAGEFILTER_UNFLATTEN_COMMON(common, 0);
103 return sk_sp<SkFlattenable>(new FailImageFilter());
104}
105
106#ifndef SK_IGNORE_TO_STRING
107void FailImageFilter::toString(SkString* str) const {
108 str->appendf("FailImageFilter: (");
109 str->append(")");
110}
111#endif
112
senorblanco297f7ce2016-03-23 13:44:26 -0700113void draw_gradient_circle(SkCanvas* canvas, int width, int height) {
114 SkScalar x = SkIntToScalar(width / 2);
115 SkScalar y = SkIntToScalar(height / 2);
116 SkScalar radius = SkMinScalar(x, y) * 0.8f;
117 canvas->clear(0x00000000);
118 SkColor colors[2];
119 colors[0] = SK_ColorWHITE;
120 colors[1] = SK_ColorBLACK;
121 sk_sp<SkShader> shader(
122 SkGradientShader::MakeRadial(SkPoint::Make(x, y), radius, colors, nullptr, 2,
123 SkShader::kClamp_TileMode)
124 );
125 SkPaint paint;
126 paint.setShader(shader);
127 canvas->drawCircle(x, y, radius, paint);
128}
129
130SkBitmap make_gradient_circle(int width, int height) {
131 SkBitmap bitmap;
132 bitmap.allocN32Pixels(width, height);
133 SkCanvas canvas(bitmap);
134 draw_gradient_circle(&canvas, width, height);
135 return bitmap;
136}
137
138class FilterList {
139public:
robertphillipsfc11b0a2016-04-05 09:09:36 -0700140 FilterList(sk_sp<SkImageFilter> input, const SkImageFilter::CropRect* cropRect = nullptr) {
senorblanco297f7ce2016-03-23 13:44:26 -0700141 SkPoint3 location = SkPoint3::Make(0, 0, SK_Scalar1);
senorblanco297f7ce2016-03-23 13:44:26 -0700142 const SkScalar five = SkIntToScalar(5);
143
robertphillips6e7025a2016-04-04 04:31:25 -0700144 {
145 sk_sp<SkColorFilter> cf(SkColorFilter::MakeModeFilter(SK_ColorRED,
146 SkXfermode::kSrcIn_Mode));
senorblanco297f7ce2016-03-23 13:44:26 -0700147
robertphillips6e7025a2016-04-04 04:31:25 -0700148 this->addFilter("color filter",
robertphillips12fa47d2016-04-08 16:28:09 -0700149 SkColorFilterImageFilter::Make(std::move(cf), input, cropRect));
robertphillips6e7025a2016-04-04 04:31:25 -0700150 }
senorblanco297f7ce2016-03-23 13:44:26 -0700151
robertphillips6e7025a2016-04-04 04:31:25 -0700152 {
153 sk_sp<SkImage> gradientImage(SkImage::MakeFromBitmap(make_gradient_circle(64, 64)));
154 sk_sp<SkImageFilter> gradientSource(SkImageSource::Make(std::move(gradientImage)));
senorblanco297f7ce2016-03-23 13:44:26 -0700155
robertphillips12fa47d2016-04-08 16:28:09 -0700156 this->addFilter("displacement map",
robertphillipsbfe11fc2016-04-15 07:17:36 -0700157 SkDisplacementMapEffect::Make(SkDisplacementMapEffect::kR_ChannelSelectorType,
158 SkDisplacementMapEffect::kB_ChannelSelectorType,
159 20.0f,
160 std::move(gradientSource), input, cropRect));
robertphillips6e7025a2016-04-04 04:31:25 -0700161 }
senorblanco297f7ce2016-03-23 13:44:26 -0700162
robertphillips6e7025a2016-04-04 04:31:25 -0700163 this->addFilter("blur", SkBlurImageFilter::Make(SK_Scalar1,
164 SK_Scalar1,
robertphillipsfc11b0a2016-04-05 09:09:36 -0700165 input,
robertphillips12fa47d2016-04-08 16:28:09 -0700166 cropRect));
robertphillipsc4169122016-04-06 08:40:59 -0700167 this->addFilter("drop shadow", SkDropShadowImageFilter::Make(
senorblanco297f7ce2016-03-23 13:44:26 -0700168 SK_Scalar1, SK_Scalar1, SK_Scalar1, SK_Scalar1, SK_ColorGREEN,
robertphillipsfc11b0a2016-04-05 09:09:36 -0700169 SkDropShadowImageFilter::kDrawShadowAndForeground_ShadowMode,
robertphillips12fa47d2016-04-08 16:28:09 -0700170 input, cropRect));
171 this->addFilter("diffuse lighting",
172 SkLightingImageFilter::MakePointLitDiffuse(location, SK_ColorGREEN, 0, 0,
173 input, cropRect));
senorblanco297f7ce2016-03-23 13:44:26 -0700174 this->addFilter("specular lighting",
robertphillips12fa47d2016-04-08 16:28:09 -0700175 SkLightingImageFilter::MakePointLitSpecular(location, SK_ColorGREEN, 0, 0, 0,
176 input, cropRect));
177 {
178 SkScalar kernel[9] = {
179 SkIntToScalar(1), SkIntToScalar(1), SkIntToScalar(1),
180 SkIntToScalar(1), SkIntToScalar(-7), SkIntToScalar(1),
181 SkIntToScalar(1), SkIntToScalar(1), SkIntToScalar(1),
182 };
183 const SkISize kernelSize = SkISize::Make(3, 3);
184 const SkScalar gain = SK_Scalar1, bias = 0;
185
186 this->addFilter("matrix convolution",
robertphillipsef6a47b2016-04-08 08:01:20 -0700187 SkMatrixConvolutionImageFilter::Make(
senorblanco297f7ce2016-03-23 13:44:26 -0700188 kernelSize, kernel, gain, bias, SkIPoint::Make(1, 1),
robertphillipsfc11b0a2016-04-05 09:09:36 -0700189 SkMatrixConvolutionImageFilter::kRepeat_TileMode, false,
robertphillips12fa47d2016-04-08 16:28:09 -0700190 input, cropRect));
191 }
192
robertphillipsfc11b0a2016-04-05 09:09:36 -0700193 this->addFilter("merge", SkMergeImageFilter::Make(input, input,
robertphillips2238c9d2016-03-30 13:34:16 -0700194 SkXfermode::kSrcOver_Mode,
robertphillips12fa47d2016-04-08 16:28:09 -0700195 cropRect));
196
robertphillips6e7025a2016-04-04 04:31:25 -0700197 {
198 SkPaint greenColorShaderPaint;
199 greenColorShaderPaint.setShader(SkShader::MakeColorShader(SK_ColorGREEN));
200
201 SkImageFilter::CropRect leftSideCropRect(SkRect::MakeXYWH(0, 0, 32, 64));
202 sk_sp<SkImageFilter> paintFilterLeft(SkPaintImageFilter::Make(greenColorShaderPaint,
203 &leftSideCropRect));
204 SkImageFilter::CropRect rightSideCropRect(SkRect::MakeXYWH(32, 0, 32, 64));
205 sk_sp<SkImageFilter> paintFilterRight(SkPaintImageFilter::Make(greenColorShaderPaint,
206 &rightSideCropRect));
207
208
209 this->addFilter("merge with disjoint inputs", SkMergeImageFilter::Make(
robertphillips2238c9d2016-03-30 13:34:16 -0700210 std::move(paintFilterLeft), std::move(paintFilterRight),
robertphillips12fa47d2016-04-08 16:28:09 -0700211 SkXfermode::kSrcOver_Mode, cropRect));
robertphillips6e7025a2016-04-04 04:31:25 -0700212 }
213
senorblanco297f7ce2016-03-23 13:44:26 -0700214 this->addFilter("offset",
robertphillipsfc11b0a2016-04-05 09:09:36 -0700215 SkOffsetImageFilter::Make(SK_Scalar1, SK_Scalar1, input,
robertphillips12fa47d2016-04-08 16:28:09 -0700216 cropRect));
217 this->addFilter("dilate", SkDilateImageFilter::Make(3, 2, input, cropRect));
218 this->addFilter("erode", SkErodeImageFilter::Make(2, 3, input, cropRect));
robertphillips534c2702016-04-15 07:57:40 -0700219 this->addFilter("tile", SkTileImageFilter::Make(
220 SkRect::MakeXYWH(0, 0, 50, 50),
221 cropRect ? cropRect->rect() : SkRect::MakeXYWH(0, 0, 100, 100),
222 input));
robertphillips6e7025a2016-04-04 04:31:25 -0700223
robertphillips12fa47d2016-04-08 16:28:09 -0700224 if (!cropRect) {
225 SkMatrix matrix;
226
227 matrix.setTranslate(SK_Scalar1, SK_Scalar1);
228 matrix.postRotate(SkIntToScalar(45), SK_Scalar1, SK_Scalar1);
229
230 this->addFilter("matrix",
231 SkImageFilter::MakeMatrixFilter(matrix, kLow_SkFilterQuality, input));
232 }
robertphillips6e7025a2016-04-04 04:31:25 -0700233 {
robertphillipsfc11b0a2016-04-05 09:09:36 -0700234 sk_sp<SkImageFilter> blur(SkBlurImageFilter::Make(five, five, input));
robertphillips6e7025a2016-04-04 04:31:25 -0700235
236 this->addFilter("blur and offset", SkOffsetImageFilter::Make(five, five,
237 std::move(blur),
robertphillips12fa47d2016-04-08 16:28:09 -0700238 cropRect));
robertphillips6e7025a2016-04-04 04:31:25 -0700239 }
240 {
241 SkRTreeFactory factory;
242 SkPictureRecorder recorder;
243 SkCanvas* recordingCanvas = recorder.beginRecording(64, 64, &factory, 0);
244
245 SkPaint greenPaint;
246 greenPaint.setColor(SK_ColorGREEN);
247 recordingCanvas->drawRect(SkRect::Make(SkIRect::MakeXYWH(10, 10, 30, 20)), greenPaint);
248 sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture());
249 sk_sp<SkImageFilter> pictureFilter(SkPictureImageFilter::Make(std::move(picture)));
250
251 this->addFilter("picture and blur", SkBlurImageFilter::Make(five, five,
252 std::move(pictureFilter),
robertphillips12fa47d2016-04-08 16:28:09 -0700253 cropRect));
robertphillips6e7025a2016-04-04 04:31:25 -0700254 }
255 {
256 SkPaint paint;
257 paint.setShader(SkPerlinNoiseShader::MakeTurbulence(SK_Scalar1, SK_Scalar1, 1, 0));
258 sk_sp<SkImageFilter> paintFilter(SkPaintImageFilter::Make(paint));
259
260 this->addFilter("paint and blur", SkBlurImageFilter::Make(five, five,
261 std::move(paintFilter),
robertphillips12fa47d2016-04-08 16:28:09 -0700262 cropRect));
robertphillips6e7025a2016-04-04 04:31:25 -0700263 }
reedcfb6bdf2016-03-29 11:32:50 -0700264 this->addFilter("xfermode", SkXfermodeImageFilter::Make(
robertphillips12fa47d2016-04-08 16:28:09 -0700265 SkXfermode::Make(SkXfermode::kSrc_Mode), input, input, cropRect));
senorblanco297f7ce2016-03-23 13:44:26 -0700266 }
267 int count() const { return fFilters.count(); }
268 SkImageFilter* getFilter(int index) const { return fFilters[index].fFilter.get(); }
269 const char* getName(int index) const { return fFilters[index].fName; }
270private:
271 struct Filter {
robertphillips12fa47d2016-04-08 16:28:09 -0700272 Filter() : fName(nullptr) {}
273 Filter(const char* name, sk_sp<SkImageFilter> filter)
274 : fName(name)
275 , fFilter(std::move(filter)) {
276 }
senorblanco297f7ce2016-03-23 13:44:26 -0700277 const char* fName;
278 sk_sp<SkImageFilter> fFilter;
279 };
robertphillips12fa47d2016-04-08 16:28:09 -0700280 void addFilter(const char* name, sk_sp<SkImageFilter> filter) {
281 fFilters.push_back(Filter(name, std::move(filter)));
senorblanco297f7ce2016-03-23 13:44:26 -0700282 }
283
284 SkTArray<Filter> fFilters;
285};
286
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +0000287}
288
reed60c9b582016-04-03 09:11:13 -0700289sk_sp<SkFlattenable> MatrixTestImageFilter::CreateProc(SkReadBuffer& buffer) {
brianosman18f13f32016-05-02 07:51:08 -0700290 SkDEBUGFAIL("Should never get here");
291 return nullptr;
reed9fa60da2014-08-21 07:59:51 -0700292}
293
robertphillipsf3f5bad2014-12-19 13:49:15 -0800294#ifndef SK_IGNORE_TO_STRING
295void MatrixTestImageFilter::toString(SkString* str) const {
296 str->appendf("MatrixTestImageFilter: (");
297 str->append(")");
298}
299#endif
300
reed9ce9d672016-03-17 10:51:11 -0700301static sk_sp<SkImage> make_small_image() {
reede8f30622016-03-23 18:59:25 -0700302 auto surface(SkSurface::MakeRasterN32Premul(kBitmapSize, kBitmapSize));
fmalita5598b632015-09-15 11:26:13 -0700303 SkCanvas* canvas = surface->getCanvas();
304 canvas->clear(0x00000000);
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000305 SkPaint darkPaint;
306 darkPaint.setColor(0xFF804020);
307 SkPaint lightPaint;
308 lightPaint.setColor(0xFF244484);
309 const int i = kBitmapSize / 4;
310 for (int y = 0; y < kBitmapSize; y += i) {
311 for (int x = 0; x < kBitmapSize; x += i) {
fmalita5598b632015-09-15 11:26:13 -0700312 canvas->save();
313 canvas->translate(SkIntToScalar(x), SkIntToScalar(y));
314 canvas->drawRect(SkRect::MakeXYWH(0, 0,
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000315 SkIntToScalar(i),
316 SkIntToScalar(i)), darkPaint);
fmalita5598b632015-09-15 11:26:13 -0700317 canvas->drawRect(SkRect::MakeXYWH(SkIntToScalar(i),
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000318 0,
319 SkIntToScalar(i),
320 SkIntToScalar(i)), lightPaint);
fmalita5598b632015-09-15 11:26:13 -0700321 canvas->drawRect(SkRect::MakeXYWH(0,
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000322 SkIntToScalar(i),
323 SkIntToScalar(i),
324 SkIntToScalar(i)), lightPaint);
fmalita5598b632015-09-15 11:26:13 -0700325 canvas->drawRect(SkRect::MakeXYWH(SkIntToScalar(i),
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000326 SkIntToScalar(i),
327 SkIntToScalar(i),
328 SkIntToScalar(i)), darkPaint);
fmalita5598b632015-09-15 11:26:13 -0700329 canvas->restore();
commit-bot@chromium.org4b681bc2013-09-13 12:40:02 +0000330 }
331 }
fmalita5598b632015-09-15 11:26:13 -0700332
reed9ce9d672016-03-17 10:51:11 -0700333 return surface->makeImageSnapshot();
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000334}
senorblanco@chromium.org194d7752013-07-24 22:19:24 +0000335
robertphillips5605b562016-04-05 11:50:42 -0700336static sk_sp<SkImageFilter> make_scale(float amount, sk_sp<SkImageFilter> input) {
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000337 SkScalar s = amount;
338 SkScalar matrix[20] = { s, 0, 0, 0, 0,
339 0, s, 0, 0, 0,
340 0, 0, s, 0, 0,
341 0, 0, 0, s, 0 };
robertphillips5605b562016-04-05 11:50:42 -0700342 sk_sp<SkColorFilter> filter(SkColorFilter::MakeMatrixFilterRowMajor255(matrix));
343 return SkColorFilterImageFilter::Make(std::move(filter), std::move(input));
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000344}
345
robertphillips5605b562016-04-05 11:50:42 -0700346static sk_sp<SkImageFilter> make_grayscale(sk_sp<SkImageFilter> input,
347 const SkImageFilter::CropRect* cropRect) {
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000348 SkScalar matrix[20];
349 memset(matrix, 0, 20 * sizeof(SkScalar));
350 matrix[0] = matrix[5] = matrix[10] = 0.2126f;
351 matrix[1] = matrix[6] = matrix[11] = 0.7152f;
352 matrix[2] = matrix[7] = matrix[12] = 0.0722f;
353 matrix[18] = 1.0f;
robertphillips5605b562016-04-05 11:50:42 -0700354 sk_sp<SkColorFilter> filter(SkColorFilter::MakeMatrixFilterRowMajor255(matrix));
355 return SkColorFilterImageFilter::Make(std::move(filter), std::move(input), cropRect);
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000356}
357
robertphillips5605b562016-04-05 11:50:42 -0700358static sk_sp<SkImageFilter> make_blue(sk_sp<SkImageFilter> input,
359 const SkImageFilter::CropRect* cropRect) {
360 sk_sp<SkColorFilter> filter(SkColorFilter::MakeModeFilter(SK_ColorBLUE,
361 SkXfermode::kSrcIn_Mode));
362 return SkColorFilterImageFilter::Make(std::move(filter), std::move(input), cropRect);
reedcedc36f2015-03-08 04:42:52 -0700363}
364
robertphillips3e302272016-04-20 11:48:36 -0700365static sk_sp<SkSpecialSurface> create_empty_special_surface(GrContext* context, int widthHeight) {
robertphillipsc91fd342016-04-25 12:32:54 -0700366#if SK_SUPPORT_GPU
robertphillips4418dba2016-03-07 12:45:14 -0800367 if (context) {
robertphillips4df16562016-04-28 15:09:34 -0700368 return SkSpecialSurface::MakeRenderTarget(context,
369 widthHeight, widthHeight,
370 kSkia8888_GrPixelConfig);
robertphillipsc91fd342016-04-25 12:32:54 -0700371 } else
372#endif
373 {
robertphillips4418dba2016-03-07 12:45:14 -0800374 const SkImageInfo info = SkImageInfo::MakeN32(widthHeight, widthHeight,
375 kOpaque_SkAlphaType);
robertphillips3e302272016-04-20 11:48:36 -0700376 return SkSpecialSurface::MakeRaster(info);
robertphillips4418dba2016-03-07 12:45:14 -0800377 }
senorblancobf680c32016-03-16 16:15:53 -0700378}
379
senorblanco5878dbd2016-05-19 14:50:29 -0700380static sk_sp<SkSurface> create_surface(GrContext* context, int width, int height) {
381 const SkImageInfo info = SkImageInfo::MakeN32(width, height, kOpaque_SkAlphaType);
382#if SK_SUPPORT_GPU
383 if (context) {
384 return SkSurface::MakeRenderTarget(context, SkBudgeted::kNo, info);
385 } else
386#endif
387 {
388 return SkSurface::MakeRaster(info);
389 }
390}
391
robertphillips3e302272016-04-20 11:48:36 -0700392static sk_sp<SkSpecialImage> create_empty_special_image(GrContext* context, int widthHeight) {
393 sk_sp<SkSpecialSurface> surf(create_empty_special_surface(context, widthHeight));
robertphillips4418dba2016-03-07 12:45:14 -0800394
395 SkASSERT(surf);
396
397 SkCanvas* canvas = surf->getCanvas();
398 SkASSERT(canvas);
399
400 canvas->clear(0x0);
401
robertphillips37bd7c32016-03-17 14:31:39 -0700402 return surf->makeImageSnapshot();
robertphillips4418dba2016-03-07 12:45:14 -0800403}
404
405
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000406DEF_TEST(ImageFilter, reporter) {
407 {
reedcedc36f2015-03-08 04:42:52 -0700408 // Check that two non-clipping color-matrice-filters concatenate into a single filter.
robertphillips5605b562016-04-05 11:50:42 -0700409 sk_sp<SkImageFilter> halfBrightness(make_scale(0.5f, nullptr));
410 sk_sp<SkImageFilter> quarterBrightness(make_scale(0.5f, std::move(halfBrightness)));
halcanary96fcdcc2015-08-27 07:41:13 -0700411 REPORTER_ASSERT(reporter, nullptr == quarterBrightness->getInput(0));
reedcedc36f2015-03-08 04:42:52 -0700412 SkColorFilter* cf;
413 REPORTER_ASSERT(reporter, quarterBrightness->asColorFilter(&cf));
halcanary96fcdcc2015-08-27 07:41:13 -0700414 REPORTER_ASSERT(reporter, cf->asColorMatrix(nullptr));
reedcedc36f2015-03-08 04:42:52 -0700415 cf->unref();
senorblanco@chromium.org194d7752013-07-24 22:19:24 +0000416 }
417
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000418 {
reedcedc36f2015-03-08 04:42:52 -0700419 // Check that a clipping color-matrice-filter followed by a color-matrice-filters
420 // concatenates into a single filter, but not a matrixfilter (due to clamping).
robertphillips5605b562016-04-05 11:50:42 -0700421 sk_sp<SkImageFilter> doubleBrightness(make_scale(2.0f, nullptr));
422 sk_sp<SkImageFilter> halfBrightness(make_scale(0.5f, std::move(doubleBrightness)));
halcanary96fcdcc2015-08-27 07:41:13 -0700423 REPORTER_ASSERT(reporter, nullptr == halfBrightness->getInput(0));
reedcedc36f2015-03-08 04:42:52 -0700424 SkColorFilter* cf;
425 REPORTER_ASSERT(reporter, halfBrightness->asColorFilter(&cf));
halcanary96fcdcc2015-08-27 07:41:13 -0700426 REPORTER_ASSERT(reporter, !cf->asColorMatrix(nullptr));
reedcedc36f2015-03-08 04:42:52 -0700427 cf->unref();
senorblanco@chromium.org194d7752013-07-24 22:19:24 +0000428 }
429
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000430 {
431 // Check that a color filter image filter without a crop rect can be
432 // expressed as a color filter.
robertphillips5605b562016-04-05 11:50:42 -0700433 sk_sp<SkImageFilter> gray(make_grayscale(nullptr, nullptr));
halcanary96fcdcc2015-08-27 07:41:13 -0700434 REPORTER_ASSERT(reporter, true == gray->asColorFilter(nullptr));
senorblanco@chromium.org194d7752013-07-24 22:19:24 +0000435 }
mtklein2afbe232016-02-07 12:23:10 -0800436
reedcedc36f2015-03-08 04:42:52 -0700437 {
438 // Check that a colorfilterimage filter without a crop rect but with an input
439 // that is another colorfilterimage can be expressed as a colorfilter (composed).
robertphillips5605b562016-04-05 11:50:42 -0700440 sk_sp<SkImageFilter> mode(make_blue(nullptr, nullptr));
441 sk_sp<SkImageFilter> gray(make_grayscale(std::move(mode), nullptr));
halcanary96fcdcc2015-08-27 07:41:13 -0700442 REPORTER_ASSERT(reporter, true == gray->asColorFilter(nullptr));
reedcedc36f2015-03-08 04:42:52 -0700443 }
444
445 {
446 // Test that if we exceed the limit of what ComposeColorFilter can combine, we still
447 // can build the DAG and won't assert if we call asColorFilter.
robertphillips5605b562016-04-05 11:50:42 -0700448 sk_sp<SkImageFilter> filter(make_blue(nullptr, nullptr));
reedcedc36f2015-03-08 04:42:52 -0700449 const int kWayTooManyForComposeColorFilter = 100;
450 for (int i = 0; i < kWayTooManyForComposeColorFilter; ++i) {
robertphillips5605b562016-04-05 11:50:42 -0700451 filter = make_blue(filter, nullptr);
reedcedc36f2015-03-08 04:42:52 -0700452 // the first few of these will succeed, but after we hit the internal limit,
453 // it will then return false.
halcanary96fcdcc2015-08-27 07:41:13 -0700454 (void)filter->asColorFilter(nullptr);
reedcedc36f2015-03-08 04:42:52 -0700455 }
456 }
reed5c518a82015-03-05 14:47:29 -0800457
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000458 {
459 // Check that a color filter image filter with a crop rect cannot
460 // be expressed as a color filter.
461 SkImageFilter::CropRect cropRect(SkRect::MakeXYWH(0, 0, 100, 100));
robertphillips5605b562016-04-05 11:50:42 -0700462 sk_sp<SkImageFilter> grayWithCrop(make_grayscale(nullptr, &cropRect));
halcanary96fcdcc2015-08-27 07:41:13 -0700463 REPORTER_ASSERT(reporter, false == grayWithCrop->asColorFilter(nullptr));
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000464 }
465
466 {
senorblanco3df05012014-07-03 11:13:09 -0700467 // Check that two non-commutative matrices are concatenated in
468 // the correct order.
469 SkScalar blueToRedMatrix[20] = { 0 };
470 blueToRedMatrix[2] = blueToRedMatrix[18] = SK_Scalar1;
471 SkScalar redToGreenMatrix[20] = { 0 };
472 redToGreenMatrix[5] = redToGreenMatrix[18] = SK_Scalar1;
robertphillips5605b562016-04-05 11:50:42 -0700473 sk_sp<SkColorFilter> blueToRed(SkColorFilter::MakeMatrixFilterRowMajor255(blueToRedMatrix));
474 sk_sp<SkImageFilter> filter1(SkColorFilterImageFilter::Make(std::move(blueToRed),
475 nullptr));
476 sk_sp<SkColorFilter> redToGreen(SkColorFilter::MakeMatrixFilterRowMajor255(redToGreenMatrix));
477 sk_sp<SkImageFilter> filter2(SkColorFilterImageFilter::Make(std::move(redToGreen),
478 std::move(filter1)));
senorblanco3df05012014-07-03 11:13:09 -0700479
480 SkBitmap result;
481 result.allocN32Pixels(kBitmapSize, kBitmapSize);
482
483 SkPaint paint;
484 paint.setColor(SK_ColorBLUE);
robertphillips5605b562016-04-05 11:50:42 -0700485 paint.setImageFilter(std::move(filter2));
senorblanco3df05012014-07-03 11:13:09 -0700486 SkCanvas canvas(result);
487 canvas.clear(0x0);
488 SkRect rect = SkRect::Make(SkIRect::MakeWH(kBitmapSize, kBitmapSize));
489 canvas.drawRect(rect, paint);
490 uint32_t pixel = *result.getAddr32(0, 0);
491 // The result here should be green, since we have effectively shifted blue to green.
492 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
493 }
494
495 {
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000496 // Tests pass by not asserting
reed9ce9d672016-03-17 10:51:11 -0700497 sk_sp<SkImage> image(make_small_image());
fmalita5598b632015-09-15 11:26:13 -0700498 SkBitmap result;
mike@reedtribe.orgdeee4962014-02-13 14:41:43 +0000499 result.allocN32Pixels(kBitmapSize, kBitmapSize);
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000500
senorblanco@chromium.org194d7752013-07-24 22:19:24 +0000501 {
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000502 // This tests for :
503 // 1 ) location at (0,0,1)
robertphillips3d32d762015-07-13 13:16:44 -0700504 SkPoint3 location = SkPoint3::Make(0, 0, SK_Scalar1);
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000505 // 2 ) location and target at same value
robertphillips3d32d762015-07-13 13:16:44 -0700506 SkPoint3 target = SkPoint3::Make(location.fX, location.fY, location.fZ);
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000507 // 3 ) large negative specular exponent value
508 SkScalar specularExponent = -1000;
509
robertphillips549c8992016-04-01 09:28:51 -0700510 sk_sp<SkImageFilter> bmSrc(SkImageSource::Make(std::move(image)));
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000511 SkPaint paint;
robertphillips12fa47d2016-04-08 16:28:09 -0700512 paint.setImageFilter(SkLightingImageFilter::MakeSpotLitSpecular(
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000513 location, target, specularExponent, 180,
514 0xFFFFFFFF, SK_Scalar1, SK_Scalar1, SK_Scalar1,
robertphillips12fa47d2016-04-08 16:28:09 -0700515 std::move(bmSrc)));
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000516 SkCanvas canvas(result);
517 SkRect r = SkRect::MakeWH(SkIntToScalar(kBitmapSize),
518 SkIntToScalar(kBitmapSize));
519 canvas.drawRect(r, paint);
senorblanco@chromium.org194d7752013-07-24 22:19:24 +0000520 }
senorblanco@chromium.org194d7752013-07-24 22:19:24 +0000521 }
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +0000522}
senorblanco@chromium.org6776b822014-01-03 21:48:22 +0000523
robertphillips3e302272016-04-20 11:48:36 -0700524static void test_crop_rects(skiatest::Reporter* reporter,
robertphillips4418dba2016-03-07 12:45:14 -0800525 GrContext* context) {
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +0000526 // Check that all filters offset to their absolute crop rect,
527 // unaffected by the input crop rect.
528 // Tests pass by not asserting.
robertphillips3e302272016-04-20 11:48:36 -0700529 sk_sp<SkSpecialImage> srcImg(create_empty_special_image(context, 100));
robertphillips4418dba2016-03-07 12:45:14 -0800530 SkASSERT(srcImg);
senorblanco@chromium.org6776b822014-01-03 21:48:22 +0000531
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +0000532 SkImageFilter::CropRect inputCropRect(SkRect::MakeXYWH(8, 13, 80, 80));
533 SkImageFilter::CropRect cropRect(SkRect::MakeXYWH(20, 30, 60, 60));
robertphillipsfc11b0a2016-04-05 09:09:36 -0700534 sk_sp<SkImageFilter> input(make_grayscale(nullptr, &inputCropRect));
senorblanco@chromium.org6776b822014-01-03 21:48:22 +0000535
robertphillipsfc11b0a2016-04-05 09:09:36 -0700536 FilterList filters(input, &cropRect);
senorblanco@chromium.org6776b822014-01-03 21:48:22 +0000537
senorblanco297f7ce2016-03-23 13:44:26 -0700538 for (int i = 0; i < filters.count(); ++i) {
539 SkImageFilter* filter = filters.getFilter(i);
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +0000540 SkIPoint offset;
reed4e23cda2016-01-11 10:56:59 -0800541 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeWH(100, 100), nullptr);
robertphillips2302de92016-03-24 07:26:32 -0700542 sk_sp<SkSpecialImage> resultImg(filter->filterImage(srcImg.get(), ctx, &offset));
senorblanco297f7ce2016-03-23 13:44:26 -0700543 REPORTER_ASSERT_MESSAGE(reporter, resultImg, filters.getName(i));
544 REPORTER_ASSERT_MESSAGE(reporter, offset.fX == 20 && offset.fY == 30, filters.getName(i));
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +0000545 }
546}
547
robertphillips3e302272016-04-20 11:48:36 -0700548static void test_negative_blur_sigma(skiatest::Reporter* reporter,
robertphillips4418dba2016-03-07 12:45:14 -0800549 GrContext* context) {
senorblanco32673b92014-09-09 09:15:04 -0700550 // Check that SkBlurImageFilter will accept a negative sigma, either in
551 // the given arguments or after CTM application.
reed5ea95df2015-10-06 14:05:32 -0700552 const int width = 32, height = 32;
553 const SkScalar five = SkIntToScalar(5);
senorblanco32673b92014-09-09 09:15:04 -0700554
robertphillips6e7025a2016-04-04 04:31:25 -0700555 sk_sp<SkImageFilter> positiveFilter(SkBlurImageFilter::Make(five, five, nullptr));
556 sk_sp<SkImageFilter> negativeFilter(SkBlurImageFilter::Make(-five, five, nullptr));
senorblanco32673b92014-09-09 09:15:04 -0700557
558 SkBitmap gradient = make_gradient_circle(width, height);
robertphillips3e302272016-04-20 11:48:36 -0700559 sk_sp<SkSpecialImage> imgSrc(SkSpecialImage::MakeFromRaster(SkIRect::MakeWH(width, height),
robertphillips37bd7c32016-03-17 14:31:39 -0700560 gradient));
robertphillips4418dba2016-03-07 12:45:14 -0800561
senorblanco32673b92014-09-09 09:15:04 -0700562 SkIPoint offset;
reed4e23cda2016-01-11 10:56:59 -0800563 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeWH(32, 32), nullptr);
robertphillips4418dba2016-03-07 12:45:14 -0800564
robertphillips2302de92016-03-24 07:26:32 -0700565 sk_sp<SkSpecialImage> positiveResult1(positiveFilter->filterImage(imgSrc.get(), ctx, &offset));
robertphillips4418dba2016-03-07 12:45:14 -0800566 REPORTER_ASSERT(reporter, positiveResult1);
567
robertphillips2302de92016-03-24 07:26:32 -0700568 sk_sp<SkSpecialImage> negativeResult1(negativeFilter->filterImage(imgSrc.get(), ctx, &offset));
robertphillips4418dba2016-03-07 12:45:14 -0800569 REPORTER_ASSERT(reporter, negativeResult1);
570
senorblanco32673b92014-09-09 09:15:04 -0700571 SkMatrix negativeScale;
572 negativeScale.setScale(-SK_Scalar1, SK_Scalar1);
reed4e23cda2016-01-11 10:56:59 -0800573 SkImageFilter::Context negativeCTX(negativeScale, SkIRect::MakeWH(32, 32), nullptr);
robertphillips4418dba2016-03-07 12:45:14 -0800574
robertphillips2302de92016-03-24 07:26:32 -0700575 sk_sp<SkSpecialImage> negativeResult2(positiveFilter->filterImage(imgSrc.get(),
576 negativeCTX,
577 &offset));
robertphillips4418dba2016-03-07 12:45:14 -0800578 REPORTER_ASSERT(reporter, negativeResult2);
579
robertphillips2302de92016-03-24 07:26:32 -0700580 sk_sp<SkSpecialImage> positiveResult2(negativeFilter->filterImage(imgSrc.get(),
581 negativeCTX,
582 &offset));
robertphillips4418dba2016-03-07 12:45:14 -0800583 REPORTER_ASSERT(reporter, positiveResult2);
584
585
586 SkBitmap positiveResultBM1, positiveResultBM2;
587 SkBitmap negativeResultBM1, negativeResultBM2;
588
robertphillips64612512016-04-08 12:10:42 -0700589 REPORTER_ASSERT(reporter, positiveResult1->getROPixels(&positiveResultBM1));
590 REPORTER_ASSERT(reporter, positiveResult2->getROPixels(&positiveResultBM2));
591 REPORTER_ASSERT(reporter, negativeResult1->getROPixels(&negativeResultBM1));
592 REPORTER_ASSERT(reporter, negativeResult2->getROPixels(&negativeResultBM2));
robertphillips4418dba2016-03-07 12:45:14 -0800593
594 SkAutoLockPixels lockP1(positiveResultBM1);
595 SkAutoLockPixels lockP2(positiveResultBM2);
596 SkAutoLockPixels lockN1(negativeResultBM1);
597 SkAutoLockPixels lockN2(negativeResultBM2);
senorblanco32673b92014-09-09 09:15:04 -0700598 for (int y = 0; y < height; y++) {
robertphillips4418dba2016-03-07 12:45:14 -0800599 int diffs = memcmp(positiveResultBM1.getAddr32(0, y),
600 negativeResultBM1.getAddr32(0, y),
601 positiveResultBM1.rowBytes());
senorblanco32673b92014-09-09 09:15:04 -0700602 REPORTER_ASSERT(reporter, !diffs);
603 if (diffs) {
604 break;
605 }
robertphillips4418dba2016-03-07 12:45:14 -0800606 diffs = memcmp(positiveResultBM1.getAddr32(0, y),
607 negativeResultBM2.getAddr32(0, y),
608 positiveResultBM1.rowBytes());
senorblanco32673b92014-09-09 09:15:04 -0700609 REPORTER_ASSERT(reporter, !diffs);
610 if (diffs) {
611 break;
612 }
robertphillips4418dba2016-03-07 12:45:14 -0800613 diffs = memcmp(positiveResultBM1.getAddr32(0, y),
614 positiveResultBM2.getAddr32(0, y),
615 positiveResultBM1.rowBytes());
senorblanco32673b92014-09-09 09:15:04 -0700616 REPORTER_ASSERT(reporter, !diffs);
617 if (diffs) {
618 break;
619 }
620 }
621}
622
senorblanco21a465d2016-04-11 11:58:39 -0700623DEF_TEST(ImageFilterNegativeBlurSigma, reporter) {
robertphillips3e302272016-04-20 11:48:36 -0700624 test_negative_blur_sigma(reporter, nullptr);
robertphillips4418dba2016-03-07 12:45:14 -0800625}
626
627#if SK_SUPPORT_GPU
bsalomon68d91342016-04-12 09:59:58 -0700628DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterNegativeBlurSigma_Gpu, reporter, ctxInfo) {
bsalomon8b7451a2016-05-11 06:33:06 -0700629 test_negative_blur_sigma(reporter, ctxInfo.grContext());
robertphillips4418dba2016-03-07 12:45:14 -0800630}
631#endif
632
robertphillips3e302272016-04-20 11:48:36 -0700633static void test_zero_blur_sigma(skiatest::Reporter* reporter, GrContext* context) {
senorblancobf680c32016-03-16 16:15:53 -0700634 // Check that SkBlurImageFilter with a zero sigma and a non-zero srcOffset works correctly.
635 SkImageFilter::CropRect cropRect(SkRect::Make(SkIRect::MakeXYWH(5, 0, 5, 10)));
robertphillips51a315e2016-03-31 09:05:49 -0700636 sk_sp<SkImageFilter> input(SkOffsetImageFilter::Make(0, 0, nullptr, &cropRect));
robertphillips6e7025a2016-04-04 04:31:25 -0700637 sk_sp<SkImageFilter> filter(SkBlurImageFilter::Make(0, 0, std::move(input), &cropRect));
senorblancobf680c32016-03-16 16:15:53 -0700638
robertphillips3e302272016-04-20 11:48:36 -0700639 sk_sp<SkSpecialSurface> surf(create_empty_special_surface(context, 10));
senorblancobf680c32016-03-16 16:15:53 -0700640 surf->getCanvas()->clear(SK_ColorGREEN);
robertphillips37bd7c32016-03-17 14:31:39 -0700641 sk_sp<SkSpecialImage> image(surf->makeImageSnapshot());
senorblancobf680c32016-03-16 16:15:53 -0700642
643 SkIPoint offset;
644 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeWH(32, 32), nullptr);
645
robertphillips2302de92016-03-24 07:26:32 -0700646 sk_sp<SkSpecialImage> result(filter->filterImage(image.get(), ctx, &offset));
senorblancobf680c32016-03-16 16:15:53 -0700647 REPORTER_ASSERT(reporter, offset.fX == 5 && offset.fY == 0);
648 REPORTER_ASSERT(reporter, result);
649 REPORTER_ASSERT(reporter, result->width() == 5 && result->height() == 10);
650
651 SkBitmap resultBM;
652
robertphillips64612512016-04-08 12:10:42 -0700653 REPORTER_ASSERT(reporter, result->getROPixels(&resultBM));
senorblancobf680c32016-03-16 16:15:53 -0700654
655 SkAutoLockPixels lock(resultBM);
656 for (int y = 0; y < resultBM.height(); y++) {
657 for (int x = 0; x < resultBM.width(); x++) {
658 bool diff = *resultBM.getAddr32(x, y) != SK_ColorGREEN;
659 REPORTER_ASSERT(reporter, !diff);
660 if (diff) {
661 break;
662 }
663 }
664 }
665}
666
senorblanco21a465d2016-04-11 11:58:39 -0700667DEF_TEST(ImageFilterZeroBlurSigma, reporter) {
robertphillips3e302272016-04-20 11:48:36 -0700668 test_zero_blur_sigma(reporter, nullptr);
senorblancobf680c32016-03-16 16:15:53 -0700669}
670
671#if SK_SUPPORT_GPU
bsalomon68d91342016-04-12 09:59:58 -0700672DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterZeroBlurSigma_Gpu, reporter, ctxInfo) {
bsalomon8b7451a2016-05-11 06:33:06 -0700673 test_zero_blur_sigma(reporter, ctxInfo.grContext());
senorblancobf680c32016-03-16 16:15:53 -0700674}
675#endif
676
senorblanco6a93fa12016-04-05 04:43:45 -0700677
678// Tests that, even when an upstream filter has returned null (due to failure or clipping), a
679// downstream filter that affects transparent black still does so even with a nullptr input.
robertphillips3e302272016-04-20 11:48:36 -0700680static void test_fail_affects_transparent_black(skiatest::Reporter* reporter, GrContext* context) {
senorblanco6a93fa12016-04-05 04:43:45 -0700681 sk_sp<FailImageFilter> failFilter(new FailImageFilter());
robertphillips3e302272016-04-20 11:48:36 -0700682 sk_sp<SkSpecialImage> source(create_empty_special_image(context, 5));
senorblanco6a93fa12016-04-05 04:43:45 -0700683 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeXYWH(0, 0, 1, 1), nullptr);
684 sk_sp<SkColorFilter> green(SkColorFilter::MakeModeFilter(SK_ColorGREEN, SkXfermode::kSrc_Mode));
685 SkASSERT(green->affectsTransparentBlack());
robertphillips5605b562016-04-05 11:50:42 -0700686 sk_sp<SkImageFilter> greenFilter(SkColorFilterImageFilter::Make(std::move(green),
687 std::move(failFilter)));
senorblanco6a93fa12016-04-05 04:43:45 -0700688 SkIPoint offset;
689 sk_sp<SkSpecialImage> result(greenFilter->filterImage(source.get(), ctx, &offset));
690 REPORTER_ASSERT(reporter, nullptr != result.get());
691 if (result.get()) {
692 SkBitmap resultBM;
robertphillips64612512016-04-08 12:10:42 -0700693 REPORTER_ASSERT(reporter, result->getROPixels(&resultBM));
senorblanco6a93fa12016-04-05 04:43:45 -0700694 SkAutoLockPixels lock(resultBM);
695 REPORTER_ASSERT(reporter, *resultBM.getAddr32(0, 0) == SK_ColorGREEN);
696 }
697}
698
699DEF_TEST(ImageFilterFailAffectsTransparentBlack, reporter) {
robertphillips3e302272016-04-20 11:48:36 -0700700 test_fail_affects_transparent_black(reporter, nullptr);
senorblanco6a93fa12016-04-05 04:43:45 -0700701}
702
703#if SK_SUPPORT_GPU
bsalomon68d91342016-04-12 09:59:58 -0700704DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterFailAffectsTransparentBlack_Gpu, reporter, ctxInfo) {
bsalomon8b7451a2016-05-11 06:33:06 -0700705 test_fail_affects_transparent_black(reporter, ctxInfo.grContext());
senorblanco6a93fa12016-04-05 04:43:45 -0700706}
707#endif
708
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +0000709DEF_TEST(ImageFilterDrawTiled, reporter) {
710 // Check that all filters when drawn tiled (with subsequent clip rects) exactly
711 // match the same filters drawn with a single full-canvas bitmap draw.
712 // Tests pass by not asserting.
713
robertphillipsfc11b0a2016-04-05 09:09:36 -0700714 FilterList filters(nullptr);
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +0000715
716 SkBitmap untiledResult, tiledResult;
reed5ea95df2015-10-06 14:05:32 -0700717 const int width = 64, height = 64;
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +0000718 untiledResult.allocN32Pixels(width, height);
719 tiledResult.allocN32Pixels(width, height);
720 SkCanvas tiledCanvas(tiledResult);
721 SkCanvas untiledCanvas(untiledResult);
senorblanco@chromium.orgd4db6572014-05-07 20:00:04 +0000722 int tileSize = 8;
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +0000723
senorblanco@chromium.orgd4db6572014-05-07 20:00:04 +0000724 for (int scale = 1; scale <= 2; ++scale) {
senorblanco297f7ce2016-03-23 13:44:26 -0700725 for (int i = 0; i < filters.count(); ++i) {
senorblanco@chromium.orgd4db6572014-05-07 20:00:04 +0000726 tiledCanvas.clear(0);
727 untiledCanvas.clear(0);
728 SkPaint paint;
senorblanco297f7ce2016-03-23 13:44:26 -0700729 paint.setImageFilter(filters.getFilter(i));
senorblanco@chromium.orgd4db6572014-05-07 20:00:04 +0000730 paint.setTextSize(SkIntToScalar(height));
731 paint.setColor(SK_ColorWHITE);
732 SkString str;
733 const char* text = "ABC";
734 SkScalar ypos = SkIntToScalar(height);
735 untiledCanvas.save();
736 untiledCanvas.scale(SkIntToScalar(scale), SkIntToScalar(scale));
737 untiledCanvas.drawText(text, strlen(text), 0, ypos, paint);
738 untiledCanvas.restore();
739 for (int y = 0; y < height; y += tileSize) {
740 for (int x = 0; x < width; x += tileSize) {
741 tiledCanvas.save();
742 tiledCanvas.clipRect(SkRect::Make(SkIRect::MakeXYWH(x, y, tileSize, tileSize)));
743 tiledCanvas.scale(SkIntToScalar(scale), SkIntToScalar(scale));
744 tiledCanvas.drawText(text, strlen(text), 0, ypos, paint);
745 tiledCanvas.restore();
746 }
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +0000747 }
senorblanco@chromium.orgd4db6572014-05-07 20:00:04 +0000748 untiledCanvas.flush();
749 tiledCanvas.flush();
750 for (int y = 0; y < height; y++) {
751 int diffs = memcmp(untiledResult.getAddr32(0, y), tiledResult.getAddr32(0, y), untiledResult.rowBytes());
senorblanco297f7ce2016-03-23 13:44:26 -0700752 REPORTER_ASSERT_MESSAGE(reporter, !diffs, filters.getName(i));
senorblanco@chromium.orgd4db6572014-05-07 20:00:04 +0000753 if (diffs) {
754 break;
755 }
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
robertphillips5605b562016-04-05 11:50:42 -0700767 sk_sp<SkColorFilter> cf(SkColorFilter::MakeModeFilter(SK_ColorWHITE, SkXfermode::kSrc_Mode));
768 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
ajuma5788faa2015-02-13 09:05:47 -0800859DEF_TEST(ImageFilterComposedBlurFastBounds, reporter) {
robertphillips6e7025a2016-04-04 04:31:25 -0700860 sk_sp<SkImageFilter> filter1(make_blur(nullptr));
861 sk_sp<SkImageFilter> filter2(make_blur(nullptr));
robertphillips491fb172016-03-30 12:32:58 -0700862 sk_sp<SkImageFilter> composedFilter(SkComposeImageFilter::Make(std::move(filter1),
863 std::move(filter2)));
ajuma5788faa2015-02-13 09:05:47 -0800864
865 SkRect boundsSrc = SkRect::MakeWH(SkIntToScalar(100), SkIntToScalar(100));
866 SkRect expectedBounds = SkRect::MakeXYWH(
867 SkIntToScalar(-6), SkIntToScalar(-6), SkIntToScalar(112), SkIntToScalar(112));
senorblancoe5e79842016-03-21 14:51:59 -0700868 SkRect boundsDst = composedFilter->computeFastBounds(boundsSrc);
ajuma5788faa2015-02-13 09:05:47 -0800869
870 REPORTER_ASSERT(reporter, boundsDst == expectedBounds);
871}
872
jbroman0e3129d2016-03-17 12:24:23 -0700873DEF_TEST(ImageFilterUnionBounds, reporter) {
robertphillips51a315e2016-03-31 09:05:49 -0700874 sk_sp<SkImageFilter> offset(SkOffsetImageFilter::Make(50, 0, nullptr));
jbroman0e3129d2016-03-17 12:24:23 -0700875 // Regardless of which order they appear in, the image filter bounds should
876 // be combined correctly.
877 {
robertphillips8c0326d2016-04-05 12:48:34 -0700878 sk_sp<SkImageFilter> composite(SkXfermodeImageFilter::Make(nullptr, offset));
jbroman0e3129d2016-03-17 12:24:23 -0700879 SkRect bounds = SkRect::MakeWH(100, 100);
880 // Intentionally aliasing here, as that's what the real callers do.
senorblancoe5e79842016-03-21 14:51:59 -0700881 bounds = composite->computeFastBounds(bounds);
jbroman0e3129d2016-03-17 12:24:23 -0700882 REPORTER_ASSERT(reporter, bounds == SkRect::MakeWH(150, 100));
883 }
884 {
reedcfb6bdf2016-03-29 11:32:50 -0700885 sk_sp<SkImageFilter> composite(SkXfermodeImageFilter::Make(nullptr, nullptr,
robertphillips8c0326d2016-04-05 12:48:34 -0700886 offset, nullptr));
jbroman0e3129d2016-03-17 12:24:23 -0700887 SkRect bounds = SkRect::MakeWH(100, 100);
888 // Intentionally aliasing here, as that's what the real callers do.
senorblancoe5e79842016-03-21 14:51:59 -0700889 bounds = composite->computeFastBounds(bounds);
jbroman0e3129d2016-03-17 12:24:23 -0700890 REPORTER_ASSERT(reporter, bounds == SkRect::MakeWH(150, 100));
891 }
892}
893
robertphillips3e302272016-04-20 11:48:36 -0700894static void test_imagefilter_merge_result_size(skiatest::Reporter* reporter, GrContext* context) {
senorblanco4a243982015-11-25 07:06:55 -0800895 SkBitmap greenBM;
896 greenBM.allocN32Pixels(20, 20);
897 greenBM.eraseColor(SK_ColorGREEN);
reed9ce9d672016-03-17 10:51:11 -0700898 sk_sp<SkImage> greenImage(SkImage::MakeFromBitmap(greenBM));
robertphillips549c8992016-04-01 09:28:51 -0700899 sk_sp<SkImageFilter> source(SkImageSource::Make(std::move(greenImage)));
robertphillips2238c9d2016-03-30 13:34:16 -0700900 sk_sp<SkImageFilter> merge(SkMergeImageFilter::Make(source, source));
senorblanco4a243982015-11-25 07:06:55 -0800901
robertphillips3e302272016-04-20 11:48:36 -0700902 sk_sp<SkSpecialImage> srcImg(create_empty_special_image(context, 1));
robertphillips4418dba2016-03-07 12:45:14 -0800903
reed4e23cda2016-01-11 10:56:59 -0800904 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeXYWH(0, 0, 100, 100), nullptr);
senorblanco4a243982015-11-25 07:06:55 -0800905 SkIPoint offset;
robertphillips4418dba2016-03-07 12:45:14 -0800906
robertphillips2302de92016-03-24 07:26:32 -0700907 sk_sp<SkSpecialImage> resultImg(merge->filterImage(srcImg.get(), ctx, &offset));
robertphillips4418dba2016-03-07 12:45:14 -0800908 REPORTER_ASSERT(reporter, resultImg);
909
910 REPORTER_ASSERT(reporter, resultImg->width() == 20 && resultImg->height() == 20);
senorblanco4a243982015-11-25 07:06:55 -0800911}
912
robertphillips4418dba2016-03-07 12:45:14 -0800913DEF_TEST(ImageFilterMergeResultSize, reporter) {
robertphillips3e302272016-04-20 11:48:36 -0700914 test_imagefilter_merge_result_size(reporter, nullptr);
robertphillips4418dba2016-03-07 12:45:14 -0800915}
916
917#if SK_SUPPORT_GPU
egdanielab527a52016-06-28 08:07:26 -0700918DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterMergeResultSize_Gpu, reporter, ctxInfo) {
bsalomon8b7451a2016-05-11 06:33:06 -0700919 test_imagefilter_merge_result_size(reporter, ctxInfo.grContext());
robertphillips4418dba2016-03-07 12:45:14 -0800920}
921#endif
922
robertphillipsa8d7f0b2014-08-29 08:03:56 -0700923static void draw_blurred_rect(SkCanvas* canvas) {
senorblanco837f5322014-07-14 10:19:54 -0700924 SkPaint filterPaint;
925 filterPaint.setColor(SK_ColorWHITE);
robertphillips6e7025a2016-04-04 04:31:25 -0700926 filterPaint.setImageFilter(SkBlurImageFilter::Make(SkIntToScalar(8), 0, nullptr));
halcanary96fcdcc2015-08-27 07:41:13 -0700927 canvas->saveLayer(nullptr, &filterPaint);
senorblanco837f5322014-07-14 10:19:54 -0700928 SkPaint whitePaint;
929 whitePaint.setColor(SK_ColorWHITE);
930 canvas->drawRect(SkRect::Make(SkIRect::MakeWH(4, 4)), whitePaint);
931 canvas->restore();
932}
933
robertphillipsa8d7f0b2014-08-29 08:03:56 -0700934static void draw_picture_clipped(SkCanvas* canvas, const SkRect& clipRect, const SkPicture* picture) {
senorblanco837f5322014-07-14 10:19:54 -0700935 canvas->save();
936 canvas->clipRect(clipRect);
937 canvas->drawPicture(picture);
938 canvas->restore();
939}
940
941DEF_TEST(ImageFilterDrawTiledBlurRTree, reporter) {
942 // Check that the blur filter when recorded with RTree acceleration,
943 // and drawn tiled (with subsequent clip rects) exactly
944 // matches the same filter drawn with without RTree acceleration.
945 // This tests that the "bleed" from the blur into the otherwise-blank
946 // tiles is correctly rendered.
947 // Tests pass by not asserting.
948
949 int width = 16, height = 8;
950 SkBitmap result1, result2;
951 result1.allocN32Pixels(width, height);
952 result2.allocN32Pixels(width, height);
953 SkCanvas canvas1(result1);
954 SkCanvas canvas2(result2);
955 int tileSize = 8;
956
957 canvas1.clear(0);
958 canvas2.clear(0);
959
960 SkRTreeFactory factory;
961
962 SkPictureRecorder recorder1, recorder2;
963 // The only difference between these two pictures is that one has RTree aceleration.
mtklein3f3b3d02014-12-01 11:47:08 -0800964 SkCanvas* recordingCanvas1 = recorder1.beginRecording(SkIntToScalar(width),
965 SkIntToScalar(height),
halcanary96fcdcc2015-08-27 07:41:13 -0700966 nullptr, 0);
mtklein3f3b3d02014-12-01 11:47:08 -0800967 SkCanvas* recordingCanvas2 = recorder2.beginRecording(SkIntToScalar(width),
968 SkIntToScalar(height),
robertphillipsa8d7f0b2014-08-29 08:03:56 -0700969 &factory, 0);
970 draw_blurred_rect(recordingCanvas1);
971 draw_blurred_rect(recordingCanvas2);
reedca2622b2016-03-18 07:25:55 -0700972 sk_sp<SkPicture> picture1(recorder1.finishRecordingAsPicture());
973 sk_sp<SkPicture> picture2(recorder2.finishRecordingAsPicture());
senorblanco837f5322014-07-14 10:19:54 -0700974 for (int y = 0; y < height; y += tileSize) {
975 for (int x = 0; x < width; x += tileSize) {
976 SkRect tileRect = SkRect::Make(SkIRect::MakeXYWH(x, y, tileSize, tileSize));
reedca2622b2016-03-18 07:25:55 -0700977 draw_picture_clipped(&canvas1, tileRect, picture1.get());
978 draw_picture_clipped(&canvas2, tileRect, picture2.get());
senorblanco837f5322014-07-14 10:19:54 -0700979 }
980 }
981 for (int y = 0; y < height; y++) {
982 int diffs = memcmp(result1.getAddr32(0, y), result2.getAddr32(0, y), result1.rowBytes());
983 REPORTER_ASSERT(reporter, !diffs);
984 if (diffs) {
985 break;
986 }
987 }
988}
989
senorblanco@chromium.org91957432014-05-01 14:03:41 +0000990DEF_TEST(ImageFilterMatrixConvolution, reporter) {
991 // Check that a 1x3 filter does not cause a spurious assert.
992 SkScalar kernel[3] = {
993 SkIntToScalar( 1), SkIntToScalar( 1), SkIntToScalar( 1),
994 };
995 SkISize kernelSize = SkISize::Make(1, 3);
996 SkScalar gain = SK_Scalar1, bias = 0;
997 SkIPoint kernelOffset = SkIPoint::Make(0, 0);
998
robertphillipsef6a47b2016-04-08 08:01:20 -0700999 sk_sp<SkImageFilter> filter(SkMatrixConvolutionImageFilter::Make(
1000 kernelSize, kernel,
1001 gain, bias, kernelOffset,
1002 SkMatrixConvolutionImageFilter::kRepeat_TileMode,
1003 false, nullptr));
senorblanco@chromium.org91957432014-05-01 14:03:41 +00001004
1005 SkBitmap result;
1006 int width = 16, height = 16;
1007 result.allocN32Pixels(width, height);
1008 SkCanvas canvas(result);
1009 canvas.clear(0);
1010
1011 SkPaint paint;
robertphillipsef6a47b2016-04-08 08:01:20 -07001012 paint.setImageFilter(std::move(filter));
senorblanco@chromium.org91957432014-05-01 14:03:41 +00001013 SkRect rect = SkRect::Make(SkIRect::MakeWH(width, height));
1014 canvas.drawRect(rect, paint);
1015}
1016
senorblanco@chromium.org8c7372b2014-05-02 19:13:11 +00001017DEF_TEST(ImageFilterMatrixConvolutionBorder, reporter) {
1018 // Check that a filter with borders outside the target bounds
1019 // does not crash.
1020 SkScalar kernel[3] = {
1021 0, 0, 0,
1022 };
1023 SkISize kernelSize = SkISize::Make(3, 1);
1024 SkScalar gain = SK_Scalar1, bias = 0;
1025 SkIPoint kernelOffset = SkIPoint::Make(2, 0);
1026
robertphillipsef6a47b2016-04-08 08:01:20 -07001027 sk_sp<SkImageFilter> filter(SkMatrixConvolutionImageFilter::Make(
1028 kernelSize, kernel, gain, bias, kernelOffset,
1029 SkMatrixConvolutionImageFilter::kClamp_TileMode,
1030 true, nullptr));
senorblanco@chromium.org8c7372b2014-05-02 19:13:11 +00001031
1032 SkBitmap result;
1033
1034 int width = 10, height = 10;
1035 result.allocN32Pixels(width, height);
1036 SkCanvas canvas(result);
1037 canvas.clear(0);
1038
1039 SkPaint filterPaint;
robertphillipsef6a47b2016-04-08 08:01:20 -07001040 filterPaint.setImageFilter(std::move(filter));
senorblanco@chromium.org8c7372b2014-05-02 19:13:11 +00001041 SkRect bounds = SkRect::MakeWH(1, 10);
1042 SkRect rect = SkRect::Make(SkIRect::MakeWH(width, height));
1043 SkPaint rectPaint;
1044 canvas.saveLayer(&bounds, &filterPaint);
1045 canvas.drawRect(rect, rectPaint);
1046 canvas.restore();
1047}
1048
robertphillips3e302272016-04-20 11:48:36 -07001049static void test_big_kernel(skiatest::Reporter* reporter, GrContext* context) {
robertphillipsdada4dd2016-04-13 04:54:36 -07001050 // Check that a kernel that is too big for the GPU still works
1051 SkScalar identityKernel[49] = {
1052 0, 0, 0, 0, 0, 0, 0,
1053 0, 0, 0, 0, 0, 0, 0,
1054 0, 0, 0, 0, 0, 0, 0,
1055 0, 0, 0, 1, 0, 0, 0,
1056 0, 0, 0, 0, 0, 0, 0,
1057 0, 0, 0, 0, 0, 0, 0,
1058 0, 0, 0, 0, 0, 0, 0
1059 };
1060 SkISize kernelSize = SkISize::Make(7, 7);
1061 SkScalar gain = SK_Scalar1, bias = 0;
1062 SkIPoint kernelOffset = SkIPoint::Make(0, 0);
1063
1064 sk_sp<SkImageFilter> filter(SkMatrixConvolutionImageFilter::Make(
1065 kernelSize, identityKernel, gain, bias, kernelOffset,
1066 SkMatrixConvolutionImageFilter::kClamp_TileMode,
1067 true, nullptr));
1068
robertphillips3e302272016-04-20 11:48:36 -07001069 sk_sp<SkSpecialImage> srcImg(create_empty_special_image(context, 100));
robertphillipsdada4dd2016-04-13 04:54:36 -07001070 SkASSERT(srcImg);
1071
1072 SkIPoint offset;
1073 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeWH(100, 100), nullptr);
1074 sk_sp<SkSpecialImage> resultImg(filter->filterImage(srcImg.get(), ctx, &offset));
1075 REPORTER_ASSERT(reporter, resultImg);
1076 REPORTER_ASSERT(reporter, SkToBool(context) == resultImg->isTextureBacked());
1077 REPORTER_ASSERT(reporter, resultImg->width() == 100 && resultImg->height() == 100);
1078 REPORTER_ASSERT(reporter, offset.fX == 0 && offset.fY == 0);
1079}
1080
1081DEF_TEST(ImageFilterMatrixConvolutionBigKernel, reporter) {
robertphillips3e302272016-04-20 11:48:36 -07001082 test_big_kernel(reporter, nullptr);
robertphillipsdada4dd2016-04-13 04:54:36 -07001083}
1084
1085#if SK_SUPPORT_GPU
egdanielab527a52016-06-28 08:07:26 -07001086DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterMatrixConvolutionBigKernel_Gpu,
1087 reporter, ctxInfo) {
bsalomon8b7451a2016-05-11 06:33:06 -07001088 test_big_kernel(reporter, ctxInfo.grContext());
robertphillipsdada4dd2016-04-13 04:54:36 -07001089}
1090#endif
1091
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +00001092DEF_TEST(ImageFilterCropRect, reporter) {
robertphillips3e302272016-04-20 11:48:36 -07001093 test_crop_rects(reporter, nullptr);
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +00001094}
1095
robertphillips4418dba2016-03-07 12:45:14 -08001096#if SK_SUPPORT_GPU
bsalomon68d91342016-04-12 09:59:58 -07001097DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterCropRect_Gpu, reporter, ctxInfo) {
bsalomon8b7451a2016-05-11 06:33:06 -07001098 test_crop_rects(reporter, ctxInfo.grContext());
robertphillips4418dba2016-03-07 12:45:14 -08001099}
1100#endif
1101
tfarina9ea53f92014-06-24 06:50:39 -07001102DEF_TEST(ImageFilterMatrix, reporter) {
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +00001103 SkBitmap temp;
mike@reedtribe.orgdeee4962014-02-13 14:41:43 +00001104 temp.allocN32Pixels(100, 100);
robertphillips9a53fd72015-06-22 09:46:59 -07001105 SkCanvas canvas(temp);
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +00001106 canvas.scale(SkIntToScalar(2), SkIntToScalar(2));
1107
1108 SkMatrix expectedMatrix = canvas.getTotalMatrix();
1109
commit-bot@chromium.org5fb2ce32014-04-17 23:35:06 +00001110 SkRTreeFactory factory;
1111 SkPictureRecorder recorder;
1112 SkCanvas* recordingCanvas = recorder.beginRecording(100, 100, &factory, 0);
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +00001113
1114 SkPaint paint;
robertphillips43c2ad42016-04-04 05:05:11 -07001115 paint.setImageFilter(MatrixTestImageFilter::Make(reporter, expectedMatrix));
halcanary96fcdcc2015-08-27 07:41:13 -07001116 recordingCanvas->saveLayer(nullptr, &paint);
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +00001117 SkPaint solidPaint;
1118 solidPaint.setColor(0xFFFFFFFF);
1119 recordingCanvas->save();
1120 recordingCanvas->scale(SkIntToScalar(10), SkIntToScalar(10));
1121 recordingCanvas->drawRect(SkRect::Make(SkIRect::MakeWH(100, 100)), solidPaint);
1122 recordingCanvas->restore(); // scale
1123 recordingCanvas->restore(); // saveLayer
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +00001124
reedca2622b2016-03-18 07:25:55 -07001125 canvas.drawPicture(recorder.finishRecordingAsPicture());
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +00001126}
1127
senorblanco3d822c22014-07-30 14:49:31 -07001128DEF_TEST(ImageFilterCrossProcessPictureImageFilter, reporter) {
senorblanco@chromium.org97f5fc62014-05-30 20:50:56 +00001129 SkRTreeFactory factory;
1130 SkPictureRecorder recorder;
1131 SkCanvas* recordingCanvas = recorder.beginRecording(1, 1, &factory, 0);
1132
1133 // Create an SkPicture which simply draws a green 1x1 rectangle.
1134 SkPaint greenPaint;
1135 greenPaint.setColor(SK_ColorGREEN);
1136 recordingCanvas->drawRect(SkRect::Make(SkIRect::MakeWH(1, 1)), greenPaint);
reedca2622b2016-03-18 07:25:55 -07001137 sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture());
senorblanco@chromium.org97f5fc62014-05-30 20:50:56 +00001138
1139 // Wrap that SkPicture in an SkPictureImageFilter.
robertphillips5ff17b12016-03-28 13:13:42 -07001140 sk_sp<SkImageFilter> imageFilter(SkPictureImageFilter::Make(picture));
senorblanco@chromium.org97f5fc62014-05-30 20:50:56 +00001141
1142 // Check that SkPictureImageFilter successfully serializes its contained
1143 // SkPicture when not in cross-process mode.
1144 SkPaint paint;
robertphillips5ff17b12016-03-28 13:13:42 -07001145 paint.setImageFilter(imageFilter);
senorblanco@chromium.org97f5fc62014-05-30 20:50:56 +00001146 SkPictureRecorder outerRecorder;
1147 SkCanvas* outerCanvas = outerRecorder.beginRecording(1, 1, &factory, 0);
1148 SkPaint redPaintWithFilter;
1149 redPaintWithFilter.setColor(SK_ColorRED);
robertphillips5ff17b12016-03-28 13:13:42 -07001150 redPaintWithFilter.setImageFilter(imageFilter);
senorblanco@chromium.org97f5fc62014-05-30 20:50:56 +00001151 outerCanvas->drawRect(SkRect::Make(SkIRect::MakeWH(1, 1)), redPaintWithFilter);
reedca2622b2016-03-18 07:25:55 -07001152 sk_sp<SkPicture> outerPicture(outerRecorder.finishRecordingAsPicture());
senorblanco@chromium.org97f5fc62014-05-30 20:50:56 +00001153
1154 SkBitmap bitmap;
1155 bitmap.allocN32Pixels(1, 1);
robertphillips9a53fd72015-06-22 09:46:59 -07001156 SkCanvas canvas(bitmap);
senorblanco@chromium.org97f5fc62014-05-30 20:50:56 +00001157
1158 // The result here should be green, since the filter replaces the primitive's red interior.
1159 canvas.clear(0x0);
robertphillips9b14f262014-06-04 05:40:44 -07001160 canvas.drawPicture(outerPicture);
senorblanco@chromium.org97f5fc62014-05-30 20:50:56 +00001161 uint32_t pixel = *bitmap.getAddr32(0, 0);
1162 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1163
1164 // Check that, for now, SkPictureImageFilter does not serialize or
1165 // deserialize its contained picture when the filter is serialized
1166 // cross-process. Do this by "laundering" it through SkValidatingReadBuffer.
robertphillips12fa47d2016-04-08 16:28:09 -07001167 sk_sp<SkData> data(SkValidatingSerializeFlattenable(imageFilter.get()));
1168 sk_sp<SkFlattenable> flattenable(SkValidatingDeserializeFlattenable(
mtklein3b375452016-04-04 14:57:19 -07001169 data->data(), data->size(), SkImageFilter::GetFlattenableType()));
senorblanco@chromium.org97f5fc62014-05-30 20:50:56 +00001170 SkImageFilter* unflattenedFilter = static_cast<SkImageFilter*>(flattenable.get());
1171
1172 redPaintWithFilter.setImageFilter(unflattenedFilter);
1173 SkPictureRecorder crossProcessRecorder;
1174 SkCanvas* crossProcessCanvas = crossProcessRecorder.beginRecording(1, 1, &factory, 0);
1175 crossProcessCanvas->drawRect(SkRect::Make(SkIRect::MakeWH(1, 1)), redPaintWithFilter);
reedca2622b2016-03-18 07:25:55 -07001176 sk_sp<SkPicture> crossProcessPicture(crossProcessRecorder.finishRecordingAsPicture());
senorblanco@chromium.org97f5fc62014-05-30 20:50:56 +00001177
1178 canvas.clear(0x0);
robertphillips9b14f262014-06-04 05:40:44 -07001179 canvas.drawPicture(crossProcessPicture);
senorblanco@chromium.org97f5fc62014-05-30 20:50:56 +00001180 pixel = *bitmap.getAddr32(0, 0);
hendrikw446ee672015-06-16 09:28:37 -07001181 // If the security precautions are enabled, the result here should not be green, since the
1182 // filter draws nothing.
mtklein2afbe232016-02-07 12:23:10 -08001183 REPORTER_ASSERT(reporter, SkPicture::PictureIOSecurityPrecautionsEnabled()
hendrikw446ee672015-06-16 09:28:37 -07001184 ? pixel != SK_ColorGREEN : pixel == SK_ColorGREEN);
senorblanco@chromium.org97f5fc62014-05-30 20:50:56 +00001185}
1186
robertphillips3e302272016-04-20 11:48:36 -07001187static void test_clipped_picture_imagefilter(skiatest::Reporter* reporter, GrContext* context) {
reedca2622b2016-03-18 07:25:55 -07001188 sk_sp<SkPicture> picture;
senorblanco3d822c22014-07-30 14:49:31 -07001189
robertphillips4418dba2016-03-07 12:45:14 -08001190 {
1191 SkRTreeFactory factory;
1192 SkPictureRecorder recorder;
1193 SkCanvas* recordingCanvas = recorder.beginRecording(1, 1, &factory, 0);
1194
1195 // Create an SkPicture which simply draws a green 1x1 rectangle.
1196 SkPaint greenPaint;
1197 greenPaint.setColor(SK_ColorGREEN);
1198 recordingCanvas->drawRect(SkRect::Make(SkIRect::MakeWH(1, 1)), greenPaint);
reedca2622b2016-03-18 07:25:55 -07001199 picture = recorder.finishRecordingAsPicture();
robertphillips4418dba2016-03-07 12:45:14 -08001200 }
1201
robertphillips3e302272016-04-20 11:48:36 -07001202 sk_sp<SkSpecialImage> srcImg(create_empty_special_image(context, 2));
senorblanco3d822c22014-07-30 14:49:31 -07001203
robertphillips5ff17b12016-03-28 13:13:42 -07001204 sk_sp<SkImageFilter> imageFilter(SkPictureImageFilter::Make(picture));
senorblanco3d822c22014-07-30 14:49:31 -07001205
senorblanco3d822c22014-07-30 14:49:31 -07001206 SkIPoint offset;
reed4e23cda2016-01-11 10:56:59 -08001207 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeXYWH(1, 1, 1, 1), nullptr);
robertphillips4418dba2016-03-07 12:45:14 -08001208
robertphillips2302de92016-03-24 07:26:32 -07001209 sk_sp<SkSpecialImage> resultImage(imageFilter->filterImage(srcImg.get(), ctx, &offset));
robertphillips4418dba2016-03-07 12:45:14 -08001210 REPORTER_ASSERT(reporter, !resultImage);
senorblanco3d822c22014-07-30 14:49:31 -07001211}
1212
robertphillips4418dba2016-03-07 12:45:14 -08001213DEF_TEST(ImageFilterClippedPictureImageFilter, reporter) {
robertphillips3e302272016-04-20 11:48:36 -07001214 test_clipped_picture_imagefilter(reporter, nullptr);
robertphillips4418dba2016-03-07 12:45:14 -08001215}
1216
1217#if SK_SUPPORT_GPU
bsalomon68d91342016-04-12 09:59:58 -07001218DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterClippedPictureImageFilter_Gpu, reporter, ctxInfo) {
bsalomon8b7451a2016-05-11 06:33:06 -07001219 test_clipped_picture_imagefilter(reporter, ctxInfo.grContext());
robertphillips4418dba2016-03-07 12:45:14 -08001220}
1221#endif
1222
tfarina9ea53f92014-06-24 06:50:39 -07001223DEF_TEST(ImageFilterEmptySaveLayer, reporter) {
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001224 // Even when there's an empty saveLayer()/restore(), ensure that an image
1225 // filter or color filter which affects transparent black still draws.
1226
1227 SkBitmap bitmap;
1228 bitmap.allocN32Pixels(10, 10);
robertphillips9a53fd72015-06-22 09:46:59 -07001229 SkCanvas canvas(bitmap);
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001230
1231 SkRTreeFactory factory;
1232 SkPictureRecorder recorder;
1233
robertphillips5605b562016-04-05 11:50:42 -07001234 sk_sp<SkColorFilter> green(SkColorFilter::MakeModeFilter(SK_ColorGREEN,
1235 SkXfermode::kSrc_Mode));
1236 sk_sp<SkImageFilter> imageFilter(SkColorFilterImageFilter::Make(green, nullptr));
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001237 SkPaint imageFilterPaint;
robertphillips5605b562016-04-05 11:50:42 -07001238 imageFilterPaint.setImageFilter(std::move(imageFilter));
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001239 SkPaint colorFilterPaint;
reedd053ce92016-03-22 10:17:23 -07001240 colorFilterPaint.setColorFilter(green);
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001241
1242 SkRect bounds = SkRect::MakeWH(10, 10);
1243
1244 SkCanvas* recordingCanvas = recorder.beginRecording(10, 10, &factory, 0);
1245 recordingCanvas->saveLayer(&bounds, &imageFilterPaint);
1246 recordingCanvas->restore();
reedca2622b2016-03-18 07:25:55 -07001247 sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture());
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001248
1249 canvas.clear(0);
robertphillips9b14f262014-06-04 05:40:44 -07001250 canvas.drawPicture(picture);
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001251 uint32_t pixel = *bitmap.getAddr32(0, 0);
1252 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1253
1254 recordingCanvas = recorder.beginRecording(10, 10, &factory, 0);
halcanary96fcdcc2015-08-27 07:41:13 -07001255 recordingCanvas->saveLayer(nullptr, &imageFilterPaint);
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001256 recordingCanvas->restore();
reedca2622b2016-03-18 07:25:55 -07001257 sk_sp<SkPicture> picture2(recorder.finishRecordingAsPicture());
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001258
1259 canvas.clear(0);
robertphillips9b14f262014-06-04 05:40:44 -07001260 canvas.drawPicture(picture2);
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001261 pixel = *bitmap.getAddr32(0, 0);
1262 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1263
1264 recordingCanvas = recorder.beginRecording(10, 10, &factory, 0);
1265 recordingCanvas->saveLayer(&bounds, &colorFilterPaint);
1266 recordingCanvas->restore();
reedca2622b2016-03-18 07:25:55 -07001267 sk_sp<SkPicture> picture3(recorder.finishRecordingAsPicture());
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001268
1269 canvas.clear(0);
robertphillips9b14f262014-06-04 05:40:44 -07001270 canvas.drawPicture(picture3);
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001271 pixel = *bitmap.getAddr32(0, 0);
1272 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1273}
1274
robertphillips9a53fd72015-06-22 09:46:59 -07001275static void test_huge_blur(SkCanvas* canvas, skiatest::Reporter* reporter) {
senorblanco@chromium.org09843fd2014-03-24 20:50:59 +00001276 SkBitmap bitmap;
1277 bitmap.allocN32Pixels(100, 100);
1278 bitmap.eraseARGB(0, 0, 0, 0);
1279
1280 // Check that a blur with an insane radius does not crash or assert.
senorblanco@chromium.org09843fd2014-03-24 20:50:59 +00001281 SkPaint paint;
robertphillips6e7025a2016-04-04 04:31:25 -07001282 paint.setImageFilter(SkBlurImageFilter::Make(SkIntToScalar(1<<30),
1283 SkIntToScalar(1<<30),
1284 nullptr));
reedda420b92015-12-16 08:38:15 -08001285 canvas->drawBitmap(bitmap, 0, 0, &paint);
senorblanco@chromium.org09843fd2014-03-24 20:50:59 +00001286}
1287
1288DEF_TEST(HugeBlurImageFilter, reporter) {
1289 SkBitmap temp;
1290 temp.allocN32Pixels(100, 100);
robertphillips9a53fd72015-06-22 09:46:59 -07001291 SkCanvas canvas(temp);
1292 test_huge_blur(&canvas, reporter);
senorblanco@chromium.org09843fd2014-03-24 20:50:59 +00001293}
1294
senorblanco21a465d2016-04-11 11:58:39 -07001295DEF_TEST(ImageFilterMatrixConvolutionSanityTest, reporter) {
senorblanco3a495202014-09-29 07:57:20 -07001296 SkScalar kernel[1] = { 0 };
1297 SkScalar gain = SK_Scalar1, bias = 0;
1298 SkIPoint kernelOffset = SkIPoint::Make(1, 1);
1299
halcanary96fcdcc2015-08-27 07:41:13 -07001300 // Check that an enormous (non-allocatable) kernel gives a nullptr filter.
robertphillipsef6a47b2016-04-08 08:01:20 -07001301 sk_sp<SkImageFilter> conv(SkMatrixConvolutionImageFilter::Make(
senorblanco3a495202014-09-29 07:57:20 -07001302 SkISize::Make(1<<30, 1<<30),
1303 kernel,
1304 gain,
1305 bias,
1306 kernelOffset,
1307 SkMatrixConvolutionImageFilter::kRepeat_TileMode,
robertphillipsef6a47b2016-04-08 08:01:20 -07001308 false,
1309 nullptr));
senorblanco3a495202014-09-29 07:57:20 -07001310
halcanary96fcdcc2015-08-27 07:41:13 -07001311 REPORTER_ASSERT(reporter, nullptr == conv.get());
senorblanco3a495202014-09-29 07:57:20 -07001312
halcanary96fcdcc2015-08-27 07:41:13 -07001313 // Check that a nullptr kernel gives a nullptr filter.
robertphillipsef6a47b2016-04-08 08:01:20 -07001314 conv = SkMatrixConvolutionImageFilter::Make(
senorblanco3a495202014-09-29 07:57:20 -07001315 SkISize::Make(1, 1),
halcanary96fcdcc2015-08-27 07:41:13 -07001316 nullptr,
senorblanco3a495202014-09-29 07:57:20 -07001317 gain,
1318 bias,
1319 kernelOffset,
1320 SkMatrixConvolutionImageFilter::kRepeat_TileMode,
robertphillipsef6a47b2016-04-08 08:01:20 -07001321 false,
1322 nullptr);
senorblanco3a495202014-09-29 07:57:20 -07001323
halcanary96fcdcc2015-08-27 07:41:13 -07001324 REPORTER_ASSERT(reporter, nullptr == conv.get());
senorblanco3a495202014-09-29 07:57:20 -07001325
halcanary96fcdcc2015-08-27 07:41:13 -07001326 // Check that a kernel width < 1 gives a nullptr filter.
robertphillipsef6a47b2016-04-08 08:01:20 -07001327 conv = SkMatrixConvolutionImageFilter::Make(
senorblanco3a495202014-09-29 07:57:20 -07001328 SkISize::Make(0, 1),
1329 kernel,
1330 gain,
1331 bias,
1332 kernelOffset,
1333 SkMatrixConvolutionImageFilter::kRepeat_TileMode,
robertphillipsef6a47b2016-04-08 08:01:20 -07001334 false,
1335 nullptr);
senorblanco3a495202014-09-29 07:57:20 -07001336
halcanary96fcdcc2015-08-27 07:41:13 -07001337 REPORTER_ASSERT(reporter, nullptr == conv.get());
senorblanco3a495202014-09-29 07:57:20 -07001338
halcanary96fcdcc2015-08-27 07:41:13 -07001339 // Check that kernel height < 1 gives a nullptr filter.
robertphillipsef6a47b2016-04-08 08:01:20 -07001340 conv = SkMatrixConvolutionImageFilter::Make(
senorblanco3a495202014-09-29 07:57:20 -07001341 SkISize::Make(1, -1),
1342 kernel,
1343 gain,
1344 bias,
1345 kernelOffset,
1346 SkMatrixConvolutionImageFilter::kRepeat_TileMode,
robertphillipsef6a47b2016-04-08 08:01:20 -07001347 false,
1348 nullptr);
senorblanco3a495202014-09-29 07:57:20 -07001349
halcanary96fcdcc2015-08-27 07:41:13 -07001350 REPORTER_ASSERT(reporter, nullptr == conv.get());
senorblanco3a495202014-09-29 07:57:20 -07001351}
1352
robertphillips9a53fd72015-06-22 09:46:59 -07001353static void test_xfermode_cropped_input(SkCanvas* canvas, skiatest::Reporter* reporter) {
1354 canvas->clear(0);
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001355
1356 SkBitmap bitmap;
1357 bitmap.allocN32Pixels(1, 1);
1358 bitmap.eraseARGB(255, 255, 255, 255);
1359
robertphillips5605b562016-04-05 11:50:42 -07001360 sk_sp<SkColorFilter> green(SkColorFilter::MakeModeFilter(SK_ColorGREEN,
1361 SkXfermode::kSrcIn_Mode));
1362 sk_sp<SkImageFilter> greenFilter(SkColorFilterImageFilter::Make(green, nullptr));
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001363 SkImageFilter::CropRect cropRect(SkRect::MakeEmpty());
robertphillips5605b562016-04-05 11:50:42 -07001364 sk_sp<SkImageFilter> croppedOut(SkColorFilterImageFilter::Make(green, nullptr, &cropRect));
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001365
1366 // Check that an xfermode image filter whose input has been cropped out still draws the other
1367 // input. Also check that drawing with both inputs cropped out doesn't cause a GPU warning.
robertphillips8c0326d2016-04-05 12:48:34 -07001368 sk_sp<SkXfermode> mode(SkXfermode::Make(SkXfermode::kSrcOver_Mode));
1369 sk_sp<SkImageFilter> xfermodeNoFg(SkXfermodeImageFilter::Make(mode, greenFilter,
1370 croppedOut, nullptr));
1371 sk_sp<SkImageFilter> xfermodeNoBg(SkXfermodeImageFilter::Make(mode, croppedOut,
1372 greenFilter, nullptr));
1373 sk_sp<SkImageFilter> xfermodeNoFgNoBg(SkXfermodeImageFilter::Make(mode, croppedOut,
1374 croppedOut, nullptr));
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001375
1376 SkPaint paint;
robertphillips8c0326d2016-04-05 12:48:34 -07001377 paint.setImageFilter(std::move(xfermodeNoFg));
reedda420b92015-12-16 08:38:15 -08001378 canvas->drawBitmap(bitmap, 0, 0, &paint); // drawSprite
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001379
1380 uint32_t pixel;
kkinnunena9d9a392015-03-06 07:16:00 -08001381 SkImageInfo info = SkImageInfo::Make(1, 1, kBGRA_8888_SkColorType, kUnpremul_SkAlphaType);
robertphillips9a53fd72015-06-22 09:46:59 -07001382 canvas->readPixels(info, &pixel, 4, 0, 0);
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001383 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1384
robertphillips8c0326d2016-04-05 12:48:34 -07001385 paint.setImageFilter(std::move(xfermodeNoBg));
reedda420b92015-12-16 08:38:15 -08001386 canvas->drawBitmap(bitmap, 0, 0, &paint); // drawSprite
robertphillips9a53fd72015-06-22 09:46:59 -07001387 canvas->readPixels(info, &pixel, 4, 0, 0);
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001388 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1389
robertphillips8c0326d2016-04-05 12:48:34 -07001390 paint.setImageFilter(std::move(xfermodeNoFgNoBg));
reedda420b92015-12-16 08:38:15 -08001391 canvas->drawBitmap(bitmap, 0, 0, &paint); // drawSprite
robertphillips9a53fd72015-06-22 09:46:59 -07001392 canvas->readPixels(info, &pixel, 4, 0, 0);
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001393 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1394}
1395
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001396DEF_TEST(ImageFilterNestedSaveLayer, reporter) {
1397 SkBitmap temp;
1398 temp.allocN32Pixels(50, 50);
robertphillips9a53fd72015-06-22 09:46:59 -07001399 SkCanvas canvas(temp);
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001400 canvas.clear(0x0);
1401
1402 SkBitmap bitmap;
1403 bitmap.allocN32Pixels(10, 10);
1404 bitmap.eraseColor(SK_ColorGREEN);
1405
1406 SkMatrix matrix;
1407 matrix.setScale(SkIntToScalar(2), SkIntToScalar(2));
1408 matrix.postTranslate(SkIntToScalar(-20), SkIntToScalar(-20));
robertphillipsae8c9332016-04-05 15:09:00 -07001409 sk_sp<SkImageFilter> matrixFilter(
1410 SkImageFilter::MakeMatrixFilter(matrix, kLow_SkFilterQuality, nullptr));
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001411
1412 // Test that saveLayer() with a filter nested inside another saveLayer() applies the
1413 // correct offset to the filter matrix.
1414 SkRect bounds1 = SkRect::MakeXYWH(10, 10, 30, 30);
halcanary96fcdcc2015-08-27 07:41:13 -07001415 canvas.saveLayer(&bounds1, nullptr);
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001416 SkPaint filterPaint;
robertphillipsae8c9332016-04-05 15:09:00 -07001417 filterPaint.setImageFilter(std::move(matrixFilter));
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001418 SkRect bounds2 = SkRect::MakeXYWH(20, 20, 10, 10);
1419 canvas.saveLayer(&bounds2, &filterPaint);
1420 SkPaint greenPaint;
1421 greenPaint.setColor(SK_ColorGREEN);
1422 canvas.drawRect(bounds2, greenPaint);
1423 canvas.restore();
1424 canvas.restore();
1425 SkPaint strokePaint;
1426 strokePaint.setStyle(SkPaint::kStroke_Style);
1427 strokePaint.setColor(SK_ColorRED);
1428
kkinnunena9d9a392015-03-06 07:16:00 -08001429 SkImageInfo info = SkImageInfo::Make(1, 1, kBGRA_8888_SkColorType, kUnpremul_SkAlphaType);
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001430 uint32_t pixel;
1431 canvas.readPixels(info, &pixel, 4, 25, 25);
1432 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1433
1434 // Test that drawSprite() with a filter nested inside a saveLayer() applies the
1435 // correct offset to the filter matrix.
1436 canvas.clear(0x0);
1437 canvas.readPixels(info, &pixel, 4, 25, 25);
halcanary96fcdcc2015-08-27 07:41:13 -07001438 canvas.saveLayer(&bounds1, nullptr);
reedda420b92015-12-16 08:38:15 -08001439 canvas.drawBitmap(bitmap, 20, 20, &filterPaint); // drawSprite
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001440 canvas.restore();
1441
1442 canvas.readPixels(info, &pixel, 4, 25, 25);
1443 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1444}
1445
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001446DEF_TEST(XfermodeImageFilterCroppedInput, reporter) {
1447 SkBitmap temp;
1448 temp.allocN32Pixels(100, 100);
robertphillips9a53fd72015-06-22 09:46:59 -07001449 SkCanvas canvas(temp);
1450 test_xfermode_cropped_input(&canvas, reporter);
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001451}
senorblanco@chromium.org09843fd2014-03-24 20:50:59 +00001452
robertphillips3e302272016-04-20 11:48:36 -07001453static void test_composed_imagefilter_offset(skiatest::Reporter* reporter, GrContext* context) {
1454 sk_sp<SkSpecialImage> srcImg(create_empty_special_image(context, 100));
ajuma5788faa2015-02-13 09:05:47 -08001455
1456 SkImageFilter::CropRect cropRect(SkRect::MakeXYWH(1, 0, 20, 20));
robertphillips51a315e2016-03-31 09:05:49 -07001457 sk_sp<SkImageFilter> offsetFilter(SkOffsetImageFilter::Make(0, 0, nullptr, &cropRect));
robertphillips6e7025a2016-04-04 04:31:25 -07001458 sk_sp<SkImageFilter> blurFilter(SkBlurImageFilter::Make(SK_Scalar1, SK_Scalar1,
1459 nullptr, &cropRect));
robertphillips491fb172016-03-30 12:32:58 -07001460 sk_sp<SkImageFilter> composedFilter(SkComposeImageFilter::Make(std::move(blurFilter),
1461 std::move(offsetFilter)));
ajuma5788faa2015-02-13 09:05:47 -08001462 SkIPoint offset;
reed4e23cda2016-01-11 10:56:59 -08001463 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeWH(100, 100), nullptr);
robertphillips4418dba2016-03-07 12:45:14 -08001464
robertphillips2302de92016-03-24 07:26:32 -07001465 sk_sp<SkSpecialImage> resultImg(composedFilter->filterImage(srcImg.get(), ctx, &offset));
robertphillips4418dba2016-03-07 12:45:14 -08001466 REPORTER_ASSERT(reporter, resultImg);
ajuma5788faa2015-02-13 09:05:47 -08001467 REPORTER_ASSERT(reporter, offset.fX == 1 && offset.fY == 0);
1468}
1469
robertphillips4418dba2016-03-07 12:45:14 -08001470DEF_TEST(ComposedImageFilterOffset, reporter) {
robertphillips3e302272016-04-20 11:48:36 -07001471 test_composed_imagefilter_offset(reporter, nullptr);
robertphillips4418dba2016-03-07 12:45:14 -08001472}
1473
1474#if SK_SUPPORT_GPU
bsalomon68d91342016-04-12 09:59:58 -07001475DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ComposedImageFilterOffset_Gpu, reporter, ctxInfo) {
bsalomon8b7451a2016-05-11 06:33:06 -07001476 test_composed_imagefilter_offset(reporter, ctxInfo.grContext());
robertphillips4418dba2016-03-07 12:45:14 -08001477}
1478#endif
1479
robertphillips3e302272016-04-20 11:48:36 -07001480static void test_composed_imagefilter_bounds(skiatest::Reporter* reporter, GrContext* context) {
jbroman17a65202016-03-21 08:38:58 -07001481 // The bounds passed to the inner filter must be filtered by the outer
1482 // filter, so that the inner filter produces the pixels that the outer
1483 // filter requires as input. This matters if the outer filter moves pixels.
1484 // Here, accounting for the outer offset is necessary so that the green
1485 // pixels of the picture are not clipped.
1486
1487 SkPictureRecorder recorder;
1488 SkCanvas* recordingCanvas = recorder.beginRecording(SkRect::MakeWH(200, 100));
1489 recordingCanvas->clipRect(SkRect::MakeXYWH(100, 0, 100, 100));
1490 recordingCanvas->clear(SK_ColorGREEN);
robertphillips491fb172016-03-30 12:32:58 -07001491 sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture());
robertphillips5ff17b12016-03-28 13:13:42 -07001492 sk_sp<SkImageFilter> pictureFilter(SkPictureImageFilter::Make(picture));
jbroman17a65202016-03-21 08:38:58 -07001493 SkImageFilter::CropRect cropRect(SkRect::MakeWH(100, 100));
robertphillips51a315e2016-03-31 09:05:49 -07001494 sk_sp<SkImageFilter> offsetFilter(SkOffsetImageFilter::Make(-100, 0, nullptr, &cropRect));
robertphillips491fb172016-03-30 12:32:58 -07001495 sk_sp<SkImageFilter> composedFilter(SkComposeImageFilter::Make(std::move(offsetFilter),
1496 std::move(pictureFilter)));
jbroman17a65202016-03-21 08:38:58 -07001497
robertphillips3e302272016-04-20 11:48:36 -07001498 sk_sp<SkSpecialImage> sourceImage(create_empty_special_image(context, 100));
jbroman17a65202016-03-21 08:38:58 -07001499 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeWH(100, 100), nullptr);
1500 SkIPoint offset;
1501 sk_sp<SkSpecialImage> result(composedFilter->filterImage(sourceImage.get(), ctx, &offset));
1502 REPORTER_ASSERT(reporter, offset.isZero());
1503 REPORTER_ASSERT(reporter, result);
1504 REPORTER_ASSERT(reporter, result->subset().size() == SkISize::Make(100, 100));
1505
1506 SkBitmap resultBM;
robertphillips64612512016-04-08 12:10:42 -07001507 REPORTER_ASSERT(reporter, result->getROPixels(&resultBM));
jbroman17a65202016-03-21 08:38:58 -07001508 SkAutoLockPixels lock(resultBM);
1509 REPORTER_ASSERT(reporter, resultBM.getColor(50, 50) == SK_ColorGREEN);
1510}
1511
1512DEF_TEST(ComposedImageFilterBounds, reporter) {
robertphillips3e302272016-04-20 11:48:36 -07001513 test_composed_imagefilter_bounds(reporter, nullptr);
jbroman17a65202016-03-21 08:38:58 -07001514}
1515
1516#if SK_SUPPORT_GPU
egdanielab527a52016-06-28 08:07:26 -07001517DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ComposedImageFilterBounds_Gpu, reporter, ctxInfo) {
bsalomon8b7451a2016-05-11 06:33:06 -07001518 test_composed_imagefilter_bounds(reporter, ctxInfo.grContext());
jbroman17a65202016-03-21 08:38:58 -07001519}
1520#endif
1521
robertphillips3e302272016-04-20 11:48:36 -07001522static void test_partial_crop_rect(skiatest::Reporter* reporter, GrContext* context) {
1523 sk_sp<SkSpecialImage> srcImg(create_empty_special_image(context, 100));
senorblanco24d2a7b2015-07-13 10:27:05 -07001524
1525 SkImageFilter::CropRect cropRect(SkRect::MakeXYWH(100, 0, 20, 30),
senorblancoed7cf272015-07-16 15:19:11 -07001526 SkImageFilter::CropRect::kHasWidth_CropEdge | SkImageFilter::CropRect::kHasHeight_CropEdge);
robertphillips5605b562016-04-05 11:50:42 -07001527 sk_sp<SkImageFilter> filter(make_grayscale(nullptr, &cropRect));
senorblanco24d2a7b2015-07-13 10:27:05 -07001528 SkIPoint offset;
reed4e23cda2016-01-11 10:56:59 -08001529 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeWH(100, 100), nullptr);
robertphillips4418dba2016-03-07 12:45:14 -08001530
robertphillips2302de92016-03-24 07:26:32 -07001531 sk_sp<SkSpecialImage> resultImg(filter->filterImage(srcImg.get(), ctx, &offset));
robertphillips4418dba2016-03-07 12:45:14 -08001532 REPORTER_ASSERT(reporter, resultImg);
1533
senorblanco24d2a7b2015-07-13 10:27:05 -07001534 REPORTER_ASSERT(reporter, offset.fX == 0);
1535 REPORTER_ASSERT(reporter, offset.fY == 0);
robertphillips4418dba2016-03-07 12:45:14 -08001536 REPORTER_ASSERT(reporter, resultImg->width() == 20);
1537 REPORTER_ASSERT(reporter, resultImg->height() == 30);
senorblanco24d2a7b2015-07-13 10:27:05 -07001538}
1539
senorblanco21a465d2016-04-11 11:58:39 -07001540DEF_TEST(ImageFilterPartialCropRect, reporter) {
robertphillips3e302272016-04-20 11:48:36 -07001541 test_partial_crop_rect(reporter, nullptr);
robertphillips4418dba2016-03-07 12:45:14 -08001542}
1543
1544#if SK_SUPPORT_GPU
bsalomon68d91342016-04-12 09:59:58 -07001545DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterPartialCropRect_Gpu, reporter, ctxInfo) {
bsalomon8b7451a2016-05-11 06:33:06 -07001546 test_partial_crop_rect(reporter, ctxInfo.grContext());
robertphillips4418dba2016-03-07 12:45:14 -08001547}
1548#endif
1549
senorblanco0abdf762015-08-20 11:10:41 -07001550DEF_TEST(ImageFilterCanComputeFastBounds, reporter) {
1551
robertphillips12fa47d2016-04-08 16:28:09 -07001552 {
1553 SkPoint3 location = SkPoint3::Make(0, 0, SK_Scalar1);
1554 sk_sp<SkImageFilter> lighting(SkLightingImageFilter::MakePointLitDiffuse(location,
1555 SK_ColorGREEN,
1556 0, 0, nullptr));
1557 REPORTER_ASSERT(reporter, !lighting->canComputeFastBounds());
1558 }
senorblanco0abdf762015-08-20 11:10:41 -07001559
senorblanco0abdf762015-08-20 11:10:41 -07001560 {
robertphillips6e7025a2016-04-04 04:31:25 -07001561 sk_sp<SkImageFilter> gray(make_grayscale(nullptr, nullptr));
1562 REPORTER_ASSERT(reporter, gray->canComputeFastBounds());
1563 {
1564 SkColorFilter* grayCF;
1565 REPORTER_ASSERT(reporter, gray->asAColorFilter(&grayCF));
1566 REPORTER_ASSERT(reporter, !grayCF->affectsTransparentBlack());
1567 grayCF->unref();
1568 }
1569 REPORTER_ASSERT(reporter, gray->canComputeFastBounds());
1570
1571 sk_sp<SkImageFilter> grayBlur(SkBlurImageFilter::Make(SK_Scalar1, SK_Scalar1,
1572 std::move(gray)));
1573 REPORTER_ASSERT(reporter, grayBlur->canComputeFastBounds());
senorblanco0abdf762015-08-20 11:10:41 -07001574 }
senorblanco0abdf762015-08-20 11:10:41 -07001575
robertphillips6e7025a2016-04-04 04:31:25 -07001576 {
1577 SkScalar greenMatrix[20] = { 0, 0, 0, 0, 0,
1578 0, 0, 0, 0, 1,
1579 0, 0, 0, 0, 0,
1580 0, 0, 0, 0, 1 };
1581 sk_sp<SkColorFilter> greenCF(SkColorFilter::MakeMatrixFilterRowMajor255(greenMatrix));
robertphillips5605b562016-04-05 11:50:42 -07001582 sk_sp<SkImageFilter> green(SkColorFilterImageFilter::Make(greenCF, nullptr));
senorblanco0abdf762015-08-20 11:10:41 -07001583
robertphillips6e7025a2016-04-04 04:31:25 -07001584 REPORTER_ASSERT(reporter, greenCF->affectsTransparentBlack());
1585 REPORTER_ASSERT(reporter, !green->canComputeFastBounds());
senorblanco0abdf762015-08-20 11:10:41 -07001586
robertphillips6e7025a2016-04-04 04:31:25 -07001587 sk_sp<SkImageFilter> greenBlur(SkBlurImageFilter::Make(SK_Scalar1, SK_Scalar1,
1588 std::move(green)));
1589 REPORTER_ASSERT(reporter, !greenBlur->canComputeFastBounds());
1590 }
senorblanco0abdf762015-08-20 11:10:41 -07001591
1592 uint8_t allOne[256], identity[256];
1593 for (int i = 0; i < 256; ++i) {
1594 identity[i] = i;
1595 allOne[i] = 255;
1596 }
1597
robertphillips5605b562016-04-05 11:50:42 -07001598 sk_sp<SkColorFilter> identityCF(SkTableColorFilter::MakeARGB(identity, identity,
1599 identity, allOne));
1600 sk_sp<SkImageFilter> identityFilter(SkColorFilterImageFilter::Make(identityCF, nullptr));
senorblanco0abdf762015-08-20 11:10:41 -07001601 REPORTER_ASSERT(reporter, !identityCF->affectsTransparentBlack());
1602 REPORTER_ASSERT(reporter, identityFilter->canComputeFastBounds());
1603
robertphillips5605b562016-04-05 11:50:42 -07001604 sk_sp<SkColorFilter> forceOpaqueCF(SkTableColorFilter::MakeARGB(allOne, identity,
1605 identity, identity));
1606 sk_sp<SkImageFilter> forceOpaque(SkColorFilterImageFilter::Make(forceOpaqueCF, nullptr));
senorblanco0abdf762015-08-20 11:10:41 -07001607 REPORTER_ASSERT(reporter, forceOpaqueCF->affectsTransparentBlack());
1608 REPORTER_ASSERT(reporter, !forceOpaque->canComputeFastBounds());
1609}
1610
fmalitacd56f812015-09-14 13:31:18 -07001611// Verify that SkImageSource survives serialization
1612DEF_TEST(ImageFilterImageSourceSerialization, reporter) {
reede8f30622016-03-23 18:59:25 -07001613 auto surface(SkSurface::MakeRasterN32Premul(10, 10));
fmalitacd56f812015-09-14 13:31:18 -07001614 surface->getCanvas()->clear(SK_ColorGREEN);
reed9ce9d672016-03-17 10:51:11 -07001615 sk_sp<SkImage> image(surface->makeImageSnapshot());
robertphillips549c8992016-04-01 09:28:51 -07001616 sk_sp<SkImageFilter> filter(SkImageSource::Make(std::move(image)));
fmalitacd56f812015-09-14 13:31:18 -07001617
robertphillips549c8992016-04-01 09:28:51 -07001618 sk_sp<SkData> data(SkValidatingSerializeFlattenable(filter.get()));
1619 sk_sp<SkFlattenable> flattenable(SkValidatingDeserializeFlattenable(
mtklein3b375452016-04-04 14:57:19 -07001620 data->data(), data->size(), SkImageFilter::GetFlattenableType()));
fmalitacd56f812015-09-14 13:31:18 -07001621 SkImageFilter* unflattenedFilter = static_cast<SkImageFilter*>(flattenable.get());
1622 REPORTER_ASSERT(reporter, unflattenedFilter);
1623
1624 SkBitmap bm;
1625 bm.allocN32Pixels(10, 10);
fmalita23cb88c2015-09-15 06:56:23 -07001626 bm.eraseColor(SK_ColorBLUE);
fmalitacd56f812015-09-14 13:31:18 -07001627 SkPaint paint;
1628 paint.setColor(SK_ColorRED);
1629 paint.setImageFilter(unflattenedFilter);
1630
1631 SkCanvas canvas(bm);
1632 canvas.drawRect(SkRect::MakeWH(10, 10), paint);
1633 REPORTER_ASSERT(reporter, *bm.getAddr32(0, 0) == SkPreMultiplyColor(SK_ColorGREEN));
1634}
1635
bsalomon45eefcf2016-01-05 08:39:28 -08001636static void test_large_blur_input(skiatest::Reporter* reporter, SkCanvas* canvas) {
1637 SkBitmap largeBmp;
1638 int largeW = 5000;
1639 int largeH = 5000;
1640#if SK_SUPPORT_GPU
1641 // If we're GPU-backed make the bitmap too large to be converted into a texture.
1642 if (GrContext* ctx = canvas->getGrContext()) {
1643 largeW = ctx->caps()->maxTextureSize() + 1;
1644 }
1645#endif
1646
1647 largeBmp.allocN32Pixels(largeW, largeH);
mtklein2afbe232016-02-07 12:23:10 -08001648 largeBmp.eraseColor(0);
bsalomon45eefcf2016-01-05 08:39:28 -08001649 if (!largeBmp.getPixels()) {
1650 ERRORF(reporter, "Failed to allocate large bmp.");
1651 return;
1652 }
1653
reed9ce9d672016-03-17 10:51:11 -07001654 sk_sp<SkImage> largeImage(SkImage::MakeFromBitmap(largeBmp));
bsalomon45eefcf2016-01-05 08:39:28 -08001655 if (!largeImage) {
1656 ERRORF(reporter, "Failed to create large image.");
1657 return;
1658 }
1659
robertphillips549c8992016-04-01 09:28:51 -07001660 sk_sp<SkImageFilter> largeSource(SkImageSource::Make(std::move(largeImage)));
bsalomon45eefcf2016-01-05 08:39:28 -08001661 if (!largeSource) {
1662 ERRORF(reporter, "Failed to create large SkImageSource.");
1663 return;
1664 }
1665
robertphillips6e7025a2016-04-04 04:31:25 -07001666 sk_sp<SkImageFilter> blur(SkBlurImageFilter::Make(10.f, 10.f, std::move(largeSource)));
bsalomon45eefcf2016-01-05 08:39:28 -08001667 if (!blur) {
1668 ERRORF(reporter, "Failed to create SkBlurImageFilter.");
1669 return;
1670 }
1671
1672 SkPaint paint;
robertphillips549c8992016-04-01 09:28:51 -07001673 paint.setImageFilter(std::move(blur));
bsalomon45eefcf2016-01-05 08:39:28 -08001674
1675 // This should not crash (http://crbug.com/570479).
1676 canvas->drawRect(SkRect::MakeIWH(largeW, largeH), paint);
1677}
1678
senorblanco21a465d2016-04-11 11:58:39 -07001679DEF_TEST(ImageFilterBlurLargeImage, reporter) {
reede8f30622016-03-23 18:59:25 -07001680 auto surface(SkSurface::MakeRaster(SkImageInfo::MakeN32Premul(100, 100)));
bsalomon45eefcf2016-01-05 08:39:28 -08001681 test_large_blur_input(reporter, surface->getCanvas());
1682}
1683
senorblanco5878dbd2016-05-19 14:50:29 -07001684static void test_make_with_filter(skiatest::Reporter* reporter, GrContext* context) {
1685 sk_sp<SkSurface> surface(create_surface(context, 100, 100));
1686 surface->getCanvas()->clear(SK_ColorRED);
1687 SkPaint bluePaint;
1688 bluePaint.setColor(SK_ColorBLUE);
1689 SkIRect subset = SkIRect::MakeXYWH(25, 20, 50, 50);
1690 surface->getCanvas()->drawRect(SkRect::Make(subset), bluePaint);
1691 sk_sp<SkImage> sourceImage = surface->makeImageSnapshot();
1692
1693 sk_sp<SkImageFilter> filter = make_grayscale(nullptr, nullptr);
1694 SkIRect clipBounds = SkIRect::MakeXYWH(30, 35, 100, 100);
1695 SkIRect outSubset;
1696 SkIPoint offset;
1697 sk_sp<SkImage> result;
1698
1699 result = sourceImage->makeWithFilter(nullptr, subset, clipBounds, &outSubset, &offset);
1700 REPORTER_ASSERT(reporter, !result);
1701
1702 result = sourceImage->makeWithFilter(filter.get(), subset, clipBounds, nullptr, &offset);
1703 REPORTER_ASSERT(reporter, !result);
1704
1705 result = sourceImage->makeWithFilter(filter.get(), subset, clipBounds, &outSubset, nullptr);
1706 REPORTER_ASSERT(reporter, !result);
1707
1708 SkIRect bigSubset = SkIRect::MakeXYWH(-10000, -10000, 20000, 20000);
1709 result = sourceImage->makeWithFilter(filter.get(), bigSubset, clipBounds, &outSubset, &offset);
1710 REPORTER_ASSERT(reporter, !result);
1711
1712 SkIRect empty = SkIRect::MakeEmpty();
1713 result = sourceImage->makeWithFilter(filter.get(), empty, clipBounds, &outSubset, &offset);
1714 REPORTER_ASSERT(reporter, !result);
1715
1716 result = sourceImage->makeWithFilter(filter.get(), subset, empty, &outSubset, &offset);
1717 REPORTER_ASSERT(reporter, !result);
1718
1719 SkIRect leftField = SkIRect::MakeXYWH(-1000, 0, 100, 100);
1720 result = sourceImage->makeWithFilter(filter.get(), subset, leftField, &outSubset, &offset);
1721 REPORTER_ASSERT(reporter, !result);
1722
1723 result = sourceImage->makeWithFilter(filter.get(), subset, clipBounds, &outSubset, &offset);
1724
1725 REPORTER_ASSERT(reporter, result);
1726 REPORTER_ASSERT(reporter, result->bounds().contains(outSubset));
1727 SkIRect destRect = SkIRect::MakeXYWH(offset.x(), offset.y(),
1728 outSubset.width(), outSubset.height());
1729 REPORTER_ASSERT(reporter, clipBounds.contains(destRect));
1730}
1731
1732DEF_TEST(ImageFilterMakeWithFilter, reporter) {
1733 test_make_with_filter(reporter, nullptr);
1734}
1735
1736#if SK_SUPPORT_GPU
1737DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterMakeWithFilter_Gpu, reporter, ctxInfo) {
1738 test_make_with_filter(reporter, ctxInfo.grContext());
1739}
1740#endif
1741
senorblanco@chromium.org58d14662014-02-03 22:36:39 +00001742#if SK_SUPPORT_GPU
reed4a8126e2014-09-22 07:29:03 -07001743
bsalomon68d91342016-04-12 09:59:58 -07001744DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterHugeBlur_Gpu, reporter, ctxInfo) {
robertphillipsefbffed2015-06-22 12:06:08 -07001745
bsalomon8b7451a2016-05-11 06:33:06 -07001746 sk_sp<SkSurface> surf(SkSurface::MakeRenderTarget(ctxInfo.grContext(),
robertphillips3e302272016-04-20 11:48:36 -07001747 SkBudgeted::kNo,
1748 SkImageInfo::MakeN32Premul(100, 100)));
robertphillips9a53fd72015-06-22 09:46:59 -07001749
robertphillips3e302272016-04-20 11:48:36 -07001750
1751 SkCanvas* canvas = surf->getCanvas();
1752
1753 test_huge_blur(canvas, reporter);
senorblanco@chromium.org09843fd2014-03-24 20:50:59 +00001754}
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001755
egdanielab527a52016-06-28 08:07:26 -07001756DEF_GPUTEST_FOR_RENDERING_CONTEXTS(XfermodeImageFilterCroppedInput_Gpu, reporter, ctxInfo) {
robertphillipsefbffed2015-06-22 12:06:08 -07001757
bsalomon8b7451a2016-05-11 06:33:06 -07001758 sk_sp<SkSurface> surf(SkSurface::MakeRenderTarget(ctxInfo.grContext(),
robertphillips3e302272016-04-20 11:48:36 -07001759 SkBudgeted::kNo,
1760 SkImageInfo::MakeN32Premul(1, 1)));
robertphillips9a53fd72015-06-22 09:46:59 -07001761
robertphillips3e302272016-04-20 11:48:36 -07001762
1763 SkCanvas* canvas = surf->getCanvas();
1764
1765 test_xfermode_cropped_input(canvas, reporter);
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001766}
senorblanco32673b92014-09-09 09:15:04 -07001767
egdanielab527a52016-06-28 08:07:26 -07001768DEF_GPUTEST_FOR_ALL_CONTEXTS(ImageFilterBlurLargeImage_Gpu, reporter, ctxInfo) {
bsalomon8b7451a2016-05-11 06:33:06 -07001769 auto surface(SkSurface::MakeRenderTarget(ctxInfo.grContext(), SkBudgeted::kYes,
reede8f30622016-03-23 18:59:25 -07001770 SkImageInfo::MakeN32Premul(100, 100)));
bsalomon45eefcf2016-01-05 08:39:28 -08001771 test_large_blur_input(reporter, surface->getCanvas());
1772}
senorblanco@chromium.org58d14662014-02-03 22:36:39 +00001773#endif
reedbb34a8a2016-04-23 15:19:07 -07001774
1775/*
1776 * Test that colorfilterimagefilter does not require its CTM to be decomposed when it has more
1777 * than just scale/translate, but that other filters do.
1778 */
reed96a04f32016-04-25 09:25:15 -07001779DEF_TEST(ImageFilterComplexCTM, reporter) {
reedbb34a8a2016-04-23 15:19:07 -07001780 // just need a colorfilter to exercise the corresponding imagefilter
1781 sk_sp<SkColorFilter> cf = SkColorFilter::MakeModeFilter(SK_ColorRED, SkXfermode::kSrcATop_Mode);
reed96a04f32016-04-25 09:25:15 -07001782 sk_sp<SkImageFilter> cfif = SkColorFilterImageFilter::Make(cf, nullptr); // can handle
1783 sk_sp<SkImageFilter> blif = SkBlurImageFilter::Make(3, 3, nullptr); // cannot handle
reedbb34a8a2016-04-23 15:19:07 -07001784
1785 struct {
1786 sk_sp<SkImageFilter> fFilter;
1787 bool fExpectCanHandle;
1788 } recs[] = {
1789 { cfif, true },
1790 { SkColorFilterImageFilter::Make(cf, cfif), true },
1791 { SkMergeImageFilter::Make(cfif, cfif), true },
reed96a04f32016-04-25 09:25:15 -07001792 { SkComposeImageFilter::Make(cfif, cfif), true },
1793
reedbb34a8a2016-04-23 15:19:07 -07001794 { blif, false },
reed96a04f32016-04-25 09:25:15 -07001795 { SkBlurImageFilter::Make(3, 3, cfif), false },
reedbb34a8a2016-04-23 15:19:07 -07001796 { SkColorFilterImageFilter::Make(cf, blif), false },
reed96a04f32016-04-25 09:25:15 -07001797 { SkMergeImageFilter::Make(cfif, blif), false },
1798 { SkComposeImageFilter::Make(blif, cfif), false },
reedbb34a8a2016-04-23 15:19:07 -07001799 };
1800
1801 for (const auto& rec : recs) {
reed96a04f32016-04-25 09:25:15 -07001802 const bool canHandle = rec.fFilter->canHandleComplexCTM();
reedbb34a8a2016-04-23 15:19:07 -07001803 REPORTER_ASSERT(reporter, canHandle == rec.fExpectCanHandle);
1804 }
1805}