Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / core / dom / ScriptedAnimationController.cpp
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 "core/dom/ScriptedAnimationController.h"
28
29 #include "core/css/MediaQueryListListener.h"
30 #include "core/dom/Document.h"
31 #include "core/dom/RequestAnimationFrameCallback.h"
32 #include "core/events/Event.h"
33 #include "core/frame/LocalDOMWindow.h"
34 #include "core/frame/FrameView.h"
35 #include "core/inspector/InspectorInstrumentation.h"
36 #include "core/inspector/InspectorTraceEvents.h"
37 #include "core/loader/DocumentLoader.h"
38
39 namespace blink {
40
41 std::pair<EventTarget*, StringImpl*> eventTargetKey(const Event* event)
42 {
43     return std::make_pair(event->target(), event->type().impl());
44 }
45
46 ScriptedAnimationController::ScriptedAnimationController(Document* document)
47     : m_document(document)
48     , m_nextCallbackId(0)
49     , m_suspendCount(0)
50 {
51 }
52
53 ScriptedAnimationController::~ScriptedAnimationController()
54 {
55 }
56
57 void ScriptedAnimationController::trace(Visitor* visitor)
58 {
59 #if ENABLE(OILPAN)
60     visitor->trace(m_document);
61     visitor->trace(m_eventQueue);
62     visitor->trace(m_mediaQueryListListeners);
63     visitor->trace(m_perFrameEvents);
64 #endif
65 }
66
67 void ScriptedAnimationController::suspend()
68 {
69     ++m_suspendCount;
70 }
71
72 void ScriptedAnimationController::resume()
73 {
74     // It would be nice to put an ASSERT(m_suspendCount > 0) here, but in WK1 resume() can be called
75     // even when suspend hasn't (if a tab was created in the background).
76     if (m_suspendCount > 0)
77         --m_suspendCount;
78     scheduleAnimationIfNeeded();
79 }
80
81 ScriptedAnimationController::CallbackId ScriptedAnimationController::registerCallback(PassOwnPtr<RequestAnimationFrameCallback> callback)
82 {
83     ScriptedAnimationController::CallbackId id = ++m_nextCallbackId;
84     callback->m_cancelled = false;
85     callback->m_id = id;
86     m_callbacks.append(callback);
87     scheduleAnimationIfNeeded();
88
89     TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"), "RequestAnimationFrame", "data", InspectorAnimationFrameEvent::data(m_document, id));
90     TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline.stack"), "CallStack", "stack", InspectorCallStackEvent::currentCallStack());
91     // FIXME(361045): remove InspectorInstrumentation calls once DevTools Timeline migrates to tracing.
92     InspectorInstrumentation::didRequestAnimationFrame(m_document, id);
93
94     return id;
95 }
96
97 void ScriptedAnimationController::cancelCallback(CallbackId id)
98 {
99     for (size_t i = 0; i < m_callbacks.size(); ++i) {
100         if (m_callbacks[i]->m_id == id) {
101             TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"), "CancelAnimationFrame", "data", InspectorAnimationFrameEvent::data(m_document, id));
102             TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline.stack"), "CallStack", "stack", InspectorCallStackEvent::currentCallStack());
103             // FIXME(361045): remove InspectorInstrumentation calls once DevTools Timeline migrates to tracing.
104             InspectorInstrumentation::didCancelAnimationFrame(m_document, id);
105             m_callbacks.remove(i);
106             return;
107         }
108     }
109     for (size_t i = 0; i < m_callbacksToInvoke.size(); ++i) {
110         if (m_callbacksToInvoke[i]->m_id == id) {
111             TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"), "CancelAnimationFrame", "data", InspectorAnimationFrameEvent::data(m_document, id));
112             TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline.stack"), "CallStack", "stack", InspectorCallStackEvent::currentCallStack());
113             // FIXME(361045): remove InspectorInstrumentation calls once DevTools Timeline migrates to tracing.
114             InspectorInstrumentation::didCancelAnimationFrame(m_document, id);
115             m_callbacksToInvoke[i]->m_cancelled = true;
116             // will be removed at the end of executeCallbacks()
117             return;
118         }
119     }
120 }
121
122 void ScriptedAnimationController::dispatchEvents()
123 {
124     WillBeHeapVector<RefPtrWillBeMember<Event> > events;
125     events.swap(m_eventQueue);
126     m_perFrameEvents.clear();
127
128     for (size_t i = 0; i < events.size(); ++i) {
129         EventTarget* eventTarget = events[i]->target();
130         // FIXME: we should figure out how to make dispatchEvent properly virtual to avoid
131         // special casting window.
132         // FIXME: We should not fire events for nodes that are no longer in the tree.
133         if (LocalDOMWindow* window = eventTarget->toDOMWindow())
134             window->dispatchEvent(events[i], nullptr);
135         else
136             eventTarget->dispatchEvent(events[i]);
137
138         InspectorInstrumentation::didRemoveEvent(eventTarget, events[i].get());
139     }
140 }
141
142 void ScriptedAnimationController::executeCallbacks(double monotonicTimeNow)
143 {
144     // dispatchEvents() runs script which can cause the document to be destroyed.
145     if (!m_document)
146         return;
147
148     double highResNowMs = 1000.0 * m_document->loader()->timing()->monotonicTimeToZeroBasedDocumentTime(monotonicTimeNow);
149     double legacyHighResNowMs = 1000.0 * m_document->loader()->timing()->monotonicTimeToPseudoWallTime(monotonicTimeNow);
150
151     // First, generate a list of callbacks to consider.  Callbacks registered from this point
152     // on are considered only for the "next" frame, not this one.
153     ASSERT(m_callbacksToInvoke.isEmpty());
154     m_callbacksToInvoke.swap(m_callbacks);
155
156     for (size_t i = 0; i < m_callbacksToInvoke.size(); ++i) {
157         RequestAnimationFrameCallback* callback = m_callbacksToInvoke[i].get();
158         if (!callback->m_cancelled) {
159             TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"), "FireAnimationFrame", "data", InspectorAnimationFrameEvent::data(m_document, callback->m_id));
160             // FIXME(361045): remove InspectorInstrumentation calls once DevTools Timeline migrates to tracing.
161             InspectorInstrumentationCookie cookie = InspectorInstrumentation::willFireAnimationFrame(m_document, callback->m_id);
162             if (callback->m_useLegacyTimeBase)
163                 callback->handleEvent(legacyHighResNowMs);
164             else
165                 callback->handleEvent(highResNowMs);
166             InspectorInstrumentation::didFireAnimationFrame(cookie);
167             TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"), "UpdateCounters", "data", InspectorUpdateCountersEvent::data());
168         }
169     }
170
171     m_callbacksToInvoke.clear();
172 }
173
174 void ScriptedAnimationController::callMediaQueryListListeners()
175 {
176     MediaQueryListListeners listeners;
177     listeners.swap(m_mediaQueryListListeners);
178
179     for (MediaQueryListListeners::const_iterator it = listeners.begin(), end = listeners.end();
180         it != end; ++it) {
181         (*it)->call();
182     }
183 }
184
185 void ScriptedAnimationController::serviceScriptedAnimations(double monotonicTimeNow)
186 {
187     if (!m_callbacks.size() && !m_eventQueue.size() && !m_mediaQueryListListeners.size())
188         return;
189
190     if (m_suspendCount)
191         return;
192
193     RefPtrWillBeRawPtr<ScriptedAnimationController> protect(this);
194
195     callMediaQueryListListeners();
196     dispatchEvents();
197     executeCallbacks(monotonicTimeNow);
198
199     scheduleAnimationIfNeeded();
200 }
201
202 void ScriptedAnimationController::enqueueEvent(PassRefPtrWillBeRawPtr<Event> event)
203 {
204     InspectorInstrumentation::didEnqueueEvent(event->target(), event.get());
205     m_eventQueue.append(event);
206     scheduleAnimationIfNeeded();
207 }
208
209 void ScriptedAnimationController::enqueuePerFrameEvent(PassRefPtrWillBeRawPtr<Event> event)
210 {
211     if (!m_perFrameEvents.add(eventTargetKey(event.get())).isNewEntry)
212         return;
213     enqueueEvent(event);
214 }
215
216 void ScriptedAnimationController::enqueueMediaQueryChangeListeners(WillBeHeapVector<RefPtrWillBeMember<MediaQueryListListener> >& listeners)
217 {
218     for (size_t i = 0; i < listeners.size(); ++i) {
219         m_mediaQueryListListeners.add(listeners[i]);
220     }
221     scheduleAnimationIfNeeded();
222 }
223
224 void ScriptedAnimationController::scheduleAnimationIfNeeded()
225 {
226     if (!m_document)
227         return;
228
229     if (m_suspendCount)
230         return;
231
232     if (!m_callbacks.size() && !m_eventQueue.size() && !m_mediaQueryListListeners.size())
233         return;
234
235     if (FrameView* frameView = m_document->view())
236         frameView->scheduleAnimation();
237 }
238
239 }