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

#include "modules/sksg/include/SkSGColorFilter.h"

#include "include/core/SkColorFilter.h"
#include "include/effects/SkTableColorFilter.h"
#include "include/private/SkColorData.h"
#include "modules/sksg/include/SkSGPaint.h"

#include <cmath>

namespace sksg {

ColorFilter::ColorFilter(sk_sp<RenderNode> child)
    : INHERITED(std::move(child)) {}

void ColorFilter::onRender(SkCanvas* canvas, const RenderContext* ctx) const {
    const auto local_ctx = ScopedRenderContext(canvas, ctx).modulateColorFilter(fColorFilter);

    this->INHERITED::onRender(canvas, local_ctx);
}

const RenderNode* ColorFilter::onNodeAt(const SkPoint& p) const {
    // TODO: we likely need to do something more sophisticated than delegate to descendants here.
    return this->INHERITED::onNodeAt(p);
}

SkRect ColorFilter::onRevalidate(InvalidationController* ic, const SkMatrix& ctm) {
    SkASSERT(this->hasInval());

    fColorFilter = this->onRevalidateFilter();

    return this->INHERITED::onRevalidate(ic, ctm);
}

sk_sp<ExternalColorFilter> ExternalColorFilter::Make(sk_sp<RenderNode> child) {
    return child ? sk_sp<ExternalColorFilter>(new ExternalColorFilter(std::move(child)))
                 : nullptr;
}

ExternalColorFilter::ExternalColorFilter(sk_sp<RenderNode> child) : INHERITED(std::move(child)) {}

ExternalColorFilter::~ExternalColorFilter() = default;

void ExternalColorFilter::onRender(SkCanvas* canvas, const RenderContext* ctx) const {
    const auto local_ctx = ScopedRenderContext(canvas, ctx).modulateColorFilter(fColorFilter);

    this->INHERITED::onRender(canvas, local_ctx);
}

sk_sp<ModeColorFilter> ModeColorFilter::Make(sk_sp<RenderNode> child, sk_sp<Color> color,
                                             SkBlendMode mode) {
    return (child && color) ? sk_sp<ModeColorFilter>(new ModeColorFilter(std::move(child),
                                                                         std::move(color), mode))
                            : nullptr;
}

ModeColorFilter::ModeColorFilter(sk_sp<RenderNode> child, sk_sp<Color> color, SkBlendMode mode)
    : INHERITED(std::move(child))
    , fColor(std::move(color))
    , fMode(mode) {
    this->observeInval(fColor);
}

ModeColorFilter::~ModeColorFilter() {
    this->unobserveInval(fColor);
}

sk_sp<SkColorFilter> ModeColorFilter::onRevalidateFilter() {
    fColor->revalidate(nullptr, SkMatrix::I());
    return SkColorFilters::Blend(fColor->getColor(), fMode);
}

sk_sp<GradientColorFilter> GradientColorFilter::Make(sk_sp<RenderNode> child,
                                                     sk_sp<Color> c0, sk_sp<Color> c1) {
    return Make(std::move(child), { std::move(c0), std::move(c1) });
}

sk_sp<GradientColorFilter> GradientColorFilter::Make(sk_sp<RenderNode> child,
                                                     std::vector<sk_sp<Color>> colors) {
    return (child && colors.size() > 1)
        ? sk_sp<GradientColorFilter>(new GradientColorFilter(std::move(child), std::move(colors)))
        : nullptr;
}

GradientColorFilter::GradientColorFilter(sk_sp<RenderNode> child, std::vector<sk_sp<Color>> colors)
    : INHERITED(std::move(child))
    , fColors(std::move(colors)) {
    for (const auto& color : fColors) {
        this->observeInval(color);
    }
}

GradientColorFilter::~GradientColorFilter() {
    for (const auto& color : fColors) {
        this->unobserveInval(color);
    }
}

namespace  {

sk_sp<SkColorFilter> Make2ColorGradient(const sk_sp<Color>& color0, const sk_sp<Color>& color1) {
    const auto c0 = SkColor4f::FromColor(color0->getColor()),
               c1 = SkColor4f::FromColor(color1->getColor());

    const auto dR = c1.fR - c0.fR,
               dG = c1.fG - c0.fG,
               dB = c1.fB - c0.fB;

    // A 2-color gradient can be expressed as a color matrix (and combined with the luminance
    // calculation).  First, the luminance:
    //
    //   L = [r,g,b] . [kR,kG,kB]
    //
    // We can compute it using a color matrix (result stored in R):
    //
    //   | kR, kG, kB,  0,  0 |    r' = L
    //   |  0,  0,  0,  0,  0 |    g' = 0
    //   |  0,  0,  0,  0,  0 |    b' = 0
    //   |  0,  0,  0,  1,  0 |    a' = a
    //
    // Then we want to interpolate component-wise, based on L:
    //
    //   r' = c0.r + (c1.r - c0.r) * L = c0.r + dR*L
    //   g' = c0.g + (c1.g - c0.g) * L = c0.g + dG*L
    //   b' = c0.b + (c1.b - c0.b) * L = c0.b + dB*L
    //   a' = a
    //
    // This can be expressed as another color matrix (when L is stored in R):
    //
    //  | dR,  0,  0,  0, c0.r |
    //  | dG,  0,  0,  0, c0.g |
    //  | dB,  0,  0,  0, c0.b |
    //  |  0,  0,  0,  1,    0 |
    //
    // Composing these two, we get the total tint matrix:

    const float tint_matrix[] = {
        dR*SK_LUM_COEFF_R, dR*SK_LUM_COEFF_G, dR*SK_LUM_COEFF_B, 0, c0.fR,
        dG*SK_LUM_COEFF_R, dG*SK_LUM_COEFF_G, dG*SK_LUM_COEFF_B, 0, c0.fG,
        dB*SK_LUM_COEFF_R, dB*SK_LUM_COEFF_G, dB*SK_LUM_COEFF_B, 0, c0.fB,
        0,                 0,                 0,                 1, 0,
    };

    return SkColorFilters::Matrix(tint_matrix);
}

sk_sp<SkColorFilter> MakeNColorGradient(const std::vector<sk_sp<Color>>& colors) {
    // For N colors, we build a gradient color table.
    uint8_t rTable[256], gTable[256], bTable[256];

    SkASSERT(colors.size() > 2);
    const auto span_count = colors.size() - 1;

    size_t span_start = 0;
    for (size_t i = 0; i < span_count; ++i) {
        const auto span_stop = static_cast<size_t>(std::round((i + 1) * 255.0f / span_count)),
                   span_size = span_stop - span_start;
        if (span_start > span_stop) {
            // Degenerate case.
            continue;
        }
        SkASSERT(span_stop <= 255);

        // Fill the gradient in [span_start,span_stop] -> [c0,c1]
        const SkColor c0 = colors[i    ]->getColor(),
                      c1 = colors[i + 1]->getColor();
        float r = SkColorGetR(c0),
              g = SkColorGetG(c0),
              b = SkColorGetB(c0);
        const float dR = (SkColorGetR(c1) - r) / span_size,
                    dG = (SkColorGetG(c1) - g) / span_size,
                    dB = (SkColorGetB(c1) - b) / span_size;

        for (size_t j = span_start; j <= span_stop; ++j) {
            rTable[j] = static_cast<uint8_t>(std::round(r));
            gTable[j] = static_cast<uint8_t>(std::round(g));
            bTable[j] = static_cast<uint8_t>(std::round(b));
            r += dR;
            g += dG;
            b += dB;
        }

        // Ensure we always advance.
        span_start = span_stop + 1;
    }
    SkASSERT(span_start == 256);

    const float luminance_matrix[] = {
        SK_LUM_COEFF_R, SK_LUM_COEFF_G, SK_LUM_COEFF_B,  0,  0,  // r' = L
        SK_LUM_COEFF_R, SK_LUM_COEFF_G, SK_LUM_COEFF_B,  0,  0,  // g' = L
        SK_LUM_COEFF_R, SK_LUM_COEFF_G, SK_LUM_COEFF_B,  0,  0,  // b' = L
                     0,              0,              0,  1,  0,  // a' = a
    };

    return SkTableColorFilter::MakeARGB(nullptr, rTable, gTable, bTable)
            ->makeComposed(SkColorFilters::Matrix(luminance_matrix));
}

} // namespace

sk_sp<SkColorFilter> GradientColorFilter::onRevalidateFilter() {
    for (const auto& color : fColors) {
        color->revalidate(nullptr, SkMatrix::I());
    }

    if (fWeight <= 0) {
        return nullptr;
    }

    SkASSERT(fColors.size() > 1);
    auto gradientCF = (fColors.size() > 2) ? MakeNColorGradient(fColors)
                                           : Make2ColorGradient(fColors[0], fColors[1]);

    return SkColorFilters::Lerp(fWeight, nullptr, std::move(gradientCF));
}

} // namespace sksg
