| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright (C) 2008 Apple Inc. All rights reserved. | 2 * Copyright (C) 2008 Apple Inc. All rights reserved. |
| 3 * | 3 * |
| 4 * Redistribution and use in source and binary forms, with or without | 4 * Redistribution and use in source and binary forms, with or without |
| 5 * modification, are permitted provided that the following conditions | 5 * modification, are permitted provided that the following conditions |
| 6 * are met: | 6 * are met: |
| 7 * 1. Redistributions of source code must retain the above copyright | 7 * 1. Redistributions of source code must retain the above copyright |
| 8 * notice, this list of conditions and the following disclaimer. | 8 * notice, this list of conditions and the following disclaimer. |
| 9 * 2. Redistributions in binary form must reproduce the above copyright | 9 * 2. Redistributions in binary form must reproduce the above copyright |
| 10 * notice, this list of conditions and the following disclaimer in the | 10 * notice, this list of conditions and the following disclaimer in the |
| (...skipping 18 matching lines...) Expand all Loading... |
| 29 #if ENABLE(SVG) | 29 #if ENABLE(SVG) |
| 30 #include "Document.h" | 30 #include "Document.h" |
| 31 #include "SVGNames.h" | 31 #include "SVGNames.h" |
| 32 #include "SVGSMILElement.h" | 32 #include "SVGSMILElement.h" |
| 33 #include "SVGSVGElement.h" | 33 #include "SVGSVGElement.h" |
| 34 #include <wtf/CurrentTime.h> | 34 #include <wtf/CurrentTime.h> |
| 35 | 35 |
| 36 using namespace std; | 36 using namespace std; |
| 37 | 37 |
| 38 namespace WebCore { | 38 namespace WebCore { |
| 39 | 39 |
| 40 static const double animationFrameDelay = 0.025; | 40 static const double animationFrameDelay = 0.025; |
| 41 | 41 |
| 42 SMILTimeContainer::SMILTimeContainer(SVGSVGElement* owner) | 42 SMILTimeContainer::SMILTimeContainer(SVGSVGElement* owner) |
| 43 : m_beginTime(0) | 43 : m_beginTime(0) |
| 44 , m_pauseTime(0) | 44 , m_pauseTime(0) |
| 45 , m_accumulatedPauseTime(0) | 45 , m_accumulatedPauseTime(0) |
| 46 , m_presetStartTime(0) | 46 , m_presetStartTime(0) |
| 47 , m_documentOrderIndexesDirty(false) | 47 , m_documentOrderIndexesDirty(false) |
| 48 , m_timer(this, &SMILTimeContainer::timerFired) | 48 , m_timer(this, &SMILTimeContainer::timerFired) |
| 49 , m_ownerSVGElement(owner) | 49 , m_ownerSVGElement(owner) |
| 50 #ifndef NDEBUG |
| 51 , m_preventScheduledAnimationsChanges(false) |
| 52 #endif |
| 50 { | 53 { |
| 51 } | 54 } |
| 52 | 55 |
| 53 void SMILTimeContainer::schedule(SVGSMILElement* animation) | 56 SMILTimeContainer::~SMILTimeContainer() |
| 57 { |
| 58 #ifndef NDEBUG |
| 59 ASSERT(!m_preventScheduledAnimationsChanges); |
| 60 #endif |
| 61 deleteAllValues(m_scheduledAnimations); |
| 62 } |
| 63 |
| 64 void SMILTimeContainer::schedule(SVGSMILElement* animation, SVGElement* target,
const QualifiedName& attributeName) |
| 54 { | 65 { |
| 55 ASSERT(animation->timeContainer() == this); | 66 ASSERT(animation->timeContainer() == this); |
| 67 ASSERT(target); |
| 68 ASSERT(animation->hasValidAttributeName()); |
| 69 |
| 70 #ifndef NDEBUG |
| 71 ASSERT(!m_preventScheduledAnimationsChanges); |
| 72 #endif |
| 73 |
| 74 ElementAttributePair key(target, attributeName); |
| 75 AnimationsVector* scheduled = m_scheduledAnimations.get(key); |
| 76 if (!scheduled) { |
| 77 scheduled = new AnimationsVector(); |
| 78 m_scheduledAnimations.set(key, scheduled); |
| 79 } |
| 80 ASSERT(!scheduled->contains(animation)); |
| 81 scheduled->append(animation); |
| 82 |
| 56 SMILTime nextFireTime = animation->nextProgressTime(); | 83 SMILTime nextFireTime = animation->nextProgressTime(); |
| 57 if (!nextFireTime.isFinite()) | 84 if (nextFireTime.isFinite()) |
| 58 return; | 85 notifyIntervalsChanged(); |
| 59 m_scheduledAnimations.add(animation); | |
| 60 startTimer(0); | |
| 61 } | 86 } |
| 62 | 87 |
| 63 void SMILTimeContainer::unschedule(SVGSMILElement* animation) | 88 void SMILTimeContainer::unschedule(SVGSMILElement* animation, SVGElement* target
, const QualifiedName& attributeName) |
| 64 { | 89 { |
| 65 ASSERT(animation->timeContainer() == this); | 90 ASSERT(animation->timeContainer() == this); |
| 66 | 91 |
| 67 m_scheduledAnimations.remove(animation); | 92 #ifndef NDEBUG |
| 93 ASSERT(!m_preventScheduledAnimationsChanges); |
| 94 #endif |
| 95 |
| 96 ElementAttributePair key(target, attributeName); |
| 97 AnimationsVector* scheduled = m_scheduledAnimations.get(key); |
| 98 ASSERT(scheduled); |
| 99 size_t idx = scheduled->find(animation); |
| 100 ASSERT(idx != notFound); |
| 101 scheduled->remove(idx); |
| 102 } |
| 103 |
| 104 void SMILTimeContainer::notifyIntervalsChanged() |
| 105 { |
| 106 // Schedule updateAnimations() to be called asynchronously so multiple inter
vals |
| 107 // can change with updateAnimations() only called once at the end. |
| 108 startTimer(0); |
| 68 } | 109 } |
| 69 | 110 |
| 70 SMILTime SMILTimeContainer::elapsed() const | 111 SMILTime SMILTimeContainer::elapsed() const |
| 71 { | 112 { |
| 72 if (!m_beginTime) | 113 if (!m_beginTime) |
| 73 return 0; | 114 return 0; |
| 74 return currentTime() - m_beginTime - m_accumulatedPauseTime; | 115 return currentTime() - m_beginTime - m_accumulatedPauseTime; |
| 75 } | 116 } |
| 76 | 117 |
| 77 bool SMILTimeContainer::isActive() const | 118 bool SMILTimeContainer::isActive() const |
| 78 { | 119 { |
| 79 return m_beginTime && !isPaused(); | 120 return m_beginTime && !isPaused(); |
| 80 } | 121 } |
| 81 | 122 |
| 82 bool SMILTimeContainer::isPaused() const | 123 bool SMILTimeContainer::isPaused() const |
| 83 { | 124 { |
| 84 return m_pauseTime; | 125 return m_pauseTime; |
| 85 } | 126 } |
| 86 | 127 |
| 87 bool SMILTimeContainer::isStarted() const | 128 bool SMILTimeContainer::isStarted() const |
| 88 { | 129 { |
| 89 return m_beginTime; | 130 return m_beginTime; |
| 90 } | 131 } |
| 91 | 132 |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 137 if (m_beginTime) | 178 if (m_beginTime) |
| 138 m_timer.stop(); | 179 m_timer.stop(); |
| 139 | 180 |
| 140 double now = currentTime(); | 181 double now = currentTime(); |
| 141 m_beginTime = now - time.value(); | 182 m_beginTime = now - time.value(); |
| 142 | 183 |
| 143 m_accumulatedPauseTime = 0; | 184 m_accumulatedPauseTime = 0; |
| 144 if (m_pauseTime) | 185 if (m_pauseTime) |
| 145 m_pauseTime = now; | 186 m_pauseTime = now; |
| 146 | 187 |
| 147 Vector<SVGSMILElement*> toReset; | 188 #ifndef NDEBUG |
| 148 copyToVector(m_scheduledAnimations, toReset); | 189 m_preventScheduledAnimationsChanges = true; |
| 149 for (unsigned n = 0; n < toReset.size(); ++n) | 190 #endif |
| 150 toReset[n]->reset(); | 191 GroupedAnimationsMap::iterator end = m_scheduledAnimations.end(); |
| 192 for (GroupedAnimationsMap::iterator it = m_scheduledAnimations.begin(); it !
= end; ++it) { |
| 193 AnimationsVector* scheduled = it->second; |
| 194 unsigned size = scheduled->size(); |
| 195 for (unsigned n = 0; n < size; n++) |
| 196 scheduled->at(n)->reset(); |
| 197 } |
| 198 #ifndef NDEBUG |
| 199 m_preventScheduledAnimationsChanges = false; |
| 200 #endif |
| 151 | 201 |
| 152 updateAnimations(time, true); | 202 updateAnimations(time, true); |
| 153 } | 203 } |
| 154 | 204 |
| 155 void SMILTimeContainer::startTimer(SMILTime fireTime, SMILTime minimumDelay) | 205 void SMILTimeContainer::startTimer(SMILTime fireTime, SMILTime minimumDelay) |
| 156 { | 206 { |
| 157 if (!m_beginTime || isPaused()) | 207 if (!m_beginTime || isPaused()) |
| 158 return; | 208 return; |
| 159 | 209 |
| 160 if (!fireTime.isFinite()) | 210 if (!fireTime.isFinite()) |
| 161 return; | 211 return; |
| 162 | 212 |
| 163 SMILTime delay = max(fireTime - elapsed(), minimumDelay); | 213 SMILTime delay = max(fireTime - elapsed(), minimumDelay); |
| 164 m_timer.startOneShot(delay.value()); | 214 m_timer.startOneShot(delay.value()); |
| 165 } | 215 } |
| 166 | 216 |
| 167 void SMILTimeContainer::timerFired(Timer<SMILTimeContainer>*) | 217 void SMILTimeContainer::timerFired(Timer<SMILTimeContainer>*) |
| 168 { | 218 { |
| 169 ASSERT(m_beginTime); | 219 ASSERT(m_beginTime); |
| 170 ASSERT(!m_pauseTime); | 220 ASSERT(!m_pauseTime); |
| 171 updateAnimations(elapsed()); | 221 updateAnimations(elapsed()); |
| 172 } | 222 } |
| (...skipping 27 matching lines...) Expand all Loading... |
| 200 | 250 |
| 201 void SMILTimeContainer::sortByPriority(Vector<SVGSMILElement*>& smilElements, SM
ILTime elapsed) | 251 void SMILTimeContainer::sortByPriority(Vector<SVGSMILElement*>& smilElements, SM
ILTime elapsed) |
| 202 { | 252 { |
| 203 if (m_documentOrderIndexesDirty) | 253 if (m_documentOrderIndexesDirty) |
| 204 updateDocumentOrderIndexes(); | 254 updateDocumentOrderIndexes(); |
| 205 std::sort(smilElements.begin(), smilElements.end(), PriorityCompare(elapsed)
); | 255 std::sort(smilElements.begin(), smilElements.end(), PriorityCompare(elapsed)
); |
| 206 } | 256 } |
| 207 | 257 |
| 208 void SMILTimeContainer::updateAnimations(SMILTime elapsed, bool seekToTime) | 258 void SMILTimeContainer::updateAnimations(SMILTime elapsed, bool seekToTime) |
| 209 { | 259 { |
| 210 SMILTime earliersFireTime = SMILTime::unresolved(); | 260 SMILTime earliestFireTime = SMILTime::unresolved(); |
| 211 | 261 |
| 212 Vector<SVGSMILElement*> toAnimate; | 262 #ifndef NDEBUG |
| 213 copyToVector(m_scheduledAnimations, toAnimate); | 263 // This boolean will catch any attempts to schedule/unschedule scheduledAnim
ations during this critical section. |
| 264 // Similarly, any elements removed will unschedule themselves, so this will
catch modification of animationsToApply. |
| 265 m_preventScheduledAnimationsChanges = true; |
| 266 #endif |
| 214 | 267 |
| 215 // Sort according to priority. Elements with later begin time have higher pr
iority. | 268 AnimationsVector animationsToApply; |
| 216 // In case of a tie, document order decides. | 269 GroupedAnimationsMap::iterator end = m_scheduledAnimations.end(); |
| 217 // FIXME: This should also consider timing relationships between the element
s. Dependents | 270 for (GroupedAnimationsMap::iterator it = m_scheduledAnimations.begin(); it !
= end; ++it) { |
| 218 // have higher priority. | 271 AnimationsVector* scheduled = it->second; |
| 219 sortByPriority(toAnimate, elapsed); | |
| 220 | 272 |
| 221 // Calculate animation contributions. | 273 // Sort according to priority. Elements with later begin time have highe
r priority. |
| 222 typedef pair<SVGElement*, QualifiedName> ElementAttributePair; | 274 // In case of a tie, document order decides. |
| 223 typedef HashMap<ElementAttributePair, SVGSMILElement*> ResultElementMap; | 275 // FIXME: This should also consider timing relationships between the ele
ments. Dependents |
| 224 ResultElementMap resultsElements; | 276 // have higher priority. |
| 225 for (unsigned n = 0; n < toAnimate.size(); ++n) { | 277 sortByPriority(*scheduled, elapsed); |
| 226 SVGSMILElement* animation = toAnimate[n]; | |
| 227 ASSERT(animation->timeContainer() == this); | |
| 228 | 278 |
| 229 SVGElement* targetElement = animation->targetElement(); | 279 SVGSMILElement* resultElement = 0; |
| 230 if (!targetElement) | 280 unsigned size = scheduled->size(); |
| 231 continue; | 281 for (unsigned n = 0; n < size; n++) { |
| 282 SVGSMILElement* animation = scheduled->at(n); |
| 283 ASSERT(animation->timeContainer() == this); |
| 284 ASSERT(animation->targetElement()); |
| 285 ASSERT(animation->hasValidAttributeName()); |
| 232 | 286 |
| 233 QualifiedName attributeName = animation->attributeName(); | 287 // Results are accumulated to the first animation that animates and
contributes to a particular element/attribute pair. |
| 234 if (attributeName == anyQName()) { | 288 if (!resultElement) { |
| 235 if (animation->hasTagName(SVGNames::animateMotionTag)) | 289 if (!animation->hasValidAttributeType()) |
| 236 attributeName = SVGNames::animateMotionTag; | 290 continue; |
| 237 else | 291 resultElement = animation; |
| 238 continue; | 292 } |
| 293 |
| 294 // This will calculate the contribution from the animation and add i
t to the resultsElement. |
| 295 if (!animation->progress(elapsed, resultElement, seekToTime) && resu
ltElement == animation) |
| 296 resultElement = 0; |
| 297 |
| 298 SMILTime nextFireTime = animation->nextProgressTime(); |
| 299 if (nextFireTime.isFinite()) |
| 300 earliestFireTime = min(nextFireTime, earliestFireTime); |
| 239 } | 301 } |
| 240 | 302 |
| 241 // Results are accumulated to the first animation that animates and cont
ributes to a particular element/attribute pair. | 303 if (resultElement) |
| 242 ElementAttributePair key(targetElement, attributeName); | 304 animationsToApply.append(resultElement); |
| 243 SVGSMILElement* resultElement = resultsElements.get(key); | |
| 244 if (!resultElement) { | |
| 245 if (!animation->hasValidAttributeType()) | |
| 246 continue; | |
| 247 resultElement = animation; | |
| 248 } else | |
| 249 ASSERT(resultElement != animation); | |
| 250 | |
| 251 // This will calculate the contribution from the animation and add it to
the resultsElement. | |
| 252 if (animation->progress(elapsed, resultElement, seekToTime) && resultEle
ment == animation) | |
| 253 resultsElements.add(key, resultElement); | |
| 254 | |
| 255 SMILTime nextFireTime = animation->nextProgressTime(); | |
| 256 if (nextFireTime.isFinite()) | |
| 257 earliersFireTime = min(nextFireTime, earliersFireTime); | |
| 258 } | 305 } |
| 259 | 306 |
| 260 unsigned resultsToApplySize = resultsElements.size(); | 307 unsigned animationsToApplySize = animationsToApply.size(); |
| 261 if (!resultsToApplySize) { | 308 if (!animationsToApplySize) { |
| 262 startTimer(earliersFireTime, animationFrameDelay); | 309 #ifndef NDEBUG |
| 310 m_preventScheduledAnimationsChanges = false; |
| 311 #endif |
| 312 startTimer(earliestFireTime, animationFrameDelay); |
| 263 return; | 313 return; |
| 264 } | 314 } |
| 265 | 315 |
| 266 // Apply results to target elements. | 316 // Apply results to target elements. |
| 267 ResultElementMap::iterator end = resultsElements.end(); | 317 for (unsigned i = 0; i < animationsToApplySize; ++i) |
| 268 for (ResultElementMap::iterator it = resultsElements.begin(); it != end; ++i
t) | 318 animationsToApply[i]->applyResultsToTarget(); |
| 269 it->second->applyResultsToTarget(); | |
| 270 | 319 |
| 271 startTimer(earliersFireTime, animationFrameDelay); | 320 #ifndef NDEBUG |
| 321 m_preventScheduledAnimationsChanges = false; |
| 322 #endif |
| 323 |
| 324 startTimer(earliestFireTime, animationFrameDelay); |
| 272 Document::updateStyleForAllDocuments(); | 325 Document::updateStyleForAllDocuments(); |
| 273 } | 326 } |
| 274 | 327 |
| 275 } | 328 } |
| 276 | 329 |
| 277 #endif // ENABLE(SVG) | 330 #endif // ENABLE(SVG) |
| OLD | NEW |