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 18const int MAX_COUNT = 400; 19 20void makeMatrix(Fuzz* fuzz, SkMatrix* m) { 21 SkScalar mat[9]; 22 fuzz->nextN(mat, 9); 23 m->set9(mat); 24} 25 26void 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 54static 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 66static 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 106void 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 142void fuzzRadialGradient(Fuzz* fuzz) { 143 SkPoint center; 144 fuzz->next(¢er.fX, ¢er.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 179void 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 217void 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 253DEF_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