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