KHTML
SMILTimeContainer.cpp
Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
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
00157 SMILTime aBegin = a->intervalBegin();
00158 SMILTime bBegin = b->intervalBegin();
00159
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
00191
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
00218
00219
00220
00221 sortByPriority(toAnimate, elapsed);
00222
00223
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
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
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
00269
00270 sortByApplyOrder(animationsToApply);
00271
00272
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