Diff
Modified: trunk/Source/WebInspectorUI/ChangeLog (181625 => 181626)
--- trunk/Source/WebInspectorUI/ChangeLog 2015-03-17 08:41:19 UTC (rev 181625)
+++ trunk/Source/WebInspectorUI/ChangeLog 2015-03-17 08:43:30 UTC (rev 181626)
@@ -1,3 +1,109 @@
+2015-03-17 Matt Baker <[email protected]>
+
+ Web Inspector: Show rendering frames (and FPS) in Layout and Rendering timeline
+ https://bugs.webkit.org/show_bug.cgi?id=142029
+
+ Reviewed by Timothy Hatcher.
+
+ Add UI for showing runloop records and their child records as a frame histogram,
+ with the recording time on the x-axis and the frame duration on the y-axis. Each frame
+ is comprised of colored regions representing the time spent in various activities (script,
+ layout, etc).
+
+ Eventually the Frames timeline will replace the Layout & Rendering timeline. Until the views
+ for the new timeline are finalized the Layout & Rendering timeline will remain in place.
+
+ * Localizations/en.lproj/localizedStrings.js:
+ * UserInterface/Main.html:
+ New string and files.
+
+ * UserInterface/Controllers/TimelineManager.js:
+ (WebInspector.TimelineManager.prototype.eventRecorded):
+ (WebInspector.TimelineManager.prototype.pageDidLoad):
+ (WebInspector.TimelineManager.prototype._processNestedRecords):
+ (WebInspector.TimelineManager.prototype._processRecord):
+ (WebInspector.TimelineManager.prototype._processEvent):
+ (WebInspector.TimelineManager.prototype._loadNewRecording):
+ (WebInspector.TimelineManager.prototype.eventRecorded.processRecord): Deleted.
+ Added support for new runloop record type and nested record handling.
+
+ * UserInterface/Images/Frames.png: Added.
+ * UserInterface/Images/[email protected]: Added.
+ * UserInterface/Images/FramesLarge.png: Added.
+ * UserInterface/Images/[email protected]: Added.
+ New images for runloop timeline overview graph and runloop tree records.
+
+ * UserInterface/Models/RunLoopTimelineRecord.js: Added.
+ (WebInspector.RunLoopTimelineRecord):
+ (WebInspector.RunLoopTimelineRecord.prototype.get children):
+ (WebInspector.RunLoopTimelineRecord.prototype.get durationRemainder):
+ (WebInspector.RunLoopTimelineRecord.prototype.durationForRecords.get var):
+ Extends TimelineRecord to add child records and subframe duration details.
+
+ * UserInterface/Models/Timeline.js:
+ (WebInspector.Timeline.prototype.get displayName):
+ (WebInspector.Timeline.prototype.get iconClassName):
+ New UI strings and icons.
+
+ * UserInterface/Models/TimelineRecord.js:
+ * UserInterface/Views/ContentView.js:
+ (WebInspector.ContentView):
+ * UserInterface/Views/LayoutTimelineView.js:
+ (WebInspector.LayoutTimelineView.prototype._layoutTimelineRecordAdded):
+ * UserInterface/Views/TimelineRecordTreeElement.js:
+ (WebInspector.TimelineRecordTreeElement):
+ Added support for new runloop record type.
+
+ * UserInterface/Views/RunLoopTimelineOverviewGraph.css: Added.
+ (.timeline-overview-graph.runloop > .divider):
+ (.timeline-overview-graph.runloop > .divider > span):
+ New styles for runloop timeline graph.
+
+ * UserInterface/Views/RunLoopTimelineOverviewGraph.js: Added.
+ (WebInspector.RunLoopTimelineOverviewGraph):
+ (WebInspector.RunLoopTimelineOverviewGraph.prototype.updateLayout.createFrame):
+ (WebInspector.RunLoopTimelineOverviewGraph.prototype.get graphHeightSeconds.this):
+ (WebInspector.RunLoopTimelineOverviewGraph.prototype.get graphHeightSeconds):
+ (WebInspector.RunLoopTimelineOverviewGraph.prototype._updateDividers.createDividerAtPosition.get if):
+ New overview graph for displaying TimelineRecordFrames and horizontal frame budget dividers.
+
+ * UserInterface/Views/TimelineIcons.css:
+ (.runloop-icon .icon):
+ (.runloop-icon.large .icon):
+ (.runloop-record .icon):
+ * UserInterface/Views/TimelineSidebarPanel.js:
+ New runloop icon styles.
+
+ * UserInterface/Views/TimelineOverviewGraph.js:
+ (WebInspector.TimelineOverviewGraph):
+ Updated factory to support creation of the new overview graph.
+
+ * UserInterface/Views/TimelineRecordFrame.css: Added.
+ (.timeline-record-frame):
+ (.timeline-record-frame > .frame):
+ (.timeline-record-frame > .dropped):
+ (.timeline-record-frame > .frame > .duration):
+ (.timeline-record-frame > .frame > .duration:first-child):
+ (.timeline-record-frame > .frame > .duration:last-child):
+ (.timeline-record-frame > .frame > .duration.timeline-record-type-network):
+ (.timeline-record-frame > .frame > .duration.timeline-record-type-layout):
+ (.timeline-record-frame > .frame > .duration.timeline-record-type-script):
+ New styles for frame bars in the runloop timeline graph.
+
+ * UserInterface/Views/TimelineRecordFrame.js: Added.
+ (WebInspector.TimelineRecordFrame):
+ (WebInspector.TimelineRecordFrame.createCombinedFrames):
+ (WebInspector.TimelineRecordFrame.prototype.get element):
+ (WebInspector.TimelineRecordFrame.prototype.get duration):
+ (WebInspector.TimelineRecordFrame.prototype.get records):
+ (WebInspector.TimelineRecordFrame.prototype.set records):
+ (WebInspector.TimelineRecordFrame.prototype._updateChildElements.createDurationElement):
+ New view representing a single frame within the runloop overview graph.
+
+ * WebInspectorUI.vcxproj/WebInspectorUI.vcxproj:
+ * WebInspectorUI.vcxproj/WebInspectorUI.vcxproj.filters:
+ New files.
+
2015-03-16 Joseph Pecoraro <[email protected]>
Web Inspector: Add more DOM Native Function parameter strings
Modified: trunk/Source/WebInspectorUI/Localizations/en.lproj/localizedStrings.js (181625 => 181626)
--- trunk/Source/WebInspectorUI/Localizations/en.lproj/localizedStrings.js 2015-03-17 08:41:19 UTC (rev 181625)
+++ trunk/Source/WebInspectorUI/Localizations/en.lproj/localizedStrings.js 2015-03-17 08:43:30 UTC (rev 181626)
@@ -397,6 +397,7 @@
localizedStrings["Reveal in Original Resource"] = "Reveal in Original Resource";
localizedStrings["Role"] = "Role";
localizedStrings["Rules"] = "Rules";
+localizedStrings["Runloop Executed"] = "Runloop Executed";
localizedStrings["Scheme"] = "Scheme";
localizedStrings["Scope Chain"] = "Scope Chain";
localizedStrings["Script"] = "Script";
Modified: trunk/Source/WebInspectorUI/UserInterface/Controllers/TimelineManager.js (181625 => 181626)
--- trunk/Source/WebInspectorUI/UserInterface/Controllers/TimelineManager.js 2015-03-17 08:41:19 UTC (rev 181625)
+++ trunk/Source/WebInspectorUI/UserInterface/Controllers/TimelineManager.js 2015-03-17 08:43:30 UTC (rev 181626)
@@ -162,248 +162,268 @@
this.dispatchEventToListeners(WebInspector.TimelineManager.Event.CapturingStopped);
},
- eventRecorded: function(originalRecordPayload)
+ eventRecorded: function(recordPayload)
{
// Called from WebInspector.TimelineObserver.
if (!this._isCapturing)
return;
- function processRecord(recordPayload, parentRecordPayload)
- {
- var startTime = this.activeRecording.computeElapsedTime(recordPayload.startTime);
- var endTime = this.activeRecording.computeElapsedTime(recordPayload.endTime);
- var callFrames = this._callFramesFromPayload(recordPayload.stackTrace);
+ var records = this._processNestedRecords(recordPayload);
+ records.forEach(function(currentValue) {
+ this._addRecord(currentValue);
+ }.bind(this));
+ },
- var significantCallFrame = null;
- if (callFrames) {
- for (var i = 0; i < callFrames.length; ++i) {
- if (callFrames[i].nativeCode)
- continue;
- significantCallFrame = callFrames[i];
- break;
- }
- }
+ pageDidLoad: function(timestamp)
+ {
+ if (isNaN(WebInspector.frameResourceManager.mainFrame.loadEventTimestamp))
+ WebInspector.frameResourceManager.mainFrame.markLoadEvent(this.activeRecording.computeElapsedTime(timestamp));
+ },
- var sourceCodeLocation = significantCallFrame && significantCallFrame.sourceCodeLocation;
+ // Private
- switch (recordPayload.type) {
- case TimelineAgent.EventType.MarkLoad:
- console.assert(isNaN(endTime));
+ _processNestedRecords: function(childRecordPayloads, parentRecordPayload)
+ {
+ // Convert to a single item array if needed.
+ if (!(childRecordPayloads instanceof Array))
+ childRecordPayloads = [childRecordPayloads];
- var frame = WebInspector.frameResourceManager.frameForIdentifier(recordPayload.frameId);
- console.assert(frame);
- if (!frame)
- break;
+ var records = [];
- frame.markLoadEvent(startTime);
+ // Iterate over the records tree using a stack. Doing this recursively has
+ // been known to cause a call stack overflow. https://webkit.org/b/79106
+ var stack = [{array: childRecordPayloads, parent: parentRecordPayload || null, index: 0}];
+ while (stack.length) {
+ var entry = stack.lastValue;
+ var recordPayloads = entry.array;
- if (!frame.isMainFrame())
- break;
+ if (entry.index < recordPayloads.length) {
+ var recordPayload = recordPayloads[entry.index];
+ var record = this._processEvent(recordPayload, entry.parent);
+ if (record)
+ records.push(record);
- var eventMarker = new WebInspector.TimelineMarker(startTime, WebInspector.TimelineMarker.Type.LoadEvent);
- this._activeRecording.addEventMarker(eventMarker);
+ if (recordPayload.children)
+ stack.push({array: recordPayload.children, parent: recordPayload, index: 0});
+ ++entry.index;
+ } else
+ stack.pop();
+ }
- this._stopAutoRecordingSoon();
+ return records;
+ },
+
+ _processRecord: function(recordPayload, parentRecordPayload)
+ {
+ var startTime = this.activeRecording.computeElapsedTime(recordPayload.startTime);
+ var endTime = this.activeRecording.computeElapsedTime(recordPayload.endTime);
+ var callFrames = this._callFramesFromPayload(recordPayload.stackTrace);
+
+ var significantCallFrame = null;
+ if (callFrames) {
+ for (var i = 0; i < callFrames.length; ++i) {
+ if (callFrames[i].nativeCode)
+ continue;
+ significantCallFrame = callFrames[i];
break;
+ }
+ }
- case TimelineAgent.EventType.MarkDOMContent:
- console.assert(isNaN(endTime));
+ var sourceCodeLocation = significantCallFrame && significantCallFrame.sourceCodeLocation;
- var frame = WebInspector.frameResourceManager.frameForIdentifier(recordPayload.frameId);
- console.assert(frame);
- if (!frame)
- break;
+ switch (recordPayload.type) {
+ case TimelineAgent.EventType.ScheduleStyleRecalculation:
+ console.assert(isNaN(endTime));
- frame.markDOMContentReadyEvent(startTime);
+ // Pass the startTime as the endTime since this record type has no duration.
+ return new WebInspector.LayoutTimelineRecord(WebInspector.LayoutTimelineRecord.EventType.InvalidateStyles, startTime, startTime, callFrames, sourceCodeLocation);
- if (!frame.isMainFrame())
- break;
+ case TimelineAgent.EventType.RecalculateStyles:
+ return new WebInspector.LayoutTimelineRecord(WebInspector.LayoutTimelineRecord.EventType.RecalculateStyles, startTime, endTime, callFrames, sourceCodeLocation);
- var eventMarker = new WebInspector.TimelineMarker(startTime, WebInspector.TimelineMarker.Type.DOMContentEvent);
- this._activeRecording.addEventMarker(eventMarker);
- break;
+ case TimelineAgent.EventType.InvalidateLayout:
+ console.assert(isNaN(endTime));
- case TimelineAgent.EventType.ScheduleStyleRecalculation:
- console.assert(isNaN(endTime));
+ // Pass the startTime as the endTime since this record type has no duration.
+ return new WebInspector.LayoutTimelineRecord(WebInspector.LayoutTimelineRecord.EventType.InvalidateLayout, startTime, startTime, callFrames, sourceCodeLocation);
- // Pass the startTime as the endTime since this record type has no duration.
- this._addRecord(new WebInspector.LayoutTimelineRecord(WebInspector.LayoutTimelineRecord.EventType.InvalidateStyles, startTime, startTime, callFrames, sourceCodeLocation));
- break;
+ case TimelineAgent.EventType.Layout:
+ var layoutRecordType = sourceCodeLocation ? WebInspector.LayoutTimelineRecord.EventType.ForcedLayout : WebInspector.LayoutTimelineRecord.EventType.Layout;
- case TimelineAgent.EventType.RecalculateStyles:
- this._addRecord(new WebInspector.LayoutTimelineRecord(WebInspector.LayoutTimelineRecord.EventType.RecalculateStyles, startTime, endTime, callFrames, sourceCodeLocation));
- break;
+ // COMPATIBILITY (iOS 6): Layout records did not contain area properties. This is not exposed via a quad "root".
+ var quad = recordPayload.data.root ? new WebInspector.Quad(recordPayload.data.root) : null;
+ if (quad)
+ return new WebInspector.LayoutTimelineRecord(layoutRecordType, startTime, endTime, callFrames, sourceCodeLocation, quad.points[0].x, quad.points[0].y, quad.width, quad.height, quad);
+ else
+ return new WebInspector.LayoutTimelineRecord(layoutRecordType, startTime, endTime, callFrames, sourceCodeLocation);
- case TimelineAgent.EventType.InvalidateLayout:
- console.assert(isNaN(endTime));
+ case TimelineAgent.EventType.Paint:
+ // COMPATIBILITY (iOS 6): Paint records data contained x, y, width, height properties. This became a quad "clip".
+ var quad = recordPayload.data.clip ? new WebInspector.Quad(recordPayload.data.clip) : null;
+ if (quad)
+ return new WebInspector.LayoutTimelineRecord(WebInspector.LayoutTimelineRecord.EventType.Paint, startTime, endTime, callFrames, sourceCodeLocation, null, null, quad.width, quad.height, quad);
+ else
+ return new WebInspector.LayoutTimelineRecord(WebInspector.LayoutTimelineRecord.EventType.Paint, startTime, endTime, callFrames, sourceCodeLocation, recordPayload.data.x, recordPayload.data.y, recordPayload.data.width, recordPayload.data.height);
- // Pass the startTime as the endTime since this record type has no duration.
- this._addRecord(new WebInspector.LayoutTimelineRecord(WebInspector.LayoutTimelineRecord.EventType.InvalidateLayout, startTime, startTime, callFrames, sourceCodeLocation));
- break;
+ case TimelineAgent.EventType.RunLoop:
+ if (!recordPayload.children)
+ return null;
- case TimelineAgent.EventType.Layout:
- var layoutRecordType = sourceCodeLocation ? WebInspector.LayoutTimelineRecord.EventType.ForcedLayout : WebInspector.LayoutTimelineRecord.EventType.Layout;
+ var children = this._processNestedRecords(recordPayload.children, recordPayload);
+ return new WebInspector.RunLoopTimelineRecord(startTime, endTime, children);
- // COMPATIBILITY (iOS 6): Layout records did not contain area properties. This is not exposed via a quad "root".
- var quad = recordPayload.data.root ? new WebInspector.Quad(recordPayload.data.root) : null;
- if (quad)
- this._addRecord(new WebInspector.LayoutTimelineRecord(layoutRecordType, startTime, endTime, callFrames, sourceCodeLocation, quad.points[0].x, quad.points[0].y, quad.width, quad.height, quad));
- else
- this._addRecord(new WebInspector.LayoutTimelineRecord(layoutRecordType, startTime, endTime, callFrames, sourceCodeLocation));
- break;
+ case TimelineAgent.EventType.EvaluateScript:
+ if (!sourceCodeLocation) {
+ var mainFrame = WebInspector.frameResourceManager.mainFrame;
+ var scriptResource = mainFrame.url ="" recordPayload.data.url ? mainFrame.mainResource : mainFrame.resourceForURL(recordPayload.data.url, true);
+ if (scriptResource) {
+ // The lineNumber is 1-based, but we expect 0-based.
+ var lineNumber = recordPayload.data.lineNumber - 1;
- case TimelineAgent.EventType.Paint:
- // COMPATIBILITY (iOS 6): Paint records data contained x, y, width, height properties. This became a quad "clip".
- var quad = recordPayload.data.clip ? new WebInspector.Quad(recordPayload.data.clip) : null;
- if (quad)
- this._addRecord(new WebInspector.LayoutTimelineRecord(WebInspector.LayoutTimelineRecord.EventType.Paint, startTime, endTime, callFrames, sourceCodeLocation, null, null, quad.width, quad.height, quad));
- else
- this._addRecord(new WebInspector.LayoutTimelineRecord(WebInspector.LayoutTimelineRecord.EventType.Paint, startTime, endTime, callFrames, sourceCodeLocation, recordPayload.data.x, recordPayload.data.y, recordPayload.data.width, recordPayload.data.height));
+ // FIXME: No column number is provided.
+ sourceCodeLocation = scriptResource.createSourceCodeLocation(lineNumber, 0);
+ }
+ }
+
+ var profileData = recordPayload.data.profile;
+
+ switch (parentRecordPayload && parentRecordPayload.type) {
+ case TimelineAgent.EventType.TimerFire:
+ return new WebInspector.ScriptTimelineRecord(WebInspector.ScriptTimelineRecord.EventType.TimerFired, startTime, endTime, callFrames, sourceCodeLocation, parentRecordPayload.data.timerId, profileData);
+ default:
+ return new WebInspector.ScriptTimelineRecord(WebInspector.ScriptTimelineRecord.EventType.ScriptEvaluated, startTime, endTime, callFrames, sourceCodeLocation, null, profileData);
+ }
+
+ break;
+
+ case TimelineAgent.EventType.ConsoleProfile:
+ var profileData = recordPayload.data.profile;
+ console.assert(profileData);
+ return new WebInspector.ScriptTimelineRecord(WebInspector.ScriptTimelineRecord.EventType.ConsoleProfileRecorded, startTime, endTime, callFrames, sourceCodeLocation, recordPayload.data.title, profileData);
+
+ case TimelineAgent.EventType.FunctionCall:
+ // FunctionCall always happens as a child of another record, and since the FunctionCall record
+ // has useful info we just make the timeline record here (combining the data from both records).
+ if (!parentRecordPayload)
break;
- case TimelineAgent.EventType.EvaluateScript:
- if (!sourceCodeLocation) {
- var mainFrame = WebInspector.frameResourceManager.mainFrame;
- var scriptResource = mainFrame.url ="" recordPayload.data.url ? mainFrame.mainResource : mainFrame.resourceForURL(recordPayload.data.url, true);
- if (scriptResource) {
- // The lineNumber is 1-based, but we expect 0-based.
- var lineNumber = recordPayload.data.lineNumber - 1;
+ if (!sourceCodeLocation) {
+ var mainFrame = WebInspector.frameResourceManager.mainFrame;
+ var scriptResource = mainFrame.url ="" recordPayload.data.scriptName ? mainFrame.mainResource : mainFrame.resourceForURL(recordPayload.data.scriptName, true);
+ if (scriptResource) {
+ // The lineNumber is 1-based, but we expect 0-based.
+ var lineNumber = recordPayload.data.scriptLine - 1;
- // FIXME: No column number is provided.
- sourceCodeLocation = scriptResource.createSourceCodeLocation(lineNumber, 0);
- }
+ // FIXME: No column number is provided.
+ sourceCodeLocation = scriptResource.createSourceCodeLocation(lineNumber, 0);
}
+ }
- var profileData = recordPayload.data.profile;
+ var profileData = recordPayload.data.profile;
- switch (parentRecordPayload && parentRecordPayload.type) {
- case TimelineAgent.EventType.TimerFire:
- this._addRecord(new WebInspector.ScriptTimelineRecord(WebInspector.ScriptTimelineRecord.EventType.TimerFired, startTime, endTime, callFrames, sourceCodeLocation, parentRecordPayload.data.timerId, profileData));
- break;
- default:
- this._addRecord(new WebInspector.ScriptTimelineRecord(WebInspector.ScriptTimelineRecord.EventType.ScriptEvaluated, startTime, endTime, callFrames, sourceCodeLocation, null, profileData));
- break;
- }
+ switch (parentRecordPayload.type) {
+ case TimelineAgent.EventType.TimerFire:
+ return new WebInspector.ScriptTimelineRecord(WebInspector.ScriptTimelineRecord.EventType.TimerFired, startTime, endTime, callFrames, sourceCodeLocation, parentRecordPayload.data.timerId, profileData);
+ case TimelineAgent.EventType.EventDispatch:
+ return new WebInspector.ScriptTimelineRecord(WebInspector.ScriptTimelineRecord.EventType.EventDispatched, startTime, endTime, callFrames, sourceCodeLocation, parentRecordPayload.data.type, profileData);
+ case TimelineAgent.EventType.XHRLoad:
+ return new WebInspector.ScriptTimelineRecord(WebInspector.ScriptTimelineRecord.EventType.EventDispatched, startTime, endTime, callFrames, sourceCodeLocation, "load", profileData);
+ case TimelineAgent.EventType.XHRReadyStateChange:
+ return new WebInspector.ScriptTimelineRecord(WebInspector.ScriptTimelineRecord.EventType.EventDispatched, startTime, endTime, callFrames, sourceCodeLocation, "readystatechange", profileData);
+ case TimelineAgent.EventType.FireAnimationFrame:
+ return new WebInspector.ScriptTimelineRecord(WebInspector.ScriptTimelineRecord.EventType.AnimationFrameFired, startTime, endTime, callFrames, sourceCodeLocation, parentRecordPayload.data.id, profileData);
+ }
- break;
+ break;
- case TimelineAgent.EventType.TimeStamp:
- var eventMarker = new WebInspector.TimelineMarker(startTime, WebInspector.TimelineMarker.Type.TimeStamp);
- this._activeRecording.addEventMarker(eventMarker);
- break;
+ case TimelineAgent.EventType.ProbeSample:
+ // Pass the startTime as the endTime since this record type has no duration.
+ sourceCodeLocation = WebInspector.probeManager.probeForIdentifier(recordPayload.data.probeId).breakpoint.sourceCodeLocation;
+ return new WebInspector.ScriptTimelineRecord(WebInspector.ScriptTimelineRecord.EventType.ProbeSampleRecorded, startTime, startTime, callFrames, sourceCodeLocation, recordPayload.data.probeId);
- case TimelineAgent.EventType.ConsoleProfile:
- var profileData = recordPayload.data.profile;
- console.assert(profileData);
- this._addRecord(new WebInspector.ScriptTimelineRecord(WebInspector.ScriptTimelineRecord.EventType.ConsoleProfileRecorded, startTime, endTime, callFrames, sourceCodeLocation, recordPayload.data.title, profileData));
- break;
+ case TimelineAgent.EventType.TimerInstall:
+ console.assert(isNaN(endTime));
- case TimelineAgent.EventType.FunctionCall:
- // FunctionCall always happens as a child of another record, and since the FunctionCall record
- // has useful info we just make the timeline record here (combining the data from both records).
- if (!parentRecordPayload)
- break;
+ // Pass the startTime as the endTime since this record type has no duration.
+ return new WebInspector.ScriptTimelineRecord(WebInspector.ScriptTimelineRecord.EventType.TimerInstalled, startTime, startTime, callFrames, sourceCodeLocation, recordPayload.data.timerId);
- if (!sourceCodeLocation) {
- var mainFrame = WebInspector.frameResourceManager.mainFrame;
- var scriptResource = mainFrame.url ="" recordPayload.data.scriptName ? mainFrame.mainResource : mainFrame.resourceForURL(recordPayload.data.scriptName, true);
- if (scriptResource) {
- // The lineNumber is 1-based, but we expect 0-based.
- var lineNumber = recordPayload.data.scriptLine - 1;
+ case TimelineAgent.EventType.TimerRemove:
+ console.assert(isNaN(endTime));
- // FIXME: No column number is provided.
- sourceCodeLocation = scriptResource.createSourceCodeLocation(lineNumber, 0);
- }
- }
+ // Pass the startTime as the endTime since this record type has no duration.
+ return new WebInspector.ScriptTimelineRecord(WebInspector.ScriptTimelineRecord.EventType.TimerRemoved, startTime, startTime, callFrames, sourceCodeLocation, recordPayload.data.timerId);
- var profileData = recordPayload.data.profile;
+ case TimelineAgent.EventType.RequestAnimationFrame:
+ console.assert(isNaN(endTime));
- switch (parentRecordPayload.type) {
- case TimelineAgent.EventType.TimerFire:
- this._addRecord(new WebInspector.ScriptTimelineRecord(WebInspector.ScriptTimelineRecord.EventType.TimerFired, startTime, endTime, callFrames, sourceCodeLocation, parentRecordPayload.data.timerId, profileData));
- break;
- case TimelineAgent.EventType.EventDispatch:
- this._addRecord(new WebInspector.ScriptTimelineRecord(WebInspector.ScriptTimelineRecord.EventType.EventDispatched, startTime, endTime, callFrames, sourceCodeLocation, parentRecordPayload.data.type, profileData));
- break;
- case TimelineAgent.EventType.XHRLoad:
- this._addRecord(new WebInspector.ScriptTimelineRecord(WebInspector.ScriptTimelineRecord.EventType.EventDispatched, startTime, endTime, callFrames, sourceCodeLocation, "load", profileData));
- break;
- case TimelineAgent.EventType.XHRReadyStateChange:
- this._addRecord(new WebInspector.ScriptTimelineRecord(WebInspector.ScriptTimelineRecord.EventType.EventDispatched, startTime, endTime, callFrames, sourceCodeLocation, "readystatechange", profileData));
- break;
- case TimelineAgent.EventType.FireAnimationFrame:
- this._addRecord(new WebInspector.ScriptTimelineRecord(WebInspector.ScriptTimelineRecord.EventType.AnimationFrameFired, startTime, endTime, callFrames, sourceCodeLocation, parentRecordPayload.data.id, profileData));
- break;
- }
+ // Pass the startTime as the endTime since this record type has no duration.
+ return new WebInspector.ScriptTimelineRecord(WebInspector.ScriptTimelineRecord.EventType.AnimationFrameRequested, startTime, startTime, callFrames, sourceCodeLocation, recordPayload.data.timerId);
- break;
+ case TimelineAgent.EventType.CancelAnimationFrame:
+ console.assert(isNaN(endTime));
- case TimelineAgent.EventType.ProbeSample:
- // Pass the startTime as the endTime since this record type has no duration.
- sourceCodeLocation = WebInspector.probeManager.probeForIdentifier(recordPayload.data.probeId).breakpoint.sourceCodeLocation;
- this._addRecord(new WebInspector.ScriptTimelineRecord(WebInspector.ScriptTimelineRecord.EventType.ProbeSampleRecorded, startTime, startTime, callFrames, sourceCodeLocation, recordPayload.data.probeId));
- break;
+ // Pass the startTime as the endTime since this record type has no duration.
+ return new WebInspector.ScriptTimelineRecord(WebInspector.ScriptTimelineRecord.EventType.AnimationFrameCanceled, startTime, startTime, callFrames, sourceCodeLocation, recordPayload.data.timerId);
+ }
- case TimelineAgent.EventType.TimerInstall:
- console.assert(isNaN(endTime));
+ return null;
+ },
- // Pass the startTime as the endTime since this record type has no duration.
- this._addRecord(new WebInspector.ScriptTimelineRecord(WebInspector.ScriptTimelineRecord.EventType.TimerInstalled, startTime, startTime, callFrames, sourceCodeLocation, recordPayload.data.timerId));
+ _processEvent: function(recordPayload, parentRecordPayload)
+ {
+ var startTime = this.activeRecording.computeElapsedTime(recordPayload.startTime);
+ var endTime = this.activeRecording.computeElapsedTime(recordPayload.endTime);
+
+ switch (recordPayload.type) {
+ case TimelineAgent.EventType.MarkLoad:
+ console.assert(isNaN(endTime));
+
+ var frame = WebInspector.frameResourceManager.frameForIdentifier(recordPayload.frameId);
+ console.assert(frame);
+ if (!frame)
break;
- case TimelineAgent.EventType.TimerRemove:
- console.assert(isNaN(endTime));
+ frame.markLoadEvent(startTime);
- // Pass the startTime as the endTime since this record type has no duration.
- this._addRecord(new WebInspector.ScriptTimelineRecord(WebInspector.ScriptTimelineRecord.EventType.TimerRemoved, startTime, startTime, callFrames, sourceCodeLocation, recordPayload.data.timerId));
+ if (!frame.isMainFrame())
break;
- case TimelineAgent.EventType.RequestAnimationFrame:
- console.assert(isNaN(endTime));
+ var eventMarker = new WebInspector.TimelineMarker(startTime, WebInspector.TimelineMarker.Type.LoadEvent);
+ this._activeRecording.addEventMarker(eventMarker);
- // Pass the startTime as the endTime since this record type has no duration.
- this._addRecord(new WebInspector.ScriptTimelineRecord(WebInspector.ScriptTimelineRecord.EventType.AnimationFrameRequested, startTime, startTime, callFrames, sourceCodeLocation, recordPayload.data.timerId));
+ this._stopAutoRecordingSoon();
+ break;
+
+ case TimelineAgent.EventType.MarkDOMContent:
+ console.assert(isNaN(endTime));
+
+ var frame = WebInspector.frameResourceManager.frameForIdentifier(recordPayload.frameId);
+ console.assert(frame);
+ if (!frame)
break;
- case TimelineAgent.EventType.CancelAnimationFrame:
- console.assert(isNaN(endTime));
+ frame.markDOMContentReadyEvent(startTime);
- // Pass the startTime as the endTime since this record type has no duration.
- this._addRecord(new WebInspector.ScriptTimelineRecord(WebInspector.ScriptTimelineRecord.EventType.AnimationFrameCanceled, startTime, startTime, callFrames, sourceCodeLocation, recordPayload.data.timerId));
+ if (!frame.isMainFrame())
break;
- }
- }
- // Iterate over the records tree using a stack. Doing this recursively has
- // been known to cause a call stack overflow. https://webkit.org/b/79106
- var stack = [{array: [originalRecordPayload], parent: null, index: 0}];
- while (stack.length) {
- var entry = stack.lastValue;
- var recordPayloads = entry.array;
- var parentRecordPayload = entry.parent;
+ var eventMarker = new WebInspector.TimelineMarker(startTime, WebInspector.TimelineMarker.Type.DOMContentEvent);
+ this._activeRecording.addEventMarker(eventMarker);
+ break;
- if (entry.index < recordPayloads.length) {
- var recordPayload = recordPayloads[entry.index];
+ case TimelineAgent.EventType.TimeStamp:
+ var eventMarker = new WebInspector.TimelineMarker(startTime, WebInspector.TimelineMarker.Type.TimeStamp);
+ this._activeRecording.addEventMarker(eventMarker);
+ break;
- processRecord.call(this, recordPayload, parentRecordPayload);
-
- if (recordPayload.children)
- stack.push({array: recordPayload.children, parent: recordPayload, index: 0});
- ++entry.index;
- } else
- stack.pop();
+ default:
+ return this._processRecord(recordPayload, parentRecordPayload);
}
- },
- pageDidLoad: function(timestamp)
- {
- if (isNaN(WebInspector.frameResourceManager.mainFrame.loadEventTimestamp))
- WebInspector.frameResourceManager.mainFrame.markLoadEvent(this.activeRecording.computeElapsedTime(timestamp));
+ return null;
},
- // Private
-
_loadNewRecording: function()
{
if (this._activeRecording && this._activeRecording.isEmpty())
@@ -411,9 +431,10 @@
var identifier = this._nextRecordingIdentifier++;
var newRecording = new WebInspector.TimelineRecording(identifier, WebInspector.UIString("Timeline Recording %d").format(identifier));
- newRecording.addTimeline(new WebInspector.Timeline(WebInspector.TimelineRecord.Type.Network));
- newRecording.addTimeline(new WebInspector.Timeline(WebInspector.TimelineRecord.Type.Layout));
- newRecording.addTimeline(new WebInspector.Timeline(WebInspector.TimelineRecord.Type.Script));
+ newRecording.addTimeline(new WebInspector.Timeline(WebInspector.TimelineRecord.Type.Network, newRecording));
+ newRecording.addTimeline(new WebInspector.Timeline(WebInspector.TimelineRecord.Type.RunLoop, newRecording));
+ newRecording.addTimeline(new WebInspector.Timeline(WebInspector.TimelineRecord.Type.Layout, newRecording));
+ newRecording.addTimeline(new WebInspector.Timeline(WebInspector.TimelineRecord.Type.Script, newRecording));
this._recordings.push(newRecording);
this.dispatchEventToListeners(WebInspector.TimelineManager.Event.RecordingCreated, {recording: newRecording});
Added: trunk/Source/WebInspectorUI/UserInterface/Images/Frames.png
(Binary files differ)
Property changes on: trunk/Source/WebInspectorUI/UserInterface/Images/Frames.png
___________________________________________________________________
Added: svn:mime-type
Added: trunk/Source/WebInspectorUI/UserInterface/Images/[email protected]
(Binary files differ)
Property changes on: trunk/Source/WebInspectorUI/UserInterface/Images/[email protected]
___________________________________________________________________
Added: svn:mime-type
Added: trunk/Source/WebInspectorUI/UserInterface/Images/FramesLarge.png
(Binary files differ)
Property changes on: trunk/Source/WebInspectorUI/UserInterface/Images/FramesLarge.png
___________________________________________________________________
Added: svn:mime-type
Added: trunk/Source/WebInspectorUI/UserInterface/Images/[email protected]
(Binary files differ)
Property changes on: trunk/Source/WebInspectorUI/UserInterface/Images/[email protected]
___________________________________________________________________
Added: svn:mime-type
Modified: trunk/Source/WebInspectorUI/UserInterface/Main.html (181625 => 181626)
--- trunk/Source/WebInspectorUI/UserInterface/Main.html 2015-03-17 08:41:19 UTC (rev 181625)
+++ trunk/Source/WebInspectorUI/UserInterface/Main.html 2015-03-17 08:43:30 UTC (rev 181626)
@@ -114,6 +114,7 @@
<link rel="stylesheet" href=""
<link rel="stylesheet" href=""
<link rel="stylesheet" href=""
+ <link rel="stylesheet" href=""
<link rel="stylesheet" href=""
<link rel="stylesheet" href=""
<link rel="stylesheet" href=""
@@ -134,6 +135,7 @@
<link rel="stylesheet" href=""
<link rel="stylesheet" href=""
<link rel="stylesheet" href=""
+ <link rel="stylesheet" href=""
<link rel="stylesheet" href=""
<link rel="stylesheet" href=""
<link rel="stylesheet" href=""
@@ -272,6 +274,7 @@
<script src=""
<script src=""
<script src=""
+ <script src=""
<script src=""
<script src=""
<script src=""
@@ -448,6 +451,7 @@
<script src=""
<script src=""
<script src=""
+ <script src=""
<script src=""
<script src=""
<script src=""
@@ -471,6 +475,7 @@
<script src=""
<script src=""
<script src=""
+ <script src=""
<script src=""
<script src=""
<script src=""
Added: trunk/Source/WebInspectorUI/UserInterface/Models/RunLoopTimelineRecord.js (0 => 181626)
--- trunk/Source/WebInspectorUI/UserInterface/Models/RunLoopTimelineRecord.js (rev 0)
+++ trunk/Source/WebInspectorUI/UserInterface/Models/RunLoopTimelineRecord.js 2015-03-17 08:43:30 UTC (rev 181626)
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2015 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.RunLoopTimelineRecord = function(startTime, endTime, children)
+{
+ WebInspector.TimelineRecord.call(this, WebInspector.TimelineRecord.Type.RunLoop, startTime, endTime);
+
+ this._children = children || [];
+ this._durationByRecordType = new Map;
+ this._durationRemainder = NaN;
+};
+
+WebInspector.RunLoopTimelineRecord.TypeIdentifier = "runloop-timeline-record";
+
+WebInspector.RunLoopTimelineRecord.prototype = {
+ constructor: WebInspector.RunLoopTimelineRecord,
+ __proto__: WebInspector.TimelineRecord.prototype,
+
+ // Public
+
+ get children()
+ {
+ return this._children.slice();
+ },
+
+ get durationRemainder()
+ {
+ if (!isNaN(this._durationRemainder))
+ return this._durationRemainder;
+
+ this._durationRemainder = this.duration;
+ for (recordType in WebInspector.TimelineRecord.Type)
+ this._durationRemainder -= this.durationForRecords(WebInspector.TimelineRecord.Type[recordType]);
+
+ return this._durationRemainder;
+ },
+
+ durationForRecords(recordType)
+ {
+ if (this._durationByRecordType.has(recordType))
+ return this._durationByRecordType.get(recordType);
+
+ var duration = this._children.reduce(function(previousValue, currentValue) {
+ if (currentValue.type === recordType) {
+ var currentDuration = currentValue.duration;
+ if (currentValue.usesActiveStartTime)
+ currentDuration -= currentValue.inactiveDuration;
+ return previousValue + currentDuration;
+ }
+ return previousValue;
+ }, 0);
+
+ this._durationByRecordType.set(recordType, duration);
+ return duration;
+ }
+};
Modified: trunk/Source/WebInspectorUI/UserInterface/Models/Timeline.js (181625 => 181626)
--- trunk/Source/WebInspectorUI/UserInterface/Models/Timeline.js 2015-03-17 08:41:19 UTC (rev 181625)
+++ trunk/Source/WebInspectorUI/UserInterface/Models/Timeline.js 2015-03-17 08:43:30 UTC (rev 181626)
@@ -80,6 +80,8 @@
return WebInspector.UIString("Layout & Rendering");
if (this._type === WebInspector.TimelineRecord.Type.Script)
return WebInspector.UIString("_javascript_ & Events");
+ if (this._type === WebInspector.TimelineRecord.Type.RunLoop)
+ return WebInspector.UIString("Frames");
console.error("Timeline has unknown type:", this._type, this);
},
@@ -90,6 +92,8 @@
return WebInspector.TimelineSidebarPanel.NetworkIconStyleClass;
if (this._type === WebInspector.TimelineRecord.Type.Layout)
return WebInspector.TimelineSidebarPanel.ColorsIconStyleClass;
+ if (this._type === WebInspector.TimelineRecord.Type.RunLoop)
+ return WebInspector.TimelineSidebarPanel.RunLoopIconStyleClass;
if (this._type === WebInspector.TimelineRecord.Type.Script)
return WebInspector.TimelineSidebarPanel.ScriptIconStyleClass;
Modified: trunk/Source/WebInspectorUI/UserInterface/Models/TimelineRecord.js (181625 => 181626)
--- trunk/Source/WebInspectorUI/UserInterface/Models/TimelineRecord.js 2015-03-17 08:41:19 UTC (rev 181625)
+++ trunk/Source/WebInspectorUI/UserInterface/Models/TimelineRecord.js 2015-03-17 08:43:30 UTC (rev 181626)
@@ -46,7 +46,8 @@
WebInspector.TimelineRecord.Type = {
Network: "timeline-record-type-network",
Layout: "timeline-record-type-layout",
- Script: "timeline-record-type-script"
+ Script: "timeline-record-type-script",
+ RunLoop: "timeline-record-type-runloop"
};
WebInspector.TimelineRecord.TypeIdentifier = "timeline-record";
Modified: trunk/Source/WebInspectorUI/UserInterface/Views/ContentView.js (181625 => 181626)
--- trunk/Source/WebInspectorUI/UserInterface/Views/ContentView.js 2015-03-17 08:41:19 UTC (rev 181625)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/ContentView.js 2015-03-17 08:43:30 UTC (rev 181626)
@@ -47,7 +47,7 @@
if (timelineType === WebInspector.TimelineRecord.Type.Network)
return new WebInspector.NetworkTimelineView(representedObject);
- if (timelineType === WebInspector.TimelineRecord.Type.Layout)
+ if (timelineType === WebInspector.TimelineRecord.Type.Layout || timelineType === WebInspector.TimelineRecord.Type.RunLoop)
return new WebInspector.LayoutTimelineView(representedObject);
if (timelineType === WebInspector.TimelineRecord.Type.Script)
Modified: trunk/Source/WebInspectorUI/UserInterface/Views/LayoutTimelineView.js (181625 => 181626)
--- trunk/Source/WebInspectorUI/UserInterface/Views/LayoutTimelineView.js 2015-03-17 08:41:19 UTC (rev 181625)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/LayoutTimelineView.js 2015-03-17 08:43:30 UTC (rev 181626)
@@ -27,7 +27,7 @@
{
WebInspector.TimelineView.call(this, timeline);
- console.assert(timeline.type === WebInspector.TimelineRecord.Type.Layout);
+ console.assert(timeline.type === WebInspector.TimelineRecord.Type.Layout || WebInspector.TimelineRecord.Type.RunLoop);
this.navigationSidebarTreeOutline._onselect_ = this._treeElementSelected.bind(this);
this.navigationSidebarTreeOutline._ondeselect_ = this._treeElementDeselected.bind(this);
@@ -185,7 +185,7 @@
_layoutTimelineRecordAdded: function(event)
{
var layoutTimelineRecord = event.data.record;
- console.assert(layoutTimelineRecord instanceof WebInspector.LayoutTimelineRecord);
+ console.assert(layoutTimelineRecord instanceof WebInspector.LayoutTimelineRecord || layoutTimelineRecord instanceof WebInspector.RunLoopTimelineRecord);
this._pendingRecords.push(layoutTimelineRecord);
Added: trunk/Source/WebInspectorUI/UserInterface/Views/RunLoopTimelineOverviewGraph.css (0 => 181626)
--- trunk/Source/WebInspectorUI/UserInterface/Views/RunLoopTimelineOverviewGraph.css (rev 0)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/RunLoopTimelineOverviewGraph.css 2015-03-17 08:43:30 UTC (rev 181626)
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2015 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.
+ */
+
+.timeline-overview-graph.runloop > .divider {
+ position: absolute;
+ z-index: 10;
+
+ width: 100%;
+ height: 1px;
+
+ background-color: rgba(0, 0, 0, 0.05);
+ text-align: right;
+}
+
+.timeline-overview-graph.runloop > .divider > span {
+ padding-right: 1px;
+
+ font-family: Helvetica, sans-serif;
+ font-size: 8px;
+
+ color: rgba(0, 0, 0, 0.2);
+}
\ No newline at end of file
Added: trunk/Source/WebInspectorUI/UserInterface/Views/RunLoopTimelineOverviewGraph.js (0 => 181626)
--- trunk/Source/WebInspectorUI/UserInterface/Views/RunLoopTimelineOverviewGraph.js (rev 0)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/RunLoopTimelineOverviewGraph.js 2015-03-17 08:43:30 UTC (rev 181626)
@@ -0,0 +1,160 @@
+/*
+ * Copyright (C) 2015 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.RunLoopTimelineOverviewGraph = function(timeline)
+{
+ WebInspector.TimelineOverviewGraph.call(this, timeline);
+
+ this.element.classList.add(WebInspector.RunLoopTimelineOverviewGraph.StyleClassName);
+
+ this._runLoopTimeline = timeline;
+ this._timelineRecordFrames = [];
+ this._graphHeightSeconds = NaN;
+ this._framesPerSecondDividers = new Map;
+
+ this._runLoopTimeline.addEventListener(WebInspector.Timeline.Event.RecordAdded, this._timelineRecordAdded, this);
+
+ this.reset();
+};
+
+WebInspector.RunLoopTimelineOverviewGraph.StyleClassName = "runloop";
+WebInspector.RunLoopTimelineOverviewGraph.MaximumGraphHeightSeconds = 0.05;
+
+WebInspector.RunLoopTimelineOverviewGraph.prototype = {
+ constructor: WebInspector.RunLoopTimelineOverviewGraph,
+ __proto__: WebInspector.TimelineOverviewGraph.prototype,
+
+ // Public
+
+ get graphHeightSeconds()
+ {
+ if (!isNaN(this._graphHeightSeconds))
+ return this._graphHeightSeconds;
+
+ var maximumFrameDuration = this._runLoopTimeline.records.reduce(function(previousValue, currentValue) {
+ return Math.max(previousValue, currentValue.duration);
+ }, 0);
+
+ this._graphHeightSeconds = maximumFrameDuration * 1.1; // Add 10% margin above frames.
+ this._graphHeightSeconds = Math.min(this._graphHeightSeconds, WebInspector.RunLoopTimelineOverviewGraph.MaximumGraphHeightSeconds);
+ return this._graphHeightSeconds;
+ },
+
+ reset()
+ {
+ WebInspector.TimelineOverviewGraph.prototype.reset.call(this);
+
+ this.element.removeChildren();
+
+ this._framesPerSecondDividers.clear();
+ },
+
+ updateLayout()
+ {
+ WebInspector.TimelineOverviewGraph.prototype.updateLayout.call(this);
+
+ var secondsPerPixel = this.timelineOverview.secondsPerPixel;
+
+ var recordFrameIndex = 0;
+
+ function createFrame(records)
+ {
+ var timelineRecordFrame = this._timelineRecordFrames[recordFrameIndex];
+ if (!timelineRecordFrame)
+ timelineRecordFrame = this._timelineRecordFrames[recordFrameIndex] = new WebInspector.TimelineRecordFrame(this, records);
+ else
+ timelineRecordFrame.records = records;
+
+ timelineRecordFrame.refresh(this);
+ if (!timelineRecordFrame.element.parentNode)
+ this.element.appendChild(timelineRecordFrame.element);
+ ++recordFrameIndex;
+ }
+
+ WebInspector.TimelineRecordFrame.createCombinedFrames(this._runLoopTimeline.records, secondsPerPixel, this, createFrame.bind(this));
+
+ // Remove the remaining unused TimelineRecordFrames.
+ for (; recordFrameIndex < this._timelineRecordFrames.length; ++recordFrameIndex) {
+ this._timelineRecordFrames[recordFrameIndex].records = null;
+ this._timelineRecordFrames[recordFrameIndex].element.remove();
+ }
+
+ this._updateDividers();
+ },
+
+ // Private
+
+ _timelineRecordAdded(event)
+ {
+ this._graphHeightSeconds = NaN;
+
+ this.needsLayout();
+ },
+
+ _updateDividers()
+ {
+ if (this.graphHeightSeconds === 0)
+ return;
+
+ var overviewGraphHeight = this.element.offsetHeight;
+
+ function createDividerAtPosition(framesPerSecond)
+ {
+ var secondsPerFrame = 1 / framesPerSecond;
+ var dividerTop = 1 - secondsPerFrame / this.graphHeightSeconds;
+ if (dividerTop < 0.01 || dividerTop >= 1)
+ return;
+
+ var divider = this._framesPerSecondDividers.get(framesPerSecond);
+ if (!divider) {
+ divider = document.createElement("div");
+ divider.classList.add("divider");
+
+ var label = document.createElement("span");
+ label.innerText = framesPerSecond + " fps";
+ divider.appendChild(label);
+
+ this.element.appendChild(divider);
+
+ this._framesPerSecondDividers.set(framesPerSecond, divider);
+ }
+
+ divider.style.marginTop = (dividerTop * overviewGraphHeight).toFixed(2) + "px";
+ }
+
+ createDividerAtPosition.call(this, 60);
+ createDividerAtPosition.call(this, 30);
+ },
+
+ _updateElementPosition(element, newPosition, property)
+ {
+ newPosition *= 100;
+ newPosition = newPosition.toFixed(2);
+
+ var currentPosition = parseFloat(element.style[property]).toFixed(2);
+ if (currentPosition !== newPosition)
+ element.style[property] = newPosition + "%";
+ }
+};
Modified: trunk/Source/WebInspectorUI/UserInterface/Views/TimelineIcons.css (181625 => 181626)
--- trunk/Source/WebInspectorUI/UserInterface/Views/TimelineIcons.css 2015-03-17 08:41:19 UTC (rev 181625)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/TimelineIcons.css 2015-03-17 08:43:30 UTC (rev 181626)
@@ -63,6 +63,14 @@
content: -webkit-image-set(url(../Images/ScriptLarge.png) 1x, url(../Images/[email protected]) 2x);
}
+.runloop-icon .icon {
+ content: -webkit-image-set(url(../Images/Frames.png) 1x, url(../Images/[email protected]) 2x);
+}
+
+.runloop-icon.large .icon {
+ content: -webkit-image-set(url(../Images/FramesLarge.png) 1x, url(../Images/[email protected]) 2x);
+}
+
.stopwatch-icon .icon {
content: -webkit-image-set(url(../Images/Stopwatch.png) 1x, url(../Images/[email protected]) 2x);
}
@@ -83,6 +91,10 @@
content: url(../Images/TimelineRecordPaint.svg);
}
+.runloop-record .icon {
+ content: -webkit-image-set(url(../Images/Frames.png) 1x, url(../Images/[email protected]) 2x);
+}
+
.evaluated-record .icon {
content: url(../Images/TimelineRecordScriptEvaluated.svg);
}
Modified: trunk/Source/WebInspectorUI/UserInterface/Views/TimelineOverviewGraph.js (181625 => 181626)
--- trunk/Source/WebInspectorUI/UserInterface/Views/TimelineOverviewGraph.js 2015-03-17 08:41:19 UTC (rev 181625)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/TimelineOverviewGraph.js 2015-03-17 08:43:30 UTC (rev 181626)
@@ -40,6 +40,9 @@
if (timelineType === WebInspector.TimelineRecord.Type.Script)
return new WebInspector.ScriptTimelineOverviewGraph(timeline);
+ if (timelineType === WebInspector.TimelineRecord.Type.RunLoop)
+ return new WebInspector.RunLoopTimelineOverviewGraph(timeline);
+
throw Error("Can't make a graph for an unknown timeline.");
}
Added: trunk/Source/WebInspectorUI/UserInterface/Views/TimelineRecordFrame.css (0 => 181626)
--- trunk/Source/WebInspectorUI/UserInterface/Views/TimelineRecordFrame.css (rev 0)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/TimelineRecordFrame.css 2015-03-17 08:43:30 UTC (rev 181626)
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2015 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.
+ */
+
+.timeline-record-frame {
+ position: absolute;
+ height: 36px;
+ min-width: 6px;
+
+ overflow: hidden;
+
+ -webkit-mask-image: -webkit-linear-gradient(rgba(0, 0, 0, 0), rgba(0, 0, 0, 1) 10%);
+}
+
+.timeline-record-frame > .frame {
+ position: absolute;
+ z-index: 1;
+ bottom: 1px;
+ min-width: 6px;
+
+ box-sizing: border-box;
+}
+
+.timeline-record-frame > .dropped {
+ position: absolute;
+ bottom: 1px;
+ right: 0;
+
+ min-width: 6px;
+ box-sizing: border-box;
+
+ background: repeating-linear-gradient(-45deg, white, white 2px, rgb(234, 234, 234) 2px, rgb(234, 234, 234) 4px);
+
+ border-top-style: solid;
+ border-right-style: solid;
+ border-width: 1px;
+ border-color: rgb(221, 221, 221);
+}
+
+.timeline-record-frame > .frame > .duration {
+ box-sizing: border-box;
+
+ background-color: rgb(221, 221, 221);
+
+ border-color: rgb(176, 176, 176);
+ border-style: none solid solid solid;
+ border-width: 1px;
+}
+
+.timeline-record-frame > .frame > .duration:first-child {
+ border-top-style: solid;
+}
+
+.timeline-record-frame > .frame > .duration:last-child {
+ border-bottom-style: none;
+}
+
+.timeline-record-frame > .frame > .duration.timeline-record-type-network {
+ background-color: rgb(120, 176, 225);
+ border-color: rgb(61, 147, 200);
+}
+
+.timeline-record-frame > .frame > .duration.timeline-record-type-layout {
+ background-color: rgb(234, 153, 153);
+ border-color: rgb(212, 108, 108);
+}
+
+.timeline-record-frame > .frame > .duration.timeline-record-type-script {
+ background-color: rgb(190, 148, 233);
+ border-color: rgb(153, 113, 185);
+}
Added: trunk/Source/WebInspectorUI/UserInterface/Views/TimelineRecordFrame.js (0 => 181626)
--- trunk/Source/WebInspectorUI/UserInterface/Views/TimelineRecordFrame.js (rev 0)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/TimelineRecordFrame.js 2015-03-17 08:43:30 UTC (rev 181626)
@@ -0,0 +1,261 @@
+/*
+ * Copyright (C) 2015 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.TimelineRecordFrame = function(graphDataSource, records)
+{
+ WebInspector.Object.call(this);
+
+ this._element = document.createElement("div");
+ this._element.classList.add(WebInspector.TimelineRecordFrame.StyleClassName);
+
+ this._graphDataSource = graphDataSource;
+ this.records = records || [];
+};
+
+WebInspector.Object.addConstructorFunctions(WebInspector.TimelineRecordFrame);
+
+WebInspector.TimelineRecordFrame.StyleClassName = "timeline-record-frame";
+WebInspector.TimelineRecordFrame.SixtyFpsFrameBudget = 0.0166;
+WebInspector.TimelineRecordFrame.MinimumWidthPixels = 6;
+WebInspector.TimelineRecordFrame.MinimumMarginPixels = 1;
+
+WebInspector.TimelineRecordFrame.createCombinedFrames = function(records, secondsPerPixel, graphDataSource, createFrameCallback)
+{
+ if (!records.length)
+ return;
+
+ var startTime = graphDataSource.startTime;
+ var currentTime = graphDataSource.currentTime;
+ var endTime = graphDataSource.endTime;
+
+ var visibleRecords = [];
+
+ for (var record of records) {
+ if (isNaN(record.startTime))
+ continue;
+
+ // If this frame is completely before the bounds of the graph, skip this record.
+ if (record.endTime < startTime)
+ continue;
+
+ // If this record is completely after the current time or end time, break out now.
+ // Records are sorted, so all records after this will be beyond the current or end time too.
+ if (record.startTime > currentTime || record.startTime > endTime)
+ break;
+
+ visibleRecords.push(record);
+ }
+
+ if (!visibleRecords.length)
+ return;
+
+ var minimumFrameDuration = secondsPerPixel * WebInspector.TimelineRecordFrame.MinimumWidthPixels;
+ var minimumMargin = secondsPerPixel * WebInspector.TimelineRecordFrame.MinimumMarginPixels;
+
+ var activeStartTime = NaN;
+ var activeEndTime = NaN;
+ var activeRecords = [];
+
+ for (var record of visibleRecords) {
+ // Check if the previous record is far enough away to create the frame.
+ if (!isNaN(activeStartTime) && (activeStartTime + Math.max(activeEndTime - activeStartTime, minimumFrameDuration) + minimumMargin <= record.startTime)) {
+ createFrameCallback(activeRecords);
+ activeRecords = [];
+ activeStartTime = NaN;
+ activeEndTime = NaN;
+ }
+
+ // If this is a new frame, peg the start time.
+ if (isNaN(activeStartTime))
+ activeStartTime = record.startTime;
+
+ // Update the end time to be the maximum we encounter. endTime might be NaN, so "|| 0" to prevent Math.max from returning NaN.
+ if (!isNaN(record.endTime))
+ activeEndTime = Math.max(activeEndTime || 0, record.endTime);
+
+ activeRecords.push(record);
+ }
+
+ // Create the active frame for the last record if needed.
+ if (!isNaN(activeStartTime))
+ createFrameCallback(activeRecords);
+};
+
+WebInspector.TimelineRecordFrame.prototype = {
+ constructor: WebInspector.TimelineRecordFrame,
+ __proto__: WebInspector.Object.prototype,
+
+ // Public
+
+ get element()
+ {
+ return this._element;
+ },
+
+ get duration()
+ {
+ if (this.records.length === 0)
+ return 0;
+
+ return this.records.lastValue.endTime - this.records[0].startTime;
+ },
+
+ get records()
+ {
+ return this._records;
+ },
+
+ set records(records)
+ {
+ records = records || [];
+
+ if (!(records instanceof Array))
+ records = [records];
+
+ this._records = records;
+ },
+
+ refresh(graphDataSource)
+ {
+ if (!this.records || !this.records.length)
+ return false;
+
+ var firstRecord = this.records[0];
+ var frameStartTime = firstRecord.startTime;
+
+ // If this frame has no time info, return early.
+ if (isNaN(frameStartTime))
+ return false;
+
+ var graphStartTime = graphDataSource.startTime;
+ var graphEndTime = graphDataSource.endTime;
+ var graphCurrentTime = graphDataSource.currentTime;
+
+ // If this frame is completely after the current time, return early.
+ if (frameStartTime > graphCurrentTime)
+ return false;
+
+ var frameEndTime = this.records.lastValue.endTime;
+
+ // If this frame is completely before or after the bounds of the graph, return early.
+ if (frameEndTime < graphStartTime || frameStartTime > graphEndTime)
+ return false;
+
+ var graphDuration = graphEndTime - graphStartTime;
+ var recordLeftPosition = (frameStartTime - graphStartTime) / graphDuration;
+ this._updateElementPosition(this._element, recordLeftPosition, "left");
+
+ var recordWidth = ((frameEndTime - graphStartTime) / graphDuration) - recordLeftPosition;
+ this._updateElementPosition(this._element, recordWidth, "width");
+
+ this._updateChildElements(graphDataSource);
+
+ return true;
+ },
+
+ // Private
+
+ _updateChildElements(graphDataSource)
+ {
+ this._element.removeChildren();
+
+ console.assert(this.records.length);
+ if (!this.records.length)
+ return;
+
+ if (graphDataSource.graphHeightSeconds === 0)
+ return;
+
+ // When combining multiple records into a frame, display the record with the longest duration rather than averaging.
+ var displayRecord = this.records.reduce(function(previousValue, currentValue) {
+ return currentValue.duration >= previousValue.duration ? currentValue : previousValue;
+ });
+
+ var frameElement = document.createElement("div");
+ frameElement.classList.add("frame");
+ this._element.appendChild(frameElement);
+
+ var frameHeight = displayRecord.duration / graphDataSource.graphHeightSeconds;
+ this._updateElementPosition(frameElement, frameHeight, "height");
+
+ function createDurationElement(duration, recordType)
+ {
+ var element = document.createElement("div");
+ this._updateElementPosition(element, duration / displayRecord.duration, "height");
+ element.classList.add("duration");
+ if (recordType)
+ element.classList.add(recordType);
+ return element;
+ }
+
+ for (type in WebInspector.TimelineRecord.Type) {
+ var recordType = WebInspector.TimelineRecord.Type[type];
+ var duration = displayRecord.durationForRecords(recordType);
+ if (duration === 0)
+ continue;
+ frameElement.appendChild(createDurationElement.call(this, duration, recordType));
+ }
+
+ if (displayRecord.durationRemainder > 0)
+ frameElement.appendChild(createDurationElement.call(this, displayRecord.durationRemainder));
+
+ // Add "includes-dropped" style class if multiple records are being combined in the frame,
+ // and one of those records exceeds the 60 fps frame budget.
+ if (this.records.length > 1 && displayRecord.duration > WebInspector.TimelineRecordFrame.SixtyFpsFrameBudget)
+ frameElement.classList.add("includes-dropped");
+
+ // If the display record is the last combined record and also exceeds the 60 fps budget,
+ // add a "dropped" element to the right of the frame.
+ var frameWidth = 1;
+ var secondsPerPixel = this._graphDataSource.timelineOverview.secondsPerPixel;
+ var minimumRecordDuration = secondsPerPixel * WebInspector.TimelineRecordFrame.MinimumWidthPixels * 2; // Combine minimum widths of the frame element and dropped element.
+
+ if (displayRecord === this.records.lastValue && displayRecord.duration > WebInspector.TimelineRecordFrame.SixtyFpsFrameBudget && displayRecord.duration >= minimumRecordDuration) {
+ var overflowDuration = displayRecord.duration - WebInspector.TimelineRecordFrame.SixtyFpsFrameBudget;
+ var droppedElementWidth = overflowDuration / displayRecord.duration;
+ frameWidth -= droppedElementWidth;
+
+ var droppedElement = document.createElement("div");
+ droppedElement.className = "dropped";
+
+ this._element.appendChild(droppedElement);
+
+ this._updateElementPosition(droppedElement, frameHeight, "height");
+ this._updateElementPosition(droppedElement, droppedElementWidth, "width");
+ }
+
+ this._updateElementPosition(frameElement, frameWidth, "width");
+ },
+
+ _updateElementPosition(element, newPosition, property)
+ {
+ newPosition *= 100;
+ newPosition = newPosition.toFixed(2);
+
+ var currentPosition = parseFloat(element.style[property]).toFixed(2);
+ if (currentPosition !== newPosition)
+ element.style[property] = newPosition + "%";
+ }
+};
Modified: trunk/Source/WebInspectorUI/UserInterface/Views/TimelineRecordTreeElement.js (181625 => 181626)
--- trunk/Source/WebInspectorUI/UserInterface/Views/TimelineRecordTreeElement.js 2015-03-17 08:41:19 UTC (rev 181625)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/TimelineRecordTreeElement.js 2015-03-17 08:43:30 UTC (rev 181626)
@@ -99,6 +99,11 @@
break;
+ case WebInspector.TimelineRecord.Type.RunLoop:
+ title = WebInspector.UIString("Runloop Executed");
+ iconStyleClass = WebInspector.TimelineRecordTreeElement.RunLoopRecordIconStyleClass;
+ break;
+
default:
console.error("Unknown TimelineRecord type: " + timelineRecord.type, timelineRecord);
}
@@ -114,6 +119,7 @@
WebInspector.TimelineRecordTreeElement.StyleRecordIconStyleClass = "style-record";
WebInspector.TimelineRecordTreeElement.LayoutRecordIconStyleClass = "layout-record";
WebInspector.TimelineRecordTreeElement.PaintRecordIconStyleClass = "paint-record";
+WebInspector.TimelineRecordTreeElement.RunLoopRecordIconStyleClass = "runloop-record";
WebInspector.TimelineRecordTreeElement.EvaluatedRecordIconStyleClass = "evaluated-record";
WebInspector.TimelineRecordTreeElement.EventRecordIconStyleClass = "event-record";
WebInspector.TimelineRecordTreeElement.TimerRecordIconStyleClass = "timer-record";
Modified: trunk/Source/WebInspectorUI/UserInterface/Views/TimelineSidebarPanel.js (181625 => 181626)
--- trunk/Source/WebInspectorUI/UserInterface/Views/TimelineSidebarPanel.js 2015-03-17 08:41:19 UTC (rev 181625)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/TimelineSidebarPanel.js 2015-03-17 08:43:30 UTC (rev 181626)
@@ -139,6 +139,7 @@
WebInspector.TimelineSidebarPanel.NetworkIconStyleClass = "network-icon";
WebInspector.TimelineSidebarPanel.ColorsIconStyleClass = "colors-icon";
WebInspector.TimelineSidebarPanel.ScriptIconStyleClass = "script-icon";
+WebInspector.TimelineSidebarPanel.RunLoopIconStyleClass = "runloop-icon";
WebInspector.TimelineSidebarPanel.TimelineRecordingContentViewShowingStyleClass = "timeline-recording-content-view-showing";
WebInspector.TimelineSidebarPanel.ShowingTimelineRecordingContentViewCookieKey = "timeline-sidebar-panel-showing-timeline-recording-content-view";
Modified: trunk/Source/WebInspectorUI/WebInspectorUI.vcxproj/WebInspectorUI.vcxproj (181625 => 181626)
--- trunk/Source/WebInspectorUI/WebInspectorUI.vcxproj/WebInspectorUI.vcxproj 2015-03-17 08:41:19 UTC (rev 181625)
+++ trunk/Source/WebInspectorUI/WebInspectorUI.vcxproj/WebInspectorUI.vcxproj 2015-03-17 08:43:30 UTC (rev 181626)
@@ -525,6 +525,10 @@
<None Include="..\UserInterface\Images\FolderGeneric.png" />
<None Include="..\UserInterface\Images\ForwardArrow.svg" />
<None Include="..\UserInterface\Images\ForwardArrowLegacy.svg" />
+ <None Include="..\UserInterface\Images\Frames.png" />
+ <None Include="..\UserInterface\Images\Frames%402x.png" />
+ <None Include="..\UserInterface\Images\FramesLarge.png" />
+ <None Include="..\UserInterface\Images\FramesLarge%402x.png" />
<None Include="..\UserInterface\Images\Function.svg" />
<None Include="..\UserInterface\Images\GoToArrow.svg" />
<None Include="..\UserInterface\Images\HierarchicalNavigationItemChevron.svg" />
@@ -747,6 +751,9 @@
<None Include="..\UserInterface\Revision.js" />
<None Include="..\UserInterface\RulesStyleDetailsPanel.css" />
<None Include="..\UserInterface\RulesStyleDetailsPanel.js" />
+ <None Include="..\UserInterface\RunLoopTimelineOverviewGraph.css" />
+ <None Include="..\UserInterface\RunLoopTimelineOverviewGraph.js" />
+ <None Include="..\UserInterface\RunLoopTimelineRecord.js" />
<None Include="..\UserInterface\RuntimeObserver.js" />
<None Include="..\UserInterface\ScopeBar.css" />
<None Include="..\UserInterface\ScopeBar.js" />
@@ -808,6 +815,8 @@
<None Include="..\UserInterface\TimelineOverview.css" />
<None Include="..\UserInterface\TimelineOverview.js" />
<None Include="..\UserInterface\TimelineRecord.js" />
+ <None Include="..\UserInterface\TimelineRecordFrame.css" />
+ <None Include="..\UserInterface\TimelineRecordFrame.js" />
<None Include="..\UserInterface\TimelinesContentView.css" />
<None Include="..\UserInterface\TimelinesContentView.js" />
<None Include="..\UserInterface\TimelinesObject.js" />
Modified: trunk/Source/WebInspectorUI/WebInspectorUI.vcxproj/WebInspectorUI.vcxproj.filters (181625 => 181626)
--- trunk/Source/WebInspectorUI/WebInspectorUI.vcxproj/WebInspectorUI.vcxproj.filters 2015-03-17 08:41:19 UTC (rev 181625)
+++ trunk/Source/WebInspectorUI/WebInspectorUI.vcxproj/WebInspectorUI.vcxproj.filters 2015-03-17 08:43:30 UTC (rev 181626)
@@ -825,6 +825,15 @@
<None Include="..\UserInterface\RulesStyleDetailsPanel.js">
<Filter>UserInterface</Filter>
</None>
+ <None Include="..\UserInterface\RunLoopTimelineOverviewGraph.css">
+ <Filter>UserInterface</Filter>
+ </None>
+ <None Include="..\UserInterface\RunLoopTimelineOverviewGraph.js">
+ <Filter>UserInterface</Filter>
+ </None>
+ <None Include="..\UserInterface\RunLoopTimelineRecord.js">
+ <Filter>UserInterface</Filter>
+ </None>
<None Include="..\UserInterface\RuntimeObserver.js">
<Filter>UserInterface</Filter>
</None>
@@ -1008,6 +1017,12 @@
<None Include="..\UserInterface\TimelineRecord.js">
<Filter>UserInterface</Filter>
</None>
+ <None Include="..\UserInterface\TimelineRecordFrame.css">
+ <Filter>UserInterface</Filter>
+ </None>
+ <None Include="..\UserInterface\TimelineRecordFrame.js">
+ <Filter>UserInterface</Filter>
+ </None>
<None Include="..\UserInterface\TimelinesContentView.css">
<Filter>UserInterface</Filter>
</None>