/* * 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 "modules/sksg/include/SkSGTransform.h" #include "include/core/SkCanvas.h" #include "modules/sksg/src/SkSGTransformPriv.h" namespace sksg { namespace { template SkMatrix AsSkMatrix(const T&); template <> SkMatrix AsSkMatrix(const SkMatrix& m) { return m; } template <> SkMatrix AsSkMatrix(const SkM44& m) { return m.asM33(); } template SkM44 AsSkM44(const T&); template <> SkM44 AsSkM44(const SkMatrix& m) { return SkM44(m); } template <> SkM44 AsSkM44(const SkM44& m) { return m; } template class Concat final : public Transform { public: template ::value || std::is_same::value >> Concat(sk_sp a, sk_sp 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(fA), TransformPriv::As(fB)); return SkRect::MakeEmpty(); } bool is44() const override { return std::is_same::value; } SkMatrix asMatrix() const override { SkASSERT(!this->hasInval()); return AsSkMatrix(fComposed); } SkM44 asM44() const override { SkASSERT(!this->hasInval()); return AsSkM44(fComposed); } private: const sk_sp fA, fB; T fComposed; using INHERITED = Transform; }; template class Inverse final : public Transform { public: template ::value || std::is_same::value >> explicit Inverse(sk_sp t) : fT(std::move(t)) { SkASSERT(fT); this->observeInval(fT); } ~Inverse() override { this->unobserveInval(fT); } protected: SkRect onRevalidate(InvalidationController* ic, const SkMatrix& ctm) override { fT->revalidate(ic, ctm); if (!TransformPriv::As(fT).invert(&fInverted)) { fInverted.setIdentity(); } return SkRect::MakeEmpty(); } bool is44() const override { return std::is_same::value; } SkMatrix asMatrix() const override { SkASSERT(!this->hasInval()); return AsSkMatrix(fInverted); } SkM44 asM44() const override { SkASSERT(!this->hasInval()); return AsSkM44(fInverted); } private: const sk_sp fT; T fInverted; using INHERITED = Transform; }; } // namespace template <> SkMatrix Matrix::asMatrix() const { return fMatrix; } template <> SkM44 Matrix::asM44() const { return SkM44(fMatrix); } template <> SkMatrix Matrix::asMatrix() const { return fMatrix.asM33(); } template <> SkM44 Matrix::asM44() const { return fMatrix; } // Transform nodes don't generate damage on their own, but via ancestor TransformEffects. Transform::Transform() : INHERITED(kBubbleDamage_Trait) {} sk_sp Transform::MakeConcat(sk_sp a, sk_sp b) { if (!a) { return b; } if (!b) { return a; } return TransformPriv::Is44(a) || TransformPriv::Is44(b) ? sk_sp(new Concat(std::move(a), std::move(b))) : sk_sp(new Concat(std::move(a), std::move(b))); } sk_sp Transform::MakeInverse(sk_sp t) { if (!t) { return nullptr; } return TransformPriv::Is44(t) ? sk_sp(new Inverse(std::move(t))) : sk_sp(new Inverse(std::move(t))); } TransformEffect::TransformEffect(sk_sp child, sk_sp 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 { SkAutoCanvasRestore acr(canvas, true); canvas->concat(TransformPriv::As(fTransform)); this->INHERITED::onRender(canvas, ctx); } const RenderNode* TransformEffect::onNodeAt(const SkPoint& p) const { const auto p4 = TransformPriv::As(fTransform).map(p.fX, p.fY, 0, 0); return this->INHERITED::onNodeAt({p4.x, p4.y}); } SkRect TransformEffect::onRevalidate(InvalidationController* ic, const SkMatrix& ctm) { SkASSERT(this->hasInval()); // We don't care about matrix reval results. fTransform->revalidate(ic, ctm); // TODO: need to update all the reval plumbing for m44. const auto m = TransformPriv::As(fTransform); auto bounds = this->INHERITED::onRevalidate(ic, SkMatrix::Concat(ctm, m)); m.mapRect(&bounds); return bounds; } } // namespace sksg