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

KHTML

  • sources
  • kde-4.12
  • kdelibs
  • 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 
37 using namespace std;
38 
39 namespace WebCore {
40 
41 static const double animationFrameDelay = 0.025;
42 
43 SMILTimeContainer::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)
54 void SMILTimeContainer::begin() {}
55 void SMILTimeContainer::pause() {}
56 void SMILTimeContainer::resume() {}
57 SMILTime SMILTimeContainer::elapsed() const { return 0; }
58 bool SMILTimeContainer::isPaused() const { return false; }
59 void SMILTimeContainer::timerFired(Timer<SMILTimeContainer>*) {}
60 #else
61 
62 void 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 
72 void SMILTimeContainer::unschedule(SVGSMILElement* animation)
73 {
74  ASSERT(animation->timeContainer() == this);
75 
76  m_scheduledAnimations.remove(animation);
77 }
78 
79 SMILTime SMILTimeContainer::elapsed() const
80 {
81  if (!m_beginTime)
82  return 0;
83  return currentTime() - m_beginTime - m_accumulatedPauseTime;
84 }
85 
86 bool SMILTimeContainer::isActive() const
87 {
88  return m_beginTime && !isPaused();
89 }
90 
91 bool SMILTimeContainer::isPaused() const
92 {
93  return m_pauseTime;
94 }
95 
96 void SMILTimeContainer::begin()
97 {
98  ASSERT(!m_beginTime);
99  m_beginTime = currentTime();
100  updateAnimations(0);
101 }
102 
103 void SMILTimeContainer::pause()
104 {
105  if (!m_beginTime)
106  return;
107  ASSERT(!isPaused());
108  m_pauseTime = currentTime();
109  m_timer.stop();
110 }
111 
112 void 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 
122 void 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 
134 void SMILTimeContainer::timerFired(Timer<SMILTimeContainer>*)
135 {
136  ASSERT(m_beginTime);
137  ASSERT(!m_pauseTime);
138  SMILTime elapsed = this->elapsed();
139  updateAnimations(elapsed);
140 }
141 
142 void 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 
152 struct 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 
169 void 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 
176 static 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 
183 static void sortByApplyOrder(Vector<SVGSMILElement*>& smilElements)
184 {
185  std::sort(smilElements.begin(), smilElements.end(), applyOrderSortFunction);
186 }
187 
188 String 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 
210 void 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 
WebCore::SVGNames::animateTransformTag
DOM::QualifiedName animateTransformTag
Definition: SVGNames.cpp:28
SMILTimeContainer.h
SVGSMILElement.h
SVGSVGElement.h
WebCore::animationFrameDelay
static const double animationFrameDelay
Definition: SMILTimeContainer.cpp:41
DOM::DOMString::find
int find(const QChar c, int start=0) const
Definition: dom_string.cpp:154
SVGAnimationElement.h
WebCore::String
DOM::DOMString String
Definition: PlatformString.h:8
end
const KShortcut & end()
WebCore::SVGNames::animateMotionTag
DOM::QualifiedName animateMotionTag
Definition: SVGNames.cpp:27
This file is part of the KDE documentation.
Documentation copyright © 1996-2014 The KDE developers.
Generated on Tue Oct 14 2014 22:51:22 by doxygen 1.8.7 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 API Reference

Skip menu "kdelibs 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
  • kjsembed
  •   WTF
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUnitConversion
  • KUtils
  • Nepomuk
  • Nepomuk-Core
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver

Search



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