summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorjdduke@chromium.org <jdduke@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-05-20 21:32:53 +0000
committerjdduke@chromium.org <jdduke@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-05-20 21:32:53 +0000
commita2b5ded72a23378831be3ea5fcd8712ef96c1d21 (patch)
tree65528ad919d8fc7ee0dbb1c6183695e130685401
parenta040b244d9bed66ba5a381a4e8e59684f901a8fe (diff)
downloadchromium_src-a2b5ded72a23378831be3ea5fcd8712ef96c1d21.zip
chromium_src-a2b5ded72a23378831be3ea5fcd8712ef96c1d21.tar.gz
chromium_src-a2b5ded72a23378831be3ea5fcd8712ef96c1d21.tar.bz2
Route compositor overscroll events to the input handler.
Various browser-side components may be interested in compositor overscroll events. This patch provides a way for routing such events from the compositor to the InputHandler for further dispatch. BUG=135975 NOTRY=true Review URL: https://chromiumcodereview.appspot.com/14499002 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@201141 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--cc/input/input_handler.h9
-rw-r--r--cc/trees/layer_tree_host_impl.cc33
-rw-r--r--cc/trees/layer_tree_host_impl.h8
-rw-r--r--cc/trees/layer_tree_host_impl_unittest.cc144
-rw-r--r--cc/trees/layer_tree_host_unittest_scroll.cc6
-rw-r--r--content/renderer/gpu/input_handler_proxy.cc6
-rw-r--r--content/renderer/gpu/input_handler_proxy.h2
-rw-r--r--content/renderer/gpu/input_handler_proxy_client.h3
-rw-r--r--content/renderer/gpu/input_handler_proxy_unittest.cc3
-rw-r--r--content/renderer/gpu/input_handler_wrapper.cc9
-rw-r--r--content/renderer/gpu/input_handler_wrapper.h2
-rw-r--r--content/renderer/render_widget.cc13
-rw-r--r--content/renderer/render_widget.h8
13 files changed, 239 insertions, 7 deletions
diff --git a/cc/input/input_handler.h b/cc/input/input_handler.h
index 2c73710..1d5298e 100644
--- a/cc/input/input_handler.h
+++ b/cc/input/input_handler.h
@@ -29,6 +29,12 @@ class CC_EXPORT InputHandlerClient {
virtual void Animate(base::TimeTicks time) = 0;
virtual void MainThreadHasStoppedFlinging() = 0;
+ // Called when scroll deltas reaching the root scrolling layer go unused.
+ // The accumulated overscroll is scoped by the most recent call to
+ // InputHandler::ScrollBegin.
+ virtual void DidOverscroll(gfx::Vector2dF accumulated_overscroll,
+ gfx::Vector2dF current_fling_velocity) = 0;
+
protected:
InputHandlerClient() {}
@@ -66,6 +72,9 @@ class CC_EXPORT InputHandler {
// scrolled will be moved instead. If no layer can be moved in the requested
// direction at all, then false is returned. If any layer is moved, then
// true is returned.
+ // If the scroll delta hits the root layer, and the layer can no longer move,
+ // the root overscroll accumulated within this ScrollBegin() scope is reported
+ // to the client.
// Should only be called if ScrollBegin() returned ScrollStarted.
virtual bool ScrollBy(gfx::Point viewport_point,
gfx::Vector2dF scroll_delta) = 0;
diff --git a/cc/trees/layer_tree_host_impl.cc b/cc/trees/layer_tree_host_impl.cc
index 4dcbe76..b6e597e 100644
--- a/cc/trees/layer_tree_host_impl.cc
+++ b/cc/trees/layer_tree_host_impl.cc
@@ -1669,6 +1669,7 @@ bool LayerTreeHostImpl::ScrollBy(gfx::Point viewport_point,
return false;
gfx::Vector2dF pending_delta = scroll_delta;
+ gfx::Vector2dF unused_root_delta;
bool did_scroll = false;
bool consume_by_top_controls = top_controls_manager_ &&
(CurrentlyScrollingLayer() == RootScrollLayer() || scroll_delta.y() < 0);
@@ -1679,11 +1680,15 @@ bool LayerTreeHostImpl::ScrollBy(gfx::Point viewport_point,
if (!layer_impl->scrollable())
continue;
- // Only allow bubble scrolling when the scroll is in the direction to make
- // the top controls visible.
- if (consume_by_top_controls && layer_impl == RootScrollLayer()) {
- pending_delta = top_controls_manager_->ScrollBy(pending_delta);
- UpdateMaxScrollOffset();
+ if (layer_impl == RootScrollLayer()) {
+ // Only allow bubble scrolling when the scroll is in the direction to make
+ // the top controls visible.
+ if (consume_by_top_controls && layer_impl == RootScrollLayer()) {
+ pending_delta = top_controls_manager_->ScrollBy(pending_delta);
+ UpdateMaxScrollOffset();
+ }
+ // Track root layer deltas for reporting overscroll.
+ unused_root_delta = pending_delta;
}
gfx::Vector2dF applied_delta;
@@ -1709,6 +1714,10 @@ bool LayerTreeHostImpl::ScrollBy(gfx::Point viewport_point,
else
break;
}
+
+ if (layer_impl == RootScrollLayer())
+ unused_root_delta.Subtract(applied_delta);
+
did_scroll = true;
did_lock_scrolling_layer_ = true;
if (!should_bubble_scrolls_) {
@@ -1731,7 +1740,7 @@ bool LayerTreeHostImpl::ScrollBy(gfx::Point viewport_point,
gfx::Vector2dF perpendicular_axis(-applied_delta.y(), applied_delta.x());
pending_delta = MathUtil::ProjectVector(pending_delta, perpendicular_axis);
- if (gfx::ToFlooredVector2d(pending_delta).IsZero())
+ if (gfx::ToRoundedVector2d(pending_delta).IsZero())
break;
}
@@ -1739,7 +1748,18 @@ bool LayerTreeHostImpl::ScrollBy(gfx::Point viewport_point,
client_->SetNeedsCommitOnImplThread();
client_->SetNeedsRedrawOnImplThread();
client_->RenewTreePriority();
+
+ // Scrolling of any layer will reset root overscroll accumulation.
+ accumulated_root_overscroll_ = gfx::Vector2dF();
}
+
+ accumulated_root_overscroll_ += unused_root_delta;
+ bool did_overscroll = !gfx::ToRoundedVector2d(unused_root_delta).IsZero();
+ if (did_overscroll && input_handler_client_) {
+ input_handler_client_->DidOverscroll(accumulated_root_overscroll_,
+ current_fling_velocity_);
+ }
+
return did_scroll;
}
@@ -1800,6 +1820,7 @@ void LayerTreeHostImpl::OnRootLayerDelegatedScrollOffsetChanged() {
void LayerTreeHostImpl::ClearCurrentlyScrollingLayer() {
active_tree_->ClearCurrentlyScrollingLayer();
did_lock_scrolling_layer_ = false;
+ accumulated_root_overscroll_ = gfx::Vector2dF();
current_fling_velocity_ = gfx::Vector2dF();
}
diff --git a/cc/trees/layer_tree_host_impl.h b/cc/trees/layer_tree_host_impl.h
index b4d9757..72b06b5 100644
--- a/cc/trees/layer_tree_host_impl.h
+++ b/cc/trees/layer_tree_host_impl.h
@@ -349,6 +349,13 @@ class CC_EXPORT LayerTreeHostImpl
skia::RefPtr<SkPicture> CapturePicture();
+ gfx::Vector2dF accumulated_root_overscroll() const {
+ return accumulated_root_overscroll_;
+ }
+ gfx::Vector2dF current_fling_velocity() const {
+ return current_fling_velocity_;
+ }
+
bool pinch_gesture_active() const { return pinch_gesture_active_; }
void SetTreePriority(TreePriority priority);
@@ -454,6 +461,7 @@ class CC_EXPORT LayerTreeHostImpl
bool visible_;
ManagedMemoryPolicy managed_memory_policy_;
+ gfx::Vector2dF accumulated_root_overscroll_;
gfx::Vector2dF current_fling_velocity_;
bool pinch_gesture_active_;
diff --git a/cc/trees/layer_tree_host_impl_unittest.cc b/cc/trees/layer_tree_host_impl_unittest.cc
index fb5a2c4..866bfca 100644
--- a/cc/trees/layer_tree_host_impl_unittest.cc
+++ b/cc/trees/layer_tree_host_impl_unittest.cc
@@ -209,7 +209,7 @@ class LayerTreeHostImplTest : public testing::Test,
scroll->SetScrollable(true);
scroll->SetScrollOffset(gfx::Vector2d());
scroll->SetMaxScrollOffset(gfx::Vector2d(content_size.width(),
- content_size.height()));
+ content_size.height()));
scroll->SetBounds(content_size);
scroll->SetContentBounds(content_size);
scroll->SetPosition(gfx::PointF());
@@ -2097,6 +2097,148 @@ TEST_F(LayerTreeHostImplTest, RootLayerScrollOffsetDelegation) {
scroll_layer->TotalScrollOffset().ToString());
}
+TEST_F(LayerTreeHostImplTest, OverscrollRoot) {
+ SetupScrollAndContentsLayers(gfx::Size(100, 100));
+ host_impl_->SetViewportSize(gfx::Size(50, 50));
+ host_impl_->active_tree()->SetPageScaleFactorAndLimits(1.f, 0.5f, 4.f);
+ InitializeRendererAndDrawFrame();
+ EXPECT_EQ(gfx::Vector2dF(), host_impl_->accumulated_root_overscroll());
+ EXPECT_EQ(gfx::Vector2dF(), host_impl_->current_fling_velocity());
+
+ // In-bounds scrolling does not affect overscroll.
+ EXPECT_EQ(InputHandler::ScrollStarted,
+ host_impl_->ScrollBegin(gfx::Point(), InputHandler::Wheel));
+ host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, 10));
+ EXPECT_EQ(gfx::Vector2dF(), host_impl_->accumulated_root_overscroll());
+ EXPECT_EQ(gfx::Vector2dF(), host_impl_->current_fling_velocity());
+
+ // Overscroll events are reflected immediately.
+ host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, 50));
+ EXPECT_EQ(gfx::Vector2dF(0, 10), host_impl_->accumulated_root_overscroll());
+ EXPECT_EQ(gfx::Vector2dF(), host_impl_->current_fling_velocity());
+
+ // In-bounds scrolling resets accumulated overscroll.
+ host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, -50));
+ EXPECT_EQ(gfx::Vector2dF(0, 0), host_impl_->accumulated_root_overscroll());
+ host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, -10));
+ EXPECT_EQ(gfx::Vector2dF(0, -10), host_impl_->accumulated_root_overscroll());
+
+ // Overscroll accumulates within the scope of ScrollBegin/ScrollEnd as long
+ // as no scroll occurs.
+ host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, -20));
+ EXPECT_EQ(gfx::Vector2dF(0, -30), host_impl_->accumulated_root_overscroll());
+ host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, -20));
+ EXPECT_EQ(gfx::Vector2dF(0, -50), host_impl_->accumulated_root_overscroll());
+ // Overscroll resets on valid scroll.
+ host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, 10));
+ EXPECT_EQ(gfx::Vector2dF(0, 0), host_impl_->accumulated_root_overscroll());
+ host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, -20));
+ EXPECT_EQ(gfx::Vector2dF(0, -10), host_impl_->accumulated_root_overscroll());
+ host_impl_->ScrollEnd();
+
+ EXPECT_EQ(InputHandler::ScrollStarted,
+ host_impl_->ScrollBegin(gfx::Point(), InputHandler::Wheel));
+ // Fling velocity is reflected immediately.
+ host_impl_->NotifyCurrentFlingVelocity(gfx::Vector2dF(10, 0));
+ EXPECT_EQ(gfx::Vector2dF(10, 0), host_impl_->current_fling_velocity());
+ host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, -20));
+ EXPECT_EQ(gfx::Vector2dF(0, -20), host_impl_->accumulated_root_overscroll());
+ EXPECT_EQ(gfx::Vector2dF(10, 0), host_impl_->current_fling_velocity());
+}
+
+
+TEST_F(LayerTreeHostImplTest, OverscrollChildWithoutBubbling) {
+ // Scroll child layers beyond their maximum scroll range and make sure root
+ // overscroll does not accumulate.
+ gfx::Size surface_size(10, 10);
+ scoped_ptr<LayerImpl> root = CreateScrollableLayer(1, surface_size);
+
+ scoped_ptr<LayerImpl> grand_child = CreateScrollableLayer(3, surface_size);
+ grand_child->SetScrollOffset(gfx::Vector2d(0, 2));
+
+ scoped_ptr<LayerImpl> child = CreateScrollableLayer(2, surface_size);
+ child->SetScrollOffset(gfx::Vector2d(0, 3));
+ child->AddChild(grand_child.Pass());
+
+ root->AddChild(child.Pass());
+ host_impl_->active_tree()->SetRootLayer(root.Pass());
+ host_impl_->active_tree()->DidBecomeActive();
+ host_impl_->SetViewportSize(surface_size);
+ InitializeRendererAndDrawFrame();
+ {
+ gfx::Vector2d scroll_delta(0, -10);
+ EXPECT_EQ(InputHandler::ScrollStarted,
+ host_impl_->ScrollBegin(gfx::Point(5, 5),
+ InputHandler::NonBubblingGesture));
+ host_impl_->ScrollBy(gfx::Point(), scroll_delta);
+ EXPECT_EQ(gfx::Vector2dF(), host_impl_->accumulated_root_overscroll());
+ host_impl_->ScrollEnd();
+
+ LayerImpl* child = host_impl_->active_tree()->root_layer()->children()[0];
+ LayerImpl* grand_child = child->children()[0];
+
+ // The next time we scroll we should only scroll the parent, but overscroll
+ // should still not reach the root layer.
+ scroll_delta = gfx::Vector2d(0, -30);
+ EXPECT_EQ(InputHandler::ScrollStarted,
+ host_impl_->ScrollBegin(gfx::Point(5, 5),
+ InputHandler::NonBubblingGesture));
+ EXPECT_EQ(host_impl_->CurrentlyScrollingLayer(), grand_child);
+ EXPECT_EQ(gfx::Vector2dF(), host_impl_->accumulated_root_overscroll());
+ host_impl_->ScrollBy(gfx::Point(), scroll_delta);
+ EXPECT_EQ(host_impl_->CurrentlyScrollingLayer(), child);
+ EXPECT_EQ(gfx::Vector2dF(), host_impl_->accumulated_root_overscroll());
+ host_impl_->ScrollEnd();
+
+ // After scrolling the parent, another scroll on the opposite direction
+ // should scroll the child, resetting the fling velocity.
+ scroll_delta = gfx::Vector2d(0, 70);
+ host_impl_->NotifyCurrentFlingVelocity(gfx::Vector2dF(10, 0));
+ EXPECT_EQ(gfx::Vector2dF(10, 0), host_impl_->current_fling_velocity());
+ EXPECT_EQ(InputHandler::ScrollStarted,
+ host_impl_->ScrollBegin(gfx::Point(5, 5),
+ InputHandler::NonBubblingGesture));
+ EXPECT_EQ(host_impl_->CurrentlyScrollingLayer(), grand_child);
+ host_impl_->ScrollBy(gfx::Point(), scroll_delta);
+ EXPECT_EQ(host_impl_->CurrentlyScrollingLayer(), grand_child);
+ EXPECT_EQ(gfx::Vector2dF(), host_impl_->accumulated_root_overscroll());
+ EXPECT_EQ(gfx::Vector2dF(), host_impl_->current_fling_velocity());
+ host_impl_->ScrollEnd();
+ }
+}
+
+TEST_F(LayerTreeHostImplTest, OverscrollChildEventBubbling) {
+ // When we try to scroll a non-scrollable child layer, the scroll delta
+ // should be applied to one of its ancestors if possible. Overscroll should
+ // be reflected only when it has bubbled up to the root scrolling layer.
+ gfx::Size surface_size(10, 10);
+ gfx::Size content_size(20, 20);
+ scoped_ptr<LayerImpl> root = CreateScrollableLayer(1, content_size);
+ scoped_ptr<LayerImpl> child = CreateScrollableLayer(2, content_size);
+
+ child->SetScrollable(false);
+ root->AddChild(child.Pass());
+
+ host_impl_->SetViewportSize(surface_size);
+ host_impl_->active_tree()->SetRootLayer(root.Pass());
+ host_impl_->active_tree()->DidBecomeActive();
+ InitializeRendererAndDrawFrame();
+ {
+ gfx::Vector2d scroll_delta(0, 8);
+ EXPECT_EQ(InputHandler::ScrollStarted,
+ host_impl_->ScrollBegin(gfx::Point(5, 5),
+ InputHandler::Wheel));
+ host_impl_->ScrollBy(gfx::Point(), scroll_delta);
+ EXPECT_EQ(gfx::Vector2dF(), host_impl_->accumulated_root_overscroll());
+ host_impl_->ScrollBy(gfx::Point(), scroll_delta);
+ EXPECT_EQ(gfx::Vector2dF(0, 6), host_impl_->accumulated_root_overscroll());
+ host_impl_->ScrollBy(gfx::Point(), scroll_delta);
+ EXPECT_EQ(gfx::Vector2dF(0, 14), host_impl_->accumulated_root_overscroll());
+ host_impl_->ScrollEnd();
+ }
+}
+
+
class BlendStateTrackerContext: public TestWebGraphicsContext3D {
public:
BlendStateTrackerContext() : blend_(false) {}
diff --git a/cc/trees/layer_tree_host_unittest_scroll.cc b/cc/trees/layer_tree_host_unittest_scroll.cc
index db6f3c9..9731436 100644
--- a/cc/trees/layer_tree_host_unittest_scroll.cc
+++ b/cc/trees/layer_tree_host_unittest_scroll.cc
@@ -708,6 +708,12 @@ class ThreadCheckingInputHandlerClient : public InputHandlerClient {
*received_stop_flinging_ = true;
}
+ virtual void DidOverscroll(gfx::Vector2dF accumulated_overscroll,
+ gfx::Vector2dF current_fling_velocity) OVERRIDE {
+ if (!task_runner_->BelongsToCurrentThread())
+ ADD_FAILURE() << "DidOverscroll called on wrong thread";
+ }
+
private:
base::SingleThreadTaskRunner* task_runner_;
bool* received_stop_flinging_;
diff --git a/content/renderer/gpu/input_handler_proxy.cc b/content/renderer/gpu/input_handler_proxy.cc
index 07514bf..620fb3e 100644
--- a/content/renderer/gpu/input_handler_proxy.cc
+++ b/content/renderer/gpu/input_handler_proxy.cc
@@ -298,6 +298,12 @@ void InputHandlerProxy::MainThreadHasStoppedFlinging() {
fling_may_be_active_on_main_thread_ = false;
}
+void InputHandlerProxy::DidOverscroll(gfx::Vector2dF accumulated_overscroll,
+ gfx::Vector2dF current_fling_velocity) {
+ DCHECK(client_);
+ client_->DidOverscroll(accumulated_overscroll, current_fling_velocity);
+}
+
bool InputHandlerProxy::CancelCurrentFling() {
bool had_fling_animation = fling_curve_;
if (had_fling_animation &&
diff --git a/content/renderer/gpu/input_handler_proxy.h b/content/renderer/gpu/input_handler_proxy.h
index 281afa9..c3f0fc2 100644
--- a/content/renderer/gpu/input_handler_proxy.h
+++ b/content/renderer/gpu/input_handler_proxy.h
@@ -37,6 +37,8 @@ class CONTENT_EXPORT InputHandlerProxy
virtual void WillShutdown() OVERRIDE;
virtual void Animate(base::TimeTicks time) OVERRIDE;
virtual void MainThreadHasStoppedFlinging() OVERRIDE;
+ virtual void DidOverscroll(gfx::Vector2dF accumulated_overscroll,
+ gfx::Vector2dF current_fling_velocity) OVERRIDE;
// WebKit::WebGestureCurveTarget implementation.
virtual void scrollBy(const WebKit::WebFloatSize& offset);
diff --git a/content/renderer/gpu/input_handler_proxy_client.h b/content/renderer/gpu/input_handler_proxy_client.h
index 713a0d2..834ee66 100644
--- a/content/renderer/gpu/input_handler_proxy_client.h
+++ b/content/renderer/gpu/input_handler_proxy_client.h
@@ -44,6 +44,9 @@ class InputHandlerProxyClient {
const WebKit::WebFloatPoint& velocity,
const WebKit::WebSize& cumulative_scroll) = 0;
+ virtual void DidOverscroll(gfx::Vector2dF accumulated_overscroll,
+ gfx::Vector2dF current_fling_velocity) = 0;
+
protected:
virtual ~InputHandlerProxyClient() {}
};
diff --git a/content/renderer/gpu/input_handler_proxy_unittest.cc b/content/renderer/gpu/input_handler_proxy_unittest.cc
index f1a6e67..02a033b 100644
--- a/content/renderer/gpu/input_handler_proxy_unittest.cc
+++ b/content/renderer/gpu/input_handler_proxy_unittest.cc
@@ -125,6 +125,9 @@ class MockInputHandlerProxyClient
return new FakeWebGestureCurve(velocity, cumulative_scroll);
}
+ virtual void DidOverscroll(gfx::Vector2dF overscroll,
+ gfx::Vector2dF fling_velocity) {}
+
private:
DISALLOW_COPY_AND_ASSIGN(MockInputHandlerProxyClient);
};
diff --git a/content/renderer/gpu/input_handler_wrapper.cc b/content/renderer/gpu/input_handler_wrapper.cc
index 76d4873..c8e1230 100644
--- a/content/renderer/gpu/input_handler_wrapper.cc
+++ b/content/renderer/gpu/input_handler_wrapper.cc
@@ -57,4 +57,13 @@ WebKit::WebGestureCurve* InputHandlerWrapper::CreateFlingAnimationCurve(
deviceSource, velocity, cumulative_scroll);
}
+void InputHandlerWrapper::DidOverscroll(gfx::Vector2dF accumulated_overscroll,
+ gfx::Vector2dF current_fling_velocity) {
+ main_loop_->PostTask(
+ FROM_HERE,
+ base::Bind(&RenderViewImpl::DidOverscroll,
+ render_view_impl_,
+ accumulated_overscroll, current_fling_velocity));
+}
+
} // namespace content
diff --git a/content/renderer/gpu/input_handler_wrapper.h b/content/renderer/gpu/input_handler_wrapper.h
index cae8339..5c91ad7 100644
--- a/content/renderer/gpu/input_handler_wrapper.h
+++ b/content/renderer/gpu/input_handler_wrapper.h
@@ -37,6 +37,8 @@ class InputHandlerWrapper
int deviceSource,
const WebKit::WebFloatPoint& velocity,
const WebKit::WebSize& cumulativeScroll) OVERRIDE;
+ virtual void DidOverscroll(gfx::Vector2dF accumulated_overscroll,
+ gfx::Vector2dF current_fling_velocity) OVERRIDE;
private:
friend class base::RefCountedThreadSafe<InputHandlerWrapper>;
diff --git a/content/renderer/render_widget.cc b/content/renderer/render_widget.cc
index d730910..521b330 100644
--- a/content/renderer/render_widget.cc
+++ b/content/renderer/render_widget.cc
@@ -177,6 +177,7 @@ RenderWidget::RenderWidget(WebKit::WebPopupType popup_type,
device_scale_factor_(screen_info_.deviceScaleFactor),
throttle_input_events_(true),
is_threaded_compositing_enabled_(false),
+ overscroll_notifications_enabled_(false),
weak_ptr_factory_(this) {
if (!swapped_out)
RenderProcess::current()->AddRefProcess();
@@ -186,6 +187,9 @@ RenderWidget::RenderWidget(WebKit::WebPopupType popup_type,
is_threaded_compositing_enabled_ =
CommandLine::ForCurrentProcess()->HasSwitch(
switches::kEnableThreadedCompositing);
+ overscroll_notifications_enabled_ =
+ CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kEnableOverscrollNotifications);
}
RenderWidget::~RenderWidget() {
@@ -2319,6 +2323,15 @@ void RenderWidget::BeginSmoothScroll(
pending_smooth_scroll_gesture_ = callback;
}
+void RenderWidget::DidOverscroll(gfx::Vector2dF accumulated_overscroll,
+ gfx::Vector2dF current_fling_velocity) {
+ if (overscroll_notifications_enabled_) {
+ Send(new ViewHostMsg_DidOverscroll(routing_id_,
+ accumulated_overscroll,
+ current_fling_velocity));
+ }
+}
+
bool RenderWidget::WillHandleMouseEvent(const WebKit::WebMouseEvent& event) {
return false;
}
diff --git a/content/renderer/render_widget.h b/content/renderer/render_widget.h
index 72a5800..3660f75 100644
--- a/content/renderer/render_widget.h
+++ b/content/renderer/render_widget.h
@@ -33,6 +33,7 @@
#include "ui/gfx/native_widget_types.h"
#include "ui/gfx/rect.h"
#include "ui/gfx/vector2d.h"
+#include "ui/gfx/vector2d_f.h"
#include "ui/surface/transport_dib.h"
#include "webkit/glue/webcursor.h"
@@ -188,6 +189,10 @@ class CONTENT_EXPORT RenderWidget
int mouse_event_x,
int mouse_event_y);
+ // Notifies the host that root scroll layer has overscrolled.
+ void DidOverscroll(gfx::Vector2dF accumulated_overscroll,
+ gfx::Vector2dF current_fling_velocity);
+
// Close the underlying WebWidget.
virtual void Close();
@@ -693,6 +698,9 @@ class CONTENT_EXPORT RenderWidget
// Specified whether the compositor will run in its own thread.
bool is_threaded_compositing_enabled_;
+ // Specifies whether overscroll notifications are forwarded to the host.
+ bool overscroll_notifications_enabled_;
+
base::WeakPtrFactory<RenderWidget> weak_ptr_factory_;
DISALLOW_COPY_AND_ASSIGN(RenderWidget);