browser_non_client_frame_view_ash.cc revision a36e5920737c6adbddd3e43b760e5de8431db6e0
1// Copyright (c) 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.
4
5#include "chrome/browser/ui/views/frame/browser_non_client_frame_view_ash.h"
6
7#include "ash/shell_delegate.h"
8#include "ash/wm/frame_painter.h"
9#include "ash/wm/workspace/frame_maximize_button.h"
10#include "chrome/browser/themes/theme_properties.h"
11#include "chrome/browser/ui/ash/chrome_shell_delegate.h"
12#include "chrome/browser/ui/browser.h"
13#include "chrome/browser/ui/immersive_fullscreen_configuration.h"
14#include "chrome/browser/ui/views/avatar_menu_button.h"
15#include "chrome/browser/ui/views/frame/browser_frame.h"
16#include "chrome/browser/ui/views/frame/browser_view.h"
17#include "chrome/browser/ui/views/frame/immersive_mode_controller.h"
18#include "chrome/browser/ui/views/tab_icon_view.h"
19#include "chrome/browser/ui/views/tabs/tab_strip.h"
20#include "content/public/browser/web_contents.h"
21#include "grit/ash_resources.h"
22#include "grit/generated_resources.h"  // Accessibility names
23#include "grit/theme_resources.h"
24#include "ui/aura/client/aura_constants.h"
25#include "ui/aura/window.h"
26#include "ui/base/accessibility/accessible_view_state.h"
27#include "ui/base/hit_test.h"
28#include "ui/base/l10n/l10n_util.h"
29#include "ui/base/layout.h"
30#include "ui/base/resource/resource_bundle.h"
31#include "ui/base/theme_provider.h"
32#include "ui/compositor/layer_animator.h"
33#include "ui/compositor/scoped_animation_duration_scale_mode.h"
34#include "ui/gfx/canvas.h"
35#include "ui/gfx/image/image_skia.h"
36#include "ui/views/controls/button/image_button.h"
37#include "ui/views/controls/label.h"
38#include "ui/views/layout/layout_constants.h"
39#include "ui/views/widget/widget.h"
40#include "ui/views/widget/widget_delegate.h"
41
42namespace {
43
44// The avatar ends 2 px above the bottom of the tabstrip (which, given the
45// way the tabstrip draws its bottom edge, will appear like a 1 px gap to the
46// user).
47const int kAvatarBottomSpacing = 2;
48// There are 2 px on each side of the avatar (between the frame border and
49// it on the left, and between it and the tabstrip on the right).
50const int kAvatarSideSpacing = 2;
51// Space between left edge of window and tabstrip.
52const int kTabstripLeftSpacing = 0;
53// Space between right edge of tabstrip and maximize button.
54const int kTabstripRightSpacing = 10;
55// Height of the shadow of the content area, at the top of the toolbar.
56const int kContentShadowHeight = 1;
57// Space between top of window and top of tabstrip for tall headers, such as
58// for restored windows, apps, etc.
59const int kTabstripTopSpacingTall = 7;
60// Space between top of window and top of tabstrip for short headers, such as
61// for maximized windows, pop-ups, etc.
62const int kTabstripTopSpacingShort = 0;
63// Height of the shadow in the tab image, used to ensure clicks in the shadow
64// area still drag restored windows.  This keeps the clickable area large enough
65// to hit easily.
66const int kTabShadowHeight = 4;
67
68}  // namespace
69
70///////////////////////////////////////////////////////////////////////////////
71// BrowserNonClientFrameViewAsh, public:
72
73// static
74const char BrowserNonClientFrameViewAsh::kViewClassName[] =
75    "BrowserNonClientFrameViewAsh";
76
77BrowserNonClientFrameViewAsh::BrowserNonClientFrameViewAsh(
78    BrowserFrame* frame, BrowserView* browser_view)
79    : BrowserNonClientFrameView(frame, browser_view),
80      size_button_(NULL),
81      close_button_(NULL),
82      window_icon_(NULL),
83      frame_painter_(new ash::FramePainter),
84      size_button_minimizes_(false) {
85}
86
87BrowserNonClientFrameViewAsh::~BrowserNonClientFrameViewAsh() {
88}
89
90void BrowserNonClientFrameViewAsh::Init() {
91  // Panels only minimize.
92  ash::FramePainter::SizeButtonBehavior size_button_behavior;
93  size_button_ = new ash::FrameMaximizeButton(this, this);
94  size_button_behavior = ash::FramePainter::SIZE_BUTTON_MAXIMIZES;
95  size_button_->SetAccessibleName(
96      l10n_util::GetStringUTF16(IDS_ACCNAME_MAXIMIZE));
97  AddChildView(size_button_);
98  close_button_ = new views::ImageButton(this);
99  close_button_->SetAccessibleName(
100      l10n_util::GetStringUTF16(IDS_ACCNAME_CLOSE));
101  AddChildView(close_button_);
102
103  // Initializing the TabIconView is expensive, so only do it if we need to.
104  if (browser_view()->ShouldShowWindowIcon()) {
105    window_icon_ = new TabIconView(this);
106    window_icon_->set_is_light(true);
107    AddChildView(window_icon_);
108    window_icon_->Update();
109  }
110
111  // Create incognito icon if necessary.
112  UpdateAvatarInfo();
113
114  // Frame painter handles layout of these buttons.
115  frame_painter_->Init(frame(), window_icon_, size_button_, close_button_,
116                       size_button_behavior);
117}
118
119///////////////////////////////////////////////////////////////////////////////
120// BrowserNonClientFrameView overrides:
121
122gfx::Rect BrowserNonClientFrameViewAsh::GetBoundsForTabStrip(
123    views::View* tabstrip) const {
124  if (!tabstrip)
125    return gfx::Rect();
126
127  // When the tab strip is painted in the immersive fullscreen light bar style,
128  // the caption buttons and the avatar button are not visible. However, their
129  // bounds are still used to compute the tab strip bounds so that the tabs have
130  // the same horizontal position when the tab strip is painted in the immersive
131  // light bar style as when the top-of-window views are revealed.
132  TabStripInsets insets(GetTabStripInsets(false));
133  return gfx::Rect(insets.left, insets.top,
134                   std::max(0, width() - insets.left - insets.right),
135                   tabstrip->GetPreferredSize().height());
136}
137
138BrowserNonClientFrameView::TabStripInsets
139BrowserNonClientFrameViewAsh::GetTabStripInsets(bool force_restored) const {
140  int left = avatar_button() ? kAvatarSideSpacing +
141      browser_view()->GetOTRAvatarIcon().width() + kAvatarSideSpacing :
142      kTabstripLeftSpacing;
143  int right = frame_painter_->GetRightInset() + kTabstripRightSpacing;
144  return TabStripInsets(NonClientTopBorderHeight(force_restored), left, right);
145}
146
147int BrowserNonClientFrameViewAsh::GetThemeBackgroundXInset() const {
148  return frame_painter_->GetThemeBackgroundXInset();
149}
150
151void BrowserNonClientFrameViewAsh::UpdateThrobber(bool running) {
152  if (window_icon_)
153    window_icon_->Update();
154}
155
156///////////////////////////////////////////////////////////////////////////////
157// views::NonClientFrameView overrides:
158
159gfx::Rect BrowserNonClientFrameViewAsh::GetBoundsForClientView() const {
160  int top_height = NonClientTopBorderHeight(false);
161  return frame_painter_->GetBoundsForClientView(top_height, bounds());
162}
163
164gfx::Rect BrowserNonClientFrameViewAsh::GetWindowBoundsForClientBounds(
165    const gfx::Rect& client_bounds) const {
166  int top_height = NonClientTopBorderHeight(false);
167  return frame_painter_->GetWindowBoundsForClientBounds(top_height,
168                                                        client_bounds);
169}
170
171int BrowserNonClientFrameViewAsh::NonClientHitTest(const gfx::Point& point) {
172  int hit_test = frame_painter_->NonClientHitTest(this, point);
173  // When the window is restored we want a large click target above the tabs
174  // to drag the window, so redirect clicks in the tab's shadow to caption.
175  if (hit_test == HTCLIENT &&
176      !(frame()->IsMaximized() || frame()->IsFullscreen())) {
177    // Convert point to client coordinates.
178    gfx::Point client_point(point);
179    View::ConvertPointToTarget(this, frame()->client_view(), &client_point);
180    // Report hits in shadow at top of tabstrip as caption.
181    gfx::Rect tabstrip_bounds(browser_view()->tabstrip()->bounds());
182    if (client_point.y() < tabstrip_bounds.y() + kTabShadowHeight)
183      hit_test = HTCAPTION;
184  }
185  return hit_test;
186}
187
188void BrowserNonClientFrameViewAsh::GetWindowMask(const gfx::Size& size,
189                                                  gfx::Path* window_mask) {
190  // Aura does not use window masks.
191}
192
193void BrowserNonClientFrameViewAsh::ResetWindowControls() {
194  // Hide the caption buttons in immersive fullscreen when the tab light bar
195  // is visible because it's confusing when the user hovers or clicks in the
196  // top-right of the screen and hits one.
197  bool button_visibility = !UseImmersiveLightbarHeaderStyle();
198  size_button_->SetVisible(button_visibility);
199  close_button_->SetVisible(button_visibility);
200
201  size_button_->SetState(views::CustomButton::STATE_NORMAL);
202  // The close button isn't affected by this constraint.
203}
204
205void BrowserNonClientFrameViewAsh::UpdateWindowIcon() {
206  if (window_icon_)
207    window_icon_->SchedulePaint();
208}
209
210void BrowserNonClientFrameViewAsh::UpdateWindowTitle() {
211  if (!frame()->IsFullscreen())
212    frame_painter_->SchedulePaintForTitle(BrowserFrame::GetTitleFont());
213}
214
215///////////////////////////////////////////////////////////////////////////////
216// views::View overrides:
217
218void BrowserNonClientFrameViewAsh::OnPaint(gfx::Canvas* canvas) {
219  if (!ShouldPaint())
220    return;
221
222  if (UseImmersiveLightbarHeaderStyle()) {
223    PaintImmersiveLightbarStyleHeader(canvas);
224    return;
225  }
226
227  // The primary header image changes based on window activation state and
228  // theme, so we look it up for each paint.
229  int theme_frame_image_id = GetThemeFrameImageId();
230  int theme_frame_overlay_image_id = GetThemeFrameOverlayImageId();
231
232  ui::ThemeProvider* theme_provider = GetThemeProvider();
233  ash::FramePainter::Themed header_themed = ash::FramePainter::THEMED_NO;
234  if (theme_provider->HasCustomImage(theme_frame_image_id) ||
235      (theme_frame_overlay_image_id != 0 &&
236       theme_provider->HasCustomImage(theme_frame_overlay_image_id))) {
237    header_themed = ash::FramePainter::THEMED_YES;
238  }
239
240  if (frame_painter_->ShouldUseMinimalHeaderStyle(header_themed))
241    theme_frame_image_id = IDR_AURA_WINDOW_HEADER_BASE_MINIMAL;
242
243  frame_painter_->PaintHeader(
244      this,
245      canvas,
246      ShouldPaintAsActive() ?
247          ash::FramePainter::ACTIVE : ash::FramePainter::INACTIVE,
248      theme_frame_image_id,
249      theme_frame_overlay_image_id);
250  if (browser_view()->ShouldShowWindowTitle())
251    frame_painter_->PaintTitleBar(this, canvas, BrowserFrame::GetTitleFont());
252  if (browser_view()->IsToolbarVisible())
253    PaintToolbarBackground(canvas);
254  else
255    PaintContentEdge(canvas);
256}
257
258void BrowserNonClientFrameViewAsh::Layout() {
259  frame_painter_->LayoutHeader(this, UseShortHeader());
260  if (avatar_button())
261    LayoutAvatar();
262  BrowserNonClientFrameView::Layout();
263}
264
265const char* BrowserNonClientFrameViewAsh::GetClassName() const {
266  return kViewClassName;
267}
268
269bool BrowserNonClientFrameViewAsh::HitTestRect(const gfx::Rect& rect) const {
270  if (!views::View::HitTestRect(rect)) {
271    // |rect| is outside BrowserNonClientFrameViewAsh's bounds.
272    return false;
273  }
274  // If the rect is outside the bounds of the client area, claim it.
275  // TODO(tdanderson): Implement View::ConvertRectToTarget().
276  gfx::Point rect_in_client_view_coords_origin(rect.origin());
277  View::ConvertPointToTarget(this, frame()->client_view(),
278      &rect_in_client_view_coords_origin);
279  gfx::Rect rect_in_client_view_coords(
280      rect_in_client_view_coords_origin, rect.size());
281  if (!frame()->client_view()->HitTestRect(rect_in_client_view_coords))
282    return true;
283
284  // Otherwise, claim |rect| only if it is above the bottom of the tabstrip in
285  // a non-tab portion.
286  TabStrip* tabstrip = browser_view()->tabstrip();
287  if (!tabstrip || !browser_view()->IsTabStripVisible())
288    return false;
289
290  gfx::Point rect_in_tabstrip_coords_origin(rect.origin());
291  View::ConvertPointToTarget(this, tabstrip,
292      &rect_in_tabstrip_coords_origin);
293  gfx::Rect rect_in_tabstrip_coords(rect_in_tabstrip_coords_origin,
294      rect.size());
295
296  if (rect_in_tabstrip_coords.bottom() > tabstrip->GetLocalBounds().bottom()) {
297    // |rect| is below the tabstrip.
298    return false;
299  }
300
301  if (tabstrip->HitTestRect(rect_in_tabstrip_coords)) {
302    // Claim |rect| if it is in a non-tab portion of the tabstrip.
303    // TODO(tdanderson): Pass |rect_in_tabstrip_coords| instead of its center
304    // point to TabStrip::IsPositionInWindowCaption() once
305    // GetEventHandlerForRect() is implemented.
306    return tabstrip->IsPositionInWindowCaption(
307        rect_in_tabstrip_coords.CenterPoint());
308  }
309
310  // We claim |rect| because it is above the bottom of the tabstrip, but
311  // not in the tabstrip. In particular, the window controls are right of
312  // the tabstrip.
313  return true;
314}
315
316void BrowserNonClientFrameViewAsh::GetAccessibleState(
317    ui::AccessibleViewState* state) {
318  state->role = ui::AccessibilityTypes::ROLE_TITLEBAR;
319}
320
321gfx::Size BrowserNonClientFrameViewAsh::GetMinimumSize() {
322  return frame_painter_->GetMinimumSize(this);
323}
324
325void BrowserNonClientFrameViewAsh::OnThemeChanged() {
326  BrowserNonClientFrameView::OnThemeChanged();
327  frame_painter_->OnThemeChanged();
328}
329
330///////////////////////////////////////////////////////////////////////////////
331// views::ButtonListener overrides:
332
333void BrowserNonClientFrameViewAsh::ButtonPressed(views::Button* sender,
334                                                 const ui::Event& event) {
335  // When shift-clicking slow down animations for visual debugging.
336  // We used to do this via an event filter that looked for the shift key being
337  // pressed but this interfered with several normal keyboard shortcuts.
338  scoped_ptr<ui::ScopedAnimationDurationScaleMode> slow_duration_mode;
339  if (event.IsShiftDown()) {
340    slow_duration_mode.reset(new ui::ScopedAnimationDurationScaleMode(
341        ui::ScopedAnimationDurationScaleMode::SLOW_DURATION));
342  }
343
344  ash::UserMetricsAction action =
345      ash::UMA_WINDOW_MAXIMIZE_BUTTON_CLICK_MAXIMIZE;
346
347  if (sender == size_button_) {
348    // The maximize button may move out from under the cursor.
349    ResetWindowControls();
350    if (size_button_minimizes_) {
351      frame()->Minimize();
352      action = ash::UMA_WINDOW_MAXIMIZE_BUTTON_CLICK_MINIMIZE;
353    } else if (frame()->IsFullscreen()) { // Can be clicked in immersive mode.
354      frame()->SetFullscreen(false);
355      action = ash::UMA_WINDOW_MAXIMIZE_BUTTON_CLICK_EXIT_FULLSCREEN;
356    } else if (frame()->IsMaximized()) {
357      frame()->Restore();
358      action = ash::UMA_WINDOW_MAXIMIZE_BUTTON_CLICK_RESTORE;
359    } else {
360      frame()->Maximize();
361    }
362    // |this| may be deleted - some windows delete their frames on maximize.
363  } else if (sender == close_button_) {
364    frame()->Close();
365    action = ash::UMA_WINDOW_CLOSE_BUTTON_CLICK;
366  } else {
367    return;
368  }
369  ChromeShellDelegate::instance()->RecordUserMetricsAction(action);
370}
371
372///////////////////////////////////////////////////////////////////////////////
373// chrome::TabIconViewModel overrides:
374
375bool BrowserNonClientFrameViewAsh::ShouldTabIconViewAnimate() const {
376  // This function is queried during the creation of the window as the
377  // TabIconView we host is initialized, so we need to NULL check the selected
378  // WebContents because in this condition there is not yet a selected tab.
379  content::WebContents* current_tab = browser_view()->GetActiveWebContents();
380  return current_tab ? current_tab->IsLoading() : false;
381}
382
383gfx::ImageSkia BrowserNonClientFrameViewAsh::GetFaviconForTabIconView() {
384  views::WidgetDelegate* delegate = frame()->widget_delegate();
385  if (!delegate)
386    return gfx::ImageSkia();
387  return delegate->GetWindowIcon();
388}
389
390///////////////////////////////////////////////////////////////////////////////
391// BrowserNonClientFrameViewAsh, private:
392
393
394int BrowserNonClientFrameViewAsh::NonClientTopBorderHeight(
395    bool force_restored) const {
396  if (force_restored)
397    return kTabstripTopSpacingTall;
398  if (!ShouldPaint() || UseImmersiveLightbarHeaderStyle())
399    return 0;
400  // Windows with tab strips need a smaller non-client area.
401  if (browser_view()->IsTabStripVisible()) {
402    if (UseShortHeader())
403      return kTabstripTopSpacingShort;
404    return kTabstripTopSpacingTall;
405  }
406  // For windows without a tab strip (popups, etc.) ensure we have enough space
407  // to see the window caption buttons.
408  return close_button_->bounds().bottom() - kContentShadowHeight;
409}
410
411bool BrowserNonClientFrameViewAsh::UseShortHeader() const {
412  // Restored browser -> tall header
413  // Maximized browser -> short header
414  // Fullscreen browser, no immersive reveal -> hidden or super short light bar
415  // Fullscreen browser, immersive reveal -> short header
416  // Popup&App window -> tall header
417  // Panel -> short header
418  // Dialogs use short header and are handled via CustomFrameViewAsh.
419  Browser* browser = browser_view()->browser();
420  switch (browser->type()) {
421    case Browser::TYPE_TABBED:
422      return frame()->IsMaximized() || frame()->IsFullscreen();
423    case Browser::TYPE_POPUP:
424      return false;
425    default:
426      NOTREACHED();
427      return false;
428  }
429}
430
431bool BrowserNonClientFrameViewAsh::UseImmersiveLightbarHeaderStyle() const {
432  ImmersiveModeController* immersive_controller =
433      browser_view()->immersive_mode_controller();
434  return immersive_controller->IsEnabled() &&
435      !immersive_controller->IsRevealed() &&
436      !immersive_controller->ShouldHideTabIndicators();
437}
438
439void BrowserNonClientFrameViewAsh::LayoutAvatar() {
440  DCHECK(avatar_button());
441  gfx::ImageSkia incognito_icon = browser_view()->GetOTRAvatarIcon();
442
443  int avatar_bottom = GetTabStripInsets(false).top +
444      browser_view()->GetTabStripHeight() - kAvatarBottomSpacing;
445  int avatar_restored_y = avatar_bottom - incognito_icon.height();
446  int avatar_y = (frame()->IsMaximized() || frame()->IsFullscreen()) ?
447      NonClientTopBorderHeight(false) + kContentShadowHeight :
448      avatar_restored_y;
449
450  // Hide the incognito icon in immersive fullscreen when the tab light bar is
451  // visible because the header is too short for the icognito icon to be
452  // recognizable.
453  bool avatar_visible = !UseImmersiveLightbarHeaderStyle();
454  int avatar_height = avatar_visible ? avatar_bottom - avatar_y : 0;
455
456  gfx::Rect avatar_bounds(kAvatarSideSpacing,
457                          avatar_y,
458                          incognito_icon.width(),
459                          avatar_height);
460  avatar_button()->SetBoundsRect(avatar_bounds);
461  avatar_button()->SetVisible(avatar_visible);
462}
463
464bool BrowserNonClientFrameViewAsh::ShouldPaint() const {
465  if (!frame()->IsFullscreen())
466    return true;
467
468  // There is nothing to paint for traditional (tab) fullscreen.
469  ImmersiveModeController* immersive_controller =
470      browser_view()->immersive_mode_controller();
471  if (!immersive_controller->IsEnabled())
472    return false;
473
474  // Need to paint during an immersive fullscreen reveal or when the immersive
475  // light bar is visible.
476  return immersive_controller->IsRevealed() ||
477      !immersive_controller->ShouldHideTabIndicators();
478}
479
480void BrowserNonClientFrameViewAsh::PaintImmersiveLightbarStyleHeader(
481    gfx::Canvas* canvas) {
482  // The light bar header is not themed because theming it does not look good.
483  gfx::ImageSkia* frame_image = GetThemeProvider()->GetImageSkiaNamed(
484      IDR_AURA_WINDOW_HEADER_BASE_MINIMAL);
485  canvas->TileImageInt(*frame_image, 0, 0, width(), frame_image->height());
486}
487
488void BrowserNonClientFrameViewAsh::PaintToolbarBackground(gfx::Canvas* canvas) {
489  gfx::Rect toolbar_bounds(browser_view()->GetToolbarBounds());
490  if (toolbar_bounds.IsEmpty())
491    return;
492  gfx::Point toolbar_origin(toolbar_bounds.origin());
493  View::ConvertPointToTarget(browser_view(), this, &toolbar_origin);
494  toolbar_bounds.set_origin(toolbar_origin);
495
496  int x = toolbar_bounds.x();
497  int w = toolbar_bounds.width();
498  int y = toolbar_bounds.y();
499  int h = toolbar_bounds.height();
500
501  // Gross hack: We split the toolbar images into two pieces, since sometimes
502  // (popup mode) the toolbar isn't tall enough to show the whole image.  The
503  // split happens between the top shadow section and the bottom gradient
504  // section so that we never break the gradient.
505  int split_point = kFrameShadowThickness * 2;
506  int bottom_y = y + split_point;
507  ui::ThemeProvider* tp = GetThemeProvider();
508  int bottom_edge_height = h - split_point;
509
510  canvas->FillRect(gfx::Rect(x, bottom_y, w, bottom_edge_height),
511                   tp->GetColor(ThemeProperties::COLOR_TOOLBAR));
512
513  // Paint the main toolbar image.  Since this image is also used to draw the
514  // tab background, we must use the tab strip offset to compute the image
515  // source y position.  If you have to debug this code use an image editor
516  // to paint a diagonal line through the toolbar image and ensure it lines up
517  // across the tab and toolbar.
518  gfx::ImageSkia* theme_toolbar = tp->GetImageSkiaNamed(IDR_THEME_TOOLBAR);
519  canvas->TileImageInt(
520      *theme_toolbar,
521      x + GetThemeBackgroundXInset(),
522      bottom_y - GetTabStripInsets(false).top,
523      x, bottom_y,
524      w, theme_toolbar->height());
525
526  // The content area line has a shadow that extends a couple of pixels above
527  // the toolbar bounds.
528  const int kContentShadowHeight = 2;
529  gfx::ImageSkia* toolbar_top = tp->GetImageSkiaNamed(IDR_TOOLBAR_SHADE_TOP);
530  canvas->TileImageInt(*toolbar_top,
531                       0, 0,
532                       x, y - kContentShadowHeight,
533                       w, split_point + kContentShadowHeight + 1);
534
535  // Draw the "lightening" shade line around the edges of the toolbar.
536  gfx::ImageSkia* toolbar_left = tp->GetImageSkiaNamed(IDR_TOOLBAR_SHADE_LEFT);
537  canvas->TileImageInt(*toolbar_left,
538                       0, 0,
539                       x + kClientEdgeThickness,
540                       y + kClientEdgeThickness + kContentShadowHeight,
541                       toolbar_left->width(), theme_toolbar->height());
542  gfx::ImageSkia* toolbar_right =
543      tp->GetImageSkiaNamed(IDR_TOOLBAR_SHADE_RIGHT);
544  canvas->TileImageInt(*toolbar_right,
545                       0, 0,
546                       w - toolbar_right->width() - 2 * kClientEdgeThickness,
547                       y + kClientEdgeThickness + kContentShadowHeight,
548                       toolbar_right->width(), theme_toolbar->height());
549
550  // Draw the content/toolbar separator.
551  canvas->FillRect(
552      gfx::Rect(x + kClientEdgeThickness,
553                toolbar_bounds.bottom() - kClientEdgeThickness,
554                w - (2 * kClientEdgeThickness),
555                kClientEdgeThickness),
556      ThemeProperties::GetDefaultColor(
557          ThemeProperties::COLOR_TOOLBAR_SEPARATOR));
558}
559
560void BrowserNonClientFrameViewAsh::PaintContentEdge(gfx::Canvas* canvas) {
561  canvas->FillRect(gfx::Rect(0, close_button_->bounds().bottom(),
562                             width(), kClientEdgeThickness),
563      ThemeProperties::GetDefaultColor(
564          ThemeProperties::COLOR_TOOLBAR_SEPARATOR));
565}
566
567int BrowserNonClientFrameViewAsh::GetThemeFrameImageId() const {
568  bool is_incognito = browser_view()->IsOffTheRecord() &&
569                      !browser_view()->IsGuestSession();
570  if (browser_view()->IsBrowserTypeNormal()) {
571    // Use the standard resource ids to allow users to theme the frames.
572    if (ShouldPaintAsActive()) {
573      return is_incognito ?
574          IDR_THEME_FRAME_INCOGNITO : IDR_THEME_FRAME;
575    }
576    return is_incognito ?
577        IDR_THEME_FRAME_INCOGNITO_INACTIVE : IDR_THEME_FRAME_INACTIVE;
578  }
579  // Never theme app and popup windows.
580  if (ShouldPaintAsActive()) {
581    return is_incognito ?
582        IDR_AURA_WINDOW_HEADER_BASE_INCOGNITO_ACTIVE :
583        IDR_AURA_WINDOW_HEADER_BASE_ACTIVE;
584  }
585  return is_incognito ?
586      IDR_AURA_WINDOW_HEADER_BASE_INCOGNITO_INACTIVE :
587      IDR_AURA_WINDOW_HEADER_BASE_INACTIVE;
588}
589
590int BrowserNonClientFrameViewAsh::GetThemeFrameOverlayImageId() const {
591  ui::ThemeProvider* tp = GetThemeProvider();
592  if (tp->HasCustomImage(IDR_THEME_FRAME_OVERLAY) &&
593      browser_view()->IsBrowserTypeNormal() &&
594      !browser_view()->IsOffTheRecord()) {
595    return ShouldPaintAsActive() ?
596        IDR_THEME_FRAME_OVERLAY : IDR_THEME_FRAME_OVERLAY_INACTIVE;
597  }
598  return 0;
599}
600