Add ENABLE_MEDIA_ROUTER define to builds other than Android and iOS.
[chromium-blink-merge.git] / chrome / browser / ui / views / frame / browser_non_client_frame_view_ash.cc
blob9e8e7767093061951305bb0639b06deb814b4b71
1 // Copyright 2012 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.
5 #include "chrome/browser/ui/views/frame/browser_non_client_frame_view_ash.h"
7 #include <algorithm>
9 #include "ash/frame/caption_buttons/frame_caption_button_container_view.h"
10 #include "ash/frame/default_header_painter.h"
11 #include "ash/frame/frame_border_hit_test_controller.h"
12 #include "ash/frame/header_painter_util.h"
13 #include "ash/shell.h"
14 #include "base/profiler/scoped_tracker.h"
15 #include "chrome/app/chrome_command_ids.h"
16 #include "chrome/browser/extensions/extension_util.h"
17 #include "chrome/browser/profiles/profiles_state.h"
18 #include "chrome/browser/themes/theme_properties.h"
19 #include "chrome/browser/ui/browser.h"
20 #include "chrome/browser/ui/browser_commands.h"
21 #include "chrome/browser/ui/views/frame/browser_frame.h"
22 #include "chrome/browser/ui/views/frame/browser_header_painter_ash.h"
23 #include "chrome/browser/ui/views/frame/browser_view.h"
24 #include "chrome/browser/ui/views/frame/immersive_mode_controller.h"
25 #include "chrome/browser/ui/views/frame/web_app_left_header_view_ash.h"
26 #include "chrome/browser/ui/views/profiles/avatar_menu_button.h"
27 #include "chrome/browser/ui/views/tab_icon_view.h"
28 #include "chrome/browser/ui/views/tabs/tab_strip.h"
29 #include "chrome/browser/web_applications/web_app.h"
30 #include "components/signin/core/common/profile_management_switches.h"
31 #include "content/public/browser/web_contents.h"
32 #include "extensions/browser/extension_registry.h"
33 #include "grit/theme_resources.h"
34 #include "ui/accessibility/ax_view_state.h"
35 #include "ui/aura/client/aura_constants.h"
36 #include "ui/aura/window.h"
37 #include "ui/base/hit_test.h"
38 #include "ui/base/layout.h"
39 #include "ui/base/resource/resource_bundle.h"
40 #include "ui/base/theme_provider.h"
41 #include "ui/compositor/layer_animator.h"
42 #include "ui/gfx/canvas.h"
43 #include "ui/gfx/geometry/rect_conversions.h"
44 #include "ui/gfx/image/image_skia.h"
45 #include "ui/views/controls/label.h"
46 #include "ui/views/layout/layout_constants.h"
47 #include "ui/views/widget/widget.h"
48 #include "ui/views/widget/widget_delegate.h"
50 #if defined(ENABLE_SUPERVISED_USERS)
51 #include "chrome/browser/ui/views/profiles/supervised_user_avatar_label.h"
52 #endif
54 namespace {
56 // The avatar ends 2 px above the bottom of the tabstrip (which, given the
57 // way the tabstrip draws its bottom edge, will appear like a 1 px gap to the
58 // user).
59 const int kAvatarBottomSpacing = 2;
60 // There are 2 px on each side of the avatar (between the frame border and
61 // it on the left, and between it and the tabstrip on the right).
62 const int kAvatarSideSpacing = 2;
63 // Space between the new avatar button and the minimize button.
64 const int kNewAvatarButtonOffset = 5;
65 // Space between left edge of window and tabstrip.
66 const int kTabstripLeftSpacing = 0;
67 // Space between right edge of tabstrip and maximize button.
68 const int kTabstripRightSpacing = 10;
69 // Height of the shadow of the content area, at the top of the toolbar.
70 const int kContentShadowHeight = 1;
71 // Space between top of window and top of tabstrip for tall headers, such as
72 // for restored windows, apps, etc.
73 const int kTabstripTopSpacingTall = 7;
74 // Space between top of window and top of tabstrip for short headers, such as
75 // for maximized windows, pop-ups, etc.
76 const int kTabstripTopSpacingShort = 0;
77 // Height of the shadow in the tab image, used to ensure clicks in the shadow
78 // area still drag restored windows. This keeps the clickable area large enough
79 // to hit easily.
80 const int kTabShadowHeight = 4;
82 // Combines View::ConvertPointToTarget() and View::HitTest() for a given
83 // |point|. Converts |point| from |src| to |dst| and hit tests it against |dst|.
84 bool ConvertedHitTest(views::View* src,
85 views::View* dst,
86 const gfx::Point& point) {
87 DCHECK(src);
88 DCHECK(dst);
89 gfx::Point converted_point(point);
90 views::View::ConvertPointToTarget(src, dst, &converted_point);
91 return dst->HitTestPoint(converted_point);
94 } // namespace
96 ///////////////////////////////////////////////////////////////////////////////
97 // BrowserNonClientFrameViewAsh, public:
99 // static
100 const char BrowserNonClientFrameViewAsh::kViewClassName[] =
101 "BrowserNonClientFrameViewAsh";
103 BrowserNonClientFrameViewAsh::BrowserNonClientFrameViewAsh(
104 BrowserFrame* frame,
105 BrowserView* browser_view)
106 : BrowserNonClientFrameView(frame, browser_view),
107 caption_button_container_(nullptr),
108 web_app_left_header_view_(nullptr),
109 window_icon_(nullptr),
110 frame_border_hit_test_controller_(
111 new ash::FrameBorderHitTestController(frame)) {
112 ash::Shell::GetInstance()->AddShellObserver(this);
115 BrowserNonClientFrameViewAsh::~BrowserNonClientFrameViewAsh() {
116 ash::Shell::GetInstance()->RemoveShellObserver(this);
119 void BrowserNonClientFrameViewAsh::Init() {
120 caption_button_container_ = new ash::FrameCaptionButtonContainerView(frame());
121 caption_button_container_->UpdateSizeButtonVisibility();
122 AddChildView(caption_button_container_);
124 // Initializing the TabIconView is expensive, so only do it if we need to.
125 if (browser_view()->ShouldShowWindowIcon()) {
126 window_icon_ = new TabIconView(this, nullptr);
127 window_icon_->set_is_light(true);
128 AddChildView(window_icon_);
129 window_icon_->Update();
132 UpdateAvatar();
134 // HeaderPainter handles layout.
135 if (UsePackagedAppHeaderStyle()) {
136 ash::DefaultHeaderPainter* header_painter = new ash::DefaultHeaderPainter;
137 header_painter_.reset(header_painter);
138 header_painter->Init(frame(), this, caption_button_container_);
139 if (window_icon_) {
140 header_painter->UpdateLeftHeaderView(window_icon_);
142 } else if (UseWebAppHeaderStyle()) {
143 web_app_left_header_view_ = new WebAppLeftHeaderView(browser_view());
144 AddChildView(web_app_left_header_view_);
146 ash::DefaultHeaderPainter* header_painter = new ash::DefaultHeaderPainter;
147 header_painter_.reset(header_painter);
148 header_painter->Init(frame(), this, caption_button_container_);
149 header_painter->UpdateLeftHeaderView(web_app_left_header_view_);
150 } else {
151 BrowserHeaderPainterAsh* header_painter = new BrowserHeaderPainterAsh;
152 header_painter_.reset(header_painter);
153 header_painter->Init(frame(), browser_view(), this, window_icon_,
154 caption_button_container_);
158 ///////////////////////////////////////////////////////////////////////////////
159 // BrowserNonClientFrameView:
161 gfx::Rect BrowserNonClientFrameViewAsh::GetBoundsForTabStrip(
162 views::View* tabstrip) const {
163 if (!tabstrip)
164 return gfx::Rect();
166 // When the tab strip is painted in the immersive fullscreen light bar style,
167 // the caption buttons and the avatar button are not visible. However, their
168 // bounds are still used to compute the tab strip bounds so that the tabs have
169 // the same horizontal position when the tab strip is painted in the immersive
170 // light bar style as when the top-of-window views are revealed.
171 int left_inset = GetTabStripLeftInset();
172 int right_inset = GetTabStripRightInset();
173 return gfx::Rect(left_inset,
174 GetTopInset(),
175 std::max(0, width() - left_inset - right_inset),
176 tabstrip->GetPreferredSize().height());
179 int BrowserNonClientFrameViewAsh::GetTopInset() const {
180 if (!ShouldPaint() || UseImmersiveLightbarHeaderStyle())
181 return 0;
183 if (browser_view()->IsTabStripVisible()) {
184 if (frame()->IsMaximized() || frame()->IsFullscreen())
185 return kTabstripTopSpacingShort;
186 else
187 return kTabstripTopSpacingTall;
190 if (UsePackagedAppHeaderStyle() || UseWebAppHeaderStyle())
191 return header_painter_->GetHeaderHeightForPainting();
193 int caption_buttons_bottom = caption_button_container_->bounds().bottom();
195 // The toolbar partially overlaps the caption buttons.
196 if (browser_view()->IsToolbarVisible())
197 return caption_buttons_bottom - kContentShadowHeight;
199 return caption_buttons_bottom + kClientEdgeThickness;
202 int BrowserNonClientFrameViewAsh::GetThemeBackgroundXInset() const {
203 return ash::HeaderPainterUtil::GetThemeBackgroundXInset();
206 void BrowserNonClientFrameViewAsh::UpdateThrobber(bool running) {
207 // TODO(robliao): Remove ScopedTracker below once crbug.com/461137 is fixed.
208 tracked_objects::ScopedTracker tracking_profile(
209 FROM_HERE_WITH_EXPLICIT_FUNCTION(
210 "461137 BrowserNonClientFrameViewAsh::UpdateThrobber"));
212 if (window_icon_)
213 window_icon_->Update();
216 void BrowserNonClientFrameViewAsh::UpdateToolbar() {
217 if (web_app_left_header_view_)
218 web_app_left_header_view_->Update();
221 views::View* BrowserNonClientFrameViewAsh::GetLocationIconView() const {
222 if (web_app_left_header_view_)
223 return web_app_left_header_view_->GetLocationIconView();
225 return nullptr;
228 ///////////////////////////////////////////////////////////////////////////////
229 // views::NonClientFrameView:
231 gfx::Rect BrowserNonClientFrameViewAsh::GetBoundsForClientView() const {
232 // The ClientView must be flush with the top edge of the widget so that the
233 // web contents can take up the entire screen in immersive fullscreen (with
234 // or without the top-of-window views revealed). When in immersive fullscreen
235 // and the top-of-window views are revealed, the TopContainerView paints the
236 // window header by redirecting paints from its background to
237 // BrowserNonClientFrameViewAsh.
238 return bounds();
241 gfx::Rect BrowserNonClientFrameViewAsh::GetWindowBoundsForClientBounds(
242 const gfx::Rect& client_bounds) const {
243 return client_bounds;
246 int BrowserNonClientFrameViewAsh::NonClientHitTest(const gfx::Point& point) {
247 int hit_test = ash::FrameBorderHitTestController::NonClientHitTest(this,
248 caption_button_container_, point);
250 // See if the point is actually within either of the avatar menu buttons.
251 if (hit_test == HTCAPTION && avatar_button() &&
252 ConvertedHitTest(this, avatar_button(), point)) {
253 #if defined(OS_CHROMEOS)
254 // In ChromeOS, a browser window which has an avatar badging on the top
255 // left corner means it's a teleported browser window. We should treat the
256 // avatar as part of the browser non client frame (e.g., clicking on it
257 // allows the user to drag the browser window around.)
258 return HTCAPTION;
259 #else
260 return HTCLIENT;
261 #endif
264 if (hit_test == HTCAPTION && new_avatar_button() &&
265 ConvertedHitTest(this, new_avatar_button(), point)) {
266 return HTCLIENT;
269 // See if the point is actually within the web app back button.
270 if (hit_test == HTCAPTION && web_app_left_header_view_ &&
271 ConvertedHitTest(this, web_app_left_header_view_, point)) {
272 return HTCLIENT;
275 #if defined(ENABLE_SUPERVISED_USERS)
276 // ...or within the avatar label, if it's a supervised user.
277 if (hit_test == HTCAPTION && supervised_user_avatar_label() &&
278 ConvertedHitTest(this, supervised_user_avatar_label(), point)) {
279 return HTCLIENT;
281 #endif
283 // When the window is restored we want a large click target above the tabs
284 // to drag the window, so redirect clicks in the tab's shadow to caption.
285 if (hit_test == HTCLIENT &&
286 !(frame()->IsMaximized() || frame()->IsFullscreen())) {
287 // Convert point to client coordinates.
288 gfx::Point client_point(point);
289 View::ConvertPointToTarget(this, frame()->client_view(), &client_point);
290 // Report hits in shadow at top of tabstrip as caption.
291 gfx::Rect tabstrip_bounds(browser_view()->tabstrip()->bounds());
292 if (client_point.y() < tabstrip_bounds.y() + kTabShadowHeight)
293 hit_test = HTCAPTION;
295 return hit_test;
298 void BrowserNonClientFrameViewAsh::GetWindowMask(const gfx::Size& size,
299 gfx::Path* window_mask) {
300 // Aura does not use window masks.
303 void BrowserNonClientFrameViewAsh::ResetWindowControls() {
304 // Hide the caption buttons in immersive fullscreen when the tab light bar
305 // is visible because it's confusing when the user hovers or clicks in the
306 // top-right of the screen and hits one.
307 bool button_visibility = !UseImmersiveLightbarHeaderStyle();
308 caption_button_container_->SetVisible(button_visibility);
310 caption_button_container_->ResetWindowControls();
313 void BrowserNonClientFrameViewAsh::UpdateWindowIcon() {
314 if (window_icon_)
315 window_icon_->SchedulePaint();
318 void BrowserNonClientFrameViewAsh::UpdateWindowTitle() {
319 if (!frame()->IsFullscreen())
320 header_painter_->SchedulePaintForTitle();
323 void BrowserNonClientFrameViewAsh::SizeConstraintsChanged() {
326 ///////////////////////////////////////////////////////////////////////////////
327 // views::View:
329 void BrowserNonClientFrameViewAsh::OnPaint(gfx::Canvas* canvas) {
330 if (!ShouldPaint())
331 return;
333 if (UseImmersiveLightbarHeaderStyle()) {
334 PaintImmersiveLightbarStyleHeader(canvas);
335 return;
338 caption_button_container_->SetPaintAsActive(ShouldPaintAsActive());
339 if (web_app_left_header_view_)
340 web_app_left_header_view_->SetPaintAsActive(ShouldPaintAsActive());
342 ash::HeaderPainter::Mode header_mode = ShouldPaintAsActive() ?
343 ash::HeaderPainter::MODE_ACTIVE : ash::HeaderPainter::MODE_INACTIVE;
344 header_painter_->PaintHeader(canvas, header_mode);
345 if (browser_view()->IsToolbarVisible())
346 PaintToolbarBackground(canvas);
347 else if (!UsePackagedAppHeaderStyle() && !UseWebAppHeaderStyle())
348 PaintContentEdge(canvas);
351 void BrowserNonClientFrameViewAsh::Layout() {
352 // The header must be laid out before computing |painted_height| because the
353 // computation of |painted_height| for app and popup windows depends on the
354 // position of the window controls.
355 header_painter_->LayoutHeader();
357 int painted_height = 0;
358 if (browser_view()->IsTabStripVisible()) {
359 painted_height = GetTopInset() +
360 browser_view()->tabstrip()->GetPreferredSize().height();
361 } else if (browser_view()->IsToolbarVisible()) {
362 // Paint the header so that it overlaps with the top few pixels of the
363 // toolbar because the top few pixels of the toolbar are not opaque.
364 painted_height = GetTopInset() + kFrameShadowThickness * 2;
365 } else {
366 painted_height = GetTopInset();
368 header_painter_->SetHeaderHeightForPainting(painted_height);
370 if (avatar_button()) {
371 LayoutAvatar();
372 header_painter_->UpdateLeftViewXInset(avatar_button()->bounds().right());
373 } else {
374 if (new_avatar_button())
375 LayoutNewStyleAvatar();
376 header_painter_->UpdateLeftViewXInset(
377 ash::HeaderPainterUtil::GetDefaultLeftViewXInset());
379 BrowserNonClientFrameView::Layout();
382 const char* BrowserNonClientFrameViewAsh::GetClassName() const {
383 return kViewClassName;
386 void BrowserNonClientFrameViewAsh::GetAccessibleState(
387 ui::AXViewState* state) {
388 state->role = ui::AX_ROLE_TITLE_BAR;
391 gfx::Size BrowserNonClientFrameViewAsh::GetMinimumSize() const {
392 gfx::Size min_client_view_size(frame()->client_view()->GetMinimumSize());
393 int min_width = std::max(header_painter_->GetMinimumHeaderWidth(),
394 min_client_view_size.width());
395 if (browser_view()->IsTabStripVisible()) {
396 // Ensure that the minimum width is enough to hold a minimum width tab strip
397 // at its usual insets.
398 int min_tabstrip_width =
399 browser_view()->tabstrip()->GetMinimumSize().width();
400 min_width = std::max(min_width,
401 min_tabstrip_width + GetTabStripLeftInset() + GetTabStripRightInset());
403 return gfx::Size(min_width, min_client_view_size.height());
406 void BrowserNonClientFrameViewAsh::
407 ChildPreferredSizeChanged(views::View* child) {
408 // FrameCaptionButtonContainerView animates the visibility changes in
409 // UpdateSizeButtonVisibility(false). Due to this a new size is not available
410 // until the completion of the animation. Layout in response to the preferred
411 // size changes.
412 if (child == caption_button_container_ || child == new_avatar_button()) {
413 InvalidateLayout();
414 frame()->GetRootView()->Layout();
418 ///////////////////////////////////////////////////////////////////////////////
419 // ash::ShellObserver:
421 void BrowserNonClientFrameViewAsh::OnMaximizeModeStarted() {
422 caption_button_container_->UpdateSizeButtonVisibility();
423 InvalidateLayout();
424 frame()->client_view()->InvalidateLayout();
425 frame()->GetRootView()->Layout();
428 void BrowserNonClientFrameViewAsh::OnMaximizeModeEnded() {
429 caption_button_container_->UpdateSizeButtonVisibility();
430 InvalidateLayout();
431 frame()->client_view()->InvalidateLayout();
432 frame()->GetRootView()->Layout();
435 ///////////////////////////////////////////////////////////////////////////////
436 // chrome::TabIconViewModel:
438 bool BrowserNonClientFrameViewAsh::ShouldTabIconViewAnimate() const {
439 // This function is queried during the creation of the window as the
440 // TabIconView we host is initialized, so we need to null check the selected
441 // WebContents because in this condition there is not yet a selected tab.
442 content::WebContents* current_tab = browser_view()->GetActiveWebContents();
443 return current_tab ? current_tab->IsLoading() : false;
446 gfx::ImageSkia BrowserNonClientFrameViewAsh::GetFaviconForTabIconView() {
447 views::WidgetDelegate* delegate = frame()->widget_delegate();
448 if (!delegate)
449 return gfx::ImageSkia();
450 return delegate->GetWindowIcon();
453 ///////////////////////////////////////////////////////////////////////////////
454 // views::ButtonListener:
456 void BrowserNonClientFrameViewAsh::ButtonPressed(views::Button* sender,
457 const ui::Event& event) {
458 DCHECK(sender == new_avatar_button());
459 int command = IDC_SHOW_AVATAR_MENU;
460 if (event.IsMouseEvent() &&
461 static_cast<const ui::MouseEvent&>(event).IsRightMouseButton()) {
462 command = IDC_SHOW_FAST_USER_SWITCHER;
464 chrome::ExecuteCommand(browser_view()->browser(), command);
467 ///////////////////////////////////////////////////////////////////////////////
468 // BrowserNonClientFrameViewAsh, protected:
470 // BrowserNonClientFrameView:
471 void BrowserNonClientFrameViewAsh::UpdateNewAvatarButtonImpl() {
472 UpdateNewAvatarButton(this, NewAvatarButton::NATIVE_BUTTON);
475 ///////////////////////////////////////////////////////////////////////////////
476 // BrowserNonClientFrameViewAsh, private:
478 // views::NonClientFrameView:
479 bool BrowserNonClientFrameViewAsh::DoesIntersectRect(
480 const views::View* target,
481 const gfx::Rect& rect) const {
482 CHECK_EQ(target, this);
483 if (!views::ViewTargeterDelegate::DoesIntersectRect(this, rect)) {
484 // |rect| is outside BrowserNonClientFrameViewAsh's bounds.
485 return false;
488 TabStrip* tabstrip = browser_view()->tabstrip();
489 if (tabstrip && browser_view()->IsTabStripVisible()) {
490 // Claim |rect| only if it is above the bottom of the tabstrip in a non-tab
491 // portion.
492 gfx::RectF rect_in_tabstrip_coords_f(rect);
493 View::ConvertRectToTarget(this, tabstrip, &rect_in_tabstrip_coords_f);
494 gfx::Rect rect_in_tabstrip_coords = gfx::ToEnclosingRect(
495 rect_in_tabstrip_coords_f);
497 if (rect_in_tabstrip_coords.y() > tabstrip->height())
498 return false;
500 return !tabstrip->HitTestRect(rect_in_tabstrip_coords) ||
501 tabstrip->IsRectInWindowCaption(rect_in_tabstrip_coords);
504 // Claim |rect| if it is above the top of the topmost view in the client area.
505 return rect.y() < GetTopInset();
508 int BrowserNonClientFrameViewAsh::GetTabStripLeftInset() const {
509 return avatar_button() ? kAvatarSideSpacing +
510 browser_view()->GetOTRAvatarIcon().width() + kAvatarSideSpacing :
511 kTabstripLeftSpacing;
514 int BrowserNonClientFrameViewAsh::GetTabStripRightInset() const {
515 int tabstrip_width = kTabstripRightSpacing +
516 caption_button_container_->GetPreferredSize().width();
518 return new_avatar_button() ? kNewAvatarButtonOffset +
519 new_avatar_button()->GetPreferredSize().width() + tabstrip_width :
520 tabstrip_width;
523 bool BrowserNonClientFrameViewAsh::UseImmersiveLightbarHeaderStyle() const {
524 ImmersiveModeController* immersive_controller =
525 browser_view()->immersive_mode_controller();
526 return immersive_controller->IsEnabled() &&
527 !immersive_controller->IsRevealed() &&
528 browser_view()->IsTabStripVisible();
531 bool BrowserNonClientFrameViewAsh::UsePackagedAppHeaderStyle() const {
532 // Use the packaged app style for apps that aren't using the newer WebApp
533 // style, and that aren't bookmark apps.
534 if (!browser_view()->browser()->is_app() || UseWebAppHeaderStyle())
535 return false;
537 const std::string extension_id = web_app::GetExtensionIdFromApplicationName(
538 browser_view()->browser()->app_name());
539 const extensions::Extension* extension =
540 extensions::ExtensionRegistry::Get(browser_view()->browser()->profile())
541 ->GetExtensionById(extension_id,
542 extensions::ExtensionRegistry::EVERYTHING);
543 return !extension || !extension->from_bookmark();
546 bool BrowserNonClientFrameViewAsh::UseWebAppHeaderStyle() const {
547 return browser_view()->browser()->SupportsWindowFeature(
548 Browser::FEATURE_WEBAPPFRAME);
551 void BrowserNonClientFrameViewAsh::LayoutAvatar() {
552 DCHECK(avatar_button());
553 #if !defined(OS_CHROMEOS)
554 // ChromeOS shows avatar on V1 app.
555 DCHECK(browser_view()->IsTabStripVisible());
556 #endif
557 gfx::ImageSkia incognito_icon = browser_view()->GetOTRAvatarIcon();
559 int avatar_bottom = GetTopInset() +
560 browser_view()->GetTabStripHeight() - kAvatarBottomSpacing;
561 int avatar_restored_y = avatar_bottom - incognito_icon.height();
562 int avatar_y =
563 (browser_view()->IsTabStripVisible() &&
564 (frame()->IsMaximized() || frame()->IsFullscreen())) ?
565 GetTopInset() + kContentShadowHeight : avatar_restored_y;
567 // Hide the incognito icon in immersive fullscreen when the tab light bar is
568 // visible because the header is too short for the icognito icon to be
569 // recognizable.
570 bool avatar_visible = !UseImmersiveLightbarHeaderStyle();
571 int avatar_height = avatar_visible ? avatar_bottom - avatar_y : 0;
573 gfx::Rect avatar_bounds(kAvatarSideSpacing,
574 avatar_y,
575 incognito_icon.width(),
576 avatar_height);
577 avatar_button()->SetBoundsRect(avatar_bounds);
578 avatar_button()->SetVisible(avatar_visible);
581 void BrowserNonClientFrameViewAsh::LayoutNewStyleAvatar() {
582 DCHECK(switches::IsNewAvatarMenu());
583 if (!new_avatar_button())
584 return;
586 gfx::Size button_size = new_avatar_button()->GetPreferredSize();
587 int button_x = width() -
588 caption_button_container_->GetPreferredSize().width() -
589 kNewAvatarButtonOffset - button_size.width();
591 new_avatar_button()->SetBounds(
592 button_x,
594 button_size.width(),
595 caption_button_container_->GetPreferredSize().height());
598 bool BrowserNonClientFrameViewAsh::ShouldPaint() const {
599 if (!frame()->IsFullscreen())
600 return true;
602 // We need to paint when in immersive fullscreen and either:
603 // - The top-of-window views are revealed.
604 // - The lightbar style tabstrip is visible.
605 ImmersiveModeController* immersive_mode_controller =
606 browser_view()->immersive_mode_controller();
607 return immersive_mode_controller->IsEnabled() &&
608 (immersive_mode_controller->IsRevealed() ||
609 UseImmersiveLightbarHeaderStyle());
612 void BrowserNonClientFrameViewAsh::PaintImmersiveLightbarStyleHeader(
613 gfx::Canvas* canvas) {
614 // The light bar header is not themed because theming it does not look good.
615 canvas->FillRect(
616 gfx::Rect(width(), header_painter_->GetHeaderHeightForPainting()),
617 SK_ColorBLACK);
620 void BrowserNonClientFrameViewAsh::PaintToolbarBackground(gfx::Canvas* canvas) {
621 gfx::Rect toolbar_bounds(browser_view()->GetToolbarBounds());
622 if (toolbar_bounds.IsEmpty())
623 return;
624 gfx::Point toolbar_origin(toolbar_bounds.origin());
625 View::ConvertPointToTarget(browser_view(), this, &toolbar_origin);
626 toolbar_bounds.set_origin(toolbar_origin);
628 int x = toolbar_bounds.x();
629 int w = toolbar_bounds.width();
630 int y = toolbar_bounds.y();
631 int h = toolbar_bounds.height();
633 // Gross hack: We split the toolbar images into two pieces, since sometimes
634 // (popup mode) the toolbar isn't tall enough to show the whole image. The
635 // split happens between the top shadow section and the bottom gradient
636 // section so that we never break the gradient.
637 // NOTE(pkotwicz): If the computation for |bottom_y| is changed, Layout() must
638 // be changed as well.
639 int split_point = kFrameShadowThickness * 2;
640 int bottom_y = y + split_point;
641 ui::ThemeProvider* tp = GetThemeProvider();
642 int bottom_edge_height = h - split_point;
644 canvas->FillRect(gfx::Rect(x, bottom_y, w, bottom_edge_height),
645 tp->GetColor(ThemeProperties::COLOR_TOOLBAR));
647 // Paint the main toolbar image. Since this image is also used to draw the
648 // tab background, we must use the tab strip offset to compute the image
649 // source y position. If you have to debug this code use an image editor
650 // to paint a diagonal line through the toolbar image and ensure it lines up
651 // across the tab and toolbar.
652 gfx::ImageSkia* theme_toolbar = tp->GetImageSkiaNamed(IDR_THEME_TOOLBAR);
653 canvas->TileImageInt(
654 *theme_toolbar,
655 x + GetThemeBackgroundXInset(),
656 bottom_y - GetTopInset(),
657 x, bottom_y,
658 w, theme_toolbar->height());
660 // The content area line has a shadow that extends a couple of pixels above
661 // the toolbar bounds.
662 const int kContentShadowHeight = 2;
663 gfx::ImageSkia* toolbar_top = tp->GetImageSkiaNamed(IDR_TOOLBAR_SHADE_TOP);
664 canvas->TileImageInt(*toolbar_top,
665 0, 0,
666 x, y - kContentShadowHeight,
667 w, split_point + kContentShadowHeight + 1);
669 // Draw the "lightening" shade line around the edges of the toolbar.
670 gfx::ImageSkia* toolbar_left = tp->GetImageSkiaNamed(IDR_TOOLBAR_SHADE_LEFT);
671 canvas->TileImageInt(*toolbar_left,
672 0, 0,
673 x + kClientEdgeThickness,
674 y + kClientEdgeThickness + kContentShadowHeight,
675 toolbar_left->width(), theme_toolbar->height());
676 gfx::ImageSkia* toolbar_right =
677 tp->GetImageSkiaNamed(IDR_TOOLBAR_SHADE_RIGHT);
678 canvas->TileImageInt(*toolbar_right,
679 0, 0,
680 w - toolbar_right->width() - 2 * kClientEdgeThickness,
681 y + kClientEdgeThickness + kContentShadowHeight,
682 toolbar_right->width(), theme_toolbar->height());
684 // Draw the content/toolbar separator.
685 canvas->FillRect(
686 gfx::Rect(x + kClientEdgeThickness,
687 toolbar_bounds.bottom() - kClientEdgeThickness,
688 w - (2 * kClientEdgeThickness),
689 kClientEdgeThickness),
690 ThemeProperties::GetDefaultColor(
691 ThemeProperties::COLOR_TOOLBAR_SEPARATOR));
694 void BrowserNonClientFrameViewAsh::PaintContentEdge(gfx::Canvas* canvas) {
695 DCHECK(!UsePackagedAppHeaderStyle() && !UseWebAppHeaderStyle());
696 canvas->FillRect(gfx::Rect(0, caption_button_container_->bounds().bottom(),
697 width(), kClientEdgeThickness),
698 ThemeProperties::GetDefaultColor(
699 ThemeProperties::COLOR_TOOLBAR_SEPARATOR));