<!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>[237028] trunk</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/237028">237028</a></dd>
<dt>Author</dt> <dd>drousso@apple.com</dd>
<dt>Date</dt> <dd>2018-10-10 21:13:17 -0700 (Wed, 10 Oct 2018)</dd>
</dl>

<h3>Log Message</h3>
<pre>Web Inspector: create special Network waterfall for media events
https://bugs.webkit.org/show_bug.cgi?id=189773
<rdar://problem/44626605>

Reviewed by Joseph Pecoraro.

Source/JavaScriptCore:

* inspector/protocol/DOM.json:
Add `didFireEvent` event that is fired when specific event listeners added by
`InspectorInstrumentation::addEventListenersToNode` are fired.

Source/WebCore:

Test: http/tests/inspector/dom/didFireEvent.html

* html/HTMLMediaElement.cpp:
(WebCore::HTMLMediaElement::HTMLMediaElement):

* inspector/InspectorInstrumentation.h:
(WebCore::InspectorInstrumentation::addEventListenersToNode): Added.
* inspector/InspectorInstrumentation.cpp:
(WebCore::InspectorInstrumentation::addEventListenersToNodeImpl): Added.

* inspector/agents/InspectorDOMAgent.h:
* inspector/agents/InspectorDOMAgent.cpp:
(WebCore::EventFiredCallback): Added.
(WebCore::EventFiredCallback::create): Added.
(WebCore::EventFiredCallback::operator==): Added.
(WebCore::EventFiredCallback::handleEvent): Added.
(WebCore::EventFiredCallback::EventFiredCallback): Added.
(WebCore::InspectorDOMAgent::didCreateFrontendAndBackend):
(WebCore::InspectorDOMAgent::addEventListenersToNode): Added.

Source/WebInspectorUI:

* Localizations/en.lproj/localizedStrings.js:
* UserInterface/Main.html:
* UserInterface/Base/Utilities.js:

* UserInterface/Protocol/DOMObserver.js:
(WI.DOMObserver.prototype.didFireEvent): Added.
* UserInterface/Controllers/DOMManager.js:
(WI.DOMManager.prototype.didFireEvent): Added.
* UserInterface/Models/DOMNode.js:
(WI.DOMNode):
(WI.DOMNode.prototype.get domEvents): Added.
(WI.DOMNode.prototype.didFireEvent): Added.
(WI.DOMNode.prototype._addDOMEvent): Added.

* UserInterface/Views/NetworkTableContentView.js:
(WI.NetworkTableContentView):
(WI.NetworkTableContentView.prototype.shown):
(WI.NetworkTableContentView.prototype.hidden):
(WI.NetworkTableContentView.prototype.closed):
(WI.NetworkTableContentView.prototype.reset):
(WI.NetworkTableContentView.prototype.showRepresentedObject):
(WI.NetworkTableContentView.prototype.networkDetailViewClose): Added.
(WI.NetworkTableContentView.prototype.tableSortChanged):
(WI.NetworkTableContentView.prototype.tableSelectionDidChange):
(WI.NetworkTableContentView.prototype._populateNameCell):
(WI.NetworkTableContentView.prototype._populateWaterfallGraph.positionByStartOffset): Added.
(WI.NetworkTableContentView.prototype._populateWaterfallGraph.setWidthForDuration): Added.
(WI.NetworkTableContentView.prototype._populateWaterfallGraph.createDOMEventLine): Added.
(WI.NetworkTableContentView.prototype._populateWaterfallGraph.appendBlock):
(WI.NetworkTableContentView.prototype._populateWaterfallGraph):
(WI.NetworkTableContentView.prototype._processPendingEntries):
(WI.NetworkTableContentView.prototype._rowIndexForRepresentedObject): Added.
(WI.NetworkTableContentView.prototype._updateEntryForResource):
(WI.NetworkTableContentView.prototype._hideDetailView): Added.
(WI.NetworkTableContentView.prototype._showDetailView): Added.
(WI.NetworkTableContentView.prototype._positionDetailView): Added.
(WI.NetworkTableContentView.prototype._resourceTransferSizeDidChange):
(WI.NetworkTableContentView.prototype._tryLinkResourceToDOMNode):
(WI.NetworkTableContentView.prototype._handleNodeDidFireEvent): Added.
(WI.NetworkTableContentView.prototype._updateFilteredEntries):
(WI.NetworkTableContentView.prototype._typeFilterScopeBarSelectionChanged):
(WI.NetworkTableContentView.prototype._urlFilterDidChange):
(WI.NetworkTableContentView.prototype._restoreSelectedRow):
(WI.NetworkTableContentView.prototype._waterfallPopoverContent): Added.
(WI.NetworkTableContentView.prototype._waterfallPopoverContentForResourceEntry): Added.
(WI.NetworkTableContentView.prototype._waterfallPopoverContentForNodeEntry): Added.
(WI.NetworkTableContentView.prototype._handleResourceEntryMousedownWaterfall): Added.
(WI.NetworkTableContentView.prototype._handleNodeEntryMousedownWaterfall): Added.
(WI.NetworkTableContentView.prototype._handleMousedownWaterfall): Added.
(WI.NetworkTableContentView.prototype.networkResourceDetailViewClose): Deleted.
(WI.NetworkTableContentView.prototype._rowIndexForResource): Deleted.
(WI.NetworkTableContentView.prototype._hideResourceDetailView): Deleted.
(WI.NetworkTableContentView.prototype._showResourceDetailView): Deleted.
(WI.NetworkTableContentView.prototype._waterfallPopoverContentForResource): Deleted.
* UserInterface/Views/NetworkTableContentView.css:
(.content-view.network .network-table): Added.
(.network-table :not(.header) .cell.waterfall .waterfall-container > .dom-event): Added.
(.network-table :not(.header) .cell.waterfall .waterfall-container > .dom-activity): Added.
(.network-table :not(.header) .cell.waterfall .waterfall-container > .dom-activity.playing): Added.

* UserInterface/Views/NetworkDOMNodeDetailView.js: Added.
(WI.NetworkDOMNodeDetailView):
(WI.NetworkDOMNodeDetailView.prototype.initialLayout):
(WI.NetworkDOMNodeDetailView.prototype.showContentViewForIdentifier):

* UserInterface/Views/NetworkResourceDetailView.css:
(.content-view.resource-details):
(.network-resource-detail): Deleted.
(.network-resource-detail .navigation-bar): Deleted.
(.network-resource-detail .item.close > .glyph): Deleted.
(.network-resource-detail .item.close > .glyph:hover): Deleted.
(.network-resource-detail .item.close > .glyph:active): Deleted.
(.network .network-resource-detail .navigation-bar .item.radio.button.text-only): Deleted.
(.network .network-resource-detail .navigation-bar .item.radio.button.text-only.selected): Deleted.
(.network-resource-detail > .content-browser): Deleted.
(@media (prefers-dark-interface)): Deleted.
* UserInterface/Views/NetworkResourceDetailView.js:
(WI.NetworkResourceDetailView):
(WI.NetworkResourceDetailView.prototype.shown):
(WI.NetworkResourceDetailView.prototype.headersContentViewGoToRequestData):
(WI.NetworkResourceDetailView.prototype.sizesContentViewGoToHeaders):
(WI.NetworkResourceDetailView.prototype.sizesContentViewGoToRequestBody):
(WI.NetworkResourceDetailView.prototype.sizesContentViewGoToResponseBody):
(WI.NetworkResourceDetailView.prototype.initialLayout):
(WI.NetworkResourceDetailView.prototype.showContentViewForIdentifier):
(WI.NetworkResourceDetailView.prototype.get resource): Deleted.
(WI.NetworkResourceDetailView.prototype.hidden): Deleted.
(WI.NetworkResourceDetailView.prototype.dispose): Deleted.
(WI.NetworkResourceDetailView.prototype.willShowWithCookie): Deleted.
(WI.NetworkResourceDetailView.prototype.initialLayout): Deleted.
(WI.NetworkResourceDetailView.prototype._showPreferredContentView): Deleted.
(WI.NetworkResourceDetailView.prototype._showContentViewForNavigationItem): Deleted.
(WI.NetworkResourceDetailView.prototype._navigationItemSelected): Deleted.
(WI.NetworkResourceDetailView.prototype._handleCloseButton): Deleted.

* UserInterface/Views/NetworkDetailView.js: Added.
(WI.NetworkDetailView):
(WI.NetworkDetailView.prototype.get representedObject):
(WI.NetworkDetailView.prototype.shown):
(WI.NetworkDetailView.prototype.hidden):
(WI.NetworkDetailView.prototype.dispose):
(WI.NetworkDetailView.prototype.willShowWithCookie):
(WI.NetworkDetailView.prototype.initialLayout):
(WI.NetworkDetailView.prototype.createDetailNavigationItem):
(WI.NetworkDetailView.prototype.detailNavigationItemForIdentifier):
(WI.NetworkDetailView.prototype.showContentViewForIdentifier):
(WI.NetworkDetailView.prototype._showPreferredContentView):
(WI.NetworkDetailView.prototype._navigationItemSelected):
(WI.NetworkDetailView.prototype._handleCloseButton):
* UserInterface/Views/NetworkDetailView.css: Added.
(.network-detail):
(.network-detail .navigation-bar):
(.network-detail .item.close > .glyph):
(.network-detail .item.close > .glyph:hover):
(.network-detail .item.close > .glyph:active):
(.network .network-detail .navigation-bar .item.radio.button.text-only):
(.network .network-detail .navigation-bar .item.radio.button.text-only.selected):
(.network-detail > .content-browser):
(@media (prefers-dark-interface)):
Create base class for detail views shown in the Network tab.

* UserInterface/Views/DOMNodeEventsContentView.js: Added.
(WI.DOMNodeEventsContentView):
(WI.DOMNodeEventsContentView.prototype.initialLayout):
(WI.DOMNodeEventsContentView.prototype.closed):
(WI.DOMNodeEventsContentView.prototype._handleDOMNodeDidFireEvent):
* UserInterface/Views/DOMNodeEventsContentView.css: Added.
(.dom-node-details.dom-events):

* UserInterface/Views/DOMEventsBreakdownView.js: Added.
(WI.DOMEventsBreakdownView):
(WI.DOMEventsBreakdownView.prototype.addEvent):
(WI.DOMEventsBreakdownView.prototype.initialLayout):
(WI.DOMEventsBreakdownView.prototype._populateTable.percentOfTotalTime):
(WI.DOMEventsBreakdownView.prototype._populateTable):
* UserInterface/Views/DOMEventsBreakdownView.css: Added.
(.waterfall-popover-content .dom-events-breakdown):
(.dom-events-breakdown):
(.dom-events-breakdown table):
(.dom-events-breakdown tr > :matches(th, td)):
(.dom-events-breakdown tbody > tr):
(.dom-events-breakdown .graph):
(.dom-events-breakdown .graph > :matches(.point, .area)):
(.dom-events-breakdown .graph > .point):
(.dom-events-breakdown .time):

* UserInterface/Views/ResourceTimingBreakdownView.css:
(.resource-timing-breakdown > table > tr.header:not(.total-row) > td): Added.
(.popover.waterfall-popover): Deleted.

LayoutTests:

* http/tests/inspector/dom/didFireEvent-expected.txt: Added.
* http/tests/inspector/dom/didFireEvent.html: Added.

* inspector/unit-tests/array-utilities-expected.txt:
* inspector/unit-tests/array-utilities.html:</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkLayoutTestsChangeLog">trunk/LayoutTests/ChangeLog</a></li>
<li><a href="#trunkLayoutTestsinspectorunittestsarrayutilitiesexpectedtxt">trunk/LayoutTests/inspector/unit-tests/array-utilities-expected.txt</a></li>
<li><a href="#trunkLayoutTestsinspectorunittestsarrayutilitieshtml">trunk/LayoutTests/inspector/unit-tests/array-utilities.html</a></li>
<li><a href="#trunkSourceJavaScriptCoreChangeLog">trunk/Source/JavaScriptCore/ChangeLog</a></li>
<li><a href="#trunkSourceJavaScriptCoreinspectorprotocolDOMjson">trunk/Source/JavaScriptCore/inspector/protocol/DOM.json</a></li>
<li><a href="#trunkSourceWebCoreChangeLog">trunk/Source/WebCore/ChangeLog</a></li>
<li><a href="#trunkSourceWebCorehtmlHTMLMediaElementcpp">trunk/Source/WebCore/html/HTMLMediaElement.cpp</a></li>
<li><a href="#trunkSourceWebCoreinspectorInspectorInstrumentationcpp">trunk/Source/WebCore/inspector/InspectorInstrumentation.cpp</a></li>
<li><a href="#trunkSourceWebCoreinspectorInspectorInstrumentationh">trunk/Source/WebCore/inspector/InspectorInstrumentation.h</a></li>
<li><a href="#trunkSourceWebCoreinspectoragentsInspectorDOMAgentcpp">trunk/Source/WebCore/inspector/agents/InspectorDOMAgent.cpp</a></li>
<li><a href="#trunkSourceWebCoreinspectoragentsInspectorDOMAgenth">trunk/Source/WebCore/inspector/agents/InspectorDOMAgent.h</a></li>
<li><a href="#trunkSourceWebInspectorUIChangeLog">trunk/Source/WebInspectorUI/ChangeLog</a></li>
<li><a href="#trunkSourceWebInspectorUILocalizationsenlprojlocalizedStringsjs">trunk/Source/WebInspectorUI/Localizations/en.lproj/localizedStrings.js</a></li>
<li><a href="#trunkSourceWebInspectorUIUserInterfaceBaseUtilitiesjs">trunk/Source/WebInspectorUI/UserInterface/Base/Utilities.js</a></li>
<li><a href="#trunkSourceWebInspectorUIUserInterfaceControllersDOMManagerjs">trunk/Source/WebInspectorUI/UserInterface/Controllers/DOMManager.js</a></li>
<li><a href="#trunkSourceWebInspectorUIUserInterfaceMainhtml">trunk/Source/WebInspectorUI/UserInterface/Main.html</a></li>
<li><a href="#trunkSourceWebInspectorUIUserInterfaceModelsDOMNodejs">trunk/Source/WebInspectorUI/UserInterface/Models/DOMNode.js</a></li>
<li><a href="#trunkSourceWebInspectorUIUserInterfaceProtocolDOMObserverjs">trunk/Source/WebInspectorUI/UserInterface/Protocol/DOMObserver.js</a></li>
<li><a href="#trunkSourceWebInspectorUIUserInterfaceViewsNetworkResourceDetailViewcss">trunk/Source/WebInspectorUI/UserInterface/Views/NetworkResourceDetailView.css</a></li>
<li><a href="#trunkSourceWebInspectorUIUserInterfaceViewsNetworkResourceDetailViewjs">trunk/Source/WebInspectorUI/UserInterface/Views/NetworkResourceDetailView.js</a></li>
<li><a href="#trunkSourceWebInspectorUIUserInterfaceViewsNetworkTableContentViewcss">trunk/Source/WebInspectorUI/UserInterface/Views/NetworkTableContentView.css</a></li>
<li><a href="#trunkSourceWebInspectorUIUserInterfaceViewsNetworkTableContentViewjs">trunk/Source/WebInspectorUI/UserInterface/Views/NetworkTableContentView.js</a></li>
<li><a href="#trunkSourceWebInspectorUIUserInterfaceViewsResourceTimingBreakdownViewcss">trunk/Source/WebInspectorUI/UserInterface/Views/ResourceTimingBreakdownView.css</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#trunkLayoutTestshttptestsinspectordomdidFireEventexpectedtxt">trunk/LayoutTests/http/tests/inspector/dom/didFireEvent-expected.txt</a></li>
<li><a href="#trunkLayoutTestshttptestsinspectordomdidFireEventhtml">trunk/LayoutTests/http/tests/inspector/dom/didFireEvent.html</a></li>
<li><a href="#trunkSourceWebInspectorUIUserInterfaceViewsDOMEventsBreakdownViewcss">trunk/Source/WebInspectorUI/UserInterface/Views/DOMEventsBreakdownView.css</a></li>
<li><a href="#trunkSourceWebInspectorUIUserInterfaceViewsDOMEventsBreakdownViewjs">trunk/Source/WebInspectorUI/UserInterface/Views/DOMEventsBreakdownView.js</a></li>
<li><a href="#trunkSourceWebInspectorUIUserInterfaceViewsDOMNodeEventsContentViewcss">trunk/Source/WebInspectorUI/UserInterface/Views/DOMNodeEventsContentView.css</a></li>
<li><a href="#trunkSourceWebInspectorUIUserInterfaceViewsDOMNodeEventsContentViewjs">trunk/Source/WebInspectorUI/UserInterface/Views/DOMNodeEventsContentView.js</a></li>
<li><a href="#trunkSourceWebInspectorUIUserInterfaceViewsNetworkDOMNodeDetailViewjs">trunk/Source/WebInspectorUI/UserInterface/Views/NetworkDOMNodeDetailView.js</a></li>
<li><a href="#trunkSourceWebInspectorUIUserInterfaceViewsNetworkDetailViewcss">trunk/Source/WebInspectorUI/UserInterface/Views/NetworkDetailView.css</a></li>
<li><a href="#trunkSourceWebInspectorUIUserInterfaceViewsNetworkDetailViewjs">trunk/Source/WebInspectorUI/UserInterface/Views/NetworkDetailView.js</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkLayoutTestsChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/ChangeLog (237027 => 237028)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/ChangeLog      2018-10-11 03:08:34 UTC (rev 237027)
+++ trunk/LayoutTests/ChangeLog 2018-10-11 04:13:17 UTC (rev 237028)
</span><span class="lines">@@ -1,3 +1,17 @@
</span><ins>+2018-10-10  Devin Rousso  <drousso@apple.com>
+
+        Web Inspector: create special Network waterfall for media events
+        https://bugs.webkit.org/show_bug.cgi?id=189773
+        <rdar://problem/44626605>
+
+        Reviewed by Joseph Pecoraro.
+
+        * http/tests/inspector/dom/didFireEvent-expected.txt: Added.
+        * http/tests/inspector/dom/didFireEvent.html: Added.
+
+        * inspector/unit-tests/array-utilities-expected.txt:
+        * inspector/unit-tests/array-utilities.html:
+
</ins><span class="cx"> 2018-10-10  Brent Fulgham  <bfulgham@apple.com>
</span><span class="cx"> 
</span><span class="cx">         Only report the supported WebGL version
</span></span></pre></div>
<a id="trunkLayoutTestshttptestsinspectordomdidFireEventexpectedtxt"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/http/tests/inspector/dom/didFireEvent-expected.txt (0 => 237028)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/http/tests/inspector/dom/didFireEvent-expected.txt                             (rev 0)
+++ trunk/LayoutTests/http/tests/inspector/dom/didFireEvent-expected.txt        2018-10-11 04:13:17 UTC (rev 237028)
</span><span class="lines">@@ -0,0 +1,10 @@
</span><ins>+Tests that listeners registered by InspectorDOMAgent::addEventListenersToNode are working.
+
+
+
+== Running test suite: DOM.didFireEvent
+-- Running test case: DOM.didFireEvent
+Adding video source "resources/white.mp4"...
+PASS: Should recieve a "loadstart" event.
+PASS: Event timestamp should be greater than 0.
+
</ins></span></pre></div>
<a id="trunkLayoutTestshttptestsinspectordomdidFireEventhtml"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/http/tests/inspector/dom/didFireEvent.html (0 => 237028)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/http/tests/inspector/dom/didFireEvent.html                             (rev 0)
+++ trunk/LayoutTests/http/tests/inspector/dom/didFireEvent.html        2018-10-11 04:13:17 UTC (rev 237028)
</span><span class="lines">@@ -0,0 +1,61 @@
</span><ins>+<!DOCTYPE html>
+<html>
+<head>
+<script src="../resources/inspector-test.js"></script>
+<script>
+function loadSource(url, type) {
+    let sourceElement = document.createElement("source");
+    sourceElement.type = type;
+    sourceElement.src = url;
+
+    document.getElementById("video").appendChild(sourceElement);
+}
+
+function test()
+{
+    let suite = InspectorTest.createAsyncSuite("DOM.didFireEvent");
+
+    let videoNode = null;
+
+    suite.addTestCase({
+        name: "DOM.didFireEvent",
+        description: "Check that HTMLMediaElement events work.",
+        test(resolve, reject) {
+            const file = "white.mp4";
+
+            let listener = videoNode.addEventListener(WI.DOMNode.Event.DidFireEvent, (event) => {
+                let {domEvent} = event.data;
+                if (domEvent.eventName !== "loadstart")
+                    return;
+
+                InspectorTest.pass(`Should recieve a "loadstart" event.`)
+                InspectorTest.expectGreaterThan(domEvent.timestamp, 0, "Event timestamp should be greater than 0.");
+
+                videoNode.removeEventListener(WI.DOMNode.Event.DidFireEvent, listener);
+                resolve();
+            });
+
+            InspectorTest.log(`Adding video source "resources/${file}"...`);
+            InspectorTest.evaluateInPage(`loadSource("resources/${file}", "video/mp4")`);
+        }
+    });
+
+    WI.domManager.requestDocument((documentNode) => {
+        WI.domManager.querySelector(documentNode.id, "#video", (videoNodeId) => {
+            videoNode = WI.domManager.nodeForId(videoNodeId);
+            if (videoNode)
+                suite.runTestCasesAndFinish();
+            else {
+                InspectorTest.fail(`DOM node for "#video" not found.`);
+                InspectorTest.completeTest();
+            }
+        });
+    });
+}
+</script>
+</head>
+<body onload="runTest()">
+    <p>Tests that listeners registered by InspectorDOMAgent::addEventListenersToNode are working.</p>
+    <video id="video" muted autoplay></video>
+</body>
+</html>
</ins></span></pre></div>
<a id="trunkLayoutTestsinspectorunittestsarrayutilitiesexpectedtxt"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/inspector/unit-tests/array-utilities-expected.txt (237027 => 237028)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/inspector/unit-tests/array-utilities-expected.txt      2018-10-11 03:08:34 UTC (rev 237027)
+++ trunk/LayoutTests/inspector/unit-tests/array-utilities-expected.txt 2018-10-11 04:13:17 UTC (rev 237028)
</span><span class="lines">@@ -74,6 +74,13 @@
</span><span class="cx"> PASS: lastValue of a nonempty array should be the last value.
</span><span class="cx"> PASS: lastValue of an empty array should be undefined.
</span><span class="cx"> 
</span><ins>+-- Running test case: Array.prototype.adjacencies
+[] => []
+[1] => []
+[1,2] => [[1,2]]
+[1,2,3] => [[1,2],[2,3]]
+[1,2,3,4] => [[1,2],[2,3],[3,4]]
+
</ins><span class="cx"> -- Running test case: Array.prototype.remove
</span><span class="cx"> PASS: remove should only remove the first matching value.
</span><span class="cx"> PASS: remove should only remove values that strictly match.
</span></span></pre></div>
<a id="trunkLayoutTestsinspectorunittestsarrayutilitieshtml"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/inspector/unit-tests/array-utilities.html (237027 => 237028)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/inspector/unit-tests/array-utilities.html      2018-10-11 03:08:34 UTC (rev 237027)
+++ trunk/LayoutTests/inspector/unit-tests/array-utilities.html 2018-10-11 04:13:17 UTC (rev 237028)
</span><span class="lines">@@ -164,6 +164,23 @@
</span><span class="cx">     });
</span><span class="cx"> 
</span><span class="cx">     suite.addTestCase({
</span><ins>+        name: "Array.prototype.adjacencies",
+        test() {
+            function logAdjacencies(array) {
+                InspectorTest.log(JSON.stringify(array) + " => " + JSON.stringify(Array.from(array.adjacencies())));
+            }
+
+            logAdjacencies([]);
+            logAdjacencies([1]);
+            logAdjacencies([1, 2]);
+            logAdjacencies([1, 2, 3]);
+            logAdjacencies([1, 2, 3, 4]);
+
+            return true;
+        }
+    });
+
+    suite.addTestCase({
</ins><span class="cx">         name: "Array.prototype.remove",
</span><span class="cx">         test() {
</span><span class="cx">             let arr1 = [1, 2, 3, 1];
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ChangeLog (237027 => 237028)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ChangeLog    2018-10-11 03:08:34 UTC (rev 237027)
+++ trunk/Source/JavaScriptCore/ChangeLog       2018-10-11 04:13:17 UTC (rev 237028)
</span><span class="lines">@@ -1,3 +1,15 @@
</span><ins>+2018-10-10  Devin Rousso  <drousso@apple.com>
+
+        Web Inspector: create special Network waterfall for media events
+        https://bugs.webkit.org/show_bug.cgi?id=189773
+        <rdar://problem/44626605>
+
+        Reviewed by Joseph Pecoraro.
+
+        * inspector/protocol/DOM.json:
+        Add `didFireEvent` event that is fired when specific event listeners added by
+        `InspectorInstrumentation::addEventListenersToNode` are fired.
+
</ins><span class="cx"> 2018-10-10  Michael Saboff  <msaboff@apple.com>
</span><span class="cx"> 
</span><span class="cx">         Increase executable memory pool from 64MB to 128MB for ARM64
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreinspectorprotocolDOMjson"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/inspector/protocol/DOM.json (237027 => 237028)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/inspector/protocol/DOM.json  2018-10-11 03:08:34 UTC (rev 237027)
+++ trunk/Source/JavaScriptCore/inspector/protocol/DOM.json     2018-10-11 04:13:17 UTC (rev 237028)
</span><span class="lines">@@ -659,6 +659,15 @@
</span><span class="cx">             "parameters": [
</span><span class="cx">                 { "name": "nodeId", "$ref": "NodeId" }
</span><span class="cx">             ]
</span><ins>+        },
+        {
+            "name": "didFireEvent",
+            "description": "Called when an event is fired on a node.",
+            "parameters": [
+                { "name": "nodeId", "$ref": "NodeId" },
+                { "name": "eventName", "type": "string" },
+                { "name": "timestamp", "$ref": "Network.Timestamp", "description": "Time when the event was fired" }
+            ]
</ins><span class="cx">         }
</span><span class="cx">     ]
</span><span class="cx"> }
</span></span></pre></div>
<a id="trunkSourceWebCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/ChangeLog (237027 => 237028)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/ChangeLog   2018-10-11 03:08:34 UTC (rev 237027)
+++ trunk/Source/WebCore/ChangeLog      2018-10-11 04:13:17 UTC (rev 237028)
</span><span class="lines">@@ -1,3 +1,31 @@
</span><ins>+2018-10-10  Devin Rousso  <drousso@apple.com>
+
+        Web Inspector: create special Network waterfall for media events
+        https://bugs.webkit.org/show_bug.cgi?id=189773
+        <rdar://problem/44626605>
+
+        Reviewed by Joseph Pecoraro.
+
+        Test: http/tests/inspector/dom/didFireEvent.html
+
+        * html/HTMLMediaElement.cpp:
+        (WebCore::HTMLMediaElement::HTMLMediaElement):
+
+        * inspector/InspectorInstrumentation.h:
+        (WebCore::InspectorInstrumentation::addEventListenersToNode): Added.
+        * inspector/InspectorInstrumentation.cpp:
+        (WebCore::InspectorInstrumentation::addEventListenersToNodeImpl): Added.
+
+        * inspector/agents/InspectorDOMAgent.h:
+        * inspector/agents/InspectorDOMAgent.cpp:
+        (WebCore::EventFiredCallback): Added.
+        (WebCore::EventFiredCallback::create): Added.
+        (WebCore::EventFiredCallback::operator==): Added.
+        (WebCore::EventFiredCallback::handleEvent): Added.
+        (WebCore::EventFiredCallback::EventFiredCallback): Added.
+        (WebCore::InspectorDOMAgent::didCreateFrontendAndBackend):
+        (WebCore::InspectorDOMAgent::addEventListenersToNode): Added.
+
</ins><span class="cx"> 2018-10-10  Daniel Bates  <dabates@apple.com>
</span><span class="cx"> 
</span><span class="cx">         [iOS] Cleanup -[WAKView _selfHandleEvent:] and -[WAKWindow sendEventSynchronously:]
</span></span></pre></div>
<a id="trunkSourceWebCorehtmlHTMLMediaElementcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/html/HTMLMediaElement.cpp (237027 => 237028)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/html/HTMLMediaElement.cpp   2018-10-11 03:08:34 UTC (rev 237027)
+++ trunk/Source/WebCore/html/HTMLMediaElement.cpp      2018-10-11 04:13:17 UTC (rev 237028)
</span><span class="lines">@@ -53,6 +53,7 @@
</span><span class="cx"> #include "HTMLParserIdioms.h"
</span><span class="cx"> #include "HTMLSourceElement.h"
</span><span class="cx"> #include "HTMLVideoElement.h"
</span><ins>+#include "InspectorInstrumentation.h"
</ins><span class="cx"> #include "JSDOMException.h"
</span><span class="cx"> #include "JSDOMPromiseDeferred.h"
</span><span class="cx"> #include "JSHTMLMediaElement.h"
</span><span class="lines">@@ -522,6 +523,8 @@
</span><span class="cx">     ALWAYS_LOG(LOGIDENTIFIER);
</span><span class="cx"> 
</span><span class="cx">     setHasCustomStyleResolveCallbacks();
</span><ins>+
+    InspectorInstrumentation::addEventListenersToNode(*this);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void HTMLMediaElement::finishInitialization()
</span></span></pre></div>
<a id="trunkSourceWebCoreinspectorInspectorInstrumentationcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/inspector/InspectorInstrumentation.cpp (237027 => 237028)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/inspector/InspectorInstrumentation.cpp      2018-10-11 03:08:34 UTC (rev 237027)
+++ trunk/Source/WebCore/inspector/InspectorInstrumentation.cpp 2018-10-11 04:13:17 UTC (rev 237028)
</span><span class="lines">@@ -135,6 +135,12 @@
</span><span class="cx">     return 0;
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+void InspectorInstrumentation::addEventListenersToNodeImpl(InstrumentingAgents& instrumentingAgents, Node& node)
+{
+    if (InspectorDOMAgent* domAgent = instrumentingAgents.inspectorDOMAgent())
+        domAgent->addEventListenersToNode(node);
+}
+
</ins><span class="cx"> void InspectorInstrumentation::willInsertDOMNodeImpl(InstrumentingAgents& instrumentingAgents, Node& parent)
</span><span class="cx"> {
</span><span class="cx">     if (InspectorDOMDebuggerAgent* domDebuggerAgent = instrumentingAgents.inspectorDOMDebuggerAgent())
</span></span></pre></div>
<a id="trunkSourceWebCoreinspectorInspectorInstrumentationh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/inspector/InspectorInstrumentation.h (237027 => 237028)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/inspector/InspectorInstrumentation.h        2018-10-11 03:08:34 UTC (rev 237027)
+++ trunk/Source/WebCore/inspector/InspectorInstrumentation.h   2018-10-11 04:13:17 UTC (rev 237028)
</span><span class="lines">@@ -107,6 +107,7 @@
</span><span class="cx">     static bool isDebuggerPaused(Frame*);
</span><span class="cx"> 
</span><span class="cx">     static int identifierForNode(Node&);
</span><ins>+    static void addEventListenersToNode(Node&);
</ins><span class="cx">     static void willInsertDOMNode(Document&, Node& parent);
</span><span class="cx">     static void didInsertDOMNode(Document&, Node&);
</span><span class="cx">     static void willRemoveDOMNode(Document&, Node&);
</span><span class="lines">@@ -292,6 +293,7 @@
</span><span class="cx">     static bool isDebuggerPausedImpl(InstrumentingAgents&);
</span><span class="cx"> 
</span><span class="cx">     static int identifierForNodeImpl(InstrumentingAgents&, Node&);
</span><ins>+    static void addEventListenersToNodeImpl(InstrumentingAgents&, Node&);
</ins><span class="cx">     static void willInsertDOMNodeImpl(InstrumentingAgents&, Node& parent);
</span><span class="cx">     static void didInsertDOMNodeImpl(InstrumentingAgents&, Node&);
</span><span class="cx">     static void willRemoveDOMNodeImpl(InstrumentingAgents&, Node&);
</span><span class="lines">@@ -480,6 +482,13 @@
</span><span class="cx">     return 0;
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+inline void InspectorInstrumentation::addEventListenersToNode(Node& node)
+{
+    FAST_RETURN_IF_NO_FRONTENDS(void());
+    if (auto* instrumentingAgents = instrumentingAgentsForDocument(node.document()))
+        addEventListenersToNodeImpl(*instrumentingAgents, node);
+}
+
</ins><span class="cx"> inline void InspectorInstrumentation::willInsertDOMNode(Document& document, Node& parent)
</span><span class="cx"> {
</span><span class="cx">     FAST_RETURN_IF_NO_FRONTENDS(void());
</span></span></pre></div>
<a id="trunkSourceWebCoreinspectoragentsInspectorDOMAgentcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/inspector/agents/InspectorDOMAgent.cpp (237027 => 237028)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/inspector/agents/InspectorDOMAgent.cpp      2018-10-11 03:08:34 UTC (rev 237027)
+++ trunk/Source/WebCore/inspector/agents/InspectorDOMAgent.cpp 2018-10-11 04:13:17 UTC (rev 237028)
</span><span class="lines">@@ -61,6 +61,7 @@
</span><span class="cx"> #include "FrameTree.h"
</span><span class="cx"> #include "HTMLElement.h"
</span><span class="cx"> #include "HTMLFrameOwnerElement.h"
</span><ins>+#include "HTMLMediaElement.h"
</ins><span class="cx"> #include "HTMLNames.h"
</span><span class="cx"> #include "HTMLParserIdioms.h"
</span><span class="cx"> #include "HTMLScriptElement.h"
</span><span class="lines">@@ -219,6 +220,42 @@
</span><span class="cx">     RefPtr<Node> m_node;
</span><span class="cx"> };
</span><span class="cx"> 
</span><ins>+class EventFiredCallback final : public EventListener {
+public:
+    static Ref<EventFiredCallback> create(InspectorDOMAgent& domAgent)
+    {
+        return adoptRef(*new EventFiredCallback(domAgent));
+    }
+
+    bool operator==(const EventListener& other) const final
+    {
+        return this == &other;
+    }
+
+    void handleEvent(ScriptExecutionContext&, Event& event) final
+    {
+        if (!is<Node>(event.target()))
+            return;
+
+        auto* node = downcast<Node>(event.target());
+        int nodeId = m_domAgent.pushNodePathToFrontend(node);
+        if (!nodeId)
+            return;
+
+        auto timestamp = m_domAgent.m_environment.executionStopwatch()->elapsedTime().seconds();
+        m_domAgent.m_frontendDispatcher->didFireEvent(nodeId, event.type(), timestamp);
+    }
+
+private:
+    EventFiredCallback(InspectorDOMAgent& domAgent)
+        : EventListener(EventListener::CPPEventListenerType)
+        , m_domAgent(domAgent)
+    {
+    }
+
+    InspectorDOMAgent& m_domAgent;
+};
+
</ins><span class="cx"> String InspectorDOMAgent::toErrorString(ExceptionCode ec)
</span><span class="cx"> {
</span><span class="cx">     return ec ? String(DOMException::name(ec)) : emptyString();
</span><span class="lines">@@ -253,6 +290,9 @@
</span><span class="cx">     m_instrumentingAgents.setInspectorDOMAgent(this);
</span><span class="cx">     m_document = m_pageAgent->mainFrame().document();
</span><span class="cx"> 
</span><ins>+    for (auto* mediaElement : HTMLMediaElement::allMediaElements())
+        addEventListenersToNode(*mediaElement);
+
</ins><span class="cx">     if (m_nodeToFocus)
</span><span class="cx">         focusNode();
</span><span class="cx"> }
</span><span class="lines">@@ -2090,6 +2130,39 @@
</span><span class="cx">     return pushNodePathToFrontend(&node);
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+void InspectorDOMAgent::addEventListenersToNode(Node& node)
+{
+    auto callback = EventFiredCallback::create(*this);
+
+    auto createEventListener = [&] (const AtomicString& eventName) {
+        node.addEventListener(eventName, callback.copyRef(), false);
+    };
+
+    if (is<HTMLMediaElement>(node)) {
+        createEventListener(eventNames().abortEvent);
+        createEventListener(eventNames().canplayEvent);
+        createEventListener(eventNames().canplaythroughEvent);
+        createEventListener(eventNames().durationchangeEvent);
+        createEventListener(eventNames().emptiedEvent);
+        createEventListener(eventNames().endedEvent);
+        createEventListener(eventNames().errorEvent);
+        createEventListener(eventNames().loadeddataEvent);
+        createEventListener(eventNames().loadedmetadataEvent);
+        createEventListener(eventNames().loadstartEvent);
+        createEventListener(eventNames().pauseEvent);
+        createEventListener(eventNames().playEvent);
+        createEventListener(eventNames().playingEvent);
+        createEventListener(eventNames().ratechangeEvent);
+        createEventListener(eventNames().seekedEvent);
+        createEventListener(eventNames().seekingEvent);
+        createEventListener(eventNames().stalledEvent);
+        createEventListener(eventNames().suspendEvent);
+        createEventListener(eventNames().timeupdateEvent);
+        createEventListener(eventNames().volumechangeEvent);
+        createEventListener(eventNames().waitingEvent);
+    }
+}
+
</ins><span class="cx"> void InspectorDOMAgent::didInsertDOMNode(Node& node)
</span><span class="cx"> {
</span><span class="cx">     if (containsOnlyHTMLWhitespace(&node))
</span></span></pre></div>
<a id="trunkSourceWebCoreinspectoragentsInspectorDOMAgenth"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/inspector/agents/InspectorDOMAgent.h (237027 => 237028)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/inspector/agents/InspectorDOMAgent.h        2018-10-11 03:08:34 UTC (rev 237027)
+++ trunk/Source/WebCore/inspector/agents/InspectorDOMAgent.h   2018-10-11 04:13:17 UTC (rev 237028)
</span><span class="lines">@@ -158,6 +158,7 @@
</span><span class="cx"> 
</span><span class="cx">     // InspectorInstrumentation
</span><span class="cx">     int identifierForNode(Node&);
</span><ins>+    void addEventListenersToNode(Node&);
</ins><span class="cx">     void didInsertDOMNode(Node&);
</span><span class="cx">     void didRemoveDOMNode(Node&);
</span><span class="cx">     void willModifyDOMAttr(Element&, const AtomicString& oldValue, const AtomicString& newValue);
</span><span class="lines">@@ -316,6 +317,8 @@
</span><span class="cx">         }
</span><span class="cx">     };
</span><span class="cx"> 
</span><ins>+    friend class EventFiredCallback;
+
</ins><span class="cx">     HashMap<int, InspectorEventListener> m_eventListenerEntries;
</span><span class="cx">     int m_lastEventListenerId { 1 };
</span><span class="cx"> };
</span></span></pre></div>
<a id="trunkSourceWebInspectorUIChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebInspectorUI/ChangeLog (237027 => 237028)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebInspectorUI/ChangeLog    2018-10-11 03:08:34 UTC (rev 237027)
+++ trunk/Source/WebInspectorUI/ChangeLog       2018-10-11 04:13:17 UTC (rev 237028)
</span><span class="lines">@@ -1,5 +1,163 @@
</span><span class="cx"> 2018-10-10  Devin Rousso  <drousso@apple.com>
</span><span class="cx"> 
</span><ins>+        Web Inspector: create special Network waterfall for media events
+        https://bugs.webkit.org/show_bug.cgi?id=189773
+        <rdar://problem/44626605>
+
+        Reviewed by Joseph Pecoraro.
+
+        * Localizations/en.lproj/localizedStrings.js:
+        * UserInterface/Main.html:
+        * UserInterface/Base/Utilities.js:
+
+        * UserInterface/Protocol/DOMObserver.js:
+        (WI.DOMObserver.prototype.didFireEvent): Added.
+        * UserInterface/Controllers/DOMManager.js:
+        (WI.DOMManager.prototype.didFireEvent): Added.
+        * UserInterface/Models/DOMNode.js:
+        (WI.DOMNode):
+        (WI.DOMNode.prototype.get domEvents): Added.
+        (WI.DOMNode.prototype.didFireEvent): Added.
+        (WI.DOMNode.prototype._addDOMEvent): Added.
+
+        * UserInterface/Views/NetworkTableContentView.js:
+        (WI.NetworkTableContentView):
+        (WI.NetworkTableContentView.prototype.shown):
+        (WI.NetworkTableContentView.prototype.hidden):
+        (WI.NetworkTableContentView.prototype.closed):
+        (WI.NetworkTableContentView.prototype.reset):
+        (WI.NetworkTableContentView.prototype.showRepresentedObject):
+        (WI.NetworkTableContentView.prototype.networkDetailViewClose): Added.
+        (WI.NetworkTableContentView.prototype.tableSortChanged):
+        (WI.NetworkTableContentView.prototype.tableSelectionDidChange):
+        (WI.NetworkTableContentView.prototype._populateNameCell):
+        (WI.NetworkTableContentView.prototype._populateWaterfallGraph.positionByStartOffset): Added.
+        (WI.NetworkTableContentView.prototype._populateWaterfallGraph.setWidthForDuration): Added.
+        (WI.NetworkTableContentView.prototype._populateWaterfallGraph.createDOMEventLine): Added.
+        (WI.NetworkTableContentView.prototype._populateWaterfallGraph.appendBlock):
+        (WI.NetworkTableContentView.prototype._populateWaterfallGraph):
+        (WI.NetworkTableContentView.prototype._processPendingEntries):
+        (WI.NetworkTableContentView.prototype._rowIndexForRepresentedObject): Added.
+        (WI.NetworkTableContentView.prototype._updateEntryForResource):
+        (WI.NetworkTableContentView.prototype._hideDetailView): Added.
+        (WI.NetworkTableContentView.prototype._showDetailView): Added.
+        (WI.NetworkTableContentView.prototype._positionDetailView): Added.
+        (WI.NetworkTableContentView.prototype._resourceTransferSizeDidChange):
+        (WI.NetworkTableContentView.prototype._tryLinkResourceToDOMNode):
+        (WI.NetworkTableContentView.prototype._handleNodeDidFireEvent): Added.
+        (WI.NetworkTableContentView.prototype._updateFilteredEntries):
+        (WI.NetworkTableContentView.prototype._typeFilterScopeBarSelectionChanged):
+        (WI.NetworkTableContentView.prototype._urlFilterDidChange):
+        (WI.NetworkTableContentView.prototype._restoreSelectedRow):
+        (WI.NetworkTableContentView.prototype._waterfallPopoverContent): Added.
+        (WI.NetworkTableContentView.prototype._waterfallPopoverContentForResourceEntry): Added.
+        (WI.NetworkTableContentView.prototype._waterfallPopoverContentForNodeEntry): Added.
+        (WI.NetworkTableContentView.prototype._handleResourceEntryMousedownWaterfall): Added.
+        (WI.NetworkTableContentView.prototype._handleNodeEntryMousedownWaterfall): Added.
+        (WI.NetworkTableContentView.prototype._handleMousedownWaterfall): Added.
+        (WI.NetworkTableContentView.prototype.networkResourceDetailViewClose): Deleted.
+        (WI.NetworkTableContentView.prototype._rowIndexForResource): Deleted.
+        (WI.NetworkTableContentView.prototype._hideResourceDetailView): Deleted.
+        (WI.NetworkTableContentView.prototype._showResourceDetailView): Deleted.
+        (WI.NetworkTableContentView.prototype._waterfallPopoverContentForResource): Deleted.
+        * UserInterface/Views/NetworkTableContentView.css:
+        (.content-view.network .network-table): Added.
+        (.network-table :not(.header) .cell.waterfall .waterfall-container > .dom-event): Added.
+        (.network-table :not(.header) .cell.waterfall .waterfall-container > .dom-activity): Added.
+        (.network-table :not(.header) .cell.waterfall .waterfall-container > .dom-activity.playing): Added.
+
+        * UserInterface/Views/NetworkDOMNodeDetailView.js: Added.
+        (WI.NetworkDOMNodeDetailView):
+        (WI.NetworkDOMNodeDetailView.prototype.initialLayout):
+        (WI.NetworkDOMNodeDetailView.prototype.showContentViewForIdentifier):
+
+        * UserInterface/Views/NetworkResourceDetailView.css:
+        (.content-view.resource-details):
+        (.network-resource-detail): Deleted.
+        (.network-resource-detail .navigation-bar): Deleted.
+        (.network-resource-detail .item.close > .glyph): Deleted.
+        (.network-resource-detail .item.close > .glyph:hover): Deleted.
+        (.network-resource-detail .item.close > .glyph:active): Deleted.
+        (.network .network-resource-detail .navigation-bar .item.radio.button.text-only): Deleted.
+        (.network .network-resource-detail .navigation-bar .item.radio.button.text-only.selected): Deleted.
+        (.network-resource-detail > .content-browser): Deleted.
+        (@media (prefers-dark-interface)): Deleted.
+        * UserInterface/Views/NetworkResourceDetailView.js:
+        (WI.NetworkResourceDetailView):
+        (WI.NetworkResourceDetailView.prototype.shown):
+        (WI.NetworkResourceDetailView.prototype.headersContentViewGoToRequestData):
+        (WI.NetworkResourceDetailView.prototype.sizesContentViewGoToHeaders):
+        (WI.NetworkResourceDetailView.prototype.sizesContentViewGoToRequestBody):
+        (WI.NetworkResourceDetailView.prototype.sizesContentViewGoToResponseBody):
+        (WI.NetworkResourceDetailView.prototype.initialLayout):
+        (WI.NetworkResourceDetailView.prototype.showContentViewForIdentifier):
+        (WI.NetworkResourceDetailView.prototype.get resource): Deleted.
+        (WI.NetworkResourceDetailView.prototype.hidden): Deleted.
+        (WI.NetworkResourceDetailView.prototype.dispose): Deleted.
+        (WI.NetworkResourceDetailView.prototype.willShowWithCookie): Deleted.
+        (WI.NetworkResourceDetailView.prototype.initialLayout): Deleted.
+        (WI.NetworkResourceDetailView.prototype._showPreferredContentView): Deleted.
+        (WI.NetworkResourceDetailView.prototype._showContentViewForNavigationItem): Deleted.
+        (WI.NetworkResourceDetailView.prototype._navigationItemSelected): Deleted.
+        (WI.NetworkResourceDetailView.prototype._handleCloseButton): Deleted.
+
+        * UserInterface/Views/NetworkDetailView.js: Added.
+        (WI.NetworkDetailView):
+        (WI.NetworkDetailView.prototype.get representedObject):
+        (WI.NetworkDetailView.prototype.shown):
+        (WI.NetworkDetailView.prototype.hidden):
+        (WI.NetworkDetailView.prototype.dispose):
+        (WI.NetworkDetailView.prototype.willShowWithCookie):
+        (WI.NetworkDetailView.prototype.initialLayout):
+        (WI.NetworkDetailView.prototype.createDetailNavigationItem):
+        (WI.NetworkDetailView.prototype.detailNavigationItemForIdentifier):
+        (WI.NetworkDetailView.prototype.showContentViewForIdentifier):
+        (WI.NetworkDetailView.prototype._showPreferredContentView):
+        (WI.NetworkDetailView.prototype._navigationItemSelected):
+        (WI.NetworkDetailView.prototype._handleCloseButton):
+        * UserInterface/Views/NetworkDetailView.css: Added.
+        (.network-detail):
+        (.network-detail .navigation-bar):
+        (.network-detail .item.close > .glyph):
+        (.network-detail .item.close > .glyph:hover):
+        (.network-detail .item.close > .glyph:active):
+        (.network .network-detail .navigation-bar .item.radio.button.text-only):
+        (.network .network-detail .navigation-bar .item.radio.button.text-only.selected):
+        (.network-detail > .content-browser):
+        (@media (prefers-dark-interface)):
+        Create base class for detail views shown in the Network tab.
+
+        * UserInterface/Views/DOMNodeEventsContentView.js: Added.
+        (WI.DOMNodeEventsContentView):
+        (WI.DOMNodeEventsContentView.prototype.initialLayout):
+        (WI.DOMNodeEventsContentView.prototype.closed):
+        (WI.DOMNodeEventsContentView.prototype._handleDOMNodeDidFireEvent):
+        * UserInterface/Views/DOMNodeEventsContentView.css: Added.
+        (.dom-node-details.dom-events):
+
+        * UserInterface/Views/DOMEventsBreakdownView.js: Added.
+        (WI.DOMEventsBreakdownView):
+        (WI.DOMEventsBreakdownView.prototype.addEvent):
+        (WI.DOMEventsBreakdownView.prototype.initialLayout):
+        (WI.DOMEventsBreakdownView.prototype._populateTable.percentOfTotalTime):
+        (WI.DOMEventsBreakdownView.prototype._populateTable):
+        * UserInterface/Views/DOMEventsBreakdownView.css: Added.
+        (.waterfall-popover-content .dom-events-breakdown):
+        (.dom-events-breakdown):
+        (.dom-events-breakdown table):
+        (.dom-events-breakdown tr > :matches(th, td)):
+        (.dom-events-breakdown tbody > tr):
+        (.dom-events-breakdown .graph):
+        (.dom-events-breakdown .graph > :matches(.point, .area)):
+        (.dom-events-breakdown .graph > .point):
+        (.dom-events-breakdown .time):
+
+        * UserInterface/Views/ResourceTimingBreakdownView.css:
+        (.resource-timing-breakdown > table > tr.header:not(.total-row) > td): Added.
+        (.popover.waterfall-popover): Deleted.
+
+2018-10-10  Devin Rousso  <drousso@apple.com>
+
</ins><span class="cx">         Web Inspector: REGRESSION(r236853): Uncaught Exception: undefined is not an object (evaluating 'entry.resource')
</span><span class="cx">         https://bugs.webkit.org/show_bug.cgi?id=190442
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceWebInspectorUILocalizationsenlprojlocalizedStringsjs"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebInspectorUI/Localizations/en.lproj/localizedStrings.js (237027 => 237028)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebInspectorUI/Localizations/en.lproj/localizedStrings.js   2018-10-11 03:08:34 UTC (rev 237027)
+++ trunk/Source/WebInspectorUI/Localizations/en.lproj/localizedStrings.js      2018-10-11 04:13:17 UTC (rev 237028)
</span><span class="lines">@@ -243,6 +243,7 @@
</span><span class="cx"> localizedStrings["DNS"] = "DNS";
</span><span class="cx"> localizedStrings["DOM Content Loaded \u2014 %s"] = "DOM Content Loaded \u2014 %s";
</span><span class="cx"> localizedStrings["DOM Event"] = "DOM Event";
</span><ins>+localizedStrings["DOM Events"] = "DOM Events";
</ins><span class="cx"> localizedStrings["Damping"] = "Damping";
</span><span class="cx"> localizedStrings["Data"] = "Data";
</span><span class="cx"> localizedStrings["Data returned from the database is too large."] = "Data returned from the database is too large.";
</span></span></pre></div>
<a id="trunkSourceWebInspectorUIUserInterfaceBaseUtilitiesjs"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebInspectorUI/UserInterface/Base/Utilities.js (237027 => 237028)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebInspectorUI/UserInterface/Base/Utilities.js      2018-10-11 03:08:34 UTC (rev 237027)
+++ trunk/Source/WebInspectorUI/UserInterface/Base/Utilities.js 2018-10-11 04:13:17 UTC (rev 237028)
</span><span class="lines">@@ -464,6 +464,14 @@
</span><span class="cx">     }
</span><span class="cx"> });
</span><span class="cx"> 
</span><ins>+Object.defineProperty(Array.prototype, "adjacencies",
+{
+    value: function*() {
+        for (let i = 1; i < this.length; ++i)
+            yield [this[i - 1], this[i]];
+    }
+});
+
</ins><span class="cx"> Object.defineProperty(Array.prototype, "remove",
</span><span class="cx"> {
</span><span class="cx">     value(value)
</span></span></pre></div>
<a id="trunkSourceWebInspectorUIUserInterfaceControllersDOMManagerjs"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebInspectorUI/UserInterface/Controllers/DOMManager.js (237027 => 237028)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebInspectorUI/UserInterface/Controllers/DOMManager.js      2018-10-11 03:08:34 UTC (rev 237027)
+++ trunk/Source/WebInspectorUI/UserInterface/Controllers/DOMManager.js 2018-10-11 04:13:17 UTC (rev 237028)
</span><span class="lines">@@ -122,6 +122,17 @@
</span><span class="cx">         node.dispatchEventToListeners(WI.DOMNode.Event.EventListenersChanged);
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    didFireEvent(nodeId, eventName, timestamp)
+    {
+        // Called from WI.DOMObserver.
+
+        let node = this._idToDOMNode[nodeId];
+        if (!node)
+            return;
+
+        node.didFireEvent(eventName, timestamp);
+    }
+
</ins><span class="cx">     // Private
</span><span class="cx"> 
</span><span class="cx">     _wrapClientCallback(callback)
</span></span></pre></div>
<a id="trunkSourceWebInspectorUIUserInterfaceMainhtml"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebInspectorUI/UserInterface/Main.html (237027 => 237028)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebInspectorUI/UserInterface/Main.html      2018-10-11 03:08:34 UTC (rev 237027)
+++ trunk/Source/WebInspectorUI/UserInterface/Main.html 2018-10-11 04:13:17 UTC (rev 237028)
</span><span class="lines">@@ -66,7 +66,9 @@
</span><span class="cx">     <link rel="stylesheet" href="Views/ContentViewContainer.css">
</span><span class="cx">     <link rel="stylesheet" href="Views/ControlToolbarItem.css">
</span><span class="cx">     <link rel="stylesheet" href="Views/CookieStorageContentView.css">
</span><ins>+    <link rel="stylesheet" href="Views/DOMEventsBreakdownView.css">
</ins><span class="cx">     <link rel="stylesheet" href="Views/DOMNodeDetailsSidebarPanel.css">
</span><ins>+    <link rel="stylesheet" href="Views/DOMNodeEventsContentView.css">
</ins><span class="cx">     <link rel="stylesheet" href="Views/DOMNodeTreeElement.css">
</span><span class="cx">     <link rel="stylesheet" href="Views/DOMStorageContentView.css">
</span><span class="cx">     <link rel="stylesheet" href="Views/DOMTreeContentView.css">
</span><span class="lines">@@ -123,6 +125,7 @@
</span><span class="cx">     <link rel="stylesheet" href="Views/Main.css">
</span><span class="cx">     <link rel="stylesheet" href="Views/NavigationBar.css">
</span><span class="cx">     <link rel="stylesheet" href="Views/NavigationSidebarPanel.css">
</span><ins>+    <link rel="stylesheet" href="Views/NetworkDetailView.css">
</ins><span class="cx">     <link rel="stylesheet" href="Views/NetworkResourceDetailView.css">
</span><span class="cx">     <link rel="stylesheet" href="Views/NetworkTabContentView.css">
</span><span class="cx">     <link rel="stylesheet" href="Views/NetworkTableContentView.css">
</span><span class="lines">@@ -496,6 +499,7 @@
</span><span class="cx">     <script src="Views/DOMDetailsSidebarPanel.js"></script>
</span><span class="cx">     <script src="Views/FolderTreeElement.js"></script>
</span><span class="cx">     <script src="Views/FolderizedTreeElement.js"></script>
</span><ins>+    <script src="Views/NetworkDetailView.js"></script>
</ins><span class="cx">     <script src="Views/NetworkTabContentView.js"></script>
</span><span class="cx">     <script src="Views/NewTabContentView.js"></script>
</span><span class="cx">     <script src="Views/ObjectTreeBaseTreeElement.js"></script>
</span><span class="lines">@@ -578,7 +582,9 @@
</span><span class="cx">     <script src="Views/CookieStorageContentView.js"></script>
</span><span class="cx">     <script src="Views/CookieStorageTreeElement.js"></script>
</span><span class="cx">     <script src="Views/DOMBreakpointTreeElement.js"></script>
</span><ins>+    <script src="Views/DOMEventsBreakdownView.js"></script>
</ins><span class="cx">     <script src="Views/DOMNodeDetailsSidebarPanel.js"></script>
</span><ins>+    <script src="Views/DOMNodeEventsContentView.js"></script>
</ins><span class="cx">     <script src="Views/DOMNodeTreeElement.js"></script>
</span><span class="cx">     <script src="Views/DOMStorageContentView.js"></script>
</span><span class="cx">     <script src="Views/DOMStorageTreeElement.js"></script>
</span><span class="lines">@@ -661,6 +667,7 @@
</span><span class="cx">     <script src="Views/MemoryTimelineView.js"></script>
</span><span class="cx">     <script src="Views/MultipleScopeBarItem.js"></script>
</span><span class="cx">     <script src="Views/NavigationBar.js"></script>
</span><ins>+    <script src="Views/NetworkDOMNodeDetailView.js"></script>
</ins><span class="cx">     <script src="Views/NetworkResourceDetailView.js"></script>
</span><span class="cx">     <script src="Views/NetworkTableContentView.js"></script>
</span><span class="cx">     <script src="Views/NetworkTimelineOverviewGraph.js"></script>
</span></span></pre></div>
<a id="trunkSourceWebInspectorUIUserInterfaceModelsDOMNodejs"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebInspectorUI/UserInterface/Models/DOMNode.js (237027 => 237028)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebInspectorUI/UserInterface/Models/DOMNode.js      2018-10-11 03:08:34 UTC (rev 237027)
+++ trunk/Source/WebInspectorUI/UserInterface/Models/DOMNode.js 2018-10-11 04:13:17 UTC (rev 237028)
</span><span class="lines">@@ -137,10 +137,14 @@
</span><span class="cx">             this.name = payload.name;
</span><span class="cx">             this.value = payload.value;
</span><span class="cx">         }
</span><ins>+
+        this._domEvents = [];
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     // Public
</span><span class="cx"> 
</span><ins>+    get domEvents() { return this._domEvents; }
+
</ins><span class="cx">     get frameIdentifier()
</span><span class="cx">     {
</span><span class="cx">         return this._frameIdentifier || this.ownerDocument.frameIdentifier;
</span><span class="lines">@@ -697,6 +701,23 @@
</span><span class="cx">         return !!this.ownerSVGElement;
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    didFireEvent(eventName, timestamp)
+    {
+        // Called from WI.DOMManager.
+
+        this._addDOMEvent({
+            eventName,
+            timestamp: WI.timelineManager.computeElapsedTime(timestamp),
+        });
+    }
+
+    _addDOMEvent(domEvent)
+    {
+        this._domEvents.push(domEvent);
+
+        this.dispatchEventToListeners(WI.DOMNode.Event.DidFireEvent, {domEvent});
+    }
+
</ins><span class="cx">     _setAttributesPayload(attrs)
</span><span class="cx">     {
</span><span class="cx">         this._attributes = [];
</span><span class="lines">@@ -844,6 +865,7 @@
</span><span class="cx">     AttributeModified: "dom-node-attribute-modified",
</span><span class="cx">     AttributeRemoved: "dom-node-attribute-removed",
</span><span class="cx">     EventListenersChanged: "dom-node-event-listeners-changed",
</span><ins>+    DidFireEvent: "dom-node-did-fire-event",
</ins><span class="cx"> };
</span><span class="cx"> 
</span><span class="cx"> WI.DOMNode.PseudoElementType = {
</span></span></pre></div>
<a id="trunkSourceWebInspectorUIUserInterfaceProtocolDOMObserverjs"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebInspectorUI/UserInterface/Protocol/DOMObserver.js (237027 => 237028)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebInspectorUI/UserInterface/Protocol/DOMObserver.js        2018-10-11 03:08:34 UTC (rev 237027)
+++ trunk/Source/WebInspectorUI/UserInterface/Protocol/DOMObserver.js   2018-10-11 04:13:17 UTC (rev 237028)
</span><span class="lines">@@ -111,4 +111,9 @@
</span><span class="cx">     {
</span><span class="cx">         WI.domManager.willRemoveEventListener(nodeId);
</span><span class="cx">     }
</span><ins>+
+    didFireEvent(nodeId, eventName, timestamp)
+    {
+        WI.domManager.didFireEvent(nodeId, eventName, timestamp);
+    }
</ins><span class="cx"> };
</span></span></pre></div>
<a id="trunkSourceWebInspectorUIUserInterfaceViewsDOMEventsBreakdownViewcssfromrev237027trunkSourceWebInspectorUIUserInterfaceViewsResourceTimingBreakdownViewcss"></a>
<div class="copfile"><h4>Copied: trunk/Source/WebInspectorUI/UserInterface/Views/DOMEventsBreakdownView.css (from rev 237027, trunk/Source/WebInspectorUI/UserInterface/Views/ResourceTimingBreakdownView.css) (0 => 237028)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebInspectorUI/UserInterface/Views/DOMEventsBreakdownView.css                               (rev 0)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/DOMEventsBreakdownView.css  2018-10-11 04:13:17 UTC (rev 237028)
</span><span class="lines">@@ -0,0 +1,74 @@
</span><ins>+/*
+ * Copyright (C) 2018 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 APPLE INC. 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 INC. 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.
+ */
+
+.waterfall-popover-content .dom-events-breakdown {
+    -webkit-user-select: text;
+    max-height: 210px;
+    overflow-y: scroll;
+}
+
+.dom-events-breakdown {
+    margin: 5px;
+}
+
+.dom-events-breakdown table {
+    width: 100%;
+    border-collapse: collapse;
+}
+
+.dom-events-breakdown tr > :matches(th, td) {
+    padding: 2px 4px;
+    text-align: start;
+}
+
+.dom-events-breakdown tbody > tr {
+    /* FIXME: <https://webkit.org/b/94128> */
+    border-top: 1px solid lightgrey;
+}
+
+.dom-events-breakdown .graph {
+    position: relative;
+    width: 100%;
+    border-right: var(--point-size) solid transparent;
+    border-left: var(--point-size) solid transparent;
+
+    --point-size: 8px;
+}
+
+.dom-events-breakdown .graph > :matches(.point, .area) {
+    position: absolute;
+}
+
+.dom-events-breakdown .graph > .point {
+    top: calc(50% - (var(--point-size) / 2));
+    width: var(--point-size);
+    height: var(--point-size);
+    background-color: var(--selected-background-color);
+    border-radius: 50%;
+}
+
+.dom-events-breakdown .time {
+    text-align: end;
+}
</ins></span></pre></div>
<a id="trunkSourceWebInspectorUIUserInterfaceViewsDOMEventsBreakdownViewjs"></a>
<div class="addfile"><h4>Added: trunk/Source/WebInspectorUI/UserInterface/Views/DOMEventsBreakdownView.js (0 => 237028)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebInspectorUI/UserInterface/Views/DOMEventsBreakdownView.js                                (rev 0)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/DOMEventsBreakdownView.js   2018-10-11 04:13:17 UTC (rev 237028)
</span><span class="lines">@@ -0,0 +1,115 @@
</span><ins>+/*
+ * Copyright (C) 2018 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 APPLE INC. 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 INC. 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.
+ */
+
+WI.DOMEventsBreakdownView = class DOMEventsBreakdownView extends WI.View
+{
+    constructor(domEvents, {includeGraph, startTimestamp} = {})
+    {
+        super();
+
+        this._domEvents = domEvents;
+        this._includeGraph = includeGraph || false;
+        this._startTimestamp = startTimestamp || 0;
+
+        this._tableBodyElement = null;
+
+        this.element.classList.add("dom-events-breakdown");
+    }
+
+    // Public
+
+    addEvent(domEvent)
+    {
+        this._domEvents.push(domEvent);
+
+        this.soon._populateTable();
+    }
+
+    // Protected
+
+    initialLayout()
+    {
+        super.initialLayout();
+
+        let tableElement = this.element.appendChild(document.createElement("table"));
+
+        let headElement = tableElement.appendChild(document.createElement("thead"));
+
+        let headRowElement = headElement.appendChild(document.createElement("tr"));
+
+        let eventHeadCell = headRowElement.appendChild(document.createElement("th"));
+        eventHeadCell.textContent = WI.UIString("Event");
+
+        if (this._includeGraph)
+            headRowElement.appendChild(document.createElement("th"));
+
+        let timeHeadCell = headRowElement.appendChild(document.createElement("th"));
+        timeHeadCell.classList.add("time");
+        timeHeadCell.textContent = WI.UIString("Time");
+
+        this._tableBodyElement = tableElement.appendChild(document.createElement("tbody"));
+
+        this._populateTable();
+    }
+
+    // Private
+
+    _populateTable()
+    {
+        this._tableBodyElement.removeChildren();
+
+        let startTimestamp = this._domEvents[0].timestamp;
+        let endTimestamp = this._domEvents.lastValue.timestamp;
+        let totalTime = endTimestamp - startTimestamp;
+        let styleAttribute = WI.resolvedLayoutDirection() === WI.LayoutDirection.LTR ? "left" : "right";
+
+        function percentOfTotalTime(time) {
+            return time / totalTime * 100;
+        }
+
+        for (let domEvent of this._domEvents) {
+            let rowElement = this._tableBodyElement.appendChild(document.createElement("tr"));
+
+            let nameCell = rowElement.appendChild(document.createElement("td"));
+            nameCell.classList.add("name");
+            nameCell.textContent = domEvent.eventName;
+
+            if (this._includeGraph) {
+                let graphCell = rowElement.appendChild(document.createElement("td"));
+                graphCell.classList.add("graph");
+
+                let graphPoint = graphCell.appendChild(document.createElement("div"));
+                graphPoint.classList.add("point");
+                graphPoint.style.setProperty(styleAttribute, `calc(${percentOfTotalTime(domEvent.timestamp - startTimestamp)}% - (var(--point-size) / 2))`);
+            }
+
+            let timeCell = rowElement.appendChild(document.createElement("td"));
+            timeCell.classList.add("time");
+
+            const higherResolution = true;
+            timeCell.textContent = Number.secondsToString(domEvent.timestamp - this._startTimestamp, higherResolution);
+        }
+    }
+};
</ins></span></pre></div>
<a id="trunkSourceWebInspectorUIUserInterfaceViewsDOMNodeEventsContentViewcss"></a>
<div class="addfile"><h4>Added: trunk/Source/WebInspectorUI/UserInterface/Views/DOMNodeEventsContentView.css (0 => 237028)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebInspectorUI/UserInterface/Views/DOMNodeEventsContentView.css                             (rev 0)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/DOMNodeEventsContentView.css        2018-10-11 04:13:17 UTC (rev 237028)
</span><span class="lines">@@ -0,0 +1,28 @@
</span><ins>+/*
+ * Copyright (C) 2018 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 APPLE INC. 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 INC. 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.
+ */
+
+.dom-node-details.dom-events {
+    overflow-y: scroll;
+}
</ins></span></pre></div>
<a id="trunkSourceWebInspectorUIUserInterfaceViewsDOMNodeEventsContentViewjs"></a>
<div class="addfile"><h4>Added: trunk/Source/WebInspectorUI/UserInterface/Views/DOMNodeEventsContentView.js (0 => 237028)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebInspectorUI/UserInterface/Views/DOMNodeEventsContentView.js                              (rev 0)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/DOMNodeEventsContentView.js 2018-10-11 04:13:17 UTC (rev 237028)
</span><span class="lines">@@ -0,0 +1,74 @@
</span><ins>+/*
+ * Copyright (C) 2018 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 APPLE INC. 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 INC. 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.
+ */
+
+WI.DOMNodeEventsContentView = class DOMNodeEventsContentView extends WI.ContentView
+{
+    constructor(domNode, {startTimestamp} = {})
+    {
+        console.assert(domNode instanceof WI.DOMNode);
+
+        const representedObject = null;
+        super(representedObject);
+
+        this._domNode = domNode;
+        this._startTimestamp = startTimestamp || 0;
+
+        this.element.classList.add("dom-node-details", "dom-events");
+
+        this._breakdownView = null;
+    }
+
+    // Protected
+
+    initialLayout()
+    {
+        super.initialLayout();
+
+        this._breakdownView = new WI.DOMEventsBreakdownView(this._domNode.domEvents.slice(), {
+            includeGraph: true,
+            startTimestamp: this._startTimestamp,
+        });
+        this.addSubview(this._breakdownView);
+
+        this._domNode.addEventListener(WI.DOMNode.Event.DidFireEvent, this._handleDOMNodeDidFireEvent, this);
+    }
+
+    closed()
+    {
+        this._domNode.removeEventListener(null, null, this);
+
+        super.closed();
+    }
+
+    // Private
+
+    _handleDOMNodeDidFireEvent(event)
+    {
+        let {domEvent} = event.data;
+
+        if (this._breakdownView)
+            this._breakdownView.addEvent(domEvent);
+    }
+};
</ins></span></pre></div>
<a id="trunkSourceWebInspectorUIUserInterfaceViewsNetworkDOMNodeDetailViewjs"></a>
<div class="addfile"><h4>Added: trunk/Source/WebInspectorUI/UserInterface/Views/NetworkDOMNodeDetailView.js (0 => 237028)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebInspectorUI/UserInterface/Views/NetworkDOMNodeDetailView.js                              (rev 0)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/NetworkDOMNodeDetailView.js 2018-10-11 04:13:17 UTC (rev 237028)
</span><span class="lines">@@ -0,0 +1,67 @@
</span><ins>+/*
+ * Copyright (C) 2018 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 APPLE INC. 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 INC. 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.
+ */
+
+WI.NetworkDOMNodeDetailView = class NetworkDOMNodeDetailView extends WI.NetworkDetailView
+{
+    constructor(domNode, delegate, {startTimestamp} = {})
+    {
+        console.assert(domNode instanceof WI.DOMNode);
+
+        super(domNode, delegate);
+
+        this._startTimestamp = startTimestamp || 0;
+
+        this.element.classList.add("dom-node");
+
+        this._domEventsContentView = null;
+    }
+
+    // Protected
+
+    initialLayout()
+    {
+        this.createDetailNavigationItem("dom-events", WI.UIString("DOM Events"));
+
+        super.initialLayout();
+    }
+
+    // Private
+
+    showContentViewForIdentifier(identifier)
+    {
+        super.showContentViewForIdentifier(identifier);
+
+        switch (identifier) {
+        case "dom-events":
+            if (!this._domEventsContentView) {
+                this._domEventsContentView = new WI.DOMNodeEventsContentView(this.representedObject, {
+                    startTimestamp: this._startTimestamp,
+                });
+            }
+            this._contentBrowser.showContentView(this._domEventsContentView, this._contentViewCookie);
+            break;
+        }
+    }
+};
</ins></span></pre></div>
<a id="trunkSourceWebInspectorUIUserInterfaceViewsNetworkDetailViewcssfromrev237027trunkSourceWebInspectorUIUserInterfaceViewsNetworkResourceDetailViewcss"></a>
<div class="copfile"><h4>Copied: trunk/Source/WebInspectorUI/UserInterface/Views/NetworkDetailView.css (from rev 237027, trunk/Source/WebInspectorUI/UserInterface/Views/NetworkResourceDetailView.css) (0 => 237028)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebInspectorUI/UserInterface/Views/NetworkDetailView.css                            (rev 0)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/NetworkDetailView.css       2018-10-11 04:13:17 UTC (rev 237028)
</span><span class="lines">@@ -0,0 +1,88 @@
</span><ins>+/*
+ * Copyright (C) 2018 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 APPLE INC. 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 INC. 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.
+ */
+
+.network-detail {
+    position: absolute;
+    top: 0;
+    left: 0;
+    right: 0;
+    bottom: 0;
+    /* left or right set by NetworkTableView on display / resize */
+    z-index: 10;
+    background-color: white;
+}
+
+.network-detail .navigation-bar {
+    position: -webkit-sticky;
+    top: 0;
+    z-index: 1;
+}
+
+.network-detail .item.close > .glyph {
+    border-radius: 2px;
+    padding: 2px;
+    background: white;
+}
+
+.network-detail .item.close > .glyph:hover {
+    background-color: var(--button-background-color-hover);
+}
+
+.network-detail .item.close > .glyph:active {
+    background-color: var(--button-background-color-pressed);
+}
+
+.network .network-detail .navigation-bar .item.radio.button.text-only {
+    color: inherit;
+    background-color: inherit;
+}
+
+.network .network-detail .navigation-bar .item.radio.button.text-only.selected {
+    color: var(--selected-background-color);
+    background-color: white;
+}
+
+.network-detail > .content-browser {
+    position: absolute;
+    top: 0;
+    left: 0;
+    right: 0;
+    bottom: 0;
+}
+
+@media (prefers-dark-interface) {
+    .network-detail {
+        background-color: var(--background-color);
+    }
+
+    .network-detail .item.close > .glyph {
+        background-color: hsla(0, 0%, 100%, 0.2);
+    }
+
+    .network .network-detail .navigation-bar .item.radio.button.text-only.selected {
+        background-color: unset;
+        color: var(--glyph-color-active);
+    }
+}
</ins></span></pre></div>
<a id="trunkSourceWebInspectorUIUserInterfaceViewsNetworkDetailViewjs"></a>
<div class="addfile"><h4>Added: trunk/Source/WebInspectorUI/UserInterface/Views/NetworkDetailView.js (0 => 237028)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebInspectorUI/UserInterface/Views/NetworkDetailView.js                             (rev 0)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/NetworkDetailView.js        2018-10-11 04:13:17 UTC (rev 237028)
</span><span class="lines">@@ -0,0 +1,172 @@
</span><ins>+/*
+ * Copyright (C) 2018 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 APPLE INC. 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 INC. 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.
+ */
+
+WI.NetworkDetailView = class NetworkDetailView extends WI.View
+{
+    constructor(representedObject, delegate)
+    {
+        super();
+
+        this._representedObject = representedObject;
+        this._delegate = delegate || null;
+
+        this.element.classList.add("network-detail");
+
+        this._contentBrowser = null;
+
+        this._detailNavigationItemMap = new Map;
+
+        this._contentViewCookie = null;
+    }
+
+    // Public
+
+    get representedObject() { return this._representedObject; }
+
+    shown()
+    {
+        if (!this._contentBrowser)
+            return;
+
+        this._showPreferredContentView();
+
+        if (this._contentViewCookie) {
+            this._contentBrowser.showContentView(this._contentBrowser.currentContentView, this._contentViewCookie);
+            this._contentViewCookie = null;
+        }
+
+        this._contentBrowser.shown();
+    }
+
+    hidden()
+    {
+        this._contentBrowser.hidden();
+    }
+
+    dispose()
+    {
+        this._delegate = null;
+
+        this._contentBrowser.contentViewContainer.closeAllContentViews();
+    }
+
+    willShowWithCookie(cookie)
+    {
+        this._contentViewCookie = cookie;
+    }
+
+    // Protected
+
+    initialLayout()
+    {
+        let closeNavigationItem = new WI.ButtonNavigationItem("close", WI.UIString("Close detail view"), "Images/CloseLarge.svg", 16, 16);
+        closeNavigationItem.addEventListener(WI.ButtonNavigationItem.Event.Clicked, this._handleCloseButton.bind(this));
+        closeNavigationItem.visibilityPriority = WI.NavigationItem.VisibilityPriority.High;
+
+        let contentViewNavigationItemsGroup = new WI.GroupNavigationItem;
+        let contentViewNavigationItemsFlexItem = new WI.FlexibleSpaceNavigationItem(contentViewNavigationItemsGroup, WI.FlexibleSpaceNavigationItem.Align.End);
+        contentViewNavigationItemsFlexItem.visibilityPriority = WI.NavigationItem.VisibilityPriority.Low;
+
+        const element = null;
+        const disableBackForward = true;
+        const disableFindBanner = false;
+        this._contentBrowser = new WI.ContentBrowser(element, this, disableBackForward, disableFindBanner, contentViewNavigationItemsFlexItem, contentViewNavigationItemsGroup);
+
+        // Insert all of our custom navigation items at the start of the ContentBrowser's NavigationBar.
+        let index = 0;
+        this._contentBrowser.navigationBar.insertNavigationItem(closeNavigationItem, index++);
+        this._contentBrowser.navigationBar.insertNavigationItem(new WI.FlexibleSpaceNavigationItem, index++);
+        for (let detailNavigationItem of this._detailNavigationItemMap.values())
+            this._contentBrowser.navigationBar.insertNavigationItem(detailNavigationItem, index++);
+
+        this._contentBrowser.navigationBar.addEventListener(WI.NavigationBar.Event.NavigationItemSelected, this._navigationItemSelected, this);
+
+        this.addSubview(this._contentBrowser);
+
+        this._showPreferredContentView();
+    }
+
+    createDetailNavigationItem(identifier, toolTip)
+    {
+        this._detailNavigationItemMap.set(identifier, new WI.RadioButtonNavigationItem(identifier, toolTip));
+    }
+
+    detailNavigationItemForIdentifier(identifier)
+    {
+        return this._detailNavigationItemMap.get(identifier);
+    }
+
+    showContentViewForIdentifier(identifier)
+    {
+        // Implemented by subclasses.
+    }
+
+    // Private
+
+    _showPreferredContentView()
+    {
+        let detailNavigationItems = Array.from(this._detailNavigationItemMap.values());
+
+        // Restore the preferred navigation item.
+        let firstNavigationItem = null;
+        let defaultIdentifier = WI.settings.selectedNetworkDetailContentViewIdentifier.value;
+        for (let navigationItem of this._contentBrowser.navigationBar.navigationItems) {
+            if (!(navigationItem instanceof WI.RadioButtonNavigationItem))
+                continue;
+
+            if (!detailNavigationItems.includes(navigationItem))
+                continue;
+
+            if (!firstNavigationItem)
+                firstNavigationItem = navigationItem;
+
+            if (navigationItem.identifier === defaultIdentifier) {
+                this._contentBrowser.navigationBar.selectedNavigationItem = navigationItem;
+                return;
+            }
+        }
+
+        console.assert(firstNavigationItem, "Should have found at least one navigation item above");
+        this._contentBrowser.navigationBar.selectedNavigationItem = firstNavigationItem;
+    }
+
+    _navigationItemSelected(event)
+    {
+        let navigationItem = event.target.selectedNavigationItem;
+        if (!(navigationItem instanceof WI.RadioButtonNavigationItem))
+            return;
+
+        this.showContentViewForIdentifier(navigationItem.identifier);
+
+        console.assert(navigationItem.identifier);
+        WI.settings.selectedNetworkDetailContentViewIdentifier.value = navigationItem.identifier;
+    }
+
+    _handleCloseButton(event)
+    {
+        if (this._delegate && this._delegate.networkDetailViewClose)
+            this._delegate.networkDetailViewClose(this);
+    }
+};
</ins></span></pre></div>
<a id="trunkSourceWebInspectorUIUserInterfaceViewsNetworkResourceDetailViewcss"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebInspectorUI/UserInterface/Views/NetworkResourceDetailView.css (237027 => 237028)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebInspectorUI/UserInterface/Views/NetworkResourceDetailView.css    2018-10-11 03:08:34 UTC (rev 237027)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/NetworkResourceDetailView.css       2018-10-11 04:13:17 UTC (rev 237028)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> /*
</span><del>- * Copyright (C) 2017 Apple Inc. All rights reserved.
</del><ins>+ * Copyright (C) 2017-2018 Apple Inc. All rights reserved.
</ins><span class="cx">  *
</span><span class="cx">  * Redistribution and use in source and binary forms, with or without
</span><span class="cx">  * modification, are permitted provided that the following conditions
</span><span class="lines">@@ -23,55 +23,6 @@
</span><span class="cx">  * THE POSSIBILITY OF SUCH DAMAGE.
</span><span class="cx">  */
</span><span class="cx"> 
</span><del>-.network-resource-detail {
-    position: absolute;
-    top: 0;
-    left: 0;
-    right: 0;
-    bottom: 0;
-    /* left or right set by NetworkTableView on display / resize */
-    z-index: 10;
-    background-color: var(--background-color);
-}
-
-.network-resource-detail .navigation-bar {
-    position: -webkit-sticky;
-    top: 0;
-    z-index: 1;
-}
-
-.network-resource-detail .item.close > .glyph {
-    border-radius: 2px;
-    padding: 2px;
-    background: white;
-}
-
-.network-resource-detail .item.close > .glyph:hover {
-    background-color: var(--button-background-color-hover);
-}
-
-.network-resource-detail .item.close > .glyph:active {
-    background-color: var(--button-background-color-pressed);
-}
-
-.network .network-resource-detail .navigation-bar .item.radio.button.text-only {
-    color: inherit;
-    background-color: inherit;
-}
-
-.network .network-resource-detail .navigation-bar .item.radio.button.text-only.selected {
-    color: var(--selected-background-color);
-    background-color: var(--background-color);
-}
-
-.network-resource-detail > .content-browser {
-    position: absolute;
-    top: 0;
-    left: 0;
-    right: 0;
-    bottom: 0;
-}
-
</del><span class="cx"> .content-view.resource-details {
</span><span class="cx">     position: absolute;
</span><span class="cx">     top: 0;
</span><span class="lines">@@ -85,14 +36,3 @@
</span><span class="cx">     -webkit-user-select: text;
</span><span class="cx">     white-space: nowrap;
</span><span class="cx"> }
</span><del>-
-@media (prefers-dark-interface) {
-    .network-resource-detail .item.close > .glyph {
-        background-color: hsla(0, 0%, 100%, 0.2);
-    }
-
-    .network .network-resource-detail .navigation-bar .item.radio.button.text-only.selected {
-        background-color: unset;
-        color: var(--glyph-color-active);
-    }
-}
</del></span></pre></div>
<a id="trunkSourceWebInspectorUIUserInterfaceViewsNetworkResourceDetailViewjs"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebInspectorUI/UserInterface/Views/NetworkResourceDetailView.js (237027 => 237028)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebInspectorUI/UserInterface/Views/NetworkResourceDetailView.js     2018-10-11 03:08:34 UTC (rev 237027)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/NetworkResourceDetailView.js        2018-10-11 04:13:17 UTC (rev 237028)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> /*
</span><del>- * Copyright (C) 2017 Apple Inc. All rights reserved.
</del><ins>+ * Copyright (C) 2017-2018 Apple Inc. All rights reserved.
</ins><span class="cx">  *
</span><span class="cx">  * Redistribution and use in source and binary forms, with or without
</span><span class="cx">  * modification, are permitted provided that the following conditions
</span><span class="lines">@@ -23,73 +23,38 @@
</span><span class="cx">  * THE POSSIBILITY OF SUCH DAMAGE.
</span><span class="cx">  */
</span><span class="cx"> 
</span><del>-WI.NetworkResourceDetailView = class NetworkResourceDetailView extends WI.View
</del><ins>+WI.NetworkResourceDetailView = class NetworkResourceDetailView extends WI.NetworkDetailView
</ins><span class="cx"> {
</span><span class="cx">     constructor(resource, delegate)
</span><span class="cx">     {
</span><del>-        super();
-
</del><span class="cx">         console.assert(resource instanceof WI.Resource);
</span><span class="cx"> 
</span><del>-        this._resource = resource;
-        this._delegate = delegate || null;
</del><ins>+        super(resource, delegate);
</ins><span class="cx"> 
</span><del>-        this.element.classList.add("network-resource-detail");
</del><ins>+        this.element.classList.add("resource");
</ins><span class="cx"> 
</span><del>-        this._contentBrowser = null;
</del><span class="cx">         this._resourceContentView = null;
</span><span class="cx">         this._headersContentView = null;
</span><span class="cx">         this._cookiesContentView = null;
</span><span class="cx">         this._sizesContentView = null;
</span><span class="cx">         this._timingContentView = null;
</span><del>-
-        this._contentViewCookie = null;
</del><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     // Public
</span><span class="cx"> 
</span><del>-    get resource() { return this._resource; }
-
</del><span class="cx">     shown()
</span><span class="cx">     {
</span><del>-        if (!this._contentBrowser)
-            return;
</del><ins>+        if (this._contentBrowser && this._contentViewCookie && "lineNumber" in this._contentViewCookie && "columnNumber" in this._contentViewCookie)
+            this._contentBrowser.navigationBar.selectedNavigationItem = this.detailNavigationItemForIdentifier("preview");
</ins><span class="cx"> 
</span><del>-        this._showPreferredContentView();
-
-        if (this._contentViewCookie) {
-            if ("lineNumber" in this._contentViewCookie && "columnNumber" in this._contentViewCookie)
-                this._contentBrowser.navigationBar.selectedNavigationItem = this._previewNavigationItem;
-
-            this._contentBrowser.showContentView(this._contentBrowser.currentContentView, this._contentViewCookie);
-            this._contentViewCookie = null;
-        }
-
-        this._contentBrowser.shown();
</del><ins>+        super.shown();
</ins><span class="cx">     }
</span><span class="cx"> 
</span><del>-    hidden()
-    {
-        this._contentBrowser.hidden();
-    }
-
-    dispose()
-    {
-        this._delegate = null;
-
-        this._contentBrowser.contentViewContainer.closeAllContentViews();
-    }
-
-    willShowWithCookie(cookie)
-    {
-        this._contentViewCookie = cookie;
-    }
-
</del><span class="cx">     // ResourceHeadersContentView delegate
</span><span class="cx"> 
</span><span class="cx">     headersContentViewGoToRequestData(headersContentView)
</span><span class="cx">     {
</span><del>-        this._contentBrowser.navigationBar.selectedNavigationItem = this._previewNavigationItem;
</del><ins>+        this._contentBrowser.navigationBar.selectedNavigationItem = this.detailNavigationItemForIdentifier("preview");
</ins><span class="cx"> 
</span><span class="cx">         this._resourceContentView.showRequest();
</span><span class="cx">     }
</span><span class="lines">@@ -98,12 +63,12 @@
</span><span class="cx"> 
</span><span class="cx">     sizesContentViewGoToHeaders(metricsContentView)
</span><span class="cx">     {
</span><del>-        this._contentBrowser.navigationBar.selectedNavigationItem = this._headersNavigationItem;
</del><ins>+        this._contentBrowser.navigationBar.selectedNavigationItem = this.detailNavigationItemForIdentifier("headers");
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     sizesContentViewGoToRequestBody(metricsContentView)
</span><span class="cx">     {
</span><del>-        this._contentBrowser.navigationBar.selectedNavigationItem = this._previewNavigationItem;
</del><ins>+        this._contentBrowser.navigationBar.selectedNavigationItem = this.detailNavigationItemForIdentifier("preview");
</ins><span class="cx"> 
</span><span class="cx">         this._resourceContentView.showRequest();
</span><span class="cx">     }
</span><span class="lines">@@ -110,7 +75,7 @@
</span><span class="cx"> 
</span><span class="cx">     sizesContentViewGoToResponseBody(metricsContentView)
</span><span class="cx">     {
</span><del>-        this._contentBrowser.navigationBar.selectedNavigationItem = this._previewNavigationItem;
</del><ins>+        this._contentBrowser.navigationBar.selectedNavigationItem = this.detailNavigationItemForIdentifier("preview");
</ins><span class="cx"> 
</span><span class="cx">         this._resourceContentView.showResponse();
</span><span class="cx">     }
</span><span class="lines">@@ -119,101 +84,48 @@
</span><span class="cx"> 
</span><span class="cx">     initialLayout()
</span><span class="cx">     {
</span><del>-        let closeNavigationItem = new WI.ButtonNavigationItem("close", WI.UIString("Close detail view"), "Images/CloseLarge.svg", 16, 16);
-        closeNavigationItem.addEventListener(WI.ButtonNavigationItem.Event.Clicked, this._handleCloseButton.bind(this));
-        closeNavigationItem.visibilityPriority = WI.NavigationItem.VisibilityPriority.High;
</del><ins>+        this.createDetailNavigationItem("preview", WI.UIString("Preview"));
+        this.createDetailNavigationItem("headers", WI.UIString("Headers"));
+        this.createDetailNavigationItem("cookies", WI.UIString("Cookies"));
+        this.createDetailNavigationItem("sizes", WI.UIString("Sizes"));
+        this.createDetailNavigationItem("timing", WI.UIString("Timing"));
</ins><span class="cx"> 
</span><del>-        let contentViewNavigationItemsGroup = new WI.GroupNavigationItem;
-        let contentViewNavigationItemsFlexItem = new WI.FlexibleSpaceNavigationItem(contentViewNavigationItemsGroup, WI.FlexibleSpaceNavigationItem.Align.End);
-        contentViewNavigationItemsFlexItem.visibilityPriority = WI.NavigationItem.VisibilityPriority.Low;
-
-        const disableBackForward = true;
-        const disableFindBanner = false;
-        this._contentBrowser = new WI.ContentBrowser(null, this, disableBackForward, disableFindBanner, contentViewNavigationItemsFlexItem, contentViewNavigationItemsGroup);
-
-        this._previewNavigationItem = new WI.RadioButtonNavigationItem("preview", WI.UIString("Preview"));
-        this._headersNavigationItem = new WI.RadioButtonNavigationItem("headers", WI.UIString("Headers"));
-        this._cookiesNavigationItem = new WI.RadioButtonNavigationItem("cookies", WI.UIString("Cookies"));
-        this._sizesNavigationItem = new WI.RadioButtonNavigationItem("sizes", WI.UIString("Sizes"));
-        this._timingNavigationItem = new WI.RadioButtonNavigationItem("timing", WI.UIString("Timing"));
-
-        // Insert all of our custom navigation items at the start of the ContentBrowser's NavigationBar.
-        let index = 0;
-        this._contentBrowser.navigationBar.insertNavigationItem(closeNavigationItem, index++);
-        this._contentBrowser.navigationBar.insertNavigationItem(new WI.FlexibleSpaceNavigationItem, index++);
-        this._contentBrowser.navigationBar.insertNavigationItem(this._previewNavigationItem, index++);
-        this._contentBrowser.navigationBar.insertNavigationItem(this._headersNavigationItem, index++);
-        this._contentBrowser.navigationBar.insertNavigationItem(this._cookiesNavigationItem, index++);
-        this._contentBrowser.navigationBar.insertNavigationItem(this._sizesNavigationItem, index++);
-        this._contentBrowser.navigationBar.insertNavigationItem(this._timingNavigationItem, index++);
-        this._contentBrowser.navigationBar.addEventListener(WI.NavigationBar.Event.NavigationItemSelected, this._navigationItemSelected, this);
-
-        this.addSubview(this._contentBrowser);
-
-        this._showPreferredContentView();
</del><ins>+        super.initialLayout();
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     // Private
</span><span class="cx"> 
</span><del>-    _showPreferredContentView()
</del><ins>+    showContentViewForIdentifier(identifier)
</ins><span class="cx">     {
</span><del>-        // Restore the preferred navigation item.
-        let firstNavigationItem = null;
-        let defaultIdentifier = WI.settings.selectedNetworkDetailContentViewIdentifier.value;
-        for (let navigationItem of this._contentBrowser.navigationBar.navigationItems) {
-            if (!(navigationItem instanceof WI.RadioButtonNavigationItem))
-                continue;
</del><ins>+        super.showContentViewForIdentifier(identifier);
</ins><span class="cx"> 
</span><del>-            if (navigationItem !== this._previewNavigationItem
-                && navigationItem !== this._headersNavigationItem
-                && navigationItem !== this._cookiesNavigationItem
-                && navigationItem !== this._sizesNavigationItem
-                && navigationItem !== this._timingNavigationItem)
-                continue;
-
-            if (!firstNavigationItem)
-                firstNavigationItem = navigationItem;
-
-            if (navigationItem.identifier === defaultIdentifier) {
-                this._contentBrowser.navigationBar.selectedNavigationItem = navigationItem;
-                return;
-            }
-        }
-
-        console.assert(firstNavigationItem, "Should have found at least one navigation item above");
-        this._contentBrowser.navigationBar.selectedNavigationItem = firstNavigationItem;
-    }
-
-    _showContentViewForNavigationItem(navigationItem)
-    {
-        let identifier = navigationItem.identifier;
</del><span class="cx">         if (this._contentViewCookie && "lineNumber" in this._contentViewCookie && "columnNumber" in this._contentViewCookie)
</span><del>-            identifier = this._previewNavigationItem.identifier;
</del><ins>+            identifier = "preview";
</ins><span class="cx"> 
</span><span class="cx">         switch (identifier) {
</span><span class="cx">         case "preview":
</span><span class="cx">             if (!this._resourceContentView)
</span><del>-                this._resourceContentView = this._contentBrowser.showContentViewForRepresentedObject(this._resource);
</del><ins>+                this._resourceContentView = this._contentBrowser.showContentViewForRepresentedObject(this.representedObject);
</ins><span class="cx">             this._contentBrowser.showContentView(this._resourceContentView, this._contentViewCookie);
</span><span class="cx">             break;
</span><span class="cx">         case "headers":
</span><span class="cx">             if (!this._headersContentView)
</span><del>-                this._headersContentView = new WI.ResourceHeadersContentView(this._resource, this);
</del><ins>+                this._headersContentView = new WI.ResourceHeadersContentView(this.representedObject, this);
</ins><span class="cx">             this._contentBrowser.showContentView(this._headersContentView, this._contentViewCookie);
</span><span class="cx">             break;
</span><span class="cx">         case "cookies":
</span><span class="cx">             if (!this._cookiesContentView)
</span><del>-                this._cookiesContentView = new WI.ResourceCookiesContentView(this._resource);
</del><ins>+                this._cookiesContentView = new WI.ResourceCookiesContentView(this.representedObject);
</ins><span class="cx">             this._contentBrowser.showContentView(this._cookiesContentView, this._contentViewCookie);
</span><span class="cx">             break;
</span><span class="cx">         case "sizes":
</span><span class="cx">             if (!this._sizesContentView)
</span><del>-                this._sizesContentView = new WI.ResourceSizesContentView(this._resource, this);
</del><ins>+                this._sizesContentView = new WI.ResourceSizesContentView(this.representedObject, this);
</ins><span class="cx">             this._contentBrowser.showContentView(this._sizesContentView, this._contentViewCookie);
</span><span class="cx">             break;
</span><span class="cx">         case "timing":
</span><span class="cx">             if (!this._timingContentView)
</span><del>-                this._timingContentView = new WI.ResourceTimingContentView(this._resource);
</del><ins>+                this._timingContentView = new WI.ResourceTimingContentView(this.representedObject);
</ins><span class="cx">             this._contentBrowser.showContentView(this._timingContentView, this._contentViewCookie);
</span><span class="cx">             break;
</span><span class="cx">         }
</span><span class="lines">@@ -220,22 +132,4 @@
</span><span class="cx"> 
</span><span class="cx">         this._contentViewCookie = null;
</span><span class="cx">     }
</span><del>-
-    _navigationItemSelected(event)
-    {
-        let navigationItem = event.target.selectedNavigationItem;
-        if (!(navigationItem instanceof WI.RadioButtonNavigationItem))
-            return;
-
-        this._showContentViewForNavigationItem(navigationItem);
-
-        console.assert(navigationItem.identifier);
-        WI.settings.selectedNetworkDetailContentViewIdentifier.value = navigationItem.identifier;
-    }
-
-    _handleCloseButton(event)
-    {
-        if (this._delegate && this._delegate.networkResourceDetailViewClose)
-            this._delegate.networkResourceDetailViewClose(this);
-    }
</del><span class="cx"> };
</span></span></pre></div>
<a id="trunkSourceWebInspectorUIUserInterfaceViewsNetworkTableContentViewcss"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebInspectorUI/UserInterface/Views/NetworkTableContentView.css (237027 => 237028)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebInspectorUI/UserInterface/Views/NetworkTableContentView.css      2018-10-11 03:08:34 UTC (rev 237027)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/NetworkTableContentView.css 2018-10-11 04:13:17 UTC (rev 237028)
</span><span class="lines">@@ -23,6 +23,10 @@
</span><span class="cx">  * THE POSSIBILITY OF SUCH DAMAGE.
</span><span class="cx">  */
</span><span class="cx"> 
</span><ins>+.content-view.network .network-table {
+    --node-waterfall-dom-event-size: 8px; /* Keep this in sync with `domEventElementSize`. */
+}
+
</ins><span class="cx"> .content-view.network .navigation-bar .filter-bar {
</span><span class="cx">     background: none;
</span><span class="cx"> }
</span><span class="lines">@@ -152,6 +156,25 @@
</span><span class="cx">     bottom: 0;
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+.network-table :not(.header) .cell.waterfall .waterfall-container > .dom-event {
+    position: absolute;
+    top: calc(50% - (var(--node-waterfall-dom-event-size) / 2));
+    min-width: var(--node-waterfall-dom-event-size);
+    height: var(--node-waterfall-dom-event-size);
+    background-color: var(--selected-background-color);
+    border-radius: calc(var(--node-waterfall-dom-event-size) / 2);
+}
+
+.network-table :not(.header) .cell.waterfall .waterfall-container > .dom-activity {
+    position: absolute;
+    top: calc(50% - 0.5px);
+    border-top: 1px dashed var(--selected-background-color);
+}
+
+.network-table :not(.header) .cell.waterfall .waterfall-container > .dom-activity.playing {
+    border-top-style: solid;
+}
+
</ins><span class="cx"> .network-table .timeline-ruler {
</span><span class="cx">     position: absolute;
</span><span class="cx">     top: 0;
</span></span></pre></div>
<a id="trunkSourceWebInspectorUIUserInterfaceViewsNetworkTableContentViewjs"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebInspectorUI/UserInterface/Views/NetworkTableContentView.js (237027 => 237028)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebInspectorUI/UserInterface/Views/NetworkTableContentView.js       2018-10-11 03:08:34 UTC (rev 237027)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/NetworkTableContentView.js  2018-10-11 04:13:17 UTC (rev 237028)
</span><span class="lines">@@ -40,9 +40,9 @@
</span><span class="cx">         this._table = null;
</span><span class="cx">         this._nameColumnWidthSetting = new WI.Setting("network-table-content-view-name-column-width", 250);
</span><span class="cx"> 
</span><del>-        this._selectedResource = null;
-        this._resourceDetailView = null;
-        this._resourceDetailViewMap = new Map;
</del><ins>+        this._selectedObject = null;
+        this._detailView = null;
+        this._detailViewMap = new Map;
</ins><span class="cx"> 
</span><span class="cx">         this._domNodeEntries = new Map;
</span><span class="cx"> 
</span><span class="lines">@@ -223,8 +223,8 @@
</span><span class="cx">     {
</span><span class="cx">         super.shown();
</span><span class="cx"> 
</span><del>-        if (this._resourceDetailView)
-            this._resourceDetailView.shown();
</del><ins>+        if (this._detailView)
+            this._detailView.shown();
</ins><span class="cx"> 
</span><span class="cx">         if (this._table)
</span><span class="cx">             this._table.restoreScrollPosition();
</span><span class="lines">@@ -234,8 +234,8 @@
</span><span class="cx">     {
</span><span class="cx">         this._hidePopover();
</span><span class="cx"> 
</span><del>-        if (this._resourceDetailView)
-            this._resourceDetailView.hidden();
</del><ins>+        if (this._detailView)
+            this._detailView.hidden();
</ins><span class="cx"> 
</span><span class="cx">         super.hidden();
</span><span class="cx">     }
</span><span class="lines">@@ -242,14 +242,14 @@
</span><span class="cx"> 
</span><span class="cx">     closed()
</span><span class="cx">     {
</span><del>-        for (let detailView of this._resourceDetailViewMap.values())
</del><ins>+        for (let detailView of this._detailViewMap.values())
</ins><span class="cx">             detailView.dispose();
</span><del>-        this._resourceDetailViewMap.clear();
</del><ins>+        this._detailViewMap.clear();
</ins><span class="cx"> 
</span><span class="cx">         this._domNodeEntries.clear();
</span><span class="cx"> 
</span><span class="cx">         this._hidePopover();
</span><del>-        this._hideResourceDetailView();
</del><ins>+        this._hideDetailView();
</ins><span class="cx"> 
</span><span class="cx">         WI.Frame.removeEventListener(null, null, this);
</span><span class="cx">         WI.Resource.removeEventListener(null, null, this);
</span><span class="lines">@@ -267,9 +267,9 @@
</span><span class="cx">         this._filteredEntries = [];
</span><span class="cx">         this._pendingInsertions = [];
</span><span class="cx"> 
</span><del>-        for (let detailView of this._resourceDetailViewMap.values())
</del><ins>+        for (let detailView of this._detailViewMap.values())
</ins><span class="cx">             detailView.dispose();
</span><del>-        this._resourceDetailViewMap.clear();
</del><ins>+        this._detailViewMap.clear();
</ins><span class="cx"> 
</span><span class="cx">         this._domNodeEntries.clear();
</span><span class="cx"> 
</span><span class="lines">@@ -282,7 +282,7 @@
</span><span class="cx">             this._selectedResource = null;
</span><span class="cx">             this._table.reloadData();
</span><span class="cx">             this._hidePopover();
</span><del>-            this._hideResourceDetailView();
</del><ins>+            this._hideDetailView();
</ins><span class="cx">         }
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="lines">@@ -290,11 +290,11 @@
</span><span class="cx">     {
</span><span class="cx">         console.assert(representedObject instanceof WI.Resource);
</span><span class="cx"> 
</span><del>-        let rowIndex = this._rowIndexForResource(representedObject);
</del><ins>+        let rowIndex = this._rowIndexForRepresentedObject(representedObject);
</ins><span class="cx">         if (rowIndex === -1) {
</span><span class="cx">             this._selectedResource = null;
</span><span class="cx">             this._table.deselectAll();
</span><del>-            this._hideResourceDetailView();
</del><ins>+            this._hideDetailView();
</ins><span class="cx">             return;
</span><span class="cx">         }
</span><span class="cx"> 
</span><span class="lines">@@ -303,13 +303,13 @@
</span><span class="cx">         this._showingRepresentedObjectCookie = null;
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    // NetworkResourceDetailView delegate
</del><ins>+    // NetworkDetailView delegate
</ins><span class="cx"> 
</span><del>-    networkResourceDetailViewClose(resourceDetailView)
</del><ins>+    networkDetailViewClose(networkDetailView)
</ins><span class="cx">     {
</span><span class="cx">         this._selectedResource = null;
</span><span class="cx">         this._table.deselectAll();
</span><del>-        this._hideResourceDetailView();
</del><ins>+        this._hideDetailView();
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     // Table dataSource
</span><span class="lines">@@ -326,7 +326,7 @@
</span><span class="cx">         if (!this._entriesSortComparator)
</span><span class="cx">             return;
</span><span class="cx"> 
</span><del>-        this._hideResourceDetailView();
</del><ins>+        this._hideDetailView();
</ins><span class="cx"> 
</span><span class="cx">         for (let nodeEntry of this._domNodeEntries.values())
</span><span class="cx">             nodeEntry.initiatedResourceEntries.sort(this._entriesSortComparator);
</span><span class="lines">@@ -362,20 +362,20 @@
</span><span class="cx">     {
</span><span class="cx">         let rowIndex = table.selectedRow;
</span><span class="cx">         if (isNaN(rowIndex)) {
</span><del>-            this._selectedResource = null;
-            this._hideResourceDetailView();
</del><ins>+            this._selectedObject = null;
+            this._hideDetailView();
</ins><span class="cx">             return;
</span><span class="cx">         }
</span><span class="cx"> 
</span><span class="cx">         let entry = this._filteredEntries[rowIndex];
</span><del>-        if (entry.resource === this._selectedResource)
</del><ins>+        if (entry.resource === this._selectedObject || entry.domNode === this._selectedObject)
</ins><span class="cx">             return;
</span><span class="cx"> 
</span><del>-        this._selectedResource = entry.resource;
-        if (this._selectedResource)
-            this._showResourceDetailView(this._selectedResource);
</del><ins>+        this._selectedObject = entry.resource || entry.domNode;
+        if (this._selectedObject)
+            this._showDetailView(this._selectedObject);
</ins><span class="cx">         else
</span><del>-            this._hideResourceDetailView();
</del><ins>+            this._hideDetailView();
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     tablePopulateCell(table, cell, column, rowIndex)
</span><span class="lines">@@ -516,7 +516,7 @@
</span><span class="cx"> 
</span><span class="cx">         if (WI.settings.groupByDOMNode.value && resource.initiatorNode) {
</span><span class="cx">             let nodeEntry = this._domNodeEntries.get(resource.initiatorNode);
</span><del>-            if (nodeEntry.initiatedResourceEntries.length > 1) {
</del><ins>+            if (nodeEntry.initiatedResourceEntries.length > 1 || nodeEntry.domNode.domEvents.length) {
</ins><span class="cx">                 cell.classList.add("child");
</span><span class="cx"> 
</span><span class="cx">                 let range = resource.requestedByteRange;
</span><span class="lines">@@ -641,9 +641,83 @@
</span><span class="cx">     {
</span><span class="cx">         cell.removeChildren();
</span><span class="cx"> 
</span><ins>+        let container = cell.appendChild(document.createElement("div"));
+        container.className = "waterfall-container";
+
+        let graphStartTime = this._waterfallTimelineRuler.startTime;
+        let secondsPerPixel = this._waterfallTimelineRuler.secondsPerPixel;
+
+        function positionByStartOffset(element, timestamp) {
+            let styleAttribute = WI.resolvedLayoutDirection() === WI.LayoutDirection.LTR ? "left" : "right";
+            element.style.setProperty(styleAttribute, ((timestamp - graphStartTime) / secondsPerPixel) + "px");
+        }
+
+        function setWidthForDuration(element, startTimestamp, endTimestamp) {
+            element.style.setProperty("width", ((endTimestamp - startTimestamp) / secondsPerPixel) + "px");
+        }
+
</ins><span class="cx">         let domNode = entry.domNode;
</span><span class="cx">         if (domNode) {
</span><del>-            // FIXME: <https://webkit.org/b/189773> Web Inspector: create special Network waterfall for media events
</del><ins>+            const domEventElementSize = 8; // Keep this in sync with `--node-waterfall-dom-event-size`.
+
+            let groupedDOMEvents = domNode.domEvents.reduce((accumulator, current) => {
+                if (!accumulator.length || (current.timestamp - accumulator.lastValue.endTimestamp) >= (domEventElementSize * secondsPerPixel)) {
+                    accumulator.push({
+                        startTimestamp: current.timestamp,
+                        domEvents: [],
+                    });
+                }
+                accumulator.lastValue.endTimestamp = current.timestamp;
+                accumulator.lastValue.domEvents.push(current);
+                return accumulator;
+            }, []);
+
+            let playing = false;
+
+            function createDOMEventLine(domEvents, startTimestamp, endTimestamp) {
+                if (domEvents.lastValue.eventName === "ended")
+                    return;
+
+                for (let i = domEvents.length - 1; i >= 0; --i) {
+                    let domEvent = domEvents[i];
+                    if (domEvent.eventName === "play" || domEvent.eventName === "playing" || domEvent.eventName === "timeupdate") {
+                        playing = true;
+                        break;
+                    }
+
+                    if (domEvent.eventName === "pause" || domEvent.eventName === "stall") {
+                        playing = false;
+                        break;
+                    }
+                }
+
+                let lineElement = container.appendChild(document.createElement("div"));
+                lineElement.classList.add("dom-activity");
+                lineElement.classList.toggle("playing", playing);
+                positionByStartOffset(lineElement, startTimestamp);
+                setWidthForDuration(lineElement, startTimestamp, endTimestamp);
+            }
+
+            for (let [a, b] of groupedDOMEvents.adjacencies())
+                createDOMEventLine(a.domEvents, a.endTimestamp, b.startTimestamp);
+
+            if (groupedDOMEvents.length)
+                createDOMEventLine(groupedDOMEvents.lastValue.domEvents, groupedDOMEvents.lastValue.endTimestamp, this._waterfallEndTime);
+
+            for (let {startTimestamp, endTimestamp, domEvents} of groupedDOMEvents) {
+                let paddingForCentering = domEventElementSize * secondsPerPixel / 2;
+
+                let eventElement = container.appendChild(document.createElement("div"));
+                eventElement.classList.add("dom-event");
+                positionByStartOffset(eventElement, startTimestamp - paddingForCentering);
+                setWidthForDuration(eventElement, startTimestamp, endTimestamp + paddingForCentering);
+                eventElement.addEventListener("mousedown", (event) => {
+                    if (event.button !== 0 || event.ctrlKey)
+                        return;
+                    this._handleNodeEntryMousedownWaterfall(eventElement, entry, domEvents);
+                });
+            }
+
</ins><span class="cx">             return;
</span><span class="cx">         }
</span><span class="cx"> 
</span><span class="lines">@@ -659,7 +733,6 @@
</span><span class="cx">             return;
</span><span class="cx">         }
</span><span class="cx"> 
</span><del>-        let graphStartTime = this._waterfallTimelineRuler.startTime;
</del><span class="cx">         if (responseEnd < graphStartTime) {
</span><span class="cx">             cell.textContent = zeroWidthSpace;
</span><span class="cx">             return;
</span><span class="lines">@@ -671,22 +744,14 @@
</span><span class="cx">             return;
</span><span class="cx">         }
</span><span class="cx"> 
</span><del>-        let secondsPerPixel = this._waterfallTimelineRuler.secondsPerPixel;
-
-        let container = cell.appendChild(document.createElement("div"));
-        container.className = "waterfall-container";
-
</del><span class="cx">         function appendBlock(startTimestamp, endTimestamp, className) {
</span><span class="cx">             if (isNaN(startTimestamp) || isNaN(endTimestamp) || endTimestamp - startTimestamp <= 0)
</span><span class="cx">                 return null;
</span><span class="cx"> 
</span><del>-            let startOffset = (startTimestamp - graphStartTime) / secondsPerPixel;
-            let width = (endTimestamp - startTimestamp) / secondsPerPixel;
</del><span class="cx">             let block = container.appendChild(document.createElement("div"));
</span><span class="cx">             block.classList.add("block", className);
</span><del>-            let styleAttribute = WI.resolvedLayoutDirection() === WI.LayoutDirection.LTR ? "left" : "right";
-            block.style[styleAttribute] = startOffset + "px";
-            block.style.width = width + "px";
</del><ins>+            positionByStartOffset(block, startTimestamp);
+            setWidthForDuration(block, startTimestamp, endTimestamp);
</ins><span class="cx">             return block;
</span><span class="cx">         }
</span><span class="cx"> 
</span><span class="lines">@@ -696,7 +761,7 @@
</span><span class="cx">         mouseBlock.addEventListener("mousedown", (event) => {
</span><span class="cx">             if (event.button !== 0 || event.ctrlKey)
</span><span class="cx">                 return;
</span><del>-            this._handleMousedownWaterfall(mouseBlock, entry, event);
</del><ins>+            this._handleResourceEntryMousedownWaterfall(mouseBlock, entry);
</ins><span class="cx">         });
</span><span class="cx"> 
</span><span class="cx">         // Super small visualization.
</span><span class="lines">@@ -1049,8 +1114,10 @@
</span><span class="cx">         }
</span><span class="cx">         this._pendingInsertions = [];
</span><span class="cx"> 
</span><del>-        for (let resource of this._pendingUpdates)
-            this._updateEntryForResource(resource);
</del><ins>+        for (let updateObject of this._pendingUpdates) {
+            if (updateObject instanceof WI.Resource)
+                this._updateEntryForResource(updateObject);
+        }
</ins><span class="cx">         this._pendingUpdates = [];
</span><span class="cx"> 
</span><span class="cx">         this._pendingFilter = false;
</span><span class="lines">@@ -1112,9 +1179,15 @@
</span><span class="cx">         }
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    _rowIndexForResource(resource)
</del><ins>+    _rowIndexForRepresentedObject(object)
</ins><span class="cx">     {
</span><del>-        return this._filteredEntries.findIndex((x) => x.resource === resource);
</del><ins>+        return this._filteredEntries.findIndex((x) => {
+            if (x.resource === object)
+                return true;
+            if (x.domNode === object)
+                return true;
+            return false;
+        });
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     _updateEntryForResource(resource)
</span><span class="lines">@@ -1132,7 +1205,7 @@
</span><span class="cx">         let entry = this._entryForResource(resource);
</span><span class="cx">         updateExistingEntry(this._entries[index], entry);
</span><span class="cx"> 
</span><del>-        let rowIndex = this._rowIndexForResource(resource);
</del><ins>+        let rowIndex = this._rowIndexForRepresentedObject(resource);
</ins><span class="cx">         if (rowIndex === -1)
</span><span class="cx">             return;
</span><span class="cx"> 
</span><span class="lines">@@ -1145,43 +1218,50 @@
</span><span class="cx">             this._waterfallPopover.dismiss();
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    _hideResourceDetailView()
</del><ins>+    _hideDetailView()
</ins><span class="cx">     {
</span><del>-        if (!this._resourceDetailView)
</del><ins>+        if (!this._detailView)
</ins><span class="cx">             return;
</span><span class="cx"> 
</span><span class="cx">         this.element.classList.remove("showing-detail");
</span><span class="cx">         this._table.scrollContainer.style.removeProperty("width");
</span><span class="cx"> 
</span><del>-        this.removeSubview(this._resourceDetailView);
</del><ins>+        this.removeSubview(this._detailView);
</ins><span class="cx"> 
</span><del>-        this._resourceDetailView.hidden();
-        this._resourceDetailView = null;
</del><ins>+        this._detailView.hidden();
+        this._detailView = null;
</ins><span class="cx"> 
</span><span class="cx">         this._table.resize();
</span><span class="cx">         this._table.reloadVisibleColumnCells(this._waterfallColumn);
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    _showResourceDetailView(resource)
</del><ins>+    _showDetailView(object)
</ins><span class="cx">     {
</span><del>-        let oldResourceDetailView = this._resourceDetailView;
</del><ins>+        let oldDetailView = this._detailView;
</ins><span class="cx"> 
</span><del>-        this._resourceDetailView = this._resourceDetailViewMap.get(resource);
-        if (!this._resourceDetailView) {
-            this._resourceDetailView = new WI.NetworkResourceDetailView(resource, this);
-            this._resourceDetailViewMap.set(resource, this._resourceDetailView);
</del><ins>+        this._detailView = this._detailViewMap.get(object);
+        if (!this._detailView) {
+            if (object instanceof WI.Resource)
+                this._detailView = new WI.NetworkResourceDetailView(object, this);
+            else if (object instanceof WI.DOMNode) {
+                this._detailView = new WI.NetworkDOMNodeDetailView(object, this, {
+                    startTimestamp: this._waterfallStartTime,
+                });
+            }
+
+            this._detailViewMap.set(object, this._detailView);
</ins><span class="cx">         }
</span><span class="cx"> 
</span><del>-        if (oldResourceDetailView) {
-            oldResourceDetailView.hidden();
-            this.replaceSubview(oldResourceDetailView, this._resourceDetailView);
</del><ins>+        if (oldDetailView) {
+            oldDetailView.hidden();
+            this.replaceSubview(oldDetailView, this._detailView);
</ins><span class="cx">         } else
</span><del>-            this.addSubview(this._resourceDetailView);
</del><ins>+            this.addSubview(this._detailView);
</ins><span class="cx"> 
</span><span class="cx">         if (this._showingRepresentedObjectCookie)
</span><del>-            this._resourceDetailView.willShowWithCookie(this._showingRepresentedObjectCookie);
</del><ins>+            this._detailView.willShowWithCookie(this._showingRepresentedObjectCookie);
</ins><span class="cx"> 
</span><del>-        this._resourceDetailView.shown();
</del><ins>+        this._detailView.shown();
</ins><span class="cx"> 
</span><span class="cx">         this.element.classList.add("showing-detail");
</span><span class="cx">         this._table.scrollContainer.style.width = this._nameColumn.width + "px";
</span><span class="lines">@@ -1194,11 +1274,11 @@
</span><span class="cx"> 
</span><span class="cx">     _positionDetailView()
</span><span class="cx">     {
</span><del>-        if (!this._resourceDetailView)
</del><ins>+        if (!this._detailView)
</ins><span class="cx">             return;
</span><span class="cx"> 
</span><span class="cx">         let side = WI.resolvedLayoutDirection() === WI.LayoutDirection.RTL ? "right" : "left";
</span><del>-        this._resourceDetailView.element.style[side] = this._nameColumn.width + "px";
</del><ins>+        this._detailView.element.style[side] = this._nameColumn.width + "px";
</ins><span class="cx">         this._table.scrollContainer.style.width = this._nameColumn.width + "px";
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="lines">@@ -1331,7 +1411,7 @@
</span><span class="cx">         let entry = this._entries[index];
</span><span class="cx">         entry.transferSize = !isNaN(resource.networkTotalTransferSize) ? resource.networkTotalTransferSize : resource.estimatedTotalTransferSize;
</span><span class="cx"> 
</span><del>-        let rowIndex = this._rowIndexForResource(resource);
</del><ins>+        let rowIndex = this._rowIndexForRepresentedObject(resource);
</ins><span class="cx">         if (rowIndex === -1)
</span><span class="cx">             return;
</span><span class="cx"> 
</span><span class="lines">@@ -1444,6 +1524,8 @@
</span><span class="cx">         if (!nodeEntry) {
</span><span class="cx">             nodeEntry = this._entryForDOMNode(resource.initiatorNode, Object.keys(resourceEntry));
</span><span class="cx">             this._domNodeEntries.set(resource.initiatorNode, nodeEntry);
</span><ins>+
+            resource.initiatorNode.addEventListener(WI.DOMNode.Event.DidFireEvent, this._handleNodeDidFireEvent, this);
</ins><span class="cx">         }
</span><span class="cx"> 
</span><span class="cx">         if (!this._entriesSortComparator)
</span><span class="lines">@@ -1466,6 +1548,19 @@
</span><span class="cx">         }, new Set);
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    _handleNodeDidFireEvent(event)
+    {
+        let domNode = event.target;
+        let {domEvent} = event.data;
+
+        this._pendingUpdates.push(domNode);
+
+        if (domEvent.timestamp > this._waterfallEndTime)
+            this._waterfallEndTime = domEvent.timestamp + (this._waterfallTimelineRuler.secondsPerPixel * 10);
+
+        this.needsLayout();
+    }
+
</ins><span class="cx">     _hasTypeFilter()
</span><span class="cx">     {
</span><span class="cx">         return !!this._activeTypeFilters;
</span><span class="lines">@@ -1517,7 +1612,7 @@
</span><span class="cx"> 
</span><span class="cx">         if (WI.settings.groupByDOMNode.value) {
</span><span class="cx">             for (let nodeEntry of this._domNodeEntries.values()) {
</span><del>-                if (nodeEntry.initiatedResourceEntries.length < 2)
</del><ins>+                if (nodeEntry.initiatedResourceEntries.length < 2 && !nodeEntry.domNode.domEvents.length)
</ins><span class="cx">                     continue;
</span><span class="cx"> 
</span><span class="cx">                 let firstIndex = Infinity;
</span><span class="lines">@@ -1614,7 +1709,7 @@
</span><span class="cx">             return;
</span><span class="cx"> 
</span><span class="cx">         // Even if the selected resource would still be visible, lets close the detail view if a filter changes.
</span><del>-        this._hideResourceDetailView();
</del><ins>+        this._hideDetailView();
</ins><span class="cx"> 
</span><span class="cx">         this._activeTypeFilters = newFilter;
</span><span class="cx">         this._updateFilteredEntries();
</span><span class="lines">@@ -1640,7 +1735,7 @@
</span><span class="cx">             return;
</span><span class="cx"> 
</span><span class="cx">         // Even if the selected resource would still be visible, lets close the detail view if a filter changes.
</span><del>-        this._hideResourceDetailView();
</del><ins>+        this._hideDetailView();
</ins><span class="cx"> 
</span><span class="cx">         // Search cleared.
</span><span class="cx">         if (!searchQuery) {
</span><span class="lines">@@ -1669,10 +1764,10 @@
</span><span class="cx"> 
</span><span class="cx">     _restoreSelectedRow()
</span><span class="cx">     {
</span><del>-        if (!this._selectedResource)
</del><ins>+        if (!this._selectedObject)
</ins><span class="cx">             return;
</span><span class="cx"> 
</span><del>-        let rowIndex = this._rowIndexForResource(this._selectedResource);
</del><ins>+        let rowIndex = this._rowIndexForRepresentedObject(this._selectedObject);
</ins><span class="cx">         if (rowIndex === -1) {
</span><span class="cx">             this._selectedResource = null;
</span><span class="cx">             this._table.deselectAll();
</span><span class="lines">@@ -1709,11 +1804,18 @@
</span><span class="cx">         }).catch(handlePromiseException);
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    _waterfallPopoverContentForResource(resource)
</del><ins>+    _waterfallPopoverContent()
</ins><span class="cx">     {
</span><span class="cx">         let contentElement = document.createElement("div");
</span><del>-        contentElement.className = "waterfall-popover-content";
</del><ins>+        contentElement.classList.add("waterfall-popover-content");
+        return contentElement;
+    }
</ins><span class="cx"> 
</span><ins>+    _waterfallPopoverContentForResourceEntry(resourceEntry)
+    {
+        let contentElement = this._waterfallPopoverContent();
+
+        let resource = resourceEntry.resource;
</ins><span class="cx">         if (!resource.hasResponse() || !resource.firstTimestamp || !resource.lastTimestamp) {
</span><span class="cx">             contentElement.textContent = WI.UIString("Resource has no timing data");
</span><span class="cx">             return contentElement;
</span><span class="lines">@@ -1726,8 +1828,33 @@
</span><span class="cx">         return contentElement;
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    _handleMousedownWaterfall(mouseBlock, entry, event)
</del><ins>+    _waterfallPopoverContentForNodeEntry(nodeEntry, domEvents)
</ins><span class="cx">     {
</span><ins>+        let contentElement = this._waterfallPopoverContent();
+
+        let breakdownView = new WI.DOMEventsBreakdownView(domEvents, {
+            startTimestamp: this._waterfallStartTime,
+        });
+        contentElement.appendChild(breakdownView.element);
+        breakdownView.updateLayout();
+
+        return contentElement;
+    }
+
+    _handleResourceEntryMousedownWaterfall(targetElement, resourceEntry)
+    {
+        let popoverContentElement = this._waterfallPopoverContentForResourceEntry(resourceEntry);
+        this._handleMousedownWaterfall(resourceEntry, targetElement, popoverContentElement);
+    }
+
+    _handleNodeEntryMousedownWaterfall(targetElement, nodeEntry, domEvents)
+    {
+        let popoverContentElement = this._waterfallPopoverContentForNodeEntry(nodeEntry, domEvents);
+        this._handleMousedownWaterfall(nodeEntry, targetElement, popoverContentElement);
+    }
+
+    _handleMousedownWaterfall(entry, targetElement, popoverContentElement)
+    {
</ins><span class="cx">         if (!this._waterfallPopover) {
</span><span class="cx">             this._waterfallPopover = new WI.Popover;
</span><span class="cx">             this._waterfallPopover.element.classList.add("waterfall-popover");
</span><span class="lines">@@ -1737,7 +1864,10 @@
</span><span class="cx">             return;
</span><span class="cx"> 
</span><span class="cx">         let calculateTargetFrame = () => {
</span><del>-            let rowIndex = this._rowIndexForResource(entry.resource);
</del><ins>+            if (!entry.resource)
+                return WI.Rect.rectFromClientRect(targetElement.getBoundingClientRect());
+
+            let rowIndex = this._rowIndexForRepresentedObject(entry.resource);
</ins><span class="cx">             let cell = this._table.cellForRowAndColumn(rowIndex, this._waterfallColumn);
</span><span class="cx">             if (!cell) {
</span><span class="cx">                 this._waterfallPopover.dismiss();
</span><span class="lines">@@ -1767,7 +1897,6 @@
</span><span class="cx">                 this._waterfallPopover.present(bounds, preferredEdges);
</span><span class="cx">         };
</span><span class="cx"> 
</span><del>-        let popoverContentElement = this._waterfallPopoverContentForResource(entry.resource);
</del><span class="cx">         this._waterfallPopover.presentNewContentWithFrame(popoverContentElement, targetFrame, preferredEdges);
</span><span class="cx">     }
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceWebInspectorUIUserInterfaceViewsResourceTimingBreakdownViewcss"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebInspectorUI/UserInterface/Views/ResourceTimingBreakdownView.css (237027 => 237028)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebInspectorUI/UserInterface/Views/ResourceTimingBreakdownView.css  2018-10-11 03:08:34 UTC (rev 237027)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/ResourceTimingBreakdownView.css     2018-10-11 04:13:17 UTC (rev 237028)
</span><span class="lines">@@ -23,10 +23,6 @@
</span><span class="cx">  * THE POSSIBILITY OF SUCH DAMAGE.
</span><span class="cx">  */
</span><span class="cx"> 
</span><del>-.popover.waterfall-popover {
-    --popover-background-color: white;
-}
-
</del><span class="cx"> .waterfall-popover-content .resource-timing-breakdown {
</span><span class="cx">     margin: 5px;
</span><span class="cx">     -webkit-user-select: text;
</span><span class="lines">@@ -73,8 +69,8 @@
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> @media (prefers-dark-interface) {
</span><del>-    .popover.waterfall-popover {
-        --popover-background-color: var(--panel-background-color);
</del><ins>+    .resource-timing-breakdown > table > tr.header:not(.total-row) > td {
+        color: var(--text-color);
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     .resource-timing-breakdown > table > tr > td.label,
</span></span></pre>
</div>
</div>

</body>
</html>