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 <>
AsSkMatrix(const SkMatrix & m)21 SkMatrix AsSkMatrix<SkMatrix>(const SkMatrix& m) { return m; }
22
23 template <>
AsSkMatrix(const SkM44 & m)24 SkMatrix AsSkMatrix<SkM44>(const SkM44& m) { return m.asM33(); }
25
26 template <typename T>
27 SkM44 AsSkM44(const T&);
28
29 template <>
AsSkM44(const SkMatrix & m)30 SkM44 AsSkM44<SkMatrix>(const SkMatrix& m) { return SkM44(m); }
31
32 template <>
AsSkM44(const SkM44 & m)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 >>
Concat(sk_sp<Transform> a,sk_sp<Transform> b)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
~Concat()49 ~Concat() override {
50 this->unobserveInval(fA);
51 this->unobserveInval(fB);
52 }
53
54 protected:
onRevalidate(InvalidationController * ic,const SkMatrix & ctm)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
is44() const64 bool is44() const override { return std::is_same<T, SkM44>::value; }
65
asMatrix() const66 SkMatrix asMatrix() const override {
67 SkASSERT(!this->hasInval());
68 return AsSkMatrix(fComposed);
69 }
70
asM44() const71 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 >>
Inverse(sk_sp<Transform> t)88 explicit Inverse(sk_sp<Transform> t)
89 : fT(std::move(t)) {
90 SkASSERT(fT);
91
92 this->observeInval(fT);
93 }
94
~Inverse()95 ~Inverse() override {
96 this->unobserveInval(fT);
97 }
98
99 protected:
onRevalidate(InvalidationController * ic,const SkMatrix & ctm)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
is44() const110 bool is44() const override { return std::is_same<T, SkM44>::value; }
111
asMatrix() const112 SkMatrix asMatrix() const override {
113 SkASSERT(!this->hasInval());
114 return AsSkMatrix(fInverted);
115 }
116
asM44() const117 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 <>
asMatrix() const132 SkMatrix Matrix<SkMatrix>::asMatrix() const { return fMatrix; }
133
134 template <>
asM44() const135 SkM44 Matrix<SkMatrix>::asM44() const { return SkM44(fMatrix); }
136
137 template <>
asMatrix() const138 SkMatrix Matrix<SkM44>::asMatrix() const { return fMatrix.asM33(); }
139
140 template <>
asM44() const141 SkM44 Matrix<SkM44>::asM44() const { return fMatrix; }
142
143 // Transform nodes don't generate damage on their own, but via ancestor TransformEffects.
Transform()144 Transform::Transform() : INHERITED(kBubbleDamage_Trait) {}
145
MakeConcat(sk_sp<Transform> a,sk_sp<Transform> b)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
MakeInverse(sk_sp<Transform> t)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
TransformEffect(sk_sp<RenderNode> child,sk_sp<Transform> transform)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
~TransformEffect()176 TransformEffect::~TransformEffect() {
177 this->unobserveInval(fTransform);
178 }
179
onRender(SkCanvas * canvas,const RenderContext * ctx) const180 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
onNodeAt(const SkPoint & p) const187 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
onRevalidate(InvalidationController * ic,const SkMatrix & ctm)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