blob: 06e14f0e7da7b3549d086942d7f875ca565146af [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"
26#include "SkRandom.h"
27#include "SkRectShaderImageFilter.h"
commit-bot@chromium.orgcd3b15c2013-12-04 17:06:49 +000028#include "SkTileImageFilter.h"
commit-bot@chromium.org22d69f92013-09-19 18:40:49 +000029#include "SkView.h"
30#include "SkXfermodeImageFilter.h"
commit-bot@chromium.orgcd3b15c2013-12-04 17:06:49 +000031#include <stdio.h>
32#include <time.h>
commit-bot@chromium.org22d69f92013-09-19 18:40:49 +000033
commit-bot@chromium.orgc2e9db32013-12-06 20:14:46 +000034//#define SK_ADD_RANDOM_BIT_FLIPS
35//#define SK_FUZZER_IS_VERBOSE
36
commit-bot@chromium.orgcd3b15c2013-12-04 17:06:49 +000037static const uint32_t kSeed = (uint32_t)(time(NULL));
commit-bot@chromium.org22d69f92013-09-19 18:40:49 +000038static SkRandom gRand(kSeed);
39static bool return_large = false;
40static bool return_undef = false;
41
42static const int kBitmapSize = 24;
43
44static int R(float x) {
45 return (int)floor(SkScalarToFloat(gRand.nextUScalar1()) * x);
46}
47
48#if defined _WIN32
49#pragma warning ( push )
50// we are intentionally causing an overflow here
51// (warning C4756: overflow in constant arithmetic)
52#pragma warning ( disable : 4756 )
53#endif
54
55static float huge() {
56 double d = 1e100;
57 float f = (float)d;
58 return f;
59}
60
61#if defined _WIN32
62#pragma warning ( pop )
63#endif
64
65static float make_number(bool positiveOnly) {
66 float f = positiveOnly ? 1.0f : 0.0f;
67 float v = f;
68 int sel;
69
70 if (return_large) sel = R(6); else sel = R(4);
71 if (!return_undef && sel == 0) sel = 1;
72
73 if (R(2) == 1) v = (float)(R(100)+f); else
74
75 switch (sel) {
76 case 0: break;
77 case 1: v = f; break;
78 case 2: v = 0.000001f; break;
79 case 3: v = 10000.0f; break;
80 case 4: v = 2000000000.0f; break;
81 case 5: v = huge(); break;
82 }
83
84 if (!positiveOnly && (R(4) == 1)) v = -v;
85 return v;
86}
87
88static SkScalar make_scalar(bool positiveOnly = false) {
commit-bot@chromium.org4b413c82013-11-25 19:44:07 +000089 return make_number(positiveOnly);
commit-bot@chromium.org22d69f92013-09-19 18:40:49 +000090}
91
commit-bot@chromium.orgcd3b15c2013-12-04 17:06:49 +000092static SkRect make_rect() {
93 return SkRect::MakeWH(SkIntToScalar(R(static_cast<float>(kBitmapSize))),
94 SkIntToScalar(R(static_cast<float>(kBitmapSize))));
commit-bot@chromium.org22d69f92013-09-19 18:40:49 +000095}
96
97static SkXfermode::Mode make_xfermode() {
98 return static_cast<SkXfermode::Mode>(R(SkXfermode::kLastMode+1));
99}
100
101static SkColor make_color() {
102 return (R(2) == 1) ? 0xFFC0F0A0 : 0xFF000090;
103}
104
105static SkPoint3 make_point() {
106 return SkPoint3(make_scalar(), make_scalar(), make_scalar(true));
107}
108
109static SkDisplacementMapEffect::ChannelSelectorType make_channel_selector_type() {
110 return static_cast<SkDisplacementMapEffect::ChannelSelectorType>(R(4)+1);
111}
112
113static void make_g_bitmap(SkBitmap& bitmap) {
114 bitmap.setConfig(SkBitmap::kARGB_8888_Config, kBitmapSize, kBitmapSize);
115 bitmap.allocPixels();
116 SkBitmapDevice device(bitmap);
117 SkCanvas canvas(&device);
118 canvas.clear(0x00000000);
119 SkPaint paint;
120 paint.setAntiAlias(true);
121 paint.setColor(0xFF884422);
122 paint.setTextSize(SkIntToScalar(kBitmapSize/2));
123 const char* str = "g";
124 canvas.drawText(str, strlen(str), SkIntToScalar(kBitmapSize/8),
125 SkIntToScalar(kBitmapSize/4), paint);
126}
127
128static void make_checkerboard_bitmap(SkBitmap& bitmap) {
129 bitmap.setConfig(SkBitmap::kARGB_8888_Config, kBitmapSize, kBitmapSize);
130 bitmap.allocPixels();
131 SkBitmapDevice device(bitmap);
132 SkCanvas canvas(&device);
133 canvas.clear(0x00000000);
134 SkPaint darkPaint;
135 darkPaint.setColor(0xFF804020);
136 SkPaint lightPaint;
137 lightPaint.setColor(0xFF244484);
138 const int i = kBitmapSize / 8;
139 const SkScalar f = SkIntToScalar(i);
140 for (int y = 0; y < kBitmapSize; y += i) {
141 for (int x = 0; x < kBitmapSize; x += i) {
142 canvas.save();
143 canvas.translate(SkIntToScalar(x), SkIntToScalar(y));
144 canvas.drawRect(SkRect::MakeXYWH(0, 0, f, f), darkPaint);
145 canvas.drawRect(SkRect::MakeXYWH(f, 0, f, f), lightPaint);
146 canvas.drawRect(SkRect::MakeXYWH(0, f, f, f), lightPaint);
147 canvas.drawRect(SkRect::MakeXYWH(f, f, f, f), darkPaint);
148 canvas.restore();
149 }
150 }
151}
152
153static const SkBitmap& make_bitmap() {
154 static SkBitmap bitmap[2];
155 static bool initialized = false;
156 if (!initialized) {
157 make_g_bitmap(bitmap[0]);
158 make_checkerboard_bitmap(bitmap[1]);
159 initialized = true;
160 }
161 return bitmap[R(2)];
162}
163
164static SkImageFilter* make_image_filter(bool canBeNull = true) {
165 SkImageFilter* filter = 0;
166
167 // Add a 1 in 3 chance to get a NULL input
168 if (canBeNull && (R(3) == 1)) { return filter; }
169
170 enum { BICUBIC, MERGE, COLOR, BLUR, MAGNIFIER, XFERMODE, OFFSET, COMPOSE,
171 DISTANT_LIGHT, POINT_LIGHT, SPOT_LIGHT, NOISE, DROP_SHADOW,
commit-bot@chromium.orgcd3b15c2013-12-04 17:06:49 +0000172 MORPHOLOGY, BITMAP, DISPLACE, TILE, NUM_FILTERS };
commit-bot@chromium.org22d69f92013-09-19 18:40:49 +0000173
174 switch (R(NUM_FILTERS)) {
175 case BICUBIC:
176 // Scale is set to 1 here so that it can fit in the DAG without resizing the output
177 filter = SkBicubicImageFilter::CreateMitchell(SkSize::Make(1, 1), make_image_filter());
178 break;
179 case MERGE:
180 filter = new SkMergeImageFilter(make_image_filter(), make_image_filter(), make_xfermode());
181 break;
182 case COLOR:
183 {
184 SkAutoTUnref<SkColorFilter> cf((R(2) == 1) ?
185 SkColorFilter::CreateModeFilter(make_color(), make_xfermode()) :
186 SkColorFilter::CreateLightingFilter(make_color(), make_color()));
187 filter = cf.get() ? SkColorFilterImageFilter::Create(cf, make_image_filter()) : 0;
188 }
189 break;
190 case BLUR:
191 filter = new SkBlurImageFilter(make_scalar(true), make_scalar(true), make_image_filter());
192 break;
193 case MAGNIFIER:
commit-bot@chromium.orgcd3b15c2013-12-04 17:06:49 +0000194 filter = new SkMagnifierImageFilter(make_rect(), make_scalar(true));
commit-bot@chromium.org22d69f92013-09-19 18:40:49 +0000195 break;
196 case XFERMODE:
197 {
198 SkAutoTUnref<SkXfermode> mode(SkXfermode::Create(make_xfermode()));
199 filter = new SkXfermodeImageFilter(mode, make_image_filter(), make_image_filter());
200 }
201 break;
202 case OFFSET:
203 filter = new SkOffsetImageFilter(make_scalar(), make_scalar(), make_image_filter());
204 break;
205 case COMPOSE:
206 filter = new SkComposeImageFilter(make_image_filter(), make_image_filter());
207 break;
208 case DISTANT_LIGHT:
209 filter = (R(2) == 1) ?
210 SkLightingImageFilter::CreateDistantLitDiffuse(make_point(),
211 make_color(), make_scalar(), make_scalar(), make_image_filter()) :
212 SkLightingImageFilter::CreateDistantLitSpecular(make_point(),
213 make_color(), make_scalar(), make_scalar(), SkIntToScalar(R(10)),
214 make_image_filter());
215 break;
216 case POINT_LIGHT:
217 filter = (R(2) == 1) ?
218 SkLightingImageFilter::CreatePointLitDiffuse(make_point(),
219 make_color(), make_scalar(), make_scalar(), make_image_filter()) :
220 SkLightingImageFilter::CreatePointLitSpecular(make_point(),
221 make_color(), make_scalar(), make_scalar(), SkIntToScalar(R(10)),
222 make_image_filter());
223 break;
224 case SPOT_LIGHT:
225 filter = (R(2) == 1) ?
226 SkLightingImageFilter::CreateSpotLitDiffuse(SkPoint3(0, 0, 0),
227 make_point(), make_scalar(), make_scalar(), make_color(),
228 make_scalar(), make_scalar(), make_image_filter()) :
229 SkLightingImageFilter::CreateSpotLitSpecular(SkPoint3(0, 0, 0),
230 make_point(), make_scalar(), make_scalar(), make_color(),
231 make_scalar(), make_scalar(), SkIntToScalar(R(10)), make_image_filter());
232 break;
233 case NOISE:
234 {
235 SkAutoTUnref<SkShader> shader((R(2) == 1) ?
236 SkPerlinNoiseShader::CreateFractalNoise(
sugoi@google.combb8148b2013-09-19 19:51:27 +0000237 make_scalar(true), make_scalar(true), R(10.0f), make_scalar()) :
commit-bot@chromium.org22d69f92013-09-19 18:40:49 +0000238 SkPerlinNoiseShader::CreateTubulence(
sugoi@google.combb8148b2013-09-19 19:51:27 +0000239 make_scalar(true), make_scalar(true), R(10.0f), make_scalar()));
reed@google.com44699382013-10-31 17:28:30 +0000240 SkImageFilter::CropRect cropR(SkRect::MakeWH(SkIntToScalar(kBitmapSize),
241 SkIntToScalar(kBitmapSize)));
242 filter = SkRectShaderImageFilter::Create(shader, &cropR);
commit-bot@chromium.org22d69f92013-09-19 18:40:49 +0000243 }
244 break;
245 case DROP_SHADOW:
246 filter = new SkDropShadowImageFilter(make_scalar(), make_scalar(),
247 make_scalar(true), make_color(), make_image_filter());
248 break;
249 case MORPHOLOGY:
250 if (R(2) == 1)
sugoi@google.combb8148b2013-09-19 19:51:27 +0000251 filter = new SkDilateImageFilter(R(static_cast<float>(kBitmapSize)),
252 R(static_cast<float>(kBitmapSize)), make_image_filter());
commit-bot@chromium.org22d69f92013-09-19 18:40:49 +0000253 else
sugoi@google.combb8148b2013-09-19 19:51:27 +0000254 filter = new SkErodeImageFilter(R(static_cast<float>(kBitmapSize)),
255 R(static_cast<float>(kBitmapSize)), make_image_filter());
commit-bot@chromium.org22d69f92013-09-19 18:40:49 +0000256 break;
257 case BITMAP:
258 filter = new SkBitmapSource(make_bitmap());
259 break;
260 case DISPLACE:
261 filter = new SkDisplacementMapEffect(make_channel_selector_type(),
262 make_channel_selector_type(), make_scalar(),
263 make_image_filter(false), make_image_filter());
264 break;
commit-bot@chromium.orgcd3b15c2013-12-04 17:06:49 +0000265 case TILE:
266 filter = new SkTileImageFilter(make_rect(), make_rect(), make_image_filter(false));
267 break;
commit-bot@chromium.org22d69f92013-09-19 18:40:49 +0000268 default:
269 break;
270 }
271 return (filter || canBeNull) ? filter : make_image_filter(canBeNull);
272}
273
commit-bot@chromium.org77e079a2013-10-28 15:52:02 +0000274static SkImageFilter* make_serialized_image_filter() {
275 SkAutoTUnref<SkImageFilter> filter(make_image_filter(false));
276 SkAutoTUnref<SkData> data(SkValidatingSerializeFlattenable(filter));
277 const unsigned char* ptr = static_cast<const unsigned char*>(data->data());
278 size_t len = data->size();
279#ifdef SK_ADD_RANDOM_BIT_FLIPS
280 unsigned char* p = const_cast<unsigned char*>(ptr);
281 for (size_t i = 0; i < len; ++i, ++p) {
commit-bot@chromium.orgcd3b15c2013-12-04 17:06:49 +0000282 if (R(250) == 1) { // 0.4% of the time, flip a bit or byte
283 if (R(10) == 1) { // Then 10% of the time, change a whole byte
284 switch(R(3)) {
285 case 0:
286 *p ^= 0xFF; // Flip entire byte
287 break;
288 case 1:
289 *p = 0xFF; // Set all bits to 1
290 break;
291 case 2:
292 *p = 0x00; // Set all bits to 0
293 break;
294 }
295 } else {
296 *p ^= (1 << R(8));
297 }
commit-bot@chromium.org77e079a2013-10-28 15:52:02 +0000298 }
299 }
300#endif // SK_ADD_RANDOM_BIT_FLIPS
301 SkFlattenable* flattenable = SkValidatingDeserializeFlattenable(ptr, len,
302 SkImageFilter::GetFlattenableType());
commit-bot@chromium.org77e079a2013-10-28 15:52:02 +0000303 return static_cast<SkImageFilter*>(flattenable);
304}
305
sugoi@google.combb8148b2013-09-19 19:51:27 +0000306static void drawClippedBitmap(SkCanvas* canvas, int x, int y, const SkPaint& paint) {
commit-bot@chromium.org22d69f92013-09-19 18:40:49 +0000307 canvas->save();
308 canvas->clipRect(SkRect::MakeXYWH(SkIntToScalar(x), SkIntToScalar(y),
309 SkIntToScalar(kBitmapSize), SkIntToScalar(kBitmapSize)));
310 canvas->drawBitmap(make_bitmap(), SkIntToScalar(x), SkIntToScalar(y), &paint);
311 canvas->restore();
312}
313
314static void do_fuzz(SkCanvas* canvas) {
commit-bot@chromium.orgcd3b15c2013-12-04 17:06:49 +0000315#ifdef SK_FUZZER_IS_VERBOSE
316 static uint32_t filterId = 0;
317 if (0 == filterId) {
318 printf("Fuzzing with %u\n", kSeed);
319 }
320 printf("Filter no %u\r", filterId);
321 fflush(stdout);
322 filterId++;
323#endif
324
commit-bot@chromium.org22d69f92013-09-19 18:40:49 +0000325 SkPaint paint;
commit-bot@chromium.orgcd3b15c2013-12-04 17:06:49 +0000326 SkSafeUnref(paint.setImageFilter(make_serialized_image_filter()));
commit-bot@chromium.org22d69f92013-09-19 18:40:49 +0000327 drawClippedBitmap(canvas, 0, 0, paint);
328}
329
330//////////////////////////////////////////////////////////////////////////////
331
332class ImageFilterFuzzView : public SampleView {
333public:
334 ImageFilterFuzzView() {
335 this->setBGColor(0xFFDDDDDD);
336 }
337
338protected:
339 // overrides from SkEventSink
340 virtual bool onQuery(SkEvent* evt) {
341 if (SampleCode::TitleQ(*evt)) {
342 SampleCode::TitleR(evt, "ImageFilterFuzzer");
343 return true;
344 }
345 return this->INHERITED::onQuery(evt);
346 }
347
348 void drawBG(SkCanvas* canvas) {
349 canvas->drawColor(0xFFDDDDDD);
350 }
351
352 virtual void onDrawContent(SkCanvas* canvas) {
353 do_fuzz(canvas);
354 this->inval(0);
355 }
356
357private:
358 typedef SkView INHERITED;
359};
360
361//////////////////////////////////////////////////////////////////////////////
362
363static SkView* MyFactory() { return new ImageFilterFuzzView; }
364static SkViewRegister reg(MyFactory);