Chromium Code Reviews| Index: content/browser/web_contents/web_contents_view_aura_browsertest.cc |
| diff --git a/content/browser/web_contents/web_contents_view_aura_browsertest.cc b/content/browser/web_contents/web_contents_view_aura_browsertest.cc |
| index bdd74817ddb5f5525b0e86487c98f4710a2e3474..f7a8f615bd114fa9f07d68b3cb0c6d0c7e97d23e 100644 |
| --- a/content/browser/web_contents/web_contents_view_aura_browsertest.cc |
| +++ b/content/browser/web_contents/web_contents_view_aura_browsertest.cc |
| @@ -18,7 +18,10 @@ |
| #include "content/browser/renderer_host/render_widget_host_view_aura.h" |
| #include "content/browser/web_contents/web_contents_impl.h" |
| #include "content/browser/web_contents/web_contents_view.h" |
| +#include "content/common/input/synthetic_web_input_event_builders.h" |
| +#include "content/common/input_messages.h" |
| #include "content/common/view_messages.h" |
| +#include "content/public/browser/browser_message_filter.h" |
| #include "content/public/browser/render_frame_host.h" |
| #include "content/public/browser/web_contents_observer.h" |
| #include "content/public/common/content_switches.h" |
| @@ -32,9 +35,24 @@ |
| #include "ui/aura/window_tree_host.h" |
| #include "ui/compositor/scoped_animation_duration_scale_mode.h" |
| #include "ui/events/event_processor.h" |
| +#include "ui/events/event_switches.h" |
| #include "ui/events/event_utils.h" |
| #include "ui/events/test/event_generator.h" |
| +namespace { |
| + |
| +void GiveItSomeTime() { |
| + base::RunLoop run_loop; |
| + base::MessageLoop::current()->PostDelayedTask( |
| + FROM_HERE, |
| + run_loop.QuitClosure(), |
| + base::TimeDelta::FromMillisecondsD(0.001)); |
|
tdresser
2014/08/15 23:10:32
0.001ms is obviously a terrible value, I'm only us
|
| + run_loop.Run(); |
| +} |
| + |
| +} //namespace |
| + |
| + |
| namespace content { |
| // This class keeps track of the RenderViewHost whose screenshot was captured. |
| @@ -127,6 +145,55 @@ class NavigationWatcher : public WebContentsObserver { |
| DISALLOW_COPY_AND_ASSIGN(NavigationWatcher); |
| }; |
| +class InputEventMessageFilterWaitsForAcks : public BrowserMessageFilter { |
| + public: |
| + InputEventMessageFilterWaitsForAcks() |
| + : BrowserMessageFilter(InputMsgStart), |
| + type_(blink::WebInputEvent::Undefined), |
| + state_(INPUT_EVENT_ACK_STATE_UNKNOWN) {} |
| + |
| + void WaitForAck(blink::WebInputEvent::Type type) { |
| + base::RunLoop run_loop; |
| + base::AutoReset<base::Closure> reset_quit(&quit_, run_loop.QuitClosure()); |
| + base::AutoReset<blink::WebInputEvent::Type> reset_type(&type_, type); |
| + run_loop.Run(); |
| + } |
| + |
| + InputEventAckState last_ack_state() const { return state_; } |
| + |
| + protected: |
| + virtual ~InputEventMessageFilterWaitsForAcks() {} |
| + |
| + private: |
| + void ReceivedEventAck(blink::WebInputEvent::Type type, |
| + InputEventAckState state) { |
| + if (type_ == type) { |
| + state_ = state; |
| + quit_.Run(); |
| + } |
| + } |
| + |
| + // BrowserMessageFilter: |
| + virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE { |
| + if (message.type() == InputHostMsg_HandleInputEvent_ACK::ID) { |
| + InputHostMsg_HandleInputEvent_ACK::Param params; |
| + InputHostMsg_HandleInputEvent_ACK::Read(&message, ¶ms); |
| + blink::WebInputEvent::Type type = params.a.type; |
| + InputEventAckState ack = params.a.state; |
| + BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, |
| + base::Bind(&InputEventMessageFilterWaitsForAcks::ReceivedEventAck, |
| + this, type, ack)); |
| + } |
| + return false; |
| + } |
| + |
| + base::Closure quit_; |
| + blink::WebInputEvent::Type type_; |
| + InputEventAckState state_; |
| + |
| + DISALLOW_COPY_AND_ASSIGN(InputEventMessageFilterWaitsForAcks); |
| +}; |
| + |
| class WebContentsViewAuraTest : public ContentBrowserTest { |
| public: |
| WebContentsViewAuraTest() |
| @@ -156,6 +223,11 @@ class WebContentsViewAuraTest : public ContentBrowserTest { |
| controller->SetScreenshotManager(screenshot_manager_); |
| } |
| + virtual void SetUpCommandLine(CommandLine* cmd) OVERRIDE { |
| + cmd->AppendSwitchASCII(switches::kTouchEvents, |
| + switches::kTouchEventsEnabled); |
| + } |
| + |
| void TestOverscrollNavigation(bool touch_handler) { |
| ASSERT_NO_FATAL_FAILURE( |
| StartTestWithPage("files/overscroll_navigation.html")); |
| @@ -256,14 +328,62 @@ class WebContentsViewAuraTest : public ContentBrowserTest { |
| return index; |
| } |
| + int ExecuteScriptAndExtractInt(const std::string& script) { |
| + int value = 0; |
| + EXPECT_TRUE(content::ExecuteScriptAndExtractInt( |
| + shell()->web_contents(), |
| + "domAutomationController.send(" + script + ")", |
| + &value)); |
| + return value; |
| + } |
| + |
| + RenderViewHost* GetRenderViewHost() const { |
| + RenderViewHost* const rvh = shell()->web_contents()->GetRenderViewHost(); |
| + CHECK(rvh); |
| + return rvh; |
| + } |
| + |
| + RenderWidgetHostImpl* GetRenderWidgetHost() const { |
| + RenderWidgetHostImpl* const rwh = |
| + RenderWidgetHostImpl::From(shell() |
| + ->web_contents() |
| + ->GetRenderWidgetHostView() |
| + ->GetRenderWidgetHost()); |
| + CHECK(rwh); |
| + return rwh; |
| + } |
| + |
| + RenderWidgetHostViewBase* GetRenderWidgetHostView() const { |
| + return static_cast<RenderWidgetHostViewBase*>( |
| + GetRenderViewHost()->GetView()); |
| + } |
| + |
| + InputEventMessageFilterWaitsForAcks* filter() { |
| + return filter_.get(); |
| + } |
| + |
| + void WaitAFrame() { |
| + uint32 frame = GetRenderWidgetHostView()->RendererFrameNumber(); |
| + while (!GetRenderWidgetHost()->ScheduleComposite()) |
| + GiveItSomeTime(); |
| + while (GetRenderWidgetHostView()->RendererFrameNumber() == frame) |
| + GiveItSomeTime(); |
| + } |
| + |
| protected: |
| ScreenshotTracker* screenshot_manager() { return screenshot_manager_; } |
| void set_min_screenshot_interval(int interval_ms) { |
| screenshot_manager_->SetScreenshotInterval(interval_ms); |
| } |
| + void AddInputEventMessageFilter() { |
| + filter_ = new InputEventMessageFilterWaitsForAcks(); |
| + GetRenderWidgetHost()->GetProcess()->AddFilter(filter_); |
| + } |
| + |
| private: |
| ScreenshotTracker* screenshot_manager_; |
| + scoped_refptr<InputEventMessageFilterWaitsForAcks> filter_; |
| DISALLOW_COPY_AND_ASSIGN(WebContentsViewAuraTest); |
| }; |
| @@ -747,4 +867,90 @@ IN_PROC_BROWSER_TEST_F(WebContentsViewAuraTest, WebContentsViewReparent) { |
| EXPECT_TRUE(rwhva->has_snapped_to_boundary()); |
| } |
| +// Tests that touch moves are not throttled when performing a scroll gesture on |
| +// a non-scrollable area, except during gesture-nav. |
| +IN_PROC_BROWSER_TEST_F(WebContentsViewAuraTest, |
| + OverscrollNavigationTouchThrottling) { |
| + ASSERT_NO_FATAL_FAILURE( |
| + StartTestWithPage("files/overscroll_navigation.html")); |
| + |
| + AddInputEventMessageFilter(); |
| + |
| + WebContentsImpl* web_contents = |
| + static_cast<WebContentsImpl*>(shell()->web_contents()); |
| + aura::Window* content = web_contents->GetContentNativeView(); |
| + gfx::Rect bounds = content->GetBoundsInRootWindow(); |
| + const int dx = 20; |
| + |
| + ExecuteSyncJSFunction(web_contents->GetMainFrame(), |
| + "install_touchmove_handler()"); |
| + |
| + WaitAFrame(); |
|
tdresser
2014/08/15 23:10:32
Dana, these WaitAFrame() calls are obviously terri
|
| + |
| + for (int navigated = 0; navigated <= 1; ++navigated) { |
| + if (navigated) { |
| + ExecuteSyncJSFunction(web_contents->GetMainFrame(), "navigate_next()"); |
| + ExecuteSyncJSFunction(web_contents->GetMainFrame(), |
| + "reset_touchmove_count()"); |
| + } |
| + // Send touch press. |
| + SyntheticWebTouchEvent touch; |
| + touch.PressPoint(bounds.x() + 2, bounds.y() + 10); |
| + GetRenderWidgetHost()->ForwardTouchEventWithLatencyInfo(touch, |
| + ui::LatencyInfo()); |
| + filter()->WaitForAck(blink::WebInputEvent::TouchStart); |
| + // Assert on the ack, because we'll end up waiting for acks that will never |
| + // come if this is not true. |
| + ASSERT_EQ(INPUT_EVENT_ACK_STATE_NOT_CONSUMED, filter()->last_ack_state()); |
| + |
| + // Send first touch move, and then a scroll begin. |
| + touch.MovePoint(0, bounds.x() + 20 + 1 * dx, bounds.y() + 100); |
| + GetRenderWidgetHost()->ForwardTouchEventWithLatencyInfo(touch, |
| + ui::LatencyInfo()); |
| + filter()->WaitForAck(blink::WebInputEvent::TouchMove); |
| + ASSERT_EQ(INPUT_EVENT_ACK_STATE_NOT_CONSUMED, filter()->last_ack_state()); |
| + |
| + blink::WebGestureEvent scroll_begin = |
| + SyntheticWebGestureEventBuilder::BuildScrollBegin(1, 1); |
| + GetRenderWidgetHost()->ForwardGestureEventWithLatencyInfo( |
| + scroll_begin, ui::LatencyInfo()); |
| + // Scroll begin ignores ack disposition, so don't wait for the ack. |
| + // GiveItSomeTime(); |
| + WaitAFrame(); |
| + |
| + // First touchmove already sent, start at 2. |
| + for (int i = 2; i <= 10; ++i) { |
| + // Send a touch move, followed by a scroll update |
| + touch.MovePoint(0, bounds.x() + 20 + i * dx, bounds.y() + 100); |
| + GetRenderWidgetHost()->ForwardTouchEventWithLatencyInfo( |
| + touch, ui::LatencyInfo()); |
| + WaitAFrame(); |
| + |
| + blink::WebGestureEvent scroll_update = |
| + SyntheticWebGestureEventBuilder::BuildScrollUpdate(dx, 5, 0); |
| + |
| + GetRenderWidgetHost()->ForwardGestureEventWithLatencyInfo( |
| + scroll_update, ui::LatencyInfo()); |
| + |
| + WaitAFrame(); |
| + } |
| + |
| + touch.ReleasePoint(0); |
| + GetRenderWidgetHost()->ForwardTouchEventWithLatencyInfo(touch, |
| + ui::LatencyInfo()); |
| + WaitAFrame(); |
| + |
| + blink::WebGestureEvent scroll_end; |
| + scroll_end.type = blink::WebInputEvent::GestureScrollEnd; |
| + GetRenderWidgetHost()->ForwardGestureEventWithLatencyInfo( |
| + scroll_end, ui::LatencyInfo()); |
| + WaitAFrame(); |
| + |
| + if (!navigated) |
| + EXPECT_EQ(10, ExecuteScriptAndExtractInt("touchmoveCount")); |
| + else |
| + EXPECT_GT(10, ExecuteScriptAndExtractInt("touchmoveCount")); |
| + } |
| +} |
| + |
| } // namespace content |