1 /*
2 * Copyright 2017 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8 #include "modules/sksg/include/SkSGTransform.h"
9
10 #include "include/core/SkCanvas.h"
11 #include "modules/sksg/src/SkSGTransformPriv.h"
12
13 namespace sksg {
14
15 namespace {
16
17 template <typename T>
18 class Concat final : public Transform {
19 public:
20 template <typename = std::enable_if<std::is_same<T, SkMatrix >::value ||
21 std::is_same<T, SkMatrix44>::value >>
Concat(sk_sp<Transform> a,sk_sp<Transform> b)22 Concat(sk_sp<Transform> a, sk_sp<Transform> b)
23 : fA(std::move(a)), fB(std::move(b)) {
24 SkASSERT(fA);
25 SkASSERT(fB);
26
27 this->observeInval(fA);
28 this->observeInval(fB);
29 }
30
~Concat()31 ~Concat() override {
32 this->unobserveInval(fA);
33 this->unobserveInval(fB);
34 }
35
36 protected:
onRevalidate(InvalidationController * ic,const SkMatrix & ctm)37 SkRect onRevalidate(InvalidationController* ic, const SkMatrix& ctm) override {
38 fA->revalidate(ic, ctm);
39 fB->revalidate(ic, ctm);
40
41 fComposed.setConcat(TransformPriv::As<T>(fA),
42 TransformPriv::As<T>(fB));
43 return SkRect::MakeEmpty();
44 }
45
is44() const46 bool is44() const override { return std::is_same<T, SkMatrix44>::value; }
47
asMatrix() const48 SkMatrix asMatrix() const override {
49 SkASSERT(!this->hasInval());
50 return fComposed;
51 }
52
asMatrix44() const53 SkMatrix44 asMatrix44() const override {
54 SkASSERT(!this->hasInval());
55 return fComposed;
56 }
57
58 private:
59 const sk_sp<Transform> fA, fB;
60 T fComposed;
61
62 using INHERITED = Transform;
63 };
64
65 template <typename T>
66 class Inverse final : public Transform {
67 public:
68 template <typename = std::enable_if<std::is_same<T, SkMatrix >::value ||
69 std::is_same<T, SkMatrix44>::value >>
Inverse(sk_sp<Transform> t)70 explicit Inverse(sk_sp<Transform> t)
71 : fT(std::move(t)) {
72 SkASSERT(fT);
73
74 this->observeInval(fT);
75 }
76
~Inverse()77 ~Inverse() override {
78 this->unobserveInval(fT);
79 }
80
81 protected:
onRevalidate(InvalidationController * ic,const SkMatrix & ctm)82 SkRect onRevalidate(InvalidationController* ic, const SkMatrix& ctm) override {
83 fT->revalidate(ic, ctm);
84
85 if (!TransformPriv::As<T>(fT).invert(&fInverted)) {
86 fInverted.reset();
87 }
88
89 return SkRect::MakeEmpty();
90 }
91
is44() const92 bool is44() const override { return std::is_same<T, SkMatrix44>::value; }
93
asMatrix() const94 SkMatrix asMatrix() const override {
95 SkASSERT(!this->hasInval());
96 return fInverted;
97 }
98
asMatrix44() const99 SkMatrix44 asMatrix44() const override {
100 SkASSERT(!this->hasInval());
101 return fInverted;
102 }
103
104 private:
105 const sk_sp<Transform> fT;
106 T fInverted;
107
108 using INHERITED = Transform;
109 };
110
111 } // namespace
112
113 // Transform nodes don't generate damage on their own, but via ancestor TransformEffects.
Transform()114 Transform::Transform() : INHERITED(kBubbleDamage_Trait) {}
115
MakeConcat(sk_sp<Transform> a,sk_sp<Transform> b)116 sk_sp<Transform> Transform::MakeConcat(sk_sp<Transform> a, sk_sp<Transform> b) {
117 if (!a) {
118 return b;
119 }
120
121 if (!b) {
122 return a;
123 }
124
125 return TransformPriv::Is44(a) || TransformPriv::Is44(b)
126 ? sk_sp<Transform>(new Concat<SkMatrix44>(std::move(a), std::move(b)))
127 : sk_sp<Transform>(new Concat<SkMatrix >(std::move(a), std::move(b)));
128 }
129
MakeInverse(sk_sp<Transform> t)130 sk_sp<Transform> Transform::MakeInverse(sk_sp<Transform> t) {
131 if (!t) {
132 return nullptr;
133 }
134
135 return TransformPriv::Is44(t)
136 ? sk_sp<Transform>(new Inverse<SkMatrix44>(std::move(t)))
137 : sk_sp<Transform>(new Inverse<SkMatrix >(std::move(t)));
138 }
139
TransformEffect(sk_sp<RenderNode> child,sk_sp<Transform> transform)140 TransformEffect::TransformEffect(sk_sp<RenderNode> child, sk_sp<Transform> transform)
141 : INHERITED(std::move(child))
142 , fTransform(std::move(transform)) {
143 this->observeInval(fTransform);
144 }
145
~TransformEffect()146 TransformEffect::~TransformEffect() {
147 this->unobserveInval(fTransform);
148 }
149
onRender(SkCanvas * canvas,const RenderContext * ctx) const150 void TransformEffect::onRender(SkCanvas* canvas, const RenderContext* ctx) const {
151 const auto m = TransformPriv::As<SkMatrix>(fTransform);
152 SkAutoCanvasRestore acr(canvas, !m.isIdentity());
153 canvas->concat(m);
154 this->INHERITED::onRender(canvas, ctx);
155 }
156
onNodeAt(const SkPoint & p) const157 const RenderNode* TransformEffect::onNodeAt(const SkPoint& p) const {
158 const auto m = TransformPriv::As<SkMatrix>(fTransform);
159
160 SkPoint mapped_p;
161 m.mapPoints(&mapped_p, &p, 1);
162
163 return this->INHERITED::onNodeAt(mapped_p);
164 }
165
onRevalidate(InvalidationController * ic,const SkMatrix & ctm)166 SkRect TransformEffect::onRevalidate(InvalidationController* ic, const SkMatrix& ctm) {
167 SkASSERT(this->hasInval());
168
169 // We don't care about matrix reval results.
170 fTransform->revalidate(ic, ctm);
171
172 const auto m = TransformPriv::As<SkMatrix>(fTransform);
173 auto bounds = this->INHERITED::onRevalidate(ic, SkMatrix::Concat(ctm, m));
174 m.mapRect(&bounds);
175
176 return bounds;
177 }
178
179 } // namespace sksg
180