<!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>[201019] 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/201019">201019</a></dd>
<dt>Author</dt> <dd>bburg@apple.com</dd>
<dt>Date</dt> <dd>2016-05-17 10:33:20 -0700 (Tue, 17 May 2016)</dd>
</dl>

<h3>Log Message</h3>
<pre>Web Inspector: breakpoints in sourceURL named scripts are not persisted
https://bugs.webkit.org/show_bug.cgi?id=157714
&lt;rdar://problem/26287099&gt;

Reviewed by Joseph Pecoraro.

The Inspector frontend doesn't try to persist a breakpoint that
lacks a URL, even if the breakpoint has a sourceURL. Similarly, for
breakpoints without a URL, the frontend asks the backend to create
the breakpoint for a specific script identifier rather than a
URL-based breakpoint. This prevents breakpoints in injected scripts
from being resolved if the page is reloaded.

The Inspector backend knows how to resolve URL-based breakpoints
by matching against the script's URL or sourceURL, so we just need
to teach the frontend when either is appropriate to use.

This patch adds SourceCode.contentIdentifier, which is roughly
`url || sourceURL` for content that is not emphemeral, such as
console evaluations. Change breakpoint and debugger code to use
`contentIdentifier` rather than `url`, and pass contentIdentifier
to the backend when setting a breakpoint by URL.

* UserInterface/Controllers/DebuggerManager.js:
(WebInspector.DebuggerManager.prototype.breakpointsForSourceCode):
(WebInspector.DebuggerManager.prototype.scriptsForURL):
(WebInspector.DebuggerManager.prototype.get searchableScripts):
(WebInspector.DebuggerManager.prototype.removeBreakpoint):
(WebInspector.DebuggerManager.prototype.reset):
(WebInspector.DebuggerManager.prototype.scriptDidParse):
(WebInspector.DebuggerManager.prototype._setBreakpoint):
(WebInspector.DebuggerManager.prototype._saveBreakpoints):
(WebInspector.DebuggerManager.prototype._associateBreakpointsWithSourceCode):

* UserInterface/Models/Breakpoint.js:
(WebInspector.Breakpoint):
(WebInspector.Breakpoint.prototype.get contentIdentifier):
(WebInspector.Breakpoint.prototype.get info):
(WebInspector.Breakpoint.prototype.saveIdentityToCookie):
(WebInspector.Breakpoint.prototype.get url): Deleted.
Replace uses of Breakpoint.prototype.get url with
contentIdentifier inside the class and at all callsites.

* UserInterface/Models/Script.js:
(WebInspector.Script.prototype.get contentIdentifier):
Added. Use the URL, or the sourceURL unless the script is
ephemeral and only run once, like as a console evaluation.

* UserInterface/Models/SourceCode.js:
(WebInspector.SourceCode.prototype.get url): Added.
All subclasses already override this getter. Add it here so that
the default implementation of contentIdentifier can use it.

(WebInspector.SourceCode.prototype.get contentIdentifier): Added.

* UserInterface/Views/BreakpointTreeElement.js:
(WebInspector.BreakpointTreeElement.prototype.get filterableData):
* UserInterface/Views/ProbeSetDetailsSection.js:
(WebInspector.ProbeSetDetailsSection.prototype._updateLinkElement):
* UserInterface/Views/SourceCodeTextEditor.js:
(WebInspector.SourceCodeTextEditor.prototype._matchesBreakpoint):
* UserInterface/Views/TextResourceContentView.js:
(WebInspector.TextResourceContentView.prototype.get supplementalRepresentedObjects):</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkSourceWebInspectorUIChangeLog">trunk/Source/WebInspectorUI/ChangeLog</a></li>
<li><a href="#trunkSourceWebInspectorUIUserInterfaceControllersDebuggerManagerjs">trunk/Source/WebInspectorUI/UserInterface/Controllers/DebuggerManager.js</a></li>
<li><a href="#trunkSourceWebInspectorUIUserInterfaceModelsBreakpointjs">trunk/Source/WebInspectorUI/UserInterface/Models/Breakpoint.js</a></li>
<li><a href="#trunkSourceWebInspectorUIUserInterfaceModelsScriptjs">trunk/Source/WebInspectorUI/UserInterface/Models/Script.js</a></li>
<li><a href="#trunkSourceWebInspectorUIUserInterfaceModelsSourceCodejs">trunk/Source/WebInspectorUI/UserInterface/Models/SourceCode.js</a></li>
<li><a href="#trunkSourceWebInspectorUIUserInterfaceViewsBreakpointTreeElementjs">trunk/Source/WebInspectorUI/UserInterface/Views/BreakpointTreeElement.js</a></li>
<li><a href="#trunkSourceWebInspectorUIUserInterfaceViewsProbeSetDetailsSectionjs">trunk/Source/WebInspectorUI/UserInterface/Views/ProbeSetDetailsSection.js</a></li>
<li><a href="#trunkSourceWebInspectorUIUserInterfaceViewsSourceCodeTextEditorjs">trunk/Source/WebInspectorUI/UserInterface/Views/SourceCodeTextEditor.js</a></li>
<li><a href="#trunkSourceWebInspectorUIUserInterfaceViewsTextResourceContentViewjs">trunk/Source/WebInspectorUI/UserInterface/Views/TextResourceContentView.js</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkSourceWebInspectorUIChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebInspectorUI/ChangeLog (201018 => 201019)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebInspectorUI/ChangeLog        2016-05-17 17:07:19 UTC (rev 201018)
+++ trunk/Source/WebInspectorUI/ChangeLog        2016-05-17 17:33:20 UTC (rev 201019)
</span><span class="lines">@@ -1,3 +1,69 @@
</span><ins>+2016-05-17  Brian Burg  &lt;bburg@apple.com&gt;
+
+        Web Inspector: breakpoints in sourceURL named scripts are not persisted
+        https://bugs.webkit.org/show_bug.cgi?id=157714
+        &lt;rdar://problem/26287099&gt;
+
+        Reviewed by Joseph Pecoraro.
+
+        The Inspector frontend doesn't try to persist a breakpoint that
+        lacks a URL, even if the breakpoint has a sourceURL. Similarly, for
+        breakpoints without a URL, the frontend asks the backend to create
+        the breakpoint for a specific script identifier rather than a
+        URL-based breakpoint. This prevents breakpoints in injected scripts
+        from being resolved if the page is reloaded.
+
+        The Inspector backend knows how to resolve URL-based breakpoints
+        by matching against the script's URL or sourceURL, so we just need
+        to teach the frontend when either is appropriate to use.
+
+        This patch adds SourceCode.contentIdentifier, which is roughly
+        `url || sourceURL` for content that is not emphemeral, such as
+        console evaluations. Change breakpoint and debugger code to use
+        `contentIdentifier` rather than `url`, and pass contentIdentifier
+        to the backend when setting a breakpoint by URL.
+
+        * UserInterface/Controllers/DebuggerManager.js:
+        (WebInspector.DebuggerManager.prototype.breakpointsForSourceCode):
+        (WebInspector.DebuggerManager.prototype.scriptsForURL):
+        (WebInspector.DebuggerManager.prototype.get searchableScripts):
+        (WebInspector.DebuggerManager.prototype.removeBreakpoint):
+        (WebInspector.DebuggerManager.prototype.reset):
+        (WebInspector.DebuggerManager.prototype.scriptDidParse):
+        (WebInspector.DebuggerManager.prototype._setBreakpoint):
+        (WebInspector.DebuggerManager.prototype._saveBreakpoints):
+        (WebInspector.DebuggerManager.prototype._associateBreakpointsWithSourceCode):
+
+        * UserInterface/Models/Breakpoint.js:
+        (WebInspector.Breakpoint):
+        (WebInspector.Breakpoint.prototype.get contentIdentifier):
+        (WebInspector.Breakpoint.prototype.get info):
+        (WebInspector.Breakpoint.prototype.saveIdentityToCookie):
+        (WebInspector.Breakpoint.prototype.get url): Deleted.
+        Replace uses of Breakpoint.prototype.get url with
+        contentIdentifier inside the class and at all callsites.
+
+        * UserInterface/Models/Script.js:
+        (WebInspector.Script.prototype.get contentIdentifier):
+        Added. Use the URL, or the sourceURL unless the script is
+        ephemeral and only run once, like as a console evaluation.
+
+        * UserInterface/Models/SourceCode.js:
+        (WebInspector.SourceCode.prototype.get url): Added.
+        All subclasses already override this getter. Add it here so that
+        the default implementation of contentIdentifier can use it.
+
+        (WebInspector.SourceCode.prototype.get contentIdentifier): Added.
+
+        * UserInterface/Views/BreakpointTreeElement.js:
+        (WebInspector.BreakpointTreeElement.prototype.get filterableData):
+        * UserInterface/Views/ProbeSetDetailsSection.js:
+        (WebInspector.ProbeSetDetailsSection.prototype._updateLinkElement):
+        * UserInterface/Views/SourceCodeTextEditor.js:
+        (WebInspector.SourceCodeTextEditor.prototype._matchesBreakpoint):
+        * UserInterface/Views/TextResourceContentView.js:
+        (WebInspector.TextResourceContentView.prototype.get supplementalRepresentedObjects):
+
</ins><span class="cx"> 2016-05-16  Joseph Pecoraro  &lt;pecoraro@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Uncaught Exception: TypeError: null is not an object (evaluating 'event.data.pathComponent.domTreeElement')
</span></span></pre></div>
<a id="trunkSourceWebInspectorUIUserInterfaceControllersDebuggerManagerjs"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebInspectorUI/UserInterface/Controllers/DebuggerManager.js (201018 => 201019)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebInspectorUI/UserInterface/Controllers/DebuggerManager.js        2016-05-17 17:07:19 UTC (rev 201018)
+++ trunk/Source/WebInspectorUI/UserInterface/Controllers/DebuggerManager.js        2016-05-17 17:33:20 UTC (rev 201019)
</span><span class="lines">@@ -53,7 +53,7 @@
</span><span class="cx">         this._allUncaughtExceptionsBreakpoint = new WebInspector.Breakpoint(specialBreakpointLocation, !this._allUncaughtExceptionsBreakpointEnabledSetting.value);
</span><span class="cx"> 
</span><span class="cx">         this._breakpoints = [];
</span><del>-        this._breakpointURLMap = new Map;
</del><ins>+        this._breakpointContentIdentifierMap = new Map;
</ins><span class="cx">         this._breakpointScriptIdentifierMap = new Map;
</span><span class="cx">         this._breakpointIdMap = new Map;
</span><span class="cx"> 
</span><span class="lines">@@ -65,7 +65,7 @@
</span><span class="cx"> 
</span><span class="cx">         this._internalWebKitScripts = [];
</span><span class="cx">         this._scriptIdMap = new Map;
</span><del>-        this._scriptURLMap = new Map;
</del><ins>+        this._scriptContentIdentifierMap = new Map;
</ins><span class="cx"> 
</span><span class="cx">         this._breakpointsSetting = new WebInspector.Setting(&quot;breakpoints&quot;, []);
</span><span class="cx">         this._breakpointsEnabledSetting = new WebInspector.Setting(&quot;breakpoints-enabled&quot;, true);
</span><span class="lines">@@ -288,10 +288,10 @@
</span><span class="cx">             });
</span><span class="cx">         }
</span><span class="cx"> 
</span><del>-        let urlBreakpoints = this._breakpointURLMap.get(sourceCode.url);
-        if (urlBreakpoints) {
-            this._associateBreakpointsWithSourceCode(urlBreakpoints, sourceCode);
-            return urlBreakpoints;
</del><ins>+        let contentIdentifierBreakpoints = this._breakpointContentIdentifierMap.get(sourceCode.contentIdentifier);
+        if (contentIdentifierBreakpoints) {
+            this._associateBreakpointsWithSourceCode(contentIdentifierBreakpoints, sourceCode);
+            return contentIdentifierBreakpoints;
</ins><span class="cx">         }
</span><span class="cx"> 
</span><span class="cx">         if (sourceCode instanceof WebInspector.Script) {
</span><span class="lines">@@ -318,7 +318,7 @@
</span><span class="cx">     scriptsForURL(url)
</span><span class="cx">     {
</span><span class="cx">         // FIXME: This may not be safe. A Resource's URL may differ from a Script's URL.
</span><del>-        return this._scriptURLMap.get(url) || [];
</del><ins>+        return this._scriptContentIdentifierMap.get(url) || [];
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     continueToLocation(scriptIdentifier, lineNumber, columnNumber)
</span><span class="lines">@@ -328,7 +328,7 @@
</span><span class="cx"> 
</span><span class="cx">     get searchableScripts()
</span><span class="cx">     {
</span><del>-        return this.knownNonResourceScripts.filter((script) =&gt; !!script.url);
</del><ins>+        return this.knownNonResourceScripts.filter((script) =&gt; !!script.contentIdentifier);
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     get knownNonResourceScripts()
</span><span class="lines">@@ -379,13 +379,13 @@
</span><span class="cx">         if (!breakpoint)
</span><span class="cx">             return;
</span><span class="cx"> 
</span><del>-        if (breakpoint.url) {
-            let urlBreakpoints = this._breakpointURLMap.get(breakpoint.url);
-            if (!urlBreakpoints) {
-                urlBreakpoints = [];
-                this._breakpointURLMap.set(breakpoint.url, urlBreakpoints);
</del><ins>+        if (breakpoint.contentIdentifier) {
+            let contentIdentifierBreakpoints = this._breakpointContentIdentifierMap.get(breakpoint.contentIdentifier);
+            if (!contentIdentifierBreakpoints) {
+                contentIdentifierBreakpoints = [];
+                this._breakpointContentIdentifierMap.set(breakpoint.contentIdentifier, contentIdentifierBreakpoints);
</ins><span class="cx">             }
</span><del>-            urlBreakpoints.push(breakpoint);
</del><ins>+            contentIdentifierBreakpoints.push(breakpoint);
</ins><span class="cx">         }
</span><span class="cx"> 
</span><span class="cx">         if (breakpoint.scriptIdentifier) {
</span><span class="lines">@@ -427,12 +427,12 @@
</span><span class="cx">         if (breakpoint.identifier)
</span><span class="cx">             this._removeBreakpoint(breakpoint);
</span><span class="cx"> 
</span><del>-        if (breakpoint.url) {
-            let urlBreakpoints = this._breakpointURLMap.get(breakpoint.url);
-            if (urlBreakpoints) {
-                urlBreakpoints.remove(breakpoint);
-                if (!urlBreakpoints.length)
-                    this._breakpointURLMap.delete(breakpoint.url);
</del><ins>+        if (breakpoint.contentIdentifier) {
+            let contentIdentifierBreakpoints = this._breakpointContentIdentifierMap.get(breakpoint.contentIdentifier);
+            if (contentIdentifierBreakpoints) {
+                contentIdentifierBreakpoints.remove(breakpoint);
+                if (!contentIdentifierBreakpoints.length)
+                    this._breakpointContentIdentifierMap.delete(breakpoint.contentIdentifier);
</ins><span class="cx">             }
</span><span class="cx">         }
</span><span class="cx"> 
</span><span class="lines">@@ -487,7 +487,7 @@
</span><span class="cx"> 
</span><span class="cx">         this._internalWebKitScripts = [];
</span><span class="cx">         this._scriptIdMap.clear();
</span><del>-        this._scriptURLMap.clear();
</del><ins>+        this._scriptContentIdentifierMap.clear();
</ins><span class="cx"> 
</span><span class="cx">         this._ignoreBreakpointDisplayLocationDidChangeEvent = true;
</span><span class="cx"> 
</span><span class="lines">@@ -591,11 +591,11 @@
</span><span class="cx"> 
</span><span class="cx">         this._scriptIdMap.set(scriptIdentifier, script);
</span><span class="cx"> 
</span><del>-        if (script.url) {
-            let scripts = this._scriptURLMap.get(script.url);
</del><ins>+        if (script.contentIdentifier) {
+            let scripts = this._scriptContentIdentifierMap.get(script.contentIdentifier);
</ins><span class="cx">             if (!scripts) {
</span><span class="cx">                 scripts = [];
</span><del>-                this._scriptURLMap.set(script.url, scripts);
</del><ins>+                this._scriptContentIdentifierMap.set(script.contentIdentifier, scripts);
</ins><span class="cx">             }
</span><span class="cx">             scripts.push(script);
</span><span class="cx">         }
</span><span class="lines">@@ -778,10 +778,10 @@
</span><span class="cx"> 
</span><span class="cx">         // COMPATIBILITY (iOS 7): iOS 7 and earlier, DebuggerAgent.setBreakpoint* took a &quot;condition&quot; string argument.
</span><span class="cx">         // This has been replaced with an &quot;options&quot; BreakpointOptions object.
</span><del>-        if (breakpoint.url) {
</del><ins>+        if (breakpoint.contentIdentifier) {
</ins><span class="cx">             DebuggerAgent.setBreakpointByUrl.invoke({
</span><span class="cx">                 lineNumber: breakpoint.sourceCodeLocation.lineNumber,
</span><del>-                url: breakpoint.url,
</del><ins>+                url: breakpoint.contentIdentifier,
</ins><span class="cx">                 urlRegex: undefined,
</span><span class="cx">                 columnNumber: breakpoint.sourceCodeLocation.columnNumber,
</span><span class="cx">                 condition: breakpoint.condition,
</span><span class="lines">@@ -949,7 +949,7 @@
</span><span class="cx">         if (this._restoringBreakpoints)
</span><span class="cx">             return;
</span><span class="cx"> 
</span><del>-        let breakpointsToSave = this._breakpoints.filter((breakpoint) =&gt; !!breakpoint.url);
</del><ins>+        let breakpointsToSave = this._breakpoints.filter((breakpoint) =&gt; !!breakpoint.contentIdentifier);
</ins><span class="cx">         let serializedBreakpoints = breakpointsToSave.map((breakpoint) =&gt; breakpoint.info);
</span><span class="cx">         this._breakpointsSetting.value = serializedBreakpoints;
</span><span class="cx">     }
</span><span class="lines">@@ -963,7 +963,7 @@
</span><span class="cx">             if (breakpoint.sourceCodeLocation.sourceCode === null)
</span><span class="cx">                 breakpoint.sourceCodeLocation.sourceCode = sourceCode;
</span><span class="cx">             // SourceCodes can be unequal if the SourceCodeLocation is associated with a Script and we are looking at the Resource.
</span><del>-            console.assert(breakpoint.sourceCodeLocation.sourceCode === sourceCode || breakpoint.sourceCodeLocation.sourceCode.url === sourceCode.url);
</del><ins>+            console.assert(breakpoint.sourceCodeLocation.sourceCode === sourceCode || breakpoint.sourceCodeLocation.sourceCode.contentIdentifier === sourceCode.contentIdentifier);
</ins><span class="cx">         }
</span><span class="cx"> 
</span><span class="cx">         this._ignoreBreakpointDisplayLocationDidChangeEvent = false;
</span></span></pre></div>
<a id="trunkSourceWebInspectorUIUserInterfaceModelsBreakpointjs"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebInspectorUI/UserInterface/Models/Breakpoint.js (201018 => 201019)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebInspectorUI/UserInterface/Models/Breakpoint.js        2016-05-17 17:07:19 UTC (rev 201018)
+++ trunk/Source/WebInspectorUI/UserInterface/Models/Breakpoint.js        2016-05-17 17:33:20 UTC (rev 201019)
</span><span class="lines">@@ -31,11 +31,12 @@
</span><span class="cx"> 
</span><span class="cx">         if (sourceCodeLocationOrInfo instanceof WebInspector.SourceCodeLocation) {
</span><span class="cx">             var sourceCode = sourceCodeLocationOrInfo.sourceCode;
</span><del>-            var url = sourceCode ? sourceCode.url : null;
</del><ins>+            var contentIdentifier = sourceCode ? sourceCode.contentIdentifier : null;
</ins><span class="cx">             var scriptIdentifier = sourceCode instanceof WebInspector.Script ? sourceCode.id : null;
</span><span class="cx">             var location = sourceCodeLocationOrInfo;
</span><span class="cx">         } else if (sourceCodeLocationOrInfo &amp;&amp; typeof sourceCodeLocationOrInfo === &quot;object&quot;) {
</span><del>-            var url = sourceCodeLocationOrInfo.url;
</del><ins>+            // The 'url' fallback is for transitioning from older frontends and should be removed.
+            var contentIdentifier = sourceCodeLocationOrInfo.contentIdentifier || sourceCodeLocationOrInfo.url;
</ins><span class="cx">             var lineNumber = sourceCodeLocationOrInfo.lineNumber || 0;
</span><span class="cx">             var columnNumber = sourceCodeLocationOrInfo.columnNumber || 0;
</span><span class="cx">             var location = new WebInspector.SourceCodeLocation(null, lineNumber, columnNumber);
</span><span class="lines">@@ -50,7 +51,7 @@
</span><span class="cx">             console.error(&quot;Unexpected type passed to WebInspector.Breakpoint&quot;, sourceCodeLocationOrInfo);
</span><span class="cx"> 
</span><span class="cx">         this._id = null;
</span><del>-        this._url = url || null;
</del><ins>+        this._contentIdentifier = contentIdentifier || null;
</ins><span class="cx">         this._scriptIdentifier = scriptIdentifier || null;
</span><span class="cx">         this._disabled = disabled || false;
</span><span class="cx">         this._condition = condition || &quot;&quot;;
</span><span class="lines">@@ -76,9 +77,9 @@
</span><span class="cx">         this._id = id || null;
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    get url()
</del><ins>+    get contentIdentifier()
</ins><span class="cx">     {
</span><del>-        return this._url;
</del><ins>+        return this._contentIdentifier;
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     get scriptIdentifier()
</span><span class="lines">@@ -196,7 +197,7 @@
</span><span class="cx">     {
</span><span class="cx">         // The id, scriptIdentifier and resolved state are tied to the current session, so don't include them for serialization.
</span><span class="cx">         return {
</span><del>-            url: this._url,
</del><ins>+            contentIdentifier: this._contentIdentifier,
</ins><span class="cx">             lineNumber: this._sourceCodeLocation.lineNumber,
</span><span class="cx">             columnNumber: this._sourceCodeLocation.columnNumber,
</span><span class="cx">             disabled: this._disabled,
</span><span class="lines">@@ -299,7 +300,7 @@
</span><span class="cx"> 
</span><span class="cx">     saveIdentityToCookie(cookie)
</span><span class="cx">     {
</span><del>-        cookie[WebInspector.Breakpoint.URLCookieKey] = this.url;
</del><ins>+        cookie[WebInspector.Breakpoint.ContentIdentifierCookieKey] = this.contentIdentifier;
</ins><span class="cx">         cookie[WebInspector.Breakpoint.LineNumberCookieKey] = this.sourceCodeLocation.lineNumber;
</span><span class="cx">         cookie[WebInspector.Breakpoint.ColumnNumberCookieKey] = this.sourceCodeLocation.columnNumber;
</span><span class="cx">     }
</span><span class="lines">@@ -340,7 +341,7 @@
</span><span class="cx"> WebInspector.Breakpoint.DefaultBreakpointActionType = WebInspector.BreakpointAction.Type.Log;
</span><span class="cx"> 
</span><span class="cx"> WebInspector.Breakpoint.TypeIdentifier = &quot;breakpoint&quot;;
</span><del>-WebInspector.Breakpoint.URLCookieKey = &quot;breakpoint-url&quot;;
</del><ins>+WebInspector.Breakpoint.ContentIdentifierCookieKey = &quot;breakpoint-content-identifier&quot;;
</ins><span class="cx"> WebInspector.Breakpoint.LineNumberCookieKey = &quot;breakpoint-line-number&quot;;
</span><span class="cx"> WebInspector.Breakpoint.ColumnNumberCookieKey = &quot;breakpoint-column-number&quot;;
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceWebInspectorUIUserInterfaceModelsScriptjs"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebInspectorUI/UserInterface/Models/Script.js (201018 => 201019)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebInspectorUI/UserInterface/Models/Script.js        2016-05-17 17:07:19 UTC (rev 201018)
+++ trunk/Source/WebInspectorUI/UserInterface/Models/Script.js        2016-05-17 17:33:20 UTC (rev 201019)
</span><span class="lines">@@ -90,6 +90,28 @@
</span><span class="cx">         return this._url;
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    get contentIdentifier()
+    {
+        if (this._url)
+            return this._url;
+
+        if (!this._sourceURL)
+            return null;
+
+        // Since reused content identifiers can cause breakpoints
+        // to show up in completely unrelated files, sourceURLs should
+        // be unique where possible. The checks below exclude cases
+        // where sourceURLs are intentionally reused and we would never
+        // expect a breakpoint to be persisted across sessions.
+        if (isWebInspectorConsoleEvaluationScript(this._sourceURL))
+            return null;
+
+        if (isWebInspectorInternalScript(this._sourceURL))
+            return null;
+
+        return this._sourceURL;
+    }
+
</ins><span class="cx">     get sourceURL()
</span><span class="cx">     {
</span><span class="cx">         return this._sourceURL;
</span></span></pre></div>
<a id="trunkSourceWebInspectorUIUserInterfaceModelsSourceCodejs"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebInspectorUI/UserInterface/Models/SourceCode.js (201018 => 201019)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebInspectorUI/UserInterface/Models/SourceCode.js        2016-05-17 17:07:19 UTC (rev 201018)
+++ trunk/Source/WebInspectorUI/UserInterface/Models/SourceCode.js        2016-05-17 17:33:20 UTC (rev 201019)
</span><span class="lines">@@ -76,6 +76,20 @@
</span><span class="cx">         return this._currentRevision.content;
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    get url()
+    {
+        // To be overridden by subclasses.
+    }
+
+    get contentIdentifier()
+    {
+        // A contentIdentifier is roughly `url || sourceURL` for cases where
+        // the content is consistent between sessions and not ephemeral.
+
+        // Can be overridden by subclasses if better behavior is possible.
+        return this.url;
+    }
+
</ins><span class="cx">     get sourceMaps()
</span><span class="cx">     {
</span><span class="cx">         return this._sourceMaps || [];
</span></span></pre></div>
<a id="trunkSourceWebInspectorUIUserInterfaceViewsBreakpointTreeElementjs"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebInspectorUI/UserInterface/Views/BreakpointTreeElement.js (201018 => 201019)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebInspectorUI/UserInterface/Views/BreakpointTreeElement.js        2016-05-17 17:07:19 UTC (rev 201018)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/BreakpointTreeElement.js        2016-05-17 17:33:20 UTC (rev 201019)
</span><span class="lines">@@ -72,7 +72,7 @@
</span><span class="cx"> 
</span><span class="cx">     get filterableData()
</span><span class="cx">     {
</span><del>-        return {text: [this.breakpoint.url]};
</del><ins>+        return {text: [this.breakpoint.contentIdentifier]};
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     ondelete()
</span></span></pre></div>
<a id="trunkSourceWebInspectorUIUserInterfaceViewsProbeSetDetailsSectionjs"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebInspectorUI/UserInterface/Views/ProbeSetDetailsSection.js (201018 => 201019)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebInspectorUI/UserInterface/Views/ProbeSetDetailsSection.js        2016-05-17 17:07:19 UTC (rev 201018)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/ProbeSetDetailsSection.js        2016-05-17 17:33:20 UTC (rev 201019)
</span><span class="lines">@@ -96,7 +96,7 @@
</span><span class="cx">             console.assert(!breakpoint.resolved);
</span><span class="cx"> 
</span><span class="cx">             var location = breakpoint.sourceCodeLocation;
</span><del>-            titleElement = WebInspector.linkifyLocation(breakpoint.url, location.displayLineNumber, location.displayColumnNumber);
</del><ins>+            titleElement = WebInspector.linkifyLocation(breakpoint.contentIdentifier, location.displayLineNumber, location.displayColumnNumber);
</ins><span class="cx">         }
</span><span class="cx"> 
</span><span class="cx">         titleElement.classList.add(WebInspector.ProbeSetDetailsSection.DontFloatLinkStyleClassName);
</span></span></pre></div>
<a id="trunkSourceWebInspectorUIUserInterfaceViewsSourceCodeTextEditorjs"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebInspectorUI/UserInterface/Views/SourceCodeTextEditor.js (201018 => 201019)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebInspectorUI/UserInterface/Views/SourceCodeTextEditor.js        2016-05-17 17:07:19 UTC (rev 201018)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/SourceCodeTextEditor.js        2016-05-17 17:33:20 UTC (rev 201019)
</span><span class="lines">@@ -788,9 +788,9 @@
</span><span class="cx">         if (this._sourceCode instanceof WebInspector.SourceMapResource)
</span><span class="cx">             return breakpoint.sourceCodeLocation.displaySourceCode === this._sourceCode;
</span><span class="cx">         if (this._sourceCode instanceof WebInspector.Resource)
</span><del>-            return breakpoint.url === this._sourceCode.url;
</del><ins>+            return breakpoint.contentIdentifier === this._sourceCode.contentIdentifier;
</ins><span class="cx">         if (this._sourceCode instanceof WebInspector.Script)
</span><del>-            return breakpoint.url === this._sourceCode.url || breakpoint.scriptIdentifier === this._sourceCode.id;
</del><ins>+            return breakpoint.contentIdentifier === this._sourceCode.contentIdentifier || breakpoint.scriptIdentifier === this._sourceCode.id;
</ins><span class="cx">         return false;
</span><span class="cx">     }
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceWebInspectorUIUserInterfaceViewsTextResourceContentViewjs"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebInspectorUI/UserInterface/Views/TextResourceContentView.js (201018 => 201019)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebInspectorUI/UserInterface/Views/TextResourceContentView.js        2016-05-17 17:07:19 UTC (rev 201018)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/TextResourceContentView.js        2016-05-17 17:33:20 UTC (rev 201019)
</span><span class="lines">@@ -78,7 +78,7 @@
</span><span class="cx">     get supplementalRepresentedObjects()
</span><span class="cx">     {
</span><span class="cx">         var objects = WebInspector.probeManager.probeSets.filter(function(probeSet) {
</span><del>-            return this._resource.url === probeSet.breakpoint.url;
</del><ins>+            return this._resource.contentIdentifier === probeSet.breakpoint.contentIdentifier;
</ins><span class="cx">         }, this);
</span><span class="cx"> 
</span><span class="cx">         // If the SourceCodeTextEditor has an executionLineNumber, we can assume
</span></span></pre>
</div>
</div>

</body>
</html>