blob: f753b503049c8f346f9cd5b000306bbcae615b9b [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
commit-bot@chromium.orga8c18312014-02-17 02:55:57 +0000114static bool valid_for_raster_canvas(const SkImageInfo& info) {
115 switch (info.colorType()) {
116 case kAlpha_8_SkColorType:
117 case kRGB_565_SkColorType:
118 return true;
119 case kPMColor_SkColorType:
120 return kPremul_SkAlphaType == info.alphaType() ||
121 kOpaque_SkAlphaType == info.alphaType();
122 default:
123 break;
commit-bot@chromium.orgef74fa12013-12-17 20:49:46 +0000124 }
commit-bot@chromium.orga8c18312014-02-17 02:55:57 +0000125 return false;
126}
127
128static SkColorType rand_colortype() {
129 return (SkColorType)R(kLastEnum_SkColorType + 1);
130}
131
132static void rand_bitmap_for_canvas(SkBitmap* bitmap) {
133 SkImageInfo info;
134 do {
135 info = SkImageInfo::Make(kBitmapSize, kBitmapSize, rand_colortype(),
136 kPremul_SkAlphaType);
137 } while (!valid_for_raster_canvas(info) || !bitmap->allocPixels(info));
138}
139
140static void make_g_bitmap(SkBitmap& bitmap) {
141 rand_bitmap_for_canvas(&bitmap);
142
143 SkCanvas canvas(bitmap);
commit-bot@chromium.org22d69f92013-09-19 18:40:49 +0000144 canvas.clear(0x00000000);
145 SkPaint paint;
146 paint.setAntiAlias(true);
147 paint.setColor(0xFF884422);
148 paint.setTextSize(SkIntToScalar(kBitmapSize/2));
149 const char* str = "g";
150 canvas.drawText(str, strlen(str), SkIntToScalar(kBitmapSize/8),
151 SkIntToScalar(kBitmapSize/4), paint);
152}
153
154static void make_checkerboard_bitmap(SkBitmap& bitmap) {
commit-bot@chromium.orga8c18312014-02-17 02:55:57 +0000155 rand_bitmap_for_canvas(&bitmap);
156
157 SkCanvas canvas(bitmap);
commit-bot@chromium.org22d69f92013-09-19 18:40:49 +0000158 canvas.clear(0x00000000);
159 SkPaint darkPaint;
160 darkPaint.setColor(0xFF804020);
161 SkPaint lightPaint;
162 lightPaint.setColor(0xFF244484);
163 const int i = kBitmapSize / 8;
164 const SkScalar f = SkIntToScalar(i);
165 for (int y = 0; y < kBitmapSize; y += i) {
166 for (int x = 0; x < kBitmapSize; x += i) {
167 canvas.save();
168 canvas.translate(SkIntToScalar(x), SkIntToScalar(y));
169 canvas.drawRect(SkRect::MakeXYWH(0, 0, f, f), darkPaint);
170 canvas.drawRect(SkRect::MakeXYWH(f, 0, f, f), lightPaint);
171 canvas.drawRect(SkRect::MakeXYWH(0, f, f, f), lightPaint);
172 canvas.drawRect(SkRect::MakeXYWH(f, f, f, f), darkPaint);
173 canvas.restore();
174 }
175 }
176}
177
178static const SkBitmap& make_bitmap() {
179 static SkBitmap bitmap[2];
180 static bool initialized = false;
181 if (!initialized) {
182 make_g_bitmap(bitmap[0]);
183 make_checkerboard_bitmap(bitmap[1]);
184 initialized = true;
185 }
186 return bitmap[R(2)];
187}
188
commit-bot@chromium.org5e0995e2014-02-07 12:20:04 +0000189#ifdef SK_ALLOW_PICTUREIMAGEFILTER_SERIALIZATION
190static void drawSomething(SkCanvas* canvas) {
191 SkPaint paint;
192
193 canvas->save();
194 canvas->scale(0.5f, 0.5f);
195 canvas->drawBitmap(make_bitmap(), 0, 0, NULL);
196 canvas->restore();
197
198 const char beforeStr[] = "before circle";
199 const char afterStr[] = "after circle";
200
201 paint.setAntiAlias(true);
202
203 paint.setColor(SK_ColorRED);
204 canvas->drawData(beforeStr, sizeof(beforeStr));
205 canvas->drawCircle(SkIntToScalar(kBitmapSize/2), SkIntToScalar(kBitmapSize/2), SkIntToScalar(kBitmapSize/3), paint);
206 canvas->drawData(afterStr, sizeof(afterStr));
207 paint.setColor(SK_ColorBLACK);
208 paint.setTextSize(SkIntToScalar(kBitmapSize/3));
209 canvas->drawText("Picture", 7, SkIntToScalar(kBitmapSize/2), SkIntToScalar(kBitmapSize/4), paint);
210}
211#endif
212
commit-bot@chromium.org22d69f92013-09-19 18:40:49 +0000213static SkImageFilter* make_image_filter(bool canBeNull = true) {
214 SkImageFilter* filter = 0;
215
216 // Add a 1 in 3 chance to get a NULL input
217 if (canBeNull && (R(3) == 1)) { return filter; }
218
219 enum { BICUBIC, MERGE, COLOR, BLUR, MAGNIFIER, XFERMODE, OFFSET, COMPOSE,
220 DISTANT_LIGHT, POINT_LIGHT, SPOT_LIGHT, NOISE, DROP_SHADOW,
commit-bot@chromium.org7b8d72d2014-01-16 22:54:41 +0000221 MORPHOLOGY, BITMAP, DISPLACE, TILE, PICTURE, NUM_FILTERS };
commit-bot@chromium.org22d69f92013-09-19 18:40:49 +0000222
223 switch (R(NUM_FILTERS)) {
224 case BICUBIC:
225 // Scale is set to 1 here so that it can fit in the DAG without resizing the output
226 filter = SkBicubicImageFilter::CreateMitchell(SkSize::Make(1, 1), make_image_filter());
227 break;
228 case MERGE:
229 filter = new SkMergeImageFilter(make_image_filter(), make_image_filter(), make_xfermode());
230 break;
231 case COLOR:
232 {
233 SkAutoTUnref<SkColorFilter> cf((R(2) == 1) ?
234 SkColorFilter::CreateModeFilter(make_color(), make_xfermode()) :
235 SkColorFilter::CreateLightingFilter(make_color(), make_color()));
236 filter = cf.get() ? SkColorFilterImageFilter::Create(cf, make_image_filter()) : 0;
237 }
238 break;
239 case BLUR:
240 filter = new SkBlurImageFilter(make_scalar(true), make_scalar(true), make_image_filter());
241 break;
242 case MAGNIFIER:
commit-bot@chromium.orgcd3b15c2013-12-04 17:06:49 +0000243 filter = new SkMagnifierImageFilter(make_rect(), make_scalar(true));
commit-bot@chromium.org22d69f92013-09-19 18:40:49 +0000244 break;
245 case XFERMODE:
246 {
247 SkAutoTUnref<SkXfermode> mode(SkXfermode::Create(make_xfermode()));
248 filter = new SkXfermodeImageFilter(mode, make_image_filter(), make_image_filter());
249 }
250 break;
251 case OFFSET:
252 filter = new SkOffsetImageFilter(make_scalar(), make_scalar(), make_image_filter());
253 break;
254 case COMPOSE:
255 filter = new SkComposeImageFilter(make_image_filter(), make_image_filter());
256 break;
257 case DISTANT_LIGHT:
258 filter = (R(2) == 1) ?
259 SkLightingImageFilter::CreateDistantLitDiffuse(make_point(),
260 make_color(), make_scalar(), make_scalar(), make_image_filter()) :
261 SkLightingImageFilter::CreateDistantLitSpecular(make_point(),
262 make_color(), make_scalar(), make_scalar(), SkIntToScalar(R(10)),
263 make_image_filter());
264 break;
265 case POINT_LIGHT:
266 filter = (R(2) == 1) ?
267 SkLightingImageFilter::CreatePointLitDiffuse(make_point(),
268 make_color(), make_scalar(), make_scalar(), make_image_filter()) :
269 SkLightingImageFilter::CreatePointLitSpecular(make_point(),
270 make_color(), make_scalar(), make_scalar(), SkIntToScalar(R(10)),
271 make_image_filter());
272 break;
273 case SPOT_LIGHT:
274 filter = (R(2) == 1) ?
275 SkLightingImageFilter::CreateSpotLitDiffuse(SkPoint3(0, 0, 0),
276 make_point(), make_scalar(), make_scalar(), make_color(),
277 make_scalar(), make_scalar(), make_image_filter()) :
278 SkLightingImageFilter::CreateSpotLitSpecular(SkPoint3(0, 0, 0),
279 make_point(), make_scalar(), make_scalar(), make_color(),
280 make_scalar(), make_scalar(), SkIntToScalar(R(10)), make_image_filter());
281 break;
282 case NOISE:
283 {
284 SkAutoTUnref<SkShader> shader((R(2) == 1) ?
285 SkPerlinNoiseShader::CreateFractalNoise(
sugoi@google.combb8148b2013-09-19 19:51:27 +0000286 make_scalar(true), make_scalar(true), R(10.0f), make_scalar()) :
commit-bot@chromium.org22d69f92013-09-19 18:40:49 +0000287 SkPerlinNoiseShader::CreateTubulence(
sugoi@google.combb8148b2013-09-19 19:51:27 +0000288 make_scalar(true), make_scalar(true), R(10.0f), make_scalar()));
reed@google.com44699382013-10-31 17:28:30 +0000289 SkImageFilter::CropRect cropR(SkRect::MakeWH(SkIntToScalar(kBitmapSize),
290 SkIntToScalar(kBitmapSize)));
291 filter = SkRectShaderImageFilter::Create(shader, &cropR);
commit-bot@chromium.org22d69f92013-09-19 18:40:49 +0000292 }
293 break;
294 case DROP_SHADOW:
295 filter = new SkDropShadowImageFilter(make_scalar(), make_scalar(),
296 make_scalar(true), make_color(), make_image_filter());
297 break;
298 case MORPHOLOGY:
commit-bot@chromium.org43f4a552014-01-15 20:20:24 +0000299 if (R(2) == 1) {
sugoi@google.combb8148b2013-09-19 19:51:27 +0000300 filter = new SkDilateImageFilter(R(static_cast<float>(kBitmapSize)),
301 R(static_cast<float>(kBitmapSize)), make_image_filter());
commit-bot@chromium.org43f4a552014-01-15 20:20:24 +0000302 } else {
sugoi@google.combb8148b2013-09-19 19:51:27 +0000303 filter = new SkErodeImageFilter(R(static_cast<float>(kBitmapSize)),
304 R(static_cast<float>(kBitmapSize)), make_image_filter());
commit-bot@chromium.org43f4a552014-01-15 20:20:24 +0000305 }
commit-bot@chromium.org22d69f92013-09-19 18:40:49 +0000306 break;
307 case BITMAP:
commit-bot@chromium.org43f4a552014-01-15 20:20:24 +0000308 if (R(2) == 1) {
309 filter = new SkBitmapSource(make_bitmap(), make_rect(), make_rect());
310 } else {
311 filter = new SkBitmapSource(make_bitmap());
312 }
commit-bot@chromium.org22d69f92013-09-19 18:40:49 +0000313 break;
314 case DISPLACE:
315 filter = new SkDisplacementMapEffect(make_channel_selector_type(),
316 make_channel_selector_type(), make_scalar(),
317 make_image_filter(false), make_image_filter());
318 break;
commit-bot@chromium.orgcd3b15c2013-12-04 17:06:49 +0000319 case TILE:
320 filter = new SkTileImageFilter(make_rect(), make_rect(), make_image_filter(false));
321 break;
commit-bot@chromium.org7b8d72d2014-01-16 22:54:41 +0000322 case PICTURE:
commit-bot@chromium.org5e0995e2014-02-07 12:20:04 +0000323 {
324 SkPicture* pict = NULL;
325#ifdef SK_ALLOW_PICTUREIMAGEFILTER_SERIALIZATION
326 pict = new SkPicture;
327 SkAutoUnref aur(pict);
328 drawSomething(pict->beginRecording(kBitmapSize, kBitmapSize));
329 pict->endRecording();
330#endif
331 filter = new SkPictureImageFilter(pict, make_rect());
332 }
commit-bot@chromium.org7b8d72d2014-01-16 22:54:41 +0000333 break;
commit-bot@chromium.org22d69f92013-09-19 18:40:49 +0000334 default:
335 break;
336 }
337 return (filter || canBeNull) ? filter : make_image_filter(canBeNull);
338}
339
commit-bot@chromium.org77e079a2013-10-28 15:52:02 +0000340static SkImageFilter* make_serialized_image_filter() {
341 SkAutoTUnref<SkImageFilter> filter(make_image_filter(false));
342 SkAutoTUnref<SkData> data(SkValidatingSerializeFlattenable(filter));
343 const unsigned char* ptr = static_cast<const unsigned char*>(data->data());
344 size_t len = data->size();
345#ifdef SK_ADD_RANDOM_BIT_FLIPS
346 unsigned char* p = const_cast<unsigned char*>(ptr);
347 for (size_t i = 0; i < len; ++i, ++p) {
commit-bot@chromium.orgcd3b15c2013-12-04 17:06:49 +0000348 if (R(250) == 1) { // 0.4% of the time, flip a bit or byte
349 if (R(10) == 1) { // Then 10% of the time, change a whole byte
350 switch(R(3)) {
351 case 0:
352 *p ^= 0xFF; // Flip entire byte
353 break;
354 case 1:
355 *p = 0xFF; // Set all bits to 1
356 break;
357 case 2:
358 *p = 0x00; // Set all bits to 0
359 break;
360 }
361 } else {
362 *p ^= (1 << R(8));
363 }
commit-bot@chromium.org77e079a2013-10-28 15:52:02 +0000364 }
365 }
366#endif // SK_ADD_RANDOM_BIT_FLIPS
367 SkFlattenable* flattenable = SkValidatingDeserializeFlattenable(ptr, len,
368 SkImageFilter::GetFlattenableType());
commit-bot@chromium.org77e079a2013-10-28 15:52:02 +0000369 return static_cast<SkImageFilter*>(flattenable);
370}
371
sugoi@google.combb8148b2013-09-19 19:51:27 +0000372static void drawClippedBitmap(SkCanvas* canvas, int x, int y, const SkPaint& paint) {
commit-bot@chromium.org22d69f92013-09-19 18:40:49 +0000373 canvas->save();
374 canvas->clipRect(SkRect::MakeXYWH(SkIntToScalar(x), SkIntToScalar(y),
375 SkIntToScalar(kBitmapSize), SkIntToScalar(kBitmapSize)));
376 canvas->drawBitmap(make_bitmap(), SkIntToScalar(x), SkIntToScalar(y), &paint);
377 canvas->restore();
378}
379
380static void do_fuzz(SkCanvas* canvas) {
commit-bot@chromium.orgef74fa12013-12-17 20:49:46 +0000381 SkImageFilter* filter = make_serialized_image_filter();
382
commit-bot@chromium.orgcd3b15c2013-12-04 17:06:49 +0000383#ifdef SK_FUZZER_IS_VERBOSE
commit-bot@chromium.orgef74fa12013-12-17 20:49:46 +0000384 static uint32_t numFilters = 0;
385 static uint32_t numValidFilters = 0;
386 if (0 == numFilters) {
commit-bot@chromium.orgcd3b15c2013-12-04 17:06:49 +0000387 printf("Fuzzing with %u\n", kSeed);
388 }
commit-bot@chromium.orgef74fa12013-12-17 20:49:46 +0000389 numFilters++;
390 if (NULL != filter) {
391 numValidFilters++;
392 }
393 printf("Filter no : %u. Valid filters so far : %u\r", numFilters, numValidFilters);
commit-bot@chromium.orgcd3b15c2013-12-04 17:06:49 +0000394 fflush(stdout);
commit-bot@chromium.orgcd3b15c2013-12-04 17:06:49 +0000395#endif
396
commit-bot@chromium.org22d69f92013-09-19 18:40:49 +0000397 SkPaint paint;
commit-bot@chromium.orgef74fa12013-12-17 20:49:46 +0000398 SkSafeUnref(paint.setImageFilter(filter));
commit-bot@chromium.org22d69f92013-09-19 18:40:49 +0000399 drawClippedBitmap(canvas, 0, 0, paint);
400}
401
402//////////////////////////////////////////////////////////////////////////////
403
404class ImageFilterFuzzView : public SampleView {
405public:
406 ImageFilterFuzzView() {
407 this->setBGColor(0xFFDDDDDD);
408 }
409
410protected:
411 // overrides from SkEventSink
412 virtual bool onQuery(SkEvent* evt) {
413 if (SampleCode::TitleQ(*evt)) {
414 SampleCode::TitleR(evt, "ImageFilterFuzzer");
415 return true;
416 }
417 return this->INHERITED::onQuery(evt);
418 }
419
420 void drawBG(SkCanvas* canvas) {
421 canvas->drawColor(0xFFDDDDDD);
422 }
423
424 virtual void onDrawContent(SkCanvas* canvas) {
425 do_fuzz(canvas);
426 this->inval(0);
427 }
428
429private:
430 typedef SkView INHERITED;
431};
432
433//////////////////////////////////////////////////////////////////////////////
434
435static SkView* MyFactory() { return new ImageFilterFuzzView; }
436static SkViewRegister reg(MyFactory);