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/SelectionTestBase.h" |
| 20 |
| 21 using ::testing::_; |
| 22 |
| 23 namespace blink { |
| 24 |
| 25 class TestFrameClient : public FrameTestHelpers::TestWebFrameClient { |
| 26 public: |
| 27 MOCK_METHOD4(loadURLExternally, |
| 28 void(const WebURLRequest&, WebNavigationPolicy, const WebString& downloa
dName, bool shouldReplaceCurrentEntry)); |
| 29 }; |
| 30 |
| 31 class LinkSelectionTest : public SelectionTestBase { |
| 32 protected: |
| 33 void SetUp() override |
| 34 { |
| 35 const char* const kHTMLString = |
| 36 "<a id='link' href='foo.com' style='font-size:20pt'>Text to select f
oobar</a>" |
| 37 "<div id='page_text'>Lorem ipsum dolor sit amet</div>"; |
| 38 |
| 39 // We need to set deviceSupportsMouse setting to true and page's focus c
ontroller to active |
| 40 // so that FrameView can set the mouse cursor. |
| 41 m_webView = m_helper.initialize(false, &m_testFrameClient, nullptr, |
| 42 [](WebSettings* settings) { settings->setDeviceSupportsMouse(true);
}); |
| 43 m_mainFrame = m_webView->mainFrameImpl(); |
| 44 FrameTestHelpers::loadHTMLString(m_mainFrame, kHTMLString, URLTestHelper
s::toKURL("http://foobar.com")); |
| 45 m_webView->resize(WebSize(800, 600)); |
| 46 m_webView->page()->focusController().setActive(true); |
| 47 |
| 48 auto* document = m_mainFrame->frame()->document(); |
| 49 ASSERT_NE(nullptr, document); |
| 50 auto* linkToSelect = document->getElementById("link")->firstChild(); |
| 51 ASSERT_NE(nullptr, linkToSelect); |
| 52 // We get larger range that we actually want to select, because we need
a slightly larger |
| 53 // rect to include the last character to the selection. |
| 54 const auto rangeToSelect = Range::create(*document, linkToSelect, 5, lin
kToSelect, 16); |
| 55 |
| 56 const auto& selectionRect = rangeToSelect->boundingBox(); |
| 57 const auto& selectionRectCenterY = selectionRect.center().y(); |
| 58 m_leftPointInLink = selectionRect.minXMinYCorner(); |
| 59 m_leftPointInLink.setY(selectionRectCenterY); |
| 60 |
| 61 m_rightPointInLink = selectionRect.maxXMinYCorner(); |
| 62 m_rightPointInLink.setY(selectionRectCenterY); |
| 63 m_rightPointInLink.move(-2, 0); |
| 64 } |
| 65 |
| 66 TestFrameClient m_testFrameClient; |
| 67 IntPoint m_leftPointInLink; |
| 68 IntPoint m_rightPointInLink; |
| 69 }; |
| 70 |
| 71 TEST_F(LinkSelectionTest, MouseDragWithoutAltAllowNoLinkSelection) |
| 72 { |
| 73 emulateMouseDrag(m_leftPointInLink, m_rightPointInLink, 0); |
| 74 EXPECT_EQ(std::string(), getSelectionText()); |
| 75 } |
| 76 |
| 77 TEST_F(LinkSelectionTest, MouseDragWithAltAllowSelection) |
| 78 { |
| 79 emulateMouseDrag(m_leftPointInLink, m_rightPointInLink, WebInputEvent::AltKe
y); |
| 80 EXPECT_EQ("to select", getSelectionText()); |
| 81 } |
| 82 |
| 83 TEST_F(LinkSelectionTest, HandCursorDuringLinkDrag) |
| 84 { |
| 85 emulateMouseDrag(m_rightPointInLink, m_leftPointInLink, 0, SendDownEvent); |
| 86 m_mainFrame->frame()->localFrameRoot()->eventHandler().scheduleCursorUpdate(
); |
| 87 testing::runDelayedTasks(50); |
| 88 const auto& cursor = m_mainFrame->frame()->chromeClient().lastSetCursorForTe
sting(); |
| 89 EXPECT_EQ(Cursor::Hand, cursor.getType()); |
| 90 } |
| 91 |
| 92 TEST_F(LinkSelectionTest, CaretCursorOverLinkDuringSelection) |
| 93 { |
| 94 emulateMouseDrag(m_rightPointInLink, m_leftPointInLink, WebInputEvent::AltKe
y, SendDownEvent); |
| 95 m_mainFrame->frame()->localFrameRoot()->eventHandler().scheduleCursorUpdate(
); |
| 96 testing::runDelayedTasks(50); |
| 97 const auto& cursor = m_mainFrame->frame()->chromeClient().lastSetCursorForTe
sting(); |
| 98 EXPECT_EQ(Cursor::IBeam, cursor.getType()); |
| 99 } |
| 100 |
| 101 TEST_F(LinkSelectionTest, HandCursorOverLinkAfterContextMenu) |
| 102 { |
| 103 // Move mouse. |
| 104 emulateMouseDrag(m_rightPointInLink, m_leftPointInLink, 0, 0); |
| 105 |
| 106 // Show context menu. We don't send mouseup event here since in browser it d
oesn't reach |
| 107 // blink because of shown context menu. |
| 108 emulateMouseDown(m_leftPointInLink, WebMouseEvent::ButtonRight, 0, 1); |
| 109 |
| 110 LocalFrame* frame = m_mainFrame->frame(); |
| 111 // Hide context menu. |
| 112 frame->page()->contextMenuController().clearContextMenu(); |
| 113 |
| 114 frame->localFrameRoot()->eventHandler().scheduleCursorUpdate(); |
| 115 testing::runDelayedTasks(50); |
| 116 const auto& cursor = m_mainFrame->frame()->chromeClient().lastSetCursorForTe
sting(); |
| 117 EXPECT_EQ(Cursor::Hand, cursor.getType()); |
| 118 } |
| 119 |
| 120 TEST_F(LinkSelectionTest, SingleClickWithAltStartsDownload) |
| 121 { |
| 122 EXPECT_CALL(m_testFrameClient, loadURLExternally(_, WebNavigationPolicy::Web
NavigationPolicyDownload, WebString(), _)); |
| 123 emulateMouseClick(m_leftPointInLink, WebMouseEvent::ButtonLeft, WebInputEven
t::AltKey); |
| 124 } |
| 125 |
| 126 TEST_F(LinkSelectionTest, SingleClickWithAltStartsDownloadWhenTextSelected) |
| 127 { |
| 128 auto* document = m_mainFrame->frame()->document(); |
| 129 auto* textToSelect = document->getElementById("page_text")->firstChild(); |
| 130 ASSERT_NE(nullptr, textToSelect); |
| 131 |
| 132 // Select some page text outside the link element. |
| 133 const RefPtrWillBeRawPtr<Range> rangeToSelect = Range::create(*document, tex
tToSelect, 1, textToSelect, 20); |
| 134 const auto& selectionRect = rangeToSelect->boundingBox(); |
| 135 m_mainFrame->moveRangeSelection(selectionRect.minXMinYCorner(), selectionRec
t.maxXMaxYCorner()); |
| 136 EXPECT_FALSE(getSelectionText().empty()); |
| 137 |
| 138 EXPECT_CALL(m_testFrameClient, loadURLExternally(_, WebNavigationPolicy::Web
NavigationPolicyDownload, WebString(), _)); |
| 139 emulateMouseClick(m_leftPointInLink, WebMouseEvent::ButtonLeft, WebInputEven
t::AltKey); |
| 140 } |
| 141 |
| 142 class LinkSelectionClickEventsTest : public SelectionTestBase { |
| 143 protected: |
| 144 class MockEventListener final : public EventListener { |
| 145 public: |
| 146 static PassRefPtrWillBeRawPtr<MockEventListener> create() |
| 147 { |
| 148 return adoptRefWillBeNoop(new MockEventListener()); |
| 149 } |
| 150 |
| 151 bool operator==(const EventListener& other) const final |
| 152 { |
| 153 return this == &other; |
| 154 } |
| 155 |
| 156 MOCK_METHOD2(handleEvent, void(ExecutionContext* executionContext, Event
*)); |
| 157 |
| 158 private: |
| 159 MockEventListener() : EventListener(CPPEventListenerType) |
| 160 { |
| 161 } |
| 162 }; |
| 163 |
| 164 void SetUp() override |
| 165 { |
| 166 const char* const kHTMLString = |
| 167 "<div id='empty_div' style='width: 100px; height: 100px;'></div>" |
| 168 "<span id='text_div'>Sometexttoshow</span>"; |
| 169 |
| 170 m_webView = m_helper.initialize(false); |
| 171 m_mainFrame = m_webView->mainFrameImpl(); |
| 172 FrameTestHelpers::loadHTMLString(m_mainFrame, kHTMLString, URLTestHelper
s::toKURL("http://foobar.com")); |
| 173 m_webView->resize(WebSize(800, 600)); |
| 174 m_webView->page()->focusController().setActive(true); |
| 175 |
| 176 auto* document = m_mainFrame->frame()->document(); |
| 177 ASSERT_NE(nullptr, document); |
| 178 |
| 179 auto* emptyDiv = document->getElementById("empty_div"); |
| 180 auto* textDiv = document->getElementById("text_div"); |
| 181 ASSERT_NE(nullptr, emptyDiv); |
| 182 ASSERT_NE(nullptr, textDiv); |
| 183 } |
| 184 |
| 185 void checkMouseClicks(Element& element, bool doubleClickEvent) |
| 186 { |
| 187 struct ScopedListenersCleaner { |
| 188 ScopedListenersCleaner(Element* element) : m_element(element) {} |
| 189 |
| 190 ~ScopedListenersCleaner() |
| 191 { |
| 192 m_element->removeAllEventListeners(); |
| 193 } |
| 194 |
| 195 RawPtrWillBePersistent<Element> m_element; |
| 196 } const listenersCleaner(&element); |
| 197 |
| 198 RefPtrWillBeRawPtr<MockEventListener> eventHandler = MockEventListener::
create(); |
| 199 element.addEventListener( |
| 200 doubleClickEvent ? EventTypeNames::dblclick : EventTypeNames::click, |
| 201 eventHandler); |
| 202 |
| 203 ::testing::InSequence s; |
| 204 EXPECT_CALL(*eventHandler, handleEvent(_, _)).Times(1); |
| 205 |
| 206 const auto& elemBounds = element.boundsInViewport(); |
| 207 const int clickCount = doubleClickEvent ? 2 : 1; |
| 208 emulateMouseClick(elemBounds.center(), WebMouseEvent::ButtonLeft, 0, cli
ckCount); |
| 209 |
| 210 if (doubleClickEvent) { |
| 211 EXPECT_EQ(element.innerText().isEmpty(), getSelectionText().empty())
; |
| 212 } |
| 213 } |
| 214 }; |
| 215 |
| 216 TEST_F(LinkSelectionClickEventsTest, SingleAndDoubleClickWillBeHandled) |
| 217 { |
| 218 auto* document = m_mainFrame->frame()->document(); |
| 219 auto* element = document->getElementById("empty_div"); |
| 220 |
| 221 { |
| 222 SCOPED_TRACE("Empty div, single click"); |
| 223 checkMouseClicks(*element, false); |
| 224 } |
| 225 |
| 226 { |
| 227 SCOPED_TRACE("Empty div, double click"); |
| 228 checkMouseClicks(*element, true); |
| 229 } |
| 230 |
| 231 element = document->getElementById("text_div"); |
| 232 |
| 233 { |
| 234 SCOPED_TRACE("Text div, single click"); |
| 235 checkMouseClicks(*element, false); |
| 236 } |
| 237 |
| 238 { |
| 239 SCOPED_TRACE("Text div, double click"); |
| 240 checkMouseClicks(*element, true); |
| 241 } |
| 242 } |
| 243 |
| 244 } // namespace blink |
OLD | NEW |