blob: 4ef7d4033a897b0ed4cffa29a092f3d437991db5 [file] [log] [blame]
commit-bot@chromium.org22d69f92013-09-19 18:40:49 +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#include "SampleCode.h"
8#include "SkBicubicImageFilter.h"
commit-bot@chromium.org77e079a2013-10-28 15:52:02 +00009#include "SkBitmapDevice.h"
commit-bot@chromium.org22d69f92013-09-19 18:40:49 +000010#include "SkBitmapSource.h"
11#include "SkBlurImageFilter.h"
12#include "SkCanvas.h"
13#include "SkColorFilter.h"
14#include "SkColorFilterImageFilter.h"
15#include "SkComposeImageFilter.h"
commit-bot@chromium.org77e079a2013-10-28 15:52:02 +000016#include "SkData.h"
commit-bot@chromium.org22d69f92013-09-19 18:40:49 +000017#include "SkDisplacementMapEffect.h"
18#include "SkDropShadowImageFilter.h"
19#include "SkFlattenableSerialization.h"
20#include "SkLightingImageFilter.h"
21#include "SkMagnifierImageFilter.h"
22#include "SkMergeImageFilter.h"
23#include "SkMorphologyImageFilter.h"
24#include "SkOffsetImageFilter.h"
25#include "SkPerlinNoiseShader.h"
commit-bot@chromium.org7b8d72d2014-01-16 22:54:41 +000026#include "SkPictureImageFilter.h"
commit-bot@chromium.org22d69f92013-09-19 18:40:49 +000027#include "SkRandom.h"
28#include "SkRectShaderImageFilter.h"
commit-bot@chromium.orgcd3b15c2013-12-04 17:06:49 +000029#include "SkTileImageFilter.h"
commit-bot@chromium.org22d69f92013-09-19 18:40:49 +000030#include "SkView.h"
31#include "SkXfermodeImageFilter.h"
commit-bot@chromium.orgcd3b15c2013-12-04 17:06:49 +000032#include <stdio.h>
33#include <time.h>
commit-bot@chromium.org22d69f92013-09-19 18:40:49 +000034
commit-bot@chromium.orgc2e9db32013-12-06 20:14:46 +000035//#define SK_ADD_RANDOM_BIT_FLIPS
36//#define SK_FUZZER_IS_VERBOSE
37
commit-bot@chromium.orgcd3b15c2013-12-04 17:06:49 +000038static const uint32_t kSeed = (uint32_t)(time(NULL));
commit-bot@chromium.org22d69f92013-09-19 18:40:49 +000039static SkRandom gRand(kSeed);
40static bool return_large = false;
41static bool return_undef = false;
42
43static const int kBitmapSize = 24;
44
45static int R(float x) {
46 return (int)floor(SkScalarToFloat(gRand.nextUScalar1()) * x);
47}
48
49#if defined _WIN32
50#pragma warning ( push )
51// we are intentionally causing an overflow here
52// (warning C4756: overflow in constant arithmetic)
53#pragma warning ( disable : 4756 )
54#endif
55
56static float huge() {
57 double d = 1e100;
58 float f = (float)d;
59 return f;
60}
61
62#if defined _WIN32
63#pragma warning ( pop )
64#endif
65
66static float make_number(bool positiveOnly) {
67 float f = positiveOnly ? 1.0f : 0.0f;
68 float v = f;
69 int sel;
70
71 if (return_large) sel = R(6); else sel = R(4);
72 if (!return_undef && sel == 0) sel = 1;
73
74 if (R(2) == 1) v = (float)(R(100)+f); else
75
76 switch (sel) {
77 case 0: break;
78 case 1: v = f; break;
79 case 2: v = 0.000001f; break;
80 case 3: v = 10000.0f; break;
81 case 4: v = 2000000000.0f; break;
82 case 5: v = huge(); break;
83 }
84
85 if (!positiveOnly && (R(4) == 1)) v = -v;
86 return v;
87}
88
89static SkScalar make_scalar(bool positiveOnly = false) {
commit-bot@chromium.org4b413c82013-11-25 19:44:07 +000090 return make_number(positiveOnly);
commit-bot@chromium.org22d69f92013-09-19 18:40:49 +000091}
92
commit-bot@chromium.orgcd3b15c2013-12-04 17:06:49 +000093static SkRect make_rect() {
94 return SkRect::MakeWH(SkIntToScalar(R(static_cast<float>(kBitmapSize))),
95 SkIntToScalar(R(static_cast<float>(kBitmapSize))));
commit-bot@chromium.org22d69f92013-09-19 18:40:49 +000096}
97
98static SkXfermode::Mode make_xfermode() {
99 return static_cast<SkXfermode::Mode>(R(SkXfermode::kLastMode+1));
100}
101
102static SkColor make_color() {
103 return (R(2) == 1) ? 0xFFC0F0A0 : 0xFF000090;
104}
105
106static SkPoint3 make_point() {
107 return SkPoint3(make_scalar(), make_scalar(), make_scalar(true));
108}
109
110static SkDisplacementMapEffect::ChannelSelectorType make_channel_selector_type() {
111 return static_cast<SkDisplacementMapEffect::ChannelSelectorType>(R(4)+1);
112}
113
114static void make_g_bitmap(SkBitmap& bitmap) {
commit-bot@chromium.orgef74fa12013-12-17 20:49:46 +0000115 bitmap.setConfig((SkBitmap::Config)R(SkBitmap::kConfigCount), kBitmapSize, kBitmapSize);
116 while (!bitmap.allocPixels()) {
117 bitmap.setConfig((SkBitmap::Config)R(SkBitmap::kConfigCount), kBitmapSize, kBitmapSize);
118 }
commit-bot@chromium.org22d69f92013-09-19 18:40:49 +0000119 SkBitmapDevice device(bitmap);
120 SkCanvas canvas(&device);
121 canvas.clear(0x00000000);
122 SkPaint paint;
123 paint.setAntiAlias(true);
124 paint.setColor(0xFF884422);
125 paint.setTextSize(SkIntToScalar(kBitmapSize/2));
126 const char* str = "g";
127 canvas.drawText(str, strlen(str), SkIntToScalar(kBitmapSize/8),
128 SkIntToScalar(kBitmapSize/4), paint);
129}
130
reed@google.com6fcd28b2014-02-04 16:03:51 +0000131static bool valid_for_raster_canvas(const SkBitmap& bm) {
132 SkImageInfo info;
133 if (!bm.asImageInfo(&info)) {
134 return false;
135 }
136 switch (info.fColorType) {
137 case kAlpha_8_SkColorType:
138 case kRGB_565_SkColorType:
139 return true;
140 case kPMColor_SkColorType:
141 return kPremul_SkAlphaType == info.fAlphaType ||
142 kOpaque_SkAlphaType == info.fAlphaType;
143 default:
144 break;
145 }
146 return false;
147}
148
commit-bot@chromium.org22d69f92013-09-19 18:40:49 +0000149static void make_checkerboard_bitmap(SkBitmap& bitmap) {
commit-bot@chromium.orgef74fa12013-12-17 20:49:46 +0000150 bitmap.setConfig((SkBitmap::Config)R(SkBitmap::kConfigCount), kBitmapSize, kBitmapSize);
reed@google.com6fcd28b2014-02-04 16:03:51 +0000151 while (valid_for_raster_canvas(bitmap) && !bitmap.allocPixels()) {
commit-bot@chromium.orgef74fa12013-12-17 20:49:46 +0000152 bitmap.setConfig((SkBitmap::Config)R(SkBitmap::kConfigCount), kBitmapSize, kBitmapSize);
153 }
commit-bot@chromium.org22d69f92013-09-19 18:40:49 +0000154 SkBitmapDevice device(bitmap);
155 SkCanvas canvas(&device);
156 canvas.clear(0x00000000);
157 SkPaint darkPaint;
158 darkPaint.setColor(0xFF804020);
159 SkPaint lightPaint;
160 lightPaint.setColor(0xFF244484);
161 const int i = kBitmapSize / 8;
162 const SkScalar f = SkIntToScalar(i);
163 for (int y = 0; y < kBitmapSize; y += i) {
164 for (int x = 0; x < kBitmapSize; x += i) {
165 canvas.save();
166 canvas.translate(SkIntToScalar(x), SkIntToScalar(y));
167 canvas.drawRect(SkRect::MakeXYWH(0, 0, f, f), darkPaint);
168 canvas.drawRect(SkRect::MakeXYWH(f, 0, f, f), lightPaint);
169 canvas.drawRect(SkRect::MakeXYWH(0, f, f, f), lightPaint);
170 canvas.drawRect(SkRect::MakeXYWH(f, f, f, f), darkPaint);
171 canvas.restore();
172 }
173 }
174}
175
176static const SkBitmap& make_bitmap() {
177 static SkBitmap bitmap[2];
178 static bool initialized = false;
179 if (!initialized) {
180 make_g_bitmap(bitmap[0]);
181 make_checkerboard_bitmap(bitmap[1]);
182 initialized = true;
183 }
184 return bitmap[R(2)];
185}
186
commit-bot@chromium.org5e0995e2014-02-07 12:20:04 +0000187#ifdef SK_ALLOW_PICTUREIMAGEFILTER_SERIALIZATION
188static void drawSomething(SkCanvas* canvas) {
189 SkPaint paint;
190
191 canvas->save();
192 canvas->scale(0.5f, 0.5f);
193 canvas->drawBitmap(make_bitmap(), 0, 0, NULL);
194 canvas->restore();
195
196 const char beforeStr[] = "before circle";
197 const char afterStr[] = "after circle";
198
199 paint.setAntiAlias(true);
200
201 paint.setColor(SK_ColorRED);
202 canvas->drawData(beforeStr, sizeof(beforeStr));
203 canvas->drawCircle(SkIntToScalar(kBitmapSize/2), SkIntToScalar(kBitmapSize/2), SkIntToScalar(kBitmapSize/3), paint);
204 canvas->drawData(afterStr, sizeof(afterStr));
205 paint.setColor(SK_ColorBLACK);
206 paint.setTextSize(SkIntToScalar(kBitmapSize/3));
207 canvas->drawText("Picture", 7, SkIntToScalar(kBitmapSize/2), SkIntToScalar(kBitmapSize/4), paint);
208}
209#endif
210
commit-bot@chromium.org22d69f92013-09-19 18:40:49 +0000211static SkImageFilter* make_image_filter(bool canBeNull = true) {
212 SkImageFilter* filter = 0;
213
214 // Add a 1 in 3 chance to get a NULL input
215 if (canBeNull && (R(3) == 1)) { return filter; }
216
217 enum { BICUBIC, MERGE, COLOR, BLUR, MAGNIFIER, XFERMODE, OFFSET, COMPOSE,
218 DISTANT_LIGHT, POINT_LIGHT, SPOT_LIGHT, NOISE, DROP_SHADOW,
commit-bot@chromium.org7b8d72d2014-01-16 22:54:41 +0000219 MORPHOLOGY, BITMAP, DISPLACE, TILE, PICTURE, NUM_FILTERS };
commit-bot@chromium.org22d69f92013-09-19 18:40:49 +0000220
221 switch (R(NUM_FILTERS)) {
222 case BICUBIC:
223 // Scale is set to 1 here so that it can fit in the DAG without resizing the output
224 filter = SkBicubicImageFilter::CreateMitchell(SkSize::Make(1, 1), make_image_filter());
225 break;
226 case MERGE:
227 filter = new SkMergeImageFilter(make_image_filter(), make_image_filter(), make_xfermode());
228 break;
229 case COLOR:
230 {
231 SkAutoTUnref<SkColorFilter> cf((R(2) == 1) ?
232 SkColorFilter::CreateModeFilter(make_color(), make_xfermode()) :
233 SkColorFilter::CreateLightingFilter(make_color(), make_color()));
234 filter = cf.get() ? SkColorFilterImageFilter::Create(cf, make_image_filter()) : 0;
235 }
236 break;
237 case BLUR:
238 filter = new SkBlurImageFilter(make_scalar(true), make_scalar(true), make_image_filter());
239 break;
240 case MAGNIFIER:
commit-bot@chromium.orgcd3b15c2013-12-04 17:06:49 +0000241 filter = new SkMagnifierImageFilter(make_rect(), make_scalar(true));
commit-bot@chromium.org22d69f92013-09-19 18:40:49 +0000242 break;
243 case XFERMODE:
244 {
245 SkAutoTUnref<SkXfermode> mode(SkXfermode::Create(make_xfermode()));
246 filter = new SkXfermodeImageFilter(mode, make_image_filter(), make_image_filter());
247 }
248 break;
249 case OFFSET:
250 filter = new SkOffsetImageFilter(make_scalar(), make_scalar(), make_image_filter());
251 break;
252 case COMPOSE:
253 filter = new SkComposeImageFilter(make_image_filter(), make_image_filter());
254 break;
255 case DISTANT_LIGHT:
256 filter = (R(2) == 1) ?
257 SkLightingImageFilter::CreateDistantLitDiffuse(make_point(),
258 make_color(), make_scalar(), make_scalar(), make_image_filter()) :
259 SkLightingImageFilter::CreateDistantLitSpecular(make_point(),
260 make_color(), make_scalar(), make_scalar(), SkIntToScalar(R(10)),
261 make_image_filter());
262 break;
263 case POINT_LIGHT:
264 filter = (R(2) == 1) ?
265 SkLightingImageFilter::CreatePointLitDiffuse(make_point(),
266 make_color(), make_scalar(), make_scalar(), make_image_filter()) :
267 SkLightingImageFilter::CreatePointLitSpecular(make_point(),
268 make_color(), make_scalar(), make_scalar(), SkIntToScalar(R(10)),
269 make_image_filter());
270 break;
271 case SPOT_LIGHT:
272 filter = (R(2) == 1) ?
273 SkLightingImageFilter::CreateSpotLitDiffuse(SkPoint3(0, 0, 0),
274 make_point(), make_scalar(), make_scalar(), make_color(),
275 make_scalar(), make_scalar(), make_image_filter()) :
276 SkLightingImageFilter::CreateSpotLitSpecular(SkPoint3(0, 0, 0),
277 make_point(), make_scalar(), make_scalar(), make_color(),
278 make_scalar(), make_scalar(), SkIntToScalar(R(10)), make_image_filter());
279 break;
280 case NOISE:
281 {
282 SkAutoTUnref<SkShader> shader((R(2) == 1) ?
283 SkPerlinNoiseShader::CreateFractalNoise(
sugoi@google.combb8148b2013-09-19 19:51:27 +0000284 make_scalar(true), make_scalar(true), R(10.0f), make_scalar()) :
commit-bot@chromium.org22d69f92013-09-19 18:40:49 +0000285 SkPerlinNoiseShader::CreateTubulence(
sugoi@google.combb8148b2013-09-19 19:51:27 +0000286 make_scalar(true), make_scalar(true), R(10.0f), make_scalar()));
reed@google.com44699382013-10-31 17:28:30 +0000287 SkImageFilter::CropRect cropR(SkRect::MakeWH(SkIntToScalar(kBitmapSize),
288 SkIntToScalar(kBitmapSize)));
289 filter = SkRectShaderImageFilter::Create(shader, &cropR);
commit-bot@chromium.org22d69f92013-09-19 18:40:49 +0000290 }
291 break;
292 case DROP_SHADOW:
293 filter = new SkDropShadowImageFilter(make_scalar(), make_scalar(),
294 make_scalar(true), make_color(), make_image_filter());
295 break;
296 case MORPHOLOGY:
commit-bot@chromium.org43f4a552014-01-15 20:20:24 +0000297 if (R(2) == 1) {
sugoi@google.combb8148b2013-09-19 19:51:27 +0000298 filter = new SkDilateImageFilter(R(static_cast<float>(kBitmapSize)),
299 R(static_cast<float>(kBitmapSize)), make_image_filter());
commit-bot@chromium.org43f4a552014-01-15 20:20:24 +0000300 } else {
sugoi@google.combb8148b2013-09-19 19:51:27 +0000301 filter = new SkErodeImageFilter(R(static_cast<float>(kBitmapSize)),
302 R(static_cast<float>(kBitmapSize)), make_image_filter());
commit-bot@chromium.org43f4a552014-01-15 20:20:24 +0000303 }
commit-bot@chromium.org22d69f92013-09-19 18:40:49 +0000304 break;
305 case BITMAP:
commit-bot@chromium.org43f4a552014-01-15 20:20:24 +0000306 if (R(2) == 1) {
307 filter = new SkBitmapSource(make_bitmap(), make_rect(), make_rect());
308 } else {
309 filter = new SkBitmapSource(make_bitmap());
310 }
commit-bot@chromium.org22d69f92013-09-19 18:40:49 +0000311 break;
312 case DISPLACE:
313 filter = new SkDisplacementMapEffect(make_channel_selector_type(),
314 make_channel_selector_type(), make_scalar(),
315 make_image_filter(false), make_image_filter());
316 break;
commit-bot@chromium.orgcd3b15c2013-12-04 17:06:49 +0000317 case TILE:
318 filter = new SkTileImageFilter(make_rect(), make_rect(), make_image_filter(false));
319 break;
commit-bot@chromium.org7b8d72d2014-01-16 22:54:41 +0000320 case PICTURE:
commit-bot@chromium.org5e0995e2014-02-07 12:20:04 +0000321 {
322 SkPicture* pict = NULL;
323#ifdef SK_ALLOW_PICTUREIMAGEFILTER_SERIALIZATION
324 pict = new SkPicture;
325 SkAutoUnref aur(pict);
326 drawSomething(pict->beginRecording(kBitmapSize, kBitmapSize));
327 pict->endRecording();
328#endif
329 filter = new SkPictureImageFilter(pict, make_rect());
330 }
commit-bot@chromium.org7b8d72d2014-01-16 22:54:41 +0000331 break;
commit-bot@chromium.org22d69f92013-09-19 18:40:49 +0000332 default:
333 break;
334 }
335 return (filter || canBeNull) ? filter : make_image_filter(canBeNull);
336}
337
commit-bot@chromium.org77e079a2013-10-28 15:52:02 +0000338static SkImageFilter* make_serialized_image_filter() {
339 SkAutoTUnref<SkImageFilter> filter(make_image_filter(false));
340 SkAutoTUnref<SkData> data(SkValidatingSerializeFlattenable(filter));
341 const unsigned char* ptr = static_cast<const unsigned char*>(data->data());
342 size_t len = data->size();
343#ifdef SK_ADD_RANDOM_BIT_FLIPS
344 unsigned char* p = const_cast<unsigned char*>(ptr);
345 for (size_t i = 0; i < len; ++i, ++p) {
commit-bot@chromium.orgcd3b15c2013-12-04 17:06:49 +0000346 if (R(250) == 1) { // 0.4% of the time, flip a bit or byte
347 if (R(10) == 1) { // Then 10% of the time, change a whole byte
348 switch(R(3)) {
349 case 0:
350 *p ^= 0xFF; // Flip entire byte
351 break;
352 case 1:
353 *p = 0xFF; // Set all bits to 1
354 break;
355 case 2:
356 *p = 0x00; // Set all bits to 0
357 break;
358 }
359 } else {
360 *p ^= (1 << R(8));
361 }
commit-bot@chromium.org77e079a2013-10-28 15:52:02 +0000362 }
363 }
364#endif // SK_ADD_RANDOM_BIT_FLIPS
365 SkFlattenable* flattenable = SkValidatingDeserializeFlattenable(ptr, len,
366 SkImageFilter::GetFlattenableType());
commit-bot@chromium.org77e079a2013-10-28 15:52:02 +0000367 return static_cast<SkImageFilter*>(flattenable);
368}
369
sugoi@google.combb8148b2013-09-19 19:51:27 +0000370static void drawClippedBitmap(SkCanvas* canvas, int x, int y, const SkPaint& paint) {
commit-bot@chromium.org22d69f92013-09-19 18:40:49 +0000371 canvas->save();
372 canvas->clipRect(SkRect::MakeXYWH(SkIntToScalar(x), SkIntToScalar(y),
373 SkIntToScalar(kBitmapSize), SkIntToScalar(kBitmapSize)));
374 canvas->drawBitmap(make_bitmap(), SkIntToScalar(x), SkIntToScalar(y), &paint);
375 canvas->restore();
376}
377
378static void do_fuzz(SkCanvas* canvas) {
commit-bot@chromium.orgef74fa12013-12-17 20:49:46 +0000379 SkImageFilter* filter = make_serialized_image_filter();
380
commit-bot@chromium.orgcd3b15c2013-12-04 17:06:49 +0000381#ifdef SK_FUZZER_IS_VERBOSE
commit-bot@chromium.orgef74fa12013-12-17 20:49:46 +0000382 static uint32_t numFilters = 0;
383 static uint32_t numValidFilters = 0;
384 if (0 == numFilters) {
commit-bot@chromium.orgcd3b15c2013-12-04 17:06:49 +0000385 printf("Fuzzing with %u\n", kSeed);
386 }
commit-bot@chromium.orgef74fa12013-12-17 20:49:46 +0000387 numFilters++;
388 if (NULL != filter) {
389 numValidFilters++;
390 }
391 printf("Filter no : %u. Valid filters so far : %u\r", numFilters, numValidFilters);
commit-bot@chromium.orgcd3b15c2013-12-04 17:06:49 +0000392 fflush(stdout);
commit-bot@chromium.orgcd3b15c2013-12-04 17:06:49 +0000393#endif
394
commit-bot@chromium.org22d69f92013-09-19 18:40:49 +0000395 SkPaint paint;
commit-bot@chromium.orgef74fa12013-12-17 20:49:46 +0000396 SkSafeUnref(paint.setImageFilter(filter));
commit-bot@chromium.org22d69f92013-09-19 18:40:49 +0000397 drawClippedBitmap(canvas, 0, 0, paint);
398}
399
400//////////////////////////////////////////////////////////////////////////////
401
402class ImageFilterFuzzView : public SampleView {
403public:
404 ImageFilterFuzzView() {
405 this->setBGColor(0xFFDDDDDD);
406 }
407
408protected:
409 // overrides from SkEventSink
410 virtual bool onQuery(SkEvent* evt) {
411 if (SampleCode::TitleQ(*evt)) {
412 SampleCode::TitleR(evt, "ImageFilterFuzzer");
413 return true;
414 }
415 return this->INHERITED::onQuery(evt);
416 }
417
418 void drawBG(SkCanvas* canvas) {
419 canvas->drawColor(0xFFDDDDDD);
420 }
421
422 virtual void onDrawContent(SkCanvas* canvas) {
423 do_fuzz(canvas);
424 this->inval(0);
425 }
426
427private:
428 typedef SkView INHERITED;
429};
430
431//////////////////////////////////////////////////////////////////////////////
432
433static SkView* MyFactory() { return new ImageFilterFuzzView; }
434static SkViewRegister reg(MyFactory);