Title: [243356] trunk
Revision
243356
Author
drou...@apple.com
Date
2019-03-21 19:47:35 -0700 (Thu, 21 Mar 2019)

Log Message

Web Inspector: Safari Canvas Inspector seems to show the canvas being rendered twice per frame.
https://bugs.webkit.org/show_bug.cgi?id=196082
<rdar://problem/49113496>

Reviewed by Dean Jackson.

Source/WebCore:

Tests: inspector/canvas/recording-2d.html
       inspector/canvas/recording-bitmaprenderer.html
       inspector/canvas/recording-html-2d.html
       inspector/canvas/recording-webgl.html
       inspector/canvas/setRecordingAutoCaptureFrameCount.html

WebGL `<canvas>` follow a different "rendering" path such that `HTMLCanvasElement::paint`
isn't called. Previously, there was a 0s timer that was started after the first action of a
frame was recorded (for the case that the `<canvas>` isn't attached to the DOM) that would
automatically stop the recording. It was possible that actions in two different "frame"s
were recorded as part of the same frame, because the WebGL `<canvas>` would instead fall
back to the timer to know when the "frame" had ended.

Now, there is additional instrumentation for the WebGL specific rendering path.
Additionally, replace the 0s timer with a microtask for more "immediate" calling.

* html/HTMLCanvasElement.cpp:
(WebCore::HTMLCanvasElement::paint):
Ensure that the `InspectorInstrumentation` call is last. This matches what we expect, as
before we were instrumenting right before is it about to paint.

* platform/graphics/GraphicsContext3D.h:
(WebCore::GraphicsContext3D::Client::~Client): Added.
(WebCore::GraphicsContext3D::addClient): Added.
(WebCore::GraphicsContext3D::removeClient): Added.
(WebCore::GraphicsContext3D::setWebGLContext): Deleted.
* platform/graphics/opengl/GraphicsContext3DOpenGLCommon.cpp:
(WebCore::GraphicsContext3D::markLayerComposited):
(WebCore::GraphicsContext3D::forceContextLost):
(WebCore::GraphicsContext3D::recycleContext):
(WebCore::GraphicsContext3D::dispatchContextChangedNotification):
* html/canvas/WebGLRenderingContextBase.h:
* html/canvas/WebGLRenderingContextBase.cpp:
(WebCore::WebGLRenderingContextBase::WebGLRenderingContextBase):
(WebCore::WebGLRenderingContextBase::destroyGraphicsContext3D):
(WebCore::WebGLRenderingContextBase::didComposite): Added.
(WebCore::WebGLRenderingContextBase::forceContextLost):
(WebCore::WebGLRenderingContextBase::recycleContext):
(WebCore::WebGLRenderingContextBase::dispatchContextChangedNotification): Added.
(WebCore::WebGLRenderingContextBase::dispatchContextChangedEvent): Deleted.
Introduce a `GraphicsContext3DClient` abstract class, rather than passing the
`WebGLRenderingContextBase` directly to the `GraphicsContext3D` (layering violation).
Notify the client whenever the `GraphicsContext3D` composites, which will in turn notify the
`InspectorCanvasAgent` so that it knows that the "frame" is over.

* inspector/agents/InspectorCanvasAgent.h:
* inspector/agents/InspectorCanvasAgent.cpp:
(WebCore::InspectorCanvasAgent::InspectorCanvasAgent):
(WebCore::InspectorCanvasAgent::requestNode):
(WebCore::InspectorCanvasAgent::requestContent):
(WebCore::InspectorCanvasAgent::requestCSSCanvasClientNodes):
(WebCore::InspectorCanvasAgent::resolveCanvasContext):
(WebCore::InspectorCanvasAgent::startRecording):
(WebCore::InspectorCanvasAgent::stopRecording):
(WebCore::InspectorCanvasAgent::requestShaderSource):
(WebCore::InspectorCanvasAgent::updateShader):
(WebCore::InspectorCanvasAgent::setShaderProgramDisabled):
(WebCore::InspectorCanvasAgent::setShaderProgramHighlighted):
(WebCore::InspectorCanvasAgent::didChangeCSSCanvasClientNodes):
(WebCore::InspectorCanvasAgent::didChangeCanvasMemory):
(WebCore::InspectorCanvasAgent::recordCanvasAction):
(WebCore::InspectorCanvasAgent::canvasDestroyed):
(WebCore::InspectorCanvasAgent::didFinishRecordingCanvasFrame):
(WebCore::InspectorCanvasAgent::consoleStartRecordingCanvas):
(WebCore::InspectorCanvasAgent::didEnableExtension):
(WebCore::InspectorCanvasAgent::didCreateProgram):
(WebCore::InspectorCanvasAgent::willDeleteProgram):
(WebCore::InspectorCanvasAgent::isShaderProgramDisabled):
(WebCore::InspectorCanvasAgent::isShaderProgramHighlighted):
(WebCore::InspectorCanvasAgent::clearCanvasData):
(WebCore::InspectorCanvasAgent::assertInspectorCanvas):
(WebCore::InspectorCanvasAgent::findInspectorCanvas):
(WebCore::InspectorCanvasAgent::assertInspectorProgram):
(WebCore::InspectorCanvasAgent::findInspectorProgram):
(WebCore::InspectorCanvasAgent::canvasRecordingTimerFired): Deleted.
Replace raw pointers with `RefPtr`s. This is primarily used so that the microtask (instead
of a timer) that is enqueued after the first action of each frame  is recorded can access a
ref-counted instance of an `InspectorCanvas`, ensuring that it isn't destructed.

* inspector/InspectorCanvas.h:
* inspector/InspectorCanvas.cpp:
(WebCore::InspectorCanvas::canvasElement):
(WebCore::InspectorCanvas::recordAction):
(WebCore::InspectorCanvas::finalizeFrame):
(WebCore::InspectorCanvas::releaseObjectForRecording): Added.
(WebCore::InspectorCanvas::getCanvasContentAsDataURL):
(WebCore::InspectorCanvas::appendActionSnapshotIfNeeded):
(WebCore::InspectorCanvas::buildInitialState):
(WebCore::InspectorCanvas::releaseInitialState): Deleted.
(WebCore::InspectorCanvas::releaseFrames): Deleted.
(WebCore::InspectorCanvas::releaseData): Deleted.
Move the recording payload construction logic to `InspectorCanvas` so the actual data
doesn't need to leave that class.
Drive-by: unify the logic for getting the contents of a canvas from `InspectorCanvasAgent`.

LayoutTests:

* inspector/canvas/recording-2d.html:
* inspector/canvas/recording-bitmaprenderer.html:
* inspector/canvas/recording-html-2d.html:
* inspector/canvas/recording-webgl.html:
* inspector/canvas/setRecordingAutoCaptureFrameCount.html:

Modified Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (243355 => 243356)


--- trunk/LayoutTests/ChangeLog	2019-03-22 02:33:38 UTC (rev 243355)
+++ trunk/LayoutTests/ChangeLog	2019-03-22 02:47:35 UTC (rev 243356)
@@ -1,3 +1,17 @@
+2019-03-21  Devin Rousso  <drou...@apple.com>
+
+        Web Inspector: Safari Canvas Inspector seems to show the canvas being rendered twice per frame.
+        https://bugs.webkit.org/show_bug.cgi?id=196082
+        <rdar://problem/49113496>
+
+        Reviewed by Dean Jackson.
+
+        * inspector/canvas/recording-2d.html:
+        * inspector/canvas/recording-bitmaprenderer.html:
+        * inspector/canvas/recording-html-2d.html:
+        * inspector/canvas/recording-webgl.html:
+        * inspector/canvas/setRecordingAutoCaptureFrameCount.html:
+
 2019-03-21  Joseph Pecoraro  <pecor...@apple.com>
 
         Web Inspector: Timelines - Cannot export on about:blank - suggested filename containing a colon silently fails

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


--- trunk/LayoutTests/inspector/canvas/recording-2d.html	2019-03-22 02:33:38 UTC (rev 243355)
+++ trunk/LayoutTests/inspector/canvas/recording-2d.html	2019-03-22 02:47:35 UTC (rev 243356)
@@ -39,8 +39,6 @@
     pattern = ctx.createPattern(image, "no-repeat");
     bitmap = await createImageBitmap(image);
 
-    document.body.appendChild(canvas);
-
     ctx.save();
     cancelActions();
 
@@ -53,7 +51,7 @@
     } catch (e) { }
 }
 
-let timeoutID = NaN;
+let requestAnimationFrameId = NaN;
 let saveCount = 1;
 
 function cancelActions() {
@@ -61,8 +59,8 @@
         ctx.restore();
     ctx.restore(); // Ensures the state is reset between test cases.
 
-    clearTimeout(timeoutID);
-    timeoutID = NaN;
+    cancelAnimationFrame(requestAnimationFrameId);
+    requestAnimationFrameId = NaN;
 
     ctx.save(); // Ensures the state is reset between test cases.
     ctx.save(); // This matches the `restore` call in `performActions`.
@@ -399,7 +397,7 @@
     function executeFrameFunction() {
         frames[index++]();
         if (index < frames.length)
-            timeoutID = setTimeout(executeFrameFunction, 0);
+            requestAnimationFrameId = requestAnimationFrame(executeFrameFunction);
     };
     executeFrameFunction();
 }

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


--- trunk/LayoutTests/inspector/canvas/recording-bitmaprenderer.html	2019-03-22 02:33:38 UTC (rev 243355)
+++ trunk/LayoutTests/inspector/canvas/recording-bitmaprenderer.html	2019-03-22 02:47:35 UTC (rev 243356)
@@ -23,7 +23,7 @@
 function load() {
     ctx = canvas.getContext("bitmaprenderer");
 
-    document.body.appendChild(canvas);
+    cancelActions();
 
     runTest();
 }
@@ -34,11 +34,11 @@
     } catch (e) { }
 }
 
-let timeoutID = NaN;
+let requestAnimationFrameId = NaN;
 
 function cancelActions() {
-    clearTimeout(timeoutID);
-    timeoutID = NaN;
+    cancelAnimationFrame(requestAnimationFrameId);
+    requestAnimationFrameId = NaN;
 
     createImageBitmap(transparentImage).then((transparentBitmap) => {
         ctx.transferFromImageBitmap(transparentBitmap);
@@ -68,7 +68,7 @@
     function executeFrameFunction() {
         frames[index++]();
         if (index < frames.length)
-            timeoutID = setTimeout(executeFrameFunction, 0);
+            requestAnimationFrameId = requestAnimationFrame(executeFrameFunction);
     };
     executeFrameFunction();
 }

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


--- trunk/LayoutTests/inspector/canvas/recording-html-2d.html	2019-03-22 02:33:38 UTC (rev 243355)
+++ trunk/LayoutTests/inspector/canvas/recording-html-2d.html	2019-03-22 02:47:35 UTC (rev 243356)
@@ -39,7 +39,7 @@
 
     imageBitmap = await createImageBitmap(image);
 
-    document.body.appendChild(canvas);
+    cancelActions();
 
     context.strokeStyle = "red";
     context.save();
@@ -56,7 +56,15 @@
     } catch (e) { }
 }
 
+let requestAnimationFrameId = NaN;
+
 function cancelActions() {
+    cancelAnimationFrame(requestAnimationFrameId);
+    requestAnimationFrameId = NaN;
+
+    context.resetTransform();
+    context.beginPath();
+    context.clearRect(0, 0, context.canvas.width, context.canvas.height);
 }
 
 function performActions() {
@@ -97,7 +105,7 @@
     function executeFrameFunction() {
         frames[index++]();
         if (index < frames.length)
-            timeoutID = setTimeout(executeFrameFunction, 0);
+            requestAnimationFrameId = requestAnimationFrame(executeFrameFunction);
     };
     executeFrameFunction();
 }

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


--- trunk/LayoutTests/inspector/canvas/recording-webgl.html	2019-03-22 02:33:38 UTC (rev 243355)
+++ trunk/LayoutTests/inspector/canvas/recording-webgl.html	2019-03-22 02:47:35 UTC (rev 243356)
@@ -49,7 +49,7 @@
     shader = context.createShader(context.VERTEX_SHADER);
     texture = context.createTexture();
 
-    document.body.appendChild(context.canvas);
+    cancelActions();
 
     runTest();
 }
@@ -60,11 +60,11 @@
     } catch (e) { }
 }
 
-let timeoutID = NaN;
+let requestAnimationFrameId = NaN;
 
 function cancelActions() {
-    clearTimeout(timeoutID);
-    timeoutID = NaN;
+    cancelAnimationFrame(requestAnimationFrameId);
+    requestAnimationFrameId = NaN;
 
     context.clearColor(0.0, 0.0, 0.0, 0.0);
     context.clear(context.COLOR_BUFFER_BIT);
@@ -502,7 +502,7 @@
     function executeFrameFunction() {
         frames[index++]();
         if (index < frames.length)
-            timeoutID = setTimeout(executeFrameFunction, 0);
+            requestAnimationFrameId = requestAnimationFrame(executeFrameFunction);
     };
     executeFrameFunction();
 }

Modified: trunk/LayoutTests/inspector/canvas/setRecordingAutoCaptureFrameCount.html (243355 => 243356)


--- trunk/LayoutTests/inspector/canvas/setRecordingAutoCaptureFrameCount.html	2019-03-22 02:33:38 UTC (rev 243355)
+++ trunk/LayoutTests/inspector/canvas/setRecordingAutoCaptureFrameCount.html	2019-03-22 02:47:35 UTC (rev 243356)
@@ -6,11 +6,11 @@
 if (window.internals)
     window.internals.settings.setWebGLErrorsToConsoleEnabled(false);
 
-let timeoutID = NaN;
+let requestAnimationFrameId = NaN;
 
 function cancelActions() {
-    clearTimeout(timeoutID);
-    timeoutID = NaN;
+    cancelAnimationFrame(requestAnimationFrameId);
+    requestAnimationFrameId = NaN;
 }
 
 function performActions(frames) {
@@ -19,7 +19,7 @@
         frames[index++]();
 
         if (index < frames.length)
-            timeoutID = setTimeout(executeFrameFunction, 0);
+            requestAnimationFrameId = requestAnimationFrame(executeFrameFunction);
         else {
             setTimeout(() => {
                 TestPage.dispatchEventToFrontend("LastFrame");

Modified: trunk/Source/WebCore/ChangeLog (243355 => 243356)


--- trunk/Source/WebCore/ChangeLog	2019-03-22 02:33:38 UTC (rev 243355)
+++ trunk/Source/WebCore/ChangeLog	2019-03-22 02:47:35 UTC (rev 243356)
@@ -1,3 +1,106 @@
+2019-03-21  Devin Rousso  <drou...@apple.com>
+
+        Web Inspector: Safari Canvas Inspector seems to show the canvas being rendered twice per frame.
+        https://bugs.webkit.org/show_bug.cgi?id=196082
+        <rdar://problem/49113496>
+
+        Reviewed by Dean Jackson.
+
+        Tests: inspector/canvas/recording-2d.html
+               inspector/canvas/recording-bitmaprenderer.html
+               inspector/canvas/recording-html-2d.html
+               inspector/canvas/recording-webgl.html
+               inspector/canvas/setRecordingAutoCaptureFrameCount.html
+
+        WebGL `<canvas>` follow a different "rendering" path such that `HTMLCanvasElement::paint`
+        isn't called. Previously, there was a 0s timer that was started after the first action of a
+        frame was recorded (for the case that the `<canvas>` isn't attached to the DOM) that would
+        automatically stop the recording. It was possible that actions in two different "frame"s
+        were recorded as part of the same frame, because the WebGL `<canvas>` would instead fall
+        back to the timer to know when the "frame" had ended.
+
+        Now, there is additional instrumentation for the WebGL specific rendering path.
+        Additionally, replace the 0s timer with a microtask for more "immediate" calling.
+
+        * html/HTMLCanvasElement.cpp:
+        (WebCore::HTMLCanvasElement::paint):
+        Ensure that the `InspectorInstrumentation` call is last. This matches what we expect, as
+        before we were instrumenting right before is it about to paint.
+
+        * platform/graphics/GraphicsContext3D.h:
+        (WebCore::GraphicsContext3D::Client::~Client): Added.
+        (WebCore::GraphicsContext3D::addClient): Added.
+        (WebCore::GraphicsContext3D::removeClient): Added.
+        (WebCore::GraphicsContext3D::setWebGLContext): Deleted.
+        * platform/graphics/opengl/GraphicsContext3DOpenGLCommon.cpp:
+        (WebCore::GraphicsContext3D::markLayerComposited):
+        (WebCore::GraphicsContext3D::forceContextLost):
+        (WebCore::GraphicsContext3D::recycleContext):
+        (WebCore::GraphicsContext3D::dispatchContextChangedNotification):
+        * html/canvas/WebGLRenderingContextBase.h:
+        * html/canvas/WebGLRenderingContextBase.cpp:
+        (WebCore::WebGLRenderingContextBase::WebGLRenderingContextBase):
+        (WebCore::WebGLRenderingContextBase::destroyGraphicsContext3D):
+        (WebCore::WebGLRenderingContextBase::didComposite): Added.
+        (WebCore::WebGLRenderingContextBase::forceContextLost):
+        (WebCore::WebGLRenderingContextBase::recycleContext):
+        (WebCore::WebGLRenderingContextBase::dispatchContextChangedNotification): Added.
+        (WebCore::WebGLRenderingContextBase::dispatchContextChangedEvent): Deleted.
+        Introduce a `GraphicsContext3DClient` abstract class, rather than passing the
+        `WebGLRenderingContextBase` directly to the `GraphicsContext3D` (layering violation).
+        Notify the client whenever the `GraphicsContext3D` composites, which will in turn notify the
+        `InspectorCanvasAgent` so that it knows that the "frame" is over.
+
+        * inspector/agents/InspectorCanvasAgent.h:
+        * inspector/agents/InspectorCanvasAgent.cpp:
+        (WebCore::InspectorCanvasAgent::InspectorCanvasAgent):
+        (WebCore::InspectorCanvasAgent::requestNode):
+        (WebCore::InspectorCanvasAgent::requestContent):
+        (WebCore::InspectorCanvasAgent::requestCSSCanvasClientNodes):
+        (WebCore::InspectorCanvasAgent::resolveCanvasContext):
+        (WebCore::InspectorCanvasAgent::startRecording):
+        (WebCore::InspectorCanvasAgent::stopRecording):
+        (WebCore::InspectorCanvasAgent::requestShaderSource):
+        (WebCore::InspectorCanvasAgent::updateShader):
+        (WebCore::InspectorCanvasAgent::setShaderProgramDisabled):
+        (WebCore::InspectorCanvasAgent::setShaderProgramHighlighted):
+        (WebCore::InspectorCanvasAgent::didChangeCSSCanvasClientNodes):
+        (WebCore::InspectorCanvasAgent::didChangeCanvasMemory):
+        (WebCore::InspectorCanvasAgent::recordCanvasAction):
+        (WebCore::InspectorCanvasAgent::canvasDestroyed):
+        (WebCore::InspectorCanvasAgent::didFinishRecordingCanvasFrame):
+        (WebCore::InspectorCanvasAgent::consoleStartRecordingCanvas):
+        (WebCore::InspectorCanvasAgent::didEnableExtension):
+        (WebCore::InspectorCanvasAgent::didCreateProgram):
+        (WebCore::InspectorCanvasAgent::willDeleteProgram):
+        (WebCore::InspectorCanvasAgent::isShaderProgramDisabled):
+        (WebCore::InspectorCanvasAgent::isShaderProgramHighlighted):
+        (WebCore::InspectorCanvasAgent::clearCanvasData):
+        (WebCore::InspectorCanvasAgent::assertInspectorCanvas):
+        (WebCore::InspectorCanvasAgent::findInspectorCanvas):
+        (WebCore::InspectorCanvasAgent::assertInspectorProgram):
+        (WebCore::InspectorCanvasAgent::findInspectorProgram):
+        (WebCore::InspectorCanvasAgent::canvasRecordingTimerFired): Deleted.
+        Replace raw pointers with `RefPtr`s. This is primarily used so that the microtask (instead
+        of a timer) that is enqueued after the first action of each frame  is recorded can access a
+        ref-counted instance of an `InspectorCanvas`, ensuring that it isn't destructed.
+
+        * inspector/InspectorCanvas.h:
+        * inspector/InspectorCanvas.cpp:
+        (WebCore::InspectorCanvas::canvasElement):
+        (WebCore::InspectorCanvas::recordAction):
+        (WebCore::InspectorCanvas::finalizeFrame):
+        (WebCore::InspectorCanvas::releaseObjectForRecording): Added.
+        (WebCore::InspectorCanvas::getCanvasContentAsDataURL):
+        (WebCore::InspectorCanvas::appendActionSnapshotIfNeeded):
+        (WebCore::InspectorCanvas::buildInitialState):
+        (WebCore::InspectorCanvas::releaseInitialState): Deleted.
+        (WebCore::InspectorCanvas::releaseFrames): Deleted.
+        (WebCore::InspectorCanvas::releaseData): Deleted.
+        Move the recording payload construction logic to `InspectorCanvas` so the actual data
+        doesn't need to leave that class.
+        Drive-by: unify the logic for getting the contents of a canvas from `InspectorCanvasAgent`.
+
 2019-03-21  Tim Horton  <timothy_hor...@apple.com>
 
         Adopt UIWKDocumentContext

Modified: trunk/Source/WebCore/html/HTMLCanvasElement.cpp (243355 => 243356)


--- trunk/Source/WebCore/html/HTMLCanvasElement.cpp	2019-03-22 02:33:38 UTC (rev 243355)
+++ trunk/Source/WebCore/html/HTMLCanvasElement.cpp	2019-03-22 02:47:35 UTC (rev 243356)
@@ -668,38 +668,40 @@
 
 void HTMLCanvasElement::paint(GraphicsContext& context, const LayoutRect& r)
 {
-    if (UNLIKELY(m_context && m_context->callTracingActive()))
-        InspectorInstrumentation::didFinishRecordingCanvasFrame(*m_context);
-
     // Clear the dirty rect
     m_dirtyRect = FloatRect();
 
-    if (context.paintingDisabled())
-        return;
-    
-    if (m_context) {
-        if (!paintsIntoCanvasBuffer() && !document().printing())
-            return;
+    if (!context.paintingDisabled()) {
+        bool shouldPaint = true;
 
-        m_context->paintRenderingResultsToCanvas();
-    }
+        if (m_context) {
+            shouldPaint = paintsIntoCanvasBuffer() || document().printing();
+            if (shouldPaint)
+                m_context->paintRenderingResultsToCanvas();
+        }
 
-    if (hasCreatedImageBuffer()) {
-        ImageBuffer* imageBuffer = buffer();
-        if (imageBuffer) {
-            if (m_presentedImage) {
-                ImageOrientationDescription orientationDescription;
+        if (shouldPaint) {
+            if (hasCreatedImageBuffer()) {
+                ImageBuffer* imageBuffer = buffer();
+                if (imageBuffer) {
+                    if (m_presentedImage) {
+                        ImageOrientationDescription orientationDescription;
 #if ENABLE(CSS_IMAGE_ORIENTATION)
-                orientationDescription.setImageOrientationEnum(renderer()->style().imageOrientation());
-#endif 
-                context.drawImage(*m_presentedImage, snappedIntRect(r), ImagePaintingOptions(orientationDescription));
-            } else
-                context.drawImageBuffer(*imageBuffer, snappedIntRect(r));
+                        orientationDescription.setImageOrientationEnum(renderer()->style().imageOrientation());
+#endif
+                        context.drawImage(*m_presentedImage, snappedIntRect(r), ImagePaintingOptions(orientationDescription));
+                    } else
+                        context.drawImageBuffer(*imageBuffer, snappedIntRect(r));
+                }
+            }
+
+            if (isGPUBased())
+                downcast<GPUBasedCanvasRenderingContext>(*m_context).markLayerComposited();
         }
     }
 
-    if (isGPUBased())
-        downcast<GPUBasedCanvasRenderingContext>(*m_context).markLayerComposited();
+    if (UNLIKELY(m_context && m_context->callTracingActive()))
+        InspectorInstrumentation::didFinishRecordingCanvasFrame(*m_context);
 }
 
 bool HTMLCanvasElement::isGPUBased() const

Modified: trunk/Source/WebCore/html/canvas/WebGLRenderingContextBase.cpp (243355 => 243356)


--- trunk/Source/WebCore/html/canvas/WebGLRenderingContextBase.cpp	2019-03-22 02:33:38 UTC (rev 243355)
+++ trunk/Source/WebCore/html/canvas/WebGLRenderingContextBase.cpp	2019-03-22 02:47:35 UTC (rev 243356)
@@ -661,7 +661,7 @@
     m_contextGroup = WebGLContextGroup::create();
     m_contextGroup->addContext(*this);
     
-    m_context->setWebGLContext(this);
+    m_context->addClient(*this);
 
     m_context->getIntegerv(GraphicsContext3D::MAX_VIEWPORT_DIMS, m_maxViewportDims);
 
@@ -914,6 +914,7 @@
     removeActivityStateChangeObserver();
 
     if (m_context) {
+        m_context->removeClient(*this);
         m_context->setContextLostCallback(nullptr);
         m_context->setErrorMessageCallback(nullptr);
         m_context = nullptr;
@@ -5042,15 +5043,6 @@
     m_contextGroup->loseContextGroup(mode);
 }
 
-void WebGLRenderingContextBase::recycleContext()
-{
-    printToConsole(MessageLevel::Error, "There are too many active WebGL contexts on this page, the oldest context will be lost.");
-    // Using SyntheticLostContext means the developer won't be able to force the restoration
-    // of the context by calling preventDefault() in a "webglcontextlost" event handler.
-    forceLostContext(SyntheticLostContext);
-    destroyGraphicsContext3D();
-}
-
 void WebGLRenderingContextBase::loseContextImpl(WebGLRenderingContextBase::LostContextMode mode)
 {
     if (isContextLost())
@@ -6225,15 +6217,6 @@
     canvas->dispatchEvent(WebGLContextEvent::create(eventNames().webglcontextrestoredEvent, Event::CanBubble::No, Event::IsCancelable::Yes, emptyString()));
 }
 
-void WebGLRenderingContextBase::dispatchContextChangedEvent()
-{
-    auto* canvas = htmlCanvas();
-    if (!canvas)
-        return;
-
-    canvas->dispatchEvent(WebGLContextEvent::create(eventNames().webglcontextchangedEvent, Event::CanBubble::No, Event::IsCancelable::Yes, emptyString()));
-}
-
 void WebGLRenderingContextBase::simulateContextChanged()
 {
     if (m_context)
@@ -6513,6 +6496,36 @@
     m_context->setFailNextGPUStatusCheck();
 }
 
+void WebGLRenderingContextBase::didComposite()
+{
+    if (UNLIKELY(callTracingActive()))
+        InspectorInstrumentation::didFinishRecordingCanvasFrame(*this);
+}
+
+void WebGLRenderingContextBase::forceContextLost()
+{
+    forceLostContext(WebGLRenderingContextBase::RealLostContext);
+}
+
+void WebGLRenderingContextBase::recycleContext()
+{
+    printToConsole(MessageLevel::Error, "There are too many active WebGL contexts on this page, the oldest context will be lost.");
+    // Using SyntheticLostContext means the developer won't be able to force the restoration
+    // of the context by calling preventDefault() in a "webglcontextlost" event handler.
+    forceLostContext(SyntheticLostContext);
+    destroyGraphicsContext3D();
+}
+
+void WebGLRenderingContextBase::dispatchContextChangedNotification()
+{
+    auto* canvas = htmlCanvas();
+    if (!canvas)
+        return;
+
+    canvas->dispatchEvent(WebGLContextEvent::create(eventNames().webglcontextchangedEvent, Event::CanBubble::No, Event::IsCancelable::Yes, emptyString()));
+}
+
+
 } // namespace WebCore
 
 #endif // ENABLE(WEBGL)

Modified: trunk/Source/WebCore/html/canvas/WebGLRenderingContextBase.h (243355 => 243356)


--- trunk/Source/WebCore/html/canvas/WebGLRenderingContextBase.h	2019-03-22 02:33:38 UTC (rev 243355)
+++ trunk/Source/WebCore/html/canvas/WebGLRenderingContextBase.h	2019-03-22 02:47:35 UTC (rev 243356)
@@ -94,7 +94,7 @@
 
 using WebGLCanvas = WTF::Variant<RefPtr<HTMLCanvasElement>, RefPtr<OffscreenCanvas>>;
 
-class WebGLRenderingContextBase : public GPUBasedCanvasRenderingContext, private ActivityStateChangeObserver {
+class WebGLRenderingContextBase : public GraphicsContext3D::Client, public GPUBasedCanvasRenderingContext, private ActivityStateChangeObserver {
 public:
     static std::unique_ptr<WebGLRenderingContextBase> create(CanvasBase&, WebGLContextAttributes&, const String&);
     virtual ~WebGLRenderingContextBase();
@@ -330,10 +330,8 @@
         SyntheticLostContext
     };
     void forceLostContext(LostContextMode);
-    void recycleContext();
     void forceRestoreContext();
     void loseContextImpl(LostContextMode);
-    void dispatchContextChangedEvent();
     WEBCORE_EXPORT void simulateContextChanged();
 
     GraphicsContext3D* graphicsContext3D() const { return m_context.get(); }
@@ -359,6 +357,12 @@
     // Used for testing only, from Internals.
     WEBCORE_EXPORT void setFailNextGPUStatusCheck();
 
+    // GraphicsContext3D::Client
+    void didComposite() override;
+    void forceContextLost() override;
+    void recycleContext() override;
+    void dispatchContextChangedNotification() override;
+
 protected:
     WebGLRenderingContextBase(CanvasBase&, WebGLContextAttributes);
     WebGLRenderingContextBase(CanvasBase&, Ref<GraphicsContext3D>&&, WebGLContextAttributes);

Modified: trunk/Source/WebCore/inspector/InspectorCanvas.cpp (243355 => 243356)


--- trunk/Source/WebCore/inspector/InspectorCanvas.cpp	2019-03-22 02:33:38 UTC (rev 243355)
+++ trunk/Source/WebCore/inspector/InspectorCanvas.cpp	2019-03-22 02:47:35 UTC (rev 243356)
@@ -89,9 +89,8 @@
 
 HTMLCanvasElement* InspectorCanvas::canvasElement()
 {
-    auto* canvasBase = &m_context.canvasBase();
-    if (is<HTMLCanvasElement>(canvasBase))
-        return downcast<HTMLCanvasElement>(canvasBase);
+    if (is<HTMLCanvasElement>(m_context.canvasBase()))
+        return &downcast<HTMLCanvasElement>(m_context.canvasBase());
     return nullptr;
 }
 
@@ -137,6 +136,9 @@
 void InspectorCanvas::recordAction(const String& name, Vector<RecordCanvasActionVariant>&& parameters)
 {
     if (!m_initialState) {
+        // We should only construct the initial state for the first action of the recording.
+        ASSERT(!m_frames && !m_currentActions);
+
         m_initialState = buildInitialState();
         m_bufferUsed += m_initialState->memoryCost();
     }
@@ -171,26 +173,10 @@
 #endif
 }
 
-RefPtr<Inspector::Protocol::Recording::InitialState>&& InspectorCanvas::releaseInitialState()
+void InspectorCanvas::finalizeFrame()
 {
-    return WTFMove(m_initialState);
-}
-
-RefPtr<JSON::ArrayOf<Inspector::Protocol::Recording::Frame>>&& InspectorCanvas::releaseFrames()
-{
     appendActionSnapshotIfNeeded();
 
-    return WTFMove(m_frames);
-}
-
-RefPtr<JSON::ArrayOf<JSON::Value>>&& InspectorCanvas::releaseData()
-{
-    m_indexedDuplicateData.clear();
-    return WTFMove(m_serializedDuplicateData);
-}
-
-void InspectorCanvas::finalizeFrame()
-{
     if (m_frames && m_frames->length() && !std::isnan(m_currentFrameStartTime)) {
         auto currentFrame = static_cast<Inspector::Protocol::Recording::Frame*>(m_frames->get(m_frames->length() - 1).get());
         currentFrame->setDuration((MonotonicTime::now() - m_currentFrameStartTime).milliseconds());
@@ -311,22 +297,61 @@
     return canvas;
 }
 
-void InspectorCanvas::appendActionSnapshotIfNeeded()
+Ref<Inspector::Protocol::Recording::Recording> InspectorCanvas::releaseObjectForRecording()
 {
-    if (!m_actionNeedingSnapshot)
-        return;
+    ASSERT(!m_currentActions);
+    ASSERT(!m_actionNeedingSnapshot);
+    ASSERT(!m_frames);
 
-    m_actionNeedingSnapshot->addItem(indexForData(getCanvasContentAsDataURL()));
-    m_actionNeedingSnapshot = nullptr;
+    // FIXME: <https://webkit.org/b/176008> Web Inspector: Record actions performed on WebGL2RenderingContext
+
+    Inspector::Protocol::Recording::Type type;
+    if (is<CanvasRenderingContext2D>(m_context))
+        type = Inspector::Protocol::Recording::Type::Canvas2D;
+    else if (is<ImageBitmapRenderingContext>(m_context))
+        type = Inspector::Protocol::Recording::Type::CanvasBitmapRenderer;
+#if ENABLE(WEBGL)
+    else if (is<WebGLRenderingContext>(m_context))
+        type = Inspector::Protocol::Recording::Type::CanvasWebGL;
+#endif
+    else {
+        ASSERT_NOT_REACHED();
+        type = Inspector::Protocol::Recording::Type::Canvas2D;
+    }
+
+    auto recording = Inspector::Protocol::Recording::Recording::create()
+        .setVersion(Inspector::Protocol::Recording::VERSION)
+        .setType(type)
+        .setInitialState(m_initialState.releaseNonNull())
+        .setData(m_serializedDuplicateData.releaseNonNull())
+        .release();
+
+    if (!m_recordingName.isEmpty())
+        recording->setName(m_recordingName);
+
+    resetRecordingData();
+
+    return recording;
 }
 
-String InspectorCanvas::getCanvasContentAsDataURL()
+String InspectorCanvas::getCanvasContentAsDataURL(ErrorString& errorString)
 {
+    // FIXME: <https://webkit.org/b/173621> Web Inspector: Support getting the content of WebMetal context;
+    if (!is<CanvasRenderingContext2D>(m_context)
+#if ENABLE(WEBGL)
+        && !is<WebGLRenderingContextBase>(m_context)
+#endif
+        && !is<ImageBitmapRenderingContext>(m_context)) {
+        errorString = "Unsupported canvas context type"_s;
+        return emptyString();
+    }
+
     // FIXME: <https://webkit.org/b/180833> Web Inspector: support OffscreenCanvas for Canvas related operations
-
     auto* node = canvasElement();
-    if (!node)
-        return String();
+    if (!node) {
+        errorString = "Context isn't related to an HTMLCanvasElement"_s;
+        return emptyString();
+    }
 
 #if ENABLE(WEBGL)
     if (is<WebGLRenderingContextBase>(m_context))
@@ -340,12 +365,29 @@
         downcast<WebGLRenderingContextBase>(m_context).setPreventBufferClearForInspector(false);
 #endif
 
-    if (result.hasException())
-        return String();
+    if (result.hasException()) {
+        errorString = result.releaseException().releaseMessage();
+        return emptyString();
+    }
 
     return result.releaseReturnValue().string;
 }
 
+void InspectorCanvas::appendActionSnapshotIfNeeded()
+{
+    if (!m_actionNeedingSnapshot)
+        return;
+
+    m_bufferUsed -= m_actionNeedingSnapshot->memoryCost();
+
+    ErrorString ignored;
+    m_actionNeedingSnapshot->addItem(indexForData(getCanvasContentAsDataURL(ignored)));
+
+    m_bufferUsed += m_actionNeedingSnapshot->memoryCost();
+
+    m_actionNeedingSnapshot = nullptr;
+}
+
 int InspectorCanvas::indexForData(DuplicateDataVariant data)
 {
     size_t index = m_indexedDuplicateData.findMatching([&] (auto item) {
@@ -561,7 +603,8 @@
     if (parametersPayload->length())
         initialStatePayload->setParameters(WTFMove(parametersPayload));
 
-    initialStatePayload->setContent(getCanvasContentAsDataURL());
+    ErrorString ignored;
+    initialStatePayload->setContent(getCanvasContentAsDataURL(ignored));
 
     return initialStatePayload;
 }

Modified: trunk/Source/WebCore/inspector/InspectorCanvas.h (243355 => 243356)


--- trunk/Source/WebCore/inspector/InspectorCanvas.h	2019-03-22 02:33:38 UTC (rev 243355)
+++ trunk/Source/WebCore/inspector/InspectorCanvas.h	2019-03-22 02:47:35 UTC (rev 243356)
@@ -44,6 +44,8 @@
 class ImageBitmap;
 class ImageData;
 
+typedef String ErrorString;
+
 class InspectorCanvas final : public RefCounted<InspectorCanvas> {
 public:
     static Ref<InspectorCanvas> create(CanvasRenderingContext&);
@@ -58,14 +60,11 @@
     bool currentFrameHasData() const;
     void recordAction(const String&, Vector<RecordCanvasActionVariant>&& = { });
 
-    RefPtr<Inspector::Protocol::Recording::InitialState>&& releaseInitialState();
-    RefPtr<JSON::ArrayOf<Inspector::Protocol::Recording::Frame>>&& releaseFrames();
-    RefPtr<JSON::ArrayOf<JSON::Value>>&& releaseData();
+    Ref<JSON::ArrayOf<Inspector::Protocol::Recording::Frame>> releaseFrames() { return m_frames.releaseNonNull(); }
 
     void finalizeFrame();
     void markCurrentFrameIncomplete();
 
-    const String& recordingName() const { return m_recordingName; }
     void setRecordingName(const String& name) { m_recordingName = name; }
 
     void setBufferLimit(long);
@@ -76,11 +75,13 @@
     bool overFrameCount() const;
 
     Ref<Inspector::Protocol::Canvas::Canvas> buildObjectForCanvas(bool captureBacktrace);
+    Ref<Inspector::Protocol::Recording::Recording> releaseObjectForRecording();
 
+    String getCanvasContentAsDataURL(ErrorString&);
+
 private:
     InspectorCanvas(CanvasRenderingContext&);
     void appendActionSnapshotIfNeeded();
-    String getCanvasContentAsDataURL();
 
     using DuplicateDataVariant = Variant<
         RefPtr<CanvasGradient>,

Modified: trunk/Source/WebCore/inspector/agents/InspectorCanvasAgent.cpp (243355 => 243356)


--- trunk/Source/WebCore/inspector/agents/InspectorCanvasAgent.cpp	2019-03-22 02:33:38 UTC (rev 243355)
+++ trunk/Source/WebCore/inspector/agents/InspectorCanvasAgent.cpp	2019-03-22 02:47:35 UTC (rev 243356)
@@ -26,6 +26,7 @@
 #include "config.h"
 #include "InspectorCanvasAgent.h"
 
+#include "ActiveDOMCallbackMicrotask.h"
 #include "CanvasRenderingContext.h"
 #include "CanvasRenderingContext2D.h"
 #include "Document.h"
@@ -37,6 +38,7 @@
 #include "JSCanvasRenderingContext2D.h"
 #include "JSExecState.h"
 #include "JSImageBitmapRenderingContext.h"
+#include "Microtasks.h"
 #include "OffscreenCanvas.h"
 #include "ScriptState.h"
 #include "StringAdaptors.h"
@@ -78,7 +80,6 @@
     , m_injectedScriptManager(context.injectedScriptManager)
     , m_inspectedPage(context.inspectedPage)
     , m_canvasDestroyedTimer(*this, &InspectorCanvasAgent::canvasDestroyedTimerFired)
-    , m_canvasRecordingTimer(*this, &InspectorCanvasAgent::canvasRecordingTimerFired)
 {
 }
 
@@ -147,7 +148,7 @@
 
 void InspectorCanvasAgent::requestNode(ErrorString& errorString, const String& canvasId, int* nodeId)
 {
-    auto* inspectorCanvas = assertInspectorCanvas(errorString, canvasId);
+    auto inspectorCanvas = assertInspectorCanvas(errorString, canvasId);
     if (!inspectorCanvas)
         return;
 
@@ -168,48 +169,16 @@
 
 void InspectorCanvasAgent::requestContent(ErrorString& errorString, const String& canvasId, String* content)
 {
-    auto* inspectorCanvas = assertInspectorCanvas(errorString, canvasId);
+    auto inspectorCanvas = assertInspectorCanvas(errorString, canvasId);
     if (!inspectorCanvas)
         return;
 
-    // FIXME: <https://webkit.org/b/180833> Web Inspector: support OffscreenCanvas for Canvas related operations
-
-    if (auto* node = inspectorCanvas->canvasElement()) {
-        if (is<CanvasRenderingContext2D>(inspectorCanvas->context()) || is<ImageBitmapRenderingContext>(inspectorCanvas->context())) {
-            auto result = node->toDataURL("image/png"_s);
-            if (result.hasException()) {
-                errorString = result.releaseException().releaseMessage();
-                return;
-            }
-            *content = result.releaseReturnValue().string;
-            return;
-        }
-
-#if ENABLE(WEBGL)
-        if (is<WebGLRenderingContextBase>(inspectorCanvas->context())) {
-            WebGLRenderingContextBase& contextWebGLBase = downcast<WebGLRenderingContextBase>(inspectorCanvas->context());
-
-            contextWebGLBase.setPreventBufferClearForInspector(true);
-            auto result = node->toDataURL("image/png"_s);
-            contextWebGLBase.setPreventBufferClearForInspector(false);
-
-            if (result.hasException()) {
-                errorString = result.releaseException().releaseMessage();
-                return;
-            }
-            *content = result.releaseReturnValue().string;
-            return;
-        }
-#endif
-    }
-
-    // FIXME: <https://webkit.org/b/173621> Web Inspector: Support getting the content of WebMetal context;
-    errorString = "Unsupported canvas context type"_s;
+    *content = inspectorCanvas->getCanvasContentAsDataURL(errorString);
 }
 
 void InspectorCanvasAgent::requestCSSCanvasClientNodes(ErrorString& errorString, const String& canvasId, RefPtr<JSON::ArrayOf<int>>& result)
 {
-    auto* inspectorCanvas = assertInspectorCanvas(errorString, canvasId);
+    auto inspectorCanvas = assertInspectorCanvas(errorString, canvasId);
     if (!inspectorCanvas)
         return;
 
@@ -250,7 +219,7 @@
 
 void InspectorCanvasAgent::resolveCanvasContext(ErrorString& errorString, const String& canvasId, const String* objectGroup, RefPtr<Inspector::Protocol::Runtime::RemoteObject>& result)
 {
-    auto* inspectorCanvas = assertInspectorCanvas(errorString, canvasId);
+    auto inspectorCanvas = assertInspectorCanvas(errorString, canvasId);
     if (!inspectorCanvas)
         return;
 
@@ -279,7 +248,7 @@
 
 void InspectorCanvasAgent::startRecording(ErrorString& errorString, const String& canvasId, const int* frameCount, const int* memoryLimit)
 {
-    auto* inspectorCanvas = assertInspectorCanvas(errorString, canvasId);
+    auto inspectorCanvas = assertInspectorCanvas(errorString, canvasId);
     if (!inspectorCanvas)
         return;
 
@@ -298,7 +267,7 @@
 
 void InspectorCanvasAgent::stopRecording(ErrorString& errorString, const String& canvasId)
 {
-    auto* inspectorCanvas = assertInspectorCanvas(errorString, canvasId);
+    auto inspectorCanvas = assertInspectorCanvas(errorString, canvasId);
     if (!inspectorCanvas)
         return;
 
@@ -313,7 +282,7 @@
 void InspectorCanvasAgent::requestShaderSource(ErrorString& errorString, const String& programId, const String& shaderType, String* content)
 {
 #if ENABLE(WEBGL)
-    auto* inspectorProgram = assertInspectorProgram(errorString, programId);
+    auto inspectorProgram = assertInspectorProgram(errorString, programId);
     if (!inspectorProgram)
         return;
 
@@ -335,7 +304,7 @@
 void InspectorCanvasAgent::updateShader(ErrorString& errorString, const String& programId, const String& shaderType, const String& source)
 {
 #if ENABLE(WEBGL)
-    auto* inspectorProgram = assertInspectorProgram(errorString, programId);
+    auto inspectorProgram = assertInspectorProgram(errorString, programId);
     if (!inspectorProgram)
         return;
 
@@ -366,7 +335,7 @@
 void InspectorCanvasAgent::setShaderProgramDisabled(ErrorString& errorString, const String& programId, bool disabled)
 {
 #if ENABLE(WEBGL)
-    auto* inspectorProgram = assertInspectorProgram(errorString, programId);
+    auto inspectorProgram = assertInspectorProgram(errorString, programId);
     if (!inspectorProgram)
         return;
 
@@ -381,7 +350,7 @@
 void InspectorCanvasAgent::setShaderProgramHighlighted(ErrorString& errorString, const String& programId, bool highlighted)
 {
 #if ENABLE(WEBGL)
-    auto* inspectorProgram = assertInspectorProgram(errorString, programId);
+    auto inspectorProgram = assertInspectorProgram(errorString, programId);
     if (!inspectorProgram)
         return;
 
@@ -424,7 +393,7 @@
         return;
     }
 
-    auto* inspectorCanvas = findInspectorCanvas(*context);
+    auto inspectorCanvas = findInspectorCanvas(*context);
     ASSERT(inspectorCanvas);
     if (!inspectorCanvas)
         return;
@@ -450,7 +419,7 @@
 
 void InspectorCanvasAgent::didChangeCanvasMemory(CanvasRenderingContext& context)
 {
-    auto* inspectorCanvas = findInspectorCanvas(context);
+    auto inspectorCanvas = findInspectorCanvas(context);
     ASSERT(inspectorCanvas);
     if (!inspectorCanvas)
         return;
@@ -463,7 +432,7 @@
 
 void InspectorCanvasAgent::recordCanvasAction(CanvasRenderingContext& canvasRenderingContext, const String& name, Vector<RecordCanvasActionVariant>&& parameters)
 {
-    auto* inspectorCanvas = findInspectorCanvas(canvasRenderingContext);
+    auto inspectorCanvas = findInspectorCanvas(canvasRenderingContext);
     ASSERT(inspectorCanvas);
     if (!inspectorCanvas)
         return;
@@ -472,11 +441,25 @@
     if (!canvasRenderingContext.callTracingActive())
         return;
 
+    // Only enqueue a microtask for the first action of each frame. Any subsequent actions will be
+    // covered by the initial microtask until the next frame.
+    if (!inspectorCanvas->currentFrameHasData()) {
+        if (auto* scriptExecutionContext = inspectorCanvas->context().canvasBase().scriptExecutionContext()) {
+            auto& queue = MicrotaskQueue::mainThreadQueue();
+            queue.append(std::make_unique<ActiveDOMCallbackMicrotask>(queue, *scriptExecutionContext, [&, protectedInspectorCanvas = inspectorCanvas.copyRef()] {
+                if (auto* canvasElement = protectedInspectorCanvas->canvasElement()) {
+                    if (canvasElement->isDescendantOf(canvasElement->document()))
+                        return;
+                }
+
+                if (protectedInspectorCanvas->context().callTracingActive())
+                    didFinishRecordingCanvasFrame(protectedInspectorCanvas->context());
+            }));
+        }
+    }
+
     inspectorCanvas->recordAction(name, WTFMove(parameters));
 
-    if (!m_canvasRecordingTimer.isActive())
-        m_canvasRecordingTimer.startOneShot(0_s);
-
     if (!inspectorCanvas->hasBufferSpace())
         didFinishRecordingCanvasFrame(inspectorCanvas->context(), true);
 }
@@ -487,7 +470,8 @@
     if (!context)
         return;
 
-    auto* inspectorCanvas = findInspectorCanvas(*context);
+    auto inspectorCanvas = findInspectorCanvas(*context);
+    ASSERT(inspectorCanvas);
     if (!inspectorCanvas)
         return;
 
@@ -504,7 +488,7 @@
 
 void InspectorCanvasAgent::didFinishRecordingCanvasFrame(CanvasRenderingContext& context, bool forceDispatch)
 {
-    auto* inspectorCanvas = findInspectorCanvas(context);
+    auto inspectorCanvas = findInspectorCanvas(context);
     ASSERT(inspectorCanvas);
     if (!inspectorCanvas)
         return;
@@ -515,7 +499,6 @@
     if (!inspectorCanvas->hasRecordingData()) {
         if (forceDispatch) {
             m_frontendDispatcher->recordingFinished(inspectorCanvas->identifier(), nullptr);
-
             inspectorCanvas->resetRecordingData();
         }
         return;
@@ -531,41 +514,12 @@
     if (!forceDispatch && !inspectorCanvas->overFrameCount())
         return;
 
-    // FIXME: <https://webkit.org/b/176008> Web Inspector: Record actions performed on WebGL2RenderingContext
-
-    Inspector::Protocol::Recording::Type type;
-    if (is<CanvasRenderingContext2D>(inspectorCanvas->context()))
-        type = Inspector::Protocol::Recording::Type::Canvas2D;
-    else if (is<ImageBitmapRenderingContext>(inspectorCanvas->context()))
-        type = Inspector::Protocol::Recording::Type::CanvasBitmapRenderer;
-#if ENABLE(WEBGL)
-    else if (is<WebGLRenderingContext>(inspectorCanvas->context()))
-        type = Inspector::Protocol::Recording::Type::CanvasWebGL;
-#endif
-    else {
-        ASSERT_NOT_REACHED();
-        type = Inspector::Protocol::Recording::Type::Canvas2D;
-    }
-
-    auto recording = Inspector::Protocol::Recording::Recording::create()
-        .setVersion(Inspector::Protocol::Recording::VERSION)
-        .setType(type)
-        .setInitialState(inspectorCanvas->releaseInitialState())
-        .setData(inspectorCanvas->releaseData())
-        .release();
-
-    const String& name = inspectorCanvas->recordingName();
-    if (!name.isEmpty())
-        recording->setName(name);
-
-    m_frontendDispatcher->recordingFinished(inspectorCanvas->identifier(), WTFMove(recording));
-
-    inspectorCanvas->resetRecordingData();
+    m_frontendDispatcher->recordingFinished(inspectorCanvas->identifier(), inspectorCanvas->releaseObjectForRecording());
 }
 
 void InspectorCanvasAgent::consoleStartRecordingCanvas(CanvasRenderingContext& context, JSC::ExecState& exec, JSC::JSObject* options)
 {
-    auto* inspectorCanvas = findInspectorCanvas(context);
+    auto inspectorCanvas = findInspectorCanvas(context);
     ASSERT(inspectorCanvas);
     if (!inspectorCanvas)
         return;
@@ -587,7 +541,7 @@
 #if ENABLE(WEBGL)
 void InspectorCanvasAgent::didEnableExtension(WebGLRenderingContextBase& context, const String& extension)
 {
-    auto* inspectorCanvas = findInspectorCanvas(context);
+    auto inspectorCanvas = findInspectorCanvas(context);
     ASSERT(inspectorCanvas);
     if (!inspectorCanvas)
         return;
@@ -597,7 +551,7 @@
 
 void InspectorCanvasAgent::didCreateProgram(WebGLRenderingContextBase& context, WebGLProgram& program)
 {
-    auto* inspectorCanvas = findInspectorCanvas(context);
+    auto inspectorCanvas = findInspectorCanvas(context);
     ASSERT(inspectorCanvas);
     if (!inspectorCanvas)
         return;
@@ -610,7 +564,7 @@
 
 void InspectorCanvasAgent::willDeleteProgram(WebGLProgram& program)
 {
-    auto* inspectorProgram = findInspectorProgram(program);
+    auto inspectorProgram = findInspectorProgram(program);
     if (!inspectorProgram)
         return;
 
@@ -620,7 +574,8 @@
 
 bool InspectorCanvasAgent::isShaderProgramDisabled(WebGLProgram& program)
 {
-    auto* inspectorProgram = findInspectorProgram(program);
+    auto inspectorProgram = findInspectorProgram(program);
+    ASSERT(inspectorProgram);
     if (!inspectorProgram)
         return false;
 
@@ -629,7 +584,8 @@
 
 bool InspectorCanvasAgent::isShaderProgramHighlighted(WebGLProgram& program)
 {
-    auto* inspectorProgram = findInspectorProgram(program);
+    auto inspectorProgram = findInspectorProgram(program);
+    ASSERT(inspectorProgram);
     if (!inspectorProgram)
         return false;
 
@@ -674,16 +630,6 @@
     m_removedCanvasIdentifiers.clear();
 }
 
-void InspectorCanvasAgent::canvasRecordingTimerFired()
-{
-    for (auto& inspectorCanvas : m_identifierToInspectorCanvas.values()) {
-        if (!inspectorCanvas->context().callTracingActive())
-            continue;
-
-        didFinishRecordingCanvasFrame(inspectorCanvas->context());
-    }
-}
-
 void InspectorCanvasAgent::clearCanvasData()
 {
     for (auto& inspectorCanvas : m_identifierToInspectorCanvas.values())
@@ -690,14 +636,11 @@
         inspectorCanvas->context().canvasBase().removeObserver(*this);
 
     m_identifierToInspectorCanvas.clear();
-    m_removedCanvasIdentifiers.clear();
 #if ENABLE(WEBGL)
     m_identifierToInspectorProgram.clear();
+    m_removedCanvasIdentifiers.clear();
 #endif
 
-    if (m_canvasRecordingTimer.isActive())
-        m_canvasRecordingTimer.stop();
-
     if (m_canvasDestroyedTimer.isActive())
         m_canvasDestroyedTimer.stop();
 }
@@ -745,22 +688,22 @@
     return identifier;
 }
 
-InspectorCanvas* InspectorCanvasAgent::assertInspectorCanvas(ErrorString& errorString, const String& identifier)
+RefPtr<InspectorCanvas> InspectorCanvasAgent::assertInspectorCanvas(ErrorString& errorString, const String& identifier)
 {
-    RefPtr<InspectorCanvas> inspectorCanvas = m_identifierToInspectorCanvas.get(identifier);
+    auto inspectorCanvas = m_identifierToInspectorCanvas.get(identifier);
     if (!inspectorCanvas) {
         errorString = "No canvas for given identifier."_s;
         return nullptr;
     }
 
-    return inspectorCanvas.get();
+    return inspectorCanvas;
 }
 
-InspectorCanvas* InspectorCanvasAgent::findInspectorCanvas(CanvasRenderingContext& context)
+RefPtr<InspectorCanvas> InspectorCanvasAgent::findInspectorCanvas(CanvasRenderingContext& context)
 {
     for (auto& inspectorCanvas : m_identifierToInspectorCanvas.values()) {
         if (&inspectorCanvas->context() == &context)
-            return inspectorCanvas.get();
+            return inspectorCanvas;
     }
 
     return nullptr;
@@ -775,22 +718,22 @@
     return identifier;
 }
 
-InspectorShaderProgram* InspectorCanvasAgent::assertInspectorProgram(ErrorString& errorString, const String& identifier)
+RefPtr<InspectorShaderProgram> InspectorCanvasAgent::assertInspectorProgram(ErrorString& errorString, const String& identifier)
 {
-    RefPtr<InspectorShaderProgram> inspectorProgram = m_identifierToInspectorProgram.get(identifier);
+    auto inspectorProgram = m_identifierToInspectorProgram.get(identifier);
     if (!inspectorProgram) {
         errorString = "No shader program for given identifier."_s;
         return nullptr;
     }
 
-    return inspectorProgram.get();
+    return inspectorProgram;
 }
 
-InspectorShaderProgram* InspectorCanvasAgent::findInspectorProgram(WebGLProgram& program)
+RefPtr<InspectorShaderProgram> InspectorCanvasAgent::findInspectorProgram(WebGLProgram& program)
 {
     for (auto& inspectorProgram : m_identifierToInspectorProgram.values()) {
         if (&inspectorProgram->program() == &program)
-            return inspectorProgram.get();
+            return inspectorProgram;
     }
 
     return nullptr;

Modified: trunk/Source/WebCore/inspector/agents/InspectorCanvasAgent.h (243355 => 243356)


--- trunk/Source/WebCore/inspector/agents/InspectorCanvasAgent.h	2019-03-22 02:33:38 UTC (rev 243355)
+++ trunk/Source/WebCore/inspector/agents/InspectorCanvasAgent.h	2019-03-22 02:47:35 UTC (rev 243356)
@@ -112,18 +112,15 @@
     void startRecording(InspectorCanvas&, Inspector::Protocol::Recording::Initiator, RecordingOptions&& = { });
 
     void canvasDestroyedTimerFired();
-    void canvasRecordingTimerFired();
     void clearCanvasData();
     InspectorCanvas& bindCanvas(CanvasRenderingContext&, bool captureBacktrace);
     String unbindCanvas(InspectorCanvas&);
-    InspectorCanvas* assertInspectorCanvas(ErrorString&, const String& identifier);
-    InspectorCanvas* findInspectorCanvas(CanvasRenderingContext&);
+    RefPtr<InspectorCanvas> assertInspectorCanvas(ErrorString&, const String& identifier);
+    RefPtr<InspectorCanvas> findInspectorCanvas(CanvasRenderingContext&);
 #if ENABLE(WEBGL)
     String unbindProgram(InspectorShaderProgram&);
-    InspectorShaderProgram* assertInspectorProgram(ErrorString&, const String& identifier);
-    InspectorShaderProgram* findInspectorProgram(WebGLProgram&);
-
-    HashMap<String, RefPtr<InspectorShaderProgram>> m_identifierToInspectorProgram;
+    RefPtr<InspectorShaderProgram> assertInspectorProgram(ErrorString&, const String& identifier);
+    RefPtr<InspectorShaderProgram> findInspectorProgram(WebGLProgram&);
 #endif
 
     std::unique_ptr<Inspector::CanvasFrontendDispatcher> m_frontendDispatcher;
@@ -133,10 +130,14 @@
     Page& m_inspectedPage;
 
     HashMap<String, RefPtr<InspectorCanvas>> m_identifierToInspectorCanvas;
+#if ENABLE(WEBGL)
+    HashMap<String, RefPtr<InspectorShaderProgram>> m_identifierToInspectorProgram;
+#endif
     Vector<String> m_removedCanvasIdentifiers;
+
     Optional<size_t> m_recordingAutoCaptureFrameCount;
+
     Timer m_canvasDestroyedTimer;
-    Timer m_canvasRecordingTimer;
 };
 
 } // namespace WebCore

Modified: trunk/Source/WebCore/platform/graphics/GraphicsContext3D.h (243355 => 243356)


--- trunk/Source/WebCore/platform/graphics/GraphicsContext3D.h	2019-03-22 02:33:38 UTC (rev 243355)
+++ trunk/Source/WebCore/platform/graphics/GraphicsContext3D.h	2019-03-22 02:47:35 UTC (rev 243356)
@@ -120,6 +120,15 @@
 
 class GraphicsContext3D : public RefCounted<GraphicsContext3D> {
 public:
+    class Client {
+    public:
+        virtual ~Client() { }
+        virtual void didComposite() = 0;
+        virtual void forceContextLost() = 0;
+        virtual void recycleContext() = 0;
+        virtual void dispatchContextChangedNotification() = 0;
+    };
+
     enum {
         // WebGL 1 constants
         DEPTH_BUFFER_BIT = 0x00000100,
@@ -764,8 +773,10 @@
 #endif
 
     bool makeContextCurrent();
-    void setWebGLContext(WebGLRenderingContextBase* base) { m_webglContext = base; }
 
+    void addClient(Client& client) { m_clients.add(&client); }
+    void removeClient(Client& client) { m_clients.remove(&client); }
+
     // With multisampling on, blit from multisampleFBO to regular FBO.
     void prepareTexture();
 
@@ -1507,8 +1518,7 @@
     std::unique_ptr<GraphicsContext3DPrivate> m_private;
 #endif
 
-    // FIXME: Layering violation.
-    WebGLRenderingContextBase* m_webglContext { nullptr };
+    HashSet<Client*> m_clients;
 
     bool m_isForWebGL2 { false };
     bool m_usingCoreProfile { false };

Modified: trunk/Source/WebCore/platform/graphics/opengl/GraphicsContext3DOpenGLCommon.cpp (243355 => 243356)


--- trunk/Source/WebCore/platform/graphics/opengl/GraphicsContext3DOpenGLCommon.cpp	2019-03-22 02:33:38 UTC (rev 243355)
+++ trunk/Source/WebCore/platform/graphics/opengl/GraphicsContext3DOpenGLCommon.cpp	2019-03-22 02:47:35 UTC (rev 243356)
@@ -2016,6 +2016,9 @@
 void GraphicsContext3D::markLayerComposited()
 {
     m_layerComposited = true;
+
+    for (auto* client : m_clients)
+        client->didComposite();
 }
 
 bool GraphicsContext3D::layerComposited() const
@@ -2025,26 +2028,20 @@
 
 void GraphicsContext3D::forceContextLost()
 {
-#if ENABLE(WEBGL)
-    if (m_webglContext)
-        m_webglContext->forceLostContext(WebGLRenderingContextBase::RealLostContext);
-#endif
+    for (auto* client : m_clients)
+        client->forceContextLost();
 }
 
 void GraphicsContext3D::recycleContext()
 {
-#if ENABLE(WEBGL)
-    if (m_webglContext)
-        m_webglContext->recycleContext();
-#endif
+    for (auto* client : m_clients)
+        client->recycleContext();
 }
 
 void GraphicsContext3D::dispatchContextChangedNotification()
 {
-#if ENABLE(WEBGL)
-    if (m_webglContext)
-        m_webglContext->dispatchContextChangedEvent();
-#endif
+    for (auto* client : m_clients)
+        client->dispatchContextChangedNotification();
 }
 
 void GraphicsContext3D::texImage2DDirect(GC3Denum target, GC3Dint level, GC3Denum internalformat, GC3Dsizei width, GC3Dsizei height, GC3Dint border, GC3Denum format, GC3Denum type, const void* pixels)
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to