| /* | |
| * Copyright 2016 Google Inc. | |
| * | |
| * Use of this source code is governed by a BSD-style license that can be | |
| * found in the LICENSE file. | |
| */ | |
| #include "fuzz/Fuzz.h" | |
| #include "include/core/SkCanvas.h" | |
| #include "include/core/SkSurface.h" | |
| #include "include/effects/SkGradientShader.h" | |
| #include "src/core/SkTLazy.h" | |
| #include "tools/flags/CommandLineFlags.h" | |
| #include <algorithm> | |
| #include <vector> | |
| static DEFINE_bool2(verbose, v, false, "log verbose linear gradient description"); | |
| const int MAX_COUNT = 400; | |
| void makeMatrix(Fuzz* fuzz, SkMatrix* m) { | |
| SkScalar mat[9]; | |
| fuzz->nextN(mat, 9); | |
| m->set9(mat); | |
| } | |
| void initGradientParams(Fuzz* fuzz, std::vector<SkColor>* colors, | |
| std::vector<SkScalar>* pos, SkTileMode* mode) { | |
| int count; | |
| fuzz->nextRange(&count, 0, MAX_COUNT); | |
| // Use a uint8_t to conserve bytes. This makes our "fuzzed bytes footprint" | |
| // smaller, which leads to more efficient fuzzing. | |
| uint8_t m; | |
| fuzz->nextRange(&m, 0, 2); | |
| *mode = static_cast<SkTileMode>(m); | |
| colors->clear(); | |
| pos ->clear(); | |
| for (int i = 0; i < count; i++) { | |
| SkColor c; | |
| SkScalar s; | |
| fuzz->next(&c, &s); | |
| colors->push_back(c); | |
| pos ->push_back(s); | |
| } | |
| if (count) { | |
| std::sort(pos->begin(), pos->end()); | |
| // The order matters. If count == 1, we want pos == 0. | |
| (*pos)[count - 1] = 1; | |
| (*pos)[0] = 0; | |
| } | |
| } | |
| static void logOptionalMatrix(const char* label, const SkMatrix* m) { | |
| if (!m) { | |
| return; | |
| } | |
| SkDEBUGF(" %s: [ ", label); | |
| for (int i = 0; i < 9; ++i) { | |
| SkDEBUGF("%.9g ", m->get(i)); | |
| } | |
| SkDEBUGF("]\n"); | |
| } | |
| static void logLinearGradient(const SkPoint pts[2], | |
| const std::vector<SkColor>& colors, | |
| const std::vector<SkScalar> pos, | |
| SkTileMode mode, | |
| uint32_t flags, | |
| const SkMatrix* localMatrix, | |
| const SkMatrix* globalMatrix) { | |
| if (!FLAGS_verbose) { | |
| return; | |
| } | |
| SkDebugf("--- fuzzLinearGradient ---\n"); | |
| SkDebugf(" pts:\t\t[ (%.9g %.9g) (%.9g %.9g) ]\n", | |
| pts[0].x(), pts[0].y(), pts[1].x(), pts[1].y()); | |
| SkDebugf(" colors:\t[ "); | |
| for (auto color : colors) { | |
| SkDebugf("0x%x ", color); | |
| } | |
| SkDebugf("]\n pos:\t\t"); | |
| if (pos.empty()) { | |
| SkDebugf("nullptr"); | |
| } else { | |
| SkDebugf("[ "); | |
| for (auto p : pos) { | |
| SkDebugf("%f ", p); | |
| } | |
| } | |
| SkDebugf("]\n"); | |
| static const char* gModeName[] = { | |
| "kClamp_TileMode", "kRepeat_TileMode", "kMirror_TileMode", "kDecal_TileMode" | |
| }; | |
| SkASSERT((unsigned)mode < SK_ARRAY_COUNT(gModeName)); | |
| SkDebugf(" mode:\t\t%s\n", gModeName[(unsigned)mode]); | |
| SkDebugf(" flags:\t0x%x\n", flags); | |
| logOptionalMatrix("local matrix", localMatrix); | |
| logOptionalMatrix("global matrix", globalMatrix); | |
| } | |
| void fuzzLinearGradient(Fuzz* fuzz) { | |
| SkPoint pts[2]; | |
| fuzz->next(&pts[0].fX, &pts[0].fY, &pts[1].fX, &pts[1].fY); | |
| bool useLocalMatrix, useGlobalMatrix; | |
| fuzz->next(&useLocalMatrix, &useGlobalMatrix); | |
| std::vector<SkColor> colors; | |
| std::vector<SkScalar> pos; | |
| SkTileMode mode; | |
| initGradientParams(fuzz, &colors, &pos, &mode); | |
| SkPaint p; | |
| uint32_t flags; | |
| fuzz->next(&flags); | |
| SkTLazy<SkMatrix> localMatrix; | |
| if (useLocalMatrix) { | |
| makeMatrix(fuzz, localMatrix.init()); | |
| } | |
| p.setShader(SkGradientShader::MakeLinear(pts, colors.data(), pos.data(), | |
| colors.size(), mode, flags, localMatrix.getMaybeNull())); | |
| sk_sp<SkSurface> surface(SkSurface::MakeRasterN32Premul(50, 50)); | |
| if (useGlobalMatrix) { | |
| SkMatrix gm; | |
| makeMatrix(fuzz, &gm); | |
| logLinearGradient(pts, colors, pos, mode, flags, localMatrix.getMaybeNull(), &gm); | |
| SkCanvas* c = surface->getCanvas(); | |
| c->setMatrix(gm); | |
| c->drawPaint(p); | |
| } else { | |
| logLinearGradient(pts, colors, pos, mode, flags, localMatrix.getMaybeNull(), nullptr); | |
| surface->getCanvas()->drawPaint(p); | |
| } | |
| } | |
| void fuzzRadialGradient(Fuzz* fuzz) { | |
| SkPoint center; | |
| fuzz->next(¢er.fX, ¢er.fY); | |
| SkScalar radius; | |
| bool useLocalMatrix, useGlobalMatrix; | |
| fuzz->next(&radius, &useLocalMatrix, &useGlobalMatrix); | |
| std::vector<SkColor> colors; | |
| std::vector<SkScalar> pos; | |
| SkTileMode mode; | |
| initGradientParams(fuzz, &colors, &pos, &mode); | |
| SkPaint p; | |
| uint32_t flags; | |
| fuzz->next(&flags); | |
| SkTLazy<SkMatrix> localMatrix; | |
| if (useLocalMatrix) { | |
| makeMatrix(fuzz, localMatrix.init()); | |
| } | |
| p.setShader(SkGradientShader::MakeRadial(center, radius, colors.data(), | |
| pos.data(), colors.size(), mode, flags, localMatrix.getMaybeNull())); | |
| sk_sp<SkSurface> surface(SkSurface::MakeRasterN32Premul(50, 50)); | |
| if (useGlobalMatrix) { | |
| SkMatrix gm; | |
| makeMatrix(fuzz, &gm); | |
| SkCanvas* c = surface->getCanvas(); | |
| c->setMatrix(gm); | |
| c->drawPaint(p); | |
| } else { | |
| surface->getCanvas()->drawPaint(p); | |
| } | |
| } | |
| void fuzzTwoPointConicalGradient(Fuzz* fuzz) { | |
| SkPoint start; | |
| fuzz->next(&start.fX, &start.fY); | |
| SkPoint end; | |
| fuzz->next(&end.fX, &end.fY); | |
| SkScalar startRadius, endRadius; | |
| bool useLocalMatrix, useGlobalMatrix; | |
| fuzz->next(&startRadius, &endRadius, &useLocalMatrix, &useGlobalMatrix); | |
| std::vector<SkColor> colors; | |
| std::vector<SkScalar> pos; | |
| SkTileMode mode; | |
| initGradientParams(fuzz, &colors, &pos, &mode); | |
| SkPaint p; | |
| uint32_t flags; | |
| fuzz->next(&flags); | |
| SkTLazy<SkMatrix> localMatrix; | |
| if (useLocalMatrix) { | |
| makeMatrix(fuzz, localMatrix.init()); | |
| } | |
| p.setShader(SkGradientShader::MakeTwoPointConical(start, startRadius, | |
| end, endRadius, colors.data(), pos.data(), colors.size(), mode, | |
| flags, localMatrix.getMaybeNull())); | |
| sk_sp<SkSurface> surface(SkSurface::MakeRasterN32Premul(50, 50)); | |
| if (useGlobalMatrix) { | |
| SkMatrix gm; | |
| makeMatrix(fuzz, &gm); | |
| SkCanvas* c = surface->getCanvas(); | |
| c->setMatrix(gm); | |
| c->drawPaint(p); | |
| } else { | |
| surface->getCanvas()->drawPaint(p); | |
| } | |
| } | |
| void fuzzSweepGradient(Fuzz* fuzz) { | |
| SkScalar cx, cy; | |
| bool useLocalMatrix, useGlobalMatrix; | |
| fuzz->next(&cx, &cy, &useLocalMatrix, &useGlobalMatrix); | |
| std::vector<SkColor> colors; | |
| std::vector<SkScalar> pos; | |
| SkTileMode mode; | |
| initGradientParams(fuzz, &colors, &pos, &mode); | |
| SkPaint p; | |
| if (useLocalMatrix) { | |
| SkMatrix m; | |
| makeMatrix(fuzz, &m); | |
| uint32_t flags; | |
| fuzz->next(&flags); | |
| p.setShader(SkGradientShader::MakeSweep(cx, cy, colors.data(), | |
| pos.data(), colors.size(), flags, &m)); | |
| } else { | |
| p.setShader(SkGradientShader::MakeSweep(cx, cy, colors.data(), | |
| pos.data(), colors.size())); | |
| } | |
| sk_sp<SkSurface> surface(SkSurface::MakeRasterN32Premul(50, 50)); | |
| if (useGlobalMatrix) { | |
| SkMatrix gm; | |
| makeMatrix(fuzz, &gm); | |
| SkCanvas* c = surface->getCanvas(); | |
| c->setMatrix(gm); | |
| c->drawPaint(p); | |
| } else { | |
| surface->getCanvas()->drawPaint(p); | |
| } | |
| } | |
| DEF_FUZZ(Gradients, fuzz) { | |
| uint8_t i; | |
| fuzz->next(&i); | |
| switch(i) { | |
| case 0: | |
| SkDEBUGF("LinearGradient\n"); | |
| fuzzLinearGradient(fuzz); | |
| return; | |
| case 1: | |
| SkDEBUGF("RadialGradient\n"); | |
| fuzzRadialGradient(fuzz); | |
| return; | |
| case 2: | |
| SkDEBUGF("TwoPointConicalGradient\n"); | |
| fuzzTwoPointConicalGradient(fuzz); | |
| return; | |
| } | |
| SkDEBUGF("SweepGradient\n"); | |
| fuzzSweepGradient(fuzz); | |
| return; | |
| } |