Popular sites on the NTP: check that experiment group StartsWith (rather than IS...
[chromium-blink-merge.git] / chrome / browser / ui / views / frame / browser_non_client_frame_view_ash.cc
bloba23f1b8baa9d3964ba69e599c4aa11af9f9b5a07
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/material_design/material_design_controller.h"
40 #include "ui/base/resource/resource_bundle.h"
41 #include "ui/base/theme_provider.h"
42 #include "ui/compositor/layer_animator.h"
43 #include "ui/gfx/canvas.h"
44 #include "ui/gfx/geometry/rect_conversions.h"
45 #include "ui/gfx/image/image_skia.h"
46 #include "ui/views/controls/label.h"
47 #include "ui/views/layout/layout_constants.h"
48 #include "ui/views/widget/widget.h"
49 #include "ui/views/widget/widget_delegate.h"
51 #if defined(ENABLE_SUPERVISED_USERS)
52 #include "chrome/browser/ui/views/profiles/supervised_user_avatar_label.h"
53 #endif
55 namespace {
57 // The avatar ends 2 px above the bottom of the tabstrip (which, given the
58 // way the tabstrip draws its bottom edge, will appear like a 1 px gap to the
59 // user).
60 const int kAvatarBottomSpacing = 2;
61 // There are 2 px on each side of the avatar (between the frame border and
62 // it on the left, and between it and the tabstrip on the right).
63 const int kAvatarSideSpacing = 2;
64 #if defined(FRAME_AVATAR_BUTTON)
65 // Space between the new avatar button and the minimize button.
66 const int kNewAvatarButtonOffset = 5;
67 #endif
68 // Space between left edge of window and tabstrip.
69 const int kTabstripLeftSpacing = 0;
70 // Space between right edge of tabstrip and maximize button.
71 const int kTabstripRightSpacing = 10;
72 // Height of the shadow of the content area, at the top of the toolbar.
73 const int kContentShadowHeight = 1;
74 // Space between top of window and top of tabstrip for tall headers, such as
75 // for restored windows, apps, etc.
76 const int kTabstripTopSpacingTall = 7;
77 // Space between top of window and top of tabstrip for short headers, such as
78 // for maximized windows, pop-ups, etc.
79 const int kTabstripTopSpacingShort = 0;
80 // Height of the shadow in the tab image, used to ensure clicks in the shadow
81 // area still drag restored windows. This keeps the clickable area large enough
82 // to hit easily.
83 const int kTabShadowHeight = 4;
85 // Combines View::ConvertPointToTarget() and View::HitTest() for a given
86 // |point|. Converts |point| from |src| to |dst| and hit tests it against |dst|.
87 bool ConvertedHitTest(views::View* src,
88 views::View* dst,
89 const gfx::Point& point) {
90 DCHECK(src);
91 DCHECK(dst);
92 gfx::Point converted_point(point);
93 views::View::ConvertPointToTarget(src, dst, &converted_point);
94 return dst->HitTestPoint(converted_point);
97 } // namespace
99 ///////////////////////////////////////////////////////////////////////////////
100 // BrowserNonClientFrameViewAsh, public:
102 // static
103 const char BrowserNonClientFrameViewAsh::kViewClassName[] =
104 "BrowserNonClientFrameViewAsh";
106 BrowserNonClientFrameViewAsh::BrowserNonClientFrameViewAsh(
107 BrowserFrame* frame,
108 BrowserView* browser_view)
109 : BrowserNonClientFrameView(frame, browser_view),
110 caption_button_container_(nullptr),
111 web_app_left_header_view_(nullptr),
112 window_icon_(nullptr),
113 frame_border_hit_test_controller_(
114 new ash::FrameBorderHitTestController(frame)) {
115 ash::Shell::GetInstance()->AddShellObserver(this);
118 BrowserNonClientFrameViewAsh::~BrowserNonClientFrameViewAsh() {
119 ash::Shell::GetInstance()->RemoveShellObserver(this);
122 void BrowserNonClientFrameViewAsh::Init() {
123 caption_button_container_ = new ash::FrameCaptionButtonContainerView(frame());
124 caption_button_container_->UpdateSizeButtonVisibility();
125 AddChildView(caption_button_container_);
127 // Initializing the TabIconView is expensive, so only do it if we need to.
128 if (browser_view()->ShouldShowWindowIcon()) {
129 window_icon_ = new TabIconView(this, nullptr);
130 window_icon_->set_is_light(true);
131 AddChildView(window_icon_);
132 window_icon_->Update();
135 UpdateAvatar();
137 // HeaderPainter handles layout.
138 if (UsePackagedAppHeaderStyle()) {
139 ash::DefaultHeaderPainter* header_painter = new ash::DefaultHeaderPainter;
140 header_painter_.reset(header_painter);
141 header_painter->Init(frame(), this, caption_button_container_);
142 if (window_icon_) {
143 header_painter->UpdateLeftHeaderView(window_icon_);
145 } else if (UseWebAppHeaderStyle()) {
146 web_app_left_header_view_ = new WebAppLeftHeaderView(browser_view());
147 AddChildView(web_app_left_header_view_);
149 ash::DefaultHeaderPainter* header_painter = new ash::DefaultHeaderPainter;
150 header_painter_.reset(header_painter);
151 header_painter->Init(frame(), this, caption_button_container_);
152 header_painter->UpdateLeftHeaderView(web_app_left_header_view_);
153 } else {
154 BrowserHeaderPainterAsh* header_painter = new BrowserHeaderPainterAsh;
155 header_painter_.reset(header_painter);
156 header_painter->Init(frame(), browser_view(), this, window_icon_,
157 caption_button_container_);
161 ///////////////////////////////////////////////////////////////////////////////
162 // BrowserNonClientFrameView:
164 gfx::Rect BrowserNonClientFrameViewAsh::GetBoundsForTabStrip(
165 views::View* tabstrip) const {
166 if (!tabstrip)
167 return gfx::Rect();
169 // When the tab strip is painted in the immersive fullscreen light bar style,
170 // the caption buttons and the avatar button are not visible. However, their
171 // bounds are still used to compute the tab strip bounds so that the tabs have
172 // the same horizontal position when the tab strip is painted in the immersive
173 // light bar style as when the top-of-window views are revealed.
174 int left_inset = GetTabStripLeftInset();
175 int right_inset = GetTabStripRightInset();
176 return gfx::Rect(left_inset,
177 GetTopInset(),
178 std::max(0, width() - left_inset - right_inset),
179 tabstrip->GetPreferredSize().height());
182 int BrowserNonClientFrameViewAsh::GetTopInset() const {
183 if (!ShouldPaint() || UseImmersiveLightbarHeaderStyle())
184 return 0;
186 if (browser_view()->IsTabStripVisible()) {
187 if (frame()->IsMaximized() || frame()->IsFullscreen())
188 return kTabstripTopSpacingShort;
189 else
190 return kTabstripTopSpacingTall;
193 if (UsePackagedAppHeaderStyle() || UseWebAppHeaderStyle())
194 return header_painter_->GetHeaderHeight();
196 int caption_buttons_bottom = caption_button_container_->bounds().bottom();
198 // The toolbar partially overlaps the caption buttons.
199 if (browser_view()->IsToolbarVisible())
200 return caption_buttons_bottom - kContentShadowHeight;
202 return caption_buttons_bottom + kClientEdgeThickness;
205 int BrowserNonClientFrameViewAsh::GetThemeBackgroundXInset() const {
206 return ash::HeaderPainterUtil::GetThemeBackgroundXInset();
209 void BrowserNonClientFrameViewAsh::UpdateThrobber(bool running) {
210 if (window_icon_)
211 window_icon_->Update();
214 void BrowserNonClientFrameViewAsh::UpdateToolbar() {
215 if (web_app_left_header_view_)
216 web_app_left_header_view_->Update();
219 views::View* BrowserNonClientFrameViewAsh::GetLocationIconView() const {
220 if (web_app_left_header_view_)
221 return web_app_left_header_view_->GetLocationIconView();
223 return nullptr;
226 ///////////////////////////////////////////////////////////////////////////////
227 // views::NonClientFrameView:
229 gfx::Rect BrowserNonClientFrameViewAsh::GetBoundsForClientView() const {
230 // The ClientView must be flush with the top edge of the widget so that the
231 // web contents can take up the entire screen in immersive fullscreen (with
232 // or without the top-of-window views revealed). When in immersive fullscreen
233 // and the top-of-window views are revealed, the TopContainerView paints the
234 // window header by redirecting paints from its background to
235 // BrowserNonClientFrameViewAsh.
236 return bounds();
239 gfx::Rect BrowserNonClientFrameViewAsh::GetWindowBoundsForClientBounds(
240 const gfx::Rect& client_bounds) const {
241 return client_bounds;
244 int BrowserNonClientFrameViewAsh::NonClientHitTest(const gfx::Point& point) {
245 int hit_test = ash::FrameBorderHitTestController::NonClientHitTest(this,
246 caption_button_container_, point);
248 #if defined(FRAME_AVATAR_BUTTON)
249 if (hit_test == HTCAPTION && new_avatar_button() &&
250 ConvertedHitTest(this, new_avatar_button(), point)) {
251 return HTCLIENT;
253 #endif
255 // See if the point is actually within the web app back button.
256 if (hit_test == HTCAPTION && web_app_left_header_view_ &&
257 ConvertedHitTest(this, web_app_left_header_view_, point)) {
258 return HTCLIENT;
261 #if defined(ENABLE_SUPERVISED_USERS)
262 // ...or within the avatar label, if it's a supervised user.
263 if (hit_test == HTCAPTION && supervised_user_avatar_label() &&
264 ConvertedHitTest(this, supervised_user_avatar_label(), point)) {
265 return HTCLIENT;
267 #endif
269 // When the window is restored we want a large click target above the tabs
270 // to drag the window, so redirect clicks in the tab's shadow to caption.
271 if (hit_test == HTCLIENT &&
272 !(frame()->IsMaximized() || frame()->IsFullscreen())) {
273 // Convert point to client coordinates.
274 gfx::Point client_point(point);
275 View::ConvertPointToTarget(this, frame()->client_view(), &client_point);
276 // Report hits in shadow at top of tabstrip as caption.
277 gfx::Rect tabstrip_bounds(browser_view()->tabstrip()->bounds());
278 if (client_point.y() < tabstrip_bounds.y() + kTabShadowHeight)
279 hit_test = HTCAPTION;
281 return hit_test;
284 void BrowserNonClientFrameViewAsh::GetWindowMask(const gfx::Size& size,
285 gfx::Path* window_mask) {
286 // Aura does not use window masks.
289 void BrowserNonClientFrameViewAsh::ResetWindowControls() {
290 // Hide the caption buttons in immersive fullscreen when the tab light bar
291 // is visible because it's confusing when the user hovers or clicks in the
292 // top-right of the screen and hits one.
293 bool button_visibility = !UseImmersiveLightbarHeaderStyle();
294 caption_button_container_->SetVisible(button_visibility);
296 caption_button_container_->ResetWindowControls();
299 void BrowserNonClientFrameViewAsh::UpdateWindowIcon() {
300 if (window_icon_)
301 window_icon_->SchedulePaint();
304 void BrowserNonClientFrameViewAsh::UpdateWindowTitle() {
305 if (!frame()->IsFullscreen())
306 header_painter_->SchedulePaintForTitle();
309 void BrowserNonClientFrameViewAsh::SizeConstraintsChanged() {
312 ///////////////////////////////////////////////////////////////////////////////
313 // views::View:
315 void BrowserNonClientFrameViewAsh::OnPaint(gfx::Canvas* canvas) {
316 if (!ShouldPaint())
317 return;
319 if (UseImmersiveLightbarHeaderStyle()) {
320 PaintImmersiveLightbarStyleHeader(canvas);
321 return;
324 caption_button_container_->SetPaintAsActive(ShouldPaintAsActive());
325 if (web_app_left_header_view_)
326 web_app_left_header_view_->SetPaintAsActive(ShouldPaintAsActive());
328 ash::HeaderPainter::Mode header_mode = ShouldPaintAsActive() ?
329 ash::HeaderPainter::MODE_ACTIVE : ash::HeaderPainter::MODE_INACTIVE;
330 header_painter_->PaintHeader(canvas, header_mode);
331 if (browser_view()->IsToolbarVisible())
332 PaintToolbarBackground(canvas);
333 else if (!UsePackagedAppHeaderStyle() && !UseWebAppHeaderStyle())
334 PaintContentEdge(canvas);
337 void BrowserNonClientFrameViewAsh::Layout() {
338 // The header must be laid out before computing |painted_height| because the
339 // computation of |painted_height| for app and popup windows depends on the
340 // position of the window controls.
341 header_painter_->LayoutHeader();
343 int painted_height = 0;
344 if (browser_view()->IsTabStripVisible()) {
345 painted_height = GetTopInset() +
346 browser_view()->tabstrip()->GetPreferredSize().height();
347 } else if (browser_view()->IsToolbarVisible()) {
348 // Paint the header so that it overlaps with the top few pixels of the
349 // toolbar because the top few pixels of the toolbar are not opaque.
350 painted_height = GetTopInset() + kFrameShadowThickness * 2;
351 } else {
352 painted_height = GetTopInset();
354 header_painter_->SetHeaderHeightForPainting(painted_height);
356 if (avatar_button()) {
357 LayoutAvatar();
358 header_painter_->UpdateLeftViewXInset(avatar_button()->bounds().right());
360 #if defined(FRAME_AVATAR_BUTTON)
361 if (new_avatar_button())
362 LayoutNewStyleAvatar();
363 #endif
364 header_painter_->UpdateLeftViewXInset(
365 ash::HeaderPainterUtil::GetDefaultLeftViewXInset());
366 BrowserNonClientFrameView::Layout();
369 const char* BrowserNonClientFrameViewAsh::GetClassName() const {
370 return kViewClassName;
373 void BrowserNonClientFrameViewAsh::GetAccessibleState(
374 ui::AXViewState* state) {
375 state->role = ui::AX_ROLE_TITLE_BAR;
378 gfx::Size BrowserNonClientFrameViewAsh::GetMinimumSize() const {
379 gfx::Size min_client_view_size(frame()->client_view()->GetMinimumSize());
380 int min_width = std::max(header_painter_->GetMinimumHeaderWidth(),
381 min_client_view_size.width());
382 if (browser_view()->IsTabStripVisible()) {
383 // Ensure that the minimum width is enough to hold a minimum width tab strip
384 // at its usual insets.
385 int min_tabstrip_width =
386 browser_view()->tabstrip()->GetMinimumSize().width();
387 min_width = std::max(min_width,
388 min_tabstrip_width + GetTabStripLeftInset() + GetTabStripRightInset());
390 return gfx::Size(min_width, min_client_view_size.height());
393 void BrowserNonClientFrameViewAsh::
394 ChildPreferredSizeChanged(views::View* child) {
395 // FrameCaptionButtonContainerView animates the visibility changes in
396 // UpdateSizeButtonVisibility(false). Due to this a new size is not available
397 // until the completion of the animation. Layout in response to the preferred
398 // size changes.
399 if (!browser_view()->initialized())
400 return;
401 bool needs_layout = child == caption_button_container_;
402 #if defined(FRAME_AVATAR_BUTTON)
403 needs_layout = needs_layout || child == new_avatar_button();
404 #endif
405 if (needs_layout) {
406 InvalidateLayout();
407 frame()->GetRootView()->Layout();
411 ///////////////////////////////////////////////////////////////////////////////
412 // ash::ShellObserver:
414 void BrowserNonClientFrameViewAsh::OnMaximizeModeStarted() {
415 caption_button_container_->UpdateSizeButtonVisibility();
416 InvalidateLayout();
417 frame()->client_view()->InvalidateLayout();
418 frame()->GetRootView()->Layout();
421 void BrowserNonClientFrameViewAsh::OnMaximizeModeEnded() {
422 caption_button_container_->UpdateSizeButtonVisibility();
423 InvalidateLayout();
424 frame()->client_view()->InvalidateLayout();
425 frame()->GetRootView()->Layout();
428 ///////////////////////////////////////////////////////////////////////////////
429 // chrome::TabIconViewModel:
431 bool BrowserNonClientFrameViewAsh::ShouldTabIconViewAnimate() const {
432 // This function is queried during the creation of the window as the
433 // TabIconView we host is initialized, so we need to null check the selected
434 // WebContents because in this condition there is not yet a selected tab.
435 content::WebContents* current_tab = browser_view()->GetActiveWebContents();
436 return current_tab ? current_tab->IsLoading() : false;
439 gfx::ImageSkia BrowserNonClientFrameViewAsh::GetFaviconForTabIconView() {
440 views::WidgetDelegate* delegate = frame()->widget_delegate();
441 if (!delegate)
442 return gfx::ImageSkia();
443 return delegate->GetWindowIcon();
446 ///////////////////////////////////////////////////////////////////////////////
447 // views::ButtonListener:
449 void BrowserNonClientFrameViewAsh::ButtonPressed(views::Button* sender,
450 const ui::Event& event) {
451 #if !defined(FRAME_AVATAR_BUTTON)
452 NOTREACHED();
453 #else
454 DCHECK(sender == new_avatar_button());
455 int command = IDC_SHOW_AVATAR_MENU;
456 if (event.IsMouseEvent() &&
457 static_cast<const ui::MouseEvent&>(event).IsRightMouseButton()) {
458 command = IDC_SHOW_FAST_USER_SWITCHER;
460 chrome::ExecuteCommand(browser_view()->browser(), command);
461 #endif
464 ///////////////////////////////////////////////////////////////////////////////
465 // BrowserNonClientFrameViewAsh, protected:
467 // BrowserNonClientFrameView:
468 void BrowserNonClientFrameViewAsh::UpdateNewAvatarButtonImpl() {
469 #if defined(FRAME_AVATAR_BUTTON)
470 UpdateNewAvatarButton(this, NewAvatarButton::NATIVE_BUTTON);
471 #endif
474 ///////////////////////////////////////////////////////////////////////////////
475 // BrowserNonClientFrameViewAsh, private:
477 // views::NonClientFrameView:
478 bool BrowserNonClientFrameViewAsh::DoesIntersectRect(
479 const views::View* target,
480 const gfx::Rect& rect) const {
481 CHECK_EQ(target, this);
482 if (!views::ViewTargeterDelegate::DoesIntersectRect(this, rect)) {
483 // |rect| is outside BrowserNonClientFrameViewAsh's bounds.
484 return false;
487 TabStrip* tabstrip = browser_view()->tabstrip();
488 if (tabstrip && browser_view()->IsTabStripVisible()) {
489 // Claim |rect| only if it is above the bottom of the tabstrip in a non-tab
490 // portion.
491 gfx::RectF rect_in_tabstrip_coords_f(rect);
492 View::ConvertRectToTarget(this, tabstrip, &rect_in_tabstrip_coords_f);
493 gfx::Rect rect_in_tabstrip_coords = gfx::ToEnclosingRect(
494 rect_in_tabstrip_coords_f);
496 if (rect_in_tabstrip_coords.y() > tabstrip->height())
497 return false;
499 return !tabstrip->HitTestRect(rect_in_tabstrip_coords) ||
500 tabstrip->IsRectInWindowCaption(rect_in_tabstrip_coords);
503 // Claim |rect| if it is above the top of the topmost view in the client area.
504 return rect.y() < GetTopInset();
507 int BrowserNonClientFrameViewAsh::GetTabStripLeftInset() const {
508 return avatar_button() ? kAvatarSideSpacing +
509 browser_view()->GetOTRAvatarIcon().width() + kAvatarSideSpacing :
510 kTabstripLeftSpacing;
513 int BrowserNonClientFrameViewAsh::GetTabStripRightInset() const {
514 int tabstrip_width = kTabstripRightSpacing +
515 caption_button_container_->GetPreferredSize().width();
517 #if defined(FRAME_AVATAR_BUTTON)
518 if (new_avatar_button()) {
519 tabstrip_width += kNewAvatarButtonOffset +
520 new_avatar_button()->GetPreferredSize().width();
522 #endif
524 return tabstrip_width;
527 bool BrowserNonClientFrameViewAsh::UseImmersiveLightbarHeaderStyle() const {
528 ImmersiveModeController* immersive_controller =
529 browser_view()->immersive_mode_controller();
530 return immersive_controller->IsEnabled() &&
531 !immersive_controller->IsRevealed() &&
532 browser_view()->IsTabStripVisible();
535 bool BrowserNonClientFrameViewAsh::UsePackagedAppHeaderStyle() const {
536 // Use the packaged app style for apps that aren't using the newer WebApp
537 // style, and that aren't bookmark apps.
538 if (!browser_view()->browser()->is_app() || UseWebAppHeaderStyle())
539 return false;
541 const std::string extension_id = web_app::GetExtensionIdFromApplicationName(
542 browser_view()->browser()->app_name());
543 const extensions::Extension* extension =
544 extensions::ExtensionRegistry::Get(browser_view()->browser()->profile())
545 ->GetExtensionById(extension_id,
546 extensions::ExtensionRegistry::EVERYTHING);
547 return !extension || !extension->from_bookmark();
550 bool BrowserNonClientFrameViewAsh::UseWebAppHeaderStyle() const {
551 return browser_view()->browser()->SupportsWindowFeature(
552 Browser::FEATURE_WEBAPPFRAME);
555 void BrowserNonClientFrameViewAsh::LayoutAvatar() {
556 DCHECK(avatar_button());
557 #if !defined(OS_CHROMEOS)
558 // ChromeOS shows avatar on V1 app.
559 DCHECK(browser_view()->IsTabStripVisible());
560 #endif
561 gfx::ImageSkia incognito_icon = browser_view()->GetOTRAvatarIcon();
563 int avatar_bottom = GetTopInset() +
564 browser_view()->GetTabStripHeight() - kAvatarBottomSpacing;
565 int avatar_restored_y = avatar_bottom - incognito_icon.height();
566 int avatar_y =
567 (browser_view()->IsTabStripVisible() &&
568 (frame()->IsMaximized() || frame()->IsFullscreen())) ?
569 GetTopInset() + kContentShadowHeight : avatar_restored_y;
571 // Hide the incognito icon in immersive fullscreen when the tab light bar is
572 // visible because the header is too short for the icognito icon to be
573 // recognizable.
574 bool avatar_visible = !UseImmersiveLightbarHeaderStyle();
575 int avatar_height = avatar_visible ? avatar_bottom - avatar_y : 0;
577 gfx::Rect avatar_bounds(kAvatarSideSpacing,
578 avatar_y,
579 incognito_icon.width(),
580 avatar_height);
581 avatar_button()->SetBoundsRect(avatar_bounds);
582 avatar_button()->SetVisible(avatar_visible);
585 #if defined(FRAME_AVATAR_BUTTON)
586 void BrowserNonClientFrameViewAsh::LayoutNewStyleAvatar() {
587 DCHECK(switches::IsNewAvatarMenu());
589 gfx::Size button_size = new_avatar_button()->GetPreferredSize();
590 int button_x = width() -
591 caption_button_container_->GetPreferredSize().width() -
592 kNewAvatarButtonOffset - button_size.width();
594 new_avatar_button()->SetBounds(
595 button_x,
597 button_size.width(),
598 caption_button_container_->GetPreferredSize().height());
600 #endif
602 bool BrowserNonClientFrameViewAsh::ShouldPaint() const {
603 if (!frame()->IsFullscreen())
604 return true;
606 // We need to paint when in immersive fullscreen and either:
607 // - The top-of-window views are revealed.
608 // - The lightbar style tabstrip is visible.
609 ImmersiveModeController* immersive_mode_controller =
610 browser_view()->immersive_mode_controller();
611 return immersive_mode_controller->IsEnabled() &&
612 (immersive_mode_controller->IsRevealed() ||
613 UseImmersiveLightbarHeaderStyle());
616 void BrowserNonClientFrameViewAsh::PaintImmersiveLightbarStyleHeader(
617 gfx::Canvas* canvas) {
618 // The light bar header is not themed because theming it does not look good.
619 canvas->FillRect(
620 gfx::Rect(width(), header_painter_->GetHeaderHeightForPainting()),
621 SK_ColorBLACK);
624 void BrowserNonClientFrameViewAsh::PaintToolbarBackground(gfx::Canvas* canvas) {
625 gfx::Rect toolbar_bounds(browser_view()->GetToolbarBounds());
626 if (toolbar_bounds.IsEmpty())
627 return;
628 gfx::Point toolbar_origin(toolbar_bounds.origin());
629 View::ConvertPointToTarget(browser_view(), this, &toolbar_origin);
630 toolbar_bounds.set_origin(toolbar_origin);
632 int x = toolbar_bounds.x();
633 int w = toolbar_bounds.width();
634 int y = toolbar_bounds.y();
635 int h = toolbar_bounds.height();
637 // Gross hack: We split the toolbar images into two pieces, since sometimes
638 // (popup mode) the toolbar isn't tall enough to show the whole image. The
639 // split happens between the top shadow section and the bottom gradient
640 // section so that we never break the gradient.
641 // NOTE(pkotwicz): If the computation for |bottom_y| is changed, Layout() must
642 // be changed as well.
643 int split_point = kFrameShadowThickness * 2;
644 int bottom_y = y + split_point;
645 ui::ThemeProvider* tp = GetThemeProvider();
646 int bottom_edge_height = h - split_point;
648 canvas->FillRect(gfx::Rect(x, bottom_y, w, bottom_edge_height),
649 tp->GetColor(ThemeProperties::COLOR_TOOLBAR));
651 // Paint the main toolbar image. Since this image is also used to draw the
652 // tab background, we must use the tab strip offset to compute the image
653 // source y position. If you have to debug this code use an image editor
654 // to paint a diagonal line through the toolbar image and ensure it lines up
655 // across the tab and toolbar.
656 gfx::ImageSkia* theme_toolbar = tp->GetImageSkiaNamed(IDR_THEME_TOOLBAR);
657 canvas->TileImageInt(
658 *theme_toolbar,
659 x + GetThemeBackgroundXInset(),
660 bottom_y - GetTopInset(),
661 x, bottom_y,
662 w, theme_toolbar->height());
664 if (ui::MaterialDesignController::IsModeMaterial()) {
665 // Draw the content/toolbar separator.
666 toolbar_bounds.Inset(kClientEdgeThickness, 0);
667 BrowserView::Paint1pxHorizontalLine(
668 canvas,
669 ThemeProperties::GetDefaultColor(
670 ThemeProperties::COLOR_TOOLBAR_SEPARATOR),
671 toolbar_bounds);
672 } else {
673 // The pre-material design content area line has a shadow that extends a
674 // couple of pixels above the toolbar bounds.
675 const int kContentShadowHeight = 2;
676 gfx::ImageSkia* toolbar_top = tp->GetImageSkiaNamed(IDR_TOOLBAR_SHADE_TOP);
677 canvas->TileImageInt(*toolbar_top,
678 0, 0,
679 x, y - kContentShadowHeight,
680 w, split_point + kContentShadowHeight + 1);
682 // Draw the "lightening" shade line around the edges of the toolbar.
683 gfx::ImageSkia* toolbar_left =
684 tp->GetImageSkiaNamed(IDR_TOOLBAR_SHADE_LEFT);
685 canvas->TileImageInt(*toolbar_left,
686 0, 0,
687 x + kClientEdgeThickness,
688 y + kClientEdgeThickness + kContentShadowHeight,
689 toolbar_left->width(), theme_toolbar->height());
690 gfx::ImageSkia* toolbar_right =
691 tp->GetImageSkiaNamed(IDR_TOOLBAR_SHADE_RIGHT);
692 canvas->TileImageInt(*toolbar_right,
693 0, 0,
694 w - toolbar_right->width() - 2 * kClientEdgeThickness,
695 y + kClientEdgeThickness + kContentShadowHeight,
696 toolbar_right->width(), theme_toolbar->height());
698 // Draw the content/toolbar separator.
699 canvas->FillRect(
700 gfx::Rect(x + kClientEdgeThickness,
701 toolbar_bounds.bottom() - kClientEdgeThickness,
702 w - (2 * kClientEdgeThickness),
703 kClientEdgeThickness),
704 ThemeProperties::GetDefaultColor(
705 ThemeProperties::COLOR_TOOLBAR_SEPARATOR));
709 void BrowserNonClientFrameViewAsh::PaintContentEdge(gfx::Canvas* canvas) {
710 DCHECK(!UsePackagedAppHeaderStyle() && !UseWebAppHeaderStyle());
711 canvas->FillRect(gfx::Rect(0, caption_button_container_->bounds().bottom(),
712 width(), kClientEdgeThickness),
713 ThemeProperties::GetDefaultColor(
714 ThemeProperties::COLOR_TOOLBAR_SEPARATOR));