opaque_browser_frame_view_layout.cc revision d0247b1b59f9c528cb6df88b4f2b9afaf80d181e
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/opaque_browser_frame_view_layout.h" 6 7#include "ui/gfx/font.h" 8#include "ui/views/controls/button/image_button.h" 9#include "ui/views/controls/label.h" 10 11#if defined(OS_WIN) 12#include "win8/util/win8_util.h" 13#endif // OS_WIN 14 15namespace { 16 17// Besides the frame border, there's another 9 px of empty space atop the 18// window in restored mode, to use to drag the window around. 19const int kNonClientRestoredExtraThickness = 9; 20 21// The titlebar never shrinks too short to show the caption button plus some 22// padding below it. 23const int kCaptionButtonHeightWithPadding = 19; 24 25// There is a 5 px gap between the title text and the caption buttons. 26const int kTitleLogoSpacing = 5; 27 28// The frame border is only visible in restored mode and is hardcoded to 4 px on 29// each side regardless of the system window border size. 30const int kFrameBorderThickness = 4; 31 32// The titlebar has a 2 px 3D edge along the top and bottom. 33const int kTitlebarTopAndBottomEdgeThickness = 2; 34 35// The icon is inset 2 px from the left frame border. 36const int kIconLeftSpacing = 2; 37 38// There is a 4 px gap between the icon and the title text. 39const int kIconTitleSpacing = 4; 40 41// The avatar ends 2 px above the bottom of the tabstrip (which, given the 42// way the tabstrip draws its bottom edge, will appear like a 1 px gap to the 43// user). 44const int kAvatarBottomSpacing = 2; 45 46// Space between the frame border and the left edge of the avatar. 47const int kAvatarLeftSpacing = 2; 48 49// Space between the right edge of the avatar and the tabstrip. 50const int kAvatarRightSpacing = -4; 51 52// In restored mode, the New Tab button isn't at the same height as the caption 53// buttons, but the space will look cluttered if it actually slides under them, 54// so we stop it when the gap between the two is down to 5 px. 55const int kNewTabCaptionRestoredSpacing = 5; 56 57// In maximized mode, where the New Tab button and the caption buttons are at 58// similar vertical coordinates, we need to reserve a larger, 16 px gap to avoid 59// looking too cluttered. 60const int kNewTabCaptionMaximizedSpacing = 16; 61 62// The top 3 px of the tabstrip is shadow; in maximized mode we push this off 63// the top of the screen so the tabs appear flush against the screen edge. 64const int kTabstripTopShadowThickness = 3; 65 66// How far to indent the tabstrip from the left side of the screen when there 67// is no avatar icon. 68const int kTabStripIndent = -6; 69 70#if defined(OS_LINUX) && !defined(OS_CHROMEOS) 71// Default extra space between the top of the frame and the top of the window 72// caption buttons. 73const int kExtraCaption = 2; 74 75// Default extra spacing between individual window caption buttons. 76const int kCaptionButtonSpacing = 2; 77#else 78const int kExtraCaption = 0; 79const int kCaptionButtonSpacing = 0; 80#endif 81 82} // namespace 83 84/////////////////////////////////////////////////////////////////////////////// 85// OpaqueBrowserFrameView, public: 86 87OpaqueBrowserFrameViewLayout::OpaqueBrowserFrameViewLayout( 88 OpaqueBrowserFrameViewLayoutDelegate* delegate) 89 : delegate_(delegate), 90 leading_button_start_(0), 91 trailing_button_start_(0), 92 minimum_size_for_buttons_(0), 93 has_leading_buttons_(false), 94 has_trailing_buttons_(false), 95 extra_caption_y_(kExtraCaption), 96 window_caption_spacing_(kCaptionButtonSpacing), 97 minimize_button_(NULL), 98 maximize_button_(NULL), 99 restore_button_(NULL), 100 close_button_(NULL), 101 window_icon_(NULL), 102 window_title_(NULL), 103 avatar_label_(NULL), 104 avatar_button_(NULL) { 105 trailing_buttons_.push_back(views::FRAME_BUTTON_MINIMIZE); 106 trailing_buttons_.push_back(views::FRAME_BUTTON_MAXIMIZE); 107 trailing_buttons_.push_back(views::FRAME_BUTTON_CLOSE); 108} 109 110OpaqueBrowserFrameViewLayout::~OpaqueBrowserFrameViewLayout() {} 111 112// static 113bool OpaqueBrowserFrameViewLayout::ShouldAddDefaultCaptionButtons() { 114#if defined(OS_WIN) 115 return !win8::IsSingleWindowMetroMode(); 116#endif // OS_WIN 117 return true; 118} 119 120void OpaqueBrowserFrameViewLayout::SetButtonOrdering( 121 const std::vector<views::FrameButton>& leading_buttons, 122 const std::vector<views::FrameButton>& trailing_buttons) { 123 leading_buttons_ = leading_buttons; 124 trailing_buttons_ = trailing_buttons; 125} 126 127gfx::Rect OpaqueBrowserFrameViewLayout::GetBoundsForTabStrip( 128 const gfx::Size& tabstrip_preferred_size, 129 int available_width) const { 130 available_width -= trailing_button_start_; 131 available_width -= leading_button_start_; 132 133 if (delegate_->GetAdditionalReservedSpaceInTabStrip()) 134 available_width -= delegate_->GetAdditionalReservedSpaceInTabStrip(); 135 136 const int caption_spacing = delegate_->IsMaximized() ? 137 kNewTabCaptionMaximizedSpacing : kNewTabCaptionRestoredSpacing; 138 const int tabstrip_width = available_width - caption_spacing; 139 gfx::Rect bounds(leading_button_start_, GetTabStripInsetsTop(false), 140 std::max(0, tabstrip_width), 141 tabstrip_preferred_size.height()); 142 143 int leading_tabstrip_indent = kTabStripIndent; 144 if (delegate_->ShouldShowAvatar()) { 145 if (avatar_label_ && avatar_label_->bounds().width()) { 146 // Space between the trailing edge of the avatar label and the tabstrip. 147 const int kAvatarLabelRightSpacing = -10; 148 leading_tabstrip_indent -= kAvatarLabelRightSpacing; 149 } else { 150 leading_tabstrip_indent -= kAvatarRightSpacing; 151 } 152 } 153 bounds.Inset(leading_tabstrip_indent, 0, 0, 0); 154 return bounds; 155} 156 157gfx::Size OpaqueBrowserFrameViewLayout::GetMinimumSize( 158 int available_width) const { 159 gfx::Size min_size = delegate_->GetBrowserViewMinimumSize(); 160 int border_thickness = NonClientBorderThickness(); 161 min_size.Enlarge(2 * border_thickness, 162 NonClientTopBorderHeight(false) + border_thickness); 163 164 // Ensure that we can, at minimum, hold our window controls and avatar icon. 165 min_size.set_width(std::max(min_size.width(), minimum_size_for_buttons_)); 166 167 // Ensure that the minimum width is enough to hold a minimum width tab strip 168 // at its usual insets. 169 if (delegate_->IsTabStripVisible()) { 170 gfx::Size preferred_size = delegate_->GetTabstripPreferredSize(); 171 const int min_tabstrip_width = preferred_size.width(); 172 const int caption_spacing = delegate_->IsMaximized() ? 173 kNewTabCaptionMaximizedSpacing : kNewTabCaptionRestoredSpacing; 174 min_size.Enlarge(min_tabstrip_width + caption_spacing, 0); 175 } 176 177 return min_size; 178} 179 180gfx::Rect OpaqueBrowserFrameViewLayout::GetWindowBoundsForClientBounds( 181 const gfx::Rect& client_bounds) const { 182 int top_height = NonClientTopBorderHeight(false); 183 int border_thickness = NonClientBorderThickness(); 184 return gfx::Rect(std::max(0, client_bounds.x() - border_thickness), 185 std::max(0, client_bounds.y() - top_height), 186 client_bounds.width() + (2 * border_thickness), 187 client_bounds.height() + top_height + border_thickness); 188} 189 190int OpaqueBrowserFrameViewLayout::FrameBorderThickness(bool restored) const { 191 return (!restored && (delegate_->IsMaximized() || 192 delegate_->IsFullscreen())) ? 193 0 : kFrameBorderThickness; 194} 195 196int OpaqueBrowserFrameViewLayout::NonClientBorderThickness() const { 197 // When we fill the screen, we don't show a client edge. 198 return FrameBorderThickness(false) + 199 ((delegate_->IsMaximized() || delegate_->IsFullscreen()) ? 200 0 : views::NonClientFrameView::kClientEdgeThickness); 201} 202 203int OpaqueBrowserFrameViewLayout::NonClientTopBorderHeight( 204 bool restored) const { 205 if (delegate_->ShouldShowWindowTitle()) { 206 return std::max(FrameBorderThickness(restored) + delegate_->GetIconSize(), 207 CaptionButtonY(restored) + kCaptionButtonHeightWithPadding) + 208 TitlebarBottomThickness(restored); 209 } 210 211 return FrameBorderThickness(restored) - 212 ((delegate_->IsTabStripVisible() && 213 !restored && !delegate_->ShouldLeaveOffsetNearTopBorder()) 214 ? kTabstripTopShadowThickness : 0); 215} 216 217int OpaqueBrowserFrameViewLayout::GetTabStripInsetsTop(bool restored) const { 218 return NonClientTopBorderHeight(restored) + ((!restored && 219 (!delegate_->ShouldLeaveOffsetNearTopBorder() || 220 delegate_->IsFullscreen())) ? 221 0 : kNonClientRestoredExtraThickness); 222} 223 224int OpaqueBrowserFrameViewLayout::TitlebarBottomThickness(bool restored) const { 225 return kTitlebarTopAndBottomEdgeThickness + 226 ((!restored && delegate_->IsMaximized()) ? 0 : 227 views::NonClientFrameView::kClientEdgeThickness); 228} 229 230int OpaqueBrowserFrameViewLayout::CaptionButtonY(bool restored) const { 231 // Maximized buttons start at window top so that even if their images aren't 232 // drawn flush with the screen edge, they still obey Fitts' Law. 233 return ((!restored && delegate_->IsMaximized()) ? 234 FrameBorderThickness(false) : 235 views::NonClientFrameView::kFrameShadowThickness) + extra_caption_y_; 236} 237 238gfx::Rect OpaqueBrowserFrameViewLayout::IconBounds() const { 239 return window_icon_bounds_; 240} 241 242gfx::Rect OpaqueBrowserFrameViewLayout::CalculateClientAreaBounds( 243 int width, 244 int height) const { 245 int top_height = NonClientTopBorderHeight(false); 246 int border_thickness = NonClientBorderThickness(); 247 return gfx::Rect(border_thickness, top_height, 248 std::max(0, width - (2 * border_thickness)), 249 std::max(0, height - top_height - border_thickness)); 250} 251 252/////////////////////////////////////////////////////////////////////////////// 253// OpaqueBrowserFrameView, private: 254 255void OpaqueBrowserFrameViewLayout::LayoutWindowControls(views::View* host) { 256 if (!ShouldAddDefaultCaptionButtons()) 257 return; 258 259 int caption_y = CaptionButtonY(false); 260 261 // Keep a list of all buttons that we don't show. 262 std::vector<views::FrameButton> buttons_not_shown; 263 buttons_not_shown.push_back(views::FRAME_BUTTON_MAXIMIZE); 264 buttons_not_shown.push_back(views::FRAME_BUTTON_MINIMIZE); 265 buttons_not_shown.push_back(views::FRAME_BUTTON_CLOSE); 266 267 for (std::vector<views::FrameButton>::const_iterator it = 268 leading_buttons_.begin(); it != leading_buttons_.end(); ++it) { 269 ConfigureButton(host, *it, ALIGN_LEADING, caption_y); 270 buttons_not_shown.erase( 271 std::remove(buttons_not_shown.begin(), buttons_not_shown.end(), *it), 272 buttons_not_shown.end()); 273 } 274 275 for (std::vector<views::FrameButton>::const_reverse_iterator it = 276 trailing_buttons_.rbegin(); it != trailing_buttons_.rend(); ++it) { 277 ConfigureButton(host, *it, ALIGN_TRAILING, caption_y); 278 buttons_not_shown.erase( 279 std::remove(buttons_not_shown.begin(), buttons_not_shown.end(), *it), 280 buttons_not_shown.end()); 281 } 282 283 for (std::vector<views::FrameButton>::const_iterator it = 284 buttons_not_shown.begin(); it != buttons_not_shown.end(); ++it) { 285 HideButton(*it); 286 } 287} 288 289void OpaqueBrowserFrameViewLayout::LayoutTitleBar(views::View* host) { 290 bool use_hidden_icon_location = true; 291 292 int size = delegate_->GetIconSize(); 293 int frame_thickness = FrameBorderThickness(false); 294 bool should_show_icon = delegate_->ShouldShowWindowIcon(); 295 bool should_show_title = delegate_->ShouldShowWindowTitle(); 296 297 if (should_show_icon || should_show_title) { 298 use_hidden_icon_location = false; 299 300 // Our frame border has a different "3D look" than Windows'. Theirs has 301 // a more complex gradient on the top that they push their icon/title 302 // below; then the maximized window cuts this off and the icon/title are 303 // centered in the remaining space. Because the apparent shape of our 304 // border is simpler, using the same positioning makes things look 305 // slightly uncentered with restored windows, so when the window is 306 // restored, instead of calculating the remaining space from below the 307 // frame border, we calculate from below the 3D edge. 308 int unavailable_px_at_top = delegate_->IsMaximized() ? 309 frame_thickness : kTitlebarTopAndBottomEdgeThickness; 310 // When the icon is shorter than the minimum space we reserve for the 311 // caption button, we vertically center it. We want to bias rounding to 312 // put extra space above the icon, since the 3D edge (+ client edge, for 313 // restored windows) below looks (to the eye) more like additional space 314 // than does the 3D edge (or nothing at all, for maximized windows) 315 // above; hence the +1. 316 int y = unavailable_px_at_top + (NonClientTopBorderHeight(false) - 317 unavailable_px_at_top - size - 318 TitlebarBottomThickness(false) + 1) / 2; 319 320 window_icon_bounds_ = gfx::Rect(leading_button_start_ + kIconLeftSpacing, y, 321 size, size); 322 leading_button_start_ += size + kIconLeftSpacing; 323 minimum_size_for_buttons_ += size + kIconLeftSpacing; 324 } 325 326 if (should_show_icon) 327 window_icon_->SetBoundsRect(window_icon_bounds_); 328 329 if (window_title_) { 330 window_title_->SetVisible(should_show_title); 331 if (should_show_title) { 332 window_title_->SetText(delegate_->GetWindowTitle()); 333 334 int text_width = std::max( 335 0, host->width() - trailing_button_start_ - kTitleLogoSpacing - 336 leading_button_start_ - kIconTitleSpacing); 337 window_title_->SetBounds(leading_button_start_ + kIconTitleSpacing, 338 window_icon_bounds_.y(), 339 text_width, window_icon_bounds_.height()); 340 leading_button_start_ += text_width + kIconTitleSpacing; 341 } 342 } 343 344 if (use_hidden_icon_location) { 345 if (has_leading_buttons_) { 346 // There are window button icons on the left. Don't size the hidden window 347 // icon that people can double click on to close the window. 348 window_icon_bounds_ = gfx::Rect(); 349 } else { 350 // We set the icon bounds to a small rectangle in the top leading corner 351 // if there are no icons on the leading side. 352 window_icon_bounds_ = gfx::Rect( 353 frame_thickness + kIconLeftSpacing, frame_thickness, size, size); 354 } 355 } 356} 357 358void OpaqueBrowserFrameViewLayout::LayoutAvatar() { 359 // Even though the avatar is used for both incognito and profiles we always 360 // use the incognito icon to layout the avatar button. The profile icon 361 // can be customized so we can't depend on its size to perform layout. 362 gfx::ImageSkia incognito_icon = delegate_->GetOTRAvatarIcon(); 363 364 int avatar_bottom = GetTabStripInsetsTop(false) + 365 delegate_->GetTabStripHeight() - kAvatarBottomSpacing; 366 int avatar_restored_y = avatar_bottom - incognito_icon.height(); 367 int avatar_y = delegate_->IsMaximized() ? 368 (NonClientTopBorderHeight(false) + kTabstripTopShadowThickness) : 369 avatar_restored_y; 370 avatar_bounds_.SetRect(leading_button_start_ + kAvatarLeftSpacing, 371 avatar_y, incognito_icon.width(), 372 delegate_->ShouldShowAvatar() ? (avatar_bottom - avatar_y) : 0); 373 if (avatar_button_) { 374 avatar_button_->SetBoundsRect(avatar_bounds_); 375 376 if (avatar_label_) { 377 // Space between the bottom of the avatar and the bottom of the avatar 378 // label. 379 const int kAvatarLabelBottomSpacing = 3; 380 gfx::Size label_size = avatar_label_->GetPreferredSize(); 381 // The x-position of the avatar label should be slightly to the left of 382 // the avatar menu button. Therefore we use the |leading_button_start_| 383 // value directly. 384 gfx::Rect label_bounds( 385 leading_button_start_, 386 avatar_bottom - kAvatarLabelBottomSpacing - label_size.height(), 387 label_size.width(), 388 delegate_->ShouldShowAvatar() ? label_size.height() : 0); 389 avatar_label_->SetBoundsRect(label_bounds); 390 leading_button_start_ += label_size.width(); 391 } else { 392 leading_button_start_ += kAvatarLeftSpacing + incognito_icon.width(); 393 } 394 395 // We just add the avatar button size to the minimum size because clicking 396 // the avatar label does the same thing as clicking the avatar button. 397 minimum_size_for_buttons_ += kAvatarLeftSpacing + incognito_icon.width(); 398 } 399} 400 401void OpaqueBrowserFrameViewLayout::ConfigureButton( 402 views::View* host, 403 views::FrameButton button_id, 404 ButtonAlignment alignment, 405 int caption_y) { 406 switch (button_id) { 407 case views::FRAME_BUTTON_MINIMIZE: { 408 minimize_button_->SetVisible(true); 409 SetBoundsForButton(host, minimize_button_, alignment, caption_y); 410 break; 411 } 412 case views::FRAME_BUTTON_MAXIMIZE: { 413 // When the window is restored, we show a maximized button; otherwise, we 414 // show a restore button. 415 bool is_restored = !delegate_->IsMaximized() && !delegate_->IsMinimized(); 416 views::ImageButton* invisible_button = is_restored ? 417 restore_button_ : maximize_button_; 418 invisible_button->SetVisible(false); 419 420 views::ImageButton* visible_button = is_restored ? 421 maximize_button_ : restore_button_; 422 visible_button->SetVisible(true); 423 SetBoundsForButton(host, visible_button, alignment, caption_y); 424 break; 425 } 426 case views::FRAME_BUTTON_CLOSE: { 427 close_button_->SetVisible(true); 428 SetBoundsForButton(host, close_button_, alignment, caption_y); 429 break; 430 } 431 } 432} 433 434void OpaqueBrowserFrameViewLayout::HideButton(views::FrameButton button_id) { 435 switch (button_id) { 436 case views::FRAME_BUTTON_MINIMIZE: 437 minimize_button_->SetVisible(false); 438 break; 439 case views::FRAME_BUTTON_MAXIMIZE: 440 restore_button_->SetVisible(false); 441 maximize_button_->SetVisible(false); 442 break; 443 case views::FRAME_BUTTON_CLOSE: 444 close_button_->SetVisible(false); 445 break; 446 } 447} 448 449void OpaqueBrowserFrameViewLayout::SetBoundsForButton( 450 views::View* host, 451 views::ImageButton* button, 452 ButtonAlignment alignment, 453 int caption_y) { 454 gfx::Size button_size = button->GetPreferredSize(); 455 456 button->SetImageAlignment( 457 (alignment == ALIGN_LEADING) ? 458 views::ImageButton::ALIGN_RIGHT : views::ImageButton::ALIGN_LEFT, 459 views::ImageButton::ALIGN_BOTTOM); 460 461 // There should always be the same number of non-shadow pixels visible to the 462 // side of the caption buttons. In maximized mode we extend the rightmost 463 // button to the screen corner to obey Fitts' Law. 464 bool is_maximized = delegate_->IsMaximized(); 465 466 switch (alignment) { 467 case ALIGN_LEADING: { 468 if (has_leading_buttons_) 469 leading_button_start_ += window_caption_spacing_; 470 471 // If we're the first button on the left and maximized, add with to the 472 // right hand side of the screen. 473 int extra_width = (is_maximized && !has_leading_buttons_) ? 474 (kFrameBorderThickness - 475 views::NonClientFrameView::kFrameShadowThickness) : 0; 476 477 button->SetBounds( 478 leading_button_start_ - extra_width, 479 caption_y, 480 button_size.width() + extra_width, 481 button_size.height()); 482 483 leading_button_start_ += extra_width + button_size.width(); 484 minimum_size_for_buttons_ += extra_width + button_size.width(); 485 has_leading_buttons_ = true; 486 break; 487 } 488 case ALIGN_TRAILING: { 489 if (has_trailing_buttons_) 490 trailing_button_start_ += window_caption_spacing_; 491 492 // If we're the first button on the right and maximized, add with to the 493 // right hand side of the screen. 494 int extra_width = (is_maximized && !has_trailing_buttons_) ? 495 (kFrameBorderThickness - 496 views::NonClientFrameView::kFrameShadowThickness) : 0; 497 498 button->SetBounds( 499 host->width() - trailing_button_start_ - extra_width - 500 button_size.width(), 501 caption_y, 502 button_size.width() + extra_width, 503 button_size.height()); 504 505 trailing_button_start_ += extra_width + button_size.width(); 506 minimum_size_for_buttons_ += extra_width + button_size.width(); 507 has_trailing_buttons_ = true; 508 break; 509 } 510 } 511} 512 513void OpaqueBrowserFrameViewLayout::SetView(int id, views::View* view) { 514 // Why do things this way instead of having an Init() method, where we're 515 // passed the views we'll handle? Because OpaqueBrowserFrameView doesn't own 516 // all the views which are part of it. The avatar stuff, for example, will be 517 // added and removed by the base class of OpaqueBrowserFrameView. 518 switch (id) { 519 case VIEW_ID_MINIMIZE_BUTTON: 520 if (view) { 521 DCHECK_EQ(std::string(views::ImageButton::kViewClassName), 522 view->GetClassName()); 523 } 524 minimize_button_ = static_cast<views::ImageButton*>(view); 525 break; 526 case VIEW_ID_MAXIMIZE_BUTTON: 527 if (view) { 528 DCHECK_EQ(std::string(views::ImageButton::kViewClassName), 529 view->GetClassName()); 530 } 531 maximize_button_ = static_cast<views::ImageButton*>(view); 532 break; 533 case VIEW_ID_RESTORE_BUTTON: 534 if (view) { 535 DCHECK_EQ(std::string(views::ImageButton::kViewClassName), 536 view->GetClassName()); 537 } 538 restore_button_ = static_cast<views::ImageButton*>(view); 539 break; 540 case VIEW_ID_CLOSE_BUTTON: 541 if (view) { 542 DCHECK_EQ(std::string(views::ImageButton::kViewClassName), 543 view->GetClassName()); 544 } 545 close_button_ = static_cast<views::ImageButton*>(view); 546 break; 547 case VIEW_ID_WINDOW_ICON: 548 window_icon_ = view; 549 break; 550 case VIEW_ID_WINDOW_TITLE: 551 if (view) { 552 DCHECK_EQ(std::string(views::Label::kViewClassName), 553 view->GetClassName()); 554 } 555 window_title_ = static_cast<views::Label*>(view); 556 break; 557 case VIEW_ID_AVATAR_LABEL: 558 avatar_label_ = view; 559 break; 560 case VIEW_ID_AVATAR_BUTTON: 561 avatar_button_ = view; 562 break; 563 default: 564 NOTIMPLEMENTED() << "Unknown view id " << id; 565 break; 566 } 567} 568 569/////////////////////////////////////////////////////////////////////////////// 570// OpaqueBrowserFrameView, views::LayoutManager: 571 572void OpaqueBrowserFrameViewLayout::Layout(views::View* host) { 573 // Reset all our data so that everything is invisible. 574 int thickness = FrameBorderThickness(false); 575 leading_button_start_ = thickness; 576 trailing_button_start_ = thickness; 577 minimum_size_for_buttons_ = leading_button_start_ + trailing_button_start_; 578 has_leading_buttons_ = false; 579 has_trailing_buttons_ = false; 580 581 LayoutWindowControls(host); 582 LayoutTitleBar(host); 583 584 // We now add a single pixel to the leading spacing. We do this because the 585 // avatar and tab strip start one pixel inward compared to where things start 586 // on the trailing side. 587 leading_button_start_++; 588 589 LayoutAvatar(); 590 591 client_view_bounds_ = CalculateClientAreaBounds( 592 host->width(), host->height()); 593} 594 595gfx::Size OpaqueBrowserFrameViewLayout::GetPreferredSize(views::View* host) { 596 // This is never used; NonClientView::GetPreferredSize() will be called 597 // instead. 598 NOTREACHED(); 599 return gfx::Size(); 600} 601 602void OpaqueBrowserFrameViewLayout::ViewAdded(views::View* host, 603 views::View* view) { 604 SetView(view->id(), view); 605} 606 607void OpaqueBrowserFrameViewLayout::ViewRemoved(views::View* host, 608 views::View* view) { 609 SetView(view->id(), NULL); 610} 611