Coordinate cursor updates from multiple renderers on a single page

Currently each RenderWidget sends cursor update messages independently
based on its last seen mouse position, with no awareness of other
RenderWidgets overriding the mouse cursor. This causes problem due to
race conditions where RenderWidgets in multiple renderer processes are
changing the cursor graphic as the user moves the mouse, and also
creates inconsistency because a RenderWidget does not know that a
different RenderWidget has modified the cursor.

This CL adds a CursorManager class to content, which tracks the last
cursor update received by each RenderWidgetHostView, and signals the
root RWHV to show the correct cursor for the view that the mouse is
currently over.

Bug: 614540, 545237
Cq-Include-Trybots: master.tryserver.chromium.linux:linux_site_isolation
Change-Id: Id7355b69f13f9e13a5113b5f63228ddf067352ed
Reviewed-on: https://chromium-review.googlesource.com/558271
Commit-Queue: Ken Buchanan <[email protected]>
Reviewed-by: Alex Moshchuk <[email protected]>
Cr-Commit-Position: refs/heads/master@{#486528}
diff --git a/content/browser/renderer_host/cursor_manager.h b/content/browser/renderer_host/cursor_manager.h
new file mode 100644
index 0000000..d1480279
--- /dev/null
+++ b/content/browser/renderer_host/cursor_manager.h
@@ -0,0 +1,59 @@
+// Copyright (c) 2017 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_CURSOR_MANAGER_H_
+#define CONTENT_BROWSER_RENDERER_HOST_CURSOR_MANAGER_H_
+
+#include <map>
+
+#include "content/common/content_export.h"
+#include "content/common/cursors/webcursor.h"
+
+namespace content {
+
+class RenderWidgetHostViewBase;
+
+// CursorManager coordinates mouse cursors for multiple RenderWidgetHostViews
+// on a single page. It is owned by the top-level RenderWidgetHostView and
+// calls back to its DisplayCursor method when the cursor needs to change,
+// either because the mouse moved over a different view or because a cursor
+// update was received for the current view.
+class CONTENT_EXPORT CursorManager {
+ public:
+  CursorManager(RenderWidgetHostViewBase* root);
+  ~CursorManager();
+
+  // Called for any RenderWidgetHostView that received an UpdateCursor message
+  // from its renderer process.
+  void UpdateCursor(RenderWidgetHostViewBase*, const WebCursor&);
+
+  // Called when the mouse moves over a different RenderWidgetHostView.
+  void UpdateViewUnderCursor(RenderWidgetHostViewBase*);
+
+  // Notification of a RenderWidgetHostView being destroyed, so that its
+  // cursor map entry can be removed if it has one. If it is the current
+  // view_under_cursor_, then the root_view_'s cursor will be displayed.
+  void ViewBeingDestroyed(RenderWidgetHostViewBase*);
+
+  // Accessor for browser tests, enabling verification of the cursor_map_.
+  // Returns false if the provided View is not in the map, and outputs
+  // the cursor otherwise.
+  bool GetCursorForTesting(RenderWidgetHostViewBase*, WebCursor&);
+
+ private:
+  // Stores the last received cursor from each RenderWidgetHostView.
+  std::map<RenderWidgetHostViewBase*, WebCursor> cursor_map_;
+
+  // The view currently underneath the cursor, which corresponds to the cursor
+  // currently displayed.
+  RenderWidgetHostViewBase* view_under_cursor_;
+
+  // The root view is the target for DisplayCursor calls whenever the active
+  // cursor needs to change.
+  RenderWidgetHostViewBase* root_view_;
+};
+
+}  // namespace content
+
+#endif  // CONTENT_BROWSER_RENDERER_HOST_CURSOR_MANAGER_H_
\ No newline at end of file