1/*
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 "SkAlphaThresholdFilter.h"
9#include "SkBitmapSource.h"
10#include "SkBlurImageFilter.h"
11#include "SkCanvas.h"
12#include "SkColorCubeFilter.h"
13#include "SkColorFilter.h"
14#include "SkColorFilterImageFilter.h"
15#include "SkComposeImageFilter.h"
16#include "SkData.h"
17#include "SkDisplacementMapEffect.h"
18#include "SkDropShadowImageFilter.h"
19#include "SkFlattenableSerialization.h"
20#include "SkLightingImageFilter.h"
21#include "SkMagnifierImageFilter.h"
22#include "SkMatrixConvolutionImageFilter.h"
23#include "SkMergeImageFilter.h"
24#include "SkMorphologyImageFilter.h"
25#include "SkOffsetImageFilter.h"
26#include "SkPerlinNoiseShader.h"
27#include "SkPictureImageFilter.h"
28#include "SkPictureRecorder.h"
29#include "SkRandom.h"
30#include "SkRectShaderImageFilter.h"
31#include "SkTestImageFilters.h"
32#include "SkTileImageFilter.h"
33#include "SkView.h"
34#include "SkXfermodeImageFilter.h"
35#include <stdio.h>
36#include <time.h>
37
38//#define SK_ADD_RANDOM_BIT_FLIPS
39//#define SK_FUZZER_IS_VERBOSE
40
41static const uint32_t kSeed = (uint32_t)(time(NULL));
42static SkRandom gRand(kSeed);
43static bool return_large = false;
44static bool return_undef = false;
45
46static const int kBitmapSize = 24;
47
48static int R(float x) {
49    return (int)floor(SkScalarToFloat(gRand.nextUScalar1()) * x);
50}
51
52#if defined _WIN32
53#pragma warning ( push )
54// we are intentionally causing an overflow here
55//      (warning C4756: overflow in constant arithmetic)
56#pragma warning ( disable : 4756 )
57#endif
58
59static float huge() {
60    double d = 1e100;
61    float f = (float)d;
62    return f;
63}
64
65#if defined _WIN32
66#pragma warning ( pop )
67#endif
68
69static float make_number(bool positiveOnly) {
70    float f = positiveOnly ? 1.0f : 0.0f;
71    float v = f;
72    int sel;
73
74    if (return_large) sel = R(6); else sel = R(4);
75    if (!return_undef && sel == 0) sel = 1;
76
77    if (R(2) == 1) v = (float)(R(100)+f); else
78
79    switch (sel) {
80        case 0: break;
81        case 1: v = f; break;
82        case 2: v = 0.000001f; break;
83        case 3: v = 10000.0f; break;
84        case 4: v = 2000000000.0f; break;
85        case 5: v = huge(); break;
86    }
87
88    if (!positiveOnly && (R(4) == 1)) v = -v;
89    return v;
90}
91
92static SkScalar make_scalar(bool positiveOnly = false) {
93    return make_number(positiveOnly);
94}
95
96static SkRect make_rect() {
97    return SkRect::MakeWH(SkIntToScalar(R(static_cast<float>(kBitmapSize))),
98                          SkIntToScalar(R(static_cast<float>(kBitmapSize))));
99}
100
101static SkRegion make_region() {
102    SkIRect iRegion = SkIRect::MakeXYWH(R(static_cast<float>(kBitmapSize)),
103                                        R(static_cast<float>(kBitmapSize)),
104                                        R(static_cast<float>(kBitmapSize)),
105                                        R(static_cast<float>(kBitmapSize)));
106    return SkRegion(iRegion);
107}
108
109static SkMatrix make_matrix() {
110    SkMatrix m;
111    for (int i = 0; i < 9; ++i) {
112        m[i] = make_scalar();
113    }
114    return m;
115}
116
117static SkXfermode::Mode make_xfermode() {
118    return static_cast<SkXfermode::Mode>(R(SkXfermode::kLastMode+1));
119}
120
121static SkColor make_color() {
122    return (R(2) == 1) ? 0xFFC0F0A0 : 0xFF000090;
123}
124
125static SkDropShadowImageFilter::ShadowMode make_shadow_mode() {
126    return (R(2) == 1) ? SkDropShadowImageFilter::kDrawShadowAndForeground_ShadowMode :
127                         SkDropShadowImageFilter::kDrawShadowOnly_ShadowMode;
128}
129
130static SkPoint3 make_point() {
131    return SkPoint3(make_scalar(), make_scalar(), make_scalar(true));
132}
133
134static SkDisplacementMapEffect::ChannelSelectorType make_channel_selector_type() {
135    return static_cast<SkDisplacementMapEffect::ChannelSelectorType>(R(4)+1);
136}
137
138static bool valid_for_raster_canvas(const SkImageInfo& info) {
139    switch (info.colorType()) {
140        case kAlpha_8_SkColorType:
141        case kRGB_565_SkColorType:
142            return true;
143        case kN32_SkColorType:
144            return kPremul_SkAlphaType == info.alphaType() ||
145                   kOpaque_SkAlphaType == info.alphaType();
146        default:
147            break;
148    }
149    return false;
150}
151
152static SkColorType rand_colortype() {
153    return (SkColorType)R(kLastEnum_SkColorType + 1);
154}
155
156static void rand_bitmap_for_canvas(SkBitmap* bitmap) {
157    SkImageInfo info;
158    do {
159        info = SkImageInfo::Make(kBitmapSize, kBitmapSize, rand_colortype(),
160                                 kPremul_SkAlphaType);
161    } while (!valid_for_raster_canvas(info) || !bitmap->tryAllocPixels(info));
162}
163
164static void make_g_bitmap(SkBitmap& bitmap) {
165    rand_bitmap_for_canvas(&bitmap);
166
167    SkCanvas canvas(bitmap);
168    canvas.clear(0x00000000);
169    SkPaint paint;
170    paint.setAntiAlias(true);
171    paint.setColor(0xFF884422);
172    paint.setTextSize(SkIntToScalar(kBitmapSize/2));
173    const char* str = "g";
174    canvas.drawText(str, strlen(str), SkIntToScalar(kBitmapSize/8),
175                    SkIntToScalar(kBitmapSize/4), paint);
176}
177
178static void make_checkerboard_bitmap(SkBitmap& bitmap) {
179    rand_bitmap_for_canvas(&bitmap);
180
181    SkCanvas canvas(bitmap);
182    canvas.clear(0x00000000);
183    SkPaint darkPaint;
184    darkPaint.setColor(0xFF804020);
185    SkPaint lightPaint;
186    lightPaint.setColor(0xFF244484);
187    const int i = kBitmapSize / 8;
188    const SkScalar f = SkIntToScalar(i);
189    for (int y = 0; y < kBitmapSize; y += i) {
190        for (int x = 0; x < kBitmapSize; x += i) {
191            canvas.save();
192            canvas.translate(SkIntToScalar(x), SkIntToScalar(y));
193            canvas.drawRect(SkRect::MakeXYWH(0, 0, f, f), darkPaint);
194            canvas.drawRect(SkRect::MakeXYWH(f, 0, f, f), lightPaint);
195            canvas.drawRect(SkRect::MakeXYWH(0, f, f, f), lightPaint);
196            canvas.drawRect(SkRect::MakeXYWH(f, f, f, f), darkPaint);
197            canvas.restore();
198        }
199    }
200}
201
202static const SkBitmap& make_bitmap() {
203    static SkBitmap bitmap[2];
204    static bool initialized = false;
205    if (!initialized) {
206        make_g_bitmap(bitmap[0]);
207        make_checkerboard_bitmap(bitmap[1]);
208        initialized = true;
209    }
210    return bitmap[R(2)];
211}
212
213static SkData* make_3Dlut(int* cubeDimension, bool invR, bool invG, bool invB) {
214    int size = 4 << R(5);
215    SkData* data = SkData::NewUninitialized(sizeof(SkColor) * size * size * size);
216    SkColor* pixels = (SkColor*)(data->writable_data());
217    SkAutoMalloc lutMemory(size);
218    SkAutoMalloc invLutMemory(size);
219    uint8_t* lut = (uint8_t*)lutMemory.get();
220    uint8_t* invLut = (uint8_t*)invLutMemory.get();
221    const int maxIndex = size - 1;
222    for (int i = 0; i < size; i++) {
223        lut[i] = (i * 255) / maxIndex;
224        invLut[i] = ((maxIndex - i) * 255) / maxIndex;
225    }
226    for (int r = 0; r < size; ++r) {
227        for (int g = 0; g < size; ++g) {
228            for (int b = 0; b < size; ++b) {
229                pixels[(size * ((size * b) + g)) + r] = SkColorSetARGB(0xFF,
230                        invR ? invLut[r] : lut[r],
231                        invG ? invLut[g] : lut[g],
232                        invB ? invLut[b] : lut[b]);
233            }
234        }
235    }
236    if (cubeDimension) {
237        *cubeDimension = size;
238    }
239    return data;
240}
241
242static void drawSomething(SkCanvas* canvas) {
243    SkPaint paint;
244
245    canvas->save();
246    canvas->scale(0.5f, 0.5f);
247    canvas->drawBitmap(make_bitmap(), 0, 0, NULL);
248    canvas->restore();
249
250    paint.setAntiAlias(true);
251
252    paint.setColor(SK_ColorRED);
253    canvas->drawCircle(SkIntToScalar(kBitmapSize/2), SkIntToScalar(kBitmapSize/2), SkIntToScalar(kBitmapSize/3), paint);
254    paint.setColor(SK_ColorBLACK);
255    paint.setTextSize(SkIntToScalar(kBitmapSize/3));
256    canvas->drawText("Picture", 7, SkIntToScalar(kBitmapSize/2), SkIntToScalar(kBitmapSize/4), paint);
257}
258
259static SkImageFilter* make_image_filter(bool canBeNull = true) {
260    SkImageFilter* filter = 0;
261
262    // Add a 1 in 3 chance to get a NULL input
263    if (canBeNull && (R(3) == 1)) { return filter; }
264
265    enum { ALPHA_THRESHOLD, MERGE, COLOR, LUT3D, BLUR, MAGNIFIER,
266           DOWN_SAMPLE, XFERMODE, OFFSET, MATRIX, MATRIX_CONVOLUTION, COMPOSE,
267           DISTANT_LIGHT, POINT_LIGHT, SPOT_LIGHT, NOISE, DROP_SHADOW,
268           MORPHOLOGY, BITMAP, DISPLACE, TILE, PICTURE, NUM_FILTERS };
269
270    switch (R(NUM_FILTERS)) {
271    case ALPHA_THRESHOLD:
272        filter = SkAlphaThresholdFilter::Create(make_region(), make_scalar(), make_scalar());
273        break;
274    case MERGE:
275        filter = SkMergeImageFilter::Create(make_image_filter(), make_image_filter(), make_xfermode());
276        break;
277    case COLOR:
278    {
279        SkAutoTUnref<SkColorFilter> cf((R(2) == 1) ?
280                 SkColorFilter::CreateModeFilter(make_color(), make_xfermode()) :
281                 SkColorFilter::CreateLightingFilter(make_color(), make_color()));
282        filter = cf.get() ? SkColorFilterImageFilter::Create(cf, make_image_filter()) : 0;
283    }
284        break;
285    case LUT3D:
286    {
287        int cubeDimension;
288        SkAutoDataUnref lut3D(make_3Dlut(&cubeDimension, (R(2) == 1), (R(2) == 1), (R(2) == 1)));
289        SkAutoTUnref<SkColorFilter> cf(SkColorCubeFilter::Create(lut3D, cubeDimension));
290        filter = cf.get() ? SkColorFilterImageFilter::Create(cf, make_image_filter()) : 0;
291    }
292        break;
293    case BLUR:
294        filter = SkBlurImageFilter::Create(make_scalar(true), make_scalar(true), make_image_filter());
295        break;
296    case MAGNIFIER:
297        filter = SkMagnifierImageFilter::Create(make_rect(), make_scalar(true));
298        break;
299    case DOWN_SAMPLE:
300        filter = SkDownSampleImageFilter::Create(make_scalar());
301        break;
302    case XFERMODE:
303    {
304        SkAutoTUnref<SkXfermode> mode(SkXfermode::Create(make_xfermode()));
305        filter = SkXfermodeImageFilter::Create(mode, make_image_filter(), make_image_filter());
306    }
307        break;
308    case OFFSET:
309        filter = SkOffsetImageFilter::Create(make_scalar(), make_scalar(), make_image_filter());
310        break;
311    case MATRIX:
312        filter = SkImageFilter::CreateMatrixFilter(make_matrix(),
313                                                   (SkFilterQuality)R(4),
314                                                   make_image_filter());
315        break;
316    case MATRIX_CONVOLUTION:
317    {
318        SkImageFilter::CropRect cropR(SkRect::MakeWH(SkIntToScalar(kBitmapSize),
319                                                     SkIntToScalar(kBitmapSize)));
320        SkISize size = SkISize::Make(R(10)+1, R(10)+1);
321        int arraySize = size.width() * size.height();
322        SkTArray<SkScalar> kernel(arraySize);
323        for (int i = 0; i < arraySize; ++i) {
324            kernel.push_back() = make_scalar();
325        }
326        SkIPoint kernelOffset = SkIPoint::Make(R(SkIntToScalar(size.width())),
327                                               R(SkIntToScalar(size.height())));
328        filter = SkMatrixConvolutionImageFilter::Create(size,
329                                                        kernel.begin(),
330                                                        make_scalar(),
331                                                        make_scalar(),
332                                                        kernelOffset,
333                                                        (SkMatrixConvolutionImageFilter::TileMode)R(3),
334                                                        R(2) == 1,
335                                                        make_image_filter(),
336                                                        &cropR);
337    }
338        break;
339    case COMPOSE:
340        filter = SkComposeImageFilter::Create(make_image_filter(), make_image_filter());
341        break;
342    case DISTANT_LIGHT:
343        filter = (R(2) == 1) ?
344                 SkLightingImageFilter::CreateDistantLitDiffuse(make_point(),
345                 make_color(), make_scalar(), make_scalar(), make_image_filter()) :
346                 SkLightingImageFilter::CreateDistantLitSpecular(make_point(),
347                 make_color(), make_scalar(), make_scalar(), SkIntToScalar(R(10)),
348                 make_image_filter());
349        break;
350    case POINT_LIGHT:
351        filter = (R(2) == 1) ?
352                 SkLightingImageFilter::CreatePointLitDiffuse(make_point(),
353                 make_color(), make_scalar(), make_scalar(), make_image_filter()) :
354                 SkLightingImageFilter::CreatePointLitSpecular(make_point(),
355                 make_color(), make_scalar(), make_scalar(), SkIntToScalar(R(10)),
356                 make_image_filter());
357        break;
358    case SPOT_LIGHT:
359        filter = (R(2) == 1) ?
360                 SkLightingImageFilter::CreateSpotLitDiffuse(SkPoint3(0, 0, 0),
361                 make_point(), make_scalar(), make_scalar(), make_color(),
362                 make_scalar(), make_scalar(), make_image_filter()) :
363                 SkLightingImageFilter::CreateSpotLitSpecular(SkPoint3(0, 0, 0),
364                 make_point(), make_scalar(), make_scalar(), make_color(),
365                 make_scalar(), make_scalar(), SkIntToScalar(R(10)), make_image_filter());
366        break;
367    case NOISE:
368    {
369        SkAutoTUnref<SkShader> shader((R(2) == 1) ?
370            SkPerlinNoiseShader::CreateFractalNoise(
371                make_scalar(true), make_scalar(true), R(10.0f), make_scalar()) :
372            SkPerlinNoiseShader::CreateTurbulence(
373                make_scalar(true), make_scalar(true), R(10.0f), make_scalar()));
374        SkImageFilter::CropRect cropR(SkRect::MakeWH(SkIntToScalar(kBitmapSize),
375                                                     SkIntToScalar(kBitmapSize)));
376        filter = SkRectShaderImageFilter::Create(shader, &cropR);
377    }
378        break;
379    case DROP_SHADOW:
380        filter = SkDropShadowImageFilter::Create(make_scalar(), make_scalar(), make_scalar(true),
381                    make_scalar(true), make_color(), make_shadow_mode(), make_image_filter(),
382                    NULL);
383        break;
384    case MORPHOLOGY:
385        if (R(2) == 1) {
386            filter = SkDilateImageFilter::Create(R(static_cast<float>(kBitmapSize)),
387                R(static_cast<float>(kBitmapSize)), make_image_filter());
388        } else {
389            filter = SkErodeImageFilter::Create(R(static_cast<float>(kBitmapSize)),
390                R(static_cast<float>(kBitmapSize)), make_image_filter());
391        }
392        break;
393    case BITMAP:
394        if (R(2) == 1) {
395            filter = SkBitmapSource::Create(make_bitmap(), make_rect(), make_rect());
396        } else {
397            filter = SkBitmapSource::Create(make_bitmap());
398        }
399        break;
400    case DISPLACE:
401        filter = SkDisplacementMapEffect::Create(make_channel_selector_type(),
402                                                 make_channel_selector_type(), make_scalar(),
403                                                 make_image_filter(false), make_image_filter());
404        break;
405    case TILE:
406        filter = SkTileImageFilter::Create(make_rect(), make_rect(), make_image_filter(false));
407        break;
408    case PICTURE:
409    {
410        SkRTreeFactory factory;
411        SkPictureRecorder recorder;
412        SkCanvas* recordingCanvas = recorder.beginRecording(SkIntToScalar(kBitmapSize),
413                                                            SkIntToScalar(kBitmapSize),
414                                                            &factory, 0);
415        drawSomething(recordingCanvas);
416        SkAutoTUnref<SkPicture> pict(recorder.endRecording());
417        filter = SkPictureImageFilter::Create(pict.get(), make_rect());
418    }
419        break;
420    default:
421        break;
422    }
423    return (filter || canBeNull) ? filter : make_image_filter(canBeNull);
424}
425
426static SkImageFilter* make_serialized_image_filter() {
427    SkAutoTUnref<SkImageFilter> filter(make_image_filter(false));
428    SkAutoTUnref<SkData> data(SkValidatingSerializeFlattenable(filter));
429    const unsigned char* ptr = static_cast<const unsigned char*>(data->data());
430    size_t len = data->size();
431#ifdef SK_ADD_RANDOM_BIT_FLIPS
432    unsigned char* p = const_cast<unsigned char*>(ptr);
433    for (size_t i = 0; i < len; ++i, ++p) {
434        if (R(250) == 1) { // 0.4% of the time, flip a bit or byte
435            if (R(10) == 1) { // Then 10% of the time, change a whole byte
436                switch(R(3)) {
437                case 0:
438                    *p ^= 0xFF; // Flip entire byte
439                    break;
440                case 1:
441                    *p = 0xFF; // Set all bits to 1
442                    break;
443                case 2:
444                    *p = 0x00; // Set all bits to 0
445                    break;
446                }
447            } else {
448                *p ^= (1 << R(8));
449            }
450        }
451    }
452#endif // SK_ADD_RANDOM_BIT_FLIPS
453    SkFlattenable* flattenable = SkValidatingDeserializeFlattenable(ptr, len,
454                                    SkImageFilter::GetFlattenableType());
455    return static_cast<SkImageFilter*>(flattenable);
456}
457
458static void drawClippedBitmap(SkCanvas* canvas, int x, int y, const SkPaint& paint) {
459    canvas->save();
460    canvas->clipRect(SkRect::MakeXYWH(SkIntToScalar(x), SkIntToScalar(y),
461        SkIntToScalar(kBitmapSize), SkIntToScalar(kBitmapSize)));
462    canvas->drawBitmap(make_bitmap(), SkIntToScalar(x), SkIntToScalar(y), &paint);
463    canvas->restore();
464}
465
466static void do_fuzz(SkCanvas* canvas) {
467    SkImageFilter* filter = make_serialized_image_filter();
468
469#ifdef SK_FUZZER_IS_VERBOSE
470    static uint32_t numFilters = 0;
471    static uint32_t numValidFilters = 0;
472    if (0 == numFilters) {
473        printf("Fuzzing with %u\n", kSeed);
474    }
475    numFilters++;
476    if (filter) {
477        numValidFilters++;
478    }
479    printf("Filter no : %u. Valid filters so far : %u\r", numFilters, numValidFilters);
480    fflush(stdout);
481#endif
482
483    SkPaint paint;
484    SkSafeUnref(paint.setImageFilter(filter));
485    drawClippedBitmap(canvas, 0, 0, paint);
486}
487
488//////////////////////////////////////////////////////////////////////////////
489
490class ImageFilterFuzzView : public SampleView {
491public:
492    ImageFilterFuzzView() {
493        this->setBGColor(0xFFDDDDDD);
494    }
495
496protected:
497    // overrides from SkEventSink
498    virtual bool onQuery(SkEvent* evt) {
499        if (SampleCode::TitleQ(*evt)) {
500            SampleCode::TitleR(evt, "ImageFilterFuzzer");
501            return true;
502        }
503        return this->INHERITED::onQuery(evt);
504    }
505
506    void drawBG(SkCanvas* canvas) {
507        canvas->drawColor(0xFFDDDDDD);
508    }
509
510    virtual void onDrawContent(SkCanvas* canvas) {
511        do_fuzz(canvas);
512        this->inval(0);
513    }
514
515private:
516    typedef SkView INHERITED;
517};
518
519//////////////////////////////////////////////////////////////////////////////
520
521static SkView* MyFactory() { return new ImageFilterFuzzView; }
522static SkViewRegister reg(MyFactory);
523