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/app_panel_browser_frame_view.h"
      6 
      7 #include "base/compiler_specific.h"
      8 #include "base/utf_string_conversions.h"
      9 #include "chrome/browser/ui/views/frame/browser_frame.h"
     10 #include "chrome/browser/ui/views/frame/browser_view.h"
     11 #include "content/browser/tab_contents/tab_contents.h"
     12 #include "grit/app_resources.h"
     13 #include "grit/chromium_strings.h"
     14 #include "grit/generated_resources.h"
     15 #include "grit/theme_resources.h"
     16 #include "ui/base/l10n/l10n_util.h"
     17 #include "ui/base/resource/resource_bundle.h"
     18 #include "ui/gfx/canvas.h"
     19 #include "ui/gfx/font.h"
     20 #include "ui/gfx/path.h"
     21 #include "views/controls/button/image_button.h"
     22 #include "views/window/window.h"
     23 #include "views/window/window_resources.h"
     24 
     25 #if defined(OS_LINUX)
     26 #include "views/window/hit_test.h"
     27 #endif
     28 
     29 namespace {
     30 // The frame border is only visible in restored mode and is hardcoded to 1 px on
     31 // each side regardless of the system window border size.
     32 const int kFrameBorderThickness = 1;
     33 // In the window corners, the resize areas don't actually expand bigger, but the
     34 // 16 px at the end of each edge triggers diagonal resizing.
     35 const int kResizeAreaCornerSize = 16;
     36 // The titlebar never shrinks too short to show the caption button plus some
     37 // padding below it.
     38 const int kCaptionButtonHeightWithPadding = 27;
     39 // The titlebar has a 2 px 3D edge along the bottom, and we reserve 2 px (1 for
     40 // border, 1 for padding) along the top.
     41 const int kTitlebarTopAndBottomEdgeThickness = 2;
     42 // The icon is inset 6 px from the left frame border.
     43 const int kIconLeftSpacing = 6;
     44 // The icon never shrinks below 16 px on a side.
     45 const int kIconMinimumSize = 16;
     46 // There is a 4 px gap between the icon and the title text.
     47 const int kIconTitleSpacing = 4;
     48 // There is a 5 px gap between the title text and the close button.
     49 const int kTitleCloseButtonSpacing = 5;
     50 // There is a 4 px gap between the close button and the frame border.
     51 const int kCloseButtonFrameBorderSpacing = 4;
     52 }
     53 
     54 ///////////////////////////////////////////////////////////////////////////////
     55 // AppPanelBrowserFrameView, public:
     56 
     57 AppPanelBrowserFrameView::AppPanelBrowserFrameView(BrowserFrame* frame,
     58                                                    BrowserView* browser_view)
     59     : BrowserNonClientFrameView(),
     60       ALLOW_THIS_IN_INITIALIZER_LIST(
     61           close_button_(new views::ImageButton(this))),
     62       window_icon_(NULL),
     63       frame_(frame),
     64       browser_view_(browser_view) {
     65   DCHECK(browser_view->ShouldShowWindowIcon());
     66   DCHECK(browser_view->ShouldShowWindowTitle());
     67 
     68   ResourceBundle& rb = ResourceBundle::GetSharedInstance();
     69   close_button_->SetImage(views::CustomButton::BS_NORMAL,
     70                           rb.GetBitmapNamed(IDR_CLOSE_BAR));
     71   close_button_->SetImage(views::CustomButton::BS_HOT,
     72                           rb.GetBitmapNamed(IDR_CLOSE_BAR_H));
     73   close_button_->SetImage(views::CustomButton::BS_PUSHED,
     74                           rb.GetBitmapNamed(IDR_CLOSE_BAR_P));
     75   close_button_->SetAccessibleName(
     76       l10n_util::GetStringUTF16(IDS_ACCNAME_CLOSE));
     77   AddChildView(close_button_);
     78 
     79   window_icon_ = new TabIconView(this);
     80   window_icon_->set_is_light(true);
     81   AddChildView(window_icon_);
     82   window_icon_->Update();
     83 }
     84 
     85 AppPanelBrowserFrameView::~AppPanelBrowserFrameView() {
     86 }
     87 
     88 ///////////////////////////////////////////////////////////////////////////////
     89 // AppPanelBrowserFrameView, BrowserNonClientFrameView implementation:
     90 
     91 gfx::Rect AppPanelBrowserFrameView::GetBoundsForTabStrip(
     92     views::View* tabstrip) const {
     93   // App panels never show a tab strip.
     94   NOTREACHED();
     95   return gfx::Rect();
     96 }
     97 
     98 int AppPanelBrowserFrameView::GetHorizontalTabStripVerticalOffset(
     99     bool restored) const {
    100   // App panels are not themed and don't need this.
    101   return 0;
    102 }
    103 
    104 void AppPanelBrowserFrameView::UpdateThrobber(bool running) {
    105   window_icon_->Update();
    106 }
    107 
    108 gfx::Size AppPanelBrowserFrameView::GetMinimumSize() {
    109   gfx::Size min_size(browser_view_->GetMinimumSize());
    110   int border_thickness = NonClientBorderThickness();
    111   min_size.Enlarge(2 * border_thickness,
    112                    NonClientTopBorderHeight() + border_thickness);
    113 
    114   min_size.set_width(std::max(min_size.width(),
    115       (2 * FrameBorderThickness()) + kIconLeftSpacing + IconSize() +
    116       kTitleCloseButtonSpacing + kCloseButtonFrameBorderSpacing));
    117   return min_size;
    118 }
    119 
    120 ///////////////////////////////////////////////////////////////////////////////
    121 // AppPanelBrowserFrameView, views::NonClientFrameView implementation:
    122 
    123 gfx::Rect AppPanelBrowserFrameView::GetBoundsForClientView() const {
    124   return client_view_bounds_;
    125 }
    126 
    127 bool AppPanelBrowserFrameView::AlwaysUseCustomFrame() const {
    128   return true;
    129 }
    130 
    131 bool AppPanelBrowserFrameView::AlwaysUseNativeFrame() const {
    132   return frame_->AlwaysUseNativeFrame();
    133 }
    134 
    135 gfx::Rect AppPanelBrowserFrameView::GetWindowBoundsForClientBounds(
    136     const gfx::Rect& client_bounds) const {
    137   int top_height = NonClientTopBorderHeight();
    138   int border_thickness = NonClientBorderThickness();
    139   return gfx::Rect(std::max(0, client_bounds.x() - border_thickness),
    140                    std::max(0, client_bounds.y() - top_height),
    141                    client_bounds.width() + (2 * border_thickness),
    142                    client_bounds.height() + top_height + border_thickness);
    143 }
    144 
    145 int AppPanelBrowserFrameView::NonClientHitTest(const gfx::Point& point) {
    146   if (!bounds().Contains(point))
    147     return HTNOWHERE;
    148 
    149   int frame_component =
    150       frame_->GetWindow()->client_view()->NonClientHitTest(point);
    151 
    152   // See if we're in the sysmenu region.  (We check the ClientView first to be
    153   // consistent with OpaqueBrowserFrameView; it's not really necessary here.)
    154   gfx::Rect sysmenu_rect(IconBounds());
    155   // In maximized mode we extend the rect to the screen corner to take advantage
    156   // of Fitts' Law.
    157   if (frame_->GetWindow()->IsMaximized())
    158     sysmenu_rect.SetRect(0, 0, sysmenu_rect.right(), sysmenu_rect.bottom());
    159   sysmenu_rect.set_x(GetMirroredXForRect(sysmenu_rect));
    160   if (sysmenu_rect.Contains(point))
    161     return (frame_component == HTCLIENT) ? HTCLIENT : HTSYSMENU;
    162 
    163   if (frame_component != HTNOWHERE)
    164     return frame_component;
    165 
    166   // Then see if the point is within any of the window controls.
    167   if (close_button_->IsVisible() &&
    168       close_button_->GetMirroredBounds().Contains(point))
    169     return HTCLOSE;
    170 
    171   int window_component = GetHTComponentForFrame(point,
    172       NonClientBorderThickness(), NonClientBorderThickness(),
    173       kResizeAreaCornerSize, kResizeAreaCornerSize,
    174       frame_->GetWindow()->window_delegate()->CanResize());
    175   // Fall back to the caption if no other component matches.
    176   return (window_component == HTNOWHERE) ? HTCAPTION : window_component;
    177 }
    178 
    179 void AppPanelBrowserFrameView::GetWindowMask(const gfx::Size& size,
    180                                              gfx::Path* window_mask) {
    181   DCHECK(window_mask);
    182 
    183   if (frame_->GetWindow()->IsMaximized())
    184     return;
    185 
    186   // Redefine the window visible region for the new size.
    187   window_mask->moveTo(0, 3);
    188   window_mask->lineTo(1, 2);
    189   window_mask->lineTo(1, 1);
    190   window_mask->lineTo(2, 1);
    191   window_mask->lineTo(3, 0);
    192 
    193   window_mask->lineTo(SkIntToScalar(size.width() - 3), 0);
    194   window_mask->lineTo(SkIntToScalar(size.width() - 2), 1);
    195   window_mask->lineTo(SkIntToScalar(size.width() - 1), 1);
    196   window_mask->lineTo(SkIntToScalar(size.width() - 1), 2);
    197   window_mask->lineTo(SkIntToScalar(size.width()), 3);
    198 
    199   window_mask->lineTo(SkIntToScalar(size.width()),
    200                       SkIntToScalar(size.height()));
    201   window_mask->lineTo(0, SkIntToScalar(size.height()));
    202   window_mask->close();
    203 }
    204 
    205 void AppPanelBrowserFrameView::EnableClose(bool enable) {
    206   close_button_->SetEnabled(enable);
    207 }
    208 
    209 void AppPanelBrowserFrameView::ResetWindowControls() {
    210   // The close button isn't affected by this constraint.
    211 }
    212 
    213 void AppPanelBrowserFrameView::UpdateWindowIcon() {
    214   window_icon_->SchedulePaint();
    215 }
    216 
    217 
    218 ///////////////////////////////////////////////////////////////////////////////
    219 // AppPanelBrowserFrameView, views::View overrides:
    220 
    221 void AppPanelBrowserFrameView::OnPaint(gfx::Canvas* canvas) {
    222   views::Window* window = frame_->GetWindow();
    223   if (window->IsMaximized())
    224     PaintMaximizedFrameBorder(canvas);
    225   else
    226     PaintRestoredFrameBorder(canvas);
    227   PaintTitleBar(canvas);
    228   if (!window->IsMaximized())
    229     PaintRestoredClientEdge(canvas);
    230 }
    231 
    232 void AppPanelBrowserFrameView::Layout() {
    233   LayoutWindowControls();
    234   LayoutTitleBar();
    235   client_view_bounds_ = CalculateClientAreaBounds(width(), height());
    236 }
    237 
    238 ///////////////////////////////////////////////////////////////////////////////
    239 // AppPanelBrowserFrameView, views::ButtonListener implementation:
    240 
    241 void AppPanelBrowserFrameView::ButtonPressed(views::Button* sender,
    242                                              const views::Event& event) {
    243   if (sender == close_button_)
    244     frame_->GetWindow()->CloseWindow();
    245 }
    246 
    247 ///////////////////////////////////////////////////////////////////////////////
    248 // AppPanelBrowserFrameView, TabIconView::TabContentsProvider implementation:
    249 
    250 bool AppPanelBrowserFrameView::ShouldTabIconViewAnimate() const {
    251   // This function is queried during the creation of the window as the
    252   // TabIconView we host is initialized, so we need to NULL check the selected
    253   // TabContents because in this condition there is not yet a selected tab.
    254   TabContents* current_tab = browser_view_->GetSelectedTabContents();
    255   return current_tab ? current_tab->is_loading() : false;
    256 }
    257 
    258 SkBitmap AppPanelBrowserFrameView::GetFaviconForTabIconView() {
    259   return frame_->GetWindow()->window_delegate()->GetWindowIcon();
    260 }
    261 
    262 ///////////////////////////////////////////////////////////////////////////////
    263 // AppPanelBrowserFrameView, private:
    264 
    265 int AppPanelBrowserFrameView::FrameBorderThickness() const {
    266   return frame_->GetWindow()->IsMaximized() ? 0 : kFrameBorderThickness;
    267 }
    268 
    269 int AppPanelBrowserFrameView::NonClientBorderThickness() const {
    270   return FrameBorderThickness() +
    271       (frame_->GetWindow()->IsMaximized() ? 0 : kClientEdgeThickness);
    272 }
    273 
    274 int AppPanelBrowserFrameView::NonClientTopBorderHeight() const {
    275   return std::max(FrameBorderThickness() + IconSize(),
    276                   FrameBorderThickness() + kCaptionButtonHeightWithPadding) +
    277       TitlebarBottomThickness();
    278 }
    279 
    280 int AppPanelBrowserFrameView::TitlebarBottomThickness() const {
    281   return kTitlebarTopAndBottomEdgeThickness +
    282       (frame_->GetWindow()->IsMaximized() ? 0 : kClientEdgeThickness);
    283 }
    284 
    285 int AppPanelBrowserFrameView::IconSize() const {
    286 #if defined(OS_WIN)
    287   // This metric scales up if either the titlebar height or the titlebar font
    288   // size are increased.
    289   return GetSystemMetrics(SM_CYSMICON);
    290 #else
    291   return std::max(BrowserFrame::GetTitleFont().height(), kIconMinimumSize);
    292 #endif
    293 }
    294 
    295 gfx::Rect AppPanelBrowserFrameView::IconBounds() const {
    296   int size = IconSize();
    297   int frame_thickness = FrameBorderThickness();
    298   // Our frame border has a different "3D look" than Windows'.  Theirs has a
    299   // more complex gradient on the top that they push their icon/title below;
    300   // then the maximized window cuts this off and the icon/title are centered
    301   // in the remaining space.  Because the apparent shape of our border is
    302   // simpler, using the same positioning makes things look slightly uncentered
    303   // with restored windows, so when the window is restored, instead of
    304   // calculating the remaining space from below the frame border, we calculate
    305   // from below the top border-plus-padding.
    306   int unavailable_px_at_top = frame_->GetWindow()->IsMaximized() ?
    307       frame_thickness : kTitlebarTopAndBottomEdgeThickness;
    308   // When the icon is shorter than the minimum space we reserve for the caption
    309   // button, we vertically center it.  We want to bias rounding to put extra
    310   // space above the icon, since the 3D edge (+ client edge, for restored
    311   // windows) below looks (to the eye) more like additional space than does the
    312   // border + padding (or nothing at all, for maximized windows) above; hence
    313   // the +1.
    314   int y = unavailable_px_at_top + (NonClientTopBorderHeight() -
    315       unavailable_px_at_top - size - TitlebarBottomThickness() + 1) / 2;
    316   return gfx::Rect(frame_thickness + kIconLeftSpacing, y, size, size);
    317 }
    318 
    319 void AppPanelBrowserFrameView::PaintRestoredFrameBorder(gfx::Canvas* canvas) {
    320   ResourceBundle& rb = ResourceBundle::GetSharedInstance();
    321 
    322   SkBitmap* top_left_corner = rb.GetBitmapNamed(IDR_WINDOW_TOP_LEFT_CORNER);
    323   SkBitmap* top_right_corner =
    324       rb.GetBitmapNamed(IDR_WINDOW_TOP_RIGHT_CORNER);
    325   SkBitmap* top_edge = rb.GetBitmapNamed(IDR_WINDOW_TOP_CENTER);
    326   SkBitmap* right_edge = rb.GetBitmapNamed(IDR_WINDOW_RIGHT_SIDE);
    327   SkBitmap* left_edge = rb.GetBitmapNamed(IDR_WINDOW_LEFT_SIDE);
    328   SkBitmap* bottom_left_corner =
    329       rb.GetBitmapNamed(IDR_WINDOW_BOTTOM_LEFT_CORNER);
    330   SkBitmap* bottom_right_corner =
    331       rb.GetBitmapNamed(IDR_WINDOW_BOTTOM_RIGHT_CORNER);
    332   SkBitmap* bottom_edge = rb.GetBitmapNamed(IDR_WINDOW_BOTTOM_CENTER);
    333 
    334   // Window frame mode and color.
    335   SkBitmap* theme_frame;
    336   SkColor frame_color;
    337   if (ShouldPaintAsActive()) {
    338     theme_frame = rb.GetBitmapNamed(IDR_FRAME_APP_PANEL);
    339     frame_color = ResourceBundle::frame_color_app_panel;
    340   } else {
    341     theme_frame = rb.GetBitmapNamed(IDR_FRAME_APP_PANEL);  // TODO
    342     frame_color = ResourceBundle::frame_color_app_panel_inactive;
    343   }
    344 
    345   // Fill with the frame color first so we have a constant background for
    346   // areas not covered by the theme image.
    347   canvas->FillRectInt(frame_color, 0, 0, width(), theme_frame->height());
    348   // Now fill down the sides.
    349   canvas->FillRectInt(frame_color, 0, theme_frame->height(), left_edge->width(),
    350                       height() - theme_frame->height());
    351   canvas->FillRectInt(frame_color, width() - right_edge->width(),
    352                       theme_frame->height(), right_edge->width(),
    353                       height() - theme_frame->height());
    354   // Now fill the bottom area.
    355   canvas->FillRectInt(frame_color, left_edge->width(),
    356                       height() - bottom_edge->height(),
    357                       width() - left_edge->width() - right_edge->width(),
    358                       bottom_edge->height());
    359 
    360   // Draw the theme frame.
    361   canvas->TileImageInt(*theme_frame, 0, 0, width(), theme_frame->height());
    362 
    363   // Top.
    364   canvas->DrawBitmapInt(*top_left_corner, 0, 0);
    365   canvas->TileImageInt(*top_edge, top_left_corner->width(), 0,
    366                        width() - top_right_corner->width(), top_edge->height());
    367   canvas->DrawBitmapInt(*top_right_corner,
    368                         width() - top_right_corner->width(), 0);
    369 
    370   // Right.
    371   canvas->TileImageInt(*right_edge, width() - right_edge->width(),
    372       top_right_corner->height(), right_edge->width(),
    373       height() - top_right_corner->height() - bottom_right_corner->height());
    374 
    375   // Bottom.
    376   canvas->DrawBitmapInt(*bottom_right_corner,
    377                         width() - bottom_right_corner->width(),
    378                         height() - bottom_right_corner->height());
    379   canvas->TileImageInt(*bottom_edge, bottom_left_corner->width(),
    380       height() - bottom_edge->height(),
    381       width() - bottom_left_corner->width() - bottom_right_corner->width(),
    382       bottom_edge->height());
    383   canvas->DrawBitmapInt(*bottom_left_corner, 0,
    384                         height() - bottom_left_corner->height());
    385 
    386   // Left.
    387   canvas->TileImageInt(*left_edge, 0, top_left_corner->height(),
    388       left_edge->width(),
    389       height() - top_left_corner->height() - bottom_left_corner->height());
    390 }
    391 
    392 void AppPanelBrowserFrameView::PaintMaximizedFrameBorder(gfx::Canvas* canvas) {
    393   ResourceBundle& rb = ResourceBundle::GetSharedInstance();
    394 
    395   SkBitmap* frame_image = rb.GetBitmapNamed(IDR_FRAME_APP_PANEL);
    396   canvas->TileImageInt(*frame_image, 0, FrameBorderThickness(), width(),
    397                        frame_image->height());
    398 
    399   // The bottom of the titlebar actually comes from the top of the Client Edge
    400   // graphic, with the actual client edge clipped off the bottom.
    401   SkBitmap* titlebar_bottom = rb.GetBitmapNamed(IDR_APP_TOP_CENTER);
    402   int edge_height = titlebar_bottom->height() - kClientEdgeThickness;
    403   canvas->TileImageInt(*titlebar_bottom, 0,
    404                        frame_->GetWindow()->client_view()->y() - edge_height,
    405                        width(), edge_height);
    406 }
    407 
    408 void AppPanelBrowserFrameView::PaintTitleBar(gfx::Canvas* canvas) {
    409   // The window icon is painted by the TabIconView.
    410   views::WindowDelegate* d = frame_->GetWindow()->window_delegate();
    411   canvas->DrawStringInt(d->GetWindowTitle(), BrowserFrame::GetTitleFont(),
    412       SK_ColorBLACK, GetMirroredXForRect(title_bounds_), title_bounds_.y(),
    413       title_bounds_.width(), title_bounds_.height());
    414 }
    415 
    416 void AppPanelBrowserFrameView::PaintRestoredClientEdge(gfx::Canvas* canvas) {
    417   gfx::Rect client_area_bounds = CalculateClientAreaBounds(width(), height());
    418   int client_area_top = client_area_bounds.y();
    419 
    420   ResourceBundle& rb = ResourceBundle::GetSharedInstance();
    421   SkBitmap* top_left = rb.GetBitmapNamed(IDR_APP_TOP_LEFT);
    422   SkBitmap* top = rb.GetBitmapNamed(IDR_APP_TOP_CENTER);
    423   SkBitmap* top_right = rb.GetBitmapNamed(IDR_APP_TOP_RIGHT);
    424   SkBitmap* right = rb.GetBitmapNamed(IDR_CONTENT_RIGHT_SIDE);
    425   SkBitmap* bottom_right =
    426       rb.GetBitmapNamed(IDR_CONTENT_BOTTOM_RIGHT_CORNER);
    427   SkBitmap* bottom = rb.GetBitmapNamed(IDR_CONTENT_BOTTOM_CENTER);
    428   SkBitmap* bottom_left =
    429       rb.GetBitmapNamed(IDR_CONTENT_BOTTOM_LEFT_CORNER);
    430   SkBitmap* left = rb.GetBitmapNamed(IDR_CONTENT_LEFT_SIDE);
    431 
    432   // Top.
    433   int top_edge_y = client_area_top - top->height();
    434   canvas->DrawBitmapInt(*top_left, client_area_bounds.x() - top_left->width(),
    435                         top_edge_y);
    436   canvas->TileImageInt(*top, client_area_bounds.x(), top_edge_y,
    437                        client_area_bounds.width(), top->height());
    438   canvas->DrawBitmapInt(*top_right, client_area_bounds.right(), top_edge_y);
    439 
    440   // Right.
    441   int client_area_bottom =
    442       std::max(client_area_top, client_area_bounds.bottom());
    443   int client_area_height = client_area_bottom - client_area_top;
    444   canvas->TileImageInt(*right, client_area_bounds.right(), client_area_top,
    445                        right->width(), client_area_height);
    446 
    447   // Bottom.
    448   canvas->DrawBitmapInt(*bottom_right, client_area_bounds.right(),
    449                         client_area_bottom);
    450   canvas->TileImageInt(*bottom, client_area_bounds.x(), client_area_bottom,
    451                        client_area_bounds.width(), bottom_right->height());
    452   canvas->DrawBitmapInt(*bottom_left,
    453       client_area_bounds.x() - bottom_left->width(), client_area_bottom);
    454 
    455   // Left.
    456   canvas->TileImageInt(*left, client_area_bounds.x() - left->width(),
    457       client_area_top, left->width(), client_area_height);
    458 
    459   // Draw the toolbar color to fill in the edges.
    460   canvas->DrawRectInt(ResourceBundle::toolbar_color,
    461       client_area_bounds.x() - kClientEdgeThickness,
    462       client_area_top - kClientEdgeThickness,
    463       client_area_bounds.width() + kClientEdgeThickness,
    464       client_area_bottom - client_area_top + kClientEdgeThickness);
    465 }
    466 
    467 void AppPanelBrowserFrameView::LayoutWindowControls() {
    468   close_button_->SetImageAlignment(views::ImageButton::ALIGN_LEFT,
    469                                    views::ImageButton::ALIGN_BOTTOM);
    470   bool is_maximized = frame_->GetWindow()->IsMaximized();
    471   // There should always be the same number of non-border pixels visible to the
    472   // side of the close button.  In maximized mode we extend the button to the
    473   // screen corner to obey Fitts' Law.
    474   int right_extra_width = is_maximized ? kCloseButtonFrameBorderSpacing : 0;
    475   gfx::Size close_button_size = close_button_->GetPreferredSize();
    476   int close_button_y =
    477       (NonClientTopBorderHeight() - close_button_size.height()) / 2;
    478   int top_extra_height = is_maximized ? close_button_y : 0;
    479   close_button_->SetBounds(width() - FrameBorderThickness() -
    480       kCloseButtonFrameBorderSpacing - close_button_size.width(),
    481       close_button_y - top_extra_height,
    482       close_button_size.width() + right_extra_width,
    483       close_button_size.height() + top_extra_height);
    484 }
    485 
    486 void AppPanelBrowserFrameView::LayoutTitleBar() {
    487   // Size the icon first; the window title is based on the icon position.
    488   gfx::Rect icon_bounds(IconBounds());
    489   window_icon_->SetBoundsRect(icon_bounds);
    490 
    491   // Size the title.
    492   int title_x = icon_bounds.right() + kIconTitleSpacing;
    493   int title_height = BrowserFrame::GetTitleFont().GetHeight();
    494   // We bias the title position so that when the difference between the icon
    495   // and title heights is odd, the extra pixel of the title is above the
    496   // vertical midline rather than below.  This compensates for how the icon is
    497   // already biased downwards (see IconBounds()) and helps prevent descenders
    498   // on the title from overlapping the 3D edge at the bottom of the titlebar.
    499   title_bounds_.SetRect(title_x,
    500       icon_bounds.y() + ((icon_bounds.height() - title_height - 1) / 2),
    501       std::max(0, close_button_->x() - kTitleCloseButtonSpacing - title_x),
    502       title_height);
    503 }
    504 
    505 gfx::Rect AppPanelBrowserFrameView::CalculateClientAreaBounds(int width,
    506     int height) const {
    507   int top_height = NonClientTopBorderHeight();
    508   int border_thickness = NonClientBorderThickness();
    509   return gfx::Rect(border_thickness, top_height,
    510                    std::max(0, width - (2 * border_thickness)),
    511                    std::max(0, height - top_height - border_thickness));
    512 }
    513