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"
38 #include "platform/Logging.h"
42 std::pair<EventTarget*, StringImpl*> eventTargetKey(const Event* event)
44 return std::make_pair(event->target(), event->type().impl());
47 ScriptedAnimationController::ScriptedAnimationController(Document* document)
48 : m_document(document)
54 ScriptedAnimationController::~ScriptedAnimationController()
58 void ScriptedAnimationController::trace(Visitor* visitor)
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);
70 void ScriptedAnimationController::suspend()
75 void ScriptedAnimationController::resume()
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)
81 scheduleAnimationIfNeeded();
84 void ScriptedAnimationController::dispatchEventsAndCallbacksForPrinting()
86 dispatchEvents(EventNames::MediaQueryListEvent);
87 callMediaQueryListListeners();
90 ScriptedAnimationController::CallbackId ScriptedAnimationController::registerCallback(RequestAnimationFrameCallback* callback)
92 ScriptedAnimationController::CallbackId id = ++m_nextCallbackId;
93 callback->m_cancelled = false;
95 m_callbacks.append(callback);
96 scheduleAnimationIfNeeded();
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);
106 void ScriptedAnimationController::cancelCallback(CallbackId id)
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);
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()
131 void ScriptedAnimationController::dispatchEvents(const AtomicString& eventInterfaceFilter)
133 WillBeHeapVector<RefPtrWillBeMember<Event> > events;
134 if (eventInterfaceFilter.isEmpty()) {
135 events.swap(m_eventQueue);
136 m_perFrameEvents.clear();
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());
144 remaining.append(event.release());
147 remaining.swap(m_eventQueue);
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);
159 eventTarget->dispatchEvent(events[i]);
161 InspectorInstrumentation::didRemoveEvent(eventTarget, events[i].get());
165 void ScriptedAnimationController::executeCallbacks(double monotonicTimeNow)
167 // dispatchEvents() runs script which can cause the document to be destroyed.
171 double highResNowMs = 1000.0 * m_document->loader()->timing()->monotonicTimeToZeroBasedDocumentTime(monotonicTimeNow);
172 double legacyHighResNowMs = 1000.0 * m_document->loader()->timing()->monotonicTimeToPseudoWallTime(monotonicTimeNow);
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);
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);
188 callback->handleEvent(highResNowMs);
189 InspectorInstrumentation::didFireAnimationFrame(cookie);
190 TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"), "UpdateCounters", "data", InspectorUpdateCountersEvent::data());
194 m_callbacksToInvoke.clear();
197 void ScriptedAnimationController::callMediaQueryListListeners()
199 MediaQueryListListeners listeners;
200 listeners.swap(m_mediaQueryListListeners);
202 for (MediaQueryListListeners::const_iterator it = listeners.begin(), end = listeners.end();
204 (*it)->notifyMediaQueryChanged();
208 void ScriptedAnimationController::serviceScriptedAnimations(double monotonicTimeNow)
210 if (!m_callbacks.size() && !m_eventQueue.size() && !m_mediaQueryListListeners.size())
216 RefPtrWillBeRawPtr<ScriptedAnimationController> protect(this);
218 callMediaQueryListListeners();
220 executeCallbacks(monotonicTimeNow);
222 scheduleAnimationIfNeeded();
225 void ScriptedAnimationController::enqueueEvent(PassRefPtrWillBeRawPtr<Event> event)
227 InspectorInstrumentation::didEnqueueEvent(event->target(), event.get());
228 m_eventQueue.append(event);
229 scheduleAnimationIfNeeded();
232 void ScriptedAnimationController::enqueuePerFrameEvent(PassRefPtrWillBeRawPtr<Event> event)
234 if (!m_perFrameEvents.add(eventTargetKey(event.get())).isNewEntry)
239 void ScriptedAnimationController::enqueueMediaQueryChangeListeners(WillBeHeapVector<RefPtrWillBeMember<MediaQueryListListener> >& listeners)
241 for (size_t i = 0; i < listeners.size(); ++i) {
242 m_mediaQueryListListeners.add(listeners[i]);
244 scheduleAnimationIfNeeded();
247 void ScriptedAnimationController::scheduleAnimationIfNeeded()
255 if (!m_callbacks.size() && !m_eventQueue.size() && !m_mediaQueryListListeners.size())
258 if (FrameView* frameView = m_document->view())
259 frameView->scheduleAnimation();