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