Web Inspector: debuggerPresentatioModel.linkifyLocation leaks updateAnchor closure...
authorloislo@chromium.org <loislo@chromium.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 3 Oct 2011 15:07:00 +0000 (15:07 +0000)
committerloislo@chromium.org <loislo@chromium.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 3 Oct 2011 15:07:00 +0000 (15:07 +0000)
https://bugs.webkit.org/show_bug.cgi?id=69146

In many places we use linkifyLocation function to produce a link node which updates automatically when the source file is changed on the fly.
Such changes happen when we use pretty print or another operation that changes the source code somehow.
linkifyLocation associates a new instance of updateAnchor closure with the each link node and add the closure to the SourceMappingUpdated event's list.
As the result the node<->closure pairs wouldn't be collected until reset the UI and DebuggerPresentationModel.

Reviewed by Yury Semikhatsky.

Test: inspector/performance/resources/network-append-30-requests.html

* WebCore.gypi:
* WebCore.vcproj/WebCore.vcproj:
* inspector/front-end/ConsoleMessage.js:
(WebInspector.ConsoleMessage.prototype._linkifyLocation):
* inspector/front-end/ConsoleView.js:
(WebInspector.ConsoleView.prototype._consoleCleared):
* inspector/front-end/DebuggerPresentationModel.js:
* inspector/front-end/EventListenersSidebarPane.js:
(WebInspector.EventListenersSidebarPane.prototype.update.callback):
(WebInspector.EventListenersSidebarPane.prototype.update):
():
* inspector/front-end/Linkifier.js: Added.
(WebInspector.Linkifier):
(WebInspector.Linkifier.prototype.linkifyLocation):
(WebInspector.Linkifier.prototype.reset):
(WebInspector.Linkifier.prototype._updateSourceAnchors):
(WebInspector.Linkifier.prototype._updateAnchor):
* inspector/front-end/NetworkPanel.js:
(WebInspector.NetworkLogView):
(WebInspector.NetworkLogView.prototype._reset):
(WebInspector.NetworkDataGridNode.prototype._refreshInitiatorCell):
* inspector/front-end/ProfileDataGridTree.js:
(WebInspector.ProfileDataGridNode.prototype.createCell):
* inspector/front-end/ProfileView.js:
(WebInspector.CPUProfileView):
(WebInspector.CPUProfileView.prototype._resetClicked):
* inspector/front-end/TimelinePanel.js:
(WebInspector.TimelinePanel):
(WebInspector.TimelinePanel.prototype._linkifyLocation):
(WebInspector.TimelinePanel.prototype._linkifyCallFrame):
(WebInspector.TimelinePanel.prototype._clearPanel):
(WebInspector.TimelinePanel.FormattedRecord):
(WebInspector.TimelinePanel.FormattedRecord.prototype._generatePopupContent):
(WebInspector.TimelinePanel.FormattedRecord.prototype._getRecordDetails):
(WebInspector.TimelinePanel.PopupContentHelper):
(WebInspector.TimelinePanel.PopupContentHelper.prototype._appendLinkRow):
(WebInspector.TimelinePanel.PopupContentHelper.prototype._appendStackTrace):
* inspector/front-end/WebKit.qrc:
* inspector/front-end/inspector.html:
* inspector/front-end/inspector.js:

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@96500 268f45cc-cd09-0410-ab3c-d52691b4dbfc

15 files changed:
Source/WebCore/ChangeLog
Source/WebCore/WebCore.gypi
Source/WebCore/WebCore.vcproj/WebCore.vcproj
Source/WebCore/inspector/front-end/ConsoleMessage.js
Source/WebCore/inspector/front-end/ConsoleView.js
Source/WebCore/inspector/front-end/DebuggerPresentationModel.js
Source/WebCore/inspector/front-end/EventListenersSidebarPane.js
Source/WebCore/inspector/front-end/Linkifier.js [new file with mode: 0644]
Source/WebCore/inspector/front-end/NetworkPanel.js
Source/WebCore/inspector/front-end/ProfileDataGridTree.js
Source/WebCore/inspector/front-end/ProfileView.js
Source/WebCore/inspector/front-end/TimelinePanel.js
Source/WebCore/inspector/front-end/WebKit.qrc
Source/WebCore/inspector/front-end/inspector.html
Source/WebCore/inspector/front-end/inspector.js

index 15cf43d927c63ea0d66217f5639c746588c787d7..0526f8f884d6b5adae135041c155f63ca9dfb813 100644 (file)
@@ -1,3 +1,58 @@
+2011-10-03  Ilya Tikhonovsky  <loislo@chromium.org>
+
+        Web Inspector: debuggerPresentatioModel.linkifyLocation leaks updateAnchor closure instances.
+        https://bugs.webkit.org/show_bug.cgi?id=69146
+
+        In many places we use linkifyLocation function to produce a link node which updates automatically when the source file is changed on the fly.
+        Such changes happen when we use pretty print or another operation that changes the source code somehow.
+        linkifyLocation associates a new instance of updateAnchor closure with the each link node and add the closure to the SourceMappingUpdated event's list.
+        As the result the node<->closure pairs wouldn't be collected until reset the UI and DebuggerPresentationModel.
+
+        Reviewed by Yury Semikhatsky.
+
+        Test: inspector/performance/resources/network-append-30-requests.html
+
+        * WebCore.gypi:
+        * WebCore.vcproj/WebCore.vcproj:
+        * inspector/front-end/ConsoleMessage.js:
+        (WebInspector.ConsoleMessage.prototype._linkifyLocation):
+        * inspector/front-end/ConsoleView.js:
+        (WebInspector.ConsoleView.prototype._consoleCleared):
+        * inspector/front-end/DebuggerPresentationModel.js:
+        * inspector/front-end/EventListenersSidebarPane.js:
+        (WebInspector.EventListenersSidebarPane.prototype.update.callback):
+        (WebInspector.EventListenersSidebarPane.prototype.update):
+        ():
+        * inspector/front-end/Linkifier.js: Added.
+        (WebInspector.Linkifier):
+        (WebInspector.Linkifier.prototype.linkifyLocation):
+        (WebInspector.Linkifier.prototype.reset):
+        (WebInspector.Linkifier.prototype._updateSourceAnchors):
+        (WebInspector.Linkifier.prototype._updateAnchor):
+        * inspector/front-end/NetworkPanel.js:
+        (WebInspector.NetworkLogView):
+        (WebInspector.NetworkLogView.prototype._reset):
+        (WebInspector.NetworkDataGridNode.prototype._refreshInitiatorCell):
+        * inspector/front-end/ProfileDataGridTree.js:
+        (WebInspector.ProfileDataGridNode.prototype.createCell):
+        * inspector/front-end/ProfileView.js:
+        (WebInspector.CPUProfileView):
+        (WebInspector.CPUProfileView.prototype._resetClicked):
+        * inspector/front-end/TimelinePanel.js:
+        (WebInspector.TimelinePanel):
+        (WebInspector.TimelinePanel.prototype._linkifyLocation):
+        (WebInspector.TimelinePanel.prototype._linkifyCallFrame):
+        (WebInspector.TimelinePanel.prototype._clearPanel):
+        (WebInspector.TimelinePanel.FormattedRecord):
+        (WebInspector.TimelinePanel.FormattedRecord.prototype._generatePopupContent):
+        (WebInspector.TimelinePanel.FormattedRecord.prototype._getRecordDetails):
+        (WebInspector.TimelinePanel.PopupContentHelper):
+        (WebInspector.TimelinePanel.PopupContentHelper.prototype._appendLinkRow):
+        (WebInspector.TimelinePanel.PopupContentHelper.prototype._appendStackTrace):
+        * inspector/front-end/WebKit.qrc:
+        * inspector/front-end/inspector.html:
+        * inspector/front-end/inspector.js:
+
 2011-10-03  Pavel Feldman  <pfeldman@google.com>
 
         Web Inspector: more compilation fixes including making ConsoleMessage a part of console model.
index fa3f9123dc79e13463fcef0576e0e084d1b93162..6fb2be099fb213012b5d16f897b799ec43a0963c 100644 (file)
             'inspector/front-end/DataGrid.js',
             'inspector/front-end/DebuggerModel.js',
             'inspector/front-end/DebuggerPresentationModel.js',
+            'inspector/front-end/Linkifier.js',
             'inspector/front-end/DetailedHeapshotGridNodes.js',
             'inspector/front-end/DetailedHeapshotView.js',
             'inspector/front-end/DOMAgent.js',
index fe9fbf5ed202dfaaa2ca8809da14c3e4d2ddc11d..2cd82209e162eeede2551398a0b5264f705190c1 100755 (executable)
                                        RelativePath="..\inspector\front-end\KeyboardShortcut.js"
                                        >
                                </File>
+                               <File
+                                       RelativePath="..\inspector\front-end\Linkifier.js"
+                                       >
+                               </File>
                                <File
                                        RelativePath="..\inspector\front-end\MetricsSidebarPane.js"
                                        >
index 3e7083f528eb51f61c30d8116a3dff64cbf162ce..456bdd09395003562e5ea6fb0e3c827b391b36d0 100644 (file)
@@ -194,7 +194,7 @@ WebInspector.ConsoleMessageImpl.prototype = {
         // FIXME(62725): stack trace line/column numbers are one-based.
         lineNumber = lineNumber ? lineNumber - 1 : undefined;
         columnNumber = columnNumber ? columnNumber - 1 : 0;
-        return WebInspector.debuggerPresentationModel.linkifyLocation(url, lineNumber, columnNumber, "console-message-url");
+        return WebInspector.ConsoleView.linkifier.linkifyLocation(url, lineNumber, columnNumber, "console-message-url");
     },
 
     _linkifyCallFrame: function(callFrame)
index 54b1ba0b4dd930bad01dd9c24ae48f1b6deaeb85..5d132a1ed1c3a97ca03c367c802e9fd40f320fea 100644 (file)
@@ -109,6 +109,8 @@ WebInspector.ConsoleView = function()
 
     WebInspector.console.addEventListener(WebInspector.ConsoleModel.Events.MessageAdded, this._consoleMessageAdded, this);
     WebInspector.console.addEventListener(WebInspector.ConsoleModel.Events.ConsoleCleared, this._consoleCleared, this);
+
+    WebInspector.ConsoleView.linkifier = new WebInspector.Linkifier(WebInspector.debuggerPresentationModel);
 }
 
 WebInspector.ConsoleView.Events = {
@@ -328,6 +330,8 @@ WebInspector.ConsoleView.prototype = {
         delete this.previousMessage;
 
         this.dispatchEventToListeners(WebInspector.ConsoleView.Events.ConsoleCleared);
+
+        WebInspector.ConsoleView.linkifier.reset();
     },
 
     completions: function(wordRange, bestMatchOnly, completionsReadyCallback)
index 3b2f8849869cdbd7bc595a7d78927a6dec8bbd7d..4a2875c61976320848b60c4eccddab70151a3c4d 100644 (file)
@@ -66,32 +66,6 @@ WebInspector.DebuggerPresentationModel.Events = {
 }
 
 WebInspector.DebuggerPresentationModel.prototype = {
-    linkifyLocation: function(sourceURL, lineNumber, columnNumber, classes)
-    {
-        var linkText = WebInspector.formatLinkText(sourceURL, lineNumber);
-        var anchor = WebInspector.linkifyURLAsNode(sourceURL, linkText, classes, false);
-
-        var rawSourceCode = this._rawSourceCodeForScript(sourceURL);
-        if (!rawSourceCode) {
-            anchor.setAttribute("preferred_panel", "resources");
-            anchor.setAttribute("line_number", lineNumber);
-            return anchor;
-        }
-
-        function updateAnchor()
-        {
-            var uiLocation = rawSourceCode.sourceMapping.rawLocationToUILocation({ lineNumber: lineNumber, columnNumber: columnNumber });
-            anchor.textContent = WebInspector.formatLinkText(uiLocation.uiSourceCode.url, uiLocation.lineNumber);
-            anchor.setAttribute("preferred_panel", "scripts");
-            anchor.uiSourceCode = uiLocation.uiSourceCode;
-            anchor.lineNumber = uiLocation.lineNumber;
-        }
-        if (rawSourceCode.sourceMapping)
-            updateAnchor.call(this);
-        rawSourceCode.addEventListener(WebInspector.RawSourceCode.Events.SourceMappingUpdated, updateAnchor, this);
-        return anchor;
-    },
-
     _parsedScriptSource: function(event)
     {
         this._addScript(event.data);
index 2eb8649601bfc3048f05fe7adcb56cb5238fc3df..dee33142febb92c97c479c3daf01d80a37539af2 100644 (file)
@@ -56,6 +56,8 @@ WebInspector.EventListenersSidebarPane = function()
     this.settingsSelectElement.addEventListener("change", this._changeSetting.bind(this), false);
 
     this.titleElement.appendChild(this.settingsSelectElement);
+
+    this._linkifier = new WebInspector.Linkifier(WebInspector.debuggerPresentationModel);
 }
 
 WebInspector.EventListenersSidebarPane._objectGroupName = "event-listeners-sidebar-pane";
@@ -64,6 +66,8 @@ WebInspector.EventListenersSidebarPane.prototype = {
     update: function(node)
     {
         RuntimeAgent.releaseObjectGroup(WebInspector.EventListenersSidebarPane._objectGroupName);
+        this._linkifier.reset();
+
         var body = this.bodyElement;
         body.removeChildren();
         this.sections = [];
@@ -84,7 +88,7 @@ WebInspector.EventListenersSidebarPane.prototype = {
                 var type = eventListener.type;
                 var section = sectionMap[type];
                 if (!section) {
-                    section = new WebInspector.EventListenersSection(type, node.id);
+                    section = new WebInspector.EventListenersSection(type, node.id, self._linkifier);
                     sectionMap[type] = section;
                     sectionNames.push(type);
                     self.sections.push(section);
@@ -124,10 +128,11 @@ WebInspector.EventListenersSidebarPane.prototype = {
 
 WebInspector.EventListenersSidebarPane.prototype.__proto__ = WebInspector.SidebarPane.prototype;
 
-WebInspector.EventListenersSection = function(title, nodeId)
+WebInspector.EventListenersSection = function(title, nodeId, linkifier)
 {
     this.eventListeners = [];
     this._nodeId = nodeId;
+    this._linkifier = linkifier;
     WebInspector.PropertiesSection.call(this, title);
 
     // Changed from a Properties List
@@ -158,7 +163,7 @@ WebInspector.EventListenersSection.prototype = {
         var length = filteredEventListeners.length;
         for (var i = 0; i < length; ++i) {
             var eventListener = filteredEventListeners[i];
-            var eventListenerBar = new WebInspector.EventListenerBar(eventListener, this._nodeId);
+            var eventListenerBar = new WebInspector.EventListenerBar(eventListener, this._nodeId, this._linkifier);
             this.eventBars.appendChild(eventListenerBar.element);
         }
     },
@@ -171,13 +176,13 @@ WebInspector.EventListenersSection.prototype = {
 
 WebInspector.EventListenersSection.prototype.__proto__ = WebInspector.PropertiesSection.prototype;
 
-WebInspector.EventListenerBar = function(eventListener, nodeId)
+WebInspector.EventListenerBar = function(eventListener, nodeId, linkifier)
 {
     this.eventListener = eventListener;
     this._nodeId = nodeId;
     WebInspector.ObjectPropertiesSection.call(this);
     this._setNodeTitle();
-    this._setFunctionSubtitle();
+    this._setFunctionSubtitle(linkifier);
     this.editable = false;
     this.element.className = "event-bar"; /* Changed from "section" */
     this.headerElement.addStyleClass("source-code");
@@ -231,7 +236,7 @@ WebInspector.EventListenerBar.prototype = {
         this.titleElement.appendChild(WebInspector.panels.elements.linkifyNodeReference(this.eventListener.node));
     },
 
-    _setFunctionSubtitle: function()
+    _setFunctionSubtitle: function(linkifier)
     {
         // Requires that Function.toString() return at least the function's signature.
         if (this.eventListener.location) {
@@ -240,7 +245,7 @@ WebInspector.EventListenerBar.prototype = {
             var url = this.eventListener.location.scriptId;
             var lineNumber = this.eventListener.location.lineNumber - 1;
             var columnNumber = 0;
-            var urlElement = WebInspector.debuggerPresentationModel.linkifyLocation(url, lineNumber, columnNumber);
+            var urlElement = linkifier.linkifyLocation(url, lineNumber, columnNumber);
             this.subtitleElement.appendChild(urlElement);
         } else {
             var match = this.eventListener.handlerBody.match(/function ([^\(]+?)\(/);
diff --git a/Source/WebCore/inspector/front-end/Linkifier.js b/Source/WebCore/inspector/front-end/Linkifier.js
new file mode 100644 (file)
index 0000000..90dc7f7
--- /dev/null
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2011 Google 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:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * 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.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER OR 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.
+ */
+
+/**
+ * @constructor
+ */
+WebInspector.Linkifier = function(debuggerPresentationModel)
+{
+    this._debuggerPresentationModel = debuggerPresentationModel;
+    this._anchorsForURL = {};
+}
+
+WebInspector.Linkifier.prototype = {
+    linkifyLocation: function(sourceURL, lineNumber, columnNumber, classes)
+    {
+        var linkText = WebInspector.formatLinkText(sourceURL, lineNumber);
+        var anchor = WebInspector.linkifyURLAsNode(sourceURL, linkText, classes, false);
+        anchor.rawLocation = { lineNumber: lineNumber, columnNumber: columnNumber };
+
+        var rawSourceCode = this._debuggerPresentationModel._rawSourceCodeForScript(sourceURL);
+        if (!rawSourceCode) {
+            anchor.setAttribute("preferred_panel", "resources");
+            anchor.setAttribute("line_number", lineNumber);
+            return anchor;
+        }
+
+        var anchors = this._anchorsForURL[sourceURL];
+        if (!anchors) {
+            anchors = [];
+            this._anchorsForURL[sourceURL] = anchors;
+            rawSourceCode.addEventListener(WebInspector.RawSourceCode.Events.SourceMappingUpdated, this._updateSourceAnchors, this);
+        }
+
+        if (rawSourceCode.sourceMapping)
+            this._updateAnchor(rawSourceCode, anchor);
+        anchors.push(anchor);
+        return anchor;
+    },
+
+    reset: function()
+    {
+        for (var sourceURL in this._anchorsForURL) {
+            var rawSourceCode = this._debuggerPresentationModel._rawSourceCodeForScript(sourceURL);
+            if (rawSourceCode)
+                rawSourceCode.removeEventListener(WebInspector.RawSourceCode.Events.SourceMappingUpdated, this._updateSourceAncors, this);
+        }
+        this._anchorsForURL = {};
+    },
+
+    _updateSourceAnchors: function(event)
+    {
+        var rawSourceCode = event.target;
+        var anchors = this._anchorsForURL[rawSourceCode.url];
+        if (!anchors)
+            return;
+
+        for (var i = 0; i < anchors.length; ++i)
+            this._updateAnchor(rawSourceCode, anchors[i]);
+    },
+
+    _updateAnchor: function(rawSourceCode, anchor)
+    {
+        var uiLocation = rawSourceCode.sourceMapping.rawLocationToUILocation(anchor.rawLocation);
+        anchor.textContent = WebInspector.formatLinkText(uiLocation.uiSourceCode.url, uiLocation.lineNumber);
+        anchor.setAttribute("preferred_panel", "scripts");
+        anchor.uiSourceCode = uiLocation.uiSourceCode;
+        anchor.lineNumber = uiLocation.lineNumber;
+    }
+}
+
index 5bbb59b49227c9c8e09a6a0e2a8a4383d98ae931..3be9e47fb38633d9c97e1521999d0c41e14dc8fb 100644 (file)
@@ -56,6 +56,7 @@ WebInspector.NetworkLogView = function(parentElement)
 
     this._createStatusbarButtons();
     this._createFilterStatusBarItems();
+    this._linkifier = new WebInspector.Linkifier(WebInspector.debuggerPresentationModel);
 
     WebInspector.networkManager.addEventListener(WebInspector.NetworkManager.EventTypes.ResourceStarted, this._onResourceStarted, this);
     WebInspector.networkManager.addEventListener(WebInspector.NetworkManager.EventTypes.ResourceUpdated, this._onResourceUpdated, this);
@@ -735,7 +736,7 @@ WebInspector.NetworkLogView.prototype = {
 
         this._mainResourceLoadTime = -1;
         this._mainResourceDOMContentTime = -1;
-
+        this._linkifier.reset();
     },
 
     get resources()
@@ -2041,7 +2042,7 @@ WebInspector.NetworkDataGridNode.prototype = {
                     return;
                 }
                 this._initiatorCell.title = topFrame.url + ":" + topFrame.lineNumber;
-                var urlElement = WebInspector.debuggerPresentationModel.linkifyLocation(topFrame.url, topFrame.lineNumber - 1, 0);
+                var urlElement = this._parentView._linkifier.linkifyLocation(topFrame.url, topFrame.lineNumber - 1, 0);
                 this._initiatorCell.appendChild(urlElement);
                 this._appendSubtitle(this._initiatorCell, WebInspector.UIString("Script"));
             } else { // initiator.type === "parser"
index 585568c3aba06981cec8529f1142b90f2643b87e..cf40bc26e79093053fd792b3737528b349afb4f0 100644 (file)
@@ -98,7 +98,7 @@ WebInspector.ProfileDataGridNode.prototype = {
         if (this.profileNode.url) {
             // FIXME(62725): profileNode should reference a debugger location.
             var lineNumber = this.profileNode.lineNumber ? this.profileNode.lineNumber - 1 : 0;
-            var urlElement = WebInspector.debuggerPresentationModel.linkifyLocation(this.profileNode.url, lineNumber, 0, "profile-node-file");
+            var urlElement = this.profileView._linkifier.linkifyLocation(this.profileNode.url, lineNumber, 0, "profile-node-file");
             urlElement.style.maxWidth = "75%";
             cell.insertBefore(urlElement, cell.firstChild);
         }
index 2a03f83051da541efe41409c11bdd2ae89431ce2..62cffc0b900ef77293495386352361ef174fc01b 100644 (file)
@@ -96,6 +96,8 @@ WebInspector.CPUProfileView = function(profile)
         self._updatePercentButton();
     }
 
+    this._linkifier = new WebInspector.Linkifier(WebInspector.debuggerPresentationModel);
+
     ProfilerAgent.getProfile(this.profile.typeId, this.profile.uid, profileCallback);
 }
 
@@ -485,6 +487,7 @@ WebInspector.CPUProfileView.prototype = {
     {
         this.resetButton.visible = false;
         this.profileDataGridTree.restore();
+        this._linkiier.reset();
         this.refresh();
         this.refreshVisibleData();
     },
index e281c5cf2640e955cf95e24c2692455883ca9391..a922fb11bc2b1e2130eb5e8cd0f75948675ce97e 100644 (file)
@@ -109,6 +109,7 @@ WebInspector.TimelinePanel = function()
 
     this._registerShortcuts();
     WebInspector.timelineManager.addEventListener(WebInspector.TimelineManager.EventTypes.TimelineEventRecorded, this._onTimelineEventRecorded, this);
+    this._linkifier = new WebInspector.Linkifier(WebInspector.debuggerPresentationModel);
 }
 
 // Define row height, should be in sync with styles for timeline graphs.
@@ -116,6 +117,19 @@ WebInspector.TimelinePanel.rowHeight = 18;
 WebInspector.TimelinePanel.shortRecordThreshold = 0.015;
 
 WebInspector.TimelinePanel.prototype = {
+    _linkifyLocation: function(url, lineNumber, columnNumber)
+    {
+        // FIXME(62725): stack trace line/column numbers are one-based.
+        lineNumber = lineNumber ? lineNumber - 1 : lineNumber;
+        columnNumber = columnNumber ? columnNumber - 1 : 0;
+        return this._linkifier.linkifyLocation(url, lineNumber, columnNumber, "timeline-details");
+    },
+
+    _linkifyCallFrame: function(callFrame)
+    {
+        return this._linkifyLocation(callFrame.url, callFrame.lineNumber, callFrame.columnNumber);
+    },
+
     _createTopPane: function() {
         var topPaneElement = document.createElement("div");
         topPaneElement.id = "timeline-overview-panel";
@@ -528,6 +542,7 @@ WebInspector.TimelinePanel.prototype = {
         this._refresh();
         this._closeRecordDetails();
         this._model._reset();
+        this._linkifier.reset();
     },
 
     elementsToRestoreScrollPositionsFor: function()
@@ -961,6 +976,7 @@ WebInspector.TimelineRecordGraphRow.prototype = {
 
 WebInspector.TimelinePanel.FormattedRecord = function(record, parentRecord, panel, scriptDetails)
 {
+    this._panel = panel;
     var recordTypes = WebInspector.TimelineAgent.RecordType;
     var style = panel._recordStyles[record.type];
     this.parent = parentRecord;
@@ -1051,7 +1067,7 @@ WebInspector.TimelinePanel.FormattedRecord.prototype = {
 
     _generatePopupContent: function(calculator, categories)
     {
-        var contentHelper = new WebInspector.TimelinePanel.PopupContentHelper(this.title);
+        var contentHelper = new WebInspector.TimelinePanel.PopupContentHelper(this.title, this._panel);
 
         if (this._children && this._children.length) {
             contentHelper._appendTextRow(WebInspector.UIString("Self Time"), Number.secondsToString(this._selfTime + 0.0001));
@@ -1136,26 +1152,26 @@ WebInspector.TimelinePanel.FormattedRecord.prototype = {
             case WebInspector.TimelineAgent.RecordType.GCEvent:
                 return WebInspector.UIString("%s collected", Number.bytesToString(this.data.usedHeapSizeDelta));
             case WebInspector.TimelineAgent.RecordType.TimerFire:
-                return this.scriptName ? this._linkifyLocation(this.scriptName, this.scriptLine, 0) : this.data.timerId;
+                return this.scriptName ? this._panel._linkifyLocation(this.scriptName, this.scriptLine, 0) : this.data.timerId;
             case WebInspector.TimelineAgent.RecordType.FunctionCall:
-                return this.scriptName ? this._linkifyLocation(this.scriptName, this.scriptLine, 0) : null;
+                return this.scriptName ? this._panel._linkifyLocation(this.scriptName, this.scriptLine, 0) : null;
             case WebInspector.TimelineAgent.RecordType.FireAnimationFrameEvent:
-                return this.scriptName ? this._linkifyLocation(this.scriptName, this.scriptLine, 0) : this.data.id;
+                return this.scriptName ? this._panel._linkifyLocation(this.scriptName, this.scriptLine, 0) : this.data.id;
             case WebInspector.TimelineAgent.RecordType.EventDispatch:
                 return this.data ? this.data.type : null;
             case WebInspector.TimelineAgent.RecordType.Paint:
                 return this.data.width + "\u2009\u00d7\u2009" + this.data.height;
             case WebInspector.TimelineAgent.RecordType.TimerInstall:
             case WebInspector.TimelineAgent.RecordType.TimerRemove:
-                return this.stackTrace ? this._linkifyCallFrame(this.stackTrace[0]) : this.data.timerId;
+                return this.stackTrace ? this._panel._linkifyCallFrame(this.stackTrace[0]) : this.data.timerId;
             case WebInspector.TimelineAgent.RecordType.RegisterAnimationFrameCallback:
             case WebInspector.TimelineAgent.RecordType.CancelAnimationFrameCallback:
-                return this.stackTrace ? this._linkifyCallFrame(this.stackTrace[0]) : this.data.id;
+                return this.stackTrace ? this._panel._linkifyCallFrame(this.stackTrace[0]) : this.data.id;
             case WebInspector.TimelineAgent.RecordType.ParseHTML:
             case WebInspector.TimelineAgent.RecordType.RecalculateStyles:
-                return this.stackTrace ? this._linkifyCallFrame(this.stackTrace[0]) : null;
+                return this.stackTrace ? this._panel._linkifyCallFrame(this.stackTrace[0]) : null;
             case WebInspector.TimelineAgent.RecordType.EvaluateScript:
-                return this.url ? this._linkifyLocation(this.url, this.data.lineNumber, 0) : null;
+                return this.url ? this._panel._linkifyLocation(this.url, this.data.lineNumber, 0) : null;
             case WebInspector.TimelineAgent.RecordType.XHRReadyStateChange:
             case WebInspector.TimelineAgent.RecordType.XHRLoad:
             case WebInspector.TimelineAgent.RecordType.ScheduleResourceRequest:
@@ -1171,19 +1187,6 @@ WebInspector.TimelinePanel.FormattedRecord.prototype = {
         }
     },
 
-    _linkifyLocation: function(url, lineNumber, columnNumber)
-    {
-        // FIXME(62725): stack trace line/column numbers are one-based.
-        lineNumber = lineNumber ? lineNumber - 1 : lineNumber;
-        columnNumber = columnNumber ? columnNumber - 1 : 0;
-        return WebInspector.debuggerPresentationModel.linkifyLocation(url, lineNumber, columnNumber, "timeline-details");
-    },
-
-    _linkifyCallFrame: function(callFrame)
-    {
-        return this._linkifyLocation(callFrame.url, callFrame.lineNumber, callFrame.columnNumber);
-    },
-
     _calculateAggregatedStats: function(categories)
     {
         this._aggregatedStats = {};
@@ -1204,8 +1207,9 @@ WebInspector.TimelinePanel.FormattedRecord.prototype = {
     }
 }
 
-WebInspector.TimelinePanel.PopupContentHelper = function(title)
+WebInspector.TimelinePanel.PopupContentHelper = function(title, panel)
 {
+    this._panel = panel;
     this._contentTable = document.createElement("table");;
     var titleCell = this._createCell(WebInspector.UIString("%s - Details", title), "timeline-details-title");
     titleCell.colSpan = 2;
@@ -1251,7 +1255,7 @@ WebInspector.TimelinePanel.PopupContentHelper.prototype = {
 
     _appendLinkRow: function(title, scriptName, scriptLine)
     {
-        var link = WebInspector.TimelinePanel.FormattedRecord.prototype._linkifyLocation(scriptName, scriptLine, 0, "timeline-details");
+        var link = this._panel._linkifyLocation(scriptName, scriptLine, 0, "timeline-details");
         this._appendElementRow(title, link);
     },
 
@@ -1266,7 +1270,7 @@ WebInspector.TimelinePanel.PopupContentHelper.prototype = {
             row.appendChild(this._createCell(stackFrame.functionName ? stackFrame.functionName : WebInspector.UIString("(anonymous function)"), "timeline-function-name"));
             row.appendChild(this._createCell(" @ "));
             var linkCell = document.createElement("td");
-            var urlElement = WebInspector.TimelinePanel.FormattedRecord.prototype._linkifyCallFrame(stackFrame);
+            var urlElement = this._panel._linkifyCallFrame(stackFrame);
             linkCell.appendChild(urlElement);
             row.appendChild(linkCell);
             framesTable.appendChild(row);
index 52ac934243b0a9fb5b4201d73d71f668abd246c4..f2c2113f3a37bf79ae0d508c7c26380f3f1ea798 100644 (file)
@@ -36,6 +36,7 @@
     <file>DataGrid.js</file>
     <file>DebuggerModel.js</file>
     <file>DebuggerPresentationModel.js</file>
+    <file>Linkifier.js</file>
     <file>DOMAgent.js</file>
     <file>DOMBreakpointsSidebarPane.js</file>
     <file>DOMStorage.js</file>
index 85b17aace1c976fcb136dc8361afd3a614eadefa..29a44a859732526ce0638e523e74efd481544180 100644 (file)
@@ -158,6 +158,7 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     <script type="text/javascript" src="DetailedHeapshotView.js"></script>
     <script type="text/javascript" src="DebuggerModel.js"></script>
     <script type="text/javascript" src="DebuggerPresentationModel.js"></script>
+    <script type="text/javascript" src="Linkifier.js"></script>
     <script type="text/javascript" src="BreakpointManager.js"></script>
     <script type="text/javascript" src="UISourceCode.js"></script>
     <script type="text/javascript" src="ContentProviders.js"></script>
index 9b8fbe5f333d4484665cea126a33a21216642a9c..e2760637ca6d567ce216b62cc5e71f09d8eee060 100644 (file)
@@ -509,6 +509,9 @@ WebInspector.doLoadedDone = function()
     this.console.addEventListener(WebInspector.ConsoleModel.Events.MessageAdded, this._updateErrorAndWarningCounts, this);
     this.console.addEventListener(WebInspector.ConsoleModel.Events.RepeatCountUpdated, this._updateErrorAndWarningCounts, this);
 
+    this.debuggerModel = new WebInspector.DebuggerModel();
+    this.debuggerPresentationModel = new WebInspector.DebuggerPresentationModel();
+
     this.drawer = new WebInspector.Drawer();
     this.consoleView = new WebInspector.ConsoleView();
 
@@ -521,8 +524,6 @@ WebInspector.doLoadedDone = function()
     InspectorBackend.registerInspectorDispatcher(this);
 
     this.cssModel = new WebInspector.CSSStyleModel();
-    this.debuggerModel = new WebInspector.DebuggerModel();
-    this.debuggerPresentationModel = new WebInspector.DebuggerPresentationModel();
 
     this.searchController = new WebInspector.SearchController();