Changeset 116451 in webkit


Ignore:
Timestamp:
May 8, 2012 12:44:17 PM (12 years ago)
Author:
Nikolas Zimmermann
Message:

Tie lifetime of SVGAnimateElement::m_animatedType to the duration of the animation
https://bugs.webkit.org/show_bug.cgi?id=85627

Reviewed by Antti Koivisto.

Source/WebCore:

Example:
<rect width="10" height="100">

<animate attributeName="width" from="10" to="100" begin="2s" dur="4s" fill="remove"/>

</rect>

At t=0s the <animate> element receives its first interval: begin=2s, end=6s.
At this point we've created the 'OwnPtr<SVGAnimatedType> m_animatedType' in
SVGAnimateElement, which holds the current animated value of the target type.
In this example it contains a SVGLength with '10' as value at t=0s.

Calling "rect.width.animVal.value" will return the value currently contained in the
m_animatedType from the SVGAnimateElement, even though the animation didn't begin
yet. This is fine, as the animVal equals to the baseVal, as long as no animation is
running.

At t=6s you'd expect that the whole 'animVal' object is destructed again, as it's no
longer needed, as animVal will be equal to baseVal again, but the current code keeps
the animVal alive, and just resets it to the baseVal. The animVals will be destructed
once the animate element leaves the tree.

CSS animations suffer from the same problem, we never remove the animated SMIL properties
but we only reset them to the base value. This makes integration with CSS Animations and
CSS Transitions harder, so this needs to be changed.

This patch starts tracking the start/end of an animation chain properly, to destruct
the animation effect for non-frozen animations at the end of their duration. This has to
work properly together with seeking (SVGSVGElement.setCurrentTime), as our testing relies
on the ability to drive the SMIL timeline from script.

Tests: svg/animations/list-wrapper-assertion-expected.svg

svg/animations/list-wrapper-assertion.svg

  • svg/SVGAnimateElement.cpp:

(WebCore::SVGAnimateElement::resetAnimatedType):
(WebCore::applyCSSPropertyToTarget):
(WebCore::removeCSSPropertyFromTarget):
(WebCore::applyCSSPropertyToTargetAndInstances):
(WebCore::removeCSSPropertyFromTargetAndInstances):
(WebCore::notifyTargetAboutAnimValChange):
(WebCore::notifyTargetAndInstancesAboutAnimValChange):
(WebCore::SVGAnimateElement::clearAnimatedType):
(WebCore::SVGAnimateElement::applyResultsToTarget):
(WebCore::SVGAnimateElement::targetElementWillChange):

  • svg/SVGAnimateElement.h:

(SVGAnimateElement):

  • svg/SVGAnimateMotionElement.cpp:

(WebCore::SVGAnimateMotionElement::resetAnimatedType):
(WebCore::SVGAnimateMotionElement::clearAnimatedType):

  • svg/SVGAnimateMotionElement.h:

(SVGAnimateMotionElement):

  • svg/SVGAnimationElement.cpp:
  • svg/SVGAnimationElement.h:
  • svg/animation/SMILTimeContainer.cpp:

(WebCore::SMILTimeContainer::updateAnimations):

  • svg/animation/SVGSMILElement.cpp:

(WebCore::SVGSMILElement::reset):
(WebCore::SVGSMILElement::targetElementWillChange):
(WebCore::SVGSMILElement::determineActiveState):
(WebCore::SVGSMILElement::progress):

  • svg/animation/SVGSMILElement.h:

(SVGSMILElement):

  • svg/properties/SVGAnimatedListPropertyTearOff.h:

Remove svgAttributeChanged() calls from animationEnded/animValDidChange.
Callers are now required to notify the target about changes. There are cases
where we want to call animValDidChange without invoking svgAttributeChanged().
That is supported now.

(WebCore::SVGAnimatedListPropertyTearOff::animationEnded):
(WebCore::SVGAnimatedListPropertyTearOff::animValDidChange):

  • svg/properties/SVGAnimatedProperty.h: Ditto.

(WebCore::SVGAnimatedProperty::commitChange): Add safety guard.

  • svg/properties/SVGAnimatedPropertyTearOff.h: Ditto.

(WebCore::SVGAnimatedPropertyTearOff::animationEnded):
(WebCore::SVGAnimatedPropertyTearOff::animValDidChange):

  • svg/properties/SVGAnimatedStaticPropertyTearOff.h: Ditto.

(WebCore::SVGAnimatedStaticPropertyTearOff::animationEnded):
(WebCore::SVGAnimatedStaticPropertyTearOff::animValDidChange):

LayoutTests:

Update animate-target-id-changed.svg test to match Firefox behavior.
When an animation element with fill="freeze" is changed to a new target
eg, via animate.href = "#someOtherID", the animation effect should be removed.

Add tests for assertions I ran into while developing this patch.

  • platform/chromium/test_expectations.txt: Require new results for animate-target-id-changed-expected.txt.
  • platform/mac/svg/custom/animate-target-id-changed-expected.png:
  • svg/animations/list-wrapper-assertion-expected.svg: Added.
  • svg/animations/list-wrapper-assertion.svg: Added.
  • svg/custom/animate-target-id-changed-expected.txt:
  • svg/custom/animate-target-id-changed.svg:
Location:
trunk
Files:
2 added
19 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r116446 r116451  
     12012-05-04  Nikolas Zimmermann  <nzimmermann@rim.com>
     2
     3        Tie lifetime of SVGAnimateElement::m_animatedType to the duration of the animation
     4        https://bugs.webkit.org/show_bug.cgi?id=85627
     5
     6        Reviewed by Antti Koivisto.
     7
     8        Update animate-target-id-changed.svg test to match Firefox behavior.
     9        When an animation element with fill="freeze" is changed to a new target
     10        eg, via animate.href = "#someOtherID", the animation effect should be removed.
     11
     12        Add tests for assertions I ran into while developing this patch.
     13
     14        * platform/chromium/test_expectations.txt: Require new results for animate-target-id-changed-expected.txt.
     15        * platform/mac/svg/custom/animate-target-id-changed-expected.png:
     16        * svg/animations/list-wrapper-assertion-expected.svg: Added.
     17        * svg/animations/list-wrapper-assertion.svg: Added.
     18        * svg/custom/animate-target-id-changed-expected.txt:
     19        * svg/custom/animate-target-id-changed.svg:
     20
    1212012-05-08  Shezan Baig  <shezbaig.wk@gmail.com>
    222
  • trunk/LayoutTests/platform/chromium/test_expectations.txt

    r116399 r116451  
    11621162// -----------------------------------------------------------------
    11631163
     1164// Needs a rebaseline, should still be green.
     1165BUGWK85627 : svg/custom/animate-target-id-changed.svg = IMAGE+TEXT IMAGE TEXT PASS
     1166
    11641167// Needs a rebaseline, only two circles should be visible now.
    11651168BUGWK84846 : svg/W3C-SVG-1.1/animate-elem-31-t.svg = IMAGE+TEXT IMAGE TEXT PASS
  • trunk/LayoutTests/svg/custom/animate-target-id-changed-expected.txt

    r107241 r116451  
    44  RenderSVGRoot {svg} at (0,0) size 100x100
    55    RenderSVGRect {rect} at (0,0) size 100x100 [fill={[type=SOLID] [color=#008000]}] [x=0.00] [y=0.00] [width=100.00] [height=100.00]
    6     RenderSVGRect {rect} at (0,0) size 100x100 [fill={[type=SOLID] [color=#008000]}] [x=0.00] [y=0.00] [width=100.00] [height=100.00]
  • trunk/LayoutTests/svg/custom/animate-target-id-changed.svg

    r107207 r116451  
    33<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" onload="runRepaintTest()">
    44<script xlink:href="../../fast/repaint/resources/repaint.js"/>
    5 <rect width="100" height="100" fill="green"/>
    6 <rect id="target" width="100" height="100" fill="red"/>
    7 <animate attributeName="fill" xlink:href="#target" from="green" to="green" begin="0s" dur="1s" fill="freeze"/>
     5<rect id="target" width="100" height="100" fill="green"/>
     6<animate attributeName="fill" xlink:href="#target" from="red" to="red" begin="0s" dur="1s" fill="freeze"/>
    87<script type="text/ecmascript">
    98<![CDATA[
  • trunk/Source/WebCore/ChangeLog

    r116450 r116451  
     12012-05-04  Nikolas Zimmermann  <nzimmermann@rim.com>
     2
     3        Tie lifetime of SVGAnimateElement::m_animatedType to the duration of the animation
     4        https://bugs.webkit.org/show_bug.cgi?id=85627
     5
     6        Reviewed by Antti Koivisto.
     7
     8        Example:
     9        <rect width="10" height="100">
     10            <animate attributeName="width" from="10" to="100" begin="2s" dur="4s" fill="remove"/>
     11        </rect>
     12
     13        At t=0s the <animate> element receives its first interval: begin=2s, end=6s.
     14        At this point we've created the 'OwnPtr<SVGAnimatedType> m_animatedType' in
     15        SVGAnimateElement, which holds the current animated value of the target type.
     16        In this example it contains a SVGLength with '10' as value at t=0s.
     17
     18        Calling "rect.width.animVal.value" will return the value currently contained in the
     19        m_animatedType from the SVGAnimateElement, even though the animation didn't begin
     20        yet. This is fine, as the animVal equals to the baseVal, as long as no animation is
     21        running.
     22
     23        At t=6s you'd expect that the whole 'animVal' object is destructed again, as it's no
     24        longer needed, as animVal will be equal to baseVal again, but the current code keeps
     25        the animVal alive, and just resets it to the baseVal. The animVals will be destructed
     26        once the animate element leaves the tree.
     27
     28        CSS animations suffer from the same problem, we never remove the animated SMIL properties
     29        but we only reset them to the base value. This makes integration with CSS Animations and
     30        CSS Transitions harder, so this needs to be changed.
     31
     32        This patch starts tracking the start/end of an animation chain properly, to destruct
     33        the animation effect for non-frozen animations at the end of their duration. This has to
     34        work properly together with seeking (SVGSVGElement.setCurrentTime), as our testing relies
     35        on the ability to drive the SMIL timeline from script.
     36
     37        Tests: svg/animations/list-wrapper-assertion-expected.svg
     38               svg/animations/list-wrapper-assertion.svg
     39
     40        * svg/SVGAnimateElement.cpp:
     41        (WebCore::SVGAnimateElement::resetAnimatedType):
     42        (WebCore::applyCSSPropertyToTarget):
     43        (WebCore::removeCSSPropertyFromTarget):
     44        (WebCore::applyCSSPropertyToTargetAndInstances):
     45        (WebCore::removeCSSPropertyFromTargetAndInstances):
     46        (WebCore::notifyTargetAboutAnimValChange):
     47        (WebCore::notifyTargetAndInstancesAboutAnimValChange):
     48        (WebCore::SVGAnimateElement::clearAnimatedType):
     49        (WebCore::SVGAnimateElement::applyResultsToTarget):
     50        (WebCore::SVGAnimateElement::targetElementWillChange):
     51        * svg/SVGAnimateElement.h:
     52        (SVGAnimateElement):
     53        * svg/SVGAnimateMotionElement.cpp:
     54        (WebCore::SVGAnimateMotionElement::resetAnimatedType):
     55        (WebCore::SVGAnimateMotionElement::clearAnimatedType):
     56        * svg/SVGAnimateMotionElement.h:
     57        (SVGAnimateMotionElement):
     58        * svg/SVGAnimationElement.cpp:
     59        * svg/SVGAnimationElement.h:
     60        * svg/animation/SMILTimeContainer.cpp:
     61        (WebCore::SMILTimeContainer::updateAnimations):
     62        * svg/animation/SVGSMILElement.cpp:
     63        (WebCore::SVGSMILElement::reset):
     64        (WebCore::SVGSMILElement::targetElementWillChange):
     65        (WebCore::SVGSMILElement::determineActiveState):
     66        (WebCore::SVGSMILElement::progress):
     67        * svg/animation/SVGSMILElement.h:
     68        (SVGSMILElement):
     69        * svg/properties/SVGAnimatedListPropertyTearOff.h:
     70            Remove svgAttributeChanged() calls from animationEnded/animValDidChange.
     71            Callers are now required to notify the target about changes. There are cases
     72            where we want to call animValDidChange without invoking svgAttributeChanged().
     73            That is supported now.
     74        (WebCore::SVGAnimatedListPropertyTearOff::animationEnded):
     75        (WebCore::SVGAnimatedListPropertyTearOff::animValDidChange):
     76        * svg/properties/SVGAnimatedProperty.h: Ditto.
     77        (WebCore::SVGAnimatedProperty::commitChange): Add safety guard.
     78        * svg/properties/SVGAnimatedPropertyTearOff.h: Ditto.
     79        (WebCore::SVGAnimatedPropertyTearOff::animationEnded):
     80        (WebCore::SVGAnimatedPropertyTearOff::animValDidChange):
     81        * svg/properties/SVGAnimatedStaticPropertyTearOff.h: Ditto.
     82        (WebCore::SVGAnimatedStaticPropertyTearOff::animationEnded):
     83        (WebCore::SVGAnimatedStaticPropertyTearOff::animValDidChange):
     84
    1852012-05-08  Ryuan Choi  <ryuan.choi@samsung.com>
    286
  • trunk/Source/WebCore/svg/SVGAnimateElement.cpp

    r115950 r116451  
    197197#endif
    198198
    199 void SVGAnimateElement::resetToBaseValue()
     199void SVGAnimateElement::resetAnimatedType()
    200200{
    201201    SVGAnimatedTypeAnimator* animator = ensureAnimator();
     
    213213        if (!m_animatedType)
    214214            m_animatedType = animator->startAnimValAnimation(m_animatedProperties);
    215         else
     215        else {
    216216            animator->resetAnimValToBaseVal(m_animatedProperties, m_animatedType.get());
     217            animator->animValDidChange(m_animatedProperties);
     218        }
    217219        return;
    218220    }
     
    233235}
    234236
     237static inline void applyCSSPropertyToTarget(SVGElement* targetElement, CSSPropertyID id, const String& value)
     238{
     239    ASSERT(!targetElement->m_deletionHasBegun);
     240
     241    StylePropertySet* propertySet = targetElement->ensureAnimatedSMILStyleProperties();
     242    if (!propertySet->setProperty(id, value, false, 0))
     243        return;
     244
     245    targetElement->setNeedsStyleRecalc(SyntheticStyleChange);
     246}
     247
     248static inline void removeCSSPropertyFromTarget(SVGElement* targetElement, CSSPropertyID id)
     249{
     250    ASSERT(!targetElement->m_deletionHasBegun);
     251    targetElement->ensureAnimatedSMILStyleProperties()->removeProperty(id);
     252    targetElement->setNeedsStyleRecalc(SyntheticStyleChange);
     253}
     254
     255static inline void applyCSSPropertyToTargetAndInstances(SVGElement* targetElement, const QualifiedName& attributeName, const String& valueAsString)
     256{
     257    ASSERT(targetElement);
     258    if (attributeName == anyQName() || !targetElement->inDocument() || !targetElement->parentNode())
     259        return;
     260
     261    CSSPropertyID id = cssPropertyID(attributeName.localName());
     262
     263    SVGElementInstance::InstanceUpdateBlocker blocker(targetElement);
     264    applyCSSPropertyToTarget(targetElement, id, valueAsString);
     265
     266    // If the target element has instances, update them as well, w/o requiring the <use> tree to be rebuilt.
     267    const HashSet<SVGElementInstance*>& instances = targetElement->instancesForElement();
     268    const HashSet<SVGElementInstance*>::const_iterator end = instances.end();
     269    for (HashSet<SVGElementInstance*>::const_iterator it = instances.begin(); it != end; ++it) {
     270        if (SVGElement* shadowTreeElement = (*it)->shadowTreeElement())
     271            applyCSSPropertyToTarget(shadowTreeElement, id, valueAsString);
     272    }
     273}
     274
     275static inline void removeCSSPropertyFromTargetAndInstances(SVGElement* targetElement, const QualifiedName& attributeName)
     276{
     277    ASSERT(targetElement);
     278    if (attributeName == anyQName() || !targetElement->inDocument() || !targetElement->parentNode())
     279        return;
     280
     281    CSSPropertyID id = cssPropertyID(attributeName.localName());
     282
     283    SVGElementInstance::InstanceUpdateBlocker blocker(targetElement);
     284    removeCSSPropertyFromTarget(targetElement, id);
     285
     286    // If the target element has instances, update them as well, w/o requiring the <use> tree to be rebuilt.
     287    const HashSet<SVGElementInstance*>& instances = targetElement->instancesForElement();
     288    const HashSet<SVGElementInstance*>::const_iterator end = instances.end();
     289    for (HashSet<SVGElementInstance*>::const_iterator it = instances.begin(); it != end; ++it) {
     290        if (SVGElement* shadowTreeElement = (*it)->shadowTreeElement())
     291            removeCSSPropertyFromTarget(shadowTreeElement, id);
     292    }
     293}
     294
     295static inline void notifyTargetAboutAnimValChange(SVGElement* targetElement, const QualifiedName& attributeName)
     296{
     297    ASSERT(!targetElement->m_deletionHasBegun);
     298    targetElement->svgAttributeChanged(attributeName);
     299}
     300
     301static inline void notifyTargetAndInstancesAboutAnimValChange(SVGElement* targetElement, const QualifiedName& attributeName)
     302{
     303    ASSERT(targetElement);
     304    if (attributeName == anyQName() || !targetElement->inDocument() || !targetElement->parentNode())
     305        return;
     306
     307    SVGElementInstance::InstanceUpdateBlocker blocker(targetElement);
     308    notifyTargetAboutAnimValChange(targetElement, attributeName);
     309
     310    // If the target element has instances, update them as well, w/o requiring the <use> tree to be rebuilt.
     311    const HashSet<SVGElementInstance*>& instances = targetElement->instancesForElement();
     312    const HashSet<SVGElementInstance*>::const_iterator end = instances.end();
     313    for (HashSet<SVGElementInstance*>::const_iterator it = instances.begin(); it != end; ++it) {
     314        if (SVGElement* shadowTreeElement = (*it)->shadowTreeElement())
     315            notifyTargetAboutAnimValChange(shadowTreeElement, attributeName);
     316    }
     317}
     318
     319void SVGAnimateElement::clearAnimatedType(SVGElement* targetElement)
     320{
     321    if (!m_animatedType)
     322        return;
     323
     324    if (!targetElement) {
     325        m_animatedType.clear();
     326        return;
     327    }
     328
     329    if (m_animatedProperties.isEmpty()) {
     330        // CSS properties animation code-path.
     331        removeCSSPropertyFromTargetAndInstances(targetElement, attributeName());
     332        m_animatedType.clear();
     333        return;
     334    }
     335
     336    // SVG DOM animVal animation code-path.
     337    if (m_animator) {
     338        m_animator->stopAnimValAnimation(m_animatedProperties);
     339        notifyTargetAndInstancesAboutAnimValChange(targetElement, attributeName());
     340    }
     341
     342    m_animatedProperties.clear();
     343    m_animatedType.clear();
     344}
     345
    235346void SVGAnimateElement::applyResultsToTarget()
    236347{
    237348    ASSERT(m_animatedPropertyType != AnimatedTransformList || hasTagName(SVGNames::animateTransformTag));
    238349    ASSERT(m_animatedPropertyType != AnimatedUnknown);
    239     ASSERT(m_animatedType);
    240350    ASSERT(m_animator);
     351
     352    // Early exit if our animated type got destructed by a previous endedActiveInterval().
     353    if (!m_animatedType)
     354        return;
    241355
    242356    if (m_animatedProperties.isEmpty()) {
    243357        // CSS properties animation code-path.
    244         setTargetAttributeAnimatedCSSValue(m_animatedType.get());
     358        // Convert the result of the animation to a String and apply it as CSS property on the target & all instances.
     359        applyCSSPropertyToTargetAndInstances(targetElement(), attributeName(), m_animatedType->valueAsString());
    245360        return;
    246361    }
    247362
    248363    // SVG DOM animVal animation code-path.
     364    // At this point the SVG DOM values are already changed, unlike for CSS.
     365    // We only have to trigger update notifications here.
    249366    m_animator->animValDidChange(m_animatedProperties);
     367    notifyTargetAndInstancesAboutAnimValChange(targetElement(), attributeName());
    250368}
    251369
     
    283401    SVGSMILElement::targetElementWillChange(currentTarget, newTarget);
    284402
    285     if (!m_animatedProperties.isEmpty()) {
    286         ensureAnimator()->stopAnimValAnimation(m_animatedProperties);
    287         m_animatedProperties.clear();
    288     }
    289 
    290     m_animatedType.clear();
     403    ASSERT(!m_animatedType);
    291404    m_fromType.clear();
    292405    m_toType.clear();
  • trunk/Source/WebCore/svg/SVGAnimateElement.h

    r115950 r116451  
    4444    SVGAnimateElement(const QualifiedName&, Document*);
    4545
    46     virtual void resetToBaseValue();
     46    virtual void resetAnimatedType();
     47    virtual void clearAnimatedType(SVGElement* targetElement);
    4748    virtual bool calculateToAtEndOfDurationValue(const String& toAtEndOfDurationString);
    4849    virtual bool calculateFromAndToValues(const String& fromString, const String& toString);
  • trunk/Source/WebCore/svg/SVGAnimateMotionElement.cpp

    r115950 r116451  
    165165}
    166166   
    167 void SVGAnimateMotionElement::resetToBaseValue()
     167void SVGAnimateMotionElement::resetAnimatedType()
    168168{
    169169    if (!hasValidAttributeType())
    170170        return;
    171     AffineTransform* transform = targetElement()->supplementalTransform();
    172     if (!transform)
    173         return;
    174     transform->makeIdentity();
     171    SVGElement* targetElement = this->targetElement();
     172    if (!targetElement)
     173        return;
     174    if (AffineTransform* transform = targetElement->supplementalTransform())
     175        transform->makeIdentity();
     176}
     177
     178void SVGAnimateMotionElement::clearAnimatedType(SVGElement* targetElement)
     179{
     180    if (!targetElement)
     181        return;
     182    if (AffineTransform* transform = targetElement->supplementalTransform())
     183        transform->makeIdentity();
    175184}
    176185
  • trunk/Source/WebCore/svg/SVGAnimateMotionElement.h

    r115950 r116451  
    4040    virtual void parseAttribute(Attribute*) OVERRIDE;
    4141
    42     virtual void resetToBaseValue();
     42    virtual void resetAnimatedType();
     43    virtual void clearAnimatedType(SVGElement* targetElement);
    4344    virtual bool calculateToAtEndOfDurationValue(const String& toAtEndOfDurationString);
    4445    virtual bool calculateFromAndToValues(const String& fromString, const String& toString);
  • trunk/Source/WebCore/svg/SVGAnimationElement.cpp

    r115950 r116451  
    3232#include "CSSParser.h"
    3333#include "CSSPropertyNames.h"
    34 #include "Color.h"
    3534#include "Document.h"
    36 #include "Event.h"
    37 #include "EventListener.h"
    3835#include "FloatConversion.h"
    39 #include "HTMLNames.h"
    40 #include "PlatformString.h"
     36#include "RenderObject.h"
    4137#include "SVGAnimateElement.h"
    4238#include "SVGElementInstance.h"
     
    4440#include "SVGParserUtilities.h"
    4541#include "SVGStyledElement.h"
    46 #include "SVGURIReference.h"
    47 #include "SVGUseElement.h"
    48 #include "XLinkNames.h"
    49 #include <wtf/StdLibExtras.h>
    50 
    51 using namespace std;
    5242
    5343namespace WebCore {
     
    340330
    341331    return SVGStyledElement::isAnimatableCSSProperty(attributeName);
    342 }
    343 
    344 static inline void applyCSSPropertyToTarget(SVGElement* targetElement, CSSPropertyID id, const String& value)
    345 {
    346     StylePropertySet* propertySet = targetElement->ensureAnimatedSMILStyleProperties();
    347     if (propertySet->setProperty(id, value, false, 0))
    348         targetElement->setNeedsStyleRecalc(SyntheticStyleChange);
    349 }
    350 
    351 void SVGAnimationElement::setTargetAttributeAnimatedCSSValue(SVGAnimatedType* animatedType)
    352 {
    353     ASSERT(animatedType);
    354     SVGElement* targetElement = this->targetElement();
    355     ASSERT(targetElement);
    356 
    357     const QualifiedName& attributeName = this->attributeName();
    358     ASSERT(attributeName != anyQName());
    359     CSSPropertyID id = cssPropertyID(attributeName.localName());
    360 
    361     const String& valueAsString = animatedType->valueAsString();
    362     SVGElementInstance::InstanceUpdateBlocker blocker(targetElement);
    363     applyCSSPropertyToTarget(targetElement, id, valueAsString);
    364 
    365     // If the target element has instances, update them as well, w/o requiring the <use> tree to be rebuilt.
    366     const HashSet<SVGElementInstance*>& instances = targetElement->instancesForElement();
    367     const HashSet<SVGElementInstance*>::const_iterator end = instances.end();
    368     for (HashSet<SVGElementInstance*>::const_iterator it = instances.begin(); it != end; ++it) {
    369         if (SVGElement* shadowTreeElement = (*it)->shadowTreeElement())
    370             applyCSSPropertyToTarget(shadowTreeElement, id, valueAsString);
    371     }
    372332}
    373333
  • trunk/Source/WebCore/svg/SVGAnimationElement.h

    r115950 r116451  
    191191
    192192    String targetAttributeBaseValue();
    193     void setTargetAttributeAnimatedCSSValue(SVGAnimatedType*);
    194193
    195194    // from SVGSMILElement
    196     virtual void startedActiveInterval();
    197     virtual void updateAnimation(float percent, unsigned repeat, SVGSMILElement* resultElement);
     195    virtual void startedActiveInterval() OVERRIDE;
     196    virtual void updateAnimation(float percent, unsigned repeat, SVGSMILElement* resultElement) OVERRIDE;
    198197
    199198    AnimatedPropertyValueType m_fromPropertyValueType;
  • trunk/Source/WebCore/svg/animation/SMILTimeContainer.cpp

    r115947 r116451  
    225225    typedef HashMap<ElementAttributePair, RefPtr<SVGSMILElement> > ResultElementMap;
    226226    ResultElementMap resultsElements;
     227    HashSet<SVGSMILElement*> contributingElements;
    227228    for (unsigned n = 0; n < toAnimate.size(); ++n) {
    228229        SVGSMILElement* animation = toAnimate[n];
     
    248249                continue;
    249250            resultElement = animation;
    250             resultElement->resetToBaseValue();
    251251            resultsElements.add(key, resultElement);
    252252        }
    253253
    254254        // This will calculate the contribution from the animation and add it to the resultsElement.
    255         animation->progress(elapsed, resultElement, seekToTime);
     255        if (animation->progress(elapsed, resultElement, seekToTime))
     256            contributingElements.add(resultElement);
    256257
    257258        SMILTime nextFireTime = animation->nextProgressTime();
     
    262263    Vector<SVGSMILElement*> animationsToApply;
    263264    ResultElementMap::iterator end = resultsElements.end();
    264     for (ResultElementMap::iterator it = resultsElements.begin(); it != end; ++it)
    265         animationsToApply.append(it->second.get());
     265    for (ResultElementMap::iterator it = resultsElements.begin(); it != end; ++it) {
     266        SVGSMILElement* animation = it->second.get();
     267        if (contributingElements.contains(animation))
     268            animationsToApply.append(animation);
     269    }
     270
     271    unsigned animationsToApplySize = animationsToApply.size();
     272    if (!animationsToApplySize) {
     273        startTimer(earliersFireTime, animationFrameDelay);
     274        return;
     275    }
    266276
    267277    // Sort <animateTranform> to be the last one to be applied. <animate> may change transform attribute as
    268278    // well (directly or indirectly by modifying <use> x/y) and this way transforms combine properly.
    269279    sortByApplyOrder(animationsToApply);
    270    
     280
    271281    // Apply results to target elements.
    272     for (unsigned n = 0; n < animationsToApply.size(); ++n)
    273         animationsToApply[n]->applyResultsToTarget();
     282    for (unsigned i = 0; i < animationsToApplySize; ++i)
     283        animationsToApply[i]->applyResultsToTarget();
    274284
    275285    startTimer(earliersFireTime, animationFrameDelay);
    276    
    277286    Document::updateStyleForAllDocuments();
    278287}
  • trunk/Source/WebCore/svg/animation/SVGSMILElement.cpp

    r116030 r116451  
    179179void SVGSMILElement::reset()
    180180{
     181    // Don't clear the animated type if we're frozen, only take action here if we're active.
     182    if (m_activeState == Active)
     183        clearAnimatedType(m_targetElement);
     184
    181185    m_activeState = Inactive;
    182186    m_isWaitingForFirstInterval = true;
     
    561565}
    562566
    563 void SVGSMILElement::targetElementWillChange(SVGElement*, SVGElement*)
    564 {
    565     // If the animation state is Active, always reset to a clear state before leaving the old target element.
    566     if (m_activeState == Active)
     567void SVGSMILElement::targetElementWillChange(SVGElement* currentTarget, SVGElement*)
     568{
     569    // Only clear the animated type, if we had a target before.
     570    if (currentTarget)
     571        clearAnimatedType(currentTarget);
     572
     573    // If the animation state is not Inactive, always reset to a clear state before leaving the old target element.
     574    if (m_activeState != Inactive)
    567575        endedActiveInterval();
    568576}
     
    991999        return Active;
    9921000
    993     if (m_activeState == Active)
    994         return fill() == FillFreeze ? Frozen : Inactive;
    995 
    996     return m_activeState;
     1001    return fill() == FillFreeze ? Frozen : Inactive;
    9971002}
    9981003   
     
    10031008}
    10041009   
    1005 void SVGSMILElement::progress(SMILTime elapsed, SVGSMILElement* resultElement, bool seekToTime)
    1006 {
     1010bool SVGSMILElement::progress(SMILTime elapsed, SVGSMILElement* resultElement, bool seekToTime)
     1011{
     1012    ASSERT(resultElement);
    10071013    ASSERT(m_timeContainer);
    10081014    ASSERT(m_isWaitingForFirstInterval || m_intervalBegin.isFinite());
     
    10141020        ASSERT(m_activeState == Inactive);
    10151021        m_nextProgressTime = SMILTime::unresolved();
    1016         return;
    1017     }
    1018    
     1022        return false;
     1023    }
     1024
    10191025    if (elapsed < m_intervalBegin) {
    10201026        ASSERT(m_activeState != Active);
    1021         if (m_activeState == Frozen && resultElement)
     1027        if (m_activeState == Frozen)
    10221028            updateAnimation(m_lastPercent, m_lastRepeat, resultElement);
    10231029        m_nextProgressTime = m_intervalBegin;
    1024         return;
     1030        return false;
    10251031    }
    10261032   
    10271033    m_previousIntervalBegin = m_intervalBegin;
    1028    
    1029     if (m_activeState == Inactive) {
     1034
     1035    if (m_isWaitingForFirstInterval) {
    10301036        m_isWaitingForFirstInterval = false;
    1031         m_activeState = Active;
    1032         startedActiveInterval();
     1037        resolveFirstInterval();
    10331038    }
    10341039
     
    10451050    ActiveState oldActiveState = m_activeState;
    10461051    m_activeState = determineActiveState(elapsed);
    1047     if (isContributing(elapsed)) {
    1048         if (resultElement)
    1049             updateAnimation(percent, repeat, resultElement);
     1052    bool animationIsContributing = isContributing(elapsed);
     1053
     1054    // Only reset the animated type to the base value once for the lowest priority animation that animates a particular element/attribute pair.
     1055    if (this == resultElement)
     1056        resetAnimatedType();
     1057
     1058    if (animationIsContributing) {
     1059        if (oldActiveState == Inactive)
     1060            startedActiveInterval();
     1061
     1062        updateAnimation(percent, repeat, resultElement);
    10501063        m_lastPercent = percent;
    10511064        m_lastRepeat = repeat;
    10521065    }
    10531066
    1054     if (oldActiveState == Active && m_activeState != Active)
     1067    if (oldActiveState == Active && m_activeState != Active) {
    10551068        endedActiveInterval();
     1069        if (m_activeState != Frozen)
     1070            clearAnimatedType(m_targetElement);
     1071    }
    10561072
    10571073    m_nextProgressTime = calculateNextProgressTime(elapsed);
     1074    return animationIsContributing;
    10581075}
    10591076   
  • trunk/Source/WebCore/svg/animation/SVGSMILElement.h

    r115947 r116451  
    9191
    9292    void seekToIntervalCorrespondingToTime(SMILTime elapsed);
    93     void progress(SMILTime elapsed, SVGSMILElement* resultsElement, bool seekToTime);
     93    bool progress(SMILTime elapsed, SVGSMILElement* resultsElement, bool seekToTime);
    9494    SMILTime nextProgressTime() const;
    9595
     
    107107
    108108    virtual bool isAdditive() const = 0;
    109     virtual void resetToBaseValue() = 0;
     109    virtual void resetAnimatedType() = 0;
     110    virtual void clearAnimatedType(SVGElement* targetElement) = 0;
    110111    virtual void applyResultsToTarget() = 0;
    111112
     
    118119    // Sub-classes may need to take action when the target is changed.
    119120    virtual void targetElementWillChange(SVGElement* currentTarget, SVGElement* newTarget);
    120     virtual void endedActiveInterval();
    121121
    122122private:
    123123    virtual void startedActiveInterval() = 0;
     124    void endedActiveInterval();
    124125    virtual void updateAnimation(float percent, unsigned repeat, SVGSMILElement* resultElement) = 0;
    125126
  • trunk/Source/WebCore/svg/properties/SVGAnimatedListPropertyTearOff.h

    r113184 r116451  
    117117        m_animatedWrappers.clear();
    118118        m_isAnimating = false;
    119 
    120         ASSERT(contextElement());
    121         contextElement()->svgAttributeChanged(attributeName());
    122119    }
    123120
     
    150147        ASSERT(m_values.size() == m_wrappers.size());
    151148        synchronizeWrappersIfNeeded();
    152 
    153         ASSERT(contextElement());
    154         contextElement()->svgAttributeChanged(attributeName());
    155149    }
    156150
  • trunk/Source/WebCore/svg/properties/SVGAnimatedProperty.h

    r115518 r116451  
    4141    {
    4242        ASSERT(m_contextElement);
     43        ASSERT(!m_contextElement->m_deletionHasBegun);
    4344        m_contextElement->invalidateSVGAttributes();
    4445        m_contextElement->svgAttributeChanged(m_attributeName);
  • trunk/Source/WebCore/svg/properties/SVGAnimatedPropertyTearOff.h

    r113003 r116451  
    7979        m_animVal->setValue(m_property);
    8080        m_isAnimating = false;
    81 
    82         SVGElement* element = contextElement();
    83         if (!element || !element->inDocument() || !element->parentNode())
    84             return;
    85         ASSERT(!element->m_deletionHasBegun);
    86         element->svgAttributeChanged(attributeName());
    8781    }
    8882
     
    9690    void animValDidChange()
    9791    {
     92        // no-op for non list types.
    9893        ASSERT(m_isAnimating);
    9994        ASSERT(m_animVal);
    100 
    101         ASSERT(contextElement());
    102         contextElement()->svgAttributeChanged(attributeName());
    10395    }
    10496
  • trunk/Source/WebCore/svg/properties/SVGAnimatedStaticPropertyTearOff.h

    r113003 r116451  
    8282        m_animatedProperty = 0;
    8383        m_isAnimating = false;
    84 
    85         SVGElement* element = contextElement();
    86         if (!element || !element->inDocument() || !element->parentNode())
    87             return;
    88         ASSERT(!element->m_deletionHasBegun);
    89         element->svgAttributeChanged(attributeName());
    9084    }
    9185
     
    9993    void animValDidChange()
    10094    {
     95        // no-op for non list types.
    10196        ASSERT(m_isAnimating);
    10297        ASSERT(m_animatedProperty);
    103 
    104         ASSERT(contextElement());
    105         contextElement()->svgAttributeChanged(attributeName());
    10698    }
    10799
Note: See TracChangeset for help on using the changeset viewer.