Coverage Report

Created: 2024-05-20 07:14

/src/skia/modules/skottie/src/Transform.cpp
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright 2020 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/skottie/src/Transform.h"
9
10
#include "include/core/SkRefCnt.h"
11
#include "include/core/SkScalar.h"
12
#include "include/private/base/SkAssert.h"
13
#include "include/private/base/SkTPin.h"
14
#include "modules/skottie/src/SkottiePriv.h"
15
#include "modules/sksg/include/SkSGTransform.h"
16
#include "src/utils/SkJSON.h"
17
18
#include <cmath>
19
20
namespace skottie {
21
namespace internal {
22
23
TransformAdapter2D::TransformAdapter2D(const AnimationBuilder& abuilder,
24
                                       const skjson::ObjectValue* janchor_point,
25
                                       const skjson::ObjectValue* jposition,
26
                                       const skjson::ObjectValue* jscale,
27
                                       const skjson::ObjectValue* jrotation,
28
                                       const skjson::ObjectValue* jskew,
29
                                       const skjson::ObjectValue* jskew_axis,
30
                                       bool auto_orient)
31
100k
    : INHERITED(sksg::Matrix<SkMatrix>::Make(SkMatrix::I())) {
32
33
100k
    this->bind(abuilder, janchor_point, fAnchorPoint);
34
100k
    this->bind(abuilder, jscale       , fScale);
35
100k
    this->bind(abuilder, jrotation    , fRotation);
36
100k
    this->bind(abuilder, jskew        , fSkew);
37
100k
    this->bind(abuilder, jskew_axis   , fSkewAxis);
38
39
100k
    this->bindAutoOrientable(abuilder, jposition, &fPosition, auto_orient ? &fOrientation
40
100k
                                                                          : nullptr);
41
100k
}
42
43
100k
TransformAdapter2D::~TransformAdapter2D() {}
44
45
53.9k
void TransformAdapter2D::onSync() {
46
53.9k
    this->node()->setMatrix(this->totalMatrix());
47
53.9k
}
48
49
141k
SkMatrix TransformAdapter2D::totalMatrix() const {
50
141k
    auto skew_matrix = [](float sk, float sa) {
51
141k
        if (!sk) return SkMatrix::I();
52
53
        // AE control limit.
54
576
        static constexpr float kMaxSkewAngle = 85;
55
576
        sk = -SkDegreesToRadians(SkTPin(sk, -kMaxSkewAngle, kMaxSkewAngle));
56
576
        sa =  SkDegreesToRadians(sa);
57
58
        // Similar to CSS/SVG SkewX [1] with an explicit rotation.
59
        // [1] https://www.w3.org/TR/css-transforms-1/#SkewXDefined
60
576
        return SkMatrix::RotateRad(sa)
61
576
             * SkMatrix::Skew(std::tan(sk), 0)
62
576
             * SkMatrix::RotateRad(-sa);
63
141k
    };
64
65
141k
    return SkMatrix::Translate(fPosition.x, fPosition.y)
66
141k
         * SkMatrix::RotateDeg(fRotation + fOrientation)
67
141k
         * skew_matrix        (fSkew, fSkewAxis)
68
141k
         * SkMatrix::Scale    (fScale.x / 100, fScale.y / 100) // 100% based
69
141k
         * SkMatrix::Translate(-fAnchorPoint.x, -fAnchorPoint.y);
70
141k
}
71
72
0
SkPoint TransformAdapter2D::getAnchorPoint() const {
73
0
    return { fAnchorPoint.x, fAnchorPoint.y };
74
0
}
75
76
0
void TransformAdapter2D::setAnchorPoint(const SkPoint& ap) {
77
0
    fAnchorPoint = { ap.x(), ap.y() };
78
0
    this->onSync();
79
0
}
80
81
0
SkPoint TransformAdapter2D::getPosition() const {
82
0
    return { fPosition.x, fPosition.y };
83
0
}
84
85
0
void TransformAdapter2D::setPosition(const SkPoint& p) {
86
0
    fPosition = { p.x(), p.y() };
87
0
    this->onSync();
88
0
}
89
90
0
SkVector TransformAdapter2D::getScale() const {
91
0
    return { fScale.x, fScale.y };
92
0
}
93
94
0
void TransformAdapter2D::setScale(const SkVector& s) {
95
0
    fScale = { s.x(), s.y() };
96
0
    this->onSync();
97
0
}
98
99
0
void TransformAdapter2D::setRotation(float r) {
100
0
    fRotation = r;
101
0
    this->onSync();
102
0
}
103
104
0
void TransformAdapter2D::setSkew(float sk) {
105
0
    fSkew = sk;
106
0
    this->onSync();
107
0
}
108
109
0
void TransformAdapter2D::setSkewAxis(float sa) {
110
0
    fSkewAxis = sa;
111
0
    this->onSync();
112
0
}
113
114
sk_sp<sksg::Transform> AnimationBuilder::attachMatrix2D(const skjson::ObjectValue& jtransform,
115
                                                        sk_sp<sksg::Transform> parent,
116
100k
                                                        bool auto_orient) const {
117
100k
    const auto* jrotation = &jtransform["r"];
118
100k
    if (jrotation->is<skjson::NullValue>()) {
119
        // Some 2D rotations are disguised as 3D...
120
33.8k
        jrotation = &jtransform["rz"];
121
33.8k
    }
122
123
100k
    auto adapter = TransformAdapter2D::Make(*this,
124
100k
                                            jtransform["a"],
125
100k
                                            jtransform["p"],
126
100k
                                            jtransform["s"],
127
100k
                                            *jrotation,
128
100k
                                            jtransform["sk"],
129
100k
                                            jtransform["sa"],
130
100k
                                            auto_orient);
131
100k
    SkASSERT(adapter);
132
133
100k
    const auto dispatched = this->dispatchTransformProperty(adapter);
134
135
100k
    if (adapter->isStatic()) {
136
87.9k
        if (!dispatched && adapter->totalMatrix().isIdentity()) {
137
            // The transform has no observable effects - we can discard.
138
40.4k
            return parent;
139
40.4k
        }
140
47.4k
        adapter->seek(0);
141
47.4k
    } else {
142
12.9k
        fCurrentAnimatorScope->push_back(adapter);
143
12.9k
    }
144
145
60.3k
    return sksg::Transform::MakeConcat(std::move(parent), adapter->node());
146
100k
}
147
148
TransformAdapter3D::TransformAdapter3D(const skjson::ObjectValue& jtransform,
149
                                       const AnimationBuilder& abuilder)
150
12.7k
    : INHERITED(sksg::Matrix<SkM44>::Make(SkM44())) {
151
152
12.7k
    this->bind(abuilder, jtransform["a"], fAnchorPoint);
153
12.7k
    this->bind(abuilder, jtransform["p"], fPosition);
154
12.7k
    this->bind(abuilder, jtransform["s"], fScale);
155
156
    // Axis-wise rotation and orientation are mapped to the same rotation property (3D rotation).
157
    // The difference is in how they get interpolated (scalar/decomposed vs. vector).
158
12.7k
    this->bind(abuilder, jtransform["rx"], fRx);
159
12.7k
    this->bind(abuilder, jtransform["ry"], fRy);
160
12.7k
    this->bind(abuilder, jtransform["rz"], fRz);
161
12.7k
    this->bind(abuilder, jtransform["or"], fOrientation);
162
12.7k
}
163
164
12.7k
TransformAdapter3D::~TransformAdapter3D() = default;
165
166
8.39k
void TransformAdapter3D::onSync() {
167
8.39k
    this->node()->setMatrix(this->totalMatrix());
168
8.39k
}
169
170
19.8k
SkV3 TransformAdapter3D::anchor_point() const {
171
19.8k
    return fAnchorPoint;
172
19.8k
}
173
174
19.8k
SkV3 TransformAdapter3D::position() const {
175
19.8k
    return fPosition;
176
19.8k
}
177
178
19.8k
SkV3 TransformAdapter3D::rotation() const {
179
    // orientation and axis-wise rotation map onto the same property.
180
19.8k
    return static_cast<SkV3>(fOrientation) + SkV3{ fRx, fRy, fRz };
181
19.8k
}
182
183
19.8k
SkM44 TransformAdapter3D::totalMatrix() const {
184
19.8k
    const auto anchor_point = this->anchor_point(),
185
19.8k
               position     = this->position(),
186
19.8k
               scale        = static_cast<SkV3>(fScale),
187
19.8k
               rotation     = this->rotation();
188
189
19.8k
    return SkM44::Translate(position.x, position.y, position.z)
190
19.8k
         * SkM44::Rotate({ 1, 0, 0 }, SkDegreesToRadians(rotation.x))
191
19.8k
         * SkM44::Rotate({ 0, 1, 0 }, SkDegreesToRadians(rotation.y))
192
19.8k
         * SkM44::Rotate({ 0, 0, 1 }, SkDegreesToRadians(rotation.z))
193
19.8k
         * SkM44::Scale(scale.x / 100, scale.y / 100, scale.z / 100)
194
19.8k
         * SkM44::Translate(-anchor_point.x, -anchor_point.y, -anchor_point.z);
195
19.8k
}
196
197
sk_sp<sksg::Transform> AnimationBuilder::attachMatrix3D(const skjson::ObjectValue& jtransform,
198
                                                        sk_sp<sksg::Transform> parent,
199
12.7k
                                                        bool /*TODO: auto_orient*/) const {
200
12.7k
    auto adapter = TransformAdapter3D::Make(jtransform, *this);
201
12.7k
    SkASSERT(adapter);
202
203
12.7k
    if (adapter->isStatic()) {
204
        // TODO: SkM44::isIdentity?
205
11.4k
        if (adapter->totalMatrix() == SkM44()) {
206
            // The transform has no observable effects - we can discard.
207
4.31k
            return parent;
208
4.31k
        }
209
7.10k
        adapter->seek(0);
210
7.10k
    } else {
211
1.35k
        fCurrentAnimatorScope->push_back(adapter);
212
1.35k
    }
213
214
8.46k
    return sksg::Transform::MakeConcat(std::move(parent), adapter->node());
215
12.7k
}
216
217
} // namespace internal
218
} // namespace skottie