Web Inspector: Initial support for variable timelines
authorjoepeck@webkit.org <joepeck@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 1 Dec 2015 21:51:08 +0000 (21:51 +0000)
committerjoepeck@webkit.org <joepeck@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 1 Dec 2015 21:51:08 +0000 (21:51 +0000)
https://bugs.webkit.org/show_bug.cgi?id=151372

Reviewed by NOBODY (OOPS!).

* UserInterface/Controllers/TimelineManager.js:
(WebInspector.TimelineManager.defaultInstruments):
(WebInspector.TimelineManager.prototype._loadNewRecording):
Keep the status quo which is the same set of instruments for each recording.

(WebInspector.TimelineManager.prototype.startCapturing):
(WebInspector.TimelineManager.prototype.stopCapturing):
Push responsibility of capturing to the Recording, which has a specific set
of instruments that know what they need to turn on an off from the backend.

* UserInterface/Main.html:
* UserInterface/Models/Instrument.js: Added.
(WebInspector.Instrument):
(WebInspector.Instrument.startLegacyTimelineAgent):
(WebInspector.Instrument.stopLegacyTimelineAgent):
(WebInspector.Instrument.prototype.get timelineRecordType):
(WebInspector.Instrument.prototype.startInstrumentation):
(WebInspector.Instrument.prototype.stopInstrumentation):
New class representing something that can be turned on and off
from the backend and produces a set of Timeline record types.
Currently instruments are 1-to-1 to a Timeline type.

* UserInterface/Models/LayoutInstrument.js: Added.
(WebInspector.LayoutInstrument.prototype.get timelineRecordType):
(WebInspector.LayoutInstrument):
* UserInterface/Models/NetworkInstrument.js: Added.
(WebInspector.NetworkInstrument.prototype.get timelineRecordType):
(WebInspector.NetworkInstrument.prototype.startInstrumentation):
(WebInspector.NetworkInstrument.prototype.stopInstrumentation):
(WebInspector.NetworkInstrument):
* UserInterface/Models/ScriptInstrument.js: Added.
(WebInspector.ScriptInstrument.prototype.get timelineRecordType):
(WebInspector.ScriptInstrument):
The default set of instruments. Currently they all enable the TimelineAgent,
so they share code to enable/disable in the base class to avoid duplication.

* UserInterface/Models/FPSInstrument.js: Added.
(WebInspector.FPSInstrument):
(WebInspector.FPSInstrument.supported):
(WebInspector.FPSInstrument.prototype.get timelineRecordType):
Provide a "supported" static method and simplify other code that
checks whether or not RenderingFrames is available or not.

* UserInterface/Models/Timeline.js:
(WebInspector.Timeline.prototype.get displayName): Deleted.
(WebInspector.Timeline.prototype.get iconClassName): Deleted.
Move these to a View class, as this is primarily View logic.

* UserInterface/Models/TimelineRecording.js:
(WebInspector.TimelineRecording):
(WebInspector.TimelineRecording.prototype.get instruments):
(WebInspector.TimelineRecording.prototype.start):
(WebInspector.TimelineRecording.prototype.stop):
(WebInspector.TimelineRecording.prototype.timelineForInstrument):
(WebInspector.TimelineRecording.prototype.addInstrument):
(WebInspector.TimelineRecording.prototype.removeInstrument):
(WebInspector.TimelineRecording.prototype.addEventMarker):
(WebInspector.TimelineRecording.prototype.addTimeline): Deleted.
(WebInspector.TimelineRecording.prototype.removeTimeline): Deleted.
A recording now has a set of Instruments and its own start/stop
which starts/stops its set of Instruments! Treat Instruments as
the variable property of a Recording instead of Timelines.

* UserInterface/Views/TimelineOverview.js:
(WebInspector.TimelineOverview):
(WebInspector.TimelineOverview.prototype._instrumentAdded):
(WebInspector.TimelineOverview.prototype._instrumentRemoved):
(WebInspector.TimelineOverview.prototype._timelineAdded): Deleted.
(WebInspector.TimelineOverview.prototype._timelineRemoved): Deleted.
* UserInterface/Views/TimelineRecordingContentView.js:
(WebInspector.TimelineRecordingContentView):
(WebInspector.TimelineRecordingContentView.prototype._instrumentAdded):
(WebInspector.TimelineRecordingContentView.prototype._instrumentRemoved):
(WebInspector.TimelineRecordingContentView.prototype._timelineAdded): Deleted.
(WebInspector.TimelineRecordingContentView.prototype._timelineRemoved): Deleted.
* UserInterface/Views/TimelineSidebarPanel.js:
(WebInspector.TimelineSidebarPanel):
(WebInspector.TimelineSidebarPanel.displayNameForTimeline):
(WebInspector.TimelineSidebarPanel.iconClassNameForTimeline):
(WebInspector.TimelineSidebarPanel.prototype.updateFrameSelection):
(WebInspector.TimelineSidebarPanel.prototype.restoreStateFromCookie):
(WebInspector.TimelineSidebarPanel.prototype._recordingSelected):
(WebInspector.TimelineSidebarPanel.prototype._instrumentAdded):
(WebInspector.TimelineSidebarPanel.prototype._instrumentRemoved):
(WebInspector.TimelineSidebarPanel.prototype._changeViewMode):
(WebInspector.TimelineSidebarPanel.prototype._timelineAdded): Deleted.
(WebInspector.TimelineSidebarPanel.prototype._timelineRemoved): Deleted.
Update all TimelineAdded/TimelineRemoved clients to instead check
InstrumentAdded/InstrumentRemoved. Immediately convert from an Instrument
to a Timeline to keep the patch simple.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@192906 268f45cc-cd09-0410-ab3c-d52691b4dbfc

14 files changed:
Source/WebInspectorUI/ChangeLog
Source/WebInspectorUI/UserInterface/Controllers/TimelineManager.js
Source/WebInspectorUI/UserInterface/Main.html
Source/WebInspectorUI/UserInterface/Models/FPSInstrument.js [new file with mode: 0644]
Source/WebInspectorUI/UserInterface/Models/Instrument.js [new file with mode: 0644]
Source/WebInspectorUI/UserInterface/Models/LayoutInstrument.js [new file with mode: 0644]
Source/WebInspectorUI/UserInterface/Models/NetworkInstrument.js [new file with mode: 0644]
Source/WebInspectorUI/UserInterface/Models/ScriptInstrument.js [new file with mode: 0644]
Source/WebInspectorUI/UserInterface/Models/Timeline.js
Source/WebInspectorUI/UserInterface/Models/TimelineRecording.js
Source/WebInspectorUI/UserInterface/Test.html
Source/WebInspectorUI/UserInterface/Views/TimelineOverview.js
Source/WebInspectorUI/UserInterface/Views/TimelineRecordingContentView.js
Source/WebInspectorUI/UserInterface/Views/TimelineSidebarPanel.js

index 3896a98..5905a16 100644 (file)
@@ -1,5 +1,104 @@
 2015-12-01  Joseph Pecoraro  <pecoraro@apple.com>
 
+        Web Inspector: Initial support for variable timelines
+        https://bugs.webkit.org/show_bug.cgi?id=151372
+
+        Reviewed by Brian Burg.
+
+        * UserInterface/Controllers/TimelineManager.js:
+        (WebInspector.TimelineManager.defaultInstruments):
+        (WebInspector.TimelineManager.prototype._loadNewRecording):
+        Keep the status quo which is the same set of instruments for each recording.
+
+        (WebInspector.TimelineManager.prototype.startCapturing):
+        (WebInspector.TimelineManager.prototype.stopCapturing):
+        Push responsibility of capturing to the Recording, which has a specific set
+        of instruments that know what they need to turn on an off from the backend.
+        
+        * UserInterface/Main.html:
+        * UserInterface/Models/Instrument.js: Added.
+        (WebInspector.Instrument):
+        (WebInspector.Instrument.startLegacyTimelineAgent):
+        (WebInspector.Instrument.stopLegacyTimelineAgent):
+        (WebInspector.Instrument.prototype.get timelineRecordType):
+        (WebInspector.Instrument.prototype.startInstrumentation):
+        (WebInspector.Instrument.prototype.stopInstrumentation):
+        New class representing something that can be turned on and off
+        from the backend and produces a set of Timeline record types.
+        Currently instruments are 1-to-1 to a Timeline type.
+
+        * UserInterface/Models/LayoutInstrument.js: Added.
+        (WebInspector.LayoutInstrument.prototype.get timelineRecordType):
+        (WebInspector.LayoutInstrument):
+        * UserInterface/Models/NetworkInstrument.js: Added.
+        (WebInspector.NetworkInstrument.prototype.get timelineRecordType):
+        (WebInspector.NetworkInstrument.prototype.startInstrumentation):
+        (WebInspector.NetworkInstrument.prototype.stopInstrumentation):
+        (WebInspector.NetworkInstrument):
+        * UserInterface/Models/ScriptInstrument.js: Added.
+        (WebInspector.ScriptInstrument.prototype.get timelineRecordType):
+        (WebInspector.ScriptInstrument):
+        The default set of instruments. Currently they all enable the TimelineAgent,
+        so they share code to enable/disable in the base class to avoid duplication.
+
+        * UserInterface/Models/FPSInstrument.js: Added.
+        (WebInspector.FPSInstrument):
+        (WebInspector.FPSInstrument.supported):
+        (WebInspector.FPSInstrument.prototype.get timelineRecordType):
+        Provide a "supported" static method and simplify other code that
+        checks whether or not RenderingFrames is available or not.
+
+
+        * UserInterface/Models/Timeline.js:
+        (WebInspector.Timeline.prototype.get displayName): Deleted.
+        (WebInspector.Timeline.prototype.get iconClassName): Deleted.
+        Move these to a View class, as this is primarily View logic.
+
+        * UserInterface/Models/TimelineRecording.js:
+        (WebInspector.TimelineRecording):
+        (WebInspector.TimelineRecording.prototype.get instruments):
+        (WebInspector.TimelineRecording.prototype.start):
+        (WebInspector.TimelineRecording.prototype.stop):
+        (WebInspector.TimelineRecording.prototype.timelineForInstrument):
+        (WebInspector.TimelineRecording.prototype.addInstrument):
+        (WebInspector.TimelineRecording.prototype.removeInstrument):
+        (WebInspector.TimelineRecording.prototype.addEventMarker):
+        (WebInspector.TimelineRecording.prototype.addTimeline): Deleted.
+        (WebInspector.TimelineRecording.prototype.removeTimeline): Deleted.
+        A recording now has a set of Instruments and its own start/stop
+        which starts/stops its set of Instruments! Treat Instruments as
+        the variable property of a Recording instead of Timelines.
+    
+        * UserInterface/Views/TimelineOverview.js:
+        (WebInspector.TimelineOverview):
+        (WebInspector.TimelineOverview.prototype._instrumentAdded):
+        (WebInspector.TimelineOverview.prototype._instrumentRemoved):
+        (WebInspector.TimelineOverview.prototype._timelineAdded): Deleted.
+        (WebInspector.TimelineOverview.prototype._timelineRemoved): Deleted.
+        * UserInterface/Views/TimelineRecordingContentView.js:
+        (WebInspector.TimelineRecordingContentView):
+        (WebInspector.TimelineRecordingContentView.prototype._instrumentAdded):
+        (WebInspector.TimelineRecordingContentView.prototype._instrumentRemoved):
+        (WebInspector.TimelineRecordingContentView.prototype._timelineAdded): Deleted.
+        (WebInspector.TimelineRecordingContentView.prototype._timelineRemoved): Deleted.
+        * UserInterface/Views/TimelineSidebarPanel.js:
+        (WebInspector.TimelineSidebarPanel):
+        (WebInspector.TimelineSidebarPanel.displayNameForTimeline):
+        (WebInspector.TimelineSidebarPanel.iconClassNameForTimeline):
+        (WebInspector.TimelineSidebarPanel.prototype.updateFrameSelection):
+        (WebInspector.TimelineSidebarPanel.prototype.restoreStateFromCookie):
+        (WebInspector.TimelineSidebarPanel.prototype._recordingSelected):
+        (WebInspector.TimelineSidebarPanel.prototype._instrumentAdded):
+        (WebInspector.TimelineSidebarPanel.prototype._instrumentRemoved):
+        (WebInspector.TimelineSidebarPanel.prototype._changeViewMode):
+        (WebInspector.TimelineSidebarPanel.prototype._timelineAdded): Deleted.
+        (WebInspector.TimelineSidebarPanel.prototype._timelineRemoved): Deleted.
+        Update all TimelineAdded/TimelineRemoved clients to instead check
+        InstrumentAdded/InstrumentRemoved. Immediately convert from an Instrument
+        to a Timeline to keep the patch simple.
+
+2015-12-01  Joseph Pecoraro  <pecoraro@apple.com>
+
         Web Inspector: Broken Inspector when resources are minified
         https://bugs.webkit.org/show_bug.cgi?id=151711
 
index 3dbb9e2..197b275 100644 (file)
@@ -45,6 +45,22 @@ WebInspector.TimelineManager = class TimelineManager extends WebInspector.Object
         this.reset();
     }
 
+    // Static
+
+    static defaultInstruments()
+    {
+        let defaults = [
+            new WebInspector.NetworkInstrument,
+            new WebInspector.LayoutInstrument,
+            new WebInspector.ScriptInstrument,
+        ];
+
+        if (WebInspector.FPSInstrument.supported())
+            defaults.push(new WebInspector.FPSInstrument);
+
+        return defaults;
+    }
+
     // Public
 
     reset()
@@ -103,21 +119,14 @@ WebInspector.TimelineManager = class TimelineManager extends WebInspector.Object
         if (!this._activeRecording || shouldCreateRecording)
             this._loadNewRecording();
 
-        var result = TimelineAgent.start();
-
-        // COMPATIBILITY (iOS 7): recordingStarted event did not exist yet. Start explicitly.
-        if (!TimelineAgent.hasEvent("recordingStarted")) {
-            result.then(function() {
-                WebInspector.timelineManager.capturingStarted();
-            });
-        }
+        this._activeRecording.start();
     }
 
     stopCapturing()
     {
         console.assert(this._isCapturing, "TimelineManager is not capturing.");
 
-        TimelineAgent.stop();
+        this._activeRecording.stop();
 
         // NOTE: Always stop immediately instead of waiting for a Timeline.recordingStopped event.
         // This way the UI feels as responsive to a stop as possible.
@@ -445,8 +454,11 @@ WebInspector.TimelineManager = class TimelineManager extends WebInspector.Object
         if (this._activeRecording && this._activeRecording.isEmpty())
             return;
 
+        // FIXME: Move the list of instruments for a new recording to a Setting when new Instruments are supported.
+        let instruments = WebInspector.TimelineManager.defaultInstruments();
+
         var identifier = this._nextRecordingIdentifier++;
-        var newRecording = new WebInspector.TimelineRecording(identifier, WebInspector.UIString("Timeline Recording %d").format(identifier));
+        var newRecording = new WebInspector.TimelineRecording(identifier, WebInspector.UIString("Timeline Recording %d").format(identifier), instruments);
 
         this._recordings.push(newRecording);
         this.dispatchEventToListeners(WebInspector.TimelineManager.Event.RecordingCreated, {recording: newRecording});
index 55e0817..c82c60d 100644 (file)
 
     <script src="Models/BreakpointAction.js"></script>
     <script src="Models/ConsoleMessage.js"></script>
+    <script src="Models/Instrument.js"></script>
     <script src="Models/SourceCode.js"></script>
     <script src="Models/SourceCodeLocation.js"></script>
     <script src="Models/Timeline.js"></script>
     <script src="Models/ExecutionContext.js"></script>
     <script src="Models/ExecutionContextList.js"></script>
     <script src="Models/Frame.js"></script>
+    <script src="Models/FPSInstrument.js"></script>
     <script src="Models/GarbageCollection.js"></script>
     <script src="Models/Geometry.js"></script>
     <script src="Models/Gradient.js"></script>
     <script src="Models/IndexedDatabaseObjectStoreIndex.js"></script>
     <script src="Models/IssueMessage.js"></script>
     <script src="Models/KeyboardShortcut.js"></script>
+    <script src="Models/LayoutInstrument.js"></script>
     <script src="Models/LayoutTimelineRecord.js"></script>
     <script src="Models/LazySourceCodeLocation.js"></script>
     <script src="Models/LineWidget.js"></script>
     <script src="Models/LogObject.js"></script>
     <script src="Models/NativeFunctionParameters.js"></script>
+    <script src="Models/NetworkInstrument.js"></script>
     <script src="Models/NetworkTimeline.js"></script>
     <script src="Models/ObjectPreview.js"></script>
     <script src="Models/Probe.js"></script>
     <script src="Models/Revision.js"></script>
     <script src="Models/ScopeChainNode.js"></script>
     <script src="Models/Script.js"></script>
+    <script src="Models/ScriptInstrument.js"></script>
     <script src="Models/ScriptSyntaxTree.js"></script>
     <script src="Models/ScriptTimelineRecord.js"></script>
     <script src="Models/Setting.js"></script>
diff --git a/Source/WebInspectorUI/UserInterface/Models/FPSInstrument.js b/Source/WebInspectorUI/UserInterface/Models/FPSInstrument.js
new file mode 100644 (file)
index 0000000..a5e4452
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * 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.FPSInstrument = class FPSInstrument extends WebInspector.Instrument
+{
+    constructor()
+    {
+        super();
+
+        console.assert(WebInspector.FPSInstrument.supported());
+    }
+
+    // Static
+
+    static supported()
+    {
+        // COMPATIBILITY (iOS 8): TimelineAgent.EventType.RenderingFrame did not exist.
+        return window.TimelineAgent && TimelineAgent.EventType.RenderingFrame;
+    }
+
+    // Protected
+
+    get timelineRecordType()
+    {
+        return WebInspector.TimelineRecord.Type.RenderingFrame;
+    }
+};
diff --git a/Source/WebInspectorUI/UserInterface/Models/Instrument.js b/Source/WebInspectorUI/UserInterface/Models/Instrument.js
new file mode 100644 (file)
index 0000000..5d12c51
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ * 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.Instrument = class Instrument extends WebInspector.Object
+{
+    // Static
+
+    static startLegacyTimelineAgent()
+    {
+        if (WebInspector.Instrument._legacyTimelineAgentStarted)
+            return;
+
+        WebInspector.Instrument._legacyTimelineAgentStarted = true;
+
+        let result = TimelineAgent.start();
+
+        // COMPATIBILITY (iOS 7): recordingStarted event did not exist yet. Start explicitly.
+        if (!TimelineAgent.hasEvent("recordingStarted")) {
+            result.then(function() {
+                WebInspector.timelineManager.capturingStarted();
+            });
+        }
+    }
+
+    static stopLegacyTimelineAgent()
+    {
+        if (!WebInspector.Instrument._legacyTimelineAgentStarted)
+            return;
+
+        WebInspector.Instrument._legacyTimelineAgentStarted = false;
+
+        TimelineAgent.stop();
+    }
+
+    // Protected
+
+    get timelineRecordType()
+    {
+        return null; // Implemented by subclasses.
+    }
+
+    startInstrumentation()
+    {
+        WebInspector.Instrument.startLegacyTimelineAgent();
+    }
+
+    stopInstrumentation()
+    {
+        WebInspector.Instrument.stopLegacyTimelineAgent();
+    }
+};
+
+WebInspector.Instrument._legacyTimelineAgentStarted = false;
diff --git a/Source/WebInspectorUI/UserInterface/Models/LayoutInstrument.js b/Source/WebInspectorUI/UserInterface/Models/LayoutInstrument.js
new file mode 100644 (file)
index 0000000..2d33ac3
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * 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.LayoutInstrument = class LayoutInstrument extends WebInspector.Instrument
+{
+    // Protected
+
+    get timelineRecordType()
+    {
+        return WebInspector.TimelineRecord.Type.Layout;
+    }
+};
diff --git a/Source/WebInspectorUI/UserInterface/Models/NetworkInstrument.js b/Source/WebInspectorUI/UserInterface/Models/NetworkInstrument.js
new file mode 100644 (file)
index 0000000..b946db5
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2015 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+WebInspector.NetworkInstrument = class NetworkInstrument extends WebInspector.Instrument
+{
+    // Protected
+
+    get timelineRecordType()
+    {
+        return WebInspector.TimelineRecord.Type.Network;
+    }
+
+    startInstrumentation()
+    {
+        // Nothing to do, network instrumentation is always happening.
+    }
+
+    stopInstrumentation()
+    {
+        // Nothing to do, network instrumentation is always happening.
+    }
+};
diff --git a/Source/WebInspectorUI/UserInterface/Models/ScriptInstrument.js b/Source/WebInspectorUI/UserInterface/Models/ScriptInstrument.js
new file mode 100644 (file)
index 0000000..f1022ea
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * 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.ScriptInstrument = class ScriptInstrument extends WebInspector.Instrument
+{
+    // Protected
+
+    get timelineRecordType()
+    {
+        return WebInspector.TimelineRecord.Type.Script;
+    }
+};
index f1e30cf..3c8b8d3 100644 (file)
@@ -66,34 +66,6 @@ WebInspector.Timeline = class Timeline extends WebInspector.Object
         return this._records;
     }
 
-    get displayName()
-    {
-        if (this._type === WebInspector.TimelineRecord.Type.Network)
-            return WebInspector.UIString("Network Requests");
-        if (this._type === WebInspector.TimelineRecord.Type.Layout)
-            return WebInspector.UIString("Layout & Rendering");
-        if (this._type === WebInspector.TimelineRecord.Type.Script)
-            return WebInspector.UIString("JavaScript & Events");
-        if (this._type === WebInspector.TimelineRecord.Type.RenderingFrame)
-            return WebInspector.UIString("Rendering Frames");
-
-        console.error("Timeline has unknown type:", this._type, this);
-    }
-
-    get iconClassName()
-    {
-        if (this._type === WebInspector.TimelineRecord.Type.Network)
-            return WebInspector.TimelineSidebarPanel.NetworkIconStyleClass;
-        if (this._type === WebInspector.TimelineRecord.Type.Layout)
-            return WebInspector.TimelineSidebarPanel.ColorsIconStyleClass;
-        if (this._type === WebInspector.TimelineRecord.Type.Script)
-            return WebInspector.TimelineSidebarPanel.ScriptIconStyleClass;
-        if (this._type === WebInspector.TimelineRecord.Type.RenderingFrame)
-            return WebInspector.TimelineSidebarPanel.RenderingFrameIconStyleClass;
-
-        console.error("Timeline has unknown type:", this._type, this);
-    }
-
     reset(suppressEvents)
     {
         this._records = [];
index f5f09bd..0bdecd2 100644 (file)
 
 WebInspector.TimelineRecording = class TimelineRecording extends WebInspector.Object
 {
-    constructor(identifier, displayName)
+    constructor(identifier, displayName, instruments)
     {
         super();
 
         this._identifier = identifier;
         this._timelines = new Map;
         this._displayName = displayName;
+        this._capturing = false;
         this._readonly = false;
-
-        this.addTimeline(WebInspector.Timeline.create(WebInspector.TimelineRecord.Type.Network));
-        this.addTimeline(WebInspector.Timeline.create(WebInspector.TimelineRecord.Type.Layout));
-        this.addTimeline(WebInspector.Timeline.create(WebInspector.TimelineRecord.Type.Script));
-
-        // COMPATIBILITY (iOS 8): TimelineAgent.EventType.RenderingFrame did not exist.
-        if (window.TimelineAgent && TimelineAgent.EventType.RenderingFrame)
-            this.addTimeline(WebInspector.Timeline.create(WebInspector.TimelineRecord.Type.RenderingFrame));
+        this._instruments = instruments || [];
+
+        let timelines = [
+            WebInspector.TimelineRecord.Type.Network,
+            WebInspector.TimelineRecord.Type.Layout,
+            WebInspector.TimelineRecord.Type.Script,
+            WebInspector.TimelineRecord.Type.RenderingFrame,
+        ];
+
+        for (let type of timelines) {
+            let timeline = WebInspector.Timeline.create(type);
+            this._timelines.set(type, timeline);
+            timeline.addEventListener(WebInspector.Timeline.Event.TimesUpdated, this._timelineTimesUpdated, this);
+        }
 
         // For legacy backends, we compute the elapsed time of records relative to this timestamp.
         this._legacyFirstRecordedTimestamp = NaN;
@@ -65,6 +72,11 @@ WebInspector.TimelineRecording = class TimelineRecording extends WebInspector.Ob
         return this._timelines;
     }
 
+    get instruments()
+    {
+        return this._instruments;
+    }
+
     get readonly()
     {
         return this._readonly;
@@ -80,6 +92,28 @@ WebInspector.TimelineRecording = class TimelineRecording extends WebInspector.Ob
         return this._endTime;
     }
 
+    start()
+    {
+        console.assert(!this._capturing, "Attempted to start an already started session.");
+        console.assert(!this._readonly, "Attempted to start a readonly session.");
+
+        this._capturing = true;
+
+        for (let instrument of this._instruments)
+            instrument.startInstrumentation();
+    }
+
+    stop()
+    {
+        console.assert(this._capturing, "Attempted to stop an already stopped session.");
+        console.assert(!this._readonly, "Attempted to stop a readonly session.");
+
+        this._capturing = false;
+
+        for (let instrument of this._instruments)
+            instrument.stopInstrumentation();
+    }
+
     saveIdentityToCookie()
     {
         // Do nothing. Timeline recordings are not persisted when the inspector is
@@ -133,32 +167,34 @@ WebInspector.TimelineRecording = class TimelineRecording extends WebInspector.Ob
         return [...timelines.values()];
     }
 
-    addTimeline(timeline)
+    timelineForInstrument(instrument)
+    {
+        return this._timelines.get(instrument.timelineRecordType);
+    }
+
+    addInstrument(instrument)
     {
-        console.assert(timeline instanceof WebInspector.Timeline, timeline);
-        console.assert(!this._timelines.has(timeline), this._timelines, timeline);
+        console.assert(instrument instanceof WebInspector.Instrument, instrument);
+        console.assert(!this._instruments.contains(instrument), this._instruments, instrument);
 
-        this._timelines.set(timeline.type, timeline);
+        this._instruments.push(instrument);
 
-        timeline.addEventListener(WebInspector.Timeline.Event.TimesUpdated, this._timelineTimesUpdated, this);
-        this.dispatchEventToListeners(WebInspector.TimelineRecording.Event.TimelineAdded, {timeline});
+        this.dispatchEventToListeners(WebInspector.TimelineRecording.Event.InstrumentAdded, {instrument});
     }
 
-    removeTimeline(timeline)
+    removeInstrument(instrument)
     {
-        console.assert(timeline instanceof WebInspector.Timeline, timeline);
-        console.assert(this._timelines.has(timeline.type), this._timelines, timeline);
-        console.assert(this._timelines.get(timeline.type) === timeline, this._timelines, timeline);
+        console.assert(instrument instanceof WebInspector.Instrument, instrument);
+        console.assert(this._instruments.contains(instrument), this._instruments, instrument);
 
-        this._timelines.delete(timeline.type);
+        this._instruments.remove(instrument);
 
-        timeline.removeEventListener(WebInspector.Timeline.Event.TimesUpdated, this._timelineTimesUpdated, this);
-        this.dispatchEventToListeners(WebInspector.TimelineRecording.Event.TimelineRemoved, {timeline});
+        this.dispatchEventToListeners(WebInspector.TimelineRecording.Event.InstrumentRemoved, {instrument});
     }
 
     addEventMarker(marker)
     {
-        if (!WebInspector.timelineManager.isCapturing())
+        if (!this._capturing)
             return;
 
         this._eventMarkers.push(marker);
@@ -291,8 +327,8 @@ WebInspector.TimelineRecording.Event = {
     Reset: "timeline-recording-reset",
     Unloaded: "timeline-recording-unloaded",
     SourceCodeTimelineAdded: "timeline-recording-source-code-timeline-added",
-    TimelineAdded: "timeline-recording-timeline-added",
-    TimelineRemoved: "timeline-recording-timeline-removed",
+    InstrumentAdded: "timeline-recording-instrument-added",
+    InstrumentRemoved: "timeline-recording-instrument-removed",
     TimesUpdated: "timeline-recording-times-updated",
     MarkerAdded: "timeline-recording-marker-added",
 };
index bedf302..0b321a5 100644 (file)
@@ -72,6 +72,7 @@
 
     <script src="Models/BreakpointAction.js"></script>
     <script src="Models/ConsoleMessage.js"></script>
+    <script src="Models/Instrument.js"></script>
     <script src="Models/SourceCode.js"></script>
     <script src="Models/SourceCodeLocation.js"></script>
     <script src="Models/Timeline.js"></script>
     <script src="Models/ExecutionContext.js"></script>
     <script src="Models/ExecutionContextList.js"></script>
     <script src="Models/Frame.js"></script>
+    <script src="Models/FPSInstrument.js"></script>
     <script src="Models/GarbageCollection.js"></script>
     <script src="Models/Geometry.js"></script>
     <script src="Models/IndexedDatabase.js"></script>
     <script src="Models/IndexedDatabaseObjectStore.js"></script>
     <script src="Models/IndexedDatabaseObjectStoreIndex.js"></script>
     <script src="Models/IssueMessage.js"></script>
+    <script src="Models/LayoutInstrument.js"></script>
     <script src="Models/LayoutTimelineRecord.js"></script>
     <script src="Models/LazySourceCodeLocation.js"></script>
+    <script src="Models/NetworkInstrument.js"></script>
     <script src="Models/NetworkTimeline.js"></script>
     <script src="Models/ObjectPreview.js"></script>
     <script src="Models/Probe.js"></script>
     <script src="Models/Revision.js"></script>
     <script src="Models/ScopeChainNode.js"></script>
     <script src="Models/Script.js"></script>
+    <script src="Models/ScriptInstrument.js"></script>
     <script src="Models/ScriptSyntaxTree.js"></script>
     <script src="Models/ScriptTimelineRecord.js"></script>
     <script src="Models/Setting.js"></script>
index a957418..01ee61b 100644 (file)
@@ -32,8 +32,8 @@ WebInspector.TimelineOverview = class TimelineOverview extends WebInspector.View
         console.assert(timelineRecording instanceof WebInspector.TimelineRecording);
 
         this._recording = timelineRecording;
-        this._recording.addEventListener(WebInspector.TimelineRecording.Event.TimelineAdded, this._timelineAdded, this);
-        this._recording.addEventListener(WebInspector.TimelineRecording.Event.TimelineRemoved, this._timelineRemoved, this);
+        this._recording.addEventListener(WebInspector.TimelineRecording.Event.InstrumentAdded, this._instrumentAdded, this);
+        this._recording.addEventListener(WebInspector.TimelineRecording.Event.InstrumentRemoved, this._instrumentRemoved, this);
         this._recording.addEventListener(WebInspector.TimelineRecording.Event.MarkerAdded, this._markerAdded, this);
         this._recording.addEventListener(WebInspector.TimelineRecording.Event.Reset, this._recordingReset, this);
 
@@ -90,8 +90,8 @@ WebInspector.TimelineOverview = class TimelineOverview extends WebInspector.View
         this.selectionStartTime = this._selectionStartValueSetting.value;
         this.selectionDuration = this._selectionDurationSetting.value;
 
-        for (var timeline of this._recording.timelines.values())
-            this._timelineAdded(timeline);
+        for (let instrument of this._recording.instruments)
+            this._instrumentAdded(instrument);
 
         if (!WebInspector.timelineManager.isCapturingPageReload())
             this._resetSelection();
@@ -496,18 +496,17 @@ WebInspector.TimelineOverview = class TimelineOverview extends WebInspector.View
         this._gestureStartDurationPerPixel = NaN;
     }
 
-    _timelineAdded(timelineOrEvent)
+    _instrumentAdded(instrumentOrEvent)
     {
-        var timeline = timelineOrEvent;
-        if (!(timeline instanceof WebInspector.Timeline))
-            timeline = timelineOrEvent.data.timeline;
+        let instrument = instrumentOrEvent instanceof WebInspector.Instrument ? instrumentOrEvent : instrumentOrEvent.data.instrument;
+        console.assert(instrument instanceof WebInspector.Instrument, instrument);
 
-        console.assert(timeline instanceof WebInspector.Timeline, timeline);
+        let timeline = this._recording.timelineForInstrument(instrument);
         console.assert(!this._timelineOverviewGraphsMap.has(timeline), timeline);
         if (!this.canShowTimeline(timeline))
             return;
 
-        var overviewGraph = WebInspector.TimelineOverviewGraph.createForTimeline(timeline, this);
+        let overviewGraph = WebInspector.TimelineOverviewGraph.createForTimeline(timeline, this);
         overviewGraph.addEventListener(WebInspector.TimelineOverviewGraph.Event.RecordSelected, this._recordSelected, this);
         this._timelineOverviewGraphsMap.set(timeline, overviewGraph);
 
@@ -515,10 +514,12 @@ WebInspector.TimelineOverview = class TimelineOverview extends WebInspector.View
         this._graphsContainerElement.appendChild(overviewGraph.element);
     }
 
-    _timelineRemoved(event)
+    _instrumentRemoved(event)
     {
-        let timeline = event.data.timeline;
-        console.assert(timeline instanceof WebInspector.Timeline, timeline);
+        let instrument = event.data.instrument;
+        console.assert(instrument instanceof WebInspector.Instrument, instrument);
+
+        let timeline = this._recording.timelineForInstrument(instrument);
         if (!this.canShowTimeline(timeline))
             return;
 
index 9506848..3015c01 100644 (file)
@@ -68,8 +68,8 @@ WebInspector.TimelineRecordingContentView = class TimelineRecordingContentView e
         this._startTimeNeedsReset = true;
         this._renderingFrameTimeline = null;
 
-        this._recording.addEventListener(WebInspector.TimelineRecording.Event.TimelineAdded, this._timelineAdded, this);
-        this._recording.addEventListener(WebInspector.TimelineRecording.Event.TimelineRemoved, this._timelineRemoved, this);
+        this._recording.addEventListener(WebInspector.TimelineRecording.Event.InstrumentAdded, this._instrumentAdded, this);
+        this._recording.addEventListener(WebInspector.TimelineRecording.Event.InstrumentRemoved, this._instrumentRemoved, this);
         this._recording.addEventListener(WebInspector.TimelineRecording.Event.Reset, this._recordingReset, this);
         this._recording.addEventListener(WebInspector.TimelineRecording.Event.Unloaded, this._recordingUnloaded, this);
 
@@ -82,8 +82,8 @@ WebInspector.TimelineRecordingContentView = class TimelineRecordingContentView e
         WebInspector.ContentView.addEventListener(WebInspector.ContentView.Event.SelectionPathComponentsDidChange, this._contentViewSelectionPathComponentDidChange, this);
         WebInspector.ContentView.addEventListener(WebInspector.ContentView.Event.SupplementalRepresentedObjectsDidChange, this._contentViewSupplementalRepresentedObjectsDidChange, this);
 
-        for (var timeline of this._recording.timelines.values())
-            this._timelineAdded(timeline);
+        for (let instrument of this._recording.instruments)
+            this._instrumentAdded(instrument);
 
         this.showOverviewTimelineView();
     }
@@ -575,33 +575,36 @@ WebInspector.TimelineRecordingContentView = class TimelineRecordingContentView e
         this._contentViewContainer.element.style.top = styleValue;
     }
 
-    _timelineAdded(timelineOrEvent)
+    _instrumentAdded(instrumentOrEvent)
     {
-        var timeline = timelineOrEvent;
-        if (!(timeline instanceof WebInspector.Timeline))
-            timeline = timelineOrEvent.data.timeline;
+        let instrument = instrumentOrEvent instanceof WebInspector.Instrument ? instrumentOrEvent : instrumentOrEvent.data.instrument;
+        console.assert(instrument instanceof WebInspector.Instrument, instrument);
 
-        console.assert(timeline instanceof WebInspector.Timeline, timeline);
+        let timeline = this._recording.timelineForInstrument(instrument);
         console.assert(!this._timelineViewMap.has(timeline), timeline);
 
         this._timelineViewMap.set(timeline, WebInspector.ContentView.createFromRepresentedObject(timeline, {timelineSidebarPanel: this._timelineSidebarPanel}));
         if (timeline.type === WebInspector.TimelineRecord.Type.RenderingFrame)
             this._renderingFrameTimeline = timeline;
 
-        var pathComponent = new WebInspector.HierarchicalPathComponent(timeline.displayName, timeline.iconClassName, timeline);
+        let displayName = WebInspector.TimelineSidebarPanel.displayNameForTimeline(timeline);
+        let iconClassName = WebInspector.TimelineSidebarPanel.iconClassNameForTimeline(timeline);
+        let pathComponent = new WebInspector.HierarchicalPathComponent(displayName, iconClassName, timeline);
         pathComponent.addEventListener(WebInspector.HierarchicalPathComponent.Event.SiblingWasSelected, this._pathComponentSelected, this);
         this._pathComponentMap.set(timeline, pathComponent);
 
         this._timelineCountChanged();
     }
 
-    _timelineRemoved(event)
+    _instrumentRemoved(event)
     {
-        var timeline = event.data.timeline;
-        console.assert(timeline instanceof WebInspector.Timeline, timeline);
+        let instrument = event.data.instrument;
+        console.assert(instrument instanceof WebInspector.Instrument);
+
+        let timeline = this._recording.timelineForInstrument(instrument);
         console.assert(this._timelineViewMap.has(timeline), timeline);
 
-        var timelineView = this._timelineViewMap.take(timeline);
+        let timelineView = this._timelineViewMap.take(timeline);
         if (this.currentTimelineView === timelineView)
             this.showOverviewTimelineView();
         if (timeline.type === WebInspector.TimelineRecord.Type.RenderingFrame)
index 73ab479..1e332c4 100644 (file)
@@ -73,10 +73,7 @@ WebInspector.TimelineSidebarPanel = class TimelineSidebarPanel extends WebInspec
 
         this._timelineTreeElementMap = new Map;
 
-        // COMPATIBILITY (iOS 8): TimelineAgent.EventType.RenderingFrame did not exist.
-        this._renderingFramesSupported = window.TimelineAgent && TimelineAgent.EventType.RenderingFrame;
-
-        if (this._renderingFramesSupported) {
+        if (WebInspector.FPSInstrument.supported()) {
             var timelinesNavigationItem = new WebInspector.RadioButtonNavigationItem(WebInspector.TimelineSidebarPanel.ViewMode.Timelines, WebInspector.UIString("Timelines"))
             var renderingFramesNavigationItem = new WebInspector.RadioButtonNavigationItem(WebInspector.TimelineSidebarPanel.ViewMode.RenderingFrames, WebInspector.UIString("Rendering Frames"))
             this._viewModeNavigationBar = new WebInspector.NavigationBar(null, [timelinesNavigationItem, renderingFramesNavigationItem], "tablist");
@@ -182,6 +179,40 @@ WebInspector.TimelineSidebarPanel = class TimelineSidebarPanel extends WebInspec
         this._toggleNewRecordingShortcut.implicitlyPreventsDefault = false;
     }
 
+    // Static
+
+    static displayNameForTimeline(timeline)
+    {
+        switch (timeline.type) {
+        case WebInspector.TimelineRecord.Type.Network:
+            return WebInspector.UIString("Network Requests");
+        case WebInspector.TimelineRecord.Type.Layout:
+            return WebInspector.UIString("Layout & Rendering");
+        case WebInspector.TimelineRecord.Type.Script:
+            return WebInspector.UIString("JavaScript & Events");
+        case WebInspector.TimelineRecord.Type.RenderingFrame:
+            return WebInspector.UIString("Rendering Frames");
+        }
+
+        console.error("Unknown Timeline type:", timeline.type);
+    }
+
+    static iconClassNameForTimeline(timeline)
+    {
+        switch (timeline.type) {
+        case WebInspector.TimelineRecord.Type.Network:
+            return "network-icon";
+        case WebInspector.TimelineRecord.Type.Layout:
+            return "colors-icon";
+        case WebInspector.TimelineRecord.Type.Script:
+            return "script-icon";
+        case WebInspector.TimelineRecord.Type.RenderingFrame:
+            return "rendering-frame-icon";
+        }
+
+        console.error("Unknown Timeline type:", timeline.type);
+    }
+
     // Public
 
     shown()
@@ -366,7 +397,7 @@ WebInspector.TimelineSidebarPanel = class TimelineSidebarPanel extends WebInspec
 
     updateFrameSelection(startFrameIndex, endFrameIndex)
     {
-        console.assert(startFrameIndex <= endFrameIndex);
+        console.assert(startFrameIndex <= endFrameIndex, startFrameIndex, endFrameIndex);
         console.assert(this.viewMode === WebInspector.TimelineSidebarPanel.ViewMode.RenderingFrames, this._viewMode);
         if (this._startFrameIndex === startFrameIndex && this._endFrameIndex === endFrameIndex)
             return;
@@ -510,7 +541,7 @@ WebInspector.TimelineSidebarPanel = class TimelineSidebarPanel extends WebInspec
         this._restoredShowingTimelineRecordingContentView = cookie[WebInspector.TimelineSidebarPanel.ShowingTimelineRecordingContentViewCookieKey];
 
         var selectedTimelineViewIdentifier = cookie[WebInspector.TimelineSidebarPanel.SelectedTimelineViewIdentifierCookieKey];
-        if (selectedTimelineViewIdentifier === WebInspector.TimelineRecord.Type.RenderingFrame && !this._renderingFramesSupported)
+        if (selectedTimelineViewIdentifier === WebInspector.TimelineRecord.Type.RenderingFrame && !WebInspector.FPSInstrument.supported())
             selectedTimelineViewIdentifier = null;
 
         if (selectedTimelineViewIdentifier && this._displayedRecording.timelines.has(selectedTimelineViewIdentifier))
@@ -669,8 +700,8 @@ WebInspector.TimelineSidebarPanel = class TimelineSidebarPanel extends WebInspec
         var oldRecording = this._displayedRecording || null;
 
         if (oldRecording) {
-            oldRecording.removeEventListener(WebInspector.TimelineRecording.Event.TimelineAdded, this._timelineAdded, this);
-            oldRecording.removeEventListener(WebInspector.TimelineRecording.Event.TimelineRemoved, this._timelineRemoved, this);
+            oldRecording.removeEventListener(WebInspector.TimelineRecording.Event.InstrumentAdded, this._instrumentAdded, this);
+            oldRecording.removeEventListener(WebInspector.TimelineRecording.Event.InstrumentRemoved, this._instrumentRemoved, this);
 
             // Destroy tree elements in one operation to avoid unnecessary fixups.
             this._timelinesTreeOutline.removeChildren();
@@ -678,11 +709,11 @@ WebInspector.TimelineSidebarPanel = class TimelineSidebarPanel extends WebInspec
         }
 
         this._displayedRecording = recording;
-        this._displayedRecording.addEventListener(WebInspector.TimelineRecording.Event.TimelineAdded, this._timelineAdded, this);
-        this._displayedRecording.addEventListener(WebInspector.TimelineRecording.Event.TimelineRemoved, this._timelineRemoved, this);
+        this._displayedRecording.addEventListener(WebInspector.TimelineRecording.Event.InstrumentAdded, this._instrumentAdded, this);
+        this._displayedRecording.addEventListener(WebInspector.TimelineRecording.Event.InstrumentRemoved, this._instrumentRemoved, this);
 
-        for (var timeline of recording.timelines.values())
-            this._timelineAdded(timeline);
+        for (let instrument of recording.instruments)
+            this._instrumentAdded(instrument);
 
         // Save the current state incase we need to restore it to a new recording.
         var cookie = {};
@@ -717,13 +748,12 @@ WebInspector.TimelineSidebarPanel = class TimelineSidebarPanel extends WebInspec
         this._recordingSelected(WebInspector.timelineManager.activeRecording);
     }
 
-    _timelineAdded(timelineOrEvent)
+    _instrumentAdded(instrumentOrEvent)
     {
-        var timeline = timelineOrEvent;
-        if (!(timeline instanceof WebInspector.Timeline))
-            timeline = timelineOrEvent.data.timeline;
+        let instrument = instrumentOrEvent instanceof WebInspector.Instrument ? instrumentOrEvent : instrumentOrEvent.data.instrument;
+        console.assert(instrument instanceof WebInspector.Instrument, instrument);
 
-        console.assert(timeline instanceof WebInspector.Timeline, timeline);
+        let timeline = this._displayedRecording.timelineForInstrument(instrument);
         console.assert(!this._timelineTreeElementMap.has(timeline), timeline);
 
         if (timeline.type === WebInspector.TimelineRecord.Type.RenderingFrame) {
@@ -731,9 +761,11 @@ WebInspector.TimelineSidebarPanel = class TimelineSidebarPanel extends WebInspec
             return;
         }
 
-        var timelineTreeElement = new WebInspector.GeneralTreeElement([timeline.iconClassName, WebInspector.TimelineSidebarPanel.LargeIconStyleClass], timeline.displayName, null, timeline);
-        var tooltip = WebInspector.UIString("Close %s timeline view").format(timeline.displayName);
-        var button = new WebInspector.TreeElementStatusButton(useSVGSymbol("Images/CloseLarge.svg", "close-button", tooltip));
+        let displayName = WebInspector.TimelineSidebarPanel.displayNameForTimeline(timeline);
+        let iconClassName = WebInspector.TimelineSidebarPanel.iconClassNameForTimeline(timeline);
+        let timelineTreeElement = new WebInspector.GeneralTreeElement([iconClassName, WebInspector.TimelineSidebarPanel.LargeIconStyleClass], displayName, null, timeline);
+        let tooltip = WebInspector.UIString("Close %s timeline view").format(displayName);
+        let button = new WebInspector.TreeElementStatusButton(useSVGSymbol("Images/CloseLarge.svg", "close-button", tooltip));
         button.addEventListener(WebInspector.TreeElementStatusButton.Event.Clicked, this.showTimelineOverview, this);
         timelineTreeElement.status = button.element;
 
@@ -743,10 +775,12 @@ WebInspector.TimelineSidebarPanel = class TimelineSidebarPanel extends WebInspec
         this._timelineCountChanged();
     }
 
-    _timelineRemoved(event)
+    _instrumentRemoved(event)
     {
-        var timeline = event.data.timeline;
-        console.assert(timeline instanceof WebInspector.Timeline, timeline);
+        let instrument = event.data.instrument;
+        console.assert(instrument instanceof WebInspector.Instrument, instrument);
+
+        let timeline = this._displayedRecording.timelineForInstrument(instrument);
 
         if (timeline.type === WebInspector.TimelineRecord.Type.RenderingFrame) {
             timeline.removeEventListener(WebInspector.Timeline.Event.TimesUpdated, this._renderingFrameTimelineTimesUpdated, this);
@@ -755,9 +789,9 @@ WebInspector.TimelineSidebarPanel = class TimelineSidebarPanel extends WebInspec
 
         console.assert(this._timelineTreeElementMap.has(timeline), timeline);
 
-        var timelineTreeElement = this._timelineTreeElementMap.take(timeline);
-        var shouldSuppressOnDeselect = false;
-        var shouldSuppressSelectSibling = true;
+        let timelineTreeElement = this._timelineTreeElementMap.take(timeline);
+        let shouldSuppressOnDeselect = false;
+        let shouldSuppressSelectSibling = true;
         this._timelinesTreeOutline.removeChild(timelineTreeElement, shouldSuppressOnDeselect, shouldSuppressSelectSibling);
         this._timelineTreeElementMap.delete(timeline);
 
@@ -835,7 +869,7 @@ WebInspector.TimelineSidebarPanel = class TimelineSidebarPanel extends WebInspec
 
     _changeViewMode(mode, selectedByUser)
     {
-        if (!this._renderingFramesSupported || this._viewMode === mode)
+        if (!WebInspector.FPSInstrument.supported() || this._viewMode === mode)
             return;
 
         this._viewMode = mode;
@@ -1021,10 +1055,6 @@ WebInspector.TimelineSidebarPanel.TimelineEventsTitleBarStyleClass = "timeline-e
 WebInspector.TimelineSidebarPanel.TimelinesContentContainerStyleClass = "timelines-content";
 WebInspector.TimelineSidebarPanel.LargeIconStyleClass = "large";
 WebInspector.TimelineSidebarPanel.StopwatchIconStyleClass = "stopwatch-icon";
-WebInspector.TimelineSidebarPanel.NetworkIconStyleClass = "network-icon";
-WebInspector.TimelineSidebarPanel.ColorsIconStyleClass = "colors-icon";
-WebInspector.TimelineSidebarPanel.ScriptIconStyleClass = "script-icon";
-WebInspector.TimelineSidebarPanel.RenderingFrameIconStyleClass = "rendering-frame-icon";
 WebInspector.TimelineSidebarPanel.TimelineRecordingContentViewShowingStyleClass = "timeline-recording-content-view-showing";
 
 WebInspector.TimelineSidebarPanel.ShowingTimelineRecordingContentViewCookieKey = "timeline-sidebar-panel-showing-timeline-recording-content-view";