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
13namespace sksg {
14
15namespace {
16
17template <typename T>
18SkMatrix AsSkMatrix(const T&);
19
20template <>
21SkMatrix AsSkMatrix<SkMatrix>(const SkMatrix& m) { return m; }
22
23template <>
24SkMatrix AsSkMatrix<SkM44>(const SkM44& m) { return m.asM33(); }
25
26template <typename T>
27SkM44 AsSkM44(const T&);
28
29template <>
30SkM44 AsSkM44<SkMatrix>(const SkMatrix& m) { return SkM44(m); }
31
32template <>
33SkM44 AsSkM44<SkM44>(const SkM44& m) { return m; }
34
35template <typename T>
36class Concat final : public Transform {
37public:
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
54protected:
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
76private:
77 const sk_sp<Transform> fA, fB;
78 T fComposed;
79
80 using INHERITED = Transform;
81};
82
83template <typename T>
84class Inverse final : public Transform {
85public:
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
99protected:
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
122private:
123 const sk_sp<Transform> fT;
124 T fInverted;
125
126 using INHERITED = Transform;
127};
128
129} // namespace
130
131template <>
132SkMatrix Matrix<SkMatrix>::asMatrix() const { return fMatrix; }
133
134template <>
135SkM44 Matrix<SkMatrix>::asM44() const { return SkM44(fMatrix); }
136
137template <>
138SkMatrix Matrix<SkM44>::asMatrix() const { return fMatrix.asM33(); }
139
140template <>
141SkM44 Matrix<SkM44>::asM44() const { return fMatrix; }
142
143// Transform nodes don't generate damage on their own, but via ancestor TransformEffects.
144Transform::Transform() : INHERITED(kBubbleDamage_Trait) {}
145
146sk_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
160sk_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
170TransformEffect::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
176TransformEffect::~TransformEffect() {
177 this->unobserveInval(fTransform);
178}
179
180void 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
187const 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
193SkRect 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