• Skip to content
  • Skip to link menu
KDE 4.2 API Reference
  • KDE API Reference
  • kdelibs
  • Sitemap
  • Contact Us
 

KHTML

SMILTimeContainer.cpp

Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2008 Apple Inc. All Rights Reserved.
00003  *
00004  * Redistribution and use in source and binary forms, with or without
00005  * modification, are permitted provided that the following conditions
00006  * are met:
00007  * 1. Redistributions of source code must retain the above copyright
00008  *    notice, this list of conditions and the following disclaimer.
00009  * 2. Redistributions in binary form must reproduce the above copyright
00010  *    notice, this list of conditions and the following disclaimer in the
00011  *    documentation and/or other materials provided with the distribution.
00012  *
00013  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
00014  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00015  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
00016  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
00017  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
00018  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
00019  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
00020  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
00021  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00022  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
00023  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
00024  */
00025 
00026 #include "config.h"
00027 #include "SMILTimeContainer.h"
00028 
00029 #include "CSSComputedStyleDeclaration.h"
00030 #include "CSSParser.h"
00031 #include "Document.h"
00032 #include "SVGAnimationElement.h"
00033 #include "SVGSMILElement.h"
00034 #include "SVGSVGElement.h"
00035 #include "SystemTime.h"
00036 
00037 using namespace std;
00038 
00039 namespace WebCore {
00040     
00041 static const double animationFrameDelay = 0.025;
00042 
00043 SMILTimeContainer::SMILTimeContainer(SVGSVGElement* owner) 
00044     : m_beginTime(0)
00045     , m_pauseTime(0)
00046     , m_accumulatedPauseTime(0)
00047     , m_documentOrderIndexesDirty(false)
00048     , m_timer(this, &SMILTimeContainer::timerFired)
00049     , m_ownerSVGElement(owner)
00050 {
00051 }
00052     
00053 #if !ENABLE(SVG_ANIMATION)
00054 void SMILTimeContainer::begin() {}
00055 void SMILTimeContainer::pause() {}
00056 void SMILTimeContainer::resume() {}
00057 SMILTime SMILTimeContainer::elapsed() const { return 0; }
00058 bool SMILTimeContainer::isPaused() const { return false; }
00059 void SMILTimeContainer::timerFired(Timer<SMILTimeContainer>*) {}
00060 #else
00061     
00062 void SMILTimeContainer::schedule(SVGSMILElement* animation)
00063 {
00064     ASSERT(animation->timeContainer() == this);
00065     SMILTime nextFireTime = animation->nextProgressTime();
00066     if (!nextFireTime.isFinite())
00067         return;
00068     m_scheduledAnimations.add(animation);
00069     startTimer(0);
00070 }
00071     
00072 void SMILTimeContainer::unschedule(SVGSMILElement* animation)
00073 {
00074     ASSERT(animation->timeContainer() == this);
00075 
00076     m_scheduledAnimations.remove(animation);
00077 }
00078 
00079 SMILTime SMILTimeContainer::elapsed() const
00080 {
00081     if (!m_beginTime)
00082         return 0;
00083     return currentTime() - m_beginTime - m_accumulatedPauseTime;
00084 }
00085     
00086 bool SMILTimeContainer::isActive() const
00087 {
00088     return m_beginTime && !isPaused();
00089 }
00090     
00091 bool SMILTimeContainer::isPaused() const
00092 {
00093     return m_pauseTime;
00094 }
00095 
00096 void SMILTimeContainer::begin()
00097 {
00098     ASSERT(!m_beginTime);
00099     m_beginTime = currentTime();
00100     updateAnimations(0);
00101 }
00102 
00103 void SMILTimeContainer::pause()
00104 {
00105     if (!m_beginTime)
00106         return;
00107     ASSERT(!isPaused());
00108     m_pauseTime = currentTime();
00109     m_timer.stop();
00110 }
00111 
00112 void SMILTimeContainer::resume()
00113 {
00114     if (!m_beginTime)
00115         return;
00116     ASSERT(isPaused());
00117     m_accumulatedPauseTime += currentTime() - m_pauseTime;
00118     m_pauseTime = 0;
00119     startTimer(0);
00120 }
00121 
00122 void SMILTimeContainer::startTimer(SMILTime fireTime, SMILTime minimumDelay)
00123 {
00124     if (!m_beginTime || isPaused())
00125         return;
00126     
00127     if (!fireTime.isFinite())
00128         return;
00129     
00130     SMILTime delay = max(fireTime - elapsed(), minimumDelay);
00131     m_timer.startOneShot(delay.value());
00132 }
00133     
00134 void SMILTimeContainer::timerFired(Timer<SMILTimeContainer>*)
00135 {
00136     ASSERT(m_beginTime);
00137     ASSERT(!m_pauseTime);
00138     SMILTime elapsed = this->elapsed();
00139     updateAnimations(elapsed);
00140 }
00141  
00142 void SMILTimeContainer::updateDocumentOrderIndexes()
00143 {
00144     unsigned timingElementCount = 0;
00145     for (Node* node = m_ownerSVGElement; node; node = node->traverseNextNode(m_ownerSVGElement)) {
00146         if (SVGSMILElement::isSMILElement(node))
00147             static_cast<SVGSMILElement*>(node)->setDocumentOrderIndex(timingElementCount++);
00148     }
00149     m_documentOrderIndexesDirty = false;
00150 }
00151 
00152 struct PriorityCompare {
00153     PriorityCompare(SMILTime elapsed) : m_elapsed(elapsed) {}
00154     bool operator()(SVGSMILElement* a, SVGSMILElement* b)
00155     {
00156         // FIXME: This should also consider possible timing relations between the elements.
00157         SMILTime aBegin = a->intervalBegin();
00158         SMILTime bBegin = b->intervalBegin();
00159         // Frozen elements need to be prioritized based on their previous interval.
00160         aBegin = a->isFrozen() && m_elapsed < aBegin ? a->previousIntervalBegin() : aBegin;
00161         bBegin = b->isFrozen() && m_elapsed < bBegin ? b->previousIntervalBegin() : bBegin;
00162         if (aBegin == bBegin)
00163             return a->documentOrderIndex() < b->documentOrderIndex();
00164         return aBegin < bBegin;
00165     }
00166     SMILTime m_elapsed;
00167 };
00168 
00169 void SMILTimeContainer::sortByPriority(Vector<SVGSMILElement*>& smilElements, SMILTime elapsed)
00170 {
00171     if (m_documentOrderIndexesDirty)
00172         updateDocumentOrderIndexes();
00173     std::sort(smilElements.begin(), smilElements.end(), PriorityCompare(elapsed));
00174 }
00175     
00176 static bool applyOrderSortFunction(SVGSMILElement* a, SVGSMILElement* b)
00177 {
00178     if (!a->hasTagName(SVGNames::animateTransformTag) && b->hasTagName(SVGNames::animateTransformTag))
00179         return true;
00180     return false;
00181 }
00182     
00183 static void sortByApplyOrder(Vector<SVGSMILElement*>& smilElements)
00184 {
00185     std::sort(smilElements.begin(), smilElements.end(), applyOrderSortFunction);
00186 }
00187 
00188 String SMILTimeContainer::baseValueFor(ElementAttributePair key)
00189 {
00190     // FIXME: We wouldn't need to do this if we were keeping base values around properly in DOM.
00191     // Currently animation overwrites them so we need to save them somewhere.
00192     BaseValueMap::iterator it = m_savedBaseValues.find(key);
00193     if (it != m_savedBaseValues.end())
00194         return it->second;
00195     
00196     SVGElement* target = key.first;
00197     String attributeName = key.second;
00198     ASSERT(target);
00199     ASSERT(!attributeName.isEmpty());
00200     String baseValue;
00201     if (SVGAnimationElement::attributeIsCSS(attributeName)) {
00202         CSSComputedStyleDeclaration computedStyle(target);
00203         baseValue = computedStyle.getPropertyValue(cssPropertyID(attributeName));
00204     } else
00205         baseValue = target->getAttribute(attributeName);
00206     m_savedBaseValues.add(key, baseValue);
00207     return baseValue;
00208 }
00209       
00210 void SMILTimeContainer::updateAnimations(SMILTime elapsed)
00211 {
00212     SMILTime earliersFireTime = SMILTime::unresolved();
00213 
00214     Vector<SVGSMILElement*> toAnimate;
00215     copyToVector(m_scheduledAnimations, toAnimate);
00216     
00217     // Sort according to priority. Elements with later begin time have higher priority.
00218     // In case of a tie, document order decides. 
00219     // FIXME: This should also consider timing relationships between the elements. Dependents
00220     // have higher priority.
00221     sortByPriority(toAnimate, elapsed);
00222     
00223     // Calculate animation contributions.
00224     typedef HashMap<ElementAttributePair, SVGSMILElement*> ResultElementMap;
00225     ResultElementMap resultsElements;
00226     for (unsigned n = 0; n < toAnimate.size(); ++n) {
00227         SVGSMILElement* animation = toAnimate[n];
00228         ASSERT(animation->timeContainer() == this);
00229 
00230         SVGElement* targetElement = animation->targetElement();
00231         if (!targetElement)
00232             continue;
00233         String attributeName = animation->attributeName();
00234         if (attributeName.isEmpty()) {
00235             if (animation->hasTagName(SVGNames::animateMotionTag))
00236                 attributeName = SVGNames::animateMotionTag.localName();
00237             else
00238                 continue;
00239         }
00240         
00241         // Results are accumulated to the first animation that animates a particular element/attribute pair.
00242         ElementAttributePair key(targetElement, attributeName); 
00243         SVGSMILElement* resultElement = resultsElements.get(key);
00244         if (!resultElement) {
00245             resultElement = animation;
00246             resultElement->resetToBaseValue(baseValueFor(key));
00247             resultsElements.add(key, resultElement);
00248         }
00249 
00250         // This will calculate the contribution from the animation and add it to the resultsElement.
00251         animation->progress(elapsed, resultElement);
00252 
00253         SMILTime nextFireTime = animation->nextProgressTime();
00254         if (nextFireTime.isFinite())
00255             earliersFireTime = min(nextFireTime, earliersFireTime);
00256         else if (!animation->isContributing(elapsed)) {
00257             m_scheduledAnimations.remove(animation);
00258             if (m_scheduledAnimations.isEmpty())
00259                 m_savedBaseValues.clear();
00260         }
00261     }
00262     
00263     Vector<SVGSMILElement*> animationsToApply;
00264     ResultElementMap::iterator end = resultsElements.end();
00265     for (ResultElementMap::iterator it = resultsElements.begin(); it != end; ++it)
00266         animationsToApply.append(it->second);
00267 
00268     // Sort <animateTranform> to be the last one to be applied. <animate> may change transform attribute as
00269     // well (directly or indirectly by modifying <use> x/y) and this way transforms combine properly.
00270     sortByApplyOrder(animationsToApply);
00271     
00272     // Apply results to target elements.
00273     for (unsigned n = 0; n < animationsToApply.size(); ++n)
00274         animationsToApply[n]->applyResultsToTarget();
00275 
00276     startTimer(earliersFireTime, animationFrameDelay);
00277     
00278     Document::updateDocumentsRendering();
00279 }
00280 
00281 #endif
00282 }
00283 

KHTML

Skip menu "KHTML"
  • Main Page
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members
  • Related Pages

kdelibs

Skip menu "kdelibs"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • Kate
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • Kross
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Generated for kdelibs by doxygen 1.5.7
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal