1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "third_party/blink/renderer/core/animation/svg_transform_list_interpolation_type.h"
6
7 #include <memory>
8 #include <utility>
9
10 #include "base/memory/ptr_util.h"
11 #include "third_party/blink/renderer/core/animation/interpolable_value.h"
12 #include "third_party/blink/renderer/core/animation/non_interpolable_value.h"
13 #include "third_party/blink/renderer/core/animation/string_keyframe.h"
14 #include "third_party/blink/renderer/core/animation/svg_interpolation_environment.h"
15 #include "third_party/blink/renderer/core/svg/svg_transform.h"
16 #include "third_party/blink/renderer/core/svg/svg_transform_list.h"
17 #include "third_party/blink/renderer/platform/heap/heap.h"
18
19 namespace blink {
20
21 class SVGTransformNonInterpolableValue : public NonInterpolableValue {
22 public:
23 ~SVGTransformNonInterpolableValue() override = default;
24
Create(Vector<SVGTransformType> & transform_types)25 static scoped_refptr<SVGTransformNonInterpolableValue> Create(
26 Vector<SVGTransformType>& transform_types) {
27 return base::AdoptRef(
28 new SVGTransformNonInterpolableValue(transform_types));
29 }
30
TransformTypes() const31 const Vector<SVGTransformType>& TransformTypes() const {
32 return transform_types_;
33 }
34
35 DECLARE_NON_INTERPOLABLE_VALUE_TYPE();
36
37 private:
SVGTransformNonInterpolableValue(Vector<SVGTransformType> & transform_types)38 SVGTransformNonInterpolableValue(Vector<SVGTransformType>& transform_types) {
39 transform_types_.swap(transform_types);
40 }
41
42 Vector<SVGTransformType> transform_types_;
43 };
44
45 DEFINE_NON_INTERPOLABLE_VALUE_TYPE(SVGTransformNonInterpolableValue);
46 template <>
47 struct DowncastTraits<SVGTransformNonInterpolableValue> {
AllowFromblink::DowncastTraits48 static bool AllowFrom(const NonInterpolableValue* value) {
49 return value && AllowFrom(*value);
50 }
AllowFromblink::DowncastTraits51 static bool AllowFrom(const NonInterpolableValue& value) {
52 return value.GetType() == SVGTransformNonInterpolableValue::static_type_;
53 }
54 };
55
56 namespace {
57
TranslateToInterpolableValue(SVGTransform * transform)58 std::unique_ptr<InterpolableValue> TranslateToInterpolableValue(
59 SVGTransform* transform) {
60 FloatPoint translate = transform->Translate();
61 auto result = std::make_unique<InterpolableList>(2);
62 result->Set(0, std::make_unique<InterpolableNumber>(translate.X()));
63 result->Set(1, std::make_unique<InterpolableNumber>(translate.Y()));
64 return std::move(result);
65 }
66
TranslateFromInterpolableValue(const InterpolableValue & value)67 SVGTransform* TranslateFromInterpolableValue(const InterpolableValue& value) {
68 const auto& list = To<InterpolableList>(value);
69
70 auto* transform =
71 MakeGarbageCollected<SVGTransform>(SVGTransformType::kTranslate);
72 transform->SetTranslate(To<InterpolableNumber>(list.Get(0))->Value(),
73 To<InterpolableNumber>(list.Get(1))->Value());
74 return transform;
75 }
76
ScaleToInterpolableValue(SVGTransform * transform)77 std::unique_ptr<InterpolableValue> ScaleToInterpolableValue(
78 SVGTransform* transform) {
79 FloatSize scale = transform->Scale();
80 auto result = std::make_unique<InterpolableList>(2);
81 result->Set(0, std::make_unique<InterpolableNumber>(scale.Width()));
82 result->Set(1, std::make_unique<InterpolableNumber>(scale.Height()));
83 return std::move(result);
84 }
85
ScaleFromInterpolableValue(const InterpolableValue & value)86 SVGTransform* ScaleFromInterpolableValue(const InterpolableValue& value) {
87 const auto& list = To<InterpolableList>(value);
88
89 auto* transform =
90 MakeGarbageCollected<SVGTransform>(SVGTransformType::kScale);
91 transform->SetScale(To<InterpolableNumber>(list.Get(0))->Value(),
92 To<InterpolableNumber>(list.Get(1))->Value());
93 return transform;
94 }
95
RotateToInterpolableValue(SVGTransform * transform)96 std::unique_ptr<InterpolableValue> RotateToInterpolableValue(
97 SVGTransform* transform) {
98 FloatPoint rotation_center = transform->RotationCenter();
99 auto result = std::make_unique<InterpolableList>(3);
100 result->Set(0, std::make_unique<InterpolableNumber>(transform->Angle()));
101 result->Set(1, std::make_unique<InterpolableNumber>(rotation_center.X()));
102 result->Set(2, std::make_unique<InterpolableNumber>(rotation_center.Y()));
103 return std::move(result);
104 }
105
RotateFromInterpolableValue(const InterpolableValue & value)106 SVGTransform* RotateFromInterpolableValue(const InterpolableValue& value) {
107 const auto& list = To<InterpolableList>(value);
108
109 auto* transform =
110 MakeGarbageCollected<SVGTransform>(SVGTransformType::kRotate);
111 transform->SetRotate(To<InterpolableNumber>(list.Get(0))->Value(),
112 To<InterpolableNumber>(list.Get(1))->Value(),
113 To<InterpolableNumber>(list.Get(2))->Value());
114 return transform;
115 }
116
SkewXToInterpolableValue(SVGTransform * transform)117 std::unique_ptr<InterpolableValue> SkewXToInterpolableValue(
118 SVGTransform* transform) {
119 return std::make_unique<InterpolableNumber>(transform->Angle());
120 }
121
SkewXFromInterpolableValue(const InterpolableValue & value)122 SVGTransform* SkewXFromInterpolableValue(const InterpolableValue& value) {
123 auto* transform =
124 MakeGarbageCollected<SVGTransform>(SVGTransformType::kSkewx);
125 transform->SetSkewX(To<InterpolableNumber>(value).Value());
126 return transform;
127 }
128
SkewYToInterpolableValue(SVGTransform * transform)129 std::unique_ptr<InterpolableValue> SkewYToInterpolableValue(
130 SVGTransform* transform) {
131 return std::make_unique<InterpolableNumber>(transform->Angle());
132 }
133
SkewYFromInterpolableValue(const InterpolableValue & value)134 SVGTransform* SkewYFromInterpolableValue(const InterpolableValue& value) {
135 auto* transform =
136 MakeGarbageCollected<SVGTransform>(SVGTransformType::kSkewy);
137 transform->SetSkewY(To<InterpolableNumber>(value).Value());
138 return transform;
139 }
140
ToInterpolableValue(SVGTransform * transform,SVGTransformType transform_type)141 std::unique_ptr<InterpolableValue> ToInterpolableValue(
142 SVGTransform* transform,
143 SVGTransformType transform_type) {
144 switch (transform_type) {
145 case SVGTransformType::kTranslate:
146 return TranslateToInterpolableValue(transform);
147 case SVGTransformType::kScale:
148 return ScaleToInterpolableValue(transform);
149 case SVGTransformType::kRotate:
150 return RotateToInterpolableValue(transform);
151 case SVGTransformType::kSkewx:
152 return SkewXToInterpolableValue(transform);
153 case SVGTransformType::kSkewy:
154 return SkewYToInterpolableValue(transform);
155 case SVGTransformType::kMatrix:
156 case SVGTransformType::kUnknown:
157 NOTREACHED();
158 }
159 NOTREACHED();
160 return nullptr;
161 }
162
FromInterpolableValue(const InterpolableValue & value,SVGTransformType transform_type)163 SVGTransform* FromInterpolableValue(const InterpolableValue& value,
164 SVGTransformType transform_type) {
165 switch (transform_type) {
166 case SVGTransformType::kTranslate:
167 return TranslateFromInterpolableValue(value);
168 case SVGTransformType::kScale:
169 return ScaleFromInterpolableValue(value);
170 case SVGTransformType::kRotate:
171 return RotateFromInterpolableValue(value);
172 case SVGTransformType::kSkewx:
173 return SkewXFromInterpolableValue(value);
174 case SVGTransformType::kSkewy:
175 return SkewYFromInterpolableValue(value);
176 case SVGTransformType::kMatrix:
177 case SVGTransformType::kUnknown:
178 NOTREACHED();
179 }
180 NOTREACHED();
181 return nullptr;
182 }
183
GetTransformTypes(const InterpolationValue & value)184 const Vector<SVGTransformType>& GetTransformTypes(
185 const InterpolationValue& value) {
186 return To<SVGTransformNonInterpolableValue>(*value.non_interpolable_value)
187 .TransformTypes();
188 }
189
190 class SVGTransformListChecker : public InterpolationType::ConversionChecker {
191 public:
SVGTransformListChecker(const InterpolationValue & underlying)192 explicit SVGTransformListChecker(const InterpolationValue& underlying)
193 : underlying_(underlying.Clone()) {}
194
IsValid(const InterpolationEnvironment &,const InterpolationValue & underlying) const195 bool IsValid(const InterpolationEnvironment&,
196 const InterpolationValue& underlying) const final {
197 // TODO(suzyh): change maybeConvertSingle so we don't have to recalculate
198 // for changes to the interpolable values
199 if (!underlying && !underlying_)
200 return true;
201 if (!underlying || !underlying_)
202 return false;
203 return underlying_.interpolable_value->Equals(
204 *underlying.interpolable_value) &&
205 GetTransformTypes(underlying_) == GetTransformTypes(underlying);
206 }
207
208 private:
209 const InterpolationValue underlying_;
210 };
211
212 } // namespace
213
MaybeConvertNeutral(const InterpolationValue &,ConversionCheckers &) const214 InterpolationValue SVGTransformListInterpolationType::MaybeConvertNeutral(
215 const InterpolationValue&,
216 ConversionCheckers&) const {
217 NOTREACHED();
218 // This function is no longer called, because maybeConvertSingle has been
219 // overridden.
220 return nullptr;
221 }
222
MaybeConvertSVGValue(const SVGPropertyBase & svg_value) const223 InterpolationValue SVGTransformListInterpolationType::MaybeConvertSVGValue(
224 const SVGPropertyBase& svg_value) const {
225 const auto* svg_list = DynamicTo<SVGTransformList>(svg_value);
226 if (!svg_list)
227 return nullptr;
228
229 auto result = std::make_unique<InterpolableList>(svg_list->length());
230
231 Vector<SVGTransformType> transform_types;
232 for (wtf_size_t i = 0; i < svg_list->length(); i++) {
233 const SVGTransform* transform = svg_list->at(i);
234 SVGTransformType transform_type(transform->TransformType());
235 if (transform_type == SVGTransformType::kMatrix) {
236 // TODO(ericwilligers): Support matrix interpolation.
237 return nullptr;
238 }
239 result->Set(i, ToInterpolableValue(transform->Clone(), transform_type));
240 transform_types.push_back(transform_type);
241 }
242 return InterpolationValue(
243 std::move(result),
244 SVGTransformNonInterpolableValue::Create(transform_types));
245 }
246
MaybeConvertSingle(const PropertySpecificKeyframe & keyframe,const InterpolationEnvironment & environment,const InterpolationValue & underlying,ConversionCheckers & conversion_checkers) const247 InterpolationValue SVGTransformListInterpolationType::MaybeConvertSingle(
248 const PropertySpecificKeyframe& keyframe,
249 const InterpolationEnvironment& environment,
250 const InterpolationValue& underlying,
251 ConversionCheckers& conversion_checkers) const {
252 Vector<SVGTransformType> types;
253 Vector<std::unique_ptr<InterpolableValue>> interpolable_parts;
254
255 if (keyframe.Composite() == EffectModel::kCompositeAdd) {
256 if (underlying) {
257 types.AppendVector(GetTransformTypes(underlying));
258 interpolable_parts.push_back(underlying.interpolable_value->Clone());
259 }
260 conversion_checkers.push_back(
261 std::make_unique<SVGTransformListChecker>(underlying));
262 } else {
263 DCHECK(!keyframe.IsNeutral());
264 }
265
266 if (!keyframe.IsNeutral()) {
267 auto* svg_value =
268 To<SVGInterpolationEnvironment>(environment)
269 .SvgBaseValue()
270 .CloneForAnimation(
271 To<SVGPropertySpecificKeyframe>(keyframe).Value());
272 InterpolationValue value = MaybeConvertSVGValue(*svg_value);
273 if (!value)
274 return nullptr;
275 types.AppendVector(GetTransformTypes(value));
276 interpolable_parts.push_back(std::move(value.interpolable_value));
277 }
278
279 auto interpolable_list = std::make_unique<InterpolableList>(types.size());
280 wtf_size_t interpolable_list_index = 0;
281 for (auto& part : interpolable_parts) {
282 auto& list = To<InterpolableList>(*part);
283 for (wtf_size_t i = 0; i < list.length(); ++i) {
284 interpolable_list->Set(interpolable_list_index,
285 std::move(list.GetMutable(i)));
286 ++interpolable_list_index;
287 }
288 }
289
290 return InterpolationValue(std::move(interpolable_list),
291 SVGTransformNonInterpolableValue::Create(types));
292 }
293
AppliedSVGValue(const InterpolableValue & interpolable_value,const NonInterpolableValue * non_interpolable_value) const294 SVGPropertyBase* SVGTransformListInterpolationType::AppliedSVGValue(
295 const InterpolableValue& interpolable_value,
296 const NonInterpolableValue* non_interpolable_value) const {
297 auto* result = MakeGarbageCollected<SVGTransformList>();
298 const auto& list = To<InterpolableList>(interpolable_value);
299 const Vector<SVGTransformType>& transform_types =
300 To<SVGTransformNonInterpolableValue>(non_interpolable_value)
301 ->TransformTypes();
302 for (wtf_size_t i = 0; i < list.length(); ++i)
303 result->Append(FromInterpolableValue(*list.Get(i), transform_types.at(i)));
304 return result;
305 }
306
MaybeMergeSingles(InterpolationValue && start,InterpolationValue && end) const307 PairwiseInterpolationValue SVGTransformListInterpolationType::MaybeMergeSingles(
308 InterpolationValue&& start,
309 InterpolationValue&& end) const {
310 if (GetTransformTypes(start) != GetTransformTypes(end))
311 return nullptr;
312
313 return PairwiseInterpolationValue(std::move(start.interpolable_value),
314 std::move(end.interpolable_value),
315 std::move(end.non_interpolable_value));
316 }
317
Composite(UnderlyingValueOwner & underlying_value_owner,double underlying_fraction,const InterpolationValue & value,double interpolation_fraction) const318 void SVGTransformListInterpolationType::Composite(
319 UnderlyingValueOwner& underlying_value_owner,
320 double underlying_fraction,
321 const InterpolationValue& value,
322 double interpolation_fraction) const {
323 underlying_value_owner.Set(*this, value);
324 }
325
326 } // namespace blink
327