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