Changeset 163142 in webkit


Ignore:
Timestamp:
Jan 30, 2014, 5:35:12 PM (11 years ago)
Author:
timothy@apple.com
Message:

Show profile data in the discrete Scripts timeline view.

https://bugs.webkit.org/show_bug.cgi?id=127900

Reviewed by Joseph Pecoraro.

  • Localizations/en.lproj/localizedStrings.js:
  • UserInterface/DataGrid.js:

(WebInspector.DataGridNode.prototype.refreshIfNeeded):
(WebInspector.DataGridNode.prototype.needsRefresh):
(WebInspector.DataGridNode.prototype.set data):
(WebInspector.DataGridNode.prototype.set revealed):
(WebInspector.DataGridNode.prototype.refresh):

  • UserInterface/LayoutTimelineDataGrid.js:

(WebInspector.LayoutTimelineDataGrid):

  • UserInterface/LayoutTimelineDataGridNode.js:

(WebInspector.LayoutTimelineDataGridNode.prototype.createCellContent):

  • UserInterface/Main.html:
  • UserInterface/NavigationSidebarPanel.js:

(WebInspector.NavigationSidebarPanel.prototype._updateFilter):
(WebInspector.NavigationSidebarPanel.prototype._treeElementAddedOrChanged):
(WebInspector.NavigationSidebarPanel.prototype._generateStyleRulesIfNeeded):

  • UserInterface/ProfileNodeDataGridNode.js: Added.

(WebInspector.ProfileNodeDataGridNode):
(WebInspector.ProfileNodeDataGridNode.prototype.get profileNode):
(WebInspector.ProfileNodeDataGridNode.prototype.get records):
(WebInspector.ProfileNodeDataGridNode.prototype.get baseStartTime):
(WebInspector.ProfileNodeDataGridNode.prototype.get rangeStartTime):
(WebInspector.ProfileNodeDataGridNode.prototype.set rangeStartTime):
(WebInspector.ProfileNodeDataGridNode.prototype.get rangeEndTime):
(WebInspector.ProfileNodeDataGridNode.prototype.set rangeEndTime):
(WebInspector.ProfileNodeDataGridNode.prototype.get data):
(WebInspector.ProfileNodeDataGridNode.prototype.refresh):
(WebInspector.ProfileNodeDataGridNode.prototype.createCellContent):

  • UserInterface/ProfileNodeTreeElement.js: Added.

(WebInspector.ProfileNodeTreeElement):
(WebInspector.ProfileNodeTreeElement.prototype.get profileNode):
(WebInspector.ProfileNodeTreeElement.prototype.get filterableData):
(WebInspector.ProfileNodeTreeElement.prototype.onattach):
(WebInspector.ProfileNodeTreeElement.prototype.onpopulate):

  • UserInterface/ResourceTimelineDataGridNode.js:

(WebInspector.ResourceTimelineDataGridNode.prototype.createCellContent):

  • UserInterface/ScriptTimelineDataGrid.js:

(WebInspector.ScriptTimelineDataGrid):

  • UserInterface/ScriptTimelineDataGridNode.js:

(WebInspector.ScriptTimelineDataGridNode):
(WebInspector.ScriptTimelineDataGridNode.prototype.get baseStartTime):
(WebInspector.ScriptTimelineDataGridNode.prototype.get rangeStartTime):
(WebInspector.ScriptTimelineDataGridNode.prototype.set rangeStartTime):
(WebInspector.ScriptTimelineDataGridNode.prototype.get rangeEndTime):
(WebInspector.ScriptTimelineDataGridNode.prototype.set rangeEndTime):
(WebInspector.ScriptTimelineDataGridNode.prototype.get data):
(WebInspector.ScriptTimelineDataGridNode.prototype.createCellContent):

  • UserInterface/ScriptTimelineRecord.js:

(WebInspector.ScriptTimelineRecord):
(WebInspector.ScriptTimelineRecord.prototype.get profile):

  • UserInterface/ScriptTimelineView.js:

(WebInspector.ScriptTimelineView.prototype.updateLayout):
(WebInspector.ScriptTimelineView.prototype.get selectionPathComponents):
(WebInspector.ScriptTimelineView.prototype.dataGridNodeForTreeElement):
(WebInspector.ScriptTimelineView.prototype.populateProfileNodeTreeElement):
(WebInspector.ScriptTimelineView.prototype._processPendingRecords):
(WebInspector.ScriptTimelineView.prototype._treeElementSelected):

  • UserInterface/TimelineContentView.js:

(WebInspector.TimelineContentView.prototype.matchTreeElementAgainstCustomFilters):

  • UserInterface/TimelineDataGrid.js:

(WebInspector.TimelineDataGrid):
(WebInspector.TimelineDataGrid.prototype.addRowInSortOrder):
(WebInspector.TimelineDataGrid.prototype._sort):

  • UserInterface/TimelineDataGridNode.js:

(WebInspector.TimelineDataGridNode):
(WebInspector.TimelineDataGridNode.prototype.collapse):
(WebInspector.TimelineDataGridNode.prototype.expand):

  • UserInterface/TimelineRecord.js:
  • UserInterface/TreeOutlineDataGridSynchronizer.js:

(WebInspector.TreeOutlineDataGridSynchronizer.prototype.get delegate):
(WebInspector.TreeOutlineDataGridSynchronizer.prototype.dataGridNodeForTreeElement):
(WebInspector.TreeOutlineDataGridSynchronizer.prototype._treeElementAdded):

Location:
trunk/Source/WebInspectorUI
Files:
1 added
19 edited
1 copied

Legend:

Unmodified
Added
Removed
  • trunk/Source/WebInspectorUI/ChangeLog

    r163141 r163142  
     12014-01-30  Timothy Hatcher  <timothy@apple.com>
     2
     3        Show profile data in the discrete Scripts timeline view.
     4
     5        https://bugs.webkit.org/show_bug.cgi?id=127900
     6
     7        Reviewed by Joseph Pecoraro.
     8
     9        * Localizations/en.lproj/localizedStrings.js:
     10        * UserInterface/DataGrid.js:
     11        (WebInspector.DataGridNode.prototype.refreshIfNeeded):
     12        (WebInspector.DataGridNode.prototype.needsRefresh):
     13        (WebInspector.DataGridNode.prototype.set data):
     14        (WebInspector.DataGridNode.prototype.set revealed):
     15        (WebInspector.DataGridNode.prototype.refresh):
     16        * UserInterface/LayoutTimelineDataGrid.js:
     17        (WebInspector.LayoutTimelineDataGrid):
     18        * UserInterface/LayoutTimelineDataGridNode.js:
     19        (WebInspector.LayoutTimelineDataGridNode.prototype.createCellContent):
     20        * UserInterface/Main.html:
     21        * UserInterface/NavigationSidebarPanel.js:
     22        (WebInspector.NavigationSidebarPanel.prototype._updateFilter):
     23        (WebInspector.NavigationSidebarPanel.prototype._treeElementAddedOrChanged):
     24        (WebInspector.NavigationSidebarPanel.prototype._generateStyleRulesIfNeeded):
     25        * UserInterface/ProfileNodeDataGridNode.js: Added.
     26        (WebInspector.ProfileNodeDataGridNode):
     27        (WebInspector.ProfileNodeDataGridNode.prototype.get profileNode):
     28        (WebInspector.ProfileNodeDataGridNode.prototype.get records):
     29        (WebInspector.ProfileNodeDataGridNode.prototype.get baseStartTime):
     30        (WebInspector.ProfileNodeDataGridNode.prototype.get rangeStartTime):
     31        (WebInspector.ProfileNodeDataGridNode.prototype.set rangeStartTime):
     32        (WebInspector.ProfileNodeDataGridNode.prototype.get rangeEndTime):
     33        (WebInspector.ProfileNodeDataGridNode.prototype.set rangeEndTime):
     34        (WebInspector.ProfileNodeDataGridNode.prototype.get data):
     35        (WebInspector.ProfileNodeDataGridNode.prototype.refresh):
     36        (WebInspector.ProfileNodeDataGridNode.prototype.createCellContent):
     37        * UserInterface/ProfileNodeTreeElement.js: Added.
     38        (WebInspector.ProfileNodeTreeElement):
     39        (WebInspector.ProfileNodeTreeElement.prototype.get profileNode):
     40        (WebInspector.ProfileNodeTreeElement.prototype.get filterableData):
     41        (WebInspector.ProfileNodeTreeElement.prototype.onattach):
     42        (WebInspector.ProfileNodeTreeElement.prototype.onpopulate):
     43        * UserInterface/ResourceTimelineDataGridNode.js:
     44        (WebInspector.ResourceTimelineDataGridNode.prototype.createCellContent):
     45        * UserInterface/ScriptTimelineDataGrid.js:
     46        (WebInspector.ScriptTimelineDataGrid):
     47        * UserInterface/ScriptTimelineDataGridNode.js:
     48        (WebInspector.ScriptTimelineDataGridNode):
     49        (WebInspector.ScriptTimelineDataGridNode.prototype.get baseStartTime):
     50        (WebInspector.ScriptTimelineDataGridNode.prototype.get rangeStartTime):
     51        (WebInspector.ScriptTimelineDataGridNode.prototype.set rangeStartTime):
     52        (WebInspector.ScriptTimelineDataGridNode.prototype.get rangeEndTime):
     53        (WebInspector.ScriptTimelineDataGridNode.prototype.set rangeEndTime):
     54        (WebInspector.ScriptTimelineDataGridNode.prototype.get data):
     55        (WebInspector.ScriptTimelineDataGridNode.prototype.createCellContent):
     56        * UserInterface/ScriptTimelineRecord.js:
     57        (WebInspector.ScriptTimelineRecord):
     58        (WebInspector.ScriptTimelineRecord.prototype.get profile):
     59        * UserInterface/ScriptTimelineView.js:
     60        (WebInspector.ScriptTimelineView.prototype.updateLayout):
     61        (WebInspector.ScriptTimelineView.prototype.get selectionPathComponents):
     62        (WebInspector.ScriptTimelineView.prototype.dataGridNodeForTreeElement):
     63        (WebInspector.ScriptTimelineView.prototype.populateProfileNodeTreeElement):
     64        (WebInspector.ScriptTimelineView.prototype._processPendingRecords):
     65        (WebInspector.ScriptTimelineView.prototype._treeElementSelected):
     66        * UserInterface/TimelineContentView.js:
     67        (WebInspector.TimelineContentView.prototype.matchTreeElementAgainstCustomFilters):
     68        * UserInterface/TimelineDataGrid.js:
     69        (WebInspector.TimelineDataGrid):
     70        (WebInspector.TimelineDataGrid.prototype.addRowInSortOrder):
     71        (WebInspector.TimelineDataGrid.prototype._sort):
     72        * UserInterface/TimelineDataGridNode.js:
     73        (WebInspector.TimelineDataGridNode):
     74        (WebInspector.TimelineDataGridNode.prototype.collapse):
     75        (WebInspector.TimelineDataGridNode.prototype.expand):
     76        * UserInterface/TimelineRecord.js:
     77        * UserInterface/TreeOutlineDataGridSynchronizer.js:
     78        (WebInspector.TreeOutlineDataGridSynchronizer.prototype.get delegate):
     79        (WebInspector.TreeOutlineDataGridSynchronizer.prototype.dataGridNodeForTreeElement):
     80        (WebInspector.TreeOutlineDataGridSynchronizer.prototype._treeElementAdded):
     81
    1822014-01-30  Timothy Hatcher  <timothy@apple.com>
    283
  • trunk/Source/WebInspectorUI/Localizations/en.lproj/localizedStrings.js

    r163130 r163142  
    1717localizedStrings["%.2fms"] = "%.2fms";
    1818localizedStrings["%.2fs"] = "%.2fs";
     19localizedStrings["%.3fms"] = "%.3fms";
    1920localizedStrings["%d \xd7 %d pixels"] = "%d \xd7 %d pixels";
    2021localizedStrings["%d \xd7 %d pixels (Natural: %d \xd7 %d pixels)"] = "%d \xd7 %d pixels (Natural: %d \xd7 %d pixels)";
     
    2425localizedStrings["%s Event Dispatched"] = "%s Event Dispatched";
    2526localizedStrings["(anonymous function)"] = "(anonymous function)";
     27localizedStrings["(program)"] = "(program)";
    2628localizedStrings["1 match"] = "1 match";
    2729localizedStrings["999+"] = "999+";
     
    5355localizedStrings["Automatically continue after evaluating"] = "Automatically continue after evaluating";
    5456localizedStrings["Average"] = "Average";
     57localizedStrings["Average Time"] = "Average Time";
    5558localizedStrings["Back (%s)"] = "Back (%s)";
    5659localizedStrings["Boundary"] = "Boundary";
     
    5861localizedStrings["Breakpoints"] = "Breakpoints";
    5962localizedStrings["Bubbling"] = "Bubbling";
    60 localizedStrings["CANVAS PROFILES"] = "CANVAS PROFILES";
    6163localizedStrings["Cached"] = "Cached";
    62 localizedStrings["Call"] = "Call";
    6364localizedStrings["Call Stack"] = "Call Stack";
    6465localizedStrings["Calls"] = "Calls";
    6566localizedStrings["Cancel Automatic Continue"] = "Cancel Automatic Continue";
    66 localizedStrings["Canvas Profile %d"] = "Canvas Profile %d";
    67 localizedStrings["Canvas profiles allow you to examine drawing operations on canvas elements."] = "Canvas profiles allow you to examine drawing operations on canvas elements.";
    6867localizedStrings["Capturing"] = "Capturing";
    6968localizedStrings["Catch Variables"] = "Catch Variables";
     
    7877localizedStrings["Code"] = "Code";
    7978localizedStrings["Collapse columns"] = "Collapse columns";
    80 localizedStrings["Collect Canvas Profile"] = "Collect Canvas Profile";
    8179localizedStrings["Collect JavaScript Profile"] = "Collect JavaScript Profile";
    8280localizedStrings["Comment"] = "Comment";
     
    292290localizedStrings["Reasons for compositing:"] = "Reasons for compositing:";
    293291localizedStrings["Recording"] = "Recording";
    294 localizedStrings["Recording Canvas Profile…"] = "Recording Canvas Profile…";
    295292localizedStrings["Recording JavaScript Profile\u2026"] = "Recording JavaScript Profile\u2026";
    296293localizedStrings["Recording\u2026"] = "Recording\u2026";
     
    324321localizedStrings["Security Issue"] = "Security Issue";
    325322localizedStrings["Self"] = "Self";
     323localizedStrings["Self Time"] = "Self Time";
    326324localizedStrings["Semantic Issue"] = "Semantic Issue";
    327325localizedStrings["Session"] = "Session";
     
    348346localizedStrings["Sockets"] = "Sockets";
    349347localizedStrings["Source Code"] = "Source Code";
    350 localizedStrings["Start Canvas profiling."] = "Start Canvas profiling.";
    351348localizedStrings["Start JavaScript profiling."] = "Start JavaScript profiling.";
    352349localizedStrings["Start Recording"] = "Start Recording";
     
    356353localizedStrings["Step out (%s or %s)"] = "Step out (%s or %s)";
    357354localizedStrings["Step over (%s or %s)"] = "Step over (%s or %s)";
    358 localizedStrings["Stop Canvas profiling."] = "Stop Canvas profiling.";
    359355localizedStrings["Stop JavaScript profiling."] = "Stop JavaScript profiling.";
    360356localizedStrings["Stop Recording"] = "Stop Recording";
     
    381377localizedStrings["Tip: "] = "Tip: ";
    382378localizedStrings["Total"] = "Total";
     379localizedStrings["Total Time"] = "Total Time";
    383380localizedStrings["Total number of resources, click to show the Resources navigation sidebar"] = "Total number of resources, click to show the Resources navigation sidebar";
    384381localizedStrings["Total size of all resources, click to show the Network Requests timeline"] = "Total size of all resources, click to show the Network Requests timeline";
  • trunk/Source/WebInspectorUI/UserInterface/DataGrid.js

    r163015 r163142  
    13651365    },
    13661366
     1367    refreshIfNeeded: function()
     1368    {
     1369        if (!this._needsRefresh)
     1370            return;
     1371
     1372        delete this._needsRefresh;
     1373
     1374        this.refresh();
     1375    },
     1376
     1377    needsRefresh: function()
     1378    {
     1379        this._needsRefresh = true;
     1380
     1381        if (!this._revealed)
     1382            return;
     1383
     1384        if (this._scheduledRefreshIdentifier)
     1385            return;
     1386
     1387        this._scheduledRefreshIdentifier = requestAnimationFrame(this.refresh.bind(this));
     1388    },
     1389
    13671390    get data()
    13681391    {
     
    13731396    {
    13741397        this._data = x || {};
    1375         this.refresh();
     1398        this.needsRefresh();
    13761399    },
    13771400
     
    14361459                this._element.classList.remove("revealed");
    14371460        }
     1461
     1462        this.refreshIfNeeded();
    14381463
    14391464        for (var i = 0; i < this.children.length; ++i)
     
    15031528        if (!this._element || !this.dataGrid)
    15041529            return;
     1530
     1531        if (this._scheduledRefreshIdentifier) {
     1532            cancelAnimationFrame(this._scheduledRefreshIdentifier);
     1533            delete this._scheduledRefreshIdentifier;
     1534        }
     1535
     1536        delete this._needsRefresh;
    15051537
    15061538        this._element.removeChildren();
  • trunk/Source/WebInspectorUI/UserInterface/LayoutTimelineDataGrid.js

    r162416 r163142  
    2424 */
    2525
    26 WebInspector.LayoutTimelineDataGrid = function(treeOutline, columns, editCallback, deleteCallback)
     26WebInspector.LayoutTimelineDataGrid = function(treeOutline, columns, delegate, editCallback, deleteCallback)
    2727{
    28     WebInspector.TimelineDataGrid.call(this, treeOutline, columns, editCallback, deleteCallback);
     28    WebInspector.TimelineDataGrid.call(this, treeOutline, columns, delegate, editCallback, deleteCallback);
    2929
    3030    this._showingHighlight = false;
  • trunk/Source/WebInspectorUI/UserInterface/LayoutTimelineDataGridNode.js

    r162416 r163142  
    7575
    7676        case "startTime":
    77             return isNaN(value) ? emptyValuePlaceholderString : Number.secondsToString(value - this._baseStartTime);
     77            return isNaN(value) ? emptyValuePlaceholderString : Number.secondsToString(value - this._baseStartTime, true);
    7878
    7979        case "duration":
    80             return isNaN(value) ? emptyValuePlaceholderString : Number.secondsToString(value);
     80            return isNaN(value) ? emptyValuePlaceholderString : Number.secondsToString(value, true);
    8181        }
    8282
  • trunk/Source/WebInspectorUI/UserInterface/Main.html

    r163141 r163142  
    370370    <script src="ScriptTimelineDataGridNode.js"></script>
    371371    <script src="SourceCodeTimelineTimelineDataGridNode.js"></script>
     372    <script src="ProfileNodeTreeElement.js"></script>
     373    <script src="ProfileNodeDataGridNode.js"></script>
    372374    <script src="TreeOutlineDataGridSynchronizer.js"></script>
    373375    <script src="TimelineOverview.js"></script>
  • trunk/Source/WebInspectorUI/UserInterface/NavigationSidebarPanel.js

    r162560 r163142  
    487487        this._filtersSetting.value = filters;
    488488
     489        // Don't populate if we don't have any active filters.
     490        // We only need to populate when a filter needs to reveal.
     491        var dontPopulate = !this._filterBar.hasActiveFilters();
     492
    489493        // Update the whole tree.
    490494        var currentTreeElement = this._contentTreeOutline.children[0];
    491495        while (currentTreeElement && !currentTreeElement.root) {
    492496            this.applyFiltersToTreeElement(currentTreeElement);
    493             currentTreeElement = currentTreeElement.traverseNextTreeElement(false, null, false);
     497            currentTreeElement = currentTreeElement.traverseNextTreeElement(false, null, dontPopulate);
    494498        }
    495499
     
    500504    _treeElementAddedOrChanged: function(treeElement)
    501505    {
     506        // Don't populate if we don't have any active filters.
     507        // We only need to populate when a filter needs to reveal.
     508        var dontPopulate = !this._filterBar.hasActiveFilters();
     509
    502510        // Apply the filters to the tree element and its descendants.
    503511        var currentTreeElement = treeElement;
    504512        while (currentTreeElement && !currentTreeElement.root) {
    505513            this.applyFiltersToTreeElement(currentTreeElement);
    506             currentTreeElement = currentTreeElement.traverseNextTreeElement(false, treeElement, false);
     514            currentTreeElement = currentTreeElement.traverseNextTreeElement(false, treeElement, dontPopulate);
    507515        }
    508516
     
    524532        WebInspector.NavigationSidebarPanel._styleElement = document.createElement("style");
    525533
    526         const maximumSidebarTreeDepth = 15;
     534        const maximumSidebarTreeDepth = 32;
    527535        const baseLeftPadding = 5; // Matches the padding in NavigationSidebarPanel.css for the item class. Keep in sync.
    528         const depthPadding = 16;
     536        const depthPadding = 10;
    529537
    530538        var styleText = "";
    531         var childrenSubstring = " > ";
     539        var childrenSubstring = "";
    532540        for (var i = 1; i <= maximumSidebarTreeDepth; ++i) {
    533             childrenSubstring += ".children > ";
    534             styleText += "." + WebInspector.NavigationSidebarPanel.ContentTreeOutlineElementStyleClassName + childrenSubstring + ".item { ";
     541            // Keep all the elements at the same depth once the maximum is reached.
     542            childrenSubstring += i === maximumSidebarTreeDepth ? " .children" : " > .children";
     543            styleText += "." + WebInspector.NavigationSidebarPanel.ContentTreeOutlineElementStyleClassName + childrenSubstring + " > .item { ";
    535544            styleText += "padding-left: " + (baseLeftPadding + (depthPadding * i)) + "px; }\n";
    536545        }
  • trunk/Source/WebInspectorUI/UserInterface/ProfileNode.js

    r163141 r163142  
    145145    computeCallInfoForTimeRange: function(rangeStartTime, rangeEndTime)
    146146    {
    147         rangeStartTime = !isNaN(rangeStartTime) ? rangeStartTime : 0;
    148         rangeEndTime = !isNaN(rangeEndTime) ? rangeEndTime : Infinity;
     147        console.assert(typeof rangeStartTime === "number");
     148        console.assert(typeof rangeEndTime === "number");
    149149
    150150        var recordCallCount = true;
  • trunk/Source/WebInspectorUI/UserInterface/ProfileNodeDataGridNode.js

    r163141 r163142  
    11/*
    2  * Copyright (C) 2013 Apple Inc. All rights reserved.
     2 * Copyright (C) 2014 Apple Inc. All rights reserved.
    33 *
    44 * Redistribution and use in source and binary forms, with or without
     
    2424 */
    2525
    26 WebInspector.LayoutTimelineDataGridNode = function(layoutTimelineRecord, baseStartTime)
     26WebInspector.ProfileNodeDataGridNode = function(profileNode, baseStartTime, rangeStartTime, rangeEndTime)
    2727{
    28     WebInspector.TimelineDataGridNode.call(this, false, null);
     28    var hasChildren = !!profileNode.childNodes.length;
    2929
    30     this._record = layoutTimelineRecord;
     30    WebInspector.TimelineDataGridNode.call(this, false, null, hasChildren);
     31
     32    this._profileNode = profileNode;
    3133    this._baseStartTime = baseStartTime || 0;
     34    this._rangeStartTime = rangeStartTime || 0;
     35    this._rangeEndTime = typeof rangeEndTime === "number" ? rangeEndTime : Infinity;
     36
     37    this._data = this._profileNode.computeCallInfoForTimeRange(this._rangeStartTime, this._rangeEndTime);
     38    this._data.location = this._profileNode.sourceCodeLocation;
    3239};
    3340
    34 WebInspector.Object.addConstructorFunctions(WebInspector.LayoutTimelineDataGridNode);
     41WebInspector.Object.addConstructorFunctions(WebInspector.ProfileNodeDataGridNode);
    3542
    36 WebInspector.LayoutTimelineDataGridNode.IconStyleClassName = "icon";
    37 WebInspector.LayoutTimelineDataGridNode.SubtitleStyleClassName = "subtitle";
     43WebInspector.ProfileNodeDataGridNode.IconStyleClassName = "icon";
    3844
    39 WebInspector.LayoutTimelineDataGridNode.prototype = {
    40     constructor: WebInspector.LayoutTimelineDataGridNode,
     45WebInspector.ProfileNodeDataGridNode.prototype = {
     46    constructor: WebInspector.ProfileNodeDataGridNode,
    4147    __proto__: WebInspector.TimelineDataGridNode.prototype,
    4248
    4349    // Public
    4450
    45     get record()
     51    get profileNode()
    4652    {
    47         return this._record;
     53        return this._profileNode;
    4854    },
    4955
    5056    get records()
    5157    {
    52         return [this._record];
     58        return null;
     59    },
     60
     61    get baseStartTime()
     62    {
     63        return this._baseStartTime;
     64    },
     65
     66    get rangeStartTime()
     67    {
     68        return this._rangeStartTime;
     69    },
     70
     71    set rangeStartTime(x)
     72    {
     73        if (this._rangeStartTime === x)
     74            return;
     75
     76        this._rangeStartTime = x;
     77        this.needsRefresh();
     78    },
     79
     80    get rangeEndTime()
     81    {
     82        return this._rangeEndTime;
     83    },
     84
     85    set rangeEndTime(x)
     86    {
     87        if (this._rangeEndTime === x)
     88            return;
     89
     90        this._rangeEndTime = x;
     91        this.needsRefresh();
    5392    },
    5493
    5594    get data()
    5695    {
    57         return this._record;
     96        return this._data;
     97    },
     98
     99    refresh: function()
     100    {
     101        this._data = this._profileNode.computeCallInfoForTimeRange(this._rangeStartTime, this._rangeEndTime);
     102        this._data.location = this._profileNode.sourceCodeLocation;
     103
     104        WebInspector.TimelineDataGridNode.prototype.refresh.call(this);
    58105    },
    59106
     
    64111
    65112        switch (columnIdentifier) {
    66         case "eventType":
    67             return WebInspector.LayoutTimelineRecord.EventType.displayName(value);
     113        case "startTime":
     114            return isNaN(value) ? emptyValuePlaceholderString : Number.secondsToString(value - this._baseStartTime, true);
    68115
    69         case "width":
    70         case "height":
    71             return isNaN(value) ? emptyValuePlaceholderString : WebInspector.UIString("%fpx").format(value);
    72 
    73         case "area":
    74             return isNaN(value) ? emptyValuePlaceholderString : WebInspector.UIString("%fpx²").format(value);
    75 
    76         case "startTime":
    77             return isNaN(value) ? emptyValuePlaceholderString : Number.secondsToString(value - this._baseStartTime);
    78 
    79         case "duration":
    80             return isNaN(value) ? emptyValuePlaceholderString : Number.secondsToString(value);
     116        case "selfTime":
     117        case "totalTime":
     118        case "averageTime":
     119            return isNaN(value) ? emptyValuePlaceholderString : Number.secondsToString(value, true);
    81120        }
    82121
  • trunk/Source/WebInspectorUI/UserInterface/ResourceTimelineDataGridNode.js

    r162560 r163142  
    142142        case "size":
    143143        case "transferSize":
    144             return isNaN(value) ? emptyValuePlaceholderString : Number.bytesToString(value);
     144            return isNaN(value) ? emptyValuePlaceholderString : Number.bytesToString(value, true);
    145145
    146146        case "requestSent":
    147147        case "latency":
    148148        case "duration":
    149             return isNaN(value) ? emptyValuePlaceholderString : Number.secondsToString(value);
     149            return isNaN(value) ? emptyValuePlaceholderString : Number.secondsToString(value, true);
    150150        }
    151151
  • trunk/Source/WebInspectorUI/UserInterface/ScriptTimelineDataGrid.js

    r162416 r163142  
    2424 */
    2525
    26 WebInspector.ScriptTimelineDataGrid = function(treeOutline, columns, editCallback, deleteCallback)
     26WebInspector.ScriptTimelineDataGrid = function(treeOutline, columns, delegate, editCallback, deleteCallback)
    2727{
    28     WebInspector.TimelineDataGrid.call(this, treeOutline, columns, editCallback, deleteCallback);
     28    WebInspector.TimelineDataGrid.call(this, treeOutline, columns, delegate, editCallback, deleteCallback);
    2929}
    3030
  • trunk/Source/WebInspectorUI/UserInterface/ScriptTimelineDataGridNode.js

    r162420 r163142  
    2424 */
    2525
    26 WebInspector.ScriptTimelineDataGridNode = function(scriptTimelineRecord, baseStartTime)
     26WebInspector.ScriptTimelineDataGridNode = function(scriptTimelineRecord, baseStartTime, rangeStartTime, rangeEndTime)
    2727{
    2828    WebInspector.TimelineDataGridNode.call(this, false, null);
     
    3030    this._record = scriptTimelineRecord;
    3131    this._baseStartTime = baseStartTime || 0;
     32    this._rangeStartTime = rangeStartTime || 0;
     33    this._rangeEndTime = typeof rangeEndTime === "number" ? rangeEndTime : Infinity;
    3234};
    3335
     
    5254    },
    5355
     56    get baseStartTime()
     57    {
     58        return this._baseStartTime;
     59    },
     60
     61    get rangeStartTime()
     62    {
     63        return this._rangeStartTime;
     64    },
     65
     66    set rangeStartTime(x)
     67    {
     68        if (this._rangeStartTime === x)
     69            return;
     70
     71        this._rangeStartTime = x;
     72        this.needsRefresh();
     73    },
     74
     75    get rangeEndTime()
     76    {
     77        return this._rangeEndTime;
     78    },
     79
     80    set rangeEndTime(x)
     81    {
     82        if (this._rangeEndTime === x)
     83            return;
     84
     85        this._rangeEndTime = x;
     86        this.needsRefresh();
     87    },
     88
    5489    get data()
    5590    {
     91        var startTime = Math.max(this._rangeStartTime, this._record.startTime);
     92        var duration = Math.min(this._record.startTime + this._record.duration, this._rangeEndTime) - startTime;
    5693        var callFrameOrSourceCodeLocation = this._record.initiatorCallFrame || this._record.sourceCodeLocation;
    57         return {eventType: this._record.eventType, details: this._record.details, startTime: this._record.startTime, duration: this._record.duration, location: callFrameOrSourceCodeLocation};
     94
     95        return {eventType: this._record.eventType, startTime: startTime, selfTime: duration, totalTime: duration,
     96            averageTime: duration, callCount: 1, location: callFrameOrSourceCodeLocation};
    5897    },
    5998
     
    67106            return WebInspector.ScriptTimelineRecord.EventType.displayName(value, this._record.details);
    68107
    69         case "details":
    70             return value ? value : emptyValuePlaceholderString;
     108        case "startTime":
     109            return isNaN(value) ? emptyValuePlaceholderString : Number.secondsToString(value - this._baseStartTime, true);
    71110
    72         case "startTime":
    73             return isNaN(value) ? emptyValuePlaceholderString : Number.secondsToString(value - this._baseStartTime);
    74 
    75         case "duration":
    76             return isNaN(value) ? emptyValuePlaceholderString : Number.secondsToString(value);
     111        case "selfTime":
     112        case "totalTime":
     113        case "averageTime":
     114            return isNaN(value) ? emptyValuePlaceholderString : Number.secondsToString(value, true);
    77115        }
    78116
  • trunk/Source/WebInspectorUI/UserInterface/ScriptTimelineRecord.js

    r162420 r163142  
    2424 */
    2525
    26 WebInspector.ScriptTimelineRecord = function(eventType, startTime, endTime, callFrames, sourceCodeLocation, details)
     26WebInspector.ScriptTimelineRecord = function(eventType, startTime, endTime, callFrames, sourceCodeLocation, details, profile)
    2727{
    2828    WebInspector.TimelineRecord.call(this, WebInspector.TimelineRecord.Type.Script, startTime, endTime, callFrames, sourceCodeLocation);
     
    3535    this._eventType = eventType;
    3636    this._details = details || "";
     37    this._profile = profile || null;
    3738};
    3839
     
    253254    },
    254255
     256    get profile()
     257    {
     258        return this._profile;
     259    },
     260
    255261    saveIdentityToCookie: function(cookie)
    256262    {
  • trunk/Source/WebInspectorUI/UserInterface/ScriptTimelineView.js

    r162527 r163142  
    2929
    3030    this.navigationSidebarTreeOutline.onselect = this._treeElementSelected.bind(this);
    31     this.navigationSidebarTreeOutline.element.classList.add(WebInspector.NavigationSidebarPanel.HideDisclosureButtonsStyleClassName);
    3231    this.navigationSidebarTreeOutline.element.classList.add(WebInspector.ScriptTimelineView.TreeOutlineStyleClassName);
    3332
    34     var columns = {eventType: {}, location: {}, startTime: {}, duration: {}};
    35 
    36     columns.eventType.title = WebInspector.UIString("Type");
    37     columns.eventType.width = "15%";
    38     columns.eventType.scopeBar = WebInspector.TimelineDataGrid.createColumnScopeBar("script", WebInspector.ScriptTimelineRecord.EventType);
    39     columns.eventType.hidden = true;
     33    var columns = {location: {}, callCount: {}, startTime: {}, totalTime: {}, selfTime: {}, averageTime: {}};
    4034
    4135    columns.location.title = WebInspector.UIString("Location");
    4236    columns.location.width = "15%";
     37
     38    columns.callCount.title = WebInspector.UIString("Calls");
     39    columns.callCount.width = "5%";
     40    columns.callCount.aligned = "right";
    4341
    4442    columns.startTime.title = WebInspector.UIString("Start Time");
     
    4745    columns.startTime.sort = "ascending";
    4846
    49     columns.duration.title = WebInspector.UIString("Duration");
    50     columns.duration.width = "10%";
    51     columns.duration.aligned = "right";
     47    columns.totalTime.title = WebInspector.UIString("Total Time");
     48    columns.totalTime.width = "10%";
     49    columns.totalTime.aligned = "right";
     50
     51    columns.selfTime.title = WebInspector.UIString("Self Time");
     52    columns.selfTime.width = "10%";
     53    columns.selfTime.aligned = "right";
     54
     55    columns.averageTime.title = WebInspector.UIString("Average Time");
     56    columns.averageTime.width = "10%";
     57    columns.averageTime.aligned = "right";
    5258
    5359    for (var column in columns)
    5460        columns[column].sortable = true;
    5561
    56     this._dataGrid = new WebInspector.ScriptTimelineDataGrid(this.navigationSidebarTreeOutline, columns);
     62    this._dataGrid = new WebInspector.ScriptTimelineDataGrid(this.navigationSidebarTreeOutline, columns, this);
    5763    this._dataGrid.addEventListener(WebInspector.TimelineDataGrid.Event.FiltersDidChange, this._dataGridFiltersDidChange, this);
    5864    this._dataGrid.addEventListener(WebInspector.DataGrid.Event.SelectedNodeChanged, this._dataGridNodeSelected, this);
     
    101107        this._dataGrid.updateLayout();
    102108
     109        if (this.startTime !== this._oldStartTime || this.endTime !== this._oldEndTime) {
     110            var dataGridNode = this._dataGrid.children[0];
     111            while (dataGridNode) {
     112                dataGridNode.rangeStartTime = this.startTime;
     113                dataGridNode.rangeEndTime = this.endTime;
     114                if (dataGridNode.revealed)
     115                    dataGridNode.refreshIfNeeded();
     116                dataGridNode = dataGridNode.traverseNextNode(false, null, true);
     117            }
     118
     119            this._oldStartTime = this.startTime;
     120            this._oldEndTime = this.endTime;
     121        }
     122
    103123        this._processPendingRecords();
     124    },
     125
     126    get selectionPathComponents()
     127    {
     128        var dataGridNode = this._dataGrid.selectedNode;
     129        if (!dataGridNode)
     130            return null;
     131
     132        var pathComponents = [];
     133
     134        while (dataGridNode && !dataGridNode.root) {
     135            var treeElement = this._dataGrid.treeElementForDataGridNode(dataGridNode);
     136            console.assert(treeElement);
     137            if (!treeElement)
     138                break;
     139
     140            if (treeElement.hidden)
     141                return null;
     142
     143            var pathComponent = new WebInspector.GeneralTreeElementPathComponent(treeElement);
     144            pathComponent.addEventListener(WebInspector.HierarchicalPathComponent.Event.SiblingWasSelected, this.treeElementPathComponentSelected, this);
     145            pathComponents.unshift(pathComponent);
     146            dataGridNode = dataGridNode.parent;
     147        }
     148
     149        return pathComponents;
    104150    },
    105151
     
    126172    },
    127173
     174    dataGridNodeForTreeElement: function(treeElement)
     175    {
     176        if (treeElement instanceof WebInspector.ProfileNodeTreeElement)
     177            return new WebInspector.ProfileNodeDataGridNode(treeElement.profileNode, this.zeroTime, this.startTime, this.endTime);
     178        return null;
     179    },
     180
     181    populateProfileNodeTreeElement: function(treeElement)
     182    {
     183        var zeroTime = this.zeroTime;
     184        var startTime = this.startTime;
     185        var endTime = this.endTime;
     186
     187        for (var childProfileNode of treeElement.profileNode.childNodes) {
     188            var profileNodeTreeElement = new WebInspector.ProfileNodeTreeElement(childProfileNode, this);
     189            var profileNodeDataGridNode = new WebInspector.ProfileNodeDataGridNode(childProfileNode, zeroTime, startTime, endTime);
     190            this._dataGrid.addRowInSortOrder(profileNodeTreeElement, profileNodeDataGridNode, treeElement);
     191        }
     192    },
     193
    128194    // Private
    129195
     
    134200
    135201        for (var scriptTimelineRecord of this._pendingRecords) {
    136             var treeElement = new WebInspector.TimelineRecordTreeElement(scriptTimelineRecord, WebInspector.SourceCodeLocation.NameStyle.Short, true);
    137             var dataGridNode = new WebInspector.ScriptTimelineDataGridNode(scriptTimelineRecord, this.zeroTime);
     202            var rootNodes = [];
     203            if (scriptTimelineRecord.profile) {
     204                // FIXME: Support using the bottom-up tree once it is implemented.
     205                rootNodes = scriptTimelineRecord.profile.topDownRootNodes;
     206
     207                // If there is only one node, promote its children. The TimelineRecordTreeElement already reflects the root
     208                // node in this case (e.g. a "Load Event Dispatched" record with an "onload" root profile node).
     209                // FIXME: Only do this for the top-down mode. Doing this for bottom-up would be incorrect.
     210                if (rootNodes.length === 1)
     211                    rootNodes = rootNodes[0].childNodes;
     212            }
     213
     214            var zeroTime = this.zeroTime;
     215            var treeElement = new WebInspector.TimelineRecordTreeElement(scriptTimelineRecord, WebInspector.SourceCodeLocation.NameStyle.Short, rootNodes.length);
     216            var dataGridNode = new WebInspector.ScriptTimelineDataGridNode(scriptTimelineRecord, zeroTime);
    138217
    139218            this._dataGrid.addRowInSortOrder(treeElement, dataGridNode);
     219
     220            var startTime = this.startTime;
     221            var endTime = this.endTime;
     222
     223            for (var profileNode of rootNodes) {
     224                var profileNodeTreeElement = new WebInspector.ProfileNodeTreeElement(profileNode, this);
     225                var profileNodeDataGridNode = new WebInspector.ProfileNodeDataGridNode(profileNode, zeroTime, startTime, endTime);
     226                this._dataGrid.addRowInSortOrder(profileNodeTreeElement, profileNodeDataGridNode, treeElement);
     227            }
    140228        }
    141229
     
    174262            return;
    175263
    176         if (!(treeElement instanceof WebInspector.TimelineRecordTreeElement)) {
     264        var sourceCodeLocation = null;
     265        if (treeElement instanceof WebInspector.TimelineRecordTreeElement)
     266            sourceCodeLocation = treeElement.record.sourceCodeLocation;
     267        else if (treeElement instanceof WebInspector.ProfileNodeTreeElement)
     268            sourceCodeLocation = treeElement.profileNode.sourceCodeLocation;
     269        else
    177270            console.error("Unknown tree element selected.");
    178             return;
    179         }
    180 
    181         if (!treeElement.record.sourceCodeLocation) {
     271
     272        if (!sourceCodeLocation) {
    182273            WebInspector.timelineSidebarPanel.showTimelineView(WebInspector.TimelineRecord.Type.Script);
    183274            return;
    184275        }
    185276
    186         WebInspector.resourceSidebarPanel.showOriginalOrFormattedSourceCodeLocation(treeElement.record.sourceCodeLocation);
     277        WebInspector.resourceSidebarPanel.showOriginalOrFormattedSourceCodeLocation(sourceCodeLocation);
    187278    }
    188279};
  • trunk/Source/WebInspectorUI/UserInterface/TimelineContentView.js

    r162561 r163142  
    202202        }
    203203
     204        if (treeElement instanceof WebInspector.ProfileNodeTreeElement) {
     205            var profileNode = treeElement.profileNode;
     206            for (var call of profileNode.calls) {
     207                if (checkTimeBounds(call.startTime, call.endTime))
     208                    return true;
     209            }
     210
     211            return false;
     212        }
     213
    204214        if (treeElement instanceof WebInspector.TimelineRecordTreeElement) {
    205215            var record = treeElement.record;
  • trunk/Source/WebInspectorUI/UserInterface/TimelineDataGrid.js

    r162560 r163142  
    2424 */
    2525
    26 WebInspector.TimelineDataGrid = function(treeOutline, columns, editCallback, deleteCallback)
     26WebInspector.TimelineDataGrid = function(treeOutline, columns, delegate, editCallback, deleteCallback)
    2727{
    2828    WebInspector.DataGrid.call(this, columns, editCallback, deleteCallback);
    2929
    30     this._treeOutlineDataGridSynchronizer = new WebInspector.TreeOutlineDataGridSynchronizer(treeOutline, this);
     30    this._treeOutlineDataGridSynchronizer = new WebInspector.TreeOutlineDataGridSynchronizer(treeOutline, this, delegate);
    3131
    3232    this.element.classList.add(WebInspector.TimelineDataGrid.StyleClassName);
     
    166166    },
    167167
    168     addRowInSortOrder: function(treeElement, dataGridNode)
     168    addRowInSortOrder: function(treeElement, dataGridNode, parentElement)
    169169    {
    170170        this._treeOutlineDataGridSynchronizer.associate(treeElement, dataGridNode);
    171171
    172         var treeOutline = this._treeOutlineDataGridSynchronizer.treeOutline;
     172        parentElement = parentElement || this._treeOutlineDataGridSynchronizer.treeOutline;
     173        parentNode = parentElement.root ? this : this._treeOutlineDataGridSynchronizer.dataGridNodeForTreeElement(parentElement);
     174
     175        console.assert(parentNode);
    173176
    174177        if (this.sortColumnIdentifier) {
    175             var insertionIndex = insertionIndexForObjectInListSortedByFunction(dataGridNode, this.children, this._sortComparator.bind(this));
    176 
    177             // Insert into the tree outline, which will cause the synchronizer to insert into the data grid.
    178             treeOutline.insertChild(treeElement, insertionIndex);
     178            var insertionIndex = insertionIndexForObjectInListSortedByFunction(dataGridNode, parentNode.children, this._sortComparator.bind(this));
     179
     180            // Insert into the parent, which will cause the synchronizer to insert into the data grid.
     181            parentElement.insertChild(treeElement, insertionIndex);
    179182        } else {
    180             // Append to the tree outline, which will cause the synchronizer to append to the data grid.
    181             treeOutline.appendChild(treeElement);
     183            // Append to the parent, which will cause the synchronizer to append to the data grid.
     184            parentElement.appendChild(treeElement);
    182185        }
    183186    },
     
    263266        this._ignoreSelectionEvent = true;
    264267
    265         var dataGridNodes = this.children.slice();
    266         dataGridNodes.sort(this._sortComparator.bind(this));
    267 
    268268        this._treeOutlineDataGridSynchronizer.enabled = false;
    269269
    270270        var treeOutline = this._treeOutlineDataGridSynchronizer.treeOutline;
    271 
    272         this.removeChildren();
    273         treeOutline.removeChildren();
    274 
    275         for (var dataGridNode of dataGridNodes) {
    276             var treeElement = this._treeOutlineDataGridSynchronizer.treeElementForDataGridNode(dataGridNode);
    277             console.assert(treeElement);
    278 
    279             treeOutline.appendChild(treeElement);
    280             this.appendChild(dataGridNode);
    281 
    282             // Adding the tree element back to the tree outline subjects it to filters.
    283             // Make sure we keep the hidden state in-sync while the synchronizer is disabled.
    284             dataGridNode.element.classList.toggle("hidden", treeElement.hidden);
     271        if (treeOutline.selectedTreeElement)
     272            treeOutline.selectedTreeElement.deselect(true);
     273
     274        // Collect parent nodes that need their children sorted. So this in two phases since
     275        // traverseNextNode would get confused if we sort the tree while traversing it.
     276        var parentDataGridNodes = [this];
     277        var currentDataGridNode = this.children[0];
     278        while (currentDataGridNode) {
     279            if (currentDataGridNode.children.length)
     280                parentDataGridNodes.push(currentDataGridNode);
     281            currentDataGridNode = currentDataGridNode.traverseNextNode(false, null, true);
     282        }
     283
     284        // Sort the children of collected parent nodes.
     285        for (var parentDataGridNode of parentDataGridNodes) {
     286            var parentTreeElement = parentDataGridNode === this ? treeOutline : this._treeOutlineDataGridSynchronizer.treeElementForDataGridNode(parentDataGridNode);
     287            console.assert(parentTreeElement);
     288
     289            var childDataGridNodes = parentDataGridNode.children.slice();
     290
     291            parentDataGridNode.removeChildren();
     292            parentTreeElement.removeChildren();
     293
     294            childDataGridNodes.sort(this._sortComparator.bind(this));
     295
     296            for (var dataGridNode of childDataGridNodes) {
     297                var treeElement = this._treeOutlineDataGridSynchronizer.treeElementForDataGridNode(dataGridNode);
     298                console.assert(treeElement);
     299
     300                parentTreeElement.appendChild(treeElement);
     301                parentDataGridNode.appendChild(dataGridNode);
     302
     303                // Adding the tree element back to the tree outline subjects it to filters.
     304                // Make sure we keep the hidden state in-sync while the synchronizer is disabled.
     305                dataGridNode.element.classList.toggle("hidden", treeElement.hidden);
     306            }
    285307        }
    286308
  • trunk/Source/WebInspectorUI/UserInterface/TimelineDataGridNode.js

    r162681 r163142  
    2424 */
    2525
    26 WebInspector.TimelineDataGridNode = function(graphOnly, graphDataSource)
     26WebInspector.TimelineDataGridNode = function(graphOnly, graphDataSource, hasChildren)
    2727{
    28     WebInspector.DataGridNode.call(this, {});
     28    WebInspector.DataGridNode.call(this, {}, hasChildren);
    2929
    3030    this._graphOnly = graphOnly || false;
     
    6969        WebInspector.DataGridNode.prototype.collapse.call(this);
    7070
    71         if (!this.revealed)
     71        if (!this._graphDataSource || !this.revealed)
    7272            return;
    7373
     
    8080        WebInspector.DataGridNode.prototype.expand.call(this);
    8181
    82         if (!this.revealed)
     82        if (!this._graphDataSource || !this.revealed)
    8383            return;
    8484
  • trunk/Source/WebInspectorUI/UserInterface/TimelineRecord.js

    r162416 r163142  
    5454WebInspector.TimelineRecord.SourceCodeLocationLineCookieKey = "timeline-record-source-code-location-line";
    5555WebInspector.TimelineRecord.SourceCodeLocationColumnCookieKey = "timeline-record-source-code-location-column";
    56 WebInspector.TimelineRecord.SourceCodeURLCookieKey = "timeline-record-source-code-url";
    5756WebInspector.TimelineRecord.TypeCookieKey = "timeline-record-type";
    5857
  • trunk/Source/WebInspectorUI/UserInterface/TreeOutlineDataGridSynchronizer.js

    r162415 r163142  
    2424 */
    2525
    26 WebInspector.TreeOutlineDataGridSynchronizer = function(treeOutline, dataGrid)
     26WebInspector.TreeOutlineDataGridSynchronizer = function(treeOutline, dataGrid, delegate)
    2727{
    2828    WebInspector.Object.call(this);
     
    3030    this._treeOutline = treeOutline;
    3131    this._dataGrid = dataGrid;
     32    this._delegate = delegate || null;
    3233    this._enabled = true;
    3334
     
    102103    },
    103104
     105    get delegate()
     106    {
     107        return this._delegate;
     108    },
     109
    104110    get enabled()
    105111    {
     
    137143    dataGridNodeForTreeElement: function(treeElement)
    138144    {
    139         return treeElement.__dataGridNode || null;
     145        if (treeElement.__dataGridNode)
     146            return treeElement.__dataGridNode;
     147
     148        if (typeof this._delegate.dataGridNodeForTreeElement === "function") {
     149            var dataGridNode = this._delegate.dataGridNodeForTreeElement(treeElement);
     150            if (dataGridNode)
     151                this.associate(treeElement, dataGridNode);
     152            return dataGridNode;
     153        }
     154
     155        return null;
    140156    },
    141157
     
    220236            return;
    221237
    222         var dataGridNode = treeElement.__dataGridNode;
     238        var dataGridNode = this.dataGridNodeForTreeElement(treeElement);
    223239        console.assert(dataGridNode);
    224240
  • trunk/Source/WebInspectorUI/UserInterface/Utilities.js

    r161689 r163142  
    776776        var ms = seconds * 1000;
    777777
     778        if (higherResolution && Math.abs(ms) < 10)
     779            return WebInspector.UIString("%.3fms").format(ms);
     780        else if (Math.abs(ms) < 10)
     781            return WebInspector.UIString("%.2fms").format(ms);
     782
    778783        if (higherResolution && Math.abs(ms) < 100)
    779784            return WebInspector.UIString("%.2fms").format(ms);
Note: See TracChangeset for help on using the changeset viewer.