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

#include "samplecode/Sample.h"

#include "include/core/SkCanvas.h"
#include "include/core/SkColor.h"
#include "include/core/SkFont.h"
#include "include/core/SkPaint.h"
#include "include/core/SkPath.h"
#include "include/core/SkPoint.h"
#include "include/core/SkRect.h"
#include "include/effects/SkDashPathEffect.h"
#include "include/effects/SkGradientShader.h"
#include "include/effects/SkImageFilters.h"

#include "src/core/SkImageFilterTypes.h"
#include "src/core/SkImageFilter_Base.h"
#include "src/core/SkMatrixPriv.h"

#include "tools/ToolUtils.h"

static constexpr float kLineHeight = 16.f;
static constexpr float kLineInset = 8.f;

static float print_size(SkCanvas* canvas, const char* prefix, const SkIRect& rect,
                        float x, float y, const SkFont& font, const SkPaint& paint) {
    canvas->drawString(prefix, x, y, font, paint);
    y += kLineHeight;
    SkString sz;
    sz.appendf("%d x %d", rect.width(), rect.height());
    canvas->drawString(sz, x, y, font, paint);
    return y + kLineHeight;
}

static float print_info(SkCanvas* canvas,
                        const SkIRect& layerContentBounds,
                        const SkIRect& outputBounds,
                        const SkIRect& hintedOutputBounds,
                        const SkIRect& unhintedLayerBounds) {
    SkFont font(nullptr, 12);
    SkPaint text;
    text.setAntiAlias(true);

    float y = kLineHeight;

    text.setColor(SK_ColorRED);
    y = print_size(canvas, "Content (in layer)", layerContentBounds, kLineInset, y, font, text);
    text.setColor(SK_ColorDKGRAY);
    y = print_size(canvas, "Target (in device)", outputBounds, kLineInset, y, font, text);
    text.setColor(SK_ColorBLUE);
    y = print_size(canvas, "Output (w/ hint)", hintedOutputBounds, kLineInset, y, font, text);
    text.setColor(SK_ColorGREEN);
    y = print_size(canvas, "Input (w/ no hint)", unhintedLayerBounds, kLineInset, y, font, text);

    return y;
}

static void print_label(SkCanvas* canvas, float x, float y, float value) {
    SkFont font(nullptr, 12);
    SkPaint text;
    text.setAntiAlias(true);

    SkString label;
    label.printf("%.3f", value);

    canvas->drawString(label, x, y + kLineHeight / 2.f, font, text);
}

static SkPaint line_paint(SkColor color, bool dashed = false) {
    SkPaint paint;
    paint.setColor(color);
    paint.setStrokeWidth(0.f);
    paint.setStyle(SkPaint::kStroke_Style);
    paint.setAntiAlias(true);
    if (dashed) {
        SkScalar dash[2] = {10.f, 10.f};
        paint.setPathEffect(SkDashPathEffect::Make(dash, 2, 0.f));
    }
    return paint;
}

static SkPath create_axis_path(const SkRect& rect, float axisSpace) {
    SkPath localSpace;
    for (float y = rect.fTop + axisSpace; y <= rect.fBottom; y += axisSpace) {
        localSpace.moveTo(rect.fLeft, y);
        localSpace.lineTo(rect.fRight, y);
    }
    for (float x = rect.fLeft + axisSpace; x <= rect.fRight; x += axisSpace) {
        localSpace.moveTo(x, rect.fTop);
        localSpace.lineTo(x, rect.fBottom);
    }
    return localSpace;
}

static const SkColor4f kScaleGradientColors[] =
                { { 0.05f, 0.0f, 6.f,  1.f },   // Severe downscaling, s < 1/8, log(s) < -3
                  { 0.6f,  0.6f, 0.8f, 0.6f },  // Okay downscaling,   s < 1/2, log(s) < -1
                  { 1.f,   1.f,  1.f,  0.2f },  // No scaling,         s = 1,   log(s) = 0
                  { 0.95f, 0.6f, 0.5f, 0.6f },  // Okay upscaling,     s > 2,   log(s) > 1
                  { 0.8f,  0.1f, 0.f,  1.f } }; // Severe upscaling,   s > 8,   log(s) > 3
static const SkScalar kLogScaleFactors[] = { -3.f, -1.f, 0.f, 1.f, 3.f };
static const SkScalar kGradientStops[] = { 0.f, 0.33333f, 0.5f, 0.66667f, 1.f };
static const int kStopCount = (int) SK_ARRAY_COUNT(kScaleGradientColors);

static void draw_scale_key(SkCanvas* canvas, float y) {
    SkRect key = SkRect::MakeXYWH(15.f, y + 30.f, 15.f, 100.f);
    SkPoint pts[] = {{key.centerX(), key.fTop}, {key.centerX(), key.fBottom}};
    sk_sp<SkShader> gradient = SkGradientShader::MakeLinear(
            pts, kScaleGradientColors, nullptr, kGradientStops, kStopCount, SkTileMode::kClamp,
            SkGradientShader::kInterpolateColorsInPremul_Flag, nullptr);
    SkPaint keyPaint;
    keyPaint.setShader(gradient);
    canvas->drawRect(key, keyPaint);
    for (int i = 0; i < kStopCount; ++i) {
        print_label(canvas, key.fRight + 5.f, key.fTop + kGradientStops[i] * key.height(),
                    SkScalarPow(2.f, kLogScaleFactors[i]));
    }
}

static void draw_scale_factors(SkCanvas* canvas, const skif::Mapping& mapping, const SkRect& rect) {
    SkPoint testPoints[5];
    testPoints[0] = {rect.centerX(), rect.centerY()};
    rect.toQuad(testPoints + 1);
    for (int i = 0; i < 5; ++i) {
        float scale = SkMatrixPriv::DifferentialAreaScale(
                mapping.deviceMatrix(),
                SkPoint(mapping.paramToLayer(skif::ParameterSpace<SkPoint>(testPoints[i]))));
        SkColor4f color = {0.f, 0.f, 0.f, 1.f};

        if (SkScalarIsFinite(scale)) {
            float logScale = SkScalarLog2(scale);
            for (int j = 0; j <= kStopCount; ++j) {
                if (j == kStopCount) {
                    color = kScaleGradientColors[j - 1];
                    break;
                } else if (kLogScaleFactors[j] >= logScale) {
                    if (j == 0) {
                        color = kScaleGradientColors[0];
                    } else {
                        SkScalar t = (logScale - kLogScaleFactors[j - 1]) /
                                    (kLogScaleFactors[j] - kLogScaleFactors[j - 1]);

                        SkColor4f a = kScaleGradientColors[j - 1] * (1.f - t);
                        SkColor4f b = kScaleGradientColors[j] * t;
                        color = {a.fR + b.fR, a.fG + b.fG, a.fB + b.fB, a.fA + b.fA};
                    }
                    break;
                }
            }
        }

        SkPaint p;
        p.setAntiAlias(true);
        p.setColor4f(color, nullptr);
        canvas->drawRect(SkRect::MakeLTRB(testPoints[i].fX - 4.f, testPoints[i].fY - 4.f,
                                          testPoints[i].fX + 4.f, testPoints[i].fY + 4.f), p);
    }
}

class FilterBoundsSample : public Sample {
public:
    FilterBoundsSample() {}

    void onOnceBeforeDraw() override {
        fBlur = SkImageFilters::Blur(8.f, 8.f, nullptr);
        fImage = SkImage::MakeFromBitmap(ToolUtils::create_checkerboard_bitmap(
                300, 300, SK_ColorMAGENTA, SK_ColorLTGRAY, 50));
    }

    void onDrawContent(SkCanvas* canvas) override {
        // The local content, e.g. what would be submitted to drawRect or the bounds to saveLayer
        const SkRect localContentRect = SkRect::MakeLTRB(100.f, 20.f, 180.f, 140.f);
        SkMatrix ctm = canvas->getTotalMatrix();

        // Base rendering of a filter
        SkPaint blurPaint;
        blurPaint.setImageFilter(fBlur);
        canvas->saveLayer(&localContentRect, &blurPaint);
        SkPaint imagePaint;
        imagePaint.setFilterQuality(kLow_SkFilterQuality);
        canvas->drawImageRect(fImage, localContentRect, &imagePaint);
        canvas->restore();

        // Now visualize the underlying bounds calculations used to determine the layer for the blur
        SkIRect target = ctm.mapRect(localContentRect).roundOut();
        if (!target.intersect(SkIRect::MakeWH(canvas->imageInfo().width(),
                                              canvas->imageInfo().height()))) {
            return;
        }
        skif::DeviceSpace<SkIRect> targetOutput(target);
        skif::ParameterSpace<SkRect> contentBounds(localContentRect);
        skif::Mapping mapping = skif::Mapping::DecomposeCTM(
                ctm, fBlur.get(), skif::ParameterSpace<SkPoint>({localContentRect.centerX(),
                                                                 localContentRect.centerY()}));

        // Add axis lines, to show perspective distortion
        canvas->save();
        canvas->setMatrix(mapping.deviceMatrix());
        canvas->drawPath(create_axis_path(SkRect(mapping.paramToLayer(contentBounds)), 20.f),
                         line_paint(SK_ColorGRAY));
        canvas->restore();

        // Visualize scale factors at the four corners and center of the local rect
        draw_scale_factors(canvas, mapping, localContentRect);

        // The device content rect, e.g. the clip bounds if 'localContentRect' were used as a clip
        // before the draw or saveLayer, representing what the filter must cover if it affects
        // transparent black or doesn't have a local content hint.
        canvas->setMatrix(SkMatrix::I());
        canvas->drawRect(ctm.mapRect(localContentRect), line_paint(SK_ColorDKGRAY));

        // Layer bounds for the filter, in the layer space compatible with the filter's matrix
        // type requirements.
        skif::LayerSpace<SkIRect> targetOutputInLayer = mapping.deviceToLayer(targetOutput);
        skif::LayerSpace<SkIRect> hintedLayerBounds = as_IFB(fBlur)->getInputBounds(
                mapping, targetOutput, &contentBounds);
        skif::LayerSpace<SkIRect> unhintedLayerBounds = as_IFB(fBlur)->getInputBounds(
                mapping, targetOutput, nullptr);

        canvas->setMatrix(mapping.deviceMatrix());
        canvas->drawRect(SkRect::Make(SkIRect(targetOutputInLayer)),
                         line_paint(SK_ColorDKGRAY, true));
        canvas->drawRect(SkRect::Make(SkIRect(hintedLayerBounds)), line_paint(SK_ColorRED));
        canvas->drawRect(SkRect::Make(SkIRect(unhintedLayerBounds)), line_paint(SK_ColorGREEN));

        // For visualization purposes, we want to show the layer-space output, this is what we get
        // when contentBounds is provided as a hint in local/parameter space.
        skif::Mapping layerOnly(SkMatrix::I(), mapping.layerMatrix());
        skif::DeviceSpace<SkIRect> hintedOutputBounds = as_IFB(fBlur)->getOutputBounds(
                layerOnly, contentBounds);
        canvas->drawRect(SkRect::Make(SkIRect(hintedOutputBounds)), line_paint(SK_ColorBLUE));

        canvas->resetMatrix();
        float y = print_info(canvas, SkIRect(mapping.paramToLayer(contentBounds).roundOut()),
                             SkIRect(targetOutput),
                             SkIRect(hintedOutputBounds),
                             SkIRect(unhintedLayerBounds));

        // Draw color key for layer visualization
        draw_scale_key(canvas, y);
    }

    SkString name() override { return SkString("FilterBounds"); }

private:
    sk_sp<SkImageFilter> fBlur;
    sk_sp<SkImage>       fImage;

    using INHERITED = Sample;
};

DEF_SAMPLE(return new FilterBoundsSample();)
