#include "chrome/browser/ui/views/tabs/tab_container_impl.h"
#include <memory>
#include "base/bits.h"
#include "base/containers/adapters.h"
#include "base/ranges/algorithm.h"
#include "base/types/to_address.h"
#include "chrome/browser/ui/layout_constants.h"
#include "chrome/browser/ui/tabs/features.h"
#include "chrome/browser/ui/ui_features.h"
#include "chrome/browser/ui/views/frame/browser_root_view.h"
#include "chrome/browser/ui/views/tabs/tab.h"
#include "chrome/browser/ui/views/tabs/tab_drag_context.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_scrolling_animation.h"
#include "chrome/browser/ui/views/tabs/tab_slot_animation_delegate.h"
#include "chrome/browser/ui/views/tabs/tab_strip.h"
#include "chrome/browser/ui/views/tabs/tab_strip_controller.h"
#include "chrome/browser/ui/views/tabs/tab_style_views.h"
#include "chrome/browser/ui/views/tabs/z_orderable_tab_container_element.h"
#include "chrome/grit/theme_resources.h"
#include "components/tab_groups/tab_group_id.h"
#include "ui/base/metadata/metadata_impl_macros.h"
#include "ui/display/screen.h"
#include "ui/gfx/image/image_skia.h"
#include "ui/gfx/image/image_skia_operations.h"
#include "ui/views/accessibility/view_accessibility.h"
#include "ui/views/controls/image_view.h"
#include "ui/views/controls/scroll_view.h"
#include "ui/views/mouse_watcher_view_host.h"
#include "ui/views/rect_based_targeting_utils.h"
#include "ui/views/view_utils.h"
namespace {
int g_drop_indicator_width = …;
int g_drop_indicator_height = …;
int GetDropArrowImageResourceId(bool is_down) { … }
}
class TabContainerImpl::RemoveTabDelegate : public TabSlotAnimationDelegate { … };
TabContainerImpl::RemoveTabDelegate::RemoveTabDelegate(
TabContainer* tab_container,
Tab* tab)
: … { … }
void TabContainerImpl::RemoveTabDelegate::AnimationEnded(
const gfx::Animation* animation) { … }
void TabContainerImpl::RemoveTabDelegate::AnimationCanceled(
const gfx::Animation* animation) { … }
TabContainerImpl::TabContainerImpl(
TabContainerController& controller,
TabHoverCardController* hover_card_controller,
TabDragContextBase* drag_context,
TabSlotController& tab_slot_controller,
views::View* scroll_contents_view)
: … { … }
TabContainerImpl::~TabContainerImpl() { … }
void TabContainerImpl::SetAvailableWidthCallback(
base::RepeatingCallback<int()> available_width_callback) { … }
Tab* TabContainerImpl::AddTab(std::unique_ptr<Tab> tab,
int model_index,
TabPinned pinned) { … }
void TabContainerImpl::MoveTab(int from_model_index, int to_model_index) { … }
void TabContainerImpl::RemoveTab(int model_index, bool was_active) { … }
void TabContainerImpl::SetTabPinned(int model_index, TabPinned pinned) { … }
void TabContainerImpl::SetActiveTab(std::optional<size_t> prev_active_index,
std::optional<size_t> new_active_index) { … }
Tab* TabContainerImpl::RemoveTabFromViewModel(int model_index) { … }
Tab* TabContainerImpl::AddTabToViewModel(Tab* tab,
int model_index,
TabPinned pinned) { … }
void TabContainerImpl::ReturnTabSlotView(TabSlotView* view) { … }
void TabContainerImpl::ScrollTabToVisible(int model_index) { … }
void TabContainerImpl::ScrollTabContainerByOffset(int offset) { … }
void TabContainerImpl::OnGroupCreated(const tab_groups::TabGroupId& group) { … }
void TabContainerImpl::OnGroupEditorOpened(
const tab_groups::TabGroupId& group) { … }
void TabContainerImpl::OnGroupContentsChanged(
const tab_groups::TabGroupId& group) { … }
void TabContainerImpl::OnGroupVisualsChanged(
const tab_groups::TabGroupId& group,
const tab_groups::TabGroupVisualData* old_visuals,
const tab_groups::TabGroupVisualData* new_visuals) { … }
void TabContainerImpl::OnGroupMoved(const tab_groups::TabGroupId& group) { … }
void TabContainerImpl::ToggleTabGroup(
const tab_groups::TabGroupId& group,
bool is_collapsing,
ToggleTabGroupCollapsedStateOrigin origin) { … }
void TabContainerImpl::OnGroupClosed(const tab_groups::TabGroupId& group) { … }
void TabContainerImpl::UpdateTabGroupVisuals(tab_groups::TabGroupId group_id) { … }
void TabContainerImpl::NotifyTabGroupEditorBubbleOpened() { … }
void TabContainerImpl::NotifyTabGroupEditorBubbleClosed() { … }
std::optional<int> TabContainerImpl::GetModelIndexOf(
const TabSlotView* slot_view) const { … }
Tab* TabContainerImpl::GetTabAtModelIndex(int index) const { … }
int TabContainerImpl::GetTabCount() const { … }
std::optional<int> TabContainerImpl::GetModelIndexOfFirstNonClosingTab(
Tab* tab) const { … }
void TabContainerImpl::UpdateHoverCard(
Tab* tab,
TabSlotController::HoverCardUpdateType update_type) { … }
void TabContainerImpl::HandleLongTap(ui::GestureEvent* event) { … }
bool TabContainerImpl::IsRectInContentArea(const gfx::Rect& rect) { … }
std::optional<ZOrderableTabContainerElement>
TabContainerImpl::GetLeadingElementForZOrdering() const { … }
std::optional<ZOrderableTabContainerElement>
TabContainerImpl::GetTrailingElementForZOrdering() const { … }
void TabContainerImpl::OnTabSlotAnimationProgressed(TabSlotView* view) { … }
void TabContainerImpl::InvalidateIdealBounds() { … }
void TabContainerImpl::AnimateToIdealBounds() { … }
bool TabContainerImpl::IsAnimating() const { … }
void TabContainerImpl::CancelAnimation() { … }
void TabContainerImpl::CompleteAnimationAndLayout() { … }
int TabContainerImpl::GetAvailableWidthForTabContainer() const { … }
void TabContainerImpl::EnterTabClosingMode(std::optional<int> override_width,
CloseTabSource source) { … }
void TabContainerImpl::ExitTabClosingMode() { … }
void TabContainerImpl::SetTabSlotVisibility() { … }
bool TabContainerImpl::InTabClose() { … }
TabGroupViews* TabContainerImpl::GetGroupViews(
tab_groups::TabGroupId group_id) const { … }
const std::map<tab_groups::TabGroupId, std::unique_ptr<TabGroupViews>>&
TabContainerImpl::get_group_views_for_testing() const { … }
int TabContainerImpl::GetActiveTabWidth() const { … }
int TabContainerImpl::GetInactiveTabWidth() const { … }
gfx::Rect TabContainerImpl::GetIdealBounds(int model_index) const { … }
gfx::Rect TabContainerImpl::GetIdealBounds(tab_groups::TabGroupId group) const { … }
void TabContainerImpl::Layout(PassKey) { … }
void TabContainerImpl::PaintChildren(const views::PaintInfo& paint_info) { … }
gfx::Size TabContainerImpl::GetMinimumSize() const { … }
gfx::Size TabContainerImpl::CalculatePreferredSize(
const views::SizeBounds& available_size) const { … }
views::View* TabContainerImpl::GetTooltipHandlerForPoint(
const gfx::Point& point) { … }
std::optional<BrowserRootView::DropIndex> TabContainerImpl::GetDropIndex(
const ui::DropTargetEvent& event) { … }
views::View* TabContainerImpl::GetViewForDrop() { … }
BrowserRootView::DropTarget* TabContainerImpl::GetDropTarget(
gfx::Point loc_in_local_coords) { … }
void TabContainerImpl::HandleDragUpdate(
const std::optional<BrowserRootView::DropIndex>& index) { … }
void TabContainerImpl::HandleDragExited() { … }
views::View* TabContainerImpl::TargetForRect(views::View* root,
const gfx::Rect& rect) { … }
void TabContainerImpl::MouseMovedOutOfHost() { … }
void TabContainerImpl::OnBoundsAnimatorProgressed(
views::BoundsAnimator* animator) { … }
void TabContainerImpl::OnBoundsAnimatorDone(views::BoundsAnimator* animator) { … }
TabContainerImpl::DropArrow::DropArrow(const BrowserRootView::DropIndex& index,
bool point_down,
views::Widget* context)
: … { … }
TabContainerImpl::DropArrow::~DropArrow() { … }
void TabContainerImpl::DropArrow::SetPointDown(bool down) { … }
void TabContainerImpl::DropArrow::SetWindowBounds(const gfx::Rect& bounds) { … }
void TabContainerImpl::DropArrow::OnWidgetDestroying(views::Widget* widget) { … }
views::ViewModelT<Tab>* TabContainerImpl::GetTabsViewModel() { … }
std::optional<gfx::Rect> TabContainerImpl::GetVisibleContentRect() { … }
void TabContainerImpl::AnimateScrollToShowXCoordinate(const int start_edge,
const int target_edge) { … }
void TabContainerImpl::AnimateTabSlotViewTo(TabSlotView* tab_slot_view,
const gfx::Rect& target_bounds) { … }
void TabContainerImpl::UpdateIdealBounds() { … }
void TabContainerImpl::SnapToIdealBounds() { … }
int TabContainerImpl::CalculateAvailableWidthForTabs() const { … }
void TabContainerImpl::StartInsertTabAnimation(int model_index) { … }
void TabContainerImpl::StartRemoveTabAnimation(Tab* tab,
int former_model_index) { … }
gfx::Rect TabContainerImpl::GetTargetBoundsForClosingTab(
Tab* tab,
int former_model_index) const { … }
int TabContainerImpl::GetIdealTrailingX() const { … }
std::optional<int> TabContainerImpl::GetMidAnimationTrailingX() const { … }
void TabContainerImpl::CloseTabInViewModel(int index) { … }
void TabContainerImpl::OnTabRemoved(Tab* tab) { … }
void TabContainerImpl::OnTabCloseAnimationCompleted(Tab* tab) { … }
void TabContainerImpl::UpdateClosingModeOnRemovedTab(int model_index,
bool was_active) { … }
void TabContainerImpl::ResizeLayoutTabs() { … }
void TabContainerImpl::ResizeLayoutTabsFromTouch() { … }
void TabContainerImpl::StartResizeLayoutTabsFromTouchTimer() { … }
bool TabContainerImpl::IsDragSessionActive() const { … }
bool TabContainerImpl::IsDragSessionEnding() const { … }
void TabContainerImpl::AddMessageLoopObserver() { … }
void TabContainerImpl::RemoveMessageLoopObserver() { … }
void TabContainerImpl::OrderTabSlotView(TabSlotView* slot_view) { … }
bool TabContainerImpl::IsPointInTab(
Tab* tab,
const gfx::Point& point_in_tabstrip_coords) { … }
Tab* TabContainerImpl::FindTabHitByPoint(const gfx::Point& point) { … }
bool TabContainerImpl::ShouldTabBeVisible(const Tab* tab) const { … }
gfx::Rect TabContainerImpl::GetDropBounds(int drop_index,
bool drop_before,
bool drop_in_group,
bool* is_beneath) { … }
void TabContainerImpl::SetDropArrow(
const std::optional<BrowserRootView::DropIndex>& index) { … }
void TabContainerImpl::UpdateAccessibleTabIndices() { … }
bool TabContainerImpl::IsValidModelIndex(int model_index) const { … }
BEGIN_METADATA(…)