/*
 * 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 "CommonFlags.h"
#include "Fuzz.h"
#include "SkCanvas.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(&center.fX, &center.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;
}
