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

Unified 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, 9 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 side-by-side diff with in-line comments
Download patch
« 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 »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: third_party/WebKit/Source/web/tests/LinkSelectionTest.cpp
diff --git a/third_party/WebKit/Source/web/tests/LinkSelectionTest.cpp b/third_party/WebKit/Source/web/tests/LinkSelectionTest.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..28a8b4bc96b18cbe894883de24b931342e59cd29
--- /dev/null
+++ b/third_party/WebKit/Source/web/tests/LinkSelectionTest.cpp
@@ -0,0 +1,314 @@
+// Copyright (c) 2016 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 "core/dom/Range.h"
+#include "core/frame/FrameView.h"
+#include "core/input/EventHandler.h"
+#include "core/page/ChromeClient.h"
+#include "core/page/ContextMenuController.h"
+#include "core/page/FocusController.h"
+#include "core/page/Page.h"
+#include "platform/Cursor.h"
+#include "platform/testing/URLTestHelpers.h"
+#include "platform/testing/UnitTestHelpers.h"
+#include "public/web/WebSettings.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "web/WebLocalFrameImpl.h"
+#include "web/tests/FrameTestHelpers.h"
+
+using ::testing::_;
+
+namespace blink {
+
+IntSize scaled(IntSize p, float scale)
+{
+ p.scale(scale, scale);
+ return p;
+}
+
+class LinkSelectionTestBase : public ::testing::Test {
+protected:
+ enum DragFlag {
+ SendDownEvent = 1,
+ SendUpEvent = 1 << 1
+ };
+ using DragFlags = unsigned;
+
+ void emulateMouseDrag(const IntPoint& downPoint, const IntPoint& upPoint, int modifiers,
+ DragFlags = SendDownEvent | SendUpEvent);
+
+ void emulateMouseClick(const IntPoint& clickPoint, WebMouseEvent::Button, int modifiers, int count = 1);
+ void emulateMouseDown(const IntPoint& clickPoint, WebMouseEvent::Button, int modifiers, int count = 1);
+
+ String getSelectionText();
+
+ FrameTestHelpers::WebViewHelper m_helper;
+ WebViewImpl* m_webView = nullptr;
+ RawPtrWillBePersistent<WebLocalFrameImpl> m_mainFrame = nullptr;
+};
+
+void LinkSelectionTestBase::emulateMouseDrag(const IntPoint& downPoint, const IntPoint& upPoint, int modifiers, DragFlags dragFlags)
+{
+ if (dragFlags & SendDownEvent) {
+ const auto& downEvent = FrameTestHelpers::createMouseEvent(WebMouseEvent::MouseDown, WebMouseEvent::ButtonLeft, downPoint, modifiers);
+ m_webView->handleInputEvent(downEvent);
+ }
+
+ const int kMoveEventsNumber = 10;
+ const float kMoveIncrementFraction = 1. / kMoveEventsNumber;
+ const auto& upDownVector = upPoint - downPoint;
+ for (int i = 0; i < kMoveEventsNumber; ++i) {
+ const auto& movePoint = downPoint + scaled(upDownVector, i * kMoveIncrementFraction);
+ const auto& moveEvent = FrameTestHelpers::createMouseEvent(WebMouseEvent::MouseMove, WebMouseEvent::ButtonLeft, movePoint, modifiers);
+ m_webView->handleInputEvent(moveEvent);
+ }
+
+ if (dragFlags & SendUpEvent) {
+ const auto& upEvent = FrameTestHelpers::createMouseEvent(WebMouseEvent::MouseUp, WebMouseEvent::ButtonLeft, upPoint, modifiers);
+ m_webView->handleInputEvent(upEvent);
+ }
+}
+
+void LinkSelectionTestBase::emulateMouseClick(const IntPoint& clickPoint, WebMouseEvent::Button button, int modifiers, int count)
+{
+ auto event = FrameTestHelpers::createMouseEvent(WebMouseEvent::MouseDown, button, clickPoint, modifiers);
+ event.clickCount = count;
+ m_webView->handleInputEvent(event);
+ event.type = WebMouseEvent::MouseUp;
+ m_webView->handleInputEvent(event);
+}
+
+void LinkSelectionTestBase::emulateMouseDown(const IntPoint& clickPoint, WebMouseEvent::Button button, int modifiers, int count)
+{
+ auto event = FrameTestHelpers::createMouseEvent(WebMouseEvent::MouseDown, button, clickPoint, modifiers);
+ event.clickCount = count;
+ m_webView->handleInputEvent(event);
+}
+
+String LinkSelectionTestBase::getSelectionText()
+{
+ return m_mainFrame->selectionAsText();
+}
+
+class TestFrameClient : public FrameTestHelpers::TestWebFrameClient {
+public:
+ MOCK_METHOD4(loadURLExternally,
+ void(const WebURLRequest&, WebNavigationPolicy, const WebString& downloadName, bool shouldReplaceCurrentEntry));
+};
+
+class LinkSelectionTest : public LinkSelectionTestBase {
+protected:
+ void SetUp() override
+ {
+ const char* const kHTMLString =
+ "<a id='link' href='foo.com' style='font-size:20pt'>Text to select foobar</a>"
+ "<div id='page_text'>Lorem ipsum dolor sit amet</div>";
+
+ // We need to set deviceSupportsMouse setting to true and page's focus controller to active
+ // so that FrameView can set the mouse cursor.
+ m_webView = m_helper.initialize(false, &m_testFrameClient, nullptr,
+ [](WebSettings* settings) { settings->setDeviceSupportsMouse(true); });
+ m_mainFrame = m_webView->mainFrameImpl();
+ FrameTestHelpers::loadHTMLString(m_mainFrame, kHTMLString, URLTestHelpers::toKURL("http://foobar.com"));
+ m_webView->resize(WebSize(800, 600));
+ m_webView->page()->focusController().setActive(true);
+
+ auto* document = m_mainFrame->frame()->document();
+ ASSERT_NE(nullptr, document);
+ auto* linkToSelect = document->getElementById("link")->firstChild();
+ ASSERT_NE(nullptr, linkToSelect);
+ // We get larger range that we actually want to select, because we need a slightly larger
+ // rect to include the last character to the selection.
+ const auto rangeToSelect = Range::create(*document, linkToSelect, 5, linkToSelect, 16);
+
+ const auto& selectionRect = rangeToSelect->boundingBox();
+ const auto& selectionRectCenterY = selectionRect.center().y();
+ m_leftPointInLink = selectionRect.minXMinYCorner();
+ m_leftPointInLink.setY(selectionRectCenterY);
+
+ m_rightPointInLink = selectionRect.maxXMinYCorner();
+ m_rightPointInLink.setY(selectionRectCenterY);
+ m_rightPointInLink.move(-2, 0);
+ }
+
+ TestFrameClient m_testFrameClient;
+ IntPoint m_leftPointInLink;
+ IntPoint m_rightPointInLink;
+};
+
+TEST_F(LinkSelectionTest, MouseDragWithoutAltAllowNoLinkSelection)
+{
+ emulateMouseDrag(m_leftPointInLink, m_rightPointInLink, 0);
+ EXPECT_TRUE(getSelectionText().isEmpty());
+}
+
+TEST_F(LinkSelectionTest, MouseDragWithAltAllowSelection)
+{
+ emulateMouseDrag(m_leftPointInLink, m_rightPointInLink, WebInputEvent::AltKey);
+ EXPECT_EQ("to select", getSelectionText());
+}
+
+TEST_F(LinkSelectionTest, HandCursorDuringLinkDrag)
+{
+ emulateMouseDrag(m_rightPointInLink, m_leftPointInLink, 0, SendDownEvent);
+ m_mainFrame->frame()->localFrameRoot()->eventHandler().scheduleCursorUpdate();
+ testing::runDelayedTasks(50);
+ const auto& cursor = m_mainFrame->frame()->chromeClient().lastSetCursorForTesting();
+ EXPECT_EQ(Cursor::Hand, cursor.getType());
+}
+
+TEST_F(LinkSelectionTest, CaretCursorOverLinkDuringSelection)
+{
+ emulateMouseDrag(m_rightPointInLink, m_leftPointInLink, WebInputEvent::AltKey, SendDownEvent);
+ m_mainFrame->frame()->localFrameRoot()->eventHandler().scheduleCursorUpdate();
+ testing::runDelayedTasks(50);
+ const auto& cursor = m_mainFrame->frame()->chromeClient().lastSetCursorForTesting();
+ EXPECT_EQ(Cursor::IBeam, cursor.getType());
+}
+
+TEST_F(LinkSelectionTest, HandCursorOverLinkAfterContextMenu)
+{
+ // Move mouse.
+ emulateMouseDrag(m_rightPointInLink, m_leftPointInLink, 0, 0);
+
+ // Show context menu. We don't send mouseup event here since in browser it doesn't reach
+ // blink because of shown context menu.
+ emulateMouseDown(m_leftPointInLink, WebMouseEvent::ButtonRight, 0, 1);
+
+ LocalFrame* frame = m_mainFrame->frame();
+ // Hide context menu.
+ frame->page()->contextMenuController().clearContextMenu();
+
+ frame->localFrameRoot()->eventHandler().scheduleCursorUpdate();
+ testing::runDelayedTasks(50);
+ const auto& cursor = m_mainFrame->frame()->chromeClient().lastSetCursorForTesting();
+ EXPECT_EQ(Cursor::Hand, cursor.getType());
+}
+
+TEST_F(LinkSelectionTest, SingleClickWithAltStartsDownload)
+{
+ EXPECT_CALL(m_testFrameClient, loadURLExternally(_, WebNavigationPolicy::WebNavigationPolicyDownload, WebString(), _));
+ emulateMouseClick(m_leftPointInLink, WebMouseEvent::ButtonLeft, WebInputEvent::AltKey);
+}
+
+TEST_F(LinkSelectionTest, SingleClickWithAltStartsDownloadWhenTextSelected)
+{
+ auto* document = m_mainFrame->frame()->document();
+ auto* textToSelect = document->getElementById("page_text")->firstChild();
+ ASSERT_NE(nullptr, textToSelect);
+
+ // Select some page text outside the link element.
+ const RefPtrWillBeRawPtr<Range> rangeToSelect = Range::create(*document, textToSelect, 1, textToSelect, 20);
+ const auto& selectionRect = rangeToSelect->boundingBox();
+ m_mainFrame->moveRangeSelection(selectionRect.minXMinYCorner(), selectionRect.maxXMaxYCorner());
+ EXPECT_FALSE(getSelectionText().isEmpty());
+
+ EXPECT_CALL(m_testFrameClient, loadURLExternally(_, WebNavigationPolicy::WebNavigationPolicyDownload, WebString(), _));
+ emulateMouseClick(m_leftPointInLink, WebMouseEvent::ButtonLeft, WebInputEvent::AltKey);
+}
+
+class LinkSelectionClickEventsTest : public LinkSelectionTestBase {
+protected:
+ class MockEventListener final : public EventListener {
+ public:
+ static PassRefPtrWillBeRawPtr<MockEventListener> create()
+ {
+ return adoptRefWillBeNoop(new MockEventListener());
+ }
+
+ bool operator==(const EventListener& other) const final
+ {
+ return this == &other;
+ }
+
+ MOCK_METHOD2(handleEvent, void(ExecutionContext* executionContext, Event*));
+
+ private:
+ MockEventListener() : EventListener(CPPEventListenerType)
+ {
+ }
+ };
+
+ void SetUp() override
+ {
+ const char* const kHTMLString =
+ "<div id='empty_div' style='width: 100px; height: 100px;'></div>"
+ "<span id='text_div'>Sometexttoshow</span>";
+
+ m_webView = m_helper.initialize(false);
+ m_mainFrame = m_webView->mainFrameImpl();
+ FrameTestHelpers::loadHTMLString(m_mainFrame, kHTMLString, URLTestHelpers::toKURL("http://foobar.com"));
+ m_webView->resize(WebSize(800, 600));
+ m_webView->page()->focusController().setActive(true);
+
+ auto* document = m_mainFrame->frame()->document();
+ ASSERT_NE(nullptr, document);
+
+ auto* emptyDiv = document->getElementById("empty_div");
+ auto* textDiv = document->getElementById("text_div");
+ ASSERT_NE(nullptr, emptyDiv);
+ ASSERT_NE(nullptr, textDiv);
+ }
+
+ void checkMouseClicks(Element& element, bool doubleClickEvent)
+ {
+ struct ScopedListenersCleaner {
+ ScopedListenersCleaner(Element* element) : m_element(element) {}
+
+ ~ScopedListenersCleaner()
+ {
+ m_element->removeAllEventListeners();
+ }
+
+ RawPtrWillBePersistent<Element> m_element;
+ } const listenersCleaner(&element);
+
+ RefPtrWillBeRawPtr<MockEventListener> eventHandler = MockEventListener::create();
+ element.addEventListener(
+ doubleClickEvent ? EventTypeNames::dblclick : EventTypeNames::click,
+ eventHandler);
+
+ ::testing::InSequence s;
+ EXPECT_CALL(*eventHandler, handleEvent(_, _)).Times(1);
+
+ const auto& elemBounds = element.boundsInViewport();
+ const int clickCount = doubleClickEvent ? 2 : 1;
+ emulateMouseClick(elemBounds.center(), WebMouseEvent::ButtonLeft, 0, clickCount);
+
+ if (doubleClickEvent) {
+ EXPECT_EQ(element.innerText().isEmpty(), getSelectionText().isEmpty());
+ }
+ }
+};
+
+TEST_F(LinkSelectionClickEventsTest, SingleAndDoubleClickWillBeHandled)
+{
+ auto* document = m_mainFrame->frame()->document();
+ auto* element = document->getElementById("empty_div");
+
+ {
+ SCOPED_TRACE("Empty div, single click");
+ checkMouseClicks(*element, false);
+ }
+
+ {
+ SCOPED_TRACE("Empty div, double click");
+ checkMouseClicks(*element, true);
+ }
+
+ element = document->getElementById("text_div");
+
+ {
+ SCOPED_TRACE("Text div, single click");
+ checkMouseClicks(*element, false);
+ }
+
+ {
+ SCOPED_TRACE("Text div, double click");
+ checkMouseClicks(*element, true);
+ }
+}
+
+} // namespace blink
« 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