Make Blink control browser mouse capture for scrollbar drags

The current behavior to allow mouse input in the browser process to be
locked to a given RenderWidgetHost is to send all mouse input between a
MouseDown and a MouseUp to the same target. This is not in accordance
with spec, and causes some site breakage.

Whether a MouseDown should cause capture depends on the node that the
event hits. Drag-highlighting text or clicking the thumb part of a
scrollbar require capture, for instance, while most elements do not.

This change removes the implicit capture currently done in the browser,
and replaces it in the case of scrollbars with an explicit signal from
Blink to start capturing. Other cases requiring capture still need to
be implemented.

Bug: 647378, 849862
Change-Id: Ifc4b690c36927ed48edd2604d40742e130295dcf
Reviewed-on: https://chromium-review.googlesource.com/1099183
Commit-Queue: Ken Buchanan <[email protected]>
Reviewed-by: Daniel Cheng <[email protected]>
Reviewed-by: Ella Ge <[email protected]>
Reviewed-by: Alex Moshchuk <[email protected]>
Reviewed-by: David Bokan <[email protected]>
Reviewed-by: Navid Zolghadr <[email protected]>
Cr-Commit-Position: refs/heads/master@{#569740}
diff --git a/content/renderer/render_frame_impl.cc b/content/renderer/render_frame_impl.cc
index 8f6bc46..a87355b 100644
--- a/content/renderer/render_frame_impl.cc
+++ b/content/renderer/render_frame_impl.cc
@@ -3719,6 +3719,10 @@
                                                                   value));
 }
 
+void RenderFrameImpl::SetMouseCapture(bool capture) {
+  GetRenderWidget()->SetMouseCapture(capture);
+}
+
 bool RenderFrameImpl::ShouldReportDetailedMessageForSource(
     const blink::WebString& source) {
   return GetContentClient()->renderer()->ShouldReportDetailedMessageForSource(
diff --git a/content/renderer/render_frame_impl.h b/content/renderer/render_frame_impl.h
index 17d323e1..88fb5919 100644
--- a/content/renderer/render_frame_impl.h
+++ b/content/renderer/render_frame_impl.h
@@ -612,6 +612,7 @@
   void UpdateUserActivationState(
       blink::UserActivationUpdateType update_type) override;
   void SetHasReceivedUserGestureBeforeNavigation(bool value) override;
+  void SetMouseCapture(bool capture) override;
   bool ShouldReportDetailedMessageForSource(
       const blink::WebString& source) override;
   void DidAddMessageToConsole(const blink::WebConsoleMessage& message,
diff --git a/content/renderer/render_widget.cc b/content/renderer/render_widget.cc
index a44975d5..245edd0e 100644
--- a/content/renderer/render_widget.cc
+++ b/content/renderer/render_widget.cc
@@ -2489,6 +2489,13 @@
   widget_binding_.Bind(std::move(request));
 }
 
+void RenderWidget::SetMouseCapture(bool capture) {
+  if (mojom::WidgetInputHandlerHost* host =
+          widget_input_handler_manager_->GetWidgetInputHandlerHost()) {
+    host->SetMouseCapture(capture);
+  }
+}
+
 bool RenderWidget::IsSurfaceSynchronizationEnabled() const {
   return compositor_ && compositor_->IsSurfaceSynchronizationEnabled();
 }
diff --git a/content/renderer/render_widget.h b/content/renderer/render_widget.h
index d43fa76..d34411f 100644
--- a/content/renderer/render_widget.h
+++ b/content/renderer/render_widget.h
@@ -477,6 +477,8 @@
                                    bool monitor_updates);
   void SetWidgetBinding(mojom::WidgetRequest request);
 
+  void SetMouseCapture(bool capture);
+
   // Time-To-First-Active-Paint(TTFAP) type
   enum {
     TTFAP_AFTER_PURGED,
diff --git a/content/renderer/render_widget_unittest.cc b/content/renderer/render_widget_unittest.cc
index d3db6e5..319ab3c 100644
--- a/content/renderer/render_widget_unittest.cc
+++ b/content/renderer/render_widget_unittest.cc
@@ -91,6 +91,8 @@
   MOCK_METHOD2(ImeCompositionRangeChanged,
                void(const gfx::Range&, const std::vector<gfx::Rect>&));
 
+  MOCK_METHOD1(SetMouseCapture, void(bool));
+
  private:
   mojo::Binding<mojom::WidgetInputHandlerHost> binding_;