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