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