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