/*
 * 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->getLocalToDeviceAs3x3();

        // 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();)
