Web Inspector: refactor WI.TimelineDataGridNode and its subclasses to unify the API...
authordrousso@apple.com <drousso@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 20 Mar 2019 17:43:05 +0000 (17:43 +0000)
committerdrousso@apple.com <drousso@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 20 Mar 2019 17:43:05 +0000 (17:43 +0000)
https://bugs.webkit.org/show_bug.cgi?id=195959
<rdar://problem/49028896>

Reviewed by Timothy Hatcher.

* UserInterface/Views/TimelineDataGridNode.js:
(WI.TimelineDataGridNode.prototype.get records):
(WI.TimelineDataGridNode.prototype.get data):
(WI.TimelineDataGridNode.prototype.refresh):

* UserInterface/Views/HeapAllocationsTimelineDataGridNode.js:
(WI.HeapAllocationsTimelineDataGridNode):
(WI.HeapAllocationsTimelineDataGridNode.prototype.get heapSnapshot): Added.
(WI.HeapAllocationsTimelineDataGridNode.prototype.get data):
(WI.HeapAllocationsTimelineDataGridNode.prototype.createCellContent):
(WI.HeapAllocationsTimelineDataGridNode.prototype.createCells):
(WI.HeapAllocationsTimelineDataGridNode.prototype._handleHeapSnapshotCollectedNodes):
(WI.HeapAllocationsTimelineDataGridNode.prototype._handleHeapSnapshotInvalidated):
(WI.HeapAllocationsTimelineDataGridNode.prototype.get record): Deleted.
(WI.HeapAllocationsTimelineDataGridNode.prototype.updateTimestamp): Deleted.
(WI.HeapAllocationsTimelineDataGridNode.prototype._heapSnapshotCollectedNodes): Deleted.
(WI.HeapAllocationsTimelineDataGridNode.prototype._heapSnapshotInvalidated): Deleted.

* UserInterface/Views/LayoutTimelineDataGridNode.js:
(WI.LayoutTimelineDataGridNode):
(WI.LayoutTimelineDataGridNode.prototype.get data):
(WI.LayoutTimelineDataGridNode.prototype.createCellContent):
(WI.LayoutTimelineDataGridNode.prototype.get records): Deleted.

* UserInterface/Views/MediaTimelineDataGridNode.js:
(WI.MediaTimelineDataGridNode):
(WI.MediaTimelineDataGridNode.prototype.get records): Deleted.

* UserInterface/Views/ProfileNodeDataGridNode.js:
(WI.ProfileNodeDataGridNode):
(WI.ProfileNodeDataGridNode.prototype.get profileNode):
(WI.ProfileNodeDataGridNode.prototype.get data):
(WI.ProfileNodeDataGridNode.prototype.createCellContent):
(WI.ProfileNodeDataGridNode.prototype._populate):
(WI.ProfileNodeDataGridNode.prototype.get records): Deleted.
(WI.ProfileNodeDataGridNode.prototype.get baseStartTime): Deleted.
(WI.ProfileNodeDataGridNode.prototype.get rangeStartTime): Deleted.
(WI.ProfileNodeDataGridNode.prototype.get rangeEndTime): Deleted.
(WI.ProfileNodeDataGridNode.prototype.updateRangeTimes): Deleted.
(WI.ProfileNodeDataGridNode.prototype.refresh): Deleted.

* UserInterface/Views/RenderingFrameTimelineDataGridNode.js:
(WI.RenderingFrameTimelineDataGridNode):
(WI.RenderingFrameTimelineDataGridNode.prototype.get data):
(WI.RenderingFrameTimelineDataGridNode.prototype.createCellContent):
(WI.RenderingFrameTimelineDataGridNode.prototype.get records): Deleted.

* UserInterface/Views/ResourceTimelineDataGridNode.js:
(WI.ResourceTimelineDataGridNode):
(WI.ResourceTimelineDataGridNode.prototype.get resource):
(WI.ResourceTimelineDataGridNode.prototype.get data):
(WI.ResourceTimelineDataGridNode.prototype.createCellContent):
(WI.ResourceTimelineDataGridNode.prototype.appendContextMenuItems):
(WI.ResourceTimelineDataGridNode.prototype.filterableDataForColumn):
(WI.ResourceTimelineDataGridNode.prototype._createNameCellDocumentFragment):
(WI.ResourceTimelineDataGridNode.prototype._cachedCellContent):
(WI.ResourceTimelineDataGridNode.prototype._timelineRecordUpdated):
(WI.ResourceTimelineDataGridNode.prototype._dataGridNodeGoToArrowClicked):
(WI.ResourceTimelineDataGridNode.prototype._updateStatus):
(WI.ResourceTimelineDataGridNode.prototype._mouseoverRecordBar.else.let.graphDataSource.get startTime):
(WI.ResourceTimelineDataGridNode.prototype._mouseoverRecordBar.else.let.graphDataSource.get currentTime):
(WI.ResourceTimelineDataGridNode.prototype._mouseoverRecordBar.else.let.graphDataSource.get endTime):
(WI.ResourceTimelineDataGridNode.prototype._mouseoverRecordBar.else.let.graphDataSource.get _extraTimePadding):
(WI.ResourceTimelineDataGridNode.prototype._mouseoverRecordBar):
(WI.ResourceTimelineDataGridNode.prototype.get records): Deleted.

* UserInterface/Views/ResourceTimingPopoverDataGridNode.js:
(WI.ResourceTimingPopoverDataGridNode):
(WI.ResourceTimingPopoverDataGridNode.prototype.get records): Deleted.

* UserInterface/Views/ScriptTimelineDataGridNode.js:
(WI.ScriptTimelineDataGridNode.prototype.get data):
(WI.ScriptTimelineDataGridNode.prototype.get subtitle):
(WI.ScriptTimelineDataGridNode.prototype.createCellContent):
(WI.ScriptTimelineDataGridNode.prototype.get records): Deleted.
(WI.ScriptTimelineDataGridNode.prototype.get baseStartTime): Deleted.
(WI.ScriptTimelineDataGridNode.prototype.get rangeStartTime): Deleted.
(WI.ScriptTimelineDataGridNode.prototype.get rangeEndTime): Deleted.
(WI.ScriptTimelineDataGridNode.prototype.updateRangeTimes): Deleted.

* UserInterface/Views/SourceCodeTimelineTimelineDataGridNode.js:
(WI.SourceCodeTimelineTimelineDataGridNode.prototype.get data):

* UserInterface/Views/HeapAllocationsTimelineView.js:
(WI.HeapAllocationsTimelineView):
(WI.HeapAllocationsTimelineView.prototype.layout):
(WI.HeapAllocationsTimelineView.prototype.reset):
* UserInterface/Views/LayoutTimelineView.js:
(WI.LayoutTimelineView.prototype._processPendingRecords):
* UserInterface/Views/MediaTimelineView.js:
(WI.MediaTimelineView.prototype._processPendingRecords):
* UserInterface/Views/NetworkTimelineView.js:
(WI.NetworkTimelineView.prototype._processPendingRecords):
* UserInterface/Views/OverviewTimelineView.js:
(WI.OverviewTimelineView.prototype._addResourceToDataGridIfNeeded):
(WI.OverviewTimelineView.prototype._addSourceCodeTimeline):
* UserInterface/Views/RenderingFrameTimelineView.js:
(WI.RenderingFrameTimelineView.prototype._processPendingRecords):
* UserInterface/Views/ScriptDetailsTimelineView.js:
(WI.ScriptDetailsTimelineView.prototype.layout):
(WI.ScriptDetailsTimelineView.prototype._processPendingRecords):
Update Timeline `WI.DataGrid` views to use the new constructor format.

* UserInterface/Views/ResourceTimelineDataGridNode.css:
(.resource-timing-popover-content .data-grid td.graph-column):
Drive-by: add extra padding before/after resource timing bars shown when hovering.
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@243213 268f45cc-cd09-0410-ab3c-d52691b4dbfc

19 files changed:
Source/WebInspectorUI/ChangeLog
Source/WebInspectorUI/UserInterface/Views/HeapAllocationsTimelineDataGridNode.js
Source/WebInspectorUI/UserInterface/Views/HeapAllocationsTimelineView.js
Source/WebInspectorUI/UserInterface/Views/LayoutTimelineDataGridNode.js
Source/WebInspectorUI/UserInterface/Views/LayoutTimelineView.js
Source/WebInspectorUI/UserInterface/Views/MediaTimelineDataGridNode.js
Source/WebInspectorUI/UserInterface/Views/MediaTimelineView.js
Source/WebInspectorUI/UserInterface/Views/NetworkTimelineView.js
Source/WebInspectorUI/UserInterface/Views/OverviewTimelineView.js
Source/WebInspectorUI/UserInterface/Views/ProfileNodeDataGridNode.js
Source/WebInspectorUI/UserInterface/Views/RenderingFrameTimelineDataGridNode.js
Source/WebInspectorUI/UserInterface/Views/RenderingFrameTimelineView.js
Source/WebInspectorUI/UserInterface/Views/ResourceTimelineDataGridNode.css
Source/WebInspectorUI/UserInterface/Views/ResourceTimelineDataGridNode.js
Source/WebInspectorUI/UserInterface/Views/ResourceTimingPopoverDataGridNode.js
Source/WebInspectorUI/UserInterface/Views/ScriptDetailsTimelineView.js
Source/WebInspectorUI/UserInterface/Views/ScriptTimelineDataGridNode.js
Source/WebInspectorUI/UserInterface/Views/SourceCodeTimelineTimelineDataGridNode.js
Source/WebInspectorUI/UserInterface/Views/TimelineDataGridNode.js

index 8d58393..16da470 100644 (file)
@@ -1,5 +1,120 @@
 2019-03-20  Devin Rousso  <drousso@apple.com>
 
+        Web Inspector: refactor WI.TimelineDataGridNode and its subclasses to unify the API surface
+        https://bugs.webkit.org/show_bug.cgi?id=195959
+        <rdar://problem/49028896>
+
+        Reviewed by Timothy Hatcher.
+
+        * UserInterface/Views/TimelineDataGridNode.js:
+        (WI.TimelineDataGridNode.prototype.get records):
+        (WI.TimelineDataGridNode.prototype.get data):
+        (WI.TimelineDataGridNode.prototype.refresh):
+
+        * UserInterface/Views/HeapAllocationsTimelineDataGridNode.js:
+        (WI.HeapAllocationsTimelineDataGridNode):
+        (WI.HeapAllocationsTimelineDataGridNode.prototype.get heapSnapshot): Added.
+        (WI.HeapAllocationsTimelineDataGridNode.prototype.get data):
+        (WI.HeapAllocationsTimelineDataGridNode.prototype.createCellContent):
+        (WI.HeapAllocationsTimelineDataGridNode.prototype.createCells):
+        (WI.HeapAllocationsTimelineDataGridNode.prototype._handleHeapSnapshotCollectedNodes):
+        (WI.HeapAllocationsTimelineDataGridNode.prototype._handleHeapSnapshotInvalidated):
+        (WI.HeapAllocationsTimelineDataGridNode.prototype.get record): Deleted.
+        (WI.HeapAllocationsTimelineDataGridNode.prototype.updateTimestamp): Deleted.
+        (WI.HeapAllocationsTimelineDataGridNode.prototype._heapSnapshotCollectedNodes): Deleted.
+        (WI.HeapAllocationsTimelineDataGridNode.prototype._heapSnapshotInvalidated): Deleted.
+
+        * UserInterface/Views/LayoutTimelineDataGridNode.js:
+        (WI.LayoutTimelineDataGridNode):
+        (WI.LayoutTimelineDataGridNode.prototype.get data):
+        (WI.LayoutTimelineDataGridNode.prototype.createCellContent):
+        (WI.LayoutTimelineDataGridNode.prototype.get records): Deleted.
+
+        * UserInterface/Views/MediaTimelineDataGridNode.js:
+        (WI.MediaTimelineDataGridNode):
+        (WI.MediaTimelineDataGridNode.prototype.get records): Deleted.
+
+        * UserInterface/Views/ProfileNodeDataGridNode.js:
+        (WI.ProfileNodeDataGridNode):
+        (WI.ProfileNodeDataGridNode.prototype.get profileNode):
+        (WI.ProfileNodeDataGridNode.prototype.get data):
+        (WI.ProfileNodeDataGridNode.prototype.createCellContent):
+        (WI.ProfileNodeDataGridNode.prototype._populate):
+        (WI.ProfileNodeDataGridNode.prototype.get records): Deleted.
+        (WI.ProfileNodeDataGridNode.prototype.get baseStartTime): Deleted.
+        (WI.ProfileNodeDataGridNode.prototype.get rangeStartTime): Deleted.
+        (WI.ProfileNodeDataGridNode.prototype.get rangeEndTime): Deleted.
+        (WI.ProfileNodeDataGridNode.prototype.updateRangeTimes): Deleted.
+        (WI.ProfileNodeDataGridNode.prototype.refresh): Deleted.
+
+        * UserInterface/Views/RenderingFrameTimelineDataGridNode.js:
+        (WI.RenderingFrameTimelineDataGridNode):
+        (WI.RenderingFrameTimelineDataGridNode.prototype.get data):
+        (WI.RenderingFrameTimelineDataGridNode.prototype.createCellContent):
+        (WI.RenderingFrameTimelineDataGridNode.prototype.get records): Deleted.
+
+        * UserInterface/Views/ResourceTimelineDataGridNode.js:
+        (WI.ResourceTimelineDataGridNode):
+        (WI.ResourceTimelineDataGridNode.prototype.get resource):
+        (WI.ResourceTimelineDataGridNode.prototype.get data):
+        (WI.ResourceTimelineDataGridNode.prototype.createCellContent):
+        (WI.ResourceTimelineDataGridNode.prototype.appendContextMenuItems):
+        (WI.ResourceTimelineDataGridNode.prototype.filterableDataForColumn):
+        (WI.ResourceTimelineDataGridNode.prototype._createNameCellDocumentFragment):
+        (WI.ResourceTimelineDataGridNode.prototype._cachedCellContent):
+        (WI.ResourceTimelineDataGridNode.prototype._timelineRecordUpdated):
+        (WI.ResourceTimelineDataGridNode.prototype._dataGridNodeGoToArrowClicked):
+        (WI.ResourceTimelineDataGridNode.prototype._updateStatus):
+        (WI.ResourceTimelineDataGridNode.prototype._mouseoverRecordBar.else.let.graphDataSource.get startTime):
+        (WI.ResourceTimelineDataGridNode.prototype._mouseoverRecordBar.else.let.graphDataSource.get currentTime):
+        (WI.ResourceTimelineDataGridNode.prototype._mouseoverRecordBar.else.let.graphDataSource.get endTime):
+        (WI.ResourceTimelineDataGridNode.prototype._mouseoverRecordBar.else.let.graphDataSource.get _extraTimePadding):
+        (WI.ResourceTimelineDataGridNode.prototype._mouseoverRecordBar):
+        (WI.ResourceTimelineDataGridNode.prototype.get records): Deleted.
+
+        * UserInterface/Views/ResourceTimingPopoverDataGridNode.js:
+        (WI.ResourceTimingPopoverDataGridNode):
+        (WI.ResourceTimingPopoverDataGridNode.prototype.get records): Deleted.
+
+        * UserInterface/Views/ScriptTimelineDataGridNode.js:
+        (WI.ScriptTimelineDataGridNode.prototype.get data):
+        (WI.ScriptTimelineDataGridNode.prototype.get subtitle):
+        (WI.ScriptTimelineDataGridNode.prototype.createCellContent):
+        (WI.ScriptTimelineDataGridNode.prototype.get records): Deleted.
+        (WI.ScriptTimelineDataGridNode.prototype.get baseStartTime): Deleted.
+        (WI.ScriptTimelineDataGridNode.prototype.get rangeStartTime): Deleted.
+        (WI.ScriptTimelineDataGridNode.prototype.get rangeEndTime): Deleted.
+        (WI.ScriptTimelineDataGridNode.prototype.updateRangeTimes): Deleted.
+
+        * UserInterface/Views/SourceCodeTimelineTimelineDataGridNode.js:
+        (WI.SourceCodeTimelineTimelineDataGridNode.prototype.get data):
+
+        * UserInterface/Views/HeapAllocationsTimelineView.js:
+        (WI.HeapAllocationsTimelineView):
+        (WI.HeapAllocationsTimelineView.prototype.layout):
+        (WI.HeapAllocationsTimelineView.prototype.reset):
+        * UserInterface/Views/LayoutTimelineView.js:
+        (WI.LayoutTimelineView.prototype._processPendingRecords):
+        * UserInterface/Views/MediaTimelineView.js:
+        (WI.MediaTimelineView.prototype._processPendingRecords):
+        * UserInterface/Views/NetworkTimelineView.js:
+        (WI.NetworkTimelineView.prototype._processPendingRecords):
+        * UserInterface/Views/OverviewTimelineView.js:
+        (WI.OverviewTimelineView.prototype._addResourceToDataGridIfNeeded):
+        (WI.OverviewTimelineView.prototype._addSourceCodeTimeline):
+        * UserInterface/Views/RenderingFrameTimelineView.js:
+        (WI.RenderingFrameTimelineView.prototype._processPendingRecords):
+        * UserInterface/Views/ScriptDetailsTimelineView.js:
+        (WI.ScriptDetailsTimelineView.prototype.layout):
+        (WI.ScriptDetailsTimelineView.prototype._processPendingRecords):
+        Update Timeline `WI.DataGrid` views to use the new constructor format.
+
+        * UserInterface/Views/ResourceTimelineDataGridNode.css:
+        (.resource-timing-popover-content .data-grid td.graph-column):
+        Drive-by: add extra padding before/after resource timing bars shown when hovering.
+
+2019-03-20  Devin Rousso  <drousso@apple.com>
+
         Web Inspector: changes to CSS resources only take affect once editing stops
         https://bugs.webkit.org/show_bug.cgi?id=195774
         <rdar://problem/48905413>
index 393f448..ecf1798 100644 (file)
 
 WI.HeapAllocationsTimelineDataGridNode = class HeapAllocationsTimelineDataGridNode extends WI.TimelineDataGridNode
 {
-    constructor(heapAllocationsTimelineRecord, zeroTime, heapAllocationsView)
+    constructor(record, options = {})
     {
-        super(false, null);
+        console.assert(record instanceof WI.HeapAllocationsTimelineRecord);
 
-        this._record = heapAllocationsTimelineRecord;
-        this._heapAllocationsView = heapAllocationsView;
+        super([record], options);
 
-        this._data = {
-            name: this.displayName(),
-            timestamp: zeroTime ? this._record.timestamp - zeroTime : NaN,
-            size: this._record.heapSnapshot.totalSize,
-            liveSize: this._record.heapSnapshot.liveSize,
-        };
+        this._heapAllocationsView = options.heapAllocationsView;
 
-        this._record.heapSnapshot.addEventListener(WI.HeapSnapshotProxy.Event.CollectedNodes, this._heapSnapshotCollectedNodes, this);
-        this._record.heapSnapshot.addEventListener(WI.HeapSnapshotProxy.Event.Invalidated, this._heapSnapshotInvalidated, this);
+        this.heapSnapshot.addEventListener(WI.HeapSnapshotProxy.Event.CollectedNodes, this._handleHeapSnapshotCollectedNodes, this);
+        this.heapSnapshot.addEventListener(WI.HeapSnapshotProxy.Event.Invalidated, this._handleHeapSnapshotInvalidated, this);
     }
 
     // Public
 
-    get record() { return this._record; }
-    get data() { return this._data; }
+    get heapSnapshot()
+    {
+        return this.record.heapSnapshot;
+    }
+
+    get data()
+    {
+        if (this._cachedData)
+            return this._cachedData;
+
+        this._cachedData = super.data;
+        this._cachedData.name = this.displayName();
+        this._cachedData.timestamp = this.record.timestamp - (this.graphDataSource ? this.graphDataSource.zeroTime : 0);
+        this._cachedData.size = this.heapSnapshot.totalSize;
+        this._cachedData.liveSize = this.heapSnapshot.liveSize;
+        return this._cachedData;
+    }
 
     createCellContent(columnIdentifier, cell)
     {
+        const higherResolution = true;
+
+        let value = this.data[columnIdentifier];
+
         switch (columnIdentifier) {
         case "name":
             cell.classList.add(...this.iconClassNames());
 
             var fragment = document.createDocumentFragment();
             var titleElement = fragment.appendChild(document.createElement("span"));
-            titleElement.textContent = this._data.name;
-            if (!this._record.heapSnapshot.invalid) {
+            titleElement.textContent = value;
+
+            if (this._heapAllocationsView && !this.heapSnapshot.invalid) {
                 var goToButton = fragment.appendChild(WI.createGoToArrowButton());
                 goToButton.addEventListener("click", (event) => {
-                    this._heapAllocationsView.showHeapSnapshotTimelineRecord(this._record);
+                    this._heapAllocationsView.showHeapSnapshotTimelineRecord(this.record);
                 });
             }
+
             return fragment;
 
-        case "timestamp":
-            return isNaN(this._data.timestamp) ? emDash : Number.secondsToString(this._data.timestamp, true);
+        case "timestamp": {
+            return isNaN(value) ? emDash : Number.secondsToString(value, higherResolution);
+        }
 
         case "size":
-            return Number.bytesToString(this._data.size);
-
         case "liveSize":
-            return Number.bytesToString(this._data.liveSize);
+            return Number.bytesToString(value, higherResolution);
         }
 
         return super.createCellContent(columnIdentifier, cell);
@@ -88,42 +102,25 @@ WI.HeapAllocationsTimelineDataGridNode = class HeapAllocationsTimelineDataGridNo
         this.element.classList.remove("baseline");
     }
 
-    updateTimestamp(zeroTime)
-    {
-        console.assert(isNaN(this._data.timestamp));
-        this._data.timestamp = this._record.timestamp - zeroTime;
-        this.needsRefresh();
-    }
-
     // Protected
 
     createCells()
     {
         super.createCells();
 
-        if (this._record.heapSnapshot.invalid)
+        if (this.heapSnapshot.invalid)
             this.element.classList.add("invalid");
     }
 
     // Private
 
-    _heapSnapshotCollectedNodes()
+    _handleHeapSnapshotCollectedNodes()
     {
-        let oldSize = this._data.liveSize;
-        let newSize = this._record.heapSnapshot.liveSize;
-
-        console.assert(newSize <= oldSize);
-        if (oldSize === newSize)
-            return;
-
-        this._data.liveSize = newSize;
         this.needsRefresh();
     }
 
-    _heapSnapshotInvalidated()
+    _handleHeapSnapshotInvalidated()
     {
-        this._data.liveSize = 0;
-
         this.needsRefresh();
     }
 };
index 4c96245..e025ebe 100644 (file)
@@ -101,7 +101,6 @@ WI.HeapAllocationsTimelineView = class HeapAllocationsTimelineView extends WI.Ti
         WI.ContentView.addEventListener(WI.ContentView.Event.SelectionPathComponentsDidChange, this._contentViewSelectionPathComponentDidChange, this);
 
         this._pendingRecords = [];
-        this._pendingZeroTimeDataGridNodes = [];
 
         timeline.addEventListener(WI.Timeline.Event.RecordAdded, this._heapAllocationsTimelineRecordAdded, this);
 
@@ -263,19 +262,12 @@ WI.HeapAllocationsTimelineView = class HeapAllocationsTimelineView extends WI.Ti
 
     layout()
     {
-        if (this._pendingZeroTimeDataGridNodes.length && this.zeroTime) {
-            for (let dataGridNode of this._pendingZeroTimeDataGridNodes)
-                dataGridNode.updateTimestamp(this.zeroTime);
-            this._pendingZeroTimeDataGridNodes = [];
-            this._dataGrid._sort();
-        }
-
-        if (this._pendingRecords.length) {
+        if (this._pendingRecords.length && this.zeroTime) {
             for (let heapAllocationsTimelineRecord of this._pendingRecords) {
-                let dataGridNode = new WI.HeapAllocationsTimelineDataGridNode(heapAllocationsTimelineRecord, this.zeroTime, this);
-                this._dataGrid.addRowInSortOrder(dataGridNode);
-                if (!this.zeroTime)
-                    this._pendingZeroTimeDataGridNodes.push(dataGridNode);
+                this._dataGrid.addRowInSortOrder(new WI.HeapAllocationsTimelineDataGridNode(heapAllocationsTimelineRecord, {
+                    graphDataSource: this,
+                    heapAllocationsView: this,
+                }));
             }
 
             this._pendingRecords = [];
@@ -291,7 +283,6 @@ WI.HeapAllocationsTimelineView = class HeapAllocationsTimelineView extends WI.Ti
 
         this.showHeapSnapshotList();
         this._pendingRecords = [];
-        this._pendingZeroTimeDataGridNodes = [];
         this._updateCompareHeapSnapshotButton();
     }
 
index 725da09..2f824be 100644 (file)
 
 WI.LayoutTimelineDataGridNode = class LayoutTimelineDataGridNode extends WI.TimelineDataGridNode
 {
-    constructor(layoutTimelineRecord, baseStartTime)
+    constructor(record, options = {})
     {
-        super(false, null);
+        console.assert(record instanceof WI.LayoutTimelineRecord);
 
-        this._record = layoutTimelineRecord;
-        this._baseStartTime = baseStartTime || 0;
+        super([record], options);
     }
 
     // Public
 
-    get records()
-    {
-        return [this._record];
-    }
-
     get data()
     {
-        if (!this._cachedData) {
-            this._cachedData = {
-                type: this._record.eventType,
-                name: this.displayName(),
-                width: this._record.width,
-                height: this._record.height,
-                area: this._record.width * this._record.height,
-                startTime: this._record.startTime,
-                totalTime: this._record.duration,
-                location: this._record.initiatorCallFrame,
-            };
-        }
+        if (this._cachedData)
+            return this._cachedData;
 
+        this._cachedData = super.data;
+        this._cachedData.type = this.record.eventType;
+        this._cachedData.name = this.displayName();
+        this._cachedData.width = this.record.width;
+        this._cachedData.height = this.record.height;
+        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;
         return this._cachedData;
     }
 
     createCellContent(columnIdentifier, cell)
     {
         var value = this.data[columnIdentifier];
+        const higherResolution = true;
 
         switch (columnIdentifier) {
         case "name":
@@ -75,10 +69,10 @@ WI.LayoutTimelineDataGridNode = class LayoutTimelineDataGridNode extends WI.Time
             return isNaN(value) ? emDash : WI.UIString("%dpx\u00B2").format(value);
 
         case "startTime":
-            return isNaN(value) ? emDash : Number.secondsToString(value - this._baseStartTime, true);
+            return isNaN(value) ? emDash : Number.secondsToString(value, higherResolution);
 
         case "totalTime":
-            return isNaN(value) ? emDash : Number.secondsToString(value, true);
+            return isNaN(value) ? emDash : Number.secondsToString(value, higherResolution);
         }
 
         return super.createCellContent(columnIdentifier, cell);
index 8f37613..0e45c39 100644 (file)
@@ -204,7 +204,9 @@ WI.LayoutTimelineView = class LayoutTimelineView extends WI.TimelineView
             return;
 
         for (var layoutTimelineRecord of this._pendingRecords) {
-            let dataGridNode = new WI.LayoutTimelineDataGridNode(layoutTimelineRecord, this.zeroTime);
+            let dataGridNode = new WI.LayoutTimelineDataGridNode(layoutTimelineRecord, {
+                graphDataSource: this,
+            });
 
             this._dataGrid.addRowInSortOrder(dataGridNode);
 
@@ -217,14 +219,24 @@ WI.LayoutTimelineView = class LayoutTimelineView extends WI.TimelineView
                 }
 
                 let childRecord = entry.children[entry.index];
-                console.assert(childRecord.type === WI.TimelineRecord.Type.Layout, childRecord);
 
-                let childDataGridNode = new WI.LayoutTimelineDataGridNode(childRecord, this.zeroTime);
+                const options = {
+                    graphDataSource: this,
+                };
+                let childDataGridNode = null;
+                if (childRecord.type === WI.TimelineRecord.Type.Script)
+                    childDataGridNode = new WI.ScriptTimelineDataGridNode(childRecord, options);
+                else {
+                    console.assert(childRecord.type === WI.TimelineRecord.Type.Layout, childRecord);
+                    childDataGridNode = new WI.LayoutTimelineDataGridNode(childRecord, options);
+                }
+
                 console.assert(entry.parentDataGridNode, "Missing parent node for entry.", entry);
                 this._dataGrid.addRowInSortOrder(childDataGridNode, entry.parentDataGridNode);
 
                 if (childDataGridNode && childRecord.children.length)
                     stack.push({children: childRecord.children, parentDataGridNode: childDataGridNode, index: 0});
+
                 ++entry.index;
             }
         }
index a18f471..6cf4e6b 100644 (file)
 
 WI.MediaTimelineDataGridNode = class MediaTimelineDataGridNode extends WI.TimelineDataGridNode
 {
-    constructor(record, graphDataSource)
+    constructor(record, options = {})
     {
         console.assert(record instanceof WI.MediaTimelineRecord);
 
-        const includesGraph = false;
-        super(includesGraph, graphDataSource);
-
-        this._records = [record];
+        super([record], options);
     }
 
     // Public
 
-    get records() { return this._records; }
-
     get data()
     {
         if (this._cachedData)
index c1648b2..c985a71 100644 (file)
@@ -186,7 +186,9 @@ WI.MediaTimelineView = class MediaTimelineView extends WI.TimelineView
             if (timelineRecord.domEvent && timelineRecord.domEvent.originator)
                 this._dataGrid.setColumnVisible("originator", true);
 
-            this._dataGrid.addRowInSortOrder(new WI.MediaTimelineDataGridNode(timelineRecord, this));
+            this._dataGrid.addRowInSortOrder(new WI.MediaTimelineDataGridNode(timelineRecord, {
+                graphDataSource: this,
+            }));
         }
 
         this._pendingRecords = [];
index 5aeb504..1222de5 100644 (file)
@@ -257,9 +257,11 @@ WI.NetworkTimelineView = class NetworkTimelineView extends WI.TimelineView
             if (dataGridNode)
                 continue;
 
-            const includesGraph = false;
-            const shouldShowPopover = true;
-            dataGridNode = new WI.ResourceTimelineDataGridNode(resourceTimelineRecord, includesGraph, this, shouldShowPopover);
+            dataGridNode = new WI.ResourceTimelineDataGridNode(resourceTimelineRecord, {
+                graphDataSource: this,
+                shouldShowPopover: true,
+            });
+
             this._resourceDataGridNodeMap.set(resourceTimelineRecord.resource, dataGridNode);
 
             this._dataGrid.addRowInSortOrder(dataGridNode);
index e8cefe8..a5b5f26 100644 (file)
@@ -220,9 +220,10 @@ WI.OverviewTimelineView = class OverviewTimelineView extends WI.TimelineView
         if (!resourceTimelineRecord)
             resourceTimelineRecord = new WI.ResourceTimelineRecord(resource);
 
-        const includesGraph = true;
-        const shouldShowPopover = false;
-        let resourceDataGridNode = new WI.ResourceTimelineDataGridNode(resourceTimelineRecord, includesGraph, this, shouldShowPopover);
+        let resourceDataGridNode = new WI.ResourceTimelineDataGridNode(resourceTimelineRecord, {
+            graphDataSource: this,
+            includesGraph: true,
+        });
         this._resourceDataGridNodeMap.set(resource, resourceDataGridNode);
 
         let expandedByDefault = false;
@@ -253,7 +254,9 @@ WI.OverviewTimelineView = class OverviewTimelineView extends WI.TimelineView
     _addSourceCodeTimeline(sourceCodeTimeline)
     {
         let parentDataGridNode = sourceCodeTimeline.sourceCodeLocation ? this._addResourceToDataGridIfNeeded(sourceCodeTimeline.sourceCode) : null;
-        let sourceCodeTimelineDataGridNode = new WI.SourceCodeTimelineTimelineDataGridNode(sourceCodeTimeline, this);
+        let sourceCodeTimelineDataGridNode = new WI.SourceCodeTimelineTimelineDataGridNode(sourceCodeTimeline, {
+            graphDataSource: this,
+        });
         this._resourceDataGridNodeMap.set(sourceCodeTimeline, sourceCodeTimelineDataGridNode);
 
         this._insertDataGridNode(sourceCodeTimelineDataGridNode, parentDataGridNode);
index 01645d1..3d3969c 100644 (file)
 
 WI.ProfileNodeDataGridNode = class ProfileNodeDataGridNode extends WI.TimelineDataGridNode
 {
-    constructor(profileNode, baseStartTime, rangeStartTime, rangeEndTime)
+    constructor(profileNode, options = {})
     {
-        var hasChildren = !!profileNode.childNodes.length;
+        console.assert(profileNode instanceof WI.ProfileNode);
 
-        super(false, null, hasChildren);
+        options.hasChildren = !!profileNode.childNodes.length;
 
-        this._profileNode = profileNode;
-        this._baseStartTime = baseStartTime || 0;
-        this._rangeStartTime = rangeStartTime || 0;
-        this._rangeEndTime = typeof rangeEndTime === "number" ? rangeEndTime : Infinity;
+        super(null, options);
 
-        this._cachedData = null;
+        this._profileNode = profileNode;
 
         this.addEventListener("populate", this._populate, this);
     }
 
     // Public
 
-    get profileNode()
-    {
-        return this._profileNode;
-    }
-
-    get records()
-    {
-        return null;
-    }
-
-    get baseStartTime()
-    {
-        return this._baseStartTime;
-    }
-
-    get rangeStartTime()
-    {
-        return this._rangeStartTime;
-    }
-
-    get rangeEndTime()
-    {
-        return this._rangeEndTime;
-    }
+    get profileNode() { return this._profileNode; }
 
     get data()
     {
-        if (!this._cachedData) {
-            this._cachedData = this._profileNode.computeCallInfoForTimeRange(this._rangeStartTime, this._rangeEndTime);
-            this._cachedData.name = this.displayName();
-            this._cachedData.location = this._profileNode.sourceCodeLocation;
+        if (this._cachedData)
+            return this._cachedData;
+
+        let baseStartTime = 0;
+        let rangeStartTime = 0;
+        let rangeEndTime = Infinity;
+        if (this.graphDataSource) {
+            baseStartTime = this.graphDataSource.zeroTime;
+            rangeStartTime = this.graphDataSource.startTime;
+            rangeEndTime = this.graphDataSource.endTime;
         }
 
-        return this._cachedData;
-    }
-
-    updateRangeTimes(startTime, endTime)
-    {
-        var oldRangeStartTime = this._rangeStartTime;
-        var oldRangeEndTime = this._rangeEndTime;
-
-        if (oldRangeStartTime === startTime && oldRangeEndTime === endTime)
-            return;
-
-        this._rangeStartTime = startTime;
-        this._rangeEndTime = endTime;
+        let callInfo = this._profileNode.computeCallInfoForTimeRange(rangeStartTime, rangeEndTime);
 
-        // We only need a refresh if the new range time changes the visible portion of this record.
-        var profileStart = this._profileNode.startTime;
-        var profileEnd = this._profileNode.endTime;
-        var oldStartBoundary = Number.constrain(oldRangeStartTime, profileStart, profileEnd);
-        var oldEndBoundary = Number.constrain(oldRangeEndTime, profileStart, profileEnd);
-        var newStartBoundary = Number.constrain(startTime, profileStart, profileEnd);
-        var newEndBoundary = Number.constrain(endTime, profileStart, profileEnd);
+        this._cachedData = super.data;
+        for (let key in callInfo)
+            this._cachedData[key] = callInfo[key];
+        this._cachedData.startTime -= baseStartTime;
+        this._cachedData.name = this.displayName();
+        this._cachedData.location = this._profileNode.sourceCodeLocation;
 
-        if (oldStartBoundary !== newStartBoundary || oldEndBoundary !== newEndBoundary)
-            this.needsRefresh();
-    }
-
-    refresh()
-    {
-        this._data = this._profileNode.computeCallInfoForTimeRange(this._rangeStartTime, this._rangeEndTime);
-        this._data.location = this._profileNode.sourceCodeLocation;
-
-        super.refresh();
+        return this._cachedData;
     }
 
     createCellContent(columnIdentifier, cell)
     {
+        const higherResolution = true;
+
         var value = this.data[columnIdentifier];
 
         switch (columnIdentifier) {
@@ -120,12 +80,10 @@ WI.ProfileNodeDataGridNode = class ProfileNodeDataGridNode extends WI.TimelineDa
             return value;
 
         case "startTime":
-            return isNaN(value) ? emDash : Number.secondsToString(value - this._baseStartTime, true);
-
         case "selfTime":
         case "totalTime":
         case "averageTime":
-            return isNaN(value) ? emDash : Number.secondsToString(value, true);
+            return isNaN(value) ? emDash : Number.secondsToString(value, higherResolution);
         }
 
         return super.createCellContent(columnIdentifier, cell);
@@ -186,6 +144,8 @@ WI.ProfileNodeDataGridNode = class ProfileNodeDataGridNode extends WI.TimelineDa
         this.removeChildren();
 
         for (let node of this._profileNode.childNodes)
-            this.appendChild(new WI.ProfileNodeDataGridNode(node, this.baseStartTime, this.rangeStartTime, this.rangeEndTime));
+            this.appendChild(new WI.ProfileNodeDataGridNode(node, {
+                graphDataSource: this.graphDataSource,
+            }));
     }
 };
index 1b0f2bc..0e14c85 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2015 Apple Inc. All rights reserved.
+ * 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
 
 WI.RenderingFrameTimelineDataGridNode = class RenderingFrameTimelineDataGridNode extends WI.TimelineDataGridNode
 {
-    constructor(renderingFrameTimelineRecord, baseStartTime)
+    constructor(record, options = {})
     {
-        super(false, null);
+        console.assert(record instanceof WI.RenderingFrameTimelineRecord);
 
-        this._record = renderingFrameTimelineRecord;
-        this._baseStartTime = baseStartTime || 0;
+        super([record], options);
     }
 
     // Public
 
-    get records()
-    {
-        return [this._record];
-    }
-
     get data()
     {
-        if (!this._cachedData) {
-            let name = WI.TimelineTabContentView.displayNameForRecord(this._record);
-            let scriptTime = this._record.durationForTask(WI.RenderingFrameTimelineRecord.TaskType.Script);
-            let layoutTime = this._record.durationForTask(WI.RenderingFrameTimelineRecord.TaskType.Layout);
-            let paintTime = this._record.durationForTask(WI.RenderingFrameTimelineRecord.TaskType.Paint);
-            let otherTime = this._record.durationForTask(WI.RenderingFrameTimelineRecord.TaskType.Other);
-            this._cachedData = {
-                name,
-                startTime: this._record.startTime,
-                totalTime: this._record.duration,
-                scriptTime,
-                layoutTime,
-                paintTime,
-                otherTime,
-            };
-        }
+        if (this._cachedData)
+            return this._cachedData;
 
+        this._cachedData = super.data;
+        this._cachedData.name = WI.TimelineTabContentView.displayNameForRecord(this.record);
+        this._cachedData.startTime = this.record.startTime - (this.graphDataSource ? this.graphDataSource.zeroTime : 0);
+        this._cachedData.totalTime = this.record.duration;
+        this._cachedData.scriptTime = this.record.durationForTask(WI.RenderingFrameTimelineRecord.TaskType.Script);
+        this._cachedData.layoutTime = this.record.durationForTask(WI.RenderingFrameTimelineRecord.TaskType.Layout);
+        this._cachedData.paintTime = this.record.durationForTask(WI.RenderingFrameTimelineRecord.TaskType.Paint);
+        this._cachedData.otherTime = this.record.durationForTask(WI.RenderingFrameTimelineRecord.TaskType.Other);
         return this._cachedData;
     }
 
     createCellContent(columnIdentifier, cell)
     {
+        const higherResolution = true;
+
         var value = this.data[columnIdentifier];
 
         switch (columnIdentifier) {
@@ -72,14 +62,14 @@ WI.RenderingFrameTimelineDataGridNode = class RenderingFrameTimelineDataGridNode
             return value;
 
         case "startTime":
-            return isNaN(value) ? emDash : Number.secondsToString(value - this._baseStartTime, true);
+            return isNaN(value) ? emDash : Number.secondsToString(value, higherResolution);
 
         case "scriptTime":
         case "layoutTime":
         case "paintTime":
         case "otherTime":
         case "totalTime":
-            return (isNaN(value) || value === 0) ? emDash : Number.secondsToString(value, true);
+            return (isNaN(value) || value === 0) ? emDash : Number.secondsToString(value, higherResolution);
         }
 
         return super.createCellContent(columnIdentifier, cell);
index 29dead8..ac4d9ca 100644 (file)
@@ -235,7 +235,9 @@ WI.RenderingFrameTimelineView = class RenderingFrameTimelineView extends WI.Time
         for (let renderingFrameTimelineRecord of this._pendingRecords) {
             console.assert(renderingFrameTimelineRecord instanceof WI.RenderingFrameTimelineRecord);
 
-            let dataGridNode = new WI.RenderingFrameTimelineDataGridNode(renderingFrameTimelineRecord, this.zeroTime);
+            let dataGridNode = new WI.RenderingFrameTimelineDataGridNode(renderingFrameTimelineRecord, {
+                graphDataSource: this,
+            });
             this._dataGrid.addRowInSortOrder(dataGridNode);
 
             let stack = [{children: renderingFrameTimelineRecord.children, parentDataGridNode: dataGridNode, index: 0}];
@@ -249,7 +251,9 @@ WI.RenderingFrameTimelineView = class RenderingFrameTimelineView extends WI.Time
                 let childRecord = entry.children[entry.index];
                 let childDataGridNode = null;
                 if (childRecord.type === WI.TimelineRecord.Type.Layout) {
-                    childDataGridNode = new WI.LayoutTimelineDataGridNode(childRecord, this.zeroTime);
+                    childDataGridNode = new WI.LayoutTimelineDataGridNode(childRecord, {
+                        graphDataSource: this,
+                    });
 
                     this._dataGrid.addRowInSortOrder(childDataGridNode, entry.parentDataGridNode);
                 } else if (childRecord.type === WI.TimelineRecord.Type.Script) {
@@ -259,12 +263,16 @@ WI.RenderingFrameTimelineView = class RenderingFrameTimelineView extends WI.Time
                         rootNodes = childRecord.profile.topDownRootNodes;
                     }
 
-                    childDataGridNode = new WI.ScriptTimelineDataGridNode(childRecord, this.zeroTime);
+                    childDataGridNode = new WI.ScriptTimelineDataGridNode(childRecord, {
+                        graphDataSource: this,
+                    });
 
                     this._dataGrid.addRowInSortOrder(childDataGridNode, entry.parentDataGridNode);
 
                     for (let profileNode of rootNodes) {
-                        let profileNodeDataGridNode = new WI.ProfileNodeDataGridNode(profileNode, this.zeroTime, this.startTime, this.endTime);
+                        let profileNodeDataGridNode = new WI.ProfileNodeDataGridNode(profileNode, {
+                            graphDataSource: this,
+                        });
                         this._dataGrid.addRowInSortOrder(profileNodeDataGridNode, childDataGridNode);
                     }
                 }
index 13b058c..ea80137 100644 (file)
@@ -37,7 +37,7 @@
 }
 
 .resource-timing-popover-content .data-grid td.graph-column {
-    padding: 4px 0 0;
+    padding: 4px 2px 0;
 }
 
 .resource-timing-popover-content .data-grid table.data {
index 7559642..0f0004f 100644 (file)
 
 WI.ResourceTimelineDataGridNode = class ResourceTimelineDataGridNode extends WI.TimelineDataGridNode
 {
-    constructor(resourceTimelineRecord, includesGraph, graphDataSource, shouldShowPopover)
+    constructor(record, options = {})
     {
-        super(includesGraph, graphDataSource);
+        console.assert(record instanceof WI.ResourceTimelineRecord);
 
-        this._resource = resourceTimelineRecord.resource;
-        this._record = resourceTimelineRecord;
-        this._shouldShowPopover = shouldShowPopover;
+        super([record], options);
 
-        this._resource.addEventListener(WI.Resource.Event.LoadingDidFinish, this._needsRefresh, this);
-        this._resource.addEventListener(WI.Resource.Event.LoadingDidFail, this._needsRefresh, this);
-        this._resource.addEventListener(WI.Resource.Event.URLDidChange, this._needsRefresh, this);
+        this._shouldShowPopover = options.shouldShowPopover;
 
-        if (includesGraph)
-            this._record.addEventListener(WI.TimelineRecord.Event.Updated, this._timelineRecordUpdated, this);
+        this.resource.addEventListener(WI.Resource.Event.LoadingDidFinish, this._needsRefresh, this);
+        this.resource.addEventListener(WI.Resource.Event.LoadingDidFail, this._needsRefresh, this);
+        this.resource.addEventListener(WI.Resource.Event.URLDidChange, this._needsRefresh, this);
+
+        if (options.includesGraph)
+            this.record.addEventListener(WI.TimelineRecord.Event.Updated, this._timelineRecordUpdated, this);
         else {
-            this._resource.addEventListener(WI.Resource.Event.TypeDidChange, this._needsRefresh, this);
-            this._resource.addEventListener(WI.Resource.Event.SizeDidChange, this._needsRefresh, this);
-            this._resource.addEventListener(WI.Resource.Event.TransferSizeDidChange, this._needsRefresh, this);
+            this.resource.addEventListener(WI.Resource.Event.TypeDidChange, this._needsRefresh, this);
+            this.resource.addEventListener(WI.Resource.Event.SizeDidChange, this._needsRefresh, this);
+            this.resource.addEventListener(WI.Resource.Event.TransferSizeDidChange, this._needsRefresh, this);
         }
     }
 
     // Public
 
-    get records()
-    {
-        return [this._record];
-    }
-
     get resource()
     {
-        return this._resource;
+        return this.record.resource;
     }
 
     get data()
@@ -63,40 +58,28 @@ WI.ResourceTimelineDataGridNode = class ResourceTimelineDataGridNode extends WI.
         if (this._cachedData)
             return this._cachedData;
 
-        var resource = this._resource;
-        var data = {};
-
-        if (!this._includesGraph) {
-            var zeroTime = this.graphDataSource ? this.graphDataSource.zeroTime : 0;
-
-            data.domain = WI.displayNameForHost(resource.urlComponents.host);
-            data.scheme = resource.urlComponents.scheme ? resource.urlComponents.scheme.toUpperCase() : "";
-            data.method = resource.requestMethod;
-            data.type = resource.type;
-            data.statusCode = resource.statusCode;
-            data.cached = resource.cached;
-            data.size = resource.size;
-            data.transferSize = !isNaN(resource.networkTotalTransferSize) ? resource.networkTotalTransferSize : resource.estimatedTotalTransferSize;
-            data.requestSent = resource.requestSentTimestamp - zeroTime;
-            data.duration = resource.receiveDuration;
-            data.latency = resource.latency;
-            data.protocol = resource.protocol;
-            data.priority = resource.priority;
-            data.remoteAddress = resource.remoteAddress;
-            data.connectionIdentifier = resource.connectionIdentifier;
-        }
-
-        data.graph = this._record.startTime;
-
-        this._cachedData = data;
-        return data;
+        this._cachedData = super.data;
+        this._cachedData.domain = WI.displayNameForHost(this.resource.urlComponents.host);
+        this._cachedData.scheme = this.resource.urlComponents.scheme ? this.resource.urlComponents.scheme.toUpperCase() : "";
+        this._cachedData.method = this.resource.requestMethod;
+        this._cachedData.type = this.resource.type;
+        this._cachedData.statusCode = this.resource.statusCode;
+        this._cachedData.cached = this.resource.cached;
+        this._cachedData.size = this.resource.size;
+        this._cachedData.transferSize = !isNaN(this.resource.networkTotalTransferSize) ? this.resource.networkTotalTransferSize : this.resource.estimatedTotalTransferSize;
+        this._cachedData.requestSent = this.resource.requestSentTimestamp - (this.graphDataSource ? this.graphDataSource.zeroTime : 0);
+        this._cachedData.duration = this.resource.receiveDuration;
+        this._cachedData.latency = this.resource.latency;
+        this._cachedData.protocol = this.resource.protocol;
+        this._cachedData.priority = this.resource.priority;
+        this._cachedData.remoteAddress = this.resource.remoteAddress;
+        this._cachedData.connectionIdentifier = this.resource.connectionIdentifier;
+        return this._cachedData;
     }
 
     createCellContent(columnIdentifier, cell)
     {
-        let resource = this._resource;
-
-        if (resource.hadLoadingError())
+        if (this.resource.hadLoadingError())
             cell.classList.add("error");
 
         let value = this.data[columnIdentifier];
@@ -104,7 +87,7 @@ WI.ResourceTimelineDataGridNode = class ResourceTimelineDataGridNode extends WI.
         switch (columnIdentifier) {
         case "name":
             cell.classList.add(...this.iconClassNames());
-            cell.title = resource.displayURL;
+            cell.title = this.resource.displayURL;
             this._updateStatus(cell);
             return this._createNameCellDocumentFragment();
 
@@ -114,7 +97,7 @@ WI.ResourceTimelineDataGridNode = class ResourceTimelineDataGridNode extends WI.
             return text;
 
         case "statusCode":
-            cell.title = resource.statusText || "";
+            cell.title = this.resource.statusText || "";
             return value || emDash;
 
         case "cached":
@@ -180,7 +163,7 @@ WI.ResourceTimelineDataGridNode = class ResourceTimelineDataGridNode extends WI.
 
     appendContextMenuItems(contextMenu)
     {
-        WI.appendContextMenuItemsForSourceCode(contextMenu, this._resource);
+        WI.appendContextMenuItemsForSourceCode(contextMenu, this.resource);
     }
 
     // Protected
@@ -213,7 +196,7 @@ WI.ResourceTimelineDataGridNode = class ResourceTimelineDataGridNode extends WI.
     filterableDataForColumn(columnIdentifier)
     {
         if (columnIdentifier === "name")
-            return this._resource.url;
+            return this.resource.url;
         return super.filterableDataForColumn(columnIdentifier);
     }
 
@@ -226,8 +209,8 @@ WI.ResourceTimelineDataGridNode = class ResourceTimelineDataGridNode extends WI.
         fragment.append(mainTitle);
 
         // Show the host as the subtitle if it is different from the main resource or if this is the main frame's main resource.
-        let frame = this._resource.parentFrame;
-        let isMainResource = this._resource.isMainResource();
+        let frame = this.resource.parentFrame;
+        let isMainResource = this.resource.isMainResource();
         let parentResourceHost;
         if (frame && isMainResource) {
             // When the resource is a main resource, get the host from the current frame's parent frame instead of the current frame.
@@ -237,8 +220,8 @@ WI.ResourceTimelineDataGridNode = class ResourceTimelineDataGridNode extends WI.
             parentResourceHost = frame.mainResource.urlComponents.host;
         }
 
-        if (parentResourceHost !== this._resource.urlComponents.host || frame.isMainFrame() && isMainResource) {
-            let subtitle = WI.displayNameForHost(this._resource.urlComponents.host);
+        if (parentResourceHost !== this.resource.urlComponents.host || frame.isMainFrame() && isMainResource) {
+            let subtitle = WI.displayNameForHost(this.resource.urlComponents.host);
             if (mainTitle !== subtitle) {
                 let subtitleElement = document.createElement("span");
                 subtitleElement.classList.add("subtitle");
@@ -252,12 +235,12 @@ WI.ResourceTimelineDataGridNode = class ResourceTimelineDataGridNode extends WI.
 
     _cachedCellContent()
     {
-        if (!this._resource.hasResponse())
+        if (!this.resource.hasResponse())
             return emDash;
 
-        let responseSource = this._resource.responseSource;
+        let responseSource = this.resource.responseSource;
         if (responseSource === WI.Resource.ResponseSource.MemoryCache || responseSource === WI.Resource.ResponseSource.DiskCache) {
-            console.assert(this._resource.cached, "This resource has a cache responseSource it should also be marked as cached", this._resource);
+            console.assert(this.resource.cached, "This resource has a cache responseSource it should also be marked as cached", this.resource);
             let span = document.createElement("span");
             let cacheType = document.createElement("span");
             cacheType.classList = "cache-type";
@@ -267,7 +250,7 @@ WI.ResourceTimelineDataGridNode = class ResourceTimelineDataGridNode extends WI.
         }
 
         let fragment = document.createDocumentFragment();
-        fragment.append(this._resource.cached ? WI.UIString("Yes") : WI.UIString("No"));
+        fragment.append(this.resource.cached ? WI.UIString("Yes") : WI.UIString("No"));
         return fragment;
     }
 
@@ -286,7 +269,7 @@ WI.ResourceTimelineDataGridNode = class ResourceTimelineDataGridNode extends WI.
 
     _timelineRecordUpdated(event)
     {
-        if (this.isRecordVisible(this._record))
+        if (this.isRecordVisible(this.record))
             this.needsGraphRefresh();
     }
 
@@ -296,21 +279,21 @@ WI.ResourceTimelineDataGridNode = class ResourceTimelineDataGridNode extends WI.
             ignoreNetworkTab: true,
             ignoreSearchTab: true,
         };
-        WI.showSourceCode(this._resource, options);
+        WI.showSourceCode(this.resource, options);
     }
 
     _updateStatus(cell)
     {
-        if (this._resource.failed)
+        if (this.resource.failed)
             cell.classList.add("error");
         else {
             cell.classList.remove("error");
 
-            if (this._resource.finished)
+            if (this.resource.finished)
                 this.createGoToArrowButton(cell, this._dataGridNodeGoToArrowClicked.bind(this));
         }
 
-        if (this._resource.isLoading()) {
+        if (this.resource.isLoading()) {
             if (!this._spinner)
                 this._spinner = new WI.IndeterminateProgressSpinner;
             let contentElement = cell.firstChild;
@@ -386,14 +369,10 @@ WI.ResourceTimelineDataGridNode = class ResourceTimelineDataGridNode extends WI.
             let graphDataSource = {
                 get secondsPerPixel() { return resource.totalDuration / WI.ResourceTimelineDataGridNode.PopoverGraphColumnWidthPixels; },
                 get zeroTime() { return resource.firstTimestamp; },
-                get startTime() { return resource.firstTimestamp; },
-                get currentTime() { return this.endTime; },
-
-                get endTime()
-                {
-                    let endTimePadding = this.secondsPerPixel * WI.TimelineRecordBar.MinimumWidthPixels;
-                    return resource.lastTimestamp + endTimePadding;
-                }
+                get startTime() { return this.zeroTime; },
+                get currentTime() { return resource.lastTimestamp + this._extraTimePadding; },
+                get endTime() { return this.currentTime; },
+                get _extraTimePadding() { return this.secondsPerPixel * WI.TimelineRecordBar.MinimumWidthPixels; },
             };
 
             if (resource.timingData.redirectEnd - resource.timingData.redirectStart) {
index 3bf03e4..96d1a01 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2016 Apple Inc. All rights reserved.
+ * 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
@@ -27,20 +27,26 @@ WI.ResourceTimingPopoverDataGridNode = class ResourceTimingPopoverDataGridNode e
 {
     constructor(description, startTime, endTime, graphDataSource)
     {
-        super(true, graphDataSource);
+        let record = new WI.TimelineRecord(WI.TimelineRecord.Type.Network, startTime, endTime);
+        super([record], {
+            includesGraph: true,
+            graphDataSource,
+        });
 
         const higherResolution = true;
         let duration = Number.secondsToMillisecondsString(endTime - startTime, higherResolution);
 
         this._data = {description, duration};
-        this._record = new WI.TimelineRecord(WI.TimelineRecord.Type.Network, startTime, endTime);
     }
 
     // Public
 
-    get records() { return [this._record]; }
     get data() { return this._data; }
-    get selectable() { return false; }
+
+    get selectable()
+    {
+        return false;
+    }
 
     // Protected
 
index 69bc1ae..6d8db3a 100644 (file)
@@ -179,9 +179,11 @@ WI.ScriptDetailsTimelineView = class ScriptDetailsTimelineView extends WI.Timeli
         if (this.startTime !== this._oldStartTime || this.endTime !== this._oldEndTime) {
             let dataGridNode = this._dataGrid.children[0];
             while (dataGridNode) {
-                dataGridNode.updateRangeTimes(this.startTime, this.endTime);
                 if (dataGridNode.revealed)
-                    dataGridNode.refreshIfNeeded();
+                    dataGridNode.refresh();
+                else
+                    dataGridNode.needsRefresh();
+
                 dataGridNode = dataGridNode.traverseNextNode(false, null, true);
             }
 
@@ -202,10 +204,6 @@ WI.ScriptDetailsTimelineView = class ScriptDetailsTimelineView extends WI.Timeli
         if (!this._pendingRecords.length)
             return;
 
-        let zeroTime = this.zeroTime;
-        let startTime = this.startTime;
-        let endTime = this.endTime;
-
         for (let scriptTimelineRecord of this._pendingRecords) {
             let rootNodes = [];
             if (scriptTimelineRecord.profile) {
@@ -213,11 +211,15 @@ WI.ScriptDetailsTimelineView = class ScriptDetailsTimelineView extends WI.Timeli
                 rootNodes = scriptTimelineRecord.profile.topDownRootNodes;
             }
 
-            let dataGridNode = new WI.ScriptTimelineDataGridNode(scriptTimelineRecord, zeroTime);
+            let dataGridNode = new WI.ScriptTimelineDataGridNode(scriptTimelineRecord, {
+                graphDataSource: this,
+            });
             this._dataGrid.addRowInSortOrder(dataGridNode);
 
             for (let profileNode of rootNodes) {
-                let profileNodeDataGridNode = new WI.ProfileNodeDataGridNode(profileNode, zeroTime, startTime, endTime);
+                let profileNodeDataGridNode = new WI.ProfileNodeDataGridNode(profileNode, {
+                    graphDataSource: this,
+                });
                 this._dataGrid.addRowInSortOrder(profileNodeDataGridNode, dataGridNode);
             }
         }
index 05d9ad1..4565bee 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2013, 2015 Apple Inc. All rights reserved.
+ * 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
 
 WI.ScriptTimelineDataGridNode = class ScriptTimelineDataGridNode extends WI.TimelineDataGridNode
 {
-    constructor(scriptTimelineRecord, baseStartTime, rangeStartTime, rangeEndTime)
+    constructor(record, options = {})
     {
-        super(false, null);
+        console.assert(record instanceof WI.ScriptTimelineRecord);
 
-        this._record = scriptTimelineRecord;
-        this._baseStartTime = baseStartTime || 0;
-        this._rangeStartTime = rangeStartTime || 0;
-        this._rangeEndTime = typeof rangeEndTime === "number" ? rangeEndTime : Infinity;
+        super([record], options);
     }
 
     // Public
 
-    get records()
-    {
-        return [this._record];
-    }
-
-    get baseStartTime()
-    {
-        return this._baseStartTime;
-    }
-
-    get rangeStartTime()
+    get data()
     {
-        return this._rangeStartTime;
-    }
+        if (this._cachedData)
+            return this._cachedData;
+
+        let baseStartTime = 0;
+        let rangeStartTime = 0;
+        let rangeEndTime = Infinity;
+        if (this.graphDataSource) {
+            baseStartTime = this.graphDataSource.zeroTime;
+            rangeStartTime = this.graphDataSource.startTime;
+            rangeEndTime = this.graphDataSource.endTime;
+        }
 
-    get rangeEndTime()
-    {
-        return this._rangeEndTime;
-    }
+        let startTime = this.record.startTime;
+        let duration = this.record.startTime + this.record.duration - startTime;
 
-    get data()
-    {
-        if (!this._cachedData) {
-            var startTime = this._record.startTime;
-            var duration = this._record.startTime + this._record.duration - startTime;
-            var callFrameOrSourceCodeLocation = this._record.initiatorCallFrame || this._record.sourceCodeLocation;
-
-            // COMPATIBILITY (iOS 8): Profiles included per-call information and can be finely partitioned.
-            if (this._record.profile) {
-                var oneRootNode = this._record.profile.topDownRootNodes[0];
-                if (oneRootNode && oneRootNode.calls) {
-                    startTime = Math.max(this._rangeStartTime, this._record.startTime);
-                    duration = Math.min(this._record.startTime + this._record.duration, this._rangeEndTime) - startTime;
-                }
+        // COMPATIBILITY (iOS 8): Profiles included per-call information and can be finely partitioned.
+        if (this.record.profile) {
+            let oneRootNode = this.record.profile.topDownRootNodes[0];
+            if (oneRootNode && oneRootNode.calls) {
+                startTime = Math.max(rangeStartTime, this.record.startTime);
+                duration = Math.min(this.record.startTime + this.record.duration, rangeEndTime) - startTime;
             }
-
-            this._cachedData = {
-                eventType: this._record.eventType,
-                startTime,
-                selfTime: duration,
-                totalTime: duration,
-                averageTime: duration,
-                callCount: this._record.callCountOrSamples,
-                location: callFrameOrSourceCodeLocation,
-            };
         }
 
+        this._cachedData = super.data;
+        this._cachedData.type = this.record.eventType;
+        this._cachedData.name = this.displayName();
+        this._cachedData.startTime = startTime - baseStartTime;
+        this._cachedData.selfTime = duration;
+        this._cachedData.totalTime = duration;
+        this._cachedData.averageTime = duration;
+        this._cachedData.callCount = this.record.callCountOrSamples;
+        this._cachedData.location = this.record.initiatorCallFrame || this.record.sourceCodeLocation;
+
         return this._cachedData;
     }
 
@@ -94,9 +80,9 @@ WI.ScriptTimelineDataGridNode = class ScriptTimelineDataGridNode extends WI.Time
 
         this._subtitle = "";
 
-        if (this._record.eventType === WI.ScriptTimelineRecord.EventType.TimerInstalled) {
-            let timeoutString = Number.secondsToString(this._record.details.timeout / 1000);
-            if (this._record.details.repeating)
+        if (this.record.eventType === WI.ScriptTimelineRecord.EventType.TimerInstalled) {
+            let timeoutString = Number.secondsToString(this.record.details.timeout / 1000);
+            if (this.record.details.repeating)
                 this._subtitle = WI.UIString("%s interval").format(timeoutString);
             else
                 this._subtitle = WI.UIString("%s delay").format(timeoutString);
@@ -105,35 +91,10 @@ WI.ScriptTimelineDataGridNode = class ScriptTimelineDataGridNode extends WI.Time
         return this._subtitle;
     }
 
-    updateRangeTimes(startTime, endTime)
-    {
-        var oldRangeStartTime = this._rangeStartTime;
-        var oldRangeEndTime = this._rangeEndTime;
-
-        if (oldRangeStartTime === startTime && oldRangeEndTime === endTime)
-            return;
-
-        this._rangeStartTime = startTime;
-        this._rangeEndTime = endTime;
-
-        // If we have no duration the range does not matter.
-        if (!this._record.duration)
-            return;
-
-        // We only need a refresh if the new range time changes the visible portion of this record.
-        var recordStart = this._record.startTime;
-        var recordEnd = this._record.startTime + this._record.duration;
-        var oldStartBoundary = Number.constrain(oldRangeStartTime, recordStart, recordEnd);
-        var oldEndBoundary = Number.constrain(oldRangeEndTime, recordStart, recordEnd);
-        var newStartBoundary = Number.constrain(startTime, recordStart, recordEnd);
-        var newEndBoundary = Number.constrain(endTime, recordStart, recordEnd);
-
-        if (oldStartBoundary !== newStartBoundary || oldEndBoundary !== newEndBoundary)
-            this.needsRefresh();
-    }
-
     createCellContent(columnIdentifier, cell)
     {
+        const higherResolution = true;
+
         var value = this.data[columnIdentifier];
 
         switch (columnIdentifier) {
@@ -142,15 +103,19 @@ WI.ScriptTimelineDataGridNode = class ScriptTimelineDataGridNode extends WI.Time
             return this._createNameCellDocumentFragment();
 
         case "startTime":
-            return isNaN(value) ? emDash : Number.secondsToString(value - this._baseStartTime, true);
-
         case "selfTime":
         case "totalTime":
         case "averageTime":
-            return isNaN(value) ? emDash : Number.secondsToString(value, true);
+            return isNaN(value) ? emDash : Number.secondsToString(value, higherResolution);
 
         case "callCount":
             return isNaN(value) ? emDash : value.toLocaleString();
+
+        // Necessary to be displayed in WI.LayoutTimelineView.
+        case "width":
+        case "height":
+        case "area":
+            return zeroWidthSpace;
         }
 
         return super.createCellContent(columnIdentifier, cell);
index ef6011e..807be16 100644 (file)
 
 WI.SourceCodeTimelineTimelineDataGridNode = class SourceCodeTimelineTimelineDataGridNode extends WI.TimelineDataGridNode
 {
-    constructor(sourceCodeTimeline, graphDataSource)
+    constructor(sourceCodeTimeline, options = {})
     {
-        super(true, graphDataSource);
+        const records = [];
+        super(records, {includesGraph: true, ...options});
 
         this._sourceCodeTimeline = sourceCodeTimeline;
         this._sourceCodeTimeline.addEventListener(WI.Timeline.Event.RecordAdded, this._timelineRecordAdded, this);
@@ -47,7 +48,12 @@ WI.SourceCodeTimelineTimelineDataGridNode = class SourceCodeTimelineTimelineData
 
     get data()
     {
-        return {graph: this._sourceCodeTimeline.startTime};
+        if (this._cachedData)
+            return this._cachedData;
+
+        this._cachedData = super.data;
+        this._cachedData.graph = this._sourceCodeTimeline.startTime;
+        return this._cachedData;
     }
 
     createCellContent(columnIdentifier, cell)
index a2f6247..5a09168 100644 (file)
 
 WI.TimelineDataGridNode = class TimelineDataGridNode extends WI.DataGridNode
 {
-    constructor(includesGraph, graphDataSource, hasChildren)
+    constructor(records, options = {})
     {
-        super({}, hasChildren);
+        super({}, options.hasChildren);
 
         this.copyable = false;
 
-        this._includesGraph = includesGraph || false;
-        this._graphDataSource = graphDataSource || null;
+        this._records = records;
+        this._includesGraph = options.includesGraph || false;
+        this._graphDataSource = options.graphDataSource || null;
+        this._cachedData = null;
 
-        if (graphDataSource) {
+        if (this._graphDataSource) {
             this._graphContainerElement = document.createElement("div");
             this._timelineRecordBars = [];
         }
@@ -42,17 +44,13 @@ WI.TimelineDataGridNode = class TimelineDataGridNode extends WI.DataGridNode
 
     // Public
 
+    get records() { return this._records; }
+
     get record()
     {
         return this.records && this.records.length ? this.records[0] : null;
     }
 
-    get records()
-    {
-        // Implemented by subclasses.
-        return [];
-    }
-
     get graphDataSource()
     {
         return this._graphDataSource;
@@ -63,8 +61,9 @@ WI.TimelineDataGridNode = class TimelineDataGridNode extends WI.DataGridNode
         if (!this._graphDataSource)
             return {};
 
-        var records = this.records || [];
-        return {graph: records.length ? records[0].startTime : 0};
+        return {
+            graph: this.record ? this.record.startTime : 0,
+        };
     }
 
     collapse()
@@ -207,6 +206,8 @@ WI.TimelineDataGridNode = class TimelineDataGridNode extends WI.DataGridNode
 
     refresh()
     {
+        this._cachedData = null;
+
         if (this._graphDataSource && this._includesGraph)
             this.needsGraphRefresh();