2 * Copyright (C) 2011 Google Inc. All Rights Reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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.
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.
27 #include "core/dom/ScriptedAnimationController.h"
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"
41 std::pair<EventTarget*, StringImpl*> eventTargetKey(const Event* event)
43 return std::make_pair(event->target(), event->type().impl());
46 ScriptedAnimationController::ScriptedAnimationController(Document* document)
47 : m_document(document)
53 ScriptedAnimationController::~ScriptedAnimationController()
57 void ScriptedAnimationController::trace(Visitor* visitor)
60 visitor->trace(m_document);
61 visitor->trace(m_eventQueue);
62 visitor->trace(m_mediaQueryListListeners);
63 visitor->trace(m_perFrameEvents);
67 void ScriptedAnimationController::suspend()
72 void ScriptedAnimationController::resume()
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)
78 scheduleAnimationIfNeeded();
81 ScriptedAnimationController::CallbackId ScriptedAnimationController::registerCallback(PassOwnPtr<RequestAnimationFrameCallback> callback)
83 ScriptedAnimationController::CallbackId id = ++m_nextCallbackId;
84 callback->m_cancelled = false;
86 m_callbacks.append(callback);
87 scheduleAnimationIfNeeded();
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);
97 void ScriptedAnimationController::cancelCallback(CallbackId id)
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);
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()
122 void ScriptedAnimationController::dispatchEvents()
124 WillBeHeapVector<RefPtrWillBeMember<Event> > events;
125 events.swap(m_eventQueue);
126 m_perFrameEvents.clear();
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);
136 eventTarget->dispatchEvent(events[i]);
138 InspectorInstrumentation::didRemoveEvent(eventTarget, events[i].get());
142 void ScriptedAnimationController::executeCallbacks(double monotonicTimeNow)
144 // dispatchEvents() runs script which can cause the document to be destroyed.
148 double highResNowMs = 1000.0 * m_document->loader()->timing()->monotonicTimeToZeroBasedDocumentTime(monotonicTimeNow);
149 double legacyHighResNowMs = 1000.0 * m_document->loader()->timing()->monotonicTimeToPseudoWallTime(monotonicTimeNow);
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);
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);
165 callback->handleEvent(highResNowMs);
166 InspectorInstrumentation::didFireAnimationFrame(cookie);
167 TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"), "UpdateCounters", "data", InspectorUpdateCountersEvent::data());
171 m_callbacksToInvoke.clear();
174 void ScriptedAnimationController::callMediaQueryListListeners()
176 MediaQueryListListeners listeners;
177 listeners.swap(m_mediaQueryListListeners);
179 for (MediaQueryListListeners::const_iterator it = listeners.begin(), end = listeners.end();
185 void ScriptedAnimationController::serviceScriptedAnimations(double monotonicTimeNow)
187 if (!m_callbacks.size() && !m_eventQueue.size() && !m_mediaQueryListListeners.size())
193 RefPtrWillBeRawPtr<ScriptedAnimationController> protect(this);
195 callMediaQueryListListeners();
197 executeCallbacks(monotonicTimeNow);
199 scheduleAnimationIfNeeded();
202 void ScriptedAnimationController::enqueueEvent(PassRefPtrWillBeRawPtr<Event> event)
204 InspectorInstrumentation::didEnqueueEvent(event->target(), event.get());
205 m_eventQueue.append(event);
206 scheduleAnimationIfNeeded();
209 void ScriptedAnimationController::enqueuePerFrameEvent(PassRefPtrWillBeRawPtr<Event> event)
211 if (!m_perFrameEvents.add(eventTargetKey(event.get())).isNewEntry)
216 void ScriptedAnimationController::enqueueMediaQueryChangeListeners(WillBeHeapVector<RefPtrWillBeMember<MediaQueryListListener> >& listeners)
218 for (size_t i = 0; i < listeners.size(); ++i) {
219 m_mediaQueryListListeners.add(listeners[i]);
221 scheduleAnimationIfNeeded();
224 void ScriptedAnimationController::scheduleAnimationIfNeeded()
232 if (!m_callbacks.size() && !m_eventQueue.size() && !m_mediaQueryListListeners.size())
235 if (FrameView* frameView = m_document->view())
236 frameView->scheduleAnimation();