Add InputEventShim for intercepting RWH messages.

As part of the effort to stop RenderWidgetHost from forwarding
it's messages in OnMessageReceived() on to other classes (which
lead to spooky message-action at a distance), this introduces
a new shim class InputEventShim that allows BrowserPlugin to
override various input event related messages in RenderWidgetHost.

This also simplifies some of the message routing in InputRouter
allowing it to NOT be a IPC::Listner, which again, makes inter-class
relations more explicit.

There should be no functionality change.

Bug: 419087
Change-Id: I75f2f4cc1d1b6d36373c75dc7b4ae7bd7af1afe4
Reviewed-on: https://chromium-review.googlesource.com/c/1274606
Reviewed-by: Albert J. Wong <[email protected]>
Reviewed-by: James MacLean <[email protected]>
Reviewed-by: Nasko Oskov <[email protected]>
Reviewed-by: danakj <[email protected]>
Commit-Queue: Albert J. Wong <[email protected]>
Cr-Commit-Position: refs/heads/master@{#599046}
diff --git a/content/browser/BUILD.gn b/content/browser/BUILD.gn
index b9925142f..f4de15d 100644
--- a/content/browser/BUILD.gn
+++ b/content/browser/BUILD.gn
@@ -1402,6 +1402,7 @@
     "renderer_host/input/web_input_event_builders_android.h",
     "renderer_host/input/web_input_event_builders_mac.h",
     "renderer_host/input/web_input_event_builders_mac.mm",
+    "renderer_host/input_event_shim.h",
     "renderer_host/legacy_render_widget_host_win.cc",
     "renderer_host/legacy_render_widget_host_win.h",
     "renderer_host/media/audio_input_delegate_impl.cc",
diff --git a/content/browser/browser_plugin/browser_plugin_guest.cc b/content/browser/browser_plugin/browser_plugin_guest.cc
index 2c585e3..983aaff 100644
--- a/content/browser/browser_plugin/browser_plugin_guest.cc
+++ b/content/browser/browser_plugin/browser_plugin_guest.cc
@@ -62,6 +62,31 @@
 
 namespace content {
 
+BrowserPluginGuest::InputEventShimImpl::InputEventShimImpl(
+    BrowserPluginGuest* browser_plugin_guest)
+    : browser_plugin_guest_(browser_plugin_guest) {}
+
+BrowserPluginGuest::InputEventShimImpl::~InputEventShimImpl() = default;
+
+void BrowserPluginGuest::InputEventShimImpl::DidSetHasTouchEventHandlers(
+    bool accept) {
+  browser_plugin_guest_->DidSetHasTouchEventHandlers(accept);
+}
+
+void BrowserPluginGuest::InputEventShimImpl::DidTextInputStateChange(
+    const TextInputState& params) {
+  browser_plugin_guest_->DidTextInputStateChange(params);
+}
+
+void BrowserPluginGuest::InputEventShimImpl::DidLockMouse(bool user_gesture,
+                                                          bool privileged) {
+  browser_plugin_guest_->DidLockMouse(user_gesture, privileged);
+}
+
+void BrowserPluginGuest::InputEventShimImpl::DidUnlockMouse() {
+  browser_plugin_guest_->DidUnlockMouse();
+}
+
 class BrowserPluginGuest::EmbedderVisibilityObserver
     : public WebContentsObserver {
  public:
@@ -87,6 +112,7 @@
                                        WebContentsImpl* web_contents,
                                        BrowserPluginGuestDelegate* delegate)
     : WebContentsObserver(web_contents),
+      input_event_shim_impl_(this),
       owner_web_contents_(nullptr),
       attached_(false),
       browser_plugin_instance_id_(browser_plugin::kInstanceIDNone),
@@ -212,6 +238,15 @@
   InitInternal(BrowserPluginHostMsg_Attach_Params(), owner_web_contents);
 }
 
+InputEventShim* BrowserPluginGuest::GetInputEventShim() {
+  // In --site-per-process mode, the input event mechanics are handled by
+  // the RenderWidgetHost so there is no need to shim things.
+  if (GuestMode::IsCrossProcessFrameGuest(GetWebContents())) {
+    return nullptr;
+  }
+  return &input_event_shim_impl_;
+}
+
 base::WeakPtr<BrowserPluginGuest> BrowserPluginGuest::AsWeakPtr() {
   return weak_ptr_factory_.GetWeakPtr();
 }
@@ -230,7 +265,7 @@
   }
   RenderWidgetHostImpl::From(rwh)->GetWidgetInputHandler()->SetFocus(focused);
   if (!focused && mouse_locked_)
-    OnUnlockMouse();
+    DidUnlockMouse();
 
   // Restore the last seen state of text input to the view.
   RenderWidgetHostViewBase* rwhv = static_cast<RenderWidgetHostViewBase*>(
@@ -697,6 +732,48 @@
   }
 }
 
+void BrowserPluginGuest::DidSetHasTouchEventHandlers(bool accept) {
+  SendMessageToEmbedder(
+      std::make_unique<BrowserPluginMsg_ShouldAcceptTouchEvents>(
+          browser_plugin_instance_id(), accept));
+}
+
+void BrowserPluginGuest::DidTextInputStateChange(const TextInputState& params) {
+  // Save the state of text input so we can restore it on focus.
+  last_text_input_state_ = std::make_unique<TextInputState>(params);
+
+  SendTextInputTypeChangedToView(static_cast<RenderWidgetHostViewBase*>(
+      web_contents()->GetRenderWidgetHostView()));
+}
+
+void BrowserPluginGuest::DidLockMouse(bool user_gesture, bool privileged) {
+  if (pending_lock_request_) {
+    // Immediately reject the lock because only one pointerLock may be active
+    // at a time.
+    RenderWidgetHost* widget_host =
+        web_contents()->GetRenderViewHost()->GetWidget();
+    widget_host->Send(
+        new WidgetMsg_LockMouse_ACK(widget_host->GetRoutingID(), false));
+    return;
+  }
+
+  pending_lock_request_ = true;
+
+  RenderWidgetHostImpl* owner = GetOwnerRenderWidgetHost();
+  bool is_last_unlocked_by_target =
+      owner ? owner->is_last_unlocked_by_target() : false;
+
+  delegate_->RequestPointerLockPermission(
+      user_gesture, is_last_unlocked_by_target,
+      base::BindRepeating(&BrowserPluginGuest::PointerLockPermissionResponse,
+                          weak_ptr_factory_.GetWeakPtr()));
+}
+
+void BrowserPluginGuest::DidUnlockMouse() {
+  SendMessageToEmbedder(std::make_unique<BrowserPluginMsg_SetMouseLock>(
+      browser_plugin_instance_id(), false));
+}
+
 // static
 bool BrowserPluginGuest::ShouldForwardToBrowserPluginGuest(
     const IPC::Message& message) {
@@ -715,14 +792,8 @@
     return false;
 
   IPC_BEGIN_MESSAGE_MAP(BrowserPluginGuest, message)
-    IPC_MESSAGE_HANDLER(ViewHostMsg_HasTouchEventHandlers,
-                        OnHasTouchEventHandlers)
-    IPC_MESSAGE_HANDLER(WidgetHostMsg_LockMouse, OnLockMouse)
     IPC_MESSAGE_HANDLER(ViewHostMsg_ShowWidget, OnShowWidget)
     IPC_MESSAGE_HANDLER(ViewHostMsg_TakeFocus, OnTakeFocus)
-    IPC_MESSAGE_HANDLER(WidgetHostMsg_TextInputStateChanged,
-                        OnTextInputStateChanged)
-    IPC_MESSAGE_HANDLER(WidgetHostMsg_UnlockMouse, OnUnlockMouse)
     IPC_MESSAGE_UNHANDLED(handled = false)
   IPC_END_MESSAGE_MAP()
   return handled;
@@ -938,30 +1009,6 @@
     rfh->GetFrameInputHandler()->ExtendSelectionAndDelete(before, after);
 }
 
-void BrowserPluginGuest::OnLockMouse(bool user_gesture,
-                                     bool privileged) {
-  if (pending_lock_request_) {
-    // Immediately reject the lock because only one pointerLock may be active
-    // at a time.
-    RenderWidgetHost* widget_host =
-        web_contents()->GetRenderViewHost()->GetWidget();
-    widget_host->Send(
-        new WidgetMsg_LockMouse_ACK(widget_host->GetRoutingID(), false));
-    return;
-  }
-
-  pending_lock_request_ = true;
-
-  RenderWidgetHostImpl* owner = GetOwnerRenderWidgetHost();
-  bool is_last_unlocked_by_target =
-      owner ? owner->is_last_unlocked_by_target() : false;
-
-  delegate_->RequestPointerLockPermission(
-      user_gesture, is_last_unlocked_by_target,
-      base::Bind(&BrowserPluginGuest::PointerLockPermissionResponse,
-                 weak_ptr_factory_.GetWeakPtr()));
-}
-
 void BrowserPluginGuest::OnLockMouseAck(int browser_plugin_instance_id,
                                         bool succeeded) {
   RenderWidgetHost* widget_host =
@@ -1009,11 +1056,6 @@
     GetWebContents()->WasOccluded();
 }
 
-void BrowserPluginGuest::OnUnlockMouse() {
-  SendMessageToEmbedder(std::make_unique<BrowserPluginMsg_SetMouseLock>(
-      browser_plugin_instance_id(), false));
-}
-
 void BrowserPluginGuest::OnUnlockMouseAck(int browser_plugin_instance_id) {
   // mouse_locked_ could be false here if the lock attempt was cancelled due
   // to window focus, or for various other reasons before the guest was informed
@@ -1076,12 +1118,6 @@
   render_widget_host->SynchronizeVisualProperties();
 }
 
-void BrowserPluginGuest::OnHasTouchEventHandlers(bool accept) {
-  SendMessageToEmbedder(
-      std::make_unique<BrowserPluginMsg_ShouldAcceptTouchEvents>(
-          browser_plugin_instance_id(), accept));
-}
-
 #if defined(OS_MACOSX)
 void BrowserPluginGuest::OnShowPopup(
     RenderFrameHost* render_frame_host,
@@ -1119,13 +1155,4 @@
       browser_plugin_instance_id(), reverse));
 }
 
-void BrowserPluginGuest::OnTextInputStateChanged(const TextInputState& params) {
-  // Save the state of text input so we can restore it on focus.
-  last_text_input_state_.reset(new TextInputState(params));
-
-  SendTextInputTypeChangedToView(
-      static_cast<RenderWidgetHostViewBase*>(
-          web_contents()->GetRenderWidgetHostView()));
-}
-
 }  // namespace content
diff --git a/content/browser/browser_plugin/browser_plugin_guest.h b/content/browser/browser_plugin/browser_plugin_guest.h
index c788a84..f3c8d6b 100644
--- a/content/browser/browser_plugin/browser_plugin_guest.h
+++ b/content/browser/browser_plugin/browser_plugin_guest.h
@@ -31,6 +31,7 @@
 #include "build/build_config.h"
 #include "components/viz/common/surfaces/local_surface_id.h"
 #include "components/viz/common/surfaces/scoped_surface_id_allocator.h"
+#include "content/browser/renderer_host/input_event_shim.h"
 #include "content/common/edit_command.h"
 #include "content/public/browser/browser_plugin_guest_delegate.h"
 #include "content/public/browser/guest_host.h"
@@ -121,6 +122,10 @@
   // guest can navigate and resize offscreen.
   void Init();
 
+  // Returns an InputEventShim if this BrowserPluginGuest needs to intercept
+  // input events normally handled by a RenderWidgetHost.
+  InputEventShim* GetInputEventShim();
+
   // Returns a WeakPtr to this BrowserPluginGuest.
   base::WeakPtr<BrowserPluginGuest> AsWeakPtr();
 
@@ -187,6 +192,12 @@
   void DisableAutoResize();
   void DidUpdateVisualProperties(const cc::RenderFrameMetadata& metadata);
 
+  // Methods to handle events from InputEventShim.
+  void DidSetHasTouchEventHandlers(bool accept);
+  void DidTextInputStateChange(const TextInputState& params);
+  void DidLockMouse(bool user_gesture, bool privileged);
+  void DidUnlockMouse();
+
   // WebContentsObserver implementation.
   void DidFinishNavigation(NavigationHandle* navigation_handle) override;
 
@@ -268,6 +279,21 @@
  private:
   class EmbedderVisibilityObserver;
 
+  // InputEventShim implementation.
+  class InputEventShimImpl : public InputEventShim {
+   public:
+    explicit InputEventShimImpl(BrowserPluginGuest* browser_plugin_guest);
+    ~InputEventShimImpl() override;
+
+    void DidSetHasTouchEventHandlers(bool accept) override;
+    void DidTextInputStateChange(const TextInputState& params) override;
+    void DidLockMouse(bool user_gesture, bool privileged) override;
+    void DidUnlockMouse() override;
+
+   private:
+    BrowserPluginGuest* browser_plugin_guest_;
+  };
+
   // The RenderWidgetHostImpl corresponding to the owner frame of BrowserPlugin.
   RenderWidgetHostImpl* GetOwnerRenderWidgetHost() const;
 
@@ -290,8 +316,6 @@
   void OnExecuteEditCommand(int instance_id,
                             const std::string& command);
 
-  void OnLockMouse(bool user_gesture,
-                   bool privileged);
   void OnLockMouseAck(int instance_id, bool succeeded);
   // Resizes the guest's web contents.
   void OnSetFocus(int instance_id,
@@ -321,14 +345,12 @@
   // collection. See RenderThreadImpl::IdleHandler (executed when hidden) and
   // RenderThreadImpl::IdleHandlerInForegroundTab (executed when visible).
   void OnSetVisibility(int instance_id, bool visible);
-  void OnUnlockMouse();
   void OnUnlockMouseAck(int instance_id);
   void OnSynchronizeVisualProperties(
       int instance_id,
       const viz::LocalSurfaceId& local_surface_id,
       const FrameVisualProperties& visual_properties);
 
-  void OnTextInputStateChanged(const TextInputState& params);
   void OnImeSetComposition(
       int instance_id,
       const BrowserPluginHostMsg_SetComposition_Params& params);
@@ -344,7 +366,6 @@
   void OnHandleInputEventAck(
       blink::WebInputEvent::Type event_type,
       InputEventAckState ack_result);
-  void OnHasTouchEventHandlers(bool accept);
 #if defined(OS_MACOSX)
   // On MacOS X popups are painted by the browser process. We handle them here
   // so that they are positioned correctly.
@@ -376,6 +397,8 @@
   // The last tooltip that was set with SetTooltipText().
   base::string16 current_tooltip_text_;
 
+  InputEventShimImpl input_event_shim_impl_;
+
   std::unique_ptr<EmbedderVisibilityObserver> embedder_visibility_observer_;
   WebContentsImpl* owner_web_contents_;
 
diff --git a/content/browser/renderer_host/input/input_router.h b/content/browser/renderer_host/input/input_router.h
index 49cde65..bc55907 100644
--- a/content/browser/renderer_host/input/input_router.h
+++ b/content/browser/renderer_host/input/input_router.h
@@ -12,7 +12,6 @@
 #include "content/common/widget.mojom.h"
 #include "content/public/browser/native_web_keyboard_event.h"
 #include "content/public/common/input_event_ack_state.h"
-#include "ipc/ipc_listener.h"
 #include "third_party/blink/public/platform/web_input_event.h"
 
 namespace content {
@@ -21,7 +20,7 @@
 // sent to the renderer, and how responses are dispatched to the browser.
 // While the router should respect the relative order in which events are
 // received, it is free to customize when those events are dispatched.
-class InputRouter : public IPC::Listener {
+class InputRouter {
  public:
   struct CONTENT_EXPORT Config {
     Config();
@@ -29,7 +28,7 @@
     PassthroughTouchEventQueue::Config touch_config;
   };
 
-  ~InputRouter() override {}
+  virtual ~InputRouter() = default;
 
   // WebInputEvents
   virtual void SendMouseEvent(
@@ -84,6 +83,10 @@
   // frame, we set the touch action in the main frame Auto even if there is no
   // pending touch start.
   virtual void ForceSetTouchActionAuto() = 0;
+
+  // Called when the renderer notifies a change in whether or not it has touch
+  // event handlers registered.
+  virtual void OnHasTouchEventHandlers(bool has_handlers) = 0;
 };
 
 }  // namespace content
diff --git a/content/browser/renderer_host/input/input_router_client.h b/content/browser/renderer_host/input/input_router_client.h
index 01c2c1f..f8aa472f 100644
--- a/content/browser/renderer_host/input/input_router_client.h
+++ b/content/browser/renderer_host/input/input_router_client.h
@@ -40,9 +40,6 @@
   // Called each time a WebInputEvent ACK IPC is received.
   virtual void DecrementInFlightEventCount(InputEventAckSource ack_source) = 0;
 
-  // Called when the renderer notifies that it has touch event handlers.
-  virtual void OnHasTouchEventHandlers(bool has_handlers) = 0;
-
   // Called when the router has received an overscroll notification from the
   // renderer.
   virtual void DidOverscroll(const ui::DidOverscrollParams& params) = 0;
diff --git a/content/browser/renderer_host/input/input_router_impl.cc b/content/browser/renderer_host/input/input_router_impl.cc
index d50dbf0..f72a8f5 100644
--- a/content/browser/renderer_host/input/input_router_impl.cc
+++ b/content/browser/renderer_host/input/input_router_impl.cc
@@ -20,7 +20,6 @@
 #include "content/common/input/input_handler.mojom.h"
 #include "content/common/input/web_touch_event_traits.h"
 #include "content/common/input_messages.h"
-#include "content/common/view_messages.h"
 #include "content/public/browser/notification_service.h"
 #include "content/public/browser/notification_types.h"
 #include "content/public/common/content_switches.h"
@@ -271,18 +270,6 @@
   client_->SetMouseCapture(capture);
 }
 
-bool InputRouterImpl::OnMessageReceived(const IPC::Message& message) {
-  // TODO(dtapuska): Move these to mojo
-  bool handled = true;
-  IPC_BEGIN_MESSAGE_MAP(InputRouterImpl, message)
-    IPC_MESSAGE_HANDLER(ViewHostMsg_HasTouchEventHandlers,
-                        OnHasTouchEventHandlers)
-    IPC_MESSAGE_UNHANDLED(handled = false)
-  IPC_END_MESSAGE_MAP()
-
-  return handled;
-}
-
 void InputRouterImpl::SetMovementXYForTouchPoints(blink::WebTouchEvent* event) {
   for (size_t i = 0; i < event->touches_length; ++i) {
     blink::WebTouchPoint* touch_point = &event->touches[i];
@@ -596,7 +583,6 @@
 
   touch_action_filter_.OnHasTouchEventHandlers(has_handlers);
   touch_event_queue_.OnHasTouchEventHandlers(has_handlers);
-  client_->OnHasTouchEventHandlers(has_handlers);
 }
 
 void InputRouterImpl::ForceSetTouchActionAuto() {
@@ -606,6 +592,7 @@
 
 void InputRouterImpl::OnHasTouchEventHandlersForTest(bool has_handlers) {
   touch_action_filter_.OnHasTouchEventHandlers(has_handlers);
+  // TODO(ajwong): Why doesn't this change |touch_event_queue_|?
 }
 
 void InputRouterImpl::OnSetTouchAction(cc::TouchAction touch_action) {
diff --git a/content/browser/renderer_host/input/input_router_impl.h b/content/browser/renderer_host/input/input_router_impl.h
index 5aa7c74..3edcf79 100644
--- a/content/browser/renderer_host/input/input_router_impl.h
+++ b/content/browser/renderer_host/input/input_router_impl.h
@@ -99,6 +99,7 @@
       const gfx::Range& range,
       const std::vector<gfx::Rect>& bounds) override;
   void SetMouseCapture(bool capture) override;
+  void OnHasTouchEventHandlers(bool has_handlers) override;
 
   // Exposed so that tests can swap out the implementation and intercept calls.
   mojo::Binding<mojom::WidgetInputHandlerHost>&
@@ -106,9 +107,6 @@
     return frame_host_binding_;
   }
 
-  // IPC::Listener
-  bool OnMessageReceived(const IPC::Message& message) override;
-
   void OnHasTouchEventHandlersForTest(bool has_handlers);
 
  private:
@@ -202,9 +200,6 @@
       const base::Optional<ui::DidOverscrollParams>& overscroll,
       const base::Optional<cc::TouchAction>& touch_action);
 
-  // IPC message handlers
-  void OnHasTouchEventHandlers(bool has_handlers);
-
   // Called when a touch timeout-affecting bit has changed, in turn toggling the
   // touch ack timeout feature of the |touch_event_queue_| as appropriate. Input
   // to that determination includes current view properties and the allowed
diff --git a/content/browser/renderer_host/input/input_router_impl_unittest.cc b/content/browser/renderer_host/input/input_router_impl_unittest.cc
index 18f0cbce..f224ecdd 100644
--- a/content/browser/renderer_host/input/input_router_impl_unittest.cc
+++ b/content/browser/renderer_host/input/input_router_impl_unittest.cc
@@ -31,7 +31,6 @@
 #include "content/common/edit_command.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/common/content_features.h"
 #include "content/public/common/content_switches.h"
 #include "content/public/test/mock_render_process_host.h"
@@ -126,10 +125,6 @@
     input_router_client_.DecrementInFlightEventCount(ack_source);
   }
 
-  void OnHasTouchEventHandlers(bool has_handlers) override {
-    input_router_client_.OnHasTouchEventHandlers(has_handlers);
-  }
-
   void DidOverscroll(const ui::DidOverscrollParams& params) override {
     input_router_client_.DidOverscroll(params);
   }
@@ -176,10 +171,6 @@
     input_router_client_.set_input_router(input_router);
   }
 
-  bool has_touch_handler() const {
-    return input_router_client_.has_touch_handler();
-  }
-
   void set_filter_state(InputEventAckState filter_state) {
     input_router_client_.set_filter_state(filter_state);
   }
@@ -388,8 +379,7 @@
   bool HasPendingEvents() const { return input_router_->HasPendingEvents(); }
 
   void OnHasTouchEventHandlers(bool has_handlers) {
-    input_router_->OnMessageReceived(
-        ViewHostMsg_HasTouchEventHandlers(0, has_handlers));
+    input_router_->OnHasTouchEventHandlers(has_handlers);
   }
 
   void CancelTouchTimeout() { input_router_->CancelTouchTimeout(); }
@@ -718,7 +708,6 @@
 // events and the outstanding ack is received.
 TEST_F(InputRouterImplTest, TouchEventQueueFlush) {
   OnHasTouchEventHandlers(true);
-  EXPECT_TRUE(client_->has_touch_handler());
   EXPECT_EQ(0U, GetAndResetDispatchedMessages().size());
   EXPECT_TRUE(TouchEventQueueEmpty());
 
@@ -735,7 +724,6 @@
   // The page stops listening for touch-events. Note that flushing is deferred
   // until the outstanding ack is received.
   OnHasTouchEventHandlers(false);
-  EXPECT_FALSE(client_->has_touch_handler());
   EXPECT_EQ(0U, GetAndResetDispatchedMessages().size());
   EXPECT_FALSE(TouchEventQueueEmpty());
 
diff --git a/content/browser/renderer_host/input/mock_input_router_client.cc b/content/browser/renderer_host/input/mock_input_router_client.cc
index c3e8f83c..1e28ed4 100644
--- a/content/browser/renderer_host/input/mock_input_router_client.cc
+++ b/content/browser/renderer_host/input/mock_input_router_client.cc
@@ -21,7 +21,6 @@
 MockInputRouterClient::MockInputRouterClient()
     : input_router_(nullptr),
       in_flight_event_count_(0),
-      has_touch_handler_(false),
       filter_state_(INPUT_EVENT_ACK_STATE_NOT_CONSUMED),
       filter_input_event_called_(false),
       white_listed_touch_action_(cc::kTouchActionAuto) {}
@@ -45,11 +44,6 @@
   --in_flight_event_count_;
 }
 
-void MockInputRouterClient::OnHasTouchEventHandlers(
-    bool has_handlers)  {
-  has_touch_handler_ = has_handlers;
-}
-
 void MockInputRouterClient::DidOverscroll(
     const ui::DidOverscrollParams& params) {
   overscroll_ = params;
diff --git a/content/browser/renderer_host/input/mock_input_router_client.h b/content/browser/renderer_host/input/mock_input_router_client.h
index 508701d..a9e5694 100644
--- a/content/browser/renderer_host/input/mock_input_router_client.h
+++ b/content/browser/renderer_host/input/mock_input_router_client.h
@@ -30,7 +30,6 @@
       const ui::LatencyInfo& latency_info) override;
   void IncrementInFlightEventCount() override;
   void DecrementInFlightEventCount(InputEventAckSource ack_source) override;
-  void OnHasTouchEventHandlers(bool has_handlers) override;
   void DidOverscroll(const ui::DidOverscrollParams& params) override;
   void OnSetWhiteListedTouchAction(cc::TouchAction touch_action) override;
   void DidStartScrollingViewport() override;
@@ -51,7 +50,6 @@
     input_router_ = input_router;
   }
 
-  bool has_touch_handler() const { return has_touch_handler_; }
   void set_filter_state(InputEventAckState filter_state) {
     filter_state_ = filter_state;
   }
@@ -78,7 +76,6 @@
  private:
   InputRouter* input_router_;
   int in_flight_event_count_;
-  bool has_touch_handler_;
 
   InputEventAckState filter_state_;
 
diff --git a/content/browser/renderer_host/input_event_shim.h b/content/browser/renderer_host/input_event_shim.h
new file mode 100644
index 0000000..cf114414
--- /dev/null
+++ b/content/browser/renderer_host/input_event_shim.h
@@ -0,0 +1,28 @@
+// Copyright 2018 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_EVENT_SHIM_H_
+#define CONTENT_BROWSER_RENDERER_HOST_INPUT_EVENT_SHIM_H_
+
+#include "content/common/text_input_state.h"
+
+namespace content {
+
+// This exists to allow BrowserPluginGuest a safe way to intercept
+// various input event messages normally handled by RenderWidgetHost.
+//
+// TODO(https://crbug.com/533069): Remove this class and all APIs using it
+// when BrowserPlugin is fully deleted.
+class InputEventShim {
+ public:
+  virtual ~InputEventShim() {}
+  virtual void DidSetHasTouchEventHandlers(bool accept) = 0;
+  virtual void DidTextInputStateChange(const TextInputState& params) = 0;
+  virtual void DidLockMouse(bool user_gesture, bool privileged) = 0;
+  virtual void DidUnlockMouse() = 0;
+};
+
+}  // namespace content
+
+#endif /* CONTENT_BROWSER_RENDERER_HOST_INPUT_EVENT_SHIM_H_ */
diff --git a/content/browser/renderer_host/render_widget_host_delegate.cc b/content/browser/renderer_host/render_widget_host_delegate.cc
index 82ce021..af242bb 100644
--- a/content/browser/renderer_host/render_widget_host_delegate.cc
+++ b/content/browser/renderer_host/render_widget_host_delegate.cc
@@ -152,4 +152,8 @@
   return false;
 }
 
+InputEventShim* RenderWidgetHostDelegate::GetInputEventShim() const {
+  return nullptr;
+}
+
 }  // namespace content
diff --git a/content/browser/renderer_host/render_widget_host_delegate.h b/content/browser/renderer_host/render_widget_host_delegate.h
index 88340958..70130160 100644
--- a/content/browser/renderer_host/render_widget_host_delegate.h
+++ b/content/browser/renderer_host/render_widget_host_delegate.h
@@ -12,6 +12,7 @@
 
 #include "base/callback.h"
 #include "build/build_config.h"
+#include "content/browser/renderer_host/input_event_shim.h"
 #include "content/common/content_export.h"
 #include "content/common/drag_event_source_info.h"
 #include "content/public/common/drop_data.h"
@@ -314,6 +315,10 @@
   // Returns true if there is context menu shown on page.
   virtual bool IsShowingContextMenuOnPage() const;
 
+  // Returns an object that will override handling of Text Input and Mouse
+  // Lock events from the renderer.
+  virtual InputEventShim* GetInputEventShim() const;
+
  protected:
   virtual ~RenderWidgetHostDelegate() {}
 };
diff --git a/content/browser/renderer_host/render_widget_host_impl.cc b/content/browser/renderer_host/render_widget_host_impl.cc
index 807466a..26d002e 100644
--- a/content/browser/renderer_host/render_widget_host_impl.cc
+++ b/content/browser/renderer_host/render_widget_host_impl.cc
@@ -655,12 +655,11 @@
                         OnForceRedrawComplete)
     IPC_MESSAGE_HANDLER(WidgetHostMsg_FrameSwapMessages,
                         OnFrameSwapMessagesReceived)
+    IPC_MESSAGE_HANDLER(WidgetHostMsg_HasTouchEventHandlers,
+                        OnHasTouchEventHandlers)
     IPC_MESSAGE_UNHANDLED(handled = false)
   IPC_END_MESSAGE_MAP()
 
-  if (!handled && input_router_ && input_router_->OnMessageReceived(msg))
-    return true;
-
   if (!handled && view_ && view_->OnMessageReceived(msg))
     return true;
 
@@ -2297,6 +2296,11 @@
 
 void RenderWidgetHostImpl::OnTextInputStateChanged(
     const TextInputState& params) {
+  if (delegate_->GetInputEventShim()) {
+    delegate_->GetInputEventShim()->DidTextInputStateChange(params);
+    return;
+  }
+
   if (view_)
     view_->TextInputStateChanged(params);
 }
@@ -2341,6 +2345,11 @@
 
 void RenderWidgetHostImpl::OnLockMouse(bool user_gesture,
                                        bool privileged) {
+  if (delegate_->GetInputEventShim()) {
+    delegate_->GetInputEventShim()->DidLockMouse(user_gesture, privileged);
+    return;
+  }
+
   if (pending_mouse_lock_request_) {
     Send(new WidgetMsg_LockMouse_ACK(routing_id_, false));
     return;
@@ -2367,6 +2376,11 @@
 }
 
 void RenderWidgetHostImpl::OnUnlockMouse() {
+  if (delegate_->GetInputEventShim()) {
+    delegate_->GetInputEventShim()->DidUnlockMouse();
+    return;
+  }
+
   // Got unlock request from renderer. Will update |is_last_unlocked_by_target_|
   // for silent re-lock.
   const bool was_mouse_locked = !pending_mouse_lock_request_ && IsMouseLocked();
@@ -2483,6 +2497,14 @@
 }
 
 void RenderWidgetHostImpl::OnHasTouchEventHandlers(bool has_handlers) {
+  if (delegate_->GetInputEventShim()) {
+    delegate_->GetInputEventShim()->DidSetHasTouchEventHandlers(has_handlers);
+    return;
+  }
+
+  if (input_router_) {
+    input_router_->OnHasTouchEventHandlers(has_handlers);
+  }
   has_touch_handler_ = has_handlers;
 }
 
diff --git a/content/browser/renderer_host/render_widget_host_impl.h b/content/browser/renderer_host/render_widget_host_impl.h
index dba7b42..63bf1ff 100644
--- a/content/browser/renderer_host/render_widget_host_impl.h
+++ b/content/browser/renderer_host/render_widget_host_impl.h
@@ -828,6 +828,7 @@
   void OnFrameSwapMessagesReceived(uint32_t frame_token,
                                    std::vector<IPC::Message> messages);
   void OnForceRedrawComplete(int snapshot_id);
+  void OnHasTouchEventHandlers(bool has_handlers);
 
   // Called when visual properties have changed in the renderer.
   void DidUpdateVisualProperties(const cc::RenderFrameMetadata& metadata);
@@ -842,7 +843,6 @@
       const ui::LatencyInfo& latency_info) override;
   void IncrementInFlightEventCount() override;
   void DecrementInFlightEventCount(InputEventAckSource ack_source) override;
-  void OnHasTouchEventHandlers(bool has_handlers) override;
   void DidOverscroll(const ui::DidOverscrollParams& params) override;
   void DidStartScrollingViewport() override;
   void OnSetWhiteListedTouchAction(
diff --git a/content/browser/renderer_host/render_widget_host_unittest.cc b/content/browser/renderer_host/render_widget_host_unittest.cc
index 5c5bcdf..4e978d4 100644
--- a/content/browser/renderer_host/render_widget_host_unittest.cc
+++ b/content/browser/renderer_host/render_widget_host_unittest.cc
@@ -99,7 +99,7 @@
         sent_keyboard_event_(false),
         sent_gesture_event_(false),
         send_touch_event_not_cancelled_(false),
-        message_received_(false),
+        has_handlers_(false),
         client_(client) {}
   ~MockInputRouter() override {}
 
@@ -138,11 +138,8 @@
   bool FlingCancellationIsDeferred() override { return false; }
   void OnSetTouchAction(cc::TouchAction touch_action) override {}
   void ForceSetTouchActionAuto() override {}
-
-  // IPC::Listener
-  bool OnMessageReceived(const IPC::Message& message) override {
-    message_received_ = true;
-    return false;
+  void OnHasTouchEventHandlers(bool has_handlers) override {
+    has_handlers_ = has_handlers;
   }
 
   bool sent_mouse_event_;
@@ -150,7 +147,7 @@
   bool sent_keyboard_event_;
   bool sent_gesture_event_;
   bool send_touch_event_not_cancelled_;
-  bool message_received_;
+  bool has_handlers_;
 
  private:
   InputRouterClient* client_;
@@ -1791,9 +1788,10 @@
 TEST_F(RenderWidgetHostTest, InputRouterReceivesHasTouchEventHandlers) {
   host_->SetupForInputRouterTest();
 
-  host_->OnMessageReceived(ViewHostMsg_HasTouchEventHandlers(0, true));
+  ASSERT_FALSE(host_->mock_input_router()->has_handlers_);
 
-  EXPECT_TRUE(host_->mock_input_router()->message_received_);
+  host_->OnMessageReceived(WidgetHostMsg_HasTouchEventHandlers(0, true));
+  EXPECT_TRUE(host_->mock_input_router()->has_handlers_);
 }
 
 void CheckLatencyInfoComponentInMessage(
@@ -1831,7 +1829,7 @@
 // ui::INPUT_EVENT_LATENCY_BEGIN_RWH_COMPONENT will always present in the
 // event's LatencyInfo.
 TEST_F(RenderWidgetHostTest, InputEventRWHLatencyComponent) {
-  host_->OnMessageReceived(ViewHostMsg_HasTouchEventHandlers(0, true));
+  host_->OnMessageReceived(WidgetHostMsg_HasTouchEventHandlers(0, true));
 
   // Tests RWHI::ForwardWheelEvent().
   SimulateWheelEvent(-5, 0, 0, true, WebMouseWheelEvent::kPhaseBegan);
@@ -2030,7 +2028,7 @@
 // Tests that event dispatch after the delegate has been detached doesn't cause
 // a crash. See crbug.com/563237.
 TEST_F(RenderWidgetHostTest, EventDispatchPostDetach) {
-  host_->OnMessageReceived(ViewHostMsg_HasTouchEventHandlers(0, true));
+  host_->OnMessageReceived(WidgetHostMsg_HasTouchEventHandlers(0, true));
   process_->sink().ClearMessages();
 
   host_->DetachDelegate();
diff --git a/content/browser/renderer_host/render_widget_host_view_aura_unittest.cc b/content/browser/renderer_host/render_widget_host_view_aura_unittest.cc
index 50d09e6..7b1c39a 100644
--- a/content/browser/renderer_host/render_widget_host_view_aura_unittest.cc
+++ b/content/browser/renderer_host/render_widget_host_view_aura_unittest.cc
@@ -1500,7 +1500,8 @@
   view_->Show();
 
   // Start with no touch-event handler in the renderer.
-  widget_host_->OnMessageReceived(ViewHostMsg_HasTouchEventHandlers(0, false));
+  widget_host_->OnMessageReceived(
+      WidgetHostMsg_HasTouchEventHandlers(0, false));
 
   ui::TouchEvent press(
       ui::ET_TOUCH_PRESSED, gfx::Point(30, 30), ui::EventTimeForNow(),
@@ -1540,7 +1541,7 @@
   // Now install some touch-event handlers and do the same steps. The touch
   // events should now be consumed. However, the touch-event state should be
   // updated as before.
-  widget_host_->OnMessageReceived(ViewHostMsg_HasTouchEventHandlers(0, true));
+  widget_host_->OnMessageReceived(WidgetHostMsg_HasTouchEventHandlers(0, true));
 
   view_->OnTouchEvent(&press);
   base::RunLoop().RunUntilIdle();
@@ -1569,7 +1570,8 @@
   events = GetAndResetDispatchedMessages();
   EXPECT_EQ(3U, events.size());
 
-  widget_host_->OnMessageReceived(ViewHostMsg_HasTouchEventHandlers(0, false));
+  widget_host_->OnMessageReceived(
+      WidgetHostMsg_HasTouchEventHandlers(0, false));
 
   // All outstanding events should have already been sent but no new events
   // should get sent.
@@ -2576,7 +2578,7 @@
   view_->InitAsChild(nullptr);
   view_->Show();
 
-  widget_host_->OnMessageReceived(ViewHostMsg_HasTouchEventHandlers(0, true));
+  widget_host_->OnMessageReceived(WidgetHostMsg_HasTouchEventHandlers(0, true));
 
   ui::TouchEvent press(
       ui::ET_TOUCH_PRESSED, gfx::Point(30, 30), ui::EventTimeForNow(),
@@ -4684,7 +4686,7 @@
 // gesture deals with them correctly.
 TEST_F(RenderWidgetHostViewAuraOverscrollTest, OverscrollWithTouchEvents) {
   SetUpOverscrollEnvironmentWithDebounce(10);
-  widget_host_->OnMessageReceived(ViewHostMsg_HasTouchEventHandlers(0, true));
+  widget_host_->OnMessageReceived(WidgetHostMsg_HasTouchEventHandlers(0, true));
 
   // The test sends an intermingled sequence of touch and gesture events.
   PressTouchPoint(0, 1);
@@ -4808,7 +4810,7 @@
 TEST_F(RenderWidgetHostViewAuraOverscrollTest,
        TouchGestureEndDispatchedAfterOverscrollComplete) {
   SetUpOverscrollEnvironmentWithDebounce(10);
-  widget_host_->OnMessageReceived(ViewHostMsg_HasTouchEventHandlers(0, true));
+  widget_host_->OnMessageReceived(WidgetHostMsg_HasTouchEventHandlers(0, true));
 
   PressAndSetTouchActionAuto();
   // Start scrolling. Receive ACK as it being processed.
@@ -5391,7 +5393,7 @@
   view_->InitAsChild(nullptr);
   view_->Show();
 
-  widget_host_->OnMessageReceived(ViewHostMsg_HasTouchEventHandlers(0, true));
+  widget_host_->OnMessageReceived(WidgetHostMsg_HasTouchEventHandlers(0, true));
 
   ui::TouchEvent press(
       ui::ET_TOUCH_PRESSED, gfx::Point(30, 30), ui::EventTimeForNow(),
diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc
index 8ce6d0d..7bc8f7b 100644
--- a/content/browser/web_contents/web_contents_impl.cc
+++ b/content/browser/web_contents/web_contents_impl.cc
@@ -3305,6 +3305,16 @@
   auto_resize_size_ = gfx::Size();
 }
 
+InputEventShim* WebContentsImpl::GetInputEventShim() const {
+  // The only thing that intercepts text input and mouse lock is the
+  // BrowserPluginGuest. Delegate to the BrowserPluginGuest logic for
+  // whether or not it needs to shim these events.
+  if (browser_plugin_guest_) {
+    return browser_plugin_guest_->GetInputEventShim();
+  }
+  return nullptr;
+}
+
 WebContents* WebContentsImpl::OpenURL(const OpenURLParams& params) {
   if (!delegate_) {
     // Embedder can delay setting a delegate on new WebContents with
diff --git a/content/browser/web_contents/web_contents_impl.h b/content/browser/web_contents/web_contents_impl.h
index 83f28751..980b7f3 100644
--- a/content/browser/web_contents/web_contents_impl.h
+++ b/content/browser/web_contents/web_contents_impl.h
@@ -707,6 +707,7 @@
                              const gfx::Size& new_size) override;
   gfx::Size GetAutoResizeSize() override;
   void ResetAutoResizeSize() override;
+  InputEventShim* GetInputEventShim() const override;
 
 #if !defined(OS_ANDROID)
   double GetPendingPageZoomLevel() const override;
diff --git a/content/common/view_messages.h b/content/common/view_messages.h
index e931fc0..32b1f5b1 100644
--- a/content/common/view_messages.h
+++ b/content/common/view_messages.h
@@ -286,10 +286,6 @@
 IPC_MESSAGE_ROUTED1(ViewHostMsg_DidContentsPreferredSizeChange,
                     gfx::Size /* pref_size */)
 
-// Notifies whether there are JavaScript touch event handlers or not.
-IPC_MESSAGE_ROUTED1(ViewHostMsg_HasTouchEventHandlers,
-                    bool /* has_handlers */)
-
 #if BUILDFLAG(ENABLE_PLUGINS)
 // A renderer sends this to the browser process when it wants to access a PPAPI
 // broker. In contrast to FrameHostMsg_OpenChannelToPpapiBroker, this is called
diff --git a/content/common/widget_messages.h b/content/common/widget_messages.h
index 1eafbbab..d5f6191 100644
--- a/content/common/widget_messages.h
+++ b/content/common/widget_messages.h
@@ -316,4 +316,8 @@
 // Sent in reply to WidgetMsg_WaitForNextFrameForTests.
 IPC_MESSAGE_ROUTED0(WidgetHostMsg_WaitForNextFrameForTests_ACK)
 
+// Notifies whether there are JavaScript touch event handlers or not.
+IPC_MESSAGE_ROUTED1(WidgetHostMsg_HasTouchEventHandlers,
+                    bool /* has_handlers */)
+
 #endif  //  CONTENT_COMMON_WIDGET_MESSAGES_H_
diff --git a/content/renderer/render_widget.cc b/content/renderer/render_widget.cc
index ee2ea08..f104196 100644
--- a/content/renderer/render_widget.cc
+++ b/content/renderer/render_widget.cc
@@ -2907,7 +2907,7 @@
   has_touch_handlers_ = has_handlers;
   if (render_widget_scheduling_state_)
     render_widget_scheduling_state_->SetHasTouchHandler(has_handlers);
-  Send(new ViewHostMsg_HasTouchEventHandlers(routing_id_, has_handlers));
+  Send(new WidgetHostMsg_HasTouchEventHandlers(routing_id_, has_handlers));
 }
 
 void RenderWidget::SetNeedsLowLatencyInput(bool needs_low_latency) {