+2014-03-03 Brian Burg <bburg@apple.com>
+
+ Web Replay: upstream input storage, capture/replay machinery, and inspector domain
+ https://bugs.webkit.org/show_bug.cgi?id=128782
+
+ Reviewed by Timothy Hatcher.
+
+ Alter the replay inputs code generator so that it knows when it is necessary to
+ to include headers for HEAVY_SCALAR types such as WTF::String and WebCore::URL.
+
+ * JavaScriptCore.xcodeproj/project.pbxproj:
+ * replay/scripts/CodeGeneratorReplayInputs.py:
+ (Framework.fromString):
+ (Frameworks): Add WTF as an allowed framework for code generation.
+ (Generator.generate_includes): Include headers for HEAVY_SCALAR types in the header file.
+ (Generator.generate_includes.declaration):
+ (Generator.generate_includes.or):
+ (Generator.generate_type_forward_declarations): Skip HEAVY_SCALAR types.
+
2014-03-02 Filip Pizlo <fpizlo@apple.com>
PolymorphicPutByIdList should have a simpler construction API with basically a single entrypoint
978801411471AD920041B016 /* JSDateMath.h in Headers */ = {isa = PBXBuildFile; fileRef = 9788FC231471AD0C0068CE2D /* JSDateMath.h */; settings = {ATTRIBUTES = (Private, ); }; };
9928FF3B18AC4AEC00B8CF12 /* JSReplayInputs.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9928FF3918AC4AEC00B8CF12 /* JSReplayInputs.cpp */; };
9928FF3C18AC4AEC00B8CF12 /* JSReplayInputs.h in Headers */ = {isa = PBXBuildFile; fileRef = 9928FF3A18AC4AEC00B8CF12 /* JSReplayInputs.h */; settings = {ATTRIBUTES = (Private, ); }; };
+ 99CC0B6218BE9946006CEBCC /* CodeGeneratorReplayInputsTemplates.py in Headers */ = {isa = PBXBuildFile; fileRef = 99E45A1E18A1B1E70026D88F /* CodeGeneratorReplayInputsTemplates.py */; settings = {ATTRIBUTES = (Private, ); }; };
+ 99CC0B6318BE9950006CEBCC /* CodeGeneratorReplayInputs.py in Headers */ = {isa = PBXBuildFile; fileRef = 99E45A1D18A1B1E70026D88F /* CodeGeneratorReplayInputs.py */; settings = {ATTRIBUTES = (Private, ); }; };
99E45A2418A1B2590026D88F /* EmptyInputCursor.h in Headers */ = {isa = PBXBuildFile; fileRef = 99E45A1F18A1B2590026D88F /* EmptyInputCursor.h */; settings = {ATTRIBUTES = (Private, ); }; };
99E45A2518A1B2590026D88F /* EncodedValue.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 99E45A2018A1B2590026D88F /* EncodedValue.cpp */; };
99E45A2618A1B2590026D88F /* EncodedValue.h in Headers */ = {isa = PBXBuildFile; fileRef = 99E45A2118A1B2590026D88F /* EncodedValue.h */; settings = {ATTRIBUTES = (Private, ); }; };
86EBF3041560F06A008E9222 /* NamePrototype.h in Headers */,
BC02E9110E1839DB000F9297 /* NativeErrorConstructor.h in Headers */,
BC02E9130E1839DB000F9297 /* NativeErrorPrototype.h in Headers */,
+ 99CC0B6318BE9950006CEBCC /* CodeGeneratorReplayInputs.py in Headers */,
0FFB922016D033B70055A5DB /* NodeConstructors.h in Headers */,
7EFF00640EC05A9A00AA7C93 /* NodeInfo.h in Headers */,
BC18C43F0E16F5CD00B34460 /* Nodes.h in Headers */,
BC18C4420E16F5CD00B34460 /* NumberConstructor.lut.h in Headers */,
BC18C4430E16F5CD00B34460 /* NumberObject.h in Headers */,
BC18C4440E16F5CD00B34460 /* NumberPrototype.h in Headers */,
+ 99CC0B6218BE9946006CEBCC /* CodeGeneratorReplayInputsTemplates.py in Headers */,
142D3939103E4560007DCB52 /* NumericStrings.h in Headers */,
86F3EEBD168CDE930077B92A /* ObjCCallbackFunction.h in Headers */,
86F3EEBF168CDE930077B92A /* ObjcRuntimeExtras.h in Headers */,
"namespace": ""
},
+ "WTF": {
+ "prefix": "WTF",
+ "namespace": "WTF",
+ },
"JavaScriptCore": {
"prefix": "JS",
"namespace": "JSC",
if frameworkString == "Global":
return Frameworks.Global
+ if frameworkString == "WTF":
+ return Frameworks.WTF
+
if frameworkString == "JavaScriptCore":
return Frameworks.JavaScriptCore
class Frameworks:
Global = Framework("Global")
+ WTF = Framework("WTF")
JavaScriptCore = Framework("JavaScriptCore")
WebCore = Framework("WebCore")
Test = Framework("Test")
if _type.framework is Frameworks.Global:
continue
# For RefCounted types, we reverse when to include the header so that the destructor can be
- # used in the header file. Enums within classes cannot be forward declared, so we include
- # headers with the relevant class declaration.
+ # used in the header file.
include_for_destructor = _type.mode is TypeModes.SHARED
+ # Enums within classes cannot be forward declared, so we include
+ # headers with the relevant class declaration.
include_for_enclosing_class = _type.is_enum() and _type.enclosing_class is not None
- if (not includes_for_types) ^ (include_for_destructor or include_for_enclosing_class):
+ # Include headers for types like URL and String which are copied, not owned or shared.
+ include_for_copyable_member = _type.mode is TypeModes.HEAVY_SCALAR or _type.mode is TypeModes.SCALAR
+ if (not includes_for_types) ^ (include_for_destructor or include_for_enclosing_class or include_for_copyable_member):
continue
if self.target_framework != _type.framework:
continue
if _type.enclosing_class is not None:
continue
+ if _type.mode == TypeModes.SCALAR or _type.mode == TypeModes.HEAVY_SCALAR:
+ continue
if _type.is_enum():
declaration = "enum %s : %s;" % (_type.type_name(), _type.underlying_storage)
else:
+2014-03-03 Brian Burg <bburg@apple.com>
+
+ Web Replay: upstream input storage, capture/replay machinery, and inspector domain
+ https://bugs.webkit.org/show_bug.cgi?id=128782
+
+ Reviewed by Timothy Hatcher, Joseph Pecoraro, and Andreas Kling.
+
+ No new tests yet, as they rely on infrastructure tracked in https://webkit.org/b/129190.
+
+ Replayable executions are organized into ReplaySessions, which can
+ contain several ReplaySessionSegments that divide overall execution
+ at main frame navigation boundaries. NondeterministicInput subclasses
+ are stored in SegmentedInputStorage according to the input's InputQueue.
+
+ Capture and playback are controlled at the page granularity by the Page's
+ ReplayController. The controller knows how to create new segments, replay to
+ arbitrary positions in the ReplaySession, and track the active InputCursor.
+
+ The capturing and replaying input cursor subclasses encapsulate state for
+ storing new inputs and loading/dispatching saved inputs, respectively.
+
+ The ReplayAgent and associated inspector protocol domain is the friendly
+ public API for programmatically capturing and replaying sessions.
+
+ * DerivedSources.make: Add replay inputs code generation target. Add the
+ replay domain specification to the list of inspector domains.
+
+ * ForwardingHeaders/replay/EncodedValue.h: Added.
+ * WebCore.xcodeproj/project.pbxproj: Add many files, and export
+ `WebReplayScripts` environment variable to DerivedSources.make.
+
+ * inspector/InspectorController.cpp: Add the replay agent.
+ (WebCore::InspectorController::InspectorController):
+
+ * inspector/InspectorInstrumentation.cpp:
+ Add events for segment lifecycle events, and loading/unloading of sessions
+ and segments, and capture/replay progress events. The replay controller
+ also needs to know about detached and committed frames.
+
+ (WebCore::InspectorInstrumentation::frameDetachedFromParentImpl):
+ (WebCore::InspectorInstrumentation::didCommitLoadImpl):
+ (WebCore::InspectorInstrumentation::sessionCreatedImpl):
+ (WebCore::InspectorInstrumentation::sessionLoadedImpl):
+ (WebCore::InspectorInstrumentation::sessionModifiedImpl):
+ (WebCore::InspectorInstrumentation::segmentCreatedImpl):
+ (WebCore::InspectorInstrumentation::segmentCompletedImpl):
+ (WebCore::InspectorInstrumentation::segmentLoadedImpl):
+ (WebCore::InspectorInstrumentation::segmentUnloadedImpl):
+ (WebCore::InspectorInstrumentation::captureStartedImpl):
+ (WebCore::InspectorInstrumentation::captureStoppedImpl):
+ (WebCore::InspectorInstrumentation::playbackStartedImpl):
+ (WebCore::InspectorInstrumentation::playbackPausedImpl):
+ (WebCore::InspectorInstrumentation::playbackHitPositionImpl):
+ (WebCore::InspectorInstrumentation::replayAgentEnabled):
+ * inspector/InspectorInstrumentation.h:
+ (WebCore::InspectorInstrumentation::replayAgentEnabled):
+ (WebCore::InspectorInstrumentation::sessionCreated):
+ (WebCore::InspectorInstrumentation::sessionLoaded):
+ (WebCore::InspectorInstrumentation::sessionModified):
+ (WebCore::InspectorInstrumentation::segmentCreated):
+ (WebCore::InspectorInstrumentation::segmentCompleted):
+ (WebCore::InspectorInstrumentation::segmentLoaded):
+ (WebCore::InspectorInstrumentation::segmentUnloaded):
+ (WebCore::InspectorInstrumentation::captureStarted):
+ (WebCore::InspectorInstrumentation::captureStopped):
+ (WebCore::InspectorInstrumentation::playbackStarted):
+ (WebCore::InspectorInstrumentation::playbackPaused):
+ (WebCore::InspectorInstrumentation::playbackHitPosition):
+
+ * inspector/InspectorReplayAgent.cpp: Added.
+ (WebCore::buildInspectorObjectForPosition):
+ (WebCore::buildInspectorObjectForInput):
+ (WebCore::buildInspectorObjectForSession):
+ (WebCore::SerializeInputToJSONFunctor::SerializeInputToJSONFunctor):
+ (WebCore::SerializeInputToJSONFunctor::~SerializeInputToJSONFunctor):
+ (WebCore::SerializeInputToJSONFunctor::operator()):
+ (WebCore::SerializeInputToJSONFunctor::returnValue):
+ (WebCore::buildInspectorObjectForSegment):
+ (WebCore::InspectorReplayAgent::InspectorReplayAgent):
+ (WebCore::InspectorReplayAgent::~InspectorReplayAgent):
+ (WebCore::InspectorReplayAgent::sessionState):
+ (WebCore::InspectorReplayAgent::didCreateFrontendAndBackend):
+ (WebCore::InspectorReplayAgent::willDestroyFrontendAndBackend):
+ (WebCore::InspectorReplayAgent::frameNavigated):
+ (WebCore::InspectorReplayAgent::frameDetached):
+ (WebCore::InspectorReplayAgent::sessionCreated):
+ (WebCore::InspectorReplayAgent::sessionModified):
+ (WebCore::InspectorReplayAgent::sessionLoaded):
+ (WebCore::InspectorReplayAgent::segmentCreated):
+ (WebCore::InspectorReplayAgent::segmentCompleted):
+ (WebCore::InspectorReplayAgent::segmentLoaded):
+ (WebCore::InspectorReplayAgent::segmentUnloaded):
+ (WebCore::InspectorReplayAgent::captureStarted):
+ (WebCore::InspectorReplayAgent::captureStopped):
+ (WebCore::InspectorReplayAgent::playbackStarted):
+ (WebCore::InspectorReplayAgent::playbackPaused):
+ (WebCore::InspectorReplayAgent::playbackHitPosition):
+ (WebCore::InspectorReplayAgent::startCapturing):
+ (WebCore::InspectorReplayAgent::stopCapturing):
+ (WebCore::InspectorReplayAgent::replayToPosition):
+ (WebCore::InspectorReplayAgent::replayToCompletion):
+ (WebCore::InspectorReplayAgent::pausePlayback):
+ (WebCore::InspectorReplayAgent::cancelPlayback):
+ (WebCore::InspectorReplayAgent::switchSession):
+ (WebCore::InspectorReplayAgent::insertSessionSegment):
+ (WebCore::InspectorReplayAgent::removeSessionSegment):
+ Provide a public API for modifying sessions. This is the backend support
+ for user editing of replay sessions to add/remove specific segments.
+
+ (WebCore::InspectorReplayAgent::findSession):
+ (WebCore::InspectorReplayAgent::findSegment):
+ (WebCore::InspectorReplayAgent::getAvailableSessions):
+ (WebCore::InspectorReplayAgent::getSerializedSession):
+ (WebCore::InspectorReplayAgent::getSerializedSegment):
+ Most of the replay protocol domain speaks in terms of sesssion and
+ segment identifiers. These functions return the actual data associated
+ with these identifiers.
+
+ * inspector/InspectorReplayAgent.h: Added.
+ * inspector/InstrumentingAgents.cpp:
+ (WebCore::InstrumentingAgents::InstrumentingAgents):
+ (WebCore::InstrumentingAgents::reset):
+ * inspector/InstrumentingAgents.h:
+ (WebCore::InstrumentingAgents::inspectorReplayAgent): Added.
+ (WebCore::InstrumentingAgents::setInspectorReplayAgent): Added.
+ * inspector/protocol/Replay.json: Added.
+
+ * page/Page.cpp:
+ (WebCore::Page::Page):
+ * page/Page.h:
+ (WebCore::Page::replayController): Added.
+ * platform/Logging.h: Add WebReplay logging channel.
+ * replay/AllReplayInputs.h: Added. Simplifies importing all input definitions.
+
+ * replay/CapturingInputCursor.cpp: Added.
+ (WebCore::CapturingInputCursor::CapturingInputCursor):
+ (WebCore::CapturingInputCursor::~CapturingInputCursor):
+ (WebCore::CapturingInputCursor::create):
+ (WebCore::CapturingInputCursor::storeInput):
+ (WebCore::CapturingInputCursor::loadInput):
+ (WebCore::CapturingInputCursor::uncheckedLoadInput):
+ * replay/CapturingInputCursor.h: Added.
+
+ * replay/EventLoopInput.h:
+ (WebCore::EventLoopInputBase::EventLoopInputBase):
+ (WebCore::EventLoopInputBase::timestamp):
+ (WebCore::EventLoopInputBase::setTimestamp): Support deserialization.
+
+ * replay/EventLoopInputDispatcher.cpp: Added. This class encapsulates the timers
+ and measurements used to dispatch event loop inputs during replay.
+
+ (WebCore::EventLoopInputDispatcher::EventLoopInputDispatcher):
+ (WebCore::EventLoopInputDispatcher::run):
+ (WebCore::EventLoopInputDispatcher::pause):
+ (WebCore::EventLoopInputDispatcher::timerFired):
+ (WebCore::EventLoopInputDispatcher::dispatchInputSoon):
+ (WebCore::EventLoopInputDispatcher::dispatchInput):
+ * replay/EventLoopInputDispatcher.h: Added.
+ (WebCore::EventLoopInputDispatcherClient::EventLoopInputDispatcherClient):
+ (WebCore::EventLoopInputDispatcherClient::~EventLoopInputDispatcherClient):
+
+ * replay/FunctorInputCursor.h: Added.
+ (WebCore::FunctorInputCursor::~FunctorInputCursor):
+ (WebCore::FunctorInputCursor::forEachInputInQueue):
+ (WebCore::FunctorInputCursor::FunctorInputCursor):
+ (WebCore::FunctorInputCursor::storeInput):
+ (WebCore::FunctorInputCursor::loadInput):
+ (WebCore::FunctorInputCursor::uncheckedLoadInput):
+
+ * replay/ReplayController.cpp: Added.
+ (WebCore::ReplayController::ReplayController):
+ (WebCore::ReplayController::switchSession):
+ (WebCore::ReplayController::createSegment):
+ (WebCore::ReplayController::completeSegment):
+ (WebCore::ReplayController::loadSegment):
+ (WebCore::ReplayController::unloadSegment):
+ (WebCore::ReplayController::startCapturing):
+ (WebCore::ReplayController::stopCapturing):
+ (WebCore::ReplayController::startPlayback):
+ (WebCore::ReplayController::pausePlayback):
+ (WebCore::ReplayController::cancelPlayback):
+ (WebCore::ReplayController::replayToPosition):
+ (WebCore::ReplayController::frameDetached):
+ (WebCore::ReplayController::frameNavigated):
+ (WebCore::ReplayController::loadedSession):
+ (WebCore::ReplayController::loadedSegment):
+ (WebCore::ReplayController::activeInputCursor):
+ (WebCore::ReplayController::dispatcher):
+ (WebCore::ReplayController::willDispatchInput):
+ (WebCore::ReplayController::didDispatchInput):
+ (WebCore::ReplayController::didDispatchFinalInput):
+ * replay/ReplayController.h: Added.
+ (WebCore::ReplayPosition::ReplayPosition):
+ (WebCore::ReplayPosition::operator<):
+ (WebCore::ReplayPosition::operator==):
+
+ * replay/ReplayInputCreationMethods.cpp: Added.
+ Static factory implementations for inputs belong here.
+ (WebCore::InitialNavigation::createFromPage):
+
+ * replay/ReplayInputDispatchMethods.cpp: Added.
+ All dispatch() implementations for generated replay inputs belong here.
+ (WebCore::BeginSegmentSentinel::dispatch):
+ (WebCore::EndSegmentSentinel::dispatch):
+ (WebCore::InitialNavigation::dispatch):
+
+ * replay/ReplayInputTypes.cpp:
+ (WebCore::ReplayInputTypes::ReplayInputTypes):
+ * replay/ReplayInputTypes.h: Define strings for WebCore inputs.
+
+ * replay/ReplaySession.cpp: Added.
+ (WebCore::ReplaySession::create):
+ (WebCore::ReplaySession::ReplaySession):
+ (WebCore::ReplaySession::~ReplaySession):
+ (WebCore::ReplaySession::appendSegment):
+ (WebCore::ReplaySession::insertSegment):
+ (WebCore::ReplaySession::removeSegment):
+ * replay/ReplaySession.h: Added.
+ (WebCore::ReplaySession::identifier):
+ (WebCore::ReplaySession::timestamp):
+ (WebCore::ReplaySession::size):
+ (WebCore::ReplaySession::at):
+ (WebCore::ReplaySession::begin):
+ (WebCore::ReplaySession::end):
+
+ * replay/ReplaySessionSegment.cpp: Added.
+ (WebCore::ReplaySessionSegment::create):
+ (WebCore::ReplaySessionSegment::ReplaySessionSegment):
+ (WebCore::ReplaySessionSegment::~ReplaySessionSegment):
+ (WebCore::ReplaySessionSegment::createCapturingCursor):
+ (WebCore::ReplaySessionSegment::createReplayingCursor):
+ (WebCore::ReplaySessionSegment::createFunctorCursor):
+ * replay/ReplaySessionSegment.h: Added.
+ (WebCore::ReplaySessionSegment::identifier):
+ (WebCore::ReplaySessionSegment::timestamp):
+
+ * replay/ReplayingInputCursor.cpp: Added.
+ (WebCore::ReplayingInputCursor::ReplayingInputCursor):
+ (WebCore::ReplayingInputCursor::~ReplayingInputCursor):
+ (WebCore::ReplayingInputCursor::create):
+ (WebCore::ReplayingInputCursor::storeInput):
+ (WebCore::ReplayingInputCursor::loadInput):
+ (WebCore::ReplayingInputCursor::uncheckedLoadInput):
+ * replay/ReplayingInputCursor.h: Added.
+
+ * replay/SegmentedInputStorage.cpp: Added.
+ (WebCore::queueTypeToLogPrefix):
+ (WebCore::jsonStringForInput):
+ (WebCore::offsetForInputQueue):
+ (WebCore::SegmentedInputStorage::SegmentedInputStorage):
+ (WebCore::SegmentedInputStorage::~SegmentedInputStorage):
+ (WebCore::SegmentedInputStorage::load):
+ (WebCore::SegmentedInputStorage::store):
+ (WebCore::SegmentedInputStorage::queueSize):
+ * replay/SegmentedInputStorage.h: Added.
+
+ * replay/SerializationMethods.cpp: Added.
+ Specializations of EncodingTraits for WebCore types belong here.
+
+ (JSC::EncodingTraits<NondeterministicInputBase>::encodeValue):
+ (JSC::EncodingTraits<NondeterministicInputBase>::decodeValue):
+ (JSC::EncodingTraits<SecurityOrigin>::encodeValue):
+ (JSC::EncodingTraits<SecurityOrigin>::decodeValue):
+ (JSC::EncodingTraits<URL>::encodeValue):
+ (JSC::EncodingTraits<URL>::decodeValue):
+ * replay/SerializationMethods.h: Added.
+ * replay/WebInputs.json: Added.
+ In this inital patch, we define BeginSegmentSentinel,
+ EndSegmentSentinel, and InitialNavigation inputs.
+
2014-03-03 Antoine Quint <graouts@webkit.org>
Respect SVG fragment identifiers in <img> src attribute
$(WebCore)/inspector/protocol/Network.json \
$(WebCore)/inspector/protocol/Page.json \
$(WebCore)/inspector/protocol/Profiler.json \
+ $(WebCore)/inspector/protocol/Replay.json \
$(WebCore)/inspector/protocol/Timeline.json \
$(WebCore)/inspector/protocol/Worker.json \
#
perl $(InspectorScripts)/xxd.pl CommandLineAPIModuleSource_js ./CommandLineAPIModuleSource.min.js CommandLineAPIModuleSource.h
rm -f ./CommandLineAPIModuleSource.min.js
+# Web Replay inputs generator
+
+INPUT_GENERATOR_SCRIPTS = \
+ $(WebReplayScripts)/CodeGeneratorReplayInputs.py \
+ $(WebReplayScripts)/CodeGeneratorReplayInputsTemplates.py \
+#
+
+INPUT_GENERATOR_SPECIFICATIONS = \
+ $(WebCore)/replay/WebInputs.json \
+#
+
+all : WebReplayInputs.h
+
+WebReplayInputs.h : $(INPUT_GENERATOR_SPECIFICATIONS) $(INPUT_GENERATOR_SCRIPTS)
+ python $(WebReplayScripts)/CodeGeneratorReplayInputs.py --outputDir . --framework WebCore $(INPUT_GENERATOR_SPECIFICATIONS)
+
-include $(JS_DOM_HEADERS:.h=.dep)
# ------------------------
--- /dev/null
+#ifndef WebCore_FWD_EncodedValue_h
+#define WebCore_FWD_EncodedValue_h
+#include <JavaScriptCore/EncodedValue.h>
+#endif
990A1A0518ADA48400183FD1 /* ReplayInputTypes.h in Headers */ = {isa = PBXBuildFile; fileRef = 990A19F518ADA48400183FD1 /* ReplayInputTypes.h */; };
9920398218B95BC600B39AF9 /* UserInputBridge.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9920398018B95BC600B39AF9 /* UserInputBridge.cpp */; };
9920398318B95BC600B39AF9 /* UserInputBridge.h in Headers */ = {isa = PBXBuildFile; fileRef = 9920398118B95BC600B39AF9 /* UserInputBridge.h */; settings = {ATTRIBUTES = (Private, ); }; };
+ 99CC0B4D18BE9849006CEBCC /* AllReplayInputs.h in Headers */ = {isa = PBXBuildFile; fileRef = 99CC0B3818BE9849006CEBCC /* AllReplayInputs.h */; };
+ 99CC0B4E18BE9849006CEBCC /* CapturingInputCursor.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 99CC0B3918BE9849006CEBCC /* CapturingInputCursor.cpp */; };
+ 99CC0B4F18BE9849006CEBCC /* CapturingInputCursor.h in Headers */ = {isa = PBXBuildFile; fileRef = 99CC0B3A18BE9849006CEBCC /* CapturingInputCursor.h */; };
+ 99CC0B5018BE9849006CEBCC /* EventLoopInputDispatcher.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 99CC0B3B18BE9849006CEBCC /* EventLoopInputDispatcher.cpp */; };
+ 99CC0B5118BE9849006CEBCC /* EventLoopInputDispatcher.h in Headers */ = {isa = PBXBuildFile; fileRef = 99CC0B3C18BE9849006CEBCC /* EventLoopInputDispatcher.h */; };
+ 99CC0B5218BE9849006CEBCC /* FunctorInputCursor.h in Headers */ = {isa = PBXBuildFile; fileRef = 99CC0B3D18BE9849006CEBCC /* FunctorInputCursor.h */; };
+ 99CC0B5318BE9849006CEBCC /* ReplayController.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 99CC0B3E18BE9849006CEBCC /* ReplayController.cpp */; };
+ 99CC0B5418BE9849006CEBCC /* ReplayController.h in Headers */ = {isa = PBXBuildFile; fileRef = 99CC0B3F18BE9849006CEBCC /* ReplayController.h */; };
+ 99CC0B5518BE9849006CEBCC /* ReplayingInputCursor.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 99CC0B4018BE9849006CEBCC /* ReplayingInputCursor.cpp */; };
+ 99CC0B5618BE984A006CEBCC /* ReplayingInputCursor.h in Headers */ = {isa = PBXBuildFile; fileRef = 99CC0B4118BE9849006CEBCC /* ReplayingInputCursor.h */; };
+ 99CC0B5718BE984A006CEBCC /* ReplayInputCreationMethods.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 99CC0B4218BE9849006CEBCC /* ReplayInputCreationMethods.cpp */; };
+ 99CC0B5818BE984A006CEBCC /* ReplayInputDispatchMethods.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 99CC0B4318BE9849006CEBCC /* ReplayInputDispatchMethods.cpp */; };
+ 99CC0B5918BE984A006CEBCC /* ReplaySession.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 99CC0B4418BE9849006CEBCC /* ReplaySession.cpp */; };
+ 99CC0B5A18BE984A006CEBCC /* ReplaySession.h in Headers */ = {isa = PBXBuildFile; fileRef = 99CC0B4518BE9849006CEBCC /* ReplaySession.h */; };
+ 99CC0B5B18BE984A006CEBCC /* ReplaySessionSegment.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 99CC0B4618BE9849006CEBCC /* ReplaySessionSegment.cpp */; };
+ 99CC0B5C18BE984A006CEBCC /* ReplaySessionSegment.h in Headers */ = {isa = PBXBuildFile; fileRef = 99CC0B4718BE9849006CEBCC /* ReplaySessionSegment.h */; };
+ 99CC0B5D18BE984A006CEBCC /* SegmentedInputStorage.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 99CC0B4818BE9849006CEBCC /* SegmentedInputStorage.cpp */; };
+ 99CC0B5E18BE984A006CEBCC /* SegmentedInputStorage.h in Headers */ = {isa = PBXBuildFile; fileRef = 99CC0B4918BE9849006CEBCC /* SegmentedInputStorage.h */; };
+ 99CC0B5F18BE984A006CEBCC /* SerializationMethods.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 99CC0B4A18BE9849006CEBCC /* SerializationMethods.cpp */; };
+ 99CC0B6018BE984A006CEBCC /* SerializationMethods.h in Headers */ = {isa = PBXBuildFile; fileRef = 99CC0B4B18BE9849006CEBCC /* SerializationMethods.h */; };
+ 99CC0B6118BE984A006CEBCC /* WebInputs.json in Resources */ = {isa = PBXBuildFile; fileRef = 99CC0B4C18BE9849006CEBCC /* WebInputs.json */; };
+ 99CC0B6618BE9F15006CEBCC /* InspectorReplayAgent.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 99CC0B6418BE9F15006CEBCC /* InspectorReplayAgent.cpp */; };
+ 99CC0B6718BE9F15006CEBCC /* InspectorReplayAgent.h in Headers */ = {isa = PBXBuildFile; fileRef = 99CC0B6518BE9F15006CEBCC /* InspectorReplayAgent.h */; };
+ 99CC0B6A18BEA1FF006CEBCC /* WebReplayInputs.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 99CC0B6818BEA1FF006CEBCC /* WebReplayInputs.cpp */; };
+ 99CC0B6B18BEA1FF006CEBCC /* WebReplayInputs.h in Headers */ = {isa = PBXBuildFile; fileRef = 99CC0B6918BEA1FF006CEBCC /* WebReplayInputs.h */; };
99E45A1718A063BE0026D88F /* EventLoopInput.h in Headers */ = {isa = PBXBuildFile; fileRef = 99E45A1618A063BE0026D88F /* EventLoopInput.h */; };
9A1142041832D135000BB8AD /* ValueToString.h in Headers */ = {isa = PBXBuildFile; fileRef = 9A1142031832D134000BB8AD /* ValueToString.h */; settings = {ATTRIBUTES = (Private, ); }; };
9A1B6F97158869C80011A8C4 /* JSDOMStringListCustom.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9A1B6F96158869C80011A8C4 /* JSDOMStringListCustom.cpp */; };
990A19F518ADA48400183FD1 /* ReplayInputTypes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ReplayInputTypes.h; sourceTree = "<group>"; };
9920398018B95BC600B39AF9 /* UserInputBridge.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = UserInputBridge.cpp; sourceTree = "<group>"; };
9920398118B95BC600B39AF9 /* UserInputBridge.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = UserInputBridge.h; sourceTree = "<group>"; };
+ 99CC0B3818BE9849006CEBCC /* AllReplayInputs.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AllReplayInputs.h; sourceTree = "<group>"; };
+ 99CC0B3918BE9849006CEBCC /* CapturingInputCursor.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CapturingInputCursor.cpp; sourceTree = "<group>"; };
+ 99CC0B3A18BE9849006CEBCC /* CapturingInputCursor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CapturingInputCursor.h; sourceTree = "<group>"; };
+ 99CC0B3B18BE9849006CEBCC /* EventLoopInputDispatcher.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = EventLoopInputDispatcher.cpp; sourceTree = "<group>"; };
+ 99CC0B3C18BE9849006CEBCC /* EventLoopInputDispatcher.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EventLoopInputDispatcher.h; sourceTree = "<group>"; };
+ 99CC0B3D18BE9849006CEBCC /* FunctorInputCursor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FunctorInputCursor.h; sourceTree = "<group>"; };
+ 99CC0B3E18BE9849006CEBCC /* ReplayController.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ReplayController.cpp; sourceTree = "<group>"; };
+ 99CC0B3F18BE9849006CEBCC /* ReplayController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ReplayController.h; sourceTree = "<group>"; };
+ 99CC0B4018BE9849006CEBCC /* ReplayingInputCursor.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ReplayingInputCursor.cpp; sourceTree = "<group>"; };
+ 99CC0B4118BE9849006CEBCC /* ReplayingInputCursor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ReplayingInputCursor.h; sourceTree = "<group>"; };
+ 99CC0B4218BE9849006CEBCC /* ReplayInputCreationMethods.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ReplayInputCreationMethods.cpp; sourceTree = "<group>"; };
+ 99CC0B4318BE9849006CEBCC /* ReplayInputDispatchMethods.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ReplayInputDispatchMethods.cpp; sourceTree = "<group>"; };
+ 99CC0B4418BE9849006CEBCC /* ReplaySession.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ReplaySession.cpp; sourceTree = "<group>"; };
+ 99CC0B4518BE9849006CEBCC /* ReplaySession.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ReplaySession.h; sourceTree = "<group>"; };
+ 99CC0B4618BE9849006CEBCC /* ReplaySessionSegment.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ReplaySessionSegment.cpp; sourceTree = "<group>"; };
+ 99CC0B4718BE9849006CEBCC /* ReplaySessionSegment.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ReplaySessionSegment.h; sourceTree = "<group>"; };
+ 99CC0B4818BE9849006CEBCC /* SegmentedInputStorage.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SegmentedInputStorage.cpp; sourceTree = "<group>"; };
+ 99CC0B4918BE9849006CEBCC /* SegmentedInputStorage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SegmentedInputStorage.h; sourceTree = "<group>"; };
+ 99CC0B4A18BE9849006CEBCC /* SerializationMethods.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SerializationMethods.cpp; sourceTree = "<group>"; };
+ 99CC0B4B18BE9849006CEBCC /* SerializationMethods.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SerializationMethods.h; sourceTree = "<group>"; };
+ 99CC0B4C18BE9849006CEBCC /* WebInputs.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = WebInputs.json; sourceTree = "<group>"; };
+ 99CC0B6418BE9F15006CEBCC /* InspectorReplayAgent.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = InspectorReplayAgent.cpp; sourceTree = "<group>"; };
+ 99CC0B6518BE9F15006CEBCC /* InspectorReplayAgent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = InspectorReplayAgent.h; sourceTree = "<group>"; };
+ 99CC0B6818BEA1FF006CEBCC /* WebReplayInputs.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WebReplayInputs.cpp; sourceTree = "<group>"; };
+ 99CC0B6918BEA1FF006CEBCC /* WebReplayInputs.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WebReplayInputs.h; sourceTree = "<group>"; };
99E45A1618A063BE0026D88F /* EventLoopInput.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EventLoopInput.h; sourceTree = "<group>"; };
9A1142031832D134000BB8AD /* ValueToString.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ValueToString.h; sourceTree = "<group>"; };
9A1B6F96158869C80011A8C4 /* JSDOMStringListCustom.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSDOMStringListCustom.cpp; sourceTree = "<group>"; };
4F6FDD631341DEDD001F8EE3 /* InspectorPageAgent.h */,
9F0D6B2C121BFEBA006C0288 /* InspectorProfilerAgent.cpp */,
9F0D6B2D121BFEBA006C0288 /* InspectorProfilerAgent.h */,
+ 99CC0B6418BE9F15006CEBCC /* InspectorReplayAgent.cpp */,
+ 99CC0B6518BE9F15006CEBCC /* InspectorReplayAgent.h */,
82AB1771125C826700C5069D /* InspectorResourceAgent.cpp */,
82AB1772125C826700C5069D /* InspectorResourceAgent.h */,
82AB176F125C826700C5069D /* InspectorStyleSheet.cpp */,
51C4AA5118B28357007BFE9B /* mac */ = {
isa = PBXGroup;
children = (
+ 510192D818B7D7AB007FC7A1 /* imageControlsMac.css */,
510192CF18B6B9AB007FC7A1 /* ImageControlsRootElementMac.cpp */,
510192D018B6B9AB007FC7A1 /* ImageControlsRootElementMac.h */,
- 510192D818B7D7AB007FC7A1 /* imageControlsMac.css */,
);
path = mac;
sourceTree = "<group>";
656581AF09D14EE6000E61D7 /* UserAgentStyleSheetsData.cpp */,
1A1414B313A0F0500019996C /* WebKitFontFamilyNames.cpp */,
1A1414B413A0F0500019996C /* WebKitFontFamilyNames.h */,
+ 99CC0B6818BEA1FF006CEBCC /* WebReplayInputs.cpp */,
+ 99CC0B6918BEA1FF006CEBCC /* WebReplayInputs.h */,
656581EA09D1508D000E61D7 /* XLinkNames.cpp */,
656581EB09D1508D000E61D7 /* XLinkNames.h */,
A833C80A0A2CF25600D57664 /* XMLNames.cpp */,
975CA287130365F800E99AD9 /* Crypto.cpp */,
975CA288130365F800E99AD9 /* Crypto.h */,
975CA289130365F800E99AD9 /* Crypto.idl */,
+ 1AF4CEE718BC350100BC2D34 /* DefaultVisitedLinkStore.cpp */,
+ 1AF4CEE818BC350100BC2D34 /* DefaultVisitedLinkStore.h */,
CCC2B51015F613060048CDD6 /* DeviceClient.h */,
CCC2B51115F613060048CDD6 /* DeviceController.cpp */,
CCC2B51215F613060048CDD6 /* DeviceController.h */,
517FBA18151AA71B00B57959 /* DOMWindowExtension.h */,
97D2AD0114B823A60093DF32 /* DOMWindowProperty.cpp */,
97D2AD0214B823A60093DF32 /* DOMWindowProperty.h */,
- 1AF4CEE718BC350100BC2D34 /* DefaultVisitedLinkStore.cpp */,
- 1AF4CEE818BC350100BC2D34 /* DefaultVisitedLinkStore.h */,
A718760D0B2A120100A16ECE /* DragActions.h */,
A7CA59620B27C1F200FA021D /* DragClient.h */,
A7CA595C0B27BD9E00FA021D /* DragController.cpp */,
99E45A1318A021760026D88F /* replay */ = {
isa = PBXGroup;
children = (
+ 99CC0B3818BE9849006CEBCC /* AllReplayInputs.h */,
+ 99CC0B3918BE9849006CEBCC /* CapturingInputCursor.cpp */,
+ 99CC0B3A18BE9849006CEBCC /* CapturingInputCursor.h */,
99E45A1618A063BE0026D88F /* EventLoopInput.h */,
+ 99CC0B3B18BE9849006CEBCC /* EventLoopInputDispatcher.cpp */,
+ 99CC0B3C18BE9849006CEBCC /* EventLoopInputDispatcher.h */,
+ 99CC0B3D18BE9849006CEBCC /* FunctorInputCursor.h */,
+ 99CC0B3E18BE9849006CEBCC /* ReplayController.cpp */,
+ 99CC0B3F18BE9849006CEBCC /* ReplayController.h */,
+ 99CC0B4018BE9849006CEBCC /* ReplayingInputCursor.cpp */,
+ 99CC0B4118BE9849006CEBCC /* ReplayingInputCursor.h */,
+ 99CC0B4218BE9849006CEBCC /* ReplayInputCreationMethods.cpp */,
+ 99CC0B4318BE9849006CEBCC /* ReplayInputDispatchMethods.cpp */,
990A19F418ADA48400183FD1 /* ReplayInputTypes.cpp */,
990A19F518ADA48400183FD1 /* ReplayInputTypes.h */,
+ 99CC0B4418BE9849006CEBCC /* ReplaySession.cpp */,
+ 99CC0B4518BE9849006CEBCC /* ReplaySession.h */,
+ 99CC0B4618BE9849006CEBCC /* ReplaySessionSegment.cpp */,
+ 99CC0B4718BE9849006CEBCC /* ReplaySessionSegment.h */,
+ 99CC0B4818BE9849006CEBCC /* SegmentedInputStorage.cpp */,
+ 99CC0B4918BE9849006CEBCC /* SegmentedInputStorage.h */,
+ 99CC0B4A18BE9849006CEBCC /* SerializationMethods.cpp */,
+ 99CC0B4B18BE9849006CEBCC /* SerializationMethods.h */,
9920398018B95BC600B39AF9 /* UserInputBridge.cpp */,
9920398118B95BC600B39AF9 /* UserInputBridge.h */,
+ 99CC0B4C18BE9849006CEBCC /* WebInputs.json */,
);
path = replay;
sourceTree = "<group>";
A5C974CE11485FDA0066F2AB /* cocoa */ = {
isa = PBXGroup;
children = (
- 7CC564B918BAC720001B9652 /* TelephoneNumberDetectorCocoa.cpp */,
A5C974CF11485FF10066F2AB /* KeyEventCocoa.h */,
A5C974D011485FF10066F2AB /* KeyEventCocoa.mm */,
+ 7CC564B918BAC720001B9652 /* TelephoneNumberDetectorCocoa.cpp */,
);
path = cocoa;
sourceTree = "<group>";
BCF7E491137CD7C7001DDAE7 /* AdjustViewSizeOrNot.h in Headers */,
84D0C4061115F1EA0018AA34 /* AffineTransform.h in Headers */,
0705850817FA4689005F2BCB /* AllAudioCapabilities.h in Headers */,
+ 99CC0B4D18BE9849006CEBCC /* AllReplayInputs.h in Headers */,
073AB4B317F8BACA006E0D6F /* AllVideoCapabilities.h in Headers */,
CEDA12D7152CA1CB00D9E08D /* AlternativeTextClient.h in Headers */,
CE08C3D2152B599A0021B8C2 /* AlternativeTextController.h in Headers */,
07C59B7617F7D0DB000FBCBB /* CapabilityRange.h in Headers */,
079D0868162F20E800DB8658 /* CaptionUserPreferences.h in Headers */,
079D086B162F21F900DB8658 /* CaptionUserPreferencesMediaAF.h in Headers */,
+ 99CC0B4F18BE9849006CEBCC /* CapturingInputCursor.h in Headers */,
6550B69E099DF0270090D781 /* CDATASection.h in Headers */,
CDDD571518B57A8200A94FCB /* CDMSession.h in Headers */,
5FA904CA178E61F5004C8A2D /* CertificateInfo.h in Headers */,
97627B8E14FB3CEE002CDCA1 /* ContextDestructionObserver.h in Headers */,
93B6A0E60B0BCA5C00F5027A /* ContextMenu.h in Headers */,
065AD4F50B0C2EDA005A2B1D /* ContextMenuClient.h in Headers */,
+ 5106D7BE18BDB76F000AB166 /* ContextMenuContext.h in Headers */,
065AD4F70B0C2EDA005A2B1D /* ContextMenuController.h in Headers */,
06027CAD0B1CBFC000884B2D /* ContextMenuItem.h in Headers */,
7ADE722610CBBB9B006B3B3A /* ContextMenuProvider.h in Headers */,
41A3D58F101C152D00316D07 /* DedicatedWorkerThread.h in Headers */,
FD06DFA6134A4DEF006F5D7D /* DefaultAudioDestinationNode.h in Headers */,
4167EBF6102962BA003D252A /* DefaultSharedWorkerRepository.h in Headers */,
+ 1AF4CEEA18BC350100BC2D34 /* DefaultVisitedLinkStore.h in Headers */,
FD31602C12B0267600C1A359 /* DelayDSPKernel.h in Headers */,
FD31602E12B0267600C1A359 /* DelayNode.h in Headers */,
FD31603112B0267600C1A359 /* DelayProcessor.h in Headers */,
AD4495F4141FC08900541EDF /* EventListenerMap.h in Headers */,
1CA19E160DC255CA0065A994 /* EventLoop.h in Headers */,
99E45A1718A063BE0026D88F /* EventLoopInput.h in Headers */,
+ 99CC0B5118BE9849006CEBCC /* EventLoopInputDispatcher.h in Headers */,
939885C408B7E3D100E707C4 /* EventNames.h in Headers */,
8F67561B1288B17B0047ACA3 /* EventQueue.h in Headers */,
E0FEF372B17C53EAC1C1FBEE /* EventSource.h in Headers */,
97205AB0123928CA00B17380 /* FTPDirectoryDocument.h in Headers */,
51C81B8A0C4422F70019ECE3 /* FTPDirectoryParser.h in Headers */,
26B999931803B9D900D01121 /* FunctionCall.h in Headers */,
+ 99CC0B5218BE9849006CEBCC /* FunctorInputCursor.h in Headers */,
FD31600D12B0267600C1A359 /* GainNode.h in Headers */,
935C477509AC4D8E00A6AAB4 /* GapRects.h in Headers */,
1432E8470C51493800B1500F /* GCController.h in Headers */,
977B3867122883E900B81FF8 /* HTMLDocumentParser.h in Headers */,
93309DE8099E64920056E581 /* htmlediting.h in Headers */,
93F198E608245E59001E9ABC /* HTMLElement.h in Headers */,
- 9920398318B95BC600B39AF9 /* UserInputBridge.h in Headers */,
A17C81230F2A5CF7005DAAEB /* HTMLElementFactory.h in Headers */,
977B37241228721700B81FF8 /* HTMLElementStack.h in Headers */,
B562DB6017D3CD630010AF96 /* HTMLElementTypeHelpers.h in Headers */,
978AD67514130A8D00C7CAE3 /* HTMLSpanElement.h in Headers */,
A871DC230A15205700B12A68 /* HTMLStyleElement.h in Headers */,
D3D4E973130C7CFE007BA540 /* HTMLSummaryElement.h in Headers */,
+ 99CC0B6B18BEA1FF006CEBCC /* WebReplayInputs.h in Headers */,
A871DB2B0A150BD600B12A68 /* HTMLTableCaptionElement.h in Headers */,
A871DB2A0A150BD600B12A68 /* HTMLTableCellElement.h in Headers */,
A871DB2F0A150BD600B12A68 /* HTMLTableColElement.h in Headers */,
0F03C0751884805500A5F8CA /* InspectorOverlay.h in Headers */,
4F6FDD651341DEDD001F8EE3 /* InspectorPageAgent.h in Headers */,
9F0D6B2F121BFEBA006C0288 /* InspectorProfilerAgent.h in Headers */,
+ 99CC0B6718BE9F15006CEBCC /* InspectorReplayAgent.h in Headers */,
82AB1776125C826700C5069D /* InspectorResourceAgent.h in Headers */,
82AB1774125C826700C5069D /* InspectorStyleSheet.h in Headers */,
82889B4D13C62392009A6156 /* InspectorStyleTextEditor.h in Headers */,
FDA15EBE12B03F0B003A583A /* JSConvolverNode.h in Headers */,
FE6FD48E0F676E9300092873 /* JSCoordinates.h in Headers */,
930705DA09E0C9BF00B17FE4 /* JSCounter.h in Headers */,
- 1AF4CEEA18BC350100BC2D34 /* DefaultVisitedLinkStore.h in Headers */,
975CA2A21303679D00E99AD9 /* JSCrypto.h in Headers */,
E157A8F118185425009F821D /* JSCryptoAlgorithmBuilder.h in Headers */,
E1C657131815F9DD00256CDD /* JSCryptoAlgorithmDictionary.h in Headers */,
1AE2AA210A1CDAB400B42B25 /* JSHTMLBaseFontElement.h in Headers */,
1AE2AA230A1CDAB400B42B25 /* JSHTMLBodyElement.h in Headers */,
1AE2AA250A1CDAB400B42B25 /* JSHTMLBRElement.h in Headers */,
- 7CC564B818BABEA6001B9652 /* TelephoneNumberDetector.h in Headers */,
A80E7E9F0A1A83E3007FB8C5 /* JSHTMLButtonElement.h in Headers */,
938E666209F09B87008A48EC /* JSHTMLCanvasElement.h in Headers */,
BCCBAD410C18C14200CE890F /* JSHTMLCollection.h in Headers */,
450CEBF115073BBE002BB149 /* LabelableElement.h in Headers */,
A456FA2711AD4A830020B420 /* LabelsNodeList.h in Headers */,
85EC9AFB0A71A2C600EEEAED /* Language.h in Headers */,
- 5106D7BE18BDB76F000AB166 /* ContextMenuContext.h in Headers */,
2917B5621473496C0052C9D0 /* LayerFlushScheduler.h in Headers */,
2917B5631473496C0052C9D0 /* LayerFlushSchedulerClient.h in Headers */,
93F72AF31666EDFC002A02BD /* LayerPool.h in Headers */,
A871DFE40A15376B00B12A68 /* RenderWidget.h in Headers */,
A89CCC530F44E98100B5DA10 /* ReplaceNodeWithSpanCommand.h in Headers */,
93309E0A099E64920056E581 /* ReplaceSelectionCommand.h in Headers */,
+ 99CC0B5418BE9849006CEBCC /* ReplayController.h in Headers */,
+ 99CC0B5618BE984A006CEBCC /* ReplayingInputCursor.h in Headers */,
990A1A0518ADA48400183FD1 /* ReplayInputTypes.h in Headers */,
+ 99CC0B5A18BE984A006CEBCC /* ReplaySession.h in Headers */,
+ 99CC0B5C18BE984A006CEBCC /* ReplaySessionSegment.h in Headers */,
4998AEC613F9D0EA0090B1AA /* RequestAnimationFrameCallback.h in Headers */,
F55B3DD01251F12D003EF269 /* ResetInputType.h in Headers */,
514BC843161CF05C004D52F4 /* ResourceBuffer.h in Headers */,
974D2DA5146A535D00D51F8B /* SecurityPolicy.h in Headers */,
2D5BC42716F882EE007048D0 /* SecurityPolicyViolationEvent.h in Headers */,
371F4FFC0D25E7F300ECE0D5 /* SegmentedFontData.h in Headers */,
+ 99CC0B5E18BE984A006CEBCC /* SegmentedInputStorage.h in Headers */,
B2C3DA2F0D006C1D00EF6F26 /* SegmentedString.h in Headers */,
BEA807C90F714A0300524199 /* SelectionRect.h in Headers */,
E44B4BB4141650D7002B1D8B /* SelectorChecker.h in Headers */,
26B999971804D54200D01121 /* SelectorCompiler.h in Headers */,
415071581685067300C3C7B3 /* SelectorFilter.h in Headers */,
E45322AC140CE267005A0F92 /* SelectorQuery.h in Headers */,
+ 99CC0B6018BE984A006CEBCC /* SerializationMethods.h in Headers */,
E18DF33518AAF12C00773E59 /* SerializedCryptoKeyWrap.h in Headers */,
A75E497610752ACB00C9B896 /* SerializedScriptValue.h in Headers */,
756B2CE118B7101600FECFAA /* SessionID.h in Headers */,
A8CFF0510A154F09000A4234 /* TableLayout.h in Headers */,
BCE3BEC30D222B1D007E06E4 /* TagNodeList.h in Headers */,
F55B3DD61251F12D003EF269 /* TelephoneInputType.h in Headers */,
+ 7CC564B818BABEA6001B9652 /* TelephoneNumberDetector.h in Headers */,
C65046A9167BFB5500CC2A4D /* TemplateContentDocumentFragment.h in Headers */,
6550B6A6099DF0270090D781 /* Text.h in Headers */,
93309E17099E64920056E581 /* TextAffinity.h in Headers */,
003F1FEA11E6AB43008258D9 /* UserContentTypes.h in Headers */,
BCACF3BD1072921A00C0C8A3 /* UserContentURLPattern.h in Headers */,
2542F4DB1166C25A00E89A86 /* UserGestureIndicator.h in Headers */,
+ 9920398318B95BC600B39AF9 /* UserInputBridge.h in Headers */,
078E092E17D14D1C00420AA1 /* UserMediaClient.h in Headers */,
078E092F17D14D1C00420AA1 /* UserMediaController.h in Headers */,
078E093017D14D1C00420AA1 /* UserMediaRequest.h in Headers */,
93309E20099E64920056E581 /* VisiblePosition.h in Headers */,
A883DF280F3D045D00F19BF6 /* VisibleSelection.h in Headers */,
93309E1E099E64920056E581 /* VisibleUnits.h in Headers */,
- 1ABA80001897341200DCE9D6 /* VisitedLinkStore.h in Headers */,
419BC2DF1685329900D64D6D /* VisitedLinkState.h in Headers */,
+ 1ABA80001897341200DCE9D6 /* VisitedLinkStore.h in Headers */,
E44613B60CD6344E00FADA75 /* VoidCallback.h in Headers */,
BE20507A18A4586B0080647E /* VTTCue.h in Headers */,
A14832B0187F618D00DA63A6 /* WAKAppKitStubs.h in Headers */,
9370918D1416D86B00477333 /* textAreaResizeCorner@2x.png in Resources */,
46D4F24B0AF97E810035385A /* verticalTextCursor.png in Resources */,
85136CA70AED665900F90A3D /* waitCursor.png in Resources */,
+ 99CC0B6118BE984A006CEBCC /* WebInputs.json in Resources */,
85136CA80AED665900F90A3D /* westResizeCursor.png in Resources */,
1AB1AE7A0C051FDE00139F4F /* zoomInCursor.png in Resources */,
1AB1AE7B0C051FDE00139F4F /* zoomOutCursor.png in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
- shellScript = "mkdir -p \"${BUILT_PRODUCTS_DIR}/DerivedSources/WebCore\"\ncd \"${BUILT_PRODUCTS_DIR}/DerivedSources/WebCore\"\n\n/bin/ln -sfh \"${SRCROOT}\" WebCore\nexport WebCore=\"WebCore\"\nexport InspectorScripts=\"${JAVASCRIPTCORE_PRIVATE_HEADERS_DIR}\"\n\nif [ ! $CC ]; then\n export CC=\"`xcrun -find clang`\"\nfi\n\nif [ ! $GPERF ]; then\n export GPERF=\"`xcrun -find gperf`\"\nfi\n\nif [ \"${ACTION}\" = \"build\" -o \"${ACTION}\" = \"install\" -o \"${ACTION}\" = \"installhdrs\" ]; then\n make --no-builtin-rules -f \"WebCore/DerivedSources.make\" -j `/usr/sbin/sysctl -n hw.activecpu` SDKROOT=\"${SDKROOT}\"\nfi\n";
+ shellScript = "mkdir -p \"${BUILT_PRODUCTS_DIR}/DerivedSources/WebCore\"\ncd \"${BUILT_PRODUCTS_DIR}/DerivedSources/WebCore\"\n\n/bin/ln -sfh \"${SRCROOT}\" WebCore\nexport WebCore=\"WebCore\"\nexport InspectorScripts=\"${JAVASCRIPTCORE_PRIVATE_HEADERS_DIR}\"\nexport WebReplayScripts=\"${JAVASCRIPTCORE_PRIVATE_HEADERS_DIR}\"\n\nif [ ! $CC ]; then\n export CC=\"`xcrun -find clang`\"\nfi\n\nif [ ! $GPERF ]; then\n export GPERF=\"`xcrun -find gperf`\"\nfi\n\nif [ \"${ACTION}\" = \"build\" -o \"${ACTION}\" = \"install\" -o \"${ACTION}\" = \"installhdrs\" ]; then\n make --no-builtin-rules -f \"WebCore/DerivedSources.make\" -j `/usr/sbin/sysctl -n hw.activecpu` SDKROOT=\"${SDKROOT}\"\nfi\n";
};
/* End PBXShellScriptBuildPhase section */
85031B3C0A44EFC700F992E0 /* BeforeUnloadEvent.cpp in Sources */,
B2C3DA230D006C1D00EF6F26 /* BidiContext.cpp in Sources */,
BCE7898B1120E8020060ECE5 /* BidiRun.cpp in Sources */,
- 5106D7BD18BDB76F000AB166 /* ContextMenuContext.cpp in Sources */,
FD31608C12B026F700C1A359 /* Biquad.cpp in Sources */,
FD31602412B0267600C1A359 /* BiquadDSPKernel.cpp in Sources */,
FDC54F041399B0DA008D9117 /* BiquadFilterNode.cpp in Sources */,
070584FF17F9F05E005F2BCB /* CapabilityRange.cpp in Sources */,
072CA86116CB4DC3008AE131 /* CaptionUserPreferences.cpp in Sources */,
079D086C162F21F900DB8658 /* CaptionUserPreferencesMediaAF.cpp in Sources */,
+ 99CC0B4E18BE9849006CEBCC /* CapturingInputCursor.cpp in Sources */,
6550B69D099DF0270090D781 /* CDATASection.cpp in Sources */,
CDA98E0B1603CD6000FEA3B1 /* CDM.cpp in Sources */,
CDCA98EB18B2C8EB00C12FF9 /* CDMPrivateMediaPlayer.cpp in Sources */,
97C471DB12F925BD0086354B /* ContentSecurityPolicy.cpp in Sources */,
41D015CB0F4B5C71004A662F /* ContentType.cpp in Sources */,
97627B8D14FB3CEE002CDCA1 /* ContextDestructionObserver.cpp in Sources */,
+ 5106D7BD18BDB76F000AB166 /* ContextMenuContext.cpp in Sources */,
065AD4F60B0C2EDA005A2B1D /* ContextMenuController.cpp in Sources */,
06027CB30B1CC03D00884B2D /* ContextMenuItemMac.mm in Sources */,
93B6A0EA0B0BCA8400F5027A /* ContextMenuMac.mm in Sources */,
41A3D58E101C152D00316D07 /* DedicatedWorkerThread.cpp in Sources */,
FD06DFA5134A4DEF006F5D7D /* DefaultAudioDestinationNode.cpp in Sources */,
4167EBF5102962BA003D252A /* DefaultSharedWorkerRepository.cpp in Sources */,
+ 1AF4CEE918BC350100BC2D34 /* DefaultVisitedLinkStore.cpp in Sources */,
FD31602B12B0267600C1A359 /* DelayDSPKernel.cpp in Sources */,
FD31602D12B0267600C1A359 /* DelayNode.cpp in Sources */,
FD31603012B0267600C1A359 /* DelayProcessor.cpp in Sources */,
FE6938B61045D67E008EABB6 /* EventHandlerIOS.mm in Sources */,
93C09A7F0B064EEF005ABD4D /* EventHandlerMac.mm in Sources */,
AD4495F3141FC08900541EDF /* EventListenerMap.cpp in Sources */,
+ 99CC0B5018BE9849006CEBCC /* EventLoopInputDispatcher.cpp in Sources */,
26F40D4A14904A6300CA67C4 /* EventLoopIOS.mm in Sources */,
1CA19E050DC255950065A994 /* EventLoopMac.mm in Sources */,
939885C308B7E3D100E707C4 /* EventNames.cpp in Sources */,
7C522D4B15B477E8009B7C95 /* InspectorOverlay.cpp in Sources */,
4F6FDD641341DEDD001F8EE3 /* InspectorPageAgent.cpp in Sources */,
9F0D6B2E121BFEBA006C0288 /* InspectorProfilerAgent.cpp in Sources */,
+ 99CC0B6618BE9F15006CEBCC /* InspectorReplayAgent.cpp in Sources */,
82AB1775125C826700C5069D /* InspectorResourceAgent.cpp in Sources */,
82AB1773125C826700C5069D /* InspectorStyleSheet.cpp in Sources */,
82889B4C13C62392009A6156 /* InspectorStyleTextEditor.cpp in Sources */,
8542A7960AE5C94200DF58DF /* JSSVGPoint.cpp in Sources */,
B2FA3DE20AB75A6F000E5AC4 /* JSSVGPointList.cpp in Sources */,
B2FA3DE50AB75A6F000E5AC4 /* JSSVGPolygonElement.cpp in Sources */,
- 7CC564BA18BAC720001B9652 /* TelephoneNumberDetectorCocoa.cpp in Sources */,
B2FA3DE70AB75A6F000E5AC4 /* JSSVGPolylineElement.cpp in Sources */,
B2FA3DE90AB75A6F000E5AC4 /* JSSVGPreserveAspectRatio.cpp in Sources */,
B2FA3DEB0AB75A6F000E5AC4 /* JSSVGRadialGradientElement.cpp in Sources */,
1ADA14100E1AE5D900023EE5 /* PluginMainThreadScheduler.cpp in Sources */,
71E2183B17359FB8006E6E4D /* PlugInsResourcesData.cpp in Sources */,
76FF17E311235673001D61B5 /* PluginViewNone.cpp in Sources */,
- 9920398218B95BC600B39AF9 /* UserInputBridge.cpp in Sources */,
B2B1F7160D00CAA8004AEA64 /* PointerEventsHitRules.cpp in Sources */,
A1E1154613015C4E0054AC8C /* PointLightSource.cpp in Sources */,
97059977107D975200A50A7C /* PolicyCallback.cpp in Sources */,
A871DFE50A15376B00B12A68 /* RenderWidget.cpp in Sources */,
A89CCC520F44E98100B5DA10 /* ReplaceNodeWithSpanCommand.cpp in Sources */,
93309E09099E64920056E581 /* ReplaceSelectionCommand.cpp in Sources */,
+ 99CC0B5318BE9849006CEBCC /* ReplayController.cpp in Sources */,
+ 99CC0B5518BE9849006CEBCC /* ReplayingInputCursor.cpp in Sources */,
+ 99CC0B5718BE984A006CEBCC /* ReplayInputCreationMethods.cpp in Sources */,
+ 99CC0B5818BE984A006CEBCC /* ReplayInputDispatchMethods.cpp in Sources */,
990A1A0418ADA48400183FD1 /* ReplayInputTypes.cpp in Sources */,
+ 99CC0B5918BE984A006CEBCC /* ReplaySession.cpp in Sources */,
+ 99CC0B5B18BE984A006CEBCC /* ReplaySessionSegment.cpp in Sources */,
F55B3DCF1251F12D003EF269 /* ResetInputType.cpp in Sources */,
514BC842161CF05C004D52F4 /* ResourceBuffer.cpp in Sources */,
514BC83F161CF04A004D52F4 /* ResourceBuffer.mm in Sources */,
BCD0E0FA0E972C3500265DEA /* SecurityOrigin.cpp in Sources */,
974D2DA4146A535D00D51F8B /* SecurityPolicy.cpp in Sources */,
371F4FFD0D25E7F300ECE0D5 /* SegmentedFontData.cpp in Sources */,
+ 99CC0B5D18BE984A006CEBCC /* SegmentedInputStorage.cpp in Sources */,
B2C3DA2E0D006C1D00EF6F26 /* SegmentedString.cpp in Sources */,
BEA807C80F714A0300524199 /* SelectionRect.cpp in Sources */,
E44B4BB3141650D7002B1D8B /* SelectorChecker.cpp in Sources */,
26B999961804D54200D01121 /* SelectorCompiler.cpp in Sources */,
415071571685067300C3C7B3 /* SelectorFilter.cpp in Sources */,
E45322AB140CE267005A0F92 /* SelectorQuery.cpp in Sources */,
+ 99CC0B5F18BE984A006CEBCC /* SerializationMethods.cpp in Sources */,
E18DF33818AAF14D00773E59 /* SerializedCryptoKeyWrapMac.mm in Sources */,
A75E497710752ACB00C9B896 /* SerializedScriptValue.cpp in Sources */,
93309E0F099E64920056E581 /* SetNodeAttributeCommand.cpp in Sources */,
B2227A230D00BF220071B782 /* SVGForeignObjectElement.cpp in Sources */,
B2227A260D00BF220071B782 /* SVGGElement.cpp in Sources */,
087E0AF613606D0B00FA4BA8 /* SVGGlyph.cpp in Sources */,
+ 99CC0B6A18BEA1FF006CEBCC /* WebReplayInputs.cpp in Sources */,
B2A1F2AD0CEF0ABF00442F6A /* SVGGlyphElement.cpp in Sources */,
24D912BD13CA9A9700D21915 /* SVGGlyphRefElement.cpp in Sources */,
B2227A290D00BF220071B782 /* SVGGradientElement.cpp in Sources */,
B2227AC00D00BF220071B782 /* SVGSymbolElement.cpp in Sources */,
B2227AC40D00BF220071B782 /* SVGTests.cpp in Sources */,
B2227AC70D00BF220071B782 /* SVGTextContentElement.cpp in Sources */,
- 1AF4CEEC18BC3C1B00BC2D34 /* VisitedLinkStore.cpp in Sources */,
B2227ACA0D00BF220071B782 /* SVGTextElement.cpp in Sources */,
B2227ACD0D00BF220071B782 /* SVGTextPathElement.cpp in Sources */,
B2227AD00D00BF220071B782 /* SVGTextPositioningElement.cpp in Sources */,
B2227AEF0D00BF220071B782 /* SVGViewElement.cpp in Sources */,
B2227AF20D00BF220071B782 /* SVGViewSpec.cpp in Sources */,
8485228A1190173C006EDC7F /* SVGVKernElement.cpp in Sources */,
- 1AF4CEE918BC350100BC2D34 /* DefaultVisitedLinkStore.cpp in Sources */,
B2227AF50D00BF220071B782 /* SVGZoomAndPan.cpp in Sources */,
B2E4EC970D00C22B00432643 /* SVGZoomEvent.cpp in Sources */,
E180811216FCF42F00B80D07 /* SynchronousLoaderClient.cpp in Sources */,
5DA97ECE168E787B000E3676 /* SystemVersionMac.mm in Sources */,
BCE3BEC20D222B1D007E06E4 /* TagNodeList.cpp in Sources */,
F55B3DD51251F12D003EF269 /* TelephoneInputType.cpp in Sources */,
+ 7CC564BA18BAC720001B9652 /* TelephoneNumberDetectorCocoa.cpp in Sources */,
7A29BA6A187B7C1D00F29CEB /* TemporaryOpenGLSetting.cpp in Sources */,
6550B6A5099DF0270090D781 /* Text.cpp in Sources */,
CE7B2DB61586ABAD0098B3FA /* TextAlternativeWithRange.mm in Sources */,
1AE79D42188DB61F002239C2 /* UserContentController.cpp in Sources */,
BCACF3BC1072921A00C0C8A3 /* UserContentURLPattern.cpp in Sources */,
2542F4DA1166C25A00E89A86 /* UserGestureIndicator.cpp in Sources */,
+ 9920398218B95BC600B39AF9 /* UserInputBridge.cpp in Sources */,
078E091217D14CEE00420AA1 /* UserMediaController.cpp in Sources */,
078E091317D14CEE00420AA1 /* UserMediaRequest.cpp in Sources */,
BCDF317B11F8D683003C5BF8 /* UserTypingGestureIndicator.cpp in Sources */,
A883DF270F3D045D00F19BF6 /* VisibleSelection.cpp in Sources */,
93309E1D099E64920056E581 /* VisibleUnits.cpp in Sources */,
419BC2DE1685329900D64D6D /* VisitedLinkState.cpp in Sources */,
+ 1AF4CEEC18BC3C1B00BC2D34 /* VisitedLinkStore.cpp in Sources */,
BE20507918A458680080647E /* VTTCue.cpp in Sources */,
A14832B1187F61E100DA63A6 /* WAKAppKitStubs.m in Sources */,
A14832B3187F629100DA63A6 /* WAKClipView.m in Sources */,
/*
* Copyright (C) 2011 Google Inc. 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
#include "InspectorOverlay.h"
#include "InspectorPageAgent.h"
#include "InspectorProfilerAgent.h"
+#include "InspectorReplayAgent.h"
#include "InspectorResourceAgent.h"
#include "InspectorTimelineAgent.h"
#include "InspectorWebBackendDispatchers.h"
m_agents.append(std::make_unique<InspectorIndexedDBAgent>(m_instrumentingAgents.get(), m_injectedScriptManager.get(), pageAgent));
#endif
+#if ENABLE(WEB_REPLAY)
+ m_agents.append(std::make_unique<InspectorReplayAgent>(m_instrumentingAgents.get(), pageAgent));
+#endif
+
auto domStorageAgentPtr = std::make_unique<InspectorDOMStorageAgent>(m_instrumentingAgents.get(), m_pageAgent);
InspectorDOMStorageAgent* domStorageAgent = domStorageAgentPtr.get();
m_agents.append(std::move(domStorageAgentPtr));
/*
* Copyright (C) 2011 Google Inc. 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
#include <wtf/StdLibExtras.h>
#include <wtf/text/CString.h>
+#if ENABLE(WEB_REPLAY)
+#include "InspectorReplayAgent.h"
+#include "ReplayController.h" // for ReplayPosition.
+#endif
+
using namespace Inspector;
namespace WebCore {
{
if (InspectorPageAgent* pageAgent = instrumentingAgents->inspectorPageAgent())
pageAgent->frameDetached(frame);
+
+#if ENABLE(WEB_REPLAY)
+ if (frame->isMainFrame()) {
+ if (InspectorReplayAgent* replayAgent = instrumentingAgents->inspectorReplayAgent())
+ replayAgent->frameDetached(frame);
+ }
+#endif
}
void InspectorInstrumentation::didCommitLoadImpl(InstrumentingAgents* instrumentingAgents, Page* page, DocumentLoader* loader)
domAgent->didCommitLoad(loader->frame()->document());
if (InspectorPageAgent* pageAgent = instrumentingAgents->inspectorPageAgent())
pageAgent->frameNavigated(loader);
+#if ENABLE(WEB_REPLAY)
+ if (InspectorReplayAgent* replayAgent = instrumentingAgents->inspectorReplayAgent())
+ replayAgent->frameNavigated(loader);
+#endif
}
void InspectorInstrumentation::frameDocumentUpdatedImpl(InstrumentingAgents* instrumentingAgents, Frame* frame)
}
#endif
+#if ENABLE(WEB_REPLAY)
+void InspectorInstrumentation::sessionCreatedImpl(InstrumentingAgents* instrumentingAgents, PassRefPtr<ReplaySession> session)
+{
+ if (InspectorReplayAgent* replayAgent = instrumentingAgents->inspectorReplayAgent())
+ replayAgent->sessionCreated(session);
+}
+
+void InspectorInstrumentation::sessionLoadedImpl(InstrumentingAgents* instrumentingAgents, PassRefPtr<ReplaySession> session)
+{
+ if (InspectorReplayAgent* replayAgent = instrumentingAgents->inspectorReplayAgent())
+ replayAgent->sessionLoaded(session);
+}
+
+void InspectorInstrumentation::sessionModifiedImpl(InstrumentingAgents* instrumentingAgents, PassRefPtr<ReplaySession> session)
+{
+ if (InspectorReplayAgent* replayAgent = instrumentingAgents->inspectorReplayAgent())
+ replayAgent->sessionModified(session);
+}
+
+void InspectorInstrumentation::segmentCreatedImpl(InstrumentingAgents* instrumentingAgents, PassRefPtr<ReplaySessionSegment> segment)
+{
+ if (InspectorReplayAgent* replayAgent = instrumentingAgents->inspectorReplayAgent())
+ replayAgent->segmentCreated(segment);
+}
+
+void InspectorInstrumentation::segmentCompletedImpl(InstrumentingAgents* instrumentingAgents, PassRefPtr<ReplaySessionSegment> segment)
+{
+ if (InspectorReplayAgent* replayAgent = instrumentingAgents->inspectorReplayAgent())
+ replayAgent->segmentCompleted(segment);
+}
+
+void InspectorInstrumentation::segmentLoadedImpl(InstrumentingAgents* instrumentingAgents, PassRefPtr<ReplaySessionSegment> segment)
+{
+ if (InspectorReplayAgent* replayAgent = instrumentingAgents->inspectorReplayAgent())
+ replayAgent->segmentLoaded(segment);
+}
+
+void InspectorInstrumentation::segmentUnloadedImpl(InstrumentingAgents* instrumentingAgents)
+{
+ if (InspectorReplayAgent* replayAgent = instrumentingAgents->inspectorReplayAgent())
+ replayAgent->segmentUnloaded();
+}
+
+void InspectorInstrumentation::captureStartedImpl(InstrumentingAgents* instrumentingAgents)
+{
+ if (InspectorReplayAgent* replayAgent = instrumentingAgents->inspectorReplayAgent())
+ replayAgent->captureStarted();
+}
+
+void InspectorInstrumentation::captureStoppedImpl(InstrumentingAgents* instrumentingAgents)
+{
+ if (InspectorReplayAgent* replayAgent = instrumentingAgents->inspectorReplayAgent())
+ replayAgent->captureStopped();
+}
+
+void InspectorInstrumentation::playbackStartedImpl(InstrumentingAgents* instrumentingAgents)
+{
+ if (InspectorReplayAgent* replayAgent = instrumentingAgents->inspectorReplayAgent())
+ replayAgent->playbackStarted();
+}
+
+void InspectorInstrumentation::playbackPausedImpl(InstrumentingAgents* instrumentingAgents, const ReplayPosition& position)
+{
+ if (InspectorReplayAgent* replayAgent = instrumentingAgents->inspectorReplayAgent())
+ replayAgent->playbackPaused(position);
+}
+
+void InspectorInstrumentation::playbackHitPositionImpl(InstrumentingAgents* instrumentingAgents, const ReplayPosition& position)
+{
+ if (InspectorReplayAgent* replayAgent = instrumentingAgents->inspectorReplayAgent())
+ replayAgent->playbackHitPosition(position);
+}
+#endif
+
void InspectorInstrumentation::networkStateChangedImpl(InstrumentingAgents* instrumentingAgents)
{
if (InspectorApplicationCacheAgent* applicationCacheAgent = instrumentingAgents->inspectorApplicationCacheAgent())
return instrumentingAgents && instrumentingAgents->inspectorTimelineAgent();
}
+bool InspectorInstrumentation::replayAgentEnabled(ScriptExecutionContext* scriptExecutionContext)
+{
+#if ENABLE(WEB_REPLAY)
+ InstrumentingAgents* instrumentingAgents = instrumentingAgentsForContext(scriptExecutionContext);
+ return instrumentingAgents && instrumentingAgents->inspectorReplayAgent();
+#else
+ UNUSED_PARAM(scriptExecutionContext);
+ return false;
+#endif
+}
+
void InspectorInstrumentation::pauseOnNativeEventIfNeeded(InstrumentingAgents* instrumentingAgents, bool isDOMEvent, const String& eventName, bool synchronous)
{
if (InspectorDOMDebuggerAgent* domDebuggerAgent = instrumentingAgents->inspectorDOMDebuggerAgent())
/*
* Copyright (C) 2010 Google Inc. 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
#include <inspector/ConsoleTypes.h>
#include <wtf/RefPtr.h>
+#if ENABLE(WEB_REPLAY)
+#include "ReplaySession.h"
+#include "ReplaySessionSegment.h"
+#endif
+
+
namespace Deprecated {
class ScriptObject;
}
class WorkerGlobalScopeProxy;
class XMLHttpRequest;
+struct ReplayPosition;
+
#define FAST_RETURN_IF_NO_FRONTENDS(value) if (LIKELY(!hasFrontends())) return value;
class InspectorInstrumentation {
static void workerGlobalScopeTerminated(ScriptExecutionContext*, WorkerGlobalScopeProxy*);
static void willEvaluateWorkerScript(WorkerGlobalScope*, int workerThreadStartMode);
+#if ENABLE(WEB_REPLAY)
+ static void sessionCreated(Page*, PassRefPtr<ReplaySession>);
+ static void sessionLoaded(Page*, PassRefPtr<ReplaySession>);
+ static void sessionModified(Page*, PassRefPtr<ReplaySession>);
+
+ static void segmentCreated(Page*, PassRefPtr<ReplaySessionSegment>);
+ static void segmentCompleted(Page*, PassRefPtr<ReplaySessionSegment>);
+ static void segmentLoaded(Page*, PassRefPtr<ReplaySessionSegment>);
+ static void segmentUnloaded(Page*);
+
+ static void captureStarted(Page*);
+ static void captureStopped(Page*);
+
+ static void playbackStarted(Page*);
+ static void playbackPaused(Page*, const ReplayPosition&);
+ static void playbackHitPosition(Page*, const ReplayPosition&);
+#endif
+
#if ENABLE(WEB_SOCKETS)
static void didCreateWebSocket(Document*, unsigned long identifier, const URL& requestURL, const URL& documentURL, const String& protocol);
static void willSendWebSocketHandshakeRequest(Document*, unsigned long identifier, const ResourceRequest&);
static bool hasFrontends() { return s_frontendCounter; }
static bool consoleAgentEnabled(ScriptExecutionContext*);
static bool timelineAgentEnabled(ScriptExecutionContext*);
+ static bool replayAgentEnabled(ScriptExecutionContext*);
#else
static bool hasFrontends() { return false; }
static bool consoleAgentEnabled(ScriptExecutionContext*) { return false; }
static bool runtimeAgentEnabled(Frame*) { return false; }
static bool timelineAgentEnabled(ScriptExecutionContext*) { return false; }
+ static bool replayAgentEnabled(ScriptExecutionContext*) { return false; }
#endif
static void registerInstrumentingAgents(InstrumentingAgents*);
static void didStartWorkerGlobalScopeImpl(InstrumentingAgents*, WorkerGlobalScopeProxy*, const URL&);
static void workerGlobalScopeTerminatedImpl(InstrumentingAgents*, WorkerGlobalScopeProxy*);
+#if ENABLE(WEB_REPLAY)
+ static void sessionCreatedImpl(InstrumentingAgents*, PassRefPtr<ReplaySession>);
+ static void sessionLoadedImpl(InstrumentingAgents*, PassRefPtr<ReplaySession>);
+ static void sessionModifiedImpl(InstrumentingAgents*, PassRefPtr<ReplaySession>);
+
+ static void segmentCreatedImpl(InstrumentingAgents*, PassRefPtr<ReplaySessionSegment>);
+ static void segmentCompletedImpl(InstrumentingAgents*, PassRefPtr<ReplaySessionSegment>);
+ static void segmentLoadedImpl(InstrumentingAgents*, PassRefPtr<ReplaySessionSegment>);
+ static void segmentUnloadedImpl(InstrumentingAgents*);
+
+ static void captureStartedImpl(InstrumentingAgents*);
+ static void captureStoppedImpl(InstrumentingAgents*);
+
+ static void playbackStartedImpl(InstrumentingAgents*);
+ static void playbackPausedImpl(InstrumentingAgents*, const ReplayPosition&);
+ static void playbackHitPositionImpl(InstrumentingAgents*, const ReplayPosition&);
+#endif
+
#if ENABLE(WEB_SOCKETS)
static void didCreateWebSocketImpl(InstrumentingAgents*, unsigned long identifier, const URL& requestURL, const URL& documentURL, const String& protocol, Document*);
static void willSendWebSocketHandshakeRequestImpl(InstrumentingAgents*, unsigned long identifier, const ResourceRequest&, Document*);
}
#endif
+#if ENABLE(WEB_REPLAY)
+inline void InspectorInstrumentation::sessionCreated(Page* page, PassRefPtr<ReplaySession> session)
+{
+#if ENABLE(INSPECTOR)
+ FAST_RETURN_IF_NO_FRONTENDS(void());
+ if (InstrumentingAgents* instrumentingAgents = instrumentingAgentsForPage(page))
+ sessionCreatedImpl(instrumentingAgents, session);
+#else
+ UNUSED_PARAM(page);
+ UNUSED_PARAM(session);
+#endif
+}
+
+inline void InspectorInstrumentation::sessionLoaded(Page* page, PassRefPtr<ReplaySession> session)
+{
+#if ENABLE(INSPECTOR)
+ FAST_RETURN_IF_NO_FRONTENDS(void());
+ if (InstrumentingAgents* instrumentingAgents = instrumentingAgentsForPage(page))
+ sessionLoadedImpl(instrumentingAgents, session);
+#else
+ UNUSED_PARAM(page);
+ UNUSED_PARAM(session);
+#endif
+}
+
+inline void InspectorInstrumentation::sessionModified(Page* page, PassRefPtr<ReplaySession> session)
+{
+#if ENABLE(INSPECTOR)
+ FAST_RETURN_IF_NO_FRONTENDS(void());
+ if (InstrumentingAgents* instrumentingAgents = instrumentingAgentsForPage(page))
+ sessionModifiedImpl(instrumentingAgents, session);
+#else
+ UNUSED_PARAM(page);
+ UNUSED_PARAM(session);
+#endif
+}
+
+inline void InspectorInstrumentation::segmentCreated(Page* page, PassRefPtr<ReplaySessionSegment> segment)
+{
+#if ENABLE(INSPECTOR)
+ FAST_RETURN_IF_NO_FRONTENDS(void());
+ if (InstrumentingAgents* instrumentingAgents = instrumentingAgentsForPage(page))
+ segmentCreatedImpl(instrumentingAgents, segment);
+#else
+ UNUSED_PARAM(page);
+ UNUSED_PARAM(segment);
+#endif
+}
+
+inline void InspectorInstrumentation::segmentCompleted(Page* page, PassRefPtr<ReplaySessionSegment> segment)
+{
+#if ENABLE(INSPECTOR)
+ FAST_RETURN_IF_NO_FRONTENDS(void());
+ if (InstrumentingAgents* instrumentingAgents = instrumentingAgentsForPage(page))
+ segmentCompletedImpl(instrumentingAgents, segment);
+#else
+ UNUSED_PARAM(page);
+ UNUSED_PARAM(segment);
+#endif
+}
+
+inline void InspectorInstrumentation::segmentLoaded(Page* page, PassRefPtr<ReplaySessionSegment> segment)
+{
+#if ENABLE(INSPECTOR)
+ FAST_RETURN_IF_NO_FRONTENDS(void());
+ if (InstrumentingAgents* instrumentingAgents = instrumentingAgentsForPage(page))
+ segmentLoadedImpl(instrumentingAgents, segment);
+#else
+ UNUSED_PARAM(page);
+ UNUSED_PARAM(segment);
+#endif
+}
+
+inline void InspectorInstrumentation::segmentUnloaded(Page* page)
+{
+#if ENABLE(INSPECTOR)
+ FAST_RETURN_IF_NO_FRONTENDS(void());
+ if (InstrumentingAgents* instrumentingAgents = instrumentingAgentsForPage(page))
+ segmentUnloadedImpl(instrumentingAgents);
+#else
+ UNUSED_PARAM(page);
+#endif
+}
+
+inline void InspectorInstrumentation::captureStarted(Page* page)
+{
+#if ENABLE(INSPECTOR)
+ FAST_RETURN_IF_NO_FRONTENDS(void());
+ if (InstrumentingAgents* instrumentingAgents = instrumentingAgentsForPage(page))
+ captureStartedImpl(instrumentingAgents);
+#else
+ UNUSED_PARAM(page);
+#endif
+}
+
+inline void InspectorInstrumentation::captureStopped(Page* page)
+{
+#if ENABLE(INSPECTOR)
+ FAST_RETURN_IF_NO_FRONTENDS(void());
+ if (InstrumentingAgents* instrumentingAgents = instrumentingAgentsForPage(page))
+ captureStoppedImpl(instrumentingAgents);
+#else
+ UNUSED_PARAM(page);
+#endif
+}
+
+inline void InspectorInstrumentation::playbackStarted(Page* page)
+{
+#if ENABLE(INSPECTOR)
+ FAST_RETURN_IF_NO_FRONTENDS(void());
+ if (InstrumentingAgents* instrumentingAgents = instrumentingAgentsForPage(page))
+ playbackStartedImpl(instrumentingAgents);
+#else
+ UNUSED_PARAM(page);
+#endif
+}
+
+inline void InspectorInstrumentation::playbackPaused(Page* page, const ReplayPosition& position)
+{
+#if ENABLE(INSPECTOR)
+ FAST_RETURN_IF_NO_FRONTENDS(void());
+ if (InstrumentingAgents* instrumentingAgents = instrumentingAgentsForPage(page))
+ playbackPausedImpl(instrumentingAgents, position);
+#else
+ UNUSED_PARAM(page);
+ UNUSED_PARAM(position);
+#endif
+}
+
+inline void InspectorInstrumentation::playbackHitPosition(Page* page, const ReplayPosition& position)
+{
+#if ENABLE(INSPECTOR)
+ FAST_RETURN_IF_NO_FRONTENDS(void());
+ if (InstrumentingAgents* instrumentingAgents = instrumentingAgentsForPage(page))
+ playbackHitPositionImpl(instrumentingAgents, position);
+#else
+ UNUSED_PARAM(page);
+ UNUSED_PARAM(position);
+#endif
+}
+#endif // ENABLE(WEB_REPLAY)
+
inline void InspectorInstrumentation::networkStateChanged(Page* page)
{
#if ENABLE(INSPECTOR)
--- /dev/null
+/*
+ * 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.
+ */
+
+#include "config.h"
+#include "InspectorReplayAgent.h"
+
+#if ENABLE(INSPECTOR) && ENABLE(WEB_REPLAY)
+
+#include "DocumentLoader.h"
+#include "Event.h"
+#include "EventLoopInput.h"
+#include "Frame.h"
+#include "FunctorInputCursor.h"
+#include "InspectorController.h"
+#include "InspectorPageAgent.h"
+#include "InspectorWebTypeBuilders.h"
+#include "InstrumentingAgents.h"
+#include "Logging.h"
+#include "Page.h"
+#include "ReplayController.h"
+#include "ReplaySession.h"
+#include "ReplaySessionSegment.h"
+#include "SerializationMethods.h"
+#include "WebReplayInputs.h" // For EncodingTraits<InputQueue>.
+#include <inspector/InspectorValues.h>
+#include <wtf/text/CString.h>
+#include <wtf/text/WTFString.h>
+
+using namespace Inspector;
+
+namespace WebCore {
+
+static PassRefPtr<TypeBuilder::Replay::ReplayPosition> buildInspectorObjectForPosition(const ReplayPosition& position)
+{
+ RefPtr<TypeBuilder::Replay::ReplayPosition> positionObject = TypeBuilder::Replay::ReplayPosition::create()
+ .setSegmentOffset(position.segmentOffset)
+ .setInputOffset(position.inputOffset);
+
+ return positionObject.release();
+}
+
+static PassRefPtr<TypeBuilder::Replay::ReplayInput> buildInspectorObjectForInput(const NondeterministicInputBase& input, size_t offset)
+{
+ EncodedValue encodedInput = EncodingTraits<NondeterministicInputBase>::encodeValue(input);
+ RefPtr<TypeBuilder::Replay::ReplayInput> inputObject = TypeBuilder::Replay::ReplayInput::create()
+ .setType(input.type())
+ .setOffset(offset)
+ .setData(encodedInput.asObject());
+
+ if (input.queue() == InputQueue::EventLoopInput)
+ inputObject->setTimestamp(static_cast<const EventLoopInputBase&>(input).timestamp());
+
+ return inputObject.release();
+}
+
+static PassRefPtr<TypeBuilder::Replay::ReplaySession> buildInspectorObjectForSession(PassRefPtr<ReplaySession> prpSession)
+{
+ RefPtr<ReplaySession> session = prpSession;
+ RefPtr<TypeBuilder::Array<SegmentIdentifier>> segments = TypeBuilder::Array<SegmentIdentifier>::create();
+
+ for (auto it = session->begin(); it != session->end(); ++it)
+ segments->addItem((*it)->identifier());
+
+ RefPtr<TypeBuilder::Replay::ReplaySession> sessionObject = TypeBuilder::Replay::ReplaySession::create()
+ .setId(session->identifier())
+ .setTimestamp(session->timestamp())
+ .setSegments(segments.release());
+
+ return sessionObject.release();
+}
+
+class SerializeInputToJSONFunctor {
+public:
+ typedef PassRefPtr<TypeBuilder::Array<TypeBuilder::Replay::ReplayInput>> ReturnType;
+
+ SerializeInputToJSONFunctor()
+ : m_inputs(TypeBuilder::Array<TypeBuilder::Replay::ReplayInput>::create()) { }
+ ~SerializeInputToJSONFunctor() { }
+
+ void operator()(size_t index, const NondeterministicInputBase* input)
+ {
+ LOG(WebReplay, "%-25s Writing %5zu: %s\n", "[SerializeInput]", index, input->type().string().ascii().data());
+
+ if (RefPtr<TypeBuilder::Replay::ReplayInput> serializedInput = buildInspectorObjectForInput(*input, index))
+ m_inputs->addItem(serializedInput.release());
+ }
+
+ ReturnType returnValue() { return m_inputs.release(); }
+private:
+ RefPtr<TypeBuilder::Array<TypeBuilder::Replay::ReplayInput>> m_inputs;
+};
+
+static PassRefPtr<TypeBuilder::Replay::SessionSegment> buildInspectorObjectForSegment(PassRefPtr<ReplaySessionSegment> prpSegment)
+{
+ RefPtr<ReplaySessionSegment> segment = prpSegment;
+ RefPtr<TypeBuilder::Array<TypeBuilder::Replay::ReplayInputQueue>> queuesObject = TypeBuilder::Array<TypeBuilder::Replay::ReplayInputQueue>::create();
+
+ for (size_t i = 0; i < static_cast<size_t>(InputQueue::Count); i++) {
+ SerializeInputToJSONFunctor collector;
+ InputQueue queue = static_cast<InputQueue>(i);
+ RefPtr<TypeBuilder::Array<TypeBuilder::Replay::ReplayInput>> queueInputs = segment->createFunctorCursor()->forEachInputInQueue(queue, collector);
+
+ RefPtr<TypeBuilder::Replay::ReplayInputQueue> queueObject = TypeBuilder::Replay::ReplayInputQueue::create()
+ .setType(EncodingTraits<InputQueue>::encodeValue(queue).convertTo<String>())
+ .setInputs(queueInputs);
+
+ queuesObject->addItem(queueObject.release());
+ }
+
+ RefPtr<TypeBuilder::Replay::SessionSegment> segmentObject = TypeBuilder::Replay::SessionSegment::create()
+ .setId(segment->identifier())
+ .setTimestamp(segment->timestamp())
+ .setQueues(queuesObject.release());
+
+ return segmentObject.release();
+}
+
+InspectorReplayAgent::InspectorReplayAgent(InstrumentingAgents* instrumentingAgents, InspectorPageAgent* pageAgent)
+ : InspectorAgentBase(ASCIILiteral("Replay"), instrumentingAgents)
+ , m_page(*pageAgent->page())
+{
+}
+
+InspectorReplayAgent::~InspectorReplayAgent()
+{
+ ASSERT(!m_sessionsMap.size());
+ ASSERT(!m_segmentsMap.size());
+}
+
+SessionState InspectorReplayAgent::sessionState() const
+{
+ return m_page.replayController().sessionState();
+}
+
+void InspectorReplayAgent::didCreateFrontendAndBackend(InspectorFrontendChannel* frontendChannel, InspectorBackendDispatcher* backendDispatcher)
+{
+ m_frontendDispatcher = std::make_unique<InspectorReplayFrontendDispatcher>(frontendChannel);
+ m_backendDispatcher = InspectorReplayBackendDispatcher::create(backendDispatcher, this);
+
+ m_instrumentingAgents->setInspectorReplayAgent(this);
+ ASSERT(sessionState() == SessionState::Inactive);
+
+ // Keep track of the (default) session currently loaded by ReplayController,
+ // and any segments within the session.
+ RefPtr<ReplaySession> session = m_page.replayController().loadedSession();
+ m_sessionsMap.add(session->identifier(), session.release());
+
+ for (auto it = session->begin(); it != session->end(); ++it)
+ m_segmentsMap.add((*it)->identifier(), *it);
+}
+
+void InspectorReplayAgent::willDestroyFrontendAndBackend(InspectorDisconnectReason)
+{
+ m_frontendDispatcher = nullptr;
+ m_backendDispatcher.clear();
+
+ m_instrumentingAgents->setInspectorReplayAgent(nullptr);
+
+ // Drop references to all sessions and segments.
+ m_sessionsMap.clear();
+ m_segmentsMap.clear();
+}
+
+void InspectorReplayAgent::frameNavigated(DocumentLoader* loader)
+{
+ if (sessionState() != SessionState::Inactive)
+ m_page.replayController().frameNavigated(loader);
+}
+
+void InspectorReplayAgent::frameDetached(Frame* frame)
+{
+ if (sessionState() != SessionState::Inactive)
+ m_page.replayController().frameDetached(frame);
+}
+
+void InspectorReplayAgent::sessionCreated(PassRefPtr<ReplaySession> prpSession)
+{
+ RefPtr<ReplaySession> session = prpSession;
+
+ auto result = m_sessionsMap.add(session->identifier(), session);
+ // Can't have two sessions with same identifier.
+ ASSERT_UNUSED(result, result.isNewEntry);
+
+ m_frontendDispatcher->sessionCreated(session->identifier());
+}
+
+void InspectorReplayAgent::sessionModified(PassRefPtr<ReplaySession> session)
+{
+ m_frontendDispatcher->sessionModified(session->identifier());
+}
+
+void InspectorReplayAgent::sessionLoaded(PassRefPtr<ReplaySession> prpSession)
+{
+ RefPtr<ReplaySession> session = prpSession;
+
+ // In case we didn't know about the loaded session, add here.
+ m_sessionsMap.add(session->identifier(), session);
+
+ m_frontendDispatcher->sessionLoaded(session->identifier());
+}
+
+void InspectorReplayAgent::segmentCreated(PassRefPtr<ReplaySessionSegment> prpSegment)
+{
+ RefPtr<ReplaySessionSegment> segment = prpSegment;
+
+ auto result = m_segmentsMap.add(segment->identifier(), segment);
+ // Can't have two segments with the same identifier.
+ ASSERT_UNUSED(result, result.isNewEntry);
+
+ m_frontendDispatcher->segmentCreated(segment->identifier());
+}
+
+void InspectorReplayAgent::segmentCompleted(PassRefPtr<ReplaySessionSegment> segment)
+{
+ m_frontendDispatcher->segmentCompleted(segment->identifier());
+}
+
+void InspectorReplayAgent::segmentLoaded(PassRefPtr<ReplaySessionSegment> prpSegment)
+{
+ RefPtr<ReplaySessionSegment> segment = prpSegment;
+
+ // In case we didn't know about the loaded segment, add here.
+ m_segmentsMap.add(segment->identifier(), segment);
+
+ m_frontendDispatcher->segmentLoaded(segment->identifier());
+}
+
+void InspectorReplayAgent::segmentUnloaded()
+{
+ m_frontendDispatcher->segmentUnloaded();
+}
+
+void InspectorReplayAgent::captureStarted()
+{
+ LOG(WebReplay, "-----CAPTURE START-----");
+
+ m_frontendDispatcher->captureStarted();
+}
+
+void InspectorReplayAgent::captureStopped()
+{
+ LOG(WebReplay, "-----CAPTURE STOP-----");
+
+ m_frontendDispatcher->captureStopped();
+}
+
+void InspectorReplayAgent::playbackStarted()
+{
+ LOG(WebReplay, "-----REPLAY START-----");
+
+ m_frontendDispatcher->playbackStarted();
+}
+
+void InspectorReplayAgent::playbackPaused(const ReplayPosition& position)
+{
+ LOG(WebReplay, "-----REPLAY PAUSED-----");
+
+ m_frontendDispatcher->playbackPaused(buildInspectorObjectForPosition(position));
+}
+
+void InspectorReplayAgent::playbackHitPosition(const ReplayPosition& position)
+{
+ m_frontendDispatcher->playbackHitPosition(buildInspectorObjectForPosition(position), monotonicallyIncreasingTime());
+}
+
+void InspectorReplayAgent::startCapturing(ErrorString* errorString)
+{
+ if (sessionState() != SessionState::Inactive) {
+ *errorString = ASCIILiteral("Can't start capturing if the session is already capturing or replaying.");
+ return;
+ }
+
+ m_page.replayController().startCapturing();
+}
+
+void InspectorReplayAgent::stopCapturing(ErrorString* errorString)
+{
+ if (sessionState() != SessionState::Capturing) {
+ *errorString = ASCIILiteral("Can't stop capturing if capture is not in progress.");
+ return;
+ }
+
+ m_page.replayController().stopCapturing();
+}
+
+void InspectorReplayAgent::replayToPosition(ErrorString* errorString, const RefPtr<InspectorObject>& positionObject, bool fastReplay)
+{
+ ReplayPosition position;
+ if (!positionObject->getNumber(ASCIILiteral("segmentOffset"), &position.segmentOffset)) {
+ *errorString = ASCIILiteral("Couldn't decode ReplayPosition segment offset provided to ReplayAgent.replayToPosition.");
+ return;
+ }
+
+ if (!positionObject->getNumber(ASCIILiteral("inputOffset"), &position.inputOffset)) {
+ *errorString = ASCIILiteral("Couldn't decode ReplayPosition input offset provided to ReplayAgent.replayToPosition.");
+ return;
+ }
+
+ if (sessionState() != SessionState::Inactive) {
+ *errorString = ASCIILiteral("Can't start replay while capture or playback is in progress.");
+ return;
+ }
+
+ m_page.replayController().replayToPosition(position, (fastReplay) ? DispatchSpeed::FastForward : DispatchSpeed::RealTime);
+}
+
+void InspectorReplayAgent::replayToCompletion(ErrorString* errorString, bool fastReplay)
+{
+ if (sessionState() != SessionState::Inactive) {
+ *errorString = ASCIILiteral("Can't start replay while capture or playback is in progress.");
+ return;
+ }
+
+ m_page.replayController().replayToCompletion((fastReplay) ? DispatchSpeed::FastForward : DispatchSpeed::RealTime);
+}
+
+void InspectorReplayAgent::pausePlayback(ErrorString* errorString)
+{
+ if (sessionState() != SessionState::Replaying) {
+ *errorString = ASCIILiteral("Can't pause playback if playback is not in progress.");
+ return;
+ }
+
+ m_page.replayController().pausePlayback();
+}
+
+void InspectorReplayAgent::cancelPlayback(ErrorString* errorString)
+{
+ if (sessionState() == SessionState::Capturing) {
+ *errorString = ASCIILiteral("Can't cancel playback if capture is in progress.");
+ return;
+ }
+
+ m_page.replayController().cancelPlayback();
+}
+
+void InspectorReplayAgent::switchSession(ErrorString* errorString, SessionIdentifier identifier)
+{
+ ASSERT(identifier > 0);
+
+ if (sessionState() != SessionState::Inactive) {
+ *errorString = ASCIILiteral("Can't switch sessions unless the session is neither capturing or replaying.");
+ return;
+ }
+
+ RefPtr<ReplaySession> session = findSession(errorString, identifier);
+ if (!session)
+ return;
+
+ m_page.replayController().switchSession(session);
+}
+
+void InspectorReplayAgent::insertSessionSegment(ErrorString* errorString, SessionIdentifier sessionIdentifier, SegmentIdentifier segmentIdentifier, int segmentIndex)
+{
+ ASSERT(sessionIdentifier > 0);
+ ASSERT(segmentIdentifier > 0);
+ ASSERT(segmentIndex >= 0);
+
+ RefPtr<ReplaySession> session = findSession(errorString, sessionIdentifier);
+ RefPtr<ReplaySessionSegment> segment = findSegment(errorString, segmentIdentifier);
+
+ if (!session || !segment)
+ return;
+
+ if (static_cast<size_t>(segmentIndex) > session->size()) {
+ *errorString = ASCIILiteral("Invalid segment index.");
+ return;
+ }
+
+ if (session == m_page.replayController().loadedSession() && sessionState() != SessionState::Inactive) {
+ *errorString = ASCIILiteral("Can't modify a loaded session unless the session is inactive.");
+ return;
+ }
+
+ session->insertSegment(segmentIndex, segment);
+ sessionModified(session);
+}
+
+void InspectorReplayAgent::removeSessionSegment(ErrorString* errorString, SessionIdentifier identifier, int segmentIndex)
+{
+ ASSERT(identifier > 0);
+ ASSERT(segmentIndex >= 0);
+
+ RefPtr<ReplaySession> session = findSession(errorString, identifier);
+
+ if (!session)
+ return;
+
+ if (static_cast<size_t>(segmentIndex) >= session->size()) {
+ *errorString = ASCIILiteral("Invalid segment index.");
+ return;
+ }
+
+ if (session == m_page.replayController().loadedSession() && sessionState() != SessionState::Inactive) {
+ *errorString = ASCIILiteral("Can't modify a loaded session unless the session is inactive.");
+ return;
+ }
+
+ session->removeSegment(segmentIndex);
+ sessionModified(session);
+}
+
+PassRefPtr<ReplaySession> InspectorReplayAgent::findSession(ErrorString* errorString, SessionIdentifier identifier)
+{
+ ASSERT(identifier > 0);
+
+ auto it = m_sessionsMap.find(identifier);
+ if (it == m_sessionsMap.end()) {
+ *errorString = ASCIILiteral("Couldn't find session with specified identifier");
+ return nullptr;
+ }
+
+ return it->value;
+}
+
+PassRefPtr<ReplaySessionSegment> InspectorReplayAgent::findSegment(ErrorString* errorString, SegmentIdentifier identifier)
+{
+ ASSERT(identifier > 0);
+
+ auto it = m_segmentsMap.find(identifier);
+ if (it == m_segmentsMap.end()) {
+ *errorString = ASCIILiteral("Couldn't find segment with specified identifier");
+ return nullptr;
+ }
+
+ return it->value;
+}
+
+void InspectorReplayAgent::getAvailableSessions(ErrorString*, RefPtr<Inspector::TypeBuilder::Array<SessionIdentifier>>& sessionsList)
+{
+ sessionsList = TypeBuilder::Array<SessionIdentifier>::create();
+ for (auto& pair : m_sessionsMap)
+ sessionsList->addItem(pair.key);
+}
+
+void InspectorReplayAgent::getSerializedSession(ErrorString* errorString, SessionIdentifier identifier, RefPtr<Inspector::TypeBuilder::Replay::ReplaySession>& serializedObject)
+{
+ RefPtr<ReplaySession> session = findSession(errorString, identifier);
+ if (!session) {
+ *errorString = ASCIILiteral("Couldn't find the specified session.");
+ return;
+ }
+
+ serializedObject = buildInspectorObjectForSession(session);
+}
+
+void InspectorReplayAgent::getSerializedSegment(ErrorString* errorString, SegmentIdentifier identifier, RefPtr<Inspector::TypeBuilder::Replay::SessionSegment>& serializedObject)
+{
+ RefPtr<ReplaySessionSegment> segment = findSegment(errorString, identifier);
+ if (!segment) {
+ *errorString = ASCIILiteral("Couldn't find the specified segment.");
+ return;
+ }
+
+ serializedObject = buildInspectorObjectForSegment(segment);
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(INSPECTOR) && ENABLE(WEB_REPLAY)
--- /dev/null
+/*
+ * 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.
+ */
+
+#ifndef InspectorReplayAgent_h
+#define InspectorReplayAgent_h
+
+#if ENABLE(INSPECTOR) && ENABLE(WEB_REPLAY)
+
+#include "InspectorWebAgentBase.h"
+#include "InspectorWebBackendDispatchers.h"
+#include "InspectorWebFrontendDispatchers.h"
+#include <wtf/Forward.h>
+#include <wtf/HashMap.h>
+#include <wtf/Noncopyable.h>
+
+namespace WebCore {
+
+class DocumentLoader;
+class Frame;
+class InspectorPageAgent;
+class InstrumentingAgents;
+class Page;
+class ReplaySession;
+class ReplaySessionSegment;
+
+enum class SessionState;
+
+struct ReplayPosition;
+
+typedef String ErrorString;
+typedef int SessionIdentifier;
+typedef int SegmentIdentifier;
+
+class InspectorReplayAgent final
+ : public InspectorAgentBase
+ , public Inspector::InspectorReplayBackendDispatcherHandler {
+ WTF_MAKE_NONCOPYABLE(InspectorReplayAgent);
+public:
+ InspectorReplayAgent(InstrumentingAgents*, InspectorPageAgent*);
+ ~InspectorReplayAgent();
+
+ virtual void didCreateFrontendAndBackend(Inspector::InspectorFrontendChannel*, Inspector::InspectorBackendDispatcher*) override;
+ virtual void willDestroyFrontendAndBackend(Inspector::InspectorDisconnectReason) override;
+
+ // Callbacks from InspectorInstrumentation.
+ void frameNavigated(DocumentLoader*);
+ void frameDetached(Frame*);
+
+ // Notifications from ReplayController.
+ void sessionCreated(PassRefPtr<ReplaySession>);
+ // This is called internally (when adding/removing) and by ReplayController during capture.
+ void sessionModified(PassRefPtr<ReplaySession>);
+ void sessionLoaded(PassRefPtr<ReplaySession>);
+
+ void segmentCreated(PassRefPtr<ReplaySessionSegment>);
+ void segmentCompleted(PassRefPtr<ReplaySessionSegment>);
+ void segmentLoaded(PassRefPtr<ReplaySessionSegment>);
+ void segmentUnloaded();
+
+ void captureStarted();
+ void captureStopped();
+
+ void playbackStarted();
+ void playbackPaused(const ReplayPosition&);
+ void playbackHitPosition(const ReplayPosition&);
+
+ // Calls from the Inspector frontend.
+ virtual void startCapturing(ErrorString*) override;
+ virtual void stopCapturing(ErrorString*) override;
+
+ virtual void replayToPosition(ErrorString*, const RefPtr<Inspector::InspectorObject>&, bool shouldFastForward) override;
+ virtual void replayToCompletion(ErrorString*, bool shouldFastForward) override;
+ virtual void pausePlayback(ErrorString*) override;
+ virtual void cancelPlayback(ErrorString*) override;
+
+ virtual void switchSession(ErrorString*, SessionIdentifier) override;
+ virtual void insertSessionSegment(ErrorString*, SessionIdentifier, SegmentIdentifier, int segmentIndex) override;
+ virtual void removeSessionSegment(ErrorString*, SessionIdentifier, int segmentIndex) override;
+
+ virtual void getAvailableSessions(ErrorString*, RefPtr<Inspector::TypeBuilder::Array<SessionIdentifier>>&) override;
+ virtual void getSerializedSession(ErrorString*, SessionIdentifier, RefPtr<Inspector::TypeBuilder::Replay::ReplaySession>&) override;
+ virtual void getSerializedSegment(ErrorString*, SegmentIdentifier, RefPtr<Inspector::TypeBuilder::Replay::SessionSegment>&) override;
+
+private:
+ PassRefPtr<ReplaySession> findSession(ErrorString*, SessionIdentifier);
+ PassRefPtr<ReplaySessionSegment> findSegment(ErrorString*, SegmentIdentifier);
+ SessionState sessionState() const;
+
+ std::unique_ptr<Inspector::InspectorReplayFrontendDispatcher> m_frontendDispatcher;
+ RefPtr<Inspector::InspectorReplayBackendDispatcher> m_backendDispatcher;
+ Page& m_page;
+
+ HashMap<int, RefPtr<ReplaySession>, WTF::IntHash<int>, WTF::UnsignedWithZeroKeyHashTraits<int>> m_sessionsMap;
+ HashMap<int, RefPtr<ReplaySessionSegment>, WTF::IntHash<int>, WTF::UnsignedWithZeroKeyHashTraits<int>> m_segmentsMap;
+};
+
+} // namespace WebCore
+
+#endif // ENABLE(INSPECTOR) && ENABLE(WEB_REPLAY)
+
+#endif // InspectorReplayAgent_h
/*
* Copyright (C) 2011 Google Inc. 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
, m_workerRuntimeAgent(nullptr)
, m_inspectorTimelineAgent(nullptr)
, m_inspectorDOMStorageAgent(nullptr)
+#if ENABLE(WEB_REPLAY)
+ , m_inspectorReplayAgent(nullptr)
+#endif
#if ENABLE(SQL_DATABASE)
, m_inspectorDatabaseAgent(nullptr)
#endif
m_workerRuntimeAgent = nullptr;
m_inspectorTimelineAgent = nullptr;
m_inspectorDOMStorageAgent = nullptr;
+#if ENABLE(WEB_REPLAY)
+ m_inspectorReplayAgent = nullptr;
+#endif
#if ENABLE(SQL_DATABASE)
m_inspectorDatabaseAgent = nullptr;
#endif
/*
* Copyright (C) 2011 Google Inc. 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
class InspectorPageAgent;
class InspectorProfilerAgent;
class InspectorResourceAgent;
+class InspectorReplayAgent;
class InspectorTimelineAgent;
class InspectorWorkerAgent;
class Page;
InspectorDOMStorageAgent* inspectorDOMStorageAgent() const { return m_inspectorDOMStorageAgent; }
void setInspectorDOMStorageAgent(InspectorDOMStorageAgent* agent) { m_inspectorDOMStorageAgent = agent; }
+#if ENABLE(WEB_REPLAY)
+ InspectorReplayAgent* inspectorReplayAgent() const { return m_inspectorReplayAgent; }
+ void setInspectorReplayAgent(InspectorReplayAgent* agent) { m_inspectorReplayAgent = agent; }
+#endif
+
#if ENABLE(SQL_DATABASE)
InspectorDatabaseAgent* inspectorDatabaseAgent() const { return m_inspectorDatabaseAgent; }
void setInspectorDatabaseAgent(InspectorDatabaseAgent* agent) { m_inspectorDatabaseAgent = agent; }
WorkerRuntimeAgent* m_workerRuntimeAgent;
InspectorTimelineAgent* m_inspectorTimelineAgent;
InspectorDOMStorageAgent* m_inspectorDOMStorageAgent;
+#if ENABLE(WEB_REPLAY)
+ InspectorReplayAgent* m_inspectorReplayAgent;
+#endif
#if ENABLE(SQL_DATABASE)
InspectorDatabaseAgent* m_inspectorDatabaseAgent;
#endif
--- /dev/null
+{
+ "domain": "Replay",
+ "description": "Controls web replay, and manages recording sessions and segments.",
+ "types": [
+ {
+ "id": "SessionIdentifier", "description": "Unique replay session identifier.",
+ "type": "integer"
+ },
+ {
+ "id": "SegmentIdentifier", "description": "Unique session segment identifier.",
+ "type": "integer"
+ },
+ {
+ "id": "ReplayPosition",
+ "type": "object",
+ "properties": [
+ { "name": "segmentOffset", "type": "integer", "description": "Offset for a segment within the currently-loaded replay session." },
+ { "name": "inputOffset", "type": "integer", "description": "Offset for an event loop input within the specified session segment." }
+ ]
+ },
+ {
+ "id": "ReplayInput",
+ "type": "object",
+ "properties": [
+ { "name": "type", "type": "string", "description": "Input type." },
+ { "name": "offset", "type": "integer", "description": "Offset of this input in its respective queue."},
+ { "name": "timestamp", "type": "number", "optional": true, "description": "The timestamp of this input." },
+ { "name": "data", "type": "object", "description": "Per-input payload." }
+ ]
+ },
+ {
+ "id": "ReplayInputQueue",
+ "type": "object",
+ "properties": [
+ { "name": "type", "type": "string", "description": "Queue type" },
+ { "name": "inputs", "type": "array", "items": { "$ref": "ReplayInput"}, "description": "Inputs belonging to this queue." }
+ ]
+ },
+ {
+ "id": "SessionSegment", "description": "A standalone segment of a replay session that corresponds to a single main frame navigation and execution.",
+ "type": "object",
+ "properties": [
+ { "name": "id", "$ref": "SegmentIdentifier", "description": "Unique session segment identifier." },
+ { "name": "timestamp", "type": "number", "description": "Start time of the segment, in milliseconds since the epoch." },
+ { "name": "queues", "type": "array", "items": { "$ref": "ReplayInputQueue"} }
+ ]
+ },
+ {
+ "id": "ReplaySession", "description": "An ordered collection of replay session segments.",
+ "type": "object",
+ "properties": [
+ { "name": "id", "$ref": "SessionIdentifier", "description": "Unique replay session identifier." },
+ { "name": "timestamp", "type": "number", "description": "Creation time of session, in milliseconds since the epoch." },
+ { "name": "segments", "type": "array", "items": { "$ref": "SegmentIdentifier" }, "description": "An ordered list identifiers for the segments that comprise this replay session." }
+ ]
+ }
+ ],
+ "commands": [
+ {
+ "name": "startCapturing",
+ "description": "Starts capture of a new replay session."
+ },
+ {
+ "name": "stopCapturing",
+ "description": "Stops capture of the currently recording replay session."
+ },
+ {
+ "name": "replayToPosition",
+ "description": "Seek execution to a specific position within the replay session.",
+ "parameters": [
+ { "name": "position", "$ref": "ReplayPosition" },
+ { "name": "shouldFastForward", "type": "boolean" }
+ ]
+ },
+ {
+ "name": "replayToCompletion",
+ "description": "Replay all session segments completely.",
+ "parameters": [
+ { "name": "shouldFastForward", "type": "boolean" }
+ ]
+ },
+ {
+ "name": "pausePlayback",
+ "description": "Pauses playback in the current segment. Can be resumed by using a replay command."
+ },
+ {
+ "name": "cancelPlayback",
+ "description": "Cancels playback of the current segment. Further replaying will start from the beginning of the current segment."
+ },
+ {
+ "name": "switchSession",
+ "description": "Unloads the current replay session and loads the specified session",
+ "parameters": [
+ { "name": "sessionIdentifier", "$ref": "SessionIdentifier" }
+ ]
+ },
+ {
+ "name": "insertSessionSegment",
+ "description": "Splices the specified session segment into the session at the specified index.",
+ "parameters": [
+ { "name": "sessionIdentifier", "$ref": "SessionIdentifier" },
+ { "name": "segmentIdentifier", "$ref": "SegmentIdentifier" },
+ { "name": "segmentIndex", "type": "integer" }
+ ]
+ },
+ {
+ "name": "removeSessionSegment",
+ "description": "Removes the session segment at the specified position from the session.",
+ "parameters": [
+ { "name": "sessionIdentifier", "$ref": "SessionIdentifier" },
+ { "name": "segmentIndex", "type": "integer" }
+ ]
+ },
+ {
+ "name": "getAvailableSessions",
+ "description": "Returns identifiers of all available sessions.",
+ "returns": [
+ { "name": "ids", "type": "array", "items": { "$ref": "SessionIdentifier" } }
+ ]
+ },
+ {
+ "name": "getSerializedSession",
+ "description": "Returns the specified session serialized to a JSON object.",
+ "parameters": [
+ { "name": "sessionIdentifier", "$ref": "SessionIdentifier" }
+ ],
+ "returns": [
+ { "name": "session", "$ref": "ReplaySession", "optional": true, "description": "The requested serialized replay session." }
+ ]
+ },
+ {
+ "name": "getSerializedSegment",
+ "description": "Returns the session segment serialized to a JSON object.",
+ "parameters": [
+ { "name": "id", "$ref": "SegmentIdentifier" }
+ ],
+ "returns": [
+ { "name": "segment", "$ref": "SessionSegment", "optional": true, "description": "The requested serialized session segment." }
+ ]
+ }
+ ],
+ "events": [
+ {
+ "name": "captureStarted",
+ "description": "Fired when capture has started."
+ },
+ {
+ "name": "captureStopped",
+ "description": "Fired when capture has stopped."
+ },
+ {
+ "name": "playbackHitPosition",
+ "description": "A position was reached during playback of the session.",
+ "parameters": [
+ { "name": "position", "$ref": "ReplayPosition", "description": "The playback position that was hit." },
+ { "name": "timestamp", "type": "number", "description": "A timestamp for the event." }
+ ]
+ },
+ {
+ "name": "playbackStarted",
+ "description": "Fired when session playback has started."
+ },
+ {
+ "name": "playbackPaused",
+ "description": "Fired when session playback has paused, but not finished.",
+ "parameters": [
+ { "name": "position", "$ref": "ReplayPosition", "description": "The playback position immediately prior to where playback is paused." }
+ ]
+ },
+ {
+ "name": "playbackFinished",
+ "description": "Fired when session playback has stopped."
+ },
+ {
+ "name": "inputSuppressionChanged",
+ "description": "Fired when the replay controller starts or stops suppressing user inputs.",
+ "parameters": [
+ { "name": "willSuppress", "type": "boolean", "description": "Whether user inputs will be suppressed during playback." }
+ ]
+ },
+ {
+ "name": "sessionCreated",
+ "description": "Fired when a new replay session is created",
+ "parameters": [
+ { "name": "id", "$ref": "SessionIdentifier", "description": "Identifier for the created session." }
+ ]
+ },
+ {
+ "name": "sessionModified",
+ "description": "Fired when a session's segments have changed.",
+ "parameters": [
+ { "name": "id", "$ref": "SessionIdentifier", "description": "Identifier for the session the segment was added to." }
+ ]
+ },
+ {
+ "name": "sessionRemoved",
+ "description": "Fired when a replay session is removed and can no longer be loaded.",
+ "parameters": [
+ { "name": "id", "$ref": "SessionIdentifier", "description": "Identifier for the removed session." }
+ ]
+ },
+ {
+ "name": "sessionLoaded",
+ "description": "Fired when a replay session is loaded.",
+ "parameters": [
+ { "name": "id", "$ref": "SessionIdentifier", "description": "Identifier for the loaded session." }
+ ]
+ },
+ {
+ "name": "segmentCreated",
+ "description": "Fired when a new session segment is created.",
+ "parameters": [
+ { "name": "id", "$ref": "SegmentIdentifier", "description": "Identifier for the created session segment." }
+ ]
+ },
+ {
+ "name": "segmentRemoved",
+ "description": "Fired when a session segment is removed and can no longer be replayed as part of a session.",
+ "parameters": [
+ { "name": "id", "$ref": "SegmentIdentifier", "description": "Identifier for the removed session segment." }
+ ]
+ },
+ {
+ "name": "segmentCompleted",
+ "description": "Fired when a session segment is completed and can no longer have inputs added to it.",
+ "parameters": [
+ { "name": "id", "$ref": "SegmentIdentifier", "description": "Identifier for the completed session segment." }
+ ]
+ },
+ {
+ "name": "segmentLoaded",
+ "description": "Fired when a segment is loaded.",
+ "parameters": [
+ { "name": "segmentIdentifier", "$ref": "SegmentIdentifier", "description": "Id for the loaded segment." }
+ ]
+ },
+ {
+ "name": "segmentUnloaded",
+ "description": "Fired when a segment is unloaded."
+ }
+ ]
+}
export SRCROOT=$PWD
export WebCore=$PWD
export InspectorScripts=$PWD/../JavaScriptCore/inspector/scripts
+export WebReplayScripts=$PWD/../JavaScriptCore/replay/scripts
mkdir -p DerivedSources/WebCore &&
make -C DerivedSources/WebCore -f ../../DerivedSources.make $@
#include <wtf/text/Base64.h>
#include <wtf/text/StringHash.h>
+#if ENABLE(WEB_REPLAY)
+#include "ReplayController.h"
+#endif
+
namespace WebCore {
static HashSet<Page*>* allPages;
, m_contextMenuController(std::make_unique<ContextMenuController>(*this, *pageClients.contextMenuClient))
#endif
, m_userInputBridge(std::make_unique<UserInputBridge>(*this))
+#if ENABLE(WEB_REPLAY)
+ , m_replayController(std::make_unique<ReplayController>(*this))
+#endif
#if ENABLE(INSPECTOR)
, m_inspectorController(std::make_unique<InspectorController>(*this, pageClients.inspectorClient))
#endif
class Range;
class RenderObject;
class RenderTheme;
+class ReplayController;
class VisibleSelection;
class ScrollableArea;
class ScrollingCoordinator;
ContextMenuController& contextMenuController() const { return *m_contextMenuController; }
#endif
UserInputBridge& userInputBridge() const { return *m_userInputBridge; }
+#if ENABLE(WEB_REPLAY)
+ ReplayController& replayController() const { return *m_replayController; }
+#endif
#if ENABLE(INSPECTOR)
InspectorController& inspectorController() const { return *m_inspectorController; }
#endif
const std::unique_ptr<ContextMenuController> m_contextMenuController;
#endif
const std::unique_ptr<UserInputBridge> m_userInputBridge;
+#if ENABLE(WEB_REPLAY)
+ const std::unique_ptr<ReplayController> m_replayController;
+#endif
#if ENABLE(INSPECTOR)
const std::unique_ptr<InspectorController> m_inspectorController;
#endif
M(Threading) \
M(WebAudio) \
M(WebGL) \
+ M(WebReplay) \
#define DECLARE_LOG_CHANNEL(name) \
extern WTFLogChannel JOIN_LOG_CHANNEL_WITH_PREFIX(LOG_CHANNEL_PREFIX, name);
--- /dev/null
+/*
+ * Copyright (C) 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.
+ */
+
+// This file is the include equivalent for WEB_REPLAY_INPUT_NAMES_FOR_EACH.
+// Note that there is not an exact correspondence between the two, since
+// Some input types reside in the same file.
+
+// Make sure that this stays in sync with ReplayInputTypes.h for custom inputs.
+
+#ifndef AllReplayInputs_h
+#define AllReplayInputs_h
+
+#if ENABLE(WEB_REPLAY)
+
+#include "WebReplayInputs.h"
+#include <JavaScriptCore/JSReplayInputs.h>
+
+#define IMPORT_FROM_JSC_NAMESPACE(name) \
+using JSC::name; \
+
+JS_REPLAY_INPUT_NAMES_FOR_EACH(IMPORT_FROM_JSC_NAMESPACE)
+
+#endif // ENABLE(WEB_REPLAY)
+
+#endif // AllReplayInputs_h
--- /dev/null
+/*
+ * Copyright (C) 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.
+ */
+
+#include "config.h"
+#include "CapturingInputCursor.h"
+
+#if ENABLE(WEB_REPLAY)
+
+#include "Logging.h"
+#include "SegmentedInputStorage.h"
+
+namespace WebCore {
+
+CapturingInputCursor::CapturingInputCursor(SegmentedInputStorage& storage)
+ : m_storage(storage)
+{
+ LOG(WebReplay, "%-30sCreated capture cursor=%p.\n", "[ReplayController]", this);
+}
+
+CapturingInputCursor::~CapturingInputCursor()
+{
+ LOG(WebReplay, "%-30sDestroyed capture cursor=%p.\n", "[ReplayController]", this);
+}
+
+PassRefPtr<CapturingInputCursor> CapturingInputCursor::create(SegmentedInputStorage& storage)
+{
+ return adoptRef(new CapturingInputCursor(storage));
+}
+
+void CapturingInputCursor::storeInput(std::unique_ptr<NondeterministicInputBase> input)
+{
+ ASSERT(input);
+ m_storage.store(std::move(input));
+}
+
+NondeterministicInputBase* CapturingInputCursor::loadInput(InputQueue, const AtomicString&)
+{
+ // Can't load inputs from capturing cursor.
+ ASSERT_NOT_REACHED();
+ return nullptr;
+}
+
+NondeterministicInputBase* CapturingInputCursor::uncheckedLoadInput(InputQueue)
+{
+ // Can't load inputs from capturing cursor.
+ ASSERT_NOT_REACHED();
+ return nullptr;
+}
+
+}; // namespace WebCore
+
+#endif // ENABLE(WEB_REPLAY)
--- /dev/null
+/*
+ * Copyright (C) 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.
+ */
+
+#ifndef CapturingInputCursor_h
+#define CapturingInputCursor_h
+
+#if ENABLE(WEB_REPLAY)
+
+#include <replay/InputCursor.h>
+#include <wtf/Noncopyable.h>
+
+namespace WebCore {
+
+class SegmentedInputStorage;
+
+class CapturingInputCursor final : public InputCursor {
+ WTF_MAKE_NONCOPYABLE(CapturingInputCursor);
+public:
+ static PassRefPtr<CapturingInputCursor> create(SegmentedInputStorage&);
+ virtual ~CapturingInputCursor();
+
+ virtual bool isCapturing() const override { return true; }
+ virtual bool isReplaying() const override { return false; }
+
+ virtual NondeterministicInputBase* uncheckedLoadInput(InputQueue) override;
+ virtual void storeInput(std::unique_ptr<NondeterministicInputBase>) override;
+protected:
+ virtual NondeterministicInputBase* loadInput(InputQueue, const AtomicString& type) override;
+private:
+ explicit CapturingInputCursor(SegmentedInputStorage&);
+
+ SegmentedInputStorage& m_storage;
+};
+
+} // namespace WebCore
+
+#endif // ENABLE(WEB_REPLAY)
+
+#endif // CapturingInputCursor_h
class ReplayController;
-struct ReplayPosition {
-public:
- ReplayPosition()
- : m_index(0)
- , m_time(0.0) { }
-
- explicit ReplayPosition(unsigned index)
- : m_index(index)
- , m_time(monotonicallyIncreasingTime()) { }
-
- unsigned index() const { return m_index; }
- double time() const { return m_time; }
-private:
- unsigned m_index;
- double m_time;
-};
-
class EventLoopInputBase : public NondeterministicInputBase {
public:
EventLoopInputBase()
- : m_position(ReplayPosition()) { }
+ : m_timestamp(monotonicallyIncreasingTime())
+ {
+ }
virtual ~EventLoopInputBase() { }
virtual InputQueue queue() const override final { return InputQueue::EventLoopInput; }
virtual void dispatch(ReplayController&) = 0;
- // During capture, the position is set when the following event loop input is captured.
- void setPosition(const ReplayPosition& position) { m_position = position; }
- ReplayPosition position() const { return m_position; }
+ double timestamp() const { return m_timestamp; }
+ void setTimestamp(double timestamp) { m_timestamp = timestamp; }
protected:
- ReplayPosition m_position;
+ double m_timestamp;
};
template <typename InputType>
--- /dev/null
+/*
+ * 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.
+ */
+
+#include "config.h"
+#include "EventLoopInputDispatcher.h"
+
+#if ENABLE(WEB_REPLAY)
+
+#include "Page.h"
+#include "ReplayInputTypes.h"
+#include "ReplayingInputCursor.h"
+#include <wtf/TemporaryChange.h>
+
+#if !LOG_DISABLED
+#include "Logging.h"
+#include "SerializationMethods.h"
+#include <replay/EncodedValue.h>
+#include <wtf/text/CString.h>
+#endif
+
+namespace WebCore {
+
+EventLoopInputDispatcher::EventLoopInputDispatcher(Page& page, ReplayingInputCursor& cursor, EventLoopInputDispatcherClient* client)
+ : m_page(page)
+ , m_client(client)
+ , m_cursor(cursor)
+ , m_timer(this, &EventLoopInputDispatcher::timerFired)
+ , m_runningInput(nullptr)
+ , m_dispatching(false)
+ , m_running(false)
+ , m_speed(DispatchSpeed::FastForward)
+ , m_previousDispatchStartTime(0.0)
+ , m_previousInputTimestamp(0.0)
+{
+}
+
+void EventLoopInputDispatcher::run()
+{
+ ASSERT(!m_running);
+ m_running = true;
+
+ LOG(WebReplay, "%-20s Starting dispatch of event loop inputs for page: %p\n", "ReplayEvents", &m_page);
+ dispatchInputSoon();
+}
+
+void EventLoopInputDispatcher::pause()
+{
+ ASSERT(!m_dispatching);
+ ASSERT(m_running);
+ m_running = false;
+
+ LOG(WebReplay, "%-20s Pausing dispatch of event loop inputs for page: %p\n", "ReplayEvents", &m_page);
+ if (m_timer.isActive())
+ m_timer.stop();
+}
+
+void EventLoopInputDispatcher::timerFired(Timer<EventLoopInputDispatcher>*)
+{
+ dispatchInput();
+}
+
+void EventLoopInputDispatcher::dispatchInputSoon()
+{
+ ASSERT(m_running);
+
+ // We may already have an input if replay was paused just before dispatching.
+ if (!m_runningInput)
+ m_runningInput = safeCast<EventLoopInputBase*>(m_cursor.uncheckedLoadInput(InputQueue::EventLoopInput));
+
+ if (m_timer.isActive())
+ m_timer.stop();
+
+ double waitInterval = 0;
+
+ if (m_speed == DispatchSpeed::RealTime) {
+ // The goal is to reproduce the dispatch delay between inputs as it was
+ // was observed during the recording. So, we need to compute how much time
+ // to wait such that the elapsed time plus the wait time will equal the
+ // observed delay between the previous and current input.
+
+ if (!m_previousInputTimestamp)
+ m_previousInputTimestamp = m_runningInput->timestamp();
+
+ double targetInterval = m_runningInput->timestamp() - m_previousInputTimestamp;
+ double elapsed = monotonicallyIncreasingTime() - m_previousDispatchStartTime;
+ waitInterval = targetInterval - elapsed;
+ }
+
+ // A negative wait time means that dispatch took longer on replay than on
+ // capture. In this case, proceed without waiting at all.
+ if (waitInterval < 0)
+ waitInterval = 0;
+
+ if (waitInterval > 1000.0) {
+ LOG_ERROR("%-20s Tried to wait for over 1000 seconds before dispatching next event loop input; this is probably a bug.", "ReplayEvents");
+ waitInterval = 0;
+ }
+
+ LOG(WebReplay, "%-20s (WAIT: %.3f ms)", "ReplayEvents", waitInterval * 1000.0);
+ m_timer.startOneShot(waitInterval);
+}
+
+void EventLoopInputDispatcher::dispatchInput()
+{
+ ASSERT(m_runningInput);
+ ASSERT(!m_dispatching);
+
+ if (m_speed == DispatchSpeed::RealTime) {
+ m_previousDispatchStartTime = monotonicallyIncreasingTime();
+ m_previousInputTimestamp = m_runningInput->timestamp();
+ }
+
+#if !LOG_DISABLED
+ EncodedValue encodedInput = EncodingTraits<NondeterministicInputBase>::encodeValue(*m_runningInput);
+ String jsonString = encodedInput.asObject()->toJSONString();
+
+ LOG(WebReplay, "%-20s ----------------------------------------------", "ReplayEvents");
+ LOG(WebReplay, "%-20s >DISPATCH: %s %s\n", "ReplayEvents", m_runningInput->type().string().utf8().data(), jsonString.utf8().data());
+#endif
+
+ m_client->willDispatchInput(*m_runningInput);
+ // Client could stop replay in the previous callback, so check again.
+ if (!m_running)
+ return;
+
+ {
+ TemporaryChange<bool> change(m_dispatching, true);
+ m_runningInput->dispatch(m_page.replayController());
+ }
+
+ EventLoopInputBase* dispatchedInput = m_runningInput;
+ m_runningInput = nullptr;
+
+ // Notify clients that the event was dispatched.
+ m_client->didDispatchInput(*dispatchedInput);
+ if (dispatchedInput->type() == inputTypes().EndSegmentSentinel) {
+ m_running = false;
+ m_client->didDispatchFinalInput();
+ return;
+ }
+
+ // Clients could stop replay during event dispatch, or from any callback above.
+ if (!m_running)
+ return;
+
+ dispatchInputSoon();
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(WEB_REPLAY)
--- /dev/null
+/*
+ * Copyright (C) 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.
+ */
+
+#ifndef EventLoopInputDispatcher_h
+#define EventLoopInputDispatcher_h
+
+#if ENABLE(WEB_REPLAY)
+
+#include "EventLoopInput.h"
+#include "Timer.h"
+#include <wtf/Noncopyable.h>
+#include <wtf/Vector.h>
+#include <wtf/text/WTFString.h>
+
+namespace WebCore {
+
+class Page;
+class ReplayingInputCursor;
+
+enum class DispatchSpeed {
+ RealTime,
+ FastForward,
+};
+
+class EventLoopInputDispatcherClient {
+public:
+ EventLoopInputDispatcherClient() { }
+ virtual ~EventLoopInputDispatcherClient() { }
+
+ virtual void willDispatchInput(const EventLoopInputBase&) =0;
+ virtual void didDispatchInput(const EventLoopInputBase&) =0;
+ virtual void didDispatchFinalInput() =0;
+};
+
+class EventLoopInputDispatcher {
+ WTF_MAKE_NONCOPYABLE(EventLoopInputDispatcher);
+public:
+ EventLoopInputDispatcher(Page&, ReplayingInputCursor&, EventLoopInputDispatcherClient*);
+
+ void run();
+ void pause();
+
+ void setDispatchSpeed(DispatchSpeed speed) { m_speed = speed; }
+ DispatchSpeed dispatchSpeed() const { return m_speed; }
+private:
+ void dispatchInputSoon();
+ void dispatchInput();
+ void timerFired(Timer<EventLoopInputDispatcher>*);
+
+ Page& m_page;
+ EventLoopInputDispatcherClient* m_client;
+ ReplayingInputCursor& m_cursor;
+ Timer<EventLoopInputDispatcher> m_timer;
+
+ // This pointer is valid when an event loop input is presently dispatching.
+ EventLoopInputBase* m_runningInput;
+ bool m_dispatching;
+ bool m_running;
+
+ DispatchSpeed m_speed;
+ // The time at which the last input dispatch() method was called.
+ double m_previousDispatchStartTime;
+ // The timestamp specified by the last dispatched input.
+ double m_previousInputTimestamp;
+};
+
+} // namespace WebCore
+
+#endif // ENABLE(WEB_REPLAY)
+
+#endif // EventLoopInputDispatcher_h
--- /dev/null
+/*
+ * Copyright (C) 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.
+ */
+
+#ifndef FunctorInputCursor_h
+#define FunctorInputCursor_h
+
+#if ENABLE(WEB_REPLAY)
+
+#include "SegmentedInputStorage.h"
+#include <replay/InputCursor.h>
+#include <replay/NondeterministicInput.h>
+#include <wtf/Assertions.h>
+#include <wtf/Noncopyable.h>
+#include <wtf/Vector.h>
+
+namespace WebCore {
+
+class FunctorInputCursor final : public InputCursor {
+ WTF_MAKE_NONCOPYABLE(FunctorInputCursor);
+public:
+ FunctorInputCursor(SegmentedInputStorage&);
+ virtual ~FunctorInputCursor() { }
+
+ // InputCursor
+ virtual bool isCapturing() const override { return false; }
+ virtual bool isReplaying() const override { return false; }
+
+ virtual void storeInput(std::unique_ptr<NondeterministicInputBase>) override;
+ virtual NondeterministicInputBase* uncheckedLoadInput(InputQueue) override;
+
+ template<typename Functor>
+ typename Functor::ReturnType forEachInputInQueue(InputQueue, Functor&);
+protected:
+ virtual NondeterministicInputBase* loadInput(InputQueue, const AtomicString&) override;
+private:
+ SegmentedInputStorage& m_storage;
+};
+
+template<typename Functor> inline
+typename Functor::ReturnType FunctorInputCursor::forEachInputInQueue(InputQueue queue, Functor& functor)
+{
+ for (size_t i = 0; i < m_storage.queueSize(queue); i++)
+ functor(i, m_storage.queue(queue).at(i).get());
+
+ return functor.returnValue();
+}
+
+inline FunctorInputCursor::FunctorInputCursor(SegmentedInputStorage& storage)
+ : m_storage(storage)
+{
+}
+
+inline void FunctorInputCursor::storeInput(std::unique_ptr<NondeterministicInputBase>)
+{
+ ASSERT_NOT_REACHED();
+}
+
+inline NondeterministicInputBase* FunctorInputCursor::loadInput(InputQueue, const AtomicString&)
+{
+ ASSERT_NOT_REACHED();
+ return nullptr;
+}
+
+inline NondeterministicInputBase* FunctorInputCursor::uncheckedLoadInput(InputQueue)
+{
+ ASSERT_NOT_REACHED();
+ return nullptr;
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(WEB_REPLAY)
+
+#endif // FunctorInputCursor_h
--- /dev/null
+/*
+ * 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.
+ */
+
+#include "config.h"
+#include "ReplayController.h"
+
+#if ENABLE(WEB_REPLAY)
+
+#include "AllReplayInputs.h"
+#include "CapturingInputCursor.h"
+#include "DOMWindow.h"
+#include "DocumentLoader.h"
+#include "Frame.h"
+#include "FrameTree.h"
+#include "InspectorInstrumentation.h"
+#include "Logging.h"
+#include "MainFrame.h"
+#include "Page.h"
+#include "ReplaySession.h"
+#include "ReplaySessionSegment.h"
+#include "ReplayingInputCursor.h"
+#include "ScriptController.h"
+#include "WebReplayInputs.h"
+#include <replay/EmptyInputCursor.h>
+#include <wtf/text/CString.h>
+
+namespace WebCore {
+
+ReplayController::ReplayController(Page& page)
+ : m_page(page)
+ , m_loadedSegment(nullptr)
+ , m_loadedSession(ReplaySession::create())
+ , m_emptyCursor(EmptyInputCursor::create())
+ , m_activeCursor(nullptr)
+ , m_targetPosition(ReplayPosition(0, 0))
+ , m_currentPosition(ReplayPosition(0, 0))
+ , m_segmentState(SegmentState::Unloaded)
+ , m_sessionState(SessionState::Inactive)
+ , m_dispatchSpeed(DispatchSpeed::FastForward)
+{
+}
+
+void ReplayController::switchSession(PassRefPtr<ReplaySession> session)
+{
+ ASSERT(m_segmentState == SegmentState::Unloaded);
+ ASSERT(m_sessionState == SessionState::Inactive);
+
+ m_loadedSession = session;
+ m_currentPosition = ReplayPosition(0, 0);
+
+ LOG(WebReplay, "%-20sSwitching sessions from %p to %p.\n", "ReplayController", m_loadedSession.get(), session.get());
+ InspectorInstrumentation::sessionLoaded(&m_page, m_loadedSession);
+}
+
+void ReplayController::createSegment()
+{
+ ASSERT(m_sessionState == SessionState::Capturing);
+ ASSERT(m_segmentState == SegmentState::Unloaded);
+
+ m_segmentState = SegmentState::Appending;
+
+ // Create a new segment but don't associate it with the current session
+ // until we stop appending to it. This preserves the invariant that
+ // segments associated with a replay session have immutable data.
+ m_loadedSegment = ReplaySessionSegment::create();
+
+ LOG(WebReplay, "%-20s Created segment: %p.\n", "ReplayController", m_loadedSegment.get());
+ InspectorInstrumentation::segmentCreated(&m_page, m_loadedSegment);
+
+ m_activeCursor = m_loadedSegment->createCapturingCursor(m_page);
+ m_activeCursor->appendInput<BeginSegmentSentinel>();
+
+ std::unique_ptr<InitialNavigation> navigationInput = InitialNavigation::createFromPage(m_page);
+ // Dispatching this input schedules navigation of the main frame, causing a refresh.
+ navigationInput->dispatch(*this);
+ m_activeCursor->storeInput(std::move(navigationInput));
+}
+
+void ReplayController::completeSegment()
+{
+ ASSERT(m_sessionState == SessionState::Capturing);
+ ASSERT(m_segmentState == SegmentState::Appending);
+
+ m_activeCursor->appendInput<EndSegmentSentinel>();
+
+ // Hold on to a reference so unloading the segment doesn't deallocate it.
+ RefPtr<ReplaySessionSegment> segment = m_loadedSegment;
+ m_segmentState = SegmentState::Loaded;
+ bool shouldSuppressNotifications = true;
+ unloadSegment(shouldSuppressNotifications);
+
+ LOG(WebReplay, "%-20s Completed segment: %p.\n", "ReplayController", segment.get());
+ InspectorInstrumentation::segmentCompleted(&m_page, segment);
+
+ m_loadedSession->appendSegment(segment);
+ InspectorInstrumentation::sessionModified(&m_page, m_loadedSession);
+}
+
+void ReplayController::loadSegment(PassRefPtr<ReplaySessionSegment> prpSegment)
+{
+ RefPtr<ReplaySessionSegment> segment = prpSegment;
+
+ ASSERT(m_sessionState == SessionState::Replaying);
+ ASSERT(m_segmentState == SegmentState::Unloaded);
+ ASSERT(segment);
+ ASSERT(!m_loadedSegment);
+
+ m_loadedSegment = segment;
+ m_segmentState = SegmentState::Loaded;
+
+ m_activeCursor = m_loadedSegment->createReplayingCursor(m_page, this);
+ dispatcher().setDispatchSpeed(m_dispatchSpeed);
+
+ LOG(WebReplay, "%-20sLoading segment: %p.\n", "ReplayController", segment.get());
+ InspectorInstrumentation::segmentLoaded(&m_page, segment);
+}
+
+void ReplayController::unloadSegment(bool suppressNotifications)
+{
+ ASSERT(m_sessionState != SessionState::Inactive);
+ ASSERT(m_segmentState == SegmentState::Loaded);
+
+ m_segmentState = SegmentState::Unloaded;
+
+ LOG(WebReplay, "%-20s Clearing input cursors for page: %p\n", "ReplayController", &m_page);
+
+ m_activeCursor = nullptr;
+ RefPtr<ReplaySessionSegment> unloadedSegment = m_loadedSegment.release();
+ for (Frame* frame = &m_page.mainFrame(); frame; frame = frame->tree().traverseNext()) {
+ frame->script().globalObject(mainThreadNormalWorld())->setInputCursor(m_emptyCursor);
+ frame->document()->setInputCursor(m_emptyCursor);
+ }
+
+ // When we stop capturing, don't send out segment unloaded events since we
+ // didn't send out the corresponding segmentLoaded event at the start of capture.
+ if (!suppressNotifications) {
+ LOG(WebReplay, "%-20sUnloading segment: %p.\n", "ReplayController", unloadedSegment.get());
+ InspectorInstrumentation::segmentUnloaded(&m_page);
+ }
+}
+
+void ReplayController::startCapturing()
+{
+ ASSERT(m_sessionState == SessionState::Inactive);
+ ASSERT(m_segmentState == SegmentState::Unloaded);
+
+ m_sessionState = SessionState::Capturing;
+
+ LOG(WebReplay, "%-20s Starting capture.\n", "ReplayController");
+ InspectorInstrumentation::captureStarted(&m_page);
+
+ m_currentPosition = ReplayPosition(0, 0);
+ createSegment();
+}
+
+void ReplayController::stopCapturing()
+{
+ ASSERT(m_sessionState == SessionState::Capturing);
+ ASSERT(m_segmentState == SegmentState::Appending);
+
+ completeSegment();
+
+ m_sessionState = SessionState::Inactive;
+
+ LOG(WebReplay, "%-20s Stopping capture.\n", "ReplayController");
+ InspectorInstrumentation::captureStopped(&m_page);
+}
+
+void ReplayController::startPlayback()
+{
+ ASSERT(m_sessionState == SessionState::Replaying);
+ ASSERT(m_segmentState == SegmentState::Loaded);
+
+ m_segmentState = SegmentState::Dispatching;
+
+ LOG(WebReplay, "%-20s Starting playback to position (segment: %d, input: %d).\n", "ReplayController", m_targetPosition.segmentOffset, m_targetPosition.inputOffset);
+ InspectorInstrumentation::playbackStarted(&m_page);
+
+ dispatcher().run();
+}
+
+void ReplayController::pausePlayback()
+{
+ ASSERT(m_sessionState == SessionState::Replaying);
+ ASSERT(m_segmentState == SegmentState::Dispatching);
+
+ m_segmentState = SegmentState::Loaded;
+
+ dispatcher().pause();
+
+ LOG(WebReplay, "%-20s Pausing playback at position (segment: %d, input: %d).\n", "ReplayController", m_currentPosition.segmentOffset, m_currentPosition.inputOffset);
+ InspectorInstrumentation::playbackPaused(&m_page, m_currentPosition);
+}
+
+void ReplayController::cancelPlayback()
+{
+ ASSERT(m_sessionState == SessionState::Replaying);
+ ASSERT(m_segmentState != SegmentState::Appending);
+
+ if (m_segmentState == SegmentState::Unloaded)
+ return;
+
+ if (m_segmentState == SegmentState::Dispatching)
+ pausePlayback();
+
+ ASSERT(m_segmentState == SegmentState::Loaded);
+ unloadSegment();
+ m_sessionState = SessionState::Inactive;
+}
+
+void ReplayController::replayToPosition(const ReplayPosition& position, DispatchSpeed speed)
+{
+ ASSERT(m_sessionState != SessionState::Capturing);
+ ASSERT(m_segmentState == SegmentState::Loaded || m_segmentState == SegmentState::Unloaded);
+ ASSERT(position.segmentOffset < m_loadedSession->size());
+
+ m_dispatchSpeed = speed;
+
+ if (m_sessionState != SessionState::Replaying)
+ m_sessionState = SessionState::Replaying;
+
+ if (m_segmentState == SegmentState::Unloaded)
+ loadSegment(m_loadedSession->at(position.segmentOffset));
+ else if (position.segmentOffset != m_currentPosition.segmentOffset || m_currentPosition.inputOffset > position.inputOffset) {
+ // If the desired segment is not loaded or we have gone past the desired input
+ // offset, then unload the current segment and load the appropriate segment.
+ unloadSegment();
+ loadSegment(m_loadedSession->at(position.segmentOffset));
+ }
+
+ ASSERT(m_currentPosition.segmentOffset == position.segmentOffset);
+ ASSERT(m_loadedSession->at(position.segmentOffset) == m_loadedSegment);
+
+ m_targetPosition = position;
+ startPlayback();
+}
+
+void ReplayController::frameNavigated(DocumentLoader* loader)
+{
+ ASSERT(m_sessionState != SessionState::Inactive);
+
+ // The initial capturing segment is created prior to main frame navigation.
+ // Otherwise, the prior capturing segment was completed when the frame detached,
+ // and it is now time to create a new segment.
+ if (m_sessionState == SessionState::Capturing && m_segmentState == SegmentState::Unloaded) {
+ m_currentPosition = ReplayPosition(m_currentPosition.segmentOffset + 1, 0);
+ createSegment();
+ }
+
+ // During playback, the next segment is loaded when the final input is dispatched,
+ // so nothing needs to be done here.
+
+ // We store the input cursor in both Document and JSDOMWindow, so that
+ // replay state is accessible from JavaScriptCore and script-free layout code.
+ loader->frame()->document()->setInputCursor(m_activeCursor.get());
+ loader->frame()->script().globalObject(mainThreadNormalWorld())->setInputCursor(m_activeCursor.get());
+}
+
+void ReplayController::frameDetached(Frame* frame)
+{
+ ASSERT(m_sessionState != SessionState::Inactive);
+ ASSERT(frame);
+
+ if (!frame->document())
+ return;
+
+ // If the frame's cursor isn't capturing or replaying, we should do nothing.
+ // This is the case for the "outbound" frame when starting capture, or when
+ // we clear the input cursor to finish or prematurely unload a segment.
+ if (frame->document()->inputCursor().isCapturing()) {
+ ASSERT(m_segmentState == SegmentState::Appending);
+ completeSegment();
+ }
+
+ // During playback, the segments are unloaded and loaded when the final
+ // input has been dispatched. So, nothing needs to be done here.
+}
+
+PassRefPtr<ReplaySession> ReplayController::loadedSession() const
+{
+ return m_loadedSession;
+}
+
+PassRefPtr<ReplaySessionSegment> ReplayController::loadedSegment() const
+{
+ return m_loadedSegment;
+}
+
+InputCursor& ReplayController::activeInputCursor() const
+{
+ return m_activeCursor ? *m_activeCursor : *m_emptyCursor;
+}
+
+EventLoopInputDispatcher& ReplayController::dispatcher() const
+{
+ ASSERT(m_sessionState == SessionState::Replaying);
+ ASSERT(m_segmentState == SegmentState::Dispatching);
+ ASSERT(m_activeCursor);
+ ASSERT(m_activeCursor->isReplaying());
+
+ return static_cast<ReplayingInputCursor&>(*m_activeCursor).dispatcher();
+}
+
+void ReplayController::willDispatchInput(const EventLoopInputBase&)
+{
+ ASSERT(m_sessionState == SessionState::Replaying);
+ ASSERT(m_segmentState == SegmentState::Dispatching);
+
+ m_currentPosition.inputOffset++;
+ if (m_currentPosition == m_targetPosition)
+ pausePlayback();
+}
+
+void ReplayController::didDispatchInput(const EventLoopInputBase&)
+{
+ ASSERT(m_sessionState == SessionState::Replaying);
+ ASSERT(m_segmentState == SegmentState::Dispatching);
+
+ InspectorInstrumentation::playbackHitPosition(&m_page, m_currentPosition);
+}
+
+void ReplayController::didDispatchFinalInput()
+{
+ ASSERT(m_segmentState == SegmentState::Dispatching);
+
+ pause();
+ unloadSegment();
+
+ // No more segments left to replay; stop.
+ if (++m_currentPosition.segmentOffset == m_loadedSession->size())
+ return;
+
+ loadSegment(m_loadedSession->at(m_currentPosition.segmentOffset));
+ startPlayback();
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(WEB_REPLAY)
--- /dev/null
+/*
+ * 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.
+ */
+
+#ifndef ReplayController_h
+#define ReplayController_h
+
+#if ENABLE(WEB_REPLAY)
+
+#include "EventLoopInputDispatcher.h"
+#include <wtf/Noncopyable.h>
+#include <wtf/Vector.h>
+
+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_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(PassRefPtr<ReplaySession>);
+
+ // InspectorReplayAgent notifications.
+ void frameNavigated(DocumentLoader*);
+ void frameDetached(Frame*);
+
+ Page& page() const { return m_page; }
+ SessionState sessionState() const { return m_sessionState; }
+ PassRefPtr<ReplaySession> loadedSession() const;
+ PassRefPtr<ReplaySessionSegment> loadedSegment() const;
+ JSC::InputCursor& activeInputCursor() const;
+
+private:
+ // EventLoopInputDispatcherClient API
+ virtual void willDispatchInput(const EventLoopInputBase&) override;
+ virtual void didDispatchInput(const EventLoopInputBase&) override;
+ virtual void didDispatchFinalInput() override;
+
+ void createSegment();
+ void completeSegment();
+
+ void loadSegment(PassRefPtr<ReplaySessionSegment>);
+ void unloadSegment(bool suppressNotifications = false);
+
+ EventLoopInputDispatcher& dispatcher() const;
+
+ Page& m_page;
+
+ RefPtr<ReplaySessionSegment> m_loadedSegment;
+ RefPtr<ReplaySession> m_loadedSession;
+ const RefPtr<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;
+};
+
+} // namespace WebCore
+
+#endif // ENABLE(WEB_REPLAY)
+
+#endif // ReplayController_h
--- /dev/null
+/*
+ * Copyright (C) 2011-2013 University of Washington.
+ * 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.
+ */
+
+#include "config.h"
+
+#if ENABLE(WEB_REPLAY)
+
+#include "Document.h"
+#include "MainFrame.h"
+#include "Page.h"
+#include "SecurityOrigin.h"
+#include "SerializationMethods.h"
+#include "WebReplayInputs.h"
+
+namespace WebCore {
+
+std::unique_ptr<InitialNavigation> InitialNavigation::createFromPage(const Page& page)
+{
+ const MainFrame& mainFrame = page.mainFrame();
+ ASSERT(mainFrame.document());
+
+ // Make sure that this is in sync with ReplayController::beginCapturing().
+ RefPtr<SecurityOrigin> originCopy = mainFrame.document()->securityOrigin()->isolatedCopy();
+ URL url = mainFrame.document()->url();
+ String referrer = mainFrame.loader().referrer();
+ return std::make_unique<InitialNavigation>(originCopy, url, referrer);
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(WEB_REPLAY)
--- /dev/null
+/*
+ * Copyright (C) 2011-2013 University of Washington.
+ * 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.
+ */
+
+#include "config.h"
+
+#if ENABLE(WEB_REPLAY)
+
+#include "AllReplayInputs.h"
+#include "MainFrame.h"
+#include "NavigationScheduler.h"
+#include "Page.h"
+#include "ReplayController.h"
+#include "URL.h"
+
+namespace WebCore {
+
+// Sentinel inputs.
+void BeginSegmentSentinel::dispatch(ReplayController&)
+{
+}
+
+void EndSegmentSentinel::dispatch(ReplayController&)
+{
+}
+
+// Navigation inputs.
+void InitialNavigation::dispatch(ReplayController& controller)
+{
+ controller.page().mainFrame().navigationScheduler().scheduleLocationChange(m_securityOrigin.get(), m_url, m_referrer, true, true);
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(WEB_REPLAY)
ReplayInputTypes::ReplayInputTypes()
: dummy(0)
JS_REPLAY_INPUT_NAMES_FOR_EACH(INITIALIZE_INPUT_TYPE)
+WEB_REPLAY_INPUT_NAMES_FOR_EACH(INITIALIZE_INPUT_TYPE)
{
UNUSED_PARAM(dummy);
}
#if ENABLE(WEB_REPLAY)
#include "ThreadGlobalData.h"
+#include "WebReplayInputs.h"
#include <JavaScriptCore/JSReplayInputs.h>
#include <wtf/text/AtomicString.h>
#define DECLARE_REPLAY_INPUT_TYPES(name) AtomicString name;
JS_REPLAY_INPUT_NAMES_FOR_EACH(DECLARE_REPLAY_INPUT_TYPES)
+ WEB_REPLAY_INPUT_NAMES_FOR_EACH(DECLARE_REPLAY_INPUT_TYPES)
#undef DECLARE_REPLAY_INPUT_TYPES
};
--- /dev/null
+/*
+ * Copyright (C) 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.
+ */
+
+#include "config.h"
+#include "ReplaySession.h"
+
+#if ENABLE(WEB_REPLAY)
+
+#include "ReplaySessionSegment.h"
+#include <wtf/CurrentTime.h>
+
+namespace WebCore {
+
+static unsigned s_nextIdentifier = 1;
+
+PassRefPtr<ReplaySession> ReplaySession::create()
+{
+ return adoptRef(new ReplaySession());
+}
+
+ReplaySession::ReplaySession()
+ : m_identifier(s_nextIdentifier++)
+ , m_timestamp(currentTimeMS())
+{
+}
+
+ReplaySession::~ReplaySession()
+{
+}
+
+PassRefPtr<ReplaySessionSegment> ReplaySession::at(size_t position) const
+{
+ return m_segments.at(position);
+}
+
+void ReplaySession::appendSegment(PassRefPtr<ReplaySessionSegment> prpSegment)
+{
+ RefPtr<ReplaySessionSegment> segment = prpSegment;
+
+ // For now, only support one segment.
+ ASSERT(!m_segments.size());
+
+ // Since replay locations are specified with segment IDs, we can only
+ // have one instance of a segment in the session.
+ size_t offset = m_segments.find(segment);
+ ASSERT_UNUSED(offset, offset == notFound);
+
+ m_segments.append(segment.release());
+}
+
+void ReplaySession::insertSegment(size_t position, PassRefPtr<ReplaySessionSegment> segment)
+{
+ ASSERT(position < m_segments.size());
+ m_segments.insert(position, segment);
+}
+
+void ReplaySession::removeSegment(size_t position)
+{
+ ASSERT(position < m_segments.size());
+ m_segments.remove(position);
+}
+
+}; // namespace WebCore
+
+#endif // ENABLE(WEB_REPLAY)
--- /dev/null
+/*
+ * Copyright (C) 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.
+ */
+
+#ifndef ReplaySession_h
+#define ReplaySession_h
+
+#if ENABLE(WEB_REPLAY)
+
+#include <wtf/Noncopyable.h>
+#include <wtf/RefCounted.h>
+#include <wtf/Vector.h>
+
+namespace WebCore {
+
+class ReplaySessionSegment;
+
+typedef Vector<RefPtr<ReplaySessionSegment>>::const_iterator SegmentIterator;
+
+class ReplaySession : public RefCounted<ReplaySession> {
+ WTF_MAKE_NONCOPYABLE(ReplaySession);
+public:
+ static PassRefPtr<ReplaySession> create();
+ ~ReplaySession();
+
+ double timestamp() const { return m_timestamp; }
+ unsigned identifier() const { return m_identifier; }
+
+ size_t size() const { return m_segments.size(); }
+ PassRefPtr<ReplaySessionSegment> at(size_t position) const;
+
+ SegmentIterator begin() const { return m_segments.begin(); }
+ SegmentIterator end() const { return m_segments.end(); }
+
+ void appendSegment(PassRefPtr<ReplaySessionSegment>);
+ void insertSegment(size_t position, PassRefPtr<ReplaySessionSegment>);
+ void removeSegment(size_t position);
+
+private:
+ ReplaySession();
+
+ Vector<RefPtr<ReplaySessionSegment>> m_segments;
+ unsigned m_identifier;
+ double m_timestamp;
+};
+
+} // namespace WebCore
+
+#endif // ENABLE(WEB_REPLAY)
+
+#endif // ReplaySession_h
--- /dev/null
+/*
+ * Copyright (C) 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.
+ */
+
+#include "config.h"
+#include "ReplaySessionSegment.h"
+
+#if ENABLE(WEB_REPLAY)
+
+#include "CapturingInputCursor.h"
+#include "FunctorInputCursor.h"
+#include "ReplayingInputCursor.h"
+#include "SegmentedInputStorage.h"
+#include <wtf/CurrentTime.h>
+
+namespace WebCore {
+
+static unsigned s_nextSegmentIdentifier = 1;
+
+PassRefPtr<ReplaySessionSegment> ReplaySessionSegment::create()
+{
+ return adoptRef(new ReplaySessionSegment);
+}
+
+ReplaySessionSegment::ReplaySessionSegment()
+ : m_storage(std::make_unique<SegmentedInputStorage>())
+ , m_identifier(s_nextSegmentIdentifier++)
+ , m_canCapture(true)
+ , m_timestamp(currentTimeMS())
+{
+}
+
+ReplaySessionSegment::~ReplaySessionSegment()
+{
+}
+
+PassRefPtr<CapturingInputCursor> ReplaySessionSegment::createCapturingCursor(Page&)
+{
+ ASSERT(m_canCapture);
+ m_canCapture = false;
+ return CapturingInputCursor::create(*m_storage);
+}
+
+PassRefPtr<ReplayingInputCursor> ReplaySessionSegment::createReplayingCursor(Page& page, EventLoopInputDispatcherClient* client)
+{
+ return ReplayingInputCursor::create(*m_storage, page, client);
+}
+
+std::unique_ptr<FunctorInputCursor> ReplaySessionSegment::createFunctorCursor()
+{
+ return std::make_unique<FunctorInputCursor>(*m_storage);
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(WEB_REPLAY)
--- /dev/null
+/*
+ * Copyright (C) 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.
+ */
+
+#ifndef ReplaySessionSegment_h
+#define ReplaySessionSegment_h
+
+#if ENABLE(WEB_REPLAY)
+
+#include <replay/NondeterministicInput.h>
+#include <wtf/RefCounted.h>
+
+namespace WebCore {
+
+class CapturingInputCursor;
+class EventLoopInputDispatcherClient;
+class FunctorInputCursor;
+class Page;
+class ReplayingInputCursor;
+class SegmentedInputStorage;
+
+class ReplaySessionSegment : public RefCounted<ReplaySessionSegment> {
+public:
+ static PassRefPtr<ReplaySessionSegment> create();
+ ~ReplaySessionSegment();
+
+ unsigned identifier() const { return m_identifier; }
+ double timestamp() const { return m_timestamp; }
+
+ PassRefPtr<CapturingInputCursor> createCapturingCursor(Page&);
+ PassRefPtr<ReplayingInputCursor> createReplayingCursor(Page&, EventLoopInputDispatcherClient*);
+ std::unique_ptr<FunctorInputCursor> createFunctorCursor();
+private:
+ ReplaySessionSegment();
+
+ std::unique_ptr<SegmentedInputStorage> m_storage;
+ unsigned m_identifier;
+ bool m_canCapture;
+ double m_timestamp;
+};
+
+} // namespace WebCore
+
+#endif // ENABLE(WEB_REPLAY)
+
+#endif // ReplaySessionSegment_h
--- /dev/null
+/*
+ * Copyright (C) 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.
+ */
+
+#include "config.h"
+#include "ReplayingInputCursor.h"
+
+#if ENABLE(WEB_REPLAY)
+
+#include "EventLoopInputDispatcher.h"
+#include "SegmentedInputStorage.h"
+#include "SerializationMethods.h"
+#include "WebReplayInputs.h"
+#include <wtf/text/CString.h>
+
+namespace WebCore {
+
+ReplayingInputCursor::ReplayingInputCursor(SegmentedInputStorage& storage, Page& page, EventLoopInputDispatcherClient* client)
+ : m_storage(storage)
+ , m_dispatcher(std::make_unique<EventLoopInputDispatcher>(page, *this, client))
+{
+ for (size_t i = 0; i < static_cast<size_t>(InputQueue::Count); i++)
+ m_positions.append(0);
+}
+
+ReplayingInputCursor::~ReplayingInputCursor()
+{
+}
+
+PassRefPtr<ReplayingInputCursor> ReplayingInputCursor::create(SegmentedInputStorage& storage, Page& page, EventLoopInputDispatcherClient* client)
+{
+ return adoptRef(new ReplayingInputCursor(storage, page, client));
+}
+
+void ReplayingInputCursor::storeInput(std::unique_ptr<NondeterministicInputBase>)
+{
+ // Cannot store inputs from a replaying input cursor.
+ ASSERT_NOT_REACHED();
+}
+
+NondeterministicInputBase* ReplayingInputCursor::loadInput(InputQueue queue, const AtomicString& type)
+{
+ NondeterministicInputBase* input = uncheckedLoadInput(queue);
+
+ if (input->type() != type) {
+ LOG_ERROR("%-25s ERROR: Expected replay input of type %s, but got type %s\n", "[ReplayingInputCursor]", type.string().ascii().data(), input->type().string().ascii().data());
+ return nullptr;
+ }
+
+ return input;
+}
+
+NondeterministicInputBase* ReplayingInputCursor::uncheckedLoadInput(InputQueue queue)
+{
+ if (m_positions[static_cast<size_t>(queue)] >= m_storage.queueSize(queue)) {
+ String queueString = EncodingTraits<InputQueue>::encodeValue(queue).convertTo<String>();
+ LOG_ERROR("%-30s ERROR No more inputs remain for determinism queue %s, but one was requested.", "[ReplayingInputCursor]", queueString.ascii().data());
+ return nullptr;
+ }
+
+ return m_storage.load(queue, m_positions[static_cast<size_t>(queue)]++);
+}
+
+}; // namespace WebCore
+
+#endif // ENABLE(WEB_REPLAY)
--- /dev/null
+/*
+ * Copyright (C) 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.
+ */
+
+#ifndef ReplayingInputCursor_h
+#define ReplayingInputCursor_h
+
+#if ENABLE(WEB_REPLAY)
+
+#include <replay/InputCursor.h>
+#include <wtf/Vector.h>
+#include <wtf/text/AtomicString.h>
+
+namespace WebCore {
+
+class EventLoopInputDispatcher;
+class EventLoopInputDispatcherClient;
+class Page;
+class SegmentedInputStorage;
+
+class ReplayingInputCursor final : public InputCursor {
+ WTF_MAKE_NONCOPYABLE(ReplayingInputCursor);
+public:
+ static PassRefPtr<ReplayingInputCursor> create(SegmentedInputStorage&, Page&, EventLoopInputDispatcherClient*);
+ virtual ~ReplayingInputCursor();
+
+ virtual bool isCapturing() const override { return false; }
+ virtual bool isReplaying() const override { return true; }
+
+ EventLoopInputDispatcher& dispatcher() const { return *m_dispatcher; }
+
+ virtual void storeInput(std::unique_ptr<NondeterministicInputBase>) override;
+ virtual NondeterministicInputBase* uncheckedLoadInput(InputQueue) override;
+protected:
+ virtual NondeterministicInputBase* loadInput(InputQueue, const AtomicString& type) override;
+private:
+ ReplayingInputCursor(SegmentedInputStorage&, Page&, EventLoopInputDispatcherClient*);
+
+ SegmentedInputStorage& m_storage;
+ std::unique_ptr<EventLoopInputDispatcher> m_dispatcher;
+ Vector<size_t> m_positions;
+};
+
+} // namespace WebCore
+
+#endif // ENABLE(WEB_REPLAY)
+
+#endif // ReplayingInputCursor_h
--- /dev/null
+/*
+ * Copyright (C) 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.
+ */
+
+#include "config.h"
+#include "SegmentedInputStorage.h"
+
+#if ENABLE(WEB_REPLAY)
+
+#if !LOG_DISABLED
+#include "Logging.h"
+#include "SerializationMethods.h"
+#include <replay/EncodedValue.h>
+#include <wtf/text/CString.h>
+#include <wtf/text/WTFString.h>
+#endif
+
+namespace WebCore {
+
+#if !LOG_DISABLED
+// These are used to make the log spew from LOG(WebReplay, ...) more readable.
+static const char* queueTypeToLogPrefix(InputQueue inputQueue, bool isLoad)
+{
+ if (isLoad) {
+ switch (inputQueue) {
+ case InputQueue::EventLoopInput: return "(DSPTCH-LOAD)";
+ case InputQueue::LoaderMemoizedData: return "<LDMEMO-LOAD";
+ case InputQueue::ScriptMemoizedData: return "<---<---<---JSMEMO-LOAD";
+ case InputQueue::Count: return "ERROR!";
+ }
+ } else {
+ switch (inputQueue) {
+ case InputQueue::EventLoopInput: return ">DSPTCH-STORE";
+ case InputQueue::LoaderMemoizedData: return "<LDMEMO-STORE";
+ case InputQueue::ScriptMemoizedData: return "<---<---<---JSMEMO-STORE";
+ case InputQueue::Count: return "ERROR!";
+ }
+ }
+}
+
+static String jsonStringForInput(const NondeterministicInputBase& input)
+{
+ EncodedValue encodedValue = EncodingTraits<NondeterministicInputBase>::encodeValue(input);
+ return encodedValue.asObject()->toJSONString();
+}
+#endif // !LOG_DISABLED
+
+static size_t offsetForInputQueue(InputQueue inputQueue)
+{
+ return static_cast<size_t>(inputQueue);
+}
+
+SegmentedInputStorage::SegmentedInputStorage()
+ : m_inputCount(0)
+{
+ for (size_t i = 0; i < offsetForInputQueue(InputQueue::Count); i++)
+ m_queues.append(new QueuedInputs);
+}
+
+SegmentedInputStorage::~SegmentedInputStorage()
+{
+ for (size_t i = 0; i < offsetForInputQueue(InputQueue::Count); i++)
+ delete m_queues.at(i);
+}
+
+NondeterministicInputBase* SegmentedInputStorage::load(InputQueue inputQueue, size_t offset)
+{
+ ASSERT(offset < queueSize(inputQueue));
+
+ NondeterministicInputBase* input = queue(inputQueue).at(offset).get();
+ ASSERT(input);
+
+ LOG(WebReplay, "%-20s %s: %s %s\n", "ReplayEvents", queueTypeToLogPrefix(inputQueue, true), input->type().string().utf8().data(), jsonStringForInput(*input).utf8().data());
+
+ return input;
+}
+
+void SegmentedInputStorage::store(std::unique_ptr<NondeterministicInputBase> input)
+{
+ ASSERT(input);
+ ASSERT(input->queue() < InputQueue::Count);
+
+ LOG(WebReplay, "%-14s#%-5u %s: %s %s\n", "ReplayEvents", m_inputCount++, queueTypeToLogPrefix(input->queue(), false), input->type().string().utf8().data(), jsonStringForInput(*input).utf8().data());
+
+ m_queues.at(offsetForInputQueue(input->queue()))->append(std::move(input));
+}
+
+size_t SegmentedInputStorage::queueSize(InputQueue inputQueue) const
+{
+ return queue(inputQueue).size();
+}
+
+const SegmentedInputStorage::QueuedInputs& SegmentedInputStorage::queue(InputQueue queue) const
+{
+ ASSERT(queue < InputQueue::Count);
+ return *m_queues.at(offsetForInputQueue(queue));
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(WEB_REPLAY)
--- /dev/null
+/*
+ * Copyright (C) 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.
+ */
+
+#ifndef SegmentedInputStorage_h
+#define SegmentedInputStorage_h
+
+#if ENABLE(WEB_REPLAY)
+
+#include <replay/NondeterministicInput.h>
+#include <wtf/Noncopyable.h>
+#include <wtf/Vector.h>
+
+namespace WebCore {
+
+class SegmentedInputStorage {
+ WTF_MAKE_NONCOPYABLE(SegmentedInputStorage);
+ friend class FunctorInputCursor;
+public:
+ SegmentedInputStorage();
+ ~SegmentedInputStorage();
+
+ NondeterministicInputBase* load(InputQueue, size_t);
+ void store(std::unique_ptr<NondeterministicInputBase>);
+ size_t queueSize(InputQueue) const;
+
+private:
+ typedef Vector<std::unique_ptr<NondeterministicInputBase>> QueuedInputs;
+ const QueuedInputs& queue(InputQueue) const;
+
+ Vector<QueuedInputs*, 3> m_queues;
+ unsigned m_inputCount;
+};
+
+} // namespace WebCore
+
+#endif // ENABLE(WEB_REPLAY)
+
+#endif // SegmentedInputStorage_h
--- /dev/null
+/*
+ * Copyright (C) 2012 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.
+ */
+
+#include "config.h"
+#include "SerializationMethods.h"
+
+#if ENABLE(WEB_REPLAY)
+
+#include "AllReplayInputs.h"
+#include "ReplayInputTypes.h"
+#include "SecurityOrigin.h"
+#include "URL.h"
+
+using WebCore::SecurityOrigin;
+using WebCore::URL;
+using WebCore::inputTypes;
+
+#define IMPORT_FROM_WEBCORE_NAMESPACE(name) \
+using WebCore::name; \
+
+WEB_REPLAY_INPUT_NAMES_FOR_EACH(IMPORT_FROM_WEBCORE_NAMESPACE)
+#undef IMPORT_FROM_WEBCORE_NAMESPACE
+
+namespace JSC {
+
+EncodedValue EncodingTraits<NondeterministicInputBase>::encodeValue(const NondeterministicInputBase& input)
+{
+ EncodedValue encodedValue = EncodedValue::createObject();
+ const AtomicString& type = input.type();
+ encodedValue.put<String>(ASCIILiteral("type"), type.string());
+
+#define ENCODE_IF_TYPE_TAG_MATCHES(name) \
+ if (type == inputTypes().name) { \
+ InputTraits<name>::encode(encodedValue, static_cast<const name&>(input)); \
+ return encodedValue; \
+ } \
+
+ JS_REPLAY_INPUT_NAMES_FOR_EACH(ENCODE_IF_TYPE_TAG_MATCHES)
+ WEB_REPLAY_INPUT_NAMES_FOR_EACH(ENCODE_IF_TYPE_TAG_MATCHES)
+#undef ENCODE_IF_TYPE_TAG_MATCHES
+
+ ASSERT_NOT_REACHED();
+ return EncodedValue();
+}
+
+bool EncodingTraits<NondeterministicInputBase>::decodeValue(EncodedValue& encodedValue, std::unique_ptr<NondeterministicInputBase>& input)
+{
+ String type;
+ if (!encodedValue.get<String>(ASCIILiteral("type"), type))
+ return false;
+
+#define DECODE_IF_TYPE_TAG_MATCHES(name) \
+ if (type == inputTypes().name) { \
+ std::unique_ptr<name> decodedInput; \
+ if (!InputTraits<name>::decode(encodedValue, decodedInput)) \
+ return false; \
+ \
+ input = std::move(decodedInput); \
+ return true; \
+ } \
+
+ JS_REPLAY_INPUT_NAMES_FOR_EACH(DECODE_IF_TYPE_TAG_MATCHES)
+ WEB_REPLAY_INPUT_NAMES_FOR_EACH(DECODE_IF_TYPE_TAG_MATCHES)
+#undef DECODE_IF_TYPE_TAG_MATCHES
+
+ return false;
+}
+
+EncodedValue EncodingTraits<SecurityOrigin>::encodeValue(RefPtr<SecurityOrigin> input)
+{
+ return EncodedValue::createString(input->toString());
+}
+
+bool EncodingTraits<SecurityOrigin>::decodeValue(EncodedValue& encodedValue, RefPtr<SecurityOrigin>& input)
+{
+ input = SecurityOrigin::createFromString(encodedValue.convertTo<String>());
+ return true;
+}
+
+EncodedValue EncodingTraits<URL>::encodeValue(const URL& input)
+{
+ return EncodedValue::createString(input.string());
+}
+
+bool EncodingTraits<URL>::decodeValue(EncodedValue& encodedValue, URL& input)
+{
+ input = URL(WebCore::ParsedURLString, encodedValue.convertTo<String>());
+ return true;
+}
+
+} // namespace JSC
+
+#endif // ENABLE(WEB_REPLAY)
--- /dev/null
+/*
+ * Copyright (C) 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.
+ */
+
+#ifndef SerializationMethods_h
+#define SerializationMethods_h
+
+#if ENABLE(WEB_REPLAY)
+
+#include <replay/EncodedValue.h>
+#include <replay/NondeterministicInput.h>
+
+namespace WebCore {
+class Document;
+class Frame;
+class Page;
+class SecurityOrigin;
+class URL;
+} // namespace WebCore
+
+// Template specializations must be defined in the same namespace as the template declaration.
+namespace JSC {
+
+template<> struct EncodingTraits<NondeterministicInputBase> {
+ typedef NondeterministicInputBase DecodedType;
+
+ static EncodedValue encodeValue(const NondeterministicInputBase& value);
+ static bool decodeValue(EncodedValue&, std::unique_ptr<NondeterministicInputBase>& value);
+};
+
+template<> struct EncodingTraits<WebCore::URL> {
+ typedef WebCore::URL DecodedType;
+
+ static EncodedValue encodeValue(const WebCore::URL& value);
+ static bool decodeValue(EncodedValue&, WebCore::URL& value);
+};
+
+template<> struct EncodingTraits<WebCore::SecurityOrigin> {
+ typedef RefPtr<WebCore::SecurityOrigin> DecodedType;
+
+ static EncodedValue encodeValue(RefPtr<WebCore::SecurityOrigin> value);
+ static bool decodeValue(EncodedValue&, RefPtr<WebCore::SecurityOrigin>& value);
+};
+
+} // namespace JSC
+
+#endif // ENABLE(WEB_REPLAY)
+
+#endif // SerializationMethods_h
--- /dev/null
+{
+ "types": {
+ "Global": [
+ { "name": "bool", "mode": "SCALAR" },
+ { "name": "double", "mode": "SCALAR" },
+ { "name": "int", "mode": "SCALAR" },
+ { "name": "unsigned", "mode": "SCALAR" },
+ { "name": "unsigned long", "mode": "SCALAR" },
+ { "name": "unsigned long long", "mode": "SCALAR" }
+ ],
+
+ "WTF": [
+ {
+ "name": "String", "mode": "HEAVY_SCALAR",
+ "header": "wtf/text/WTFString.h"
+ }
+ ],
+
+ "JavaScriptCore": [
+ {
+ "name": "InputQueue", "mode": "SCALAR", "storage": "uint8_t",
+ "flags": ["ENUM_CLASS"],
+ "values": ["EventLoopInput", "LoaderMemoizedData", "ScriptMemoizedData", "Count"],
+ "header": "replay/NondeterministicInput.h"
+ }
+ ],
+
+ "WebCore": [
+ {
+ "name": "URL", "mode": "HEAVY_SCALAR",
+ "header": "platform/URL.h"
+ },
+ {
+ "name": "SecurityOrigin", "mode": "SHARED",
+ "header": "page/SecurityOrigin.h"
+ },
+ {
+ "name": "Page", "mode": "OWNED",
+ "header": "page/Page.h"
+ }
+ ]
+ },
+
+ "inputs": [
+ {
+ "name": "BeginSegmentSentinel",
+ "description": "A sentinel input to signal the start of a segment.",
+ "queue": "EVENT_LOOP",
+ "members": [ ]
+ },
+ {
+ "name": "EndSegmentSentinel",
+ "description": "A sentinel input to signal the end of a segment.",
+ "queue": "EVENT_LOOP",
+ "members": [ ]
+ },
+ {
+ "name": "InitialNavigation",
+ "description": "Initiate the initial main frame navigation.",
+ "queue": "EVENT_LOOP",
+ "flags": ["HIDDEN", "CREATE_FROM_PAGE"],
+ "members": [
+ { "name": "securityOrigin", "type": "SecurityOrigin" },
+ { "name": "url", "type": "URL" },
+ { "name": "referrer", "type": "String" }
+ ]
+ }
+ ]
+}