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