Home | History | Annotate | Download | only in frame
      1 // Copyright (c) 2011 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/sidebar/sidebar_manager.h"
      8 #include "chrome/browser/ui/find_bar/find_bar.h"
      9 #include "chrome/browser/ui/find_bar/find_bar_controller.h"
     10 #include "chrome/browser/ui/view_ids.h"
     11 #include "chrome/browser/ui/views/bookmarks/bookmark_bar_view.h"
     12 #include "chrome/browser/ui/views/download/download_shelf_view.h"
     13 #include "chrome/browser/ui/views/frame/browser_frame.h"
     14 #include "chrome/browser/ui/views/frame/browser_view.h"
     15 #include "chrome/browser/ui/views/frame/contents_container.h"
     16 #include "chrome/browser/ui/views/infobars/infobar_container_view.h"
     17 #include "chrome/browser/ui/views/tab_contents/tab_contents_container.h"
     18 #include "chrome/browser/ui/views/tabs/abstract_tab_strip_view.h"
     19 #include "chrome/browser/ui/views/toolbar_view.h"
     20 #include "ui/gfx/point.h"
     21 #include "ui/gfx/scrollbar_size.h"
     22 #include "ui/gfx/size.h"
     23 #include "views/controls/single_split_view.h"
     24 #include "views/window/window.h"
     25 
     26 #if defined(OS_LINUX)
     27 #include "views/window/hit_test.h"
     28 #endif
     29 
     30 namespace {
     31 
     32 // The visible height of the shadow above the tabs. Clicks in this area are
     33 // treated as clicks to the frame, rather than clicks to the tab.
     34 const int kTabShadowSize = 2;
     35 // The vertical overlap between the TabStrip and the Toolbar.
     36 const int kToolbarTabStripVerticalOverlap = 3;
     37 
     38 }  // namespace
     39 
     40 ////////////////////////////////////////////////////////////////////////////////
     41 // BrowserViewLayout, public:
     42 
     43 BrowserViewLayout::BrowserViewLayout()
     44     : tabstrip_(NULL),
     45       toolbar_(NULL),
     46       contents_split_(NULL),
     47       contents_container_(NULL),
     48       infobar_container_(NULL),
     49       download_shelf_(NULL),
     50       active_bookmark_bar_(NULL),
     51       browser_view_(NULL),
     52       find_bar_y_(0) {
     53 }
     54 
     55 BrowserViewLayout::~BrowserViewLayout() {
     56 }
     57 
     58 gfx::Size BrowserViewLayout::GetMinimumSize() {
     59   // TODO(noname): In theory the tabstrip width should probably be
     60   // (OTR + tabstrip + caption buttons) width.
     61   gfx::Size tabstrip_size(
     62       browser()->SupportsWindowFeature(Browser::FEATURE_TABSTRIP) ?
     63       tabstrip_->GetMinimumSize() : gfx::Size());
     64   gfx::Size toolbar_size(
     65       (browser()->SupportsWindowFeature(Browser::FEATURE_TOOLBAR) ||
     66        browser()->SupportsWindowFeature(Browser::FEATURE_LOCATIONBAR)) ?
     67       toolbar_->GetMinimumSize() : gfx::Size());
     68   if (tabstrip_size.height() && toolbar_size.height())
     69     toolbar_size.Enlarge(0, -kToolbarTabStripVerticalOverlap);
     70   gfx::Size bookmark_bar_size;
     71   if (active_bookmark_bar_ &&
     72       browser()->SupportsWindowFeature(Browser::FEATURE_BOOKMARKBAR)) {
     73     bookmark_bar_size = active_bookmark_bar_->GetMinimumSize();
     74     bookmark_bar_size.Enlarge(0,
     75         -(views::NonClientFrameView::kClientEdgeThickness +
     76             active_bookmark_bar_->GetToolbarOverlap(true)));
     77   }
     78   gfx::Size contents_size(contents_split_->GetMinimumSize());
     79 
     80   int min_height = tabstrip_size.height() + toolbar_size.height() +
     81       bookmark_bar_size.height() + contents_size.height();
     82   int widths[] = { tabstrip_size.width(), toolbar_size.width(),
     83                    bookmark_bar_size.width(), contents_size.width() };
     84   int min_width = *std::max_element(&widths[0], &widths[arraysize(widths)]);
     85   return gfx::Size(min_width, min_height);
     86 }
     87 
     88 gfx::Rect BrowserViewLayout::GetFindBarBoundingBox() const {
     89   // This function returns the area the Find Bar can be laid out
     90   // within. This basically implies the "user-perceived content
     91   // area" of the browser window excluding the vertical
     92   // scrollbar. This is not quite so straightforward as positioning
     93   // based on the TabContentsContainer since the BookmarkBarView may
     94   // be visible but not persistent (in the New Tab case) and we
     95   // position the Find Bar over the top of it in that case since the
     96   // BookmarkBarView is not _visually_ connected to the Toolbar.
     97 
     98   // First determine the bounding box of the content area in Widget
     99   // coordinates.
    100   gfx::Rect bounding_box(contents_container_->bounds());
    101 
    102   gfx::Point topleft;
    103   views::View::ConvertPointToWidget(contents_container_, &topleft);
    104   bounding_box.set_origin(topleft);
    105 
    106   // Adjust the position and size of the bounding box by the find bar offset
    107   // calculated during the last Layout.
    108   int height_delta = find_bar_y_ - bounding_box.y();
    109   bounding_box.set_y(find_bar_y_);
    110   bounding_box.set_height(std::max(0, bounding_box.height() + height_delta));
    111 
    112   // Finally decrease the width of the bounding box by the width of
    113   // the vertical scroll bar.
    114   int scrollbar_width = gfx::scrollbar_size();
    115   bounding_box.set_width(std::max(0, bounding_box.width() - scrollbar_width));
    116   if (base::i18n::IsRTL())
    117     bounding_box.set_x(bounding_box.x() + scrollbar_width);
    118 
    119   return bounding_box;
    120 }
    121 
    122 bool BrowserViewLayout::IsPositionInWindowCaption(
    123     const gfx::Point& point) {
    124   gfx::Point tabstrip_point(point);
    125   views::View::ConvertPointToView(browser_view_, tabstrip_, &tabstrip_point);
    126   return tabstrip_->IsPositionInWindowCaption(tabstrip_point);
    127 }
    128 
    129 int BrowserViewLayout::NonClientHitTest(
    130     const gfx::Point& point) {
    131   // Since the TabStrip only renders in some parts of the top of the window,
    132   // the un-obscured area is considered to be part of the non-client caption
    133   // area of the window. So we need to treat hit-tests in these regions as
    134   // hit-tests of the titlebar.
    135 
    136   views::View* parent = browser_view_->parent();
    137 
    138   gfx::Point point_in_browser_view_coords(point);
    139   views::View::ConvertPointToView(
    140       parent, browser_view_, &point_in_browser_view_coords);
    141 
    142   // Determine if the TabStrip exists and is capable of being clicked on. We
    143   // might be a popup window without a TabStrip.
    144   if (browser_view_->IsTabStripVisible()) {
    145     // See if the mouse pointer is within the bounds of the TabStrip.
    146     gfx::Point point_in_tabstrip_coords(point);
    147     views::View::ConvertPointToView(parent, tabstrip_,
    148                                     &point_in_tabstrip_coords);
    149     if (tabstrip_->HitTest(point_in_tabstrip_coords)) {
    150       if (tabstrip_->IsPositionInWindowCaption(point_in_tabstrip_coords))
    151         return HTCAPTION;
    152       return HTCLIENT;
    153     }
    154 
    155     // The top few pixels of the TabStrip are a drop-shadow - as we're pretty
    156     // starved of dragable area, let's give it to window dragging (this also
    157     // makes sense visually).
    158     if (!browser_view_->IsMaximized() &&
    159         (point_in_browser_view_coords.y() <
    160          (tabstrip_->y() + kTabShadowSize))) {
    161       // We return HTNOWHERE as this is a signal to our containing
    162       // NonClientView that it should figure out what the correct hit-test
    163       // code is given the mouse position...
    164       return HTNOWHERE;
    165     }
    166   }
    167 
    168   // If the point's y coordinate is below the top of the toolbar and otherwise
    169   // within the bounds of this view, the point is considered to be within the
    170   // client area.
    171   gfx::Rect bv_bounds = browser_view_->bounds();
    172   bv_bounds.Offset(0, toolbar_->y());
    173   bv_bounds.set_height(bv_bounds.height() - toolbar_->y());
    174   if (bv_bounds.Contains(point))
    175     return HTCLIENT;
    176 
    177   // If the point's y coordinate is above the top of the toolbar, but not in
    178   // the tabstrip (per previous checking in this function), then we consider it
    179   // in the window caption (e.g. the area to the right of the tabstrip
    180   // underneath the window controls). However, note that we DO NOT return
    181   // HTCAPTION here, because when the window is maximized the window controls
    182   // will fall into this space (since the BrowserView is sized to entire size
    183   // of the window at that point), and the HTCAPTION value will cause the
    184   // window controls not to work. So we return HTNOWHERE so that the caller
    185   // will hit-test the window controls before finally falling back to
    186   // HTCAPTION.
    187   bv_bounds = browser_view_->bounds();
    188   bv_bounds.set_height(toolbar_->y());
    189   if (bv_bounds.Contains(point))
    190     return HTNOWHERE;
    191 
    192   // If the point is somewhere else, delegate to the default implementation.
    193   return browser_view_->views::ClientView::NonClientHitTest(point);
    194 }
    195 
    196 //////////////////////////////////////////////////////////////////////////////
    197 // BrowserViewLayout, views::LayoutManager implementation:
    198 
    199 void BrowserViewLayout::Installed(views::View* host) {
    200   toolbar_ = NULL;
    201   contents_split_ = NULL;
    202   contents_container_ = NULL;
    203   infobar_container_ = NULL;
    204   download_shelf_ = NULL;
    205   active_bookmark_bar_ = NULL;
    206   tabstrip_ = NULL;
    207   browser_view_ = static_cast<BrowserView*>(host);
    208 }
    209 
    210 void BrowserViewLayout::Uninstalled(views::View* host) {}
    211 
    212 void BrowserViewLayout::ViewAdded(views::View* host, views::View* view) {
    213   switch (view->GetID()) {
    214     case VIEW_ID_CONTENTS_SPLIT: {
    215       contents_split_ = static_cast<views::SingleSplitView*>(view);
    216       // We're installed as the LayoutManager before BrowserView creates the
    217       // contents, so we have to set contents_container_ here rather than in
    218       // Installed.
    219       contents_container_ = browser_view_->contents_;
    220       break;
    221     }
    222     case VIEW_ID_INFO_BAR_CONTAINER:
    223       infobar_container_ = view;
    224       break;
    225     case VIEW_ID_DOWNLOAD_SHELF:
    226       download_shelf_ = static_cast<DownloadShelfView*>(view);
    227       break;
    228     case VIEW_ID_BOOKMARK_BAR:
    229       active_bookmark_bar_ = static_cast<BookmarkBarView*>(view);
    230       break;
    231     case VIEW_ID_TOOLBAR:
    232       toolbar_ = static_cast<ToolbarView*>(view);
    233       break;
    234     case VIEW_ID_TAB_STRIP:
    235       tabstrip_ = static_cast<AbstractTabStripView*>(view);
    236       break;
    237   }
    238 }
    239 
    240 void BrowserViewLayout::ViewRemoved(views::View* host, views::View* view) {
    241   switch (view->GetID()) {
    242     case VIEW_ID_BOOKMARK_BAR:
    243       active_bookmark_bar_ = NULL;
    244       break;
    245   }
    246 }
    247 
    248 void BrowserViewLayout::Layout(views::View* host) {
    249   vertical_layout_rect_ = browser_view_->GetLocalBounds();
    250   int top = LayoutTabStrip();
    251   if (browser_view_->IsTabStripVisible() && !browser_view_->UseVerticalTabs()) {
    252     tabstrip_->SetBackgroundOffset(gfx::Point(
    253         tabstrip_->GetMirroredX() + browser_view_->GetMirroredX(),
    254         browser_view_->frame()->GetHorizontalTabStripVerticalOffset(false)));
    255   }
    256   top = LayoutToolbar(top);
    257   top = LayoutBookmarkAndInfoBars(top);
    258   int bottom = LayoutDownloadShelf(browser_view_->height());
    259   int active_top_margin = GetTopMarginForActiveContent();
    260   top -= active_top_margin;
    261   contents_container_->SetActiveTopMargin(active_top_margin);
    262   LayoutTabContents(top, bottom);
    263   // This must be done _after_ we lay out the TabContents since this
    264   // code calls back into us to find the bounding box the find bar
    265   // must be laid out within, and that code depends on the
    266   // TabContentsContainer's bounds being up to date.
    267   if (browser()->HasFindBarController()) {
    268     browser()->GetFindBarController()->find_bar()->MoveWindowIfNecessary(
    269         gfx::Rect(), true);
    270   }
    271 }
    272 
    273 // Return the preferred size which is the size required to give each
    274 // children their respective preferred size.
    275 gfx::Size BrowserViewLayout::GetPreferredSize(views::View* host) {
    276   return gfx::Size();
    277 }
    278 
    279 //////////////////////////////////////////////////////////////////////////////
    280 // BrowserViewLayout, private:
    281 
    282 Browser* BrowserViewLayout::browser() {
    283   return browser_view_->browser();
    284 }
    285 
    286 const Browser* BrowserViewLayout::browser() const {
    287   return browser_view_->browser();
    288 }
    289 
    290 int BrowserViewLayout::LayoutTabStrip() {
    291   if (!browser_view_->IsTabStripVisible()) {
    292     tabstrip_->SetVisible(false);
    293     tabstrip_->SetBounds(0, 0, 0, 0);
    294     return 0;
    295   }
    296 
    297   gfx::Rect tabstrip_bounds(
    298       browser_view_->frame()->GetBoundsForTabStrip(tabstrip_));
    299   gfx::Point tabstrip_origin(tabstrip_bounds.origin());
    300   views::View::ConvertPointToView(browser_view_->parent(), browser_view_,
    301                                   &tabstrip_origin);
    302   tabstrip_bounds.set_origin(tabstrip_origin);
    303 
    304   if (browser_view_->UseVerticalTabs())
    305     vertical_layout_rect_.Inset(tabstrip_bounds.width(), 0, 0, 0);
    306 
    307   tabstrip_->SetVisible(true);
    308   tabstrip_->SetBoundsRect(tabstrip_bounds);
    309   return browser_view_->UseVerticalTabs() ?
    310       tabstrip_bounds.y() : tabstrip_bounds.bottom();
    311 }
    312 
    313 int BrowserViewLayout::LayoutToolbar(int top) {
    314   int browser_view_width = vertical_layout_rect_.width();
    315   bool visible = browser_view_->IsToolbarVisible();
    316   toolbar_->location_bar()->SetFocusable(visible);
    317   int y = top;
    318   if (!browser_view_->UseVerticalTabs()) {
    319     y -= ((visible && browser_view_->IsTabStripVisible()) ?
    320           kToolbarTabStripVerticalOverlap : 0);
    321   }
    322   int height = visible ? toolbar_->GetPreferredSize().height() : 0;
    323   toolbar_->SetVisible(visible);
    324   toolbar_->SetBounds(vertical_layout_rect_.x(), y, browser_view_width, height);
    325   return y + height;
    326 }
    327 
    328 int BrowserViewLayout::LayoutBookmarkAndInfoBars(int top) {
    329   find_bar_y_ = top + browser_view_->y() - 1;
    330   if (active_bookmark_bar_) {
    331     // If we're showing the Bookmark bar in detached style, then we
    332     // need to show any Info bar _above_ the Bookmark bar, since the
    333     // Bookmark bar is styled to look like it's part of the page.
    334     if (active_bookmark_bar_->IsDetached())
    335       return LayoutBookmarkBar(LayoutInfoBar(top));
    336     // Otherwise, Bookmark bar first, Info bar second.
    337     top = std::max(toolbar_->bounds().bottom(), LayoutBookmarkBar(top));
    338   }
    339   find_bar_y_ = top + browser_view_->y() - 1;
    340   return LayoutInfoBar(top);
    341 }
    342 
    343 int BrowserViewLayout::LayoutBookmarkBar(int top) {
    344   DCHECK(active_bookmark_bar_);
    345   int y = top;
    346   if (!browser_view_->IsBookmarkBarVisible()) {
    347     active_bookmark_bar_->SetVisible(false);
    348     active_bookmark_bar_->SetBounds(0, y, browser_view_->width(), 0);
    349     return y;
    350   }
    351 
    352   active_bookmark_bar_->set_infobar_visible(InfobarVisible());
    353   int bookmark_bar_height = active_bookmark_bar_->GetPreferredSize().height();
    354   y -= views::NonClientFrameView::kClientEdgeThickness +
    355       active_bookmark_bar_->GetToolbarOverlap(false);
    356   active_bookmark_bar_->SetVisible(true);
    357   active_bookmark_bar_->SetBounds(vertical_layout_rect_.x(), y,
    358                                   vertical_layout_rect_.width(),
    359                                   bookmark_bar_height);
    360   return y + bookmark_bar_height;
    361 }
    362 
    363 int BrowserViewLayout::LayoutInfoBar(int top) {
    364   // Raise the |infobar_container_| by its vertical overlap.
    365   infobar_container_->SetVisible(InfobarVisible());
    366   int height;
    367   int overlapped_top = top -
    368       static_cast<InfoBarContainerView*>(infobar_container_)->
    369           GetVerticalOverlap(&height);
    370   infobar_container_->SetBounds(vertical_layout_rect_.x(),
    371                                 overlapped_top,
    372                                 vertical_layout_rect_.width(),
    373                                 height);
    374   return overlapped_top + height;
    375 }
    376 
    377 // |browser_reserved_rect| is in browser_view_ coordinates.
    378 // |future_source_bounds| is in |source|'s parent coordinates.
    379 // |future_parent_offset| is required, since parent view is not moved yet.
    380 // Note that |future_parent_offset| is relative to browser_view_, not to
    381 // the parent view.
    382 void BrowserViewLayout::UpdateReservedContentsRect(
    383     const gfx::Rect& browser_reserved_rect,
    384     TabContentsContainer* source,
    385     const gfx::Rect& future_source_bounds,
    386     const gfx::Point& future_parent_offset) {
    387   gfx::Point resize_corner_origin(browser_reserved_rect.origin());
    388   // Convert |resize_corner_origin| from browser_view_ to source's parent
    389   // coordinates.
    390   views::View::ConvertPointToView(browser_view_, source->parent(),
    391                                   &resize_corner_origin);
    392   // Create |reserved_rect| in source's parent coordinates.
    393   gfx::Rect reserved_rect(resize_corner_origin, browser_reserved_rect.size());
    394   // Apply source's parent future offset to it.
    395   reserved_rect.Offset(-future_parent_offset.x(), -future_parent_offset.y());
    396   if (future_source_bounds.Intersects(reserved_rect)) {
    397     // |source| is not properly positioned yet to use ConvertPointToView,
    398     // so convert it into |source|'s coordinates manually.
    399     reserved_rect.Offset(-future_source_bounds.x(), -future_source_bounds.y());
    400   } else {
    401     reserved_rect = gfx::Rect();
    402   }
    403 
    404   source->SetReservedContentsRect(reserved_rect);
    405 }
    406 
    407 void BrowserViewLayout::LayoutTabContents(int top, int bottom) {
    408   // The ultimate idea is to calcualte bounds and reserved areas for all
    409   // contents views first and then resize them all, so every view
    410   // (and its contents) is resized and laid out only once.
    411 
    412   // The views hierarcy (see browser_view.h for more details):
    413   // 1) Sidebar is not allowed:
    414   //     contents_split_ -> [contents_container_ | devtools]
    415   // 2) Sidebar is allowed:
    416   //     contents_split_ ->
    417   //         [sidebar_split -> [contents_container_ | sidebar]] | devtools
    418 
    419   gfx::Rect sidebar_split_bounds;
    420   gfx::Rect contents_bounds;
    421   gfx::Rect sidebar_bounds;
    422   gfx::Rect devtools_bounds;
    423 
    424   gfx::Rect contents_split_bounds(vertical_layout_rect_.x(), top,
    425                                   vertical_layout_rect_.width(),
    426                                   std::max(0, bottom - top));
    427   contents_split_->CalculateChildrenBounds(
    428       contents_split_bounds, &sidebar_split_bounds, &devtools_bounds);
    429   gfx::Point contents_split_offset(
    430       contents_split_bounds.x() - contents_split_->bounds().x(),
    431       contents_split_bounds.y() - contents_split_->bounds().y());
    432   gfx::Point sidebar_split_offset(contents_split_offset);
    433   sidebar_split_offset.Offset(sidebar_split_bounds.x(),
    434                               sidebar_split_bounds.y());
    435 
    436   views::SingleSplitView* sidebar_split = browser_view_->sidebar_split_;
    437   if (sidebar_split) {
    438     DCHECK(sidebar_split == contents_split_->GetChildViewAt(0));
    439     sidebar_split->CalculateChildrenBounds(
    440         sidebar_split_bounds, &contents_bounds, &sidebar_bounds);
    441   } else {
    442     contents_bounds = sidebar_split_bounds;
    443   }
    444 
    445   // Layout resize corner, sidebar mini tabs and calculate reserved contents
    446   // rects here as all contents view bounds are already determined, but not yet
    447   // set at this point, so contents will be laid out once at most.
    448   // TODO(alekseys): layout sidebar minitabs and adjust reserved rect
    449   // accordingly.
    450   gfx::Rect browser_reserved_rect;
    451   if (!browser_view_->frame_->GetWindow()->IsMaximized() &&
    452       !browser_view_->frame_->GetWindow()->IsFullscreen()) {
    453     gfx::Size resize_corner_size = browser_view_->GetResizeCornerSize();
    454     if (!resize_corner_size.IsEmpty()) {
    455       gfx::Rect bounds = browser_view_->GetContentsBounds();
    456       gfx::Point resize_corner_origin(
    457           bounds.right() - resize_corner_size.width(),
    458           bounds.bottom() - resize_corner_size.height());
    459       browser_reserved_rect =
    460           gfx::Rect(resize_corner_origin, resize_corner_size);
    461     }
    462   }
    463 
    464   UpdateReservedContentsRect(browser_reserved_rect,
    465                              browser_view_->contents_container_,
    466                              contents_bounds,
    467                              sidebar_split_offset);
    468   if (sidebar_split) {
    469     UpdateReservedContentsRect(browser_reserved_rect,
    470                                browser_view_->sidebar_container_,
    471                                sidebar_bounds,
    472                                sidebar_split_offset);
    473   }
    474   UpdateReservedContentsRect(browser_reserved_rect,
    475                              browser_view_->devtools_container_,
    476                              devtools_bounds,
    477                              contents_split_offset);
    478 
    479   // Now it's safe to actually resize all contents views in the hierarchy.
    480   contents_split_->SetBoundsRect(contents_split_bounds);
    481   if (sidebar_split)
    482     sidebar_split->SetBoundsRect(sidebar_split_bounds);
    483 }
    484 
    485 int BrowserViewLayout::GetTopMarginForActiveContent() {
    486   if (!active_bookmark_bar_ || !browser_view_->IsBookmarkBarVisible() ||
    487       !active_bookmark_bar_->IsDetached()) {
    488     return 0;
    489   }
    490 
    491   if (contents_split_->GetChildViewAt(1) &&
    492       contents_split_->GetChildViewAt(1)->IsVisible())
    493     return 0;
    494 
    495   if (SidebarManager::IsSidebarAllowed()) {
    496     views::View* sidebar_split = contents_split_->GetChildViewAt(0);
    497     if (sidebar_split->GetChildViewAt(1) &&
    498         sidebar_split->GetChildViewAt(1)->IsVisible())
    499       return 0;
    500   }
    501 
    502   // Adjust for separator.
    503   return active_bookmark_bar_->height() -
    504       views::NonClientFrameView::kClientEdgeThickness;
    505 }
    506 
    507 int BrowserViewLayout::LayoutDownloadShelf(int bottom) {
    508   // Re-layout the shelf either if it is visible or if it's close animation
    509   // is currently running.
    510   if (browser_view_->IsDownloadShelfVisible() ||
    511       (download_shelf_ && download_shelf_->IsClosing())) {
    512     bool visible = browser()->SupportsWindowFeature(
    513         Browser::FEATURE_DOWNLOADSHELF);
    514     DCHECK(download_shelf_);
    515     int height = visible ? download_shelf_->GetPreferredSize().height() : 0;
    516     download_shelf_->SetVisible(visible);
    517     download_shelf_->SetBounds(vertical_layout_rect_.x(), bottom - height,
    518                                vertical_layout_rect_.width(), height);
    519     download_shelf_->Layout();
    520     bottom -= height;
    521   }
    522   return bottom;
    523 }
    524 
    525 bool BrowserViewLayout::InfobarVisible() const {
    526   // NOTE: Can't check if the size IsEmpty() since it's always 0-width.
    527   return browser()->SupportsWindowFeature(Browser::FEATURE_INFOBAR) &&
    528       (infobar_container_->GetPreferredSize().height() != 0);
    529 }
    530