blob: f46519d94eaa23759247b870724200a5eaceac16 [file] [log] [blame]
senorblanco@chromium.org194d7752013-07-24 22:19:24 +00001/*
2 * Copyright 2013 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
commit-bot@chromium.org4b681bc2013-09-13 12:40:02 +00008#include "SkBitmap.h"
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00009#include "SkBlurImageFilter.h"
tfarina@chromium.org8f6884a2014-01-24 20:56:26 +000010#include "SkCanvas.h"
11#include "SkColorFilterImageFilter.h"
12#include "SkColorMatrixFilter.h"
ajuma5788faa2015-02-13 09:05:47 -080013#include "SkComposeImageFilter.h"
senorblanco@chromium.org6776b822014-01-03 21:48:22 +000014#include "SkDisplacementMapEffect.h"
15#include "SkDropShadowImageFilter.h"
senorblanco@chromium.org97f5fc62014-05-30 20:50:56 +000016#include "SkFlattenableSerialization.h"
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +000017#include "SkGradientShader.h"
fmalita5598b632015-09-15 11:26:13 -070018#include "SkImage.h"
fmalitacd56f812015-09-14 13:31:18 -070019#include "SkImageSource.h"
commit-bot@chromium.org4b681bc2013-09-13 12:40:02 +000020#include "SkLightingImageFilter.h"
tfarina@chromium.org8f6884a2014-01-24 20:56:26 +000021#include "SkMatrixConvolutionImageFilter.h"
senorblanco@chromium.org6776b822014-01-03 21:48:22 +000022#include "SkMergeImageFilter.h"
23#include "SkMorphologyImageFilter.h"
senorblanco@chromium.org6776b822014-01-03 21:48:22 +000024#include "SkOffsetImageFilter.h"
ajuma77b6ba32016-01-08 14:58:35 -080025#include "SkPaintImageFilter.h"
senorblanco8f3937d2014-10-29 12:36:32 -070026#include "SkPerlinNoiseShader.h"
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +000027#include "SkPicture.h"
senorblanco@chromium.org910702b2014-05-30 20:36:15 +000028#include "SkPictureImageFilter.h"
robertphillips@google.com770963f2014-04-18 18:04:41 +000029#include "SkPictureRecorder.h"
robertphillips3d32d762015-07-13 13:16:44 -070030#include "SkPoint3.h"
halcanary97d2c0a2014-08-19 06:27:53 -070031#include "SkReadBuffer.h"
tfarina@chromium.org8f6884a2014-01-24 20:56:26 +000032#include "SkRect.h"
robertphillips4418dba2016-03-07 12:45:14 -080033#include "SkSpecialImage.h"
34#include "SkSpecialSurface.h"
fmalitacd56f812015-09-14 13:31:18 -070035#include "SkSurface.h"
senorblanco0abdf762015-08-20 11:10:41 -070036#include "SkTableColorFilter.h"
senorblanco@chromium.org6776b822014-01-03 21:48:22 +000037#include "SkTileImageFilter.h"
38#include "SkXfermodeImageFilter.h"
tfarina@chromium.org8f6884a2014-01-24 20:56:26 +000039#include "Test.h"
senorblanco@chromium.org194d7752013-07-24 22:19:24 +000040
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +000041#if SK_SUPPORT_GPU
kkinnunen15302832015-12-01 04:35:26 -080042#include "GrContext.h"
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +000043#endif
44
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +000045static const int kBitmapSize = 4;
commit-bot@chromium.org4b681bc2013-09-13 12:40:02 +000046
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +000047namespace {
48
49class MatrixTestImageFilter : public SkImageFilter {
50public:
robertphillips43c2ad42016-04-04 05:05:11 -070051 static sk_sp<SkImageFilter> Make(skiatest::Reporter* reporter,
52 const SkMatrix& expectedMatrix) {
53 return sk_sp<SkImageFilter>(new MatrixTestImageFilter(reporter, expectedMatrix));
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +000054 }
55
robertphillipsf3f5bad2014-12-19 13:49:15 -080056 SK_TO_STRING_OVERRIDE()
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +000057 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(MatrixTestImageFilter)
58
59protected:
robertphillips4ba94e22016-04-04 12:07:47 -070060 sk_sp<SkSpecialImage> onFilterImage(SkSpecialImage* source, const Context& ctx,
61 SkIPoint* offset) const override {
robertphillips43c2ad42016-04-04 05:05:11 -070062 REPORTER_ASSERT(fReporter, ctx.ctm() == fExpectedMatrix);
robertphillips4ba94e22016-04-04 12:07:47 -070063 offset->fX = offset->fY = 0;
64 return sk_ref_sp<SkSpecialImage>(source);
robertphillips43c2ad42016-04-04 05:05:11 -070065 }
66
mtklein36352bf2015-03-25 18:17:31 -070067 void flatten(SkWriteBuffer& buffer) const override {
brianosman18f13f32016-05-02 07:51:08 -070068 SkDEBUGFAIL("Should never get here");
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +000069 }
70
71private:
robertphillips43c2ad42016-04-04 05:05:11 -070072 MatrixTestImageFilter(skiatest::Reporter* reporter, const SkMatrix& expectedMatrix)
73 : INHERITED(nullptr, 0, nullptr)
74 , fReporter(reporter)
75 , fExpectedMatrix(expectedMatrix) {
76 }
77
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +000078 skiatest::Reporter* fReporter;
79 SkMatrix fExpectedMatrix;
mtklein3f3b3d02014-12-01 11:47:08 -080080
reed9fa60da2014-08-21 07:59:51 -070081 typedef SkImageFilter INHERITED;
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +000082};
83
senorblanco6a93fa12016-04-05 04:43:45 -070084class FailImageFilter : public SkImageFilter {
85public:
robertphillips6b134732016-04-15 09:58:37 -070086 FailImageFilter() : SkImageFilter(nullptr, 0, nullptr) { }
senorblanco6a93fa12016-04-05 04:43:45 -070087
88 sk_sp<SkSpecialImage> onFilterImage(SkSpecialImage* source,
89 const Context& ctx,
90 SkIPoint* offset) const override {
91 return nullptr;
92 }
93
94 SK_TO_STRING_OVERRIDE()
95 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(FailImageFilter)
96
97private:
98 typedef SkImageFilter INHERITED;
99};
100
101sk_sp<SkFlattenable> FailImageFilter::CreateProc(SkReadBuffer& buffer) {
102 SK_IMAGEFILTER_UNFLATTEN_COMMON(common, 0);
103 return sk_sp<SkFlattenable>(new FailImageFilter());
104}
105
106#ifndef SK_IGNORE_TO_STRING
107void FailImageFilter::toString(SkString* str) const {
108 str->appendf("FailImageFilter: (");
109 str->append(")");
110}
111#endif
112
senorblanco297f7ce2016-03-23 13:44:26 -0700113void draw_gradient_circle(SkCanvas* canvas, int width, int height) {
114 SkScalar x = SkIntToScalar(width / 2);
115 SkScalar y = SkIntToScalar(height / 2);
116 SkScalar radius = SkMinScalar(x, y) * 0.8f;
117 canvas->clear(0x00000000);
118 SkColor colors[2];
119 colors[0] = SK_ColorWHITE;
120 colors[1] = SK_ColorBLACK;
121 sk_sp<SkShader> shader(
122 SkGradientShader::MakeRadial(SkPoint::Make(x, y), radius, colors, nullptr, 2,
123 SkShader::kClamp_TileMode)
124 );
125 SkPaint paint;
126 paint.setShader(shader);
127 canvas->drawCircle(x, y, radius, paint);
128}
129
130SkBitmap make_gradient_circle(int width, int height) {
131 SkBitmap bitmap;
132 bitmap.allocN32Pixels(width, height);
133 SkCanvas canvas(bitmap);
134 draw_gradient_circle(&canvas, width, height);
135 return bitmap;
136}
137
138class FilterList {
139public:
robertphillipsfc11b0a2016-04-05 09:09:36 -0700140 FilterList(sk_sp<SkImageFilter> input, const SkImageFilter::CropRect* cropRect = nullptr) {
senorblanco297f7ce2016-03-23 13:44:26 -0700141 SkPoint3 location = SkPoint3::Make(0, 0, SK_Scalar1);
senorblanco297f7ce2016-03-23 13:44:26 -0700142 const SkScalar five = SkIntToScalar(5);
143
robertphillips6e7025a2016-04-04 04:31:25 -0700144 {
145 sk_sp<SkColorFilter> cf(SkColorFilter::MakeModeFilter(SK_ColorRED,
146 SkXfermode::kSrcIn_Mode));
senorblanco297f7ce2016-03-23 13:44:26 -0700147
robertphillips6e7025a2016-04-04 04:31:25 -0700148 this->addFilter("color filter",
robertphillips12fa47d2016-04-08 16:28:09 -0700149 SkColorFilterImageFilter::Make(std::move(cf), input, cropRect));
robertphillips6e7025a2016-04-04 04:31:25 -0700150 }
senorblanco297f7ce2016-03-23 13:44:26 -0700151
robertphillips6e7025a2016-04-04 04:31:25 -0700152 {
153 sk_sp<SkImage> gradientImage(SkImage::MakeFromBitmap(make_gradient_circle(64, 64)));
154 sk_sp<SkImageFilter> gradientSource(SkImageSource::Make(std::move(gradientImage)));
senorblanco297f7ce2016-03-23 13:44:26 -0700155
robertphillips12fa47d2016-04-08 16:28:09 -0700156 this->addFilter("displacement map",
robertphillipsbfe11fc2016-04-15 07:17:36 -0700157 SkDisplacementMapEffect::Make(SkDisplacementMapEffect::kR_ChannelSelectorType,
158 SkDisplacementMapEffect::kB_ChannelSelectorType,
159 20.0f,
160 std::move(gradientSource), input, cropRect));
robertphillips6e7025a2016-04-04 04:31:25 -0700161 }
senorblanco297f7ce2016-03-23 13:44:26 -0700162
robertphillips6e7025a2016-04-04 04:31:25 -0700163 this->addFilter("blur", SkBlurImageFilter::Make(SK_Scalar1,
164 SK_Scalar1,
robertphillipsfc11b0a2016-04-05 09:09:36 -0700165 input,
robertphillips12fa47d2016-04-08 16:28:09 -0700166 cropRect));
robertphillipsc4169122016-04-06 08:40:59 -0700167 this->addFilter("drop shadow", SkDropShadowImageFilter::Make(
senorblanco297f7ce2016-03-23 13:44:26 -0700168 SK_Scalar1, SK_Scalar1, SK_Scalar1, SK_Scalar1, SK_ColorGREEN,
robertphillipsfc11b0a2016-04-05 09:09:36 -0700169 SkDropShadowImageFilter::kDrawShadowAndForeground_ShadowMode,
robertphillips12fa47d2016-04-08 16:28:09 -0700170 input, cropRect));
171 this->addFilter("diffuse lighting",
172 SkLightingImageFilter::MakePointLitDiffuse(location, SK_ColorGREEN, 0, 0,
173 input, cropRect));
senorblanco297f7ce2016-03-23 13:44:26 -0700174 this->addFilter("specular lighting",
robertphillips12fa47d2016-04-08 16:28:09 -0700175 SkLightingImageFilter::MakePointLitSpecular(location, SK_ColorGREEN, 0, 0, 0,
176 input, cropRect));
177 {
178 SkScalar kernel[9] = {
179 SkIntToScalar(1), SkIntToScalar(1), SkIntToScalar(1),
180 SkIntToScalar(1), SkIntToScalar(-7), SkIntToScalar(1),
181 SkIntToScalar(1), SkIntToScalar(1), SkIntToScalar(1),
182 };
183 const SkISize kernelSize = SkISize::Make(3, 3);
184 const SkScalar gain = SK_Scalar1, bias = 0;
185
186 this->addFilter("matrix convolution",
robertphillipsef6a47b2016-04-08 08:01:20 -0700187 SkMatrixConvolutionImageFilter::Make(
senorblanco297f7ce2016-03-23 13:44:26 -0700188 kernelSize, kernel, gain, bias, SkIPoint::Make(1, 1),
robertphillipsfc11b0a2016-04-05 09:09:36 -0700189 SkMatrixConvolutionImageFilter::kRepeat_TileMode, false,
robertphillips12fa47d2016-04-08 16:28:09 -0700190 input, cropRect));
191 }
192
robertphillipsfc11b0a2016-04-05 09:09:36 -0700193 this->addFilter("merge", SkMergeImageFilter::Make(input, input,
robertphillips2238c9d2016-03-30 13:34:16 -0700194 SkXfermode::kSrcOver_Mode,
robertphillips12fa47d2016-04-08 16:28:09 -0700195 cropRect));
196
robertphillips6e7025a2016-04-04 04:31:25 -0700197 {
198 SkPaint greenColorShaderPaint;
199 greenColorShaderPaint.setShader(SkShader::MakeColorShader(SK_ColorGREEN));
200
201 SkImageFilter::CropRect leftSideCropRect(SkRect::MakeXYWH(0, 0, 32, 64));
202 sk_sp<SkImageFilter> paintFilterLeft(SkPaintImageFilter::Make(greenColorShaderPaint,
203 &leftSideCropRect));
204 SkImageFilter::CropRect rightSideCropRect(SkRect::MakeXYWH(32, 0, 32, 64));
205 sk_sp<SkImageFilter> paintFilterRight(SkPaintImageFilter::Make(greenColorShaderPaint,
206 &rightSideCropRect));
207
208
209 this->addFilter("merge with disjoint inputs", SkMergeImageFilter::Make(
robertphillips2238c9d2016-03-30 13:34:16 -0700210 std::move(paintFilterLeft), std::move(paintFilterRight),
robertphillips12fa47d2016-04-08 16:28:09 -0700211 SkXfermode::kSrcOver_Mode, cropRect));
robertphillips6e7025a2016-04-04 04:31:25 -0700212 }
213
senorblanco297f7ce2016-03-23 13:44:26 -0700214 this->addFilter("offset",
robertphillipsfc11b0a2016-04-05 09:09:36 -0700215 SkOffsetImageFilter::Make(SK_Scalar1, SK_Scalar1, input,
robertphillips12fa47d2016-04-08 16:28:09 -0700216 cropRect));
217 this->addFilter("dilate", SkDilateImageFilter::Make(3, 2, input, cropRect));
218 this->addFilter("erode", SkErodeImageFilter::Make(2, 3, input, cropRect));
robertphillips534c2702016-04-15 07:57:40 -0700219 this->addFilter("tile", SkTileImageFilter::Make(
220 SkRect::MakeXYWH(0, 0, 50, 50),
221 cropRect ? cropRect->rect() : SkRect::MakeXYWH(0, 0, 100, 100),
222 input));
robertphillips6e7025a2016-04-04 04:31:25 -0700223
robertphillips12fa47d2016-04-08 16:28:09 -0700224 if (!cropRect) {
225 SkMatrix matrix;
226
227 matrix.setTranslate(SK_Scalar1, SK_Scalar1);
228 matrix.postRotate(SkIntToScalar(45), SK_Scalar1, SK_Scalar1);
229
230 this->addFilter("matrix",
231 SkImageFilter::MakeMatrixFilter(matrix, kLow_SkFilterQuality, input));
232 }
robertphillips6e7025a2016-04-04 04:31:25 -0700233 {
robertphillipsfc11b0a2016-04-05 09:09:36 -0700234 sk_sp<SkImageFilter> blur(SkBlurImageFilter::Make(five, five, input));
robertphillips6e7025a2016-04-04 04:31:25 -0700235
236 this->addFilter("blur and offset", SkOffsetImageFilter::Make(five, five,
237 std::move(blur),
robertphillips12fa47d2016-04-08 16:28:09 -0700238 cropRect));
robertphillips6e7025a2016-04-04 04:31:25 -0700239 }
240 {
241 SkRTreeFactory factory;
242 SkPictureRecorder recorder;
243 SkCanvas* recordingCanvas = recorder.beginRecording(64, 64, &factory, 0);
244
245 SkPaint greenPaint;
246 greenPaint.setColor(SK_ColorGREEN);
247 recordingCanvas->drawRect(SkRect::Make(SkIRect::MakeXYWH(10, 10, 30, 20)), greenPaint);
248 sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture());
249 sk_sp<SkImageFilter> pictureFilter(SkPictureImageFilter::Make(std::move(picture)));
250
251 this->addFilter("picture and blur", SkBlurImageFilter::Make(five, five,
252 std::move(pictureFilter),
robertphillips12fa47d2016-04-08 16:28:09 -0700253 cropRect));
robertphillips6e7025a2016-04-04 04:31:25 -0700254 }
255 {
256 SkPaint paint;
257 paint.setShader(SkPerlinNoiseShader::MakeTurbulence(SK_Scalar1, SK_Scalar1, 1, 0));
258 sk_sp<SkImageFilter> paintFilter(SkPaintImageFilter::Make(paint));
259
260 this->addFilter("paint and blur", SkBlurImageFilter::Make(five, five,
261 std::move(paintFilter),
robertphillips12fa47d2016-04-08 16:28:09 -0700262 cropRect));
robertphillips6e7025a2016-04-04 04:31:25 -0700263 }
reedcfb6bdf2016-03-29 11:32:50 -0700264 this->addFilter("xfermode", SkXfermodeImageFilter::Make(
robertphillips12fa47d2016-04-08 16:28:09 -0700265 SkXfermode::Make(SkXfermode::kSrc_Mode), input, input, cropRect));
senorblanco297f7ce2016-03-23 13:44:26 -0700266 }
267 int count() const { return fFilters.count(); }
268 SkImageFilter* getFilter(int index) const { return fFilters[index].fFilter.get(); }
269 const char* getName(int index) const { return fFilters[index].fName; }
270private:
271 struct Filter {
robertphillips12fa47d2016-04-08 16:28:09 -0700272 Filter() : fName(nullptr) {}
273 Filter(const char* name, sk_sp<SkImageFilter> filter)
274 : fName(name)
275 , fFilter(std::move(filter)) {
276 }
senorblanco297f7ce2016-03-23 13:44:26 -0700277 const char* fName;
278 sk_sp<SkImageFilter> fFilter;
279 };
robertphillips12fa47d2016-04-08 16:28:09 -0700280 void addFilter(const char* name, sk_sp<SkImageFilter> filter) {
281 fFilters.push_back(Filter(name, std::move(filter)));
senorblanco297f7ce2016-03-23 13:44:26 -0700282 }
283
284 SkTArray<Filter> fFilters;
285};
286
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +0000287}
288
reed60c9b582016-04-03 09:11:13 -0700289sk_sp<SkFlattenable> MatrixTestImageFilter::CreateProc(SkReadBuffer& buffer) {
brianosman18f13f32016-05-02 07:51:08 -0700290 SkDEBUGFAIL("Should never get here");
291 return nullptr;
reed9fa60da2014-08-21 07:59:51 -0700292}
293
robertphillipsf3f5bad2014-12-19 13:49:15 -0800294#ifndef SK_IGNORE_TO_STRING
295void MatrixTestImageFilter::toString(SkString* str) const {
296 str->appendf("MatrixTestImageFilter: (");
297 str->append(")");
298}
299#endif
300
reed9ce9d672016-03-17 10:51:11 -0700301static sk_sp<SkImage> make_small_image() {
reede8f30622016-03-23 18:59:25 -0700302 auto surface(SkSurface::MakeRasterN32Premul(kBitmapSize, kBitmapSize));
fmalita5598b632015-09-15 11:26:13 -0700303 SkCanvas* canvas = surface->getCanvas();
304 canvas->clear(0x00000000);
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000305 SkPaint darkPaint;
306 darkPaint.setColor(0xFF804020);
307 SkPaint lightPaint;
308 lightPaint.setColor(0xFF244484);
309 const int i = kBitmapSize / 4;
310 for (int y = 0; y < kBitmapSize; y += i) {
311 for (int x = 0; x < kBitmapSize; x += i) {
fmalita5598b632015-09-15 11:26:13 -0700312 canvas->save();
313 canvas->translate(SkIntToScalar(x), SkIntToScalar(y));
314 canvas->drawRect(SkRect::MakeXYWH(0, 0,
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000315 SkIntToScalar(i),
316 SkIntToScalar(i)), darkPaint);
fmalita5598b632015-09-15 11:26:13 -0700317 canvas->drawRect(SkRect::MakeXYWH(SkIntToScalar(i),
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000318 0,
319 SkIntToScalar(i),
320 SkIntToScalar(i)), lightPaint);
fmalita5598b632015-09-15 11:26:13 -0700321 canvas->drawRect(SkRect::MakeXYWH(0,
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000322 SkIntToScalar(i),
323 SkIntToScalar(i),
324 SkIntToScalar(i)), lightPaint);
fmalita5598b632015-09-15 11:26:13 -0700325 canvas->drawRect(SkRect::MakeXYWH(SkIntToScalar(i),
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000326 SkIntToScalar(i),
327 SkIntToScalar(i),
328 SkIntToScalar(i)), darkPaint);
fmalita5598b632015-09-15 11:26:13 -0700329 canvas->restore();
commit-bot@chromium.org4b681bc2013-09-13 12:40:02 +0000330 }
331 }
fmalita5598b632015-09-15 11:26:13 -0700332
reed9ce9d672016-03-17 10:51:11 -0700333 return surface->makeImageSnapshot();
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000334}
senorblanco@chromium.org194d7752013-07-24 22:19:24 +0000335
robertphillips5605b562016-04-05 11:50:42 -0700336static sk_sp<SkImageFilter> make_scale(float amount, sk_sp<SkImageFilter> input) {
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000337 SkScalar s = amount;
338 SkScalar matrix[20] = { s, 0, 0, 0, 0,
339 0, s, 0, 0, 0,
340 0, 0, s, 0, 0,
341 0, 0, 0, s, 0 };
robertphillips5605b562016-04-05 11:50:42 -0700342 sk_sp<SkColorFilter> filter(SkColorFilter::MakeMatrixFilterRowMajor255(matrix));
343 return SkColorFilterImageFilter::Make(std::move(filter), std::move(input));
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000344}
345
robertphillips5605b562016-04-05 11:50:42 -0700346static sk_sp<SkImageFilter> make_grayscale(sk_sp<SkImageFilter> input,
347 const SkImageFilter::CropRect* cropRect) {
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000348 SkScalar matrix[20];
349 memset(matrix, 0, 20 * sizeof(SkScalar));
350 matrix[0] = matrix[5] = matrix[10] = 0.2126f;
351 matrix[1] = matrix[6] = matrix[11] = 0.7152f;
352 matrix[2] = matrix[7] = matrix[12] = 0.0722f;
353 matrix[18] = 1.0f;
robertphillips5605b562016-04-05 11:50:42 -0700354 sk_sp<SkColorFilter> filter(SkColorFilter::MakeMatrixFilterRowMajor255(matrix));
355 return SkColorFilterImageFilter::Make(std::move(filter), std::move(input), cropRect);
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000356}
357
robertphillips5605b562016-04-05 11:50:42 -0700358static sk_sp<SkImageFilter> make_blue(sk_sp<SkImageFilter> input,
359 const SkImageFilter::CropRect* cropRect) {
360 sk_sp<SkColorFilter> filter(SkColorFilter::MakeModeFilter(SK_ColorBLUE,
361 SkXfermode::kSrcIn_Mode));
362 return SkColorFilterImageFilter::Make(std::move(filter), std::move(input), cropRect);
reedcedc36f2015-03-08 04:42:52 -0700363}
364
robertphillips3e302272016-04-20 11:48:36 -0700365static sk_sp<SkSpecialSurface> create_empty_special_surface(GrContext* context, int widthHeight) {
robertphillipsc91fd342016-04-25 12:32:54 -0700366#if SK_SUPPORT_GPU
robertphillips4418dba2016-03-07 12:45:14 -0800367 if (context) {
robertphillips4df16562016-04-28 15:09:34 -0700368 return SkSpecialSurface::MakeRenderTarget(context,
369 widthHeight, widthHeight,
370 kSkia8888_GrPixelConfig);
robertphillipsc91fd342016-04-25 12:32:54 -0700371 } else
372#endif
373 {
robertphillips4418dba2016-03-07 12:45:14 -0800374 const SkImageInfo info = SkImageInfo::MakeN32(widthHeight, widthHeight,
375 kOpaque_SkAlphaType);
robertphillips3e302272016-04-20 11:48:36 -0700376 return SkSpecialSurface::MakeRaster(info);
robertphillips4418dba2016-03-07 12:45:14 -0800377 }
senorblancobf680c32016-03-16 16:15:53 -0700378}
379
senorblanco5878dbd2016-05-19 14:50:29 -0700380static sk_sp<SkSurface> create_surface(GrContext* context, int width, int height) {
381 const SkImageInfo info = SkImageInfo::MakeN32(width, height, kOpaque_SkAlphaType);
382#if SK_SUPPORT_GPU
383 if (context) {
384 return SkSurface::MakeRenderTarget(context, SkBudgeted::kNo, info);
385 } else
386#endif
387 {
388 return SkSurface::MakeRaster(info);
389 }
390}
391
robertphillips3e302272016-04-20 11:48:36 -0700392static sk_sp<SkSpecialImage> create_empty_special_image(GrContext* context, int widthHeight) {
393 sk_sp<SkSpecialSurface> surf(create_empty_special_surface(context, widthHeight));
robertphillips4418dba2016-03-07 12:45:14 -0800394
395 SkASSERT(surf);
396
397 SkCanvas* canvas = surf->getCanvas();
398 SkASSERT(canvas);
399
400 canvas->clear(0x0);
401
robertphillips37bd7c32016-03-17 14:31:39 -0700402 return surf->makeImageSnapshot();
robertphillips4418dba2016-03-07 12:45:14 -0800403}
404
405
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000406DEF_TEST(ImageFilter, reporter) {
407 {
reedcedc36f2015-03-08 04:42:52 -0700408 // Check that two non-clipping color-matrice-filters concatenate into a single filter.
robertphillips5605b562016-04-05 11:50:42 -0700409 sk_sp<SkImageFilter> halfBrightness(make_scale(0.5f, nullptr));
410 sk_sp<SkImageFilter> quarterBrightness(make_scale(0.5f, std::move(halfBrightness)));
halcanary96fcdcc2015-08-27 07:41:13 -0700411 REPORTER_ASSERT(reporter, nullptr == quarterBrightness->getInput(0));
reedcedc36f2015-03-08 04:42:52 -0700412 SkColorFilter* cf;
413 REPORTER_ASSERT(reporter, quarterBrightness->asColorFilter(&cf));
halcanary96fcdcc2015-08-27 07:41:13 -0700414 REPORTER_ASSERT(reporter, cf->asColorMatrix(nullptr));
reedcedc36f2015-03-08 04:42:52 -0700415 cf->unref();
senorblanco@chromium.org194d7752013-07-24 22:19:24 +0000416 }
417
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000418 {
reedcedc36f2015-03-08 04:42:52 -0700419 // Check that a clipping color-matrice-filter followed by a color-matrice-filters
420 // concatenates into a single filter, but not a matrixfilter (due to clamping).
robertphillips5605b562016-04-05 11:50:42 -0700421 sk_sp<SkImageFilter> doubleBrightness(make_scale(2.0f, nullptr));
422 sk_sp<SkImageFilter> halfBrightness(make_scale(0.5f, std::move(doubleBrightness)));
halcanary96fcdcc2015-08-27 07:41:13 -0700423 REPORTER_ASSERT(reporter, nullptr == halfBrightness->getInput(0));
reedcedc36f2015-03-08 04:42:52 -0700424 SkColorFilter* cf;
425 REPORTER_ASSERT(reporter, halfBrightness->asColorFilter(&cf));
halcanary96fcdcc2015-08-27 07:41:13 -0700426 REPORTER_ASSERT(reporter, !cf->asColorMatrix(nullptr));
reedcedc36f2015-03-08 04:42:52 -0700427 cf->unref();
senorblanco@chromium.org194d7752013-07-24 22:19:24 +0000428 }
429
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000430 {
431 // Check that a color filter image filter without a crop rect can be
432 // expressed as a color filter.
robertphillips5605b562016-04-05 11:50:42 -0700433 sk_sp<SkImageFilter> gray(make_grayscale(nullptr, nullptr));
halcanary96fcdcc2015-08-27 07:41:13 -0700434 REPORTER_ASSERT(reporter, true == gray->asColorFilter(nullptr));
senorblanco@chromium.org194d7752013-07-24 22:19:24 +0000435 }
mtklein2afbe232016-02-07 12:23:10 -0800436
reedcedc36f2015-03-08 04:42:52 -0700437 {
438 // Check that a colorfilterimage filter without a crop rect but with an input
439 // that is another colorfilterimage can be expressed as a colorfilter (composed).
robertphillips5605b562016-04-05 11:50:42 -0700440 sk_sp<SkImageFilter> mode(make_blue(nullptr, nullptr));
441 sk_sp<SkImageFilter> gray(make_grayscale(std::move(mode), nullptr));
halcanary96fcdcc2015-08-27 07:41:13 -0700442 REPORTER_ASSERT(reporter, true == gray->asColorFilter(nullptr));
reedcedc36f2015-03-08 04:42:52 -0700443 }
444
445 {
446 // Test that if we exceed the limit of what ComposeColorFilter can combine, we still
447 // can build the DAG and won't assert if we call asColorFilter.
robertphillips5605b562016-04-05 11:50:42 -0700448 sk_sp<SkImageFilter> filter(make_blue(nullptr, nullptr));
reedcedc36f2015-03-08 04:42:52 -0700449 const int kWayTooManyForComposeColorFilter = 100;
450 for (int i = 0; i < kWayTooManyForComposeColorFilter; ++i) {
robertphillips5605b562016-04-05 11:50:42 -0700451 filter = make_blue(filter, nullptr);
reedcedc36f2015-03-08 04:42:52 -0700452 // the first few of these will succeed, but after we hit the internal limit,
453 // it will then return false.
halcanary96fcdcc2015-08-27 07:41:13 -0700454 (void)filter->asColorFilter(nullptr);
reedcedc36f2015-03-08 04:42:52 -0700455 }
456 }
reed5c518a82015-03-05 14:47:29 -0800457
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000458 {
459 // Check that a color filter image filter with a crop rect cannot
460 // be expressed as a color filter.
461 SkImageFilter::CropRect cropRect(SkRect::MakeXYWH(0, 0, 100, 100));
robertphillips5605b562016-04-05 11:50:42 -0700462 sk_sp<SkImageFilter> grayWithCrop(make_grayscale(nullptr, &cropRect));
halcanary96fcdcc2015-08-27 07:41:13 -0700463 REPORTER_ASSERT(reporter, false == grayWithCrop->asColorFilter(nullptr));
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000464 }
465
466 {
senorblanco3df05012014-07-03 11:13:09 -0700467 // Check that two non-commutative matrices are concatenated in
468 // the correct order.
469 SkScalar blueToRedMatrix[20] = { 0 };
470 blueToRedMatrix[2] = blueToRedMatrix[18] = SK_Scalar1;
471 SkScalar redToGreenMatrix[20] = { 0 };
472 redToGreenMatrix[5] = redToGreenMatrix[18] = SK_Scalar1;
robertphillips5605b562016-04-05 11:50:42 -0700473 sk_sp<SkColorFilter> blueToRed(SkColorFilter::MakeMatrixFilterRowMajor255(blueToRedMatrix));
474 sk_sp<SkImageFilter> filter1(SkColorFilterImageFilter::Make(std::move(blueToRed),
475 nullptr));
476 sk_sp<SkColorFilter> redToGreen(SkColorFilter::MakeMatrixFilterRowMajor255(redToGreenMatrix));
477 sk_sp<SkImageFilter> filter2(SkColorFilterImageFilter::Make(std::move(redToGreen),
478 std::move(filter1)));
senorblanco3df05012014-07-03 11:13:09 -0700479
480 SkBitmap result;
481 result.allocN32Pixels(kBitmapSize, kBitmapSize);
482
483 SkPaint paint;
484 paint.setColor(SK_ColorBLUE);
robertphillips5605b562016-04-05 11:50:42 -0700485 paint.setImageFilter(std::move(filter2));
senorblanco3df05012014-07-03 11:13:09 -0700486 SkCanvas canvas(result);
487 canvas.clear(0x0);
488 SkRect rect = SkRect::Make(SkIRect::MakeWH(kBitmapSize, kBitmapSize));
489 canvas.drawRect(rect, paint);
490 uint32_t pixel = *result.getAddr32(0, 0);
491 // The result here should be green, since we have effectively shifted blue to green.
492 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
493 }
494
495 {
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000496 // Tests pass by not asserting
reed9ce9d672016-03-17 10:51:11 -0700497 sk_sp<SkImage> image(make_small_image());
fmalita5598b632015-09-15 11:26:13 -0700498 SkBitmap result;
mike@reedtribe.orgdeee4962014-02-13 14:41:43 +0000499 result.allocN32Pixels(kBitmapSize, kBitmapSize);
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000500
senorblanco@chromium.org194d7752013-07-24 22:19:24 +0000501 {
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000502 // This tests for :
503 // 1 ) location at (0,0,1)
robertphillips3d32d762015-07-13 13:16:44 -0700504 SkPoint3 location = SkPoint3::Make(0, 0, SK_Scalar1);
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000505 // 2 ) location and target at same value
robertphillips3d32d762015-07-13 13:16:44 -0700506 SkPoint3 target = SkPoint3::Make(location.fX, location.fY, location.fZ);
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000507 // 3 ) large negative specular exponent value
508 SkScalar specularExponent = -1000;
509
robertphillips549c8992016-04-01 09:28:51 -0700510 sk_sp<SkImageFilter> bmSrc(SkImageSource::Make(std::move(image)));
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000511 SkPaint paint;
robertphillips12fa47d2016-04-08 16:28:09 -0700512 paint.setImageFilter(SkLightingImageFilter::MakeSpotLitSpecular(
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000513 location, target, specularExponent, 180,
514 0xFFFFFFFF, SK_Scalar1, SK_Scalar1, SK_Scalar1,
robertphillips12fa47d2016-04-08 16:28:09 -0700515 std::move(bmSrc)));
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000516 SkCanvas canvas(result);
517 SkRect r = SkRect::MakeWH(SkIntToScalar(kBitmapSize),
518 SkIntToScalar(kBitmapSize));
519 canvas.drawRect(r, paint);
senorblanco@chromium.org194d7752013-07-24 22:19:24 +0000520 }
senorblanco@chromium.org194d7752013-07-24 22:19:24 +0000521 }
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +0000522}
senorblanco@chromium.org6776b822014-01-03 21:48:22 +0000523
robertphillips3e302272016-04-20 11:48:36 -0700524static void test_crop_rects(skiatest::Reporter* reporter,
robertphillips4418dba2016-03-07 12:45:14 -0800525 GrContext* context) {
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +0000526 // Check that all filters offset to their absolute crop rect,
527 // unaffected by the input crop rect.
528 // Tests pass by not asserting.
robertphillips3e302272016-04-20 11:48:36 -0700529 sk_sp<SkSpecialImage> srcImg(create_empty_special_image(context, 100));
robertphillips4418dba2016-03-07 12:45:14 -0800530 SkASSERT(srcImg);
senorblanco@chromium.org6776b822014-01-03 21:48:22 +0000531
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +0000532 SkImageFilter::CropRect inputCropRect(SkRect::MakeXYWH(8, 13, 80, 80));
533 SkImageFilter::CropRect cropRect(SkRect::MakeXYWH(20, 30, 60, 60));
robertphillipsfc11b0a2016-04-05 09:09:36 -0700534 sk_sp<SkImageFilter> input(make_grayscale(nullptr, &inputCropRect));
senorblanco@chromium.org6776b822014-01-03 21:48:22 +0000535
robertphillipsfc11b0a2016-04-05 09:09:36 -0700536 FilterList filters(input, &cropRect);
senorblanco@chromium.org6776b822014-01-03 21:48:22 +0000537
senorblanco297f7ce2016-03-23 13:44:26 -0700538 for (int i = 0; i < filters.count(); ++i) {
539 SkImageFilter* filter = filters.getFilter(i);
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +0000540 SkIPoint offset;
reed4e23cda2016-01-11 10:56:59 -0800541 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeWH(100, 100), nullptr);
robertphillips2302de92016-03-24 07:26:32 -0700542 sk_sp<SkSpecialImage> resultImg(filter->filterImage(srcImg.get(), ctx, &offset));
senorblanco297f7ce2016-03-23 13:44:26 -0700543 REPORTER_ASSERT_MESSAGE(reporter, resultImg, filters.getName(i));
544 REPORTER_ASSERT_MESSAGE(reporter, offset.fX == 20 && offset.fY == 30, filters.getName(i));
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +0000545 }
546}
547
robertphillips3e302272016-04-20 11:48:36 -0700548static void test_negative_blur_sigma(skiatest::Reporter* reporter,
robertphillips4418dba2016-03-07 12:45:14 -0800549 GrContext* context) {
senorblanco32673b92014-09-09 09:15:04 -0700550 // Check that SkBlurImageFilter will accept a negative sigma, either in
551 // the given arguments or after CTM application.
reed5ea95df2015-10-06 14:05:32 -0700552 const int width = 32, height = 32;
553 const SkScalar five = SkIntToScalar(5);
senorblanco32673b92014-09-09 09:15:04 -0700554
robertphillips6e7025a2016-04-04 04:31:25 -0700555 sk_sp<SkImageFilter> positiveFilter(SkBlurImageFilter::Make(five, five, nullptr));
556 sk_sp<SkImageFilter> negativeFilter(SkBlurImageFilter::Make(-five, five, nullptr));
senorblanco32673b92014-09-09 09:15:04 -0700557
558 SkBitmap gradient = make_gradient_circle(width, height);
robertphillips3e302272016-04-20 11:48:36 -0700559 sk_sp<SkSpecialImage> imgSrc(SkSpecialImage::MakeFromRaster(SkIRect::MakeWH(width, height),
robertphillips37bd7c32016-03-17 14:31:39 -0700560 gradient));
robertphillips4418dba2016-03-07 12:45:14 -0800561
senorblanco32673b92014-09-09 09:15:04 -0700562 SkIPoint offset;
reed4e23cda2016-01-11 10:56:59 -0800563 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeWH(32, 32), nullptr);
robertphillips4418dba2016-03-07 12:45:14 -0800564
robertphillips2302de92016-03-24 07:26:32 -0700565 sk_sp<SkSpecialImage> positiveResult1(positiveFilter->filterImage(imgSrc.get(), ctx, &offset));
robertphillips4418dba2016-03-07 12:45:14 -0800566 REPORTER_ASSERT(reporter, positiveResult1);
567
robertphillips2302de92016-03-24 07:26:32 -0700568 sk_sp<SkSpecialImage> negativeResult1(negativeFilter->filterImage(imgSrc.get(), ctx, &offset));
robertphillips4418dba2016-03-07 12:45:14 -0800569 REPORTER_ASSERT(reporter, negativeResult1);
570
senorblanco32673b92014-09-09 09:15:04 -0700571 SkMatrix negativeScale;
572 negativeScale.setScale(-SK_Scalar1, SK_Scalar1);
reed4e23cda2016-01-11 10:56:59 -0800573 SkImageFilter::Context negativeCTX(negativeScale, SkIRect::MakeWH(32, 32), nullptr);
robertphillips4418dba2016-03-07 12:45:14 -0800574
robertphillips2302de92016-03-24 07:26:32 -0700575 sk_sp<SkSpecialImage> negativeResult2(positiveFilter->filterImage(imgSrc.get(),
576 negativeCTX,
577 &offset));
robertphillips4418dba2016-03-07 12:45:14 -0800578 REPORTER_ASSERT(reporter, negativeResult2);
579
robertphillips2302de92016-03-24 07:26:32 -0700580 sk_sp<SkSpecialImage> positiveResult2(negativeFilter->filterImage(imgSrc.get(),
581 negativeCTX,
582 &offset));
robertphillips4418dba2016-03-07 12:45:14 -0800583 REPORTER_ASSERT(reporter, positiveResult2);
584
585
586 SkBitmap positiveResultBM1, positiveResultBM2;
587 SkBitmap negativeResultBM1, negativeResultBM2;
588
robertphillips64612512016-04-08 12:10:42 -0700589 REPORTER_ASSERT(reporter, positiveResult1->getROPixels(&positiveResultBM1));
590 REPORTER_ASSERT(reporter, positiveResult2->getROPixels(&positiveResultBM2));
591 REPORTER_ASSERT(reporter, negativeResult1->getROPixels(&negativeResultBM1));
592 REPORTER_ASSERT(reporter, negativeResult2->getROPixels(&negativeResultBM2));
robertphillips4418dba2016-03-07 12:45:14 -0800593
594 SkAutoLockPixels lockP1(positiveResultBM1);
595 SkAutoLockPixels lockP2(positiveResultBM2);
596 SkAutoLockPixels lockN1(negativeResultBM1);
597 SkAutoLockPixels lockN2(negativeResultBM2);
senorblanco32673b92014-09-09 09:15:04 -0700598 for (int y = 0; y < height; y++) {
robertphillips4418dba2016-03-07 12:45:14 -0800599 int diffs = memcmp(positiveResultBM1.getAddr32(0, y),
600 negativeResultBM1.getAddr32(0, y),
601 positiveResultBM1.rowBytes());
senorblanco32673b92014-09-09 09:15:04 -0700602 REPORTER_ASSERT(reporter, !diffs);
603 if (diffs) {
604 break;
605 }
robertphillips4418dba2016-03-07 12:45:14 -0800606 diffs = memcmp(positiveResultBM1.getAddr32(0, y),
607 negativeResultBM2.getAddr32(0, y),
608 positiveResultBM1.rowBytes());
senorblanco32673b92014-09-09 09:15:04 -0700609 REPORTER_ASSERT(reporter, !diffs);
610 if (diffs) {
611 break;
612 }
robertphillips4418dba2016-03-07 12:45:14 -0800613 diffs = memcmp(positiveResultBM1.getAddr32(0, y),
614 positiveResultBM2.getAddr32(0, y),
615 positiveResultBM1.rowBytes());
senorblanco32673b92014-09-09 09:15:04 -0700616 REPORTER_ASSERT(reporter, !diffs);
617 if (diffs) {
618 break;
619 }
620 }
621}
622
senorblanco21a465d2016-04-11 11:58:39 -0700623DEF_TEST(ImageFilterNegativeBlurSigma, reporter) {
robertphillips3e302272016-04-20 11:48:36 -0700624 test_negative_blur_sigma(reporter, nullptr);
robertphillips4418dba2016-03-07 12:45:14 -0800625}
626
627#if SK_SUPPORT_GPU
bsalomon68d91342016-04-12 09:59:58 -0700628DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterNegativeBlurSigma_Gpu, reporter, ctxInfo) {
bsalomon8b7451a2016-05-11 06:33:06 -0700629 test_negative_blur_sigma(reporter, ctxInfo.grContext());
robertphillips4418dba2016-03-07 12:45:14 -0800630}
631#endif
632
robertphillips3e302272016-04-20 11:48:36 -0700633static void test_zero_blur_sigma(skiatest::Reporter* reporter, GrContext* context) {
senorblancobf680c32016-03-16 16:15:53 -0700634 // Check that SkBlurImageFilter with a zero sigma and a non-zero srcOffset works correctly.
635 SkImageFilter::CropRect cropRect(SkRect::Make(SkIRect::MakeXYWH(5, 0, 5, 10)));
robertphillips51a315e2016-03-31 09:05:49 -0700636 sk_sp<SkImageFilter> input(SkOffsetImageFilter::Make(0, 0, nullptr, &cropRect));
robertphillips6e7025a2016-04-04 04:31:25 -0700637 sk_sp<SkImageFilter> filter(SkBlurImageFilter::Make(0, 0, std::move(input), &cropRect));
senorblancobf680c32016-03-16 16:15:53 -0700638
robertphillips3e302272016-04-20 11:48:36 -0700639 sk_sp<SkSpecialSurface> surf(create_empty_special_surface(context, 10));
senorblancobf680c32016-03-16 16:15:53 -0700640 surf->getCanvas()->clear(SK_ColorGREEN);
robertphillips37bd7c32016-03-17 14:31:39 -0700641 sk_sp<SkSpecialImage> image(surf->makeImageSnapshot());
senorblancobf680c32016-03-16 16:15:53 -0700642
643 SkIPoint offset;
644 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeWH(32, 32), nullptr);
645
robertphillips2302de92016-03-24 07:26:32 -0700646 sk_sp<SkSpecialImage> result(filter->filterImage(image.get(), ctx, &offset));
senorblancobf680c32016-03-16 16:15:53 -0700647 REPORTER_ASSERT(reporter, offset.fX == 5 && offset.fY == 0);
648 REPORTER_ASSERT(reporter, result);
649 REPORTER_ASSERT(reporter, result->width() == 5 && result->height() == 10);
650
651 SkBitmap resultBM;
652
robertphillips64612512016-04-08 12:10:42 -0700653 REPORTER_ASSERT(reporter, result->getROPixels(&resultBM));
senorblancobf680c32016-03-16 16:15:53 -0700654
655 SkAutoLockPixels lock(resultBM);
656 for (int y = 0; y < resultBM.height(); y++) {
657 for (int x = 0; x < resultBM.width(); x++) {
658 bool diff = *resultBM.getAddr32(x, y) != SK_ColorGREEN;
659 REPORTER_ASSERT(reporter, !diff);
660 if (diff) {
661 break;
662 }
663 }
664 }
665}
666
senorblanco21a465d2016-04-11 11:58:39 -0700667DEF_TEST(ImageFilterZeroBlurSigma, reporter) {
robertphillips3e302272016-04-20 11:48:36 -0700668 test_zero_blur_sigma(reporter, nullptr);
senorblancobf680c32016-03-16 16:15:53 -0700669}
670
671#if SK_SUPPORT_GPU
bsalomon68d91342016-04-12 09:59:58 -0700672DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterZeroBlurSigma_Gpu, reporter, ctxInfo) {
bsalomon8b7451a2016-05-11 06:33:06 -0700673 test_zero_blur_sigma(reporter, ctxInfo.grContext());
senorblancobf680c32016-03-16 16:15:53 -0700674}
675#endif
676
senorblanco6a93fa12016-04-05 04:43:45 -0700677
678// Tests that, even when an upstream filter has returned null (due to failure or clipping), a
679// downstream filter that affects transparent black still does so even with a nullptr input.
robertphillips3e302272016-04-20 11:48:36 -0700680static void test_fail_affects_transparent_black(skiatest::Reporter* reporter, GrContext* context) {
senorblanco6a93fa12016-04-05 04:43:45 -0700681 sk_sp<FailImageFilter> failFilter(new FailImageFilter());
robertphillips3e302272016-04-20 11:48:36 -0700682 sk_sp<SkSpecialImage> source(create_empty_special_image(context, 5));
senorblanco6a93fa12016-04-05 04:43:45 -0700683 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeXYWH(0, 0, 1, 1), nullptr);
684 sk_sp<SkColorFilter> green(SkColorFilter::MakeModeFilter(SK_ColorGREEN, SkXfermode::kSrc_Mode));
685 SkASSERT(green->affectsTransparentBlack());
robertphillips5605b562016-04-05 11:50:42 -0700686 sk_sp<SkImageFilter> greenFilter(SkColorFilterImageFilter::Make(std::move(green),
687 std::move(failFilter)));
senorblanco6a93fa12016-04-05 04:43:45 -0700688 SkIPoint offset;
689 sk_sp<SkSpecialImage> result(greenFilter->filterImage(source.get(), ctx, &offset));
690 REPORTER_ASSERT(reporter, nullptr != result.get());
691 if (result.get()) {
692 SkBitmap resultBM;
robertphillips64612512016-04-08 12:10:42 -0700693 REPORTER_ASSERT(reporter, result->getROPixels(&resultBM));
senorblanco6a93fa12016-04-05 04:43:45 -0700694 SkAutoLockPixels lock(resultBM);
695 REPORTER_ASSERT(reporter, *resultBM.getAddr32(0, 0) == SK_ColorGREEN);
696 }
697}
698
699DEF_TEST(ImageFilterFailAffectsTransparentBlack, reporter) {
robertphillips3e302272016-04-20 11:48:36 -0700700 test_fail_affects_transparent_black(reporter, nullptr);
senorblanco6a93fa12016-04-05 04:43:45 -0700701}
702
703#if SK_SUPPORT_GPU
bsalomon68d91342016-04-12 09:59:58 -0700704DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterFailAffectsTransparentBlack_Gpu, reporter, ctxInfo) {
bsalomon8b7451a2016-05-11 06:33:06 -0700705 test_fail_affects_transparent_black(reporter, ctxInfo.grContext());
senorblanco6a93fa12016-04-05 04:43:45 -0700706}
707#endif
708
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +0000709DEF_TEST(ImageFilterDrawTiled, reporter) {
710 // Check that all filters when drawn tiled (with subsequent clip rects) exactly
711 // match the same filters drawn with a single full-canvas bitmap draw.
712 // Tests pass by not asserting.
713
robertphillipsfc11b0a2016-04-05 09:09:36 -0700714 FilterList filters(nullptr);
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +0000715
716 SkBitmap untiledResult, tiledResult;
reed5ea95df2015-10-06 14:05:32 -0700717 const int width = 64, height = 64;
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +0000718 untiledResult.allocN32Pixels(width, height);
719 tiledResult.allocN32Pixels(width, height);
720 SkCanvas tiledCanvas(tiledResult);
721 SkCanvas untiledCanvas(untiledResult);
senorblanco@chromium.orgd4db6572014-05-07 20:00:04 +0000722 int tileSize = 8;
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +0000723
senorblanco@chromium.orgd4db6572014-05-07 20:00:04 +0000724 for (int scale = 1; scale <= 2; ++scale) {
senorblanco297f7ce2016-03-23 13:44:26 -0700725 for (int i = 0; i < filters.count(); ++i) {
senorblanco@chromium.orgd4db6572014-05-07 20:00:04 +0000726 tiledCanvas.clear(0);
727 untiledCanvas.clear(0);
728 SkPaint paint;
senorblanco297f7ce2016-03-23 13:44:26 -0700729 paint.setImageFilter(filters.getFilter(i));
senorblanco@chromium.orgd4db6572014-05-07 20:00:04 +0000730 paint.setTextSize(SkIntToScalar(height));
731 paint.setColor(SK_ColorWHITE);
732 SkString str;
733 const char* text = "ABC";
734 SkScalar ypos = SkIntToScalar(height);
735 untiledCanvas.save();
736 untiledCanvas.scale(SkIntToScalar(scale), SkIntToScalar(scale));
737 untiledCanvas.drawText(text, strlen(text), 0, ypos, paint);
738 untiledCanvas.restore();
739 for (int y = 0; y < height; y += tileSize) {
740 for (int x = 0; x < width; x += tileSize) {
741 tiledCanvas.save();
742 tiledCanvas.clipRect(SkRect::Make(SkIRect::MakeXYWH(x, y, tileSize, tileSize)));
743 tiledCanvas.scale(SkIntToScalar(scale), SkIntToScalar(scale));
744 tiledCanvas.drawText(text, strlen(text), 0, ypos, paint);
745 tiledCanvas.restore();
746 }
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +0000747 }
senorblanco@chromium.orgd4db6572014-05-07 20:00:04 +0000748 untiledCanvas.flush();
749 tiledCanvas.flush();
750 for (int y = 0; y < height; y++) {
751 int diffs = memcmp(untiledResult.getAddr32(0, y), tiledResult.getAddr32(0, y), untiledResult.rowBytes());
senorblanco297f7ce2016-03-23 13:44:26 -0700752 REPORTER_ASSERT_MESSAGE(reporter, !diffs, filters.getName(i));
senorblanco@chromium.orgd4db6572014-05-07 20:00:04 +0000753 if (diffs) {
754 break;
755 }
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +0000756 }
757 }
758 }
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +0000759}
760
mtklein3f3b3d02014-12-01 11:47:08 -0800761static void draw_saveLayer_picture(int width, int height, int tileSize,
robertphillipsa8d7f0b2014-08-29 08:03:56 -0700762 SkBBHFactory* factory, SkBitmap* result) {
mtkleind910f542014-08-22 09:06:34 -0700763
764 SkMatrix matrix;
765 matrix.setTranslate(SkIntToScalar(50), 0);
766
robertphillips5605b562016-04-05 11:50:42 -0700767 sk_sp<SkColorFilter> cf(SkColorFilter::MakeModeFilter(SK_ColorWHITE, SkXfermode::kSrc_Mode));
768 sk_sp<SkImageFilter> cfif(SkColorFilterImageFilter::Make(std::move(cf), nullptr));
robertphillipsae8c9332016-04-05 15:09:00 -0700769 sk_sp<SkImageFilter> imageFilter(SkImageFilter::MakeMatrixFilter(matrix,
770 kNone_SkFilterQuality,
771 std::move(cfif)));
mtkleind910f542014-08-22 09:06:34 -0700772
773 SkPaint paint;
robertphillips5605b562016-04-05 11:50:42 -0700774 paint.setImageFilter(std::move(imageFilter));
mtkleind910f542014-08-22 09:06:34 -0700775 SkPictureRecorder recorder;
776 SkRect bounds = SkRect::Make(SkIRect::MakeXYWH(0, 0, 50, 50));
mtklein3f3b3d02014-12-01 11:47:08 -0800777 SkCanvas* recordingCanvas = recorder.beginRecording(SkIntToScalar(width),
778 SkIntToScalar(height),
robertphillipsa8d7f0b2014-08-29 08:03:56 -0700779 factory, 0);
mtkleind910f542014-08-22 09:06:34 -0700780 recordingCanvas->translate(-55, 0);
781 recordingCanvas->saveLayer(&bounds, &paint);
782 recordingCanvas->restore();
reedca2622b2016-03-18 07:25:55 -0700783 sk_sp<SkPicture> picture1(recorder.finishRecordingAsPicture());
mtkleind910f542014-08-22 09:06:34 -0700784
785 result->allocN32Pixels(width, height);
786 SkCanvas canvas(*result);
787 canvas.clear(0);
788 canvas.clipRect(SkRect::Make(SkIRect::MakeWH(tileSize, tileSize)));
789 canvas.drawPicture(picture1.get());
790}
791
792DEF_TEST(ImageFilterDrawMatrixBBH, reporter) {
793 // Check that matrix filter when drawn tiled with BBH exactly
794 // matches the same thing drawn without BBH.
795 // Tests pass by not asserting.
796
797 const int width = 200, height = 200;
798 const int tileSize = 100;
799 SkBitmap result1, result2;
800 SkRTreeFactory factory;
801
robertphillipsa8d7f0b2014-08-29 08:03:56 -0700802 draw_saveLayer_picture(width, height, tileSize, &factory, &result1);
halcanary96fcdcc2015-08-27 07:41:13 -0700803 draw_saveLayer_picture(width, height, tileSize, nullptr, &result2);
mtkleind910f542014-08-22 09:06:34 -0700804
805 for (int y = 0; y < height; y++) {
806 int diffs = memcmp(result1.getAddr32(0, y), result2.getAddr32(0, y), result1.rowBytes());
807 REPORTER_ASSERT(reporter, !diffs);
808 if (diffs) {
809 break;
810 }
811 }
812}
813
robertphillips6e7025a2016-04-04 04:31:25 -0700814static sk_sp<SkImageFilter> make_blur(sk_sp<SkImageFilter> input) {
815 return SkBlurImageFilter::Make(SK_Scalar1, SK_Scalar1, std::move(input));
senorblanco1150a6d2014-08-25 12:46:58 -0700816}
817
robertphillips6e7025a2016-04-04 04:31:25 -0700818static sk_sp<SkImageFilter> make_drop_shadow(sk_sp<SkImageFilter> input) {
robertphillipsc4169122016-04-06 08:40:59 -0700819 return SkDropShadowImageFilter::Make(
senorblanco1150a6d2014-08-25 12:46:58 -0700820 SkIntToScalar(100), SkIntToScalar(100),
821 SkIntToScalar(10), SkIntToScalar(10),
sugoi234f0362014-10-23 13:59:52 -0700822 SK_ColorBLUE, SkDropShadowImageFilter::kDrawShadowAndForeground_ShadowMode,
robertphillipsc4169122016-04-06 08:40:59 -0700823 std::move(input));
senorblanco1150a6d2014-08-25 12:46:58 -0700824}
825
826DEF_TEST(ImageFilterBlurThenShadowBounds, reporter) {
robertphillips6e7025a2016-04-04 04:31:25 -0700827 sk_sp<SkImageFilter> filter1(make_blur(nullptr));
828 sk_sp<SkImageFilter> filter2(make_drop_shadow(std::move(filter1)));
senorblanco1150a6d2014-08-25 12:46:58 -0700829
830 SkIRect bounds = SkIRect::MakeXYWH(0, 0, 100, 100);
831 SkIRect expectedBounds = SkIRect::MakeXYWH(-133, -133, 236, 236);
senorblancoe5e79842016-03-21 14:51:59 -0700832 bounds = filter2->filterBounds(bounds, SkMatrix::I());
senorblanco1150a6d2014-08-25 12:46:58 -0700833
834 REPORTER_ASSERT(reporter, bounds == expectedBounds);
835}
836
837DEF_TEST(ImageFilterShadowThenBlurBounds, reporter) {
robertphillips6e7025a2016-04-04 04:31:25 -0700838 sk_sp<SkImageFilter> filter1(make_drop_shadow(nullptr));
839 sk_sp<SkImageFilter> filter2(make_blur(std::move(filter1)));
senorblanco1150a6d2014-08-25 12:46:58 -0700840
841 SkIRect bounds = SkIRect::MakeXYWH(0, 0, 100, 100);
842 SkIRect expectedBounds = SkIRect::MakeXYWH(-133, -133, 236, 236);
senorblancoe5e79842016-03-21 14:51:59 -0700843 bounds = filter2->filterBounds(bounds, SkMatrix::I());
senorblanco1150a6d2014-08-25 12:46:58 -0700844
845 REPORTER_ASSERT(reporter, bounds == expectedBounds);
846}
847
848DEF_TEST(ImageFilterDilateThenBlurBounds, reporter) {
robertphillipsfc11b0a2016-04-05 09:09:36 -0700849 sk_sp<SkImageFilter> filter1(SkDilateImageFilter::Make(2, 2, nullptr));
robertphillips6e7025a2016-04-04 04:31:25 -0700850 sk_sp<SkImageFilter> filter2(make_drop_shadow(std::move(filter1)));
senorblanco1150a6d2014-08-25 12:46:58 -0700851
852 SkIRect bounds = SkIRect::MakeXYWH(0, 0, 100, 100);
853 SkIRect expectedBounds = SkIRect::MakeXYWH(-132, -132, 234, 234);
senorblancoe5e79842016-03-21 14:51:59 -0700854 bounds = filter2->filterBounds(bounds, SkMatrix::I());
senorblanco1150a6d2014-08-25 12:46:58 -0700855
856 REPORTER_ASSERT(reporter, bounds == expectedBounds);
857}
858
jbroman203a9932016-07-11 14:07:59 -0700859DEF_TEST(ImageFilterScaledBlurRadius, reporter) {
860 // Each blur should spread 3*sigma, so 3 for the blur and 30 for the shadow
861 // (before the CTM). Bounds should be computed correctly in the presence of
862 // a (possibly negative) scale.
863 sk_sp<SkImageFilter> blur(make_blur(nullptr));
864 sk_sp<SkImageFilter> dropShadow(make_drop_shadow(nullptr));
865 {
866 // Uniform scale by 2.
867 SkMatrix scaleMatrix;
868 scaleMatrix.setScale(2, 2);
869 SkIRect bounds = SkIRect::MakeLTRB(0, 0, 200, 200);
870
871 SkIRect expectedBlurBounds = SkIRect::MakeLTRB(-6, -6, 206, 206);
872 SkIRect blurBounds = blur->filterBounds(
873 bounds, scaleMatrix, SkImageFilter::kForward_MapDirection);
874 REPORTER_ASSERT(reporter, blurBounds == expectedBlurBounds);
875 SkIRect reverseBlurBounds = blur->filterBounds(
876 bounds, scaleMatrix, SkImageFilter::kReverse_MapDirection);
877 REPORTER_ASSERT(reporter, reverseBlurBounds == expectedBlurBounds);
878
879 SkIRect expectedShadowBounds = SkIRect::MakeLTRB(0, 0, 460, 460);
880 SkIRect shadowBounds = dropShadow->filterBounds(
881 bounds, scaleMatrix, SkImageFilter::kForward_MapDirection);
882 REPORTER_ASSERT(reporter, shadowBounds == expectedShadowBounds);
883 SkIRect expectedReverseShadowBounds =
884 SkIRect::MakeLTRB(-260, -260, 200, 200);
885 SkIRect reverseShadowBounds = dropShadow->filterBounds(
886 bounds, scaleMatrix, SkImageFilter::kReverse_MapDirection);
887 REPORTER_ASSERT(reporter,
888 reverseShadowBounds == expectedReverseShadowBounds);
889 }
890 {
891 // Vertical flip.
892 SkMatrix scaleMatrix;
893 scaleMatrix.setScale(1, -1);
894 SkIRect bounds = SkIRect::MakeLTRB(0, -100, 100, 0);
895
896 SkIRect expectedBlurBounds = SkIRect::MakeLTRB(-3, -103, 103, 3);
897 SkIRect blurBounds = blur->filterBounds(
898 bounds, scaleMatrix, SkImageFilter::kForward_MapDirection);
899 REPORTER_ASSERT(reporter, blurBounds == expectedBlurBounds);
900 SkIRect reverseBlurBounds = blur->filterBounds(
901 bounds, scaleMatrix, SkImageFilter::kReverse_MapDirection);
902 REPORTER_ASSERT(reporter, reverseBlurBounds == expectedBlurBounds);
903
904 SkIRect expectedShadowBounds = SkIRect::MakeLTRB(0, -230, 230, 0);
905 SkIRect shadowBounds = dropShadow->filterBounds(
906 bounds, scaleMatrix, SkImageFilter::kForward_MapDirection);
907 REPORTER_ASSERT(reporter, shadowBounds == expectedShadowBounds);
908 SkIRect expectedReverseShadowBounds =
909 SkIRect::MakeLTRB(-130, -100, 100, 130);
910 SkIRect reverseShadowBounds = dropShadow->filterBounds(
911 bounds, scaleMatrix, SkImageFilter::kReverse_MapDirection);
912 REPORTER_ASSERT(reporter,
913 reverseShadowBounds == expectedReverseShadowBounds);
914 }
915}
916
ajuma5788faa2015-02-13 09:05:47 -0800917DEF_TEST(ImageFilterComposedBlurFastBounds, reporter) {
robertphillips6e7025a2016-04-04 04:31:25 -0700918 sk_sp<SkImageFilter> filter1(make_blur(nullptr));
919 sk_sp<SkImageFilter> filter2(make_blur(nullptr));
robertphillips491fb172016-03-30 12:32:58 -0700920 sk_sp<SkImageFilter> composedFilter(SkComposeImageFilter::Make(std::move(filter1),
921 std::move(filter2)));
ajuma5788faa2015-02-13 09:05:47 -0800922
923 SkRect boundsSrc = SkRect::MakeWH(SkIntToScalar(100), SkIntToScalar(100));
924 SkRect expectedBounds = SkRect::MakeXYWH(
925 SkIntToScalar(-6), SkIntToScalar(-6), SkIntToScalar(112), SkIntToScalar(112));
senorblancoe5e79842016-03-21 14:51:59 -0700926 SkRect boundsDst = composedFilter->computeFastBounds(boundsSrc);
ajuma5788faa2015-02-13 09:05:47 -0800927
928 REPORTER_ASSERT(reporter, boundsDst == expectedBounds);
929}
930
jbroman0e3129d2016-03-17 12:24:23 -0700931DEF_TEST(ImageFilterUnionBounds, reporter) {
robertphillips51a315e2016-03-31 09:05:49 -0700932 sk_sp<SkImageFilter> offset(SkOffsetImageFilter::Make(50, 0, nullptr));
jbroman0e3129d2016-03-17 12:24:23 -0700933 // Regardless of which order they appear in, the image filter bounds should
934 // be combined correctly.
935 {
robertphillips8c0326d2016-04-05 12:48:34 -0700936 sk_sp<SkImageFilter> composite(SkXfermodeImageFilter::Make(nullptr, offset));
jbroman0e3129d2016-03-17 12:24:23 -0700937 SkRect bounds = SkRect::MakeWH(100, 100);
938 // Intentionally aliasing here, as that's what the real callers do.
senorblancoe5e79842016-03-21 14:51:59 -0700939 bounds = composite->computeFastBounds(bounds);
jbroman0e3129d2016-03-17 12:24:23 -0700940 REPORTER_ASSERT(reporter, bounds == SkRect::MakeWH(150, 100));
941 }
942 {
reedcfb6bdf2016-03-29 11:32:50 -0700943 sk_sp<SkImageFilter> composite(SkXfermodeImageFilter::Make(nullptr, nullptr,
robertphillips8c0326d2016-04-05 12:48:34 -0700944 offset, nullptr));
jbroman0e3129d2016-03-17 12:24:23 -0700945 SkRect bounds = SkRect::MakeWH(100, 100);
946 // Intentionally aliasing here, as that's what the real callers do.
senorblancoe5e79842016-03-21 14:51:59 -0700947 bounds = composite->computeFastBounds(bounds);
jbroman0e3129d2016-03-17 12:24:23 -0700948 REPORTER_ASSERT(reporter, bounds == SkRect::MakeWH(150, 100));
949 }
950}
951
robertphillips3e302272016-04-20 11:48:36 -0700952static void test_imagefilter_merge_result_size(skiatest::Reporter* reporter, GrContext* context) {
senorblanco4a243982015-11-25 07:06:55 -0800953 SkBitmap greenBM;
954 greenBM.allocN32Pixels(20, 20);
955 greenBM.eraseColor(SK_ColorGREEN);
reed9ce9d672016-03-17 10:51:11 -0700956 sk_sp<SkImage> greenImage(SkImage::MakeFromBitmap(greenBM));
robertphillips549c8992016-04-01 09:28:51 -0700957 sk_sp<SkImageFilter> source(SkImageSource::Make(std::move(greenImage)));
robertphillips2238c9d2016-03-30 13:34:16 -0700958 sk_sp<SkImageFilter> merge(SkMergeImageFilter::Make(source, source));
senorblanco4a243982015-11-25 07:06:55 -0800959
robertphillips3e302272016-04-20 11:48:36 -0700960 sk_sp<SkSpecialImage> srcImg(create_empty_special_image(context, 1));
robertphillips4418dba2016-03-07 12:45:14 -0800961
reed4e23cda2016-01-11 10:56:59 -0800962 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeXYWH(0, 0, 100, 100), nullptr);
senorblanco4a243982015-11-25 07:06:55 -0800963 SkIPoint offset;
robertphillips4418dba2016-03-07 12:45:14 -0800964
robertphillips2302de92016-03-24 07:26:32 -0700965 sk_sp<SkSpecialImage> resultImg(merge->filterImage(srcImg.get(), ctx, &offset));
robertphillips4418dba2016-03-07 12:45:14 -0800966 REPORTER_ASSERT(reporter, resultImg);
967
968 REPORTER_ASSERT(reporter, resultImg->width() == 20 && resultImg->height() == 20);
senorblanco4a243982015-11-25 07:06:55 -0800969}
970
robertphillips4418dba2016-03-07 12:45:14 -0800971DEF_TEST(ImageFilterMergeResultSize, reporter) {
robertphillips3e302272016-04-20 11:48:36 -0700972 test_imagefilter_merge_result_size(reporter, nullptr);
robertphillips4418dba2016-03-07 12:45:14 -0800973}
974
975#if SK_SUPPORT_GPU
egdanielab527a52016-06-28 08:07:26 -0700976DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterMergeResultSize_Gpu, reporter, ctxInfo) {
bsalomon8b7451a2016-05-11 06:33:06 -0700977 test_imagefilter_merge_result_size(reporter, ctxInfo.grContext());
robertphillips4418dba2016-03-07 12:45:14 -0800978}
979#endif
980
robertphillipsa8d7f0b2014-08-29 08:03:56 -0700981static void draw_blurred_rect(SkCanvas* canvas) {
senorblanco837f5322014-07-14 10:19:54 -0700982 SkPaint filterPaint;
983 filterPaint.setColor(SK_ColorWHITE);
robertphillips6e7025a2016-04-04 04:31:25 -0700984 filterPaint.setImageFilter(SkBlurImageFilter::Make(SkIntToScalar(8), 0, nullptr));
halcanary96fcdcc2015-08-27 07:41:13 -0700985 canvas->saveLayer(nullptr, &filterPaint);
senorblanco837f5322014-07-14 10:19:54 -0700986 SkPaint whitePaint;
987 whitePaint.setColor(SK_ColorWHITE);
988 canvas->drawRect(SkRect::Make(SkIRect::MakeWH(4, 4)), whitePaint);
989 canvas->restore();
990}
991
robertphillipsa8d7f0b2014-08-29 08:03:56 -0700992static void draw_picture_clipped(SkCanvas* canvas, const SkRect& clipRect, const SkPicture* picture) {
senorblanco837f5322014-07-14 10:19:54 -0700993 canvas->save();
994 canvas->clipRect(clipRect);
995 canvas->drawPicture(picture);
996 canvas->restore();
997}
998
999DEF_TEST(ImageFilterDrawTiledBlurRTree, reporter) {
1000 // Check that the blur filter when recorded with RTree acceleration,
1001 // and drawn tiled (with subsequent clip rects) exactly
1002 // matches the same filter drawn with without RTree acceleration.
1003 // This tests that the "bleed" from the blur into the otherwise-blank
1004 // tiles is correctly rendered.
1005 // Tests pass by not asserting.
1006
1007 int width = 16, height = 8;
1008 SkBitmap result1, result2;
1009 result1.allocN32Pixels(width, height);
1010 result2.allocN32Pixels(width, height);
1011 SkCanvas canvas1(result1);
1012 SkCanvas canvas2(result2);
1013 int tileSize = 8;
1014
1015 canvas1.clear(0);
1016 canvas2.clear(0);
1017
1018 SkRTreeFactory factory;
1019
1020 SkPictureRecorder recorder1, recorder2;
1021 // The only difference between these two pictures is that one has RTree aceleration.
mtklein3f3b3d02014-12-01 11:47:08 -08001022 SkCanvas* recordingCanvas1 = recorder1.beginRecording(SkIntToScalar(width),
1023 SkIntToScalar(height),
halcanary96fcdcc2015-08-27 07:41:13 -07001024 nullptr, 0);
mtklein3f3b3d02014-12-01 11:47:08 -08001025 SkCanvas* recordingCanvas2 = recorder2.beginRecording(SkIntToScalar(width),
1026 SkIntToScalar(height),
robertphillipsa8d7f0b2014-08-29 08:03:56 -07001027 &factory, 0);
1028 draw_blurred_rect(recordingCanvas1);
1029 draw_blurred_rect(recordingCanvas2);
reedca2622b2016-03-18 07:25:55 -07001030 sk_sp<SkPicture> picture1(recorder1.finishRecordingAsPicture());
1031 sk_sp<SkPicture> picture2(recorder2.finishRecordingAsPicture());
senorblanco837f5322014-07-14 10:19:54 -07001032 for (int y = 0; y < height; y += tileSize) {
1033 for (int x = 0; x < width; x += tileSize) {
1034 SkRect tileRect = SkRect::Make(SkIRect::MakeXYWH(x, y, tileSize, tileSize));
reedca2622b2016-03-18 07:25:55 -07001035 draw_picture_clipped(&canvas1, tileRect, picture1.get());
1036 draw_picture_clipped(&canvas2, tileRect, picture2.get());
senorblanco837f5322014-07-14 10:19:54 -07001037 }
1038 }
1039 for (int y = 0; y < height; y++) {
1040 int diffs = memcmp(result1.getAddr32(0, y), result2.getAddr32(0, y), result1.rowBytes());
1041 REPORTER_ASSERT(reporter, !diffs);
1042 if (diffs) {
1043 break;
1044 }
1045 }
1046}
1047
senorblanco@chromium.org91957432014-05-01 14:03:41 +00001048DEF_TEST(ImageFilterMatrixConvolution, reporter) {
1049 // Check that a 1x3 filter does not cause a spurious assert.
1050 SkScalar kernel[3] = {
1051 SkIntToScalar( 1), SkIntToScalar( 1), SkIntToScalar( 1),
1052 };
1053 SkISize kernelSize = SkISize::Make(1, 3);
1054 SkScalar gain = SK_Scalar1, bias = 0;
1055 SkIPoint kernelOffset = SkIPoint::Make(0, 0);
1056
robertphillipsef6a47b2016-04-08 08:01:20 -07001057 sk_sp<SkImageFilter> filter(SkMatrixConvolutionImageFilter::Make(
1058 kernelSize, kernel,
1059 gain, bias, kernelOffset,
1060 SkMatrixConvolutionImageFilter::kRepeat_TileMode,
1061 false, nullptr));
senorblanco@chromium.org91957432014-05-01 14:03:41 +00001062
1063 SkBitmap result;
1064 int width = 16, height = 16;
1065 result.allocN32Pixels(width, height);
1066 SkCanvas canvas(result);
1067 canvas.clear(0);
1068
1069 SkPaint paint;
robertphillipsef6a47b2016-04-08 08:01:20 -07001070 paint.setImageFilter(std::move(filter));
senorblanco@chromium.org91957432014-05-01 14:03:41 +00001071 SkRect rect = SkRect::Make(SkIRect::MakeWH(width, height));
1072 canvas.drawRect(rect, paint);
1073}
1074
senorblanco@chromium.org8c7372b2014-05-02 19:13:11 +00001075DEF_TEST(ImageFilterMatrixConvolutionBorder, reporter) {
1076 // Check that a filter with borders outside the target bounds
1077 // does not crash.
1078 SkScalar kernel[3] = {
1079 0, 0, 0,
1080 };
1081 SkISize kernelSize = SkISize::Make(3, 1);
1082 SkScalar gain = SK_Scalar1, bias = 0;
1083 SkIPoint kernelOffset = SkIPoint::Make(2, 0);
1084
robertphillipsef6a47b2016-04-08 08:01:20 -07001085 sk_sp<SkImageFilter> filter(SkMatrixConvolutionImageFilter::Make(
1086 kernelSize, kernel, gain, bias, kernelOffset,
1087 SkMatrixConvolutionImageFilter::kClamp_TileMode,
1088 true, nullptr));
senorblanco@chromium.org8c7372b2014-05-02 19:13:11 +00001089
1090 SkBitmap result;
1091
1092 int width = 10, height = 10;
1093 result.allocN32Pixels(width, height);
1094 SkCanvas canvas(result);
1095 canvas.clear(0);
1096
1097 SkPaint filterPaint;
robertphillipsef6a47b2016-04-08 08:01:20 -07001098 filterPaint.setImageFilter(std::move(filter));
senorblanco@chromium.org8c7372b2014-05-02 19:13:11 +00001099 SkRect bounds = SkRect::MakeWH(1, 10);
1100 SkRect rect = SkRect::Make(SkIRect::MakeWH(width, height));
1101 SkPaint rectPaint;
1102 canvas.saveLayer(&bounds, &filterPaint);
1103 canvas.drawRect(rect, rectPaint);
1104 canvas.restore();
1105}
1106
robertphillips3e302272016-04-20 11:48:36 -07001107static void test_big_kernel(skiatest::Reporter* reporter, GrContext* context) {
robertphillipsdada4dd2016-04-13 04:54:36 -07001108 // Check that a kernel that is too big for the GPU still works
1109 SkScalar identityKernel[49] = {
1110 0, 0, 0, 0, 0, 0, 0,
1111 0, 0, 0, 0, 0, 0, 0,
1112 0, 0, 0, 0, 0, 0, 0,
1113 0, 0, 0, 1, 0, 0, 0,
1114 0, 0, 0, 0, 0, 0, 0,
1115 0, 0, 0, 0, 0, 0, 0,
1116 0, 0, 0, 0, 0, 0, 0
1117 };
1118 SkISize kernelSize = SkISize::Make(7, 7);
1119 SkScalar gain = SK_Scalar1, bias = 0;
1120 SkIPoint kernelOffset = SkIPoint::Make(0, 0);
1121
1122 sk_sp<SkImageFilter> filter(SkMatrixConvolutionImageFilter::Make(
1123 kernelSize, identityKernel, gain, bias, kernelOffset,
1124 SkMatrixConvolutionImageFilter::kClamp_TileMode,
1125 true, nullptr));
1126
robertphillips3e302272016-04-20 11:48:36 -07001127 sk_sp<SkSpecialImage> srcImg(create_empty_special_image(context, 100));
robertphillipsdada4dd2016-04-13 04:54:36 -07001128 SkASSERT(srcImg);
1129
1130 SkIPoint offset;
1131 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeWH(100, 100), nullptr);
1132 sk_sp<SkSpecialImage> resultImg(filter->filterImage(srcImg.get(), ctx, &offset));
1133 REPORTER_ASSERT(reporter, resultImg);
1134 REPORTER_ASSERT(reporter, SkToBool(context) == resultImg->isTextureBacked());
1135 REPORTER_ASSERT(reporter, resultImg->width() == 100 && resultImg->height() == 100);
1136 REPORTER_ASSERT(reporter, offset.fX == 0 && offset.fY == 0);
1137}
1138
1139DEF_TEST(ImageFilterMatrixConvolutionBigKernel, reporter) {
robertphillips3e302272016-04-20 11:48:36 -07001140 test_big_kernel(reporter, nullptr);
robertphillipsdada4dd2016-04-13 04:54:36 -07001141}
1142
1143#if SK_SUPPORT_GPU
egdanielab527a52016-06-28 08:07:26 -07001144DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterMatrixConvolutionBigKernel_Gpu,
1145 reporter, ctxInfo) {
bsalomon8b7451a2016-05-11 06:33:06 -07001146 test_big_kernel(reporter, ctxInfo.grContext());
robertphillipsdada4dd2016-04-13 04:54:36 -07001147}
1148#endif
1149
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +00001150DEF_TEST(ImageFilterCropRect, reporter) {
robertphillips3e302272016-04-20 11:48:36 -07001151 test_crop_rects(reporter, nullptr);
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +00001152}
1153
robertphillips4418dba2016-03-07 12:45:14 -08001154#if SK_SUPPORT_GPU
bsalomon68d91342016-04-12 09:59:58 -07001155DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterCropRect_Gpu, reporter, ctxInfo) {
bsalomon8b7451a2016-05-11 06:33:06 -07001156 test_crop_rects(reporter, ctxInfo.grContext());
robertphillips4418dba2016-03-07 12:45:14 -08001157}
1158#endif
1159
tfarina9ea53f92014-06-24 06:50:39 -07001160DEF_TEST(ImageFilterMatrix, reporter) {
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +00001161 SkBitmap temp;
mike@reedtribe.orgdeee4962014-02-13 14:41:43 +00001162 temp.allocN32Pixels(100, 100);
robertphillips9a53fd72015-06-22 09:46:59 -07001163 SkCanvas canvas(temp);
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +00001164 canvas.scale(SkIntToScalar(2), SkIntToScalar(2));
1165
1166 SkMatrix expectedMatrix = canvas.getTotalMatrix();
1167
commit-bot@chromium.org5fb2ce32014-04-17 23:35:06 +00001168 SkRTreeFactory factory;
1169 SkPictureRecorder recorder;
1170 SkCanvas* recordingCanvas = recorder.beginRecording(100, 100, &factory, 0);
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +00001171
1172 SkPaint paint;
robertphillips43c2ad42016-04-04 05:05:11 -07001173 paint.setImageFilter(MatrixTestImageFilter::Make(reporter, expectedMatrix));
halcanary96fcdcc2015-08-27 07:41:13 -07001174 recordingCanvas->saveLayer(nullptr, &paint);
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +00001175 SkPaint solidPaint;
1176 solidPaint.setColor(0xFFFFFFFF);
1177 recordingCanvas->save();
1178 recordingCanvas->scale(SkIntToScalar(10), SkIntToScalar(10));
1179 recordingCanvas->drawRect(SkRect::Make(SkIRect::MakeWH(100, 100)), solidPaint);
1180 recordingCanvas->restore(); // scale
1181 recordingCanvas->restore(); // saveLayer
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +00001182
reedca2622b2016-03-18 07:25:55 -07001183 canvas.drawPicture(recorder.finishRecordingAsPicture());
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +00001184}
1185
senorblanco3d822c22014-07-30 14:49:31 -07001186DEF_TEST(ImageFilterCrossProcessPictureImageFilter, reporter) {
senorblanco@chromium.org97f5fc62014-05-30 20:50:56 +00001187 SkRTreeFactory factory;
1188 SkPictureRecorder recorder;
1189 SkCanvas* recordingCanvas = recorder.beginRecording(1, 1, &factory, 0);
1190
1191 // Create an SkPicture which simply draws a green 1x1 rectangle.
1192 SkPaint greenPaint;
1193 greenPaint.setColor(SK_ColorGREEN);
1194 recordingCanvas->drawRect(SkRect::Make(SkIRect::MakeWH(1, 1)), greenPaint);
reedca2622b2016-03-18 07:25:55 -07001195 sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture());
senorblanco@chromium.org97f5fc62014-05-30 20:50:56 +00001196
1197 // Wrap that SkPicture in an SkPictureImageFilter.
robertphillips5ff17b12016-03-28 13:13:42 -07001198 sk_sp<SkImageFilter> imageFilter(SkPictureImageFilter::Make(picture));
senorblanco@chromium.org97f5fc62014-05-30 20:50:56 +00001199
1200 // Check that SkPictureImageFilter successfully serializes its contained
1201 // SkPicture when not in cross-process mode.
1202 SkPaint paint;
robertphillips5ff17b12016-03-28 13:13:42 -07001203 paint.setImageFilter(imageFilter);
senorblanco@chromium.org97f5fc62014-05-30 20:50:56 +00001204 SkPictureRecorder outerRecorder;
1205 SkCanvas* outerCanvas = outerRecorder.beginRecording(1, 1, &factory, 0);
1206 SkPaint redPaintWithFilter;
1207 redPaintWithFilter.setColor(SK_ColorRED);
robertphillips5ff17b12016-03-28 13:13:42 -07001208 redPaintWithFilter.setImageFilter(imageFilter);
senorblanco@chromium.org97f5fc62014-05-30 20:50:56 +00001209 outerCanvas->drawRect(SkRect::Make(SkIRect::MakeWH(1, 1)), redPaintWithFilter);
reedca2622b2016-03-18 07:25:55 -07001210 sk_sp<SkPicture> outerPicture(outerRecorder.finishRecordingAsPicture());
senorblanco@chromium.org97f5fc62014-05-30 20:50:56 +00001211
1212 SkBitmap bitmap;
1213 bitmap.allocN32Pixels(1, 1);
robertphillips9a53fd72015-06-22 09:46:59 -07001214 SkCanvas canvas(bitmap);
senorblanco@chromium.org97f5fc62014-05-30 20:50:56 +00001215
1216 // The result here should be green, since the filter replaces the primitive's red interior.
1217 canvas.clear(0x0);
robertphillips9b14f262014-06-04 05:40:44 -07001218 canvas.drawPicture(outerPicture);
senorblanco@chromium.org97f5fc62014-05-30 20:50:56 +00001219 uint32_t pixel = *bitmap.getAddr32(0, 0);
1220 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1221
1222 // Check that, for now, SkPictureImageFilter does not serialize or
1223 // deserialize its contained picture when the filter is serialized
1224 // cross-process. Do this by "laundering" it through SkValidatingReadBuffer.
robertphillips12fa47d2016-04-08 16:28:09 -07001225 sk_sp<SkData> data(SkValidatingSerializeFlattenable(imageFilter.get()));
1226 sk_sp<SkFlattenable> flattenable(SkValidatingDeserializeFlattenable(
mtklein3b375452016-04-04 14:57:19 -07001227 data->data(), data->size(), SkImageFilter::GetFlattenableType()));
senorblanco@chromium.org97f5fc62014-05-30 20:50:56 +00001228 SkImageFilter* unflattenedFilter = static_cast<SkImageFilter*>(flattenable.get());
1229
1230 redPaintWithFilter.setImageFilter(unflattenedFilter);
1231 SkPictureRecorder crossProcessRecorder;
1232 SkCanvas* crossProcessCanvas = crossProcessRecorder.beginRecording(1, 1, &factory, 0);
1233 crossProcessCanvas->drawRect(SkRect::Make(SkIRect::MakeWH(1, 1)), redPaintWithFilter);
reedca2622b2016-03-18 07:25:55 -07001234 sk_sp<SkPicture> crossProcessPicture(crossProcessRecorder.finishRecordingAsPicture());
senorblanco@chromium.org97f5fc62014-05-30 20:50:56 +00001235
1236 canvas.clear(0x0);
robertphillips9b14f262014-06-04 05:40:44 -07001237 canvas.drawPicture(crossProcessPicture);
senorblanco@chromium.org97f5fc62014-05-30 20:50:56 +00001238 pixel = *bitmap.getAddr32(0, 0);
hendrikw446ee672015-06-16 09:28:37 -07001239 // If the security precautions are enabled, the result here should not be green, since the
1240 // filter draws nothing.
mtklein2afbe232016-02-07 12:23:10 -08001241 REPORTER_ASSERT(reporter, SkPicture::PictureIOSecurityPrecautionsEnabled()
hendrikw446ee672015-06-16 09:28:37 -07001242 ? pixel != SK_ColorGREEN : pixel == SK_ColorGREEN);
senorblanco@chromium.org97f5fc62014-05-30 20:50:56 +00001243}
1244
robertphillips3e302272016-04-20 11:48:36 -07001245static void test_clipped_picture_imagefilter(skiatest::Reporter* reporter, GrContext* context) {
reedca2622b2016-03-18 07:25:55 -07001246 sk_sp<SkPicture> picture;
senorblanco3d822c22014-07-30 14:49:31 -07001247
robertphillips4418dba2016-03-07 12:45:14 -08001248 {
1249 SkRTreeFactory factory;
1250 SkPictureRecorder recorder;
1251 SkCanvas* recordingCanvas = recorder.beginRecording(1, 1, &factory, 0);
1252
1253 // Create an SkPicture which simply draws a green 1x1 rectangle.
1254 SkPaint greenPaint;
1255 greenPaint.setColor(SK_ColorGREEN);
1256 recordingCanvas->drawRect(SkRect::Make(SkIRect::MakeWH(1, 1)), greenPaint);
reedca2622b2016-03-18 07:25:55 -07001257 picture = recorder.finishRecordingAsPicture();
robertphillips4418dba2016-03-07 12:45:14 -08001258 }
1259
robertphillips3e302272016-04-20 11:48:36 -07001260 sk_sp<SkSpecialImage> srcImg(create_empty_special_image(context, 2));
senorblanco3d822c22014-07-30 14:49:31 -07001261
robertphillips5ff17b12016-03-28 13:13:42 -07001262 sk_sp<SkImageFilter> imageFilter(SkPictureImageFilter::Make(picture));
senorblanco3d822c22014-07-30 14:49:31 -07001263
senorblanco3d822c22014-07-30 14:49:31 -07001264 SkIPoint offset;
reed4e23cda2016-01-11 10:56:59 -08001265 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeXYWH(1, 1, 1, 1), nullptr);
robertphillips4418dba2016-03-07 12:45:14 -08001266
robertphillips2302de92016-03-24 07:26:32 -07001267 sk_sp<SkSpecialImage> resultImage(imageFilter->filterImage(srcImg.get(), ctx, &offset));
robertphillips4418dba2016-03-07 12:45:14 -08001268 REPORTER_ASSERT(reporter, !resultImage);
senorblanco3d822c22014-07-30 14:49:31 -07001269}
1270
robertphillips4418dba2016-03-07 12:45:14 -08001271DEF_TEST(ImageFilterClippedPictureImageFilter, reporter) {
robertphillips3e302272016-04-20 11:48:36 -07001272 test_clipped_picture_imagefilter(reporter, nullptr);
robertphillips4418dba2016-03-07 12:45:14 -08001273}
1274
1275#if SK_SUPPORT_GPU
bsalomon68d91342016-04-12 09:59:58 -07001276DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterClippedPictureImageFilter_Gpu, reporter, ctxInfo) {
bsalomon8b7451a2016-05-11 06:33:06 -07001277 test_clipped_picture_imagefilter(reporter, ctxInfo.grContext());
robertphillips4418dba2016-03-07 12:45:14 -08001278}
1279#endif
1280
tfarina9ea53f92014-06-24 06:50:39 -07001281DEF_TEST(ImageFilterEmptySaveLayer, reporter) {
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001282 // Even when there's an empty saveLayer()/restore(), ensure that an image
1283 // filter or color filter which affects transparent black still draws.
1284
1285 SkBitmap bitmap;
1286 bitmap.allocN32Pixels(10, 10);
robertphillips9a53fd72015-06-22 09:46:59 -07001287 SkCanvas canvas(bitmap);
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001288
1289 SkRTreeFactory factory;
1290 SkPictureRecorder recorder;
1291
robertphillips5605b562016-04-05 11:50:42 -07001292 sk_sp<SkColorFilter> green(SkColorFilter::MakeModeFilter(SK_ColorGREEN,
1293 SkXfermode::kSrc_Mode));
1294 sk_sp<SkImageFilter> imageFilter(SkColorFilterImageFilter::Make(green, nullptr));
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001295 SkPaint imageFilterPaint;
robertphillips5605b562016-04-05 11:50:42 -07001296 imageFilterPaint.setImageFilter(std::move(imageFilter));
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001297 SkPaint colorFilterPaint;
reedd053ce92016-03-22 10:17:23 -07001298 colorFilterPaint.setColorFilter(green);
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001299
1300 SkRect bounds = SkRect::MakeWH(10, 10);
1301
1302 SkCanvas* recordingCanvas = recorder.beginRecording(10, 10, &factory, 0);
1303 recordingCanvas->saveLayer(&bounds, &imageFilterPaint);
1304 recordingCanvas->restore();
reedca2622b2016-03-18 07:25:55 -07001305 sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture());
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001306
1307 canvas.clear(0);
robertphillips9b14f262014-06-04 05:40:44 -07001308 canvas.drawPicture(picture);
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001309 uint32_t pixel = *bitmap.getAddr32(0, 0);
1310 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1311
1312 recordingCanvas = recorder.beginRecording(10, 10, &factory, 0);
halcanary96fcdcc2015-08-27 07:41:13 -07001313 recordingCanvas->saveLayer(nullptr, &imageFilterPaint);
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001314 recordingCanvas->restore();
reedca2622b2016-03-18 07:25:55 -07001315 sk_sp<SkPicture> picture2(recorder.finishRecordingAsPicture());
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001316
1317 canvas.clear(0);
robertphillips9b14f262014-06-04 05:40:44 -07001318 canvas.drawPicture(picture2);
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001319 pixel = *bitmap.getAddr32(0, 0);
1320 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1321
1322 recordingCanvas = recorder.beginRecording(10, 10, &factory, 0);
1323 recordingCanvas->saveLayer(&bounds, &colorFilterPaint);
1324 recordingCanvas->restore();
reedca2622b2016-03-18 07:25:55 -07001325 sk_sp<SkPicture> picture3(recorder.finishRecordingAsPicture());
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001326
1327 canvas.clear(0);
robertphillips9b14f262014-06-04 05:40:44 -07001328 canvas.drawPicture(picture3);
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001329 pixel = *bitmap.getAddr32(0, 0);
1330 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1331}
1332
robertphillips9a53fd72015-06-22 09:46:59 -07001333static void test_huge_blur(SkCanvas* canvas, skiatest::Reporter* reporter) {
senorblanco@chromium.org09843fd2014-03-24 20:50:59 +00001334 SkBitmap bitmap;
1335 bitmap.allocN32Pixels(100, 100);
1336 bitmap.eraseARGB(0, 0, 0, 0);
1337
1338 // Check that a blur with an insane radius does not crash or assert.
senorblanco@chromium.org09843fd2014-03-24 20:50:59 +00001339 SkPaint paint;
robertphillips6e7025a2016-04-04 04:31:25 -07001340 paint.setImageFilter(SkBlurImageFilter::Make(SkIntToScalar(1<<30),
1341 SkIntToScalar(1<<30),
1342 nullptr));
reedda420b92015-12-16 08:38:15 -08001343 canvas->drawBitmap(bitmap, 0, 0, &paint);
senorblanco@chromium.org09843fd2014-03-24 20:50:59 +00001344}
1345
1346DEF_TEST(HugeBlurImageFilter, reporter) {
1347 SkBitmap temp;
1348 temp.allocN32Pixels(100, 100);
robertphillips9a53fd72015-06-22 09:46:59 -07001349 SkCanvas canvas(temp);
1350 test_huge_blur(&canvas, reporter);
senorblanco@chromium.org09843fd2014-03-24 20:50:59 +00001351}
1352
senorblanco21a465d2016-04-11 11:58:39 -07001353DEF_TEST(ImageFilterMatrixConvolutionSanityTest, reporter) {
senorblanco3a495202014-09-29 07:57:20 -07001354 SkScalar kernel[1] = { 0 };
1355 SkScalar gain = SK_Scalar1, bias = 0;
1356 SkIPoint kernelOffset = SkIPoint::Make(1, 1);
1357
halcanary96fcdcc2015-08-27 07:41:13 -07001358 // Check that an enormous (non-allocatable) kernel gives a nullptr filter.
robertphillipsef6a47b2016-04-08 08:01:20 -07001359 sk_sp<SkImageFilter> conv(SkMatrixConvolutionImageFilter::Make(
senorblanco3a495202014-09-29 07:57:20 -07001360 SkISize::Make(1<<30, 1<<30),
1361 kernel,
1362 gain,
1363 bias,
1364 kernelOffset,
1365 SkMatrixConvolutionImageFilter::kRepeat_TileMode,
robertphillipsef6a47b2016-04-08 08:01:20 -07001366 false,
1367 nullptr));
senorblanco3a495202014-09-29 07:57:20 -07001368
halcanary96fcdcc2015-08-27 07:41:13 -07001369 REPORTER_ASSERT(reporter, nullptr == conv.get());
senorblanco3a495202014-09-29 07:57:20 -07001370
halcanary96fcdcc2015-08-27 07:41:13 -07001371 // Check that a nullptr kernel gives a nullptr filter.
robertphillipsef6a47b2016-04-08 08:01:20 -07001372 conv = SkMatrixConvolutionImageFilter::Make(
senorblanco3a495202014-09-29 07:57:20 -07001373 SkISize::Make(1, 1),
halcanary96fcdcc2015-08-27 07:41:13 -07001374 nullptr,
senorblanco3a495202014-09-29 07:57:20 -07001375 gain,
1376 bias,
1377 kernelOffset,
1378 SkMatrixConvolutionImageFilter::kRepeat_TileMode,
robertphillipsef6a47b2016-04-08 08:01:20 -07001379 false,
1380 nullptr);
senorblanco3a495202014-09-29 07:57:20 -07001381
halcanary96fcdcc2015-08-27 07:41:13 -07001382 REPORTER_ASSERT(reporter, nullptr == conv.get());
senorblanco3a495202014-09-29 07:57:20 -07001383
halcanary96fcdcc2015-08-27 07:41:13 -07001384 // Check that a kernel width < 1 gives a nullptr filter.
robertphillipsef6a47b2016-04-08 08:01:20 -07001385 conv = SkMatrixConvolutionImageFilter::Make(
senorblanco3a495202014-09-29 07:57:20 -07001386 SkISize::Make(0, 1),
1387 kernel,
1388 gain,
1389 bias,
1390 kernelOffset,
1391 SkMatrixConvolutionImageFilter::kRepeat_TileMode,
robertphillipsef6a47b2016-04-08 08:01:20 -07001392 false,
1393 nullptr);
senorblanco3a495202014-09-29 07:57:20 -07001394
halcanary96fcdcc2015-08-27 07:41:13 -07001395 REPORTER_ASSERT(reporter, nullptr == conv.get());
senorblanco3a495202014-09-29 07:57:20 -07001396
halcanary96fcdcc2015-08-27 07:41:13 -07001397 // Check that kernel height < 1 gives a nullptr filter.
robertphillipsef6a47b2016-04-08 08:01:20 -07001398 conv = SkMatrixConvolutionImageFilter::Make(
senorblanco3a495202014-09-29 07:57:20 -07001399 SkISize::Make(1, -1),
1400 kernel,
1401 gain,
1402 bias,
1403 kernelOffset,
1404 SkMatrixConvolutionImageFilter::kRepeat_TileMode,
robertphillipsef6a47b2016-04-08 08:01:20 -07001405 false,
1406 nullptr);
senorblanco3a495202014-09-29 07:57:20 -07001407
halcanary96fcdcc2015-08-27 07:41:13 -07001408 REPORTER_ASSERT(reporter, nullptr == conv.get());
senorblanco3a495202014-09-29 07:57:20 -07001409}
1410
robertphillips9a53fd72015-06-22 09:46:59 -07001411static void test_xfermode_cropped_input(SkCanvas* canvas, skiatest::Reporter* reporter) {
1412 canvas->clear(0);
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001413
1414 SkBitmap bitmap;
1415 bitmap.allocN32Pixels(1, 1);
1416 bitmap.eraseARGB(255, 255, 255, 255);
1417
robertphillips5605b562016-04-05 11:50:42 -07001418 sk_sp<SkColorFilter> green(SkColorFilter::MakeModeFilter(SK_ColorGREEN,
1419 SkXfermode::kSrcIn_Mode));
1420 sk_sp<SkImageFilter> greenFilter(SkColorFilterImageFilter::Make(green, nullptr));
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001421 SkImageFilter::CropRect cropRect(SkRect::MakeEmpty());
robertphillips5605b562016-04-05 11:50:42 -07001422 sk_sp<SkImageFilter> croppedOut(SkColorFilterImageFilter::Make(green, nullptr, &cropRect));
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001423
1424 // Check that an xfermode image filter whose input has been cropped out still draws the other
1425 // input. Also check that drawing with both inputs cropped out doesn't cause a GPU warning.
robertphillips8c0326d2016-04-05 12:48:34 -07001426 sk_sp<SkXfermode> mode(SkXfermode::Make(SkXfermode::kSrcOver_Mode));
1427 sk_sp<SkImageFilter> xfermodeNoFg(SkXfermodeImageFilter::Make(mode, greenFilter,
1428 croppedOut, nullptr));
1429 sk_sp<SkImageFilter> xfermodeNoBg(SkXfermodeImageFilter::Make(mode, croppedOut,
1430 greenFilter, nullptr));
1431 sk_sp<SkImageFilter> xfermodeNoFgNoBg(SkXfermodeImageFilter::Make(mode, croppedOut,
1432 croppedOut, nullptr));
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001433
1434 SkPaint paint;
robertphillips8c0326d2016-04-05 12:48:34 -07001435 paint.setImageFilter(std::move(xfermodeNoFg));
reedda420b92015-12-16 08:38:15 -08001436 canvas->drawBitmap(bitmap, 0, 0, &paint); // drawSprite
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001437
1438 uint32_t pixel;
kkinnunena9d9a392015-03-06 07:16:00 -08001439 SkImageInfo info = SkImageInfo::Make(1, 1, kBGRA_8888_SkColorType, kUnpremul_SkAlphaType);
robertphillips9a53fd72015-06-22 09:46:59 -07001440 canvas->readPixels(info, &pixel, 4, 0, 0);
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001441 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1442
robertphillips8c0326d2016-04-05 12:48:34 -07001443 paint.setImageFilter(std::move(xfermodeNoBg));
reedda420b92015-12-16 08:38:15 -08001444 canvas->drawBitmap(bitmap, 0, 0, &paint); // drawSprite
robertphillips9a53fd72015-06-22 09:46:59 -07001445 canvas->readPixels(info, &pixel, 4, 0, 0);
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001446 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1447
robertphillips8c0326d2016-04-05 12:48:34 -07001448 paint.setImageFilter(std::move(xfermodeNoFgNoBg));
reedda420b92015-12-16 08:38:15 -08001449 canvas->drawBitmap(bitmap, 0, 0, &paint); // drawSprite
robertphillips9a53fd72015-06-22 09:46:59 -07001450 canvas->readPixels(info, &pixel, 4, 0, 0);
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001451 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1452}
1453
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001454DEF_TEST(ImageFilterNestedSaveLayer, reporter) {
1455 SkBitmap temp;
1456 temp.allocN32Pixels(50, 50);
robertphillips9a53fd72015-06-22 09:46:59 -07001457 SkCanvas canvas(temp);
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001458 canvas.clear(0x0);
1459
1460 SkBitmap bitmap;
1461 bitmap.allocN32Pixels(10, 10);
1462 bitmap.eraseColor(SK_ColorGREEN);
1463
1464 SkMatrix matrix;
1465 matrix.setScale(SkIntToScalar(2), SkIntToScalar(2));
1466 matrix.postTranslate(SkIntToScalar(-20), SkIntToScalar(-20));
robertphillipsae8c9332016-04-05 15:09:00 -07001467 sk_sp<SkImageFilter> matrixFilter(
1468 SkImageFilter::MakeMatrixFilter(matrix, kLow_SkFilterQuality, nullptr));
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001469
1470 // Test that saveLayer() with a filter nested inside another saveLayer() applies the
1471 // correct offset to the filter matrix.
1472 SkRect bounds1 = SkRect::MakeXYWH(10, 10, 30, 30);
halcanary96fcdcc2015-08-27 07:41:13 -07001473 canvas.saveLayer(&bounds1, nullptr);
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001474 SkPaint filterPaint;
robertphillipsae8c9332016-04-05 15:09:00 -07001475 filterPaint.setImageFilter(std::move(matrixFilter));
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001476 SkRect bounds2 = SkRect::MakeXYWH(20, 20, 10, 10);
1477 canvas.saveLayer(&bounds2, &filterPaint);
1478 SkPaint greenPaint;
1479 greenPaint.setColor(SK_ColorGREEN);
1480 canvas.drawRect(bounds2, greenPaint);
1481 canvas.restore();
1482 canvas.restore();
1483 SkPaint strokePaint;
1484 strokePaint.setStyle(SkPaint::kStroke_Style);
1485 strokePaint.setColor(SK_ColorRED);
1486
kkinnunena9d9a392015-03-06 07:16:00 -08001487 SkImageInfo info = SkImageInfo::Make(1, 1, kBGRA_8888_SkColorType, kUnpremul_SkAlphaType);
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001488 uint32_t pixel;
1489 canvas.readPixels(info, &pixel, 4, 25, 25);
1490 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1491
1492 // Test that drawSprite() with a filter nested inside a saveLayer() applies the
1493 // correct offset to the filter matrix.
1494 canvas.clear(0x0);
1495 canvas.readPixels(info, &pixel, 4, 25, 25);
halcanary96fcdcc2015-08-27 07:41:13 -07001496 canvas.saveLayer(&bounds1, nullptr);
reedda420b92015-12-16 08:38:15 -08001497 canvas.drawBitmap(bitmap, 20, 20, &filterPaint); // drawSprite
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001498 canvas.restore();
1499
1500 canvas.readPixels(info, &pixel, 4, 25, 25);
1501 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1502}
1503
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001504DEF_TEST(XfermodeImageFilterCroppedInput, reporter) {
1505 SkBitmap temp;
1506 temp.allocN32Pixels(100, 100);
robertphillips9a53fd72015-06-22 09:46:59 -07001507 SkCanvas canvas(temp);
1508 test_xfermode_cropped_input(&canvas, reporter);
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001509}
senorblanco@chromium.org09843fd2014-03-24 20:50:59 +00001510
robertphillips3e302272016-04-20 11:48:36 -07001511static void test_composed_imagefilter_offset(skiatest::Reporter* reporter, GrContext* context) {
1512 sk_sp<SkSpecialImage> srcImg(create_empty_special_image(context, 100));
ajuma5788faa2015-02-13 09:05:47 -08001513
1514 SkImageFilter::CropRect cropRect(SkRect::MakeXYWH(1, 0, 20, 20));
robertphillips51a315e2016-03-31 09:05:49 -07001515 sk_sp<SkImageFilter> offsetFilter(SkOffsetImageFilter::Make(0, 0, nullptr, &cropRect));
robertphillips6e7025a2016-04-04 04:31:25 -07001516 sk_sp<SkImageFilter> blurFilter(SkBlurImageFilter::Make(SK_Scalar1, SK_Scalar1,
1517 nullptr, &cropRect));
robertphillips491fb172016-03-30 12:32:58 -07001518 sk_sp<SkImageFilter> composedFilter(SkComposeImageFilter::Make(std::move(blurFilter),
1519 std::move(offsetFilter)));
ajuma5788faa2015-02-13 09:05:47 -08001520 SkIPoint offset;
reed4e23cda2016-01-11 10:56:59 -08001521 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeWH(100, 100), nullptr);
robertphillips4418dba2016-03-07 12:45:14 -08001522
robertphillips2302de92016-03-24 07:26:32 -07001523 sk_sp<SkSpecialImage> resultImg(composedFilter->filterImage(srcImg.get(), ctx, &offset));
robertphillips4418dba2016-03-07 12:45:14 -08001524 REPORTER_ASSERT(reporter, resultImg);
ajuma5788faa2015-02-13 09:05:47 -08001525 REPORTER_ASSERT(reporter, offset.fX == 1 && offset.fY == 0);
1526}
1527
robertphillips4418dba2016-03-07 12:45:14 -08001528DEF_TEST(ComposedImageFilterOffset, reporter) {
robertphillips3e302272016-04-20 11:48:36 -07001529 test_composed_imagefilter_offset(reporter, nullptr);
robertphillips4418dba2016-03-07 12:45:14 -08001530}
1531
1532#if SK_SUPPORT_GPU
bsalomon68d91342016-04-12 09:59:58 -07001533DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ComposedImageFilterOffset_Gpu, reporter, ctxInfo) {
bsalomon8b7451a2016-05-11 06:33:06 -07001534 test_composed_imagefilter_offset(reporter, ctxInfo.grContext());
robertphillips4418dba2016-03-07 12:45:14 -08001535}
1536#endif
1537
robertphillips3e302272016-04-20 11:48:36 -07001538static void test_composed_imagefilter_bounds(skiatest::Reporter* reporter, GrContext* context) {
jbroman17a65202016-03-21 08:38:58 -07001539 // The bounds passed to the inner filter must be filtered by the outer
1540 // filter, so that the inner filter produces the pixels that the outer
1541 // filter requires as input. This matters if the outer filter moves pixels.
1542 // Here, accounting for the outer offset is necessary so that the green
1543 // pixels of the picture are not clipped.
1544
1545 SkPictureRecorder recorder;
1546 SkCanvas* recordingCanvas = recorder.beginRecording(SkRect::MakeWH(200, 100));
1547 recordingCanvas->clipRect(SkRect::MakeXYWH(100, 0, 100, 100));
1548 recordingCanvas->clear(SK_ColorGREEN);
robertphillips491fb172016-03-30 12:32:58 -07001549 sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture());
robertphillips5ff17b12016-03-28 13:13:42 -07001550 sk_sp<SkImageFilter> pictureFilter(SkPictureImageFilter::Make(picture));
jbroman17a65202016-03-21 08:38:58 -07001551 SkImageFilter::CropRect cropRect(SkRect::MakeWH(100, 100));
robertphillips51a315e2016-03-31 09:05:49 -07001552 sk_sp<SkImageFilter> offsetFilter(SkOffsetImageFilter::Make(-100, 0, nullptr, &cropRect));
robertphillips491fb172016-03-30 12:32:58 -07001553 sk_sp<SkImageFilter> composedFilter(SkComposeImageFilter::Make(std::move(offsetFilter),
1554 std::move(pictureFilter)));
jbroman17a65202016-03-21 08:38:58 -07001555
robertphillips3e302272016-04-20 11:48:36 -07001556 sk_sp<SkSpecialImage> sourceImage(create_empty_special_image(context, 100));
jbroman17a65202016-03-21 08:38:58 -07001557 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeWH(100, 100), nullptr);
1558 SkIPoint offset;
1559 sk_sp<SkSpecialImage> result(composedFilter->filterImage(sourceImage.get(), ctx, &offset));
1560 REPORTER_ASSERT(reporter, offset.isZero());
1561 REPORTER_ASSERT(reporter, result);
1562 REPORTER_ASSERT(reporter, result->subset().size() == SkISize::Make(100, 100));
1563
1564 SkBitmap resultBM;
robertphillips64612512016-04-08 12:10:42 -07001565 REPORTER_ASSERT(reporter, result->getROPixels(&resultBM));
jbroman17a65202016-03-21 08:38:58 -07001566 SkAutoLockPixels lock(resultBM);
1567 REPORTER_ASSERT(reporter, resultBM.getColor(50, 50) == SK_ColorGREEN);
1568}
1569
1570DEF_TEST(ComposedImageFilterBounds, reporter) {
robertphillips3e302272016-04-20 11:48:36 -07001571 test_composed_imagefilter_bounds(reporter, nullptr);
jbroman17a65202016-03-21 08:38:58 -07001572}
1573
1574#if SK_SUPPORT_GPU
egdanielab527a52016-06-28 08:07:26 -07001575DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ComposedImageFilterBounds_Gpu, reporter, ctxInfo) {
bsalomon8b7451a2016-05-11 06:33:06 -07001576 test_composed_imagefilter_bounds(reporter, ctxInfo.grContext());
jbroman17a65202016-03-21 08:38:58 -07001577}
1578#endif
1579
robertphillips3e302272016-04-20 11:48:36 -07001580static void test_partial_crop_rect(skiatest::Reporter* reporter, GrContext* context) {
1581 sk_sp<SkSpecialImage> srcImg(create_empty_special_image(context, 100));
senorblanco24d2a7b2015-07-13 10:27:05 -07001582
1583 SkImageFilter::CropRect cropRect(SkRect::MakeXYWH(100, 0, 20, 30),
senorblancoed7cf272015-07-16 15:19:11 -07001584 SkImageFilter::CropRect::kHasWidth_CropEdge | SkImageFilter::CropRect::kHasHeight_CropEdge);
robertphillips5605b562016-04-05 11:50:42 -07001585 sk_sp<SkImageFilter> filter(make_grayscale(nullptr, &cropRect));
senorblanco24d2a7b2015-07-13 10:27:05 -07001586 SkIPoint offset;
reed4e23cda2016-01-11 10:56:59 -08001587 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeWH(100, 100), nullptr);
robertphillips4418dba2016-03-07 12:45:14 -08001588
robertphillips2302de92016-03-24 07:26:32 -07001589 sk_sp<SkSpecialImage> resultImg(filter->filterImage(srcImg.get(), ctx, &offset));
robertphillips4418dba2016-03-07 12:45:14 -08001590 REPORTER_ASSERT(reporter, resultImg);
1591
senorblanco24d2a7b2015-07-13 10:27:05 -07001592 REPORTER_ASSERT(reporter, offset.fX == 0);
1593 REPORTER_ASSERT(reporter, offset.fY == 0);
robertphillips4418dba2016-03-07 12:45:14 -08001594 REPORTER_ASSERT(reporter, resultImg->width() == 20);
1595 REPORTER_ASSERT(reporter, resultImg->height() == 30);
senorblanco24d2a7b2015-07-13 10:27:05 -07001596}
1597
senorblanco21a465d2016-04-11 11:58:39 -07001598DEF_TEST(ImageFilterPartialCropRect, reporter) {
robertphillips3e302272016-04-20 11:48:36 -07001599 test_partial_crop_rect(reporter, nullptr);
robertphillips4418dba2016-03-07 12:45:14 -08001600}
1601
1602#if SK_SUPPORT_GPU
bsalomon68d91342016-04-12 09:59:58 -07001603DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterPartialCropRect_Gpu, reporter, ctxInfo) {
bsalomon8b7451a2016-05-11 06:33:06 -07001604 test_partial_crop_rect(reporter, ctxInfo.grContext());
robertphillips4418dba2016-03-07 12:45:14 -08001605}
1606#endif
1607
senorblanco0abdf762015-08-20 11:10:41 -07001608DEF_TEST(ImageFilterCanComputeFastBounds, reporter) {
1609
robertphillips12fa47d2016-04-08 16:28:09 -07001610 {
1611 SkPoint3 location = SkPoint3::Make(0, 0, SK_Scalar1);
1612 sk_sp<SkImageFilter> lighting(SkLightingImageFilter::MakePointLitDiffuse(location,
1613 SK_ColorGREEN,
1614 0, 0, nullptr));
1615 REPORTER_ASSERT(reporter, !lighting->canComputeFastBounds());
1616 }
senorblanco0abdf762015-08-20 11:10:41 -07001617
senorblanco0abdf762015-08-20 11:10:41 -07001618 {
robertphillips6e7025a2016-04-04 04:31:25 -07001619 sk_sp<SkImageFilter> gray(make_grayscale(nullptr, nullptr));
1620 REPORTER_ASSERT(reporter, gray->canComputeFastBounds());
1621 {
1622 SkColorFilter* grayCF;
1623 REPORTER_ASSERT(reporter, gray->asAColorFilter(&grayCF));
1624 REPORTER_ASSERT(reporter, !grayCF->affectsTransparentBlack());
1625 grayCF->unref();
1626 }
1627 REPORTER_ASSERT(reporter, gray->canComputeFastBounds());
1628
1629 sk_sp<SkImageFilter> grayBlur(SkBlurImageFilter::Make(SK_Scalar1, SK_Scalar1,
1630 std::move(gray)));
1631 REPORTER_ASSERT(reporter, grayBlur->canComputeFastBounds());
senorblanco0abdf762015-08-20 11:10:41 -07001632 }
senorblanco0abdf762015-08-20 11:10:41 -07001633
robertphillips6e7025a2016-04-04 04:31:25 -07001634 {
1635 SkScalar greenMatrix[20] = { 0, 0, 0, 0, 0,
1636 0, 0, 0, 0, 1,
1637 0, 0, 0, 0, 0,
1638 0, 0, 0, 0, 1 };
1639 sk_sp<SkColorFilter> greenCF(SkColorFilter::MakeMatrixFilterRowMajor255(greenMatrix));
robertphillips5605b562016-04-05 11:50:42 -07001640 sk_sp<SkImageFilter> green(SkColorFilterImageFilter::Make(greenCF, nullptr));
senorblanco0abdf762015-08-20 11:10:41 -07001641
robertphillips6e7025a2016-04-04 04:31:25 -07001642 REPORTER_ASSERT(reporter, greenCF->affectsTransparentBlack());
1643 REPORTER_ASSERT(reporter, !green->canComputeFastBounds());
senorblanco0abdf762015-08-20 11:10:41 -07001644
robertphillips6e7025a2016-04-04 04:31:25 -07001645 sk_sp<SkImageFilter> greenBlur(SkBlurImageFilter::Make(SK_Scalar1, SK_Scalar1,
1646 std::move(green)));
1647 REPORTER_ASSERT(reporter, !greenBlur->canComputeFastBounds());
1648 }
senorblanco0abdf762015-08-20 11:10:41 -07001649
1650 uint8_t allOne[256], identity[256];
1651 for (int i = 0; i < 256; ++i) {
1652 identity[i] = i;
1653 allOne[i] = 255;
1654 }
1655
robertphillips5605b562016-04-05 11:50:42 -07001656 sk_sp<SkColorFilter> identityCF(SkTableColorFilter::MakeARGB(identity, identity,
1657 identity, allOne));
1658 sk_sp<SkImageFilter> identityFilter(SkColorFilterImageFilter::Make(identityCF, nullptr));
senorblanco0abdf762015-08-20 11:10:41 -07001659 REPORTER_ASSERT(reporter, !identityCF->affectsTransparentBlack());
1660 REPORTER_ASSERT(reporter, identityFilter->canComputeFastBounds());
1661
robertphillips5605b562016-04-05 11:50:42 -07001662 sk_sp<SkColorFilter> forceOpaqueCF(SkTableColorFilter::MakeARGB(allOne, identity,
1663 identity, identity));
1664 sk_sp<SkImageFilter> forceOpaque(SkColorFilterImageFilter::Make(forceOpaqueCF, nullptr));
senorblanco0abdf762015-08-20 11:10:41 -07001665 REPORTER_ASSERT(reporter, forceOpaqueCF->affectsTransparentBlack());
1666 REPORTER_ASSERT(reporter, !forceOpaque->canComputeFastBounds());
1667}
1668
fmalitacd56f812015-09-14 13:31:18 -07001669// Verify that SkImageSource survives serialization
1670DEF_TEST(ImageFilterImageSourceSerialization, reporter) {
reede8f30622016-03-23 18:59:25 -07001671 auto surface(SkSurface::MakeRasterN32Premul(10, 10));
fmalitacd56f812015-09-14 13:31:18 -07001672 surface->getCanvas()->clear(SK_ColorGREEN);
reed9ce9d672016-03-17 10:51:11 -07001673 sk_sp<SkImage> image(surface->makeImageSnapshot());
robertphillips549c8992016-04-01 09:28:51 -07001674 sk_sp<SkImageFilter> filter(SkImageSource::Make(std::move(image)));
fmalitacd56f812015-09-14 13:31:18 -07001675
robertphillips549c8992016-04-01 09:28:51 -07001676 sk_sp<SkData> data(SkValidatingSerializeFlattenable(filter.get()));
1677 sk_sp<SkFlattenable> flattenable(SkValidatingDeserializeFlattenable(
mtklein3b375452016-04-04 14:57:19 -07001678 data->data(), data->size(), SkImageFilter::GetFlattenableType()));
fmalitacd56f812015-09-14 13:31:18 -07001679 SkImageFilter* unflattenedFilter = static_cast<SkImageFilter*>(flattenable.get());
1680 REPORTER_ASSERT(reporter, unflattenedFilter);
1681
1682 SkBitmap bm;
1683 bm.allocN32Pixels(10, 10);
fmalita23cb88c2015-09-15 06:56:23 -07001684 bm.eraseColor(SK_ColorBLUE);
fmalitacd56f812015-09-14 13:31:18 -07001685 SkPaint paint;
1686 paint.setColor(SK_ColorRED);
1687 paint.setImageFilter(unflattenedFilter);
1688
1689 SkCanvas canvas(bm);
1690 canvas.drawRect(SkRect::MakeWH(10, 10), paint);
1691 REPORTER_ASSERT(reporter, *bm.getAddr32(0, 0) == SkPreMultiplyColor(SK_ColorGREEN));
1692}
1693
bsalomon45eefcf2016-01-05 08:39:28 -08001694static void test_large_blur_input(skiatest::Reporter* reporter, SkCanvas* canvas) {
1695 SkBitmap largeBmp;
1696 int largeW = 5000;
1697 int largeH = 5000;
1698#if SK_SUPPORT_GPU
1699 // If we're GPU-backed make the bitmap too large to be converted into a texture.
1700 if (GrContext* ctx = canvas->getGrContext()) {
1701 largeW = ctx->caps()->maxTextureSize() + 1;
1702 }
1703#endif
1704
1705 largeBmp.allocN32Pixels(largeW, largeH);
mtklein2afbe232016-02-07 12:23:10 -08001706 largeBmp.eraseColor(0);
bsalomon45eefcf2016-01-05 08:39:28 -08001707 if (!largeBmp.getPixels()) {
1708 ERRORF(reporter, "Failed to allocate large bmp.");
1709 return;
1710 }
1711
reed9ce9d672016-03-17 10:51:11 -07001712 sk_sp<SkImage> largeImage(SkImage::MakeFromBitmap(largeBmp));
bsalomon45eefcf2016-01-05 08:39:28 -08001713 if (!largeImage) {
1714 ERRORF(reporter, "Failed to create large image.");
1715 return;
1716 }
1717
robertphillips549c8992016-04-01 09:28:51 -07001718 sk_sp<SkImageFilter> largeSource(SkImageSource::Make(std::move(largeImage)));
bsalomon45eefcf2016-01-05 08:39:28 -08001719 if (!largeSource) {
1720 ERRORF(reporter, "Failed to create large SkImageSource.");
1721 return;
1722 }
1723
robertphillips6e7025a2016-04-04 04:31:25 -07001724 sk_sp<SkImageFilter> blur(SkBlurImageFilter::Make(10.f, 10.f, std::move(largeSource)));
bsalomon45eefcf2016-01-05 08:39:28 -08001725 if (!blur) {
1726 ERRORF(reporter, "Failed to create SkBlurImageFilter.");
1727 return;
1728 }
1729
1730 SkPaint paint;
robertphillips549c8992016-04-01 09:28:51 -07001731 paint.setImageFilter(std::move(blur));
bsalomon45eefcf2016-01-05 08:39:28 -08001732
1733 // This should not crash (http://crbug.com/570479).
1734 canvas->drawRect(SkRect::MakeIWH(largeW, largeH), paint);
1735}
1736
senorblanco21a465d2016-04-11 11:58:39 -07001737DEF_TEST(ImageFilterBlurLargeImage, reporter) {
reede8f30622016-03-23 18:59:25 -07001738 auto surface(SkSurface::MakeRaster(SkImageInfo::MakeN32Premul(100, 100)));
bsalomon45eefcf2016-01-05 08:39:28 -08001739 test_large_blur_input(reporter, surface->getCanvas());
1740}
1741
senorblanco5878dbd2016-05-19 14:50:29 -07001742static void test_make_with_filter(skiatest::Reporter* reporter, GrContext* context) {
1743 sk_sp<SkSurface> surface(create_surface(context, 100, 100));
1744 surface->getCanvas()->clear(SK_ColorRED);
1745 SkPaint bluePaint;
1746 bluePaint.setColor(SK_ColorBLUE);
1747 SkIRect subset = SkIRect::MakeXYWH(25, 20, 50, 50);
1748 surface->getCanvas()->drawRect(SkRect::Make(subset), bluePaint);
1749 sk_sp<SkImage> sourceImage = surface->makeImageSnapshot();
1750
1751 sk_sp<SkImageFilter> filter = make_grayscale(nullptr, nullptr);
1752 SkIRect clipBounds = SkIRect::MakeXYWH(30, 35, 100, 100);
1753 SkIRect outSubset;
1754 SkIPoint offset;
1755 sk_sp<SkImage> result;
1756
1757 result = sourceImage->makeWithFilter(nullptr, subset, clipBounds, &outSubset, &offset);
1758 REPORTER_ASSERT(reporter, !result);
1759
1760 result = sourceImage->makeWithFilter(filter.get(), subset, clipBounds, nullptr, &offset);
1761 REPORTER_ASSERT(reporter, !result);
1762
1763 result = sourceImage->makeWithFilter(filter.get(), subset, clipBounds, &outSubset, nullptr);
1764 REPORTER_ASSERT(reporter, !result);
1765
1766 SkIRect bigSubset = SkIRect::MakeXYWH(-10000, -10000, 20000, 20000);
1767 result = sourceImage->makeWithFilter(filter.get(), bigSubset, clipBounds, &outSubset, &offset);
1768 REPORTER_ASSERT(reporter, !result);
1769
1770 SkIRect empty = SkIRect::MakeEmpty();
1771 result = sourceImage->makeWithFilter(filter.get(), empty, clipBounds, &outSubset, &offset);
1772 REPORTER_ASSERT(reporter, !result);
1773
1774 result = sourceImage->makeWithFilter(filter.get(), subset, empty, &outSubset, &offset);
1775 REPORTER_ASSERT(reporter, !result);
1776
1777 SkIRect leftField = SkIRect::MakeXYWH(-1000, 0, 100, 100);
1778 result = sourceImage->makeWithFilter(filter.get(), subset, leftField, &outSubset, &offset);
1779 REPORTER_ASSERT(reporter, !result);
1780
1781 result = sourceImage->makeWithFilter(filter.get(), subset, clipBounds, &outSubset, &offset);
1782
1783 REPORTER_ASSERT(reporter, result);
1784 REPORTER_ASSERT(reporter, result->bounds().contains(outSubset));
1785 SkIRect destRect = SkIRect::MakeXYWH(offset.x(), offset.y(),
1786 outSubset.width(), outSubset.height());
1787 REPORTER_ASSERT(reporter, clipBounds.contains(destRect));
1788}
1789
1790DEF_TEST(ImageFilterMakeWithFilter, reporter) {
1791 test_make_with_filter(reporter, nullptr);
1792}
1793
1794#if SK_SUPPORT_GPU
1795DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterMakeWithFilter_Gpu, reporter, ctxInfo) {
1796 test_make_with_filter(reporter, ctxInfo.grContext());
1797}
1798#endif
1799
senorblanco@chromium.org58d14662014-02-03 22:36:39 +00001800#if SK_SUPPORT_GPU
reed4a8126e2014-09-22 07:29:03 -07001801
bsalomon68d91342016-04-12 09:59:58 -07001802DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterHugeBlur_Gpu, reporter, ctxInfo) {
robertphillipsefbffed2015-06-22 12:06:08 -07001803
bsalomon8b7451a2016-05-11 06:33:06 -07001804 sk_sp<SkSurface> surf(SkSurface::MakeRenderTarget(ctxInfo.grContext(),
robertphillips3e302272016-04-20 11:48:36 -07001805 SkBudgeted::kNo,
1806 SkImageInfo::MakeN32Premul(100, 100)));
robertphillips9a53fd72015-06-22 09:46:59 -07001807
robertphillips3e302272016-04-20 11:48:36 -07001808
1809 SkCanvas* canvas = surf->getCanvas();
1810
1811 test_huge_blur(canvas, reporter);
senorblanco@chromium.org09843fd2014-03-24 20:50:59 +00001812}
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001813
egdanielab527a52016-06-28 08:07:26 -07001814DEF_GPUTEST_FOR_RENDERING_CONTEXTS(XfermodeImageFilterCroppedInput_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(1, 1)));
robertphillips9a53fd72015-06-22 09:46:59 -07001819
robertphillips3e302272016-04-20 11:48:36 -07001820
1821 SkCanvas* canvas = surf->getCanvas();
1822
1823 test_xfermode_cropped_input(canvas, reporter);
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001824}
senorblanco32673b92014-09-09 09:15:04 -07001825
egdanielab527a52016-06-28 08:07:26 -07001826DEF_GPUTEST_FOR_ALL_CONTEXTS(ImageFilterBlurLargeImage_Gpu, reporter, ctxInfo) {
bsalomon8b7451a2016-05-11 06:33:06 -07001827 auto surface(SkSurface::MakeRenderTarget(ctxInfo.grContext(), SkBudgeted::kYes,
reede8f30622016-03-23 18:59:25 -07001828 SkImageInfo::MakeN32Premul(100, 100)));
bsalomon45eefcf2016-01-05 08:39:28 -08001829 test_large_blur_input(reporter, surface->getCanvas());
1830}
senorblanco@chromium.org58d14662014-02-03 22:36:39 +00001831#endif
reedbb34a8a2016-04-23 15:19:07 -07001832
1833/*
1834 * Test that colorfilterimagefilter does not require its CTM to be decomposed when it has more
1835 * than just scale/translate, but that other filters do.
1836 */
reed96a04f32016-04-25 09:25:15 -07001837DEF_TEST(ImageFilterComplexCTM, reporter) {
reedbb34a8a2016-04-23 15:19:07 -07001838 // just need a colorfilter to exercise the corresponding imagefilter
1839 sk_sp<SkColorFilter> cf = SkColorFilter::MakeModeFilter(SK_ColorRED, SkXfermode::kSrcATop_Mode);
reed96a04f32016-04-25 09:25:15 -07001840 sk_sp<SkImageFilter> cfif = SkColorFilterImageFilter::Make(cf, nullptr); // can handle
1841 sk_sp<SkImageFilter> blif = SkBlurImageFilter::Make(3, 3, nullptr); // cannot handle
reedbb34a8a2016-04-23 15:19:07 -07001842
1843 struct {
1844 sk_sp<SkImageFilter> fFilter;
1845 bool fExpectCanHandle;
1846 } recs[] = {
1847 { cfif, true },
1848 { SkColorFilterImageFilter::Make(cf, cfif), true },
1849 { SkMergeImageFilter::Make(cfif, cfif), true },
reed96a04f32016-04-25 09:25:15 -07001850 { SkComposeImageFilter::Make(cfif, cfif), true },
1851
reedbb34a8a2016-04-23 15:19:07 -07001852 { blif, false },
reed96a04f32016-04-25 09:25:15 -07001853 { SkBlurImageFilter::Make(3, 3, cfif), false },
reedbb34a8a2016-04-23 15:19:07 -07001854 { SkColorFilterImageFilter::Make(cf, blif), false },
reed96a04f32016-04-25 09:25:15 -07001855 { SkMergeImageFilter::Make(cfif, blif), false },
1856 { SkComposeImageFilter::Make(blif, cfif), false },
reedbb34a8a2016-04-23 15:19:07 -07001857 };
1858
1859 for (const auto& rec : recs) {
reed96a04f32016-04-25 09:25:15 -07001860 const bool canHandle = rec.fFilter->canHandleComplexCTM();
reedbb34a8a2016-04-23 15:19:07 -07001861 REPORTER_ASSERT(reporter, canHandle == rec.fExpectCanHandle);
1862 }
1863}