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