summaryrefslogtreecommitdiff
path: root/Source/WebCore/replay/ReplayController.h
diff options
context:
space:
mode:
Diffstat (limited to 'Source/WebCore/replay/ReplayController.h')
-rw-r--r--Source/WebCore/replay/ReplayController.h197
1 files changed, 197 insertions, 0 deletions
diff --git a/Source/WebCore/replay/ReplayController.h b/Source/WebCore/replay/ReplayController.h
new file mode 100644
index 000000000..f4eff4649
--- /dev/null
+++ b/Source/WebCore/replay/ReplayController.h
@@ -0,0 +1,197 @@
+/*
+ * Copyright (C) 2011-2013 University of Washington. All rights reserved.
+ * Copyright (C) 2014 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#if ENABLE(WEB_REPLAY)
+
+#include "EventLoopInputDispatcher.h"
+#include <wtf/Noncopyable.h>
+
+// Determinism assertions are guarded by this macro. When a user-facing error reporting and
+// recovery mechanism is implemented, this guard can be removed. <https://webkit.org/b/131279>
+#define ENABLE_AGGRESSIVE_DETERMINISM_CHECKS 0
+
+namespace JSC {
+class InputCursor;
+}
+
+namespace WebCore {
+
+class DOMWindow;
+class Document;
+class DocumentLoader;
+class Element;
+class Event;
+class EventLoopInputBase;
+class Frame;
+class Node;
+class Page;
+class ReplaySession;
+class ReplaySessionSegment;
+
+// Each state may transition to the state immediately above or below it.
+// SessionState transitions are only allowed when SegmentState is Unloaded.
+enum class SessionState {
+ Capturing,
+ // Neither capturing or replaying. m_currentPosition is not valid in this state.
+ Inactive,
+ Replaying,
+};
+
+// Each state may transition to the state immediately above or below it.
+enum class SegmentState {
+ // Inputs can be appended into an unassociated session segment.
+ // We can stop capturing, which reverts to the Unloaded state.
+ Appending,
+ // No session segment is loaded.
+ // We can start capturing, or load a segment (and then replay it).
+ Unloaded,
+ // A session segment is loaded.
+ // We can unload the segment, or begin playback from m_currentPosition.
+ Loaded,
+ // The controller is actively dispatching event loop inputs.
+ // We can pause or cancel playback, which reverts to the Loaded state.
+ Dispatching,
+};
+
+struct ReplayPosition {
+ ReplayPosition(unsigned segmentOffset, unsigned inputOffset)
+ : segmentOffset(segmentOffset)
+ , inputOffset(inputOffset)
+ {
+ }
+
+ // By convention, this position represents the end of the last segment of the session.
+ ReplayPosition()
+ : segmentOffset(0)
+ , inputOffset(0)
+ {
+ }
+
+ bool operator<(const ReplayPosition& other)
+ {
+ return segmentOffset <= other.segmentOffset && inputOffset < other.inputOffset;
+ }
+
+ bool operator==(const ReplayPosition& other)
+ {
+ return segmentOffset == other.segmentOffset && inputOffset == other.inputOffset;
+ }
+
+ unsigned segmentOffset;
+ unsigned inputOffset;
+};
+
+class ReplayController final : public EventLoopInputDispatcherClient {
+ WTF_MAKE_FAST_ALLOCATED;
+ WTF_MAKE_NONCOPYABLE(ReplayController);
+public:
+ ReplayController(Page&);
+
+ void startCapturing();
+ void stopCapturing();
+
+ // Start or resume playback with default speed and target replay position.
+ void startPlayback();
+ void pausePlayback();
+ void cancelPlayback();
+
+ void replayToPosition(const ReplayPosition&, DispatchSpeed = DispatchSpeed::FastForward);
+ void replayToCompletion(DispatchSpeed speed = DispatchSpeed::FastForward)
+ {
+ replayToPosition(ReplayPosition(), speed);
+ }
+
+ void switchSession(RefPtr<ReplaySession>&&);
+
+ // InspectorReplayAgent notifications.
+ void frameNavigated(Frame&);
+ void frameDetached(Frame&);
+ void willDispatchEvent(const Event&, Frame*);
+
+ Page& page() const { return m_page; }
+
+ SessionState sessionState() const { return m_sessionState; }
+ SegmentState segmentState() const { return m_segmentState; }
+
+ RefPtr<ReplaySession> loadedSession() const;
+ RefPtr<ReplaySessionSegment> loadedSegment() const;
+
+ JSC::InputCursor& activeInputCursor();
+ ReplayPosition currentPosition() const { return m_currentPosition; }
+
+private:
+ // EventLoopInputDispatcherClient API
+ void willDispatchInput(const EventLoopInputBase&) override;
+ void didDispatchInput(const EventLoopInputBase&) override;
+ void didDispatchFinalInput() override;
+
+ void createSegment();
+ void completeSegment();
+
+ void loadSegmentAtIndex(size_t);
+ void unloadSegment(bool suppressNotifications = false);
+
+ EventLoopInputDispatcher& dispatcher() const;
+
+ void setSessionState(SessionState);
+ void setSegmentState(SegmentState);
+ void setForceDeterministicSettings(bool);
+
+ struct SavedSettings {
+ bool usesPageCache;
+
+ SavedSettings()
+ : usesPageCache(false)
+ { }
+ };
+
+ Page& m_page;
+
+ RefPtr<ReplaySessionSegment> m_loadedSegment;
+ RefPtr<ReplaySession> m_loadedSession;
+ Ref<JSC::InputCursor> m_emptyCursor;
+ // The active cursor is set to nullptr when invalid.
+ RefPtr<JSC::InputCursor> m_activeCursor;
+
+ // This position is valid when SessionState == Replaying.
+ ReplayPosition m_targetPosition;
+ // This position is valid when SessionState != Inactive.
+ ReplayPosition m_currentPosition;
+ SegmentState m_segmentState;
+ // This tracks state across multiple segments. When navigating the main frame,
+ // there is a small interval during segment switching when no segment is loaded.
+ SessionState m_sessionState;
+
+ DispatchSpeed m_dispatchSpeed;
+ SavedSettings m_savedSettings;
+};
+
+} // namespace WebCore
+
+#endif // ENABLE(WEB_REPLAY)