1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "third_party/blink/renderer/core/inspector/inspector_highlight.h"
6 
7 #include "base/macros.h"
8 #include "third_party/blink/renderer/core/css/css_color_value.h"
9 #include "third_party/blink/renderer/core/css/css_computed_style_declaration.h"
10 #include "third_party/blink/renderer/core/css/css_grid_auto_repeat_value.h"
11 #include "third_party/blink/renderer/core/css/css_grid_integer_repeat_value.h"
12 #include "third_party/blink/renderer/core/css/css_property_name.h"
13 #include "third_party/blink/renderer/core/css/css_property_names.h"
14 #include "third_party/blink/renderer/core/css/css_value.h"
15 #include "third_party/blink/renderer/core/display_lock/display_lock_utilities.h"
16 #include "third_party/blink/renderer/core/dom/pseudo_element.h"
17 #include "third_party/blink/renderer/core/frame/local_frame_view.h"
18 #include "third_party/blink/renderer/core/frame/visual_viewport.h"
19 #include "third_party/blink/renderer/core/geometry/dom_rect.h"
20 #include "third_party/blink/renderer/core/inspector/dom_traversal_utils.h"
21 #include "third_party/blink/renderer/core/inspector/inspector_dom_agent.h"
22 #include "third_party/blink/renderer/core/layout/adjust_for_absolute_zoom.h"
23 #include "third_party/blink/renderer/core/layout/geometry/physical_offset.h"
24 #include "third_party/blink/renderer/core/layout/layout_box.h"
25 #include "third_party/blink/renderer/core/layout/layout_flexible_box.h"
26 #include "third_party/blink/renderer/core/layout/layout_grid.h"
27 #include "third_party/blink/renderer/core/layout/layout_inline.h"
28 #include "third_party/blink/renderer/core/layout/layout_object.h"
29 #include "third_party/blink/renderer/core/layout/layout_view.h"
30 #include "third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h"
31 #include "third_party/blink/renderer/core/layout/shapes/shape_outside_info.h"
32 #include "third_party/blink/renderer/core/page/chrome_client.h"
33 #include "third_party/blink/renderer/core/page/page.h"
34 #include "third_party/blink/renderer/core/style/computed_style_constants.h"
35 #include "third_party/blink/renderer/core/style/grid_positions_resolver.h"
36 #include "third_party/blink/renderer/platform/geometry/float_point.h"
37 #include "third_party/blink/renderer/platform/geometry/layout_unit.h"
38 #include "third_party/blink/renderer/platform/graphics/path.h"
39 #include "third_party/blink/renderer/platform/text/writing_mode.h"
40 #include "third_party/blink/renderer/platform/web_test_support.h"
41 
42 namespace blink {
43 
44 namespace {
45 
46 class PathBuilder {
47   STACK_ALLOCATED();
48 
49  public:
PathBuilder()50   PathBuilder() : path_(protocol::ListValue::create()) {}
51   virtual ~PathBuilder() = default;
52 
Release()53   std::unique_ptr<protocol::ListValue> Release() { return std::move(path_); }
54 
AppendPath(const Path & path,float scale)55   void AppendPath(const Path& path, float scale) {
56     Path transform_path(path);
57     transform_path.Transform(AffineTransform().Scale(scale));
58     transform_path.Apply(this, &PathBuilder::AppendPathElement);
59   }
60 
61  protected:
TranslatePoint(const FloatPoint & point)62   virtual FloatPoint TranslatePoint(const FloatPoint& point) { return point; }
63 
64  private:
AppendPathElement(void * path_builder,const PathElement * path_element)65   static void AppendPathElement(void* path_builder,
66                                 const PathElement* path_element) {
67     static_cast<PathBuilder*>(path_builder)->AppendPathElement(path_element);
68   }
69 
70   void AppendPathElement(const PathElement*);
71   void AppendPathCommandAndPoints(const char* command,
72                                   const FloatPoint points[],
73                                   size_t length);
74 
75   std::unique_ptr<protocol::ListValue> path_;
76   DISALLOW_COPY_AND_ASSIGN(PathBuilder);
77 };
78 
AppendPathCommandAndPoints(const char * command,const FloatPoint points[],size_t length)79 void PathBuilder::AppendPathCommandAndPoints(const char* command,
80                                              const FloatPoint points[],
81                                              size_t length) {
82   path_->pushValue(protocol::StringValue::create(command));
83   for (size_t i = 0; i < length; i++) {
84     FloatPoint point = TranslatePoint(points[i]);
85     path_->pushValue(protocol::FundamentalValue::create(point.X()));
86     path_->pushValue(protocol::FundamentalValue::create(point.Y()));
87   }
88 }
89 
AppendPathElement(const PathElement * path_element)90 void PathBuilder::AppendPathElement(const PathElement* path_element) {
91   switch (path_element->type) {
92     // The points member will contain 1 value.
93     case kPathElementMoveToPoint:
94       AppendPathCommandAndPoints("M", path_element->points, 1);
95       break;
96     // The points member will contain 1 value.
97     case kPathElementAddLineToPoint:
98       AppendPathCommandAndPoints("L", path_element->points, 1);
99       break;
100     // The points member will contain 3 values.
101     case kPathElementAddCurveToPoint:
102       AppendPathCommandAndPoints("C", path_element->points, 3);
103       break;
104     // The points member will contain 2 values.
105     case kPathElementAddQuadCurveToPoint:
106       AppendPathCommandAndPoints("Q", path_element->points, 2);
107       break;
108     // The points member will contain no values.
109     case kPathElementCloseSubpath:
110       AppendPathCommandAndPoints("Z", nullptr, 0);
111       break;
112   }
113 }
114 
115 class ShapePathBuilder : public PathBuilder {
116  public:
ShapePathBuilder(LocalFrameView & view,LayoutObject & layout_object,const ShapeOutsideInfo & shape_outside_info)117   ShapePathBuilder(LocalFrameView& view,
118                    LayoutObject& layout_object,
119                    const ShapeOutsideInfo& shape_outside_info)
120       : view_(&view),
121         layout_object_(&layout_object),
122         shape_outside_info_(shape_outside_info) {}
123 
BuildPath(LocalFrameView & view,LayoutObject & layout_object,const ShapeOutsideInfo & shape_outside_info,const Path & path,float scale)124   static std::unique_ptr<protocol::ListValue> BuildPath(
125       LocalFrameView& view,
126       LayoutObject& layout_object,
127       const ShapeOutsideInfo& shape_outside_info,
128       const Path& path,
129       float scale) {
130     ShapePathBuilder builder(view, layout_object, shape_outside_info);
131     builder.AppendPath(path, scale);
132     return builder.Release();
133   }
134 
135  protected:
TranslatePoint(const FloatPoint & point)136   FloatPoint TranslatePoint(const FloatPoint& point) override {
137     PhysicalOffset layout_object_point = PhysicalOffset::FromFloatPointRound(
138         shape_outside_info_.ShapeToLayoutObjectPoint(point));
139     // TODO(pfeldman): Is this kIgnoreTransforms correct?
140     return FloatPoint(view_->FrameToViewport(
141         RoundedIntPoint(layout_object_->LocalToAbsolutePoint(
142             layout_object_point, kIgnoreTransforms))));
143   }
144 
145  private:
146   LocalFrameView* view_;
147   LayoutObject* const layout_object_;
148   const ShapeOutsideInfo& shape_outside_info_;
149 };
150 
BuildArrayForQuad(const FloatQuad & quad)151 std::unique_ptr<protocol::Array<double>> BuildArrayForQuad(
152     const FloatQuad& quad) {
153   return std::make_unique<std::vector<double>, std::initializer_list<double>>(
154       {quad.P1().X(), quad.P1().Y(), quad.P2().X(), quad.P2().Y(),
155        quad.P3().X(), quad.P3().Y(), quad.P4().X(), quad.P4().Y()});
156 }
157 
QuadToPath(const FloatQuad & quad)158 Path QuadToPath(const FloatQuad& quad) {
159   Path quad_path;
160   quad_path.MoveTo(quad.P1());
161   quad_path.AddLineTo(quad.P2());
162   quad_path.AddLineTo(quad.P3());
163   quad_path.AddLineTo(quad.P4());
164   quad_path.CloseSubpath();
165   return quad_path;
166 }
167 
RowQuadToPath(const FloatQuad & quad,bool drawEndLine)168 Path RowQuadToPath(const FloatQuad& quad, bool drawEndLine) {
169   Path quad_path;
170   quad_path.MoveTo(quad.P1());
171   quad_path.AddLineTo(quad.P2());
172   if (drawEndLine) {
173     quad_path.MoveTo(quad.P3());
174     quad_path.AddLineTo(quad.P4());
175   }
176   return quad_path;
177 }
178 
ColumnQuadToPath(const FloatQuad & quad,bool drawEndLine)179 Path ColumnQuadToPath(const FloatQuad& quad, bool drawEndLine) {
180   Path quad_path;
181   quad_path.MoveTo(quad.P1());
182   quad_path.AddLineTo(quad.P4());
183   if (drawEndLine) {
184     quad_path.MoveTo(quad.P3());
185     quad_path.AddLineTo(quad.P2());
186   }
187   return quad_path;
188 }
189 
FramePointToViewport(const LocalFrameView * view,FloatPoint point_in_frame)190 FloatPoint FramePointToViewport(const LocalFrameView* view,
191                                 FloatPoint point_in_frame) {
192   FloatPoint point_in_root_frame = view->ConvertToRootFrame(point_in_frame);
193   return view->GetPage()->GetVisualViewport().RootFrameToViewport(
194       point_in_root_frame);
195 }
196 
FrameQuadToViewport(const LocalFrameView * view,FloatQuad & quad)197 void FrameQuadToViewport(const LocalFrameView* view, FloatQuad& quad) {
198   quad.SetP1(FramePointToViewport(view, quad.P1()));
199   quad.SetP2(FramePointToViewport(view, quad.P2()));
200   quad.SetP3(FramePointToViewport(view, quad.P3()));
201   quad.SetP4(FramePointToViewport(view, quad.P4()));
202 }
203 
ShapeOutsideInfoForNode(Node * node,Shape::DisplayPaths * paths,FloatQuad * bounds)204 const ShapeOutsideInfo* ShapeOutsideInfoForNode(Node* node,
205                                                 Shape::DisplayPaths* paths,
206                                                 FloatQuad* bounds) {
207   LayoutObject* layout_object = node->GetLayoutObject();
208   if (!layout_object || !layout_object->IsBox() ||
209       !To<LayoutBox>(layout_object)->GetShapeOutsideInfo())
210     return nullptr;
211 
212   LocalFrameView* containing_view = node->GetDocument().View();
213   auto* layout_box = To<LayoutBox>(layout_object);
214   const ShapeOutsideInfo* shape_outside_info =
215       layout_box->GetShapeOutsideInfo();
216 
217   shape_outside_info->ComputedShape().BuildDisplayPaths(*paths);
218 
219   PhysicalRect shape_bounds =
220       shape_outside_info->ComputedShapePhysicalBoundingBox();
221   *bounds = layout_box->LocalRectToAbsoluteQuad(shape_bounds);
222   FrameQuadToViewport(containing_view, *bounds);
223 
224   return shape_outside_info;
225 }
226 
ToHEXA(const Color & color)227 String ToHEXA(const Color& color) {
228   return String::Format("#%02X%02X%02X%02X", color.Red(), color.Green(),
229                         color.Blue(), color.Alpha());
230 }
231 
AppendStyleInfo(Node * node,protocol::DictionaryValue * element_info,const InspectorHighlightContrastInfo & node_contrast)232 void AppendStyleInfo(Node* node,
233                      protocol::DictionaryValue* element_info,
234                      const InspectorHighlightContrastInfo& node_contrast) {
235   std::unique_ptr<protocol::DictionaryValue> computed_style =
236       protocol::DictionaryValue::create();
237   CSSComputedStyleDeclaration* style =
238       MakeGarbageCollected<CSSComputedStyleDeclaration>(node, true);
239   Vector<CSSPropertyID> properties;
240 
241   // For text nodes, we can show color & font properties.
242   bool has_text_children = false;
243   for (Node* child = node->firstChild(); !has_text_children && child;
244        child = child->nextSibling()) {
245     has_text_children = child->IsTextNode();
246   }
247   if (has_text_children) {
248     properties.push_back(CSSPropertyID::kColor);
249     properties.push_back(CSSPropertyID::kFontFamily);
250     properties.push_back(CSSPropertyID::kFontSize);
251     properties.push_back(CSSPropertyID::kLineHeight);
252   }
253 
254   properties.push_back(CSSPropertyID::kPadding);
255   properties.push_back(CSSPropertyID::kMargin);
256   properties.push_back(CSSPropertyID::kBackgroundColor);
257 
258   for (size_t i = 0; i < properties.size(); ++i) {
259     const CSSValue* value = style->GetPropertyCSSValue(properties[i]);
260     if (!value)
261       continue;
262     AtomicString name = CSSPropertyName(properties[i]).ToAtomicString();
263     if (value->IsColorValue()) {
264       Color color = static_cast<const cssvalue::CSSColorValue*>(value)->Value();
265       computed_style->setString(name, ToHEXA(color));
266     } else {
267       computed_style->setString(name, value->CssText());
268     }
269   }
270   element_info->setValue("style", std::move(computed_style));
271 
272   if (!node_contrast.font_size.IsEmpty()) {
273     std::unique_ptr<protocol::DictionaryValue> contrast =
274         protocol::DictionaryValue::create();
275     contrast->setString("fontSize", node_contrast.font_size);
276     contrast->setString("fontWeight", node_contrast.font_weight);
277     contrast->setString("backgroundColor",
278                         ToHEXA(node_contrast.background_color));
279     element_info->setValue("contrast", std::move(contrast));
280   }
281 }
282 
BuildElementInfo(Element * element)283 std::unique_ptr<protocol::DictionaryValue> BuildElementInfo(Element* element) {
284   std::unique_ptr<protocol::DictionaryValue> element_info =
285       protocol::DictionaryValue::create();
286   Element* real_element = element;
287   auto* pseudo_element = DynamicTo<PseudoElement>(element);
288   if (pseudo_element) {
289     real_element = element->ParentOrShadowHostElement();
290   }
291   bool is_xhtml = real_element->GetDocument().IsXHTMLDocument();
292   element_info->setString(
293       "tagName", is_xhtml ? real_element->nodeName()
294                           : real_element->nodeName().DeprecatedLower());
295   element_info->setString("idValue", real_element->GetIdAttribute());
296   StringBuilder class_names;
297   if (real_element->HasClass() && real_element->IsStyledElement()) {
298     HashSet<AtomicString> used_class_names;
299     const SpaceSplitString& class_names_string = real_element->ClassNames();
300     wtf_size_t class_name_count = class_names_string.size();
301     for (wtf_size_t i = 0; i < class_name_count; ++i) {
302       const AtomicString& class_name = class_names_string[i];
303       if (!used_class_names.insert(class_name).is_new_entry)
304         continue;
305       class_names.Append('.');
306       class_names.Append(class_name);
307     }
308   }
309   if (pseudo_element) {
310     if (pseudo_element->GetPseudoId() == kPseudoIdBefore)
311       class_names.Append("::before");
312     else if (pseudo_element->GetPseudoId() == kPseudoIdAfter)
313       class_names.Append("::after");
314     else if (pseudo_element->GetPseudoId() == kPseudoIdMarker)
315       class_names.Append("::marker");
316   }
317   if (!class_names.IsEmpty())
318     element_info->setString("className", class_names.ToString());
319 
320   LayoutObject* layout_object = element->GetLayoutObject();
321   LocalFrameView* containing_view = element->GetDocument().View();
322   if (!layout_object || !containing_view)
323     return element_info;
324 
325   // layoutObject the getBoundingClientRect() data in the tooltip
326   // to be consistent with the rulers (see http://crbug.com/262338).
327   DOMRect* bounding_box = element->getBoundingClientRect();
328   element_info->setString("nodeWidth", String::Number(bounding_box->width()));
329   element_info->setString("nodeHeight", String::Number(bounding_box->height()));
330 
331   element_info->setBoolean("isKeyboardFocusable",
332                            element->IsKeyboardFocusable());
333   element_info->setString("accessibleName", element->computedName());
334   element_info->setString("accessibleRole", element->computedRole());
335 
336   element_info->setString("layoutObjectName", layout_object->GetName());
337 
338   return element_info;
339 }
340 
BuildTextNodeInfo(Text * text_node)341 std::unique_ptr<protocol::DictionaryValue> BuildTextNodeInfo(Text* text_node) {
342   std::unique_ptr<protocol::DictionaryValue> text_info =
343       protocol::DictionaryValue::create();
344   LayoutObject* layout_object = text_node->GetLayoutObject();
345   if (!layout_object || !layout_object->IsText())
346     return text_info;
347   PhysicalRect bounding_box =
348       To<LayoutText>(layout_object)->PhysicalVisualOverflowRect();
349   text_info->setString("nodeWidth", bounding_box.Width().ToString());
350   text_info->setString("nodeHeight", bounding_box.Height().ToString());
351   text_info->setString("tagName", "#text");
352   text_info->setBoolean("showAccessibilityInfo", false);
353   return text_info;
354 }
355 
AppendLineStyleConfig(const std::unique_ptr<LineStyle> & line_style,std::unique_ptr<protocol::DictionaryValue> & parent_config,String line_name)356 void AppendLineStyleConfig(
357     const std::unique_ptr<LineStyle>& line_style,
358     std::unique_ptr<protocol::DictionaryValue>& parent_config,
359     String line_name) {
360   if (line_style && line_style->color != Color::kTransparent) {
361     std::unique_ptr<protocol::DictionaryValue> config =
362         protocol::DictionaryValue::create();
363     config->setString("color", line_style->color.Serialized());
364     config->setString("pattern", line_style->pattern);
365 
366     parent_config->setValue(line_name, std::move(config));
367   }
368 }
369 
370 std::unique_ptr<protocol::DictionaryValue>
BuildFlexContainerHighlightConfigInfo(const InspectorFlexContainerHighlightConfig & flex_config)371 BuildFlexContainerHighlightConfigInfo(
372     const InspectorFlexContainerHighlightConfig& flex_config) {
373   std::unique_ptr<protocol::DictionaryValue> flex_config_info =
374       protocol::DictionaryValue::create();
375 
376   AppendLineStyleConfig(flex_config.container_border, flex_config_info,
377                         "containerBorder");
378   AppendLineStyleConfig(flex_config.line_separator, flex_config_info,
379                         "lineSeparator");
380   AppendLineStyleConfig(flex_config.item_separator, flex_config_info,
381                         "itemSeparator");
382 
383   return flex_config_info;
384 }
385 
BuildGridHighlightConfigInfo(const InspectorGridHighlightConfig & grid_config)386 std::unique_ptr<protocol::DictionaryValue> BuildGridHighlightConfigInfo(
387     const InspectorGridHighlightConfig& grid_config) {
388   std::unique_ptr<protocol::DictionaryValue> grid_config_info =
389       protocol::DictionaryValue::create();
390   grid_config_info->setBoolean("gridBorderDash", grid_config.grid_border_dash);
391   grid_config_info->setBoolean("rowLineDash", grid_config.row_line_dash);
392   grid_config_info->setBoolean("columnLineDash", grid_config.column_line_dash);
393   grid_config_info->setBoolean("showGridExtensionLines",
394                                grid_config.show_grid_extension_lines);
395   grid_config_info->setBoolean("showPositiveLineNumbers",
396                                grid_config.show_positive_line_numbers);
397   grid_config_info->setBoolean("showNegativeLineNumbers",
398                                grid_config.show_negative_line_numbers);
399   grid_config_info->setBoolean("showAreaNames", grid_config.show_area_names);
400   grid_config_info->setBoolean("showLineNames", grid_config.show_line_names);
401 
402   if (grid_config.grid_color != Color::kTransparent) {
403     grid_config_info->setString("gridBorderColor",
404                                 grid_config.grid_color.Serialized());
405   }
406   if (grid_config.row_line_color != Color::kTransparent) {
407     grid_config_info->setString("rowLineColor",
408                                 grid_config.row_line_color.Serialized());
409   }
410   if (grid_config.column_line_color != Color::kTransparent) {
411     grid_config_info->setString("columnLineColor",
412                                 grid_config.column_line_color.Serialized());
413   }
414   if (grid_config.row_gap_color != Color::kTransparent) {
415     grid_config_info->setString("rowGapColor",
416                                 grid_config.row_gap_color.Serialized());
417   }
418   if (grid_config.column_gap_color != Color::kTransparent) {
419     grid_config_info->setString("columnGapColor",
420                                 grid_config.column_gap_color.Serialized());
421   }
422   if (grid_config.row_hatch_color != Color::kTransparent) {
423     grid_config_info->setString("rowHatchColor",
424                                 grid_config.row_hatch_color.Serialized());
425   }
426   if (grid_config.column_hatch_color != Color::kTransparent) {
427     grid_config_info->setString("columnHatchColor",
428                                 grid_config.column_hatch_color.Serialized());
429   }
430   if (grid_config.area_border_color != Color::kTransparent) {
431     grid_config_info->setString("areaBorderColor",
432                                 grid_config.area_border_color.Serialized());
433   }
434   if (grid_config.grid_background_color != Color::kTransparent) {
435     grid_config_info->setString("gridBackgroundColor",
436                                 grid_config.grid_background_color.Serialized());
437   }
438   return grid_config_info;
439 }
440 
441 // Swaps |left| and |top| of an offset.
Transpose(PhysicalOffset & offset)442 PhysicalOffset Transpose(PhysicalOffset& offset) {
443   return PhysicalOffset(offset.top, offset.left);
444 }
445 
GetTrackCount(const LayoutGrid * layout_grid,GridTrackSizingDirection direction)446 size_t GetTrackCount(const LayoutGrid* layout_grid,
447                      GridTrackSizingDirection direction) {
448   return direction == kForRows ? layout_grid->RowPositions().size()
449                                : layout_grid->ColumnPositions().size();
450 }
451 
GetPositionForTrackAt(const LayoutGrid * layout_grid,size_t index,GridTrackSizingDirection direction)452 LayoutUnit GetPositionForTrackAt(const LayoutGrid* layout_grid,
453                                  size_t index,
454                                  GridTrackSizingDirection direction) {
455   if (direction == kForRows)
456     return layout_grid->RowPositions().at(index);
457 
458   LayoutUnit position = layout_grid->ColumnPositions().at(index);
459   return layout_grid->StyleRef().IsLeftToRightDirection()
460              ? position
461              : layout_grid->TranslateRTLCoordinate(position);
462 }
463 
GetPositionForFirstTrack(const LayoutGrid * layout_grid,GridTrackSizingDirection direction)464 LayoutUnit GetPositionForFirstTrack(const LayoutGrid* layout_grid,
465                                     GridTrackSizingDirection direction) {
466   return GetPositionForTrackAt(layout_grid, 0, direction);
467 }
468 
GetPositionForLastTrack(const LayoutGrid * layout_grid,GridTrackSizingDirection direction)469 LayoutUnit GetPositionForLastTrack(const LayoutGrid* layout_grid,
470                                    GridTrackSizingDirection direction) {
471   size_t index = GetTrackCount(layout_grid, direction) - 1;
472   return GetPositionForTrackAt(layout_grid, index, direction);
473 }
474 
LocalToAbsolutePoint(Node * node,PhysicalOffset local,float scale)475 PhysicalOffset LocalToAbsolutePoint(Node* node,
476                                     PhysicalOffset local,
477                                     float scale) {
478   LayoutObject* layout_object = node->GetLayoutObject();
479   LayoutGrid* layout_grid = ToLayoutGrid(layout_object);
480   FloatPoint local_in_frame = FramePointToViewport(
481       node->GetDocument().View(), FloatPoint(local.left, local.top));
482   PhysicalOffset abs_number_pos = layout_grid->LocalToAbsolutePoint(
483       PhysicalOffset::FromFloatPointRound(local_in_frame));
484   abs_number_pos.Scale(scale);
485   return abs_number_pos;
486 }
487 
BuildPosition(PhysicalOffset position)488 std::unique_ptr<protocol::DictionaryValue> BuildPosition(
489     PhysicalOffset position) {
490   std::unique_ptr<protocol::DictionaryValue> result =
491       protocol::DictionaryValue::create();
492   result->setDouble("x", position.left);
493   result->setDouble("y", position.top);
494   return result;
495 }
496 
BuildGridTrackSizes(Node * node,GridTrackSizingDirection direction,float scale,LayoutUnit gap,const Vector<String> * authored_values)497 std::unique_ptr<protocol::ListValue> BuildGridTrackSizes(
498     Node* node,
499     GridTrackSizingDirection direction,
500     float scale,
501     LayoutUnit gap,
502     const Vector<String>* authored_values) {
503   LayoutObject* layout_object = node->GetLayoutObject();
504   LayoutGrid* layout_grid = ToLayoutGrid(layout_object);
505   bool is_rtl = direction == kForColumns &&
506                 !layout_grid->StyleRef().IsLeftToRightDirection();
507 
508   std::unique_ptr<protocol::ListValue> sizes = protocol::ListValue::create();
509   size_t track_count = GetTrackCount(layout_grid, direction);
510   LayoutUnit alt_axis_pos = GetPositionForFirstTrack(
511       layout_grid, direction == kForRows ? kForColumns : kForRows);
512 
513   for (size_t i = 1; i < track_count; i++) {
514     LayoutUnit current_position =
515         GetPositionForTrackAt(layout_grid, i, direction);
516     LayoutUnit prev_position =
517         GetPositionForTrackAt(layout_grid, i - 1, direction);
518     LayoutUnit gap_offset = i < track_count - 1 ? gap : LayoutUnit();
519     LayoutUnit width = current_position - prev_position - gap_offset;
520     if (is_rtl)
521       width = prev_position - current_position - gap_offset;
522     LayoutUnit main_axis_pos = prev_position + width / 2;
523     if (is_rtl)
524       main_axis_pos = prev_position - width / 2;
525     auto adjusted_size = AdjustForAbsoluteZoom::AdjustFloat(
526         width * scale, layout_grid->StyleRef());
527     PhysicalOffset track_size_pos(main_axis_pos, alt_axis_pos);
528     if (direction == kForRows)
529       track_size_pos = Transpose(track_size_pos);
530     std::unique_ptr<protocol::DictionaryValue> size_info =
531         BuildPosition(LocalToAbsolutePoint(node, track_size_pos, scale));
532     size_info->setDouble("computedSize", adjusted_size);
533     if (i - 1 < authored_values->size()) {
534       size_info->setString("authoredSize", authored_values->at(i - 1));
535     }
536     sizes->pushValue(std::move(size_info));
537   }
538 
539   return sizes;
540 }
541 
BuildGridPositiveLineNumberPositions(Node * node,const LayoutUnit & grid_gap,GridTrackSizingDirection direction,float scale)542 std::unique_ptr<protocol::ListValue> BuildGridPositiveLineNumberPositions(
543     Node* node,
544     const LayoutUnit& grid_gap,
545     GridTrackSizingDirection direction,
546     float scale) {
547   LayoutObject* layout_object = node->GetLayoutObject();
548   LayoutGrid* layout_grid = ToLayoutGrid(layout_object);
549   bool is_rtl = direction == kForColumns &&
550                 !layout_grid->StyleRef().IsLeftToRightDirection();
551 
552   std::unique_ptr<protocol::ListValue> number_positions =
553       protocol::ListValue::create();
554 
555   size_t track_count = GetTrackCount(layout_grid, direction);
556   LayoutUnit alt_axis_pos = GetPositionForFirstTrack(
557       layout_grid, direction == kForRows ? kForColumns : kForRows);
558 
559   // Find index of the first explicit Grid Line.
560   size_t first_explicit_index =
561       layout_grid->ExplicitGridStartForDirection(direction);
562 
563   // Go line by line, calculating the offset to fall in the middle of gaps
564   // if needed.
565   for (size_t i = first_explicit_index; i < track_count; ++i) {
566     LayoutUnit gapOffset = grid_gap / 2;
567     if (is_rtl)
568       gapOffset *= -1;
569     // No need for a gap offset if there is no gap, or the first line is
570     // explicit, or this is the last line.
571     if (grid_gap == 0 || i == 0 || i == track_count - 1) {
572       gapOffset = LayoutUnit();
573     }
574     LayoutUnit offset = GetPositionForTrackAt(layout_grid, i, direction);
575     PhysicalOffset number_position(offset - gapOffset, alt_axis_pos);
576     if (direction == kForRows)
577       number_position = Transpose(number_position);
578     number_positions->pushValue(
579         BuildPosition(LocalToAbsolutePoint(node, number_position, scale)));
580   }
581 
582   return number_positions;
583 }
584 
BuildGridNegativeLineNumberPositions(Node * node,const LayoutUnit & grid_gap,GridTrackSizingDirection direction,float scale)585 std::unique_ptr<protocol::ListValue> BuildGridNegativeLineNumberPositions(
586     Node* node,
587     const LayoutUnit& grid_gap,
588     GridTrackSizingDirection direction,
589     float scale) {
590   LayoutObject* layout_object = node->GetLayoutObject();
591   LayoutGrid* layout_grid = ToLayoutGrid(layout_object);
592   bool is_rtl = direction == kForColumns &&
593                 !layout_grid->StyleRef().IsLeftToRightDirection();
594 
595   std::unique_ptr<protocol::ListValue> number_positions =
596       protocol::ListValue::create();
597 
598   size_t track_count = GetTrackCount(layout_grid, direction);
599   LayoutUnit alt_axis_pos = GetPositionForLastTrack(
600       layout_grid, direction == kForRows ? kForColumns : kForRows);
601 
602   // This is the number of tracks from the start of the grid, to the end of the
603   // explicit grid (including any leading implicit tracks).
604   size_t explicit_grid_end_track_count =
605       layout_grid->ExplicitGridEndForDirection(direction);
606 
607   {
608     LayoutUnit first_offset = GetPositionForFirstTrack(layout_grid, direction);
609 
610     // Always start negative numbers at the first line.
611     std::unique_ptr<protocol::DictionaryValue> pos =
612         protocol::DictionaryValue::create();
613     PhysicalOffset number_position(first_offset, alt_axis_pos);
614     if (direction == kForRows)
615       number_position = Transpose(number_position);
616     number_positions->pushValue(
617         BuildPosition(LocalToAbsolutePoint(node, number_position, scale)));
618   }
619 
620   // Then go line by line, calculating the offset to fall in the middle of gaps
621   // if needed.
622   for (size_t i = 1; i <= explicit_grid_end_track_count; i++) {
623     LayoutUnit gapOffset = grid_gap / 2;
624     if (is_rtl)
625       gapOffset *= -1;
626     if (grid_gap == 0 ||
627         (i == explicit_grid_end_track_count && i == track_count - 1)) {
628       gapOffset = LayoutUnit();
629     }
630     LayoutUnit offset = GetPositionForTrackAt(layout_grid, i, direction);
631     PhysicalOffset number_position(offset - gapOffset, alt_axis_pos);
632     if (direction == kForRows)
633       number_position = Transpose(number_position);
634     number_positions->pushValue(
635         BuildPosition(LocalToAbsolutePoint(node, number_position, scale)));
636   }
637 
638   return number_positions;
639 }
640 
BuildAreaNamePaths(Node * node,float scale)641 std::unique_ptr<protocol::DictionaryValue> BuildAreaNamePaths(Node* node,
642                                                               float scale) {
643   LayoutObject* layout_object = node->GetLayoutObject();
644   LayoutGrid* layout_grid = ToLayoutGrid(layout_object);
645   LocalFrameView* containing_view = node->GetDocument().View();
646   bool is_rtl = !layout_grid->StyleRef().IsLeftToRightDirection();
647 
648   std::unique_ptr<protocol::DictionaryValue> area_paths =
649       protocol::DictionaryValue::create();
650 
651   const Vector<LayoutUnit>& rows = layout_grid->RowPositions();
652   const Vector<LayoutUnit>& columns = layout_grid->ColumnPositions();
653   LayoutUnit row_gap = layout_grid->GridGap(kForRows);
654   LayoutUnit column_gap = layout_grid->GridGap(kForColumns);
655 
656   NamedGridAreaMap grid_area_map = layout_grid->StyleRef().NamedGridArea();
657   for (const auto& item : grid_area_map) {
658     const GridArea& area = item.value;
659     const String& name = item.key;
660 
661     LayoutUnit start_column = GetPositionForTrackAt(
662         layout_grid, area.columns.StartLine(), kForColumns);
663     LayoutUnit end_column =
664         GetPositionForTrackAt(layout_grid, area.columns.EndLine(), kForColumns);
665     LayoutUnit start_row =
666         GetPositionForTrackAt(layout_grid, area.rows.StartLine(), kForRows);
667     LayoutUnit end_row =
668         GetPositionForTrackAt(layout_grid, area.rows.EndLine(), kForRows);
669 
670     // Only subtract the gap size if the end line isn't the last line in the
671     // container.
672     LayoutUnit row_gap_offset =
673         area.rows.EndLine() == rows.size() - 1 ? LayoutUnit() : row_gap;
674     LayoutUnit column_gap_offset = area.columns.EndLine() == columns.size() - 1
675                                        ? LayoutUnit()
676                                        : column_gap;
677     if (is_rtl)
678       column_gap_offset *= -1;
679 
680     PhysicalOffset position(start_column, start_row);
681     PhysicalSize size(end_column - start_column - column_gap_offset,
682                       end_row - start_row - row_gap_offset);
683     PhysicalRect area_rect(position, size);
684     FloatQuad area_quad = layout_grid->LocalRectToAbsoluteQuad(area_rect);
685     FrameQuadToViewport(containing_view, area_quad);
686     PathBuilder area_builder;
687     area_builder.AppendPath(QuadToPath(area_quad), scale);
688 
689     area_paths->setValue(name, area_builder.Release());
690   }
691 
692   return area_paths;
693 }
694 
BuildGridLineNames(Node * node,GridTrackSizingDirection direction,float scale)695 std::unique_ptr<protocol::ListValue> BuildGridLineNames(
696     Node* node,
697     GridTrackSizingDirection direction,
698     float scale) {
699   LayoutObject* layout_object = node->GetLayoutObject();
700   LayoutGrid* layout_grid = ToLayoutGrid(layout_object);
701   bool is_rtl = direction == kForColumns &&
702                 !layout_grid->StyleRef().IsLeftToRightDirection();
703 
704   std::unique_ptr<protocol::ListValue> lines = protocol::ListValue::create();
705 
706   const Vector<LayoutUnit>& tracks = direction == kForColumns
707                                          ? layout_grid->ColumnPositions()
708                                          : layout_grid->RowPositions();
709   const NamedGridLinesMap& named_lines_map =
710       direction == kForColumns ? layout_grid->StyleRef().NamedGridColumnLines()
711                                : layout_grid->StyleRef().NamedGridRowLines();
712   LayoutUnit gap = layout_grid->GridGap(direction);
713   LayoutUnit alt_axis_pos = GetPositionForFirstTrack(
714       layout_grid, direction == kForRows ? kForColumns : kForRows);
715 
716   for (const auto& item : named_lines_map) {
717     const String& name = item.key;
718 
719     for (const size_t index : item.value) {
720       LayoutUnit track = GetPositionForTrackAt(layout_grid, index, direction);
721 
722       LayoutUnit gap_offset =
723           index > 0 && index < tracks.size() - 1 ? gap / 2 : LayoutUnit();
724       if (is_rtl)
725         gap_offset *= -1;
726 
727       LayoutUnit main_axis_pos = track - gap_offset;
728       PhysicalOffset line_name_pos(main_axis_pos, alt_axis_pos);
729 
730       if (direction == kForRows)
731         line_name_pos = Transpose(line_name_pos);
732 
733       std::unique_ptr<protocol::DictionaryValue> line =
734           BuildPosition(LocalToAbsolutePoint(node, line_name_pos, scale));
735 
736       line->setString("name", name);
737 
738       lines->pushValue(std::move(line));
739     }
740   }
741 
742   return lines;
743 }
744 
745 // Gets the rotation angle of the grid layout (clock-wise).
GetRotationAngle(LayoutGrid * layout_grid)746 int GetRotationAngle(LayoutGrid* layout_grid) {
747   // Local vector has 135deg bearing to the Y axis.
748   int local_vector_bearing = 135;
749   FloatPoint local_a(0, 0);
750   FloatPoint local_b(1, 1);
751   FloatPoint abs_a = layout_grid->LocalToAbsoluteFloatPoint(local_a);
752   FloatPoint abs_b = layout_grid->LocalToAbsoluteFloatPoint(local_b);
753   // Compute bearing of the absolute vector against the Y axis.
754   double theta = atan2(abs_b.X() - abs_a.X(), abs_a.Y() - abs_b.Y());
755   if (theta < 0.0)
756     theta += kTwoPiDouble;
757   int bearing = std::round(rad2deg(theta));
758   return bearing - local_vector_bearing;
759 }
760 
GetWritingMode(const LayoutGrid * layout_grid)761 String GetWritingMode(const LayoutGrid* layout_grid) {
762   // The grid overlay uses this to flip the grid lines and labels accordingly.
763   // lr, lr-tb, rl, rl-tb, tb, and tb-rl are deprecated and not handled here.
764   // sideways-lr and sideways-rl are not supported yet and not handled here.
765   WritingMode writing_mode = layout_grid->StyleRef().GetWritingMode();
766   if (writing_mode == WritingMode::kVerticalLr) {
767     return "vertical-lr";
768   }
769   if (writing_mode == WritingMode::kVerticalRl) {
770     return "vertical-rl";
771   }
772   return "horizontal-tb";
773 }
774 
775 // Gets the list of authored track size values resolving repeat() functions
776 // and skipping line names.
GetAuthoredGridTrackSizes(const CSSValue * value,size_t auto_repeat_count)777 Vector<String> GetAuthoredGridTrackSizes(const CSSValue* value,
778                                          size_t auto_repeat_count) {
779   Vector<String> result;
780 
781   if (!value)
782     return result;
783 
784   // TODO(alexrudenko): this would not handle track sizes defined using CSS
785   // variables.
786   const CSSValueList* value_list = DynamicTo<CSSValueList>(value);
787 
788   if (!value_list)
789     return result;
790 
791   for (auto list_value : *value_list) {
792     if (auto* grid_auto_repeat_value =
793             DynamicTo<cssvalue::CSSGridAutoRepeatValue>(list_value.Get())) {
794       Vector<String> repeated_track_sizes;
795       for (auto auto_repeat_value : To<CSSValueList>(*list_value)) {
796         if (!auto_repeat_value->IsGridLineNamesValue())
797           repeated_track_sizes.push_back(auto_repeat_value->CssText());
798       }
799       // There could be only one auto repeat value in a |value_list|, therefore,
800       // resetting auto_repeat_count to zero after inserting repeated values.
801       for (; auto_repeat_count; --auto_repeat_count)
802         result.AppendVector(repeated_track_sizes);
803       continue;
804     }
805 
806     if (auto* repeated_values =
807             DynamicTo<cssvalue::CSSGridIntegerRepeatValue>(list_value.Get())) {
808       size_t repetitions = repeated_values->Repetitions();
809       for (size_t i = 0; i < repetitions; ++i) {
810         for (auto repeated_value : *repeated_values) {
811           if (repeated_value->IsGridLineNamesValue())
812             continue;
813           result.push_back(repeated_value->CssText());
814         }
815       }
816       continue;
817     }
818 
819     if (list_value->IsGridLineNamesValue())
820       continue;
821 
822     result.push_back(list_value->CssText());
823   }
824 
825   return result;
826 }
827 
IsHorizontalFlex(LayoutObject * layout_flex)828 bool IsHorizontalFlex(LayoutObject* layout_flex) {
829   return layout_flex->StyleRef().IsHorizontalWritingMode() !=
830          layout_flex->StyleRef().ResolvedIsColumnFlexDirection();
831 }
832 
GetFlexLinesAndItems(LayoutBox * layout_box,bool is_horizontal)833 Vector<Vector<PhysicalRect>> GetFlexLinesAndItems(LayoutBox* layout_box,
834                                                   bool is_horizontal) {
835   Vector<Vector<PhysicalRect>> flex_lines;
836 
837   // Flex containers can't get fragmented yet, but this may change in the
838   // future.
839   for (const auto& fragment : layout_box->PhysicalFragments()) {
840     LayoutUnit progression;
841     for (const auto& child : fragment.Children()) {
842       const NGPhysicalFragment* child_fragment = child.get();
843       if (!child_fragment || child_fragment->IsOutOfFlowPositioned())
844         continue;
845 
846       PhysicalSize fragment_size = child_fragment->Size();
847       PhysicalOffset fragment_offset = child.Offset();
848 
849       const LayoutObject* object = child_fragment->GetLayoutObject();
850       const auto* box = To<LayoutBox>(object);
851       PhysicalRect item_rect =
852           PhysicalRect(fragment_offset.left - box->MarginLeft(),
853                        fragment_offset.top - box->MarginTop(),
854                        fragment_size.width + box->MarginWidth(),
855                        fragment_size.height + box->MarginHeight());
856 
857       LayoutUnit item_start = is_horizontal ? item_rect.X() : item_rect.Y();
858       LayoutUnit item_end = is_horizontal ? item_rect.X() + item_rect.Width()
859                                           : item_rect.Y() + item_rect.Height();
860 
861       if (flex_lines.IsEmpty() || item_start < progression) {
862         flex_lines.emplace_back();
863       }
864 
865       flex_lines.back().push_back(item_rect);
866 
867       progression = item_end;
868     }
869   }
870 
871   return flex_lines;
872 }
873 
BuildFlexInfo(Node * node,const InspectorFlexContainerHighlightConfig & flex_container_highlight_config,float scale)874 std::unique_ptr<protocol::DictionaryValue> BuildFlexInfo(
875     Node* node,
876     const InspectorFlexContainerHighlightConfig&
877         flex_container_highlight_config,
878     float scale) {
879   LocalFrameView* containing_view = node->GetDocument().View();
880   LayoutObject* layout_object = node->GetLayoutObject();
881   auto* layout_box = To<LayoutBox>(layout_object);
882   DCHECK(layout_object);
883   bool is_horizontal = IsHorizontalFlex(layout_object);
884 
885   std::unique_ptr<protocol::DictionaryValue> flex_info =
886       protocol::DictionaryValue::create();
887 
888   // Create the path for the flex container
889   PathBuilder container_builder;
890   PhysicalRect content_box = layout_box->PhysicalContentBoxRect();
891   FloatQuad content_quad = layout_object->LocalRectToAbsoluteQuad(content_box);
892   FrameQuadToViewport(containing_view, content_quad);
893   container_builder.AppendPath(QuadToPath(content_quad), scale);
894 
895   // Gather all flex items, sorted by flex line.
896   Vector<Vector<PhysicalRect>> flex_lines =
897       GetFlexLinesAndItems(layout_box, is_horizontal);
898 
899   // Send the offset information for each item to the frontend.
900   std::unique_ptr<protocol::ListValue> lines_info =
901       protocol::ListValue::create();
902   for (auto line : flex_lines) {
903     std::unique_ptr<protocol::ListValue> items_info =
904         protocol::ListValue::create();
905     for (auto item_rect : line) {
906       FloatQuad item_margin_quad =
907           layout_object->LocalRectToAbsoluteQuad(item_rect);
908       FrameQuadToViewport(containing_view, item_margin_quad);
909       PathBuilder item_builder;
910       item_builder.AppendPath(QuadToPath(item_margin_quad), scale);
911 
912       items_info->pushValue(item_builder.Release());
913     }
914     lines_info->pushValue(std::move(items_info));
915   }
916 
917   flex_info->setValue("containerBorder", container_builder.Release());
918   flex_info->setArray("lines", std::move(lines_info));
919   flex_info->setBoolean("isHorizontalFlow", is_horizontal);
920   flex_info->setValue(
921       "flexContainerHighlightConfig",
922       BuildFlexContainerHighlightConfigInfo(flex_container_highlight_config));
923 
924   return flex_info;
925 }
926 
BuildGridInfo(Node * node,const InspectorGridHighlightConfig & grid_highlight_config,float scale,bool isPrimary)927 std::unique_ptr<protocol::DictionaryValue> BuildGridInfo(
928     Node* node,
929     const InspectorGridHighlightConfig& grid_highlight_config,
930     float scale,
931     bool isPrimary) {
932   LocalFrameView* containing_view = node->GetDocument().View();
933   LayoutObject* layout_object = node->GetLayoutObject();
934   DCHECK(layout_object);
935   LayoutGrid* layout_grid = ToLayoutGrid(layout_object);
936 
937   std::unique_ptr<protocol::DictionaryValue> grid_info =
938       protocol::DictionaryValue::create();
939 
940   const auto& rows = layout_grid->RowPositions();
941   const auto& columns = layout_grid->ColumnPositions();
942 
943   grid_info->setInteger("rotationAngle", GetRotationAngle(layout_grid));
944 
945   // The grid track information collected in this method and sent to the overlay
946   // frontend assumes that the grid layout is in a horizontal-tb writing-mode.
947   // It is the responsibility of the frontend to flip the rendering of the grid
948   // overlay based on the following writingMode value.
949   grid_info->setString("writingMode", GetWritingMode(layout_grid));
950 
951   auto row_gap =
952       layout_grid->GridGap(kForRows) + layout_grid->GridItemOffset(kForRows);
953   auto column_gap = layout_grid->GridGap(kForColumns) +
954                     layout_grid->GridItemOffset(kForColumns);
955 
956   if (grid_highlight_config.show_track_sizes) {
957     Element* element = DynamicTo<Element>(node);
958     DCHECK(element);
959     StyleResolver& style_resolver = element->GetDocument().GetStyleResolver();
960     HeapHashMap<CSSPropertyName, Member<const CSSValue>> cascaded_values =
961         style_resolver.CascadedValuesForElement(element, kPseudoIdNone);
962     Vector<String> column_authored_values = GetAuthoredGridTrackSizes(
963         cascaded_values.at(
964             CSSPropertyName(CSSPropertyID::kGridTemplateColumns)),
965         layout_grid->AutoRepeatCountForDirection(kForColumns));
966     Vector<String> row_authored_values = GetAuthoredGridTrackSizes(
967         cascaded_values.at(CSSPropertyName(CSSPropertyID::kGridTemplateRows)),
968         layout_grid->AutoRepeatCountForDirection(kForRows));
969 
970     grid_info->setValue(
971         "columnTrackSizes",
972         BuildGridTrackSizes(node, kForColumns, scale, column_gap,
973                             &column_authored_values));
974     grid_info->setValue("rowTrackSizes",
975                         BuildGridTrackSizes(node, kForRows, scale, row_gap,
976                                             &row_authored_values));
977   }
978 
979   PathBuilder row_builder;
980   PathBuilder row_gap_builder;
981   LayoutUnit row_left = columns.front();
982   LayoutUnit row_width = columns.back() - columns.front();
983   for (size_t i = 1; i < rows.size(); ++i) {
984     // Rows
985     PhysicalOffset position(row_left, rows.at(i - 1));
986     PhysicalSize size(row_width, rows.at(i) - rows.at(i - 1));
987     if (i != rows.size() - 1)
988       size.height -= row_gap;
989     PhysicalRect row(position, size);
990     FloatQuad row_quad = layout_grid->LocalRectToAbsoluteQuad(row);
991     FrameQuadToViewport(containing_view, row_quad);
992     row_builder.AppendPath(
993         RowQuadToPath(row_quad, i == rows.size() - 1 || row_gap > 0), scale);
994     // Row Gaps
995     if (i != rows.size() - 1) {
996       PhysicalOffset gap_position(row_left, rows.at(i) - row_gap);
997       PhysicalSize gap_size(row_width, row_gap);
998       PhysicalRect gap(gap_position, gap_size);
999       FloatQuad gap_quad = layout_grid->LocalRectToAbsoluteQuad(gap);
1000       FrameQuadToViewport(containing_view, gap_quad);
1001       row_gap_builder.AppendPath(QuadToPath(gap_quad), scale);
1002     }
1003   }
1004   grid_info->setValue("rows", row_builder.Release());
1005   grid_info->setValue("rowGaps", row_gap_builder.Release());
1006 
1007   PathBuilder column_builder;
1008   PathBuilder column_gap_builder;
1009   LayoutUnit column_top = rows.front();
1010   LayoutUnit column_height = rows.back() - rows.front();
1011   bool is_ltr = layout_grid->StyleRef().IsLeftToRightDirection();
1012   for (size_t i = 1; i < columns.size(); ++i) {
1013     PhysicalSize size(columns.at(i) - columns.at(i - 1), column_height);
1014     if (i != columns.size() - 1)
1015       size.width -= column_gap;
1016     LayoutUnit line_left =
1017         GetPositionForTrackAt(layout_grid, i - 1, kForColumns);
1018     if (!is_ltr)
1019       line_left -= size.width;
1020     PhysicalOffset position(line_left, column_top);
1021     PhysicalRect column(position, size);
1022     FloatQuad column_quad = layout_grid->LocalRectToAbsoluteQuad(column);
1023     FrameQuadToViewport(containing_view, column_quad);
1024     bool draw_end_line = is_ltr ? i == columns.size() - 1 : i == 1;
1025     column_builder.AppendPath(
1026         ColumnQuadToPath(column_quad, draw_end_line || column_gap > 0), scale);
1027     // Column Gaps
1028     if (i != columns.size() - 1) {
1029       LayoutUnit gap_left = GetPositionForTrackAt(layout_grid, i, kForColumns);
1030       if (is_ltr)
1031         gap_left -= column_gap;
1032       PhysicalOffset gap_position(gap_left, column_top);
1033       PhysicalSize gap_size(column_gap, column_height);
1034       PhysicalRect gap(gap_position, gap_size);
1035       FloatQuad gap_quad = layout_grid->LocalRectToAbsoluteQuad(gap);
1036       FrameQuadToViewport(containing_view, gap_quad);
1037       column_gap_builder.AppendPath(QuadToPath(gap_quad), scale);
1038     }
1039   }
1040   grid_info->setValue("columns", column_builder.Release());
1041   grid_info->setValue("columnGaps", column_gap_builder.Release());
1042 
1043   // Positive Row and column Line positions
1044   if (grid_highlight_config.show_positive_line_numbers) {
1045     grid_info->setValue(
1046         "positiveRowLineNumberPositions",
1047         BuildGridPositiveLineNumberPositions(node, row_gap, kForRows, scale));
1048     grid_info->setValue("positiveColumnLineNumberPositions",
1049                         BuildGridPositiveLineNumberPositions(
1050                             node, column_gap, kForColumns, scale));
1051   }
1052 
1053   // Negative Row and column Line positions
1054   if (grid_highlight_config.show_negative_line_numbers) {
1055     grid_info->setValue(
1056         "negativeRowLineNumberPositions",
1057         BuildGridNegativeLineNumberPositions(node, row_gap, kForRows, scale));
1058     grid_info->setValue("negativeColumnLineNumberPositions",
1059                         BuildGridNegativeLineNumberPositions(
1060                             node, column_gap, kForColumns, scale));
1061   }
1062 
1063   // Area names
1064   if (grid_highlight_config.show_area_names) {
1065     grid_info->setValue("areaNames", BuildAreaNamePaths(node, scale));
1066   }
1067 
1068   // line names
1069   if (grid_highlight_config.show_line_names) {
1070     grid_info->setValue("rowLineNameOffsets",
1071                         BuildGridLineNames(node, kForRows, scale));
1072     grid_info->setValue("columnLineNameOffsets",
1073                         BuildGridLineNames(node, kForColumns, scale));
1074   }
1075 
1076   // Grid border
1077   PathBuilder grid_border_builder;
1078   PhysicalOffset grid_position(row_left, column_top);
1079   PhysicalSize grid_size(row_width, column_height);
1080   PhysicalRect grid_rect(grid_position, grid_size);
1081   FloatQuad grid_quad = layout_grid->LocalRectToAbsoluteQuad(grid_rect);
1082   FrameQuadToViewport(containing_view, grid_quad);
1083   grid_border_builder.AppendPath(QuadToPath(grid_quad), scale);
1084   grid_info->setValue("gridBorder", grid_border_builder.Release());
1085 
1086   grid_info->setValue("gridHighlightConfig",
1087                       BuildGridHighlightConfigInfo(grid_highlight_config));
1088 
1089   grid_info->setBoolean("isPrimaryGrid", isPrimary);
1090   return grid_info;
1091 }
1092 
BuildGridInfo(Node * node,const InspectorHighlightConfig & highlight_config,float scale,bool isPrimary)1093 std::unique_ptr<protocol::DictionaryValue> BuildGridInfo(
1094     Node* node,
1095     const InspectorHighlightConfig& highlight_config,
1096     float scale,
1097     bool isPrimary) {
1098   // Legacy support for highlight_config.css_grid
1099   if (highlight_config.css_grid != Color::kTransparent) {
1100     std::unique_ptr<InspectorGridHighlightConfig> grid_config =
1101         std::make_unique<InspectorGridHighlightConfig>();
1102     grid_config->row_line_color = highlight_config.css_grid;
1103     grid_config->column_line_color = highlight_config.css_grid;
1104     grid_config->row_line_dash = true;
1105     grid_config->column_line_dash = true;
1106     return BuildGridInfo(node, *grid_config, scale, isPrimary);
1107   }
1108 
1109   return BuildGridInfo(node, *(highlight_config.grid_highlight_config), scale,
1110                        isPrimary);
1111 }
1112 
CollectQuadsRecursive(Node * node,Vector<FloatQuad> & out_quads)1113 void CollectQuadsRecursive(Node* node, Vector<FloatQuad>& out_quads) {
1114   LayoutObject* layout_object = node->GetLayoutObject();
1115   if (!layout_object)
1116     return;
1117 
1118   // For inline elements, absoluteQuads will return a line box based on the
1119   // line-height and font metrics, which is technically incorrect as replaced
1120   // elements like images should use their intristic height and expand the
1121   // linebox  as needed. To get an appropriate quads we descend
1122   // into the children and have them add their boxes.
1123   if (layout_object->IsLayoutInline() &&
1124       LayoutTreeBuilderTraversal::FirstChild(*node)) {
1125     for (Node* child = LayoutTreeBuilderTraversal::FirstChild(*node); child;
1126          child = LayoutTreeBuilderTraversal::NextSibling(*child))
1127       CollectQuadsRecursive(child, out_quads);
1128   } else {
1129     layout_object->AbsoluteQuads(out_quads);
1130   }
1131 }
1132 
CollectQuads(Node * node,Vector<FloatQuad> & out_quads)1133 void CollectQuads(Node* node, Vector<FloatQuad>& out_quads) {
1134   CollectQuadsRecursive(node, out_quads);
1135   LocalFrameView* containing_view =
1136       node->GetLayoutObject() ? node->GetLayoutObject()->GetFrameView()
1137                               : nullptr;
1138   if (containing_view) {
1139     for (FloatQuad& quad : out_quads)
1140       FrameQuadToViewport(containing_view, quad);
1141   }
1142 }
1143 
RectForPhysicalRect(const PhysicalRect & rect)1144 std::unique_ptr<protocol::Array<double>> RectForPhysicalRect(
1145     const PhysicalRect& rect) {
1146   return std::make_unique<std::vector<double>, std::initializer_list<double>>(
1147       {rect.X(), rect.Y(), rect.Width(), rect.Height()});
1148 }
1149 
1150 // Returns |layout_object|'s bounding box in document coordinates.
RectInRootFrame(const LayoutObject * layout_object)1151 PhysicalRect RectInRootFrame(const LayoutObject* layout_object) {
1152   LocalFrameView* local_frame_view = layout_object->GetFrameView();
1153   PhysicalRect rect_in_absolute = PhysicalRect::EnclosingRect(
1154       layout_object->AbsoluteBoundingBoxFloatRect());
1155   return local_frame_view
1156              ? local_frame_view->ConvertToRootFrame(rect_in_absolute)
1157              : rect_in_absolute;
1158 }
1159 
TextFragmentRectInRootFrame(const LayoutObject * layout_object,const LayoutText::TextBoxInfo & text_box)1160 PhysicalRect TextFragmentRectInRootFrame(
1161     const LayoutObject* layout_object,
1162     const LayoutText::TextBoxInfo& text_box) {
1163   PhysicalRect absolute_coords_text_box_rect =
1164       layout_object->LocalToAbsoluteRect(
1165           layout_object->FlipForWritingMode(text_box.local_rect));
1166   LocalFrameView* local_frame_view = layout_object->GetFrameView();
1167   return local_frame_view ? local_frame_view->ConvertToRootFrame(
1168                                 absolute_coords_text_box_rect)
1169                           : absolute_coords_text_box_rect;
1170 }
1171 
1172 }  // namespace
1173 
InspectorHighlightConfig()1174 InspectorHighlightConfig::InspectorHighlightConfig()
1175     : show_info(false),
1176       show_styles(false),
1177       show_rulers(false),
1178       show_extension_lines(false),
1179       show_accessibility_info(true),
1180       color_format(ColorFormat::HEX) {}
1181 
InspectorHighlight(float scale)1182 InspectorHighlight::InspectorHighlight(float scale)
1183     : InspectorHighlightBase(scale),
1184       show_rulers_(false),
1185       show_extension_lines_(false),
1186       show_accessibility_info_(true),
1187       color_format_(ColorFormat::HEX) {}
1188 
1189 InspectorSourceOrderConfig::InspectorSourceOrderConfig() = default;
1190 
1191 LineStyle::LineStyle() = default;
1192 
InspectorGridHighlightConfig()1193 InspectorGridHighlightConfig::InspectorGridHighlightConfig()
1194     : show_grid_extension_lines(false),
1195       grid_border_dash(false),
1196       row_line_dash(false),
1197       column_line_dash(false),
1198       show_positive_line_numbers(false),
1199       show_negative_line_numbers(false),
1200       show_area_names(false),
1201       show_line_names(false),
1202       show_track_sizes(false) {}
1203 
1204 InspectorFlexContainerHighlightConfig::InspectorFlexContainerHighlightConfig() =
1205     default;
1206 
InspectorHighlightBase(float scale)1207 InspectorHighlightBase::InspectorHighlightBase(float scale)
1208     : highlight_paths_(protocol::ListValue::create()), scale_(scale) {}
1209 
InspectorHighlightBase(Node * node)1210 InspectorHighlightBase::InspectorHighlightBase(Node* node)
1211     : highlight_paths_(protocol::ListValue::create()), scale_(1.f) {
1212   DCHECK(!DisplayLockUtilities::NearestLockedExclusiveAncestor(*node));
1213   LocalFrameView* frame_view = node->GetDocument().View();
1214   if (frame_view) {
1215     scale_ = 1.f / frame_view->GetChromeClient()->WindowToViewportScalar(
1216                        &frame_view->GetFrame(), 1.f);
1217   }
1218 }
1219 
BuildNodeQuads(Node * node,FloatQuad * content,FloatQuad * padding,FloatQuad * border,FloatQuad * margin)1220 bool InspectorHighlightBase::BuildNodeQuads(Node* node,
1221                                             FloatQuad* content,
1222                                             FloatQuad* padding,
1223                                             FloatQuad* border,
1224                                             FloatQuad* margin) {
1225   LayoutObject* layout_object = node->GetLayoutObject();
1226   if (!layout_object)
1227     return false;
1228 
1229   LocalFrameView* containing_view = layout_object->GetFrameView();
1230   if (!containing_view)
1231     return false;
1232   if (!layout_object->IsBox() && !layout_object->IsLayoutInline() &&
1233       !layout_object->IsText()) {
1234     return false;
1235   }
1236 
1237   PhysicalRect content_box;
1238   PhysicalRect padding_box;
1239   PhysicalRect border_box;
1240   PhysicalRect margin_box;
1241 
1242   if (layout_object->IsText()) {
1243     auto* layout_text = To<LayoutText>(layout_object);
1244     PhysicalRect text_rect = layout_text->PhysicalVisualOverflowRect();
1245     content_box = text_rect;
1246     padding_box = text_rect;
1247     border_box = text_rect;
1248     margin_box = text_rect;
1249   } else if (layout_object->IsBox()) {
1250     auto* layout_box = To<LayoutBox>(layout_object);
1251     content_box = layout_box->PhysicalContentBoxRect();
1252 
1253     // Include scrollbars and gutters in the padding highlight.
1254     padding_box = layout_box->PhysicalPaddingBoxRect();
1255     NGPhysicalBoxStrut scrollbars = layout_box->ComputeScrollbars();
1256     padding_box.SetX(padding_box.X() - scrollbars.left);
1257     padding_box.SetY(padding_box.Y() - scrollbars.top);
1258     padding_box.SetWidth(padding_box.Width() + scrollbars.HorizontalSum());
1259     padding_box.SetHeight(padding_box.Height() + scrollbars.VerticalSum());
1260 
1261     border_box = layout_box->PhysicalBorderBoxRect();
1262 
1263     margin_box = PhysicalRect(border_box.X() - layout_box->MarginLeft(),
1264                               border_box.Y() - layout_box->MarginTop(),
1265                               border_box.Width() + layout_box->MarginWidth(),
1266                               border_box.Height() + layout_box->MarginHeight());
1267   } else {
1268     auto* layout_inline = To<LayoutInline>(layout_object);
1269 
1270     // LayoutInline's bounding box includes paddings and borders, excludes
1271     // margins.
1272     border_box = layout_inline->PhysicalLinesBoundingBox();
1273     padding_box =
1274         PhysicalRect(border_box.X() + layout_inline->BorderLeft(),
1275                      border_box.Y() + layout_inline->BorderTop(),
1276                      border_box.Width() - layout_inline->BorderLeft() -
1277                          layout_inline->BorderRight(),
1278                      border_box.Height() - layout_inline->BorderTop() -
1279                          layout_inline->BorderBottom());
1280     content_box =
1281         PhysicalRect(padding_box.X() + layout_inline->PaddingLeft(),
1282                      padding_box.Y() + layout_inline->PaddingTop(),
1283                      padding_box.Width() - layout_inline->PaddingLeft() -
1284                          layout_inline->PaddingRight(),
1285                      padding_box.Height() - layout_inline->PaddingTop() -
1286                          layout_inline->PaddingBottom());
1287     // Ignore marginTop and marginBottom for inlines.
1288     margin_box = PhysicalRect(
1289         border_box.X() - layout_inline->MarginLeft(), border_box.Y(),
1290         border_box.Width() + layout_inline->MarginWidth(), border_box.Height());
1291   }
1292 
1293   *content = layout_object->LocalRectToAbsoluteQuad(content_box);
1294   *padding = layout_object->LocalRectToAbsoluteQuad(padding_box);
1295   *border = layout_object->LocalRectToAbsoluteQuad(border_box);
1296   *margin = layout_object->LocalRectToAbsoluteQuad(margin_box);
1297 
1298   FrameQuadToViewport(containing_view, *content);
1299   FrameQuadToViewport(containing_view, *padding);
1300   FrameQuadToViewport(containing_view, *border);
1301   FrameQuadToViewport(containing_view, *margin);
1302 
1303   return true;
1304 }
1305 
AppendQuad(const FloatQuad & quad,const Color & fill_color,const Color & outline_color,const String & name)1306 void InspectorHighlightBase::AppendQuad(const FloatQuad& quad,
1307                                         const Color& fill_color,
1308                                         const Color& outline_color,
1309                                         const String& name) {
1310   Path path = QuadToPath(quad);
1311   PathBuilder builder;
1312   builder.AppendPath(path, scale_);
1313   AppendPath(builder.Release(), fill_color, outline_color, name);
1314 }
1315 
AppendPath(std::unique_ptr<protocol::ListValue> path,const Color & fill_color,const Color & outline_color,const String & name)1316 void InspectorHighlightBase::AppendPath(
1317     std::unique_ptr<protocol::ListValue> path,
1318     const Color& fill_color,
1319     const Color& outline_color,
1320     const String& name) {
1321   std::unique_ptr<protocol::DictionaryValue> object =
1322       protocol::DictionaryValue::create();
1323   object->setValue("path", std::move(path));
1324   object->setString("fillColor", fill_color.Serialized());
1325   if (outline_color != Color::kTransparent)
1326     object->setString("outlineColor", outline_color.Serialized());
1327   if (!name.IsEmpty())
1328     object->setString("name", name);
1329   highlight_paths_->pushValue(std::move(object));
1330 }
1331 
InspectorSourceOrderHighlight(Node * node,Color outline_color,int source_order_position)1332 InspectorSourceOrderHighlight::InspectorSourceOrderHighlight(
1333     Node* node,
1334     Color outline_color,
1335     int source_order_position)
1336     : InspectorHighlightBase(node),
1337       source_order_position_(source_order_position) {
1338   FloatQuad content, padding, border, margin;
1339   if (!BuildNodeQuads(node, &content, &padding, &border, &margin))
1340     return;
1341   AppendQuad(border, Color::kTransparent, outline_color, "border");
1342 }
1343 
1344 std::unique_ptr<protocol::DictionaryValue>
AsProtocolValue() const1345 InspectorSourceOrderHighlight::AsProtocolValue() const {
1346   std::unique_ptr<protocol::DictionaryValue> object =
1347       protocol::DictionaryValue::create();
1348   object->setValue("paths", highlight_paths_->clone());
1349   object->setInteger("sourceOrder", source_order_position_);
1350   return object;
1351 }
1352 
1353 // static
DefaultConfig()1354 InspectorSourceOrderConfig InspectorSourceOrderHighlight::DefaultConfig() {
1355   InspectorSourceOrderConfig config;
1356   config.parent_outline_color = Color(224, 90, 183, 1);
1357   config.child_outline_color = Color(0, 120, 212, 1);
1358   return config;
1359 }
1360 
InspectorHighlight(Node * node,const InspectorHighlightConfig & highlight_config,const InspectorHighlightContrastInfo & node_contrast,bool append_element_info,bool append_distance_info,bool is_locked_ancestor)1361 InspectorHighlight::InspectorHighlight(
1362     Node* node,
1363     const InspectorHighlightConfig& highlight_config,
1364     const InspectorHighlightContrastInfo& node_contrast,
1365     bool append_element_info,
1366     bool append_distance_info,
1367     bool is_locked_ancestor)
1368     : InspectorHighlightBase(node),
1369       show_rulers_(highlight_config.show_rulers),
1370       show_extension_lines_(highlight_config.show_extension_lines),
1371       show_accessibility_info_(highlight_config.show_accessibility_info),
1372       color_format_(highlight_config.color_format) {
1373   AppendPathsForShapeOutside(node, highlight_config);
1374   AppendNodeHighlight(node, highlight_config);
1375   auto* text_node = DynamicTo<Text>(node);
1376   auto* element = DynamicTo<Element>(node);
1377   if (append_element_info && element)
1378     element_info_ = BuildElementInfo(element);
1379   else if (append_element_info && text_node)
1380     element_info_ = BuildTextNodeInfo(text_node);
1381   if (element_info_ && highlight_config.show_styles)
1382     AppendStyleInfo(node, element_info_.get(), node_contrast);
1383 
1384   if (element_info_ && is_locked_ancestor)
1385     element_info_->setString("isLockedAncestor", "true");
1386   if (element_info_) {
1387     element_info_->setBoolean("showAccessibilityInfo",
1388                               show_accessibility_info_);
1389   }
1390   if (append_distance_info)
1391     AppendDistanceInfo(node);
1392 }
1393 
1394 InspectorHighlight::~InspectorHighlight() = default;
1395 
AppendDistanceInfo(Node * node)1396 void InspectorHighlight::AppendDistanceInfo(Node* node) {
1397   if (!InspectorHighlight::GetBoxModel(node, &model_, false))
1398     return;
1399   boxes_ = std::make_unique<protocol::Array<protocol::Array<double>>>();
1400   computed_style_ = protocol::DictionaryValue::create();
1401 
1402   node->GetDocument().EnsurePaintLocationDataValidForNode(
1403       node, DocumentUpdateReason::kInspector);
1404   LayoutObject* layout_object = node->GetLayoutObject();
1405   if (!layout_object)
1406     return;
1407 
1408   CSSComputedStyleDeclaration* style =
1409       MakeGarbageCollected<CSSComputedStyleDeclaration>(node, true);
1410   for (size_t i = 0; i < style->length(); ++i) {
1411     AtomicString name(style->item(i));
1412     const CSSValue* value = style->GetPropertyCSSValue(
1413         cssPropertyID(node->GetExecutionContext(), name));
1414     if (!value)
1415       continue;
1416     if (value->IsColorValue()) {
1417       Color color = static_cast<const cssvalue::CSSColorValue*>(value)->Value();
1418       computed_style_->setString(name, ToHEXA(color));
1419     } else {
1420       computed_style_->setString(name, value->CssText());
1421     }
1422   }
1423 
1424   VisitAndCollectDistanceInfo(&(node->GetDocument()));
1425   PhysicalRect document_rect(
1426       node->GetDocument().GetLayoutView()->DocumentRect());
1427   LocalFrameView* local_frame_view = node->GetDocument().View();
1428   boxes_->emplace_back(
1429       RectForPhysicalRect(local_frame_view->ConvertToRootFrame(document_rect)));
1430 }
1431 
VisitAndCollectDistanceInfo(Node * node)1432 void InspectorHighlight::VisitAndCollectDistanceInfo(Node* node) {
1433   LayoutObject* layout_object = node->GetLayoutObject();
1434   if (layout_object)
1435     AddLayoutBoxToDistanceInfo(layout_object);
1436 
1437   if (auto* element = DynamicTo<Element>(node)) {
1438     if (element->GetPseudoId()) {
1439       if (layout_object)
1440         VisitAndCollectDistanceInfo(element->GetPseudoId(), layout_object);
1441     } else {
1442       for (PseudoId pseudo_id :
1443            {kPseudoIdFirstLetter, kPseudoIdBefore, kPseudoIdAfter}) {
1444         if (Node* pseudo_node = element->GetPseudoElement(pseudo_id))
1445           VisitAndCollectDistanceInfo(pseudo_node);
1446       }
1447     }
1448   }
1449 
1450   if (!node->IsContainerNode())
1451     return;
1452   for (Node* child = blink::dom_traversal_utils::FirstChild(*node, false);
1453        child; child = blink::dom_traversal_utils::NextSibling(*child, false)) {
1454     VisitAndCollectDistanceInfo(child);
1455   }
1456 }
1457 
VisitAndCollectDistanceInfo(PseudoId pseudo_id,LayoutObject * layout_object)1458 void InspectorHighlight::VisitAndCollectDistanceInfo(
1459     PseudoId pseudo_id,
1460     LayoutObject* layout_object) {
1461   protocol::DOM::PseudoType pseudo_type;
1462   if (pseudo_id == kPseudoIdNone)
1463     return;
1464   for (LayoutObject* child = layout_object->SlowFirstChild(); child;
1465        child = child->NextSibling()) {
1466     if (child->IsAnonymous())
1467       AddLayoutBoxToDistanceInfo(child);
1468   }
1469 }
1470 
AddLayoutBoxToDistanceInfo(LayoutObject * layout_object)1471 void InspectorHighlight::AddLayoutBoxToDistanceInfo(
1472     LayoutObject* layout_object) {
1473   if (layout_object->IsText()) {
1474     auto* layout_text = To<LayoutText>(layout_object);
1475     for (const auto& text_box : layout_text->GetTextBoxInfo()) {
1476       PhysicalRect text_rect(
1477           TextFragmentRectInRootFrame(layout_object, text_box));
1478       boxes_->emplace_back(RectForPhysicalRect(text_rect));
1479     }
1480   } else {
1481     PhysicalRect rect(RectInRootFrame(layout_object));
1482     boxes_->emplace_back(RectForPhysicalRect(rect));
1483   }
1484 }
1485 
AppendEventTargetQuads(Node * event_target_node,const InspectorHighlightConfig & highlight_config)1486 void InspectorHighlight::AppendEventTargetQuads(
1487     Node* event_target_node,
1488     const InspectorHighlightConfig& highlight_config) {
1489   if (event_target_node->GetLayoutObject()) {
1490     FloatQuad border, unused;
1491     if (BuildNodeQuads(event_target_node, &unused, &unused, &border, &unused))
1492       AppendQuad(border, highlight_config.event_target);
1493   }
1494 }
1495 
AppendPathsForShapeOutside(Node * node,const InspectorHighlightConfig & config)1496 void InspectorHighlight::AppendPathsForShapeOutside(
1497     Node* node,
1498     const InspectorHighlightConfig& config) {
1499   Shape::DisplayPaths paths;
1500   FloatQuad bounds_quad;
1501 
1502   const ShapeOutsideInfo* shape_outside_info =
1503       ShapeOutsideInfoForNode(node, &paths, &bounds_quad);
1504   if (!shape_outside_info)
1505     return;
1506 
1507   if (!paths.shape.length()) {
1508     AppendQuad(bounds_quad, config.shape);
1509     return;
1510   }
1511 
1512   AppendPath(ShapePathBuilder::BuildPath(
1513                  *node->GetDocument().View(), *node->GetLayoutObject(),
1514                  *shape_outside_info, paths.shape, scale_),
1515              config.shape, Color::kTransparent);
1516   if (paths.margin_shape.length())
1517     AppendPath(ShapePathBuilder::BuildPath(
1518                    *node->GetDocument().View(), *node->GetLayoutObject(),
1519                    *shape_outside_info, paths.margin_shape, scale_),
1520                config.shape_margin, Color::kTransparent);
1521 }
1522 
AppendNodeHighlight(Node * node,const InspectorHighlightConfig & highlight_config)1523 void InspectorHighlight::AppendNodeHighlight(
1524     Node* node,
1525     const InspectorHighlightConfig& highlight_config) {
1526   LayoutObject* layout_object = node->GetLayoutObject();
1527   if (!layout_object)
1528     return;
1529 
1530   Vector<FloatQuad> svg_quads;
1531   if (BuildSVGQuads(node, svg_quads)) {
1532     for (wtf_size_t i = 0; i < svg_quads.size(); ++i) {
1533       AppendQuad(svg_quads[i], highlight_config.content,
1534                  highlight_config.content_outline);
1535     }
1536     return;
1537   }
1538 
1539   FloatQuad content, padding, border, margin;
1540   if (!BuildNodeQuads(node, &content, &padding, &border, &margin))
1541     return;
1542   AppendQuad(content, highlight_config.content,
1543              highlight_config.content_outline, "content");
1544   AppendQuad(padding, highlight_config.padding, Color::kTransparent, "padding");
1545   AppendQuad(border, highlight_config.border, Color::kTransparent, "border");
1546   AppendQuad(margin, highlight_config.margin, Color::kTransparent, "margin");
1547 
1548   // Don't append node's grid / flex info if it's locked since those values may
1549   // not be generated yet.
1550   if (auto* context = layout_object->GetDisplayLockContext()) {
1551     if (context->IsLocked())
1552       return;
1553   }
1554 
1555   if (highlight_config.css_grid != Color::kTransparent ||
1556       highlight_config.grid_highlight_config) {
1557     grid_info_ = protocol::ListValue::create();
1558     if (layout_object->IsLayoutGrid()) {
1559       grid_info_->pushValue(
1560           BuildGridInfo(node, highlight_config, scale_, true));
1561     }
1562   }
1563 
1564   if (highlight_config.flex_container_highlight_config) {
1565     flex_info_ = protocol::ListValue::create();
1566     // Some objects are flexible boxes even though display:flex is not set, we
1567     // need to avoid those.
1568     if (layout_object->StyleRef().IsDisplayFlexibleBox() &&
1569         layout_object->IsFlexibleBoxIncludingNG()) {
1570       flex_info_->pushValue(BuildFlexInfo(
1571           node, *(highlight_config.flex_container_highlight_config), scale_));
1572     }
1573   }
1574 }
1575 
AsProtocolValue() const1576 std::unique_ptr<protocol::DictionaryValue> InspectorHighlight::AsProtocolValue()
1577     const {
1578   std::unique_ptr<protocol::DictionaryValue> object =
1579       protocol::DictionaryValue::create();
1580   object->setValue("paths", highlight_paths_->clone());
1581   object->setBoolean("showRulers", show_rulers_);
1582   object->setBoolean("showExtensionLines", show_extension_lines_);
1583   object->setBoolean("showAccessibilityInfo", show_accessibility_info_);
1584   switch (color_format_) {
1585     case ColorFormat::RGB:
1586       object->setString("colorFormat", "rgb");
1587       break;
1588     case ColorFormat::HSL:
1589       object->setString("colorFormat", "hsl");
1590       break;
1591     case ColorFormat::HEX:
1592       object->setString("colorFormat", "hex");
1593       break;
1594   }
1595 
1596   if (model_) {
1597     std::unique_ptr<protocol::DictionaryValue> distance_info =
1598         protocol::DictionaryValue::create();
1599     distance_info->setArray(
1600         "boxes",
1601         protocol::ValueConversions<std::vector<
1602             std::unique_ptr<std::vector<double>>>>::toValue(boxes_.get()));
1603     distance_info->setArray(
1604         "content", protocol::ValueConversions<std::vector<double>>::toValue(
1605                        model_->getContent()));
1606     distance_info->setArray(
1607         "padding", protocol::ValueConversions<std::vector<double>>::toValue(
1608                        model_->getPadding()));
1609     distance_info->setArray(
1610         "border", protocol::ValueConversions<std::vector<double>>::toValue(
1611                       model_->getBorder()));
1612     distance_info->setValue("style", computed_style_->clone());
1613     object->setValue("distanceInfo", std::move(distance_info));
1614   }
1615   if (element_info_)
1616     object->setValue("elementInfo", element_info_->clone());
1617   if (grid_info_ && grid_info_->size() > 0)
1618     object->setValue("gridInfo", grid_info_->clone());
1619   if (flex_info_ && flex_info_->size() > 0)
1620     object->setValue("flexInfo", flex_info_->clone());
1621   return object;
1622 }
1623 
1624 // static
GetBoxModel(Node * node,std::unique_ptr<protocol::DOM::BoxModel> * model,bool use_absolute_zoom)1625 bool InspectorHighlight::GetBoxModel(
1626     Node* node,
1627     std::unique_ptr<protocol::DOM::BoxModel>* model,
1628     bool use_absolute_zoom) {
1629   node->GetDocument().EnsurePaintLocationDataValidForNode(
1630       node, DocumentUpdateReason::kInspector);
1631   LayoutObject* layout_object = node->GetLayoutObject();
1632   LocalFrameView* view = node->GetDocument().View();
1633   if (!layout_object || !view)
1634     return false;
1635 
1636   FloatQuad content, padding, border, margin;
1637   Vector<FloatQuad> svg_quads;
1638   if (BuildSVGQuads(node, svg_quads)) {
1639     if (!svg_quads.size())
1640       return false;
1641     content = svg_quads[0];
1642     padding = svg_quads[0];
1643     border = svg_quads[0];
1644     margin = svg_quads[0];
1645   } else if (!BuildNodeQuads(node, &content, &padding, &border, &margin)) {
1646     return false;
1647   }
1648 
1649   if (use_absolute_zoom) {
1650     AdjustForAbsoluteZoom::AdjustFloatQuad(content, *layout_object);
1651     AdjustForAbsoluteZoom::AdjustFloatQuad(padding, *layout_object);
1652     AdjustForAbsoluteZoom::AdjustFloatQuad(border, *layout_object);
1653     AdjustForAbsoluteZoom::AdjustFloatQuad(margin, *layout_object);
1654   }
1655 
1656   float scale = 1 / view->GetPage()->GetVisualViewport().Scale();
1657   content.Scale(scale, scale);
1658   padding.Scale(scale, scale);
1659   border.Scale(scale, scale);
1660   margin.Scale(scale, scale);
1661 
1662   IntRect bounding_box =
1663       view->ConvertToRootFrame(layout_object->AbsoluteBoundingBoxRect());
1664   auto* model_object = DynamicTo<LayoutBoxModelObject>(layout_object);
1665 
1666   *model =
1667       protocol::DOM::BoxModel::create()
1668           .setContent(BuildArrayForQuad(content))
1669           .setPadding(BuildArrayForQuad(padding))
1670           .setBorder(BuildArrayForQuad(border))
1671           .setMargin(BuildArrayForQuad(margin))
1672           .setWidth(model_object ? AdjustForAbsoluteZoom::AdjustInt(
1673                                        model_object->PixelSnappedOffsetWidth(
1674                                            model_object->OffsetParent()),
1675                                        model_object)
1676                                  : bounding_box.Width())
1677           .setHeight(model_object ? AdjustForAbsoluteZoom::AdjustInt(
1678                                         model_object->PixelSnappedOffsetHeight(
1679                                             model_object->OffsetParent()),
1680                                         model_object)
1681                                   : bounding_box.Height())
1682           .build();
1683 
1684   Shape::DisplayPaths paths;
1685   FloatQuad bounds_quad;
1686   protocol::ErrorSupport errors;
1687   if (const ShapeOutsideInfo* shape_outside_info =
1688           ShapeOutsideInfoForNode(node, &paths, &bounds_quad)) {
1689     auto shape = ShapePathBuilder::BuildPath(
1690         *view, *layout_object, *shape_outside_info, paths.shape, 1.f);
1691     auto margin_shape = ShapePathBuilder::BuildPath(
1692         *view, *layout_object, *shape_outside_info, paths.margin_shape, 1.f);
1693     (*model)->setShapeOutside(
1694         protocol::DOM::ShapeOutsideInfo::create()
1695             .setBounds(BuildArrayForQuad(bounds_quad))
1696             .setShape(protocol::ValueConversions<
1697                       protocol::Array<protocol::Value>>::fromValue(shape.get(),
1698                                                                    &errors))
1699             .setMarginShape(
1700                 protocol::ValueConversions<protocol::Array<protocol::Value>>::
1701                     fromValue(margin_shape.get(), &errors))
1702             .build());
1703   }
1704 
1705   return true;
1706 }
1707 
1708 // static
BuildSVGQuads(Node * node,Vector<FloatQuad> & quads)1709 bool InspectorHighlight::BuildSVGQuads(Node* node, Vector<FloatQuad>& quads) {
1710   LayoutObject* layout_object = node->GetLayoutObject();
1711   if (!layout_object)
1712     return false;
1713   if (!layout_object->GetNode() || !layout_object->GetNode()->IsSVGElement() ||
1714       layout_object->IsSVGRoot())
1715     return false;
1716   CollectQuads(node, quads);
1717   return true;
1718 }
1719 
1720 // static
GetContentQuads(Node * node,std::unique_ptr<protocol::Array<protocol::Array<double>>> * result)1721 bool InspectorHighlight::GetContentQuads(
1722     Node* node,
1723     std::unique_ptr<protocol::Array<protocol::Array<double>>>* result) {
1724   LayoutObject* layout_object = node->GetLayoutObject();
1725   LocalFrameView* view = node->GetDocument().View();
1726   if (!layout_object || !view)
1727     return false;
1728   Vector<FloatQuad> quads;
1729   CollectQuads(node, quads);
1730   float scale = 1 / view->GetPage()->GetVisualViewport().Scale();
1731   for (FloatQuad& quad : quads) {
1732     AdjustForAbsoluteZoom::AdjustFloatQuad(quad, *layout_object);
1733     quad.Scale(scale, scale);
1734   }
1735 
1736   result->reset(new protocol::Array<protocol::Array<double>>());
1737   for (FloatQuad& quad : quads)
1738     (*result)->emplace_back(BuildArrayForQuad(quad));
1739   return true;
1740 }
1741 
InspectorGridHighlight(Node * node,const InspectorGridHighlightConfig & config)1742 std::unique_ptr<protocol::DictionaryValue> InspectorGridHighlight(
1743     Node* node,
1744     const InspectorGridHighlightConfig& config) {
1745   if (DisplayLockUtilities::NearestLockedExclusiveAncestor(*node)) {
1746     // Skip if node is part of display locked tree.
1747     return nullptr;
1748   }
1749 
1750   LocalFrameView* frame_view = node->GetDocument().View();
1751   if (!frame_view)
1752     return nullptr;
1753 
1754   float scale = 1.f / frame_view->GetChromeClient()->WindowToViewportScalar(
1755                           &frame_view->GetFrame(), 1.f);
1756   LayoutObject* layout_object = node->GetLayoutObject();
1757   if (!layout_object || !layout_object->IsLayoutGrid())
1758     return nullptr;
1759 
1760   std::unique_ptr<protocol::DictionaryValue> grid_info =
1761       BuildGridInfo(node, config, scale, true);
1762   return grid_info;
1763 }
1764 
1765 // static
DefaultConfig()1766 InspectorHighlightConfig InspectorHighlight::DefaultConfig() {
1767   InspectorHighlightConfig config;
1768   config.content = Color(255, 0, 0, 0);
1769   config.content_outline = Color(128, 0, 0, 0);
1770   config.padding = Color(0, 255, 0, 0);
1771   config.border = Color(0, 0, 255, 0);
1772   config.margin = Color(255, 255, 255, 0);
1773   config.event_target = Color(128, 128, 128, 0);
1774   config.shape = Color(0, 0, 0, 0);
1775   config.shape_margin = Color(128, 128, 128, 0);
1776   config.show_info = true;
1777   config.show_styles = false;
1778   config.show_rulers = true;
1779   config.show_extension_lines = true;
1780   config.css_grid = Color::kTransparent;
1781   config.color_format = ColorFormat::HEX;
1782   config.grid_highlight_config = std::make_unique<InspectorGridHighlightConfig>(
1783       InspectorHighlight::DefaultGridConfig());
1784   config.flex_container_highlight_config =
1785       std::make_unique<InspectorFlexContainerHighlightConfig>(
1786           InspectorHighlight::DefaultFlexContainerConfig());
1787   return config;
1788 }
1789 
1790 // static
DefaultGridConfig()1791 InspectorGridHighlightConfig InspectorHighlight::DefaultGridConfig() {
1792   InspectorGridHighlightConfig config;
1793   config.grid_color = Color(255, 0, 0, 0);
1794   config.row_line_color = Color(128, 0, 0, 0);
1795   config.column_line_color = Color(128, 0, 0, 0);
1796   config.row_gap_color = Color(0, 255, 0, 0);
1797   config.column_gap_color = Color(0, 0, 255, 0);
1798   config.row_hatch_color = Color(255, 255, 255, 0);
1799   config.column_hatch_color = Color(128, 128, 128, 0);
1800   config.area_border_color = Color(255, 0, 0, 0);
1801   config.grid_background_color = Color(255, 0, 0, 0);
1802   config.show_grid_extension_lines = true;
1803   config.show_positive_line_numbers = true;
1804   config.show_negative_line_numbers = true;
1805   config.show_area_names = true;
1806   config.show_line_names = true;
1807   config.grid_border_dash = false;
1808   config.row_line_dash = true;
1809   config.column_line_dash = true;
1810   config.show_track_sizes = true;
1811   return config;
1812 }
1813 
1814 // static
1815 InspectorFlexContainerHighlightConfig
DefaultFlexContainerConfig()1816 InspectorHighlight::DefaultFlexContainerConfig() {
1817   InspectorFlexContainerHighlightConfig config;
1818   config.container_border =
1819       std::make_unique<LineStyle>(InspectorHighlight::DefaultLineStyle());
1820   config.line_separator =
1821       std::make_unique<LineStyle>(InspectorHighlight::DefaultLineStyle());
1822   config.item_separator =
1823       std::make_unique<LineStyle>(InspectorHighlight::DefaultLineStyle());
1824   return config;
1825 }
1826 
1827 // static
DefaultLineStyle()1828 LineStyle InspectorHighlight::DefaultLineStyle() {
1829   LineStyle style;
1830   style.color = Color(255, 0, 0, 0);
1831   style.pattern = "solid";
1832   return style;
1833 }
1834 
1835 }  // namespace blink
1836