blob: 42ffd387915a0880bf554318ef8f2d24509f84cf [file] [log] [blame]
senorblanco@chromium.org194d7752013-07-24 22:19:24 +00001/*
2 * Copyright 2013 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
commit-bot@chromium.org4b681bc2013-09-13 12:40:02 +00008#include "SkBitmap.h"
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00009#include "SkBlurImageFilter.h"
tfarina@chromium.org8f6884a2014-01-24 20:56:26 +000010#include "SkCanvas.h"
11#include "SkColorFilterImageFilter.h"
12#include "SkColorMatrixFilter.h"
ajuma5788faa2015-02-13 09:05:47 -080013#include "SkComposeImageFilter.h"
senorblanco@chromium.org6776b822014-01-03 21:48:22 +000014#include "SkDisplacementMapEffect.h"
15#include "SkDropShadowImageFilter.h"
senorblanco@chromium.org97f5fc62014-05-30 20:50:56 +000016#include "SkFlattenableSerialization.h"
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +000017#include "SkGradientShader.h"
fmalita5598b632015-09-15 11:26:13 -070018#include "SkImage.h"
fmalitacd56f812015-09-14 13:31:18 -070019#include "SkImageSource.h"
commit-bot@chromium.org4b681bc2013-09-13 12:40:02 +000020#include "SkLightingImageFilter.h"
tfarina@chromium.org8f6884a2014-01-24 20:56:26 +000021#include "SkMatrixConvolutionImageFilter.h"
senorblanco@chromium.org6776b822014-01-03 21:48:22 +000022#include "SkMergeImageFilter.h"
23#include "SkMorphologyImageFilter.h"
senorblanco@chromium.org6776b822014-01-03 21:48:22 +000024#include "SkOffsetImageFilter.h"
ajuma77b6ba32016-01-08 14:58:35 -080025#include "SkPaintImageFilter.h"
senorblanco8f3937d2014-10-29 12:36:32 -070026#include "SkPerlinNoiseShader.h"
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +000027#include "SkPicture.h"
senorblanco@chromium.org910702b2014-05-30 20:36:15 +000028#include "SkPictureImageFilter.h"
robertphillips@google.com770963f2014-04-18 18:04:41 +000029#include "SkPictureRecorder.h"
robertphillips3d32d762015-07-13 13:16:44 -070030#include "SkPoint3.h"
halcanary97d2c0a2014-08-19 06:27:53 -070031#include "SkReadBuffer.h"
tfarina@chromium.org8f6884a2014-01-24 20:56:26 +000032#include "SkRect.h"
robertphillips4418dba2016-03-07 12:45:14 -080033#include "SkSpecialImage.h"
34#include "SkSpecialSurface.h"
fmalitacd56f812015-09-14 13:31:18 -070035#include "SkSurface.h"
senorblanco0abdf762015-08-20 11:10:41 -070036#include "SkTableColorFilter.h"
senorblanco@chromium.org6776b822014-01-03 21:48:22 +000037#include "SkTileImageFilter.h"
38#include "SkXfermodeImageFilter.h"
tfarina@chromium.org8f6884a2014-01-24 20:56:26 +000039#include "Test.h"
senorblanco@chromium.org194d7752013-07-24 22:19:24 +000040
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +000041#if SK_SUPPORT_GPU
kkinnunen15302832015-12-01 04:35:26 -080042#include "GrContext.h"
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +000043#endif
44
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +000045static const int kBitmapSize = 4;
commit-bot@chromium.org4b681bc2013-09-13 12:40:02 +000046
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +000047namespace {
48
49class MatrixTestImageFilter : public SkImageFilter {
50public:
robertphillips43c2ad42016-04-04 05:05:11 -070051 static sk_sp<SkImageFilter> Make(skiatest::Reporter* reporter,
52 const SkMatrix& expectedMatrix) {
53 return sk_sp<SkImageFilter>(new MatrixTestImageFilter(reporter, expectedMatrix));
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +000054 }
55
robertphillipsf3f5bad2014-12-19 13:49:15 -080056 SK_TO_STRING_OVERRIDE()
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +000057 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(MatrixTestImageFilter)
58
59protected:
robertphillips4ba94e22016-04-04 12:07:47 -070060 sk_sp<SkSpecialImage> onFilterImage(SkSpecialImage* source, const Context& ctx,
61 SkIPoint* offset) const override {
robertphillips43c2ad42016-04-04 05:05:11 -070062 REPORTER_ASSERT(fReporter, ctx.ctm() == fExpectedMatrix);
robertphillips4ba94e22016-04-04 12:07:47 -070063 offset->fX = offset->fY = 0;
64 return sk_ref_sp<SkSpecialImage>(source);
robertphillips43c2ad42016-04-04 05:05:11 -070065 }
66
mtklein36352bf2015-03-25 18:17:31 -070067 void flatten(SkWriteBuffer& buffer) const override {
brianosman18f13f32016-05-02 07:51:08 -070068 SkDEBUGFAIL("Should never get here");
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +000069 }
70
71private:
robertphillips43c2ad42016-04-04 05:05:11 -070072 MatrixTestImageFilter(skiatest::Reporter* reporter, const SkMatrix& expectedMatrix)
73 : INHERITED(nullptr, 0, nullptr)
74 , fReporter(reporter)
75 , fExpectedMatrix(expectedMatrix) {
76 }
77
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +000078 skiatest::Reporter* fReporter;
79 SkMatrix fExpectedMatrix;
mtklein3f3b3d02014-12-01 11:47:08 -080080
reed9fa60da2014-08-21 07:59:51 -070081 typedef SkImageFilter INHERITED;
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +000082};
83
senorblanco6a93fa12016-04-05 04:43:45 -070084class FailImageFilter : public SkImageFilter {
85public:
robertphillips6b134732016-04-15 09:58:37 -070086 FailImageFilter() : SkImageFilter(nullptr, 0, nullptr) { }
senorblanco6a93fa12016-04-05 04:43:45 -070087
88 sk_sp<SkSpecialImage> onFilterImage(SkSpecialImage* source,
89 const Context& ctx,
90 SkIPoint* offset) const override {
91 return nullptr;
92 }
93
94 SK_TO_STRING_OVERRIDE()
95 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(FailImageFilter)
96
97private:
98 typedef SkImageFilter INHERITED;
99};
100
101sk_sp<SkFlattenable> FailImageFilter::CreateProc(SkReadBuffer& buffer) {
102 SK_IMAGEFILTER_UNFLATTEN_COMMON(common, 0);
103 return sk_sp<SkFlattenable>(new FailImageFilter());
104}
105
106#ifndef SK_IGNORE_TO_STRING
107void FailImageFilter::toString(SkString* str) const {
108 str->appendf("FailImageFilter: (");
109 str->append(")");
110}
111#endif
112
senorblanco297f7ce2016-03-23 13:44:26 -0700113void draw_gradient_circle(SkCanvas* canvas, int width, int height) {
114 SkScalar x = SkIntToScalar(width / 2);
115 SkScalar y = SkIntToScalar(height / 2);
116 SkScalar radius = SkMinScalar(x, y) * 0.8f;
117 canvas->clear(0x00000000);
118 SkColor colors[2];
119 colors[0] = SK_ColorWHITE;
120 colors[1] = SK_ColorBLACK;
121 sk_sp<SkShader> shader(
122 SkGradientShader::MakeRadial(SkPoint::Make(x, y), radius, colors, nullptr, 2,
123 SkShader::kClamp_TileMode)
124 );
125 SkPaint paint;
126 paint.setShader(shader);
127 canvas->drawCircle(x, y, radius, paint);
128}
129
130SkBitmap make_gradient_circle(int width, int height) {
131 SkBitmap bitmap;
132 bitmap.allocN32Pixels(width, height);
133 SkCanvas canvas(bitmap);
134 draw_gradient_circle(&canvas, width, height);
135 return bitmap;
136}
137
138class FilterList {
139public:
robertphillipsfc11b0a2016-04-05 09:09:36 -0700140 FilterList(sk_sp<SkImageFilter> input, const SkImageFilter::CropRect* cropRect = nullptr) {
senorblanco297f7ce2016-03-23 13:44:26 -0700141 SkPoint3 location = SkPoint3::Make(0, 0, SK_Scalar1);
senorblanco297f7ce2016-03-23 13:44:26 -0700142 const SkScalar five = SkIntToScalar(5);
143
robertphillips6e7025a2016-04-04 04:31:25 -0700144 {
145 sk_sp<SkColorFilter> cf(SkColorFilter::MakeModeFilter(SK_ColorRED,
Mike Reed7d954ad2016-10-28 15:42:34 -0400146 SkBlendMode::kSrcIn));
senorblanco297f7ce2016-03-23 13:44:26 -0700147
robertphillips6e7025a2016-04-04 04:31:25 -0700148 this->addFilter("color filter",
robertphillips12fa47d2016-04-08 16:28:09 -0700149 SkColorFilterImageFilter::Make(std::move(cf), input, cropRect));
robertphillips6e7025a2016-04-04 04:31:25 -0700150 }
senorblanco297f7ce2016-03-23 13:44:26 -0700151
robertphillips6e7025a2016-04-04 04:31:25 -0700152 {
153 sk_sp<SkImage> gradientImage(SkImage::MakeFromBitmap(make_gradient_circle(64, 64)));
154 sk_sp<SkImageFilter> gradientSource(SkImageSource::Make(std::move(gradientImage)));
senorblanco297f7ce2016-03-23 13:44:26 -0700155
robertphillips12fa47d2016-04-08 16:28:09 -0700156 this->addFilter("displacement map",
robertphillipsbfe11fc2016-04-15 07:17:36 -0700157 SkDisplacementMapEffect::Make(SkDisplacementMapEffect::kR_ChannelSelectorType,
158 SkDisplacementMapEffect::kB_ChannelSelectorType,
159 20.0f,
160 std::move(gradientSource), input, cropRect));
robertphillips6e7025a2016-04-04 04:31:25 -0700161 }
senorblanco297f7ce2016-03-23 13:44:26 -0700162
robertphillips6e7025a2016-04-04 04:31:25 -0700163 this->addFilter("blur", SkBlurImageFilter::Make(SK_Scalar1,
164 SK_Scalar1,
robertphillipsfc11b0a2016-04-05 09:09:36 -0700165 input,
robertphillips12fa47d2016-04-08 16:28:09 -0700166 cropRect));
robertphillipsc4169122016-04-06 08:40:59 -0700167 this->addFilter("drop shadow", SkDropShadowImageFilter::Make(
senorblanco297f7ce2016-03-23 13:44:26 -0700168 SK_Scalar1, SK_Scalar1, SK_Scalar1, SK_Scalar1, SK_ColorGREEN,
robertphillipsfc11b0a2016-04-05 09:09:36 -0700169 SkDropShadowImageFilter::kDrawShadowAndForeground_ShadowMode,
robertphillips12fa47d2016-04-08 16:28:09 -0700170 input, cropRect));
171 this->addFilter("diffuse lighting",
172 SkLightingImageFilter::MakePointLitDiffuse(location, SK_ColorGREEN, 0, 0,
173 input, cropRect));
senorblanco297f7ce2016-03-23 13:44:26 -0700174 this->addFilter("specular lighting",
robertphillips12fa47d2016-04-08 16:28:09 -0700175 SkLightingImageFilter::MakePointLitSpecular(location, SK_ColorGREEN, 0, 0, 0,
176 input, cropRect));
177 {
178 SkScalar kernel[9] = {
179 SkIntToScalar(1), SkIntToScalar(1), SkIntToScalar(1),
180 SkIntToScalar(1), SkIntToScalar(-7), SkIntToScalar(1),
181 SkIntToScalar(1), SkIntToScalar(1), SkIntToScalar(1),
182 };
183 const SkISize kernelSize = SkISize::Make(3, 3);
184 const SkScalar gain = SK_Scalar1, bias = 0;
185
186 this->addFilter("matrix convolution",
robertphillipsef6a47b2016-04-08 08:01:20 -0700187 SkMatrixConvolutionImageFilter::Make(
senorblanco297f7ce2016-03-23 13:44:26 -0700188 kernelSize, kernel, gain, bias, SkIPoint::Make(1, 1),
robertphillipsfc11b0a2016-04-05 09:09:36 -0700189 SkMatrixConvolutionImageFilter::kRepeat_TileMode, false,
robertphillips12fa47d2016-04-08 16:28:09 -0700190 input, cropRect));
191 }
192
robertphillipsfc11b0a2016-04-05 09:09:36 -0700193 this->addFilter("merge", SkMergeImageFilter::Make(input, input,
Mike Reed7d954ad2016-10-28 15:42:34 -0400194 SkBlendMode::kSrcOver,
robertphillips12fa47d2016-04-08 16:28:09 -0700195 cropRect));
196
robertphillips6e7025a2016-04-04 04:31:25 -0700197 {
198 SkPaint greenColorShaderPaint;
199 greenColorShaderPaint.setShader(SkShader::MakeColorShader(SK_ColorGREEN));
200
201 SkImageFilter::CropRect leftSideCropRect(SkRect::MakeXYWH(0, 0, 32, 64));
202 sk_sp<SkImageFilter> paintFilterLeft(SkPaintImageFilter::Make(greenColorShaderPaint,
203 &leftSideCropRect));
204 SkImageFilter::CropRect rightSideCropRect(SkRect::MakeXYWH(32, 0, 32, 64));
205 sk_sp<SkImageFilter> paintFilterRight(SkPaintImageFilter::Make(greenColorShaderPaint,
206 &rightSideCropRect));
207
208
209 this->addFilter("merge with disjoint inputs", SkMergeImageFilter::Make(
robertphillips2238c9d2016-03-30 13:34:16 -0700210 std::move(paintFilterLeft), std::move(paintFilterRight),
Mike Reed7d954ad2016-10-28 15:42:34 -0400211 SkBlendMode::kSrcOver, cropRect));
robertphillips6e7025a2016-04-04 04:31:25 -0700212 }
213
senorblanco297f7ce2016-03-23 13:44:26 -0700214 this->addFilter("offset",
robertphillipsfc11b0a2016-04-05 09:09:36 -0700215 SkOffsetImageFilter::Make(SK_Scalar1, SK_Scalar1, input,
robertphillips12fa47d2016-04-08 16:28:09 -0700216 cropRect));
217 this->addFilter("dilate", SkDilateImageFilter::Make(3, 2, input, cropRect));
218 this->addFilter("erode", SkErodeImageFilter::Make(2, 3, input, cropRect));
robertphillips534c2702016-04-15 07:57:40 -0700219 this->addFilter("tile", SkTileImageFilter::Make(
220 SkRect::MakeXYWH(0, 0, 50, 50),
221 cropRect ? cropRect->rect() : SkRect::MakeXYWH(0, 0, 100, 100),
222 input));
robertphillips6e7025a2016-04-04 04:31:25 -0700223
robertphillips12fa47d2016-04-08 16:28:09 -0700224 if (!cropRect) {
225 SkMatrix matrix;
226
227 matrix.setTranslate(SK_Scalar1, SK_Scalar1);
228 matrix.postRotate(SkIntToScalar(45), SK_Scalar1, SK_Scalar1);
229
230 this->addFilter("matrix",
231 SkImageFilter::MakeMatrixFilter(matrix, kLow_SkFilterQuality, input));
232 }
robertphillips6e7025a2016-04-04 04:31:25 -0700233 {
robertphillipsfc11b0a2016-04-05 09:09:36 -0700234 sk_sp<SkImageFilter> blur(SkBlurImageFilter::Make(five, five, input));
robertphillips6e7025a2016-04-04 04:31:25 -0700235
236 this->addFilter("blur and offset", SkOffsetImageFilter::Make(five, five,
237 std::move(blur),
robertphillips12fa47d2016-04-08 16:28:09 -0700238 cropRect));
robertphillips6e7025a2016-04-04 04:31:25 -0700239 }
240 {
241 SkRTreeFactory factory;
242 SkPictureRecorder recorder;
243 SkCanvas* recordingCanvas = recorder.beginRecording(64, 64, &factory, 0);
244
245 SkPaint greenPaint;
246 greenPaint.setColor(SK_ColorGREEN);
247 recordingCanvas->drawRect(SkRect::Make(SkIRect::MakeXYWH(10, 10, 30, 20)), greenPaint);
248 sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture());
249 sk_sp<SkImageFilter> pictureFilter(SkPictureImageFilter::Make(std::move(picture)));
250
251 this->addFilter("picture and blur", SkBlurImageFilter::Make(five, five,
252 std::move(pictureFilter),
robertphillips12fa47d2016-04-08 16:28:09 -0700253 cropRect));
robertphillips6e7025a2016-04-04 04:31:25 -0700254 }
255 {
256 SkPaint paint;
257 paint.setShader(SkPerlinNoiseShader::MakeTurbulence(SK_Scalar1, SK_Scalar1, 1, 0));
258 sk_sp<SkImageFilter> paintFilter(SkPaintImageFilter::Make(paint));
259
260 this->addFilter("paint and blur", SkBlurImageFilter::Make(five, five,
261 std::move(paintFilter),
robertphillips12fa47d2016-04-08 16:28:09 -0700262 cropRect));
robertphillips6e7025a2016-04-04 04:31:25 -0700263 }
reed374772b2016-10-05 17:33:02 -0700264 this->addFilter("xfermode", SkXfermodeImageFilter::Make(SkBlendMode::kSrc, input, input,
265 cropRect));
senorblanco297f7ce2016-03-23 13:44:26 -0700266 }
267 int count() const { return fFilters.count(); }
268 SkImageFilter* getFilter(int index) const { return fFilters[index].fFilter.get(); }
269 const char* getName(int index) const { return fFilters[index].fName; }
270private:
271 struct Filter {
robertphillips12fa47d2016-04-08 16:28:09 -0700272 Filter() : fName(nullptr) {}
273 Filter(const char* name, sk_sp<SkImageFilter> filter)
274 : fName(name)
275 , fFilter(std::move(filter)) {
276 }
senorblanco297f7ce2016-03-23 13:44:26 -0700277 const char* fName;
278 sk_sp<SkImageFilter> fFilter;
279 };
robertphillips12fa47d2016-04-08 16:28:09 -0700280 void addFilter(const char* name, sk_sp<SkImageFilter> filter) {
281 fFilters.push_back(Filter(name, std::move(filter)));
senorblanco297f7ce2016-03-23 13:44:26 -0700282 }
283
284 SkTArray<Filter> fFilters;
285};
286
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +0000287}
288
reed60c9b582016-04-03 09:11:13 -0700289sk_sp<SkFlattenable> MatrixTestImageFilter::CreateProc(SkReadBuffer& buffer) {
brianosman18f13f32016-05-02 07:51:08 -0700290 SkDEBUGFAIL("Should never get here");
291 return nullptr;
reed9fa60da2014-08-21 07:59:51 -0700292}
293
robertphillipsf3f5bad2014-12-19 13:49:15 -0800294#ifndef SK_IGNORE_TO_STRING
295void MatrixTestImageFilter::toString(SkString* str) const {
296 str->appendf("MatrixTestImageFilter: (");
297 str->append(")");
298}
299#endif
300
reed9ce9d672016-03-17 10:51:11 -0700301static sk_sp<SkImage> make_small_image() {
reede8f30622016-03-23 18:59:25 -0700302 auto surface(SkSurface::MakeRasterN32Premul(kBitmapSize, kBitmapSize));
fmalita5598b632015-09-15 11:26:13 -0700303 SkCanvas* canvas = surface->getCanvas();
304 canvas->clear(0x00000000);
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000305 SkPaint darkPaint;
306 darkPaint.setColor(0xFF804020);
307 SkPaint lightPaint;
308 lightPaint.setColor(0xFF244484);
309 const int i = kBitmapSize / 4;
310 for (int y = 0; y < kBitmapSize; y += i) {
311 for (int x = 0; x < kBitmapSize; x += i) {
fmalita5598b632015-09-15 11:26:13 -0700312 canvas->save();
313 canvas->translate(SkIntToScalar(x), SkIntToScalar(y));
314 canvas->drawRect(SkRect::MakeXYWH(0, 0,
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000315 SkIntToScalar(i),
316 SkIntToScalar(i)), darkPaint);
fmalita5598b632015-09-15 11:26:13 -0700317 canvas->drawRect(SkRect::MakeXYWH(SkIntToScalar(i),
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000318 0,
319 SkIntToScalar(i),
320 SkIntToScalar(i)), lightPaint);
fmalita5598b632015-09-15 11:26:13 -0700321 canvas->drawRect(SkRect::MakeXYWH(0,
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000322 SkIntToScalar(i),
323 SkIntToScalar(i),
324 SkIntToScalar(i)), lightPaint);
fmalita5598b632015-09-15 11:26:13 -0700325 canvas->drawRect(SkRect::MakeXYWH(SkIntToScalar(i),
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000326 SkIntToScalar(i),
327 SkIntToScalar(i),
328 SkIntToScalar(i)), darkPaint);
fmalita5598b632015-09-15 11:26:13 -0700329 canvas->restore();
commit-bot@chromium.org4b681bc2013-09-13 12:40:02 +0000330 }
331 }
fmalita5598b632015-09-15 11:26:13 -0700332
reed9ce9d672016-03-17 10:51:11 -0700333 return surface->makeImageSnapshot();
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000334}
senorblanco@chromium.org194d7752013-07-24 22:19:24 +0000335
robertphillips5605b562016-04-05 11:50:42 -0700336static sk_sp<SkImageFilter> make_scale(float amount, sk_sp<SkImageFilter> input) {
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000337 SkScalar s = amount;
338 SkScalar matrix[20] = { s, 0, 0, 0, 0,
339 0, s, 0, 0, 0,
340 0, 0, s, 0, 0,
341 0, 0, 0, s, 0 };
robertphillips5605b562016-04-05 11:50:42 -0700342 sk_sp<SkColorFilter> filter(SkColorFilter::MakeMatrixFilterRowMajor255(matrix));
343 return SkColorFilterImageFilter::Make(std::move(filter), std::move(input));
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000344}
345
robertphillips5605b562016-04-05 11:50:42 -0700346static sk_sp<SkImageFilter> make_grayscale(sk_sp<SkImageFilter> input,
347 const SkImageFilter::CropRect* cropRect) {
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000348 SkScalar matrix[20];
349 memset(matrix, 0, 20 * sizeof(SkScalar));
350 matrix[0] = matrix[5] = matrix[10] = 0.2126f;
351 matrix[1] = matrix[6] = matrix[11] = 0.7152f;
352 matrix[2] = matrix[7] = matrix[12] = 0.0722f;
353 matrix[18] = 1.0f;
robertphillips5605b562016-04-05 11:50:42 -0700354 sk_sp<SkColorFilter> filter(SkColorFilter::MakeMatrixFilterRowMajor255(matrix));
355 return SkColorFilterImageFilter::Make(std::move(filter), std::move(input), cropRect);
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000356}
357
robertphillips5605b562016-04-05 11:50:42 -0700358static sk_sp<SkImageFilter> make_blue(sk_sp<SkImageFilter> input,
359 const SkImageFilter::CropRect* cropRect) {
360 sk_sp<SkColorFilter> filter(SkColorFilter::MakeModeFilter(SK_ColorBLUE,
Mike Reed7d954ad2016-10-28 15:42:34 -0400361 SkBlendMode::kSrcIn));
robertphillips5605b562016-04-05 11:50:42 -0700362 return SkColorFilterImageFilter::Make(std::move(filter), std::move(input), cropRect);
reedcedc36f2015-03-08 04:42:52 -0700363}
364
robertphillips3e302272016-04-20 11:48:36 -0700365static sk_sp<SkSpecialSurface> create_empty_special_surface(GrContext* context, int widthHeight) {
robertphillipsc91fd342016-04-25 12:32:54 -0700366#if SK_SUPPORT_GPU
robertphillips4418dba2016-03-07 12:45:14 -0800367 if (context) {
robertphillips4df16562016-04-28 15:09:34 -0700368 return SkSpecialSurface::MakeRenderTarget(context,
369 widthHeight, widthHeight,
Brian Osman777b5632016-10-14 09:16:21 -0400370 kRGBA_8888_GrPixelConfig, nullptr);
robertphillipsc91fd342016-04-25 12:32:54 -0700371 } else
372#endif
373 {
robertphillips4418dba2016-03-07 12:45:14 -0800374 const SkImageInfo info = SkImageInfo::MakeN32(widthHeight, widthHeight,
375 kOpaque_SkAlphaType);
robertphillips3e302272016-04-20 11:48:36 -0700376 return SkSpecialSurface::MakeRaster(info);
robertphillips4418dba2016-03-07 12:45:14 -0800377 }
senorblancobf680c32016-03-16 16:15:53 -0700378}
379
senorblanco5878dbd2016-05-19 14:50:29 -0700380static sk_sp<SkSurface> create_surface(GrContext* context, int width, int height) {
381 const SkImageInfo info = SkImageInfo::MakeN32(width, height, kOpaque_SkAlphaType);
382#if SK_SUPPORT_GPU
383 if (context) {
384 return SkSurface::MakeRenderTarget(context, SkBudgeted::kNo, info);
385 } else
386#endif
387 {
388 return SkSurface::MakeRaster(info);
389 }
390}
391
robertphillips3e302272016-04-20 11:48:36 -0700392static sk_sp<SkSpecialImage> create_empty_special_image(GrContext* context, int widthHeight) {
393 sk_sp<SkSpecialSurface> surf(create_empty_special_surface(context, widthHeight));
robertphillips4418dba2016-03-07 12:45:14 -0800394
395 SkASSERT(surf);
396
397 SkCanvas* canvas = surf->getCanvas();
398 SkASSERT(canvas);
399
400 canvas->clear(0x0);
401
robertphillips37bd7c32016-03-17 14:31:39 -0700402 return surf->makeImageSnapshot();
robertphillips4418dba2016-03-07 12:45:14 -0800403}
404
405
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000406DEF_TEST(ImageFilter, reporter) {
407 {
reedcedc36f2015-03-08 04:42:52 -0700408 // Check that two non-clipping color-matrice-filters concatenate into a single filter.
robertphillips5605b562016-04-05 11:50:42 -0700409 sk_sp<SkImageFilter> halfBrightness(make_scale(0.5f, nullptr));
410 sk_sp<SkImageFilter> quarterBrightness(make_scale(0.5f, std::move(halfBrightness)));
halcanary96fcdcc2015-08-27 07:41:13 -0700411 REPORTER_ASSERT(reporter, nullptr == quarterBrightness->getInput(0));
reedcedc36f2015-03-08 04:42:52 -0700412 SkColorFilter* cf;
413 REPORTER_ASSERT(reporter, quarterBrightness->asColorFilter(&cf));
halcanary96fcdcc2015-08-27 07:41:13 -0700414 REPORTER_ASSERT(reporter, cf->asColorMatrix(nullptr));
reedcedc36f2015-03-08 04:42:52 -0700415 cf->unref();
senorblanco@chromium.org194d7752013-07-24 22:19:24 +0000416 }
417
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000418 {
reedcedc36f2015-03-08 04:42:52 -0700419 // Check that a clipping color-matrice-filter followed by a color-matrice-filters
420 // concatenates into a single filter, but not a matrixfilter (due to clamping).
robertphillips5605b562016-04-05 11:50:42 -0700421 sk_sp<SkImageFilter> doubleBrightness(make_scale(2.0f, nullptr));
422 sk_sp<SkImageFilter> halfBrightness(make_scale(0.5f, std::move(doubleBrightness)));
halcanary96fcdcc2015-08-27 07:41:13 -0700423 REPORTER_ASSERT(reporter, nullptr == halfBrightness->getInput(0));
reedcedc36f2015-03-08 04:42:52 -0700424 SkColorFilter* cf;
425 REPORTER_ASSERT(reporter, halfBrightness->asColorFilter(&cf));
halcanary96fcdcc2015-08-27 07:41:13 -0700426 REPORTER_ASSERT(reporter, !cf->asColorMatrix(nullptr));
reedcedc36f2015-03-08 04:42:52 -0700427 cf->unref();
senorblanco@chromium.org194d7752013-07-24 22:19:24 +0000428 }
429
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000430 {
431 // Check that a color filter image filter without a crop rect can be
432 // expressed as a color filter.
robertphillips5605b562016-04-05 11:50:42 -0700433 sk_sp<SkImageFilter> gray(make_grayscale(nullptr, nullptr));
halcanary96fcdcc2015-08-27 07:41:13 -0700434 REPORTER_ASSERT(reporter, true == gray->asColorFilter(nullptr));
senorblanco@chromium.org194d7752013-07-24 22:19:24 +0000435 }
mtklein2afbe232016-02-07 12:23:10 -0800436
reedcedc36f2015-03-08 04:42:52 -0700437 {
438 // Check that a colorfilterimage filter without a crop rect but with an input
439 // that is another colorfilterimage can be expressed as a colorfilter (composed).
robertphillips5605b562016-04-05 11:50:42 -0700440 sk_sp<SkImageFilter> mode(make_blue(nullptr, nullptr));
441 sk_sp<SkImageFilter> gray(make_grayscale(std::move(mode), nullptr));
halcanary96fcdcc2015-08-27 07:41:13 -0700442 REPORTER_ASSERT(reporter, true == gray->asColorFilter(nullptr));
reedcedc36f2015-03-08 04:42:52 -0700443 }
444
445 {
446 // Test that if we exceed the limit of what ComposeColorFilter can combine, we still
447 // can build the DAG and won't assert if we call asColorFilter.
robertphillips5605b562016-04-05 11:50:42 -0700448 sk_sp<SkImageFilter> filter(make_blue(nullptr, nullptr));
reedcedc36f2015-03-08 04:42:52 -0700449 const int kWayTooManyForComposeColorFilter = 100;
450 for (int i = 0; i < kWayTooManyForComposeColorFilter; ++i) {
robertphillips5605b562016-04-05 11:50:42 -0700451 filter = make_blue(filter, nullptr);
reedcedc36f2015-03-08 04:42:52 -0700452 // the first few of these will succeed, but after we hit the internal limit,
453 // it will then return false.
halcanary96fcdcc2015-08-27 07:41:13 -0700454 (void)filter->asColorFilter(nullptr);
reedcedc36f2015-03-08 04:42:52 -0700455 }
456 }
reed5c518a82015-03-05 14:47:29 -0800457
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000458 {
459 // Check that a color filter image filter with a crop rect cannot
460 // be expressed as a color filter.
461 SkImageFilter::CropRect cropRect(SkRect::MakeXYWH(0, 0, 100, 100));
robertphillips5605b562016-04-05 11:50:42 -0700462 sk_sp<SkImageFilter> grayWithCrop(make_grayscale(nullptr, &cropRect));
halcanary96fcdcc2015-08-27 07:41:13 -0700463 REPORTER_ASSERT(reporter, false == grayWithCrop->asColorFilter(nullptr));
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000464 }
465
466 {
senorblanco3df05012014-07-03 11:13:09 -0700467 // Check that two non-commutative matrices are concatenated in
468 // the correct order.
469 SkScalar blueToRedMatrix[20] = { 0 };
470 blueToRedMatrix[2] = blueToRedMatrix[18] = SK_Scalar1;
471 SkScalar redToGreenMatrix[20] = { 0 };
472 redToGreenMatrix[5] = redToGreenMatrix[18] = SK_Scalar1;
robertphillips5605b562016-04-05 11:50:42 -0700473 sk_sp<SkColorFilter> blueToRed(SkColorFilter::MakeMatrixFilterRowMajor255(blueToRedMatrix));
474 sk_sp<SkImageFilter> filter1(SkColorFilterImageFilter::Make(std::move(blueToRed),
475 nullptr));
476 sk_sp<SkColorFilter> redToGreen(SkColorFilter::MakeMatrixFilterRowMajor255(redToGreenMatrix));
477 sk_sp<SkImageFilter> filter2(SkColorFilterImageFilter::Make(std::move(redToGreen),
478 std::move(filter1)));
senorblanco3df05012014-07-03 11:13:09 -0700479
480 SkBitmap result;
481 result.allocN32Pixels(kBitmapSize, kBitmapSize);
482
483 SkPaint paint;
484 paint.setColor(SK_ColorBLUE);
robertphillips5605b562016-04-05 11:50:42 -0700485 paint.setImageFilter(std::move(filter2));
senorblanco3df05012014-07-03 11:13:09 -0700486 SkCanvas canvas(result);
487 canvas.clear(0x0);
488 SkRect rect = SkRect::Make(SkIRect::MakeWH(kBitmapSize, kBitmapSize));
489 canvas.drawRect(rect, paint);
490 uint32_t pixel = *result.getAddr32(0, 0);
491 // The result here should be green, since we have effectively shifted blue to green.
492 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
493 }
494
495 {
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000496 // Tests pass by not asserting
reed9ce9d672016-03-17 10:51:11 -0700497 sk_sp<SkImage> image(make_small_image());
fmalita5598b632015-09-15 11:26:13 -0700498 SkBitmap result;
mike@reedtribe.orgdeee4962014-02-13 14:41:43 +0000499 result.allocN32Pixels(kBitmapSize, kBitmapSize);
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000500
senorblanco@chromium.org194d7752013-07-24 22:19:24 +0000501 {
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000502 // This tests for :
503 // 1 ) location at (0,0,1)
robertphillips3d32d762015-07-13 13:16:44 -0700504 SkPoint3 location = SkPoint3::Make(0, 0, SK_Scalar1);
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000505 // 2 ) location and target at same value
robertphillips3d32d762015-07-13 13:16:44 -0700506 SkPoint3 target = SkPoint3::Make(location.fX, location.fY, location.fZ);
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000507 // 3 ) large negative specular exponent value
508 SkScalar specularExponent = -1000;
509
robertphillips549c8992016-04-01 09:28:51 -0700510 sk_sp<SkImageFilter> bmSrc(SkImageSource::Make(std::move(image)));
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000511 SkPaint paint;
robertphillips12fa47d2016-04-08 16:28:09 -0700512 paint.setImageFilter(SkLightingImageFilter::MakeSpotLitSpecular(
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000513 location, target, specularExponent, 180,
514 0xFFFFFFFF, SK_Scalar1, SK_Scalar1, SK_Scalar1,
robertphillips12fa47d2016-04-08 16:28:09 -0700515 std::move(bmSrc)));
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000516 SkCanvas canvas(result);
517 SkRect r = SkRect::MakeWH(SkIntToScalar(kBitmapSize),
518 SkIntToScalar(kBitmapSize));
519 canvas.drawRect(r, paint);
senorblanco@chromium.org194d7752013-07-24 22:19:24 +0000520 }
senorblanco@chromium.org194d7752013-07-24 22:19:24 +0000521 }
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +0000522}
senorblanco@chromium.org6776b822014-01-03 21:48:22 +0000523
robertphillips3e302272016-04-20 11:48:36 -0700524static void test_crop_rects(skiatest::Reporter* reporter,
robertphillips4418dba2016-03-07 12:45:14 -0800525 GrContext* context) {
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +0000526 // Check that all filters offset to their absolute crop rect,
527 // unaffected by the input crop rect.
528 // Tests pass by not asserting.
robertphillips3e302272016-04-20 11:48:36 -0700529 sk_sp<SkSpecialImage> srcImg(create_empty_special_image(context, 100));
robertphillips4418dba2016-03-07 12:45:14 -0800530 SkASSERT(srcImg);
senorblanco@chromium.org6776b822014-01-03 21:48:22 +0000531
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +0000532 SkImageFilter::CropRect inputCropRect(SkRect::MakeXYWH(8, 13, 80, 80));
533 SkImageFilter::CropRect cropRect(SkRect::MakeXYWH(20, 30, 60, 60));
robertphillipsfc11b0a2016-04-05 09:09:36 -0700534 sk_sp<SkImageFilter> input(make_grayscale(nullptr, &inputCropRect));
senorblanco@chromium.org6776b822014-01-03 21:48:22 +0000535
robertphillipsfc11b0a2016-04-05 09:09:36 -0700536 FilterList filters(input, &cropRect);
senorblanco@chromium.org6776b822014-01-03 21:48:22 +0000537
senorblanco297f7ce2016-03-23 13:44:26 -0700538 for (int i = 0; i < filters.count(); ++i) {
539 SkImageFilter* filter = filters.getFilter(i);
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +0000540 SkIPoint offset;
brianosman2a75e5d2016-09-22 07:15:37 -0700541 SkImageFilter::OutputProperties noColorSpace(nullptr);
542 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeWH(100, 100), nullptr, noColorSpace);
robertphillips2302de92016-03-24 07:26:32 -0700543 sk_sp<SkSpecialImage> resultImg(filter->filterImage(srcImg.get(), ctx, &offset));
senorblanco297f7ce2016-03-23 13:44:26 -0700544 REPORTER_ASSERT_MESSAGE(reporter, resultImg, filters.getName(i));
545 REPORTER_ASSERT_MESSAGE(reporter, offset.fX == 20 && offset.fY == 30, filters.getName(i));
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +0000546 }
547}
548
robertphillips3e302272016-04-20 11:48:36 -0700549static void test_negative_blur_sigma(skiatest::Reporter* reporter,
robertphillips4418dba2016-03-07 12:45:14 -0800550 GrContext* context) {
senorblanco32673b92014-09-09 09:15:04 -0700551 // Check that SkBlurImageFilter will accept a negative sigma, either in
552 // the given arguments or after CTM application.
reed5ea95df2015-10-06 14:05:32 -0700553 const int width = 32, height = 32;
554 const SkScalar five = SkIntToScalar(5);
senorblanco32673b92014-09-09 09:15:04 -0700555
robertphillips6e7025a2016-04-04 04:31:25 -0700556 sk_sp<SkImageFilter> positiveFilter(SkBlurImageFilter::Make(five, five, nullptr));
557 sk_sp<SkImageFilter> negativeFilter(SkBlurImageFilter::Make(-five, five, nullptr));
senorblanco32673b92014-09-09 09:15:04 -0700558
559 SkBitmap gradient = make_gradient_circle(width, height);
robertphillips3e302272016-04-20 11:48:36 -0700560 sk_sp<SkSpecialImage> imgSrc(SkSpecialImage::MakeFromRaster(SkIRect::MakeWH(width, height),
robertphillips37bd7c32016-03-17 14:31:39 -0700561 gradient));
robertphillips4418dba2016-03-07 12:45:14 -0800562
senorblanco32673b92014-09-09 09:15:04 -0700563 SkIPoint offset;
brianosman2a75e5d2016-09-22 07:15:37 -0700564 SkImageFilter::OutputProperties noColorSpace(nullptr);
565 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeWH(32, 32), nullptr, noColorSpace);
robertphillips4418dba2016-03-07 12:45:14 -0800566
robertphillips2302de92016-03-24 07:26:32 -0700567 sk_sp<SkSpecialImage> positiveResult1(positiveFilter->filterImage(imgSrc.get(), ctx, &offset));
robertphillips4418dba2016-03-07 12:45:14 -0800568 REPORTER_ASSERT(reporter, positiveResult1);
569
robertphillips2302de92016-03-24 07:26:32 -0700570 sk_sp<SkSpecialImage> negativeResult1(negativeFilter->filterImage(imgSrc.get(), ctx, &offset));
robertphillips4418dba2016-03-07 12:45:14 -0800571 REPORTER_ASSERT(reporter, negativeResult1);
572
senorblanco32673b92014-09-09 09:15:04 -0700573 SkMatrix negativeScale;
574 negativeScale.setScale(-SK_Scalar1, SK_Scalar1);
brianosman2a75e5d2016-09-22 07:15:37 -0700575 SkImageFilter::Context negativeCTX(negativeScale, SkIRect::MakeWH(32, 32), nullptr,
576 noColorSpace);
robertphillips4418dba2016-03-07 12:45:14 -0800577
robertphillips2302de92016-03-24 07:26:32 -0700578 sk_sp<SkSpecialImage> negativeResult2(positiveFilter->filterImage(imgSrc.get(),
579 negativeCTX,
580 &offset));
robertphillips4418dba2016-03-07 12:45:14 -0800581 REPORTER_ASSERT(reporter, negativeResult2);
582
robertphillips2302de92016-03-24 07:26:32 -0700583 sk_sp<SkSpecialImage> positiveResult2(negativeFilter->filterImage(imgSrc.get(),
584 negativeCTX,
585 &offset));
robertphillips4418dba2016-03-07 12:45:14 -0800586 REPORTER_ASSERT(reporter, positiveResult2);
587
588
589 SkBitmap positiveResultBM1, positiveResultBM2;
590 SkBitmap negativeResultBM1, negativeResultBM2;
591
robertphillips64612512016-04-08 12:10:42 -0700592 REPORTER_ASSERT(reporter, positiveResult1->getROPixels(&positiveResultBM1));
593 REPORTER_ASSERT(reporter, positiveResult2->getROPixels(&positiveResultBM2));
594 REPORTER_ASSERT(reporter, negativeResult1->getROPixels(&negativeResultBM1));
595 REPORTER_ASSERT(reporter, negativeResult2->getROPixels(&negativeResultBM2));
robertphillips4418dba2016-03-07 12:45:14 -0800596
597 SkAutoLockPixels lockP1(positiveResultBM1);
598 SkAutoLockPixels lockP2(positiveResultBM2);
599 SkAutoLockPixels lockN1(negativeResultBM1);
600 SkAutoLockPixels lockN2(negativeResultBM2);
senorblanco32673b92014-09-09 09:15:04 -0700601 for (int y = 0; y < height; y++) {
robertphillips4418dba2016-03-07 12:45:14 -0800602 int diffs = memcmp(positiveResultBM1.getAddr32(0, y),
603 negativeResultBM1.getAddr32(0, y),
604 positiveResultBM1.rowBytes());
senorblanco32673b92014-09-09 09:15:04 -0700605 REPORTER_ASSERT(reporter, !diffs);
606 if (diffs) {
607 break;
608 }
robertphillips4418dba2016-03-07 12:45:14 -0800609 diffs = memcmp(positiveResultBM1.getAddr32(0, y),
610 negativeResultBM2.getAddr32(0, y),
611 positiveResultBM1.rowBytes());
senorblanco32673b92014-09-09 09:15:04 -0700612 REPORTER_ASSERT(reporter, !diffs);
613 if (diffs) {
614 break;
615 }
robertphillips4418dba2016-03-07 12:45:14 -0800616 diffs = memcmp(positiveResultBM1.getAddr32(0, y),
617 positiveResultBM2.getAddr32(0, y),
618 positiveResultBM1.rowBytes());
senorblanco32673b92014-09-09 09:15:04 -0700619 REPORTER_ASSERT(reporter, !diffs);
620 if (diffs) {
621 break;
622 }
623 }
624}
625
senorblanco21a465d2016-04-11 11:58:39 -0700626DEF_TEST(ImageFilterNegativeBlurSigma, reporter) {
robertphillips3e302272016-04-20 11:48:36 -0700627 test_negative_blur_sigma(reporter, nullptr);
robertphillips4418dba2016-03-07 12:45:14 -0800628}
629
630#if SK_SUPPORT_GPU
bsalomon68d91342016-04-12 09:59:58 -0700631DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterNegativeBlurSigma_Gpu, reporter, ctxInfo) {
bsalomon8b7451a2016-05-11 06:33:06 -0700632 test_negative_blur_sigma(reporter, ctxInfo.grContext());
robertphillips4418dba2016-03-07 12:45:14 -0800633}
634#endif
635
robertphillips3e302272016-04-20 11:48:36 -0700636static void test_zero_blur_sigma(skiatest::Reporter* reporter, GrContext* context) {
senorblancobf680c32016-03-16 16:15:53 -0700637 // Check that SkBlurImageFilter with a zero sigma and a non-zero srcOffset works correctly.
638 SkImageFilter::CropRect cropRect(SkRect::Make(SkIRect::MakeXYWH(5, 0, 5, 10)));
robertphillips51a315e2016-03-31 09:05:49 -0700639 sk_sp<SkImageFilter> input(SkOffsetImageFilter::Make(0, 0, nullptr, &cropRect));
robertphillips6e7025a2016-04-04 04:31:25 -0700640 sk_sp<SkImageFilter> filter(SkBlurImageFilter::Make(0, 0, std::move(input), &cropRect));
senorblancobf680c32016-03-16 16:15:53 -0700641
robertphillips3e302272016-04-20 11:48:36 -0700642 sk_sp<SkSpecialSurface> surf(create_empty_special_surface(context, 10));
senorblancobf680c32016-03-16 16:15:53 -0700643 surf->getCanvas()->clear(SK_ColorGREEN);
robertphillips37bd7c32016-03-17 14:31:39 -0700644 sk_sp<SkSpecialImage> image(surf->makeImageSnapshot());
senorblancobf680c32016-03-16 16:15:53 -0700645
646 SkIPoint offset;
brianosman2a75e5d2016-09-22 07:15:37 -0700647 SkImageFilter::OutputProperties noColorSpace(nullptr);
648 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeWH(32, 32), nullptr, noColorSpace);
senorblancobf680c32016-03-16 16:15:53 -0700649
robertphillips2302de92016-03-24 07:26:32 -0700650 sk_sp<SkSpecialImage> result(filter->filterImage(image.get(), ctx, &offset));
senorblancobf680c32016-03-16 16:15:53 -0700651 REPORTER_ASSERT(reporter, offset.fX == 5 && offset.fY == 0);
652 REPORTER_ASSERT(reporter, result);
653 REPORTER_ASSERT(reporter, result->width() == 5 && result->height() == 10);
654
655 SkBitmap resultBM;
656
robertphillips64612512016-04-08 12:10:42 -0700657 REPORTER_ASSERT(reporter, result->getROPixels(&resultBM));
senorblancobf680c32016-03-16 16:15:53 -0700658
659 SkAutoLockPixels lock(resultBM);
660 for (int y = 0; y < resultBM.height(); y++) {
661 for (int x = 0; x < resultBM.width(); x++) {
662 bool diff = *resultBM.getAddr32(x, y) != SK_ColorGREEN;
663 REPORTER_ASSERT(reporter, !diff);
664 if (diff) {
665 break;
666 }
667 }
668 }
669}
670
senorblanco21a465d2016-04-11 11:58:39 -0700671DEF_TEST(ImageFilterZeroBlurSigma, reporter) {
robertphillips3e302272016-04-20 11:48:36 -0700672 test_zero_blur_sigma(reporter, nullptr);
senorblancobf680c32016-03-16 16:15:53 -0700673}
674
675#if SK_SUPPORT_GPU
bsalomon68d91342016-04-12 09:59:58 -0700676DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterZeroBlurSigma_Gpu, reporter, ctxInfo) {
bsalomon8b7451a2016-05-11 06:33:06 -0700677 test_zero_blur_sigma(reporter, ctxInfo.grContext());
senorblancobf680c32016-03-16 16:15:53 -0700678}
679#endif
680
senorblanco6a93fa12016-04-05 04:43:45 -0700681
682// Tests that, even when an upstream filter has returned null (due to failure or clipping), a
683// downstream filter that affects transparent black still does so even with a nullptr input.
robertphillips3e302272016-04-20 11:48:36 -0700684static void test_fail_affects_transparent_black(skiatest::Reporter* reporter, GrContext* context) {
senorblanco6a93fa12016-04-05 04:43:45 -0700685 sk_sp<FailImageFilter> failFilter(new FailImageFilter());
robertphillips3e302272016-04-20 11:48:36 -0700686 sk_sp<SkSpecialImage> source(create_empty_special_image(context, 5));
brianosman2a75e5d2016-09-22 07:15:37 -0700687 SkImageFilter::OutputProperties noColorSpace(nullptr);
688 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeXYWH(0, 0, 1, 1), nullptr, noColorSpace);
Mike Reed7d954ad2016-10-28 15:42:34 -0400689 sk_sp<SkColorFilter> green(SkColorFilter::MakeModeFilter(SK_ColorGREEN, SkBlendMode::kSrc));
senorblanco6a93fa12016-04-05 04:43:45 -0700690 SkASSERT(green->affectsTransparentBlack());
robertphillips5605b562016-04-05 11:50:42 -0700691 sk_sp<SkImageFilter> greenFilter(SkColorFilterImageFilter::Make(std::move(green),
692 std::move(failFilter)));
senorblanco6a93fa12016-04-05 04:43:45 -0700693 SkIPoint offset;
694 sk_sp<SkSpecialImage> result(greenFilter->filterImage(source.get(), ctx, &offset));
695 REPORTER_ASSERT(reporter, nullptr != result.get());
696 if (result.get()) {
697 SkBitmap resultBM;
robertphillips64612512016-04-08 12:10:42 -0700698 REPORTER_ASSERT(reporter, result->getROPixels(&resultBM));
senorblanco6a93fa12016-04-05 04:43:45 -0700699 SkAutoLockPixels lock(resultBM);
700 REPORTER_ASSERT(reporter, *resultBM.getAddr32(0, 0) == SK_ColorGREEN);
701 }
702}
703
704DEF_TEST(ImageFilterFailAffectsTransparentBlack, reporter) {
robertphillips3e302272016-04-20 11:48:36 -0700705 test_fail_affects_transparent_black(reporter, nullptr);
senorblanco6a93fa12016-04-05 04:43:45 -0700706}
707
708#if SK_SUPPORT_GPU
bsalomon68d91342016-04-12 09:59:58 -0700709DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterFailAffectsTransparentBlack_Gpu, reporter, ctxInfo) {
bsalomon8b7451a2016-05-11 06:33:06 -0700710 test_fail_affects_transparent_black(reporter, ctxInfo.grContext());
senorblanco6a93fa12016-04-05 04:43:45 -0700711}
712#endif
713
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +0000714DEF_TEST(ImageFilterDrawTiled, reporter) {
715 // Check that all filters when drawn tiled (with subsequent clip rects) exactly
716 // match the same filters drawn with a single full-canvas bitmap draw.
717 // Tests pass by not asserting.
718
robertphillipsfc11b0a2016-04-05 09:09:36 -0700719 FilterList filters(nullptr);
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +0000720
721 SkBitmap untiledResult, tiledResult;
reed5ea95df2015-10-06 14:05:32 -0700722 const int width = 64, height = 64;
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +0000723 untiledResult.allocN32Pixels(width, height);
724 tiledResult.allocN32Pixels(width, height);
725 SkCanvas tiledCanvas(tiledResult);
726 SkCanvas untiledCanvas(untiledResult);
senorblanco@chromium.orgd4db6572014-05-07 20:00:04 +0000727 int tileSize = 8;
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +0000728
senorblanco@chromium.orgd4db6572014-05-07 20:00:04 +0000729 for (int scale = 1; scale <= 2; ++scale) {
senorblanco297f7ce2016-03-23 13:44:26 -0700730 for (int i = 0; i < filters.count(); ++i) {
senorblanco@chromium.orgd4db6572014-05-07 20:00:04 +0000731 tiledCanvas.clear(0);
732 untiledCanvas.clear(0);
733 SkPaint paint;
senorblanco297f7ce2016-03-23 13:44:26 -0700734 paint.setImageFilter(filters.getFilter(i));
senorblanco@chromium.orgd4db6572014-05-07 20:00:04 +0000735 paint.setTextSize(SkIntToScalar(height));
736 paint.setColor(SK_ColorWHITE);
737 SkString str;
738 const char* text = "ABC";
739 SkScalar ypos = SkIntToScalar(height);
740 untiledCanvas.save();
741 untiledCanvas.scale(SkIntToScalar(scale), SkIntToScalar(scale));
742 untiledCanvas.drawText(text, strlen(text), 0, ypos, paint);
743 untiledCanvas.restore();
744 for (int y = 0; y < height; y += tileSize) {
745 for (int x = 0; x < width; x += tileSize) {
746 tiledCanvas.save();
747 tiledCanvas.clipRect(SkRect::Make(SkIRect::MakeXYWH(x, y, tileSize, tileSize)));
748 tiledCanvas.scale(SkIntToScalar(scale), SkIntToScalar(scale));
749 tiledCanvas.drawText(text, strlen(text), 0, ypos, paint);
750 tiledCanvas.restore();
751 }
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +0000752 }
senorblanco@chromium.orgd4db6572014-05-07 20:00:04 +0000753 untiledCanvas.flush();
754 tiledCanvas.flush();
755 for (int y = 0; y < height; y++) {
756 int diffs = memcmp(untiledResult.getAddr32(0, y), tiledResult.getAddr32(0, y), untiledResult.rowBytes());
senorblanco297f7ce2016-03-23 13:44:26 -0700757 REPORTER_ASSERT_MESSAGE(reporter, !diffs, filters.getName(i));
senorblanco@chromium.orgd4db6572014-05-07 20:00:04 +0000758 if (diffs) {
759 break;
760 }
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +0000761 }
762 }
763 }
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +0000764}
765
mtklein3f3b3d02014-12-01 11:47:08 -0800766static void draw_saveLayer_picture(int width, int height, int tileSize,
robertphillipsa8d7f0b2014-08-29 08:03:56 -0700767 SkBBHFactory* factory, SkBitmap* result) {
mtkleind910f542014-08-22 09:06:34 -0700768
769 SkMatrix matrix;
770 matrix.setTranslate(SkIntToScalar(50), 0);
771
Mike Reed7d954ad2016-10-28 15:42:34 -0400772 sk_sp<SkColorFilter> cf(SkColorFilter::MakeModeFilter(SK_ColorWHITE, SkBlendMode::kSrc));
robertphillips5605b562016-04-05 11:50:42 -0700773 sk_sp<SkImageFilter> cfif(SkColorFilterImageFilter::Make(std::move(cf), nullptr));
robertphillipsae8c9332016-04-05 15:09:00 -0700774 sk_sp<SkImageFilter> imageFilter(SkImageFilter::MakeMatrixFilter(matrix,
775 kNone_SkFilterQuality,
776 std::move(cfif)));
mtkleind910f542014-08-22 09:06:34 -0700777
778 SkPaint paint;
robertphillips5605b562016-04-05 11:50:42 -0700779 paint.setImageFilter(std::move(imageFilter));
mtkleind910f542014-08-22 09:06:34 -0700780 SkPictureRecorder recorder;
781 SkRect bounds = SkRect::Make(SkIRect::MakeXYWH(0, 0, 50, 50));
mtklein3f3b3d02014-12-01 11:47:08 -0800782 SkCanvas* recordingCanvas = recorder.beginRecording(SkIntToScalar(width),
783 SkIntToScalar(height),
robertphillipsa8d7f0b2014-08-29 08:03:56 -0700784 factory, 0);
mtkleind910f542014-08-22 09:06:34 -0700785 recordingCanvas->translate(-55, 0);
786 recordingCanvas->saveLayer(&bounds, &paint);
787 recordingCanvas->restore();
reedca2622b2016-03-18 07:25:55 -0700788 sk_sp<SkPicture> picture1(recorder.finishRecordingAsPicture());
mtkleind910f542014-08-22 09:06:34 -0700789
790 result->allocN32Pixels(width, height);
791 SkCanvas canvas(*result);
792 canvas.clear(0);
793 canvas.clipRect(SkRect::Make(SkIRect::MakeWH(tileSize, tileSize)));
794 canvas.drawPicture(picture1.get());
795}
796
797DEF_TEST(ImageFilterDrawMatrixBBH, reporter) {
798 // Check that matrix filter when drawn tiled with BBH exactly
799 // matches the same thing drawn without BBH.
800 // Tests pass by not asserting.
801
802 const int width = 200, height = 200;
803 const int tileSize = 100;
804 SkBitmap result1, result2;
805 SkRTreeFactory factory;
806
robertphillipsa8d7f0b2014-08-29 08:03:56 -0700807 draw_saveLayer_picture(width, height, tileSize, &factory, &result1);
halcanary96fcdcc2015-08-27 07:41:13 -0700808 draw_saveLayer_picture(width, height, tileSize, nullptr, &result2);
mtkleind910f542014-08-22 09:06:34 -0700809
810 for (int y = 0; y < height; y++) {
811 int diffs = memcmp(result1.getAddr32(0, y), result2.getAddr32(0, y), result1.rowBytes());
812 REPORTER_ASSERT(reporter, !diffs);
813 if (diffs) {
814 break;
815 }
816 }
817}
818
robertphillips6e7025a2016-04-04 04:31:25 -0700819static sk_sp<SkImageFilter> make_blur(sk_sp<SkImageFilter> input) {
820 return SkBlurImageFilter::Make(SK_Scalar1, SK_Scalar1, std::move(input));
senorblanco1150a6d2014-08-25 12:46:58 -0700821}
822
robertphillips6e7025a2016-04-04 04:31:25 -0700823static sk_sp<SkImageFilter> make_drop_shadow(sk_sp<SkImageFilter> input) {
robertphillipsc4169122016-04-06 08:40:59 -0700824 return SkDropShadowImageFilter::Make(
senorblanco1150a6d2014-08-25 12:46:58 -0700825 SkIntToScalar(100), SkIntToScalar(100),
826 SkIntToScalar(10), SkIntToScalar(10),
sugoi234f0362014-10-23 13:59:52 -0700827 SK_ColorBLUE, SkDropShadowImageFilter::kDrawShadowAndForeground_ShadowMode,
robertphillipsc4169122016-04-06 08:40:59 -0700828 std::move(input));
senorblanco1150a6d2014-08-25 12:46:58 -0700829}
830
831DEF_TEST(ImageFilterBlurThenShadowBounds, reporter) {
robertphillips6e7025a2016-04-04 04:31:25 -0700832 sk_sp<SkImageFilter> filter1(make_blur(nullptr));
833 sk_sp<SkImageFilter> filter2(make_drop_shadow(std::move(filter1)));
senorblanco1150a6d2014-08-25 12:46:58 -0700834
835 SkIRect bounds = SkIRect::MakeXYWH(0, 0, 100, 100);
836 SkIRect expectedBounds = SkIRect::MakeXYWH(-133, -133, 236, 236);
senorblancoe5e79842016-03-21 14:51:59 -0700837 bounds = filter2->filterBounds(bounds, SkMatrix::I());
senorblanco1150a6d2014-08-25 12:46:58 -0700838
839 REPORTER_ASSERT(reporter, bounds == expectedBounds);
840}
841
842DEF_TEST(ImageFilterShadowThenBlurBounds, reporter) {
robertphillips6e7025a2016-04-04 04:31:25 -0700843 sk_sp<SkImageFilter> filter1(make_drop_shadow(nullptr));
844 sk_sp<SkImageFilter> filter2(make_blur(std::move(filter1)));
senorblanco1150a6d2014-08-25 12:46:58 -0700845
846 SkIRect bounds = SkIRect::MakeXYWH(0, 0, 100, 100);
847 SkIRect expectedBounds = SkIRect::MakeXYWH(-133, -133, 236, 236);
senorblancoe5e79842016-03-21 14:51:59 -0700848 bounds = filter2->filterBounds(bounds, SkMatrix::I());
senorblanco1150a6d2014-08-25 12:46:58 -0700849
850 REPORTER_ASSERT(reporter, bounds == expectedBounds);
851}
852
853DEF_TEST(ImageFilterDilateThenBlurBounds, reporter) {
robertphillipsfc11b0a2016-04-05 09:09:36 -0700854 sk_sp<SkImageFilter> filter1(SkDilateImageFilter::Make(2, 2, nullptr));
robertphillips6e7025a2016-04-04 04:31:25 -0700855 sk_sp<SkImageFilter> filter2(make_drop_shadow(std::move(filter1)));
senorblanco1150a6d2014-08-25 12:46:58 -0700856
857 SkIRect bounds = SkIRect::MakeXYWH(0, 0, 100, 100);
858 SkIRect expectedBounds = SkIRect::MakeXYWH(-132, -132, 234, 234);
senorblancoe5e79842016-03-21 14:51:59 -0700859 bounds = filter2->filterBounds(bounds, SkMatrix::I());
senorblanco1150a6d2014-08-25 12:46:58 -0700860
861 REPORTER_ASSERT(reporter, bounds == expectedBounds);
862}
863
jbroman203a9932016-07-11 14:07:59 -0700864DEF_TEST(ImageFilterScaledBlurRadius, reporter) {
865 // Each blur should spread 3*sigma, so 3 for the blur and 30 for the shadow
866 // (before the CTM). Bounds should be computed correctly in the presence of
867 // a (possibly negative) scale.
868 sk_sp<SkImageFilter> blur(make_blur(nullptr));
869 sk_sp<SkImageFilter> dropShadow(make_drop_shadow(nullptr));
870 {
871 // Uniform scale by 2.
872 SkMatrix scaleMatrix;
873 scaleMatrix.setScale(2, 2);
874 SkIRect bounds = SkIRect::MakeLTRB(0, 0, 200, 200);
875
876 SkIRect expectedBlurBounds = SkIRect::MakeLTRB(-6, -6, 206, 206);
877 SkIRect blurBounds = blur->filterBounds(
878 bounds, scaleMatrix, SkImageFilter::kForward_MapDirection);
879 REPORTER_ASSERT(reporter, blurBounds == expectedBlurBounds);
880 SkIRect reverseBlurBounds = blur->filterBounds(
881 bounds, scaleMatrix, SkImageFilter::kReverse_MapDirection);
882 REPORTER_ASSERT(reporter, reverseBlurBounds == expectedBlurBounds);
883
884 SkIRect expectedShadowBounds = SkIRect::MakeLTRB(0, 0, 460, 460);
885 SkIRect shadowBounds = dropShadow->filterBounds(
886 bounds, scaleMatrix, SkImageFilter::kForward_MapDirection);
887 REPORTER_ASSERT(reporter, shadowBounds == expectedShadowBounds);
888 SkIRect expectedReverseShadowBounds =
889 SkIRect::MakeLTRB(-260, -260, 200, 200);
890 SkIRect reverseShadowBounds = dropShadow->filterBounds(
891 bounds, scaleMatrix, SkImageFilter::kReverse_MapDirection);
892 REPORTER_ASSERT(reporter,
893 reverseShadowBounds == expectedReverseShadowBounds);
894 }
895 {
896 // Vertical flip.
897 SkMatrix scaleMatrix;
898 scaleMatrix.setScale(1, -1);
899 SkIRect bounds = SkIRect::MakeLTRB(0, -100, 100, 0);
900
901 SkIRect expectedBlurBounds = SkIRect::MakeLTRB(-3, -103, 103, 3);
902 SkIRect blurBounds = blur->filterBounds(
903 bounds, scaleMatrix, SkImageFilter::kForward_MapDirection);
904 REPORTER_ASSERT(reporter, blurBounds == expectedBlurBounds);
905 SkIRect reverseBlurBounds = blur->filterBounds(
906 bounds, scaleMatrix, SkImageFilter::kReverse_MapDirection);
907 REPORTER_ASSERT(reporter, reverseBlurBounds == expectedBlurBounds);
908
909 SkIRect expectedShadowBounds = SkIRect::MakeLTRB(0, -230, 230, 0);
910 SkIRect shadowBounds = dropShadow->filterBounds(
911 bounds, scaleMatrix, SkImageFilter::kForward_MapDirection);
912 REPORTER_ASSERT(reporter, shadowBounds == expectedShadowBounds);
913 SkIRect expectedReverseShadowBounds =
914 SkIRect::MakeLTRB(-130, -100, 100, 130);
915 SkIRect reverseShadowBounds = dropShadow->filterBounds(
916 bounds, scaleMatrix, SkImageFilter::kReverse_MapDirection);
917 REPORTER_ASSERT(reporter,
918 reverseShadowBounds == expectedReverseShadowBounds);
919 }
920}
921
ajuma5788faa2015-02-13 09:05:47 -0800922DEF_TEST(ImageFilterComposedBlurFastBounds, reporter) {
robertphillips6e7025a2016-04-04 04:31:25 -0700923 sk_sp<SkImageFilter> filter1(make_blur(nullptr));
924 sk_sp<SkImageFilter> filter2(make_blur(nullptr));
robertphillips491fb172016-03-30 12:32:58 -0700925 sk_sp<SkImageFilter> composedFilter(SkComposeImageFilter::Make(std::move(filter1),
926 std::move(filter2)));
ajuma5788faa2015-02-13 09:05:47 -0800927
928 SkRect boundsSrc = SkRect::MakeWH(SkIntToScalar(100), SkIntToScalar(100));
929 SkRect expectedBounds = SkRect::MakeXYWH(
930 SkIntToScalar(-6), SkIntToScalar(-6), SkIntToScalar(112), SkIntToScalar(112));
senorblancoe5e79842016-03-21 14:51:59 -0700931 SkRect boundsDst = composedFilter->computeFastBounds(boundsSrc);
ajuma5788faa2015-02-13 09:05:47 -0800932
933 REPORTER_ASSERT(reporter, boundsDst == expectedBounds);
934}
935
jbroman0e3129d2016-03-17 12:24:23 -0700936DEF_TEST(ImageFilterUnionBounds, reporter) {
robertphillips51a315e2016-03-31 09:05:49 -0700937 sk_sp<SkImageFilter> offset(SkOffsetImageFilter::Make(50, 0, nullptr));
jbroman0e3129d2016-03-17 12:24:23 -0700938 // Regardless of which order they appear in, the image filter bounds should
939 // be combined correctly.
940 {
reed374772b2016-10-05 17:33:02 -0700941 sk_sp<SkImageFilter> composite(SkXfermodeImageFilter::Make(SkBlendMode::kSrcOver, offset));
jbroman0e3129d2016-03-17 12:24:23 -0700942 SkRect bounds = SkRect::MakeWH(100, 100);
943 // Intentionally aliasing here, as that's what the real callers do.
senorblancoe5e79842016-03-21 14:51:59 -0700944 bounds = composite->computeFastBounds(bounds);
jbroman0e3129d2016-03-17 12:24:23 -0700945 REPORTER_ASSERT(reporter, bounds == SkRect::MakeWH(150, 100));
946 }
947 {
reed374772b2016-10-05 17:33:02 -0700948 sk_sp<SkImageFilter> composite(SkXfermodeImageFilter::Make(SkBlendMode::kSrcOver, nullptr,
robertphillips8c0326d2016-04-05 12:48:34 -0700949 offset, nullptr));
jbroman0e3129d2016-03-17 12:24:23 -0700950 SkRect bounds = SkRect::MakeWH(100, 100);
951 // Intentionally aliasing here, as that's what the real callers do.
senorblancoe5e79842016-03-21 14:51:59 -0700952 bounds = composite->computeFastBounds(bounds);
jbroman0e3129d2016-03-17 12:24:23 -0700953 REPORTER_ASSERT(reporter, bounds == SkRect::MakeWH(150, 100));
954 }
955}
956
robertphillips3e302272016-04-20 11:48:36 -0700957static void test_imagefilter_merge_result_size(skiatest::Reporter* reporter, GrContext* context) {
senorblanco4a243982015-11-25 07:06:55 -0800958 SkBitmap greenBM;
959 greenBM.allocN32Pixels(20, 20);
960 greenBM.eraseColor(SK_ColorGREEN);
reed9ce9d672016-03-17 10:51:11 -0700961 sk_sp<SkImage> greenImage(SkImage::MakeFromBitmap(greenBM));
robertphillips549c8992016-04-01 09:28:51 -0700962 sk_sp<SkImageFilter> source(SkImageSource::Make(std::move(greenImage)));
Mike Reed7d954ad2016-10-28 15:42:34 -0400963 sk_sp<SkImageFilter> merge(SkMergeImageFilter::Make(source, source, SkBlendMode::kSrcOver));
senorblanco4a243982015-11-25 07:06:55 -0800964
robertphillips3e302272016-04-20 11:48:36 -0700965 sk_sp<SkSpecialImage> srcImg(create_empty_special_image(context, 1));
robertphillips4418dba2016-03-07 12:45:14 -0800966
brianosman2a75e5d2016-09-22 07:15:37 -0700967 SkImageFilter::OutputProperties noColorSpace(nullptr);
968 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeXYWH(0, 0, 100, 100), nullptr,
969 noColorSpace);
senorblanco4a243982015-11-25 07:06:55 -0800970 SkIPoint offset;
robertphillips4418dba2016-03-07 12:45:14 -0800971
robertphillips2302de92016-03-24 07:26:32 -0700972 sk_sp<SkSpecialImage> resultImg(merge->filterImage(srcImg.get(), ctx, &offset));
robertphillips4418dba2016-03-07 12:45:14 -0800973 REPORTER_ASSERT(reporter, resultImg);
974
975 REPORTER_ASSERT(reporter, resultImg->width() == 20 && resultImg->height() == 20);
senorblanco4a243982015-11-25 07:06:55 -0800976}
977
robertphillips4418dba2016-03-07 12:45:14 -0800978DEF_TEST(ImageFilterMergeResultSize, reporter) {
robertphillips3e302272016-04-20 11:48:36 -0700979 test_imagefilter_merge_result_size(reporter, nullptr);
robertphillips4418dba2016-03-07 12:45:14 -0800980}
981
982#if SK_SUPPORT_GPU
egdanielab527a52016-06-28 08:07:26 -0700983DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterMergeResultSize_Gpu, reporter, ctxInfo) {
bsalomon8b7451a2016-05-11 06:33:06 -0700984 test_imagefilter_merge_result_size(reporter, ctxInfo.grContext());
robertphillips4418dba2016-03-07 12:45:14 -0800985}
986#endif
987
robertphillipsa8d7f0b2014-08-29 08:03:56 -0700988static void draw_blurred_rect(SkCanvas* canvas) {
senorblanco837f5322014-07-14 10:19:54 -0700989 SkPaint filterPaint;
990 filterPaint.setColor(SK_ColorWHITE);
robertphillips6e7025a2016-04-04 04:31:25 -0700991 filterPaint.setImageFilter(SkBlurImageFilter::Make(SkIntToScalar(8), 0, nullptr));
halcanary96fcdcc2015-08-27 07:41:13 -0700992 canvas->saveLayer(nullptr, &filterPaint);
senorblanco837f5322014-07-14 10:19:54 -0700993 SkPaint whitePaint;
994 whitePaint.setColor(SK_ColorWHITE);
995 canvas->drawRect(SkRect::Make(SkIRect::MakeWH(4, 4)), whitePaint);
996 canvas->restore();
997}
998
robertphillipsa8d7f0b2014-08-29 08:03:56 -0700999static void draw_picture_clipped(SkCanvas* canvas, const SkRect& clipRect, const SkPicture* picture) {
senorblanco837f5322014-07-14 10:19:54 -07001000 canvas->save();
1001 canvas->clipRect(clipRect);
1002 canvas->drawPicture(picture);
1003 canvas->restore();
1004}
1005
1006DEF_TEST(ImageFilterDrawTiledBlurRTree, reporter) {
1007 // Check that the blur filter when recorded with RTree acceleration,
1008 // and drawn tiled (with subsequent clip rects) exactly
1009 // matches the same filter drawn with without RTree acceleration.
1010 // This tests that the "bleed" from the blur into the otherwise-blank
1011 // tiles is correctly rendered.
1012 // Tests pass by not asserting.
1013
1014 int width = 16, height = 8;
1015 SkBitmap result1, result2;
1016 result1.allocN32Pixels(width, height);
1017 result2.allocN32Pixels(width, height);
1018 SkCanvas canvas1(result1);
1019 SkCanvas canvas2(result2);
1020 int tileSize = 8;
1021
1022 canvas1.clear(0);
1023 canvas2.clear(0);
1024
1025 SkRTreeFactory factory;
1026
1027 SkPictureRecorder recorder1, recorder2;
1028 // The only difference between these two pictures is that one has RTree aceleration.
mtklein3f3b3d02014-12-01 11:47:08 -08001029 SkCanvas* recordingCanvas1 = recorder1.beginRecording(SkIntToScalar(width),
1030 SkIntToScalar(height),
halcanary96fcdcc2015-08-27 07:41:13 -07001031 nullptr, 0);
mtklein3f3b3d02014-12-01 11:47:08 -08001032 SkCanvas* recordingCanvas2 = recorder2.beginRecording(SkIntToScalar(width),
1033 SkIntToScalar(height),
robertphillipsa8d7f0b2014-08-29 08:03:56 -07001034 &factory, 0);
1035 draw_blurred_rect(recordingCanvas1);
1036 draw_blurred_rect(recordingCanvas2);
reedca2622b2016-03-18 07:25:55 -07001037 sk_sp<SkPicture> picture1(recorder1.finishRecordingAsPicture());
1038 sk_sp<SkPicture> picture2(recorder2.finishRecordingAsPicture());
senorblanco837f5322014-07-14 10:19:54 -07001039 for (int y = 0; y < height; y += tileSize) {
1040 for (int x = 0; x < width; x += tileSize) {
1041 SkRect tileRect = SkRect::Make(SkIRect::MakeXYWH(x, y, tileSize, tileSize));
reedca2622b2016-03-18 07:25:55 -07001042 draw_picture_clipped(&canvas1, tileRect, picture1.get());
1043 draw_picture_clipped(&canvas2, tileRect, picture2.get());
senorblanco837f5322014-07-14 10:19:54 -07001044 }
1045 }
1046 for (int y = 0; y < height; y++) {
1047 int diffs = memcmp(result1.getAddr32(0, y), result2.getAddr32(0, y), result1.rowBytes());
1048 REPORTER_ASSERT(reporter, !diffs);
1049 if (diffs) {
1050 break;
1051 }
1052 }
1053}
1054
senorblanco@chromium.org91957432014-05-01 14:03:41 +00001055DEF_TEST(ImageFilterMatrixConvolution, reporter) {
1056 // Check that a 1x3 filter does not cause a spurious assert.
1057 SkScalar kernel[3] = {
1058 SkIntToScalar( 1), SkIntToScalar( 1), SkIntToScalar( 1),
1059 };
1060 SkISize kernelSize = SkISize::Make(1, 3);
1061 SkScalar gain = SK_Scalar1, bias = 0;
1062 SkIPoint kernelOffset = SkIPoint::Make(0, 0);
1063
robertphillipsef6a47b2016-04-08 08:01:20 -07001064 sk_sp<SkImageFilter> filter(SkMatrixConvolutionImageFilter::Make(
1065 kernelSize, kernel,
1066 gain, bias, kernelOffset,
1067 SkMatrixConvolutionImageFilter::kRepeat_TileMode,
1068 false, nullptr));
senorblanco@chromium.org91957432014-05-01 14:03:41 +00001069
1070 SkBitmap result;
1071 int width = 16, height = 16;
1072 result.allocN32Pixels(width, height);
1073 SkCanvas canvas(result);
1074 canvas.clear(0);
1075
1076 SkPaint paint;
robertphillipsef6a47b2016-04-08 08:01:20 -07001077 paint.setImageFilter(std::move(filter));
senorblanco@chromium.org91957432014-05-01 14:03:41 +00001078 SkRect rect = SkRect::Make(SkIRect::MakeWH(width, height));
1079 canvas.drawRect(rect, paint);
1080}
1081
senorblanco@chromium.org8c7372b2014-05-02 19:13:11 +00001082DEF_TEST(ImageFilterMatrixConvolutionBorder, reporter) {
1083 // Check that a filter with borders outside the target bounds
1084 // does not crash.
1085 SkScalar kernel[3] = {
1086 0, 0, 0,
1087 };
1088 SkISize kernelSize = SkISize::Make(3, 1);
1089 SkScalar gain = SK_Scalar1, bias = 0;
1090 SkIPoint kernelOffset = SkIPoint::Make(2, 0);
1091
robertphillipsef6a47b2016-04-08 08:01:20 -07001092 sk_sp<SkImageFilter> filter(SkMatrixConvolutionImageFilter::Make(
1093 kernelSize, kernel, gain, bias, kernelOffset,
1094 SkMatrixConvolutionImageFilter::kClamp_TileMode,
1095 true, nullptr));
senorblanco@chromium.org8c7372b2014-05-02 19:13:11 +00001096
1097 SkBitmap result;
1098
1099 int width = 10, height = 10;
1100 result.allocN32Pixels(width, height);
1101 SkCanvas canvas(result);
1102 canvas.clear(0);
1103
1104 SkPaint filterPaint;
robertphillipsef6a47b2016-04-08 08:01:20 -07001105 filterPaint.setImageFilter(std::move(filter));
senorblanco@chromium.org8c7372b2014-05-02 19:13:11 +00001106 SkRect bounds = SkRect::MakeWH(1, 10);
1107 SkRect rect = SkRect::Make(SkIRect::MakeWH(width, height));
1108 SkPaint rectPaint;
1109 canvas.saveLayer(&bounds, &filterPaint);
1110 canvas.drawRect(rect, rectPaint);
1111 canvas.restore();
1112}
1113
robertphillips3e302272016-04-20 11:48:36 -07001114static void test_big_kernel(skiatest::Reporter* reporter, GrContext* context) {
robertphillipsdada4dd2016-04-13 04:54:36 -07001115 // Check that a kernel that is too big for the GPU still works
1116 SkScalar identityKernel[49] = {
1117 0, 0, 0, 0, 0, 0, 0,
1118 0, 0, 0, 0, 0, 0, 0,
1119 0, 0, 0, 0, 0, 0, 0,
1120 0, 0, 0, 1, 0, 0, 0,
1121 0, 0, 0, 0, 0, 0, 0,
1122 0, 0, 0, 0, 0, 0, 0,
1123 0, 0, 0, 0, 0, 0, 0
1124 };
1125 SkISize kernelSize = SkISize::Make(7, 7);
1126 SkScalar gain = SK_Scalar1, bias = 0;
1127 SkIPoint kernelOffset = SkIPoint::Make(0, 0);
1128
1129 sk_sp<SkImageFilter> filter(SkMatrixConvolutionImageFilter::Make(
1130 kernelSize, identityKernel, gain, bias, kernelOffset,
1131 SkMatrixConvolutionImageFilter::kClamp_TileMode,
1132 true, nullptr));
1133
robertphillips3e302272016-04-20 11:48:36 -07001134 sk_sp<SkSpecialImage> srcImg(create_empty_special_image(context, 100));
robertphillipsdada4dd2016-04-13 04:54:36 -07001135 SkASSERT(srcImg);
1136
1137 SkIPoint offset;
brianosman2a75e5d2016-09-22 07:15:37 -07001138 SkImageFilter::OutputProperties noColorSpace(nullptr);
1139 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeWH(100, 100), nullptr, noColorSpace);
robertphillipsdada4dd2016-04-13 04:54:36 -07001140 sk_sp<SkSpecialImage> resultImg(filter->filterImage(srcImg.get(), ctx, &offset));
1141 REPORTER_ASSERT(reporter, resultImg);
1142 REPORTER_ASSERT(reporter, SkToBool(context) == resultImg->isTextureBacked());
1143 REPORTER_ASSERT(reporter, resultImg->width() == 100 && resultImg->height() == 100);
1144 REPORTER_ASSERT(reporter, offset.fX == 0 && offset.fY == 0);
1145}
1146
1147DEF_TEST(ImageFilterMatrixConvolutionBigKernel, reporter) {
robertphillips3e302272016-04-20 11:48:36 -07001148 test_big_kernel(reporter, nullptr);
robertphillipsdada4dd2016-04-13 04:54:36 -07001149}
1150
1151#if SK_SUPPORT_GPU
egdanielab527a52016-06-28 08:07:26 -07001152DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterMatrixConvolutionBigKernel_Gpu,
1153 reporter, ctxInfo) {
bsalomon8b7451a2016-05-11 06:33:06 -07001154 test_big_kernel(reporter, ctxInfo.grContext());
robertphillipsdada4dd2016-04-13 04:54:36 -07001155}
1156#endif
1157
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +00001158DEF_TEST(ImageFilterCropRect, reporter) {
robertphillips3e302272016-04-20 11:48:36 -07001159 test_crop_rects(reporter, nullptr);
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +00001160}
1161
robertphillips4418dba2016-03-07 12:45:14 -08001162#if SK_SUPPORT_GPU
bsalomon68d91342016-04-12 09:59:58 -07001163DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterCropRect_Gpu, reporter, ctxInfo) {
bsalomon8b7451a2016-05-11 06:33:06 -07001164 test_crop_rects(reporter, ctxInfo.grContext());
robertphillips4418dba2016-03-07 12:45:14 -08001165}
1166#endif
1167
tfarina9ea53f92014-06-24 06:50:39 -07001168DEF_TEST(ImageFilterMatrix, reporter) {
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +00001169 SkBitmap temp;
mike@reedtribe.orgdeee4962014-02-13 14:41:43 +00001170 temp.allocN32Pixels(100, 100);
robertphillips9a53fd72015-06-22 09:46:59 -07001171 SkCanvas canvas(temp);
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +00001172 canvas.scale(SkIntToScalar(2), SkIntToScalar(2));
1173
1174 SkMatrix expectedMatrix = canvas.getTotalMatrix();
1175
commit-bot@chromium.org5fb2ce32014-04-17 23:35:06 +00001176 SkRTreeFactory factory;
1177 SkPictureRecorder recorder;
1178 SkCanvas* recordingCanvas = recorder.beginRecording(100, 100, &factory, 0);
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +00001179
1180 SkPaint paint;
robertphillips43c2ad42016-04-04 05:05:11 -07001181 paint.setImageFilter(MatrixTestImageFilter::Make(reporter, expectedMatrix));
halcanary96fcdcc2015-08-27 07:41:13 -07001182 recordingCanvas->saveLayer(nullptr, &paint);
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +00001183 SkPaint solidPaint;
1184 solidPaint.setColor(0xFFFFFFFF);
1185 recordingCanvas->save();
1186 recordingCanvas->scale(SkIntToScalar(10), SkIntToScalar(10));
1187 recordingCanvas->drawRect(SkRect::Make(SkIRect::MakeWH(100, 100)), solidPaint);
1188 recordingCanvas->restore(); // scale
1189 recordingCanvas->restore(); // saveLayer
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +00001190
reedca2622b2016-03-18 07:25:55 -07001191 canvas.drawPicture(recorder.finishRecordingAsPicture());
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +00001192}
1193
senorblanco3d822c22014-07-30 14:49:31 -07001194DEF_TEST(ImageFilterCrossProcessPictureImageFilter, reporter) {
senorblanco@chromium.org97f5fc62014-05-30 20:50:56 +00001195 SkRTreeFactory factory;
1196 SkPictureRecorder recorder;
1197 SkCanvas* recordingCanvas = recorder.beginRecording(1, 1, &factory, 0);
1198
1199 // Create an SkPicture which simply draws a green 1x1 rectangle.
1200 SkPaint greenPaint;
1201 greenPaint.setColor(SK_ColorGREEN);
1202 recordingCanvas->drawRect(SkRect::Make(SkIRect::MakeWH(1, 1)), greenPaint);
reedca2622b2016-03-18 07:25:55 -07001203 sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture());
senorblanco@chromium.org97f5fc62014-05-30 20:50:56 +00001204
1205 // Wrap that SkPicture in an SkPictureImageFilter.
robertphillips5ff17b12016-03-28 13:13:42 -07001206 sk_sp<SkImageFilter> imageFilter(SkPictureImageFilter::Make(picture));
senorblanco@chromium.org97f5fc62014-05-30 20:50:56 +00001207
1208 // Check that SkPictureImageFilter successfully serializes its contained
1209 // SkPicture when not in cross-process mode.
1210 SkPaint paint;
robertphillips5ff17b12016-03-28 13:13:42 -07001211 paint.setImageFilter(imageFilter);
senorblanco@chromium.org97f5fc62014-05-30 20:50:56 +00001212 SkPictureRecorder outerRecorder;
1213 SkCanvas* outerCanvas = outerRecorder.beginRecording(1, 1, &factory, 0);
1214 SkPaint redPaintWithFilter;
1215 redPaintWithFilter.setColor(SK_ColorRED);
robertphillips5ff17b12016-03-28 13:13:42 -07001216 redPaintWithFilter.setImageFilter(imageFilter);
senorblanco@chromium.org97f5fc62014-05-30 20:50:56 +00001217 outerCanvas->drawRect(SkRect::Make(SkIRect::MakeWH(1, 1)), redPaintWithFilter);
reedca2622b2016-03-18 07:25:55 -07001218 sk_sp<SkPicture> outerPicture(outerRecorder.finishRecordingAsPicture());
senorblanco@chromium.org97f5fc62014-05-30 20:50:56 +00001219
1220 SkBitmap bitmap;
1221 bitmap.allocN32Pixels(1, 1);
robertphillips9a53fd72015-06-22 09:46:59 -07001222 SkCanvas canvas(bitmap);
senorblanco@chromium.org97f5fc62014-05-30 20:50:56 +00001223
1224 // The result here should be green, since the filter replaces the primitive's red interior.
1225 canvas.clear(0x0);
robertphillips9b14f262014-06-04 05:40:44 -07001226 canvas.drawPicture(outerPicture);
senorblanco@chromium.org97f5fc62014-05-30 20:50:56 +00001227 uint32_t pixel = *bitmap.getAddr32(0, 0);
1228 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1229
1230 // Check that, for now, SkPictureImageFilter does not serialize or
1231 // deserialize its contained picture when the filter is serialized
1232 // cross-process. Do this by "laundering" it through SkValidatingReadBuffer.
robertphillips12fa47d2016-04-08 16:28:09 -07001233 sk_sp<SkData> data(SkValidatingSerializeFlattenable(imageFilter.get()));
1234 sk_sp<SkFlattenable> flattenable(SkValidatingDeserializeFlattenable(
mtklein3b375452016-04-04 14:57:19 -07001235 data->data(), data->size(), SkImageFilter::GetFlattenableType()));
senorblanco@chromium.org97f5fc62014-05-30 20:50:56 +00001236 SkImageFilter* unflattenedFilter = static_cast<SkImageFilter*>(flattenable.get());
1237
1238 redPaintWithFilter.setImageFilter(unflattenedFilter);
1239 SkPictureRecorder crossProcessRecorder;
1240 SkCanvas* crossProcessCanvas = crossProcessRecorder.beginRecording(1, 1, &factory, 0);
1241 crossProcessCanvas->drawRect(SkRect::Make(SkIRect::MakeWH(1, 1)), redPaintWithFilter);
reedca2622b2016-03-18 07:25:55 -07001242 sk_sp<SkPicture> crossProcessPicture(crossProcessRecorder.finishRecordingAsPicture());
senorblanco@chromium.org97f5fc62014-05-30 20:50:56 +00001243
1244 canvas.clear(0x0);
robertphillips9b14f262014-06-04 05:40:44 -07001245 canvas.drawPicture(crossProcessPicture);
senorblanco@chromium.org97f5fc62014-05-30 20:50:56 +00001246 pixel = *bitmap.getAddr32(0, 0);
hendrikw446ee672015-06-16 09:28:37 -07001247 // If the security precautions are enabled, the result here should not be green, since the
1248 // filter draws nothing.
mtklein2afbe232016-02-07 12:23:10 -08001249 REPORTER_ASSERT(reporter, SkPicture::PictureIOSecurityPrecautionsEnabled()
hendrikw446ee672015-06-16 09:28:37 -07001250 ? pixel != SK_ColorGREEN : pixel == SK_ColorGREEN);
senorblanco@chromium.org97f5fc62014-05-30 20:50:56 +00001251}
1252
robertphillips3e302272016-04-20 11:48:36 -07001253static void test_clipped_picture_imagefilter(skiatest::Reporter* reporter, GrContext* context) {
reedca2622b2016-03-18 07:25:55 -07001254 sk_sp<SkPicture> picture;
senorblanco3d822c22014-07-30 14:49:31 -07001255
robertphillips4418dba2016-03-07 12:45:14 -08001256 {
1257 SkRTreeFactory factory;
1258 SkPictureRecorder recorder;
1259 SkCanvas* recordingCanvas = recorder.beginRecording(1, 1, &factory, 0);
1260
1261 // Create an SkPicture which simply draws a green 1x1 rectangle.
1262 SkPaint greenPaint;
1263 greenPaint.setColor(SK_ColorGREEN);
1264 recordingCanvas->drawRect(SkRect::Make(SkIRect::MakeWH(1, 1)), greenPaint);
reedca2622b2016-03-18 07:25:55 -07001265 picture = recorder.finishRecordingAsPicture();
robertphillips4418dba2016-03-07 12:45:14 -08001266 }
1267
robertphillips3e302272016-04-20 11:48:36 -07001268 sk_sp<SkSpecialImage> srcImg(create_empty_special_image(context, 2));
senorblanco3d822c22014-07-30 14:49:31 -07001269
robertphillips5ff17b12016-03-28 13:13:42 -07001270 sk_sp<SkImageFilter> imageFilter(SkPictureImageFilter::Make(picture));
senorblanco3d822c22014-07-30 14:49:31 -07001271
senorblanco3d822c22014-07-30 14:49:31 -07001272 SkIPoint offset;
brianosman2a75e5d2016-09-22 07:15:37 -07001273 SkImageFilter::OutputProperties noColorSpace(nullptr);
1274 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeXYWH(1, 1, 1, 1), nullptr, noColorSpace);
robertphillips4418dba2016-03-07 12:45:14 -08001275
robertphillips2302de92016-03-24 07:26:32 -07001276 sk_sp<SkSpecialImage> resultImage(imageFilter->filterImage(srcImg.get(), ctx, &offset));
robertphillips4418dba2016-03-07 12:45:14 -08001277 REPORTER_ASSERT(reporter, !resultImage);
senorblanco3d822c22014-07-30 14:49:31 -07001278}
1279
robertphillips4418dba2016-03-07 12:45:14 -08001280DEF_TEST(ImageFilterClippedPictureImageFilter, reporter) {
robertphillips3e302272016-04-20 11:48:36 -07001281 test_clipped_picture_imagefilter(reporter, nullptr);
robertphillips4418dba2016-03-07 12:45:14 -08001282}
1283
1284#if SK_SUPPORT_GPU
bsalomon68d91342016-04-12 09:59:58 -07001285DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterClippedPictureImageFilter_Gpu, reporter, ctxInfo) {
bsalomon8b7451a2016-05-11 06:33:06 -07001286 test_clipped_picture_imagefilter(reporter, ctxInfo.grContext());
robertphillips4418dba2016-03-07 12:45:14 -08001287}
1288#endif
1289
tfarina9ea53f92014-06-24 06:50:39 -07001290DEF_TEST(ImageFilterEmptySaveLayer, reporter) {
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001291 // Even when there's an empty saveLayer()/restore(), ensure that an image
1292 // filter or color filter which affects transparent black still draws.
1293
1294 SkBitmap bitmap;
1295 bitmap.allocN32Pixels(10, 10);
robertphillips9a53fd72015-06-22 09:46:59 -07001296 SkCanvas canvas(bitmap);
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001297
1298 SkRTreeFactory factory;
1299 SkPictureRecorder recorder;
1300
robertphillips5605b562016-04-05 11:50:42 -07001301 sk_sp<SkColorFilter> green(SkColorFilter::MakeModeFilter(SK_ColorGREEN,
Mike Reed7d954ad2016-10-28 15:42:34 -04001302 SkBlendMode::kSrc));
robertphillips5605b562016-04-05 11:50:42 -07001303 sk_sp<SkImageFilter> imageFilter(SkColorFilterImageFilter::Make(green, nullptr));
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001304 SkPaint imageFilterPaint;
robertphillips5605b562016-04-05 11:50:42 -07001305 imageFilterPaint.setImageFilter(std::move(imageFilter));
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001306 SkPaint colorFilterPaint;
reedd053ce92016-03-22 10:17:23 -07001307 colorFilterPaint.setColorFilter(green);
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001308
1309 SkRect bounds = SkRect::MakeWH(10, 10);
1310
1311 SkCanvas* recordingCanvas = recorder.beginRecording(10, 10, &factory, 0);
1312 recordingCanvas->saveLayer(&bounds, &imageFilterPaint);
1313 recordingCanvas->restore();
reedca2622b2016-03-18 07:25:55 -07001314 sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture());
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001315
1316 canvas.clear(0);
robertphillips9b14f262014-06-04 05:40:44 -07001317 canvas.drawPicture(picture);
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001318 uint32_t pixel = *bitmap.getAddr32(0, 0);
1319 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1320
1321 recordingCanvas = recorder.beginRecording(10, 10, &factory, 0);
halcanary96fcdcc2015-08-27 07:41:13 -07001322 recordingCanvas->saveLayer(nullptr, &imageFilterPaint);
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001323 recordingCanvas->restore();
reedca2622b2016-03-18 07:25:55 -07001324 sk_sp<SkPicture> picture2(recorder.finishRecordingAsPicture());
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001325
1326 canvas.clear(0);
robertphillips9b14f262014-06-04 05:40:44 -07001327 canvas.drawPicture(picture2);
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001328 pixel = *bitmap.getAddr32(0, 0);
1329 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1330
1331 recordingCanvas = recorder.beginRecording(10, 10, &factory, 0);
1332 recordingCanvas->saveLayer(&bounds, &colorFilterPaint);
1333 recordingCanvas->restore();
reedca2622b2016-03-18 07:25:55 -07001334 sk_sp<SkPicture> picture3(recorder.finishRecordingAsPicture());
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001335
1336 canvas.clear(0);
robertphillips9b14f262014-06-04 05:40:44 -07001337 canvas.drawPicture(picture3);
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001338 pixel = *bitmap.getAddr32(0, 0);
1339 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1340}
1341
robertphillips9a53fd72015-06-22 09:46:59 -07001342static void test_huge_blur(SkCanvas* canvas, skiatest::Reporter* reporter) {
senorblanco@chromium.org09843fd2014-03-24 20:50:59 +00001343 SkBitmap bitmap;
1344 bitmap.allocN32Pixels(100, 100);
1345 bitmap.eraseARGB(0, 0, 0, 0);
1346
1347 // Check that a blur with an insane radius does not crash or assert.
senorblanco@chromium.org09843fd2014-03-24 20:50:59 +00001348 SkPaint paint;
robertphillips6e7025a2016-04-04 04:31:25 -07001349 paint.setImageFilter(SkBlurImageFilter::Make(SkIntToScalar(1<<30),
1350 SkIntToScalar(1<<30),
1351 nullptr));
reedda420b92015-12-16 08:38:15 -08001352 canvas->drawBitmap(bitmap, 0, 0, &paint);
senorblanco@chromium.org09843fd2014-03-24 20:50:59 +00001353}
1354
1355DEF_TEST(HugeBlurImageFilter, reporter) {
1356 SkBitmap temp;
1357 temp.allocN32Pixels(100, 100);
robertphillips9a53fd72015-06-22 09:46:59 -07001358 SkCanvas canvas(temp);
1359 test_huge_blur(&canvas, reporter);
senorblanco@chromium.org09843fd2014-03-24 20:50:59 +00001360}
1361
senorblanco21a465d2016-04-11 11:58:39 -07001362DEF_TEST(ImageFilterMatrixConvolutionSanityTest, reporter) {
senorblanco3a495202014-09-29 07:57:20 -07001363 SkScalar kernel[1] = { 0 };
1364 SkScalar gain = SK_Scalar1, bias = 0;
1365 SkIPoint kernelOffset = SkIPoint::Make(1, 1);
1366
halcanary96fcdcc2015-08-27 07:41:13 -07001367 // Check that an enormous (non-allocatable) kernel gives a nullptr filter.
robertphillipsef6a47b2016-04-08 08:01:20 -07001368 sk_sp<SkImageFilter> conv(SkMatrixConvolutionImageFilter::Make(
senorblanco3a495202014-09-29 07:57:20 -07001369 SkISize::Make(1<<30, 1<<30),
1370 kernel,
1371 gain,
1372 bias,
1373 kernelOffset,
1374 SkMatrixConvolutionImageFilter::kRepeat_TileMode,
robertphillipsef6a47b2016-04-08 08:01:20 -07001375 false,
1376 nullptr));
senorblanco3a495202014-09-29 07:57:20 -07001377
halcanary96fcdcc2015-08-27 07:41:13 -07001378 REPORTER_ASSERT(reporter, nullptr == conv.get());
senorblanco3a495202014-09-29 07:57:20 -07001379
halcanary96fcdcc2015-08-27 07:41:13 -07001380 // Check that a nullptr kernel gives a nullptr filter.
robertphillipsef6a47b2016-04-08 08:01:20 -07001381 conv = SkMatrixConvolutionImageFilter::Make(
senorblanco3a495202014-09-29 07:57:20 -07001382 SkISize::Make(1, 1),
halcanary96fcdcc2015-08-27 07:41:13 -07001383 nullptr,
senorblanco3a495202014-09-29 07:57:20 -07001384 gain,
1385 bias,
1386 kernelOffset,
1387 SkMatrixConvolutionImageFilter::kRepeat_TileMode,
robertphillipsef6a47b2016-04-08 08:01:20 -07001388 false,
1389 nullptr);
senorblanco3a495202014-09-29 07:57:20 -07001390
halcanary96fcdcc2015-08-27 07:41:13 -07001391 REPORTER_ASSERT(reporter, nullptr == conv.get());
senorblanco3a495202014-09-29 07:57:20 -07001392
halcanary96fcdcc2015-08-27 07:41:13 -07001393 // Check that a kernel width < 1 gives a nullptr filter.
robertphillipsef6a47b2016-04-08 08:01:20 -07001394 conv = SkMatrixConvolutionImageFilter::Make(
senorblanco3a495202014-09-29 07:57:20 -07001395 SkISize::Make(0, 1),
1396 kernel,
1397 gain,
1398 bias,
1399 kernelOffset,
1400 SkMatrixConvolutionImageFilter::kRepeat_TileMode,
robertphillipsef6a47b2016-04-08 08:01:20 -07001401 false,
1402 nullptr);
senorblanco3a495202014-09-29 07:57:20 -07001403
halcanary96fcdcc2015-08-27 07:41:13 -07001404 REPORTER_ASSERT(reporter, nullptr == conv.get());
senorblanco3a495202014-09-29 07:57:20 -07001405
halcanary96fcdcc2015-08-27 07:41:13 -07001406 // Check that kernel height < 1 gives a nullptr filter.
robertphillipsef6a47b2016-04-08 08:01:20 -07001407 conv = SkMatrixConvolutionImageFilter::Make(
senorblanco3a495202014-09-29 07:57:20 -07001408 SkISize::Make(1, -1),
1409 kernel,
1410 gain,
1411 bias,
1412 kernelOffset,
1413 SkMatrixConvolutionImageFilter::kRepeat_TileMode,
robertphillipsef6a47b2016-04-08 08:01:20 -07001414 false,
1415 nullptr);
senorblanco3a495202014-09-29 07:57:20 -07001416
halcanary96fcdcc2015-08-27 07:41:13 -07001417 REPORTER_ASSERT(reporter, nullptr == conv.get());
senorblanco3a495202014-09-29 07:57:20 -07001418}
1419
robertphillips9a53fd72015-06-22 09:46:59 -07001420static void test_xfermode_cropped_input(SkCanvas* canvas, skiatest::Reporter* reporter) {
1421 canvas->clear(0);
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001422
1423 SkBitmap bitmap;
1424 bitmap.allocN32Pixels(1, 1);
1425 bitmap.eraseARGB(255, 255, 255, 255);
1426
robertphillips5605b562016-04-05 11:50:42 -07001427 sk_sp<SkColorFilter> green(SkColorFilter::MakeModeFilter(SK_ColorGREEN,
Mike Reed7d954ad2016-10-28 15:42:34 -04001428 SkBlendMode::kSrcIn));
robertphillips5605b562016-04-05 11:50:42 -07001429 sk_sp<SkImageFilter> greenFilter(SkColorFilterImageFilter::Make(green, nullptr));
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001430 SkImageFilter::CropRect cropRect(SkRect::MakeEmpty());
robertphillips5605b562016-04-05 11:50:42 -07001431 sk_sp<SkImageFilter> croppedOut(SkColorFilterImageFilter::Make(green, nullptr, &cropRect));
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001432
1433 // Check that an xfermode image filter whose input has been cropped out still draws the other
1434 // input. Also check that drawing with both inputs cropped out doesn't cause a GPU warning.
reed374772b2016-10-05 17:33:02 -07001435 SkBlendMode mode = SkBlendMode::kSrcOver;
robertphillips8c0326d2016-04-05 12:48:34 -07001436 sk_sp<SkImageFilter> xfermodeNoFg(SkXfermodeImageFilter::Make(mode, greenFilter,
1437 croppedOut, nullptr));
1438 sk_sp<SkImageFilter> xfermodeNoBg(SkXfermodeImageFilter::Make(mode, croppedOut,
1439 greenFilter, nullptr));
1440 sk_sp<SkImageFilter> xfermodeNoFgNoBg(SkXfermodeImageFilter::Make(mode, croppedOut,
1441 croppedOut, nullptr));
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001442
1443 SkPaint paint;
robertphillips8c0326d2016-04-05 12:48:34 -07001444 paint.setImageFilter(std::move(xfermodeNoFg));
reedda420b92015-12-16 08:38:15 -08001445 canvas->drawBitmap(bitmap, 0, 0, &paint); // drawSprite
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001446
1447 uint32_t pixel;
kkinnunena9d9a392015-03-06 07:16:00 -08001448 SkImageInfo info = SkImageInfo::Make(1, 1, kBGRA_8888_SkColorType, kUnpremul_SkAlphaType);
robertphillips9a53fd72015-06-22 09:46:59 -07001449 canvas->readPixels(info, &pixel, 4, 0, 0);
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001450 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1451
robertphillips8c0326d2016-04-05 12:48:34 -07001452 paint.setImageFilter(std::move(xfermodeNoBg));
reedda420b92015-12-16 08:38:15 -08001453 canvas->drawBitmap(bitmap, 0, 0, &paint); // drawSprite
robertphillips9a53fd72015-06-22 09:46:59 -07001454 canvas->readPixels(info, &pixel, 4, 0, 0);
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001455 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1456
robertphillips8c0326d2016-04-05 12:48:34 -07001457 paint.setImageFilter(std::move(xfermodeNoFgNoBg));
reedda420b92015-12-16 08:38:15 -08001458 canvas->drawBitmap(bitmap, 0, 0, &paint); // drawSprite
robertphillips9a53fd72015-06-22 09:46:59 -07001459 canvas->readPixels(info, &pixel, 4, 0, 0);
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001460 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1461}
1462
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001463DEF_TEST(ImageFilterNestedSaveLayer, reporter) {
1464 SkBitmap temp;
1465 temp.allocN32Pixels(50, 50);
robertphillips9a53fd72015-06-22 09:46:59 -07001466 SkCanvas canvas(temp);
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001467 canvas.clear(0x0);
1468
1469 SkBitmap bitmap;
1470 bitmap.allocN32Pixels(10, 10);
1471 bitmap.eraseColor(SK_ColorGREEN);
1472
1473 SkMatrix matrix;
1474 matrix.setScale(SkIntToScalar(2), SkIntToScalar(2));
1475 matrix.postTranslate(SkIntToScalar(-20), SkIntToScalar(-20));
robertphillipsae8c9332016-04-05 15:09:00 -07001476 sk_sp<SkImageFilter> matrixFilter(
1477 SkImageFilter::MakeMatrixFilter(matrix, kLow_SkFilterQuality, nullptr));
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001478
1479 // Test that saveLayer() with a filter nested inside another saveLayer() applies the
1480 // correct offset to the filter matrix.
1481 SkRect bounds1 = SkRect::MakeXYWH(10, 10, 30, 30);
halcanary96fcdcc2015-08-27 07:41:13 -07001482 canvas.saveLayer(&bounds1, nullptr);
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001483 SkPaint filterPaint;
robertphillipsae8c9332016-04-05 15:09:00 -07001484 filterPaint.setImageFilter(std::move(matrixFilter));
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001485 SkRect bounds2 = SkRect::MakeXYWH(20, 20, 10, 10);
1486 canvas.saveLayer(&bounds2, &filterPaint);
1487 SkPaint greenPaint;
1488 greenPaint.setColor(SK_ColorGREEN);
1489 canvas.drawRect(bounds2, greenPaint);
1490 canvas.restore();
1491 canvas.restore();
1492 SkPaint strokePaint;
1493 strokePaint.setStyle(SkPaint::kStroke_Style);
1494 strokePaint.setColor(SK_ColorRED);
1495
kkinnunena9d9a392015-03-06 07:16:00 -08001496 SkImageInfo info = SkImageInfo::Make(1, 1, kBGRA_8888_SkColorType, kUnpremul_SkAlphaType);
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001497 uint32_t pixel;
1498 canvas.readPixels(info, &pixel, 4, 25, 25);
1499 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1500
1501 // Test that drawSprite() with a filter nested inside a saveLayer() applies the
1502 // correct offset to the filter matrix.
1503 canvas.clear(0x0);
1504 canvas.readPixels(info, &pixel, 4, 25, 25);
halcanary96fcdcc2015-08-27 07:41:13 -07001505 canvas.saveLayer(&bounds1, nullptr);
reedda420b92015-12-16 08:38:15 -08001506 canvas.drawBitmap(bitmap, 20, 20, &filterPaint); // drawSprite
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001507 canvas.restore();
1508
1509 canvas.readPixels(info, &pixel, 4, 25, 25);
1510 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1511}
1512
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001513DEF_TEST(XfermodeImageFilterCroppedInput, reporter) {
1514 SkBitmap temp;
1515 temp.allocN32Pixels(100, 100);
robertphillips9a53fd72015-06-22 09:46:59 -07001516 SkCanvas canvas(temp);
1517 test_xfermode_cropped_input(&canvas, reporter);
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001518}
senorblanco@chromium.org09843fd2014-03-24 20:50:59 +00001519
robertphillips3e302272016-04-20 11:48:36 -07001520static void test_composed_imagefilter_offset(skiatest::Reporter* reporter, GrContext* context) {
1521 sk_sp<SkSpecialImage> srcImg(create_empty_special_image(context, 100));
ajuma5788faa2015-02-13 09:05:47 -08001522
1523 SkImageFilter::CropRect cropRect(SkRect::MakeXYWH(1, 0, 20, 20));
robertphillips51a315e2016-03-31 09:05:49 -07001524 sk_sp<SkImageFilter> offsetFilter(SkOffsetImageFilter::Make(0, 0, nullptr, &cropRect));
robertphillips6e7025a2016-04-04 04:31:25 -07001525 sk_sp<SkImageFilter> blurFilter(SkBlurImageFilter::Make(SK_Scalar1, SK_Scalar1,
1526 nullptr, &cropRect));
robertphillips491fb172016-03-30 12:32:58 -07001527 sk_sp<SkImageFilter> composedFilter(SkComposeImageFilter::Make(std::move(blurFilter),
1528 std::move(offsetFilter)));
ajuma5788faa2015-02-13 09:05:47 -08001529 SkIPoint offset;
brianosman2a75e5d2016-09-22 07:15:37 -07001530 SkImageFilter::OutputProperties noColorSpace(nullptr);
1531 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeWH(100, 100), nullptr, noColorSpace);
robertphillips4418dba2016-03-07 12:45:14 -08001532
robertphillips2302de92016-03-24 07:26:32 -07001533 sk_sp<SkSpecialImage> resultImg(composedFilter->filterImage(srcImg.get(), ctx, &offset));
robertphillips4418dba2016-03-07 12:45:14 -08001534 REPORTER_ASSERT(reporter, resultImg);
ajuma5788faa2015-02-13 09:05:47 -08001535 REPORTER_ASSERT(reporter, offset.fX == 1 && offset.fY == 0);
1536}
1537
robertphillips4418dba2016-03-07 12:45:14 -08001538DEF_TEST(ComposedImageFilterOffset, reporter) {
robertphillips3e302272016-04-20 11:48:36 -07001539 test_composed_imagefilter_offset(reporter, nullptr);
robertphillips4418dba2016-03-07 12:45:14 -08001540}
1541
1542#if SK_SUPPORT_GPU
bsalomon68d91342016-04-12 09:59:58 -07001543DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ComposedImageFilterOffset_Gpu, reporter, ctxInfo) {
bsalomon8b7451a2016-05-11 06:33:06 -07001544 test_composed_imagefilter_offset(reporter, ctxInfo.grContext());
robertphillips4418dba2016-03-07 12:45:14 -08001545}
1546#endif
1547
robertphillips3e302272016-04-20 11:48:36 -07001548static void test_composed_imagefilter_bounds(skiatest::Reporter* reporter, GrContext* context) {
jbroman17a65202016-03-21 08:38:58 -07001549 // The bounds passed to the inner filter must be filtered by the outer
1550 // filter, so that the inner filter produces the pixels that the outer
1551 // filter requires as input. This matters if the outer filter moves pixels.
1552 // Here, accounting for the outer offset is necessary so that the green
1553 // pixels of the picture are not clipped.
1554
1555 SkPictureRecorder recorder;
1556 SkCanvas* recordingCanvas = recorder.beginRecording(SkRect::MakeWH(200, 100));
1557 recordingCanvas->clipRect(SkRect::MakeXYWH(100, 0, 100, 100));
1558 recordingCanvas->clear(SK_ColorGREEN);
robertphillips491fb172016-03-30 12:32:58 -07001559 sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture());
robertphillips5ff17b12016-03-28 13:13:42 -07001560 sk_sp<SkImageFilter> pictureFilter(SkPictureImageFilter::Make(picture));
jbroman17a65202016-03-21 08:38:58 -07001561 SkImageFilter::CropRect cropRect(SkRect::MakeWH(100, 100));
robertphillips51a315e2016-03-31 09:05:49 -07001562 sk_sp<SkImageFilter> offsetFilter(SkOffsetImageFilter::Make(-100, 0, nullptr, &cropRect));
robertphillips491fb172016-03-30 12:32:58 -07001563 sk_sp<SkImageFilter> composedFilter(SkComposeImageFilter::Make(std::move(offsetFilter),
1564 std::move(pictureFilter)));
jbroman17a65202016-03-21 08:38:58 -07001565
robertphillips3e302272016-04-20 11:48:36 -07001566 sk_sp<SkSpecialImage> sourceImage(create_empty_special_image(context, 100));
brianosman2a75e5d2016-09-22 07:15:37 -07001567 SkImageFilter::OutputProperties noColorSpace(nullptr);
1568 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeWH(100, 100), nullptr, noColorSpace);
jbroman17a65202016-03-21 08:38:58 -07001569 SkIPoint offset;
1570 sk_sp<SkSpecialImage> result(composedFilter->filterImage(sourceImage.get(), ctx, &offset));
1571 REPORTER_ASSERT(reporter, offset.isZero());
1572 REPORTER_ASSERT(reporter, result);
1573 REPORTER_ASSERT(reporter, result->subset().size() == SkISize::Make(100, 100));
1574
1575 SkBitmap resultBM;
robertphillips64612512016-04-08 12:10:42 -07001576 REPORTER_ASSERT(reporter, result->getROPixels(&resultBM));
jbroman17a65202016-03-21 08:38:58 -07001577 SkAutoLockPixels lock(resultBM);
1578 REPORTER_ASSERT(reporter, resultBM.getColor(50, 50) == SK_ColorGREEN);
1579}
1580
1581DEF_TEST(ComposedImageFilterBounds, reporter) {
robertphillips3e302272016-04-20 11:48:36 -07001582 test_composed_imagefilter_bounds(reporter, nullptr);
jbroman17a65202016-03-21 08:38:58 -07001583}
1584
1585#if SK_SUPPORT_GPU
egdanielab527a52016-06-28 08:07:26 -07001586DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ComposedImageFilterBounds_Gpu, reporter, ctxInfo) {
bsalomon8b7451a2016-05-11 06:33:06 -07001587 test_composed_imagefilter_bounds(reporter, ctxInfo.grContext());
jbroman17a65202016-03-21 08:38:58 -07001588}
1589#endif
1590
robertphillips3e302272016-04-20 11:48:36 -07001591static void test_partial_crop_rect(skiatest::Reporter* reporter, GrContext* context) {
1592 sk_sp<SkSpecialImage> srcImg(create_empty_special_image(context, 100));
senorblanco24d2a7b2015-07-13 10:27:05 -07001593
1594 SkImageFilter::CropRect cropRect(SkRect::MakeXYWH(100, 0, 20, 30),
senorblancoed7cf272015-07-16 15:19:11 -07001595 SkImageFilter::CropRect::kHasWidth_CropEdge | SkImageFilter::CropRect::kHasHeight_CropEdge);
robertphillips5605b562016-04-05 11:50:42 -07001596 sk_sp<SkImageFilter> filter(make_grayscale(nullptr, &cropRect));
senorblanco24d2a7b2015-07-13 10:27:05 -07001597 SkIPoint offset;
brianosman2a75e5d2016-09-22 07:15:37 -07001598 SkImageFilter::OutputProperties noColorSpace(nullptr);
1599 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeWH(100, 100), nullptr, noColorSpace);
robertphillips4418dba2016-03-07 12:45:14 -08001600
robertphillips2302de92016-03-24 07:26:32 -07001601 sk_sp<SkSpecialImage> resultImg(filter->filterImage(srcImg.get(), ctx, &offset));
robertphillips4418dba2016-03-07 12:45:14 -08001602 REPORTER_ASSERT(reporter, resultImg);
1603
senorblanco24d2a7b2015-07-13 10:27:05 -07001604 REPORTER_ASSERT(reporter, offset.fX == 0);
1605 REPORTER_ASSERT(reporter, offset.fY == 0);
robertphillips4418dba2016-03-07 12:45:14 -08001606 REPORTER_ASSERT(reporter, resultImg->width() == 20);
1607 REPORTER_ASSERT(reporter, resultImg->height() == 30);
senorblanco24d2a7b2015-07-13 10:27:05 -07001608}
1609
senorblanco21a465d2016-04-11 11:58:39 -07001610DEF_TEST(ImageFilterPartialCropRect, reporter) {
robertphillips3e302272016-04-20 11:48:36 -07001611 test_partial_crop_rect(reporter, nullptr);
robertphillips4418dba2016-03-07 12:45:14 -08001612}
1613
1614#if SK_SUPPORT_GPU
bsalomon68d91342016-04-12 09:59:58 -07001615DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterPartialCropRect_Gpu, reporter, ctxInfo) {
bsalomon8b7451a2016-05-11 06:33:06 -07001616 test_partial_crop_rect(reporter, ctxInfo.grContext());
robertphillips4418dba2016-03-07 12:45:14 -08001617}
1618#endif
1619
senorblanco0abdf762015-08-20 11:10:41 -07001620DEF_TEST(ImageFilterCanComputeFastBounds, reporter) {
1621
robertphillips12fa47d2016-04-08 16:28:09 -07001622 {
1623 SkPoint3 location = SkPoint3::Make(0, 0, SK_Scalar1);
1624 sk_sp<SkImageFilter> lighting(SkLightingImageFilter::MakePointLitDiffuse(location,
1625 SK_ColorGREEN,
1626 0, 0, nullptr));
1627 REPORTER_ASSERT(reporter, !lighting->canComputeFastBounds());
1628 }
senorblanco0abdf762015-08-20 11:10:41 -07001629
senorblanco0abdf762015-08-20 11:10:41 -07001630 {
robertphillips6e7025a2016-04-04 04:31:25 -07001631 sk_sp<SkImageFilter> gray(make_grayscale(nullptr, nullptr));
1632 REPORTER_ASSERT(reporter, gray->canComputeFastBounds());
1633 {
1634 SkColorFilter* grayCF;
1635 REPORTER_ASSERT(reporter, gray->asAColorFilter(&grayCF));
1636 REPORTER_ASSERT(reporter, !grayCF->affectsTransparentBlack());
1637 grayCF->unref();
1638 }
1639 REPORTER_ASSERT(reporter, gray->canComputeFastBounds());
1640
1641 sk_sp<SkImageFilter> grayBlur(SkBlurImageFilter::Make(SK_Scalar1, SK_Scalar1,
1642 std::move(gray)));
1643 REPORTER_ASSERT(reporter, grayBlur->canComputeFastBounds());
senorblanco0abdf762015-08-20 11:10:41 -07001644 }
senorblanco0abdf762015-08-20 11:10:41 -07001645
robertphillips6e7025a2016-04-04 04:31:25 -07001646 {
1647 SkScalar greenMatrix[20] = { 0, 0, 0, 0, 0,
1648 0, 0, 0, 0, 1,
1649 0, 0, 0, 0, 0,
1650 0, 0, 0, 0, 1 };
1651 sk_sp<SkColorFilter> greenCF(SkColorFilter::MakeMatrixFilterRowMajor255(greenMatrix));
robertphillips5605b562016-04-05 11:50:42 -07001652 sk_sp<SkImageFilter> green(SkColorFilterImageFilter::Make(greenCF, nullptr));
senorblanco0abdf762015-08-20 11:10:41 -07001653
robertphillips6e7025a2016-04-04 04:31:25 -07001654 REPORTER_ASSERT(reporter, greenCF->affectsTransparentBlack());
1655 REPORTER_ASSERT(reporter, !green->canComputeFastBounds());
senorblanco0abdf762015-08-20 11:10:41 -07001656
robertphillips6e7025a2016-04-04 04:31:25 -07001657 sk_sp<SkImageFilter> greenBlur(SkBlurImageFilter::Make(SK_Scalar1, SK_Scalar1,
1658 std::move(green)));
1659 REPORTER_ASSERT(reporter, !greenBlur->canComputeFastBounds());
1660 }
senorblanco0abdf762015-08-20 11:10:41 -07001661
1662 uint8_t allOne[256], identity[256];
1663 for (int i = 0; i < 256; ++i) {
1664 identity[i] = i;
1665 allOne[i] = 255;
1666 }
1667
robertphillips5605b562016-04-05 11:50:42 -07001668 sk_sp<SkColorFilter> identityCF(SkTableColorFilter::MakeARGB(identity, identity,
1669 identity, allOne));
1670 sk_sp<SkImageFilter> identityFilter(SkColorFilterImageFilter::Make(identityCF, nullptr));
senorblanco0abdf762015-08-20 11:10:41 -07001671 REPORTER_ASSERT(reporter, !identityCF->affectsTransparentBlack());
1672 REPORTER_ASSERT(reporter, identityFilter->canComputeFastBounds());
1673
robertphillips5605b562016-04-05 11:50:42 -07001674 sk_sp<SkColorFilter> forceOpaqueCF(SkTableColorFilter::MakeARGB(allOne, identity,
1675 identity, identity));
1676 sk_sp<SkImageFilter> forceOpaque(SkColorFilterImageFilter::Make(forceOpaqueCF, nullptr));
senorblanco0abdf762015-08-20 11:10:41 -07001677 REPORTER_ASSERT(reporter, forceOpaqueCF->affectsTransparentBlack());
1678 REPORTER_ASSERT(reporter, !forceOpaque->canComputeFastBounds());
1679}
1680
fmalitacd56f812015-09-14 13:31:18 -07001681// Verify that SkImageSource survives serialization
1682DEF_TEST(ImageFilterImageSourceSerialization, reporter) {
reede8f30622016-03-23 18:59:25 -07001683 auto surface(SkSurface::MakeRasterN32Premul(10, 10));
fmalitacd56f812015-09-14 13:31:18 -07001684 surface->getCanvas()->clear(SK_ColorGREEN);
reed9ce9d672016-03-17 10:51:11 -07001685 sk_sp<SkImage> image(surface->makeImageSnapshot());
robertphillips549c8992016-04-01 09:28:51 -07001686 sk_sp<SkImageFilter> filter(SkImageSource::Make(std::move(image)));
fmalitacd56f812015-09-14 13:31:18 -07001687
robertphillips549c8992016-04-01 09:28:51 -07001688 sk_sp<SkData> data(SkValidatingSerializeFlattenable(filter.get()));
1689 sk_sp<SkFlattenable> flattenable(SkValidatingDeserializeFlattenable(
mtklein3b375452016-04-04 14:57:19 -07001690 data->data(), data->size(), SkImageFilter::GetFlattenableType()));
fmalitacd56f812015-09-14 13:31:18 -07001691 SkImageFilter* unflattenedFilter = static_cast<SkImageFilter*>(flattenable.get());
1692 REPORTER_ASSERT(reporter, unflattenedFilter);
1693
1694 SkBitmap bm;
1695 bm.allocN32Pixels(10, 10);
fmalita23cb88c2015-09-15 06:56:23 -07001696 bm.eraseColor(SK_ColorBLUE);
fmalitacd56f812015-09-14 13:31:18 -07001697 SkPaint paint;
1698 paint.setColor(SK_ColorRED);
1699 paint.setImageFilter(unflattenedFilter);
1700
1701 SkCanvas canvas(bm);
1702 canvas.drawRect(SkRect::MakeWH(10, 10), paint);
1703 REPORTER_ASSERT(reporter, *bm.getAddr32(0, 0) == SkPreMultiplyColor(SK_ColorGREEN));
1704}
1705
bsalomon45eefcf2016-01-05 08:39:28 -08001706static void test_large_blur_input(skiatest::Reporter* reporter, SkCanvas* canvas) {
1707 SkBitmap largeBmp;
1708 int largeW = 5000;
1709 int largeH = 5000;
1710#if SK_SUPPORT_GPU
1711 // If we're GPU-backed make the bitmap too large to be converted into a texture.
1712 if (GrContext* ctx = canvas->getGrContext()) {
1713 largeW = ctx->caps()->maxTextureSize() + 1;
1714 }
1715#endif
1716
1717 largeBmp.allocN32Pixels(largeW, largeH);
mtklein2afbe232016-02-07 12:23:10 -08001718 largeBmp.eraseColor(0);
bsalomon45eefcf2016-01-05 08:39:28 -08001719 if (!largeBmp.getPixels()) {
1720 ERRORF(reporter, "Failed to allocate large bmp.");
1721 return;
1722 }
1723
reed9ce9d672016-03-17 10:51:11 -07001724 sk_sp<SkImage> largeImage(SkImage::MakeFromBitmap(largeBmp));
bsalomon45eefcf2016-01-05 08:39:28 -08001725 if (!largeImage) {
1726 ERRORF(reporter, "Failed to create large image.");
1727 return;
1728 }
1729
robertphillips549c8992016-04-01 09:28:51 -07001730 sk_sp<SkImageFilter> largeSource(SkImageSource::Make(std::move(largeImage)));
bsalomon45eefcf2016-01-05 08:39:28 -08001731 if (!largeSource) {
1732 ERRORF(reporter, "Failed to create large SkImageSource.");
1733 return;
1734 }
1735
robertphillips6e7025a2016-04-04 04:31:25 -07001736 sk_sp<SkImageFilter> blur(SkBlurImageFilter::Make(10.f, 10.f, std::move(largeSource)));
bsalomon45eefcf2016-01-05 08:39:28 -08001737 if (!blur) {
1738 ERRORF(reporter, "Failed to create SkBlurImageFilter.");
1739 return;
1740 }
1741
1742 SkPaint paint;
robertphillips549c8992016-04-01 09:28:51 -07001743 paint.setImageFilter(std::move(blur));
bsalomon45eefcf2016-01-05 08:39:28 -08001744
1745 // This should not crash (http://crbug.com/570479).
1746 canvas->drawRect(SkRect::MakeIWH(largeW, largeH), paint);
1747}
1748
senorblanco21a465d2016-04-11 11:58:39 -07001749DEF_TEST(ImageFilterBlurLargeImage, reporter) {
reede8f30622016-03-23 18:59:25 -07001750 auto surface(SkSurface::MakeRaster(SkImageInfo::MakeN32Premul(100, 100)));
bsalomon45eefcf2016-01-05 08:39:28 -08001751 test_large_blur_input(reporter, surface->getCanvas());
1752}
1753
senorblanco5878dbd2016-05-19 14:50:29 -07001754static void test_make_with_filter(skiatest::Reporter* reporter, GrContext* context) {
1755 sk_sp<SkSurface> surface(create_surface(context, 100, 100));
1756 surface->getCanvas()->clear(SK_ColorRED);
1757 SkPaint bluePaint;
1758 bluePaint.setColor(SK_ColorBLUE);
1759 SkIRect subset = SkIRect::MakeXYWH(25, 20, 50, 50);
1760 surface->getCanvas()->drawRect(SkRect::Make(subset), bluePaint);
1761 sk_sp<SkImage> sourceImage = surface->makeImageSnapshot();
1762
1763 sk_sp<SkImageFilter> filter = make_grayscale(nullptr, nullptr);
1764 SkIRect clipBounds = SkIRect::MakeXYWH(30, 35, 100, 100);
1765 SkIRect outSubset;
1766 SkIPoint offset;
1767 sk_sp<SkImage> result;
1768
1769 result = sourceImage->makeWithFilter(nullptr, subset, clipBounds, &outSubset, &offset);
1770 REPORTER_ASSERT(reporter, !result);
1771
1772 result = sourceImage->makeWithFilter(filter.get(), subset, clipBounds, nullptr, &offset);
1773 REPORTER_ASSERT(reporter, !result);
1774
1775 result = sourceImage->makeWithFilter(filter.get(), subset, clipBounds, &outSubset, nullptr);
1776 REPORTER_ASSERT(reporter, !result);
1777
1778 SkIRect bigSubset = SkIRect::MakeXYWH(-10000, -10000, 20000, 20000);
1779 result = sourceImage->makeWithFilter(filter.get(), bigSubset, clipBounds, &outSubset, &offset);
1780 REPORTER_ASSERT(reporter, !result);
1781
1782 SkIRect empty = SkIRect::MakeEmpty();
1783 result = sourceImage->makeWithFilter(filter.get(), empty, clipBounds, &outSubset, &offset);
1784 REPORTER_ASSERT(reporter, !result);
1785
1786 result = sourceImage->makeWithFilter(filter.get(), subset, empty, &outSubset, &offset);
1787 REPORTER_ASSERT(reporter, !result);
1788
1789 SkIRect leftField = SkIRect::MakeXYWH(-1000, 0, 100, 100);
1790 result = sourceImage->makeWithFilter(filter.get(), subset, leftField, &outSubset, &offset);
1791 REPORTER_ASSERT(reporter, !result);
1792
1793 result = sourceImage->makeWithFilter(filter.get(), subset, clipBounds, &outSubset, &offset);
1794
1795 REPORTER_ASSERT(reporter, result);
1796 REPORTER_ASSERT(reporter, result->bounds().contains(outSubset));
1797 SkIRect destRect = SkIRect::MakeXYWH(offset.x(), offset.y(),
1798 outSubset.width(), outSubset.height());
1799 REPORTER_ASSERT(reporter, clipBounds.contains(destRect));
1800}
1801
1802DEF_TEST(ImageFilterMakeWithFilter, reporter) {
1803 test_make_with_filter(reporter, nullptr);
1804}
1805
1806#if SK_SUPPORT_GPU
1807DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterMakeWithFilter_Gpu, reporter, ctxInfo) {
1808 test_make_with_filter(reporter, ctxInfo.grContext());
1809}
1810#endif
1811
senorblanco@chromium.org58d14662014-02-03 22:36:39 +00001812#if SK_SUPPORT_GPU
reed4a8126e2014-09-22 07:29:03 -07001813
bsalomon68d91342016-04-12 09:59:58 -07001814DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterHugeBlur_Gpu, reporter, ctxInfo) {
robertphillipsefbffed2015-06-22 12:06:08 -07001815
bsalomon8b7451a2016-05-11 06:33:06 -07001816 sk_sp<SkSurface> surf(SkSurface::MakeRenderTarget(ctxInfo.grContext(),
robertphillips3e302272016-04-20 11:48:36 -07001817 SkBudgeted::kNo,
1818 SkImageInfo::MakeN32Premul(100, 100)));
robertphillips9a53fd72015-06-22 09:46:59 -07001819
robertphillips3e302272016-04-20 11:48:36 -07001820
1821 SkCanvas* canvas = surf->getCanvas();
1822
1823 test_huge_blur(canvas, reporter);
senorblanco@chromium.org09843fd2014-03-24 20:50:59 +00001824}
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001825
egdanielab527a52016-06-28 08:07:26 -07001826DEF_GPUTEST_FOR_RENDERING_CONTEXTS(XfermodeImageFilterCroppedInput_Gpu, reporter, ctxInfo) {
robertphillipsefbffed2015-06-22 12:06:08 -07001827
bsalomon8b7451a2016-05-11 06:33:06 -07001828 sk_sp<SkSurface> surf(SkSurface::MakeRenderTarget(ctxInfo.grContext(),
robertphillips3e302272016-04-20 11:48:36 -07001829 SkBudgeted::kNo,
1830 SkImageInfo::MakeN32Premul(1, 1)));
robertphillips9a53fd72015-06-22 09:46:59 -07001831
robertphillips3e302272016-04-20 11:48:36 -07001832
1833 SkCanvas* canvas = surf->getCanvas();
1834
1835 test_xfermode_cropped_input(canvas, reporter);
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001836}
senorblanco32673b92014-09-09 09:15:04 -07001837
egdanielab527a52016-06-28 08:07:26 -07001838DEF_GPUTEST_FOR_ALL_CONTEXTS(ImageFilterBlurLargeImage_Gpu, reporter, ctxInfo) {
bsalomon8b7451a2016-05-11 06:33:06 -07001839 auto surface(SkSurface::MakeRenderTarget(ctxInfo.grContext(), SkBudgeted::kYes,
reede8f30622016-03-23 18:59:25 -07001840 SkImageInfo::MakeN32Premul(100, 100)));
bsalomon45eefcf2016-01-05 08:39:28 -08001841 test_large_blur_input(reporter, surface->getCanvas());
1842}
senorblanco@chromium.org58d14662014-02-03 22:36:39 +00001843#endif
reedbb34a8a2016-04-23 15:19:07 -07001844
1845/*
1846 * Test that colorfilterimagefilter does not require its CTM to be decomposed when it has more
1847 * than just scale/translate, but that other filters do.
1848 */
reed96a04f32016-04-25 09:25:15 -07001849DEF_TEST(ImageFilterComplexCTM, reporter) {
reedbb34a8a2016-04-23 15:19:07 -07001850 // just need a colorfilter to exercise the corresponding imagefilter
Mike Reed7d954ad2016-10-28 15:42:34 -04001851 sk_sp<SkColorFilter> cf = SkColorFilter::MakeModeFilter(SK_ColorRED, SkBlendMode::kSrcATop);
reed96a04f32016-04-25 09:25:15 -07001852 sk_sp<SkImageFilter> cfif = SkColorFilterImageFilter::Make(cf, nullptr); // can handle
1853 sk_sp<SkImageFilter> blif = SkBlurImageFilter::Make(3, 3, nullptr); // cannot handle
reedbb34a8a2016-04-23 15:19:07 -07001854
1855 struct {
1856 sk_sp<SkImageFilter> fFilter;
1857 bool fExpectCanHandle;
1858 } recs[] = {
1859 { cfif, true },
1860 { SkColorFilterImageFilter::Make(cf, cfif), true },
Mike Reed7d954ad2016-10-28 15:42:34 -04001861 { SkMergeImageFilter::Make(cfif, cfif, SkBlendMode::kSrcOver), true },
reed96a04f32016-04-25 09:25:15 -07001862 { SkComposeImageFilter::Make(cfif, cfif), true },
1863
reedbb34a8a2016-04-23 15:19:07 -07001864 { blif, false },
reed96a04f32016-04-25 09:25:15 -07001865 { SkBlurImageFilter::Make(3, 3, cfif), false },
reedbb34a8a2016-04-23 15:19:07 -07001866 { SkColorFilterImageFilter::Make(cf, blif), false },
Mike Reed7d954ad2016-10-28 15:42:34 -04001867 { SkMergeImageFilter::Make(cfif, blif, SkBlendMode::kSrcOver), false },
reed96a04f32016-04-25 09:25:15 -07001868 { SkComposeImageFilter::Make(blif, cfif), false },
reedbb34a8a2016-04-23 15:19:07 -07001869 };
1870
1871 for (const auto& rec : recs) {
reed96a04f32016-04-25 09:25:15 -07001872 const bool canHandle = rec.fFilter->canHandleComplexCTM();
reedbb34a8a2016-04-23 15:19:07 -07001873 REPORTER_ASSERT(reporter, canHandle == rec.fExpectCanHandle);
1874 }
1875}