source: trunk/Source/WebCore/svg/SVGAnimateElement.cpp @ 110838

Revision 110838, 10.9 KB checked in by zimmermann@webkit.org, 3 years ago (diff)

Enable animVal support for SVGTransformList
https://bugs.webkit.org/show_bug.cgi?id=80758

Reviewed by Antti Koivisto.

Source/WebCore:

Enable animVal support for SVGTransformList. SVGTransformLists are only animatable
via <animateTransform>, not via <animate> directly. Still we can handle it in the
same framework as all other types used for <animate>, as we also need proper animVal
support for <animateTransform>.

This patch removes the special <animateTransform> implementation, and lets
SVGAnimateTransformElement inherit from SVGAnimateElement, just like its done
for SVGAnimateColorElement & SVGSetElement.

All existing code (calculateFromAndToValues/FromAndByValues/etc..) are moved from
SVGAnimateTransform right into the SVGAnimatedTransformListAnimator.

This doesn't change <animateTransform> behavior, it just simplies the code
and enables animVal support for SVGTransformLists - all covered by existing tests.

  • CMakeLists.txt:
  • GNUmakefile.list.am:
  • Target.pri:
  • WebCore.gypi:
  • WebCore.xcodeproj/project.pbxproj:
  • svg/SVGAllInOne.cpp:
  • svg/SVGAnimateElement.cpp:

(WebCore::SVGAnimateElement::SVGAnimateElement):
(WebCore::SVGAnimateElement::determineAnimatedPropertyType):
(WebCore::SVGAnimateElement::calculateAnimatedValue):
(WebCore::SVGAnimateElement::applyResultsToTarget):

  • svg/SVGAnimateTransformElement.cpp:

(WebCore::SVGAnimateTransformElement::SVGAnimateTransformElement):
(WebCore::SVGAnimateTransformElement::hasValidAttributeType):
(WebCore::SVGAnimateTransformElement::parseAttribute):

  • svg/SVGAnimateTransformElement.h:

(WebCore::SVGAnimateTransformElement::transformType):
(SVGAnimateTransformElement):

  • svg/SVGAnimatedTransformList.cpp: Added.

(WebCore):
(WebCore::SVGAnimatedTransformListAnimator::SVGAnimatedTransformListAnimator):
(WebCore::SVGAnimatedTransformListAnimator::constructFromString):
(WebCore::SVGAnimatedTransformListAnimator::constructFromCopy):
(WebCore::SVGAnimatedTransformListAnimator::calculateFromAndToValues):
(WebCore::SVGAnimatedTransformListAnimator::calculateFromAndByValues):
(WebCore::SVGAnimatedTransformListAnimator::calculateAnimatedValue):
(WebCore::SVGAnimatedTransformListAnimator::calculateDistance):

  • svg/SVGAnimatedTransformList.h:

(WebCore):
(SVGAnimatedTransformListAnimator):
(WebCore::SVGAnimatedTransformListAnimator::~SVGAnimatedTransformListAnimator):

  • svg/SVGAnimatedType.cpp:

(WebCore::SVGAnimatedType::~SVGAnimatedType):
(WebCore::SVGAnimatedType::createTransformList):
(WebCore):
(WebCore::SVGAnimatedType::transformList):
(WebCore::SVGAnimatedType::valueAsString):
(WebCore::SVGAnimatedType::setValueAsString):
(WebCore::SVGAnimatedType::supportsAnimVal):
(WebCore::SVGAnimatedType::setVariantValue):

  • svg/SVGAnimatedType.h:

(WebCore):
(SVGAnimatedType):

  • svg/SVGAnimatorFactory.h:

(WebCore::SVGAnimatorFactory::create):

  • svg/SVGGradientElement.cpp:

(WebCore::SVGGradientElement::parseAttribute):

  • svg/SVGPatternElement.cpp:

(WebCore::SVGPatternElement::parseAttribute):

  • svg/SVGStyledTransformableElement.cpp:

(WebCore::SVGStyledTransformableElement::parseAttribute):

  • svg/SVGTextElement.cpp:

(WebCore::SVGTextElement::parseAttribute):

  • svg/SVGTransform.cpp:

(WebCore::SVGTransform::transformTypePrefixForParsing):
(WebCore):
(WebCore::SVGTransform::valueAsString):

  • svg/SVGTransform.h:

(SVGTransform):

  • svg/SVGTransformList.cpp:

(WebCore::SVGTransformList::parse):
(WebCore):

  • svg/SVGTransformList.h:

(SVGTransformList):

  • svg/SVGTransformable.cpp:

(WebCore::SVGTransformable::parseTransformType):

  • svg/SVGTransformable.h:

(WebCore):

  • svg/SVGViewSpec.cpp:

(WebCore::SVGViewSpec::setTransform):

LayoutTests:

Rebaseline tests after enabling animVal support SVGAnimateTransformElement/SVGTransformList.

  • svg/animations/animate-gradient-transform-expected.txt:
  • svg/animations/animateTransform-pattern-transform-expected.txt:
  • svg/animations/script-tests/animate-gradient-transform.js:

(sample1):
(sample2):
(sample3):
(executeTest):

  • svg/animations/script-tests/animateTransform-pattern-transform.js:

(sample1):
(sample2):
(sample3):
(sample4):
(executeTest):

  • Property svn:eol-style set to native
Line 
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 "config.h"
24
25#if ENABLE(SVG)
26#include "SVGAnimateElement.h"
27
28#include "CSSComputedStyleDeclaration.h"
29#include "CSSParser.h"
30#include "CSSPropertyNames.h"
31#include "QualifiedName.h"
32#include "RenderObject.h"
33#include "SVGAnimatorFactory.h"
34#include "SVGNames.h"
35#include "SVGStyledElement.h"
36
37namespace WebCore {
38
39SVGAnimateElement::SVGAnimateElement(const QualifiedName& tagName, Document* document)
40    : SVGAnimationElement(tagName, document)
41    , m_animatedPropertyType(AnimatedString)
42    , m_fromPropertyValueType(RegularPropertyValue)
43    , m_toPropertyValueType(RegularPropertyValue)
44    , m_animatedProperty(0)
45{
46    ASSERT(hasTagName(SVGNames::animateTag) || hasTagName(SVGNames::setTag) || hasTagName(SVGNames::animateColorTag) || hasTagName(SVGNames::animateTransformTag));
47}
48
49PassRefPtr<SVGAnimateElement> SVGAnimateElement::create(const QualifiedName& tagName, Document* document)
50{
51    return adoptRef(new SVGAnimateElement(tagName, document));
52}
53
54SVGAnimateElement::~SVGAnimateElement()
55{
56}
57
58static inline void getPropertyValue(SVGElement* svgParent, const QualifiedName& attributeName, String& value)
59{
60    ASSERT(svgParent->isStyled());
61    value = CSSComputedStyleDeclaration::create(svgParent)->getPropertyValue(cssPropertyID(attributeName.localName()));
62}
63
64static bool inheritsFromProperty(SVGElement* targetElement, const QualifiedName& attributeName, const String& value)
65{
66    ASSERT(targetElement);
67    DEFINE_STATIC_LOCAL(const AtomicString, inherit, ("inherit"));
68   
69    if (value.isEmpty() || value != inherit || !targetElement->isStyled())
70        return false;
71    return SVGStyledElement::isAnimatableCSSProperty(attributeName);
72}
73
74static bool attributeValueIsCurrentColor(const String& value)
75{
76    DEFINE_STATIC_LOCAL(const AtomicString, currentColor, ("currentColor"));
77    return value == currentColor;
78}
79
80void SVGAnimateElement::adjustForCurrentColor(SVGElement* targetElement, Color& color)
81{
82    ASSERT(targetElement);
83
84    if (RenderObject* targetRenderer = targetElement->renderer())
85        color = targetRenderer->style()->visitedDependentColor(CSSPropertyColor);
86    else
87        color = Color();
88}
89
90void SVGAnimateElement::adjustForInheritance(SVGElement* targetElement, const QualifiedName& attributeName, String& value)
91{
92    // FIXME: At the moment the computed style gets returned as a String and needs to get parsed again.
93    // In the future we might want to work with the value type directly to avoid the String parsing.
94    ASSERT(targetElement);
95
96    Element* parent = targetElement->parentElement();
97    if (!parent || !parent->isSVGElement())
98        return;
99
100    SVGElement* svgParent = static_cast<SVGElement*>(parent);
101    if (svgParent->isStyled())
102        getPropertyValue(svgParent, attributeName, value);
103}
104
105bool SVGAnimateElement::hasValidAttributeType()
106{
107    SVGElement* targetElement = this->targetElement();
108    if (!targetElement)
109        return false;
110   
111    return m_animatedPropertyType != AnimatedUnknown;
112}
113
114AnimatedPropertyType SVGAnimateElement::determineAnimatedPropertyType(SVGElement* targetElement) const
115{
116    ASSERT(targetElement);
117
118    Vector<AnimatedPropertyType> propertyTypes;
119    targetElement->animatedPropertyTypeForAttribute(attributeName(), propertyTypes);
120    if (propertyTypes.isEmpty())
121        return AnimatedUnknown;
122
123    AnimatedPropertyType type = propertyTypes[0];
124    if (hasTagName(SVGNames::animateColorTag) && type != AnimatedColor)
125        return AnimatedUnknown;
126
127    // FIXME: Animator for AnimatedEnumeration missing. Falling back to String animation.
128    if (type == AnimatedEnumeration)
129        return AnimatedString;
130
131    // Animations of transform lists are not allowed for <animate> or <set>
132    // http://www.w3.org/TR/SVG/animate.html#AnimationAttributesAndProperties
133    if (type == AnimatedTransformList && !hasTagName(SVGNames::animateTransformTag))
134        return AnimatedUnknown;
135
136    return type;
137}
138
139void SVGAnimateElement::determinePropertyValueTypes(const String& from, const String& to)
140{
141    SVGElement* targetElement = this->targetElement();
142    ASSERT(targetElement);
143
144    if (inheritsFromProperty(targetElement, attributeName(), from))
145        m_fromPropertyValueType = InheritValue;
146    if (inheritsFromProperty(targetElement, attributeName(), to))
147        m_toPropertyValueType = InheritValue;
148
149    if (m_animatedPropertyType != AnimatedColor)
150        return;
151   
152    if (attributeValueIsCurrentColor(from))
153        m_fromPropertyValueType = CurrentColorValue;
154    if (attributeValueIsCurrentColor(to))
155        m_toPropertyValueType = CurrentColorValue;
156}
157
158void SVGAnimateElement::calculateAnimatedValue(float percentage, unsigned repeat, SVGSMILElement* resultElement)
159{
160    ASSERT(resultElement);
161    SVGElement* targetElement = this->targetElement();
162    if (!targetElement)
163        return;
164
165    ASSERT(m_animatedPropertyType == determineAnimatedPropertyType(targetElement));
166
167    ASSERT(percentage >= 0 && percentage <= 1);
168    ASSERT(m_animatedPropertyType != AnimatedEnumeration);
169    ASSERT(m_animatedPropertyType != AnimatedTransformList || hasTagName(SVGNames::animateTransformTag));
170    ASSERT(m_animatedPropertyType != AnimatedUnknown);
171    ASSERT(m_animator);
172    ASSERT(m_animator->type() == m_animatedPropertyType);
173    ASSERT(m_fromType);
174    ASSERT(m_fromType->type() == m_animatedPropertyType);
175    ASSERT(m_toType);
176
177    ASSERT(resultElement->hasTagName(SVGNames::animateTag)
178        || resultElement->hasTagName(SVGNames::animateColorTag)
179        || resultElement->hasTagName(SVGNames::animateTransformTag)
180        || resultElement->hasTagName(SVGNames::setTag));
181
182    SVGAnimateElement* resultAnimationElement = static_cast<SVGAnimateElement*>(resultElement);
183    ASSERT(resultAnimationElement->m_animatedType);
184    ASSERT(resultAnimationElement->m_animatedPropertyType == m_animatedPropertyType);
185
186    if (hasTagName(SVGNames::setTag))
187        percentage = 1;
188
189    // Target element might have changed.
190    m_animator->setContextElement(targetElement);
191
192    // Be sure to detach list wrappers before we modfiy their underlying value. If we'd do
193    // if after calculateAnimatedValue() ran the cached pointers in the list propery tear
194    // offs would point nowhere, and we couldn't create copies of those values anymore,
195    // while detaching. This is covered by assertions, moving this down would fire them.
196    if (SVGAnimatedProperty* animatedProperty = animatedPropertyForType(m_animator->type()))
197        animatedProperty->animationValueWillChange();
198
199    m_animator->calculateAnimatedValue(percentage, repeat, m_fromType, m_toType, resultAnimationElement->m_animatedType);
200}
201
202bool SVGAnimateElement::calculateFromAndToValues(const String& fromString, const String& toString)
203{
204    SVGElement* targetElement = this->targetElement();
205    if (!targetElement)
206        return false;
207
208    ensureAnimator()->calculateFromAndToValues(m_fromType, m_toType, fromString, toString);
209    ASSERT(m_animatedPropertyType == m_animator->type());
210    return true;
211}
212
213bool SVGAnimateElement::calculateFromAndByValues(const String& fromString, const String& byString)
214{
215    SVGElement* targetElement = this->targetElement();
216    if (!targetElement)
217        return false;
218
219    ASSERT(!hasTagName(SVGNames::setTag));
220
221    ensureAnimator()->calculateFromAndByValues(m_fromType, m_toType, fromString, byString);
222    ASSERT(m_animatedPropertyType == m_animator->type());
223    return true;
224}
225
226void SVGAnimateElement::resetToBaseValue(const String& baseString)
227{
228    // If animatedProperty is not null, we're dealing with a SVG DOM primitive animation.
229    // In that case we don't need any base value strings, but can directly operate on these
230    // SVG DOM primitives, like SVGLength.
231    SVGAnimatedTypeAnimator* animator = ensureAnimator();
232    m_animatedProperty = animatedPropertyForType(animator->type());
233    if (m_animatedProperty) {
234        if (!m_animatedType) {
235            m_animatedType = animator->constructFromCopy(m_animatedProperty->currentBaseValue(animator->type()));
236            animationStarted(m_animatedProperty, m_animatedType.get());
237        } else
238            m_animatedType->setVariantValue(m_animatedProperty->currentBaseValue(m_animator->type()));
239        ASSERT(m_animatedPropertyType == animator->type());
240        ASSERT(m_animatedPropertyType == m_animatedProperty->animatedPropertyType());
241        return;
242    }
243
244    if (!m_animatedType)
245        m_animatedType = animator->constructFromString(baseString);
246    else
247        m_animatedType->setValueAsString(attributeName(), baseString);
248    ASSERT(m_animatedPropertyType == animator->type());
249}
250
251void SVGAnimateElement::applyResultsToTarget()
252{
253    ASSERT(m_animatedPropertyType != AnimatedEnumeration);
254    ASSERT(m_animatedPropertyType != AnimatedTransformList || hasTagName(SVGNames::animateTransformTag));
255    ASSERT(m_animatedPropertyType != AnimatedUnknown);
256    ASSERT(m_animatedType);
257    setTargetAttributeAnimatedValue(m_animatedType.get());
258}
259   
260float SVGAnimateElement::calculateDistance(const String& fromString, const String& toString)
261{
262    // FIXME: A return value of float is not enough to support paced animations on lists.
263    SVGElement* targetElement = this->targetElement();
264    if (!targetElement)
265        return -1;
266
267    return ensureAnimator()->calculateDistance(fromString, toString);
268}
269
270void SVGAnimateElement::targetElementWillChange(SVGElement* currentTarget, SVGElement* newTarget)
271{
272    SVGSMILElement::targetElementWillChange(currentTarget, newTarget);
273
274    if (m_animatedProperty) {
275        animationEnded(m_animatedProperty);
276        m_animatedProperty = 0;
277    }
278
279    m_animatedType.clear();
280    m_fromType.clear();
281    m_toType.clear();
282    m_animator.clear();
283    m_animatedPropertyType = newTarget ? determineAnimatedPropertyType(newTarget) : AnimatedString;
284}
285
286SVGAnimatedTypeAnimator* SVGAnimateElement::ensureAnimator()
287{
288    if (!m_animator)
289        m_animator = SVGAnimatorFactory::create(this, targetElement(), m_animatedPropertyType);
290    ASSERT(m_animatedPropertyType == m_animator->type());
291    return m_animator.get();
292}
293
294}
295
296#endif // ENABLE(SVG)
Note: See TracBrowser for help on using the repository browser.