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 "ReplayInputTypes.h" 35#include "ReplayingInputCursor.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 45namespace WebCore { 46 47EventLoopInputDispatcher::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_runningInput(nullptr) 53 , m_dispatching(false) 54 , m_running(false) 55 , m_speed(DispatchSpeed::FastForward) 56 , m_previousDispatchStartTime(0.0) 57 , m_previousInputTimestamp(0.0) 58{ 59} 60 61void EventLoopInputDispatcher::run() 62{ 63 ASSERT(!m_running); 64 m_running = true; 65 66 LOG(WebReplay, "%-20s Starting dispatch of event loop inputs for page: %p\n", "ReplayEvents", &m_page); 67 dispatchInputSoon(); 68} 69 70void EventLoopInputDispatcher::pause() 71{ 72 ASSERT(!m_dispatching); 73 ASSERT(m_running); 74 m_running = false; 75 76 LOG(WebReplay, "%-20s Pausing dispatch of event loop inputs for page: %p\n", "ReplayEvents", &m_page); 77 if (m_timer.isActive()) 78 m_timer.stop(); 79} 80 81void EventLoopInputDispatcher::timerFired(Timer<EventLoopInputDispatcher>*) 82{ 83 dispatchInput(); 84} 85 86void EventLoopInputDispatcher::dispatchInputSoon() 87{ 88 ASSERT(m_running); 89 90 // We may already have an input if replay was paused just before dispatching. 91 if (!m_runningInput) 92 m_runningInput = static_cast<EventLoopInputBase*>(m_cursor.uncheckedLoadInput(InputQueue::EventLoopInput)); 93 94 if (m_timer.isActive()) 95 m_timer.stop(); 96 97 double waitInterval = 0; 98 99 if (m_speed == DispatchSpeed::RealTime) { 100 // The goal is to reproduce the dispatch delay between inputs as it was 101 // was observed during the recording. So, we need to compute how much time 102 // to wait such that the elapsed time plus the wait time will equal the 103 // observed delay between the previous and current input. 104 105 if (!m_previousInputTimestamp) 106 m_previousInputTimestamp = m_runningInput->timestamp(); 107 108 double targetInterval = m_runningInput->timestamp() - m_previousInputTimestamp; 109 double elapsed = monotonicallyIncreasingTime() - m_previousDispatchStartTime; 110 waitInterval = targetInterval - elapsed; 111 } 112 113 // A negative wait time means that dispatch took longer on replay than on 114 // capture. In this case, proceed without waiting at all. 115 if (waitInterval < 0) 116 waitInterval = 0; 117 118 if (waitInterval > 1000.0) { 119 LOG_ERROR("%-20s Tried to wait for over 1000 seconds before dispatching next event loop input; this is probably a bug.", "ReplayEvents"); 120 waitInterval = 0; 121 } 122 123 LOG(WebReplay, "%-20s (WAIT: %.3f ms)", "ReplayEvents", waitInterval * 1000.0); 124 m_timer.startOneShot(waitInterval); 125} 126 127void EventLoopInputDispatcher::dispatchInput() 128{ 129 ASSERT(m_runningInput); 130 ASSERT(!m_dispatching); 131 132 if (m_speed == DispatchSpeed::RealTime) { 133 m_previousDispatchStartTime = monotonicallyIncreasingTime(); 134 m_previousInputTimestamp = m_runningInput->timestamp(); 135 } 136 137#if !LOG_DISABLED 138 EncodedValue encodedInput = EncodingTraits<NondeterministicInputBase>::encodeValue(*m_runningInput); 139 String jsonString = encodedInput.asObject()->toJSONString(); 140 141 LOG(WebReplay, "%-20s ----------------------------------------------", "ReplayEvents"); 142 LOG(WebReplay, "%-20s >DISPATCH: %s %s\n", "ReplayEvents", m_runningInput->type().string().utf8().data(), jsonString.utf8().data()); 143#endif 144 145 m_client->willDispatchInput(*m_runningInput); 146 // Client could stop replay in the previous callback, so check again. 147 if (!m_running) 148 return; 149 150 { 151 TemporaryChange<bool> change(m_dispatching, true); 152 m_runningInput->dispatch(m_page.replayController()); 153 } 154 155 EventLoopInputBase* dispatchedInput = m_runningInput; 156 m_runningInput = nullptr; 157 158 // Notify clients that the event was dispatched. 159 m_client->didDispatchInput(*dispatchedInput); 160 if (dispatchedInput->type() == inputTypes().EndSegmentSentinel) { 161 m_running = false; 162 m_dispatching = false; 163 m_client->didDispatchFinalInput(); 164 return; 165 } 166 167 // Clients could stop replay during event dispatch, or from any callback above. 168 if (!m_running) 169 return; 170 171 dispatchInputSoon(); 172} 173 174} // namespace WebCore 175 176#endif // ENABLE(WEB_REPLAY) 177