Add a minor text member to ui::MenuModel.
[chromium-blink-merge.git] / chrome / browser / ui / views / external_tab_container_win.cc
blob806f3b0755c87ad9599d8262534bdc163ca3e953
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.
5 #include "chrome/browser/ui/views/external_tab_container_win.h"
7 #include <atlbase.h>
8 #include <atlapp.h>
9 #include <atlconv.h>
10 #include <atlcrack.h>
11 #include <atlmisc.h>
12 #include <string>
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"
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
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;
96 namespace {
98 static const char kWindowObjectKey[] = "ChromeWindowObject";
100 // The following helper functions exist to localize UI toolkit-specific code.
102 void ShowNativeView(gfx::NativeView view) {
103 #if !defined(USE_AURA)
104 ::ShowWindow(view, SW_SHOWNA);
105 #endif
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
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
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;
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));
148 new_model->items.push_back(item);
152 return new_model;
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");
162 if (!referrer_is_web_url)
163 return true;
165 if (!referrer_is_secure)
166 return false;
168 return !url.SchemeIsSecure();
171 GURL GenerateReferrer(WebKit::WebReferrerPolicy policy,
172 const GURL& url,
173 const GURL& referrer) {
174 if (referrer.is_empty())
175 return GURL();
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;
188 return ShouldHideReferrer(url, referrer) ? GURL() : referrer;
192 } // namespace
194 #if defined(USE_AURA)
195 typedef ATL::CWinTraits<WS_POPUP | WS_CLIPSIBLINGS | WS_CLIPCHILDREN,
196 WS_EX_NOACTIVATE | WS_EX_TOOLWINDOW>
197 ContainerWindowHWNDTraits;
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);
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()
218 ContainerWindow(HWND parent, const gfx::Rect& bounds) : child_(NULL) {
219 RECT rect = bounds.ToRECT();
220 Create(parent, rect);
223 HWND hwnd() {
224 DCHECK(::IsWindow(m_hWnd));
225 return m_hWnd;
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;
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));
239 ::SetParent(window, hwnd());
242 protected:
243 virtual void OnFinalMessage(HWND hwnd) OVERRIDE {
244 delete this;
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);
253 void OnShowWindow(BOOL show, UINT status) {
254 ::ShowWindow(child_, SW_SHOWNA);
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);
262 HWND child_;
264 DISALLOW_COPY_AND_ASSIGN(ContainerWindow);
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) {}
281 protected:
282 // HWNDMessageHandlerDelegate methods:
283 virtual void HandleNativeFocus(HWND last_focused_window) OVERRIDE {
284 views::DesktopRootWindowHostWin::HandleNativeFocus(last_focused_window);
285 RestoreFocusOnActivate();
288 virtual void HandleNativeBlur(HWND focused_window) OVERRIDE {
289 SaveFocusOnDeactivate();
290 views::DesktopRootWindowHostWin::HandleNativeBlur(focused_window);
293 private:
294 DISALLOW_COPY_AND_ASSIGN(ExternalTabRootWindowHost);
296 #endif
298 base::LazyInstance<ExternalTabContainerWin::PendingTabs>
299 ExternalTabContainerWin::pending_tabs_ = LAZY_INSTANCE_INITIALIZER;
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) {
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;
335 NOTREACHED() << "Failed to find ExternalTabContainer for cookie: "
336 << cookie;
337 return NULL;
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;
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;
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();
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);
380 #if defined(USE_AURA)
381 tab_container_window_->SetChild(views::HWNDForWidget(widget_));
382 #endif
384 // TODO(jcampan): limit focus traversal to contents.
386 prop_.reset(new ui::ViewProp(views::HWNDForWidget(widget_), kWindowObjectKey,
387 this));
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);
397 existing_contents->SetDelegate(this);
398 existing_contents->GetMutableRendererPrefs()->
399 browser_handles_non_local_top_level_requests = handle_top_level_requests;
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));
410 content::RenderViewHost::AddCreatedCallback(rvh_callback_);
411 content::WebContentsObserver::Observe(existing_contents);
413 BrowserTabContents::AttachTabHelpers(existing_contents);
414 web_contents_.reset(existing_contents);
416 if (!infobars_enabled) {
417 InfoBarService::FromWebContents(existing_contents)->set_infobars_enabled(
418 false);
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));
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);
442 // Now apply the parenting and style
443 if (parent)
444 SetParent(window, parent);
446 ShowNativeView(existing_contents->GetView()->GetNativeView());
448 LoadAccelerators();
449 SetupExternalTabView();
450 BlockedContentTabHelper::FromWebContents(existing_contents)->
451 set_delegate(this);
452 return true;
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());
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.
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.
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);
481 if (widget_->GetRootView())
482 widget_->GetRootView()->RemoveAllChildViews(true);
483 widget_ = NULL;
485 content::NotificationService::current()->Notify(
486 chrome::NOTIFICATION_EXTERNAL_TAB_CLOSED,
487 content::Source<NavigationController>(&web_contents_->GetController()),
488 content::Details<ExternalTabContainer>(this));
490 web_contents_.reset(NULL);
493 if (focus_manager_) {
494 focus_manager_->UnregisterAccelerators(this);
495 focus_manager_ = NULL;
498 external_tab_view_ = NULL;
499 request_context_ = NULL;
500 tab_contents_container_ = NULL;
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;
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()));
521 if (parent_window)
522 SetParent(GetExternalTabHWND(), parent_window);
523 return true;
526 WebContents* ExternalTabContainerWin::GetWebContents() const {
527 return web_contents_.get();
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
538 HWND ExternalTabContainerWin::GetContentHWND() const {
539 return views::HWNDForNativeWindow(web_contents_->GetView()->GetNativeView());
542 void ExternalTabContainerWin::SetTabHandle(int handle) {
543 tab_handle_ = handle;
546 int ExternalTabContainerWin::GetTabHandle() const {
547 return tab_handle_;
550 bool ExternalTabContainerWin::ExecuteContextMenuCommand(int command) {
551 if (!external_context_menu_.get()) {
552 NOTREACHED();
553 return false;
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;
566 external_context_menu_->ExecuteCommand(command, 0);
567 return true;
570 void ExternalTabContainerWin::RunUnloadHandlers(IPC::Message* reply_message) {
571 if (!automation_) {
572 delete reply_message;
573 return;
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;
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;
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_);
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();
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);
619 ////////////////////////////////////////////////////////////////////////////////
620 // ExternalTabContainer, content::WebContentsDelegate implementation:
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;
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;
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);
665 return web_contents_.get();
667 break;
668 default:
669 NOTREACHED();
670 break;
673 return NULL;
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));
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;
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_);
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_);
733 if (result) {
734 if (route_all_top_level_navigations_) {
735 return;
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();
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;
763 RenderViewHost* rvh = new_contents->GetRenderViewHost();
764 DCHECK(rvh != NULL);
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);
772 void ExternalTabContainerWin::CloseContents(content::WebContents* source) {
773 if (!automation_)
774 return;
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_));
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));
792 content::WebContents* ExternalTabContainerWin::GetConstrainingWebContents(
793 content::WebContents* source) {
794 return source;
797 ExternalTabContainerWin::~ExternalTabContainerWin() {
798 Uninitialize();
801 bool ExternalTabContainerWin::IsPopupOrPanel(const WebContents* source) const {
802 return is_popup_window_;
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));
815 void ExternalTabContainerWin::ContentsZoomChange(bool zoom_in) {
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()));
825 return true;
828 void ExternalTabContainerWin::WebContentsFocused(
829 content::WebContents* contents) {
830 DCHECK_EQ(tab_contents_container_->GetWebContents(), contents);
831 tab_contents_container_->OnWebContentsFocused(contents);
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);
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));
852 } else {
853 DLOG(WARNING) << "Downloads are only supported with host browser network "
854 "stack enabled.";
857 // Never allow downloads.
858 callback.Run(false);
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);
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);
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());
900 content::JavaScriptDialogManager*
901 ExternalTabContainerWin::GetJavaScriptDialogManager() {
902 return GetJavaScriptDialogManagerInstance();
905 bool ExternalTabContainerWin::HandleContextMenu(
906 const content::ContextMenuParams& params) {
907 if (!automation_) {
908 NOTREACHED();
909 return false;
912 if (params.custom_context.is_pepper_menu)
913 return false;
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();
921 scoped_ptr<ContextMenuModel> context_menu_model(
922 ConvertMenuModel(&external_context_menu_->menu_model()));
924 POINT screen_pt = { params.x, params.y };
925 MapWindowPoints(views::HWNDForWidget(widget_), HWND_DESKTOP, &screen_pt, 1);
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;
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));
943 return true;
946 bool ExternalTabContainerWin::PreHandleKeyboardEvent(
947 content::WebContents* source,
948 const NativeWebKeyboardEvent& event,
949 bool* is_keyboard_shortcut) {
950 return false;
953 void ExternalTabContainerWin::HandleKeyboardEvent(
954 content::WebContents* source,
955 const NativeWebKeyboardEvent& event) {
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
966 const MSG& message = MessageFromKeyboardEvent(event);
967 ProcessUnhandledKeyStroke(message.hwnd, message.message,
968 message.wParam, message.lParam);
971 void ExternalTabContainerWin::BeforeUnloadFired(WebContents* tab,
972 bool proceed,
973 bool* proceed_to_fire_unload) {
974 *proceed_to_fire_unload = true;
976 if (!automation_) {
977 delete unload_reply_message_;
978 unload_reply_message_ = NULL;
979 return;
982 if (!unload_reply_message_) {
983 NOTREACHED() << "**** NULL unload reply message pointer.";
984 return;
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;
996 void ExternalTabContainerWin::ShowRepostFormWarningDialog(WebContents* source) {
997 TabModalConfirmDialog::Create(new RepostFormWarningController(source),
998 source);
1001 content::ColorChooser* ExternalTabContainerWin::OpenColorChooser(
1002 WebContents* web_contents, SkColor initial_color) {
1003 return chrome::ShowColorChooser(web_contents, initial_color);
1006 void ExternalTabContainerWin::RunFileChooser(
1007 WebContents* tab,
1008 const content::FileChooserParams& params) {
1009 FileSelectHelper::RunFileChooser(tab, params);
1012 void ExternalTabContainerWin::EnumerateDirectory(WebContents* tab,
1013 int request_id,
1014 const base::FilePath& path) {
1015 FileSelectHelper::EnumerateDirectory(tab, request_id, path);
1018 void ExternalTabContainerWin::JSOutOfMemory(WebContents* tab) {
1019 Browser::JSOutOfMemoryHelper(tab);
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);
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);
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);
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;
1058 void ExternalTabContainerWin::RenderViewDeleted(
1059 content::RenderViewHost* render_view_host) {
1060 if (load_requests_via_automation_)
1061 UnregisterRenderViewHost(render_view_host);
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;
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));
1085 ignore_next_load_notification_ = true;
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));
1098 ////////////////////////////////////////////////////////////////////////////////
1099 // ExternalTabContainer, NotificationObserver implementation:
1101 void ExternalTabContainerWin::Observe(
1102 int type,
1103 const content::NotificationSource& source,
1104 const content::NotificationDetails& details) {
1105 if (!automation_)
1106 return;
1108 static const int kHttpClientErrorStart = 400;
1109 static const int kHttpServerErrorEnd = 510;
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));
1121 break;
1123 case content::NOTIFICATION_NAV_ENTRY_COMMITTED: {
1124 if (ignore_next_load_notification_) {
1125 ignore_next_load_notification_ = false;
1126 return;
1129 const content::LoadCommittedDetails* commit =
1130 content::Details<content::LoadCommittedDetails>(details).ptr();
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()));
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));
1149 break;
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);
1156 break;
1158 default:
1159 NOTREACHED();
1163 ////////////////////////////////////////////////////////////////////////////////
1164 // WidgetObserver overrides:
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();
1172 void ExternalTabContainerWin::OnWidgetDestroying(views::Widget* widget) {
1173 DCHECK_EQ(widget_, widget);
1174 Uninitialize();
1175 prop_.reset();
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();
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;
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;
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;
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;
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());
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;
1241 SkColor ExternalTabContainerWin::GetInfoBarSeparatorColor() const {
1242 return ThemeProperties::GetDefaultColor(
1243 ThemeProperties::COLOR_TOOLBAR_SEPARATOR);
1246 void ExternalTabContainerWin::InfoBarContainerStateChanged(bool is_animating) {
1247 if (external_tab_view_)
1248 external_tab_view_->Layout();
1251 bool ExternalTabContainerWin::DrawInfoBarArrows(int* x) const {
1252 return false;
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());
1261 if (!web_contents_.get() || !web_contents_->GetRenderViewHost()) {
1262 NOTREACHED();
1263 return false;
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;
1302 return true;
1305 bool ExternalTabContainerWin::CanHandleAccelerators() const {
1306 return true;
1309 void ExternalTabContainerWin::Navigate(const GURL& url, const GURL& referrer) {
1310 if (!web_contents_.get()) {
1311 NOTREACHED();
1312 return;
1315 TRACE_EVENT_BEGIN_ETW("ExternalTabContainerWin::Navigate", 0, url.spec());
1317 web_contents_->GetController().LoadURL(
1318 url, content::Referrer(referrer, WebKit::WebReferrerPolicyDefault),
1319 content::PAGE_TRANSITION_AUTO_TOPLEVEL, std::string());
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));
1328 return false;
1331 return true;
1334 void ExternalTabContainerWin::LoadAccelerators() {
1335 HACCEL accelerator_table = AtlLoadAccelerators(IDR_CHROMEFRAME);
1336 DCHECK(accelerator_table);
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;
1345 scoped_ptr<ACCEL[]> scoped_accelerators(new ACCEL[count]);
1346 ACCEL* accelerators = scoped_accelerators.get();
1347 DCHECK(accelerators != NULL);
1349 CopyAcceleratorTable(accelerator_table, accelerators, count);
1351 focus_manager_ = widget_->GetFocusManager();
1352 DCHECK(focus_manager_);
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;
1361 // Also register with the focus manager.
1362 if (focus_manager_) {
1363 focus_manager_->RegisterAccelerator(
1364 accelerator, ui::AcceleratorManager::kNormalPriority, this);
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_);
1379 NavigationStateChanged(web_contents(), 0);
1380 ServicePendingOpenURLRequests();
1383 void ExternalTabContainerWin::ServicePendingOpenURLRequests() {
1384 DCHECK(pending());
1386 set_pending(false);
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);
1393 pending_open_url_requests_.clear();
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);
1403 // The views created here will be destroyed when the ExternalTabContainer
1404 // widget is torn down.
1405 external_tab_view_ = new views::View();
1407 InfoBarContainerView* infobar_container = new InfoBarContainerView(this);
1408 infobar_container->ChangeInfoBarService(
1409 InfoBarService::FromWebContents(web_contents_.get()));
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,
1417 views::GridLayout::USE_PREF,
1421 external_tab_view_->SetLayoutManager(layout);
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());
1432 // static
1433 ExternalTabContainer* ExternalTabContainer::Create(
1434 AutomationProvider* automation_provider,
1435 AutomationResourceMessageFilter* filter) {
1436 return new ExternalTabContainerWin(automation_provider, filter);
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));
1455 // static
1456 scoped_refptr<ExternalTabContainer> ExternalTabContainer::RemovePendingTab(
1457 uintptr_t cookie) {
1458 return ExternalTabContainerWin::RemovePendingExternalTab(cookie);
1461 ///////////////////////////////////////////////////////////////////////////////
1462 // TemporaryPopupExternalTabContainerWin
1464 TemporaryPopupExternalTabContainerWin::TemporaryPopupExternalTabContainerWin(
1465 AutomationProvider* automation,
1466 AutomationResourceMessageFilter* filter)
1467 : ExternalTabContainerWin(automation, filter) {
1470 TemporaryPopupExternalTabContainerWin::~TemporaryPopupExternalTabContainerWin(
1472 DVLOG(1) << __FUNCTION__;
1475 WebContents* TemporaryPopupExternalTabContainerWin::OpenURLFromTab(
1476 WebContents* source,
1477 const OpenURLParams& params) {
1478 if (!automation_)
1479 return NULL;
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;
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;