/*
 * Copyright 2021 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/SkCanvas.h"
#include "include/core/SkColor.h"
#include "include/core/SkFont.h"
#include "include/core/SkFontMetrics.h"
#include "include/core/SkPaint.h"
#include "include/core/SkRefCnt.h"
#include "include/core/SkScalar.h"
#include "include/core/SkSize.h"
#include "include/core/SkString.h"
#include "include/core/SkTypeface.h"
#include "tools/Resources.h"
#include "tools/ToolUtils.h"

#include <string.h>
#include <initializer_list>

namespace skiagm {

class ColrV1GM : public GM {
public:

  // TODO(drott): Consolidate test fonts.
  enum ColrV1TestType {
    kSkiaSampleFont,
    kColorFontsRepoGradients,
    kColorFontsRepoScaling,
    kColorFontsRepoExtendMode,
    kColorFontsRepoRotate,
    kColorFontsRepoSkew,
    kColorFontsRepoTransform,
    kColorFontsRepoClipBox,
    kColorFontsRepoComposite,
    kColorFontsRepoForeground
  };

  ColrV1GM(ColrV1TestType testType, SkScalar skewX, SkScalar rotateDeg)
          : fSkewX(skewX), fRotateDeg(rotateDeg), fTestType(testType) {}

protected:
    static SkString testTypeToString(ColrV1TestType testType) {
        switch (testType) {
            case kSkiaSampleFont:
                return SkString("skia");
            case kColorFontsRepoGradients:
                return SkString("gradients");
            case kColorFontsRepoScaling:
                return SkString("scaling");
            case kColorFontsRepoExtendMode:
                return SkString("extend_mode");
            case kColorFontsRepoRotate:
                return SkString("rotate");
            case kColorFontsRepoSkew:
                return SkString("skew");
            case kColorFontsRepoTransform:
                return SkString("transform");
            case kColorFontsRepoClipBox:
                return SkString("clipbox");
            case kColorFontsRepoComposite:
                return SkString("composite");
            case kColorFontsRepoForeground:
                return SkString("foreground");
        }
        SkASSERT(false); /* not reached */
        return SkString();
    }

    struct EmojiFont {
        sk_sp<SkTypeface> fTypeface;
        std::vector<uint16_t> fGlyphs;
        size_t bytesize() { return fGlyphs.size() * sizeof(uint16_t); }
    } fEmojiFont;

    void onOnceBeforeDraw() override {
        if (fTestType == kSkiaSampleFont) {
            fEmojiFont.fTypeface = MakeResourceAsTypeface("fonts/colrv1_samples.ttf");
            fEmojiFont.fGlyphs = {19, 33, 34, 35, 20, 21, 22, 23, 24, 25};
            return;
        }

        fEmojiFont.fTypeface = MakeResourceAsTypeface("fonts/more_samples-glyf_colr_1.ttf");

        switch (fTestType) {
            case kSkiaSampleFont:
                SkASSERT(false);
                break;
            case kColorFontsRepoGradients:
                fEmojiFont.fGlyphs = {2, 5, 6, 7, 8};
                break;
            case kColorFontsRepoScaling:
                fEmojiFont.fGlyphs = {9, 10, 11, 12, 13, 14};
                break;
            case kColorFontsRepoExtendMode:
                fEmojiFont.fGlyphs = {15, 16, 17, 18, 19, 20};
                break;
            case kColorFontsRepoRotate:
                fEmojiFont.fGlyphs = {21, 22, 23, 24};
                break;
            case kColorFontsRepoSkew:
                fEmojiFont.fGlyphs = {25, 26, 27, 28, 29, 30};
                break;
            case kColorFontsRepoTransform:
                fEmojiFont.fGlyphs = {31, 32, 33, 34};
                break;
            case kColorFontsRepoClipBox:
                fEmojiFont.fGlyphs = {35, 36, 37, 38, 39};
                break;
            case kColorFontsRepoComposite:
                fEmojiFont.fGlyphs = {40, 41, 42, 43, 44, 45, 46};
                break;
            case kColorFontsRepoForeground:
                fEmojiFont.fGlyphs = {47, 48, 49, 50, 51, 52, 53, 54};
                break;
        }
    }

    SkString onShortName() override {
        SkString gm_name = SkStringPrintf("colrv1_%s_samples",
                                          testTypeToString(fTestType).c_str());
        if (fSkewX) {
            gm_name.append("_skew");
        }

        if (fRotateDeg) {
            gm_name.append("_rotate");
        }
        return gm_name;
    }

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

    DrawResult onDraw(SkCanvas* canvas, SkString* errorMsg) override {
        canvas->drawColor(SK_ColorWHITE);
        SkPaint paint;

        canvas->translate(200, 20);

        if (!fEmojiFont.fTypeface) {
          *errorMsg = "Did not recognize COLR v1 font format.";
          return DrawResult::kSkip;
        }

        canvas->rotate(fRotateDeg);
        canvas->skew(fSkewX, 0);

        SkFont font(fEmojiFont.fTypeface);

        SkFontMetrics metrics;
        SkScalar y = 0;
        std::vector<SkColor> paint_colors = {
                SK_ColorBLACK, SK_ColorGREEN, SK_ColorRED, SK_ColorBLUE};
        auto paint_color_iterator = paint_colors.begin();
        for (SkScalar textSize : { 12, 18, 30, 120 }) {
            font.setSize(textSize);
            font.getMetrics(&metrics);
            y += -metrics.fAscent;
            paint.setColor(*paint_color_iterator);
            canvas->drawSimpleText(fEmojiFont.fGlyphs.data(),
                                   fEmojiFont.bytesize(),
                                   SkTextEncoding::kGlyphID,
                                   10, y, font, paint);
            y += metrics.fDescent + metrics.fLeading;
            paint_color_iterator++;
        }
        return DrawResult::kOk;
    }

private:
    using INHERITED = GM;
    SkScalar fSkewX;
    SkScalar fRotateDeg;
    ColrV1TestType fTestType;
};

DEF_GM(return new ColrV1GM(ColrV1GM::kSkiaSampleFont, 0.f, 0.f);)
DEF_GM(return new ColrV1GM(ColrV1GM::kSkiaSampleFont, -0.5f, 0.f);)
DEF_GM(return new ColrV1GM(ColrV1GM::kSkiaSampleFont, 0.f, 20.f);)
DEF_GM(return new ColrV1GM(ColrV1GM::kSkiaSampleFont, -0.5f, 20.f);)
DEF_GM(return new ColrV1GM(ColrV1GM::kColorFontsRepoGradients, 0.f, 0.f);)
DEF_GM(return new ColrV1GM(ColrV1GM::kColorFontsRepoScaling, 0.f, 0.f);)
DEF_GM(return new ColrV1GM(ColrV1GM::kColorFontsRepoExtendMode, 0.f, 0.f);)
DEF_GM(return new ColrV1GM(ColrV1GM::kColorFontsRepoRotate, 0.f, 0.f);)
DEF_GM(return new ColrV1GM(ColrV1GM::kColorFontsRepoSkew, 0.f, 0.f);)
DEF_GM(return new ColrV1GM(ColrV1GM::kColorFontsRepoTransform, 0.f, 0.f);)
DEF_GM(return new ColrV1GM(ColrV1GM::kColorFontsRepoClipBox, 0.f, 0.f);)
DEF_GM(return new ColrV1GM(ColrV1GM::kColorFontsRepoClipBox, -0.5f, 20.f);)
DEF_GM(return new ColrV1GM(ColrV1GM::kColorFontsRepoComposite, 0.f, 0.f);)
DEF_GM(return new ColrV1GM(ColrV1GM::kColorFontsRepoForeground, 0.f, 0.f);)

}  // namespace skiagm