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