blob: b88176e36744faee241c044b53beedf19f1f3005 [file] [log] [blame]
// Copyright 2015 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/input/event_handler.h"
#include <memory>
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/renderer/core/dom/document.h"
#include "third_party/blink/renderer/core/dom/range.h"
#include "third_party/blink/renderer/core/editing/editing_behavior.h"
#include "third_party/blink/renderer/core/editing/editor.h"
#include "third_party/blink/renderer/core/editing/ephemeral_range.h"
#include "third_party/blink/renderer/core/editing/frame_selection.h"
#include "third_party/blink/renderer/core/editing/selection_controller.h"
#include "third_party/blink/renderer/core/editing/selection_template.h"
#include "third_party/blink/renderer/core/editing/testing/editing_test_base.h"
#include "third_party/blink/renderer/core/frame/local_frame.h"
#include "third_party/blink/renderer/core/frame/local_frame_view.h"
#include "third_party/blink/renderer/core/frame/settings.h"
#include "third_party/blink/renderer/core/html/canvas/html_canvas_element.h"
#include "third_party/blink/renderer/core/html/forms/html_input_element.h"
#include "third_party/blink/renderer/core/html/html_iframe_element.h"
#include "third_party/blink/renderer/core/layout/layout_object.h"
#include "third_party/blink/renderer/core/loader/empty_clients.h"
#include "third_party/blink/renderer/core/page/autoscroll_controller.h"
#include "third_party/blink/renderer/core/page/page.h"
#include "third_party/blink/renderer/core/paint/paint_layer_scrollable_area.h"
#include "third_party/blink/renderer/core/testing/page_test_base.h"
#include "third_party/blink/renderer/core/testing/sim/sim_request.h"
#include "third_party/blink/renderer/core/testing/sim/sim_test.h"
#include "third_party/blink/renderer/platform/testing/unit_test_helpers.h"
namespace blink {
class EventHandlerTest : public PageTestBase {
protected:
void SetUp() override;
void SetHtmlInnerHTML(const char* html_content);
ShadowRoot* SetShadowContent(const char* shadow_content, const char* host);
};
class EventHandlerSimTest : public SimTest {};
class TapEventBuilder : public WebGestureEvent {
public:
TapEventBuilder(FloatPoint position, int tap_count)
: WebGestureEvent(WebInputEvent::kGestureTap,
WebInputEvent::kNoModifiers,
CurrentTimeTicks(),
kWebGestureDeviceTouchscreen) {
SetPositionInWidget(position);
SetPositionInScreen(position);
data.tap.tap_count = tap_count;
data.tap.width = 5;
data.tap.height = 5;
frame_scale_ = 1;
}
};
class TapDownEventBuilder : public WebGestureEvent {
public:
TapDownEventBuilder(FloatPoint position)
: WebGestureEvent(WebInputEvent::kGestureTapDown,
WebInputEvent::kNoModifiers,
CurrentTimeTicks(),
kWebGestureDeviceTouchscreen) {
SetPositionInWidget(position);
SetPositionInScreen(position);
data.tap_down.width = 5;
data.tap_down.height = 5;
frame_scale_ = 1;
}
};
class ShowPressEventBuilder : public WebGestureEvent {
public:
ShowPressEventBuilder(FloatPoint position)
: WebGestureEvent(WebInputEvent::kGestureShowPress,
WebInputEvent::kNoModifiers,
CurrentTimeTicks(),
kWebGestureDeviceTouchscreen) {
SetPositionInWidget(position);
SetPositionInScreen(position);
data.show_press.width = 5;
data.show_press.height = 5;
frame_scale_ = 1;
}
};
class LongPressEventBuilder : public WebGestureEvent {
public:
LongPressEventBuilder(FloatPoint position)
: WebGestureEvent(WebInputEvent::kGestureLongPress,
WebInputEvent::kNoModifiers,
CurrentTimeTicks(),
kWebGestureDeviceTouchscreen) {
SetPositionInWidget(position);
SetPositionInScreen(position);
data.long_press.width = 5;
data.long_press.height = 5;
frame_scale_ = 1;
}
};
class MousePressEventBuilder : public WebMouseEvent {
public:
MousePressEventBuilder(IntPoint position_param,
int click_count_param,
WebMouseEvent::Button button_param)
: WebMouseEvent(WebInputEvent::kMouseDown,
WebInputEvent::kNoModifiers,
CurrentTimeTicks()) {
click_count = click_count_param;
button = button_param;
SetPositionInWidget(position_param.X(), position_param.Y());
SetPositionInScreen(position_param.X(), position_param.Y());
frame_scale_ = 1;
}
};
void EventHandlerTest::SetUp() {
PageTestBase::SetUp(IntSize(300, 400));
}
void EventHandlerTest::SetHtmlInnerHTML(const char* html_content) {
GetDocument().documentElement()->SetInnerHTMLFromString(
String::FromUTF8(html_content));
UpdateAllLifecyclePhasesForTest();
}
ShadowRoot* EventHandlerTest::SetShadowContent(const char* shadow_content,
const char* host) {
ShadowRoot* shadow_root =
EditingTestBase::CreateShadowRootForElementWithIDAndSetInnerHTML(
GetDocument(), host, shadow_content);
return shadow_root;
}
TEST_F(EventHandlerTest, dragSelectionAfterScroll) {
SetHtmlInnerHTML(
"<style> body { margin: 0px; } .upper { width: 300px; height: 400px; }"
".lower { margin: 0px; width: 300px; height: 400px; } .line { display: "
"block; width: 300px; height: 30px; } </style>"
"<div class='upper'></div>"
"<div class='lower'>"
"<span class='line'>Line 1</span><span class='line'>Line 2</span><span "
"class='line'>Line 3</span><span class='line'>Line 4</span><span "
"class='line'>Line 5</span>"
"<span class='line'>Line 6</span><span class='line'>Line 7</span><span "
"class='line'>Line 8</span><span class='line'>Line 9</span><span "
"class='line'>Line 10</span>"
"</div>");
LocalFrameView* frame_view = GetDocument().View();
frame_view->LayoutViewport()->SetScrollOffset(ScrollOffset(0, 400),
kProgrammaticScroll);
WebMouseEvent mouse_down_event(WebInputEvent::kMouseDown, WebFloatPoint(0, 0),
WebFloatPoint(100, 200),
WebPointerProperties::Button::kLeft, 1,
WebInputEvent::Modifiers::kLeftButtonDown,
WebInputEvent::GetStaticTimeStampForTests());
mouse_down_event.SetFrameScale(1);
GetDocument().GetFrame()->GetEventHandler().HandleMousePressEvent(
mouse_down_event);
ASSERT_TRUE(GetDocument()
.GetFrame()
->GetEventHandler()
.GetSelectionController()
.MouseDownMayStartSelect());
WebMouseEvent mouse_move_event(
WebInputEvent::kMouseMove, WebFloatPoint(100, 50),
WebFloatPoint(200, 250), WebPointerProperties::Button::kLeft, 1,
WebInputEvent::Modifiers::kLeftButtonDown,
WebInputEvent::GetStaticTimeStampForTests());
mouse_move_event.SetFrameScale(1);
GetDocument().GetFrame()->GetEventHandler().HandleMouseMoveEvent(
mouse_move_event, Vector<WebMouseEvent>(), Vector<WebMouseEvent>());
GetPage().GetAutoscrollController().Animate();
GetPage().Animator().ServiceScriptedAnimations(WTF::CurrentTimeTicks());
WebMouseEvent mouse_up_event(
WebMouseEvent::kMouseUp, WebFloatPoint(100, 50), WebFloatPoint(200, 250),
WebPointerProperties::Button::kLeft, 1, WebInputEvent::kNoModifiers,
WebInputEvent::GetStaticTimeStampForTests());
mouse_up_event.SetFrameScale(1);
GetDocument().GetFrame()->GetEventHandler().HandleMouseReleaseEvent(
mouse_up_event);
ASSERT_FALSE(GetDocument()
.GetFrame()
->GetEventHandler()
.GetSelectionController()
.MouseDownMayStartSelect());
ASSERT_TRUE(Selection().GetSelectionInDOMTree().IsRange());
Range* range =
CreateRange(EphemeralRange(Selection().GetSelectionInDOMTree().Base(),
Selection().GetSelectionInDOMTree().Extent()));
ASSERT_TRUE(range);
EXPECT_EQ("Line 1\nLine 2", range->GetText());
}
TEST_F(EventHandlerTest, multiClickSelectionFromTap) {
SetHtmlInnerHTML(
"<style> body { margin: 0px; } .line { display: block; width: 300px; "
"height: 30px; } </style>"
"<body contenteditable='true'><span class='line' id='line'>One Two "
"Three</span></body>");
Node* line = GetDocument().getElementById("line")->firstChild();
TapEventBuilder single_tap_event(FloatPoint(0, 0), 1);
GetDocument().GetFrame()->GetEventHandler().HandleGestureEvent(
single_tap_event);
ASSERT_TRUE(Selection().GetSelectionInDOMTree().IsCaret());
EXPECT_EQ(Position(line, 0), Selection().GetSelectionInDOMTree().Base());
// Multi-tap events on editable elements should trigger selection, just
// like multi-click events.
TapEventBuilder double_tap_event(FloatPoint(0, 0), 2);
GetDocument().GetFrame()->GetEventHandler().HandleGestureEvent(
double_tap_event);
ASSERT_TRUE(Selection().GetSelectionInDOMTree().IsRange());
EXPECT_EQ(Position(line, 0), Selection().GetSelectionInDOMTree().Base());
if (GetDocument()
.GetFrame()
->GetEditor()
.IsSelectTrailingWhitespaceEnabled()) {
EXPECT_EQ(Position(line, 4), Selection().GetSelectionInDOMTree().Extent());
EXPECT_EQ("One ", WebString(Selection().SelectedText()).Utf8());
} else {
EXPECT_EQ(Position(line, 3), Selection().GetSelectionInDOMTree().Extent());
EXPECT_EQ("One", WebString(Selection().SelectedText()).Utf8());
}
TapEventBuilder triple_tap_event(FloatPoint(0, 0), 3);
GetDocument().GetFrame()->GetEventHandler().HandleGestureEvent(
triple_tap_event);
ASSERT_TRUE(Selection().GetSelectionInDOMTree().IsRange());
EXPECT_EQ(Position(line, 0), Selection().GetSelectionInDOMTree().Base());
EXPECT_EQ(Position(line, 13), Selection().GetSelectionInDOMTree().Extent());
EXPECT_EQ("One Two Three", WebString(Selection().SelectedText()).Utf8());
}
TEST_F(EventHandlerTest, multiClickSelectionFromTapDisabledIfNotEditable) {
SetHtmlInnerHTML(
"<style> body { margin: 0px; } .line { display: block; width: 300px; "
"height: 30px; } </style>"
"<span class='line' id='line'>One Two Three</span>");
Node* line = GetDocument().getElementById("line")->firstChild();
TapEventBuilder single_tap_event(FloatPoint(0, 0), 1);
GetDocument().GetFrame()->GetEventHandler().HandleGestureEvent(
single_tap_event);
ASSERT_TRUE(Selection().GetSelectionInDOMTree().IsCaret());
EXPECT_EQ(Position(line, 0), Selection().GetSelectionInDOMTree().Base());
// As the text is readonly, multi-tap events should not trigger selection.
TapEventBuilder double_tap_event(FloatPoint(0, 0), 2);
GetDocument().GetFrame()->GetEventHandler().HandleGestureEvent(
double_tap_event);
ASSERT_TRUE(Selection().GetSelectionInDOMTree().IsCaret());
EXPECT_EQ(Position(line, 0), Selection().GetSelectionInDOMTree().Base());
TapEventBuilder triple_tap_event(FloatPoint(0, 0), 3);
GetDocument().GetFrame()->GetEventHandler().HandleGestureEvent(
triple_tap_event);
ASSERT_TRUE(Selection().GetSelectionInDOMTree().IsCaret());
EXPECT_EQ(Position(line, 0), Selection().GetSelectionInDOMTree().Base());
}
TEST_F(EventHandlerTest, draggedInlinePositionTest) {
SetHtmlInnerHTML(
"<style>"
"body { margin: 0px; }"
".line { font-family: sans-serif; background: blue; width: 300px; "
"height: 30px; font-size: 40px; margin-left: 250px; }"
"</style>"
"<div style='width: 300px; height: 100px;'>"
"<span class='line' draggable='true'>abcd</span>"
"</div>");
WebMouseEvent mouse_down_event(WebMouseEvent::kMouseDown,
WebFloatPoint(262, 29), WebFloatPoint(329, 67),
WebPointerProperties::Button::kLeft, 1,
WebInputEvent::Modifiers::kLeftButtonDown,
WebInputEvent::GetStaticTimeStampForTests());
mouse_down_event.SetFrameScale(1);
GetDocument().GetFrame()->GetEventHandler().HandleMousePressEvent(
mouse_down_event);
WebMouseEvent mouse_move_event(
WebMouseEvent::kMouseMove, WebFloatPoint(618, 298),
WebFloatPoint(685, 436), WebPointerProperties::Button::kLeft, 1,
WebInputEvent::Modifiers::kLeftButtonDown,
WebInputEvent::GetStaticTimeStampForTests());
mouse_move_event.SetFrameScale(1);
GetDocument().GetFrame()->GetEventHandler().HandleMouseMoveEvent(
mouse_move_event, Vector<WebMouseEvent>(), Vector<WebMouseEvent>());
EXPECT_EQ(IntPoint(12, 29), GetDocument()
.GetFrame()
->GetEventHandler()
.DragDataTransferLocationForTesting());
}
TEST_F(EventHandlerTest, draggedSVGImagePositionTest) {
SetHtmlInnerHTML(
"<style>"
"body { margin: 0px; }"
"[draggable] {"
"-webkit-user-select: none; user-select: none; -webkit-user-drag: "
"element; }"
"</style>"
"<div style='width: 300px; height: 100px;'>"
"<svg width='500' height='500'>"
"<rect x='100' y='100' width='100px' height='100px' fill='blue' "
"draggable='true'/>"
"</svg>"
"</div>");
WebMouseEvent mouse_down_event(
WebMouseEvent::kMouseDown, WebFloatPoint(145, 144),
WebFloatPoint(212, 282), WebPointerProperties::Button::kLeft, 1,
WebInputEvent::Modifiers::kLeftButtonDown,
WebInputEvent::GetStaticTimeStampForTests());
mouse_down_event.SetFrameScale(1);
GetDocument().GetFrame()->GetEventHandler().HandleMousePressEvent(
mouse_down_event);
WebMouseEvent mouse_move_event(
WebMouseEvent::kMouseMove, WebFloatPoint(618, 298),
WebFloatPoint(685, 436), WebPointerProperties::Button::kLeft, 1,
WebInputEvent::Modifiers::kLeftButtonDown,
WebInputEvent::GetStaticTimeStampForTests());
mouse_move_event.SetFrameScale(1);
GetDocument().GetFrame()->GetEventHandler().HandleMouseMoveEvent(
mouse_move_event, Vector<WebMouseEvent>(), Vector<WebMouseEvent>());
EXPECT_EQ(IntPoint(45, 44), GetDocument()
.GetFrame()
->GetEventHandler()
.DragDataTransferLocationForTesting());
}
TEST_F(EventHandlerTest, HitOnNothingDoesNotShowIBeam) {
SetHtmlInnerHTML("");
HitTestLocation location((LayoutPoint(10, 10)));
HitTestResult hit =
GetDocument().GetFrame()->GetEventHandler().HitTestResultAtLocation(
location);
EXPECT_FALSE(
GetDocument().GetFrame()->GetEventHandler().ShouldShowIBeamForNode(
GetDocument().body(), hit));
}
TEST_F(EventHandlerTest, HitOnTextShowsIBeam) {
SetHtmlInnerHTML("blabla");
Node* const text = GetDocument().body()->firstChild();
HitTestLocation location(
text->GetLayoutObject()->FirstFragment().VisualRect().Center());
HitTestResult hit =
GetDocument().GetFrame()->GetEventHandler().HitTestResultAtLocation(
location);
EXPECT_TRUE(text->CanStartSelection());
EXPECT_TRUE(
GetDocument().GetFrame()->GetEventHandler().ShouldShowIBeamForNode(text,
hit));
}
TEST_F(EventHandlerTest, HitOnUserSelectNoneDoesNotShowIBeam) {
SetHtmlInnerHTML("<span style='user-select: none'>blabla</span>");
Node* const text = GetDocument().body()->firstChild()->firstChild();
HitTestLocation location(
text->GetLayoutObject()->FirstFragment().VisualRect().Center());
HitTestResult hit =
GetDocument().GetFrame()->GetEventHandler().HitTestResultAtLocation(
location);
EXPECT_FALSE(text->CanStartSelection());
EXPECT_FALSE(
GetDocument().GetFrame()->GetEventHandler().ShouldShowIBeamForNode(text,
hit));
}
TEST_F(EventHandlerTest, ShadowChildCanOverrideUserSelectNone) {
SetHtmlInnerHTML("<p style='user-select: none' id='host'></p>");
ShadowRoot* const shadow_root = SetShadowContent(
"<span style='user-select: text' id='bla'>blabla</span>", "host");
Node* const text = shadow_root->getElementById("bla")->firstChild();
HitTestLocation location(
text->GetLayoutObject()->FirstFragment().VisualRect().Center());
HitTestResult hit =
GetDocument().GetFrame()->GetEventHandler().HitTestResultAtLocation(
location);
EXPECT_TRUE(text->CanStartSelection());
EXPECT_TRUE(
GetDocument().GetFrame()->GetEventHandler().ShouldShowIBeamForNode(text,
hit));
}
TEST_F(EventHandlerTest, UserSelectAllCanOverrideUserSelectNone) {
SetHtmlInnerHTML(
"<div style='user-select: none'>"
"<span style='user-select: all'>blabla</span>"
"</div>");
Node* const text =
GetDocument().body()->firstChild()->firstChild()->firstChild();
HitTestLocation location(
text->GetLayoutObject()->FirstFragment().VisualRect().Center());
HitTestResult hit =
GetDocument().GetFrame()->GetEventHandler().HitTestResultAtLocation(
location);
EXPECT_TRUE(text->CanStartSelection());
EXPECT_TRUE(
GetDocument().GetFrame()->GetEventHandler().ShouldShowIBeamForNode(text,
hit));
}
TEST_F(EventHandlerTest, UserSelectNoneCanOverrideUserSelectAll) {
SetHtmlInnerHTML(
"<div style='user-select: all'>"
"<span style='user-select: none'>blabla</span>"
"</div>");
Node* const text =
GetDocument().body()->firstChild()->firstChild()->firstChild();
HitTestLocation location(
text->GetLayoutObject()->FirstFragment().VisualRect().Center());
HitTestResult hit =
GetDocument().GetFrame()->GetEventHandler().HitTestResultAtLocation(
location);
EXPECT_FALSE(text->CanStartSelection());
EXPECT_FALSE(
GetDocument().GetFrame()->GetEventHandler().ShouldShowIBeamForNode(text,
hit));
}
TEST_F(EventHandlerTest, UserSelectTextCanOverrideUserSelectNone) {
SetHtmlInnerHTML(
"<div style='user-select: none'>"
"<span style='user-select: text'>blabla</span>"
"</div>");
Node* const text =
GetDocument().body()->firstChild()->firstChild()->firstChild();
HitTestLocation location(
text->GetLayoutObject()->FirstFragment().VisualRect().Center());
HitTestResult hit =
GetDocument().GetFrame()->GetEventHandler().HitTestResultAtLocation(
location);
EXPECT_TRUE(text->CanStartSelection());
EXPECT_TRUE(
GetDocument().GetFrame()->GetEventHandler().ShouldShowIBeamForNode(text,
hit));
}
TEST_F(EventHandlerTest, UserSelectNoneCanOverrideUserSelectText) {
SetHtmlInnerHTML(
"<div style='user-select: text'>"
"<span style='user-select: none'>blabla</span>"
"</div>");
Node* const text = GetDocument().body()->firstChild()->firstChild()->firstChild();
HitTestLocation location(
text->GetLayoutObject()->FirstFragment().VisualRect().Center());
HitTestResult hit =
GetDocument().GetFrame()->GetEventHandler().HitTestResultAtLocation(
location);
EXPECT_FALSE(text->CanStartSelection());
EXPECT_FALSE(
GetDocument().GetFrame()->GetEventHandler().ShouldShowIBeamForNode(text,
hit));
}
TEST_F(EventHandlerTest, ShadowChildCanOverrideUserSelectText) {
SetHtmlInnerHTML("<p style='user-select: text' id='host'></p>");
ShadowRoot* const shadow_root = SetShadowContent(
"<span style='user-select: none' id='bla'>blabla</span>", "host");
Node* const text = shadow_root->getElementById("bla")->firstChild();
HitTestLocation location(
text->GetLayoutObject()->FirstFragment().VisualRect().Center());
HitTestResult hit =
GetDocument().GetFrame()->GetEventHandler().HitTestResultAtLocation(
location);
EXPECT_FALSE(text->CanStartSelection());
EXPECT_FALSE(
GetDocument().GetFrame()->GetEventHandler().ShouldShowIBeamForNode(text,
hit));
}
TEST_F(EventHandlerTest, InputFieldsCanStartSelection) {
SetHtmlInnerHTML("<input value='blabla'>");
auto* const field = ToHTMLInputElement(GetDocument().body()->firstChild());
Element* const text = field->InnerEditorElement();
HitTestLocation location(
text->GetLayoutObject()->FirstFragment().VisualRect().Center());
HitTestResult hit =
GetDocument().GetFrame()->GetEventHandler().HitTestResultAtLocation(
location);
EXPECT_TRUE(text->CanStartSelection());
EXPECT_TRUE(
GetDocument().GetFrame()->GetEventHandler().ShouldShowIBeamForNode(text,
hit));
}
TEST_F(EventHandlerTest, ReadOnlyInputDoesNotInheritUserSelect) {
SetHtmlInnerHTML(
"<div style='user-select: none'>"
"<input id='sample' readonly value='blabla'>"
"</div>");
HTMLInputElement* const input =
ToHTMLInputElement(GetDocument().getElementById("sample"));
Node* const text = input->InnerEditorElement()->firstChild();
HitTestLocation location(
text->GetLayoutObject()->FirstFragment().VisualRect().Center());
HitTestResult hit =
GetDocument().GetFrame()->GetEventHandler().HitTestResultAtLocation(
location);
EXPECT_TRUE(text->CanStartSelection());
EXPECT_TRUE(
GetDocument().GetFrame()->GetEventHandler().ShouldShowIBeamForNode(text,
hit));
}
TEST_F(EventHandlerTest, ImagesCannotStartSelection) {
SetHtmlInnerHTML("<img>");
Element* const img = ToElement(GetDocument().body()->firstChild());
HitTestLocation location(
img->GetLayoutObject()->FirstFragment().VisualRect().Center());
HitTestResult hit =
GetDocument().GetFrame()->GetEventHandler().HitTestResultAtLocation(
location);
EXPECT_FALSE(img->CanStartSelection());
EXPECT_FALSE(
GetDocument().GetFrame()->GetEventHandler().ShouldShowIBeamForNode(img,
hit));
}
TEST_F(EventHandlerTest, AnchorTextCannotStartSelection) {
SetHtmlInnerHTML("<a href='bala'>link text</a>");
Node* const link = GetDocument().body()->firstChild();
HitTestLocation location(
link->GetLayoutObject()->FirstFragment().VisualRect().Center());
HitTestResult result =
GetDocument().GetFrame()->GetEventHandler().HitTestResultAtLocation(
location);
Node* const text = link->firstChild();
EXPECT_FALSE(text->CanStartSelection());
EXPECT_TRUE(result.IsOverLink());
// ShouldShowIBeamForNode() returns |cursor: auto|'s value.
// In https://github.com/w3c/csswg-drafts/issues/1598 it was decided that:
// a { cursor: auto } /* gives I-beam over links */
EXPECT_TRUE(
GetDocument().GetFrame()->GetEventHandler().ShouldShowIBeamForNode(
text, result));
EXPECT_EQ(GetDocument()
.GetFrame()
->GetEventHandler()
.SelectCursor(location, result)
.GetCursor()
.GetType(),
Cursor::Type::kHand); // A hand signals ability to navigate.
}
TEST_F(EventHandlerTest, EditableAnchorTextCanStartSelection) {
SetHtmlInnerHTML("<a contenteditable='true' href='bala'>editable link</a>");
Node* const link = GetDocument().body()->firstChild();
HitTestLocation location(
link->GetLayoutObject()->FirstFragment().VisualRect().Center());
HitTestResult result =
GetDocument().GetFrame()->GetEventHandler().HitTestResultAtLocation(
location);
Node* const text = link->firstChild();
EXPECT_TRUE(text->CanStartSelection());
EXPECT_TRUE(result.IsOverLink());
EXPECT_TRUE(
GetDocument().GetFrame()->GetEventHandler().ShouldShowIBeamForNode(
text, result));
EXPECT_EQ(GetDocument()
.GetFrame()
->GetEventHandler()
.SelectCursor(location, result)
.GetCursor()
.GetType(),
Cursor::Type::kIBeam); // An I-beam signals editability.
}
// Regression test for http://crbug.com/641403 to verify we use up-to-date
// layout tree for dispatching "contextmenu" event.
TEST_F(EventHandlerTest, sendContextMenuEventWithHover) {
SetHtmlInnerHTML(
"<style>*:hover { color: red; }</style>"
"<div>foo</div>");
GetDocument().GetSettings()->SetScriptEnabled(true);
Element* script = GetDocument().CreateRawElement(html_names::kScriptTag);
script->SetInnerHTMLFromString(
"document.addEventListener('contextmenu', event => "
"event.preventDefault());");
GetDocument().body()->AppendChild(script);
GetDocument().UpdateStyleAndLayout();
GetDocument().GetFrame()->Selection().SetSelectionAndEndTyping(
SelectionInDOMTree::Builder()
.Collapse(Position(GetDocument().body(), 0))
.Build());
WebMouseEvent mouse_down_event(
WebMouseEvent::kMouseDown, WebFloatPoint(0, 0), WebFloatPoint(100, 200),
WebPointerProperties::Button::kRight, 1,
WebInputEvent::Modifiers::kRightButtonDown, CurrentTimeTicks());
mouse_down_event.SetFrameScale(1);
EXPECT_EQ(WebInputEventResult::kHandledApplication,
GetDocument().GetFrame()->GetEventHandler().SendContextMenuEvent(
mouse_down_event));
}
TEST_F(EventHandlerTest, EmptyTextfieldInsertionOnTap) {
SetHtmlInnerHTML("<textarea cols=50 rows=50></textarea>");
TapEventBuilder single_tap_event(FloatPoint(200, 200), 1);
GetDocument().GetFrame()->GetEventHandler().HandleGestureEvent(
single_tap_event);
ASSERT_TRUE(Selection().GetSelectionInDOMTree().IsCaret());
ASSERT_FALSE(Selection().IsHandleVisible());
}
TEST_F(EventHandlerTest, NonEmptyTextfieldInsertionOnTap) {
SetHtmlInnerHTML("<textarea cols=50 rows=50>Enter text</textarea>");
TapEventBuilder single_tap_event(FloatPoint(200, 200), 1);
GetDocument().GetFrame()->GetEventHandler().HandleGestureEvent(
single_tap_event);
ASSERT_TRUE(Selection().GetSelectionInDOMTree().IsCaret());
ASSERT_TRUE(Selection().IsHandleVisible());
}
TEST_F(EventHandlerTest, NewlineDivInsertionOnTap) {
SetHtmlInnerHTML("<div contenteditable><br/></div>");
TapEventBuilder single_tap_event(FloatPoint(10, 10), 1);
GetDocument().GetFrame()->GetEventHandler().HandleGestureEvent(
single_tap_event);
ASSERT_TRUE(Selection().GetSelectionInDOMTree().IsCaret());
ASSERT_TRUE(Selection().IsHandleVisible());
}
TEST_F(EventHandlerTest, EmptyTextfieldInsertionOnLongPress) {
SetHtmlInnerHTML("<textarea cols=50 rows=50></textarea>");
LongPressEventBuilder long_press_event(FloatPoint(200, 200));
GetDocument().GetFrame()->GetEventHandler().HandleGestureEvent(
long_press_event);
ASSERT_TRUE(Selection().GetSelectionInDOMTree().IsCaret());
ASSERT_TRUE(Selection().IsHandleVisible());
// Single Tap on an empty edit field should clear insertion handle
TapEventBuilder single_tap_event(FloatPoint(200, 200), 1);
GetDocument().GetFrame()->GetEventHandler().HandleGestureEvent(
single_tap_event);
ASSERT_TRUE(Selection().GetSelectionInDOMTree().IsCaret());
ASSERT_FALSE(Selection().IsHandleVisible());
}
TEST_F(EventHandlerTest, NonEmptyTextfieldInsertionOnLongPress) {
SetHtmlInnerHTML("<textarea cols=50 rows=50>Enter text</textarea>");
LongPressEventBuilder long_press_event(FloatPoint(200, 200));
GetDocument().GetFrame()->GetEventHandler().HandleGestureEvent(
long_press_event);
ASSERT_TRUE(Selection().GetSelectionInDOMTree().IsCaret());
ASSERT_TRUE(Selection().IsHandleVisible());
}
TEST_F(EventHandlerTest, ClearHandleAfterTap) {
SetHtmlInnerHTML("<textarea cols=50 rows=10>Enter text</textarea>");
// Show handle
LongPressEventBuilder long_press_event(FloatPoint(200, 10));
GetDocument().GetFrame()->GetEventHandler().HandleGestureEvent(
long_press_event);
ASSERT_TRUE(Selection().GetSelectionInDOMTree().IsCaret());
ASSERT_TRUE(Selection().IsHandleVisible());
// Tap away from text area should clear handle
TapEventBuilder single_tap_event(FloatPoint(200, 350), 1);
GetDocument().GetFrame()->GetEventHandler().HandleGestureEvent(
single_tap_event);
ASSERT_FALSE(Selection().IsHandleVisible());
}
TEST_F(EventHandlerTest, HandleNotShownOnMouseEvents) {
SetHtmlInnerHTML("<textarea cols=50 rows=50>Enter text</textarea>");
MousePressEventBuilder left_mouse_press_event(
IntPoint(200, 200), 1, WebPointerProperties::Button::kLeft);
GetDocument().GetFrame()->GetEventHandler().HandleMousePressEvent(
left_mouse_press_event);
ASSERT_TRUE(Selection().GetSelectionInDOMTree().IsCaret());
ASSERT_FALSE(Selection().IsHandleVisible());
MousePressEventBuilder right_mouse_press_event(
IntPoint(200, 200), 1, WebPointerProperties::Button::kRight);
GetDocument().GetFrame()->GetEventHandler().HandleMousePressEvent(
right_mouse_press_event);
ASSERT_TRUE(Selection().GetSelectionInDOMTree().IsCaret());
ASSERT_FALSE(Selection().IsHandleVisible());
MousePressEventBuilder double_click_mouse_press_event(
IntPoint(200, 200), 2, WebPointerProperties::Button::kLeft);
GetDocument().GetFrame()->GetEventHandler().HandleMousePressEvent(
double_click_mouse_press_event);
ASSERT_TRUE(Selection().GetSelectionInDOMTree().IsRange());
ASSERT_FALSE(Selection().IsHandleVisible());
MousePressEventBuilder triple_click_mouse_press_event(
IntPoint(200, 200), 3, WebPointerProperties::Button::kLeft);
GetDocument().GetFrame()->GetEventHandler().HandleMousePressEvent(
triple_click_mouse_press_event);
ASSERT_TRUE(Selection().GetSelectionInDOMTree().IsRange());
ASSERT_FALSE(Selection().IsHandleVisible());
}
TEST_F(EventHandlerTest, MisspellingContextMenuEvent) {
if (GetDocument()
.GetFrame()
->GetEditor()
.Behavior()
.ShouldSelectOnContextualMenuClick())
return;
SetHtmlInnerHTML("<textarea cols=50 rows=50>Mispellinggg</textarea>");
TapEventBuilder single_tap_event(FloatPoint(10, 10), 1);
GetDocument().GetFrame()->GetEventHandler().HandleGestureEvent(
single_tap_event);
ASSERT_TRUE(Selection().GetSelectionInDOMTree().IsCaret());
ASSERT_TRUE(Selection().IsHandleVisible());
GetDocument().GetFrame()->GetEventHandler().ShowNonLocatedContextMenu(
nullptr, kMenuSourceTouchHandle);
ASSERT_TRUE(Selection().GetSelectionInDOMTree().IsCaret());
ASSERT_TRUE(Selection().IsHandleVisible());
}
TEST_F(EventHandlerTest, dragEndInNewDrag) {
SetHtmlInnerHTML(
"<style>.box { width: 100px; height: 100px; display: block; }</style>"
"<a class='box' href=''>Drag me</a>");
WebMouseEvent mouse_down_event(
WebInputEvent::kMouseDown, WebFloatPoint(50, 50), WebFloatPoint(50, 50),
WebPointerProperties::Button::kLeft, 1,
WebInputEvent::Modifiers::kLeftButtonDown, CurrentTimeTicks());
mouse_down_event.SetFrameScale(1);
GetDocument().GetFrame()->GetEventHandler().HandleMousePressEvent(
mouse_down_event);
WebMouseEvent mouse_move_event(
WebInputEvent::kMouseMove, WebFloatPoint(51, 50), WebFloatPoint(51, 50),
WebPointerProperties::Button::kLeft, 1,
WebInputEvent::Modifiers::kLeftButtonDown, CurrentTimeTicks());
mouse_move_event.SetFrameScale(1);
GetDocument().GetFrame()->GetEventHandler().HandleMouseMoveEvent(
mouse_move_event, Vector<WebMouseEvent>(), Vector<WebMouseEvent>());
// This reproduces what might be the conditions of http://crbug.com/677916
//
// TODO(crbug.com/682047): The call sequence below should not occur outside
// this contrived test. Given the current code, it is unclear how the
// dragSourceEndedAt() call could occur before a drag operation is started.
WebMouseEvent mouse_up_event(WebInputEvent::kMouseUp, WebFloatPoint(100, 50),
WebFloatPoint(200, 250),
WebPointerProperties::Button::kLeft, 1,
WebInputEvent::kNoModifiers, CurrentTimeTicks());
mouse_up_event.SetFrameScale(1);
GetDocument().GetFrame()->GetEventHandler().DragSourceEndedAt(
mouse_up_event, kDragOperationNone);
// This test passes if it doesn't crash.
}
// This test mouse move with modifier kRelativeMotionEvent
// should not start drag.
TEST_F(EventHandlerTest, FakeMouseMoveNotStartDrag) {
SetHtmlInnerHTML(
"<style>"
"body { margin: 0px; }"
".line { font-family: sans-serif; background: blue; width: 300px; "
"height: 30px; font-size: 40px; margin-left: 250px; }"
"</style>"
"<div style='width: 300px; height: 100px;'>"
"<span class='line' draggable='true'>abcd</span>"
"</div>");
WebMouseEvent mouse_down_event(WebMouseEvent::kMouseDown,
WebFloatPoint(262, 29), WebFloatPoint(329, 67),
WebPointerProperties::Button::kLeft, 1,
WebInputEvent::Modifiers::kLeftButtonDown,
WebInputEvent::GetStaticTimeStampForTests());
mouse_down_event.SetFrameScale(1);
GetDocument().GetFrame()->GetEventHandler().HandleMousePressEvent(
mouse_down_event);
WebMouseEvent fake_mouse_move(
WebMouseEvent::kMouseMove, WebFloatPoint(618, 298),
WebFloatPoint(685, 436), WebPointerProperties::Button::kLeft, 1,
WebInputEvent::Modifiers::kLeftButtonDown |
WebInputEvent::Modifiers::kRelativeMotionEvent,
WebInputEvent::GetStaticTimeStampForTests());
fake_mouse_move.SetFrameScale(1);
EXPECT_EQ(
WebInputEventResult::kHandledSuppressed,
GetDocument().GetFrame()->GetEventHandler().HandleMouseMoveEvent(
fake_mouse_move, Vector<WebMouseEvent>(), Vector<WebMouseEvent>()));
EXPECT_EQ(IntPoint(0, 0), GetDocument()
.GetFrame()
->GetEventHandler()
.DragDataTransferLocationForTesting());
}
class TooltipCapturingChromeClient : public EmptyChromeClient {
public:
TooltipCapturingChromeClient() = default;
void SetToolTip(LocalFrame&, const String& str, TextDirection) override {
last_tool_tip_ = str;
}
String& LastToolTip() { return last_tool_tip_; }
private:
String last_tool_tip_;
};
class EventHandlerTooltipTest : public EventHandlerTest {
public:
EventHandlerTooltipTest() = default;
void SetUp() override {
chrome_client_ = new TooltipCapturingChromeClient();
Page::PageClients clients;
FillWithEmptyClients(clients);
clients.chrome_client = chrome_client_.Get();
SetupPageWithClients(&clients);
}
String& LastToolTip() { return chrome_client_->LastToolTip(); }
private:
Persistent<TooltipCapturingChromeClient> chrome_client_;
};
TEST_F(EventHandlerTooltipTest, mouseLeaveClearsTooltip) {
GetDocument().SetCompatibilityMode(Document::kQuirksMode);
SetHtmlInnerHTML(
"<style>.box { width: 100%; height: 100%; }</style>"
"<img src='image.png' class='box' title='tooltip'>link</img>");
EXPECT_EQ(WTF::String(), LastToolTip());
WebMouseEvent mouse_move_event(
WebInputEvent::kMouseMove, WebFloatPoint(51, 50), WebFloatPoint(51, 50),
WebPointerProperties::Button::kNoButton, 0, WebInputEvent::kNoModifiers,
CurrentTimeTicks());
mouse_move_event.SetFrameScale(1);
GetDocument().GetFrame()->GetEventHandler().HandleMouseMoveEvent(
mouse_move_event, Vector<WebMouseEvent>(), Vector<WebMouseEvent>());
EXPECT_EQ("tooltip", LastToolTip());
WebMouseEvent mouse_leave_event(
WebInputEvent::kMouseLeave, WebFloatPoint(0, 0), WebFloatPoint(0, 0),
WebPointerProperties::Button::kNoButton, 0, WebInputEvent::kNoModifiers,
CurrentTimeTicks());
mouse_leave_event.SetFrameScale(1);
GetDocument().GetFrame()->GetEventHandler().HandleMouseLeaveEvent(
mouse_leave_event);
EXPECT_EQ(WTF::String(), LastToolTip());
}
class UnbufferedInputEventsTrackingChromeClient : public EmptyChromeClient {
public:
UnbufferedInputEventsTrackingChromeClient() = default;
void RequestUnbufferedInputEvents(LocalFrame*) override {
received_unbuffered_request_ = true;
}
bool ReceivedRequestForUnbufferedInput() {
bool value = received_unbuffered_request_;
received_unbuffered_request_ = false;
return value;
}
private:
bool received_unbuffered_request_ = false;
};
class EventHandlerLatencyTest : public PageTestBase {
protected:
void SetUp() override {
chrome_client_ = new UnbufferedInputEventsTrackingChromeClient();
Page::PageClients page_clients;
FillWithEmptyClients(page_clients);
page_clients.chrome_client = chrome_client_.Get();
SetupPageWithClients(&page_clients);
}
void SetHtmlInnerHTML(const char* html_content) {
GetDocument().documentElement()->SetInnerHTMLFromString(
String::FromUTF8(html_content));
UpdateAllLifecyclePhasesForTest();
}
Persistent<UnbufferedInputEventsTrackingChromeClient> chrome_client_;
};
TEST_F(EventHandlerLatencyTest, NeedsUnbufferedInput) {
GetDocument().GetSettings()->SetScriptEnabled(true);
SetHtmlInnerHTML(
"<canvas style='width: 100px; height: 100px' id='first' "
"onpointermove='return;'>");
HTMLCanvasElement& canvas =
ToHTMLCanvasElement(*GetDocument().getElementById("first"));
ASSERT_FALSE(chrome_client_->ReceivedRequestForUnbufferedInput());
WebMouseEvent mouse_press_event(
WebInputEvent::kMouseDown, WebFloatPoint(51, 50), WebFloatPoint(51, 50),
WebPointerProperties::Button::kLeft, 0, WebInputEvent::kNoModifiers,
CurrentTimeTicks());
mouse_press_event.SetFrameScale(1);
GetDocument().GetFrame()->GetEventHandler().HandleMousePressEvent(
mouse_press_event);
ASSERT_FALSE(chrome_client_->ReceivedRequestForUnbufferedInput());
canvas.SetNeedsUnbufferedInputEvents(true);
GetDocument().GetFrame()->GetEventHandler().HandleMousePressEvent(
mouse_press_event);
ASSERT_TRUE(chrome_client_->ReceivedRequestForUnbufferedInput());
canvas.SetNeedsUnbufferedInputEvents(false);
GetDocument().GetFrame()->GetEventHandler().HandleMousePressEvent(
mouse_press_event);
ASSERT_FALSE(chrome_client_->ReceivedRequestForUnbufferedInput());
}
class NavigationCapturingFrameClient : public EmptyLocalFrameClient {
public:
NavigationCapturingFrameClient() = default;
bool NavigateBackForward(int offset) const override {
offset_ = offset;
return true;
}
int Offset() const { return offset_; }
private:
mutable int offset_ = 0;
};
class EventHandlerNavigationTest : public EventHandlerTest {
public:
EventHandlerNavigationTest() = default;
void SetUp() override {
frame_client_ = new NavigationCapturingFrameClient();
Page::PageClients clients;
FillWithEmptyClients(clients);
SetupPageWithClients(&clients, frame_client_);
}
int Offset() { return frame_client_->Offset(); }
private:
Persistent<NavigationCapturingFrameClient> frame_client_;
};
TEST_F(EventHandlerNavigationTest, MouseButtonsNavigate) {
SetHtmlInnerHTML("<div>");
EXPECT_EQ(0, Offset());
WebMouseEvent mouse_back_event(
WebInputEvent::kMouseUp, WebFloatPoint(51, 50), WebFloatPoint(51, 50),
WebPointerProperties::Button::kBack, 0, WebInputEvent::kNoModifiers,
CurrentTimeTicks());
mouse_back_event.SetFrameScale(1);
GetDocument().GetFrame()->GetEventHandler().HandleMouseReleaseEvent(
mouse_back_event);
EXPECT_EQ(-1, Offset());
WebMouseEvent mouse_forward_event(
WebInputEvent::kMouseUp, WebFloatPoint(51, 50), WebFloatPoint(51, 50),
WebPointerProperties::Button::kForward, 0, WebInputEvent::kNoModifiers,
CurrentTimeTicks());
mouse_forward_event.SetFrameScale(1);
GetDocument().GetFrame()->GetEventHandler().HandleMouseReleaseEvent(
mouse_forward_event);
EXPECT_EQ(1, Offset());
}
TEST_F(EventHandlerNavigationTest, MouseButtonsDontNavigate) {
SetHtmlInnerHTML("<div>");
GetDocument().GetSettings()->SetScriptEnabled(true);
Element* script = GetDocument().CreateRawElement(html_names::kScriptTag);
script->SetInnerHTMLFromString(
"document.addEventListener('mouseup', event => "
"event.preventDefault());");
GetDocument().body()->AppendChild(script);
EXPECT_EQ(0, Offset());
WebMouseEvent mouse_back_event(
WebInputEvent::kMouseUp, WebFloatPoint(51, 50), WebFloatPoint(51, 50),
WebPointerProperties::Button::kBack, 0, WebInputEvent::kNoModifiers,
CurrentTimeTicks());
mouse_back_event.SetFrameScale(1);
GetDocument().GetFrame()->GetEventHandler().HandleMouseReleaseEvent(
mouse_back_event);
EXPECT_EQ(0, Offset());
WebMouseEvent mouse_forward_event(
WebInputEvent::kMouseUp, WebFloatPoint(51, 50), WebFloatPoint(51, 50),
WebPointerProperties::Button::kForward, 0, WebInputEvent::kNoModifiers,
CurrentTimeTicks());
mouse_forward_event.SetFrameScale(1);
GetDocument().GetFrame()->GetEventHandler().HandleMouseReleaseEvent(
mouse_forward_event);
EXPECT_EQ(0, Offset());
}
// Test that leaving a window leaves mouse position unknown.
TEST_F(EventHandlerTest, MouseLeaveResetsUnknownState) {
SetHtmlInnerHTML("<div></div>");
WebMouseEvent mouse_down_event(WebMouseEvent::kMouseDown,
WebFloatPoint(262, 29), WebFloatPoint(329, 67),
WebPointerProperties::Button::kLeft, 1,
WebInputEvent::Modifiers::kLeftButtonDown,
WebInputEvent::GetStaticTimeStampForTests());
mouse_down_event.SetFrameScale(1);
GetDocument().GetFrame()->GetEventHandler().HandleMousePressEvent(
mouse_down_event);
EXPECT_FALSE(
GetDocument().GetFrame()->GetEventHandler().IsMousePositionUnknown());
WebMouseEvent mouse_leave_event(
WebMouseEvent::kMouseLeave, WebFloatPoint(262, 29),
WebFloatPoint(329, 67), WebPointerProperties::Button::kNoButton, 1,
WebInputEvent::Modifiers::kNoModifiers,
WebInputEvent::GetStaticTimeStampForTests());
mouse_leave_event.SetFrameScale(1);
GetDocument().GetFrame()->GetEventHandler().HandleMouseLeaveEvent(
mouse_leave_event);
EXPECT_TRUE(
GetDocument().GetFrame()->GetEventHandler().IsMousePositionUnknown());
}
// Test that leaving an iframe sets the mouse position to unknown on that
// iframe.
TEST_F(EventHandlerSimTest, MouseLeaveIFrameResets) {
WebView().Resize(WebSize(800, 600));
SimRequest main_resource("https://example.com/test.html", "text/html");
SimRequest frame_resource("https://example.com/frame.html", "text/html");
LoadURL("https://example.com/test.html");
main_resource.Complete(R"HTML(
<!DOCTYPE html>
<style>
div {
width: 200px;
height: 200px;
}
iframe {
width: 200px;
height: 200px;
}
</style>
<div></div>
<iframe id='frame' src='frame.html'></iframe>
)HTML");
frame_resource.Complete("<!DOCTYPE html>");
Compositor().BeginFrame();
WebMouseEvent mouse_move_inside_event(
WebMouseEvent::kMouseMove, WebFloatPoint(100, 229),
WebFloatPoint(100, 229), WebPointerProperties::Button::kNoButton, 0,
WebInputEvent::Modifiers::kNoModifiers,
WebInputEvent::GetStaticTimeStampForTests());
mouse_move_inside_event.SetFrameScale(1);
GetDocument().GetFrame()->GetEventHandler().HandleMouseMoveEvent(
mouse_move_inside_event, Vector<WebMouseEvent>(),
Vector<WebMouseEvent>());
EXPECT_FALSE(
GetDocument().GetFrame()->GetEventHandler().IsMousePositionUnknown());
auto* child_frame =
ToHTMLIFrameElement(GetDocument().getElementById("frame"));
child_frame->contentDocument()
->UpdateStyleAndLayoutIgnorePendingStylesheets();
EXPECT_TRUE(GetDocument().GetFrame()->Tree().FirstChild());
EXPECT_TRUE(GetDocument().GetFrame()->Tree().FirstChild()->IsLocalFrame());
EXPECT_FALSE(ToLocalFrame(GetDocument().GetFrame()->Tree().FirstChild())
->GetEventHandler()
.IsMousePositionUnknown());
WebMouseEvent mouse_move_outside_event(
WebMouseEvent::kMouseMove, WebFloatPoint(300, 29), WebFloatPoint(300, 29),
WebPointerProperties::Button::kNoButton, 0,
WebInputEvent::Modifiers::kNoModifiers,
WebInputEvent::GetStaticTimeStampForTests());
mouse_move_outside_event.SetFrameScale(1);
GetDocument().GetFrame()->GetEventHandler().HandleMouseMoveEvent(
mouse_move_outside_event, Vector<WebMouseEvent>(),
Vector<WebMouseEvent>());
EXPECT_FALSE(
GetDocument().GetFrame()->GetEventHandler().IsMousePositionUnknown());
EXPECT_TRUE(GetDocument().GetFrame()->Tree().FirstChild());
EXPECT_TRUE(GetDocument().GetFrame()->Tree().FirstChild()->IsLocalFrame());
EXPECT_TRUE(ToLocalFrame(GetDocument().GetFrame()->Tree().FirstChild())
->GetEventHandler()
.IsMousePositionUnknown());
}
// Test that mouse down and move a small distance on a draggable element will
// not change cursor style.
TEST_F(EventHandlerSimTest, CursorStyleBeforeStartDragging) {
WebView().Resize(WebSize(800, 600));
SimRequest request("https://example.com/test.html", "text/html");
LoadURL("https://example.com/test.html");
request.Complete(R"HTML(
<!DOCTYPE html>
<style>
div {
width: 300px;
height: 100px;
cursor: help;
}
</style>
<div draggable='true'>foo</div>
)HTML");
Compositor().BeginFrame();
WebMouseEvent mouse_down_event(WebMouseEvent::kMouseDown,
WebFloatPoint(150, 50), WebFloatPoint(150, 50),
WebPointerProperties::Button::kLeft, 1,
WebInputEvent::Modifiers::kLeftButtonDown,
WebInputEvent::GetStaticTimeStampForTests());
mouse_down_event.SetFrameScale(1);
GetDocument().GetFrame()->GetEventHandler().HandleMousePressEvent(
mouse_down_event);
WebMouseEvent mouse_move_event(WebMouseEvent::kMouseMove,
WebFloatPoint(151, 50), WebFloatPoint(151, 50),
WebPointerProperties::Button::kLeft, 1,
WebInputEvent::Modifiers::kLeftButtonDown,
WebInputEvent::GetStaticTimeStampForTests());
mouse_move_event.SetFrameScale(1);
GetDocument().GetFrame()->GetEventHandler().HandleMouseMoveEvent(
mouse_move_event, Vector<WebMouseEvent>(), Vector<WebMouseEvent>());
EXPECT_EQ(Cursor::Type::kHelp, GetDocument()
.GetFrame()
->GetChromeClient()
.LastSetCursorForTesting()
.GetType());
}
// Ensure that tap on element in iframe should apply active state.
TEST_F(EventHandlerSimTest, TapActiveInFrame) {
WebView().Resize(WebSize(800, 600));
SimRequest main_resource("https://example.com/test.html", "text/html");
SimRequest frame_resource("https://example.com/iframe.html", "text/html");
LoadURL("https://example.com/test.html");
main_resource.Complete(R"HTML(
<!DOCTYPE html>
<style>
body {
margin: 0;
}
iframe {
width: 200px;
height: 200px;
}
</style>
<iframe id='iframe' src='iframe.html'>
</iframe>
)HTML");
frame_resource.Complete(R"HTML(
<!DOCTYPE html>
<style>
body {
margin: 0;
}
div {
width: 100px;
height: 100px;
}
</style>
<div></div>
)HTML");
Compositor().BeginFrame();
auto* iframe_element =
ToHTMLIFrameElement(GetDocument().getElementById("iframe"));
Document* iframe_doc = iframe_element->contentDocument();
TapDownEventBuilder tap_down(FloatPoint(10, 10));
GetDocument().GetFrame()->GetEventHandler().HandleGestureEvent(tap_down);
ShowPressEventBuilder show_press(FloatPoint(10, 10));
GetDocument().GetFrame()->GetEventHandler().HandleGestureEvent(show_press);
// TapDown and ShowPress active the iframe.
EXPECT_TRUE(GetDocument().GetActiveElement());
EXPECT_TRUE(iframe_doc->GetActiveElement());
TapEventBuilder tap(FloatPoint(10, 10), 1);
GetDocument().GetFrame()->GetEventHandler().HandleGestureEvent(tap);
// Should still active.
EXPECT_TRUE(GetDocument().GetActiveElement());
EXPECT_TRUE(iframe_doc->GetActiveElement());
// The active will cancel after 15ms.
test::RunDelayedTasks(TimeDelta::FromSecondsD(0.2));
EXPECT_FALSE(GetDocument().GetActiveElement());
EXPECT_FALSE(iframe_doc->GetActiveElement());
}
} // namespace blink