xref: /aosp_15_r20/external/skia/modules/sksg/src/SkSGTransform.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1*c8dee2aaSAndroid Build Coastguard Worker /*
2*c8dee2aaSAndroid Build Coastguard Worker  * Copyright 2017 Google Inc.
3*c8dee2aaSAndroid Build Coastguard Worker  *
4*c8dee2aaSAndroid Build Coastguard Worker  * Use of this source code is governed by a BSD-style license that can be
5*c8dee2aaSAndroid Build Coastguard Worker  * found in the LICENSE file.
6*c8dee2aaSAndroid Build Coastguard Worker  */
7*c8dee2aaSAndroid Build Coastguard Worker 
8*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkCanvas.h"
9*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkPoint.h"
10*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkAssert.h"
11*c8dee2aaSAndroid Build Coastguard Worker #include "modules/sksg/include/SkSGTransform.h"
12*c8dee2aaSAndroid Build Coastguard Worker #include "modules/sksg/src/SkSGTransformPriv.h"
13*c8dee2aaSAndroid Build Coastguard Worker 
14*c8dee2aaSAndroid Build Coastguard Worker namespace sksg {
15*c8dee2aaSAndroid Build Coastguard Worker namespace {
16*c8dee2aaSAndroid Build Coastguard Worker 
17*c8dee2aaSAndroid Build Coastguard Worker template <typename T>
18*c8dee2aaSAndroid Build Coastguard Worker SkMatrix AsSkMatrix(const T&);
19*c8dee2aaSAndroid Build Coastguard Worker 
20*c8dee2aaSAndroid Build Coastguard Worker template <>
AsSkMatrix(const SkMatrix & m)21*c8dee2aaSAndroid Build Coastguard Worker SkMatrix AsSkMatrix<SkMatrix>(const SkMatrix& m) { return m; }
22*c8dee2aaSAndroid Build Coastguard Worker 
23*c8dee2aaSAndroid Build Coastguard Worker template <>
AsSkMatrix(const SkM44 & m)24*c8dee2aaSAndroid Build Coastguard Worker SkMatrix AsSkMatrix<SkM44>(const SkM44& m) { return m.asM33(); }
25*c8dee2aaSAndroid Build Coastguard Worker 
26*c8dee2aaSAndroid Build Coastguard Worker template <typename T>
27*c8dee2aaSAndroid Build Coastguard Worker SkM44 AsSkM44(const T&);
28*c8dee2aaSAndroid Build Coastguard Worker 
29*c8dee2aaSAndroid Build Coastguard Worker template <>
AsSkM44(const SkMatrix & m)30*c8dee2aaSAndroid Build Coastguard Worker SkM44 AsSkM44<SkMatrix>(const SkMatrix& m) { return SkM44(m); }
31*c8dee2aaSAndroid Build Coastguard Worker 
32*c8dee2aaSAndroid Build Coastguard Worker template <>
AsSkM44(const SkM44 & m)33*c8dee2aaSAndroid Build Coastguard Worker SkM44 AsSkM44<SkM44>(const SkM44& m) { return m; }
34*c8dee2aaSAndroid Build Coastguard Worker 
35*c8dee2aaSAndroid Build Coastguard Worker template <typename T>
36*c8dee2aaSAndroid Build Coastguard Worker class Concat final : public Transform {
37*c8dee2aaSAndroid Build Coastguard Worker public:
38*c8dee2aaSAndroid Build Coastguard Worker     template <typename = std::enable_if<std::is_same<T, SkMatrix>::value ||
39*c8dee2aaSAndroid Build Coastguard Worker                                         std::is_same<T, SkM44   >::value >>
Concat(sk_sp<Transform> a,sk_sp<Transform> b)40*c8dee2aaSAndroid Build Coastguard Worker     Concat(sk_sp<Transform> a, sk_sp<Transform> b)
41*c8dee2aaSAndroid Build Coastguard Worker         : fA(std::move(a)), fB(std::move(b)) {
42*c8dee2aaSAndroid Build Coastguard Worker         SkASSERT(fA);
43*c8dee2aaSAndroid Build Coastguard Worker         SkASSERT(fB);
44*c8dee2aaSAndroid Build Coastguard Worker 
45*c8dee2aaSAndroid Build Coastguard Worker         this->observeInval(fA);
46*c8dee2aaSAndroid Build Coastguard Worker         this->observeInval(fB);
47*c8dee2aaSAndroid Build Coastguard Worker     }
48*c8dee2aaSAndroid Build Coastguard Worker 
~Concat()49*c8dee2aaSAndroid Build Coastguard Worker     ~Concat() override {
50*c8dee2aaSAndroid Build Coastguard Worker         this->unobserveInval(fA);
51*c8dee2aaSAndroid Build Coastguard Worker         this->unobserveInval(fB);
52*c8dee2aaSAndroid Build Coastguard Worker     }
53*c8dee2aaSAndroid Build Coastguard Worker 
54*c8dee2aaSAndroid Build Coastguard Worker protected:
onRevalidate(InvalidationController * ic,const SkMatrix & ctm)55*c8dee2aaSAndroid Build Coastguard Worker     SkRect onRevalidate(InvalidationController* ic, const SkMatrix& ctm) override {
56*c8dee2aaSAndroid Build Coastguard Worker         fA->revalidate(ic, ctm);
57*c8dee2aaSAndroid Build Coastguard Worker         fB->revalidate(ic, ctm);
58*c8dee2aaSAndroid Build Coastguard Worker 
59*c8dee2aaSAndroid Build Coastguard Worker         fComposed.setConcat(TransformPriv::As<T>(fA),
60*c8dee2aaSAndroid Build Coastguard Worker                             TransformPriv::As<T>(fB));
61*c8dee2aaSAndroid Build Coastguard Worker         return SkRect::MakeEmpty();
62*c8dee2aaSAndroid Build Coastguard Worker     }
63*c8dee2aaSAndroid Build Coastguard Worker 
is44() const64*c8dee2aaSAndroid Build Coastguard Worker     bool is44() const override { return std::is_same<T, SkM44>::value; }
65*c8dee2aaSAndroid Build Coastguard Worker 
asMatrix() const66*c8dee2aaSAndroid Build Coastguard Worker     SkMatrix asMatrix() const override {
67*c8dee2aaSAndroid Build Coastguard Worker         SkASSERT(!this->hasInval());
68*c8dee2aaSAndroid Build Coastguard Worker         return AsSkMatrix(fComposed);
69*c8dee2aaSAndroid Build Coastguard Worker     }
70*c8dee2aaSAndroid Build Coastguard Worker 
asM44() const71*c8dee2aaSAndroid Build Coastguard Worker     SkM44 asM44() const override {
72*c8dee2aaSAndroid Build Coastguard Worker         SkASSERT(!this->hasInval());
73*c8dee2aaSAndroid Build Coastguard Worker         return AsSkM44(fComposed);
74*c8dee2aaSAndroid Build Coastguard Worker     }
75*c8dee2aaSAndroid Build Coastguard Worker 
76*c8dee2aaSAndroid Build Coastguard Worker private:
77*c8dee2aaSAndroid Build Coastguard Worker     const sk_sp<Transform> fA, fB;
78*c8dee2aaSAndroid Build Coastguard Worker     T                      fComposed;
79*c8dee2aaSAndroid Build Coastguard Worker 
80*c8dee2aaSAndroid Build Coastguard Worker     using INHERITED = Transform;
81*c8dee2aaSAndroid Build Coastguard Worker };
82*c8dee2aaSAndroid Build Coastguard Worker 
83*c8dee2aaSAndroid Build Coastguard Worker template <typename T>
84*c8dee2aaSAndroid Build Coastguard Worker class Inverse final : public Transform {
85*c8dee2aaSAndroid Build Coastguard Worker public:
86*c8dee2aaSAndroid Build Coastguard Worker     template <typename = std::enable_if<std::is_same<T, SkMatrix>::value ||
87*c8dee2aaSAndroid Build Coastguard Worker                                         std::is_same<T, SkM44   >::value >>
Inverse(sk_sp<Transform> t)88*c8dee2aaSAndroid Build Coastguard Worker     explicit Inverse(sk_sp<Transform> t)
89*c8dee2aaSAndroid Build Coastguard Worker         : fT(std::move(t)) {
90*c8dee2aaSAndroid Build Coastguard Worker         SkASSERT(fT);
91*c8dee2aaSAndroid Build Coastguard Worker 
92*c8dee2aaSAndroid Build Coastguard Worker         this->observeInval(fT);
93*c8dee2aaSAndroid Build Coastguard Worker     }
94*c8dee2aaSAndroid Build Coastguard Worker 
~Inverse()95*c8dee2aaSAndroid Build Coastguard Worker     ~Inverse() override {
96*c8dee2aaSAndroid Build Coastguard Worker         this->unobserveInval(fT);
97*c8dee2aaSAndroid Build Coastguard Worker     }
98*c8dee2aaSAndroid Build Coastguard Worker 
99*c8dee2aaSAndroid Build Coastguard Worker protected:
onRevalidate(InvalidationController * ic,const SkMatrix & ctm)100*c8dee2aaSAndroid Build Coastguard Worker     SkRect onRevalidate(InvalidationController* ic, const SkMatrix& ctm) override {
101*c8dee2aaSAndroid Build Coastguard Worker         fT->revalidate(ic, ctm);
102*c8dee2aaSAndroid Build Coastguard Worker 
103*c8dee2aaSAndroid Build Coastguard Worker         if (!TransformPriv::As<T>(fT).invert(&fInverted)) {
104*c8dee2aaSAndroid Build Coastguard Worker             fInverted.setIdentity();
105*c8dee2aaSAndroid Build Coastguard Worker         }
106*c8dee2aaSAndroid Build Coastguard Worker 
107*c8dee2aaSAndroid Build Coastguard Worker         return SkRect::MakeEmpty();
108*c8dee2aaSAndroid Build Coastguard Worker     }
109*c8dee2aaSAndroid Build Coastguard Worker 
is44() const110*c8dee2aaSAndroid Build Coastguard Worker     bool is44() const override { return std::is_same<T, SkM44>::value; }
111*c8dee2aaSAndroid Build Coastguard Worker 
asMatrix() const112*c8dee2aaSAndroid Build Coastguard Worker     SkMatrix asMatrix() const override {
113*c8dee2aaSAndroid Build Coastguard Worker         SkASSERT(!this->hasInval());
114*c8dee2aaSAndroid Build Coastguard Worker         return AsSkMatrix(fInverted);
115*c8dee2aaSAndroid Build Coastguard Worker     }
116*c8dee2aaSAndroid Build Coastguard Worker 
asM44() const117*c8dee2aaSAndroid Build Coastguard Worker     SkM44 asM44() const override {
118*c8dee2aaSAndroid Build Coastguard Worker         SkASSERT(!this->hasInval());
119*c8dee2aaSAndroid Build Coastguard Worker         return AsSkM44(fInverted);
120*c8dee2aaSAndroid Build Coastguard Worker     }
121*c8dee2aaSAndroid Build Coastguard Worker 
122*c8dee2aaSAndroid Build Coastguard Worker private:
123*c8dee2aaSAndroid Build Coastguard Worker     const sk_sp<Transform> fT;
124*c8dee2aaSAndroid Build Coastguard Worker     T                      fInverted;
125*c8dee2aaSAndroid Build Coastguard Worker 
126*c8dee2aaSAndroid Build Coastguard Worker     using INHERITED = Transform;
127*c8dee2aaSAndroid Build Coastguard Worker };
128*c8dee2aaSAndroid Build Coastguard Worker 
129*c8dee2aaSAndroid Build Coastguard Worker } // namespace
130*c8dee2aaSAndroid Build Coastguard Worker 
131*c8dee2aaSAndroid Build Coastguard Worker template <>
asMatrix() const132*c8dee2aaSAndroid Build Coastguard Worker SkMatrix Matrix<SkMatrix>::asMatrix() const { return fMatrix; }
133*c8dee2aaSAndroid Build Coastguard Worker 
134*c8dee2aaSAndroid Build Coastguard Worker template <>
asM44() const135*c8dee2aaSAndroid Build Coastguard Worker SkM44 Matrix<SkMatrix>::asM44() const { return SkM44(fMatrix); }
136*c8dee2aaSAndroid Build Coastguard Worker 
137*c8dee2aaSAndroid Build Coastguard Worker template <>
asMatrix() const138*c8dee2aaSAndroid Build Coastguard Worker SkMatrix Matrix<SkM44>::asMatrix() const { return fMatrix.asM33(); }
139*c8dee2aaSAndroid Build Coastguard Worker 
140*c8dee2aaSAndroid Build Coastguard Worker template <>
asM44() const141*c8dee2aaSAndroid Build Coastguard Worker SkM44 Matrix<SkM44>::asM44() const { return fMatrix; }
142*c8dee2aaSAndroid Build Coastguard Worker 
143*c8dee2aaSAndroid Build Coastguard Worker // Transform nodes don't generate damage on their own, but via ancestor TransformEffects.
Transform()144*c8dee2aaSAndroid Build Coastguard Worker Transform::Transform() : INHERITED(kBubbleDamage_Trait) {}
145*c8dee2aaSAndroid Build Coastguard Worker 
MakeConcat(sk_sp<Transform> a,sk_sp<Transform> b)146*c8dee2aaSAndroid Build Coastguard Worker sk_sp<Transform> Transform::MakeConcat(sk_sp<Transform> a, sk_sp<Transform> b) {
147*c8dee2aaSAndroid Build Coastguard Worker     if (!a) {
148*c8dee2aaSAndroid Build Coastguard Worker         return b;
149*c8dee2aaSAndroid Build Coastguard Worker     }
150*c8dee2aaSAndroid Build Coastguard Worker 
151*c8dee2aaSAndroid Build Coastguard Worker     if (!b) {
152*c8dee2aaSAndroid Build Coastguard Worker         return a;
153*c8dee2aaSAndroid Build Coastguard Worker     }
154*c8dee2aaSAndroid Build Coastguard Worker 
155*c8dee2aaSAndroid Build Coastguard Worker     return TransformPriv::Is44(a) || TransformPriv::Is44(b)
156*c8dee2aaSAndroid Build Coastguard Worker         ? sk_sp<Transform>(new Concat<SkM44   >(std::move(a), std::move(b)))
157*c8dee2aaSAndroid Build Coastguard Worker         : sk_sp<Transform>(new Concat<SkMatrix>(std::move(a), std::move(b)));
158*c8dee2aaSAndroid Build Coastguard Worker }
159*c8dee2aaSAndroid Build Coastguard Worker 
MakeInverse(sk_sp<Transform> t)160*c8dee2aaSAndroid Build Coastguard Worker sk_sp<Transform> Transform::MakeInverse(sk_sp<Transform> t) {
161*c8dee2aaSAndroid Build Coastguard Worker     if (!t) {
162*c8dee2aaSAndroid Build Coastguard Worker         return nullptr;
163*c8dee2aaSAndroid Build Coastguard Worker     }
164*c8dee2aaSAndroid Build Coastguard Worker 
165*c8dee2aaSAndroid Build Coastguard Worker     return TransformPriv::Is44(t)
166*c8dee2aaSAndroid Build Coastguard Worker         ? sk_sp<Transform>(new Inverse<SkM44   >(std::move(t)))
167*c8dee2aaSAndroid Build Coastguard Worker         : sk_sp<Transform>(new Inverse<SkMatrix>(std::move(t)));
168*c8dee2aaSAndroid Build Coastguard Worker }
169*c8dee2aaSAndroid Build Coastguard Worker 
TransformEffect(sk_sp<RenderNode> child,sk_sp<Transform> transform)170*c8dee2aaSAndroid Build Coastguard Worker TransformEffect::TransformEffect(sk_sp<RenderNode> child, sk_sp<Transform> transform)
171*c8dee2aaSAndroid Build Coastguard Worker     : INHERITED(std::move(child))
172*c8dee2aaSAndroid Build Coastguard Worker     , fTransform(std::move(transform)) {
173*c8dee2aaSAndroid Build Coastguard Worker     this->observeInval(fTransform);
174*c8dee2aaSAndroid Build Coastguard Worker }
175*c8dee2aaSAndroid Build Coastguard Worker 
~TransformEffect()176*c8dee2aaSAndroid Build Coastguard Worker TransformEffect::~TransformEffect() {
177*c8dee2aaSAndroid Build Coastguard Worker     this->unobserveInval(fTransform);
178*c8dee2aaSAndroid Build Coastguard Worker }
179*c8dee2aaSAndroid Build Coastguard Worker 
onRender(SkCanvas * canvas,const RenderContext * ctx) const180*c8dee2aaSAndroid Build Coastguard Worker void TransformEffect::onRender(SkCanvas* canvas, const RenderContext* ctx) const {
181*c8dee2aaSAndroid Build Coastguard Worker     SkAutoCanvasRestore acr(canvas, true);
182*c8dee2aaSAndroid Build Coastguard Worker     canvas->concat(TransformPriv::As<SkM44>(fTransform));
183*c8dee2aaSAndroid Build Coastguard Worker 
184*c8dee2aaSAndroid Build Coastguard Worker     this->INHERITED::onRender(canvas, ctx);
185*c8dee2aaSAndroid Build Coastguard Worker }
186*c8dee2aaSAndroid Build Coastguard Worker 
onNodeAt(const SkPoint & p) const187*c8dee2aaSAndroid Build Coastguard Worker const RenderNode* TransformEffect::onNodeAt(const SkPoint& p) const {
188*c8dee2aaSAndroid Build Coastguard Worker     const auto p4 = TransformPriv::As<SkM44>(fTransform).map(p.fX, p.fY, 0, 0);
189*c8dee2aaSAndroid Build Coastguard Worker 
190*c8dee2aaSAndroid Build Coastguard Worker     return this->INHERITED::onNodeAt({p4.x, p4.y});
191*c8dee2aaSAndroid Build Coastguard Worker }
192*c8dee2aaSAndroid Build Coastguard Worker 
onRevalidate(InvalidationController * ic,const SkMatrix & ctm)193*c8dee2aaSAndroid Build Coastguard Worker SkRect TransformEffect::onRevalidate(InvalidationController* ic, const SkMatrix& ctm) {
194*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(this->hasInval());
195*c8dee2aaSAndroid Build Coastguard Worker 
196*c8dee2aaSAndroid Build Coastguard Worker     // We don't care about matrix reval results.
197*c8dee2aaSAndroid Build Coastguard Worker     fTransform->revalidate(ic, ctm);
198*c8dee2aaSAndroid Build Coastguard Worker 
199*c8dee2aaSAndroid Build Coastguard Worker     // TODO: need to update all the reval plumbing for m44.
200*c8dee2aaSAndroid Build Coastguard Worker     const auto m = TransformPriv::As<SkMatrix>(fTransform);
201*c8dee2aaSAndroid Build Coastguard Worker     auto bounds = this->INHERITED::onRevalidate(ic, SkMatrix::Concat(ctm, m));
202*c8dee2aaSAndroid Build Coastguard Worker     m.mapRect(&bounds);
203*c8dee2aaSAndroid Build Coastguard Worker 
204*c8dee2aaSAndroid Build Coastguard Worker     return bounds;
205*c8dee2aaSAndroid Build Coastguard Worker }
206*c8dee2aaSAndroid Build Coastguard Worker 
207*c8dee2aaSAndroid Build Coastguard Worker } // namespace sksg
208