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 |