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