Commit 3d9b1dd6 authored by Erik Luo's avatar Erik Luo Committed by Commit Bot

DevTools: highight text nodes with overlay

Hovering over a TextNode in DevTools will now highlight it on the
page. Its tooltip shows "#text" with VisualOverflowRect dimensions.

Screenshot: https://imgur.com/a/yPFT73e

Bug: 893426
Change-Id: If988e72960aa68b2d9c666c5de3feb5ce1192509
Reviewed-on: https://chromium-review.googlesource.com/c/1269859Reviewed-by: default avatarDmitry Gozman <dgozman@chromium.org>
Commit-Queue: Erik Luo <luoe@chromium.org>
Cr-Commit-Position: refs/heads/master@{#607013}
parent 674a1d16
This test verifies the position and size of the highlight rectangles overlayed on an inspected div.
This test verifies the position and size of the highlight rectangles overlaid on an inspected node.
inspectedElement{
"paths": [
......@@ -91,3 +91,183 @@ inspectedElement{
"displayAsMaterial": false
}
First text node{
"paths": [
{
"path": [
"M",
"<number>",
"<number>",
"L",
"<number>",
"<number>",
"L",
"<number>",
"<number>",
"L",
"<number>",
"<number>",
"Z"
],
"fillColor": "rgba(255, 0, 0, 0)",
"outlineColor": "rgba(128, 0, 0, 0)",
"name": "content"
},
{
"path": [
"M",
"<number>",
"<number>",
"L",
"<number>",
"<number>",
"L",
"<number>",
"<number>",
"L",
"<number>",
"<number>",
"Z"
],
"fillColor": "rgba(0, 255, 0, 0)",
"name": "padding"
},
{
"path": [
"M",
"<number>",
"<number>",
"L",
"<number>",
"<number>",
"L",
"<number>",
"<number>",
"L",
"<number>",
"<number>",
"Z"
],
"fillColor": "rgba(0, 0, 255, 0)",
"name": "border"
},
{
"path": [
"M",
"<number>",
"<number>",
"L",
"<number>",
"<number>",
"L",
"<number>",
"<number>",
"L",
"<number>",
"<number>",
"Z"
],
"fillColor": "rgba(255, 255, 255, 0)",
"name": "margin"
}
],
"showRulers": true,
"showExtensionLines": true,
"elementInfo": {
"nodeWidth": "Width within 3px from 28? true",
"nodeHeight": "Height within 3px from 25? true",
"tagName": "#text"
},
"displayAsMaterial": false
}
Second text node{
"paths": [
{
"path": [
"M",
"<number>",
"<number>",
"L",
"<number>",
"<number>",
"L",
"<number>",
"<number>",
"L",
"<number>",
"<number>",
"Z"
],
"fillColor": "rgba(255, 0, 0, 0)",
"outlineColor": "rgba(128, 0, 0, 0)",
"name": "content"
},
{
"path": [
"M",
"<number>",
"<number>",
"L",
"<number>",
"<number>",
"L",
"<number>",
"<number>",
"L",
"<number>",
"<number>",
"Z"
],
"fillColor": "rgba(0, 255, 0, 0)",
"name": "padding"
},
{
"path": [
"M",
"<number>",
"<number>",
"L",
"<number>",
"<number>",
"L",
"<number>",
"<number>",
"L",
"<number>",
"<number>",
"Z"
],
"fillColor": "rgba(0, 0, 255, 0)",
"name": "border"
},
{
"path": [
"M",
"<number>",
"<number>",
"L",
"<number>",
"<number>",
"L",
"<number>",
"<number>",
"L",
"<number>",
"<number>",
"Z"
],
"fillColor": "rgba(255, 255, 255, 0)",
"name": "margin"
}
],
"showRulers": true,
"showExtensionLines": true,
"elementInfo": {
"nodeWidth": "Width within 3px from 30? true",
"nodeHeight": "Height within 3px from 24? true",
"tagName": "#text"
},
"displayAsMaterial": false
}
......@@ -4,7 +4,7 @@
(async function() {
TestRunner.addResult(
`This test verifies the position and size of the highlight rectangles overlayed on an inspected div.\n`);
`This test verifies the position and size of the highlight rectangles overlaid on an inspected node.\n`);
await TestRunner.loadModule('elements_test_runner');
await TestRunner.showPanel('elements');
await TestRunner.loadHTML(`
......@@ -29,12 +29,69 @@
}
#description {
clear: both;
height: 10px;
font-size: 20px;
font-family: Arial;
}
</style>
<div id="inspectedElement"></div>
<p id="description"></p>
<p id="description">foo<br />bar</p>
`);
ElementsTestRunner.dumpInspectorHighlightJSON('inspectedElement', TestRunner.completeTest.bind(TestRunner));
const div = await ElementsTestRunner.nodeWithIdPromise('inspectedElement');
await nodeResolved(div, 'inspectedElement');
let textNode = await ElementsTestRunner.findNodePromise(node => {
return node.nodeType() === Node.TEXT_NODE && node.parentNode && node.parentNode.nodeName() === 'P' && node.parentNode.children()[0] === node;
});
await nodeResolvedApproximate(textNode, '\nFirst text node', 28, 25);
textNode = await ElementsTestRunner.findNodePromise(node => {
return node.nodeType() === Node.TEXT_NODE && node.parentNode && node.parentNode.nodeName() === 'P' && node.parentNode.children()[2] === node;
});
await nodeResolvedApproximate(textNode, '\nSecond text node', 30, 24);
TestRunner.completeTest();
/**
* @param {!Node} node
* @param {string} name
* @param {!Promise}
*/
async function nodeResolved(node, name) {
const result = await TestRunner.OverlayAgent.getHighlightObjectForTest(node.id);
TestRunner.addResult(name + JSON.stringify(result, null, 2));
}
/**
* @param {!Node} node
* @param {string} name
* @param {number} expectedWidth
* @param {number} expectedHeight
* @param {number=} tolerance
* @param {!Promise}
*/
async function nodeResolvedApproximate(node, name, expectedWidth, expectedHeight, tolerance = 3) {
const result = await TestRunner.OverlayAgent.getHighlightObjectForTest(node.id);
if (result['paths']) {
for (const path of result['paths']) {
path['path'] = path['path'].map(value => {
return typeof value === 'number' ? '<number>' : value;
});
}
}
if (result['elementInfo']) {
const actualWidth = result['elementInfo']['nodeWidth'];
const actualHeight = result['elementInfo']['nodeHeight'];
const widthInTolerance = Math.abs(actualWidth - expectedWidth) < tolerance;
const heightInTolerance = Math.abs(actualHeight - expectedHeight) < tolerance;
result['elementInfo']['nodeWidth'] = `Width within ${tolerance}px from ${expectedWidth}? ${widthInTolerance}`;
result['elementInfo']['nodeHeight'] = `Height within ${tolerance}px from ${expectedHeight}? ${heightInTolerance}`;
}
TestRunner.addResult(name + JSON.stringify(result, null, 2));
}
})();
......@@ -240,6 +240,20 @@ std::unique_ptr<protocol::DictionaryValue> BuildElementInfo(Element* element) {
return element_info;
}
std::unique_ptr<protocol::DictionaryValue> BuildTextNodeInfo(Text* text_node) {
std::unique_ptr<protocol::DictionaryValue> text_info =
protocol::DictionaryValue::create();
LayoutObject* layout_object = text_node->GetLayoutObject();
if (!layout_object || !layout_object->IsText())
return text_info;
LayoutRect bounding_box = ToLayoutText(layout_object)->VisualOverflowRect();
text_info->setString("nodeWidth", bounding_box.Width().ToString());
text_info->setString("nodeHeight", bounding_box.Height().ToString());
text_info->setString("tagName", "#text");
return text_info;
}
std::unique_ptr<protocol::Value> BuildGapAndPositions(
double origin,
LayoutUnit gap,
......@@ -346,6 +360,8 @@ InspectorHighlight::InspectorHighlight(
AppendNodeHighlight(node, highlight_config);
if (append_element_info && node->IsElementNode())
element_info_ = BuildElementInfo(ToElement(node));
else if (append_element_info && node->IsTextNode())
element_info_ = BuildTextNodeInfo(ToText(node));
}
InspectorHighlight::~InspectorHighlight() = default;
......@@ -606,7 +622,8 @@ bool InspectorHighlight::BuildNodeQuads(Node* node,
LocalFrameView* containing_view = layout_object->GetFrameView();
if (!containing_view)
return false;
if (!layout_object->IsBox() && !layout_object->IsLayoutInline())
if (!layout_object->IsBox() && !layout_object->IsLayoutInline() &&
!layout_object->IsText())
return false;
LayoutRect content_box;
......@@ -614,7 +631,14 @@ bool InspectorHighlight::BuildNodeQuads(Node* node,
LayoutRect border_box;
LayoutRect margin_box;
if (layout_object->IsBox()) {
if (layout_object->IsText()) {
LayoutText* layout_text = ToLayoutText(layout_object);
LayoutRect text_rect = layout_text->VisualOverflowRect();
content_box = text_rect;
padding_box = text_rect;
border_box = text_rect;
margin_box = text_rect;
} else if (layout_object->IsBox()) {
LayoutBox* layout_box = ToLayoutBox(layout_object);
// LayoutBox returns the "pure" content area box, exclusive of the
......
......@@ -697,8 +697,9 @@ void InspectorOverlayAgent::DrawNodeHighlight() {
}
bool append_element_info =
highlight_node_->IsElementNode() && !omit_tooltip_ &&
node_highlight_config_.show_info && highlight_node_->GetLayoutObject() &&
(highlight_node_->IsElementNode() || highlight_node_->IsTextNode()) &&
!omit_tooltip_ && node_highlight_config_.show_info &&
highlight_node_->GetLayoutObject() &&
highlight_node_->GetDocument().GetFrame();
InspectorHighlight highlight(highlight_node_.Get(), node_highlight_config_,
append_element_info);
......
......@@ -92,6 +92,14 @@ ElementsTestRunner.findNode = async function(matchFunction, callback) {
doc.getChildNodes(processChildren.bind(null, doc));
};
/**
* @param {function(!Element): boolean} matchFunction
* @param {!Promise}
*/
ElementsTestRunner.findNodePromise = function(matchFunction) {
return new Promise(resolve => ElementsTestRunner.findNode(matchFunction, resolve));
};
/**
* @param {!EventListeners.EventListenersView} eventListenersView
* @param {function():void} callback
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment