wayland: retain origin surface on fallback window drag sessions

Even though not explicitly mentioned in the Wayland spec, most
compositors end the drag session (by emitting wl_data_source.cancelled)
if the origin surface for a dnd session gets destroyed in the middle of
the process.

To fix it, patches WaylandDataDragController to retain the origin
surface until the drag session actually quits, which is already done by
WaylandWindowDragController.

R=max@igalia.com

Bug: 356565284
Change-Id: If95cc8b6a3061c9a6d70c420a8cb002967fc5400
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5753304
Reviewed-by: Max Ihlenfeldt <max@igalia.com>
Commit-Queue: Max Ihlenfeldt <max@igalia.com>
Auto-Submit: Nick Yamane <nickdiego@igalia.com>
Cr-Commit-Position: refs/heads/main@{#1336537}
diff --git a/ui/ozone/platform/wayland/host/wayland_data_drag_controller.cc b/ui/ozone/platform/wayland/host/wayland_data_drag_controller.cc
index 38b15cf..148b9ae 100644
--- a/ui/ozone/platform/wayland/host/wayland_data_drag_controller.cc
+++ b/ui/ozone/platform/wayland/host/wayland_data_drag_controller.cc
@@ -571,6 +571,10 @@
   }
 
   if (window == origin_window_) {
+    // See the declaration of TakeWaylandSurface() for why this is needed.
+    if (IsWindowDragSessionRunning()) {
+      origin_surface_ = origin_window_->TakeWaylandSurface();
+    }
     origin_window_ = nullptr;
   }
 
@@ -699,6 +703,8 @@
 
   data_source_.reset();
   data_offer_.reset();
+  origin_window_ = nullptr;
+  origin_surface_.reset();
   icon_buffer_.reset();
   icon_surface_.reset();
   icon_surface_buffer_scale_ = 1.0f;
diff --git a/ui/ozone/platform/wayland/host/wayland_data_drag_controller.h b/ui/ozone/platform/wayland/host/wayland_data_drag_controller.h
index 93ef858..fd64ade 100644
--- a/ui/ozone/platform/wayland/host/wayland_data_drag_controller.h
+++ b/ui/ozone/platform/wayland/host/wayland_data_drag_controller.h
@@ -279,6 +279,8 @@
   // has been started by an external Wayland client.
   raw_ptr<WaylandWindow> origin_window_ = nullptr;
 
+  std::unique_ptr<WaylandSurface> origin_surface_;
+
   // Current window under pointer.
   raw_ptr<WaylandWindow, DanglingUntriaged> window_ = nullptr;
 
diff --git a/ui/ozone/platform/wayland/host/wayland_window.h b/ui/ozone/platform/wayland/host/wayland_window.h
index 21ba2e69..947b14e 100644
--- a/ui/ozone/platform/wayland/host/wayland_window.h
+++ b/ui/ozone/platform/wayland/host/wayland_window.h
@@ -60,6 +60,7 @@
 class WaylandBubble;
 class WaylandConnection;
 class WaylandSubsurface;
+class WaylandDataDragController;
 class WaylandWindowDragController;
 class WaylandFrameManager;
 class WaylandPopup;
@@ -550,13 +551,15 @@
   virtual bool OnInitialize(PlatformWindowInitProperties properties,
                             PlatformWindowDelegate::State* state) = 0;
 
-  // WaylandWindowDragController might need to take ownership of the wayland
-  // surface whether the window that originated the DND session gets destroyed
-  // in the middle of that session (e.g: when it is snapped into a tab strip).
-  // Surface ownership is allowed to be taken only when the window is under
-  // destruction, i.e: |shutting_down_| is set. This can be done, for example,
-  // by implementing |WaylandWindowObserver::OnWindowRemoved|.
+  // Drag controllers might need to take ownership of the dnd origin surface
+  // when its associated window gets closed in the middle of the session (e.g:
+  // in the process of being snapped into a tab strip) to prevent the drag
+  // session from getting cancelled abruptly by the Wayland compositor. Surface
+  // ownership is allowed to be transferred only when the window is already
+  // under destruction (i.e: |shutting_down_| is set) which can be done, for
+  // example, by implementing |WaylandWindowObserver::OnWindowRemoved|.
   friend WaylandWindowDragController;
+  friend WaylandDataDragController;
   std::unique_ptr<WaylandSurface> TakeWaylandSurface();
 
   void UpdateCursorShape(scoped_refptr<BitmapCursor> cursor);
diff --git a/ui/ozone/platform/wayland/host/wayland_window_drag_controller.cc b/ui/ozone/platform/wayland/host/wayland_window_drag_controller.cc
index 9079d65..2e95a32 100644
--- a/ui/ozone/platform/wayland/host/wayland_window_drag_controller.cc
+++ b/ui/ozone/platform/wayland/host/wayland_window_drag_controller.cc
@@ -548,6 +548,7 @@
   }
 
   if (window == origin_window_) {
+    // See the declaration of TakeWaylandSurface() for why this is needed.
     origin_surface_ = origin_window_->TakeWaylandSurface();
     origin_window_ = nullptr;
   }