2007-01-01 Eric Seidel <eric@webkit.org>
authoreseidel <eseidel@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 1 Jan 2007 08:12:43 +0000 (08:12 +0000)
committereseidel <eseidel@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 1 Jan 2007 08:12:43 +0000 (08:12 +0000)
        Reviewed by olliej.

        Begin pushing more animation logic out of SVGTimer and into the SVGAnimate* classes.

        * ksvg2/misc/SVGTimer.cpp:
        (WebCore::SVGTimer::animationsByElement): add comment
        (WebCore::SVGTimer::notifyAll): push logic into SVGAnimte* classes
        * ksvg2/svg/SVGAnimateColorElement.cpp:
        (WebCore::SVGAnimateColorElement::applyAnimationToValue): added.
        * ksvg2/svg/SVGAnimateColorElement.h:
        * ksvg2/svg/SVGAnimateElement.cpp:
        * ksvg2/svg/SVGAnimateTransformElement.cpp:
        (WebCore::SVGAnimateTransformElement::applyAnimationToValue): added.
        * ksvg2/svg/SVGAnimateTransformElement.h:
        * ksvg2/svg/SVGAnimationElement.cpp:
        (WebCore::calculateTimePercentage): logic moved from SVGTimer
        (WebCore::SVGAnimationElement::updateForElapsedSeconds): logic moved from SVGTimer
        * ksvg2/svg/SVGAnimationElement.h:
        * ksvg2/svg/SVGTransformList.cpp:
        (SVGTransformList::concatenate): fixed spacing

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@18502 268f45cc-cd09-0410-ab3c-d52691b4dbfc

12 files changed:
WebCore/ChangeLog
WebCore/ksvg2/misc/SVGTimer.cpp
WebCore/ksvg2/misc/SVGTimer.h
WebCore/ksvg2/svg/SVGAnimateColorElement.cpp
WebCore/ksvg2/svg/SVGAnimateColorElement.h
WebCore/ksvg2/svg/SVGAnimateElement.cpp
WebCore/ksvg2/svg/SVGAnimateElement.h
WebCore/ksvg2/svg/SVGAnimateTransformElement.cpp
WebCore/ksvg2/svg/SVGAnimateTransformElement.h
WebCore/ksvg2/svg/SVGAnimationElement.cpp
WebCore/ksvg2/svg/SVGAnimationElement.h
WebCore/ksvg2/svg/SVGTransformList.cpp

index 6af9828..5b45002 100644 (file)
@@ -2,6 +2,29 @@
 
         Reviewed by olliej.
 
+        Begin pushing more animation logic out of SVGTimer and into the SVGAnimate* classes.
+        
+        * ksvg2/misc/SVGTimer.cpp:
+        (WebCore::SVGTimer::animationsByElement): add comment
+        (WebCore::SVGTimer::notifyAll): push logic into SVGAnimte* classes
+        * ksvg2/svg/SVGAnimateColorElement.cpp:
+        (WebCore::SVGAnimateColorElement::applyAnimationToValue): added.
+        * ksvg2/svg/SVGAnimateColorElement.h:
+        * ksvg2/svg/SVGAnimateElement.cpp:
+        * ksvg2/svg/SVGAnimateTransformElement.cpp:
+        (WebCore::SVGAnimateTransformElement::applyAnimationToValue): added.
+        * ksvg2/svg/SVGAnimateTransformElement.h:
+        * ksvg2/svg/SVGAnimationElement.cpp:
+        (WebCore::calculateTimePercentage): logic moved from SVGTimer
+        (WebCore::SVGAnimationElement::updateForElapsedSeconds): logic moved from SVGTimer
+        * ksvg2/svg/SVGAnimationElement.h:
+        * ksvg2/svg/SVGTransformList.cpp:
+        (SVGTransformList::concatenate): fixed spacing
+
+2007-01-01  Eric Seidel  <eric@webkit.org>
+
+        Reviewed by olliej.
+
         Split out animationsByElement() logic in preparation for adding AnimationCompositor class
         Add addColorsAndClamp helper (since adding and clamping is the common case)
 
index afea091..a38a9d4 100644 (file)
@@ -49,27 +49,10 @@ void SVGTimer::start()
         startRepeating(m_interval);
 }
 
-double SVGTimer::calculateTimePercentage(double elapsedSeconds, double start, double end, double duration, double repetitions)
-{
-    double percentage = 0.0;
-
-    double useElapsed = elapsedSeconds - (duration * repetitions);
-    
-    if (duration > 0.0 && end == 0.0)
-        percentage = 1.0 - (((start + duration) - useElapsed) / duration);
-    else if (duration > 0.0 && end != 0.0) {
-        if (duration > end)
-            percentage = 1.0 - (((start + end) - useElapsed) / end);
-        else
-            percentage = 1.0 - (((start + duration) - useElapsed) / duration);
-    } else if (duration == 0.0 && end != 0.0)
-        percentage = 1.0 - (((start + end) - useElapsed) / end);
-
-    return percentage;
-}
-
 SVGTimer::TargetAnimationMap SVGTimer::animationsByElement(double elapsedSeconds)
 {
+    // Build a list of all animations which apply to each element
+    // FIXME: This list should be sorted by animation priority
     ExceptionCode ec = 0;
     TargetAnimationMap targetMap;
     SVGNotifySet::const_iterator end = m_notifySet.end();
@@ -98,104 +81,68 @@ SVGTimer::TargetAnimationMap SVGTimer::animationsByElement(double elapsedSeconds
     return targetMap;
 }
 
-void SVGTimer::notifyAll()
+// FIXME: This funtion will eventually become part of the AnimationCompositor
+void SVGTimer::applyAnimations(double elapsedSeconds, const SVGTimer::TargetAnimationMap& targetMap)
 {
-    if (m_enabledNotifySet.isEmpty())
-        return;
-
-    double elapsedSeconds = m_scheduler->elapsed() * 1000.0; // Take time now.
-
-    // First build a list of animation elements per target element
-    // This is important to decide about the order & priority of 
-    // the animations -> 'additive' support is handled this way.
-    TargetAnimationMap targetMap = animationsByElement(elapsedSeconds);
-
     ExceptionCode ec = 0;
-
-    TargetAnimationMap::iterator targetIterator = targetMap.begin();
-    TargetAnimationMap::iterator tend = targetMap.end();
+    
+    TargetAnimationMap::const_iterator targetIterator = targetMap.begin();
+    TargetAnimationMap::const_iterator tend = targetMap.end();
     for (; targetIterator != tend; ++targetIterator) {
-        HashMap<String, Color> targetColor; // special <animateColor> case
-        RefPtr<SVGTransformList> targetTransforms; // special <animateTransform> case    
-
+        HashMap<String, Color> attributeToColorMap; // special <animateColor> case
+        RefPtr<SVGTransformList> targetTransforms; // special <animateTransform> case
+        
+        // FIXME: This is still not 100% correct.  Correct would be:
+        // 1. Walk backwards through the priority list until a replace (!isAdditive()) is found
+        // 2. Set the initial value (or last replace) as the new animVal
+        // 3. Call each enabled animation in turn, to have it apply its changes
+        // 4. After building a new animVal, set it on the element.
+        
         unsigned count = targetIterator->second.size();
         for (unsigned i = 0; i < count; ++i) {
             SVGAnimationElement* animation = targetIterator->second[i];
-
-            double end = animation->getEndTime();
-            double start = animation->getStartTime();
-            double duration = animation->getSimpleDuration(ec);
-            double repetitions = animation->repeations();
-
-            // Validate animation timing settings:
-            // #1 (duration > 0) -> fine
-            // #2 (duration <= 0.0 && end > 0) -> fine
             
-            if ((duration <= 0.0 && end <= 0.0) || (animation->isIndefinite(duration) && end <= 0.0))
-                continue; // Ignore dur="0" or dur="-neg"
+            if (!animation->updateForElapsedSeconds(elapsedSeconds))
+                continue;
             
-            float percentage = calculateTimePercentage(elapsedSeconds, start, end, duration, repetitions);
-                
-            if (percentage <= 1.0 || animation->connected())
-                animation->handleTimerEvent(percentage);
-
-            // Special cases for animate* objects depending on 'additive' attribute
             if (animation->hasTagName(SVGNames::animateTransformTag)) {
                 SVGAnimateTransformElement* animTransform = static_cast<SVGAnimateTransformElement*>(animation);
-                AffineTransform transformMatrix = animTransform->transformMatrix();
-                RefPtr<SVGTransform> targetTransform = new SVGTransform();
-
-                if (!targetTransforms) { // lazy creation, only if needed.
+                if (!targetTransforms) {
                     targetTransforms = new SVGTransformList();
-
-                    if (animation->isAdditive()) {
-                        targetTransform->setMatrix(animTransform->initialMatrix());
-                        targetTransforms->appendItem(targetTransform.get(), ec);
-                        targetTransform = new SVGTransform();
+                    if (animation->isAdditive()) { // Avoid mallocing a transform which is about to be replaced
+                        RefPtr<SVGTransform> initialTransform = new SVGTransform();
+                        initialTransform->setMatrix(animTransform->initialMatrix());
+                        targetTransforms->appendItem(initialTransform.get(), ec);
                     }
                 }
-
-                if (targetTransforms->numberOfItems() <= 1)
-                    targetTransform->setMatrix(transformMatrix);
-                else {
-                    if (!animation->isAdditive())
-                        targetTransforms->clear(ec);
-                    targetTransform->setMatrix(transformMatrix);
-                }
-
-                targetTransforms->appendItem(targetTransform.get(), ec);
+                animTransform->applyAnimationToValue(targetTransforms.get());
             } else if (animation->hasTagName(SVGNames::animateColorTag)) {
                 SVGAnimateColorElement* animColor = static_cast<SVGAnimateColorElement*>(animation);
                 String name = animColor->attributeName();
-
-                if (animation->isAdditive()) {
-                    if (targetColor.contains(name))
-                        targetColor.set(name, animColor->addColorsAndClamp(targetColor.get(name), animColor->color()));
-                    else
-                        targetColor.set(name, animColor->addColorsAndClamp(animColor->initialColor(), animColor->color()));
-                } else
-                    targetColor.set(name, animColor->color());
+                Color currentColor = attributeToColorMap.contains(name) ? attributeToColorMap.get(name) : animColor->initialColor();
+                animColor->applyAnimationToValue(currentColor);
+                attributeToColorMap.set(name, currentColor);
             }
         }
-
-        // Handle <animateTransform>.
+        
+        // Apply any transform changes (animateTransform)
         if (targetTransforms) {
             SVGElement* key = targetIterator->first;
-            if (key && key->isStyled() && key->isStyledTransformable()) {
+            if (key && key->isStyledTransformable()) {
                 SVGStyledTransformableElement* transform = static_cast<SVGStyledTransformableElement*>(key);
                 transform->setTransform(targetTransforms.get());
                 transform->updateLocalTransform(transform->transform());
             }
         }
-
-        // Handle <animateColor>.
-        HashMap<String, Color>::iterator colorIteratorEnd = targetColor.end();
-        for (HashMap<String, Color>::iterator colorIterator = targetColor.begin(); colorIterator != colorIteratorEnd; ++colorIterator) {
+        
+        // Apply any color changes (animateColor)
+        HashMap<String, Color>::iterator colorIteratorEnd = attributeToColorMap.end();
+        for (HashMap<String, Color>::iterator colorIterator = attributeToColorMap.begin(); colorIterator != colorIteratorEnd; ++colorIterator) {
             if (colorIterator->second.isValid())
                 SVGAnimationElement::setTargetAttribute(targetIterator->first, colorIterator->first, colorIterator->second.name());
         }
     }
-
+    
     // Make a second pass through the map to avoid multiple setChanged calls on the same element.
     for (targetIterator = targetMap.begin(); targetIterator != tend; ++targetIterator) {
         SVGElement* key = targetIterator->first;
@@ -204,6 +151,19 @@ void SVGTimer::notifyAll()
     }
 }
 
+void SVGTimer::notifyAll()
+{
+    if (m_enabledNotifySet.isEmpty())
+        return;
+
+    // First build a list of animation elements per target element
+    double elapsedSeconds = m_scheduler->elapsed() * 1000.0; // Take time now.
+    TargetAnimationMap targetMap = animationsByElement(elapsedSeconds);
+    
+    // Then composite those animations down to final values and apply
+    applyAnimations(elapsedSeconds, targetMap);
+}
+
 void SVGTimer::addNotify(SVGAnimationElement* element, bool enabled)
 {
     m_notifySet.add(element);
index c028256..fb3538d 100644 (file)
@@ -51,10 +51,9 @@ public:
     static SVGTimer* downcast(Timer<TimeScheduler>* t) { return static_cast<SVGTimer*>(t); }
 
 private:
-    double calculateTimePercentage(double elapsed, double start, double end, double duration, double repetitions);
-    
     typedef HashMap<SVGElement*, Vector<SVGAnimationElement*> > TargetAnimationMap;
     TargetAnimationMap animationsByElement(double elapsedTime);
+    void applyAnimations(double elapsedSeconds, const SVGTimer::TargetAnimationMap& targetMap);
 
     TimeScheduler* m_scheduler;
     double m_interval;
index 1cec4b8..ba3ddf9 100644 (file)
@@ -49,6 +49,13 @@ SVGAnimateColorElement::~SVGAnimateColorElement()
 {
 }
 
+void calculateColorDifference(const Color& first, const Color& second, int& redDiff, int& greenDiff, int& blueDiff)
+{
+    redDiff = first.red() - second.red();
+    greenDiff = first.green() - second.green();
+    blueDiff = first.blue() - second.blue();
+}
+
 void SVGAnimateColorElement::handleTimerEvent(double timePercentage)
 {
     // Start condition.
@@ -112,11 +119,8 @@ void SVGAnimateColorElement::handleTimerEvent(double timePercentage)
             
                 String toColorString(qTo.name());
                 m_toColor->setRGBColor(toColorString);
-            
-                m_redDiff = qTo.red() - qFrom.red();
-                m_greenDiff = qTo.green() - qFrom.green();
-                m_blueDiff = qTo.blue() - qFrom.blue();
-
+                
+                calculateColorDifference(qTo, qFrom, m_redDiff, m_greenDiff, m_blueDiff);
                 break;
             }
             case VALUES_ANIMATION:
@@ -165,18 +169,9 @@ void SVGAnimateColorElement::handleTimerEvent(double timePercentage)
                     apply = true;
                 }
 
-                String toColorString(value2);
-                m_toColor->setRGBColor(toColorString);
-    
-                String fromColorString(value1);
-                m_fromColor->setRGBColor(fromColorString);    
-
-                Color qTo = m_toColor->color();
-                Color qFrom = m_fromColor->color();
-
-                m_redDiff = qTo.red() - qFrom.red();
-                m_greenDiff = qTo.green() - qFrom.green();
-                m_blueDiff = qTo.blue() - qFrom.blue();
+                m_toColor->setRGBColor(value2);
+                m_fromColor->setRGBColor(value1);
+                calculateColorDifference(m_toColor->color(), m_fromColor->color(), m_redDiff, m_greenDiff, m_blueDiff);
 
                 m_currentItem = itemByPercentage;
 
@@ -225,6 +220,14 @@ void SVGAnimateColorElement::handleTimerEvent(double timePercentage)
     }
 }
 
+void SVGAnimateColorElement::applyAnimationToValue(Color& currentColor)
+{
+    if (isAdditive())
+        currentColor = addColorsAndClamp(currentColor, color());
+    else
+        currentColor = color();
+}
+
 static inline int clampColorValue(int v)
 {
     if (v > 255)
index 5df0c69..04e2398 100644 (file)
@@ -36,6 +36,7 @@ namespace WebCore {
         SVGAnimateColorElement(const QualifiedName&, Document*);
         virtual ~SVGAnimateColorElement();
 
+        void applyAnimationToValue(Color& currentColor);
         virtual void handleTimerEvent(double timePercentage);
 
         // Helper
index 17cdfe2..2436e68 100644 (file)
@@ -40,31 +40,6 @@ SVGAnimateElement::~SVGAnimateElement()
 {
 }
 
-void SVGAnimateElement::handleTimerEvent(double timePercentage)
-{
-    // Start condition.
-    if (!m_connected) {
-        ownerSVGElement()->timeScheduler()->connectIntervalTimer(this);
-        m_connected = true;
-        return;
-    }
-
-    // Commit changes!
-    
-    // End condition.
-    if (timePercentage == 1.0) {
-        if ((m_repeatCount > 0 && m_repeations < m_repeatCount - 1) || isIndefinite(m_repeatCount)) {
-            m_repeations++;
-            return;
-        }
-        ownerSVGElement()->timeScheduler()->disconnectIntervalTimer(this);
-        m_connected = false;
-
-        // Reset...
-        m_currentItem = -1;
-    }
-}
-
 }
 
 // vim:ts=4:noet
index e34cfee..819c57f 100644 (file)
@@ -33,7 +33,7 @@ namespace WebCore {
         SVGAnimateElement(const QualifiedName&, Document*);
         virtual ~SVGAnimateElement();
 
-        virtual void handleTimerEvent(double timePercentage);
+        virtual void handleTimerEvent(double timePercentage) { }
     
     protected:
         virtual const SVGElement* contextElement() const { return this; }
@@ -41,7 +41,7 @@ namespace WebCore {
     private:
         int m_currentItem;
 
-        DeprecatedString m_savedTo;
+        String m_savedTo;
     };
 
 } // namespace WebCore
index 1681b04..24118fd 100644 (file)
@@ -318,6 +318,17 @@ void SVGAnimateTransformElement::handleTimerEvent(double timePercentage)
     }
 }
 
+void SVGAnimateTransformElement::applyAnimationToValue(SVGTransformList* targetTransforms)
+{
+    ExceptionCode ec;
+    if (!isAdditive())
+        targetTransforms->clear(ec);
+    
+    RefPtr<SVGTransform> targetTransform = new SVGTransform();
+    targetTransform->setMatrix(m_transformMatrix);
+    targetTransforms->appendItem(targetTransform.get(), ec);
+}
+
 RefPtr<SVGTransform> SVGAnimateTransformElement::parseTransformValue(const String& data) const
 {
     DeprecatedString parse = data.deprecatedString().stripWhiteSpace();
index b2715dc..574716e 100644 (file)
@@ -39,6 +39,7 @@ namespace WebCore {
         virtual void parseMappedAttribute(MappedAttribute*);
 
         virtual void handleTimerEvent(double timePercentage);
+        void applyAnimationToValue(SVGTransformList*);
 
         // Helpers
         RefPtr<SVGTransform> parseTransformValue(const String&) const;
index bd04aab..15d0013 100644 (file)
@@ -512,6 +512,41 @@ bool SVGAnimationElement::isIndefinite(double value) const
     return (value == DBL_MAX);
 }
 
+static double calculateTimePercentage(double elapsedSeconds, double start, double end, double duration, double repetitions)
+{
+    double percentage = 0.0;
+    double useElapsed = elapsedSeconds - (duration * repetitions);
+    
+    if (duration > 0.0 && end == 0.0)
+        percentage = 1.0 - (((start + duration) - useElapsed) / duration);
+    else if (duration > 0.0 && end != 0.0) {
+        if (duration > end)
+            percentage = 1.0 - (((start + end) - useElapsed) / end);
+        else
+            percentage = 1.0 - (((start + duration) - useElapsed) / duration);
+    } else if (duration == 0.0 && end != 0.0)
+        percentage = 1.0 - (((start + end) - useElapsed) / end);
+    
+    return percentage;
+}
+
+bool SVGAnimationElement::updateForElapsedSeconds(double elapsedSeconds)
+{
+    // Validate animation timing settings:
+    // #1 (duration > 0) -> fine
+    // #2 (duration <= 0.0 && end > 0) -> fine
+    
+    if ((m_simpleDuration <= 0.0 && m_end <= 0.0) || (isIndefinite(m_simpleDuration) && m_end <= 0.0))
+        return false; // Ignore dur="0" or dur="-neg"
+    
+    float percentage = calculateTimePercentage(elapsedSeconds, m_begin, m_end, m_simpleDuration, m_repeations);
+    
+    if (percentage <= 1.0 || connected())
+        handleTimerEvent(percentage);
+    
+    return true;
+}
+
 }
 
 // vim:ts=4:noet
index 8ad6cfb..ebbcae0 100644 (file)
@@ -98,6 +98,7 @@ namespace WebCore {
         virtual void closeRenderer();
 
         // Helpers
+        bool updateForElapsedSeconds(double);
         virtual void handleTimerEvent(double timePercentage) = 0;
 
         double parseClockValue(const String&) const;
index 36012ed..e381c25 100644 (file)
@@ -65,7 +65,7 @@ SVGTransform* SVGTransformList::concatenate() const
     AffineTransform matrix;
 
     ExceptionCode ec = 0;
-    for(unsigned int i = 0; i < length; i++)
+    for (unsigned int i = 0; i < length; i++)
         matrix = getItem(i, ec)->matrix() * matrix;
 
     obj->setMatrix(matrix);