/*
 * 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 "Benchmark.h"
#include "Resources.h"
#include "SkAutoPixmapStorage.h"
#include "SkData.h"
#include "SkGradientShader.h"
#include "SkImage.h"
#include "SkPDFBitmap.h"
#include "SkPDFDocument.h"
#include "SkPDFShader.h"
#include "SkPDFUtils.h"
#include "SkPixmap.h"
#include "SkRandom.h"

namespace {
struct NullWStream : public SkWStream {
    NullWStream() : fN(0) {}
    bool write(const void*, size_t n) override { fN += n; return true; }
    size_t bytesWritten() const override { return fN; }
    size_t fN;
};

static void test_pdf_object_serialization(const sk_sp<SkPDFObject> object) {
    // SkDebugWStream wStream;
    NullWStream wStream;
    SkPDFSubstituteMap substitutes;
    SkPDFObjNumMap objNumMap;
    objNumMap.addObjectRecursively(object.get(), substitutes);
    for (int i = 0; i < objNumMap.objects().count(); ++i) {
        SkPDFObject* object = objNumMap.objects()[i].get();
        wStream.writeDecAsText(i + 1);
        wStream.writeText(" 0 obj\n");
        object->emitObject(&wStream, objNumMap, substitutes);
        wStream.writeText("\nendobj\n");
    }
}

class PDFImageBench : public Benchmark {
public:
    PDFImageBench() {}
    virtual ~PDFImageBench() {}

protected:
    const char* onGetName() override { return "PDFImage"; }
    bool isSuitableFor(Backend backend) override {
        return backend == kNonRendering_Backend;
    }
    void onDelayedSetup() override {
        sk_sp<SkImage> img(GetResourceAsImage("color_wheel.png"));
        if (img) {
            // force decoding, throw away reference to encoded data.
            SkAutoPixmapStorage pixmap;
            pixmap.alloc(SkImageInfo::MakeN32Premul(img->dimensions()));
            if (img->readPixels(pixmap, 0, 0)) {
                fImage = SkImage::MakeRasterCopy(pixmap);
            }
        }
    }
    void onDraw(int loops, SkCanvas*) override {
        if (!fImage) {
            return;
        }
        while (loops-- > 0) {
            auto object = SkPDFCreateBitmapObject(fImage, nullptr);
            SkASSERT(object);
            if (!object) {
                return;
            }
            test_pdf_object_serialization(object);
        }
    }

private:
    sk_sp<SkImage> fImage;
};

class PDFJpegImageBench : public Benchmark {
public:
    PDFJpegImageBench() {}
    virtual ~PDFJpegImageBench() {}

protected:
    const char* onGetName() override { return "PDFJpegImage"; }
    bool isSuitableFor(Backend backend) override {
        return backend == kNonRendering_Backend;
    }
    void onDelayedSetup() override {
        sk_sp<SkImage> img(GetResourceAsImage("mandrill_512_q075.jpg"));
        if (!img) { return; }
        sk_sp<SkData> encoded(img->refEncoded());
        SkASSERT(encoded);
        if (!encoded) { return; }
        fImage = img;
    }
    void onDraw(int loops, SkCanvas*) override {
        if (!fImage) {
            SkDEBUGFAIL("");
            return;
        }
        while (loops-- > 0) {
            auto object = SkPDFCreateBitmapObject(fImage, nullptr);
            SkASSERT(object);
            if (!object) {
                return;
            }
            test_pdf_object_serialization(object);
        }
    }

private:
    sk_sp<SkImage> fImage;
};

/** Test calling DEFLATE on a 78k PDF command stream. Used for measuring
    alternate zlib settings, usage, and library versions. */
class PDFCompressionBench : public Benchmark {
public:
    PDFCompressionBench() {}
    virtual ~PDFCompressionBench() {}

protected:
    const char* onGetName() override { return "PDFCompression"; }
    bool isSuitableFor(Backend backend) override {
        return backend == kNonRendering_Backend;
    }
    void onDelayedSetup() override {
        fAsset.reset(GetResourceAsStream("pdf_command_stream.txt"));
    }
    void onDraw(int loops, SkCanvas*) override {
        SkASSERT(fAsset);
        if (!fAsset) { return; }
        while (loops-- > 0) {
            sk_sp<SkPDFObject> object(
                    new SkPDFSharedStream(fAsset->duplicate()));
            test_pdf_object_serialization(object);
        }
    }

private:
    SkAutoTDelete<SkStreamAsset> fAsset;
};

// Test speed of SkPDFUtils::FloatToDecimal for typical floats that
// might be found in a PDF document.
struct PDFScalarBench : public Benchmark {
    bool isSuitableFor(Backend b) override {
        return b == kNonRendering_Backend;
    }
    const char* onGetName() override { return "PDFScalar"; }
    void onDraw(int loops, SkCanvas*) override {
        SkRandom random;
        char dst[SkPDFUtils::kMaximumFloatDecimalLength];
        while (loops-- > 0) {
            auto f = random.nextRangeF(-500.0f, 1500.0f);
            (void)SkPDFUtils::FloatToDecimal(f, dst);
        }
    }
};

struct PDFShaderBench : public Benchmark {
    sk_sp<SkShader> fShader;
    const char* onGetName() final { return "PDFShader"; }
    bool isSuitableFor(Backend b) final { return b == kNonRendering_Backend; }
    void onDelayedSetup() final {
        const SkPoint pts[2] = {{0.0f, 0.0f}, {100.0f, 100.0f}};
        const SkColor colors[] = {
            SK_ColorRED, SK_ColorGREEN, SK_ColorBLUE,
            SK_ColorWHITE, SK_ColorBLACK,
        };
        fShader = SkGradientShader::MakeLinear(
                pts, colors, nullptr, SK_ARRAY_COUNT(colors),
                SkShader::kClamp_TileMode);
    }
    void onDraw(int loops, SkCanvas*) final {
        SkASSERT(fShader);
        while (loops-- > 0) {
            NullWStream nullStream;
            SkPDFDocument doc(&nullStream, nullptr, 72, nullptr);
            sk_sp<SkPDFObject> shader(
                    SkPDFShader::GetPDFShader(
                            &doc, 72, fShader.get(), SkMatrix::I(),
                            SkIRect::MakeWH(400,400), 72));
        }
    }
};

}  // namespace
DEF_BENCH(return new PDFImageBench;)
DEF_BENCH(return new PDFJpegImageBench;)
DEF_BENCH(return new PDFCompressionBench;)
DEF_BENCH(return new PDFScalarBench;)
DEF_BENCH(return new PDFShaderBench;)
