// Copyright (c) 2013 The Chromium Embedded Framework Authors. // Portions copyright (c) 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "libcef/renderer/content_renderer_client.h" #include #include "base/compiler_specific.h" // Enable deprecation warnings for MSVC. See http://crbug.com/585142. #if defined(OS_WIN) #pragma warning(push) #pragma warning(default : 4996) #endif #include "libcef/browser/context.h" #include "libcef/common/cef_messages.h" #include "libcef/common/cef_switches.h" #include "libcef/common/content_client.h" #include "libcef/common/extensions/extensions_client.h" #include "libcef/common/extensions/extensions_util.h" #include "libcef/common/request_impl.h" #include "libcef/common/values_impl.h" #include "libcef/renderer/browser_impl.h" #include "libcef/renderer/extensions/extensions_renderer_client.h" #include "libcef/renderer/extensions/print_render_frame_helper_delegate.h" #include "libcef/renderer/media/cef_key_systems.h" #include "libcef/renderer/pepper/pepper_helper.h" #include "libcef/renderer/plugins/cef_plugin_placeholder.h" #include "libcef/renderer/plugins/plugin_preroller.h" #include "libcef/renderer/render_frame_observer.h" #include "libcef/renderer/render_message_filter.h" #include "libcef/renderer/render_thread_observer.h" #include "libcef/renderer/thread_util.h" #include "libcef/renderer/v8_impl.h" #include "libcef/renderer/webkit_glue.h" #include "base/command_line.h" #include "base/macros.h" #include "base/memory/ptr_util.h" #include "base/metrics/user_metrics_action.h" #include "base/path_service.h" #include "base/stl_util.h" #include "base/strings/string_number_conversions.h" #include "base/strings/utf_string_conversions.h" #include "build/build_config.h" #include "chrome/common/chrome_switches.h" #include "chrome/common/pepper_permission_util.h" #include "chrome/common/url_constants.h" #include "chrome/grit/generated_resources.h" #include "chrome/grit/renderer_resources.h" #include "chrome/renderer/content_settings_observer.h" #include "chrome/renderer/loadtimes_extension_bindings.h" #include "chrome/renderer/pepper/chrome_pdf_print_client.h" #include "chrome/renderer/plugins/power_saver_info.h" #include "components/content_settings/core/common/content_settings_types.h" #include "components/nacl/common/nacl_constants.h" #include "components/printing/renderer/print_render_frame_helper.h" #include "components/spellcheck/renderer/spellcheck.h" #include "components/spellcheck/renderer/spellcheck_provider.h" #include "components/visitedlink/renderer/visitedlink_slave.h" #include "components/web_cache/renderer/web_cache_impl.h" #include "content/common/frame_messages.h" #include "content/public/browser/browser_thread.h" #include "content/public/browser/render_process_host.h" #include "content/public/child/child_thread.h" #include "content/public/common/content_constants.h" #include "content/public/common/content_paths.h" #include "content/public/common/content_switches.h" #include "content/public/renderer/plugin_instance_throttler.h" #include "content/public/renderer/render_thread.h" #include "content/public/renderer/render_view.h" #include "content/public/renderer/render_view_visitor.h" #include "content/renderer/render_frame_impl.h" #include "content/renderer/render_widget.h" #include "extensions/common/switches.h" #include "extensions/renderer/renderer_extension_registry.h" #include "ipc/ipc_sync_channel.h" #include "media/base/media.h" #include "printing/print_settings.h" #include "third_party/WebKit/public/platform/URLConversion.h" #include "third_party/WebKit/public/platform/WebPrerenderingSupport.h" #include "third_party/WebKit/public/platform/WebRuntimeFeatures.h" #include "third_party/WebKit/public/platform/WebString.h" #include "third_party/WebKit/public/platform/WebURL.h" #include "third_party/WebKit/public/platform/scheduler/renderer_process_type.h" #include "third_party/WebKit/public/web/WebConsoleMessage.h" #include "third_party/WebKit/public/web/WebElement.h" #include "third_party/WebKit/public/web/WebFrame.h" #include "third_party/WebKit/public/web/WebLocalFrame.h" #include "third_party/WebKit/public/web/WebPrerendererClient.h" #include "third_party/WebKit/public/web/WebSecurityPolicy.h" #include "third_party/WebKit/public/web/WebView.h" #include "ui/base/l10n/l10n_util.h" #if defined(OS_MACOSX) #include "base/mac/mac_util.h" #include "base/strings/sys_string_conversions.h" #endif namespace { // Stub implementation of blink::WebPrerenderingSupport. class CefPrerenderingSupport : public blink::WebPrerenderingSupport { private: void Add(const blink::WebPrerender& prerender) override {} void Cancel(const blink::WebPrerender& prerender) override {} void Abandon(const blink::WebPrerender& prerender) override {} void PrefetchFinished() override {} }; // Stub implementation of blink::WebPrerendererClient. class CefPrerendererClient : public content::RenderViewObserver, public blink::WebPrerendererClient { public: explicit CefPrerendererClient(content::RenderView* render_view) : content::RenderViewObserver(render_view) { DCHECK(render_view); render_view->GetWebView()->SetPrerendererClient(this); } private: ~CefPrerendererClient() override {} // RenderViewObserver methods: void OnDestruct() override { delete this; } // WebPrerendererClient methods: void WillAddPrerender(blink::WebPrerender* prerender) override {} bool IsPrefetchOnly() override { return false; } }; void AppendParams(const std::vector& additional_names, const std::vector& additional_values, blink::WebVector* existing_names, blink::WebVector* existing_values) { DCHECK(additional_names.size() == additional_values.size()); DCHECK(existing_names->size() == existing_values->size()); size_t existing_size = existing_names->size(); size_t total_size = existing_size + additional_names.size(); blink::WebVector names(total_size); blink::WebVector values(total_size); for (size_t i = 0; i < existing_size; ++i) { names[i] = (*existing_names)[i]; values[i] = (*existing_values)[i]; } for (size_t i = 0; i < additional_names.size(); ++i) { names[existing_size + i] = blink::WebString::FromUTF16(additional_names[i]); values[existing_size + i] = blink::WebString::FromUTF16(additional_values[i]); } existing_names->Swap(names); existing_values->Swap(values); } bool IsStandaloneExtensionProcess() { return extensions::ExtensionsEnabled() && extensions::CefExtensionsRendererClient:: IsStandaloneExtensionProcess(); } } // namespace // Placeholder object for guest views. class CefGuestView : public content::RenderViewObserver { public: explicit CefGuestView(content::RenderView* render_view) : content::RenderViewObserver(render_view) {} private: // RenderViewObserver methods. void OnDestruct() override { CefContentRendererClient::Get()->OnGuestViewDestroyed(this); } }; CefContentRendererClient::CefContentRendererClient() : devtools_agent_count_(0), uncaught_exception_stack_size_(0), single_process_cleanup_complete_(false) { if (extensions::ExtensionsEnabled()) { extensions_client_.reset(new extensions::CefExtensionsClient); extensions::ExtensionsClient::Set(extensions_client_.get()); extensions_renderer_client_.reset( new extensions::CefExtensionsRendererClient); extensions::ExtensionsRendererClient::Set( extensions_renderer_client_.get()); } printing::SetAgent(CefContentClient::Get()->GetUserAgent()); } CefContentRendererClient::~CefContentRendererClient() {} // static CefContentRendererClient* CefContentRendererClient::Get() { return static_cast( CefContentClient::Get()->renderer()); } CefRefPtr CefContentRendererClient::GetBrowserForView( content::RenderView* view) { CEF_REQUIRE_RT_RETURN(NULL); BrowserMap::const_iterator it = browsers_.find(view); if (it != browsers_.end()) return it->second; return NULL; } CefRefPtr CefContentRendererClient::GetBrowserForMainFrame( blink::WebFrame* frame) { CEF_REQUIRE_RT_RETURN(NULL); BrowserMap::const_iterator it = browsers_.begin(); for (; it != browsers_.end(); ++it) { content::RenderView* render_view = it->second->render_view(); if (render_view && render_view->GetWebView() && render_view->GetWebView()->MainFrame() == frame) { return it->second; } } return NULL; } void CefContentRendererClient::OnBrowserDestroyed(CefBrowserImpl* browser) { BrowserMap::iterator it = browsers_.begin(); for (; it != browsers_.end(); ++it) { if (it->second.get() == browser) { browsers_.erase(it); return; } } // No browser was found in the map. NOTREACHED(); } bool CefContentRendererClient::HasGuestViewForView(content::RenderView* view) { CEF_REQUIRE_RT_RETURN(false); GuestViewMap::const_iterator it = guest_views_.find(view); return it != guest_views_.end(); } void CefContentRendererClient::OnGuestViewDestroyed(CefGuestView* guest_view) { GuestViewMap::iterator it = guest_views_.begin(); for (; it != guest_views_.end(); ++it) { if (it->second.get() == guest_view) { guest_views_.erase(it); return; } } // No guest view was found in the map. NOTREACHED(); } void CefContentRendererClient::WebKitInitialized() { const base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); // Create global objects associated with the default Isolate. CefV8IsolateCreated(); // TODO(cef): Enable these once the implementation supports it. blink::WebRuntimeFeatures::EnableNotifications(false); const CefContentClient::SchemeInfoList* schemes = CefContentClient::Get()->GetCustomSchemes(); if (!schemes->empty()) { // Register the custom schemes. The |is_standard| value is excluded here // because it's not explicitly registered with Blink. CefContentClient::SchemeInfoList::const_iterator it = schemes->begin(); for (; it != schemes->end(); ++it) { const CefContentClient::SchemeInfo& info = *it; const blink::WebString& scheme = blink::WebString::FromUTF8(info.scheme_name); if (info.is_local) webkit_glue::RegisterURLSchemeAsLocal(scheme); if (info.is_display_isolated) blink::WebSecurityPolicy::RegisterURLSchemeAsDisplayIsolated(scheme); if (info.is_secure) webkit_glue::RegisterURLSchemeAsSecure(scheme); } } if (!cross_origin_whitelist_entries_.empty()) { // Add the cross-origin white list entries. for (size_t i = 0; i < cross_origin_whitelist_entries_.size(); ++i) { const Cef_CrossOriginWhiteListEntry_Params& entry = cross_origin_whitelist_entries_[i]; GURL gurl = GURL(entry.source_origin); blink::WebSecurityPolicy::AddOriginAccessWhitelistEntry( gurl, blink::WebString::FromUTF8(entry.target_protocol), blink::WebString::FromUTF8(entry.target_domain), entry.allow_target_subdomains); } cross_origin_whitelist_entries_.clear(); } // The number of stack trace frames to capture for uncaught exceptions. if (command_line->HasSwitch(switches::kUncaughtExceptionStackSize)) { int uncaught_exception_stack_size = 0; base::StringToInt(command_line->GetSwitchValueASCII( switches::kUncaughtExceptionStackSize), &uncaught_exception_stack_size); if (uncaught_exception_stack_size > 0) { uncaught_exception_stack_size_ = uncaught_exception_stack_size; CefV8SetUncaughtExceptionStackSize(uncaught_exception_stack_size_); } } // Notify the render process handler. CefRefPtr application = CefContentClient::Get()->application(); if (application.get()) { CefRefPtr handler = application->GetRenderProcessHandler(); if (handler.get()) handler->OnWebKitInitialized(); } } void CefContentRendererClient::DevToolsAgentAttached() { CEF_REQUIRE_RT(); ++devtools_agent_count_; } void CefContentRendererClient::DevToolsAgentDetached() { CEF_REQUIRE_RT(); --devtools_agent_count_; if (devtools_agent_count_ == 0 && uncaught_exception_stack_size_ > 0) { // When the last DevToolsAgent is detached the stack size is set to 0. // Restore the user-specified stack size here. CefV8SetUncaughtExceptionStackSize(uncaught_exception_stack_size_); } } scoped_refptr CefContentRendererClient::GetCurrentTaskRunner() { // Check if currently on the render thread. if (CEF_CURRENTLY_ON_RT()) return render_task_runner_; return NULL; } void CefContentRendererClient::RunSingleProcessCleanup() { DCHECK(content::RenderProcessHost::run_renderer_in_process()); // Make sure the render thread was actually started. if (!render_task_runner_.get()) return; if (content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)) { RunSingleProcessCleanupOnUIThread(); } else { content::BrowserThread::PostTask( content::BrowserThread::UI, FROM_HERE, base::Bind(&CefContentRendererClient::RunSingleProcessCleanupOnUIThread, base::Unretained(this))); } // Wait for the render thread cleanup to complete. Spin instead of using // base::WaitableEvent because calling Wait() is not allowed on the UI // thread. bool complete = false; do { { base::AutoLock lock_scope(single_process_cleanup_lock_); complete = single_process_cleanup_complete_; } if (!complete) base::PlatformThread::YieldCurrentThread(); } while (!complete); } void CefContentRendererClient::RenderThreadStarted() { const base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); render_task_runner_ = base::ThreadTaskRunnerHandle::Get(); observer_.reset(new CefRenderThreadObserver()); web_cache_impl_.reset(new web_cache::WebCacheImpl()); content::RenderThread* thread = content::RenderThread::Get(); thread->SetRendererProcessType( IsStandaloneExtensionProcess() ? blink::scheduler::RendererProcessType::kExtensionRenderer : blink::scheduler::RendererProcessType::kRenderer); thread->AddObserver(observer_.get()); thread->GetChannel()->AddFilter(new CefRenderMessageFilter); if (!command_line->HasSwitch(switches::kDisableSpellChecking)) { spellcheck_.reset(new SpellCheck()); thread->AddObserver(spellcheck_.get()); } if (content::RenderProcessHost::run_renderer_in_process()) { // When running in single-process mode register as a destruction observer // on the render thread's MessageLoop. base::MessageLoop::current()->AddDestructionObserver(this); } blink::WebPrerenderingSupport::Initialize(new CefPrerenderingSupport()); #if defined(OS_MACOSX) { base::ScopedCFTypeRef key( base::SysUTF8ToCFStringRef("NSScrollViewRubberbanding")); base::ScopedCFTypeRef value; // If the command-line switch is specified then set the value that will be // checked in RenderThreadImpl::Init(). Otherwise, remove the application- // level value. if (command_line->HasSwitch(switches::kDisableScrollBounce)) value.reset(base::SysUTF8ToCFStringRef("false")); CFPreferencesSetAppValue(key, value, kCFPreferencesCurrentApplication); CFPreferencesAppSynchronize(kCFPreferencesCurrentApplication); } #endif // defined(OS_MACOSX) if (extensions::PdfExtensionEnabled()) { pdf_print_client_.reset(new ChromePDFPrintClient()); pdf::PepperPDFHost::SetPrintClient(pdf_print_client_.get()); } if (extensions::ExtensionsEnabled()) extensions_renderer_client_->RenderThreadStarted(); } void CefContentRendererClient::RenderThreadConnected() { content::RenderThread* thread = content::RenderThread::Get(); // Retrieve the new render thread information synchronously. CefProcessHostMsg_GetNewRenderThreadInfo_Params params; thread->Send(new CefProcessHostMsg_GetNewRenderThreadInfo(¶ms)); // Cross-origin entries need to be added after WebKit is initialized. cross_origin_whitelist_entries_ = params.cross_origin_whitelist_entries; // Notify the render process handler. CefRefPtr application = CefContentClient::Get()->application(); if (application.get()) { CefRefPtr handler = application->GetRenderProcessHandler(); if (handler.get()) { CefRefPtr listValuePtr( new CefListValueImpl(¶ms.extra_info, false, true)); handler->OnRenderThreadCreated(listValuePtr.get()); listValuePtr->Detach(NULL); } } // Register extensions last because it will trigger WebKit initialization. thread->RegisterExtension(extensions_v8::LoadTimesExtension::Get()); WebKitInitialized(); } void CefContentRendererClient::RenderFrameCreated( content::RenderFrame* render_frame) { CefRenderFrameObserver* render_frame_observer = new CefRenderFrameObserver(render_frame); service_manager::BinderRegistry* registry = render_frame_observer->registry(); new CefPepperHelper(render_frame); new printing::PrintRenderFrameHelper( render_frame, base::WrapUnique(new extensions::CefPrintRenderFrameHelperDelegate())); if (extensions::ExtensionsEnabled()) extensions_renderer_client_->RenderFrameCreated(render_frame, registry); const base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); if (!command_line->HasSwitch(switches::kDisableSpellChecking)) new SpellCheckProvider(render_frame, spellcheck_.get()); BrowserCreated(render_frame->GetRenderView(), render_frame); } void CefContentRendererClient::RenderViewCreated( content::RenderView* render_view) { new CefPrerendererClient(render_view); if (extensions::ExtensionsEnabled()) extensions_renderer_client_->RenderViewCreated(render_view); const base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); if (!command_line->HasSwitch(switches::kDisableSpellChecking)) { // This is a workaround keeping the behavior that, the Blink side spellcheck // enabled state is initialized on RenderView creation. // TODO(xiaochengh): Design better way to sync between Chrome-side and // Blink-side spellcheck enabled states. See crbug.com/710097. if (SpellCheckProvider* provider = SpellCheckProvider::Get(render_view->GetMainRenderFrame())) { provider->EnableSpellcheck(spellcheck_->IsSpellcheckEnabled()); } } BrowserCreated(render_view, render_view->GetMainRenderFrame()); } bool CefContentRendererClient::OverrideCreatePlugin( content::RenderFrame* render_frame, const blink::WebPluginParams& params, blink::WebPlugin** plugin) { std::string orig_mime_type = params.mime_type.Utf8(); if (extensions::ExtensionsEnabled() && !extensions_renderer_client_->OverrideCreatePlugin(render_frame, params)) { return false; } GURL url(params.url); CefViewHostMsg_GetPluginInfo_Output output; render_frame->Send(new CefViewHostMsg_GetPluginInfo( render_frame->GetRoutingID(), url, render_frame->GetWebFrame()->Parent() == nullptr, render_frame->GetWebFrame()->Top()->GetSecurityOrigin(), orig_mime_type, &output)); *plugin = CreatePlugin(render_frame, params, output); return true; } bool CefContentRendererClient::HandleNavigation( content::RenderFrame* render_frame, bool is_content_initiated, bool render_view_was_created_by_renderer, blink::WebFrame* frame, const blink::WebURLRequest& request, blink::WebNavigationType type, blink::WebNavigationPolicy default_policy, bool is_redirect) { if (!frame->IsWebLocalFrame()) return false; CefRefPtr application = CefContentClient::Get()->application(); if (application.get()) { CefRefPtr handler = application->GetRenderProcessHandler(); if (handler.get()) { CefRefPtr browserPtr = CefBrowserImpl::GetBrowserForMainFrame(frame->Top()); if (browserPtr.get()) { CefRefPtr framePtr = browserPtr->GetWebFrameImpl(frame->ToWebLocalFrame()); CefRefPtr requestPtr(CefRequest::Create()); CefRequestImpl* requestImpl = static_cast(requestPtr.get()); requestImpl->Set(request); requestImpl->SetReadOnly(true); cef_navigation_type_t navigation_type = NAVIGATION_OTHER; switch (type) { case blink::kWebNavigationTypeLinkClicked: navigation_type = NAVIGATION_LINK_CLICKED; break; case blink::kWebNavigationTypeFormSubmitted: navigation_type = NAVIGATION_FORM_SUBMITTED; break; case blink::kWebNavigationTypeBackForward: navigation_type = NAVIGATION_BACK_FORWARD; break; case blink::kWebNavigationTypeReload: navigation_type = NAVIGATION_RELOAD; break; case blink::kWebNavigationTypeFormResubmitted: navigation_type = NAVIGATION_FORM_RESUBMITTED; break; case blink::kWebNavigationTypeOther: navigation_type = NAVIGATION_OTHER; break; } if (handler->OnBeforeNavigation(browserPtr.get(), framePtr.get(), requestPtr.get(), navigation_type, is_redirect)) { return true; } } } } return false; } bool CefContentRendererClient::ShouldFork(blink::WebLocalFrame* frame, const GURL& url, const std::string& http_method, bool is_initial_navigation, bool is_server_redirect, bool* send_referrer) { DCHECK(!frame->Parent()); // For now, we skip the rest for POST submissions. This is because // http://crbug.com/101395 is more likely to cause compatibility issues // with hosted apps and extensions than WebUI pages. We will remove this // check when cross-process POST submissions are supported. if (http_method != "GET") return false; if (extensions::ExtensionsEnabled()) { return extensions::CefExtensionsRendererClient::ShouldFork( frame, url, is_initial_navigation, is_server_redirect, send_referrer); } return false; } bool CefContentRendererClient::WillSendRequest( blink::WebLocalFrame* frame, ui::PageTransition transition_type, const blink::WebURL& url, std::vector>* throttles, GURL* new_url) { if (extensions::ExtensionsEnabled()) { return extensions_renderer_client_->WillSendRequest(frame, transition_type, url, new_url); } return false; } unsigned long long CefContentRendererClient::VisitedLinkHash( const char* canonical_url, size_t length) { return observer_->visited_link_slave()->ComputeURLFingerprint(canonical_url, length); } bool CefContentRendererClient::IsLinkVisited(unsigned long long link_hash) { return observer_->visited_link_slave()->IsVisited(link_hash); } content::BrowserPluginDelegate* CefContentRendererClient::CreateBrowserPluginDelegate( content::RenderFrame* render_frame, const std::string& mime_type, const GURL& original_url) { DCHECK(extensions::ExtensionsEnabled()); return extensions::CefExtensionsRendererClient::CreateBrowserPluginDelegate( render_frame, mime_type, original_url); } void CefContentRendererClient::AddSupportedKeySystems( std::vector>* key_systems) { AddCefKeySystems(key_systems); } void CefContentRendererClient::RunScriptsAtDocumentStart( content::RenderFrame* render_frame) { if (extensions::ExtensionsEnabled()) extensions_renderer_client_->RunScriptsAtDocumentStart(render_frame); } void CefContentRendererClient::RunScriptsAtDocumentEnd( content::RenderFrame* render_frame) { if (extensions::ExtensionsEnabled()) extensions_renderer_client_->RunScriptsAtDocumentEnd(render_frame); } void CefContentRendererClient::RunScriptsAtDocumentIdle( content::RenderFrame* render_frame) { if (extensions::ExtensionsEnabled()) extensions_renderer_client_->RunScriptsAtDocumentIdle(render_frame); } void CefContentRendererClient::WillDestroyCurrentMessageLoop() { base::AutoLock lock_scope(single_process_cleanup_lock_); single_process_cleanup_complete_ = true; } // static blink::WebPlugin* CefContentRendererClient::CreatePlugin( content::RenderFrame* render_frame, const blink::WebPluginParams& original_params, const CefViewHostMsg_GetPluginInfo_Output& output) { const content::WebPluginInfo& info = output.plugin; const std::string& actual_mime_type = output.actual_mime_type; const base::string16& group_name = output.group_name; const std::string& identifier = output.group_identifier; CefViewHostMsg_GetPluginInfo_Status status = output.status; GURL url(original_params.url); std::string orig_mime_type = original_params.mime_type.Utf8(); CefPluginPlaceholder* placeholder = NULL; // If the browser plugin is to be enabled, this should be handled by the // renderer, so the code won't reach here due to the early exit in // OverrideCreatePlugin. if (status == CefViewHostMsg_GetPluginInfo_Status::kNotFound || orig_mime_type == content::kBrowserPluginMimeType) { placeholder = CefPluginPlaceholder::CreateLoadableMissingPlugin( render_frame, original_params); } else { // TODO(bauerb): This should be in content/. blink::WebPluginParams params(original_params); for (const auto& mime_type : info.mime_types) { if (mime_type.mime_type == actual_mime_type) { AppendParams(mime_type.additional_param_names, mime_type.additional_param_values, ¶ms.attribute_names, ¶ms.attribute_values); break; } } if (params.mime_type.IsNull() && (actual_mime_type.size() > 0)) { // Webkit might say that mime type is null while we already know the // actual mime type via CefViewHostMsg_GetPluginInfo. In that case // we should use what we know since WebpluginDelegateProxy does some // specific initializations based on this information. params.mime_type = blink::WebString::FromUTF8(actual_mime_type); } auto create_blocked_plugin = [&render_frame, ¶ms, &info, &identifier, &group_name](int template_id, const base::string16& message) { return CefPluginPlaceholder::CreateBlockedPlugin( render_frame, params, info, identifier, group_name, template_id, message, PowerSaverInfo()); }; blink::WebLocalFrame* frame = render_frame->GetWebFrame(); switch (status) { case CefViewHostMsg_GetPluginInfo_Status::kNotFound: { NOTREACHED(); break; } case CefViewHostMsg_GetPluginInfo_Status::kAllowed: case CefViewHostMsg_GetPluginInfo_Status::kPlayImportantContent: { // Delay loading plugins if prerendering. // TODO(mmenke): In the case of prerendering, feed into // CefContentRendererClient::CreatePlugin instead, to // reduce the chance of future regressions. bool is_prerendering = false; bool power_saver_setting_on = status == CefViewHostMsg_GetPluginInfo_Status::kPlayImportantContent; PowerSaverInfo power_saver_info = PowerSaverInfo::Get(render_frame, power_saver_setting_on, params, info, frame->GetDocument().Url()); if (power_saver_info.blocked_for_background_tab || is_prerendering || !power_saver_info.poster_attribute.empty()) { placeholder = CefPluginPlaceholder::CreateBlockedPlugin( render_frame, params, info, identifier, group_name, power_saver_info.poster_attribute.empty() ? IDR_BLOCKED_PLUGIN_HTML : IDR_PLUGIN_POSTER_HTML, l10n_util::GetStringFUTF16(IDS_PLUGIN_BLOCKED, group_name), power_saver_info); placeholder->set_blocked_for_prerendering(is_prerendering); placeholder->AllowLoading(); break; } std::unique_ptr throttler; if (power_saver_info.power_saver_enabled) { throttler = content::PluginInstanceThrottler::Create( content::RenderFrame::DONT_RECORD_DECISION); // PluginPreroller manages its own lifetime. new CefPluginPreroller( render_frame, params, info, identifier, group_name, l10n_util::GetStringFUTF16(IDS_PLUGIN_BLOCKED, group_name), throttler.get()); } return render_frame->CreatePlugin(info, params, std::move(throttler)); } case CefViewHostMsg_GetPluginInfo_Status::kDisabled: { // Intentionally using the blocked plugin resources instead of the // disabled plugin resources. This provides better messaging (no link to // chrome://plugins) and adds testing support. placeholder = create_blocked_plugin( IDR_BLOCKED_PLUGIN_HTML, l10n_util::GetStringFUTF16(IDS_PLUGIN_BLOCKED_BY_POLICY, group_name)); break; } case CefViewHostMsg_GetPluginInfo_Status::kOutdatedBlocked: { NOTREACHED() << "Plugin installation is not supported."; break; } case CefViewHostMsg_GetPluginInfo_Status::kOutdatedDisallowed: { placeholder = create_blocked_plugin( IDR_BLOCKED_PLUGIN_HTML, l10n_util::GetStringFUTF16(IDS_PLUGIN_OUTDATED, group_name)); break; } case CefViewHostMsg_GetPluginInfo_Status::kUnauthorized: { placeholder = create_blocked_plugin( IDR_BLOCKED_PLUGIN_HTML, l10n_util::GetStringFUTF16(IDS_PLUGIN_NOT_AUTHORIZED, group_name)); placeholder->AllowLoading(); break; } case CefViewHostMsg_GetPluginInfo_Status::kBlocked: { placeholder = create_blocked_plugin( IDR_BLOCKED_PLUGIN_HTML, l10n_util::GetStringFUTF16(IDS_PLUGIN_BLOCKED, group_name)); placeholder->AllowLoading(); content::RenderThread::Get()->RecordAction( base::UserMetricsAction("Plugin_Blocked")); break; } case CefViewHostMsg_GetPluginInfo_Status::kBlockedByPolicy: { placeholder = create_blocked_plugin( IDR_BLOCKED_PLUGIN_HTML, l10n_util::GetStringFUTF16(IDS_PLUGIN_BLOCKED_BY_POLICY, group_name)); content::RenderThread::Get()->RecordAction( base::UserMetricsAction("Plugin_BlockedByPolicy")); break; } default: break; } } placeholder->SetStatus(status); return placeholder->plugin(); } void CefContentRendererClient::BrowserCreated( content::RenderView* render_view, content::RenderFrame* render_frame) { if (!render_view || !render_frame) return; // Swapped out RenderWidgets will be created in the parent/owner process for // frames that are hosted in a separate process (e.g. guest views or OOP // frames). Don't create any CEF objects for swapped out RenderWidgets. content::RenderFrameImpl* render_frame_impl = static_cast(render_frame); if (render_frame_impl->GetRenderWidget()->is_swapped_out()) return; // Don't create another browser or guest view object if one already exists for // the view. if (GetBrowserForView(render_view).get() || HasGuestViewForView(render_view)) return; const int render_view_routing_id = render_view->GetRoutingID(); const int render_frame_routing_id = render_frame->GetRoutingID(); // Retrieve the browser information synchronously. This will also register // the routing ids with the browser info object in the browser process. CefProcessHostMsg_GetNewBrowserInfo_Params params; content::RenderThread::Get()->Send(new CefProcessHostMsg_GetNewBrowserInfo( render_view_routing_id, render_frame_routing_id, ¶ms)); if (params.browser_id == 0) { // The popup may have been canceled during creation. return; } if (params.is_guest_view) { // Don't create a CefBrowser for guest views. guest_views_.insert(std::make_pair( render_view, base::MakeUnique(render_view))); return; } #if defined(OS_MACOSX) // FIXME: It would be better if this API would be a callback from the // WebKit layer, or if it would be exposed as an WebView instance method; the // current implementation uses a static variable, and WebKit needs to be // patched in order to make it work for each WebView instance render_view->GetWebView()->SetUseExternalPopupMenusThisInstance( !params.is_windowless); #endif CefRefPtr browser = new CefBrowserImpl( render_view, params.browser_id, params.is_popup, params.is_windowless); browsers_.insert(std::make_pair(render_view, browser)); // Notify the render process handler. CefRefPtr application = CefContentClient::Get()->application(); if (application.get()) { CefRefPtr handler = application->GetRenderProcessHandler(); if (handler.get()) handler->OnBrowserCreated(browser.get()); } } void CefContentRendererClient::RunSingleProcessCleanupOnUIThread() { DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); // Clean up the single existing RenderProcessHost. content::RenderProcessHost* host = NULL; content::RenderProcessHost::iterator iterator( content::RenderProcessHost::AllHostsIterator()); if (!iterator.IsAtEnd()) { host = iterator.GetCurrentValue(); host->Cleanup(); iterator.Advance(); DCHECK(iterator.IsAtEnd()); } DCHECK(host); // Clear the run_renderer_in_process() flag to avoid a DCHECK in the // RenderProcessHost destructor. content::RenderProcessHost::SetRunRendererInProcess(false); // Deletion of the RenderProcessHost object will stop the render thread and // result in a call to WillDestroyCurrentMessageLoop. // Cleanup() will cause deletion to be posted as a task on the UI thread but // this task will only execute when running in multi-threaded message loop // mode (because otherwise the UI message loop has already stopped). Therefore // we need to explicitly delete the object when not running in this mode. if (!CefContext::Get()->settings().multi_threaded_message_loop) delete host; } // Enable deprecation warnings for MSVC. See http://crbug.com/585142. #if defined(OS_WIN) #pragma warning(pop) #endif