Mac: Add rails for scrolling.
Add a MouseWheelRailsFilter structure to compute the rail mode for
input events, based on some simple hysteresis.
Make InputHandlerProxy honor the rails requests of MouseWheel events.
This is not an ideal long-term implementation -- the rails should be
passed to cc::InputHandler, so that they can be handled correctly by
other event types. This version is being used so that it may be merged.
BUG=468454
Review URL: https://codereview.chromium.org/1019153002
Cr-Commit-Position: refs/heads/master@{#321738}
diff --git a/content/browser/renderer_host/input/mouse_wheel_rails_filter_mac.cc b/content/browser/renderer_host/input/mouse_wheel_rails_filter_mac.cc
new file mode 100644
index 0000000..3681ba9
--- /dev/null
+++ b/content/browser/renderer_host/input/mouse_wheel_rails_filter_mac.cc
@@ -0,0 +1,38 @@
+// Copyright 2015 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 "content/browser/renderer_host/input/mouse_wheel_rails_filter_mac.h"
+
+using blink::WebInputEvent;
+using blink::WebMouseWheelEvent;
+
+namespace content {
+
+MouseWheelRailsFilterMac::MouseWheelRailsFilterMac() {
+}
+
+MouseWheelRailsFilterMac::~MouseWheelRailsFilterMac() {
+}
+
+WebInputEvent::RailsMode MouseWheelRailsFilterMac::UpdateRailsMode(
+ const WebMouseWheelEvent& event) {
+ // A somewhat-arbitrary decay constant for hysteresis.
+ const float kDecayConstant = 0.8f;
+
+ if (event.phase == WebMouseWheelEvent::PhaseBegan) {
+ decayed_delta_ = gfx::Vector2dF();
+ }
+ if (event.deltaX == 0 && event.deltaY == 0)
+ return WebInputEvent::RailsModeFree;
+
+ decayed_delta_.Scale(kDecayConstant);
+ decayed_delta_ +=
+ gfx::Vector2dF(std::abs(event.deltaX), std::abs(event.deltaY));
+
+ if (decayed_delta_.y() >= decayed_delta_.x())
+ return WebInputEvent::RailsModeVertical;
+ return WebInputEvent::RailsModeHorizontal;
+}
+
+} // namespace content
diff --git a/content/browser/renderer_host/input/mouse_wheel_rails_filter_mac.h b/content/browser/renderer_host/input/mouse_wheel_rails_filter_mac.h
new file mode 100644
index 0000000..ffed162c9
--- /dev/null
+++ b/content/browser/renderer_host/input/mouse_wheel_rails_filter_mac.h
@@ -0,0 +1,27 @@
+// Copyright 2015 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.
+
+#ifndef CONTENT_BROWSER_RENDERER_HOST_INPUT_MOUSE_WHEEL_RAILS_FILTER_MAC_H_
+#define CONTENT_BROWSER_RENDERER_HOST_INPUT_MOUSE_WHEEL_RAILS_FILTER_MAC_H_
+
+#include "content/common/content_export.h"
+#include "third_party/WebKit/public/web/WebInputEvent.h"
+#include "ui/gfx/geometry/vector2d_f.h"
+
+namespace content {
+
+class CONTENT_EXPORT MouseWheelRailsFilterMac {
+ public:
+ MouseWheelRailsFilterMac();
+ ~MouseWheelRailsFilterMac();
+ blink::WebInputEvent::RailsMode UpdateRailsMode(
+ const blink::WebMouseWheelEvent& event);
+
+ private:
+ gfx::Vector2dF decayed_delta_;
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_RENDERER_HOST_INPUT_MOUSE_WHEEL_RAILS_FILTER_MAC_H_
diff --git a/content/browser/renderer_host/input/mouse_wheel_rails_filter_unittest_mac.cc b/content/browser/renderer_host/input/mouse_wheel_rails_filter_unittest_mac.cc
new file mode 100644
index 0000000..7811ef7
--- /dev/null
+++ b/content/browser/renderer_host/input/mouse_wheel_rails_filter_unittest_mac.cc
@@ -0,0 +1,64 @@
+// Copyright 2015 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 "content/browser/renderer_host/input/mouse_wheel_rails_filter_mac.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using blink::WebInputEvent;
+using blink::WebMouseWheelEvent;
+
+namespace content {
+namespace {
+
+WebMouseWheelEvent MakeEvent(WebMouseWheelEvent::Phase phase,
+ float delta_x,
+ float delta_y) {
+ WebMouseWheelEvent event;
+ event.phase = phase;
+ event.deltaX = delta_x;
+ event.deltaY = delta_y;
+ return event;
+}
+
+TEST(MouseWheelRailsFilterMacTest, Functionality) {
+ WebInputEvent::RailsMode mode;
+ MouseWheelRailsFilterMac filter;
+
+ // Start with a mostly-horizontal event and see that it is locked
+ // horizontally and continues to be locked.
+ mode =
+ filter.UpdateRailsMode(MakeEvent(WebMouseWheelEvent::PhaseBegan, 2, 1));
+ EXPECT_EQ(mode, WebInputEvent::RailsModeHorizontal);
+ mode = filter.UpdateRailsMode(
+ MakeEvent(WebMouseWheelEvent::PhaseChanged, 2, 2));
+ EXPECT_EQ(mode, WebInputEvent::RailsModeHorizontal);
+ mode = filter.UpdateRailsMode(
+ MakeEvent(WebMouseWheelEvent::PhaseChanged, 10, -4));
+ EXPECT_EQ(mode, WebInputEvent::RailsModeHorizontal);
+
+ // Change from horizontal to vertical and back.
+ mode =
+ filter.UpdateRailsMode(MakeEvent(WebMouseWheelEvent::PhaseBegan, 4, 1));
+ EXPECT_EQ(mode, WebInputEvent::RailsModeHorizontal);
+ mode = filter.UpdateRailsMode(
+ MakeEvent(WebMouseWheelEvent::PhaseChanged, 3, 4));
+ EXPECT_EQ(mode, WebInputEvent::RailsModeHorizontal);
+ mode = filter.UpdateRailsMode(
+ MakeEvent(WebMouseWheelEvent::PhaseChanged, 1, 4));
+ EXPECT_EQ(mode, WebInputEvent::RailsModeVertical);
+ mode = filter.UpdateRailsMode(
+ MakeEvent(WebMouseWheelEvent::PhaseChanged, 10, 0));
+ EXPECT_EQ(mode, WebInputEvent::RailsModeHorizontal);
+
+ // Make sure zeroes don't break things.
+ mode = filter.UpdateRailsMode(
+ MakeEvent(WebMouseWheelEvent::PhaseChanged, 0, 0));
+ EXPECT_EQ(mode, WebInputEvent::RailsModeFree);
+ mode =
+ filter.UpdateRailsMode(MakeEvent(WebMouseWheelEvent::PhaseBegan, 0, 0));
+ EXPECT_EQ(mode, WebInputEvent::RailsModeFree);
+}
+
+} // namespace
+} // namespace content
diff --git a/content/browser/renderer_host/render_widget_host_view_mac.h b/content/browser/renderer_host/render_widget_host_view_mac.h
index 3f3fc1e..2465dd1 100644
--- a/content/browser/renderer_host/render_widget_host_view_mac.h
+++ b/content/browser/renderer_host/render_widget_host_view_mac.h
@@ -21,6 +21,7 @@
#include "content/browser/compositor/browser_compositor_view_mac.h"
#include "content/browser/compositor/delegated_frame_host.h"
#include "content/browser/renderer_host/display_link_mac.h"
+#include "content/browser/renderer_host/input/mouse_wheel_rails_filter_mac.h"
#include "content/browser/renderer_host/render_widget_host_view_base.h"
#include "content/common/content_export.h"
#include "content/common/cursors/webcursor.h"
@@ -35,6 +36,7 @@
#include "ui/gfx/display_observer.h"
namespace content {
+class RenderWidgetHostImpl;
class RenderWidgetHostViewMac;
class RenderWidgetHostViewMacEditCommandHelper;
class WebContents;
@@ -171,6 +173,10 @@
// key up events yet.
// Used for filtering out non-matching NSKeyUp events.
std::set<unsigned short> keyDownCodes_;
+
+ // The filter used to guide touch events towards a horizontal or vertical
+ // orientation.
+ content::MouseWheelRailsFilterMac mouseWheelFilter_;
}
@property(nonatomic, readonly) NSRange selectedRange;
@@ -199,7 +205,6 @@
@end
namespace content {
-class RenderWidgetHostImpl;
///////////////////////////////////////////////////////////////////////////////
// RenderWidgetHostViewMac
diff --git a/content/browser/renderer_host/render_widget_host_view_mac.mm b/content/browser/renderer_host/render_widget_host_view_mac.mm
index 7f0cb00..71bb4038 100644
--- a/content/browser/renderer_host/render_widget_host_view_mac.mm
+++ b/content/browser/renderer_host/render_widget_host_view_mac.mm
@@ -2254,8 +2254,9 @@
// Allow rubber-banding in both directions.
bool canRubberbandLeft = true;
bool canRubberbandRight = true;
- const WebMouseWheelEvent webEvent = WebInputEventFactory::mouseWheelEvent(
+ WebMouseWheelEvent webEvent = WebInputEventFactory::mouseWheelEvent(
event, self, canRubberbandLeft, canRubberbandRight);
+ webEvent.railsMode = mouseWheelFilter_.UpdateRailsMode(webEvent);
renderWidgetHostView_->render_widget_host_->ForwardWheelEvent(webEvent);
}
@@ -2377,8 +2378,9 @@
if (renderWidgetHostView_->render_widget_host_) {
BOOL canRubberbandLeft = [responderDelegate_ canRubberbandLeft:self];
BOOL canRubberbandRight = [responderDelegate_ canRubberbandRight:self];
- const WebMouseWheelEvent webEvent = WebInputEventFactory::mouseWheelEvent(
+ WebMouseWheelEvent webEvent = WebInputEventFactory::mouseWheelEvent(
event, self, canRubberbandLeft, canRubberbandRight);
+ webEvent.railsMode = mouseWheelFilter_.UpdateRailsMode(webEvent);
renderWidgetHostView_->render_widget_host_->ForwardWheelEvent(webEvent);
}
}
diff --git a/content/content_browser.gypi b/content/content_browser.gypi
index 9db87bff..94ca3117 100644
--- a/content/content_browser.gypi
+++ b/content/content_browser.gypi
@@ -1096,6 +1096,8 @@
'browser/renderer_host/input/motion_event_android.h',
'browser/renderer_host/input/motion_event_web.cc',
'browser/renderer_host/input/motion_event_web.h',
+ 'browser/renderer_host/input/mouse_wheel_rails_filter_mac.cc',
+ 'browser/renderer_host/input/mouse_wheel_rails_filter_mac.h',
'browser/renderer_host/input/stylus_text_selector.cc',
'browser/renderer_host/input/stylus_text_selector.h',
'browser/renderer_host/input/synthetic_gesture.cc',
diff --git a/content/content_tests.gypi b/content/content_tests.gypi
index f80176c6..7f628e6 100644
--- a/content/content_tests.gypi
+++ b/content/content_tests.gypi
@@ -497,6 +497,7 @@
'browser/renderer_host/input/mock_input_ack_handler.h',
'browser/renderer_host/input/mock_input_router_client.cc',
'browser/renderer_host/input/mock_input_router_client.h',
+ 'browser/renderer_host/input/mouse_wheel_rails_filter_unittest_mac.cc',
'browser/renderer_host/input/stylus_text_selector_unittest.cc',
'browser/renderer_host/input/synthetic_gesture_controller_unittest.cc',
'browser/renderer_host/input/tap_suppression_controller_unittest.cc',
diff --git a/content/renderer/input/input_handler_proxy.cc b/content/renderer/input/input_handler_proxy.cc
index f9cc75b9..57f425d 100644
--- a/content/renderer/input/input_handler_proxy.cc
+++ b/content/renderer/input/input_handler_proxy.cc
@@ -332,6 +332,16 @@
InputHandlerProxy::EventDisposition result = DID_NOT_HANDLE;
cc::InputHandlerScrollResult scroll_result;
+ // TODO(ccameron): The rail information should be pushed down into
+ // InputHandler.
+ gfx::Vector2dF scroll_delta(
+ wheel_event.railsMode != WebInputEvent::RailsModeVertical
+ ? -wheel_event.deltaX
+ : 0,
+ wheel_event.railsMode != WebInputEvent::RailsModeHorizontal
+ ? -wheel_event.deltaY
+ : 0);
+
if (wheel_event.scrollByPage) {
// TODO(jamesr): We don't properly handle scroll by page in the compositor
// thread, so punt it to the main thread. http://crbug.com/236639
@@ -342,9 +352,8 @@
result = DID_NOT_HANDLE;
} else if (smooth_scroll_enabled_) {
cc::InputHandler::ScrollStatus scroll_status =
- input_handler_->ScrollAnimated(
- gfx::Point(wheel_event.x, wheel_event.y),
- gfx::Vector2dF(-wheel_event.deltaX, -wheel_event.deltaY));
+ input_handler_->ScrollAnimated(gfx::Point(wheel_event.x, wheel_event.y),
+ scroll_delta);
switch (scroll_status) {
case cc::InputHandler::SCROLL_STARTED:
result = DID_HANDLE;
@@ -360,12 +369,11 @@
gfx::Point(wheel_event.x, wheel_event.y), cc::InputHandler::WHEEL);
switch (scroll_status) {
case cc::InputHandler::SCROLL_STARTED: {
- TRACE_EVENT_INSTANT2(
- "input", "InputHandlerProxy::handle_input wheel scroll",
- TRACE_EVENT_SCOPE_THREAD, "deltaX", -wheel_event.deltaX, "deltaY",
- -wheel_event.deltaY);
+ TRACE_EVENT_INSTANT2("input",
+ "InputHandlerProxy::handle_input wheel scroll",
+ TRACE_EVENT_SCOPE_THREAD, "deltaX",
+ scroll_delta.x(), "deltaY", scroll_delta.y());
gfx::Point scroll_point(wheel_event.x, wheel_event.y);
- gfx::Vector2dF scroll_delta(-wheel_event.deltaX, -wheel_event.deltaY);
scroll_result = input_handler_->ScrollBy(scroll_point, scroll_delta);
HandleOverscroll(scroll_point, scroll_result);
input_handler_->ScrollEnd();