Web Inspector: add 2D/WebGL canvas instrumentation infrastructure
authorcommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 31 Mar 2015 17:23:12 +0000 (17:23 +0000)
committercommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 31 Mar 2015 17:23:12 +0000 (17:23 +0000)
https://bugs.webkit.org/show_bug.cgi?id=137278

Patch by Matt Baker <mattbaker@apple.com> on 2015-03-31
Reviewed by Timothy Hatcher.

Source/JavaScriptCore:

Added Canvas protocol which defines types used by InspectorCanvasAgent.

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

* inspector/scripts/codegen/generator.py:
(Generator.stylized_name_for_enum_value):
Added special handling for 2D (always uppercase) and WebGL (rename mapping) enum strings.

Source/WebCore:

Added backend agent for canvas inspection. A canvas is instrumented once its CanvasRenderingContext has been
created. WebGLRenderingContext is instrumented to track the lifetime of shader program objects.

To instrument off-screen rendering contexts (CSS canvases and detached canvas elements), the canvas agent must
track all CanvasRenderingContexts as they are created, even in the absense of the frontend. As far as I know,
there is no practical way to identify rendering contexts belonging to a frame that are not in the DOM. In the
absence of the inspector frontend the agent does only the minimum required to track the lifetime of rendering
contexts and their resources, to avoid creating a negative performance impact.

Tests: inspector/canvas/canvas-add-remove-events.html
       inspector/canvas/canvas-context-attributes.html
       inspector/canvas/canvas-css-name.html

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

* dom/Document.cpp:
(WebCore::Document::getCSSCanvasElement):
Instrumentation for CSS canvases.

* html/HTMLCanvasElement.cpp:
(WebCore::HTMLCanvasElement::getContext):
Instrumentation for context creation.

* html/canvas/WebGLRenderingContextBase.cpp:
(WebCore::WebGLRenderingContextBase::attachShader):
(WebCore::WebGLRenderingContextBase::createProgram):
(WebCore::WebGLRenderingContextBase::deleteProgram):
(WebCore::WebGLRenderingContextBase::detachShader):
Instrumentation for programs and shaders.

* inspector/InspectorAllInOne.cpp:

* inspector/InspectorCanvasAgent.cpp: Added.
(WebCore::InspectorCanvasAgent::InspectorCanvasAgent):
(WebCore::InspectorCanvasAgent::didCreateFrontendAndBackend):
(WebCore::InspectorCanvasAgent::willDestroyFrontendAndBackend):
(WebCore::InspectorCanvasAgent::frameNavigated):
(WebCore::InspectorCanvasAgent::didCreateCSSCanvas):
(WebCore::InspectorCanvasAgent::didCreateCanvasRenderingContext):
(WebCore::InspectorCanvasAgent::didAttachShader):
(WebCore::InspectorCanvasAgent::didDetachShader):
(WebCore::InspectorCanvasAgent::didCreateProgram):
(WebCore::InspectorCanvasAgent::didDeleteProgram):
(WebCore::InspectorCanvasAgent::getCanvases):
(WebCore::InspectorCanvasAgent::canvasDestroyed):
(WebCore::InspectorCanvasAgent::canvasDestroyedTimerFired):
(WebCore::InspectorCanvasAgent::reset):
(WebCore::InspectorCanvasAgent::getCanvasEntry):
(WebCore::InspectorCanvasAgent::getProgramEntry):
(WebCore::InspectorCanvasAgent::removeShaderFromShaderMap):
(WebCore::InspectorCanvasAgent::contextTypeJson):
(WebCore::InspectorCanvasAgent::buildObjectForCanvas):
* inspector/InspectorCanvasAgent.h: Added.
New backend agent.

* inspector/InspectorController.cpp:
(WebCore::InspectorController::InspectorController):
Support for new backend agent.

* inspector/InspectorInstrumentation.cpp:
(WebCore::InspectorInstrumentation::didCommitLoadImpl):
(WebCore::InspectorInstrumentation::didCreateCSSCanvasImpl):
(WebCore::InspectorInstrumentation::didCreateCanvasRenderingContextImpl):
(WebCore::InspectorInstrumentation::didAttachShaderImpl):
(WebCore::InspectorInstrumentation::didDetachShaderImpl):
(WebCore::InspectorInstrumentation::didCreateProgramImpl):
(WebCore::InspectorInstrumentation::didDeleteProgramImpl):
(WebCore::InspectorInstrumentation::instrumentingAgentsForRenderingContext):
Plumbing for canvas instrumentation.

* inspector/InspectorInstrumentation.h:
(WebCore::InspectorInstrumentation::didCreateCSSCanvas):
(WebCore::InspectorInstrumentation::didCreateCanvasRenderingContext):
(WebCore::InspectorInstrumentation::didAttachShader):
(WebCore::InspectorInstrumentation::didDetachShader):
(WebCore::InspectorInstrumentation::didCreateProgram):
(WebCore::InspectorInstrumentation::didDeleteProgram):

* inspector/InstrumentingAgents.cpp:
(WebCore::InstrumentingAgents::InstrumentingAgents):
(WebCore::InstrumentingAgents::reset):
* inspector/InstrumentingAgents.h:
(WebCore::InstrumentingAgents::inspectorCanvasAgent):
(WebCore::InstrumentingAgents::setInspectorCanvasAgent):
Support for new backend agent.

Source/WebInspectorUI:

Added models, views, and controller classes for 2D and WebGL canvas inspection. Each canvas is shown in the
Resources navigation sidebar under its parent frame. Shader programs are displayed as child nodes of
their respective canvas. Canvases will get an associated content view and details sidebar in a later patch
(see https://bugs.webkit.org/show_bug.cgi?id=138941).

Shader programs will get an associated content view for editing shader source in a later patch (see
https://bugs.webkit.org/show_bug.cgi?id=138593). Individual shaders are not shown in the Resource navigation
sidebar, and at this time there are no plans to instrument shaders that aren't attached to a program.

* Localizations/en.lproj/localizedStrings.js:
* UserInterface/Base/Main.js:
(WebInspector.loaded):
(WebInspector.sidebarPanelForRepresentedObject):
* UserInterface/Base/Test.js:
(WebInspector.loaded):
* UserInterface/Main.html:
* UserInterface/Test.html:
Updated for new canvas/shader program types.

* UserInterface/Controllers/CanvasManager.js: Added.
(WebInspector.CanvasManager):
(WebInspector.CanvasManager.prototype.canvasesForFrame):
(WebInspector.CanvasManager.prototype.canvasAdded.set this):
(WebInspector.CanvasManager.prototype.canvasAdded):
(WebInspector.CanvasManager.prototype.canvasRemoved):
(WebInspector.CanvasManager.programDeleted.get console):
(WebInspector.CanvasManager.prototype.programCreated.get console):
(WebInspector.CanvasManager.prototype.programCreated):
(WebInspector.CanvasManager.prototype._mainResourceDidChange):
Frontend controller for canvases and their shader programs.

* UserInterface/Images/Canvas.svg: Added.
* UserInterface/Images/DocumentGL.png: Added.
* UserInterface/Images/DocumentGL@2x.png: Added.
New art for canvas and shader program tree elements.

* UserInterface/Models/Canvas.js: Added.
(WebInspector.Canvas):
(WebInspector.Canvas.prototype.set fromPayload):
(WebInspector.Canvas.displayNameForContextType):
(WebInspector.Canvas.resetUniqueDisplayNameNumbers):
(WebInspector.Canvas.prototype.get id):
(WebInspector.Canvas.prototype.get parentFrame):
(WebInspector.Canvas.prototype.get name):
(WebInspector.Canvas.prototype.get cssCanvas):
(WebInspector.Canvas.prototype.get contextType):
(WebInspector.Canvas.prototype.get contextAttributes):
(WebInspector.Canvas.prototype.get programs):
(WebInspector.Canvas.prototype.get displayName):
(WebInspector.Canvas.programForId):
(WebInspector.Canvas.get programWasCreated.set this):
(WebInspector.Canvas.prototype.get programWasCreated):
(WebInspector.Canvas.prototype.programWasDeleted):
(WebInspector.Canvas.prototype.saveIdentityToCookie):
Model for DOM or CSS canvas (2D or WebGL).

* UserInterface/Models/ShaderProgram.js: Added.
(WebInspector.ShaderProgram):
(WebInspector.ShaderProgram.prototype.get id):
(WebInspector.ShaderProgram.prototype.get canvas):
(WebInspector.ShaderProgram.prototype.get displayName):
(WebInspector.ShaderProgram.prototype.saveIdentityToCookie):
(WebInspector.ShaderProgram.prototype.updateCanvas):
* UserInterface/Models/WebGLContextAttributes.js: Added.
(WebInspector.WebGLContextAttributes):
(WebInspector.WebGLContextAttributes.fromPayload):
(WebInspector.WebGLContextAttributes.prototype.get alpha):
(WebInspector.WebGLContextAttributes.prototype.get depth):
(WebInspector.WebGLContextAttributes.prototype.get stencil):
(WebInspector.WebGLContextAttributes.prototype.get antialias):
(WebInspector.WebGLContextAttributes.prototype.get premultipliedAlpha):
(WebInspector.WebGLContextAttributes.prototype.get preserveDrawingBuffer):
Model for WebGL canvas context attributes.

* UserInterface/Protocol/CanvasObserver.js: Added.
(WebInspector.CanvasObserver.prototype.canvasAdded):
(WebInspector.CanvasObserver.prototype.canvasRemoved):
(WebInspector.CanvasObserver.prototype.programCreated):
(WebInspector.CanvasObserver.prototype.programDeleted):
(WebInspector.CanvasObserver):
Model for WebGL canvas shader program.

* UserInterface/Views/CanvasTreeElement.js: Added.
(WebInspector.CanvasTreeElement.validateRepresentedObject):
(WebInspector.CanvasTreeElement.countChildren):
(WebInspector.CanvasTreeElement):
(WebInspector.CanvasTreeElement.prototype.onexpand):
(WebInspector.CanvasTreeElement.prototype.oncollapse):
(WebInspector.CanvasTreeElement.prototype.onpopulate):
(WebInspector.CanvasTreeElement.prototype._programWasCreated):
(WebInspector.CanvasTreeElement.prototype._programWasDeleted):
Folderized tree element for canvases and their child objects (shader programs).

* UserInterface/Views/FrameTreeElement.js:
(WebInspector.FrameTreeElement.prototype.onattach):
(WebInspector.FrameTreeElement.prototype.ondetach):
(WebInspector.FrameTreeElement.prototype.onpopulate):
(WebInspector.FrameTreeElement.prototype._canvasesAvailable):
(WebInspector.FrameTreeElement.prototype._canvasWasAdded):
(WebInspector.FrameTreeElement.prototype._canvasWasRemoved):
Updated to support canvas tree elements.

* UserInterface/Views/ResourceIcons.css:
(.canvas-icon .icon):
(.shader-program-icon .icon):
Styles for new canvas and shader program icons.

* UserInterface/Views/ResourceSidebarPanel.js:
(WebInspector.ResourceSidebarPanel.prototype._treeElementSelected):
Updated for new tree element types.

* UserInterface/Views/ShaderProgramTreeElement.js: Added.
(WebInspector.ShaderProgramTreeElement):
Tree element for shader programs. Shown as children of CanvasTreeElement.

* WebInspectorUI.vcxproj/WebInspectorUI.vcxproj:
* WebInspectorUI.vcxproj/WebInspectorUI.vcxproj.filters:

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

40 files changed:
Source/JavaScriptCore/CMakeLists.txt
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/DerivedSources.make
Source/JavaScriptCore/inspector/protocol/Canvas.json [new file with mode: 0644]
Source/JavaScriptCore/inspector/scripts/codegen/generator.py
Source/WebCore/CMakeLists.txt
Source/WebCore/ChangeLog
Source/WebCore/WebCore.xcodeproj/project.pbxproj
Source/WebCore/dom/Document.cpp
Source/WebCore/html/HTMLCanvasElement.cpp
Source/WebCore/html/canvas/WebGLRenderingContextBase.cpp
Source/WebCore/inspector/InspectorAllInOne.cpp
Source/WebCore/inspector/InspectorCanvasAgent.cpp [new file with mode: 0644]
Source/WebCore/inspector/InspectorCanvasAgent.h [new file with mode: 0644]
Source/WebCore/inspector/InspectorController.cpp
Source/WebCore/inspector/InspectorInstrumentation.cpp
Source/WebCore/inspector/InspectorInstrumentation.h
Source/WebCore/inspector/InstrumentingAgents.cpp
Source/WebCore/inspector/InstrumentingAgents.h
Source/WebInspectorUI/ChangeLog
Source/WebInspectorUI/Localizations/en.lproj/localizedStrings.js
Source/WebInspectorUI/UserInterface/Base/Main.js
Source/WebInspectorUI/UserInterface/Base/Test.js
Source/WebInspectorUI/UserInterface/Controllers/CanvasManager.js [new file with mode: 0644]
Source/WebInspectorUI/UserInterface/Images/Canvas.svg [new file with mode: 0644]
Source/WebInspectorUI/UserInterface/Images/DocumentGL.png [new file with mode: 0644]
Source/WebInspectorUI/UserInterface/Images/DocumentGL@2x.png [new file with mode: 0644]
Source/WebInspectorUI/UserInterface/Main.html
Source/WebInspectorUI/UserInterface/Models/Canvas.js [new file with mode: 0644]
Source/WebInspectorUI/UserInterface/Models/ShaderProgram.js [new file with mode: 0644]
Source/WebInspectorUI/UserInterface/Models/WebGLContextAttributes.js [new file with mode: 0644]
Source/WebInspectorUI/UserInterface/Protocol/CanvasObserver.js [new file with mode: 0644]
Source/WebInspectorUI/UserInterface/Test.html
Source/WebInspectorUI/UserInterface/Views/CanvasTreeElement.js [new file with mode: 0644]
Source/WebInspectorUI/UserInterface/Views/FrameTreeElement.js
Source/WebInspectorUI/UserInterface/Views/ResourceIcons.css
Source/WebInspectorUI/UserInterface/Views/ResourceSidebarPanel.js
Source/WebInspectorUI/UserInterface/Views/ShaderProgramTreeElement.js [new file with mode: 0644]
Source/WebInspectorUI/WebInspectorUI.vcxproj/WebInspectorUI.vcxproj
Source/WebInspectorUI/WebInspectorUI.vcxproj/WebInspectorUI.vcxproj.filters

index 7211276..e444135 100644 (file)
@@ -1041,6 +1041,7 @@ set(JavaScriptCore_INSPECTOR_PROTOCOL_SCRIPTS
 set(JavaScriptCore_INSPECTOR_DOMAINS
     ${JAVASCRIPTCORE_DIR}/inspector/protocol/ApplicationCache.json
     ${JAVASCRIPTCORE_DIR}/inspector/protocol/CSS.json
+    ${JAVASCRIPTCORE_DIR}/inspector/protocol/Canvas.json
     ${JAVASCRIPTCORE_DIR}/inspector/protocol/Console.json
     ${JAVASCRIPTCORE_DIR}/inspector/protocol/DOM.json
     ${JAVASCRIPTCORE_DIR}/inspector/protocol/DOMDebugger.json
index 5d80d07..f6a94ca 100644 (file)
@@ -1,3 +1,20 @@
+2015-03-31  Matt Baker  <mattbaker@apple.com>
+
+        Web Inspector: add 2D/WebGL canvas instrumentation infrastructure
+        https://bugs.webkit.org/show_bug.cgi?id=137278
+
+        Reviewed by Timothy Hatcher.
+
+        Added Canvas protocol which defines types used by InspectorCanvasAgent.
+
+        * CMakeLists.txt:
+        * DerivedSources.make:
+        * inspector/protocol/Canvas.json: Added.
+
+        * inspector/scripts/codegen/generator.py:
+        (Generator.stylized_name_for_enum_value):
+        Added special handling for 2D (always uppercase) and WebGL (rename mapping) enum strings.
+
 2015-03-30  Ryosuke Niwa  <rniwa@webkit.org>
 
         Extending null should set __proto__ to null
index 699ac7e..d2d7f60 100644 (file)
@@ -117,6 +117,7 @@ InitBytecodes.asm: $(JavaScriptCore)/generate-bytecode-files $(JavaScriptCore)/b
 INSPECTOR_DOMAINS = \
     $(JavaScriptCore)/inspector/protocol/ApplicationCache.json \
     $(JavaScriptCore)/inspector/protocol/CSS.json \
+    $(JavaScriptCore)/inspector/protocol/Canvas.json \
     $(JavaScriptCore)/inspector/protocol/Console.json \
     $(JavaScriptCore)/inspector/protocol/DOM.json \
     $(JavaScriptCore)/inspector/protocol/DOMDebugger.json \
diff --git a/Source/JavaScriptCore/inspector/protocol/Canvas.json b/Source/JavaScriptCore/inspector/protocol/Canvas.json
new file mode 100644 (file)
index 0000000..0115f6f
--- /dev/null
@@ -0,0 +1,94 @@
+{
+    "domain": "Canvas",
+    "availability": "web",
+    "description": "Canvas domain allows tracking of 2D and WebGL canvases that have an associated graphics context. Tracks canvases belonging to a frame as well as CSS canvases created with -webkit-canvas.",
+    "types": [
+        {
+            "id": "CanvasId",
+            "type": "integer"
+        },
+        {
+            "id": "ProgramId",
+            "type": "object",
+            "properties": [
+                { "name": "canvasId", "$ref": "CanvasId", "description": "Parent canvas identifier." },
+                { "name": "objectId", "type": "integer", "description": "Uniquely identifies shader program within parent canvas." }
+            ]
+        },
+        {
+            "id": "ContextType",
+            "type": "string",
+            "enum": ["canvas-2d", "webgl"],
+            "description": "The type of rendering context backing the canvas element."
+        },
+        {
+            "id": "ShaderType",
+            "type": "string",
+            "enum": ["fragment", "vertex"],
+            "description": "Shader type. WebGL 1.0 supports VERTEX_SHADER and FRAGMENT_SHADER types."
+        },
+        {
+            "id": "ContextAttributes",
+            "type": "object",
+            "description": "WebGL drawing surface attributes.",
+            "properties": [
+                { "name": "alpha", "type": "boolean" },
+                { "name": "depth", "type": "boolean" },
+                { "name": "stencil", "type": "boolean" },
+                { "name": "antialias", "type": "boolean" },
+                { "name": "premultipliedAlpha", "type": "boolean" },
+                { "name": "preserveDrawingBuffer", "type": "boolean" }
+            ]
+        },
+        {
+            "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": "The id for the canvas." },
+                { "name": "frameId", "$ref": "Network.FrameId", "description": "Parent frame identifier." },
+                { "name": "name", "type": "string", "description": "The CSS canvas identifier, or the canvas element id attribute." },
+                { "name": "cssCanvas", "type": "boolean", "description": "True for canvases created with -webkit-canvas." },
+                { "name": "contextType", "$ref": "ContextType", "description": "The type of rendering context backing the canvas." },
+                { "name": "contextAttributes", "$ref": "ContextAttributes", "optional": true, "description": "Context attributes for WebGL rendering contexts." },
+                { "name": "programIds", "type": "array", "items": { "$ref": "ProgramId" }, "description": "Array of program IDs for linked programs belonging to the canvas rendering context." }
+            ]
+        }
+    ],
+    "commands": [
+        {
+            "name": "getCanvases",
+            "description": "Returns available canvases for all frames.",
+            "returns": [
+                { "name": "result", "type": "array", "items": { "$ref": "Canvas" }, "description": "Array of canvas objects." }
+            ]
+        }
+    ],
+    "events": [
+        {
+            "name": "canvasAdded",
+            "parameters": [
+                { "name": "canvas", "$ref": "Canvas", "description": "Canvas object." }
+            ]
+        },
+        {
+            "name": "canvasRemoved",
+            "parameters": [
+                { "name": "canvasId", "$ref": "CanvasId", "description": "Id of the canvas that was removed." }
+            ]
+        },
+        {
+            "name": "programCreated",
+            "description": "Fired when a program is created. Does not imply that link was successful.",
+            "parameters": [
+                { "name": "programId", "$ref": "ProgramId", "description": "Id of the program." }
+            ]
+        },
+        {
+            "name": "programDeleted",
+            "parameters": [
+                { "name": "programId", "$ref": "ProgramId", "description": "Id of the program." }
+            ]
+        }
+    ]
+}
index a1923fe..9f083fe 100755 (executable)
@@ -38,7 +38,11 @@ log = logging.getLogger('global')
 def ucfirst(str):
     return str[:1].upper() + str[1:]
 
-_ALWAYS_UPPERCASED_ENUM_VALUE_SUBSTRINGS = set(['API', 'CSS', 'DOM', 'HTML', 'XHR', 'XML'])
+_ALWAYS_UPPERCASED_ENUM_VALUE_SUBSTRINGS = set(['2D', 'API', 'CSS', 'DOM', 'HTML', 'XHR', 'XML'])
+
+_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.
@@ -219,7 +223,7 @@ class Generator:
             return 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
index d747e6a..353861d 100644 (file)
@@ -1786,6 +1786,7 @@ set(WebCore_SOURCES
     inspector/DOMPatchSupport.cpp
     inspector/InspectorApplicationCacheAgent.cpp
     inspector/InspectorCSSAgent.cpp
+    inspector/InspectorCanvasAgent.cpp
     inspector/InspectorClient.cpp
     inspector/InspectorController.cpp
     inspector/InspectorDOMAgent.cpp
index f01bc02..d64a425 100644 (file)
@@ -1,3 +1,97 @@
+2015-03-31  Matt Baker  <mattbaker@apple.com>
+
+        Web Inspector: add 2D/WebGL canvas instrumentation infrastructure
+        https://bugs.webkit.org/show_bug.cgi?id=137278
+
+        Reviewed by Timothy Hatcher.
+
+        Added backend agent for canvas inspection. A canvas is instrumented once its CanvasRenderingContext has been
+        created. WebGLRenderingContext is instrumented to track the lifetime of shader program objects.
+
+        To instrument off-screen rendering contexts (CSS canvases and detached canvas elements), the canvas agent must
+        track all CanvasRenderingContexts as they are created, even in the absense of the frontend. As far as I know,
+        there is no practical way to identify rendering contexts belonging to a frame that are not in the DOM. In the
+        absence of the inspector frontend the agent does only the minimum required to track the lifetime of rendering
+        contexts and their resources, to avoid creating a negative performance impact.
+
+        Tests: inspector/canvas/canvas-add-remove-events.html
+               inspector/canvas/canvas-context-attributes.html
+               inspector/canvas/canvas-css-name.html
+
+        * CMakeLists.txt:
+        * WebCore.xcodeproj/project.pbxproj:
+
+        * dom/Document.cpp:
+        (WebCore::Document::getCSSCanvasElement):
+        Instrumentation for CSS canvases.
+
+        * html/HTMLCanvasElement.cpp:
+        (WebCore::HTMLCanvasElement::getContext):
+        Instrumentation for context creation.
+
+        * html/canvas/WebGLRenderingContextBase.cpp:
+        (WebCore::WebGLRenderingContextBase::attachShader):
+        (WebCore::WebGLRenderingContextBase::createProgram):
+        (WebCore::WebGLRenderingContextBase::deleteProgram):
+        (WebCore::WebGLRenderingContextBase::detachShader):
+        Instrumentation for programs and shaders.
+
+        * inspector/InspectorAllInOne.cpp:
+
+        * inspector/InspectorCanvasAgent.cpp: Added.
+        (WebCore::InspectorCanvasAgent::InspectorCanvasAgent):
+        (WebCore::InspectorCanvasAgent::didCreateFrontendAndBackend):
+        (WebCore::InspectorCanvasAgent::willDestroyFrontendAndBackend):
+        (WebCore::InspectorCanvasAgent::frameNavigated):
+        (WebCore::InspectorCanvasAgent::didCreateCSSCanvas):
+        (WebCore::InspectorCanvasAgent::didCreateCanvasRenderingContext):
+        (WebCore::InspectorCanvasAgent::didAttachShader):
+        (WebCore::InspectorCanvasAgent::didDetachShader):
+        (WebCore::InspectorCanvasAgent::didCreateProgram):
+        (WebCore::InspectorCanvasAgent::didDeleteProgram):
+        (WebCore::InspectorCanvasAgent::getCanvases):
+        (WebCore::InspectorCanvasAgent::canvasDestroyed):
+        (WebCore::InspectorCanvasAgent::canvasDestroyedTimerFired):
+        (WebCore::InspectorCanvasAgent::reset):
+        (WebCore::InspectorCanvasAgent::getCanvasEntry):
+        (WebCore::InspectorCanvasAgent::getProgramEntry):
+        (WebCore::InspectorCanvasAgent::removeShaderFromShaderMap):
+        (WebCore::InspectorCanvasAgent::contextTypeJson):
+        (WebCore::InspectorCanvasAgent::buildObjectForCanvas):
+        * inspector/InspectorCanvasAgent.h: Added.
+        New backend agent.
+
+        * inspector/InspectorController.cpp:
+        (WebCore::InspectorController::InspectorController):
+        Support for new backend agent.
+
+        * inspector/InspectorInstrumentation.cpp:
+        (WebCore::InspectorInstrumentation::didCommitLoadImpl):
+        (WebCore::InspectorInstrumentation::didCreateCSSCanvasImpl):
+        (WebCore::InspectorInstrumentation::didCreateCanvasRenderingContextImpl):
+        (WebCore::InspectorInstrumentation::didAttachShaderImpl):
+        (WebCore::InspectorInstrumentation::didDetachShaderImpl):
+        (WebCore::InspectorInstrumentation::didCreateProgramImpl):
+        (WebCore::InspectorInstrumentation::didDeleteProgramImpl):
+        (WebCore::InspectorInstrumentation::instrumentingAgentsForRenderingContext):
+        Plumbing for canvas instrumentation.
+
+        * inspector/InspectorInstrumentation.h:
+        (WebCore::InspectorInstrumentation::didCreateCSSCanvas):
+        (WebCore::InspectorInstrumentation::didCreateCanvasRenderingContext):
+        (WebCore::InspectorInstrumentation::didAttachShader):
+        (WebCore::InspectorInstrumentation::didDetachShader):
+        (WebCore::InspectorInstrumentation::didCreateProgram):
+        (WebCore::InspectorInstrumentation::didDeleteProgram):
+
+        * inspector/InstrumentingAgents.cpp:
+        (WebCore::InstrumentingAgents::InstrumentingAgents):
+        (WebCore::InstrumentingAgents::reset):
+        * inspector/InstrumentingAgents.h:
+        (WebCore::InstrumentingAgents::inspectorCanvasAgent):
+        (WebCore::InstrumentingAgents::setInspectorCanvasAgent):
+        Support for new backend agent.
+
 2015-03-31  Xabier Rodriguez Calvar <calvaris@igalia.com> and Youenn Fablet  <youenn.fablet@crf.canon.fr>
 
         [Streams API] Implement a barebone ReadableStreamReader interface
index 0ec629e..19d2359 100644 (file)
                65FD466519B596F0001E2B4D /* WebVideoFullscreenModelVideoElement.h in Headers */ = {isa = PBXBuildFile; fileRef = 6586FE3C19B548BD005C3C82 /* WebVideoFullscreenModelVideoElement.h */; settings = {ATTRIBUTES = (Private, ); }; };
                65FD466619B596F6001E2B4D /* WebVideoFullscreenModelVideoElement.mm in Sources */ = {isa = PBXBuildFile; fileRef = 6586FE3D19B548BD005C3C82 /* WebVideoFullscreenModelVideoElement.mm */; };
                65FEA86909833ADE00BED4AB /* Page.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 65FEA86809833ADE00BED4AB /* Page.cpp */; };
+               6A32D7CE1A16D8C000412F0B /* InspectorCanvasAgent.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6A4B6D6619D225D8006F11D3 /* InspectorCanvasAgent.cpp */; };
+               6A4B6D6519D22519006F11D3 /* InspectorCanvasAgent.h in Headers */ = {isa = PBXBuildFile; fileRef = 6A4B6D6419D22519006F11D3 /* InspectorCanvasAgent.h */; };
                6B3480940EEF50D400AC1B41 /* NativeImagePtr.h in Headers */ = {isa = PBXBuildFile; fileRef = 6B3480920EEF50D400AC1B41 /* NativeImagePtr.h */; settings = {ATTRIBUTES = (Private, ); }; };
                6C568CB019DAFEA000430CA2 /* MaskImageOperation.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6C568CAE19DAFEA000430CA2 /* MaskImageOperation.cpp */; };
                6C568CB119DAFEA000430CA2 /* MaskImageOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = 6C568CAF19DAFEA000430CA2 /* MaskImageOperation.h */; settings = {ATTRIBUTES = (Private, ); }; };
                65E0E9431133C89F00B4CB10 /* JSDOMWrapper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSDOMWrapper.h; sourceTree = "<group>"; };
                65F80697054D9F86008BF776 /* BlockExceptions.mm */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = BlockExceptions.mm; sourceTree = "<group>"; tabWidth = 8; usesTabs = 0; };
                65FEA86809833ADE00BED4AB /* Page.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = Page.cpp; 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>"; };
                6B3480920EEF50D400AC1B41 /* NativeImagePtr.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = NativeImagePtr.h; sourceTree = "<group>"; };
                6C568CAE19DAFEA000430CA2 /* MaskImageOperation.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MaskImageOperation.cpp; sourceTree = "<group>"; };
                6C568CAF19DAFEA000430CA2 /* MaskImageOperation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MaskImageOperation.h; sourceTree = "<group>"; };
                                7A54881514E432A1006AE05A /* DOMPatchSupport.h */,
                                B885E8D211E06DD2009FFBF4 /* InspectorApplicationCacheAgent.cpp */,
                                B885E8D311E06DD2009FFBF4 /* InspectorApplicationCacheAgent.h */,
+                               6A4B6D6619D225D8006F11D3 /* InspectorCanvasAgent.cpp */,
+                               6A4B6D6419D22519006F11D3 /* InspectorCanvasAgent.h */,
                                7A1F2B51126C61B20006A7E6 /* InspectorClient.cpp */,
                                1C81B9580E97330800266E07 /* InspectorClient.h */,
                                F3F5CF1012ED81A80084C569 /* InspectorConsoleInstrumentation.h */,
                                A871DE2B0A152AC800B12A68 /* HTMLFrameElement.h in Headers */,
                                14FFE31D0AE1963300136BF5 /* HTMLFrameElementBase.h in Headers */,
                                93E241FF0B2B4E4000C732A1 /* HTMLFrameOwnerElement.h in Headers */,
+                               6A4B6D6519D22519006F11D3 /* InspectorCanvasAgent.h in Headers */,
                                A871DE280A152AC800B12A68 /* HTMLFrameSetElement.h in Headers */,
                                A871DE2D0A152AC800B12A68 /* HTMLHeadElement.h in Headers */,
                                A8EA7CB80A192B9C00A8EF5F /* HTMLHeadingElement.h in Headers */,
                        isa = PBXSourcesBuildPhase;
                        buildActionMask = 2147483647;
                        files = (
+                               6A32D7CE1A16D8C000412F0B /* InspectorCanvasAgent.cpp in Sources */,
                                41E1B1D00FF5986900576B3B /* AbstractWorker.cpp in Sources */,
                                37F57AB91A50726900876F98 /* AccessibilityARIAGrid.cpp in Sources */,
                                37F57ABA1A50726F00876F98 /* AccessibilityARIAGridCell.cpp in Sources */,
index 30cd2dc..64ca1c4 100644 (file)
@@ -5053,8 +5053,10 @@ CanvasRenderingContext* Document::getCSSCanvasContext(const String& type, const
 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();
 }
 
index eed70aa..3c64b7d 100644 (file)
@@ -41,6 +41,7 @@
 #include "GraphicsContext.h"
 #include "HTMLNames.h"
 #include "ImageData.h"
+#include "InspectorInstrumentation.h"
 #include "MIMETypeRegistry.h"
 #include "Page.h"
 #include "RenderHTMLCanvas.h"
@@ -193,6 +194,7 @@ CanvasRenderingContext* HTMLCanvasElement::getContext(const String& type, Canvas
                 usesDashbardCompatibilityMode = settings->usesDashboardBackwardCompatibilityMode();
 #endif
             m_context = std::make_unique<CanvasRenderingContext2D>(this, document().inQuirksMode(), usesDashbardCompatibilityMode);
+            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
             setNeedsStyleRecalc(SyntheticStyleChange);
@@ -209,6 +211,7 @@ CanvasRenderingContext* HTMLCanvasElement::getContext(const String& type, Canvas
             if (!m_context) {
                 m_context = WebGLRenderingContextBase::create(this, static_cast<WebGLContextAttributes*>(attrs), type);
                 if (m_context) {
+                    InspectorInstrumentation::didCreateCanvasRenderingContext(*this);
                     // Need to make sure a RenderLayer and compositing layer get created for the Canvas
                     setNeedsStyleRecalc(SyntheticStyleChange);
                 }
index 1e54e53..70f273f 100644 (file)
@@ -49,6 +49,7 @@
 #include "HTMLVideoElement.h"
 #include "ImageBuffer.h"
 #include "ImageData.h"
+#include "InspectorInstrumentation.h"
 #include "IntSize.h"
 #include "Logging.h"
 #include "MainFrame.h"
@@ -833,6 +834,8 @@ void WebGLRenderingContextBase::attachShader(WebGLProgram* program, WebGLShader*
     }
     m_context->attachShader(objectOrZero(program), objectOrZero(shader));
     shader->onAttached();
+
+    InspectorInstrumentation::didAttachShader(*this, *program, *shader);
 }
 
 void WebGLRenderingContextBase::bindAttribLocation(WebGLProgram* program, GC3Duint index, const String& name, ExceptionCode& ec)
@@ -1408,6 +1411,9 @@ PassRefPtr<WebGLProgram> WebGLRenderingContextBase::createProgram()
         return nullptr;
     RefPtr<WebGLProgram> o = WebGLProgram::create(this);
     addSharedObject(o.get());
+
+    InspectorInstrumentation::didCreateProgram(*this, *o);
+
     return o;
 }
 
@@ -1482,6 +1488,8 @@ void WebGLRenderingContextBase::deleteProgram(WebGLProgram* program)
     deleteObject(program);
     // We don't reset m_currentProgram to 0 here because the deletion of the
     // current program is delayed.
+
+    InspectorInstrumentation::didDeleteProgram(*this, *program);
 }
 
 void WebGLRenderingContextBase::deleteRenderbuffer(WebGLRenderbuffer* renderbuffer)
@@ -1550,6 +1558,8 @@ void WebGLRenderingContextBase::detachShader(WebGLProgram* program, WebGLShader*
     }
     m_context->detachShader(objectOrZero(program), objectOrZero(shader));
     shader->onDetached(graphicsContext3D());
+
+    InspectorInstrumentation::didDetachShader(*this, *program, *shader);
 }
 
 void WebGLRenderingContextBase::disable(GC3Denum cap)
index a2a266c..f802bb6 100644 (file)
@@ -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"
diff --git a/Source/WebCore/inspector/InspectorCanvasAgent.cpp b/Source/WebCore/inspector/InspectorCanvasAgent.cpp
new file mode 100644 (file)
index 0000000..b7763eb
--- /dev/null
@@ -0,0 +1,346 @@
+/*
+ * Copyright (C) 2015 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "InspectorCanvasAgent.h"
+
+#include "CanvasRenderingContext2D.h"
+#include "Document.h"
+#include "DocumentLoader.h"
+#include "Event.h"
+#include "EventListener.h"
+#include "EventTarget.h"
+#include "ExceptionCode.h"
+#include "Frame.h"
+#include "GraphicsContext3D.h"
+#include "GraphicsTypes3D.h"
+#include "InspectorPageAgent.h"
+#include "InstrumentingAgents.h"
+#include "JSMainThreadExecState.h"
+#include "MainFrame.h"
+#include "WebGLContextAttributes.h"
+#include "WebGLProgram.h"
+#include "WebGLRenderingContextBase.h"
+#include "WebGLShader.h"
+#include <inspector/InspectorValues.h>
+#include <inspector/ScriptCallStack.h>
+#include <inspector/ScriptCallStackFactory.h>
+#include <wtf/Vector.h>
+
+using namespace Inspector;
+
+namespace WebCore {
+
+InspectorCanvasAgent::InspectorCanvasAgent(InstrumentingAgents* instrumentingAgents, InspectorPageAgent* pageAgent)
+    : InspectorAgentBase(ASCIILiteral("Canvas"), instrumentingAgents)
+    , m_pageAgent(pageAgent)
+    , m_timer(*this, &InspectorCanvasAgent::canvasDestroyedTimerFired)
+{
+    reset();
+}
+
+void InspectorCanvasAgent::didCreateFrontendAndBackend(Inspector::FrontendChannel* frontendChannel, Inspector::BackendDispatcher* backendDispatcher)
+{
+    m_frontendDispatcher = std::make_unique<Inspector::CanvasFrontendDispatcher>(frontendChannel);
+    m_backendDispatcher = Inspector::CanvasBackendDispatcher::create(backendDispatcher, this);
+}
+
+void InspectorCanvasAgent::willDestroyFrontendAndBackend(Inspector::DisconnectReason)
+{
+    m_frontendDispatcher = nullptr;
+    m_backendDispatcher.clear();
+}
+
+void InspectorCanvasAgent::frameNavigated(DocumentLoader* loader)
+{
+    if (loader->frame()->isMainFrame()) {
+        reset();
+        return;
+    }
+
+    Vector<HTMLCanvasElement*> canvasesForFrame;
+    for (const auto& canvasElement : m_canvasEntries.keys()) {
+        if (canvasElement->document().frame() == loader->frame())
+            canvasesForFrame.append(canvasElement);
+    }
+
+    for (auto* canvasElement : canvasesForFrame) {
+        const auto& canvasEntry = m_canvasEntries.get(canvasElement);
+        for (const auto& programEntry : canvasEntry.programEntries.values()) {
+            removeShaderFromShaderMap(programEntry, programEntry.vertexShader);
+            removeShaderFromShaderMap(programEntry, programEntry.fragmentShader);
+        }
+
+        if (m_frontendDispatcher)
+            m_frontendDispatcher->canvasRemoved(canvasEntry.canvasId);
+    }
+}
+
+void InspectorCanvasAgent::didCreateCSSCanvas(HTMLCanvasElement& canvasElement, const String& name)
+{
+    ASSERT(!m_canvasToCSSCanvasId.contains(&canvasElement));
+    ASSERT(!m_canvasEntries.contains(&canvasElement));
+    if (m_canvasEntries.contains(&canvasElement))
+        return;
+
+    m_canvasToCSSCanvasId.set(&canvasElement, name);
+}
+
+void InspectorCanvasAgent::didCreateCanvasRenderingContext(HTMLCanvasElement& canvasElement)
+{
+    ASSERT(!m_canvasEntries.contains(&canvasElement));
+    if (m_canvasEntries.contains(&canvasElement))
+        return;
+
+    CanvasEntry newCanvasEntry(m_nextCanvasId++, &canvasElement);
+    if (m_canvasToCSSCanvasId.contains(&canvasElement)) {
+        ASSERT(!canvasElement.parentElement());
+        newCanvasEntry.name = m_canvasToCSSCanvasId.get(&canvasElement);
+        newCanvasEntry.cssCanvas = true;
+        m_canvasToCSSCanvasId.remove(&canvasElement);
+    } else
+        newCanvasEntry.name = canvasElement.getAttribute("id");
+
+    m_canvasEntries.set(&canvasElement, newCanvasEntry);
+    canvasElement.addObserver(*this);
+    if (m_frontendDispatcher)
+        m_frontendDispatcher->canvasAdded(buildObjectForCanvas(newCanvasEntry, canvasElement));
+}
+
+void InspectorCanvasAgent::didAttachShader(WebGLRenderingContextBase& context, WebGLProgram& program, WebGLShader& shader)
+{
+    ProgramEntry* programEntry = getProgramEntry(context, program);
+    ASSERT(programEntry);
+    if (!programEntry)
+        return;
+
+    ASSERT(!(programEntry->vertexShader == &shader || programEntry->fragmentShader == &shader));
+    if (shader.getType() == GraphicsContext3D::VERTEX_SHADER)
+        programEntry->vertexShader = &shader;
+    else
+        programEntry->fragmentShader = &shader;
+
+    auto addResult = m_shaderToProgramEntries.add(&shader, HashSet<const ProgramEntry*>({programEntry}));
+    if (!addResult.isNewEntry)
+        addResult.iterator->value.add(programEntry);
+    ASSERT(m_shaderToProgramEntries.contains(&shader));
+}
+
+void InspectorCanvasAgent::didDetachShader(WebGLRenderingContextBase& context, WebGLProgram& program, WebGLShader& shader)
+{
+    ProgramEntry* programEntry = getProgramEntry(context, program);
+    ASSERT(programEntry);
+    if (!programEntry)
+        return;
+
+    ASSERT(programEntry->vertexShader == &shader || programEntry->fragmentShader == &shader);
+    if (shader.getType() == GraphicsContext3D::VERTEX_SHADER) {
+        removeShaderFromShaderMap(*programEntry, programEntry->vertexShader);
+        programEntry->vertexShader = nullptr;
+    } else {
+        removeShaderFromShaderMap(*programEntry, programEntry->fragmentShader);
+        programEntry->fragmentShader = nullptr;
+    }
+}
+
+void InspectorCanvasAgent::didCreateProgram(WebGLRenderingContextBase& context, WebGLProgram& program)
+{
+    CanvasEntry* canvasEntry = getCanvasEntry(context.canvas());
+    ASSERT(canvasEntry);
+    if (!canvasEntry)
+        return;
+
+    auto findResult = canvasEntry->programEntries.find(&program);
+    ASSERT(findResult == canvasEntry->programEntries.end());
+    if (findResult != canvasEntry->programEntries.end())
+        return;
+
+    unsigned programId = canvasEntry->nextProgramId++;
+    canvasEntry->programEntries.set(&program, ProgramEntry(programId, canvasEntry, &program));
+    if (m_frontendDispatcher) {
+        auto compoundId = CanvasObjectId(canvasEntry->canvasId, programId);
+        m_frontendDispatcher->programCreated(compoundId.asProtocolValue<Inspector::Protocol::Canvas::ProgramId>());
+    }
+}
+
+void InspectorCanvasAgent::didDeleteProgram(WebGLRenderingContextBase& context, WebGLProgram& program)
+{
+    ProgramEntry* programEntry = getProgramEntry(context, program);
+    if (!programEntry)
+        return;
+
+    if (programEntry->vertexShader)
+        removeShaderFromShaderMap(*programEntry, programEntry->vertexShader);
+    if (programEntry->fragmentShader)
+        removeShaderFromShaderMap(*programEntry, programEntry->fragmentShader);
+    programEntry->canvasEntry->programEntries.remove(&program);
+    if (m_frontendDispatcher) {
+        auto compoundId = CanvasObjectId(programEntry->canvasEntry->canvasId, programEntry->programId);
+        m_frontendDispatcher->programDeleted(compoundId.asProtocolValue<Inspector::Protocol::Canvas::ProgramId>());
+    }
+}
+
+void InspectorCanvasAgent::getCanvases(ErrorString&, RefPtr<Inspector::Protocol::Array<Inspector::Protocol::Canvas::Canvas>>& result)
+{
+    result = Inspector::Protocol::Array<Inspector::Protocol::Canvas::Canvas>::create();
+    for (const auto& pair : m_canvasEntries) {
+        HTMLCanvasElement& canvasElement = *pair.key;
+        result->addItem(buildObjectForCanvas(pair.value, canvasElement));
+    }
+}
+
+void InspectorCanvasAgent::canvasDestroyed(HTMLCanvasElement& canvasElement)
+{
+    ASSERT(!m_canvasToCSSCanvasId.contains(&canvasElement));
+
+    const CanvasEntry* canvasEntry = getCanvasEntry(&canvasElement);
+    ASSERT(canvasEntry);
+    if (!canvasEntry)
+        return;
+
+    m_canvasEntries.remove(&canvasElement);
+
+    // 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_lastRemovedCanvasId = canvasEntry->canvasId;
+    m_timer.startOneShot(0);
+}
+
+void InspectorCanvasAgent::canvasDestroyedTimerFired()
+{
+    if (m_frontendDispatcher)
+        m_frontendDispatcher->canvasRemoved(m_lastRemovedCanvasId);
+
+    m_lastRemovedCanvasId = 0;
+}
+
+void InspectorCanvasAgent::reset()
+{
+    m_nextCanvasId = 1;
+    for (auto* canvasElement : m_canvasEntries.keys())
+        canvasElement->removeObserver(*this);
+
+    m_canvasToCSSCanvasId.clear();
+    m_canvasEntries.clear();
+    m_shaderToProgramEntries.clear();
+}
+
+InspectorCanvasAgent::CanvasEntry* InspectorCanvasAgent::getCanvasEntry(HTMLCanvasElement* canvasElement)
+{
+    ASSERT(canvasElement);
+    if (!canvasElement)
+        return nullptr;
+
+    auto findResult = m_canvasEntries.find(canvasElement);
+    if (findResult != m_canvasEntries.end())
+        return &findResult->value;
+    return nullptr;
+}
+
+InspectorCanvasAgent::CanvasEntry* InspectorCanvasAgent::getCanvasEntry(unsigned canvasId)
+{
+    for (auto& canvasEntry : m_canvasEntries.values()) {
+        if (canvasEntry.canvasId == canvasId)
+            return &canvasEntry;
+    }
+    return nullptr;
+}
+
+InspectorCanvasAgent::ProgramEntry* InspectorCanvasAgent::getProgramEntry(WebGLRenderingContextBase& context, WebGLProgram& program)
+{
+    CanvasEntry* canvasEntry = getCanvasEntry(context.canvas());
+    if (!canvasEntry)
+        return nullptr;
+
+    auto findResult = canvasEntry->programEntries.find(&program);
+    if (findResult == canvasEntry->programEntries.end())
+        return nullptr;
+
+    return &findResult->value;
+}
+
+void InspectorCanvasAgent::removeShaderFromShaderMap(const ProgramEntry& programEntry, WebGLShader* shader)
+{
+    ASSERT(shader);
+    if (!shader)
+        return;
+
+    auto findResult = m_shaderToProgramEntries.find(shader);
+    ASSERT(findResult != m_shaderToProgramEntries.end());
+    if (findResult == m_shaderToProgramEntries.end())
+        return;
+
+    auto& programEntries = findResult->value;
+    programEntries.remove(&programEntry);
+    if (programEntries.isEmpty())
+        m_shaderToProgramEntries.remove(shader);
+}
+
+Inspector::Protocol::Canvas::ContextType InspectorCanvasAgent::contextTypeJson(const CanvasRenderingContext* context)
+{
+    if (context->is2d())
+        return Inspector::Protocol::Canvas::ContextType::Canvas2D;
+
+    ASSERT(context->is3d());
+    return Inspector::Protocol::Canvas::ContextType::WebGL;
+}
+
+Ref<Inspector::Protocol::Canvas::Canvas> InspectorCanvasAgent::buildObjectForCanvas(const CanvasEntry& canvasEntry, HTMLCanvasElement& canvasElement)
+{
+    Frame* frame = canvasElement.document().frame();
+    CanvasRenderingContext* context = canvasElement.renderingContext();
+
+    auto programIds = Inspector::Protocol::Array<Inspector::Protocol::Canvas::ProgramId>::create();
+    for (auto& pair : canvasEntry.programEntries) {
+        auto compoundId = CanvasObjectId(canvasEntry.canvasId, pair.value.programId);
+        programIds->addItem(compoundId.asProtocolValue<Inspector::Protocol::Canvas::ProgramId>());
+    }
+
+    auto canvas = Inspector::Protocol::Canvas::Canvas::create()
+        .setCanvasId(canvasEntry.canvasId)
+        .setFrameId(m_pageAgent->frameId(frame))
+        .setName(canvasEntry.name)
+        .setCssCanvas(canvasEntry.cssCanvas)
+        .setContextType(contextTypeJson(context))
+        .setProgramIds(WTF::move(programIds))
+        .release();
+
+    if (context->is3d()) {
+        auto attributes = static_cast<WebGLRenderingContextBase*>(context)->getContextAttributes();
+        canvas->setContextAttributes(Inspector::Protocol::Canvas::ContextAttributes::create()
+            .setAlpha(attributes->alpha())
+            .setDepth(attributes->depth())
+            .setStencil(attributes->stencil())
+            .setAntialias(attributes->antialias())
+            .setPremultipliedAlpha(attributes->premultipliedAlpha())
+            .setPreserveDrawingBuffer(attributes->preserveDrawingBuffer())
+            .release());
+    }
+
+    return canvas;
+}
+
+} // namespace WebCore
diff --git a/Source/WebCore/inspector/InspectorCanvasAgent.h b/Source/WebCore/inspector/InspectorCanvasAgent.h
new file mode 100644 (file)
index 0000000..071624a
--- /dev/null
@@ -0,0 +1,176 @@
+/*
+ * Copyright (C) 2015 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef InspectorCanvasAgent_h
+#define InspectorCanvasAgent_h
+
+#include "HTMLCanvasElement.h"
+#include "InspectorWebAgentBase.h"
+#include "Timer.h"
+#include <inspector/InspectorBackendDispatchers.h>
+#include <inspector/InspectorFrontendDispatchers.h>
+#include <wtf/RefPtr.h>
+#include <wtf/text/WTFString.h>
+
+namespace WebCore {
+
+class DocumentLoader;
+class InspectorPageAgent;
+class WebGLProgram;
+class WebGLShader;
+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(InstrumentingAgents*, InspectorPageAgent*);
+    virtual ~InspectorCanvasAgent() { }
+
+    virtual void didCreateFrontendAndBackend(Inspector::FrontendChannel*, Inspector::BackendDispatcher*) override;
+    virtual void willDestroyFrontendAndBackend(Inspector::DisconnectReason) override;
+
+    // InspectorInstrumentation API
+    void frameNavigated(DocumentLoader*);
+    void didCreateCSSCanvas(HTMLCanvasElement&, const String&);
+    void didCreateCanvasRenderingContext(HTMLCanvasElement&);
+    void didAttachShader(WebGLRenderingContextBase&, WebGLProgram&, WebGLShader&);
+    void didDetachShader(WebGLRenderingContextBase&, WebGLProgram&, WebGLShader&);
+    void didCreateProgram(WebGLRenderingContextBase&, WebGLProgram&);
+    void didDeleteProgram(WebGLRenderingContextBase&, WebGLProgram&);
+
+    // Canvas API for InspectorFrontend
+    virtual void getCanvases(ErrorString&, RefPtr<Inspector::Protocol::Array<Inspector::Protocol::Canvas::Canvas>>&) override;
+
+    // CanvasObserver implementation
+    virtual void canvasChanged(HTMLCanvasElement&, const FloatRect&) override { }
+    virtual void canvasResized(HTMLCanvasElement&) override { }
+    virtual void canvasDestroyed(HTMLCanvasElement&) override;
+
+private:
+    class CanvasObjectId {
+    public:
+        CanvasObjectId() { }
+
+        explicit CanvasObjectId(const RefPtr<Inspector::InspectorObject> value)
+        {
+            if (!value->getInteger(ASCIILiteral("canvasId"), m_canvasId))
+                return;
+            if (!value->getInteger(ASCIILiteral("objectId"), m_objectId))
+                m_canvasId = 0;
+        }
+
+        CanvasObjectId(unsigned canvasId, unsigned programId)
+            : m_canvasId(canvasId)
+            , m_objectId(programId)
+        {
+        }
+
+        bool isEmpty() const { return !(m_canvasId && m_objectId); }
+        unsigned canvasId() const { return m_canvasId; }
+        unsigned objectId() const { return m_objectId; }
+
+        // ID type is either Inspector::Protocol::Canvas::ProgramId or Inspector::Protocol::Canvas::TextureId.
+        template<typename ID>
+        RefPtr<ID> asProtocolValue() const
+        {
+            if (isEmpty())
+                return nullptr;
+
+            return ID::create()
+                .setCanvasId(m_canvasId)
+                .setObjectId(m_objectId).release();
+        }
+
+    private:
+        unsigned m_canvasId = {0};
+        unsigned m_objectId = {0};
+    };
+
+    struct CanvasEntry;
+
+    struct ProgramEntry {
+        unsigned programId = {0};
+        CanvasEntry* canvasEntry = {nullptr};
+        WebGLProgram* program = {nullptr};
+        WebGLShader* vertexShader = {nullptr};
+        WebGLShader* fragmentShader = {nullptr};
+
+        ProgramEntry() { }
+
+        ProgramEntry(unsigned id, CanvasEntry* canvasEntry, WebGLProgram* program)
+            : programId(id)
+            , canvasEntry(canvasEntry)
+            , program(program)
+        {
+        }
+    };
+
+    struct CanvasEntry {
+        unsigned canvasId = {0};
+        unsigned nextProgramId = {1};
+        bool cssCanvas = {false};
+        String name;
+        HTMLCanvasElement* element = {nullptr};
+        HashMap<WebGLProgram*, ProgramEntry> programEntries;
+
+        CanvasEntry() { }
+
+        CanvasEntry(unsigned id, HTMLCanvasElement* canvasElement)
+            : canvasId(id)
+            , element(canvasElement)
+        {
+        }
+    };
+
+    void canvasDestroyedTimerFired();
+    void reset();
+    CanvasEntry* getCanvasEntry(HTMLCanvasElement*);
+    CanvasEntry* getCanvasEntry(unsigned);
+    ProgramEntry* getProgramEntry(WebGLRenderingContextBase&, WebGLProgram&);
+    void removeShaderFromShaderMap(const ProgramEntry&, WebGLShader*);
+    static Inspector::Protocol::Canvas::ContextType contextTypeJson(const CanvasRenderingContext*);
+    Ref<Inspector::Protocol::Canvas::Canvas> buildObjectForCanvas(const CanvasEntry&, HTMLCanvasElement&);
+
+    InspectorPageAgent* m_pageAgent;
+    std::unique_ptr<Inspector::CanvasFrontendDispatcher> m_frontendDispatcher;
+    RefPtr<Inspector::CanvasBackendDispatcher> m_backendDispatcher;
+
+    HashMap<HTMLCanvasElement*, String> m_canvasToCSSCanvasId;
+    HashMap<HTMLCanvasElement*, CanvasEntry> m_canvasEntries;
+    HashMap<const WebGLShader*, HashSet<const ProgramEntry*>> m_shaderToProgramEntries;
+    Timer m_timer;
+    unsigned m_nextCanvasId = {0};
+    unsigned m_lastRemovedCanvasId = {0};
+};
+
+} // namespace WebCore
+
+#endif // !defined(InspectorCanvasAgent_h)
index a19ba4a..8752c89 100644 (file)
@@ -37,6 +37,7 @@
 #include "GraphicsContext.h"
 #include "InspectorApplicationCacheAgent.h"
 #include "InspectorCSSAgent.h"
+#include "InspectorCanvasAgent.h"
 #include "InspectorClient.h"
 #include "InspectorDOMAgent.h"
 #include "InspectorDOMDebuggerAgent.h"
@@ -157,6 +158,10 @@ InspectorController::InspectorController(Page& page, InspectorClient* inspectorC
     m_domDebuggerAgent = domDebuggerAgentPtr.get();
     m_agents.append(WTF::move(domDebuggerAgentPtr));
 
+    auto canvasAgentPtr = std::make_unique<InspectorCanvasAgent>(m_instrumentingAgents.get(), m_pageAgent);
+    m_instrumentingAgents->setInspectorCanvasAgent(canvasAgentPtr.get());
+    m_agents.append(WTF::move(canvasAgentPtr));
+
     m_agents.append(std::make_unique<InspectorApplicationCacheAgent>(m_instrumentingAgents.get(), pageAgent));
     m_agents.append(std::make_unique<InspectorWorkerAgent>(m_instrumentingAgents.get()));
     m_agents.append(std::make_unique<InspectorLayerTreeAgent>(m_instrumentingAgents.get()));
index e60f0d6..3662a94 100644 (file)
@@ -43,6 +43,7 @@
 #include "InspectorApplicationCacheAgent.h"
 #include "InspectorController.h"
 #include "InspectorCSSAgent.h"
+#include "InspectorCanvasAgent.h"
 #include "InspectorDOMAgent.h"
 #include "InspectorDOMDebuggerAgent.h"
 #include "InspectorDOMStorageAgent.h"
@@ -62,6 +63,7 @@
 #include "StyleResolver.h"
 #include "StyleRule.h"
 #include "WebConsoleAgent.h"
+#include "WebGLRenderingContextBase.h"
 #include "WorkerGlobalScope.h"
 #include "WorkerInspectorController.h"
 #include "WorkerRuntimeAgent.h"
@@ -762,6 +764,9 @@ void InspectorInstrumentation::didCommitLoadImpl(InstrumentingAgents& instrument
             layerTreeAgent->reset();
     }
 
+    if (InspectorCanvasAgent* canvasAgent = instrumentingAgents.inspectorCanvasAgent())
+        canvasAgent->frameNavigated(loader);
+
     if (InspectorDOMAgent* domAgent = instrumentingAgents.inspectorDOMAgent())
         domAgent->didCommitLoad(loader->frame()->document());
 
@@ -1028,6 +1033,44 @@ void InspectorInstrumentation::didSendWebSocketFrameImpl(InstrumentingAgents& in
 }
 #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(WEBGL)
+void InspectorInstrumentation::didAttachShaderImpl(InstrumentingAgents* instrumentingAgents, WebGLRenderingContextBase& context, WebGLProgram& program, WebGLShader& shader)
+{
+    if (InspectorCanvasAgent* canvasAgent = instrumentingAgents->inspectorCanvasAgent())
+        canvasAgent->didAttachShader(context, program, shader);
+}
+
+void InspectorInstrumentation::didDetachShaderImpl(InstrumentingAgents* instrumentingAgents, WebGLRenderingContextBase& context, WebGLProgram& program, WebGLShader& shader)
+{
+    if (InspectorCanvasAgent* canvasAgent = instrumentingAgents->inspectorCanvasAgent())
+        canvasAgent->didDetachShader(context, program, shader);
+}
+
+void InspectorInstrumentation::didCreateProgramImpl(InstrumentingAgents* instrumentingAgents, WebGLRenderingContextBase& context, WebGLProgram& program)
+{
+    if (InspectorCanvasAgent* canvasAgent = instrumentingAgents->inspectorCanvasAgent())
+        canvasAgent->didCreateProgram(context, program);
+}
+
+void InspectorInstrumentation::didDeleteProgramImpl(InstrumentingAgents* instrumentingAgents, WebGLRenderingContextBase& context, WebGLProgram& program)
+{
+    if (InspectorCanvasAgent* canvasAgent = instrumentingAgents->inspectorCanvasAgent())
+        canvasAgent->didDeleteProgram(context, program);
+}
+#endif
+
 #if ENABLE(WEB_REPLAY)
 void InspectorInstrumentation::sessionCreatedImpl(InstrumentingAgents& instrumentingAgents, RefPtr<ReplaySession>&& session)
 {
@@ -1221,6 +1264,16 @@ InspectorTimelineAgent* InspectorInstrumentation::retrieveTimelineAgent(const In
     return nullptr;
 }
 
+InstrumentingAgents* InspectorInstrumentation::instrumentingAgentsForRenderingContext(WebGLRenderingContextBase* context)
+{
+    if (!context)
+        return nullptr;
+    HTMLCanvasElement* canvasElement = context->canvas();
+    if (canvasElement)
+        return instrumentingAgentsForDocument(&canvasElement->document());
+    return nullptr;
+}
+
 InstrumentingAgents* InspectorInstrumentation::instrumentingAgentsForPage(Page* page)
 {
     return page ? instrumentingAgentsForPage(*page) : nullptr;
index ad8de6b..f975343 100644 (file)
@@ -36,6 +36,7 @@
 #include "Element.h"
 #include "FormData.h"
 #include "Frame.h"
+#include "HTMLCanvasElement.h"
 #include "HitTestResult.h"
 #include "InspectorInstrumentationCookie.h"
 #include "Page.h"
@@ -75,7 +76,6 @@ class DOMWindow;
 class DOMWrapperWorld;
 class Database;
 class Document;
-class Element;
 class DocumentLoader;
 class DocumentStyleSheetCollection;
 class GraphicsContext;
@@ -93,13 +93,15 @@ class RenderLayerBacking;
 class RenderObject;
 class ResourceRequest;
 class ResourceResponse;
-class ScriptExecutionContext;
 class SecurityOrigin;
 class ShadowRoot;
 class StorageArea;
 class StyleResolver;
 class StyleRule;
 class ThreadableLoaderClient;
+class WebGLShader;
+class WebGLProgram;
+class WebGLRenderingContextBase;
 class WorkerGlobalScope;
 class WorkerGlobalScopeProxy;
 class XMLHttpRequest;
@@ -263,9 +265,13 @@ public:
     static void didReceiveWebSocketFrameError(Document*, unsigned long identifier, const String& errorMessage);
 #endif
 
-    static Deprecated::ScriptObject wrapCanvas2DRenderingContextForInstrumentation(Document*, const Deprecated::ScriptObject&);
+    static void didCreateCSSCanvas(HTMLCanvasElement&, const String&);
+    static void didCreateCanvasRenderingContext(HTMLCanvasElement&);
 #if ENABLE(WEBGL)
-    static Deprecated::ScriptObject wrapWebGLRenderingContextForInstrumentation(Document*, const Deprecated::ScriptObject&);
+    static void didAttachShader(WebGLRenderingContextBase&, WebGLProgram&, WebGLShader&);
+    static void didDetachShader(WebGLRenderingContextBase&, WebGLProgram&, WebGLShader&);
+    static void didCreateProgram(WebGLRenderingContextBase&, WebGLProgram&);
+    static void didDeleteProgram(WebGLRenderingContextBase&, WebGLProgram&);
 #endif
 
     static void networkStateChanged(Page*);
@@ -442,6 +448,15 @@ private:
 
     static void networkStateChangedImpl(InstrumentingAgents&);
     static void updateApplicationCacheStatusImpl(InstrumentingAgents&, Frame*);
+    static void didCreateCSSCanvasImpl(InstrumentingAgents*, HTMLCanvasElement&, const String&);
+    static void didCreateCanvasRenderingContextImpl(InstrumentingAgents*, HTMLCanvasElement&);
+
+#if ENABLE(WEBGL)
+    static void didAttachShaderImpl(InstrumentingAgents*, WebGLRenderingContextBase&, WebGLProgram&, WebGLShader&);
+    static void didDetachShaderImpl(InstrumentingAgents*, WebGLRenderingContextBase&, WebGLProgram&, WebGLShader&);
+    static void didCreateProgramImpl(InstrumentingAgents*, WebGLRenderingContextBase&, WebGLProgram&);
+    static void didDeleteProgramImpl(InstrumentingAgents*, WebGLRenderingContextBase&, WebGLProgram&);
+#endif
 
     static void layerTreeDidChangeImpl(InstrumentingAgents&);
     static void renderLayerDestroyedImpl(InstrumentingAgents&, const RenderLayer&);
@@ -450,6 +465,7 @@ private:
     static InstrumentingAgents* instrumentingAgentsForPage(Page&);
     static InstrumentingAgents* instrumentingAgentsForFrame(Frame&);
     static InstrumentingAgents* instrumentingAgentsForFrame(Frame*);
+    static InstrumentingAgents* instrumentingAgentsForRenderingContext(WebGLRenderingContextBase*);
     static InstrumentingAgents* instrumentingAgentsForContext(ScriptExecutionContext*);
     static InstrumentingAgents* instrumentingAgentsForDocument(Document&);
     static InstrumentingAgents* instrumentingAgentsForDocument(Document*);
@@ -1155,6 +1171,75 @@ inline void InspectorInstrumentation::didSendWebSocketFrame(Document* document,
 }
 #endif // ENABLE(WEB_SOCKETS)
 
+inline void InspectorInstrumentation::didCreateCSSCanvas(HTMLCanvasElement& canvasElement, const String& name)
+{
+#if ENABLE(INSPECTOR)
+    if (InstrumentingAgents* instrumentingAgents = instrumentingAgentsForDocument(&canvasElement.document()))
+        didCreateCSSCanvasImpl(instrumentingAgents, canvasElement, name);
+#else
+    UNUSED_PARAM(canvasElement);
+    UNUSED_PARAM(name);
+#endif
+}
+
+inline void InspectorInstrumentation::didCreateCanvasRenderingContext(HTMLCanvasElement& canvasElement)
+{
+#if ENABLE(INSPECTOR)
+    if (InstrumentingAgents* instrumentingAgents = instrumentingAgentsForDocument(&canvasElement.document()))
+        didCreateCanvasRenderingContextImpl(instrumentingAgents, canvasElement);
+#else
+    UNUSED_PARAM(canvasElement);
+#endif
+}
+
+#if ENABLE(WEBGL)
+inline void InspectorInstrumentation::didAttachShader(WebGLRenderingContextBase& context, WebGLProgram& program, WebGLShader& shader)
+{
+#if ENABLE(INSPECTOR)
+    if (InstrumentingAgents* instrumentingAgents = instrumentingAgentsForRenderingContext(&context))
+        didAttachShaderImpl(instrumentingAgents, context, program, shader);
+#else
+    UNUSED_PARAM(context);
+    UNUSED_PARAM(program);
+    UNUSED_PARAM(shader);
+#endif
+}
+
+inline void InspectorInstrumentation::didDetachShader(WebGLRenderingContextBase& context, WebGLProgram& program, WebGLShader& shader)
+{
+#if ENABLE(INSPECTOR)
+    if (InstrumentingAgents* instrumentingAgents = instrumentingAgentsForRenderingContext(&context))
+        didDetachShaderImpl(instrumentingAgents, context, program, shader);
+#else
+    UNUSED_PARAM(context);
+    UNUSED_PARAM(program);
+    UNUSED_PARAM(shader);
+#endif
+}
+
+inline void InspectorInstrumentation::didCreateProgram(WebGLRenderingContextBase& context, WebGLProgram& program)
+{
+#if ENABLE(INSPECTOR)
+    if (InstrumentingAgents* instrumentingAgents = instrumentingAgentsForRenderingContext(&context))
+        didCreateProgramImpl(instrumentingAgents, context, program);
+#else
+    UNUSED_PARAM(context);
+    UNUSED_PARAM(program);
+#endif
+}
+
+inline void InspectorInstrumentation::didDeleteProgram(WebGLRenderingContextBase& context, WebGLProgram& program)
+{
+#if ENABLE(INSPECTOR)
+    if (InstrumentingAgents* instrumentingAgents = instrumentingAgentsForRenderingContext(&context))
+        didDeleteProgramImpl(instrumentingAgents, context, program);
+#else
+    UNUSED_PARAM(context);
+    UNUSED_PARAM(program);
+#endif
+}
+#endif
+
 #if ENABLE(WEB_REPLAY)
 inline void InspectorInstrumentation::sessionCreated(Page& page, RefPtr<ReplaySession>&& session)
 {
index ec04642..695811a 100644 (file)
@@ -46,6 +46,7 @@ InstrumentingAgents::InstrumentingAgents(InspectorEnvironment& environment)
     : m_environment(environment)
     , m_inspectorAgent(nullptr)
     , m_inspectorPageAgent(nullptr)
+    , m_inspectorCanvasAgent(nullptr)
     , m_inspectorCSSAgent(nullptr)
     , m_inspectorLayerTreeAgent(nullptr)
     , m_webConsoleAgent(nullptr)
@@ -72,6 +73,7 @@ void InstrumentingAgents::reset()
 {
     m_inspectorAgent = nullptr;
     m_inspectorPageAgent = nullptr;
+    m_inspectorCanvasAgent = nullptr;
     m_inspectorCSSAgent = nullptr;
     m_inspectorLayerTreeAgent = nullptr;
     m_webConsoleAgent = nullptr;
index f91a685..aa2a4e1 100644 (file)
@@ -46,6 +46,7 @@ class InspectorDebuggerAgent;
 namespace WebCore {
 
 class InspectorApplicationCacheAgent;
+class InspectorCanvasAgent;
 class InspectorCSSAgent;
 class InspectorDOMAgent;
 class InspectorDOMDebuggerAgent;
@@ -83,6 +84,9 @@ public:
     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; }
 
@@ -143,6 +147,7 @@ private:
 
     Inspector::InspectorAgent* m_inspectorAgent;
     InspectorPageAgent* m_inspectorPageAgent;
+    InspectorCanvasAgent* m_inspectorCanvasAgent;
     InspectorCSSAgent* m_inspectorCSSAgent;
     InspectorLayerTreeAgent* m_inspectorLayerTreeAgent;
     WebConsoleAgent* m_webConsoleAgent;
index 02d8954..b3b9fe0 100644 (file)
@@ -1,3 +1,128 @@
+2015-03-31  Matt Baker  <mattbaker@apple.com>
+
+        Web Inspector: add 2D/WebGL canvas instrumentation infrastructure
+        https://bugs.webkit.org/show_bug.cgi?id=137278
+
+        Reviewed by Timothy Hatcher.
+
+        Added models, views, and controller classes for 2D and WebGL canvas inspection. Each canvas is shown in the
+        Resources navigation sidebar under its parent frame. Shader programs are displayed as child nodes of
+        their respective canvas. Canvases will get an associated content view and details sidebar in a later patch
+        (see https://bugs.webkit.org/show_bug.cgi?id=138941).
+
+        Shader programs will get an associated content view for editing shader source in a later patch (see
+        https://bugs.webkit.org/show_bug.cgi?id=138593). Individual shaders are not shown in the Resource navigation
+        sidebar, and at this time there are no plans to instrument shaders that aren't attached to a program.
+
+        * Localizations/en.lproj/localizedStrings.js:
+        * UserInterface/Base/Main.js:
+        (WebInspector.loaded):
+        (WebInspector.sidebarPanelForRepresentedObject):
+        * UserInterface/Base/Test.js:
+        (WebInspector.loaded):
+        * UserInterface/Main.html:
+        * UserInterface/Test.html:
+        Updated for new canvas/shader program types.
+
+        * UserInterface/Controllers/CanvasManager.js: Added.
+        (WebInspector.CanvasManager):
+        (WebInspector.CanvasManager.prototype.canvasesForFrame):
+        (WebInspector.CanvasManager.prototype.canvasAdded.set this):
+        (WebInspector.CanvasManager.prototype.canvasAdded):
+        (WebInspector.CanvasManager.prototype.canvasRemoved):
+        (WebInspector.CanvasManager.programDeleted.get console):
+        (WebInspector.CanvasManager.prototype.programCreated.get console):
+        (WebInspector.CanvasManager.prototype.programCreated):
+        (WebInspector.CanvasManager.prototype._mainResourceDidChange):
+        Frontend controller for canvases and their shader programs.
+
+        * UserInterface/Images/Canvas.svg: Added.
+        * UserInterface/Images/DocumentGL.png: Added.
+        * UserInterface/Images/DocumentGL@2x.png: Added.
+        New art for canvas and shader program tree elements.
+
+        * UserInterface/Models/Canvas.js: Added.
+        (WebInspector.Canvas):
+        (WebInspector.Canvas.prototype.set fromPayload):
+        (WebInspector.Canvas.displayNameForContextType):
+        (WebInspector.Canvas.resetUniqueDisplayNameNumbers):
+        (WebInspector.Canvas.prototype.get id):
+        (WebInspector.Canvas.prototype.get parentFrame):
+        (WebInspector.Canvas.prototype.get name):
+        (WebInspector.Canvas.prototype.get cssCanvas):
+        (WebInspector.Canvas.prototype.get contextType):
+        (WebInspector.Canvas.prototype.get contextAttributes):
+        (WebInspector.Canvas.prototype.get programs):
+        (WebInspector.Canvas.prototype.get displayName):
+        (WebInspector.Canvas.programForId):
+        (WebInspector.Canvas.get programWasCreated.set this):
+        (WebInspector.Canvas.prototype.get programWasCreated):
+        (WebInspector.Canvas.prototype.programWasDeleted):
+        (WebInspector.Canvas.prototype.saveIdentityToCookie):
+        Model for DOM or CSS canvas (2D or WebGL).
+
+        * UserInterface/Models/ShaderProgram.js: Added.
+        (WebInspector.ShaderProgram):
+        (WebInspector.ShaderProgram.prototype.get id):
+        (WebInspector.ShaderProgram.prototype.get canvas):
+        (WebInspector.ShaderProgram.prototype.get displayName):
+        (WebInspector.ShaderProgram.prototype.saveIdentityToCookie):
+        (WebInspector.ShaderProgram.prototype.updateCanvas):
+        * UserInterface/Models/WebGLContextAttributes.js: Added.
+        (WebInspector.WebGLContextAttributes):
+        (WebInspector.WebGLContextAttributes.fromPayload):
+        (WebInspector.WebGLContextAttributes.prototype.get alpha):
+        (WebInspector.WebGLContextAttributes.prototype.get depth):
+        (WebInspector.WebGLContextAttributes.prototype.get stencil):
+        (WebInspector.WebGLContextAttributes.prototype.get antialias):
+        (WebInspector.WebGLContextAttributes.prototype.get premultipliedAlpha):
+        (WebInspector.WebGLContextAttributes.prototype.get preserveDrawingBuffer):
+        Model for WebGL canvas context attributes.
+
+        * UserInterface/Protocol/CanvasObserver.js: Added.
+        (WebInspector.CanvasObserver.prototype.canvasAdded):
+        (WebInspector.CanvasObserver.prototype.canvasRemoved):
+        (WebInspector.CanvasObserver.prototype.programCreated):
+        (WebInspector.CanvasObserver.prototype.programDeleted):
+        (WebInspector.CanvasObserver):
+        Model for WebGL canvas shader program.
+
+        * UserInterface/Views/CanvasTreeElement.js: Added.
+        (WebInspector.CanvasTreeElement.validateRepresentedObject):
+        (WebInspector.CanvasTreeElement.countChildren):
+        (WebInspector.CanvasTreeElement):
+        (WebInspector.CanvasTreeElement.prototype.onexpand):
+        (WebInspector.CanvasTreeElement.prototype.oncollapse):
+        (WebInspector.CanvasTreeElement.prototype.onpopulate):
+        (WebInspector.CanvasTreeElement.prototype._programWasCreated):
+        (WebInspector.CanvasTreeElement.prototype._programWasDeleted):
+        Folderized tree element for canvases and their child objects (shader programs).
+
+        * UserInterface/Views/FrameTreeElement.js:
+        (WebInspector.FrameTreeElement.prototype.onattach):
+        (WebInspector.FrameTreeElement.prototype.ondetach):
+        (WebInspector.FrameTreeElement.prototype.onpopulate):
+        (WebInspector.FrameTreeElement.prototype._canvasesAvailable):
+        (WebInspector.FrameTreeElement.prototype._canvasWasAdded):
+        (WebInspector.FrameTreeElement.prototype._canvasWasRemoved):
+        Updated to support canvas tree elements.
+
+        * UserInterface/Views/ResourceIcons.css:
+        (.canvas-icon .icon):
+        (.shader-program-icon .icon):
+        Styles for new canvas and shader program icons.
+
+        * UserInterface/Views/ResourceSidebarPanel.js:
+        (WebInspector.ResourceSidebarPanel.prototype._treeElementSelected):
+        Updated for new tree element types.
+
+        * UserInterface/Views/ShaderProgramTreeElement.js: Added.
+        (WebInspector.ShaderProgramTreeElement):
+        Tree element for shader programs. Shown as children of CanvasTreeElement.
+
+        * WebInspectorUI.vcxproj/WebInspectorUI.vcxproj:
+        * WebInspectorUI.vcxproj/WebInspectorUI.vcxproj.filters:
+
 2015-03-30  Joseph Pecoraro  <pecoraro@apple.com>
 
         Web Inspector: Regression: null shouldn't be expandable in object outline
index 9f2e20b..10bddb7 100644 (file)
Binary files a/Source/WebInspectorUI/Localizations/en.lproj/localizedStrings.js and b/Source/WebInspectorUI/Localizations/en.lproj/localizedStrings.js differ
index 19a2f29..ee1662b 100644 (file)
@@ -78,6 +78,8 @@ WebInspector.loaded = function()
         InspectorBackend.registerRuntimeDispatcher(new WebInspector.RuntimeObserver);
     if (InspectorBackend.registerReplayDispatcher)
         InspectorBackend.registerReplayDispatcher(new WebInspector.ReplayObserver);
+    if (InspectorBackend.registerCanvasDispatcher)
+        InspectorBackend.registerCanvasDispatcher(new WebInspector.CanvasObserver);
 
     // Enable agents.
     if (window.InspectorAgent)
@@ -110,6 +112,7 @@ WebInspector.loaded = function()
     this.dashboardManager = new WebInspector.DashboardManager;
     this.probeManager = new WebInspector.ProbeManager;
     this.replayManager = new WebInspector.ReplayManager;
+    this.canvasManager = new WebInspector.CanvasManager;
 
     // Enable the Console Agent after creating the singleton managers.
     if (window.ConsoleAgent)
@@ -383,7 +386,8 @@ WebInspector.sidebarPanelForCurrentContentView = function()
 WebInspector.sidebarPanelForRepresentedObject = function(representedObject)
 {
     if (representedObject instanceof WebInspector.Frame || representedObject instanceof WebInspector.Resource ||
-        representedObject instanceof WebInspector.Script || representedObject instanceof WebInspector.ContentFlow)
+        representedObject instanceof WebInspector.Script || representedObject instanceof WebInspector.ContentFlow ||
+        representedObject instanceof WebInspector.Canvas || representedObject instanceof WebInspector.ShaderProgram)
         return this.resourceSidebarPanel;
 
     if (representedObject instanceof WebInspector.DOMStorageObject || representedObject instanceof WebInspector.CookieStorageObject ||
index 273207e..d785e64 100644 (file)
@@ -45,6 +45,7 @@ WebInspector.loaded = function()
     InspectorBackend.registerRuntimeDispatcher(new WebInspector.RuntimeObserver);
     if (InspectorBackend.registerReplayDispatcher)
         InspectorBackend.registerReplayDispatcher(new WebInspector.ReplayObserver);
+    InspectorBackend.registerCanvasDispatcher(new WebInspector.CanvasObserver);
 
     // Instantiate controllers used by tests.
     this.frameResourceManager = new WebInspector.FrameResourceManager;
@@ -55,6 +56,7 @@ WebInspector.loaded = function()
     this.debuggerManager = new WebInspector.DebuggerManager;
     this.probeManager = new WebInspector.ProbeManager;
     this.replayManager = new WebInspector.ReplayManager;
+    this.canvasManager = new WebInspector.CanvasManager;
 
     // Global controllers.
     this.quickConsole = {executionContextIdentifier: undefined};
diff --git a/Source/WebInspectorUI/UserInterface/Controllers/CanvasManager.js b/Source/WebInspectorUI/UserInterface/Controllers/CanvasManager.js
new file mode 100644 (file)
index 0000000..699651c
--- /dev/null
@@ -0,0 +1,162 @@
+/*
+ * Copyright (C) 2015 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+WebInspector.CanvasManager = class CanvasManager extends WebInspector.Object
+{
+    constructor()
+    {
+        super();
+
+        WebInspector.Frame.addEventListener(WebInspector.Frame.Event.MainResourceDidChange, this._mainResourceDidChange, this);
+
+        this._waitingForCanvasesPayload = false;
+        this._canvasIdMap = new Map;
+
+        this._initialize();
+    }
+
+    canvasesForFrame(frame)
+    {
+        if (this._waitingForCanvasesPayload)
+            return [];
+
+        var canvases = [];
+        for (var canvas of this._canvasIdMap.values()) {
+            if (canvas.parentFrame.id === frame.id)
+                canvases.push(canvas);
+        }
+        return canvases;
+    }
+
+    canvasAdded(canvasPayload)
+    {
+        // Called from WebInspector.CanvasObserver.
+        console.assert(!this._canvasIdMap.has(canvasPayload.canvasId));
+        var canvas = WebInspector.Canvas.fromPayload(canvasPayload);
+
+        this._canvasIdMap.set(canvas.id, canvas);
+        this.dispatchEventToListeners(WebInspector.CanvasManager.Event.CanvasWasAdded, {canvas: canvas});
+    }
+
+    canvasRemoved(canvasIdentifier)
+    {
+        // Called from WebInspector.CanvasObserver.
+
+        console.assert(this._canvasIdMap.has(canvasIdentifier));
+        if (!this._canvasIdMap.has(canvasIdentifier))
+            return;
+
+        var canvas = this._canvasIdMap.take(canvasIdentifier);
+        this.dispatchEventToListeners(WebInspector.CanvasManager.Event.CanvasWasRemoved, {canvas: canvas});
+    }
+
+    programCreated(programIdentifier)
+    {
+        // Called from WebInspector.CanvasObserver.
+
+        var canvas = this._canvasIdMap.get(programIdentifier.canvasId);
+        console.assert(canvas);
+        if (!canvas)
+            return;
+
+        canvas.programWasCreated(new WebInspector.ShaderProgram(programIdentifier, canvas));
+    }
+
+    programDeleted(programIdentifier)
+    {
+        // Called from WebInspector.CanvasObserver.
+
+        var canvas = this._canvasIdMap.get(programIdentifier.canvasId);
+        console.assert(canvas);
+        if (!canvas)
+            return;
+
+        canvas.programWasDeleted(programIdentifier);
+    }
+
+    // Private
+
+    _getCanvasesForFrameId(frameIdentifier)
+    {
+        var canvases = [];
+        for (var canvas of this._canvasIdMap.values()) {
+            if (canvas.parentFrame.id === frameIdentifier)
+                canvases.push(canvas);
+        }
+        return canvases;
+    }
+
+    _initialize()
+    {
+        if (!window.CanvasAgent)
+            return;
+
+        for (var canvas of this._canvasIdMap.values())
+            this.dispatchEventToListeners(WebInspector.CanvasManager.Event.CanvasWasRemoved, {canvas: canvas});
+
+        WebInspector.Canvas.resetUniqueDisplayNameNumbers();
+
+        this._canvasIdMap.clear();
+        this._waitingForCanvasesPayload = true;
+
+        CanvasAgent.getCanvases(this._processCanvasesPayload.bind(this));
+    }
+
+    _mainResourceDidChange(event)
+    {
+        console.assert(event.target instanceof WebInspector.Frame);
+
+        if (!event.target.isMainFrame())
+            return;
+
+        this._initialize();
+    }
+
+    _processCanvasesPayload(error, canvasArrayPayload)
+    {
+        console.assert(this._waitingForCanvasesPayload);
+        this._waitingForCanvasesPayload = false;
+
+        if (error) {
+            console.error(JSON.stringify(error));
+            return;
+        }
+
+        for (var canvasPayload of canvasArrayPayload) {
+            if (!this._canvasIdMap.has(canvasPayload.canvasId)) {
+                var canvas = WebInspector.Canvas.fromPayload(canvasPayload);
+                this._canvasIdMap.set(canvas.id, canvas);
+            }
+        }
+
+        this.dispatchEventToListeners(WebInspector.CanvasManager.Event.CanvasesAvailable);
+    }
+};
+
+WebInspector.CanvasManager.Event = {
+    CanvasesAvailable: "canvas-manager-canvases-available",
+    CanvasWasAdded: "canvas-manager-canvas-was-added",
+    CanvasWasRemoved: "canvas-manager-canvas-was-removed"
+};
diff --git a/Source/WebInspectorUI/UserInterface/Images/Canvas.svg b/Source/WebInspectorUI/UserInterface/Images/Canvas.svg
new file mode 100644 (file)
index 0000000..c3af8fa
--- /dev/null
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright © 2015 Apple Inc. All rights reserved. -->
+<svg viewBox="0 0 14 16" version="1.1" xmlns="http://www.w3.org/2000/svg">
+    <path d="M 0.5 4.29857047 L 7.09714095 7.59714095 L 7.09714095 15.0189245 L 0.5 11.720354 L 0.5 4.29857047 Z" stroke="white" stroke-width="0.5" stroke-linecap="square" stroke-linejoin="round" fill="rgb(92, 140, 229)"/>
+    <path d="M 13.697 4.299 L 7.097 7.597 L 7.097 15.019 L 13.697 11.72 L 13.697 4.299 Z" stroke="white" stroke-width="0.5" stroke-linecap="square" stroke-linejoin="round" fill="rgb(242, 97, 97)"/>
+    <path d="M 0.5 4.29857047 L 7.09714095 1 L 13.6908901 4.29857047 L 7.09714095 7.59714095 L 0.5 4.29857047 Z" stroke="white" stroke-width="0.5" stroke-linejoin="round" fill="rgb(97, 242, 97)"/>
+</svg>
diff --git a/Source/WebInspectorUI/UserInterface/Images/DocumentGL.png b/Source/WebInspectorUI/UserInterface/Images/DocumentGL.png
new file mode 100644 (file)
index 0000000..408ad5a
Binary files /dev/null and b/Source/WebInspectorUI/UserInterface/Images/DocumentGL.png differ
diff --git a/Source/WebInspectorUI/UserInterface/Images/DocumentGL@2x.png b/Source/WebInspectorUI/UserInterface/Images/DocumentGL@2x.png
new file mode 100644 (file)
index 0000000..7c006e3
Binary files /dev/null and b/Source/WebInspectorUI/UserInterface/Images/DocumentGL@2x.png differ
index 028467f..ebbb27d 100644 (file)
 
     <script src="Protocol/ApplicationCacheObserver.js"></script>
     <script src="Protocol/CSSObserver.js"></script>
+    <script src="Protocol/CanvasObserver.js"></script>
     <script src="Protocol/ConsoleObserver.js"></script>
     <script src="Protocol/DOMObserver.js"></script>
     <script src="Protocol/DOMStorageObserver.js"></script>
     <script src="Models/CSSStyleDeclaration.js"></script>
     <script src="Models/CSSStyleSheet.js"></script>
     <script src="Models/CallFrame.js"></script>
+    <script src="Models/Canvas.js"></script>
     <script src="Models/CollectionEntry.js"></script>
     <script src="Models/CollectionEntryPreview.js"></script>
     <script src="Models/Color.js"></script>
     <script src="Models/ScriptSyntaxTree.js"></script>
     <script src="Models/ScriptTimelineRecord.js"></script>
     <script src="Models/Setting.js"></script>
+    <script src="Models/ShaderProgram.js"></script>
     <script src="Models/SourceCodePosition.js"></script>
     <script src="Models/SourceCodeRevision.js"></script>
     <script src="Models/SourceCodeSearchMatchObject.js"></script>
     <script src="Models/TimelineRecording.js"></script>
     <script src="Models/TypeSet.js"></script>
     <script src="Models/UnitBezier.js"></script>
+    <script src="Models/WebGLContextAttributes.js"></script>
 
     <script src="Views/LegacyConsoleMessage.js"></script>
     <script src="Views/ContentView.js"></script>
     <script src="Views/ObjectTreeBaseTreeElement.js"></script>
     <script src="Views/FolderTreeElement.js"></script>
     <script src="Views/FolderizedTreeElement.js"></script>
+    <script src="Views/ShaderProgramTreeElement.js"></script>
     <script src="Views/SourceCodeTreeElement.js"></script>
     <script src="Views/StorageTreeElement.js"></script>
     <script src="Views/TimelineRecordTreeElement.js"></script>
     <script src="Views/CSSStyleDeclarationTextEditor.js"></script>
     <script src="Views/CSSStyleDetailsSidebarPanel.js"></script>
     <script src="Views/CallFrameTreeElement.js"></script>
+    <script src="Views/CanvasTreeElement.js"></script>
     <script src="Views/ClusterContentView.js"></script>
     <script src="Views/CodeMirrorAdditions.js"></script>
     <script src="Views/CodeMirrorFormatters.js"></script>
     <script src="Controllers/BasicBlockAnnotator.js"></script>
     <script src="Controllers/BranchManager.js"></script>
     <script src="Controllers/CSSStyleManager.js"></script>
+    <script src="Controllers/CanvasManager.js"></script>
     <script src="Controllers/CodeMirrorColorEditingController.js"></script>
     <script src="Controllers/CodeMirrorCompletionController.js"></script>
     <script src="Controllers/CodeMirrorDragToAdjustNumberController.js"></script>
diff --git a/Source/WebInspectorUI/UserInterface/Models/Canvas.js b/Source/WebInspectorUI/UserInterface/Models/Canvas.js
new file mode 100644 (file)
index 0000000..96c80ce
--- /dev/null
@@ -0,0 +1,196 @@
+/*
+ * Copyright (C) 2015 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+WebInspector.Canvas = class Canvas extends WebInspector.Object
+{
+    constructor(id, parentFrame, name, cssCanvas, contextType, contextAttributes, programs)
+    {
+        super();
+
+        console.assert(id);
+        console.assert(parentFrame);
+        console.assert(contextType);
+        console.assert(this._contextType !== WebInspector.Canvas.ContextType.WebGL || contextAttributes);
+
+        this._id = id;
+        this._parentFrame = parentFrame;
+        this._name = name;
+        this._cssCanvas = cssCanvas;
+        this._contextType = contextType;
+        this._contextAttributes = contextAttributes;
+        this._programs = new Map;
+
+        if (programs) {
+            for (var program of programs) {
+                program.updateCanvas(this);
+                this._programs.set(program.id.objectId, program);
+            }
+        }
+    }
+
+    // Static
+
+    static fromPayload(payload)
+    {
+        var parentFrame = WebInspector.frameResourceManager.frameForIdentifier(payload.frameId);
+        var 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);
+        }
+
+        var programs = [];
+        for (var programId of payload.programIds)
+            programs.push(new WebInspector.ShaderProgram(programId));
+
+        var contextAttributes = null;
+        if (payload.contextAttributes) {
+            console.assert(contextType === WebInspector.Canvas.ContextType.WebGL);
+            contextAttributes = WebInspector.WebGLContextAttributes.fromPayload(payload.contextAttributes);
+        }
+
+        return new WebInspector.Canvas(payload.canvasId, parentFrame, payload.name, payload.cssCanvas, contextType, contextAttributes, programs);
+    }
+
+    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 id()
+    {
+        return this._id;
+    }
+
+    get parentFrame()
+    {
+        return this._parentFrame;
+    }
+
+    get name()
+    {
+        return this._name;
+    }
+
+    get cssCanvas()
+    {
+        return this._cssCanvas;
+    }
+
+    get contextType()
+    {
+        return this._contextType;
+    }
+
+    get contextAttributes()
+    {
+        return this._contextAttributes;
+    }
+
+    get programs()
+    {
+        var programs = [];
+        for (var program of this._programs.values())
+            programs.push(program);
+        return programs;
+    }
+
+    get displayName()
+    {
+        if (this._cssCanvas)
+            return WebInspector.UIString("CSS canvas “%s”").format(this._name);
+
+        if (this._name)
+            return WebInspector.UIString("Canvas #%s").format(this._name);
+
+        if (!this._uniqueDisplayNameNumber)
+            this._uniqueDisplayNameNumber = this.constructor._nextUniqueDisplayNameNumber++;
+        return WebInspector.UIString("Canvas %d").format(this._uniqueDisplayNameNumber);
+    }
+
+    programForId(programIdentifier)
+    {
+        return this._programs.get(programIdentifier.objectId);
+    }
+
+    programWasCreated(program)
+    {
+        console.assert(!this._programs.has(program.id.objectId));
+        this._programs.set(program.id.objectId, program);
+
+        this.dispatchEventToListeners(WebInspector.Canvas.Event.ProgramWasCreated, {program: program});
+    }
+
+    programWasDeleted(programIdentifier)
+    {
+        var program = this._programs.take(programIdentifier.objectId);
+        console.assert(program);
+
+        this.dispatchEventToListeners(WebInspector.Canvas.Event.ProgramWasDeleted, {program: program});
+    }
+
+    saveIdentityToCookie(cookie)
+    {
+        cookie[WebInspector.Canvas.FrameURLCookieKey] = this.parentFrame.url.hash;
+        cookie[WebInspector.Canvas.CSSCanvasCookieKey] = this._cssCanvas;
+        cookie[WebInspector.Canvas.NameCookieKey] = this._name;
+    }
+};
+
+WebInspector.Canvas.Event = {
+    ProgramWasCreated: "canvas-program-was-created",
+    ProgramWasDeleted: "canvas-program-was-deleted",
+};
+
+WebInspector.Canvas.ContextType = {
+    Canvas2D: Symbol("canvas-context-type-canvas-2d"),
+    WebGL: Symbol("canvas-context-type-webgl"),
+};
+
+WebInspector.Canvas._nextUniqueDisplayNameNumber = 1;
+
+WebInspector.Canvas.FrameURLCookieKey = "canvas-frame-url";
+WebInspector.Canvas.CSSCanvasCookieKey = "canvas-css-canvas";
+WebInspector.Canvas.NameCookieKey = "canvas-name";
diff --git a/Source/WebInspectorUI/UserInterface/Models/ShaderProgram.js b/Source/WebInspectorUI/UserInterface/Models/ShaderProgram.js
new file mode 100644 (file)
index 0000000..12cc3ee
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2015 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+WebInspector.ShaderProgram = class ShaderProgram extends WebInspector.Object
+{
+    constructor(id, canvas)
+    {
+        super();
+
+        this._id = id;
+        this._canvas = canvas || null;
+    }
+
+    // Public
+
+    get id()
+    {
+        return this._id;
+    }
+
+    get canvas()
+    {
+        return this._canvas;
+    }
+
+    get displayName()
+    {
+        return WebInspector.UIString("Program %d").format(this._id.objectId);
+    }
+
+    saveIdentityToCookie(cookie)
+    {
+        cookie[WebInspector.ShaderProgram.FrameURLCookieKey] = this.canvas.parentFrame.url.hash;
+        cookie[WebInspector.ShaderProgram.CanvasNameKey] = this.canvas.name.hash;
+        cookie[WebInspector.ShaderProgram.IDCookieKey] = this._id;
+    }
+
+    updateCanvas(canvas)
+    {
+        // Called by canvas.
+
+        console.assert(!this._canvas);
+        this._canvas = canvas;
+    }
+};
+
+WebInspector.ShaderProgram.FrameURLCookieKey = "shader-program-url";
+WebInspector.ShaderProgram.CanvasNameKey = "shader-program-canvas-name";
+WebInspector.ShaderProgram.IDCookieKey = "shader-program-id";
diff --git a/Source/WebInspectorUI/UserInterface/Models/WebGLContextAttributes.js b/Source/WebInspectorUI/UserInterface/Models/WebGLContextAttributes.js
new file mode 100644 (file)
index 0000000..10b5fd3
--- /dev/null
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2015 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+WebInspector.WebGLContextAttributes = class WebGLContextAttributes extends WebInspector.Object
+{
+    constructor(alpha, depth, stencil, antialias, premultipliedAlpha, preserveDrawingBuffer)
+    {
+        super();
+
+        this._alpha = alpha;
+        this._depth = depth;
+        this._stencil = stencil;
+        this._antialias = antialias;
+        this._premultipliedAlpha = premultipliedAlpha;
+        this._preserveDrawingBuffer = preserveDrawingBuffer;
+    }
+
+    // Static
+
+    static fromPayload(payload)
+    {
+        console.assert(payload);
+        return new WebInspector.WebGLContextAttributes(payload.alpha, payload.depth, payload.stencil, payload.antialias, payload.premultipliedAlpha, payload.preserveDrawingBuffer);
+    }
+
+    // Public
+
+    get alpha()
+    {
+        return this._alpha;
+    }
+
+    get depth()
+    {
+        return this._depth;
+    }
+
+    get stencil()
+    {
+        return this._stencil;
+    }
+
+    get antialias()
+    {
+        return this._antialias;
+    }
+
+    get premultipliedAlpha()
+    {
+        return this._premultipliedAlpha;
+    }
+
+    get preserveDrawingBuffer()
+    {
+        return this._preserveDrawingBuffer;
+    }
+};
diff --git a/Source/WebInspectorUI/UserInterface/Protocol/CanvasObserver.js b/Source/WebInspectorUI/UserInterface/Protocol/CanvasObserver.js
new file mode 100644 (file)
index 0000000..5f9de7c
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2015 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+WebInspector.CanvasObserver = class CanvasObserver
+{
+    // Events defined by the "Canvas" domain.
+
+    canvasAdded(canvas)
+    {
+        WebInspector.canvasManager.canvasAdded(canvas);
+    }
+
+    canvasRemoved(canvasId)
+    {
+        WebInspector.canvasManager.canvasRemoved(canvasId);
+    }
+
+    programCreated(programId)
+    {
+        WebInspector.canvasManager.programCreated(programId);
+    }
+
+    programDeleted(programId)
+    {
+        WebInspector.canvasManager.programDeleted(programId);
+    }
+};
index 8226399..2430f92 100644 (file)
@@ -50,6 +50,7 @@
 
     <script src="Protocol/InspectorObserver.js"></script>
     <script src="Protocol/CSSObserver.js"></script>
+    <script src="Protocol/CanvasObserver.js"></script>
     <script src="Protocol/DOMObserver.js"></script>
     <script src="Protocol/DOMStorageObserver.js"></script>
     <script src="Protocol/DebuggerObserver.js"></script>
@@ -75,6 +76,7 @@
     <script src="Models/CSSStyleDeclaration.js"></script>
     <script src="Models/CSSStyleSheet.js"></script>
     <script src="Models/CallFrame.js"></script>
+    <script src="Models/Canvas.js"></script>
     <script src="Models/CollectionEntry.js"></script>
     <script src="Models/Color.js"></script>
     <script src="Models/ContentFlow.js"></script>
     <script src="Models/ScriptSyntaxTree.js"></script>
     <script src="Models/ScriptTimelineRecord.js"></script>
     <script src="Models/Setting.js"></script>
+    <script src="Models/ShaderProgram.js"></script>
     <script src="Models/SourceCodeLocation.js"></script>
     <script src="Models/SourceCodeRevision.js"></script>
     <script src="Models/SourceCodeTimeline.js"></script>
     <script src="Models/TextRange.js"></script>
     <script src="Models/TimelineMarker.js"></script>
     <script src="Models/TimelineRecording.js"></script>
+    <script src="Models/WebGLContextAttributes.js"></script>
 
     <script src="Controllers/CSSStyleManager.js"></script>
+    <script src="Controllers/CanvasManager.js"></script>
     <script src="Controllers/DOMTreeManager.js"></script>
     <script src="Controllers/DebuggerManager.js"></script>
     <script src="Controllers/FrameResourceManager.js"></script>
diff --git a/Source/WebInspectorUI/UserInterface/Views/CanvasTreeElement.js b/Source/WebInspectorUI/UserInterface/Views/CanvasTreeElement.js
new file mode 100644 (file)
index 0000000..7be72cf
--- /dev/null
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2015 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+WebInspector.CanvasTreeElement = class CanvasTreeElement extends WebInspector.FolderizedTreeElement
+{
+    constructor(canvas)
+    {
+        super("canvas-icon", canvas.displayName, null, canvas, false);
+
+        console.assert(canvas instanceof WebInspector.Canvas);
+
+        this.small = true;
+        this.folderSettingsKey = canvas.parentFrame.url.hash + canvas.displayName.hash;
+
+        this._expandedSetting = new WebInspector.Setting("canvas-expanded-" + this.folderSettingsKey, false);
+        if (this._expandedSetting.value)
+            this.expand();
+        else
+            this.collapse();
+
+        canvas.addEventListener(WebInspector.Canvas.Event.ProgramWasCreated, this._programWasCreated, this);
+        canvas.addEventListener(WebInspector.Canvas.Event.ProgramWasDeleted, this._programWasDeleted, this);
+
+        function validateRepresentedObject(representedObject) {
+            return representedObject instanceof WebInspector.ShaderProgram;
+        }
+
+        function countChildren() {
+            return canvas.programs.length;
+        }
+
+        this.registerFolderizeSettings("programs", WebInspector.UIString("Programs"), validateRepresentedObject, countChildren.bind(this), WebInspector.ShaderProgramTreeElement);
+        this.updateParentStatus();
+    }
+
+    // Overrides from TreeElement (Protected).
+
+    onexpand()
+    {
+        this._expandedSetting.value = true;
+    }
+
+    oncollapse()
+    {
+        // Only store the setting if we have children, since setting hasChildren to false will cause a collapse,
+        // and we only care about user triggered collapses.
+        if (this.hasChildren)
+            this._expandedSetting.value = false;
+    }
+
+    onpopulate()
+    {
+        if (this.children.length && !this.shouldRefreshChildren)
+            return;
+
+        this.shouldRefreshChildren = false;
+
+        this.removeChildren();
+
+        for (var program of this.representedObject.programs)
+            this.addChildForRepresentedObject(program);
+    }
+
+    // Private
+
+    _programWasCreated(event)
+    {
+        this.addRepresentedObjectToNewChildQueue(event.data.program);
+    }
+
+    _programWasDeleted(event)
+    {
+        this.removeChildForRepresentedObject(event.data.program);
+    }
+};
index ae2ba79..35af996 100644 (file)
@@ -63,6 +63,12 @@ WebInspector.FrameTreeElement = class FrameTreeElement extends WebInspector.Reso
             WebInspector.ContentFlowTreeElement
         );
 
+        this.registerFolderizeSettings("canvases", WebInspector.UIString("Canvases"),
+            function(representedObject) { return representedObject instanceof WebInspector.Canvas; },
+            function() { return WebInspector.canvasManager.canvasesForFrame(this._frame).length; }.bind(this),
+            WebInspector.CanvasTreeElement
+        );
+
         function makeValidateCallback(resourceType) {
             return function(representedObject) {
                 return representedObject instanceof WebInspector.Resource && representedObject.type === resourceType;
@@ -136,6 +142,10 @@ WebInspector.FrameTreeElement = class FrameTreeElement extends WebInspector.Reso
         // Immediate superclasses are skipped, since Frames handle their own SourceMapResources.
         WebInspector.GeneralTreeElement.prototype.onattach.call(this);
 
+        WebInspector.canvasManager.addEventListener(WebInspector.CanvasManager.Event.CanvasesAvailable, this._canvasesAvailable, this);
+        WebInspector.canvasManager.addEventListener(WebInspector.CanvasManager.Event.CanvasWasAdded, this._canvasWasAdded, this);
+        WebInspector.canvasManager.addEventListener(WebInspector.CanvasManager.Event.CanvasWasRemoved, this._canvasWasRemoved, this);
+
         if (this._frame.isMainFrame()) {
             WebInspector.notifications.addEventListener(WebInspector.Notification.PageArchiveStarted, this._pageArchiveStarted, this);
             WebInspector.notifications.addEventListener(WebInspector.Notification.PageArchiveEnded, this._pageArchiveEnded, this);
@@ -146,6 +156,10 @@ WebInspector.FrameTreeElement = class FrameTreeElement extends WebInspector.Reso
     {
         WebInspector.ResourceTreeElement.prototype.ondetach.call(this);
 
+        WebInspector.canvasManager.removeEventListener(WebInspector.CanvasManager.Event.CanvasesAvailable, this._canvasesAvailable, this);
+        WebInspector.canvasManager.removeEventListener(WebInspector.CanvasManager.Event.CanvasWasAdded, this._canvasWasAdded, this);
+        WebInspector.canvasManager.removeEventListener(WebInspector.CanvasManager.Event.CanvasWasRemoved, this._canvasWasRemoved, this);
+
         if (this._frame.isMainFrame()) {
             WebInspector.notifications.removeEventListener(WebInspector.Notification.PageArchiveStarted, this._pageArchiveStarted, this);
             WebInspector.notifications.removeEventListener(WebInspector.Notification.PageArchiveEnded, this._pageArchiveEnded, this);
@@ -250,8 +264,11 @@ WebInspector.FrameTreeElement = class FrameTreeElement extends WebInspector.Reso
         for (var flowKey in flowMap)
             this.addChildForRepresentedObject(flowMap[flowKey]);
 
+        var canvases = WebInspector.canvasManager.canvasesForFrame(this._frame);
+        for (var canvas of canvases)
+            this.addChildForRepresentedObject(canvas);
     }
-
+        
     onexpand()
     {
         this._expandedSetting.value = true;
@@ -324,6 +341,28 @@ WebInspector.FrameTreeElement = class FrameTreeElement extends WebInspector.Reso
         this.removeChildForRepresentedObject(event.data.flow);
     }
 
+    _canvasesAvailable(event)
+    {
+        this.updateParentStatus();
+        this.removeChildren();
+
+        this.shouldRefreshChildren = true;
+    }
+
+    _canvasWasAdded(event)
+    {
+        var canvas = event.data.canvas;
+        if (canvas.parentFrame == this._frame)
+            this.addRepresentedObjectToNewChildQueue(canvas);
+    }
+
+    _canvasWasRemoved(event)
+    {
+        var canvas = event.data.canvas;
+        if (canvas.parentFrame == this._frame)
+            this.removeChildForRepresentedObject(canvas);
+    }
+
     _rootDOMNodeInvalidated()
     {
         if (this.expanded)
index f3e22ed..dd9ae53 100644 (file)
     content: -webkit-image-set(url(../Images/ClippingJS.png) 1x, url(../Images/ClippingJS@2x.png) 2x);
 }
 
+.canvas-icon .icon {
+    content: url(../Images/Canvas.svg);
+}
+
+.shader-program-icon .icon {
+    content: -webkit-image-set(url(../Images/DocumentGL.png) 1x, url(../Images/DocumentGL@2x.png) 2x);
+}
+
 .source-map-resource.resource-icon .icon {
     content: -webkit-image-set(url(../Images/ClippingGeneric.png) 1x, url(../Images/ClippingGeneric@2x.png) 2x);
 }
index 8a0b92a..b67c2ec 100644 (file)
@@ -774,6 +774,7 @@ WebInspector.ResourceSidebarPanel = class ResourceSidebarPanel extends WebInspec
         if (treeElement instanceof WebInspector.ResourceTreeElement || treeElement instanceof WebInspector.ScriptTreeElement ||
             treeElement instanceof WebInspector.StorageTreeElement || treeElement instanceof WebInspector.DatabaseTableTreeElement ||
             treeElement instanceof WebInspector.DatabaseTreeElement || treeElement instanceof WebInspector.ApplicationCacheFrameTreeElement ||
+            treeElement instanceof WebInspector.CanvasTreeElement || treeElement instanceof WebInspector.ShaderProgramTreeElement ||
             treeElement instanceof WebInspector.ContentFlowTreeElement || treeElement instanceof WebInspector.IndexedDatabaseObjectStoreTreeElement ||
             treeElement instanceof WebInspector.IndexedDatabaseObjectStoreIndexTreeElement) {
             WebInspector.contentBrowser.showContentViewForRepresentedObject(treeElement.representedObject);
diff --git a/Source/WebInspectorUI/UserInterface/Views/ShaderProgramTreeElement.js b/Source/WebInspectorUI/UserInterface/Views/ShaderProgramTreeElement.js
new file mode 100644 (file)
index 0000000..8c57b0c
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2015 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+WebInspector.ShaderProgramTreeElement = class ShaderProgramTreeElement extends WebInspector.GeneralTreeElement
+{
+    constructor(program)
+    {
+        super("shader-program-icon", program.displayName, null, program, false);
+
+        console.assert(program instanceof WebInspector.ShaderProgram);
+
+        this.small = true;
+    }
+};
index f529543..c49f55e 100644 (file)
     <None Include="..\UserInterface\CallFrame.js" />
     <None Include="..\UserInterface\CallFrameIcons.css" />
     <None Include="..\UserInterface\CallFrameTreeElement.js" />
+    <None Include="..\UserInterface\Canvas.js" />
     <None Include="..\UserInterface\CanvasDataGridNode.js" />
+    <None Include="..\UserInterface\CanvasManager.js" />
     <None Include="..\UserInterface\CanvasObserver.js" />
     <None Include="..\UserInterface\CanvasProfileObject.js" />
     <None Include="..\UserInterface\CanvasProfileType.js" />
     <None Include="..\UserInterface\CanvasProfileView.js" />
+    <None Include="..\UserInterface\CanvasTreeElement.js" />
     <None Include="..\UserInterface\ClusterContentView.css" />
     <None Include="..\UserInterface\ClusterContentView.js" />
     <None Include="..\UserInterface\CodeMirrorAdditions.js" />
     <None Include="..\UserInterface\Images\BreakpointInactive.png" />
     <None Include="..\UserInterface\Images\BreakpointInactiveButton.svg" />
     <None Include="..\UserInterface\Images\Breakpoints.svg" />
+    <None Include="..\UserInterface\Images\Canvas.svg" />
     <None Include="..\UserInterface\Images\ClippingCSS%402x.png" />
     <None Include="..\UserInterface\Images\ClippingCSS.png" />
     <None Include="..\UserInterface\Images\ClippingGeneric%402x.png" />
     <None Include="..\UserInterface\Images\Script.png" />
     <None Include="..\UserInterface\Images\SessionStorage%402x.png" />
     <None Include="..\UserInterface\Images\SessionStorage.png" />
+    <None Include="..\UserInterface\Images\ShaderProgram%402x.png" />
+    <None Include="..\UserInterface\Images\ShaderProgram.png" />
     <None Include="..\UserInterface\Images\ShadowDOM.svg" />
     <None Include="..\UserInterface\Images\SortIndicatorDownArrow.svg" />
     <None Include="..\UserInterface\Images\SortIndicatorUpArrow.svg" />
     <None Include="..\UserInterface\Section.css" />
     <None Include="..\UserInterface\Section.js" />
     <None Include="..\UserInterface\Setting.js" />
+    <None Include="..\UserInterface\ShaderProgram.js" />
+    <None Include="..\UserInterface\ShaderProgramTreeElement.js" />
     <None Include="..\UserInterface\Sidebar.css" />
     <None Include="..\UserInterface\Sidebar.js" />
     <None Include="..\UserInterface\SidebarPanel.css" />
index 6d17aa8..83b9958 100644 (file)
     <None Include="..\UserInterface\CallFrameTreeElement.js">
       <Filter>UserInterface</Filter>
     </None>
+    <None Include="..\UserInterface\Canvas.js">
+      <Filter>UserInterface</Filter>
+    </None>
     <None Include="..\UserInterface\CanvasDataGridNode.js">
       <Filter>UserInterface</Filter>
     </None>
+    <None Include="..\UserInterface\CanvasManager.js">
+      <Filter>UserInterface</Filter>
+    </None>
     <None Include="..\UserInterface\CanvasObserver.js">
       <Filter>UserInterface</Filter>
     </None>
     <None Include="..\UserInterface\CanvasProfileView.js">
       <Filter>UserInterface</Filter>
     </None>
+    <None Include="..\UserInterface\CanvasTreeElement.js">
+      <Filter>UserInterface</Filter>
+    </None>
     <None Include="..\UserInterface\ClusterContentView.css">
       <Filter>UserInterface</Filter>
     </None>
     <None Include="..\UserInterface\Setting.js">
       <Filter>UserInterface</Filter>
     </None>
+    <None Include="..\UserInterface\ShaderProgram.js">
+      <Filter>UserInterface</Filter>
+    </None>
+    <None Include="..\UserInterface\ShaderProgramTreeElement.js">
+      <Filter>UserInterface</Filter>
+    </None>
     <None Include="..\UserInterface\Sidebar.css">
       <Filter>UserInterface</Filter>
     </None>
     <None Include="..\UserInterface\Images\Breakpoints.svg">
       <Filter>Images</Filter>
     </None>
+    <None Include="..\UserInterface\Images\Canvas.svg">
+      <Filter>Images</Filter>
+    </None>
     <None Include="..\UserInterface\Images\ClippingCSS.png">
       <Filter>Images</Filter>
     </None>
     <None Include="..\UserInterface\Images\SessionStorage%402x.png">
       <Filter>Images</Filter>
     </None>
+    <None Include="..\UserInterface\Images\ShaderProgram%402x.png">
+      <Filter>Images</Filter>
+    </None>
+    <None Include="..\UserInterface\Images\ShaderProgram.png">
+      <Filter>Images</Filter>
+    </None>
     <None Include="..\UserInterface\Images\ShadowDOM.svg">
       <Filter>Images</Filter>
     </None>