/*
 * 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 "gm.h"
#include "SkColorPriv.h"
#include "SkImageShader.h"

static const sk_sp<SkImage> make_image(int firstBlackRow, int lastBlackRow) {
    static const int kWidth = 25;
    static const int kHeight = 27;

    SkBitmap bm;
    bm.allocN32Pixels(kWidth, kHeight);
    bm.eraseColor(SK_ColorWHITE);
    for (int y = firstBlackRow; y < lastBlackRow; ++y) {
        for (int x = 0; x < kWidth; ++x) {
            *bm.getAddr32(x, y) = SkPackARGB32(0xFF, 0x0, 0x0, 0x0);
        }
    }

    bm.setAlphaType(SkAlphaType::kOpaque_SkAlphaType);
    bm.setImmutable();

    return SkImage::MakeFromBitmap(bm);
}

// GM to reproduce crbug.com/673261.
class FilterBugGM : public skiagm::GM {
public:
    FilterBugGM() { this->setBGColor(SK_ColorRED); }

protected:
    SkString onShortName() override { return SkString("filterbug"); }

    SkISize onISize() override { return SkISize::Make(150, 150); }

    void onOnceBeforeDraw() override {
        // The top texture has 5 black rows on top and then 22 white rows on the bottom
        fTop = make_image(0, 5);
        // The bottom texture has 5 black rows on the bottom and then 22 white rows on the top
        fBot = make_image(22, 27);
    }

    void onDraw(SkCanvas* canvas) override {
        static const SkFilterQuality kFilterQuality = SkFilterQuality::kHigh_SkFilterQuality;
        static const bool kDoAA = true;

        {
            SkRect r1 = SkRect::MakeXYWH(50.0f, 0.0f, 50.0f, 50.0f);
            SkPaint p1;
            p1.setAntiAlias(kDoAA);
            p1.setFilterQuality(kFilterQuality);
            SkMatrix localMat;
            localMat.setScaleTranslate(2.0f, 2.0f, 50.0f, 0.0f);
            p1.setShader(SkImageShader::Make(fTop,
                                             SkShader::kRepeat_TileMode, SkShader::kRepeat_TileMode,
                                             &localMat));

            canvas->drawRect(r1, p1);
        }

        {
            SkRect r2 = SkRect::MakeXYWH(50.0f, 50.0f, 50.0f, 36.0f);

            SkPaint p2;
            p2.setColor(SK_ColorWHITE);
            p2.setAntiAlias(kDoAA);
            p2.setFilterQuality(kFilterQuality);

            canvas->drawRect(r2, p2);
        }

        {
            SkRect r3 = SkRect::MakeXYWH(50.0f, 86.0f, 50.0f, 50.0f);

            SkPaint p3;
            p3.setAntiAlias(kDoAA);
            p3.setFilterQuality(kFilterQuality);
            SkMatrix localMat;
            localMat.setScaleTranslate(2.0f, 2.0f, 50.0f, 86.0f);
            p3.setShader(SkImageShader::Make(fBot,
                                             SkShader::kRepeat_TileMode, SkShader::kRepeat_TileMode,
                                             &localMat));

            canvas->drawRect(r3, p3);
        }
    }

private:
    sk_sp<SkImage> fTop;
    sk_sp<SkImage> fBot;

    typedef skiagm::GM INHERITED;
};

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

DEF_GM(return new FilterBugGM;)
