e8c659208edf9f36ba773803157e186bdacc3f72
[WebKit-https.git] / Source / WebInspectorUI / UserInterface / Models / ScriptTimelineRecord.js
1 /*
2  * Copyright (C) 2013 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.ScriptTimelineRecord = class ScriptTimelineRecord extends WebInspector.TimelineRecord
27 {
28     constructor(eventType, startTime, endTime, callFrames, sourceCodeLocation, details, profilePayload)
29     {
30         super(WebInspector.TimelineRecord.Type.Script, startTime, endTime, callFrames, sourceCodeLocation);
31
32         console.assert(eventType);
33
34         if (eventType in WebInspector.ScriptTimelineRecord.EventType)
35             eventType = WebInspector.ScriptTimelineRecord.EventType[eventType];
36
37         this._eventType = eventType;
38         this._details = details || "";
39         this._profilePayload = profilePayload || null;
40         this._profile = null;
41     }
42
43     // Public
44
45     get eventType()
46     {
47         return this._eventType;
48     }
49
50     get details()
51     {
52         return this._details;
53     }
54
55     get profile()
56     {
57         this._initializeProfileFromPayload();
58         return this._profile;
59     }
60
61     isGarbageCollection()
62     {
63         return this._eventType === WebInspector.ScriptTimelineRecord.EventType.GarbageCollected;
64     }
65
66     saveIdentityToCookie(cookie)
67     {
68         super.saveIdentityToCookie(cookie);
69
70         cookie[WebInspector.ScriptTimelineRecord.EventTypeCookieKey] = this._eventType;
71         cookie[WebInspector.ScriptTimelineRecord.DetailsCookieKey] = this._details;
72     }
73
74     // Private
75
76     _initializeProfileFromPayload(payload)
77     {
78         if (this._profile || !this._profilePayload)
79             return;
80
81         var payload = this._profilePayload;
82         this._profilePayload = undefined;
83
84         console.assert(payload.rootNodes instanceof Array);
85
86         function profileNodeFromPayload(nodePayload)
87         {
88             console.assert("id" in nodePayload);
89
90             if (nodePayload.url) {
91                 var sourceCode = WebInspector.frameResourceManager.resourceForURL(nodePayload.url);
92                 if (!sourceCode)
93                     sourceCode = WebInspector.debuggerManager.scriptsForURL(nodePayload.url)[0];
94
95                 // The lineNumber is 1-based, but we expect 0-based.
96                 var lineNumber = nodePayload.lineNumber - 1;
97
98                 var sourceCodeLocation = sourceCode ? sourceCode.createLazySourceCodeLocation(lineNumber, nodePayload.columnNumber) : null;
99             }
100
101             var isProgramCode = nodePayload.functionName === "(program)";
102             var isAnonymousFunction = nodePayload.functionName === "(anonymous function)";
103
104             var type = isProgramCode ? WebInspector.ProfileNode.Type.Program : WebInspector.ProfileNode.Type.Function;
105             var functionName = !isProgramCode && !isAnonymousFunction && nodePayload.functionName !== "(unknown)" ? nodePayload.functionName : null;
106
107             // COMPATIBILITY (iOS 8): Timeline.CPUProfileNodes used to include an array of complete
108             // call information instead of the aggregated "callInfo" data.
109             var calls = null;
110             if ("calls" in nodePayload) {
111                 console.assert(nodePayload.calls instanceof Array);
112                 calls = nodePayload.calls.map(profileNodeCallFromPayload);
113             }
114
115             return new WebInspector.ProfileNode(nodePayload.id, type, functionName, sourceCodeLocation, nodePayload.callInfo, calls, nodePayload.children);
116         }
117
118         function profileNodeCallFromPayload(nodeCallPayload)
119         {
120             console.assert("startTime" in nodeCallPayload);
121             console.assert("totalTime" in nodeCallPayload);
122
123             var startTime = WebInspector.timelineManager.computeElapsedTime(nodeCallPayload.startTime);
124
125             return new WebInspector.ProfileNodeCall(startTime, nodeCallPayload.totalTime);
126         }
127
128         var rootNodes = payload.rootNodes;
129
130         // Iterate over the node tree using a stack. Doing this recursively can easily cause a stack overflow.
131         // We traverse the profile in post-order and convert the payloads in place until we get back to the root.
132         var stack = [{parent: {children: rootNodes}, index: 0, root: true}];
133         while (stack.length) {
134             var entry = stack.lastValue;
135
136             if (entry.index < entry.parent.children.length) {
137                 var childNodePayload = entry.parent.children[entry.index];
138                 if (childNodePayload.children && childNodePayload.children.length)
139                     stack.push({parent: childNodePayload, index: 0});
140
141                 ++entry.index;
142             } else {
143                 if (!entry.root)
144                     entry.parent.children = entry.parent.children.map(profileNodeFromPayload);
145                 else
146                     rootNodes = rootNodes.map(profileNodeFromPayload);
147
148                 stack.pop();
149             }
150         }
151
152         this._profile = new WebInspector.Profile(rootNodes);
153     }
154 };
155
156 WebInspector.ScriptTimelineRecord.EventType = {
157     ScriptEvaluated: "script-timeline-record-script-evaluated",
158     EventDispatched: "script-timeline-record-event-dispatch",
159     ProbeSampleRecorded: "script-timeline-record-probe-sample-recorded",
160     TimerFired: "script-timeline-record-timer-fired",
161     TimerInstalled: "script-timeline-record-timer-installed",
162     TimerRemoved: "script-timeline-record-timer-removed",
163     AnimationFrameFired: "script-timeline-record-animation-frame-fired",
164     AnimationFrameRequested: "script-timeline-record-animation-frame-requested",
165     AnimationFrameCanceled: "script-timeline-record-animation-frame-canceled",
166     ConsoleProfileRecorded: "script-timeline-record-console-profile-recorded",
167     GarbageCollected: "script-timeline-record-garbage-collected"
168 };
169
170 WebInspector.ScriptTimelineRecord.EventType.displayName = function(eventType, details, includeDetailsInformationInMainTitle)
171 {
172     if (details && !WebInspector.ScriptTimelineRecord._eventDisplayNames) {
173         // These display names are not localized because they closely represent
174         // the real API name, just with word spaces and Title Case.
175
176         var nameMap = new Map;
177         nameMap.set("DOMActivate", "DOM Activate");
178         nameMap.set("DOMCharacterDataModified", "DOM Character Data Modified");
179         nameMap.set("DOMContentLoaded", "DOM Content Loaded");
180         nameMap.set("DOMFocusIn", "DOM Focus In");
181         nameMap.set("DOMFocusOut", "DOM Focus Out");
182         nameMap.set("DOMNodeInserted", "DOM Node Inserted");
183         nameMap.set("DOMNodeInsertedIntoDocument", "DOM Node Inserted Into Document");
184         nameMap.set("DOMNodeRemoved", "DOM Node Removed");
185         nameMap.set("DOMNodeRemovedFromDocument", "DOM Node Removed From Document");
186         nameMap.set("DOMSubtreeModified", "DOM Sub-Tree Modified");
187         nameMap.set("addsourcebuffer", "Add Source Buffer");
188         nameMap.set("addstream", "Add Stream");
189         nameMap.set("addtrack", "Add Track");
190         nameMap.set("animationend", "Animation End");
191         nameMap.set("animationiteration", "Animation Iteration");
192         nameMap.set("animationstart", "Animation Start");
193         nameMap.set("audioend", "Audio End");
194         nameMap.set("audioprocess", "Audio Process");
195         nameMap.set("audiostart", "Audio Start");
196         nameMap.set("beforecopy", "Before Copy");
197         nameMap.set("beforecut", "Before Cut");
198         nameMap.set("beforeload", "Before Load");
199         nameMap.set("beforepaste", "Before Paste");
200         nameMap.set("beforeunload", "Before Unload");
201         nameMap.set("canplay", "Can Play");
202         nameMap.set("canplaythrough", "Can Play Through");
203         nameMap.set("chargingchange", "Charging Change");
204         nameMap.set("chargingtimechange", "Charging Time Change");
205         nameMap.set("compositionend", "Composition End");
206         nameMap.set("compositionstart", "Composition Start");
207         nameMap.set("compositionupdate", "Composition Update");
208         nameMap.set("contextmenu", "Context Menu");
209         nameMap.set("cuechange", "Cue Change");
210         nameMap.set("datachannel", "Data Channel");
211         nameMap.set("dblclick", "Double Click");
212         nameMap.set("devicemotion", "Device Motion");
213         nameMap.set("deviceorientation", "Device Orientation");
214         nameMap.set("dischargingtimechange", "Discharging Time Change");
215         nameMap.set("dragend", "Drag End");
216         nameMap.set("dragenter", "Drag Enter");
217         nameMap.set("dragleave", "Drag Leave");
218         nameMap.set("dragover", "Drag Over");
219         nameMap.set("dragstart", "Drag Start");
220         nameMap.set("durationchange", "Duration Change");
221         nameMap.set("focusin", "Focus In");
222         nameMap.set("focusout", "Focus Out");
223         nameMap.set("gesturechange", "Gesture Change");
224         nameMap.set("gestureend", "Gesture End");
225         nameMap.set("gesturescrollend", "Gesture Scroll End");
226         nameMap.set("gesturescrollstart", "Gesture Scroll Start");
227         nameMap.set("gesturescrollupdate", "Gesture Scroll Update");
228         nameMap.set("gesturestart", "Gesture Start");
229         nameMap.set("gesturetap", "Gesture Tap");
230         nameMap.set("gesturetapdown", "Gesture Tap Down");
231         nameMap.set("hashchange", "Hash Change");
232         nameMap.set("icecandidate", "ICE Candidate");
233         nameMap.set("iceconnectionstatechange", "ICE Connection State Change");
234         nameMap.set("keydown", "Key Down");
235         nameMap.set("keypress", "Key Press");
236         nameMap.set("keyup", "Key Up");
237         nameMap.set("levelchange", "Level Change");
238         nameMap.set("loadeddata", "Loaded Data");
239         nameMap.set("loadedmetadata", "Loaded Metadata");
240         nameMap.set("loadend", "Load End");
241         nameMap.set("loadingdone", "Loading Done");
242         nameMap.set("loadstart", "Load Start");
243         nameMap.set("mousedown", "Mouse Down");
244         nameMap.set("mouseenter", "Mouse Enter");
245         nameMap.set("mouseleave", "Mouse Leave");
246         nameMap.set("mousemove", "Mouse Move");
247         nameMap.set("mouseout", "Mouse Out");
248         nameMap.set("mouseover", "Mouse Over");
249         nameMap.set("mouseup", "Mouse Up");
250         nameMap.set("mousewheel", "Mouse Wheel");
251         nameMap.set("negotiationneeded", "Negotiation Needed");
252         nameMap.set("nomatch", "No Match");
253         nameMap.set("noupdate", "No Update");
254         nameMap.set("orientationchange", "Orientation Change");
255         nameMap.set("overflowchanged", "Overflow Changed");
256         nameMap.set("pagehide", "Page Hide");
257         nameMap.set("pageshow", "Page Show");
258         nameMap.set("popstate", "Pop State");
259         nameMap.set("ratechange", "Rate Change");
260         nameMap.set("readystatechange", "Ready State Change");
261         nameMap.set("removesourcebuffer", "Remove Source Buffer");
262         nameMap.set("removestream", "Remove Stream");
263         nameMap.set("removetrack", "Remove Track");
264         nameMap.set("securitypolicyviolation", "Security Policy Violation");
265         nameMap.set("selectionchange", "Selection Change");
266         nameMap.set("selectstart", "Select Start");
267         nameMap.set("signalingstatechange", "Signaling State Change");
268         nameMap.set("soundend", "Sound End");
269         nameMap.set("soundstart", "Sound Start");
270         nameMap.set("sourceclose", "Source Close");
271         nameMap.set("sourceended", "Source Ended");
272         nameMap.set("sourceopen", "Source Open");
273         nameMap.set("speechend", "Speech End");
274         nameMap.set("speechstart", "Speech Start");
275         nameMap.set("textInput", "Text Input");
276         nameMap.set("timeupdate", "Time Update");
277         nameMap.set("tonechange", "Tone Change");
278         nameMap.set("touchcancel", "Touch Cancel");
279         nameMap.set("touchend", "Touch End");
280         nameMap.set("touchmove", "Touch Move");
281         nameMap.set("touchstart", "Touch Start");
282         nameMap.set("transitionend", "Transition End");
283         nameMap.set("updateend", "Update End");
284         nameMap.set("updateready", "Update Ready");
285         nameMap.set("updatestart", "Update Start");
286         nameMap.set("upgradeneeded", "Upgrade Needed");
287         nameMap.set("versionchange", "Version Change");
288         nameMap.set("visibilitychange", "Visibility Change");
289         nameMap.set("volumechange", "Volume Change");
290         nameMap.set("webglcontextcreationerror", "WebGL Context Creation Error");
291         nameMap.set("webglcontextlost", "WebGL Context Lost");
292         nameMap.set("webglcontextrestored", "WebGL Context Restored");
293         nameMap.set("webkitAnimationEnd", "Animation End");
294         nameMap.set("webkitAnimationIteration", "Animation Iteration");
295         nameMap.set("webkitAnimationStart", "Animation Start");
296         nameMap.set("webkitBeforeTextInserted", "Before Text Inserted");
297         nameMap.set("webkitEditableContentChanged", "Editable Content Changed");
298         nameMap.set("webkitTransitionEnd", "Transition End");
299         nameMap.set("webkitaddsourcebuffer", "Add Source Buffer");
300         nameMap.set("webkitbeginfullscreen", "Begin Fullscreen");
301         nameMap.set("webkitcurrentplaybacktargetiswirelesschanged", "Current Playback Target Is Wireless Changed");
302         nameMap.set("webkitdeviceproximity", "Device Proximity");
303         nameMap.set("webkitendfullscreen", "End Fullscreen");
304         nameMap.set("webkitfullscreenchange", "Fullscreen Change");
305         nameMap.set("webkitfullscreenerror", "Fullscreen Error");
306         nameMap.set("webkitkeyadded", "Key Added");
307         nameMap.set("webkitkeyerror", "Key Error");
308         nameMap.set("webkitkeymessage", "Key Message");
309         nameMap.set("webkitneedkey", "Need Key");
310         nameMap.set("webkitnetworkinfochange", "Network Info Change");
311         nameMap.set("webkitplaybacktargetavailabilitychanged", "Playback Target Availability Changed");
312         nameMap.set("webkitpointerlockchange", "Pointer Lock Change");
313         nameMap.set("webkitpointerlockerror", "Pointer Lock Error");
314         nameMap.set("webkitregionlayoutupdate", "Region Layout Update");    // COMPATIBILITY (iOS 7): regionLayoutUpdated was removed and replaced by regionOversetChanged.
315         nameMap.set("webkitregionoversetchange", "Region Overset Change");
316         nameMap.set("webkitremovesourcebuffer", "Remove Source Buffer");
317         nameMap.set("webkitresourcetimingbufferfull", "Resource Timing Buffer Full");
318         nameMap.set("webkitsourceclose", "Source Close");
319         nameMap.set("webkitsourceended", "Source Ended");
320         nameMap.set("webkitsourceopen", "Source Open");
321         nameMap.set("webkitspeechchange", "Speech Change");
322         nameMap.set("writeend", "Write End");
323         nameMap.set("writestart", "Write Start");
324
325         WebInspector.ScriptTimelineRecord._eventDisplayNames = nameMap;
326     }
327
328     switch(eventType) {
329     case WebInspector.ScriptTimelineRecord.EventType.ScriptEvaluated:
330         return WebInspector.UIString("Script Evaluated");
331     case WebInspector.ScriptTimelineRecord.EventType.EventDispatched:
332         if (details && (details instanceof String || typeof details === "string")) {
333             var eventDisplayName = WebInspector.ScriptTimelineRecord._eventDisplayNames.get(details) || details.capitalize();
334             return WebInspector.UIString("%s Event Dispatched").format(eventDisplayName);
335         }
336
337         return WebInspector.UIString("Event Dispatched");
338     case WebInspector.ScriptTimelineRecord.EventType.ProbeSampleRecorded:
339         return WebInspector.UIString("Probe Sample Recorded");
340     case WebInspector.ScriptTimelineRecord.EventType.ConsoleProfileRecorded:
341         if (details && (details instanceof String || typeof details === "string"))
342             return WebInspector.UIString("ā€œ%sā€ Profile Recorded").format(details);
343         return WebInspector.UIString("Console Profile Recorded");
344     case WebInspector.ScriptTimelineRecord.EventType.GarbageCollected:
345         console.assert(details);
346         if (details && (details instanceof WebInspector.GarbageCollection) && includeDetailsInformationInMainTitle) {
347             switch (details.type) {
348             case WebInspector.GarbageCollection.Type.Partial:
349                 return WebInspector.UIString("Partial Garbage Collection");
350             case WebInspector.GarbageCollection.Type.Full:
351                 return WebInspector.UIString("Full Garbage Collection");
352             }
353         }
354         return WebInspector.UIString("Garbage Collection");
355     case WebInspector.ScriptTimelineRecord.EventType.TimerFired:
356         if (details && includeDetailsInformationInMainTitle)
357             return WebInspector.UIString("Timer %s Fired").format(details);
358         return WebInspector.UIString("Timer Fired");
359     case WebInspector.ScriptTimelineRecord.EventType.TimerInstalled:
360         if (details && includeDetailsInformationInMainTitle)
361             return WebInspector.UIString("Timer %s Installed").format(details);
362         return WebInspector.UIString("Timer Installed");
363     case WebInspector.ScriptTimelineRecord.EventType.TimerRemoved:
364         if (details && includeDetailsInformationInMainTitle)
365             return WebInspector.UIString("Timer %s Removed").format(details);
366         return WebInspector.UIString("Timer Removed");
367     case WebInspector.ScriptTimelineRecord.EventType.AnimationFrameFired:
368         return WebInspector.UIString("Animation Frame Fired");
369     case WebInspector.ScriptTimelineRecord.EventType.AnimationFrameRequested:
370         return WebInspector.UIString("Animation Frame Requested");
371     case WebInspector.ScriptTimelineRecord.EventType.AnimationFrameCanceled:
372         return WebInspector.UIString("Animation Frame Canceled");
373     }
374 };
375
376 WebInspector.ScriptTimelineRecord.TypeIdentifier = "script-timeline-record";
377 WebInspector.ScriptTimelineRecord.EventTypeCookieKey = "script-timeline-record-event-type";
378 WebInspector.ScriptTimelineRecord.DetailsCookieKey = "script-timeline-record-details";