<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[181626] trunk/Source/WebInspectorUI</title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://trac.webkit.org/projects/webkit/changeset/181626">181626</a></dd>
<dt>Author</dt> <dd>commit-queue@webkit.org</dd>
<dt>Date</dt> <dd>2015-03-17 01:43:30 -0700 (Tue, 17 Mar 2015)</dd>
</dl>

<h3>Log Message</h3>
<pre>Web Inspector: Show rendering frames (and FPS) in Layout and Rendering timeline
https://bugs.webkit.org/show_bug.cgi?id=142029

Patch by Matt Baker &lt;mattbaker@apple.com&gt; on 2015-03-17
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 &amp; Rendering timeline. Until the views
for the new timeline are finalized the Layout &amp; 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/Frames@2x.png: Added.
* UserInterface/Images/FramesLarge.png: Added.
* UserInterface/Images/FramesLarge@2x.png: 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 &gt; .divider):
(.timeline-overview-graph.runloop &gt; .divider &gt; 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 &gt; .frame):
(.timeline-record-frame &gt; .dropped):
(.timeline-record-frame &gt; .frame &gt; .duration):
(.timeline-record-frame &gt; .frame &gt; .duration:first-child):
(.timeline-record-frame &gt; .frame &gt; .duration:last-child):
(.timeline-record-frame &gt; .frame &gt; .duration.timeline-record-type-network):
(.timeline-record-frame &gt; .frame &gt; .duration.timeline-record-type-layout):
(.timeline-record-frame &gt; .frame &gt; .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.</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkSourceWebInspectorUIChangeLog">trunk/Source/WebInspectorUI/ChangeLog</a></li>
<li><a href="#trunkSourceWebInspectorUILocalizationsenlprojlocalizedStringsjs">trunk/Source/WebInspectorUI/Localizations/en.lproj/localizedStrings.js</a></li>
<li><a href="#trunkSourceWebInspectorUIUserInterfaceControllersTimelineManagerjs">trunk/Source/WebInspectorUI/UserInterface/Controllers/TimelineManager.js</a></li>
<li><a href="#trunkSourceWebInspectorUIUserInterfaceMainhtml">trunk/Source/WebInspectorUI/UserInterface/Main.html</a></li>
<li><a href="#trunkSourceWebInspectorUIUserInterfaceModelsTimelinejs">trunk/Source/WebInspectorUI/UserInterface/Models/Timeline.js</a></li>
<li><a href="#trunkSourceWebInspectorUIUserInterfaceModelsTimelineRecordjs">trunk/Source/WebInspectorUI/UserInterface/Models/TimelineRecord.js</a></li>
<li><a href="#trunkSourceWebInspectorUIUserInterfaceViewsContentViewjs">trunk/Source/WebInspectorUI/UserInterface/Views/ContentView.js</a></li>
<li><a href="#trunkSourceWebInspectorUIUserInterfaceViewsLayoutTimelineViewjs">trunk/Source/WebInspectorUI/UserInterface/Views/LayoutTimelineView.js</a></li>
<li><a href="#trunkSourceWebInspectorUIUserInterfaceViewsTimelineIconscss">trunk/Source/WebInspectorUI/UserInterface/Views/TimelineIcons.css</a></li>
<li><a href="#trunkSourceWebInspectorUIUserInterfaceViewsTimelineOverviewGraphjs">trunk/Source/WebInspectorUI/UserInterface/Views/TimelineOverviewGraph.js</a></li>
<li><a href="#trunkSourceWebInspectorUIUserInterfaceViewsTimelineRecordTreeElementjs">trunk/Source/WebInspectorUI/UserInterface/Views/TimelineRecordTreeElement.js</a></li>
<li><a href="#trunkSourceWebInspectorUIUserInterfaceViewsTimelineSidebarPaneljs">trunk/Source/WebInspectorUI/UserInterface/Views/TimelineSidebarPanel.js</a></li>
<li><a href="#trunkSourceWebInspectorUIWebInspectorUIvcxprojWebInspectorUIvcxproj">trunk/Source/WebInspectorUI/WebInspectorUI.vcxproj/WebInspectorUI.vcxproj</a></li>
<li><a href="#trunkSourceWebInspectorUIWebInspectorUIvcxprojWebInspectorUIvcxprojfilters">trunk/Source/WebInspectorUI/WebInspectorUI.vcxproj/WebInspectorUI.vcxproj.filters</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#trunkSourceWebInspectorUIUserInterfaceImagesFramespng">trunk/Source/WebInspectorUI/UserInterface/Images/Frames.png</a></li>
<li><a href="#trunkSourceWebInspectorUIUserInterfaceImagesFrames2xpng">trunk/Source/WebInspectorUI/UserInterface/Images/Frames@2x.png</a></li>
<li><a href="#trunkSourceWebInspectorUIUserInterfaceImagesFramesLargepng">trunk/Source/WebInspectorUI/UserInterface/Images/FramesLarge.png</a></li>
<li><a href="#trunkSourceWebInspectorUIUserInterfaceImagesFramesLarge2xpng">trunk/Source/WebInspectorUI/UserInterface/Images/FramesLarge@2x.png</a></li>
<li><a href="#trunkSourceWebInspectorUIUserInterfaceModelsRunLoopTimelineRecordjs">trunk/Source/WebInspectorUI/UserInterface/Models/RunLoopTimelineRecord.js</a></li>
<li><a href="#trunkSourceWebInspectorUIUserInterfaceViewsRunLoopTimelineOverviewGraphcss">trunk/Source/WebInspectorUI/UserInterface/Views/RunLoopTimelineOverviewGraph.css</a></li>
<li><a href="#trunkSourceWebInspectorUIUserInterfaceViewsRunLoopTimelineOverviewGraphjs">trunk/Source/WebInspectorUI/UserInterface/Views/RunLoopTimelineOverviewGraph.js</a></li>
<li><a href="#trunkSourceWebInspectorUIUserInterfaceViewsTimelineRecordFramecss">trunk/Source/WebInspectorUI/UserInterface/Views/TimelineRecordFrame.css</a></li>
<li><a href="#trunkSourceWebInspectorUIUserInterfaceViewsTimelineRecordFramejs">trunk/Source/WebInspectorUI/UserInterface/Views/TimelineRecordFrame.js</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkSourceWebInspectorUIChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebInspectorUI/ChangeLog (181625 => 181626)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -1,3 +1,109 @@
</span><ins>+2015-03-17  Matt Baker  &lt;mattbaker@apple.com&gt;
+
+        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 &amp; Rendering timeline. Until the views
+        for the new timeline are finalized the Layout &amp; 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/Frames@2x.png: Added.
+        * UserInterface/Images/FramesLarge.png: Added.
+        * UserInterface/Images/FramesLarge@2x.png: 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 &gt; .divider):
+        (.timeline-overview-graph.runloop &gt; .divider &gt; 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 &gt; .frame):
+        (.timeline-record-frame &gt; .dropped):
+        (.timeline-record-frame &gt; .frame &gt; .duration):
+        (.timeline-record-frame &gt; .frame &gt; .duration:first-child):
+        (.timeline-record-frame &gt; .frame &gt; .duration:last-child):
+        (.timeline-record-frame &gt; .frame &gt; .duration.timeline-record-type-network):
+        (.timeline-record-frame &gt; .frame &gt; .duration.timeline-record-type-layout):
+        (.timeline-record-frame &gt; .frame &gt; .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.
+
</ins><span class="cx"> 2015-03-16  Joseph Pecoraro  &lt;pecoraro@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Web Inspector: Add more DOM Native Function parameter strings
</span></span></pre></div>
<a id="trunkSourceWebInspectorUILocalizationsenlprojlocalizedStringsjs"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebInspectorUI/Localizations/en.lproj/localizedStrings.js (181625 => 181626)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -397,6 +397,7 @@
</span><span class="cx"> localizedStrings[&quot;Reveal in Original Resource&quot;] = &quot;Reveal in Original Resource&quot;;
</span><span class="cx"> localizedStrings[&quot;Role&quot;] = &quot;Role&quot;;
</span><span class="cx"> localizedStrings[&quot;Rules&quot;] = &quot;Rules&quot;;
</span><ins>+localizedStrings[&quot;Runloop Executed&quot;] = &quot;Runloop Executed&quot;;
</ins><span class="cx"> localizedStrings[&quot;Scheme&quot;] = &quot;Scheme&quot;;
</span><span class="cx"> localizedStrings[&quot;Scope Chain&quot;] = &quot;Scope Chain&quot;;
</span><span class="cx"> localizedStrings[&quot;Script&quot;] = &quot;Script&quot;;
</span></span></pre></div>
<a id="trunkSourceWebInspectorUIUserInterfaceControllersTimelineManagerjs"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebInspectorUI/UserInterface/Controllers/TimelineManager.js (181625 => 181626)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -162,248 +162,268 @@
</span><span class="cx">         this.dispatchEventToListeners(WebInspector.TimelineManager.Event.CapturingStopped);
</span><span class="cx">     },
</span><span class="cx"> 
</span><del>-    eventRecorded: function(originalRecordPayload)
</del><ins>+    eventRecorded: function(recordPayload)
</ins><span class="cx">     {
</span><span class="cx">         // Called from WebInspector.TimelineObserver.
</span><span class="cx"> 
</span><span class="cx">         if (!this._isCapturing)
</span><span class="cx">             return;
</span><span class="cx"> 
</span><del>-        function processRecord(recordPayload, parentRecordPayload)
-        {
-            var startTime = this.activeRecording.computeElapsedTime(recordPayload.startTime);
-            var endTime = this.activeRecording.computeElapsedTime(recordPayload.endTime);
-            var callFrames = this._callFramesFromPayload(recordPayload.stackTrace);
</del><ins>+        var records = this._processNestedRecords(recordPayload);
+        records.forEach(function(currentValue) {
+            this._addRecord(currentValue);
+        }.bind(this));
+    },
</ins><span class="cx"> 
</span><del>-            var significantCallFrame = null;
-            if (callFrames) {
-                for (var i = 0; i &lt; callFrames.length; ++i) {
-                    if (callFrames[i].nativeCode)
-                        continue;
-                    significantCallFrame = callFrames[i];
-                    break;
-                }
-            }
</del><ins>+    pageDidLoad: function(timestamp)
+    {
+        if (isNaN(WebInspector.frameResourceManager.mainFrame.loadEventTimestamp))
+            WebInspector.frameResourceManager.mainFrame.markLoadEvent(this.activeRecording.computeElapsedTime(timestamp));
+    },
</ins><span class="cx"> 
</span><del>-            var sourceCodeLocation = significantCallFrame &amp;&amp; significantCallFrame.sourceCodeLocation;
</del><ins>+    // Private
</ins><span class="cx"> 
</span><del>-            switch (recordPayload.type) {
-            case TimelineAgent.EventType.MarkLoad:
-                console.assert(isNaN(endTime));
</del><ins>+    _processNestedRecords: function(childRecordPayloads, parentRecordPayload)
+    {
+        // Convert to a single item array if needed.
+        if (!(childRecordPayloads instanceof Array))
+            childRecordPayloads = [childRecordPayloads];
</ins><span class="cx"> 
</span><del>-                var frame = WebInspector.frameResourceManager.frameForIdentifier(recordPayload.frameId);
-                console.assert(frame);
-                if (!frame)
-                    break;
</del><ins>+        var records = [];
</ins><span class="cx"> 
</span><del>-                frame.markLoadEvent(startTime);
</del><ins>+        // 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;
</ins><span class="cx"> 
</span><del>-                if (!frame.isMainFrame())
-                    break;
</del><ins>+            if (entry.index &lt; recordPayloads.length) {
+                var recordPayload = recordPayloads[entry.index];
+                var record = this._processEvent(recordPayload, entry.parent);
+                if (record)
+                    records.push(record);
</ins><span class="cx"> 
</span><del>-                var eventMarker = new WebInspector.TimelineMarker(startTime, WebInspector.TimelineMarker.Type.LoadEvent);
-                this._activeRecording.addEventMarker(eventMarker);
</del><ins>+                if (recordPayload.children)
+                    stack.push({array: recordPayload.children, parent: recordPayload, index: 0});
+                ++entry.index;
+            } else
+                stack.pop();
+        }
</ins><span class="cx"> 
</span><del>-                this._stopAutoRecordingSoon();
</del><ins>+        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 &lt; callFrames.length; ++i) {
+                if (callFrames[i].nativeCode)
+                    continue;
+                significantCallFrame = callFrames[i];
</ins><span class="cx">                 break;
</span><ins>+            }
+        }
</ins><span class="cx"> 
</span><del>-            case TimelineAgent.EventType.MarkDOMContent:
-                console.assert(isNaN(endTime));
</del><ins>+        var sourceCodeLocation = significantCallFrame &amp;&amp; significantCallFrame.sourceCodeLocation;
</ins><span class="cx"> 
</span><del>-                var frame = WebInspector.frameResourceManager.frameForIdentifier(recordPayload.frameId);
-                console.assert(frame);
-                if (!frame)
-                    break;
</del><ins>+        switch (recordPayload.type) {
+        case TimelineAgent.EventType.ScheduleStyleRecalculation:
+            console.assert(isNaN(endTime));
</ins><span class="cx"> 
</span><del>-                frame.markDOMContentReadyEvent(startTime);
</del><ins>+            // 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);
</ins><span class="cx"> 
</span><del>-                if (!frame.isMainFrame())
-                    break;
</del><ins>+        case TimelineAgent.EventType.RecalculateStyles:
+            return new WebInspector.LayoutTimelineRecord(WebInspector.LayoutTimelineRecord.EventType.RecalculateStyles, startTime, endTime, callFrames, sourceCodeLocation);
</ins><span class="cx"> 
</span><del>-                var eventMarker = new WebInspector.TimelineMarker(startTime, WebInspector.TimelineMarker.Type.DOMContentEvent);
-                this._activeRecording.addEventMarker(eventMarker);
-                break;
</del><ins>+        case TimelineAgent.EventType.InvalidateLayout:
+            console.assert(isNaN(endTime));
</ins><span class="cx"> 
</span><del>-            case TimelineAgent.EventType.ScheduleStyleRecalculation:
-                console.assert(isNaN(endTime));
</del><ins>+            // 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);
</ins><span class="cx"> 
</span><del>-                // 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;
</del><ins>+        case TimelineAgent.EventType.Layout:
+            var layoutRecordType = sourceCodeLocation ? WebInspector.LayoutTimelineRecord.EventType.ForcedLayout : WebInspector.LayoutTimelineRecord.EventType.Layout;
</ins><span class="cx"> 
</span><del>-            case TimelineAgent.EventType.RecalculateStyles:
-                this._addRecord(new WebInspector.LayoutTimelineRecord(WebInspector.LayoutTimelineRecord.EventType.RecalculateStyles, startTime, endTime, callFrames, sourceCodeLocation));
-                break;
</del><ins>+            // COMPATIBILITY (iOS 6): Layout records did not contain area properties. This is not exposed via a quad &quot;root&quot;.
+            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);
</ins><span class="cx"> 
</span><del>-            case TimelineAgent.EventType.InvalidateLayout:
-                console.assert(isNaN(endTime));
</del><ins>+        case TimelineAgent.EventType.Paint:
+            // COMPATIBILITY (iOS 6): Paint records data contained x, y, width, height properties. This became a quad &quot;clip&quot;.
+            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);
</ins><span class="cx"> 
</span><del>-                // 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;
</del><ins>+        case TimelineAgent.EventType.RunLoop:
+            if (!recordPayload.children)
+                return null;
</ins><span class="cx"> 
</span><del>-            case TimelineAgent.EventType.Layout:
-                var layoutRecordType = sourceCodeLocation ? WebInspector.LayoutTimelineRecord.EventType.ForcedLayout : WebInspector.LayoutTimelineRecord.EventType.Layout;
</del><ins>+            var children = this._processNestedRecords(recordPayload.children, recordPayload);
+            return new WebInspector.RunLoopTimelineRecord(startTime, endTime, children);
</ins><span class="cx"> 
</span><del>-                // COMPATIBILITY (iOS 6): Layout records did not contain area properties. This is not exposed via a quad &quot;root&quot;.
-                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;
</del><ins>+        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;
</ins><span class="cx"> 
</span><del>-            case TimelineAgent.EventType.Paint:
-                // COMPATIBILITY (iOS 6): Paint records data contained x, y, width, height properties. This became a quad &quot;clip&quot;.
-                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));
</del><ins>+                    // FIXME: No column number is provided.
+                    sourceCodeLocation = scriptResource.createSourceCodeLocation(lineNumber, 0);
+                }
+            }
+
+            var profileData = recordPayload.data.profile;
+
+            switch (parentRecordPayload &amp;&amp; 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)
</ins><span class="cx">                 break;
</span><span class="cx"> 
</span><del>-            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;
</del><ins>+            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;
</ins><span class="cx"> 
</span><del>-                        // FIXME: No column number is provided.
-                        sourceCodeLocation = scriptResource.createSourceCodeLocation(lineNumber, 0);
-                    }
</del><ins>+                    // FIXME: No column number is provided.
+                    sourceCodeLocation = scriptResource.createSourceCodeLocation(lineNumber, 0);
</ins><span class="cx">                 }
</span><ins>+            }
</ins><span class="cx"> 
</span><del>-                var profileData = recordPayload.data.profile;
</del><ins>+            var profileData = recordPayload.data.profile;
</ins><span class="cx"> 
</span><del>-                switch (parentRecordPayload &amp;&amp; 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;
-                }
</del><ins>+            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, &quot;load&quot;, profileData);
+            case TimelineAgent.EventType.XHRReadyStateChange:
+                return new WebInspector.ScriptTimelineRecord(WebInspector.ScriptTimelineRecord.EventType.EventDispatched, startTime, endTime, callFrames, sourceCodeLocation, &quot;readystatechange&quot;, profileData);
+            case TimelineAgent.EventType.FireAnimationFrame:
+                return new WebInspector.ScriptTimelineRecord(WebInspector.ScriptTimelineRecord.EventType.AnimationFrameFired, startTime, endTime, callFrames, sourceCodeLocation, parentRecordPayload.data.id, profileData);
+            }
</ins><span class="cx"> 
</span><del>-                break;
</del><ins>+            break;
</ins><span class="cx"> 
</span><del>-            case TimelineAgent.EventType.TimeStamp:
-                var eventMarker = new WebInspector.TimelineMarker(startTime, WebInspector.TimelineMarker.Type.TimeStamp);
-                this._activeRecording.addEventMarker(eventMarker);
-                break;
</del><ins>+        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);
</ins><span class="cx"> 
</span><del>-            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;
</del><ins>+        case TimelineAgent.EventType.TimerInstall:
+            console.assert(isNaN(endTime));
</ins><span class="cx"> 
</span><del>-            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;
</del><ins>+            // 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);
</ins><span class="cx"> 
</span><del>-                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;
</del><ins>+        case TimelineAgent.EventType.TimerRemove:
+            console.assert(isNaN(endTime));
</ins><span class="cx"> 
</span><del>-                        // FIXME: No column number is provided.
-                        sourceCodeLocation = scriptResource.createSourceCodeLocation(lineNumber, 0);
-                    }
-                }
</del><ins>+            // 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);
</ins><span class="cx"> 
</span><del>-                var profileData = recordPayload.data.profile;
</del><ins>+        case TimelineAgent.EventType.RequestAnimationFrame:
+            console.assert(isNaN(endTime));
</ins><span class="cx"> 
</span><del>-                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, &quot;load&quot;, profileData));
-                    break;
-                case TimelineAgent.EventType.XHRReadyStateChange:
-                    this._addRecord(new WebInspector.ScriptTimelineRecord(WebInspector.ScriptTimelineRecord.EventType.EventDispatched, startTime, endTime, callFrames, sourceCodeLocation, &quot;readystatechange&quot;, profileData));
-                    break;
-                case TimelineAgent.EventType.FireAnimationFrame:
-                    this._addRecord(new WebInspector.ScriptTimelineRecord(WebInspector.ScriptTimelineRecord.EventType.AnimationFrameFired, startTime, endTime, callFrames, sourceCodeLocation, parentRecordPayload.data.id, profileData));
-                    break;
-                }
</del><ins>+            // 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);
</ins><span class="cx"> 
</span><del>-                break;
</del><ins>+        case TimelineAgent.EventType.CancelAnimationFrame:
+            console.assert(isNaN(endTime));
</ins><span class="cx"> 
</span><del>-            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;
</del><ins>+            // 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);
+        }
</ins><span class="cx"> 
</span><del>-            case TimelineAgent.EventType.TimerInstall:
-                console.assert(isNaN(endTime));
</del><ins>+        return null;
+    },
</ins><span class="cx"> 
</span><del>-                // 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));
</del><ins>+    _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)
</ins><span class="cx">                 break;
</span><span class="cx"> 
</span><del>-            case TimelineAgent.EventType.TimerRemove:
-                console.assert(isNaN(endTime));
</del><ins>+            frame.markLoadEvent(startTime);
</ins><span class="cx"> 
</span><del>-                // 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));
</del><ins>+            if (!frame.isMainFrame())
</ins><span class="cx">                 break;
</span><span class="cx"> 
</span><del>-            case TimelineAgent.EventType.RequestAnimationFrame:
-                console.assert(isNaN(endTime));
</del><ins>+            var eventMarker = new WebInspector.TimelineMarker(startTime, WebInspector.TimelineMarker.Type.LoadEvent);
+            this._activeRecording.addEventMarker(eventMarker);
</ins><span class="cx"> 
</span><del>-                // 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));
</del><ins>+            this._stopAutoRecordingSoon();
+            break;
+
+        case TimelineAgent.EventType.MarkDOMContent:
+            console.assert(isNaN(endTime));
+
+            var frame = WebInspector.frameResourceManager.frameForIdentifier(recordPayload.frameId);
+            console.assert(frame);
+            if (!frame)
</ins><span class="cx">                 break;
</span><span class="cx"> 
</span><del>-            case TimelineAgent.EventType.CancelAnimationFrame:
-                console.assert(isNaN(endTime));
</del><ins>+            frame.markDOMContentReadyEvent(startTime);
</ins><span class="cx"> 
</span><del>-                // 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));
</del><ins>+            if (!frame.isMainFrame())
</ins><span class="cx">                 break;
</span><del>-            }
-        }
</del><span class="cx"> 
</span><del>-        // 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;
</del><ins>+            var eventMarker = new WebInspector.TimelineMarker(startTime, WebInspector.TimelineMarker.Type.DOMContentEvent);
+            this._activeRecording.addEventMarker(eventMarker);
+            break;
</ins><span class="cx"> 
</span><del>-            if (entry.index &lt; recordPayloads.length) {
-                var recordPayload = recordPayloads[entry.index];
</del><ins>+        case TimelineAgent.EventType.TimeStamp:
+            var eventMarker = new WebInspector.TimelineMarker(startTime, WebInspector.TimelineMarker.Type.TimeStamp);
+            this._activeRecording.addEventMarker(eventMarker);
+            break;
</ins><span class="cx"> 
</span><del>-                processRecord.call(this, recordPayload, parentRecordPayload);
-
-                if (recordPayload.children)
-                    stack.push({array: recordPayload.children, parent: recordPayload, index: 0});
-                ++entry.index;
-            } else
-                stack.pop();
</del><ins>+        default:
+            return this._processRecord(recordPayload, parentRecordPayload);
</ins><span class="cx">         }
</span><del>-    },
</del><span class="cx"> 
</span><del>-    pageDidLoad: function(timestamp)
-    {
-        if (isNaN(WebInspector.frameResourceManager.mainFrame.loadEventTimestamp))
-            WebInspector.frameResourceManager.mainFrame.markLoadEvent(this.activeRecording.computeElapsedTime(timestamp));
</del><ins>+        return null;
</ins><span class="cx">     },
</span><span class="cx"> 
</span><del>-    // Private
-
</del><span class="cx">     _loadNewRecording: function()
</span><span class="cx">     {
</span><span class="cx">         if (this._activeRecording &amp;&amp; this._activeRecording.isEmpty())
</span><span class="lines">@@ -411,9 +431,10 @@
</span><span class="cx"> 
</span><span class="cx">         var identifier = this._nextRecordingIdentifier++;
</span><span class="cx">         var newRecording = new WebInspector.TimelineRecording(identifier, WebInspector.UIString(&quot;Timeline Recording %d&quot;).format(identifier));
</span><del>-        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));
</del><ins>+        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));
</ins><span class="cx"> 
</span><span class="cx">         this._recordings.push(newRecording);
</span><span class="cx">         this.dispatchEventToListeners(WebInspector.TimelineManager.Event.RecordingCreated, {recording: newRecording});
</span></span></pre></div>
<a id="trunkSourceWebInspectorUIUserInterfaceImagesFramespng"></a>
<div class="binary"><h4>Added: trunk/Source/WebInspectorUI/UserInterface/Images/Frames.png</h4>
<pre class="diff"><span>
<span class="cx">(Binary files differ)
</span></span></pre></div>
<span class="cx">Property changes on: trunk/Source/WebInspectorUI/UserInterface/Images/Frames.png
</span><span class="cx">___________________________________________________________________
</span><a id="svnmimetype"></a>
<div class="addfile"><h4>Added: svn:mime-type</h4></div>
<a id="trunkSourceWebInspectorUIUserInterfaceImagesFrames2xpng"></a>
<div class="binary"><h4>Added: trunk/Source/WebInspectorUI/UserInterface/Images/Frames@2x.png</h4>
<pre class="diff"><span>
<span class="cx">(Binary files differ)
</span></span></pre></div>
<span class="cx">Property changes on: trunk/Source/WebInspectorUI/UserInterface/Images/Frames@2x.png
</span><span class="cx">___________________________________________________________________
</span><a id="svnmimetype"></a>
<div class="addfile"><h4>Added: svn:mime-type</h4></div>
<a id="trunkSourceWebInspectorUIUserInterfaceImagesFramesLargepng"></a>
<div class="binary"><h4>Added: trunk/Source/WebInspectorUI/UserInterface/Images/FramesLarge.png</h4>
<pre class="diff"><span>
<span class="cx">(Binary files differ)
</span></span></pre></div>
<span class="cx">Property changes on: trunk/Source/WebInspectorUI/UserInterface/Images/FramesLarge.png
</span><span class="cx">___________________________________________________________________
</span><a id="svnmimetype"></a>
<div class="addfile"><h4>Added: svn:mime-type</h4></div>
<a id="trunkSourceWebInspectorUIUserInterfaceImagesFramesLarge2xpng"></a>
<div class="binary"><h4>Added: trunk/Source/WebInspectorUI/UserInterface/Images/FramesLarge@2x.png</h4>
<pre class="diff"><span>
<span class="cx">(Binary files differ)
</span></span></pre></div>
<span class="cx">Property changes on: trunk/Source/WebInspectorUI/UserInterface/Images/FramesLarge@2x.png
</span><span class="cx">___________________________________________________________________
</span><a id="svnmimetype"></a>
<div class="addfile"><h4>Added: svn:mime-type</h4></div>
<a id="trunkSourceWebInspectorUIUserInterfaceMainhtml"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebInspectorUI/UserInterface/Main.html (181625 => 181626)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -114,6 +114,7 @@
</span><span class="cx">     &lt;link rel=&quot;stylesheet&quot; href=&quot;Views/ResourceSidebarPanel.css&quot;&gt;
</span><span class="cx">     &lt;link rel=&quot;stylesheet&quot; href=&quot;Views/ResourceTreeElement.css&quot;&gt;
</span><span class="cx">     &lt;link rel=&quot;stylesheet&quot; href=&quot;Views/RulesStyleDetailsPanel.css&quot;&gt;
</span><ins>+    &lt;link rel=&quot;stylesheet&quot; href=&quot;Views/RunLoopTimelineOverviewGraph.css&quot;&gt;
</ins><span class="cx">     &lt;link rel=&quot;stylesheet&quot; href=&quot;Views/ScopeBar.css&quot;&gt;
</span><span class="cx">     &lt;link rel=&quot;stylesheet&quot; href=&quot;Views/ScriptContentView.css&quot;&gt;
</span><span class="cx">     &lt;link rel=&quot;stylesheet&quot; href=&quot;Views/ScriptTimelineOverviewGraph.css&quot;&gt;
</span><span class="lines">@@ -134,6 +135,7 @@
</span><span class="cx">     &lt;link rel=&quot;stylesheet&quot; href=&quot;Views/TimelineIcons.css&quot;&gt;
</span><span class="cx">     &lt;link rel=&quot;stylesheet&quot; href=&quot;Views/TimelineOverview.css&quot;&gt;
</span><span class="cx">     &lt;link rel=&quot;stylesheet&quot; href=&quot;Views/TimelineRecordBar.css&quot;&gt;
</span><ins>+    &lt;link rel=&quot;stylesheet&quot; href=&quot;Views/TimelineRecordFrame.css&quot;&gt;
</ins><span class="cx">     &lt;link rel=&quot;stylesheet&quot; href=&quot;Views/TimelineRecordingContentView.css&quot;&gt;
</span><span class="cx">     &lt;link rel=&quot;stylesheet&quot; href=&quot;Views/TimelineRuler.css&quot;&gt;
</span><span class="cx">     &lt;link rel=&quot;stylesheet&quot; href=&quot;Views/TimelineSidebarPanel.css&quot;&gt;
</span><span class="lines">@@ -272,6 +274,7 @@
</span><span class="cx">     &lt;script src=&quot;Models/ResourceCollection.js&quot;&gt;&lt;/script&gt;
</span><span class="cx">     &lt;script src=&quot;Models/ResourceTimelineRecord.js&quot;&gt;&lt;/script&gt;
</span><span class="cx">     &lt;script src=&quot;Models/Revision.js&quot;&gt;&lt;/script&gt;
</span><ins>+    &lt;script src=&quot;Models/RunLoopTimelineRecord.js&quot;&gt;&lt;/script&gt;
</ins><span class="cx">     &lt;script src=&quot;Models/ScopeChainNode.js&quot;&gt;&lt;/script&gt;
</span><span class="cx">     &lt;script src=&quot;Models/Script.js&quot;&gt;&lt;/script&gt;
</span><span class="cx">     &lt;script src=&quot;Models/ScriptSyntaxTree.js&quot;&gt;&lt;/script&gt;
</span><span class="lines">@@ -448,6 +451,7 @@
</span><span class="cx">     &lt;script src=&quot;Views/ResourceTimelineDataGridNode.js&quot;&gt;&lt;/script&gt;
</span><span class="cx">     &lt;script src=&quot;Views/ResourceTimelineDataGridNodePathComponent.js&quot;&gt;&lt;/script&gt;
</span><span class="cx">     &lt;script src=&quot;Views/RulesStyleDetailsPanel.js&quot;&gt;&lt;/script&gt;
</span><ins>+    &lt;script src=&quot;Views/RunLoopTimelineOverviewGraph.js&quot;&gt;&lt;/script&gt;
</ins><span class="cx">     &lt;script src=&quot;Views/ScopeBar.js&quot;&gt;&lt;/script&gt;
</span><span class="cx">     &lt;script src=&quot;Views/ScopeBarItem.js&quot;&gt;&lt;/script&gt;
</span><span class="cx">     &lt;script src=&quot;Views/ScopeChainDetailsSidebarPanel.js&quot;&gt;&lt;/script&gt;
</span><span class="lines">@@ -471,6 +475,7 @@
</span><span class="cx">     &lt;script src=&quot;Views/TextResourceContentView.js&quot;&gt;&lt;/script&gt;
</span><span class="cx">     &lt;script src=&quot;Views/TimelineOverview.js&quot;&gt;&lt;/script&gt;
</span><span class="cx">     &lt;script src=&quot;Views/TimelineRecordBar.js&quot;&gt;&lt;/script&gt;
</span><ins>+    &lt;script src=&quot;Views/TimelineRecordFrame.js&quot;&gt;&lt;/script&gt;
</ins><span class="cx">     &lt;script src=&quot;Views/TimelineRecordingContentView.js&quot;&gt;&lt;/script&gt;
</span><span class="cx">     &lt;script src=&quot;Views/TimelineRuler.js&quot;&gt;&lt;/script&gt;
</span><span class="cx">     &lt;script src=&quot;Views/TimelineSidebarPanel.js&quot;&gt;&lt;/script&gt;
</span></span></pre></div>
<a id="trunkSourceWebInspectorUIUserInterfaceModelsRunLoopTimelineRecordjs"></a>
<div class="addfile"><h4>Added: trunk/Source/WebInspectorUI/UserInterface/Models/RunLoopTimelineRecord.js (0 => 181626)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,78 @@
</span><ins>+/*
+ * 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 = &quot;runloop-timeline-record&quot;;
+
+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;
+    }
+};
</ins></span></pre></div>
<a id="trunkSourceWebInspectorUIUserInterfaceModelsTimelinejs"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebInspectorUI/UserInterface/Models/Timeline.js (181625 => 181626)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -80,6 +80,8 @@
</span><span class="cx">             return WebInspector.UIString(&quot;Layout &amp; Rendering&quot;);
</span><span class="cx">         if (this._type === WebInspector.TimelineRecord.Type.Script)
</span><span class="cx">             return WebInspector.UIString(&quot;JavaScript &amp; Events&quot;);
</span><ins>+        if (this._type === WebInspector.TimelineRecord.Type.RunLoop)
+            return WebInspector.UIString(&quot;Frames&quot;);
</ins><span class="cx"> 
</span><span class="cx">         console.error(&quot;Timeline has unknown type:&quot;, this._type, this);
</span><span class="cx">     },
</span><span class="lines">@@ -90,6 +92,8 @@
</span><span class="cx">             return WebInspector.TimelineSidebarPanel.NetworkIconStyleClass;
</span><span class="cx">         if (this._type === WebInspector.TimelineRecord.Type.Layout)
</span><span class="cx">             return WebInspector.TimelineSidebarPanel.ColorsIconStyleClass;
</span><ins>+        if (this._type === WebInspector.TimelineRecord.Type.RunLoop)
+            return WebInspector.TimelineSidebarPanel.RunLoopIconStyleClass;
</ins><span class="cx">         if (this._type === WebInspector.TimelineRecord.Type.Script)
</span><span class="cx">             return WebInspector.TimelineSidebarPanel.ScriptIconStyleClass;
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceWebInspectorUIUserInterfaceModelsTimelineRecordjs"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebInspectorUI/UserInterface/Models/TimelineRecord.js (181625 => 181626)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -46,7 +46,8 @@
</span><span class="cx"> WebInspector.TimelineRecord.Type = {
</span><span class="cx">     Network: &quot;timeline-record-type-network&quot;,
</span><span class="cx">     Layout: &quot;timeline-record-type-layout&quot;,
</span><del>-    Script: &quot;timeline-record-type-script&quot;
</del><ins>+    Script: &quot;timeline-record-type-script&quot;,
+    RunLoop: &quot;timeline-record-type-runloop&quot;
</ins><span class="cx"> };
</span><span class="cx"> 
</span><span class="cx"> WebInspector.TimelineRecord.TypeIdentifier = &quot;timeline-record&quot;;
</span></span></pre></div>
<a id="trunkSourceWebInspectorUIUserInterfaceViewsContentViewjs"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebInspectorUI/UserInterface/Views/ContentView.js (181625 => 181626)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -47,7 +47,7 @@
</span><span class="cx">             if (timelineType === WebInspector.TimelineRecord.Type.Network)
</span><span class="cx">                 return new WebInspector.NetworkTimelineView(representedObject);
</span><span class="cx"> 
</span><del>-            if (timelineType === WebInspector.TimelineRecord.Type.Layout)
</del><ins>+            if (timelineType === WebInspector.TimelineRecord.Type.Layout || timelineType === WebInspector.TimelineRecord.Type.RunLoop)
</ins><span class="cx">                 return new WebInspector.LayoutTimelineView(representedObject);
</span><span class="cx"> 
</span><span class="cx">             if (timelineType === WebInspector.TimelineRecord.Type.Script)
</span></span></pre></div>
<a id="trunkSourceWebInspectorUIUserInterfaceViewsLayoutTimelineViewjs"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebInspectorUI/UserInterface/Views/LayoutTimelineView.js (181625 => 181626)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -27,7 +27,7 @@
</span><span class="cx"> {
</span><span class="cx">     WebInspector.TimelineView.call(this, timeline);
</span><span class="cx"> 
</span><del>-    console.assert(timeline.type === WebInspector.TimelineRecord.Type.Layout);
</del><ins>+    console.assert(timeline.type === WebInspector.TimelineRecord.Type.Layout || WebInspector.TimelineRecord.Type.RunLoop);
</ins><span class="cx"> 
</span><span class="cx">     this.navigationSidebarTreeOutline.onselect = this._treeElementSelected.bind(this);
</span><span class="cx">     this.navigationSidebarTreeOutline.ondeselect = this._treeElementDeselected.bind(this);
</span><span class="lines">@@ -185,7 +185,7 @@
</span><span class="cx">     _layoutTimelineRecordAdded: function(event)
</span><span class="cx">     {
</span><span class="cx">         var layoutTimelineRecord = event.data.record;
</span><del>-        console.assert(layoutTimelineRecord instanceof WebInspector.LayoutTimelineRecord);
</del><ins>+        console.assert(layoutTimelineRecord instanceof WebInspector.LayoutTimelineRecord || layoutTimelineRecord instanceof WebInspector.RunLoopTimelineRecord);
</ins><span class="cx"> 
</span><span class="cx">         this._pendingRecords.push(layoutTimelineRecord);
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceWebInspectorUIUserInterfaceViewsRunLoopTimelineOverviewGraphcss"></a>
<div class="addfile"><h4>Added: trunk/Source/WebInspectorUI/UserInterface/Views/RunLoopTimelineOverviewGraph.css (0 => 181626)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,44 @@
</span><ins>+/*
+ * 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 &gt; .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 &gt; .divider &gt; span {
+    padding-right: 1px;
+
+    font-family: Helvetica, sans-serif;
+    font-size: 8px;
+
+    color: rgba(0, 0, 0, 0.2);
+}
</ins><span class="cx">\ No newline at end of file
</span></span></pre></div>
<a id="trunkSourceWebInspectorUIUserInterfaceViewsRunLoopTimelineOverviewGraphjs"></a>
<div class="addfile"><h4>Added: trunk/Source/WebInspectorUI/UserInterface/Views/RunLoopTimelineOverviewGraph.js (0 => 181626)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,160 @@
</span><ins>+/*
+ * 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 = &quot;runloop&quot;;
+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 &lt; 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 &lt; 0.01 || dividerTop &gt;= 1)
+                return;
+
+            var divider = this._framesPerSecondDividers.get(framesPerSecond);
+            if (!divider) {
+                divider = document.createElement(&quot;div&quot;);
+                divider.classList.add(&quot;divider&quot;);
+
+                var label = document.createElement(&quot;span&quot;);
+                label.innerText = framesPerSecond + &quot; fps&quot;;
+                divider.appendChild(label);
+
+                this.element.appendChild(divider);
+
+                this._framesPerSecondDividers.set(framesPerSecond, divider);
+            }
+
+            divider.style.marginTop = (dividerTop * overviewGraphHeight).toFixed(2) + &quot;px&quot;;
+        }
+
+        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 + &quot;%&quot;;
+    }
+};
</ins></span></pre></div>
<a id="trunkSourceWebInspectorUIUserInterfaceViewsTimelineIconscss"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebInspectorUI/UserInterface/Views/TimelineIcons.css (181625 => 181626)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -63,6 +63,14 @@
</span><span class="cx">     content: -webkit-image-set(url(../Images/ScriptLarge.png) 1x, url(../Images/ScriptLarge@2x.png) 2x);
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+.runloop-icon .icon {
+    content: -webkit-image-set(url(../Images/Frames.png) 1x, url(../Images/Frames@2x.png) 2x);
+}
+
+.runloop-icon.large .icon {
+    content: -webkit-image-set(url(../Images/FramesLarge.png) 1x, url(../Images/FramesLarge@2x.png) 2x);
+}
+
</ins><span class="cx"> .stopwatch-icon .icon {
</span><span class="cx">     content: -webkit-image-set(url(../Images/Stopwatch.png) 1x, url(../Images/Stopwatch@2x.png) 2x);
</span><span class="cx"> }
</span><span class="lines">@@ -83,6 +91,10 @@
</span><span class="cx">     content: url(../Images/TimelineRecordPaint.svg);
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+.runloop-record .icon {
+    content: -webkit-image-set(url(../Images/Frames.png) 1x, url(../Images/Frames@2x.png) 2x);
+}
+
</ins><span class="cx"> .evaluated-record .icon {
</span><span class="cx">     content: url(../Images/TimelineRecordScriptEvaluated.svg);
</span><span class="cx"> }
</span></span></pre></div>
<a id="trunkSourceWebInspectorUIUserInterfaceViewsTimelineOverviewGraphjs"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebInspectorUI/UserInterface/Views/TimelineOverviewGraph.js (181625 => 181626)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -40,6 +40,9 @@
</span><span class="cx">         if (timelineType === WebInspector.TimelineRecord.Type.Script)
</span><span class="cx">             return new WebInspector.ScriptTimelineOverviewGraph(timeline);
</span><span class="cx"> 
</span><ins>+        if (timelineType === WebInspector.TimelineRecord.Type.RunLoop)
+            return new WebInspector.RunLoopTimelineOverviewGraph(timeline);
+
</ins><span class="cx">         throw Error(&quot;Can't make a graph for an unknown timeline.&quot;);
</span><span class="cx">     }
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceWebInspectorUIUserInterfaceViewsTimelineRecordFramecss"></a>
<div class="addfile"><h4>Added: trunk/Source/WebInspectorUI/UserInterface/Views/TimelineRecordFrame.css (0 => 181626)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,92 @@
</span><ins>+/*
+ * 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 &gt; .frame {
+    position: absolute;
+    z-index: 1;
+    bottom: 1px;
+    min-width: 6px;
+
+    box-sizing: border-box;
+}
+
+.timeline-record-frame &gt; .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 &gt; .frame &gt; .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 &gt; .frame &gt; .duration:first-child {
+    border-top-style: solid;
+}
+
+.timeline-record-frame &gt; .frame &gt; .duration:last-child {
+    border-bottom-style: none;
+}
+
+.timeline-record-frame &gt; .frame &gt; .duration.timeline-record-type-network {
+    background-color: rgb(120, 176, 225);
+    border-color: rgb(61, 147, 200);
+}
+
+.timeline-record-frame &gt; .frame &gt; .duration.timeline-record-type-layout {
+    background-color: rgb(234, 153, 153);
+    border-color: rgb(212, 108, 108);
+}
+
+.timeline-record-frame &gt; .frame &gt; .duration.timeline-record-type-script {
+    background-color: rgb(190, 148, 233);
+    border-color: rgb(153, 113, 185);
+}
</ins></span></pre></div>
<a id="trunkSourceWebInspectorUIUserInterfaceViewsTimelineRecordFramejs"></a>
<div class="addfile"><h4>Added: trunk/Source/WebInspectorUI/UserInterface/Views/TimelineRecordFrame.js (0 => 181626)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,261 @@
</span><ins>+/*
+ * 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(&quot;div&quot;);
+    this._element.classList.add(WebInspector.TimelineRecordFrame.StyleClassName);
+
+    this._graphDataSource = graphDataSource;
+    this.records = records || [];
+};
+
+WebInspector.Object.addConstructorFunctions(WebInspector.TimelineRecordFrame);
+
+WebInspector.TimelineRecordFrame.StyleClassName = &quot;timeline-record-frame&quot;;
+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 &lt; 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 &gt; currentTime || record.startTime &gt; 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) &amp;&amp; (activeStartTime + Math.max(activeEndTime - activeStartTime, minimumFrameDuration) + minimumMargin &lt;= 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 &quot;|| 0&quot; 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 &gt; 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 &lt; graphStartTime || frameStartTime &gt; graphEndTime)
+            return false;
+
+        var graphDuration = graphEndTime - graphStartTime;
+        var recordLeftPosition = (frameStartTime - graphStartTime) / graphDuration;
+        this._updateElementPosition(this._element, recordLeftPosition, &quot;left&quot;);
+
+        var recordWidth = ((frameEndTime - graphStartTime) / graphDuration) - recordLeftPosition;
+        this._updateElementPosition(this._element, recordWidth, &quot;width&quot;);
+
+        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 &gt;= previousValue.duration ? currentValue : previousValue;
+        });
+
+        var frameElement = document.createElement(&quot;div&quot;);
+        frameElement.classList.add(&quot;frame&quot;);
+        this._element.appendChild(frameElement);
+
+        var frameHeight = displayRecord.duration / graphDataSource.graphHeightSeconds;
+        this._updateElementPosition(frameElement, frameHeight, &quot;height&quot;);
+
+        function createDurationElement(duration, recordType)
+        {
+            var element = document.createElement(&quot;div&quot;);
+            this._updateElementPosition(element, duration / displayRecord.duration, &quot;height&quot;);
+            element.classList.add(&quot;duration&quot;);
+            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 &gt; 0)
+            frameElement.appendChild(createDurationElement.call(this, displayRecord.durationRemainder));
+
+        // Add &quot;includes-dropped&quot; 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 &gt; 1 &amp;&amp; displayRecord.duration &gt; WebInspector.TimelineRecordFrame.SixtyFpsFrameBudget)
+            frameElement.classList.add(&quot;includes-dropped&quot;);
+
+        // If the display record is the last combined record and also exceeds the 60 fps budget,
+        // add a &quot;dropped&quot; 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 &amp;&amp; displayRecord.duration &gt; WebInspector.TimelineRecordFrame.SixtyFpsFrameBudget &amp;&amp; displayRecord.duration &gt;= minimumRecordDuration) {
+            var overflowDuration = displayRecord.duration - WebInspector.TimelineRecordFrame.SixtyFpsFrameBudget;
+            var droppedElementWidth = overflowDuration / displayRecord.duration;
+            frameWidth -= droppedElementWidth;
+
+            var droppedElement = document.createElement(&quot;div&quot;);
+            droppedElement.className = &quot;dropped&quot;;
+
+            this._element.appendChild(droppedElement);
+
+            this._updateElementPosition(droppedElement, frameHeight, &quot;height&quot;);
+            this._updateElementPosition(droppedElement, droppedElementWidth, &quot;width&quot;);
+        }
+
+        this._updateElementPosition(frameElement, frameWidth, &quot;width&quot;);
+    },
+
+    _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 + &quot;%&quot;;
+    }
+};
</ins></span></pre></div>
<a id="trunkSourceWebInspectorUIUserInterfaceViewsTimelineRecordTreeElementjs"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebInspectorUI/UserInterface/Views/TimelineRecordTreeElement.js (181625 => 181626)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -99,6 +99,11 @@
</span><span class="cx"> 
</span><span class="cx">         break;
</span><span class="cx"> 
</span><ins>+    case WebInspector.TimelineRecord.Type.RunLoop:
+        title = WebInspector.UIString(&quot;Runloop Executed&quot;);
+        iconStyleClass = WebInspector.TimelineRecordTreeElement.RunLoopRecordIconStyleClass;
+        break;
+
</ins><span class="cx">     default:
</span><span class="cx">         console.error(&quot;Unknown TimelineRecord type: &quot; + timelineRecord.type, timelineRecord);
</span><span class="cx">     }
</span><span class="lines">@@ -114,6 +119,7 @@
</span><span class="cx"> WebInspector.TimelineRecordTreeElement.StyleRecordIconStyleClass = &quot;style-record&quot;;
</span><span class="cx"> WebInspector.TimelineRecordTreeElement.LayoutRecordIconStyleClass = &quot;layout-record&quot;;
</span><span class="cx"> WebInspector.TimelineRecordTreeElement.PaintRecordIconStyleClass = &quot;paint-record&quot;;
</span><ins>+WebInspector.TimelineRecordTreeElement.RunLoopRecordIconStyleClass = &quot;runloop-record&quot;;
</ins><span class="cx"> WebInspector.TimelineRecordTreeElement.EvaluatedRecordIconStyleClass = &quot;evaluated-record&quot;;
</span><span class="cx"> WebInspector.TimelineRecordTreeElement.EventRecordIconStyleClass = &quot;event-record&quot;;
</span><span class="cx"> WebInspector.TimelineRecordTreeElement.TimerRecordIconStyleClass = &quot;timer-record&quot;;
</span></span></pre></div>
<a id="trunkSourceWebInspectorUIUserInterfaceViewsTimelineSidebarPaneljs"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebInspectorUI/UserInterface/Views/TimelineSidebarPanel.js (181625 => 181626)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -139,6 +139,7 @@
</span><span class="cx"> WebInspector.TimelineSidebarPanel.NetworkIconStyleClass = &quot;network-icon&quot;;
</span><span class="cx"> WebInspector.TimelineSidebarPanel.ColorsIconStyleClass = &quot;colors-icon&quot;;
</span><span class="cx"> WebInspector.TimelineSidebarPanel.ScriptIconStyleClass = &quot;script-icon&quot;;
</span><ins>+WebInspector.TimelineSidebarPanel.RunLoopIconStyleClass = &quot;runloop-icon&quot;;
</ins><span class="cx"> WebInspector.TimelineSidebarPanel.TimelineRecordingContentViewShowingStyleClass = &quot;timeline-recording-content-view-showing&quot;;
</span><span class="cx"> 
</span><span class="cx"> WebInspector.TimelineSidebarPanel.ShowingTimelineRecordingContentViewCookieKey = &quot;timeline-sidebar-panel-showing-timeline-recording-content-view&quot;;
</span></span></pre></div>
<a id="trunkSourceWebInspectorUIWebInspectorUIvcxprojWebInspectorUIvcxproj"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebInspectorUI/WebInspectorUI.vcxproj/WebInspectorUI.vcxproj (181625 => 181626)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -525,6 +525,10 @@
</span><span class="cx">     &lt;None Include=&quot;..\UserInterface\Images\FolderGeneric.png&quot; /&gt;
</span><span class="cx">     &lt;None Include=&quot;..\UserInterface\Images\ForwardArrow.svg&quot; /&gt;
</span><span class="cx">     &lt;None Include=&quot;..\UserInterface\Images\ForwardArrowLegacy.svg&quot; /&gt;
</span><ins>+    &lt;None Include=&quot;..\UserInterface\Images\Frames.png&quot; /&gt;
+    &lt;None Include=&quot;..\UserInterface\Images\Frames%402x.png&quot; /&gt;
+    &lt;None Include=&quot;..\UserInterface\Images\FramesLarge.png&quot; /&gt;
+    &lt;None Include=&quot;..\UserInterface\Images\FramesLarge%402x.png&quot; /&gt;
</ins><span class="cx">     &lt;None Include=&quot;..\UserInterface\Images\Function.svg&quot; /&gt;
</span><span class="cx">     &lt;None Include=&quot;..\UserInterface\Images\GoToArrow.svg&quot; /&gt;
</span><span class="cx">     &lt;None Include=&quot;..\UserInterface\Images\HierarchicalNavigationItemChevron.svg&quot; /&gt;
</span><span class="lines">@@ -747,6 +751,9 @@
</span><span class="cx">     &lt;None Include=&quot;..\UserInterface\Revision.js&quot; /&gt;
</span><span class="cx">     &lt;None Include=&quot;..\UserInterface\RulesStyleDetailsPanel.css&quot; /&gt;
</span><span class="cx">     &lt;None Include=&quot;..\UserInterface\RulesStyleDetailsPanel.js&quot; /&gt;
</span><ins>+    &lt;None Include=&quot;..\UserInterface\RunLoopTimelineOverviewGraph.css&quot; /&gt;
+    &lt;None Include=&quot;..\UserInterface\RunLoopTimelineOverviewGraph.js&quot; /&gt;
+    &lt;None Include=&quot;..\UserInterface\RunLoopTimelineRecord.js&quot; /&gt;
</ins><span class="cx">     &lt;None Include=&quot;..\UserInterface\RuntimeObserver.js&quot; /&gt;
</span><span class="cx">     &lt;None Include=&quot;..\UserInterface\ScopeBar.css&quot; /&gt;
</span><span class="cx">     &lt;None Include=&quot;..\UserInterface\ScopeBar.js&quot; /&gt;
</span><span class="lines">@@ -808,6 +815,8 @@
</span><span class="cx">     &lt;None Include=&quot;..\UserInterface\TimelineOverview.css&quot; /&gt;
</span><span class="cx">     &lt;None Include=&quot;..\UserInterface\TimelineOverview.js&quot; /&gt;
</span><span class="cx">     &lt;None Include=&quot;..\UserInterface\TimelineRecord.js&quot; /&gt;
</span><ins>+    &lt;None Include=&quot;..\UserInterface\TimelineRecordFrame.css&quot; /&gt;
+    &lt;None Include=&quot;..\UserInterface\TimelineRecordFrame.js&quot; /&gt;
</ins><span class="cx">     &lt;None Include=&quot;..\UserInterface\TimelinesContentView.css&quot; /&gt;
</span><span class="cx">     &lt;None Include=&quot;..\UserInterface\TimelinesContentView.js&quot; /&gt;
</span><span class="cx">     &lt;None Include=&quot;..\UserInterface\TimelinesObject.js&quot; /&gt;
</span></span></pre></div>
<a id="trunkSourceWebInspectorUIWebInspectorUIvcxprojWebInspectorUIvcxprojfilters"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebInspectorUI/WebInspectorUI.vcxproj/WebInspectorUI.vcxproj.filters (181625 => 181626)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -825,6 +825,15 @@
</span><span class="cx">     &lt;None Include=&quot;..\UserInterface\RulesStyleDetailsPanel.js&quot;&gt;
</span><span class="cx">       &lt;Filter&gt;UserInterface&lt;/Filter&gt;
</span><span class="cx">     &lt;/None&gt;
</span><ins>+    &lt;None Include=&quot;..\UserInterface\RunLoopTimelineOverviewGraph.css&quot;&gt;
+      &lt;Filter&gt;UserInterface&lt;/Filter&gt;
+    &lt;/None&gt;
+    &lt;None Include=&quot;..\UserInterface\RunLoopTimelineOverviewGraph.js&quot;&gt;
+      &lt;Filter&gt;UserInterface&lt;/Filter&gt;
+    &lt;/None&gt;
+    &lt;None Include=&quot;..\UserInterface\RunLoopTimelineRecord.js&quot;&gt;
+      &lt;Filter&gt;UserInterface&lt;/Filter&gt;
+    &lt;/None&gt;
</ins><span class="cx">     &lt;None Include=&quot;..\UserInterface\RuntimeObserver.js&quot;&gt;
</span><span class="cx">       &lt;Filter&gt;UserInterface&lt;/Filter&gt;
</span><span class="cx">     &lt;/None&gt;
</span><span class="lines">@@ -1008,6 +1017,12 @@
</span><span class="cx">     &lt;None Include=&quot;..\UserInterface\TimelineRecord.js&quot;&gt;
</span><span class="cx">       &lt;Filter&gt;UserInterface&lt;/Filter&gt;
</span><span class="cx">     &lt;/None&gt;
</span><ins>+    &lt;None Include=&quot;..\UserInterface\TimelineRecordFrame.css&quot;&gt;
+      &lt;Filter&gt;UserInterface&lt;/Filter&gt;
+    &lt;/None&gt;
+    &lt;None Include=&quot;..\UserInterface\TimelineRecordFrame.js&quot;&gt;
+      &lt;Filter&gt;UserInterface&lt;/Filter&gt;
+    &lt;/None&gt;
</ins><span class="cx">     &lt;None Include=&quot;..\UserInterface\TimelinesContentView.css&quot;&gt;
</span><span class="cx">       &lt;Filter&gt;UserInterface&lt;/Filter&gt;
</span><span class="cx">     &lt;/None&gt;
</span></span></pre>
</div>
</div>

</body>
</html>