| /* |
| * 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 "include/core/SkCanvas.h" |
| #include "include/core/SkPoint.h" |
| #include "include/private/base/SkAssert.h" |
| #include "modules/sksg/include/SkSGTransform.h" |
| #include "modules/sksg/src/SkSGTransformPriv.h" |
| |
| namespace sksg { |
| namespace { |
| |
| template <typename T> |
| SkMatrix AsSkMatrix(const T&); |
| |
| template <> |
| SkMatrix AsSkMatrix<SkMatrix>(const SkMatrix& m) { return m; } |
| |
| template <> |
| SkMatrix AsSkMatrix<SkM44>(const SkM44& m) { return m.asM33(); } |
| |
| template <typename T> |
| SkM44 AsSkM44(const T&); |
| |
| template <> |
| SkM44 AsSkM44<SkMatrix>(const SkMatrix& m) { return SkM44(m); } |
| |
| template <> |
| SkM44 AsSkM44<SkM44>(const SkM44& m) { return m; } |
| |
| template <typename T> |
| class Concat final : public Transform { |
| public: |
| template <typename = std::enable_if<std::is_same<T, SkMatrix>::value || |
| std::is_same<T, SkM44 >::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, SkM44>::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<Transform> fA, fB; |
| T fComposed; |
| |
| using INHERITED = Transform; |
| }; |
| |
| template <typename T> |
| class Inverse final : public Transform { |
| public: |
| template <typename = std::enable_if<std::is_same<T, SkMatrix>::value || |
| std::is_same<T, SkM44 >::value >> |
| explicit Inverse(sk_sp<Transform> 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<T>(fT).invert(&fInverted)) { |
| fInverted.setIdentity(); |
| } |
| |
| return SkRect::MakeEmpty(); |
| } |
| |
| bool is44() const override { return std::is_same<T, SkM44>::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<Transform> fT; |
| T fInverted; |
| |
| using INHERITED = Transform; |
| }; |
| |
| } // namespace |
| |
| template <> |
| SkMatrix Matrix<SkMatrix>::asMatrix() const { return fMatrix; } |
| |
| template <> |
| SkM44 Matrix<SkMatrix>::asM44() const { return SkM44(fMatrix); } |
| |
| template <> |
| SkMatrix Matrix<SkM44>::asMatrix() const { return fMatrix.asM33(); } |
| |
| template <> |
| SkM44 Matrix<SkM44>::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> 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<SkM44 >(std::move(a), std::move(b))) |
| : sk_sp<Transform>(new Concat<SkMatrix>(std::move(a), std::move(b))); |
| } |
| |
| sk_sp<Transform> Transform::MakeInverse(sk_sp<Transform> t) { |
| if (!t) { |
| return nullptr; |
| } |
| |
| return TransformPriv::Is44(t) |
| ? sk_sp<Transform>(new Inverse<SkM44 >(std::move(t))) |
| : sk_sp<Transform>(new Inverse<SkMatrix>(std::move(t))); |
| } |
| |
| 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 { |
| SkAutoCanvasRestore acr(canvas, true); |
| canvas->concat(TransformPriv::As<SkM44>(fTransform)); |
| |
| this->INHERITED::onRender(canvas, ctx); |
| } |
| |
| const RenderNode* TransformEffect::onNodeAt(const SkPoint& p) const { |
| const auto p4 = TransformPriv::As<SkM44>(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<SkMatrix>(fTransform); |
| auto bounds = this->INHERITED::onRevalidate(ic, SkMatrix::Concat(ctm, m)); |
| m.mapRect(&bounds); |
| |
| return bounds; |
| } |
| |
| } // namespace sksg |