https://bugs.webkit.org/show_bug.cgi?id=131193
Reviewed by Andreas Kling.
Add assertions to catch potential nondeterministic behavior.
The assertion added by this patch catches dispatched DOM events
that are triggered by nondeterministic event loop cycles. If we
did not capture an event loop input in the current event loop
cycle nor are we manually simulating an event loop input during
playback, then DOM events fired during the unordered cycle could
run JavaScript and diverge the execution.
During playback, we can assert that EventLoopInputDispatcher is dispatching
when a DOM event is be dispatched to a document that is being replayed.
During capturing, event loop inputs are captured rather than
dispatched, so we add some accounting to track what caused a DOM
event. To approximate the extent of computation triggered by an
event loop input, we add RAII helpers to call sites where event
loop inputs are captured.
The assertions are disabled by default until the most common
sources of nondeterminism are handled and playback errors are
gracefully surfaced to the user. <https://webkit.org/b/131279>
No new tests. This patch adds extra assertions for debugging purposes.
* WebCore.xcodeproj/project.pbxproj:
* inspector/InspectorInstrumentation.cpp: Notify ReplayAgent of dispatched DOM event.
(WebCore::InspectorInstrumentation::willDispatchEventImpl):
(WebCore::InspectorInstrumentation::willDispatchEventOnWindowImpl):
* inspector/InspectorReplayAgent.cpp: Forward dispatched DOM events to ReplayController.
(WebCore::InspectorReplayAgent::willDispatchEvent): Added.
* inspector/InspectorReplayAgent.h:
* replay/CapturingInputCursor.cpp:
(WebCore::CapturingInputCursor::CapturingInputCursor):
(WebCore::CapturingInputCursor::setWithinEventLoopInputExtent): Added.
* replay/CapturingInputCursor.h:
* replay/EventLoopInput.cpp: Added.
(WebCore::EventLoopInputExtent::EventLoopInputExtent): Added.
(WebCore::EventLoopInputExtent::~EventLoopInputExtent): Added.
* replay/EventLoopInput.h:
* replay/EventLoopInputDispatcher.h:
(WebCore::EventLoopInputDispatcher::isDispatching): Add a getter.
* replay/ReplayController.cpp:
(WebCore::logDispatchedDOMEvent): Added. This is useful for understanding script-visible events.
(WebCore::ReplayController::willDispatchEvent): Added.
* replay/ReplayController.h:
* replay/UserInputBridge.cpp: Add extent helpers to call sites that capture inputs.
(WebCore::UserInputBridge::handleMousePressEvent):
(WebCore::UserInputBridge::handleMouseReleaseEvent):
(WebCore::UserInputBridge::handleMouseMoveEvent):
(WebCore::UserInputBridge::handleMouseMoveOnScrollbarEvent):
(WebCore::UserInputBridge::handleKeyEvent):
(WebCore::UserInputBridge::handleWheelEvent):
(WebCore::UserInputBridge::scrollRecursively):
(WebCore::UserInputBridge::logicalScrollRecursively):
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@166880
268f45cc-cd09-0410-ab3c-
d52691b4dbfc
+2014-04-07 Brian J. Burg <burg@cs.washington.edu>
+
+ Web Replay: detect possible replay divergence from unexpected DOM event dispatches
+ https://bugs.webkit.org/show_bug.cgi?id=131193
+
+ Reviewed by Andreas Kling.
+
+ Add assertions to catch potential nondeterministic behavior.
+
+ The assertion added by this patch catches dispatched DOM events
+ that are triggered by nondeterministic event loop cycles. If we
+ did not capture an event loop input in the current event loop
+ cycle nor are we manually simulating an event loop input during
+ playback, then DOM events fired during the unordered cycle could
+ run JavaScript and diverge the execution.
+
+ During playback, we can assert that EventLoopInputDispatcher is dispatching
+ when a DOM event is be dispatched to a document that is being replayed.
+
+ During capturing, event loop inputs are captured rather than
+ dispatched, so we add some accounting to track what caused a DOM
+ event. To approximate the extent of computation triggered by an
+ event loop input, we add RAII helpers to call sites where event
+ loop inputs are captured.
+
+ The assertions are disabled by default until the most common
+ sources of nondeterminism are handled and playback errors are
+ gracefully surfaced to the user. <https://webkit.org/b/131279>
+
+ No new tests. This patch adds extra assertions for debugging purposes.
+
+ * WebCore.xcodeproj/project.pbxproj:
+ * inspector/InspectorInstrumentation.cpp: Notify ReplayAgent of dispatched DOM event.
+ (WebCore::InspectorInstrumentation::willDispatchEventImpl):
+ (WebCore::InspectorInstrumentation::willDispatchEventOnWindowImpl):
+ * inspector/InspectorReplayAgent.cpp: Forward dispatched DOM events to ReplayController.
+ (WebCore::InspectorReplayAgent::willDispatchEvent): Added.
+ * inspector/InspectorReplayAgent.h:
+ * replay/CapturingInputCursor.cpp:
+ (WebCore::CapturingInputCursor::CapturingInputCursor):
+ (WebCore::CapturingInputCursor::setWithinEventLoopInputExtent): Added.
+ * replay/CapturingInputCursor.h:
+ * replay/EventLoopInput.cpp: Added.
+ (WebCore::EventLoopInputExtent::EventLoopInputExtent): Added.
+ (WebCore::EventLoopInputExtent::~EventLoopInputExtent): Added.
+ * replay/EventLoopInput.h:
+ * replay/EventLoopInputDispatcher.h:
+ (WebCore::EventLoopInputDispatcher::isDispatching): Add a getter.
+ * replay/ReplayController.cpp:
+ (WebCore::logDispatchedDOMEvent): Added. This is useful for understanding script-visible events.
+ (WebCore::ReplayController::willDispatchEvent): Added.
+ * replay/ReplayController.h:
+ * replay/UserInputBridge.cpp: Add extent helpers to call sites that capture inputs.
+ (WebCore::UserInputBridge::handleMousePressEvent):
+ (WebCore::UserInputBridge::handleMouseReleaseEvent):
+ (WebCore::UserInputBridge::handleMouseMoveEvent):
+ (WebCore::UserInputBridge::handleMouseMoveOnScrollbarEvent):
+ (WebCore::UserInputBridge::handleKeyEvent):
+ (WebCore::UserInputBridge::handleWheelEvent):
+ (WebCore::UserInputBridge::scrollRecursively):
+ (WebCore::UserInputBridge::logicalScrollRecursively):
+
2014-04-07 Timothy Hatcher <timothy@apple.com>
Remove copy of combine-javascript-resources.pl that isn't used anymore
C3CF17A515B0063F00276D39 /* IdTargetObserver.h in Headers */ = {isa = PBXBuildFile; fileRef = C3CF17A115B0063F00276D39 /* IdTargetObserver.h */; settings = {ATTRIBUTES = (Private, ); }; };
C3CF17A615B0063F00276D39 /* IdTargetObserverRegistry.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C3CF17A215B0063F00276D39 /* IdTargetObserverRegistry.cpp */; };
C3CF17A715B0063F00276D39 /* IdTargetObserverRegistry.h in Headers */ = {isa = PBXBuildFile; fileRef = C3CF17A315B0063F00276D39 /* IdTargetObserverRegistry.h */; settings = {ATTRIBUTES = (Private, ); }; };
+ C400D10918F1C8F60090D863 /* EventLoopInput.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C400D10818F1C8F60090D863 /* EventLoopInput.cpp */; };
C4CD629A18383766007EBAF1 /* FrameSnapshotting.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C4CD629818383766007EBAF1 /* FrameSnapshotting.cpp */; };
C4CD629B18383766007EBAF1 /* FrameSnapshotting.h in Headers */ = {isa = PBXBuildFile; fileRef = C4CD629918383766007EBAF1 /* FrameSnapshotting.h */; settings = {ATTRIBUTES = (Private, ); }; };
C50B561612119D23008B46E0 /* GroupSettings.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C50B561412119D23008B46E0 /* GroupSettings.cpp */; };
C3CF17A215B0063F00276D39 /* IdTargetObserverRegistry.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = IdTargetObserverRegistry.cpp; sourceTree = "<group>"; };
C3CF17A315B0063F00276D39 /* IdTargetObserverRegistry.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IdTargetObserverRegistry.h; sourceTree = "<group>"; };
C3E61C653A64807A83E76FB8 /* MathMLMencloseElement.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MathMLMencloseElement.cpp; sourceTree = "<group>"; };
+ C400D10818F1C8F60090D863 /* EventLoopInput.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = EventLoopInput.cpp; sourceTree = "<group>"; };
C4CD629818383766007EBAF1 /* FrameSnapshotting.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = FrameSnapshotting.cpp; sourceTree = "<group>"; };
C4CD629918383766007EBAF1 /* FrameSnapshotting.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FrameSnapshotting.h; sourceTree = "<group>"; };
C50B561412119D23008B46E0 /* GroupSettings.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = GroupSettings.cpp; sourceTree = "<group>"; };
99CC0B3818BE9849006CEBCC /* AllReplayInputs.h */,
99CC0B3918BE9849006CEBCC /* CapturingInputCursor.cpp */,
99CC0B3A18BE9849006CEBCC /* CapturingInputCursor.h */,
+ C400D10818F1C8F60090D863 /* EventLoopInput.cpp */,
99E45A1618A063BE0026D88F /* EventLoopInput.h */,
99CC0B3B18BE9849006CEBCC /* EventLoopInputDispatcher.cpp */,
99CC0B3C18BE9849006CEBCC /* EventLoopInputDispatcher.h */,
FD315FF812B0267600C1A359 /* AudioBuffer.cpp in Sources */,
FD315FFB12B0267600C1A359 /* AudioBufferSourceNode.cpp in Sources */,
FD31607B12B026F700C1A359 /* AudioBus.cpp in Sources */,
+ C400D10918F1C8F60090D863 /* EventLoopInput.cpp in Sources */,
FD3160BB12B0272A00C1A359 /* AudioBusMac.mm in Sources */,
FD31607D12B026F700C1A359 /* AudioChannel.cpp in Sources */,
FD31600412B0267600C1A359 /* AudioContext.cpp in Sources */,
timelineAgent->willDispatchEvent(event, document->frame());
timelineAgentId = timelineAgent->id();
}
+#if ENABLE(WEB_REPLAY)
+ if (InspectorReplayAgent* replayAgent = instrumentingAgents->inspectorReplayAgent())
+ replayAgent->willDispatchEvent(event, document->frame());
+#endif
return InspectorInstrumentationCookie(instrumentingAgents, timelineAgentId);
}
timelineAgent->willDispatchEvent(event, window ? window->frame() : nullptr);
timelineAgentId = timelineAgent->id();
}
+#if ENABLE(WEB_REPLAY)
+ if (InspectorReplayAgent* replayAgent = instrumentingAgents->inspectorReplayAgent())
+ replayAgent->willDispatchEvent(event, window ? window->frame() : nullptr);
+#endif
return InspectorInstrumentationCookie(instrumentingAgents, timelineAgentId);
}
m_page.replayController().frameDetached(frame);
}
+void InspectorReplayAgent::willDispatchEvent(const Event& event, Frame* frame)
+{
+ if (sessionState() != SessionState::Inactive)
+ m_page.replayController().willDispatchEvent(event, frame);
+}
+
void InspectorReplayAgent::sessionCreated(PassRefPtr<ReplaySession> prpSession)
{
RefPtr<ReplaySession> session = prpSession;
namespace WebCore {
class DocumentLoader;
+class Event;
class Frame;
class InspectorPageAgent;
class InstrumentingAgents;
// Callbacks from InspectorInstrumentation.
void frameNavigated(DocumentLoader*);
void frameDetached(Frame*);
+ void willDispatchEvent(const Event&, Frame*);
// Notifications from ReplayController.
void sessionCreated(PassRefPtr<ReplaySession>);
CapturingInputCursor::CapturingInputCursor(SegmentedInputStorage& storage)
: m_storage(storage)
+ , m_withinEventLoopInputExtent(false)
{
LOG(WebReplay, "%-30sCreated capture cursor=%p.\n", "[ReplayController]", this);
}
return nullptr;
}
+void CapturingInputCursor::setWithinEventLoopInputExtent(bool withinEventLoopInputExtent)
+{
+ // We cannot enter more than one extent at a time, since they represent a single run loop.
+ ASSERT(withinEventLoopInputExtent != m_withinEventLoopInputExtent);
+ m_withinEventLoopInputExtent = withinEventLoopInputExtent;
+}
+
}; // namespace WebCore
#endif // ENABLE(WEB_REPLAY)
namespace WebCore {
+class EventLoopInputExtent;
class SegmentedInputStorage;
class CapturingInputCursor final : public InputCursor {
virtual bool isCapturing() const override { return true; }
virtual bool isReplaying() const override { return false; }
+ void setWithinEventLoopInputExtent(bool);
+ bool withinEventLoopInputExtent() const { return m_withinEventLoopInputExtent; }
+
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;
+ bool m_withinEventLoopInputExtent;
};
} // namespace WebCore
--- /dev/null
+/*
+ * Copyright (C) 2014 University of Washington. 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 APPLE AND ITS 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 APPLE OR ITS 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 "EventLoopInput.h"
+
+#if ENABLE(WEB_REPLAY)
+
+#include "CapturingInputCursor.h"
+
+namespace WebCore {
+
+EventLoopInputExtent::EventLoopInputExtent(InputCursor& cursor)
+ : m_cursor(cursor)
+{
+ if (!m_cursor.isCapturing())
+ return;
+
+ static_cast<CapturingInputCursor&>(cursor).setWithinEventLoopInputExtent(true);
+}
+
+EventLoopInputExtent::~EventLoopInputExtent()
+{
+ if (!m_cursor.isCapturing())
+ return;
+
+ static_cast<CapturingInputCursor&>(m_cursor).setWithinEventLoopInputExtent(false);
+}
+
+}; // namespace WebCore
+
+#endif // ENABLE(WEB_REPLAY)
#include <replay/NondeterministicInput.h>
#include <wtf/CurrentTime.h>
+namespace JSC {
+class InputCursor;
+};
+
namespace WebCore {
class ReplayController;
+// This is an RAII helper used during capturing which sets a flag on the input cursor
+// to track the dynamic extent of a captured event loop input. This extent approximates
+// the interval in which EventLoopInputDispatcher::dispatching() is true.
+class EventLoopInputExtent {
+ WTF_MAKE_NONCOPYABLE(EventLoopInputExtent);
+public:
+ EventLoopInputExtent(JSC::InputCursor&);
+ ~EventLoopInputExtent();
+private:
+ JSC::InputCursor& m_cursor;
+};
+
class EventLoopInputBase : public NondeterministicInputBase {
public:
EventLoopInputBase()
DispatchSpeed dispatchSpeed() const { return m_speed; }
bool isRunning() const { return m_running; }
+ bool isDispatching() const { return m_dispatching; }
private:
void dispatchInputSoon();
void dispatchInput();
#include "Frame.h"
#include "FrameTree.h"
#include "InspectorInstrumentation.h"
+#include "Location.h"
#include "Logging.h"
#include "MainFrame.h"
#include "Page.h"
#include "ReplaySessionSegment.h"
#include "ReplayingInputCursor.h"
#include "ScriptController.h"
+#include "SerializationMethods.h"
#include "Settings.h"
#include "UserInputBridge.h"
#include "WebReplayInputs.h"
namespace WebCore {
+static void logDispatchedDOMEvent(const Event& event, bool eventIsUnrelated)
+{
+#if !LOG_DISABLED
+ EventTarget* target = event.target();
+ if (!target)
+ return;
+
+ // A DOM event is unrelated if it is being dispatched to a document that is neither capturing nor replaying.
+ if (Node* node = target->toNode()) {
+ LOG(WebReplay, "%-20s --->%s DOM event: type=%s, target=%lu/node[%p] %s\n", "ReplayEvents",
+ (eventIsUnrelated) ? "Unrelated" : "Dispatching",
+ event.type().string().utf8().data(),
+ frameIndexFromDocument((node->inDocument()) ? &node->document() : node->ownerDocument()),
+ node,
+ node->nodeName().utf8().data());
+ } else if (DOMWindow* window = target->toDOMWindow()) {
+ LOG(WebReplay, "%-20s --->%s DOM event: type=%s, target=%lu/window[%p] %s\n", "ReplayEvents",
+ (eventIsUnrelated) ? "Unrelated" : "Dispatching",
+ event.type().string().utf8().data(),
+ frameIndexFromDocument(window->document()),
+ window,
+ window->location()->href().utf8().data());
+ }
+#else
+ UNUSED_PARAM(event);
+ UNUSED_PARAM(eventIsUnrelated);
+#endif
+}
+
ReplayController::ReplayController(Page& page)
: m_page(page)
, m_loadedSegment(nullptr)
// input has been dispatched. So, nothing needs to be done here.
}
+void ReplayController::willDispatchEvent(const Event& event, Frame* frame)
+{
+ EventTarget* target = event.target();
+ if (!target && !frame)
+ return;
+
+ Document* document = frame ? frame->document() : nullptr;
+ // Fetch the document from the event target, because the target could be detached.
+ if (Node* node = target->toNode())
+ document = node->inDocument() ? &node->document() : node->ownerDocument();
+ else if (DOMWindow* window = target->toDOMWindow())
+ document = window->document();
+
+ ASSERT(document);
+
+ InputCursor& cursor = document->inputCursor();
+ bool eventIsUnrelated = !cursor.isCapturing() && !cursor.isReplaying();
+ logDispatchedDOMEvent(event, eventIsUnrelated);
+
+#if ENABLE_AGGRESSIVE_DETERMINISM_CHECKS
+ // To ensure deterministic JS execution, all DOM events must be dispatched deterministically.
+ // If these assertions fail, then this DOM event is being dispatched by a nondeterministic EventLoop
+ // cycle, and may cause program execution to diverge if any JS code runs because of the DOM event.
+ if (cursor.isCapturing())
+ ASSERT(static_cast<CapturingInputCursor&>(cursor).withinEventLoopInputExtent());
+ else if (cursor.isReplaying())
+ ASSERT(dispatcher().isDispatching());
+#endif
+}
+
PassRefPtr<ReplaySession> ReplayController::loadedSession() const
{
return m_loadedSession;
#include <wtf/Noncopyable.h>
#include <wtf/Vector.h>
+// Determinism assertions are guarded by this macro. When a user-facing error reporting and
+// recovery mechanism is implemented, this guard can be removed. <https://webkit.org/b/131279>
+#define ENABLE_AGGRESSIVE_DETERMINISM_CHECKS 0
+
namespace JSC {
class InputCursor;
}
// InspectorReplayAgent notifications.
void frameNavigated(DocumentLoader*);
void frameDetached(Frame*);
+ void willDispatchEvent(const Event&, Frame*);
Page& page() const { return m_page; }
SessionState sessionState() const { return m_sessionState; }
#if ENABLE(WEB_REPLAY)
EARLY_RETURN_IF_SHOULD_IGNORE_INPUT;
- if (activeCursor().isCapturing()) {
+ InputCursor& cursor = activeCursor();
+ if (cursor.isCapturing()) {
std::unique_ptr<PlatformMouseEvent> ownedEvent = std::make_unique<PlatformMouseEvent>(mouseEvent);
- activeCursor().appendInput<HandleMousePress>(std::move(ownedEvent));
+ cursor.appendInput<HandleMousePress>(std::move(ownedEvent));
}
+ EventLoopInputExtent extent(cursor);
#else
UNUSED_PARAM(inputSource);
#endif
#if ENABLE(WEB_REPLAY)
EARLY_RETURN_IF_SHOULD_IGNORE_INPUT;
- if (activeCursor().isCapturing()) {
+ InputCursor& cursor = activeCursor();
+ if (cursor.isCapturing()) {
std::unique_ptr<PlatformMouseEvent> ownedEvent = std::make_unique<PlatformMouseEvent>(mouseEvent);
- activeCursor().appendInput<HandleMouseRelease>(std::move(ownedEvent));
+ cursor.appendInput<HandleMouseRelease>(std::move(ownedEvent));
}
+ EventLoopInputExtent extent(cursor);
#else
UNUSED_PARAM(inputSource);
#endif
#if ENABLE(WEB_REPLAY)
EARLY_RETURN_IF_SHOULD_IGNORE_INPUT;
- if (activeCursor().isCapturing()) {
+ InputCursor& cursor = activeCursor();
+ if (cursor.isCapturing()) {
std::unique_ptr<PlatformMouseEvent> ownedEvent = std::make_unique<PlatformMouseEvent>(mouseEvent);
- activeCursor().appendInput<HandleMouseMove>(std::move(ownedEvent), false);
+ cursor.appendInput<HandleMouseMove>(std::move(ownedEvent), false);
}
+ EventLoopInputExtent extent(cursor);
#else
UNUSED_PARAM(inputSource);
#endif
#if ENABLE(WEB_REPLAY)
EARLY_RETURN_IF_SHOULD_IGNORE_INPUT;
- if (activeCursor().isCapturing()) {
+ InputCursor& cursor = activeCursor();
+ if (cursor.isCapturing()) {
std::unique_ptr<PlatformMouseEvent> ownedEvent = std::make_unique<PlatformMouseEvent>(mouseEvent);
- activeCursor().appendInput<HandleMouseMove>(std::move(ownedEvent), true);
+ cursor.appendInput<HandleMouseMove>(std::move(ownedEvent), true);
}
+ EventLoopInputExtent extent(cursor);
#else
UNUSED_PARAM(inputSource);
#endif
#if ENABLE(WEB_REPLAY)
EARLY_RETURN_IF_SHOULD_IGNORE_INPUT;
- if (activeCursor().isCapturing()) {
+ InputCursor& cursor = activeCursor();
+ if (cursor.isCapturing()) {
std::unique_ptr<PlatformKeyboardEvent> ownedEvent = std::make_unique<PlatformKeyboardEvent>(keyEvent);
- activeCursor().appendInput<HandleKeyPress>(std::move(ownedEvent));
+ cursor.appendInput<HandleKeyPress>(std::move(ownedEvent));
}
+ EventLoopInputExtent extent(cursor);
#else
UNUSED_PARAM(inputSource);
#endif
#if ENABLE(WEB_REPLAY)
EARLY_RETURN_IF_SHOULD_IGNORE_INPUT;
- if (activeCursor().isCapturing()) {
+ InputCursor& cursor = activeCursor();
+ if (cursor.isCapturing()) {
std::unique_ptr<PlatformWheelEvent> ownedEvent = std::make_unique<PlatformWheelEvent>(wheelEvent);
- activeCursor().appendInput<HandleWheelEvent>(std::move(ownedEvent));
+ cursor.appendInput<HandleWheelEvent>(std::move(ownedEvent));
}
+ EventLoopInputExtent extent(cursor);
#else
UNUSED_PARAM(inputSource);
#endif
#if ENABLE(WEB_REPLAY)
EARLY_RETURN_IF_SHOULD_IGNORE_INPUT;
- if (activeCursor().isCapturing())
- activeCursor().appendInput<ScrollPage>(direction, granularity);
+ InputCursor& cursor = activeCursor();
+ if (cursor.isCapturing())
+ cursor.appendInput<ScrollPage>(direction, granularity);
+
+ EventLoopInputExtent extent(cursor);
#else
UNUSED_PARAM(inputSource);
#endif
#if ENABLE(WEB_REPLAY)
EARLY_RETURN_IF_SHOULD_IGNORE_INPUT;
- if (activeCursor().isCapturing())
- activeCursor().appendInput<LogicalScrollPage>(direction, granularity);
+ InputCursor& cursor = activeCursor();
+ if (cursor.isCapturing())
+ cursor.appendInput<LogicalScrollPage>(direction, granularity);
+
+ EventLoopInputExtent extent(cursor);
#else
UNUSED_PARAM(inputSource);
#endif