• Skip to content
  • Skip to link menu
  • KDE API Reference
  • kdelibs-4.14.38 API Reference
  • KDE Home
  • Contact Us
 

KHTML

  • khtml
  • svg
  • animation
SMILTimeContainer.cpp
Go to the documentation of this file.
1/*
2 * Copyright (C) 2008 Apple Inc. All Rights Reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#include "config.h"
27#include "SMILTimeContainer.h"
28
29#include "CSSComputedStyleDeclaration.h"
30#include "CSSParser.h"
31#include "Document.h"
32#include "SVGAnimationElement.h"
33#include "SVGSMILElement.h"
34#include "SVGSVGElement.h"
35#include "SystemTime.h"
36
37using namespace std;
38
39namespace WebCore {
40
41static const double animationFrameDelay = 0.025;
42
43SMILTimeContainer::SMILTimeContainer(SVGSVGElement* owner)
44 : m_beginTime(0)
45 , m_pauseTime(0)
46 , m_accumulatedPauseTime(0)
47 , m_documentOrderIndexesDirty(false)
48 , m_timer(this, &SMILTimeContainer::timerFired)
49 , m_ownerSVGElement(owner)
50{
51}
52
53#if !ENABLE(SVG_ANIMATION)
54void SMILTimeContainer::begin() {}
55void SMILTimeContainer::pause() {}
56void SMILTimeContainer::resume() {}
57SMILTime SMILTimeContainer::elapsed() const { return 0; }
58bool SMILTimeContainer::isPaused() const { return false; }
59void SMILTimeContainer::timerFired(Timer<SMILTimeContainer>*) {}
60#else
61
62void SMILTimeContainer::schedule(SVGSMILElement* animation)
63{
64 ASSERT(animation->timeContainer() == this);
65 SMILTime nextFireTime = animation->nextProgressTime();
66 if (!nextFireTime.isFinite())
67 return;
68 m_scheduledAnimations.add(animation);
69 startTimer(0);
70}
71
72void SMILTimeContainer::unschedule(SVGSMILElement* animation)
73{
74 ASSERT(animation->timeContainer() == this);
75
76 m_scheduledAnimations.remove(animation);
77}
78
79SMILTime SMILTimeContainer::elapsed() const
80{
81 if (!m_beginTime)
82 return 0;
83 return currentTime() - m_beginTime - m_accumulatedPauseTime;
84}
85
86bool SMILTimeContainer::isActive() const
87{
88 return m_beginTime && !isPaused();
89}
90
91bool SMILTimeContainer::isPaused() const
92{
93 return m_pauseTime;
94}
95
96void SMILTimeContainer::begin()
97{
98 ASSERT(!m_beginTime);
99 m_beginTime = currentTime();
100 updateAnimations(0);
101}
102
103void SMILTimeContainer::pause()
104{
105 if (!m_beginTime)
106 return;
107 ASSERT(!isPaused());
108 m_pauseTime = currentTime();
109 m_timer.stop();
110}
111
112void SMILTimeContainer::resume()
113{
114 if (!m_beginTime)
115 return;
116 ASSERT(isPaused());
117 m_accumulatedPauseTime += currentTime() - m_pauseTime;
118 m_pauseTime = 0;
119 startTimer(0);
120}
121
122void SMILTimeContainer::startTimer(SMILTime fireTime, SMILTime minimumDelay)
123{
124 if (!m_beginTime || isPaused())
125 return;
126
127 if (!fireTime.isFinite())
128 return;
129
130 SMILTime delay = max(fireTime - elapsed(), minimumDelay);
131 m_timer.startOneShot(delay.value());
132}
133
134void SMILTimeContainer::timerFired(Timer<SMILTimeContainer>*)
135{
136 ASSERT(m_beginTime);
137 ASSERT(!m_pauseTime);
138 SMILTime elapsed = this->elapsed();
139 updateAnimations(elapsed);
140}
141
142void SMILTimeContainer::updateDocumentOrderIndexes()
143{
144 unsigned timingElementCount = 0;
145 for (Node* node = m_ownerSVGElement; node; node = node->traverseNextNode(m_ownerSVGElement)) {
146 if (SVGSMILElement::isSMILElement(node))
147 static_cast<SVGSMILElement*>(node)->setDocumentOrderIndex(timingElementCount++);
148 }
149 m_documentOrderIndexesDirty = false;
150}
151
152struct PriorityCompare {
153 PriorityCompare(SMILTime elapsed) : m_elapsed(elapsed) {}
154 bool operator()(SVGSMILElement* a, SVGSMILElement* b)
155 {
156 // FIXME: This should also consider possible timing relations between the elements.
157 SMILTime aBegin = a->intervalBegin();
158 SMILTime bBegin = b->intervalBegin();
159 // Frozen elements need to be prioritized based on their previous interval.
160 aBegin = a->isFrozen() && m_elapsed < aBegin ? a->previousIntervalBegin() : aBegin;
161 bBegin = b->isFrozen() && m_elapsed < bBegin ? b->previousIntervalBegin() : bBegin;
162 if (aBegin == bBegin)
163 return a->documentOrderIndex() < b->documentOrderIndex();
164 return aBegin < bBegin;
165 }
166 SMILTime m_elapsed;
167};
168
169void SMILTimeContainer::sortByPriority(Vector<SVGSMILElement*>& smilElements, SMILTime elapsed)
170{
171 if (m_documentOrderIndexesDirty)
172 updateDocumentOrderIndexes();
173 std::sort(smilElements.begin(), smilElements.end(), PriorityCompare(elapsed));
174}
175
176static bool applyOrderSortFunction(SVGSMILElement* a, SVGSMILElement* b)
177{
178 if (!a->hasTagName(SVGNames::animateTransformTag) && b->hasTagName(SVGNames::animateTransformTag))
179 return true;
180 return false;
181}
182
183static void sortByApplyOrder(Vector<SVGSMILElement*>& smilElements)
184{
185 std::sort(smilElements.begin(), smilElements.end(), applyOrderSortFunction);
186}
187
188String SMILTimeContainer::baseValueFor(ElementAttributePair key)
189{
190 // FIXME: We wouldn't need to do this if we were keeping base values around properly in DOM.
191 // Currently animation overwrites them so we need to save them somewhere.
192 BaseValueMap::iterator it = m_savedBaseValues.find(key);
193 if (it != m_savedBaseValues.end())
194 return it->second;
195
196 SVGElement* target = key.first;
197 String attributeName = key.second;
198 ASSERT(target);
199 ASSERT(!attributeName.isEmpty());
200 String baseValue;
201 if (SVGAnimationElement::attributeIsCSS(attributeName)) {
202 CSSComputedStyleDeclaration computedStyle(target);
203 baseValue = computedStyle.getPropertyValue(cssPropertyID(attributeName));
204 } else
205 baseValue = target->getAttribute(attributeName);
206 m_savedBaseValues.add(key, baseValue);
207 return baseValue;
208}
209
210void SMILTimeContainer::updateAnimations(SMILTime elapsed)
211{
212 SMILTime earliersFireTime = SMILTime::unresolved();
213
214 Vector<SVGSMILElement*> toAnimate;
215 copyToVector(m_scheduledAnimations, toAnimate);
216
217 // Sort according to priority. Elements with later begin time have higher priority.
218 // In case of a tie, document order decides.
219 // FIXME: This should also consider timing relationships between the elements. Dependents
220 // have higher priority.
221 sortByPriority(toAnimate, elapsed);
222
223 // Calculate animation contributions.
224 typedef HashMap<ElementAttributePair, SVGSMILElement*> ResultElementMap;
225 ResultElementMap resultsElements;
226 for (unsigned n = 0; n < toAnimate.size(); ++n) {
227 SVGSMILElement* animation = toAnimate[n];
228 ASSERT(animation->timeContainer() == this);
229
230 SVGElement* targetElement = animation->targetElement();
231 if (!targetElement)
232 continue;
233 String attributeName = animation->attributeName();
234 if (attributeName.isEmpty()) {
235 if (animation->hasTagName(SVGNames::animateMotionTag))
236 attributeName = SVGNames::animateMotionTag.localName();
237 else
238 continue;
239 }
240
241 // Results are accumulated to the first animation that animates a particular element/attribute pair.
242 ElementAttributePair key(targetElement, attributeName);
243 SVGSMILElement* resultElement = resultsElements.get(key);
244 if (!resultElement) {
245 resultElement = animation;
246 resultElement->resetToBaseValue(baseValueFor(key));
247 resultsElements.add(key, resultElement);
248 }
249
250 // This will calculate the contribution from the animation and add it to the resultsElement.
251 animation->progress(elapsed, resultElement);
252
253 SMILTime nextFireTime = animation->nextProgressTime();
254 if (nextFireTime.isFinite())
255 earliersFireTime = min(nextFireTime, earliersFireTime);
256 else if (!animation->isContributing(elapsed)) {
257 m_scheduledAnimations.remove(animation);
258 if (m_scheduledAnimations.isEmpty())
259 m_savedBaseValues.clear();
260 }
261 }
262
263 Vector<SVGSMILElement*> animationsToApply;
264 ResultElementMap::iterator end = resultsElements.end();
265 for (ResultElementMap::iterator it = resultsElements.begin(); it != end; ++it)
266 animationsToApply.append(it->second);
267
268 // Sort <animateTranform> to be the last one to be applied. <animate> may change transform attribute as
269 // well (directly or indirectly by modifying <use> x/y) and this way transforms combine properly.
270 sortByApplyOrder(animationsToApply);
271
272 // Apply results to target elements.
273 for (unsigned n = 0; n < animationsToApply.size(); ++n)
274 animationsToApply[n]->applyResultsToTarget();
275
276 startTimer(earliersFireTime, animationFrameDelay);
277
278 Document::updateDocumentsRendering();
279}
280
281#endif
282}
283
SMILTimeContainer.h
SVGAnimationElement.h
SVGSMILElement.h
SVGSVGElement.h
DOM::DOMString::find
int find(const QChar c, int start=0) const
Definition: dom_string.cpp:154
end
const KShortcut & end()
WebCore
Definition: CSSHelper.h:7
WebCore::String
DOM::DOMString String
Definition: PlatformString.h:8
WebCore::animationFrameDelay
static const double animationFrameDelay
Definition: SMILTimeContainer.cpp:41
This file is part of the KDE documentation.
Documentation copyright © 1996-2023 The KDE developers.
Generated on Mon Feb 20 2023 00:00:00 by doxygen 1.9.6 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

KHTML

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

kdelibs-4.14.38 API Reference

Skip menu "kdelibs-4.14.38 API Reference"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDEWebKit
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUnitConversion
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal