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