Web Inspector: Timelines: flatten the overview to show all records, one per line
authordrousso@apple.com <drousso@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 21 Mar 2019 18:03:02 +0000 (18:03 +0000)
committerdrousso@apple.com <drousso@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 21 Mar 2019 18:03:02 +0000 (18:03 +0000)
https://bugs.webkit.org/show_bug.cgi?id=191901
<rdar://problem/46423618>

Reviewed by Timothy Hatcher.

* UserInterface/Views/OverviewTimelineView.js:
(WI.OverviewTimelineView):
(WI.OverviewTimelineView.prototype.closed):
(WI.OverviewTimelineView.prototype.get navigationItems): Added.
(WI.OverviewTimelineView.prototype.reset):
(WI.OverviewTimelineView.prototype.layout):
(WI.OverviewTimelineView.prototype.get _relevantTimelines): Added.
(WI.OverviewTimelineView.prototype.get _shouldGroupBySourceCode): Added.
(WI.OverviewTimelineView.prototype._loadExistingRecords): Added.
(WI.OverviewTimelineView.prototype._insertDataGridNode):
(WI.OverviewTimelineView.prototype._addResourceToDataGridIfNeeded):
(WI.OverviewTimelineView.prototype._addSourceCodeTimeline):
(WI.OverviewTimelineView.prototype._processPendingRepresentedObjects):
(WI.OverviewTimelineView.prototype._handleGroupBySourceCodeSettingChanged): Added.
(WI.OverviewTimelineView.prototype._handleGroupBySourceCodeNavigationItemCheckedDidChange): Added.
(WI.OverviewTimelineView.prototype._handleTimelineRecordAdded): Added.
(WI.OverviewTimelineView.prototype._sourceCodeTimelineAdded):
(WI.OverviewTimelineView.prototype._networkTimelineRecordAdded): Deleted.
Listen for new records on all timelines. Add each record as a new line. Since each timeline
has different data to display, only show the "name" and "graph" for all records.

* UserInterface/Views/TimelineRecordingContentView.js:
(WI.TimelineRecordingContentView):
(WI.TimelineRecordingContentView.prototype._currentContentViewDidChange):
(WI.TimelineRecordingContentView.prototype._updateImportedView): Deleted.
When viewing the overview of an imported recording, show the non-grouped overview.

* UserInterface/Models/TimelineRecording.js:
(WI.TimelineRecording.prototype.addRecord):
(WI.TimelineRecording.prototype._keyForRecord):
Drive-by: show Media timeline events under the owner frame's resource when grouped.
* UserInterface/Views/TimelineRecordBar.css:
(.timeline-record-bar.timeline-record-type-script.garbage-collected > .segment, .timeline-record-bar.timeline-record-type-heap-allocations > .segment): Added.
(.timeline-record-bar.timeline-record-type-script.garbage-collected > .segment): Deleted.

* UserInterface/Base/Setting.js:
Add setting for controlling the Timeline overview grouping.

* UserInterface/Main.html:
* UserInterface/Views/SourceCodeTimelineTreeElement.js: Removed.
* UserInterface/Views/TimelineRecordingImportedView.js: Removed.
* UserInterface/Views/TimelineRecordingImportedView.css: Removed.
Remove unused files.

* Localizations/en.lproj/localizedStrings.js:

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

17 files changed:
Source/WebInspectorUI/ChangeLog
Source/WebInspectorUI/Localizations/en.lproj/localizedStrings.js
Source/WebInspectorUI/UserInterface/Base/Setting.js
Source/WebInspectorUI/UserInterface/Main.html
Source/WebInspectorUI/UserInterface/Models/TimelineRecording.js
Source/WebInspectorUI/UserInterface/Views/LayoutTimelineDataGridNode.js
Source/WebInspectorUI/UserInterface/Views/LayoutTimelineView.js
Source/WebInspectorUI/UserInterface/Views/MediaTimelineDataGridNode.js
Source/WebInspectorUI/UserInterface/Views/NetworkTimelineView.js
Source/WebInspectorUI/UserInterface/Views/OverviewTimelineView.js
Source/WebInspectorUI/UserInterface/Views/ResourceTimelineDataGridNode.js
Source/WebInspectorUI/UserInterface/Views/ScriptTimelineDataGridNode.js
Source/WebInspectorUI/UserInterface/Views/SourceCodeTimelineTreeElement.js [deleted file]
Source/WebInspectorUI/UserInterface/Views/TimelineRecordBar.css
Source/WebInspectorUI/UserInterface/Views/TimelineRecordingContentView.js
Source/WebInspectorUI/UserInterface/Views/TimelineRecordingImportedView.css [deleted file]
Source/WebInspectorUI/UserInterface/Views/TimelineRecordingImportedView.js [deleted file]

index 3e9a09b..4709cb1 100644 (file)
@@ -1,5 +1,60 @@
 2019-03-21  Devin Rousso  <drousso@apple.com>
 
+        Web Inspector: Timelines: flatten the overview to show all records, one per line
+        https://bugs.webkit.org/show_bug.cgi?id=191901
+        <rdar://problem/46423618>
+
+        Reviewed by Timothy Hatcher.
+
+        * UserInterface/Views/OverviewTimelineView.js:
+        (WI.OverviewTimelineView):
+        (WI.OverviewTimelineView.prototype.closed):
+        (WI.OverviewTimelineView.prototype.get navigationItems): Added.
+        (WI.OverviewTimelineView.prototype.reset):
+        (WI.OverviewTimelineView.prototype.layout):
+        (WI.OverviewTimelineView.prototype.get _relevantTimelines): Added.
+        (WI.OverviewTimelineView.prototype.get _shouldGroupBySourceCode): Added.
+        (WI.OverviewTimelineView.prototype._loadExistingRecords): Added.
+        (WI.OverviewTimelineView.prototype._insertDataGridNode):
+        (WI.OverviewTimelineView.prototype._addResourceToDataGridIfNeeded):
+        (WI.OverviewTimelineView.prototype._addSourceCodeTimeline):
+        (WI.OverviewTimelineView.prototype._processPendingRepresentedObjects):
+        (WI.OverviewTimelineView.prototype._handleGroupBySourceCodeSettingChanged): Added.
+        (WI.OverviewTimelineView.prototype._handleGroupBySourceCodeNavigationItemCheckedDidChange): Added.
+        (WI.OverviewTimelineView.prototype._handleTimelineRecordAdded): Added.
+        (WI.OverviewTimelineView.prototype._sourceCodeTimelineAdded):
+        (WI.OverviewTimelineView.prototype._networkTimelineRecordAdded): Deleted.
+        Listen for new records on all timelines. Add each record as a new line. Since each timeline
+        has different data to display, only show the "name" and "graph" for all records.
+
+        * UserInterface/Views/TimelineRecordingContentView.js:
+        (WI.TimelineRecordingContentView):
+        (WI.TimelineRecordingContentView.prototype._currentContentViewDidChange):
+        (WI.TimelineRecordingContentView.prototype._updateImportedView): Deleted.
+        When viewing the overview of an imported recording, show the non-grouped overview.
+
+        * UserInterface/Models/TimelineRecording.js:
+        (WI.TimelineRecording.prototype.addRecord):
+        (WI.TimelineRecording.prototype._keyForRecord):
+        Drive-by: show Media timeline events under the owner frame's resource when grouped.
+
+        * UserInterface/Views/TimelineRecordBar.css:
+        (.timeline-record-bar.timeline-record-type-script.garbage-collected > .segment, .timeline-record-bar.timeline-record-type-heap-allocations > .segment): Added.
+        (.timeline-record-bar.timeline-record-type-script.garbage-collected > .segment): Deleted.
+
+        * UserInterface/Base/Setting.js:
+        Add setting for controlling the Timeline overview grouping.
+
+        * UserInterface/Main.html:
+        * UserInterface/Views/SourceCodeTimelineTreeElement.js: Removed.
+        * UserInterface/Views/TimelineRecordingImportedView.js: Removed.
+        * UserInterface/Views/TimelineRecordingImportedView.css: Removed.
+        Remove unused files.
+
+        * Localizations/en.lproj/localizedStrings.js:
+
+2019-03-21  Devin Rousso  <drousso@apple.com>
+
         Web Inspector: Sources: the name of the file should not be used as a folder
         https://bugs.webkit.org/show_bug.cgi?id=196064
         <rdar://problem/49097710>
index 4e9b0ce..6e153b1 100644 (file)
@@ -514,6 +514,7 @@ localizedStrings["Global Lexical Environment"] = "Global Lexical Environment";
 localizedStrings["Global Variables"] = "Global Variables";
 localizedStrings["Grammar"] = "Grammar";
 localizedStrings["Group"] = "Group";
+localizedStrings["Group By Resource"] = "Group By Resource";
 localizedStrings["Group Media Requests"] = "Group Media Requests";
 localizedStrings["Group by Event"] = "Group by Event";
 localizedStrings["Group by Path"] = "Group by Path";
@@ -563,7 +564,6 @@ localizedStrings["Import"] = "Import";
 localizedStrings["Imported"] = "Imported";
 localizedStrings["Imported - %s"] = "Imported - %s";
 localizedStrings["Imported Recordings"] = "Imported Recordings";
-localizedStrings["Imported Timeline Recording"] = "Imported Timeline Recording";
 localizedStrings["Imported \u2014 %s"] = "Imported \u2014 %s";
 localizedStrings["Incomplete"] = "Incomplete";
 localizedStrings["Indent width:"] = "Indent width:";
index 21e65e6..b3c6e57 100644 (file)
@@ -156,6 +156,7 @@ WI.settings = {
     showWhitespaceCharacters: new WI.Setting("show-whitespace-characters", false),
     tabSize: new WI.Setting("tab-size", 4),
     timelinesAutoStop: new WI.Setting("timelines-auto-stop", true),
+    timelineOverviewGroupBySourceCode: new WI.Setting("timeline-overview-group-by-source-code", true),
     zoomFactor: new WI.Setting("zoom-factor", 1),
 
     // Experimental
index 41db7de..4f7a2d0 100644 (file)
     <link rel="stylesheet" href="Views/TimelineRecordBar.css">
     <link rel="stylesheet" href="Views/TimelineRecordFrame.css">
     <link rel="stylesheet" href="Views/TimelineRecordingContentView.css">
-    <link rel="stylesheet" href="Views/TimelineRecordingImportedView.css">
     <link rel="stylesheet" href="Views/TimelineRuler.css">
     <link rel="stylesheet" href="Views/TimelineTabContentView.css">
     <link rel="stylesheet" href="Views/TimelineView.css">
     <script src="Views/SoftContextMenu.js"></script>
     <script src="Views/SourceCodeTextEditor.js"></script>
     <script src="Views/SourceCodeTimelineTimelineDataGridNode.js"></script>
-    <script src="Views/SourceCodeTimelineTreeElement.js"></script>
     <script src="Views/SourcesNavigationSidebarPanel.js"></script>
     <script src="Views/SourceMapResourceTreeElement.js"></script>
     <script src="Views/SpanningDataGridNode.js"></script>
     <script src="Views/TimelineRecordFrame.js"></script>
     <script src="Views/TimelineRecordingContentView.js"></script>
     <script src="Views/TimelineRecordingProgressView.js"></script>
-    <script src="Views/TimelineRecordingImportedView.js"></script>
     <script src="Views/TimelineRuler.js"></script>
     <script src="Views/TitleView.js"></script>
     <script src="Views/ToggleButtonNavigationItem.js"></script>
index d33a12d..d09fa66 100644 (file)
@@ -238,12 +238,12 @@ WI.TimelineRecording = class TimelineRecording extends WI.Object
         }
     }
 
-    sourceCodeTimelinesForSourceCode(sourceCode)
+    get sourceCodeTimelines()
     {
-        var timelines = this._sourceCodeTimelinesMap.get(sourceCode);
-        if (!timelines)
-            return [];
-        return [...timelines.values()];
+        let timelines = [];
+        for (let timelinesForSourceCode of this._sourceCodeTimelinesMap.values())
+            timelines = timelines.concat(Array.from(timelinesForSourceCode.values()));
+        return timelines;
     }
 
     timelineForInstrument(instrument)
@@ -308,16 +308,22 @@ WI.TimelineRecording = class TimelineRecording extends WI.Object
             || record.type === WI.TimelineRecord.Type.RenderingFrame
             || record.type === WI.TimelineRecord.Type.CPU
             || record.type === WI.TimelineRecord.Type.Memory
-            || record.type === WI.TimelineRecord.Type.HeapAllocations
-            || record.type === WI.TimelineRecord.Type.Media)
+            || record.type === WI.TimelineRecord.Type.HeapAllocations)
             return;
 
         if (!WI.TimelineRecording.sourceCodeTimelinesSupported())
             return;
 
         // Add the record to the source code timelines.
-        var activeMainResource = WI.networkManager.mainFrame.provisionalMainResource || WI.networkManager.mainFrame.mainResource;
-        var sourceCode = record.sourceCodeLocation ? record.sourceCodeLocation.sourceCode : activeMainResource;
+        let sourceCode = null;
+        if (record.sourceCodeLocation)
+            sourceCode = record.sourceCodeLocation.sourceCode;
+        else if (record.type === WI.TimelineRecord.Type.Media) {
+            if (record.domNode && record.domNode.frame)
+                sourceCode = record.domNode.frame.mainResource;
+        }
+        if (!sourceCode)
+            sourceCode = WI.networkManager.mainFrame.provisionalMainResource || WI.networkManager.mainFrame.mainResource;
 
         var sourceCodeTimelines = this._sourceCodeTimelinesMap.get(sourceCode);
         if (!sourceCodeTimelines) {
@@ -452,10 +458,18 @@ WI.TimelineRecording = class TimelineRecording extends WI.Object
     _keyForRecord(record)
     {
         var key = record.type;
-        if (record instanceof WI.ScriptTimelineRecord || record instanceof WI.LayoutTimelineRecord || record instanceof WI.MediaTimelineRecord)
+        if (record instanceof WI.ScriptTimelineRecord || record instanceof WI.LayoutTimelineRecord)
             key += ":" + record.eventType;
         if (record instanceof WI.ScriptTimelineRecord && record.eventType === WI.ScriptTimelineRecord.EventType.EventDispatched)
             key += ":" + record.details;
+        if (record instanceof WI.MediaTimelineRecord) {
+            key += ":" + record.eventType;
+            if (record.eventType === WI.MediaTimelineRecord.EventType.DOMEvent) {
+                if (record.domEvent && record.domEvent.eventName)
+                    key += ":" + record.domEvent.eventName;
+            } else if (record.eventType === WI.MediaTimelineRecord.EventType.LowPower)
+                key += ":" + (record.isLowPower ? "enabled" : "disabled");
+        }
         if (record.sourceCodeLocation)
             key += ":" + record.sourceCodeLocation.lineNumber + ":" + record.sourceCodeLocation.columnNumber;
         return key;
index 2f824be..5e78d4a 100644 (file)
@@ -47,7 +47,7 @@ WI.LayoutTimelineDataGridNode = class LayoutTimelineDataGridNode extends WI.Time
         this._cachedData.area = this.record.width * this.record.height;
         this._cachedData.startTime = this.record.startTime - (this.graphDataSource ? this.graphDataSource.zeroTime : 0);
         this._cachedData.totalTime = this.record.duration;
-        this._cachedData.location = this.record.initiatorCallFrame;
+        this._cachedData.initiator = this.record.initiatorCallFrame;
         return this._cachedData;
     }
 
@@ -73,6 +73,9 @@ WI.LayoutTimelineDataGridNode = class LayoutTimelineDataGridNode extends WI.Time
 
         case "totalTime":
             return isNaN(value) ? emDash : Number.secondsToString(value, higherResolution);
+
+        case "source": // Timeline Overview
+            return super.createCellContent("initiator", cell);
         }
 
         return super.createCellContent(columnIdentifier, cell);
index 0e45c39..393a969 100644 (file)
@@ -31,7 +31,7 @@ WI.LayoutTimelineView = class LayoutTimelineView extends WI.TimelineView
 
         console.assert(timeline.type === WI.TimelineRecord.Type.Layout, timeline);
 
-        let columns = {type: {}, name: {}, location: {}, area: {}, width: {}, height: {}, startTime: {}, totalTime: {}};
+        let columns = {type: {}, name: {}, initiator: {}, area: {}, width: {}, height: {}, startTime: {}, totalTime: {}};
 
         columns.name.title = WI.UIString("Type");
         columns.name.width = "15%";
@@ -52,8 +52,8 @@ WI.LayoutTimelineView = class LayoutTimelineView extends WI.TimelineView
 
         this._scopeBar = columns.type.scopeBar;
 
-        columns.location.title = WI.UIString("Initiator");
-        columns.location.width = "25%";
+        columns.initiator.title = WI.UIString("Initiator");
+        columns.initiator.width = "25%";
 
         columns.area.title = WI.UIString("Area");
         columns.area.width = "8%";
index 6cf4e6b..6dceac1 100644 (file)
@@ -58,6 +58,7 @@ WI.MediaTimelineDataGridNode = class MediaTimelineDataGridNode extends WI.Timeli
             cell.classList.add(...this.iconClassNames());
             return value;
 
+        case "source": // Timeline Overview
         case "element":
             return value ? WI.linkifyNodeReference(value) : emDash;
 
index 1222de5..08c9fb2 100644 (file)
@@ -31,7 +31,7 @@ WI.NetworkTimelineView = class NetworkTimelineView extends WI.TimelineView
 
         console.assert(timeline.type === WI.TimelineRecord.Type.Network);
 
-        let columns = {name: {}, domain: {}, type: {}, method: {}, scheme: {}, statusCode: {}, cached: {}, protocol: {}, priority: {}, remoteAddress: {}, connectionIdentifier: {}, size: {}, transferSize: {}, requestSent: {}, latency: {}, duration: {}, graph: {}};
+        let columns = {name: {}, domain: {}, type: {}, method: {}, scheme: {}, statusCode: {}, cached: {}, protocol: {}, priority: {}, remoteAddress: {}, connectionIdentifier: {}, size: {}, transferSize: {}, requestSent: {}, latency: {}, duration: {}, initiator: {}, graph: {}};
 
         columns.name.title = WI.UIString("Name");
         columns.name.icon = true;
index a5b5f26..0d73ae4 100644 (file)
@@ -27,24 +27,45 @@ WI.OverviewTimelineView = class OverviewTimelineView extends WI.TimelineView
 {
     constructor(recording, extraArguments)
     {
+        console.assert(recording instanceof WI.TimelineRecording);
+
         super(recording, extraArguments);
 
         this._recording = recording;
+        this._pendingRepresentedObjects = [];
+        this._resourceDataGridNodeMap = new Map;
+
+        if (WI.TimelineRecording.sourceCodeTimelinesSupported() && !this._recording.imported) {
+            WI.settings.timelineOverviewGroupBySourceCode.addEventListener(WI.Setting.Event.Changed, this._handleGroupBySourceCodeSettingChanged, this);
 
-        let columns = {name: {}, graph: {}};
+            this._groupBySourceCodeNavigationItem = new WI.CheckboxNavigationItem("overview-timeline-group-by-resource", WI.UIString("Group By Resource"), WI.settings.timelineOverviewGroupBySourceCode.value);
+            this._groupBySourceCodeNavigationItem.addEventListener(WI.CheckboxNavigationItem.Event.CheckedDidChange, this._handleGroupBySourceCodeNavigationItemCheckedDidChange, this);
+        }
+
+        let columns = {name: {}, source: {}, graph: {}};
 
         columns.name.title = WI.UIString("Name");
         columns.name.width = "20%";
         columns.name.icon = true;
-        columns.name.disclosure = true;
+        columns.name.locked = true;
+        if (this._shouldGroupBySourceCode)
+            columns.name.disclosure = true;
+
+        columns.source.title = WI.UIString("Source");
+        columns.source.width = "10%";
+        columns.source.icon = true;
+        columns.source.locked = true;
+        if (this._shouldGroupBySourceCode)
+            columns.source.hidden = true;
 
         this._timelineRuler = new WI.TimelineRuler;
         this._timelineRuler.allowsClippedLabels = true;
 
-        columns.graph.width = "80%";
+        columns.graph.width = "70%";
         columns.graph.headerView = this._timelineRuler;
+        columns.graph.locked = true;
 
-        this._dataGrid = new WI.DataGrid(columns);
+        this._dataGrid = new WI.TimelineDataGrid(columns);
 
         this.setupDataGrid(this._dataGrid);
 
@@ -52,19 +73,16 @@ WI.OverviewTimelineView = class OverviewTimelineView extends WI.TimelineView
         this._timelineRuler.addMarker(this._currentTimeMarker);
 
         this.element.classList.add("overview");
-        if (!this._recording.imported)
-            this.addSubview(this._dataGrid);
+        this.addSubview(this._dataGrid);
 
-        this._networkTimeline = recording.timelines.get(WI.TimelineRecord.Type.Network);
-        if (this._networkTimeline)
-            this._networkTimeline.addEventListener(WI.Timeline.Event.RecordAdded, this._networkTimelineRecordAdded, this);
+        for (let timeline of this._relevantTimelines)
+            timeline.addEventListener(WI.Timeline.Event.RecordAdded, this._handleTimelineRecordAdded, this);
 
         recording.addEventListener(WI.TimelineRecording.Event.SourceCodeTimelineAdded, this._sourceCodeTimelineAdded, this);
         recording.addEventListener(WI.TimelineRecording.Event.MarkerAdded, this._markerAdded, this);
         recording.addEventListener(WI.TimelineRecording.Event.Reset, this._recordingReset, this);
 
-        this._pendingRepresentedObjects = [];
-        this._resourceDataGridNodeMap = new Map;
+        this._loadExistingRecords();
     }
 
     // Public
@@ -88,11 +106,20 @@ WI.OverviewTimelineView = class OverviewTimelineView extends WI.TimelineView
 
     closed()
     {
-        if (this._networkTimeline)
-            this._networkTimeline.removeEventListener(null, null, this);
+        for (let timeline of this._recording.timelines.values())
+            timeline.removeEventListener(null, null, this);
+
         this._recording.removeEventListener(null, null, this);
     }
 
+    get navigationItems()
+    {
+        let navigationItems = [];
+        if (this._groupBySourceCodeNavigationItem)
+            navigationItems.push(this._groupBySourceCodeNavigationItem);
+        return navigationItems;
+    }
+
     get selectionPathComponents()
     {
         let dataGridNode = this._dataGrid.selectedNode;
@@ -119,9 +146,10 @@ WI.OverviewTimelineView = class OverviewTimelineView extends WI.TimelineView
     {
         super.reset();
 
-        this._dataGrid.removeChildren();
+        this._dataGrid.reset();
 
         this._pendingRepresentedObjects = [];
+        this._resourceDataGridNodeMap.clear();
     }
 
     // Protected
@@ -141,9 +169,6 @@ WI.OverviewTimelineView = class OverviewTimelineView extends WI.TimelineView
 
     layout()
     {
-        if (this._recording.imported)
-            return;
-
         let oldZeroTime = this._timelineRuler.zeroTime;
         let oldStartTime = this._timelineRuler.startTime;
         let oldEndTime = this._timelineRuler.endTime;
@@ -169,6 +194,48 @@ WI.OverviewTimelineView = class OverviewTimelineView extends WI.TimelineView
 
     // Private
 
+    get _relevantTimelines()
+    {
+        let timelines = [];
+        for (let [type, timeline] of this._recording.timelines) {
+            if (type === WI.TimelineRecord.Type.RenderingFrame || type === WI.TimelineRecord.Type.CPU || type === WI.TimelineRecord.Type.Memory)
+                continue;
+
+            timelines.push(timeline);
+        }
+        return timelines;
+    }
+
+    get _shouldGroupBySourceCode()
+    {
+        // Always show imported records as non-grouped.
+        if (this._recording.imported)
+            return false;
+
+        return WI.TimelineRecording.sourceCodeTimelinesSupported() && WI.settings.timelineOverviewGroupBySourceCode.value;
+    }
+
+    _loadExistingRecords()
+    {
+        this._pendingRepresentedObjects = [];
+        this._resourceDataGridNodeMap.clear();
+
+        this._dataGrid.removeChildren();
+
+        if (this._shouldGroupBySourceCode) {
+            let networkTimeline = this._recording.timelines.get(WI.TimelineRecord.Type.Network);
+            if (networkTimeline)
+                this._pendingRepresentedObjects = this._pendingRepresentedObjects.concat(networkTimeline.records.map((record) => record.resource));
+
+            this._pendingRepresentedObjects = this._pendingRepresentedObjects.concat(this._recording.sourceCodeTimelines);
+        } else {
+            for (let timeline of this._relevantTimelines)
+                this._pendingRepresentedObjects = this._pendingRepresentedObjects.concat(timeline.records);
+        }
+
+        this.needsLayout();
+    }
+
     _compareDataGridNodesByStartTime(a, b)
     {
         function getStartTime(dataGridNode)
@@ -195,10 +262,10 @@ WI.OverviewTimelineView = class OverviewTimelineView extends WI.TimelineView
         console.assert(dataGridNode);
         console.assert(!dataGridNode.parent);
 
-        if (parentDataGridNode)
-            parentDataGridNode.insertChild(dataGridNode, insertionIndexForObjectInListSortedByFunction(dataGridNode, parentDataGridNode.children, this._compareDataGridNodesByStartTime.bind(this)));
-        else
-            this._dataGrid.appendChild(dataGridNode);
+        if (!parentDataGridNode)
+            parentDataGridNode = this._dataGrid;
+
+        parentDataGridNode.insertChild(dataGridNode, insertionIndexForObjectInListSortedByFunction(dataGridNode, parentDataGridNode.children, this._compareDataGridNodesByStartTime));
     }
 
     _addResourceToDataGridIfNeeded(resource)
@@ -209,57 +276,64 @@ WI.OverviewTimelineView = class OverviewTimelineView extends WI.TimelineView
 
         // FIXME: replace with this._dataGrid.findDataGridNode(resource) once <https://webkit.org/b/155305> is fixed.
         let dataGridNode = this._resourceDataGridNodeMap.get(resource);
-        if (dataGridNode)
-            return dataGridNode;
-
-        let parentFrame = resource.parentFrame;
-        if (!parentFrame)
-            return null;
+        if (!dataGridNode) {
+            let resourceTimelineRecord = this._networkTimeline ? this._networkTimeline.recordForResource(resource) : null;
+            if (!resourceTimelineRecord)
+                resourceTimelineRecord = new WI.ResourceTimelineRecord(resource);
+
+            dataGridNode = new WI.ResourceTimelineDataGridNode(resourceTimelineRecord, {
+                graphDataSource: this,
+                includesGraph: true,
+            });
+            this._resourceDataGridNodeMap.set(resource, dataGridNode);
+        }
 
-        let resourceTimelineRecord = this._networkTimeline ? this._networkTimeline.recordForResource(resource) : null;
-        if (!resourceTimelineRecord)
-            resourceTimelineRecord = new WI.ResourceTimelineRecord(resource);
+        if (!dataGridNode.parent) {
+            let parentFrame = resource.parentFrame;
+            if (!parentFrame)
+                return null;
 
-        let resourceDataGridNode = new WI.ResourceTimelineDataGridNode(resourceTimelineRecord, {
-            graphDataSource: this,
-            includesGraph: true,
-        });
-        this._resourceDataGridNodeMap.set(resource, resourceDataGridNode);
+            let expandedByDefault = false;
+            if (parentFrame.mainResource === resource || parentFrame.provisionalMainResource === resource) {
+                parentFrame = parentFrame.parentFrame;
+                expandedByDefault = !parentFrame; // Main frame expands by default.
+            }
 
-        let expandedByDefault = false;
-        if (parentFrame.mainResource === resource || parentFrame.provisionalMainResource === resource) {
-            parentFrame = parentFrame.parentFrame;
-            expandedByDefault = !parentFrame; // Main frame expands by default.
-        }
+            if (expandedByDefault)
+                dataGridNode.expand();
 
-        if (expandedByDefault)
-            resourceDataGridNode.expand();
+            let parentDataGridNode = null;
+            if (parentFrame) {
+                // Find the parent main resource, adding it if needed, to append this resource as a child.
+                let parentResource = parentFrame.provisionalMainResource || parentFrame.mainResource;
 
-        let parentDataGridNode = null;
-        if (parentFrame) {
-            // Find the parent main resource, adding it if needed, to append this resource as a child.
-            let parentResource = parentFrame.provisionalMainResource || parentFrame.mainResource;
+                parentDataGridNode = this._addResourceToDataGridIfNeeded(parentResource);
+                console.assert(parentDataGridNode);
+                if (!parentDataGridNode)
+                    return null;
+            }
 
-            parentDataGridNode = this._addResourceToDataGridIfNeeded(parentResource);
-            console.assert(parentDataGridNode);
-            if (!parentDataGridNode)
-                return null;
+            this._insertDataGridNode(dataGridNode, parentDataGridNode);
         }
 
-        this._insertDataGridNode(resourceDataGridNode, parentDataGridNode);
-
-        return resourceDataGridNode;
+        dataGridNode.refresh();
+        return dataGridNode;
     }
 
     _addSourceCodeTimeline(sourceCodeTimeline)
     {
-        let parentDataGridNode = sourceCodeTimeline.sourceCodeLocation ? this._addResourceToDataGridIfNeeded(sourceCodeTimeline.sourceCode) : null;
-        let sourceCodeTimelineDataGridNode = new WI.SourceCodeTimelineTimelineDataGridNode(sourceCodeTimeline, {
-            graphDataSource: this,
-        });
-        this._resourceDataGridNodeMap.set(sourceCodeTimeline, sourceCodeTimelineDataGridNode);
+        let dataGridNode = this._resourceDataGridNodeMap.get(sourceCodeTimeline);
+        if (!dataGridNode) {
+            dataGridNode = new WI.SourceCodeTimelineTimelineDataGridNode(sourceCodeTimeline, {
+                graphDataSource: this,
+            });
+            this._resourceDataGridNodeMap.set(sourceCodeTimeline, dataGridNode);
+        }
 
-        this._insertDataGridNode(sourceCodeTimelineDataGridNode, parentDataGridNode);
+        if (!dataGridNode.parent) {
+            let parentDataGridNode = sourceCodeTimeline.sourceCodeLocation ? this._addResourceToDataGridIfNeeded(sourceCodeTimeline.sourceCode) : null;
+            this._insertDataGridNode(dataGridNode, parentDataGridNode);
+        }
     }
 
     _processPendingRepresentedObjects()
@@ -268,32 +342,84 @@ WI.OverviewTimelineView = class OverviewTimelineView extends WI.TimelineView
             return;
 
         for (var representedObject of this._pendingRepresentedObjects) {
-            if (representedObject instanceof WI.Resource)
-                this._addResourceToDataGridIfNeeded(representedObject);
-            else if (representedObject instanceof WI.SourceCodeTimeline)
-                this._addSourceCodeTimeline(representedObject);
-            else
-                console.error("Unknown represented object");
+            if (this._shouldGroupBySourceCode) {
+                if (representedObject instanceof WI.Resource)
+                    this._addResourceToDataGridIfNeeded(representedObject);
+                else if (representedObject instanceof WI.SourceCodeTimeline)
+                    this._addSourceCodeTimeline(representedObject);
+                else
+                    console.error("Unknown represented object", representedObject);
+            } else {
+                const options = {
+                    graphDataSource: this,
+                    shouldShowPopover: true,
+                };
+
+                let dataGridNode = null;
+                if (representedObject instanceof WI.ResourceTimelineRecord)
+                    dataGridNode = new WI.ResourceTimelineDataGridNode(representedObject, options);
+                else if (representedObject instanceof WI.LayoutTimelineRecord)
+                    dataGridNode = new WI.LayoutTimelineDataGridNode(representedObject, options);
+                else if (representedObject instanceof WI.MediaTimelineRecord)
+                    dataGridNode = new WI.MediaTimelineDataGridNode(representedObject, options);
+                else if (representedObject instanceof WI.ScriptTimelineRecord)
+                    dataGridNode = new WI.ScriptTimelineDataGridNode(representedObject, options);
+                else if (representedObject instanceof WI.HeapAllocationsTimelineRecord)
+                    dataGridNode = new WI.HeapAllocationsTimelineDataGridNode(representedObject, options);
+
+                console.assert(dataGridNode, representedObject);
+                if (!dataGridNode)
+                    continue;
+
+                let comparator = (a, b) => {
+                    return a.record.startTime - b.record.startTime;
+                };
+
+                this._dataGrid.insertChild(dataGridNode, insertionIndexForObjectInListSortedByFunction(dataGridNode, this._dataGrid.children, comparator));
+            }
         }
 
         this._pendingRepresentedObjects = [];
     }
 
-    _networkTimelineRecordAdded(event)
+    _handleGroupBySourceCodeSettingChanged(event)
     {
-        var resourceTimelineRecord = event.data.record;
-        console.assert(resourceTimelineRecord instanceof WI.ResourceTimelineRecord);
+        let groupBySourceCode = this._shouldGroupBySourceCode;
+        this._dataGrid.disclosureColumnIdentifier = groupBySourceCode ? "name" : undefined;
+        this._dataGrid.setColumnVisible("source", !groupBySourceCode);
+        if (this._groupBySourceCodeNavigationItem)
+            this._groupBySourceCodeNavigationItem.checked = groupBySourceCode;
 
-        this._pendingRepresentedObjects.push(resourceTimelineRecord.resource);
+        this._loadExistingRecords();
+    }
 
-        this.needsLayout();
+    _handleGroupBySourceCodeNavigationItemCheckedDidChange(event)
+    {
+        WI.settings.timelineOverviewGroupBySourceCode.value = !WI.settings.timelineOverviewGroupBySourceCode.value;
+    }
 
-        // We don't expect to have any source code timelines yet. Those should be added with _sourceCodeTimelineAdded.
-        console.assert(!this._recording.sourceCodeTimelinesForSourceCode(resourceTimelineRecord.resource).length);
+    _handleTimelineRecordAdded(event)
+    {
+        let {record} = event.data;
+
+        if (this._shouldGroupBySourceCode) {
+            if (event.target.type !== WI.TimelineRecord.Type.Network)
+                return;
+
+            console.assert(record instanceof WI.ResourceTimelineRecord);
+
+            this._pendingRepresentedObjects.push(record.resource);
+        } else
+            this._pendingRepresentedObjects.push(record);
+
+        this.needsLayout();
     }
 
     _sourceCodeTimelineAdded(event)
     {
+        if (!this._shouldGroupBySourceCode)
+            return;
+
         var sourceCodeTimeline = event.data.sourceCodeTimeline;
         console.assert(sourceCodeTimeline);
         if (!sourceCodeTimeline)
index 0f0004f..c431da8 100644 (file)
@@ -74,6 +74,7 @@ WI.ResourceTimelineDataGridNode = class ResourceTimelineDataGridNode extends WI.
         this._cachedData.priority = this.resource.priority;
         this._cachedData.remoteAddress = this.resource.remoteAddress;
         this._cachedData.connectionIdentifier = this.resource.connectionIdentifier;
+        this._cachedData.initiator = this.resource.initiatorSourceCodeLocation;
         return this._cachedData;
     }
 
@@ -139,6 +140,9 @@ WI.ResourceTimelineDataGridNode = class ResourceTimelineDataGridNode extends WI.
             if (title)
                 cell.title = title;
             return title || emDash;
+
+        case "source": // Timeline Overview
+            return super.createCellContent("initiator", cell);
         }
 
         return super.createCellContent(columnIdentifier, cell);
index 96896f4..c8da946 100644 (file)
@@ -69,7 +69,6 @@ WI.ScriptTimelineDataGridNode = class ScriptTimelineDataGridNode extends WI.Time
         this._cachedData.averageTime = duration;
         this._cachedData.callCount = this.record.callCountOrSamples;
         this._cachedData.location = this.record.initiatorCallFrame || this.record.sourceCodeLocation;
-
         return this._cachedData;
     }
 
@@ -86,8 +85,8 @@ WI.ScriptTimelineDataGridNode = class ScriptTimelineDataGridNode extends WI.Time
                 this._subtitle = WI.UIString("%s interval").format(timeoutString);
             else
                 this._subtitle = WI.UIString("%s delay").format(timeoutString);
-        } else if (this._record.eventType === WI.ScriptTimelineRecord.EventType.EventDispatched) {
-            if (this._record.extraDetails && this._record.extraDetails.defaultPrevented)
+        } else if (this.record.eventType === WI.ScriptTimelineRecord.EventType.EventDispatched) {
+            if (this.record.extraDetails && this.record.extraDetails.defaultPrevented)
                 this._subtitle = WI.UIString("default prevented");
         }
 
@@ -119,6 +118,9 @@ WI.ScriptTimelineDataGridNode = class ScriptTimelineDataGridNode extends WI.Time
         case "height":
         case "area":
             return zeroWidthSpace;
+
+        case "source": // Timeline Overview
+            return super.createCellContent("location", cell);
         }
 
         return super.createCellContent(columnIdentifier, cell);
diff --git a/Source/WebInspectorUI/UserInterface/Views/SourceCodeTimelineTreeElement.js b/Source/WebInspectorUI/UserInterface/Views/SourceCodeTimelineTreeElement.js
deleted file mode 100644 (file)
index f7bb5fb..0000000
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright (C) 2013, 2015 Apple Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
- * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
- * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
- * THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-WI.SourceCodeTimelineTreeElement = class SourceCodeTimelineTreeElement extends WI.TimelineRecordTreeElement
-{
-    constructor(sourceCodeTimeline, subtitleNameStyle, includeDetailsInMainTitle)
-    {
-        console.assert(sourceCodeTimeline);
-
-        subtitleNameStyle = subtitleNameStyle || WI.SourceCodeLocation.NameStyle.None;
-
-        super(sourceCodeTimeline.records[0], subtitleNameStyle, includeDetailsInMainTitle, sourceCodeTimeline.sourceCodeLocation, sourceCodeTimeline);
-
-        this._sourceCodeTimeline = sourceCodeTimeline;
-    }
-
-    // Public
-
-    get record()
-    {
-        return undefined;
-    }
-
-    get sourceCodeTimeline()
-    {
-        return this._sourceCodeTimeline;
-    }
-};
index a5d60e5..8bcd525 100644 (file)
@@ -122,7 +122,8 @@ body[dir=rtl] :focus .selected .timeline-record-bar.has-inactive-segment > .segm
     border-color: hsl(273, 33%, 58%);
 }
 
-.timeline-record-bar.timeline-record-type-script.garbage-collected > .segment {
+.timeline-record-bar.timeline-record-type-script.garbage-collected > .segment,
+.timeline-record-bar.timeline-record-type-heap-allocations > .segment {
     background-color: hsl(23, 69%, 73%);
     border-color: hsl(11, 54%, 62%);    
 }
index 9ceb7f6..bd31043 100644 (file)
@@ -87,9 +87,6 @@ WI.TimelineRecordingContentView = class TimelineRecordingContentView extends WI.
         this._progressView = new WI.TimelineRecordingProgressView;
         this._timelineContentBrowser.addSubview(this._progressView);
 
-        this._importedView = new WI.TimelineRecordingImportedView;
-        this._timelineContentBrowser.addSubview(this._importedView);
-
         this._timelineViewMap = new Map;
         this._pathComponentMap = new Map;
 
@@ -316,7 +313,6 @@ WI.TimelineRecordingContentView = class TimelineRecordingContentView extends WI.
         this._timelineOverview.viewMode = newViewMode;
         this._updateTimelineOverviewHeight();
         this._updateProgressView();
-        this._updateImportedView();
         this._updateFilterBar();
 
         if (timelineView) {
@@ -942,11 +938,6 @@ WI.TimelineRecordingContentView = class TimelineRecordingContentView extends WI.
         this._progressView.visible = isCapturing && this.currentTimelineView && !this.currentTimelineView.showsLiveRecordingData;
     }
 
-    _updateImportedView()
-    {
-        this._importedView.visible = this._recording.imported && this.currentTimelineView && this.currentTimelineView.showsImportedRecordingMessage;
-    }
-
     _updateFilterBar()
     {
         this._filterBarNavigationItem.hidden = !this.currentTimelineView || !this.currentTimelineView.showsFilterBar;
diff --git a/Source/WebInspectorUI/UserInterface/Views/TimelineRecordingImportedView.css b/Source/WebInspectorUI/UserInterface/Views/TimelineRecordingImportedView.css
deleted file mode 100644 (file)
index e5142b9..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Copyright (C) 2019 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.
- */
-
-.content-view.timeline-recording > .content-browser .recording-imported .message-text-view > .message {
-    font-size: var(--message-text-view-large-font-size);
-    font-weight: 600;
-    letter-spacing: 0.02em;
-}
diff --git a/Source/WebInspectorUI/UserInterface/Views/TimelineRecordingImportedView.js b/Source/WebInspectorUI/UserInterface/Views/TimelineRecordingImportedView.js
deleted file mode 100644 (file)
index 52717ef..0000000
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright (C) 2019 Apple Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
- * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
- * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
- * THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-WI.TimelineRecordingImportedView = class TimelineRecordingImportedView extends WI.View
-{
-    constructor()
-    {
-        super();
-
-        this.element.classList.add("recording-imported");
-        this.element.appendChild(WI.createMessageTextView(WI.UIString("Imported Timeline Recording")));
-    }
-
-    // Public
-
-    get visible()
-    {
-        return this._visible;
-    }
-
-    set visible(x)
-    {
-        if (this._visible === x)
-            return;
-
-        // FIXME: remove once <https://webkit.org/b/150741> is fixed.
-        this._visible = x;
-        this.element.classList.toggle("hidden", !this._visible);
-    }
-};