Remove the Timer parameters from timer callbacks
[WebKit-https.git] / Source / WebCore / replay / EventLoopInputDispatcher.cpp
1 /*
2  * Copyright (C) 2011-2013 University of Washington. All rights reserved.
3  * Copyright (C) 2014 Apple Inc. All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * 1.  Redistributions of source code must retain the above copyright
10  *     notice, this list of conditions and the following disclaimer.
11  * 2.  Redistributions in binary form must reproduce the above copyright
12  *     notice, this list of conditions and the following disclaimer in the
13  *     documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
16  * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
17  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
18  * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
19  * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
21  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
27
28 #include "config.h"
29 #include "EventLoopInputDispatcher.h"
30
31 #if ENABLE(WEB_REPLAY)
32
33 #include "Page.h"
34 #include "ReplayingInputCursor.h"
35 #include "WebReplayInputs.h"
36 #include <wtf/TemporaryChange.h>
37
38 #if !LOG_DISABLED
39 #include "Logging.h"
40 #include "SerializationMethods.h"
41 #include <replay/EncodedValue.h>
42 #include <wtf/text/CString.h>
43 #endif
44
45 namespace WebCore {
46
47 EventLoopInputDispatcher::EventLoopInputDispatcher(Page& page, ReplayingInputCursor& cursor, EventLoopInputDispatcherClient* client)
48     : m_page(page)
49     , m_client(client)
50     , m_cursor(cursor)
51     , m_timer(*this, &EventLoopInputDispatcher::timerFired)
52     , m_dispatching(false)
53     , m_running(false)
54     , m_speed(DispatchSpeed::FastForward)
55     , m_previousDispatchStartTime(0.0)
56     , m_previousInputTimestamp(0.0)
57 {
58     m_currentWork.input = nullptr;
59     m_currentWork.timestamp = 0.0;
60 }
61
62 void EventLoopInputDispatcher::run()
63 {
64     ASSERT(!m_running);
65     m_running = true;
66
67     LOG(WebReplay, "%-20s Starting dispatch of event loop inputs for page: %p\n", "ReplayEvents", &m_page);
68     dispatchInputSoon();
69 }
70
71 void EventLoopInputDispatcher::pause()
72 {
73     ASSERT(!m_dispatching);
74     ASSERT(m_running);
75     m_running = false;
76
77     LOG(WebReplay, "%-20s Pausing dispatch of event loop inputs for page: %p\n", "ReplayEvents", &m_page);
78     if (m_timer.isActive())
79         m_timer.stop();
80 }
81
82 void EventLoopInputDispatcher::timerFired()
83 {
84     dispatchInput();
85 }
86
87 void EventLoopInputDispatcher::dispatchInputSoon()
88 {
89     ASSERT(m_running);
90
91     // We may already have an input if replay was paused just before dispatching.
92     if (!m_currentWork.input)
93         m_currentWork = m_cursor.loadEventLoopInput();
94
95     if (m_timer.isActive())
96         m_timer.stop();
97
98     double waitInterval = 0;
99
100     if (m_speed == DispatchSpeed::RealTime) {
101         // The goal is to reproduce the dispatch delay between inputs as it was
102         // was observed during the recording. So, we need to compute how much time
103         // to wait such that the elapsed time plus the wait time will equal the
104         // observed delay between the previous and current input.
105
106         if (!m_previousInputTimestamp)
107             m_previousInputTimestamp = m_currentWork.timestamp;
108
109         double targetInterval = m_currentWork.timestamp - m_previousInputTimestamp;
110         double elapsed = monotonicallyIncreasingTime() - m_previousDispatchStartTime;
111         waitInterval = targetInterval - elapsed;
112     }
113
114     // A negative wait time means that dispatch took longer on replay than on
115     // capture. In this case, proceed without waiting at all.
116     if (waitInterval < 0)
117         waitInterval = 0;
118
119     if (waitInterval > 1000.0) {
120         LOG_ERROR("%-20s Tried to wait for over 1000 seconds before dispatching next event loop input; this is probably a bug.", "ReplayEvents");
121         waitInterval = 0;
122     }
123
124     LOG(WebReplay, "%-20s (WAIT: %.3f ms)", "ReplayEvents", waitInterval * 1000.0);
125     m_timer.startOneShot(waitInterval);
126 }
127
128 void EventLoopInputDispatcher::dispatchInput()
129 {
130     ASSERT(m_currentWork.input);
131     ASSERT(!m_dispatching);
132
133     if (m_speed == DispatchSpeed::RealTime) {
134         m_previousDispatchStartTime = monotonicallyIncreasingTime();
135         m_previousInputTimestamp = m_currentWork.timestamp;
136     }
137
138 #if !LOG_DISABLED
139     EncodedValue encodedInput = EncodingTraits<NondeterministicInputBase>::encodeValue(*m_currentWork.input);
140     String jsonString = encodedInput.asObject()->toJSONString();
141
142     LOG(WebReplay, "%-20s ----------------------------------------------", "ReplayEvents");
143     LOG(WebReplay, "%-20s >DISPATCH: %s %s\n", "ReplayEvents", m_currentWork.input->type().utf8().data(), jsonString.utf8().data());
144 #endif
145
146     m_client->willDispatchInput(*m_currentWork.input);
147     // Client could stop replay in the previous callback, so check again.
148     if (!m_running)
149         return;
150
151     {
152         TemporaryChange<bool> change(m_dispatching, true);
153         m_currentWork.input->dispatch(m_page.replayController());
154     }
155
156     EventLoopInputBase* dispatchedInput = m_currentWork.input;
157     m_currentWork.input = nullptr;
158
159     // Notify clients that the event was dispatched.
160     m_client->didDispatchInput(*dispatchedInput);
161     if (dispatchedInput->type() == InputTraits<EndSegmentSentinel>::type()) {
162         m_running = false;
163         m_dispatching = false;
164         m_client->didDispatchFinalInput();
165         return;
166     }
167
168     // Clients could stop replay during event dispatch, or from any callback above.
169     if (!m_running)
170         return;
171
172     dispatchInputSoon();
173 }
174
175 } // namespace WebCore
176
177 #endif // ENABLE(WEB_REPLAY)