diff --git a/chrome/browser/ui/views/autofill/popup/popup_row_view.cc b/chrome/browser/ui/views/autofill/popup/popup_row_view.cc index 333fb65b0ac29..127af192ad961 100644 --- a/chrome/browser/ui/views/autofill/popup/popup_row_view.cc +++ b/chrome/browser/ui/views/autofill/popup/popup_row_view.cc @@ -45,6 +45,7 @@ #include "ui/events/keycodes/keyboard_codes.h" #include "ui/events/types/event_type.h" #include "ui/gfx/geometry/insets.h" +#include "ui/views/view_tracker.h" #include "ui/gfx/geometry/outsets_f.h" #include "ui/gfx/geometry/rect_f.h" #include "ui/views/accessibility/view_accessibility.h" @@ -370,6 +371,10 @@ void PopupRowView::SetSelectedCell(std::optional new_cell) { controller_->UnselectSuggestion(); } + // NotifyAXSelection() can synchronously re-enter the browser thread on + // Windows (UIA COM pump) and destroy `*this` via OnSuggestionsChanged(). + // See popup_base_view.cc and crbug.com/514228954. + views::ViewTracker this_tracker(this); if ((new_cell == CellType::kControl && expand_child_suggestions_view_) || (new_cell == CellType::kContent && !suggestion_is_acceptable_)) { // TODO(crbug.com/370695550): `SetIsSelected()` must go after @@ -378,6 +383,9 @@ void PopupRowView::SetSelectedCell(std::optional new_cell) { // moving `SetIsSelected()` into `NotifyAXSelection()` (and rename it) to // hide this API complexity from clients. GetA11ySelectionDelegate().NotifyAXSelection(*this); + if (!this_tracker.view()) { + return; + } GetViewAccessibility().SetIsSelected(true); NotifyAccessibilityEventDeprecated( ax::mojom::Event::kSelectedChildrenChanged, true); @@ -386,6 +394,9 @@ void PopupRowView::SetSelectedCell(std::optional new_cell) { controller_->SelectSuggestion(line_number_); content_view_->UpdateStyle(/*selected=*/true); GetA11ySelectionDelegate().NotifyAXSelection(*content_view_); + if (!this_tracker.view()) { + return; + } content_view_->GetViewAccessibility().SetIsSelected(true); NotifyAccessibilityEventDeprecated( ax::mojom::Event::kSelectedChildrenChanged, true); diff --git a/chrome/browser/ui/views/autofill/popup/popup_row_with_button_view.cc b/chrome/browser/ui/views/autofill/popup/popup_row_with_button_view.cc index fffa5adc19676..3b3acb7a8ec50 100644 --- a/chrome/browser/ui/views/autofill/popup/popup_row_with_button_view.cc +++ b/chrome/browser/ui/views/autofill/popup/popup_row_with_button_view.cc @@ -29,6 +29,7 @@ #include "ui/views/layout/box_layout.h" #include "ui/views/metadata/view_factory.h" #include "ui/views/view.h" +#include "ui/views/view_tracker.h" #include "ui/views/widget/widget.h" namespace autofill { @@ -248,7 +249,13 @@ bool PopupRowWithButtonView::HandleKeyPressEvent( } void PopupRowWithButtonView::SetSelectedCell(std::optional cell) { + // PopupRowView::SetSelectedCell() -> NotifyAXSelection() can synchronously + // re-enter on Windows (UIA COM pump) and free `*this`. + views::ViewTracker this_tracker(this); autofill::PopupRowView::SetSelectedCell(cell); + if (!this_tracker.view()) { + return; + } button_->SetVisible(ShouldButtonBeVisible()); diff --git a/chrome/browser/ui/views/autofill/popup/popup_view_views.cc b/chrome/browser/ui/views/autofill/popup/popup_view_views.cc index fa0289fc084b9..c67bed21d4b3e 100644 --- a/chrome/browser/ui/views/autofill/popup/popup_view_views.cc +++ b/chrome/browser/ui/views/autofill/popup/popup_view_views.cc @@ -103,6 +103,7 @@ #include "ui/views/metadata/view_factory.h" #include "ui/views/view.h" #include "ui/views/view_class_properties.h" +#include "ui/views/view_tracker.h" #include "ui/views/widget/widget.h" using views::BubbleBorder; @@ -930,13 +931,18 @@ void PopupViewViews::SetSelectedCell( row_with_selected_cell_ = cell_index->first; PopupRowView& new_selected_row = GetPopupRowViewAt(cell_index->first); + // SetSelectedCell() -> NotifyAXSelection() can synchronously re-enter on + // Windows (UIA COM pump) and free the row via OnSuggestionsChanged() + // -> CreateSuggestionViews() -> RemoveAllChildViews(). The `!controller_` + // check below does not catch the OnSuggestionsChanged() path. + views::ViewTracker row_tracker(&new_selected_row); new_selected_row.SetSelectedCell(cell_index->second); - new_selected_row.ScrollViewToVisible(); - - if (!controller_) { - // The previous SetSelectedCell() call may have hidden the popup. + if (!row_tracker.view() || !controller_) { + // The previous SetSelectedCell() call may have hidden the popup or + // rebuilt the suggestion rows. return; } + new_selected_row.ScrollViewToVisible(); const Suggestion& suggestion = controller_->GetSuggestionAt(cell_index->first);