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