browser_view.cc revision a02191e04bc25c4935f804f2c080ae28663d096d
1// Copyright 2012 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "chrome/browser/ui/views/frame/browser_view.h"
6
7#include <algorithm>
8
9#include "base/auto_reset.h"
10#include "base/command_line.h"
11#include "base/i18n/rtl.h"
12#include "base/memory/scoped_ptr.h"
13#include "base/metrics/histogram.h"
14#include "base/prefs/pref_service.h"
15#include "base/strings/string_number_conversions.h"
16#include "chrome/app/chrome_command_ids.h"
17#include "chrome/app/chrome_dll_resource.h"
18#include "chrome/browser/app_mode/app_mode_utils.h"
19#include "chrome/browser/bookmarks/bookmark_stats.h"
20#include "chrome/browser/browser_process.h"
21#include "chrome/browser/chrome_notification_types.h"
22#include "chrome/browser/extensions/tab_helper.h"
23#include "chrome/browser/infobars/infobar_service.h"
24#include "chrome/browser/native_window_notification_source.h"
25#include "chrome/browser/password_manager/chrome_password_manager_client.h"
26#include "chrome/browser/profiles/avatar_menu.h"
27#include "chrome/browser/profiles/profile.h"
28#include "chrome/browser/profiles/profile_info_cache.h"
29#include "chrome/browser/profiles/profile_manager.h"
30#include "chrome/browser/profiles/profiles_state.h"
31#include "chrome/browser/search/search.h"
32#include "chrome/browser/sessions/tab_restore_service.h"
33#include "chrome/browser/sessions/tab_restore_service_factory.h"
34#include "chrome/browser/speech/tts_controller.h"
35#include "chrome/browser/themes/theme_properties.h"
36#include "chrome/browser/themes/theme_service_factory.h"
37#include "chrome/browser/translate/translate_tab_helper.h"
38#include "chrome/browser/ui/app_modal_dialogs/app_modal_dialog.h"
39#include "chrome/browser/ui/app_modal_dialogs/app_modal_dialog_queue.h"
40#include "chrome/browser/ui/bookmarks/bookmark_bar_constants.h"
41#include "chrome/browser/ui/bookmarks/bookmark_bubble_delegate.h"
42#include "chrome/browser/ui/bookmarks/bookmark_bubble_sign_in_delegate.h"
43#include "chrome/browser/ui/browser.h"
44#include "chrome/browser/ui/browser_command_controller.h"
45#include "chrome/browser/ui/browser_commands.h"
46#include "chrome/browser/ui/browser_dialogs.h"
47#include "chrome/browser/ui/browser_finder.h"
48#include "chrome/browser/ui/browser_list.h"
49#include "chrome/browser/ui/browser_window_state.h"
50#include "chrome/browser/ui/ntp_background_util.h"
51#include "chrome/browser/ui/omnibox/omnibox_popup_model.h"
52#include "chrome/browser/ui/omnibox/omnibox_popup_view.h"
53#include "chrome/browser/ui/omnibox/omnibox_view.h"
54#include "chrome/browser/ui/search/search_delegate.h"
55#include "chrome/browser/ui/search/search_model.h"
56#include "chrome/browser/ui/search/search_ui.h"
57#include "chrome/browser/ui/tabs/tab_menu_model.h"
58#include "chrome/browser/ui/tabs/tab_strip_model.h"
59#include "chrome/browser/ui/view_ids.h"
60#include "chrome/browser/ui/views/accelerator_table.h"
61#include "chrome/browser/ui/views/accessibility/invert_bubble_view.h"
62#include "chrome/browser/ui/views/bookmarks/bookmark_bar_view.h"
63#include "chrome/browser/ui/views/bookmarks/bookmark_bubble_view.h"
64#include "chrome/browser/ui/views/browser_dialogs.h"
65#include "chrome/browser/ui/views/download/download_in_progress_dialog_view.h"
66#include "chrome/browser/ui/views/download/download_shelf_view.h"
67#include "chrome/browser/ui/views/extensions/bookmark_app_bubble_view.h"
68#include "chrome/browser/ui/views/frame/browser_view_layout.h"
69#include "chrome/browser/ui/views/frame/browser_view_layout_delegate.h"
70#include "chrome/browser/ui/views/frame/contents_layout_manager.h"
71#include "chrome/browser/ui/views/frame/immersive_mode_controller.h"
72#include "chrome/browser/ui/views/frame/native_browser_frame_factory.h"
73#include "chrome/browser/ui/views/frame/top_container_view.h"
74#include "chrome/browser/ui/views/frame/web_contents_close_handler.h"
75#include "chrome/browser/ui/views/fullscreen_exit_bubble_views.h"
76#include "chrome/browser/ui/views/infobars/infobar_container_view.h"
77#include "chrome/browser/ui/views/location_bar/location_bar_view.h"
78#include "chrome/browser/ui/views/location_bar/location_icon_view.h"
79#include "chrome/browser/ui/views/omnibox/omnibox_view_views.h"
80#include "chrome/browser/ui/views/password_generation_bubble_view.h"
81#include "chrome/browser/ui/views/profiles/avatar_menu_bubble_view.h"
82#include "chrome/browser/ui/views/profiles/avatar_menu_button.h"
83#include "chrome/browser/ui/views/profiles/profile_chooser_view.h"
84#include "chrome/browser/ui/views/status_bubble_views.h"
85#include "chrome/browser/ui/views/tabs/browser_tab_strip_controller.h"
86#include "chrome/browser/ui/views/tabs/tab.h"
87#include "chrome/browser/ui/views/tabs/tab_strip.h"
88#include "chrome/browser/ui/views/toolbar/reload_button.h"
89#include "chrome/browser/ui/views/toolbar/toolbar_view.h"
90#include "chrome/browser/ui/views/translate/translate_bubble_view.h"
91#include "chrome/browser/ui/views/update_recommended_message_box.h"
92#include "chrome/browser/ui/views/website_settings/permissions_bubble_view.h"
93#include "chrome/browser/ui/views/website_settings/website_settings_popup_view.h"
94#include "chrome/browser/ui/website_settings/permission_bubble_manager.h"
95#include "chrome/browser/ui/window_sizer/window_sizer.h"
96#include "chrome/common/chrome_switches.h"
97#include "chrome/common/pref_names.h"
98#include "chrome/common/profile_management_switches.h"
99#include "chrome/common/url_constants.h"
100#include "components/password_manager/core/browser/password_manager.h"
101#include "content/public/browser/download_manager.h"
102#include "content/public/browser/native_web_keyboard_event.h"
103#include "content/public/browser/notification_service.h"
104#include "content/public/browser/render_frame_host.h"
105#include "content/public/browser/render_view_host.h"
106#include "content/public/browser/user_metrics.h"
107#include "content/public/browser/web_contents.h"
108#include "content/public/browser/web_contents_view.h"
109#include "content/public/common/content_switches.h"
110#include "grit/chromium_strings.h"
111#include "grit/generated_resources.h"
112#include "grit/locale_settings.h"
113#include "grit/theme_resources.h"
114#include "grit/ui_resources.h"
115#include "grit/ui_strings.h"
116#include "grit/webkit_resources.h"
117#include "ui/accessibility/ax_view_state.h"
118#include "ui/base/accelerators/accelerator.h"
119#include "ui/base/hit_test.h"
120#include "ui/base/l10n/l10n_util.h"
121#include "ui/base/resource/resource_bundle.h"
122#include "ui/base/theme_provider.h"
123#include "ui/events/event_utils.h"
124#include "ui/gfx/canvas.h"
125#include "ui/gfx/color_utils.h"
126#include "ui/gfx/rect_conversions.h"
127#include "ui/gfx/sys_color_change_listener.h"
128#include "ui/views/controls/button/menu_button.h"
129#include "ui/views/controls/textfield/textfield.h"
130#include "ui/views/controls/webview/webview.h"
131#include "ui/views/focus/external_focus_tracker.h"
132#include "ui/views/focus/view_storage.h"
133#include "ui/views/layout/grid_layout.h"
134#include "ui/views/widget/native_widget.h"
135#include "ui/views/widget/root_view.h"
136#include "ui/views/widget/widget.h"
137#include "ui/views/window/dialog_delegate.h"
138
139#if defined(USE_ASH)
140#include "ash/ash_switches.h"
141#include "ash/shelf/shelf.h"
142#include "ash/shelf/shelf_model.h"
143#include "ash/shell.h"
144#include "chrome/browser/ui/ash/ash_util.h"
145#endif
146
147#if defined(USE_AURA)
148#include "ui/aura/client/window_tree_client.h"
149#include "ui/aura/window.h"
150#include "ui/aura/window_tree_host.h"
151#include "ui/gfx/screen.h"
152#endif
153
154#if defined(OS_WIN)
155#include "base/win/windows_version.h"
156#include "chrome/browser/jumplist_win.h"
157#include "ui/views/win/scoped_fullscreen_visibility.h"
158#include "win8/util/win8_util.h"
159#endif
160
161#if defined(ENABLE_ONE_CLICK_SIGNIN)
162#include "chrome/browser/ui/sync/one_click_signin_bubble_delegate.h"
163#include "chrome/browser/ui/sync/one_click_signin_bubble_links_delegate.h"
164#include "chrome/browser/ui/views/sync/one_click_signin_bubble_view.h"
165#endif
166
167#if defined(OS_CHROMEOS)
168#include "chrome/browser/ui/ash/multi_user/multi_user_window_manager.h"
169#endif
170
171using base::TimeDelta;
172using base::UserMetricsAction;
173using content::NativeWebKeyboardEvent;
174using content::SSLStatus;
175using content::WebContents;
176using views::ColumnSet;
177using views::GridLayout;
178using web_modal::WebContentsModalDialogHost;
179
180namespace {
181// The name of a key to store on the window handle so that other code can
182// locate this object using just the handle.
183const char* const kBrowserViewKey = "__BROWSER_VIEW__";
184
185// The number of milliseconds between loading animation frames.
186const int kLoadingAnimationFrameTimeMs = 30;
187
188// TODO(kuan): These functions are temporarily for the bookmark bar while its
189// detached state is at the top of the page;  it'll be moved to float on the
190// content page in the very near future, at which time, these local functions
191// will be removed.
192void PaintDetachedBookmarkBar(gfx::Canvas* canvas,
193                              DetachableToolbarView* view,
194                              ThemeService* theme_service) {
195  // Paint background for detached state; if animating, this is fade in/out.
196  canvas->DrawColor(
197      chrome::GetDetachedBookmarkBarBackgroundColor(theme_service));
198  // Draw the separators above and below bookmark bar;
199  // if animating, these are fading in/out.
200  SkColor separator_color =
201      chrome::GetDetachedBookmarkBarSeparatorColor(theme_service);
202  DetachableToolbarView::PaintHorizontalBorder(canvas, view, true,
203                                               separator_color);
204  // The bottom border needs to be 1-px thick in both regular and retina
205  // displays, so we can't use DetachableToolbarView::PaintHorizontalBorder
206  // which paints a 2-px thick border in retina display.
207  SkPaint paint;
208  paint.setAntiAlias(false);
209  // Sets border to 1-px thick regardless of scale factor.
210  paint.setStrokeWidth(0);
211  // Bottom border is at 50% opacity of top border.
212  paint.setColor(SkColorSetA(separator_color,
213                             SkColorGetA(separator_color) / 2));
214  // Calculate thickness of bottom border as per current scale factor to
215  // determine where to draw the 1-px thick border.
216  float thickness = views::NonClientFrameView::kClientEdgeThickness /
217                    canvas->image_scale();
218  SkScalar y = SkIntToScalar(view->height()) - SkFloatToScalar(thickness);
219  canvas->sk_canvas()->drawLine(SkIntToScalar(0), y,
220                                SkIntToScalar(view->width()), y, paint);
221}
222
223void PaintAttachedBookmarkBar(gfx::Canvas* canvas,
224                              DetachableToolbarView* view,
225                              BrowserView* browser_view,
226                              chrome::HostDesktopType host_desktop_type,
227                              int toolbar_overlap) {
228  // Paint background for attached state, this is fade in/out.
229  gfx::Point background_image_offset =
230      browser_view->OffsetPointForToolbarBackgroundImage(
231          gfx::Point(view->GetMirroredX(), view->y()));
232  DetachableToolbarView::PaintBackgroundAttachedMode(canvas,
233      view->GetThemeProvider(), view->GetLocalBounds(),
234      background_image_offset, host_desktop_type);
235  if (view->height() >= toolbar_overlap) {
236    // Draw the separator below bookmark bar; this is fading in/out.
237    DetachableToolbarView::PaintHorizontalBorder(canvas, view, false,
238        ThemeProperties::GetDefaultColor(
239            ThemeProperties::COLOR_TOOLBAR_SEPARATOR));
240  }
241}
242
243}  // namespace
244
245// static
246const char BrowserView::kViewClassName[] = "BrowserView";
247
248namespace {
249
250bool ShouldSaveOrRestoreWindowPos() {
251#if defined(OS_WIN)
252  // In Windows 8's single window Metro mode the window is always maximized
253  // (without the WS_MAXIMIZE style).
254  if (win8::IsSingleWindowMetroMode())
255    return false;
256#endif
257  return true;
258}
259
260}  // namespace
261
262///////////////////////////////////////////////////////////////////////////////
263
264// Delegate implementation for BrowserViewLayout. Usually just forwards calls
265// into BrowserView.
266class BrowserViewLayoutDelegateImpl : public BrowserViewLayoutDelegate {
267 public:
268  explicit BrowserViewLayoutDelegateImpl(BrowserView* browser_view)
269      : browser_view_(browser_view) {}
270  virtual ~BrowserViewLayoutDelegateImpl() {}
271
272  // BrowserViewLayoutDelegate overrides:
273  virtual views::View* GetContentsWebView() const OVERRIDE {
274    return browser_view_->contents_web_view_;
275  }
276
277  virtual views::View* GetWindowSwitcherButton() const OVERRIDE {
278    return browser_view_->window_switcher_button();
279  }
280
281  virtual bool DownloadShelfNeedsLayout() const OVERRIDE {
282    DownloadShelfView* download_shelf = browser_view_->download_shelf_.get();
283    // Re-layout the shelf either if it is visible or if its close animation
284    // is currently running.
285    return download_shelf &&
286           (download_shelf->IsShowing() || download_shelf->IsClosing());
287  }
288
289  virtual bool IsTabStripVisible() const OVERRIDE {
290    return browser_view_->IsTabStripVisible();
291  }
292
293  virtual gfx::Rect GetBoundsForTabStripInBrowserView() const OVERRIDE {
294    gfx::RectF bounds_f(browser_view_->frame()->GetBoundsForTabStrip(
295        browser_view_->tabstrip()));
296    views::View::ConvertRectToTarget(browser_view_->parent(), browser_view_,
297        &bounds_f);
298    return gfx::ToEnclosingRect(bounds_f);
299  }
300
301  virtual int GetTopInsetInBrowserView() const OVERRIDE {
302    return browser_view_->frame()->GetTopInset() -
303        browser_view_->y();
304  }
305
306  virtual int GetThemeBackgroundXInset() const OVERRIDE {
307    // TODO(pkotwicz): Return the inset with respect to the left edge of the
308    // BrowserView.
309    return browser_view_->frame()->GetThemeBackgroundXInset();
310  }
311
312  virtual bool IsToolbarVisible() const OVERRIDE {
313    return browser_view_->IsToolbarVisible();
314  }
315
316  virtual bool IsBookmarkBarVisible() const OVERRIDE {
317    return browser_view_->IsBookmarkBarVisible();
318  }
319
320  virtual FullscreenExitBubbleViews* GetFullscreenExitBubble() const OVERRIDE {
321    return browser_view_->fullscreen_exit_bubble();
322  }
323
324 private:
325  BrowserView* browser_view_;
326
327  DISALLOW_COPY_AND_ASSIGN(BrowserViewLayoutDelegateImpl);
328};
329
330///////////////////////////////////////////////////////////////////////////////
331// BookmarkExtensionBackground, private:
332// This object serves as the views::Background object which is used to layout
333// and paint the bookmark bar.
334class BookmarkExtensionBackground : public views::Background {
335 public:
336  BookmarkExtensionBackground(BrowserView* browser_view,
337                              DetachableToolbarView* host_view,
338                              Browser* browser);
339
340  // View methods overridden from views:Background.
341  virtual void Paint(gfx::Canvas* canvas, views::View* view) const OVERRIDE;
342
343 private:
344  BrowserView* browser_view_;
345
346  // The view hosting this background.
347  DetachableToolbarView* host_view_;
348
349  Browser* browser_;
350
351  DISALLOW_COPY_AND_ASSIGN(BookmarkExtensionBackground);
352};
353
354BookmarkExtensionBackground::BookmarkExtensionBackground(
355    BrowserView* browser_view,
356    DetachableToolbarView* host_view,
357    Browser* browser)
358    : browser_view_(browser_view),
359      host_view_(host_view),
360      browser_(browser) {
361}
362
363void BookmarkExtensionBackground::Paint(gfx::Canvas* canvas,
364                                        views::View* view) const {
365  int toolbar_overlap = host_view_->GetToolbarOverlap();
366  if (!host_view_->IsDetached()) {
367    PaintAttachedBookmarkBar(canvas, host_view_, browser_view_,
368                             browser_->host_desktop_type(), toolbar_overlap);
369    return;
370  }
371
372  // As 'hidden' according to the animation is the full in-tab state, we invert
373  // the value - when current_state is at '0', we expect the bar to be docked.
374  double current_state = 1 - host_view_->GetAnimationValue();
375
376  ThemeService* ts =
377      ThemeServiceFactory::GetForProfile(browser_->profile());
378  if (current_state == 0.0 || current_state == 1.0) {
379    PaintDetachedBookmarkBar(canvas, host_view_, ts);
380    return;
381  }
382  // While animating, set opacity to cross-fade between attached and detached
383  // backgrounds including their respective separators.
384  int detached_alpha = static_cast<uint8>(current_state * 255);
385  int attached_alpha = 255 - detached_alpha;
386  if (browser_->bookmark_bar_state() == BookmarkBar::DETACHED) {
387    // To animate from attached to detached state:
388    // - fade out attached background
389    // - fade in detached background.
390    canvas->SaveLayerAlpha(attached_alpha);
391    PaintAttachedBookmarkBar(canvas, host_view_, browser_view_,
392                             browser_->host_desktop_type(),
393                             toolbar_overlap);
394    canvas->Restore();
395    canvas->SaveLayerAlpha(detached_alpha);
396    PaintDetachedBookmarkBar(canvas, host_view_, ts);
397  } else {
398    // To animate from detached to attached state:
399    // - fade out detached background
400    // - fade in attached background.
401    canvas->SaveLayerAlpha(detached_alpha);
402    PaintDetachedBookmarkBar(canvas, host_view_, ts);
403    canvas->Restore();
404    canvas->SaveLayerAlpha(attached_alpha);
405    PaintAttachedBookmarkBar(canvas, host_view_, browser_view_,
406                             browser_->host_desktop_type(),
407                             toolbar_overlap);
408  }
409  canvas->Restore();
410}
411
412///////////////////////////////////////////////////////////////////////////////
413// BrowserView, public:
414
415BrowserView::BrowserView()
416    : views::ClientView(NULL, NULL),
417      last_focused_view_storage_id_(
418          views::ViewStorage::GetInstance()->CreateStorageID()),
419      frame_(NULL),
420      top_container_(NULL),
421      tabstrip_(NULL),
422      toolbar_(NULL),
423      window_switcher_button_(NULL),
424      find_bar_host_view_(NULL),
425      infobar_container_(NULL),
426      contents_web_view_(NULL),
427      contents_container_(NULL),
428      devtools_window_(NULL),
429      initialized_(false),
430      in_process_fullscreen_(false),
431#if defined(OS_WIN)
432      hung_window_detector_(&hung_plugin_action_),
433      ticker_(0),
434#endif
435      force_location_bar_focus_(false),
436#if defined(OS_CHROMEOS)
437      scroll_end_effect_controller_(ScrollEndEffectController::Create()),
438#endif
439      color_change_listener_(this),
440      activate_modal_dialog_factory_(this) {
441}
442
443BrowserView::~BrowserView() {
444  // All the tabs should have been destroyed already. If we were closed by the
445  // OS with some tabs than the NativeBrowserFrame should have destroyed them.
446  DCHECK_EQ(0, browser_->tab_strip_model()->count());
447
448  // Immersive mode may need to reparent views before they are removed/deleted.
449  immersive_mode_controller_.reset();
450
451  browser_->tab_strip_model()->RemoveObserver(this);
452
453#if defined(OS_WIN)
454  // Stop hung plugin monitoring.
455  ticker_.Stop();
456  ticker_.UnregisterTickHandler(&hung_window_detector_);
457
458  // Terminate the jumplist (must be called before browser_->profile() is
459  // destroyed.
460  if (jumplist_) {
461    jumplist_->Terminate();
462  }
463#endif
464
465  // We destroy the download shelf before |browser_| to remove its child
466  // download views from the set of download observers (since the observed
467  // downloads can be destroyed along with |browser_| and the observer
468  // notifications will call back into deleted objects).
469  BrowserViewLayout* browser_view_layout = GetBrowserViewLayout();
470  if (browser_view_layout)
471    browser_view_layout->set_download_shelf(NULL);
472  download_shelf_.reset();
473
474  // The TabStrip attaches a listener to the model. Make sure we shut down the
475  // TabStrip first so that it can cleanly remove the listener.
476  if (tabstrip_) {
477    tabstrip_->parent()->RemoveChildView(tabstrip_);
478    if (browser_view_layout)
479      browser_view_layout->set_tab_strip(NULL);
480    delete tabstrip_;
481    tabstrip_ = NULL;
482  }
483  // Child views maintain PrefMember attributes that point to
484  // OffTheRecordProfile's PrefService which gets deleted by ~Browser.
485  RemoveAllChildViews(true);
486  toolbar_ = NULL;
487
488  // Explicitly set browser_ to NULL.
489  browser_.reset();
490}
491
492void BrowserView::Init(Browser* browser) {
493  browser_.reset(browser);
494  browser_->tab_strip_model()->AddObserver(this);
495  immersive_mode_controller_.reset(
496      chrome::CreateImmersiveModeController(browser_->host_desktop_type()));
497}
498
499// static
500BrowserView* BrowserView::GetBrowserViewForNativeWindow(
501    gfx::NativeWindow window) {
502  views::Widget* widget = views::Widget::GetWidgetForNativeWindow(window);
503  return widget ?
504      reinterpret_cast<BrowserView*>(widget->GetNativeWindowProperty(
505          kBrowserViewKey)) : NULL;
506}
507
508// static
509BrowserView* BrowserView::GetBrowserViewForBrowser(const Browser* browser) {
510  return static_cast<BrowserView*>(browser->window());
511}
512
513void BrowserView::InitStatusBubble() {
514  status_bubble_.reset(new StatusBubbleViews(contents_web_view_));
515  contents_web_view_->SetStatusBubble(status_bubble_.get());
516}
517
518void BrowserView::InitPermissionBubbleView() {
519  permission_bubble_view_.reset(new PermissionBubbleViewViews(
520      GetLocationBarView()->GetLocationIconView()));
521}
522
523gfx::Rect BrowserView::GetToolbarBounds() const {
524  gfx::Rect toolbar_bounds(toolbar_->bounds());
525  if (toolbar_bounds.IsEmpty())
526    return toolbar_bounds;
527  // The apparent toolbar edges are outside the "real" toolbar edges.
528  toolbar_bounds.Inset(-views::NonClientFrameView::kClientEdgeThickness, 0);
529  return toolbar_bounds;
530}
531
532gfx::Rect BrowserView::GetFindBarBoundingBox() const {
533  return GetBrowserViewLayout()->GetFindBarBoundingBox();
534}
535
536int BrowserView::GetTabStripHeight() const {
537  // We want to return tabstrip_->height(), but we might be called in the midst
538  // of layout, when that hasn't yet been updated to reflect the current state.
539  // So return what the tabstrip height _ought_ to be right now.
540  return IsTabStripVisible() ? tabstrip_->GetPreferredSize().height() : 0;
541}
542
543gfx::Point BrowserView::OffsetPointForToolbarBackgroundImage(
544    const gfx::Point& point) const {
545  // The background image starts tiling horizontally at the window left edge and
546  // vertically at the top edge of the horizontal tab strip (or where it would
547  // be).  We expect our parent's origin to be the window origin.
548  gfx::Point window_point(point + GetMirroredPosition().OffsetFromOrigin());
549  window_point.Offset(frame_->GetThemeBackgroundXInset(),
550                      -frame_->GetTopInset());
551  return window_point;
552}
553
554bool BrowserView::IsTabStripVisible() const {
555  if (immersive_mode_controller_->ShouldHideTopViews() &&
556      immersive_mode_controller_->ShouldHideTabIndicators())
557    return false;
558  return browser_->SupportsWindowFeature(Browser::FEATURE_TABSTRIP);
559}
560
561bool BrowserView::IsOffTheRecord() const {
562  return browser_->profile()->IsOffTheRecord();
563}
564
565bool BrowserView::IsGuestSession() const {
566  return browser_->profile()->IsGuestSession();
567}
568
569bool BrowserView::IsRegularOrGuestSession() const {
570  return profiles::IsRegularOrGuestSession(browser_.get());
571}
572
573int BrowserView::GetOTRIconResourceID() const {
574  int otr_resource_id = IDR_OTR_ICON;
575  if (ui::GetDisplayLayout() == ui::LAYOUT_TOUCH) {
576    if (IsFullscreen())
577      otr_resource_id = IDR_OTR_ICON_FULLSCREEN;
578#if defined(OS_WIN)
579    if (win8::IsSingleWindowMetroMode())
580      otr_resource_id = IDR_OTR_ICON_FULLSCREEN;
581#endif
582  }
583
584  return otr_resource_id;
585}
586
587int BrowserView::GetGuestIconResourceID() const {
588  return IDR_LOGIN_GUEST;
589}
590
591bool BrowserView::ShouldShowAvatar() const {
592#if defined(OS_CHROMEOS)
593  if (!browser_->is_type_tabbed() && !browser_->is_app())
594    return false;
595  // Don't show incognito avatar in the guest session.
596  if (IsOffTheRecord() && !IsGuestSession())
597    return true;
598  // This function is called via BrowserNonClientFrameView::UpdateAvatarInfo
599  // during the creation of the BrowserWindow, so browser->window() will not
600  // yet be set. In this case we can safely return false.
601  if (!browser_->window())
602    return false;
603  return chrome::MultiUserWindowManager::ShouldShowAvatar(
604      browser_->window()->GetNativeWindow());
605#else
606  if (!IsBrowserTypeNormal())
607    return false;
608  if (IsOffTheRecord())  // Desktop guest is incognito and needs avatar.
609    return true;
610  // Tests may not have a profile manager.
611  if (!g_browser_process->profile_manager())
612    return false;
613  ProfileInfoCache& cache =
614      g_browser_process->profile_manager()->GetProfileInfoCache();
615  if (cache.GetIndexOfProfileWithPath(browser_->profile()->GetPath()) ==
616      std::string::npos) {
617    return false;
618  }
619
620  return AvatarMenu::ShouldShowAvatarMenu();
621#endif
622}
623
624bool BrowserView::GetAccelerator(int cmd_id, ui::Accelerator* accelerator) {
625  // We retrieve the accelerator information for standard accelerators
626  // for cut, copy and paste.
627  if (chrome::GetStandardAcceleratorForCommandId(cmd_id, accelerator))
628    return true;
629  // Else, we retrieve the accelerator information from the accelerator table.
630  for (std::map<ui::Accelerator, int>::const_iterator it =
631           accelerator_table_.begin(); it != accelerator_table_.end(); ++it) {
632    if (it->second == cmd_id) {
633      *accelerator = it->first;
634      return true;
635    }
636  }
637  // Else, we retrieve the accelerator information from Ash (if applicable).
638  return chrome::GetAshAcceleratorForCommandId(
639      cmd_id, browser_->host_desktop_type(), accelerator);
640}
641
642bool BrowserView::IsAcceleratorRegistered(const ui::Accelerator& accelerator) {
643  return accelerator_table_.find(accelerator) != accelerator_table_.end();
644}
645
646WebContents* BrowserView::GetActiveWebContents() const {
647  return browser_->tab_strip_model()->GetActiveWebContents();
648}
649
650gfx::ImageSkia BrowserView::GetOTRAvatarIcon() const {
651  return *GetThemeProvider()->GetImageSkiaNamed(GetOTRIconResourceID());
652}
653
654///////////////////////////////////////////////////////////////////////////////
655// BrowserView, BrowserWindow implementation:
656
657void BrowserView::Show() {
658  // If the window is already visible, just activate it.
659  if (frame_->IsVisible()) {
660    frame_->Activate();
661    return;
662  }
663
664  // Showing the window doesn't make the browser window active right away.
665  // This can cause SetFocusToLocationBar() to skip setting focus to the
666  // location bar. To avoid this we explicilty let SetFocusToLocationBar()
667  // know that it's ok to steal focus.
668  force_location_bar_focus_ = true;
669
670  // Setting the focus doesn't work when the window is invisible, so any focus
671  // initialization that happened before this will be lost.
672  //
673  // We really "should" restore the focus whenever the window becomes unhidden,
674  // but I think initializing is the only time where this can happen where
675  // there is some focus change we need to pick up, and this is easier than
676  // plumbing through an un-hide message all the way from the frame.
677  //
678  // If we do find there are cases where we need to restore the focus on show,
679  // that should be added and this should be removed.
680  RestoreFocus();
681
682  frame_->Show();
683
684  force_location_bar_focus_ = false;
685
686  browser()->OnWindowDidShow();
687
688  chrome::MaybeShowInvertBubbleView(this);
689}
690
691void BrowserView::ShowInactive() {
692  if (!frame_->IsVisible())
693    frame_->ShowInactive();
694}
695
696void BrowserView::Hide() {
697  // Not implemented.
698}
699
700void BrowserView::SetBounds(const gfx::Rect& bounds) {
701  ExitFullscreen();
702  GetWidget()->SetBounds(bounds);
703}
704
705void BrowserView::Close() {
706  frame_->Close();
707}
708
709void BrowserView::Activate() {
710  frame_->Activate();
711}
712
713void BrowserView::Deactivate() {
714  frame_->Deactivate();
715}
716
717bool BrowserView::IsActive() const {
718  return frame_->IsActive();
719}
720
721void BrowserView::FlashFrame(bool flash) {
722  frame_->FlashFrame(flash);
723}
724
725bool BrowserView::IsAlwaysOnTop() const {
726  return false;
727}
728
729void BrowserView::SetAlwaysOnTop(bool always_on_top) {
730  // Not implemented for browser windows.
731  NOTIMPLEMENTED();
732}
733
734gfx::NativeWindow BrowserView::GetNativeWindow() {
735  // While the browser destruction is going on, the widget can already be gone,
736  // but utility functions like FindBrowserWithWindow will come here and crash.
737  // We short circuit therefore.
738  if (!GetWidget())
739    return NULL;
740  return GetWidget()->GetTopLevelWidget()->GetNativeWindow();
741}
742
743BrowserWindowTesting* BrowserView::GetBrowserWindowTesting() {
744  return this;
745}
746
747StatusBubble* BrowserView::GetStatusBubble() {
748  return status_bubble_.get();
749}
750
751namespace {
752  // Only used by ToolbarSizeChanged() below, but placed here because template
753  // arguments (to base::AutoReset<>) must have external linkage.
754  enum CallState { NORMAL, REENTRANT, REENTRANT_FORCE_FAST_RESIZE };
755}
756
757void BrowserView::UpdateTitleBar() {
758  frame_->UpdateWindowTitle();
759  if (ShouldShowWindowIcon() && !loading_animation_timer_.IsRunning())
760    frame_->UpdateWindowIcon();
761}
762
763void BrowserView::BookmarkBarStateChanged(
764    BookmarkBar::AnimateChangeType change_type) {
765  if (bookmark_bar_view_.get()) {
766    BookmarkBar::State new_state = browser_->bookmark_bar_state();
767
768    // We don't properly support animating the bookmark bar to and from the
769    // detached state in immersive fullscreen.
770    bool detached_changed = (new_state == BookmarkBar::DETACHED) ||
771        bookmark_bar_view_->IsDetached();
772    if (detached_changed && immersive_mode_controller_->IsEnabled())
773      change_type = BookmarkBar::DONT_ANIMATE_STATE_CHANGE;
774
775    bookmark_bar_view_->SetBookmarkBarState(new_state, change_type);
776  }
777  if (MaybeShowBookmarkBar(GetActiveWebContents()))
778    Layout();
779}
780
781void BrowserView::UpdateDevTools() {
782  UpdateDevToolsForContents(GetActiveWebContents(), true);
783  Layout();
784}
785
786void BrowserView::UpdateLoadingAnimations(bool should_animate) {
787  if (should_animate) {
788    if (!loading_animation_timer_.IsRunning()) {
789      // Loads are happening, and the timer isn't running, so start it.
790      last_animation_time_ = base::TimeTicks::Now();
791      loading_animation_timer_.Start(FROM_HERE,
792          TimeDelta::FromMilliseconds(kLoadingAnimationFrameTimeMs), this,
793          &BrowserView::LoadingAnimationCallback);
794    }
795  } else {
796    if (loading_animation_timer_.IsRunning()) {
797      last_animation_time_ = base::TimeTicks();
798      loading_animation_timer_.Stop();
799      // Loads are now complete, update the state if a task was scheduled.
800      LoadingAnimationCallback();
801    }
802  }
803}
804
805void BrowserView::SetStarredState(bool is_starred) {
806  GetLocationBarView()->SetStarToggled(is_starred);
807}
808
809void BrowserView::SetTranslateIconToggled(bool is_lit) {
810  GetLocationBarView()->SetTranslateIconToggled(is_lit);
811}
812
813void BrowserView::OnActiveTabChanged(content::WebContents* old_contents,
814                                     content::WebContents* new_contents,
815                                     int index,
816                                     int reason) {
817  DCHECK(new_contents);
818
819  // If |contents_container_| already has the correct WebContents, we can save
820  // some work.  This also prevents extra events from being reported by the
821  // Visibility API under Windows, as ChangeWebContents will briefly hide
822  // the WebContents window.
823  bool change_tab_contents =
824      contents_web_view_->web_contents() != new_contents;
825
826  // Update various elements that are interested in knowing the current
827  // WebContents.
828
829  // When we toggle the NTP floating bookmarks bar and/or the info bar,
830  // we don't want any WebContents to be attached, so that we
831  // avoid an unnecessary resize and re-layout of a WebContents.
832  if (change_tab_contents) {
833    contents_web_view_->SetWebContents(NULL);
834    devtools_web_view_->SetWebContents(NULL);
835  }
836
837  infobar_container_->ChangeInfoBarManager(
838      InfoBarService::FromWebContents(new_contents));
839
840  if (old_contents && PermissionBubbleManager::FromWebContents(old_contents))
841    PermissionBubbleManager::FromWebContents(old_contents)->SetView(NULL);
842
843  if (new_contents && PermissionBubbleManager::FromWebContents(new_contents)) {
844    PermissionBubbleManager::FromWebContents(new_contents)->SetView(
845        permission_bubble_view_.get());
846  }
847
848  if (bookmark_bar_view_.get()) {
849    bookmark_bar_view_->SetBookmarkBarState(
850        browser_->bookmark_bar_state(),
851        BookmarkBar::DONT_ANIMATE_STATE_CHANGE);
852  }
853  UpdateUIForContents(new_contents);
854
855  // Layout for DevTools _before_ setting the both main and devtools WebContents
856  // to avoid toggling the size of any of them.
857  UpdateDevToolsForContents(new_contents, !change_tab_contents);
858
859  if (change_tab_contents) {
860    web_contents_close_handler_->ActiveTabChanged();
861    contents_web_view_->SetWebContents(new_contents);
862    // The second layout update should be no-op. It will just set the
863    // DevTools WebContents.
864    UpdateDevToolsForContents(new_contents, true);
865  }
866
867  if (!browser_->tab_strip_model()->closing_all() && GetWidget()->IsActive() &&
868      GetWidget()->IsVisible()) {
869    // We only restore focus if our window is visible, to avoid invoking blur
870    // handlers when we are eventually shown.
871    new_contents->GetView()->RestoreFocus();
872  }
873
874  // Update all the UI bits.
875  UpdateTitleBar();
876}
877
878void BrowserView::ZoomChangedForActiveTab(bool can_show_bubble) {
879  GetLocationBarView()->ZoomChangedForActiveTab(
880      can_show_bubble && !toolbar_->IsWrenchMenuShowing());
881}
882
883gfx::Rect BrowserView::GetRestoredBounds() const {
884  return frame_->GetRestoredBounds();
885}
886
887ui::WindowShowState BrowserView::GetRestoredState() const {
888  if (IsMaximized())
889    return ui::SHOW_STATE_MAXIMIZED;
890  if (IsMinimized())
891    return ui::SHOW_STATE_MINIMIZED;
892  return ui::SHOW_STATE_NORMAL;
893}
894
895gfx::Rect BrowserView::GetBounds() const {
896  return frame_->GetWindowBoundsInScreen();
897}
898
899bool BrowserView::IsMaximized() const {
900  return frame_->IsMaximized();
901}
902
903bool BrowserView::IsMinimized() const {
904  return frame_->IsMinimized();
905}
906
907void BrowserView::Maximize() {
908  frame_->Maximize();
909}
910
911void BrowserView::Minimize() {
912  frame_->Minimize();
913}
914
915void BrowserView::Restore() {
916  frame_->Restore();
917}
918
919void BrowserView::EnterFullscreen(
920    const GURL& url, FullscreenExitBubbleType bubble_type) {
921  if (IsFullscreen())
922    return;  // Nothing to do.
923
924  ProcessFullscreen(true, NORMAL_FULLSCREEN, url, bubble_type);
925}
926
927void BrowserView::ExitFullscreen() {
928  if (!IsFullscreen())
929    return;  // Nothing to do.
930
931  ProcessFullscreen(false, NORMAL_FULLSCREEN, GURL(), FEB_TYPE_NONE);
932}
933
934void BrowserView::UpdateFullscreenExitBubbleContent(
935    const GURL& url,
936    FullscreenExitBubbleType bubble_type) {
937  // Immersive mode has no exit bubble because it has a visible strip at the
938  // top that gives the user a hover target.
939  // TODO(jamescook): Figure out what to do with mouse-lock.
940  if (bubble_type == FEB_TYPE_NONE || ShouldUseImmersiveFullscreenForUrl(url)) {
941    fullscreen_bubble_.reset();
942  } else if (fullscreen_bubble_.get()) {
943    fullscreen_bubble_->UpdateContent(url, bubble_type);
944  } else {
945    fullscreen_bubble_.reset(new FullscreenExitBubbleViews(
946        this, url, bubble_type));
947  }
948}
949
950bool BrowserView::ShouldHideUIForFullscreen() const {
951#if defined(USE_ASH)
952  // Immersive mode needs UI for the slide-down top panel.
953  if (immersive_mode_controller_->IsEnabled())
954    return false;
955#endif
956  return IsFullscreen();
957}
958
959bool BrowserView::IsFullscreen() const {
960  return frame_->IsFullscreen();
961}
962
963bool BrowserView::IsFullscreenBubbleVisible() const {
964  return fullscreen_bubble_ != NULL;
965}
966
967#if defined(OS_WIN)
968void BrowserView::SetMetroSnapMode(bool enable) {
969  HISTOGRAM_COUNTS("Metro.SnapModeToggle", enable);
970  ProcessFullscreen(enable, METRO_SNAP_FULLSCREEN, GURL(), FEB_TYPE_NONE);
971}
972
973bool BrowserView::IsInMetroSnapMode() const {
974  return false;
975}
976#endif  // defined(OS_WIN)
977
978void BrowserView::RestoreFocus() {
979  WebContents* selected_web_contents = GetActiveWebContents();
980  if (selected_web_contents)
981    selected_web_contents->GetView()->RestoreFocus();
982}
983
984void BrowserView::SetWindowSwitcherButton(views::Button* button) {
985  if (window_switcher_button_)
986    RemoveChildView(window_switcher_button_);
987  window_switcher_button_ = button;
988}
989
990void BrowserView::FullscreenStateChanged() {
991  CHECK(!IsFullscreen());
992  ProcessFullscreen(false, NORMAL_FULLSCREEN, GURL(), FEB_TYPE_NONE);
993}
994
995void BrowserView::ToolbarSizeChanged(bool is_animating) {
996  // The call to InfoBarContainer::SetMaxTopArrowHeight() below can result in
997  // reentrancy; |call_state| tracks whether we're reentrant.  We can't just
998  // early-return in this case because we need to layout again so the infobar
999  // container's bounds are set correctly.
1000  static CallState call_state = NORMAL;
1001
1002  // A reentrant call can (and should) use the fast resize path unless both it
1003  // and the normal call are both non-animating.
1004  bool use_fast_resize =
1005      is_animating || (call_state == REENTRANT_FORCE_FAST_RESIZE);
1006  if (use_fast_resize)
1007    contents_web_view_->SetFastResize(true);
1008  UpdateUIForContents(GetActiveWebContents());
1009  if (use_fast_resize)
1010    contents_web_view_->SetFastResize(false);
1011
1012  // Inform the InfoBarContainer that the distance to the location icon may have
1013  // changed.  We have to do this after the block above so that the toolbars are
1014  // laid out correctly for calculating the maximum arrow height below.
1015  {
1016    base::AutoReset<CallState> resetter(&call_state,
1017        is_animating ? REENTRANT_FORCE_FAST_RESIZE : REENTRANT);
1018    infobar_container_->SetMaxTopArrowHeight(GetMaxTopInfoBarArrowHeight());
1019  }
1020
1021  // When transitioning from animating to not animating we need to make sure the
1022  // contents_container_ gets layed out. If we don't do this and the bounds
1023  // haven't changed contents_container_ won't get a Layout out and we'll end up
1024  // with a gray rect because the clip wasn't updated.  Note that a reentrant
1025  // call never needs to do this, because after it returns, the normal call
1026  // wrapping it will do it.
1027  if ((call_state == NORMAL) && !is_animating) {
1028    contents_web_view_->InvalidateLayout();
1029    contents_container_->Layout();
1030  }
1031}
1032
1033LocationBar* BrowserView::GetLocationBar() const {
1034  return GetLocationBarView();
1035}
1036
1037void BrowserView::SetFocusToLocationBar(bool select_all) {
1038  // On Windows, changing focus to the location bar causes the browser
1039  // window to become active. This can steal focus if the user has
1040  // another window open already. On ChromeOS, changing focus makes a
1041  // view believe it has a focus even if the widget doens't have a
1042  // focus. Either cases, we need to ignore this when the browser
1043  // window isn't active.
1044  if (!force_location_bar_focus_ && !IsActive())
1045    return;
1046
1047  // Temporarily reveal the top-of-window views (if not already revealed) so
1048  // that the location bar view is visible and is considered focusable. If the
1049  // location bar view gains focus, |immersive_mode_controller_| will keep the
1050  // top-of-window views revealed.
1051  scoped_ptr<ImmersiveRevealedLock> focus_reveal_lock(
1052      immersive_mode_controller_->GetRevealedLock(
1053          ImmersiveModeController::ANIMATE_REVEAL_YES));
1054
1055  LocationBarView* location_bar = GetLocationBarView();
1056  if (location_bar->omnibox_view()->IsFocusable()) {
1057    // Location bar got focus.
1058    //
1059    // select_all is true when it's expected that the user may want to copy
1060    // the URL to the clipboard. If the URL is not being shown because the
1061    // origin chip is enabled, show it now to support the same functionality.
1062    if (select_all &&
1063        location_bar->GetToolbarModel()->WouldOmitURLDueToOriginChip())
1064      location_bar->ShowURL();
1065    else
1066      location_bar->FocusLocation(select_all);
1067  } else {
1068    // If none of location bar got focus, then clear focus.
1069    views::FocusManager* focus_manager = GetFocusManager();
1070    DCHECK(focus_manager);
1071    focus_manager->ClearFocus();
1072  }
1073}
1074
1075void BrowserView::UpdateReloadStopState(bool is_loading, bool force) {
1076  toolbar_->reload_button()->ChangeMode(
1077      is_loading ? ReloadButton::MODE_STOP : ReloadButton::MODE_RELOAD, force);
1078}
1079
1080void BrowserView::UpdateToolbar(content::WebContents* contents) {
1081  // We may end up here during destruction.
1082  if (toolbar_)
1083    toolbar_->Update(contents);
1084}
1085
1086void BrowserView::FocusToolbar() {
1087  // Temporarily reveal the top-of-window views (if not already revealed) so
1088  // that the toolbar is visible and is considered focusable. If the
1089  // toolbar gains focus, |immersive_mode_controller_| will keep the
1090  // top-of-window views revealed.
1091  scoped_ptr<ImmersiveRevealedLock> focus_reveal_lock(
1092      immersive_mode_controller_->GetRevealedLock(
1093          ImmersiveModeController::ANIMATE_REVEAL_YES));
1094
1095  // Start the traversal within the main toolbar. SetPaneFocus stores
1096  // the current focused view before changing focus.
1097  toolbar_->SetPaneFocus(NULL);
1098}
1099
1100void BrowserView::FocusBookmarksToolbar() {
1101  DCHECK(!immersive_mode_controller_->IsEnabled());
1102  if (bookmark_bar_view_.get() &&
1103      bookmark_bar_view_->visible() &&
1104      bookmark_bar_view_->GetPreferredSize().height() != 0) {
1105    bookmark_bar_view_->SetPaneFocusAndFocusDefault();
1106  }
1107}
1108
1109void BrowserView::FocusInfobars() {
1110  if (infobar_container_->child_count() > 0)
1111    infobar_container_->SetPaneFocusAndFocusDefault();
1112}
1113
1114void BrowserView::FocusAppMenu() {
1115  // Chrome doesn't have a traditional menu bar, but it has a menu button in the
1116  // main toolbar that plays the same role.  If the user presses a key that
1117  // would typically focus the menu bar, tell the toolbar to focus the menu
1118  // button.  If the user presses the key again, return focus to the previous
1119  // location.
1120  //
1121  // Not used on the Mac, which has a normal menu bar.
1122  if (toolbar_->IsAppMenuFocused()) {
1123    RestoreFocus();
1124  } else {
1125    DCHECK(!immersive_mode_controller_->IsEnabled());
1126    toolbar_->SetPaneFocusAndFocusAppMenu();
1127  }
1128}
1129
1130void BrowserView::RotatePaneFocus(bool forwards) {
1131  GetWidget()->GetFocusManager()->RotatePaneFocus(
1132      forwards ?
1133          views::FocusManager::kForward : views::FocusManager::kBackward,
1134      views::FocusManager::kWrap);
1135}
1136
1137void BrowserView::DestroyBrowser() {
1138  // After this returns other parts of Chrome are going to be shutdown. Close
1139  // the window now so that we are deleted immediately and aren't left holding
1140  // references to deleted objects.
1141  GetWidget()->RemoveObserver(this);
1142  GetLocationBar()->GetOmniboxView()->model()->popup_model()->RemoveObserver(
1143      this);
1144  frame_->CloseNow();
1145}
1146
1147bool BrowserView::IsBookmarkBarVisible() const {
1148  if (!browser_->SupportsWindowFeature(Browser::FEATURE_BOOKMARKBAR))
1149    return false;
1150  if (!bookmark_bar_view_.get())
1151    return false;
1152  if (bookmark_bar_view_->GetPreferredSize().height() == 0)
1153    return false;
1154  // New tab page needs visible bookmarks even when top-views are hidden.
1155  if (immersive_mode_controller_->ShouldHideTopViews() &&
1156      !bookmark_bar_view_->IsDetached())
1157    return false;
1158  return true;
1159}
1160
1161bool BrowserView::IsBookmarkBarAnimating() const {
1162  return bookmark_bar_view_.get() && bookmark_bar_view_->is_animating();
1163}
1164
1165bool BrowserView::IsTabStripEditable() const {
1166  return tabstrip_->IsTabStripEditable();
1167}
1168
1169bool BrowserView::IsToolbarVisible() const {
1170  if (immersive_mode_controller_->ShouldHideTopViews())
1171    return false;
1172  return browser_->SupportsWindowFeature(Browser::FEATURE_TOOLBAR) ||
1173         browser_->SupportsWindowFeature(Browser::FEATURE_LOCATIONBAR);
1174}
1175
1176gfx::Rect BrowserView::GetRootWindowResizerRect() const {
1177  // Views does not support resizer rects because they caused page cycler
1178  // performance regressions when they were added. See crrev.com/9654
1179  return gfx::Rect();
1180}
1181
1182void BrowserView::ConfirmAddSearchProvider(TemplateURL* template_url,
1183                                           Profile* profile) {
1184  chrome::EditSearchEngine(GetWidget()->GetNativeWindow(), template_url, NULL,
1185                           profile);
1186}
1187
1188void BrowserView::ShowUpdateChromeDialog() {
1189  UpdateRecommendedMessageBox::Show(GetWidget()->GetNativeWindow());
1190}
1191
1192void BrowserView::ShowBookmarkBubble(const GURL& url, bool already_bookmarked) {
1193  scoped_ptr<BookmarkBubbleDelegate> delegate;
1194  delegate.reset(new BookmarkBubbleSignInDelegate(browser_.get()));
1195
1196  BookmarkBubbleView::ShowBubble(GetToolbarView()->GetBookmarkBubbleAnchor(),
1197                                 bookmark_bar_view_.get(),
1198                                 delegate.Pass(),
1199                                 browser_->profile(),
1200                                 url,
1201                                 !already_bookmarked);
1202}
1203
1204void BrowserView::ShowBookmarkAppBubble(
1205    const WebApplicationInfo& web_app_info,
1206    const std::string& extension_id) {
1207  BookmarkAppBubbleView::ShowBubble(GetToolbarView(),
1208                                    browser_->profile(),
1209                                    web_app_info,
1210                                    extension_id);
1211}
1212
1213void BrowserView::ShowBookmarkPrompt() {
1214  GetLocationBarView()->ShowBookmarkPrompt();
1215}
1216
1217void BrowserView::ShowTranslateBubble(content::WebContents* web_contents,
1218                                      translate::TranslateStep step,
1219                                      TranslateErrors::Type error_type) {
1220  TranslateTabHelper* translate_tab_helper =
1221      TranslateTabHelper::FromWebContents(web_contents);
1222  LanguageState& language_state = translate_tab_helper->GetLanguageState();
1223  language_state.SetTranslateEnabled(true);
1224
1225  TranslateBubbleView::ShowBubble(
1226      GetToolbarView()->GetTranslateBubbleAnchor(), web_contents, step,
1227      error_type);
1228}
1229
1230#if defined(ENABLE_ONE_CLICK_SIGNIN)
1231void BrowserView::ShowOneClickSigninBubble(
1232    OneClickSigninBubbleType type,
1233    const base::string16& email,
1234    const base::string16& error_message,
1235    const StartSyncCallback& start_sync_callback) {
1236  scoped_ptr<OneClickSigninBubbleDelegate> delegate;
1237  delegate.reset(new OneClickSigninBubbleLinksDelegate(browser()));
1238
1239  views::View* anchor_view;
1240  if (type == BrowserWindow::ONE_CLICK_SIGNIN_BUBBLE_TYPE_BUBBLE)
1241    anchor_view = toolbar_->app_menu();
1242  else
1243    anchor_view = toolbar_->location_bar();
1244
1245  OneClickSigninBubbleView::ShowBubble(type, email, error_message,
1246                                       delegate.Pass(), anchor_view,
1247                                       start_sync_callback);
1248}
1249#endif
1250
1251void BrowserView::SetDownloadShelfVisible(bool visible) {
1252  // This can be called from the superclass destructor, when it destroys our
1253  // child views. At that point, browser_ is already gone.
1254  if (browser_ == NULL)
1255    return;
1256
1257  if (visible && IsDownloadShelfVisible() != visible) {
1258    // Invoke GetDownloadShelf to force the shelf to be created.
1259    GetDownloadShelf();
1260  }
1261
1262  if (browser_ != NULL)
1263    browser_->UpdateDownloadShelfVisibility(visible);
1264
1265  // SetDownloadShelfVisible can force-close the shelf, so make sure we lay out
1266  // everything correctly, as if the animation had finished. This doesn't
1267  // matter for showing the shelf, as the show animation will do it.
1268  ToolbarSizeChanged(false);
1269}
1270
1271bool BrowserView::IsDownloadShelfVisible() const {
1272  return download_shelf_.get() && download_shelf_->IsShowing();
1273}
1274
1275DownloadShelf* BrowserView::GetDownloadShelf() {
1276  if (!download_shelf_.get()) {
1277    download_shelf_.reset(new DownloadShelfView(browser_.get(), this));
1278    download_shelf_->set_owned_by_client();
1279    GetBrowserViewLayout()->set_download_shelf(download_shelf_.get());
1280  }
1281  return download_shelf_.get();
1282}
1283
1284void BrowserView::ConfirmBrowserCloseWithPendingDownloads(
1285    int download_count,
1286    Browser::DownloadClosePreventionType dialog_type,
1287    bool app_modal,
1288    const base::Callback<void(bool)>& callback) {
1289  DownloadInProgressDialogView::Show(
1290      GetNativeWindow(), download_count, dialog_type, app_modal, callback);
1291}
1292
1293void BrowserView::UserChangedTheme() {
1294  frame_->FrameTypeChanged();
1295}
1296
1297int BrowserView::GetExtraRenderViewHeight() const {
1298  // Currently this is only used on linux.
1299  return 0;
1300}
1301
1302void BrowserView::WebContentsFocused(WebContents* contents) {
1303  if (contents_web_view_->GetWebContents() == contents)
1304    contents_web_view_->OnWebContentsFocused(contents);
1305  else
1306    devtools_web_view_->OnWebContentsFocused(contents);
1307}
1308
1309void BrowserView::ShowWebsiteSettings(Profile* profile,
1310                                      content::WebContents* web_contents,
1311                                      const GURL& url,
1312                                      const content::SSLStatus& ssl) {
1313  WebsiteSettingsPopupView::ShowPopup(
1314      GetLocationBarView()->GetLocationIconView(), profile,
1315      web_contents, url, ssl, browser_.get());
1316}
1317
1318void BrowserView::ShowAppMenu() {
1319  // Keep the top-of-window views revealed as long as the app menu is visible.
1320  scoped_ptr<ImmersiveRevealedLock> revealed_lock(
1321      immersive_mode_controller_->GetRevealedLock(
1322          ImmersiveModeController::ANIMATE_REVEAL_NO));
1323
1324  toolbar_->app_menu()->Activate();
1325}
1326
1327bool BrowserView::PreHandleKeyboardEvent(const NativeWebKeyboardEvent& event,
1328                                         bool* is_keyboard_shortcut) {
1329  *is_keyboard_shortcut = false;
1330
1331  if ((event.type != blink::WebInputEvent::RawKeyDown) &&
1332      (event.type != blink::WebInputEvent::KeyUp)) {
1333    return false;
1334  }
1335
1336  views::FocusManager* focus_manager = GetFocusManager();
1337  DCHECK(focus_manager);
1338
1339  if (focus_manager->shortcut_handling_suspended())
1340    return false;
1341
1342  ui::Accelerator accelerator(
1343      static_cast<ui::KeyboardCode>(event.windowsKeyCode),
1344      content::GetModifiersFromNativeWebKeyboardEvent(event));
1345  if (event.type == blink::WebInputEvent::KeyUp)
1346    accelerator.set_type(ui::ET_KEY_RELEASED);
1347
1348  // What we have to do here is as follows:
1349  // - If the |browser_| is for an app, do nothing.
1350  // - If the |browser_| is not for an app, and the |accelerator| is not
1351  //   associated with the browser (e.g. an Ash shortcut), process it.
1352  // - If the |browser_| is not for an app, and the |accelerator| is associated
1353  //   with the browser, and it is a reserved one (e.g. Ctrl+w), process it.
1354  // - If the |browser_| is not for an app, and the |accelerator| is associated
1355  //   with the browser, and it is not a reserved one, do nothing.
1356
1357  if (browser_->is_app()) {
1358    // Let all keys fall through to a v1 app's web content, even accelerators.
1359    // We don't have to flip |is_keyboard_shortcut| here. If we do that, the app
1360    // might not be able to see a subsequent Char event. See OnHandleInputEvent
1361    // in content/renderer/render_widget.cc for details.
1362    return false;
1363  }
1364
1365  chrome::BrowserCommandController* controller = browser_->command_controller();
1366
1367  // Here we need to retrieve the command id (if any) associated to the
1368  // keyboard event. Instead of looking up the command id in the
1369  // |accelerator_table_| by ourselves, we block the command execution of
1370  // the |browser_| object then send the keyboard event to the
1371  // |focus_manager| as if we are activating an accelerator key.
1372  // Then we can retrieve the command id from the |browser_| object.
1373  bool original_block_command_state = controller->block_command_execution();
1374  controller->SetBlockCommandExecution(true);
1375  // If the |accelerator| is a non-browser shortcut (e.g. Ash shortcut), the
1376  // command execution cannot be blocked and true is returned. However, it is
1377  // okay as long as is_app() is false. See comments in this function.
1378  const bool processed = focus_manager->ProcessAccelerator(accelerator);
1379  const int id = controller->GetLastBlockedCommand(NULL);
1380  controller->SetBlockCommandExecution(original_block_command_state);
1381
1382  // Executing the command may cause |this| object to be destroyed.
1383  if (controller->IsReservedCommandOrKey(id, event)) {
1384    UpdateAcceleratorMetrics(accelerator, id);
1385    return chrome::ExecuteCommand(browser_.get(), id);
1386  }
1387
1388  if (id != -1) {
1389    // |accelerator| is a non-reserved browser shortcut (e.g. Ctrl+f).
1390    if (event.type == blink::WebInputEvent::RawKeyDown)
1391      *is_keyboard_shortcut = true;
1392  } else if (processed) {
1393    // |accelerator| is a non-browser shortcut (e.g. F4-F10 on Ash). Report
1394    // that we handled it.
1395    return true;
1396  }
1397
1398  return false;
1399}
1400
1401void BrowserView::HandleKeyboardEvent(const NativeWebKeyboardEvent& event) {
1402  unhandled_keyboard_event_handler_.HandleKeyboardEvent(event,
1403                                                        GetFocusManager());
1404}
1405
1406// TODO(devint): http://b/issue?id=1117225 Cut, Copy, and Paste are always
1407// enabled in the page menu regardless of whether the command will do
1408// anything. When someone selects the menu item, we just act as if they hit
1409// the keyboard shortcut for the command by sending the associated key press
1410// to windows. The real fix to this bug is to disable the commands when they
1411// won't do anything. We'll need something like an overall clipboard command
1412// manager to do that.
1413void BrowserView::Cut() {
1414  // If a WebContent is focused, call WebContents::Cut. Otherwise, e.g. if
1415  // Omnibox is focused, send a Ctrl+x key event to Chrome. Using RWH interface
1416  // rather than the fake key event for a WebContent is important since the fake
1417  // event might be consumed by the web content (crbug.com/137908).
1418  DoCutCopyPaste(&content::WebContents::Cut, IDS_APP_CUT);
1419}
1420
1421void BrowserView::Copy() {
1422  DoCutCopyPaste(&content::WebContents::Copy, IDS_APP_COPY);
1423}
1424
1425void BrowserView::Paste() {
1426  DoCutCopyPaste(&content::WebContents::Paste, IDS_APP_PASTE);
1427}
1428
1429WindowOpenDisposition BrowserView::GetDispositionForPopupBounds(
1430    const gfx::Rect& bounds) {
1431#if defined(OS_WIN)
1432  // If we are in Win8's single window Metro mode, we can't allow popup windows.
1433  return win8::IsSingleWindowMetroMode() ? NEW_BACKGROUND_TAB : NEW_POPUP;
1434#else
1435  return NEW_POPUP;
1436#endif
1437}
1438
1439FindBar* BrowserView::CreateFindBar() {
1440  return chrome::CreateFindBar(this);
1441}
1442
1443WebContentsModalDialogHost* BrowserView::GetWebContentsModalDialogHost() {
1444  return GetBrowserViewLayout()->GetWebContentsModalDialogHost();
1445}
1446
1447///////////////////////////////////////////////////////////////////////////////
1448// BrowserView, BrowserWindowTesting implementation:
1449
1450BookmarkBarView* BrowserView::GetBookmarkBarView() const {
1451  return bookmark_bar_view_.get();
1452}
1453
1454LocationBarView* BrowserView::GetLocationBarView() const {
1455  return toolbar_ ? toolbar_->location_bar() : NULL;
1456}
1457
1458views::View* BrowserView::GetTabContentsContainerView() const {
1459  return contents_web_view_;
1460}
1461
1462ToolbarView* BrowserView::GetToolbarView() const {
1463  return toolbar_;
1464}
1465
1466///////////////////////////////////////////////////////////////////////////////
1467// BrowserView, TabStripModelObserver implementation:
1468
1469void BrowserView::TabInsertedAt(WebContents* contents,
1470                                int index,
1471                                bool foreground) {
1472  // WebContents inserted in tabs might not have been added to the root
1473  // window yet. Per http://crbug/342672 add them now since drawing the
1474  // WebContents requires root window specific data - information about
1475  // the screen the WebContents is drawn on, for example.
1476  if (!contents->GetView()->GetNativeView()->GetRootWindow()) {
1477    aura::Window* window = contents->GetView()->GetNativeView();
1478    aura::Window* root_window = GetNativeWindow()->GetRootWindow();
1479    aura::client::ParentWindowWithContext(
1480        window, root_window, root_window->GetBoundsInScreen());
1481    DCHECK(contents->GetView()->GetNativeView()->GetRootWindow());
1482  }
1483  web_contents_close_handler_->TabInserted();
1484}
1485
1486void BrowserView::TabDetachedAt(WebContents* contents, int index) {
1487  if (PermissionBubbleManager::FromWebContents(contents))
1488    PermissionBubbleManager::FromWebContents(contents)->SetView(NULL);
1489
1490  // We use index here rather than comparing |contents| because by this time
1491  // the model has already removed |contents| from its list, so
1492  // browser_->GetActiveWebContents() will return NULL or something else.
1493  if (index == browser_->tab_strip_model()->active_index()) {
1494    // We need to reset the current tab contents to NULL before it gets
1495    // freed. This is because the focus manager performs some operations
1496    // on the selected WebContents when it is removed.
1497    web_contents_close_handler_->ActiveTabChanged();
1498    contents_web_view_->SetWebContents(NULL);
1499    infobar_container_->ChangeInfoBarManager(NULL);
1500    UpdateDevToolsForContents(NULL, true);
1501  }
1502}
1503
1504void BrowserView::TabDeactivated(WebContents* contents) {
1505  if (PermissionBubbleManager::FromWebContents(contents))
1506    PermissionBubbleManager::FromWebContents(contents)->SetView(NULL);
1507
1508  // We do not store the focus when closing the tab to work-around bug 4633.
1509  // Some reports seem to show that the focus manager and/or focused view can
1510  // be garbage at that point, it is not clear why.
1511  if (!contents->IsBeingDestroyed())
1512    contents->GetView()->StoreFocus();
1513}
1514
1515void BrowserView::TabStripEmpty() {
1516  // Make sure all optional UI is removed before we are destroyed, otherwise
1517  // there will be consequences (since our view hierarchy will still have
1518  // references to freed views).
1519  UpdateUIForContents(NULL);
1520}
1521
1522void BrowserView::WillCloseAllTabs() {
1523  web_contents_close_handler_->WillCloseAllTabs();
1524}
1525
1526void BrowserView::CloseAllTabsCanceled() {
1527  web_contents_close_handler_->CloseAllTabsCanceled();
1528}
1529
1530///////////////////////////////////////////////////////////////////////////////
1531// BrowserView, ui::AcceleratorProvider implementation:
1532
1533bool BrowserView::GetAcceleratorForCommandId(int command_id,
1534                                             ui::Accelerator* accelerator) {
1535  // Let's let the ToolbarView own the canonical implementation of this method.
1536  return toolbar_->GetAcceleratorForCommandId(command_id, accelerator);
1537}
1538
1539///////////////////////////////////////////////////////////////////////////////
1540// BrowserView, views::WidgetDelegate implementation:
1541
1542bool BrowserView::CanResize() const {
1543  return true;
1544}
1545
1546bool BrowserView::CanMaximize() const {
1547  return true;
1548}
1549
1550bool BrowserView::CanActivate() const {
1551  if (!AppModalDialogQueue::GetInstance()->active_dialog() ||
1552      !AppModalDialogQueue::GetInstance()->active_dialog()->native_dialog())
1553    return true;
1554
1555#if defined(USE_AURA) && defined(OS_CHROMEOS)
1556  // On Aura window manager controls all windows so settings focus via PostTask
1557  // will make only worse because posted task will keep trying to steal focus.
1558  AppModalDialogQueue::GetInstance()->ActivateModalDialog();
1559#else
1560  // If another browser is app modal, flash and activate the modal browser. This
1561  // has to be done in a post task, otherwise if the user clicked on a window
1562  // that doesn't have the modal dialog the windows keep trying to get the focus
1563  // from each other on Windows. http://crbug.com/141650.
1564  base::MessageLoop::current()->PostTask(
1565      FROM_HERE,
1566      base::Bind(&BrowserView::ActivateAppModalDialog,
1567                 activate_modal_dialog_factory_.GetWeakPtr()));
1568#endif
1569  return false;
1570}
1571
1572base::string16 BrowserView::GetWindowTitle() const {
1573  return browser_->GetWindowTitleForCurrentTab();
1574}
1575
1576base::string16 BrowserView::GetAccessibleWindowTitle() const {
1577  if (IsOffTheRecord()) {
1578    return l10n_util::GetStringFUTF16(
1579        IDS_ACCESSIBLE_INCOGNITO_WINDOW_TITLE_FORMAT,
1580        GetWindowTitle());
1581  }
1582  return GetWindowTitle();
1583}
1584
1585views::View* BrowserView::GetInitiallyFocusedView() {
1586  return NULL;
1587}
1588
1589bool BrowserView::ShouldShowWindowTitle() const {
1590  // For Ash only, app host windows do not show an icon, crbug.com/119411.
1591  // Child windows (i.e. popups) do show an icon.
1592  if (browser_->host_desktop_type() == chrome::HOST_DESKTOP_TYPE_ASH &&
1593      browser_->is_app() &&
1594      browser_->is_trusted_source())
1595    return false;
1596
1597  return browser_->SupportsWindowFeature(Browser::FEATURE_TITLEBAR);
1598}
1599
1600gfx::ImageSkia BrowserView::GetWindowAppIcon() {
1601  if (browser_->is_app()) {
1602    WebContents* contents = browser_->tab_strip_model()->GetActiveWebContents();
1603    extensions::TabHelper* extensions_tab_helper =
1604        contents ? extensions::TabHelper::FromWebContents(contents) : NULL;
1605    if (extensions_tab_helper && extensions_tab_helper->GetExtensionAppIcon())
1606      return gfx::ImageSkia::CreateFrom1xBitmap(
1607          *extensions_tab_helper->GetExtensionAppIcon());
1608  }
1609
1610  return GetWindowIcon();
1611}
1612
1613gfx::ImageSkia BrowserView::GetWindowIcon() {
1614  if (browser_->is_app() || browser_->is_type_popup())
1615    return browser_->GetCurrentPageIcon().AsImageSkia();
1616  return gfx::ImageSkia();
1617}
1618
1619bool BrowserView::ShouldShowWindowIcon() const {
1620  // For Ash only, app host windows do not show an icon, crbug.com/119411.
1621  // Child windows (i.e. popups) do show an icon.
1622  if (browser_->host_desktop_type() == chrome::HOST_DESKTOP_TYPE_ASH &&
1623      browser_->is_app() &&
1624      browser_->is_trusted_source())
1625    return false;
1626
1627  return browser_->SupportsWindowFeature(Browser::FEATURE_TITLEBAR);
1628}
1629
1630bool BrowserView::ExecuteWindowsCommand(int command_id) {
1631  // This function handles WM_SYSCOMMAND, WM_APPCOMMAND, and WM_COMMAND.
1632#if defined(OS_WIN)
1633  if (command_id == IDC_DEBUG_FRAME_TOGGLE)
1634    GetWidget()->DebugToggleFrameType();
1635
1636  // In Windows 8 metro mode prevent sizing and moving.
1637  if (win8::IsSingleWindowMetroMode()) {
1638    // Windows uses the 4 lower order bits of |notification_code| for type-
1639    // specific information so we must exclude this when comparing.
1640    static const int sc_mask = 0xFFF0;
1641    if (((command_id & sc_mask) == SC_MOVE) ||
1642        ((command_id & sc_mask) == SC_SIZE) ||
1643        ((command_id & sc_mask) == SC_MAXIMIZE))
1644      return true;
1645  }
1646#endif
1647  // Translate WM_APPCOMMAND command ids into a command id that the browser
1648  // knows how to handle.
1649  int command_id_from_app_command = GetCommandIDForAppCommandID(command_id);
1650  if (command_id_from_app_command != -1)
1651    command_id = command_id_from_app_command;
1652
1653  return chrome::ExecuteCommand(browser_.get(), command_id);
1654}
1655
1656std::string BrowserView::GetWindowName() const {
1657  return chrome::GetWindowPlacementKey(browser_.get());
1658}
1659
1660void BrowserView::SaveWindowPlacement(const gfx::Rect& bounds,
1661                                      ui::WindowShowState show_state) {
1662  // If IsFullscreen() is true, we've just changed into fullscreen mode, and
1663  // we're catching the going-into-fullscreen sizing and positioning calls,
1664  // which we want to ignore.
1665  if (!ShouldSaveOrRestoreWindowPos())
1666    return;
1667
1668  if (!IsFullscreen() && chrome::ShouldSaveWindowPlacement(browser_.get())) {
1669    WidgetDelegate::SaveWindowPlacement(bounds, show_state);
1670    chrome::SaveWindowPlacement(browser_.get(), bounds, show_state);
1671  }
1672}
1673
1674bool BrowserView::GetSavedWindowPlacement(
1675    const views::Widget* widget,
1676    gfx::Rect* bounds,
1677    ui::WindowShowState* show_state) const {
1678  if (!ShouldSaveOrRestoreWindowPos())
1679    return false;
1680  chrome::GetSavedWindowBoundsAndShowState(browser_.get(), bounds, show_state);
1681
1682  if (browser_->is_type_popup() &&
1683      !browser_->is_app() &&
1684      !browser_->is_trusted_source()) {
1685    // This is normal non-app popup window. The value passed in |bounds|
1686    // represents two pieces of information:
1687    // - the position of the window, in screen coordinates (outer position).
1688    // - the size of the content area (inner size).
1689    // We need to use these values to determine the appropriate size and
1690    // position of the resulting window.
1691    if (IsToolbarVisible()) {
1692      // If we're showing the toolbar, we need to adjust |*bounds| to include
1693      // its desired height, since the toolbar is considered part of the
1694      // window's client area as far as GetWindowBoundsForClientBounds is
1695      // concerned...
1696      bounds->set_height(
1697          bounds->height() + toolbar_->GetPreferredSize().height());
1698    }
1699
1700    gfx::Rect window_rect = frame_->non_client_view()->
1701        GetWindowBoundsForClientBounds(*bounds);
1702    window_rect.set_origin(bounds->origin());
1703
1704    // When we are given x/y coordinates of 0 on a created popup window,
1705    // assume none were given by the window.open() command.
1706    if (window_rect.x() == 0 && window_rect.y() == 0) {
1707      gfx::Size size = window_rect.size();
1708      window_rect.set_origin(
1709          WindowSizer::GetDefaultPopupOrigin(size,
1710                                             browser_->host_desktop_type()));
1711    }
1712
1713    *bounds = window_rect;
1714    *show_state = ui::SHOW_STATE_NORMAL;
1715  }
1716
1717  // We return true because we can _always_ locate reasonable bounds using the
1718  // WindowSizer, and we don't want to trigger the Window's built-in "size to
1719  // default" handling because the browser window has no default preferred
1720  // size.
1721  return true;
1722}
1723
1724views::View* BrowserView::GetContentsView() {
1725  return contents_web_view_;
1726}
1727
1728views::ClientView* BrowserView::CreateClientView(views::Widget* widget) {
1729  return this;
1730}
1731
1732void BrowserView::OnWidgetActivationChanged(views::Widget* widget,
1733                                            bool active) {
1734  if (active)
1735    BrowserList::SetLastActive(browser_.get());
1736}
1737
1738void BrowserView::OnWindowBeginUserBoundsChange() {
1739  WebContents* web_contents = GetActiveWebContents();
1740  if (!web_contents)
1741    return;
1742  web_contents->GetRenderViewHost()->NotifyMoveOrResizeStarted();
1743}
1744
1745void BrowserView::OnWidgetMove() {
1746  if (!initialized_) {
1747    // Creating the widget can trigger a move. Ignore it until we've initialized
1748    // things.
1749    return;
1750  }
1751
1752  // Cancel any tabstrip animations, some of them may be invalidated by the
1753  // window being repositioned.
1754  // Comment out for one cycle to see if this fixes dist tests.
1755  // tabstrip_->DestroyDragController();
1756
1757  // status_bubble_ may be NULL if this is invoked during construction.
1758  if (status_bubble_.get())
1759    status_bubble_->Reposition();
1760
1761  BookmarkBubbleView::Hide();
1762
1763  // Close the omnibox popup, if any.
1764  LocationBarView* location_bar_view = GetLocationBarView();
1765  if (location_bar_view)
1766    location_bar_view->GetOmniboxView()->CloseOmniboxPopup();
1767}
1768
1769views::Widget* BrowserView::GetWidget() {
1770  return View::GetWidget();
1771}
1772
1773const views::Widget* BrowserView::GetWidget() const {
1774  return View::GetWidget();
1775}
1776
1777void BrowserView::GetAccessiblePanes(std::vector<views::View*>* panes) {
1778  // This should be in the order of pane traversal of the panes using F6
1779  // (Windows) or Ctrl+Back/Forward (Chrome OS).  If one of these is
1780  // invisible or has no focusable children, it will be automatically
1781  // skipped.
1782  panes->push_back(toolbar_);
1783  if (bookmark_bar_view_.get())
1784    panes->push_back(bookmark_bar_view_.get());
1785  if (infobar_container_)
1786    panes->push_back(infobar_container_);
1787  if (download_shelf_.get())
1788    panes->push_back(download_shelf_.get());
1789  panes->push_back(GetTabContentsContainerView());
1790  if (devtools_web_view_->visible())
1791    panes->push_back(devtools_web_view_);
1792}
1793
1794///////////////////////////////////////////////////////////////////////////////
1795// BrowserView, views::ClientView overrides:
1796
1797bool BrowserView::CanClose() {
1798  // You cannot close a frame for which there is an active originating drag
1799  // session.
1800  if (tabstrip_ && !tabstrip_->IsTabStripCloseable())
1801    return false;
1802
1803  // Give beforeunload handlers the chance to cancel the close before we hide
1804  // the window below.
1805  if (!browser_->ShouldCloseWindow())
1806    return false;
1807
1808  bool fast_tab_closing_enabled =
1809    CommandLine::ForCurrentProcess()->HasSwitch(switches::kEnableFastUnload);
1810
1811  if (!browser_->tab_strip_model()->empty()) {
1812    // Tab strip isn't empty.  Hide the frame (so it appears to have closed
1813    // immediately) and close all the tabs, allowing the renderers to shut
1814    // down. When the tab strip is empty we'll be called back again.
1815    frame_->Hide();
1816    browser_->OnWindowClosing();
1817    if (fast_tab_closing_enabled)
1818      browser_->tab_strip_model()->CloseAllTabs();
1819    return false;
1820  } else if (fast_tab_closing_enabled &&
1821        !browser_->HasCompletedUnloadProcessing()) {
1822    // The browser needs to finish running unload handlers.
1823    // Hide the frame (so it appears to have closed immediately), and
1824    // the browser will call us back again when it is ready to close.
1825    frame_->Hide();
1826    return false;
1827  }
1828
1829  // Empty TabStripModel, it's now safe to allow the Window to be closed.
1830  content::NotificationService::current()->Notify(
1831      chrome::NOTIFICATION_WINDOW_CLOSED,
1832      content::Source<gfx::NativeWindow>(frame_->GetNativeWindow()),
1833      content::NotificationService::NoDetails());
1834  return true;
1835}
1836
1837int BrowserView::NonClientHitTest(const gfx::Point& point) {
1838  return GetBrowserViewLayout()->NonClientHitTest(point);
1839}
1840
1841gfx::Size BrowserView::GetMinimumSize() {
1842  return GetBrowserViewLayout()->GetMinimumSize();
1843}
1844
1845///////////////////////////////////////////////////////////////////////////////
1846// BrowserView, views::View overrides:
1847
1848const char* BrowserView::GetClassName() const {
1849  return kViewClassName;
1850}
1851
1852void BrowserView::Layout() {
1853  if (!initialized_ || in_process_fullscreen_)
1854    return;
1855
1856  views::View::Layout();
1857
1858  // TODO(jamescook): Why was this in the middle of layout code?
1859  toolbar_->location_bar()->omnibox_view()->SetFocusable(IsToolbarVisible());
1860}
1861
1862void BrowserView::PaintChildren(gfx::Canvas* canvas) {
1863  // Paint the |infobar_container_| last so that it may paint its
1864  // overlapping tabs.
1865  for (int i = 0; i < child_count(); ++i) {
1866    View* child = child_at(i);
1867    if (child != infobar_container_ && !child->layer())
1868      child->Paint(canvas);
1869  }
1870
1871  infobar_container_->Paint(canvas);
1872}
1873
1874void BrowserView::ViewHierarchyChanged(
1875    const ViewHierarchyChangedDetails& details) {
1876  if (!initialized_ && details.is_add && details.child == this && GetWidget()) {
1877    InitViews();
1878    initialized_ = true;
1879  }
1880}
1881
1882void BrowserView::ChildPreferredSizeChanged(View* child) {
1883  Layout();
1884}
1885
1886void BrowserView::GetAccessibleState(ui::AXViewState* state) {
1887  state->role = ui::AX_ROLE_CLIENT;
1888}
1889
1890///////////////////////////////////////////////////////////////////////////////
1891// BrowserView, ui::AcceleratorTarget overrides:
1892
1893bool BrowserView::AcceleratorPressed(const ui::Accelerator& accelerator) {
1894#if defined(OS_CHROMEOS)
1895  // If accessibility is enabled, stop speech and return false so that key
1896  // combinations involving Search can be used for extra accessibility
1897  // functionality.
1898  if (accelerator.key_code() == ui::VKEY_LWIN &&
1899      g_browser_process->local_state()->GetBoolean(
1900          prefs::kSpokenFeedbackEnabled)) {
1901    TtsController::GetInstance()->Stop();
1902    return false;
1903  }
1904#endif
1905
1906  std::map<ui::Accelerator, int>::const_iterator iter =
1907      accelerator_table_.find(accelerator);
1908  DCHECK(iter != accelerator_table_.end());
1909  int command_id = iter->second;
1910
1911  chrome::BrowserCommandController* controller = browser_->command_controller();
1912  if (!controller->block_command_execution())
1913    UpdateAcceleratorMetrics(accelerator, command_id);
1914  return chrome::ExecuteCommand(browser_.get(), command_id);
1915}
1916
1917///////////////////////////////////////////////////////////////////////////////
1918// BrowserView, OmniboxPopupModelObserver overrides:
1919void BrowserView::OnOmniboxPopupShownOrHidden() {
1920  infobar_container_->SetMaxTopArrowHeight(GetMaxTopInfoBarArrowHeight());
1921}
1922
1923///////////////////////////////////////////////////////////////////////////////
1924// BrowserView, InfoBarContainer::Delegate overrides:
1925
1926SkColor BrowserView::GetInfoBarSeparatorColor() const {
1927  // NOTE: Keep this in sync with ToolbarView::OnPaint()!
1928  return (IsTabStripVisible() || !frame_->ShouldUseNativeFrame()) ?
1929      ThemeProperties::GetDefaultColor(
1930          ThemeProperties::COLOR_TOOLBAR_SEPARATOR) :
1931      SK_ColorBLACK;
1932}
1933
1934void BrowserView::InfoBarContainerStateChanged(bool is_animating) {
1935  ToolbarSizeChanged(is_animating);
1936}
1937
1938bool BrowserView::DrawInfoBarArrows(int* x) const {
1939  if (x) {
1940    gfx::Point anchor(toolbar_->location_bar()->GetLocationBarAnchorPoint());
1941    ConvertPointToTarget(toolbar_->location_bar(), this, &anchor);
1942    *x = anchor.x();
1943  }
1944  return true;
1945}
1946
1947void BrowserView::OnSysColorChange() {
1948  chrome::MaybeShowInvertBubbleView(this);
1949}
1950
1951void BrowserView::InitViews() {
1952  GetWidget()->AddObserver(this);
1953
1954  // Stow a pointer to this object onto the window handle so that we can get at
1955  // it later when all we have is a native view.
1956  GetWidget()->SetNativeWindowProperty(kBrowserViewKey, this);
1957
1958  // Stow a pointer to the browser's profile onto the window handle so that we
1959  // can get it later when all we have is a native view.
1960  GetWidget()->SetNativeWindowProperty(Profile::kProfileKey,
1961                                       browser_->profile());
1962
1963  // Start a hung plugin window detector for this browser object (as long as
1964  // hang detection is not disabled).
1965  if (!CommandLine::ForCurrentProcess()->HasSwitch(
1966          switches::kDisableHangMonitor)) {
1967    InitHangMonitor();
1968  }
1969
1970  LoadAccelerators();
1971
1972  infobar_container_ = new InfoBarContainerView(this);
1973  AddChildView(infobar_container_);
1974
1975  contents_web_view_ = new ContentsWebView(browser_->profile());
1976  contents_web_view_->set_id(VIEW_ID_TAB_CONTAINER);
1977  contents_web_view_->SetEmbedFullscreenWidgetMode(
1978      implicit_cast<content::WebContentsDelegate*>(browser_.get())->
1979          EmbedsFullscreenWidget());
1980
1981  web_contents_close_handler_.reset(
1982      new WebContentsCloseHandler(contents_web_view_));
1983
1984  devtools_web_view_ = new views::WebView(browser_->profile());
1985  devtools_web_view_->set_id(VIEW_ID_DEV_TOOLS_DOCKED);
1986  devtools_web_view_->SetVisible(false);
1987
1988  contents_container_ = new views::View();
1989  contents_container_->set_background(views::Background::CreateSolidBackground(
1990      ThemeProperties::GetDefaultColor(
1991          ThemeProperties::COLOR_CONTROL_BACKGROUND)));
1992  contents_container_->AddChildView(devtools_web_view_);
1993  contents_container_->AddChildView(contents_web_view_);
1994  contents_container_->SetLayoutManager(new ContentsLayoutManager(
1995      devtools_web_view_, contents_web_view_));
1996  AddChildView(contents_container_);
1997  set_contents_view(contents_container_);
1998
1999  // Top container holds tab strip and toolbar and lives at the front of the
2000  // view hierarchy.
2001  top_container_ = new TopContainerView(this);
2002  AddChildView(top_container_);
2003
2004  // TabStrip takes ownership of the controller.
2005  BrowserTabStripController* tabstrip_controller =
2006      new BrowserTabStripController(browser_.get(),
2007                                    browser_->tab_strip_model());
2008  tabstrip_ = new TabStrip(tabstrip_controller);
2009  top_container_->AddChildView(tabstrip_);
2010  tabstrip_controller->InitFromModel(tabstrip_);
2011
2012  toolbar_ = new ToolbarView(browser_.get());
2013  top_container_->AddChildView(toolbar_);
2014  toolbar_->Init();
2015
2016  InitStatusBubble();
2017  InitPermissionBubbleView();
2018
2019  // Create do-nothing view for the sake of controlling the z-order of the find
2020  // bar widget.
2021  find_bar_host_view_ = new View();
2022  AddChildView(find_bar_host_view_);
2023
2024  if (window_switcher_button_)
2025    AddChildView(window_switcher_button_);
2026
2027  immersive_mode_controller_->Init(this);
2028
2029  BrowserViewLayout* browser_view_layout = new BrowserViewLayout;
2030  browser_view_layout->Init(new BrowserViewLayoutDelegateImpl(this),
2031                            browser(),
2032                            this,
2033                            top_container_,
2034                            tabstrip_,
2035                            toolbar_,
2036                            infobar_container_,
2037                            contents_container_,
2038                            GetContentsLayoutManager(),
2039                            immersive_mode_controller_.get());
2040  SetLayoutManager(browser_view_layout);
2041
2042#if defined(OS_WIN)
2043  // Create a custom JumpList and add it to an observer of TabRestoreService
2044  // so we can update the custom JumpList when a tab is added or removed.
2045  if (JumpList::Enabled()) {
2046    load_complete_listener_.reset(new LoadCompleteListener(this));
2047  }
2048#endif
2049
2050  GetLocationBar()->GetOmniboxView()->model()->popup_model()->AddObserver(this);
2051}
2052
2053void BrowserView::LoadingAnimationCallback() {
2054  base::TimeTicks now = base::TimeTicks::Now();
2055  if (!last_animation_time_.is_null()) {
2056    UMA_HISTOGRAM_TIMES(
2057        "Tabs.LoadingAnimationTime",
2058        now - last_animation_time_);
2059  }
2060  last_animation_time_ = now;
2061  if (browser_->is_type_tabbed()) {
2062    // Loading animations are shown in the tab for tabbed windows.  We check the
2063    // browser type instead of calling IsTabStripVisible() because the latter
2064    // will return false for fullscreen windows, but we still need to update
2065    // their animations (so that when they come out of fullscreen mode they'll
2066    // be correct).
2067    tabstrip_->UpdateLoadingAnimations();
2068  } else if (ShouldShowWindowIcon()) {
2069    // ... or in the window icon area for popups and app windows.
2070    WebContents* web_contents =
2071        browser_->tab_strip_model()->GetActiveWebContents();
2072    // GetActiveWebContents can return NULL for example under Purify when
2073    // the animations are running slowly and this function is called on a timer
2074    // through LoadingAnimationCallback.
2075    frame_->UpdateThrobber(web_contents && web_contents->IsLoading());
2076  }
2077}
2078
2079void BrowserView::OnLoadCompleted() {
2080#if defined(OS_WIN)
2081  DCHECK(!jumplist_);
2082  jumplist_ = new JumpList();
2083  jumplist_->AddObserver(browser_->profile());
2084#endif
2085}
2086
2087BrowserViewLayout* BrowserView::GetBrowserViewLayout() const {
2088  return static_cast<BrowserViewLayout*>(GetLayoutManager());
2089}
2090
2091ContentsLayoutManager* BrowserView::GetContentsLayoutManager() const {
2092  return static_cast<ContentsLayoutManager*>(
2093      contents_container_->GetLayoutManager());
2094}
2095
2096bool BrowserView::MaybeShowBookmarkBar(WebContents* contents) {
2097  bool show_bookmark_bar = contents &&
2098      browser_->SupportsWindowFeature(Browser::FEATURE_BOOKMARKBAR);
2099  if (!show_bookmark_bar && !bookmark_bar_view_.get())
2100    return false;
2101  if (!bookmark_bar_view_.get()) {
2102    bookmark_bar_view_.reset(new BookmarkBarView(browser_.get(), this));
2103    bookmark_bar_view_->set_owned_by_client();
2104    bookmark_bar_view_->set_background(
2105        new BookmarkExtensionBackground(this,
2106                                        bookmark_bar_view_.get(),
2107                                        browser_.get()));
2108    bookmark_bar_view_->SetBookmarkBarState(
2109        browser_->bookmark_bar_state(),
2110        BookmarkBar::DONT_ANIMATE_STATE_CHANGE);
2111    GetBrowserViewLayout()->set_bookmark_bar(bookmark_bar_view_.get());
2112  }
2113  bookmark_bar_view_->SetVisible(show_bookmark_bar);
2114  bookmark_bar_view_->SetPageNavigator(contents);
2115
2116  // Update parenting for the bookmark bar. This may detach it from all views.
2117  bool needs_layout = false;
2118  views::View* new_parent = NULL;
2119  if (show_bookmark_bar) {
2120    if (bookmark_bar_view_->IsDetached())
2121      new_parent = this;
2122    else
2123      new_parent = top_container_;
2124  }
2125  if (new_parent != bookmark_bar_view_->parent()) {
2126    SetBookmarkBarParent(new_parent);
2127    needs_layout = true;
2128  }
2129
2130  // Check for updates to the desired size.
2131  if (bookmark_bar_view_->GetPreferredSize().height() !=
2132      bookmark_bar_view_->height())
2133    needs_layout = true;
2134
2135  return needs_layout;
2136}
2137
2138void BrowserView::SetBookmarkBarParent(views::View* new_parent) {
2139  if (new_parent == this) {
2140    // Add it underneath |top_container_| or at the end if top container isn't
2141    // found.
2142    int top_container_index = GetIndexOf(top_container_);
2143    if (top_container_index >= 0)
2144      AddChildViewAt(bookmark_bar_view_.get(), top_container_index);
2145    else
2146      AddChildView(bookmark_bar_view_.get());
2147  } else if (new_parent) {
2148    // No special stacking is required for other parents.
2149    new_parent->AddChildView(bookmark_bar_view_.get());
2150  } else {
2151    // Bookmark bar is being detached from all views because it is hidden.
2152    bookmark_bar_view_->parent()->RemoveChildView(bookmark_bar_view_.get());
2153  }
2154}
2155
2156bool BrowserView::MaybeShowInfoBar(WebContents* contents) {
2157  // TODO(beng): Remove this function once the interface between
2158  //             InfoBarContainer, DownloadShelfView and WebContents and this
2159  //             view is sorted out.
2160  return true;
2161}
2162
2163void BrowserView::UpdateDevToolsForContents(
2164    WebContents* web_contents, bool update_devtools_web_contents) {
2165  DevToolsWindow* new_devtools_window = web_contents ?
2166      DevToolsWindow::GetDockedInstanceForInspectedTab(web_contents) : NULL;
2167
2168  // Replace devtools WebContents.
2169  WebContents* new_contents = new_devtools_window ?
2170      new_devtools_window->web_contents() : NULL;
2171  if (devtools_web_view_->web_contents() != new_contents &&
2172      update_devtools_web_contents) {
2173    devtools_web_view_->SetWebContents(new_contents);
2174  }
2175
2176  if (!devtools_window_ && new_devtools_window &&
2177      !devtools_focus_tracker_.get()) {
2178    // Install devtools focus tracker when dev tools window is shown for the
2179    // first time.
2180    devtools_focus_tracker_.reset(
2181        new views::ExternalFocusTracker(devtools_web_view_,
2182                                        GetFocusManager()));
2183  }
2184
2185  // Restore focus to the last focused view when hiding devtools window.
2186  if (devtools_window_ && !new_devtools_window &&
2187      devtools_focus_tracker_.get()) {
2188    devtools_focus_tracker_->FocusLastFocusedExternalView();
2189    devtools_focus_tracker_.reset();
2190  }
2191
2192  devtools_window_ = new_devtools_window;
2193  if (devtools_window_) {
2194    devtools_web_view_->SetPreferredSize(devtools_window_->GetMinimumSize());
2195    devtools_web_view_->SetVisible(true);
2196    GetContentsLayoutManager()->SetContentsResizingStrategy(
2197        devtools_window_->GetContentsResizingStrategy());
2198  } else {
2199    devtools_web_view_->SetVisible(false);
2200    GetContentsLayoutManager()->SetContentsResizingStrategy(
2201        DevToolsContentsResizingStrategy());
2202  }
2203  contents_container_->Layout();
2204}
2205
2206void BrowserView::UpdateUIForContents(WebContents* contents) {
2207  bool needs_layout = MaybeShowBookmarkBar(contents);
2208  // TODO(jamescook): This function always returns true. Remove it and figure
2209  // out when layout is actually required.
2210  needs_layout |= MaybeShowInfoBar(contents);
2211  if (needs_layout)
2212    Layout();
2213}
2214
2215void BrowserView::ProcessFullscreen(bool fullscreen,
2216                                    FullscreenMode mode,
2217                                    const GURL& url,
2218                                    FullscreenExitBubbleType bubble_type) {
2219  if (in_process_fullscreen_)
2220    return;
2221  in_process_fullscreen_ = true;
2222
2223  // Reduce jankiness during the following position changes by:
2224  //   * Hiding the window until it's in the final position
2225  //   * Ignoring all intervening Layout() calls, which resize the webpage and
2226  //     thus are slow and look ugly (enforced via |in_process_fullscreen_|).
2227  LocationBarView* location_bar = GetLocationBarView();
2228
2229  if (mode == METRO_SNAP_FULLSCREEN || !fullscreen) {
2230    // Hide the fullscreen bubble as soon as possible, since the mode toggle can
2231    // take enough time for the user to notice.
2232    fullscreen_bubble_.reset();
2233  }
2234
2235  if (fullscreen) {
2236    // Move focus out of the location bar if necessary.
2237    views::FocusManager* focus_manager = GetFocusManager();
2238    DCHECK(focus_manager);
2239    // Look for focus in the location bar itself or any child view.
2240    if (location_bar->Contains(focus_manager->GetFocusedView()))
2241      focus_manager->ClearFocus();
2242  }
2243
2244  // Toggle fullscreen mode.
2245  frame_->SetFullscreen(fullscreen);
2246
2247  // Enable immersive before the browser refreshes its list of enabled commands.
2248  if (mode != METRO_SNAP_FULLSCREEN && ShouldUseImmersiveFullscreenForUrl(url))
2249    immersive_mode_controller_->SetEnabled(fullscreen);
2250
2251  browser_->WindowFullscreenStateChanged();
2252
2253  if (fullscreen && !chrome::IsRunningInAppMode() &&
2254      mode != METRO_SNAP_FULLSCREEN) {
2255    UpdateFullscreenExitBubbleContent(url, bubble_type);
2256  }
2257
2258  // Undo our anti-jankiness hacks and force a re-layout. We also need to
2259  // recompute the height of the infobar top arrow because toggling in and out
2260  // of fullscreen changes it. Calling ToolbarSizeChanged() will do both these
2261  // things since it computes the arrow height directly and forces a layout
2262  // indirectly via UpdateUIForContents(). Reset |in_process_fullscreen_| in
2263  // order to let the layout occur.
2264  in_process_fullscreen_ = false;
2265  ToolbarSizeChanged(false);
2266}
2267
2268bool BrowserView::ShouldUseImmersiveFullscreenForUrl(const GURL& url) const {
2269  // Kiosk mode needs the whole screen, and if we're not in an Ash desktop
2270  // immersive fullscreen doesn't exist.
2271  if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kKioskMode) ||
2272      browser()->host_desktop_type() != chrome::HOST_DESKTOP_TYPE_ASH) {
2273    return false;
2274  }
2275
2276  return url.is_empty();
2277}
2278
2279void BrowserView::LoadAccelerators() {
2280  views::FocusManager* focus_manager = GetFocusManager();
2281  DCHECK(focus_manager);
2282
2283  // Let's fill our own accelerator table.
2284  const bool is_app_mode = chrome::IsRunningInForcedAppMode();
2285  const std::vector<chrome::AcceleratorMapping> accelerator_list(
2286      chrome::GetAcceleratorList());
2287  for (std::vector<chrome::AcceleratorMapping>::const_iterator it =
2288           accelerator_list.begin(); it != accelerator_list.end(); ++it) {
2289    // In app mode, only allow accelerators of white listed commands to pass
2290    // through.
2291    if (is_app_mode && !chrome::IsCommandAllowedInAppMode(it->command_id))
2292      continue;
2293
2294    ui::Accelerator accelerator(it->keycode, it->modifiers);
2295    accelerator_table_[accelerator] = it->command_id;
2296
2297    // Also register with the focus manager.
2298    focus_manager->RegisterAccelerator(
2299        accelerator, ui::AcceleratorManager::kNormalPriority, this);
2300  }
2301}
2302
2303int BrowserView::GetCommandIDForAppCommandID(int app_command_id) const {
2304#if defined(OS_WIN)
2305  switch (app_command_id) {
2306    // NOTE: The order here matches the APPCOMMAND declaration order in the
2307    // Windows headers.
2308    case APPCOMMAND_BROWSER_BACKWARD: return IDC_BACK;
2309    case APPCOMMAND_BROWSER_FORWARD:  return IDC_FORWARD;
2310    case APPCOMMAND_BROWSER_REFRESH:  return IDC_RELOAD;
2311    case APPCOMMAND_BROWSER_HOME:     return IDC_HOME;
2312    case APPCOMMAND_BROWSER_STOP:     return IDC_STOP;
2313    case APPCOMMAND_BROWSER_SEARCH:   return IDC_FOCUS_SEARCH;
2314    case APPCOMMAND_HELP:             return IDC_HELP_PAGE_VIA_KEYBOARD;
2315    case APPCOMMAND_NEW:              return IDC_NEW_TAB;
2316    case APPCOMMAND_OPEN:             return IDC_OPEN_FILE;
2317    case APPCOMMAND_CLOSE:            return IDC_CLOSE_TAB;
2318    case APPCOMMAND_SAVE:             return IDC_SAVE_PAGE;
2319    case APPCOMMAND_PRINT:            return IDC_PRINT;
2320    case APPCOMMAND_COPY:             return IDC_COPY;
2321    case APPCOMMAND_CUT:              return IDC_CUT;
2322    case APPCOMMAND_PASTE:            return IDC_PASTE;
2323
2324      // TODO(pkasting): http://b/1113069 Handle these.
2325    case APPCOMMAND_UNDO:
2326    case APPCOMMAND_REDO:
2327    case APPCOMMAND_SPELL_CHECK:
2328    default:                          return -1;
2329  }
2330#else
2331  // App commands are Windows-specific so there's nothing to do here.
2332  return -1;
2333#endif
2334}
2335
2336void BrowserView::InitHangMonitor() {
2337#if defined(OS_WIN)
2338  PrefService* pref_service = g_browser_process->local_state();
2339  if (!pref_service)
2340    return;
2341
2342  int plugin_message_response_timeout =
2343      pref_service->GetInteger(prefs::kPluginMessageResponseTimeout);
2344  int hung_plugin_detect_freq =
2345      pref_service->GetInteger(prefs::kHungPluginDetectFrequency);
2346#if defined(USE_AURA)
2347  HWND window = GetWidget()->GetNativeView()->GetHost()->
2348      GetAcceleratedWidget();
2349#else
2350  HWND window = GetWidget()->GetNativeView();
2351#endif
2352  if ((hung_plugin_detect_freq > 0) &&
2353      hung_window_detector_.Initialize(window,
2354                                       plugin_message_response_timeout)) {
2355    ticker_.set_tick_interval(hung_plugin_detect_freq);
2356    ticker_.RegisterTickHandler(&hung_window_detector_);
2357    ticker_.Start();
2358
2359    pref_service->SetInteger(prefs::kPluginMessageResponseTimeout,
2360                             plugin_message_response_timeout);
2361    pref_service->SetInteger(prefs::kHungPluginDetectFrequency,
2362                             hung_plugin_detect_freq);
2363  }
2364#endif
2365}
2366
2367void BrowserView::UpdateAcceleratorMetrics(const ui::Accelerator& accelerator,
2368                                           int command_id) {
2369  const ui::KeyboardCode key_code = accelerator.key_code();
2370  if (command_id == IDC_HELP_PAGE_VIA_KEYBOARD && key_code == ui::VKEY_F1)
2371    content::RecordAction(UserMetricsAction("ShowHelpTabViaF1"));
2372
2373  if (command_id == IDC_BOOKMARK_PAGE)
2374    UMA_HISTOGRAM_ENUMERATION("Bookmarks.EntryPoint",
2375                              BOOKMARK_ENTRY_POINT_ACCELERATOR,
2376                              BOOKMARK_ENTRY_POINT_LIMIT);
2377
2378#if defined(OS_CHROMEOS)
2379  // Collect information about the relative popularity of various accelerators
2380  // on Chrome OS.
2381  switch (command_id) {
2382    case IDC_BACK:
2383      if (key_code == ui::VKEY_BACK)
2384        content::RecordAction(UserMetricsAction("Accel_Back_Backspace"));
2385      else if (key_code == ui::VKEY_BROWSER_BACK)
2386        content::RecordAction(UserMetricsAction("Accel_Back_F1"));
2387      else if (key_code == ui::VKEY_LEFT)
2388        content::RecordAction(UserMetricsAction("Accel_Back_Left"));
2389      break;
2390    case IDC_FORWARD:
2391      if (key_code == ui::VKEY_BACK)
2392        content::RecordAction(UserMetricsAction("Accel_Forward_Backspace"));
2393      else if (key_code == ui::VKEY_BROWSER_FORWARD)
2394        content::RecordAction(UserMetricsAction("Accel_Forward_F2"));
2395      else if (key_code == ui::VKEY_RIGHT)
2396        content::RecordAction(UserMetricsAction("Accel_Forward_Right"));
2397      break;
2398    case IDC_RELOAD:
2399    case IDC_RELOAD_IGNORING_CACHE:
2400      if (key_code == ui::VKEY_R)
2401        content::RecordAction(UserMetricsAction("Accel_Reload_R"));
2402      else if (key_code == ui::VKEY_BROWSER_REFRESH)
2403        content::RecordAction(UserMetricsAction("Accel_Reload_F3"));
2404      break;
2405    case IDC_FOCUS_LOCATION:
2406      if (key_code == ui::VKEY_D)
2407        content::RecordAction(UserMetricsAction("Accel_FocusLocation_D"));
2408      else if (key_code == ui::VKEY_L)
2409        content::RecordAction(UserMetricsAction("Accel_FocusLocation_L"));
2410      break;
2411    case IDC_FOCUS_SEARCH:
2412      if (key_code == ui::VKEY_E)
2413        content::RecordAction(UserMetricsAction("Accel_FocusSearch_E"));
2414      else if (key_code == ui::VKEY_K)
2415        content::RecordAction(UserMetricsAction("Accel_FocusSearch_K"));
2416      break;
2417    default:
2418      // Do nothing.
2419      break;
2420  }
2421#endif
2422}
2423
2424// static
2425BrowserWindow* BrowserWindow::CreateBrowserWindow(Browser* browser) {
2426  // Create the view and the frame. The frame will attach itself via the view
2427  // so we don't need to do anything with the pointer.
2428  BrowserView* view = new BrowserView();
2429  view->Init(browser);
2430  (new BrowserFrame(view))->InitBrowserFrame();
2431  view->GetWidget()->non_client_view()->SetAccessibleName(
2432      l10n_util::GetStringUTF16(IDS_PRODUCT_NAME));
2433  return view;
2434}
2435
2436// static
2437chrome::HostDesktopType BrowserWindow::AdjustHostDesktopType(
2438    chrome::HostDesktopType desktop_type) {
2439  return NativeBrowserFrameFactory::AdjustHostDesktopType(desktop_type);
2440}
2441
2442void BrowserView::ShowAvatarBubble(WebContents* web_contents,
2443                                   const gfx::Rect& rect) {
2444  gfx::Point origin(rect.origin());
2445  views::View::ConvertPointToScreen(GetTabContentsContainerView(), &origin);
2446  gfx::Rect bounds(origin, rect.size());
2447
2448  AvatarMenuBubbleView::ShowBubble(this, views::BubbleBorder::TOP_RIGHT,
2449      views::BubbleBorder::ALIGN_EDGE_TO_ANCHOR_EDGE, bounds, browser_.get());
2450}
2451
2452void BrowserView::ShowAvatarBubbleFromAvatarButton(AvatarBubbleMode mode) {
2453  if (switches::IsNewAvatarMenu()) {
2454    NewAvatarButton* button = frame_->GetNewAvatarMenuButton();
2455    if (button) {
2456      gfx::Point origin;
2457      views::View::ConvertPointToScreen(button, &origin);
2458      gfx::Rect bounds(origin, size());
2459
2460      ProfileChooserView::BubbleViewMode view_mode =
2461          (mode == BrowserWindow::AVATAR_BUBBLE_MODE_ACCOUNT_MANAGEMENT) ?
2462          ProfileChooserView::BUBBLE_VIEW_MODE_ACCOUNT_MANAGEMENT :
2463          ProfileChooserView::BUBBLE_VIEW_MODE_PROFILE_CHOOSER;
2464      ProfileChooserView::ShowBubble(
2465          view_mode, button, views::BubbleBorder::TOP_RIGHT,
2466          views::BubbleBorder::ALIGN_EDGE_TO_ANCHOR_EDGE, bounds, browser());
2467    }
2468  } else {
2469    AvatarMenuButton* button = frame_->GetAvatarMenuButton();
2470    if (button)
2471      button->ShowAvatarBubble();
2472  }
2473}
2474
2475void BrowserView::ShowPasswordGenerationBubble(
2476    const gfx::Rect& rect,
2477    const autofill::PasswordForm& form,
2478    autofill::PasswordGenerator* password_generator) {
2479  // Create a rect in the content bounds that the bubble will point to.
2480  gfx::Point origin(rect.origin());
2481  views::View::ConvertPointToScreen(GetTabContentsContainerView(), &origin);
2482  gfx::Rect bounds(origin, rect.size());
2483
2484  // Create the bubble.
2485  WebContents* web_contents = GetActiveWebContents();
2486  if (!web_contents)
2487    return;
2488
2489  PasswordGenerationBubbleView* bubble = new PasswordGenerationBubbleView(
2490      form,
2491      bounds,
2492      this,
2493      web_contents->GetRenderViewHost(),
2494      ChromePasswordManagerClient::GetManagerFromWebContents(web_contents),
2495      password_generator,
2496      browser_.get(),
2497      GetWidget()->GetThemeProvider());
2498
2499  views::BubbleDelegateView::CreateBubble(bubble);
2500  bubble->SetAlignment(views::BubbleBorder::ALIGN_ARROW_TO_MID_ANCHOR);
2501  bubble->GetWidget()->Show();
2502}
2503
2504void BrowserView::OverscrollUpdate(int delta_y) {
2505  if (scroll_end_effect_controller_)
2506    scroll_end_effect_controller_->OverscrollUpdate(delta_y);
2507}
2508
2509int BrowserView::GetRenderViewHeightInsetWithDetachedBookmarkBar() {
2510  if (browser_->bookmark_bar_state() != BookmarkBar::DETACHED ||
2511      !bookmark_bar_view_.get() || !bookmark_bar_view_->IsDetached()) {
2512    return 0;
2513  }
2514  // Don't use bookmark_bar_view_->height() which won't be the final height if
2515  // the bookmark bar is animating.
2516  return chrome::kNTPBookmarkBarHeight -
2517      bookmark_bar_view_->GetFullyDetachedToolbarOverlap();
2518}
2519
2520void BrowserView::ExecuteExtensionCommand(
2521    const extensions::Extension* extension,
2522    const extensions::Command& command) {
2523  toolbar_->ExecuteExtensionCommand(extension, command);
2524}
2525
2526void BrowserView::ShowPageActionPopup(
2527    const extensions::Extension* extension) {
2528  toolbar_->ShowPageActionPopup(extension);
2529}
2530
2531void BrowserView::ShowBrowserActionPopup(
2532    const extensions::Extension* extension) {
2533  toolbar_->ShowBrowserActionPopup(extension);
2534}
2535
2536void BrowserView::DoCutCopyPaste(void (WebContents::*method)(),
2537                                 int command_id) {
2538  WebContents* contents = browser_->tab_strip_model()->GetActiveWebContents();
2539  if (!contents)
2540    return;
2541  if (DoCutCopyPasteForWebContents(contents, method))
2542    return;
2543
2544  DevToolsWindow* devtools_window =
2545      DevToolsWindow::GetDockedInstanceForInspectedTab(contents);
2546  if (devtools_window &&
2547      DoCutCopyPasteForWebContents(devtools_window->web_contents(), method)) {
2548    return;
2549  }
2550
2551  views::FocusManager* focus_manager = GetFocusManager();
2552  views::View* focused = focus_manager->GetFocusedView();
2553  if (focused &&
2554      (!strcmp(focused->GetClassName(), views::Textfield::kViewClassName) ||
2555       !strcmp(focused->GetClassName(), OmniboxViewViews::kViewClassName))) {
2556    views::Textfield* textfield = static_cast<views::Textfield*>(focused);
2557    textfield->ExecuteCommand(command_id);
2558  }
2559}
2560
2561bool BrowserView::DoCutCopyPasteForWebContents(
2562    WebContents* contents,
2563    void (WebContents::*method)()) {
2564  gfx::NativeView native_view = contents->GetView()->GetContentNativeView();
2565  if (!native_view)
2566    return false;
2567#if defined(USE_AURA)
2568  if (native_view->HasFocus()) {
2569#elif defined(OS_WIN)
2570  if (native_view == ::GetFocus()) {
2571#endif
2572    (contents->*method)();
2573    return true;
2574  }
2575
2576  return false;
2577}
2578
2579void BrowserView::ActivateAppModalDialog() const {
2580  // If another browser is app modal, flash and activate the modal browser.
2581  AppModalDialog* active_dialog =
2582      AppModalDialogQueue::GetInstance()->active_dialog();
2583  if (!active_dialog)
2584    return;
2585
2586  Browser* modal_browser =
2587      chrome::FindBrowserWithWebContents(active_dialog->web_contents());
2588  if (modal_browser && (browser_ != modal_browser)) {
2589    modal_browser->window()->FlashFrame(true);
2590    modal_browser->window()->Activate();
2591  }
2592
2593  AppModalDialogQueue::GetInstance()->ActivateModalDialog();
2594}
2595
2596int BrowserView::GetMaxTopInfoBarArrowHeight() {
2597  int top_arrow_height = 0;
2598  // Only show the arrows when not in fullscreen and when there's no omnibox
2599  // popup.
2600  if (!IsFullscreen() &&
2601      !GetLocationBar()->GetOmniboxView()->model()->popup_model()->IsOpen()) {
2602    gfx::Point icon_bottom(
2603        toolbar_->location_bar()->GetLocationBarAnchorPoint());
2604    ConvertPointToTarget(toolbar_->location_bar(), this, &icon_bottom);
2605    gfx::Point infobar_top(0, infobar_container_->GetVerticalOverlap(NULL));
2606    ConvertPointToTarget(infobar_container_, this, &infobar_top);
2607    top_arrow_height = infobar_top.y() - icon_bottom.y();
2608  }
2609  return top_arrow_height;
2610}
2611