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/extensions/extension_host.h" 6 7 #include <list> 8 9 #include "base/bind.h" 10 #include "base/memory/singleton.h" 11 #include "base/memory/weak_ptr.h" 12 #include "base/message_loop/message_loop.h" 13 #include "base/metrics/histogram.h" 14 #include "base/strings/string_util.h" 15 #include "base/strings/utf_string_conversions.h" 16 #include "chrome/browser/browser_shutdown.h" 17 #include "chrome/browser/chrome_notification_types.h" 18 #include "chrome/browser/extensions/event_router.h" 19 #include "chrome/browser/extensions/extension_process_manager.h" 20 #include "chrome/browser/extensions/extension_service.h" 21 #include "chrome/browser/extensions/extension_system.h" 22 #include "chrome/browser/extensions/extension_tab_util.h" 23 #include "chrome/browser/extensions/window_controller.h" 24 #include "chrome/browser/file_select_helper.h" 25 #include "chrome/browser/media/media_capture_devices_dispatcher.h" 26 #include "chrome/browser/profiles/profile.h" 27 #include "chrome/browser/ui/app_modal_dialogs/javascript_dialog_manager.h" 28 #include "chrome/browser/ui/browser.h" 29 #include "chrome/browser/ui/browser_dialogs.h" 30 #include "chrome/browser/ui/browser_finder.h" 31 #include "chrome/browser/ui/browser_list.h" 32 #include "chrome/browser/ui/browser_window.h" 33 #include "chrome/browser/ui/prefs/prefs_tab_helper.h" 34 #include "chrome/common/chrome_constants.h" 35 #include "chrome/common/extensions/background_info.h" 36 #include "chrome/common/extensions/extension.h" 37 #include "chrome/common/extensions/extension_constants.h" 38 #include "chrome/common/extensions/extension_messages.h" 39 #include "chrome/common/extensions/feature_switch.h" 40 #include "chrome/common/render_messages.h" 41 #include "chrome/common/url_constants.h" 42 #include "content/public/browser/content_browser_client.h" 43 #include "content/public/browser/native_web_keyboard_event.h" 44 #include "content/public/browser/notification_service.h" 45 #include "content/public/browser/render_process_host.h" 46 #include "content/public/browser/render_view_host.h" 47 #include "content/public/browser/site_instance.h" 48 #include "content/public/browser/web_contents.h" 49 #include "content/public/browser/web_contents_view.h" 50 #include "extensions/browser/view_type_utils.h" 51 #include "grit/browser_resources.h" 52 #include "grit/chromium_strings.h" 53 #include "grit/generated_resources.h" 54 #include "ui/base/keycodes/keyboard_codes.h" 55 #include "ui/base/l10n/l10n_util.h" 56 #include "ui/base/resource/resource_bundle.h" 57 58 #if !defined(OS_ANDROID) 59 #include "components/web_modal/web_contents_modal_dialog_manager.h" 60 #endif 61 62 using WebKit::WebDragOperation; 63 using WebKit::WebDragOperationsMask; 64 using content::NativeWebKeyboardEvent; 65 using content::OpenURLParams; 66 using content::RenderViewHost; 67 using content::SiteInstance; 68 using content::WebContents; 69 70 namespace extensions { 71 72 // Helper class that rate-limits the creation of renderer processes for 73 // ExtensionHosts, to avoid blocking the UI. 74 class ExtensionHost::ProcessCreationQueue { 75 public: 76 static ProcessCreationQueue* GetInstance() { 77 return Singleton<ProcessCreationQueue>::get(); 78 } 79 80 // Add a host to the queue for RenderView creation. 81 void CreateSoon(ExtensionHost* host) { 82 queue_.push_back(host); 83 PostTask(); 84 } 85 86 // Remove a host from the queue (in case it's being deleted). 87 void Remove(ExtensionHost* host) { 88 Queue::iterator it = std::find(queue_.begin(), queue_.end(), host); 89 if (it != queue_.end()) 90 queue_.erase(it); 91 } 92 93 private: 94 friend class Singleton<ProcessCreationQueue>; 95 friend struct DefaultSingletonTraits<ProcessCreationQueue>; 96 ProcessCreationQueue() 97 : pending_create_(false), 98 ptr_factory_(this) {} 99 100 // Queue up a delayed task to process the next ExtensionHost in the queue. 101 void PostTask() { 102 if (!pending_create_) { 103 base::MessageLoop::current()->PostTask(FROM_HERE, 104 base::Bind(&ProcessCreationQueue::ProcessOneHost, 105 ptr_factory_.GetWeakPtr())); 106 pending_create_ = true; 107 } 108 } 109 110 // Create the RenderView for the next host in the queue. 111 void ProcessOneHost() { 112 pending_create_ = false; 113 if (queue_.empty()) 114 return; // can happen on shutdown 115 116 queue_.front()->CreateRenderViewNow(); 117 queue_.pop_front(); 118 119 if (!queue_.empty()) 120 PostTask(); 121 } 122 123 typedef std::list<ExtensionHost*> Queue; 124 Queue queue_; 125 bool pending_create_; 126 base::WeakPtrFactory<ProcessCreationQueue> ptr_factory_; 127 }; 128 129 //////////////// 130 // ExtensionHost 131 132 ExtensionHost::ExtensionHost(const Extension* extension, 133 SiteInstance* site_instance, 134 const GURL& url, 135 ViewType host_type) 136 : extension_(extension), 137 extension_id_(extension->id()), 138 profile_(Profile::FromBrowserContext( 139 site_instance->GetBrowserContext())), 140 render_view_host_(NULL), 141 did_stop_loading_(false), 142 document_element_available_(false), 143 initial_url_(url), 144 extension_function_dispatcher_(profile_, this), 145 extension_host_type_(host_type), 146 associated_web_contents_(NULL) { 147 host_contents_.reset(WebContents::Create( 148 WebContents::CreateParams(profile_, site_instance))), 149 content::WebContentsObserver::Observe(host_contents_.get()); 150 host_contents_->SetDelegate(this); 151 SetViewType(host_contents_.get(), host_type); 152 153 PrefsTabHelper::CreateForWebContents(host_contents()); 154 155 render_view_host_ = host_contents_->GetRenderViewHost(); 156 157 // Listen for when an extension is unloaded from the same profile, as it may 158 // be the same extension that this points to. 159 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_UNLOADED, 160 content::Source<Profile>(profile_)); 161 } 162 163 ExtensionHost::~ExtensionHost() { 164 if (extension_host_type_ == VIEW_TYPE_EXTENSION_BACKGROUND_PAGE && 165 extension_ && BackgroundInfo::HasLazyBackgroundPage(extension_)) { 166 UMA_HISTOGRAM_LONG_TIMES("Extensions.EventPageActiveTime", 167 since_created_.Elapsed()); 168 } 169 content::NotificationService::current()->Notify( 170 chrome::NOTIFICATION_EXTENSION_HOST_DESTROYED, 171 content::Source<Profile>(profile_), 172 content::Details<ExtensionHost>(this)); 173 ProcessCreationQueue::GetInstance()->Remove(this); 174 } 175 176 void ExtensionHost::CreateView(Browser* browser) { 177 #if defined(TOOLKIT_VIEWS) 178 view_.reset(new ExtensionViewViews(this, browser)); 179 // We own |view_|, so don't auto delete when it's removed from the view 180 // hierarchy. 181 view_->set_owned_by_client(); 182 #elif defined(OS_MACOSX) 183 view_.reset(new ExtensionViewMac(this, browser)); 184 view_->Init(); 185 #elif defined(TOOLKIT_GTK) 186 view_.reset(new ExtensionViewGtk(this, browser)); 187 view_->Init(); 188 #else 189 // TODO(port) 190 NOTREACHED(); 191 #endif 192 } 193 194 WebContents* ExtensionHost::GetAssociatedWebContents() const { 195 return associated_web_contents_; 196 } 197 198 WebContents* ExtensionHost::GetVisibleWebContents() const { 199 if (associated_web_contents_) 200 return associated_web_contents_; 201 if ((extension_host_type_ == VIEW_TYPE_EXTENSION_POPUP) || 202 (extension_host_type_ == VIEW_TYPE_PANEL)) 203 return host_contents_.get(); 204 return NULL; 205 } 206 207 void ExtensionHost::SetAssociatedWebContents( 208 content::WebContents* web_contents) { 209 associated_web_contents_ = web_contents; 210 if (web_contents) { 211 registrar_.Add(this, content::NOTIFICATION_WEB_CONTENTS_DESTROYED, 212 content::Source<WebContents>(associated_web_contents_)); 213 } 214 } 215 216 content::RenderProcessHost* ExtensionHost::render_process_host() const { 217 return render_view_host()->GetProcess(); 218 } 219 220 RenderViewHost* ExtensionHost::render_view_host() const { 221 // TODO(mpcomplete): This can be NULL. How do we handle that? 222 return render_view_host_; 223 } 224 225 bool ExtensionHost::IsRenderViewLive() const { 226 return render_view_host()->IsRenderViewLive(); 227 } 228 229 void ExtensionHost::CreateRenderViewSoon() { 230 if ((render_process_host() && render_process_host()->HasConnection())) { 231 // If the process is already started, go ahead and initialize the RenderView 232 // synchronously. The process creation is the real meaty part that we want 233 // to defer. 234 CreateRenderViewNow(); 235 } else { 236 ProcessCreationQueue::GetInstance()->CreateSoon(this); 237 } 238 } 239 240 void ExtensionHost::CreateRenderViewNow() { 241 LoadInitialURL(); 242 if (is_background_page()) { 243 DCHECK(IsRenderViewLive()); 244 ExtensionSystem::Get(profile_)->extension_service()-> 245 DidCreateRenderViewForBackgroundPage(this); 246 } 247 } 248 249 WindowController* ExtensionHost::GetExtensionWindowController() const { 250 return view() && view()->browser() ? 251 view()->browser()->extension_window_controller() : NULL; 252 } 253 254 const GURL& ExtensionHost::GetURL() const { 255 return host_contents()->GetURL(); 256 } 257 258 void ExtensionHost::LoadInitialURL() { 259 if (!is_background_page() && 260 !ExtensionSystem::Get(profile_)->extension_service()-> 261 IsBackgroundPageReady(extension_)) { 262 // Make sure the background page loads before any others. 263 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_BACKGROUND_PAGE_READY, 264 content::Source<Extension>(extension_)); 265 return; 266 } 267 268 #if !defined(OS_ANDROID) 269 if ((extension_host_type_ == VIEW_TYPE_EXTENSION_POPUP) || 270 (extension_host_type_ == VIEW_TYPE_PANEL)) { 271 web_modal::WebContentsModalDialogManager::CreateForWebContents( 272 host_contents_.get()); 273 web_modal::WebContentsModalDialogManager::FromWebContents( 274 host_contents_.get())->set_delegate(this); 275 } 276 #endif 277 278 host_contents_->GetController().LoadURL( 279 initial_url_, content::Referrer(), content::PAGE_TRANSITION_LINK, 280 std::string()); 281 } 282 283 void ExtensionHost::Close() { 284 content::NotificationService::current()->Notify( 285 chrome::NOTIFICATION_EXTENSION_HOST_VIEW_SHOULD_CLOSE, 286 content::Source<Profile>(profile_), 287 content::Details<ExtensionHost>(this)); 288 } 289 290 void ExtensionHost::Observe(int type, 291 const content::NotificationSource& source, 292 const content::NotificationDetails& details) { 293 switch (type) { 294 case chrome::NOTIFICATION_EXTENSION_BACKGROUND_PAGE_READY: 295 DCHECK(ExtensionSystem::Get(profile_)->extension_service()-> 296 IsBackgroundPageReady(extension_)); 297 LoadInitialURL(); 298 break; 299 case chrome::NOTIFICATION_EXTENSION_UNLOADED: 300 // The extension object will be deleted after this notification has been 301 // sent. NULL it out so that dirty pointer issues don't arise in cases 302 // when multiple ExtensionHost objects pointing to the same Extension are 303 // present. 304 if (extension_ == content::Details<UnloadedExtensionInfo>(details)-> 305 extension) { 306 extension_ = NULL; 307 } 308 break; 309 case content::NOTIFICATION_WEB_CONTENTS_DESTROYED: 310 if (content::Source<WebContents>(source).ptr() == 311 associated_web_contents_) { 312 associated_web_contents_ = NULL; 313 } 314 break; 315 default: 316 NOTREACHED() << "Unexpected notification sent."; 317 break; 318 } 319 } 320 321 void ExtensionHost::ResizeDueToAutoResize(WebContents* source, 322 const gfx::Size& new_size) { 323 if (view()) 324 view()->ResizeDueToAutoResize(new_size); 325 } 326 327 void ExtensionHost::RenderProcessGone(base::TerminationStatus status) { 328 // During browser shutdown, we may use sudden termination on an extension 329 // process, so it is expected to lose our connection to the render view. 330 // Do nothing. 331 if (browser_shutdown::GetShutdownType() != browser_shutdown::NOT_VALID) 332 return; 333 334 // In certain cases, multiple ExtensionHost objects may have pointed to 335 // the same Extension at some point (one with a background page and a 336 // popup, for example). When the first ExtensionHost goes away, the extension 337 // is unloaded, and any other host that pointed to that extension will have 338 // its pointer to it NULLed out so that any attempt to unload a dirty pointer 339 // will be averted. 340 if (!extension_) 341 return; 342 343 // TODO(aa): This is suspicious. There can be multiple views in an extension, 344 // and they aren't all going to use ExtensionHost. This should be in someplace 345 // more central, like EPM maybe. 346 content::NotificationService::current()->Notify( 347 chrome::NOTIFICATION_EXTENSION_PROCESS_TERMINATED, 348 content::Source<Profile>(profile_), 349 content::Details<ExtensionHost>(this)); 350 } 351 352 void ExtensionHost::InsertInfobarCSS() { 353 DCHECK(!is_background_page()); 354 355 static const base::StringPiece css( 356 ResourceBundle::GetSharedInstance().GetRawDataResource( 357 IDR_EXTENSIONS_INFOBAR_CSS)); 358 359 render_view_host()->InsertCSS(string16(), css.as_string()); 360 } 361 362 void ExtensionHost::DidStopLoading(content::RenderViewHost* render_view_host) { 363 bool notify = !did_stop_loading_; 364 did_stop_loading_ = true; 365 if (extension_host_type_ == VIEW_TYPE_EXTENSION_POPUP || 366 extension_host_type_ == VIEW_TYPE_EXTENSION_DIALOG || 367 extension_host_type_ == VIEW_TYPE_EXTENSION_INFOBAR || 368 extension_host_type_ == VIEW_TYPE_PANEL) { 369 #if defined(TOOLKIT_VIEWS) || defined(OS_MACOSX) 370 if (view()) 371 view()->DidStopLoading(); 372 #endif 373 } 374 if (notify) { 375 if (extension_host_type_ == VIEW_TYPE_EXTENSION_BACKGROUND_PAGE) { 376 if (extension_ && BackgroundInfo::HasLazyBackgroundPage(extension_)) { 377 UMA_HISTOGRAM_TIMES("Extensions.EventPageLoadTime", 378 since_created_.Elapsed()); 379 } else { 380 UMA_HISTOGRAM_TIMES("Extensions.BackgroundPageLoadTime", 381 since_created_.Elapsed()); 382 } 383 } else if (extension_host_type_ == VIEW_TYPE_EXTENSION_DIALOG) { 384 UMA_HISTOGRAM_TIMES("Extensions.DialogLoadTime", 385 since_created_.Elapsed()); 386 } else if (extension_host_type_ == VIEW_TYPE_EXTENSION_POPUP) { 387 UMA_HISTOGRAM_TIMES("Extensions.PopupLoadTime", 388 since_created_.Elapsed()); 389 } else if (extension_host_type_ == VIEW_TYPE_EXTENSION_INFOBAR) { 390 UMA_HISTOGRAM_TIMES("Extensions.InfobarLoadTime", 391 since_created_.Elapsed()); 392 } else if (extension_host_type_ == VIEW_TYPE_PANEL) { 393 UMA_HISTOGRAM_TIMES("Extensions.PanelLoadTime", since_created_.Elapsed()); 394 } 395 396 // Send the notification last, because it might result in this being 397 // deleted. 398 content::NotificationService::current()->Notify( 399 chrome::NOTIFICATION_EXTENSION_HOST_DID_STOP_LOADING, 400 content::Source<Profile>(profile_), 401 content::Details<ExtensionHost>(this)); 402 } 403 } 404 405 void ExtensionHost::DocumentAvailableInMainFrame() { 406 // If the document has already been marked as available for this host, then 407 // bail. No need for the redundant setup. http://crbug.com/31170 408 if (document_element_available_) 409 return; 410 411 document_element_available_ = true; 412 if (is_background_page()) { 413 ExtensionSystem::Get(profile_)->extension_service()-> 414 SetBackgroundPageReady(extension_); 415 } else { 416 switch (extension_host_type_) { 417 case VIEW_TYPE_EXTENSION_INFOBAR: 418 InsertInfobarCSS(); 419 break; 420 default: 421 break; // No style sheet for other types, at the moment. 422 } 423 } 424 } 425 426 void ExtensionHost::CloseContents(WebContents* contents) { 427 // TODO(mpcomplete): is this check really necessary? 428 if (extension_host_type_ == VIEW_TYPE_EXTENSION_POPUP || 429 extension_host_type_ == VIEW_TYPE_EXTENSION_DIALOG || 430 extension_host_type_ == VIEW_TYPE_EXTENSION_BACKGROUND_PAGE || 431 extension_host_type_ == VIEW_TYPE_EXTENSION_INFOBAR || 432 extension_host_type_ == VIEW_TYPE_PANEL) { 433 Close(); 434 } 435 } 436 437 void ExtensionHost::WillRunJavaScriptDialog() { 438 ExtensionProcessManager* pm = 439 ExtensionSystem::Get(profile_)->process_manager(); 440 if (pm) 441 pm->IncrementLazyKeepaliveCount(extension()); 442 } 443 444 void ExtensionHost::DidCloseJavaScriptDialog() { 445 ExtensionProcessManager* pm = 446 ExtensionSystem::Get(profile_)->process_manager(); 447 if (pm) 448 pm->DecrementLazyKeepaliveCount(extension()); 449 } 450 451 WebContents* ExtensionHost::OpenURLFromTab(WebContents* source, 452 const OpenURLParams& params) { 453 // Whitelist the dispositions we will allow to be opened. 454 switch (params.disposition) { 455 case SINGLETON_TAB: 456 case NEW_FOREGROUND_TAB: 457 case NEW_BACKGROUND_TAB: 458 case NEW_POPUP: 459 case NEW_WINDOW: 460 case SAVE_TO_DISK: 461 case OFF_THE_RECORD: { 462 // Only allow these from hosts that are bound to a browser (e.g. popups). 463 // Otherwise they are not driven by a user gesture. 464 Browser* browser = view() ? view()->browser() : NULL; 465 return browser ? browser->OpenURL(params) : NULL; 466 } 467 default: 468 return NULL; 469 } 470 } 471 472 bool ExtensionHost::PreHandleKeyboardEvent(WebContents* source, 473 const NativeWebKeyboardEvent& event, 474 bool* is_keyboard_shortcut) { 475 if (extension_host_type_ == VIEW_TYPE_EXTENSION_POPUP && 476 event.type == NativeWebKeyboardEvent::RawKeyDown && 477 event.windowsKeyCode == ui::VKEY_ESCAPE) { 478 DCHECK(is_keyboard_shortcut != NULL); 479 *is_keyboard_shortcut = true; 480 return false; 481 } 482 483 // Handle higher priority browser shortcuts such as Ctrl-w. 484 Browser* browser = view() ? view()->browser() : NULL; 485 if (browser) 486 return browser->PreHandleKeyboardEvent(source, event, is_keyboard_shortcut); 487 488 *is_keyboard_shortcut = false; 489 return false; 490 } 491 492 void ExtensionHost::HandleKeyboardEvent(WebContents* source, 493 const NativeWebKeyboardEvent& event) { 494 if (extension_host_type_ == VIEW_TYPE_EXTENSION_POPUP) { 495 if (event.type == NativeWebKeyboardEvent::RawKeyDown && 496 event.windowsKeyCode == ui::VKEY_ESCAPE) { 497 Close(); 498 return; 499 } 500 } 501 UnhandledKeyboardEvent(source, event); 502 } 503 504 bool ExtensionHost::OnMessageReceived(const IPC::Message& message) { 505 bool handled = true; 506 IPC_BEGIN_MESSAGE_MAP(ExtensionHost, message) 507 IPC_MESSAGE_HANDLER(ExtensionHostMsg_Request, OnRequest) 508 IPC_MESSAGE_HANDLER(ExtensionHostMsg_EventAck, OnEventAck) 509 IPC_MESSAGE_HANDLER(ExtensionHostMsg_IncrementLazyKeepaliveCount, 510 OnIncrementLazyKeepaliveCount) 511 IPC_MESSAGE_HANDLER(ExtensionHostMsg_DecrementLazyKeepaliveCount, 512 OnDecrementLazyKeepaliveCount) 513 IPC_MESSAGE_UNHANDLED(handled = false) 514 IPC_END_MESSAGE_MAP() 515 return handled; 516 } 517 518 void ExtensionHost::OnRequest(const ExtensionHostMsg_Request_Params& params) { 519 extension_function_dispatcher_.Dispatch(params, render_view_host()); 520 } 521 522 void ExtensionHost::OnEventAck() { 523 EventRouter* router = ExtensionSystem::Get(profile_)->event_router(); 524 if (router) 525 router->OnEventAck(profile_, extension_id()); 526 } 527 528 void ExtensionHost::OnIncrementLazyKeepaliveCount() { 529 ExtensionProcessManager* pm = 530 ExtensionSystem::Get(profile_)->process_manager(); 531 if (pm) 532 pm->IncrementLazyKeepaliveCount(extension()); 533 } 534 535 void ExtensionHost::OnDecrementLazyKeepaliveCount() { 536 ExtensionProcessManager* pm = 537 ExtensionSystem::Get(profile_)->process_manager(); 538 if (pm) 539 pm->DecrementLazyKeepaliveCount(extension()); 540 } 541 542 void ExtensionHost::UnhandledKeyboardEvent( 543 WebContents* source, 544 const content::NativeWebKeyboardEvent& event) { 545 Browser* browser = view() ? view()->browser() : NULL; 546 if (browser) { 547 // Handle lower priority browser shortcuts such as Ctrl-f. 548 return browser->HandleKeyboardEvent(source, event); 549 } else { 550 #if defined(TOOLKIT_VIEWS) 551 // In case there's no Browser (e.g. for dialogs), pass it to 552 // ExtensionViewViews to handle acceleratos. The view's FocusManager does 553 // not know anything about Browser accelerators, but might know others such 554 // as Ash's. 555 if (view()) 556 view()->HandleKeyboardEvent(event); 557 #endif 558 } 559 } 560 561 void ExtensionHost::RenderViewCreated(RenderViewHost* render_view_host) { 562 render_view_host_ = render_view_host; 563 564 if (view()) 565 view()->RenderViewCreated(); 566 567 // If the host is bound to a window, then extract its id. Extensions hosted 568 // in ExternalTabContainer objects may not have an associated window. 569 WindowController* window = GetExtensionWindowController(); 570 if (window) { 571 render_view_host->Send(new ExtensionMsg_UpdateBrowserWindowId( 572 render_view_host->GetRoutingID(), window->GetWindowId())); 573 } 574 } 575 576 void ExtensionHost::RenderViewDeleted(RenderViewHost* render_view_host) { 577 // If our RenderViewHost is deleted, fall back to the host_contents' current 578 // RVH. There is sometimes a small gap between the pending RVH being deleted 579 // and RenderViewCreated being called, so we update it here. 580 if (render_view_host == render_view_host_) 581 render_view_host_ = host_contents_->GetRenderViewHost(); 582 } 583 584 content::JavaScriptDialogManager* ExtensionHost::GetJavaScriptDialogManager() { 585 if (!dialog_manager_) { 586 dialog_manager_.reset(CreateJavaScriptDialogManagerInstance(this)); 587 } 588 return dialog_manager_.get(); 589 } 590 591 content::ColorChooser* ExtensionHost::OpenColorChooser( 592 WebContents* web_contents, SkColor initial_color) { 593 return chrome::ShowColorChooser(web_contents, initial_color); 594 } 595 596 void ExtensionHost::RunFileChooser(WebContents* tab, 597 const content::FileChooserParams& params) { 598 FileSelectHelper::RunFileChooser(tab, params); 599 } 600 601 void ExtensionHost::AddNewContents(WebContents* source, 602 WebContents* new_contents, 603 WindowOpenDisposition disposition, 604 const gfx::Rect& initial_pos, 605 bool user_gesture, 606 bool* was_blocked) { 607 // First, if the creating extension view was associated with a tab contents, 608 // use that tab content's delegate. We must be careful here that the 609 // associated tab contents has the same profile as the new tab contents. In 610 // the case of extensions in 'spanning' incognito mode, they can mismatch. 611 // We don't want to end up putting a normal tab into an incognito window, or 612 // vice versa. 613 // Note that we don't do this for popup windows, because we need to associate 614 // those with their extension_app_id. 615 if (disposition != NEW_POPUP) { 616 WebContents* associated_contents = GetAssociatedWebContents(); 617 if (associated_contents && 618 associated_contents->GetBrowserContext() == 619 new_contents->GetBrowserContext()) { 620 WebContentsDelegate* delegate = associated_contents->GetDelegate(); 621 if (delegate) { 622 delegate->AddNewContents( 623 associated_contents, new_contents, disposition, initial_pos, 624 user_gesture, was_blocked); 625 return; 626 } 627 } 628 } 629 630 ExtensionTabUtil::CreateTab(new_contents, extension_id_, disposition, 631 initial_pos, user_gesture); 632 } 633 634 void ExtensionHost::RenderViewReady() { 635 content::NotificationService::current()->Notify( 636 chrome::NOTIFICATION_EXTENSION_HOST_CREATED, 637 content::Source<Profile>(profile_), 638 content::Details<ExtensionHost>(this)); 639 } 640 641 void ExtensionHost::RequestMediaAccessPermission( 642 content::WebContents* web_contents, 643 const content::MediaStreamRequest& request, 644 const content::MediaResponseCallback& callback) { 645 MediaCaptureDevicesDispatcher::GetInstance()->ProcessMediaAccessRequest( 646 web_contents, request, callback, extension()); 647 } 648 649 } // namespace extensions 650