1 // Copyright (c) 2013 The Chromium Embedded Framework Authors.
2 // Portions copyright (c) 2012 The Chromium Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5
6 #include "libcef/renderer/alloy/alloy_content_renderer_client.h"
7
8 #include <utility>
9
10 #include "base/compiler_specific.h"
11
12 // Enable deprecation warnings on Windows. See http://crbug.com/585142.
13 #if defined(OS_WIN)
14 #if defined(__clang__)
15 #pragma GCC diagnostic push
16 #pragma GCC diagnostic error "-Wdeprecated-declarations"
17 #else
18 #pragma warning(push)
19 #pragma warning(default : 4996)
20 #endif
21 #endif
22
23 #include "libcef/browser/alloy/alloy_content_browser_client.h"
24 #include "libcef/browser/context.h"
25 #include "libcef/common/alloy/alloy_content_client.h"
26 #include "libcef/common/app_manager.h"
27 #include "libcef/common/cef_messages.h"
28 #include "libcef/common/cef_switches.h"
29 #include "libcef/common/extensions/extensions_client.h"
30 #include "libcef/common/extensions/extensions_util.h"
31 #include "libcef/common/request_impl.h"
32 #include "libcef/features/runtime_checks.h"
33 #include "libcef/renderer/alloy/alloy_render_frame_observer.h"
34 #include "libcef/renderer/alloy/alloy_render_thread_observer.h"
35 #include "libcef/renderer/alloy/url_loader_throttle_provider_impl.h"
36 #include "libcef/renderer/browser_impl.h"
37 #include "libcef/renderer/browser_manager.h"
38 #include "libcef/renderer/extensions/extensions_renderer_client.h"
39 #include "libcef/renderer/extensions/print_render_frame_helper_delegate.h"
40 #include "libcef/renderer/thread_util.h"
41
42 #include "base/command_line.h"
43 #include "base/macros.h"
44 #include "base/memory/ptr_util.h"
45 #include "base/metrics/user_metrics_action.h"
46 #include "base/path_service.h"
47 #include "base/stl_util.h"
48 #include "base/strings/utf_string_conversions.h"
49 #include "base/task/post_task.h"
50 #include "build/build_config.h"
51 #include "chrome/common/chrome_switches.h"
52 #include "chrome/common/url_constants.h"
53 #include "chrome/renderer/browser_exposed_renderer_interfaces.h"
54 #include "chrome/renderer/chrome_content_renderer_client.h"
55 #include "chrome/renderer/extensions/chrome_extensions_renderer_client.h"
56 #include "chrome/renderer/loadtimes_extension_bindings.h"
57 #include "chrome/renderer/media/chrome_key_systems.h"
58 #include "chrome/renderer/pepper/chrome_pdf_print_client.h"
59 #include "chrome/renderer/pepper/pepper_helper.h"
60 #include "chrome/renderer/plugins/chrome_plugin_placeholder.h"
61 #include "components/content_settings/core/common/content_settings_types.h"
62 #include "components/nacl/common/nacl_constants.h"
63 #include "components/printing/renderer/print_render_frame_helper.h"
64 #include "components/spellcheck/renderer/spellcheck.h"
65 #include "components/spellcheck/renderer/spellcheck_provider.h"
66 #include "components/visitedlink/renderer/visitedlink_reader.h"
67 #include "components/web_cache/renderer/web_cache_impl.h"
68 #include "content/common/frame_messages.h"
69 #include "content/public/browser/browser_task_traits.h"
70 #include "content/public/browser/browser_thread.h"
71 #include "content/public/browser/render_process_host.h"
72 #include "content/public/child/child_thread.h"
73 #include "content/public/common/content_constants.h"
74 #include "content/public/common/content_paths.h"
75 #include "content/public/common/content_switches.h"
76 #include "content/public/common/url_constants.h"
77 #include "content/public/renderer/render_view.h"
78 #include "content/public/renderer/render_view_visitor.h"
79 #include "extensions/common/switches.h"
80 #include "extensions/renderer/guest_view/mime_handler_view/mime_handler_view_container_manager.h"
81 #include "extensions/renderer/renderer_extension_registry.h"
82 #include "ipc/ipc_sync_channel.h"
83 #include "media/base/media.h"
84 #include "mojo/public/cpp/bindings/binder_map.h"
85 #include "mojo/public/cpp/bindings/generic_pending_receiver.h"
86 #include "printing/print_settings.h"
87 #include "services/network/public/cpp/is_potentially_trustworthy.h"
88 #include "services/service_manager/public/cpp/connector.h"
89 #include "services/service_manager/public/cpp/interface_provider.h"
90 #include "third_party/blink/public/common/associated_interfaces/associated_interface_provider.h"
91 #include "third_party/blink/public/common/associated_interfaces/associated_interface_registry.h"
92 #include "third_party/blink/public/platform/scheduler/web_renderer_process_type.h"
93 #include "third_party/blink/public/platform/url_conversion.h"
94 #include "third_party/blink/public/platform/web_runtime_features.h"
95 #include "third_party/blink/public/platform/web_string.h"
96 #include "third_party/blink/public/platform/web_url.h"
97 #include "third_party/blink/public/web/web_console_message.h"
98 #include "third_party/blink/public/web/web_element.h"
99 #include "third_party/blink/public/web/web_frame.h"
100 #include "third_party/blink/public/web/web_local_frame.h"
101 #include "third_party/blink/public/web/web_security_policy.h"
102 #include "third_party/blink/public/web/web_view.h"
103 #include "third_party/blink/renderer/platform/runtime_enabled_features.h"
104 #include "ui/base/l10n/l10n_util.h"
105
106 #if defined(OS_MAC)
107 #include "base/mac/mac_util.h"
108 #include "base/strings/sys_string_conversions.h"
109 #endif
110
111 namespace {
112
IsStandaloneExtensionProcess()113 bool IsStandaloneExtensionProcess() {
114 return extensions::ExtensionsEnabled() &&
115 extensions::CefExtensionsRendererClient::
116 IsStandaloneExtensionProcess();
117 }
118
119 } // namespace
120
AlloyContentRendererClient()121 AlloyContentRendererClient::AlloyContentRendererClient()
122 : main_entry_time_(base::TimeTicks::Now()),
123 browser_manager_(new CefBrowserManager) {
124 if (extensions::ExtensionsEnabled()) {
125 extensions_client_.reset(new extensions::CefExtensionsClient);
126 extensions::ExtensionsClient::Set(extensions_client_.get());
127 extensions_renderer_client_.reset(
128 new extensions::CefExtensionsRendererClient);
129 extensions::ExtensionsRendererClient::Set(
130 extensions_renderer_client_.get());
131 }
132 }
133
~AlloyContentRendererClient()134 AlloyContentRendererClient::~AlloyContentRendererClient() {}
135
136 // static
Get()137 AlloyContentRendererClient* AlloyContentRendererClient::Get() {
138 REQUIRE_ALLOY_RUNTIME();
139 return static_cast<AlloyContentRendererClient*>(
140 CefAppManager::Get()->GetContentClient()->renderer());
141 }
142
143 scoped_refptr<base::SingleThreadTaskRunner>
GetCurrentTaskRunner()144 AlloyContentRendererClient::GetCurrentTaskRunner() {
145 // Check if currently on the render thread.
146 if (CEF_CURRENTLY_ON_RT())
147 return render_task_runner_;
148 return nullptr;
149 }
150
RunSingleProcessCleanup()151 void AlloyContentRendererClient::RunSingleProcessCleanup() {
152 DCHECK(content::RenderProcessHost::run_renderer_in_process());
153
154 // Make sure the render thread was actually started.
155 if (!render_task_runner_.get())
156 return;
157
158 if (content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)) {
159 RunSingleProcessCleanupOnUIThread();
160 } else {
161 base::PostTask(
162 FROM_HERE, {content::BrowserThread::UI},
163 base::Bind(
164 &AlloyContentRendererClient::RunSingleProcessCleanupOnUIThread,
165 base::Unretained(this)));
166 }
167
168 // Wait for the render thread cleanup to complete. Spin instead of using
169 // base::WaitableEvent because calling Wait() is not allowed on the UI
170 // thread.
171 bool complete = false;
172 do {
173 {
174 base::AutoLock lock_scope(single_process_cleanup_lock_);
175 complete = single_process_cleanup_complete_;
176 }
177 if (!complete)
178 base::PlatformThread::YieldCurrentThread();
179 } while (!complete);
180 }
181
PostIOThreadCreated(base::SingleThreadTaskRunner *)182 void AlloyContentRendererClient::PostIOThreadCreated(
183 base::SingleThreadTaskRunner*) {
184 // TODO(cef): Enable these once the implementation supports it.
185 blink::WebRuntimeFeatures::EnableNotifications(false);
186 blink::WebRuntimeFeatures::EnablePushMessaging(false);
187 blink::RuntimeEnabledFeatures::SetBadgingEnabled(false);
188 }
189
RenderThreadStarted()190 void AlloyContentRendererClient::RenderThreadStarted() {
191 const base::CommandLine* command_line =
192 base::CommandLine::ForCurrentProcess();
193
194 render_task_runner_ = base::ThreadTaskRunnerHandle::Get();
195 observer_ = std::make_unique<AlloyRenderThreadObserver>();
196 web_cache_impl_ = std::make_unique<web_cache::WebCacheImpl>();
197 visited_link_slave_ = std::make_unique<visitedlink::VisitedLinkReader>();
198
199 content::RenderThread* thread = content::RenderThread::Get();
200
201 thread->SetRendererProcessType(
202 IsStandaloneExtensionProcess()
203 ? blink::scheduler::WebRendererProcessType::kExtensionRenderer
204 : blink::scheduler::WebRendererProcessType::kRenderer);
205
206 thread->AddObserver(observer_.get());
207
208 if (!command_line->HasSwitch(switches::kDisableSpellChecking)) {
209 spellcheck_ = std::make_unique<SpellCheck>(this);
210 }
211
212 if (content::RenderProcessHost::run_renderer_in_process()) {
213 // When running in single-process mode register as a destruction observer
214 // on the render thread's MessageLoop.
215 base::CurrentThread::Get()->AddDestructionObserver(this);
216 }
217
218 #if defined(OS_MAC)
219 {
220 base::ScopedCFTypeRef<CFStringRef> key(
221 base::SysUTF8ToCFStringRef("NSScrollViewRubberbanding"));
222 base::ScopedCFTypeRef<CFStringRef> value;
223
224 // If the command-line switch is specified then set the value that will be
225 // checked in RenderThreadImpl::Init(). Otherwise, remove the application-
226 // level value.
227 if (command_line->HasSwitch(switches::kDisableScrollBounce))
228 value.reset(base::SysUTF8ToCFStringRef("false"));
229
230 CFPreferencesSetAppValue(key, value, kCFPreferencesCurrentApplication);
231 CFPreferencesAppSynchronize(kCFPreferencesCurrentApplication);
232 }
233 #endif // defined(OS_MAC)
234
235 if (extensions::PdfExtensionEnabled()) {
236 pdf_print_client_.reset(new ChromePDFPrintClient());
237 pdf::PepperPDFHost::SetPrintClient(pdf_print_client_.get());
238 }
239
240 if (extensions::ExtensionsEnabled())
241 extensions_renderer_client_->RenderThreadStarted();
242 }
243
ExposeInterfacesToBrowser(mojo::BinderMap * binders)244 void AlloyContentRendererClient::ExposeInterfacesToBrowser(
245 mojo::BinderMap* binders) {
246 auto task_runner = base::SequencedTaskRunnerHandle::Get();
247
248 binders->Add(base::BindRepeating(&web_cache::WebCacheImpl::BindReceiver,
249 base::Unretained(web_cache_impl_.get())),
250 task_runner);
251
252 binders->Add(visited_link_slave_->GetBindCallback(), task_runner);
253
254 if (spellcheck_) {
255 binders->Add(
256 base::BindRepeating(
257 [](SpellCheck* spellcheck,
258 mojo::PendingReceiver<spellcheck::mojom::SpellChecker>
259 receiver) { spellcheck->BindReceiver(std::move(receiver)); },
260 base::Unretained(spellcheck_.get())),
261 task_runner);
262 }
263 }
264
RenderThreadConnected()265 void AlloyContentRendererClient::RenderThreadConnected() {
266 // Register extensions last because it will trigger WebKit initialization.
267 content::RenderThread* thread = content::RenderThread::Get();
268 thread->RegisterExtension(extensions_v8::LoadTimesExtension::Get());
269
270 browser_manager_->RenderThreadConnected();
271 }
272
RenderFrameCreated(content::RenderFrame * render_frame)273 void AlloyContentRendererClient::RenderFrameCreated(
274 content::RenderFrame* render_frame) {
275 AlloyRenderFrameObserver* render_frame_observer =
276 new AlloyRenderFrameObserver(render_frame);
277 service_manager::BinderRegistry* registry = render_frame_observer->registry();
278
279 new PepperHelper(render_frame);
280
281 if (extensions::ExtensionsEnabled()) {
282 extensions_renderer_client_->RenderFrameCreated(render_frame, registry);
283
284 blink::AssociatedInterfaceRegistry* associated_interfaces =
285 render_frame_observer->associated_interfaces();
286 associated_interfaces->AddInterface(base::BindRepeating(
287 &extensions::MimeHandlerViewContainerManager::BindReceiver,
288 render_frame->GetRoutingID()));
289 }
290
291 const base::CommandLine* command_line =
292 base::CommandLine::ForCurrentProcess();
293 if (!command_line->HasSwitch(switches::kDisableSpellChecking)) {
294 new SpellCheckProvider(render_frame, spellcheck_.get(), this);
295 }
296
297 bool browser_created;
298 base::Optional<bool> is_windowless;
299 browser_manager_->RenderFrameCreated(render_frame, render_frame_observer,
300 browser_created, is_windowless);
301 if (browser_created) {
302 OnBrowserCreated(render_frame->GetRenderView(), is_windowless);
303 }
304
305 if (is_windowless.has_value()) {
306 new printing::PrintRenderFrameHelper(
307 render_frame,
308 base::WrapUnique(
309 new extensions::CefPrintRenderFrameHelperDelegate(*is_windowless)));
310 }
311 }
312
RenderViewCreated(content::RenderView * render_view)313 void AlloyContentRendererClient::RenderViewCreated(
314 content::RenderView* render_view) {
315 bool browser_created;
316 base::Optional<bool> is_windowless;
317 browser_manager_->RenderViewCreated(render_view, browser_created,
318 is_windowless);
319 if (browser_created) {
320 OnBrowserCreated(render_view, is_windowless);
321 }
322 }
323
IsPluginHandledExternally(content::RenderFrame * render_frame,const blink::WebElement & plugin_element,const GURL & original_url,const std::string & mime_type)324 bool AlloyContentRendererClient::IsPluginHandledExternally(
325 content::RenderFrame* render_frame,
326 const blink::WebElement& plugin_element,
327 const GURL& original_url,
328 const std::string& mime_type) {
329 if (!extensions::ExtensionsEnabled())
330 return false;
331
332 DCHECK(plugin_element.HasHTMLTagName("object") ||
333 plugin_element.HasHTMLTagName("embed"));
334 // Blink will next try to load a WebPlugin which would end up in
335 // OverrideCreatePlugin, sending another IPC only to find out the plugin is
336 // not supported. Here it suffices to return false but there should perhaps be
337 // a more unified approach to avoid sending the IPC twice.
338 chrome::mojom::PluginInfoPtr plugin_info = chrome::mojom::PluginInfo::New();
339 ChromeContentRendererClient::GetPluginInfoHost()->GetPluginInfo(
340 render_frame->GetRoutingID(), original_url,
341 render_frame->GetWebFrame()->Top()->GetSecurityOrigin(), mime_type,
342 &plugin_info);
343 // TODO(ekaramad): Not continuing here due to a disallowed status should take
344 // us to CreatePlugin. See if more in depths investigation of |status| is
345 // necessary here (see https://crbug.com/965747). For now, returning false
346 // should take us to CreatePlugin after HTMLPlugInElement which is called
347 // through HTMLPlugInElement::LoadPlugin code path.
348 if (plugin_info->status != chrome::mojom::PluginStatus::kAllowed &&
349 plugin_info->status !=
350 chrome::mojom::PluginStatus::kPlayImportantContent) {
351 // We could get here when a MimeHandlerView is loaded inside a <webview>
352 // which is using permissions API (see WebViewPluginTests).
353 ChromeExtensionsRendererClient::DidBlockMimeHandlerViewForDisallowedPlugin(
354 plugin_element);
355 return false;
356 }
357 return ChromeExtensionsRendererClient::MaybeCreateMimeHandlerView(
358 plugin_element, original_url, plugin_info->actual_mime_type,
359 plugin_info->plugin);
360 }
361
OverrideCreatePlugin(content::RenderFrame * render_frame,const blink::WebPluginParams & params,blink::WebPlugin ** plugin)362 bool AlloyContentRendererClient::OverrideCreatePlugin(
363 content::RenderFrame* render_frame,
364 const blink::WebPluginParams& params,
365 blink::WebPlugin** plugin) {
366 std::string orig_mime_type = params.mime_type.Utf8();
367 if (extensions::ExtensionsEnabled() &&
368 !extensions_renderer_client_->OverrideCreatePlugin(render_frame,
369 params)) {
370 return false;
371 }
372
373 GURL url(params.url);
374 chrome::mojom::PluginInfoPtr plugin_info = chrome::mojom::PluginInfo::New();
375 ChromeContentRendererClient::GetPluginInfoHost()->GetPluginInfo(
376 render_frame->GetRoutingID(), url,
377 render_frame->GetWebFrame()->Top()->GetSecurityOrigin(), orig_mime_type,
378 &plugin_info);
379 *plugin = ChromeContentRendererClient::CreatePlugin(render_frame, params,
380 *plugin_info);
381 return true;
382 }
383
WillSendRequest(blink::WebLocalFrame * frame,ui::PageTransition transition_type,const blink::WebURL & url,const net::SiteForCookies & site_for_cookies,const url::Origin * initiator_origin,GURL * new_url)384 void AlloyContentRendererClient::WillSendRequest(
385 blink::WebLocalFrame* frame,
386 ui::PageTransition transition_type,
387 const blink::WebURL& url,
388 const net::SiteForCookies& site_for_cookies,
389 const url::Origin* initiator_origin,
390 GURL* new_url) {
391 if (extensions::ExtensionsEnabled()) {
392 extensions_renderer_client_->WillSendRequest(frame, transition_type, url,
393 site_for_cookies,
394 initiator_origin, new_url);
395 if (!new_url->is_empty())
396 return;
397 }
398 }
399
VisitedLinkHash(const char * canonical_url,size_t length)400 uint64_t AlloyContentRendererClient::VisitedLinkHash(const char* canonical_url,
401 size_t length) {
402 return visited_link_slave_->ComputeURLFingerprint(canonical_url, length);
403 }
404
IsLinkVisited(uint64_t link_hash)405 bool AlloyContentRendererClient::IsLinkVisited(uint64_t link_hash) {
406 return visited_link_slave_->IsVisited(link_hash);
407 }
408
IsOriginIsolatedPepperPlugin(const base::FilePath & plugin_path)409 bool AlloyContentRendererClient::IsOriginIsolatedPepperPlugin(
410 const base::FilePath& plugin_path) {
411 // Isolate all the plugins (including the PDF plugin).
412 return true;
413 }
414
AddSupportedKeySystems(std::vector<std::unique_ptr<::media::KeySystemProperties>> * key_systems)415 void AlloyContentRendererClient::AddSupportedKeySystems(
416 std::vector<std::unique_ptr<::media::KeySystemProperties>>* key_systems) {
417 AddChromeKeySystems(key_systems);
418 }
419
RunScriptsAtDocumentStart(content::RenderFrame * render_frame)420 void AlloyContentRendererClient::RunScriptsAtDocumentStart(
421 content::RenderFrame* render_frame) {
422 if (extensions::ExtensionsEnabled())
423 extensions_renderer_client_->RunScriptsAtDocumentStart(render_frame);
424 }
425
RunScriptsAtDocumentEnd(content::RenderFrame * render_frame)426 void AlloyContentRendererClient::RunScriptsAtDocumentEnd(
427 content::RenderFrame* render_frame) {
428 if (extensions::ExtensionsEnabled())
429 extensions_renderer_client_->RunScriptsAtDocumentEnd(render_frame);
430 }
431
RunScriptsAtDocumentIdle(content::RenderFrame * render_frame)432 void AlloyContentRendererClient::RunScriptsAtDocumentIdle(
433 content::RenderFrame* render_frame) {
434 if (extensions::ExtensionsEnabled())
435 extensions_renderer_client_->RunScriptsAtDocumentIdle(render_frame);
436 }
437
DevToolsAgentAttached()438 void AlloyContentRendererClient::DevToolsAgentAttached() {
439 // WebWorkers may be creating agents on a different thread.
440 if (!render_task_runner_->BelongsToCurrentThread()) {
441 render_task_runner_->PostTask(
442 FROM_HERE,
443 base::BindOnce(&AlloyContentRendererClient::DevToolsAgentAttached,
444 base::Unretained(this)));
445 return;
446 }
447
448 browser_manager_->DevToolsAgentAttached();
449 }
450
DevToolsAgentDetached()451 void AlloyContentRendererClient::DevToolsAgentDetached() {
452 // WebWorkers may be creating agents on a different thread.
453 if (!render_task_runner_->BelongsToCurrentThread()) {
454 render_task_runner_->PostTask(
455 FROM_HERE,
456 base::BindOnce(&AlloyContentRendererClient::DevToolsAgentDetached,
457 base::Unretained(this)));
458 return;
459 }
460
461 browser_manager_->DevToolsAgentDetached();
462 }
463
464 std::unique_ptr<blink::URLLoaderThrottleProvider>
CreateURLLoaderThrottleProvider(blink::URLLoaderThrottleProviderType provider_type)465 AlloyContentRendererClient::CreateURLLoaderThrottleProvider(
466 blink::URLLoaderThrottleProviderType provider_type) {
467 return std::make_unique<CefURLLoaderThrottleProviderImpl>(provider_type);
468 }
469
GetInterface(const std::string & interface_name,mojo::ScopedMessagePipeHandle interface_pipe)470 void AlloyContentRendererClient::GetInterface(
471 const std::string& interface_name,
472 mojo::ScopedMessagePipeHandle interface_pipe) {
473 // TODO(crbug.com/977637): Get rid of the use of this implementation of
474 // |service_manager::LocalInterfaceProvider|. This was done only to avoid
475 // churning spellcheck code while eliminating the "chrome" and
476 // "chrome_renderer" services. Spellcheck is (and should remain) the only
477 // consumer of this implementation.
478 content::RenderThread::Get()->BindHostReceiver(
479 mojo::GenericPendingReceiver(interface_name, std::move(interface_pipe)));
480 }
481
WillDestroyCurrentMessageLoop()482 void AlloyContentRendererClient::WillDestroyCurrentMessageLoop() {
483 base::AutoLock lock_scope(single_process_cleanup_lock_);
484 single_process_cleanup_complete_ = true;
485 }
486
OnBrowserCreated(content::RenderView * render_view,base::Optional<bool> is_windowless)487 void AlloyContentRendererClient::OnBrowserCreated(
488 content::RenderView* render_view,
489 base::Optional<bool> is_windowless) {
490 #if defined(OS_MAC)
491 const bool windowless = is_windowless.has_value() && *is_windowless;
492
493 // FIXME: It would be better if this API would be a callback from the
494 // WebKit layer, or if it would be exposed as an WebView instance method; the
495 // current implementation uses a static variable, and WebKit needs to be
496 // patched in order to make it work for each WebView instance
497 render_view->GetWebView()->SetUseExternalPopupMenusThisInstance(!windowless);
498 #endif
499 }
500
RunSingleProcessCleanupOnUIThread()501 void AlloyContentRendererClient::RunSingleProcessCleanupOnUIThread() {
502 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
503
504 // Clean up the single existing RenderProcessHost.
505 content::RenderProcessHost* host = nullptr;
506 content::RenderProcessHost::iterator iterator(
507 content::RenderProcessHost::AllHostsIterator());
508 if (!iterator.IsAtEnd()) {
509 host = iterator.GetCurrentValue();
510 host->Cleanup();
511 iterator.Advance();
512 DCHECK(iterator.IsAtEnd());
513 }
514 DCHECK(host);
515
516 // Clear the run_renderer_in_process() flag to avoid a DCHECK in the
517 // RenderProcessHost destructor.
518 content::RenderProcessHost::SetRunRendererInProcess(false);
519
520 // Deletion of the RenderProcessHost object will stop the render thread and
521 // result in a call to WillDestroyCurrentMessageLoop.
522 // Cleanup() will cause deletion to be posted as a task on the UI thread but
523 // this task will only execute when running in multi-threaded message loop
524 // mode (because otherwise the UI message loop has already stopped). Therefore
525 // we need to explicitly delete the object when not running in this mode.
526 if (!CefContext::Get()->settings().multi_threaded_message_loop)
527 delete host;
528 }
529
530 // Enable deprecation warnings on Windows. See http://crbug.com/585142.
531 #if defined(OS_WIN)
532 #if defined(__clang__)
533 #pragma GCC diagnostic pop
534 #else
535 #pragma warning(pop)
536 #endif
537 #endif
538