opaque_browser_frame_view.cc revision a1401311d1ab56c4ed0a474bd38c108f75cb0cd9
15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/views/frame/opaque_browser_frame_view.h" 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <algorithm> 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <string> 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "base/compiler_specific.h" 11f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "base/prefs/pref_service.h" 125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/strings/utf_string_conversions.h" 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/chrome_notification_types.h" 142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/profiles/profiles_state.h" 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/themes/theme_properties.h" 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/views/avatar_label.h" 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/views/avatar_menu_button.h" 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/views/frame/browser_frame.h" 196e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)#include "chrome/browser/ui/views/frame/browser_view.h" 206e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)#include "chrome/browser/ui/views/frame/opaque_browser_frame_view_layout.h" 216e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)#include "chrome/browser/ui/views/frame/opaque_browser_frame_view_platform_specific.h" 226e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)#include "chrome/browser/ui/views/new_avatar_button.h" 236e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)#include "chrome/browser/ui/views/tab_icon_view.h" 246e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)#include "chrome/browser/ui/views/tabs/tab_strip.h" 256e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)#include "chrome/browser/ui/views/theme_image_mapper.h" 266e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)#include "chrome/browser/ui/views/toolbar/toolbar_view.h" 276e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)#include "chrome/common/pref_names.h" 282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/common/profile_management_switches.h" 296d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)#include "content/public/browser/notification_service.h" 306d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)#include "content/public/browser/web_contents.h" 312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "grit/chromium_strings.h" 322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "grit/generated_resources.h" 336d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)#include "grit/theme_resources.h" 342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "grit/ui_resources.h" 352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ui/accessibility/ax_view_state.h" 362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ui/base/hit_test.h" 372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ui/base/l10n/l10n_util.h" 385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "ui/base/resource/resource_bundle.h" 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/base/theme_provider.h" 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gfx/canvas.h" 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gfx/font_list.h" 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gfx/image/image.h" 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gfx/image/image_skia.h" 44a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "ui/gfx/path.h" 45a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "ui/gfx/rect_conversions.h" 46a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "ui/views/controls/button/image_button.h" 47a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "ui/views/controls/image_view.h" 48a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "ui/views/controls/label.h" 49a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "ui/views/layout/layout_constants.h" 502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ui/views/views_delegate.h" 512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ui/views/widget/root_view.h" 522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ui/views/window/frame_background.h" 53a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch#include "ui/views/window/window_shape.h" 542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 55a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#if defined(OS_LINUX) 562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ui/views/controls/menu/menu_runner.h" 572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#endif 5890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 596e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)using content::WebContents; 606e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 616e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)namespace { 626e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 636e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)// While resize areas on Windows are normally the same size as the window 646e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)// borders, our top area is shrunk by 1 px to make it easier to move the window 6590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// around with our thinner top grabbable strip. (Incidentally, our side and 666e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)// bottom resize areas don't match the frame border thickness either -- they 67a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch// span the whole nonclient area, so there's no "dead zone" for the mouse.) 6890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)const int kTopResizeAdjust = 1; 6990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 7090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// In the window corners, the resize areas don't actually expand bigger, but the 7190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// 16 px at the end of each edge triggers diagonal resizing. 72a3f7b4e666c476898878fa745f637129375cd889Ben Murdochconst int kResizeAreaCornerSize = 16; 73a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch 74a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch// The content left/right images have a shadow built into them. 75a3f7b4e666c476898878fa745f637129375cd889Ben Murdochconst int kContentEdgeShadowThickness = 2; 76a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch 7790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// The icon never shrinks below 16 px on a side. 7890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)const int kIconMinimumSize = 16; 7990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 8090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#if defined(OS_LINUX) && !defined(OS_CHROMEOS) 8190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// The number of pixels to move the frame background image upwards when using 8290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// the GTK+ theme and the titlebar is condensed. 8390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)const int kGTKThemeCondensedFrameTopInset = 15; 8490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#endif 856e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 8690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)} // namespace 8790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 8890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)/////////////////////////////////////////////////////////////////////////////// 896e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)// OpaqueBrowserFrameView, public: 9090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 9190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)OpaqueBrowserFrameView::OpaqueBrowserFrameView(BrowserFrame* frame, 9290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) BrowserView* browser_view) 936e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) : BrowserNonClientFrameView(frame, browser_view), 946e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) layout_(new OpaqueBrowserFrameViewLayout(this)), 9590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) minimize_button_(NULL), 9690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) maximize_button_(NULL), 9790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) restore_button_(NULL), 9890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) close_button_(NULL), 9990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) window_icon_(NULL), 10090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) window_title_(NULL), 10190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) frame_background_(new views::FrameBackground()) { 10290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) SetLayoutManager(layout_); 10390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 10490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) if (OpaqueBrowserFrameViewLayout::ShouldAddDefaultCaptionButtons()) { 10590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) minimize_button_ = InitWindowCaptionButton(IDR_MINIMIZE, 10690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) IDR_MINIMIZE_H, 10790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) IDR_MINIMIZE_P, 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) IDR_MINIMIZE_BUTTON_MASK, 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) IDS_ACCNAME_MINIMIZE, 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) VIEW_ID_MINIMIZE_BUTTON); 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) maximize_button_ = InitWindowCaptionButton(IDR_MAXIMIZE, 1122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) IDR_MAXIMIZE_H, 1132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) IDR_MAXIMIZE_P, 114a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) IDR_MAXIMIZE_BUTTON_MASK, 1155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) IDS_ACCNAME_MAXIMIZE, 1165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) VIEW_ID_MAXIMIZE_BUTTON); 1172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) restore_button_ = InitWindowCaptionButton(IDR_RESTORE, 1182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) IDR_RESTORE_H, 1192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) IDR_RESTORE_P, 120a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) IDR_RESTORE_BUTTON_MASK, 121a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) IDS_ACCNAME_RESTORE, 1222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) VIEW_ID_RESTORE_BUTTON); 1232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) close_button_ = InitWindowCaptionButton(IDR_CLOSE, 1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) IDR_CLOSE_H, 1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) IDR_CLOSE_P, 1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) IDR_CLOSE_BUTTON_MASK, 1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) IDS_ACCNAME_CLOSE, 128424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) VIEW_ID_CLOSE_BUTTON); 129424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) } 130424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) 131424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) // Initializing the TabIconView is expensive, so only do it if we need to. 132424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) if (browser_view->ShouldShowWindowIcon()) { 133a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) window_icon_ = new TabIconView(this, this); 1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) window_icon_->set_is_light(true); 1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) window_icon_->set_id(VIEW_ID_WINDOW_ICON); 136424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) AddChildView(window_icon_); 1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) window_icon_->Update(); 1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 140424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) window_title_ = new views::Label( 141424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) browser_view->GetWindowTitle(), 142424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) gfx::FontList(BrowserFrame::GetTitleFontList())); 143424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) window_title_->SetVisible(browser_view->ShouldShowWindowTitle()); 1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) window_title_->SetEnabledColor(SK_ColorWHITE); 1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // TODO(msw): Use a transparent background color as a workaround to use the 1462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // gfx::Canvas::NO_SUBPIXEL_RENDERING flag and avoid some visual artifacts. 1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) window_title_->SetBackgroundColor(0x00000000); 1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) window_title_->SetHorizontalAlignment(gfx::ALIGN_LEFT); 1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) window_title_->set_id(VIEW_ID_WINDOW_TITLE); 1502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) AddChildView(window_title_); 1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (browser_view->IsRegularOrGuestSession() && 1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) switches::IsNewProfileManagement()) 1542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) UpdateNewStyleAvatarInfo(this, NewAvatarButton::THEMED_BUTTON); 1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else 1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) UpdateAvatarInfo(); 1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!browser_view->IsOffTheRecord()) { 1592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) registrar_.Add(this, chrome::NOTIFICATION_PROFILE_CACHED_INFO_CHANGED, 1602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) content::NotificationService::AllSources()); 1612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 1622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) platform_observer_.reset(OpaqueBrowserFrameViewPlatformSpecific::Create( 1642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) this, layout_, browser_view->browser()->profile())); 1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 16790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)OpaqueBrowserFrameView::~OpaqueBrowserFrameView() { 168a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)} 16990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 1702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)/////////////////////////////////////////////////////////////////////////////// 1712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// OpaqueBrowserFrameView, BrowserNonClientFrameView implementation: 1722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)gfx::Rect OpaqueBrowserFrameView::GetBoundsForTabStrip( 1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) views::View* tabstrip) const { 1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!tabstrip) 176 return gfx::Rect(); 177 178 return layout_->GetBoundsForTabStrip(tabstrip->GetPreferredSize(), width()); 179} 180 181int OpaqueBrowserFrameView::GetTopInset() const { 182 return browser_view()->IsTabStripVisible() ? 183 layout_->GetTabStripInsetsTop(false) : 184 layout_->NonClientTopBorderHeight(false); 185} 186 187int OpaqueBrowserFrameView::GetThemeBackgroundXInset() const { 188 return 0; 189} 190 191void OpaqueBrowserFrameView::UpdateThrobber(bool running) { 192 if (window_icon_) 193 window_icon_->Update(); 194} 195 196gfx::Size OpaqueBrowserFrameView::GetMinimumSize() { 197 return layout_->GetMinimumSize(width()); 198} 199 200/////////////////////////////////////////////////////////////////////////////// 201// OpaqueBrowserFrameView, views::NonClientFrameView implementation: 202 203gfx::Rect OpaqueBrowserFrameView::GetBoundsForClientView() const { 204 return layout_->client_view_bounds(); 205} 206 207gfx::Rect OpaqueBrowserFrameView::GetWindowBoundsForClientBounds( 208 const gfx::Rect& client_bounds) const { 209 return layout_->GetWindowBoundsForClientBounds(client_bounds); 210} 211 212int OpaqueBrowserFrameView::NonClientHitTest(const gfx::Point& point) { 213 if (!bounds().Contains(point)) 214 return HTNOWHERE; 215 216 // See if the point is within the avatar menu button or within the avatar 217 // label. 218 if ((avatar_button() && 219 avatar_button()->GetMirroredBounds().Contains(point)) || 220 (avatar_label() && avatar_label()->GetMirroredBounds().Contains(point)) || 221 (new_avatar_button() && 222 new_avatar_button()->GetMirroredBounds().Contains(point))) 223 return HTCLIENT; 224 225 int frame_component = frame()->client_view()->NonClientHitTest(point); 226 227 // See if we're in the sysmenu region. We still have to check the tabstrip 228 // first so that clicks in a tab don't get treated as sysmenu clicks. 229 gfx::Rect sysmenu_rect(IconBounds()); 230 // In maximized mode we extend the rect to the screen corner to take advantage 231 // of Fitts' Law. 232 if (layout_->IsTitleBarCondensed()) 233 sysmenu_rect.SetRect(0, 0, sysmenu_rect.right(), sysmenu_rect.bottom()); 234 sysmenu_rect.set_x(GetMirroredXForRect(sysmenu_rect)); 235 if (sysmenu_rect.Contains(point)) 236 return (frame_component == HTCLIENT) ? HTCLIENT : HTSYSMENU; 237 238 if (frame_component != HTNOWHERE) 239 return frame_component; 240 241 // Then see if the point is within any of the window controls. 242 if (close_button_ && close_button_->visible() && 243 close_button_->GetMirroredBounds().Contains(point)) 244 return HTCLOSE; 245 if (restore_button_ && restore_button_->visible() && 246 restore_button_->GetMirroredBounds().Contains(point)) 247 return HTMAXBUTTON; 248 if (maximize_button_ && maximize_button_->visible() && 249 maximize_button_->GetMirroredBounds().Contains(point)) 250 return HTMAXBUTTON; 251 if (minimize_button_ && minimize_button_->visible() && 252 minimize_button_->GetMirroredBounds().Contains(point)) 253 return HTMINBUTTON; 254 255 views::WidgetDelegate* delegate = frame()->widget_delegate(); 256 if (!delegate) { 257 LOG(WARNING) << "delegate is NULL, returning safe default."; 258 return HTCAPTION; 259 } 260 int window_component = GetHTComponentForFrame(point, TopResizeHeight(), 261 NonClientBorderThickness(), kResizeAreaCornerSize, kResizeAreaCornerSize, 262 delegate->CanResize()); 263 // Fall back to the caption if no other component matches. 264 return (window_component == HTNOWHERE) ? HTCAPTION : window_component; 265} 266 267void OpaqueBrowserFrameView::GetWindowMask(const gfx::Size& size, 268 gfx::Path* window_mask) { 269 DCHECK(window_mask); 270 271 if (layout_->IsTitleBarCondensed() || frame()->IsFullscreen()) 272 return; 273 274 views::GetDefaultWindowMask(size, window_mask); 275} 276 277void OpaqueBrowserFrameView::ResetWindowControls() { 278 if (!OpaqueBrowserFrameViewLayout::ShouldAddDefaultCaptionButtons()) 279 return; 280 restore_button_->SetState(views::CustomButton::STATE_NORMAL); 281 minimize_button_->SetState(views::CustomButton::STATE_NORMAL); 282 maximize_button_->SetState(views::CustomButton::STATE_NORMAL); 283 // The close button isn't affected by this constraint. 284} 285 286void OpaqueBrowserFrameView::UpdateWindowIcon() { 287 window_icon_->SchedulePaint(); 288} 289 290void OpaqueBrowserFrameView::UpdateWindowTitle() { 291 if (!frame()->IsFullscreen()) 292 window_title_->SchedulePaint(); 293} 294 295/////////////////////////////////////////////////////////////////////////////// 296// OpaqueBrowserFrameView, views::View overrides: 297 298bool OpaqueBrowserFrameView::HitTestRect(const gfx::Rect& rect) const { 299 if (!views::View::HitTestRect(rect)) { 300 // |rect| is outside OpaqueBrowserFrameView's bounds. 301 return false; 302 } 303 304 // If the rect is outside the bounds of the client area, claim it. 305 gfx::RectF rect_in_client_view_coords_f(rect); 306 View::ConvertRectToTarget(this, frame()->client_view(), 307 &rect_in_client_view_coords_f); 308 gfx::Rect rect_in_client_view_coords = gfx::ToEnclosingRect( 309 rect_in_client_view_coords_f); 310 if (!frame()->client_view()->HitTestRect(rect_in_client_view_coords)) 311 return true; 312 313 // Otherwise, claim |rect| only if it is above the bottom of the tabstrip in 314 // a non-tab portion. 315 TabStrip* tabstrip = browser_view()->tabstrip(); 316 if (!tabstrip || !browser_view()->IsTabStripVisible()) 317 return false; 318 319 gfx::RectF rect_in_tabstrip_coords_f(rect); 320 View::ConvertRectToTarget(this, tabstrip, &rect_in_tabstrip_coords_f); 321 gfx::Rect rect_in_tabstrip_coords = gfx::ToEnclosingRect( 322 rect_in_tabstrip_coords_f); 323 if (rect_in_tabstrip_coords.bottom() > tabstrip->GetLocalBounds().bottom()) { 324 // |rect| is below the tabstrip. 325 return false; 326 } 327 328 if (tabstrip->HitTestRect(rect_in_tabstrip_coords)) { 329 // Claim |rect| if it is in a non-tab portion of the tabstrip. 330 return tabstrip->IsRectInWindowCaption(rect_in_tabstrip_coords); 331 } 332 333 // The window switcher button is to the right of the tabstrip but is 334 // part of the client view. 335 views::View* window_switcher_button = 336 browser_view()->window_switcher_button(); 337 if (window_switcher_button && window_switcher_button->visible()) { 338 gfx::RectF rect_in_window_switcher_coords_f(rect); 339 View::ConvertRectToTarget(this, window_switcher_button, 340 &rect_in_window_switcher_coords_f); 341 gfx::Rect rect_in_window_switcher_coords = gfx::ToEnclosingRect( 342 rect_in_window_switcher_coords_f); 343 344 if (window_switcher_button->HitTestRect(rect_in_window_switcher_coords)) 345 return false; 346 } 347 348 // We claim |rect| because it is above the bottom of the tabstrip, but 349 // neither in the tabstrip nor in the window switcher button. In particular, 350 // the avatar label/button is left of the tabstrip and the window controls 351 // are right of the tabstrip. 352 return true; 353} 354 355void OpaqueBrowserFrameView::GetAccessibleState( 356 ui::AXViewState* state) { 357 state->role = ui::AX_ROLE_TITLE_BAR; 358} 359 360/////////////////////////////////////////////////////////////////////////////// 361// OpaqueBrowserFrameView, views::ButtonListener implementation: 362 363void OpaqueBrowserFrameView::ButtonPressed(views::Button* sender, 364 const ui::Event& event) { 365 if (sender == minimize_button_) 366 frame()->Minimize(); 367 else if (sender == maximize_button_) 368 frame()->Maximize(); 369 else if (sender == restore_button_) 370 frame()->Restore(); 371 else if (sender == close_button_) 372 frame()->Close(); 373 else if (sender == new_avatar_button()) 374 browser_view()->ShowAvatarBubbleFromAvatarButton(); 375} 376 377void OpaqueBrowserFrameView::OnMenuButtonClicked(views::View* source, 378 const gfx::Point& point) { 379#if defined(OS_LINUX) 380 views::MenuRunner menu_runner(frame()->GetSystemMenuModel()); 381 ignore_result(menu_runner.RunMenuAt(browser_view()->GetWidget(), 382 window_icon_, 383 window_icon_->GetBoundsInScreen(), 384 views::MenuItemView::TOPLEFT, 385 ui::MENU_SOURCE_MOUSE, 386 views::MenuRunner::HAS_MNEMONICS)); 387#endif 388} 389 390/////////////////////////////////////////////////////////////////////////////// 391// OpaqueBrowserFrameView, TabIconView::TabContentsProvider implementation: 392 393bool OpaqueBrowserFrameView::ShouldTabIconViewAnimate() const { 394 // This function is queried during the creation of the window as the 395 // TabIconView we host is initialized, so we need to NULL check the selected 396 // WebContents because in this condition there is not yet a selected tab. 397 WebContents* current_tab = browser_view()->GetActiveWebContents(); 398 return current_tab ? current_tab->IsLoading() : false; 399} 400 401gfx::ImageSkia OpaqueBrowserFrameView::GetFaviconForTabIconView() { 402 views::WidgetDelegate* delegate = frame()->widget_delegate(); 403 if (!delegate) { 404 LOG(WARNING) << "delegate is NULL, returning safe default."; 405 return gfx::ImageSkia(); 406 } 407 return delegate->GetWindowIcon(); 408} 409 410/////////////////////////////////////////////////////////////////////////////// 411// OpaqueBrowserFrameView, protected: 412 413void OpaqueBrowserFrameView::Observe( 414 int type, 415 const content::NotificationSource& source, 416 const content::NotificationDetails& details) { 417 switch (type) { 418 case chrome::NOTIFICATION_PROFILE_CACHED_INFO_CHANGED: 419 if (browser_view() ->IsRegularOrGuestSession() && 420 switches::IsNewProfileManagement()) 421 UpdateNewStyleAvatarInfo(this, NewAvatarButton::THEMED_BUTTON); 422 else 423 UpdateAvatarInfo(); 424 break; 425 default: 426 NOTREACHED() << "Got a notification we didn't register for!"; 427 break; 428 } 429} 430 431/////////////////////////////////////////////////////////////////////////////// 432// OpaqueBrowserFrameView, OpaqueBrowserFrameViewLayoutDelegate implementation: 433 434bool OpaqueBrowserFrameView::ShouldShowWindowIcon() const { 435 views::WidgetDelegate* delegate = frame()->widget_delegate(); 436 return ShouldShowWindowTitleBar() && delegate && 437 delegate->ShouldShowWindowIcon(); 438} 439 440bool OpaqueBrowserFrameView::ShouldShowWindowTitle() const { 441 // |delegate| may be NULL if called from callback of InputMethodChanged while 442 // a window is being destroyed. 443 // See more discussion at http://crosbug.com/8958 444 views::WidgetDelegate* delegate = frame()->widget_delegate(); 445 return ShouldShowWindowTitleBar() && delegate && 446 delegate->ShouldShowWindowTitle(); 447} 448 449base::string16 OpaqueBrowserFrameView::GetWindowTitle() const { 450 return frame()->widget_delegate()->GetWindowTitle(); 451} 452 453int OpaqueBrowserFrameView::GetIconSize() const { 454#if defined(OS_WIN) 455 // This metric scales up if either the titlebar height or the titlebar font 456 // size are increased. 457 return GetSystemMetrics(SM_CYSMICON); 458#else 459 return std::max(BrowserFrame::GetTitleFontList().GetHeight(), 460 kIconMinimumSize); 461#endif 462} 463 464bool OpaqueBrowserFrameView::ShouldLeaveOffsetNearTopBorder() const { 465 return frame()->ShouldLeaveOffsetNearTopBorder(); 466} 467 468gfx::Size OpaqueBrowserFrameView::GetBrowserViewMinimumSize() const { 469 return browser_view()->GetMinimumSize(); 470} 471 472bool OpaqueBrowserFrameView::ShouldShowCaptionButtons() const { 473 if (!OpaqueBrowserFrameViewLayout::ShouldAddDefaultCaptionButtons()) 474 return false; 475 return ShouldShowWindowTitleBar(); 476} 477 478bool OpaqueBrowserFrameView::ShouldShowAvatar() const { 479 return browser_view()->ShouldShowAvatar(); 480} 481 482bool OpaqueBrowserFrameView::IsRegularOrGuestSession() const { 483 return browser_view()->IsRegularOrGuestSession(); 484} 485 486gfx::ImageSkia OpaqueBrowserFrameView::GetOTRAvatarIcon() const { 487 return browser_view()->GetOTRAvatarIcon(); 488} 489 490bool OpaqueBrowserFrameView::IsMaximized() const { 491 return frame()->IsMaximized(); 492} 493 494bool OpaqueBrowserFrameView::IsMinimized() const { 495 return frame()->IsMinimized(); 496} 497 498bool OpaqueBrowserFrameView::IsFullscreen() const { 499 return frame()->IsFullscreen(); 500} 501 502bool OpaqueBrowserFrameView::IsTabStripVisible() const { 503 return browser_view()->IsTabStripVisible(); 504} 505 506int OpaqueBrowserFrameView::GetTabStripHeight() const { 507 return browser_view()->GetTabStripHeight(); 508} 509 510int OpaqueBrowserFrameView::GetAdditionalReservedSpaceInTabStrip() const { 511 // We don't have the sysmenu buttons in Windows 8 metro mode. However there 512 // are buttons like the window switcher which are drawn in the non client 513 // are in the BrowserView. We need to ensure that the tab strip does not 514 // draw on the window switcher button. 515 views::View* button = browser_view()->window_switcher_button(); 516 return button ? button->width() : 0; 517} 518 519gfx::Size OpaqueBrowserFrameView::GetTabstripPreferredSize() const { 520 gfx::Size s = browser_view()->tabstrip()->GetPreferredSize(); 521 return s; 522} 523 524/////////////////////////////////////////////////////////////////////////////// 525// OpaqueBrowserFrameView, views::View overrides: 526 527void OpaqueBrowserFrameView::OnPaint(gfx::Canvas* canvas) { 528 if (frame()->IsFullscreen()) 529 return; // Nothing is visible, so don't bother to paint. 530 531 if (layout_->IsTitleBarCondensed()) 532 PaintMaximizedFrameBorder(canvas); 533 else 534 PaintRestoredFrameBorder(canvas); 535 536 // The window icon and title are painted by their respective views. 537 /* TODO(pkasting): If this window is active, we should also draw a drop 538 * shadow on the title. This is tricky, because we don't want to hardcode a 539 * shadow color (since we want to work with various themes), but we can't 540 * alpha-blend either (since the Windows text APIs don't really do this). 541 * So we'd need to sample the background color at the right location and 542 * synthesize a good shadow color. */ 543 544 if (browser_view()->IsToolbarVisible()) 545 PaintToolbarBackground(canvas); 546 if (!layout_->IsTitleBarCondensed()) 547 PaintRestoredClientEdge(canvas); 548} 549 550/////////////////////////////////////////////////////////////////////////////// 551// OpaqueBrowserFrameView, private: 552 553views::ImageButton* OpaqueBrowserFrameView::InitWindowCaptionButton( 554 int normal_image_id, 555 int hot_image_id, 556 int pushed_image_id, 557 int mask_image_id, 558 int accessibility_string_id, 559 ViewID view_id) { 560 views::ImageButton* button = new views::ImageButton(this); 561 ui::ThemeProvider* tp = frame()->GetThemeProvider(); 562 button->SetImage(views::CustomButton::STATE_NORMAL, 563 tp->GetImageSkiaNamed(normal_image_id)); 564 button->SetImage(views::CustomButton::STATE_HOVERED, 565 tp->GetImageSkiaNamed(hot_image_id)); 566 button->SetImage(views::CustomButton::STATE_PRESSED, 567 tp->GetImageSkiaNamed(pushed_image_id)); 568 if (browser_view()->IsBrowserTypeNormal()) { 569 button->SetBackground( 570 tp->GetColor(ThemeProperties::COLOR_BUTTON_BACKGROUND), 571 tp->GetImageSkiaNamed(IDR_THEME_WINDOW_CONTROL_BACKGROUND), 572 tp->GetImageSkiaNamed(mask_image_id)); 573 } 574 button->SetAccessibleName( 575 l10n_util::GetStringUTF16(accessibility_string_id)); 576 button->set_id(view_id); 577 AddChildView(button); 578 return button; 579} 580 581int OpaqueBrowserFrameView::FrameBorderThickness(bool restored) const { 582 return layout_->FrameBorderThickness(restored); 583} 584 585int OpaqueBrowserFrameView::TopResizeHeight() const { 586 return FrameBorderThickness(false) - kTopResizeAdjust; 587} 588 589int OpaqueBrowserFrameView::NonClientBorderThickness() const { 590 return layout_->NonClientBorderThickness(); 591} 592 593gfx::Rect OpaqueBrowserFrameView::IconBounds() const { 594 return layout_->IconBounds(); 595} 596 597bool OpaqueBrowserFrameView::ShouldShowWindowTitleBar() const { 598#if defined(OS_LINUX) && !defined(OS_CHROMEOS) 599 // Do not show the custom title bar if the system title bar option is enabled. 600 if (!frame()->UseCustomFrame()) 601 return false; 602#endif 603 604 // Do not show caption buttons if the window manager is forcefully providing a 605 // title bar (e.g., in Ubuntu Unity, if the window is maximized). 606 if (!views::ViewsDelegate::views_delegate) 607 return true; 608 return !views::ViewsDelegate::views_delegate->WindowManagerProvidesTitleBar( 609 IsMaximized()); 610} 611 612void OpaqueBrowserFrameView::PaintRestoredFrameBorder(gfx::Canvas* canvas) { 613 frame_background_->set_frame_color(GetFrameColor()); 614 frame_background_->set_theme_image(GetFrameImage()); 615 frame_background_->set_theme_overlay_image(GetFrameOverlayImage()); 616 frame_background_->set_top_area_height(GetTopAreaHeight()); 617 618 ui::ThemeProvider* tp = GetThemeProvider(); 619 frame_background_->SetSideImages( 620 tp->GetImageSkiaNamed(IDR_WINDOW_LEFT_SIDE), 621 tp->GetImageSkiaNamed(IDR_WINDOW_TOP_CENTER), 622 tp->GetImageSkiaNamed(IDR_WINDOW_RIGHT_SIDE), 623 tp->GetImageSkiaNamed(IDR_WINDOW_BOTTOM_CENTER)); 624 frame_background_->SetCornerImages( 625 tp->GetImageSkiaNamed(IDR_WINDOW_TOP_LEFT_CORNER), 626 tp->GetImageSkiaNamed(IDR_WINDOW_TOP_RIGHT_CORNER), 627 tp->GetImageSkiaNamed(IDR_WINDOW_BOTTOM_LEFT_CORNER), 628 tp->GetImageSkiaNamed(IDR_WINDOW_BOTTOM_RIGHT_CORNER)); 629 frame_background_->PaintRestored(canvas, this); 630 631 // Note: When we don't have a toolbar, we need to draw some kind of bottom 632 // edge here. Because the App Window graphics we use for this have an 633 // attached client edge and their sizing algorithm is a little involved, we do 634 // all this in PaintRestoredClientEdge(). 635} 636 637void OpaqueBrowserFrameView::PaintMaximizedFrameBorder(gfx::Canvas* canvas) { 638 ui::ThemeProvider* tp = GetThemeProvider(); 639 frame_background_->set_frame_color(GetFrameColor()); 640 frame_background_->set_theme_image(GetFrameImage()); 641 frame_background_->set_theme_overlay_image(GetFrameOverlayImage()); 642 frame_background_->set_top_area_height(GetTopAreaHeight()); 643#if defined(OS_LINUX) && !defined(OS_CHROMEOS) 644 // The window manager typically shows a gradient in the native title bar (when 645 // the system title bar pref is set, or when maximized on Ubuntu). Hide the 646 // gradient in the tab strip (by shifting it up vertically) to avoid a 647 // double-gradient effect. 648 if (tp->UsingNativeTheme()) 649 frame_background_->set_maximized_top_inset(kGTKThemeCondensedFrameTopInset); 650#endif 651 652 frame_background_->PaintMaximized(canvas, this); 653 654 // TODO(jamescook): Migrate this into FrameBackground. 655 if (!browser_view()->IsToolbarVisible()) { 656 // There's no toolbar to edge the frame border, so we need to draw a bottom 657 // edge. The graphic we use for this has a built in client edge, so we clip 658 // it off the bottom. 659 gfx::ImageSkia* top_center = tp->GetImageSkiaNamed(IDR_APP_TOP_CENTER); 660 int edge_height = top_center->height() - kClientEdgeThickness; 661 canvas->TileImageInt(*top_center, 0, 662 frame()->client_view()->y() - edge_height, width(), edge_height); 663 } 664} 665 666void OpaqueBrowserFrameView::PaintToolbarBackground(gfx::Canvas* canvas) { 667 gfx::Rect toolbar_bounds(browser_view()->GetToolbarBounds()); 668 if (toolbar_bounds.IsEmpty()) 669 return; 670 gfx::Point toolbar_origin(toolbar_bounds.origin()); 671 ConvertPointToTarget(browser_view(), this, &toolbar_origin); 672 toolbar_bounds.set_origin(toolbar_origin); 673 674 int x = toolbar_bounds.x(); 675 int w = toolbar_bounds.width(); 676 int y = toolbar_bounds.y(); 677 int h = toolbar_bounds.height(); 678 679 // Gross hack: We split the toolbar images into two pieces, since sometimes 680 // (popup mode) the toolbar isn't tall enough to show the whole image. The 681 // split happens between the top shadow section and the bottom gradient 682 // section so that we never break the gradient. 683 int split_point = kFrameShadowThickness * 2; 684 int bottom_y = y + split_point; 685 ui::ThemeProvider* tp = GetThemeProvider(); 686 gfx::ImageSkia* toolbar_left = tp->GetImageSkiaNamed( 687 IDR_CONTENT_TOP_LEFT_CORNER); 688 int bottom_edge_height = std::min(toolbar_left->height(), h) - split_point; 689 690 // Split our canvas out so we can mask out the corners of the toolbar 691 // without masking out the frame. 692 canvas->SaveLayerAlpha( 693 255, gfx::Rect(x - kClientEdgeThickness, y, w + kClientEdgeThickness * 3, 694 h)); 695 696 // Paint the bottom rect. 697 canvas->FillRect(gfx::Rect(x, bottom_y, w, bottom_edge_height), 698 tp->GetColor(ThemeProperties::COLOR_TOOLBAR)); 699 700 // Tile the toolbar image starting at the frame edge on the left and where the 701 // horizontal tabstrip is (or would be) on the top. 702 gfx::ImageSkia* theme_toolbar = tp->GetImageSkiaNamed(IDR_THEME_TOOLBAR); 703 canvas->TileImageInt(*theme_toolbar, 704 x + GetThemeBackgroundXInset(), 705 bottom_y - GetTopInset(), 706 x, bottom_y, w, theme_toolbar->height()); 707 708 // Draw rounded corners for the tab. 709 gfx::ImageSkia* toolbar_left_mask = 710 tp->GetImageSkiaNamed(IDR_CONTENT_TOP_LEFT_CORNER_MASK); 711 gfx::ImageSkia* toolbar_right_mask = 712 tp->GetImageSkiaNamed(IDR_CONTENT_TOP_RIGHT_CORNER_MASK); 713 714 // We mask out the corners by using the DestinationIn transfer mode, 715 // which keeps the RGB pixels from the destination and the alpha from 716 // the source. 717 SkPaint paint; 718 paint.setXfermodeMode(SkXfermode::kDstIn_Mode); 719 720 // Mask the left edge. 721 int left_x = x - kContentEdgeShadowThickness; 722 canvas->DrawImageInt(*toolbar_left_mask, 0, 0, toolbar_left_mask->width(), 723 split_point, left_x, y, toolbar_left_mask->width(), 724 split_point, false, paint); 725 canvas->DrawImageInt(*toolbar_left_mask, 0, 726 toolbar_left_mask->height() - bottom_edge_height, 727 toolbar_left_mask->width(), bottom_edge_height, left_x, bottom_y, 728 toolbar_left_mask->width(), bottom_edge_height, false, paint); 729 730 // Mask the right edge. 731 int right_x = 732 x + w - toolbar_right_mask->width() + kContentEdgeShadowThickness; 733 canvas->DrawImageInt(*toolbar_right_mask, 0, 0, toolbar_right_mask->width(), 734 split_point, right_x, y, toolbar_right_mask->width(), 735 split_point, false, paint); 736 canvas->DrawImageInt(*toolbar_right_mask, 0, 737 toolbar_right_mask->height() - bottom_edge_height, 738 toolbar_right_mask->width(), bottom_edge_height, right_x, bottom_y, 739 toolbar_right_mask->width(), bottom_edge_height, false, paint); 740 canvas->Restore(); 741 742 canvas->DrawImageInt(*toolbar_left, 0, 0, toolbar_left->width(), split_point, 743 left_x, y, toolbar_left->width(), split_point, false); 744 canvas->DrawImageInt(*toolbar_left, 0, 745 toolbar_left->height() - bottom_edge_height, toolbar_left->width(), 746 bottom_edge_height, left_x, bottom_y, toolbar_left->width(), 747 bottom_edge_height, false); 748 749 gfx::ImageSkia* toolbar_center = 750 tp->GetImageSkiaNamed(IDR_CONTENT_TOP_CENTER); 751 canvas->TileImageInt(*toolbar_center, 0, 0, left_x + toolbar_left->width(), 752 y, right_x - (left_x + toolbar_left->width()), 753 split_point); 754 755 gfx::ImageSkia* toolbar_right = tp->GetImageSkiaNamed( 756 IDR_CONTENT_TOP_RIGHT_CORNER); 757 canvas->DrawImageInt(*toolbar_right, 0, 0, toolbar_right->width(), 758 split_point, right_x, y, toolbar_right->width(), split_point, false); 759 canvas->DrawImageInt(*toolbar_right, 0, 760 toolbar_right->height() - bottom_edge_height, toolbar_right->width(), 761 bottom_edge_height, right_x, bottom_y, toolbar_right->width(), 762 bottom_edge_height, false); 763 764 // Draw the content/toolbar separator. 765 canvas->FillRect( 766 gfx::Rect(x + kClientEdgeThickness, 767 toolbar_bounds.bottom() - kClientEdgeThickness, 768 w - (2 * kClientEdgeThickness), 769 kClientEdgeThickness), 770 ThemeProperties::GetDefaultColor( 771 ThemeProperties::COLOR_TOOLBAR_SEPARATOR)); 772} 773 774void OpaqueBrowserFrameView::PaintRestoredClientEdge(gfx::Canvas* canvas) { 775 ui::ThemeProvider* tp = GetThemeProvider(); 776 int client_area_top = frame()->client_view()->y(); 777 int image_top = client_area_top; 778 779 gfx::Rect client_area_bounds = 780 layout_->CalculateClientAreaBounds(width(), height()); 781 SkColor toolbar_color = tp->GetColor(ThemeProperties::COLOR_TOOLBAR); 782 783 if (browser_view()->IsToolbarVisible()) { 784 // The client edge images always start below the toolbar corner images. The 785 // client edge filled rects start there or at the bottom of the toolbar, 786 // whichever is shorter. 787 gfx::Rect toolbar_bounds(browser_view()->GetToolbarBounds()); 788 image_top += toolbar_bounds.y() + 789 tp->GetImageSkiaNamed(IDR_CONTENT_TOP_LEFT_CORNER)->height(); 790 client_area_top = std::min(image_top, 791 client_area_top + toolbar_bounds.bottom() - kClientEdgeThickness); 792 } else if (!browser_view()->IsTabStripVisible()) { 793 // The toolbar isn't going to draw a client edge for us, so draw one 794 // ourselves. 795 gfx::ImageSkia* top_left = tp->GetImageSkiaNamed(IDR_APP_TOP_LEFT); 796 gfx::ImageSkia* top_center = tp->GetImageSkiaNamed(IDR_APP_TOP_CENTER); 797 gfx::ImageSkia* top_right = tp->GetImageSkiaNamed(IDR_APP_TOP_RIGHT); 798 int top_edge_y = client_area_top - top_center->height(); 799 int height = client_area_top - top_edge_y; 800 801 canvas->DrawImageInt(*top_left, 0, 0, top_left->width(), height, 802 client_area_bounds.x() - top_left->width(), top_edge_y, 803 top_left->width(), height, false); 804 canvas->TileImageInt(*top_center, 0, 0, client_area_bounds.x(), top_edge_y, 805 client_area_bounds.width(), std::min(height, top_center->height())); 806 canvas->DrawImageInt(*top_right, 0, 0, top_right->width(), height, 807 client_area_bounds.right(), top_edge_y, 808 top_right->width(), height, false); 809 810 // Draw the toolbar color across the top edge. 811 canvas->FillRect(gfx::Rect(client_area_bounds.x() - kClientEdgeThickness, 812 client_area_top - kClientEdgeThickness, 813 client_area_bounds.width() + (2 * kClientEdgeThickness), 814 kClientEdgeThickness), toolbar_color); 815 } 816 817 int client_area_bottom = 818 std::max(client_area_top, height() - NonClientBorderThickness()); 819 int image_height = client_area_bottom - image_top; 820 821 // Draw the client edge images. 822 gfx::ImageSkia* right = tp->GetImageSkiaNamed(IDR_CONTENT_RIGHT_SIDE); 823 canvas->TileImageInt(*right, client_area_bounds.right(), image_top, 824 right->width(), image_height); 825 canvas->DrawImageInt( 826 *tp->GetImageSkiaNamed(IDR_CONTENT_BOTTOM_RIGHT_CORNER), 827 client_area_bounds.right(), client_area_bottom); 828 gfx::ImageSkia* bottom = tp->GetImageSkiaNamed(IDR_CONTENT_BOTTOM_CENTER); 829 canvas->TileImageInt(*bottom, client_area_bounds.x(), 830 client_area_bottom, client_area_bounds.width(), 831 bottom->height()); 832 gfx::ImageSkia* bottom_left = 833 tp->GetImageSkiaNamed(IDR_CONTENT_BOTTOM_LEFT_CORNER); 834 canvas->DrawImageInt(*bottom_left, 835 client_area_bounds.x() - bottom_left->width(), client_area_bottom); 836 gfx::ImageSkia* left = tp->GetImageSkiaNamed(IDR_CONTENT_LEFT_SIDE); 837 canvas->TileImageInt(*left, client_area_bounds.x() - left->width(), 838 image_top, left->width(), image_height); 839 840 // Draw the toolbar color so that the client edges show the right color even 841 // where not covered by the toolbar image. NOTE: We do this after drawing the 842 // images because the images are meant to alpha-blend atop the frame whereas 843 // these rects are meant to be fully opaque, without anything overlaid. 844 canvas->FillRect(gfx::Rect(client_area_bounds.x() - kClientEdgeThickness, 845 client_area_top, kClientEdgeThickness, 846 client_area_bottom + kClientEdgeThickness - client_area_top), 847 toolbar_color); 848 canvas->FillRect(gfx::Rect(client_area_bounds.x(), client_area_bottom, 849 client_area_bounds.width(), kClientEdgeThickness), 850 toolbar_color); 851 canvas->FillRect(gfx::Rect(client_area_bounds.right(), client_area_top, 852 kClientEdgeThickness, 853 client_area_bottom + kClientEdgeThickness - client_area_top), 854 toolbar_color); 855} 856 857SkColor OpaqueBrowserFrameView::GetFrameColor() const { 858 bool is_incognito = browser_view()->IsOffTheRecord(); 859 ThemeProperties::OverwritableByUserThemeProperty color_id; 860 if (ShouldPaintAsActive()) { 861 color_id = is_incognito ? 862 ThemeProperties::COLOR_FRAME_INCOGNITO : 863 ThemeProperties::COLOR_FRAME; 864 } else { 865 color_id = is_incognito ? 866 ThemeProperties::COLOR_FRAME_INCOGNITO_INACTIVE : 867 ThemeProperties::COLOR_FRAME_INACTIVE; 868 } 869 870 if (browser_view()->IsBrowserTypeNormal() || 871 platform_observer_->IsUsingNativeTheme()) { 872 return GetThemeProvider()->GetColor(color_id); 873 } 874 875 // Never theme app and popup windows unless the |platform_observer_| 876 // requested an override. 877 return ThemeProperties::GetDefaultColor(color_id); 878} 879 880gfx::ImageSkia* OpaqueBrowserFrameView::GetFrameImage() const { 881 bool is_incognito = browser_view()->IsOffTheRecord(); 882 int resource_id; 883 if (browser_view()->IsBrowserTypeNormal()) { 884 if (ShouldPaintAsActive()) { 885 resource_id = is_incognito ? 886 IDR_THEME_FRAME_INCOGNITO : IDR_THEME_FRAME; 887 } else { 888 resource_id = is_incognito ? 889 IDR_THEME_FRAME_INCOGNITO_INACTIVE : IDR_THEME_FRAME_INACTIVE; 890 } 891 return GetThemeProvider()->GetImageSkiaNamed(resource_id); 892 } 893 if (ShouldPaintAsActive()) { 894 resource_id = is_incognito ? 895 IDR_THEME_FRAME_INCOGNITO : IDR_FRAME; 896 } else { 897 resource_id = is_incognito ? 898 IDR_THEME_FRAME_INCOGNITO_INACTIVE : IDR_THEME_FRAME_INACTIVE; 899 } 900 901 if (platform_observer_->IsUsingNativeTheme()) { 902 // We want to use theme images provided by the platform theme when enabled, 903 // even if we are an app or popup window. 904 return GetThemeProvider()->GetImageSkiaNamed(resource_id); 905 } 906 907 // Otherwise, never theme app and popup windows. 908 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); 909 return rb.GetImageSkiaNamed(chrome::MapThemeImage( 910 chrome::GetHostDesktopTypeForNativeWindow( 911 browser_view()->GetNativeWindow()), 912 resource_id)); 913} 914 915gfx::ImageSkia* OpaqueBrowserFrameView::GetFrameOverlayImage() const { 916 ui::ThemeProvider* tp = GetThemeProvider(); 917 if (tp->HasCustomImage(IDR_THEME_FRAME_OVERLAY) && 918 browser_view()->IsBrowserTypeNormal() && 919 !browser_view()->IsOffTheRecord()) { 920 return tp->GetImageSkiaNamed(ShouldPaintAsActive() ? 921 IDR_THEME_FRAME_OVERLAY : IDR_THEME_FRAME_OVERLAY_INACTIVE); 922 } 923 return NULL; 924} 925 926int OpaqueBrowserFrameView::GetTopAreaHeight() const { 927 gfx::ImageSkia* frame_image = GetFrameImage(); 928 int top_area_height = frame_image->height(); 929 if (browser_view()->IsTabStripVisible()) { 930 top_area_height = std::max(top_area_height, 931 GetBoundsForTabStrip(browser_view()->tabstrip()).bottom()); 932 } 933 return top_area_height; 934} 935