Improvements in FlexLayout "stretch" cross-axis alignment handling.

Previously, a child view with a very large cross-axis size would cause
a layout with cross-axis alignment set to "stretch" to become larger, so
child views would be stretched to a size larger than the host view,
cutting off the trailing end of the child views.

Now, when the cross-axis alignment is set to stretch and a cross-axis
size is specified, the layout will be exactly that large in the
cross-axis dimension. The only exception is if a minimum cross-axis size
is specified, or the interior margines would be too large to fit in the
available space.

Example:
Vertical layout with cross-axis set to stretch.
Host view width = 100.
Two child views, one with a width of 120, the other with a width of 50.

In the old behavior, the first child would force the layout to 120 DIPs
and both views would stretch to that size.
+-------------------+
| Host view         |
|+-----------------------+
|| Child view 1          |
|+-----------------------+
|+-----------------------+
|| Child view 2          |
|+-----------------------+
+-------------------+

In the new behavior, the layout would be forced to fit in exactly the
size of the host view, setting them both to 100 DIPs.
+-------------------+
| Host view         |
|+-----------------+|
|| Child view 1    ||
|+-----------------+|
|+-----------------+|
|| Child view 2    ||
|+-----------------+|
+-------------------+

In nearly all cases, this second behavior is the intended one when
stretch is specified, hence the change.

Still to do: properly handle GetHeightForWidth() in this case, but that
only affects vertical layouts with multiline text and so far there are
no known examples using FlexLayout.

Bug: 930500

Change-Id: I44aa75051406628210751cd1a36040def47996b4
Reviewed-on: https://chromium-review.googlesource.com/c/1461829
Commit-Queue: Dana Fried <dfried@chromium.org>
Reviewed-by: Bret Sepulveda <bsep@chromium.org>
Cr-Commit-Position: refs/heads/master@{#631485}
diff --git a/ui/views/layout/flex_layout.cc b/ui/views/layout/flex_layout.cc
index ca5e664..b8c7edb 100644
--- a/ui/views/layout/flex_layout.cc
+++ b/ui/views/layout/flex_layout.cc
@@ -354,6 +354,13 @@
                                 ChildViewSpacing* child_spacing,
                                 const NormalizedSizeBounds& bounds) const;
 
+  // Calculates the cross-layout space available to a view based on the
+  // available space and margins.
+  base::Optional<int> GetAvailableCrossAxisSize(
+      const Layout& layout,
+      int child_index,
+      const NormalizedSizeBounds& bounds) const;
+
   // Calculates a margin between two child views based on each's margin and any
   // internal padding present in one or both elements. Uses properties of the
   // layout, like whether adjacent margins should be collapsed.
@@ -390,8 +397,8 @@
 const Layout& FlexLayoutInternal::CalculateLayout(const SizeBounds& bounds) {
   // If bounds are smaller than the minimum cross axis size, expand them.
   NormalizedSizeBounds normalized_bounds = Normalize(orientation(), bounds);
-  if (normalized_bounds.cross().has_value() &&
-      normalized_bounds.cross().value() < layout_.minimum_cross_axis_size()) {
+  if (normalized_bounds.cross() &&
+      *normalized_bounds.cross() < layout_.minimum_cross_axis_size()) {
     normalized_bounds = NormalizedSizeBounds{normalized_bounds.main(),
                                              layout_.minimum_cross_axis_size()};
   }
@@ -441,6 +448,25 @@
   }
 }
 
+base::Optional<int> FlexLayoutInternal::GetAvailableCrossAxisSize(
+    const Layout& layout,
+    int child_index,
+    const NormalizedSizeBounds& bounds) const {
+  if (!bounds.cross())
+    return base::Optional<int>();
+
+  const ChildLayout& child_layout = layout.child_layouts[child_index];
+  const int leading_margin =
+      CalculateMargin(layout.interior_margin.cross_leading(),
+                      child_layout.margins.cross_leading(),
+                      child_layout.internal_padding.cross_leading());
+  const int trailing_margin =
+      CalculateMargin(layout.interior_margin.cross_trailing(),
+                      child_layout.margins.cross_trailing(),
+                      child_layout.internal_padding.cross_trailing());
+  return std::max(0, *bounds.cross() - (leading_margin + trailing_margin));
+}
+
 int FlexLayoutInternal::CalculateMargin(int margin1,
                                         int margin2,
                                         int internal_padding) const {
@@ -482,13 +508,19 @@
     ChildViewSpacing* child_spacing,
     const NormalizedSizeBounds& bounds) const {
   // Calculate starting minimum for cross-axis size.
-  const int min_cross_size =
+  int min_cross_size =
       std::max(layout_.minimum_cross_axis_size(),
                CalculateMargin(layout->interior_margin.cross_leading(),
                                layout->interior_margin.cross_trailing(), 0));
   layout->total_size = NormalizedSize(0, min_cross_size);
-  if (bounds.cross().has_value())
-    layout->total_size.SetToMax(0, bounds.cross().value());
+
+  // For cases with a non-zero cross-axis bound, the objective is to fit the
+  // layout into that precise size, not to determine what size we need.
+  bool force_cross_size = false;
+  if (bounds.cross() && *bounds.cross() > 0) {
+    layout->total_size.SetToMax(0, *bounds.cross());
+    force_cross_size = true;
+  }
 
   std::vector<Inset1D> cross_spacings(layout->child_layouts.size());
   for (size_t i = 0; i < layout->child_layouts.size(); ++i) {
@@ -498,7 +530,7 @@
     if (child_layout.excluded || !child_layout.visible)
       continue;
 
-    // Update the cross-axis size.
+    // Update the cross-axis margins and if necessary, the size.
     Inset1D& cross_spacing = cross_spacings[i];
     cross_spacing.set_leading(
         CalculateMargin(layout->interior_margin.cross_leading(),
@@ -509,9 +541,11 @@
                         child_layout.margins.cross_trailing(),
                         child_layout.internal_padding.cross_trailing()));
 
-    const int cross_size = std::min(child_layout.current_size.cross(),
-                                    child_layout.preferred_size.cross());
-    layout->total_size.SetToMax(0, cross_spacing.size() + cross_size);
+    if (!force_cross_size) {
+      const int cross_size = std::min(child_layout.current_size.cross(),
+                                      child_layout.preferred_size.cross());
+      layout->total_size.SetToMax(0, cross_spacing.size() + cross_size);
+    }
 
     // Calculate main-axis size and upper-left main axis coordinate.
     int leading_space;
@@ -530,8 +564,8 @@
   // Add the end margin.
   layout->total_size.Enlarge(child_spacing->GetTrailingInset(), 0);
 
-  // Calculate vertical positioning given the cross-axis size we've already
-  // calculated above.
+  // Calculate cross-axis positioning based on the cross margins and size that
+  // were calculated above.
   const Span cross_span(0, layout->total_size.cross());
   for (size_t i = 0; i < layout->child_layouts.size(); ++i) {
     ChildLayout& child_layout = layout->child_layouts[i];
@@ -540,12 +574,13 @@
     if (child_layout.excluded || !child_layout.visible)
       continue;
 
-    // Because we have an explicit kStretch option, regardless of what the
-    // control *says* we won't allow the cross-axis size to exceed the preferred
-    // size. kStretch may cause it to become larger.
-    const int cross_size = std::min(child_layout.current_size.cross(),
-                                    child_layout.preferred_size.cross());
-    child_layout.actual_bounds.set_size_cross(cross_size);
+    // Start with a size appropriate for the child view. For child views which
+    // can become larger than the preferred size, start with the preferred size
+    // and let the alignment operation (specifically, if the alignment is set to
+    // kStretch) grow the child view.
+    const int starting_cross_size = std::min(
+        child_layout.current_size.cross(), child_layout.preferred_size.cross());
+    child_layout.actual_bounds.set_size_cross(starting_cross_size);
     child_layout.actual_bounds.AlignCross(
         cross_span, layout_.cross_axis_alignment(), cross_spacings[i]);
   }
@@ -553,20 +588,13 @@
 
 const Layout& FlexLayoutInternal::CalculateNewLayout(
     const NormalizedSizeBounds& bounds) {
-  DCHECK(!bounds.cross().has_value() ||
-         bounds.cross().value() >= layout_.minimum_cross_axis_size());
+  DCHECK(!bounds.cross() ||
+         *bounds.cross() >= layout_.minimum_cross_axis_size());
   std::unique_ptr<Layout> layout = std::make_unique<Layout>(layout_counter_);
   layout->interior_margin = Normalize(orientation(), layout_.interior_margin());
   std::map<int, std::vector<int>> order_to_view_index;
   const bool main_axis_bounded = bounds.main().has_value();
 
-  // Start with the smallest size the child view can occupy.
-  NormalizedSizeBounds effective_bounds{0, bounds.cross()};
-  if (effective_bounds.cross()) {
-    effective_bounds.set_cross(std::max(
-        0, *effective_bounds.cross() - layout->interior_margin.cross_size()));
-  }
-
   // Step through the children, creating placeholder layout view elements
   // and setting up initial minimal visibility.
   View* const view = layout_.host();
@@ -592,10 +620,12 @@
 
     // gfx::Size calculation depends on whether flex is allowed.
     if (main_axis_bounded) {
-      child_layout.current_size =
-          Normalize(orientation(),
-                    child_layout.flex.rule().Run(
-                        child, Denormalize(orientation(), effective_bounds)));
+      child_layout.available_size = {
+          0, GetAvailableCrossAxisSize(*layout, i, bounds)};
+      child_layout.current_size = Normalize(
+          orientation(),
+          child_layout.flex.rule().Run(
+              child, Denormalize(orientation(), child_layout.available_size)));
 
       // We should revisit whether this is a valid assumption for text views
       // in vertical layouts.
@@ -605,7 +635,7 @@
       // Keep track of non-hidden flex controls.
       const bool can_flex =
           (child_layout.flex.weight() > 0 &&
-           !child_layout.preferred_size.is_empty()) ||
+           child_layout.preferred_size.main() > 0) ||
           child_layout.current_size.main() < child_layout.preferred_size.main();
       if (can_flex)
         order_to_view_index[child_layout.flex.order()].push_back(i);
@@ -615,7 +645,7 @@
       child_layout.current_size = child_layout.preferred_size;
     }
 
-    child_layout.visible = !child_layout.current_size.is_empty();
+    child_layout.visible = child_layout.current_size.main() > 0;
 
     // Actual size and positioning will be set during the final layout
     // calculation.
@@ -720,12 +750,13 @@
         // Offer the modified flex space to the child view and see how large it
         // wants to be (or if it wants to be visible at that size at all).
         const NormalizedSizeBounds available(
-            flex_amount + old_size - margin_delta, effective_bounds.cross());
+            flex_amount + old_size - margin_delta,
+            child_layout.available_size.cross());
         const NormalizedSize new_size = Normalize(
             orientation(),
             child_layout.flex.rule().Run(
                 child_layout.view, Denormalize(orientation(), available)));
-        if (new_size.is_empty())
+        if (new_size.main() <= 0)
           continue;
 
         // If the amount of space claimed increases (but is still within
diff --git a/ui/views/layout/flex_layout_types_internal.cc b/ui/views/layout/flex_layout_types_internal.cc
index 83e255e..c1707f3 100644
--- a/ui/views/layout/flex_layout_types_internal.cc
+++ b/ui/views/layout/flex_layout_types_internal.cc
@@ -49,13 +49,25 @@
 }
 
 void Span::Center(const Span& container, const Inset1D& margins) {
-  const int margin_total = margins.size();
-  const int remaining = container.length() - (length() + margin_total);
-  if (remaining >= 0 || margin_total <= 0)
-    set_start(container.start() + margins.leading() + remaining / 2);
-  else
-    set_start(((container.length() - length()) * margins.leading()) /
-              margin_total);
+  int remaining = container.length() - length();
+
+  // Case 1: no room for any margins. Just center the span in the container,
+  // with equal overflow on each side.
+  if (remaining <= 0) {
+    set_start(std::ceilf(remaining * 0.5f));
+    return;
+  }
+
+  // Case 2: room for only part of the margins.
+  if (margins.size() > remaining) {
+    float scale = float{remaining} / float{margins.size()};
+    set_start(std::roundf(scale * margins.leading()));
+    return;
+  }
+
+  // Case 3: room for both span and margins. Center the whole unit.
+  remaining -= margins.size();
+  set_start(remaining / 2 + margins.leading());
 }
 
 void Span::Align(const Span& container,
diff --git a/ui/views/layout/flex_layout_unittest.cc b/ui/views/layout/flex_layout_unittest.cc
index 18cb42e..50ffda4 100644
--- a/ui/views/layout/flex_layout_unittest.cc
+++ b/ui/views/layout/flex_layout_unittest.cc
@@ -5,6 +5,8 @@
 #include "ui/views/layout/flex_layout.h"
 
 #include <stddef.h>
+
+#include <algorithm>
 #include <vector>
 
 #include "base/bind.h"
@@ -114,6 +116,13 @@
   }
 
  protected:
+  // Constants re-used in many tests.
+  static const Insets kLayoutInsets;
+  static const Insets kLargeInsets;
+  static const Size kChild1Size;
+  static const Size kChild2Size;
+  static const Size kChild3Size;
+
   // Preferred size or drop out.
   static const FlexSpecification kDropOut;
   static const FlexSpecification kDropOutHighPriority;
@@ -137,6 +146,12 @@
   FlexLayout* layout_;
 };
 
+const Insets FlexLayoutTest::kLayoutInsets{5, 6, 7, 9};
+const Insets FlexLayoutTest::kLargeInsets{10, 11, 12, 13};
+const Size FlexLayoutTest::kChild1Size{12, 10};
+const Size FlexLayoutTest::kChild2Size{13, 11};
+const Size FlexLayoutTest::kChild3Size{17, 13};
+
 const FlexSpecification FlexLayoutTest::kDropOut =
     FlexSpecification::ForSizeRule(MinimumFlexSizeRule::kPreferredSnapToZero,
                                    MaximumFlexSizeRule::kPreferred)
@@ -191,21 +206,21 @@
 TEST_F(FlexLayoutTest, GetMinimumSize_Empty_ViewInsets) {
   layout_->SetOrientation(LayoutOrientation::kHorizontal);
   layout_->SetCollapseMargins(false);
-  host_->SetBorder(CreateEmptyBorder(5, 6, 7, 9));
+  host_->SetBorder(CreateEmptyBorder(kLayoutInsets));
   EXPECT_EQ(Size(15, 12), host_->GetMinimumSize());
 }
 
 TEST_F(FlexLayoutTest, GetMinimumSize_Empty_InternalMargin_Collapsed) {
   layout_->SetOrientation(LayoutOrientation::kHorizontal);
   layout_->SetCollapseMargins(true);
-  layout_->SetInteriorMargin(Insets(5, 6, 7, 9));
+  layout_->SetInteriorMargin(kLayoutInsets);
   EXPECT_EQ(Size(9, 7), host_->GetMinimumSize());
 }
 
 TEST_F(FlexLayoutTest, GetMinimumSize_Empty_InternalMargin_NotCollapsed) {
   layout_->SetOrientation(LayoutOrientation::kHorizontal);
   layout_->SetCollapseMargins(false);
-  layout_->SetInteriorMargin(Insets(5, 6, 7, 9));
+  layout_->SetInteriorMargin(kLayoutInsets);
   EXPECT_EQ(Size(15, 12), host_->GetMinimumSize());
 }
 
@@ -213,7 +228,7 @@
        GetMinimumSize_Empty_InternalMargin_DefaultMarginHasNoEffect) {
   layout_->SetOrientation(LayoutOrientation::kHorizontal);
   layout_->SetCollapseMargins(false);
-  layout_->SetInteriorMargin(Insets(5, 6, 7, 9));
+  layout_->SetInteriorMargin(kLayoutInsets);
   layout_->SetDefaultChildMargins(gfx::Insets(11, 11));
   EXPECT_EQ(Size(15, 12), host_->GetMinimumSize());
 }
@@ -221,7 +236,7 @@
 TEST_F(FlexLayoutTest, GetMinimumSize_MinimumCross_Horizontal) {
   layout_->SetOrientation(LayoutOrientation::kHorizontal);
   layout_->SetCollapseMargins(true);
-  layout_->SetInteriorMargin(Insets(5, 6, 7, 9));
+  layout_->SetInteriorMargin(kLayoutInsets);
   layout_->SetMinimumCrossAxisSize(5);
   EXPECT_EQ(Size(9, 7), host_->GetMinimumSize());
   layout_->SetMinimumCrossAxisSize(10);
@@ -233,7 +248,7 @@
 TEST_F(FlexLayoutTest, GetMinimumSize_MinimumCross_Vertical) {
   layout_->SetOrientation(LayoutOrientation::kVertical);
   layout_->SetCollapseMargins(true);
-  layout_->SetInteriorMargin(Insets(5, 6, 7, 9));
+  layout_->SetInteriorMargin(kLayoutInsets);
   layout_->SetMinimumCrossAxisSize(5);
   EXPECT_EQ(Size(9, 7), host_->GetMinimumSize());
   layout_->SetMinimumCrossAxisSize(10);
@@ -287,11 +302,11 @@
 TEST_F(FlexLayoutTest, Layout_VisibilitySetBeforeAdd) {
   layout_->SetOrientation(LayoutOrientation::kHorizontal);
   layout_->SetCollapseMargins(true);
-  layout_->SetInteriorMargin(Insets(5, 6, 7, 9));
+  layout_->SetInteriorMargin(kLayoutInsets);
   layout_->SetCrossAxisAlignment(LayoutAlignment::kStart);
-  View* child1 = AddChild(Size(12, 10));
-  View* child2 = AddChild(Size(13, 11), Optional<Size>(), false);
-  View* child3 = AddChild(Size(17, 13));
+  View* child1 = AddChild(kChild1Size);
+  View* child2 = AddChild(kChild2Size, Optional<Size>(), false);
+  View* child3 = AddChild(kChild3Size);
 
   host_->Layout();
   EXPECT_EQ(true, layout_->IsHiddenByOwner(child2));
@@ -322,11 +337,11 @@
 TEST_F(FlexLayoutTest, Layout_VisibilitySetAfterAdd) {
   layout_->SetOrientation(LayoutOrientation::kHorizontal);
   layout_->SetCollapseMargins(true);
-  layout_->SetInteriorMargin(Insets(5, 6, 7, 9));
+  layout_->SetInteriorMargin(kLayoutInsets);
   layout_->SetCrossAxisAlignment(LayoutAlignment::kStart);
-  View* child1 = AddChild(Size(12, 10));
-  View* child2 = AddChild(Size(13, 11));
-  View* child3 = AddChild(Size(17, 13));
+  View* child1 = AddChild(kChild1Size);
+  View* child2 = AddChild(kChild2Size);
+  View* child3 = AddChild(kChild3Size);
 
   child2->SetVisible(false);
   host_->Layout();
@@ -350,11 +365,11 @@
        Layout_ViewVisibilitySetNotContingentOnActualVisibility) {
   layout_->SetOrientation(LayoutOrientation::kHorizontal);
   layout_->SetCollapseMargins(true);
-  layout_->SetInteriorMargin(Insets(5, 6, 7, 9));
+  layout_->SetInteriorMargin(kLayoutInsets);
   layout_->SetCrossAxisAlignment(LayoutAlignment::kStart);
-  View* child1 = AddChild(Size(12, 10));
-  View* child2 = AddChild(Size(13, 11));
-  View* child3 = AddChild(Size(17, 13));
+  View* child1 = AddChild(kChild1Size);
+  View* child2 = AddChild(kChild2Size);
+  View* child3 = AddChild(kChild3Size);
   layout_->SetFlexForView(child2, kDropOut);
 
   // Layout makes child view invisible due to flex rule.
@@ -383,11 +398,11 @@
 TEST_F(FlexLayoutTest, Layout_Exlcude) {
   layout_->SetOrientation(LayoutOrientation::kHorizontal);
   layout_->SetCollapseMargins(true);
-  layout_->SetInteriorMargin(Insets(5, 6, 7, 9));
+  layout_->SetInteriorMargin(kLayoutInsets);
   layout_->SetCrossAxisAlignment(LayoutAlignment::kStart);
-  const View* child1 = AddChild(Size(12, 10));
-  View* child2 = AddChild(Size(13, 11));
-  const View* child3 = AddChild(Size(17, 13));
+  const View* child1 = AddChild(kChild1Size);
+  View* child2 = AddChild(kChild2Size);
+  const View* child3 = AddChild(kChild3Size);
 
   layout_->SetViewExcluded(child2, true);
   child2->SetBounds(3, 3, 3, 3);
@@ -412,8 +427,8 @@
 TEST_F(FlexLayoutTest, LayoutSingleView_Horizontal) {
   layout_->SetOrientation(LayoutOrientation::kHorizontal);
   layout_->SetCollapseMargins(true);
-  layout_->SetInteriorMargin(Insets(5, 6, 7, 9));
-  View* child = AddChild(Size(12, 10));
+  layout_->SetInteriorMargin(kLayoutInsets);
+  View* child = AddChild(kChild1Size);
   host_->Layout();
   EXPECT_EQ(Rect(6, 5, 12, 10), child->bounds());
 }
@@ -421,8 +436,8 @@
 TEST_F(FlexLayoutTest, LayoutSingleView_Vertical) {
   layout_->SetOrientation(LayoutOrientation::kVertical);
   layout_->SetCollapseMargins(true);
-  layout_->SetInteriorMargin(Insets(5, 6, 7, 9));
-  View* child = AddChild(Size(12, 10));
+  layout_->SetInteriorMargin(kLayoutInsets);
+  View* child = AddChild(kChild1Size);
   host_->Layout();
   EXPECT_EQ(Rect(6, 5, 12, 10), child->bounds());
 }
@@ -430,11 +445,11 @@
 TEST_F(FlexLayoutTest, LayoutMultipleViews_Horizontal_CrossStart) {
   layout_->SetOrientation(LayoutOrientation::kHorizontal);
   layout_->SetCollapseMargins(true);
-  layout_->SetInteriorMargin(Insets(5, 6, 7, 9));
+  layout_->SetInteriorMargin(kLayoutInsets);
   layout_->SetCrossAxisAlignment(LayoutAlignment::kStart);
-  AddChild(Size(12, 10));
-  AddChild(Size(13, 11));
-  AddChild(Size(17, 13));
+  AddChild(kChild1Size);
+  AddChild(kChild2Size);
+  AddChild(kChild3Size);
   host_->Layout();
   std::vector<Rect> expected{Rect(6, 5, 12, 10), Rect(18, 5, 13, 11),
                              Rect(31, 5, 17, 13)};
@@ -445,11 +460,11 @@
 TEST_F(FlexLayoutTest, LayoutMultipleViews_Horizontal_CrossCenter) {
   layout_->SetOrientation(LayoutOrientation::kHorizontal);
   layout_->SetCollapseMargins(true);
-  layout_->SetInteriorMargin(Insets(5, 6, 7, 9));
+  layout_->SetInteriorMargin(kLayoutInsets);
   layout_->SetCrossAxisAlignment(LayoutAlignment::kCenter);
-  AddChild(Size(12, 10));
-  AddChild(Size(13, 11));
-  AddChild(Size(17, 13));
+  AddChild(kChild1Size);
+  AddChild(kChild2Size);
+  AddChild(kChild3Size);
   host_->Layout();
   std::vector<Rect> expected{Rect(6, 6, 12, 10), Rect(18, 6, 13, 11),
                              Rect(31, 5, 17, 13)};
@@ -460,11 +475,11 @@
 TEST_F(FlexLayoutTest, LayoutMultipleViews_Horizontal_CrossEnd) {
   layout_->SetOrientation(LayoutOrientation::kHorizontal);
   layout_->SetCollapseMargins(true);
-  layout_->SetInteriorMargin(Insets(5, 6, 7, 9));
+  layout_->SetInteriorMargin(kLayoutInsets);
   layout_->SetCrossAxisAlignment(LayoutAlignment::kEnd);
-  AddChild(Size(12, 10));
-  AddChild(Size(13, 11));
-  AddChild(Size(17, 13));
+  AddChild(kChild1Size);
+  AddChild(kChild2Size);
+  AddChild(kChild3Size);
   host_->Layout();
   std::vector<Rect> expected{Rect(6, 8, 12, 10), Rect(18, 7, 13, 11),
                              Rect(31, 5, 17, 13)};
@@ -475,12 +490,12 @@
 TEST_F(FlexLayoutTest, LayoutMultipleViews_Horizontal_CrossStretch) {
   layout_->SetOrientation(LayoutOrientation::kHorizontal);
   layout_->SetCollapseMargins(true);
-  layout_->SetInteriorMargin(Insets(5, 6, 7, 9));
+  layout_->SetInteriorMargin(kLayoutInsets);
   layout_->SetCrossAxisAlignment(LayoutAlignment::kStretch);
   host_->SetSize(Size(100, 25));
-  AddChild(Size(12, 10));
-  AddChild(Size(13, 11));
-  AddChild(Size(17, 13));
+  AddChild(kChild1Size);
+  AddChild(kChild2Size);
+  AddChild(kChild3Size);
   host_->Layout();
   std::vector<Rect> expected{Rect(6, 5, 12, 13), Rect(18, 5, 13, 13),
                              Rect(31, 5, 17, 13)};
@@ -491,11 +506,11 @@
 TEST_F(FlexLayoutTest, LayoutMultipleViews_Vertical_CrossStart) {
   layout_->SetOrientation(LayoutOrientation::kVertical);
   layout_->SetCollapseMargins(true);
-  layout_->SetInteriorMargin(Insets(5, 6, 7, 9));
+  layout_->SetInteriorMargin(kLayoutInsets);
   layout_->SetCrossAxisAlignment(LayoutAlignment::kStart);
-  AddChild(Size(12, 10));
-  AddChild(Size(13, 11));
-  AddChild(Size(17, 13));
+  AddChild(kChild1Size);
+  AddChild(kChild2Size);
+  AddChild(kChild3Size);
   host_->Layout();
   std::vector<Rect> expected{Rect(6, 5, 12, 10), Rect(6, 15, 13, 11),
                              Rect(6, 26, 17, 13)};
@@ -506,11 +521,11 @@
 TEST_F(FlexLayoutTest, LayoutMultipleViews_Vertical_CrossCenter) {
   layout_->SetOrientation(LayoutOrientation::kVertical);
   layout_->SetCollapseMargins(true);
-  layout_->SetInteriorMargin(Insets(5, 6, 7, 9));
+  layout_->SetInteriorMargin(kLayoutInsets);
   layout_->SetCrossAxisAlignment(LayoutAlignment::kCenter);
-  AddChild(Size(12, 10));
-  AddChild(Size(13, 11));
-  AddChild(Size(17, 13));
+  AddChild(kChild1Size);
+  AddChild(kChild2Size);
+  AddChild(kChild3Size);
   host_->Layout();
   std::vector<Rect> expected{Rect(8, 5, 12, 10), Rect(8, 15, 13, 11),
                              Rect(6, 26, 17, 13)};
@@ -521,11 +536,11 @@
 TEST_F(FlexLayoutTest, LayoutMultipleViews_Vertical_CrossEnd) {
   layout_->SetOrientation(LayoutOrientation::kVertical);
   layout_->SetCollapseMargins(true);
-  layout_->SetInteriorMargin(Insets(5, 6, 7, 9));
+  layout_->SetInteriorMargin(kLayoutInsets);
   layout_->SetCrossAxisAlignment(LayoutAlignment::kEnd);
-  AddChild(Size(12, 10));
-  AddChild(Size(13, 11));
-  AddChild(Size(17, 13));
+  AddChild(kChild1Size);
+  AddChild(kChild2Size);
+  AddChild(kChild3Size);
   host_->Layout();
   std::vector<Rect> expected{Rect(11, 5, 12, 10), Rect(10, 15, 13, 11),
                              Rect(6, 26, 17, 13)};
@@ -536,11 +551,11 @@
 TEST_F(FlexLayoutTest, LayoutMultipleViews_Vertical_CrossStretch) {
   layout_->SetOrientation(LayoutOrientation::kVertical);
   layout_->SetCollapseMargins(true);
-  layout_->SetInteriorMargin(Insets(5, 6, 7, 9));
+  layout_->SetInteriorMargin(kLayoutInsets);
   layout_->SetCrossAxisAlignment(LayoutAlignment::kStretch);
-  AddChild(Size(12, 10));
-  AddChild(Size(13, 11));
-  AddChild(Size(17, 13));
+  AddChild(kChild1Size);
+  AddChild(kChild2Size);
+  AddChild(kChild3Size);
   host_->SetSize(Size(32, 50));
   host_->Layout();
   std::vector<Rect> expected{Rect(6, 5, 17, 10), Rect(6, 15, 17, 11),
@@ -553,11 +568,11 @@
        LayoutMultipleViews_MarginAndSpacing_NoCollapse_Horizontal) {
   layout_->SetOrientation(LayoutOrientation::kHorizontal);
   layout_->SetCollapseMargins(false);
-  layout_->SetInteriorMargin(Insets(5, 6, 7, 9));
+  layout_->SetInteriorMargin(kLayoutInsets);
   layout_->SetCrossAxisAlignment(LayoutAlignment::kStart);
-  View* child1 = AddChild(Size(12, 10));
-  View* child2 = AddChild(Size(13, 11));
-  View* child3 = AddChild(Size(17, 13));
+  View* child1 = AddChild(kChild1Size);
+  View* child2 = AddChild(kChild2Size);
+  View* child3 = AddChild(kChild3Size);
   host_->Layout();
   std::vector<Rect> expected{Rect(6, 5, 12, 10), Rect(18, 5, 13, 11),
                              Rect(31, 5, 17, 13)};
@@ -594,12 +609,12 @@
        LayoutMultipleViews_MarginAndSpacing_NoCollapse_Vertical) {
   layout_->SetOrientation(LayoutOrientation::kVertical);
   layout_->SetCollapseMargins(false);
-  layout_->SetInteriorMargin(Insets(5, 6, 7, 9));
+  layout_->SetInteriorMargin(kLayoutInsets);
   layout_->SetCrossAxisAlignment(LayoutAlignment::kStart);
   layout_->SetDefaultChildMargins(gfx::Insets(3));
-  View* child1 = AddChild(Size(12, 10));
-  View* child2 = AddChild(Size(13, 11));
-  View* child3 = AddChild(Size(17, 13));
+  View* child1 = AddChild(kChild1Size);
+  View* child2 = AddChild(kChild2Size);
+  View* child3 = AddChild(kChild3Size);
   child1->SetProperty(views::kMarginsKey, new Insets(20, 21, 22, 23));
   child2->SetProperty(views::kMarginsKey, new Insets(1, 1, 1, 1));
   child3->SetProperty(views::kMarginsKey, new Insets(2, 2, 2, 2));
@@ -615,12 +630,12 @@
        LayoutMultipleViews_MarginAndSpacing_Collapse_Horizontal) {
   layout_->SetOrientation(LayoutOrientation::kHorizontal);
   layout_->SetCollapseMargins(true);
-  layout_->SetInteriorMargin(Insets(5, 6, 7, 9));
+  layout_->SetInteriorMargin(kLayoutInsets);
   layout_->SetCrossAxisAlignment(LayoutAlignment::kStart);
   layout_->SetDefaultChildMargins(gfx::Insets(3));
-  View* child1 = AddChild(Size(12, 10));
-  View* child2 = AddChild(Size(13, 11));
-  View* child3 = AddChild(Size(17, 13));
+  View* child1 = AddChild(kChild1Size);
+  View* child2 = AddChild(kChild2Size);
+  View* child3 = AddChild(kChild3Size);
   child1->SetProperty(views::kMarginsKey, new Insets(20, 21, 22, 23));
   child2->SetProperty(views::kMarginsKey, new Insets(1, 1, 1, 1));
   child3->SetProperty(views::kMarginsKey, new Insets(2, 2, 2, 2));
@@ -635,12 +650,12 @@
 TEST_F(FlexLayoutTest, LayoutMultipleViews_MarginAndSpacing_Collapse_Vertical) {
   layout_->SetOrientation(LayoutOrientation::kVertical);
   layout_->SetCollapseMargins(true);
-  layout_->SetInteriorMargin(Insets(5, 6, 7, 9));
+  layout_->SetInteriorMargin(kLayoutInsets);
   layout_->SetCrossAxisAlignment(LayoutAlignment::kStart);
   layout_->SetDefaultChildMargins(gfx::Insets(3));
-  View* child1 = AddChild(Size(12, 10));
-  View* child2 = AddChild(Size(13, 11));
-  View* child3 = AddChild(Size(17, 13));
+  View* child1 = AddChild(kChild1Size);
+  View* child2 = AddChild(kChild2Size);
+  View* child3 = AddChild(kChild3Size);
   child1->SetProperty(views::kMarginsKey, new Insets(20, 21, 22, 23));
   child2->SetProperty(views::kMarginsKey, new Insets(1, 1, 1, 1));
   child3->SetProperty(views::kMarginsKey, new Insets(2, 2, 2, 2));
@@ -655,11 +670,11 @@
 TEST_F(FlexLayoutTest, LayoutMultipleViews_InteriorPadding) {
   layout_->SetOrientation(LayoutOrientation::kHorizontal);
   layout_->SetCollapseMargins(true);
-  layout_->SetInteriorMargin(Insets(5, 6, 7, 9));
+  layout_->SetInteriorMargin(kLayoutInsets);
   layout_->SetCrossAxisAlignment(LayoutAlignment::kStart);
   layout_->SetDefaultChildMargins(gfx::Insets(10));
   View* child = AddChild(Size(13, 15));
-  AddChild(Size(17, 13));
+  AddChild(kChild3Size);
   child->SetProperty(views::kInternalPaddingKey, new Insets(1, 2, 4, 8));
   host_->InvalidateLayout();
   host_->Layout();
@@ -674,11 +689,11 @@
 TEST_F(FlexLayoutTest, LayoutMultipleViews_InteriorPadding_Margins) {
   layout_->SetOrientation(LayoutOrientation::kHorizontal);
   layout_->SetCollapseMargins(true);
-  layout_->SetInteriorMargin(Insets(5, 6, 7, 9));
+  layout_->SetInteriorMargin(kLayoutInsets);
   layout_->SetCrossAxisAlignment(LayoutAlignment::kStart);
   layout_->SetDefaultChildMargins(gfx::Insets(2));
   View* child = AddChild(Size(13, 15));
-  View* child2 = AddChild(Size(17, 13));
+  View* child2 = AddChild(kChild3Size);
   child->SetProperty(views::kInternalPaddingKey, new Insets(1, 2, 4, 8));
   child2->SetProperty(views::kMarginsKey, new Insets(5, 5, 5, 5));
   host_->InvalidateLayout();
@@ -694,11 +709,11 @@
 TEST_F(FlexLayoutTest, LayoutMultipleViews_InteriorPadding_Additive) {
   layout_->SetOrientation(LayoutOrientation::kHorizontal);
   layout_->SetCollapseMargins(true);
-  layout_->SetInteriorMargin(Insets(5, 6, 7, 9));
+  layout_->SetInteriorMargin(kLayoutInsets);
   layout_->SetCrossAxisAlignment(LayoutAlignment::kStart);
   layout_->SetDefaultChildMargins(gfx::Insets(20));
   View* child = AddChild(Size(13, 15));
-  View* child2 = AddChild(Size(17, 13));
+  View* child2 = AddChild(kChild3Size);
   child->SetProperty(views::kInternalPaddingKey, new Insets(1, 2, 4, 8));
   child2->SetProperty(views::kInternalPaddingKey, new Insets(5, 5, 5, 5));
   host_->InvalidateLayout();
@@ -716,13 +731,13 @@
 TEST_F(FlexLayoutTest, Layout_CrossStart) {
   layout_->SetOrientation(LayoutOrientation::kHorizontal);
   layout_->SetCollapseMargins(true);
-  layout_->SetInteriorMargin(Insets(5, 6, 7, 9));
+  layout_->SetInteriorMargin(kLayoutInsets);
   layout_->SetMainAxisAlignment(LayoutAlignment::kStart);
   layout_->SetCrossAxisAlignment(LayoutAlignment::kStart);
-  View* child1 = AddChild(Size(12, 10));
-  View* child2 = AddChild(Size(13, 11));
-  View* child3 = AddChild(Size(17, 13));
-  child1->SetProperty(views::kMarginsKey, new Insets(10, 11, 12, 13));
+  View* child1 = AddChild(kChild1Size);
+  View* child2 = AddChild(kChild2Size);
+  View* child3 = AddChild(kChild3Size);
+  child1->SetProperty(views::kMarginsKey, new Insets(kLargeInsets));
   child2->SetProperty(views::kMarginsKey, new Insets(1, 1, 1, 1));
   child3->SetProperty(views::kMarginsKey, new Insets(2, 2, 2, 2));
   host_->SetSize(Size(200, 200));
@@ -735,13 +750,13 @@
 TEST_F(FlexLayoutTest, Layout_CrossCenter) {
   layout_->SetOrientation(LayoutOrientation::kHorizontal);
   layout_->SetCollapseMargins(true);
-  layout_->SetInteriorMargin(Insets(5, 6, 7, 9));
+  layout_->SetInteriorMargin(kLayoutInsets);
   layout_->SetMainAxisAlignment(LayoutAlignment::kStart);
   layout_->SetCrossAxisAlignment(LayoutAlignment::kCenter);
-  View* child1 = AddChild(Size(12, 10));
-  View* child2 = AddChild(Size(13, 11));
-  View* child3 = AddChild(Size(17, 13));
-  child1->SetProperty(views::kMarginsKey, new Insets(10, 11, 12, 13));
+  View* child1 = AddChild(kChild1Size);
+  View* child2 = AddChild(kChild2Size);
+  View* child3 = AddChild(kChild3Size);
+  child1->SetProperty(views::kMarginsKey, new Insets(kLargeInsets));
   child2->SetProperty(views::kMarginsKey, new Insets(1, 1, 1, 1));
   child3->SetProperty(views::kMarginsKey, new Insets(2, 2, 2, 2));
   host_->SetSize(Size(200, 200));
@@ -754,13 +769,13 @@
 TEST_F(FlexLayoutTest, Layout_CrossEnd) {
   layout_->SetOrientation(LayoutOrientation::kHorizontal);
   layout_->SetCollapseMargins(true);
-  layout_->SetInteriorMargin(Insets(5, 6, 7, 9));
+  layout_->SetInteriorMargin(kLayoutInsets);
   layout_->SetMainAxisAlignment(LayoutAlignment::kStart);
   layout_->SetCrossAxisAlignment(LayoutAlignment::kEnd);
-  View* child1 = AddChild(Size(12, 10));
-  View* child2 = AddChild(Size(13, 11));
-  View* child3 = AddChild(Size(17, 13));
-  child1->SetProperty(views::kMarginsKey, new Insets(10, 11, 12, 13));
+  View* child1 = AddChild(kChild1Size);
+  View* child2 = AddChild(kChild2Size);
+  View* child3 = AddChild(kChild3Size);
+  child1->SetProperty(views::kMarginsKey, new Insets(kLargeInsets));
   child2->SetProperty(views::kMarginsKey, new Insets(1, 1, 1, 1));
   child3->SetProperty(views::kMarginsKey, new Insets(2, 2, 2, 2));
   host_->SetSize(Size(200, 200));
@@ -773,13 +788,13 @@
 TEST_F(FlexLayoutTest, Layout_CrossStretch) {
   layout_->SetOrientation(LayoutOrientation::kHorizontal);
   layout_->SetCollapseMargins(true);
-  layout_->SetInteriorMargin(Insets(5, 6, 7, 9));
+  layout_->SetInteriorMargin(kLayoutInsets);
   layout_->SetMainAxisAlignment(LayoutAlignment::kStart);
   layout_->SetCrossAxisAlignment(LayoutAlignment::kStretch);
-  View* child1 = AddChild(Size(12, 10));
-  View* child2 = AddChild(Size(13, 11));
-  View* child3 = AddChild(Size(17, 13));
-  child1->SetProperty(views::kMarginsKey, new Insets(10, 11, 12, 13));
+  View* child1 = AddChild(kChild1Size);
+  View* child2 = AddChild(kChild2Size);
+  View* child3 = AddChild(kChild3Size);
+  child1->SetProperty(views::kMarginsKey, new Insets(kLargeInsets));
   child2->SetProperty(views::kMarginsKey, new Insets(1, 1, 1, 1));
   child3->SetProperty(views::kMarginsKey, new Insets(2, 2, 2, 2));
   host_->SetSize(Size(200, 200));
@@ -795,13 +810,13 @@
 TEST_F(FlexLayoutTest, Layout_AlignStart) {
   layout_->SetOrientation(LayoutOrientation::kHorizontal);
   layout_->SetCollapseMargins(true);
-  layout_->SetInteriorMargin(Insets(5, 6, 7, 9));
+  layout_->SetInteriorMargin(kLayoutInsets);
   layout_->SetMainAxisAlignment(LayoutAlignment::kStart);
   layout_->SetCrossAxisAlignment(LayoutAlignment::kStart);
   layout_->SetDefaultChildMargins(gfx::Insets(3));
-  View* child1 = AddChild(Size(12, 10));
-  View* child2 = AddChild(Size(13, 11));
-  View* child3 = AddChild(Size(17, 13));
+  View* child1 = AddChild(kChild1Size);
+  View* child2 = AddChild(kChild2Size);
+  View* child3 = AddChild(kChild3Size);
   child1->SetProperty(views::kMarginsKey, new Insets(20, 21, 22, 23));
   child2->SetProperty(views::kMarginsKey, new Insets(1, 1, 1, 1));
   child3->SetProperty(views::kMarginsKey, new Insets(2, 2, 2, 2));
@@ -815,13 +830,13 @@
 TEST_F(FlexLayoutTest, Layout_AlignCenter) {
   layout_->SetOrientation(LayoutOrientation::kHorizontal);
   layout_->SetCollapseMargins(true);
-  layout_->SetInteriorMargin(Insets(5, 6, 7, 9));
+  layout_->SetInteriorMargin(kLayoutInsets);
   layout_->SetMainAxisAlignment(LayoutAlignment::kCenter);
   layout_->SetCrossAxisAlignment(LayoutAlignment::kStart);
   layout_->SetDefaultChildMargins(gfx::Insets(3));
-  View* child1 = AddChild(Size(12, 10));
-  View* child2 = AddChild(Size(13, 11));
-  View* child3 = AddChild(Size(17, 13));
+  View* child1 = AddChild(kChild1Size);
+  View* child2 = AddChild(kChild2Size);
+  View* child3 = AddChild(kChild3Size);
   child1->SetProperty(views::kMarginsKey, new Insets(20, 21, 22, 23));
   child2->SetProperty(views::kMarginsKey, new Insets(1, 1, 1, 1));
   child3->SetProperty(views::kMarginsKey, new Insets(2, 2, 2, 2));
@@ -835,13 +850,13 @@
 TEST_F(FlexLayoutTest, Layout_AlignEnd) {
   layout_->SetOrientation(LayoutOrientation::kHorizontal);
   layout_->SetCollapseMargins(true);
-  layout_->SetInteriorMargin(Insets(5, 6, 7, 9));
+  layout_->SetInteriorMargin(kLayoutInsets);
   layout_->SetMainAxisAlignment(LayoutAlignment::kEnd);
   layout_->SetCrossAxisAlignment(LayoutAlignment::kStart);
   layout_->SetDefaultChildMargins(gfx::Insets(3));
-  View* child1 = AddChild(Size(12, 10));
-  View* child2 = AddChild(Size(13, 11));
-  View* child3 = AddChild(Size(17, 13));
+  View* child1 = AddChild(kChild1Size);
+  View* child2 = AddChild(kChild2Size);
+  View* child3 = AddChild(kChild3Size);
   child1->SetProperty(views::kMarginsKey, new Insets(20, 21, 22, 23));
   child2->SetProperty(views::kMarginsKey, new Insets(1, 1, 1, 1));
   child3->SetProperty(views::kMarginsKey, new Insets(2, 2, 2, 2));
@@ -883,14 +898,14 @@
 TEST_F(FlexLayoutTest, Layout_IgnoreMinimumSize_DropViews) {
   layout_->SetOrientation(LayoutOrientation::kHorizontal);
   layout_->SetCollapseMargins(true);
-  layout_->SetInteriorMargin(Insets(5, 6, 7, 9));
+  layout_->SetInteriorMargin(kLayoutInsets);
   layout_->SetMainAxisAlignment(LayoutAlignment::kStart);
   layout_->SetCrossAxisAlignment(LayoutAlignment::kStart);
   layout_->SetDefaultChildMargins(gfx::Insets(3));
-  View* child1 = AddChild(Size(12, 10));
-  View* child2 = AddChild(Size(13, 11));
-  View* child3 = AddChild(Size(17, 13));
-  child1->SetProperty(views::kMarginsKey, new Insets(10, 11, 12, 13));
+  View* child1 = AddChild(kChild1Size);
+  View* child2 = AddChild(kChild2Size);
+  View* child3 = AddChild(kChild3Size);
+  child1->SetProperty(views::kMarginsKey, new Insets(kLargeInsets));
   child2->SetProperty(views::kMarginsKey, new Insets(1, 1, 1, 1));
   child3->SetProperty(views::kMarginsKey, new Insets(2, 2, 2, 2));
   host_->SetSize(Size(55, 50));
@@ -935,14 +950,14 @@
 TEST_F(FlexLayoutTest, Layout_IgnoreMinimumSize_DropInOrder) {
   layout_->SetOrientation(LayoutOrientation::kHorizontal);
   layout_->SetCollapseMargins(true);
-  layout_->SetInteriorMargin(Insets(5, 6, 7, 9));
+  layout_->SetInteriorMargin(kLayoutInsets);
   layout_->SetMainAxisAlignment(LayoutAlignment::kStart);
   layout_->SetCrossAxisAlignment(LayoutAlignment::kStart);
   layout_->SetDefaultChildMargins(gfx::Insets(3));
-  View* child1 = AddChild(Size(12, 10));
-  View* child2 = AddChild(Size(13, 11));
-  View* child3 = AddChild(Size(17, 13));
-  child1->SetProperty(views::kMarginsKey, new Insets(10, 11, 12, 13));
+  View* child1 = AddChild(kChild1Size);
+  View* child2 = AddChild(kChild2Size);
+  View* child3 = AddChild(kChild3Size);
+  child1->SetProperty(views::kMarginsKey, new Insets(kLargeInsets));
   child2->SetProperty(views::kMarginsKey, new Insets(1, 1, 1, 1));
   child3->SetProperty(views::kMarginsKey, new Insets(2, 2, 2, 2));
   // Set flex separately; we'll test default flex later.
@@ -987,14 +1002,14 @@
   // Perform the same test as above but with default flex set instead.
   layout_->SetOrientation(LayoutOrientation::kHorizontal);
   layout_->SetCollapseMargins(true);
-  layout_->SetInteriorMargin(Insets(5, 6, 7, 9));
+  layout_->SetInteriorMargin(kLayoutInsets);
   layout_->SetMainAxisAlignment(LayoutAlignment::kStart);
   layout_->SetCrossAxisAlignment(LayoutAlignment::kStart);
   layout_->SetDefaultChildMargins(gfx::Insets(3));
-  View* child1 = AddChild(Size(12, 10));
-  View* child2 = AddChild(Size(13, 11));
-  View* child3 = AddChild(Size(17, 13));
-  child1->SetProperty(views::kMarginsKey, new Insets(10, 11, 12, 13));
+  View* child1 = AddChild(kChild1Size);
+  View* child2 = AddChild(kChild2Size);
+  View* child3 = AddChild(kChild3Size);
+  child1->SetProperty(views::kMarginsKey, new Insets(kLargeInsets));
   child2->SetProperty(views::kMarginsKey, new Insets(1, 1, 1, 1));
   child3->SetProperty(views::kMarginsKey, new Insets(2, 2, 2, 2));
   layout_->SetDefaultFlex(kDropOut);
@@ -1035,14 +1050,14 @@
 TEST_F(FlexLayoutTest, Layout_IgnoreMinimumSize_DropByPriority) {
   layout_->SetOrientation(LayoutOrientation::kHorizontal);
   layout_->SetCollapseMargins(true);
-  layout_->SetInteriorMargin(Insets(5, 6, 7, 9));
+  layout_->SetInteriorMargin(kLayoutInsets);
   layout_->SetMainAxisAlignment(LayoutAlignment::kStart);
   layout_->SetCrossAxisAlignment(LayoutAlignment::kStart);
   layout_->SetDefaultChildMargins(gfx::Insets(3));
-  View* child1 = AddChild(Size(12, 10));
-  View* child2 = AddChild(Size(13, 11));
-  View* child3 = AddChild(Size(17, 13));
-  child1->SetProperty(views::kMarginsKey, new Insets(10, 11, 12, 13));
+  View* child1 = AddChild(kChild1Size);
+  View* child2 = AddChild(kChild2Size);
+  View* child3 = AddChild(kChild3Size);
+  child1->SetProperty(views::kMarginsKey, new Insets(kLargeInsets));
   child2->SetProperty(views::kMarginsKey, new Insets(1, 1, 1, 1));
   child3->SetProperty(views::kMarginsKey, new Insets(2, 2, 2, 2));
   layout_->SetDefaultFlex(kDropOut);
@@ -1216,7 +1231,7 @@
 
   host_->SetSize(Size(45, 20));
   host_->Layout();
-  EXPECT_EQ(Size(12, 10), child1->size());
+  EXPECT_EQ(kChild1Size, child1->size());
   EXPECT_EQ(Size(18, 10), child2->size());
 }
 
@@ -1360,9 +1375,12 @@
   host_->Layout();
   EXPECT_EQ(Size(15, 6), child->size());
 
+  // This is too short to display the view, however it has horizontal size, so
+  // the view does not drop out.
   host_->SetSize(Size(25, 10));
   host_->Layout();
-  EXPECT_FALSE(child->visible());
+  EXPECT_TRUE(child->visible());
+  EXPECT_EQ(Size(15, 0), child->size());
 
   host_->SetSize(Size(15, 15));
   host_->Layout();
@@ -1401,9 +1419,12 @@
   host_->Layout();
   EXPECT_EQ(Size(15, 6), child->size());
 
+  // This is too short to display the view, however it has horizontal size, so
+  // the view does not drop out.
   host_->SetSize(Size(25, 10));
   host_->Layout();
-  EXPECT_FALSE(child->visible());
+  EXPECT_TRUE(child->visible());
+  EXPECT_EQ(Size(15, 0), child->size());
 
   host_->SetSize(Size(15, 15));
   host_->Layout();
@@ -1566,6 +1587,117 @@
   EXPECT_EQ(0, child2->GetSetVisibleCount());
 }
 
+// Cross-axis Fit Tests --------------------------------------------------------
+
+// Tests for cross-axis alignment that checks three different conditions:
+//  - child1 fits entirely in the space provided, with margins
+//  - child2 fits in the space, but its margins don't
+//  - child3 does not fit in the space provided
+class FlexLayoutCrossAxisFitTest : public FlexLayoutTest {
+ public:
+  void SetUp() override {
+    FlexLayoutTest::SetUp();
+    DCHECK(child_views_.empty());
+
+    for (int i = 0; i < kNumChildren; ++i) {
+      View* const child = AddChild(kChildSizes[i]);
+      child->SetProperty(kMarginsKey, new gfx::Insets(kChildMargins[i]));
+      child_views_.push_back(child);
+    }
+
+    layout_->SetOrientation(LayoutOrientation::kHorizontal);
+    layout_->SetCollapseMargins(true);
+    layout_->SetMainAxisAlignment(LayoutAlignment::kStart);
+    host_->SetSize(kHostSize);
+  }
+
+  void TearDown() override { child_views_.clear(); }
+
+ protected:
+  static constexpr int kNumChildren = 3;
+  static const gfx::Size kHostSize;
+  static const gfx::Size kChildSizes[kNumChildren];
+  static const gfx::Insets kChildMargins[kNumChildren];
+
+  std::vector<View*> child_views_;
+};
+
+const gfx::Size FlexLayoutCrossAxisFitTest::kHostSize{200, 20};
+
+const gfx::Size FlexLayoutCrossAxisFitTest::kChildSizes[]{{10, 10},
+                                                          {10, 10},
+                                                          {10, 30}};
+
+const gfx::Insets FlexLayoutCrossAxisFitTest::kChildMargins[]{{6, 0, 2, 0},
+                                                              {10, 0, 5, 0},
+                                                              {6, 0, 2, 0}};
+
+TEST_F(FlexLayoutCrossAxisFitTest, Layout_CrossStretch) {
+  layout_->SetCrossAxisAlignment(LayoutAlignment::kStretch);
+  host_->Layout();
+
+  // Expect child views to respect their leading margin and to occupy all
+  // available space (other than margins), with a minimum size of zero.
+  for (int i = 0; i < kNumChildren; ++i) {
+    EXPECT_EQ(kChildMargins[i].top(), child_views_[i]->origin().y());
+    const int expected_height =
+        std::max(0, kHostSize.height() - kChildMargins[i].height());
+    EXPECT_EQ(expected_height, child_views_[i]->size().height());
+  }
+}
+
+TEST_F(FlexLayoutCrossAxisFitTest, Layout_CrossStart) {
+  layout_->SetCrossAxisAlignment(LayoutAlignment::kStart);
+  host_->Layout();
+
+  // These should all justify to the leading edge and keep their original size.
+  for (int i = 0; i < kNumChildren; ++i) {
+    EXPECT_EQ(kChildMargins[i].top(), child_views_[i]->origin().y());
+    EXPECT_EQ(kChildSizes[i].height(), child_views_[i]->size().height());
+  }
+}
+
+TEST_F(FlexLayoutCrossAxisFitTest, Layout_CrossCenter) {
+  layout_->SetCrossAxisAlignment(LayoutAlignment::kCenter);
+  host_->Layout();
+
+  // First child view fits entirely in the host view with margins (18 DIPs).
+  // The entire height (including margins) will be centered vertically.
+  int remain = kHostSize.height() -
+               (kChildSizes[0].height() + kChildMargins[0].height());
+  int expected = remain / 2 + kChildMargins[0].top();
+  EXPECT_EQ(expected, child_views_[0]->origin().y());
+
+  // Second child view is smaller than the host view, but margins don't fit.
+  // The margins will be scaled down.
+  remain = kHostSize.height() - kChildSizes[0].height();
+  expected = std::roundf(kChildMargins[1].top() * float{remain} /
+                         float{kChildMargins[1].height()});
+  EXPECT_EQ(expected, child_views_[1]->origin().y());
+
+  // Third child view does not fit, so is centered.
+  remain = kHostSize.height() - kChildSizes[2].height();
+  expected = std::ceilf(remain * 0.5f);
+  EXPECT_EQ(expected, child_views_[2]->origin().y());
+
+  // Expect child views to retain their preferred sizes.
+  for (int i = 0; i < kNumChildren; ++i) {
+    EXPECT_EQ(kChildSizes[i].height(), child_views_[i]->size().height());
+  }
+}
+
+TEST_F(FlexLayoutCrossAxisFitTest, Layout_CrossEnd) {
+  layout_->SetCrossAxisAlignment(LayoutAlignment::kEnd);
+  host_->Layout();
+
+  // These should all justify to the trailing edge and keep their original size.
+  for (int i = 0; i < kNumChildren; ++i) {
+    EXPECT_EQ(kHostSize.height() - kChildMargins[i].bottom(),
+              child_views_[i]->bounds().bottom());
+    EXPECT_EQ(kChildSizes[i].height(), child_views_[i]->size().height());
+  }
+}
+
 // Nested Layout Tests ---------------------------------------------------------
 
 class NestedFlexLayoutTest : public FlexLayoutTest {