[ui_controls] Refactor InputDispatcher's memory model.

Extracted from https://chromium-review.googlesource.com/c/chromium/src/+/1392178

Removes manual ref-counting in favor of just-in-time creation + unique
self ownership. Required for WeakPtr scheme in follow-up CL.

Note: Patch set 1 tried to add checks that confirm the pre-existing assumptions
made by InputDispatcher (i.e. that the input was successfully sent) but some
scenarios fail those tests. To be investigated as a follow-up.

R=grt@chromium.org, sadrul@chromium.org

Bug: 892228, 640996
Change-Id: Ia1df67e809845a228c4a9a6b77da08de037cf621
Reviewed-on: https://chromium-review.googlesource.com/c/1400950
Reviewed-by: Sadrul Chowdhury <sadrul@chromium.org>
Reviewed-by: Greg Thompson <grt@chromium.org>
Commit-Queue: Gabriel Charette <gab@chromium.org>
Cr-Commit-Position: refs/heads/master@{#621639}
diff --git a/ui/base/test/ui_controls_internal_win.cc b/ui/base/test/ui_controls_internal_win.cc
index 45e2493..4ba5e90 100644
--- a/ui/base/test/ui_controls_internal_win.cc
+++ b/ui/base/test/ui_controls_internal_win.cc
@@ -13,8 +13,6 @@
 #include "base/location.h"
 #include "base/logging.h"
 #include "base/macros.h"
-#include "base/memory/ref_counted.h"
-#include "base/memory/scoped_refptr.h"
 #include "base/single_thread_task_runner.h"
 #include "base/test/test_timeouts.h"
 #include "base/threading/thread_checker.h"
@@ -31,35 +29,24 @@
 // InputDispatcher is used to listen for a mouse/keyboard event. Only one
 // instance may be alive at a time. The callback is run when the appropriate
 // event is received.
-class InputDispatcher : public base::RefCounted<InputDispatcher> {
+class InputDispatcher {
  public:
-  // Constructs a dispatcher that will invoke |callback| when |message_type| is
-  // received. The returned instance does not hold a ref on itself to keep it
-  // alive while waiting for messages. The caller is responsible for adding one
-  // ref before returning to the message loop. The instance will release this
-  // reference when the message is received.
-  static scoped_refptr<InputDispatcher> CreateForMessage(
-      WPARAM message_type,
-      base::OnceClosure callback);
+  // Constructs an InputDispatcher that will invoke |callback| when
+  // |message_type| is received. This must be invoked on thread, after the input
+  // is sent but before it is processed.
+  static void CreateForMessage(WPARAM message_type, base::OnceClosure callback);
 
   // Constructs a dispatcher that will invoke |callback| when a mouse move
   // message has been received. Upon receipt, an error message is logged if the
   // destination of the move is not |screen_point|. |callback| is run regardless
   // after a sufficiently long delay. This generally happens when another
   // process has a window over the test's window, or if |screen_point| is not
-  // over a window owned by the test. The returned instance does not hold a ref
-  // on itself to keep it alive while waiting for messages. The caller is
-  // responsible for adding one ref before returning to the message loop. The
-  // instance will release this reference when the message is received.
-  static scoped_refptr<InputDispatcher> CreateForMouseMove(
-      const gfx::Point& screen_point,
-      base::OnceClosure callback);
+  // over a window owned by the test. This must be invoked on thread, after the
+  // input is sent but before it is processed.
+  static void CreateForMouseMove(const gfx::Point& screen_point,
+                                 base::OnceClosure callback);
 
  private:
-  template <typename T, typename... Args>
-  friend scoped_refptr<T> base::MakeRefCounted(Args&&... args);
-  friend class base::RefCounted<InputDispatcher>;
-
   InputDispatcher(WPARAM message_waiting_for,
                   const gfx::Point& screen_point,
                   base::OnceClosure callback);
@@ -68,9 +55,6 @@
   // Installs the dispatcher as the current hook.
   void InstallHook();
 
-  // Uninstalls the hook set in InstallHook.
-  void UninstallHook();
-
   // Callback from hook when a mouse message is received.
   static LRESULT CALLBACK MouseHook(int n_code, WPARAM w_param, LPARAM l_param);
 
@@ -103,7 +87,7 @@
   // The callback to run when the desired message is received.
   base::OnceClosure callback_;
 
-  // The message on which the instance is waiting -- unsed for WM_KEYUP
+  // The message on which the instance is waiting -- unused for WM_KEYUP
   // messages.
   const WPARAM message_waiting_for_;
 
@@ -122,20 +106,19 @@
 HHOOK InputDispatcher::next_hook_ = nullptr;
 
 // static
-scoped_refptr<InputDispatcher> InputDispatcher::CreateForMessage(
-    WPARAM message_type,
-    base::OnceClosure callback) {
+void InputDispatcher::CreateForMessage(WPARAM message_type,
+                                       base::OnceClosure callback) {
   DCHECK_NE(message_type, static_cast<WPARAM>(WM_MOUSEMOVE));
-  return base::MakeRefCounted<InputDispatcher>(message_type, gfx::Point(0, 0),
-                                               std::move(callback));
+
+  // Owns self.
+  new InputDispatcher(message_type, gfx::Point(0, 0), std::move(callback));
 }
 
 // static
-scoped_refptr<InputDispatcher> InputDispatcher::CreateForMouseMove(
-    const gfx::Point& screen_point,
-    base::OnceClosure callback) {
-  return base::MakeRefCounted<InputDispatcher>(WM_MOUSEMOVE, screen_point,
-                                               std::move(callback));
+void InputDispatcher::CreateForMouseMove(const gfx::Point& screen_point,
+                                         base::OnceClosure callback) {
+  // Owns self.
+  new InputDispatcher(WM_MOUSEMOVE, screen_point, std::move(callback));
 }
 
 InputDispatcher::InputDispatcher(WPARAM message_waiting_for,
@@ -150,7 +133,10 @@
 
 InputDispatcher::~InputDispatcher() {
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  UninstallHook();
+  DCHECK_EQ(current_dispatcher_, this);
+  current_dispatcher_ = nullptr;
+  UnhookWindowsHookEx(next_hook_);
+  next_hook_ = nullptr;
 }
 
 void InputDispatcher::InstallHook() {
@@ -183,16 +169,6 @@
   DCHECK(next_hook_);
 }
 
-void InputDispatcher::UninstallHook() {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  if (current_dispatcher_ == this) {
-    current_dispatcher_ = nullptr;
-    UnhookWindowsHookEx(next_hook_);
-    next_hook_ = nullptr;
-    weak_factory_.InvalidateWeakPtrs();
-  }
-}
-
 // static
 LRESULT CALLBACK InputDispatcher::MouseHook(int n_code,
                                             WPARAM w_param,
@@ -254,12 +230,12 @@
 
 void InputDispatcher::MatchingMessageFound() {
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  UninstallHook();
+
   // The hook proc is invoked before the message is process. Post a task to run
   // the callback so that handling of this event completes first.
   base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
                                                 std::move(callback_));
-  Release();
+  delete this;
 }
 
 void InputDispatcher::OnTimeout() {
@@ -377,10 +353,6 @@
   if (window && ::GetForegroundWindow() != target_window)
     return false;
 
-  scoped_refptr<InputDispatcher> dispatcher;
-  if (task)
-    dispatcher = InputDispatcher::CreateForMessage(WM_KEYUP, std::move(task));
-
   // If a pop-up menu is open, it won't receive events sent using SendInput.
   // Check for a pop-up menu using its window class (#32768) and if one
   // exists, send the key event directly there.
@@ -391,8 +363,8 @@
     ::SendMessage(popup_menu, WM_KEYDOWN, w_param, l_param);
     ::SendMessage(popup_menu, WM_KEYUP, w_param, l_param);
 
-    if (dispatcher)
-      dispatcher->AddRef();
+    if (task)
+      InputDispatcher::CreateForMessage(WM_KEYUP, std::move(task));
     return true;
   }
 
@@ -411,9 +383,8 @@
     return false;
   }
 
-  if (dispatcher)
-    dispatcher->AddRef();
-
+  if (task)
+    InputDispatcher::CreateForMessage(WM_KEYUP, std::move(task));
   return true;
 }
 
@@ -457,18 +428,11 @@
       static_cast<LONG>(std::max(1.0, std::ceil(screen_y * (65535.0 / max_y))));
   input.mi.dwFlags = MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_MOVE;
 
-  scoped_refptr<InputDispatcher> dispatcher;
-  if (task) {
-    dispatcher = InputDispatcher::CreateForMouseMove({screen_x, screen_y},
-                                                     std::move(task));
-  }
-
   if (!::SendInput(1, &input, sizeof(input)))
     return false;
 
-  if (dispatcher)
-    dispatcher->AddRef();
-
+  if (task)
+    InputDispatcher::CreateForMouseMove({screen_x, screen_y}, std::move(task));
   return true;
 }
 
@@ -504,10 +468,6 @@
       return false;
   }
 
-  scoped_refptr<InputDispatcher> dispatcher;
-  if (task)
-    dispatcher = InputDispatcher::CreateForMessage(last_event, std::move(task));
-
   std::vector<INPUT> input;
   if (button_state & DOWN) {
     AppendAcceleratorInputs(accelerator_state & kControl,
@@ -531,9 +491,8 @@
     return false;
   }
 
-  if (dispatcher)
-    dispatcher->AddRef();
-
+  if (task)
+    InputDispatcher::CreateForMessage(last_event, std::move(task));
   return true;
 }