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