#ifdef UNSAFE_BUFFERS_BUILD
#pragma allow_unsafe_buffers
#endif
#include "chrome/browser/ui/tabs/tab_strip_model.h"
#include <algorithm>
#include <memory>
#include <optional>
#include <set>
#include <string>
#include <unordered_map>
#include <utility>
#include "base/containers/adapters.h"
#include "base/containers/contains.h"
#include "base/containers/flat_map.h"
#include "base/memory/raw_ptr.h"
#include "base/metrics/histogram_macros.h"
#include "base/metrics/user_metrics.h"
#include "base/not_fatal_until.h"
#include "base/observer_list.h"
#include "base/ranges/algorithm.h"
#include "base/trace_event/common/trace_event_common.h"
#include "base/trace_event/trace_event.h"
#include "build/build_config.h"
#include "chrome/app/chrome_command_ids.h"
#include "chrome/browser/commerce/browser_utils.h"
#include "chrome/browser/content_settings/host_content_settings_map_factory.h"
#include "chrome/browser/extensions/tab_helper.h"
#include "chrome/browser/lifetime/browser_shutdown.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/reading_list/reading_list_model_factory.h"
#include "chrome/browser/resource_coordinator/tab_helper.h"
#include "chrome/browser/send_tab_to_self/send_tab_to_self_util.h"
#include "chrome/browser/ui/bookmarks/bookmark_utils.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_commands.h"
#include "chrome/browser/ui/browser_finder.h"
#include "chrome/browser/ui/browser_window.h"
#include "chrome/browser/ui/send_tab_to_self/send_tab_to_self_bubble.h"
#include "chrome/browser/ui/tab_ui_helper.h"
#include "chrome/browser/ui/tabs/features.h"
#include "chrome/browser/ui/tabs/organization/metrics.h"
#include "chrome/browser/ui/tabs/organization/tab_organization_service.h"
#include "chrome/browser/ui/tabs/organization/tab_organization_service_factory.h"
#include "chrome/browser/ui/tabs/organization/tab_organization_session.h"
#include "chrome/browser/ui/tabs/tab_contents_data.h"
#include "chrome/browser/ui/tabs/tab_enums.h"
#include "chrome/browser/ui/tabs/tab_group.h"
#include "chrome/browser/ui/tabs/tab_group_model.h"
#include "chrome/browser/ui/tabs/tab_model.h"
#include "chrome/browser/ui/tabs/tab_strip_collection.h"
#include "chrome/browser/ui/tabs/tab_strip_model_delegate.h"
#include "chrome/browser/ui/tabs/tab_strip_model_observer.h"
#include "chrome/browser/ui/tabs/tab_utils.h"
#include "chrome/browser/ui/thumbnails/thumbnail_tab_helper.h"
#include "chrome/browser/ui/ui_features.h"
#include "chrome/browser/ui/views/tabs/tab_drag_controller.h"
#include "chrome/browser/ui/web_applications/web_app_dialog_utils.h"
#include "chrome/browser/ui/web_applications/web_app_launch_utils.h"
#include "chrome/browser/ui/web_applications/web_app_tabbed_utils.h"
#include "chrome/browser/web_applications/policy/web_app_policy_manager.h"
#include "chrome/browser/web_applications/web_app_provider.h"
#include "chrome/browser/web_applications/web_app_tab_helper.h"
#include "chrome/common/webui_url_constants.h"
#include "components/commerce/core/commerce_utils.h"
#include "components/content_settings/core/browser/host_content_settings_map.h"
#include "components/feature_engagement/public/feature_constants.h"
#include "components/reading_list/core/reading_list_model.h"
#include "components/tab_groups/tab_group_id.h"
#include "components/tab_groups/tab_group_visual_data.h"
#include "components/web_modal/web_contents_modal_dialog_manager.h"
#include "components/webapps/common/web_app_id.h"
#include "content/public/browser/render_process_host.h"
#include "content/public/browser/render_widget_host.h"
#include "content/public/browser/render_widget_host_observer.h"
#include "content/public/browser/render_widget_host_view.h"
#include "content/public/browser/web_contents.h"
#include "content/public/common/url_constants.h"
#include "media/base/media_switches.h"
#include "third_party/perfetto/include/perfetto/tracing/traced_value.h"
#include "ui/base/page_transition_types.h"
#include "ui/gfx/range/range.h"
UserMetricsAction;
WebContents;
namespace {
TabGroupModelFactory* factory_instance = …;
class ReentrancyCheck { … };
bool ShouldForgetOpenersForTransition(ui::PageTransition transition) { … }
tabs::TabInterface::DetachReason RemoveReasonToDetachReason(
TabStripModelChange::RemoveReason reason) { … }
}
TabGroupModelFactory::TabGroupModelFactory() { … }
TabGroupModelFactory* TabGroupModelFactory::GetInstance() { … }
std::unique_ptr<TabGroupModel> TabGroupModelFactory::Create(
TabGroupController* controller) { … }
DetachedWebContents::DetachedWebContents(
int index_before_any_removals,
int index_at_time_of_removal,
std::unique_ptr<tabs::TabModel> tab,
content::WebContents* contents,
TabStripModelChange::RemoveReason remove_reason,
std::optional<SessionID> id)
: … { … }
DetachedWebContents::~DetachedWebContents() = default;
DetachedWebContents::DetachedWebContents(DetachedWebContents&&) = default;
struct TabStripModel::DetachNotifications { … };
constexpr int TabStripModel::kNoTab;
TabStripModel::TabStripModel(TabStripModelDelegate* delegate,
Profile* profile,
TabGroupModelFactory* group_model_factory)
: … { … }
TabStripModel::~TabStripModel() { … }
void TabStripModel::SetTabStripUI(TabStripModelObserver* observer) { … }
void TabStripModel::AddObserver(TabStripModelObserver* observer) { … }
void TabStripModel::RemoveObserver(TabStripModelObserver* observer) { … }
int TabStripModel::count() const { … }
bool TabStripModel::empty() const { … }
int TabStripModel::GetIndexOfTab(tabs::TabHandle tab_handle) const { … }
tabs::TabHandle TabStripModel::GetTabHandleAt(int index) const { … }
bool TabStripModel::ContainsIndex(int index) const { … }
void TabStripModel::AppendWebContents(std::unique_ptr<WebContents> contents,
bool foreground) { … }
void TabStripModel::AppendTab(std::unique_ptr<tabs::TabModel> tab,
bool foreground) { … }
int TabStripModel::InsertWebContentsAt(
int index,
std::unique_ptr<WebContents> contents,
int add_types,
std::optional<tab_groups::TabGroupId> group) { … }
int TabStripModel::InsertDetachedTabAt(
int index,
std::unique_ptr<tabs::TabModel> tab,
int add_types,
std::optional<tab_groups::TabGroupId> group) { … }
std::unique_ptr<content::WebContents> TabStripModel::DiscardWebContentsAt(
int index,
std::unique_ptr<WebContents> new_contents) { … }
std::unique_ptr<tabs::TabModel> TabStripModel::DetachTabAtForInsertion(
int index) { … }
void TabStripModel::DetachAndDeleteWebContentsAt(int index) { … }
std::unique_ptr<DetachedWebContents>
TabStripModel::DetachWebContentsWithReasonAt(
int index,
TabStripModelChange::RemoveReason reason) { … }
void TabStripModel::OnChange(const TabStripModelChange& change,
const TabStripSelectionChange& selection) { … }
std::unique_ptr<DetachedWebContents> TabStripModel::DetachWebContentsImpl(
int index_before_any_removals,
int index_at_time_of_removal,
bool create_historical_tab,
TabStripModelChange::RemoveReason reason) { … }
void TabStripModel::SendDetachWebContentsNotifications(
DetachNotifications* notifications) { … }
void TabStripModel::ActivateTabAt(int index,
TabStripUserGestureDetails user_gesture) { … }
int TabStripModel::MoveWebContentsAt(int index,
int to_position,
bool select_after_move) { … }
int TabStripModel::MoveWebContentsAt(
int index,
int to_position,
bool select_after_move,
std::optional<tab_groups::TabGroupId> group) { … }
void TabStripModel::MoveSelectedTabsTo(
int index,
std::optional<tab_groups::TabGroupId> group) { … }
void TabStripModel::MoveGroupTo(const tab_groups::TabGroupId& group,
int to_index) { … }
void TabStripModel::MoveGroupToImpl(const tab_groups::TabGroupId& group,
int to_index) { … }
WebContents* TabStripModel::GetActiveWebContents() const { … }
tabs::TabModel* TabStripModel::GetActiveTab() const { … }
WebContents* TabStripModel::GetWebContentsAt(int index) const { … }
int TabStripModel::GetIndexOfWebContents(const WebContents* contents) const { … }
void TabStripModel::UpdateWebContentsStateAt(int index,
TabChangeType change_type) { … }
void TabStripModel::SetTabNeedsAttentionAt(int index, bool attention) { … }
void TabStripModel::CloseAllTabs() { … }
void TabStripModel::CloseAllTabsInGroup(const tab_groups::TabGroupId& group) { … }
void TabStripModel::CloseWebContentsAt(int index, uint32_t close_types) { … }
bool TabStripModel::TabsAreLoading() const { … }
tabs::TabModel* TabStripModel::GetOpenerOfTabAt(const int index) const { … }
void TabStripModel::SetOpenerOfWebContentsAt(int index, WebContents* opener) { … }
int TabStripModel::GetIndexOfLastWebContentsOpenedBy(const WebContents* opener,
int start_index) const { … }
void TabStripModel::TabNavigating(WebContents* contents,
ui::PageTransition transition) { … }
void TabStripModel::SetTabBlocked(int index, bool blocked) { … }
int TabStripModel::SetTabPinned(int index, bool pinned) { … }
bool TabStripModel::IsTabPinned(int index) const { … }
bool TabStripModel::IsTabCollapsed(int index) const { … }
bool TabStripModel::IsGroupCollapsed(
const tab_groups::TabGroupId& group) const { … }
bool TabStripModel::IsTabBlocked(int index) const { … }
bool TabStripModel::IsTabClosable(int index) const { … }
bool TabStripModel::IsTabClosable(const content::WebContents* contents) const { … }
std::optional<tab_groups::TabGroupId> TabStripModel::GetTabGroupForTab(
int index) const { … }
std::optional<tab_groups::TabGroupId> TabStripModel::GetSurroundingTabGroup(
int index) const { … }
int TabStripModel::IndexOfFirstNonPinnedTab() const { … }
void TabStripModel::ExtendSelectionTo(int index) { … }
bool TabStripModel::ToggleSelectionAt(int index) { … }
void TabStripModel::AddSelectionFromAnchorTo(int index) { … }
bool TabStripModel::IsTabSelected(int index) const { … }
void TabStripModel::SetSelectionFromModel(ui::ListSelectionModel source) { … }
const ui::ListSelectionModel& TabStripModel::selection_model() const { … }
bool TabStripModel::CanShowModalUI() const { … }
std::unique_ptr<ScopedTabStripModalUI> TabStripModel::ShowModalUI() { … }
void TabStripModel::ForceShowingModalUIForTesting(bool showing) { … }
void TabStripModel::AddWebContents(
std::unique_ptr<WebContents> contents,
int index,
ui::PageTransition transition,
int add_types,
std::optional<tab_groups::TabGroupId> group) { … }
void TabStripModel::AddTab(std::unique_ptr<tabs::TabModel> tab,
int index,
ui::PageTransition transition,
int add_types,
std::optional<tab_groups::TabGroupId> group) { … }
void TabStripModel::CloseSelectedTabs() { … }
void TabStripModel::SelectNextTab(TabStripUserGestureDetails detail) { … }
void TabStripModel::SelectPreviousTab(TabStripUserGestureDetails detail) { … }
void TabStripModel::SelectLastTab(TabStripUserGestureDetails detail) { … }
void TabStripModel::MoveTabNext() { … }
void TabStripModel::MoveTabPrevious() { … }
tab_groups::TabGroupId TabStripModel::AddToNewGroup(
const std::vector<int> indices,
const tab_groups::TabGroupId group_id,
tab_groups::TabGroupVisualData visual_data) { … }
tab_groups::TabGroupId TabStripModel::AddToNewGroup(
const std::vector<int> indices) { … }
void TabStripModel::AddToExistingGroup(const std::vector<int> indices,
const tab_groups::TabGroupId group,
const bool add_to_end) { … }
void TabStripModel::AddToGroupForRestore(const std::vector<int>& indices,
const tab_groups::TabGroupId& group) { … }
void TabStripModel::RemoveFromGroup(const std::vector<int>& indices) { … }
bool TabStripModel::IsReadLaterSupportedForAny(
const std::vector<int>& indices) { … }
void TabStripModel::AddToReadLater(const std::vector<int>& indices) { … }
void TabStripModel::CreateTabGroup(const tab_groups::TabGroupId& group) { … }
void TabStripModel::OpenTabGroupEditor(const tab_groups::TabGroupId& group) { … }
void TabStripModel::ChangeTabGroupContents(
const tab_groups::TabGroupId& group) { … }
void TabStripModel::ChangeTabGroupVisuals(
const tab_groups::TabGroupId& group,
const TabGroupChange::VisualsChange& visuals) { … }
void TabStripModel::MoveTabGroup(const tab_groups::TabGroupId& group) { … }
void TabStripModel::CloseTabGroup(const tab_groups::TabGroupId& group) { … }
std::u16string TabStripModel::GetTitleAt(int index) const { … }
int TabStripModel::GetTabCount() const { … }
bool TabStripModel::IsContextMenuCommandEnabled(
int context_index,
ContextMenuCommand command_id) const { … }
void TabStripModel::ExecuteContextMenuCommand(int context_index,
ContextMenuCommand command_id) { … }
void TabStripModel::ExecuteAddToExistingGroupCommand(
int context_index,
const tab_groups::TabGroupId& group) { … }
void TabStripModel::ExecuteAddToExistingWindowCommand(int context_index,
int browser_index) { … }
std::vector<tab_groups::TabGroupId>
TabStripModel::GetGroupsDestroyedFromRemovingIndices(
const std::vector<int>& indices) const { … }
void TabStripModel::ExecuteCloseTabsByIndicesCommand(
const std::vector<int>& indices_to_delete) { … }
bool TabStripModel::WillContextMenuMuteSites(int index) { … }
bool TabStripModel::WillContextMenuPin(int index) { … }
bool TabStripModel::WillContextMenuGroup(int index) { … }
bool TabStripModel::ContextMenuCommandToBrowserCommand(int cmd_id,
int* browser_cmd) { … }
int TabStripModel::GetIndexOfNextWebContentsOpenedBy(const WebContents* opener,
int start_index) const { … }
std::optional<int> TabStripModel::GetNextExpandedActiveTab(
int start_index,
std::optional<tab_groups::TabGroupId> collapsing_group) const { … }
void TabStripModel::ForgetAllOpeners() { … }
void TabStripModel::ForgetOpener(WebContents* contents) { … }
void TabStripModel::WriteIntoTrace(perfetto::TracedValue context) const { … }
bool TabStripModel::RunUnloadListenerBeforeClosing(
content::WebContents* contents) { … }
bool TabStripModel::ShouldRunUnloadListenerBeforeClosing(
content::WebContents* contents) { … }
int TabStripModel::ConstrainInsertionIndex(int index, bool pinned_tab) const { … }
int TabStripModel::ConstrainMoveIndex(int index, bool pinned_tab) const { … }
std::vector<int> TabStripModel::GetIndicesForCommand(int index) const { … }
std::vector<int> TabStripModel::GetIndicesClosedByCommand(
int index,
ContextMenuCommand id) const { … }
bool TabStripModel::IsNewTabAtEndOfTabStrip(WebContents* contents) const { … }
std::vector<content::WebContents*> TabStripModel::GetWebContentsesByIndices(
const std::vector<int>& indices) const { … }
int TabStripModel::InsertTabAtImpl(
int index,
std::unique_ptr<tabs::TabModel> tab,
int add_types,
std::optional<tab_groups::TabGroupId> group) { … }
tabs::TabModel* TabStripModel::GetTabAtIndex(int index) const { … }
tabs::TabModel* TabStripModel::GetTabForWebContents(
const content::WebContents* contents) const { … }
void TabStripModel::CloseTabs(base::span<content::WebContents* const> items,
uint32_t close_types) { … }
bool TabStripModel::CloseWebContentses(
base::span<content::WebContents* const> items,
uint32_t close_types,
DetachNotifications* notifications) { … }
TabStripSelectionChange TabStripModel::SetSelection(
ui::ListSelectionModel new_model,
TabStripModelObserver::ChangeReason reason,
bool triggered_by_other_operation) { … }
void TabStripModel::SelectRelativeTab(TabRelativeDirection direction,
TabStripUserGestureDetails detail) { … }
void TabStripModel::MoveTabRelative(TabRelativeDirection direction) { … }
std::pair<std::optional<int>, std::optional<int>>
TabStripModel::GetAdjacentTabsAfterSelectedMove(
base::PassKey<TabDragController>,
int destination_index) { … }
std::vector<int> TabStripModel::GetSelectedPinnedTabs() { … }
std::vector<int> TabStripModel::GetSelectedUnpinnedTabs() { … }
void TabStripModel::AddToNewGroupImpl(
const std::vector<int>& indices,
const tab_groups::TabGroupId& new_group,
std::optional<tab_groups::TabGroupVisualData> visual_data) { … }
void TabStripModel::AddToExistingGroupImpl(const std::vector<int>& indices,
const tab_groups::TabGroupId& group,
const bool add_to_end) { … }
void TabStripModel::MoveTabsAndSetGroupImpl(
const std::vector<int>& indices,
int destination_index,
std::optional<tab_groups::TabGroupId> group) { … }
void TabStripModel::AddToReadLaterImpl(const std::vector<int>& indices) { … }
void TabStripModel::InsertTabAtIndexImpl(
std::unique_ptr<tabs::TabModel> tab_model,
int index,
std::optional<tab_groups::TabGroupId> group,
bool pin,
bool active) { … }
std::unique_ptr<tabs::TabModel> TabStripModel::RemoveTabFromIndexImpl(
int index) { … }
void TabStripModel::MoveTabToIndexImpl(
int initial_index,
int final_index,
const std::optional<tab_groups::TabGroupId> group,
bool pin,
bool select_after_move) { … }
void TabStripModel::MoveTabsToIndexImpl(
const std::vector<int>& tab_indices,
int destination_index,
const std::optional<tab_groups::TabGroupId> group) { … }
void TabStripModel::TabGroupStateChanged(
int index,
tabs::TabModel* tab,
const std::optional<tab_groups::TabGroupId> initial_group,
const std::optional<tab_groups::TabGroupId> new_group) { … }
void TabStripModel::RemoveTabFromGroupModel(
const tab_groups::TabGroupId& group) { … }
void TabStripModel::AddTabToGroupModel(const tab_groups::TabGroupId& group) { … }
void TabStripModel::ValidateTabStripModel() { … }
void TabStripModel::SendMoveNotificationForWebContents(
int index,
int to_position,
WebContents* web_contents,
TabStripSelectionChange& selection_change) { … }
TabStripSelectionChange TabStripModel::MaybeUpdateSelectionModel(
int initial_index,
int final_index,
bool select_after_move) { … }
std::vector<std::pair<int, int>> TabStripModel::CalculateIncrementalTabMoves(
const std::vector<int>& tab_indices,
int destination_index) const { … }
std::vector<TabStripModel::MoveNotification>
TabStripModel::PrepareTabsToMoveToIndex(const std::vector<int>& tab_indices,
int destination_index) { … }
void TabStripModel::SetTabsPinned(std::vector<int> indices, bool pinned) { … }
void TabStripModel::SetSitesMuted(const std::vector<int>& indices,
bool mute) const { … }
void TabStripModel::FixOpeners(int index) { … }
std::optional<tab_groups::TabGroupId> TabStripModel::GetGroupToAssign(
int index,
int to_position) { … }
int TabStripModel::GetTabIndexAfterClosing(int index,
int removing_index) const { … }
void TabStripModel::OnActiveTabChanged(
const TabStripSelectionChange& selection) { … }
bool TabStripModel::PolicyAllowsTabClosing(
content::WebContents* contents) const { … }
int TabStripModel::DetermineInsertionIndex(ui::PageTransition transition,
bool foreground) { … }
void TabStripModel::GroupCloseStopped(const tab_groups::TabGroupId& group) { … }
std::optional<int> TabStripModel::DetermineNewSelectedIndex(
int removing_index) const { … }
TabStripModel::ScopedTabStripModalUIImpl::ScopedTabStripModalUIImpl(
TabStripModel* model)
: … { … }
TabStripModel::ScopedTabStripModalUIImpl::~ScopedTabStripModalUIImpl() { … }