PageRenderTime 56ms CodeModel.GetById 26ms RepoModel.GetById 1ms app.codeStats 0ms

/opensource.apple.com/source/WebCore/WebCore-1298.39/svg/animation/SMILTimeContainer.cpp

#
C++ | 347 lines | 274 code | 51 blank | 22 comment | 13 complexity | d6c82e7bfe98a8029ed60458d29324c1 MD5 | raw file
Possible License(s): MPL-2.0-no-copyleft-exception, GPL-2.0, BSD-3-Clause, GPL-3.0, MPL-2.0, LGPL-2.0, LGPL-2.1, CC-BY-SA-3.0, IPL-1.0, ISC, AGPL-1.0, AGPL-3.0, JSON, Apache-2.0, 0BSD
  1. <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
  2. "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
  3. <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
  4. <head>
  5. <title>SMILTimeContainer.cpp</title>
  6. <style type="text/css">
  7. .enscript-comment { font-style: italic; color: rgb(178,34,34); }
  8. .enscript-function-name { font-weight: bold; color: rgb(0,0,255); }
  9. .enscript-variable-name { font-weight: bold; color: rgb(184,134,11); }
  10. .enscript-keyword { font-weight: bold; color: rgb(160,32,240); }
  11. .enscript-reference { font-weight: bold; color: rgb(95,158,160); }
  12. .enscript-string { font-weight: bold; color: rgb(188,143,143); }
  13. .enscript-builtin { font-weight: bold; color: rgb(218,112,214); }
  14. .enscript-type { font-weight: bold; color: rgb(34,139,34); }
  15. .enscript-highlight { text-decoration: underline; color: 0; }
  16. </style>
  17. </head>
  18. <body id="top">
  19. <h1 style="margin:8px;" id="f1">SMILTimeContainer.cpp&nbsp;&nbsp;&nbsp;<span style="font-weight: normal; font-size: 0.5em;">[<a href="?txt">plain text</a>]</span></h1>
  20. <hr/>
  21. <div></div>
  22. <pre>
  23. <span class="enscript-comment">/*
  24. * Copyright (C) 2008 Apple Inc. All rights reserved.
  25. *
  26. * Redistribution and use in source and binary forms, with or without
  27. * modification, are permitted provided that the following conditions
  28. * are met:
  29. * 1. Redistributions of source code must retain the above copyright
  30. * notice, this list of conditions and the following disclaimer.
  31. * 2. Redistributions in binary form must reproduce the above copyright
  32. * notice, this list of conditions and the following disclaimer in the
  33. * documentation and/or other materials provided with the distribution.
  34. *
  35. * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
  36. * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  37. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  38. * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
  39. * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  40. * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  41. * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  42. * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
  43. * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  44. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  45. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  46. */</span>
  47. #<span class="enscript-reference">include</span> <span class="enscript-string">&quot;config.h&quot;</span>
  48. #<span class="enscript-reference">include</span> <span class="enscript-string">&quot;SMILTimeContainer.h&quot;</span>
  49. #<span class="enscript-reference">if</span> <span class="enscript-variable-name">ENABLE</span>(<span class="enscript-variable-name">SVG</span>)
  50. #<span class="enscript-reference">include</span> <span class="enscript-string">&quot;CSSComputedStyleDeclaration.h&quot;</span>
  51. #<span class="enscript-reference">include</span> <span class="enscript-string">&quot;CSSParser.h&quot;</span>
  52. #<span class="enscript-reference">include</span> <span class="enscript-string">&quot;Document.h&quot;</span>
  53. #<span class="enscript-reference">include</span> <span class="enscript-string">&quot;SVGAnimationElement.h&quot;</span>
  54. #<span class="enscript-reference">include</span> <span class="enscript-string">&quot;SVGNames.h&quot;</span>
  55. #<span class="enscript-reference">include</span> <span class="enscript-string">&quot;SVGSMILElement.h&quot;</span>
  56. #<span class="enscript-reference">include</span> <span class="enscript-string">&quot;SVGSVGElement.h&quot;</span>
  57. #<span class="enscript-reference">include</span> <span class="enscript-string">&lt;wtf/CurrentTime.h&gt;</span>
  58. using namespace std;
  59. namespace WebCore {
  60. <span class="enscript-type">static</span> <span class="enscript-type">const</span> <span class="enscript-type">double</span> animationFrameDelay = 0.025;
  61. <span class="enscript-function-name">SMILTimeContainer::SMILTimeContainer</span>(SVGSVGElement* owner)
  62. : m_beginTime(0)
  63. , m_pauseTime(0)
  64. , m_accumulatedPauseTime(0)
  65. , m_nextManualSampleTime(0)
  66. , m_documentOrderIndexesDirty(false)
  67. , m_timer(<span class="enscript-keyword">this</span>, &amp;SMILTimeContainer::timerFired)
  68. , m_ownerSVGElement(owner)
  69. {
  70. }
  71. #<span class="enscript-reference">if</span> !<span class="enscript-variable-name">ENABLE</span>(<span class="enscript-variable-name">SVG_ANIMATION</span>)
  72. <span class="enscript-type">void</span> <span class="enscript-function-name">SMILTimeContainer::begin</span>() {}
  73. <span class="enscript-type">void</span> <span class="enscript-function-name">SMILTimeContainer::pause</span>() {}
  74. <span class="enscript-type">void</span> <span class="enscript-function-name">SMILTimeContainer::resume</span>() {}
  75. SMILTime <span class="enscript-function-name">SMILTimeContainer::elapsed</span>() <span class="enscript-type">const</span> { <span class="enscript-keyword">return</span> 0; }
  76. <span class="enscript-type">bool</span> <span class="enscript-function-name">SMILTimeContainer::isPaused</span>() <span class="enscript-type">const</span> { <span class="enscript-keyword">return</span> false; }
  77. <span class="enscript-type">void</span> <span class="enscript-function-name">SMILTimeContainer::timerFired</span>(Timer&lt;SMILTimeContainer&gt;*) {}
  78. #<span class="enscript-reference">else</span>
  79. <span class="enscript-type">void</span> <span class="enscript-function-name">SMILTimeContainer::schedule</span>(SVGSMILElement* animation)
  80. {
  81. ASSERT(animation-&gt;timeContainer() == <span class="enscript-keyword">this</span>);
  82. SMILTime nextFireTime = animation-&gt;nextProgressTime();
  83. <span class="enscript-keyword">if</span> (!nextFireTime.isFinite())
  84. <span class="enscript-keyword">return</span>;
  85. m_scheduledAnimations.add(animation);
  86. startTimer(0);
  87. }
  88. <span class="enscript-type">void</span> <span class="enscript-function-name">SMILTimeContainer::unschedule</span>(SVGSMILElement* animation)
  89. {
  90. ASSERT(animation-&gt;timeContainer() == <span class="enscript-keyword">this</span>);
  91. m_scheduledAnimations.remove(animation);
  92. }
  93. SMILTime <span class="enscript-function-name">SMILTimeContainer::elapsed</span>() <span class="enscript-type">const</span>
  94. {
  95. <span class="enscript-keyword">if</span> (!m_beginTime)
  96. <span class="enscript-keyword">return</span> 0;
  97. <span class="enscript-keyword">return</span> currentTime() - m_beginTime - m_accumulatedPauseTime;
  98. }
  99. <span class="enscript-type">bool</span> <span class="enscript-function-name">SMILTimeContainer::isActive</span>() <span class="enscript-type">const</span>
  100. {
  101. <span class="enscript-keyword">return</span> m_beginTime &amp;&amp; !isPaused();
  102. }
  103. <span class="enscript-type">bool</span> <span class="enscript-function-name">SMILTimeContainer::isPaused</span>() <span class="enscript-type">const</span>
  104. {
  105. <span class="enscript-keyword">return</span> m_pauseTime;
  106. }
  107. <span class="enscript-type">void</span> <span class="enscript-function-name">SMILTimeContainer::begin</span>()
  108. {
  109. ASSERT(!m_beginTime);
  110. m_beginTime = currentTime();
  111. updateAnimations(0);
  112. }
  113. <span class="enscript-type">void</span> <span class="enscript-function-name">SMILTimeContainer::pause</span>()
  114. {
  115. <span class="enscript-keyword">if</span> (!m_beginTime)
  116. <span class="enscript-keyword">return</span>;
  117. ASSERT(!isPaused());
  118. m_pauseTime = currentTime();
  119. m_timer.stop();
  120. }
  121. <span class="enscript-type">void</span> <span class="enscript-function-name">SMILTimeContainer::resume</span>()
  122. {
  123. <span class="enscript-keyword">if</span> (!m_beginTime)
  124. <span class="enscript-keyword">return</span>;
  125. ASSERT(isPaused());
  126. m_accumulatedPauseTime += currentTime() - m_pauseTime;
  127. m_pauseTime = 0;
  128. startTimer(0);
  129. }
  130. <span class="enscript-type">void</span> <span class="enscript-function-name">SMILTimeContainer::startTimer</span>(SMILTime fireTime, SMILTime minimumDelay)
  131. {
  132. <span class="enscript-keyword">if</span> (!m_beginTime || isPaused())
  133. <span class="enscript-keyword">return</span>;
  134. <span class="enscript-keyword">if</span> (!fireTime.isFinite())
  135. <span class="enscript-keyword">return</span>;
  136. SMILTime delay = max(fireTime - elapsed(), minimumDelay);
  137. m_timer.startOneShot(delay.value());
  138. }
  139. <span class="enscript-type">void</span> <span class="enscript-function-name">SMILTimeContainer::timerFired</span>(Timer&lt;SMILTimeContainer&gt;*)
  140. {
  141. ASSERT(m_beginTime);
  142. ASSERT(!m_pauseTime);
  143. SMILTime elapsed = <span class="enscript-keyword">this</span>-&gt;elapsed();
  144. updateAnimations(elapsed);
  145. }
  146. <span class="enscript-type">void</span> <span class="enscript-function-name">SMILTimeContainer::updateDocumentOrderIndexes</span>()
  147. {
  148. <span class="enscript-type">unsigned</span> timingElementCount = 0;
  149. <span class="enscript-keyword">for</span> (Node* node = m_ownerSVGElement; node; node = node-&gt;traverseNextNode(m_ownerSVGElement)) {
  150. <span class="enscript-keyword">if</span> (SVGSMILElement::isSMILElement(node))
  151. static_cast&lt;SVGSMILElement*&gt;(node)-&gt;setDocumentOrderIndex(timingElementCount++);
  152. }
  153. m_documentOrderIndexesDirty = false;
  154. }
  155. <span class="enscript-type">struct</span> PriorityCompare {
  156. PriorityCompare(SMILTime elapsed) : m_elapsed(elapsed) {}
  157. <span class="enscript-type">bool</span> <span class="enscript-keyword">operator</span>()(SVGSMILElement* a, SVGSMILElement* b)
  158. {
  159. <span class="enscript-comment">// FIXME: This should also consider possible timing relations between the elements.
  160. </span> SMILTime aBegin = a-&gt;intervalBegin();
  161. SMILTime bBegin = b-&gt;intervalBegin();
  162. <span class="enscript-comment">// Frozen elements need to be prioritized based on their previous interval.
  163. </span> aBegin = a-&gt;isFrozen() &amp;&amp; m_elapsed &lt; aBegin ? a-&gt;previousIntervalBegin() : aBegin;
  164. bBegin = b-&gt;isFrozen() &amp;&amp; m_elapsed &lt; bBegin ? b-&gt;previousIntervalBegin() : bBegin;
  165. <span class="enscript-keyword">if</span> (aBegin == bBegin)
  166. <span class="enscript-keyword">return</span> a-&gt;documentOrderIndex() &lt; b-&gt;documentOrderIndex();
  167. <span class="enscript-keyword">return</span> aBegin &lt; bBegin;
  168. }
  169. SMILTime m_elapsed;
  170. };
  171. <span class="enscript-type">void</span> <span class="enscript-function-name">SMILTimeContainer::sortByPriority</span>(Vector&lt;SVGSMILElement*&gt;&amp; smilElements, SMILTime elapsed)
  172. {
  173. <span class="enscript-keyword">if</span> (m_documentOrderIndexesDirty)
  174. updateDocumentOrderIndexes();
  175. <span class="enscript-reference">std</span>::sort(smilElements.begin(), smilElements.end(), PriorityCompare(elapsed));
  176. }
  177. <span class="enscript-type">static</span> <span class="enscript-type">bool</span> <span class="enscript-function-name">applyOrderSortFunction</span>(SVGSMILElement* a, SVGSMILElement* b)
  178. {
  179. <span class="enscript-keyword">if</span> (!a-&gt;hasTagName(SVGNames::animateTransformTag) &amp;&amp; b-&gt;hasTagName(SVGNames::animateTransformTag))
  180. <span class="enscript-keyword">return</span> true;
  181. <span class="enscript-keyword">return</span> false;
  182. }
  183. <span class="enscript-type">static</span> <span class="enscript-type">void</span> <span class="enscript-function-name">sortByApplyOrder</span>(Vector&lt;SVGSMILElement*&gt;&amp; smilElements)
  184. {
  185. <span class="enscript-reference">std</span>::sort(smilElements.begin(), smilElements.end(), applyOrderSortFunction);
  186. }
  187. String <span class="enscript-function-name">SMILTimeContainer::baseValueFor</span>(ElementAttributePair key)
  188. {
  189. <span class="enscript-comment">// FIXME: We wouldn't need to do this if we were keeping base values around properly in DOM.
  190. </span> <span class="enscript-comment">// Currently animation overwrites them so we need to save them somewhere.
  191. </span> <span class="enscript-reference">BaseValueMap</span>::iterator it = m_savedBaseValues.find(key);
  192. <span class="enscript-keyword">if</span> (it != m_savedBaseValues.end())
  193. <span class="enscript-keyword">return</span> it-&gt;second;
  194. SVGElement* targetElement = key.first;
  195. QualifiedName attributeName = key.second;
  196. ASSERT(targetElement);
  197. ASSERT(attributeName != anyQName());
  198. String baseValue;
  199. <span class="enscript-keyword">if</span> (SVGAnimationElement::isTargetAttributeCSSProperty(targetElement, attributeName))
  200. baseValue = computedStyle(targetElement)-&gt;getPropertyValue(cssPropertyID(attributeName.localName()));
  201. <span class="enscript-keyword">else</span>
  202. baseValue = targetElement-&gt;getAttribute(attributeName);
  203. m_savedBaseValues.add(key, baseValue);
  204. <span class="enscript-keyword">return</span> baseValue;
  205. }
  206. <span class="enscript-type">void</span> <span class="enscript-function-name">SMILTimeContainer::sampleAnimationAtTime</span>(<span class="enscript-type">const</span> String&amp; elementId, <span class="enscript-type">double</span> newTime)
  207. {
  208. ASSERT(m_beginTime);
  209. ASSERT(!isPaused());
  210. <span class="enscript-comment">// Fast-forward to the time DRT wants to sample
  211. </span> m_timer.stop();
  212. m_nextSamplingTarget = elementId;
  213. m_nextManualSampleTime = newTime;
  214. updateAnimations(elapsed());
  215. }
  216. <span class="enscript-type">void</span> <span class="enscript-function-name">SMILTimeContainer::updateAnimations</span>(SMILTime elapsed)
  217. {
  218. SMILTime earliersFireTime = SMILTime::unresolved();
  219. Vector&lt;SVGSMILElement*&gt; toAnimate;
  220. copyToVector(m_scheduledAnimations, toAnimate);
  221. <span class="enscript-keyword">if</span> (m_nextManualSampleTime) {
  222. SMILTime samplingDiff;
  223. <span class="enscript-keyword">for</span> (<span class="enscript-type">unsigned</span> n = 0; n &lt; toAnimate.size(); ++n) {
  224. SVGSMILElement* animation = toAnimate[n];
  225. ASSERT(animation-&gt;timeContainer() == <span class="enscript-keyword">this</span>);
  226. SVGElement* targetElement = animation-&gt;targetElement();
  227. <span class="enscript-comment">// FIXME: This should probably be using getIdAttribute instead of idForStyleResolution.
  228. </span> <span class="enscript-keyword">if</span> (!targetElement || !targetElement-&gt;hasID() || targetElement-&gt;idForStyleResolution() != m_nextSamplingTarget)
  229. <span class="enscript-keyword">continue</span>;
  230. samplingDiff = animation-&gt;intervalBegin();
  231. <span class="enscript-keyword">break</span>;
  232. }
  233. elapsed = SMILTime(m_nextManualSampleTime) + samplingDiff;
  234. m_nextManualSampleTime = 0;
  235. }
  236. <span class="enscript-comment">// Sort according to priority. Elements with later begin time have higher priority.
  237. </span> <span class="enscript-comment">// In case of a tie, document order decides.
  238. </span> <span class="enscript-comment">// FIXME: This should also consider timing relationships between the elements. Dependents
  239. </span> <span class="enscript-comment">// have higher priority.
  240. </span> sortByPriority(toAnimate, elapsed);
  241. <span class="enscript-comment">// Calculate animation contributions.
  242. </span> <span class="enscript-type">typedef</span> HashMap&lt;ElementAttributePair, RefPtr&lt;SVGSMILElement&gt; &gt; ResultElementMap;
  243. ResultElementMap resultsElements;
  244. <span class="enscript-keyword">for</span> (<span class="enscript-type">unsigned</span> n = 0; n &lt; toAnimate.size(); ++n) {
  245. SVGSMILElement* animation = toAnimate[n];
  246. ASSERT(animation-&gt;timeContainer() == <span class="enscript-keyword">this</span>);
  247. SVGElement* targetElement = animation-&gt;targetElement();
  248. <span class="enscript-keyword">if</span> (!targetElement)
  249. <span class="enscript-keyword">continue</span>;
  250. QualifiedName attributeName = animation-&gt;attributeName();
  251. <span class="enscript-keyword">if</span> (attributeName == anyQName()) {
  252. <span class="enscript-keyword">if</span> (animation-&gt;hasTagName(SVGNames::animateMotionTag))
  253. attributeName = SVGNames::animateMotionTag;
  254. <span class="enscript-keyword">else</span>
  255. <span class="enscript-keyword">continue</span>;
  256. }
  257. <span class="enscript-comment">// Results are accumulated to the first animation that animates a particular element/attribute pair.
  258. </span> ElementAttributePair key(targetElement, attributeName);
  259. SVGSMILElement* resultElement = resultsElements.get(key).get();
  260. <span class="enscript-keyword">if</span> (!resultElement) {
  261. <span class="enscript-keyword">if</span> (!animation-&gt;hasValidAttributeType())
  262. <span class="enscript-keyword">continue</span>;
  263. resultElement = animation;
  264. resultElement-&gt;resetToBaseValue(baseValueFor(key));
  265. resultsElements.add(key, resultElement);
  266. }
  267. <span class="enscript-comment">// This will calculate the contribution from the animation and add it to the resultsElement.
  268. </span> animation-&gt;progress(elapsed, resultElement);
  269. SMILTime nextFireTime = animation-&gt;nextProgressTime();
  270. <span class="enscript-keyword">if</span> (nextFireTime.isFinite())
  271. earliersFireTime = min(nextFireTime, earliersFireTime);
  272. <span class="enscript-keyword">else</span> <span class="enscript-keyword">if</span> (!animation-&gt;isContributing(elapsed)) {
  273. m_scheduledAnimations.remove(animation);
  274. <span class="enscript-keyword">if</span> (m_scheduledAnimations.isEmpty())
  275. m_savedBaseValues.clear();
  276. }
  277. }
  278. Vector&lt;SVGSMILElement*&gt; animationsToApply;
  279. <span class="enscript-reference">ResultElementMap</span>::iterator end = resultsElements.end();
  280. <span class="enscript-keyword">for</span> (ResultElementMap::iterator it = resultsElements.begin(); it != end; ++it)
  281. animationsToApply.append(it-&gt;second.get());
  282. <span class="enscript-comment">// Sort &lt;animateTranform&gt; to be the last one to be applied. &lt;animate&gt; may change transform attribute as
  283. </span> <span class="enscript-comment">// well (directly or indirectly by modifying &lt;use&gt; x/y) and this way transforms combine properly.
  284. </span> sortByApplyOrder(animationsToApply);
  285. <span class="enscript-comment">// Apply results to target elements.
  286. </span> <span class="enscript-keyword">for</span> (<span class="enscript-type">unsigned</span> n = 0; n &lt; animationsToApply.size(); ++n)
  287. animationsToApply[n]-&gt;applyResultsToTarget();
  288. startTimer(earliersFireTime, animationFrameDelay);
  289. <span class="enscript-reference">Document</span>::updateStyleForAllDocuments();
  290. }
  291. #<span class="enscript-reference">endif</span>
  292. }
  293. #<span class="enscript-reference">endif</span> // <span class="enscript-variable-name">ENABLE</span>(<span class="enscript-variable-name">SVG</span>)
  294. </pre>
  295. <hr />
  296. </body></html>