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 | SkMatrix AsSkMatrix(const T&); |
19 | |
20 | template <> |
21 | SkMatrix AsSkMatrix<SkMatrix>(const SkMatrix& m) { return m; } |
22 | |
23 | template <> |
24 | SkMatrix AsSkMatrix<SkM44>(const SkM44& m) { return m.asM33(); } |
25 | |
26 | template <typename T> |
27 | SkM44 AsSkM44(const T&); |
28 | |
29 | template <> |
30 | SkM44 AsSkM44<SkMatrix>(const SkMatrix& m) { return SkM44(m); } |
31 | |
32 | template <> |
33 | SkM44 AsSkM44<SkM44>(const SkM44& m) { return m; } |
34 | |
35 | template <typename T> |
36 | class Concat final : public Transform { |
37 | public: |
38 | template <typename = std::enable_if<std::is_same<T, SkMatrix>::value || |
39 | std::is_same<T, SkM44 >::value >> |
40 | Concat(sk_sp<Transform> a, sk_sp<Transform> b) |
41 | : fA(std::move(a)), fB(std::move(b)) { |
42 | SkASSERT(fA); |
43 | SkASSERT(fB); |
44 | |
45 | this->observeInval(fA); |
46 | this->observeInval(fB); |
47 | } |
48 | |
49 | ~Concat() override { |
50 | this->unobserveInval(fA); |
51 | this->unobserveInval(fB); |
52 | } |
53 | |
54 | protected: |
55 | SkRect onRevalidate(InvalidationController* ic, const SkMatrix& ctm) override { |
56 | fA->revalidate(ic, ctm); |
57 | fB->revalidate(ic, ctm); |
58 | |
59 | fComposed.setConcat(TransformPriv::As<T>(fA), |
60 | TransformPriv::As<T>(fB)); |
61 | return SkRect::MakeEmpty(); |
62 | } |
63 | |
64 | bool is44() const override { return std::is_same<T, SkM44>::value; } |
65 | |
66 | SkMatrix asMatrix() const override { |
67 | SkASSERT(!this->hasInval()); |
68 | return AsSkMatrix(fComposed); |
69 | } |
70 | |
71 | SkM44 asM44() const override { |
72 | SkASSERT(!this->hasInval()); |
73 | return AsSkM44(fComposed); |
74 | } |
75 | |
76 | private: |
77 | const sk_sp<Transform> fA, fB; |
78 | T fComposed; |
79 | |
80 | using INHERITED = Transform; |
81 | }; |
82 | |
83 | template <typename T> |
84 | class Inverse final : public Transform { |
85 | public: |
86 | template <typename = std::enable_if<std::is_same<T, SkMatrix>::value || |
87 | std::is_same<T, SkM44 >::value >> |
88 | explicit Inverse(sk_sp<Transform> t) |
89 | : fT(std::move(t)) { |
90 | SkASSERT(fT); |
91 | |
92 | this->observeInval(fT); |
93 | } |
94 | |
95 | ~Inverse() override { |
96 | this->unobserveInval(fT); |
97 | } |
98 | |
99 | protected: |
100 | SkRect onRevalidate(InvalidationController* ic, const SkMatrix& ctm) override { |
101 | fT->revalidate(ic, ctm); |
102 | |
103 | if (!TransformPriv::As<T>(fT).invert(&fInverted)) { |
104 | fInverted.setIdentity(); |
105 | } |
106 | |
107 | return SkRect::MakeEmpty(); |
108 | } |
109 | |
110 | bool is44() const override { return std::is_same<T, SkM44>::value; } |
111 | |
112 | SkMatrix asMatrix() const override { |
113 | SkASSERT(!this->hasInval()); |
114 | return AsSkMatrix(fInverted); |
115 | } |
116 | |
117 | SkM44 asM44() const override { |
118 | SkASSERT(!this->hasInval()); |
119 | return AsSkM44(fInverted); |
120 | } |
121 | |
122 | private: |
123 | const sk_sp<Transform> fT; |
124 | T fInverted; |
125 | |
126 | using INHERITED = Transform; |
127 | }; |
128 | |
129 | } // namespace |
130 | |
131 | template <> |
132 | SkMatrix Matrix<SkMatrix>::asMatrix() const { return fMatrix; } |
133 | |
134 | template <> |
135 | SkM44 Matrix<SkMatrix>::asM44() const { return SkM44(fMatrix); } |
136 | |
137 | template <> |
138 | SkMatrix Matrix<SkM44>::asMatrix() const { return fMatrix.asM33(); } |
139 | |
140 | template <> |
141 | SkM44 Matrix<SkM44>::asM44() const { return fMatrix; } |
142 | |
143 | // Transform nodes don't generate damage on their own, but via ancestor TransformEffects. |
144 | Transform::Transform() : INHERITED(kBubbleDamage_Trait) {} |
145 | |
146 | sk_sp<Transform> Transform::MakeConcat(sk_sp<Transform> a, sk_sp<Transform> b) { |
147 | if (!a) { |
148 | return b; |
149 | } |
150 | |
151 | if (!b) { |
152 | return a; |
153 | } |
154 | |
155 | return TransformPriv::Is44(a) || TransformPriv::Is44(b) |
156 | ? sk_sp<Transform>(new Concat<SkM44 >(std::move(a), std::move(b))) |
157 | : sk_sp<Transform>(new Concat<SkMatrix>(std::move(a), std::move(b))); |
158 | } |
159 | |
160 | sk_sp<Transform> Transform::MakeInverse(sk_sp<Transform> t) { |
161 | if (!t) { |
162 | return nullptr; |
163 | } |
164 | |
165 | return TransformPriv::Is44(t) |
166 | ? sk_sp<Transform>(new Inverse<SkM44 >(std::move(t))) |
167 | : sk_sp<Transform>(new Inverse<SkMatrix>(std::move(t))); |
168 | } |
169 | |
170 | TransformEffect::TransformEffect(sk_sp<RenderNode> child, sk_sp<Transform> transform) |
171 | : INHERITED(std::move(child)) |
172 | , fTransform(std::move(transform)) { |
173 | this->observeInval(fTransform); |
174 | } |
175 | |
176 | TransformEffect::~TransformEffect() { |
177 | this->unobserveInval(fTransform); |
178 | } |
179 | |
180 | void TransformEffect::onRender(SkCanvas* canvas, const RenderContext* ctx) const { |
181 | SkAutoCanvasRestore acr(canvas, true); |
182 | canvas->concat(TransformPriv::As<SkM44>(fTransform)); |
183 | |
184 | this->INHERITED::onRender(canvas, ctx); |
185 | } |
186 | |
187 | const RenderNode* TransformEffect::onNodeAt(const SkPoint& p) const { |
188 | const auto p4 = TransformPriv::As<SkM44>(fTransform).map(p.fX, p.fY, 0, 0); |
189 | |
190 | return this->INHERITED::onNodeAt({p4.x, p4.y}); |
191 | } |
192 | |
193 | SkRect TransformEffect::onRevalidate(InvalidationController* ic, const SkMatrix& ctm) { |
194 | SkASSERT(this->hasInval()); |
195 | |
196 | // We don't care about matrix reval results. |
197 | fTransform->revalidate(ic, ctm); |
198 | |
199 | // TODO: need to update all the reval plumbing for m44. |
200 | const auto m = TransformPriv::As<SkMatrix>(fTransform); |
201 | auto bounds = this->INHERITED::onRevalidate(ic, SkMatrix::Concat(ctm, m)); |
202 | m.mapRect(&bounds); |
203 | |
204 | return bounds; |
205 | } |
206 | |
207 | } // namespace sksg |
208 | |