blob: 54e9a60007e90f4658a601f6c1e016cffc4bb2a6 [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 {
reed9fa60da2014-08-21 07:59:51 -070068 this->INHERITED::flatten(buffer);
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +000069 buffer.writeFunctionPtr(fReporter);
70 buffer.writeMatrix(fExpectedMatrix);
71 }
72
73private:
robertphillips43c2ad42016-04-04 05:05:11 -070074 MatrixTestImageFilter(skiatest::Reporter* reporter, const SkMatrix& expectedMatrix)
75 : INHERITED(nullptr, 0, nullptr)
76 , fReporter(reporter)
77 , fExpectedMatrix(expectedMatrix) {
78 }
79
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +000080 skiatest::Reporter* fReporter;
81 SkMatrix fExpectedMatrix;
mtklein3f3b3d02014-12-01 11:47:08 -080082
reed9fa60da2014-08-21 07:59:51 -070083 typedef SkImageFilter INHERITED;
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +000084};
85
senorblanco6a93fa12016-04-05 04:43:45 -070086class FailImageFilter : public SkImageFilter {
87public:
robertphillips6b134732016-04-15 09:58:37 -070088 FailImageFilter() : SkImageFilter(nullptr, 0, nullptr) { }
senorblanco6a93fa12016-04-05 04:43:45 -070089
90 sk_sp<SkSpecialImage> onFilterImage(SkSpecialImage* source,
91 const Context& ctx,
92 SkIPoint* offset) const override {
93 return nullptr;
94 }
95
96 SK_TO_STRING_OVERRIDE()
97 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(FailImageFilter)
98
99private:
100 typedef SkImageFilter INHERITED;
101};
102
103sk_sp<SkFlattenable> FailImageFilter::CreateProc(SkReadBuffer& buffer) {
104 SK_IMAGEFILTER_UNFLATTEN_COMMON(common, 0);
105 return sk_sp<SkFlattenable>(new FailImageFilter());
106}
107
108#ifndef SK_IGNORE_TO_STRING
109void FailImageFilter::toString(SkString* str) const {
110 str->appendf("FailImageFilter: (");
111 str->append(")");
112}
113#endif
114
senorblanco297f7ce2016-03-23 13:44:26 -0700115void draw_gradient_circle(SkCanvas* canvas, int width, int height) {
116 SkScalar x = SkIntToScalar(width / 2);
117 SkScalar y = SkIntToScalar(height / 2);
118 SkScalar radius = SkMinScalar(x, y) * 0.8f;
119 canvas->clear(0x00000000);
120 SkColor colors[2];
121 colors[0] = SK_ColorWHITE;
122 colors[1] = SK_ColorBLACK;
123 sk_sp<SkShader> shader(
124 SkGradientShader::MakeRadial(SkPoint::Make(x, y), radius, colors, nullptr, 2,
125 SkShader::kClamp_TileMode)
126 );
127 SkPaint paint;
128 paint.setShader(shader);
129 canvas->drawCircle(x, y, radius, paint);
130}
131
132SkBitmap make_gradient_circle(int width, int height) {
133 SkBitmap bitmap;
134 bitmap.allocN32Pixels(width, height);
135 SkCanvas canvas(bitmap);
136 draw_gradient_circle(&canvas, width, height);
137 return bitmap;
138}
139
140class FilterList {
141public:
robertphillipsfc11b0a2016-04-05 09:09:36 -0700142 FilterList(sk_sp<SkImageFilter> input, const SkImageFilter::CropRect* cropRect = nullptr) {
senorblanco297f7ce2016-03-23 13:44:26 -0700143 SkPoint3 location = SkPoint3::Make(0, 0, SK_Scalar1);
senorblanco297f7ce2016-03-23 13:44:26 -0700144 const SkScalar five = SkIntToScalar(5);
145
robertphillips6e7025a2016-04-04 04:31:25 -0700146 {
147 sk_sp<SkColorFilter> cf(SkColorFilter::MakeModeFilter(SK_ColorRED,
148 SkXfermode::kSrcIn_Mode));
senorblanco297f7ce2016-03-23 13:44:26 -0700149
robertphillips6e7025a2016-04-04 04:31:25 -0700150 this->addFilter("color filter",
robertphillips12fa47d2016-04-08 16:28:09 -0700151 SkColorFilterImageFilter::Make(std::move(cf), input, cropRect));
robertphillips6e7025a2016-04-04 04:31:25 -0700152 }
senorblanco297f7ce2016-03-23 13:44:26 -0700153
robertphillips6e7025a2016-04-04 04:31:25 -0700154 {
155 sk_sp<SkImage> gradientImage(SkImage::MakeFromBitmap(make_gradient_circle(64, 64)));
156 sk_sp<SkImageFilter> gradientSource(SkImageSource::Make(std::move(gradientImage)));
senorblanco297f7ce2016-03-23 13:44:26 -0700157
robertphillips12fa47d2016-04-08 16:28:09 -0700158 this->addFilter("displacement map",
robertphillipsbfe11fc2016-04-15 07:17:36 -0700159 SkDisplacementMapEffect::Make(SkDisplacementMapEffect::kR_ChannelSelectorType,
160 SkDisplacementMapEffect::kB_ChannelSelectorType,
161 20.0f,
162 std::move(gradientSource), input, cropRect));
robertphillips6e7025a2016-04-04 04:31:25 -0700163 }
senorblanco297f7ce2016-03-23 13:44:26 -0700164
robertphillips6e7025a2016-04-04 04:31:25 -0700165 this->addFilter("blur", SkBlurImageFilter::Make(SK_Scalar1,
166 SK_Scalar1,
robertphillipsfc11b0a2016-04-05 09:09:36 -0700167 input,
robertphillips12fa47d2016-04-08 16:28:09 -0700168 cropRect));
robertphillipsc4169122016-04-06 08:40:59 -0700169 this->addFilter("drop shadow", SkDropShadowImageFilter::Make(
senorblanco297f7ce2016-03-23 13:44:26 -0700170 SK_Scalar1, SK_Scalar1, SK_Scalar1, SK_Scalar1, SK_ColorGREEN,
robertphillipsfc11b0a2016-04-05 09:09:36 -0700171 SkDropShadowImageFilter::kDrawShadowAndForeground_ShadowMode,
robertphillips12fa47d2016-04-08 16:28:09 -0700172 input, cropRect));
173 this->addFilter("diffuse lighting",
174 SkLightingImageFilter::MakePointLitDiffuse(location, SK_ColorGREEN, 0, 0,
175 input, cropRect));
senorblanco297f7ce2016-03-23 13:44:26 -0700176 this->addFilter("specular lighting",
robertphillips12fa47d2016-04-08 16:28:09 -0700177 SkLightingImageFilter::MakePointLitSpecular(location, SK_ColorGREEN, 0, 0, 0,
178 input, cropRect));
179 {
180 SkScalar kernel[9] = {
181 SkIntToScalar(1), SkIntToScalar(1), SkIntToScalar(1),
182 SkIntToScalar(1), SkIntToScalar(-7), SkIntToScalar(1),
183 SkIntToScalar(1), SkIntToScalar(1), SkIntToScalar(1),
184 };
185 const SkISize kernelSize = SkISize::Make(3, 3);
186 const SkScalar gain = SK_Scalar1, bias = 0;
187
188 this->addFilter("matrix convolution",
robertphillipsef6a47b2016-04-08 08:01:20 -0700189 SkMatrixConvolutionImageFilter::Make(
senorblanco297f7ce2016-03-23 13:44:26 -0700190 kernelSize, kernel, gain, bias, SkIPoint::Make(1, 1),
robertphillipsfc11b0a2016-04-05 09:09:36 -0700191 SkMatrixConvolutionImageFilter::kRepeat_TileMode, false,
robertphillips12fa47d2016-04-08 16:28:09 -0700192 input, cropRect));
193 }
194
robertphillipsfc11b0a2016-04-05 09:09:36 -0700195 this->addFilter("merge", SkMergeImageFilter::Make(input, input,
robertphillips2238c9d2016-03-30 13:34:16 -0700196 SkXfermode::kSrcOver_Mode,
robertphillips12fa47d2016-04-08 16:28:09 -0700197 cropRect));
198
robertphillips6e7025a2016-04-04 04:31:25 -0700199 {
200 SkPaint greenColorShaderPaint;
201 greenColorShaderPaint.setShader(SkShader::MakeColorShader(SK_ColorGREEN));
202
203 SkImageFilter::CropRect leftSideCropRect(SkRect::MakeXYWH(0, 0, 32, 64));
204 sk_sp<SkImageFilter> paintFilterLeft(SkPaintImageFilter::Make(greenColorShaderPaint,
205 &leftSideCropRect));
206 SkImageFilter::CropRect rightSideCropRect(SkRect::MakeXYWH(32, 0, 32, 64));
207 sk_sp<SkImageFilter> paintFilterRight(SkPaintImageFilter::Make(greenColorShaderPaint,
208 &rightSideCropRect));
209
210
211 this->addFilter("merge with disjoint inputs", SkMergeImageFilter::Make(
robertphillips2238c9d2016-03-30 13:34:16 -0700212 std::move(paintFilterLeft), std::move(paintFilterRight),
robertphillips12fa47d2016-04-08 16:28:09 -0700213 SkXfermode::kSrcOver_Mode, cropRect));
robertphillips6e7025a2016-04-04 04:31:25 -0700214 }
215
senorblanco297f7ce2016-03-23 13:44:26 -0700216 this->addFilter("offset",
robertphillipsfc11b0a2016-04-05 09:09:36 -0700217 SkOffsetImageFilter::Make(SK_Scalar1, SK_Scalar1, input,
robertphillips12fa47d2016-04-08 16:28:09 -0700218 cropRect));
219 this->addFilter("dilate", SkDilateImageFilter::Make(3, 2, input, cropRect));
220 this->addFilter("erode", SkErodeImageFilter::Make(2, 3, input, cropRect));
robertphillips534c2702016-04-15 07:57:40 -0700221 this->addFilter("tile", SkTileImageFilter::Make(
222 SkRect::MakeXYWH(0, 0, 50, 50),
223 cropRect ? cropRect->rect() : SkRect::MakeXYWH(0, 0, 100, 100),
224 input));
robertphillips6e7025a2016-04-04 04:31:25 -0700225
robertphillips12fa47d2016-04-08 16:28:09 -0700226 if (!cropRect) {
227 SkMatrix matrix;
228
229 matrix.setTranslate(SK_Scalar1, SK_Scalar1);
230 matrix.postRotate(SkIntToScalar(45), SK_Scalar1, SK_Scalar1);
231
232 this->addFilter("matrix",
233 SkImageFilter::MakeMatrixFilter(matrix, kLow_SkFilterQuality, input));
234 }
robertphillips6e7025a2016-04-04 04:31:25 -0700235 {
robertphillipsfc11b0a2016-04-05 09:09:36 -0700236 sk_sp<SkImageFilter> blur(SkBlurImageFilter::Make(five, five, input));
robertphillips6e7025a2016-04-04 04:31:25 -0700237
238 this->addFilter("blur and offset", SkOffsetImageFilter::Make(five, five,
239 std::move(blur),
robertphillips12fa47d2016-04-08 16:28:09 -0700240 cropRect));
robertphillips6e7025a2016-04-04 04:31:25 -0700241 }
242 {
243 SkRTreeFactory factory;
244 SkPictureRecorder recorder;
245 SkCanvas* recordingCanvas = recorder.beginRecording(64, 64, &factory, 0);
246
247 SkPaint greenPaint;
248 greenPaint.setColor(SK_ColorGREEN);
249 recordingCanvas->drawRect(SkRect::Make(SkIRect::MakeXYWH(10, 10, 30, 20)), greenPaint);
250 sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture());
251 sk_sp<SkImageFilter> pictureFilter(SkPictureImageFilter::Make(std::move(picture)));
252
253 this->addFilter("picture and blur", SkBlurImageFilter::Make(five, five,
254 std::move(pictureFilter),
robertphillips12fa47d2016-04-08 16:28:09 -0700255 cropRect));
robertphillips6e7025a2016-04-04 04:31:25 -0700256 }
257 {
258 SkPaint paint;
259 paint.setShader(SkPerlinNoiseShader::MakeTurbulence(SK_Scalar1, SK_Scalar1, 1, 0));
260 sk_sp<SkImageFilter> paintFilter(SkPaintImageFilter::Make(paint));
261
262 this->addFilter("paint and blur", SkBlurImageFilter::Make(five, five,
263 std::move(paintFilter),
robertphillips12fa47d2016-04-08 16:28:09 -0700264 cropRect));
robertphillips6e7025a2016-04-04 04:31:25 -0700265 }
reedcfb6bdf2016-03-29 11:32:50 -0700266 this->addFilter("xfermode", SkXfermodeImageFilter::Make(
robertphillips12fa47d2016-04-08 16:28:09 -0700267 SkXfermode::Make(SkXfermode::kSrc_Mode), input, input, cropRect));
senorblanco297f7ce2016-03-23 13:44:26 -0700268 }
269 int count() const { return fFilters.count(); }
270 SkImageFilter* getFilter(int index) const { return fFilters[index].fFilter.get(); }
271 const char* getName(int index) const { return fFilters[index].fName; }
272private:
273 struct Filter {
robertphillips12fa47d2016-04-08 16:28:09 -0700274 Filter() : fName(nullptr) {}
275 Filter(const char* name, sk_sp<SkImageFilter> filter)
276 : fName(name)
277 , fFilter(std::move(filter)) {
278 }
senorblanco297f7ce2016-03-23 13:44:26 -0700279 const char* fName;
280 sk_sp<SkImageFilter> fFilter;
281 };
robertphillips12fa47d2016-04-08 16:28:09 -0700282 void addFilter(const char* name, sk_sp<SkImageFilter> filter) {
283 fFilters.push_back(Filter(name, std::move(filter)));
senorblanco297f7ce2016-03-23 13:44:26 -0700284 }
285
286 SkTArray<Filter> fFilters;
287};
288
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +0000289}
290
reed60c9b582016-04-03 09:11:13 -0700291sk_sp<SkFlattenable> MatrixTestImageFilter::CreateProc(SkReadBuffer& buffer) {
reed9fa60da2014-08-21 07:59:51 -0700292 SK_IMAGEFILTER_UNFLATTEN_COMMON(common, 1);
293 skiatest::Reporter* reporter = (skiatest::Reporter*)buffer.readFunctionPtr();
294 SkMatrix matrix;
295 buffer.readMatrix(&matrix);
robertphillips43c2ad42016-04-04 05:05:11 -0700296 return MatrixTestImageFilter::Make(reporter, matrix);
reed9fa60da2014-08-21 07:59:51 -0700297}
298
robertphillipsf3f5bad2014-12-19 13:49:15 -0800299#ifndef SK_IGNORE_TO_STRING
300void MatrixTestImageFilter::toString(SkString* str) const {
301 str->appendf("MatrixTestImageFilter: (");
302 str->append(")");
303}
304#endif
305
reed9ce9d672016-03-17 10:51:11 -0700306static sk_sp<SkImage> make_small_image() {
reede8f30622016-03-23 18:59:25 -0700307 auto surface(SkSurface::MakeRasterN32Premul(kBitmapSize, kBitmapSize));
fmalita5598b632015-09-15 11:26:13 -0700308 SkCanvas* canvas = surface->getCanvas();
309 canvas->clear(0x00000000);
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000310 SkPaint darkPaint;
311 darkPaint.setColor(0xFF804020);
312 SkPaint lightPaint;
313 lightPaint.setColor(0xFF244484);
314 const int i = kBitmapSize / 4;
315 for (int y = 0; y < kBitmapSize; y += i) {
316 for (int x = 0; x < kBitmapSize; x += i) {
fmalita5598b632015-09-15 11:26:13 -0700317 canvas->save();
318 canvas->translate(SkIntToScalar(x), SkIntToScalar(y));
319 canvas->drawRect(SkRect::MakeXYWH(0, 0,
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000320 SkIntToScalar(i),
321 SkIntToScalar(i)), darkPaint);
fmalita5598b632015-09-15 11:26:13 -0700322 canvas->drawRect(SkRect::MakeXYWH(SkIntToScalar(i),
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000323 0,
324 SkIntToScalar(i),
325 SkIntToScalar(i)), lightPaint);
fmalita5598b632015-09-15 11:26:13 -0700326 canvas->drawRect(SkRect::MakeXYWH(0,
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000327 SkIntToScalar(i),
328 SkIntToScalar(i),
329 SkIntToScalar(i)), lightPaint);
fmalita5598b632015-09-15 11:26:13 -0700330 canvas->drawRect(SkRect::MakeXYWH(SkIntToScalar(i),
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000331 SkIntToScalar(i),
332 SkIntToScalar(i),
333 SkIntToScalar(i)), darkPaint);
fmalita5598b632015-09-15 11:26:13 -0700334 canvas->restore();
commit-bot@chromium.org4b681bc2013-09-13 12:40:02 +0000335 }
336 }
fmalita5598b632015-09-15 11:26:13 -0700337
reed9ce9d672016-03-17 10:51:11 -0700338 return surface->makeImageSnapshot();
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000339}
senorblanco@chromium.org194d7752013-07-24 22:19:24 +0000340
robertphillips5605b562016-04-05 11:50:42 -0700341static sk_sp<SkImageFilter> make_scale(float amount, sk_sp<SkImageFilter> input) {
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000342 SkScalar s = amount;
343 SkScalar matrix[20] = { s, 0, 0, 0, 0,
344 0, s, 0, 0, 0,
345 0, 0, s, 0, 0,
346 0, 0, 0, s, 0 };
robertphillips5605b562016-04-05 11:50:42 -0700347 sk_sp<SkColorFilter> filter(SkColorFilter::MakeMatrixFilterRowMajor255(matrix));
348 return SkColorFilterImageFilter::Make(std::move(filter), std::move(input));
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000349}
350
robertphillips5605b562016-04-05 11:50:42 -0700351static sk_sp<SkImageFilter> make_grayscale(sk_sp<SkImageFilter> input,
352 const SkImageFilter::CropRect* cropRect) {
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000353 SkScalar matrix[20];
354 memset(matrix, 0, 20 * sizeof(SkScalar));
355 matrix[0] = matrix[5] = matrix[10] = 0.2126f;
356 matrix[1] = matrix[6] = matrix[11] = 0.7152f;
357 matrix[2] = matrix[7] = matrix[12] = 0.0722f;
358 matrix[18] = 1.0f;
robertphillips5605b562016-04-05 11:50:42 -0700359 sk_sp<SkColorFilter> filter(SkColorFilter::MakeMatrixFilterRowMajor255(matrix));
360 return SkColorFilterImageFilter::Make(std::move(filter), std::move(input), cropRect);
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000361}
362
robertphillips5605b562016-04-05 11:50:42 -0700363static sk_sp<SkImageFilter> make_blue(sk_sp<SkImageFilter> input,
364 const SkImageFilter::CropRect* cropRect) {
365 sk_sp<SkColorFilter> filter(SkColorFilter::MakeModeFilter(SK_ColorBLUE,
366 SkXfermode::kSrcIn_Mode));
367 return SkColorFilterImageFilter::Make(std::move(filter), std::move(input), cropRect);
reedcedc36f2015-03-08 04:42:52 -0700368}
369
robertphillips3e302272016-04-20 11:48:36 -0700370static sk_sp<SkSpecialSurface> create_empty_special_surface(GrContext* context, int widthHeight) {
robertphillipsc91fd342016-04-25 12:32:54 -0700371#if SK_SUPPORT_GPU
robertphillips4418dba2016-03-07 12:45:14 -0800372 if (context) {
373 GrSurfaceDesc desc;
374 desc.fConfig = kSkia8888_GrPixelConfig;
375 desc.fFlags = kRenderTarget_GrSurfaceFlag;
376 desc.fWidth = widthHeight;
377 desc.fHeight = widthHeight;
robertphillips3e302272016-04-20 11:48:36 -0700378 return SkSpecialSurface::MakeRenderTarget(context, desc);
robertphillipsc91fd342016-04-25 12:32:54 -0700379 } else
380#endif
381 {
robertphillips4418dba2016-03-07 12:45:14 -0800382 const SkImageInfo info = SkImageInfo::MakeN32(widthHeight, widthHeight,
383 kOpaque_SkAlphaType);
robertphillips3e302272016-04-20 11:48:36 -0700384 return SkSpecialSurface::MakeRaster(info);
robertphillips4418dba2016-03-07 12:45:14 -0800385 }
senorblancobf680c32016-03-16 16:15:53 -0700386}
387
robertphillips3e302272016-04-20 11:48:36 -0700388static sk_sp<SkSpecialImage> create_empty_special_image(GrContext* context, int widthHeight) {
389 sk_sp<SkSpecialSurface> surf(create_empty_special_surface(context, widthHeight));
robertphillips4418dba2016-03-07 12:45:14 -0800390
391 SkASSERT(surf);
392
393 SkCanvas* canvas = surf->getCanvas();
394 SkASSERT(canvas);
395
396 canvas->clear(0x0);
397
robertphillips37bd7c32016-03-17 14:31:39 -0700398 return surf->makeImageSnapshot();
robertphillips4418dba2016-03-07 12:45:14 -0800399}
400
401
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000402DEF_TEST(ImageFilter, reporter) {
403 {
reedcedc36f2015-03-08 04:42:52 -0700404 // Check that two non-clipping color-matrice-filters concatenate into a single filter.
robertphillips5605b562016-04-05 11:50:42 -0700405 sk_sp<SkImageFilter> halfBrightness(make_scale(0.5f, nullptr));
406 sk_sp<SkImageFilter> quarterBrightness(make_scale(0.5f, std::move(halfBrightness)));
halcanary96fcdcc2015-08-27 07:41:13 -0700407 REPORTER_ASSERT(reporter, nullptr == quarterBrightness->getInput(0));
reedcedc36f2015-03-08 04:42:52 -0700408 SkColorFilter* cf;
409 REPORTER_ASSERT(reporter, quarterBrightness->asColorFilter(&cf));
halcanary96fcdcc2015-08-27 07:41:13 -0700410 REPORTER_ASSERT(reporter, cf->asColorMatrix(nullptr));
reedcedc36f2015-03-08 04:42:52 -0700411 cf->unref();
senorblanco@chromium.org194d7752013-07-24 22:19:24 +0000412 }
413
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000414 {
reedcedc36f2015-03-08 04:42:52 -0700415 // Check that a clipping color-matrice-filter followed by a color-matrice-filters
416 // concatenates into a single filter, but not a matrixfilter (due to clamping).
robertphillips5605b562016-04-05 11:50:42 -0700417 sk_sp<SkImageFilter> doubleBrightness(make_scale(2.0f, nullptr));
418 sk_sp<SkImageFilter> halfBrightness(make_scale(0.5f, std::move(doubleBrightness)));
halcanary96fcdcc2015-08-27 07:41:13 -0700419 REPORTER_ASSERT(reporter, nullptr == halfBrightness->getInput(0));
reedcedc36f2015-03-08 04:42:52 -0700420 SkColorFilter* cf;
421 REPORTER_ASSERT(reporter, halfBrightness->asColorFilter(&cf));
halcanary96fcdcc2015-08-27 07:41:13 -0700422 REPORTER_ASSERT(reporter, !cf->asColorMatrix(nullptr));
reedcedc36f2015-03-08 04:42:52 -0700423 cf->unref();
senorblanco@chromium.org194d7752013-07-24 22:19:24 +0000424 }
425
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000426 {
427 // Check that a color filter image filter without a crop rect can be
428 // expressed as a color filter.
robertphillips5605b562016-04-05 11:50:42 -0700429 sk_sp<SkImageFilter> gray(make_grayscale(nullptr, nullptr));
halcanary96fcdcc2015-08-27 07:41:13 -0700430 REPORTER_ASSERT(reporter, true == gray->asColorFilter(nullptr));
senorblanco@chromium.org194d7752013-07-24 22:19:24 +0000431 }
mtklein2afbe232016-02-07 12:23:10 -0800432
reedcedc36f2015-03-08 04:42:52 -0700433 {
434 // Check that a colorfilterimage filter without a crop rect but with an input
435 // that is another colorfilterimage can be expressed as a colorfilter (composed).
robertphillips5605b562016-04-05 11:50:42 -0700436 sk_sp<SkImageFilter> mode(make_blue(nullptr, nullptr));
437 sk_sp<SkImageFilter> gray(make_grayscale(std::move(mode), nullptr));
halcanary96fcdcc2015-08-27 07:41:13 -0700438 REPORTER_ASSERT(reporter, true == gray->asColorFilter(nullptr));
reedcedc36f2015-03-08 04:42:52 -0700439 }
440
441 {
442 // Test that if we exceed the limit of what ComposeColorFilter can combine, we still
443 // can build the DAG and won't assert if we call asColorFilter.
robertphillips5605b562016-04-05 11:50:42 -0700444 sk_sp<SkImageFilter> filter(make_blue(nullptr, nullptr));
reedcedc36f2015-03-08 04:42:52 -0700445 const int kWayTooManyForComposeColorFilter = 100;
446 for (int i = 0; i < kWayTooManyForComposeColorFilter; ++i) {
robertphillips5605b562016-04-05 11:50:42 -0700447 filter = make_blue(filter, nullptr);
reedcedc36f2015-03-08 04:42:52 -0700448 // the first few of these will succeed, but after we hit the internal limit,
449 // it will then return false.
halcanary96fcdcc2015-08-27 07:41:13 -0700450 (void)filter->asColorFilter(nullptr);
reedcedc36f2015-03-08 04:42:52 -0700451 }
452 }
reed5c518a82015-03-05 14:47:29 -0800453
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000454 {
455 // Check that a color filter image filter with a crop rect cannot
456 // be expressed as a color filter.
457 SkImageFilter::CropRect cropRect(SkRect::MakeXYWH(0, 0, 100, 100));
robertphillips5605b562016-04-05 11:50:42 -0700458 sk_sp<SkImageFilter> grayWithCrop(make_grayscale(nullptr, &cropRect));
halcanary96fcdcc2015-08-27 07:41:13 -0700459 REPORTER_ASSERT(reporter, false == grayWithCrop->asColorFilter(nullptr));
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000460 }
461
462 {
senorblanco3df05012014-07-03 11:13:09 -0700463 // Check that two non-commutative matrices are concatenated in
464 // the correct order.
465 SkScalar blueToRedMatrix[20] = { 0 };
466 blueToRedMatrix[2] = blueToRedMatrix[18] = SK_Scalar1;
467 SkScalar redToGreenMatrix[20] = { 0 };
468 redToGreenMatrix[5] = redToGreenMatrix[18] = SK_Scalar1;
robertphillips5605b562016-04-05 11:50:42 -0700469 sk_sp<SkColorFilter> blueToRed(SkColorFilter::MakeMatrixFilterRowMajor255(blueToRedMatrix));
470 sk_sp<SkImageFilter> filter1(SkColorFilterImageFilter::Make(std::move(blueToRed),
471 nullptr));
472 sk_sp<SkColorFilter> redToGreen(SkColorFilter::MakeMatrixFilterRowMajor255(redToGreenMatrix));
473 sk_sp<SkImageFilter> filter2(SkColorFilterImageFilter::Make(std::move(redToGreen),
474 std::move(filter1)));
senorblanco3df05012014-07-03 11:13:09 -0700475
476 SkBitmap result;
477 result.allocN32Pixels(kBitmapSize, kBitmapSize);
478
479 SkPaint paint;
480 paint.setColor(SK_ColorBLUE);
robertphillips5605b562016-04-05 11:50:42 -0700481 paint.setImageFilter(std::move(filter2));
senorblanco3df05012014-07-03 11:13:09 -0700482 SkCanvas canvas(result);
483 canvas.clear(0x0);
484 SkRect rect = SkRect::Make(SkIRect::MakeWH(kBitmapSize, kBitmapSize));
485 canvas.drawRect(rect, paint);
486 uint32_t pixel = *result.getAddr32(0, 0);
487 // The result here should be green, since we have effectively shifted blue to green.
488 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
489 }
490
491 {
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000492 // Tests pass by not asserting
reed9ce9d672016-03-17 10:51:11 -0700493 sk_sp<SkImage> image(make_small_image());
fmalita5598b632015-09-15 11:26:13 -0700494 SkBitmap result;
mike@reedtribe.orgdeee4962014-02-13 14:41:43 +0000495 result.allocN32Pixels(kBitmapSize, kBitmapSize);
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000496
senorblanco@chromium.org194d7752013-07-24 22:19:24 +0000497 {
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000498 // This tests for :
499 // 1 ) location at (0,0,1)
robertphillips3d32d762015-07-13 13:16:44 -0700500 SkPoint3 location = SkPoint3::Make(0, 0, SK_Scalar1);
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000501 // 2 ) location and target at same value
robertphillips3d32d762015-07-13 13:16:44 -0700502 SkPoint3 target = SkPoint3::Make(location.fX, location.fY, location.fZ);
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000503 // 3 ) large negative specular exponent value
504 SkScalar specularExponent = -1000;
505
robertphillips549c8992016-04-01 09:28:51 -0700506 sk_sp<SkImageFilter> bmSrc(SkImageSource::Make(std::move(image)));
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000507 SkPaint paint;
robertphillips12fa47d2016-04-08 16:28:09 -0700508 paint.setImageFilter(SkLightingImageFilter::MakeSpotLitSpecular(
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000509 location, target, specularExponent, 180,
510 0xFFFFFFFF, SK_Scalar1, SK_Scalar1, SK_Scalar1,
robertphillips12fa47d2016-04-08 16:28:09 -0700511 std::move(bmSrc)));
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000512 SkCanvas canvas(result);
513 SkRect r = SkRect::MakeWH(SkIntToScalar(kBitmapSize),
514 SkIntToScalar(kBitmapSize));
515 canvas.drawRect(r, paint);
senorblanco@chromium.org194d7752013-07-24 22:19:24 +0000516 }
senorblanco@chromium.org194d7752013-07-24 22:19:24 +0000517 }
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +0000518}
senorblanco@chromium.org6776b822014-01-03 21:48:22 +0000519
robertphillips3e302272016-04-20 11:48:36 -0700520static void test_crop_rects(skiatest::Reporter* reporter,
robertphillips4418dba2016-03-07 12:45:14 -0800521 GrContext* context) {
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +0000522 // Check that all filters offset to their absolute crop rect,
523 // unaffected by the input crop rect.
524 // Tests pass by not asserting.
robertphillips3e302272016-04-20 11:48:36 -0700525 sk_sp<SkSpecialImage> srcImg(create_empty_special_image(context, 100));
robertphillips4418dba2016-03-07 12:45:14 -0800526 SkASSERT(srcImg);
senorblanco@chromium.org6776b822014-01-03 21:48:22 +0000527
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +0000528 SkImageFilter::CropRect inputCropRect(SkRect::MakeXYWH(8, 13, 80, 80));
529 SkImageFilter::CropRect cropRect(SkRect::MakeXYWH(20, 30, 60, 60));
robertphillipsfc11b0a2016-04-05 09:09:36 -0700530 sk_sp<SkImageFilter> input(make_grayscale(nullptr, &inputCropRect));
senorblanco@chromium.org6776b822014-01-03 21:48:22 +0000531
robertphillipsfc11b0a2016-04-05 09:09:36 -0700532 FilterList filters(input, &cropRect);
senorblanco@chromium.org6776b822014-01-03 21:48:22 +0000533
senorblanco297f7ce2016-03-23 13:44:26 -0700534 for (int i = 0; i < filters.count(); ++i) {
535 SkImageFilter* filter = filters.getFilter(i);
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +0000536 SkIPoint offset;
reed4e23cda2016-01-11 10:56:59 -0800537 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeWH(100, 100), nullptr);
robertphillips2302de92016-03-24 07:26:32 -0700538 sk_sp<SkSpecialImage> resultImg(filter->filterImage(srcImg.get(), ctx, &offset));
senorblanco297f7ce2016-03-23 13:44:26 -0700539 REPORTER_ASSERT_MESSAGE(reporter, resultImg, filters.getName(i));
540 REPORTER_ASSERT_MESSAGE(reporter, offset.fX == 20 && offset.fY == 30, filters.getName(i));
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +0000541 }
542}
543
robertphillips3e302272016-04-20 11:48:36 -0700544static void test_negative_blur_sigma(skiatest::Reporter* reporter,
robertphillips4418dba2016-03-07 12:45:14 -0800545 GrContext* context) {
senorblanco32673b92014-09-09 09:15:04 -0700546 // Check that SkBlurImageFilter will accept a negative sigma, either in
547 // the given arguments or after CTM application.
reed5ea95df2015-10-06 14:05:32 -0700548 const int width = 32, height = 32;
549 const SkScalar five = SkIntToScalar(5);
senorblanco32673b92014-09-09 09:15:04 -0700550
robertphillips6e7025a2016-04-04 04:31:25 -0700551 sk_sp<SkImageFilter> positiveFilter(SkBlurImageFilter::Make(five, five, nullptr));
552 sk_sp<SkImageFilter> negativeFilter(SkBlurImageFilter::Make(-five, five, nullptr));
senorblanco32673b92014-09-09 09:15:04 -0700553
554 SkBitmap gradient = make_gradient_circle(width, height);
robertphillips3e302272016-04-20 11:48:36 -0700555 sk_sp<SkSpecialImage> imgSrc(SkSpecialImage::MakeFromRaster(SkIRect::MakeWH(width, height),
robertphillips37bd7c32016-03-17 14:31:39 -0700556 gradient));
robertphillips4418dba2016-03-07 12:45:14 -0800557
senorblanco32673b92014-09-09 09:15:04 -0700558 SkIPoint offset;
reed4e23cda2016-01-11 10:56:59 -0800559 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeWH(32, 32), nullptr);
robertphillips4418dba2016-03-07 12:45:14 -0800560
robertphillips2302de92016-03-24 07:26:32 -0700561 sk_sp<SkSpecialImage> positiveResult1(positiveFilter->filterImage(imgSrc.get(), ctx, &offset));
robertphillips4418dba2016-03-07 12:45:14 -0800562 REPORTER_ASSERT(reporter, positiveResult1);
563
robertphillips2302de92016-03-24 07:26:32 -0700564 sk_sp<SkSpecialImage> negativeResult1(negativeFilter->filterImage(imgSrc.get(), ctx, &offset));
robertphillips4418dba2016-03-07 12:45:14 -0800565 REPORTER_ASSERT(reporter, negativeResult1);
566
senorblanco32673b92014-09-09 09:15:04 -0700567 SkMatrix negativeScale;
568 negativeScale.setScale(-SK_Scalar1, SK_Scalar1);
reed4e23cda2016-01-11 10:56:59 -0800569 SkImageFilter::Context negativeCTX(negativeScale, SkIRect::MakeWH(32, 32), nullptr);
robertphillips4418dba2016-03-07 12:45:14 -0800570
robertphillips2302de92016-03-24 07:26:32 -0700571 sk_sp<SkSpecialImage> negativeResult2(positiveFilter->filterImage(imgSrc.get(),
572 negativeCTX,
573 &offset));
robertphillips4418dba2016-03-07 12:45:14 -0800574 REPORTER_ASSERT(reporter, negativeResult2);
575
robertphillips2302de92016-03-24 07:26:32 -0700576 sk_sp<SkSpecialImage> positiveResult2(negativeFilter->filterImage(imgSrc.get(),
577 negativeCTX,
578 &offset));
robertphillips4418dba2016-03-07 12:45:14 -0800579 REPORTER_ASSERT(reporter, positiveResult2);
580
581
582 SkBitmap positiveResultBM1, positiveResultBM2;
583 SkBitmap negativeResultBM1, negativeResultBM2;
584
robertphillips64612512016-04-08 12:10:42 -0700585 REPORTER_ASSERT(reporter, positiveResult1->getROPixels(&positiveResultBM1));
586 REPORTER_ASSERT(reporter, positiveResult2->getROPixels(&positiveResultBM2));
587 REPORTER_ASSERT(reporter, negativeResult1->getROPixels(&negativeResultBM1));
588 REPORTER_ASSERT(reporter, negativeResult2->getROPixels(&negativeResultBM2));
robertphillips4418dba2016-03-07 12:45:14 -0800589
590 SkAutoLockPixels lockP1(positiveResultBM1);
591 SkAutoLockPixels lockP2(positiveResultBM2);
592 SkAutoLockPixels lockN1(negativeResultBM1);
593 SkAutoLockPixels lockN2(negativeResultBM2);
senorblanco32673b92014-09-09 09:15:04 -0700594 for (int y = 0; y < height; y++) {
robertphillips4418dba2016-03-07 12:45:14 -0800595 int diffs = memcmp(positiveResultBM1.getAddr32(0, y),
596 negativeResultBM1.getAddr32(0, y),
597 positiveResultBM1.rowBytes());
senorblanco32673b92014-09-09 09:15:04 -0700598 REPORTER_ASSERT(reporter, !diffs);
599 if (diffs) {
600 break;
601 }
robertphillips4418dba2016-03-07 12:45:14 -0800602 diffs = memcmp(positiveResultBM1.getAddr32(0, y),
603 negativeResultBM2.getAddr32(0, y),
604 positiveResultBM1.rowBytes());
senorblanco32673b92014-09-09 09:15:04 -0700605 REPORTER_ASSERT(reporter, !diffs);
606 if (diffs) {
607 break;
608 }
robertphillips4418dba2016-03-07 12:45:14 -0800609 diffs = memcmp(positiveResultBM1.getAddr32(0, y),
610 positiveResultBM2.getAddr32(0, y),
611 positiveResultBM1.rowBytes());
senorblanco32673b92014-09-09 09:15:04 -0700612 REPORTER_ASSERT(reporter, !diffs);
613 if (diffs) {
614 break;
615 }
616 }
617}
618
senorblanco21a465d2016-04-11 11:58:39 -0700619DEF_TEST(ImageFilterNegativeBlurSigma, reporter) {
robertphillips3e302272016-04-20 11:48:36 -0700620 test_negative_blur_sigma(reporter, nullptr);
robertphillips4418dba2016-03-07 12:45:14 -0800621}
622
623#if SK_SUPPORT_GPU
bsalomon68d91342016-04-12 09:59:58 -0700624DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterNegativeBlurSigma_Gpu, reporter, ctxInfo) {
robertphillips3e302272016-04-20 11:48:36 -0700625 test_negative_blur_sigma(reporter, ctxInfo.fGrContext);
robertphillips4418dba2016-03-07 12:45:14 -0800626}
627#endif
628
robertphillips3e302272016-04-20 11:48:36 -0700629static void test_zero_blur_sigma(skiatest::Reporter* reporter, GrContext* context) {
senorblancobf680c32016-03-16 16:15:53 -0700630 // Check that SkBlurImageFilter with a zero sigma and a non-zero srcOffset works correctly.
631 SkImageFilter::CropRect cropRect(SkRect::Make(SkIRect::MakeXYWH(5, 0, 5, 10)));
robertphillips51a315e2016-03-31 09:05:49 -0700632 sk_sp<SkImageFilter> input(SkOffsetImageFilter::Make(0, 0, nullptr, &cropRect));
robertphillips6e7025a2016-04-04 04:31:25 -0700633 sk_sp<SkImageFilter> filter(SkBlurImageFilter::Make(0, 0, std::move(input), &cropRect));
senorblancobf680c32016-03-16 16:15:53 -0700634
robertphillips3e302272016-04-20 11:48:36 -0700635 sk_sp<SkSpecialSurface> surf(create_empty_special_surface(context, 10));
senorblancobf680c32016-03-16 16:15:53 -0700636 surf->getCanvas()->clear(SK_ColorGREEN);
robertphillips37bd7c32016-03-17 14:31:39 -0700637 sk_sp<SkSpecialImage> image(surf->makeImageSnapshot());
senorblancobf680c32016-03-16 16:15:53 -0700638
639 SkIPoint offset;
640 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeWH(32, 32), nullptr);
641
robertphillips2302de92016-03-24 07:26:32 -0700642 sk_sp<SkSpecialImage> result(filter->filterImage(image.get(), ctx, &offset));
senorblancobf680c32016-03-16 16:15:53 -0700643 REPORTER_ASSERT(reporter, offset.fX == 5 && offset.fY == 0);
644 REPORTER_ASSERT(reporter, result);
645 REPORTER_ASSERT(reporter, result->width() == 5 && result->height() == 10);
646
647 SkBitmap resultBM;
648
robertphillips64612512016-04-08 12:10:42 -0700649 REPORTER_ASSERT(reporter, result->getROPixels(&resultBM));
senorblancobf680c32016-03-16 16:15:53 -0700650
651 SkAutoLockPixels lock(resultBM);
652 for (int y = 0; y < resultBM.height(); y++) {
653 for (int x = 0; x < resultBM.width(); x++) {
654 bool diff = *resultBM.getAddr32(x, y) != SK_ColorGREEN;
655 REPORTER_ASSERT(reporter, !diff);
656 if (diff) {
657 break;
658 }
659 }
660 }
661}
662
senorblanco21a465d2016-04-11 11:58:39 -0700663DEF_TEST(ImageFilterZeroBlurSigma, reporter) {
robertphillips3e302272016-04-20 11:48:36 -0700664 test_zero_blur_sigma(reporter, nullptr);
senorblancobf680c32016-03-16 16:15:53 -0700665}
666
667#if SK_SUPPORT_GPU
bsalomon68d91342016-04-12 09:59:58 -0700668DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterZeroBlurSigma_Gpu, reporter, ctxInfo) {
robertphillips3e302272016-04-20 11:48:36 -0700669 test_zero_blur_sigma(reporter, ctxInfo.fGrContext);
senorblancobf680c32016-03-16 16:15:53 -0700670}
671#endif
672
senorblanco6a93fa12016-04-05 04:43:45 -0700673
674// Tests that, even when an upstream filter has returned null (due to failure or clipping), a
675// downstream filter that affects transparent black still does so even with a nullptr input.
robertphillips3e302272016-04-20 11:48:36 -0700676static void test_fail_affects_transparent_black(skiatest::Reporter* reporter, GrContext* context) {
senorblanco6a93fa12016-04-05 04:43:45 -0700677 sk_sp<FailImageFilter> failFilter(new FailImageFilter());
robertphillips3e302272016-04-20 11:48:36 -0700678 sk_sp<SkSpecialImage> source(create_empty_special_image(context, 5));
senorblanco6a93fa12016-04-05 04:43:45 -0700679 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeXYWH(0, 0, 1, 1), nullptr);
680 sk_sp<SkColorFilter> green(SkColorFilter::MakeModeFilter(SK_ColorGREEN, SkXfermode::kSrc_Mode));
681 SkASSERT(green->affectsTransparentBlack());
robertphillips5605b562016-04-05 11:50:42 -0700682 sk_sp<SkImageFilter> greenFilter(SkColorFilterImageFilter::Make(std::move(green),
683 std::move(failFilter)));
senorblanco6a93fa12016-04-05 04:43:45 -0700684 SkIPoint offset;
685 sk_sp<SkSpecialImage> result(greenFilter->filterImage(source.get(), ctx, &offset));
686 REPORTER_ASSERT(reporter, nullptr != result.get());
687 if (result.get()) {
688 SkBitmap resultBM;
robertphillips64612512016-04-08 12:10:42 -0700689 REPORTER_ASSERT(reporter, result->getROPixels(&resultBM));
senorblanco6a93fa12016-04-05 04:43:45 -0700690 SkAutoLockPixels lock(resultBM);
691 REPORTER_ASSERT(reporter, *resultBM.getAddr32(0, 0) == SK_ColorGREEN);
692 }
693}
694
695DEF_TEST(ImageFilterFailAffectsTransparentBlack, reporter) {
robertphillips3e302272016-04-20 11:48:36 -0700696 test_fail_affects_transparent_black(reporter, nullptr);
senorblanco6a93fa12016-04-05 04:43:45 -0700697}
698
699#if SK_SUPPORT_GPU
bsalomon68d91342016-04-12 09:59:58 -0700700DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterFailAffectsTransparentBlack_Gpu, reporter, ctxInfo) {
robertphillips3e302272016-04-20 11:48:36 -0700701 test_fail_affects_transparent_black(reporter, ctxInfo.fGrContext);
senorblanco6a93fa12016-04-05 04:43:45 -0700702}
703#endif
704
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +0000705DEF_TEST(ImageFilterDrawTiled, reporter) {
706 // Check that all filters when drawn tiled (with subsequent clip rects) exactly
707 // match the same filters drawn with a single full-canvas bitmap draw.
708 // Tests pass by not asserting.
709
robertphillipsfc11b0a2016-04-05 09:09:36 -0700710 FilterList filters(nullptr);
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +0000711
712 SkBitmap untiledResult, tiledResult;
reed5ea95df2015-10-06 14:05:32 -0700713 const int width = 64, height = 64;
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +0000714 untiledResult.allocN32Pixels(width, height);
715 tiledResult.allocN32Pixels(width, height);
716 SkCanvas tiledCanvas(tiledResult);
717 SkCanvas untiledCanvas(untiledResult);
senorblanco@chromium.orgd4db6572014-05-07 20:00:04 +0000718 int tileSize = 8;
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +0000719
senorblanco@chromium.orgd4db6572014-05-07 20:00:04 +0000720 for (int scale = 1; scale <= 2; ++scale) {
senorblanco297f7ce2016-03-23 13:44:26 -0700721 for (int i = 0; i < filters.count(); ++i) {
senorblanco@chromium.orgd4db6572014-05-07 20:00:04 +0000722 tiledCanvas.clear(0);
723 untiledCanvas.clear(0);
724 SkPaint paint;
senorblanco297f7ce2016-03-23 13:44:26 -0700725 paint.setImageFilter(filters.getFilter(i));
senorblanco@chromium.orgd4db6572014-05-07 20:00:04 +0000726 paint.setTextSize(SkIntToScalar(height));
727 paint.setColor(SK_ColorWHITE);
728 SkString str;
729 const char* text = "ABC";
730 SkScalar ypos = SkIntToScalar(height);
731 untiledCanvas.save();
732 untiledCanvas.scale(SkIntToScalar(scale), SkIntToScalar(scale));
733 untiledCanvas.drawText(text, strlen(text), 0, ypos, paint);
734 untiledCanvas.restore();
735 for (int y = 0; y < height; y += tileSize) {
736 for (int x = 0; x < width; x += tileSize) {
737 tiledCanvas.save();
738 tiledCanvas.clipRect(SkRect::Make(SkIRect::MakeXYWH(x, y, tileSize, tileSize)));
739 tiledCanvas.scale(SkIntToScalar(scale), SkIntToScalar(scale));
740 tiledCanvas.drawText(text, strlen(text), 0, ypos, paint);
741 tiledCanvas.restore();
742 }
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +0000743 }
senorblanco@chromium.orgd4db6572014-05-07 20:00:04 +0000744 untiledCanvas.flush();
745 tiledCanvas.flush();
746 for (int y = 0; y < height; y++) {
747 int diffs = memcmp(untiledResult.getAddr32(0, y), tiledResult.getAddr32(0, y), untiledResult.rowBytes());
senorblanco297f7ce2016-03-23 13:44:26 -0700748 REPORTER_ASSERT_MESSAGE(reporter, !diffs, filters.getName(i));
senorblanco@chromium.orgd4db6572014-05-07 20:00:04 +0000749 if (diffs) {
750 break;
751 }
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +0000752 }
753 }
754 }
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +0000755}
756
mtklein3f3b3d02014-12-01 11:47:08 -0800757static void draw_saveLayer_picture(int width, int height, int tileSize,
robertphillipsa8d7f0b2014-08-29 08:03:56 -0700758 SkBBHFactory* factory, SkBitmap* result) {
mtkleind910f542014-08-22 09:06:34 -0700759
760 SkMatrix matrix;
761 matrix.setTranslate(SkIntToScalar(50), 0);
762
robertphillips5605b562016-04-05 11:50:42 -0700763 sk_sp<SkColorFilter> cf(SkColorFilter::MakeModeFilter(SK_ColorWHITE, SkXfermode::kSrc_Mode));
764 sk_sp<SkImageFilter> cfif(SkColorFilterImageFilter::Make(std::move(cf), nullptr));
robertphillipsae8c9332016-04-05 15:09:00 -0700765 sk_sp<SkImageFilter> imageFilter(SkImageFilter::MakeMatrixFilter(matrix,
766 kNone_SkFilterQuality,
767 std::move(cfif)));
mtkleind910f542014-08-22 09:06:34 -0700768
769 SkPaint paint;
robertphillips5605b562016-04-05 11:50:42 -0700770 paint.setImageFilter(std::move(imageFilter));
mtkleind910f542014-08-22 09:06:34 -0700771 SkPictureRecorder recorder;
772 SkRect bounds = SkRect::Make(SkIRect::MakeXYWH(0, 0, 50, 50));
mtklein3f3b3d02014-12-01 11:47:08 -0800773 SkCanvas* recordingCanvas = recorder.beginRecording(SkIntToScalar(width),
774 SkIntToScalar(height),
robertphillipsa8d7f0b2014-08-29 08:03:56 -0700775 factory, 0);
mtkleind910f542014-08-22 09:06:34 -0700776 recordingCanvas->translate(-55, 0);
777 recordingCanvas->saveLayer(&bounds, &paint);
778 recordingCanvas->restore();
reedca2622b2016-03-18 07:25:55 -0700779 sk_sp<SkPicture> picture1(recorder.finishRecordingAsPicture());
mtkleind910f542014-08-22 09:06:34 -0700780
781 result->allocN32Pixels(width, height);
782 SkCanvas canvas(*result);
783 canvas.clear(0);
784 canvas.clipRect(SkRect::Make(SkIRect::MakeWH(tileSize, tileSize)));
785 canvas.drawPicture(picture1.get());
786}
787
788DEF_TEST(ImageFilterDrawMatrixBBH, reporter) {
789 // Check that matrix filter when drawn tiled with BBH exactly
790 // matches the same thing drawn without BBH.
791 // Tests pass by not asserting.
792
793 const int width = 200, height = 200;
794 const int tileSize = 100;
795 SkBitmap result1, result2;
796 SkRTreeFactory factory;
797
robertphillipsa8d7f0b2014-08-29 08:03:56 -0700798 draw_saveLayer_picture(width, height, tileSize, &factory, &result1);
halcanary96fcdcc2015-08-27 07:41:13 -0700799 draw_saveLayer_picture(width, height, tileSize, nullptr, &result2);
mtkleind910f542014-08-22 09:06:34 -0700800
801 for (int y = 0; y < height; y++) {
802 int diffs = memcmp(result1.getAddr32(0, y), result2.getAddr32(0, y), result1.rowBytes());
803 REPORTER_ASSERT(reporter, !diffs);
804 if (diffs) {
805 break;
806 }
807 }
808}
809
robertphillips6e7025a2016-04-04 04:31:25 -0700810static sk_sp<SkImageFilter> make_blur(sk_sp<SkImageFilter> input) {
811 return SkBlurImageFilter::Make(SK_Scalar1, SK_Scalar1, std::move(input));
senorblanco1150a6d2014-08-25 12:46:58 -0700812}
813
robertphillips6e7025a2016-04-04 04:31:25 -0700814static sk_sp<SkImageFilter> make_drop_shadow(sk_sp<SkImageFilter> input) {
robertphillipsc4169122016-04-06 08:40:59 -0700815 return SkDropShadowImageFilter::Make(
senorblanco1150a6d2014-08-25 12:46:58 -0700816 SkIntToScalar(100), SkIntToScalar(100),
817 SkIntToScalar(10), SkIntToScalar(10),
sugoi234f0362014-10-23 13:59:52 -0700818 SK_ColorBLUE, SkDropShadowImageFilter::kDrawShadowAndForeground_ShadowMode,
robertphillipsc4169122016-04-06 08:40:59 -0700819 std::move(input));
senorblanco1150a6d2014-08-25 12:46:58 -0700820}
821
822DEF_TEST(ImageFilterBlurThenShadowBounds, reporter) {
robertphillips6e7025a2016-04-04 04:31:25 -0700823 sk_sp<SkImageFilter> filter1(make_blur(nullptr));
824 sk_sp<SkImageFilter> filter2(make_drop_shadow(std::move(filter1)));
senorblanco1150a6d2014-08-25 12:46:58 -0700825
826 SkIRect bounds = SkIRect::MakeXYWH(0, 0, 100, 100);
827 SkIRect expectedBounds = SkIRect::MakeXYWH(-133, -133, 236, 236);
senorblancoe5e79842016-03-21 14:51:59 -0700828 bounds = filter2->filterBounds(bounds, SkMatrix::I());
senorblanco1150a6d2014-08-25 12:46:58 -0700829
830 REPORTER_ASSERT(reporter, bounds == expectedBounds);
831}
832
833DEF_TEST(ImageFilterShadowThenBlurBounds, reporter) {
robertphillips6e7025a2016-04-04 04:31:25 -0700834 sk_sp<SkImageFilter> filter1(make_drop_shadow(nullptr));
835 sk_sp<SkImageFilter> filter2(make_blur(std::move(filter1)));
senorblanco1150a6d2014-08-25 12:46:58 -0700836
837 SkIRect bounds = SkIRect::MakeXYWH(0, 0, 100, 100);
838 SkIRect expectedBounds = SkIRect::MakeXYWH(-133, -133, 236, 236);
senorblancoe5e79842016-03-21 14:51:59 -0700839 bounds = filter2->filterBounds(bounds, SkMatrix::I());
senorblanco1150a6d2014-08-25 12:46:58 -0700840
841 REPORTER_ASSERT(reporter, bounds == expectedBounds);
842}
843
844DEF_TEST(ImageFilterDilateThenBlurBounds, reporter) {
robertphillipsfc11b0a2016-04-05 09:09:36 -0700845 sk_sp<SkImageFilter> filter1(SkDilateImageFilter::Make(2, 2, nullptr));
robertphillips6e7025a2016-04-04 04:31:25 -0700846 sk_sp<SkImageFilter> filter2(make_drop_shadow(std::move(filter1)));
senorblanco1150a6d2014-08-25 12:46:58 -0700847
848 SkIRect bounds = SkIRect::MakeXYWH(0, 0, 100, 100);
849 SkIRect expectedBounds = SkIRect::MakeXYWH(-132, -132, 234, 234);
senorblancoe5e79842016-03-21 14:51:59 -0700850 bounds = filter2->filterBounds(bounds, SkMatrix::I());
senorblanco1150a6d2014-08-25 12:46:58 -0700851
852 REPORTER_ASSERT(reporter, bounds == expectedBounds);
853}
854
ajuma5788faa2015-02-13 09:05:47 -0800855DEF_TEST(ImageFilterComposedBlurFastBounds, reporter) {
robertphillips6e7025a2016-04-04 04:31:25 -0700856 sk_sp<SkImageFilter> filter1(make_blur(nullptr));
857 sk_sp<SkImageFilter> filter2(make_blur(nullptr));
robertphillips491fb172016-03-30 12:32:58 -0700858 sk_sp<SkImageFilter> composedFilter(SkComposeImageFilter::Make(std::move(filter1),
859 std::move(filter2)));
ajuma5788faa2015-02-13 09:05:47 -0800860
861 SkRect boundsSrc = SkRect::MakeWH(SkIntToScalar(100), SkIntToScalar(100));
862 SkRect expectedBounds = SkRect::MakeXYWH(
863 SkIntToScalar(-6), SkIntToScalar(-6), SkIntToScalar(112), SkIntToScalar(112));
senorblancoe5e79842016-03-21 14:51:59 -0700864 SkRect boundsDst = composedFilter->computeFastBounds(boundsSrc);
ajuma5788faa2015-02-13 09:05:47 -0800865
866 REPORTER_ASSERT(reporter, boundsDst == expectedBounds);
867}
868
jbroman0e3129d2016-03-17 12:24:23 -0700869DEF_TEST(ImageFilterUnionBounds, reporter) {
robertphillips51a315e2016-03-31 09:05:49 -0700870 sk_sp<SkImageFilter> offset(SkOffsetImageFilter::Make(50, 0, nullptr));
jbroman0e3129d2016-03-17 12:24:23 -0700871 // Regardless of which order they appear in, the image filter bounds should
872 // be combined correctly.
873 {
robertphillips8c0326d2016-04-05 12:48:34 -0700874 sk_sp<SkImageFilter> composite(SkXfermodeImageFilter::Make(nullptr, offset));
jbroman0e3129d2016-03-17 12:24:23 -0700875 SkRect bounds = SkRect::MakeWH(100, 100);
876 // Intentionally aliasing here, as that's what the real callers do.
senorblancoe5e79842016-03-21 14:51:59 -0700877 bounds = composite->computeFastBounds(bounds);
jbroman0e3129d2016-03-17 12:24:23 -0700878 REPORTER_ASSERT(reporter, bounds == SkRect::MakeWH(150, 100));
879 }
880 {
reedcfb6bdf2016-03-29 11:32:50 -0700881 sk_sp<SkImageFilter> composite(SkXfermodeImageFilter::Make(nullptr, nullptr,
robertphillips8c0326d2016-04-05 12:48:34 -0700882 offset, nullptr));
jbroman0e3129d2016-03-17 12:24:23 -0700883 SkRect bounds = SkRect::MakeWH(100, 100);
884 // Intentionally aliasing here, as that's what the real callers do.
senorblancoe5e79842016-03-21 14:51:59 -0700885 bounds = composite->computeFastBounds(bounds);
jbroman0e3129d2016-03-17 12:24:23 -0700886 REPORTER_ASSERT(reporter, bounds == SkRect::MakeWH(150, 100));
887 }
888}
889
robertphillips3e302272016-04-20 11:48:36 -0700890static void test_imagefilter_merge_result_size(skiatest::Reporter* reporter, GrContext* context) {
senorblanco4a243982015-11-25 07:06:55 -0800891 SkBitmap greenBM;
892 greenBM.allocN32Pixels(20, 20);
893 greenBM.eraseColor(SK_ColorGREEN);
reed9ce9d672016-03-17 10:51:11 -0700894 sk_sp<SkImage> greenImage(SkImage::MakeFromBitmap(greenBM));
robertphillips549c8992016-04-01 09:28:51 -0700895 sk_sp<SkImageFilter> source(SkImageSource::Make(std::move(greenImage)));
robertphillips2238c9d2016-03-30 13:34:16 -0700896 sk_sp<SkImageFilter> merge(SkMergeImageFilter::Make(source, source));
senorblanco4a243982015-11-25 07:06:55 -0800897
robertphillips3e302272016-04-20 11:48:36 -0700898 sk_sp<SkSpecialImage> srcImg(create_empty_special_image(context, 1));
robertphillips4418dba2016-03-07 12:45:14 -0800899
reed4e23cda2016-01-11 10:56:59 -0800900 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeXYWH(0, 0, 100, 100), nullptr);
senorblanco4a243982015-11-25 07:06:55 -0800901 SkIPoint offset;
robertphillips4418dba2016-03-07 12:45:14 -0800902
robertphillips2302de92016-03-24 07:26:32 -0700903 sk_sp<SkSpecialImage> resultImg(merge->filterImage(srcImg.get(), ctx, &offset));
robertphillips4418dba2016-03-07 12:45:14 -0800904 REPORTER_ASSERT(reporter, resultImg);
905
906 REPORTER_ASSERT(reporter, resultImg->width() == 20 && resultImg->height() == 20);
senorblanco4a243982015-11-25 07:06:55 -0800907}
908
robertphillips4418dba2016-03-07 12:45:14 -0800909DEF_TEST(ImageFilterMergeResultSize, reporter) {
robertphillips3e302272016-04-20 11:48:36 -0700910 test_imagefilter_merge_result_size(reporter, nullptr);
robertphillips4418dba2016-03-07 12:45:14 -0800911}
912
913#if SK_SUPPORT_GPU
bsalomon758586c2016-04-06 14:02:39 -0700914DEF_GPUTEST_FOR_GL_RENDERING_CONTEXTS(ImageFilterMergeResultSize_Gpu, reporter, ctxInfo) {
robertphillips3e302272016-04-20 11:48:36 -0700915 test_imagefilter_merge_result_size(reporter, ctxInfo.fGrContext);
robertphillips4418dba2016-03-07 12:45:14 -0800916}
917#endif
918
robertphillipsa8d7f0b2014-08-29 08:03:56 -0700919static void draw_blurred_rect(SkCanvas* canvas) {
senorblanco837f5322014-07-14 10:19:54 -0700920 SkPaint filterPaint;
921 filterPaint.setColor(SK_ColorWHITE);
robertphillips6e7025a2016-04-04 04:31:25 -0700922 filterPaint.setImageFilter(SkBlurImageFilter::Make(SkIntToScalar(8), 0, nullptr));
halcanary96fcdcc2015-08-27 07:41:13 -0700923 canvas->saveLayer(nullptr, &filterPaint);
senorblanco837f5322014-07-14 10:19:54 -0700924 SkPaint whitePaint;
925 whitePaint.setColor(SK_ColorWHITE);
926 canvas->drawRect(SkRect::Make(SkIRect::MakeWH(4, 4)), whitePaint);
927 canvas->restore();
928}
929
robertphillipsa8d7f0b2014-08-29 08:03:56 -0700930static void draw_picture_clipped(SkCanvas* canvas, const SkRect& clipRect, const SkPicture* picture) {
senorblanco837f5322014-07-14 10:19:54 -0700931 canvas->save();
932 canvas->clipRect(clipRect);
933 canvas->drawPicture(picture);
934 canvas->restore();
935}
936
937DEF_TEST(ImageFilterDrawTiledBlurRTree, reporter) {
938 // Check that the blur filter when recorded with RTree acceleration,
939 // and drawn tiled (with subsequent clip rects) exactly
940 // matches the same filter drawn with without RTree acceleration.
941 // This tests that the "bleed" from the blur into the otherwise-blank
942 // tiles is correctly rendered.
943 // Tests pass by not asserting.
944
945 int width = 16, height = 8;
946 SkBitmap result1, result2;
947 result1.allocN32Pixels(width, height);
948 result2.allocN32Pixels(width, height);
949 SkCanvas canvas1(result1);
950 SkCanvas canvas2(result2);
951 int tileSize = 8;
952
953 canvas1.clear(0);
954 canvas2.clear(0);
955
956 SkRTreeFactory factory;
957
958 SkPictureRecorder recorder1, recorder2;
959 // The only difference between these two pictures is that one has RTree aceleration.
mtklein3f3b3d02014-12-01 11:47:08 -0800960 SkCanvas* recordingCanvas1 = recorder1.beginRecording(SkIntToScalar(width),
961 SkIntToScalar(height),
halcanary96fcdcc2015-08-27 07:41:13 -0700962 nullptr, 0);
mtklein3f3b3d02014-12-01 11:47:08 -0800963 SkCanvas* recordingCanvas2 = recorder2.beginRecording(SkIntToScalar(width),
964 SkIntToScalar(height),
robertphillipsa8d7f0b2014-08-29 08:03:56 -0700965 &factory, 0);
966 draw_blurred_rect(recordingCanvas1);
967 draw_blurred_rect(recordingCanvas2);
reedca2622b2016-03-18 07:25:55 -0700968 sk_sp<SkPicture> picture1(recorder1.finishRecordingAsPicture());
969 sk_sp<SkPicture> picture2(recorder2.finishRecordingAsPicture());
senorblanco837f5322014-07-14 10:19:54 -0700970 for (int y = 0; y < height; y += tileSize) {
971 for (int x = 0; x < width; x += tileSize) {
972 SkRect tileRect = SkRect::Make(SkIRect::MakeXYWH(x, y, tileSize, tileSize));
reedca2622b2016-03-18 07:25:55 -0700973 draw_picture_clipped(&canvas1, tileRect, picture1.get());
974 draw_picture_clipped(&canvas2, tileRect, picture2.get());
senorblanco837f5322014-07-14 10:19:54 -0700975 }
976 }
977 for (int y = 0; y < height; y++) {
978 int diffs = memcmp(result1.getAddr32(0, y), result2.getAddr32(0, y), result1.rowBytes());
979 REPORTER_ASSERT(reporter, !diffs);
980 if (diffs) {
981 break;
982 }
983 }
984}
985
senorblanco@chromium.org91957432014-05-01 14:03:41 +0000986DEF_TEST(ImageFilterMatrixConvolution, reporter) {
987 // Check that a 1x3 filter does not cause a spurious assert.
988 SkScalar kernel[3] = {
989 SkIntToScalar( 1), SkIntToScalar( 1), SkIntToScalar( 1),
990 };
991 SkISize kernelSize = SkISize::Make(1, 3);
992 SkScalar gain = SK_Scalar1, bias = 0;
993 SkIPoint kernelOffset = SkIPoint::Make(0, 0);
994
robertphillipsef6a47b2016-04-08 08:01:20 -0700995 sk_sp<SkImageFilter> filter(SkMatrixConvolutionImageFilter::Make(
996 kernelSize, kernel,
997 gain, bias, kernelOffset,
998 SkMatrixConvolutionImageFilter::kRepeat_TileMode,
999 false, nullptr));
senorblanco@chromium.org91957432014-05-01 14:03:41 +00001000
1001 SkBitmap result;
1002 int width = 16, height = 16;
1003 result.allocN32Pixels(width, height);
1004 SkCanvas canvas(result);
1005 canvas.clear(0);
1006
1007 SkPaint paint;
robertphillipsef6a47b2016-04-08 08:01:20 -07001008 paint.setImageFilter(std::move(filter));
senorblanco@chromium.org91957432014-05-01 14:03:41 +00001009 SkRect rect = SkRect::Make(SkIRect::MakeWH(width, height));
1010 canvas.drawRect(rect, paint);
1011}
1012
senorblanco@chromium.org8c7372b2014-05-02 19:13:11 +00001013DEF_TEST(ImageFilterMatrixConvolutionBorder, reporter) {
1014 // Check that a filter with borders outside the target bounds
1015 // does not crash.
1016 SkScalar kernel[3] = {
1017 0, 0, 0,
1018 };
1019 SkISize kernelSize = SkISize::Make(3, 1);
1020 SkScalar gain = SK_Scalar1, bias = 0;
1021 SkIPoint kernelOffset = SkIPoint::Make(2, 0);
1022
robertphillipsef6a47b2016-04-08 08:01:20 -07001023 sk_sp<SkImageFilter> filter(SkMatrixConvolutionImageFilter::Make(
1024 kernelSize, kernel, gain, bias, kernelOffset,
1025 SkMatrixConvolutionImageFilter::kClamp_TileMode,
1026 true, nullptr));
senorblanco@chromium.org8c7372b2014-05-02 19:13:11 +00001027
1028 SkBitmap result;
1029
1030 int width = 10, height = 10;
1031 result.allocN32Pixels(width, height);
1032 SkCanvas canvas(result);
1033 canvas.clear(0);
1034
1035 SkPaint filterPaint;
robertphillipsef6a47b2016-04-08 08:01:20 -07001036 filterPaint.setImageFilter(std::move(filter));
senorblanco@chromium.org8c7372b2014-05-02 19:13:11 +00001037 SkRect bounds = SkRect::MakeWH(1, 10);
1038 SkRect rect = SkRect::Make(SkIRect::MakeWH(width, height));
1039 SkPaint rectPaint;
1040 canvas.saveLayer(&bounds, &filterPaint);
1041 canvas.drawRect(rect, rectPaint);
1042 canvas.restore();
1043}
1044
robertphillips3e302272016-04-20 11:48:36 -07001045static void test_big_kernel(skiatest::Reporter* reporter, GrContext* context) {
robertphillipsdada4dd2016-04-13 04:54:36 -07001046 // Check that a kernel that is too big for the GPU still works
1047 SkScalar identityKernel[49] = {
1048 0, 0, 0, 0, 0, 0, 0,
1049 0, 0, 0, 0, 0, 0, 0,
1050 0, 0, 0, 0, 0, 0, 0,
1051 0, 0, 0, 1, 0, 0, 0,
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 };
1056 SkISize kernelSize = SkISize::Make(7, 7);
1057 SkScalar gain = SK_Scalar1, bias = 0;
1058 SkIPoint kernelOffset = SkIPoint::Make(0, 0);
1059
1060 sk_sp<SkImageFilter> filter(SkMatrixConvolutionImageFilter::Make(
1061 kernelSize, identityKernel, gain, bias, kernelOffset,
1062 SkMatrixConvolutionImageFilter::kClamp_TileMode,
1063 true, nullptr));
1064
robertphillips3e302272016-04-20 11:48:36 -07001065 sk_sp<SkSpecialImage> srcImg(create_empty_special_image(context, 100));
robertphillipsdada4dd2016-04-13 04:54:36 -07001066 SkASSERT(srcImg);
1067
1068 SkIPoint offset;
1069 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeWH(100, 100), nullptr);
1070 sk_sp<SkSpecialImage> resultImg(filter->filterImage(srcImg.get(), ctx, &offset));
1071 REPORTER_ASSERT(reporter, resultImg);
1072 REPORTER_ASSERT(reporter, SkToBool(context) == resultImg->isTextureBacked());
1073 REPORTER_ASSERT(reporter, resultImg->width() == 100 && resultImg->height() == 100);
1074 REPORTER_ASSERT(reporter, offset.fX == 0 && offset.fY == 0);
1075}
1076
1077DEF_TEST(ImageFilterMatrixConvolutionBigKernel, reporter) {
robertphillips3e302272016-04-20 11:48:36 -07001078 test_big_kernel(reporter, nullptr);
robertphillipsdada4dd2016-04-13 04:54:36 -07001079}
1080
1081#if SK_SUPPORT_GPU
1082DEF_GPUTEST_FOR_GL_RENDERING_CONTEXTS(ImageFilterMatrixConvolutionBigKernel_Gpu,
1083 reporter, ctxInfo) {
robertphillips3e302272016-04-20 11:48:36 -07001084 test_big_kernel(reporter, ctxInfo.fGrContext);
robertphillipsdada4dd2016-04-13 04:54:36 -07001085}
1086#endif
1087
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +00001088DEF_TEST(ImageFilterCropRect, reporter) {
robertphillips3e302272016-04-20 11:48:36 -07001089 test_crop_rects(reporter, nullptr);
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +00001090}
1091
robertphillips4418dba2016-03-07 12:45:14 -08001092#if SK_SUPPORT_GPU
bsalomon68d91342016-04-12 09:59:58 -07001093DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterCropRect_Gpu, reporter, ctxInfo) {
robertphillips3e302272016-04-20 11:48:36 -07001094 test_crop_rects(reporter, ctxInfo.fGrContext);
robertphillips4418dba2016-03-07 12:45:14 -08001095}
1096#endif
1097
tfarina9ea53f92014-06-24 06:50:39 -07001098DEF_TEST(ImageFilterMatrix, reporter) {
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +00001099 SkBitmap temp;
mike@reedtribe.orgdeee4962014-02-13 14:41:43 +00001100 temp.allocN32Pixels(100, 100);
robertphillips9a53fd72015-06-22 09:46:59 -07001101 SkCanvas canvas(temp);
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +00001102 canvas.scale(SkIntToScalar(2), SkIntToScalar(2));
1103
1104 SkMatrix expectedMatrix = canvas.getTotalMatrix();
1105
commit-bot@chromium.org5fb2ce32014-04-17 23:35:06 +00001106 SkRTreeFactory factory;
1107 SkPictureRecorder recorder;
1108 SkCanvas* recordingCanvas = recorder.beginRecording(100, 100, &factory, 0);
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +00001109
1110 SkPaint paint;
robertphillips43c2ad42016-04-04 05:05:11 -07001111 paint.setImageFilter(MatrixTestImageFilter::Make(reporter, expectedMatrix));
halcanary96fcdcc2015-08-27 07:41:13 -07001112 recordingCanvas->saveLayer(nullptr, &paint);
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +00001113 SkPaint solidPaint;
1114 solidPaint.setColor(0xFFFFFFFF);
1115 recordingCanvas->save();
1116 recordingCanvas->scale(SkIntToScalar(10), SkIntToScalar(10));
1117 recordingCanvas->drawRect(SkRect::Make(SkIRect::MakeWH(100, 100)), solidPaint);
1118 recordingCanvas->restore(); // scale
1119 recordingCanvas->restore(); // saveLayer
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +00001120
reedca2622b2016-03-18 07:25:55 -07001121 canvas.drawPicture(recorder.finishRecordingAsPicture());
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +00001122}
1123
senorblanco3d822c22014-07-30 14:49:31 -07001124DEF_TEST(ImageFilterCrossProcessPictureImageFilter, reporter) {
senorblanco@chromium.org97f5fc62014-05-30 20:50:56 +00001125 SkRTreeFactory factory;
1126 SkPictureRecorder recorder;
1127 SkCanvas* recordingCanvas = recorder.beginRecording(1, 1, &factory, 0);
1128
1129 // Create an SkPicture which simply draws a green 1x1 rectangle.
1130 SkPaint greenPaint;
1131 greenPaint.setColor(SK_ColorGREEN);
1132 recordingCanvas->drawRect(SkRect::Make(SkIRect::MakeWH(1, 1)), greenPaint);
reedca2622b2016-03-18 07:25:55 -07001133 sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture());
senorblanco@chromium.org97f5fc62014-05-30 20:50:56 +00001134
1135 // Wrap that SkPicture in an SkPictureImageFilter.
robertphillips5ff17b12016-03-28 13:13:42 -07001136 sk_sp<SkImageFilter> imageFilter(SkPictureImageFilter::Make(picture));
senorblanco@chromium.org97f5fc62014-05-30 20:50:56 +00001137
1138 // Check that SkPictureImageFilter successfully serializes its contained
1139 // SkPicture when not in cross-process mode.
1140 SkPaint paint;
robertphillips5ff17b12016-03-28 13:13:42 -07001141 paint.setImageFilter(imageFilter);
senorblanco@chromium.org97f5fc62014-05-30 20:50:56 +00001142 SkPictureRecorder outerRecorder;
1143 SkCanvas* outerCanvas = outerRecorder.beginRecording(1, 1, &factory, 0);
1144 SkPaint redPaintWithFilter;
1145 redPaintWithFilter.setColor(SK_ColorRED);
robertphillips5ff17b12016-03-28 13:13:42 -07001146 redPaintWithFilter.setImageFilter(imageFilter);
senorblanco@chromium.org97f5fc62014-05-30 20:50:56 +00001147 outerCanvas->drawRect(SkRect::Make(SkIRect::MakeWH(1, 1)), redPaintWithFilter);
reedca2622b2016-03-18 07:25:55 -07001148 sk_sp<SkPicture> outerPicture(outerRecorder.finishRecordingAsPicture());
senorblanco@chromium.org97f5fc62014-05-30 20:50:56 +00001149
1150 SkBitmap bitmap;
1151 bitmap.allocN32Pixels(1, 1);
robertphillips9a53fd72015-06-22 09:46:59 -07001152 SkCanvas canvas(bitmap);
senorblanco@chromium.org97f5fc62014-05-30 20:50:56 +00001153
1154 // The result here should be green, since the filter replaces the primitive's red interior.
1155 canvas.clear(0x0);
robertphillips9b14f262014-06-04 05:40:44 -07001156 canvas.drawPicture(outerPicture);
senorblanco@chromium.org97f5fc62014-05-30 20:50:56 +00001157 uint32_t pixel = *bitmap.getAddr32(0, 0);
1158 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1159
1160 // Check that, for now, SkPictureImageFilter does not serialize or
1161 // deserialize its contained picture when the filter is serialized
1162 // cross-process. Do this by "laundering" it through SkValidatingReadBuffer.
robertphillips12fa47d2016-04-08 16:28:09 -07001163 sk_sp<SkData> data(SkValidatingSerializeFlattenable(imageFilter.get()));
1164 sk_sp<SkFlattenable> flattenable(SkValidatingDeserializeFlattenable(
mtklein3b375452016-04-04 14:57:19 -07001165 data->data(), data->size(), SkImageFilter::GetFlattenableType()));
senorblanco@chromium.org97f5fc62014-05-30 20:50:56 +00001166 SkImageFilter* unflattenedFilter = static_cast<SkImageFilter*>(flattenable.get());
1167
1168 redPaintWithFilter.setImageFilter(unflattenedFilter);
1169 SkPictureRecorder crossProcessRecorder;
1170 SkCanvas* crossProcessCanvas = crossProcessRecorder.beginRecording(1, 1, &factory, 0);
1171 crossProcessCanvas->drawRect(SkRect::Make(SkIRect::MakeWH(1, 1)), redPaintWithFilter);
reedca2622b2016-03-18 07:25:55 -07001172 sk_sp<SkPicture> crossProcessPicture(crossProcessRecorder.finishRecordingAsPicture());
senorblanco@chromium.org97f5fc62014-05-30 20:50:56 +00001173
1174 canvas.clear(0x0);
robertphillips9b14f262014-06-04 05:40:44 -07001175 canvas.drawPicture(crossProcessPicture);
senorblanco@chromium.org97f5fc62014-05-30 20:50:56 +00001176 pixel = *bitmap.getAddr32(0, 0);
hendrikw446ee672015-06-16 09:28:37 -07001177 // If the security precautions are enabled, the result here should not be green, since the
1178 // filter draws nothing.
mtklein2afbe232016-02-07 12:23:10 -08001179 REPORTER_ASSERT(reporter, SkPicture::PictureIOSecurityPrecautionsEnabled()
hendrikw446ee672015-06-16 09:28:37 -07001180 ? pixel != SK_ColorGREEN : pixel == SK_ColorGREEN);
senorblanco@chromium.org97f5fc62014-05-30 20:50:56 +00001181}
1182
robertphillips3e302272016-04-20 11:48:36 -07001183static void test_clipped_picture_imagefilter(skiatest::Reporter* reporter, GrContext* context) {
reedca2622b2016-03-18 07:25:55 -07001184 sk_sp<SkPicture> picture;
senorblanco3d822c22014-07-30 14:49:31 -07001185
robertphillips4418dba2016-03-07 12:45:14 -08001186 {
1187 SkRTreeFactory factory;
1188 SkPictureRecorder recorder;
1189 SkCanvas* recordingCanvas = recorder.beginRecording(1, 1, &factory, 0);
1190
1191 // Create an SkPicture which simply draws a green 1x1 rectangle.
1192 SkPaint greenPaint;
1193 greenPaint.setColor(SK_ColorGREEN);
1194 recordingCanvas->drawRect(SkRect::Make(SkIRect::MakeWH(1, 1)), greenPaint);
reedca2622b2016-03-18 07:25:55 -07001195 picture = recorder.finishRecordingAsPicture();
robertphillips4418dba2016-03-07 12:45:14 -08001196 }
1197
robertphillips3e302272016-04-20 11:48:36 -07001198 sk_sp<SkSpecialImage> srcImg(create_empty_special_image(context, 2));
senorblanco3d822c22014-07-30 14:49:31 -07001199
robertphillips5ff17b12016-03-28 13:13:42 -07001200 sk_sp<SkImageFilter> imageFilter(SkPictureImageFilter::Make(picture));
senorblanco3d822c22014-07-30 14:49:31 -07001201
senorblanco3d822c22014-07-30 14:49:31 -07001202 SkIPoint offset;
reed4e23cda2016-01-11 10:56:59 -08001203 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeXYWH(1, 1, 1, 1), nullptr);
robertphillips4418dba2016-03-07 12:45:14 -08001204
robertphillips2302de92016-03-24 07:26:32 -07001205 sk_sp<SkSpecialImage> resultImage(imageFilter->filterImage(srcImg.get(), ctx, &offset));
robertphillips4418dba2016-03-07 12:45:14 -08001206 REPORTER_ASSERT(reporter, !resultImage);
senorblanco3d822c22014-07-30 14:49:31 -07001207}
1208
robertphillips4418dba2016-03-07 12:45:14 -08001209DEF_TEST(ImageFilterClippedPictureImageFilter, reporter) {
robertphillips3e302272016-04-20 11:48:36 -07001210 test_clipped_picture_imagefilter(reporter, nullptr);
robertphillips4418dba2016-03-07 12:45:14 -08001211}
1212
1213#if SK_SUPPORT_GPU
bsalomon68d91342016-04-12 09:59:58 -07001214DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterClippedPictureImageFilter_Gpu, reporter, ctxInfo) {
robertphillips3e302272016-04-20 11:48:36 -07001215 test_clipped_picture_imagefilter(reporter, ctxInfo.fGrContext);
robertphillips4418dba2016-03-07 12:45:14 -08001216}
1217#endif
1218
tfarina9ea53f92014-06-24 06:50:39 -07001219DEF_TEST(ImageFilterEmptySaveLayer, reporter) {
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001220 // Even when there's an empty saveLayer()/restore(), ensure that an image
1221 // filter or color filter which affects transparent black still draws.
1222
1223 SkBitmap bitmap;
1224 bitmap.allocN32Pixels(10, 10);
robertphillips9a53fd72015-06-22 09:46:59 -07001225 SkCanvas canvas(bitmap);
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001226
1227 SkRTreeFactory factory;
1228 SkPictureRecorder recorder;
1229
robertphillips5605b562016-04-05 11:50:42 -07001230 sk_sp<SkColorFilter> green(SkColorFilter::MakeModeFilter(SK_ColorGREEN,
1231 SkXfermode::kSrc_Mode));
1232 sk_sp<SkImageFilter> imageFilter(SkColorFilterImageFilter::Make(green, nullptr));
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001233 SkPaint imageFilterPaint;
robertphillips5605b562016-04-05 11:50:42 -07001234 imageFilterPaint.setImageFilter(std::move(imageFilter));
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001235 SkPaint colorFilterPaint;
reedd053ce92016-03-22 10:17:23 -07001236 colorFilterPaint.setColorFilter(green);
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001237
1238 SkRect bounds = SkRect::MakeWH(10, 10);
1239
1240 SkCanvas* recordingCanvas = recorder.beginRecording(10, 10, &factory, 0);
1241 recordingCanvas->saveLayer(&bounds, &imageFilterPaint);
1242 recordingCanvas->restore();
reedca2622b2016-03-18 07:25:55 -07001243 sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture());
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001244
1245 canvas.clear(0);
robertphillips9b14f262014-06-04 05:40:44 -07001246 canvas.drawPicture(picture);
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001247 uint32_t pixel = *bitmap.getAddr32(0, 0);
1248 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1249
1250 recordingCanvas = recorder.beginRecording(10, 10, &factory, 0);
halcanary96fcdcc2015-08-27 07:41:13 -07001251 recordingCanvas->saveLayer(nullptr, &imageFilterPaint);
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001252 recordingCanvas->restore();
reedca2622b2016-03-18 07:25:55 -07001253 sk_sp<SkPicture> picture2(recorder.finishRecordingAsPicture());
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001254
1255 canvas.clear(0);
robertphillips9b14f262014-06-04 05:40:44 -07001256 canvas.drawPicture(picture2);
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001257 pixel = *bitmap.getAddr32(0, 0);
1258 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1259
1260 recordingCanvas = recorder.beginRecording(10, 10, &factory, 0);
1261 recordingCanvas->saveLayer(&bounds, &colorFilterPaint);
1262 recordingCanvas->restore();
reedca2622b2016-03-18 07:25:55 -07001263 sk_sp<SkPicture> picture3(recorder.finishRecordingAsPicture());
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001264
1265 canvas.clear(0);
robertphillips9b14f262014-06-04 05:40:44 -07001266 canvas.drawPicture(picture3);
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001267 pixel = *bitmap.getAddr32(0, 0);
1268 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1269}
1270
robertphillips9a53fd72015-06-22 09:46:59 -07001271static void test_huge_blur(SkCanvas* canvas, skiatest::Reporter* reporter) {
senorblanco@chromium.org09843fd2014-03-24 20:50:59 +00001272 SkBitmap bitmap;
1273 bitmap.allocN32Pixels(100, 100);
1274 bitmap.eraseARGB(0, 0, 0, 0);
1275
1276 // Check that a blur with an insane radius does not crash or assert.
senorblanco@chromium.org09843fd2014-03-24 20:50:59 +00001277 SkPaint paint;
robertphillips6e7025a2016-04-04 04:31:25 -07001278 paint.setImageFilter(SkBlurImageFilter::Make(SkIntToScalar(1<<30),
1279 SkIntToScalar(1<<30),
1280 nullptr));
reedda420b92015-12-16 08:38:15 -08001281 canvas->drawBitmap(bitmap, 0, 0, &paint);
senorblanco@chromium.org09843fd2014-03-24 20:50:59 +00001282}
1283
1284DEF_TEST(HugeBlurImageFilter, reporter) {
1285 SkBitmap temp;
1286 temp.allocN32Pixels(100, 100);
robertphillips9a53fd72015-06-22 09:46:59 -07001287 SkCanvas canvas(temp);
1288 test_huge_blur(&canvas, reporter);
senorblanco@chromium.org09843fd2014-03-24 20:50:59 +00001289}
1290
senorblanco21a465d2016-04-11 11:58:39 -07001291DEF_TEST(ImageFilterMatrixConvolutionSanityTest, reporter) {
senorblanco3a495202014-09-29 07:57:20 -07001292 SkScalar kernel[1] = { 0 };
1293 SkScalar gain = SK_Scalar1, bias = 0;
1294 SkIPoint kernelOffset = SkIPoint::Make(1, 1);
1295
halcanary96fcdcc2015-08-27 07:41:13 -07001296 // Check that an enormous (non-allocatable) kernel gives a nullptr filter.
robertphillipsef6a47b2016-04-08 08:01:20 -07001297 sk_sp<SkImageFilter> conv(SkMatrixConvolutionImageFilter::Make(
senorblanco3a495202014-09-29 07:57:20 -07001298 SkISize::Make(1<<30, 1<<30),
1299 kernel,
1300 gain,
1301 bias,
1302 kernelOffset,
1303 SkMatrixConvolutionImageFilter::kRepeat_TileMode,
robertphillipsef6a47b2016-04-08 08:01:20 -07001304 false,
1305 nullptr));
senorblanco3a495202014-09-29 07:57:20 -07001306
halcanary96fcdcc2015-08-27 07:41:13 -07001307 REPORTER_ASSERT(reporter, nullptr == conv.get());
senorblanco3a495202014-09-29 07:57:20 -07001308
halcanary96fcdcc2015-08-27 07:41:13 -07001309 // Check that a nullptr kernel gives a nullptr filter.
robertphillipsef6a47b2016-04-08 08:01:20 -07001310 conv = SkMatrixConvolutionImageFilter::Make(
senorblanco3a495202014-09-29 07:57:20 -07001311 SkISize::Make(1, 1),
halcanary96fcdcc2015-08-27 07:41:13 -07001312 nullptr,
senorblanco3a495202014-09-29 07:57:20 -07001313 gain,
1314 bias,
1315 kernelOffset,
1316 SkMatrixConvolutionImageFilter::kRepeat_TileMode,
robertphillipsef6a47b2016-04-08 08:01:20 -07001317 false,
1318 nullptr);
senorblanco3a495202014-09-29 07:57:20 -07001319
halcanary96fcdcc2015-08-27 07:41:13 -07001320 REPORTER_ASSERT(reporter, nullptr == conv.get());
senorblanco3a495202014-09-29 07:57:20 -07001321
halcanary96fcdcc2015-08-27 07:41:13 -07001322 // Check that a kernel width < 1 gives a nullptr filter.
robertphillipsef6a47b2016-04-08 08:01:20 -07001323 conv = SkMatrixConvolutionImageFilter::Make(
senorblanco3a495202014-09-29 07:57:20 -07001324 SkISize::Make(0, 1),
1325 kernel,
1326 gain,
1327 bias,
1328 kernelOffset,
1329 SkMatrixConvolutionImageFilter::kRepeat_TileMode,
robertphillipsef6a47b2016-04-08 08:01:20 -07001330 false,
1331 nullptr);
senorblanco3a495202014-09-29 07:57:20 -07001332
halcanary96fcdcc2015-08-27 07:41:13 -07001333 REPORTER_ASSERT(reporter, nullptr == conv.get());
senorblanco3a495202014-09-29 07:57:20 -07001334
halcanary96fcdcc2015-08-27 07:41:13 -07001335 // Check that kernel height < 1 gives a nullptr filter.
robertphillipsef6a47b2016-04-08 08:01:20 -07001336 conv = SkMatrixConvolutionImageFilter::Make(
senorblanco3a495202014-09-29 07:57:20 -07001337 SkISize::Make(1, -1),
1338 kernel,
1339 gain,
1340 bias,
1341 kernelOffset,
1342 SkMatrixConvolutionImageFilter::kRepeat_TileMode,
robertphillipsef6a47b2016-04-08 08:01:20 -07001343 false,
1344 nullptr);
senorblanco3a495202014-09-29 07:57:20 -07001345
halcanary96fcdcc2015-08-27 07:41:13 -07001346 REPORTER_ASSERT(reporter, nullptr == conv.get());
senorblanco3a495202014-09-29 07:57:20 -07001347}
1348
robertphillips9a53fd72015-06-22 09:46:59 -07001349static void test_xfermode_cropped_input(SkCanvas* canvas, skiatest::Reporter* reporter) {
1350 canvas->clear(0);
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001351
1352 SkBitmap bitmap;
1353 bitmap.allocN32Pixels(1, 1);
1354 bitmap.eraseARGB(255, 255, 255, 255);
1355
robertphillips5605b562016-04-05 11:50:42 -07001356 sk_sp<SkColorFilter> green(SkColorFilter::MakeModeFilter(SK_ColorGREEN,
1357 SkXfermode::kSrcIn_Mode));
1358 sk_sp<SkImageFilter> greenFilter(SkColorFilterImageFilter::Make(green, nullptr));
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001359 SkImageFilter::CropRect cropRect(SkRect::MakeEmpty());
robertphillips5605b562016-04-05 11:50:42 -07001360 sk_sp<SkImageFilter> croppedOut(SkColorFilterImageFilter::Make(green, nullptr, &cropRect));
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001361
1362 // Check that an xfermode image filter whose input has been cropped out still draws the other
1363 // input. Also check that drawing with both inputs cropped out doesn't cause a GPU warning.
robertphillips8c0326d2016-04-05 12:48:34 -07001364 sk_sp<SkXfermode> mode(SkXfermode::Make(SkXfermode::kSrcOver_Mode));
1365 sk_sp<SkImageFilter> xfermodeNoFg(SkXfermodeImageFilter::Make(mode, greenFilter,
1366 croppedOut, nullptr));
1367 sk_sp<SkImageFilter> xfermodeNoBg(SkXfermodeImageFilter::Make(mode, croppedOut,
1368 greenFilter, nullptr));
1369 sk_sp<SkImageFilter> xfermodeNoFgNoBg(SkXfermodeImageFilter::Make(mode, croppedOut,
1370 croppedOut, nullptr));
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001371
1372 SkPaint paint;
robertphillips8c0326d2016-04-05 12:48:34 -07001373 paint.setImageFilter(std::move(xfermodeNoFg));
reedda420b92015-12-16 08:38:15 -08001374 canvas->drawBitmap(bitmap, 0, 0, &paint); // drawSprite
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001375
1376 uint32_t pixel;
kkinnunena9d9a392015-03-06 07:16:00 -08001377 SkImageInfo info = SkImageInfo::Make(1, 1, kBGRA_8888_SkColorType, kUnpremul_SkAlphaType);
robertphillips9a53fd72015-06-22 09:46:59 -07001378 canvas->readPixels(info, &pixel, 4, 0, 0);
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001379 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1380
robertphillips8c0326d2016-04-05 12:48:34 -07001381 paint.setImageFilter(std::move(xfermodeNoBg));
reedda420b92015-12-16 08:38:15 -08001382 canvas->drawBitmap(bitmap, 0, 0, &paint); // drawSprite
robertphillips9a53fd72015-06-22 09:46:59 -07001383 canvas->readPixels(info, &pixel, 4, 0, 0);
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001384 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1385
robertphillips8c0326d2016-04-05 12:48:34 -07001386 paint.setImageFilter(std::move(xfermodeNoFgNoBg));
reedda420b92015-12-16 08:38:15 -08001387 canvas->drawBitmap(bitmap, 0, 0, &paint); // drawSprite
robertphillips9a53fd72015-06-22 09:46:59 -07001388 canvas->readPixels(info, &pixel, 4, 0, 0);
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001389 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1390}
1391
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001392DEF_TEST(ImageFilterNestedSaveLayer, reporter) {
1393 SkBitmap temp;
1394 temp.allocN32Pixels(50, 50);
robertphillips9a53fd72015-06-22 09:46:59 -07001395 SkCanvas canvas(temp);
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001396 canvas.clear(0x0);
1397
1398 SkBitmap bitmap;
1399 bitmap.allocN32Pixels(10, 10);
1400 bitmap.eraseColor(SK_ColorGREEN);
1401
1402 SkMatrix matrix;
1403 matrix.setScale(SkIntToScalar(2), SkIntToScalar(2));
1404 matrix.postTranslate(SkIntToScalar(-20), SkIntToScalar(-20));
robertphillipsae8c9332016-04-05 15:09:00 -07001405 sk_sp<SkImageFilter> matrixFilter(
1406 SkImageFilter::MakeMatrixFilter(matrix, kLow_SkFilterQuality, nullptr));
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001407
1408 // Test that saveLayer() with a filter nested inside another saveLayer() applies the
1409 // correct offset to the filter matrix.
1410 SkRect bounds1 = SkRect::MakeXYWH(10, 10, 30, 30);
halcanary96fcdcc2015-08-27 07:41:13 -07001411 canvas.saveLayer(&bounds1, nullptr);
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001412 SkPaint filterPaint;
robertphillipsae8c9332016-04-05 15:09:00 -07001413 filterPaint.setImageFilter(std::move(matrixFilter));
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001414 SkRect bounds2 = SkRect::MakeXYWH(20, 20, 10, 10);
1415 canvas.saveLayer(&bounds2, &filterPaint);
1416 SkPaint greenPaint;
1417 greenPaint.setColor(SK_ColorGREEN);
1418 canvas.drawRect(bounds2, greenPaint);
1419 canvas.restore();
1420 canvas.restore();
1421 SkPaint strokePaint;
1422 strokePaint.setStyle(SkPaint::kStroke_Style);
1423 strokePaint.setColor(SK_ColorRED);
1424
kkinnunena9d9a392015-03-06 07:16:00 -08001425 SkImageInfo info = SkImageInfo::Make(1, 1, kBGRA_8888_SkColorType, kUnpremul_SkAlphaType);
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001426 uint32_t pixel;
1427 canvas.readPixels(info, &pixel, 4, 25, 25);
1428 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1429
1430 // Test that drawSprite() with a filter nested inside a saveLayer() applies the
1431 // correct offset to the filter matrix.
1432 canvas.clear(0x0);
1433 canvas.readPixels(info, &pixel, 4, 25, 25);
halcanary96fcdcc2015-08-27 07:41:13 -07001434 canvas.saveLayer(&bounds1, nullptr);
reedda420b92015-12-16 08:38:15 -08001435 canvas.drawBitmap(bitmap, 20, 20, &filterPaint); // drawSprite
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001436 canvas.restore();
1437
1438 canvas.readPixels(info, &pixel, 4, 25, 25);
1439 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1440}
1441
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001442DEF_TEST(XfermodeImageFilterCroppedInput, reporter) {
1443 SkBitmap temp;
1444 temp.allocN32Pixels(100, 100);
robertphillips9a53fd72015-06-22 09:46:59 -07001445 SkCanvas canvas(temp);
1446 test_xfermode_cropped_input(&canvas, reporter);
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001447}
senorblanco@chromium.org09843fd2014-03-24 20:50:59 +00001448
robertphillips3e302272016-04-20 11:48:36 -07001449static void test_composed_imagefilter_offset(skiatest::Reporter* reporter, GrContext* context) {
1450 sk_sp<SkSpecialImage> srcImg(create_empty_special_image(context, 100));
ajuma5788faa2015-02-13 09:05:47 -08001451
1452 SkImageFilter::CropRect cropRect(SkRect::MakeXYWH(1, 0, 20, 20));
robertphillips51a315e2016-03-31 09:05:49 -07001453 sk_sp<SkImageFilter> offsetFilter(SkOffsetImageFilter::Make(0, 0, nullptr, &cropRect));
robertphillips6e7025a2016-04-04 04:31:25 -07001454 sk_sp<SkImageFilter> blurFilter(SkBlurImageFilter::Make(SK_Scalar1, SK_Scalar1,
1455 nullptr, &cropRect));
robertphillips491fb172016-03-30 12:32:58 -07001456 sk_sp<SkImageFilter> composedFilter(SkComposeImageFilter::Make(std::move(blurFilter),
1457 std::move(offsetFilter)));
ajuma5788faa2015-02-13 09:05:47 -08001458 SkIPoint offset;
reed4e23cda2016-01-11 10:56:59 -08001459 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeWH(100, 100), nullptr);
robertphillips4418dba2016-03-07 12:45:14 -08001460
robertphillips2302de92016-03-24 07:26:32 -07001461 sk_sp<SkSpecialImage> resultImg(composedFilter->filterImage(srcImg.get(), ctx, &offset));
robertphillips4418dba2016-03-07 12:45:14 -08001462 REPORTER_ASSERT(reporter, resultImg);
ajuma5788faa2015-02-13 09:05:47 -08001463 REPORTER_ASSERT(reporter, offset.fX == 1 && offset.fY == 0);
1464}
1465
robertphillips4418dba2016-03-07 12:45:14 -08001466DEF_TEST(ComposedImageFilterOffset, reporter) {
robertphillips3e302272016-04-20 11:48:36 -07001467 test_composed_imagefilter_offset(reporter, nullptr);
robertphillips4418dba2016-03-07 12:45:14 -08001468}
1469
1470#if SK_SUPPORT_GPU
bsalomon68d91342016-04-12 09:59:58 -07001471DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ComposedImageFilterOffset_Gpu, reporter, ctxInfo) {
robertphillips3e302272016-04-20 11:48:36 -07001472 test_composed_imagefilter_offset(reporter, ctxInfo.fGrContext);
robertphillips4418dba2016-03-07 12:45:14 -08001473}
1474#endif
1475
robertphillips3e302272016-04-20 11:48:36 -07001476static void test_composed_imagefilter_bounds(skiatest::Reporter* reporter, GrContext* context) {
jbroman17a65202016-03-21 08:38:58 -07001477 // The bounds passed to the inner filter must be filtered by the outer
1478 // filter, so that the inner filter produces the pixels that the outer
1479 // filter requires as input. This matters if the outer filter moves pixels.
1480 // Here, accounting for the outer offset is necessary so that the green
1481 // pixels of the picture are not clipped.
1482
1483 SkPictureRecorder recorder;
1484 SkCanvas* recordingCanvas = recorder.beginRecording(SkRect::MakeWH(200, 100));
1485 recordingCanvas->clipRect(SkRect::MakeXYWH(100, 0, 100, 100));
1486 recordingCanvas->clear(SK_ColorGREEN);
robertphillips491fb172016-03-30 12:32:58 -07001487 sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture());
robertphillips5ff17b12016-03-28 13:13:42 -07001488 sk_sp<SkImageFilter> pictureFilter(SkPictureImageFilter::Make(picture));
jbroman17a65202016-03-21 08:38:58 -07001489 SkImageFilter::CropRect cropRect(SkRect::MakeWH(100, 100));
robertphillips51a315e2016-03-31 09:05:49 -07001490 sk_sp<SkImageFilter> offsetFilter(SkOffsetImageFilter::Make(-100, 0, nullptr, &cropRect));
robertphillips491fb172016-03-30 12:32:58 -07001491 sk_sp<SkImageFilter> composedFilter(SkComposeImageFilter::Make(std::move(offsetFilter),
1492 std::move(pictureFilter)));
jbroman17a65202016-03-21 08:38:58 -07001493
robertphillips3e302272016-04-20 11:48:36 -07001494 sk_sp<SkSpecialImage> sourceImage(create_empty_special_image(context, 100));
jbroman17a65202016-03-21 08:38:58 -07001495 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeWH(100, 100), nullptr);
1496 SkIPoint offset;
1497 sk_sp<SkSpecialImage> result(composedFilter->filterImage(sourceImage.get(), ctx, &offset));
1498 REPORTER_ASSERT(reporter, offset.isZero());
1499 REPORTER_ASSERT(reporter, result);
1500 REPORTER_ASSERT(reporter, result->subset().size() == SkISize::Make(100, 100));
1501
1502 SkBitmap resultBM;
robertphillips64612512016-04-08 12:10:42 -07001503 REPORTER_ASSERT(reporter, result->getROPixels(&resultBM));
jbroman17a65202016-03-21 08:38:58 -07001504 SkAutoLockPixels lock(resultBM);
1505 REPORTER_ASSERT(reporter, resultBM.getColor(50, 50) == SK_ColorGREEN);
1506}
1507
1508DEF_TEST(ComposedImageFilterBounds, reporter) {
robertphillips3e302272016-04-20 11:48:36 -07001509 test_composed_imagefilter_bounds(reporter, nullptr);
jbroman17a65202016-03-21 08:38:58 -07001510}
1511
1512#if SK_SUPPORT_GPU
bsalomon758586c2016-04-06 14:02:39 -07001513DEF_GPUTEST_FOR_GL_RENDERING_CONTEXTS(ComposedImageFilterBounds_Gpu, reporter, ctxInfo) {
robertphillips3e302272016-04-20 11:48:36 -07001514 test_composed_imagefilter_bounds(reporter, ctxInfo.fGrContext);
jbroman17a65202016-03-21 08:38:58 -07001515}
1516#endif
1517
robertphillips3e302272016-04-20 11:48:36 -07001518static void test_partial_crop_rect(skiatest::Reporter* reporter, GrContext* context) {
1519 sk_sp<SkSpecialImage> srcImg(create_empty_special_image(context, 100));
senorblanco24d2a7b2015-07-13 10:27:05 -07001520
1521 SkImageFilter::CropRect cropRect(SkRect::MakeXYWH(100, 0, 20, 30),
senorblancoed7cf272015-07-16 15:19:11 -07001522 SkImageFilter::CropRect::kHasWidth_CropEdge | SkImageFilter::CropRect::kHasHeight_CropEdge);
robertphillips5605b562016-04-05 11:50:42 -07001523 sk_sp<SkImageFilter> filter(make_grayscale(nullptr, &cropRect));
senorblanco24d2a7b2015-07-13 10:27:05 -07001524 SkIPoint offset;
reed4e23cda2016-01-11 10:56:59 -08001525 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeWH(100, 100), nullptr);
robertphillips4418dba2016-03-07 12:45:14 -08001526
robertphillips2302de92016-03-24 07:26:32 -07001527 sk_sp<SkSpecialImage> resultImg(filter->filterImage(srcImg.get(), ctx, &offset));
robertphillips4418dba2016-03-07 12:45:14 -08001528 REPORTER_ASSERT(reporter, resultImg);
1529
senorblanco24d2a7b2015-07-13 10:27:05 -07001530 REPORTER_ASSERT(reporter, offset.fX == 0);
1531 REPORTER_ASSERT(reporter, offset.fY == 0);
robertphillips4418dba2016-03-07 12:45:14 -08001532 REPORTER_ASSERT(reporter, resultImg->width() == 20);
1533 REPORTER_ASSERT(reporter, resultImg->height() == 30);
senorblanco24d2a7b2015-07-13 10:27:05 -07001534}
1535
senorblanco21a465d2016-04-11 11:58:39 -07001536DEF_TEST(ImageFilterPartialCropRect, reporter) {
robertphillips3e302272016-04-20 11:48:36 -07001537 test_partial_crop_rect(reporter, nullptr);
robertphillips4418dba2016-03-07 12:45:14 -08001538}
1539
1540#if SK_SUPPORT_GPU
bsalomon68d91342016-04-12 09:59:58 -07001541DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterPartialCropRect_Gpu, reporter, ctxInfo) {
robertphillips3e302272016-04-20 11:48:36 -07001542 test_partial_crop_rect(reporter, ctxInfo.fGrContext);
robertphillips4418dba2016-03-07 12:45:14 -08001543}
1544#endif
1545
senorblanco0abdf762015-08-20 11:10:41 -07001546DEF_TEST(ImageFilterCanComputeFastBounds, reporter) {
1547
robertphillips12fa47d2016-04-08 16:28:09 -07001548 {
1549 SkPoint3 location = SkPoint3::Make(0, 0, SK_Scalar1);
1550 sk_sp<SkImageFilter> lighting(SkLightingImageFilter::MakePointLitDiffuse(location,
1551 SK_ColorGREEN,
1552 0, 0, nullptr));
1553 REPORTER_ASSERT(reporter, !lighting->canComputeFastBounds());
1554 }
senorblanco0abdf762015-08-20 11:10:41 -07001555
senorblanco0abdf762015-08-20 11:10:41 -07001556 {
robertphillips6e7025a2016-04-04 04:31:25 -07001557 sk_sp<SkImageFilter> gray(make_grayscale(nullptr, nullptr));
1558 REPORTER_ASSERT(reporter, gray->canComputeFastBounds());
1559 {
1560 SkColorFilter* grayCF;
1561 REPORTER_ASSERT(reporter, gray->asAColorFilter(&grayCF));
1562 REPORTER_ASSERT(reporter, !grayCF->affectsTransparentBlack());
1563 grayCF->unref();
1564 }
1565 REPORTER_ASSERT(reporter, gray->canComputeFastBounds());
1566
1567 sk_sp<SkImageFilter> grayBlur(SkBlurImageFilter::Make(SK_Scalar1, SK_Scalar1,
1568 std::move(gray)));
1569 REPORTER_ASSERT(reporter, grayBlur->canComputeFastBounds());
senorblanco0abdf762015-08-20 11:10:41 -07001570 }
senorblanco0abdf762015-08-20 11:10:41 -07001571
robertphillips6e7025a2016-04-04 04:31:25 -07001572 {
1573 SkScalar greenMatrix[20] = { 0, 0, 0, 0, 0,
1574 0, 0, 0, 0, 1,
1575 0, 0, 0, 0, 0,
1576 0, 0, 0, 0, 1 };
1577 sk_sp<SkColorFilter> greenCF(SkColorFilter::MakeMatrixFilterRowMajor255(greenMatrix));
robertphillips5605b562016-04-05 11:50:42 -07001578 sk_sp<SkImageFilter> green(SkColorFilterImageFilter::Make(greenCF, nullptr));
senorblanco0abdf762015-08-20 11:10:41 -07001579
robertphillips6e7025a2016-04-04 04:31:25 -07001580 REPORTER_ASSERT(reporter, greenCF->affectsTransparentBlack());
1581 REPORTER_ASSERT(reporter, !green->canComputeFastBounds());
senorblanco0abdf762015-08-20 11:10:41 -07001582
robertphillips6e7025a2016-04-04 04:31:25 -07001583 sk_sp<SkImageFilter> greenBlur(SkBlurImageFilter::Make(SK_Scalar1, SK_Scalar1,
1584 std::move(green)));
1585 REPORTER_ASSERT(reporter, !greenBlur->canComputeFastBounds());
1586 }
senorblanco0abdf762015-08-20 11:10:41 -07001587
1588 uint8_t allOne[256], identity[256];
1589 for (int i = 0; i < 256; ++i) {
1590 identity[i] = i;
1591 allOne[i] = 255;
1592 }
1593
robertphillips5605b562016-04-05 11:50:42 -07001594 sk_sp<SkColorFilter> identityCF(SkTableColorFilter::MakeARGB(identity, identity,
1595 identity, allOne));
1596 sk_sp<SkImageFilter> identityFilter(SkColorFilterImageFilter::Make(identityCF, nullptr));
senorblanco0abdf762015-08-20 11:10:41 -07001597 REPORTER_ASSERT(reporter, !identityCF->affectsTransparentBlack());
1598 REPORTER_ASSERT(reporter, identityFilter->canComputeFastBounds());
1599
robertphillips5605b562016-04-05 11:50:42 -07001600 sk_sp<SkColorFilter> forceOpaqueCF(SkTableColorFilter::MakeARGB(allOne, identity,
1601 identity, identity));
1602 sk_sp<SkImageFilter> forceOpaque(SkColorFilterImageFilter::Make(forceOpaqueCF, nullptr));
senorblanco0abdf762015-08-20 11:10:41 -07001603 REPORTER_ASSERT(reporter, forceOpaqueCF->affectsTransparentBlack());
1604 REPORTER_ASSERT(reporter, !forceOpaque->canComputeFastBounds());
1605}
1606
fmalitacd56f812015-09-14 13:31:18 -07001607// Verify that SkImageSource survives serialization
1608DEF_TEST(ImageFilterImageSourceSerialization, reporter) {
reede8f30622016-03-23 18:59:25 -07001609 auto surface(SkSurface::MakeRasterN32Premul(10, 10));
fmalitacd56f812015-09-14 13:31:18 -07001610 surface->getCanvas()->clear(SK_ColorGREEN);
reed9ce9d672016-03-17 10:51:11 -07001611 sk_sp<SkImage> image(surface->makeImageSnapshot());
robertphillips549c8992016-04-01 09:28:51 -07001612 sk_sp<SkImageFilter> filter(SkImageSource::Make(std::move(image)));
fmalitacd56f812015-09-14 13:31:18 -07001613
robertphillips549c8992016-04-01 09:28:51 -07001614 sk_sp<SkData> data(SkValidatingSerializeFlattenable(filter.get()));
1615 sk_sp<SkFlattenable> flattenable(SkValidatingDeserializeFlattenable(
mtklein3b375452016-04-04 14:57:19 -07001616 data->data(), data->size(), SkImageFilter::GetFlattenableType()));
fmalitacd56f812015-09-14 13:31:18 -07001617 SkImageFilter* unflattenedFilter = static_cast<SkImageFilter*>(flattenable.get());
1618 REPORTER_ASSERT(reporter, unflattenedFilter);
1619
1620 SkBitmap bm;
1621 bm.allocN32Pixels(10, 10);
fmalita23cb88c2015-09-15 06:56:23 -07001622 bm.eraseColor(SK_ColorBLUE);
fmalitacd56f812015-09-14 13:31:18 -07001623 SkPaint paint;
1624 paint.setColor(SK_ColorRED);
1625 paint.setImageFilter(unflattenedFilter);
1626
1627 SkCanvas canvas(bm);
1628 canvas.drawRect(SkRect::MakeWH(10, 10), paint);
1629 REPORTER_ASSERT(reporter, *bm.getAddr32(0, 0) == SkPreMultiplyColor(SK_ColorGREEN));
1630}
1631
bsalomon45eefcf2016-01-05 08:39:28 -08001632static void test_large_blur_input(skiatest::Reporter* reporter, SkCanvas* canvas) {
1633 SkBitmap largeBmp;
1634 int largeW = 5000;
1635 int largeH = 5000;
1636#if SK_SUPPORT_GPU
1637 // If we're GPU-backed make the bitmap too large to be converted into a texture.
1638 if (GrContext* ctx = canvas->getGrContext()) {
1639 largeW = ctx->caps()->maxTextureSize() + 1;
1640 }
1641#endif
1642
1643 largeBmp.allocN32Pixels(largeW, largeH);
mtklein2afbe232016-02-07 12:23:10 -08001644 largeBmp.eraseColor(0);
bsalomon45eefcf2016-01-05 08:39:28 -08001645 if (!largeBmp.getPixels()) {
1646 ERRORF(reporter, "Failed to allocate large bmp.");
1647 return;
1648 }
1649
reed9ce9d672016-03-17 10:51:11 -07001650 sk_sp<SkImage> largeImage(SkImage::MakeFromBitmap(largeBmp));
bsalomon45eefcf2016-01-05 08:39:28 -08001651 if (!largeImage) {
1652 ERRORF(reporter, "Failed to create large image.");
1653 return;
1654 }
1655
robertphillips549c8992016-04-01 09:28:51 -07001656 sk_sp<SkImageFilter> largeSource(SkImageSource::Make(std::move(largeImage)));
bsalomon45eefcf2016-01-05 08:39:28 -08001657 if (!largeSource) {
1658 ERRORF(reporter, "Failed to create large SkImageSource.");
1659 return;
1660 }
1661
robertphillips6e7025a2016-04-04 04:31:25 -07001662 sk_sp<SkImageFilter> blur(SkBlurImageFilter::Make(10.f, 10.f, std::move(largeSource)));
bsalomon45eefcf2016-01-05 08:39:28 -08001663 if (!blur) {
1664 ERRORF(reporter, "Failed to create SkBlurImageFilter.");
1665 return;
1666 }
1667
1668 SkPaint paint;
robertphillips549c8992016-04-01 09:28:51 -07001669 paint.setImageFilter(std::move(blur));
bsalomon45eefcf2016-01-05 08:39:28 -08001670
1671 // This should not crash (http://crbug.com/570479).
1672 canvas->drawRect(SkRect::MakeIWH(largeW, largeH), paint);
1673}
1674
senorblanco21a465d2016-04-11 11:58:39 -07001675DEF_TEST(ImageFilterBlurLargeImage, reporter) {
reede8f30622016-03-23 18:59:25 -07001676 auto surface(SkSurface::MakeRaster(SkImageInfo::MakeN32Premul(100, 100)));
bsalomon45eefcf2016-01-05 08:39:28 -08001677 test_large_blur_input(reporter, surface->getCanvas());
1678}
1679
senorblanco@chromium.org58d14662014-02-03 22:36:39 +00001680#if SK_SUPPORT_GPU
reed4a8126e2014-09-22 07:29:03 -07001681
bsalomon68d91342016-04-12 09:59:58 -07001682DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterHugeBlur_Gpu, reporter, ctxInfo) {
robertphillipsefbffed2015-06-22 12:06:08 -07001683
robertphillips3e302272016-04-20 11:48:36 -07001684 sk_sp<SkSurface> surf(SkSurface::MakeRenderTarget(ctxInfo.fGrContext,
1685 SkBudgeted::kNo,
1686 SkImageInfo::MakeN32Premul(100, 100)));
robertphillips9a53fd72015-06-22 09:46:59 -07001687
robertphillips3e302272016-04-20 11:48:36 -07001688
1689 SkCanvas* canvas = surf->getCanvas();
1690
1691 test_huge_blur(canvas, reporter);
senorblanco@chromium.org09843fd2014-03-24 20:50:59 +00001692}
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001693
bsalomon758586c2016-04-06 14:02:39 -07001694DEF_GPUTEST_FOR_GL_RENDERING_CONTEXTS(XfermodeImageFilterCroppedInput_Gpu, reporter, ctxInfo) {
robertphillipsefbffed2015-06-22 12:06:08 -07001695
robertphillips3e302272016-04-20 11:48:36 -07001696 sk_sp<SkSurface> surf(SkSurface::MakeRenderTarget(ctxInfo.fGrContext,
1697 SkBudgeted::kNo,
1698 SkImageInfo::MakeN32Premul(1, 1)));
robertphillips9a53fd72015-06-22 09:46:59 -07001699
robertphillips3e302272016-04-20 11:48:36 -07001700
1701 SkCanvas* canvas = surf->getCanvas();
1702
1703 test_xfermode_cropped_input(canvas, reporter);
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001704}
senorblanco32673b92014-09-09 09:15:04 -07001705
senorblanco21a465d2016-04-11 11:58:39 -07001706DEF_GPUTEST_FOR_ALL_GL_CONTEXTS(ImageFilterBlurLargeImage_Gpu, reporter, ctxInfo) {
bsalomonf2f1c172016-04-05 12:59:06 -07001707 auto surface(SkSurface::MakeRenderTarget(ctxInfo.fGrContext, SkBudgeted::kYes,
reede8f30622016-03-23 18:59:25 -07001708 SkImageInfo::MakeN32Premul(100, 100)));
bsalomon45eefcf2016-01-05 08:39:28 -08001709 test_large_blur_input(reporter, surface->getCanvas());
1710}
senorblanco@chromium.org58d14662014-02-03 22:36:39 +00001711#endif
reedbb34a8a2016-04-23 15:19:07 -07001712
1713/*
1714 * Test that colorfilterimagefilter does not require its CTM to be decomposed when it has more
1715 * than just scale/translate, but that other filters do.
1716 */
reed96a04f32016-04-25 09:25:15 -07001717DEF_TEST(ImageFilterComplexCTM, reporter) {
reedbb34a8a2016-04-23 15:19:07 -07001718 // just need a colorfilter to exercise the corresponding imagefilter
1719 sk_sp<SkColorFilter> cf = SkColorFilter::MakeModeFilter(SK_ColorRED, SkXfermode::kSrcATop_Mode);
reed96a04f32016-04-25 09:25:15 -07001720 sk_sp<SkImageFilter> cfif = SkColorFilterImageFilter::Make(cf, nullptr); // can handle
1721 sk_sp<SkImageFilter> blif = SkBlurImageFilter::Make(3, 3, nullptr); // cannot handle
reedbb34a8a2016-04-23 15:19:07 -07001722
1723 struct {
1724 sk_sp<SkImageFilter> fFilter;
1725 bool fExpectCanHandle;
1726 } recs[] = {
1727 { cfif, true },
1728 { SkColorFilterImageFilter::Make(cf, cfif), true },
1729 { SkMergeImageFilter::Make(cfif, cfif), true },
reed96a04f32016-04-25 09:25:15 -07001730 { SkComposeImageFilter::Make(cfif, cfif), true },
1731
reedbb34a8a2016-04-23 15:19:07 -07001732 { blif, false },
reed96a04f32016-04-25 09:25:15 -07001733 { SkBlurImageFilter::Make(3, 3, cfif), false },
reedbb34a8a2016-04-23 15:19:07 -07001734 { SkColorFilterImageFilter::Make(cf, blif), false },
reed96a04f32016-04-25 09:25:15 -07001735 { SkMergeImageFilter::Make(cfif, blif), false },
1736 { SkComposeImageFilter::Make(blif, cfif), false },
reedbb34a8a2016-04-23 15:19:07 -07001737 };
1738
1739 for (const auto& rec : recs) {
reed96a04f32016-04-25 09:25:15 -07001740 const bool canHandle = rec.fFilter->canHandleComplexCTM();
reedbb34a8a2016-04-23 15:19:07 -07001741 REPORTER_ASSERT(reporter, canHandle == rec.fExpectCanHandle);
1742 }
1743}