// Copyright 2014 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 "base/auto_reset.h" #include "base/bind.h" #include "base/command_line.h" #include "base/run_loop.h" #include "base/strings/utf_string_conversions.h" #include "content/browser/renderer_host/input/synthetic_gesture.h" #include "content/browser/renderer_host/input/synthetic_gesture_controller.h" #include "content/browser/renderer_host/input/synthetic_gesture_target.h" #include "content/browser/renderer_host/input/synthetic_smooth_scroll_gesture.h" #include "content/browser/renderer_host/input/touch_event_queue.h" #include "content/browser/renderer_host/render_widget_host_impl.h" #include "content/browser/renderer_host/render_widget_host_view_base.h" #include "content/browser/web_contents/web_contents_impl.h" #include "content/common/input/synthetic_gesture_params.h" #include "content/common/input/synthetic_smooth_scroll_gesture_params.h" #include "content/common/input_messages.h" #include "content/public/browser/render_view_host.h" #include "content/public/browser/render_widget_host_view.h" #include "content/public/common/content_switches.h" #include "content/public/test/browser_test_utils.h" #include "content/public/test/content_browser_test.h" #include "content/public/test/content_browser_test_utils.h" #include "content/public/test/test_utils.h" #include "content/shell/browser/shell.h" #include "third_party/WebKit/public/web/WebInputEvent.h" #include "ui/events/event_switches.h" #include "ui/events/latency_info.h" using blink::WebInputEvent; namespace { const char kTouchActionDataURL[] = "data:text/html;charset=utf-8," "" "" "" "
" "
" "
" ""; } // namespace namespace content { class TouchActionBrowserTest : public ContentBrowserTest { public: TouchActionBrowserTest() {} ~TouchActionBrowserTest() override {} RenderWidgetHostImpl* GetWidgetHost() { return RenderWidgetHostImpl::From(shell()->web_contents()-> GetRenderViewHost()); } void OnSyntheticGestureCompleted(SyntheticGesture::Result result) { EXPECT_EQ(SyntheticGesture::GESTURE_FINISHED, result); runner_->Quit(); } protected: void LoadURL() { const GURL data_url(kTouchActionDataURL); NavigateToURL(shell(), data_url); RenderWidgetHostImpl* host = GetWidgetHost(); host->GetView()->SetSize(gfx::Size(400, 400)); base::string16 ready_title(base::ASCIIToUTF16("ready")); TitleWatcher watcher(shell()->web_contents(), ready_title); ignore_result(watcher.WaitAndGetTitle()); } // ContentBrowserTest: void SetUpCommandLine(base::CommandLine* cmd) override { cmd->AppendSwitchASCII(switches::kTouchEvents, switches::kTouchEventsEnabled); // TODO(rbyers): Remove this switch once touch-action ships. // http://crbug.com/241964 cmd->AppendSwitch(switches::kEnableExperimentalWebPlatformFeatures); } int ExecuteScriptAndExtractInt(const std::string& script) { int value = 0; EXPECT_TRUE(content::ExecuteScriptAndExtractInt( shell()->web_contents(), "domAutomationController.send(" + script + ")", &value)); return value; } int GetScrollTop() { return ExecuteScriptAndExtractInt("document.documentElement.scrollTop"); } // Generate touch events for a synthetic scroll from |point| for |distance|. // Returns true if the page scrolled by the desired amount, and false if // it didn't scroll at all. bool DoTouchScroll(const gfx::Point& point, const gfx::Vector2d& distance) { EXPECT_EQ(0, GetScrollTop()); int scrollHeight = ExecuteScriptAndExtractInt( "document.documentElement.scrollHeight"); EXPECT_EQ(1200, scrollHeight); SyntheticSmoothScrollGestureParams params; params.gesture_source_type = SyntheticGestureParams::TOUCH_INPUT; params.anchor = point; params.distances.push_back(-distance); runner_ = new MessageLoopRunner(); scoped_ptr gesture( new SyntheticSmoothScrollGesture(params)); GetWidgetHost()->QueueSyntheticGesture( gesture.Pass(), base::Bind(&TouchActionBrowserTest::OnSyntheticGestureCompleted, base::Unretained(this))); // Runs until we get the OnSyntheticGestureCompleted callback runner_->Run(); runner_ = NULL; // Check the scroll offset int scrollTop = GetScrollTop(); if (scrollTop == 0) return false; EXPECT_EQ(distance.y(), scrollTop); return true; } private: scoped_refptr runner_; DISALLOW_COPY_AND_ASSIGN(TouchActionBrowserTest); }; // TouchActionBrowserTest.DefaultAuto fails under ThreadSanitizer v2, see // http://crbug.com/348539 and is flaky on XP, see // http://crbug.com/354763 // // Mac doesn't yet have a gesture recognizer, so can't support turning touch // events into scroll gestures. // Will be fixed with http://crbug.com/337142 // // Verify the test infrastructure works - we can touch-scroll the page and get a // touchcancel as expected. IN_PROC_BROWSER_TEST_F(TouchActionBrowserTest, DISABLED_DefaultAuto) { LoadURL(); bool scrolled = DoTouchScroll(gfx::Point(50, 50), gfx::Vector2d(0, 45)); EXPECT_TRUE(scrolled); EXPECT_EQ(1, ExecuteScriptAndExtractInt("eventCounts.touchstart")); EXPECT_EQ(1, ExecuteScriptAndExtractInt("eventCounts.touchmove")); EXPECT_EQ(1, ExecuteScriptAndExtractInt("eventCounts.touchend")); EXPECT_EQ(0, ExecuteScriptAndExtractInt("eventCounts.touchcancel")); } // Verify that touching a touch-action: none region disables scrolling and // enables all touch events to be sent. // Disabled on MacOS because it doesn't support touch input. // It's just flaky everywhere. IN_PROC_BROWSER_TEST_F(TouchActionBrowserTest, DISABLED_TouchActionNone) { LoadURL(); bool scrolled = DoTouchScroll(gfx::Point(50, 150), gfx::Vector2d(0, 45)); EXPECT_FALSE(scrolled); EXPECT_EQ(1, ExecuteScriptAndExtractInt("eventCounts.touchstart")); EXPECT_GT(ExecuteScriptAndExtractInt("eventCounts.touchmove"), 1); EXPECT_EQ(1, ExecuteScriptAndExtractInt("eventCounts.touchend")); EXPECT_EQ(0, ExecuteScriptAndExtractInt("eventCounts.touchcancel")); } } // namespace content