Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Web Inspector: Show grid/flex overlays when highlighting elements
https://bugs.webkit.org/show_bug.cgi?id=251937

Reviewed by Patrick Angle.

This makes it so that the experience is the same between element selection and highlighting elements in Web Inspector (e.g. via the Elements Tab). Otherwise, it could be confusing for a developer to see grid/flex/etc. overlays when in element selection but not when highlighting the same element in Web Inspector.

* Source/JavaScriptCore/inspector/protocol/DOM.json:
* Source/WebCore/inspector/agents/InspectorDOMAgent.h:
* Source/WebCore/inspector/agents/InspectorDOMAgent.cpp:
(WebCore::InspectorDOMAgent::willDestroyFrontendAndBackend):
(WebCore::InspectorDOMAgent::handleTouchEvent):
(WebCore::InspectorDOMAgent::highlightMousedOverNode):
(WebCore::InspectorDOMAgent::setSearchingForNode):
(WebCore::InspectorDOMAgent::gridOverlayConfigFromInspectorObject):
(WebCore::InspectorDOMAgent::flexOverlayConfigFromInspectorObject):
(WebCore::InspectorDOMAgent::highlightSelector):
(WebCore::InspectorDOMAgent::highlightNode):
(WebCore::InspectorDOMAgent::highlightNodeList):
Add optional parameters for `DOM.GridOverlayConfig` and `DOM.FlexOverlayConfig` to `DOM.highlightSelector`, `DOM.highlightNode`, and `DOM.highlightNodeList`.

* Source/WebCore/inspector/InspectorOverlay.h:
* Source/WebCore/inspector/InspectorOverlay.cpp:
(WebCore::isInNodeList): Added.
(WebCore::InspectorOverlay::paint):
(WebCore::InspectorOverlay::getHighlight):
(WebCore::InspectorOverlay::hideHighlight):
(WebCore::InspectorOverlay::highlightNodeList):
(WebCore::InspectorOverlay::highlightNode):
(WebCore::InspectorOverlay::shouldShowOverlay const):
(WebCore::InspectorOverlay::showHighlightGridOverlayForNode): Deleted.
(WebCore::InspectorOverlay::hideHighlightGridOverlay): Deleted.
(WebCore::InspectorOverlay::showHighlightFlexOverlayForNode): Deleted.
(WebCore::InspectorOverlay::hideHighlightFlexOverlay): Deleted.
Move the logic for `*Highlight{Grid,Flex}Overlay` to be part of `highlightNodeList` and `highlightNode`, since they all operate on the same `m_highlightNode` (and `m_highlightNodeList`) anyways.

* Source/WebInspectorUI/UserInterface/Controllers/DOMManager.js:
(WI.DOMManager.buildHighlightConfigs): Renamed from `buildHighlightConfig`.
(WI.DOMManager.prototype.highlightDOMNodeList):
(WI.DOMManager.prototype.highlightSelector):
(WI.DOMManager.prototype.set inspectModeEnabled):
* Source/WebInspectorUI/UserInterface/Models/DOMNode.js:
(WI.DOMNode.prototype.highlight):
Pass all the grid/flex overlay options to all callers of `DOM.highlightSelector`, `DOM.highlightNode`, and `DOM.highlightNodeList`.
Drive-by: Unify all the places where these arguments are generated to avoid repeated code.

Canonical link: https://commits.webkit.org/260061@main
  • Loading branch information
dcrousso committed Feb 9, 2023
1 parent 5149f37 commit 7cd3669
Show file tree
Hide file tree
Showing 7 changed files with 217 additions and 178 deletions.
16 changes: 11 additions & 5 deletions Source/JavaScriptCore/inspector/protocol/DOM.json
Expand Up @@ -494,26 +494,32 @@
"description": "Highlights all DOM nodes that match a given selector. A string containing a CSS selector must be specified.",
"targetTypes": ["page"],
"parameters": [
{ "name": "highlightConfig", "$ref": "HighlightConfig", "description": "A descriptor for the highlight appearance." },
{ "name": "selectorString", "type": "string", "description": "A CSS selector for finding matching nodes to highlight." },
{ "name": "frameId", "type": "string", "optional": true, "description": "Identifier of the frame which will be searched using the selector. If not provided, the main frame will be used." }
{ "name": "frameId", "type": "string", "optional": true, "description": "Identifier of the frame which will be searched using the selector. If not provided, the main frame will be used." },
{ "name": "highlightConfig", "$ref": "HighlightConfig", "description": "A descriptor for the highlight appearance." },
{ "name": "gridOverlayConfig", "$ref": "GridOverlayConfig", "optional": true, "description": "If provided, used to configure a grid overlay shown during element selection. This overrides DOM.showGridOverlay." },
{ "name": "flexOverlayConfig", "$ref": "FlexOverlayConfig", "optional": true, "description": "If provided, used to configure a flex overlay shown during element selection. This overrides DOM.showFlexOverlay." }
]
},
{
"name": "highlightNode",
"description": "Highlights DOM node with given id or with the given JavaScript object wrapper. Either nodeId or objectId must be specified.",
"parameters": [
{ "name": "highlightConfig", "$ref": "HighlightConfig", "description": "A descriptor for the highlight appearance." },
{ "name": "nodeId", "$ref": "NodeId", "optional": true, "description": "Identifier of the node to highlight." },
{ "name": "objectId", "$ref": "Runtime.RemoteObjectId", "optional": true, "description": "JavaScript object id of the node to be highlighted." }
{ "name": "objectId", "$ref": "Runtime.RemoteObjectId", "optional": true, "description": "JavaScript object id of the node to be highlighted." },
{ "name": "highlightConfig", "$ref": "HighlightConfig", "description": "A descriptor for the highlight appearance." },
{ "name": "gridOverlayConfig", "$ref": "GridOverlayConfig", "optional": true, "description": "If provided, used to configure a grid overlay shown during element selection. This overrides DOM.showGridOverlay." },
{ "name": "flexOverlayConfig", "$ref": "FlexOverlayConfig", "optional": true, "description": "If provided, used to configure a flex overlay shown during element selection. This overrides DOM.showFlexOverlay." }
]
},
{
"name": "highlightNodeList",
"description": "Highlights each DOM node in the given list.",
"parameters": [
{ "name": "nodeIds", "type": "array", "items": { "$ref": "NodeId" } },
{ "name": "highlightConfig", "$ref": "HighlightConfig" }
{ "name": "highlightConfig", "$ref": "HighlightConfig" },
{ "name": "gridOverlayConfig", "$ref": "GridOverlayConfig", "optional": true, "description": "If provided, used to configure a grid overlay shown during element selection. This overrides DOM.showGridOverlay." },
{ "name": "flexOverlayConfig", "$ref": "FlexOverlayConfig", "optional": true, "description": "If provided, used to configure a flex overlay shown during element selection. This overrides DOM.showFlexOverlay." }
]
},
{
Expand Down
171 changes: 96 additions & 75 deletions Source/WebCore/inspector/InspectorOverlay.cpp
Expand Up @@ -95,6 +95,15 @@ static constexpr UChar emSpace = 0x2003;

enum class Flip : bool { No, Yes };

static bool isInNodeList(const Node& node, const NodeList& list)
{
for (unsigned i = 0; i < list.length(); ++i) {
if (&node == list.item(i))
return true;
}
return false;
}

static void truncateWithEllipsis(String& string, size_t length)
{
if (string.length() > length)
Expand Down Expand Up @@ -421,6 +430,16 @@ void InspectorOverlay::paint(GraphicsContext& context)
if (auto* node = m_highlightNodeList->item(i)) {
auto nodeRulerExclusion = drawNodeHighlight(context, *node);
rulerExclusion.bounds.unite(nodeRulerExclusion.bounds);

if (m_nodeGridOverlayConfig) {
if (auto gridHighlightOverlay = buildGridOverlay({ *node, *m_nodeGridOverlayConfig }))
drawGridOverlay(context, *gridHighlightOverlay);
}

if (m_nodeFlexOverlayConfig) {
if (auto flexHighlightOverlay = buildFlexOverlay({ *node, *m_nodeFlexOverlayConfig }))
drawFlexOverlay(context, *flexHighlightOverlay);
}
}
}
}
Expand All @@ -429,34 +448,42 @@ void InspectorOverlay::paint(GraphicsContext& context)
auto nodeRulerExclusion = drawNodeHighlight(context, *m_highlightNode);
rulerExclusion.bounds.unite(nodeRulerExclusion.bounds);
rulerExclusion.titlePath = nodeRulerExclusion.titlePath;

if (m_nodeGridOverlayConfig) {
if (auto gridHighlightOverlay = buildGridOverlay({ *m_highlightNode, *m_nodeGridOverlayConfig }))
drawGridOverlay(context, *gridHighlightOverlay);
}

if (m_nodeFlexOverlayConfig) {
if (auto flexHighlightOverlay = buildFlexOverlay({ *m_highlightNode, *m_nodeFlexOverlayConfig }))
drawFlexOverlay(context, *flexHighlightOverlay);
}
}

for (const InspectorOverlay::Grid& gridOverlay : m_activeGridOverlays) {
if (m_highlightGridOverlay && gridOverlay.gridNode == m_highlightGridOverlay->gridNode)
continue;
if (m_nodeGridOverlayConfig && gridOverlay.gridNode) {
if (m_highlightNodeList && isInNodeList(*gridOverlay.gridNode, *m_highlightNodeList))
continue;
if (gridOverlay.gridNode == m_highlightNode.get())
continue;
}

if (auto gridHighlightOverlay = buildGridOverlay(gridOverlay))
drawGridOverlay(context, *gridHighlightOverlay);
}

if (m_highlightGridOverlay) {
if (auto gridHighlightOverlay = buildGridOverlay(*m_highlightGridOverlay))
drawGridOverlay(context, *gridHighlightOverlay);
}

for (const InspectorOverlay::Flex& flexOverlay : m_activeFlexOverlays) {
if (m_highlightFlexOverlay && flexOverlay.flexNode == m_highlightFlexOverlay->flexNode)
continue;
if (m_nodeFlexOverlayConfig && flexOverlay.flexNode) {
if (m_highlightNodeList && isInNodeList(*flexOverlay.flexNode, *m_highlightNodeList))
continue;
if (flexOverlay.flexNode == m_highlightNode.get())
continue;
}

if (auto flexHighlightOverlay = buildFlexOverlay(flexOverlay))
drawFlexOverlay(context, *flexHighlightOverlay);
}

if (m_highlightFlexOverlay) {
if (auto flexHighlightOverlay = buildFlexOverlay(*m_highlightFlexOverlay))
drawFlexOverlay(context, *flexHighlightOverlay);
}

if (!m_paintRects.isEmpty())
drawPaintRects(context, m_paintRects);

Expand All @@ -466,76 +493,106 @@ void InspectorOverlay::paint(GraphicsContext& context)

void InspectorOverlay::getHighlight(InspectorOverlay::Highlight& highlight, InspectorOverlay::CoordinateSystem coordinateSystem)
{
if (!m_highlightNode && !m_highlightQuad && !m_highlightNodeList && !m_highlightGridOverlay && !m_activeGridOverlays.size() && !m_highlightFlexOverlay && !m_activeFlexOverlays.size())
if (!m_highlightNode && !m_highlightQuad && !m_highlightNodeList && !m_activeGridOverlays.size() && !m_activeFlexOverlays.size())
return;

constexpr bool offsetBoundsByScroll = true;

highlight.type = InspectorOverlay::Highlight::Type::None;
if (m_highlightNode)
if (m_highlightNode) {
buildNodeHighlight(*m_highlightNode, m_nodeHighlightConfig, highlight, coordinateSystem);
else if (m_highlightNodeList) {

if (m_nodeGridOverlayConfig) {
if (auto gridHighlightOverlay = buildGridOverlay({ *m_highlightNode, *m_nodeGridOverlayConfig }, offsetBoundsByScroll))
highlight.gridHighlightOverlays.append(*gridHighlightOverlay);
}

if (m_nodeFlexOverlayConfig) {
if (auto flexHighlightOverlay = buildFlexOverlay({ *m_highlightNode, *m_nodeFlexOverlayConfig }))
highlight.flexHighlightOverlays.append(*flexHighlightOverlay);
}
} else if (m_highlightNodeList) {
highlight.setDataFromConfig(m_nodeHighlightConfig);
for (unsigned i = 0; i < m_highlightNodeList->length(); ++i) {
auto* node = m_highlightNodeList->item(i);

InspectorOverlay::Highlight nodeHighlight;
buildNodeHighlight(*(m_highlightNodeList->item(i)), m_nodeHighlightConfig, nodeHighlight, coordinateSystem);
buildNodeHighlight(*node, m_nodeHighlightConfig, nodeHighlight, coordinateSystem);
if (nodeHighlight.type == InspectorOverlay::Highlight::Type::Node)
highlight.quads.appendVector(nodeHighlight.quads);

if (m_nodeGridOverlayConfig) {
if (auto gridHighlightOverlay = buildGridOverlay({ *node, *m_nodeGridOverlayConfig }, offsetBoundsByScroll))
highlight.gridHighlightOverlays.append(*gridHighlightOverlay);
}

if (m_nodeFlexOverlayConfig) {
if (auto flexHighlightOverlay = buildFlexOverlay({ *node, *m_nodeFlexOverlayConfig }))
highlight.flexHighlightOverlays.append(*flexHighlightOverlay);
}
}
highlight.type = InspectorOverlay::Highlight::Type::NodeList;
} else if (m_highlightQuad) {
highlight.type = InspectorOverlay::Highlight::Type::Rects;
buildQuadHighlight(*m_highlightQuad, m_quadHighlightConfig, highlight);
}

constexpr bool offsetBoundsByScroll = true;

for (const InspectorOverlay::Grid& gridOverlay : m_activeGridOverlays) {
if (m_highlightGridOverlay && gridOverlay.gridNode == m_highlightGridOverlay->gridNode)
continue;
if (m_nodeGridOverlayConfig && gridOverlay.gridNode) {
if (m_highlightNodeList && isInNodeList(*gridOverlay.gridNode, *m_highlightNodeList))
continue;
if (gridOverlay.gridNode == m_highlightNode.get())
continue;
}

if (auto gridHighlightOverlay = buildGridOverlay(gridOverlay, offsetBoundsByScroll))
highlight.gridHighlightOverlays.append(*gridHighlightOverlay);
}

if (m_highlightGridOverlay) {
if (auto gridHighlightOverlay = buildGridOverlay(*m_highlightGridOverlay, offsetBoundsByScroll))
highlight.gridHighlightOverlays.append(*gridHighlightOverlay);
}

for (const InspectorOverlay::Flex& flexOverlay : m_activeFlexOverlays) {
if (m_highlightFlexOverlay && flexOverlay.flexNode == m_highlightFlexOverlay->flexNode)
continue;
if (m_nodeFlexOverlayConfig && flexOverlay.flexNode) {
if (m_highlightNodeList && isInNodeList(*flexOverlay.flexNode, *m_highlightNodeList))
continue;
if (flexOverlay.flexNode == m_highlightNode.get())
continue;
}

if (auto flexHighlightOverlay = buildFlexOverlay(flexOverlay))
highlight.flexHighlightOverlays.append(*flexHighlightOverlay);
}

if (m_highlightFlexOverlay) {
if (auto flexHighlightOverlay = buildFlexOverlay(*m_highlightFlexOverlay))
highlight.flexHighlightOverlays.append(*flexHighlightOverlay);
}
}

void InspectorOverlay::hideHighlight()
{
m_highlightNode = nullptr;
m_highlightNodeList = nullptr;
m_nodeHighlightConfig = { };
m_nodeGridOverlayConfig = std::nullopt;
m_nodeFlexOverlayConfig = std::nullopt;

m_highlightQuad = nullptr;
m_quadHighlightConfig = { };

update();
}

void InspectorOverlay::highlightNodeList(RefPtr<NodeList>&& nodes, const InspectorOverlay::Highlight::Config& highlightConfig)
void InspectorOverlay::highlightNodeList(RefPtr<NodeList>&& nodes, const InspectorOverlay::Highlight::Config& highlightConfig, const std::optional<Grid::Config>& gridOverlayConfig, const std::optional<Flex::Config>& flexOverlayConfig)
{
m_nodeHighlightConfig = highlightConfig;
m_highlightNodeList = WTFMove(nodes);
m_highlightNode = nullptr;
m_highlightNodeList = WTFMove(nodes);
m_nodeHighlightConfig = highlightConfig;
m_nodeGridOverlayConfig = gridOverlayConfig;
m_nodeFlexOverlayConfig = flexOverlayConfig;
update();
}

void InspectorOverlay::highlightNode(Node* node, const InspectorOverlay::Highlight::Config& highlightConfig)
void InspectorOverlay::highlightNode(Node* node, const InspectorOverlay::Highlight::Config& highlightConfig, const std::optional<Grid::Config>& gridOverlayConfig, const std::optional<Flex::Config>& flexOverlayConfig)
{
m_nodeHighlightConfig = highlightConfig;
m_highlightNode = node;
m_highlightNodeList = nullptr;
m_nodeHighlightConfig = highlightConfig;
m_nodeGridOverlayConfig = gridOverlayConfig;
m_nodeFlexOverlayConfig = flexOverlayConfig;
update();
}

Expand Down Expand Up @@ -576,9 +633,7 @@ bool InspectorOverlay::shouldShowOverlay() const
return m_highlightNode
|| m_highlightNodeList
|| m_highlightQuad
|| m_highlightGridOverlay
|| m_activeGridOverlays.size()
|| m_highlightFlexOverlay
|| m_activeFlexOverlays.size()
|| m_indicating
|| m_showPaintRects
Expand Down Expand Up @@ -650,23 +705,6 @@ bool InspectorOverlay::removeGridOverlayForNode(Node& node)
});
}

void InspectorOverlay::showHighlightGridOverlayForNode(Node& node, const InspectorOverlay::Grid::Config& gridOverlayConfig)
{
if (!is<RenderGrid>(node.renderer())) {
hideHighlightGridOverlay();
return;
}

m_highlightGridOverlay = { node, gridOverlayConfig };
update();
}

void InspectorOverlay::hideHighlightGridOverlay()
{
m_highlightGridOverlay = std::nullopt;
update();
}

ErrorStringOr<void> InspectorOverlay::setGridOverlayForNode(Node& node, const InspectorOverlay::Grid::Config& gridOverlayConfig)
{
RenderObject* renderer = node.renderer();
Expand Down Expand Up @@ -707,23 +745,6 @@ bool InspectorOverlay::removeFlexOverlayForNode(Node& node)
});
}

void InspectorOverlay::showHighlightFlexOverlayForNode(Node& node, const InspectorOverlay::Flex::Config& flexOverlayConfig)
{
if (!is<RenderFlexibleBox>(node.renderer())) {
hideHighlightFlexOverlay();
return;
}

m_highlightFlexOverlay = { node, flexOverlayConfig };
update();
}

void InspectorOverlay::hideHighlightFlexOverlay()
{
m_highlightFlexOverlay = std::nullopt;
update();
}

ErrorStringOr<void> InspectorOverlay::setFlexOverlayForNode(Node& node, const InspectorOverlay::Flex::Config& flexOverlayConfig)
{
if (!is<RenderFlexibleBox>(node.renderer()))
Expand Down
13 changes: 4 additions & 9 deletions Source/WebCore/inspector/InspectorOverlay.h
Expand Up @@ -201,8 +201,8 @@ class InspectorOverlay {
bool shouldShowOverlay() const;

void hideHighlight();
void highlightNodeList(RefPtr<NodeList>&&, const Highlight::Config&);
void highlightNode(Node*, const Highlight::Config&);
void highlightNodeList(RefPtr<NodeList>&&, const Highlight::Config&, const std::optional<Grid::Config>& = std::nullopt, const std::optional<Flex::Config>& = std::nullopt);
void highlightNode(Node*, const Highlight::Config&, const std::optional<Grid::Config>& = std::nullopt, const std::optional<Flex::Config>& = std::nullopt);
void highlightQuad(std::unique_ptr<FloatQuad>, const Highlight::Config&);

void setShowPaintRects(bool);
Expand All @@ -223,14 +223,10 @@ class InspectorOverlay {
// Multiple grid and flex overlays can be active at the same time. These methods
// will fail if the node is not a grid or if the node has been GC'd.

void showHighlightGridOverlayForNode(Node&, const InspectorOverlay::Grid::Config&);
void hideHighlightGridOverlay();
Inspector::ErrorStringOr<void> setGridOverlayForNode(Node&, const InspectorOverlay::Grid::Config&);
Inspector::ErrorStringOr<void> clearGridOverlayForNode(Node&);
void clearAllGridOverlays();

void showHighlightFlexOverlayForNode(Node&, const InspectorOverlay::Flex::Config&);
void hideHighlightFlexOverlay();
Inspector::ErrorStringOr<void> setFlexOverlayForNode(Node&, const InspectorOverlay::Flex::Config&);
Inspector::ErrorStringOr<void> clearFlexOverlayForNode(Node&);
void clearAllFlexOverlays();
Expand Down Expand Up @@ -267,17 +263,16 @@ class InspectorOverlay {
RefPtr<Node> m_highlightNode;
RefPtr<NodeList> m_highlightNodeList;
Highlight::Config m_nodeHighlightConfig;
std::optional<Grid::Config> m_nodeGridOverlayConfig;
std::optional<Flex::Config> m_nodeFlexOverlayConfig;

std::unique_ptr<FloatQuad> m_highlightQuad;
Highlight::Config m_quadHighlightConfig;

Deque<TimeRectPair> m_paintRects;
Timer m_paintRectUpdateTimer;

std::optional<InspectorOverlay::Grid> m_highlightGridOverlay;
Vector<InspectorOverlay::Grid> m_activeGridOverlays;

std::optional<InspectorOverlay::Flex> m_highlightFlexOverlay;
Vector<InspectorOverlay::Flex> m_activeFlexOverlays;

bool m_indicating { false };
Expand Down

0 comments on commit 7cd3669

Please sign in to comment.