/*
 * Copyright 2011 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "gm/gm.h"
#include "include/core/SkBitmap.h"
#include "include/core/SkCanvas.h"
#include "include/core/SkColor.h"
#include "include/core/SkFont.h"
#include "include/core/SkImageInfo.h"
#include "include/core/SkPaint.h"
#include "include/core/SkScalar.h"
#include "include/core/SkSize.h"
#include "include/core/SkString.h"
#include "include/core/SkTypeface.h"
#include "include/core/SkTypes.h"
#include "tools/ToolUtils.h"
#include "tools/fonts/FontToolUtils.h"

static void make_bm(SkBitmap* bm) {
    const SkColor colors[4] = {
        SK_ColorRED, SK_ColorGREEN,
        SK_ColorBLUE, SK_ColorWHITE
    };
    SkPMColor colorsPM[4];
    for (size_t i = 0; i < std::size(colors); ++i) {
        colorsPM[i] = SkPreMultiplyColor(colors[i]);
    }
    bm->allocN32Pixels(2, 2, true);

    *bm->getAddr32(0, 0) = colorsPM[0];
    *bm->getAddr32(1, 0) = colorsPM[1];
    *bm->getAddr32(0, 1) = colorsPM[2];
    *bm->getAddr32(1, 1) = colorsPM[3];
}

static SkScalar draw_bm(SkCanvas* canvas, sk_sp<SkImage> img, SkScalar x, SkScalar y,
                        const SkSamplingOptions& sampling, SkPaint* paint) {
    canvas->drawImage(img, x, y, sampling, paint);
    return SkIntToScalar(img->width()) * 5/4;
}

static SkScalar draw_set(SkCanvas* c, sk_sp<SkImage> img, SkScalar x, SkPaint* p) {
    x += draw_bm(c, img, x, 0, SkSamplingOptions(), p);
    x += draw_bm(c, img, x, 0, SkSamplingOptions(SkFilterMode::kLinear), p);
    p->setDither(true);
    return x + draw_bm(c, img, x, 0, SkSamplingOptions(SkFilterMode::kLinear), p);
}

static SkScalar draw_row(SkCanvas* canvas, sk_sp<SkImage> img) {
    SkAutoCanvasRestore acr(canvas, true);

    SkPaint paint;
    paint.setAntiAlias(true);

    SkScalar x = 0;
    const int scale = 32;

    SkFont      font = ToolUtils::DefaultPortableFont();
    const char* name = ToolUtils::colortype_name(img->colorType());
    canvas->drawString(name, x, SkIntToScalar(img->height())*scale*5/8, font, paint);
    canvas->translate(SkIntToScalar(48), 0);

    canvas->scale(SkIntToScalar(scale), SkIntToScalar(scale));

    x += draw_set(canvas, img, 0, &paint);
    paint.reset();
    paint.setAlphaf(0.5f);
    draw_set(canvas, img, x, &paint);
    return x * scale / 3;
}

class FilterGM : public skiagm::GM {
    void onOnceBeforeDraw() override {
        SkBitmap bm32, bm4444, bm565;
        make_bm(&bm32);
        ToolUtils::copy_to(&bm4444, kARGB_4444_SkColorType, bm32);
        ToolUtils::copy_to(&bm565, kRGB_565_SkColorType, bm32);

        fImg32 = bm32.asImage();
        fImg4444 = bm4444.asImage();
        fImg565 = bm565.asImage();
    }

public:
    sk_sp<SkImage> fImg32, fImg4444, fImg565;

    FilterGM() {
        this->setBGColor(0xFFDDDDDD);
    }

protected:
    SkString getName() const override { return SkString("bitmapfilters"); }

    SkISize getISize() override { return SkISize::Make(540, 250); }

    void onDraw(SkCanvas* canvas) override {
        SkScalar x = SkIntToScalar(10);
        SkScalar y = SkIntToScalar(10);

        canvas->translate(x, y);
        y = draw_row(canvas, fImg4444);
        canvas->translate(0, y);
        y = draw_row(canvas, fImg565);
        canvas->translate(0, y);
        draw_row(canvas, fImg32);
    }

private:
    using INHERITED = skiagm::GM;
};
DEF_GM( return new FilterGM; )

//////////////////////////////////////////////////////////////////////////////

class TestExtractAlphaGM : public skiagm::GM {
    void onOnceBeforeDraw() override {
        // Make a bitmap with per-pixels alpha (stroked circle)
        fBitmap.allocN32Pixels(100, 100);
        SkCanvas canvas(fBitmap);
        canvas.clear(0);

        SkPaint paint;
        paint.setAntiAlias(true);
        paint.setColor(SK_ColorBLUE);
        paint.setStyle(SkPaint::kStroke_Style);
        paint.setStrokeWidth(20);

        canvas.drawCircle(50, 50, 39, paint);

        fBitmap.extractAlpha(&fAlpha);
    }

public:
    SkBitmap fBitmap, fAlpha;

protected:
    SkString getName() const override { return SkString("extractalpha"); }

    SkISize getISize() override { return SkISize::Make(540, 330); }

    void onDraw(SkCanvas* canvas) override {
        SkPaint paint;
        paint.setAntiAlias(true);
        paint.setColor(SK_ColorRED);

        SkSamplingOptions sampling(SkFilterMode::kLinear);

        // should stay blue (ignore paint's color)
        canvas->drawImage(fBitmap.asImage(), 10, 10, sampling, &paint);
        // should draw red
        canvas->drawImage(fAlpha.asImage(), 120, 10, sampling, &paint);
    }

private:
    using INHERITED = skiagm::GM;
};
DEF_GM( return new TestExtractAlphaGM; )
