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#ifndef ReplayController_h 29#define ReplayController_h 30 31#if ENABLE(WEB_REPLAY) 32 33#include "EventLoopInputDispatcher.h" 34#include <wtf/Noncopyable.h> 35#include <wtf/Vector.h> 36 37// Determinism assertions are guarded by this macro. When a user-facing error reporting and 38// recovery mechanism is implemented, this guard can be removed. <https://webkit.org/b/131279> 39#define ENABLE_AGGRESSIVE_DETERMINISM_CHECKS 0 40 41namespace JSC { 42class InputCursor; 43} 44 45namespace WebCore { 46 47class DOMWindow; 48class Document; 49class DocumentLoader; 50class Element; 51class Event; 52class EventLoopInputBase; 53class Frame; 54class Node; 55class Page; 56class ReplaySession; 57class ReplaySessionSegment; 58 59// Each state may transition to the state immediately above or below it. 60// SessionState transitions are only allowed when SegmentState is Unloaded. 61enum class SessionState { 62 Capturing, 63 // Neither capturing or replaying. m_currentPosition is not valid in this state. 64 Inactive, 65 Replaying, 66}; 67 68// Each state may transition to the state immediately above or below it. 69enum class SegmentState { 70 // Inputs can be appended into an unassociated session segment. 71 // We can stop capturing, which reverts to the Unloaded state. 72 Appending, 73 // No session segment is loaded. 74 // We can start capturing, or load a segment (and then replay it). 75 Unloaded, 76 // A session segment is loaded. 77 // We can unload the segment, or begin playback from m_currentPosition. 78 Loaded, 79 // The controller is actively dispatching event loop inputs. 80 // We can pause or cancel playback, which reverts to the Loaded state. 81 Dispatching, 82}; 83 84struct ReplayPosition { 85 ReplayPosition(unsigned segmentOffset, unsigned inputOffset) 86 : segmentOffset(segmentOffset) 87 , inputOffset(inputOffset) 88 { 89 } 90 91 // By convention, this position represents the end of the last segment of the session. 92 ReplayPosition() 93 : segmentOffset(0) 94 , inputOffset(0) 95 { 96 } 97 98 bool operator<(const ReplayPosition& other) 99 { 100 return segmentOffset <= other.segmentOffset && inputOffset < other.inputOffset; 101 } 102 103 bool operator==(const ReplayPosition& other) 104 { 105 return segmentOffset == other.segmentOffset && inputOffset == other.inputOffset; 106 } 107 108 unsigned segmentOffset; 109 unsigned inputOffset; 110}; 111 112class ReplayController final : public EventLoopInputDispatcherClient { 113 WTF_MAKE_NONCOPYABLE(ReplayController); 114public: 115 ReplayController(Page&); 116 117 void startCapturing(); 118 void stopCapturing(); 119 120 // Start or resume playback with default speed and target replay position. 121 void startPlayback(); 122 void pausePlayback(); 123 void cancelPlayback(); 124 125 void replayToPosition(const ReplayPosition&, DispatchSpeed = DispatchSpeed::FastForward); 126 void replayToCompletion(DispatchSpeed speed = DispatchSpeed::FastForward) 127 { 128 replayToPosition(ReplayPosition(), speed); 129 } 130 131 void switchSession(PassRefPtr<ReplaySession>); 132 133 // InspectorReplayAgent notifications. 134 void frameNavigated(DocumentLoader*); 135 void frameDetached(Frame*); 136 void willDispatchEvent(const Event&, Frame*); 137 138 Page& page() const { return m_page; } 139 SessionState sessionState() const { return m_sessionState; } 140 PassRefPtr<ReplaySession> loadedSession() const; 141 PassRefPtr<ReplaySessionSegment> loadedSegment() const; 142 JSC::InputCursor& activeInputCursor() const; 143 144private: 145 // EventLoopInputDispatcherClient API 146 virtual void willDispatchInput(const EventLoopInputBase&) override; 147 virtual void didDispatchInput(const EventLoopInputBase&) override; 148 virtual void didDispatchFinalInput() override; 149 150 void createSegment(); 151 void completeSegment(); 152 153 void loadSegmentAtIndex(size_t); 154 void unloadSegment(bool suppressNotifications = false); 155 156 EventLoopInputDispatcher& dispatcher() const; 157 158 void setSessionState(SessionState); 159 void setForceDeterministicSettings(bool); 160 161 struct SavedSettings { 162 bool usesPageCache; 163 164 SavedSettings() 165 : usesPageCache(false) 166 { } 167 }; 168 169 Page& m_page; 170 171 RefPtr<ReplaySessionSegment> m_loadedSegment; 172 RefPtr<ReplaySession> m_loadedSession; 173 const RefPtr<JSC::InputCursor> m_emptyCursor; 174 // The active cursor is set to nullptr when invalid. 175 RefPtr<JSC::InputCursor> m_activeCursor; 176 177 // This position is valid when SessionState == Replaying. 178 ReplayPosition m_targetPosition; 179 // This position is valid when SessionState != Inactive. 180 ReplayPosition m_currentPosition; 181 SegmentState m_segmentState; 182 // This tracks state across multiple segments. When navigating the main frame, 183 // there is a small interval during segment switching when no segment is loaded. 184 SessionState m_sessionState; 185 186 DispatchSpeed m_dispatchSpeed; 187 SavedSettings m_savedSettings; 188}; 189 190} // namespace WebCore 191 192#endif // ENABLE(WEB_REPLAY) 193 194#endif // ReplayController_h 195