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