extension_host.cc revision c407dc5cd9bdc5668497f21b26b09d988ab439de
1// Copyright (c) 2010 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 "app/l10n_util.h" 10#include "app/resource_bundle.h" 11#include "base/keyboard_codes.h" 12#include "base/message_loop.h" 13#include "base/singleton.h" 14#include "base/string_util.h" 15#include "chrome/browser/browser.h" 16#include "chrome/browser/browser_list.h" 17#include "chrome/browser/browser_shutdown.h" 18#include "chrome/browser/browser_theme_provider.h" 19#include "chrome/browser/browsing_instance.h" 20#include "chrome/browser/debugger/devtools_manager.h" 21#include "chrome/browser/dom_ui/dom_ui_factory.h" 22#include "chrome/browser/extensions/extension_message_service.h" 23#include "chrome/browser/extensions/extension_tabs_module.h" 24#include "chrome/browser/extensions/extension_tabs_module_constants.h" 25#include "chrome/browser/extensions/extensions_service.h" 26#include "chrome/browser/in_process_webkit/dom_storage_context.h" 27#include "chrome/browser/in_process_webkit/webkit_context.h" 28#include "chrome/browser/message_box_handler.h" 29#include "chrome/browser/platform_util.h" 30#include "chrome/browser/pref_service.h" 31#include "chrome/browser/profile.h" 32#include "chrome/browser/renderer_host/render_view_host.h" 33#include "chrome/browser/renderer_host/render_process_host.h" 34#include "chrome/browser/renderer_host/render_widget_host.h" 35#include "chrome/browser/renderer_host/render_widget_host_view.h" 36#include "chrome/browser/renderer_host/site_instance.h" 37#include "chrome/browser/renderer_preferences_util.h" 38#include "chrome/browser/tab_contents/tab_contents.h" 39#include "chrome/browser/tab_contents/tab_contents_view.h" 40#include "chrome/common/bindings_policy.h" 41#include "chrome/common/extensions/extension.h" 42#include "chrome/common/extensions/extension_constants.h" 43#include "chrome/common/notification_service.h" 44#include "chrome/common/pref_names.h" 45#include "chrome/common/view_types.h" 46#include "chrome/common/render_messages.h" 47#include "chrome/common/url_constants.h" 48#include "grit/browser_resources.h" 49#include "grit/generated_resources.h" 50#include "webkit/glue/context_menu.h" 51 52#if defined(TOOLKIT_VIEWS) 53#include "views/widget/widget.h" 54#endif 55 56using WebKit::WebDragOperation; 57using WebKit::WebDragOperationsMask; 58 59// static 60bool ExtensionHost::enable_dom_automation_ = false; 61 62static const char* kToolstripTextColorSubstitution = "$TEXT_COLOR$"; 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* get() { 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(Extension* extension, SiteInstance* site_instance, 125 const GURL& url, ViewType::Type host_type) 126 : extension_(extension), 127 profile_(site_instance->browsing_instance()->profile()), 128 did_stop_loading_(false), 129 document_element_available_(false), 130 url_(url), 131 extension_host_type_(host_type), 132 associated_tab_contents_(NULL) { 133 int64 session_storage_namespace_id = profile_->GetWebKitContext()-> 134 dom_storage_context()->AllocateSessionStorageNamespaceId(); 135 render_view_host_ = new RenderViewHost(site_instance, this, MSG_ROUTING_NONE, 136 session_storage_namespace_id); 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 152ExtensionHost::~ExtensionHost() { 153 NotificationService::current()->Notify( 154 NotificationType::EXTENSION_HOST_DESTROYED, 155 Source<Profile>(profile_), 156 Details<ExtensionHost>(this)); 157 ProcessCreationQueue::get()->Remove(this); 158 render_view_host_->Shutdown(); // deletes render_view_host 159} 160 161void ExtensionHost::CreateView(Browser* browser) { 162#if defined(TOOLKIT_VIEWS) 163 view_.reset(new ExtensionView(this, browser)); 164 // We own |view_|, so don't auto delete when it's removed from the view 165 // hierarchy. 166 view_->set_parent_owned(false); 167#elif defined(OS_MACOSX) 168 view_.reset(new ExtensionViewMac(this, browser)); 169 view_->Init(); 170#elif defined(TOOLKIT_USES_GTK) 171 view_.reset(new ExtensionViewGtk(this, browser)); 172 view_->Init(); 173#else 174 // TODO(port) 175 NOTREACHED(); 176#endif 177} 178 179RenderProcessHost* ExtensionHost::render_process_host() const { 180 return render_view_host_->process(); 181} 182 183SiteInstance* ExtensionHost::site_instance() const { 184 return render_view_host_->site_instance(); 185} 186 187bool ExtensionHost::IsRenderViewLive() const { 188 return render_view_host_->IsRenderViewLive(); 189} 190 191void ExtensionHost::CreateRenderViewSoon(RenderWidgetHostView* host_view) { 192 LOG(INFO) << "Creating RenderView for " + extension_->name(); 193 render_view_host_->set_view(host_view); 194 if (render_view_host_->process()->HasConnection()) { 195 // If the process is already started, go ahead and initialize the RenderView 196 // synchronously. The process creation is the real meaty part that we want 197 // to defer. 198 CreateRenderViewNow(); 199 } else { 200 ProcessCreationQueue::get()->CreateSoon(this); 201 } 202} 203 204void ExtensionHost::CreateRenderViewNow() { 205 render_view_host_->CreateRenderView(profile_->GetRequestContext(), 206 string16()); 207 NavigateToURL(url_); 208 DCHECK(IsRenderViewLive()); 209} 210 211void ExtensionHost::NavigateToURL(const GURL& url) { 212 LOG(INFO) << "Request to NavigateToURL " << url.spec() << " for " 213 << extension_->name(); 214 // Prevent explicit navigation to another extension id's pages. 215 // This method is only called by some APIs, so we still need to protect 216 // DidNavigate below (location = ""). 217 if (url.SchemeIs(chrome::kExtensionScheme) && 218 url.host() != extension_->id()) { 219 // TODO(erikkay) communicate this back to the caller? 220 return; 221 } 222 223 url_ = url; 224 225 if (!is_background_page() && !extension_->GetBackgroundPageReady()) { 226 LOG(INFO) << "...Waiting on EXTENSION_BACKGROUND_PAGE_READY"; 227 // Make sure the background page loads before any others. 228 registrar_.Add(this, NotificationType::EXTENSION_BACKGROUND_PAGE_READY, 229 Source<Extension>(extension_)); 230 return; 231 } 232 233 LOG(INFO) << "Navigating to " << url_.spec(); 234 render_view_host_->NavigateToURL(url_); 235} 236 237void ExtensionHost::Observe(NotificationType type, 238 const NotificationSource& source, 239 const NotificationDetails& details) { 240 switch (type.value) { 241 case NotificationType::EXTENSION_BACKGROUND_PAGE_READY: 242 DCHECK(extension_->GetBackgroundPageReady()); 243 NavigateToURL(url_); 244 break; 245 case NotificationType::BROWSER_THEME_CHANGED: 246 if (extension_host_type_ == ViewType::EXTENSION_TOOLSTRIP || 247 extension_host_type_ == ViewType::EXTENSION_MOLE) { 248 InsertThemedToolstripCSS(); 249 } 250 break; 251 case NotificationType::RENDERER_PROCESS_CREATED: 252 LOG(INFO) << "Sending EXTENSION_PROCESS_CREATED"; 253 NotificationService::current()->Notify( 254 NotificationType::EXTENSION_PROCESS_CREATED, 255 Source<Profile>(profile_), 256 Details<ExtensionHost>(this)); 257 break; 258 case NotificationType::EXTENSION_UNLOADED: 259 // The extension object will be deleted after this notification has been 260 // sent. NULL it out so that dirty pointer issues don't arise in cases 261 // when multiple ExtensionHost objects pointing to the same Extension are 262 // present. 263 if (extension_ == Details<Extension>(details).ptr()) 264 extension_ = NULL; 265 break; 266 default: 267 NOTREACHED() << "Unexpected notification sent."; 268 break; 269 } 270} 271 272void ExtensionHost::UpdatePreferredSize(const gfx::Size& new_size) { 273 if (view_.get()) 274 view_->UpdatePreferredSize(new_size); 275} 276 277void ExtensionHost::RenderViewGone(RenderViewHost* render_view_host) { 278 // During browser shutdown, we may use sudden termination on an extension 279 // process, so it is expected to lose our connection to the render view. 280 // Do nothing. 281 if (browser_shutdown::GetShutdownType() != browser_shutdown::NOT_VALID) 282 return; 283 284 // In certain cases, multiple ExtensionHost objects may have pointed to 285 // the same Extension at some point (one with a background page and a 286 // popup, for example). When the first ExtensionHost goes away, the extension 287 // is unloaded, and any other host that pointed to that extension will have 288 // its pointer to it NULLed out so that any attempt to unload a dirty pointer 289 // will be averted. 290 if (!extension_) 291 return; 292 293 LOG(INFO) << "Sending EXTENSION_PROCESS_TERMINATED for " + extension_->name(); 294 DCHECK_EQ(render_view_host_, render_view_host); 295 NotificationService::current()->Notify( 296 NotificationType::EXTENSION_PROCESS_TERMINATED, 297 Source<Profile>(profile_), 298 Details<ExtensionHost>(this)); 299} 300 301void ExtensionHost::DidNavigate(RenderViewHost* render_view_host, 302 const ViewHostMsg_FrameNavigate_Params& params) { 303 // We only care when the outer frame changes. 304 if (!PageTransition::IsMainFrame(params.transition)) 305 return; 306 307 if (!params.url.SchemeIs(chrome::kExtensionScheme)) { 308 extension_function_dispatcher_.reset(NULL); 309 url_ = params.url; 310 return; 311 } 312 313 // This catches two bogus use cases: 314 // (1) URLs that look like chrome-extension://somethingbogus or 315 // chrome-extension://nosuchid/, in other words, no Extension would 316 // be found. 317 // (2) URLs that refer to a different extension than this one. 318 // In both cases, we preserve the old URL and reset the EFD to NULL. This 319 // will leave the host in kind of a bad state with poor UI and errors, but 320 // it's better than the alternative. 321 // TODO(erikkay) Perhaps we should display log errors or display a big 404 322 // in the toolstrip or something like that. 323 if (params.url.host() != extension_->id()) { 324 extension_function_dispatcher_.reset(NULL); 325 return; 326 } 327 328 LOG(INFO) << "(DidNavigate) Resetting EFD to " << url_.spec() << " for " 329 << extension_->name(); 330 url_ = params.url; 331 extension_function_dispatcher_.reset( 332 ExtensionFunctionDispatcher::Create(render_view_host_, this, url_)); 333} 334 335void ExtensionHost::InsertInfobarCSS() { 336 DCHECK(!is_background_page()); 337 338 static const base::StringPiece css( 339 ResourceBundle::GetSharedInstance().GetRawDataResource( 340 IDR_EXTENSIONS_INFOBAR_CSS)); 341 342 render_view_host()->InsertCSSInWebFrame( 343 L"", css.as_string(), "InfobarThemeCSS"); 344} 345 346void ExtensionHost::InsertThemedToolstripCSS() { 347 DCHECK(!is_background_page()); 348 349 static const base::StringPiece toolstrip_theme_css( 350 ResourceBundle::GetSharedInstance().GetRawDataResource( 351 IDR_EXTENSIONS_TOOLSTRIP_THEME_CSS)); 352 353 std::string css = toolstrip_theme_css.as_string(); 354 ThemeProvider* theme_provider = 355 render_view_host()->process()->profile()->GetThemeProvider(); 356 357 SkColor text_color = theme_provider ? 358 theme_provider->GetColor(BrowserThemeProvider::COLOR_BOOKMARK_TEXT) : 359 SK_ColorBLACK; 360 361 std::string hex_color_string = StringPrintf( 362 "#%02x%02x%02x", SkColorGetR(text_color), 363 SkColorGetG(text_color), 364 SkColorGetB(text_color)); 365 size_t pos = css.find(kToolstripTextColorSubstitution); 366 while (pos != std::string::npos) { 367 css.replace(pos, 12, hex_color_string); 368 pos = css.find(kToolstripTextColorSubstitution); 369 } 370 371 // As a toolstrip, inject our toolstrip CSS to make it easier for toolstrips 372 // to blend in with the chrome UI. 373 render_view_host()->InsertCSSInWebFrame(L"", css, "ToolstripThemeCSS"); 374} 375 376void ExtensionHost::DisableScrollbarsForSmallWindows( 377 const gfx::Size& size_limit) { 378 render_view_host()->Send(new ViewMsg_DisableScrollbarsForSmallWindows( 379 render_view_host()->routing_id(), size_limit)); 380} 381 382void ExtensionHost::DidStopLoading() { 383 bool notify = !did_stop_loading_; 384 did_stop_loading_ = true; 385 if (extension_host_type_ == ViewType::EXTENSION_TOOLSTRIP || 386 extension_host_type_ == ViewType::EXTENSION_MOLE || 387 extension_host_type_ == ViewType::EXTENSION_POPUP || 388 extension_host_type_ == ViewType::EXTENSION_INFOBAR) { 389#if defined(TOOLKIT_VIEWS) 390 if (view_.get()) 391 view_->DidStopLoading(); 392#endif 393 } 394 if (notify) { 395 LOG(INFO) << "Sending EXTENSION_HOST_DID_STOP_LOADING"; 396 NotificationService::current()->Notify( 397 NotificationType::EXTENSION_HOST_DID_STOP_LOADING, 398 Source<Profile>(profile_), 399 Details<ExtensionHost>(this)); 400 if (extension_host_type_ == ViewType::EXTENSION_BACKGROUND_PAGE) { 401 UMA_HISTOGRAM_TIMES("Extensions.BackgroundPageLoadTime", 402 since_created_.Elapsed()); 403 } else if (extension_host_type_ == ViewType::EXTENSION_POPUP) { 404 UMA_HISTOGRAM_TIMES("Extensions.PopupLoadTime", 405 since_created_.Elapsed()); 406 } else if (extension_host_type_ == ViewType::EXTENSION_TOOLSTRIP) { 407 UMA_HISTOGRAM_TIMES("Extensions.ToolstripLoadTime", 408 since_created_.Elapsed()); 409 } else if (extension_host_type_ == ViewType::EXTENSION_INFOBAR) { 410 UMA_HISTOGRAM_TIMES("Extensions.InfobarLoadTime", 411 since_created_.Elapsed()); 412 } 413 } 414} 415 416void ExtensionHost::DocumentAvailableInMainFrame(RenderViewHost* rvh) { 417 // If the document has already been marked as available for this host, then 418 // bail. No need for the redundant setup. http://crbug.com/31170 419 if (document_element_available_) 420 return; 421 422 document_element_available_ = true; 423 if (is_background_page()) { 424 extension_->SetBackgroundPageReady(); 425 } else { 426 switch (extension_host_type_) { 427 case ViewType::EXTENSION_INFOBAR: 428 InsertInfobarCSS(); 429 break; 430 case ViewType::EXTENSION_TOOLSTRIP: 431 case ViewType::EXTENSION_MOLE: 432 // See also BROWSER_THEME_CHANGED in the Observe function. 433 InsertThemedToolstripCSS(); 434 435 // Listen for browser changes so we can resend the CSS. 436 registrar_.Add(this, NotificationType::BROWSER_THEME_CHANGED, 437 NotificationService::AllSources()); 438 break; 439 default: 440 break; // No style sheet for other types, at the moment. 441 } 442 } 443} 444 445void ExtensionHost::DocumentOnLoadCompletedInMainFrame(RenderViewHost* rvh) { 446 if (ViewType::EXTENSION_POPUP == GetRenderViewType()) { 447 NotificationService::current()->Notify( 448 NotificationType::EXTENSION_POPUP_VIEW_READY, 449 Source<Profile>(profile_), 450 Details<ExtensionHost>(this)); 451 } 452} 453 454void ExtensionHost::RunJavaScriptMessage(const std::wstring& message, 455 const std::wstring& default_prompt, 456 const GURL& frame_url, 457 const int flags, 458 IPC::Message* reply_msg, 459 bool* did_suppress_message) { 460 *did_suppress_message = false; 461 // Unlike for page alerts, navigations aren't a good signal for when to 462 // resume showing alerts, so we can't reasonably stop showing them even if 463 // the extension is spammy. 464 RunJavascriptMessageBox(this, frame_url, flags, message, default_prompt, 465 false, reply_msg); 466} 467 468std::wstring ExtensionHost::GetMessageBoxTitle(const GURL& frame_url, 469 bool is_alert) { 470 if (extension_->name().empty()) 471 return l10n_util::GetString( 472 is_alert ? IDS_EXTENSION_ALERT_DEFAULT_TITLE 473 : IDS_EXTENSION_MESSAGEBOX_DEFAULT_TITLE); 474 475 return l10n_util::GetStringF( 476 is_alert ? IDS_EXTENSION_ALERT_TITLE : IDS_EXTENSION_MESSAGEBOX_TITLE, 477 UTF8ToWide(extension_->name())); 478} 479 480gfx::NativeWindow ExtensionHost::GetMessageBoxRootWindow() { 481 // If we have a view, use that. 482 gfx::NativeView native_view = GetNativeViewOfHost(); 483 if (native_view) 484 return platform_util::GetTopLevel(native_view); 485 486 // Otherwise, try the active tab's view. 487 Browser* browser = extension_function_dispatcher_->GetCurrentBrowser(true); 488 if (browser) { 489 TabContents* active_tab = browser->GetSelectedTabContents(); 490 if (active_tab) 491 return active_tab->view()->GetTopLevelNativeWindow(); 492 } 493 494 return NULL; 495} 496 497void ExtensionHost::OnMessageBoxClosed(IPC::Message* reply_msg, 498 bool success, 499 const std::wstring& prompt) { 500 render_view_host()->JavaScriptMessageBoxClosed(reply_msg, success, prompt); 501} 502 503void ExtensionHost::Close(RenderViewHost* render_view_host) { 504 if (extension_host_type_ == ViewType::EXTENSION_POPUP || 505 extension_host_type_ == ViewType::EXTENSION_INFOBAR) { 506 NotificationService::current()->Notify( 507 NotificationType::EXTENSION_HOST_VIEW_SHOULD_CLOSE, 508 Source<Profile>(profile_), 509 Details<ExtensionHost>(this)); 510 } 511} 512 513RendererPreferences ExtensionHost::GetRendererPrefs(Profile* profile) const { 514 RendererPreferences preferences; 515 renderer_preferences_util::UpdateFromSystemSettings(&preferences, profile); 516 return preferences; 517} 518 519WebPreferences ExtensionHost::GetWebkitPrefs() { 520 Profile* profile = render_view_host()->process()->profile(); 521 WebPreferences webkit_prefs = 522 RenderViewHostDelegateHelper::GetWebkitPrefs(profile, 523 false); // is_dom_ui 524 // Extensions are trusted so we override any user preferences for disabling 525 // javascript or images. 526 webkit_prefs.loads_images_automatically = true; 527 webkit_prefs.javascript_enabled = true; 528 529 if (extension_host_type_ == ViewType::EXTENSION_POPUP || 530 extension_host_type_ == ViewType::EXTENSION_INFOBAR) 531 webkit_prefs.allow_scripts_to_close_windows = true; 532 533 // TODO(dcheng): incorporate this setting into kClipboardPermission check. 534 webkit_prefs.javascript_can_access_clipboard = true; 535 536 // TODO(dcheng): check kClipboardPermission instead once it's implemented. 537 if (extension_->HasApiPermission(Extension::kExperimentalPermission)) 538 webkit_prefs.dom_paste_enabled = true; 539 return webkit_prefs; 540} 541 542void ExtensionHost::ProcessDOMUIMessage(const std::string& message, 543 const ListValue* content, 544 const GURL& source_url, 545 int request_id, 546 bool has_callback) { 547 if (extension_function_dispatcher_.get()) { 548 extension_function_dispatcher_->HandleRequest( 549 message, content, source_url, request_id, has_callback); 550 } 551} 552 553RenderViewHostDelegate::View* ExtensionHost::GetViewDelegate() { 554 return this; 555} 556 557void ExtensionHost::CreateNewWindow( 558 int route_id, 559 WindowContainerType window_container_type, 560 const string16& frame_name) { 561 delegate_view_helper_.CreateNewWindow( 562 route_id, 563 render_view_host()->process()->profile(), 564 site_instance(), 565 DOMUIFactory::GetDOMUIType(url_), 566 this, 567 window_container_type, 568 frame_name); 569} 570 571void ExtensionHost::CreateNewWidget(int route_id, 572 WebKit::WebPopupType popup_type) { 573 CreateNewWidgetInternal(route_id, popup_type); 574} 575 576RenderWidgetHostView* ExtensionHost::CreateNewWidgetInternal( 577 int route_id, WebKit::WebPopupType popup_type) { 578 return delegate_view_helper_.CreateNewWidget(route_id, popup_type, 579 site_instance()->GetProcess()); 580} 581 582void ExtensionHost::ShowCreatedWindow(int route_id, 583 WindowOpenDisposition disposition, 584 const gfx::Rect& initial_pos, 585 bool user_gesture) { 586 TabContents* contents = delegate_view_helper_.GetCreatedWindow(route_id); 587 if (!contents) 588 return; 589 590 Browser* browser = extension_function_dispatcher_->GetCurrentBrowser( 591 profile_->GetExtensionsService()->IsIncognitoEnabled(extension_)); 592 if (!browser) 593 return; 594 595 browser->AddTabContents(contents, disposition, initial_pos, user_gesture); 596} 597 598void ExtensionHost::ShowCreatedWidget(int route_id, 599 const gfx::Rect& initial_pos) { 600 ShowCreatedWidgetInternal(delegate_view_helper_.GetCreatedWidget(route_id), 601 initial_pos); 602} 603 604void ExtensionHost::ShowCreatedWidgetInternal( 605 RenderWidgetHostView* widget_host_view, 606 const gfx::Rect& initial_pos) { 607 Browser *browser = GetBrowser(); 608 DCHECK(browser); 609 if (!browser) 610 return; 611 browser->BrowserRenderWidgetShowing(); 612 // TODO(erikkay): These two lines could be refactored with TabContentsView. 613 widget_host_view->InitAsPopup(render_view_host()->view(), initial_pos); 614 widget_host_view->GetRenderWidgetHost()->Init(); 615} 616 617void ExtensionHost::ShowContextMenu(const ContextMenuParams& params) { 618 // TODO(erikkay) Show a default context menu. 619} 620 621void ExtensionHost::StartDragging(const WebDropData& drop_data, 622 WebDragOperationsMask operation_mask, 623 const SkBitmap& image, 624 const gfx::Point& image_offset) { 625 // We're not going to do any drag & drop, but we have to tell the renderer the 626 // drag & drop ended, othewise the renderer thinks the drag operation is 627 // underway and mouse events won't work. See bug 34061. 628 // TODO(twiz) Implement drag & drop support for ExtensionHost instances. 629 // See feature issue 36288. 630 render_view_host()->DragSourceSystemDragEnded(); 631} 632 633void ExtensionHost::UpdateDragCursor(WebDragOperation operation) { 634} 635 636void ExtensionHost::GotFocus() { 637#if defined(TOOLKIT_VIEWS) 638 // Request focus so that the FocusManager has a focused view and can perform 639 // normally its key event processing (so that it lets tab key events go to the 640 // renderer). 641 view()->RequestFocus(); 642#else 643 // TODO(port) 644#endif 645} 646 647void ExtensionHost::TakeFocus(bool reverse) { 648} 649 650bool ExtensionHost::PreHandleKeyboardEvent(const NativeWebKeyboardEvent& event, 651 bool* is_keyboard_shortcut) { 652 if (extension_host_type_ == ViewType::EXTENSION_POPUP && 653 event.type == NativeWebKeyboardEvent::RawKeyDown && 654 event.windowsKeyCode == base::VKEY_ESCAPE) { 655 DCHECK(is_keyboard_shortcut != NULL); 656 *is_keyboard_shortcut = true; 657 } 658 return false; 659} 660 661void ExtensionHost::HandleKeyboardEvent(const NativeWebKeyboardEvent& event) { 662 if (extension_host_type_ == ViewType::EXTENSION_POPUP) { 663 if (event.type == NativeWebKeyboardEvent::RawKeyDown && 664 event.windowsKeyCode == base::VKEY_ESCAPE) { 665 NotificationService::current()->Notify( 666 NotificationType::EXTENSION_HOST_VIEW_SHOULD_CLOSE, 667 Source<Profile>(profile_), 668 Details<ExtensionHost>(this)); 669 return; 670 } 671 } 672 UnhandledKeyboardEvent(event); 673} 674 675void ExtensionHost::HandleMouseEvent() { 676#if defined(OS_WIN) 677 if (view_.get()) 678 view_->HandleMouseEvent(); 679#endif 680} 681 682void ExtensionHost::HandleMouseLeave() { 683#if defined(OS_WIN) 684 if (view_.get()) 685 view_->HandleMouseLeave(); 686#endif 687} 688 689void ExtensionHost::SetRenderViewType(ViewType::Type type) { 690 DCHECK(type == ViewType::EXTENSION_MOLE || 691 type == ViewType::EXTENSION_TOOLSTRIP || 692 type == ViewType::EXTENSION_POPUP); 693 extension_host_type_ = type; 694 render_view_host()->ViewTypeChanged(extension_host_type_); 695} 696 697ViewType::Type ExtensionHost::GetRenderViewType() const { 698 return extension_host_type_; 699} 700 701void ExtensionHost::RenderViewCreated(RenderViewHost* render_view_host) { 702 if (view_.get()) 703 view_->RenderViewCreated(); 704 705 // TODO(mpcomplete): This is duplicated in DidNavigate, which means that 706 // we'll create 2 EFDs for the first navigation. We should try to find a 707 // better way to unify them. 708 // See http://code.google.com/p/chromium/issues/detail?id=18240 709 LOG(INFO) << "(RenderViewCreated) Resetting EFD to " << url_.spec() << " for " 710 << extension_->name(); 711 extension_function_dispatcher_.reset( 712 ExtensionFunctionDispatcher::Create(render_view_host, this, url_)); 713 714 if (extension_host_type_ == ViewType::EXTENSION_TOOLSTRIP || 715 extension_host_type_ == ViewType::EXTENSION_MOLE || 716 extension_host_type_ == ViewType::EXTENSION_POPUP || 717 extension_host_type_ == ViewType::EXTENSION_INFOBAR) { 718 render_view_host->EnablePreferredSizeChangedMode( 719 kPreferredSizeWidth | kPreferredSizeHeightThisIsSlow); 720 } 721} 722 723int ExtensionHost::GetBrowserWindowID() const { 724 // Hosts not attached to any browser window have an id of -1. This includes 725 // those mentioned below, and background pages. 726 int window_id = extension_misc::kUnknownWindowId; 727 if (extension_host_type_ == ViewType::EXTENSION_TOOLSTRIP || 728 extension_host_type_ == ViewType::EXTENSION_MOLE || 729 extension_host_type_ == ViewType::EXTENSION_POPUP || 730 extension_host_type_ == ViewType::EXTENSION_INFOBAR) { 731 // If the host is bound to a browser, then extract its window id. 732 // Extensions hosted in ExternalTabContainer objects may not have 733 // an associated browser. 734 Browser* browser = GetBrowser(); 735 if (browser) 736 window_id = ExtensionTabUtil::GetWindowId(browser); 737 } else if (extension_host_type_ != ViewType::EXTENSION_BACKGROUND_PAGE) { 738 NOTREACHED(); 739 } 740 return window_id; 741} 742