diff options
Diffstat (limited to 'Source/WebInspectorUI/UserInterface/Models/ScriptTimelineRecord.js')
-rw-r--r-- | Source/WebInspectorUI/UserInterface/Models/ScriptTimelineRecord.js | 418 |
1 files changed, 418 insertions, 0 deletions
diff --git a/Source/WebInspectorUI/UserInterface/Models/ScriptTimelineRecord.js b/Source/WebInspectorUI/UserInterface/Models/ScriptTimelineRecord.js new file mode 100644 index 000000000..4a4231d82 --- /dev/null +++ b/Source/WebInspectorUI/UserInterface/Models/ScriptTimelineRecord.js @@ -0,0 +1,418 @@ +/* + * Copyright (C) 2013 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +WebInspector.ScriptTimelineRecord = class ScriptTimelineRecord extends WebInspector.TimelineRecord +{ + constructor(eventType, startTime, endTime, callFrames, sourceCodeLocation, details, profilePayload) + { + super(WebInspector.TimelineRecord.Type.Script, startTime, endTime, callFrames, sourceCodeLocation); + + console.assert(eventType); + + if (eventType in WebInspector.ScriptTimelineRecord.EventType) + eventType = WebInspector.ScriptTimelineRecord.EventType[eventType]; + + this._eventType = eventType; + this._details = details || ""; + this._profilePayload = profilePayload || null; + this._profile = null; + + // COMPATIBILITY(iOS 9): Before the ScriptProfilerAgent we did not have sample data. Return NaN to match old behavior. + if (!window.ScriptProfilerAgent) + this._callCountOrSamples = NaN; + else { + // NOTE: _callCountOrSamples is being treated as the number of samples. + this._callCountOrSamples = 0; + } + } + + // Public + + get eventType() + { + return this._eventType; + } + + get details() + { + return this._details; + } + + get profile() + { + this._initializeProfileFromPayload(); + return this._profile; + } + + get callCountOrSamples() + { + return this._callCountOrSamples; + } + + isGarbageCollection() + { + return this._eventType === WebInspector.ScriptTimelineRecord.EventType.GarbageCollected; + } + + saveIdentityToCookie(cookie) + { + super.saveIdentityToCookie(cookie); + + cookie[WebInspector.ScriptTimelineRecord.EventTypeCookieKey] = this._eventType; + cookie[WebInspector.ScriptTimelineRecord.DetailsCookieKey] = this._details; + } + + get profilePayload() + { + return this._profilePayload; + } + + set profilePayload(payload) + { + this._profilePayload = payload; + } + + // Private + + _initializeProfileFromPayload(payload) + { + if (this._profile || !this._profilePayload) + return; + + var payload = this._profilePayload; + this._profilePayload = undefined; + + console.assert(payload.rootNodes instanceof Array); + + function profileNodeFromPayload(nodePayload) + { + console.assert("id" in nodePayload); + + if (nodePayload.url) { + var sourceCode = WebInspector.frameResourceManager.resourceForURL(nodePayload.url); + if (!sourceCode) + sourceCode = WebInspector.debuggerManager.scriptsForURL(nodePayload.url, WebInspector.assumingMainTarget())[0]; + + // The lineNumber is 1-based, but we expect 0-based. + var lineNumber = nodePayload.lineNumber - 1; + + var sourceCodeLocation = sourceCode ? sourceCode.createLazySourceCodeLocation(lineNumber, nodePayload.columnNumber) : null; + } + + var isProgramCode = nodePayload.functionName === "(program)"; + var isAnonymousFunction = nodePayload.functionName === "(anonymous function)"; + + var type = isProgramCode ? WebInspector.ProfileNode.Type.Program : WebInspector.ProfileNode.Type.Function; + var functionName = !isProgramCode && !isAnonymousFunction && nodePayload.functionName !== "(unknown)" ? nodePayload.functionName : null; + + // COMPATIBILITY (iOS 8): Timeline.CPUProfileNodes used to include an array of complete + // call information instead of the aggregated "callInfo" data. + var calls = null; + if ("calls" in nodePayload) { + console.assert(nodePayload.calls instanceof Array); + calls = nodePayload.calls.map(profileNodeCallFromPayload); + } + + return new WebInspector.ProfileNode(nodePayload.id, type, functionName, sourceCodeLocation, nodePayload.callInfo, calls, nodePayload.children); + } + + function profileNodeCallFromPayload(nodeCallPayload) + { + console.assert("startTime" in nodeCallPayload); + console.assert("totalTime" in nodeCallPayload); + + var startTime = WebInspector.timelineManager.computeElapsedTime(nodeCallPayload.startTime); + + return new WebInspector.ProfileNodeCall(startTime, nodeCallPayload.totalTime); + } + + var rootNodes = payload.rootNodes; + + // Iterate over the node tree using a stack. Doing this recursively can easily cause a stack overflow. + // We traverse the profile in post-order and convert the payloads in place until we get back to the root. + var stack = [{parent: {children: rootNodes}, index: 0, root: true}]; + while (stack.length) { + var entry = stack.lastValue; + + if (entry.index < entry.parent.children.length) { + var childNodePayload = entry.parent.children[entry.index]; + if (childNodePayload.children && childNodePayload.children.length) + stack.push({parent: childNodePayload, index: 0}); + + ++entry.index; + } else { + if (!entry.root) + entry.parent.children = entry.parent.children.map(profileNodeFromPayload); + else + rootNodes = rootNodes.map(profileNodeFromPayload); + + stack.pop(); + } + } + + // COMPATIBILITY (iOS 9): We only do this when we have ScriptProfilerAgent because before that we didn't have a Sampling Profiler. + if (window.ScriptProfilerAgent) { + for (let i = 0; i < rootNodes.length; i++) + this._callCountOrSamples += rootNodes[i].callInfo.callCount; + } + + this._profile = new WebInspector.Profile(rootNodes); + } +}; + +WebInspector.ScriptTimelineRecord.EventType = { + ScriptEvaluated: "script-timeline-record-script-evaluated", + APIScriptEvaluated: "script-timeline-record-api-script-evaluated", + MicrotaskDispatched: "script-timeline-record-microtask-dispatched", + EventDispatched: "script-timeline-record-event-dispatched", + ProbeSampleRecorded: "script-timeline-record-probe-sample-recorded", + TimerFired: "script-timeline-record-timer-fired", + TimerInstalled: "script-timeline-record-timer-installed", + TimerRemoved: "script-timeline-record-timer-removed", + AnimationFrameFired: "script-timeline-record-animation-frame-fired", + AnimationFrameRequested: "script-timeline-record-animation-frame-requested", + AnimationFrameCanceled: "script-timeline-record-animation-frame-canceled", + ConsoleProfileRecorded: "script-timeline-record-console-profile-recorded", + GarbageCollected: "script-timeline-record-garbage-collected", +}; + +WebInspector.ScriptTimelineRecord.EventType.displayName = function(eventType, details, includeDetailsInMainTitle) +{ + if (details && !WebInspector.ScriptTimelineRecord._eventDisplayNames) { + // These display names are not localized because they closely represent + // the real API name, just with word spaces and Title Case. + + var nameMap = new Map; + nameMap.set("DOMActivate", "DOM Activate"); + nameMap.set("DOMCharacterDataModified", "DOM Character Data Modified"); + nameMap.set("DOMContentLoaded", "DOM Content Loaded"); + nameMap.set("DOMFocusIn", "DOM Focus In"); + nameMap.set("DOMFocusOut", "DOM Focus Out"); + nameMap.set("DOMNodeInserted", "DOM Node Inserted"); + nameMap.set("DOMNodeInsertedIntoDocument", "DOM Node Inserted Into Document"); + nameMap.set("DOMNodeRemoved", "DOM Node Removed"); + nameMap.set("DOMNodeRemovedFromDocument", "DOM Node Removed From Document"); + nameMap.set("DOMSubtreeModified", "DOM Sub-Tree Modified"); + nameMap.set("addsourcebuffer", "Add Source Buffer"); + nameMap.set("addstream", "Add Stream"); + nameMap.set("addtrack", "Add Track"); + nameMap.set("animationend", "Animation End"); + nameMap.set("animationiteration", "Animation Iteration"); + nameMap.set("animationstart", "Animation Start"); + nameMap.set("audioend", "Audio End"); + nameMap.set("audioprocess", "Audio Process"); + nameMap.set("audiostart", "Audio Start"); + nameMap.set("beforecopy", "Before Copy"); + nameMap.set("beforecut", "Before Cut"); + nameMap.set("beforeload", "Before Load"); + nameMap.set("beforepaste", "Before Paste"); + nameMap.set("beforeunload", "Before Unload"); + nameMap.set("canplay", "Can Play"); + nameMap.set("canplaythrough", "Can Play Through"); + nameMap.set("chargingchange", "Charging Change"); + nameMap.set("chargingtimechange", "Charging Time Change"); + nameMap.set("compositionend", "Composition End"); + nameMap.set("compositionstart", "Composition Start"); + nameMap.set("compositionupdate", "Composition Update"); + nameMap.set("contextmenu", "Context Menu"); + nameMap.set("cuechange", "Cue Change"); + nameMap.set("datachannel", "Data Channel"); + nameMap.set("dblclick", "Double Click"); + nameMap.set("devicemotion", "Device Motion"); + nameMap.set("deviceorientation", "Device Orientation"); + nameMap.set("dischargingtimechange", "Discharging Time Change"); + nameMap.set("dragend", "Drag End"); + nameMap.set("dragenter", "Drag Enter"); + nameMap.set("dragleave", "Drag Leave"); + nameMap.set("dragover", "Drag Over"); + nameMap.set("dragstart", "Drag Start"); + nameMap.set("durationchange", "Duration Change"); + nameMap.set("focusin", "Focus In"); + nameMap.set("focusout", "Focus Out"); + nameMap.set("gesturechange", "Gesture Change"); + nameMap.set("gestureend", "Gesture End"); + nameMap.set("gesturescrollend", "Gesture Scroll End"); + nameMap.set("gesturescrollstart", "Gesture Scroll Start"); + nameMap.set("gesturescrollupdate", "Gesture Scroll Update"); + nameMap.set("gesturestart", "Gesture Start"); + nameMap.set("gesturetap", "Gesture Tap"); + nameMap.set("gesturetapdown", "Gesture Tap Down"); + nameMap.set("hashchange", "Hash Change"); + nameMap.set("icecandidate", "ICE Candidate"); + nameMap.set("iceconnectionstatechange", "ICE Connection State Change"); + nameMap.set("keydown", "Key Down"); + nameMap.set("keypress", "Key Press"); + nameMap.set("keyup", "Key Up"); + nameMap.set("levelchange", "Level Change"); + nameMap.set("loadeddata", "Loaded Data"); + nameMap.set("loadedmetadata", "Loaded Metadata"); + nameMap.set("loadend", "Load End"); + nameMap.set("loadingdone", "Loading Done"); + nameMap.set("loadstart", "Load Start"); + nameMap.set("mousedown", "Mouse Down"); + nameMap.set("mouseenter", "Mouse Enter"); + nameMap.set("mouseleave", "Mouse Leave"); + nameMap.set("mousemove", "Mouse Move"); + nameMap.set("mouseout", "Mouse Out"); + nameMap.set("mouseover", "Mouse Over"); + nameMap.set("mouseup", "Mouse Up"); + nameMap.set("mousewheel", "Mouse Wheel"); + nameMap.set("negotiationneeded", "Negotiation Needed"); + nameMap.set("nomatch", "No Match"); + nameMap.set("noupdate", "No Update"); + nameMap.set("orientationchange", "Orientation Change"); + nameMap.set("overflowchanged", "Overflow Changed"); + nameMap.set("pagehide", "Page Hide"); + nameMap.set("pageshow", "Page Show"); + nameMap.set("popstate", "Pop State"); + nameMap.set("ratechange", "Rate Change"); + nameMap.set("readystatechange", "Ready State Change"); + nameMap.set("removesourcebuffer", "Remove Source Buffer"); + nameMap.set("removestream", "Remove Stream"); + nameMap.set("removetrack", "Remove Track"); + nameMap.set("resize", "Resize"); + nameMap.set("securitypolicyviolation", "Security Policy Violation"); + nameMap.set("selectionchange", "Selection Change"); + nameMap.set("selectstart", "Select Start"); + nameMap.set("signalingstatechange", "Signaling State Change"); + nameMap.set("soundend", "Sound End"); + nameMap.set("soundstart", "Sound Start"); + nameMap.set("sourceclose", "Source Close"); + nameMap.set("sourceended", "Source Ended"); + nameMap.set("sourceopen", "Source Open"); + nameMap.set("speechend", "Speech End"); + nameMap.set("speechstart", "Speech Start"); + nameMap.set("textInput", "Text Input"); + nameMap.set("timeupdate", "Time Update"); + nameMap.set("tonechange", "Tone Change"); + nameMap.set("touchcancel", "Touch Cancel"); + nameMap.set("touchend", "Touch End"); + nameMap.set("touchmove", "Touch Move"); + nameMap.set("touchstart", "Touch Start"); + nameMap.set("transitionend", "Transition End"); + nameMap.set("updateend", "Update End"); + nameMap.set("updateready", "Update Ready"); + nameMap.set("updatestart", "Update Start"); + nameMap.set("upgradeneeded", "Upgrade Needed"); + nameMap.set("versionchange", "Version Change"); + nameMap.set("visibilitychange", "Visibility Change"); + nameMap.set("volumechange", "Volume Change"); + nameMap.set("webglcontextcreationerror", "WebGL Context Creation Error"); + nameMap.set("webglcontextlost", "WebGL Context Lost"); + nameMap.set("webglcontextrestored", "WebGL Context Restored"); + nameMap.set("webkitAnimationEnd", "Animation End"); + nameMap.set("webkitAnimationIteration", "Animation Iteration"); + nameMap.set("webkitAnimationStart", "Animation Start"); + nameMap.set("webkitBeforeTextInserted", "Before Text Inserted"); + nameMap.set("webkitEditableContentChanged", "Editable Content Changed"); + nameMap.set("webkitTransitionEnd", "Transition End"); + nameMap.set("webkitaddsourcebuffer", "Add Source Buffer"); + nameMap.set("webkitbeginfullscreen", "Begin Fullscreen"); + nameMap.set("webkitcurrentplaybacktargetiswirelesschanged", "Current Playback Target Is Wireless Changed"); + nameMap.set("webkitdeviceproximity", "Device Proximity"); + nameMap.set("webkitendfullscreen", "End Fullscreen"); + nameMap.set("webkitfullscreenchange", "Fullscreen Change"); + nameMap.set("webkitfullscreenerror", "Fullscreen Error"); + nameMap.set("webkitkeyadded", "Key Added"); + nameMap.set("webkitkeyerror", "Key Error"); + nameMap.set("webkitkeymessage", "Key Message"); + nameMap.set("webkitneedkey", "Need Key"); + nameMap.set("webkitnetworkinfochange", "Network Info Change"); + nameMap.set("webkitplaybacktargetavailabilitychanged", "Playback Target Availability Changed"); + nameMap.set("webkitpointerlockchange", "Pointer Lock Change"); + nameMap.set("webkitpointerlockerror", "Pointer Lock Error"); + nameMap.set("webkitregionlayoutupdate", "Region Layout Update"); // COMPATIBILITY (iOS 7): regionLayoutUpdated was removed and replaced by regionOversetChanged. + nameMap.set("webkitregionoversetchange", "Region Overset Change"); + nameMap.set("webkitremovesourcebuffer", "Remove Source Buffer"); + nameMap.set("webkitresourcetimingbufferfull", "Resource Timing Buffer Full"); + nameMap.set("webkitsourceclose", "Source Close"); + nameMap.set("webkitsourceended", "Source Ended"); + nameMap.set("webkitsourceopen", "Source Open"); + nameMap.set("webkitspeechchange", "Speech Change"); + nameMap.set("writeend", "Write End"); + nameMap.set("writestart", "Write Start"); + + WebInspector.ScriptTimelineRecord._eventDisplayNames = nameMap; + } + + switch (eventType) { + case WebInspector.ScriptTimelineRecord.EventType.ScriptEvaluated: + case WebInspector.ScriptTimelineRecord.EventType.APIScriptEvaluated: + return WebInspector.UIString("Script Evaluated"); + case WebInspector.ScriptTimelineRecord.EventType.MicrotaskDispatched: + return WebInspector.UIString("Microtask Dispatched"); + case WebInspector.ScriptTimelineRecord.EventType.EventDispatched: + if (details && (details instanceof String || typeof details === "string")) { + var eventDisplayName = WebInspector.ScriptTimelineRecord._eventDisplayNames.get(details) || details.capitalize(); + return WebInspector.UIString("%s Event Dispatched").format(eventDisplayName); + } + return WebInspector.UIString("Event Dispatched"); + case WebInspector.ScriptTimelineRecord.EventType.ProbeSampleRecorded: + return WebInspector.UIString("Probe Sample Recorded"); + case WebInspector.ScriptTimelineRecord.EventType.ConsoleProfileRecorded: + if (details && (details instanceof String || typeof details === "string")) + return WebInspector.UIString("ā%sā Profile Recorded").format(details); + return WebInspector.UIString("Console Profile Recorded"); + case WebInspector.ScriptTimelineRecord.EventType.GarbageCollected: + console.assert(details); + if (details && (details instanceof WebInspector.GarbageCollection) && includeDetailsInMainTitle) { + switch (details.type) { + case WebInspector.GarbageCollection.Type.Partial: + return WebInspector.UIString("Partial Garbage Collection"); + case WebInspector.GarbageCollection.Type.Full: + return WebInspector.UIString("Full Garbage Collection"); + } + } + return WebInspector.UIString("Garbage Collection"); + case WebInspector.ScriptTimelineRecord.EventType.TimerFired: + if (details && includeDetailsInMainTitle) + return WebInspector.UIString("Timer %s Fired").format(details); + return WebInspector.UIString("Timer Fired"); + case WebInspector.ScriptTimelineRecord.EventType.TimerInstalled: + if (details && includeDetailsInMainTitle) + return WebInspector.UIString("Timer %s Installed").format(details.timerId); + return WebInspector.UIString("Timer Installed"); + case WebInspector.ScriptTimelineRecord.EventType.TimerRemoved: + if (details && includeDetailsInMainTitle) + return WebInspector.UIString("Timer %s Removed").format(details); + return WebInspector.UIString("Timer Removed"); + case WebInspector.ScriptTimelineRecord.EventType.AnimationFrameFired: + if (details && includeDetailsInMainTitle) + return WebInspector.UIString("Animation Frame %s Fired").format(details); + return WebInspector.UIString("Animation Frame Fired"); + case WebInspector.ScriptTimelineRecord.EventType.AnimationFrameRequested: + if (details && includeDetailsInMainTitle) + return WebInspector.UIString("Animation Frame %s Requested").format(details); + return WebInspector.UIString("Animation Frame Requested"); + case WebInspector.ScriptTimelineRecord.EventType.AnimationFrameCanceled: + if (details && includeDetailsInMainTitle) + return WebInspector.UIString("Animation Frame %s Canceled").format(details); + return WebInspector.UIString("Animation Frame Canceled"); + } +}; + +WebInspector.ScriptTimelineRecord.TypeIdentifier = "script-timeline-record"; +WebInspector.ScriptTimelineRecord.EventTypeCookieKey = "script-timeline-record-event-type"; +WebInspector.ScriptTimelineRecord.DetailsCookieKey = "script-timeline-record-details"; |