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