1 // Copyright 2019 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/inspect_tools.h"
6 
7 #include "third_party/blink/public/common/input/web_gesture_event.h"
8 #include "third_party/blink/public/common/input/web_input_event.h"
9 #include "third_party/blink/public/common/input/web_keyboard_event.h"
10 #include "third_party/blink/public/common/input/web_pointer_event.h"
11 #include "third_party/blink/public/platform/web_input_event_result.h"
12 #include "third_party/blink/public/resources/grit/inspector_overlay_resources_map.h"
13 #include "third_party/blink/renderer/core/css/css_color_value.h"
14 #include "third_party/blink/renderer/core/css/css_computed_style_declaration.h"
15 #include "third_party/blink/renderer/core/display_lock/display_lock_utilities.h"
16 #include "third_party/blink/renderer/core/dom/element.h"
17 #include "third_party/blink/renderer/core/dom/node_computed_style.h"
18 #include "third_party/blink/renderer/core/dom/shadow_root.h"
19 #include "third_party/blink/renderer/core/dom/static_node_list.h"
20 #include "third_party/blink/renderer/core/frame/local_frame.h"
21 #include "third_party/blink/renderer/core/frame/root_frame_viewport.h"
22 #include "third_party/blink/renderer/core/frame/visual_viewport.h"
23 #include "third_party/blink/renderer/core/html/html_frame_owner_element.h"
24 #include "third_party/blink/renderer/core/inspector/inspector_css_agent.h"
25 #include "third_party/blink/renderer/core/inspector/inspector_dom_agent.h"
26 #include "third_party/blink/renderer/core/layout/hit_test_location.h"
27 #include "third_party/blink/renderer/core/layout/layout_view.h"
28 #include "third_party/blink/renderer/core/page/chrome_client.h"
29 #include "third_party/blink/renderer/core/page/page.h"
30 #include "third_party/blink/renderer/platform/cursors.h"
31 #include "third_party/blink/renderer/platform/keyboard_codes.h"
32 #include "third_party/inspector_protocol/crdtp/json.h"
33 
34 namespace blink {
35 
36 namespace {
37 
FetchContrast(Node * node)38 InspectorHighlightContrastInfo FetchContrast(Node* node) {
39   InspectorHighlightContrastInfo result;
40   auto* element = DynamicTo<Element>(node);
41   if (!element)
42     return result;
43 
44   Vector<Color> bgcolors;
45   String font_size;
46   String font_weight;
47   InspectorCSSAgent::GetBackgroundColors(element, &bgcolors, &font_size,
48                                          &font_weight);
49   if (bgcolors.size() == 1) {
50     result.font_size = font_size;
51     result.font_weight = font_weight;
52     result.background_color = bgcolors[0];
53   }
54   return result;
55 }
56 
HoveredNodeForPoint(LocalFrame * frame,const IntPoint & point_in_root_frame,bool ignore_pointer_events_none)57 Node* HoveredNodeForPoint(LocalFrame* frame,
58                           const IntPoint& point_in_root_frame,
59                           bool ignore_pointer_events_none) {
60   HitTestRequest::HitTestRequestType hit_type =
61       HitTestRequest::kMove | HitTestRequest::kReadOnly |
62       HitTestRequest::kAllowChildFrameContent;
63   if (ignore_pointer_events_none)
64     hit_type |= HitTestRequest::kIgnorePointerEventsNone;
65   HitTestRequest request(hit_type);
66   HitTestLocation location(
67       frame->View()->ConvertFromRootFrame(point_in_root_frame));
68   HitTestResult result(request, location);
69   frame->ContentLayoutObject()->HitTest(location, result);
70   Node* node = result.InnerPossiblyPseudoNode();
71   while (node && node->getNodeType() == Node::kTextNode)
72     node = node->parentNode();
73   return node;
74 }
75 
HoveredNodeForEvent(LocalFrame * frame,const WebGestureEvent & event,bool ignore_pointer_events_none)76 Node* HoveredNodeForEvent(LocalFrame* frame,
77                           const WebGestureEvent& event,
78                           bool ignore_pointer_events_none) {
79   return HoveredNodeForPoint(
80       frame, RoundedIntPoint(FloatPoint(event.PositionInRootFrame())),
81       ignore_pointer_events_none);
82 }
83 
HoveredNodeForEvent(LocalFrame * frame,const WebMouseEvent & event,bool ignore_pointer_events_none)84 Node* HoveredNodeForEvent(LocalFrame* frame,
85                           const WebMouseEvent& event,
86                           bool ignore_pointer_events_none) {
87   return HoveredNodeForPoint(
88       frame, RoundedIntPoint(FloatPoint(event.PositionInRootFrame())),
89       ignore_pointer_events_none);
90 }
91 
HoveredNodeForEvent(LocalFrame * frame,const WebPointerEvent & event,bool ignore_pointer_events_none)92 Node* HoveredNodeForEvent(LocalFrame* frame,
93                           const WebPointerEvent& event,
94                           bool ignore_pointer_events_none) {
95   WebPointerEvent transformed_point = event.WebPointerEventInRootFrame();
96   return HoveredNodeForPoint(
97       frame, RoundedIntPoint(FloatPoint(transformed_point.PositionInWidget())),
98       ignore_pointer_events_none);
99 }
100 
101 }  // namespace
102 
103 // SearchingForNodeTool --------------------------------------------------------
104 
SearchingForNodeTool(InspectorOverlayAgent * overlay,OverlayFrontend * frontend,InspectorDOMAgent * dom_agent,bool ua_shadow,const std::vector<uint8_t> & config)105 SearchingForNodeTool::SearchingForNodeTool(InspectorOverlayAgent* overlay,
106                                            OverlayFrontend* frontend,
107                                            InspectorDOMAgent* dom_agent,
108                                            bool ua_shadow,
109                                            const std::vector<uint8_t>& config)
110     : InspectTool(overlay, frontend),
111       dom_agent_(dom_agent),
112       ua_shadow_(ua_shadow) {
113   auto parsed_config = protocol::Overlay::HighlightConfig::FromBinary(
114       config.data(), config.size());
115   if (parsed_config) {
116     highlight_config_ =
117         InspectorOverlayAgent::ToHighlightConfig(parsed_config.get());
118   }
119 }
120 
GetOverlayName()121 String SearchingForNodeTool::GetOverlayName() {
122   return OverlayNames::OVERLAY_HIGHLIGHT;
123 }
124 
Trace(Visitor * visitor) const125 void SearchingForNodeTool::Trace(Visitor* visitor) const {
126   InspectTool::Trace(visitor);
127   visitor->Trace(dom_agent_);
128   visitor->Trace(hovered_node_);
129   visitor->Trace(event_target_node_);
130 }
131 
Draw(float scale)132 void SearchingForNodeTool::Draw(float scale) {
133   if (!hovered_node_)
134     return;
135 
136   Node* node = hovered_node_.Get();
137 
138   bool append_element_info = (node->IsElementNode() || node->IsTextNode()) &&
139                              !omit_tooltip_ && highlight_config_->show_info &&
140                              node->GetLayoutObject() &&
141                              node->GetDocument().GetFrame();
142   overlay_->EnsureAXContext(node);
143   InspectorHighlight highlight(node, *highlight_config_, contrast_info_,
144                                append_element_info, false, is_locked_ancestor_);
145   if (event_target_node_) {
146     highlight.AppendEventTargetQuads(event_target_node_.Get(),
147                                      *highlight_config_);
148   }
149   overlay_->EvaluateInOverlay("drawHighlight", highlight.AsProtocolValue());
150 }
151 
SupportsPersistentOverlays()152 bool SearchingForNodeTool::SupportsPersistentOverlays() {
153   return true;
154 }
155 
HandleInputEvent(LocalFrameView * frame_view,const WebInputEvent & input_event,bool * swallow_next_mouse_up)156 bool SearchingForNodeTool::HandleInputEvent(LocalFrameView* frame_view,
157                                             const WebInputEvent& input_event,
158                                             bool* swallow_next_mouse_up) {
159   if (input_event.GetType() == WebInputEvent::Type::kGestureScrollBegin ||
160       input_event.GetType() == WebInputEvent::Type::kGestureScrollUpdate) {
161     hovered_node_.Clear();
162     event_target_node_.Clear();
163     overlay_->ScheduleUpdate();
164     return false;
165   }
166   return InspectTool::HandleInputEvent(frame_view, input_event,
167                                        swallow_next_mouse_up);
168 }
169 
HandleMouseMove(const WebMouseEvent & event)170 bool SearchingForNodeTool::HandleMouseMove(const WebMouseEvent& event) {
171   LocalFrame* frame = overlay_->GetFrame();
172   if (!frame || !frame->View() || !frame->ContentLayoutObject())
173     return false;
174   Node* node = HoveredNodeForEvent(
175       frame, event, event.GetModifiers() & WebInputEvent::kShiftKey);
176 
177   // Do not highlight within user agent shadow root unless requested.
178   if (!ua_shadow_) {
179     ShadowRoot* shadow_root = InspectorDOMAgent::UserAgentShadowRoot(node);
180     if (shadow_root)
181       node = &shadow_root->host();
182   }
183 
184   // Shadow roots don't have boxes - use host element instead.
185   if (node && node->IsShadowRoot())
186     node = node->ParentOrShadowHostNode();
187 
188   if (!node)
189     return true;
190 
191   // If |node| is in a display locked subtree, highlight the highest locked
192   // element instead.
193   if (Node* locked_ancestor =
194           DisplayLockUtilities::HighestLockedExclusiveAncestor(*node)) {
195     node = locked_ancestor;
196     is_locked_ancestor_ = true;
197   } else {
198     is_locked_ancestor_ = false;
199   }
200 
201   if (auto* frame_owner = DynamicTo<HTMLFrameOwnerElement>(node)) {
202     if (!IsA<LocalFrame>(frame_owner->ContentFrame())) {
203       // Do not consume event so that remote frame can handle it.
204       overlay_->hideHighlight();
205       hovered_node_.Clear();
206       return false;
207     }
208   }
209 
210   // Store values for the highlight.
211   hovered_node_ = node;
212   event_target_node_ = (event.GetModifiers() & WebInputEvent::kShiftKey)
213                            ? HoveredNodeForEvent(frame, event, false)
214                            : nullptr;
215   if (event_target_node_ == hovered_node_)
216     event_target_node_ = nullptr;
217   omit_tooltip_ = event.GetModifiers() &
218                   (WebInputEvent::kControlKey | WebInputEvent::kMetaKey);
219 
220   contrast_info_ = FetchContrast(node);
221   NodeHighlightRequested(node);
222   return true;
223 }
224 
HandleMouseDown(const WebMouseEvent & event,bool * swallow_next_mouse_up)225 bool SearchingForNodeTool::HandleMouseDown(const WebMouseEvent& event,
226                                            bool* swallow_next_mouse_up) {
227   if (hovered_node_) {
228     *swallow_next_mouse_up = true;
229     overlay_->Inspect(hovered_node_.Get());
230     hovered_node_.Clear();
231     return true;
232   }
233   return false;
234 }
235 
HandleGestureTapEvent(const WebGestureEvent & event)236 bool SearchingForNodeTool::HandleGestureTapEvent(const WebGestureEvent& event) {
237   Node* node = HoveredNodeForEvent(overlay_->GetFrame(), event, false);
238   if (node) {
239     overlay_->Inspect(node);
240     return true;
241   }
242   return false;
243 }
244 
HandlePointerEvent(const WebPointerEvent & event)245 bool SearchingForNodeTool::HandlePointerEvent(const WebPointerEvent& event) {
246   // Trigger Inspect only when a pointer device is pressed down.
247   if (event.GetType() != WebInputEvent::Type::kPointerDown)
248     return false;
249   Node* node = HoveredNodeForEvent(overlay_->GetFrame(), event, false);
250   if (node) {
251     overlay_->Inspect(node);
252     return true;
253   }
254   return false;
255 }
256 
NodeHighlightRequested(Node * node)257 void SearchingForNodeTool::NodeHighlightRequested(Node* node) {
258   while (node && !node->IsElementNode() && !node->IsDocumentNode() &&
259          !node->IsDocumentFragment())
260     node = node->ParentOrShadowHostNode();
261 
262   if (!node)
263     return;
264 
265   int node_id = dom_agent_->PushNodePathToFrontend(node);
266   if (node_id)
267     frontend_->nodeHighlightRequested(node_id);
268 }
269 
270 // QuadHighlightTool -----------------------------------------------------------
271 
QuadHighlightTool(InspectorOverlayAgent * overlay,OverlayFrontend * frontend,std::unique_ptr<FloatQuad> quad,Color color,Color outline_color)272 QuadHighlightTool::QuadHighlightTool(InspectorOverlayAgent* overlay,
273                                      OverlayFrontend* frontend,
274                                      std::unique_ptr<FloatQuad> quad,
275                                      Color color,
276                                      Color outline_color)
277     : InspectTool(overlay, frontend),
278       quad_(std::move(quad)),
279       color_(color),
280       outline_color_(outline_color) {}
281 
GetOverlayName()282 String QuadHighlightTool::GetOverlayName() {
283   return OverlayNames::OVERLAY_HIGHLIGHT;
284 }
285 
ForwardEventsToOverlay()286 bool QuadHighlightTool::ForwardEventsToOverlay() {
287   return false;
288 }
289 
HideOnHideHighlight()290 bool QuadHighlightTool::HideOnHideHighlight() {
291   return true;
292 }
293 
Draw(float scale)294 void QuadHighlightTool::Draw(float scale) {
295   InspectorHighlight highlight(scale);
296   highlight.AppendQuad(*quad_, color_, outline_color_);
297   overlay_->EvaluateInOverlay("drawHighlight", highlight.AsProtocolValue());
298 }
299 
300 // NodeHighlightTool -----------------------------------------------------------
301 
NodeHighlightTool(InspectorOverlayAgent * overlay,OverlayFrontend * frontend,Member<Node> node,String selector_list,std::unique_ptr<InspectorHighlightConfig> highlight_config)302 NodeHighlightTool::NodeHighlightTool(
303     InspectorOverlayAgent* overlay,
304     OverlayFrontend* frontend,
305     Member<Node> node,
306     String selector_list,
307     std::unique_ptr<InspectorHighlightConfig> highlight_config)
308     : InspectTool(overlay, frontend),
309       selector_list_(selector_list),
310       highlight_config_(std::move(highlight_config)) {
311   if (Node* locked_ancestor =
312           DisplayLockUtilities::HighestLockedExclusiveAncestor(*node)) {
313     is_locked_ancestor_ = true;
314     node_ = locked_ancestor;
315   } else {
316     node_ = node;
317   }
318   contrast_info_ = FetchContrast(node_);
319 }
320 
GetOverlayName()321 String NodeHighlightTool::GetOverlayName() {
322   return OverlayNames::OVERLAY_HIGHLIGHT;
323 }
324 
ForwardEventsToOverlay()325 bool NodeHighlightTool::ForwardEventsToOverlay() {
326   return false;
327 }
328 
SupportsPersistentOverlays()329 bool NodeHighlightTool::SupportsPersistentOverlays() {
330   return true;
331 }
332 
HideOnHideHighlight()333 bool NodeHighlightTool::HideOnHideHighlight() {
334   return true;
335 }
336 
HideOnMouseMove()337 bool NodeHighlightTool::HideOnMouseMove() {
338   return true;
339 }
340 
Draw(float scale)341 void NodeHighlightTool::Draw(float scale) {
342   DrawNode();
343   DrawMatchingSelector();
344 }
345 
DrawNode()346 void NodeHighlightTool::DrawNode() {
347   bool append_element_info = (node_->IsElementNode() || node_->IsTextNode()) &&
348                              highlight_config_->show_info &&
349                              node_->GetLayoutObject() &&
350                              node_->GetDocument().GetFrame();
351   overlay_->EvaluateInOverlay(
352       "drawHighlight",
353       GetNodeInspectorHighlightAsJson(append_element_info,
354                                       false /* append_distance_info */));
355 }
356 
DrawMatchingSelector()357 void NodeHighlightTool::DrawMatchingSelector() {
358   if (selector_list_.IsEmpty() || !node_)
359     return;
360   DummyExceptionStateForTesting exception_state;
361   ContainerNode* query_base = node_->ContainingShadowRoot();
362   if (!query_base)
363     query_base = node_->ownerDocument();
364 
365   overlay_->EnsureAXContext(query_base);
366 
367   StaticElementList* elements = query_base->QuerySelectorAll(
368       AtomicString(selector_list_), exception_state);
369   if (exception_state.HadException())
370     return;
371 
372   for (unsigned i = 0; i < elements->length(); ++i) {
373     Element* element = elements->item(i);
374     // Skip elements in locked subtrees.
375     if (DisplayLockUtilities::NearestLockedExclusiveAncestor(*element))
376       continue;
377     InspectorHighlight highlight(element, *highlight_config_, contrast_info_,
378                                  false /* append_element_info */,
379                                  false /* append_distance_info */,
380                                  false /* is_locked_ancestor */);
381     overlay_->EvaluateInOverlay("drawHighlight", highlight.AsProtocolValue());
382   }
383 }
384 
Trace(Visitor * visitor) const385 void NodeHighlightTool::Trace(Visitor* visitor) const {
386   InspectTool::Trace(visitor);
387   visitor->Trace(node_);
388 }
389 
390 std::unique_ptr<protocol::DictionaryValue>
GetNodeInspectorHighlightAsJson(bool append_element_info,bool append_distance_info) const391 NodeHighlightTool::GetNodeInspectorHighlightAsJson(
392     bool append_element_info,
393     bool append_distance_info) const {
394   overlay_->EnsureAXContext(node_.Get());
395   InspectorHighlight highlight(node_.Get(), *highlight_config_, contrast_info_,
396                                append_element_info, append_distance_info,
397                                is_locked_ancestor_);
398   return highlight.AsProtocolValue();
399 }
400 
401 // GridHighlightTool -----------------------------------------------------------
GetOverlayName()402 String GridHighlightTool::GetOverlayName() {
403   return OverlayNames::OVERLAY_HIGHLIGHT_GRID;
404 }
405 
AddGridConfig(Node * node,std::unique_ptr<InspectorGridHighlightConfig> grid_highlight_config)406 void GridHighlightTool::AddGridConfig(
407     Node* node,
408     std::unique_ptr<InspectorGridHighlightConfig> grid_highlight_config) {
409   grid_node_highlights_.emplace_back(
410       std::make_pair(node, std::move(grid_highlight_config)));
411 }
412 
ForwardEventsToOverlay()413 bool GridHighlightTool::ForwardEventsToOverlay() {
414   return false;
415 }
416 
HideOnHideHighlight()417 bool GridHighlightTool::HideOnHideHighlight() {
418   return false;
419 }
420 
HideOnMouseMove()421 bool GridHighlightTool::HideOnMouseMove() {
422   return false;
423 }
424 
Draw(float scale)425 void GridHighlightTool::Draw(float scale) {
426   for (auto& entry : grid_node_highlights_) {
427     std::unique_ptr<protocol::Value> highlight =
428         InspectorGridHighlight(entry.first.Get(), *(entry.second));
429     if (!highlight)
430       continue;
431     overlay_->EvaluateInOverlay("drawGridHighlight", std::move(highlight));
432   }
433 }
434 
435 std::unique_ptr<protocol::DictionaryValue>
GetGridInspectorHighlightsAsJson() const436 GridHighlightTool::GetGridInspectorHighlightsAsJson() const {
437   std::unique_ptr<protocol::ListValue> highlights =
438       protocol::ListValue::create();
439   for (auto& entry : grid_node_highlights_) {
440     std::unique_ptr<protocol::Value> highlight =
441         InspectorGridHighlight(entry.first.Get(), *(entry.second));
442     if (!highlight)
443       continue;
444     highlights->pushValue(std::move(highlight));
445   }
446   std::unique_ptr<protocol::DictionaryValue> result =
447       protocol::DictionaryValue::create();
448   if (highlights->size() > 0) {
449     result->setValue("gridHighlights", std::move(highlights));
450   }
451   return result;
452 }
453 
454 // SourceOrderTool -----------------------------------------------------------
455 
SourceOrderTool(InspectorOverlayAgent * overlay,OverlayFrontend * frontend,Node * node,std::unique_ptr<InspectorSourceOrderConfig> source_order_config)456 SourceOrderTool::SourceOrderTool(
457     InspectorOverlayAgent* overlay,
458     OverlayFrontend* frontend,
459     Node* node,
460     std::unique_ptr<InspectorSourceOrderConfig> source_order_config)
461     : InspectTool(overlay, frontend),
462       source_order_config_(std::move(source_order_config)) {
463   if (Node* locked_ancestor =
464           DisplayLockUtilities::HighestLockedExclusiveAncestor(*node)) {
465     node_ = locked_ancestor;
466   } else {
467     node_ = node;
468   }
469 }
470 
GetOverlayName()471 String SourceOrderTool::GetOverlayName() {
472   return OverlayNames::OVERLAY_SOURCE_ORDER;
473 }
474 
Draw(float scale)475 void SourceOrderTool::Draw(float scale) {
476   DrawParentNode();
477 
478   // Draw child outlines and labels.
479   int position_number = 1;
480   for (Node& child_node : NodeTraversal::ChildrenOf(*node_)) {
481     // Don't draw if it's not an element or is not the direct child of the
482     // parent node.
483     if (!child_node.IsElementNode())
484       continue;
485     // Don't draw if it's not rendered/would be ignored by a screen reader.
486     if (child_node.GetComputedStyle()) {
487       bool display_none =
488           child_node.GetComputedStyle()->Display() == EDisplay::kNone;
489       bool visibility_hidden =
490           child_node.GetComputedStyle()->Visibility() == EVisibility::kHidden;
491       if (display_none || visibility_hidden)
492         continue;
493     }
494     DrawNode(&child_node, position_number);
495     position_number++;
496   }
497 }
498 
DrawNode(Node * node,int source_order_position)499 void SourceOrderTool::DrawNode(Node* node, int source_order_position) {
500   InspectorSourceOrderHighlight highlight(
501       node, source_order_config_->child_outline_color, source_order_position);
502   overlay_->EvaluateInOverlay("drawSourceOrder", highlight.AsProtocolValue());
503 }
504 
DrawParentNode()505 void SourceOrderTool::DrawParentNode() {
506   InspectorSourceOrderHighlight highlight(
507       node_.Get(), source_order_config_->parent_outline_color, 0);
508   overlay_->EvaluateInOverlay("drawSourceOrder", highlight.AsProtocolValue());
509 }
510 
HideOnHideHighlight()511 bool SourceOrderTool::HideOnHideHighlight() {
512   return true;
513 }
514 
HideOnMouseMove()515 bool SourceOrderTool::HideOnMouseMove() {
516   return false;
517 }
518 
519 std::unique_ptr<protocol::DictionaryValue>
GetNodeInspectorSourceOrderHighlightAsJson() const520 SourceOrderTool::GetNodeInspectorSourceOrderHighlightAsJson() const {
521   InspectorSourceOrderHighlight highlight(
522       node_.Get(), source_order_config_->parent_outline_color, 0);
523   return highlight.AsProtocolValue();
524 }
525 
Trace(Visitor * visitor) const526 void SourceOrderTool::Trace(Visitor* visitor) const {
527   InspectTool::Trace(visitor);
528   visitor->Trace(node_);
529 }
530 
531 // NearbyDistanceTool ----------------------------------------------------------
532 
GetOverlayName()533 String NearbyDistanceTool::GetOverlayName() {
534   return OverlayNames::OVERLAY_DISTANCES;
535 }
536 
HandleMouseDown(const WebMouseEvent & event,bool * swallow_next_mouse_up)537 bool NearbyDistanceTool::HandleMouseDown(const WebMouseEvent& event,
538                                          bool* swallow_next_mouse_up) {
539   return true;
540 }
541 
HandleMouseMove(const WebMouseEvent & event)542 bool NearbyDistanceTool::HandleMouseMove(const WebMouseEvent& event) {
543   Node* node = HoveredNodeForEvent(overlay_->GetFrame(), event, true);
544 
545   // Do not highlight within user agent shadow root
546   ShadowRoot* shadow_root = InspectorDOMAgent::UserAgentShadowRoot(node);
547   if (shadow_root)
548     node = &shadow_root->host();
549 
550   // Shadow roots don't have boxes - use host element instead.
551   if (node && node->IsShadowRoot())
552     node = node->ParentOrShadowHostNode();
553 
554   if (!node)
555     return true;
556 
557   if (auto* frame_owner = DynamicTo<HTMLFrameOwnerElement>(node)) {
558     if (!IsA<LocalFrame>(frame_owner->ContentFrame())) {
559       // Do not consume event so that remote frame can handle it.
560       overlay_->hideHighlight();
561       hovered_node_.Clear();
562       return false;
563     }
564   }
565 
566   // If |node| is in a display locked subtree, highlight the highest locked
567   // element instead.
568   if (Node* locked_ancestor =
569           DisplayLockUtilities::HighestLockedExclusiveAncestor(*node))
570     node = locked_ancestor;
571 
572   // Store values for the highlight.
573   hovered_node_ = node;
574   return true;
575 }
576 
HandleMouseUp(const WebMouseEvent & event)577 bool NearbyDistanceTool::HandleMouseUp(const WebMouseEvent& event) {
578   return true;
579 }
580 
Draw(float scale)581 void NearbyDistanceTool::Draw(float scale) {
582   Node* node = hovered_node_.Get();
583   if (!node)
584     return;
585   overlay_->EnsureAXContext(node);
586   InspectorHighlight highlight(
587       node, InspectorHighlight::DefaultConfig(),
588       InspectorHighlightContrastInfo(), false /* append_element_info */,
589       true /* append_distance_info */, false /* is_locked_ancestor */);
590   overlay_->EvaluateInOverlay("drawDistances", highlight.AsProtocolValue());
591 }
592 
Trace(Visitor * visitor) const593 void NearbyDistanceTool::Trace(Visitor* visitor) const {
594   InspectTool::Trace(visitor);
595   visitor->Trace(hovered_node_);
596 }
597 
598 // ShowViewSizeTool ------------------------------------------------------------
599 
Draw(float scale)600 void ShowViewSizeTool::Draw(float scale) {
601   overlay_->EvaluateInOverlay("drawViewSize", "");
602 }
603 
GetOverlayName()604 String ShowViewSizeTool::GetOverlayName() {
605   return OverlayNames::OVERLAY_VIEWPORT_SIZE;
606 }
607 
ForwardEventsToOverlay()608 bool ShowViewSizeTool::ForwardEventsToOverlay() {
609   return false;
610 }
611 
612 // ScreenshotTool --------------------------------------------------------------
613 
ScreenshotTool(InspectorOverlayAgent * overlay,OverlayFrontend * frontend)614 ScreenshotTool::ScreenshotTool(InspectorOverlayAgent* overlay,
615                                OverlayFrontend* frontend)
616     : InspectTool(overlay, frontend) {
617   auto& client = overlay_->GetFrame()->GetPage()->GetChromeClient();
618   client.SetCursorOverridden(false);
619   client.SetCursor(CrossCursor(), overlay_->GetFrame());
620   client.SetCursorOverridden(true);
621 }
622 
GetOverlayName()623 String ScreenshotTool::GetOverlayName() {
624   return OverlayNames::OVERLAY_SCREENSHOT;
625 }
626 
Dispatch(const String & message)627 void ScreenshotTool::Dispatch(const String& message) {
628   if (message.IsEmpty())
629     return;
630   std::vector<uint8_t> cbor;
631   if (message.Is8Bit()) {
632     crdtp::json::ConvertJSONToCBOR(
633         crdtp::span<uint8_t>(message.Characters8(), message.length()), &cbor);
634   } else {
635     crdtp::json::ConvertJSONToCBOR(
636         crdtp::span<uint16_t>(
637             reinterpret_cast<const uint16_t*>(message.Characters16()),
638             message.length()),
639         &cbor);
640   }
641   std::unique_ptr<protocol::DOM::Rect> box =
642       protocol::DOM::Rect::FromBinary(cbor.data(), cbor.size());
643   if (!box)
644     return;
645   float scale = 1.0f;
646   // Capture values in the CSS pixels.
647   IntPoint p1(box->getX(), box->getY());
648   IntPoint p2(box->getX() + box->getWidth(), box->getY() + box->getHeight());
649 
650   if (LocalFrame* frame = overlay_->GetFrame()) {
651     float emulation_scale = overlay_->GetFrame()
652                                 ->GetPage()
653                                 ->GetChromeClient()
654                                 .InputEventsScaleForEmulation();
655     // Convert from overlay terms into the absolute.
656     p1.Scale(1 / emulation_scale, 1 / emulation_scale);
657     p2.Scale(1 / emulation_scale, 1 / emulation_scale);
658 
659     // Scroll offset in the viewport is in the device pixels, convert before
660     // calling ViewportToRootFrame.
661     float dip_to_dp = overlay_->WindowToViewportScale();
662     p1.Scale(dip_to_dp, dip_to_dp);
663     p2.Scale(dip_to_dp, dip_to_dp);
664 
665     const VisualViewport& visual_viewport =
666         frame->GetPage()->GetVisualViewport();
667     p1 = visual_viewport.ViewportToRootFrame(p1);
668     p2 = visual_viewport.ViewportToRootFrame(p2);
669 
670     scale = frame->GetPage()->PageScaleFactor();
671     if (const RootFrameViewport* root_frame_viewport =
672             frame->View()->GetRootFrameViewport()) {
673       IntSize scroll_offset = FlooredIntSize(
674           root_frame_viewport->LayoutViewport().GetScrollOffset());
675       // Accunt for the layout scroll (different from viewport scroll offset).
676       p1 += scroll_offset;
677       p2 += scroll_offset;
678     }
679   }
680 
681   // Go back to dip for the protocol.
682   float dp_to_dip = 1.f / overlay_->WindowToViewportScale();
683   p1.Scale(dp_to_dip, dp_to_dip);
684   p2.Scale(dp_to_dip, dp_to_dip);
685 
686   // Points are in device independent pixels (dip) now.
687   IntRect rect =
688       UnionRectEvenIfEmpty(IntRect(p1, IntSize()), IntRect(p2, IntSize()));
689   frontend_->screenshotRequested(protocol::Page::Viewport::create()
690                                      .setX(rect.X())
691                                      .setY(rect.Y())
692                                      .setWidth(rect.Width())
693                                      .setHeight(rect.Height())
694                                      .setScale(scale)
695                                      .build());
696 }
697 
698 // PausedInDebuggerTool --------------------------------------------------------
699 
GetOverlayName()700 String PausedInDebuggerTool::GetOverlayName() {
701   return OverlayNames::OVERLAY_PAUSED;
702 }
703 
Draw(float scale)704 void PausedInDebuggerTool::Draw(float scale) {
705   overlay_->EvaluateInOverlay("drawPausedInDebuggerMessage", message_);
706 }
707 
Dispatch(const String & message)708 void PausedInDebuggerTool::Dispatch(const String& message) {
709   if (message == "resume")
710     v8_session_->resume();
711   else if (message == "stepOver")
712     v8_session_->stepOver();
713 }
714 
715 }  // namespace blink
716