1// Copyright 2013 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 "chrome/browser/ui/views/frame/browser_view_layout.h"
6
7#include "chrome/browser/ui/views/frame/browser_view.h"
8#include "chrome/browser/ui/views/frame/browser_view_layout_delegate.h"
9#include "chrome/browser/ui/views/frame/contents_layout_manager.h"
10#include "chrome/browser/ui/views/frame/immersive_mode_controller.h"
11#include "chrome/browser/ui/views/infobars/infobar_container_view.h"
12#include "chrome/browser/ui/views/tabs/tab_strip.h"
13#include "chrome/test/base/browser_with_test_window_test.h"
14#include "testing/gtest/include/gtest/gtest.h"
15
16class MockBrowserViewLayoutDelegate : public BrowserViewLayoutDelegate {
17 public:
18  explicit MockBrowserViewLayoutDelegate(views::View* contents_web_view)
19      : contents_web_view_(contents_web_view),
20        tab_strip_visible_(true),
21        toolbar_visible_(true),
22        bookmark_bar_visible_(true),
23        download_shelf_needs_layout_(false) {
24  }
25  virtual ~MockBrowserViewLayoutDelegate() {}
26
27  void set_download_shelf_needs_layout(bool layout) {
28    download_shelf_needs_layout_ = layout;
29  }
30  void set_tab_strip_visible(bool visible) {
31    tab_strip_visible_ = visible;
32  }
33  void set_toolbar_visible(bool visible) {
34    toolbar_visible_ = visible;
35  }
36  void set_bookmark_bar_visible(bool visible) {
37    bookmark_bar_visible_ = visible;
38  }
39
40  // BrowserViewLayout::Delegate overrides:
41  virtual views::View* GetContentsWebView() const OVERRIDE {
42    return contents_web_view_;
43  }
44  virtual bool IsTabStripVisible() const OVERRIDE {
45    return tab_strip_visible_;
46  }
47  virtual gfx::Rect GetBoundsForTabStripInBrowserView() const OVERRIDE {
48    return gfx::Rect();
49  }
50  virtual int GetTopInsetInBrowserView() const OVERRIDE {
51    return 0;
52  }
53  virtual int GetThemeBackgroundXInset() const OVERRIDE {
54    return 0;
55  }
56  virtual bool IsToolbarVisible() const OVERRIDE {
57    return toolbar_visible_;
58  }
59  virtual bool IsBookmarkBarVisible() const OVERRIDE {
60    return bookmark_bar_visible_;
61  }
62  virtual bool DownloadShelfNeedsLayout() const OVERRIDE {
63    return download_shelf_needs_layout_;
64  }
65
66  virtual FullscreenExitBubbleViews* GetFullscreenExitBubble() const OVERRIDE {
67    return NULL;
68  }
69
70 private:
71  views::View* contents_web_view_;
72  bool tab_strip_visible_;
73  bool toolbar_visible_;
74  bool bookmark_bar_visible_;
75  bool download_shelf_needs_layout_;
76
77  DISALLOW_COPY_AND_ASSIGN(MockBrowserViewLayoutDelegate);
78};
79
80///////////////////////////////////////////////////////////////////////////////
81
82// A simple view that prefers an initial size.
83class MockView : public views::View {
84 public:
85  explicit MockView(gfx::Size initial_size)
86      : size_(initial_size) {
87    SetBoundsRect(gfx::Rect(gfx::Point(), size_));
88  }
89  virtual ~MockView() {}
90
91  // views::View overrides:
92  virtual gfx::Size GetPreferredSize() const OVERRIDE {
93    return size_;
94  }
95
96 private:
97  gfx::Size size_;
98
99  DISALLOW_COPY_AND_ASSIGN(MockView);
100};
101
102///////////////////////////////////////////////////////////////////////////////
103
104class MockImmersiveModeController : public ImmersiveModeController {
105 public:
106  MockImmersiveModeController() {}
107  virtual ~MockImmersiveModeController() {}
108
109  // ImmersiveModeController overrides:
110  virtual void Init(BrowserView* browser_view) OVERRIDE {}
111  virtual void SetEnabled(bool enabled) OVERRIDE {}
112  virtual bool IsEnabled() const OVERRIDE { return false; }
113  virtual bool ShouldHideTabIndicators() const OVERRIDE { return false; }
114  virtual bool ShouldHideTopViews() const OVERRIDE { return false; }
115  virtual bool IsRevealed() const OVERRIDE { return false; }
116  virtual int GetTopContainerVerticalOffset(
117      const gfx::Size& top_container_size) const OVERRIDE { return 0; }
118  virtual ImmersiveRevealedLock* GetRevealedLock(
119      AnimateReveal animate_reveal) OVERRIDE WARN_UNUSED_RESULT { return NULL; }
120  virtual void OnFindBarVisibleBoundsChanged(
121      const gfx::Rect& new_visible_bounds) OVERRIDE {}
122  virtual void SetupForTest() OVERRIDE {}
123
124 private:
125  DISALLOW_COPY_AND_ASSIGN(MockImmersiveModeController);
126};
127
128///////////////////////////////////////////////////////////////////////////////
129// Tests of BrowserViewLayout. Runs tests without constructing a BrowserView.
130class BrowserViewLayoutTest : public BrowserWithTestWindowTest {
131 public:
132  BrowserViewLayoutTest()
133      : delegate_(NULL),
134        top_container_(NULL),
135        tab_strip_(NULL),
136        toolbar_(NULL),
137        infobar_container_(NULL),
138        contents_container_(NULL),
139        contents_web_view_(NULL),
140        devtools_web_view_(NULL) {}
141  virtual ~BrowserViewLayoutTest() {}
142
143  BrowserViewLayout* layout() { return layout_.get(); }
144  MockBrowserViewLayoutDelegate* delegate() { return delegate_; }
145  MockView* root_view() { return root_view_.get(); }
146  MockView* top_container() { return top_container_; }
147  TabStrip* tab_strip() { return tab_strip_; }
148  MockView* toolbar() { return toolbar_; }
149  InfoBarContainerView* infobar_container() { return infobar_container_; }
150  MockView* contents_container() { return contents_container_; }
151
152  // BrowserWithTestWindowTest overrides:
153  virtual void SetUp() OVERRIDE {
154    BrowserWithTestWindowTest::SetUp();
155
156    root_view_.reset(new MockView(gfx::Size(800, 600)));
157
158    immersive_mode_controller_.reset(new MockImmersiveModeController);
159
160    top_container_ = new MockView(gfx::Size(800, 60));
161    tab_strip_ = new TabStrip(NULL);
162    top_container_->AddChildView(tab_strip_);
163    toolbar_ = new MockView(gfx::Size(800, 30));
164    top_container_->AddChildView(toolbar_);
165    root_view_->AddChildView(top_container_);
166
167    infobar_container_ = new InfoBarContainerView(NULL);
168    root_view_->AddChildView(infobar_container_);
169
170    contents_web_view_ = new MockView(gfx::Size(800, 600));
171    devtools_web_view_ = new MockView(gfx::Size(800, 600));
172    devtools_web_view_->SetVisible(false);
173
174    contents_container_ = new MockView(gfx::Size(800, 600));
175    contents_container_->AddChildView(devtools_web_view_);
176    contents_container_->AddChildView(contents_web_view_);
177    ContentsLayoutManager* contents_layout_manager =
178        new ContentsLayoutManager(devtools_web_view_, contents_web_view_);
179    contents_container_->SetLayoutManager(contents_layout_manager);
180
181    root_view_->AddChildView(contents_container_);
182
183    // TODO(jamescook): Attach |layout_| to |root_view_|?
184    layout_.reset(new BrowserViewLayout);
185    delegate_ = new MockBrowserViewLayoutDelegate(contents_web_view_);
186    layout_->Init(delegate_,
187                  browser(),
188                  NULL,  // BrowserView.
189                  top_container_,
190                  tab_strip_,
191                  toolbar_,
192                  infobar_container_,
193                  contents_container_,
194                  contents_layout_manager,
195                  immersive_mode_controller_.get());
196  }
197
198 private:
199  scoped_ptr<BrowserViewLayout> layout_;
200  MockBrowserViewLayoutDelegate* delegate_;  // Owned by |layout_|.
201  scoped_ptr<MockView> root_view_;
202
203  // Views owned by |root_view_|.
204  MockView* top_container_;
205  TabStrip* tab_strip_;
206  MockView* toolbar_;
207  InfoBarContainerView* infobar_container_;
208  MockView* contents_container_;
209  MockView* contents_web_view_;
210  MockView* devtools_web_view_;
211
212  scoped_ptr<MockImmersiveModeController> immersive_mode_controller_;
213
214  DISALLOW_COPY_AND_ASSIGN(BrowserViewLayoutTest);
215};
216
217// Test basic construction and initialization.
218TEST_F(BrowserViewLayoutTest, BrowserViewLayout) {
219  EXPECT_TRUE(layout()->browser());
220  EXPECT_TRUE(layout()->GetWebContentsModalDialogHost());
221  EXPECT_FALSE(layout()->InfobarVisible());
222}
223
224// Test the core layout functions.
225TEST_F(BrowserViewLayoutTest, Layout) {
226  // Simulate a window with no interesting UI.
227  delegate()->set_tab_strip_visible(false);
228  delegate()->set_toolbar_visible(false);
229  delegate()->set_bookmark_bar_visible(false);
230  layout()->Layout(root_view());
231
232  // Top views are zero-height.
233  EXPECT_EQ("0,0 0x0", tab_strip()->bounds().ToString());
234  EXPECT_EQ("0,0 800x0", toolbar()->bounds().ToString());
235  EXPECT_EQ("0,0 800x0", infobar_container()->bounds().ToString());
236  // Contents split fills the window.
237  EXPECT_EQ("0,0 800x600", contents_container()->bounds().ToString());
238
239  // Turn on the toolbar, like in a pop-up window.
240  delegate()->set_toolbar_visible(true);
241  layout()->Layout(root_view());
242
243  // Now the toolbar has bounds and other views shift down.
244  EXPECT_EQ("0,0 0x0", tab_strip()->bounds().ToString());
245  EXPECT_EQ("0,0 800x30", toolbar()->bounds().ToString());
246  EXPECT_EQ("0,30 800x0", infobar_container()->bounds().ToString());
247  EXPECT_EQ("0,30 800x570", contents_container()->bounds().ToString());
248
249  // TODO(jamescook): Tab strip and bookmark bar.
250}
251
252TEST_F(BrowserViewLayoutTest, LayoutDownloadShelf) {
253  scoped_ptr<MockView> download_shelf(new MockView(gfx::Size(800, 50)));
254  layout()->set_download_shelf(download_shelf.get());
255
256  // If download shelf doesn't need layout, it doesn't move the bottom edge.
257  delegate()->set_download_shelf_needs_layout(false);
258  const int kBottom = 500;
259  EXPECT_EQ(kBottom, layout()->LayoutDownloadShelf(kBottom));
260
261  // Download shelf layout moves up the bottom edge and sets visibility.
262  delegate()->set_download_shelf_needs_layout(true);
263  download_shelf->SetVisible(false);
264  EXPECT_EQ(450, layout()->LayoutDownloadShelf(kBottom));
265  EXPECT_TRUE(download_shelf->visible());
266  EXPECT_EQ("0,450 0x50", download_shelf->bounds().ToString());
267}
268