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.TimelineRecording = function() 27{ 28 WebInspector.Object.call(this); 29 30 this._timelines = new Map; 31 this._timelines.set(WebInspector.TimelineRecord.Type.Network, new WebInspector.NetworkTimeline); 32 this._timelines.set(WebInspector.TimelineRecord.Type.Script, new WebInspector.Timeline); 33 this._timelines.set(WebInspector.TimelineRecord.Type.Layout, new WebInspector.Timeline); 34 35 for (var timeline of this._timelines.values()) 36 timeline.addEventListener(WebInspector.Timeline.Event.TimesUpdated, this._timelineTimesUpdated, this); 37 38 this.reset(true); 39}; 40 41WebInspector.TimelineRecording.Event = { 42 Reset: "timeline-recording-reset", 43 SourceCodeTimelineAdded: "timeline-recording-source-code-timeline-added", 44 TimesUpdated: "timeline-recording-times-updated" 45}; 46 47WebInspector.TimelineRecording.prototype = { 48 constructor: WebInspector.TimelineRecording, 49 __proto__: WebInspector.Object.prototype, 50 51 // Public 52 53 get timelines() 54 { 55 return this._timelines; 56 }, 57 58 get startTime() 59 { 60 return this._startTime; 61 }, 62 63 get endTime() 64 { 65 return this._endTime; 66 }, 67 68 reset: function(suppressEvents) 69 { 70 this._sourceCodeTimelinesMap = new Map; 71 this._eventMarkers = []; 72 this._startTime = NaN; 73 this._endTime = NaN; 74 75 for (var timeline of this._timelines.values()) 76 timeline.reset(suppressEvents); 77 78 if (!suppressEvents) { 79 this.dispatchEventToListeners(WebInspector.TimelineRecording.Event.Reset); 80 this.dispatchEventToListeners(WebInspector.TimelineRecording.Event.TimesUpdated); 81 } 82 }, 83 84 sourceCodeTimelinesForSourceCode: function(sourceCode) 85 { 86 var timelines = this._sourceCodeTimelinesMap.get(sourceCode); 87 if (!timelines) 88 return []; 89 return timelines.values(); 90 }, 91 92 addEventMarker: function(eventMarker) 93 { 94 this._eventMarkers.push(eventMarker); 95 }, 96 97 addRecord: function(record) 98 { 99 // Add the record to the global timeline by type. 100 this._timelines.get(record.type).addRecord(record); 101 102 // Network records don't have source code timelines. 103 if (record.type === WebInspector.TimelineRecord.Type.Network) 104 return; 105 106 // Add the record to the source code timelines. 107 var activeMainResource = WebInspector.frameResourceManager.mainFrame.provisionalMainResource || WebInspector.frameResourceManager.mainFrame.mainResource; 108 var sourceCode = record.sourceCodeLocation ? record.sourceCodeLocation.sourceCode : activeMainResource; 109 110 var sourceCodeTimelines = this._sourceCodeTimelinesMap.get(sourceCode); 111 if (!sourceCodeTimelines) { 112 sourceCodeTimelines = new Map; 113 this._sourceCodeTimelinesMap.set(sourceCode, sourceCodeTimelines); 114 } 115 116 var newTimeline = false; 117 var key = this._keyForRecord(record); 118 var sourceCodeTimeline = sourceCodeTimelines.get(key); 119 if (!sourceCodeTimeline) { 120 sourceCodeTimeline = new WebInspector.SourceCodeTimeline(sourceCode, record.sourceCodeLocation, record.type, record.eventType); 121 sourceCodeTimelines.set(key, sourceCodeTimeline); 122 newTimeline = true; 123 } 124 125 sourceCodeTimeline.addRecord(record); 126 127 if (newTimeline) 128 this.dispatchEventToListeners(WebInspector.TimelineRecording.Event.SourceCodeTimelineAdded, {sourceCodeTimeline: sourceCodeTimeline}); 129 }, 130 131 // Private 132 133 _keyForRecord: function(record) 134 { 135 var key = record.type; 136 if (record instanceof WebInspector.ScriptTimelineRecord || record instanceof WebInspector.LayoutTimelineRecord) 137 key += ":" + record.eventType; 138 if (record instanceof WebInspector.ScriptTimelineRecord && record.eventType === WebInspector.ScriptTimelineRecord.EventType.EventDispatched) 139 key += ":" + record.details; 140 if (record.sourceCodeLocation) 141 key += ":" + record.sourceCodeLocation.lineNumber + ":" + record.sourceCodeLocation.columnNumber; 142 return key; 143 }, 144 145 _timelineTimesUpdated: function(event) 146 { 147 var timeline = event.target; 148 var changed = false; 149 150 if (isNaN(this._startTime) || timeline.startTime < this._startTime) { 151 this._startTime = timeline.startTime; 152 changed = true; 153 } 154 155 if (isNaN(this._endTime) || this._endTime < timeline.endTime) { 156 this._endTime = timeline.endTime; 157 changed = true; 158 } 159 160 if (changed) 161 this.dispatchEventToListeners(WebInspector.TimelineRecording.Event.TimesUpdated); 162 } 163}; 164