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