OLD | NEW |
---|---|
(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 std::string getSelectionText(); | |
tkent
2016/03/28 07:59:21
Please don't use std::string in Blink. Use WTF::S
kotenkov
2016/03/28 08:26:30
FIY: there are 251 more mentions of std::string in
| |
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 std::string LinkSelectionTestBase::getSelectionText() | |
91 { | |
92 return m_mainFrame->selectionAsText().utf8(); | |
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_EQ(std::string(), getSelectionText()); | |
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().empty()); | |
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().empty()) ; | |
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 | |
OLD | NEW |