Title: [218440] trunk
Revision
218440
Author
mattba...@apple.com
Date
2017-06-16 19:58:24 -0700 (Fri, 16 Jun 2017)

Log Message

Web Inspector: Instrument 2D/WebGL canvas contexts in the backend
https://bugs.webkit.org/show_bug.cgi?id=172623
<rdar://problem/32415986>

Reviewed by Devin Rousso and Joseph Pecoraro.

Source/_javascript_Core:

This patch adds a basic Canvas protocol. It includes Canvas and related
types and events for monitoring the lifetime of canvases in the page.

* CMakeLists.txt:
* DerivedSources.make:
* inspector/protocol/Canvas.json: Added.

* inspector/scripts/codegen/generator.py:
(Generator.stylized_name_for_enum_value):
Add special handling for Canvas.ContextType protocol enumeration,
so that "canvas-2d" and "webgl" map to `Canvas2D` and `WebGL`.

Source/WebCore:

Test: inspector/canvas/create-canvas-contexts.html

* CMakeLists.txt:
* WebCore.xcodeproj/project.pbxproj:

* dom/Document.cpp:
(WebCore::Document::getCSSCanvasElement):
Instrument creation of CSS canvases. This merely registers the canvas
element with InspectorCanvasAgent and stores the name (identifier passed
to getCSSCanvasContext) for later use. It isn't until the context is
actually created that the frontend receives a notification.

* html/HTMLCanvasElement.cpp:
(WebCore::HTMLCanvasElement::getContext2d):
(WebCore::HTMLCanvasElement::getContextWebGL):
Instrument creation of 2D and WebGL canvas contexts.

* inspector/InspectorAllInOne.cpp:

* inspector/InspectorCanvasAgent.cpp: Added.
New backend agent for canvas inspection. Canvas creation and destruction
are continuously monitored by the agent, regardless of the presence of
a frontend. This is necessary since there is no way to retrieve the
rendering contexts for with a given frame once they've been created.

(WebCore::InspectorCanvasAgent::InspectorCanvasAgent):
(WebCore::InspectorCanvasAgent::didCreateFrontendAndBackend):
(WebCore::InspectorCanvasAgent::willDestroyFrontendAndBackend):
(WebCore::InspectorCanvasAgent::discardAgent):
Unregister canvas observers to prevent dangling agent pointer.
(WebCore::InspectorCanvasAgent::enable):
Dispatch events for existing canvases, now that the frontend exists.
(WebCore::InspectorCanvasAgent::disable):
(WebCore::InspectorCanvasAgent::frameNavigated):
(WebCore::InspectorCanvasAgent::didCreateCSSCanvas):
Register the name/identifier associated with the CSS canvas, so that it
can be retrieved and associated with the rendering context later.

(WebCore::InspectorCanvasAgent::didCreateCanvasRenderingContext):
(WebCore::InspectorCanvasAgent::canvasDestroyed):
Removes the canvas from the agent, and queues it for notifying the
frontend during the next event loop.

(WebCore::InspectorCanvasAgent::canvasDestroyedTimerFired):
(WebCore::InspectorCanvasAgent::clearCanvasData):
(WebCore::InspectorCanvasAgent::getCanvasEntry):
(WebCore::InspectorCanvasAgent::buildObjectForCanvas):
* inspector/InspectorCanvasAgent.h: Added.

* inspector/InspectorController.cpp:
(WebCore::InspectorController::InspectorController):

* inspector/InspectorInstrumentation.cpp:
(WebCore::InspectorInstrumentation::didCommitLoadImpl):
(WebCore::InspectorInstrumentation::didCreateCSSCanvasImpl):
(WebCore::InspectorInstrumentation::didCreateCanvasRenderingContextImpl):

* inspector/InspectorInstrumentation.h:
(WebCore::InspectorInstrumentation::didCreateCSSCanvas):
(WebCore::InspectorInstrumentation::didCreateCanvasRenderingContext):
These instrumentation points should not fast return when no frontend
is attached.

* inspector/InstrumentingAgents.cpp:
(WebCore::InstrumentingAgents::reset):

* inspector/InstrumentingAgents.h:
(WebCore::InstrumentingAgents::inspectorCanvasAgent):
(WebCore::InstrumentingAgents::setInspectorCanvasAgent):
Plumbing for the new agent.

Source/WebInspectorUI:

* UserInterface/Base/Main.js:
(WebInspector.loaded):

* UserInterface/Controllers/CanvasManager.js: Added.
New frontend manager for the Canvas domain.
(WebInspector.CanvasManager):
(WebInspector.CanvasManager.prototype.get canvases):
(WebInspector.CanvasManager.prototype.canvasAdded):
(WebInspector.CanvasManager.prototype.canvasRemoved):
(WebInspector.CanvasManager.prototype._mainResourceDidChange):

* UserInterface/Main.html:
New files.

* UserInterface/Models/Canvas.js: Added.
(WebInspector.Canvas):
(WebInspector.Canvas.fromPayload):
(WebInspector.Canvas.displayNameForContextType):
Get displayable text "2D" or "WebGL" based on context type.
(WebInspector.Canvas.resetUniqueDisplayNameNumbers):
Called by CanvasManager when canvases are cleared.
(WebInspector.Canvas.prototype.get identifier):
(WebInspector.Canvas.prototype.get contextType):
(WebInspector.Canvas.prototype.get frame):
(WebInspector.Canvas.prototype.get cssCanvasName):
For CSS canvases, the identifier passed to getCSSCanvasContext.
(WebInspector.Canvas.prototype.get displayName):
Get displayable canvas name. The name depends on how the canvas was
created, and the information available:
  - getCSSCanvasContext: "CSS Canvas <identifier>"
  - getContext: "Canvas #<DOM id attribute value>"
  - Otherwise: "Canvas 1", "Canvas 2", ...

(WebInspector.Canvas.saveIdentityToCookie):

* UserInterface/Protocol/CanvasObserver.js: Added.
(WebInspector.CanvasObserver.prototype.canvasAdded):
(WebInspector.CanvasObserver.prototype.canvasRemoved):
(WebInspector.CanvasObserver):

* UserInterface/Test.html:
* UserInterface/Test/Test.js:
(WebInspector.loaded):

LayoutTests:

Test that CanvasAgent dispatches events for canvas lifecycle events.

* inspector/canvas/create-canvas-contexts-expected.txt: Added.
* inspector/canvas/create-canvas-contexts.html: Added.

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (218439 => 218440)


--- trunk/LayoutTests/ChangeLog	2017-06-17 02:39:20 UTC (rev 218439)
+++ trunk/LayoutTests/ChangeLog	2017-06-17 02:58:24 UTC (rev 218440)
@@ -1,3 +1,16 @@
+2017-06-16  Matt Baker  <mattba...@apple.com>
+
+        Web Inspector: Instrument 2D/WebGL canvas contexts in the backend
+        https://bugs.webkit.org/show_bug.cgi?id=172623
+        <rdar://problem/32415986>
+
+        Reviewed by Devin Rousso and Joseph Pecoraro.
+
+        Test that CanvasAgent dispatches events for canvas lifecycle events.
+
+        * inspector/canvas/create-canvas-contexts-expected.txt: Added.
+        * inspector/canvas/create-canvas-contexts.html: Added.
+
 2017-06-16  Sam Weinig  <s...@webkit.org>
 
         [WebIDL] Remove custom bindings for HTMLDocument

Added: trunk/LayoutTests/inspector/canvas/create-canvas-contexts-expected.txt (0 => 218440)


--- trunk/LayoutTests/inspector/canvas/create-canvas-contexts-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/inspector/canvas/create-canvas-contexts-expected.txt	2017-06-17 02:58:24 UTC (rev 218440)
@@ -0,0 +1,48 @@
+Test that CanvasManager tracks creation and destruction of 2D and WebGL canvases.
+
+
+== Running test suite: Canvas.canvasContexts
+-- Running test case: CheckNoCanvases
+PASS: CanvasManager should have no canvases.
+
+-- Running test case: CheckCanvasesCleared
+Added canvas.
+Cleared canvases after reloading page.
+PASS: CanvasManager should have no canvases.
+
+-- Running test case: Create2DCanvasContext
+Added canvas.
+PASS: Canvas context should be 2D.
+Removed canvas.
+PASS: Removed canvas has expected ID.
+
+-- Running test case: CreateWebGLCanvasContext
+Added canvas.
+PASS: Canvas context should be WebGL.
+Removed canvas.
+PASS: Removed canvas has expected ID.
+
+-- Running test case: Create2DCanvasContextOffscreen
+Added canvas.
+PASS: Canvas context should be 2D.
+Removed canvas.
+PASS: Removed canvas has expected ID.
+
+-- Running test case: CreateWebGLCanvasContextOffscreen
+Added canvas.
+PASS: Canvas context should be WebGL.
+Removed canvas.
+PASS: Removed canvas has expected ID.
+
+-- Running test case: CreateCSSCanvas2D
+Create CSS canvas from -webkit-canvas(css-canvas-2d).
+Added canvas.
+PASS: Canvas context should be 2D.
+PASS: Canvas name should equal the identifier passed to -webkit-canvas.
+
+-- Running test case: CreateCSSCanvasWebGL
+Create CSS canvas from -webkit-canvas(css-canvas-webgl).
+Added canvas.
+PASS: Canvas context should be WebGL.
+PASS: Canvas name should equal the identifier passed to -webkit-canvas.
+

Added: trunk/LayoutTests/inspector/canvas/create-canvas-contexts.html (0 => 218440)


--- trunk/LayoutTests/inspector/canvas/create-canvas-contexts.html	                        (rev 0)
+++ trunk/LayoutTests/inspector/canvas/create-canvas-contexts.html	2017-06-17 02:58:24 UTC (rev 218440)
@@ -0,0 +1,171 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src=""
+<script>
+let contexts = [];
+
+function createCanvas(contextType) {
+    let canvas = document.body.appendChild(document.createElement("canvas"));
+    contexts.push(canvas.getContext(contextType));
+}
+
+function createCSSCanvas(contextType, canvasName) {
+    contexts.push(document.getCSSCanvasContext(contextType, canvasName, 10, 10));
+}
+
+function createOffscreenCanvas(contextType) {
+    contexts.push(document.createElement("canvas").getContext(contextType));
+}
+
+function destroyCanvases() {
+    for (let context of contexts) {
+        let canvasElement = context.canvas;
+        if (canvasElement && canvasElement.parentNode)
+            canvasElement.remove();
+    }
+
+    contexts = [];
+
+    // Force GC to make sure the canvas element is destroyed, otherwise the frontend
+    // does not receive WebInspector.CanvasManager.Event.CanvasWasRemoved events.
+    setTimeout(() => { GCController.collect(); }, 0);
+}
+
+function test() {
+    let suite = InspectorTest.createAsyncSuite("Canvas.canvasContexts");
+
+    function awaitCanvasAdded(contextType) {
+        return WebInspector.canvasManager.awaitEvent(WebInspector.CanvasManager.Event.CanvasWasAdded)
+        .then((event) => {
+            let canvas = event.data.canvas;
+            InspectorTest.log("Added canvas.");
+
+            let contextDisplayName = WebInspector.Canvas.displayNameForContextType(contextType);
+            InspectorTest.expectEqual(canvas.contextType, contextType, `Canvas context should be ${contextDisplayName}.`);
+
+            return canvas;
+        });
+    }
+
+    function awaitCanvasRemoved(canvasIdentifier) {
+        return WebInspector.canvasManager.awaitEvent(WebInspector.CanvasManager.Event.CanvasWasRemoved)
+        .then((event) => {
+            let canvas = event.data.canvas;
+            InspectorTest.log("Removed canvas.");
+            InspectorTest.expectEqual(canvas.identifier, canvasIdentifier, "Removed canvas has expected ID.");
+        });
+    }
+
+    suite.addTestCase({
+        name: "CheckNoCanvases",
+        description: "Check that the CanvasManager has no canvases initially.",
+        test(resolve, reject) {
+            InspectorTest.expectEqual(WebInspector.canvasManager.canvases.length, 0, "CanvasManager should have no canvases.");
+            resolve();
+        }
+    });
+
+    suite.addTestCase({
+        name: "CheckCanvasesCleared",
+        description: "Check that canvases are cleared on reload.",
+        test(resolve, reject) {
+            WebInspector.canvasManager.awaitEvent(WebInspector.CanvasManager.Event.Cleared)
+            .then((event) => {
+                InspectorTest.log("Cleared canvases after reloading page.");
+                InspectorTest.expectEqual(WebInspector.canvasManager.canvases.length, 0, "CanvasManager should have no canvases.");
+            })
+            .then(resolve, reject);
+
+            WebInspector.canvasManager.awaitEvent(WebInspector.CanvasManager.Event.CanvasWasAdded)
+            .then((event) => {
+                InspectorTest.log("Added canvas.");
+                InspectorTest.reloadPage();
+            });
+
+            InspectorTest.evaluateInPage(`createCanvas('2d')`);
+        }
+    });
+
+    function addSimpleTestCase({name, description, _expression_, contextType}) {
+        suite.addTestCase({
+            name,
+            description,
+            test(resolve, reject) {
+                awaitCanvasAdded(contextType)
+                .then((canvas) => {
+                    if (canvas.cssCanvasName) {
+                        InspectorTest.log("CSS canvas will not be destroyed");
+                        resolve();
+                        return;
+                    }
+
+                    let promise = awaitCanvasRemoved(canvas.identifier);
+                    InspectorTest.evaluateInPage(`destroyCanvases()`);
+                    return promise;
+                })
+                .then(resolve, reject);
+
+                InspectorTest.evaluateInPage(_expression_);
+            }
+        });
+    }
+
+    let simpleTestCases = [
+        {
+            name: "Create2DCanvasContext",
+            _expression_: `createCanvas("2d")`,
+            contextType: WebInspector.Canvas.ContextType.Canvas2D,
+        },
+        {
+            name: "CreateWebGLCanvasContext",
+            _expression_: `createCanvas("webgl")`,
+            contextType: WebInspector.Canvas.ContextType.WebGL,
+        },
+        {
+            name: "Create2DCanvasContextOffscreen",
+            _expression_: `createOffscreenCanvas("2d")`,
+            contextType: WebInspector.Canvas.ContextType.Canvas2D,
+        },
+        {
+            name: "CreateWebGLCanvasContextOffscreen",
+            _expression_: `createOffscreenCanvas("webgl")`,
+            contextType: WebInspector.Canvas.ContextType.WebGL,
+        }
+    ];
+
+    simpleTestCases.forEach(addSimpleTestCase);
+
+    function addCSSCanvasTest(contextType, cssCanvasIdentifier) {
+        let displayContextType = WebInspector.Canvas.displayNameForContextType(contextType);
+
+        suite.addTestCase({
+            name: `CreateCSSCanvas${displayContextType}`,
+            description: "Check that CSS canvases have the correct name and type.",
+            test(resolve, reject) {
+                awaitCanvasAdded(contextType, !!cssCanvasIdentifier)
+                .then((canvas) => { InspectorTest.expectEqual(canvas.cssCanvasName, cssCanvasIdentifier, "Canvas name should equal the identifier passed to -webkit-canvas."); })
+                .then(resolve, reject);
+
+                let contextId = contextType === WebInspector.Canvas.ContextType.Canvas2D ? "2d" : "webgl";
+                InspectorTest.log(`Create CSS canvas from -webkit-canvas(${cssCanvasIdentifier}).`);
+                InspectorTest.evaluateInPage(`createCSSCanvas("${contextId}", "${cssCanvasIdentifier}")`);
+            }
+        });
+    }
+
+    addCSSCanvasTest(WebInspector.Canvas.ContextType.Canvas2D, "css-canvas-2d");
+    addCSSCanvasTest(WebInspector.Canvas.ContextType.WebGL, "css-canvas-webgl");
+
+    suite.runTestCasesAndFinish();
+}
+</script>
+<style>
+    .canvas1 { background-image: -webkit-canvas(css-canvas-2d); }
+    .canvas2 { background-image: -webkit-canvas(css-canvas-webgl); }
+</style>
+</head>
+<body _onload_="runTest()">
+    <p>Test that CanvasManager tracks creation and destruction of 2D and WebGL canvases.</p>
+</body>
+</html>

Modified: trunk/Source/_javascript_Core/CMakeLists.txt (218439 => 218440)


--- trunk/Source/_javascript_Core/CMakeLists.txt	2017-06-17 02:39:20 UTC (rev 218439)
+++ trunk/Source/_javascript_Core/CMakeLists.txt	2017-06-17 02:58:24 UTC (rev 218440)
@@ -1350,6 +1350,7 @@
 set(_javascript_Core_INSPECTOR_DOMAINS
     ${_javascript_CORE_DIR}/inspector/protocol/ApplicationCache.json
     ${_javascript_CORE_DIR}/inspector/protocol/CSS.json
+    ${_javascript_CORE_DIR}/inspector/protocol/Canvas.json
     ${_javascript_CORE_DIR}/inspector/protocol/Console.json
     ${_javascript_CORE_DIR}/inspector/protocol/DOM.json
     ${_javascript_CORE_DIR}/inspector/protocol/DOMDebugger.json

Modified: trunk/Source/_javascript_Core/ChangeLog (218439 => 218440)


--- trunk/Source/_javascript_Core/ChangeLog	2017-06-17 02:39:20 UTC (rev 218439)
+++ trunk/Source/_javascript_Core/ChangeLog	2017-06-17 02:58:24 UTC (rev 218440)
@@ -1,3 +1,23 @@
+2017-06-16  Matt Baker  <mattba...@apple.com>
+
+        Web Inspector: Instrument 2D/WebGL canvas contexts in the backend
+        https://bugs.webkit.org/show_bug.cgi?id=172623
+        <rdar://problem/32415986>
+
+        Reviewed by Devin Rousso and Joseph Pecoraro.
+
+        This patch adds a basic Canvas protocol. It includes Canvas and related
+        types and events for monitoring the lifetime of canvases in the page.
+
+        * CMakeLists.txt:
+        * DerivedSources.make:
+        * inspector/protocol/Canvas.json: Added.
+
+        * inspector/scripts/codegen/generator.py:
+        (Generator.stylized_name_for_enum_value):
+        Add special handling for Canvas.ContextType protocol enumeration,
+        so that "canvas-2d" and "webgl" map to `Canvas2D` and `WebGL`.
+
 2017-06-16  Wenson Hsieh  <wenson_hs...@apple.com>
 
         [iOS DnD] Upstream iOS drag and drop implementation into OpenSource WebKit

Modified: trunk/Source/_javascript_Core/DerivedSources.make (218439 => 218440)


--- trunk/Source/_javascript_Core/DerivedSources.make	2017-06-17 02:39:20 UTC (rev 218439)
+++ trunk/Source/_javascript_Core/DerivedSources.make	2017-06-17 02:58:24 UTC (rev 218440)
@@ -214,6 +214,7 @@
 INSPECTOR_DOMAINS = \
     $(_javascript_Core)/inspector/protocol/ApplicationCache.json \
     $(_javascript_Core)/inspector/protocol/CSS.json \
+    $(_javascript_Core)/inspector/protocol/Canvas.json \
     $(_javascript_Core)/inspector/protocol/Console.json \
     $(_javascript_Core)/inspector/protocol/DOM.json \
     $(_javascript_Core)/inspector/protocol/DOMDebugger.json \

Added: trunk/Source/_javascript_Core/inspector/protocol/Canvas.json (0 => 218440)


--- trunk/Source/_javascript_Core/inspector/protocol/Canvas.json	                        (rev 0)
+++ trunk/Source/_javascript_Core/inspector/protocol/Canvas.json	2017-06-17 02:58:24 UTC (rev 218440)
@@ -0,0 +1,53 @@
+{
+    "domain": "Canvas",
+    "availability": "web",
+    "description": "Canvas domain allows tracking of 2D and WebGL canvases that have an associated graphics context. Tracks canvases in the DOM and CSS canvases created with -webkit-canvas.",
+    "types": [
+        {
+            "id": "CanvasId",
+            "type": "string",
+            "description": "Unique canvas identifier."
+        },
+        {
+            "id": "ContextType",
+            "type": "string",
+            "enum": ["canvas-2d", "webgl"],
+            "description": "The type of rendering context backing the canvas element."
+        },
+        {
+            "id": "Canvas",
+            "type": "object",
+            "description": "Information about a 2D/WebGL canvas for which a rendering context has been created.",
+            "properties": [
+                { "name": "canvasId", "$ref": "CanvasId", "description": "Canvas identifier." },
+                { "name": "contextType", "$ref": "ContextType", "description": "The type of rendering context backing the canvas." },
+                { "name": "frameId", "$ref": "Network.FrameId", "description": "Parent frame identifier." },
+                { "name": "cssCanvasName", "type": "string", "optional": true, "description": "The CSS canvas identifier, for canvases created with <code>document.getCSSCanvasContext</code>." }
+            ]
+        }
+    ],
+    "commands": [
+        {
+            "name": "enable",
+            "description": "Enables Canvas domain events."
+        },
+        {
+            "name": "disable",
+            "description": "Disables Canvas domain events."
+        }
+    ],
+    "events": [
+        {
+            "name": "canvasAdded",
+            "parameters": [
+                { "name": "canvas", "$ref": "Canvas", "description": "Canvas object." }
+            ]
+        },
+        {
+            "name": "canvasRemoved",
+            "parameters": [
+                { "name": "canvasId", "$ref": "CanvasId", "description": "Removed canvas identifier." }
+            ]
+        }
+    ]
+}

Modified: trunk/Source/_javascript_Core/inspector/scripts/codegen/generator.py (218439 => 218440)


--- trunk/Source/_javascript_Core/inspector/scripts/codegen/generator.py	2017-06-17 02:39:20 UTC (rev 218439)
+++ trunk/Source/_javascript_Core/inspector/scripts/codegen/generator.py	2017-06-17 02:58:24 UTC (rev 218440)
@@ -38,9 +38,13 @@
 def ucfirst(str):
     return str[:1].upper() + str[1:]
 
-_ALWAYS_SPECIALCASED_ENUM_VALUE_SUBSTRINGS = set(['API', 'CSS', 'DOM', 'HTML', 'JIT', 'XHR', 'XML', 'IOS', 'MacOS'])
+_ALWAYS_SPECIALCASED_ENUM_VALUE_SUBSTRINGS = set(['2D', 'API', 'CSS', 'DOM', 'HTML', 'JIT', 'XHR', 'XML', 'IOS', 'MacOS'])
 _ALWAYS_SPECIALCASED_ENUM_VALUE_LOOKUP_TABLE = dict([(s.upper(), s) for s in _ALWAYS_SPECIALCASED_ENUM_VALUE_SUBSTRINGS])
 
+_ENUM_IDENTIFIER_RENAME_MAP = {
+    'webgl': 'WebGL',  # Canvas.ContextType.webgl
+}
+
 # These objects are built manually by creating and setting InspectorValues.
 # Before sending these over the protocol, their shapes are checked against the specification.
 # So, any types referenced by these types require debug-only assertions that check values.
@@ -251,7 +255,7 @@
             return _ALWAYS_SPECIALCASED_ENUM_VALUE_LOOKUP_TABLE[match.group(1).upper()]
 
         # Split on hyphen, introduce camelcase, and force uppercasing of acronyms.
-        subwords = map(ucfirst, enum_value.split('-'))
+        subwords = map(ucfirst, _ENUM_IDENTIFIER_RENAME_MAP.get(enum_value, enum_value).split('-'))
         return re.sub(re.compile(regex, re.IGNORECASE), replaceCallback, "".join(subwords))
 
     @staticmethod

Modified: trunk/Source/WebCore/CMakeLists.txt (218439 => 218440)


--- trunk/Source/WebCore/CMakeLists.txt	2017-06-17 02:39:20 UTC (rev 218439)
+++ trunk/Source/WebCore/CMakeLists.txt	2017-06-17 02:58:24 UTC (rev 218440)
@@ -1889,6 +1889,7 @@
     inspector/DOMPatchSupport.cpp
     inspector/InspectorApplicationCacheAgent.cpp
     inspector/InspectorCSSAgent.cpp
+    inspector/InspectorCanvasAgent.cpp
     inspector/InspectorClient.cpp
     inspector/InspectorController.cpp
     inspector/InspectorDOMAgent.cpp

Modified: trunk/Source/WebCore/ChangeLog (218439 => 218440)


--- trunk/Source/WebCore/ChangeLog	2017-06-17 02:39:20 UTC (rev 218439)
+++ trunk/Source/WebCore/ChangeLog	2017-06-17 02:58:24 UTC (rev 218440)
@@ -1,3 +1,82 @@
+2017-06-16  Matt Baker  <mattba...@apple.com>
+
+        Web Inspector: Instrument 2D/WebGL canvas contexts in the backend
+        https://bugs.webkit.org/show_bug.cgi?id=172623
+        <rdar://problem/32415986>
+
+        Reviewed by Devin Rousso and Joseph Pecoraro.
+
+        Test: inspector/canvas/create-canvas-contexts.html
+
+        * CMakeLists.txt:
+        * WebCore.xcodeproj/project.pbxproj:
+
+        * dom/Document.cpp:
+        (WebCore::Document::getCSSCanvasElement):
+        Instrument creation of CSS canvases. This merely registers the canvas
+        element with InspectorCanvasAgent and stores the name (identifier passed
+        to getCSSCanvasContext) for later use. It isn't until the context is
+        actually created that the frontend receives a notification.
+
+        * html/HTMLCanvasElement.cpp:
+        (WebCore::HTMLCanvasElement::getContext2d):
+        (WebCore::HTMLCanvasElement::getContextWebGL):
+        Instrument creation of 2D and WebGL canvas contexts.
+
+        * inspector/InspectorAllInOne.cpp:
+
+        * inspector/InspectorCanvasAgent.cpp: Added.
+        New backend agent for canvas inspection. Canvas creation and destruction
+        are continuously monitored by the agent, regardless of the presence of
+        a frontend. This is necessary since there is no way to retrieve the
+        rendering contexts for with a given frame once they've been created.
+
+        (WebCore::InspectorCanvasAgent::InspectorCanvasAgent):
+        (WebCore::InspectorCanvasAgent::didCreateFrontendAndBackend):
+        (WebCore::InspectorCanvasAgent::willDestroyFrontendAndBackend):
+        (WebCore::InspectorCanvasAgent::discardAgent):
+        Unregister canvas observers to prevent dangling agent pointer.
+        (WebCore::InspectorCanvasAgent::enable):
+        Dispatch events for existing canvases, now that the frontend exists.
+        (WebCore::InspectorCanvasAgent::disable):
+        (WebCore::InspectorCanvasAgent::frameNavigated):
+        (WebCore::InspectorCanvasAgent::didCreateCSSCanvas):
+        Register the name/identifier associated with the CSS canvas, so that it
+        can be retrieved and associated with the rendering context later.
+
+        (WebCore::InspectorCanvasAgent::didCreateCanvasRenderingContext):
+        (WebCore::InspectorCanvasAgent::canvasDestroyed):
+        Removes the canvas from the agent, and queues it for notifying the
+        frontend during the next event loop.
+
+        (WebCore::InspectorCanvasAgent::canvasDestroyedTimerFired):
+        (WebCore::InspectorCanvasAgent::clearCanvasData):
+        (WebCore::InspectorCanvasAgent::getCanvasEntry):
+        (WebCore::InspectorCanvasAgent::buildObjectForCanvas):
+        * inspector/InspectorCanvasAgent.h: Added.
+
+        * inspector/InspectorController.cpp:
+        (WebCore::InspectorController::InspectorController):
+
+        * inspector/InspectorInstrumentation.cpp:
+        (WebCore::InspectorInstrumentation::didCommitLoadImpl):
+        (WebCore::InspectorInstrumentation::didCreateCSSCanvasImpl):
+        (WebCore::InspectorInstrumentation::didCreateCanvasRenderingContextImpl):
+
+        * inspector/InspectorInstrumentation.h:
+        (WebCore::InspectorInstrumentation::didCreateCSSCanvas):
+        (WebCore::InspectorInstrumentation::didCreateCanvasRenderingContext):
+        These instrumentation points should not fast return when no frontend
+        is attached.
+
+        * inspector/InstrumentingAgents.cpp:
+        (WebCore::InstrumentingAgents::reset):
+
+        * inspector/InstrumentingAgents.h:
+        (WebCore::InstrumentingAgents::inspectorCanvasAgent):
+        (WebCore::InstrumentingAgents::setInspectorCanvasAgent):
+        Plumbing for the new agent.
+
 2017-06-16  Antoine Quint  <grao...@apple.com>
 
         Add a WebKit2 setting to control whether media documents should automatically enter fullscreen

Modified: trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj (218439 => 218440)


--- trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj	2017-06-17 02:39:20 UTC (rev 218439)
+++ trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj	2017-06-17 02:58:24 UTC (rev 218440)
@@ -2880,6 +2880,8 @@
 		6C4C96DF1AD4483500363F64 /* JSReadableByteStreamController.h in Headers */ = {isa = PBXBuildFile; fileRef = 6C4C96DB1AD4483500363F64 /* JSReadableByteStreamController.h */; };
 		6C4C96DF1AD4483500365672 /* JSReadableStreamBYOBRequest.h in Headers */ = {isa = PBXBuildFile; fileRef = 6C4C96DB1AD4483500365672 /* JSReadableStreamBYOBRequest.h */; };
 		6C4C96DF1AD4483500365A50 /* JSReadableStreamDefaultController.h in Headers */ = {isa = PBXBuildFile; fileRef = 6C4C96DB1AD4483500365A50 /* JSReadableStreamDefaultController.h */; };
+		6A32D7CE1A16D8C000412F0B /* InspectorCanvasAgent.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6A4B6D6619D225D8006F11D3 /* InspectorCanvasAgent.cpp */; };
+		6A4B6D6519D22519006F11D3 /* InspectorCanvasAgent.h in Headers */ = {isa = PBXBuildFile; fileRef = 6A4B6D6419D22519006F11D3 /* InspectorCanvasAgent.h */; };
 		6C638895A96CCEE50C8C946C /* CachedResourceRequestInitiators.h in Headers */ = {isa = PBXBuildFile; fileRef = 6C638893A96CCEE50C8C946C /* CachedResourceRequestInitiators.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		6C638896A96CCEE50C8C946C /* CachedResourceRequestInitiators.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6C638894A96CCEE50C8C946C /* CachedResourceRequestInitiators.cpp */; };
 		6CDDE8D01770BB220016E072 /* RegionOversetState.h in Headers */ = {isa = PBXBuildFile; fileRef = 6C70A81417707C49009A446E /* RegionOversetState.h */; settings = {ATTRIBUTES = (Private, ); }; };
@@ -10723,6 +10725,8 @@
 		6C4C96DB1AD4483500363F64 /* JSReadableByteStreamController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSReadableByteStreamController.h; sourceTree = "<group>"; };
 		6C4C96DB1AD4483500365672 /* JSReadableStreamBYOBRequest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSReadableStreamBYOBRequest.h; sourceTree = "<group>"; };
 		6C4C96DB1AD4483500365A50 /* JSReadableStreamDefaultController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSReadableStreamDefaultController.h; sourceTree = "<group>"; };
+		6A4B6D6419D22519006F11D3 /* InspectorCanvasAgent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = InspectorCanvasAgent.h; sourceTree = "<group>"; };
+		6A4B6D6619D225D8006F11D3 /* InspectorCanvasAgent.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = InspectorCanvasAgent.cpp; sourceTree = "<group>"; };
 		6C638893A96CCEE50C8C946C /* CachedResourceRequestInitiators.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = CachedResourceRequestInitiators.h; sourceTree = "<group>"; };
 		6C638894A96CCEE50C8C946C /* CachedResourceRequestInitiators.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = CachedResourceRequestInitiators.cpp; sourceTree = "<group>"; };
 		6C70A81417707C49009A446E /* RegionOversetState.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RegionOversetState.h; sourceTree = "<group>"; };
@@ -17227,6 +17231,8 @@
 				7A54881514E432A1006AE05A /* DOMPatchSupport.h */,
 				B885E8D211E06DD2009FFBF4 /* InspectorApplicationCacheAgent.cpp */,
 				B885E8D311E06DD2009FFBF4 /* InspectorApplicationCacheAgent.h */,
+				6A4B6D6619D225D8006F11D3 /* InspectorCanvasAgent.cpp */,
+				6A4B6D6419D22519006F11D3 /* InspectorCanvasAgent.h */,
 				7A1F2B51126C61B20006A7E6 /* InspectorClient.cpp */,
 				1C81B9580E97330800266E07 /* InspectorClient.h */,
 				1C81B9570E97330800266E07 /* InspectorController.cpp */,
@@ -27756,6 +27762,7 @@
 				1C81B95A0E97330800266E07 /* InspectorController.h in Headers */,
 				82AB1744124B99EC00C5069D /* InspectorCSSAgent.h in Headers */,
 				4A9CC82116BF9BB400EC645A /* InspectorCSSOMWrappers.h in Headers */,
+				6A4B6D6519D22519006F11D3 /* InspectorCanvasAgent.h in Headers */,
 				7AB0B1C11211A62200A76940 /* InspectorDatabaseAgent.h in Headers */,
 				41F062140F5F192600A07EAC /* InspectorDatabaseResource.h in Headers */,
 				7A24587C1021EAF4000A00AA /* InspectorDOMAgent.h in Headers */,
@@ -31735,6 +31742,7 @@
 				93309DEF099E64920056E581 /* InsertParagraphSeparatorCommand.cpp in Sources */,
 				93309DF1099E64920056E581 /* InsertTextCommand.cpp in Sources */,
 				B885E8D411E06DD2009FFBF4 /* InspectorApplicationCacheAgent.cpp in Sources */,
+				6A32D7CE1A16D8C000412F0B /* InspectorCanvasAgent.cpp in Sources */,
 				7A1F2B52126C61B20006A7E6 /* InspectorClient.cpp in Sources */,
 				1C81B95B0E97330800266E07 /* InspectorController.cpp in Sources */,
 				82AB1743124B99EC00C5069D /* InspectorCSSAgent.cpp in Sources */,

Modified: trunk/Source/WebCore/dom/Document.cpp (218439 => 218440)


--- trunk/Source/WebCore/dom/Document.cpp	2017-06-17 02:39:20 UTC (rev 218439)
+++ trunk/Source/WebCore/dom/Document.cpp	2017-06-17 02:58:24 UTC (rev 218440)
@@ -5460,8 +5460,10 @@
 HTMLCanvasElement* Document::getCSSCanvasElement(const String& name)
 {
     RefPtr<HTMLCanvasElement>& element = m_cssCanvasElements.add(name, nullptr).iterator->value;
-    if (!element)
+    if (!element) {
         element = HTMLCanvasElement::create(*this);
+        InspectorInstrumentation::didCreateCSSCanvas(*element, name);
+    }
     return element.get();
 }
 

Modified: trunk/Source/WebCore/html/HTMLCanvasElement.cpp (218439 => 218440)


--- trunk/Source/WebCore/html/HTMLCanvasElement.cpp	2017-06-17 02:39:20 UTC (rev 218439)
+++ trunk/Source/WebCore/html/HTMLCanvasElement.cpp	2017-06-17 02:58:24 UTC (rev 218440)
@@ -43,6 +43,7 @@
 #include "HTMLNames.h"
 #include "HTMLParserIdioms.h"
 #include "ImageData.h"
+#include "InspectorInstrumentation.h"
 #include "MIMETypeRegistry.h"
 #include "RenderHTMLCanvas.h"
 #include "RuntimeEnabledFeatures.h"
@@ -247,6 +248,8 @@
         downcast<CanvasRenderingContext2D>(*m_context).setUsesDisplayListDrawing(m_usesDisplayListDrawing);
         downcast<CanvasRenderingContext2D>(*m_context).setTracksDisplayListReplay(m_tracksDisplayListReplay);
 
+        InspectorInstrumentation::didCreateCanvasRenderingContext(*this);
+
 #if USE(IOSURFACE_CANVAS_BACKING_STORE) || ENABLE(ACCELERATED_2D_CANVAS)
         // Need to make sure a RenderLayer and compositing layer get created for the Canvas
         invalidateStyleAndLayerComposition();
@@ -302,6 +305,8 @@
         if (m_context) {
             // Need to make sure a RenderLayer and compositing layer get created for the Canvas
             invalidateStyleAndLayerComposition();
+
+            InspectorInstrumentation::didCreateCanvasRenderingContext(*this);
         }
     }
 

Modified: trunk/Source/WebCore/inspector/InspectorAllInOne.cpp (218439 => 218440)


--- trunk/Source/WebCore/inspector/InspectorAllInOne.cpp	2017-06-17 02:39:20 UTC (rev 218439)
+++ trunk/Source/WebCore/inspector/InspectorAllInOne.cpp	2017-06-17 02:58:24 UTC (rev 218440)
@@ -31,6 +31,7 @@
 #include "DOMPatchSupport.cpp"
 #include "InspectorApplicationCacheAgent.cpp"
 #include "InspectorCSSAgent.cpp"
+#include "InspectorCanvasAgent.cpp"
 #include "InspectorClient.cpp"
 #include "InspectorController.cpp"
 #include "InspectorDOMAgent.cpp"

Added: trunk/Source/WebCore/inspector/InspectorCanvasAgent.cpp (0 => 218440)


--- trunk/Source/WebCore/inspector/InspectorCanvasAgent.cpp	                        (rev 0)
+++ trunk/Source/WebCore/inspector/InspectorCanvasAgent.cpp	2017-06-17 02:58:24 UTC (rev 218440)
@@ -0,0 +1,236 @@
+/*
+ * Copyright (C) 2017 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "InspectorCanvasAgent.h"
+
+#include "CanvasRenderingContext.h"
+#include "Document.h"
+#include "DocumentLoader.h"
+#include "Frame.h"
+#include "InspectorDOMAgent.h"
+#include "InspectorPageAgent.h"
+#include "InstrumentingAgents.h"
+#include "MainFrame.h"
+#include <inspector/IdentifiersFactory.h>
+#include <inspector/InspectorProtocolObjects.h>
+
+using namespace Inspector;
+
+namespace WebCore {
+
+InspectorCanvasAgent::InspectorCanvasAgent(WebAgentContext& context, InspectorPageAgent* pageAgent)
+    : InspectorAgentBase(ASCIILiteral("Canvas"), context)
+    , m_frontendDispatcher(std::make_unique<Inspector::CanvasFrontendDispatcher>(context.frontendRouter))
+    , m_backendDispatcher(Inspector::CanvasBackendDispatcher::create(context.backendDispatcher, this))
+    , m_pageAgent(pageAgent)
+    , m_timer(*this, &InspectorCanvasAgent::canvasDestroyedTimerFired)
+{
+}
+
+void InspectorCanvasAgent::didCreateFrontendAndBackend(Inspector::FrontendRouter*, Inspector::BackendDispatcher*)
+{
+}
+
+void InspectorCanvasAgent::willDestroyFrontendAndBackend(Inspector::DisconnectReason)
+{
+    ErrorString ignored;
+    disable(ignored);
+}
+
+void InspectorCanvasAgent::discardAgent()
+{
+    clearCanvasData();
+}
+
+void InspectorCanvasAgent::enable(ErrorString&)
+{
+    if (m_enabled)
+        return;
+
+    m_enabled = true;
+
+    for (const auto& pair : m_canvasEntries) {
+        auto* canvasElement = pair.key;
+        auto& canvasEntry = pair.value;
+        m_frontendDispatcher->canvasAdded(buildObjectForCanvas(canvasEntry, *canvasElement));
+    }
+}
+
+void InspectorCanvasAgent::disable(ErrorString&)
+{
+    if (!m_enabled)
+        return;
+
+    if (m_timer.isActive())
+        m_timer.stop();
+
+    m_removedCanvasIdentifiers.clear();
+
+    m_enabled = false;
+}
+
+void InspectorCanvasAgent::frameNavigated(Frame& frame)
+{
+    if (frame.isMainFrame()) {
+        clearCanvasData();
+        return;
+    }
+
+    Vector<HTMLCanvasElement*> canvasesForFrame;
+    for (const auto& canvasElement : m_canvasEntries.keys()) {
+        if (canvasElement->document().frame() == &frame)
+            canvasesForFrame.append(canvasElement);
+    }
+
+    if (!m_enabled) {
+        m_canvasEntries.clear();
+        return;
+    }
+
+    for (auto* canvasElement : canvasesForFrame) {
+        auto canvasEntry = m_canvasEntries.take(canvasElement);
+        m_frontendDispatcher->canvasRemoved(canvasEntry.identifier);
+    }
+}
+
+void InspectorCanvasAgent::didCreateCSSCanvas(HTMLCanvasElement& canvasElement, const String& name)
+{
+    ASSERT(!m_canvasToCSSCanvasId.contains(&canvasElement));
+    ASSERT(!m_canvasEntries.contains(&canvasElement));
+
+    m_canvasToCSSCanvasId.set(&canvasElement, name);
+}
+
+void InspectorCanvasAgent::didCreateCanvasRenderingContext(HTMLCanvasElement& canvasElement)
+{
+    if (m_canvasEntries.contains(&canvasElement)) {
+        ASSERT_NOT_REACHED();
+        return;
+    }
+
+    CanvasEntry newCanvasEntry("canvas:" + IdentifiersFactory::createIdentifier(), &canvasElement);
+    if (m_canvasToCSSCanvasId.contains(&canvasElement))
+        newCanvasEntry.cssCanvasName = m_canvasToCSSCanvasId.take(&canvasElement);
+
+    m_canvasEntries.set(&canvasElement, newCanvasEntry);
+    canvasElement.addObserver(*this);
+
+    if (!m_enabled)
+        return;
+
+    m_frontendDispatcher->canvasAdded(buildObjectForCanvas(newCanvasEntry, canvasElement));
+}
+
+void InspectorCanvasAgent::canvasDestroyed(HTMLCanvasElement& canvasElement)
+{
+    auto it = m_canvasEntries.find(&canvasElement);
+    if (it == m_canvasEntries.end())
+        return;
+
+    String canvasIdentifier = it->value.identifier;
+    m_canvasEntries.remove(it);
+
+    if (!m_enabled)
+        return;
+
+    // WebCore::CanvasObserver::canvasDestroyed is called in response to the GC destroying the HTMLCanvasElement.
+    // Due to the single-process model used in WebKit1, the event must be dispatched from a timer to prevent
+    // the frontend from making JS allocations while the GC is still active.
+    m_removedCanvasIdentifiers.append(canvasIdentifier);
+
+    if (!m_timer.isActive())
+        m_timer.startOneShot(0_s);
+}
+
+void InspectorCanvasAgent::canvasDestroyedTimerFired()
+{
+    if (!m_removedCanvasIdentifiers.size())
+        return;
+
+    for (const auto& identifier : m_removedCanvasIdentifiers)
+        m_frontendDispatcher->canvasRemoved(identifier);
+
+    m_removedCanvasIdentifiers.clear();
+}
+
+void InspectorCanvasAgent::clearCanvasData()
+{
+    for (auto* canvasElement : m_canvasEntries.keys())
+        canvasElement->removeObserver(*this);
+
+    m_canvasEntries.clear();
+    m_canvasToCSSCanvasId.clear();
+    m_removedCanvasIdentifiers.clear();
+
+    if (m_timer.isActive())
+        m_timer.stop();
+}
+
+InspectorCanvasAgent::CanvasEntry* InspectorCanvasAgent::getCanvasEntry(HTMLCanvasElement& canvasElement)
+{
+    auto findResult = m_canvasEntries.find(&canvasElement);
+    if (findResult != m_canvasEntries.end())
+        return &findResult->value;
+
+    return nullptr;
+}
+
+InspectorCanvasAgent::CanvasEntry* InspectorCanvasAgent::getCanvasEntry(const String& canvasIdentifier)
+{
+    for (auto& canvasEntry : m_canvasEntries.values()) {
+        if (canvasEntry.identifier == canvasIdentifier)
+            return &canvasEntry;
+    }
+
+    return nullptr;
+}
+
+Ref<Inspector::Protocol::Canvas::Canvas> InspectorCanvasAgent::buildObjectForCanvas(const CanvasEntry& canvasEntry, HTMLCanvasElement& canvasElement)
+{
+    Frame* frame = canvasElement.document().frame();
+    CanvasRenderingContext* context = canvasElement.renderingContext();
+
+    Inspector::Protocol::Canvas::ContextType contextType;
+    if (context->is2d())
+        contextType = Inspector::Protocol::Canvas::ContextType::Canvas2D;
+    else {
+        ASSERT(context->isWebGL());
+        contextType = Inspector::Protocol::Canvas::ContextType::WebGL;
+    }
+
+    auto canvas = Inspector::Protocol::Canvas::Canvas::create()
+        .setCanvasId(canvasEntry.identifier)
+        .setFrameId(m_pageAgent->frameId(frame))
+        .setContextType(contextType)
+        .release();
+
+    if (!canvasEntry.cssCanvasName.isEmpty())
+        canvas->setCssCanvasName(canvasEntry.cssCanvasName);
+
+    return canvas;
+}
+
+} // namespace WebCore

Added: trunk/Source/WebCore/inspector/InspectorCanvasAgent.h (0 => 218440)


--- trunk/Source/WebCore/inspector/InspectorCanvasAgent.h	                        (rev 0)
+++ trunk/Source/WebCore/inspector/InspectorCanvasAgent.h	2017-06-17 02:58:24 UTC (rev 218440)
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2017 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include "HTMLCanvasElement.h"
+#include "InspectorWebAgentBase.h"
+#include "Timer.h"
+#include <inspector/InspectorBackendDispatchers.h>
+#include <inspector/InspectorFrontendDispatchers.h>
+#include <wtf/HashMap.h>
+#include <wtf/HashSet.h>
+#include <wtf/RefPtr.h>
+#include <wtf/Vector.h>
+#include <wtf/text/WTFString.h>
+
+namespace WebCore {
+
+class DocumentLoader;
+class InspectorPageAgent;
+class WebGLRenderingContextBase;
+
+typedef String ErrorString;
+
+class InspectorCanvasAgent final : public InspectorAgentBase, public CanvasObserver, public Inspector::CanvasBackendDispatcherHandler {
+    WTF_MAKE_NONCOPYABLE(InspectorCanvasAgent);
+    WTF_MAKE_FAST_ALLOCATED;
+public:
+    InspectorCanvasAgent(WebAgentContext&, InspectorPageAgent*);
+    virtual ~InspectorCanvasAgent() { }
+
+    void didCreateFrontendAndBackend(Inspector::FrontendRouter*, Inspector::BackendDispatcher*) override;
+    void willDestroyFrontendAndBackend(Inspector::DisconnectReason) override;
+    void discardAgent() override;
+
+    // CanvasBackendDispatcherHandler
+    void enable(ErrorString&) override;
+    void disable(ErrorString&) override;
+
+    // InspectorInstrumentation
+    void frameNavigated(Frame&);
+    void didCreateCSSCanvas(HTMLCanvasElement&, const String&);
+    void didCreateCanvasRenderingContext(HTMLCanvasElement&);
+
+    // CanvasObserver
+    void canvasChanged(HTMLCanvasElement&, const FloatRect&) override { }
+    void canvasResized(HTMLCanvasElement&) override { }
+    void canvasDestroyed(HTMLCanvasElement&) override;
+
+private:
+    struct CanvasEntry {
+        String identifier;
+        String cssCanvasName;
+        HTMLCanvasElement* element = { nullptr };
+
+        CanvasEntry() { }
+
+        CanvasEntry(const String& identifier, HTMLCanvasElement* canvasElement)
+            : identifier(identifier)
+            , element(canvasElement)
+        {
+        }
+    };
+
+    void canvasDestroyedTimerFired();
+    void clearCanvasData();
+    CanvasEntry* getCanvasEntry(HTMLCanvasElement&);
+    CanvasEntry* getCanvasEntry(const String&);
+    Ref<Inspector::Protocol::Canvas::Canvas> buildObjectForCanvas(const CanvasEntry&, HTMLCanvasElement&);
+
+    std::unique_ptr<Inspector::CanvasFrontendDispatcher> m_frontendDispatcher;
+    RefPtr<Inspector::CanvasBackendDispatcher> m_backendDispatcher;
+    InspectorPageAgent* m_pageAgent;
+
+    HashMap<HTMLCanvasElement*, CanvasEntry> m_canvasEntries;
+    HashMap<HTMLCanvasElement*, String> m_canvasToCSSCanvasId;
+    Vector<String> m_removedCanvasIdentifiers;
+    Timer m_timer;
+    bool m_enabled { false };
+};
+
+} // namespace WebCore

Modified: trunk/Source/WebCore/inspector/InspectorController.cpp (218439 => 218440)


--- trunk/Source/WebCore/inspector/InspectorController.cpp	2017-06-17 02:39:20 UTC (rev 218439)
+++ trunk/Source/WebCore/inspector/InspectorController.cpp	2017-06-17 02:58:24 UTC (rev 218440)
@@ -38,6 +38,7 @@
 #include "GraphicsContext.h"
 #include "InspectorApplicationCacheAgent.h"
 #include "InspectorCSSAgent.h"
+#include "InspectorCanvasAgent.h"
 #include "InspectorClient.h"
 #include "InspectorDOMAgent.h"
 #include "InspectorDOMDebuggerAgent.h"
@@ -183,6 +184,10 @@
     m_agents.append(std::make_unique<InspectorLayerTreeAgent>(pageContext));
     m_agents.append(std::make_unique<InspectorWorkerAgent>(pageContext));
 
+    auto canvasAgentPtr = std::make_unique<InspectorCanvasAgent>(pageContext, pageAgent);
+    m_instrumentingAgents->setInspectorCanvasAgent(canvasAgentPtr.get());
+    m_agents.append(WTFMove(canvasAgentPtr));
+
     ASSERT(m_injectedScriptManager->commandLineAPIHost());
     if (CommandLineAPIHost* commandLineAPIHost = m_injectedScriptManager->commandLineAPIHost()) {
         commandLineAPIHost->init(m_inspectorAgent

Modified: trunk/Source/WebCore/inspector/InspectorInstrumentation.cpp (218439 => 218440)


--- trunk/Source/WebCore/inspector/InspectorInstrumentation.cpp	2017-06-17 02:39:20 UTC (rev 218439)
+++ trunk/Source/WebCore/inspector/InspectorInstrumentation.cpp	2017-06-17 02:58:24 UTC (rev 218440)
@@ -40,6 +40,7 @@
 #include "EventDispatcher.h"
 #include "InspectorApplicationCacheAgent.h"
 #include "InspectorCSSAgent.h"
+#include "InspectorCanvasAgent.h"
 #include "InspectorDOMAgent.h"
 #include "InspectorDOMDebuggerAgent.h"
 #include "InspectorDOMStorageAgent.h"
@@ -61,6 +62,7 @@
 #include "RenderView.h"
 #include "ScriptController.h"
 #include "WebConsoleAgent.h"
+#include "WebGLRenderingContextBase.h"
 #include "WebSocketFrame.h"
 #include <inspector/ConsoleMessage.h>
 #include <inspector/ScriptArguments.h>
@@ -748,6 +750,9 @@
             pageHeapAgent->mainFrameNavigated();
     }
 
+    if (InspectorCanvasAgent* canvasAgent = instrumentingAgents.inspectorCanvasAgent())
+        canvasAgent->frameNavigated(frame);
+
     if (InspectorDOMAgent* domAgent = instrumentingAgents.inspectorDOMAgent())
         domAgent->didCommitLoad(frame.document());
 
@@ -988,6 +993,18 @@
 }
 #endif
 
+void InspectorInstrumentation::didCreateCSSCanvasImpl(InstrumentingAgents* instrumentingAgents, HTMLCanvasElement& canvasElement, const String& name)
+{
+    if (InspectorCanvasAgent* canvasAgent = instrumentingAgents->inspectorCanvasAgent())
+        canvasAgent->didCreateCSSCanvas(canvasElement, name);
+}
+
+void InspectorInstrumentation::didCreateCanvasRenderingContextImpl(InstrumentingAgents* instrumentingAgents, HTMLCanvasElement& canvasElement)
+{
+    if (InspectorCanvasAgent* canvasAgent = instrumentingAgents->inspectorCanvasAgent())
+        canvasAgent->didCreateCanvasRenderingContext(canvasElement);
+}
+
 #if ENABLE(WEB_REPLAY)
 void InspectorInstrumentation::sessionCreatedImpl(InstrumentingAgents& instrumentingAgents, RefPtr<ReplaySession>&& session)
 {

Modified: trunk/Source/WebCore/inspector/InspectorInstrumentation.h (218439 => 218440)


--- trunk/Source/WebCore/inspector/InspectorInstrumentation.h	2017-06-17 02:39:20 UTC (rev 218439)
+++ trunk/Source/WebCore/inspector/InspectorInstrumentation.h	2017-06-17 02:58:24 UTC (rev 218440)
@@ -36,6 +36,7 @@
 #include "Element.h"
 #include "FormData.h"
 #include "Frame.h"
+#include "HTMLCanvasElement.h"
 #include "HitTestResult.h"
 #include "InspectorController.h"
 #include "InspectorInstrumentationCookie.h"
@@ -81,6 +82,7 @@
 class SecurityOrigin;
 class ShadowRoot;
 class URL;
+class WebGLRenderingContextBase;
 class WebKitNamedFlow;
 class WorkerInspectorProxy;
 
@@ -243,6 +245,9 @@
     static void didHandleMemoryPressure(Page&, Critical);
 #endif
 
+    static void didCreateCSSCanvas(HTMLCanvasElement&, const String&);
+    static void didCreateCanvasRenderingContext(HTMLCanvasElement&);
+
     static void networkStateChanged(Page&);
     static void updateApplicationCacheStatus(Frame*);
 
@@ -415,6 +420,9 @@
     static void networkStateChangedImpl(InstrumentingAgents&);
     static void updateApplicationCacheStatusImpl(InstrumentingAgents&, Frame&);
 
+    static void didCreateCSSCanvasImpl(InstrumentingAgents*, HTMLCanvasElement&, const String&);
+    static void didCreateCanvasRenderingContextImpl(InstrumentingAgents*, HTMLCanvasElement&);
+
     static void layerTreeDidChangeImpl(InstrumentingAgents&);
     static void renderLayerDestroyedImpl(InstrumentingAgents&, const RenderLayer&);
 
@@ -1173,6 +1181,18 @@
 }
 #endif
 
+inline void InspectorInstrumentation::didCreateCSSCanvas(HTMLCanvasElement& canvasElement, const String& name)
+{
+    if (InstrumentingAgents* instrumentingAgents = instrumentingAgentsForDocument(&canvasElement.document()))
+        didCreateCSSCanvasImpl(instrumentingAgents, canvasElement, name);
+}
+    
+inline void InspectorInstrumentation::didCreateCanvasRenderingContext(HTMLCanvasElement& canvasElement)
+{
+    if (InstrumentingAgents* instrumentingAgents = instrumentingAgentsForDocument(&canvasElement.document()))
+        didCreateCanvasRenderingContextImpl(instrumentingAgents, canvasElement);
+}
+
 inline void InspectorInstrumentation::networkStateChanged(Page& page)
 {
     FAST_RETURN_IF_NO_FRONTENDS(void());

Modified: trunk/Source/WebCore/inspector/InstrumentingAgents.cpp (218439 => 218440)


--- trunk/Source/WebCore/inspector/InstrumentingAgents.cpp	2017-06-17 02:39:20 UTC (rev 218439)
+++ trunk/Source/WebCore/inspector/InstrumentingAgents.cpp	2017-06-17 02:58:24 UTC (rev 218440)
@@ -67,6 +67,7 @@
     m_pageDebuggerAgent = nullptr;
     m_pageHeapAgent = nullptr;
     m_inspectorDOMDebuggerAgent = nullptr;
+    m_inspectorCanvasAgent = nullptr;
 }
 
 } // namespace WebCore

Modified: trunk/Source/WebCore/inspector/InstrumentingAgents.h (218439 => 218440)


--- trunk/Source/WebCore/inspector/InstrumentingAgents.h	2017-06-17 02:39:20 UTC (rev 218439)
+++ trunk/Source/WebCore/inspector/InstrumentingAgents.h	2017-06-17 02:58:24 UTC (rev 218440)
@@ -44,6 +44,7 @@
 namespace WebCore {
 
 class InspectorApplicationCacheAgent;
+class InspectorCanvasAgent;
 class InspectorCSSAgent;
 class InspectorDOMAgent;
 class InspectorDOMDebuggerAgent;
@@ -83,6 +84,9 @@
     InspectorPageAgent* inspectorPageAgent() const { return m_inspectorPageAgent; }
     void setInspectorPageAgent(InspectorPageAgent* agent) { m_inspectorPageAgent = agent; }
 
+    InspectorCanvasAgent* inspectorCanvasAgent() const { return m_inspectorCanvasAgent; }
+    void setInspectorCanvasAgent(InspectorCanvasAgent* agent) { m_inspectorCanvasAgent = agent; }
+
     InspectorCSSAgent* inspectorCSSAgent() const { return m_inspectorCSSAgent; }
     void setInspectorCSSAgent(InspectorCSSAgent* agent) { m_inspectorCSSAgent = agent; }
 
@@ -170,6 +174,7 @@
     PageDebuggerAgent* m_pageDebuggerAgent { nullptr };
     PageHeapAgent* m_pageHeapAgent { nullptr };
     InspectorDOMDebuggerAgent* m_inspectorDOMDebuggerAgent { nullptr };
+    InspectorCanvasAgent* m_inspectorCanvasAgent { nullptr };
 };
 
 } // namespace WebCore

Modified: trunk/Source/WebInspectorUI/ChangeLog (218439 => 218440)


--- trunk/Source/WebInspectorUI/ChangeLog	2017-06-17 02:39:20 UTC (rev 218439)
+++ trunk/Source/WebInspectorUI/ChangeLog	2017-06-17 02:58:24 UTC (rev 218440)
@@ -1,3 +1,55 @@
+2017-06-16  Matt Baker  <mattba...@apple.com>
+
+        Web Inspector: Instrument 2D/WebGL canvas contexts in the backend
+        https://bugs.webkit.org/show_bug.cgi?id=172623
+        <rdar://problem/32415986>
+
+        Reviewed by Devin Rousso and Joseph Pecoraro.
+
+        * UserInterface/Base/Main.js:
+        (WebInspector.loaded):
+
+        * UserInterface/Controllers/CanvasManager.js: Added.
+        New frontend manager for the Canvas domain.
+        (WebInspector.CanvasManager):
+        (WebInspector.CanvasManager.prototype.get canvases):
+        (WebInspector.CanvasManager.prototype.canvasAdded):
+        (WebInspector.CanvasManager.prototype.canvasRemoved):
+        (WebInspector.CanvasManager.prototype._mainResourceDidChange):
+
+        * UserInterface/Main.html:
+        New files.
+
+        * UserInterface/Models/Canvas.js: Added.
+        (WebInspector.Canvas):
+        (WebInspector.Canvas.fromPayload):
+        (WebInspector.Canvas.displayNameForContextType):
+        Get displayable text "2D" or "WebGL" based on context type.
+        (WebInspector.Canvas.resetUniqueDisplayNameNumbers):
+        Called by CanvasManager when canvases are cleared.
+        (WebInspector.Canvas.prototype.get identifier):
+        (WebInspector.Canvas.prototype.get contextType):
+        (WebInspector.Canvas.prototype.get frame):
+        (WebInspector.Canvas.prototype.get cssCanvasName):
+        For CSS canvases, the identifier passed to getCSSCanvasContext.
+        (WebInspector.Canvas.prototype.get displayName):
+        Get displayable canvas name. The name depends on how the canvas was
+        created, and the information available:
+          - getCSSCanvasContext: "CSS Canvas <identifier>"
+          - getContext: "Canvas #<DOM id attribute value>"
+          - Otherwise: "Canvas 1", "Canvas 2", ...
+
+        (WebInspector.Canvas.saveIdentityToCookie):
+
+        * UserInterface/Protocol/CanvasObserver.js: Added.
+        (WebInspector.CanvasObserver.prototype.canvasAdded):
+        (WebInspector.CanvasObserver.prototype.canvasRemoved):
+        (WebInspector.CanvasObserver):
+
+        * UserInterface/Test.html:
+        * UserInterface/Test/Test.js:
+        (WebInspector.loaded):
+
 2017-06-16  Matt Lewis  <jlew...@apple.com>
 
         Unreviewed, rolling out r218376.

Modified: trunk/Source/WebInspectorUI/UserInterface/Base/Main.js (218439 => 218440)


--- trunk/Source/WebInspectorUI/UserInterface/Base/Main.js	2017-06-17 02:39:20 UTC (rev 218439)
+++ trunk/Source/WebInspectorUI/UserInterface/Base/Main.js	2017-06-17 02:58:24 UTC (rev 218440)
@@ -95,6 +95,8 @@
         InspectorBackend.registerWorkerDispatcher(new WebInspector.WorkerObserver);
     if (InspectorBackend.registerReplayDispatcher)
         InspectorBackend.registerReplayDispatcher(new WebInspector.ReplayObserver);
+    if (InspectorBackend.registerCanvasDispatcher)
+        InspectorBackend.registerCanvasDispatcher(new WebInspector.CanvasObserver);
 
     // Main backend target.
     WebInspector.mainTarget = new WebInspector.MainTarget;
@@ -136,6 +138,7 @@
     this.workerManager = new WebInspector.WorkerManager;
     this.replayManager = new WebInspector.ReplayManager;
     this.domDebuggerManager = new WebInspector.DOMDebuggerManager;
+    this.canvasManager = new WebInspector.CanvasManager;
 
     // Enable the Console Agent after creating the singleton managers.
     ConsoleAgent.enable();

Added: trunk/Source/WebInspectorUI/UserInterface/Controllers/CanvasManager.js (0 => 218440)


--- trunk/Source/WebInspectorUI/UserInterface/Controllers/CanvasManager.js	                        (rev 0)
+++ trunk/Source/WebInspectorUI/UserInterface/Controllers/CanvasManager.js	2017-06-17 02:58:24 UTC (rev 218440)
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2017 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+WebInspector.CanvasManager = class CanvasManager extends WebInspector.Object
+{
+    constructor()
+    {
+        super();
+
+        WebInspector.Frame.addEventListener(WebInspector.Frame.Event.MainResourceDidChange, this._mainResourceDidChange, this);
+
+        this._canvasIdentifierMap = new Map;
+
+        if (window.CanvasAgent)
+            CanvasAgent.enable();
+    }
+
+    // Public
+
+    get canvases()
+    {
+        return [...this._canvasIdentifierMap.values()];
+    }
+
+    canvasAdded(canvasPayload)
+    {
+        // Called from WebInspector.CanvasObserver.
+
+        console.assert(!this._canvasIdentifierMap.has(canvasPayload.canvasId), `Canvas already exists with id ${canvasPayload.canvasId}.`);
+
+        let canvas = WebInspector.Canvas.fromPayload(canvasPayload);
+        this._canvasIdentifierMap.set(canvas.identifier, canvas);
+
+        this.dispatchEventToListeners(WebInspector.CanvasManager.Event.CanvasWasAdded, {canvas});
+    }
+
+    canvasRemoved(canvasIdentifier)
+    {
+        // Called from WebInspector.CanvasObserver.
+
+        let canvas = this._canvasIdentifierMap.take(canvasIdentifier);
+        console.assert(canvas);
+        if (!canvas)
+            return;
+
+        this.dispatchEventToListeners(WebInspector.CanvasManager.Event.CanvasWasRemoved, {canvas});
+    }
+
+    // Private
+
+    _mainResourceDidChange(event)
+    {
+        console.assert(event.target instanceof WebInspector.Frame);
+        if (!event.target.isMainFrame())
+            return;
+
+        WebInspector.Canvas.resetUniqueDisplayNameNumbers();
+
+        if (this._canvasIdentifierMap.size) {
+            this._canvasIdentifierMap.clear();
+            this.dispatchEventToListeners(WebInspector.CanvasManager.Event.Cleared);
+        }
+    }
+};
+
+WebInspector.CanvasManager.Event = {
+    Cleared: "canvas-manager-cleared",
+    CanvasWasAdded: "canvas-manager-canvas-was-added",
+    CanvasWasRemoved: "canvas-manager-canvas-was-removed",
+};

Modified: trunk/Source/WebInspectorUI/UserInterface/Main.html (218439 => 218440)


--- trunk/Source/WebInspectorUI/UserInterface/Main.html	2017-06-17 02:39:20 UTC (rev 218439)
+++ trunk/Source/WebInspectorUI/UserInterface/Main.html	2017-06-17 02:58:24 UTC (rev 218440)
@@ -274,6 +274,7 @@
 
     <script src=""
     <script src=""
+    <script src=""
     <script src=""
     <script src=""
     <script src=""
@@ -317,6 +318,7 @@
     <script src=""
     <script src=""
     <script src=""
+    <script src=""
     <script src=""
     <script src=""
     <script src=""
@@ -734,6 +736,7 @@
     <script src=""
     <script src=""
     <script src=""
+    <script src=""
     <script src=""
     <script src=""
     <script src=""

Added: trunk/Source/WebInspectorUI/UserInterface/Models/Canvas.js (0 => 218440)


--- trunk/Source/WebInspectorUI/UserInterface/Models/Canvas.js	                        (rev 0)
+++ trunk/Source/WebInspectorUI/UserInterface/Models/Canvas.js	2017-06-17 02:58:24 UTC (rev 218440)
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 2017 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+WebInspector.Canvas = class Canvas extends WebInspector.Object
+{
+    constructor(identifier, contextType, frame, cssCanvasName)
+    {
+        super();
+
+        console.assert(identifier);
+        console.assert(contextType);
+        console.assert(frame instanceof WebInspector.Frame);
+
+        this._identifier = identifier;
+        this._contextType = contextType;
+        this._frame = frame;
+        this._cssCanvasName = cssCanvasName || "";
+    }
+
+    // Static
+
+    static fromPayload(payload)
+    {
+        let contextType = null;
+        switch (payload.contextType) {
+        case CanvasAgent.ContextType.Canvas2D:
+            contextType = WebInspector.Canvas.ContextType.Canvas2D;
+            break;
+        case CanvasAgent.ContextType.WebGL:
+            contextType = WebInspector.Canvas.ContextType.WebGL;
+            break;
+        default:
+            console.error("Invalid canvas context type", payload.contextType);
+        }
+
+        let frame = WebInspector.frameResourceManager.frameForIdentifier(payload.frameId);
+        return new WebInspector.Canvas(payload.canvasId, contextType, frame, payload.cssCanvasName);
+    }
+
+    static displayNameForContextType(contextType)
+    {
+        switch (contextType) {
+        case WebInspector.Canvas.ContextType.Canvas2D:
+            return WebInspector.UIString("2D");
+        case WebInspector.Canvas.ContextType.WebGL:
+            return WebInspector.UIString("WebGL");
+        default:
+            console.error("Invalid canvas context type", contextType);
+        }
+    }
+
+    static resetUniqueDisplayNameNumbers()
+    {
+        WebInspector.Canvas._nextUniqueDisplayNameNumber = 1;
+    }
+
+    // Public
+
+    get identifier() { return this._identifier; }
+    get contextType() { return this._contextType; }
+    get frame() { return this._frame; }
+    get cssCanvasName() { return this._cssCanvasName; }
+
+    get displayName()
+    {
+        if (this.cssCanvasName) {
+            console.assert(!this._node, "Unexpected DOM node for CSS canvas.");
+            return WebInspector.UIString("CSS canvas ā€œ%sā€").format(this._cssCanvasName);
+        }
+
+        // TODO:if the DOM node for the canvas is known and an id attribute value
+        // exists, return the following: WebInspector.UIString("Canvas #%s").format(id);
+
+        if (!this._uniqueDisplayNameNumber)
+            this._uniqueDisplayNameNumber = this.constructor._nextUniqueDisplayNameNumber++;
+        return WebInspector.UIString("Canvas %d").format(this._uniqueDisplayNameNumber);
+    }
+
+    saveIdentityToCookie(cookie)
+    {
+        cookie[WebInspector.Canvas.FrameURLCookieKey] = this._frame.url.hash;
+        if (this._cssCanvasName)
+            cookie[WebInspector.Canvas.CSSCanvasNameCookieKey] = this._cssCanvasName;
+
+        // TODO: if the canvas has an associated DOM node, and the node path to the cookie.
+    }
+};
+
+WebInspector.Canvas._nextUniqueDisplayNameNumber = 1;
+
+WebInspector.Canvas.FrameURLCookieKey = "canvas-frame-url";
+WebInspector.Canvas.CSSCanvasNameCookieKey = "canvas-css-canvas-name";
+
+WebInspector.Canvas.ContextType = {
+    Canvas2D: Symbol("canvas-2d"),
+    WebGL: Symbol("webgl"),
+};

Added: trunk/Source/WebInspectorUI/UserInterface/Protocol/CanvasObserver.js (0 => 218440)


--- trunk/Source/WebInspectorUI/UserInterface/Protocol/CanvasObserver.js	                        (rev 0)
+++ trunk/Source/WebInspectorUI/UserInterface/Protocol/CanvasObserver.js	2017-06-17 02:58:24 UTC (rev 218440)
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2017 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+WebInspector.CanvasObserver = class CanvasObserver
+{
+    // Events defined by the "Canvas" domain.
+
+    canvasAdded(canvas)
+    {
+        WebInspector.canvasManager.canvasAdded(canvas);
+    }
+
+    canvasRemoved(canvasId)
+    {
+        WebInspector.canvasManager.canvasRemoved(canvasId);
+    }
+};

Modified: trunk/Source/WebInspectorUI/UserInterface/Test/Test.js (218439 => 218440)


--- trunk/Source/WebInspectorUI/UserInterface/Test/Test.js	2017-06-17 02:39:20 UTC (rev 218439)
+++ trunk/Source/WebInspectorUI/UserInterface/Test/Test.js	2017-06-17 02:58:24 UTC (rev 218440)
@@ -49,6 +49,7 @@
     InspectorBackend.registerWorkerDispatcher(new WebInspector.WorkerObserver);
     if (InspectorBackend.registerReplayDispatcher)
         InspectorBackend.registerReplayDispatcher(new WebInspector.ReplayObserver);
+    InspectorBackend.registerCanvasDispatcher(new WebInspector.CanvasObserver);
 
     WebInspector.mainTarget = new WebInspector.MainTarget;
 
@@ -69,6 +70,7 @@
     this.workerManager = new WebInspector.WorkerManager;
     this.replayManager = new WebInspector.ReplayManager;
     this.domDebuggerManager = new WebInspector.DOMDebuggerManager;
+    this.canvasManager = new WebInspector.CanvasManager;
 
     document.addEventListener("DOMContentLoaded", this.contentLoaded);
 

Modified: trunk/Source/WebInspectorUI/UserInterface/Test.html (218439 => 218440)


--- trunk/Source/WebInspectorUI/UserInterface/Test.html	2017-06-17 02:39:20 UTC (rev 218439)
+++ trunk/Source/WebInspectorUI/UserInterface/Test.html	2017-06-17 02:58:24 UTC (rev 218440)
@@ -71,6 +71,7 @@
 
     <script src=""
     <script src=""
+    <script src=""
     <script src=""
     <script src=""
     <script src=""
@@ -105,6 +106,7 @@
     <script src=""
     <script src=""
     <script src=""
+    <script src=""
     <script src=""
     <script src=""
     <script src=""
@@ -185,6 +187,7 @@
 
     <script src=""
     <script src=""
+    <script src=""
     <script src=""
     <script src=""
     <script src=""
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to