1 // Copyright 2019 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "ui/views/layout/layout_manager_base.h"
6 
7 #include <algorithm>
8 
9 #include "testing/gtest/include/gtest/gtest.h"
10 #include "ui/views/test/test_layout_manager.h"
11 #include "ui/views/test/test_views.h"
12 #include "ui/views/view.h"
13 
14 namespace views {
15 
16 namespace {
17 
18 constexpr int kChildViewPadding = 5;
19 constexpr gfx::Size kMinimumSize(40, 50);
20 constexpr gfx::Size kPreferredSize(100, 90);
21 constexpr gfx::Size kSquarishSize(10, 11);
22 constexpr gfx::Size kLongSize(20, 8);
23 constexpr gfx::Size kTallSize(4, 22);
24 constexpr gfx::Size kLargeSize(30, 28);
25 
26 // Dummy class that minimally implements LayoutManagerBase for basic
27 // functionality testing.
28 class TestLayoutManagerBase : public LayoutManagerBase {
29  public:
GetIncludedChildViews() const30   std::vector<const View*> GetIncludedChildViews() const {
31     std::vector<const View*> included;
32     std::copy_if(host_view()->children().begin(), host_view()->children().end(),
33                  std::back_inserter(included), [=](const View* child) {
34                    return IsChildIncludedInLayout(child);
35                  });
36     return included;
37   }
38 
OverrideProposedLayout(const ProposedLayout & forced_layout)39   void OverrideProposedLayout(const ProposedLayout& forced_layout) {
40     forced_layout_ = forced_layout;
41     InvalidateHost(true);
42   }
43 
44   // LayoutManagerBase:
CalculateProposedLayout(const SizeBounds & size_bounds) const45   ProposedLayout CalculateProposedLayout(
46       const SizeBounds& size_bounds) const override {
47     if (forced_layout_)
48       return *forced_layout_;
49 
50     ProposedLayout layout;
51     layout.host_size.set_width(
52         std::max(kMinimumSize.width(),
53                  size_bounds.width().value_or(kPreferredSize.width())));
54     layout.host_size.set_height(
55         std::max(kMinimumSize.height(),
56                  size_bounds.height().value_or(kPreferredSize.height())));
57     return layout;
58   }
59 
LayoutImpl()60   void LayoutImpl() override {
61     ++layout_count_;
62     LayoutManagerBase::LayoutImpl();
63   }
64 
layout_count() const65   size_t layout_count() const { return layout_count_; }
66 
67  private:
68   // If specified, will always return this layout.
69   base::Optional<ProposedLayout> forced_layout_;
70 
71   size_t layout_count_ = 0;
72 };
73 
74 // This layout layout lays out included child views in the upper-left of the
75 // host view with kChildViewPadding around them. Views that will not fit are
76 // made invisible. Child views are expected to overlap as they all have the
77 // same top-left corner.
78 class MockLayoutManagerBase : public LayoutManagerBase {
79  public:
80   using LayoutManagerBase::AddOwnedLayout;
81   using LayoutManagerBase::InvalidateHost;
82 
num_invalidations() const83   int num_invalidations() const { return num_invalidations_; }
num_layouts_generated() const84   int num_layouts_generated() const { return num_layouts_generated_; }
85 
86   // LayoutManagerBase:
CalculateProposedLayout(const SizeBounds & size_bounds) const87   ProposedLayout CalculateProposedLayout(
88       const SizeBounds& size_bounds) const override {
89     ProposedLayout layout;
90     layout.host_size = {kChildViewPadding, kChildViewPadding};
91     for (auto* it : host_view()->children()) {
92       if (!IsChildIncludedInLayout(it))
93         continue;
94       const gfx::Size preferred_size = it->GetPreferredSize();
95       bool visible = false;
96       gfx::Rect bounds;
97       const int required_width = preferred_size.width() + 2 * kChildViewPadding;
98       const int required_height =
99           preferred_size.height() + 2 * kChildViewPadding;
100       if ((!size_bounds.width() || required_width <= *size_bounds.width()) &&
101           (!size_bounds.height() || required_height <= *size_bounds.height())) {
102         visible = true;
103         bounds = gfx::Rect(kChildViewPadding, kChildViewPadding,
104                            preferred_size.width(), preferred_size.height());
105         layout.host_size.set_width(std::max(
106             layout.host_size.width(), bounds.right() + kChildViewPadding));
107         layout.host_size.set_height(std::max(
108             layout.host_size.height(), bounds.bottom() + kChildViewPadding));
109       }
110       layout.child_layouts.push_back({it, visible, bounds});
111     }
112     ++num_layouts_generated_;
113     return layout;
114   }
115 
OnLayoutChanged()116   void OnLayoutChanged() override {
117     LayoutManagerBase::OnLayoutChanged();
118     ++num_invalidations_;
119   }
120 
121   using LayoutManagerBase::ApplyLayout;
122 
123  private:
124   mutable int num_layouts_generated_ = 0;
125   mutable int num_invalidations_ = 0;
126 };
127 
ExpectSameViews(const std::vector<const View * > & expected,const std::vector<const View * > & actual)128 void ExpectSameViews(const std::vector<const View*>& expected,
129                      const std::vector<const View*>& actual) {
130   EXPECT_EQ(expected.size(), actual.size());
131   for (size_t i = 0; i < expected.size(); ++i) {
132     EXPECT_EQ(expected[i], actual[i]);
133   }
134 }
135 
136 }  // namespace
137 
TEST(LayoutManagerBaseTest,GetMinimumSize)138 TEST(LayoutManagerBaseTest, GetMinimumSize) {
139   TestLayoutManagerBase layout;
140   EXPECT_EQ(kMinimumSize, layout.GetMinimumSize(nullptr));
141 }
142 
TEST(LayoutManagerBaseTest,GetPreferredSize)143 TEST(LayoutManagerBaseTest, GetPreferredSize) {
144   TestLayoutManagerBase layout;
145   EXPECT_EQ(kPreferredSize, layout.GetPreferredSize(nullptr));
146 }
147 
TEST(LayoutManagerBaseTest,GetPreferredHeightForWidth)148 TEST(LayoutManagerBaseTest, GetPreferredHeightForWidth) {
149   constexpr int kWidth = 45;
150   TestLayoutManagerBase layout;
151   EXPECT_EQ(kPreferredSize.height(),
152             layout.GetPreferredHeightForWidth(nullptr, kWidth));
153 }
154 
TEST(LayoutManagerBaseTest,Installed)155 TEST(LayoutManagerBaseTest, Installed) {
156   auto layout_ptr = std::make_unique<TestLayoutManagerBase>();
157   LayoutManagerBase* layout = layout_ptr.get();
158   EXPECT_EQ(nullptr, layout->host_view());
159 
160   View view;
161   view.SetLayoutManager(std::move(layout_ptr));
162   EXPECT_EQ(&view, layout->host_view());
163 }
164 
TEST(LayoutManagerBaseTest,SetChildIncludedInLayout)165 TEST(LayoutManagerBaseTest, SetChildIncludedInLayout) {
166   View view;
167   View* const child1 = view.AddChildView(std::make_unique<View>());
168   View* const child2 = view.AddChildView(std::make_unique<View>());
169   View* const child3 = view.AddChildView(std::make_unique<View>());
170 
171   auto layout_ptr = std::make_unique<TestLayoutManagerBase>();
172   TestLayoutManagerBase* layout = layout_ptr.get();
173   view.SetLayoutManager(std::move(layout_ptr));
174 
175   // All views should be present.
176   ExpectSameViews({child1, child2, child3}, layout->GetIncludedChildViews());
177 
178   // Remove one.
179   layout->SetChildViewIgnoredByLayout(child2, true);
180   ExpectSameViews({child1, child3}, layout->GetIncludedChildViews());
181 
182   // Remove another.
183   layout->SetChildViewIgnoredByLayout(child1, true);
184   ExpectSameViews({child3}, layout->GetIncludedChildViews());
185 
186   // Removing it again should have no effect.
187   layout->SetChildViewIgnoredByLayout(child1, true);
188   ExpectSameViews({child3}, layout->GetIncludedChildViews());
189 
190   // Add one back.
191   layout->SetChildViewIgnoredByLayout(child1, false);
192   ExpectSameViews({child1, child3}, layout->GetIncludedChildViews());
193 
194   // Adding it back again should have no effect.
195   layout->SetChildViewIgnoredByLayout(child1, false);
196   ExpectSameViews({child1, child3}, layout->GetIncludedChildViews());
197 
198   // Add the other view back.
199   layout->SetChildViewIgnoredByLayout(child2, false);
200   ExpectSameViews({child1, child2, child3}, layout->GetIncludedChildViews());
201 }
202 
TEST(LayoutManagerBaseTest,InvalidateHost_NotInstalled)203 TEST(LayoutManagerBaseTest, InvalidateHost_NotInstalled) {
204   MockLayoutManagerBase root_layout;
205   MockLayoutManagerBase* const child1 =
206       root_layout.AddOwnedLayout(std::make_unique<MockLayoutManagerBase>());
207   MockLayoutManagerBase* const child2 =
208       root_layout.AddOwnedLayout(std::make_unique<MockLayoutManagerBase>());
209   MockLayoutManagerBase* const grandchild =
210       child1->AddOwnedLayout(std::make_unique<MockLayoutManagerBase>());
211 
212   root_layout.InvalidateHost(false);
213   EXPECT_EQ(0, root_layout.num_invalidations());
214   EXPECT_EQ(0, child1->num_invalidations());
215   EXPECT_EQ(0, child2->num_invalidations());
216   EXPECT_EQ(0, grandchild->num_invalidations());
217 
218   child1->InvalidateHost(false);
219   EXPECT_EQ(0, root_layout.num_invalidations());
220   EXPECT_EQ(0, child1->num_invalidations());
221   EXPECT_EQ(0, child2->num_invalidations());
222   EXPECT_EQ(0, grandchild->num_invalidations());
223 
224   child2->InvalidateHost(false);
225   EXPECT_EQ(0, root_layout.num_invalidations());
226   EXPECT_EQ(0, child1->num_invalidations());
227   EXPECT_EQ(0, child2->num_invalidations());
228   EXPECT_EQ(0, grandchild->num_invalidations());
229 
230   grandchild->InvalidateHost(false);
231   EXPECT_EQ(0, root_layout.num_invalidations());
232   EXPECT_EQ(0, child1->num_invalidations());
233   EXPECT_EQ(0, child2->num_invalidations());
234   EXPECT_EQ(0, grandchild->num_invalidations());
235 
236   root_layout.InvalidateHost(true);
237   EXPECT_EQ(1, root_layout.num_invalidations());
238   EXPECT_EQ(1, child1->num_invalidations());
239   EXPECT_EQ(1, child2->num_invalidations());
240   EXPECT_EQ(1, grandchild->num_invalidations());
241 
242   child1->InvalidateHost(true);
243   EXPECT_EQ(2, root_layout.num_invalidations());
244   EXPECT_EQ(2, child1->num_invalidations());
245   EXPECT_EQ(2, child2->num_invalidations());
246   EXPECT_EQ(2, grandchild->num_invalidations());
247 
248   child2->InvalidateHost(true);
249   EXPECT_EQ(3, root_layout.num_invalidations());
250   EXPECT_EQ(3, child1->num_invalidations());
251   EXPECT_EQ(3, child2->num_invalidations());
252   EXPECT_EQ(3, grandchild->num_invalidations());
253 
254   grandchild->InvalidateHost(true);
255   EXPECT_EQ(4, root_layout.num_invalidations());
256   EXPECT_EQ(4, child1->num_invalidations());
257   EXPECT_EQ(4, child2->num_invalidations());
258   EXPECT_EQ(4, grandchild->num_invalidations());
259 }
260 
TEST(LayoutManagerBaseTest,InvalidateHost_Installed)261 TEST(LayoutManagerBaseTest, InvalidateHost_Installed) {
262   View view;
263   MockLayoutManagerBase* const root_layout =
264       view.SetLayoutManager(std::make_unique<MockLayoutManagerBase>());
265   MockLayoutManagerBase* const child1 =
266       root_layout->AddOwnedLayout(std::make_unique<MockLayoutManagerBase>());
267   MockLayoutManagerBase* const child2 =
268       root_layout->AddOwnedLayout(std::make_unique<MockLayoutManagerBase>());
269   MockLayoutManagerBase* const grandchild =
270       child1->AddOwnedLayout(std::make_unique<MockLayoutManagerBase>());
271 
272   root_layout->InvalidateHost(false);
273   EXPECT_EQ(0, root_layout->num_invalidations());
274   EXPECT_EQ(0, child1->num_invalidations());
275   EXPECT_EQ(0, child2->num_invalidations());
276   EXPECT_EQ(0, grandchild->num_invalidations());
277 
278   child1->InvalidateHost(false);
279   EXPECT_EQ(0, root_layout->num_invalidations());
280   EXPECT_EQ(0, child1->num_invalidations());
281   EXPECT_EQ(0, child2->num_invalidations());
282   EXPECT_EQ(0, grandchild->num_invalidations());
283 
284   child2->InvalidateHost(false);
285   EXPECT_EQ(0, root_layout->num_invalidations());
286   EXPECT_EQ(0, child1->num_invalidations());
287   EXPECT_EQ(0, child2->num_invalidations());
288   EXPECT_EQ(0, grandchild->num_invalidations());
289 
290   grandchild->InvalidateHost(false);
291   EXPECT_EQ(0, root_layout->num_invalidations());
292   EXPECT_EQ(0, child1->num_invalidations());
293   EXPECT_EQ(0, child2->num_invalidations());
294   EXPECT_EQ(0, grandchild->num_invalidations());
295 
296   root_layout->InvalidateHost(true);
297   EXPECT_EQ(1, root_layout->num_invalidations());
298   EXPECT_EQ(1, child1->num_invalidations());
299   EXPECT_EQ(1, child2->num_invalidations());
300   EXPECT_EQ(1, grandchild->num_invalidations());
301 
302   child1->InvalidateHost(true);
303   EXPECT_EQ(2, root_layout->num_invalidations());
304   EXPECT_EQ(2, child1->num_invalidations());
305   EXPECT_EQ(2, child2->num_invalidations());
306   EXPECT_EQ(2, grandchild->num_invalidations());
307 
308   child2->InvalidateHost(true);
309   EXPECT_EQ(3, root_layout->num_invalidations());
310   EXPECT_EQ(3, child1->num_invalidations());
311   EXPECT_EQ(3, child2->num_invalidations());
312   EXPECT_EQ(3, grandchild->num_invalidations());
313 
314   grandchild->InvalidateHost(true);
315   EXPECT_EQ(4, root_layout->num_invalidations());
316   EXPECT_EQ(4, child1->num_invalidations());
317   EXPECT_EQ(4, child2->num_invalidations());
318   EXPECT_EQ(4, grandchild->num_invalidations());
319 }
320 
321 // Test LayoutManager functionality of LayoutManagerBase:
322 
323 namespace {
324 
325 // Base for tests that evaluate the LayoutManager functionality of
326 // LayoutManagerBase (rather than the LayoutManagerBase-specific behavior).
327 class LayoutManagerBaseManagerTest : public testing::Test {
328  public:
SetUp()329   void SetUp() override {
330     host_view_ = std::make_unique<View>();
331     layout_manager_ =
332         host_view_->SetLayoutManager(std::make_unique<MockLayoutManagerBase>());
333   }
334 
AddChildView(gfx::Size preferred_size)335   View* AddChildView(gfx::Size preferred_size) {
336     auto child = std::make_unique<StaticSizedView>(preferred_size);
337     return host_view_->AddChildView(std::move(child));
338   }
339 
host_view()340   View* host_view() { return host_view_.get(); }
layout_manager()341   MockLayoutManagerBase* layout_manager() { return layout_manager_; }
child(int index)342   View* child(int index) { return host_view_->children().at(index); }
343 
344  private:
345   std::unique_ptr<View> host_view_;
346   MockLayoutManagerBase* layout_manager_;
347 };
348 
349 }  // namespace
350 
TEST_F(LayoutManagerBaseManagerTest,ApplyLayout)351 TEST_F(LayoutManagerBaseManagerTest, ApplyLayout) {
352   AddChildView(gfx::Size());
353   AddChildView(gfx::Size());
354   AddChildView(gfx::Size());
355 
356   // We don't want to set the size of the host view because it will trigger a
357   // superfluous layout, so we'll just keep the old size and make sure it
358   // doesn't change.
359   const gfx::Size old_size = host_view()->size();
360 
361   ProposedLayout layout;
362   // This should be ignored.
363   layout.host_size = {123, 456};
364 
365   // Set the child visibility and bounds.
366   constexpr gfx::Rect kChild1Bounds(3, 4, 10, 15);
367   constexpr gfx::Rect kChild3Bounds(20, 21, 12, 14);
368   layout.child_layouts.push_back({child(0), true, kChild1Bounds});
369   layout.child_layouts.push_back({child(1), false});
370   layout.child_layouts.push_back({child(2), true, kChild3Bounds});
371 
372   layout_manager()->ApplyLayout(layout);
373 
374   EXPECT_TRUE(child(0)->GetVisible());
375   EXPECT_EQ(kChild1Bounds, child(0)->bounds());
376   EXPECT_FALSE(child(1)->GetVisible());
377   EXPECT_TRUE(child(2)->GetVisible());
378   EXPECT_EQ(kChild3Bounds, child(2)->bounds());
379   EXPECT_EQ(old_size, host_view()->size());
380 }
381 
TEST_F(LayoutManagerBaseManagerTest,ApplyLayout_SkipsOmittedViews)382 TEST_F(LayoutManagerBaseManagerTest, ApplyLayout_SkipsOmittedViews) {
383   AddChildView(gfx::Size());
384   AddChildView(gfx::Size());
385   AddChildView(gfx::Size());
386 
387   ProposedLayout layout;
388   // Set the child visibility and bounds.
389   constexpr gfx::Rect kChild1Bounds(3, 4, 10, 15);
390   constexpr gfx::Rect kChild2Bounds(1, 2, 3, 4);
391   layout.child_layouts.push_back({child(0), true, kChild1Bounds});
392   layout.child_layouts.push_back({child(2), false});
393 
394   // We'll set the second child separately.
395   child(1)->SetVisible(true);
396   child(1)->SetBoundsRect(kChild2Bounds);
397 
398   layout_manager()->ApplyLayout(layout);
399 
400   EXPECT_TRUE(child(0)->GetVisible());
401   EXPECT_EQ(kChild1Bounds, child(0)->bounds());
402   EXPECT_TRUE(child(1)->GetVisible());
403   EXPECT_EQ(kChild2Bounds, child(1)->bounds());
404   EXPECT_FALSE(child(2)->GetVisible());
405 }
406 
TEST_F(LayoutManagerBaseManagerTest,Install)407 TEST_F(LayoutManagerBaseManagerTest, Install) {
408   EXPECT_EQ(host_view(), layout_manager()->host_view());
409 }
410 
TEST_F(LayoutManagerBaseManagerTest,GetMinimumSize)411 TEST_F(LayoutManagerBaseManagerTest, GetMinimumSize) {
412   AddChildView(kSquarishSize);
413   AddChildView(kLongSize);
414   AddChildView(kTallSize);
415   EXPECT_EQ(gfx::Size(kChildViewPadding, kChildViewPadding),
416             host_view()->GetMinimumSize());
417 }
418 
TEST_F(LayoutManagerBaseManagerTest,GetPreferredSize)419 TEST_F(LayoutManagerBaseManagerTest, GetPreferredSize) {
420   AddChildView(kSquarishSize);
421   AddChildView(kLongSize);
422   AddChildView(kTallSize);
423   const gfx::Size expected(kLongSize.width() + 2 * kChildViewPadding,
424                            kTallSize.height() + 2 * kChildViewPadding);
425   EXPECT_EQ(expected, host_view()->GetPreferredSize());
426 }
427 
TEST_F(LayoutManagerBaseManagerTest,GetPreferredHeightForWidth)428 TEST_F(LayoutManagerBaseManagerTest, GetPreferredHeightForWidth) {
429   AddChildView(kSquarishSize);
430   AddChildView(kLargeSize);
431   const int expected = kSquarishSize.height() + 2 * kChildViewPadding;
432   EXPECT_EQ(expected,
433             layout_manager()->GetPreferredHeightForWidth(host_view(), 20));
434   EXPECT_EQ(1, layout_manager()->num_layouts_generated());
435   layout_manager()->GetPreferredHeightForWidth(host_view(), 20);
436   EXPECT_EQ(1, layout_manager()->num_layouts_generated());
437   layout_manager()->GetPreferredHeightForWidth(host_view(), 25);
438   EXPECT_EQ(2, layout_manager()->num_layouts_generated());
439 }
440 
TEST_F(LayoutManagerBaseManagerTest,InvalidateLayout)441 TEST_F(LayoutManagerBaseManagerTest, InvalidateLayout) {
442   // Some invalidation could have been triggered during setup.
443   const int old_num_invalidations = layout_manager()->num_invalidations();
444 
445   host_view()->InvalidateLayout();
446   EXPECT_EQ(old_num_invalidations + 1, layout_manager()->num_invalidations());
447 }
448 
TEST_F(LayoutManagerBaseManagerTest,Layout)449 TEST_F(LayoutManagerBaseManagerTest, Layout) {
450   constexpr gfx::Point kUpperLeft(kChildViewPadding, kChildViewPadding);
451   AddChildView(kSquarishSize);
452   AddChildView(kLongSize);
453   AddChildView(kTallSize);
454 
455   // This should fit all of the child views and trigger layout.
456   host_view()->SetSize({40, 40});
457   EXPECT_EQ(1, layout_manager()->num_layouts_generated());
458   EXPECT_EQ(gfx::Rect(kUpperLeft, child(0)->GetPreferredSize()),
459             child(0)->bounds());
460   EXPECT_TRUE(child(0)->GetVisible());
461   EXPECT_EQ(gfx::Rect(kUpperLeft, child(1)->GetPreferredSize()),
462             child(1)->bounds());
463   EXPECT_TRUE(child(1)->GetVisible());
464   EXPECT_EQ(gfx::Rect(kUpperLeft, child(2)->GetPreferredSize()),
465             child(2)->bounds());
466   EXPECT_TRUE(child(2)->GetVisible());
467 
468   // This should drop out some children.
469   host_view()->SetSize({25, 25});
470   EXPECT_EQ(2, layout_manager()->num_layouts_generated());
471   EXPECT_EQ(gfx::Rect(kUpperLeft, child(0)->GetPreferredSize()),
472             child(0)->bounds());
473   EXPECT_TRUE(child(0)->GetVisible());
474   EXPECT_FALSE(child(1)->GetVisible());
475   EXPECT_FALSE(child(2)->GetVisible());
476 }
477 
TEST_F(LayoutManagerBaseManagerTest,ChildViewIgnoredByLayout)478 TEST_F(LayoutManagerBaseManagerTest, ChildViewIgnoredByLayout) {
479   AddChildView(kSquarishSize);
480   AddChildView(kLongSize);
481   AddChildView(kTallSize);
482 
483   EXPECT_FALSE(layout_manager()->IsChildViewIgnoredByLayout(child(0)));
484   EXPECT_FALSE(layout_manager()->IsChildViewIgnoredByLayout(child(1)));
485   EXPECT_FALSE(layout_manager()->IsChildViewIgnoredByLayout(child(2)));
486 
487   layout_manager()->SetChildViewIgnoredByLayout(child(1), true);
488 
489   EXPECT_FALSE(layout_manager()->IsChildViewIgnoredByLayout(child(0)));
490   EXPECT_TRUE(layout_manager()->IsChildViewIgnoredByLayout(child(1)));
491   EXPECT_FALSE(layout_manager()->IsChildViewIgnoredByLayout(child(2)));
492 }
493 
TEST_F(LayoutManagerBaseManagerTest,ChildViewIgnoredByLayout_IgnoresChildView)494 TEST_F(LayoutManagerBaseManagerTest,
495        ChildViewIgnoredByLayout_IgnoresChildView) {
496   AddChildView(kSquarishSize);
497   AddChildView(kLongSize);
498   AddChildView(kTallSize);
499 
500   layout_manager()->SetChildViewIgnoredByLayout(child(1), true);
501 
502   child(1)->SetSize(kLargeSize);
503 
504   // Makes enough room for all views, and triggers layout.
505   host_view()->SetSize({50, 50});
506 
507   EXPECT_EQ(child(0)->GetPreferredSize(), child(0)->size());
508   EXPECT_EQ(kLargeSize, child(1)->size());
509   EXPECT_EQ(child(2)->GetPreferredSize(), child(2)->size());
510 }
511 
TEST_F(LayoutManagerBaseManagerTest,ViewVisibilitySet)512 TEST_F(LayoutManagerBaseManagerTest, ViewVisibilitySet) {
513   AddChildView(kSquarishSize);
514   AddChildView(kLongSize);
515   AddChildView(kTallSize);
516 
517   child(1)->SetVisible(false);
518 
519   // Makes enough room for all views, and triggers layout.
520   host_view()->SetSize({50, 50});
521 
522   EXPECT_TRUE(child(0)->GetVisible());
523   EXPECT_EQ(child(0)->GetPreferredSize(), child(0)->size());
524   EXPECT_FALSE(child(1)->GetVisible());
525   EXPECT_TRUE(child(2)->GetVisible());
526   EXPECT_EQ(child(2)->GetPreferredSize(), child(2)->size());
527 
528   // Turn the second child view back on and verify it's present in the layout
529   // again.
530   child(1)->SetVisible(true);
531   host_view()->Layout();
532 
533   EXPECT_TRUE(child(0)->GetVisible());
534   EXPECT_EQ(child(0)->GetPreferredSize(), child(0)->size());
535   EXPECT_TRUE(child(1)->GetVisible());
536   EXPECT_EQ(child(1)->GetPreferredSize(), child(1)->size());
537   EXPECT_TRUE(child(2)->GetVisible());
538   EXPECT_EQ(child(2)->GetPreferredSize(), child(2)->size());
539 }
540 
TEST_F(LayoutManagerBaseManagerTest,ViewAdded)541 TEST_F(LayoutManagerBaseManagerTest, ViewAdded) {
542   AddChildView(kLongSize);
543   AddChildView(kTallSize);
544 
545   // Makes enough room for all views, and triggers layout.
546   host_view()->SetSize({50, 50});
547 
548   EXPECT_TRUE(child(0)->GetVisible());
549   EXPECT_EQ(child(0)->GetPreferredSize(), child(0)->size());
550   EXPECT_TRUE(child(1)->GetVisible());
551   EXPECT_EQ(child(1)->GetPreferredSize(), child(1)->size());
552 
553   // Add a new view and verify it is being laid out.
554   View* new_view = AddChildView(kSquarishSize);
555   host_view()->Layout();
556 
557   EXPECT_TRUE(new_view->GetVisible());
558   EXPECT_EQ(new_view->GetPreferredSize(), new_view->size());
559 }
560 
TEST_F(LayoutManagerBaseManagerTest,ViewAdded_NotVisible)561 TEST_F(LayoutManagerBaseManagerTest, ViewAdded_NotVisible) {
562   AddChildView(kLongSize);
563   AddChildView(kTallSize);
564 
565   // Makes enough room for all views, and triggers layout.
566   host_view()->SetSize({50, 50});
567 
568   EXPECT_TRUE(child(0)->GetVisible());
569   EXPECT_EQ(child(0)->GetPreferredSize(), child(0)->size());
570   EXPECT_TRUE(child(1)->GetVisible());
571   EXPECT_EQ(child(1)->GetPreferredSize(), child(1)->size());
572 
573   // Add a new view that is not visible and ensure that the layout manager
574   // doesn't touch it during layout.
575   View* new_view = new StaticSizedView(kSquarishSize);
576   new_view->SetVisible(false);
577   host_view()->AddChildView(new_view);
578   host_view()->Layout();
579 
580   EXPECT_FALSE(new_view->GetVisible());
581 }
582 
TEST_F(LayoutManagerBaseManagerTest,ViewRemoved)583 TEST_F(LayoutManagerBaseManagerTest, ViewRemoved) {
584   AddChildView(kSquarishSize);
585   View* const child_view = AddChildView(kLongSize);
586   AddChildView(kTallSize);
587 
588   // Makes enough room for all views, and triggers layout.
589   host_view()->SetSize({50, 50});
590 
591   EXPECT_TRUE(child(0)->GetVisible());
592   EXPECT_EQ(child(0)->GetPreferredSize(), child(0)->size());
593   EXPECT_TRUE(child(1)->GetVisible());
594   EXPECT_EQ(child(1)->GetPreferredSize(), child(1)->size());
595   EXPECT_TRUE(child(2)->GetVisible());
596   EXPECT_EQ(child(2)->GetPreferredSize(), child(2)->size());
597 
598   host_view()->RemoveChildView(child_view);
599   child_view->SetSize(kLargeSize);
600   host_view()->Layout();
601 
602   EXPECT_TRUE(child(0)->GetVisible());
603   EXPECT_EQ(child(0)->GetPreferredSize(), child(0)->size());
604   EXPECT_TRUE(child(1)->GetVisible());
605   EXPECT_EQ(child(1)->GetPreferredSize(), child(1)->size());
606 
607   EXPECT_TRUE(child_view->GetVisible());
608   EXPECT_EQ(kLargeSize, child_view->size());
609 
610   // Required since we removed it from the parent view.
611   delete child_view;
612 }
613 
TEST(LayoutManagerBase_ProposedLayoutTest,Equality)614 TEST(LayoutManagerBase_ProposedLayoutTest, Equality) {
615   View* ptr0 = nullptr;
616   View* ptr1 = ptr0 + 1;
617   View* ptr2 = ptr0 + 2;
618   ProposedLayout a;
619   ProposedLayout b;
620   EXPECT_TRUE(a == b);
621   a.host_size = {1, 2};
622   EXPECT_FALSE(a == b);
623   b.host_size = {1, 2};
624   EXPECT_TRUE(a == b);
625   a.child_layouts.push_back({ptr0, true, {1, 1, 2, 2}});
626   EXPECT_FALSE(a == b);
627   b.child_layouts.push_back(a.child_layouts[0]);
628   EXPECT_TRUE(a == b);
629   a.child_layouts[0].visible = false;
630   EXPECT_FALSE(a == b);
631   b.child_layouts[0].visible = false;
632   EXPECT_TRUE(a == b);
633   b.child_layouts[0].bounds = {0, 0, 3, 3};
634   // Since |visible| == false, changing bounds doesn't change anything.
635   EXPECT_TRUE(a == b);
636   a.child_layouts[0].visible = true;
637   b.child_layouts[0].visible = true;
638   EXPECT_FALSE(a == b);
639   a.child_layouts[0].visible = false;
640   b.child_layouts[0].visible = false;
641   a.child_layouts.push_back({ptr1, true, {1, 2, 3, 4}});
642   b.child_layouts.push_back({ptr2, true, {1, 2, 3, 4}});
643   EXPECT_FALSE(a == b);
644   b.child_layouts[1].child_view = ptr1;
645   EXPECT_TRUE(a == b);
646 }
647 
648 class LayoutManagerBaseAvailableSizeTest : public testing::Test {
649  public:
SetUp()650   void SetUp() override {
651     view_ = std::make_unique<View>();
652     layout_ =
653         view_->SetLayoutManager(std::make_unique<TestLayoutManagerBase>());
654   }
655 
view()656   View* view() { return view_.get(); }
layout()657   TestLayoutManagerBase* layout() { return layout_; }
658 
659  private:
660   std::unique_ptr<View> view_;
661   TestLayoutManagerBase* layout_;
662 };
663 
TEST_F(LayoutManagerBaseAvailableSizeTest,ReturnsCorrectValues)664 TEST_F(LayoutManagerBaseAvailableSizeTest, ReturnsCorrectValues) {
665   const SizeBounds kChild1Bounds(3, 7);
666   const SizeBounds kChild2Bounds(11, 13);
667   View* const child1 = view()->AddChildView(std::make_unique<View>());
668   View* const child2 = view()->AddChildView(std::make_unique<View>());
669   View not_a_child;
670 
671   layout()->OverrideProposedLayout(
672       {{10, 10},
673        {{child1, true, {1, 1, 1, 1}, kChild1Bounds},
674         {child2, true, {2, 2, 2, 2}, kChild2Bounds}}});
675   view()->SizeToPreferredSize();
676 
677   EXPECT_EQ(kChild1Bounds, view()->GetAvailableSize(child1));
678   EXPECT_EQ(kChild2Bounds, view()->GetAvailableSize(child2));
679   EXPECT_EQ(SizeBounds(), view()->GetAvailableSize(&not_a_child));
680 }
681 
TEST_F(LayoutManagerBaseAvailableSizeTest,AvailableSizesInNestedValuesAdd)682 TEST_F(LayoutManagerBaseAvailableSizeTest, AvailableSizesInNestedValuesAdd) {
683   View* const child = view()->AddChildView(std::make_unique<View>());
684   View* const grandchild = child->AddChildView(std::make_unique<View>());
685   auto* const child_layout =
686       child->SetLayoutManager(std::make_unique<TestLayoutManagerBase>());
687 
688   constexpr gfx::Size kViewSize(18, 17);
689   constexpr SizeBounds kChildAvailableSize(16, 15);
690   constexpr gfx::Size kChildSize(13, 12);
691   constexpr SizeBounds kGrandchildAvailableSize(10, 9);
692   constexpr gfx::Size kGrandchildSize(3, 2);
693   layout()->OverrideProposedLayout(
694       {kViewSize, {{child, true, {{3, 3}, kChildSize}, kChildAvailableSize}}});
695   child_layout->OverrideProposedLayout({kChildSize,
696                                         {{grandchild,
697                                           true,
698                                           {{2, 2}, kGrandchildSize},
699                                           kGrandchildAvailableSize}}});
700   view()->SizeToPreferredSize();
701 
702   EXPECT_EQ(kChildAvailableSize, view()->GetAvailableSize(child));
703   SizeBounds expected;
704   expected.set_width(*kGrandchildAvailableSize.width() +
705                      *kChildAvailableSize.width() - kChildSize.width());
706   expected.set_height(*kGrandchildAvailableSize.height() +
707                       *kChildAvailableSize.height() - kChildSize.height());
708   EXPECT_EQ(expected, child->GetAvailableSize(grandchild));
709 }
710 
TEST_F(LayoutManagerBaseAvailableSizeTest,PartiallySpecifiedAvailableSizesInNestedLayoutsAddPartially)711 TEST_F(LayoutManagerBaseAvailableSizeTest,
712        PartiallySpecifiedAvailableSizesInNestedLayoutsAddPartially) {
713   View* const child = view()->AddChildView(std::make_unique<View>());
714   View* const grandchild = child->AddChildView(std::make_unique<View>());
715   auto* const child_layout =
716       child->SetLayoutManager(std::make_unique<TestLayoutManagerBase>());
717 
718   constexpr gfx::Size kViewSize(18, 17);
719   constexpr SizeBounds kChildAvailableSize(16, base::nullopt);
720   constexpr gfx::Size kChildSize(13, 12);
721   constexpr SizeBounds kGrandchildAvailableSize(10, 9);
722   constexpr gfx::Size kGrandchildSize(3, 2);
723   layout()->OverrideProposedLayout(
724       {kViewSize, {{child, true, {{3, 3}, kChildSize}, kChildAvailableSize}}});
725   child_layout->OverrideProposedLayout({kChildSize,
726                                         {{grandchild,
727                                           true,
728                                           {{2, 2}, kGrandchildSize},
729                                           kGrandchildAvailableSize}}});
730   view()->SizeToPreferredSize();
731 
732   EXPECT_EQ(kChildAvailableSize, view()->GetAvailableSize(child));
733   SizeBounds expected;
734   expected.set_width(*kGrandchildAvailableSize.width() +
735                      *kChildAvailableSize.width() - kChildSize.width());
736   expected.set_height(*kGrandchildAvailableSize.height());
737   EXPECT_EQ(expected, child->GetAvailableSize(grandchild));
738 }
739 
TEST_F(LayoutManagerBaseAvailableSizeTest,MismatchedAvailableSizesInNestedLayoutsDoNotAdd)740 TEST_F(LayoutManagerBaseAvailableSizeTest,
741        MismatchedAvailableSizesInNestedLayoutsDoNotAdd) {
742   View* const child = view()->AddChildView(std::make_unique<View>());
743   View* const grandchild = child->AddChildView(std::make_unique<View>());
744   auto* const child_layout =
745       child->SetLayoutManager(std::make_unique<TestLayoutManagerBase>());
746 
747   constexpr gfx::Size kViewSize(18, 17);
748   constexpr SizeBounds kChildAvailableSize(16, base::nullopt);
749   constexpr gfx::Size kChildSize(13, 12);
750   constexpr SizeBounds kGrandchildAvailableSize(base::nullopt, 9);
751   constexpr gfx::Size kGrandchildSize(3, 2);
752   layout()->OverrideProposedLayout(
753       {kViewSize, {{child, true, {{3, 3}, kChildSize}, kChildAvailableSize}}});
754   child_layout->OverrideProposedLayout({kChildSize,
755                                         {{grandchild,
756                                           true,
757                                           {{2, 2}, kGrandchildSize},
758                                           kGrandchildAvailableSize}}});
759   view()->SizeToPreferredSize();
760 
761   EXPECT_EQ(kChildAvailableSize, view()->GetAvailableSize(child));
762   EXPECT_EQ(kGrandchildAvailableSize, child->GetAvailableSize(grandchild));
763 }
764 
TEST_F(LayoutManagerBaseAvailableSizeTest,AvaialbleSizeChangeTriggersDescendantLayout)765 TEST_F(LayoutManagerBaseAvailableSizeTest,
766        AvaialbleSizeChangeTriggersDescendantLayout) {
767   View* const child = view()->AddChildView(std::make_unique<View>());
768   TestLayoutManagerBase* const child_layout =
769       child->SetLayoutManager(std::make_unique<TestLayoutManagerBase>());
770   View* const grandchild = child->AddChildView(std::make_unique<View>());
771   TestLayoutManagerBase* const grandchild_layout =
772       grandchild->SetLayoutManager(std::make_unique<TestLayoutManagerBase>());
773   View* const great_grandchild =
774       grandchild->AddChildView(std::make_unique<View>());
775   TestLayoutManagerBase* const great_grandchild_layout =
776       great_grandchild->SetLayoutManager(
777           std::make_unique<TestLayoutManagerBase>());
778 
779   // Create a default root layout with non-visible, zero-size child with no
780   // available size.
781   ProposedLayout root_layout;
782   root_layout.child_layouts.push_back(ChildLayout());
783   root_layout.child_layouts[0].child_view = child;
784   root_layout.child_layouts[0].available_size = SizeBounds(0, 0);
785 
786   // Set some default layouts for the rest of the hierarchy.
787   layout()->OverrideProposedLayout(root_layout);
788   child_layout->OverrideProposedLayout({{}, {{grandchild, false, {}, {0, 0}}}});
789   grandchild_layout->OverrideProposedLayout(
790       {{}, {{great_grandchild, false, {}, {0, 0}}}});
791 
792   view()->Layout();
793 
794   const size_t num_grandchild_layouts = grandchild_layout->layout_count();
795   const size_t num_great_grandchild_layouts =
796       great_grandchild_layout->layout_count();
797 
798   // Set the same rootlayout again as a control. This should not have an effect
799   // on the layout of the grand- and great-grandchild views.
800   layout()->OverrideProposedLayout(root_layout);
801   view()->Layout();
802 
803   EXPECT_EQ(num_grandchild_layouts, grandchild_layout->layout_count());
804   EXPECT_EQ(num_great_grandchild_layouts,
805             great_grandchild_layout->layout_count());
806 
807   // Now set the child view to be visible with nonzero size and even larger
808   // available size. Applying this layout should change the size available to
809   // all views down the hierarchy, forcing a re-layout.
810   root_layout.child_layouts[0].visible = true;
811   root_layout.child_layouts[0].bounds = gfx::Rect(0, 0, 5, 5);
812   root_layout.child_layouts[0].available_size = SizeBounds(10, 10);
813   layout()->OverrideProposedLayout(root_layout);
814   view()->Layout();
815 
816   EXPECT_EQ(num_grandchild_layouts + 1, grandchild_layout->layout_count());
817   EXPECT_EQ(num_great_grandchild_layouts + 1,
818             great_grandchild_layout->layout_count());
819 }
820 
821 }  // namespace views
822