Title: [237670] trunk
Revision
237670
Author
drou...@apple.com
Date
2018-10-31 21:13:41 -0700 (Wed, 31 Oct 2018)

Log Message

Web Inspector: Canvas: create a setting for auto-recording newly created contexts
https://bugs.webkit.org/show_bug.cgi?id=190856

Reviewed by Brian Burg.

Source/_javascript_Core:

* inspector/protocol/Canvas.json:
Add `setRecordingAutoCaptureFrameCount` command for setting the number of frames to record
immediately after a context is created.

* inspector/protocol/Recording.json:
Add `creation` value for `Initiator` enum.

Source/WebCore:

Test: inspector/canvas/setRecordingAutoCaptureFrameCount.html

* inspector/agents/InspectorCanvasAgent.h:
(WebCore::InspectorCanvasAgent::RecordingOptions): Added.
* inspector/agents/InspectorCanvasAgent.cpp:
(WebCore::InspectorCanvasAgent::enable):
(WebCore::InspectorCanvasAgent::disable):
(WebCore::InspectorCanvasAgent::setRecordingAutoCaptureFrameCount): Added.
(WebCore::InspectorCanvasAgent::startRecording):
(WebCore::InspectorCanvasAgent::didCreateCanvasRenderingContext):
(WebCore::InspectorCanvasAgent::didFinishRecordingCanvasFrame):
(WebCore::InspectorCanvasAgent::consoleStartRecordingCanvas):
(WebCore::InspectorCanvasAgent::startRecording): Added.
Unify the different functions that are able to start a recording to use a single path.

* inspector/InspectorCanvas.h:
* inspector/InspectorCanvas.cpp:
(WebCore::InspectorCanvas::resetRecordingData):
(WebCore::InspectorCanvas::recordAction):
(WebCore::InspectorCanvas::setFrameCount): Added.
(WebCore::InspectorCanvas::overFrameCount const): Added.

Source/WebInspectorUI:

* UserInterface/Controllers/CanvasManager.js:
(WI.CanvasManager.supportsRecordingAutoCapture): Added.
(WI.CanvasManager.prototype.setRecordingAutoCaptureFrameCount): Added.

* UserInterface/Models/Canvas.js:
(WI.Canvas.prototype.startRecording):
(WI.Canvas.prototype.recordingStarted):
(WI.Canvas.prototype.recordingFinished):

* UserInterface/Models/Recording.js:

* UserInterface/Views/CanvasOverviewContentView.js:
(WI.CanvasOverviewContentView):
(WI.CanvasOverviewContentView.prototype.get navigationItems):
(WI.CanvasOverviewContentView.prototype.initialLayout): Added.
(WI.CanvasOverviewContentView.prototype.attached):
(WI.CanvasOverviewContentView.prototype.detached):
(WI.CanvasOverviewContentView.prototype._setRecordingAutoCaptureFrameCount): Added.
(WI.CanvasOverviewContentView.prototype._updateRecordingAutoCaptureInputElementSize): Added.
(WI.CanvasOverviewContentView.prototype._handleRecordingAutoCaptureInput): Added.
(WI.CanvasOverviewContentView.prototype._handleRecordingAutoCaptureCheckedDidChange): Added.
(WI.CanvasOverviewContentView.prototype._handleCanvasRecordingAutoCaptureEnabledChanged): Added.
(WI.CanvasOverviewContentView.prototype._handleCanvasRecordingAutoCaptureFrameCountChanged): Added.
* UserInterface/Views/CanvasOverviewContentView.css:
(.navigation-bar > .item.canvas-recording-auto-capture > label): Added.
(.navigation-bar > .item.canvas-recording-auto-capture > label > input): Added.
(.navigation-bar > .item.canvas-recording-auto-capture > label > input::-webkit-inner-spin-button): Added.
(.popover-content > .tree-outline .item.recording > .icon): Deleted.
(.popover-content > .tree-outline .item.recording:hover): Deleted.
(.popover-content > .tree-outline .item.recording:hover > .icon): Deleted.
Drive-by: removed unused CSS rules.

* UserInterface/Views/CanvasContentView.js:
(WI.CanvasContentView.prototype.initialLayout):
(WI.CanvasContentView.prototype._updateProgressView):
(WI.CanvasContentView.prototype._updateViewRelatedItems):

* UserInterface/Views/CanvasTabContentView.js:
(WI.CanvasTabContentView.prototype._recordingImportedOrStopped):

* UserInterface/Views/CheckboxNavigationItem.js:
(WI.CheckboxNavigationItem):
(WI.CheckboxNavigationItem.prototype._handleLabelClick): Added.

* UserInterface/Base/Setting.js:

* Localizations/en.lproj/localizedStrings.js:

LayoutTests:

* inspector/canvas/resources/recording-utilities.js:
(TestPage.registerInitializer.window.startRecording):
(TestPage.registerInitializer.handleRecordingProgress):
* inspector/canvas/recording-2d.html:
* inspector/canvas/recording-bitmaprenderer.html:
* inspector/canvas/recording-webgl-snapshots.html:
* inspector/canvas/recording-webgl.html:

* inspector/canvas/setRecordingAutoCaptureFrameCount-expected.txt: Added.
* inspector/canvas/setRecordingAutoCaptureFrameCount.html: Added.

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (237669 => 237670)


--- trunk/LayoutTests/ChangeLog	2018-11-01 04:12:59 UTC (rev 237669)
+++ trunk/LayoutTests/ChangeLog	2018-11-01 04:13:41 UTC (rev 237670)
@@ -1,5 +1,23 @@
 2018-10-31  Devin Rousso  <drou...@apple.com>
 
+        Web Inspector: Canvas: create a setting for auto-recording newly created contexts
+        https://bugs.webkit.org/show_bug.cgi?id=190856
+
+        Reviewed by Brian Burg.
+
+        * inspector/canvas/resources/recording-utilities.js:
+        (TestPage.registerInitializer.window.startRecording):
+        (TestPage.registerInitializer.handleRecordingProgress):
+        * inspector/canvas/recording-2d.html:
+        * inspector/canvas/recording-bitmaprenderer.html:
+        * inspector/canvas/recording-webgl-snapshots.html:
+        * inspector/canvas/recording-webgl.html:
+
+        * inspector/canvas/setRecordingAutoCaptureFrameCount-expected.txt: Added.
+        * inspector/canvas/setRecordingAutoCaptureFrameCount.html: Added.
+
+2018-10-31  Devin Rousso  <drou...@apple.com>
+
         Web Inspector: Audit: save imported audits across WebInspector sessions
         https://bugs.webkit.org/show_bug.cgi?id=190858
         <rdar://problem/45527625>

Modified: trunk/LayoutTests/inspector/canvas/recording-2d.html (237669 => 237670)


--- trunk/LayoutTests/inspector/canvas/recording-2d.html	2018-11-01 04:12:59 UTC (rev 237669)
+++ trunk/LayoutTests/inspector/canvas/recording-2d.html	2018-11-01 04:13:41 UTC (rev 237670)
@@ -436,7 +436,7 @@
         name: "Canvas.recording2D.singleFrame",
         description: "Check that the recording is stopped after a single frame.",
         test(resolve, reject) {
-            startRecording(WI.Canvas.ContextType.Canvas2D, resolve, reject, {singleFrame: true});
+            startRecording(WI.Canvas.ContextType.Canvas2D, resolve, reject, {frameCount: 1});
         },
     });
 
@@ -444,7 +444,7 @@
         name: "Canvas.recording2D.multipleFrames",
         description: "Check that recording data is serialized correctly for multiple frames.",
         test(resolve, reject) {
-            startRecording(WI.Canvas.ContextType.Canvas2D, resolve, reject, {singleFrame: false});
+            startRecording(WI.Canvas.ContextType.Canvas2D, resolve, reject);
         },
     });
 
@@ -493,8 +493,8 @@
                 InspectorTest.evaluateInPage(`performNaNActions()`);
             });
 
-            const singleFrame = true;
-            CanvasAgent.startRecording(canvas.identifier, singleFrame)
+            const frameCount = 1;
+            CanvasAgent.startRecording(canvas.identifier, frameCount)
             .catch(reject);
         },
     });
@@ -538,8 +538,8 @@
 
             InspectorTest.evaluateInPage(`performSavePreActions()`)
             .then(() => {
-                const singleFrame = true;
-                CanvasAgent.startRecording(canvas.identifier, singleFrame).catch(reject);
+                const frameCount = 1;
+                CanvasAgent.startRecording(canvas.identifier, frameCount).catch(reject);
             }, reject);
         },
     });

Modified: trunk/LayoutTests/inspector/canvas/recording-bitmaprenderer.html (237669 => 237670)


--- trunk/LayoutTests/inspector/canvas/recording-bitmaprenderer.html	2018-11-01 04:12:59 UTC (rev 237669)
+++ trunk/LayoutTests/inspector/canvas/recording-bitmaprenderer.html	2018-11-01 04:13:41 UTC (rev 237670)
@@ -87,7 +87,7 @@
         name: "Canvas.recordingBitmapRenderer.singleFrame",
         description: "Check that the recording is stopped after a single frame.",
         test(resolve, reject) {
-            startRecording(WI.Canvas.ContextType.BitmapRenderer, resolve, reject, {singleFrame: true});
+            startRecording(WI.Canvas.ContextType.BitmapRenderer, resolve, reject, {frameCount: 1});
         },
     });
 
@@ -95,7 +95,7 @@
         name: "Canvas.recordingBitmapRenderer.multipleFrames",
         description: "Check that recording data is serialized correctly for multiple frames.",
         test(resolve, reject) {
-            startRecording(WI.Canvas.ContextType.BitmapRenderer, resolve, reject, {singleFrame: false});
+            startRecording(WI.Canvas.ContextType.BitmapRenderer, resolve, reject);
         },
     });
 

Modified: trunk/LayoutTests/inspector/canvas/recording-webgl-snapshots.html (237669 => 237670)


--- trunk/LayoutTests/inspector/canvas/recording-webgl-snapshots.html	2018-11-01 04:12:59 UTC (rev 237669)
+++ trunk/LayoutTests/inspector/canvas/recording-webgl-snapshots.html	2018-11-01 04:13:41 UTC (rev 237670)
@@ -100,7 +100,7 @@
         name: "Canvas.recordingWebGL.snapshots",
         description: "Check that the snapshot taken after each visual action is different.",
         test(resolve, reject) {
-            startRecording(WI.Canvas.ContextType.WebGL, resolve, reject, {singleFrame: true});
+            startRecording(WI.Canvas.ContextType.WebGL, resolve, reject, {frameCount: 1});
         },
     });
 

Modified: trunk/LayoutTests/inspector/canvas/recording-webgl.html (237669 => 237670)


--- trunk/LayoutTests/inspector/canvas/recording-webgl.html	2018-11-01 04:12:59 UTC (rev 237669)
+++ trunk/LayoutTests/inspector/canvas/recording-webgl.html	2018-11-01 04:13:41 UTC (rev 237670)
@@ -513,7 +513,7 @@
         name: "Canvas.recordingWebGL.singleFrame",
         description: "Check that the recording is stopped after a single frame.",
         test(resolve, reject) {
-            startRecording(WI.Canvas.ContextType.WebGL, resolve, reject, {singleFrame: true});
+            startRecording(WI.Canvas.ContextType.WebGL, resolve, reject, {frameCount: 1});
         },
     });
 
@@ -521,7 +521,7 @@
         name: "Canvas.recordingWebGL.multipleFrames",
         description: "Check that recording data is serialized correctly for multiple frames.",
         test(resolve, reject) {
-            startRecording(WI.Canvas.ContextType.WebGL, resolve, reject, {singleFrame: false});
+            startRecording(WI.Canvas.ContextType.WebGL, resolve, reject);
         },
     });
 

Modified: trunk/LayoutTests/inspector/canvas/resources/recording-utilities.js (237669 => 237670)


--- trunk/LayoutTests/inspector/canvas/resources/recording-utilities.js	2018-11-01 04:12:59 UTC (rev 237669)
+++ trunk/LayoutTests/inspector/canvas/resources/recording-utilities.js	2018-11-01 04:13:41 UTC (rev 237670)
@@ -83,7 +83,7 @@
         return canvases[0];
     };
 
-    window.startRecording = function(type, resolve, reject, {singleFrame, memoryLimit} = {}) {
+    window.startRecording = function(type, resolve, reject, {frameCount, memoryLimit} = {}) {
         let canvas = getCanvas(type);
         if (!canvas) {
             reject(`Missing canvas with type "${type}".`);
@@ -110,10 +110,10 @@
         });
 
         let bufferUsed = 0;
-        let frameCount = 0;
+        let recordingFrameCount = 0;
         function handleRecordingProgress(event) {
-            InspectorTest.assert(canvas.recordingFrameCount > frameCount, "Additional frames were captured for this progress event.");
-            frameCount = canvas.recordingFrameCount;
+            InspectorTest.assert(canvas.recordingFrameCount > recordingFrameCount, "Additional frames were captured for this progress event.");
+            recordingFrameCount = canvas.recordingFrameCount;
 
             InspectorTest.assert(canvas.recordingBufferUsed > bufferUsed, "Total memory usage increases with each progress event.");
             bufferUsed = canvas.recordingBufferUsed;
@@ -129,8 +129,11 @@
             InspectorTest.assert(recording.source === canvas, "Recording should be of the given canvas.");
             InspectorTest.assert(recording.source.contextType === type, `Recording should be of a canvas with type "${type}".`);
             InspectorTest.assert(recording.source.recordingCollection.has(recording), "Recording should be in the canvas' list of recordings.");
-            InspectorTest.assert(recording.frames.length === frameCount, `Recording should have ${frameCount} frames.`)
+            InspectorTest.assert(recording.frames.length === recordingFrameCount, `Recording should have ${recordingFrameCount} frames.`)
 
+            if (frameCount)
+                InspectorTest.assert(recording.frames.length === frameCount, `Recording frame count should match the provided value ${frameCount}.`)
+
             Promise.all(recording.actions.map((action) => action.swizzle(recording))).then(() => {
                 swizzled = true;
 
@@ -148,7 +151,7 @@
             InspectorTest.evaluateInPage(`performActions()`).catch(reject);
         });
 
-        CanvasAgent.startRecording(canvas.identifier, singleFrame, memoryLimit).catch(reject);
+        CanvasAgent.startRecording(canvas.identifier, frameCount, memoryLimit).catch(reject);
     };
 
     window.consoleRecord = function(type, resolve, reject) {

Added: trunk/LayoutTests/inspector/canvas/setRecordingAutoCaptureFrameCount-expected.txt (0 => 237670)


--- trunk/LayoutTests/inspector/canvas/setRecordingAutoCaptureFrameCount-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/inspector/canvas/setRecordingAutoCaptureFrameCount-expected.txt	2018-11-01 04:13:41 UTC (rev 237670)
@@ -0,0 +1,32 @@
+Test that contexts created after calling Canvas.setRecordingAutoCaptureFrameCount are properly recorded.
+
+
+== Running test suite: Canvas.setRecordingAutoCaptureFrameCount
+-- Running test case: Canvas.setRecordingAutoCaptureFrameCount.2D.None
+PASS: Canvas should have no finished recordings.
+
+-- Running test case: Canvas.setRecordingAutoCaptureFrameCount.2D.Single
+PASS: Recording stopped.
+PASS: Recording should have one frame.
+PASS: Recording should have one action.
+PASS: Canvas should have one finished recording.
+
+-- Running test case: Canvas.setRecordingAutoCaptureFrameCount.2D.Multiple
+PASS: Canvas should have no finished recordings.
+PASS: Canvas should be actively recording.
+PASS: Recording should have 2 frames.
+
+-- Running test case: Canvas.setRecordingAutoCaptureFrameCount.WebGL.None
+PASS: Canvas should have no finished recordings.
+
+-- Running test case: Canvas.setRecordingAutoCaptureFrameCount.WebGL.Single
+PASS: Recording stopped.
+PASS: Recording should have one frame.
+PASS: Recording should have one action.
+PASS: Canvas should have one finished recording.
+
+-- Running test case: Canvas.setRecordingAutoCaptureFrameCount.WebGL.Multiple
+PASS: Canvas should have no finished recordings.
+PASS: Canvas should be actively recording.
+PASS: Recording should have 2 frames.
+

Added: trunk/LayoutTests/inspector/canvas/setRecordingAutoCaptureFrameCount.html (0 => 237670)


--- trunk/LayoutTests/inspector/canvas/setRecordingAutoCaptureFrameCount.html	                        (rev 0)
+++ trunk/LayoutTests/inspector/canvas/setRecordingAutoCaptureFrameCount.html	2018-11-01 04:13:41 UTC (rev 237670)
@@ -0,0 +1,221 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src=""
+<script>
+if (window.internals)
+    window.internals.settings.setWebGLErrorsToConsoleEnabled(false);
+
+let timeoutID = NaN;
+
+function cancelActions() {
+    clearTimeout(timeoutID);
+    timeoutID = NaN;
+}
+
+function performActions(frames) {
+    let index = 0;
+    function executeFrameFunction() {
+        frames[index++]();
+
+        if (index < frames.length)
+            timeoutID = setTimeout(executeFrameFunction, 0);
+        else {
+            setTimeout(() => {
+                TestPage.dispatchEventToFrontend("LastFrame");
+            }, 0);
+        }
+    };
+    executeFrameFunction();
+}
+
+function performActions2D() {
+    let context = document.createElement("canvas").getContext("2d");
+    performActions([
+        () => {
+            context.fill();
+        },
+        () => {
+            context.stroke();
+        },
+    ]);
+}
+
+function performActionsWebGL() {
+    let context = document.createElement("canvas").getContext("webgl");
+    performActions([
+        () => {
+            context.drawArrays(1, 2, 3);
+        },
+        () => {
+            context.drawElements(1, 2, 3, 4);
+        },
+    ]);
+}
+
+function test() {
+    let suite = InspectorTest.createAsyncSuite("Canvas.setRecordingAutoCaptureFrameCount");
+
+    function addTest({name, description, frameCount, _expression_, handleRecordingStarted, handleRecordingStopped, handleLastFrame}) {
+        suite.addTestCase({
+            name,
+            description,
+            test(resolve, reject) {
+                let canvas = null;
+
+                function handleRecordingStartedWrapper(event)
+                {
+                    InspectorTest.assert(event.target === canvas, "Should be recording the canvas.");
+
+                    handleRecordingStarted(canvas);
+                }
+
+                function handleRecordingStoppedWrapper(event)
+                {
+                    InspectorTest.assert(event.target === canvas, "Should be recording the canvas.");
+
+                    handleRecordingStopped(canvas, event.data.recording);
+                }
+
+                WI.canvasManager.awaitEvent(WI.CanvasManager.Event.CanvasAdded)
+                .then((event) => {
+                    canvas = event.data.canvas;
+
+                    canvas.addEventListener(WI.Canvas.Event.RecordingStarted, handleRecordingStartedWrapper);
+                    canvas.addEventListener(WI.Canvas.Event.RecordingStopped, handleRecordingStoppedWrapper);
+                });
+
+                InspectorTest.awaitEvent("LastFrame")
+                .then((event) => {
+                    canvas.removeEventListener(WI.Canvas.Event.RecordingStarted, handleRecordingStartedWrapper);
+                    canvas.removeEventListener(WI.Canvas.Event.RecordingStopped, handleRecordingStoppedWrapper);
+
+                    handleLastFrame(canvas);
+                })
+                .then(resolve, reject);
+
+                CanvasAgent.setRecordingAutoCaptureFrameCount(frameCount)
+                .then(() => {
+                    InspectorTest.evaluateInPage(_expression_).catch(reject);
+                })
+                .catch(reject);
+            },
+        });
+    }
+
+    addTest({
+        name: "Canvas.setRecordingAutoCaptureFrameCount.2D.None",
+        description: "Check that newly created 2D contexts are not recorded when setRecordingAutoCaptureFrameCount is 0.",
+        frameCount: 0,
+        _expression_: `performActions2D()`,
+        handleRecordingStarted(canvas) {
+            InspectorTest.fail("Canvas should not be recording.");
+        },
+        handleRecordingStopped(canvas, recording) {
+            InspectorTest.fail("Canvas should not be recording.");
+        },
+        handleLastFrame(canvas) {
+            InspectorTest.expectEqual(canvas.recordingCollection.size, 0, "Canvas should have no finished recordings.");
+        },
+    });
+
+    addTest({
+        name: "Canvas.setRecordingAutoCaptureFrameCount.2D.Single",
+        description: "Check that newly created 2D contexts only record one frame when setRecordingAutoCaptureFrameCount is 1.",
+        frameCount: 1,
+        _expression_: `performActions2D()`,
+        handleRecordingStarted(canvas) {
+            InspectorTest.pass("Recording started.");
+        },
+        handleRecordingStopped(canvas, recording) {
+            InspectorTest.pass("Recording stopped.");
+            InspectorTest.expectEqual(recording.frames.length, 1, "Recording should have one frame.");
+            InspectorTest.expectEqual(recording.frames[0].actions.length, 1, "Recording should have one action.");
+        },
+        handleLastFrame(canvas) {
+            InspectorTest.expectEqual(canvas.recordingCollection.size, 1, "Canvas should have one finished recording.");
+        },
+    });
+
+    addTest({
+        name: "Canvas.setRecordingAutoCaptureFrameCount.2D.Multiple",
+        description: "Check that newly created 2D contexts don't finish recording when setRecordingAutoCaptureFrameCount is 10.",
+        frameCount: 10,
+        _expression_: `performActions2D()`,
+        handleRecordingStarted(canvas) {
+            InspectorTest.pass("Recording started.");
+        },
+        handleRecordingStopped(canvas, recording) {
+            InspectorTest.fail("Canvas should not be done recording.");
+        },
+        handleLastFrame(canvas) {
+            InspectorTest.expectEqual(canvas.recordingCollection.size, 0, "Canvas should have no finished recordings.");
+            InspectorTest.expectThat(canvas.recordingActive, "Canvas should be actively recording.");
+            InspectorTest.expectEqual(canvas.recordingFrameCount, 2, "Recording should have 2 frames.");
+
+            canvas.stopRecording();
+        },
+    });
+
+    addTest({
+        name: "Canvas.setRecordingAutoCaptureFrameCount.WebGL.None",
+        description: "Check that newly created WebGL contexts are not recorded when setRecordingAutoCaptureFrameCount is 0.",
+        frameCount: 0,
+        _expression_: `performActionsWebGL()`,
+        handleRecordingStarted(canvas) {
+            InspectorTest.fail("Canvas should not be recording.");
+        },
+        handleRecordingStopped(canvas, recording) {
+            InspectorTest.fail("Canvas should not be recording.");
+        },
+        handleLastFrame(canvas) {
+            InspectorTest.expectEqual(canvas.recordingCollection.size, 0, "Canvas should have no finished recordings.");
+        },
+    });
+
+    addTest({
+        name: "Canvas.setRecordingAutoCaptureFrameCount.WebGL.Single",
+        description: "Check that newly created WebGL contexts only record one frame when setRecordingAutoCaptureFrameCount is 1.",
+        frameCount: 1,
+        _expression_: `performActionsWebGL()`,
+        handleRecordingStarted(canvas) {
+            InspectorTest.pass("Recording started.");
+        },
+        handleRecordingStopped(canvas, recording) {
+            InspectorTest.pass("Recording stopped.");
+            InspectorTest.expectEqual(recording.frames.length, 1, "Recording should have one frame.");
+            InspectorTest.expectEqual(recording.frames[0].actions.length, 1, "Recording should have one action.");
+        },
+        handleLastFrame(canvas) {
+            InspectorTest.expectEqual(canvas.recordingCollection.size, 1, "Canvas should have one finished recording.");
+        },
+    });
+
+    addTest({
+        name: "Canvas.setRecordingAutoCaptureFrameCount.WebGL.Multiple",
+        description: "Check that newly created WebGL contexts don't finish recording when setRecordingAutoCaptureFrameCount is 10.",
+        frameCount: 10,
+        _expression_: `performActionsWebGL()`,
+        handleRecordingStarted(canvas) {
+            InspectorTest.pass("Recording started.");
+        },
+        handleRecordingStopped(canvas, recording) {
+            InspectorTest.fail("Canvas should not be done recording.");
+        },
+        handleLastFrame(canvas) {
+            InspectorTest.expectEqual(canvas.recordingCollection.size, 0, "Canvas should have no finished recordings.");
+            InspectorTest.expectThat(canvas.recordingActive, "Canvas should be actively recording.");
+            InspectorTest.expectEqual(canvas.recordingFrameCount, 2, "Recording should have 2 frames.");
+
+            canvas.stopRecording();
+        },
+    });
+
+    suite.runTestCasesAndFinish();
+}
+</script>
+</head>
+<body _onload_="runTest()">
+    <p>Test that contexts created after calling Canvas.setRecordingAutoCaptureFrameCount are properly recorded.</p>
+</body>
+</html>

Modified: trunk/Source/_javascript_Core/ChangeLog (237669 => 237670)


--- trunk/Source/_javascript_Core/ChangeLog	2018-11-01 04:12:59 UTC (rev 237669)
+++ trunk/Source/_javascript_Core/ChangeLog	2018-11-01 04:13:41 UTC (rev 237670)
@@ -1,5 +1,19 @@
 2018-10-31  Devin Rousso  <drou...@apple.com>
 
+        Web Inspector: Canvas: create a setting for auto-recording newly created contexts
+        https://bugs.webkit.org/show_bug.cgi?id=190856
+
+        Reviewed by Brian Burg.
+
+        * inspector/protocol/Canvas.json:
+        Add `setRecordingAutoCaptureFrameCount` command for setting the number of frames to record
+        immediately after a context is created.
+
+        * inspector/protocol/Recording.json:
+        Add `creation` value for `Initiator` enum.
+
+2018-10-31  Devin Rousso  <drou...@apple.com>
+
         Web Inspector: display low-power enter/exit events in Timelines and Network node waterfalls
         https://bugs.webkit.org/show_bug.cgi?id=190641
         <rdar://problem/45319049>

Modified: trunk/Source/_javascript_Core/inspector/protocol/Canvas.json (237669 => 237670)


--- trunk/Source/_javascript_Core/inspector/protocol/Canvas.json	2018-11-01 04:12:59 UTC (rev 237669)
+++ trunk/Source/_javascript_Core/inspector/protocol/Canvas.json	2018-11-01 04:13:41 UTC (rev 237670)
@@ -105,12 +105,19 @@
             ]
         },
         {
+            "name": "setRecordingAutoCaptureFrameCount",
+            "description": "Tells the backend to record `count` frames whenever a new context is created.",
+            "parameters": [
+                { "name": "count", "type": "integer", "description": "Number of frames to record (0 means don't record anything)." }
+            ]
+        },
+        {
             "name": "startRecording",
             "description": "Record the next frame, or up to the given number of bytes of data, for the given canvas.",
             "parameters": [
                 { "name": "canvasId", "$ref": "CanvasId" },
-                { "name": "singleFrame", "type": "boolean", "optional": true, "description": "Whether to record a single frame or until the memory limit is reached." },
-                { "name": "memoryLimit", "type": "integer", "optional": true, "description": "Memory limit of recorded data." }
+                { "name": "frameCount", "type": "integer", "optional": true, "description": "Number of frames to record (unlimited when not specified)." },
+                { "name": "memoryLimit", "type": "integer", "optional": true, "description": "Memory limit of recorded data (100MB when not specified)." }
             ]
         },
         {

Modified: trunk/Source/_javascript_Core/inspector/protocol/Recording.json (237669 => 237670)


--- trunk/Source/_javascript_Core/inspector/protocol/Recording.json	2018-11-01 04:12:59 UTC (rev 237669)
+++ trunk/Source/_javascript_Core/inspector/protocol/Recording.json	2018-11-01 04:13:41 UTC (rev 237670)
@@ -11,7 +11,7 @@
         {
             "id": "Initiator",
             "type": "string",
-            "enum": ["frontend", "console"]
+            "enum": ["frontend", "console", "auto-capture"]
         },
         {
             "id": "InitialState",

Modified: trunk/Source/WebCore/ChangeLog (237669 => 237670)


--- trunk/Source/WebCore/ChangeLog	2018-11-01 04:12:59 UTC (rev 237669)
+++ trunk/Source/WebCore/ChangeLog	2018-11-01 04:13:41 UTC (rev 237670)
@@ -1,5 +1,34 @@
 2018-10-31  Devin Rousso  <drou...@apple.com>
 
+        Web Inspector: Canvas: create a setting for auto-recording newly created contexts
+        https://bugs.webkit.org/show_bug.cgi?id=190856
+
+        Reviewed by Brian Burg.
+
+        Test: inspector/canvas/setRecordingAutoCaptureFrameCount.html
+
+        * inspector/agents/InspectorCanvasAgent.h:
+        (WebCore::InspectorCanvasAgent::RecordingOptions): Added.
+        * inspector/agents/InspectorCanvasAgent.cpp:
+        (WebCore::InspectorCanvasAgent::enable):
+        (WebCore::InspectorCanvasAgent::disable):
+        (WebCore::InspectorCanvasAgent::setRecordingAutoCaptureFrameCount): Added.
+        (WebCore::InspectorCanvasAgent::startRecording):
+        (WebCore::InspectorCanvasAgent::didCreateCanvasRenderingContext):
+        (WebCore::InspectorCanvasAgent::didFinishRecordingCanvasFrame):
+        (WebCore::InspectorCanvasAgent::consoleStartRecordingCanvas):
+        (WebCore::InspectorCanvasAgent::startRecording): Added.
+        Unify the different functions that are able to start a recording to use a single path.
+
+        * inspector/InspectorCanvas.h:
+        * inspector/InspectorCanvas.cpp:
+        (WebCore::InspectorCanvas::resetRecordingData):
+        (WebCore::InspectorCanvas::recordAction):
+        (WebCore::InspectorCanvas::setFrameCount): Added.
+        (WebCore::InspectorCanvas::overFrameCount const): Added.
+
+2018-10-31  Devin Rousso  <drou...@apple.com>
+
         Web Inspector: display low-power enter/exit events in Timelines and Network node waterfalls
         https://bugs.webkit.org/show_bug.cgi?id=190641
         <rdar://problem/45319049>

Modified: trunk/Source/WebCore/inspector/InspectorCanvas.cpp (237669 => 237670)


--- trunk/Source/WebCore/inspector/InspectorCanvas.cpp	2018-11-01 04:12:59 UTC (rev 237669)
+++ trunk/Source/WebCore/inspector/InspectorCanvas.cpp	2018-11-01 04:13:41 UTC (rev 237670)
@@ -105,7 +105,8 @@
     m_recordingName = { };
     m_bufferLimit = 100 * 1024 * 1024;
     m_bufferUsed = 0;
-    m_singleFrame = true;
+    m_frameCount = std::nullopt;
+    m_framesCaptured = 0;
 
     m_context.setCallTracingActive(false);
 }
@@ -150,6 +151,7 @@
             .release();
 
         m_frames->addItem(WTFMove(frame));
+        ++m_framesCaptured;
 
         m_currentFrameStartTime = MonotonicTime::now();
     }
@@ -216,6 +218,19 @@
     return m_bufferUsed < m_bufferLimit;
 }
 
+void InspectorCanvas::setFrameCount(long frameCount)
+{
+    if (frameCount > 0)
+        m_frameCount = std::min<long>(frameCount, std::numeric_limits<int>::max());
+    else
+        m_frameCount = std::nullopt;
+}
+
+bool InspectorCanvas::overFrameCount() const
+{
+    return m_frameCount && m_framesCaptured >= m_frameCount.value();
+}
+
 Ref<Inspector::Protocol::Canvas::Canvas> InspectorCanvas::buildObjectForCanvas(bool captureBacktrace)
 {
     Inspector::Protocol::Canvas::ContextType contextType;

Modified: trunk/Source/WebCore/inspector/InspectorCanvas.h (237669 => 237670)


--- trunk/Source/WebCore/inspector/InspectorCanvas.h	2018-11-01 04:12:59 UTC (rev 237669)
+++ trunk/Source/WebCore/inspector/InspectorCanvas.h	2018-11-01 04:13:41 UTC (rev 237670)
@@ -71,8 +71,8 @@
     bool hasBufferSpace() const;
     long bufferUsed() const { return m_bufferUsed; }
 
-    bool singleFrame() const { return m_singleFrame; }
-    void setSingleFrame(bool singleFrame) { m_singleFrame = singleFrame; }
+    void setFrameCount(long);
+    bool overFrameCount() const;
 
     Ref<Inspector::Protocol::Canvas::Canvas> buildObjectForCanvas(bool captureBacktrace);
 
@@ -117,7 +117,8 @@
     MonotonicTime m_currentFrameStartTime { MonotonicTime::nan() };
     size_t m_bufferLimit { 100 * 1024 * 1024 };
     size_t m_bufferUsed { 0 };
-    bool m_singleFrame { false };
+    std::optional<size_t> m_frameCount;
+    size_t m_framesCaptured { 0 };
 };
 
 } // namespace WebCore

Modified: trunk/Source/WebCore/inspector/agents/InspectorCanvasAgent.cpp (237669 => 237670)


--- trunk/Source/WebCore/inspector/agents/InspectorCanvasAgent.cpp	2018-11-01 04:12:59 UTC (rev 237669)
+++ trunk/Source/WebCore/inspector/agents/InspectorCanvasAgent.cpp	2018-11-01 04:13:41 UTC (rev 237670)
@@ -95,6 +95,8 @@
     if (m_enabled)
         return;
 
+    m_recordingAutoCaptureFrameCount = std::nullopt;
+
     m_enabled = true;
 
     const bool captureBacktrace = false;
@@ -138,6 +140,8 @@
     for (auto& inspectorCanvas : m_identifierToInspectorCanvas.values())
         inspectorCanvas->resetRecordingData();
 
+    m_recordingAutoCaptureFrameCount = std::nullopt;
+
     m_enabled = false;
 }
 
@@ -261,8 +265,16 @@
     result = injectedScript.wrapObject(value, objectGroupName);
 }
 
-void InspectorCanvasAgent::startRecording(ErrorString& errorString, const String& canvasId, const bool* singleFrame, const int* memoryLimit)
+void InspectorCanvasAgent::setRecordingAutoCaptureFrameCount(ErrorString&, int count)
 {
+    if (count > 0)
+        m_recordingAutoCaptureFrameCount = count;
+    else
+        m_recordingAutoCaptureFrameCount = std::nullopt;
+}
+
+void InspectorCanvasAgent::startRecording(ErrorString& errorString, const String& canvasId, const int* frameCount, const int* memoryLimit)
+{
     auto* inspectorCanvas = assertInspectorCanvas(errorString, canvasId);
     if (!inspectorCanvas)
         return;
@@ -272,15 +284,12 @@
         return;
     }
 
-    inspectorCanvas->resetRecordingData();
-    if (singleFrame)
-        inspectorCanvas->setSingleFrame(*singleFrame);
+    RecordingOptions recordingOptions;
+    if (frameCount)
+        recordingOptions.frameCount = *frameCount;
     if (memoryLimit)
-        inspectorCanvas->setBufferLimit(*memoryLimit);
-
-    inspectorCanvas->context().setCallTracingActive(true);
-
-    m_frontendDispatcher->recordingStarted(inspectorCanvas->identifier(), Inspector::Protocol::Recording::Initiator::Frontend);
+        recordingOptions.memoryLimit = *memoryLimit;
+    startRecording(*inspectorCanvas, Inspector::Protocol::Recording::Initiator::Frontend, WTFMove(recordingOptions));
 }
 
 void InspectorCanvasAgent::stopRecording(ErrorString& errorString, const String& canvasId)
@@ -429,14 +438,20 @@
 
     context.canvasBase().addObserver(*this);
 
-    auto inspectorCanvas = InspectorCanvas::create(context);
+    RefPtr<InspectorCanvas> inspectorCanvas = InspectorCanvas::create(context);
+    m_identifierToInspectorCanvas.set(inspectorCanvas->identifier(), inspectorCanvas);
 
-    if (m_enabled) {
-        const bool captureBacktrace = true;
-        m_frontendDispatcher->canvasAdded(inspectorCanvas->buildObjectForCanvas(captureBacktrace));
+    if (!m_enabled)
+        return;
+
+    const bool captureBacktrace = true;
+    m_frontendDispatcher->canvasAdded(inspectorCanvas->buildObjectForCanvas(captureBacktrace));
+
+    if (m_recordingAutoCaptureFrameCount) {
+        RecordingOptions recordingOptions;
+        recordingOptions.frameCount = m_recordingAutoCaptureFrameCount.value();
+        startRecording(*inspectorCanvas, Inspector::Protocol::Recording::Initiator::AutoCapture, WTFMove(recordingOptions));
     }
-
-    m_identifierToInspectorCanvas.set(inspectorCanvas->identifier(), WTFMove(inspectorCanvas));
 }
 
 void InspectorCanvasAgent::didChangeCanvasMemory(CanvasRenderingContext& context)
@@ -523,7 +538,7 @@
     if (inspectorCanvas->currentFrameHasData())
         m_frontendDispatcher->recordingProgress(inspectorCanvas->identifier(), inspectorCanvas->releaseFrames(), inspectorCanvas->bufferUsed());
 
-    if (!forceDispatch && !inspectorCanvas->singleFrame())
+    if (!forceDispatch && !inspectorCanvas->overFrameCount())
         return;
 
     // FIXME: <https://webkit.org/b/176008> Web Inspector: Record actions performed on WebGL2RenderingContext
@@ -565,23 +580,18 @@
     if (!inspectorCanvas)
         return;
 
-    if (inspectorCanvas->context().callTracingActive())
-        return;
-
-    inspectorCanvas->resetRecordingData();
-
+    RecordingOptions recordingOptions;
     if (options) {
-        if (JSC::JSValue optionName = options->get(&exec, JSC::Identifier::fromString(&exec, "name")))
-            inspectorCanvas->setRecordingName(optionName.toWTFString(&exec));
         if (JSC::JSValue optionSingleFrame = options->get(&exec, JSC::Identifier::fromString(&exec, "singleFrame")))
-            inspectorCanvas->setSingleFrame(optionSingleFrame.toBoolean(&exec));
+            recordingOptions.frameCount = optionSingleFrame.toBoolean(&exec) ? 1 : 0;
+        if (JSC::JSValue optionFrameCount = options->get(&exec, JSC::Identifier::fromString(&exec, "frameCount")))
+            recordingOptions.frameCount = optionFrameCount.toNumber(&exec);
         if (JSC::JSValue optionMemoryLimit = options->get(&exec, JSC::Identifier::fromString(&exec, "memoryLimit")))
-            inspectorCanvas->setBufferLimit(optionMemoryLimit.toNumber(&exec));
+            recordingOptions.memoryLimit = optionMemoryLimit.toNumber(&exec);
+        if (JSC::JSValue optionName = options->get(&exec, JSC::Identifier::fromString(&exec, "name")))
+            recordingOptions.name = optionName.toWTFString(&exec);
     }
-
-    inspectorCanvas->context().setCallTracingActive(true);
-
-    m_frontendDispatcher->recordingStarted(inspectorCanvas->identifier(), Inspector::Protocol::Recording::Initiator::Console);
+    startRecording(*inspectorCanvas, Inspector::Protocol::Recording::Initiator::Console, WTFMove(recordingOptions));
 }
 
 #if ENABLE(WEBGL)
@@ -640,6 +650,32 @@
 }
 #endif
 
+void InspectorCanvasAgent::startRecording(InspectorCanvas& inspectorCanvas, Inspector::Protocol::Recording::Initiator initiator, RecordingOptions&& recordingOptions)
+{
+    auto& canvasRenderingContext = inspectorCanvas.context();
+
+    if (!is<CanvasRenderingContext2D>(canvasRenderingContext)
+#if ENABLE(WEBGL)
+        && !is<WebGLRenderingContext>(canvasRenderingContext)
+#endif
+        && !is<ImageBitmapRenderingContext>(canvasRenderingContext))
+        return;
+
+    if (canvasRenderingContext.callTracingActive())
+        return;
+
+    inspectorCanvas.resetRecordingData();
+    if (recordingOptions.frameCount)
+        inspectorCanvas.setFrameCount(recordingOptions.frameCount.value());
+    if (recordingOptions.memoryLimit)
+        inspectorCanvas.setBufferLimit(recordingOptions.memoryLimit.value());
+    if (recordingOptions.name)
+        inspectorCanvas.setRecordingName(recordingOptions.name.value());
+    canvasRenderingContext.setCallTracingActive(true);
+
+    m_frontendDispatcher->recordingStarted(inspectorCanvas.identifier(), initiator);
+}
+
 void InspectorCanvasAgent::canvasDestroyedTimerFired()
 {
     if (!m_removedCanvasIdentifiers.size())

Modified: trunk/Source/WebCore/inspector/agents/InspectorCanvasAgent.h (237669 => 237670)


--- trunk/Source/WebCore/inspector/agents/InspectorCanvasAgent.h	2018-11-01 04:12:59 UTC (rev 237669)
+++ trunk/Source/WebCore/inspector/agents/InspectorCanvasAgent.h	2018-11-01 04:13:41 UTC (rev 237670)
@@ -73,7 +73,8 @@
     void requestContent(ErrorString&, const String& canvasId, String* content) override;
     void requestCSSCanvasClientNodes(ErrorString&, const String& canvasId, RefPtr<JSON::ArrayOf<int>>&) override;
     void resolveCanvasContext(ErrorString&, const String& canvasId, const String* objectGroup, RefPtr<Inspector::Protocol::Runtime::RemoteObject>&) override;
-    void startRecording(ErrorString&, const String& canvasId, const bool* singleFrame, const int* memoryLimit) override;
+    void setRecordingAutoCaptureFrameCount(ErrorString&, int count) override;
+    void startRecording(ErrorString&, const String& canvasId, const int* frameCount, const int* memoryLimit) override;
     void stopRecording(ErrorString&, const String& canvasId) override;
     void requestShaderSource(ErrorString&, const String& programId, const String& shaderType, String*) override;
     void updateShader(ErrorString&, const String& programId, const String& shaderType, const String& source) override;
@@ -103,6 +104,13 @@
     void canvasDestroyed(CanvasBase&) override;
 
 private:
+    struct RecordingOptions {
+        std::optional<long> frameCount;
+        std::optional<long> memoryLimit;
+        std::optional<String> name;
+    };
+    void startRecording(InspectorCanvas&, Inspector::Protocol::Recording::Initiator, RecordingOptions&& = { });
+
     void canvasDestroyedTimerFired();
     void canvasRecordingTimerFired();
     void clearCanvasData();
@@ -124,6 +132,7 @@
     Vector<String> m_removedCanvasIdentifiers;
     Timer m_canvasDestroyedTimer;
     Timer m_canvasRecordingTimer;
+    std::optional<size_t> m_recordingAutoCaptureFrameCount;
 
     bool m_enabled { false };
 };

Modified: trunk/Source/WebInspectorUI/ChangeLog (237669 => 237670)


--- trunk/Source/WebInspectorUI/ChangeLog	2018-11-01 04:12:59 UTC (rev 237669)
+++ trunk/Source/WebInspectorUI/ChangeLog	2018-11-01 04:13:41 UTC (rev 237670)
@@ -1,5 +1,60 @@
 2018-10-31  Devin Rousso  <drou...@apple.com>
 
+        Web Inspector: Canvas: create a setting for auto-recording newly created contexts
+        https://bugs.webkit.org/show_bug.cgi?id=190856
+
+        Reviewed by Brian Burg.
+
+        * UserInterface/Controllers/CanvasManager.js:
+        (WI.CanvasManager.supportsRecordingAutoCapture): Added.
+        (WI.CanvasManager.prototype.setRecordingAutoCaptureFrameCount): Added.
+
+        * UserInterface/Models/Canvas.js:
+        (WI.Canvas.prototype.startRecording):
+        (WI.Canvas.prototype.recordingStarted):
+        (WI.Canvas.prototype.recordingFinished):
+
+        * UserInterface/Models/Recording.js:
+
+        * UserInterface/Views/CanvasOverviewContentView.js:
+        (WI.CanvasOverviewContentView):
+        (WI.CanvasOverviewContentView.prototype.get navigationItems):
+        (WI.CanvasOverviewContentView.prototype.initialLayout): Added.
+        (WI.CanvasOverviewContentView.prototype.attached):
+        (WI.CanvasOverviewContentView.prototype.detached):
+        (WI.CanvasOverviewContentView.prototype._setRecordingAutoCaptureFrameCount): Added.
+        (WI.CanvasOverviewContentView.prototype._updateRecordingAutoCaptureInputElementSize): Added.
+        (WI.CanvasOverviewContentView.prototype._handleRecordingAutoCaptureInput): Added.
+        (WI.CanvasOverviewContentView.prototype._handleRecordingAutoCaptureCheckedDidChange): Added.
+        (WI.CanvasOverviewContentView.prototype._handleCanvasRecordingAutoCaptureEnabledChanged): Added.
+        (WI.CanvasOverviewContentView.prototype._handleCanvasRecordingAutoCaptureFrameCountChanged): Added.
+        * UserInterface/Views/CanvasOverviewContentView.css:
+        (.navigation-bar > .item.canvas-recording-auto-capture > label): Added.
+        (.navigation-bar > .item.canvas-recording-auto-capture > label > input): Added.
+        (.navigation-bar > .item.canvas-recording-auto-capture > label > input::-webkit-inner-spin-button): Added.
+        (.popover-content > .tree-outline .item.recording > .icon): Deleted.
+        (.popover-content > .tree-outline .item.recording:hover): Deleted.
+        (.popover-content > .tree-outline .item.recording:hover > .icon): Deleted.
+        Drive-by: removed unused CSS rules.
+
+        * UserInterface/Views/CanvasContentView.js:
+        (WI.CanvasContentView.prototype.initialLayout):
+        (WI.CanvasContentView.prototype._updateProgressView):
+        (WI.CanvasContentView.prototype._updateViewRelatedItems):
+
+        * UserInterface/Views/CanvasTabContentView.js:
+        (WI.CanvasTabContentView.prototype._recordingImportedOrStopped):
+
+        * UserInterface/Views/CheckboxNavigationItem.js:
+        (WI.CheckboxNavigationItem):
+        (WI.CheckboxNavigationItem.prototype._handleLabelClick): Added.
+
+        * UserInterface/Base/Setting.js:
+
+        * Localizations/en.lproj/localizedStrings.js:
+
+2018-10-31  Devin Rousso  <drou...@apple.com>
+
         Web Inspector: display low-power enter/exit events in Timelines and Network node waterfalls
         https://bugs.webkit.org/show_bug.cgi?id=190641
         <rdar://problem/45319049>

Modified: trunk/Source/WebInspectorUI/Localizations/en.lproj/localizedStrings.js (237669 => 237670)


--- trunk/Source/WebInspectorUI/Localizations/en.lproj/localizedStrings.js	2018-11-01 04:12:59 UTC (rev 237669)
+++ trunk/Source/WebInspectorUI/Localizations/en.lproj/localizedStrings.js	2018-11-01 04:13:41 UTC (rev 237670)
@@ -678,6 +678,7 @@
 localizedStrings["Readonly"] = "Readonly";
 localizedStrings["Reasons for compositing"] = "Reasons for compositing";
 localizedStrings["Reasons for compositing:"] = "Reasons for compositing:";
+localizedStrings["Record first %s frames"] = "Record first %s frames";
 localizedStrings["Recording"] = "Recording";
 localizedStrings["Recording %d"] = "Recording %d";
 localizedStrings["Recording Timeline Data"] = "Recording Timeline Data";

Modified: trunk/Source/WebInspectorUI/UserInterface/Base/Setting.js (237669 => 237670)


--- trunk/Source/WebInspectorUI/UserInterface/Base/Setting.js	2018-11-01 04:12:59 UTC (rev 237669)
+++ trunk/Source/WebInspectorUI/UserInterface/Base/Setting.js	2018-11-01 04:13:41 UTC (rev 237670)
@@ -103,6 +103,8 @@
 };
 
 WI.settings = {
+    canvasRecordingAutoCaptureEnabled: new WI.Setting("canvas-recording-auto-capture-enabled", false),
+    canvasRecordingAutoCaptureFrameCount: new WI.Setting("canvas-recording-auto-capture-frame-count", 1),
     clearLogOnNavigate: new WI.Setting("clear-log-on-navigate", true),
     clearNetworkOnNavigate: new WI.Setting("clear-network-on-navigate", true),
     enableControlFlowProfiler: new WI.Setting("enable-control-flow-profiler", false),

Modified: trunk/Source/WebInspectorUI/UserInterface/Controllers/CanvasManager.js (237669 => 237670)


--- trunk/Source/WebInspectorUI/UserInterface/Controllers/CanvasManager.js	2018-11-01 04:12:59 UTC (rev 237669)
+++ trunk/Source/WebInspectorUI/UserInterface/Controllers/CanvasManager.js	2018-11-01 04:13:41 UTC (rev 237670)
@@ -46,6 +46,13 @@
             target.CanvasAgent.enable();
     }
 
+    // Static
+
+    static supportsRecordingAutoCapture()
+    {
+        return window.CanvasAgent && CanvasAgent.setRecordingAutoCaptureFrameCount;
+    }
+
     // Public
 
     get importedRecordings() { return this._importedRecordings; }
@@ -91,6 +98,20 @@
         });
     }
 
+    setRecordingAutoCaptureFrameCount(enabled, count)
+    {
+        console.assert(!isNaN(count) && count >= 0);
+
+        return CanvasAgent.setRecordingAutoCaptureFrameCount(enabled ? count : 0)
+        .then(() => {
+            WI.settings.canvasRecordingAutoCaptureEnabled.value = enabled && count;
+            WI.settings.canvasRecordingAutoCaptureFrameCount.value = count;
+        })
+        .catch((error) => {
+            console.error(error);
+        });
+    }
+
     canvasAdded(canvasPayload)
     {
         // Called from WI.CanvasObserver.

Modified: trunk/Source/WebInspectorUI/UserInterface/Models/Canvas.js (237669 => 237670)


--- trunk/Source/WebInspectorUI/UserInterface/Models/Canvas.js	2018-11-01 04:12:59 UTC (rev 237669)
+++ trunk/Source/WebInspectorUI/UserInterface/Models/Canvas.js	2018-11-01 04:13:41 UTC (rev 237670)
@@ -269,7 +269,7 @@
 
     startRecording(singleFrame)
     {
-        CanvasAgent.startRecording(this._identifier, singleFrame, (error) => {
+        let handleStartRecording = (error) => {
             if (error) {
                 console.error(error);
                 return;
@@ -285,7 +285,19 @@
             this._recordingBufferUsed = 0;
 
             this.dispatchEventToListeners(WI.Canvas.Event.RecordingStarted);
-        });
+        };
+
+        // COMPATIBILITY (iOS 12.1): `frameCount` did not exist yet.
+        if (CanvasAgent.startRecording.supports("singleFrame")) {
+            CanvasAgent.startRecording(this._identifier, singleFrame, handleStartRecording);
+            return;
+        }
+
+        if (singleFrame) {
+            const frameCount = 1;
+            CanvasAgent.startRecording(this._identifier, frameCount, handleStartRecording);
+        } else
+            CanvasAgent.startRecording(this._identifier, handleStartRecording);
     }
 
     stopRecording()
@@ -330,10 +342,12 @@
     {
         // Called from WI.CanvasManager.
 
-        if (initiator === WI.Recording.Initiator.Console)
+        if (initiator === RecordingAgent.Initiator.Console)
             this._recordingState = WI.Canvas.RecordingState.ActiveConsole;
+        else if (initiator === RecordingAgent.Initiator.AutoCapture)
+            this._recordingState = WI.Canvas.RecordingState.ActiveAutoCapture;
         else {
-            console.assert(initiator === WI.Recording.Initiator.Frontend);
+            console.assert(initiator === RecordingAgent.Initiator.Frontend);
             this._recordingState = WI.Canvas.RecordingState.ActiveFrontend;
         }
 
@@ -358,11 +372,11 @@
     {
         // Called from WI.CanvasManager.
 
-        let fromConsole = this._recordingState === WI.Canvas.RecordingState.ActiveConsole;
+        let initiatedByUser = this._recordingState === WI.Canvas.RecordingState.ActiveFrontend;
 
         // COMPATIBILITY (iOS 12.1): Canvas.event.recordingStarted did not exist yet
-        if (!fromConsole && !CanvasAgent.hasEvent("recordingStarted"))
-            fromConsole = !this.recordingActive;
+        if (!initiatedByUser && !CanvasAgent.hasEvent("recordingStarted"))
+            initiatedByUser = !!this.recordingActive;
 
         let recording = recordingPayload ? WI.Recording.fromPayload(recordingPayload, this._recordingFrames) : null;
         if (recording) {
@@ -376,7 +390,7 @@
         this._recordingFrames = [];
         this._recordingBufferUsed = 0;
 
-        this.dispatchEventToListeners(WI.Canvas.Event.RecordingStopped, {recording, fromConsole});
+        this.dispatchEventToListeners(WI.Canvas.Event.RecordingStopped, {recording, initiatedByUser});
     }
 
     nextShaderProgramDisplayNumber()
@@ -405,6 +419,7 @@
     Inactive: "canvas-recording-state-inactive",
     ActiveFrontend: "canvas-recording-state-active-frontend",
     ActiveConsole: "canvas-recording-state-active-console",
+    ActiveAutoCapture: "canvas-recording-state-active-auto-capture",
 };
 
 WI.Canvas.Event = {

Modified: trunk/Source/WebInspectorUI/UserInterface/Models/Recording.js (237669 => 237670)


--- trunk/Source/WebInspectorUI/UserInterface/Models/Recording.js	2018-11-01 04:12:59 UTC (rev 237669)
+++ trunk/Source/WebInspectorUI/UserInterface/Models/Recording.js	2018-11-01 04:13:41 UTC (rev 237670)
@@ -539,11 +539,6 @@
     CanvasWebGL: "canvas-webgl",
 };
 
-WI.Recording.Initiator = {
-    Frontend: "frontend",
-    Console: "console",
-};
-
 // Keep this in sync with WebCore::RecordingSwizzleTypes.
 WI.Recording.Swizzle = {
     None: 0,

Modified: trunk/Source/WebInspectorUI/UserInterface/Views/CanvasContentView.js (237669 => 237670)


--- trunk/Source/WebInspectorUI/UserInterface/Views/CanvasContentView.js	2018-11-01 04:12:59 UTC (rev 237669)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/CanvasContentView.js	2018-11-01 04:13:41 UTC (rev 237670)
@@ -149,6 +149,8 @@
 
         if (this._errorElement)
             this._showError();
+
+        this._updateProgressView();
     }
 
     layout()
@@ -371,6 +373,9 @@
 
     _updateProgressView()
     {
+        if (!this._previewContainerElement)
+            return;
+
         if (!this.representedObject.recordingActive) {
             if (this._progressView && this._progressView.parentView) {
                 this.removeSubview(this._progressView);
@@ -398,6 +403,9 @@
 
     _updateViewRelatedItems()
     {
+        if (!this._viewRelatedItemsContainer)
+            return;
+
         this._viewRelatedItemsContainer.removeChildren();
 
         if (this.representedObject.shaderProgramCollection.size)

Modified: trunk/Source/WebInspectorUI/UserInterface/Views/CanvasOverviewContentView.css (237669 => 237670)


--- trunk/Source/WebInspectorUI/UserInterface/Views/CanvasOverviewContentView.css	2018-11-01 04:12:59 UTC (rev 237669)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/CanvasOverviewContentView.css	2018-11-01 04:13:41 UTC (rev 237670)
@@ -173,18 +173,20 @@
     -webkit-padding-start: 4px;
 }
 
-.popover-content > .tree-outline .item.recording > .icon {
-    content: url(../Images/Recording.svg);
+.navigation-bar > .item.canvas-recording-auto-capture > label {
+    display: flex;
+    align-items: center;
 }
 
-.popover-content > .tree-outline .item.recording:hover {
-    color: var(--selected-foreground-color);
-    background-color: var(--selected-background-color);
-    border-radius: 3px;
+.navigation-bar > .item.canvas-recording-auto-capture > label > input {
+    width: 1.5em;
+    min-width: 1.5em;
+    margin: 0 4px;
+    text-align: center;
 }
 
-.popover-content > .tree-outline .item.recording:hover > .icon {
-    filter: invert();
+.navigation-bar > .item.canvas-recording-auto-capture > label > input::-webkit-inner-spin-button {
+    -webkit-appearance: none;
 }
 
 @media (prefers-dark-interface) {

Modified: trunk/Source/WebInspectorUI/UserInterface/Views/CanvasOverviewContentView.js (237669 => 237670)


--- trunk/Source/WebInspectorUI/UserInterface/Views/CanvasOverviewContentView.js	2018-11-01 04:12:59 UTC (rev 237669)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/CanvasOverviewContentView.js	2018-11-01 04:13:41 UTC (rev 237670)
@@ -45,6 +45,24 @@
 
         this.element.classList.add("canvas-overview");
 
+        if (WI.CanvasManager.supportsRecordingAutoCapture()) {
+            this._recordingAutoCaptureFrameCountInputElement = document.createElement("input");
+            this._recordingAutoCaptureFrameCountInputElement.type = "number";
+            this._recordingAutoCaptureFrameCountInputElement.min = 0;
+            this._recordingAutoCaptureFrameCountInputElement.value = WI.settings.canvasRecordingAutoCaptureFrameCount.value;
+            this._recordingAutoCaptureFrameCountInputElement.addEventListener("input", this._handleRecordingAutoCaptureInput.bind(this));
+
+            let label = document.createDocumentFragment();
+            String.format(WI.UIString("Record first %s frames"), [this._recordingAutoCaptureFrameCountInputElement], String.standardFormatters, label, (a, b) => {
+                a.append(b);
+                return a;
+            });
+
+            this._recordingAutoCaptureNavigationItem = new WI.CheckboxNavigationItem("canvas-recording-auto-capture", label, !!WI.settings.canvasRecordingAutoCaptureEnabled.value);
+            this._recordingAutoCaptureNavigationItem.visibilityPriority = WI.NavigationItem.VisibilityPriority.Low;
+            this._recordingAutoCaptureNavigationItem.addEventListener(WI.CheckboxNavigationItem.Event.CheckedDidChange, this._handleRecordingAutoCaptureCheckedDidChange, this);
+        }
+
         this._importButtonNavigationItem = new WI.ButtonNavigationItem("import-recording", WI.UIString("Import"), "Images/Import.svg", 15, 15);
         this._importButtonNavigationItem.toolTip = WI.UIString("Import recording from file");
         this._importButtonNavigationItem.buttonStyle = WI.ButtonNavigationItem.Style.ImageAndText;
@@ -64,7 +82,10 @@
 
     get navigationItems()
     {
-        return [this._importButtonNavigationItem, new WI.DividerNavigationItem, this._refreshButtonNavigationItem, this._showGridButtonNavigationItem];
+        let navigationItems = [this._importButtonNavigationItem, new WI.DividerNavigationItem, this._refreshButtonNavigationItem, this._showGridButtonNavigationItem];
+        if (WI.CanvasManager.supportsRecordingAutoCapture())
+            navigationItems.unshift(this._recordingAutoCaptureNavigationItem, new WI.DividerNavigationItem);
+        return navigationItems;
     }
 
     hidden()
@@ -76,6 +97,16 @@
 
     // Protected
 
+    initialLayout()
+    {
+        super.initialLayout();
+
+        if (WI.CanvasManager.supportsRecordingAutoCapture()) {
+            this._updateRecordingAutoCaptureInputElementSize();
+            this._setRecordingAutoCaptureFrameCount();
+        }
+    }
+
     contentViewAdded(contentView)
     {
         contentView.element.addEventListener("mouseenter", this._contentViewMouseEnter);
@@ -97,10 +128,14 @@
         super.attached();
 
         WI.settings.showImageGrid.addEventListener(WI.Setting.Event.Changed, this._updateShowImageGrid, this);
+        WI.settings.canvasRecordingAutoCaptureEnabled.addEventListener(WI.Setting.Event.Changed, this._handleCanvasRecordingAutoCaptureEnabledChanged, this);
+        WI.settings.canvasRecordingAutoCaptureFrameCount.addEventListener(WI.Setting.Event.Changed, this._handleCanvasRecordingAutoCaptureFrameCountChanged, this);
     }
 
     detached()
     {
+        WI.settings.canvasRecordingAutoCaptureFrameCount.removeEventListener(null, null, this);
+        WI.settings.canvasRecordingAutoCaptureEnabled.removeEventListener(null, null, this);
         WI.settings.showImageGrid.removeEventListener(null, null, this);
 
         super.detached();
@@ -161,4 +196,57 @@
     {
         WI.domManager.hideDOMNodeHighlight();
     }
+
+    _setRecordingAutoCaptureFrameCount()
+    {
+        let frameCount = parseInt(this._recordingAutoCaptureFrameCountInputElement.value);
+        console.assert(!isNaN(frameCount) && frameCount >= 0);
+
+        let enabled = frameCount && !!this._recordingAutoCaptureNavigationItem.checked;
+
+        WI.canvasManager.setRecordingAutoCaptureFrameCount(enabled, frameCount);
+    }
+
+    _updateRecordingAutoCaptureInputElementSize()
+    {
+        let frameCount = parseInt(this._recordingAutoCaptureFrameCountInputElement.value);
+        if (isNaN(frameCount) || frameCount < 0) {
+            frameCount = 0;
+            this._recordingAutoCaptureFrameCountInputElement.value = frameCount;
+        }
+
+        WI.ImageUtilities.scratchCanvasContext2D((context) => {
+            if (!this._recordingAutoCaptureFrameCountInputElement.__cachedFont) {
+                let computedStyle = window.getComputedStyle(this._recordingAutoCaptureFrameCountInputElement);
+                this._recordingAutoCaptureFrameCountInputElement.__cachedFont = computedStyle.font;
+            }
+
+            context.font = this._recordingAutoCaptureFrameCountInputElement.__cachedFont;
+            let textMetrics = context.measureText(this._recordingAutoCaptureFrameCountInputElement.value);
+            this._recordingAutoCaptureFrameCountInputElement.style.setProperty("width", (textMetrics.width + 8) + "px");
+        });
+
+        this._recordingAutoCaptureNavigationItem.checked = !!frameCount;
+    }
+
+    _handleRecordingAutoCaptureInput(event)
+    {
+        this._updateRecordingAutoCaptureInputElementSize();
+        this._setRecordingAutoCaptureFrameCount();
+    }
+
+    _handleRecordingAutoCaptureCheckedDidChange(event)
+    {
+        this._setRecordingAutoCaptureFrameCount();
+    }
+
+    _handleCanvasRecordingAutoCaptureEnabledChanged(event)
+    {
+        this._recordingAutoCaptureNavigationItem.checked = WI.settings.canvasRecordingAutoCaptureEnabled.value;
+    }
+
+    _handleCanvasRecordingAutoCaptureFrameCountChanged(event)
+    {
+        this._recordingAutoCaptureFrameCountInputElement.value = WI.settings.canvasRecordingAutoCaptureFrameCount.value;
+    }
 };

Modified: trunk/Source/WebInspectorUI/UserInterface/Views/CanvasTabContentView.js (237669 => 237670)


--- trunk/Source/WebInspectorUI/UserInterface/Views/CanvasTabContentView.js	2018-11-01 04:12:59 UTC (rev 237669)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/CanvasTabContentView.js	2018-11-01 04:13:41 UTC (rev 237670)
@@ -247,12 +247,12 @@
 
     _recordingImportedOrStopped(event)
     {
-        let recording = event.data.recording;
+        let {recording, initiatedByUser} = event.data;
         if (!recording)
             return;
 
         this._addRecording(recording, {
-            suppressShowRecording: event.data.fromConsole || this.contentBrowser.currentRepresentedObjects.some((representedObject) => representedObject instanceof WI.Recording),
+            suppressShowRecording: !initiatedByUser || this.contentBrowser.currentRepresentedObjects.some((representedObject) => representedObject instanceof WI.Recording),
         });
     }
 

Modified: trunk/Source/WebInspectorUI/UserInterface/Views/CheckboxNavigationItem.js (237669 => 237670)


--- trunk/Source/WebInspectorUI/UserInterface/Views/CheckboxNavigationItem.js	2018-11-01 04:12:59 UTC (rev 237669)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/CheckboxNavigationItem.js	2018-11-01 04:13:41 UTC (rev 237670)
@@ -33,13 +33,13 @@
         this._checkboxElement.checked = checked;
         this._checkboxElement.id = "checkbox-navigation-item-" + identifier;
         this._checkboxElement.type = "checkbox";
-
         this._checkboxElement.addEventListener("change", this._checkboxChanged.bind(this));
 
         this._checkboxLabel = this.element.appendChild(document.createElement("label"));
         this._checkboxLabel.className = "toggle";
-        this._checkboxLabel.textContent = label;
+        this._checkboxLabel.append(label);
         this._checkboxLabel.setAttribute("for", this._checkboxElement.id);
+        this._checkboxLabel.addEventListener("click", this._handleLabelClick.bind(this));
     }
 
     // Public
@@ -67,6 +67,12 @@
     {
         this.dispatchEventToListeners(WI.CheckboxNavigationItem.Event.CheckedDidChange);
     }
+
+    _handleLabelClick(event)
+    {
+        if (WI.isEventTargetAnEditableField(event))
+            event.stop();
+    }
 };
 
 WI.CheckboxNavigationItem.Event = {
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to