x11-ozone-fix-two-edge-cases.patch 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136
  1. From 5e3a738b1204941aab9f15c0eb3d06e20fefd96e Mon Sep 17 00:00:00 2001
  2. From: Scott Violet <sky@chromium.org>
  3. Date: Mon, 8 Mar 2021 21:07:39 +0000
  4. Subject: [PATCH] x11/ozone: fix two edge cases
  5. WindowTreeHost::OnHostMovedInPixels() may trigger a nested message
  6. loop (tab dragging), which when the stack unravels means this may
  7. be deleted. This adds an early out if this happens.
  8. X11WholeScreenMoveLoop has a similar issue, in so far as notifying
  9. the delegate may delete this.
  10. BUG=1185482
  11. TEST=WindowTreeHostPlatform.DeleteHostFromOnHostMovedInPixels
  12. Change-Id: Ieca1c90b3e4358da50b332abe2941fdbb50c5c25
  13. Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2743555
  14. Reviewed-by: Thomas Anderson <thomasanderson@chromium.org>
  15. Commit-Queue: Scott Violet <sky@chromium.org>
  16. Cr-Commit-Position: refs/heads/master@{#860852}
  17. ---
  18. ui/aura/window_tree_host_platform.cc | 10 ++++-
  19. ui/aura/window_tree_host_platform_unittest.cc | 40 ++++++++++++++++++-
  20. ui/base/x/x11_whole_screen_move_loop.cc | 4 ++
  21. 3 files changed, 51 insertions(+), 3 deletions(-)
  22. diff --git a/ui/aura/window_tree_host_platform.cc b/ui/aura/window_tree_host_platform.cc
  23. index ce8395fe07..7589542026 100644
  24. --- a/ui/aura/window_tree_host_platform.cc
  25. +++ b/ui/aura/window_tree_host_platform.cc
  26. @@ -214,13 +214,21 @@ void WindowTreeHostPlatform::OnBoundsChanged(const gfx::Rect& new_bounds) {
  27. float current_scale = compositor()->device_scale_factor();
  28. float new_scale = ui::GetScaleFactorForNativeView(window());
  29. gfx::Rect old_bounds = bounds_in_pixels_;
  30. + auto weak_ref = GetWeakPtr();
  31. bounds_in_pixels_ = new_bounds;
  32. - if (bounds_in_pixels_.origin() != old_bounds.origin())
  33. + if (bounds_in_pixels_.origin() != old_bounds.origin()) {
  34. OnHostMovedInPixels(bounds_in_pixels_.origin());
  35. + // Changing the bounds may destroy this.
  36. + if (!weak_ref)
  37. + return;
  38. + }
  39. if (bounds_in_pixels_.size() != old_bounds.size() ||
  40. current_scale != new_scale) {
  41. pending_size_ = gfx::Size();
  42. OnHostResizedInPixels(bounds_in_pixels_.size());
  43. + // Changing the size may destroy this.
  44. + if (!weak_ref)
  45. + return;
  46. }
  47. DCHECK_GT(on_bounds_changed_recursion_depth_, 0);
  48. if (--on_bounds_changed_recursion_depth_ == 0) {
  49. diff --git a/ui/aura/window_tree_host_platform_unittest.cc b/ui/aura/window_tree_host_platform_unittest.cc
  50. index eda14e2f0c..4de039c88a 100644
  51. --- a/ui/aura/window_tree_host_platform_unittest.cc
  52. +++ b/ui/aura/window_tree_host_platform_unittest.cc
  53. @@ -34,7 +34,7 @@ class TestWindowTreeHost : public WindowTreeHostPlatform {
  54. // OnHostWill/DidProcessBoundsChange. Additionally, this triggers a bounds
  55. // change from within OnHostResized(). Such a scenario happens in production
  56. // code.
  57. -class TestWindowTreeHostObserver : public aura::WindowTreeHostObserver {
  58. +class TestWindowTreeHostObserver : public WindowTreeHostObserver {
  59. public:
  60. TestWindowTreeHostObserver(WindowTreeHostPlatform* host,
  61. ui::PlatformWindow* platform_window)
  62. @@ -51,7 +51,7 @@ class TestWindowTreeHostObserver : public aura::WindowTreeHostObserver {
  63. return on_host_will_process_bounds_change_count_;
  64. }
  65. - // aura::WindowTreeHostObserver:
  66. + // WindowTreeHostObserver:
  67. void OnHostResized(WindowTreeHost* host) override {
  68. if (!should_change_bounds_in_on_resized_)
  69. return;
  70. @@ -92,5 +92,41 @@ TEST_F(WindowTreeHostPlatformTest, HostWillProcessBoundsChangeRecursion) {
  71. EXPECT_EQ(1, observer.on_host_will_process_bounds_change_count());
  72. }
  73. +// Deletes WindowTreeHostPlatform from OnHostMovedInPixels().
  74. +class DeleteHostWindowTreeHostObserver : public WindowTreeHostObserver {
  75. + public:
  76. + explicit DeleteHostWindowTreeHostObserver(
  77. + std::unique_ptr<TestWindowTreeHost> host)
  78. + : host_(std::move(host)) {
  79. + host_->AddObserver(this);
  80. + }
  81. + ~DeleteHostWindowTreeHostObserver() override = default;
  82. +
  83. + TestWindowTreeHost* host() { return host_.get(); }
  84. +
  85. + // WindowTreeHostObserver:
  86. + void OnHostMovedInPixels(WindowTreeHost* host,
  87. + const gfx::Point& new_origin_in_pixels) override {
  88. + host_->RemoveObserver(this);
  89. + host_.reset();
  90. + }
  91. +
  92. + private:
  93. + std::unique_ptr<TestWindowTreeHost> host_;
  94. +
  95. + DISALLOW_COPY_AND_ASSIGN(DeleteHostWindowTreeHostObserver);
  96. +};
  97. +
  98. +// Verifies WindowTreeHostPlatform can be safely deleted when calling
  99. +// OnHostMovedInPixels().
  100. +// Regression test for https://crbug.com/1185482
  101. +TEST_F(WindowTreeHostPlatformTest, DeleteHostFromOnHostMovedInPixels) {
  102. + std::unique_ptr<TestWindowTreeHost> host =
  103. + std::make_unique<TestWindowTreeHost>();
  104. + DeleteHostWindowTreeHostObserver observer(std::move(host));
  105. + observer.host()->SetBoundsInPixels(gfx::Rect(1, 2, 3, 4));
  106. + EXPECT_EQ(nullptr, observer.host());
  107. +}
  108. +
  109. } // namespace
  110. } // namespace aura
  111. diff --git a/ui/base/x/x11_whole_screen_move_loop.cc b/ui/base/x/x11_whole_screen_move_loop.cc
  112. index 5ed215db66..db678799db 100644
  113. --- a/ui/base/x/x11_whole_screen_move_loop.cc
  114. +++ b/ui/base/x/x11_whole_screen_move_loop.cc
  115. @@ -78,9 +78,13 @@ X11WholeScreenMoveLoop::~X11WholeScreenMoveLoop() {
  116. void X11WholeScreenMoveLoop::DispatchMouseMovement() {
  117. if (!last_motion_in_screen_)
  118. return;
  119. + auto weak_ref = weak_factory_.GetWeakPtr();
  120. delegate_->OnMouseMovement(last_motion_in_screen_->root_location(),
  121. last_motion_in_screen_->flags(),
  122. last_motion_in_screen_->time_stamp());
  123. + // The delegate may delete this during dispatch.
  124. + if (!weak_ref)
  125. + return;
  126. last_motion_in_screen_.reset();
  127. }