1 /*
2 * Copyright (C) 2004, 2005 Nikolas Zimmermann <zimmermann@kde.org>
3 * Copyright (C) 2004, 2005, 2006 Rob Buis <buis@kde.org>
4 * Copyright (C) 2008 Apple Inc. All rights reserved.
5 * Copyright (C) Research In Motion Limited 2011. All rights reserved.
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Library General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Library General Public License for more details.
16 *
17 * You should have received a copy of the GNU Library General Public License
18 * along with this library; see the file COPYING.LIB. If not, write to
19 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20 * Boston, MA 02110-1301, USA.
21 */
22
23 #include "third_party/blink/renderer/core/svg/svg_animate_element.h"
24
25 #include "third_party/blink/renderer/core/css/css_computed_style_declaration.h"
26 #include "third_party/blink/renderer/core/css/css_property_value_set.h"
27 #include "third_party/blink/renderer/core/css/css_style_sheet.h"
28 #include "third_party/blink/renderer/core/css/style_change_reason.h"
29 #include "third_party/blink/renderer/core/dom/document.h"
30 #include "third_party/blink/renderer/core/dom/qualified_name.h"
31 #include "third_party/blink/renderer/core/svg/properties/svg_animated_property.h"
32 #include "third_party/blink/renderer/core/svg/properties/svg_property.h"
33 #include "third_party/blink/renderer/core/svg/svg_animated_color.h"
34 #include "third_party/blink/renderer/core/svg/svg_length.h"
35 #include "third_party/blink/renderer/core/svg/svg_length_list.h"
36 #include "third_party/blink/renderer/core/svg/svg_number.h"
37 #include "third_party/blink/renderer/core/svg/svg_string.h"
38 #include "third_party/blink/renderer/core/xlink_names.h"
39 #include "third_party/blink/renderer/platform/heap/heap.h"
40
41 namespace blink {
42
43 namespace {
44
IsTargetAttributeCSSProperty(const SVGElement & target_element,const QualifiedName & attribute_name)45 bool IsTargetAttributeCSSProperty(const SVGElement& target_element,
46 const QualifiedName& attribute_name) {
47 return SVGElement::IsAnimatableCSSProperty(attribute_name) ||
48 target_element.IsPresentationAttribute(attribute_name);
49 }
50
ComputeCSSPropertyValue(SVGElement * element,CSSPropertyID id)51 String ComputeCSSPropertyValue(SVGElement* element, CSSPropertyID id) {
52 DCHECK(element);
53 // TODO(fs): StyleEngine doesn't support document without a frame.
54 // Refer to comment in Element::computedStyle.
55 DCHECK(element->InActiveDocument());
56
57 // Don't include any properties resulting from CSS Transitions/Animations or
58 // SMIL animations, as we want to retrieve the "base value".
59 element->SetUseOverrideComputedStyle(true);
60 String value = MakeGarbageCollected<CSSComputedStyleDeclaration>(element)
61 ->GetPropertyValue(id);
62 element->SetUseOverrideComputedStyle(false);
63 return value;
64 }
65
PropertyValueType(const QualifiedName & attribute_name,const String & value)66 AnimatedPropertyValueType PropertyValueType(const QualifiedName& attribute_name,
67 const String& value) {
68 DEFINE_STATIC_LOCAL(const AtomicString, inherit, ("inherit"));
69 if (value.IsEmpty() || value != inherit ||
70 !SVGElement::IsAnimatableCSSProperty(attribute_name))
71 return kRegularPropertyValue;
72 return kInheritValue;
73 }
74
ConstructQualifiedName(const SVGElement & svg_element,const AtomicString & attribute_name)75 QualifiedName ConstructQualifiedName(const SVGElement& svg_element,
76 const AtomicString& attribute_name) {
77 if (attribute_name.IsEmpty())
78 return AnyQName();
79 if (!attribute_name.Contains(':'))
80 return QualifiedName(g_null_atom, attribute_name, g_null_atom);
81
82 AtomicString prefix;
83 AtomicString local_name;
84 if (!Document::ParseQualifiedName(attribute_name, prefix, local_name,
85 IGNORE_EXCEPTION_FOR_TESTING))
86 return AnyQName();
87
88 const AtomicString& namespace_uri = svg_element.lookupNamespaceURI(prefix);
89 if (namespace_uri.IsEmpty())
90 return AnyQName();
91
92 QualifiedName resolved_attr_name(g_null_atom, local_name, namespace_uri);
93 // "Animation elements treat attributeName='xlink:href' as being an alias
94 // for targetting the 'href' attribute."
95 // https://svgwg.org/svg2-draft/types.html#__svg__SVGURIReference__href
96 if (resolved_attr_name == xlink_names::kHrefAttr)
97 return svg_names::kHrefAttr;
98 return resolved_attr_name;
99 }
100
101 } // unnamed namespace
102
SVGAnimateElement(Document & document)103 SVGAnimateElement::SVGAnimateElement(Document& document)
104 : SVGAnimateElement(svg_names::kAnimateTag, document) {}
105
SVGAnimateElement(const QualifiedName & tag_name,Document & document)106 SVGAnimateElement::SVGAnimateElement(const QualifiedName& tag_name,
107 Document& document)
108 : SVGAnimationElement(tag_name, document),
109 attribute_name_(AnyQName()),
110 type_(kAnimatedUnknown),
111 css_property_id_(CSSPropertyID::kInvalid),
112 from_property_value_type_(kRegularPropertyValue),
113 to_property_value_type_(kRegularPropertyValue),
114 attribute_type_(kAttributeTypeAuto) {}
115
116 SVGAnimateElement::~SVGAnimateElement() = default;
117
IsSVGAnimationAttributeSettingJavaScriptURL(const Attribute & attribute) const118 bool SVGAnimateElement::IsSVGAnimationAttributeSettingJavaScriptURL(
119 const Attribute& attribute) const {
120 if ((attribute.GetName() == svg_names::kFromAttr ||
121 attribute.GetName() == svg_names::kToAttr) &&
122 AttributeValueIsJavaScriptURL(attribute))
123 return true;
124
125 if (attribute.GetName() == svg_names::kValuesAttr) {
126 Vector<String> parts;
127 if (!ParseValues(attribute.Value(), parts)) {
128 // Assume the worst.
129 return true;
130 }
131 for (const auto& part : parts) {
132 if (ProtocolIsJavaScript(part))
133 return true;
134 }
135 }
136
137 return SVGSMILElement::IsSVGAnimationAttributeSettingJavaScriptURL(attribute);
138 }
139
InsertedInto(ContainerNode & root_parent)140 Node::InsertionNotificationRequest SVGAnimateElement::InsertedInto(
141 ContainerNode& root_parent) {
142 SVGAnimationElement::InsertedInto(root_parent);
143 if (root_parent.isConnected()) {
144 SetAttributeName(ConstructQualifiedName(
145 *this, FastGetAttribute(svg_names::kAttributeNameAttr)));
146 }
147 return kInsertionDone;
148 }
149
RemovedFrom(ContainerNode & root_parent)150 void SVGAnimateElement::RemovedFrom(ContainerNode& root_parent) {
151 if (root_parent.isConnected())
152 SetAttributeName(AnyQName());
153 SVGAnimationElement::RemovedFrom(root_parent);
154 }
155
ParseAttribute(const AttributeModificationParams & params)156 void SVGAnimateElement::ParseAttribute(
157 const AttributeModificationParams& params) {
158 if (params.name == svg_names::kAttributeTypeAttr) {
159 SetAttributeType(params.new_value);
160 return;
161 }
162 if (params.name == svg_names::kAttributeNameAttr) {
163 SetAttributeName(ConstructQualifiedName(*this, params.new_value));
164 return;
165 }
166 SVGAnimationElement::ParseAttribute(params);
167 }
168
ResolveTargetProperty()169 void SVGAnimateElement::ResolveTargetProperty() {
170 DCHECK(targetElement());
171 target_property_ = targetElement()->PropertyFromAttribute(AttributeName());
172 if (target_property_) {
173 type_ = target_property_->GetType();
174 css_property_id_ = target_property_->CssPropertyId();
175
176 // Only <animateTransform> is allowed to animate AnimatedTransformList.
177 // http://www.w3.org/TR/SVG/animate.html#AnimationAttributesAndProperties
178 if (type_ == kAnimatedTransformList) {
179 type_ = kAnimatedUnknown;
180 css_property_id_ = CSSPropertyID::kInvalid;
181 }
182 } else {
183 type_ = SVGElement::AnimatedPropertyTypeForCSSAttribute(AttributeName());
184 css_property_id_ =
185 type_ != kAnimatedUnknown
186 ? cssPropertyID(targetElement()->GetDocument().ToExecutionContext(),
187 AttributeName().LocalName())
188 : CSSPropertyID::kInvalid;
189 }
190 // Blacklist <script> targets here for now to prevent unpleasantries. This
191 // also disallows the perfectly "valid" animation of 'className' on said
192 // element. If SVGScriptElement.href is transitioned off of SVGAnimatedHref,
193 // this can be removed.
194 if (IsA<SVGScriptElement>(*targetElement())) {
195 type_ = kAnimatedUnknown;
196 css_property_id_ = CSSPropertyID::kInvalid;
197 }
198 DCHECK(type_ != kAnimatedPoint && type_ != kAnimatedStringList &&
199 type_ != kAnimatedTransform && type_ != kAnimatedTransformList);
200 }
201
ClearTargetProperty()202 void SVGAnimateElement::ClearTargetProperty() {
203 target_property_ = nullptr;
204 type_ = kAnimatedUnknown;
205 css_property_id_ = CSSPropertyID::kInvalid;
206 }
207
UpdateTargetProperty()208 void SVGAnimateElement::UpdateTargetProperty() {
209 if (SVGElement* target = targetElement())
210 ResolveTargetProperty();
211 else
212 ClearTargetProperty();
213 }
214
GetAnimatedPropertyType() const215 AnimatedPropertyType SVGAnimateElement::GetAnimatedPropertyType() const {
216 // TODO(fs): Should be possible to DCHECK targetElement() here instead.
217 return !targetElement() ? kAnimatedUnknown : type_;
218 }
219
HasValidAnimation() const220 bool SVGAnimateElement::HasValidAnimation() const {
221 if (AttributeName() == AnyQName())
222 return false;
223 if (type_ == kAnimatedUnknown)
224 return false;
225 // Always animate CSS properties using the ApplyCSSAnimation code path,
226 // regardless of the attributeType value.
227 // If attributeType="CSS" and attributeName doesn't point to a CSS property,
228 // ignore the animation.
229 return IsTargetAttributeCSSProperty(*targetElement(), AttributeName()) ||
230 GetAttributeType() != kAttributeTypeCSS;
231 }
232
CreatePropertyForAttributeAnimation(const String & value) const233 SVGPropertyBase* SVGAnimateElement::CreatePropertyForAttributeAnimation(
234 const String& value) const {
235 // SVG DOM animVal animation code-path.
236 // TransformList must be animated via <animateTransform>, and its
237 // {from,by,to} attribute values needs to be parsed w.r.t. its "type"
238 // attribute. Spec:
239 // http://www.w3.org/TR/SVG/single-page.html#animate-AnimateTransformElement
240 DCHECK_NE(type_, kAnimatedTransformList);
241 DCHECK(target_property_);
242 return target_property_->CurrentValueBase()->CloneForAnimation(value);
243 }
244
CreatePropertyForCSSAnimation(const String & value) const245 SVGPropertyBase* SVGAnimateElement::CreatePropertyForCSSAnimation(
246 const String& value) const {
247 // CSS properties animation code-path.
248 // Create a basic instance of the corresponding SVG property.
249 // The instance will not have full context info. (e.g. SVGLengthMode)
250 switch (type_) {
251 case kAnimatedColor:
252 return MakeGarbageCollected<SVGColorProperty>(value);
253 case kAnimatedNumber: {
254 auto* property = MakeGarbageCollected<SVGNumber>();
255 property->SetValueAsString(value);
256 return property;
257 }
258 case kAnimatedLength: {
259 auto* property = MakeGarbageCollected<SVGLength>();
260 property->SetValueAsString(value);
261 return property;
262 }
263 case kAnimatedLengthList: {
264 auto* property = MakeGarbageCollected<SVGLengthList>();
265 property->SetValueAsString(value);
266 return property;
267 }
268 case kAnimatedString: {
269 auto* property = MakeGarbageCollected<SVGString>();
270 property->SetValueAsString(value);
271 return property;
272 }
273 // These types don't appear in the table in
274 // SVGElement::animatedPropertyTypeForCSSAttribute() and thus don't need
275 // support.
276 case kAnimatedAngle:
277 case kAnimatedBoolean:
278 case kAnimatedEnumeration:
279 case kAnimatedInteger:
280 case kAnimatedIntegerOptionalInteger:
281 case kAnimatedNumberList:
282 case kAnimatedNumberOptionalNumber:
283 case kAnimatedPath:
284 case kAnimatedPoint:
285 case kAnimatedPoints:
286 case kAnimatedPreserveAspectRatio:
287 case kAnimatedRect:
288 case kAnimatedStringList:
289 case kAnimatedTransform:
290 case kAnimatedTransformList:
291 case kAnimatedUnknown:
292 break;
293 default:
294 break;
295 }
296 NOTREACHED();
297 return nullptr;
298 }
299
CreatePropertyForAnimation(const String & value) const300 SVGPropertyBase* SVGAnimateElement::CreatePropertyForAnimation(
301 const String& value) const {
302 if (IsAnimatingSVGDom())
303 return CreatePropertyForAttributeAnimation(value);
304 DCHECK(IsAnimatingCSSProperty());
305 return CreatePropertyForCSSAnimation(value);
306 }
307
AdjustForInheritance(SVGPropertyBase * property_value,AnimatedPropertyValueType value_type) const308 SVGPropertyBase* SVGAnimateElement::AdjustForInheritance(
309 SVGPropertyBase* property_value,
310 AnimatedPropertyValueType value_type) const {
311 if (value_type != kInheritValue)
312 return property_value;
313 // TODO(fs): At the moment the computed style gets returned as a String and
314 // needs to get parsed again. In the future we might want to work with the
315 // value type directly to avoid the String parsing.
316 DCHECK(targetElement());
317 Element* parent = targetElement()->parentElement();
318 auto* svg_parent = DynamicTo<SVGElement>(parent);
319 if (!svg_parent)
320 return property_value;
321 // Replace 'inherit' by its computed property value.
322 String value = ComputeCSSPropertyValue(svg_parent, css_property_id_);
323 return CreatePropertyForAnimation(value);
324 }
325
DiscreteSelectValue(AnimationMode animation_mode,float percentage,SVGPropertyBase * from,SVGPropertyBase * to)326 static SVGPropertyBase* DiscreteSelectValue(AnimationMode animation_mode,
327 float percentage,
328 SVGPropertyBase* from,
329 SVGPropertyBase* to) {
330 if ((animation_mode == kFromToAnimation && percentage > 0.5) ||
331 animation_mode == kToAnimation || percentage == 1) {
332 return to;
333 }
334 return from;
335 }
336
CalculateAnimatedValue(float percentage,unsigned repeat_count,SVGSMILElement * result_element) const337 void SVGAnimateElement::CalculateAnimatedValue(
338 float percentage,
339 unsigned repeat_count,
340 SVGSMILElement* result_element) const {
341 DCHECK(result_element);
342 DCHECK(targetElement());
343 if (!IsSVGAnimateElement(*result_element))
344 return;
345
346 DCHECK(percentage >= 0 && percentage <= 1);
347 DCHECK_NE(GetAnimatedPropertyType(), kAnimatedUnknown);
348 DCHECK(from_property_);
349 DCHECK_EQ(from_property_->GetType(), GetAnimatedPropertyType());
350 DCHECK(to_property_);
351
352 auto* result_animation_element = To<SVGAnimateElement>(result_element);
353 DCHECK(result_animation_element->animated_value_);
354 DCHECK_EQ(result_animation_element->GetAnimatedPropertyType(),
355 GetAnimatedPropertyType());
356
357 if (IsA<SVGSetElement>(*this))
358 percentage = 1;
359
360 if (GetCalcMode() == kCalcModeDiscrete)
361 percentage = percentage < 0.5 ? 0 : 1;
362
363 // Target element might have changed.
364 SVGElement* target_element = targetElement();
365
366 // Values-animation accumulates using the last values entry corresponding to
367 // the end of duration time.
368 SVGPropertyBase* animated_value = result_animation_element->animated_value_;
369 SVGPropertyBase* to_at_end_of_duration_value =
370 to_at_end_of_duration_property_ ? to_at_end_of_duration_property_
371 : to_property_;
372 SVGPropertyBase* from_value = GetAnimationMode() == kToAnimation
373 ? animated_value
374 : from_property_.Get();
375 SVGPropertyBase* to_value = to_property_;
376
377 // Apply CSS inheritance rules.
378 from_value = AdjustForInheritance(from_value, from_property_value_type_);
379 to_value = AdjustForInheritance(to_value, to_property_value_type_);
380
381 // If the animated type can only be animated discretely, then do that here,
382 // replacing |result_element|s animated value.
383 if (!AnimatedPropertyTypeSupportsAddition()) {
384 result_animation_element->animated_value_ = DiscreteSelectValue(
385 GetAnimationMode(), percentage, from_value, to_value);
386 return;
387 }
388
389 animated_value->CalculateAnimatedValue(
390 *this, percentage, repeat_count, from_value, to_value,
391 to_at_end_of_duration_value, target_element);
392 }
393
CalculateToAtEndOfDurationValue(const String & to_at_end_of_duration_string)394 bool SVGAnimateElement::CalculateToAtEndOfDurationValue(
395 const String& to_at_end_of_duration_string) {
396 if (to_at_end_of_duration_string.IsEmpty())
397 return false;
398 to_at_end_of_duration_property_ =
399 CreatePropertyForAnimation(to_at_end_of_duration_string);
400 return true;
401 }
402
CalculateFromAndToValues(const String & from_string,const String & to_string)403 bool SVGAnimateElement::CalculateFromAndToValues(const String& from_string,
404 const String& to_string) {
405 DCHECK(targetElement());
406 from_property_ = CreatePropertyForAnimation(from_string);
407 from_property_value_type_ = PropertyValueType(AttributeName(), from_string);
408 to_property_ = CreatePropertyForAnimation(to_string);
409 to_property_value_type_ = PropertyValueType(AttributeName(), to_string);
410 return true;
411 }
412
CalculateFromAndByValues(const String & from_string,const String & by_string)413 bool SVGAnimateElement::CalculateFromAndByValues(const String& from_string,
414 const String& by_string) {
415 DCHECK(targetElement());
416
417 if (GetAnimationMode() == kByAnimation && !IsAdditive())
418 return false;
419
420 // from-by animation may only be used with attributes that support addition
421 // (e.g. most numeric attributes).
422 if (GetAnimationMode() == kFromByAnimation &&
423 !AnimatedPropertyTypeSupportsAddition())
424 return false;
425
426 DCHECK(!IsA<SVGSetElement>(*this));
427
428 from_property_ = CreatePropertyForAnimation(from_string);
429 from_property_value_type_ = PropertyValueType(AttributeName(), from_string);
430 to_property_ = CreatePropertyForAnimation(by_string);
431 to_property_value_type_ = PropertyValueType(AttributeName(), by_string);
432 to_property_->Add(from_property_, targetElement());
433 return true;
434 }
435
ResetAnimatedType()436 void SVGAnimateElement::ResetAnimatedType() {
437 DCHECK(targetElement());
438 if (IsAnimatingSVGDom()) {
439 // SVG DOM animVal animation code-path.
440 animated_value_ = target_property_->CreateAnimatedValue();
441 DCHECK_EQ(animated_value_->GetType(), type_);
442 return;
443 }
444 DCHECK(IsAnimatingCSSProperty());
445 // Presentation attributes which has an SVG DOM representation should use the
446 // "SVG DOM" code-path (above.)
447 DCHECK(SVGElement::IsAnimatableCSSProperty(AttributeName()));
448
449 // CSS properties animation code-path.
450 String base_value =
451 ComputeCSSPropertyValue(targetElement(), css_property_id_);
452 animated_value_ = CreatePropertyForAnimation(base_value);
453 }
454
ClearAnimatedType()455 void SVGAnimateElement::ClearAnimatedType() {
456 SVGElement* target_element = targetElement();
457 DCHECK(target_element);
458
459 // CSS properties animation code-path.
460 if (IsAnimatingCSSProperty()) {
461 MutableCSSPropertyValueSet* property_set =
462 target_element->EnsureAnimatedSMILStyleProperties();
463 if (property_set->RemoveProperty(css_property_id_)) {
464 target_element->SetNeedsStyleRecalc(
465 kLocalStyleChange,
466 StyleChangeReasonForTracing::Create(style_change_reason::kAnimation));
467 }
468 }
469 // SVG DOM animVal animation code-path.
470 if (IsAnimatingSVGDom())
471 target_element->ClearAnimatedAttribute(AttributeName());
472
473 animated_value_.Clear();
474 }
475
ApplyResultsToTarget()476 void SVGAnimateElement::ApplyResultsToTarget() {
477 DCHECK_NE(GetAnimatedPropertyType(), kAnimatedUnknown);
478 DCHECK(animated_value_);
479 DCHECK(targetElement());
480
481 // We do update the style and the animation property independent of each
482 // other.
483 SVGElement* target_element = targetElement();
484
485 // CSS properties animation code-path.
486 if (IsAnimatingCSSProperty()) {
487 // Convert the result of the animation to a String and apply it as CSS
488 // property on the target_element.
489 MutableCSSPropertyValueSet* properties =
490 target_element->EnsureAnimatedSMILStyleProperties();
491 auto animated_value_string = animated_value_->ValueAsString();
492 auto& document = target_element->GetDocument();
493 auto set_result = properties->SetProperty(
494 css_property_id_, animated_value_string, false,
495 document.GetSecureContextMode(), document.ElementSheet().Contents());
496 if (set_result.did_change) {
497 target_element->SetNeedsStyleRecalc(
498 kLocalStyleChange,
499 StyleChangeReasonForTracing::Create(style_change_reason::kAnimation));
500 }
501 }
502 // SVG DOM animVal animation code-path.
503 if (IsAnimatingSVGDom())
504 target_element->SetAnimatedAttribute(AttributeName(), animated_value_);
505 }
506
AnimatedPropertyTypeSupportsAddition() const507 bool SVGAnimateElement::AnimatedPropertyTypeSupportsAddition() const {
508 // http://www.w3.org/TR/SVG/animate.html#AnimationAttributesAndProperties.
509 switch (GetAnimatedPropertyType()) {
510 case kAnimatedBoolean:
511 case kAnimatedEnumeration:
512 case kAnimatedPreserveAspectRatio:
513 case kAnimatedString:
514 case kAnimatedUnknown:
515 return false;
516 default:
517 return true;
518 }
519 }
520
IsAdditive() const521 bool SVGAnimateElement::IsAdditive() const {
522 if (GetAnimationMode() == kByAnimation ||
523 GetAnimationMode() == kFromByAnimation) {
524 if (!AnimatedPropertyTypeSupportsAddition())
525 return false;
526 }
527
528 return SVGAnimationElement::IsAdditive();
529 }
530
CalculateDistance(const String & from_string,const String & to_string)531 float SVGAnimateElement::CalculateDistance(const String& from_string,
532 const String& to_string) {
533 DCHECK(targetElement());
534 // FIXME: A return value of float is not enough to support paced animations on
535 // lists.
536 SVGPropertyBase* from_value = CreatePropertyForAnimation(from_string);
537 SVGPropertyBase* to_value = CreatePropertyForAnimation(to_string);
538 return from_value->CalculateDistance(to_value, targetElement());
539 }
540
WillChangeAnimatedType()541 void SVGAnimateElement::WillChangeAnimatedType() {
542 UnregisterAnimation(attribute_name_);
543 // Should've been cleared by the above if needed.
544 DCHECK(!animated_value_);
545 from_property_.Clear();
546 to_property_.Clear();
547 to_at_end_of_duration_property_.Clear();
548 }
549
DidChangeAnimatedType()550 void SVGAnimateElement::DidChangeAnimatedType() {
551 UpdateTargetProperty();
552 RegisterAnimation(attribute_name_);
553 }
554
WillChangeAnimationTarget()555 void SVGAnimateElement::WillChangeAnimationTarget() {
556 SVGAnimationElement::WillChangeAnimationTarget();
557 WillChangeAnimatedType();
558 }
559
DidChangeAnimationTarget()560 void SVGAnimateElement::DidChangeAnimationTarget() {
561 DidChangeAnimatedType();
562 SVGAnimationElement::DidChangeAnimationTarget();
563 }
564
SetAttributeName(const QualifiedName & attribute_name)565 void SVGAnimateElement::SetAttributeName(const QualifiedName& attribute_name) {
566 if (attribute_name == attribute_name_)
567 return;
568 WillChangeAnimatedType();
569 attribute_name_ = attribute_name;
570 DidChangeAnimatedType();
571 AnimationAttributeChanged();
572 }
573
SetAttributeType(const AtomicString & attribute_type_string)574 void SVGAnimateElement::SetAttributeType(
575 const AtomicString& attribute_type_string) {
576 AttributeType attribute_type = kAttributeTypeAuto;
577 if (attribute_type_string == "CSS")
578 attribute_type = kAttributeTypeCSS;
579 else if (attribute_type_string == "XML")
580 attribute_type = kAttributeTypeXML;
581 if (attribute_type == attribute_type_)
582 return;
583 WillChangeAnimatedType();
584 attribute_type_ = attribute_type;
585 DidChangeAnimatedType();
586 AnimationAttributeChanged();
587 }
588
Trace(Visitor * visitor)589 void SVGAnimateElement::Trace(Visitor* visitor) {
590 visitor->Trace(from_property_);
591 visitor->Trace(to_property_);
592 visitor->Trace(to_at_end_of_duration_property_);
593 visitor->Trace(animated_value_);
594 visitor->Trace(target_property_);
595 SVGAnimationElement::Trace(visitor);
596 }
597
598 } // namespace blink
599