Provide the backend for exposing the layer tree to the Web Inspector
authorcommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 7 Dec 2012 17:54:54 +0000 (17:54 +0000)
committercommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 7 Dec 2012 17:54:54 +0000 (17:54 +0000)
https://bugs.webkit.org/show_bug.cgi?id=103513

Patch by Antoine Quint <graouts@apple.com> on 2012-12-07
Reviewed by Pavel Feldman.

Source/WebCore:

The purpose of this patch is to provide a new agent enabling the Web Inspector to interface
with WebCore to access information about the render layer tree and, more specifically, expose
useful information about layers backed by textures composited on the GPU such as metrics and
backing store. Thus we now provide a LayerTreeAgent which will inform the front-end of
changes to the render layer tree via a new layerTreeDidChange event, providing an object
containing the entire hierarchy of RenderLayers for the inspected document. This hierarchy
can be queried at any time using the .getLayerTree() method on the LayerTreeAgent. Finally,
the LayerTreeAgent also exposes a .nodeIdForLayerId() method allowing to get the id of the
node associated with the RenderLayer with the provided layer id.

In terms of implementation, RenderLayerCompositor has been changed such that in its
updateCompositingLayers() method we call the layerTreeDidChange method on the
InspectorLayerTreeAgent instance via the InspectorInstrumentation.

Test: inspector-protocol/layer-tree.html

* CMakeLists.txt:
* GNUmakefile.list.am:
* Target.pri:
* WebCore.gypi:
* WebCore.vcproj/WebCore.vcproj:
* WebCore.xcodeproj/project.pbxproj:
* inspector/Inspector.json: Define new types IntRect (x, y, width, height) and Layer, which
holds the information for a RenderLayer (layerId, bounds, isComposited, memory,
compositedBounds) and its children (childLayers). We also define the methods of the
LayerTreeAgent object (enable, disable, getLayerTree, nodeIdForLayerId) and the
layerTreeDidChange event it
fires.
* inspector/InspectorAllInOne.cpp:
* inspector/InspectorController.cpp:
(WebCore::InspectorController::InspectorController):
* inspector/InspectorDOMAgent.cpp:
(WebCore::InspectorDOMAgent::pushNodePathForRenderLayerToFrontend): New method facilitating
pushing the node associated with a given RenderLayer to the front-end.
(WebCore):
* inspector/InspectorDOMAgent.h:
(InspectorDOMAgent):
* inspector/InspectorInstrumentation.cpp:
(WebCore):
(WebCore::InspectorInstrumentation::didCommitLoadImpl):
(WebCore::InspectorInstrumentation::layerTreeDidChangeImpl):
(WebCore::InspectorInstrumentation::renderLayerDestroyedImpl):
* inspector/InspectorInstrumentation.h:
(WebCore):
(InspectorInstrumentation):
(WebCore::InspectorInstrumentation::layerTreeDidChange):
(WebCore::InspectorInstrumentation::renderLayerDestroyed):
* inspector/InspectorLayerTreeAgent.cpp: Added.
(WebCore):
(LayerTreeAgentState):
(WebCore::InspectorLayerTreeAgent::InspectorLayerTreeAgent):
(WebCore::InspectorLayerTreeAgent::~InspectorLayerTreeAgent):
(WebCore::InspectorLayerTreeAgent::setFrontend):
(WebCore::InspectorLayerTreeAgent::clearFrontend):
(WebCore::InspectorLayerTreeAgent::restore):
(WebCore::InspectorLayerTreeAgent::reset):
(WebCore::InspectorLayerTreeAgent::enable):
(WebCore::InspectorLayerTreeAgent::disable):
(WebCore::InspectorLayerTreeAgent::layerTreeDidChange):
(WebCore::InspectorLayerTreeAgent::renderLayerDestroyed):
(WebCore::InspectorLayerTreeAgent::getLayerTree):
(WebCore::InspectorLayerTreeAgent::buildObjectForRootLayer):
(WebCore::InspectorLayerTreeAgent::buildObjectForLayer): Build the entire hierarchy of
RenderLayers from the provided RenderLayer.
(WebCore::InspectorLayerTreeAgent::buildObjectForIntRect):
(WebCore::InspectorLayerTreeAgent::bind):
(WebCore::InspectorLayerTreeAgent::unbind):
(WebCore::InspectorLayerTreeAgent::nodeIdForLayerId):
* inspector/InspectorLayerTreeAgent.h: Added.
(WebCore):
(InspectorLayerTreeAgent):
(WebCore::InspectorLayerTreeAgent::create):
* inspector/InstrumentingAgents.h:
(WebCore):
(WebCore::InstrumentingAgents::InstrumentingAgents):
(InstrumentingAgents):
(WebCore::InstrumentingAgents::inspectorLayerTreeAgent):
(WebCore::InstrumentingAgents::setInspectorLayerTreeAgent):
* rendering/RenderLayerCompositor.cpp:
(WebCore::RenderLayerCompositor::updateCompositingLayers): Call the layerTreeDidChange method
on the LayerTreeAgent via the InspectorInstrumentation to inform the front-end that the
RenderLayer hierarchy has changed.
(WebCore):
(WebCore::RenderLayerCompositor::layerBecameNonComposited): Call the renderLayerDestroyed
method on the LayerTreeAgent via the InspectorInstrumentation to unbind the layer that is
being destroyed.
* rendering/RenderLayerCompositor.h:
(RenderLayerCompositor):

LayoutTests:

Adding a LayoutTest that exercises the various APIs and event exposed by the LayerTreeAgent.
This test is skipped on EFL where ACCELERATED_COMPOSITING is not available.

* inspector-protocol/layer-tree-expected.txt: Added.
* inspector-protocol/layer-tree.html: Added.
* platform/efl/TestExpectations:

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

23 files changed:
LayoutTests/ChangeLog
LayoutTests/inspector-protocol/layer-tree-expected.txt [new file with mode: 0644]
LayoutTests/inspector-protocol/layer-tree.html [new file with mode: 0644]
LayoutTests/platform/efl/TestExpectations
Source/WebCore/CMakeLists.txt
Source/WebCore/ChangeLog
Source/WebCore/GNUmakefile.list.am
Source/WebCore/Target.pri
Source/WebCore/WebCore.gypi
Source/WebCore/WebCore.vcproj/WebCore.vcproj
Source/WebCore/WebCore.xcodeproj/project.pbxproj
Source/WebCore/inspector/Inspector.json
Source/WebCore/inspector/InspectorAllInOne.cpp
Source/WebCore/inspector/InspectorController.cpp
Source/WebCore/inspector/InspectorDOMAgent.cpp
Source/WebCore/inspector/InspectorDOMAgent.h
Source/WebCore/inspector/InspectorInstrumentation.cpp
Source/WebCore/inspector/InspectorInstrumentation.h
Source/WebCore/inspector/InspectorLayerTreeAgent.cpp [new file with mode: 0644]
Source/WebCore/inspector/InspectorLayerTreeAgent.h [new file with mode: 0644]
Source/WebCore/inspector/InstrumentingAgents.h
Source/WebCore/rendering/RenderLayerCompositor.cpp
Source/WebCore/rendering/RenderLayerCompositor.h

index 1e6ca78..196ca12 100644 (file)
@@ -1,3 +1,17 @@
+2012-12-07  Antoine Quint  <graouts@apple.com>
+
+        Provide the backend for exposing the layer tree to the Web Inspector
+        https://bugs.webkit.org/show_bug.cgi?id=103513
+
+        Reviewed by Pavel Feldman.
+
+        Adding a LayoutTest that exercises the various APIs and event exposed by the LayerTreeAgent.
+        This test is skipped on EFL where ACCELERATED_COMPOSITING is not available.
+
+        * inspector-protocol/layer-tree-expected.txt: Added.
+        * inspector-protocol/layer-tree.html: Added.
+        * platform/efl/TestExpectations:
+
 2012-12-07  Zan Dobersek  <zandobersek@gmail.com>
 
         Unreviewed GTK gardening.
diff --git a/LayoutTests/inspector-protocol/layer-tree-expected.txt b/LayoutTests/inspector-protocol/layer-tree-expected.txt
new file mode 100644 (file)
index 0000000..5ba75fe
--- /dev/null
@@ -0,0 +1,363 @@
+
+=== Get the Document ===
+
+PASS
+
+=== Enable the LayerTree agent ===
+
+PASS
+
+=== Get the initial layer tree ===
+
+PASS
+
+{
+    "layerId": "string",
+    "bounds": {
+        "x": 0,
+        "y": 0,
+        "width": "number",
+        "height": "number"
+    },
+    "isComposited": true,
+    "memory": "number",
+    "compositedBounds": {
+        "x": 0,
+        "y": 0,
+        "width": "number",
+        "height": "number"
+    },
+    "childLayers": [
+        {
+            "layerId": "string",
+            "bounds": {
+                "x": 0,
+                "y": 0,
+                "width": "number",
+                "height": "number"
+            },
+            "isComposited": false,
+            "childLayers": [
+                {
+                    "layerId": "string",
+                    "bounds": {
+                        "x": 0,
+                        "y": 0,
+                        "width": 100,
+                        "height": 100
+                    },
+                    "isComposited": false,
+                    "childLayers": []
+                },
+                {
+                    "layerId": "string",
+                    "bounds": {
+                        "x": 0,
+                        "y": 0,
+                        "width": 50,
+                        "height": 50
+                    },
+                    "isComposited": true,
+                    "memory": "number",
+                    "compositedBounds": {
+                        "x": 0,
+                        "y": 0,
+                        "width": 50,
+                        "height": 50
+                    },
+                    "childLayers": [
+                        {
+                            "layerId": "string",
+                            "bounds": {
+                                "x": 0,
+                                "y": 0,
+                                "width": 50,
+                                "height": 50
+                            },
+                            "isComposited": true,
+                            "memory": "number",
+                            "compositedBounds": {
+                                "x": 0,
+                                "y": 0,
+                                "width": 50,
+                                "height": 50
+                            },
+                            "childLayers": []
+                        }
+                    ]
+                },
+                {
+                    "layerId": "string",
+                    "bounds": {
+                        "x": 0,
+                        "y": 0,
+                        "width": 100,
+                        "height": 100
+                    },
+                    "isComposited": true,
+                    "memory": "number",
+                    "compositedBounds": {
+                        "x": 0,
+                        "y": 0,
+                        "width": 100,
+                        "height": 100
+                    },
+                    "childLayers": [
+                        {
+                            "layerId": "string",
+                            "bounds": {
+                                "x": 0,
+                                "y": 0,
+                                "width": 50,
+                                "height": 50
+                            },
+                            "isComposited": true,
+                            "memory": "number",
+                            "compositedBounds": {
+                                "x": 0,
+                                "y": 0,
+                                "width": 50,
+                                "height": 50
+                            },
+                            "childLayers": []
+                        }
+                    ]
+                },
+                {
+                    "layerId": "string",
+                    "bounds": {
+                        "x": 0,
+                        "y": 0,
+                        "width": 0,
+                        "height": 0
+                    },
+                    "isComposited": false,
+                    "childLayers": []
+                },
+                {
+                    "layerId": "string",
+                    "bounds": {
+                        "x": 0,
+                        "y": 0,
+                        "width": 0,
+                        "height": 0
+                    },
+                    "isComposited": false,
+                    "childLayers": []
+                },
+                {
+                    "layerId": "string",
+                    "bounds": {
+                        "x": 0,
+                        "y": 0,
+                        "width": "number",
+                        "height": "number"
+                    },
+                    "isComposited": true,
+                    "memory": "number",
+                    "compositedBounds": {
+                        "x": 0,
+                        "y": 0,
+                        "width": "number",
+                        "height": "number"
+                    },
+                    "childLayers": []
+                }
+            ]
+        }
+    ]
+}
+
+=== Message the page to add a new composited layer ===
+
+PASS
+
+=== Get the modified layer tree ===
+
+PASS
+
+{
+    "layerId": "string",
+    "bounds": {
+        "x": 0,
+        "y": 0,
+        "width": "number",
+        "height": "number"
+    },
+    "isComposited": true,
+    "memory": "number",
+    "compositedBounds": {
+        "x": 0,
+        "y": 0,
+        "width": "number",
+        "height": "number"
+    },
+    "childLayers": [
+        {
+            "layerId": "string",
+            "bounds": {
+                "x": 0,
+                "y": 0,
+                "width": "number",
+                "height": "number"
+            },
+            "isComposited": false,
+            "childLayers": [
+                {
+                    "layerId": "string",
+                    "bounds": {
+                        "x": 0,
+                        "y": 0,
+                        "width": 100,
+                        "height": 100
+                    },
+                    "isComposited": false,
+                    "childLayers": []
+                },
+                {
+                    "layerId": "string",
+                    "bounds": {
+                        "x": 0,
+                        "y": 0,
+                        "width": 50,
+                        "height": 50
+                    },
+                    "isComposited": true,
+                    "memory": "number",
+                    "compositedBounds": {
+                        "x": 0,
+                        "y": 0,
+                        "width": 50,
+                        "height": 50
+                    },
+                    "childLayers": [
+                        {
+                            "layerId": "string",
+                            "bounds": {
+                                "x": 0,
+                                "y": 0,
+                                "width": 50,
+                                "height": 50
+                            },
+                            "isComposited": true,
+                            "memory": "number",
+                            "compositedBounds": {
+                                "x": 0,
+                                "y": 0,
+                                "width": 50,
+                                "height": 50
+                            },
+                            "childLayers": []
+                        }
+                    ]
+                },
+                {
+                    "layerId": "string",
+                    "bounds": {
+                        "x": 0,
+                        "y": 0,
+                        "width": 100,
+                        "height": 100
+                    },
+                    "isComposited": true,
+                    "memory": "number",
+                    "compositedBounds": {
+                        "x": 0,
+                        "y": 0,
+                        "width": 100,
+                        "height": 100
+                    },
+                    "childLayers": [
+                        {
+                            "layerId": "string",
+                            "bounds": {
+                                "x": 0,
+                                "y": 0,
+                                "width": 50,
+                                "height": 50
+                            },
+                            "isComposited": true,
+                            "memory": "number",
+                            "compositedBounds": {
+                                "x": 0,
+                                "y": 0,
+                                "width": 50,
+                                "height": 50
+                            },
+                            "childLayers": []
+                        }
+                    ]
+                },
+                {
+                    "layerId": "string",
+                    "bounds": {
+                        "x": 0,
+                        "y": 0,
+                        "width": 0,
+                        "height": 0
+                    },
+                    "isComposited": false,
+                    "childLayers": []
+                },
+                {
+                    "layerId": "string",
+                    "bounds": {
+                        "x": 0,
+                        "y": 0,
+                        "width": 0,
+                        "height": 0
+                    },
+                    "isComposited": false,
+                    "childLayers": []
+                },
+                {
+                    "layerId": "string",
+                    "bounds": {
+                        "x": 0,
+                        "y": 0,
+                        "width": "number",
+                        "height": "number"
+                    },
+                    "isComposited": true,
+                    "memory": "number",
+                    "compositedBounds": {
+                        "x": 0,
+                        "y": 0,
+                        "width": "number",
+                        "height": "number"
+                    },
+                    "childLayers": []
+                },
+                {
+                    "layerId": "string",
+                    "bounds": {
+                        "x": 0,
+                        "y": 0,
+                        "width": 50,
+                        "height": 50
+                    },
+                    "isComposited": true,
+                    "memory": "number",
+                    "compositedBounds": {
+                        "x": 0,
+                        "y": 0,
+                        "width": 50,
+                        "height": 50
+                    },
+                    "childLayers": []
+                }
+            ]
+        }
+    ]
+}
+
+=== Obtain the node id for the newly inserted layer ===
+
+PASS
+
+=== Get attributes for the newly inserted node ===
+
+PASS
+
+=== Test complete, all expected conditions met ===
+
diff --git a/LayoutTests/inspector-protocol/layer-tree.html b/LayoutTests/inspector-protocol/layer-tree.html
new file mode 100644 (file)
index 0000000..1a1bc62
--- /dev/null
@@ -0,0 +1,250 @@
+<html>
+<head>
+<script type="text/javascript" src="../http/tests/inspector-protocol/resources/protocol-test.js"></script>
+<script type="text/javascript">
+
+function addCompositedLayer()
+{
+    var element = document.createElement("div");
+    element.className = "composited";
+    element.id = "last-element";
+    document.body.appendChild(element);
+};
+
+function test()
+{
+    var initialLayerTree;
+    var eventsCount = 0;
+
+    InspectorTest.eventHandler["LayerTree.layerTreeDidChange"] = function (messageObject) {
+        eventsCount++;
+    };
+
+    getDocument();
+    
+    function getDocument()
+    {
+        // We must first get the document so that later on we may get sensible nodeIds.
+        step({
+            name: "Get the Document",
+            command: "DOM.getDocument",
+            parameters: {},
+            callback: enableLayerTreeAgent
+        });
+    };
+    
+    function enableLayerTreeAgent(result)
+    {
+        step({
+            name: "Enable the LayerTree agent",
+            command: "LayerTree.enable",
+            parameters: {},
+            callback: getInitialLayerTree
+        });
+    };
+
+    function getInitialLayerTree(result)
+    {
+        step({
+            name: "Get the initial layer tree",
+            command: "LayerTree.getLayerTree",
+            parameters: {},
+            callback: gotInitialLayerTree
+        });
+    };
+
+    function gotInitialLayerTree(result)
+    {
+        initialLayerTree = result.layerTree;
+
+        dumpLayerTree(initialLayerTree);
+
+        step({
+            name: "Message the page to add a new composited layer",
+            command: "Runtime.evaluate",
+            parameters: {"expression": "addCompositedLayer()"},
+            callback: getModifiedLayerTree
+        });
+    };
+
+    function getModifiedLayerTree(result)
+    {
+        step({
+            name: "Get the modified layer tree",
+            command: "LayerTree.getLayerTree",
+            parameters: {},
+            callback: gotModifiedLayerTree
+        });
+    };
+
+    var layerCount = 0;
+
+    function gotModifiedLayerTree(result)
+    {
+        dumpLayerTree(result.layerTree);
+
+        var mutations = layerTreeMutations(initialLayerTree, result.layerTree);
+        var lastId = mutations.additions[0];
+
+        step({
+            name: "Obtain the node id for the newly inserted layer",
+            command: "LayerTree.nodeIdForLayerId",
+            parameters: {"layerId": lastId},
+            callback: gotNodeIdForLastLayer
+        });
+    };
+
+    function gotNodeIdForLastLayer(result)
+    {
+        var id = result.nodeId;
+        step({
+            name: "Get attributes for the newly inserted node",
+            command: "DOM.getAttributes",
+            parameters: {"nodeId": id},
+            callback: gotNodeAttributes
+        });
+    };
+
+    function gotNodeAttributes(result)
+    {
+        var attributes = attributesDictionaryFromArray(result.attributes);
+        if (attributes.id !== "last-element")
+            InspectorTest.log("FAIL: Did not obtain the expected element for the last inserted layer.");
+
+        finishTest();
+    };
+
+    function finishTest()
+    {
+        if (!eventsCount)
+            InspectorTest.log("FAIL: Did not receive layerTreeDidChange events.");
+        else
+            InspectorTest.log("\n=== Test complete, all expected conditions met ===");
+
+        InspectorTest.completeTest();
+    };
+
+    function layerTreeMutations(oldLayerTree, newLayerTree)
+    {
+        var oldKeys = Object.keys(flattenedLayerTree(oldLayerTree));
+        var newKeys = Object.keys(flattenedLayerTree(newLayerTree));
+
+        return {
+            additions: newKeys.filter(function (key) {
+                return (oldKeys.indexOf(key) === -1);
+            }),
+            removals: oldKeys.filter(function (key) {
+                return (newKeys.indexOf(key) === -1);
+            })
+        };
+    };
+
+    function flattenedLayerTree(layerTree)
+    {
+        var layerByIds = {};
+
+        function recurse(layer)
+        {
+            layerByIds[layer.layerId] = layer;
+            if (layer.childLayers)
+                layer.childLayers.forEach(recurse);
+        };
+        
+        recurse(layerTree);
+
+        return layerByIds;
+    };
+
+    function attributesDictionaryFromArray(attributes)
+    {
+        var dictionary = {}
+        for (var i = 0, count = attributes.length; i < count; i += 2) {
+            dictionary[attributes[i]] = attributes[i + 1];
+        }
+        return dictionary;
+    };
+
+    function dumpLayerTree(layerTree)
+    {
+        function replacer(key, value)
+        {
+            if (key === "layerId" || key === "memory")
+                return typeof(value);
+
+            // some values differ based on port, but the ones we most
+            // care about will always be less or equal 100.
+            if ((key === "width" || key === "height") && value > 100) 
+                return typeof(value);
+            
+            return value;
+        };
+        
+        InspectorTest.log("\n" + JSON.stringify(layerTree, replacer, "    "));
+    };
+
+    function step(test)
+    {
+        InspectorTest.log("\n=== " + test.name + " ===\n")
+        InspectorTest.sendCommand(test.command, test.parameters, function(messageObject) {
+            if (messageObject.hasOwnProperty("error")) {
+                InspectorTest.log("FAIL: " + messageObject.error.message + " (" + messageObject.error.code + ")");
+                InspectorTest.completeTest();
+                return;
+            }
+
+            InspectorTest.log("PASS");
+            test.callback(messageObject.result);
+        });
+    };
+
+};
+
+window.addEventListener("DOMContentLoaded", function () {
+    runTest();
+}, false);
+
+</script>
+<style type="text/css">
+      
+    div {
+        position: absolute;
+        top: 0;
+        left: 0;
+    }
+      
+    .regular {
+        width: 100px;
+        height: 100px;
+        background-color: black;
+    }
+
+    .composited {
+        top: 25px;
+        left: 25px;
+        width: 50px;
+        height: 50px;
+        background-color: blue;
+        -webkit-transform: translateZ(0);
+    }
+      
+    .offset {
+        left: 200px;
+        -webkit-transform: translateZ(0);
+    }
+
+</style>
+</head>
+<body>
+
+    <div class="regular"></div>
+
+    <div class="composited">
+        <div class="composited"></div>
+    </div>
+
+    <div class="regular offset">
+        <div class="composited"></div>
+    </div>
+
+</body>
+</html>
index d1b4773..b8d423b 100644 (file)
@@ -1119,6 +1119,7 @@ webkit.org/b/79766 compositing/tiling/tile-cache-zoomed.html [ Failure ]
 webkit.org/b/79766 compositing/video/video-poster.html [ Failure ]
 webkit.org/b/79766 compositing/geometry/fixed-position-composited-switch.html [ Failure ]
 webkit.org/b/79766 compositing/visibility/visibility-image-layers-dynamic.html [ Failure ]
+webkit.org/b/104372 inspector-protocol/layer-tree.html [ Skip ]
 
 # LAYER_TREE_INCLUDES_VISIBLE_RECTS option to layerTreeAsText is only applicable to Mac.
 compositing/visible-rect [ Skip ]
index 2d16a16..188f311 100644 (file)
@@ -1603,6 +1603,7 @@ set(WebCore_SOURCES
     inspector/InspectorIndexedDBAgent.cpp
     inspector/InspectorInputAgent.cpp
     inspector/InspectorInstrumentation.cpp
+    inspector/InspectorLayerTreeAgent.cpp
     inspector/InspectorMemoryAgent.cpp
     inspector/InspectorOverlay.cpp
     inspector/InspectorProfilerAgent.cpp
index ec6e9a6..b305a6f 100644 (file)
@@ -1,3 +1,99 @@
+2012-12-07  Antoine Quint  <graouts@apple.com>
+
+        Provide the backend for exposing the layer tree to the Web Inspector
+        https://bugs.webkit.org/show_bug.cgi?id=103513
+
+        Reviewed by Pavel Feldman.
+
+        The purpose of this patch is to provide a new agent enabling the Web Inspector to interface
+        with WebCore to access information about the render layer tree and, more specifically, expose
+        useful information about layers backed by textures composited on the GPU such as metrics and
+        backing store. Thus we now provide a LayerTreeAgent which will inform the front-end of 
+        changes to the render layer tree via a new layerTreeDidChange event, providing an object
+        containing the entire hierarchy of RenderLayers for the inspected document. This hierarchy 
+        can be queried at any time using the .getLayerTree() method on the LayerTreeAgent. Finally, 
+        the LayerTreeAgent also exposes a .nodeIdForLayerId() method allowing to get the id of the 
+        node associated with the RenderLayer with the provided layer id.
+        
+        In terms of implementation, RenderLayerCompositor has been changed such that in its 
+        updateCompositingLayers() method we call the layerTreeDidChange method on the 
+        InspectorLayerTreeAgent instance via the InspectorInstrumentation.
+
+        Test: inspector-protocol/layer-tree.html
+
+        * CMakeLists.txt:
+        * GNUmakefile.list.am:
+        * Target.pri:
+        * WebCore.gypi:
+        * WebCore.vcproj/WebCore.vcproj:
+        * WebCore.xcodeproj/project.pbxproj:
+        * inspector/Inspector.json: Define new types IntRect (x, y, width, height) and Layer, which 
+        holds the information for a RenderLayer (layerId, bounds, isComposited, memory, 
+        compositedBounds) and its children (childLayers). We also define the methods of the 
+        LayerTreeAgent object (enable, disable, getLayerTree, nodeIdForLayerId) and the 
+        layerTreeDidChange event it  
+        fires.
+        * inspector/InspectorAllInOne.cpp:
+        * inspector/InspectorController.cpp:
+        (WebCore::InspectorController::InspectorController):
+        * inspector/InspectorDOMAgent.cpp:
+        (WebCore::InspectorDOMAgent::pushNodePathForRenderLayerToFrontend): New method facilitating 
+        pushing the node associated with a given RenderLayer to the front-end.
+        (WebCore):
+        * inspector/InspectorDOMAgent.h:
+        (InspectorDOMAgent):
+        * inspector/InspectorInstrumentation.cpp:
+        (WebCore):
+        (WebCore::InspectorInstrumentation::didCommitLoadImpl):
+        (WebCore::InspectorInstrumentation::layerTreeDidChangeImpl):
+        (WebCore::InspectorInstrumentation::renderLayerDestroyedImpl):
+        * inspector/InspectorInstrumentation.h:
+        (WebCore):
+        (InspectorInstrumentation):
+        (WebCore::InspectorInstrumentation::layerTreeDidChange):
+        (WebCore::InspectorInstrumentation::renderLayerDestroyed):
+        * inspector/InspectorLayerTreeAgent.cpp: Added.
+        (WebCore):
+        (LayerTreeAgentState):
+        (WebCore::InspectorLayerTreeAgent::InspectorLayerTreeAgent):
+        (WebCore::InspectorLayerTreeAgent::~InspectorLayerTreeAgent):
+        (WebCore::InspectorLayerTreeAgent::setFrontend):
+        (WebCore::InspectorLayerTreeAgent::clearFrontend):
+        (WebCore::InspectorLayerTreeAgent::restore):
+        (WebCore::InspectorLayerTreeAgent::reset):
+        (WebCore::InspectorLayerTreeAgent::enable):
+        (WebCore::InspectorLayerTreeAgent::disable):
+        (WebCore::InspectorLayerTreeAgent::layerTreeDidChange):
+        (WebCore::InspectorLayerTreeAgent::renderLayerDestroyed):
+        (WebCore::InspectorLayerTreeAgent::getLayerTree):
+        (WebCore::InspectorLayerTreeAgent::buildObjectForRootLayer):
+        (WebCore::InspectorLayerTreeAgent::buildObjectForLayer): Build the entire hierarchy of 
+        RenderLayers from the provided RenderLayer.
+        (WebCore::InspectorLayerTreeAgent::buildObjectForIntRect):
+        (WebCore::InspectorLayerTreeAgent::bind):
+        (WebCore::InspectorLayerTreeAgent::unbind):
+        (WebCore::InspectorLayerTreeAgent::nodeIdForLayerId):
+        * inspector/InspectorLayerTreeAgent.h: Added.
+        (WebCore):
+        (InspectorLayerTreeAgent):
+        (WebCore::InspectorLayerTreeAgent::create):
+        * inspector/InstrumentingAgents.h:
+        (WebCore):
+        (WebCore::InstrumentingAgents::InstrumentingAgents):
+        (InstrumentingAgents):
+        (WebCore::InstrumentingAgents::inspectorLayerTreeAgent):
+        (WebCore::InstrumentingAgents::setInspectorLayerTreeAgent):
+        * rendering/RenderLayerCompositor.cpp:
+        (WebCore::RenderLayerCompositor::updateCompositingLayers): Call the layerTreeDidChange method 
+        on the LayerTreeAgent via the InspectorInstrumentation to inform the front-end that the 
+        RenderLayer hierarchy has changed.
+        (WebCore):
+        (WebCore::RenderLayerCompositor::layerBecameNonComposited): Call the renderLayerDestroyed 
+        method on the LayerTreeAgent via the InspectorInstrumentation to unbind the layer that is 
+        being destroyed.
+        * rendering/RenderLayerCompositor.h:
+        (RenderLayerCompositor):
+
 2012-12-07  Joshua Bell  <jsbell@chromium.org>
 
         IndexedDB: Check SSV version when opening database
index b7046cc..05b3ca6 100644 (file)
@@ -3749,6 +3749,8 @@ webcore_sources += \
        Source/WebCore/inspector/InspectorInputAgent.h \
        Source/WebCore/inspector/InspectorInstrumentation.cpp \
        Source/WebCore/inspector/InspectorInstrumentation.h \
+       Source/WebCore/inspector/InspectorLayerTreeAgent.cpp \
+       Source/WebCore/inspector/InspectorLayerTreeAgent.h \
        Source/WebCore/inspector/InspectorMemoryAgent.cpp \
        Source/WebCore/inspector/InspectorMemoryAgent.h \
        Source/WebCore/inspector/InspectorOverlay.cpp \
index 5b4687c..e0a48d5 100644 (file)
@@ -776,6 +776,7 @@ SOURCES += \
     inspector/InspectorHistory.cpp \
     inspector/InspectorInputAgent.cpp \
     inspector/InspectorInstrumentation.cpp \
+    inspector/InspectorLayerTreeAgent.cpp \
     inspector/InspectorMemoryAgent.cpp \
     inspector/InspectorOverlay.cpp \
     inspector/InspectorPageAgent.cpp \
@@ -1929,6 +1930,7 @@ HEADERS += \
     inspector/InspectorFrontendHost.h \
     inspector/InspectorHistory.h \
     inspector/InspectorInstrumentation.h \
+    inspector/InspectorLayerTreeAgent.h \
     inspector/InspectorMemoryAgent.h \
     inspector/InspectorOverlay.h \
     inspector/InspectorPageAgent.h \
index 4e7d3db..badb75f 100644 (file)
             'inspector/InspectorInputAgent.h',
             'inspector/InspectorInstrumentation.cpp',
             'inspector/InspectorInstrumentation.h',
+            'inspector/InspectorLayerTreeAgent.cpp',
+            'inspector/InspectorLayerTreeAgent.h',
             'inspector/InspectorMemoryAgent.cpp',
             'inspector/InspectorMemoryAgent.h',
             'inspector/InspectorOverlay.cpp',
index abc09eb..46db90a 100755 (executable)
                                >
                        </File>
                        <File
+                               RelativePath="..\inspector\InspectorLayerTreeAgent.cpp"
+                               >
+                               <FileConfiguration
+                                       Name="Release|Win32"
+                                       ExcludedFromBuild="true"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Production|Win32"
+                                       ExcludedFromBuild="true"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                       />
+                               </FileConfiguration>
+                       </File>
+                       <File
+                               RelativePath="..\inspector\InspectorLayerTreeAgent.h"
+                               >
+                       </File>
+                       <File
                                RelativePath="..\inspector\InspectorMemoryAgent.cpp"
                                >
                                <FileConfiguration
index 7e6b66d..7dc6d41 100644 (file)
                71904DEA156A633A001E1BA5 /* DOMSVGViewSpecInternal.h in Copy Generated Headers */ = {isa = PBXBuildFile; fileRef = 718512331568649800C40967 /* DOMSVGViewSpecInternal.h */; };
                71A57DF1154BE25C0009D120 /* SVGPathUtilities.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 71A57DEF154BE25C0009D120 /* SVGPathUtilities.cpp */; };
                71A57DF2154BE25C0009D120 /* SVGPathUtilities.h in Headers */ = {isa = PBXBuildFile; fileRef = 71A57DF0154BE25C0009D120 /* SVGPathUtilities.h */; };
+               71B1E125164048F700B1880A /* InspectorLayerTreeAgent.h in Headers */ = {isa = PBXBuildFile; fileRef = 71B1E124164048CC00B1880A /* InspectorLayerTreeAgent.h */; };
+               71B1E1261640491A00B1880A /* InspectorLayerTreeAgent.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 71B1E123164048CC00B1880A /* InspectorLayerTreeAgent.cpp */; };
                71CC7A20152A0BFE009EEAF9 /* SVGAnimatedEnumeration.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 71CC7A1F152A0BFE009EEAF9 /* SVGAnimatedEnumeration.cpp */; };
                71DCB7011568197600862271 /* JSSVGZoomAndPan.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 71DCB6FF1568197600862271 /* JSSVGZoomAndPan.cpp */; };
                71DCB7021568197600862271 /* JSSVGZoomAndPan.h in Headers */ = {isa = PBXBuildFile; fileRef = 71DCB7001568197600862271 /* JSSVGZoomAndPan.h */; };
                718512331568649800C40967 /* DOMSVGViewSpecInternal.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = DOMSVGViewSpecInternal.h; sourceTree = "<group>"; };
                71A57DEF154BE25C0009D120 /* SVGPathUtilities.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SVGPathUtilities.cpp; sourceTree = "<group>"; };
                71A57DF0154BE25C0009D120 /* SVGPathUtilities.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SVGPathUtilities.h; sourceTree = "<group>"; };
+               71B1E123164048CC00B1880A /* InspectorLayerTreeAgent.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = InspectorLayerTreeAgent.cpp; sourceTree = "<group>"; };
+               71B1E124164048CC00B1880A /* InspectorLayerTreeAgent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = InspectorLayerTreeAgent.h; sourceTree = "<group>"; };
                71CC7A1F152A0BFE009EEAF9 /* SVGAnimatedEnumeration.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SVGAnimatedEnumeration.cpp; sourceTree = "<group>"; };
                71DCB6FF1568197600862271 /* JSSVGZoomAndPan.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSSVGZoomAndPan.cpp; sourceTree = "<group>"; };
                71DCB7001568197600862271 /* JSSVGZoomAndPan.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSSVGZoomAndPan.h; sourceTree = "<group>"; };
                                AA73183C159255B900A93E6E /* InjectedScriptCanvasModule.cpp */,
                                AA73183D159255B900A93E6E /* InjectedScriptCanvasModule.h */,
                                AA9030FE157E16A000276247 /* InjectedScriptCanvasModuleSource.js */,
+                               71B1E123164048CC00B1880A /* InspectorLayerTreeAgent.cpp */,
+                               71B1E124164048CC00B1880A /* InspectorLayerTreeAgent.h */,
                                7A0E76F610BF08ED00A0276E /* InjectedScriptHost.cpp */,
                                7A0E76F710BF08ED00A0276E /* InjectedScriptHost.h */,
                                7A0E76F810BF08ED00A0276E /* InjectedScriptHost.idl */,
                                8502AB540AD438C000378540 /* DOMSVGFEFuncGElement.h in Headers */,
                                8502AB980AD4394E00378540 /* DOMSVGFEFuncGElementInternal.h in Headers */,
                                8502AB560AD438C000378540 /* DOMSVGFEFuncRElement.h in Headers */,
+                               71B1E125164048F700B1880A /* InspectorLayerTreeAgent.h in Headers */,
                                8502AB990AD4394E00378540 /* DOMSVGFEFuncRElementInternal.h in Headers */,
                                8502AB580AD438C000378540 /* DOMSVGFEGaussianBlurElement.h in Headers */,
                                8502AB9A0AD4394E00378540 /* DOMSVGFEGaussianBlurElementInternal.h in Headers */,
                        isa = PBXSourcesBuildPhase;
                        buildActionMask = 2147483647;
                        files = (
+                               71B1E1261640491A00B1880A /* InspectorLayerTreeAgent.cpp in Sources */,
                                97BC69DA1505F076001B74AC /* AbstractDatabase.cpp in Sources */,
                                41E1B1D00FF5986900576B3B /* AbstractWorker.cpp in Sources */,
                                0F29C16E1300C2E2002D794E /* AccessibilityAllInOne.cpp in Sources */,
index d21b520..97c6ea3 100644 (file)
             }
         ],
         "events": []
+    },
+    {
+        "domain": "LayerTree",
+        "hidden": true,
+        "types": [
+            {
+                "id": "LayerId",
+                "type": "string",
+                "description": "Unique RenderLayer identifier."
+            },
+            {
+                "id": "IntRect",
+                "type": "object",
+                "description": "A rectangle.",
+                "properties": [
+                    { "name": "x", "type": "integer", "description": "The x position." },
+                    { "name": "y", "type": "integer", "description": "The y position." },
+                    { "name": "width", "type": "integer", "description": "The width metric." },
+                    { "name": "height", "type": "integer", "description": "The height metric." }
+                ]
+            },
+            {
+                "id": "Layer",
+                "type": "object",
+                "description": "Information about a compositing layer.",
+                "properties": [
+                    { "name": "layerId", "$ref": "LayerId", "description": "The unique id for this layer." },
+                    { "name": "bounds", "$ref": "IntRect", "description": "Bounds of the layer." },
+                    { "name": "isComposited", "type": "boolean", "description": "Indicates whether this layer is composited." },
+                    { "name": "memory", "type": "integer", "optional": true, "description": "Estimated memory used by this layer." },
+                    { "name": "compositedBounds", "$ref": "IntRect", "optional": true, "description": "The bounds of the composited layer." },
+                    { "name": "childLayers", "type": "array", "optional": true, "items": { "$ref": "Layer" }, "description": "Child layers." }
+                ]
+            }
+        ],
+        "commands": [
+            {
+                "name": "enable",
+                "description": "Enables compositing tree inspection."
+            },
+            {
+                "name": "disable",
+                "description": "Disables compositing tree inspection."
+            },
+            {
+                "name": "getLayerTree",
+                "description": "Returns the layer tree structure of the current page.",
+                "returns": [
+                    { "name": "layerTree", "$ref": "Layer", "description": "Layer tree structure of the current page." }
+                ]
+            },
+            {
+                "name": "nodeIdForLayerId",
+                "description": "Returns the node id for a given layer id.",
+                "parameters": [
+                    { "name": "layerId", "$ref": "LayerId" }
+                ],
+                "returns": [
+                    { "name": "nodeId", "$ref": "DOM.NodeId", "description": "The node id for the given layer id." }
+                ]
+            }
+        ],
+        "events": [
+            {
+                "name": "layerTreeDidChange"
+            }
+        ]
     }]
 }
index c9a80ad..2561f61 100644 (file)
@@ -59,6 +59,7 @@
 #include "InspectorIndexedDBAgent.cpp"
 #include "InspectorInputAgent.cpp"
 #include "InspectorInstrumentation.cpp"
+#include "InspectorLayerTreeAgent.cpp"
 #include "InspectorMemoryAgent.cpp"
 #include "InspectorOverlay.cpp"
 #include "InspectorPageAgent.cpp"
index d03886b..eb339e8 100644 (file)
@@ -57,6 +57,7 @@
 #include "InspectorIndexedDBAgent.h"
 #include "InspectorInputAgent.h"
 #include "InspectorInstrumentation.h"
+#include "InspectorLayerTreeAgent.h"
 #include "InspectorMemoryAgent.h"
 #include "InspectorOverlay.h"
 #include "InspectorPageAgent.h"
@@ -154,6 +155,8 @@ InspectorController::InspectorController(Page* page, InspectorClient* inspectorC
 
     m_agents.append(InspectorInputAgent::create(m_instrumentingAgents.get(), m_state.get(), page));
 
+    m_agents.append(InspectorLayerTreeAgent::create(m_instrumentingAgents.get(), m_state.get(), page));
+
     ASSERT_ARG(inspectorClient, inspectorClient);
     m_injectedScriptManager->injectedScriptHost()->init(m_inspectorAgent
         , consoleAgent
index 3b6c112..4915a0c 100644 (file)
@@ -564,6 +564,11 @@ int InspectorDOMAgent::pushNodePathToFrontend(Node* nodeToPush)
     return map->get(nodeToPush);
 }
 
+int InspectorDOMAgent::pushNodePathForRenderLayerToFrontend(const RenderLayer* renderLayer)
+{
+    return pushNodePathToFrontend(renderLayer->renderer()->node());
+}
+
 int InspectorDOMAgent::boundNodeId(Node* node)
 {
     return m_documentNodeToIdMap.get(node);
index 707cad0..80cd508 100644 (file)
@@ -37,6 +37,7 @@
 #include "InspectorFrontend.h"
 #include "InspectorOverlay.h"
 #include "InspectorValues.h"
+#include "RenderLayer.h"
 #include "Timer.h"
 
 #include <wtf/Deque.h>
@@ -200,6 +201,7 @@ public:
 
     // Methods called from other agents.
     InspectorPageAgent* pageAgent() { return m_pageAgent; }
+    int pushNodePathForRenderLayerToFrontend(const RenderLayer*);
 
 private:
     InspectorDOMAgent(InstrumentingAgents*, InspectorPageAgent*, InspectorState*, InjectedScriptManager*, InspectorOverlay*);
index 25ea6de..0c9d17e 100644 (file)
@@ -54,6 +54,7 @@
 #include "InspectorDOMAgent.h"
 #include "InspectorDOMStorageAgent.h"
 #include "InspectorDebuggerAgent.h"
+#include "InspectorLayerTreeAgent.h"
 #include "InspectorPageAgent.h"
 #include "InspectorProfilerAgent.h"
 #include "InspectorResourceAgent.h"
@@ -908,7 +909,10 @@ void InspectorInstrumentation::didCommitLoadImpl(InstrumentingAgents* instrument
             domStorageAgent->clearResources();
         if (InspectorDOMAgent* domAgent = instrumentingAgents->inspectorDOMAgent())
             domAgent->setDocument(mainFrame->document());
-
+#if USE(ACCELERATED_COMPOSITING)
+        if (InspectorLayerTreeAgent* layerTreeAgent = instrumentingAgents->inspectorLayerTreeAgent())
+            layerTreeAgent->reset();
+#endif
         inspectorAgent->didCommitLoad();
     }
     if (InspectorPageAgent* pageAgent = instrumentingAgents->inspectorPageAgent())
@@ -1296,6 +1300,20 @@ DeviceOrientationData* InspectorInstrumentation::overrideDeviceOrientationImpl(I
     return deviceOrientation;
 }
 
+#if USE(ACCELERATED_COMPOSITING)
+void InspectorInstrumentation::layerTreeDidChangeImpl(InstrumentingAgents* instrumentingAgents)
+{
+    if (InspectorLayerTreeAgent* layerTreeAgent = instrumentingAgents->inspectorLayerTreeAgent())
+        layerTreeAgent->layerTreeDidChange();
+}
+
+void InspectorInstrumentation::renderLayerDestroyedImpl(InstrumentingAgents* instrumentingAgents, const RenderLayer* renderLayer)
+{
+    if (InspectorLayerTreeAgent* layerTreeAgent = instrumentingAgents->inspectorLayerTreeAgent())
+        layerTreeAgent->renderLayerDestroyed(renderLayer);
+}
+#endif
+
 } // namespace WebCore
 
 #endif // !ENABLE(INSPECTOR)
index 237080e..de63fc4 100644 (file)
@@ -60,6 +60,7 @@ class InspectorTimelineAgent;
 class InstrumentingAgents;
 class KURL;
 class Node;
+class RenderLayer;
 class RenderObject;
 class ResourceRequest;
 class ResourceResponse;
@@ -280,6 +281,11 @@ public:
 
     static DeviceOrientationData* overrideDeviceOrientation(Page*, DeviceOrientationData*);
 
+#if USE(ACCELERATED_COMPOSITING)
+    static void layerTreeDidChange(Page*);
+    static void renderLayerDestroyed(Page*, const RenderLayer*);
+#endif
+
 private:
 #if ENABLE(INSPECTOR)
     static void didClearWindowObjectInWorldImpl(InstrumentingAgents*, Frame*, DOMWrapperWorld*);
@@ -458,6 +464,12 @@ private:
 #endif
 
     static DeviceOrientationData* overrideDeviceOrientationImpl(InstrumentingAgents*, DeviceOrientationData*);
+
+#if USE(ACCELERATED_COMPOSITING)
+    static void layerTreeDidChangeImpl(InstrumentingAgents*);
+    static void renderLayerDestroyedImpl(InstrumentingAgents*, const RenderLayer*);
+#endif
+
     static int s_frontendCounter;
 #endif
 };
@@ -1532,6 +1544,20 @@ inline DeviceOrientationData* InspectorInstrumentation::overrideDeviceOrientatio
     return deviceOrientation;
 }
 
+#if USE(ACCELERATED_COMPOSITING)
+inline void InspectorInstrumentation::layerTreeDidChange(Page* page)
+{
+    if (InstrumentingAgents* instrumentingAgents = instrumentingAgentsForPage(page))
+        layerTreeDidChangeImpl(instrumentingAgents);
+}
+
+inline void InspectorInstrumentation::renderLayerDestroyed(Page* page, const RenderLayer* renderLayer)
+{
+    if (InstrumentingAgents* instrumentingAgents = instrumentingAgentsForPage(page))
+        renderLayerDestroyedImpl(instrumentingAgents, renderLayer);
+}
+#endif
+
 #if ENABLE(INSPECTOR)
 inline bool InspectorInstrumentation::collectingHTMLParseErrors(Page* page)
 {
diff --git a/Source/WebCore/inspector/InspectorLayerTreeAgent.cpp b/Source/WebCore/inspector/InspectorLayerTreeAgent.cpp
new file mode 100644 (file)
index 0000000..ecb5e92
--- /dev/null
@@ -0,0 +1,228 @@
+/*
+ * Copyright (C) 2012 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:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * 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.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER OR 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"
+
+#if USE(ACCELERATED_COMPOSITING)
+#if ENABLE(INSPECTOR)
+
+#include "InspectorLayerTreeAgent.h"
+
+#include "IdentifiersFactory.h"
+#include "InspectorDOMAgent.h"
+#include "InspectorFrontend.h"
+#include "InspectorState.h"
+#include "InstrumentingAgents.h"
+#include "IntRect.h"
+#include "Page.h"
+#include "RenderLayer.h"
+#include "RenderLayerBacking.h"
+#include "RenderLayerCompositor.h"
+#include "RenderView.h"
+
+namespace WebCore {
+
+namespace LayerTreeAgentState {
+static const char layerTreeAgentEnabled[] = "layerTreeAgentEnabled";
+};
+
+InspectorLayerTreeAgent::InspectorLayerTreeAgent(InstrumentingAgents* instrumentingAgents, InspectorState* state, Page* page)
+    : InspectorBaseAgent<InspectorLayerTreeAgent>("LayerTree", instrumentingAgents, state)
+    , m_inspectedPage(page)
+    , m_frontend(0)
+{
+}
+
+InspectorLayerTreeAgent::~InspectorLayerTreeAgent()
+{
+    reset();
+}
+
+void InspectorLayerTreeAgent::setFrontend(InspectorFrontend* frontend)
+{
+    m_frontend = frontend->layertree();
+}
+
+void InspectorLayerTreeAgent::clearFrontend()
+{
+    m_frontend = 0;
+    disable(0);
+}
+
+void InspectorLayerTreeAgent::restore()
+{
+    enable(0);
+}
+
+void InspectorLayerTreeAgent::reset()
+{
+    m_documentLayerToIdMap.clear();
+    m_idToLayer.clear();
+}
+
+void InspectorLayerTreeAgent::enable(ErrorString*)
+{
+    m_state->setBoolean(LayerTreeAgentState::layerTreeAgentEnabled, true);
+    m_instrumentingAgents->setInspectorLayerTreeAgent(this);
+}
+
+void InspectorLayerTreeAgent::disable(ErrorString*)
+{
+    if (!m_state->getBoolean(LayerTreeAgentState::layerTreeAgentEnabled))
+        return;
+    m_state->setBoolean(LayerTreeAgentState::layerTreeAgentEnabled, false);
+    m_instrumentingAgents->setInspectorLayerTreeAgent(0);
+}
+
+void InspectorLayerTreeAgent::layerTreeDidChange()
+{
+    m_frontend->layerTreeDidChange();
+}
+
+void InspectorLayerTreeAgent::renderLayerDestroyed(const RenderLayer* renderLayer)
+{
+    unbind(renderLayer);
+}
+
+void InspectorLayerTreeAgent::getLayerTree(ErrorString*, RefPtr<TypeBuilder::LayerTree::Layer>& object)
+{
+    object = buildObjectForRootLayer();
+}
+
+PassRefPtr<TypeBuilder::LayerTree::Layer> InspectorLayerTreeAgent::buildObjectForRootLayer()
+{
+    return buildObjectForLayer(m_inspectedPage->mainFrame()->contentRenderer()->compositor()->rootRenderLayer());
+}
+
+PassRefPtr<TypeBuilder::LayerTree::Layer> InspectorLayerTreeAgent::buildObjectForLayer(RenderLayer* renderLayer)
+{
+    bool isComposited = renderLayer->isComposited();
+
+    // Basic set of properties.
+    RefPtr<TypeBuilder::LayerTree::Layer> layerObject = TypeBuilder::LayerTree::Layer::create()
+        .setLayerId(bind(renderLayer))
+        .setBounds(buildObjectForIntRect(enclosingIntRect(renderLayer->localBoundingBox())))
+        .setIsComposited(isComposited);
+
+    // Optional properties for composited layers only.
+    if (isComposited) {
+        RenderLayerBacking* backing = renderLayer->backing();
+        layerObject->setMemory(backing->backingStoreMemoryEstimate());
+        layerObject->setCompositedBounds(buildObjectForIntRect(backing->compositedBounds()));
+    }
+
+    // Process children layers.
+    RefPtr<TypeBuilder::Array<TypeBuilder::LayerTree::Layer> > childrenArray = TypeBuilder::Array<TypeBuilder::LayerTree::Layer>::create();
+
+    renderLayer->updateLayerListsIfNeeded();
+
+    // Check if we have a reflection layer.
+    if (renderLayer->reflectionLayer())
+        childrenArray->addItem(buildObjectForLayer(renderLayer->reflectionLayer()));
+
+    if (renderLayer->isStackingContext()) {
+        if (Vector<RenderLayer*>* negZOrderList = renderLayer->negZOrderList()) {
+            size_t listSize = negZOrderList->size();
+            for (size_t i = 0; i < listSize; ++i)
+                childrenArray->addItem(buildObjectForLayer(negZOrderList->at(i)));
+        }
+    }
+
+    if (Vector<RenderLayer*>* normalFlowList = renderLayer->normalFlowList()) {
+        size_t listSize = normalFlowList->size();
+        for (size_t i = 0; i < listSize; ++i)
+            childrenArray->addItem(buildObjectForLayer(normalFlowList->at(i)));
+    }
+    
+    if (renderLayer->isStackingContext()) {
+        if (Vector<RenderLayer*>* posZOrderList = renderLayer->posZOrderList()) {
+            size_t listSize = posZOrderList->size();
+            for (size_t i = 0; i < listSize; ++i)
+                childrenArray->addItem(buildObjectForLayer(posZOrderList->at(i)));
+        }
+    }
+
+    layerObject->setChildLayers(childrenArray);
+    
+    return layerObject;
+}
+
+PassRefPtr<TypeBuilder::LayerTree::IntRect> InspectorLayerTreeAgent::buildObjectForIntRect(const IntRect& rect)
+{
+    return TypeBuilder::LayerTree::IntRect::create()
+        .setX(rect.x())
+        .setY(rect.y())
+        .setWidth(rect.width())
+        .setHeight(rect.height()).release();
+}
+
+String InspectorLayerTreeAgent::bind(const RenderLayer* layer)
+{
+    if (!layer)
+        return "";
+    String identifier = m_documentLayerToIdMap.get(layer);
+    if (identifier.isNull()) {
+        identifier = IdentifiersFactory::createIdentifier();
+        m_documentLayerToIdMap.set(layer, identifier);
+        m_idToLayer.set(identifier, layer);
+    }
+    return identifier;
+}
+
+void InspectorLayerTreeAgent::unbind(const RenderLayer* layer)
+{
+    String identifier = m_documentLayerToIdMap.get(layer);
+    if (identifier.isNull())
+        return;
+
+    m_documentLayerToIdMap.remove(layer);
+    m_idToLayer.remove(identifier);
+}
+
+void InspectorLayerTreeAgent::nodeIdForLayerId(ErrorString* errorString, const String& layerId, int* resultNodeId)
+{
+    // Obtain the RenderLayer from the identifier provided.
+    const RenderLayer* renderLayer = m_idToLayer.get(layerId);
+    
+    // Send an error if there is no such registered layer id.
+    if (!renderLayer) {
+        *errorString = "Could not find a bound layer for the provided id";
+        return;
+    }
+    
+    // Get the node id from the DOM agent and return it to the front-end.
+    InspectorDOMAgent* inspectorDOMAgent = m_instrumentingAgents->inspectorDOMAgent();
+    *resultNodeId = inspectorDOMAgent->pushNodePathForRenderLayerToFrontend(renderLayer);
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(INSPECTOR)
+#endif // USE(ACCELERATED_COMPOSITING)
diff --git a/Source/WebCore/inspector/InspectorLayerTreeAgent.h b/Source/WebCore/inspector/InspectorLayerTreeAgent.h
new file mode 100644 (file)
index 0000000..6711b86
--- /dev/null
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2012 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.
+ * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ *     its contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE 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 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 InspectorLayerTreeAgent_h
+#define InspectorLayerTreeAgent_h
+
+#if ENABLE(INSPECTOR)
+
+#include "InspectorBaseAgent.h"
+#include "InspectorFrontend.h"
+#include "InspectorTypeBuilder.h"
+#include "RenderLayer.h"
+#include <wtf/PassOwnPtr.h>
+#include <wtf/PassRefPtr.h>
+#include <wtf/Vector.h>
+#include <wtf/text/WTFString.h>
+
+namespace WebCore {
+
+class InspectorState;
+class InstrumentingAgents;
+class Page;
+
+typedef String ErrorString;
+
+class InspectorLayerTreeAgent : public InspectorBaseAgent<InspectorLayerTreeAgent>, public InspectorBackendDispatcher::LayerTreeCommandHandler {
+public:
+    static PassOwnPtr<InspectorLayerTreeAgent> create(InstrumentingAgents* instrumentingAgents, InspectorState* state, Page* page)
+    {
+        return adoptPtr(new InspectorLayerTreeAgent(instrumentingAgents, state, page));
+    }
+    ~InspectorLayerTreeAgent();
+
+    virtual void setFrontend(InspectorFrontend*);
+    virtual void clearFrontend();
+    virtual void restore();
+    void reset();
+
+    void layerTreeDidChange();
+    void renderLayerDestroyed(const RenderLayer*);
+
+    // Called from the front-end.
+    virtual void enable(ErrorString*);
+    virtual void disable(ErrorString*);
+    virtual void getLayerTree(ErrorString*, RefPtr<TypeBuilder::LayerTree::Layer>&);
+    virtual void nodeIdForLayerId(ErrorString*, const String& layerId, int* resultNodeId);
+
+private:
+    InspectorLayerTreeAgent(InstrumentingAgents*, InspectorState*, Page*);
+
+    // RenderLayer-related methods.
+    String bind(const RenderLayer*);
+    void unbind(const RenderLayer*);
+
+    PassRefPtr<TypeBuilder::LayerTree::Layer> buildObjectForRootLayer();   
+    PassRefPtr<TypeBuilder::LayerTree::Layer> buildObjectForLayer(RenderLayer*);
+    PassRefPtr<TypeBuilder::LayerTree::IntRect> buildObjectForIntRect(const IntRect&);
+        
+    Page* m_inspectedPage;
+    InspectorFrontend::LayerTree* m_frontend;
+
+    HashMap<const RenderLayer*, String> m_documentLayerToIdMap;
+    HashMap<String, const RenderLayer*> m_idToLayer;
+};
+
+} // namespace WebCore
+
+#endif // ENABLE(INSPECTOR)
+
+#endif // !defined(InspectorLayerTreeAgent_h)
index e493410..42c94cb 100644 (file)
@@ -47,6 +47,7 @@ class InspectorDOMStorageAgent;
 class InspectorDatabaseAgent;
 class InspectorDebuggerAgent;
 class InspectorFileSystemAgent;
+class InspectorLayerTreeAgent;
 class InspectorPageAgent;
 class InspectorProfilerAgent;
 class InspectorResourceAgent;
@@ -66,6 +67,7 @@ public:
         : m_inspectorAgent(0)
         , m_inspectorPageAgent(0)
         , m_inspectorCSSAgent(0)
+        , m_inspectorLayerTreeAgent(0)
         , m_inspectorConsoleAgent(0)
         , m_inspectorDOMAgent(0)
         , m_inspectorResourceAgent(0)
@@ -158,10 +160,18 @@ public:
     InspectorCanvasAgent* inspectorCanvasAgent() const { return m_inspectorCanvasAgent; }
     void setInspectorCanvasAgent(InspectorCanvasAgent* agent) { m_inspectorCanvasAgent = agent; }
 
+#if USE(ACCELERATED_COMPOSITING)
+    InspectorLayerTreeAgent* inspectorLayerTreeAgent() const { return m_inspectorLayerTreeAgent; }
+    void setInspectorLayerTreeAgent(InspectorLayerTreeAgent* agent) { m_inspectorLayerTreeAgent = agent; }
+#endif
+
 private:
     InspectorAgent* m_inspectorAgent;
     InspectorPageAgent* m_inspectorPageAgent;
     InspectorCSSAgent* m_inspectorCSSAgent;
+#if USE(ACCELERATED_COMPOSITING)
+    InspectorLayerTreeAgent* m_inspectorLayerTreeAgent;
+#endif
     InspectorConsoleAgent* m_inspectorConsoleAgent;
     InspectorDOMAgent* m_inspectorDOMAgent;
     InspectorResourceAgent* m_inspectorResourceAgent;
index 561eb28..a0ac5a1 100644 (file)
@@ -40,6 +40,7 @@
 #include "HTMLIFrameElement.h"
 #include "HTMLNames.h"
 #include "HitTestResult.h"
+#include "InspectorInstrumentation.h"
 #include "NodeList.h"
 #include "Page.h"
 #include "RenderApplet.h"
@@ -508,6 +509,18 @@ void RenderLayerCompositor::updateCompositingLayers(CompositingUpdateType update
 
     if (!hasAcceleratedCompositing())
         enableCompositingMode(false);
+
+    // Inform the inspector that the layer tree has changed.
+    InspectorInstrumentation::layerTreeDidChange(page());
+}
+
+void RenderLayerCompositor::layerBecameNonComposited(const RenderLayer* renderLayer)
+{
+    // Inform the inspector that the given RenderLayer was destroyed.
+    InspectorInstrumentation::renderLayerDestroyed(page(), renderLayer);
+
+    ASSERT(m_compositedLayerCount > 0);
+    --m_compositedLayerCount;
 }
 
 #if !LOG_DISABLED
index 5193411..e89ec79 100644 (file)
@@ -170,11 +170,7 @@ public:
     void clearBackingForAllLayers();
     
     void layerBecameComposited(const RenderLayer*) { ++m_compositedLayerCount; }
-    void layerBecameNonComposited(const RenderLayer*)
-    {
-        ASSERT(m_compositedLayerCount > 0);
-        --m_compositedLayerCount;
-    }
+    void layerBecameNonComposited(const RenderLayer*);
     
 #if ENABLE(VIDEO)
     // Use by RenderVideo to ask if it should try to use accelerated compositing.