extension_host.cc revision 72a454cd3513ac24fbdd0e0cb9ad70b86a99b801
1// Copyright (c) 2011 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/extensions/extension_host.h" 6 7#include <list> 8 9#include "base/message_loop.h" 10#include "base/singleton.h" 11#include "base/metrics/histogram.h" 12#include "base/string_util.h" 13#include "chrome/browser/browser_list.h" 14#include "chrome/browser/browser_shutdown.h" 15#include "chrome/browser/browser_window.h" 16#include "chrome/browser/browsing_instance.h" 17#include "chrome/browser/debugger/devtools_manager.h" 18#include "chrome/browser/desktop_notification_handler.h" 19#include "chrome/browser/dom_ui/web_ui_factory.h" 20#include "chrome/browser/extensions/extension_message_service.h" 21#include "chrome/browser/extensions/extension_tabs_module.h" 22#include "chrome/browser/extensions/extension_service.h" 23#include "chrome/browser/file_select_helper.h" 24#include "chrome/browser/platform_util.h" 25#include "chrome/browser/profiles/profile.h" 26#include "chrome/browser/renderer_host/render_process_host.h" 27#include "chrome/browser/renderer_host/render_view_host.h" 28#include "chrome/browser/renderer_host/render_widget_host.h" 29#include "chrome/browser/renderer_host/render_widget_host_view.h" 30#include "chrome/browser/renderer_host/site_instance.h" 31#include "chrome/browser/renderer_preferences_util.h" 32#include "chrome/browser/tab_contents/popup_menu_helper_mac.h" 33#include "chrome/browser/tab_contents/tab_contents.h" 34#include "chrome/browser/tab_contents/tab_contents_view.h" 35#include "chrome/browser/themes/browser_theme_provider.h" 36#include "chrome/browser/ui/app_modal_dialogs/message_box_handler.h" 37#include "chrome/browser/ui/browser.h" 38#include "chrome/common/bindings_policy.h" 39#include "chrome/common/extensions/extension.h" 40#include "chrome/common/extensions/extension_constants.h" 41#include "chrome/common/native_web_keyboard_event.h" 42#include "chrome/common/notification_service.h" 43#include "chrome/common/render_messages.h" 44#include "chrome/common/render_messages_params.h" 45#include "chrome/common/url_constants.h" 46#include "chrome/common/view_types.h" 47#include "grit/browser_resources.h" 48#include "grit/generated_resources.h" 49#include "ui/base/keycodes/keyboard_codes.h" 50#include "ui/base/l10n/l10n_util.h" 51#include "ui/base/resource/resource_bundle.h" 52#include "webkit/glue/context_menu.h" 53 54#if defined(TOOLKIT_VIEWS) 55#include "views/widget/widget.h" 56#endif 57 58using WebKit::WebDragOperation; 59using WebKit::WebDragOperationsMask; 60 61// static 62bool ExtensionHost::enable_dom_automation_ = false; 63 64// Helper class that rate-limits the creation of renderer processes for 65// ExtensionHosts, to avoid blocking the UI. 66class ExtensionHost::ProcessCreationQueue { 67 public: 68 static ProcessCreationQueue* GetInstance() { 69 return Singleton<ProcessCreationQueue>::get(); 70 } 71 72 // Add a host to the queue for RenderView creation. 73 void CreateSoon(ExtensionHost* host) { 74 queue_.push_back(host); 75 PostTask(); 76 } 77 78 // Remove a host from the queue (in case it's being deleted). 79 void Remove(ExtensionHost* host) { 80 Queue::iterator it = std::find(queue_.begin(), queue_.end(), host); 81 if (it != queue_.end()) 82 queue_.erase(it); 83 } 84 85 private: 86 friend class Singleton<ProcessCreationQueue>; 87 friend struct DefaultSingletonTraits<ProcessCreationQueue>; 88 ProcessCreationQueue() 89 : pending_create_(false), 90 ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)) { } 91 92 // Queue up a delayed task to process the next ExtensionHost in the queue. 93 void PostTask() { 94 if (!pending_create_) { 95 MessageLoop::current()->PostTask(FROM_HERE, 96 method_factory_.NewRunnableMethod( 97 &ProcessCreationQueue::ProcessOneHost)); 98 pending_create_ = true; 99 } 100 } 101 102 // Create the RenderView for the next host in the queue. 103 void ProcessOneHost() { 104 pending_create_ = false; 105 if (queue_.empty()) 106 return; // can happen on shutdown 107 108 queue_.front()->CreateRenderViewNow(); 109 queue_.pop_front(); 110 111 if (!queue_.empty()) 112 PostTask(); 113 } 114 115 typedef std::list<ExtensionHost*> Queue; 116 Queue queue_; 117 bool pending_create_; 118 ScopedRunnableMethodFactory<ProcessCreationQueue> method_factory_; 119}; 120 121//////////////// 122// ExtensionHost 123 124ExtensionHost::ExtensionHost(const Extension* extension, 125 SiteInstance* site_instance, 126 const GURL& url, 127 ViewType::Type host_type) 128 : extension_(extension), 129 profile_(site_instance->browsing_instance()->profile()), 130 did_stop_loading_(false), 131 document_element_available_(false), 132 url_(url), 133 extension_host_type_(host_type), 134 associated_tab_contents_(NULL) { 135 render_view_host_ = new RenderViewHost(site_instance, this, MSG_ROUTING_NONE, 136 NULL); 137 render_view_host_->set_is_extension_process(true); 138 render_view_host_->AllowBindings(BindingsPolicy::EXTENSION); 139 if (enable_dom_automation_) 140 render_view_host_->AllowBindings(BindingsPolicy::DOM_AUTOMATION); 141 142 // Listen for when the render process' handle is available so we can add it 143 // to the task manager then. 144 registrar_.Add(this, NotificationType::RENDERER_PROCESS_CREATED, 145 Source<RenderProcessHost>(render_process_host())); 146 // Listen for when an extension is unloaded from the same profile, as it may 147 // be the same extension that this points to. 148 registrar_.Add(this, NotificationType::EXTENSION_UNLOADED, 149 Source<Profile>(profile_)); 150 151 desktop_notification_handler_.reset( 152 new DesktopNotificationHandler(NULL, render_process_host())); 153} 154 155ExtensionHost::~ExtensionHost() { 156 NotificationService::current()->Notify( 157 NotificationType::EXTENSION_HOST_DESTROYED, 158 Source<Profile>(profile_), 159 Details<ExtensionHost>(this)); 160 ProcessCreationQueue::GetInstance()->Remove(this); 161 render_view_host_->Shutdown(); // deletes render_view_host 162} 163 164void ExtensionHost::CreateView(Browser* browser) { 165#if defined(TOOLKIT_VIEWS) 166 view_.reset(new ExtensionView(this, browser)); 167 // We own |view_|, so don't auto delete when it's removed from the view 168 // hierarchy. 169 view_->set_parent_owned(false); 170#elif defined(OS_MACOSX) 171 view_.reset(new ExtensionViewMac(this, browser)); 172 view_->Init(); 173#elif defined(TOOLKIT_USES_GTK) 174 view_.reset(new ExtensionViewGtk(this, browser)); 175 view_->Init(); 176#else 177 // TODO(port) 178 NOTREACHED(); 179#endif 180} 181 182TabContents* ExtensionHost::associated_tab_contents() const { 183 return associated_tab_contents_; 184} 185 186RenderProcessHost* ExtensionHost::render_process_host() const { 187 return render_view_host_->process(); 188} 189 190SiteInstance* ExtensionHost::site_instance() const { 191 return render_view_host_->site_instance(); 192} 193 194bool ExtensionHost::IsRenderViewLive() const { 195 return render_view_host_->IsRenderViewLive(); 196} 197 198void ExtensionHost::CreateRenderViewSoon(RenderWidgetHostView* host_view) { 199 render_view_host_->set_view(host_view); 200 if (render_view_host_->process()->HasConnection()) { 201 // If the process is already started, go ahead and initialize the RenderView 202 // synchronously. The process creation is the real meaty part that we want 203 // to defer. 204 CreateRenderViewNow(); 205 } else { 206 ProcessCreationQueue::GetInstance()->CreateSoon(this); 207 } 208} 209 210void ExtensionHost::CreateRenderViewNow() { 211 render_view_host_->CreateRenderView(string16()); 212 NavigateToURL(url_); 213 DCHECK(IsRenderViewLive()); 214 if (is_background_page()) 215 profile_->GetExtensionService()->DidCreateRenderViewForBackgroundPage( 216 this); 217} 218 219const Browser* ExtensionHost::GetBrowser() const { 220 return view() ? view()->browser() : NULL; 221} 222 223Browser* ExtensionHost::GetBrowser() { 224 return view() ? view()->browser() : NULL; 225} 226 227gfx::NativeView ExtensionHost::GetNativeViewOfHost() { 228 return view() ? view()->native_view() : NULL; 229} 230 231void ExtensionHost::NavigateToURL(const GURL& url) { 232 // Prevent explicit navigation to another extension id's pages. 233 // This method is only called by some APIs, so we still need to protect 234 // DidNavigate below (location = ""). 235 if (url.SchemeIs(chrome::kExtensionScheme) && 236 url.host() != extension_->id()) { 237 // TODO(erikkay) communicate this back to the caller? 238 return; 239 } 240 241 url_ = url; 242 243 if (!is_background_page() && 244 !profile_->GetExtensionService()->IsBackgroundPageReady(extension_)) { 245 // Make sure the background page loads before any others. 246 registrar_.Add(this, NotificationType::EXTENSION_BACKGROUND_PAGE_READY, 247 Source<Extension>(extension_)); 248 return; 249 } 250 251 render_view_host_->NavigateToURL(url_); 252} 253 254void ExtensionHost::Observe(NotificationType type, 255 const NotificationSource& source, 256 const NotificationDetails& details) { 257 switch (type.value) { 258 case NotificationType::EXTENSION_BACKGROUND_PAGE_READY: 259 DCHECK(profile_->GetExtensionService()-> 260 IsBackgroundPageReady(extension_)); 261 NavigateToURL(url_); 262 break; 263 case NotificationType::RENDERER_PROCESS_CREATED: 264 NotificationService::current()->Notify( 265 NotificationType::EXTENSION_PROCESS_CREATED, 266 Source<Profile>(profile_), 267 Details<ExtensionHost>(this)); 268 break; 269 case NotificationType::EXTENSION_UNLOADED: 270 // The extension object will be deleted after this notification has been 271 // sent. NULL it out so that dirty pointer issues don't arise in cases 272 // when multiple ExtensionHost objects pointing to the same Extension are 273 // present. 274 if (extension_ == Details<UnloadedExtensionInfo>(details)->extension) 275 extension_ = NULL; 276 break; 277 default: 278 NOTREACHED() << "Unexpected notification sent."; 279 break; 280 } 281} 282 283void ExtensionHost::UpdatePreferredSize(const gfx::Size& new_size) { 284 if (view_.get()) 285 view_->UpdatePreferredSize(new_size); 286} 287 288void ExtensionHost::UpdateInspectorSetting(const std::string& key, 289 const std::string& value) { 290 RenderViewHostDelegateHelper::UpdateInspectorSetting(profile(), key, value); 291} 292 293void ExtensionHost::ClearInspectorSettings() { 294 RenderViewHostDelegateHelper::ClearInspectorSettings(profile()); 295} 296 297void ExtensionHost::RenderViewGone(RenderViewHost* render_view_host, 298 base::TerminationStatus status, 299 int error_code) { 300 // During browser shutdown, we may use sudden termination on an extension 301 // process, so it is expected to lose our connection to the render view. 302 // Do nothing. 303 if (browser_shutdown::GetShutdownType() != browser_shutdown::NOT_VALID) 304 return; 305 306 // In certain cases, multiple ExtensionHost objects may have pointed to 307 // the same Extension at some point (one with a background page and a 308 // popup, for example). When the first ExtensionHost goes away, the extension 309 // is unloaded, and any other host that pointed to that extension will have 310 // its pointer to it NULLed out so that any attempt to unload a dirty pointer 311 // will be averted. 312 if (!extension_) 313 return; 314 315 DCHECK_EQ(render_view_host_, render_view_host); 316 NotificationService::current()->Notify( 317 NotificationType::EXTENSION_PROCESS_TERMINATED, 318 Source<Profile>(profile_), 319 Details<ExtensionHost>(this)); 320} 321 322void ExtensionHost::DidNavigate(RenderViewHost* render_view_host, 323 const ViewHostMsg_FrameNavigate_Params& params) { 324 // We only care when the outer frame changes. 325 if (!PageTransition::IsMainFrame(params.transition)) 326 return; 327 328 if (!params.url.SchemeIs(chrome::kExtensionScheme)) { 329 extension_function_dispatcher_.reset(NULL); 330 url_ = params.url; 331 return; 332 } 333 334 // This catches two bogus use cases: 335 // (1) URLs that look like chrome-extension://somethingbogus or 336 // chrome-extension://nosuchid/, in other words, no Extension would 337 // be found. 338 // (2) URLs that refer to a different extension than this one. 339 // In both cases, we preserve the old URL and reset the EFD to NULL. This 340 // will leave the host in kind of a bad state with poor UI and errors, but 341 // it's better than the alternative. 342 // TODO(erikkay) Perhaps we should display errors in developer mode. 343 if (params.url.host() != extension_->id()) { 344 extension_function_dispatcher_.reset(NULL); 345 return; 346 } 347 348 url_ = params.url; 349 extension_function_dispatcher_.reset( 350 ExtensionFunctionDispatcher::Create(render_view_host_, this, url_)); 351} 352 353void ExtensionHost::InsertInfobarCSS() { 354 DCHECK(!is_background_page()); 355 356 static const base::StringPiece css( 357 ResourceBundle::GetSharedInstance().GetRawDataResource( 358 IDR_EXTENSIONS_INFOBAR_CSS)); 359 360 render_view_host()->InsertCSSInWebFrame( 361 L"", css.as_string(), "InfobarThemeCSS"); 362} 363 364void ExtensionHost::DisableScrollbarsForSmallWindows( 365 const gfx::Size& size_limit) { 366 render_view_host()->Send(new ViewMsg_DisableScrollbarsForSmallWindows( 367 render_view_host()->routing_id(), size_limit)); 368} 369 370void ExtensionHost::DidStopLoading() { 371 bool notify = !did_stop_loading_; 372 did_stop_loading_ = true; 373 if (extension_host_type_ == ViewType::EXTENSION_POPUP || 374 extension_host_type_ == ViewType::EXTENSION_INFOBAR) { 375#if defined(TOOLKIT_VIEWS) 376 if (view_.get()) 377 view_->DidStopLoading(); 378#endif 379 } 380 if (notify) { 381 NotificationService::current()->Notify( 382 NotificationType::EXTENSION_HOST_DID_STOP_LOADING, 383 Source<Profile>(profile_), 384 Details<ExtensionHost>(this)); 385 if (extension_host_type_ == ViewType::EXTENSION_BACKGROUND_PAGE) { 386 UMA_HISTOGRAM_TIMES("Extensions.BackgroundPageLoadTime", 387 since_created_.Elapsed()); 388 } else if (extension_host_type_ == ViewType::EXTENSION_POPUP) { 389 UMA_HISTOGRAM_TIMES("Extensions.PopupLoadTime", 390 since_created_.Elapsed()); 391 } else if (extension_host_type_ == ViewType::EXTENSION_INFOBAR) { 392 UMA_HISTOGRAM_TIMES("Extensions.InfobarLoadTime", 393 since_created_.Elapsed()); 394 } 395 } 396} 397 398void ExtensionHost::DocumentAvailableInMainFrame(RenderViewHost* rvh) { 399 // If the document has already been marked as available for this host, then 400 // bail. No need for the redundant setup. http://crbug.com/31170 401 if (document_element_available_) 402 return; 403 404 document_element_available_ = true; 405 if (is_background_page()) { 406 profile_->GetExtensionService()->SetBackgroundPageReady(extension_); 407 } else { 408 switch (extension_host_type_) { 409 case ViewType::EXTENSION_INFOBAR: 410 InsertInfobarCSS(); 411 break; 412 default: 413 break; // No style sheet for other types, at the moment. 414 } 415 } 416} 417 418void ExtensionHost::DocumentOnLoadCompletedInMainFrame(RenderViewHost* rvh, 419 int32 page_id) { 420 if (ViewType::EXTENSION_POPUP == GetRenderViewType()) { 421 NotificationService::current()->Notify( 422 NotificationType::EXTENSION_POPUP_VIEW_READY, 423 Source<Profile>(profile_), 424 Details<ExtensionHost>(this)); 425 } 426} 427 428void ExtensionHost::RunJavaScriptMessage(const std::wstring& message, 429 const std::wstring& default_prompt, 430 const GURL& frame_url, 431 const int flags, 432 IPC::Message* reply_msg, 433 bool* did_suppress_message) { 434 *did_suppress_message = false; 435 // Unlike for page alerts, navigations aren't a good signal for when to 436 // resume showing alerts, so we can't reasonably stop showing them even if 437 // the extension is spammy. 438 RunJavascriptMessageBox(profile_, this, frame_url, flags, message, 439 default_prompt, false, reply_msg); 440} 441 442gfx::NativeWindow ExtensionHost::GetMessageBoxRootWindow() { 443 // If we have a view, use that. 444 gfx::NativeView native_view = GetNativeViewOfHost(); 445 if (native_view) 446 return platform_util::GetTopLevel(native_view); 447 448 // Otherwise, try the active tab's view. 449 Browser* browser = extension_function_dispatcher_->GetCurrentBrowser(true); 450 if (browser) { 451 TabContents* active_tab = browser->GetSelectedTabContents(); 452 if (active_tab) 453 return active_tab->view()->GetTopLevelNativeWindow(); 454 } 455 456 return NULL; 457} 458 459TabContents* ExtensionHost::AsTabContents() { 460 return NULL; 461} 462 463ExtensionHost* ExtensionHost::AsExtensionHost() { 464 return this; 465} 466 467void ExtensionHost::OnMessageBoxClosed(IPC::Message* reply_msg, 468 bool success, 469 const std::wstring& prompt) { 470 render_view_host()->JavaScriptMessageBoxClosed(reply_msg, success, prompt); 471} 472 473void ExtensionHost::Close(RenderViewHost* render_view_host) { 474 if (extension_host_type_ == ViewType::EXTENSION_POPUP || 475 extension_host_type_ == ViewType::EXTENSION_INFOBAR) { 476 NotificationService::current()->Notify( 477 NotificationType::EXTENSION_HOST_VIEW_SHOULD_CLOSE, 478 Source<Profile>(profile_), 479 Details<ExtensionHost>(this)); 480 } 481} 482 483RendererPreferences ExtensionHost::GetRendererPrefs(Profile* profile) const { 484 RendererPreferences preferences; 485 486 TabContents* associated_contents = associated_tab_contents(); 487 if (associated_contents) 488 preferences = 489 static_cast<RenderViewHostDelegate*>(associated_contents)-> 490 GetRendererPrefs(profile); 491 492 renderer_preferences_util::UpdateFromSystemSettings(&preferences, profile); 493 return preferences; 494} 495 496WebPreferences ExtensionHost::GetWebkitPrefs() { 497 Profile* profile = render_view_host()->process()->profile(); 498 WebPreferences webkit_prefs = 499 RenderViewHostDelegateHelper::GetWebkitPrefs(profile, 500 false); // is_dom_ui 501 // Extensions are trusted so we override any user preferences for disabling 502 // javascript or images. 503 webkit_prefs.loads_images_automatically = true; 504 webkit_prefs.javascript_enabled = true; 505 506 if (extension_host_type_ == ViewType::EXTENSION_POPUP || 507 extension_host_type_ == ViewType::EXTENSION_INFOBAR) 508 webkit_prefs.allow_scripts_to_close_windows = true; 509 510 // Disable anything that requires the GPU process for background pages. 511 // See http://crbug.com/64512 and http://crbug.com/64841. 512 if (extension_host_type_ == ViewType::EXTENSION_BACKGROUND_PAGE) { 513 webkit_prefs.experimental_webgl_enabled = false; 514 webkit_prefs.accelerated_compositing_enabled = false; 515 webkit_prefs.accelerated_2d_canvas_enabled = false; 516 } 517 518 // TODO(dcheng): incorporate this setting into kClipboardPermission check. 519 webkit_prefs.javascript_can_access_clipboard = true; 520 521 // TODO(dcheng): check kClipboardPermission instead once it's implemented. 522 if (extension_->HasApiPermission(Extension::kExperimentalPermission)) 523 webkit_prefs.dom_paste_enabled = true; 524 return webkit_prefs; 525} 526 527void ExtensionHost::ProcessWebUIMessage( 528 const ViewHostMsg_DomMessage_Params& params) { 529 if (extension_function_dispatcher_.get()) { 530 extension_function_dispatcher_->HandleRequest(params); 531 } 532} 533 534RenderViewHostDelegate::View* ExtensionHost::GetViewDelegate() { 535 return this; 536} 537 538void ExtensionHost::CreateNewWindow( 539 int route_id, 540 const ViewHostMsg_CreateWindow_Params& params) { 541 // TODO(aa): Use the browser's profile if the extension is split mode 542 // incognito. 543 TabContents* new_contents = delegate_view_helper_.CreateNewWindow( 544 route_id, 545 render_view_host()->process()->profile(), 546 site_instance(), 547 WebUIFactory::GetWebUIType(render_view_host()->process()->profile(), 548 url_), 549 this, 550 params.window_container_type, 551 params.frame_name); 552 553 TabContents* associated_contents = associated_tab_contents(); 554 if (associated_contents && associated_contents->delegate()) 555 associated_contents->delegate()->TabContentsCreated(new_contents); 556} 557 558void ExtensionHost::CreateNewWidget(int route_id, 559 WebKit::WebPopupType popup_type) { 560 CreateNewWidgetInternal(route_id, popup_type); 561} 562 563void ExtensionHost::CreateNewFullscreenWidget(int route_id) { 564 NOTREACHED() 565 << "ExtensionHost does not support showing full screen popups yet."; 566} 567 568RenderWidgetHostView* ExtensionHost::CreateNewWidgetInternal( 569 int route_id, WebKit::WebPopupType popup_type) { 570 return delegate_view_helper_.CreateNewWidget(route_id, popup_type, 571 site_instance()->GetProcess()); 572} 573 574void ExtensionHost::ShowCreatedWindow(int route_id, 575 WindowOpenDisposition disposition, 576 const gfx::Rect& initial_pos, 577 bool user_gesture) { 578 TabContents* contents = delegate_view_helper_.GetCreatedWindow(route_id); 579 if (!contents) 580 return; 581 582 if (disposition == NEW_POPUP) { 583 // Create a new Browser window of type TYPE_APP_POPUP. 584 // (AddTabContents would otherwise create a window of type TYPE_POPUP). 585 Browser* browser = Browser::CreateForPopup(Browser::TYPE_APP_POPUP, 586 contents->profile(), 587 contents, 588 initial_pos); 589 browser->window()->Show(); 590 return; 591 } 592 593 // If the tab contents isn't a popup, it's a normal tab. We need to find a 594 // home for it. This is typically a Browser, but it can also be some other 595 // TabContentsDelegate in the case of ChromeFrame. 596 597 // First, if the creating extension view was associated with a tab contents, 598 // use that tab content's delegate. We must be careful here that the 599 // associated tab contents has the same profile as the new tab contents. In 600 // the case of extensions in 'spanning' incognito mode, they can mismatch. 601 // We don't want to end up putting a normal tab into an incognito window, or 602 // vice versa. 603 TabContents* associated_contents = associated_tab_contents(); 604 if (associated_contents && 605 associated_contents->profile() == contents->profile()) { 606 associated_contents->AddNewContents(contents, disposition, initial_pos, 607 user_gesture); 608 return; 609 } 610 611 // If there's no associated tab contents, or it doesn't have a matching 612 // profile, try finding an open window. Again, we must make sure to find a 613 // window with the correct profile. 614 Browser* browser = BrowserList::FindBrowserWithType( 615 contents->profile(), 616 Browser::TYPE_NORMAL, 617 false); // Match incognito exactly. 618 619 // If there's no Browser open with the right profile, create a new one. 620 if (!browser) { 621 browser = Browser::Create(contents->profile()); 622 browser->window()->Show(); 623 } 624 625 if (browser) 626 browser->AddTabContents(contents, disposition, initial_pos, user_gesture); 627} 628 629void ExtensionHost::ShowCreatedWidget(int route_id, 630 const gfx::Rect& initial_pos) { 631 ShowCreatedWidgetInternal(delegate_view_helper_.GetCreatedWidget(route_id), 632 initial_pos); 633} 634 635void ExtensionHost::ShowCreatedFullscreenWidget(int route_id) { 636 NOTREACHED() 637 << "ExtensionHost does not support showing full screen popups yet."; 638} 639 640void ExtensionHost::ShowCreatedWidgetInternal( 641 RenderWidgetHostView* widget_host_view, 642 const gfx::Rect& initial_pos) { 643 Browser *browser = GetBrowser(); 644 DCHECK(browser); 645 if (!browser) 646 return; 647 browser->BrowserRenderWidgetShowing(); 648 // TODO(erikkay): These two lines could be refactored with TabContentsView. 649 widget_host_view->InitAsPopup(render_view_host()->view(), initial_pos); 650 widget_host_view->GetRenderWidgetHost()->Init(); 651} 652 653void ExtensionHost::ShowContextMenu(const ContextMenuParams& params) { 654 // TODO(erikkay) Show a default context menu. 655} 656 657void ExtensionHost::ShowPopupMenu(const gfx::Rect& bounds, 658 int item_height, 659 double item_font_size, 660 int selected_item, 661 const std::vector<WebMenuItem>& items, 662 bool right_aligned) { 663#if defined(OS_MACOSX) 664 PopupMenuHelper popup_menu_helper(render_view_host()); 665 popup_menu_helper.ShowPopupMenu(bounds, item_height, item_font_size, 666 selected_item, items, right_aligned); 667#else 668 // Only on Mac are select popup menus external. 669 NOTREACHED(); 670#endif 671} 672 673void ExtensionHost::StartDragging(const WebDropData& drop_data, 674 WebDragOperationsMask operation_mask, 675 const SkBitmap& image, 676 const gfx::Point& image_offset) { 677 // We're not going to do any drag & drop, but we have to tell the renderer the 678 // drag & drop ended, othewise the renderer thinks the drag operation is 679 // underway and mouse events won't work. See bug 34061. 680 // TODO(twiz) Implement drag & drop support for ExtensionHost instances. 681 // See feature issue 36288. 682 render_view_host()->DragSourceSystemDragEnded(); 683} 684 685void ExtensionHost::UpdateDragCursor(WebDragOperation operation) { 686} 687 688void ExtensionHost::GotFocus() { 689#if defined(TOOLKIT_VIEWS) 690 // Request focus so that the FocusManager has a focused view and can perform 691 // normally its key event processing (so that it lets tab key events go to the 692 // renderer). 693 view()->RequestFocus(); 694#else 695 // TODO(port) 696#endif 697} 698 699void ExtensionHost::TakeFocus(bool reverse) { 700} 701 702void ExtensionHost::LostCapture() { 703} 704 705void ExtensionHost::Activate() { 706} 707 708void ExtensionHost::Deactivate() { 709} 710 711bool ExtensionHost::PreHandleKeyboardEvent(const NativeWebKeyboardEvent& event, 712 bool* is_keyboard_shortcut) { 713 if (extension_host_type_ == ViewType::EXTENSION_POPUP && 714 event.type == NativeWebKeyboardEvent::RawKeyDown && 715 event.windowsKeyCode == ui::VKEY_ESCAPE) { 716 DCHECK(is_keyboard_shortcut != NULL); 717 *is_keyboard_shortcut = true; 718 } 719 return false; 720} 721 722void ExtensionHost::HandleKeyboardEvent(const NativeWebKeyboardEvent& event) { 723 if (extension_host_type_ == ViewType::EXTENSION_POPUP) { 724 if (event.type == NativeWebKeyboardEvent::RawKeyDown && 725 event.windowsKeyCode == ui::VKEY_ESCAPE) { 726 NotificationService::current()->Notify( 727 NotificationType::EXTENSION_HOST_VIEW_SHOULD_CLOSE, 728 Source<Profile>(profile_), 729 Details<ExtensionHost>(this)); 730 return; 731 } 732 } 733 UnhandledKeyboardEvent(event); 734} 735 736void ExtensionHost::HandleMouseMove() { 737#if defined(OS_WIN) 738 if (view_.get()) 739 view_->HandleMouseMove(); 740#endif 741} 742 743void ExtensionHost::HandleMouseDown() { 744} 745 746void ExtensionHost::HandleMouseLeave() { 747#if defined(OS_WIN) 748 if (view_.get()) 749 view_->HandleMouseLeave(); 750#endif 751} 752 753void ExtensionHost::HandleMouseUp() { 754} 755 756void ExtensionHost::HandleMouseActivate() { 757} 758 759ViewType::Type ExtensionHost::GetRenderViewType() const { 760 return extension_host_type_; 761} 762 763bool ExtensionHost::OnMessageReceived(const IPC::Message& message) { 764 bool handled = true; 765 IPC_BEGIN_MESSAGE_MAP(ExtensionHost, message) 766 IPC_MESSAGE_HANDLER(ViewHostMsg_RunFileChooser, OnRunFileChooser) 767 IPC_MESSAGE_UNHANDLED(handled = false) 768 IPC_END_MESSAGE_MAP() 769 770 if (!handled) { 771 // Pass desktop notification IPCs to the DesktopNotificationHandler. 772 handled = desktop_notification_handler_->OnMessageReceived(message); 773 } 774 return handled; 775} 776 777const GURL& ExtensionHost::GetURL() const { 778 return url_; 779} 780 781void ExtensionHost::RenderViewCreated(RenderViewHost* render_view_host) { 782 if (view_.get()) 783 view_->RenderViewCreated(); 784 785 // TODO(mpcomplete): This is duplicated in DidNavigate, which means that 786 // we'll create 2 EFDs for the first navigation. We should try to find a 787 // better way to unify them. 788 // See http://code.google.com/p/chromium/issues/detail?id=18240 789 extension_function_dispatcher_.reset( 790 ExtensionFunctionDispatcher::Create(render_view_host, this, url_)); 791 792 if (extension_host_type_ == ViewType::EXTENSION_POPUP || 793 extension_host_type_ == ViewType::EXTENSION_INFOBAR) { 794 render_view_host->EnablePreferredSizeChangedMode( 795 kPreferredSizeWidth | kPreferredSizeHeightThisIsSlow); 796 } 797} 798 799int ExtensionHost::GetBrowserWindowID() const { 800 // Hosts not attached to any browser window have an id of -1. This includes 801 // those mentioned below, and background pages. 802 int window_id = extension_misc::kUnknownWindowId; 803 if (extension_host_type_ == ViewType::EXTENSION_POPUP || 804 extension_host_type_ == ViewType::EXTENSION_INFOBAR) { 805 // If the host is bound to a browser, then extract its window id. 806 // Extensions hosted in ExternalTabContainer objects may not have 807 // an associated browser. 808 const Browser* browser = GetBrowser(); 809 if (browser) 810 window_id = ExtensionTabUtil::GetWindowId(browser); 811 } else if (extension_host_type_ != ViewType::EXTENSION_BACKGROUND_PAGE) { 812 NOTREACHED(); 813 } 814 return window_id; 815} 816 817void ExtensionHost::OnRunFileChooser( 818 const ViewHostMsg_RunFileChooser_Params& params) { 819 if (file_select_helper_.get() == NULL) 820 file_select_helper_.reset(new FileSelectHelper(profile())); 821 file_select_helper_->RunFileChooser(render_view_host_, params); 822} 823