711b1f5bd1464bda50498d004fcf3c76673aec6a
[WebKit-https.git] / Source / WebInspectorUI / UserInterface / Views / ProfileNodeDataGridNode.js
1 /*
2  * Copyright (C) 2014, 2015 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23  * THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 WebInspector.ProfileNodeDataGridNode = class ProfileNodeDataGridNode extends WebInspector.TimelineDataGridNode
27 {
28     constructor(profileNode, baseStartTime, rangeStartTime, rangeEndTime)
29     {
30         var hasChildren = !!profileNode.childNodes.length;
31
32         super(false, null, hasChildren);
33
34         this._profileNode = profileNode;
35         this._baseStartTime = baseStartTime || 0;
36         this._rangeStartTime = rangeStartTime || 0;
37         this._rangeEndTime = typeof rangeEndTime === "number" ? rangeEndTime : Infinity;
38
39         this._cachedData = null;
40     }
41
42     // Public
43
44     get profileNode()
45     {
46         return this._profileNode;
47     }
48
49     get records()
50     {
51         return null;
52     }
53
54     get baseStartTime()
55     {
56         return this._baseStartTime;
57     }
58
59     get rangeStartTime()
60     {
61         return this._rangeStartTime;
62     }
63
64     get rangeEndTime()
65     {
66         return this._rangeEndTime;
67     }
68
69     get data()
70     {
71         if (!this._cachedData) {
72             this._cachedData = this._profileNode.computeCallInfoForTimeRange(this._rangeStartTime, this._rangeEndTime);
73             this._cachedData.name = this._titleForProfileNode();
74             this._cachedData.location = this._profileNode.sourceCodeLocation;
75         }
76
77         return this._cachedData;
78     }
79
80     updateRangeTimes(startTime, endTime)
81     {
82         var oldRangeStartTime = this._rangeStartTime;
83         var oldRangeEndTime = this._rangeEndTime;
84
85         if (oldRangeStartTime === startTime && oldRangeEndTime === endTime)
86             return;
87
88         this._rangeStartTime = startTime;
89         this._rangeEndTime = endTime;
90
91         // We only need a refresh if the new range time changes the visible portion of this record.
92         var profileStart = this._profileNode.startTime;
93         var profileEnd = this._profileNode.endTime;
94         var oldStartBoundary = Number.constrain(oldRangeStartTime, profileStart, profileEnd);
95         var oldEndBoundary = Number.constrain(oldRangeEndTime, profileStart, profileEnd);
96         var newStartBoundary = Number.constrain(startTime, profileStart, profileEnd);
97         var newEndBoundary = Number.constrain(endTime, profileStart, profileEnd);
98
99         if (oldStartBoundary !== newStartBoundary || oldEndBoundary !== newEndBoundary)
100             this.needsRefresh();
101     }
102
103     refresh()
104     {
105         this._data = this._profileNode.computeCallInfoForTimeRange(this._rangeStartTime, this._rangeEndTime);
106         this._data.location = this._profileNode.sourceCodeLocation;
107
108         super.refresh();
109     }
110
111     createCellContent(columnIdentifier, cell)
112     {
113         var value = this.data[columnIdentifier];
114
115         switch (columnIdentifier) {
116         case "name":
117             cell.classList.add(this._iconClassNameForProfileNode());
118             return value;
119
120         case "startTime":
121             return isNaN(value) ? emDash : Number.secondsToString(value - this._baseStartTime, true);
122
123         case "selfTime":
124         case "totalTime":
125         case "averageTime":
126             return isNaN(value) ? emDash : Number.secondsToString(value, true);
127         }
128
129         return super.createCellContent(columnIdentifier, cell);
130     }
131
132     // Private
133
134     _iconClassNameForProfileNode()
135     {
136         let className;
137         switch (this._profileNode.type) {
138         case WebInspector.ProfileNode.Type.Function:
139             className = WebInspector.CallFrameView.FunctionIconStyleClassName;
140             if (!this._profileNode.sourceCodeLocation)
141                 className = WebInspector.CallFrameView.NativeIconStyleClassName;
142             break;
143         case WebInspector.ProfileNode.Type.Program:
144             className = WebInspector.TimelineRecordTreeElement.EvaluatedRecordIconStyleClass;
145             break;
146         }
147
148         console.assert(className);
149
150         // This is more than likely an event listener function with an "on" prefix and it is
151         // as long or longer than the shortest event listener name -- "oncut".
152         if (this._profileNode.functionName && this._profileNode.functionName.startsWith("on") && this._profileNode.functionName.length >= 5)
153             className = WebInspector.CallFrameView.EventListenerIconStyleClassName;
154
155         return className;
156     }
157
158     _titleForProfileNode()
159     {
160         let title = this._profileNode.functionName;
161         if (!name) {
162             switch (this._profileNode.type) {
163             case WebInspector.ProfileNode.Type.Function:
164                 title = WebInspector.UIString("(anonymous function)");
165                 break;
166             case WebInspector.ProfileNode.Type.Program:
167                 title = WebInspector.UIString("(program)");
168                 break;
169             default:
170                 title = WebInspector.UIString("(anonymous function)");
171                 console.error("Unknown ProfileNode type: " + this._profileNode.type);
172             }
173         }
174
175         return title;
176     }
177 };