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 16 class 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. 83 class 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 104 class 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. 130 class 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. 218 TEST_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. 225 TEST_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 252 TEST_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