blob: 4db9196db9bb220f2d0fb5c7e41b965b7d401876 [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) {
robertphillips4418dba2016-03-07 12:45:14 -0800371 if (context) {
372 GrSurfaceDesc desc;
373 desc.fConfig = kSkia8888_GrPixelConfig;
374 desc.fFlags = kRenderTarget_GrSurfaceFlag;
375 desc.fWidth = widthHeight;
376 desc.fHeight = widthHeight;
robertphillips3e302272016-04-20 11:48:36 -0700377 return SkSpecialSurface::MakeRenderTarget(context, desc);
robertphillips4418dba2016-03-07 12:45:14 -0800378 } else {
379 const SkImageInfo info = SkImageInfo::MakeN32(widthHeight, widthHeight,
380 kOpaque_SkAlphaType);
robertphillips3e302272016-04-20 11:48:36 -0700381 return SkSpecialSurface::MakeRaster(info);
robertphillips4418dba2016-03-07 12:45:14 -0800382 }
senorblancobf680c32016-03-16 16:15:53 -0700383}
384
robertphillips3e302272016-04-20 11:48:36 -0700385static sk_sp<SkSpecialImage> create_empty_special_image(GrContext* context, int widthHeight) {
386 sk_sp<SkSpecialSurface> surf(create_empty_special_surface(context, widthHeight));
robertphillips4418dba2016-03-07 12:45:14 -0800387
388 SkASSERT(surf);
389
390 SkCanvas* canvas = surf->getCanvas();
391 SkASSERT(canvas);
392
393 canvas->clear(0x0);
394
robertphillips37bd7c32016-03-17 14:31:39 -0700395 return surf->makeImageSnapshot();
robertphillips4418dba2016-03-07 12:45:14 -0800396}
397
398
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000399DEF_TEST(ImageFilter, reporter) {
400 {
reedcedc36f2015-03-08 04:42:52 -0700401 // Check that two non-clipping color-matrice-filters concatenate into a single filter.
robertphillips5605b562016-04-05 11:50:42 -0700402 sk_sp<SkImageFilter> halfBrightness(make_scale(0.5f, nullptr));
403 sk_sp<SkImageFilter> quarterBrightness(make_scale(0.5f, std::move(halfBrightness)));
halcanary96fcdcc2015-08-27 07:41:13 -0700404 REPORTER_ASSERT(reporter, nullptr == quarterBrightness->getInput(0));
reedcedc36f2015-03-08 04:42:52 -0700405 SkColorFilter* cf;
406 REPORTER_ASSERT(reporter, quarterBrightness->asColorFilter(&cf));
halcanary96fcdcc2015-08-27 07:41:13 -0700407 REPORTER_ASSERT(reporter, cf->asColorMatrix(nullptr));
reedcedc36f2015-03-08 04:42:52 -0700408 cf->unref();
senorblanco@chromium.org194d7752013-07-24 22:19:24 +0000409 }
410
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000411 {
reedcedc36f2015-03-08 04:42:52 -0700412 // Check that a clipping color-matrice-filter followed by a color-matrice-filters
413 // concatenates into a single filter, but not a matrixfilter (due to clamping).
robertphillips5605b562016-04-05 11:50:42 -0700414 sk_sp<SkImageFilter> doubleBrightness(make_scale(2.0f, nullptr));
415 sk_sp<SkImageFilter> halfBrightness(make_scale(0.5f, std::move(doubleBrightness)));
halcanary96fcdcc2015-08-27 07:41:13 -0700416 REPORTER_ASSERT(reporter, nullptr == halfBrightness->getInput(0));
reedcedc36f2015-03-08 04:42:52 -0700417 SkColorFilter* cf;
418 REPORTER_ASSERT(reporter, halfBrightness->asColorFilter(&cf));
halcanary96fcdcc2015-08-27 07:41:13 -0700419 REPORTER_ASSERT(reporter, !cf->asColorMatrix(nullptr));
reedcedc36f2015-03-08 04:42:52 -0700420 cf->unref();
senorblanco@chromium.org194d7752013-07-24 22:19:24 +0000421 }
422
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000423 {
424 // Check that a color filter image filter without a crop rect can be
425 // expressed as a color filter.
robertphillips5605b562016-04-05 11:50:42 -0700426 sk_sp<SkImageFilter> gray(make_grayscale(nullptr, nullptr));
halcanary96fcdcc2015-08-27 07:41:13 -0700427 REPORTER_ASSERT(reporter, true == gray->asColorFilter(nullptr));
senorblanco@chromium.org194d7752013-07-24 22:19:24 +0000428 }
mtklein2afbe232016-02-07 12:23:10 -0800429
reedcedc36f2015-03-08 04:42:52 -0700430 {
431 // Check that a colorfilterimage filter without a crop rect but with an input
432 // that is another colorfilterimage can be expressed as a colorfilter (composed).
robertphillips5605b562016-04-05 11:50:42 -0700433 sk_sp<SkImageFilter> mode(make_blue(nullptr, nullptr));
434 sk_sp<SkImageFilter> gray(make_grayscale(std::move(mode), nullptr));
halcanary96fcdcc2015-08-27 07:41:13 -0700435 REPORTER_ASSERT(reporter, true == gray->asColorFilter(nullptr));
reedcedc36f2015-03-08 04:42:52 -0700436 }
437
438 {
439 // Test that if we exceed the limit of what ComposeColorFilter can combine, we still
440 // can build the DAG and won't assert if we call asColorFilter.
robertphillips5605b562016-04-05 11:50:42 -0700441 sk_sp<SkImageFilter> filter(make_blue(nullptr, nullptr));
reedcedc36f2015-03-08 04:42:52 -0700442 const int kWayTooManyForComposeColorFilter = 100;
443 for (int i = 0; i < kWayTooManyForComposeColorFilter; ++i) {
robertphillips5605b562016-04-05 11:50:42 -0700444 filter = make_blue(filter, nullptr);
reedcedc36f2015-03-08 04:42:52 -0700445 // the first few of these will succeed, but after we hit the internal limit,
446 // it will then return false.
halcanary96fcdcc2015-08-27 07:41:13 -0700447 (void)filter->asColorFilter(nullptr);
reedcedc36f2015-03-08 04:42:52 -0700448 }
449 }
reed5c518a82015-03-05 14:47:29 -0800450
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000451 {
452 // Check that a color filter image filter with a crop rect cannot
453 // be expressed as a color filter.
454 SkImageFilter::CropRect cropRect(SkRect::MakeXYWH(0, 0, 100, 100));
robertphillips5605b562016-04-05 11:50:42 -0700455 sk_sp<SkImageFilter> grayWithCrop(make_grayscale(nullptr, &cropRect));
halcanary96fcdcc2015-08-27 07:41:13 -0700456 REPORTER_ASSERT(reporter, false == grayWithCrop->asColorFilter(nullptr));
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000457 }
458
459 {
senorblanco3df05012014-07-03 11:13:09 -0700460 // Check that two non-commutative matrices are concatenated in
461 // the correct order.
462 SkScalar blueToRedMatrix[20] = { 0 };
463 blueToRedMatrix[2] = blueToRedMatrix[18] = SK_Scalar1;
464 SkScalar redToGreenMatrix[20] = { 0 };
465 redToGreenMatrix[5] = redToGreenMatrix[18] = SK_Scalar1;
robertphillips5605b562016-04-05 11:50:42 -0700466 sk_sp<SkColorFilter> blueToRed(SkColorFilter::MakeMatrixFilterRowMajor255(blueToRedMatrix));
467 sk_sp<SkImageFilter> filter1(SkColorFilterImageFilter::Make(std::move(blueToRed),
468 nullptr));
469 sk_sp<SkColorFilter> redToGreen(SkColorFilter::MakeMatrixFilterRowMajor255(redToGreenMatrix));
470 sk_sp<SkImageFilter> filter2(SkColorFilterImageFilter::Make(std::move(redToGreen),
471 std::move(filter1)));
senorblanco3df05012014-07-03 11:13:09 -0700472
473 SkBitmap result;
474 result.allocN32Pixels(kBitmapSize, kBitmapSize);
475
476 SkPaint paint;
477 paint.setColor(SK_ColorBLUE);
robertphillips5605b562016-04-05 11:50:42 -0700478 paint.setImageFilter(std::move(filter2));
senorblanco3df05012014-07-03 11:13:09 -0700479 SkCanvas canvas(result);
480 canvas.clear(0x0);
481 SkRect rect = SkRect::Make(SkIRect::MakeWH(kBitmapSize, kBitmapSize));
482 canvas.drawRect(rect, paint);
483 uint32_t pixel = *result.getAddr32(0, 0);
484 // The result here should be green, since we have effectively shifted blue to green.
485 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
486 }
487
488 {
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000489 // Tests pass by not asserting
reed9ce9d672016-03-17 10:51:11 -0700490 sk_sp<SkImage> image(make_small_image());
fmalita5598b632015-09-15 11:26:13 -0700491 SkBitmap result;
mike@reedtribe.orgdeee4962014-02-13 14:41:43 +0000492 result.allocN32Pixels(kBitmapSize, kBitmapSize);
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000493
senorblanco@chromium.org194d7752013-07-24 22:19:24 +0000494 {
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000495 // This tests for :
496 // 1 ) location at (0,0,1)
robertphillips3d32d762015-07-13 13:16:44 -0700497 SkPoint3 location = SkPoint3::Make(0, 0, SK_Scalar1);
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000498 // 2 ) location and target at same value
robertphillips3d32d762015-07-13 13:16:44 -0700499 SkPoint3 target = SkPoint3::Make(location.fX, location.fY, location.fZ);
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000500 // 3 ) large negative specular exponent value
501 SkScalar specularExponent = -1000;
502
robertphillips549c8992016-04-01 09:28:51 -0700503 sk_sp<SkImageFilter> bmSrc(SkImageSource::Make(std::move(image)));
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000504 SkPaint paint;
robertphillips12fa47d2016-04-08 16:28:09 -0700505 paint.setImageFilter(SkLightingImageFilter::MakeSpotLitSpecular(
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000506 location, target, specularExponent, 180,
507 0xFFFFFFFF, SK_Scalar1, SK_Scalar1, SK_Scalar1,
robertphillips12fa47d2016-04-08 16:28:09 -0700508 std::move(bmSrc)));
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000509 SkCanvas canvas(result);
510 SkRect r = SkRect::MakeWH(SkIntToScalar(kBitmapSize),
511 SkIntToScalar(kBitmapSize));
512 canvas.drawRect(r, paint);
senorblanco@chromium.org194d7752013-07-24 22:19:24 +0000513 }
senorblanco@chromium.org194d7752013-07-24 22:19:24 +0000514 }
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +0000515}
senorblanco@chromium.org6776b822014-01-03 21:48:22 +0000516
robertphillips3e302272016-04-20 11:48:36 -0700517static void test_crop_rects(skiatest::Reporter* reporter,
robertphillips4418dba2016-03-07 12:45:14 -0800518 GrContext* context) {
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +0000519 // Check that all filters offset to their absolute crop rect,
520 // unaffected by the input crop rect.
521 // Tests pass by not asserting.
robertphillips3e302272016-04-20 11:48:36 -0700522 sk_sp<SkSpecialImage> srcImg(create_empty_special_image(context, 100));
robertphillips4418dba2016-03-07 12:45:14 -0800523 SkASSERT(srcImg);
senorblanco@chromium.org6776b822014-01-03 21:48:22 +0000524
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +0000525 SkImageFilter::CropRect inputCropRect(SkRect::MakeXYWH(8, 13, 80, 80));
526 SkImageFilter::CropRect cropRect(SkRect::MakeXYWH(20, 30, 60, 60));
robertphillipsfc11b0a2016-04-05 09:09:36 -0700527 sk_sp<SkImageFilter> input(make_grayscale(nullptr, &inputCropRect));
senorblanco@chromium.org6776b822014-01-03 21:48:22 +0000528
robertphillipsfc11b0a2016-04-05 09:09:36 -0700529 FilterList filters(input, &cropRect);
senorblanco@chromium.org6776b822014-01-03 21:48:22 +0000530
senorblanco297f7ce2016-03-23 13:44:26 -0700531 for (int i = 0; i < filters.count(); ++i) {
532 SkImageFilter* filter = filters.getFilter(i);
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +0000533 SkIPoint offset;
reed4e23cda2016-01-11 10:56:59 -0800534 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeWH(100, 100), nullptr);
robertphillips2302de92016-03-24 07:26:32 -0700535 sk_sp<SkSpecialImage> resultImg(filter->filterImage(srcImg.get(), ctx, &offset));
senorblanco297f7ce2016-03-23 13:44:26 -0700536 REPORTER_ASSERT_MESSAGE(reporter, resultImg, filters.getName(i));
537 REPORTER_ASSERT_MESSAGE(reporter, offset.fX == 20 && offset.fY == 30, filters.getName(i));
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +0000538 }
539}
540
robertphillips3e302272016-04-20 11:48:36 -0700541static void test_negative_blur_sigma(skiatest::Reporter* reporter,
robertphillips4418dba2016-03-07 12:45:14 -0800542 GrContext* context) {
senorblanco32673b92014-09-09 09:15:04 -0700543 // Check that SkBlurImageFilter will accept a negative sigma, either in
544 // the given arguments or after CTM application.
reed5ea95df2015-10-06 14:05:32 -0700545 const int width = 32, height = 32;
546 const SkScalar five = SkIntToScalar(5);
senorblanco32673b92014-09-09 09:15:04 -0700547
robertphillips6e7025a2016-04-04 04:31:25 -0700548 sk_sp<SkImageFilter> positiveFilter(SkBlurImageFilter::Make(five, five, nullptr));
549 sk_sp<SkImageFilter> negativeFilter(SkBlurImageFilter::Make(-five, five, nullptr));
senorblanco32673b92014-09-09 09:15:04 -0700550
551 SkBitmap gradient = make_gradient_circle(width, height);
robertphillips3e302272016-04-20 11:48:36 -0700552 sk_sp<SkSpecialImage> imgSrc(SkSpecialImage::MakeFromRaster(SkIRect::MakeWH(width, height),
robertphillips37bd7c32016-03-17 14:31:39 -0700553 gradient));
robertphillips4418dba2016-03-07 12:45:14 -0800554
senorblanco32673b92014-09-09 09:15:04 -0700555 SkIPoint offset;
reed4e23cda2016-01-11 10:56:59 -0800556 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeWH(32, 32), nullptr);
robertphillips4418dba2016-03-07 12:45:14 -0800557
robertphillips2302de92016-03-24 07:26:32 -0700558 sk_sp<SkSpecialImage> positiveResult1(positiveFilter->filterImage(imgSrc.get(), ctx, &offset));
robertphillips4418dba2016-03-07 12:45:14 -0800559 REPORTER_ASSERT(reporter, positiveResult1);
560
robertphillips2302de92016-03-24 07:26:32 -0700561 sk_sp<SkSpecialImage> negativeResult1(negativeFilter->filterImage(imgSrc.get(), ctx, &offset));
robertphillips4418dba2016-03-07 12:45:14 -0800562 REPORTER_ASSERT(reporter, negativeResult1);
563
senorblanco32673b92014-09-09 09:15:04 -0700564 SkMatrix negativeScale;
565 negativeScale.setScale(-SK_Scalar1, SK_Scalar1);
reed4e23cda2016-01-11 10:56:59 -0800566 SkImageFilter::Context negativeCTX(negativeScale, SkIRect::MakeWH(32, 32), nullptr);
robertphillips4418dba2016-03-07 12:45:14 -0800567
robertphillips2302de92016-03-24 07:26:32 -0700568 sk_sp<SkSpecialImage> negativeResult2(positiveFilter->filterImage(imgSrc.get(),
569 negativeCTX,
570 &offset));
robertphillips4418dba2016-03-07 12:45:14 -0800571 REPORTER_ASSERT(reporter, negativeResult2);
572
robertphillips2302de92016-03-24 07:26:32 -0700573 sk_sp<SkSpecialImage> positiveResult2(negativeFilter->filterImage(imgSrc.get(),
574 negativeCTX,
575 &offset));
robertphillips4418dba2016-03-07 12:45:14 -0800576 REPORTER_ASSERT(reporter, positiveResult2);
577
578
579 SkBitmap positiveResultBM1, positiveResultBM2;
580 SkBitmap negativeResultBM1, negativeResultBM2;
581
robertphillips64612512016-04-08 12:10:42 -0700582 REPORTER_ASSERT(reporter, positiveResult1->getROPixels(&positiveResultBM1));
583 REPORTER_ASSERT(reporter, positiveResult2->getROPixels(&positiveResultBM2));
584 REPORTER_ASSERT(reporter, negativeResult1->getROPixels(&negativeResultBM1));
585 REPORTER_ASSERT(reporter, negativeResult2->getROPixels(&negativeResultBM2));
robertphillips4418dba2016-03-07 12:45:14 -0800586
587 SkAutoLockPixels lockP1(positiveResultBM1);
588 SkAutoLockPixels lockP2(positiveResultBM2);
589 SkAutoLockPixels lockN1(negativeResultBM1);
590 SkAutoLockPixels lockN2(negativeResultBM2);
senorblanco32673b92014-09-09 09:15:04 -0700591 for (int y = 0; y < height; y++) {
robertphillips4418dba2016-03-07 12:45:14 -0800592 int diffs = memcmp(positiveResultBM1.getAddr32(0, y),
593 negativeResultBM1.getAddr32(0, y),
594 positiveResultBM1.rowBytes());
senorblanco32673b92014-09-09 09:15:04 -0700595 REPORTER_ASSERT(reporter, !diffs);
596 if (diffs) {
597 break;
598 }
robertphillips4418dba2016-03-07 12:45:14 -0800599 diffs = memcmp(positiveResultBM1.getAddr32(0, y),
600 negativeResultBM2.getAddr32(0, y),
601 positiveResultBM1.rowBytes());
senorblanco32673b92014-09-09 09:15:04 -0700602 REPORTER_ASSERT(reporter, !diffs);
603 if (diffs) {
604 break;
605 }
robertphillips4418dba2016-03-07 12:45:14 -0800606 diffs = memcmp(positiveResultBM1.getAddr32(0, y),
607 positiveResultBM2.getAddr32(0, y),
608 positiveResultBM1.rowBytes());
senorblanco32673b92014-09-09 09:15:04 -0700609 REPORTER_ASSERT(reporter, !diffs);
610 if (diffs) {
611 break;
612 }
613 }
614}
615
senorblanco21a465d2016-04-11 11:58:39 -0700616DEF_TEST(ImageFilterNegativeBlurSigma, reporter) {
robertphillips3e302272016-04-20 11:48:36 -0700617 test_negative_blur_sigma(reporter, nullptr);
robertphillips4418dba2016-03-07 12:45:14 -0800618}
619
620#if SK_SUPPORT_GPU
bsalomon68d91342016-04-12 09:59:58 -0700621DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterNegativeBlurSigma_Gpu, reporter, ctxInfo) {
robertphillips3e302272016-04-20 11:48:36 -0700622 test_negative_blur_sigma(reporter, ctxInfo.fGrContext);
robertphillips4418dba2016-03-07 12:45:14 -0800623}
624#endif
625
robertphillips3e302272016-04-20 11:48:36 -0700626static void test_zero_blur_sigma(skiatest::Reporter* reporter, GrContext* context) {
senorblancobf680c32016-03-16 16:15:53 -0700627 // Check that SkBlurImageFilter with a zero sigma and a non-zero srcOffset works correctly.
628 SkImageFilter::CropRect cropRect(SkRect::Make(SkIRect::MakeXYWH(5, 0, 5, 10)));
robertphillips51a315e2016-03-31 09:05:49 -0700629 sk_sp<SkImageFilter> input(SkOffsetImageFilter::Make(0, 0, nullptr, &cropRect));
robertphillips6e7025a2016-04-04 04:31:25 -0700630 sk_sp<SkImageFilter> filter(SkBlurImageFilter::Make(0, 0, std::move(input), &cropRect));
senorblancobf680c32016-03-16 16:15:53 -0700631
robertphillips3e302272016-04-20 11:48:36 -0700632 sk_sp<SkSpecialSurface> surf(create_empty_special_surface(context, 10));
senorblancobf680c32016-03-16 16:15:53 -0700633 surf->getCanvas()->clear(SK_ColorGREEN);
robertphillips37bd7c32016-03-17 14:31:39 -0700634 sk_sp<SkSpecialImage> image(surf->makeImageSnapshot());
senorblancobf680c32016-03-16 16:15:53 -0700635
636 SkIPoint offset;
637 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeWH(32, 32), nullptr);
638
robertphillips2302de92016-03-24 07:26:32 -0700639 sk_sp<SkSpecialImage> result(filter->filterImage(image.get(), ctx, &offset));
senorblancobf680c32016-03-16 16:15:53 -0700640 REPORTER_ASSERT(reporter, offset.fX == 5 && offset.fY == 0);
641 REPORTER_ASSERT(reporter, result);
642 REPORTER_ASSERT(reporter, result->width() == 5 && result->height() == 10);
643
644 SkBitmap resultBM;
645
robertphillips64612512016-04-08 12:10:42 -0700646 REPORTER_ASSERT(reporter, result->getROPixels(&resultBM));
senorblancobf680c32016-03-16 16:15:53 -0700647
648 SkAutoLockPixels lock(resultBM);
649 for (int y = 0; y < resultBM.height(); y++) {
650 for (int x = 0; x < resultBM.width(); x++) {
651 bool diff = *resultBM.getAddr32(x, y) != SK_ColorGREEN;
652 REPORTER_ASSERT(reporter, !diff);
653 if (diff) {
654 break;
655 }
656 }
657 }
658}
659
senorblanco21a465d2016-04-11 11:58:39 -0700660DEF_TEST(ImageFilterZeroBlurSigma, reporter) {
robertphillips3e302272016-04-20 11:48:36 -0700661 test_zero_blur_sigma(reporter, nullptr);
senorblancobf680c32016-03-16 16:15:53 -0700662}
663
664#if SK_SUPPORT_GPU
bsalomon68d91342016-04-12 09:59:58 -0700665DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterZeroBlurSigma_Gpu, reporter, ctxInfo) {
robertphillips3e302272016-04-20 11:48:36 -0700666 test_zero_blur_sigma(reporter, ctxInfo.fGrContext);
senorblancobf680c32016-03-16 16:15:53 -0700667}
668#endif
669
senorblanco6a93fa12016-04-05 04:43:45 -0700670
671// Tests that, even when an upstream filter has returned null (due to failure or clipping), a
672// downstream filter that affects transparent black still does so even with a nullptr input.
robertphillips3e302272016-04-20 11:48:36 -0700673static void test_fail_affects_transparent_black(skiatest::Reporter* reporter, GrContext* context) {
senorblanco6a93fa12016-04-05 04:43:45 -0700674 sk_sp<FailImageFilter> failFilter(new FailImageFilter());
robertphillips3e302272016-04-20 11:48:36 -0700675 sk_sp<SkSpecialImage> source(create_empty_special_image(context, 5));
senorblanco6a93fa12016-04-05 04:43:45 -0700676 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeXYWH(0, 0, 1, 1), nullptr);
677 sk_sp<SkColorFilter> green(SkColorFilter::MakeModeFilter(SK_ColorGREEN, SkXfermode::kSrc_Mode));
678 SkASSERT(green->affectsTransparentBlack());
robertphillips5605b562016-04-05 11:50:42 -0700679 sk_sp<SkImageFilter> greenFilter(SkColorFilterImageFilter::Make(std::move(green),
680 std::move(failFilter)));
senorblanco6a93fa12016-04-05 04:43:45 -0700681 SkIPoint offset;
682 sk_sp<SkSpecialImage> result(greenFilter->filterImage(source.get(), ctx, &offset));
683 REPORTER_ASSERT(reporter, nullptr != result.get());
684 if (result.get()) {
685 SkBitmap resultBM;
robertphillips64612512016-04-08 12:10:42 -0700686 REPORTER_ASSERT(reporter, result->getROPixels(&resultBM));
senorblanco6a93fa12016-04-05 04:43:45 -0700687 SkAutoLockPixels lock(resultBM);
688 REPORTER_ASSERT(reporter, *resultBM.getAddr32(0, 0) == SK_ColorGREEN);
689 }
690}
691
692DEF_TEST(ImageFilterFailAffectsTransparentBlack, reporter) {
robertphillips3e302272016-04-20 11:48:36 -0700693 test_fail_affects_transparent_black(reporter, nullptr);
senorblanco6a93fa12016-04-05 04:43:45 -0700694}
695
696#if SK_SUPPORT_GPU
bsalomon68d91342016-04-12 09:59:58 -0700697DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterFailAffectsTransparentBlack_Gpu, reporter, ctxInfo) {
robertphillips3e302272016-04-20 11:48:36 -0700698 test_fail_affects_transparent_black(reporter, ctxInfo.fGrContext);
senorblanco6a93fa12016-04-05 04:43:45 -0700699}
700#endif
701
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +0000702DEF_TEST(ImageFilterDrawTiled, reporter) {
703 // Check that all filters when drawn tiled (with subsequent clip rects) exactly
704 // match the same filters drawn with a single full-canvas bitmap draw.
705 // Tests pass by not asserting.
706
robertphillipsfc11b0a2016-04-05 09:09:36 -0700707 FilterList filters(nullptr);
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +0000708
709 SkBitmap untiledResult, tiledResult;
reed5ea95df2015-10-06 14:05:32 -0700710 const int width = 64, height = 64;
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +0000711 untiledResult.allocN32Pixels(width, height);
712 tiledResult.allocN32Pixels(width, height);
713 SkCanvas tiledCanvas(tiledResult);
714 SkCanvas untiledCanvas(untiledResult);
senorblanco@chromium.orgd4db6572014-05-07 20:00:04 +0000715 int tileSize = 8;
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +0000716
senorblanco@chromium.orgd4db6572014-05-07 20:00:04 +0000717 for (int scale = 1; scale <= 2; ++scale) {
senorblanco297f7ce2016-03-23 13:44:26 -0700718 for (int i = 0; i < filters.count(); ++i) {
senorblanco@chromium.orgd4db6572014-05-07 20:00:04 +0000719 tiledCanvas.clear(0);
720 untiledCanvas.clear(0);
721 SkPaint paint;
senorblanco297f7ce2016-03-23 13:44:26 -0700722 paint.setImageFilter(filters.getFilter(i));
senorblanco@chromium.orgd4db6572014-05-07 20:00:04 +0000723 paint.setTextSize(SkIntToScalar(height));
724 paint.setColor(SK_ColorWHITE);
725 SkString str;
726 const char* text = "ABC";
727 SkScalar ypos = SkIntToScalar(height);
728 untiledCanvas.save();
729 untiledCanvas.scale(SkIntToScalar(scale), SkIntToScalar(scale));
730 untiledCanvas.drawText(text, strlen(text), 0, ypos, paint);
731 untiledCanvas.restore();
732 for (int y = 0; y < height; y += tileSize) {
733 for (int x = 0; x < width; x += tileSize) {
734 tiledCanvas.save();
735 tiledCanvas.clipRect(SkRect::Make(SkIRect::MakeXYWH(x, y, tileSize, tileSize)));
736 tiledCanvas.scale(SkIntToScalar(scale), SkIntToScalar(scale));
737 tiledCanvas.drawText(text, strlen(text), 0, ypos, paint);
738 tiledCanvas.restore();
739 }
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +0000740 }
senorblanco@chromium.orgd4db6572014-05-07 20:00:04 +0000741 untiledCanvas.flush();
742 tiledCanvas.flush();
743 for (int y = 0; y < height; y++) {
744 int diffs = memcmp(untiledResult.getAddr32(0, y), tiledResult.getAddr32(0, y), untiledResult.rowBytes());
senorblanco297f7ce2016-03-23 13:44:26 -0700745 REPORTER_ASSERT_MESSAGE(reporter, !diffs, filters.getName(i));
senorblanco@chromium.orgd4db6572014-05-07 20:00:04 +0000746 if (diffs) {
747 break;
748 }
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +0000749 }
750 }
751 }
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +0000752}
753
mtklein3f3b3d02014-12-01 11:47:08 -0800754static void draw_saveLayer_picture(int width, int height, int tileSize,
robertphillipsa8d7f0b2014-08-29 08:03:56 -0700755 SkBBHFactory* factory, SkBitmap* result) {
mtkleind910f542014-08-22 09:06:34 -0700756
757 SkMatrix matrix;
758 matrix.setTranslate(SkIntToScalar(50), 0);
759
robertphillips5605b562016-04-05 11:50:42 -0700760 sk_sp<SkColorFilter> cf(SkColorFilter::MakeModeFilter(SK_ColorWHITE, SkXfermode::kSrc_Mode));
761 sk_sp<SkImageFilter> cfif(SkColorFilterImageFilter::Make(std::move(cf), nullptr));
robertphillipsae8c9332016-04-05 15:09:00 -0700762 sk_sp<SkImageFilter> imageFilter(SkImageFilter::MakeMatrixFilter(matrix,
763 kNone_SkFilterQuality,
764 std::move(cfif)));
mtkleind910f542014-08-22 09:06:34 -0700765
766 SkPaint paint;
robertphillips5605b562016-04-05 11:50:42 -0700767 paint.setImageFilter(std::move(imageFilter));
mtkleind910f542014-08-22 09:06:34 -0700768 SkPictureRecorder recorder;
769 SkRect bounds = SkRect::Make(SkIRect::MakeXYWH(0, 0, 50, 50));
mtklein3f3b3d02014-12-01 11:47:08 -0800770 SkCanvas* recordingCanvas = recorder.beginRecording(SkIntToScalar(width),
771 SkIntToScalar(height),
robertphillipsa8d7f0b2014-08-29 08:03:56 -0700772 factory, 0);
mtkleind910f542014-08-22 09:06:34 -0700773 recordingCanvas->translate(-55, 0);
774 recordingCanvas->saveLayer(&bounds, &paint);
775 recordingCanvas->restore();
reedca2622b2016-03-18 07:25:55 -0700776 sk_sp<SkPicture> picture1(recorder.finishRecordingAsPicture());
mtkleind910f542014-08-22 09:06:34 -0700777
778 result->allocN32Pixels(width, height);
779 SkCanvas canvas(*result);
780 canvas.clear(0);
781 canvas.clipRect(SkRect::Make(SkIRect::MakeWH(tileSize, tileSize)));
782 canvas.drawPicture(picture1.get());
783}
784
785DEF_TEST(ImageFilterDrawMatrixBBH, reporter) {
786 // Check that matrix filter when drawn tiled with BBH exactly
787 // matches the same thing drawn without BBH.
788 // Tests pass by not asserting.
789
790 const int width = 200, height = 200;
791 const int tileSize = 100;
792 SkBitmap result1, result2;
793 SkRTreeFactory factory;
794
robertphillipsa8d7f0b2014-08-29 08:03:56 -0700795 draw_saveLayer_picture(width, height, tileSize, &factory, &result1);
halcanary96fcdcc2015-08-27 07:41:13 -0700796 draw_saveLayer_picture(width, height, tileSize, nullptr, &result2);
mtkleind910f542014-08-22 09:06:34 -0700797
798 for (int y = 0; y < height; y++) {
799 int diffs = memcmp(result1.getAddr32(0, y), result2.getAddr32(0, y), result1.rowBytes());
800 REPORTER_ASSERT(reporter, !diffs);
801 if (diffs) {
802 break;
803 }
804 }
805}
806
robertphillips6e7025a2016-04-04 04:31:25 -0700807static sk_sp<SkImageFilter> make_blur(sk_sp<SkImageFilter> input) {
808 return SkBlurImageFilter::Make(SK_Scalar1, SK_Scalar1, std::move(input));
senorblanco1150a6d2014-08-25 12:46:58 -0700809}
810
robertphillips6e7025a2016-04-04 04:31:25 -0700811static sk_sp<SkImageFilter> make_drop_shadow(sk_sp<SkImageFilter> input) {
robertphillipsc4169122016-04-06 08:40:59 -0700812 return SkDropShadowImageFilter::Make(
senorblanco1150a6d2014-08-25 12:46:58 -0700813 SkIntToScalar(100), SkIntToScalar(100),
814 SkIntToScalar(10), SkIntToScalar(10),
sugoi234f0362014-10-23 13:59:52 -0700815 SK_ColorBLUE, SkDropShadowImageFilter::kDrawShadowAndForeground_ShadowMode,
robertphillipsc4169122016-04-06 08:40:59 -0700816 std::move(input));
senorblanco1150a6d2014-08-25 12:46:58 -0700817}
818
819DEF_TEST(ImageFilterBlurThenShadowBounds, reporter) {
robertphillips6e7025a2016-04-04 04:31:25 -0700820 sk_sp<SkImageFilter> filter1(make_blur(nullptr));
821 sk_sp<SkImageFilter> filter2(make_drop_shadow(std::move(filter1)));
senorblanco1150a6d2014-08-25 12:46:58 -0700822
823 SkIRect bounds = SkIRect::MakeXYWH(0, 0, 100, 100);
824 SkIRect expectedBounds = SkIRect::MakeXYWH(-133, -133, 236, 236);
senorblancoe5e79842016-03-21 14:51:59 -0700825 bounds = filter2->filterBounds(bounds, SkMatrix::I());
senorblanco1150a6d2014-08-25 12:46:58 -0700826
827 REPORTER_ASSERT(reporter, bounds == expectedBounds);
828}
829
830DEF_TEST(ImageFilterShadowThenBlurBounds, reporter) {
robertphillips6e7025a2016-04-04 04:31:25 -0700831 sk_sp<SkImageFilter> filter1(make_drop_shadow(nullptr));
832 sk_sp<SkImageFilter> filter2(make_blur(std::move(filter1)));
senorblanco1150a6d2014-08-25 12:46:58 -0700833
834 SkIRect bounds = SkIRect::MakeXYWH(0, 0, 100, 100);
835 SkIRect expectedBounds = SkIRect::MakeXYWH(-133, -133, 236, 236);
senorblancoe5e79842016-03-21 14:51:59 -0700836 bounds = filter2->filterBounds(bounds, SkMatrix::I());
senorblanco1150a6d2014-08-25 12:46:58 -0700837
838 REPORTER_ASSERT(reporter, bounds == expectedBounds);
839}
840
841DEF_TEST(ImageFilterDilateThenBlurBounds, reporter) {
robertphillipsfc11b0a2016-04-05 09:09:36 -0700842 sk_sp<SkImageFilter> filter1(SkDilateImageFilter::Make(2, 2, nullptr));
robertphillips6e7025a2016-04-04 04:31:25 -0700843 sk_sp<SkImageFilter> filter2(make_drop_shadow(std::move(filter1)));
senorblanco1150a6d2014-08-25 12:46:58 -0700844
845 SkIRect bounds = SkIRect::MakeXYWH(0, 0, 100, 100);
846 SkIRect expectedBounds = SkIRect::MakeXYWH(-132, -132, 234, 234);
senorblancoe5e79842016-03-21 14:51:59 -0700847 bounds = filter2->filterBounds(bounds, SkMatrix::I());
senorblanco1150a6d2014-08-25 12:46:58 -0700848
849 REPORTER_ASSERT(reporter, bounds == expectedBounds);
850}
851
ajuma5788faa2015-02-13 09:05:47 -0800852DEF_TEST(ImageFilterComposedBlurFastBounds, reporter) {
robertphillips6e7025a2016-04-04 04:31:25 -0700853 sk_sp<SkImageFilter> filter1(make_blur(nullptr));
854 sk_sp<SkImageFilter> filter2(make_blur(nullptr));
robertphillips491fb172016-03-30 12:32:58 -0700855 sk_sp<SkImageFilter> composedFilter(SkComposeImageFilter::Make(std::move(filter1),
856 std::move(filter2)));
ajuma5788faa2015-02-13 09:05:47 -0800857
858 SkRect boundsSrc = SkRect::MakeWH(SkIntToScalar(100), SkIntToScalar(100));
859 SkRect expectedBounds = SkRect::MakeXYWH(
860 SkIntToScalar(-6), SkIntToScalar(-6), SkIntToScalar(112), SkIntToScalar(112));
senorblancoe5e79842016-03-21 14:51:59 -0700861 SkRect boundsDst = composedFilter->computeFastBounds(boundsSrc);
ajuma5788faa2015-02-13 09:05:47 -0800862
863 REPORTER_ASSERT(reporter, boundsDst == expectedBounds);
864}
865
jbroman0e3129d2016-03-17 12:24:23 -0700866DEF_TEST(ImageFilterUnionBounds, reporter) {
robertphillips51a315e2016-03-31 09:05:49 -0700867 sk_sp<SkImageFilter> offset(SkOffsetImageFilter::Make(50, 0, nullptr));
jbroman0e3129d2016-03-17 12:24:23 -0700868 // Regardless of which order they appear in, the image filter bounds should
869 // be combined correctly.
870 {
robertphillips8c0326d2016-04-05 12:48:34 -0700871 sk_sp<SkImageFilter> composite(SkXfermodeImageFilter::Make(nullptr, offset));
jbroman0e3129d2016-03-17 12:24:23 -0700872 SkRect bounds = SkRect::MakeWH(100, 100);
873 // Intentionally aliasing here, as that's what the real callers do.
senorblancoe5e79842016-03-21 14:51:59 -0700874 bounds = composite->computeFastBounds(bounds);
jbroman0e3129d2016-03-17 12:24:23 -0700875 REPORTER_ASSERT(reporter, bounds == SkRect::MakeWH(150, 100));
876 }
877 {
reedcfb6bdf2016-03-29 11:32:50 -0700878 sk_sp<SkImageFilter> composite(SkXfermodeImageFilter::Make(nullptr, nullptr,
robertphillips8c0326d2016-04-05 12:48:34 -0700879 offset, nullptr));
jbroman0e3129d2016-03-17 12:24:23 -0700880 SkRect bounds = SkRect::MakeWH(100, 100);
881 // Intentionally aliasing here, as that's what the real callers do.
senorblancoe5e79842016-03-21 14:51:59 -0700882 bounds = composite->computeFastBounds(bounds);
jbroman0e3129d2016-03-17 12:24:23 -0700883 REPORTER_ASSERT(reporter, bounds == SkRect::MakeWH(150, 100));
884 }
885}
886
robertphillips3e302272016-04-20 11:48:36 -0700887static void test_imagefilter_merge_result_size(skiatest::Reporter* reporter, GrContext* context) {
senorblanco4a243982015-11-25 07:06:55 -0800888 SkBitmap greenBM;
889 greenBM.allocN32Pixels(20, 20);
890 greenBM.eraseColor(SK_ColorGREEN);
reed9ce9d672016-03-17 10:51:11 -0700891 sk_sp<SkImage> greenImage(SkImage::MakeFromBitmap(greenBM));
robertphillips549c8992016-04-01 09:28:51 -0700892 sk_sp<SkImageFilter> source(SkImageSource::Make(std::move(greenImage)));
robertphillips2238c9d2016-03-30 13:34:16 -0700893 sk_sp<SkImageFilter> merge(SkMergeImageFilter::Make(source, source));
senorblanco4a243982015-11-25 07:06:55 -0800894
robertphillips3e302272016-04-20 11:48:36 -0700895 sk_sp<SkSpecialImage> srcImg(create_empty_special_image(context, 1));
robertphillips4418dba2016-03-07 12:45:14 -0800896
reed4e23cda2016-01-11 10:56:59 -0800897 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeXYWH(0, 0, 100, 100), nullptr);
senorblanco4a243982015-11-25 07:06:55 -0800898 SkIPoint offset;
robertphillips4418dba2016-03-07 12:45:14 -0800899
robertphillips2302de92016-03-24 07:26:32 -0700900 sk_sp<SkSpecialImage> resultImg(merge->filterImage(srcImg.get(), ctx, &offset));
robertphillips4418dba2016-03-07 12:45:14 -0800901 REPORTER_ASSERT(reporter, resultImg);
902
903 REPORTER_ASSERT(reporter, resultImg->width() == 20 && resultImg->height() == 20);
senorblanco4a243982015-11-25 07:06:55 -0800904}
905
robertphillips4418dba2016-03-07 12:45:14 -0800906DEF_TEST(ImageFilterMergeResultSize, reporter) {
robertphillips3e302272016-04-20 11:48:36 -0700907 test_imagefilter_merge_result_size(reporter, nullptr);
robertphillips4418dba2016-03-07 12:45:14 -0800908}
909
910#if SK_SUPPORT_GPU
bsalomon758586c2016-04-06 14:02:39 -0700911DEF_GPUTEST_FOR_GL_RENDERING_CONTEXTS(ImageFilterMergeResultSize_Gpu, reporter, ctxInfo) {
robertphillips3e302272016-04-20 11:48:36 -0700912 test_imagefilter_merge_result_size(reporter, ctxInfo.fGrContext);
robertphillips4418dba2016-03-07 12:45:14 -0800913}
914#endif
915
robertphillipsa8d7f0b2014-08-29 08:03:56 -0700916static void draw_blurred_rect(SkCanvas* canvas) {
senorblanco837f5322014-07-14 10:19:54 -0700917 SkPaint filterPaint;
918 filterPaint.setColor(SK_ColorWHITE);
robertphillips6e7025a2016-04-04 04:31:25 -0700919 filterPaint.setImageFilter(SkBlurImageFilter::Make(SkIntToScalar(8), 0, nullptr));
halcanary96fcdcc2015-08-27 07:41:13 -0700920 canvas->saveLayer(nullptr, &filterPaint);
senorblanco837f5322014-07-14 10:19:54 -0700921 SkPaint whitePaint;
922 whitePaint.setColor(SK_ColorWHITE);
923 canvas->drawRect(SkRect::Make(SkIRect::MakeWH(4, 4)), whitePaint);
924 canvas->restore();
925}
926
robertphillipsa8d7f0b2014-08-29 08:03:56 -0700927static void draw_picture_clipped(SkCanvas* canvas, const SkRect& clipRect, const SkPicture* picture) {
senorblanco837f5322014-07-14 10:19:54 -0700928 canvas->save();
929 canvas->clipRect(clipRect);
930 canvas->drawPicture(picture);
931 canvas->restore();
932}
933
934DEF_TEST(ImageFilterDrawTiledBlurRTree, reporter) {
935 // Check that the blur filter when recorded with RTree acceleration,
936 // and drawn tiled (with subsequent clip rects) exactly
937 // matches the same filter drawn with without RTree acceleration.
938 // This tests that the "bleed" from the blur into the otherwise-blank
939 // tiles is correctly rendered.
940 // Tests pass by not asserting.
941
942 int width = 16, height = 8;
943 SkBitmap result1, result2;
944 result1.allocN32Pixels(width, height);
945 result2.allocN32Pixels(width, height);
946 SkCanvas canvas1(result1);
947 SkCanvas canvas2(result2);
948 int tileSize = 8;
949
950 canvas1.clear(0);
951 canvas2.clear(0);
952
953 SkRTreeFactory factory;
954
955 SkPictureRecorder recorder1, recorder2;
956 // The only difference between these two pictures is that one has RTree aceleration.
mtklein3f3b3d02014-12-01 11:47:08 -0800957 SkCanvas* recordingCanvas1 = recorder1.beginRecording(SkIntToScalar(width),
958 SkIntToScalar(height),
halcanary96fcdcc2015-08-27 07:41:13 -0700959 nullptr, 0);
mtklein3f3b3d02014-12-01 11:47:08 -0800960 SkCanvas* recordingCanvas2 = recorder2.beginRecording(SkIntToScalar(width),
961 SkIntToScalar(height),
robertphillipsa8d7f0b2014-08-29 08:03:56 -0700962 &factory, 0);
963 draw_blurred_rect(recordingCanvas1);
964 draw_blurred_rect(recordingCanvas2);
reedca2622b2016-03-18 07:25:55 -0700965 sk_sp<SkPicture> picture1(recorder1.finishRecordingAsPicture());
966 sk_sp<SkPicture> picture2(recorder2.finishRecordingAsPicture());
senorblanco837f5322014-07-14 10:19:54 -0700967 for (int y = 0; y < height; y += tileSize) {
968 for (int x = 0; x < width; x += tileSize) {
969 SkRect tileRect = SkRect::Make(SkIRect::MakeXYWH(x, y, tileSize, tileSize));
reedca2622b2016-03-18 07:25:55 -0700970 draw_picture_clipped(&canvas1, tileRect, picture1.get());
971 draw_picture_clipped(&canvas2, tileRect, picture2.get());
senorblanco837f5322014-07-14 10:19:54 -0700972 }
973 }
974 for (int y = 0; y < height; y++) {
975 int diffs = memcmp(result1.getAddr32(0, y), result2.getAddr32(0, y), result1.rowBytes());
976 REPORTER_ASSERT(reporter, !diffs);
977 if (diffs) {
978 break;
979 }
980 }
981}
982
senorblanco@chromium.org91957432014-05-01 14:03:41 +0000983DEF_TEST(ImageFilterMatrixConvolution, reporter) {
984 // Check that a 1x3 filter does not cause a spurious assert.
985 SkScalar kernel[3] = {
986 SkIntToScalar( 1), SkIntToScalar( 1), SkIntToScalar( 1),
987 };
988 SkISize kernelSize = SkISize::Make(1, 3);
989 SkScalar gain = SK_Scalar1, bias = 0;
990 SkIPoint kernelOffset = SkIPoint::Make(0, 0);
991
robertphillipsef6a47b2016-04-08 08:01:20 -0700992 sk_sp<SkImageFilter> filter(SkMatrixConvolutionImageFilter::Make(
993 kernelSize, kernel,
994 gain, bias, kernelOffset,
995 SkMatrixConvolutionImageFilter::kRepeat_TileMode,
996 false, nullptr));
senorblanco@chromium.org91957432014-05-01 14:03:41 +0000997
998 SkBitmap result;
999 int width = 16, height = 16;
1000 result.allocN32Pixels(width, height);
1001 SkCanvas canvas(result);
1002 canvas.clear(0);
1003
1004 SkPaint paint;
robertphillipsef6a47b2016-04-08 08:01:20 -07001005 paint.setImageFilter(std::move(filter));
senorblanco@chromium.org91957432014-05-01 14:03:41 +00001006 SkRect rect = SkRect::Make(SkIRect::MakeWH(width, height));
1007 canvas.drawRect(rect, paint);
1008}
1009
senorblanco@chromium.org8c7372b2014-05-02 19:13:11 +00001010DEF_TEST(ImageFilterMatrixConvolutionBorder, reporter) {
1011 // Check that a filter with borders outside the target bounds
1012 // does not crash.
1013 SkScalar kernel[3] = {
1014 0, 0, 0,
1015 };
1016 SkISize kernelSize = SkISize::Make(3, 1);
1017 SkScalar gain = SK_Scalar1, bias = 0;
1018 SkIPoint kernelOffset = SkIPoint::Make(2, 0);
1019
robertphillipsef6a47b2016-04-08 08:01:20 -07001020 sk_sp<SkImageFilter> filter(SkMatrixConvolutionImageFilter::Make(
1021 kernelSize, kernel, gain, bias, kernelOffset,
1022 SkMatrixConvolutionImageFilter::kClamp_TileMode,
1023 true, nullptr));
senorblanco@chromium.org8c7372b2014-05-02 19:13:11 +00001024
1025 SkBitmap result;
1026
1027 int width = 10, height = 10;
1028 result.allocN32Pixels(width, height);
1029 SkCanvas canvas(result);
1030 canvas.clear(0);
1031
1032 SkPaint filterPaint;
robertphillipsef6a47b2016-04-08 08:01:20 -07001033 filterPaint.setImageFilter(std::move(filter));
senorblanco@chromium.org8c7372b2014-05-02 19:13:11 +00001034 SkRect bounds = SkRect::MakeWH(1, 10);
1035 SkRect rect = SkRect::Make(SkIRect::MakeWH(width, height));
1036 SkPaint rectPaint;
1037 canvas.saveLayer(&bounds, &filterPaint);
1038 canvas.drawRect(rect, rectPaint);
1039 canvas.restore();
1040}
1041
robertphillips3e302272016-04-20 11:48:36 -07001042static void test_big_kernel(skiatest::Reporter* reporter, GrContext* context) {
robertphillipsdada4dd2016-04-13 04:54:36 -07001043 // Check that a kernel that is too big for the GPU still works
1044 SkScalar identityKernel[49] = {
1045 0, 0, 0, 0, 0, 0, 0,
1046 0, 0, 0, 0, 0, 0, 0,
1047 0, 0, 0, 0, 0, 0, 0,
1048 0, 0, 0, 1, 0, 0, 0,
1049 0, 0, 0, 0, 0, 0, 0,
1050 0, 0, 0, 0, 0, 0, 0,
1051 0, 0, 0, 0, 0, 0, 0
1052 };
1053 SkISize kernelSize = SkISize::Make(7, 7);
1054 SkScalar gain = SK_Scalar1, bias = 0;
1055 SkIPoint kernelOffset = SkIPoint::Make(0, 0);
1056
1057 sk_sp<SkImageFilter> filter(SkMatrixConvolutionImageFilter::Make(
1058 kernelSize, identityKernel, gain, bias, kernelOffset,
1059 SkMatrixConvolutionImageFilter::kClamp_TileMode,
1060 true, nullptr));
1061
robertphillips3e302272016-04-20 11:48:36 -07001062 sk_sp<SkSpecialImage> srcImg(create_empty_special_image(context, 100));
robertphillipsdada4dd2016-04-13 04:54:36 -07001063 SkASSERT(srcImg);
1064
1065 SkIPoint offset;
1066 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeWH(100, 100), nullptr);
1067 sk_sp<SkSpecialImage> resultImg(filter->filterImage(srcImg.get(), ctx, &offset));
1068 REPORTER_ASSERT(reporter, resultImg);
1069 REPORTER_ASSERT(reporter, SkToBool(context) == resultImg->isTextureBacked());
1070 REPORTER_ASSERT(reporter, resultImg->width() == 100 && resultImg->height() == 100);
1071 REPORTER_ASSERT(reporter, offset.fX == 0 && offset.fY == 0);
1072}
1073
1074DEF_TEST(ImageFilterMatrixConvolutionBigKernel, reporter) {
robertphillips3e302272016-04-20 11:48:36 -07001075 test_big_kernel(reporter, nullptr);
robertphillipsdada4dd2016-04-13 04:54:36 -07001076}
1077
1078#if SK_SUPPORT_GPU
1079DEF_GPUTEST_FOR_GL_RENDERING_CONTEXTS(ImageFilterMatrixConvolutionBigKernel_Gpu,
1080 reporter, ctxInfo) {
robertphillips3e302272016-04-20 11:48:36 -07001081 test_big_kernel(reporter, ctxInfo.fGrContext);
robertphillipsdada4dd2016-04-13 04:54:36 -07001082}
1083#endif
1084
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +00001085DEF_TEST(ImageFilterCropRect, reporter) {
robertphillips3e302272016-04-20 11:48:36 -07001086 test_crop_rects(reporter, nullptr);
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +00001087}
1088
robertphillips4418dba2016-03-07 12:45:14 -08001089#if SK_SUPPORT_GPU
bsalomon68d91342016-04-12 09:59:58 -07001090DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterCropRect_Gpu, reporter, ctxInfo) {
robertphillips3e302272016-04-20 11:48:36 -07001091 test_crop_rects(reporter, ctxInfo.fGrContext);
robertphillips4418dba2016-03-07 12:45:14 -08001092}
1093#endif
1094
tfarina9ea53f92014-06-24 06:50:39 -07001095DEF_TEST(ImageFilterMatrix, reporter) {
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +00001096 SkBitmap temp;
mike@reedtribe.orgdeee4962014-02-13 14:41:43 +00001097 temp.allocN32Pixels(100, 100);
robertphillips9a53fd72015-06-22 09:46:59 -07001098 SkCanvas canvas(temp);
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +00001099 canvas.scale(SkIntToScalar(2), SkIntToScalar(2));
1100
1101 SkMatrix expectedMatrix = canvas.getTotalMatrix();
1102
commit-bot@chromium.org5fb2ce32014-04-17 23:35:06 +00001103 SkRTreeFactory factory;
1104 SkPictureRecorder recorder;
1105 SkCanvas* recordingCanvas = recorder.beginRecording(100, 100, &factory, 0);
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +00001106
1107 SkPaint paint;
robertphillips43c2ad42016-04-04 05:05:11 -07001108 paint.setImageFilter(MatrixTestImageFilter::Make(reporter, expectedMatrix));
halcanary96fcdcc2015-08-27 07:41:13 -07001109 recordingCanvas->saveLayer(nullptr, &paint);
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +00001110 SkPaint solidPaint;
1111 solidPaint.setColor(0xFFFFFFFF);
1112 recordingCanvas->save();
1113 recordingCanvas->scale(SkIntToScalar(10), SkIntToScalar(10));
1114 recordingCanvas->drawRect(SkRect::Make(SkIRect::MakeWH(100, 100)), solidPaint);
1115 recordingCanvas->restore(); // scale
1116 recordingCanvas->restore(); // saveLayer
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +00001117
reedca2622b2016-03-18 07:25:55 -07001118 canvas.drawPicture(recorder.finishRecordingAsPicture());
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +00001119}
1120
senorblanco3d822c22014-07-30 14:49:31 -07001121DEF_TEST(ImageFilterCrossProcessPictureImageFilter, reporter) {
senorblanco@chromium.org97f5fc62014-05-30 20:50:56 +00001122 SkRTreeFactory factory;
1123 SkPictureRecorder recorder;
1124 SkCanvas* recordingCanvas = recorder.beginRecording(1, 1, &factory, 0);
1125
1126 // Create an SkPicture which simply draws a green 1x1 rectangle.
1127 SkPaint greenPaint;
1128 greenPaint.setColor(SK_ColorGREEN);
1129 recordingCanvas->drawRect(SkRect::Make(SkIRect::MakeWH(1, 1)), greenPaint);
reedca2622b2016-03-18 07:25:55 -07001130 sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture());
senorblanco@chromium.org97f5fc62014-05-30 20:50:56 +00001131
1132 // Wrap that SkPicture in an SkPictureImageFilter.
robertphillips5ff17b12016-03-28 13:13:42 -07001133 sk_sp<SkImageFilter> imageFilter(SkPictureImageFilter::Make(picture));
senorblanco@chromium.org97f5fc62014-05-30 20:50:56 +00001134
1135 // Check that SkPictureImageFilter successfully serializes its contained
1136 // SkPicture when not in cross-process mode.
1137 SkPaint paint;
robertphillips5ff17b12016-03-28 13:13:42 -07001138 paint.setImageFilter(imageFilter);
senorblanco@chromium.org97f5fc62014-05-30 20:50:56 +00001139 SkPictureRecorder outerRecorder;
1140 SkCanvas* outerCanvas = outerRecorder.beginRecording(1, 1, &factory, 0);
1141 SkPaint redPaintWithFilter;
1142 redPaintWithFilter.setColor(SK_ColorRED);
robertphillips5ff17b12016-03-28 13:13:42 -07001143 redPaintWithFilter.setImageFilter(imageFilter);
senorblanco@chromium.org97f5fc62014-05-30 20:50:56 +00001144 outerCanvas->drawRect(SkRect::Make(SkIRect::MakeWH(1, 1)), redPaintWithFilter);
reedca2622b2016-03-18 07:25:55 -07001145 sk_sp<SkPicture> outerPicture(outerRecorder.finishRecordingAsPicture());
senorblanco@chromium.org97f5fc62014-05-30 20:50:56 +00001146
1147 SkBitmap bitmap;
1148 bitmap.allocN32Pixels(1, 1);
robertphillips9a53fd72015-06-22 09:46:59 -07001149 SkCanvas canvas(bitmap);
senorblanco@chromium.org97f5fc62014-05-30 20:50:56 +00001150
1151 // The result here should be green, since the filter replaces the primitive's red interior.
1152 canvas.clear(0x0);
robertphillips9b14f262014-06-04 05:40:44 -07001153 canvas.drawPicture(outerPicture);
senorblanco@chromium.org97f5fc62014-05-30 20:50:56 +00001154 uint32_t pixel = *bitmap.getAddr32(0, 0);
1155 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1156
1157 // Check that, for now, SkPictureImageFilter does not serialize or
1158 // deserialize its contained picture when the filter is serialized
1159 // cross-process. Do this by "laundering" it through SkValidatingReadBuffer.
robertphillips12fa47d2016-04-08 16:28:09 -07001160 sk_sp<SkData> data(SkValidatingSerializeFlattenable(imageFilter.get()));
1161 sk_sp<SkFlattenable> flattenable(SkValidatingDeserializeFlattenable(
mtklein3b375452016-04-04 14:57:19 -07001162 data->data(), data->size(), SkImageFilter::GetFlattenableType()));
senorblanco@chromium.org97f5fc62014-05-30 20:50:56 +00001163 SkImageFilter* unflattenedFilter = static_cast<SkImageFilter*>(flattenable.get());
1164
1165 redPaintWithFilter.setImageFilter(unflattenedFilter);
1166 SkPictureRecorder crossProcessRecorder;
1167 SkCanvas* crossProcessCanvas = crossProcessRecorder.beginRecording(1, 1, &factory, 0);
1168 crossProcessCanvas->drawRect(SkRect::Make(SkIRect::MakeWH(1, 1)), redPaintWithFilter);
reedca2622b2016-03-18 07:25:55 -07001169 sk_sp<SkPicture> crossProcessPicture(crossProcessRecorder.finishRecordingAsPicture());
senorblanco@chromium.org97f5fc62014-05-30 20:50:56 +00001170
1171 canvas.clear(0x0);
robertphillips9b14f262014-06-04 05:40:44 -07001172 canvas.drawPicture(crossProcessPicture);
senorblanco@chromium.org97f5fc62014-05-30 20:50:56 +00001173 pixel = *bitmap.getAddr32(0, 0);
hendrikw446ee672015-06-16 09:28:37 -07001174 // If the security precautions are enabled, the result here should not be green, since the
1175 // filter draws nothing.
mtklein2afbe232016-02-07 12:23:10 -08001176 REPORTER_ASSERT(reporter, SkPicture::PictureIOSecurityPrecautionsEnabled()
hendrikw446ee672015-06-16 09:28:37 -07001177 ? pixel != SK_ColorGREEN : pixel == SK_ColorGREEN);
senorblanco@chromium.org97f5fc62014-05-30 20:50:56 +00001178}
1179
robertphillips3e302272016-04-20 11:48:36 -07001180static void test_clipped_picture_imagefilter(skiatest::Reporter* reporter, GrContext* context) {
reedca2622b2016-03-18 07:25:55 -07001181 sk_sp<SkPicture> picture;
senorblanco3d822c22014-07-30 14:49:31 -07001182
robertphillips4418dba2016-03-07 12:45:14 -08001183 {
1184 SkRTreeFactory factory;
1185 SkPictureRecorder recorder;
1186 SkCanvas* recordingCanvas = recorder.beginRecording(1, 1, &factory, 0);
1187
1188 // Create an SkPicture which simply draws a green 1x1 rectangle.
1189 SkPaint greenPaint;
1190 greenPaint.setColor(SK_ColorGREEN);
1191 recordingCanvas->drawRect(SkRect::Make(SkIRect::MakeWH(1, 1)), greenPaint);
reedca2622b2016-03-18 07:25:55 -07001192 picture = recorder.finishRecordingAsPicture();
robertphillips4418dba2016-03-07 12:45:14 -08001193 }
1194
robertphillips3e302272016-04-20 11:48:36 -07001195 sk_sp<SkSpecialImage> srcImg(create_empty_special_image(context, 2));
senorblanco3d822c22014-07-30 14:49:31 -07001196
robertphillips5ff17b12016-03-28 13:13:42 -07001197 sk_sp<SkImageFilter> imageFilter(SkPictureImageFilter::Make(picture));
senorblanco3d822c22014-07-30 14:49:31 -07001198
senorblanco3d822c22014-07-30 14:49:31 -07001199 SkIPoint offset;
reed4e23cda2016-01-11 10:56:59 -08001200 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeXYWH(1, 1, 1, 1), nullptr);
robertphillips4418dba2016-03-07 12:45:14 -08001201
robertphillips2302de92016-03-24 07:26:32 -07001202 sk_sp<SkSpecialImage> resultImage(imageFilter->filterImage(srcImg.get(), ctx, &offset));
robertphillips4418dba2016-03-07 12:45:14 -08001203 REPORTER_ASSERT(reporter, !resultImage);
senorblanco3d822c22014-07-30 14:49:31 -07001204}
1205
robertphillips4418dba2016-03-07 12:45:14 -08001206DEF_TEST(ImageFilterClippedPictureImageFilter, reporter) {
robertphillips3e302272016-04-20 11:48:36 -07001207 test_clipped_picture_imagefilter(reporter, nullptr);
robertphillips4418dba2016-03-07 12:45:14 -08001208}
1209
1210#if SK_SUPPORT_GPU
bsalomon68d91342016-04-12 09:59:58 -07001211DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterClippedPictureImageFilter_Gpu, reporter, ctxInfo) {
robertphillips3e302272016-04-20 11:48:36 -07001212 test_clipped_picture_imagefilter(reporter, ctxInfo.fGrContext);
robertphillips4418dba2016-03-07 12:45:14 -08001213}
1214#endif
1215
tfarina9ea53f92014-06-24 06:50:39 -07001216DEF_TEST(ImageFilterEmptySaveLayer, reporter) {
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001217 // Even when there's an empty saveLayer()/restore(), ensure that an image
1218 // filter or color filter which affects transparent black still draws.
1219
1220 SkBitmap bitmap;
1221 bitmap.allocN32Pixels(10, 10);
robertphillips9a53fd72015-06-22 09:46:59 -07001222 SkCanvas canvas(bitmap);
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001223
1224 SkRTreeFactory factory;
1225 SkPictureRecorder recorder;
1226
robertphillips5605b562016-04-05 11:50:42 -07001227 sk_sp<SkColorFilter> green(SkColorFilter::MakeModeFilter(SK_ColorGREEN,
1228 SkXfermode::kSrc_Mode));
1229 sk_sp<SkImageFilter> imageFilter(SkColorFilterImageFilter::Make(green, nullptr));
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001230 SkPaint imageFilterPaint;
robertphillips5605b562016-04-05 11:50:42 -07001231 imageFilterPaint.setImageFilter(std::move(imageFilter));
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001232 SkPaint colorFilterPaint;
reedd053ce92016-03-22 10:17:23 -07001233 colorFilterPaint.setColorFilter(green);
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001234
1235 SkRect bounds = SkRect::MakeWH(10, 10);
1236
1237 SkCanvas* recordingCanvas = recorder.beginRecording(10, 10, &factory, 0);
1238 recordingCanvas->saveLayer(&bounds, &imageFilterPaint);
1239 recordingCanvas->restore();
reedca2622b2016-03-18 07:25:55 -07001240 sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture());
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001241
1242 canvas.clear(0);
robertphillips9b14f262014-06-04 05:40:44 -07001243 canvas.drawPicture(picture);
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001244 uint32_t pixel = *bitmap.getAddr32(0, 0);
1245 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1246
1247 recordingCanvas = recorder.beginRecording(10, 10, &factory, 0);
halcanary96fcdcc2015-08-27 07:41:13 -07001248 recordingCanvas->saveLayer(nullptr, &imageFilterPaint);
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001249 recordingCanvas->restore();
reedca2622b2016-03-18 07:25:55 -07001250 sk_sp<SkPicture> picture2(recorder.finishRecordingAsPicture());
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001251
1252 canvas.clear(0);
robertphillips9b14f262014-06-04 05:40:44 -07001253 canvas.drawPicture(picture2);
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001254 pixel = *bitmap.getAddr32(0, 0);
1255 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1256
1257 recordingCanvas = recorder.beginRecording(10, 10, &factory, 0);
1258 recordingCanvas->saveLayer(&bounds, &colorFilterPaint);
1259 recordingCanvas->restore();
reedca2622b2016-03-18 07:25:55 -07001260 sk_sp<SkPicture> picture3(recorder.finishRecordingAsPicture());
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001261
1262 canvas.clear(0);
robertphillips9b14f262014-06-04 05:40:44 -07001263 canvas.drawPicture(picture3);
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001264 pixel = *bitmap.getAddr32(0, 0);
1265 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1266}
1267
robertphillips9a53fd72015-06-22 09:46:59 -07001268static void test_huge_blur(SkCanvas* canvas, skiatest::Reporter* reporter) {
senorblanco@chromium.org09843fd2014-03-24 20:50:59 +00001269 SkBitmap bitmap;
1270 bitmap.allocN32Pixels(100, 100);
1271 bitmap.eraseARGB(0, 0, 0, 0);
1272
1273 // Check that a blur with an insane radius does not crash or assert.
senorblanco@chromium.org09843fd2014-03-24 20:50:59 +00001274 SkPaint paint;
robertphillips6e7025a2016-04-04 04:31:25 -07001275 paint.setImageFilter(SkBlurImageFilter::Make(SkIntToScalar(1<<30),
1276 SkIntToScalar(1<<30),
1277 nullptr));
reedda420b92015-12-16 08:38:15 -08001278 canvas->drawBitmap(bitmap, 0, 0, &paint);
senorblanco@chromium.org09843fd2014-03-24 20:50:59 +00001279}
1280
1281DEF_TEST(HugeBlurImageFilter, reporter) {
1282 SkBitmap temp;
1283 temp.allocN32Pixels(100, 100);
robertphillips9a53fd72015-06-22 09:46:59 -07001284 SkCanvas canvas(temp);
1285 test_huge_blur(&canvas, reporter);
senorblanco@chromium.org09843fd2014-03-24 20:50:59 +00001286}
1287
senorblanco21a465d2016-04-11 11:58:39 -07001288DEF_TEST(ImageFilterMatrixConvolutionSanityTest, reporter) {
senorblanco3a495202014-09-29 07:57:20 -07001289 SkScalar kernel[1] = { 0 };
1290 SkScalar gain = SK_Scalar1, bias = 0;
1291 SkIPoint kernelOffset = SkIPoint::Make(1, 1);
1292
halcanary96fcdcc2015-08-27 07:41:13 -07001293 // Check that an enormous (non-allocatable) kernel gives a nullptr filter.
robertphillipsef6a47b2016-04-08 08:01:20 -07001294 sk_sp<SkImageFilter> conv(SkMatrixConvolutionImageFilter::Make(
senorblanco3a495202014-09-29 07:57:20 -07001295 SkISize::Make(1<<30, 1<<30),
1296 kernel,
1297 gain,
1298 bias,
1299 kernelOffset,
1300 SkMatrixConvolutionImageFilter::kRepeat_TileMode,
robertphillipsef6a47b2016-04-08 08:01:20 -07001301 false,
1302 nullptr));
senorblanco3a495202014-09-29 07:57:20 -07001303
halcanary96fcdcc2015-08-27 07:41:13 -07001304 REPORTER_ASSERT(reporter, nullptr == conv.get());
senorblanco3a495202014-09-29 07:57:20 -07001305
halcanary96fcdcc2015-08-27 07:41:13 -07001306 // Check that a nullptr kernel gives a nullptr filter.
robertphillipsef6a47b2016-04-08 08:01:20 -07001307 conv = SkMatrixConvolutionImageFilter::Make(
senorblanco3a495202014-09-29 07:57:20 -07001308 SkISize::Make(1, 1),
halcanary96fcdcc2015-08-27 07:41:13 -07001309 nullptr,
senorblanco3a495202014-09-29 07:57:20 -07001310 gain,
1311 bias,
1312 kernelOffset,
1313 SkMatrixConvolutionImageFilter::kRepeat_TileMode,
robertphillipsef6a47b2016-04-08 08:01:20 -07001314 false,
1315 nullptr);
senorblanco3a495202014-09-29 07:57:20 -07001316
halcanary96fcdcc2015-08-27 07:41:13 -07001317 REPORTER_ASSERT(reporter, nullptr == conv.get());
senorblanco3a495202014-09-29 07:57:20 -07001318
halcanary96fcdcc2015-08-27 07:41:13 -07001319 // Check that a kernel width < 1 gives a nullptr filter.
robertphillipsef6a47b2016-04-08 08:01:20 -07001320 conv = SkMatrixConvolutionImageFilter::Make(
senorblanco3a495202014-09-29 07:57:20 -07001321 SkISize::Make(0, 1),
1322 kernel,
1323 gain,
1324 bias,
1325 kernelOffset,
1326 SkMatrixConvolutionImageFilter::kRepeat_TileMode,
robertphillipsef6a47b2016-04-08 08:01:20 -07001327 false,
1328 nullptr);
senorblanco3a495202014-09-29 07:57:20 -07001329
halcanary96fcdcc2015-08-27 07:41:13 -07001330 REPORTER_ASSERT(reporter, nullptr == conv.get());
senorblanco3a495202014-09-29 07:57:20 -07001331
halcanary96fcdcc2015-08-27 07:41:13 -07001332 // Check that kernel height < 1 gives a nullptr filter.
robertphillipsef6a47b2016-04-08 08:01:20 -07001333 conv = SkMatrixConvolutionImageFilter::Make(
senorblanco3a495202014-09-29 07:57:20 -07001334 SkISize::Make(1, -1),
1335 kernel,
1336 gain,
1337 bias,
1338 kernelOffset,
1339 SkMatrixConvolutionImageFilter::kRepeat_TileMode,
robertphillipsef6a47b2016-04-08 08:01:20 -07001340 false,
1341 nullptr);
senorblanco3a495202014-09-29 07:57:20 -07001342
halcanary96fcdcc2015-08-27 07:41:13 -07001343 REPORTER_ASSERT(reporter, nullptr == conv.get());
senorblanco3a495202014-09-29 07:57:20 -07001344}
1345
robertphillips9a53fd72015-06-22 09:46:59 -07001346static void test_xfermode_cropped_input(SkCanvas* canvas, skiatest::Reporter* reporter) {
1347 canvas->clear(0);
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001348
1349 SkBitmap bitmap;
1350 bitmap.allocN32Pixels(1, 1);
1351 bitmap.eraseARGB(255, 255, 255, 255);
1352
robertphillips5605b562016-04-05 11:50:42 -07001353 sk_sp<SkColorFilter> green(SkColorFilter::MakeModeFilter(SK_ColorGREEN,
1354 SkXfermode::kSrcIn_Mode));
1355 sk_sp<SkImageFilter> greenFilter(SkColorFilterImageFilter::Make(green, nullptr));
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001356 SkImageFilter::CropRect cropRect(SkRect::MakeEmpty());
robertphillips5605b562016-04-05 11:50:42 -07001357 sk_sp<SkImageFilter> croppedOut(SkColorFilterImageFilter::Make(green, nullptr, &cropRect));
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001358
1359 // Check that an xfermode image filter whose input has been cropped out still draws the other
1360 // input. Also check that drawing with both inputs cropped out doesn't cause a GPU warning.
robertphillips8c0326d2016-04-05 12:48:34 -07001361 sk_sp<SkXfermode> mode(SkXfermode::Make(SkXfermode::kSrcOver_Mode));
1362 sk_sp<SkImageFilter> xfermodeNoFg(SkXfermodeImageFilter::Make(mode, greenFilter,
1363 croppedOut, nullptr));
1364 sk_sp<SkImageFilter> xfermodeNoBg(SkXfermodeImageFilter::Make(mode, croppedOut,
1365 greenFilter, nullptr));
1366 sk_sp<SkImageFilter> xfermodeNoFgNoBg(SkXfermodeImageFilter::Make(mode, croppedOut,
1367 croppedOut, nullptr));
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001368
1369 SkPaint paint;
robertphillips8c0326d2016-04-05 12:48:34 -07001370 paint.setImageFilter(std::move(xfermodeNoFg));
reedda420b92015-12-16 08:38:15 -08001371 canvas->drawBitmap(bitmap, 0, 0, &paint); // drawSprite
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001372
1373 uint32_t pixel;
kkinnunena9d9a392015-03-06 07:16:00 -08001374 SkImageInfo info = SkImageInfo::Make(1, 1, kBGRA_8888_SkColorType, kUnpremul_SkAlphaType);
robertphillips9a53fd72015-06-22 09:46:59 -07001375 canvas->readPixels(info, &pixel, 4, 0, 0);
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001376 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1377
robertphillips8c0326d2016-04-05 12:48:34 -07001378 paint.setImageFilter(std::move(xfermodeNoBg));
reedda420b92015-12-16 08:38:15 -08001379 canvas->drawBitmap(bitmap, 0, 0, &paint); // drawSprite
robertphillips9a53fd72015-06-22 09:46:59 -07001380 canvas->readPixels(info, &pixel, 4, 0, 0);
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001381 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1382
robertphillips8c0326d2016-04-05 12:48:34 -07001383 paint.setImageFilter(std::move(xfermodeNoFgNoBg));
reedda420b92015-12-16 08:38:15 -08001384 canvas->drawBitmap(bitmap, 0, 0, &paint); // drawSprite
robertphillips9a53fd72015-06-22 09:46:59 -07001385 canvas->readPixels(info, &pixel, 4, 0, 0);
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001386 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1387}
1388
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001389DEF_TEST(ImageFilterNestedSaveLayer, reporter) {
1390 SkBitmap temp;
1391 temp.allocN32Pixels(50, 50);
robertphillips9a53fd72015-06-22 09:46:59 -07001392 SkCanvas canvas(temp);
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001393 canvas.clear(0x0);
1394
1395 SkBitmap bitmap;
1396 bitmap.allocN32Pixels(10, 10);
1397 bitmap.eraseColor(SK_ColorGREEN);
1398
1399 SkMatrix matrix;
1400 matrix.setScale(SkIntToScalar(2), SkIntToScalar(2));
1401 matrix.postTranslate(SkIntToScalar(-20), SkIntToScalar(-20));
robertphillipsae8c9332016-04-05 15:09:00 -07001402 sk_sp<SkImageFilter> matrixFilter(
1403 SkImageFilter::MakeMatrixFilter(matrix, kLow_SkFilterQuality, nullptr));
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001404
1405 // Test that saveLayer() with a filter nested inside another saveLayer() applies the
1406 // correct offset to the filter matrix.
1407 SkRect bounds1 = SkRect::MakeXYWH(10, 10, 30, 30);
halcanary96fcdcc2015-08-27 07:41:13 -07001408 canvas.saveLayer(&bounds1, nullptr);
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001409 SkPaint filterPaint;
robertphillipsae8c9332016-04-05 15:09:00 -07001410 filterPaint.setImageFilter(std::move(matrixFilter));
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001411 SkRect bounds2 = SkRect::MakeXYWH(20, 20, 10, 10);
1412 canvas.saveLayer(&bounds2, &filterPaint);
1413 SkPaint greenPaint;
1414 greenPaint.setColor(SK_ColorGREEN);
1415 canvas.drawRect(bounds2, greenPaint);
1416 canvas.restore();
1417 canvas.restore();
1418 SkPaint strokePaint;
1419 strokePaint.setStyle(SkPaint::kStroke_Style);
1420 strokePaint.setColor(SK_ColorRED);
1421
kkinnunena9d9a392015-03-06 07:16:00 -08001422 SkImageInfo info = SkImageInfo::Make(1, 1, kBGRA_8888_SkColorType, kUnpremul_SkAlphaType);
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001423 uint32_t pixel;
1424 canvas.readPixels(info, &pixel, 4, 25, 25);
1425 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1426
1427 // Test that drawSprite() with a filter nested inside a saveLayer() applies the
1428 // correct offset to the filter matrix.
1429 canvas.clear(0x0);
1430 canvas.readPixels(info, &pixel, 4, 25, 25);
halcanary96fcdcc2015-08-27 07:41:13 -07001431 canvas.saveLayer(&bounds1, nullptr);
reedda420b92015-12-16 08:38:15 -08001432 canvas.drawBitmap(bitmap, 20, 20, &filterPaint); // drawSprite
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001433 canvas.restore();
1434
1435 canvas.readPixels(info, &pixel, 4, 25, 25);
1436 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1437}
1438
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001439DEF_TEST(XfermodeImageFilterCroppedInput, reporter) {
1440 SkBitmap temp;
1441 temp.allocN32Pixels(100, 100);
robertphillips9a53fd72015-06-22 09:46:59 -07001442 SkCanvas canvas(temp);
1443 test_xfermode_cropped_input(&canvas, reporter);
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001444}
senorblanco@chromium.org09843fd2014-03-24 20:50:59 +00001445
robertphillips3e302272016-04-20 11:48:36 -07001446static void test_composed_imagefilter_offset(skiatest::Reporter* reporter, GrContext* context) {
1447 sk_sp<SkSpecialImage> srcImg(create_empty_special_image(context, 100));
ajuma5788faa2015-02-13 09:05:47 -08001448
1449 SkImageFilter::CropRect cropRect(SkRect::MakeXYWH(1, 0, 20, 20));
robertphillips51a315e2016-03-31 09:05:49 -07001450 sk_sp<SkImageFilter> offsetFilter(SkOffsetImageFilter::Make(0, 0, nullptr, &cropRect));
robertphillips6e7025a2016-04-04 04:31:25 -07001451 sk_sp<SkImageFilter> blurFilter(SkBlurImageFilter::Make(SK_Scalar1, SK_Scalar1,
1452 nullptr, &cropRect));
robertphillips491fb172016-03-30 12:32:58 -07001453 sk_sp<SkImageFilter> composedFilter(SkComposeImageFilter::Make(std::move(blurFilter),
1454 std::move(offsetFilter)));
ajuma5788faa2015-02-13 09:05:47 -08001455 SkIPoint offset;
reed4e23cda2016-01-11 10:56:59 -08001456 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeWH(100, 100), nullptr);
robertphillips4418dba2016-03-07 12:45:14 -08001457
robertphillips2302de92016-03-24 07:26:32 -07001458 sk_sp<SkSpecialImage> resultImg(composedFilter->filterImage(srcImg.get(), ctx, &offset));
robertphillips4418dba2016-03-07 12:45:14 -08001459 REPORTER_ASSERT(reporter, resultImg);
ajuma5788faa2015-02-13 09:05:47 -08001460 REPORTER_ASSERT(reporter, offset.fX == 1 && offset.fY == 0);
1461}
1462
robertphillips4418dba2016-03-07 12:45:14 -08001463DEF_TEST(ComposedImageFilterOffset, reporter) {
robertphillips3e302272016-04-20 11:48:36 -07001464 test_composed_imagefilter_offset(reporter, nullptr);
robertphillips4418dba2016-03-07 12:45:14 -08001465}
1466
1467#if SK_SUPPORT_GPU
bsalomon68d91342016-04-12 09:59:58 -07001468DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ComposedImageFilterOffset_Gpu, reporter, ctxInfo) {
robertphillips3e302272016-04-20 11:48:36 -07001469 test_composed_imagefilter_offset(reporter, ctxInfo.fGrContext);
robertphillips4418dba2016-03-07 12:45:14 -08001470}
1471#endif
1472
robertphillips3e302272016-04-20 11:48:36 -07001473static void test_composed_imagefilter_bounds(skiatest::Reporter* reporter, GrContext* context) {
jbroman17a65202016-03-21 08:38:58 -07001474 // The bounds passed to the inner filter must be filtered by the outer
1475 // filter, so that the inner filter produces the pixels that the outer
1476 // filter requires as input. This matters if the outer filter moves pixels.
1477 // Here, accounting for the outer offset is necessary so that the green
1478 // pixels of the picture are not clipped.
1479
1480 SkPictureRecorder recorder;
1481 SkCanvas* recordingCanvas = recorder.beginRecording(SkRect::MakeWH(200, 100));
1482 recordingCanvas->clipRect(SkRect::MakeXYWH(100, 0, 100, 100));
1483 recordingCanvas->clear(SK_ColorGREEN);
robertphillips491fb172016-03-30 12:32:58 -07001484 sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture());
robertphillips5ff17b12016-03-28 13:13:42 -07001485 sk_sp<SkImageFilter> pictureFilter(SkPictureImageFilter::Make(picture));
jbroman17a65202016-03-21 08:38:58 -07001486 SkImageFilter::CropRect cropRect(SkRect::MakeWH(100, 100));
robertphillips51a315e2016-03-31 09:05:49 -07001487 sk_sp<SkImageFilter> offsetFilter(SkOffsetImageFilter::Make(-100, 0, nullptr, &cropRect));
robertphillips491fb172016-03-30 12:32:58 -07001488 sk_sp<SkImageFilter> composedFilter(SkComposeImageFilter::Make(std::move(offsetFilter),
1489 std::move(pictureFilter)));
jbroman17a65202016-03-21 08:38:58 -07001490
robertphillips3e302272016-04-20 11:48:36 -07001491 sk_sp<SkSpecialImage> sourceImage(create_empty_special_image(context, 100));
jbroman17a65202016-03-21 08:38:58 -07001492 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeWH(100, 100), nullptr);
1493 SkIPoint offset;
1494 sk_sp<SkSpecialImage> result(composedFilter->filterImage(sourceImage.get(), ctx, &offset));
1495 REPORTER_ASSERT(reporter, offset.isZero());
1496 REPORTER_ASSERT(reporter, result);
1497 REPORTER_ASSERT(reporter, result->subset().size() == SkISize::Make(100, 100));
1498
1499 SkBitmap resultBM;
robertphillips64612512016-04-08 12:10:42 -07001500 REPORTER_ASSERT(reporter, result->getROPixels(&resultBM));
jbroman17a65202016-03-21 08:38:58 -07001501 SkAutoLockPixels lock(resultBM);
1502 REPORTER_ASSERT(reporter, resultBM.getColor(50, 50) == SK_ColorGREEN);
1503}
1504
1505DEF_TEST(ComposedImageFilterBounds, reporter) {
robertphillips3e302272016-04-20 11:48:36 -07001506 test_composed_imagefilter_bounds(reporter, nullptr);
jbroman17a65202016-03-21 08:38:58 -07001507}
1508
1509#if SK_SUPPORT_GPU
bsalomon758586c2016-04-06 14:02:39 -07001510DEF_GPUTEST_FOR_GL_RENDERING_CONTEXTS(ComposedImageFilterBounds_Gpu, reporter, ctxInfo) {
robertphillips3e302272016-04-20 11:48:36 -07001511 test_composed_imagefilter_bounds(reporter, ctxInfo.fGrContext);
jbroman17a65202016-03-21 08:38:58 -07001512}
1513#endif
1514
robertphillips3e302272016-04-20 11:48:36 -07001515static void test_partial_crop_rect(skiatest::Reporter* reporter, GrContext* context) {
1516 sk_sp<SkSpecialImage> srcImg(create_empty_special_image(context, 100));
senorblanco24d2a7b2015-07-13 10:27:05 -07001517
1518 SkImageFilter::CropRect cropRect(SkRect::MakeXYWH(100, 0, 20, 30),
senorblancoed7cf272015-07-16 15:19:11 -07001519 SkImageFilter::CropRect::kHasWidth_CropEdge | SkImageFilter::CropRect::kHasHeight_CropEdge);
robertphillips5605b562016-04-05 11:50:42 -07001520 sk_sp<SkImageFilter> filter(make_grayscale(nullptr, &cropRect));
senorblanco24d2a7b2015-07-13 10:27:05 -07001521 SkIPoint offset;
reed4e23cda2016-01-11 10:56:59 -08001522 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeWH(100, 100), nullptr);
robertphillips4418dba2016-03-07 12:45:14 -08001523
robertphillips2302de92016-03-24 07:26:32 -07001524 sk_sp<SkSpecialImage> resultImg(filter->filterImage(srcImg.get(), ctx, &offset));
robertphillips4418dba2016-03-07 12:45:14 -08001525 REPORTER_ASSERT(reporter, resultImg);
1526
senorblanco24d2a7b2015-07-13 10:27:05 -07001527 REPORTER_ASSERT(reporter, offset.fX == 0);
1528 REPORTER_ASSERT(reporter, offset.fY == 0);
robertphillips4418dba2016-03-07 12:45:14 -08001529 REPORTER_ASSERT(reporter, resultImg->width() == 20);
1530 REPORTER_ASSERT(reporter, resultImg->height() == 30);
senorblanco24d2a7b2015-07-13 10:27:05 -07001531}
1532
senorblanco21a465d2016-04-11 11:58:39 -07001533DEF_TEST(ImageFilterPartialCropRect, reporter) {
robertphillips3e302272016-04-20 11:48:36 -07001534 test_partial_crop_rect(reporter, nullptr);
robertphillips4418dba2016-03-07 12:45:14 -08001535}
1536
1537#if SK_SUPPORT_GPU
bsalomon68d91342016-04-12 09:59:58 -07001538DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterPartialCropRect_Gpu, reporter, ctxInfo) {
robertphillips3e302272016-04-20 11:48:36 -07001539 test_partial_crop_rect(reporter, ctxInfo.fGrContext);
robertphillips4418dba2016-03-07 12:45:14 -08001540}
1541#endif
1542
senorblanco0abdf762015-08-20 11:10:41 -07001543DEF_TEST(ImageFilterCanComputeFastBounds, reporter) {
1544
robertphillips12fa47d2016-04-08 16:28:09 -07001545 {
1546 SkPoint3 location = SkPoint3::Make(0, 0, SK_Scalar1);
1547 sk_sp<SkImageFilter> lighting(SkLightingImageFilter::MakePointLitDiffuse(location,
1548 SK_ColorGREEN,
1549 0, 0, nullptr));
1550 REPORTER_ASSERT(reporter, !lighting->canComputeFastBounds());
1551 }
senorblanco0abdf762015-08-20 11:10:41 -07001552
senorblanco0abdf762015-08-20 11:10:41 -07001553 {
robertphillips6e7025a2016-04-04 04:31:25 -07001554 sk_sp<SkImageFilter> gray(make_grayscale(nullptr, nullptr));
1555 REPORTER_ASSERT(reporter, gray->canComputeFastBounds());
1556 {
1557 SkColorFilter* grayCF;
1558 REPORTER_ASSERT(reporter, gray->asAColorFilter(&grayCF));
1559 REPORTER_ASSERT(reporter, !grayCF->affectsTransparentBlack());
1560 grayCF->unref();
1561 }
1562 REPORTER_ASSERT(reporter, gray->canComputeFastBounds());
1563
1564 sk_sp<SkImageFilter> grayBlur(SkBlurImageFilter::Make(SK_Scalar1, SK_Scalar1,
1565 std::move(gray)));
1566 REPORTER_ASSERT(reporter, grayBlur->canComputeFastBounds());
senorblanco0abdf762015-08-20 11:10:41 -07001567 }
senorblanco0abdf762015-08-20 11:10:41 -07001568
robertphillips6e7025a2016-04-04 04:31:25 -07001569 {
1570 SkScalar greenMatrix[20] = { 0, 0, 0, 0, 0,
1571 0, 0, 0, 0, 1,
1572 0, 0, 0, 0, 0,
1573 0, 0, 0, 0, 1 };
1574 sk_sp<SkColorFilter> greenCF(SkColorFilter::MakeMatrixFilterRowMajor255(greenMatrix));
robertphillips5605b562016-04-05 11:50:42 -07001575 sk_sp<SkImageFilter> green(SkColorFilterImageFilter::Make(greenCF, nullptr));
senorblanco0abdf762015-08-20 11:10:41 -07001576
robertphillips6e7025a2016-04-04 04:31:25 -07001577 REPORTER_ASSERT(reporter, greenCF->affectsTransparentBlack());
1578 REPORTER_ASSERT(reporter, !green->canComputeFastBounds());
senorblanco0abdf762015-08-20 11:10:41 -07001579
robertphillips6e7025a2016-04-04 04:31:25 -07001580 sk_sp<SkImageFilter> greenBlur(SkBlurImageFilter::Make(SK_Scalar1, SK_Scalar1,
1581 std::move(green)));
1582 REPORTER_ASSERT(reporter, !greenBlur->canComputeFastBounds());
1583 }
senorblanco0abdf762015-08-20 11:10:41 -07001584
1585 uint8_t allOne[256], identity[256];
1586 for (int i = 0; i < 256; ++i) {
1587 identity[i] = i;
1588 allOne[i] = 255;
1589 }
1590
robertphillips5605b562016-04-05 11:50:42 -07001591 sk_sp<SkColorFilter> identityCF(SkTableColorFilter::MakeARGB(identity, identity,
1592 identity, allOne));
1593 sk_sp<SkImageFilter> identityFilter(SkColorFilterImageFilter::Make(identityCF, nullptr));
senorblanco0abdf762015-08-20 11:10:41 -07001594 REPORTER_ASSERT(reporter, !identityCF->affectsTransparentBlack());
1595 REPORTER_ASSERT(reporter, identityFilter->canComputeFastBounds());
1596
robertphillips5605b562016-04-05 11:50:42 -07001597 sk_sp<SkColorFilter> forceOpaqueCF(SkTableColorFilter::MakeARGB(allOne, identity,
1598 identity, identity));
1599 sk_sp<SkImageFilter> forceOpaque(SkColorFilterImageFilter::Make(forceOpaqueCF, nullptr));
senorblanco0abdf762015-08-20 11:10:41 -07001600 REPORTER_ASSERT(reporter, forceOpaqueCF->affectsTransparentBlack());
1601 REPORTER_ASSERT(reporter, !forceOpaque->canComputeFastBounds());
1602}
1603
fmalitacd56f812015-09-14 13:31:18 -07001604// Verify that SkImageSource survives serialization
1605DEF_TEST(ImageFilterImageSourceSerialization, reporter) {
reede8f30622016-03-23 18:59:25 -07001606 auto surface(SkSurface::MakeRasterN32Premul(10, 10));
fmalitacd56f812015-09-14 13:31:18 -07001607 surface->getCanvas()->clear(SK_ColorGREEN);
reed9ce9d672016-03-17 10:51:11 -07001608 sk_sp<SkImage> image(surface->makeImageSnapshot());
robertphillips549c8992016-04-01 09:28:51 -07001609 sk_sp<SkImageFilter> filter(SkImageSource::Make(std::move(image)));
fmalitacd56f812015-09-14 13:31:18 -07001610
robertphillips549c8992016-04-01 09:28:51 -07001611 sk_sp<SkData> data(SkValidatingSerializeFlattenable(filter.get()));
1612 sk_sp<SkFlattenable> flattenable(SkValidatingDeserializeFlattenable(
mtklein3b375452016-04-04 14:57:19 -07001613 data->data(), data->size(), SkImageFilter::GetFlattenableType()));
fmalitacd56f812015-09-14 13:31:18 -07001614 SkImageFilter* unflattenedFilter = static_cast<SkImageFilter*>(flattenable.get());
1615 REPORTER_ASSERT(reporter, unflattenedFilter);
1616
1617 SkBitmap bm;
1618 bm.allocN32Pixels(10, 10);
fmalita23cb88c2015-09-15 06:56:23 -07001619 bm.eraseColor(SK_ColorBLUE);
fmalitacd56f812015-09-14 13:31:18 -07001620 SkPaint paint;
1621 paint.setColor(SK_ColorRED);
1622 paint.setImageFilter(unflattenedFilter);
1623
1624 SkCanvas canvas(bm);
1625 canvas.drawRect(SkRect::MakeWH(10, 10), paint);
1626 REPORTER_ASSERT(reporter, *bm.getAddr32(0, 0) == SkPreMultiplyColor(SK_ColorGREEN));
1627}
1628
bsalomon45eefcf2016-01-05 08:39:28 -08001629static void test_large_blur_input(skiatest::Reporter* reporter, SkCanvas* canvas) {
1630 SkBitmap largeBmp;
1631 int largeW = 5000;
1632 int largeH = 5000;
1633#if SK_SUPPORT_GPU
1634 // If we're GPU-backed make the bitmap too large to be converted into a texture.
1635 if (GrContext* ctx = canvas->getGrContext()) {
1636 largeW = ctx->caps()->maxTextureSize() + 1;
1637 }
1638#endif
1639
1640 largeBmp.allocN32Pixels(largeW, largeH);
mtklein2afbe232016-02-07 12:23:10 -08001641 largeBmp.eraseColor(0);
bsalomon45eefcf2016-01-05 08:39:28 -08001642 if (!largeBmp.getPixels()) {
1643 ERRORF(reporter, "Failed to allocate large bmp.");
1644 return;
1645 }
1646
reed9ce9d672016-03-17 10:51:11 -07001647 sk_sp<SkImage> largeImage(SkImage::MakeFromBitmap(largeBmp));
bsalomon45eefcf2016-01-05 08:39:28 -08001648 if (!largeImage) {
1649 ERRORF(reporter, "Failed to create large image.");
1650 return;
1651 }
1652
robertphillips549c8992016-04-01 09:28:51 -07001653 sk_sp<SkImageFilter> largeSource(SkImageSource::Make(std::move(largeImage)));
bsalomon45eefcf2016-01-05 08:39:28 -08001654 if (!largeSource) {
1655 ERRORF(reporter, "Failed to create large SkImageSource.");
1656 return;
1657 }
1658
robertphillips6e7025a2016-04-04 04:31:25 -07001659 sk_sp<SkImageFilter> blur(SkBlurImageFilter::Make(10.f, 10.f, std::move(largeSource)));
bsalomon45eefcf2016-01-05 08:39:28 -08001660 if (!blur) {
1661 ERRORF(reporter, "Failed to create SkBlurImageFilter.");
1662 return;
1663 }
1664
1665 SkPaint paint;
robertphillips549c8992016-04-01 09:28:51 -07001666 paint.setImageFilter(std::move(blur));
bsalomon45eefcf2016-01-05 08:39:28 -08001667
1668 // This should not crash (http://crbug.com/570479).
1669 canvas->drawRect(SkRect::MakeIWH(largeW, largeH), paint);
1670}
1671
senorblanco21a465d2016-04-11 11:58:39 -07001672DEF_TEST(ImageFilterBlurLargeImage, reporter) {
reede8f30622016-03-23 18:59:25 -07001673 auto surface(SkSurface::MakeRaster(SkImageInfo::MakeN32Premul(100, 100)));
bsalomon45eefcf2016-01-05 08:39:28 -08001674 test_large_blur_input(reporter, surface->getCanvas());
1675}
1676
senorblanco@chromium.org58d14662014-02-03 22:36:39 +00001677#if SK_SUPPORT_GPU
reed4a8126e2014-09-22 07:29:03 -07001678
bsalomon68d91342016-04-12 09:59:58 -07001679DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterHugeBlur_Gpu, reporter, ctxInfo) {
robertphillipsefbffed2015-06-22 12:06:08 -07001680
robertphillips3e302272016-04-20 11:48:36 -07001681 sk_sp<SkSurface> surf(SkSurface::MakeRenderTarget(ctxInfo.fGrContext,
1682 SkBudgeted::kNo,
1683 SkImageInfo::MakeN32Premul(100, 100)));
robertphillips9a53fd72015-06-22 09:46:59 -07001684
robertphillips3e302272016-04-20 11:48:36 -07001685
1686 SkCanvas* canvas = surf->getCanvas();
1687
1688 test_huge_blur(canvas, reporter);
senorblanco@chromium.org09843fd2014-03-24 20:50:59 +00001689}
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001690
bsalomon758586c2016-04-06 14:02:39 -07001691DEF_GPUTEST_FOR_GL_RENDERING_CONTEXTS(XfermodeImageFilterCroppedInput_Gpu, reporter, ctxInfo) {
robertphillipsefbffed2015-06-22 12:06:08 -07001692
robertphillips3e302272016-04-20 11:48:36 -07001693 sk_sp<SkSurface> surf(SkSurface::MakeRenderTarget(ctxInfo.fGrContext,
1694 SkBudgeted::kNo,
1695 SkImageInfo::MakeN32Premul(1, 1)));
robertphillips9a53fd72015-06-22 09:46:59 -07001696
robertphillips3e302272016-04-20 11:48:36 -07001697
1698 SkCanvas* canvas = surf->getCanvas();
1699
1700 test_xfermode_cropped_input(canvas, reporter);
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001701}
senorblanco32673b92014-09-09 09:15:04 -07001702
senorblanco21a465d2016-04-11 11:58:39 -07001703DEF_GPUTEST_FOR_ALL_GL_CONTEXTS(ImageFilterBlurLargeImage_Gpu, reporter, ctxInfo) {
bsalomonf2f1c172016-04-05 12:59:06 -07001704 auto surface(SkSurface::MakeRenderTarget(ctxInfo.fGrContext, SkBudgeted::kYes,
reede8f30622016-03-23 18:59:25 -07001705 SkImageInfo::MakeN32Premul(100, 100)));
bsalomon45eefcf2016-01-05 08:39:28 -08001706 test_large_blur_input(reporter, surface->getCanvas());
1707}
senorblanco@chromium.org58d14662014-02-03 22:36:39 +00001708#endif