You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
275 lines
7.5 KiB
275 lines
7.5 KiB
/*
|
|
* 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.h"
|
|
#include "SkCanvas.h"
|
|
#include "SkCommonFlags.h"
|
|
#include "SkGradientShader.h"
|
|
#include "SkSurface.h"
|
|
#include "SkTLazy.h"
|
|
|
|
#include <algorithm>
|
|
#include <vector>
|
|
|
|
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, SkShader::TileMode* 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<SkShader::TileMode>(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,
|
|
SkShader::TileMode 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"
|
|
};
|
|
SkASSERT(mode < SK_ARRAY_COUNT(gModeName));
|
|
SkDebugf(" mode:\t\t%s\n", gModeName[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;
|
|
SkShader::TileMode 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;
|
|
SkShader::TileMode 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;
|
|
SkShader::TileMode 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;
|
|
SkShader::TileMode 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;
|
|
}
|