Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1209)

Side by Side Diff: third_party/WebKit/Source/web/tests/LinkSelectionTest.cpp

Issue 1774123006: Implement link selection on alt+mouse drag. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Use String instead of std::string. Created 4 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright (c) 2016 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 "core/dom/Range.h"
6 #include "core/frame/FrameView.h"
7 #include "core/input/EventHandler.h"
8 #include "core/page/ChromeClient.h"
9 #include "core/page/ContextMenuController.h"
10 #include "core/page/FocusController.h"
11 #include "core/page/Page.h"
12 #include "platform/Cursor.h"
13 #include "platform/testing/URLTestHelpers.h"
14 #include "platform/testing/UnitTestHelpers.h"
15 #include "public/web/WebSettings.h"
16 #include "testing/gmock/include/gmock/gmock.h"
17 #include "testing/gtest/include/gtest/gtest.h"
18 #include "web/WebLocalFrameImpl.h"
19 #include "web/tests/FrameTestHelpers.h"
20
21 using ::testing::_;
22
23 namespace blink {
24
25 IntSize scaled(IntSize p, float scale)
26 {
27 p.scale(scale, scale);
28 return p;
29 }
30
31 class LinkSelectionTestBase : public ::testing::Test {
32 protected:
33 enum DragFlag {
34 SendDownEvent = 1,
35 SendUpEvent = 1 << 1
36 };
37 using DragFlags = unsigned;
38
39 void emulateMouseDrag(const IntPoint& downPoint, const IntPoint& upPoint, in t modifiers,
40 DragFlags = SendDownEvent | SendUpEvent);
41
42 void emulateMouseClick(const IntPoint& clickPoint, WebMouseEvent::Button, in t modifiers, int count = 1);
43 void emulateMouseDown(const IntPoint& clickPoint, WebMouseEvent::Button, int modifiers, int count = 1);
44
45 String getSelectionText();
46
47 FrameTestHelpers::WebViewHelper m_helper;
48 WebViewImpl* m_webView = nullptr;
49 RawPtrWillBePersistent<WebLocalFrameImpl> m_mainFrame = nullptr;
50 };
51
52 void LinkSelectionTestBase::emulateMouseDrag(const IntPoint& downPoint, const In tPoint& upPoint, int modifiers, DragFlags dragFlags)
53 {
54 if (dragFlags & SendDownEvent) {
55 const auto& downEvent = FrameTestHelpers::createMouseEvent(WebMouseEvent ::MouseDown, WebMouseEvent::ButtonLeft, downPoint, modifiers);
56 m_webView->handleInputEvent(downEvent);
57 }
58
59 const int kMoveEventsNumber = 10;
60 const float kMoveIncrementFraction = 1. / kMoveEventsNumber;
61 const auto& upDownVector = upPoint - downPoint;
62 for (int i = 0; i < kMoveEventsNumber; ++i) {
63 const auto& movePoint = downPoint + scaled(upDownVector, i * kMoveIncrem entFraction);
64 const auto& moveEvent = FrameTestHelpers::createMouseEvent(WebMouseEvent ::MouseMove, WebMouseEvent::ButtonLeft, movePoint, modifiers);
65 m_webView->handleInputEvent(moveEvent);
66 }
67
68 if (dragFlags & SendUpEvent) {
69 const auto& upEvent = FrameTestHelpers::createMouseEvent(WebMouseEvent:: MouseUp, WebMouseEvent::ButtonLeft, upPoint, modifiers);
70 m_webView->handleInputEvent(upEvent);
71 }
72 }
73
74 void LinkSelectionTestBase::emulateMouseClick(const IntPoint& clickPoint, WebMou seEvent::Button button, int modifiers, int count)
75 {
76 auto event = FrameTestHelpers::createMouseEvent(WebMouseEvent::MouseDown, bu tton, clickPoint, modifiers);
77 event.clickCount = count;
78 m_webView->handleInputEvent(event);
79 event.type = WebMouseEvent::MouseUp;
80 m_webView->handleInputEvent(event);
81 }
82
83 void LinkSelectionTestBase::emulateMouseDown(const IntPoint& clickPoint, WebMous eEvent::Button button, int modifiers, int count)
84 {
85 auto event = FrameTestHelpers::createMouseEvent(WebMouseEvent::MouseDown, bu tton, clickPoint, modifiers);
86 event.clickCount = count;
87 m_webView->handleInputEvent(event);
88 }
89
90 String LinkSelectionTestBase::getSelectionText()
91 {
92 return m_mainFrame->selectionAsText();
93 }
94
95 class TestFrameClient : public FrameTestHelpers::TestWebFrameClient {
96 public:
97 MOCK_METHOD4(loadURLExternally,
98 void(const WebURLRequest&, WebNavigationPolicy, const WebString& downloa dName, bool shouldReplaceCurrentEntry));
99 };
100
101 class LinkSelectionTest : public LinkSelectionTestBase {
102 protected:
103 void SetUp() override
104 {
105 const char* const kHTMLString =
106 "<a id='link' href='foo.com' style='font-size:20pt'>Text to select f oobar</a>"
107 "<div id='page_text'>Lorem ipsum dolor sit amet</div>";
108
109 // We need to set deviceSupportsMouse setting to true and page's focus c ontroller to active
110 // so that FrameView can set the mouse cursor.
111 m_webView = m_helper.initialize(false, &m_testFrameClient, nullptr,
112 [](WebSettings* settings) { settings->setDeviceSupportsMouse(true); });
113 m_mainFrame = m_webView->mainFrameImpl();
114 FrameTestHelpers::loadHTMLString(m_mainFrame, kHTMLString, URLTestHelper s::toKURL("http://foobar.com"));
115 m_webView->resize(WebSize(800, 600));
116 m_webView->page()->focusController().setActive(true);
117
118 auto* document = m_mainFrame->frame()->document();
119 ASSERT_NE(nullptr, document);
120 auto* linkToSelect = document->getElementById("link")->firstChild();
121 ASSERT_NE(nullptr, linkToSelect);
122 // We get larger range that we actually want to select, because we need a slightly larger
123 // rect to include the last character to the selection.
124 const auto rangeToSelect = Range::create(*document, linkToSelect, 5, lin kToSelect, 16);
125
126 const auto& selectionRect = rangeToSelect->boundingBox();
127 const auto& selectionRectCenterY = selectionRect.center().y();
128 m_leftPointInLink = selectionRect.minXMinYCorner();
129 m_leftPointInLink.setY(selectionRectCenterY);
130
131 m_rightPointInLink = selectionRect.maxXMinYCorner();
132 m_rightPointInLink.setY(selectionRectCenterY);
133 m_rightPointInLink.move(-2, 0);
134 }
135
136 TestFrameClient m_testFrameClient;
137 IntPoint m_leftPointInLink;
138 IntPoint m_rightPointInLink;
139 };
140
141 TEST_F(LinkSelectionTest, MouseDragWithoutAltAllowNoLinkSelection)
142 {
143 emulateMouseDrag(m_leftPointInLink, m_rightPointInLink, 0);
144 EXPECT_TRUE(getSelectionText().isEmpty());
145 }
146
147 TEST_F(LinkSelectionTest, MouseDragWithAltAllowSelection)
148 {
149 emulateMouseDrag(m_leftPointInLink, m_rightPointInLink, WebInputEvent::AltKe y);
150 EXPECT_EQ("to select", getSelectionText());
151 }
152
153 TEST_F(LinkSelectionTest, HandCursorDuringLinkDrag)
154 {
155 emulateMouseDrag(m_rightPointInLink, m_leftPointInLink, 0, SendDownEvent);
156 m_mainFrame->frame()->localFrameRoot()->eventHandler().scheduleCursorUpdate( );
157 testing::runDelayedTasks(50);
158 const auto& cursor = m_mainFrame->frame()->chromeClient().lastSetCursorForTe sting();
159 EXPECT_EQ(Cursor::Hand, cursor.getType());
160 }
161
162 TEST_F(LinkSelectionTest, CaretCursorOverLinkDuringSelection)
163 {
164 emulateMouseDrag(m_rightPointInLink, m_leftPointInLink, WebInputEvent::AltKe y, SendDownEvent);
165 m_mainFrame->frame()->localFrameRoot()->eventHandler().scheduleCursorUpdate( );
166 testing::runDelayedTasks(50);
167 const auto& cursor = m_mainFrame->frame()->chromeClient().lastSetCursorForTe sting();
168 EXPECT_EQ(Cursor::IBeam, cursor.getType());
169 }
170
171 TEST_F(LinkSelectionTest, HandCursorOverLinkAfterContextMenu)
172 {
173 // Move mouse.
174 emulateMouseDrag(m_rightPointInLink, m_leftPointInLink, 0, 0);
175
176 // Show context menu. We don't send mouseup event here since in browser it d oesn't reach
177 // blink because of shown context menu.
178 emulateMouseDown(m_leftPointInLink, WebMouseEvent::ButtonRight, 0, 1);
179
180 LocalFrame* frame = m_mainFrame->frame();
181 // Hide context menu.
182 frame->page()->contextMenuController().clearContextMenu();
183
184 frame->localFrameRoot()->eventHandler().scheduleCursorUpdate();
185 testing::runDelayedTasks(50);
186 const auto& cursor = m_mainFrame->frame()->chromeClient().lastSetCursorForTe sting();
187 EXPECT_EQ(Cursor::Hand, cursor.getType());
188 }
189
190 TEST_F(LinkSelectionTest, SingleClickWithAltStartsDownload)
191 {
192 EXPECT_CALL(m_testFrameClient, loadURLExternally(_, WebNavigationPolicy::Web NavigationPolicyDownload, WebString(), _));
193 emulateMouseClick(m_leftPointInLink, WebMouseEvent::ButtonLeft, WebInputEven t::AltKey);
194 }
195
196 TEST_F(LinkSelectionTest, SingleClickWithAltStartsDownloadWhenTextSelected)
197 {
198 auto* document = m_mainFrame->frame()->document();
199 auto* textToSelect = document->getElementById("page_text")->firstChild();
200 ASSERT_NE(nullptr, textToSelect);
201
202 // Select some page text outside the link element.
203 const RefPtrWillBeRawPtr<Range> rangeToSelect = Range::create(*document, tex tToSelect, 1, textToSelect, 20);
204 const auto& selectionRect = rangeToSelect->boundingBox();
205 m_mainFrame->moveRangeSelection(selectionRect.minXMinYCorner(), selectionRec t.maxXMaxYCorner());
206 EXPECT_FALSE(getSelectionText().isEmpty());
207
208 EXPECT_CALL(m_testFrameClient, loadURLExternally(_, WebNavigationPolicy::Web NavigationPolicyDownload, WebString(), _));
209 emulateMouseClick(m_leftPointInLink, WebMouseEvent::ButtonLeft, WebInputEven t::AltKey);
210 }
211
212 class LinkSelectionClickEventsTest : public LinkSelectionTestBase {
213 protected:
214 class MockEventListener final : public EventListener {
215 public:
216 static PassRefPtrWillBeRawPtr<MockEventListener> create()
217 {
218 return adoptRefWillBeNoop(new MockEventListener());
219 }
220
221 bool operator==(const EventListener& other) const final
222 {
223 return this == &other;
224 }
225
226 MOCK_METHOD2(handleEvent, void(ExecutionContext* executionContext, Event *));
227
228 private:
229 MockEventListener() : EventListener(CPPEventListenerType)
230 {
231 }
232 };
233
234 void SetUp() override
235 {
236 const char* const kHTMLString =
237 "<div id='empty_div' style='width: 100px; height: 100px;'></div>"
238 "<span id='text_div'>Sometexttoshow</span>";
239
240 m_webView = m_helper.initialize(false);
241 m_mainFrame = m_webView->mainFrameImpl();
242 FrameTestHelpers::loadHTMLString(m_mainFrame, kHTMLString, URLTestHelper s::toKURL("http://foobar.com"));
243 m_webView->resize(WebSize(800, 600));
244 m_webView->page()->focusController().setActive(true);
245
246 auto* document = m_mainFrame->frame()->document();
247 ASSERT_NE(nullptr, document);
248
249 auto* emptyDiv = document->getElementById("empty_div");
250 auto* textDiv = document->getElementById("text_div");
251 ASSERT_NE(nullptr, emptyDiv);
252 ASSERT_NE(nullptr, textDiv);
253 }
254
255 void checkMouseClicks(Element& element, bool doubleClickEvent)
256 {
257 struct ScopedListenersCleaner {
258 ScopedListenersCleaner(Element* element) : m_element(element) {}
259
260 ~ScopedListenersCleaner()
261 {
262 m_element->removeAllEventListeners();
263 }
264
265 RawPtrWillBePersistent<Element> m_element;
266 } const listenersCleaner(&element);
267
268 RefPtrWillBeRawPtr<MockEventListener> eventHandler = MockEventListener:: create();
269 element.addEventListener(
270 doubleClickEvent ? EventTypeNames::dblclick : EventTypeNames::click,
271 eventHandler);
272
273 ::testing::InSequence s;
274 EXPECT_CALL(*eventHandler, handleEvent(_, _)).Times(1);
275
276 const auto& elemBounds = element.boundsInViewport();
277 const int clickCount = doubleClickEvent ? 2 : 1;
278 emulateMouseClick(elemBounds.center(), WebMouseEvent::ButtonLeft, 0, cli ckCount);
279
280 if (doubleClickEvent) {
281 EXPECT_EQ(element.innerText().isEmpty(), getSelectionText().isEmpty( ));
282 }
283 }
284 };
285
286 TEST_F(LinkSelectionClickEventsTest, SingleAndDoubleClickWillBeHandled)
287 {
288 auto* document = m_mainFrame->frame()->document();
289 auto* element = document->getElementById("empty_div");
290
291 {
292 SCOPED_TRACE("Empty div, single click");
293 checkMouseClicks(*element, false);
294 }
295
296 {
297 SCOPED_TRACE("Empty div, double click");
298 checkMouseClicks(*element, true);
299 }
300
301 element = document->getElementById("text_div");
302
303 {
304 SCOPED_TRACE("Text div, single click");
305 checkMouseClicks(*element, false);
306 }
307
308 {
309 SCOPED_TRACE("Text div, double click");
310 checkMouseClicks(*element, true);
311 }
312 }
313
314 } // namespace blink
OLDNEW
« no previous file with comments | « third_party/WebKit/Source/web/tests/FrameTestHelpers.cpp ('k') | third_party/WebKit/Source/web/web.gypi » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698