blob: 937955cb02f8449ce45853710c1970ae60fc84f0 [file] [log] [blame]
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "third_party/blink/renderer/core/inspector/inspect_tools.h"
#include "third_party/blink/public/common/input/web_gesture_event.h"
#include "third_party/blink/public/common/input/web_input_event.h"
#include "third_party/blink/public/common/input/web_keyboard_event.h"
#include "third_party/blink/public/common/input/web_pointer_event.h"
#include "third_party/blink/public/platform/web_input_event_result.h"
#include "third_party/blink/public/resources/grit/inspector_overlay_resources_map.h"
#include "third_party/blink/renderer/core/css/css_color_value.h"
#include "third_party/blink/renderer/core/css/css_computed_style_declaration.h"
#include "third_party/blink/renderer/core/display_lock/display_lock_utilities.h"
#include "third_party/blink/renderer/core/dom/element.h"
#include "third_party/blink/renderer/core/dom/node_computed_style.h"
#include "third_party/blink/renderer/core/dom/shadow_root.h"
#include "third_party/blink/renderer/core/dom/static_node_list.h"
#include "third_party/blink/renderer/core/frame/local_frame.h"
#include "third_party/blink/renderer/core/frame/root_frame_viewport.h"
#include "third_party/blink/renderer/core/frame/visual_viewport.h"
#include "third_party/blink/renderer/core/html/html_frame_owner_element.h"
#include "third_party/blink/renderer/core/inspector/inspector_css_agent.h"
#include "third_party/blink/renderer/core/inspector/inspector_dom_agent.h"
#include "third_party/blink/renderer/core/inspector/node_content_visibility_state.h"
#include "third_party/blink/renderer/core/layout/hit_test_location.h"
#include "third_party/blink/renderer/core/layout/layout_view.h"
#include "third_party/blink/renderer/core/page/chrome_client.h"
#include "third_party/blink/renderer/core/page/page.h"
#include "third_party/blink/renderer/platform/cursors.h"
#include "third_party/blink/renderer/platform/keyboard_codes.h"
#include "third_party/inspector_protocol/crdtp/json.h"
namespace blink {
namespace {
InspectorHighlightContrastInfo FetchContrast(Node* node) {
InspectorHighlightContrastInfo result;
auto* element = DynamicTo<Element>(node);
if (!element)
return result;
Vector<Color> bgcolors;
String font_size;
String font_weight;
float text_opacity = 1.0f;
InspectorCSSAgent::GetBackgroundColors(element, &bgcolors, &font_size,
&font_weight, &text_opacity);
if (bgcolors.size() == 1) {
result.font_size = font_size;
result.font_weight = font_weight;
result.background_color = bgcolors[0];
result.text_opacity = text_opacity;
}
return result;
}
Node* HoveredNodeForPoint(LocalFrame* frame,
const IntPoint& point_in_root_frame,
bool ignore_pointer_events_none) {
HitTestRequest::HitTestRequestType hit_type =
HitTestRequest::kMove | HitTestRequest::kReadOnly |
HitTestRequest::kAllowChildFrameContent;
if (ignore_pointer_events_none)
hit_type |= HitTestRequest::kIgnorePointerEventsNone;
HitTestRequest request(hit_type);
HitTestLocation location(
frame->View()->ConvertFromRootFrame(point_in_root_frame));
HitTestResult result(request, location);
frame->ContentLayoutObject()->HitTest(location, result);
Node* node = result.InnerPossiblyPseudoNode();
while (node && node->getNodeType() == Node::kTextNode)
node = node->parentNode();
return node;
}
Node* HoveredNodeForEvent(LocalFrame* frame,
const WebGestureEvent& event,
bool ignore_pointer_events_none) {
return HoveredNodeForPoint(
frame, RoundedIntPoint(FloatPoint(event.PositionInRootFrame())),
ignore_pointer_events_none);
}
Node* HoveredNodeForEvent(LocalFrame* frame,
const WebMouseEvent& event,
bool ignore_pointer_events_none) {
return HoveredNodeForPoint(
frame, RoundedIntPoint(FloatPoint(event.PositionInRootFrame())),
ignore_pointer_events_none);
}
Node* HoveredNodeForEvent(LocalFrame* frame,
const WebPointerEvent& event,
bool ignore_pointer_events_none) {
WebPointerEvent transformed_point = event.WebPointerEventInRootFrame();
return HoveredNodeForPoint(
frame, RoundedIntPoint(FloatPoint(transformed_point.PositionInWidget())),
ignore_pointer_events_none);
}
bool IsSelfLocked(Node* node) {
auto* element = DynamicTo<Element>(node);
if (!element)
return false;
auto* context = element->GetDisplayLockContext();
if (!context)
return false;
return context->IsLocked();
}
NodeContentVisibilityState DetermineSelfContentVisibilityState(Node* node) {
return IsSelfLocked(node) ? NodeContentVisibilityState::kIsLocked
: NodeContentVisibilityState::kNone;
}
std::pair<Node*, NodeContentVisibilityState> DetermineContentVisibilityState(
Node* node) {
DCHECK(node);
std::pair<Node*, NodeContentVisibilityState> result;
if (auto* locked_ancestor =
DisplayLockUtilities::HighestLockedExclusiveAncestor(*node)) {
result.first = locked_ancestor;
result.second = NodeContentVisibilityState::kIsLockedAncestor;
} else {
result.first = node;
result.second = DetermineSelfContentVisibilityState(node);
}
return result;
}
} // namespace
// SearchingForNodeTool --------------------------------------------------------
SearchingForNodeTool::SearchingForNodeTool(InspectorOverlayAgent* overlay,
OverlayFrontend* frontend,
InspectorDOMAgent* dom_agent,
bool ua_shadow,
const std::vector<uint8_t>& config)
: InspectTool(overlay, frontend),
dom_agent_(dom_agent),
ua_shadow_(ua_shadow) {
auto parsed_config = protocol::Overlay::HighlightConfig::FromBinary(
config.data(), config.size());
if (parsed_config) {
highlight_config_ =
InspectorOverlayAgent::ToHighlightConfig(parsed_config.get());
}
}
String SearchingForNodeTool::GetOverlayName() {
return OverlayNames::OVERLAY_HIGHLIGHT;
}
void SearchingForNodeTool::Trace(Visitor* visitor) const {
InspectTool::Trace(visitor);
visitor->Trace(dom_agent_);
visitor->Trace(hovered_node_);
visitor->Trace(event_target_node_);
}
void SearchingForNodeTool::Draw(float scale) {
if (!hovered_node_)
return;
Node* node = hovered_node_.Get();
bool append_element_info = (node->IsElementNode() || node->IsTextNode()) &&
!omit_tooltip_ && highlight_config_->show_info &&
node->GetLayoutObject() &&
node->GetDocument().GetFrame();
overlay_->EnsureAXContext(node);
InspectorHighlight highlight(node, *highlight_config_, contrast_info_,
append_element_info, false,
content_visibility_state_);
if (event_target_node_) {
highlight.AppendEventTargetQuads(event_target_node_.Get(),
*highlight_config_);
}
overlay_->EvaluateInOverlay("drawHighlight", highlight.AsProtocolValue());
}
bool SearchingForNodeTool::SupportsPersistentOverlays() {
return true;
}
bool SearchingForNodeTool::HandleInputEvent(LocalFrameView* frame_view,
const WebInputEvent& input_event,
bool* swallow_next_mouse_up) {
if (input_event.GetType() == WebInputEvent::Type::kGestureScrollBegin ||
input_event.GetType() == WebInputEvent::Type::kGestureScrollUpdate ||
input_event.GetType() == WebInputEvent::Type::kMouseLeave) {
hovered_node_.Clear();
event_target_node_.Clear();
overlay_->ScheduleUpdate();
return false;
}
return InspectTool::HandleInputEvent(frame_view, input_event,
swallow_next_mouse_up);
}
bool SearchingForNodeTool::HandleMouseMove(const WebMouseEvent& event) {
LocalFrame* frame = overlay_->GetFrame();
if (!frame || !frame->View() || !frame->ContentLayoutObject())
return false;
Node* node = HoveredNodeForEvent(
frame, event, event.GetModifiers() & WebInputEvent::kShiftKey);
// Do not highlight within user agent shadow root unless requested.
if (!ua_shadow_) {
ShadowRoot* shadow_root = InspectorDOMAgent::UserAgentShadowRoot(node);
if (shadow_root)
node = &shadow_root->host();
}
// Shadow roots don't have boxes - use host element instead.
if (node && node->IsShadowRoot())
node = node->ParentOrShadowHostNode();
if (!node)
return true;
std::tie(node, content_visibility_state_) =
DetermineContentVisibilityState(node);
if (auto* frame_owner = DynamicTo<HTMLFrameOwnerElement>(node)) {
if (!IsA<LocalFrame>(frame_owner->ContentFrame())) {
// Do not consume event so that remote frame can handle it.
overlay_->hideHighlight();
hovered_node_.Clear();
return false;
}
}
// Store values for the highlight.
bool hovered_node_changed = node != hovered_node_;
hovered_node_ = node;
event_target_node_ = (event.GetModifiers() & WebInputEvent::kShiftKey)
? HoveredNodeForEvent(frame, event, false)
: nullptr;
if (event_target_node_ == hovered_node_)
event_target_node_ = nullptr;
omit_tooltip_ = event.GetModifiers() &
(WebInputEvent::kControlKey | WebInputEvent::kMetaKey);
contrast_info_ = FetchContrast(node);
if (hovered_node_changed)
NodeHighlightRequested(node);
return true;
}
bool SearchingForNodeTool::HandleMouseDown(const WebMouseEvent& event,
bool* swallow_next_mouse_up) {
if (hovered_node_) {
*swallow_next_mouse_up = true;
overlay_->Inspect(hovered_node_.Get());
hovered_node_.Clear();
return true;
}
return false;
}
bool SearchingForNodeTool::HandleGestureTapEvent(const WebGestureEvent& event) {
Node* node = HoveredNodeForEvent(overlay_->GetFrame(), event, false);
if (node) {
overlay_->Inspect(node);
return true;
}
return false;
}
bool SearchingForNodeTool::HandlePointerEvent(const WebPointerEvent& event) {
// Trigger Inspect only when a pointer device is pressed down.
if (event.GetType() != WebInputEvent::Type::kPointerDown)
return false;
Node* node = HoveredNodeForEvent(overlay_->GetFrame(), event, false);
if (node) {
overlay_->Inspect(node);
return true;
}
return false;
}
void SearchingForNodeTool::NodeHighlightRequested(Node* node) {
while (node && !node->IsElementNode() && !node->IsDocumentNode() &&
!node->IsDocumentFragment())
node = node->ParentOrShadowHostNode();
if (!node)
return;
int node_id = dom_agent_->PushNodePathToFrontend(node);
if (node_id)
frontend_->nodeHighlightRequested(node_id);
}
// QuadHighlightTool -----------------------------------------------------------
QuadHighlightTool::QuadHighlightTool(InspectorOverlayAgent* overlay,
OverlayFrontend* frontend,
std::unique_ptr<FloatQuad> quad,
Color color,
Color outline_color)
: InspectTool(overlay, frontend),
quad_(std::move(quad)),
color_(color),
outline_color_(outline_color) {}
String QuadHighlightTool::GetOverlayName() {
return OverlayNames::OVERLAY_HIGHLIGHT;
}
bool QuadHighlightTool::ForwardEventsToOverlay() {
return false;
}
bool QuadHighlightTool::HideOnHideHighlight() {
return true;
}
void QuadHighlightTool::Draw(float scale) {
InspectorHighlight highlight(scale);
highlight.AppendQuad(*quad_, color_, outline_color_);
overlay_->EvaluateInOverlay("drawHighlight", highlight.AsProtocolValue());
}
// NodeHighlightTool -----------------------------------------------------------
NodeHighlightTool::NodeHighlightTool(
InspectorOverlayAgent* overlay,
OverlayFrontend* frontend,
Member<Node> node,
String selector_list,
std::unique_ptr<InspectorHighlightConfig> highlight_config)
: InspectTool(overlay, frontend),
selector_list_(selector_list),
highlight_config_(std::move(highlight_config)) {
std::tie(node_, content_visibility_state_) =
DetermineContentVisibilityState(node);
contrast_info_ = FetchContrast(node_);
}
String NodeHighlightTool::GetOverlayName() {
return OverlayNames::OVERLAY_HIGHLIGHT;
}
bool NodeHighlightTool::ForwardEventsToOverlay() {
return false;
}
bool NodeHighlightTool::SupportsPersistentOverlays() {
return true;
}
bool NodeHighlightTool::HideOnHideHighlight() {
return true;
}
bool NodeHighlightTool::HideOnMouseMove() {
return true;
}
void NodeHighlightTool::Draw(float scale) {
DrawNode();
DrawMatchingSelector();
}
void NodeHighlightTool::DrawNode() {
bool append_element_info = (node_->IsElementNode() || node_->IsTextNode()) &&
highlight_config_->show_info &&
node_->GetLayoutObject() &&
node_->GetDocument().GetFrame();
overlay_->EvaluateInOverlay(
"drawHighlight",
GetNodeInspectorHighlightAsJson(append_element_info,
false /* append_distance_info */));
}
void NodeHighlightTool::DrawMatchingSelector() {
if (selector_list_.IsEmpty() || !node_)
return;
DummyExceptionStateForTesting exception_state;
ContainerNode* query_base = node_->ContainingShadowRoot();
if (!query_base)
query_base = node_->ownerDocument();
overlay_->EnsureAXContext(query_base);
StaticElementList* elements = query_base->QuerySelectorAll(
AtomicString(selector_list_), exception_state);
if (exception_state.HadException())
return;
for (unsigned i = 0; i < elements->length(); ++i) {
Element* element = elements->item(i);
// Skip elements in locked subtrees.
if (DisplayLockUtilities::NearestLockedExclusiveAncestor(*element))
continue;
NodeContentVisibilityState content_visibility_state =
DetermineSelfContentVisibilityState(element);
InspectorHighlight highlight(element, *highlight_config_, contrast_info_,
false /* append_element_info */,
false /* append_distance_info */,
content_visibility_state);
overlay_->EvaluateInOverlay("drawHighlight", highlight.AsProtocolValue());
}
}
void NodeHighlightTool::Trace(Visitor* visitor) const {
InspectTool::Trace(visitor);
visitor->Trace(node_);
}
std::unique_ptr<protocol::DictionaryValue>
NodeHighlightTool::GetNodeInspectorHighlightAsJson(
bool append_element_info,
bool append_distance_info) const {
overlay_->EnsureAXContext(node_.Get());
InspectorHighlight highlight(node_.Get(), *highlight_config_, contrast_info_,
append_element_info, append_distance_info,
content_visibility_state_);
return highlight.AsProtocolValue();
}
// GridHighlightTool -----------------------------------------------------------
String PersistentTool::GetOverlayName() {
return OverlayNames::OVERLAY_PERSISTENT;
}
bool PersistentTool::IsEmpty() {
return !grid_node_highlights_.size() && !flex_container_configs_.size();
}
void PersistentTool::SetGridConfigs(
Vector<std::pair<Member<Node>,
std::unique_ptr<InspectorGridHighlightConfig>>> configs) {
grid_node_highlights_ = std::move(configs);
}
void PersistentTool::SetFlexContainerConfigs(
Vector<std::pair<Member<Node>,
std::unique_ptr<InspectorFlexContainerHighlightConfig>>>
configs) {
flex_container_configs_ = std::move(configs);
}
bool PersistentTool::ForwardEventsToOverlay() {
return false;
}
bool PersistentTool::HideOnHideHighlight() {
return false;
}
bool PersistentTool::HideOnMouseMove() {
return false;
}
void PersistentTool::Draw(float scale) {
for (auto& entry : grid_node_highlights_) {
std::unique_ptr<protocol::Value> highlight =
InspectorGridHighlight(entry.first.Get(), *(entry.second));
if (!highlight)
continue;
overlay_->EvaluateInOverlay("drawGridHighlight", std::move(highlight));
}
for (auto& entry : flex_container_configs_) {
std::unique_ptr<protocol::Value> highlight =
InspectorFlexContainerHighlight(entry.first.Get(), *(entry.second));
if (!highlight)
continue;
overlay_->EvaluateInOverlay("drawFlexContainerHighlight",
std::move(highlight));
}
}
std::unique_ptr<protocol::DictionaryValue>
PersistentTool::GetGridInspectorHighlightsAsJson() const {
std::unique_ptr<protocol::ListValue> highlights =
protocol::ListValue::create();
for (auto& entry : grid_node_highlights_) {
std::unique_ptr<protocol::Value> highlight =
InspectorGridHighlight(entry.first.Get(), *(entry.second));
if (!highlight)
continue;
highlights->pushValue(std::move(highlight));
}
std::unique_ptr<protocol::DictionaryValue> result =
protocol::DictionaryValue::create();
if (highlights->size() > 0) {
result->setValue("gridHighlights", std::move(highlights));
}
return result;
}
// SourceOrderTool -----------------------------------------------------------
SourceOrderTool::SourceOrderTool(
InspectorOverlayAgent* overlay,
OverlayFrontend* frontend,
Node* node,
std::unique_ptr<InspectorSourceOrderConfig> source_order_config)
: InspectTool(overlay, frontend),
source_order_config_(std::move(source_order_config)) {
node_ = DetermineContentVisibilityState(node).first;
}
String SourceOrderTool::GetOverlayName() {
return OverlayNames::OVERLAY_SOURCE_ORDER;
}
void SourceOrderTool::Draw(float scale) {
DrawParentNode();
// Draw child outlines and labels.
int position_number = 1;
for (Node& child_node : NodeTraversal::ChildrenOf(*node_)) {
// Don't draw if it's not an element or is not the direct child of the
// parent node.
if (!child_node.IsElementNode())
continue;
// Don't draw if it's not rendered/would be ignored by a screen reader.
if (child_node.GetComputedStyle()) {
bool display_none =
child_node.GetComputedStyle()->Display() == EDisplay::kNone;
bool visibility_hidden =
child_node.GetComputedStyle()->Visibility() == EVisibility::kHidden;
if (display_none || visibility_hidden)
continue;
}
DrawNode(&child_node, position_number);
position_number++;
}
}
void SourceOrderTool::DrawNode(Node* node, int source_order_position) {
InspectorSourceOrderHighlight highlight(
node, source_order_config_->child_outline_color, source_order_position);
overlay_->EvaluateInOverlay("drawSourceOrder", highlight.AsProtocolValue());
}
void SourceOrderTool::DrawParentNode() {
InspectorSourceOrderHighlight highlight(
node_.Get(), source_order_config_->parent_outline_color, 0);
overlay_->EvaluateInOverlay("drawSourceOrder", highlight.AsProtocolValue());
}
bool SourceOrderTool::HideOnHideHighlight() {
return true;
}
bool SourceOrderTool::HideOnMouseMove() {
return false;
}
std::unique_ptr<protocol::DictionaryValue>
SourceOrderTool::GetNodeInspectorSourceOrderHighlightAsJson() const {
InspectorSourceOrderHighlight highlight(
node_.Get(), source_order_config_->parent_outline_color, 0);
return highlight.AsProtocolValue();
}
void SourceOrderTool::Trace(Visitor* visitor) const {
InspectTool::Trace(visitor);
visitor->Trace(node_);
}
// NearbyDistanceTool ----------------------------------------------------------
String NearbyDistanceTool::GetOverlayName() {
return OverlayNames::OVERLAY_DISTANCES;
}
bool NearbyDistanceTool::HandleMouseDown(const WebMouseEvent& event,
bool* swallow_next_mouse_up) {
return true;
}
bool NearbyDistanceTool::HandleMouseMove(const WebMouseEvent& event) {
Node* node = HoveredNodeForEvent(overlay_->GetFrame(), event, true);
// Do not highlight within user agent shadow root
ShadowRoot* shadow_root = InspectorDOMAgent::UserAgentShadowRoot(node);
if (shadow_root)
node = &shadow_root->host();
// Shadow roots don't have boxes - use host element instead.
if (node && node->IsShadowRoot())
node = node->ParentOrShadowHostNode();
if (!node)
return true;
if (auto* frame_owner = DynamicTo<HTMLFrameOwnerElement>(node)) {
if (!IsA<LocalFrame>(frame_owner->ContentFrame())) {
// Do not consume event so that remote frame can handle it.
overlay_->hideHighlight();
hovered_node_.Clear();
return false;
}
}
node = DetermineContentVisibilityState(node).first;
// Store values for the highlight.
hovered_node_ = node;
return true;
}
bool NearbyDistanceTool::HandleMouseUp(const WebMouseEvent& event) {
return true;
}
void NearbyDistanceTool::Draw(float scale) {
Node* node = hovered_node_.Get();
if (!node)
return;
overlay_->EnsureAXContext(node);
auto content_visibility_state = DetermineSelfContentVisibilityState(node);
InspectorHighlight highlight(
node, InspectorHighlight::DefaultConfig(),
InspectorHighlightContrastInfo(), false /* append_element_info */,
true /* append_distance_info */, content_visibility_state);
overlay_->EvaluateInOverlay("drawDistances", highlight.AsProtocolValue());
}
void NearbyDistanceTool::Trace(Visitor* visitor) const {
InspectTool::Trace(visitor);
visitor->Trace(hovered_node_);
}
// ShowViewSizeTool ------------------------------------------------------------
void ShowViewSizeTool::Draw(float scale) {
overlay_->EvaluateInOverlay("drawViewSize", "");
}
String ShowViewSizeTool::GetOverlayName() {
return OverlayNames::OVERLAY_VIEWPORT_SIZE;
}
bool ShowViewSizeTool::ForwardEventsToOverlay() {
return false;
}
// ScreenshotTool --------------------------------------------------------------
ScreenshotTool::ScreenshotTool(InspectorOverlayAgent* overlay,
OverlayFrontend* frontend)
: InspectTool(overlay, frontend) {
auto& client = overlay_->GetFrame()->GetPage()->GetChromeClient();
client.SetCursorOverridden(false);
client.SetCursor(CrossCursor(), overlay_->GetFrame());
client.SetCursorOverridden(true);
}
String ScreenshotTool::GetOverlayName() {
return OverlayNames::OVERLAY_SCREENSHOT;
}
void ScreenshotTool::Dispatch(const String& message) {
if (message.IsEmpty())
return;
std::vector<uint8_t> cbor;
if (message.Is8Bit()) {
crdtp::json::ConvertJSONToCBOR(
crdtp::span<uint8_t>(message.Characters8(), message.length()), &cbor);
} else {
crdtp::json::ConvertJSONToCBOR(
crdtp::span<uint16_t>(
reinterpret_cast<const uint16_t*>(message.Characters16()),
message.length()),
&cbor);
}
std::unique_ptr<protocol::DOM::Rect> box =
protocol::DOM::Rect::FromBinary(cbor.data(), cbor.size());
if (!box)
return;
float scale = 1.0f;
// Capture values in the CSS pixels.
IntPoint p1(box->getX(), box->getY());
IntPoint p2(box->getX() + box->getWidth(), box->getY() + box->getHeight());
if (LocalFrame* frame = overlay_->GetFrame()) {
float emulation_scale = overlay_->GetFrame()
->GetPage()
->GetChromeClient()
.InputEventsScaleForEmulation();
// Convert from overlay terms into the absolute.
p1.Scale(1 / emulation_scale, 1 / emulation_scale);
p2.Scale(1 / emulation_scale, 1 / emulation_scale);
// Scroll offset in the viewport is in the device pixels, convert before
// calling ViewportToRootFrame.
float dip_to_dp = overlay_->WindowToViewportScale();
p1.Scale(dip_to_dp, dip_to_dp);
p2.Scale(dip_to_dp, dip_to_dp);
const VisualViewport& visual_viewport =
frame->GetPage()->GetVisualViewport();
p1 = visual_viewport.ViewportToRootFrame(p1);
p2 = visual_viewport.ViewportToRootFrame(p2);
scale = frame->GetPage()->PageScaleFactor();
if (const RootFrameViewport* root_frame_viewport =
frame->View()->GetRootFrameViewport()) {
IntSize scroll_offset = FlooredIntSize(
root_frame_viewport->LayoutViewport().GetScrollOffset());
// Accunt for the layout scroll (different from viewport scroll offset).
p1 += scroll_offset;
p2 += scroll_offset;
}
}
// Go back to dip for the protocol.
float dp_to_dip = 1.f / overlay_->WindowToViewportScale();
p1.Scale(dp_to_dip, dp_to_dip);
p2.Scale(dp_to_dip, dp_to_dip);
// Points are in device independent pixels (dip) now.
IntRect rect =
UnionRectEvenIfEmpty(IntRect(p1, IntSize()), IntRect(p2, IntSize()));
frontend_->screenshotRequested(protocol::Page::Viewport::create()
.setX(rect.X())
.setY(rect.Y())
.setWidth(rect.Width())
.setHeight(rect.Height())
.setScale(scale)
.build());
}
// PausedInDebuggerTool --------------------------------------------------------
String PausedInDebuggerTool::GetOverlayName() {
return OverlayNames::OVERLAY_PAUSED;
}
void PausedInDebuggerTool::Draw(float scale) {
overlay_->EvaluateInOverlay("drawPausedInDebuggerMessage", message_);
}
void PausedInDebuggerTool::Dispatch(const String& message) {
if (message == "resume")
v8_session_->resume();
else if (message == "stepOver")
v8_session_->stepOver();
}
} // namespace blink