<!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>[242743] trunk/Source/WebInspectorUI</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/242743">242743</a></dd>
<dt>Author</dt> <dd>drousso@apple.com</dd>
<dt>Date</dt> <dd>2019-03-11 14:56:32 -0700 (Mon, 11 Mar 2019)</dd>
</dl>

<h3>Log Message</h3>
<pre>Web Inspector: DOMDebugger: protocol error on first open
https://bugs.webkit.org/show_bug.cgi?id=195248
<rdar://problem/48538465>

Reviewed by Joseph Pecoraro.

Don't try to call `DOMDebugger` commands until a target has been initialized.
Still attempt to resolve DOM breakpoints whenever the main resource/frame changes.

* UserInterface/Controllers/DOMDebuggerManager.js:
(WI.DOMDebuggerManager):
(WI.DOMDebuggerManager.prototype.initializeTarget): Added.
(WI.DOMDebuggerManager.supportsEventBreakpoints):
(WI.DOMDebuggerManager.prototype.get supported):
(WI.DOMDebuggerManager.prototype.addDOMBreakpoint):
(WI.DOMDebuggerManager.prototype.removeDOMBreakpoint):
(WI.DOMDebuggerManager.prototype.addEventBreakpoint):
(WI.DOMDebuggerManager.prototype.removeEventBreakpoint):
(WI.DOMDebuggerManager.prototype.addURLBreakpoint):
(WI.DOMDebuggerManager.prototype.removeURLBreakpoint):
(WI.DOMDebuggerManager.prototype._speculativelyResolveDOMBreakpointsForURL): Added.
(WI.DOMDebuggerManager.prototype._resolveDOMBreakpoint):
(WI.DOMDebuggerManager.prototype._updateDOMBreakpoint):
(WI.DOMDebuggerManager.prototype._updateEventBreakpoint):
(WI.DOMDebuggerManager.prototype._updateURLBreakpoint):
(WI.DOMDebuggerManager.prototype._saveDOMBreakpoints):
(WI.DOMDebuggerManager.prototype._handleDOMBreakpointDisabledStateChanged):
(WI.DOMDebuggerManager.prototype._handleEventBreakpointDisabledStateChanged):
(WI.DOMDebuggerManager.prototype._handleURLBreakpointDisabledStateChanged):
(WI.DOMDebuggerManager.prototype._mainFrameDidChange):
(WI.DOMDebuggerManager.prototype._mainResourceDidChange):
(WI.DOMDebuggerManager.prototype.removeEventBreakpoint.breakpointRemoved): Deleted.
(WI.DOMDebuggerManager.prototype._speculativelyResolveBreakpoints): Deleted.
(WI.DOMDebuggerManager.prototype._updateDOMBreakpoint.breakpointUpdated): Deleted.
(WI.DOMDebuggerManager.prototype._resolveEventBreakpoint): Deleted.
(WI.DOMDebuggerManager.prototype._resolveURLBreakpoint): Deleted.

* UserInterface/Base/Multimap.js: Added.
(Multimap):
(Multimap.prototype.get):
(Multimap.prototype.add):
(Multimap.prototype.delete):
(Multimap.prototype.clear):
(Multimap.prototype.keys):
(Multimap.prototype.*values):
(Multimap.prototype.*[Symbol.iterator]):
(Multimap.prototype.toJSON):
* .eslintrc:
* UserInterface/Main.html:
* UserInterface/Test.html:
Helper data structure for managing Maps of Sets (e.g. all DOM breakpoints for a URL).</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkSourceWebInspectorUIeslintrc">trunk/Source/WebInspectorUI/.eslintrc</a></li>
<li><a href="#trunkSourceWebInspectorUIChangeLog">trunk/Source/WebInspectorUI/ChangeLog</a></li>
<li><a href="#trunkSourceWebInspectorUIUserInterfaceControllersDOMDebuggerManagerjs">trunk/Source/WebInspectorUI/UserInterface/Controllers/DOMDebuggerManager.js</a></li>
<li><a href="#trunkSourceWebInspectorUIUserInterfaceMainhtml">trunk/Source/WebInspectorUI/UserInterface/Main.html</a></li>
<li><a href="#trunkSourceWebInspectorUIUserInterfaceTesthtml">trunk/Source/WebInspectorUI/UserInterface/Test.html</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#trunkSourceWebInspectorUIUserInterfaceBaseMultimapjs">trunk/Source/WebInspectorUI/UserInterface/Base/Multimap.js</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkSourceWebInspectorUIeslintrc"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebInspectorUI/.eslintrc (242742 => 242743)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebInspectorUI/.eslintrc    2019-03-11 21:55:00 UTC (rev 242742)
+++ trunk/Source/WebInspectorUI/.eslintrc       2019-03-11 21:56:32 UTC (rev 242743)
</span><span class="lines">@@ -76,6 +76,7 @@
</span><span class="cx">         "InspectorTest": true,
</span><span class="cx">         "LinkedList": true,
</span><span class="cx">         "ListMultimap": true,
</span><ins>+        "Multimap": true,
</ins><span class="cx">         "ProtocolTest": true,
</span><span class="cx">         "ProtocolTestHarness": true,
</span><span class="cx">         "SyncTestSuite": true,
</span></span></pre></div>
<a id="trunkSourceWebInspectorUIChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebInspectorUI/ChangeLog (242742 => 242743)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebInspectorUI/ChangeLog    2019-03-11 21:55:00 UTC (rev 242742)
+++ trunk/Source/WebInspectorUI/ChangeLog       2019-03-11 21:56:32 UTC (rev 242743)
</span><span class="lines">@@ -1,3 +1,57 @@
</span><ins>+2019-03-11  Devin Rousso  <drousso@apple.com>
+
+        Web Inspector: DOMDebugger: protocol error on first open
+        https://bugs.webkit.org/show_bug.cgi?id=195248
+        <rdar://problem/48538465>
+
+        Reviewed by Joseph Pecoraro.
+
+        Don't try to call `DOMDebugger` commands until a target has been initialized.
+        Still attempt to resolve DOM breakpoints whenever the main resource/frame changes.
+
+        * UserInterface/Controllers/DOMDebuggerManager.js:
+        (WI.DOMDebuggerManager):
+        (WI.DOMDebuggerManager.prototype.initializeTarget): Added.
+        (WI.DOMDebuggerManager.supportsEventBreakpoints):
+        (WI.DOMDebuggerManager.prototype.get supported):
+        (WI.DOMDebuggerManager.prototype.addDOMBreakpoint):
+        (WI.DOMDebuggerManager.prototype.removeDOMBreakpoint):
+        (WI.DOMDebuggerManager.prototype.addEventBreakpoint):
+        (WI.DOMDebuggerManager.prototype.removeEventBreakpoint):
+        (WI.DOMDebuggerManager.prototype.addURLBreakpoint):
+        (WI.DOMDebuggerManager.prototype.removeURLBreakpoint):
+        (WI.DOMDebuggerManager.prototype._speculativelyResolveDOMBreakpointsForURL): Added.
+        (WI.DOMDebuggerManager.prototype._resolveDOMBreakpoint):
+        (WI.DOMDebuggerManager.prototype._updateDOMBreakpoint):
+        (WI.DOMDebuggerManager.prototype._updateEventBreakpoint):
+        (WI.DOMDebuggerManager.prototype._updateURLBreakpoint):
+        (WI.DOMDebuggerManager.prototype._saveDOMBreakpoints):
+        (WI.DOMDebuggerManager.prototype._handleDOMBreakpointDisabledStateChanged):
+        (WI.DOMDebuggerManager.prototype._handleEventBreakpointDisabledStateChanged):
+        (WI.DOMDebuggerManager.prototype._handleURLBreakpointDisabledStateChanged):
+        (WI.DOMDebuggerManager.prototype._mainFrameDidChange):
+        (WI.DOMDebuggerManager.prototype._mainResourceDidChange):
+        (WI.DOMDebuggerManager.prototype.removeEventBreakpoint.breakpointRemoved): Deleted.
+        (WI.DOMDebuggerManager.prototype._speculativelyResolveBreakpoints): Deleted.
+        (WI.DOMDebuggerManager.prototype._updateDOMBreakpoint.breakpointUpdated): Deleted.
+        (WI.DOMDebuggerManager.prototype._resolveEventBreakpoint): Deleted.
+        (WI.DOMDebuggerManager.prototype._resolveURLBreakpoint): Deleted.
+
+        * UserInterface/Base/Multimap.js: Added.
+        (Multimap):
+        (Multimap.prototype.get):
+        (Multimap.prototype.add):
+        (Multimap.prototype.delete):
+        (Multimap.prototype.clear):
+        (Multimap.prototype.keys):
+        (Multimap.prototype.*values):
+        (Multimap.prototype.*[Symbol.iterator]):
+        (Multimap.prototype.toJSON):
+        * .eslintrc:
+        * UserInterface/Main.html:
+        * UserInterface/Test.html:
+        Helper data structure for managing Maps of Sets (e.g. all DOM breakpoints for a URL).
+
</ins><span class="cx"> 2019-03-11  Joseph Pecoraro  <pecoraro@apple.com>
</span><span class="cx"> 
</span><span class="cx">         Web Inspector: CPU Usage Timeline - Enable by default
</span></span></pre></div>
<a id="trunkSourceWebInspectorUIUserInterfaceBaseMultimapjs"></a>
<div class="addfile"><h4>Added: trunk/Source/WebInspectorUI/UserInterface/Base/Multimap.js (0 => 242743)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebInspectorUI/UserInterface/Base/Multimap.js                               (rev 0)
+++ trunk/Source/WebInspectorUI/UserInterface/Base/Multimap.js  2019-03-11 21:56:32 UTC (rev 242743)
</span><span class="lines">@@ -0,0 +1,103 @@
</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.
+ */
+
+class Multimap
+{
+    constructor(items = [])
+    {
+        this._map = new Map;
+
+        for (let [key, value] of items)
+            this.add(key, value);
+    }
+
+    // Public
+
+    get(key)
+    {
+        return this._map.get(key);
+    }
+
+    add(key, value)
+    {
+        let valueSet = this._map.get(key);
+        if (!valueSet) {
+            valueSet = new Set;
+            this._map.set(key, valueSet);
+        }
+        valueSet.add(value);
+
+        return this;
+    }
+
+    delete(key, value)
+    {
+        // Allow an entire key to be removed by not passing a value.
+        if (arguments.length === 1)
+            return this._map.delete(key);
+
+        let valueSet = this._map.get(key);
+        if (!valueSet)
+            return false;
+
+        let deleted = valueSet.delete(value);
+
+        if (!valueSet.size)
+            this._map.delete(key);
+
+        return deleted;
+    }
+
+    clear()
+    {
+        this._map.clear();
+    }
+
+    keys()
+    {
+        return this._map.keys();
+    }
+
+    *values()
+    {
+        for (let valueSet of this._map.values()) {
+            for (let value of valueSet)
+                yield value;
+        }
+    }
+
+    *[Symbol.iterator]()
+    {
+        for (let [key, valueSet] of this._map) {
+            for (let value of valueSet)
+                yield [key, value];
+        }
+    }
+
+    toJSON()
+    {
+        return Array.from(this);
+    }
+}
</ins></span></pre></div>
<a id="trunkSourceWebInspectorUIUserInterfaceControllersDOMDebuggerManagerjs"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebInspectorUI/UserInterface/Controllers/DOMDebuggerManager.js (242742 => 242743)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebInspectorUI/UserInterface/Controllers/DOMDebuggerManager.js      2019-03-11 21:55:00 UTC (rev 242742)
+++ trunk/Source/WebInspectorUI/UserInterface/Controllers/DOMDebuggerManager.js 2019-03-11 21:56:32 UTC (rev 242743)
</span><span class="lines">@@ -30,7 +30,7 @@
</span><span class="cx">         super();
</span><span class="cx"> 
</span><span class="cx">         this._domBreakpointsSetting = new WI.Setting("dom-breakpoints", []);
</span><del>-        this._domBreakpointURLMap = new Map;
</del><ins>+        this._domBreakpointURLMap = new Multimap;
</ins><span class="cx">         this._domBreakpointFrameIdentifierMap = new Map;
</span><span class="cx"> 
</span><span class="cx">         this._eventBreakpointSetting = new WI.Setting("event-breakpoints", []);
</span><span class="lines">@@ -69,10 +69,29 @@
</span><span class="cx">                 this.addURLBreakpoint(WI.URLBreakpoint.deserialize(serializedInfo));
</span><span class="cx"> 
</span><span class="cx">             this._restoringBreakpoints = false;
</span><del>-            this._speculativelyResolveBreakpoints();
</del><ins>+        }
+    }
</ins><span class="cx"> 
</span><ins>+    // Target
+
+    initializeTarget(target)
+    {
+        if (target.DOMDebuggerAgent) {
+            if (target === WI.assumingMainTarget() && target.mainResource)
+                this._speculativelyResolveDOMBreakpointsForURL(target.mainResource.url);
+
+            for (let breakpoint of this._eventBreakpoints) {
+                if (!breakpoint.disabled)
+                    this._updateEventBreakpoint(breakpoint, target);
+            }
+
+            for (let breakpoint of this._urlBreakpoints) {
+                if (!breakpoint.disabled)
+                    this._updateURLBreakpoint(breakpoint, target);
+            }
+
</ins><span class="cx">             if (!this._allRequestsBreakpoint.disabled)
</span><del>-                this._updateURLBreakpoint(this._allRequestsBreakpoint);
</del><ins>+                this._updateURLBreakpoint(this._allRequestsBreakpoint, target);
</ins><span class="cx">         }
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="lines">@@ -80,7 +99,7 @@
</span><span class="cx"> 
</span><span class="cx">     static supportsEventBreakpoints()
</span><span class="cx">     {
</span><del>-        return DOMDebuggerAgent.setEventBreakpoint && DOMDebuggerAgent.removeEventBreakpoint;
</del><ins>+        return InspectorBackend.domains.DOMDebugger.setEventBreakpoint && InspectorBackend.domains.DOMDebugger.removeEventBreakpoint;
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     static supportsURLBreakpoints()
</span><span class="lines">@@ -92,7 +111,7 @@
</span><span class="cx"> 
</span><span class="cx">     get supported()
</span><span class="cx">     {
</span><del>-        return !!window.DOMDebuggerAgent;
</del><ins>+        return !!InspectorBackend.domains.DOMDebugger;
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     get allRequestsBreakpoint() { return this._allRequestsBreakpoint; }
</span><span class="lines">@@ -154,15 +173,13 @@
</span><span class="cx">             return;
</span><span class="cx">         }
</span><span class="cx"> 
</span><del>-        let breakpoints = this._domBreakpointURLMap.get(breakpoint.url);
-        if (!breakpoints) {
-            breakpoints = [breakpoint];
-            this._domBreakpointURLMap.set(breakpoint.url, breakpoints);
-        } else
-            breakpoints.push(breakpoint);
</del><ins>+        this._domBreakpointURLMap.add(breakpoint.url, breakpoint);
</ins><span class="cx"> 
</span><del>-        if (breakpoint.domNodeIdentifier)
-            this._resolveDOMBreakpoint(breakpoint, breakpoint.domNodeIdentifier);
</del><ins>+        if (!breakpoint.disabled) {
+            let target = WI.assumingMainTarget();
+            if (target && target.DOMDebuggerAgent)
+                this._updateDOMBreakpoint(breakpoint, target);
+        }
</ins><span class="cx"> 
</span><span class="cx">         this.dispatchEventToListeners(WI.DOMDebuggerManager.Event.DOMBreakpointAdded, {breakpoint});
</span><span class="cx"> 
</span><span class="lines">@@ -188,15 +205,14 @@
</span><span class="cx"> 
</span><span class="cx">         this._detachDOMBreakpoint(breakpoint);
</span><span class="cx"> 
</span><del>-        let urlBreakpoints = this._domBreakpointURLMap.get(breakpoint.url);
-        urlBreakpoints.remove(breakpoint, true);
</del><ins>+        this._domBreakpointURLMap.delete(breakpoint.url);
</ins><span class="cx"> 
</span><del>-        if (!breakpoint.disabled)
-            DOMDebuggerAgent.removeDOMBreakpoint(nodeIdentifier, breakpoint.type);
</del><ins>+        if (!breakpoint.disabled) {
+            // We should get the target associated with the nodeIdentifier of this breakpoint.
+            let target = WI.assumingMainTarget();
+            target.DOMDebuggerAgent.removeDOMBreakpoint(nodeIdentifier, breakpoint.type);
+        }
</ins><span class="cx"> 
</span><del>-        if (!urlBreakpoints.length)
-            this._domBreakpointURLMap.delete(breakpoint.url);
-
</del><span class="cx">         this.dispatchEventToListeners(WI.DOMDebuggerManager.Event.DOMBreakpointRemoved, {breakpoint});
</span><span class="cx"> 
</span><span class="cx">         breakpoint.domNodeIdentifier = null;
</span><span class="lines">@@ -237,7 +253,13 @@
</span><span class="cx"> 
</span><span class="cx">         this.dispatchEventToListeners(WI.DOMDebuggerManager.Event.EventBreakpointAdded, {breakpoint});
</span><span class="cx"> 
</span><del>-        this._resolveEventBreakpoint(breakpoint);
</del><ins>+        if (!breakpoint.disabled) {
+            for (let target of WI.targets) {
+                if (target.DOMDebuggerAgent)
+                    this._updateEventBreakpoint(breakpoint, target);
+            }
+        }
+
</ins><span class="cx">         this._saveEventBreakpoints();
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="lines">@@ -264,19 +286,18 @@
</span><span class="cx">         if (breakpoint.disabled)
</span><span class="cx">             return;
</span><span class="cx"> 
</span><del>-        function breakpointRemoved(error) {
-            if (error)
-                console.error(error);
-        }
</del><ins>+        for (let target of WI.targets) {
+            if (target.DOMDebuggerAgent) {
+                // Compatibility (iOS 12): DOMDebuggerAgent.removeEventBreakpoint did not exist.
+                if (!WI.DOMDebuggerManager.supportsEventBreakpoints()) {
+                    console.assert(breakpoint.type === WI.EventBreakpoint.Type.Listener);
+                    target.DOMDebuggerAgent.removeEventListenerBreakpoint(breakpoint.eventName);
+                    continue;
+                }
</ins><span class="cx"> 
</span><del>-        // Compatibility (iOS 12): DOMDebuggerAgent.removeEventBreakpoint did not exist.
-        if (!WI.DOMDebuggerManager.supportsEventBreakpoints()) {
-            console.assert(breakpoint.type === WI.EventBreakpoint.Type.Listener);
-            DOMDebuggerAgent.removeEventListenerBreakpoint(breakpoint.eventName, breakpointRemoved);
-            return;
</del><ins>+                target.DOMDebuggerAgent.removeEventBreakpoint(breakpoint.type, breakpoint.eventName);
+            }
</ins><span class="cx">         }
</span><del>-
-        DOMDebuggerAgent.removeEventBreakpoint(breakpoint.type, breakpoint.eventName, breakpointRemoved);
</del><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     urlBreakpointForURL(url)
</span><span class="lines">@@ -306,7 +327,13 @@
</span><span class="cx"> 
</span><span class="cx">         this.dispatchEventToListeners(WI.DOMDebuggerManager.Event.URLBreakpointAdded, {breakpoint});
</span><span class="cx"> 
</span><del>-        this._resolveURLBreakpoint(breakpoint);
</del><ins>+        if (!breakpoint.disabled) {
+            for (let target of WI.targets) {
+                if (target.DOMDebuggerAgent)
+                    this._updateURLBreakpoint(breakpoint, target);
+            }
+        }
+
</ins><span class="cx">         this._saveURLBreakpoints();
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="lines">@@ -333,17 +360,14 @@
</span><span class="cx">         if (breakpoint.disabled)
</span><span class="cx">             return;
</span><span class="cx"> 
</span><del>-        // Compatibility (iOS 12.1): DOMDebuggerAgent.removeURLBreakpoint did not exist.
-        if (WI.DOMDebuggerManager.supportsURLBreakpoints()) {
-            DOMDebuggerAgent.removeURLBreakpoint(breakpoint.url, (error) => {
-                if (error)
-                    console.error(error);
-            });
-        } else {
-            DOMDebuggerAgent.removeXHRBreakpoint(breakpoint.url, (error) => {
-                if (error)
-                    console.error(error);
-            });
</del><ins>+        for (let target of WI.targets) {
+            if (target.DOMDebuggerAgent) {
+                // Compatibility (iOS 12.1): DOMDebuggerAgent.removeURLBreakpoint did not exist.
+                if (WI.DOMDebuggerManager.supportsURLBreakpoints())
+                    target.DOMDebuggerAgent.removeURLBreakpoint(breakpoint.url);
+                else
+                    target.DOMDebuggerAgent.removeXHRBreakpoint(breakpoint.url);
+            }
</ins><span class="cx">         }
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="lines">@@ -393,32 +417,21 @@
</span><span class="cx">         }
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    _speculativelyResolveBreakpoints()
</del><ins>+    _speculativelyResolveDOMBreakpointsForURL(url)
</ins><span class="cx">     {
</span><del>-        let mainFrame = WI.networkManager.mainFrame;
-        if (!mainFrame)
</del><ins>+        let domBreakpoints = this._domBreakpointURLMap.get(url);
+        if (!domBreakpoints)
</ins><span class="cx">             return;
</span><span class="cx"> 
</span><del>-        let domBreakpoints = this._domBreakpointURLMap.get(mainFrame.url);
-        if (domBreakpoints) {
-            for (let breakpoint of domBreakpoints) {
-                if (breakpoint.domNodeIdentifier)
-                    continue;
</del><ins>+        for (let breakpoint of domBreakpoints) {
+            if (breakpoint.domNodeIdentifier)
+                continue;
</ins><span class="cx"> 
</span><del>-                WI.domManager.pushNodeByPathToFrontend(breakpoint.path, (nodeIdentifier) => {
-                    if (!nodeIdentifier)
-                        return;
-
</del><ins>+            WI.domManager.pushNodeByPathToFrontend(breakpoint.path, (nodeIdentifier) => {
+                if (nodeIdentifier)
</ins><span class="cx">                     this._resolveDOMBreakpoint(breakpoint, nodeIdentifier);
</span><del>-                });
-            }
</del><ins>+            });
</ins><span class="cx">         }
</span><del>-
-        for (let breakpoint of this._eventBreakpoints)
-            this._resolveEventBreakpoint(breakpoint);
-
-        for (let breakpoint of this._urlBreakpoints)
-            this._resolveURLBreakpoint(breakpoint);
</del><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     _resolveDOMBreakpoint(breakpoint, nodeIdentifier)
</span><span class="lines">@@ -443,92 +456,74 @@
</span><span class="cx"> 
</span><span class="cx">         breakpoint.domNodeIdentifier = nodeIdentifier;
</span><span class="cx"> 
</span><del>-        this._updateDOMBreakpoint(breakpoint);
</del><ins>+        // We should get the target associated with the nodeIdentifier of this breakpoint.
+        let target = WI.assumingMainTarget();
+        if (target && target.DOMDebuggerAgent)
+            this._updateDOMBreakpoint(breakpoint, target);
</ins><span class="cx">     }
</span><span class="cx"> 
</span><del>-    _updateDOMBreakpoint(breakpoint)
</del><ins>+    _updateDOMBreakpoint(breakpoint, target)
</ins><span class="cx">     {
</span><del>-        let nodeIdentifier = breakpoint.domNodeIdentifier;
-        if (!nodeIdentifier)
</del><ins>+        console.assert(target.DOMDebuggerAgent);
+
+        if (!breakpoint.domNodeIdentifier)
</ins><span class="cx">             return;
</span><span class="cx"> 
</span><del>-        function breakpointUpdated(error)
-        {
-            if (error)
-                console.error(error);
-        }
-
</del><span class="cx">         if (breakpoint.disabled)
</span><del>-            DOMDebuggerAgent.removeDOMBreakpoint(nodeIdentifier, breakpoint.type, breakpointUpdated);
</del><ins>+            target.DOMDebuggerAgent.removeDOMBreakpoint(breakpoint.domNodeIdentifier, breakpoint.type);
</ins><span class="cx">         else
</span><del>-            DOMDebuggerAgent.setDOMBreakpoint(nodeIdentifier, breakpoint.type, breakpointUpdated);
</del><ins>+            target.DOMDebuggerAgent.setDOMBreakpoint(breakpoint.domNodeIdentifier, breakpoint.type);
</ins><span class="cx">     }
</span><span class="cx"> 
</span><del>-    _updateEventBreakpoint(breakpoint)
</del><ins>+    _updateEventBreakpoint(breakpoint, target)
</ins><span class="cx">     {
</span><ins>+        console.assert(target.DOMDebuggerAgent);
+
</ins><span class="cx">         // Compatibility (iOS 12): DOMDebuggerAgent.removeEventBreakpoint did not exist.
</span><span class="cx">         if (!WI.DOMDebuggerManager.supportsEventBreakpoints()) {
</span><span class="cx">             console.assert(breakpoint.type === WI.EventBreakpoint.Type.Listener);
</span><span class="cx">             if (breakpoint.disabled)
</span><del>-                DOMDebuggerAgent.removeEventListenerBreakpoint(breakpoint.eventName);
</del><ins>+                target.DOMDebuggerAgent.removeEventListenerBreakpoint(breakpoint.eventName);
</ins><span class="cx">             else
</span><del>-                DOMDebuggerAgent.setEventListenerBreakpoint(breakpoint.eventName);
</del><ins>+                target.DOMDebuggerAgent.setEventListenerBreakpoint(breakpoint.eventName);
</ins><span class="cx">             return;
</span><span class="cx">         }
</span><span class="cx"> 
</span><span class="cx">         if (breakpoint.disabled)
</span><del>-            DOMDebuggerAgent.removeEventBreakpoint(breakpoint.type, breakpoint.eventName);
</del><ins>+            target.DOMDebuggerAgent.removeEventBreakpoint(breakpoint.type, breakpoint.eventName);
</ins><span class="cx">         else
</span><del>-            DOMDebuggerAgent.setEventBreakpoint(breakpoint.type, breakpoint.eventName);
</del><ins>+            target.DOMDebuggerAgent.setEventBreakpoint(breakpoint.type, breakpoint.eventName);
</ins><span class="cx">     }
</span><span class="cx"> 
</span><del>-    _updateURLBreakpoint(breakpoint)
</del><ins>+    _updateURLBreakpoint(breakpoint, target)
</ins><span class="cx">     {
</span><ins>+        console.assert(target.DOMDebuggerAgent);
+
</ins><span class="cx">         // Compatibility (iOS 12.1): DOMDebuggerAgent.removeURLBreakpoint did not exist.
</span><span class="cx">         if (!WI.DOMDebuggerManager.supportsURLBreakpoints()) {
</span><span class="cx">             if (breakpoint.disabled)
</span><del>-                DOMDebuggerAgent.removeXHRBreakpoint(breakpoint.url);
</del><ins>+                target.DOMDebuggerAgent.removeXHRBreakpoint(breakpoint.url);
</ins><span class="cx">             else {
</span><span class="cx">                 let isRegex = breakpoint.type === WI.URLBreakpoint.Type.RegularExpression;
</span><del>-                DebuggerAgent.setXHRBreakpoint(breakpoint.url, isRegex);
</del><ins>+                target.DOMDebuggerAgent.setXHRBreakpoint(breakpoint.url, isRegex);
</ins><span class="cx">             }
</span><span class="cx">             return;
</span><span class="cx">         }
</span><span class="cx"> 
</span><span class="cx">         if (breakpoint.disabled)
</span><del>-            DOMDebuggerAgent.removeURLBreakpoint(breakpoint.url);
</del><ins>+            target.DOMDebuggerAgent.removeURLBreakpoint(breakpoint.url);
</ins><span class="cx">         else {
</span><span class="cx">             let isRegex = breakpoint.type === WI.URLBreakpoint.Type.RegularExpression;
</span><del>-            DOMDebuggerAgent.setURLBreakpoint(breakpoint.url, isRegex);
</del><ins>+            target.DOMDebuggerAgent.setURLBreakpoint(breakpoint.url, isRegex);
</ins><span class="cx">         }
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    _resolveEventBreakpoint(breakpoint)
-    {
-        if (breakpoint.disabled)
-            return;
-
-        this._updateEventBreakpoint(breakpoint);
-    }
-
-    _resolveURLBreakpoint(breakpoint)
-    {
-        if (breakpoint.disabled)
-            return;
-
-        this._updateURLBreakpoint(breakpoint);
-    }
-
</del><span class="cx">     _saveDOMBreakpoints()
</span><span class="cx">     {
</span><span class="cx">         if (this._restoringBreakpoints)
</span><span class="cx">             return;
</span><span class="cx"> 
</span><del>-        let breakpointsToSave = [];
-        for (let breakpoints of this._domBreakpointURLMap.values())
-            breakpointsToSave = breakpointsToSave.concat(breakpoints);
-
-        this._domBreakpointsSetting.value = breakpointsToSave.map((breakpoint) => breakpoint.serializableInfo);
</del><ins>+        this._domBreakpointsSetting.value = Array.from(this._domBreakpointURLMap.values()).map((breakpoint) => breakpoint.serializableInfo);
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     _saveEventBreakpoints()
</span><span class="lines">@@ -550,7 +545,10 @@
</span><span class="cx">     _handleDOMBreakpointDisabledStateChanged(event)
</span><span class="cx">     {
</span><span class="cx">         let breakpoint = event.target;
</span><del>-        this._updateDOMBreakpoint(breakpoint);
</del><ins>+        let target = WI.assumingMainTarget();
+        if (target && target.DOMDebuggerAgent)
+            this._updateDOMBreakpoint(breakpoint, target);
+
</ins><span class="cx">         this._saveDOMBreakpoints();
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="lines">@@ -557,7 +555,10 @@
</span><span class="cx">     _handleEventBreakpointDisabledStateChanged(event)
</span><span class="cx">     {
</span><span class="cx">         let breakpoint = event.target;
</span><del>-        this._updateEventBreakpoint(breakpoint);
</del><ins>+        for (let target of WI.targets) {
+            if (target.DOMDebuggerAgent)
+                this._updateEventBreakpoint(breakpoint, target);
+        }
</ins><span class="cx">         this._saveEventBreakpoints();
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="lines">@@ -568,7 +569,10 @@
</span><span class="cx">         if (breakpoint === this._allRequestsBreakpoint)
</span><span class="cx">             this._allRequestsBreakpointEnabledSetting.value = !breakpoint.disabled;
</span><span class="cx"> 
</span><del>-        this._updateURLBreakpoint(breakpoint);
</del><ins>+        for (let target of WI.targets) {
+            if (target.DOMDebuggerAgent)
+                this._updateURLBreakpoint(breakpoint, target);
+        }
</ins><span class="cx">         this._saveURLBreakpoints();
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="lines">@@ -578,9 +582,9 @@
</span><span class="cx">         this._detachBreakpointsForFrame(frame);
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    _mainFrameDidChange()
</del><ins>+    _mainFrameDidChange(event)
</ins><span class="cx">     {
</span><del>-        this._speculativelyResolveBreakpoints();
</del><ins>+        this._speculativelyResolveDOMBreakpointsForURL(WI.networkManager.mainFrame.url);
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     _mainResourceDidChange(event)
</span><span class="lines">@@ -587,14 +591,14 @@
</span><span class="cx">     {
</span><span class="cx">         let frame = event.target;
</span><span class="cx">         if (frame.isMainFrame()) {
</span><del>-            for (let breakpoints of this._domBreakpointURLMap.values())
-                breakpoints.forEach((breakpoint) => { breakpoint.domNodeIdentifier = null; });
</del><ins>+            for (let breakpoint of this._domBreakpointURLMap.values())
+                breakpoint.domNodeIdentifier = null;
</ins><span class="cx"> 
</span><span class="cx">             this._domBreakpointFrameIdentifierMap.clear();
</span><span class="cx">         } else
</span><span class="cx">             this._detachBreakpointsForFrame(frame);
</span><span class="cx"> 
</span><del>-        this._speculativelyResolveBreakpoints();
</del><ins>+        this._speculativelyResolveDOMBreakpointsForURL(frame.url);
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     _nodeInserted(event)
</span></span></pre></div>
<a id="trunkSourceWebInspectorUIUserInterfaceMainhtml"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebInspectorUI/UserInterface/Main.html (242742 => 242743)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebInspectorUI/UserInterface/Main.html      2019-03-11 21:55:00 UTC (rev 242742)
+++ trunk/Source/WebInspectorUI/UserInterface/Main.html 2019-03-11 21:56:32 UTC (rev 242743)
</span><span class="lines">@@ -281,6 +281,7 @@
</span><span class="cx">     <script src="Base/DebuggableType.js"></script>
</span><span class="cx">     <script src="Base/LinkedList.js"></script>
</span><span class="cx">     <script src="Base/ListMultimap.js"></script>
</span><ins>+    <script src="Base/Multimap.js"></script>
</ins><span class="cx">     <script src="Base/Object.js"></script>
</span><span class="cx">     <script src="Base/Throttler.js"></script>
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceWebInspectorUIUserInterfaceTesthtml"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebInspectorUI/UserInterface/Test.html (242742 => 242743)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebInspectorUI/UserInterface/Test.html      2019-03-11 21:55:00 UTC (rev 242742)
+++ trunk/Source/WebInspectorUI/UserInterface/Test.html 2019-03-11 21:56:32 UTC (rev 242743)
</span><span class="lines">@@ -41,6 +41,7 @@
</span><span class="cx">     <script src="Base/DebuggableType.js"></script>
</span><span class="cx">     <script src="Base/LinkedList.js"></script>
</span><span class="cx">     <script src="Base/ListMultimap.js"></script>
</span><ins>+    <script src="Base/Multimap.js"></script>
</ins><span class="cx">     <script src="Base/Object.js"></script>
</span><span class="cx">     <script src="Base/Throttler.js"></script>
</span><span class="cx"> 
</span></span></pre>
</div>
</div>

</body>
</html>