blob: f10d83f4ec9b3b2b13d7ad9b1eb89a01e1216406 [file] [log] [blame]
/*
* 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 "SkSGColorFilter.h"
#include "SkColorFilter.h"
#include "SkSGColor.h"
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<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 SkColorFilter::MakeModeFilter(fColor->getColor(), fMode);
}
sk_sp<TintColorFilter> TintColorFilter::Make(sk_sp<RenderNode> child,
sk_sp<Color> c0, sk_sp<Color> c1) {
return (child && c0 && c1) ? sk_sp<TintColorFilter>(new TintColorFilter(std::move(child),
std::move(c0),
std::move(c1)))
: nullptr;
}
TintColorFilter::TintColorFilter(sk_sp<RenderNode> child, sk_sp<Color> c0, sk_sp<Color> c1)
: INHERITED(std::move(child))
, fColor0(std::move(c0))
, fColor1(std::move(c1)) {
this->observeInval(fColor0);
this->observeInval(fColor1);
}
TintColorFilter::~TintColorFilter() {
this->unobserveInval(fColor0);
this->unobserveInval(fColor1);
}
sk_sp<SkColorFilter> TintColorFilter::onRevalidateFilter() {
fColor0->revalidate(nullptr, SkMatrix::I());
fColor1->revalidate(nullptr, SkMatrix::I());
if (fWeight <= 0) {
return nullptr;
}
const auto c0 = SkColor4f::FromColor(fColor0->getColor()),
c1 = SkColor4f::FromColor(fColor1->getColor());
// luminance coefficients
static constexpr float kR = 0.2126f,
kG = 0.7152f,
kB = 0.0722f;
const auto dR = c1.fR - c0.fR,
dG = c1.fG - c0.fG,
dB = c1.fB - c0.fB;
// First, we need a 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 SkScalar tint_matrix[] = {
dR*kR, dR*kG, dR*kB, 0, c0.fR * 255,
dG*kR, dG*kG, dG*kB, 0, c0.fG * 255,
dB*kR, dB*kG, dB*kB, 0, c0.fB * 255,
0, 0, 0, 1, 0,
};
return SkColorFilter::MakeMixer(nullptr,
SkColorFilter::MakeMatrixFilterRowMajor255(tint_matrix),
fWeight);
}
} // namespace sksg