diff --git a/ui/views/win/hwnd_message_handler_headless.h b/ui/views/win/hwnd_message_handler_headless.h index 0000000..0000000 100644 --- a/ui/views/win/hwnd_message_handler_headless.h +++ b/ui/views/win/hwnd_message_handler_headless.h @@ -12,6 +12,7 @@ #include #include +#include "base/memory/weak_ptr.h" #include "ui/base/mojom/window_show_state.mojom-forward.h" #include "ui/gfx/geometry/rect.h" #include "ui/gfx/geometry/size.h" @@ -125,6 +126,12 @@ class VIEWS_EXPORT HWNDMessageHandlerHeadless : public HWNDMessageHandler { gfx::Rect bounds_; std::optional restored_bounds_; + + // The base class's |msg_handler_weak_factory_| is private (declared inside + // CR_MSG_MAP_CLASS_DECLARATIONS), so the headless overrides need their own + // factory to detect re-entrant destruction across delegate_ callouts. Must + // be last. + base::WeakPtrFactory headless_weak_factory_{this}; }; } // namespace views diff --git a/ui/views/win/hwnd_message_handler_headless.cc b/ui/views/win/hwnd_message_handler_headless.cc index 0000000..0000000 100644 --- a/ui/views/win/hwnd_message_handler_headless.cc +++ b/ui/views/win/hwnd_message_handler_headless.cc @@ -156,9 +156,13 @@ void HWNDMessageHandlerHeadless::SetSize(const gfx::Size& size) { // Update the headless window size and pretend the platform window size has // updated. bool size_changed = bounds_.size() != size; gfx::Rect bounds = bounds_; bounds.set_size(size); + auto ref = headless_weak_factory_.GetWeakPtr(); SetHeadlessWindowBounds(bounds); + if (!ref) { + return; + } if (size_changed) { delegate_->HandleClientSizeChanged(GetClientAreaBounds().size()); } @@ -204,6 +208,7 @@ void HWNDMessageHandlerHeadless::Show(ui::mojom::WindowShowState show_state, const gfx::Rect& pixel_restore_bounds) { TRACE_EVENT0("views", "HWNDMessageHandlerHeadless::Show"); + auto ref = headless_weak_factory_.GetWeakPtr(); bool activate = true; switch (show_state) { @@ -228,6 +233,9 @@ void HWNDMessageHandlerHeadless::Show(ui::mojom::WindowShowState show_state, default: break; } + if (!ref) { + return; + } // In headless mode the platform window is always hidden, so instead of // showing it just maintain a local flag to track the expected headless @@ -236,6 +244,9 @@ void HWNDMessageHandlerHeadless::Show(ui::mojom::WindowShowState show_state, if (!is_visible_) { is_visible_ = true; delegate_->HandleVisibilityChanged(/*visible=*/true); + if (!ref) { + return; + } } if (activate) { @@ -261,8 +272,12 @@ void HWNDMessageHandlerHeadless::Maximize() { restored_bounds_ = bounds_; window_state_ = WindowState::kMaximized; + auto ref = headless_weak_factory_.GetWeakPtr(); gfx::Rect bounds = GetZoomedWindowBounds(); SetBoundsInternal(bounds, /*force_size_changed=*/false); + if (!ref) { + return; + } delegate_->HandleCommand(static_cast(SC_MAXIMIZE)); } @@ -276,13 +291,23 @@ void HWNDMessageHandlerHeadless::Minimize() { // Windows automatiaclly deactivates minimized windows, so we need to // replicate this behavior to prevent focus not being restored, see // https://crbug.com/358998544. + auto ref = headless_weak_factory_.GetWeakPtr(); was_active_before_minimize_ = is_active_; if (is_active_) { Deactivate(); + if (!ref) { + return; + } } delegate_->HandleWindowMinimizedOrRestored(/*restored=*/false); + if (!ref) { + return; + } delegate_->HandleCommand(static_cast(SC_MINIMIZE)); + if (!ref) { + return; + } delegate_->HandleNativeBlur(nullptr); } @@ -294,12 +319,22 @@ void HWNDMessageHandlerHeadless::Restore() { auto prev_state = window_state_; window_state_ = WindowState::kNormal; + auto ref = headless_weak_factory_.GetWeakPtr(); RestoreBounds(); + if (!ref) { + return; + } if (prev_state == WindowState::kMinimized) { delegate_->HandleWindowMinimizedOrRestored(/*restored=*/true); + if (!ref) { + return; + } if (was_active_before_minimize_) { Activate(); + if (!ref) { + return; + } } } @@ -445,13 +480,21 @@ void HWNDMessageHandlerHeadless::SetBoundsInternal( bool force_size_changed) { gfx::Rect old_bounds = GetClientAreaBounds(); + // |delegate_| callouts below can synchronously delete |this| (see + // crbug.com/1185482, crbug.com/1197436); the base-class override guards the + // identical operation with |msg_handler_weak_factory_|. + auto ref = headless_weak_factory_.GetWeakPtr(); SetHeadlessWindowBounds(bounds_in_pixels); + if (!ref) { + return; + } // In normal mode the delegate is called when the platform window receives // WM_MOVE/WM_MOVING messages, however, in headless mode platform window is // never moved, so call the delegate here. See http://crbug.com/401294443. if (old_bounds.origin() != bounds_in_pixels.origin()) { delegate_->HandleMove(); + if (!ref) { + return; + } } // Notify the delegate pretending the platform window size has been changed.