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