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