[exo] Relax image drag/drop conditions for touch tab dragging

Tab drag/drop does not have drag images associated with it.

BUG=1140736
R=oshima@chromium.org

Change-Id: If613d4e4edc9a349d65cdf049d2d4972cfbabd56
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3035903
Commit-Queue: Antonio Gomes <tonikitoo@igalia.com>
Reviewed-by: Mitsuru Oshima (catching up) <oshima@chromium.org>
Cr-Commit-Position: refs/heads/master@{#903876}
diff --git a/ash/drag_drop/drag_drop_controller.cc b/ash/drag_drop/drag_drop_controller.cc
index 9aabdee..ed44b65 100644
--- a/ash/drag_drop/drag_drop_controller.cc
+++ b/ash/drag_drop/drag_drop_controller.cc
@@ -172,10 +172,13 @@
     return DragOperation::kNone;
 
   const ui::OSExchangeDataProvider* provider = &data->provider();
-  // We do not support touch drag/drop without a drag image.
+  // We do not support touch drag/drop without a drag image, unless it is a tab
+  // drag/drop.
   if (source == ui::mojom::DragEventSource::kTouch &&
-      provider->GetDragImage().size().IsEmpty())
+      provider->GetDragImage().size().IsEmpty() &&
+      !toplevel_window_drag_delegate_) {
     return DragOperation::kNone;
+  }
 
   operation_ = DragOperation::kNone;
   current_drag_event_source_ = source;
@@ -383,16 +386,20 @@
   if (current_drag_event_source_ != ui::mojom::DragEventSource::kTouch)
     return;
 
-  // Apply kTouchDragImageVerticalOffset to the location.
+  // Apply kTouchDragImageVerticalOffset to the location, if it is not a tab
+  // drag/drop.
   ui::GestureEvent touch_offset_event(*event,
                                       static_cast<aura::Window*>(nullptr),
                                       static_cast<aura::Window*>(nullptr));
-  gfx::PointF touch_offset_location = touch_offset_event.location_f();
-  gfx::PointF touch_offset_root_location = touch_offset_event.root_location_f();
-  touch_offset_location.Offset(0, kTouchDragImageVerticalOffset);
-  touch_offset_root_location.Offset(0, kTouchDragImageVerticalOffset);
-  touch_offset_event.set_location_f(touch_offset_location);
-  touch_offset_event.set_root_location_f(touch_offset_root_location);
+  if (!toplevel_window_drag_delegate_) {
+    gfx::PointF touch_offset_location = touch_offset_event.location_f();
+    gfx::PointF touch_offset_root_location =
+        touch_offset_event.root_location_f();
+    touch_offset_location.Offset(0, kTouchDragImageVerticalOffset);
+    touch_offset_root_location.Offset(0, kTouchDragImageVerticalOffset);
+    touch_offset_event.set_location_f(touch_offset_location);
+    touch_offset_event.set_root_location_f(touch_offset_root_location);
+  }
 
   aura::Window* translated_target =
       drag_drop_tracker_->GetTarget(touch_offset_event);
diff --git a/ash/drag_drop/drag_drop_controller_unittest.cc b/ash/drag_drop/drag_drop_controller_unittest.cc
index c871fc0..060d3b7e4 100644
--- a/ash/drag_drop/drag_drop_controller_unittest.cc
+++ b/ash/drag_drop/drag_drop_controller_unittest.cc
@@ -1503,6 +1503,29 @@
   }
 }
 
+TEST_F(DragDropControllerTest, ToplevelWindowDragDelegateWithTouch) {
+  std::unique_ptr<aura::Window> window(CreateTestWindowInShellWithDelegate(
+      aura::test::TestWindowDelegate::CreateSelfDestroyingDelegate(), -1,
+      gfx::Rect(0, 0, 100, 100)));
+
+  // Emulate a full drag and drop flow and verify that toplevel window drag
+  // delegate gets notified about the events as expected.
+  TestToplevelWindowDragDelegate delegate;
+  drag_drop_controller_->set_toplevel_window_drag_delegate(&delegate);
+
+  auto data(std::make_unique<ui::OSExchangeData>());
+  drag_drop_controller_->StartDragAndDrop(
+      std::move(data), window->GetRootWindow(), window.get(), gfx::Point(5, 5),
+      ui::DragDropTypes::DRAG_MOVE, ui::mojom::DragEventSource::kTouch);
+
+  EXPECT_EQ(TestToplevelWindowDragDelegate::State::kDragStartedInvoked,
+            delegate.state());
+  EXPECT_EQ(ui::mojom::DragEventSource::kTouch, delegate.source());
+  EXPECT_TRUE(delegate.current_location().has_value());
+  EXPECT_EQ(gfx::PointF(5, 5), *delegate.current_location());
+  EXPECT_EQ(0, delegate.events_forwarded());
+}
+
 namespace {
 
 class MockDataTransferPolicyController