Web Inspector: Provide UIString descriptions to improve localizations
[WebKit-https.git] / Source / WebInspectorUI / UserInterface / Models / RenderingFrameTimelineRecord.js
1 /*
2  * Copyright (C) 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 WI.RenderingFrameTimelineRecord = class RenderingFrameTimelineRecord extends WI.TimelineRecord
27 {
28     constructor(startTime, endTime)
29     {
30         super(WI.TimelineRecord.Type.RenderingFrame, startTime, endTime);
31
32         this._durationByTaskType = new Map;
33         this._frameIndex = -1;
34     }
35
36     // Static
37
38     static resetFrameIndex()
39     {
40         WI.RenderingFrameTimelineRecord._nextFrameIndex = 0;
41     }
42
43     static displayNameForTaskType(taskType)
44     {
45         switch (taskType) {
46         case WI.RenderingFrameTimelineRecord.TaskType.Script:
47             return WI.UIString("Script");
48         case WI.RenderingFrameTimelineRecord.TaskType.Layout:
49             return WI.repeatedUIString.timelineRecordLayout();
50         case WI.RenderingFrameTimelineRecord.TaskType.Paint:
51             return WI.repeatedUIString.timelineRecordPaint();
52         case WI.RenderingFrameTimelineRecord.TaskType.Other:
53             return WI.UIString("Other");
54         }
55     }
56
57     static taskTypeForTimelineRecord(record)
58     {
59         switch (record.type) {
60         case WI.TimelineRecord.Type.Script:
61             return WI.RenderingFrameTimelineRecord.TaskType.Script;
62         case WI.TimelineRecord.Type.Layout:
63             if (record.eventType === WI.LayoutTimelineRecord.EventType.Paint || record.eventType === WI.LayoutTimelineRecord.EventType.Composite)
64                 return WI.RenderingFrameTimelineRecord.TaskType.Paint;
65             return WI.RenderingFrameTimelineRecord.TaskType.Layout;
66         default:
67             console.error("Unsupported timeline record type: " + record.type);
68             return null;
69         }
70     }
71
72     // Import / Export
73
74     static fromJSON(json)
75     {
76         let {startTime, endTime} = json;
77         let record = new WI.RenderingFrameTimelineRecord(startTime, endTime);
78         record.setupFrameIndex();
79         return record;
80     }
81
82     toJSON()
83     {
84         // FIXME: durationByTaskType data cannot be calculated if this does not have children.
85
86         return {
87             type: this.type,
88             startTime: this.startTime,
89             endTime: this.endTime,
90         };
91     }
92
93     // Public
94
95     get frameIndex()
96     {
97         return this._frameIndex;
98     }
99
100     get frameNumber()
101     {
102         return this._frameIndex + 1;
103     }
104
105     setupFrameIndex()
106     {
107         console.assert(this._frameIndex === -1, "Frame index should only be set once.");
108         if (this._frameIndex >= 0)
109             return;
110         this._frameIndex = WI.RenderingFrameTimelineRecord._nextFrameIndex++;
111     }
112
113     durationForTask(taskType)
114     {
115         if (this._durationByTaskType.has(taskType))
116             return this._durationByTaskType.get(taskType);
117
118         var duration;
119         if (taskType === WI.RenderingFrameTimelineRecord.TaskType.Other)
120             duration = this._calculateDurationRemainder();
121         else {
122             duration = this.children.reduce(function(previousValue, currentValue) {
123                 if (taskType !== WI.RenderingFrameTimelineRecord.taskTypeForTimelineRecord(currentValue))
124                     return previousValue;
125
126                 var currentDuration = currentValue.duration;
127                 if (currentValue.usesActiveStartTime)
128                     currentDuration -= currentValue.inactiveDuration;
129                 return previousValue + currentDuration;
130             }, 0);
131
132             if (taskType === WI.RenderingFrameTimelineRecord.TaskType.Script) {
133                 // Layout events synchronously triggered from JavaScript must be subtracted from the total
134                 // script time, to prevent the time from being counted twice.
135                 duration -= this.children.reduce(function(previousValue, currentValue) {
136                     if (currentValue.type === WI.TimelineRecord.Type.Layout && (currentValue.sourceCodeLocation || currentValue.callFrames))
137                         return previousValue + currentValue.duration;
138                     return previousValue;
139                 }, 0);
140             }
141         }
142
143         this._durationByTaskType.set(taskType, duration);
144         return duration;
145     }
146
147     // Private
148
149     _calculateDurationRemainder()
150     {
151         return Object.keys(WI.RenderingFrameTimelineRecord.TaskType).reduce((previousValue, key) => {
152             let taskType = WI.RenderingFrameTimelineRecord.TaskType[key];
153             if (taskType === WI.RenderingFrameTimelineRecord.TaskType.Other)
154                 return previousValue;
155             return previousValue - this.durationForTask(taskType);
156         }, this.duration);
157     }
158 };
159
160 WI.RenderingFrameTimelineRecord.TaskType = {
161     Script: "rendering-frame-timeline-record-script",
162     Layout: "rendering-frame-timeline-record-layout",
163     Paint: "rendering-frame-timeline-record-paint",
164     Other: "rendering-frame-timeline-record-other"
165 };
166
167 WI.RenderingFrameTimelineRecord.TypeIdentifier = "rendering-frame-timeline-record";
168
169 WI.RenderingFrameTimelineRecord._nextFrameIndex = 0;