<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[166880] trunk/Source/WebCore</title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://trac.webkit.org/projects/webkit/changeset/166880">166880</a></dd>
<dt>Author</dt> <dd>burg@cs.washington.edu</dd>
<dt>Date</dt> <dd>2014-04-07 12:58:07 -0700 (Mon, 07 Apr 2014)</dd>
</dl>

<h3>Log Message</h3>
<pre>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. &lt;https://webkit.org/b/131279&gt;

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):</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkSourceWebCoreChangeLog">trunk/Source/WebCore/ChangeLog</a></li>
<li><a href="#trunkSourceWebCoreWebCorexcodeprojprojectpbxproj">trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj</a></li>
<li><a href="#trunkSourceWebCoreinspectorInspectorInstrumentationcpp">trunk/Source/WebCore/inspector/InspectorInstrumentation.cpp</a></li>
<li><a href="#trunkSourceWebCoreinspectorInspectorReplayAgentcpp">trunk/Source/WebCore/inspector/InspectorReplayAgent.cpp</a></li>
<li><a href="#trunkSourceWebCoreinspectorInspectorReplayAgenth">trunk/Source/WebCore/inspector/InspectorReplayAgent.h</a></li>
<li><a href="#trunkSourceWebCorereplayCapturingInputCursorcpp">trunk/Source/WebCore/replay/CapturingInputCursor.cpp</a></li>
<li><a href="#trunkSourceWebCorereplayCapturingInputCursorh">trunk/Source/WebCore/replay/CapturingInputCursor.h</a></li>
<li><a href="#trunkSourceWebCorereplayEventLoopInputh">trunk/Source/WebCore/replay/EventLoopInput.h</a></li>
<li><a href="#trunkSourceWebCorereplayEventLoopInputDispatcherh">trunk/Source/WebCore/replay/EventLoopInputDispatcher.h</a></li>
<li><a href="#trunkSourceWebCorereplayReplayControllercpp">trunk/Source/WebCore/replay/ReplayController.cpp</a></li>
<li><a href="#trunkSourceWebCorereplayReplayControllerh">trunk/Source/WebCore/replay/ReplayController.h</a></li>
<li><a href="#trunkSourceWebCorereplayUserInputBridgecpp">trunk/Source/WebCore/replay/UserInputBridge.cpp</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#trunkSourceWebCorereplayEventLoopInputcpp">trunk/Source/WebCore/replay/EventLoopInput.cpp</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkSourceWebCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/ChangeLog (166879 => 166880)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/ChangeLog        2014-04-07 19:44:06 UTC (rev 166879)
+++ trunk/Source/WebCore/ChangeLog        2014-04-07 19:58:07 UTC (rev 166880)
</span><span class="lines">@@ -1,3 +1,65 @@
</span><ins>+2014-04-07  Brian J. Burg  &lt;burg@cs.washington.edu&gt;
+
+        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. &lt;https://webkit.org/b/131279&gt;
+
+        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):
+
</ins><span class="cx"> 2014-04-07  Timothy Hatcher  &lt;timothy@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Remove copy of combine-javascript-resources.pl that isn't used anymore
</span></span></pre></div>
<a id="trunkSourceWebCoreWebCorexcodeprojprojectpbxproj"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj (166879 => 166880)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj        2014-04-07 19:44:06 UTC (rev 166879)
+++ trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj        2014-04-07 19:58:07 UTC (rev 166880)
</span><span class="lines">@@ -5440,6 +5440,7 @@
</span><span class="cx">                 C3CF17A515B0063F00276D39 /* IdTargetObserver.h in Headers */ = {isa = PBXBuildFile; fileRef = C3CF17A115B0063F00276D39 /* IdTargetObserver.h */; settings = {ATTRIBUTES = (Private, ); }; };
</span><span class="cx">                 C3CF17A615B0063F00276D39 /* IdTargetObserverRegistry.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C3CF17A215B0063F00276D39 /* IdTargetObserverRegistry.cpp */; };
</span><span class="cx">                 C3CF17A715B0063F00276D39 /* IdTargetObserverRegistry.h in Headers */ = {isa = PBXBuildFile; fileRef = C3CF17A315B0063F00276D39 /* IdTargetObserverRegistry.h */; settings = {ATTRIBUTES = (Private, ); }; };
</span><ins>+                C400D10918F1C8F60090D863 /* EventLoopInput.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C400D10818F1C8F60090D863 /* EventLoopInput.cpp */; };
</ins><span class="cx">                 C4CD629A18383766007EBAF1 /* FrameSnapshotting.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C4CD629818383766007EBAF1 /* FrameSnapshotting.cpp */; };
</span><span class="cx">                 C4CD629B18383766007EBAF1 /* FrameSnapshotting.h in Headers */ = {isa = PBXBuildFile; fileRef = C4CD629918383766007EBAF1 /* FrameSnapshotting.h */; settings = {ATTRIBUTES = (Private, ); }; };
</span><span class="cx">                 C50B561612119D23008B46E0 /* GroupSettings.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C50B561412119D23008B46E0 /* GroupSettings.cpp */; };
</span><span class="lines">@@ -12742,6 +12743,7 @@
</span><span class="cx">                 C3CF17A215B0063F00276D39 /* IdTargetObserverRegistry.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = IdTargetObserverRegistry.cpp; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 C3CF17A315B0063F00276D39 /* IdTargetObserverRegistry.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IdTargetObserverRegistry.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 C3E61C653A64807A83E76FB8 /* MathMLMencloseElement.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MathMLMencloseElement.cpp; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><ins>+                C400D10818F1C8F60090D863 /* EventLoopInput.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = EventLoopInput.cpp; sourceTree = &quot;&lt;group&gt;&quot;; };
</ins><span class="cx">                 C4CD629818383766007EBAF1 /* FrameSnapshotting.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = FrameSnapshotting.cpp; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 C4CD629918383766007EBAF1 /* FrameSnapshotting.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FrameSnapshotting.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 C50B561412119D23008B46E0 /* GroupSettings.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = GroupSettings.cpp; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="lines">@@ -18041,6 +18043,7 @@
</span><span class="cx">                                 99CC0B3818BE9849006CEBCC /* AllReplayInputs.h */,
</span><span class="cx">                                 99CC0B3918BE9849006CEBCC /* CapturingInputCursor.cpp */,
</span><span class="cx">                                 99CC0B3A18BE9849006CEBCC /* CapturingInputCursor.h */,
</span><ins>+                                C400D10818F1C8F60090D863 /* EventLoopInput.cpp */,
</ins><span class="cx">                                 99E45A1618A063BE0026D88F /* EventLoopInput.h */,
</span><span class="cx">                                 99CC0B3B18BE9849006CEBCC /* EventLoopInputDispatcher.cpp */,
</span><span class="cx">                                 99CC0B3C18BE9849006CEBCC /* EventLoopInputDispatcher.h */,
</span><span class="lines">@@ -26648,6 +26651,7 @@
</span><span class="cx">                                 FD315FF812B0267600C1A359 /* AudioBuffer.cpp in Sources */,
</span><span class="cx">                                 FD315FFB12B0267600C1A359 /* AudioBufferSourceNode.cpp in Sources */,
</span><span class="cx">                                 FD31607B12B026F700C1A359 /* AudioBus.cpp in Sources */,
</span><ins>+                                C400D10918F1C8F60090D863 /* EventLoopInput.cpp in Sources */,
</ins><span class="cx">                                 FD3160BB12B0272A00C1A359 /* AudioBusMac.mm in Sources */,
</span><span class="cx">                                 FD31607D12B026F700C1A359 /* AudioChannel.cpp in Sources */,
</span><span class="cx">                                 FD31600412B0267600C1A359 /* AudioContext.cpp in Sources */,
</span></span></pre></div>
<a id="trunkSourceWebCoreinspectorInspectorInstrumentationcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/inspector/InspectorInstrumentation.cpp (166879 => 166880)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/inspector/InspectorInstrumentation.cpp        2014-04-07 19:44:06 UTC (rev 166879)
+++ trunk/Source/WebCore/inspector/InspectorInstrumentation.cpp        2014-04-07 19:58:07 UTC (rev 166880)
</span><span class="lines">@@ -350,6 +350,10 @@
</span><span class="cx">         timelineAgent-&gt;willDispatchEvent(event, document-&gt;frame());
</span><span class="cx">         timelineAgentId = timelineAgent-&gt;id();
</span><span class="cx">     }
</span><ins>+#if ENABLE(WEB_REPLAY)
+    if (InspectorReplayAgent* replayAgent = instrumentingAgents-&gt;inspectorReplayAgent())
+        replayAgent-&gt;willDispatchEvent(event, document-&gt;frame());
+#endif
</ins><span class="cx">     return InspectorInstrumentationCookie(instrumentingAgents, timelineAgentId);
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -378,6 +382,10 @@
</span><span class="cx">         timelineAgent-&gt;willDispatchEvent(event, window ? window-&gt;frame() : nullptr);
</span><span class="cx">         timelineAgentId = timelineAgent-&gt;id();
</span><span class="cx">     }
</span><ins>+#if ENABLE(WEB_REPLAY)
+    if (InspectorReplayAgent* replayAgent = instrumentingAgents-&gt;inspectorReplayAgent())
+        replayAgent-&gt;willDispatchEvent(event, window ? window-&gt;frame() : nullptr);
+#endif
</ins><span class="cx">     return InspectorInstrumentationCookie(instrumentingAgents, timelineAgentId);
</span><span class="cx"> }
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceWebCoreinspectorInspectorReplayAgentcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/inspector/InspectorReplayAgent.cpp (166879 => 166880)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/inspector/InspectorReplayAgent.cpp        2014-04-07 19:44:06 UTC (rev 166879)
+++ trunk/Source/WebCore/inspector/InspectorReplayAgent.cpp        2014-04-07 19:58:07 UTC (rev 166880)
</span><span class="lines">@@ -198,6 +198,12 @@
</span><span class="cx">         m_page.replayController().frameDetached(frame);
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+void InspectorReplayAgent::willDispatchEvent(const Event&amp; event, Frame* frame)
+{
+    if (sessionState() != SessionState::Inactive)
+        m_page.replayController().willDispatchEvent(event, frame);
+}
+
</ins><span class="cx"> void InspectorReplayAgent::sessionCreated(PassRefPtr&lt;ReplaySession&gt; prpSession)
</span><span class="cx"> {
</span><span class="cx">     RefPtr&lt;ReplaySession&gt; session = prpSession;
</span></span></pre></div>
<a id="trunkSourceWebCoreinspectorInspectorReplayAgenth"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/inspector/InspectorReplayAgent.h (166879 => 166880)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/inspector/InspectorReplayAgent.h        2014-04-07 19:44:06 UTC (rev 166879)
+++ trunk/Source/WebCore/inspector/InspectorReplayAgent.h        2014-04-07 19:58:07 UTC (rev 166880)
</span><span class="lines">@@ -40,6 +40,7 @@
</span><span class="cx"> namespace WebCore {
</span><span class="cx"> 
</span><span class="cx"> class DocumentLoader;
</span><ins>+class Event;
</ins><span class="cx"> class Frame;
</span><span class="cx"> class InspectorPageAgent;
</span><span class="cx"> class InstrumentingAgents;
</span><span class="lines">@@ -69,6 +70,7 @@
</span><span class="cx">     // Callbacks from InspectorInstrumentation.
</span><span class="cx">     void frameNavigated(DocumentLoader*);
</span><span class="cx">     void frameDetached(Frame*);
</span><ins>+    void willDispatchEvent(const Event&amp;, Frame*);
</ins><span class="cx"> 
</span><span class="cx">     // Notifications from ReplayController.
</span><span class="cx">     void sessionCreated(PassRefPtr&lt;ReplaySession&gt;);
</span></span></pre></div>
<a id="trunkSourceWebCorereplayCapturingInputCursorcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/replay/CapturingInputCursor.cpp (166879 => 166880)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/replay/CapturingInputCursor.cpp        2014-04-07 19:44:06 UTC (rev 166879)
+++ trunk/Source/WebCore/replay/CapturingInputCursor.cpp        2014-04-07 19:58:07 UTC (rev 166880)
</span><span class="lines">@@ -37,6 +37,7 @@
</span><span class="cx"> 
</span><span class="cx"> CapturingInputCursor::CapturingInputCursor(SegmentedInputStorage&amp; storage)
</span><span class="cx">     : m_storage(storage)
</span><ins>+    , m_withinEventLoopInputExtent(false)
</ins><span class="cx"> {
</span><span class="cx">     LOG(WebReplay, &quot;%-30sCreated capture cursor=%p.\n&quot;, &quot;[ReplayController]&quot;, this);
</span><span class="cx"> }
</span><span class="lines">@@ -71,6 +72,13 @@
</span><span class="cx">     return nullptr;
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+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;
+}
+
</ins><span class="cx"> }; // namespace WebCore
</span><span class="cx"> 
</span><span class="cx"> #endif // ENABLE(WEB_REPLAY)
</span></span></pre></div>
<a id="trunkSourceWebCorereplayCapturingInputCursorh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/replay/CapturingInputCursor.h (166879 => 166880)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/replay/CapturingInputCursor.h        2014-04-07 19:44:06 UTC (rev 166879)
+++ trunk/Source/WebCore/replay/CapturingInputCursor.h        2014-04-07 19:58:07 UTC (rev 166880)
</span><span class="lines">@@ -35,6 +35,7 @@
</span><span class="cx"> 
</span><span class="cx"> namespace WebCore {
</span><span class="cx"> 
</span><ins>+class EventLoopInputExtent;
</ins><span class="cx"> class SegmentedInputStorage;
</span><span class="cx"> 
</span><span class="cx"> class CapturingInputCursor final : public InputCursor {
</span><span class="lines">@@ -46,14 +47,19 @@
</span><span class="cx">     virtual bool isCapturing() const override { return true; }
</span><span class="cx">     virtual bool isReplaying() const override { return false; }
</span><span class="cx"> 
</span><ins>+    void setWithinEventLoopInputExtent(bool);
+    bool withinEventLoopInputExtent() const { return m_withinEventLoopInputExtent; }
+
</ins><span class="cx">     virtual NondeterministicInputBase* uncheckedLoadInput(InputQueue) override;
</span><span class="cx">     virtual void storeInput(std::unique_ptr&lt;NondeterministicInputBase&gt;) override;
</span><span class="cx"> protected:
</span><span class="cx">     virtual NondeterministicInputBase* loadInput(InputQueue, const AtomicString&amp; type) override;
</span><ins>+
</ins><span class="cx"> private:
</span><span class="cx">     explicit CapturingInputCursor(SegmentedInputStorage&amp;);
</span><span class="cx"> 
</span><span class="cx">     SegmentedInputStorage&amp; m_storage;
</span><ins>+    bool m_withinEventLoopInputExtent;
</ins><span class="cx"> };
</span><span class="cx"> 
</span><span class="cx"> } // namespace WebCore
</span></span></pre></div>
<a id="trunkSourceWebCorereplayEventLoopInputcpp"></a>
<div class="addfile"><h4>Added: trunk/Source/WebCore/replay/EventLoopInput.cpp (0 => 166880)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/replay/EventLoopInput.cpp                                (rev 0)
+++ trunk/Source/WebCore/replay/EventLoopInput.cpp        2014-04-07 19:58:07 UTC (rev 166880)
</span><span class="lines">@@ -0,0 +1,54 @@
</span><ins>+/*
+ * 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 &quot;AS IS&quot; 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 &quot;config.h&quot;
+#include &quot;EventLoopInput.h&quot;
+
+#if ENABLE(WEB_REPLAY)
+
+#include &quot;CapturingInputCursor.h&quot;
+
+namespace WebCore {
+
+EventLoopInputExtent::EventLoopInputExtent(InputCursor&amp; cursor)
+    : m_cursor(cursor)
+{
+    if (!m_cursor.isCapturing())
+        return;
+
+    static_cast&lt;CapturingInputCursor&amp;&gt;(cursor).setWithinEventLoopInputExtent(true);
+}
+
+EventLoopInputExtent::~EventLoopInputExtent()
+{
+    if (!m_cursor.isCapturing())
+        return;
+
+    static_cast&lt;CapturingInputCursor&amp;&gt;(m_cursor).setWithinEventLoopInputExtent(false);
+}
+
+}; // namespace WebCore
+
+#endif // ENABLE(WEB_REPLAY)
</ins></span></pre></div>
<a id="trunkSourceWebCorereplayEventLoopInputh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/replay/EventLoopInput.h (166879 => 166880)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/replay/EventLoopInput.h        2014-04-07 19:44:06 UTC (rev 166879)
+++ trunk/Source/WebCore/replay/EventLoopInput.h        2014-04-07 19:58:07 UTC (rev 166880)
</span><span class="lines">@@ -33,10 +33,26 @@
</span><span class="cx"> #include &lt;replay/NondeterministicInput.h&gt;
</span><span class="cx"> #include &lt;wtf/CurrentTime.h&gt;
</span><span class="cx"> 
</span><ins>+namespace JSC {
+class InputCursor;
+};
+
</ins><span class="cx"> namespace WebCore {
</span><span class="cx"> 
</span><span class="cx"> class ReplayController;
</span><span class="cx"> 
</span><ins>+// 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&amp;);
+    ~EventLoopInputExtent();
+private:
+    JSC::InputCursor&amp; m_cursor;
+};
+
</ins><span class="cx"> class EventLoopInputBase : public NondeterministicInputBase {
</span><span class="cx"> public:
</span><span class="cx">     EventLoopInputBase()
</span></span></pre></div>
<a id="trunkSourceWebCorereplayEventLoopInputDispatcherh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/replay/EventLoopInputDispatcher.h (166879 => 166880)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/replay/EventLoopInputDispatcher.h        2014-04-07 19:44:06 UTC (rev 166879)
+++ trunk/Source/WebCore/replay/EventLoopInputDispatcher.h        2014-04-07 19:58:07 UTC (rev 166880)
</span><span class="lines">@@ -68,6 +68,7 @@
</span><span class="cx">     DispatchSpeed dispatchSpeed() const { return m_speed; }
</span><span class="cx"> 
</span><span class="cx">     bool isRunning() const { return m_running; }
</span><ins>+    bool isDispatching() const { return m_dispatching; }
</ins><span class="cx"> private:
</span><span class="cx">     void dispatchInputSoon();
</span><span class="cx">     void dispatchInput();
</span></span></pre></div>
<a id="trunkSourceWebCorereplayReplayControllercpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/replay/ReplayController.cpp (166879 => 166880)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/replay/ReplayController.cpp        2014-04-07 19:44:06 UTC (rev 166879)
+++ trunk/Source/WebCore/replay/ReplayController.cpp        2014-04-07 19:58:07 UTC (rev 166880)
</span><span class="lines">@@ -37,6 +37,7 @@
</span><span class="cx"> #include &quot;Frame.h&quot;
</span><span class="cx"> #include &quot;FrameTree.h&quot;
</span><span class="cx"> #include &quot;InspectorInstrumentation.h&quot;
</span><ins>+#include &quot;Location.h&quot;
</ins><span class="cx"> #include &quot;Logging.h&quot;
</span><span class="cx"> #include &quot;MainFrame.h&quot;
</span><span class="cx"> #include &quot;Page.h&quot;
</span><span class="lines">@@ -44,6 +45,7 @@
</span><span class="cx"> #include &quot;ReplaySessionSegment.h&quot;
</span><span class="cx"> #include &quot;ReplayingInputCursor.h&quot;
</span><span class="cx"> #include &quot;ScriptController.h&quot;
</span><ins>+#include &quot;SerializationMethods.h&quot;
</ins><span class="cx"> #include &quot;Settings.h&quot;
</span><span class="cx"> #include &quot;UserInputBridge.h&quot;
</span><span class="cx"> #include &quot;WebReplayInputs.h&quot;
</span><span class="lines">@@ -56,6 +58,35 @@
</span><span class="cx"> 
</span><span class="cx"> namespace WebCore {
</span><span class="cx"> 
</span><ins>+static void logDispatchedDOMEvent(const Event&amp; 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-&gt;toNode()) {
+        LOG(WebReplay, &quot;%-20s ---&gt;%s DOM event: type=%s, target=%lu/node[%p] %s\n&quot;, &quot;ReplayEvents&quot;,
+            (eventIsUnrelated) ? &quot;Unrelated&quot; : &quot;Dispatching&quot;,
+            event.type().string().utf8().data(),
+            frameIndexFromDocument((node-&gt;inDocument()) ? &amp;node-&gt;document() : node-&gt;ownerDocument()),
+            node,
+            node-&gt;nodeName().utf8().data());
+    } else if (DOMWindow* window = target-&gt;toDOMWindow()) {
+        LOG(WebReplay, &quot;%-20s ---&gt;%s DOM event: type=%s, target=%lu/window[%p] %s\n&quot;, &quot;ReplayEvents&quot;,
+            (eventIsUnrelated) ? &quot;Unrelated&quot; : &quot;Dispatching&quot;,
+            event.type().string().utf8().data(),
+            frameIndexFromDocument(window-&gt;document()),
+            window,
+            window-&gt;location()-&gt;href().utf8().data());
+    }
+#else
+    UNUSED_PARAM(event);
+    UNUSED_PARAM(eventIsUnrelated);
+#endif
+}
+
</ins><span class="cx"> ReplayController::ReplayController(Page&amp; page)
</span><span class="cx">     : m_page(page)
</span><span class="cx">     , m_loadedSegment(nullptr)
</span><span class="lines">@@ -360,6 +391,36 @@
</span><span class="cx">     // input has been dispatched. So, nothing needs to be done here.
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+void ReplayController::willDispatchEvent(const Event&amp; event, Frame* frame)
+{
+    EventTarget* target = event.target();
+    if (!target &amp;&amp; !frame)
+        return;
+
+    Document* document = frame ? frame-&gt;document() : nullptr;
+    // Fetch the document from the event target, because the target could be detached.
+    if (Node* node = target-&gt;toNode())
+        document = node-&gt;inDocument() ? &amp;node-&gt;document() : node-&gt;ownerDocument();
+    else if (DOMWindow* window = target-&gt;toDOMWindow())
+        document = window-&gt;document();
+
+    ASSERT(document);
+
+    InputCursor&amp; cursor = document-&gt;inputCursor();
+    bool eventIsUnrelated = !cursor.isCapturing() &amp;&amp; !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&lt;CapturingInputCursor&amp;&gt;(cursor).withinEventLoopInputExtent());
+    else if (cursor.isReplaying())
+        ASSERT(dispatcher().isDispatching());
+#endif
+}
+
</ins><span class="cx"> PassRefPtr&lt;ReplaySession&gt; ReplayController::loadedSession() const
</span><span class="cx"> {
</span><span class="cx">     return m_loadedSession;
</span></span></pre></div>
<a id="trunkSourceWebCorereplayReplayControllerh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/replay/ReplayController.h (166879 => 166880)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/replay/ReplayController.h        2014-04-07 19:44:06 UTC (rev 166879)
+++ trunk/Source/WebCore/replay/ReplayController.h        2014-04-07 19:58:07 UTC (rev 166880)
</span><span class="lines">@@ -34,6 +34,10 @@
</span><span class="cx"> #include &lt;wtf/Noncopyable.h&gt;
</span><span class="cx"> #include &lt;wtf/Vector.h&gt;
</span><span class="cx"> 
</span><ins>+// Determinism assertions are guarded by this macro. When a user-facing error reporting and
+// recovery mechanism is implemented, this guard can be removed. &lt;https://webkit.org/b/131279&gt;
+#define ENABLE_AGGRESSIVE_DETERMINISM_CHECKS 0
+
</ins><span class="cx"> namespace JSC {
</span><span class="cx"> class InputCursor;
</span><span class="cx"> }
</span><span class="lines">@@ -129,6 +133,7 @@
</span><span class="cx">     // InspectorReplayAgent notifications.
</span><span class="cx">     void frameNavigated(DocumentLoader*);
</span><span class="cx">     void frameDetached(Frame*);
</span><ins>+    void willDispatchEvent(const Event&amp;, Frame*);
</ins><span class="cx"> 
</span><span class="cx">     Page&amp; page() const { return m_page; }
</span><span class="cx">     SessionState sessionState() const { return m_sessionState; }
</span></span></pre></div>
<a id="trunkSourceWebCorereplayUserInputBridgecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/replay/UserInputBridge.cpp (166879 => 166880)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/replay/UserInputBridge.cpp        2014-04-07 19:44:06 UTC (rev 166879)
+++ trunk/Source/WebCore/replay/UserInputBridge.cpp        2014-04-07 19:58:07 UTC (rev 166880)
</span><span class="lines">@@ -80,10 +80,12 @@
</span><span class="cx"> #if ENABLE(WEB_REPLAY)
</span><span class="cx">     EARLY_RETURN_IF_SHOULD_IGNORE_INPUT;
</span><span class="cx"> 
</span><del>-    if (activeCursor().isCapturing()) {
</del><ins>+    InputCursor&amp; cursor = activeCursor();
+    if (cursor.isCapturing()) {
</ins><span class="cx">         std::unique_ptr&lt;PlatformMouseEvent&gt; ownedEvent = std::make_unique&lt;PlatformMouseEvent&gt;(mouseEvent);
</span><del>-        activeCursor().appendInput&lt;HandleMousePress&gt;(std::move(ownedEvent));
</del><ins>+        cursor.appendInput&lt;HandleMousePress&gt;(std::move(ownedEvent));
</ins><span class="cx">     }
</span><ins>+    EventLoopInputExtent extent(cursor);
</ins><span class="cx"> #else
</span><span class="cx">     UNUSED_PARAM(inputSource);
</span><span class="cx"> #endif
</span><span class="lines">@@ -96,10 +98,12 @@
</span><span class="cx"> #if ENABLE(WEB_REPLAY)
</span><span class="cx">     EARLY_RETURN_IF_SHOULD_IGNORE_INPUT;
</span><span class="cx"> 
</span><del>-    if (activeCursor().isCapturing()) {
</del><ins>+    InputCursor&amp; cursor = activeCursor();
+    if (cursor.isCapturing()) {
</ins><span class="cx">         std::unique_ptr&lt;PlatformMouseEvent&gt; ownedEvent = std::make_unique&lt;PlatformMouseEvent&gt;(mouseEvent);
</span><del>-        activeCursor().appendInput&lt;HandleMouseRelease&gt;(std::move(ownedEvent));
</del><ins>+        cursor.appendInput&lt;HandleMouseRelease&gt;(std::move(ownedEvent));
</ins><span class="cx">     }
</span><ins>+    EventLoopInputExtent extent(cursor);
</ins><span class="cx"> #else
</span><span class="cx">     UNUSED_PARAM(inputSource);
</span><span class="cx"> #endif
</span><span class="lines">@@ -112,10 +116,12 @@
</span><span class="cx"> #if ENABLE(WEB_REPLAY)
</span><span class="cx">     EARLY_RETURN_IF_SHOULD_IGNORE_INPUT;
</span><span class="cx"> 
</span><del>-    if (activeCursor().isCapturing()) {
</del><ins>+    InputCursor&amp; cursor = activeCursor();
+    if (cursor.isCapturing()) {
</ins><span class="cx">         std::unique_ptr&lt;PlatformMouseEvent&gt; ownedEvent = std::make_unique&lt;PlatformMouseEvent&gt;(mouseEvent);
</span><del>-        activeCursor().appendInput&lt;HandleMouseMove&gt;(std::move(ownedEvent), false);
</del><ins>+        cursor.appendInput&lt;HandleMouseMove&gt;(std::move(ownedEvent), false);
</ins><span class="cx">     }
</span><ins>+    EventLoopInputExtent extent(cursor);
</ins><span class="cx"> #else
</span><span class="cx">     UNUSED_PARAM(inputSource);
</span><span class="cx"> #endif
</span><span class="lines">@@ -128,10 +134,12 @@
</span><span class="cx"> #if ENABLE(WEB_REPLAY)
</span><span class="cx">     EARLY_RETURN_IF_SHOULD_IGNORE_INPUT;
</span><span class="cx"> 
</span><del>-    if (activeCursor().isCapturing()) {
</del><ins>+    InputCursor&amp; cursor = activeCursor();
+    if (cursor.isCapturing()) {
</ins><span class="cx">         std::unique_ptr&lt;PlatformMouseEvent&gt; ownedEvent = std::make_unique&lt;PlatformMouseEvent&gt;(mouseEvent);
</span><del>-        activeCursor().appendInput&lt;HandleMouseMove&gt;(std::move(ownedEvent), true);
</del><ins>+        cursor.appendInput&lt;HandleMouseMove&gt;(std::move(ownedEvent), true);
</ins><span class="cx">     }
</span><ins>+    EventLoopInputExtent extent(cursor);
</ins><span class="cx"> #else
</span><span class="cx">     UNUSED_PARAM(inputSource);
</span><span class="cx"> #endif
</span><span class="lines">@@ -144,10 +152,12 @@
</span><span class="cx"> #if ENABLE(WEB_REPLAY)
</span><span class="cx">     EARLY_RETURN_IF_SHOULD_IGNORE_INPUT;
</span><span class="cx"> 
</span><del>-    if (activeCursor().isCapturing()) {
</del><ins>+    InputCursor&amp; cursor = activeCursor();
+    if (cursor.isCapturing()) {
</ins><span class="cx">         std::unique_ptr&lt;PlatformKeyboardEvent&gt; ownedEvent = std::make_unique&lt;PlatformKeyboardEvent&gt;(keyEvent);
</span><del>-        activeCursor().appendInput&lt;HandleKeyPress&gt;(std::move(ownedEvent));
</del><ins>+        cursor.appendInput&lt;HandleKeyPress&gt;(std::move(ownedEvent));
</ins><span class="cx">     }
</span><ins>+    EventLoopInputExtent extent(cursor);
</ins><span class="cx"> #else
</span><span class="cx">     UNUSED_PARAM(inputSource);
</span><span class="cx"> #endif
</span><span class="lines">@@ -165,10 +175,12 @@
</span><span class="cx"> #if ENABLE(WEB_REPLAY)
</span><span class="cx">     EARLY_RETURN_IF_SHOULD_IGNORE_INPUT;
</span><span class="cx"> 
</span><del>-    if (activeCursor().isCapturing()) {
</del><ins>+    InputCursor&amp; cursor = activeCursor();
+    if (cursor.isCapturing()) {
</ins><span class="cx">         std::unique_ptr&lt;PlatformWheelEvent&gt; ownedEvent = std::make_unique&lt;PlatformWheelEvent&gt;(wheelEvent);
</span><del>-        activeCursor().appendInput&lt;HandleWheelEvent&gt;(std::move(ownedEvent));
</del><ins>+        cursor.appendInput&lt;HandleWheelEvent&gt;(std::move(ownedEvent));
</ins><span class="cx">     }
</span><ins>+    EventLoopInputExtent extent(cursor);
</ins><span class="cx"> #else
</span><span class="cx">     UNUSED_PARAM(inputSource);
</span><span class="cx"> #endif
</span><span class="lines">@@ -191,8 +203,11 @@
</span><span class="cx"> #if ENABLE(WEB_REPLAY)
</span><span class="cx">     EARLY_RETURN_IF_SHOULD_IGNORE_INPUT;
</span><span class="cx"> 
</span><del>-    if (activeCursor().isCapturing())
-        activeCursor().appendInput&lt;ScrollPage&gt;(direction, granularity);
</del><ins>+    InputCursor&amp; cursor = activeCursor();
+    if (cursor.isCapturing())
+        cursor.appendInput&lt;ScrollPage&gt;(direction, granularity);
+
+    EventLoopInputExtent extent(cursor);
</ins><span class="cx"> #else
</span><span class="cx">     UNUSED_PARAM(inputSource);
</span><span class="cx"> #endif
</span><span class="lines">@@ -205,8 +220,11 @@
</span><span class="cx"> #if ENABLE(WEB_REPLAY)
</span><span class="cx">     EARLY_RETURN_IF_SHOULD_IGNORE_INPUT;
</span><span class="cx"> 
</span><del>-    if (activeCursor().isCapturing())
-        activeCursor().appendInput&lt;LogicalScrollPage&gt;(direction, granularity);
</del><ins>+    InputCursor&amp; cursor = activeCursor();
+    if (cursor.isCapturing())
+        cursor.appendInput&lt;LogicalScrollPage&gt;(direction, granularity);
+
+    EventLoopInputExtent extent(cursor);
</ins><span class="cx"> #else
</span><span class="cx">     UNUSED_PARAM(inputSource);
</span><span class="cx"> #endif
</span></span></pre>
</div>
</div>

</body>
</html>