Commit b1a59a0b authored by Patrick Brosset's avatar Patrick Brosset Committed by Commit Bot

DevTools: Boilerplate code for the new Flexbox on-hover overlay

This adds the code necessary to highlight flex containers on hover in
DevTools.
For now, only the container's content box can be highlighted.

Frontend CL: https://chromium-review.googlesource.com/c/devtools/devtools-frontend/+/2488661/

Bug: 1139949
Change-Id: I8268227095bec552f45cc93d4240b555c3ad2534
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2487065
Commit-Queue: Patrick Brosset <patrick.brosset@microsoft.com>
Reviewed-by: default avatarChristian Biesinger <cbiesinger@chromium.org>
Reviewed-by: default avatarAndrey Kosyakov <caseq@chromium.org>
Reviewed-by: default avatarAlex Rudenko <alexrudenko@chromium.org>
Cr-Commit-Position: refs/heads/master@{#824351}
parent 5f91c63b
......@@ -5629,6 +5629,22 @@ experimental domain Overlay
# The grid container background color (Default: transparent).
optional DOM.RGBA gridBackgroundColor
# Configuration data for the highlighting of Flex container elements.
type FlexContainerHighlightConfig extends object
properties
# The style of the container border
optional LineStyle containerBorder
# Style information for drawing a line.
type LineStyle extends object
properties
# The color of the line (default: transparent)
optional DOM.RGBA color
# The line pattern (default: solid)
optional enum pattern
dashed
dotted
# Configuration data for the highlighting of page elements.
type HighlightConfig extends object
properties
......@@ -5662,6 +5678,8 @@ experimental domain Overlay
optional ColorFormat colorFormat
# The grid layout highlight configuration (default: all transparent).
optional GridHighlightConfig gridHighlightConfig
# The flex container highlight configuration (default: all transparent).
optional FlexContainerHighlightConfig flexContainerHighlightConfig
type ColorFormat extends string
enum
......
......@@ -365,6 +365,27 @@ std::unique_ptr<protocol::DictionaryValue> BuildTextNodeInfo(Text* text_node) {
return text_info;
}
std::unique_ptr<protocol::DictionaryValue>
BuildFlexContainerHighlightConfigInfo(
const InspectorFlexContainerHighlightConfig& flex_config) {
std::unique_ptr<protocol::DictionaryValue> flex_config_info =
protocol::DictionaryValue::create();
// Container border style
if (flex_config.container_border &&
flex_config.container_border->color != Color::kTransparent) {
std::unique_ptr<protocol::DictionaryValue> border_config =
protocol::DictionaryValue::create();
border_config->setString("color",
flex_config.container_border->color.Serialized());
border_config->setString("pattern", flex_config.container_border->pattern);
flex_config_info->setValue("containerBorder", std::move(border_config));
}
return flex_config_info;
}
std::unique_ptr<protocol::DictionaryValue> BuildGridHighlightConfigInfo(
const InspectorGridHighlightConfig& grid_config) {
std::unique_ptr<protocol::DictionaryValue> grid_config_info =
......@@ -807,6 +828,34 @@ Vector<String> GetAuthoredGridTrackSizes(const CSSValue* value,
return result;
}
std::unique_ptr<protocol::DictionaryValue> BuildFlexInfo(
Node* node,
const InspectorFlexContainerHighlightConfig&
flex_container_highlight_config,
float scale) {
LocalFrameView* containing_view = node->GetDocument().View();
LayoutObject* layout_object = node->GetLayoutObject();
DCHECK(layout_object);
std::unique_ptr<protocol::DictionaryValue> flex_info =
protocol::DictionaryValue::create();
// For now, we're only drawing a path around the container's content area.
PathBuilder container_border_builder;
LayoutBox* layout_box = ToLayoutBox(layout_object);
PhysicalRect content_box = layout_box->PhysicalContentBoxRect();
FloatQuad content_quad = layout_object->LocalRectToAbsoluteQuad(content_box);
FrameQuadToViewport(containing_view, content_quad);
container_border_builder.AppendPath(QuadToPath(content_quad), scale);
flex_info->setValue("containerBorder", container_border_builder.Release());
flex_info->setValue(
"flexContainerHighlightConfig",
BuildFlexContainerHighlightConfigInfo(flex_container_highlight_config));
return flex_info;
}
std::unique_ptr<protocol::DictionaryValue> BuildGridInfo(
Node* node,
const InspectorGridHighlightConfig& grid_highlight_config,
......@@ -1071,6 +1120,8 @@ InspectorHighlight::InspectorHighlight(float scale)
InspectorSourceOrderConfig::InspectorSourceOrderConfig() = default;
LineStyle::LineStyle() = default;
InspectorGridHighlightConfig::InspectorGridHighlightConfig()
: show_grid_extension_lines(false),
grid_border_dash(false),
......@@ -1082,6 +1133,9 @@ InspectorGridHighlightConfig::InspectorGridHighlightConfig()
show_line_names(false),
show_track_sizes(false) {}
InspectorFlexContainerHighlightConfig::InspectorFlexContainerHighlightConfig() =
default;
InspectorHighlightBase::InspectorHighlightBase(float scale)
: highlight_paths_(protocol::ListValue::create()), scale_(scale) {}
......@@ -1423,13 +1477,24 @@ void InspectorHighlight::AppendNodeHighlight(
AppendQuad(border, highlight_config.border, Color::kTransparent, "border");
AppendQuad(margin, highlight_config.margin, Color::kTransparent, "margin");
if (highlight_config.css_grid == Color::kTransparent &&
!highlight_config.grid_highlight_config) {
return;
if (highlight_config.css_grid != Color::kTransparent ||
highlight_config.grid_highlight_config) {
grid_info_ = protocol::ListValue::create();
if (layout_object->IsLayoutGrid()) {
grid_info_->pushValue(
BuildGridInfo(node, highlight_config, scale_, true));
}
}
grid_info_ = protocol::ListValue::create();
if (layout_object->IsLayoutGrid()) {
grid_info_->pushValue(BuildGridInfo(node, highlight_config, scale_, true));
if (highlight_config.flex_container_highlight_config) {
flex_info_ = protocol::ListValue::create();
// Some objects are flexible boxes even though display:flex is not set, we
// need to avoid those.
if (layout_object->StyleRef().IsDisplayFlexibleBox() &&
layout_object->IsFlexibleBoxIncludingNG()) {
flex_info_->pushValue(BuildFlexInfo(
node, *(highlight_config.flex_container_highlight_config), scale_));
}
}
}
......@@ -1476,6 +1541,8 @@ std::unique_ptr<protocol::DictionaryValue> InspectorHighlight::AsProtocolValue()
object->setValue("elementInfo", element_info_->clone());
if (grid_info_ && grid_info_->size() > 0)
object->setValue("gridInfo", grid_info_->clone());
if (flex_info_ && flex_info_->size() > 0)
object->setValue("flexInfo", flex_info_->clone());
return object;
}
......@@ -1641,6 +1708,9 @@ InspectorHighlightConfig InspectorHighlight::DefaultConfig() {
config.color_format = ColorFormat::HEX;
config.grid_highlight_config = std::make_unique<InspectorGridHighlightConfig>(
InspectorHighlight::DefaultGridConfig());
config.flex_container_highlight_config =
std::make_unique<InspectorFlexContainerHighlightConfig>(
InspectorHighlight::DefaultFlexContainerConfig());
return config;
}
......@@ -1668,4 +1738,21 @@ InspectorGridHighlightConfig InspectorHighlight::DefaultGridConfig() {
return config;
}
// static
InspectorFlexContainerHighlightConfig
InspectorHighlight::DefaultFlexContainerConfig() {
InspectorFlexContainerHighlightConfig config;
config.container_border =
std::make_unique<LineStyle>(InspectorHighlight::DefaultLineStyle());
return config;
}
// static
LineStyle InspectorHighlight::DefaultLineStyle() {
LineStyle style;
style.color = Color(255, 0, 0, 0);
style.pattern = "solid";
return style;
}
} // namespace blink
......@@ -18,6 +18,17 @@ namespace blink {
class Color;
enum class ColorFormat { RGB, HEX, HSL };
struct CORE_EXPORT LineStyle {
USING_FAST_MALLOC(LineStyle);
public:
LineStyle();
Color color;
String pattern;
};
struct CORE_EXPORT InspectorSourceOrderConfig {
USING_FAST_MALLOC(InspectorSourceOrderConfig);
......@@ -55,6 +66,15 @@ struct CORE_EXPORT InspectorGridHighlightConfig {
bool show_track_sizes;
};
struct CORE_EXPORT InspectorFlexContainerHighlightConfig {
USING_FAST_MALLOC(InspectorFlexContainerHighlightConfig);
public:
InspectorFlexContainerHighlightConfig();
std::unique_ptr<LineStyle> container_border;
};
struct CORE_EXPORT InspectorHighlightConfig {
USING_FAST_MALLOC(InspectorHighlightConfig);
......@@ -81,6 +101,8 @@ struct CORE_EXPORT InspectorHighlightConfig {
ColorFormat color_format;
std::unique_ptr<InspectorGridHighlightConfig> grid_highlight_config;
std::unique_ptr<InspectorFlexContainerHighlightConfig>
flex_container_highlight_config;
};
struct InspectorHighlightContrastInfo {
......@@ -148,6 +170,7 @@ class CORE_EXPORT InspectorHighlight : public InspectorHighlightBase {
std::unique_ptr<protocol::Array<protocol::Array<double>>>*);
static InspectorHighlightConfig DefaultConfig();
static InspectorGridHighlightConfig DefaultGridConfig();
static InspectorFlexContainerHighlightConfig DefaultFlexContainerConfig();
void AppendEventTargetQuads(Node* event_target_node,
const InspectorHighlightConfig&);
std::unique_ptr<protocol::DictionaryValue> AsProtocolValue() const override;
......@@ -163,12 +186,15 @@ class CORE_EXPORT InspectorHighlight : public InspectorHighlightBase {
LayoutObject* layout_object);
void AddLayoutBoxToDistanceInfo(LayoutObject* layout_object);
static LineStyle DefaultLineStyle();
std::unique_ptr<protocol::Array<protocol::Array<double>>> boxes_;
std::unique_ptr<protocol::DictionaryValue> computed_style_;
std::unique_ptr<protocol::DOM::BoxModel> model_;
std::unique_ptr<protocol::DictionaryValue> distance_info_;
std::unique_ptr<protocol::DictionaryValue> element_info_;
std::unique_ptr<protocol::ListValue> grid_info_;
std::unique_ptr<protocol::ListValue> flex_info_;
bool show_rulers_;
bool show_extension_lines_;
bool show_accessibility_info_;
......
......@@ -1479,6 +1479,34 @@ InspectorOverlayAgent::ToGridHighlightConfig(
return highlight_config;
}
// static
std::unique_ptr<InspectorFlexContainerHighlightConfig>
InspectorOverlayAgent::ToFlexContainerHighlightConfig(
protocol::Overlay::FlexContainerHighlightConfig* config) {
if (!config) {
return nullptr;
}
std::unique_ptr<InspectorFlexContainerHighlightConfig> highlight_config =
std::make_unique<InspectorFlexContainerHighlightConfig>();
highlight_config->container_border =
InspectorOverlayAgent::ToLineStyle(config->getContainerBorder(nullptr));
return highlight_config;
}
// static
std::unique_ptr<LineStyle> InspectorOverlayAgent::ToLineStyle(
protocol::Overlay::LineStyle* config) {
if (!config) {
return nullptr;
}
std::unique_ptr<LineStyle> line_style = std::make_unique<LineStyle>();
line_style->color = InspectorDOMAgent::ParseColor(config->getColor(nullptr));
line_style->pattern = config->getPattern("solid");
return line_style;
}
// static
std::unique_ptr<InspectorHighlightConfig>
InspectorOverlayAgent::ToHighlightConfig(
......@@ -1523,6 +1551,10 @@ InspectorOverlayAgent::ToHighlightConfig(
highlight_config->grid_highlight_config =
InspectorOverlayAgent::ToGridHighlightConfig(
config->getGridHighlightConfig(nullptr));
highlight_config->flex_container_highlight_config =
InspectorOverlayAgent::ToFlexContainerHighlightConfig(
config->getFlexContainerHighlightConfig(nullptr));
return highlight_config;
}
......
......@@ -145,6 +145,10 @@ class CORE_EXPORT InspectorOverlayAgent final
public:
static std::unique_ptr<InspectorGridHighlightConfig> ToGridHighlightConfig(
protocol::Overlay::GridHighlightConfig*);
static std::unique_ptr<InspectorFlexContainerHighlightConfig>
ToFlexContainerHighlightConfig(
protocol::Overlay::FlexContainerHighlightConfig*);
static std::unique_ptr<LineStyle> ToLineStyle(protocol::Overlay::LineStyle*);
static std::unique_ptr<InspectorHighlightConfig> ToHighlightConfig(
protocol::Overlay::HighlightConfig*);
InspectorOverlayAgent(WebLocalFrameImpl*,
......
......@@ -2064,6 +2064,7 @@ class ComputedStyle : public ComputedStyleBase,
return IsDisplayBlockContainer(Display());
}
bool IsDisplayTableBox() const { return IsDisplayTableBox(Display()); }
bool IsDisplayFlexibleBox() const { return IsDisplayFlexibleBox(Display()); }
bool IsDisplayFlexibleOrGridBox() const {
return IsDisplayFlexibleBox(Display()) || IsDisplayGridBox(Display());
}
......
This test verifies the position and size of the highlight rectangles overlayed on an inspected CSS flex div.
flex-container{
"paths": [
{
"path": [
"M",
8,
8,
"L",
508,
8,
"L",
508,
108,
"L",
8,
108,
"Z"
],
"fillColor": "rgba(255, 0, 0, 0)",
"outlineColor": "rgba(128, 0, 0, 0)",
"name": "content"
},
{
"path": [
"M",
8,
8,
"L",
508,
8,
"L",
508,
108,
"L",
8,
108,
"Z"
],
"fillColor": "rgba(0, 255, 0, 0)",
"name": "padding"
},
{
"path": [
"M",
8,
8,
"L",
508,
8,
"L",
508,
108,
"L",
8,
108,
"Z"
],
"fillColor": "rgba(0, 0, 255, 0)",
"name": "border"
},
{
"path": [
"M",
8,
8,
"L",
792,
8,
"L",
792,
108,
"L",
8,
108,
"Z"
],
"fillColor": "rgba(255, 255, 255, 0)",
"name": "margin"
}
],
"showRulers": true,
"showExtensionLines": true,
"showAccessibilityInfo": true,
"colorFormat": "hex",
"elementInfo": {
"tagName": "div",
"idValue": "flex-container",
"nodeWidth": "500",
"nodeHeight": "100",
"isKeyboardFocusable": false,
"accessibleName": "",
"accessibleRole": "generic",
"layoutObjectName": "LayoutNGFlexibleBox",
"showAccessibilityInfo": true
},
"flexInfo": [
{
"containerBorder": [
"M",
8,
8,
"L",
508,
8,
"L",
508,
108,
"L",
8,
108,
"Z"
],
"flexContainerHighlightConfig": {
"containerBorder": {
"color": "rgba(255, 0, 0, 0)",
"pattern": "solid"
}
}
}
]
}
should-not-be-flexbox{
"paths": [
{
"path": [
"M",
8,
108,
"L",
58,
108,
"L",
58,
158,
"L",
8,
158,
"Z"
],
"fillColor": "rgba(255, 0, 0, 0)",
"outlineColor": "rgba(128, 0, 0, 0)",
"name": "content"
},
{
"path": [
"M",
8,
108,
"L",
58,
108,
"L",
58,
158,
"L",
8,
158,
"Z"
],
"fillColor": "rgba(0, 255, 0, 0)",
"name": "padding"
},
{
"path": [
"M",
8,
108,
"L",
58,
108,
"L",
58,
158,
"L",
8,
158,
"Z"
],
"fillColor": "rgba(0, 0, 255, 0)",
"name": "border"
},
{
"path": [
"M",
8,
108,
"L",
58,
108,
"L",
58,
158,
"L",
8,
158,
"Z"
],
"fillColor": "rgba(255, 255, 255, 0)",
"name": "margin"
}
],
"showRulers": true,
"showExtensionLines": true,
"showAccessibilityInfo": true,
"colorFormat": "hex",
"elementInfo": {
"tagName": "button",
"idValue": "should-not-be-flexbox",
"nodeWidth": "50",
"nodeHeight": "50",
"isKeyboardFocusable": true,
"accessibleName": "click",
"accessibleRole": "button",
"layoutObjectName": "LayoutNGButton",
"showAccessibilityInfo": true
}
}
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
(async function() {
TestRunner.addResult(`This test verifies the position and size of the highlight rectangles overlayed on an inspected CSS flex div.\n`);
await TestRunner.loadModule('elements_test_runner');
await TestRunner.showPanel('elements');
await TestRunner.loadHTML(`
<style>
#flex-container {
width: 500px;
height: 100px;
display: flex;
}
.item {
margin: 10px;
flex: 1;
}
button {
width: 50px;
height: 50px;
border: 0;
padding: 0;
}
</style>
<div id="flex-container">
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
</div>
<button id="should-not-be-flexbox">click</button>
<p id="description">This test verifies the position and size of the highlight rectangles overlayed on an inspected CSS flex div.</p>
`);
function dumFlexHighlight(id) {
return new Promise(resolve => ElementsTestRunner.dumpInspectorHighlightJSON(id, resolve));
}
await dumFlexHighlight('flex-container');
await dumFlexHighlight('should-not-be-flexbox');
TestRunner.completeTest();
})();
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