Commit d22ae8d8 authored by Taylor Bergquist's avatar Taylor Bergquist Committed by Commit Bot

Track closing tabs in layout_helper_ instead of tabs_closing_map_.

This requires notifying layout_helper_ when a tab is being destroyed,
and TabStripLayoutHelper to step carefully around closing tabs in a few
places, but saves more complexity by not duplicating state between
TabStrip and TabStripLayoutHelper.

Bug: 958173
Change-Id: Iaeafc2391ecac0397947ccc34ddaecf853feb787
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1725271
Commit-Queue: Taylor Bergquist <tbergquist@chromium.org>
Reviewed-by: default avatarBret Sepulveda <bsep@chromium.org>
Cr-Commit-Position: refs/heads/master@{#683380}
parent af7c83f8
This diff is collapsed.
...@@ -298,11 +298,6 @@ class TabStrip : public views::AccessiblePaneView, ...@@ -298,11 +298,6 @@ class TabStrip : public views::AccessiblePaneView,
void HandleDragExited() override; void HandleDragExited() override;
private: private:
using Tabs = std::vector<Tab*>;
using TabsClosingMap = std::map<int, Tabs>;
using FindClosingTabResult =
std::pair<TabsClosingMap::iterator, Tabs::iterator>;
class RemoveTabDelegate; class RemoveTabDelegate;
class TabDragContextImpl; class TabDragContextImpl;
...@@ -403,8 +398,7 @@ class TabStrip : public views::AccessiblePaneView, ...@@ -403,8 +398,7 @@ class TabStrip : public views::AccessiblePaneView,
// the actual last tab unless the strip is in the overflow node_data. // the actual last tab unless the strip is in the overflow node_data.
const Tab* GetLastVisibleTab() const; const Tab* GetLastVisibleTab() const;
// Adds the tab at |index| to |tabs_closing_map_| and removes the tab from // Removes the tab at |index| from |tabs_|.
// |tabs_|.
void RemoveTabFromViewModel(int index); void RemoveTabFromViewModel(int index);
// Cleans up the Tab from the TabStrip. This is called from the tab animation // Cleans up the Tab from the TabStrip. This is called from the tab animation
...@@ -415,18 +409,10 @@ class TabStrip : public views::AccessiblePaneView, ...@@ -415,18 +409,10 @@ class TabStrip : public views::AccessiblePaneView,
// from the tab animation code and is not a general-purpose method. // from the tab animation code and is not a general-purpose method.
void OnGroupCloseAnimationCompleted(TabGroupId group); void OnGroupCloseAnimationCompleted(TabGroupId group);
// Adjusts the indices of all tabs in |tabs_closing_map_| whose index is
// >= |index| to have a new index of |index + delta|.
void UpdateTabsClosingMap(int index, int delta);
// Invoked from StoppedDraggingTabs to cleanup |tab|. If |tab| is known // Invoked from StoppedDraggingTabs to cleanup |tab|. If |tab| is known
// |is_first_tab| is set to true. // |is_first_tab| is set to true.
void StoppedDraggingTab(Tab* tab, bool* is_first_tab); void StoppedDraggingTab(Tab* tab, bool* is_first_tab);
// Finds |tab| in the |tab_closing_map_| and returns a pair of iterators
// indicating precisely where it is.
FindClosingTabResult FindClosingTab(const Tab* tab);
// Invoked when a mouse event occurs over |source|. Potentially switches the // Invoked when a mouse event occurs over |source|. Potentially switches the
// |stacked_layout_|. // |stacked_layout_|.
void UpdateStackedLayoutFromMouseEvent(views::View* source, void UpdateStackedLayoutFromMouseEvent(views::View* source,
...@@ -563,12 +549,9 @@ class TabStrip : public views::AccessiblePaneView, ...@@ -563,12 +549,9 @@ class TabStrip : public views::AccessiblePaneView,
// There is a one-to-one mapping between each of the tabs in the // There is a one-to-one mapping between each of the tabs in the
// TabStripController (TabStripModel) and |tabs_|. Because we animate tab // TabStripController (TabStripModel) and |tabs_|. Because we animate tab
// removal there exists a period of time where a tab is displayed but not in // removal there exists a period of time where a tab is displayed but not in
// the model. When this occurs the tab is removed from |tabs_| and placed in // the model. When this occurs the tab is removed from |tabs_|, but remains
// |tabs_closing_map_|. When the animation completes the tab is removed from // in |layout_helper_| until the remove animation completes.
// |tabs_closing_map_|. The painting code ensures both sets of tabs are
// painted, and the event handling code ensures only tabs in |tabs_| are used.
views::ViewModelT<Tab> tabs_; views::ViewModelT<Tab> tabs_;
TabsClosingMap tabs_closing_map_;
// Map associating each group to its TabGroupHeader instance. // Map associating each group to its TabGroupHeader instance.
std::map<TabGroupId, std::unique_ptr<TabGroupHeader>> group_headers_; std::map<TabGroupId, std::unique_ptr<TabGroupHeader>> group_headers_;
......
...@@ -54,11 +54,13 @@ enum class ViewType { ...@@ -54,11 +54,13 @@ enum class ViewType {
struct TabStripLayoutHelper::TabSlot { struct TabStripLayoutHelper::TabSlot {
static TabStripLayoutHelper::TabSlot CreateForTab( static TabStripLayoutHelper::TabSlot CreateForTab(
Tab* tab,
TabAnimationState::TabOpenness openness, TabAnimationState::TabOpenness openness,
TabAnimationState::TabPinnedness pinned, TabAnimationState::TabPinnedness pinned,
base::OnceClosure removed_callback) { base::OnceClosure removed_callback) {
TabStripLayoutHelper::TabSlot slot; TabStripLayoutHelper::TabSlot slot;
slot.type = ViewType::kTab; slot.type = ViewType::kTab;
slot.tab = tab;
TabAnimationState initial_state = TabAnimationState::ForIdealTabState( TabAnimationState initial_state = TabAnimationState::ForIdealTabState(
openness, pinned, TabAnimationState::TabActiveness::kInactive, 0); openness, pinned, TabAnimationState::TabActiveness::kInactive, 0);
slot.animation = std::make_unique<TabAnimation>( slot.animation = std::make_unique<TabAnimation>(
...@@ -86,9 +88,15 @@ struct TabStripLayoutHelper::TabSlot { ...@@ -86,9 +88,15 @@ struct TabStripLayoutHelper::TabSlot {
return group.value(); return group.value();
} }
Tab* GetTab() const {
DCHECK(tab.has_value());
return tab.value();
}
ViewType type; ViewType type;
std::unique_ptr<TabAnimation> animation; std::unique_ptr<TabAnimation> animation;
base::Optional<TabGroupId> group; base::Optional<TabGroupId> group;
base::Optional<Tab*> tab;
}; };
TabStripLayoutHelper::TabStripLayoutHelper( TabStripLayoutHelper::TabStripLayoutHelper(
...@@ -107,6 +115,17 @@ TabStripLayoutHelper::TabStripLayoutHelper( ...@@ -107,6 +115,17 @@ TabStripLayoutHelper::TabStripLayoutHelper(
TabStripLayoutHelper::~TabStripLayoutHelper() = default; TabStripLayoutHelper::~TabStripLayoutHelper() = default;
std::vector<Tab*> TabStripLayoutHelper::GetTabs() {
std::vector<Tab*> tabs;
for (const TabSlot& slot : slots_) {
if (slot.type == ViewType::kTab) {
tabs.push_back(slot.GetTab());
}
}
return tabs;
}
bool TabStripLayoutHelper::IsAnimating() const { bool TabStripLayoutHelper::IsAnimating() const {
return animation_timer_.IsRunning(); return animation_timer_.IsRunning();
} }
...@@ -123,32 +142,48 @@ int TabStripLayoutHelper::GetPinnedTabCount() const { ...@@ -123,32 +142,48 @@ int TabStripLayoutHelper::GetPinnedTabCount() const {
void TabStripLayoutHelper::InsertTabAtNoAnimation( void TabStripLayoutHelper::InsertTabAtNoAnimation(
int model_index, int model_index,
Tab* tab,
base::OnceClosure tab_removed_callback, base::OnceClosure tab_removed_callback,
TabAnimationState::TabActiveness active, TabAnimationState::TabActiveness active,
TabAnimationState::TabPinnedness pinned) { TabAnimationState::TabPinnedness pinned) {
const int slot_index = GetSlotIndexForTabModelIndex(model_index); const int slot_index = GetSlotIndexForTabModelIndex(model_index);
slots_.insert(slots_.begin() + slot_index, slots_.insert(
TabSlot::CreateForTab(TabAnimationState::TabOpenness::kOpen, slots_.begin() + slot_index,
pinned, std::move(tab_removed_callback))); TabSlot::CreateForTab(tab, TabAnimationState::TabOpenness::kOpen, pinned,
std::move(tab_removed_callback)));
} }
void TabStripLayoutHelper::InsertTabAt( void TabStripLayoutHelper::InsertTabAt(
int model_index, int model_index,
Tab* tab,
base::OnceClosure tab_removed_callback, base::OnceClosure tab_removed_callback,
TabAnimationState::TabActiveness active, TabAnimationState::TabActiveness active,
TabAnimationState::TabPinnedness pinned) { TabAnimationState::TabPinnedness pinned) {
const int slot_index = GetSlotIndexForTabModelIndex(model_index); const int slot_index = GetSlotIndexForTabModelIndex(model_index);
slots_.insert(slots_.begin() + slot_index, slots_.insert(
TabSlot::CreateForTab(TabAnimationState::TabOpenness::kClosed, slots_.begin() + slot_index,
pinned, std::move(tab_removed_callback))); TabSlot::CreateForTab(tab, TabAnimationState::TabOpenness::kClosed,
pinned, std::move(tab_removed_callback)));
AnimateSlot(slot_index, AnimateSlot(slot_index,
slots_[slot_index].animation->target_state().WithOpenness( slots_[slot_index].animation->target_state().WithOpenness(
TabAnimationState::TabOpenness::kOpen)); TabAnimationState::TabOpenness::kOpen));
} }
void TabStripLayoutHelper::RemoveTabAt(int model_index) { void TabStripLayoutHelper::CloseTabAt(int model_index) {
// TODO(958173): Animate closed. // TODO(958173): Animate closed.
slots_.erase(slots_.begin() + GetSlotIndexForTabModelIndex(model_index)); TabAnimation* animation =
slots_[GetSlotIndexForTabModelIndex(model_index)].animation.get();
animation->AnimateTo(animation->target_state().WithOpenness(
TabAnimationState::TabOpenness::kClosed));
}
void TabStripLayoutHelper::OnTabDestroyed(Tab* tab) {
auto it =
std::find_if(slots_.begin(), slots_.end(), [tab](const TabSlot& slot) {
return slot.type == ViewType::kTab && slot.GetTab() == tab;
});
DCHECK(it != slots_.end());
slots_.erase(it);
} }
void TabStripLayoutHelper::MoveTab( void TabStripLayoutHelper::MoveTab(
...@@ -254,8 +289,11 @@ void TabStripLayoutHelper::UpdateIdealBounds(int available_width) { ...@@ -254,8 +289,11 @@ void TabStripLayoutHelper::UpdateIdealBounds(int available_width) {
auto pinned = i <= last_pinned_tab_slot_index auto pinned = i <= last_pinned_tab_slot_index
? TabAnimationState::TabPinnedness::kPinned ? TabAnimationState::TabPinnedness::kPinned
: TabAnimationState::TabPinnedness::kUnpinned; : TabAnimationState::TabPinnedness::kUnpinned;
ideal_animation_states.push_back(TabAnimationState::ForIdealTabState( auto open = slots_[i].animation->target_state().IsFullyClosed()
TabAnimationState::TabOpenness::kOpen, pinned, active, 0)); ? TabAnimationState::TabOpenness::kClosed
: TabAnimationState::TabOpenness::kOpen;
ideal_animation_states.push_back(
TabAnimationState::ForIdealTabState(open, pinned, active, 0));
} }
const std::vector<gfx::Rect> bounds = CalculateTabBounds( const std::vector<gfx::Rect> bounds = CalculateTabBounds(
...@@ -271,9 +309,12 @@ void TabStripLayoutHelper::UpdateIdealBounds(int available_width) { ...@@ -271,9 +309,12 @@ void TabStripLayoutHelper::UpdateIdealBounds(int available_width) {
const TabSlot& slot = slots_[i]; const TabSlot& slot = slots_[i];
switch (slot.type) { switch (slot.type) {
case ViewType::kTab: case ViewType::kTab:
tabs->set_ideal_bounds(current_tab_model_index, bounds[i]); if (!slot.animation->target_state().IsFullyClosed()) {
UpdateCachedTabWidth(i, bounds[i].width(), i == active_tab_slot_index); tabs->set_ideal_bounds(current_tab_model_index, bounds[i]);
++current_tab_model_index; UpdateCachedTabWidth(i, bounds[i].width(),
i == active_tab_slot_index);
++current_tab_model_index;
}
break; break;
case ViewType::kGroupHeader: case ViewType::kGroupHeader:
group_headers[slot.GetGroup()]->SetBoundsRect(bounds[i]); group_headers[slot.GetGroup()]->SetBoundsRect(bounds[i]);
...@@ -314,8 +355,15 @@ int TabStripLayoutHelper::LayoutTabs(int available_width) { ...@@ -314,8 +355,15 @@ int TabStripLayoutHelper::LayoutTabs(int available_width) {
std::vector<gfx::Rect> bounds = CalculateTabBounds( std::vector<gfx::Rect> bounds = CalculateTabBounds(
GetTabSizeInfo(), GetCurrentTabStates(), available_width); GetTabSizeInfo(), GetCurrentTabStates(), available_width);
// TODO(958173): Assume for now that there are no closing tabs or headers. if (DCHECK_IS_ON()) {
DCHECK_EQ(bounds.size(), tabs->view_size() + group_headers.size()); int num_closing_tabs = 0;
for (Tab* tab : GetTabs()) {
if (tab->closing())
++num_closing_tabs;
}
DCHECK_EQ(bounds.size(),
tabs->view_size() + num_closing_tabs + group_headers.size());
}
int trailing_x = 0; int trailing_x = 0;
...@@ -325,8 +373,9 @@ int TabStripLayoutHelper::LayoutTabs(int available_width) { ...@@ -325,8 +373,9 @@ int TabStripLayoutHelper::LayoutTabs(int available_width) {
for (size_t i = 0; i < bounds.size(); i++) { for (size_t i = 0; i < bounds.size(); i++) {
switch (slots_[i].type) { switch (slots_[i].type) {
case ViewType::kTab: { case ViewType::kTab: {
if (!tabs->view_at(current_tab_model_index)->dragging()) { Tab* tab = slots_[i].GetTab();
tabs->view_at(current_tab_model_index)->SetBoundsRect(bounds[i]); if (!tab->dragging()) {
tab->SetBoundsRect(bounds[i]);
trailing_x = std::max(trailing_x, bounds[i].right()); trailing_x = std::max(trailing_x, bounds[i].right());
// TODO(958173): We shouldn't need to update the cached widths here, // TODO(958173): We shouldn't need to update the cached widths here,
// since they're also updated in UpdateIdealBounds. However, tests // since they're also updated in UpdateIdealBounds. However, tests
...@@ -335,7 +384,8 @@ int TabStripLayoutHelper::LayoutTabs(int available_width) { ...@@ -335,7 +384,8 @@ int TabStripLayoutHelper::LayoutTabs(int available_width) {
current_tab_model_index, bounds[i].width(), current_tab_model_index, bounds[i].width(),
current_tab_model_index == active_tab_model_index); current_tab_model_index == active_tab_model_index);
} }
++current_tab_model_index; if (!slots_[i].animation->target_state().IsFullyClosed())
++current_tab_model_index;
break; break;
} }
case ViewType::kGroupHeader: { case ViewType::kGroupHeader: {
...@@ -353,7 +403,8 @@ int TabStripLayoutHelper::LayoutTabs(int available_width) { ...@@ -353,7 +403,8 @@ int TabStripLayoutHelper::LayoutTabs(int available_width) {
int TabStripLayoutHelper::GetSlotIndexForTabModelIndex(int model_index) const { int TabStripLayoutHelper::GetSlotIndexForTabModelIndex(int model_index) const {
int current_model_index = 0; int current_model_index = 0;
for (size_t i = 0; i < slots_.size(); i++) { for (size_t i = 0; i < slots_.size(); i++) {
if (slots_[i].type == ViewType::kTab) { if (slots_[i].type == ViewType::kTab &&
!slots_[i].animation->target_state().IsFullyClosed()) {
if (current_model_index == model_index) if (current_model_index == model_index)
return i; return i;
++current_model_index; ++current_model_index;
......
...@@ -36,6 +36,10 @@ class TabStripLayoutHelper { ...@@ -36,6 +36,10 @@ class TabStripLayoutHelper {
base::RepeatingClosure on_animation_progressed); base::RepeatingClosure on_animation_progressed);
~TabStripLayoutHelper(); ~TabStripLayoutHelper();
// Returns a vector of all tabs in the strip, including both closing tabs
// and tabs still in the model.
std::vector<Tab*> GetTabs();
// Returns whether any animations for tabs or group headers are in progress. // Returns whether any animations for tabs or group headers are in progress.
bool IsAnimating() const; bool IsAnimating() const;
...@@ -50,6 +54,7 @@ class TabStripLayoutHelper { ...@@ -50,6 +54,7 @@ class TabStripLayoutHelper {
// Inserts a new tab at |index|, without animation. |tab_removed_callback| // Inserts a new tab at |index|, without animation. |tab_removed_callback|
// will be invoked if the tab is removed at the end of a remove animation. // will be invoked if the tab is removed at the end of a remove animation.
void InsertTabAtNoAnimation(int model_index, void InsertTabAtNoAnimation(int model_index,
Tab* tab,
base::OnceClosure tab_removed_callback, base::OnceClosure tab_removed_callback,
TabAnimationState::TabActiveness active, TabAnimationState::TabActiveness active,
TabAnimationState::TabPinnedness pinned); TabAnimationState::TabPinnedness pinned);
...@@ -57,14 +62,18 @@ class TabStripLayoutHelper { ...@@ -57,14 +62,18 @@ class TabStripLayoutHelper {
// Inserts a new tab at |index|, with animation. |tab_removed_callback| will // Inserts a new tab at |index|, with animation. |tab_removed_callback| will
// be invoked if the tab is removed at the end of a remove animation. // be invoked if the tab is removed at the end of a remove animation.
void InsertTabAt(int model_index, void InsertTabAt(int model_index,
Tab* tab,
base::OnceClosure tab_removed_callback, base::OnceClosure tab_removed_callback,
TabAnimationState::TabActiveness active, TabAnimationState::TabActiveness active,
TabAnimationState::TabPinnedness pinned); TabAnimationState::TabPinnedness pinned);
// Removes the tab at |index|. TODO(958173): This should invoke the associated // Marks the tab at |model_index| as closing. Invoked when the remove
// |tab_removed_callback| but currently does not, as it would duplicate // animation begins and the tab is removed from the model.
// TabStrip::RemoveTabDelegate::AnimationEnded. void CloseTabAt(int model_index);
void RemoveTabAt(int model_index);
// Invoked when |tab| has been destroyed by TabStrip (i.e. the remove
// animation has completed).
void OnTabDestroyed(Tab* tab);
// Moves the tab at |prev_index| with group |group_at_prev_index| to // Moves the tab at |prev_index| with group |group_at_prev_index| to
// |new_index|. Also updates the group header's location if necessary. // |new_index|. Also updates the group header's location if necessary.
...@@ -90,9 +99,11 @@ class TabStripLayoutHelper { ...@@ -90,9 +99,11 @@ class TabStripLayoutHelper {
// Finishes all in-progress animations. // Finishes all in-progress animations.
void CompleteAnimations(); void CompleteAnimations();
// TODO(958173): Temporary method. Like CompleteAnimations, but does not call // TODO(958173): Temporary method that completes running animations
// any associated |tab_removed_callback| or |header_removed_callback|. See // without invoking the callback to destroy removed tabs. Use to hand
// comment on TabStripAnimator::CompleteAnimationsWithoutDestroyingTabs. // off animation (and removed tab destruction) responsibilities from
// this animator to elsewhere without teleporting tabs or destroying
// the same tab more than once.
void CompleteAnimationsWithoutDestroyingTabs(); void CompleteAnimationsWithoutDestroyingTabs();
// Generates and sets the ideal bounds for the views in |tabs| and // Generates and sets the ideal bounds for the views in |tabs| and
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment