browser_non_client_frame_view_ash.cc revision 868fa2fe829687343ffae624259930155e16dbd8
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  TabStripInsets insets(GetTabStripInsets(false));
127  return gfx::Rect(insets.left, insets.top,
128                   std::max(0, width() - insets.left - insets.right),
129                   tabstrip->GetPreferredSize().height());
130}
131
132BrowserNonClientFrameView::TabStripInsets
133BrowserNonClientFrameViewAsh::GetTabStripInsets(bool force_restored) const {
134  int left = avatar_button() ? kAvatarSideSpacing +
135      browser_view()->GetOTRAvatarIcon().width() + kAvatarSideSpacing :
136      kTabstripLeftSpacing;
137  if (avatar_label()) {
138    left += avatar_label()->GetPreferredSize().width() +
139            views::kRelatedControlHorizontalSpacing;
140  }
141  int right = frame_painter_->GetRightInset() + kTabstripRightSpacing;
142  return TabStripInsets(NonClientTopBorderHeight(force_restored), left, right);
143}
144
145int BrowserNonClientFrameViewAsh::GetThemeBackgroundXInset() const {
146  return frame_painter_->GetThemeBackgroundXInset();
147}
148
149void BrowserNonClientFrameViewAsh::UpdateThrobber(bool running) {
150  if (window_icon_)
151    window_icon_->Update();
152}
153
154///////////////////////////////////////////////////////////////////////////////
155// views::NonClientFrameView overrides:
156
157gfx::Rect BrowserNonClientFrameViewAsh::GetBoundsForClientView() const {
158  int top_height = NonClientTopBorderHeight(false);
159  return frame_painter_->GetBoundsForClientView(top_height, bounds());
160}
161
162gfx::Rect BrowserNonClientFrameViewAsh::GetWindowBoundsForClientBounds(
163    const gfx::Rect& client_bounds) const {
164  int top_height = NonClientTopBorderHeight(false);
165  return frame_painter_->GetWindowBoundsForClientBounds(top_height,
166                                                        client_bounds);
167}
168
169int BrowserNonClientFrameViewAsh::NonClientHitTest(const gfx::Point& point) {
170  int hit_test = frame_painter_->NonClientHitTest(this, point);
171  // When the window is restored we want a large click target above the tabs
172  // to drag the window, so redirect clicks in the tab's shadow to caption.
173  if (hit_test == HTCLIENT &&
174      !(frame()->IsMaximized() || frame()->IsFullscreen())) {
175    // Convert point to client coordinates.
176    gfx::Point client_point(point);
177    View::ConvertPointToTarget(this, frame()->client_view(), &client_point);
178    // Report hits in shadow at top of tabstrip as caption.
179    gfx::Rect tabstrip_bounds(browser_view()->tabstrip()->bounds());
180    if (client_point.y() < tabstrip_bounds.y() + kTabShadowHeight)
181      hit_test = HTCAPTION;
182  }
183  return hit_test;
184}
185
186void BrowserNonClientFrameViewAsh::GetWindowMask(const gfx::Size& size,
187                                                  gfx::Path* window_mask) {
188  // Aura does not use window masks.
189}
190
191void BrowserNonClientFrameViewAsh::ResetWindowControls() {
192  if (ImmersiveFullscreenConfiguration::UseImmersiveFullscreen()) {
193    // Hide the caption buttons in immersive mode because it's confusing when
194    // the user hovers or clicks in the top-right of the screen and hits one.
195    // Only show them during a reveal.
196    ImmersiveModeController* controller =
197        browser_view()->immersive_mode_controller();
198    if (controller->IsEnabled()) {
199      bool revealed = controller->IsRevealed();
200      size_button_->SetVisible(revealed);
201      close_button_->SetVisible(revealed);
202    } else {
203      size_button_->SetVisible(true);
204      close_button_->SetVisible(true);
205    }
206  }
207
208  size_button_->SetState(views::CustomButton::STATE_NORMAL);
209  // The close button isn't affected by this constraint.
210}
211
212void BrowserNonClientFrameViewAsh::UpdateWindowIcon() {
213  if (window_icon_)
214    window_icon_->SchedulePaint();
215}
216
217void BrowserNonClientFrameViewAsh::UpdateWindowTitle() {
218  if (!frame()->IsFullscreen())
219    frame_painter_->SchedulePaintForTitle(this, BrowserFrame::GetTitleFont());
220}
221
222///////////////////////////////////////////////////////////////////////////////
223// views::View overrides:
224
225void BrowserNonClientFrameViewAsh::OnPaint(gfx::Canvas* canvas) {
226  if (!ShouldPaint())
227    return;
228  // The primary header image changes based on window activation state and
229  // theme, so we look it up for each paint.
230  int theme_frame_image_id = GetThemeFrameImageId();
231  int theme_frame_overlay_image_id = GetThemeFrameOverlayImageId();
232
233  ui::ThemeProvider* theme_provider = GetThemeProvider();
234  ash::FramePainter::Themed header_themed = ash::FramePainter::THEMED_NO;
235  if (theme_provider->HasCustomImage(theme_frame_image_id) ||
236      (theme_frame_overlay_image_id != 0 &&
237       theme_provider->HasCustomImage(theme_frame_overlay_image_id))) {
238    header_themed = ash::FramePainter::THEMED_YES;
239  }
240
241  if (frame_painter_->ShouldUseMinimalHeaderStyle(header_themed))
242    theme_frame_image_id = IDR_AURA_WINDOW_HEADER_BASE_MINIMAL;
243
244  frame_painter_->PaintHeader(
245      this,
246      canvas,
247      ShouldPaintAsActive() ?
248          ash::FramePainter::ACTIVE : ash::FramePainter::INACTIVE,
249      theme_frame_image_id,
250      theme_frame_overlay_image_id);
251  if (browser_view()->ShouldShowWindowTitle())
252    frame_painter_->PaintTitleBar(this, canvas, BrowserFrame::GetTitleFont());
253  if (browser_view()->IsToolbarVisible())
254    PaintToolbarBackground(canvas);
255  else
256    PaintContentEdge(canvas);
257}
258
259void BrowserNonClientFrameViewAsh::Layout() {
260  frame_painter_->LayoutHeader(this, UseShortHeader());
261  if (avatar_button())
262    LayoutAvatar();
263  BrowserNonClientFrameView::Layout();
264}
265
266const char* BrowserNonClientFrameViewAsh::GetClassName() const {
267  return kViewClassName;
268}
269
270bool BrowserNonClientFrameViewAsh::HitTestRect(const gfx::Rect& rect) const {
271  // If the rect is outside the bounds of the client area, claim it.
272  if (NonClientFrameView::HitTestRect(rect))
273    return true;
274
275  // Otherwise claim it only if it's in a non-tab portion of the tabstrip.
276  if (!browser_view()->tabstrip())
277    return false;
278  gfx::Rect tabstrip_bounds(browser_view()->tabstrip()->bounds());
279  gfx::Point tabstrip_origin(tabstrip_bounds.origin());
280  View::ConvertPointToTarget(frame()->client_view(), this, &tabstrip_origin);
281  tabstrip_bounds.set_origin(tabstrip_origin);
282  if (rect.bottom() > tabstrip_bounds.bottom())
283    return false;
284
285  // We convert from our parent's coordinates since we assume we fill its bounds
286  // completely. We need to do this since we're not a parent of the tabstrip,
287  // meaning ConvertPointToTarget would otherwise return something bogus.
288  // TODO(tdanderson): Initialize |browser_view_point| using |rect| instead of
289  // its center point once GetEventHandlerForRect() is implemented.
290  gfx::Point browser_view_point(rect.CenterPoint());
291  View::ConvertPointToTarget(parent(), browser_view(), &browser_view_point);
292  return browser_view()->IsPositionInWindowCaption(browser_view_point);
293}
294
295void BrowserNonClientFrameViewAsh::GetAccessibleState(
296    ui::AccessibleViewState* state) {
297  state->role = ui::AccessibilityTypes::ROLE_TITLEBAR;
298}
299
300gfx::Size BrowserNonClientFrameViewAsh::GetMinimumSize() {
301  return frame_painter_->GetMinimumSize(this);
302}
303
304void BrowserNonClientFrameViewAsh::OnThemeChanged() {
305  BrowserNonClientFrameView::OnThemeChanged();
306  frame_painter_->OnThemeChanged();
307}
308
309///////////////////////////////////////////////////////////////////////////////
310// views::ButtonListener overrides:
311
312void BrowserNonClientFrameViewAsh::ButtonPressed(views::Button* sender,
313                                                 const ui::Event& event) {
314  // When shift-clicking slow down animations for visual debugging.
315  // We used to do this via an event filter that looked for the shift key being
316  // pressed but this interfered with several normal keyboard shortcuts.
317  scoped_ptr<ui::ScopedAnimationDurationScaleMode> slow_duration_mode;
318  if (event.IsShiftDown()) {
319    slow_duration_mode.reset(new ui::ScopedAnimationDurationScaleMode(
320        ui::ScopedAnimationDurationScaleMode::SLOW_DURATION));
321  }
322
323  ash::UserMetricsAction action =
324      ash::UMA_WINDOW_MAXIMIZE_BUTTON_CLICK_MAXIMIZE;
325
326  if (sender == size_button_) {
327    // The maximize button may move out from under the cursor.
328    ResetWindowControls();
329    if (size_button_minimizes_) {
330      frame()->Minimize();
331      action = ash::UMA_WINDOW_MAXIMIZE_BUTTON_CLICK_MINIMIZE;
332    } else if (frame()->IsFullscreen()) { // Can be clicked in immersive mode.
333      frame()->SetFullscreen(false);
334      action = ash::UMA_WINDOW_MAXIMIZE_BUTTON_CLICK_EXIT_FULLSCREEN;
335    } else if (frame()->IsMaximized()) {
336      frame()->Restore();
337      action = ash::UMA_WINDOW_MAXIMIZE_BUTTON_CLICK_RESTORE;
338    } else {
339      frame()->Maximize();
340    }
341    // |this| may be deleted - some windows delete their frames on maximize.
342  } else if (sender == close_button_) {
343    frame()->Close();
344    action = ash::UMA_WINDOW_CLOSE_BUTTON_CLICK;
345  } else {
346    return;
347  }
348  ChromeShellDelegate::instance()->RecordUserMetricsAction(action);
349}
350
351///////////////////////////////////////////////////////////////////////////////
352// chrome::TabIconViewModel overrides:
353
354bool BrowserNonClientFrameViewAsh::ShouldTabIconViewAnimate() const {
355  // This function is queried during the creation of the window as the
356  // TabIconView we host is initialized, so we need to NULL check the selected
357  // WebContents because in this condition there is not yet a selected tab.
358  content::WebContents* current_tab = browser_view()->GetActiveWebContents();
359  return current_tab ? current_tab->IsLoading() : false;
360}
361
362gfx::ImageSkia BrowserNonClientFrameViewAsh::GetFaviconForTabIconView() {
363  views::WidgetDelegate* delegate = frame()->widget_delegate();
364  if (!delegate)
365    return gfx::ImageSkia();
366  return delegate->GetWindowIcon();
367}
368
369///////////////////////////////////////////////////////////////////////////////
370// BrowserNonClientFrameViewAsh, private:
371
372
373int BrowserNonClientFrameViewAsh::NonClientTopBorderHeight(
374    bool force_restored) const {
375  if (force_restored)
376    return kTabstripTopSpacingTall;
377  if (frame()->IsFullscreen())
378    return 0;
379  // Windows with tab strips need a smaller non-client area.
380  if (browser_view()->IsTabStripVisible()) {
381    if (UseShortHeader())
382      return kTabstripTopSpacingShort;
383    return kTabstripTopSpacingTall;
384  }
385  // For windows without a tab strip (popups, etc.) ensure we have enough space
386  // to see the window caption buttons.
387  return close_button_->bounds().bottom() - kContentShadowHeight;
388}
389
390bool BrowserNonClientFrameViewAsh::UseShortHeader() const {
391  // Restored browser -> tall header
392  // Maximized browser -> short header
393  // Fullscreen browser (header shows with immersive reveal) -> short header
394  // Popup&App window -> tall header
395  // Panel -> short header
396  // Dialogs use short header and are handled via CustomFrameViewAsh.
397  Browser* browser = browser_view()->browser();
398  switch (browser->type()) {
399    case Browser::TYPE_TABBED:
400      return frame()->IsMaximized() || frame()->IsFullscreen();
401    case Browser::TYPE_POPUP:
402      return false;
403    default:
404      NOTREACHED();
405      return false;
406  }
407}
408
409void BrowserNonClientFrameViewAsh::LayoutAvatar() {
410  DCHECK(avatar_button());
411  gfx::ImageSkia incognito_icon = browser_view()->GetOTRAvatarIcon();
412
413  if (frame()->IsFullscreen()) {
414    ImmersiveModeController* immersive_controller =
415        browser_view()->immersive_mode_controller();
416    // Hide the incognito icon when the top-of-window views are closed in
417    // immersive mode as the tab indicators are too short for the incognito
418    // icon to still be recongizable.
419    if (immersive_controller->IsEnabled() &&
420        !immersive_controller->IsRevealed()) {
421      avatar_button()->SetBoundsRect(gfx::Rect());
422      if (avatar_label())
423        avatar_label()->SetBoundsRect(gfx::Rect());
424      return;
425    }
426  }
427
428  int avatar_bottom = GetTabStripInsets(false).top +
429      browser_view()->GetTabStripHeight() - kAvatarBottomSpacing;
430  int avatar_restored_y = avatar_bottom - incognito_icon.height();
431  int avatar_y = (frame()->IsMaximized() || frame()->IsFullscreen()) ?
432      NonClientTopBorderHeight(false) + kContentShadowHeight :
433      avatar_restored_y;
434  gfx::Rect avatar_bounds(kAvatarSideSpacing,
435                          avatar_y,
436                          incognito_icon.width(),
437                          avatar_bottom - avatar_y);
438  avatar_button()->SetBoundsRect(avatar_bounds);
439  if (avatar_label()) {
440    gfx::Size size = avatar_label()->GetPreferredSize();
441    int label_height = std::min(avatar_bounds.height(), size.height());
442    gfx::Rect label_bounds(
443        avatar_bounds.right() + views::kRelatedControlHorizontalSpacing,
444        avatar_y + (avatar_bounds.height() - label_height) / 2,
445        size.width(),
446        size.height());
447    avatar_label()->SetBoundsRect(label_bounds);
448  }
449}
450
451bool BrowserNonClientFrameViewAsh::ShouldPaint() const {
452  // Immersive mode windows are fullscreen, but need to paint during a reveal.
453  return !frame()->IsFullscreen() ||
454      browser_view()->immersive_mode_controller()->IsRevealed();
455}
456
457void BrowserNonClientFrameViewAsh::PaintToolbarBackground(gfx::Canvas* canvas) {
458  gfx::Rect toolbar_bounds(browser_view()->GetToolbarBounds());
459  if (toolbar_bounds.IsEmpty())
460    return;
461  gfx::Point toolbar_origin(toolbar_bounds.origin());
462  View::ConvertPointToTarget(browser_view(), this, &toolbar_origin);
463  toolbar_bounds.set_origin(toolbar_origin);
464
465  int x = toolbar_bounds.x();
466  int w = toolbar_bounds.width();
467  int y = toolbar_bounds.y();
468  int h = toolbar_bounds.height();
469
470  // Gross hack: We split the toolbar images into two pieces, since sometimes
471  // (popup mode) the toolbar isn't tall enough to show the whole image.  The
472  // split happens between the top shadow section and the bottom gradient
473  // section so that we never break the gradient.
474  int split_point = kFrameShadowThickness * 2;
475  int bottom_y = y + split_point;
476  ui::ThemeProvider* tp = GetThemeProvider();
477  int bottom_edge_height = h - split_point;
478
479  canvas->FillRect(gfx::Rect(x, bottom_y, w, bottom_edge_height),
480                   tp->GetColor(ThemeProperties::COLOR_TOOLBAR));
481
482  // Paint the main toolbar image.  Since this image is also used to draw the
483  // tab background, we must use the tab strip offset to compute the image
484  // source y position.  If you have to debug this code use an image editor
485  // to paint a diagonal line through the toolbar image and ensure it lines up
486  // across the tab and toolbar.
487  gfx::ImageSkia* theme_toolbar = tp->GetImageSkiaNamed(IDR_THEME_TOOLBAR);
488  canvas->TileImageInt(
489      *theme_toolbar,
490      x + GetThemeBackgroundXInset(),
491      bottom_y - GetTabStripInsets(false).top,
492      x, bottom_y,
493      w, theme_toolbar->height());
494
495  // The content area line has a shadow that extends a couple of pixels above
496  // the toolbar bounds.
497  const int kContentShadowHeight = 2;
498  gfx::ImageSkia* toolbar_top = tp->GetImageSkiaNamed(IDR_TOOLBAR_SHADE_TOP);
499  canvas->TileImageInt(*toolbar_top,
500                       0, 0,
501                       x, y - kContentShadowHeight,
502                       w, split_point + kContentShadowHeight + 1);
503
504  // Draw the "lightening" shade line around the edges of the toolbar.
505  gfx::ImageSkia* toolbar_left = tp->GetImageSkiaNamed(IDR_TOOLBAR_SHADE_LEFT);
506  canvas->TileImageInt(*toolbar_left,
507                       0, 0,
508                       x + kClientEdgeThickness,
509                       y + kClientEdgeThickness + kContentShadowHeight,
510                       toolbar_left->width(), theme_toolbar->height());
511  gfx::ImageSkia* toolbar_right =
512      tp->GetImageSkiaNamed(IDR_TOOLBAR_SHADE_RIGHT);
513  canvas->TileImageInt(*toolbar_right,
514                       0, 0,
515                       w - toolbar_right->width() - 2 * kClientEdgeThickness,
516                       y + kClientEdgeThickness + kContentShadowHeight,
517                       toolbar_right->width(), theme_toolbar->height());
518
519  // Draw the content/toolbar separator.
520  canvas->FillRect(
521      gfx::Rect(x + kClientEdgeThickness,
522                toolbar_bounds.bottom() - kClientEdgeThickness,
523                w - (2 * kClientEdgeThickness),
524                kClientEdgeThickness),
525      ThemeProperties::GetDefaultColor(
526          ThemeProperties::COLOR_TOOLBAR_SEPARATOR));
527}
528
529void BrowserNonClientFrameViewAsh::PaintContentEdge(gfx::Canvas* canvas) {
530  canvas->FillRect(gfx::Rect(0, close_button_->bounds().bottom(),
531                             width(), kClientEdgeThickness),
532      ThemeProperties::GetDefaultColor(
533          ThemeProperties::COLOR_TOOLBAR_SEPARATOR));
534}
535
536int BrowserNonClientFrameViewAsh::GetThemeFrameImageId() const {
537  bool is_incognito = browser_view()->IsOffTheRecord() &&
538                      !browser_view()->IsGuestSession();
539  if (browser_view()->IsBrowserTypeNormal()) {
540    // Use the standard resource ids to allow users to theme the frames.
541    if (ShouldPaintAsActive()) {
542      return is_incognito ?
543          IDR_THEME_FRAME_INCOGNITO : IDR_THEME_FRAME;
544    }
545    return is_incognito ?
546        IDR_THEME_FRAME_INCOGNITO_INACTIVE : IDR_THEME_FRAME_INACTIVE;
547  }
548  // Never theme app and popup windows.
549  if (ShouldPaintAsActive()) {
550    return is_incognito ?
551        IDR_AURA_WINDOW_HEADER_BASE_INCOGNITO_ACTIVE :
552        IDR_AURA_WINDOW_HEADER_BASE_ACTIVE;
553  }
554  return is_incognito ?
555      IDR_AURA_WINDOW_HEADER_BASE_INCOGNITO_INACTIVE :
556      IDR_AURA_WINDOW_HEADER_BASE_INACTIVE;
557}
558
559int BrowserNonClientFrameViewAsh::GetThemeFrameOverlayImageId() const {
560  ui::ThemeProvider* tp = GetThemeProvider();
561  if (tp->HasCustomImage(IDR_THEME_FRAME_OVERLAY) &&
562      browser_view()->IsBrowserTypeNormal() &&
563      !browser_view()->IsOffTheRecord()) {
564    return ShouldPaintAsActive() ?
565        IDR_THEME_FRAME_OVERLAY : IDR_THEME_FRAME_OVERLAY_INACTIVE;
566  }
567  return 0;
568}
569