Home | History | Annotate | Download | only in fuzz
      1 /*
      2  * Copyright 2016 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 
      8 #include "Fuzz.h"
      9 #include "SkCanvas.h"
     10 #include "SkCommonFlags.h"
     11 #include "SkGradientShader.h"
     12 #include "SkSurface.h"
     13 #include "SkTLazy.h"
     14 
     15 #include <algorithm>
     16 #include <vector>
     17 
     18 const int MAX_COUNT = 400;
     19 
     20 void makeMatrix(Fuzz* fuzz, SkMatrix* m) {
     21     SkScalar mat[9];
     22     fuzz->nextN(mat, 9);
     23     m->set9(mat);
     24 }
     25 
     26 void initGradientParams(Fuzz* fuzz, std::vector<SkColor>* colors,
     27                         std::vector<SkScalar>* pos, SkShader::TileMode* mode) {
     28     int count;
     29     fuzz->nextRange(&count, 0, MAX_COUNT);
     30 
     31     // Use a uint8_t to conserve bytes.  This makes our "fuzzed bytes footprint"
     32     // smaller, which leads to more efficient fuzzing.
     33     uint8_t m;
     34     fuzz->nextRange(&m, 0, 2);
     35     *mode = static_cast<SkShader::TileMode>(m);
     36 
     37     colors->clear();
     38     pos   ->clear();
     39     for (int i = 0; i < count; i++) {
     40         SkColor c;
     41         SkScalar s;
     42         fuzz->next(&c, &s);
     43         colors->push_back(c);
     44         pos   ->push_back(s);
     45     }
     46     if (count) {
     47         std::sort(pos->begin(), pos->end());
     48         // The order matters.  If count == 1, we want pos == 0.
     49         (*pos)[count - 1] = 1;
     50         (*pos)[0]         = 0;
     51     }
     52 }
     53 
     54 static void logOptionalMatrix(const char* label, const SkMatrix* m) {
     55     if (!m) {
     56         return;
     57     }
     58 
     59     SkDEBUGF("  %s: [ ", label);
     60     for (int i = 0; i < 9; ++i) {
     61         SkDEBUGF("%.9g ", m->get(i));
     62     }
     63     SkDEBUGF("]\n");
     64 }
     65 
     66 static void logLinearGradient(const SkPoint pts[2],
     67                               const std::vector<SkColor>& colors,
     68                               const std::vector<SkScalar> pos,
     69                               SkShader::TileMode mode,
     70                               uint32_t flags,
     71                               const SkMatrix* localMatrix,
     72                               const SkMatrix* globalMatrix) {
     73     if (!FLAGS_verbose) {
     74         return;
     75     }
     76 
     77     SkDebugf("--- fuzzLinearGradient ---\n");
     78     SkDebugf("  pts:\t\t[ (%.9g %.9g) (%.9g %.9g) ]\n",
     79              pts[0].x(), pts[0].y(), pts[1].x(), pts[1].y());
     80     SkDebugf("  colors:\t[ ");
     81     for (auto color : colors) {
     82         SkDebugf("0x%x ", color);
     83     }
     84 
     85     SkDebugf("]\n  pos:\t\t");
     86     if (pos.empty()) {
     87         SkDebugf("nullptr");
     88     } else {
     89         SkDebugf("[ ");
     90         for (auto p : pos) {
     91             SkDebugf("%f ", p);
     92         }
     93     }
     94     SkDebugf("]\n");
     95 
     96     static const char* gModeName[] = {
     97         "kClamp_TileMode", "kRepeat_TileMode", "kMirror_TileMode"
     98     };
     99     SkASSERT(mode < SK_ARRAY_COUNT(gModeName));
    100     SkDebugf("  mode:\t\t%s\n", gModeName[mode]);
    101     SkDebugf("  flags:\t0x%x\n", flags);
    102     logOptionalMatrix("local matrix", localMatrix);
    103     logOptionalMatrix("global matrix", globalMatrix);
    104 }
    105 
    106 void fuzzLinearGradient(Fuzz* fuzz) {
    107     SkPoint pts[2];
    108     fuzz->next(&pts[0].fX, &pts[0].fY, &pts[1].fX, &pts[1].fY);
    109     bool useLocalMatrix, useGlobalMatrix;
    110     fuzz->next(&useLocalMatrix, &useGlobalMatrix);
    111 
    112     std::vector<SkColor> colors;
    113     std::vector<SkScalar> pos;
    114     SkShader::TileMode mode;
    115     initGradientParams(fuzz, &colors, &pos, &mode);
    116 
    117     SkPaint p;
    118     uint32_t flags;
    119     fuzz->next(&flags);
    120 
    121     SkTLazy<SkMatrix> localMatrix;
    122     if (useLocalMatrix) {
    123         makeMatrix(fuzz, localMatrix.init());
    124     }
    125     p.setShader(SkGradientShader::MakeLinear(pts, colors.data(), pos.data(),
    126         colors.size(), mode, flags, localMatrix.getMaybeNull()));
    127 
    128     sk_sp<SkSurface> surface(SkSurface::MakeRasterN32Premul(50, 50));
    129     if (useGlobalMatrix) {
    130         SkMatrix gm;
    131         makeMatrix(fuzz, &gm);
    132         logLinearGradient(pts, colors, pos, mode, flags, localMatrix.getMaybeNull(), &gm);
    133         SkCanvas* c = surface->getCanvas();
    134         c->setMatrix(gm);
    135         c->drawPaint(p);
    136     } else {
    137         logLinearGradient(pts, colors, pos, mode, flags, localMatrix.getMaybeNull(), nullptr);
    138         surface->getCanvas()->drawPaint(p);
    139     }
    140 }
    141 
    142 void fuzzRadialGradient(Fuzz* fuzz) {
    143     SkPoint center;
    144     fuzz->next(&center.fX, &center.fY);
    145     SkScalar radius;
    146     bool useLocalMatrix, useGlobalMatrix;
    147     fuzz->next(&radius, &useLocalMatrix, &useGlobalMatrix);
    148 
    149 
    150     std::vector<SkColor> colors;
    151     std::vector<SkScalar> pos;
    152     SkShader::TileMode mode;
    153     initGradientParams(fuzz, &colors, &pos, &mode);
    154 
    155     SkPaint p;
    156     uint32_t flags;
    157     fuzz->next(&flags);
    158 
    159     SkTLazy<SkMatrix> localMatrix;
    160     if (useLocalMatrix) {
    161         makeMatrix(fuzz, localMatrix.init());
    162     }
    163     p.setShader(SkGradientShader::MakeRadial(center, radius, colors.data(),
    164         pos.data(), colors.size(), mode, flags, localMatrix.getMaybeNull()));
    165 
    166 
    167     sk_sp<SkSurface> surface(SkSurface::MakeRasterN32Premul(50, 50));
    168     if (useGlobalMatrix) {
    169         SkMatrix gm;
    170         makeMatrix(fuzz, &gm);
    171         SkCanvas* c = surface->getCanvas();
    172         c->setMatrix(gm);
    173         c->drawPaint(p);
    174     } else {
    175         surface->getCanvas()->drawPaint(p);
    176     }
    177 }
    178 
    179 void fuzzTwoPointConicalGradient(Fuzz* fuzz) {
    180     SkPoint start;
    181     fuzz->next(&start.fX, &start.fY);
    182     SkPoint end;
    183     fuzz->next(&end.fX, &end.fY);
    184     SkScalar startRadius, endRadius;
    185     bool useLocalMatrix, useGlobalMatrix;
    186     fuzz->next(&startRadius, &endRadius, &useLocalMatrix, &useGlobalMatrix);
    187 
    188     std::vector<SkColor> colors;
    189     std::vector<SkScalar> pos;
    190     SkShader::TileMode mode;
    191     initGradientParams(fuzz, &colors, &pos, &mode);
    192 
    193     SkPaint p;
    194     uint32_t flags;
    195     fuzz->next(&flags);
    196 
    197     SkTLazy<SkMatrix> localMatrix;
    198     if (useLocalMatrix) {
    199         makeMatrix(fuzz, localMatrix.init());
    200     }
    201     p.setShader(SkGradientShader::MakeTwoPointConical(start, startRadius,
    202         end, endRadius, colors.data(), pos.data(), colors.size(), mode,
    203         flags, localMatrix.getMaybeNull()));
    204 
    205     sk_sp<SkSurface> surface(SkSurface::MakeRasterN32Premul(50, 50));
    206     if (useGlobalMatrix) {
    207         SkMatrix gm;
    208         makeMatrix(fuzz, &gm);
    209         SkCanvas* c = surface->getCanvas();
    210         c->setMatrix(gm);
    211         c->drawPaint(p);
    212     } else {
    213         surface->getCanvas()->drawPaint(p);
    214     }
    215 }
    216 
    217 void fuzzSweepGradient(Fuzz* fuzz) {
    218     SkScalar cx, cy;
    219     bool useLocalMatrix, useGlobalMatrix;
    220     fuzz->next(&cx, &cy, &useLocalMatrix, &useGlobalMatrix);
    221 
    222     std::vector<SkColor> colors;
    223     std::vector<SkScalar> pos;
    224     SkShader::TileMode mode;
    225     initGradientParams(fuzz, &colors, &pos, &mode);
    226 
    227     SkPaint p;
    228     if (useLocalMatrix) {
    229         SkMatrix m;
    230         makeMatrix(fuzz, &m);
    231         uint32_t flags;
    232         fuzz->next(&flags);
    233 
    234         p.setShader(SkGradientShader::MakeSweep(cx, cy, colors.data(),
    235             pos.data(), colors.size(), flags, &m));
    236     } else {
    237         p.setShader(SkGradientShader::MakeSweep(cx, cy, colors.data(),
    238             pos.data(), colors.size()));
    239     }
    240 
    241     sk_sp<SkSurface> surface(SkSurface::MakeRasterN32Premul(50, 50));
    242     if (useGlobalMatrix) {
    243         SkMatrix gm;
    244         makeMatrix(fuzz, &gm);
    245         SkCanvas* c = surface->getCanvas();
    246         c->setMatrix(gm);
    247         c->drawPaint(p);
    248     } else {
    249         surface->getCanvas()->drawPaint(p);
    250     }
    251 }
    252 
    253 DEF_FUZZ(Gradients, fuzz) {
    254     uint8_t i;
    255     fuzz->next(&i);
    256 
    257     switch(i) {
    258         case 0:
    259             SkDEBUGF("LinearGradient\n");
    260             fuzzLinearGradient(fuzz);
    261             return;
    262         case 1:
    263             SkDEBUGF("RadialGradient\n");
    264             fuzzRadialGradient(fuzz);
    265             return;
    266         case 2:
    267             SkDEBUGF("TwoPointConicalGradient\n");
    268             fuzzTwoPointConicalGradient(fuzz);
    269             return;
    270     }
    271     SkDEBUGF("SweepGradient\n");
    272     fuzzSweepGradient(fuzz);
    273     return;
    274 }
    275