/*
* Copyright 2017 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "SkSGTransform.h"
#include "SkCanvas.h"
#include "SkSGTransformPriv.h"
namespace sksg {
namespace {
template <typename T>
class Concat final : public Transform {
public:
template <typename = std::enable_if<std::is_same<T, SkMatrix >::value ||
std::is_same<T, SkMatrix44>::value >>
Concat(sk_sp<Transform> a, sk_sp<Transform> b)
: fA(std::move(a)), fB(std::move(b)) {
SkASSERT(fA);
SkASSERT(fB);
this->observeInval(fA);
this->observeInval(fB);
}
~Concat() override {
this->unobserveInval(fA);
this->unobserveInval(fB);
}
protected:
SkRect onRevalidate(InvalidationController* ic, const SkMatrix& ctm) override {
fA->revalidate(ic, ctm);
fB->revalidate(ic, ctm);
fComposed.setConcat(TransformPriv::As<T>(fA),
TransformPriv::As<T>(fB));
return SkRect::MakeEmpty();
}
bool is44() const override { return std::is_same<T, SkMatrix44>::value; }
SkMatrix asMatrix() const override {
return fComposed;
}
SkMatrix44 asMatrix44() const override {
return fComposed;
}
private:
const sk_sp<Transform> fA, fB;
T fComposed;
using INHERITED = Transform;
};
} // namespace
// Transform nodes don't generate damage on their own, but via ancestor TransformEffects.
Transform::Transform() : INHERITED(kBubbleDamage_Trait) {}
sk_sp<Transform> Transform::MakeConcat(sk_sp<Transform> a, sk_sp<Transform> b) {
if (!a) {
return b;
}
if (!b) {
return a;
}
return TransformPriv::Is44(a) || TransformPriv::Is44(b)
? sk_sp<Transform>(new Concat<SkMatrix44>(std::move(a), std::move(b)))
: sk_sp<Transform>(new Concat<SkMatrix >(std::move(a), std::move(b)));
}
TransformEffect::TransformEffect(sk_sp<RenderNode> child, sk_sp<Transform> transform)
: INHERITED(std::move(child))
, fTransform(std::move(transform)) {
this->observeInval(fTransform);
}
TransformEffect::~TransformEffect() {
this->unobserveInval(fTransform);
}
void TransformEffect::onRender(SkCanvas* canvas, const RenderContext* ctx) const {
const auto m = TransformPriv::As<SkMatrix>(fTransform);
SkAutoCanvasRestore acr(canvas, !m.isIdentity());
canvas->concat(m);
this->INHERITED::onRender(canvas, ctx);
}
const RenderNode* TransformEffect::onNodeAt(const SkPoint& p) const {
const auto m = TransformPriv::As<SkMatrix>(fTransform);
SkPoint mapped_p;
m.mapPoints(&mapped_p, &p, 1);
return this->INHERITED::onNodeAt(mapped_p);
}
SkRect TransformEffect::onRevalidate(InvalidationController* ic, const SkMatrix& ctm) {
SkASSERT(this->hasInval());
// We don't care about matrix reval results.
fTransform->revalidate(ic, ctm);
const auto m = TransformPriv::As<SkMatrix>(fTransform);
auto bounds = this->INHERITED::onRevalidate(ic, SkMatrix::Concat(ctm, m));
m.mapRect(&bounds);
return bounds;
}
} // namespace sksg