chromium/chrome/browser/ui/views/tabs/tab_strip.cc

// Copyright 2017 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifdef UNSAFE_BUFFERS_BUILD
// TODO(crbug.com/40285824): Remove this and convert code to safer constructs.
#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) {}

}  // namespace

///////////////////////////////////////////////////////////////////////////////
// TabStrip::TabDragContextImpl
//
class TabStrip::TabDragContextImpl : public TabDragContext,
                                     public views::BoundsAnimatorObserver {};

BEGIN_METADATA(TabStrip, TabDragContextImpl);
END_METADATA

///////////////////////////////////////////////////////////////////////////////
// TabStrip, public:

TabStrip::TabStrip(std::unique_ptr<TabStripController> controller)
    :{}

TabStrip::~TabStrip() {}

void TabStrip::SetAvailableWidthCallback(
    base::RepeatingCallback<int()> available_width_callback) {}

// static
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 {}

// Returns the accessible tab name for the tab.
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

///////////////////////////////////////////////////////////////////////////////
// TabStrip, views::View overrides:

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() {}

///////////////////////////////////////////////////////////////////////////////
// TabStrip, private:

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:
// ----------------------------------------------------------

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()