#ifdef UNSAFE_BUFFERS_BUILD
#pragma allow_unsafe_buffers
#endif
#include "chrome/browser/ui/views/tabs/tab_strip.h"
#include <stddef.h>
#include <algorithm>
#include <iterator>
#include <limits>
#include <memory>
#include <string>
#include <utility>
#include <vector>
#include "base/check.h"
#include "base/compiler_specific.h"
#include "base/containers/adapters.h"
#include "base/containers/contains.h"
#include "base/containers/flat_map.h"
#include "base/feature_list.h"
#include "base/functional/bind.h"
#include "base/functional/callback.h"
#include "base/i18n/rtl.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/metrics/histogram.h"
#include "base/metrics/histogram_functions.h"
#include "base/metrics/histogram_macros.h"
#include "base/metrics/user_metrics.h"
#include "base/not_fatal_until.h"
#include "base/numerics/safe_conversions.h"
#include "base/observer_list.h"
#include "base/ranges/algorithm.h"
#include "base/scoped_observation.h"
#include "base/stl_util.h"
#include "base/strings/utf_string_conversions.h"
#include "base/time/time.h"
#include "base/timer/elapsed_timer.h"
#include "base/types/to_address.h"
#include "build/build_config.h"
#include "build/chromeos_buildflags.h"
#include "chrome/browser/defaults.h"
#include "chrome/browser/themes/theme_properties.h"
#include "chrome/browser/themes/theme_service_factory.h"
#include "chrome/browser/ui/browser_element_identifiers.h"
#include "chrome/browser/ui/color/chrome_color_id.h"
#include "chrome/browser/ui/layout_constants.h"
#include "chrome/browser/ui/tabs/features.h"
#include "chrome/browser/ui/tabs/tab_group_theme.h"
#include "chrome/browser/ui/tabs/tab_strip_model.h"
#include "chrome/browser/ui/tabs/tab_strip_prefs.h"
#include "chrome/browser/ui/tabs/tab_types.h"
#include "chrome/browser/ui/ui_features.h"
#include "chrome/browser/ui/view_ids.h"
#include "chrome/browser/ui/views/frame/browser_view.h"
#include "chrome/browser/ui/views/tabs/browser_tab_strip_controller.h"
#include "chrome/browser/ui/views/tabs/compound_tab_container.h"
#include "chrome/browser/ui/views/tabs/tab.h"
#include "chrome/browser/ui/views/tabs/tab_container_impl.h"
#include "chrome/browser/ui/views/tabs/tab_drag_controller.h"
#include "chrome/browser/ui/views/tabs/tab_group_header.h"
#include "chrome/browser/ui/views/tabs/tab_group_highlight.h"
#include "chrome/browser/ui/views/tabs/tab_group_underline.h"
#include "chrome/browser/ui/views/tabs/tab_group_views.h"
#include "chrome/browser/ui/views/tabs/tab_hover_card_controller.h"
#include "chrome/browser/ui/views/tabs/tab_slot_view.h"
#include "chrome/browser/ui/views/tabs/tab_strip_controller.h"
#include "chrome/browser/ui/views/tabs/tab_strip_layout_helper.h"
#include "chrome/browser/ui/views/tabs/tab_strip_layout_types.h"
#include "chrome/browser/ui/views/tabs/tab_strip_observer.h"
#include "chrome/browser/ui/views/tabs/tab_strip_types.h"
#include "chrome/browser/ui/views/tabs/z_orderable_tab_container_element.h"
#include "chrome/browser/ui/web_applications/app_browser_controller.h"
#include "chrome/grit/generated_resources.h"
#include "chrome/grit/theme_resources.h"
#include "chromeos/constants/chromeos_features.h"
#include "components/crash/core/common/crash_key.h"
#include "components/tab_groups/tab_group_color.h"
#include "components/tab_groups/tab_group_id.h"
#include "components/tab_groups/tab_group_visual_data.h"
#include "ui/base/clipboard/clipboard.h"
#include "ui/base/clipboard/clipboard_constants.h"
#include "ui/base/dragdrop/drag_drop_types.h"
#include "ui/base/dragdrop/mojom/drag_drop_types.mojom.h"
#include "ui/base/interaction/element_identifier.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/metadata/metadata_impl_macros.h"
#include "ui/base/models/list_selection_model.h"
#include "ui/base/resource/resource_bundle.h"
#include "ui/base/theme_provider.h"
#include "ui/color/color_provider.h"
#include "ui/display/display.h"
#include "ui/gfx/animation/throb_animation.h"
#include "ui/gfx/animation/tween.h"
#include "ui/gfx/geometry/rect_conversions.h"
#include "ui/gfx/geometry/size.h"
#include "ui/gfx/geometry/skia_conversions.h"
#include "ui/gfx/native_widget_types.h"
#include "ui/gfx/range/range.h"
#include "ui/views/accessibility/view_accessibility.h"
#include "ui/views/cascading_property.h"
#include "ui/views/controls/scroll_view.h"
#include "ui/views/interaction/element_tracker_views.h"
#include "ui/views/view_class_properties.h"
#include "ui/views/view_observer.h"
#include "ui/views/view_utils.h"
#include "ui/views/widget/root_view.h"
#include "ui/views/widget/widget.h"
#include "ui/views/window/non_client_view.h"
#if BUILDFLAG(IS_WIN)
#include "ui/display/win/screen_win.h"
#include "ui/gfx/win/hwnd_util.h"
#include "ui/views/win/hwnd_util.h"
#endif
#if defined(USE_AURA)
#include "ui/aura/window.h"
#endif
namespace {
ui::mojom::DragEventSource EventSourceFromEvent(const ui::LocatedEvent& event) { … }
std::unique_ptr<TabContainer> MakeTabContainer(
TabStrip* tab_strip,
TabHoverCardController* hover_card_controller,
TabDragContext* drag_context) { … }
void UpdateDragEventSourceCrashKey(
std::optional<ui::mojom::DragEventSource> event_source) { … }
}
class TabStrip::TabDragContextImpl : public TabDragContext,
public views::BoundsAnimatorObserver { … };
BEGIN_METADATA(TabStrip, TabDragContextImpl);
END_METADATA
TabStrip::TabStrip(std::unique_ptr<TabStripController> controller)
: … { … }
TabStrip::~TabStrip() { … }
void TabStrip::SetAvailableWidthCallback(
base::RepeatingCallback<int()> available_width_callback) { … }
int TabStrip::GetSizeNeededForViews(
const std::vector<raw_ptr<TabSlotView, VectorExperimental>>& views) { … }
void TabStrip::SetTabStripObserver(TabStripObserver* observer) { … }
void TabStrip::SetBackgroundOffset(int background_offset) { … }
bool TabStrip::IsRectInWindowCaption(const gfx::Rect& rect) { … }
bool TabStrip::IsTabStripCloseable() const { … }
bool TabStrip::IsTabStripEditable() const { … }
bool TabStrip::IsTabCrashed(int tab_index) const { … }
bool TabStrip::TabHasNetworkError(int tab_index) const { … }
std::optional<TabAlertState> TabStrip::GetTabAlertState(int tab_index) const { … }
void TabStrip::UpdateLoadingAnimations(const base::TimeDelta& elapsed_time) { … }
void TabStrip::AddTabAt(int model_index, TabRendererData data) { … }
void TabStrip::MoveTab(int from_model_index,
int to_model_index,
TabRendererData data) { … }
void TabStrip::RemoveTabAt(content::WebContents* contents,
int model_index,
bool was_active) { … }
void TabStrip::OnTabWillBeRemoved(content::WebContents* contents,
int model_index) { … }
void TabStrip::SetTabData(int model_index, TabRendererData data) { … }
void TabStrip::AddTabToGroup(std::optional<tab_groups::TabGroupId> group,
int model_index) { … }
void TabStrip::OnGroupCreated(const tab_groups::TabGroupId& group) { … }
void TabStrip::OnGroupEditorOpened(const tab_groups::TabGroupId& group) { … }
void TabStrip::OnGroupContentsChanged(const tab_groups::TabGroupId& group) { … }
void TabStrip::OnGroupVisualsChanged(
const tab_groups::TabGroupId& group,
const tab_groups::TabGroupVisualData* old_visuals,
const tab_groups::TabGroupVisualData* new_visuals) { … }
void TabStrip::ToggleTabGroup(const tab_groups::TabGroupId& group,
bool is_collapsing,
ToggleTabGroupCollapsedStateOrigin origin) { … }
void TabStrip::OnGroupMoved(const tab_groups::TabGroupId& group) { … }
void TabStrip::OnGroupClosed(const tab_groups::TabGroupId& group) { … }
bool TabStrip::ShouldDrawStrokes() const { … }
void TabStrip::SetSelection(const ui::ListSelectionModel& new_selection) { … }
void TabStrip::ScrollTowardsTrailingTabs(int offset) { … }
void TabStrip::ScrollTowardsLeadingTabs(int offset) { … }
void TabStrip::OnWidgetActivationChanged(views::Widget* widget, bool active) { … }
void TabStrip::SetTabNeedsAttention(int model_index, bool attention) { … }
std::optional<int> TabStrip::GetModelIndexOf(const TabSlotView* view) const { … }
int TabStrip::GetTabCount() const { … }
int TabStrip::GetModelCount() const { … }
int TabStrip::GetModelPinnedTabCount() const { … }
TabDragContext* TabStrip::GetDragContext() { … }
bool TabStrip::IsAnimating() const { … }
void TabStrip::StopAnimating(bool layout) { … }
std::optional<int> TabStrip::GetFocusedTabIndex() const { … }
views::View* TabStrip::GetTabViewForPromoAnchor(int index_hint) { … }
views::View* TabStrip::GetDefaultFocusableChild() { … }
bool TabStrip::IsValidModelIndex(int index) const { … }
std::optional<int> TabStrip::GetActiveIndex() const { … }
int TabStrip::NumPinnedTabsInModel() const { … }
void TabStrip::OnDropIndexUpdate(const std::optional<int> index,
const bool drop_before) { … }
std::optional<int> TabStrip::GetFirstTabInGroup(
const tab_groups::TabGroupId& group) const { … }
gfx::Range TabStrip::ListTabsInGroup(
const tab_groups::TabGroupId& group) const { … }
bool TabStrip::CanExtendDragHandle() const { … }
const views::View* TabStrip::GetTabClosingModeMouseWatcherHostView() const { … }
bool TabStrip::IsAnimatingInTabStrip() const { … }
void TabStrip::UpdateAnimationTarget(TabSlotView* tab_slot_view,
gfx::Rect target_bounds) { … }
bool TabStrip::IsGroupCollapsed(const tab_groups::TabGroupId& group) const { … }
const ui::ListSelectionModel& TabStrip::GetSelectionModel() const { … }
Tab* TabStrip::tab_at(int index) const { … }
void TabStrip::SelectTab(Tab* tab, const ui::Event& event) { … }
void TabStrip::ExtendSelectionTo(Tab* tab) { … }
void TabStrip::ToggleSelected(Tab* tab) { … }
void TabStrip::AddSelectionFromAnchorTo(Tab* tab) { … }
void TabStrip::CloseTab(Tab* tab, CloseTabSource source) { … }
void TabStrip::ToggleTabAudioMute(Tab* tab) { … }
void TabStrip::ShiftTabNext(Tab* tab) { … }
void TabStrip::ShiftTabPrevious(Tab* tab) { … }
void TabStrip::MoveTabFirst(Tab* tab) { … }
void TabStrip::MoveTabLast(Tab* tab) { … }
void TabStrip::ToggleTabGroupCollapsedState(
const tab_groups::TabGroupId group,
ToggleTabGroupCollapsedStateOrigin origin) { … }
void TabStrip::NotifyTabGroupEditorBubbleOpened() { … }
void TabStrip::NotifyTabGroupEditorBubbleClosed() { … }
void TabStrip::ShowContextMenuForTab(Tab* tab,
const gfx::Point& p,
ui::MenuSourceType source_type) { … }
bool TabStrip::IsActiveTab(const Tab* tab) const { … }
bool TabStrip::IsTabSelected(const Tab* tab) const { … }
bool TabStrip::IsTabPinned(const Tab* tab) const { … }
bool TabStrip::IsTabFirst(const Tab* tab) const { … }
bool TabStrip::IsFocusInTabs() const { … }
bool TabStrip::ShouldCompactLeadingEdge() const { … }
void TabStrip::MaybeStartDrag(
TabSlotView* source,
const ui::LocatedEvent& event,
const ui::ListSelectionModel& original_selection) { … }
TabSlotController::Liveness TabStrip::ContinueDrag(
views::View* view,
const ui::LocatedEvent& event) { … }
bool TabStrip::EndDrag(EndDragReason reason) { … }
Tab* TabStrip::GetTabAt(const gfx::Point& point) { … }
const Tab* TabStrip::GetAdjacentTab(const Tab* tab, int offset) { … }
void TabStrip::OnMouseEventInTab(views::View* source,
const ui::MouseEvent& event) { … }
void TabStrip::UpdateHoverCard(Tab* tab, HoverCardUpdateType update_type) { … }
bool TabStrip::HoverCardIsShowingForTab(Tab* tab) { … }
int TabStrip::GetBackgroundOffset() const { … }
int TabStrip::GetStrokeThickness() const { … }
bool TabStrip::CanPaintThrobberToLayer() const { … }
bool TabStrip::HasVisibleBackgroundTabShapes() const { … }
SkColor TabStrip::GetTabSeparatorColor() const { … }
SkColor TabStrip::GetTabForegroundColor(TabActive active) const { … }
std::u16string TabStrip::GetAccessibleTabName(const Tab* tab) const { … }
std::optional<int> TabStrip::GetCustomBackgroundId(
BrowserFrameActiveState active_state) const { … }
float TabStrip::GetHoverOpacityForTab(float range_parameter) const { … }
float TabStrip::GetHoverOpacityForRadialHighlight() const { … }
std::u16string TabStrip::GetGroupTitle(
const tab_groups::TabGroupId& group) const { … }
std::u16string TabStrip::GetGroupContentString(
const tab_groups::TabGroupId& group) const { … }
tab_groups::TabGroupColorId TabStrip::GetGroupColorId(
const tab_groups::TabGroupId& group) const { … }
SkColor TabStrip::GetPaintedGroupColor(
const tab_groups::TabGroupColorId& color_id) const { … }
void TabStrip::ShiftGroupLeft(const tab_groups::TabGroupId& group) { … }
void TabStrip::ShiftGroupRight(const tab_groups::TabGroupId& group) { … }
const Browser* TabStrip::GetBrowser() const { … }
int TabStrip::GetInactiveTabWidth() const { … }
bool TabStrip::IsFrameCondensed() const { … }
#if BUILDFLAG(IS_CHROMEOS_ASH)
bool TabStrip::IsLockedForOnTask() {
return controller_->IsLockedForOnTask();
}
#endif
views::SizeBounds TabStrip::GetAvailableSize(const views::View* child) const { … }
gfx::Size TabStrip::GetMinimumSize() const { … }
gfx::Size TabStrip::CalculatePreferredSize(
const views::SizeBounds& available_size) const { … }
void TabStrip::Layout(PassKey) { … }
void TabStrip::ChildPreferredSizeChanged(views::View* child) { … }
std::optional<BrowserRootView::DropIndex> TabStrip::GetDropIndex(
const ui::DropTargetEvent& event) { … }
BrowserRootView::DropTarget* TabStrip::GetDropTarget(
gfx::Point loc_in_local_coords) { … }
views::View* TabStrip::GetViewForDrop() { … }
void TabStrip::Init() { … }
void TabStrip::NewTabButtonPressed(const ui::Event& event) { … }
bool TabStrip::ShouldHighlightCloseButtonAfterRemove() { … }
bool TabStrip::TitlebarBackgroundIsTransparent() const { … }
int TabStrip::GetActiveTabWidth() const { … }
const Tab* TabStrip::GetLastVisibleTab() const { … }
void TabStrip::CloseTabInternal(int model_index, CloseTabSource source) { … }
void TabStrip::UpdateContrastRatioValues() { … }
void TabStrip::ShiftTabRelative(Tab* tab, int offset) { … }
void TabStrip::ShiftGroupRelative(const tab_groups::TabGroupId& group,
int offset) { … }
void TabStrip::LogTabWidthsForTabScrolling() { … }
TabStrip::TabContextMenuController::TabContextMenuController(TabStrip* parent)
: … { … }
void TabStrip::TabContextMenuController::ShowContextMenuForViewImpl(
views::View* source,
const gfx::Point& point,
ui::MenuSourceType source_type) { … }
void TabStrip::OnMouseEntered(const ui::MouseEvent& event) { … }
void TabStrip::OnMouseExited(const ui::MouseEvent& event) { … }
void TabStrip::AddedToWidget() { … }
void TabStrip::RemovedFromWidget() { … }
void TabStrip::OnThemeChanged() { … }
void TabStrip::OnGestureEvent(ui::GestureEvent* event) { … }
void TabStrip::OnViewFocused(views::View* observed_view) { … }
void TabStrip::OnViewBlurred(views::View* observed_view) { … }
void TabStrip::OnTouchUiChanged() { … }
void TabStrip::AnnounceTabAddedToGroup(tab_groups::TabGroupId group_id) { … }
void TabStrip::AnnounceTabRemovedFromGroup(tab_groups::TabGroupId group_id) { … }
BEGIN_METADATA(…)