Home | History | Annotate | Download | only in views
      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/external_tab_container_win.h"
      6 
      7 #include <atlbase.h>
      8 #include <atlapp.h>
      9 #include <atlconv.h>
     10 #include <atlcrack.h>
     11 #include <atlmisc.h>
     12 #include <string>
     13 
     14 #include "base/bind.h"
     15 #include "base/bind_helpers.h"
     16 #include "base/debug/trace_event.h"
     17 #include "base/i18n/rtl.h"
     18 #include "base/logging.h"
     19 #include "base/memory/scoped_ptr.h"
     20 #include "base/strings/string16.h"
     21 #include "base/strings/utf_string_conversions.h"
     22 #include "base/time/time.h"
     23 #include "base/win/win_util.h"
     24 #include "chrome/app/chrome_command_ids.h"
     25 #include "chrome/app/chrome_dll_resource.h"
     26 #include "chrome/browser/automation/automation_provider.h"
     27 #include "chrome/browser/chrome_notification_types.h"
     28 #include "chrome/browser/devtools/devtools_toggle_action.h"
     29 #include "chrome/browser/devtools/devtools_window.h"
     30 #include "chrome/browser/file_select_helper.h"
     31 #include "chrome/browser/history/history_tab_helper.h"
     32 #include "chrome/browser/history/history_types.h"
     33 #include "chrome/browser/infobars/infobar_service.h"
     34 #include "chrome/browser/media/media_stream_infobar_delegate.h"
     35 #include "chrome/browser/pepper_broker_infobar_delegate.h"
     36 #include "chrome/browser/profiles/profile.h"
     37 #include "chrome/browser/repost_form_warning_controller.h"
     38 #include "chrome/browser/themes/theme_properties.h"
     39 #include "chrome/browser/ui/app_modal_dialogs/javascript_dialog_manager.h"
     40 #include "chrome/browser/ui/browser.h"
     41 #include "chrome/browser/ui/browser_dialogs.h"
     42 #include "chrome/browser/ui/browser_tab_contents.h"
     43 #include "chrome/browser/ui/browser_window.h"
     44 #include "chrome/browser/ui/tab_modal_confirm_dialog.h"
     45 #include "chrome/browser/ui/views/infobars/infobar_container_view.h"
     46 #include "chrome/browser/ui/views/tab_contents/render_view_context_menu_win.h"
     47 #include "chrome/common/automation_messages.h"
     48 #include "chrome/common/chrome_constants.h"
     49 #include "chrome/common/render_messages.h"
     50 #include "chrome/common/url_constants.h"
     51 #include "content/public/browser/load_notification_details.h"
     52 #include "content/public/browser/native_web_keyboard_event.h"
     53 #include "content/public/browser/navigation_details.h"
     54 #include "content/public/browser/navigation_entry.h"
     55 #include "content/public/browser/notification_service.h"
     56 #include "content/public/browser/render_process_host.h"
     57 #include "content/public/browser/render_view_host.h"
     58 #include "content/public/browser/web_contents.h"
     59 #include "content/public/browser/web_contents_view.h"
     60 #include "content/public/common/bindings_policy.h"
     61 #include "content/public/common/frame_navigate_params.h"
     62 #include "content/public/common/page_transition_types.h"
     63 #include "content/public/common/page_zoom.h"
     64 #include "content/public/common/renderer_preferences.h"
     65 #include "content/public/common/ssl_status.h"
     66 #include "grit/generated_resources.h"
     67 #include "grit/locale_settings.h"
     68 #include "third_party/WebKit/public/platform/WebReferrerPolicy.h"
     69 #include "ui/base/l10n/l10n_util.h"
     70 #include "ui/base/models/menu_model.h"
     71 #include "ui/base/view_prop.h"
     72 #include "ui/events/event_utils.h"
     73 #include "ui/views/controls/webview/webview.h"
     74 #include "ui/views/layout/grid_layout.h"
     75 #include "ui/views/widget/widget.h"
     76 #include "ui/views/win/hwnd_util.h"
     77 
     78 #if defined(USE_AURA)
     79 #include "ui/aura/root_window.h"
     80 #include "ui/aura/window.h"
     81 #include "ui/views/widget/desktop_aura/desktop_native_widget_aura.h"
     82 #include "ui/views/widget/desktop_aura/desktop_root_window_host_win.h"
     83 #endif
     84 
     85 using content::BrowserThread;
     86 using content::LoadNotificationDetails;
     87 using content::NativeWebKeyboardEvent;
     88 using content::NavigationController;
     89 using content::NavigationEntry;
     90 using content::OpenURLParams;
     91 using content::RenderViewHost;
     92 using content::SSLStatus;
     93 using content::WebContents;
     94 
     95 namespace {
     96 
     97 static const char kWindowObjectKey[] = "ChromeWindowObject";
     98 
     99 // The following helper functions exist to localize UI toolkit-specific code.
    100 
    101 void ShowNativeView(gfx::NativeView view) {
    102 #if !defined(USE_AURA)
    103   ::ShowWindow(view, SW_SHOWNA);
    104 #endif
    105 }
    106 
    107 scoped_ptr<NativeWebKeyboardEvent> CreateKeyboardEvent(const MSG& msg) {
    108 #if defined(USE_AURA)
    109   // TODO(grt): confirm that this is a translated character event.
    110   ui::KeyEvent key_event(msg, true);
    111   return scoped_ptr<NativeWebKeyboardEvent>(
    112       new NativeWebKeyboardEvent(&key_event));
    113 #else
    114   return scoped_ptr<NativeWebKeyboardEvent>(new NativeWebKeyboardEvent(msg));
    115 #endif
    116 }
    117 
    118 const MSG& MessageFromKeyboardEvent(const NativeWebKeyboardEvent& event) {
    119 #if defined(USE_AURA)
    120   DCHECK(event.os_event);
    121   return event.os_event->native_event();
    122 #else
    123   return event.os_event;
    124 #endif
    125 }
    126 
    127 // Convert ui::MenuModel into a serializable form for Chrome Frame
    128 ContextMenuModel* ConvertMenuModel(const ui::MenuModel* ui_model) {
    129   ContextMenuModel* new_model = new ContextMenuModel;
    130 
    131   const int item_count = ui_model->GetItemCount();
    132   new_model->items.reserve(item_count);
    133   for (int i = 0; i < item_count; ++i) {
    134     if (ui_model->IsVisibleAt(i)) {
    135       ContextMenuModel::Item item;
    136       item.type = ui_model->GetTypeAt(i);
    137       item.item_id = ui_model->GetCommandIdAt(i);
    138       item.label = ui_model->GetLabelAt(i);
    139       item.checked = ui_model->IsItemCheckedAt(i);
    140       item.enabled = ui_model->IsEnabledAt(i);
    141       if (item.type == ui::MenuModel::TYPE_SUBMENU)
    142         item.submenu = ConvertMenuModel(ui_model->GetSubmenuModelAt(i));
    143 
    144       new_model->items.push_back(item);
    145     }
    146   }
    147 
    148   return new_model;
    149 }
    150 
    151 // Generates a referrer header used by the AutomationProvider on navigation.
    152 // Based on code from
    153 // http://src.chromium.org/viewvc/blink/trunk/Source/weborigin/SecurityPolicy.cpp?revision=151498
    154 bool ShouldHideReferrer(const GURL& url, const GURL& referrer) {
    155   bool referrer_is_secure = referrer.SchemeIsSecure();
    156   bool referrer_is_web_url = referrer_is_secure || referrer.SchemeIs("http");
    157 
    158   if (!referrer_is_web_url)
    159     return true;
    160 
    161   if (!referrer_is_secure)
    162     return false;
    163 
    164   return !url.SchemeIsSecure();
    165 }
    166 
    167 GURL GenerateReferrer(blink::WebReferrerPolicy policy,
    168                       const GURL& url,
    169                       const GURL& referrer) {
    170   if (referrer.is_empty())
    171     return GURL();
    172 
    173   switch (policy) {
    174     case blink::WebReferrerPolicyNever:
    175       return GURL();
    176     case blink::WebReferrerPolicyAlways:
    177       return referrer;
    178     case blink::WebReferrerPolicyOrigin:
    179       return referrer.GetOrigin();
    180     default:
    181       break;
    182   }
    183 
    184   return ShouldHideReferrer(url, referrer) ? GURL() : referrer;
    185 }
    186 
    187 
    188 }  // namespace
    189 
    190 #if defined(USE_AURA)
    191 typedef ATL::CWinTraits<WS_POPUP | WS_CLIPSIBLINGS | WS_CLIPCHILDREN,
    192                         WS_EX_NOACTIVATE | WS_EX_TOOLWINDOW>
    193     ContainerWindowHWNDTraits;
    194 
    195 // A window placed in the parent/child hierarchy between the host (e.g., a
    196 // ChromeFrameAutomationClient window) and the Aura DesktopRootWindowHostWin.
    197 // This non-activatable window is necessary to prevent focus from warping from
    198 // the DRWHW up to the CFAC window during reparenting. This is not needed in the
    199 // non-Aura case because the ExternalTabContainer's primary widget takes this
    200 // role (the RenderWidgetHostViewWin's HWND is a grandchild of it).
    201 class ContainerWindow : public ATL::CWindowImpl<ContainerWindow,
    202                                                 ATL::CWindow,
    203                                                 ContainerWindowHWNDTraits>,
    204                         public base::SupportsWeakPtr<ContainerWindow> {
    205  public:
    206   DECLARE_WND_CLASS_EX(NULL, CS_DBLCLKS, 0);
    207 
    208   BEGIN_MSG_MAP_EX(ContainerWindow)
    209     MSG_WM_MOVE(OnMove)
    210     MSG_WM_SHOWWINDOW(OnShowWindow)
    211     MSG_WM_SIZE(OnSize)
    212   END_MSG_MAP()
    213 
    214   ContainerWindow(HWND parent, const gfx::Rect& bounds) : widget_(NULL) {
    215     RECT rect = bounds.ToRECT();
    216     Create(parent, rect);
    217   }
    218 
    219   HWND hwnd() {
    220     DCHECK(::IsWindow(m_hWnd));
    221     return m_hWnd;
    222   }
    223 
    224   // Sets the Widget. The widget's HWND is made activateable as part of the
    225   // operation.
    226   void SetWidget(views::Widget* widget) {
    227     widget_ = widget;
    228 
    229     HWND window = child();
    230     ::SetWindowLong(
    231         window, GWL_STYLE,
    232         (::GetWindowLong(window, GWL_STYLE) & ~WS_POPUP) | WS_CHILD);
    233     ::SetWindowLong(window, GWL_EXSTYLE,
    234                     (::GetWindowLong(window, GWL_EXSTYLE) & ~WS_EX_NOACTIVATE));
    235 
    236     ::SetParent(window, hwnd());
    237   }
    238 
    239  protected:
    240   virtual void OnFinalMessage(HWND hwnd) OVERRIDE {
    241     delete this;
    242   }
    243 
    244  private:
    245   HWND child() {
    246     return views::HWNDForWidget(widget_);
    247   }
    248 
    249   void OnMove(const CPoint& position) {
    250     if (!widget_)
    251       return;
    252     ::SetWindowPos(child(), NULL, position.x, position.y, 0, 0,
    253                    SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOZORDER);
    254   }
    255 
    256   void OnShowWindow(BOOL show, UINT status) {
    257     if (!widget_)
    258       return;
    259     // We need to show |widget_| without changing focus. Contrary to the name,
    260     // Widget::ShowInactive() still changes activation.  So, we inline the
    261     // implementation minus the focus change.
    262     ::ShowWindow(child(), SW_SHOWNA);
    263     widget_->GetNativeView()->Show();
    264   }
    265 
    266   void OnSize(UINT type, const CSize& size) {
    267     if (!widget_)
    268       return;
    269     ::SetWindowPos(child(), NULL, 0, 0, size.cx, size.cy,
    270                    SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOZORDER);
    271   }
    272 
    273   views::Widget* widget_;
    274 
    275   DISALLOW_COPY_AND_ASSIGN(ContainerWindow);
    276 };
    277 
    278 // A specialization of DesktopRootWindowHost for an external tab container that
    279 // saves and restores focus as the ETC is blurred and focused. DRWHW ordinarily
    280 // does this during window activation and deactivation. Since the ETC is a child
    281 // window, it does not receive activation messages.
    282 class ExternalTabRootWindowHost : public views::DesktopRootWindowHostWin {
    283  public:
    284   ExternalTabRootWindowHost(
    285       views::internal::NativeWidgetDelegate* native_widget_delegate,
    286       views::DesktopNativeWidgetAura* desktop_native_widget_aura)
    287       : views::DesktopRootWindowHostWin(native_widget_delegate,
    288                                         desktop_native_widget_aura) {}
    289 
    290  protected:
    291   // HWNDMessageHandlerDelegate methods:
    292   virtual void HandleNativeFocus(HWND last_focused_window) OVERRIDE {
    293     views::DesktopRootWindowHostWin::HandleNativeFocus(last_focused_window);
    294     RestoreFocusOnActivate();
    295   }
    296 
    297   virtual void HandleNativeBlur(HWND focused_window) OVERRIDE {
    298     SaveFocusOnDeactivate();
    299     views::DesktopRootWindowHostWin::HandleNativeBlur(focused_window);
    300   }
    301 
    302  private:
    303   DISALLOW_COPY_AND_ASSIGN(ExternalTabRootWindowHost);
    304 };
    305 #endif
    306 
    307 base::LazyInstance<ExternalTabContainerWin::PendingTabs>
    308     ExternalTabContainerWin::pending_tabs_ = LAZY_INSTANCE_INITIALIZER;
    309 
    310 ExternalTabContainerWin::ExternalTabContainerWin(
    311     AutomationProvider* automation,
    312     AutomationResourceMessageFilter* filter)
    313     : widget_(NULL),
    314       automation_(automation),
    315       tab_contents_container_(NULL),
    316       tab_handle_(0),
    317       ignore_next_load_notification_(false),
    318       automation_resource_message_filter_(filter),
    319       load_requests_via_automation_(false),
    320       handle_top_level_requests_(false),
    321       route_all_top_level_navigations_(false),
    322       weak_factory_(this),
    323       pending_(false),
    324       focus_manager_(NULL),
    325       external_tab_view_(NULL),
    326       unload_reply_message_(NULL),
    327       is_popup_window_(false) {
    328 }
    329 
    330 // static
    331 scoped_refptr<ExternalTabContainer>
    332     ExternalTabContainerWin::RemovePendingExternalTab(uintptr_t cookie) {
    333   PendingTabs& pending_tabs = pending_tabs_.Get();
    334   PendingTabs::iterator index = pending_tabs.find(cookie);
    335   if (index != pending_tabs.end()) {
    336     scoped_refptr<ExternalTabContainer> container = (*index).second;
    337     pending_tabs.erase(index);
    338     return container;
    339   }
    340 
    341   NOTREACHED() << "Failed to find ExternalTabContainer for cookie: "
    342                << cookie;
    343   return NULL;
    344 }
    345 
    346 bool ExternalTabContainerWin::Init(Profile* profile,
    347                                    HWND parent,
    348                                    const gfx::Rect& bounds,
    349                                    DWORD style,
    350                                    bool load_requests_via_automation,
    351                                    bool handle_top_level_requests,
    352                                    content::WebContents* existing_contents,
    353                                    const GURL& initial_url,
    354                                    const GURL& referrer,
    355                                    bool infobars_enabled,
    356                                    bool route_all_top_level_navigations) {
    357   if (widget_) {
    358     NOTREACHED();
    359     return false;
    360   }
    361 
    362   widget_ = new views::Widget();
    363   widget_->AddObserver(this);
    364   load_requests_via_automation_ = load_requests_via_automation;
    365   handle_top_level_requests_ = handle_top_level_requests;
    366   route_all_top_level_navigations_ = route_all_top_level_navigations;
    367 
    368   views::Widget::InitParams params(views::Widget::InitParams::TYPE_POPUP);
    369   params.bounds = bounds;
    370 #if defined(USE_AURA)
    371   // Create the window that sits between the parent (most likely a
    372   // ChromeFrameAutomationClient) and the DesktopRootWindowHostWin.
    373   tab_container_window_ =
    374       (new ContainerWindow(HWND_DESKTOP, params.bounds))->AsWeakPtr();
    375 
    376   views::DesktopNativeWidgetAura* native_widget =
    377       new views::DesktopNativeWidgetAura(widget_);
    378   params.native_widget = native_widget;
    379   params.desktop_root_window_host =
    380       new ExternalTabRootWindowHost(widget_, native_widget);
    381   params.type = views::Widget::InitParams::TYPE_WINDOW_FRAMELESS;
    382   params.opacity = views::Widget::InitParams::OPAQUE_WINDOW;
    383 #endif
    384   widget_->Init(params);
    385 
    386 #if defined(USE_AURA)
    387   tab_container_window_->SetWidget(widget_);
    388 #endif
    389 
    390   // TODO(jcampan): limit focus traversal to contents.
    391 
    392   prop_.reset(new ui::ViewProp(views::HWNDForWidget(widget_), kWindowObjectKey,
    393                                this));
    394 
    395   if (existing_contents) {
    396     existing_contents->GetController().SetBrowserContext(profile);
    397   } else {
    398     existing_contents = WebContents::Create(WebContents::CreateParams(profile));
    399     existing_contents->GetRenderViewHost()->AllowBindings(
    400         content::BINDINGS_POLICY_EXTERNAL_HOST);
    401   }
    402 
    403   existing_contents->SetDelegate(this);
    404   existing_contents->GetMutableRendererPrefs()->
    405       browser_handles_non_local_top_level_requests = handle_top_level_requests;
    406 
    407   NavigationController* controller = &existing_contents->GetController();
    408   registrar_.Add(this, content::NOTIFICATION_NAV_ENTRY_COMMITTED,
    409                  content::Source<NavigationController>(controller));
    410   registrar_.Add(this, content::NOTIFICATION_LOAD_STOP,
    411                  content::Source<NavigationController>(controller));
    412   registrar_.Add(this,
    413                  content::NOTIFICATION_WEB_CONTENTS_RENDER_VIEW_HOST_CREATED,
    414                  content::Source<WebContents>(existing_contents));
    415   content::WebContentsObserver::Observe(existing_contents);
    416 
    417   BrowserTabContents::AttachTabHelpers(existing_contents);
    418   web_contents_.reset(existing_contents);
    419 
    420   if (!infobars_enabled) {
    421     InfoBarService::FromWebContents(existing_contents)->set_infobars_enabled(
    422         false);
    423   }
    424 
    425   // Start loading initial URL
    426   if (!initial_url.is_empty()) {
    427     // Navigate out of context since we don't have a 'tab_handle_' yet.
    428     base::MessageLoop::current()->PostTask(
    429         FROM_HERE,
    430         base::Bind(&ExternalTabContainerWin::Navigate,
    431                    weak_factory_.GetWeakPtr(),
    432                    initial_url,
    433                    referrer));
    434   }
    435 
    436   // We need WS_POPUP to be on the window during initialization, but
    437   // once initialized we apply the requested style which may or may not
    438   // include the popup bit.
    439   // Note that it's important to do this before we call SetParent since
    440   // during the SetParent call we will otherwise get a WA_ACTIVATE call
    441   // that causes us to steal the current focus.
    442   HWND window = GetExternalTabHWND();
    443   SetWindowLong(window, GWL_STYLE,
    444                 (GetWindowLong(window, GWL_STYLE) & ~WS_POPUP) | style);
    445 
    446   // Now apply the parenting and style
    447   if (parent)
    448     SetParent(window, parent);
    449 
    450   ShowNativeView(existing_contents->GetView()->GetNativeView());
    451 
    452   LoadAccelerators();
    453   SetupExternalTabView();
    454   return true;
    455 }
    456 
    457 void ExternalTabContainerWin::Uninitialize() {
    458   registrar_.RemoveAll();
    459   if (web_contents_.get()) {
    460     tab_contents_container_->SetWebContents(NULL);
    461     UnregisterRenderViewHost(web_contents_->GetRenderViewHost());
    462 
    463     // Explicitly tell the RPH to shutdown, as doing so is the only thing that
    464     // cleans up certain resources like infobars (crbug.com/148398).
    465     // Tell the RPH to shutdown iff it has a page count of 1, meaning that
    466     // there is only a single remaining render widget host (the one owned by
    467     // web_contents_) using this RPH.
    468     //
    469     // Note that it is not possible to simply call FastShutdownIfPossible on the
    470     // RPH here as that unfortunately ignores RPH's internal ref count, which
    471     // leaves any other render widget hosts using the same RPH dangling.
    472     //
    473     // Note that in an ideal world, this would not be needed. The WebContents
    474     // could just destroy itself, resulting in RPH::Release() eventually getting
    475     // called and all would be neat and tidy. Sadly, the RPH only fires
    476     // NOTIFICATION_RENDERER_PROCESS_CLOSED if one of the FastShutdownXXX
    477     // methods is called and other components rely on that notification to avoid
    478     // crashing on shutdown. Sad panda. Or maybe clinically depressed panda is
    479     // more fitting.
    480     web_contents_->GetRenderProcessHost()->FastShutdownForPageCount(1);
    481 
    482     if (widget_->GetRootView())
    483       widget_->GetRootView()->RemoveAllChildViews(true);
    484     widget_ = NULL;
    485 
    486     content::NotificationService::current()->Notify(
    487         chrome::NOTIFICATION_EXTERNAL_TAB_CLOSED,
    488         content::Source<NavigationController>(&web_contents_->GetController()),
    489         content::Details<ExternalTabContainer>(this));
    490 
    491     web_contents_.reset(NULL);
    492   }
    493 
    494   if (focus_manager_) {
    495     focus_manager_->UnregisterAccelerators(this);
    496     focus_manager_ = NULL;
    497   }
    498 
    499   external_tab_view_ = NULL;
    500   request_context_ = NULL;
    501   tab_contents_container_ = NULL;
    502 }
    503 
    504 bool ExternalTabContainerWin::Reinitialize(
    505     AutomationProvider* automation_provider,
    506     AutomationResourceMessageFilter* filter,
    507     HWND parent_window) {
    508   if (!automation_provider || !filter) {
    509     NOTREACHED();
    510     return false;
    511   }
    512 
    513   automation_ = automation_provider;
    514   automation_resource_message_filter_ = filter;
    515   // Wait for the automation channel to be initialized before resuming pending
    516   // render views and sending in the navigation state.
    517   base::MessageLoop::current()->PostTask(
    518       FROM_HERE,
    519       base::Bind(&ExternalTabContainerWin::OnReinitialize,
    520                  weak_factory_.GetWeakPtr()));
    521 
    522   if (parent_window)
    523     SetParent(GetExternalTabHWND(), parent_window);
    524   return true;
    525 }
    526 
    527 WebContents* ExternalTabContainerWin::GetWebContents() const {
    528   return web_contents_.get();
    529 }
    530 
    531 HWND ExternalTabContainerWin::GetExternalTabHWND() const {
    532 #if defined(USE_AURA)
    533   return tab_container_window_.get() ? tab_container_window_->hwnd() : NULL;
    534 #else
    535   return views::HWNDForWidget(widget_);
    536 #endif
    537 }
    538 
    539 HWND ExternalTabContainerWin::GetContentHWND() const {
    540   return views::HWNDForNativeWindow(web_contents_->GetView()->GetNativeView());
    541 }
    542 
    543 void ExternalTabContainerWin::SetTabHandle(int handle) {
    544   tab_handle_ = handle;
    545 }
    546 
    547 int ExternalTabContainerWin::GetTabHandle() const {
    548   return tab_handle_;
    549 }
    550 
    551 bool ExternalTabContainerWin::ExecuteContextMenuCommand(int command) {
    552   if (!external_context_menu_.get()) {
    553     NOTREACHED();
    554     return false;
    555   }
    556 
    557   switch (command) {
    558     case IDS_CONTENT_CONTEXT_SAVEAUDIOAS:
    559     case IDS_CONTENT_CONTEXT_SAVEVIDEOAS:
    560     case IDS_CONTENT_CONTEXT_SAVEIMAGEAS:
    561     case IDS_CONTENT_CONTEXT_SAVELINKAS: {
    562       NOTREACHED();  // Should be handled in host.
    563       break;
    564     }
    565   }
    566 
    567   external_context_menu_->ExecuteCommand(command, 0);
    568   return true;
    569 }
    570 
    571 void ExternalTabContainerWin::RunUnloadHandlers(IPC::Message* reply_message) {
    572 }
    573 
    574 void ExternalTabContainerWin::ProcessUnhandledAccelerator(const MSG& msg) {
    575   scoped_ptr<NativeWebKeyboardEvent> keyboard_event(CreateKeyboardEvent(msg));
    576   unhandled_keyboard_event_handler_.HandleKeyboardEvent(*keyboard_event,
    577                                                         focus_manager_);
    578 }
    579 
    580 void ExternalTabContainerWin::FocusThroughTabTraversal(
    581     bool reverse,
    582     bool restore_focus_to_view) {
    583   DCHECK(web_contents_.get());
    584 #if defined(USE_AURA)
    585   SetFocus(views::HWNDForWidget(widget_));
    586 #endif  // USE_AURA
    587   if (web_contents_.get())
    588     web_contents_->GetView()->Focus();
    589 
    590   // The web_contents_ member can get destroyed in the context of the call to
    591   // WebContentsViewViews::Focus() above. This method eventually calls SetFocus
    592   // on the native window, which could end up dispatching messages like
    593   // WM_DESTROY for the external tab.
    594   if (web_contents_.get() && restore_focus_to_view)
    595     web_contents_->FocusThroughTabTraversal(reverse);
    596 }
    597 
    598 ////////////////////////////////////////////////////////////////////////////////
    599 // ExternalTabContainer, content::WebContentsDelegate implementation:
    600 
    601 WebContents* ExternalTabContainerWin::OpenURLFromTab(
    602     WebContents* source,
    603     const OpenURLParams& params) {
    604   if (pending()) {
    605     pending_open_url_requests_.push_back(params);
    606     return NULL;
    607   }
    608 
    609   switch (params.disposition) {
    610     case CURRENT_TAB:
    611     case SINGLETON_TAB:
    612     case NEW_FOREGROUND_TAB:
    613     case NEW_BACKGROUND_TAB:
    614     case NEW_POPUP:
    615     case NEW_WINDOW:
    616     case SAVE_TO_DISK:
    617       if (automation_) {
    618         GURL referrer = GenerateReferrer(params.referrer.policy,
    619                                          params.url,
    620                                          params.referrer.url);
    621         automation_->Send(new AutomationMsg_OpenURL(tab_handle_,
    622                                                     params.url,
    623                                                     referrer,
    624                                                     params.disposition));
    625         // TODO(ananta)
    626         // We should populate other fields in the
    627         // ViewHostMsg_FrameNavigate_Params structure. Another option could be
    628         // to refactor the UpdateHistoryForNavigation function in WebContents.
    629         content::FrameNavigateParams nav_params;
    630         nav_params.referrer = content::Referrer(referrer,
    631                                                 params.referrer.policy);
    632         nav_params.url = params.url;
    633         nav_params.page_id = -1;
    634         nav_params.transition = content::PAGE_TRANSITION_LINK;
    635 
    636         HistoryTabHelper* history_tab_helper =
    637             HistoryTabHelper::FromWebContents(web_contents_.get());
    638         const history::HistoryAddPageArgs& add_page_args =
    639             history_tab_helper->CreateHistoryAddPageArgs(
    640                 params.url, base::Time::Now(),
    641                 false /* did_replace_entry */, nav_params);
    642         history_tab_helper->UpdateHistoryForNavigation(add_page_args);
    643 
    644         return web_contents_.get();
    645       }
    646       break;
    647     default:
    648       NOTREACHED();
    649       break;
    650   }
    651 
    652   return NULL;
    653 }
    654 
    655 void ExternalTabContainerWin::NavigationStateChanged(const WebContents* source,
    656                                                      unsigned changed_flags) {
    657   if (automation_) {
    658     NavigationInfo nav_info;
    659     if (InitNavigationInfo(&nav_info, content::NAVIGATION_TYPE_NAV_IGNORE, 0))
    660       automation_->Send(new AutomationMsg_NavigationStateChanged(
    661           tab_handle_, changed_flags, nav_info));
    662   }
    663 }
    664 
    665 void ExternalTabContainerWin::AddNewContents(WebContents* source,
    666                                              WebContents* new_contents,
    667                                              WindowOpenDisposition disposition,
    668                                              const gfx::Rect& initial_pos,
    669                                              bool user_gesture,
    670                                              bool* was_blocked) {
    671   if (!automation_) {
    672     DCHECK(pending_);
    673     LOG(ERROR) << "Invalid automation provider. Dropping new contents notify";
    674     delete new_contents;
    675     return;
    676   }
    677 
    678   scoped_refptr<ExternalTabContainerWin> new_container;
    679   // If the host is a browser like IE8, then the URL being navigated to in the
    680   // new tab contents could potentially navigate back to Chrome from a new
    681   // IE process. We support full tab mode only for IE and hence we use that as
    682   // a determining factor in whether the new ExternalTabContainer instance is
    683   // created as pending or not.
    684   if (!route_all_top_level_navigations_) {
    685     new_container = new ExternalTabContainerWin(NULL, NULL);
    686   } else {
    687     // Reuse the same tab handle here as the new container instance is a dummy
    688     // instance which does not have an automation client connected at the other
    689     // end.
    690     new_container = new TemporaryPopupExternalTabContainerWin(
    691         automation_, automation_resource_message_filter_.get());
    692     new_container->SetTabHandle(tab_handle_);
    693   }
    694 
    695   // Make sure that ExternalTabContainer instance is initialized with
    696   // an unwrapped Profile.
    697   Profile* profile =
    698       Profile::FromBrowserContext(new_contents->GetBrowserContext())->
    699           GetOriginalProfile();
    700   bool result = new_container->Init(profile,
    701                                     NULL,
    702                                     initial_pos,
    703                                     WS_CHILD,
    704                                     load_requests_via_automation_,
    705                                     handle_top_level_requests_,
    706                                     new_contents,
    707                                     GURL(),
    708                                     GURL(),
    709                                     true,
    710                                     route_all_top_level_navigations_);
    711 
    712   if (result) {
    713     if (route_all_top_level_navigations_) {
    714       return;
    715     }
    716     uintptr_t cookie = reinterpret_cast<uintptr_t>(new_container.get());
    717     pending_tabs_.Get()[cookie] = new_container;
    718     new_container->set_pending(true);
    719     new_container->set_is_popup_window(disposition == NEW_POPUP);
    720     AttachExternalTabParams attach_params_;
    721     attach_params_.cookie = static_cast<uint64>(cookie);
    722     attach_params_.dimensions = initial_pos;
    723     attach_params_.user_gesture = user_gesture;
    724     attach_params_.disposition = disposition;
    725     attach_params_.profile_name = base::WideToUTF8(
    726         profile->GetPath().DirName().BaseName().value());
    727     automation_->Send(new AutomationMsg_AttachExternalTab(
    728         tab_handle_, attach_params_));
    729   } else {
    730     NOTREACHED();
    731   }
    732 }
    733 
    734 void ExternalTabContainerWin::WebContentsCreated(
    735     WebContents* source_contents,
    736     int64 source_frame_id,
    737     const base::string16& frame_name,
    738     const GURL& target_url,
    739     WebContents* new_contents) {
    740   if (!load_requests_via_automation_)
    741     return;
    742 
    743   RenderViewHost* rvh = new_contents->GetRenderViewHost();
    744   DCHECK(rvh != NULL);
    745 
    746   // Register this render view as a pending render view, i.e. any network
    747   // requests initiated by this render view would be serviced when the
    748   // external host connects to the new external tab instance.
    749   RegisterRenderViewHostForAutomation(true, rvh);
    750 }
    751 
    752 void ExternalTabContainerWin::CloseContents(content::WebContents* source) {
    753   if (!automation_)
    754     return;
    755 
    756   if (unload_reply_message_) {
    757     AutomationMsg_RunUnloadHandlers::WriteReplyParams(unload_reply_message_,
    758                                                       true);
    759     automation_->Send(unload_reply_message_);
    760     unload_reply_message_ = NULL;
    761   } else {
    762     automation_->Send(new AutomationMsg_CloseExternalTab(tab_handle_));
    763   }
    764 }
    765 
    766 void ExternalTabContainerWin::MoveContents(WebContents* source,
    767                                            const gfx::Rect& pos) {
    768   if (automation_ && is_popup_window_)
    769     automation_->Send(new AutomationMsg_MoveWindow(tab_handle_, pos));
    770 }
    771 
    772 ExternalTabContainerWin::~ExternalTabContainerWin() {
    773   Uninitialize();
    774 }
    775 
    776 bool ExternalTabContainerWin::IsPopupOrPanel(const WebContents* source) const {
    777   return is_popup_window_;
    778 }
    779 
    780 void ExternalTabContainerWin::UpdateTargetURL(WebContents* source,
    781                                               int32 page_id,
    782                                               const GURL& url) {
    783   if (automation_) {
    784     base::string16 url_string = base::UTF8ToUTF16(url.spec());
    785     automation_->Send(
    786         new AutomationMsg_UpdateTargetUrl(tab_handle_, url_string));
    787   }
    788 }
    789 
    790 void ExternalTabContainerWin::ContentsZoomChange(bool zoom_in) {
    791 }
    792 
    793 bool ExternalTabContainerWin::TakeFocus(content::WebContents* source,
    794                                         bool reverse) {
    795   if (automation_) {
    796     automation_->Send(new AutomationMsg_TabbedOut(tab_handle_,
    797         base::win::IsShiftPressed()));
    798   }
    799 
    800   return true;
    801 }
    802 
    803 void ExternalTabContainerWin::WebContentsFocused(
    804     content::WebContents* contents) {
    805   DCHECK_EQ(tab_contents_container_->GetWebContents(), contents);
    806   tab_contents_container_->OnWebContentsFocused(contents);
    807 }
    808 
    809 void ExternalTabContainerWin::CanDownload(
    810     RenderViewHost* render_view_host,
    811     int request_id,
    812     const std::string& request_method,
    813     const base::Callback<void(bool)>& callback) {
    814   if (load_requests_via_automation_) {
    815     if (automation_) {
    816       // In case the host needs to show UI that needs to take the focus.
    817       ::AllowSetForegroundWindow(ASFW_ANY);
    818 
    819       BrowserThread::PostTask(
    820           BrowserThread::IO, FROM_HERE,
    821           base::Bind(
    822              base::IgnoreResult(
    823                  &AutomationResourceMessageFilter::SendDownloadRequestToHost),
    824              automation_resource_message_filter_.get(), 0, tab_handle_,
    825              request_id));
    826     }
    827   } else {
    828     DLOG(WARNING) << "Downloads are only supported with host browser network "
    829                      "stack enabled.";
    830   }
    831 
    832   // Never allow downloads.
    833   callback.Run(false);
    834 }
    835 
    836 void ExternalTabContainerWin::RegisterRenderViewHostForAutomation(
    837     bool pending_view,
    838     RenderViewHost* render_view_host) {
    839   if (!GetTabHandle()) {
    840     // This method is being called when it shouldn't be on the win_rel trybot;
    841     // see http://crbug.com/250965. Don't crash release builds in that case
    842     // until the root cause can be diagnosed and fixed. TODO(grt): fix this.
    843     DLOG(FATAL) << "tab_handle_ unset";
    844   } else if (render_view_host) {
    845     AutomationResourceMessageFilter::RegisterRenderView(
    846         render_view_host->GetProcess()->GetID(),
    847         render_view_host->GetRoutingID(),
    848         GetTabHandle(),
    849         automation_resource_message_filter_,
    850         pending_view);
    851   }
    852 }
    853 
    854 void ExternalTabContainerWin::RegisterRenderViewHost(
    855     RenderViewHost* render_view_host) {
    856   // RenderViewHost instances that are to be associated with this
    857   // ExternalTabContainer should share the same resource request automation
    858   // settings.
    859   RegisterRenderViewHostForAutomation(
    860       false,  // Network requests should not be handled later.
    861       render_view_host);
    862 }
    863 
    864 void ExternalTabContainerWin::UnregisterRenderViewHost(
    865     RenderViewHost* render_view_host) {
    866   // Undo the resource automation registration performed in
    867   // ExternalTabContainerWin::RegisterRenderViewHost.
    868   if (render_view_host) {
    869     AutomationResourceMessageFilter::UnRegisterRenderView(
    870       render_view_host->GetProcess()->GetID(),
    871       render_view_host->GetRoutingID());
    872   }
    873 }
    874 
    875 content::JavaScriptDialogManager*
    876 ExternalTabContainerWin::GetJavaScriptDialogManager() {
    877   return GetJavaScriptDialogManagerInstance();
    878 }
    879 
    880 bool ExternalTabContainerWin::HandleContextMenu(
    881     const content::ContextMenuParams& params) {
    882   if (!automation_) {
    883     NOTREACHED();
    884     return false;
    885   }
    886 
    887   if (params.custom_context.is_pepper_menu)
    888     return false;
    889 
    890   external_context_menu_.reset(RenderViewContextMenuViews::Create(
    891       web_contents(), params));
    892   static_cast<RenderViewContextMenuWin*>(
    893       external_context_menu_.get())->SetExternal();
    894   external_context_menu_->Init();
    895 
    896   scoped_ptr<ContextMenuModel> context_menu_model(
    897     ConvertMenuModel(&external_context_menu_->menu_model()));
    898 
    899   POINT screen_pt = { params.x, params.y };
    900   MapWindowPoints(views::HWNDForWidget(widget_), HWND_DESKTOP, &screen_pt, 1);
    901 
    902   MiniContextMenuParams ipc_params;
    903   ipc_params.screen_x = screen_pt.x;
    904   ipc_params.screen_y = screen_pt.y;
    905   ipc_params.link_url = params.link_url;
    906   ipc_params.unfiltered_link_url = params.unfiltered_link_url;
    907   ipc_params.src_url = params.src_url;
    908   ipc_params.page_url = params.page_url;
    909   ipc_params.keyword_url = params.keyword_url;
    910   ipc_params.frame_url = params.frame_url;
    911 
    912   bool rtl = base::i18n::IsRTL();
    913   automation_->Send(
    914       new AutomationMsg_ForwardContextMenuToExternalHost(tab_handle_,
    915           *context_menu_model,
    916           rtl ? TPM_RIGHTALIGN : TPM_LEFTALIGN, ipc_params));
    917 
    918   return true;
    919 }
    920 
    921 bool ExternalTabContainerWin::PreHandleKeyboardEvent(
    922     content::WebContents* source,
    923     const NativeWebKeyboardEvent& event,
    924     bool* is_keyboard_shortcut) {
    925   return false;
    926 }
    927 
    928 void ExternalTabContainerWin::HandleKeyboardEvent(
    929     content::WebContents* source,
    930     const NativeWebKeyboardEvent& event) {
    931 
    932 #if defined(USE_AURA)
    933   // Character events created and inserted by the IME code on Aura will not
    934   // contain a native os_event, so don't attempt to pluck one out. These events
    935   // also do not correspond to accelerator key presses so do not need to be
    936   // forwarded to the host.
    937   if (!event.os_event)
    938     return;
    939 #endif
    940 
    941   const MSG& message = MessageFromKeyboardEvent(event);
    942   ProcessUnhandledKeyStroke(message.hwnd, message.message,
    943                             message.wParam, message.lParam);
    944 }
    945 
    946 void ExternalTabContainerWin::BeforeUnloadFired(WebContents* tab,
    947                                                 bool proceed,
    948                                                 bool* proceed_to_fire_unload) {
    949   *proceed_to_fire_unload = true;
    950 
    951   if (!automation_) {
    952     delete unload_reply_message_;
    953     unload_reply_message_ = NULL;
    954     return;
    955   }
    956 
    957   if (!unload_reply_message_) {
    958     NOTREACHED() << "**** NULL unload reply message pointer.";
    959     return;
    960   }
    961 
    962   if (!proceed) {
    963     AutomationMsg_RunUnloadHandlers::WriteReplyParams(unload_reply_message_,
    964                                                       false);
    965     automation_->Send(unload_reply_message_);
    966     unload_reply_message_ = NULL;
    967     *proceed_to_fire_unload = false;
    968   }
    969 }
    970 
    971 void ExternalTabContainerWin::ShowRepostFormWarningDialog(WebContents* source) {
    972   TabModalConfirmDialog::Create(new RepostFormWarningController(source),
    973                                 source);
    974 }
    975 
    976 content::ColorChooser* ExternalTabContainerWin::OpenColorChooser(
    977       WebContents* web_contents,
    978       SkColor initial_color,
    979       const std::vector<content::ColorSuggestion>& suggestions) {
    980   return chrome::ShowColorChooser(web_contents, initial_color);
    981 }
    982 
    983 void ExternalTabContainerWin::RunFileChooser(
    984     WebContents* tab,
    985     const content::FileChooserParams& params) {
    986   FileSelectHelper::RunFileChooser(tab, params);
    987 }
    988 
    989 void ExternalTabContainerWin::EnumerateDirectory(WebContents* tab,
    990                                                  int request_id,
    991                                                  const base::FilePath& path) {
    992   FileSelectHelper::EnumerateDirectory(tab, request_id, path);
    993 }
    994 
    995 void ExternalTabContainerWin::RequestMediaAccessPermission(
    996     content::WebContents* web_contents,
    997     const content::MediaStreamRequest& request,
    998     const content::MediaResponseCallback& callback) {
    999   MediaStreamInfoBarDelegate::Create(web_contents, request, callback);
   1000 }
   1001 
   1002 bool ExternalTabContainerWin::RequestPpapiBrokerPermission(
   1003     WebContents* web_contents,
   1004     const GURL& url,
   1005     const base::FilePath& plugin_path,
   1006     const base::Callback<void(bool)>& callback) {
   1007   PepperBrokerInfoBarDelegate::Create(web_contents, url, plugin_path, callback);
   1008   return true;
   1009 }
   1010 
   1011 void ExternalTabContainerWin::RenderViewDeleted(
   1012     content::RenderViewHost* render_view_host) {
   1013   if (load_requests_via_automation_)
   1014     UnregisterRenderViewHost(render_view_host);
   1015 }
   1016 
   1017 bool ExternalTabContainerWin::OnMessageReceived(const IPC::Message& message) {
   1018   bool handled = true;
   1019   IPC_BEGIN_MESSAGE_MAP(ExternalTabContainerWin, message)
   1020     IPC_MESSAGE_HANDLER(ChromeViewHostMsg_ForwardMessageToExternalHost,
   1021                         OnForwardMessageToExternalHost)
   1022     IPC_MESSAGE_UNHANDLED(handled = false)
   1023   IPC_END_MESSAGE_MAP()
   1024   return handled;
   1025 }
   1026 
   1027 void ExternalTabContainerWin::DidFailProvisionalLoad(
   1028     int64 frame_id,
   1029     const base::string16& frame_unique_name,
   1030     bool is_main_frame,
   1031     const GURL& validated_url,
   1032     int error_code,
   1033     const base::string16& error_description,
   1034     content::RenderViewHost* render_view_host) {
   1035   if (automation_) {
   1036     automation_->Send(new AutomationMsg_NavigationFailed(
   1037         tab_handle_, error_code, validated_url));
   1038   }
   1039   ignore_next_load_notification_ = true;
   1040 }
   1041 
   1042 void ExternalTabContainerWin::OnForwardMessageToExternalHost(
   1043     const std::string& message,
   1044     const std::string& origin,
   1045     const std::string& target) {
   1046   if (automation_) {
   1047     automation_->Send(new AutomationMsg_ForwardMessageToExternalHost(
   1048         tab_handle_, message, origin, target));
   1049   }
   1050 }
   1051 
   1052 ////////////////////////////////////////////////////////////////////////////////
   1053 // ExternalTabContainer, NotificationObserver implementation:
   1054 
   1055 void ExternalTabContainerWin::Observe(
   1056     int type,
   1057     const content::NotificationSource& source,
   1058     const content::NotificationDetails& details) {
   1059   if (!automation_)
   1060     return;
   1061 
   1062   static const int kHttpClientErrorStart = 400;
   1063   static const int kHttpServerErrorEnd = 510;
   1064 
   1065   switch (type) {
   1066     case content::NOTIFICATION_LOAD_STOP: {
   1067         const LoadNotificationDetails* load =
   1068             content::Details<LoadNotificationDetails>(details).ptr();
   1069         if (load && content::PageTransitionIsMainFrame(load->origin)) {
   1070           TRACE_EVENT_END_ETW("ExternalTabContainerWin::Navigate", 0,
   1071                               load->url.spec());
   1072           automation_->Send(new AutomationMsg_TabLoaded(tab_handle_,
   1073                                                         load->url));
   1074         }
   1075         break;
   1076       }
   1077     case content::NOTIFICATION_NAV_ENTRY_COMMITTED: {
   1078       if (ignore_next_load_notification_) {
   1079         ignore_next_load_notification_ = false;
   1080         return;
   1081       }
   1082 
   1083       const content::LoadCommittedDetails* commit =
   1084           content::Details<content::LoadCommittedDetails>(details).ptr();
   1085 
   1086       if (commit->http_status_code >= kHttpClientErrorStart &&
   1087           commit->http_status_code <= kHttpServerErrorEnd) {
   1088         automation_->Send(new AutomationMsg_NavigationFailed(
   1089             tab_handle_, commit->http_status_code, commit->entry->GetURL()));
   1090 
   1091         ignore_next_load_notification_ = true;
   1092       } else {
   1093         NavigationInfo navigation_info;
   1094         // When the previous entry index is invalid, it will be -1, which
   1095         // will still make the computation come out right (navigating to the
   1096         // 0th entry will be +1).
   1097         if (InitNavigationInfo(&navigation_info, commit->type,
   1098                 commit->previous_entry_index -
   1099                 web_contents_->GetController().GetLastCommittedEntryIndex()))
   1100           automation_->Send(new AutomationMsg_DidNavigate(tab_handle_,
   1101                                                           navigation_info));
   1102       }
   1103       break;
   1104     }
   1105     case content::NOTIFICATION_WEB_CONTENTS_RENDER_VIEW_HOST_CREATED: {
   1106       if (load_requests_via_automation_) {
   1107         RenderViewHost* rvh = content::Details<RenderViewHost>(details).ptr();
   1108         RegisterRenderViewHostForAutomation(false, rvh);
   1109       }
   1110       break;
   1111     }
   1112     default:
   1113       NOTREACHED();
   1114   }
   1115 }
   1116 
   1117 ////////////////////////////////////////////////////////////////////////////////
   1118 // WidgetObserver overrides:
   1119 
   1120 void ExternalTabContainerWin::OnWidgetCreated(views::Widget* widget) {
   1121   DCHECK_EQ(widget_, widget);
   1122   // Grab a reference here which will be released in OnWidgetDestroyed.
   1123   AddRef();
   1124 }
   1125 
   1126 void ExternalTabContainerWin::OnWidgetDestroying(views::Widget* widget) {
   1127   DCHECK_EQ(widget_, widget);
   1128   Uninitialize();
   1129   prop_.reset();
   1130 }
   1131 
   1132 void ExternalTabContainerWin::OnWidgetDestroyed(views::Widget* widget) {
   1133   DCHECK_EQ(widget_, static_cast<views::Widget*>(NULL));
   1134   // Release the reference which we grabbed in OnWidgetCreated.
   1135   Release();
   1136 }
   1137 
   1138 ////////////////////////////////////////////////////////////////////////////////
   1139 // ExternalTabContainer, private:
   1140 bool ExternalTabContainerWin::ProcessUnhandledKeyStroke(HWND window,
   1141                                                         UINT message,
   1142                                                         WPARAM wparam,
   1143                                                         LPARAM lparam) {
   1144   if (!automation_) {
   1145     return false;
   1146   }
   1147   if ((wparam == VK_TAB) && !base::win::IsCtrlPressed()) {
   1148     // Tabs are handled separately (except if this is Ctrl-Tab or
   1149     // Ctrl-Shift-Tab)
   1150     return false;
   1151   }
   1152 
   1153   // Send this keystroke to the external host as it could be processed as an
   1154   // accelerator there. If the host does not handle this accelerator, it will
   1155   // reflect the accelerator back to us via the ProcessUnhandledAccelerator
   1156   // method.
   1157   MSG msg = {0};
   1158   msg.hwnd = window;
   1159   msg.message = message;
   1160   msg.wParam = wparam;
   1161   msg.lParam = lparam;
   1162   automation_->Send(new AutomationMsg_HandleAccelerator(tab_handle_, msg));
   1163   return true;
   1164 }
   1165 
   1166 bool ExternalTabContainerWin::InitNavigationInfo(
   1167     NavigationInfo* nav_info,
   1168     content::NavigationType nav_type,
   1169     int relative_offset) {
   1170   DCHECK(nav_info);
   1171   NavigationEntry* entry = web_contents_->GetController().GetActiveEntry();
   1172   // If this is very early in the game then there may not be an entry.
   1173   if (!entry)
   1174     return false;
   1175 
   1176   nav_info->navigation_type = nav_type;
   1177   nav_info->relative_offset = relative_offset;
   1178   nav_info->navigation_index =
   1179       web_contents_->GetController().GetCurrentEntryIndex();
   1180   nav_info->url = entry->GetURL();
   1181   nav_info->referrer = entry->GetReferrer().url;
   1182   nav_info->title = entry->GetTitle();
   1183   if (nav_info->title.empty())
   1184     nav_info->title = base::UTF8ToWide(nav_info->url.spec());
   1185 
   1186   nav_info->security_style = entry->GetSSL().security_style;
   1187   int content_status = entry->GetSSL().content_status;
   1188   nav_info->displayed_insecure_content =
   1189       !!(content_status & SSLStatus::DISPLAYED_INSECURE_CONTENT);
   1190   nav_info->ran_insecure_content =
   1191       !!(content_status & SSLStatus::RAN_INSECURE_CONTENT);
   1192   return true;
   1193 }
   1194 
   1195 SkColor ExternalTabContainerWin::GetInfoBarSeparatorColor() const {
   1196   return ThemeProperties::GetDefaultColor(
   1197       ThemeProperties::COLOR_TOOLBAR_SEPARATOR);
   1198 }
   1199 
   1200 void ExternalTabContainerWin::InfoBarContainerStateChanged(bool is_animating) {
   1201   if (external_tab_view_)
   1202     external_tab_view_->Layout();
   1203 }
   1204 
   1205 bool ExternalTabContainerWin::DrawInfoBarArrows(int* x) const {
   1206   return false;
   1207 }
   1208 
   1209 bool ExternalTabContainerWin::AcceleratorPressed(
   1210     const ui::Accelerator& accelerator) {
   1211   std::map<ui::Accelerator, int>::const_iterator iter =
   1212       accelerator_table_.find(accelerator);
   1213   DCHECK(iter != accelerator_table_.end());
   1214 
   1215   if (!web_contents_.get() || !web_contents_->GetRenderViewHost()) {
   1216     NOTREACHED();
   1217     return false;
   1218   }
   1219 
   1220   RenderViewHost* host = web_contents_->GetRenderViewHost();
   1221   int command_id = iter->second;
   1222   switch (command_id) {
   1223     case IDC_ZOOM_PLUS:
   1224       host->Zoom(content::PAGE_ZOOM_IN);
   1225       break;
   1226     case IDC_ZOOM_NORMAL:
   1227       host->Zoom(content::PAGE_ZOOM_RESET);
   1228       break;
   1229     case IDC_ZOOM_MINUS:
   1230       host->Zoom(content::PAGE_ZOOM_OUT);
   1231       break;
   1232     case IDC_DEV_TOOLS:
   1233       DevToolsWindow::ToggleDevToolsWindow(web_contents_->GetRenderViewHost(),
   1234                                            false,
   1235                                            DevToolsToggleAction::Show());
   1236       break;
   1237     case IDC_DEV_TOOLS_CONSOLE:
   1238       DevToolsWindow::ToggleDevToolsWindow(web_contents_->GetRenderViewHost(),
   1239                                            false,
   1240                                            DevToolsToggleAction::ShowConsole());
   1241       break;
   1242     case IDC_DEV_TOOLS_INSPECT:
   1243       DevToolsWindow::ToggleDevToolsWindow(web_contents_->GetRenderViewHost(),
   1244                                            false,
   1245                                            DevToolsToggleAction::Inspect());
   1246       break;
   1247     case IDC_DEV_TOOLS_TOGGLE:
   1248       DevToolsWindow::ToggleDevToolsWindow(web_contents_->GetRenderViewHost(),
   1249                                            false,
   1250                                            DevToolsToggleAction::Toggle());
   1251       break;
   1252     default:
   1253       NOTREACHED() << "Unsupported accelerator: " << command_id;
   1254       return false;
   1255   }
   1256   return true;
   1257 }
   1258 
   1259 bool ExternalTabContainerWin::CanHandleAccelerators() const {
   1260   return true;
   1261 }
   1262 
   1263 void ExternalTabContainerWin::Navigate(const GURL& url, const GURL& referrer) {
   1264   if (!web_contents_.get()) {
   1265     NOTREACHED();
   1266     return;
   1267   }
   1268 
   1269   TRACE_EVENT_BEGIN_ETW("ExternalTabContainerWin::Navigate", 0, url.spec());
   1270 
   1271   web_contents_->GetController().LoadURL(
   1272       url, content::Referrer(referrer, blink::WebReferrerPolicyDefault),
   1273       content::PAGE_TRANSITION_AUTO_TOPLEVEL, std::string());
   1274 }
   1275 
   1276 bool ExternalTabContainerWin::OnGoToEntryOffset(int offset) {
   1277   if (load_requests_via_automation_) {
   1278     if (automation_) {
   1279       automation_->Send(new AutomationMsg_RequestGoToHistoryEntryOffset(
   1280           tab_handle_, offset));
   1281     }
   1282     return false;
   1283   }
   1284 
   1285   return true;
   1286 }
   1287 
   1288 void ExternalTabContainerWin::LoadAccelerators() {
   1289   HACCEL accelerator_table = AtlLoadAccelerators(IDR_CHROMEFRAME);
   1290   DCHECK(accelerator_table);
   1291 
   1292   // We have to copy the table to access its contents.
   1293   int count = CopyAcceleratorTable(accelerator_table, 0, 0);
   1294   if (count == 0) {
   1295     // Nothing to do in that case.
   1296     return;
   1297   }
   1298 
   1299   scoped_ptr<ACCEL[]> scoped_accelerators(new ACCEL[count]);
   1300   ACCEL* accelerators = scoped_accelerators.get();
   1301   DCHECK(accelerators != NULL);
   1302 
   1303   CopyAcceleratorTable(accelerator_table, accelerators, count);
   1304 
   1305   focus_manager_ = widget_->GetFocusManager();
   1306   DCHECK(focus_manager_);
   1307 
   1308   // Let's fill our own accelerator table.
   1309   for (int i = 0; i < count; ++i) {
   1310     ui::Accelerator accelerator(
   1311         static_cast<ui::KeyboardCode>(accelerators[i].key),
   1312         ui::GetModifiersFromACCEL(accelerators[i]));
   1313     accelerator_table_[accelerator] = accelerators[i].cmd;
   1314 
   1315     // Also register with the focus manager.
   1316     if (focus_manager_) {
   1317       focus_manager_->RegisterAccelerator(
   1318           accelerator, ui::AcceleratorManager::kNormalPriority, this);
   1319     }
   1320   }
   1321 }
   1322 
   1323 void ExternalTabContainerWin::OnReinitialize() {
   1324   if (load_requests_via_automation_) {
   1325     RenderViewHost* rvh = web_contents_->GetRenderViewHost();
   1326     if (rvh) {
   1327       AutomationResourceMessageFilter::ResumePendingRenderView(
   1328           rvh->GetProcess()->GetID(), rvh->GetRoutingID(),
   1329           tab_handle_, automation_resource_message_filter_);
   1330     }
   1331   }
   1332 
   1333   NavigationStateChanged(web_contents(), 0);
   1334   ServicePendingOpenURLRequests();
   1335 }
   1336 
   1337 void ExternalTabContainerWin::ServicePendingOpenURLRequests() {
   1338   DCHECK(pending());
   1339 
   1340   set_pending(false);
   1341 
   1342   for (size_t index = 0; index < pending_open_url_requests_.size();
   1343        ++index) {
   1344     const OpenURLParams& url_request = pending_open_url_requests_[index];
   1345     OpenURLFromTab(web_contents(), url_request);
   1346   }
   1347   pending_open_url_requests_.clear();
   1348 }
   1349 
   1350 void ExternalTabContainerWin::SetupExternalTabView() {
   1351   // Create a TabContentsContainer to handle focus cycling using Tab and
   1352   // Shift-Tab.
   1353   Profile* profile =
   1354       Profile::FromBrowserContext(web_contents_->GetBrowserContext());
   1355   tab_contents_container_ = new views::WebView(profile);
   1356 
   1357   // The views created here will be destroyed when the ExternalTabContainer
   1358   // widget is torn down.
   1359   external_tab_view_ = new views::View();
   1360 
   1361   InfoBarContainerView* infobar_container = new InfoBarContainerView(this);
   1362   infobar_container->ChangeInfoBarService(
   1363       InfoBarService::FromWebContents(web_contents_.get()));
   1364 
   1365   views::GridLayout* layout = new views::GridLayout(external_tab_view_);
   1366   // Give this column an identifier of 0.
   1367   views::ColumnSet* columns = layout->AddColumnSet(0);
   1368   columns->AddColumn(views::GridLayout::FILL,
   1369                      views::GridLayout::FILL,
   1370                      1,
   1371                      views::GridLayout::USE_PREF,
   1372                      0,
   1373                      0);
   1374 
   1375   external_tab_view_->SetLayoutManager(layout);
   1376 
   1377   layout->StartRow(0, 0);
   1378   layout->AddView(infobar_container);
   1379   layout->StartRow(1, 0);
   1380   layout->AddView(tab_contents_container_);
   1381   widget_->SetContentsView(external_tab_view_);
   1382   // Note that SetWebContents must be called after AddChildView is called
   1383   tab_contents_container_->SetWebContents(web_contents());
   1384 }
   1385 
   1386 // static
   1387 ExternalTabContainer* ExternalTabContainer::Create(
   1388     AutomationProvider* automation_provider,
   1389     AutomationResourceMessageFilter* filter) {
   1390   return new ExternalTabContainerWin(automation_provider, filter);
   1391 }
   1392 
   1393 // static
   1394 ExternalTabContainer* ExternalTabContainer::GetContainerForTab(
   1395     content::WebContents* web_contents) {
   1396   HWND window = views::HWNDForNativeWindow(
   1397       web_contents->GetView()->GetNativeView());
   1398 #if !defined(USE_AURA)
   1399   // In the non-Aura case, it is the parent of the WebContents's view that has
   1400   // the property set.
   1401   window = ::GetParent(window);
   1402   if (!::IsWindow(window))
   1403     return NULL;
   1404 #endif
   1405   return reinterpret_cast<ExternalTabContainerWin*>(
   1406       ui::ViewProp::GetValue(window, kWindowObjectKey));
   1407 }
   1408 
   1409 // static
   1410 scoped_refptr<ExternalTabContainer> ExternalTabContainer::RemovePendingTab(
   1411     uintptr_t cookie) {
   1412   return ExternalTabContainerWin::RemovePendingExternalTab(cookie);
   1413 }
   1414 
   1415 ///////////////////////////////////////////////////////////////////////////////
   1416 // TemporaryPopupExternalTabContainerWin
   1417 
   1418 TemporaryPopupExternalTabContainerWin::TemporaryPopupExternalTabContainerWin(
   1419     AutomationProvider* automation,
   1420     AutomationResourceMessageFilter* filter)
   1421     : ExternalTabContainerWin(automation, filter) {
   1422 }
   1423 
   1424 TemporaryPopupExternalTabContainerWin::~TemporaryPopupExternalTabContainerWin(
   1425     ) {
   1426   DVLOG(1) << __FUNCTION__;
   1427 }
   1428 
   1429 WebContents* TemporaryPopupExternalTabContainerWin::OpenURLFromTab(
   1430     WebContents* source,
   1431     const OpenURLParams& params) {
   1432   if (!automation_)
   1433     return NULL;
   1434 
   1435   OpenURLParams forward_params = params;
   1436   if (params.disposition == CURRENT_TAB) {
   1437     DCHECK(route_all_top_level_navigations_);
   1438     forward_params.disposition = NEW_FOREGROUND_TAB;
   1439   }
   1440   WebContents* new_contents =
   1441       ExternalTabContainerWin::OpenURLFromTab(source, forward_params);
   1442   // support only one navigation for a dummy tab before it is killed.
   1443   widget_->CloseNow();
   1444   return new_contents;
   1445 }
   1446