9130504662120468bc6ff9212a630c5722b15ccd
[WebKit-https.git] / Source / WebInspectorUI / UserInterface / Views / ScriptTimelineDataGridNode.js
1 /*
2  * Copyright (C) 2013, 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.ScriptTimelineDataGridNode = class ScriptTimelineDataGridNode extends WebInspector.TimelineDataGridNode
27 {
28     constructor(scriptTimelineRecord, baseStartTime, rangeStartTime, rangeEndTime)
29     {
30         super(false, null);
31
32         this._record = scriptTimelineRecord;
33         this._baseStartTime = baseStartTime || 0;
34         this._rangeStartTime = rangeStartTime || 0;
35         this._rangeEndTime = typeof rangeEndTime === "number" ? rangeEndTime : Infinity;
36     }
37
38     // Public
39
40     get record()
41     {
42         return this._record;
43     }
44
45     get records()
46     {
47         return [this._record];
48     }
49
50     get baseStartTime()
51     {
52         return this._baseStartTime;
53     }
54
55     get rangeStartTime()
56     {
57         return this._rangeStartTime;
58     }
59
60     get rangeEndTime()
61     {
62         return this._rangeEndTime;
63     }
64
65     get data()
66     {
67         if (!this._cachedData) {
68             var startTime = this._record.startTime;
69             var duration = this._record.startTime + this._record.duration - startTime;
70             var callFrameOrSourceCodeLocation = this._record.initiatorCallFrame || this._record.sourceCodeLocation;
71
72             // COMPATIBILITY (iOS 8): Profiles included per-call information and can be finely partitioned.
73             if (this._record.profile) {
74                 var oneRootNode = this._record.profile.topDownRootNodes[0];
75                 if (oneRootNode && oneRootNode.calls) {
76                     startTime = Math.max(this._rangeStartTime, this._record.startTime);
77                     duration = Math.min(this._record.startTime + this._record.duration, this._rangeEndTime) - startTime;
78                 }
79             }
80
81             this._cachedData = {
82                 eventType: this._record.eventType,
83                 startTime,
84                 selfTime: duration,
85                 totalTime: duration,
86                 averageTime: duration,
87                 callCount: this._record.callCountOrSamples,
88                 location: callFrameOrSourceCodeLocation,
89             };
90         }
91
92         return this._cachedData;
93     }
94
95     updateRangeTimes(startTime, endTime)
96     {
97         var oldRangeStartTime = this._rangeStartTime;
98         var oldRangeEndTime = this._rangeEndTime;
99
100         if (oldRangeStartTime === startTime && oldRangeEndTime === endTime)
101             return;
102
103         this._rangeStartTime = startTime;
104         this._rangeEndTime = endTime;
105
106         // If we have no duration the range does not matter.
107         if (!this._record.duration)
108             return;
109
110         // We only need a refresh if the new range time changes the visible portion of this record.
111         var recordStart = this._record.startTime;
112         var recordEnd = this._record.startTime + this._record.duration;
113         var oldStartBoundary = Number.constrain(oldRangeStartTime, recordStart, recordEnd);
114         var oldEndBoundary = Number.constrain(oldRangeEndTime, recordStart, recordEnd);
115         var newStartBoundary = Number.constrain(startTime, recordStart, recordEnd);
116         var newEndBoundary = Number.constrain(endTime, recordStart, recordEnd);
117
118         if (oldStartBoundary !== newStartBoundary || oldEndBoundary !== newEndBoundary)
119             this.needsRefresh();
120     }
121
122     createCellContent(columnIdentifier, cell)
123     {
124         var value = this.data[columnIdentifier];
125
126         switch (columnIdentifier) {
127         case "name":
128             cell.classList.add(WebInspector.TimelineTabContentView.iconClassNameForRecord(this._record));
129             return this._createNameCellDocumentFragment();
130
131         case "startTime":
132             return isNaN(value) ? emDash : Number.secondsToString(value - this._baseStartTime, true);
133
134         case "selfTime":
135         case "totalTime":
136         case "averageTime":
137             return isNaN(value) ? emDash : Number.secondsToString(value, true);
138
139         case "callCount":
140             return isNaN(value) ? emDash : value;
141         }
142
143         return super.createCellContent(columnIdentifier, cell);
144     }
145
146     // Private
147
148     _createNameCellDocumentFragment(cellElement)
149     {
150         let fragment = document.createDocumentFragment();
151         let mainTitle = WebInspector.TimelineTabContentView.displayNameForRecord(this._record);
152         fragment.append(mainTitle);
153
154         if (this._record.eventType === WebInspector.ScriptTimelineRecord.EventType.TimerInstalled) {
155             let subtitleElement = document.createElement("span");
156             subtitleElement.classList.add("subtitle");
157             fragment.append(subtitleElement);
158
159             let timeoutString = Number.secondsToString(this._record.details.timeout / 1000);
160             if (this._record.details.repeating)
161                 subtitleElement.textContent = WebInspector.UIString("%s interval").format(timeoutString);
162             else
163                 subtitleElement.textContent = WebInspector.UIString("%s delay").format(timeoutString);
164         }
165
166         return fragment;
167     }
168 };