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