Title: [223209] trunk/Source/WebInspectorUI
Revision
223209
Author
[email protected]
Date
2017-10-11 13:54:56 -0700 (Wed, 11 Oct 2017)

Log Message

Web Inspector: Make 3D objects selectable in Layers visualization
https://bugs.webkit.org/show_bug.cgi?id=178136

Patch by Ross Kirsling <[email protected]> on 2017-10-11
Reviewed by Devin Rousso.

* UserInterface/Views/Layers3DContentView.js:
(WI.Layers3DContentView):
(WI.Layers3DContentView.prototype.initialLayout):
(WI.Layers3DContentView.prototype._canvasMouseDown):
(WI.Layers3DContentView.prototype._updateLayerGroupSelection):
Implement selection of 3D layer objects.

(WI.Layers3DContentView.prototype._addLayerGroup): Renamed from _addLayer.
(WI.Layers3DContentView.prototype._updateLayerGroupPosition):
(WI.Layers3DContentView.prototype._createLayerMesh):
Refactor -- one group per layer (visible plane and composited outline), not groups by shape.

(WI.Layers3DContentView.prototype.layout):
(WI.Layers3DContentView.prototype._updateLayers):
(WI.Layers3DContentView.prototype._clearLayers): Deleted.
Don't destroy all 3D objects on every LayerTreeDidChange; make use of layerTreeMutations.
(Not only a performance improvement, but also necessary to properly preserve highlighting.)

(WI.Layers3DContentView.prototype.selectLayerById):
Allow selection to be updated from the outside.

* UserInterface/Views/LayerDetailsSidebarPanel.js:
(WI.LayerDetailsSidebarPanel.prototype.selectNodeByLayerId):
(WI.LayerDetailsSidebarPanel.prototype._buildDataGrid):
(WI.LayerDetailsSidebarPanel.prototype._dataGridSelectedNodeChanged):
Allow selection to be updated from the outside.

(WI.LayerDetailsSidebarPanel.prototype.inspect):
(WI.LayerDetailsSidebarPanel.prototype._updateLayers): Renamed from _updateDisplayWithLayers.
(WI.LayerDetailsSidebarPanel.prototype._updateDataGrid):
(WI.LayerDetailsSidebarPanel.prototype._updateBottomBar):
(WI.LayerDetailsSidebarPanel.prototype._contentForPopover):
(WI.LayerDetailsSidebarPanel.prototype._dataGridNodeForLayer): Deleted.
Cleanup.

* UserInterface/Views/LayersTabContentView.js:
(WI.LayersTabContentView):
(WI.LayersTabContentView.prototype._detailsSidebarSelectedLayerChanged):
(WI.LayersTabContentView.prototype._contentViewSelectedLayerChanged):
Orchestrate communication of selection state between visualization and sidebar.

Modified Paths

Diff

Modified: trunk/Source/WebInspectorUI/ChangeLog (223208 => 223209)


--- trunk/Source/WebInspectorUI/ChangeLog	2017-10-11 20:43:58 UTC (rev 223208)
+++ trunk/Source/WebInspectorUI/ChangeLog	2017-10-11 20:54:56 UTC (rev 223209)
@@ -1,3 +1,51 @@
+2017-10-11  Ross Kirsling  <[email protected]>
+
+        Web Inspector: Make 3D objects selectable in Layers visualization
+        https://bugs.webkit.org/show_bug.cgi?id=178136
+
+        Reviewed by Devin Rousso.
+
+        * UserInterface/Views/Layers3DContentView.js:
+        (WI.Layers3DContentView):
+        (WI.Layers3DContentView.prototype.initialLayout):
+        (WI.Layers3DContentView.prototype._canvasMouseDown):
+        (WI.Layers3DContentView.prototype._updateLayerGroupSelection):
+        Implement selection of 3D layer objects.
+        
+        (WI.Layers3DContentView.prototype._addLayerGroup): Renamed from _addLayer.
+        (WI.Layers3DContentView.prototype._updateLayerGroupPosition):
+        (WI.Layers3DContentView.prototype._createLayerMesh):
+        Refactor -- one group per layer (visible plane and composited outline), not groups by shape.
+
+        (WI.Layers3DContentView.prototype.layout):
+        (WI.Layers3DContentView.prototype._updateLayers):
+        (WI.Layers3DContentView.prototype._clearLayers): Deleted.
+        Don't destroy all 3D objects on every LayerTreeDidChange; make use of layerTreeMutations.
+        (Not only a performance improvement, but also necessary to properly preserve highlighting.) 
+        
+        (WI.Layers3DContentView.prototype.selectLayerById):
+        Allow selection to be updated from the outside.
+
+        * UserInterface/Views/LayerDetailsSidebarPanel.js:
+        (WI.LayerDetailsSidebarPanel.prototype.selectNodeByLayerId):
+        (WI.LayerDetailsSidebarPanel.prototype._buildDataGrid):
+        (WI.LayerDetailsSidebarPanel.prototype._dataGridSelectedNodeChanged):
+        Allow selection to be updated from the outside.
+
+        (WI.LayerDetailsSidebarPanel.prototype.inspect):
+        (WI.LayerDetailsSidebarPanel.prototype._updateLayers): Renamed from _updateDisplayWithLayers.
+        (WI.LayerDetailsSidebarPanel.prototype._updateDataGrid):
+        (WI.LayerDetailsSidebarPanel.prototype._updateBottomBar):
+        (WI.LayerDetailsSidebarPanel.prototype._contentForPopover):
+        (WI.LayerDetailsSidebarPanel.prototype._dataGridNodeForLayer): Deleted.
+        Cleanup.
+        
+        * UserInterface/Views/LayersTabContentView.js:
+        (WI.LayersTabContentView):
+        (WI.LayersTabContentView.prototype._detailsSidebarSelectedLayerChanged):
+        (WI.LayersTabContentView.prototype._contentViewSelectedLayerChanged):
+        Orchestrate communication of selection state between visualization and sidebar.
+
 2017-10-11  Joseph Pecoraro  <[email protected]>
 
         Web Inspector: Avoid "100.00ms" vs "100.0ms" jitter in TimelineRuler labels

Modified: trunk/Source/WebInspectorUI/UserInterface/Views/LayerDetailsSidebarPanel.js (223208 => 223209)


--- trunk/Source/WebInspectorUI/UserInterface/Views/LayerDetailsSidebarPanel.js	2017-10-11 20:43:58 UTC (rev 223208)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/LayerDetailsSidebarPanel.js	2017-10-11 20:54:56 UTC (rev 223209)
@@ -51,7 +51,7 @@
             objects = [objects];
 
         let layers = objects.filter((object) => object instanceof WI.Layer);
-        this._updateDisplayWithLayers(layers);
+        this._updateLayers(layers);
 
         return !!layers.length;
     }
@@ -61,6 +61,18 @@
         this._popover = null;
     }
 
+    selectNodeByLayerId(layerId)
+    {
+        let node = this._dataGridNodesByLayerId.get(layerId);
+        if (node === this._dataGrid.selectedNode)
+            return;
+
+        if (node)
+            node.revealAndSelect();
+        else if (this._dataGrid.selectedNode)
+            this._dataGrid.selectedNode.deselect();
+    }
+
     // Private
 
     _buildDataGrid()
@@ -92,9 +104,14 @@
         this._dataGrid.sortOrder = WI.DataGrid.SortOrder.Descending;
         this._dataGrid.createSettings("layer-details-sidebar-panel");
 
-        this._dataGrid.element.addEventListener("mousemove", this._dataGridMouseMove.bind(this), false);
-        this._dataGrid.element.addEventListener("mouseleave", this._dataGridMouseLeave.bind(this), false);
+        this._dataGrid.element.addEventListener("mousemove", this._dataGridMouseMove.bind(this));
+        this._dataGrid.element.addEventListener("mouseleave", this._dataGridMouseLeave.bind(this));
 
+        // FIXME: We can't use virtualized rows until DataGrid is able to scroll them programmatically.
+        //        See TreeElement#reveal -> TreeOutline#updateVirtualizedElements for an analogy.
+        this._dataGrid.inline = true;
+        this._dataGrid.element.classList.remove("inline");
+
         this.contentView.addSubview(this._dataGrid);
     }
 
@@ -125,6 +142,9 @@
 
     _dataGridSelectedNodeChanged()
     {
+        let layerId = this._dataGrid.selectedNode ? this._dataGrid.selectedNode.layer.layerId : null;
+        this.dispatchEventToListeners(WI.LayerDetailsSidebarPanel.Event.SelectedLayerChanged, {layerId});
+
         this._showPopoverForSelectedNode();
     }
 
@@ -159,41 +179,38 @@
         this._hoveredDataGridNode = null;
     }
 
-    _updateDisplayWithLayers(newLayers)
+    _updateLayers(newLayers)
     {
-        let previousLayers = this._layers;
+        if (this._popover)
+            this._popover.dismiss();
+
+        this._updateDataGrid(newLayers);
+        this._updateBottomBar(newLayers);
+
         this._layers = newLayers;
-
-        this._updateDataGrid(previousLayers);
-        this._updateBottomBar();
     }
 
-    _updateDataGrid(previousLayers)
+    _updateDataGrid(newLayers)
     {
         if (!this._dataGrid)
             this._buildDataGrid();
 
-        let mutations = WI.layerTreeManager.layerTreeMutations(previousLayers, this._layers);
+        let {removals, additions, preserved} = WI.layerTreeManager.layerTreeMutations(this._layers, newLayers);
 
-        mutations.removals.forEach((layer) => {
+        removals.forEach((layer) => {
             let node = this._dataGridNodesByLayerId.get(layer.layerId);
-            if (!node)
-                return;
-
             this._dataGrid.removeChild(node);
             this._dataGridNodesByLayerId.delete(layer.layerId);
         });
 
-        mutations.additions.forEach((layer) => {
-            let node = this._dataGridNodeForLayer(layer);
+        additions.forEach((layer) => {
+            let node = new WI.LayerTreeDataGridNode(layer);
+            this._dataGridNodesByLayerId.set(layer.layerId, node);
             this._dataGrid.appendChild(node);
         });
 
-        mutations.preserved.forEach((layer) => {
+        preserved.forEach((layer) => {
             let node = this._dataGridNodesByLayerId.get(layer.layerId);
-            if (!node)
-                return;
-
             node.layer = layer;
         });
 
@@ -200,22 +217,14 @@
         this._sortDataGrid();
     }
 
-    _dataGridNodeForLayer(layer)
+    _updateBottomBar(newLayers)
     {
-        let node = new WI.LayerTreeDataGridNode(layer);
-        this._dataGridNodesByLayerId.set(layer.layerId, node);
-
-        return node;
-    }
-
-    _updateBottomBar()
-    {
         if (!this._bottomBar)
             this._buildBottomBar();
 
-        this._layersCountLabel.textContent = WI.UIString("Layer Count: %d").format(this._layers.length);
+        this._layersCountLabel.textContent = WI.UIString("Layer Count: %d").format(newLayers.length);
 
-        let totalMemory = this._layers.reduce((total, layer) => total + (layer.memory || 0), 0);
+        let totalMemory = newLayers.reduce((total, layer) => total + (layer.memory || 0), 0);
         this._layersMemoryLabel.textContent = WI.UIString("Memory: %s").format(Number.bytesToString(totalMemory));
     }
 
@@ -273,13 +282,9 @@
         let list = content.appendChild(document.createElement("ul"));
 
         WI.layerTreeManager.reasonsForCompositingLayer(layer, (compositingReasons) => {
-            if (isEmptyObject(compositingReasons)) {
-                callback(content);
-                return;
-            }
+            if (!isEmptyObject(compositingReasons))
+                this._populateListOfCompositingReasons(list, compositingReasons);
 
-            this._populateListOfCompositingReasons(list, compositingReasons);
-
             callback(content);
         });
 
@@ -349,3 +354,7 @@
             addReason(WI.UIString("Element has “blend-mode” style"));
     }
 };
+
+WI.LayerDetailsSidebarPanel.Event = {
+    SelectedLayerChanged: "selected-layer-changed"
+};

Modified: trunk/Source/WebInspectorUI/UserInterface/Views/Layers3DContentView.js (223208 => 223209)


--- trunk/Source/WebInspectorUI/UserInterface/Views/Layers3DContentView.js	2017-10-11 20:43:58 UTC (rev 223208)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/Layers3DContentView.js	2017-10-11 20:54:56 UTC (rev 223209)
@@ -34,13 +34,16 @@
         WI.layerTreeManager.addEventListener(WI.LayerTreeManager.Event.LayerTreeDidChange, this._layerTreeDidChange, this);
 
         this._layers = [];
+        this._layerGroupsById = new Map;
+        this._selectedLayerGroup = null;
         this._layersChangedWhileHidden = false;
+
         this._renderer = null;
         this._camera = null;
         this._controls = null;
-        this._boundsGroup = null;
-        this._compositedBoundsGroup = null;
         this._scene = null;
+        this._raycaster = null;
+        this._mouse = null;
         this._animationFrameRequestId = null;
     }
 
@@ -79,6 +82,12 @@
         super.closed();
     }
 
+    selectLayerById(layerId)
+    {
+        let layerGroup = this._layerGroupsById.get(layerId);
+        this._updateLayerGroupSelection(layerGroup);
+    }
+
     // Protected
 
     initialLayout()
@@ -100,14 +109,13 @@
         this._controls.minAzimuthAngle = -Math.PI / 2;
         this._controls.maxAzimuthAngle = Math.PI / 2;
 
-        this._boundsGroup = new THREE.Group();
-        this._compositedBoundsGroup = new THREE.Group();
-
-        this._scene = new THREE.Scene();
+        this._scene = new THREE.Scene;
         this._scene.position.set(-this.element.offsetWidth / 2, this.element.offsetHeight / 2, 0);
-        this._scene.add(this._boundsGroup);
-        this._scene.add(this._compositedBoundsGroup);
 
+        this._raycaster = new THREE.Raycaster;
+        this._mouse = new THREE.Vector2;
+        this._renderer.domElement.addEventListener("mousedown", this._canvasMouseDown.bind(this));
+
         this.element.appendChild(this._renderer.domElement);
 
         this._animate();
@@ -120,11 +128,7 @@
 
         WI.domTreeManager.requestDocument((node) => {
             WI.layerTreeManager.layersForNode(node, (layerForNode, childLayers) => {
-                this._clearLayers();
-                for (let i = 0; i < childLayers.length; i++)
-                    this._addLayer(childLayers[i], i);
-
-                this._layers = childLayers;
+                this._updateLayers(childLayers);
                 this.dispatchEventToListeners(WI.ContentView.Event.SelectionPathComponentsDidChange);
             });
         });
@@ -166,30 +170,58 @@
         this._animationFrameRequestId = null;
     }
 
-    _clearLayers()
+    _updateLayers(newLayers)
     {
-        this._boundsGroup.children.length = 0;
-        this._compositedBoundsGroup.children.length = 0;
+        // FIXME: This should be made into the basic usage of the manager, if not the agent itself.
+        //        At that point, we can remove this duplication from the visualization and sidebar.
+        let {removals, additions, preserved} = WI.layerTreeManager.layerTreeMutations(this._layers, newLayers);
+
+        for (let layer of removals) {
+            let layerGroup = this._layerGroupsById.get(layer.layerId);
+            this._scene.remove(layerGroup);
+            this._layerGroupsById.delete(layer.layerId);
+        }
+
+        if (this._selectedLayerGroup && !this._layerGroupsById.get(this._selectedLayerGroup.userData.layerId))
+            this.selectedLayerGroup = null;
+
+        additions.forEach(this._addLayerGroup, this);
+        preserved.forEach(this._updateLayerGroupPosition, this);
+
+        this._layers = newLayers;
     }
 
-    _addLayer(layer, index)
+    _addLayerGroup(layer, index)
     {
-        this._boundsGroup.add(this._createLayerMesh(layer.bounds, index));
-        this._compositedBoundsGroup.add(this._createLayerMesh(layer.compositedBounds, index, true));
+        let layerGroup = new THREE.Group;
+        layerGroup.userData.layerId = layer.layerId;
+        layerGroup.add(this._createLayerMesh(layer.bounds));
+        layerGroup.add(this._createLayerMesh(layer.compositedBounds, true));
+
+        this._layerGroupsById.set(layer.layerId, layerGroup);
+        this._updateLayerGroupPosition(layer, index);
+
+        this._scene.add(layerGroup);
     }
 
-    _createLayerMesh(rect, index, isOutline = false)
-    {
+    _updateLayerGroupPosition(layer, index) {
+        let layerGroup = this._layerGroupsById.get(layer.layerId);
+        console.assert(layerGroup);
+
         const zInterval = 25;
+        layerGroup.position.set(layer.bounds.x, -layer.bounds.y, index * zInterval);
+    }
 
-        let geometry = new THREE.Geometry();
-        geometry.vertices.push(new THREE.Vector3(rect.x,              -rect.y,               index * zInterval));
-        geometry.vertices.push(new THREE.Vector3(rect.x + rect.width, -rect.y,               index * zInterval));
-        geometry.vertices.push(new THREE.Vector3(rect.x + rect.width, -rect.y - rect.height, index * zInterval));
-        geometry.vertices.push(new THREE.Vector3(rect.x,              -rect.y - rect.height, index * zInterval));
+    _createLayerMesh({width, height}, isOutline = false)
+    {
+        let geometry = new THREE.Geometry;
+        geometry.vertices.push(new THREE.Vector3(0,     0,       0));
+        geometry.vertices.push(new THREE.Vector3(width, 0,       0));
+        geometry.vertices.push(new THREE.Vector3(width, -height, 0));
+        geometry.vertices.push(new THREE.Vector3(0,     -height, 0));
 
         if (isOutline) {
-            let material = new THREE.LineBasicMaterial({color: "hsl(79, 45%, 50%)"});
+            let material = new THREE.LineBasicMaterial({color: WI.Layers3DContentView._layerColor.stroke});
             return new THREE.LineLoop(geometry, material);
         }
 
@@ -197,7 +229,7 @@
         geometry.faces.push(new THREE.Face3(1, 2, 3));
 
         let material = new THREE.MeshBasicMaterial({
-            color: "hsl(76, 49%, 75%)",
+            color: WI.Layers3DContentView._layerColor.fill,
             transparent: true,
             opacity: 0.4,
             side: THREE.DoubleSide,
@@ -205,4 +237,57 @@
 
         return new THREE.Mesh(geometry, material);
     }
+
+    _canvasMouseDown(event)
+    {
+        this._mouse.x = (event.offsetX / event.target.width) * 2 - 1;
+        this._mouse.y = -(event.offsetY / event.target.height) * 2 + 1;
+        this._raycaster.setFromCamera(this._mouse, this._camera);
+
+        const recursive = true;
+        let intersects = this._raycaster.intersectObjects(this._scene.children, recursive);
+        let selection = intersects.length ? intersects[0].object.parent : null;
+        if (selection && selection === this._selectedLayerGroup) {
+            if (!event.metaKey)
+                return;
+
+            selection = null;
+        }
+
+        this._updateLayerGroupSelection(selection);
+
+        let layerId = selection ? selection.userData.layerId : null;
+        this.dispatchEventToListeners(WI.Layers3DContentView.Event.SelectedLayerChanged, {layerId});
+    }
+
+    _updateLayerGroupSelection(layerGroup)
+    {
+        let setColor = ({fill, stroke}) => {
+            let [plane, outline] = this._selectedLayerGroup.children;
+            plane.material.color.set(fill);
+            outline.material.color.set(stroke);
+        };
+
+        if (this._selectedLayerGroup)
+            setColor(WI.Layers3DContentView._layerColor);
+
+        this._selectedLayerGroup = layerGroup;
+
+        if (this._selectedLayerGroup)
+            setColor(WI.Layers3DContentView._selectedLayerColor);
+    }
 };
+
+WI.Layers3DContentView._layerColor = {
+    fill: "hsl(76, 49%, 75%)",
+    stroke: "hsl(79, 45%, 50%)"
+};
+
+WI.Layers3DContentView._selectedLayerColor = {
+    fill: "hsl(208, 66%, 79%)",
+    stroke: "hsl(202, 57%, 68%)"
+};
+
+WI.Layers3DContentView.Event = {
+    SelectedLayerChanged: "selected-layer-changed"
+};

Modified: trunk/Source/WebInspectorUI/UserInterface/Views/LayersTabContentView.js (223208 => 223209)


--- trunk/Source/WebInspectorUI/UserInterface/Views/LayersTabContentView.js	2017-10-11 20:43:58 UTC (rev 223208)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/LayersTabContentView.js	2017-10-11 20:54:56 UTC (rev 223209)
@@ -35,7 +35,11 @@
         const disableBackForward = true;
         super("layers", "layers", tabBarItem, navigationSidebarPanelConstructor, detailsSidebarPanelConstructors, disableBackForward);
 
+        this._layerDetailsSidebarPanel = this.detailsSidebarPanels[0];
+        this._layerDetailsSidebarPanel.addEventListener(WI.LayerDetailsSidebarPanel.Event.SelectedLayerChanged, this._detailsSidebarSelectedLayerChanged, this);
+
         this._layers3DContentView = new WI.Layers3DContentView;
+        this._layers3DContentView.addEventListener(WI.Layers3DContentView.Event.SelectedLayerChanged, this._contentViewSelectedLayerChanged, this);
     }
 
     // Static
@@ -64,6 +68,18 @@
 
         this.contentBrowser.showContentView(this._layers3DContentView);
     }
+
+    // Private
+
+    _detailsSidebarSelectedLayerChanged(event)
+    {
+        this._layers3DContentView.selectLayerById(event.data.layerId);
+    }
+
+    _contentViewSelectedLayerChanged(event)
+    {
+        this._layerDetailsSidebarPanel.selectNodeByLayerId(event.data.layerId);
+    }
 };
 
 WI.LayersTabContentView.Type = "layers";
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to