OLD | NEW |
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/browser/extensions/extension_host.h" | 5 #include "chrome/browser/extensions/extension_host.h" |
6 | 6 |
7 #include <list> | 7 #include <list> |
8 | 8 |
9 #include "app/l10n_util.h" | 9 #include "app/l10n_util.h" |
10 #include "app/resource_bundle.h" | 10 #include "app/resource_bundle.h" |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
52 #if defined(TOOLKIT_VIEWS) | 52 #if defined(TOOLKIT_VIEWS) |
53 #include "views/widget/widget.h" | 53 #include "views/widget/widget.h" |
54 #endif | 54 #endif |
55 | 55 |
56 using WebKit::WebDragOperation; | 56 using WebKit::WebDragOperation; |
57 using WebKit::WebDragOperationsMask; | 57 using WebKit::WebDragOperationsMask; |
58 | 58 |
59 // static | 59 // static |
60 bool ExtensionHost::enable_dom_automation_ = false; | 60 bool ExtensionHost::enable_dom_automation_ = false; |
61 | 61 |
62 static const char* kToolstripTextColorSubstitution = "$TEXT_COLOR$"; | |
63 | |
64 // Helper class that rate-limits the creation of renderer processes for | 62 // Helper class that rate-limits the creation of renderer processes for |
65 // ExtensionHosts, to avoid blocking the UI. | 63 // ExtensionHosts, to avoid blocking the UI. |
66 class ExtensionHost::ProcessCreationQueue { | 64 class ExtensionHost::ProcessCreationQueue { |
67 public: | 65 public: |
68 static ProcessCreationQueue* get() { | 66 static ProcessCreationQueue* get() { |
69 return Singleton<ProcessCreationQueue>::get(); | 67 return Singleton<ProcessCreationQueue>::get(); |
70 } | 68 } |
71 | 69 |
72 // Add a host to the queue for RenderView creation. | 70 // Add a host to the queue for RenderView creation. |
73 void CreateSoon(ExtensionHost* host) { | 71 void CreateSoon(ExtensionHost* host) { |
(...skipping 168 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
242 } | 240 } |
243 | 241 |
244 void ExtensionHost::Observe(NotificationType type, | 242 void ExtensionHost::Observe(NotificationType type, |
245 const NotificationSource& source, | 243 const NotificationSource& source, |
246 const NotificationDetails& details) { | 244 const NotificationDetails& details) { |
247 switch (type.value) { | 245 switch (type.value) { |
248 case NotificationType::EXTENSION_BACKGROUND_PAGE_READY: | 246 case NotificationType::EXTENSION_BACKGROUND_PAGE_READY: |
249 DCHECK(extension_->GetBackgroundPageReady()); | 247 DCHECK(extension_->GetBackgroundPageReady()); |
250 NavigateToURL(url_); | 248 NavigateToURL(url_); |
251 break; | 249 break; |
252 case NotificationType::BROWSER_THEME_CHANGED: | |
253 if (extension_host_type_ == ViewType::EXTENSION_TOOLSTRIP || | |
254 extension_host_type_ == ViewType::EXTENSION_MOLE) { | |
255 InsertThemedToolstripCSS(); | |
256 } | |
257 break; | |
258 case NotificationType::RENDERER_PROCESS_CREATED: | 250 case NotificationType::RENDERER_PROCESS_CREATED: |
259 LOG(INFO) << "Sending EXTENSION_PROCESS_CREATED"; | 251 LOG(INFO) << "Sending EXTENSION_PROCESS_CREATED"; |
260 NotificationService::current()->Notify( | 252 NotificationService::current()->Notify( |
261 NotificationType::EXTENSION_PROCESS_CREATED, | 253 NotificationType::EXTENSION_PROCESS_CREATED, |
262 Source<Profile>(profile_), | 254 Source<Profile>(profile_), |
263 Details<ExtensionHost>(this)); | 255 Details<ExtensionHost>(this)); |
264 break; | 256 break; |
265 case NotificationType::EXTENSION_UNLOADED: | 257 case NotificationType::EXTENSION_UNLOADED: |
266 // The extension object will be deleted after this notification has been | 258 // The extension object will be deleted after this notification has been |
267 // sent. NULL it out so that dirty pointer issues don't arise in cases | 259 // sent. NULL it out so that dirty pointer issues don't arise in cases |
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
318 } | 310 } |
319 | 311 |
320 // This catches two bogus use cases: | 312 // This catches two bogus use cases: |
321 // (1) URLs that look like chrome-extension://somethingbogus or | 313 // (1) URLs that look like chrome-extension://somethingbogus or |
322 // chrome-extension://nosuchid/, in other words, no Extension would | 314 // chrome-extension://nosuchid/, in other words, no Extension would |
323 // be found. | 315 // be found. |
324 // (2) URLs that refer to a different extension than this one. | 316 // (2) URLs that refer to a different extension than this one. |
325 // In both cases, we preserve the old URL and reset the EFD to NULL. This | 317 // In both cases, we preserve the old URL and reset the EFD to NULL. This |
326 // will leave the host in kind of a bad state with poor UI and errors, but | 318 // will leave the host in kind of a bad state with poor UI and errors, but |
327 // it's better than the alternative. | 319 // it's better than the alternative. |
328 // TODO(erikkay) Perhaps we should display log errors or display a big 404 | 320 // TODO(erikkay) Perhaps we should display errors in developer mode. |
329 // in the toolstrip or something like that. | |
330 if (params.url.host() != extension_->id()) { | 321 if (params.url.host() != extension_->id()) { |
331 extension_function_dispatcher_.reset(NULL); | 322 extension_function_dispatcher_.reset(NULL); |
332 return; | 323 return; |
333 } | 324 } |
334 | 325 |
335 LOG(INFO) << "(DidNavigate) Resetting EFD to " << url_.spec() << " for " | 326 LOG(INFO) << "(DidNavigate) Resetting EFD to " << url_.spec() << " for " |
336 << extension_->name(); | 327 << extension_->name(); |
337 url_ = params.url; | 328 url_ = params.url; |
338 extension_function_dispatcher_.reset( | 329 extension_function_dispatcher_.reset( |
339 ExtensionFunctionDispatcher::Create(render_view_host_, this, url_)); | 330 ExtensionFunctionDispatcher::Create(render_view_host_, this, url_)); |
340 } | 331 } |
341 | 332 |
342 void ExtensionHost::InsertInfobarCSS() { | 333 void ExtensionHost::InsertInfobarCSS() { |
343 DCHECK(!is_background_page()); | 334 DCHECK(!is_background_page()); |
344 | 335 |
345 static const base::StringPiece css( | 336 static const base::StringPiece css( |
346 ResourceBundle::GetSharedInstance().GetRawDataResource( | 337 ResourceBundle::GetSharedInstance().GetRawDataResource( |
347 IDR_EXTENSIONS_INFOBAR_CSS)); | 338 IDR_EXTENSIONS_INFOBAR_CSS)); |
348 | 339 |
349 render_view_host()->InsertCSSInWebFrame( | 340 render_view_host()->InsertCSSInWebFrame( |
350 L"", css.as_string(), "InfobarThemeCSS"); | 341 L"", css.as_string(), "InfobarThemeCSS"); |
351 } | 342 } |
352 | 343 |
353 void ExtensionHost::InsertThemedToolstripCSS() { | |
354 DCHECK(!is_background_page()); | |
355 | |
356 static const base::StringPiece toolstrip_theme_css( | |
357 ResourceBundle::GetSharedInstance().GetRawDataResource( | |
358 IDR_EXTENSIONS_TOOLSTRIP_THEME_CSS)); | |
359 | |
360 std::string css = toolstrip_theme_css.as_string(); | |
361 ThemeProvider* theme_provider = | |
362 render_view_host()->process()->profile()->GetThemeProvider(); | |
363 | |
364 SkColor text_color = theme_provider ? | |
365 theme_provider->GetColor(BrowserThemeProvider::COLOR_BOOKMARK_TEXT) : | |
366 SK_ColorBLACK; | |
367 | |
368 std::string hex_color_string = StringPrintf( | |
369 "#%02x%02x%02x", SkColorGetR(text_color), | |
370 SkColorGetG(text_color), | |
371 SkColorGetB(text_color)); | |
372 size_t pos = css.find(kToolstripTextColorSubstitution); | |
373 while (pos != std::string::npos) { | |
374 css.replace(pos, 12, hex_color_string); | |
375 pos = css.find(kToolstripTextColorSubstitution); | |
376 } | |
377 | |
378 // As a toolstrip, inject our toolstrip CSS to make it easier for toolstrips | |
379 // to blend in with the chrome UI. | |
380 render_view_host()->InsertCSSInWebFrame(L"", css, "ToolstripThemeCSS"); | |
381 } | |
382 | |
383 void ExtensionHost::DisableScrollbarsForSmallWindows( | 344 void ExtensionHost::DisableScrollbarsForSmallWindows( |
384 const gfx::Size& size_limit) { | 345 const gfx::Size& size_limit) { |
385 render_view_host()->Send(new ViewMsg_DisableScrollbarsForSmallWindows( | 346 render_view_host()->Send(new ViewMsg_DisableScrollbarsForSmallWindows( |
386 render_view_host()->routing_id(), size_limit)); | 347 render_view_host()->routing_id(), size_limit)); |
387 } | 348 } |
388 | 349 |
389 void ExtensionHost::DidStopLoading() { | 350 void ExtensionHost::DidStopLoading() { |
390 bool notify = !did_stop_loading_; | 351 bool notify = !did_stop_loading_; |
391 did_stop_loading_ = true; | 352 did_stop_loading_ = true; |
392 if (extension_host_type_ == ViewType::EXTENSION_TOOLSTRIP || | 353 if (extension_host_type_ == ViewType::EXTENSION_POPUP || |
393 extension_host_type_ == ViewType::EXTENSION_MOLE || | |
394 extension_host_type_ == ViewType::EXTENSION_POPUP || | |
395 extension_host_type_ == ViewType::EXTENSION_INFOBAR) { | 354 extension_host_type_ == ViewType::EXTENSION_INFOBAR) { |
396 #if defined(TOOLKIT_VIEWS) | 355 #if defined(TOOLKIT_VIEWS) |
397 if (view_.get()) | 356 if (view_.get()) |
398 view_->DidStopLoading(); | 357 view_->DidStopLoading(); |
399 #endif | 358 #endif |
400 } | 359 } |
401 if (notify) { | 360 if (notify) { |
402 LOG(INFO) << "Sending EXTENSION_HOST_DID_STOP_LOADING"; | 361 LOG(INFO) << "Sending EXTENSION_HOST_DID_STOP_LOADING"; |
403 NotificationService::current()->Notify( | 362 NotificationService::current()->Notify( |
404 NotificationType::EXTENSION_HOST_DID_STOP_LOADING, | 363 NotificationType::EXTENSION_HOST_DID_STOP_LOADING, |
405 Source<Profile>(profile_), | 364 Source<Profile>(profile_), |
406 Details<ExtensionHost>(this)); | 365 Details<ExtensionHost>(this)); |
407 if (extension_host_type_ == ViewType::EXTENSION_BACKGROUND_PAGE) { | 366 if (extension_host_type_ == ViewType::EXTENSION_BACKGROUND_PAGE) { |
408 UMA_HISTOGRAM_TIMES("Extensions.BackgroundPageLoadTime", | 367 UMA_HISTOGRAM_TIMES("Extensions.BackgroundPageLoadTime", |
409 since_created_.Elapsed()); | 368 since_created_.Elapsed()); |
410 } else if (extension_host_type_ == ViewType::EXTENSION_POPUP) { | 369 } else if (extension_host_type_ == ViewType::EXTENSION_POPUP) { |
411 UMA_HISTOGRAM_TIMES("Extensions.PopupLoadTime", | 370 UMA_HISTOGRAM_TIMES("Extensions.PopupLoadTime", |
412 since_created_.Elapsed()); | 371 since_created_.Elapsed()); |
413 } else if (extension_host_type_ == ViewType::EXTENSION_TOOLSTRIP) { | |
414 UMA_HISTOGRAM_TIMES("Extensions.ToolstripLoadTime", | |
415 since_created_.Elapsed()); | |
416 } else if (extension_host_type_ == ViewType::EXTENSION_INFOBAR) { | 372 } else if (extension_host_type_ == ViewType::EXTENSION_INFOBAR) { |
417 UMA_HISTOGRAM_TIMES("Extensions.InfobarLoadTime", | 373 UMA_HISTOGRAM_TIMES("Extensions.InfobarLoadTime", |
418 since_created_.Elapsed()); | 374 since_created_.Elapsed()); |
419 } | 375 } |
420 } | 376 } |
421 } | 377 } |
422 | 378 |
423 void ExtensionHost::DocumentAvailableInMainFrame(RenderViewHost* rvh) { | 379 void ExtensionHost::DocumentAvailableInMainFrame(RenderViewHost* rvh) { |
424 // If the document has already been marked as available for this host, then | 380 // If the document has already been marked as available for this host, then |
425 // bail. No need for the redundant setup. http://crbug.com/31170 | 381 // bail. No need for the redundant setup. http://crbug.com/31170 |
426 if (document_element_available_) | 382 if (document_element_available_) |
427 return; | 383 return; |
428 | 384 |
429 document_element_available_ = true; | 385 document_element_available_ = true; |
430 if (is_background_page()) { | 386 if (is_background_page()) { |
431 extension_->SetBackgroundPageReady(); | 387 extension_->SetBackgroundPageReady(); |
432 } else { | 388 } else { |
433 switch (extension_host_type_) { | 389 switch (extension_host_type_) { |
434 case ViewType::EXTENSION_INFOBAR: | 390 case ViewType::EXTENSION_INFOBAR: |
435 InsertInfobarCSS(); | 391 InsertInfobarCSS(); |
436 break; | 392 break; |
437 case ViewType::EXTENSION_TOOLSTRIP: | |
438 case ViewType::EXTENSION_MOLE: | |
439 // See also BROWSER_THEME_CHANGED in the Observe function. | |
440 InsertThemedToolstripCSS(); | |
441 | |
442 // Listen for browser changes so we can resend the CSS. | |
443 registrar_.Add(this, NotificationType::BROWSER_THEME_CHANGED, | |
444 NotificationService::AllSources()); | |
445 break; | |
446 default: | 393 default: |
447 break; // No style sheet for other types, at the moment. | 394 break; // No style sheet for other types, at the moment. |
448 } | 395 } |
449 } | 396 } |
450 } | 397 } |
451 | 398 |
452 void ExtensionHost::DocumentOnLoadCompletedInMainFrame(RenderViewHost* rvh) { | 399 void ExtensionHost::DocumentOnLoadCompletedInMainFrame(RenderViewHost* rvh) { |
453 if (ViewType::EXTENSION_POPUP == GetRenderViewType()) { | 400 if (ViewType::EXTENSION_POPUP == GetRenderViewType()) { |
454 NotificationService::current()->Notify( | 401 NotificationService::current()->Notify( |
455 NotificationType::EXTENSION_POPUP_VIEW_READY, | 402 NotificationType::EXTENSION_POPUP_VIEW_READY, |
(...skipping 239 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
695 void ExtensionHost::HandleMouseDown() { | 642 void ExtensionHost::HandleMouseDown() { |
696 } | 643 } |
697 | 644 |
698 void ExtensionHost::HandleMouseLeave() { | 645 void ExtensionHost::HandleMouseLeave() { |
699 #if defined(OS_WIN) | 646 #if defined(OS_WIN) |
700 if (view_.get()) | 647 if (view_.get()) |
701 view_->HandleMouseLeave(); | 648 view_->HandleMouseLeave(); |
702 #endif | 649 #endif |
703 } | 650 } |
704 | 651 |
705 void ExtensionHost::SetRenderViewType(ViewType::Type type) { | |
706 DCHECK(type == ViewType::EXTENSION_MOLE || | |
707 type == ViewType::EXTENSION_TOOLSTRIP || | |
708 type == ViewType::EXTENSION_POPUP); | |
709 extension_host_type_ = type; | |
710 render_view_host()->ViewTypeChanged(extension_host_type_); | |
711 } | |
712 | |
713 ViewType::Type ExtensionHost::GetRenderViewType() const { | 652 ViewType::Type ExtensionHost::GetRenderViewType() const { |
714 return extension_host_type_; | 653 return extension_host_type_; |
715 } | 654 } |
716 | 655 |
717 void ExtensionHost::RenderViewCreated(RenderViewHost* render_view_host) { | 656 void ExtensionHost::RenderViewCreated(RenderViewHost* render_view_host) { |
718 if (view_.get()) | 657 if (view_.get()) |
719 view_->RenderViewCreated(); | 658 view_->RenderViewCreated(); |
720 | 659 |
721 // TODO(mpcomplete): This is duplicated in DidNavigate, which means that | 660 // TODO(mpcomplete): This is duplicated in DidNavigate, which means that |
722 // we'll create 2 EFDs for the first navigation. We should try to find a | 661 // we'll create 2 EFDs for the first navigation. We should try to find a |
723 // better way to unify them. | 662 // better way to unify them. |
724 // See http://code.google.com/p/chromium/issues/detail?id=18240 | 663 // See http://code.google.com/p/chromium/issues/detail?id=18240 |
725 LOG(INFO) << "(RenderViewCreated) Resetting EFD to " << url_.spec() << " for " | 664 LOG(INFO) << "(RenderViewCreated) Resetting EFD to " << url_.spec() << " for " |
726 << extension_->name(); | 665 << extension_->name(); |
727 extension_function_dispatcher_.reset( | 666 extension_function_dispatcher_.reset( |
728 ExtensionFunctionDispatcher::Create(render_view_host, this, url_)); | 667 ExtensionFunctionDispatcher::Create(render_view_host, this, url_)); |
729 | 668 |
730 if (extension_host_type_ == ViewType::EXTENSION_TOOLSTRIP || | 669 if (extension_host_type_ == ViewType::EXTENSION_POPUP || |
731 extension_host_type_ == ViewType::EXTENSION_MOLE || | |
732 extension_host_type_ == ViewType::EXTENSION_POPUP || | |
733 extension_host_type_ == ViewType::EXTENSION_INFOBAR) { | 670 extension_host_type_ == ViewType::EXTENSION_INFOBAR) { |
734 render_view_host->EnablePreferredSizeChangedMode( | 671 render_view_host->EnablePreferredSizeChangedMode( |
735 kPreferredSizeWidth | kPreferredSizeHeightThisIsSlow); | 672 kPreferredSizeWidth | kPreferredSizeHeightThisIsSlow); |
736 } | 673 } |
737 } | 674 } |
738 | 675 |
739 int ExtensionHost::GetBrowserWindowID() const { | 676 int ExtensionHost::GetBrowserWindowID() const { |
740 // Hosts not attached to any browser window have an id of -1. This includes | 677 // Hosts not attached to any browser window have an id of -1. This includes |
741 // those mentioned below, and background pages. | 678 // those mentioned below, and background pages. |
742 int window_id = extension_misc::kUnknownWindowId; | 679 int window_id = extension_misc::kUnknownWindowId; |
743 if (extension_host_type_ == ViewType::EXTENSION_TOOLSTRIP || | 680 if (extension_host_type_ == ViewType::EXTENSION_POPUP || |
744 extension_host_type_ == ViewType::EXTENSION_MOLE || | |
745 extension_host_type_ == ViewType::EXTENSION_POPUP || | |
746 extension_host_type_ == ViewType::EXTENSION_INFOBAR) { | 681 extension_host_type_ == ViewType::EXTENSION_INFOBAR) { |
747 // If the host is bound to a browser, then extract its window id. | 682 // If the host is bound to a browser, then extract its window id. |
748 // Extensions hosted in ExternalTabContainer objects may not have | 683 // Extensions hosted in ExternalTabContainer objects may not have |
749 // an associated browser. | 684 // an associated browser. |
750 Browser* browser = GetBrowser(); | 685 Browser* browser = GetBrowser(); |
751 if (browser) | 686 if (browser) |
752 window_id = ExtensionTabUtil::GetWindowId(browser); | 687 window_id = ExtensionTabUtil::GetWindowId(browser); |
753 } else if (extension_host_type_ != ViewType::EXTENSION_BACKGROUND_PAGE) { | 688 } else if (extension_host_type_ != ViewType::EXTENSION_BACKGROUND_PAGE) { |
754 NOTREACHED(); | 689 NOTREACHED(); |
755 } | 690 } |
756 return window_id; | 691 return window_id; |
757 } | 692 } |
OLD | NEW |