[Vertical Tabs] Wrap top container buttons around caption buttons

Narrow panel: https://screenshot.googleplex.com/BjG4Lt6C89WxUcY
Wide panel: https://screenshot.googleplex.com/38FpnAm5uPmKA27

Bug: 465857622
Change-Id: I001cd820dc367ea498c722796769d98f71fb0ed8
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/7256774
Commit-Queue: Alison Gale <agale@chromium.org>
Reviewed-by: Eshwar Stalin <estalin@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1558326}
diff --git a/chrome/browser/ui/views/tabs/vertical/vertical_tab_strip_top_container.cc b/chrome/browser/ui/views/tabs/vertical/vertical_tab_strip_top_container.cc
index 6012fea..2933231 100644
--- a/chrome/browser/ui/views/tabs/vertical/vertical_tab_strip_top_container.cc
+++ b/chrome/browser/ui/views/tabs/vertical/vertical_tab_strip_top_container.cc
@@ -86,29 +86,38 @@
 views::ProposedLayout VerticalTabStripTopContainer::CalculateProposedLayout(
     const views::SizeBounds& size_bounds) const {
   views::ProposedLayout layout;
-  // TODO(crbug.com/465857622): Implement smarter reflow around caption buttons.
-  const int exclusion_height = exclusion_width_ > 0 ? toolbar_height_ : 0;
-  layout.host_size =
+  gfx::Size host_size =
       gfx::Size(size_bounds.width().is_bounded() ? size_bounds.width().value()
                                                  : parent()->width(),
-                kTopButtonContainerHeight + exclusion_height);
+                kTopButtonContainerHeight);
 
   CHECK(tab_search_button_);
   CHECK(collapse_button_);
 
   const gfx::Size tab_search_button_pref_size =
-      tab_search_button_->GetPreferredSize(views::SizeBounds(layout.host_size));
+      tab_search_button_->GetPreferredSize();
   const gfx::Size collapse_button_pref_size =
-      collapse_button_->GetPreferredSize(views::SizeBounds(layout.host_size));
+      collapse_button_->GetPreferredSize();
 
-  int current_x = layout.host_size.width();
-  int current_y = layout.host_size.height() - exclusion_height;
+  // If there is not enough space for the buttons on a single line with caption
+  // buttons, shift them below.
+  if (exclusion_width_ > 0 &&
+      exclusion_width_ + tab_search_button_pref_size.width() +
+              kTopButtonPadding + collapse_button_pref_size.width() >
+          host_size.width()) {
+    host_size.Enlarge(0, toolbar_height_);
+  }
+
+  int current_x = host_size.width();
+  int current_y = host_size.height();
 
   // Calculate bounds to right-align the button horizontally and center it
   // vertically within the available space.
   gfx::Rect tab_search_button_bounds(
       current_x - tab_search_button_pref_size.width(),
-      (current_y - tab_search_button_pref_size.height()) / 2 + exclusion_height,
+      current_y -
+          (kTopButtonContainerHeight + tab_search_button_pref_size.height()) /
+              2,
       tab_search_button_pref_size.width(),
       tab_search_button_pref_size.height());
   layout.child_layouts.emplace_back(
@@ -120,12 +129,14 @@
   // Re-calculate bounds based on new x value, offset by the tab search button.
   gfx::Rect collapse_button_bounds(
       current_x - collapse_button_pref_size.width(),
-      (current_y - collapse_button_pref_size.height()) / 2 + exclusion_height,
+      current_y -
+          (kTopButtonContainerHeight + collapse_button_pref_size.height()) / 2,
       collapse_button_pref_size.width(), collapse_button_pref_size.height());
   layout.child_layouts.emplace_back(
       collapse_button_.get(), collapse_button_->GetVisible(),
       collapse_button_bounds, views::SizeBounds(collapse_button_pref_size));
 
+  layout.host_size = host_size;
   return layout;
 }
 
diff --git a/chrome/browser/ui/views/tabs/vertical/vertical_tab_strip_top_container_unittest.cc b/chrome/browser/ui/views/tabs/vertical/vertical_tab_strip_top_container_unittest.cc
index ec704be8..b377a798 100644
--- a/chrome/browser/ui/views/tabs/vertical/vertical_tab_strip_top_container_unittest.cc
+++ b/chrome/browser/ui/views/tabs/vertical/vertical_tab_strip_top_container_unittest.cc
@@ -142,3 +142,24 @@
   EXPECT_EQ(collapse_bounds.right_center().y(),
             initial_collapse_bounds.right_center().y() + kExclusionHeight);
 }
+
+TEST_F(VerticalTabStripTopContainerTest, LayoutWithPartialWidthExclusionZone) {
+  top_container()->SetExclusionWidthForLayout(50);
+  top_container()->SetToolbarHeightForLayout(50);
+  LayoutView();
+
+  const gfx::Rect container_bounds = top_container()->bounds();
+  const gfx::Rect search_bounds = tab_search_button()->bounds();
+  const gfx::Rect collapse_bounds = collapse_button()->bounds();
+
+  // The tab search button should be right aligned to the container and
+  // vertically centered. Due to rounding, there is an off-by-one error
+  // with the vertical centering of the button.
+  EXPECT_EQ(search_bounds.top_right().x(), container_bounds.top_right().x());
+  EXPECT_NEAR(search_bounds.right_center().y(),
+              container_bounds.right_center().y(), 1);
+
+  // The collapse button should be to the left of the tab search button.
+  EXPECT_LT(collapse_bounds.CenterPoint().x(), search_bounds.CenterPoint().x());
+  EXPECT_EQ(collapse_bounds.CenterPoint().y(), search_bounds.CenterPoint().y());
+}