1 /*
2 * Copyright (C) 2011 Google 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. AND ITS CONTRIBUTORS ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
15 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
16 * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY
17 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
18 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
19 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
20 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
22 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23 *
24 */
25
26 #include "config.h"
27 #include "ScriptedAnimationController.h"
28
29 #if ENABLE(REQUEST_ANIMATION_FRAME)
30
31 #include "Document.h"
32 #include "Element.h"
33 #include "FrameView.h"
34 #include "RequestAnimationFrameCallback.h"
35
36 namespace WebCore {
37
ScriptedAnimationController(Document * document)38 ScriptedAnimationController::ScriptedAnimationController(Document* document)
39 : m_document(document)
40 , m_nextCallbackId(0)
41 , m_suspendCount(0)
42 {
43 }
44
suspend()45 void ScriptedAnimationController::suspend()
46 {
47 ++m_suspendCount;
48 }
49
resume()50 void ScriptedAnimationController::resume()
51 {
52 --m_suspendCount;
53 if (!m_suspendCount && m_callbacks.size())
54 if (FrameView* fv = m_document->view())
55 fv->scheduleAnimation();
56 }
57
registerCallback(PassRefPtr<RequestAnimationFrameCallback> callback,Element * animationElement)58 ScriptedAnimationController::CallbackId ScriptedAnimationController::registerCallback(PassRefPtr<RequestAnimationFrameCallback> callback, Element* animationElement)
59 {
60 ScriptedAnimationController::CallbackId id = m_nextCallbackId++;
61 callback->m_firedOrCancelled = false;
62 callback->m_id = id;
63 callback->m_element = animationElement;
64 m_callbacks.append(callback);
65 if (!m_suspendCount)
66 if (FrameView* view = m_document->view())
67 view->scheduleAnimation();
68 return id;
69 }
70
cancelCallback(CallbackId id)71 void ScriptedAnimationController::cancelCallback(CallbackId id)
72 {
73 for (size_t i = 0; i < m_callbacks.size(); ++i) {
74 if (m_callbacks[i]->m_id == id) {
75 m_callbacks[i]->m_firedOrCancelled = true;
76 m_callbacks.remove(i);
77 return;
78 }
79 }
80 }
81
serviceScriptedAnimations(DOMTimeStamp time)82 void ScriptedAnimationController::serviceScriptedAnimations(DOMTimeStamp time)
83 {
84 if (!m_callbacks.size() || m_suspendCount)
85 return;
86 // We want to run the callback for all elements in the document that have registered
87 // for a callback and that are visible. Running the callbacks can cause new callbacks
88 // to be registered, existing callbacks to be cancelled, and elements to gain or lose
89 // visibility so this code has to iterate carefully.
90
91 // FIXME: Currently, this code doesn't do any visibility tests beyond checking display:
92
93 // First, generate a list of callbacks to consider. Callbacks registered from this point
94 // on are considered only for the "next" frame, not this one.
95 CallbackList callbacks(m_callbacks);
96
97 // Firing the callback may cause the visibility of other elements to change. To avoid
98 // missing any callbacks, we keep iterating through the list of candiate callbacks and firing
99 // them until nothing new becomes visible.
100 bool firedCallback;
101 do {
102 firedCallback = false;
103 // A previous iteration may have invalidated style (or layout). Update styles for each iteration
104 // for now since all we check is the existence of a renderer.
105 m_document->updateStyleIfNeeded();
106 for (size_t i = 0; i < callbacks.size(); ++i) {
107 RequestAnimationFrameCallback* callback = callbacks[i].get();
108 if (!callback->m_firedOrCancelled && (!callback->m_element || callback->m_element->renderer())) {
109 callback->m_firedOrCancelled = true;
110 callback->handleEvent(time);
111 firedCallback = true;
112 callbacks.remove(i);
113 break;
114 }
115 }
116 } while (firedCallback);
117
118 // Remove any callbacks we fired from the list of pending callbacks.
119 for (size_t i = 0; i < m_callbacks.size();) {
120 if (m_callbacks[i]->m_firedOrCancelled)
121 m_callbacks.remove(i);
122 else
123 ++i;
124 }
125
126 if (m_callbacks.size())
127 if (FrameView* view = m_document->view())
128 view->scheduleAnimation();
129 }
130
131 }
132
133 #endif
134
135