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 "content/renderer/renderer_webkitplatformsupport_impl.h" 6 7 #include "base/command_line.h" 8 #include "base/files/file_path.h" 9 #include "base/lazy_instance.h" 10 #include "base/logging.h" 11 #include "base/memory/shared_memory.h" 12 #include "base/message_loop/message_loop_proxy.h" 13 #include "base/metrics/histogram.h" 14 #include "base/numerics/safe_conversions.h" 15 #include "base/strings/string_number_conversions.h" 16 #include "base/strings/utf_string_conversions.h" 17 #include "content/child/database_util.h" 18 #include "content/child/file_info_util.h" 19 #include "content/child/fileapi/webfilesystem_impl.h" 20 #include "content/child/indexed_db/webidbfactory_impl.h" 21 #include "content/child/npapi/npobject_util.h" 22 #include "content/child/quota_dispatcher.h" 23 #include "content/child/quota_message_filter.h" 24 #include "content/child/simple_webmimeregistry_impl.h" 25 #include "content/child/thread_safe_sender.h" 26 #include "content/child/web_database_observer_impl.h" 27 #include "content/child/webblobregistry_impl.h" 28 #include "content/child/webfileutilities_impl.h" 29 #include "content/child/webmessageportchannel_impl.h" 30 #include "content/common/file_utilities_messages.h" 31 #include "content/common/gpu/client/context_provider_command_buffer.h" 32 #include "content/common/gpu/client/gpu_channel_host.h" 33 #include "content/common/gpu/client/webgraphicscontext3d_command_buffer_impl.h" 34 #include "content/common/gpu/gpu_process_launch_causes.h" 35 #include "content/common/mime_registry_messages.h" 36 #include "content/common/view_messages.h" 37 #include "content/public/common/content_switches.h" 38 #include "content/public/common/webplugininfo.h" 39 #include "content/public/renderer/content_renderer_client.h" 40 #include "content/renderer/battery_status/battery_status_dispatcher.h" 41 #include "content/renderer/device_sensors/device_light_event_pump.h" 42 #include "content/renderer/device_sensors/device_motion_event_pump.h" 43 #include "content/renderer/device_sensors/device_orientation_event_pump.h" 44 #include "content/renderer/dom_storage/webstoragenamespace_impl.h" 45 #include "content/renderer/gamepad_shared_memory_reader.h" 46 #include "content/renderer/media/audio_decoder.h" 47 #include "content/renderer/media/crypto/key_systems.h" 48 #include "content/renderer/media/renderer_webaudiodevice_impl.h" 49 #include "content/renderer/media/renderer_webmidiaccessor_impl.h" 50 #include "content/renderer/media/webcontentdecryptionmodule_impl.h" 51 #include "content/renderer/render_thread_impl.h" 52 #include "content/renderer/renderer_clipboard_client.h" 53 #include "content/renderer/screen_orientation/screen_orientation_observer.h" 54 #include "content/renderer/webclipboard_impl.h" 55 #include "content/renderer/webgraphicscontext3d_provider_impl.h" 56 #include "content/renderer/webpublicsuffixlist_impl.h" 57 #include "gpu/config/gpu_info.h" 58 #include "ipc/ipc_sync_message_filter.h" 59 #include "media/audio/audio_output_device.h" 60 #include "media/base/audio_hardware_config.h" 61 #include "media/filters/stream_parser_factory.h" 62 #include "net/base/mime_util.h" 63 #include "net/base/net_util.h" 64 #include "storage/common/quota/quota_types.h" 65 #include "third_party/WebKit/public/platform/WebBatteryStatusListener.h" 66 #include "third_party/WebKit/public/platform/WebBlobRegistry.h" 67 #include "third_party/WebKit/public/platform/WebDeviceLightListener.h" 68 #include "third_party/WebKit/public/platform/WebDeviceMotionListener.h" 69 #include "third_party/WebKit/public/platform/WebDeviceOrientationListener.h" 70 #include "third_party/WebKit/public/platform/WebFileInfo.h" 71 #include "third_party/WebKit/public/platform/WebGamepads.h" 72 #include "third_party/WebKit/public/platform/WebMediaStreamCenter.h" 73 #include "third_party/WebKit/public/platform/WebMediaStreamCenterClient.h" 74 #include "third_party/WebKit/public/platform/WebPluginListBuilder.h" 75 #include "third_party/WebKit/public/platform/WebURL.h" 76 #include "third_party/WebKit/public/platform/WebVector.h" 77 #include "ui/gfx/color_profile.h" 78 #include "url/gurl.h" 79 #include "webkit/common/gpu/context_provider_web_context.h" 80 81 #if defined(OS_ANDROID) 82 #include "content/renderer/android/synchronous_compositor_factory.h" 83 #include "content/renderer/media/android/audio_decoder_android.h" 84 #endif 85 86 #if defined(OS_MACOSX) 87 #include "content/common/mac/font_descriptor.h" 88 #include "content/common/mac/font_loader.h" 89 #include "content/renderer/webscrollbarbehavior_impl_mac.h" 90 #include "third_party/WebKit/public/platform/mac/WebSandboxSupport.h" 91 #endif 92 93 #if defined(OS_POSIX) 94 #include "base/file_descriptor_posix.h" 95 #if !defined(OS_MACOSX) && !defined(OS_ANDROID) 96 #include <map> 97 #include <string> 98 99 #include "base/synchronization/lock.h" 100 #include "content/common/child_process_sandbox_support_impl_linux.h" 101 #include "third_party/WebKit/public/platform/linux/WebFallbackFont.h" 102 #include "third_party/WebKit/public/platform/linux/WebSandboxSupport.h" 103 #include "third_party/icu/source/common/unicode/utf16.h" 104 #endif 105 #endif 106 107 #if defined(OS_WIN) 108 #include "content/common/child_process_messages.h" 109 #include "third_party/WebKit/public/platform/win/WebSandboxSupport.h" 110 #endif 111 112 #if defined(USE_AURA) 113 #include "content/renderer/webscrollbarbehavior_impl_gtkoraura.h" 114 #elif !defined(OS_MACOSX) 115 #include "third_party/WebKit/public/platform/WebScrollbarBehavior.h" 116 #define WebScrollbarBehaviorImpl blink::WebScrollbarBehavior 117 #endif 118 119 #if defined(ENABLE_WEBRTC) 120 #include "content/renderer/media/webrtc/peer_connection_dependency_factory.h" 121 #endif 122 123 using blink::Platform; 124 using blink::WebAudioDevice; 125 using blink::WebBlobRegistry; 126 using blink::WebDatabaseObserver; 127 using blink::WebFileInfo; 128 using blink::WebFileSystem; 129 using blink::WebGamepad; 130 using blink::WebGamepads; 131 using blink::WebIDBFactory; 132 using blink::WebMIDIAccessor; 133 using blink::WebMediaStreamCenter; 134 using blink::WebMediaStreamCenterClient; 135 using blink::WebMimeRegistry; 136 using blink::WebRTCPeerConnectionHandler; 137 using blink::WebRTCPeerConnectionHandlerClient; 138 using blink::WebStorageNamespace; 139 using blink::WebString; 140 using blink::WebURL; 141 using blink::WebVector; 142 143 namespace content { 144 145 namespace { 146 147 bool g_sandbox_enabled = true; 148 double g_test_device_light_data = -1; 149 base::LazyInstance<blink::WebDeviceMotionData>::Leaky 150 g_test_device_motion_data = LAZY_INSTANCE_INITIALIZER; 151 base::LazyInstance<blink::WebDeviceOrientationData>::Leaky 152 g_test_device_orientation_data = LAZY_INSTANCE_INITIALIZER; 153 154 } // namespace 155 156 //------------------------------------------------------------------------------ 157 158 class RendererWebKitPlatformSupportImpl::MimeRegistry 159 : public SimpleWebMimeRegistryImpl { 160 public: 161 virtual blink::WebMimeRegistry::SupportsType supportsMediaMIMEType( 162 const blink::WebString& mime_type, 163 const blink::WebString& codecs, 164 const blink::WebString& key_system); 165 virtual bool supportsMediaSourceMIMEType(const blink::WebString& mime_type, 166 const blink::WebString& codecs); 167 virtual bool supportsEncryptedMediaMIMEType(const WebString& key_system, 168 const WebString& mime_type, 169 const WebString& codecs) OVERRIDE; 170 virtual blink::WebString mimeTypeForExtension( 171 const blink::WebString& file_extension); 172 virtual blink::WebString mimeTypeFromFile( 173 const blink::WebString& file_path); 174 }; 175 176 class RendererWebKitPlatformSupportImpl::FileUtilities 177 : public WebFileUtilitiesImpl { 178 public: 179 explicit FileUtilities(ThreadSafeSender* sender) 180 : thread_safe_sender_(sender) {} 181 virtual bool getFileInfo(const WebString& path, WebFileInfo& result); 182 private: 183 bool SendSyncMessageFromAnyThread(IPC::SyncMessage* msg) const; 184 scoped_refptr<ThreadSafeSender> thread_safe_sender_; 185 }; 186 187 #if defined(OS_ANDROID) 188 // WebKit doesn't use WebSandboxSupport on android so we don't need to 189 // implement anything here. 190 class RendererWebKitPlatformSupportImpl::SandboxSupport { 191 }; 192 #else 193 class RendererWebKitPlatformSupportImpl::SandboxSupport 194 : public blink::WebSandboxSupport { 195 public: 196 virtual ~SandboxSupport() {} 197 198 #if defined(OS_WIN) 199 virtual bool ensureFontLoaded(HFONT); 200 #elif defined(OS_MACOSX) 201 virtual bool loadFont( 202 NSFont* src_font, 203 CGFontRef* container, 204 uint32* font_id); 205 #elif defined(OS_POSIX) 206 virtual void getFallbackFontForCharacter( 207 blink::WebUChar32 character, 208 const char* preferred_locale, 209 blink::WebFallbackFont* fallbackFont); 210 virtual void getRenderStyleForStrike( 211 const char* family, int sizeAndStyle, blink::WebFontRenderStyle* out); 212 213 private: 214 // WebKit likes to ask us for the correct font family to use for a set of 215 // unicode code points. It needs this information frequently so we cache it 216 // here. 217 base::Lock unicode_font_families_mutex_; 218 std::map<int32_t, blink::WebFallbackFont> unicode_font_families_; 219 #endif 220 }; 221 #endif // defined(OS_ANDROID) 222 223 //------------------------------------------------------------------------------ 224 225 RendererWebKitPlatformSupportImpl::RendererWebKitPlatformSupportImpl() 226 : clipboard_client_(new RendererClipboardClient), 227 clipboard_(new WebClipboardImpl(clipboard_client_.get())), 228 mime_registry_(new RendererWebKitPlatformSupportImpl::MimeRegistry), 229 sudden_termination_disables_(0), 230 plugin_refresh_allowed_(true), 231 child_thread_loop_(base::MessageLoopProxy::current()), 232 web_scrollbar_behavior_(new WebScrollbarBehaviorImpl) { 233 if (g_sandbox_enabled && sandboxEnabled()) { 234 sandbox_support_.reset( 235 new RendererWebKitPlatformSupportImpl::SandboxSupport); 236 } else { 237 DVLOG(1) << "Disabling sandbox support for testing."; 238 } 239 240 // ChildThread may not exist in some tests. 241 if (ChildThread::current()) { 242 sync_message_filter_ = ChildThread::current()->sync_message_filter(); 243 thread_safe_sender_ = ChildThread::current()->thread_safe_sender(); 244 quota_message_filter_ = ChildThread::current()->quota_message_filter(); 245 blob_registry_.reset(new WebBlobRegistryImpl(thread_safe_sender_.get())); 246 web_idb_factory_.reset(new WebIDBFactoryImpl(thread_safe_sender_.get())); 247 web_database_observer_impl_.reset( 248 new WebDatabaseObserverImpl(sync_message_filter_.get())); 249 } 250 } 251 252 RendererWebKitPlatformSupportImpl::~RendererWebKitPlatformSupportImpl() { 253 WebFileSystemImpl::DeleteThreadSpecificInstance(); 254 } 255 256 //------------------------------------------------------------------------------ 257 258 blink::WebClipboard* RendererWebKitPlatformSupportImpl::clipboard() { 259 blink::WebClipboard* clipboard = 260 GetContentClient()->renderer()->OverrideWebClipboard(); 261 if (clipboard) 262 return clipboard; 263 return clipboard_.get(); 264 } 265 266 blink::WebMimeRegistry* RendererWebKitPlatformSupportImpl::mimeRegistry() { 267 return mime_registry_.get(); 268 } 269 270 blink::WebFileUtilities* 271 RendererWebKitPlatformSupportImpl::fileUtilities() { 272 if (!file_utilities_) { 273 file_utilities_.reset(new FileUtilities(thread_safe_sender_.get())); 274 file_utilities_->set_sandbox_enabled(sandboxEnabled()); 275 } 276 return file_utilities_.get(); 277 } 278 279 blink::WebSandboxSupport* RendererWebKitPlatformSupportImpl::sandboxSupport() { 280 #if defined(OS_ANDROID) 281 // WebKit doesn't use WebSandboxSupport on android. 282 return NULL; 283 #else 284 return sandbox_support_.get(); 285 #endif 286 } 287 288 blink::WebCookieJar* RendererWebKitPlatformSupportImpl::cookieJar() { 289 NOTREACHED() << "Use WebFrameClient::cookieJar() instead!"; 290 return NULL; 291 } 292 293 blink::WebThemeEngine* RendererWebKitPlatformSupportImpl::themeEngine() { 294 blink::WebThemeEngine* theme_engine = 295 GetContentClient()->renderer()->OverrideThemeEngine(); 296 if (theme_engine) 297 return theme_engine; 298 return BlinkPlatformImpl::themeEngine(); 299 } 300 301 bool RendererWebKitPlatformSupportImpl::sandboxEnabled() { 302 // As explained in Platform.h, this function is used to decide 303 // whether to allow file system operations to come out of WebKit or not. 304 // Even if the sandbox is disabled, there's no reason why the code should 305 // act any differently...unless we're in single process mode. In which 306 // case, we have no other choice. Platform.h discourages using 307 // this switch unless absolutely necessary, so hopefully we won't end up 308 // with too many code paths being different in single-process mode. 309 return !CommandLine::ForCurrentProcess()->HasSwitch(switches::kSingleProcess); 310 } 311 312 unsigned long long RendererWebKitPlatformSupportImpl::visitedLinkHash( 313 const char* canonical_url, 314 size_t length) { 315 return GetContentClient()->renderer()->VisitedLinkHash(canonical_url, length); 316 } 317 318 bool RendererWebKitPlatformSupportImpl::isLinkVisited( 319 unsigned long long link_hash) { 320 return GetContentClient()->renderer()->IsLinkVisited(link_hash); 321 } 322 323 void RendererWebKitPlatformSupportImpl::createMessageChannel( 324 blink::WebMessagePortChannel** channel1, 325 blink::WebMessagePortChannel** channel2) { 326 WebMessagePortChannelImpl::CreatePair( 327 child_thread_loop_.get(), channel1, channel2); 328 } 329 330 blink::WebPrescientNetworking* 331 RendererWebKitPlatformSupportImpl::prescientNetworking() { 332 return GetContentClient()->renderer()->GetPrescientNetworking(); 333 } 334 335 void RendererWebKitPlatformSupportImpl::cacheMetadata( 336 const blink::WebURL& url, 337 double response_time, 338 const char* data, 339 size_t size) { 340 // Let the browser know we generated cacheable metadata for this resource. The 341 // browser may cache it and return it on subsequent responses to speed 342 // the processing of this resource. 343 std::vector<char> copy(data, data + size); 344 RenderThread::Get()->Send( 345 new ViewHostMsg_DidGenerateCacheableMetadata(url, response_time, copy)); 346 } 347 348 WebString RendererWebKitPlatformSupportImpl::defaultLocale() { 349 return base::ASCIIToUTF16(RenderThread::Get()->GetLocale()); 350 } 351 352 void RendererWebKitPlatformSupportImpl::suddenTerminationChanged(bool enabled) { 353 if (enabled) { 354 // We should not get more enables than disables, but we want it to be a 355 // non-fatal error if it does happen. 356 DCHECK_GT(sudden_termination_disables_, 0); 357 sudden_termination_disables_ = std::max(sudden_termination_disables_ - 1, 358 0); 359 if (sudden_termination_disables_ != 0) 360 return; 361 } else { 362 sudden_termination_disables_++; 363 if (sudden_termination_disables_ != 1) 364 return; 365 } 366 367 RenderThread* thread = RenderThread::Get(); 368 if (thread) // NULL in unittests. 369 thread->Send(new ViewHostMsg_SuddenTerminationChanged(enabled)); 370 } 371 372 WebStorageNamespace* 373 RendererWebKitPlatformSupportImpl::createLocalStorageNamespace() { 374 return new WebStorageNamespaceImpl(); 375 } 376 377 378 //------------------------------------------------------------------------------ 379 380 WebIDBFactory* RendererWebKitPlatformSupportImpl::idbFactory() { 381 return web_idb_factory_.get(); 382 } 383 384 //------------------------------------------------------------------------------ 385 386 WebFileSystem* RendererWebKitPlatformSupportImpl::fileSystem() { 387 return WebFileSystemImpl::ThreadSpecificInstance(child_thread_loop_.get()); 388 } 389 390 //------------------------------------------------------------------------------ 391 392 WebMimeRegistry::SupportsType 393 RendererWebKitPlatformSupportImpl::MimeRegistry::supportsMediaMIMEType( 394 const WebString& mime_type, 395 const WebString& codecs, 396 const WebString& key_system) { 397 const std::string mime_type_ascii = ToASCIIOrEmpty(mime_type); 398 // Not supporting the container is a flat-out no. 399 if (!net::IsSupportedMediaMimeType(mime_type_ascii)) 400 return IsNotSupported; 401 402 if (!key_system.isEmpty()) { 403 // Check whether the key system is supported with the mime_type and codecs. 404 405 // Chromium only supports ASCII parameters. 406 if (!base::IsStringASCII(key_system)) 407 return IsNotSupported; 408 409 std::string key_system_ascii = 410 GetUnprefixedKeySystemName(base::UTF16ToASCII(key_system)); 411 std::vector<std::string> strict_codecs; 412 net::ParseCodecString(ToASCIIOrEmpty(codecs), &strict_codecs, true); 413 414 if (!IsSupportedKeySystemWithMediaMimeType( 415 mime_type_ascii, strict_codecs, key_system_ascii)) { 416 return IsNotSupported; 417 } 418 419 // Continue processing the mime_type and codecs. 420 } 421 422 // Check list of strict codecs to see if it is supported. 423 if (net::IsStrictMediaMimeType(mime_type_ascii)) { 424 // Check if the codecs are a perfect match. 425 std::vector<std::string> strict_codecs; 426 net::ParseCodecString(ToASCIIOrEmpty(codecs), &strict_codecs, false); 427 return static_cast<WebMimeRegistry::SupportsType> ( 428 net::IsSupportedStrictMediaMimeType(mime_type_ascii, strict_codecs)); 429 } 430 431 // If we don't recognize the codec, it's possible we support it. 432 std::vector<std::string> parsed_codecs; 433 net::ParseCodecString(ToASCIIOrEmpty(codecs), &parsed_codecs, true); 434 if (!net::AreSupportedMediaCodecs(parsed_codecs)) 435 return MayBeSupported; 436 437 // Otherwise we have a perfect match. 438 return IsSupported; 439 } 440 441 bool 442 RendererWebKitPlatformSupportImpl::MimeRegistry::supportsMediaSourceMIMEType( 443 const blink::WebString& mime_type, 444 const WebString& codecs) { 445 const std::string mime_type_ascii = ToASCIIOrEmpty(mime_type); 446 std::vector<std::string> parsed_codec_ids; 447 net::ParseCodecString(ToASCIIOrEmpty(codecs), &parsed_codec_ids, false); 448 if (mime_type_ascii.empty()) 449 return false; 450 return media::StreamParserFactory::IsTypeSupported( 451 mime_type_ascii, parsed_codec_ids); 452 } 453 454 bool 455 RendererWebKitPlatformSupportImpl::MimeRegistry::supportsEncryptedMediaMIMEType( 456 const WebString& key_system, 457 const WebString& mime_type, 458 const WebString& codecs) { 459 // Chromium only supports ASCII parameters. 460 if (!base::IsStringASCII(key_system) || !base::IsStringASCII(mime_type) || 461 !base::IsStringASCII(codecs)) { 462 return false; 463 } 464 465 if (key_system.isEmpty()) 466 return false; 467 468 const std::string mime_type_ascii = base::UTF16ToASCII(mime_type); 469 470 std::vector<std::string> codec_vector; 471 bool strip_suffix = !net::IsStrictMediaMimeType(mime_type_ascii); 472 net::ParseCodecString(base::UTF16ToASCII(codecs), &codec_vector, 473 strip_suffix); 474 475 return IsSupportedKeySystemWithMediaMimeType( 476 mime_type_ascii, codec_vector, base::UTF16ToASCII(key_system)); 477 } 478 479 WebString 480 RendererWebKitPlatformSupportImpl::MimeRegistry::mimeTypeForExtension( 481 const WebString& file_extension) { 482 if (IsPluginProcess()) 483 return SimpleWebMimeRegistryImpl::mimeTypeForExtension(file_extension); 484 485 // The sandbox restricts our access to the registry, so we need to proxy 486 // these calls over to the browser process. 487 std::string mime_type; 488 RenderThread::Get()->Send( 489 new MimeRegistryMsg_GetMimeTypeFromExtension( 490 base::FilePath::FromUTF16Unsafe(file_extension).value(), &mime_type)); 491 return base::ASCIIToUTF16(mime_type); 492 } 493 494 WebString RendererWebKitPlatformSupportImpl::MimeRegistry::mimeTypeFromFile( 495 const WebString& file_path) { 496 if (IsPluginProcess()) 497 return SimpleWebMimeRegistryImpl::mimeTypeFromFile(file_path); 498 499 // The sandbox restricts our access to the registry, so we need to proxy 500 // these calls over to the browser process. 501 std::string mime_type; 502 RenderThread::Get()->Send(new MimeRegistryMsg_GetMimeTypeFromFile( 503 base::FilePath::FromUTF16Unsafe(file_path), 504 &mime_type)); 505 return base::ASCIIToUTF16(mime_type); 506 } 507 508 //------------------------------------------------------------------------------ 509 510 bool RendererWebKitPlatformSupportImpl::FileUtilities::getFileInfo( 511 const WebString& path, 512 WebFileInfo& web_file_info) { 513 base::File::Info file_info; 514 base::File::Error status = base::File::FILE_ERROR_MAX; 515 if (!SendSyncMessageFromAnyThread(new FileUtilitiesMsg_GetFileInfo( 516 base::FilePath::FromUTF16Unsafe(path), &file_info, &status)) || 517 status != base::File::FILE_OK) { 518 return false; 519 } 520 FileInfoToWebFileInfo(file_info, &web_file_info); 521 web_file_info.platformPath = path; 522 return true; 523 } 524 525 bool RendererWebKitPlatformSupportImpl::FileUtilities:: 526 SendSyncMessageFromAnyThread(IPC::SyncMessage* msg) const { 527 base::TimeTicks begin = base::TimeTicks::Now(); 528 const bool success = thread_safe_sender_->Send(msg); 529 base::TimeDelta delta = base::TimeTicks::Now() - begin; 530 UMA_HISTOGRAM_TIMES("RendererSyncIPC.ElapsedTime", delta); 531 return success; 532 } 533 534 //------------------------------------------------------------------------------ 535 536 #if defined(OS_WIN) 537 538 bool RendererWebKitPlatformSupportImpl::SandboxSupport::ensureFontLoaded( 539 HFONT font) { 540 LOGFONT logfont; 541 GetObject(font, sizeof(LOGFONT), &logfont); 542 RenderThread::Get()->PreCacheFont(logfont); 543 return true; 544 } 545 546 #elif defined(OS_MACOSX) 547 548 bool RendererWebKitPlatformSupportImpl::SandboxSupport::loadFont( 549 NSFont* src_font, CGFontRef* out, uint32* font_id) { 550 uint32 font_data_size; 551 FontDescriptor src_font_descriptor(src_font); 552 base::SharedMemoryHandle font_data; 553 if (!RenderThread::Get()->Send(new ViewHostMsg_LoadFont( 554 src_font_descriptor, &font_data_size, &font_data, font_id))) { 555 *out = NULL; 556 *font_id = 0; 557 return false; 558 } 559 560 if (font_data_size == 0 || font_data == base::SharedMemory::NULLHandle() || 561 *font_id == 0) { 562 LOG(ERROR) << "Bad response from ViewHostMsg_LoadFont() for " << 563 src_font_descriptor.font_name; 564 *out = NULL; 565 *font_id = 0; 566 return false; 567 } 568 569 // TODO(jeremy): Need to call back into WebKit to make sure that the font 570 // isn't already activated, based on the font id. If it's already 571 // activated, don't reactivate it here - crbug.com/72727 . 572 573 return FontLoader::CGFontRefFromBuffer(font_data, font_data_size, out); 574 } 575 576 #elif defined(OS_ANDROID) 577 578 // WebKit doesn't use WebSandboxSupport on android so we don't need to 579 // implement anything here. This is cleaner to support than excluding the 580 // whole class for android. 581 582 #elif defined(OS_POSIX) 583 584 void 585 RendererWebKitPlatformSupportImpl::SandboxSupport::getFallbackFontForCharacter( 586 blink::WebUChar32 character, 587 const char* preferred_locale, 588 blink::WebFallbackFont* fallbackFont) { 589 base::AutoLock lock(unicode_font_families_mutex_); 590 const std::map<int32_t, blink::WebFallbackFont>::const_iterator iter = 591 unicode_font_families_.find(character); 592 if (iter != unicode_font_families_.end()) { 593 fallbackFont->name = iter->second.name; 594 fallbackFont->filename = iter->second.filename; 595 fallbackFont->fontconfigInterfaceId = iter->second.fontconfigInterfaceId; 596 fallbackFont->ttcIndex = iter->second.ttcIndex; 597 fallbackFont->isBold = iter->second.isBold; 598 fallbackFont->isItalic = iter->second.isItalic; 599 return; 600 } 601 602 GetFallbackFontForCharacter(character, preferred_locale, fallbackFont); 603 unicode_font_families_.insert(std::make_pair(character, *fallbackFont)); 604 } 605 606 void 607 RendererWebKitPlatformSupportImpl::SandboxSupport::getRenderStyleForStrike( 608 const char* family, int sizeAndStyle, blink::WebFontRenderStyle* out) { 609 GetRenderStyleForStrike(family, sizeAndStyle, out); 610 } 611 612 #endif 613 614 //------------------------------------------------------------------------------ 615 616 Platform::FileHandle 617 RendererWebKitPlatformSupportImpl::databaseOpenFile( 618 const WebString& vfs_file_name, int desired_flags) { 619 return DatabaseUtil::DatabaseOpenFile( 620 vfs_file_name, desired_flags, sync_message_filter_.get()); 621 } 622 623 int RendererWebKitPlatformSupportImpl::databaseDeleteFile( 624 const WebString& vfs_file_name, bool sync_dir) { 625 return DatabaseUtil::DatabaseDeleteFile( 626 vfs_file_name, sync_dir, sync_message_filter_.get()); 627 } 628 629 long RendererWebKitPlatformSupportImpl::databaseGetFileAttributes( 630 const WebString& vfs_file_name) { 631 return DatabaseUtil::DatabaseGetFileAttributes(vfs_file_name, 632 sync_message_filter_.get()); 633 } 634 635 long long RendererWebKitPlatformSupportImpl::databaseGetFileSize( 636 const WebString& vfs_file_name) { 637 return DatabaseUtil::DatabaseGetFileSize(vfs_file_name, 638 sync_message_filter_.get()); 639 } 640 641 long long RendererWebKitPlatformSupportImpl::databaseGetSpaceAvailableForOrigin( 642 const WebString& origin_identifier) { 643 return DatabaseUtil::DatabaseGetSpaceAvailable(origin_identifier, 644 sync_message_filter_.get()); 645 } 646 647 bool RendererWebKitPlatformSupportImpl::canAccelerate2dCanvas() { 648 RenderThreadImpl* thread = RenderThreadImpl::current(); 649 GpuChannelHost* host = thread->EstablishGpuChannelSync( 650 CAUSE_FOR_GPU_LAUNCH_CANVAS_2D); 651 if (!host) 652 return false; 653 654 return host->gpu_info().SupportsAccelerated2dCanvas(); 655 } 656 657 bool RendererWebKitPlatformSupportImpl::isThreadedCompositingEnabled() { 658 RenderThreadImpl* thread = RenderThreadImpl::current(); 659 // thread can be NULL in tests. 660 return thread && thread->compositor_message_loop_proxy().get(); 661 } 662 663 double RendererWebKitPlatformSupportImpl::audioHardwareSampleRate() { 664 RenderThreadImpl* thread = RenderThreadImpl::current(); 665 return thread->GetAudioHardwareConfig()->GetOutputSampleRate(); 666 } 667 668 size_t RendererWebKitPlatformSupportImpl::audioHardwareBufferSize() { 669 RenderThreadImpl* thread = RenderThreadImpl::current(); 670 return thread->GetAudioHardwareConfig()->GetOutputBufferSize(); 671 } 672 673 unsigned RendererWebKitPlatformSupportImpl::audioHardwareOutputChannels() { 674 RenderThreadImpl* thread = RenderThreadImpl::current(); 675 return thread->GetAudioHardwareConfig()->GetOutputChannels(); 676 } 677 678 WebDatabaseObserver* RendererWebKitPlatformSupportImpl::databaseObserver() { 679 return web_database_observer_impl_.get(); 680 } 681 682 WebAudioDevice* 683 RendererWebKitPlatformSupportImpl::createAudioDevice( 684 size_t buffer_size, 685 unsigned input_channels, 686 unsigned channels, 687 double sample_rate, 688 WebAudioDevice::RenderCallback* callback, 689 const blink::WebString& input_device_id) { 690 // Use a mock for testing. 691 blink::WebAudioDevice* mock_device = 692 GetContentClient()->renderer()->OverrideCreateAudioDevice(sample_rate); 693 if (mock_device) 694 return mock_device; 695 696 // The |channels| does not exactly identify the channel layout of the 697 // device. The switch statement below assigns a best guess to the channel 698 // layout based on number of channels. 699 // TODO(crogers): WebKit should give the channel layout instead of the hard 700 // channel count. 701 media::ChannelLayout layout = media::CHANNEL_LAYOUT_UNSUPPORTED; 702 switch (channels) { 703 case 1: 704 layout = media::CHANNEL_LAYOUT_MONO; 705 break; 706 case 2: 707 layout = media::CHANNEL_LAYOUT_STEREO; 708 break; 709 case 3: 710 layout = media::CHANNEL_LAYOUT_2_1; 711 break; 712 case 4: 713 layout = media::CHANNEL_LAYOUT_4_0; 714 break; 715 case 5: 716 layout = media::CHANNEL_LAYOUT_5_0; 717 break; 718 case 6: 719 layout = media::CHANNEL_LAYOUT_5_1; 720 break; 721 case 7: 722 layout = media::CHANNEL_LAYOUT_7_0; 723 break; 724 case 8: 725 layout = media::CHANNEL_LAYOUT_7_1; 726 break; 727 default: 728 layout = media::CHANNEL_LAYOUT_STEREO; 729 } 730 731 int session_id = 0; 732 if (input_device_id.isNull() || 733 !base::StringToInt(base::UTF16ToUTF8(input_device_id), &session_id)) { 734 if (input_channels > 0) 735 DLOG(WARNING) << "createAudioDevice(): request for audio input ignored"; 736 737 input_channels = 0; 738 } 739 740 media::AudioParameters params( 741 media::AudioParameters::AUDIO_PCM_LOW_LATENCY, 742 layout, static_cast<int>(sample_rate), 16, buffer_size, 743 media::AudioParameters::NO_EFFECTS); 744 745 return new RendererWebAudioDeviceImpl(params, callback, session_id); 746 } 747 748 #if defined(OS_ANDROID) 749 bool RendererWebKitPlatformSupportImpl::loadAudioResource( 750 blink::WebAudioBus* destination_bus, const char* audio_file_data, 751 size_t data_size) { 752 return DecodeAudioFileData(destination_bus, 753 audio_file_data, 754 data_size, 755 thread_safe_sender_); 756 } 757 #else 758 bool RendererWebKitPlatformSupportImpl::loadAudioResource( 759 blink::WebAudioBus* destination_bus, const char* audio_file_data, 760 size_t data_size) { 761 return DecodeAudioFileData( 762 destination_bus, audio_file_data, data_size); 763 } 764 #endif // defined(OS_ANDROID) 765 766 //------------------------------------------------------------------------------ 767 768 blink::WebMIDIAccessor* 769 RendererWebKitPlatformSupportImpl::createMIDIAccessor( 770 blink::WebMIDIAccessorClient* client) { 771 blink::WebMIDIAccessor* accessor = 772 GetContentClient()->renderer()->OverrideCreateMIDIAccessor(client); 773 if (accessor) 774 return accessor; 775 776 return new RendererWebMIDIAccessorImpl(client); 777 } 778 779 void RendererWebKitPlatformSupportImpl::getPluginList( 780 bool refresh, 781 blink::WebPluginListBuilder* builder) { 782 #if defined(ENABLE_PLUGINS) 783 std::vector<WebPluginInfo> plugins; 784 if (!plugin_refresh_allowed_) 785 refresh = false; 786 RenderThread::Get()->Send( 787 new ViewHostMsg_GetPlugins(refresh, &plugins)); 788 for (size_t i = 0; i < plugins.size(); ++i) { 789 const WebPluginInfo& plugin = plugins[i]; 790 791 builder->addPlugin( 792 plugin.name, plugin.desc, 793 plugin.path.BaseName().AsUTF16Unsafe()); 794 795 for (size_t j = 0; j < plugin.mime_types.size(); ++j) { 796 const WebPluginMimeType& mime_type = plugin.mime_types[j]; 797 798 builder->addMediaTypeToLastPlugin( 799 WebString::fromUTF8(mime_type.mime_type), mime_type.description); 800 801 for (size_t k = 0; k < mime_type.file_extensions.size(); ++k) { 802 builder->addFileExtensionToLastMediaType( 803 WebString::fromUTF8(mime_type.file_extensions[k])); 804 } 805 } 806 } 807 #endif 808 } 809 810 //------------------------------------------------------------------------------ 811 812 blink::WebPublicSuffixList* 813 RendererWebKitPlatformSupportImpl::publicSuffixList() { 814 return &public_suffix_list_; 815 } 816 817 //------------------------------------------------------------------------------ 818 819 blink::WebString 820 RendererWebKitPlatformSupportImpl::signedPublicKeyAndChallengeString( 821 unsigned key_size_index, 822 const blink::WebString& challenge, 823 const blink::WebURL& url) { 824 std::string signed_public_key; 825 RenderThread::Get()->Send(new ViewHostMsg_Keygen( 826 static_cast<uint32>(key_size_index), 827 challenge.utf8(), 828 GURL(url), 829 &signed_public_key)); 830 return WebString::fromUTF8(signed_public_key); 831 } 832 833 //------------------------------------------------------------------------------ 834 835 void RendererWebKitPlatformSupportImpl::screenColorProfile( 836 WebVector<char>* to_profile) { 837 #if defined(OS_WIN) 838 // On Windows screen color profile is only available in the browser. 839 std::vector<char> profile; 840 // This Send() can be called from any impl-side thread. Use a thread 841 // safe send to avoid crashing trying to access RenderThread::Get(), 842 // which is not accessible from arbitrary threads. 843 thread_safe_sender_->Send( 844 new ViewHostMsg_GetMonitorColorProfile(&profile)); 845 *to_profile = profile; 846 #else 847 // On other platforms, the primary monitor color profile can be read 848 // directly. 849 gfx::ColorProfile profile; 850 *to_profile = profile.profile(); 851 #endif 852 } 853 854 //------------------------------------------------------------------------------ 855 856 blink::WebScrollbarBehavior* 857 RendererWebKitPlatformSupportImpl::scrollbarBehavior() { 858 return web_scrollbar_behavior_.get(); 859 } 860 861 //------------------------------------------------------------------------------ 862 863 WebBlobRegistry* RendererWebKitPlatformSupportImpl::blobRegistry() { 864 // blob_registry_ can be NULL when running some tests. 865 return blob_registry_.get(); 866 } 867 868 //------------------------------------------------------------------------------ 869 870 void RendererWebKitPlatformSupportImpl::sampleGamepads(WebGamepads& gamepads) { 871 PlatformEventObserverBase* observer = 872 platform_event_observers_.Lookup(blink::WebPlatformEventGamepad); 873 if (!observer) 874 return; 875 static_cast<RendererGamepadProvider*>(observer)->SampleGamepads(gamepads); 876 } 877 878 //------------------------------------------------------------------------------ 879 880 WebRTCPeerConnectionHandler* 881 RendererWebKitPlatformSupportImpl::createRTCPeerConnectionHandler( 882 WebRTCPeerConnectionHandlerClient* client) { 883 RenderThreadImpl* render_thread = RenderThreadImpl::current(); 884 DCHECK(render_thread); 885 if (!render_thread) 886 return NULL; 887 888 #if defined(ENABLE_WEBRTC) 889 WebRTCPeerConnectionHandler* peer_connection_handler = 890 GetContentClient()->renderer()->OverrideCreateWebRTCPeerConnectionHandler( 891 client); 892 if (peer_connection_handler) 893 return peer_connection_handler; 894 895 PeerConnectionDependencyFactory* rtc_dependency_factory = 896 render_thread->GetPeerConnectionDependencyFactory(); 897 return rtc_dependency_factory->CreateRTCPeerConnectionHandler(client); 898 #else 899 return NULL; 900 #endif // defined(ENABLE_WEBRTC) 901 } 902 903 //------------------------------------------------------------------------------ 904 905 WebMediaStreamCenter* 906 RendererWebKitPlatformSupportImpl::createMediaStreamCenter( 907 WebMediaStreamCenterClient* client) { 908 RenderThreadImpl* render_thread = RenderThreadImpl::current(); 909 DCHECK(render_thread); 910 if (!render_thread) 911 return NULL; 912 return render_thread->CreateMediaStreamCenter(client); 913 } 914 915 // static 916 bool RendererWebKitPlatformSupportImpl::SetSandboxEnabledForTesting( 917 bool enable) { 918 bool was_enabled = g_sandbox_enabled; 919 g_sandbox_enabled = enable; 920 return was_enabled; 921 } 922 923 //------------------------------------------------------------------------------ 924 925 blink::WebSpeechSynthesizer* 926 RendererWebKitPlatformSupportImpl::createSpeechSynthesizer( 927 blink::WebSpeechSynthesizerClient* client) { 928 return GetContentClient()->renderer()->OverrideSpeechSynthesizer(client); 929 } 930 931 //------------------------------------------------------------------------------ 932 933 bool RendererWebKitPlatformSupportImpl::processMemorySizesInBytes( 934 size_t* private_bytes, size_t* shared_bytes) { 935 content::RenderThread::Get()->Send( 936 new ViewHostMsg_GetProcessMemorySizes(private_bytes, shared_bytes)); 937 return true; 938 } 939 940 //------------------------------------------------------------------------------ 941 942 blink::WebGraphicsContext3D* 943 RendererWebKitPlatformSupportImpl::createOffscreenGraphicsContext3D( 944 const blink::WebGraphicsContext3D::Attributes& attributes) { 945 return createOffscreenGraphicsContext3D(attributes, NULL); 946 } 947 948 blink::WebGraphicsContext3D* 949 RendererWebKitPlatformSupportImpl::createOffscreenGraphicsContext3D( 950 const blink::WebGraphicsContext3D::Attributes& attributes, 951 blink::WebGraphicsContext3D* share_context) { 952 if (!RenderThreadImpl::current()) 953 return NULL; 954 955 scoped_ptr<webkit::gpu::WebGraphicsContext3DImpl> context; 956 bool must_use_synchronous_factory = false; 957 #if defined(OS_ANDROID) 958 if (SynchronousCompositorFactory* factory = 959 SynchronousCompositorFactory::GetInstance()) { 960 context.reset(factory->CreateOffscreenGraphicsContext3D(attributes)); 961 must_use_synchronous_factory = true; 962 } 963 #endif 964 if (!must_use_synchronous_factory) { 965 scoped_refptr<GpuChannelHost> gpu_channel_host( 966 RenderThreadImpl::current()->EstablishGpuChannelSync( 967 CAUSE_FOR_GPU_LAUNCH_WEBGRAPHICSCONTEXT3DCOMMANDBUFFERIMPL_INITIALIZE)); 968 969 WebGraphicsContext3DCommandBufferImpl::SharedMemoryLimits limits; 970 bool lose_context_when_out_of_memory = false; 971 context.reset(WebGraphicsContext3DCommandBufferImpl::CreateOffscreenContext( 972 gpu_channel_host.get(), 973 attributes, 974 lose_context_when_out_of_memory, 975 GURL(attributes.topDocumentURL), 976 limits, 977 static_cast<WebGraphicsContext3DCommandBufferImpl*>(share_context))); 978 } 979 // Most likely the GPU process exited and the attempt to reconnect to it 980 // failed. Need to try to restore the context again later. 981 if (!context || !context->InitializeOnCurrentThread()) 982 return NULL; 983 return context.release(); 984 } 985 986 //------------------------------------------------------------------------------ 987 988 blink::WebGraphicsContext3DProvider* RendererWebKitPlatformSupportImpl:: 989 createSharedOffscreenGraphicsContext3DProvider() { 990 scoped_refptr<webkit::gpu::ContextProviderWebContext> provider = 991 RenderThreadImpl::current()->SharedMainThreadContextProvider(); 992 if (!provider.get()) 993 return NULL; 994 return new WebGraphicsContext3DProviderImpl(provider); 995 } 996 997 //------------------------------------------------------------------------------ 998 999 blink::WebCompositorSupport* 1000 RendererWebKitPlatformSupportImpl::compositorSupport() { 1001 return &compositor_support_; 1002 } 1003 1004 //------------------------------------------------------------------------------ 1005 1006 blink::WebString RendererWebKitPlatformSupportImpl::convertIDNToUnicode( 1007 const blink::WebString& host, 1008 const blink::WebString& languages) { 1009 return net::IDNToUnicode(host.utf8(), languages.utf8()); 1010 } 1011 1012 //------------------------------------------------------------------------------ 1013 1014 // static 1015 void RendererWebKitPlatformSupportImpl::SetMockDeviceLightDataForTesting( 1016 double data) { 1017 g_test_device_light_data = data; 1018 } 1019 1020 //------------------------------------------------------------------------------ 1021 1022 // static 1023 void RendererWebKitPlatformSupportImpl::SetMockDeviceMotionDataForTesting( 1024 const blink::WebDeviceMotionData& data) { 1025 g_test_device_motion_data.Get() = data; 1026 } 1027 1028 //------------------------------------------------------------------------------ 1029 1030 // static 1031 void RendererWebKitPlatformSupportImpl::SetMockDeviceOrientationDataForTesting( 1032 const blink::WebDeviceOrientationData& data) { 1033 g_test_device_orientation_data.Get() = data; 1034 } 1035 1036 //------------------------------------------------------------------------------ 1037 1038 void RendererWebKitPlatformSupportImpl::vibrate(unsigned int milliseconds) { 1039 RenderThread::Get()->Send( 1040 new ViewHostMsg_Vibrate(base::checked_cast<int64>(milliseconds))); 1041 } 1042 1043 void RendererWebKitPlatformSupportImpl::cancelVibration() { 1044 RenderThread::Get()->Send(new ViewHostMsg_CancelVibration()); 1045 } 1046 1047 //------------------------------------------------------------------------------ 1048 1049 // static 1050 PlatformEventObserverBase* 1051 RendererWebKitPlatformSupportImpl::CreatePlatformEventObserverFromType( 1052 blink::WebPlatformEventType type) { 1053 RenderThread* thread = RenderThreadImpl::current(); 1054 1055 // When running layout tests, those observers should not listen to the actual 1056 // hardware changes. In order to make that happen, they will receive a null 1057 // thread. 1058 if (thread && RenderThreadImpl::current()->layout_test_mode()) 1059 thread = 0; 1060 1061 switch (type) { 1062 case blink::WebPlatformEventDeviceMotion: { 1063 return new DeviceMotionEventPump(thread); 1064 } 1065 case blink::WebPlatformEventDeviceOrientation: { 1066 return new DeviceOrientationEventPump(thread); 1067 } 1068 case blink::WebPlatformEventDeviceLight: { 1069 return new DeviceLightEventPump(thread); 1070 } 1071 case blink::WebPlatformEventBattery: { 1072 return new BatteryStatusDispatcher(thread); 1073 } 1074 case blink::WebPlatformEventGamepad: 1075 return new GamepadSharedMemoryReader(thread); 1076 break; 1077 case blink::WebPlatformEventScreenOrientation: 1078 return new ScreenOrientationObserver(); 1079 default: 1080 // A default statement is required to prevent compilation errors when Blink 1081 // adds a new type. 1082 VLOG(1) << "RendererWebKitPlatformSupportImpl::startListening() with " 1083 "unknown type."; 1084 } 1085 1086 return 0; 1087 } 1088 1089 void RendererWebKitPlatformSupportImpl::SetPlatformEventObserverForTesting( 1090 blink::WebPlatformEventType type, 1091 scoped_ptr<PlatformEventObserverBase> observer) { 1092 if (platform_event_observers_.Lookup(type)) 1093 platform_event_observers_.Remove(type); 1094 platform_event_observers_.AddWithID(observer.release(), type); 1095 } 1096 1097 void RendererWebKitPlatformSupportImpl::startListening( 1098 blink::WebPlatformEventType type, 1099 blink::WebPlatformEventListener* listener) { 1100 PlatformEventObserverBase* observer = platform_event_observers_.Lookup(type); 1101 if (!observer) { 1102 observer = CreatePlatformEventObserverFromType(type); 1103 if (!observer) 1104 return; 1105 platform_event_observers_.AddWithID(observer, static_cast<int32>(type)); 1106 } 1107 observer->Start(listener); 1108 1109 // Device events (motion, orientation and light) expect to get an event fired 1110 // as soon as a listener is registered if a fake data was passed before. 1111 // TODO(mlamouri,timvolodine): make those send mock values directly instead of 1112 // using this broken pattern. 1113 if (RenderThreadImpl::current() && 1114 RenderThreadImpl::current()->layout_test_mode() && 1115 (type == blink::WebPlatformEventDeviceMotion || 1116 type == blink::WebPlatformEventDeviceOrientation || 1117 type == blink::WebPlatformEventDeviceLight)) { 1118 SendFakeDeviceEventDataForTesting(type); 1119 } 1120 } 1121 1122 void RendererWebKitPlatformSupportImpl::SendFakeDeviceEventDataForTesting( 1123 blink::WebPlatformEventType type) { 1124 PlatformEventObserverBase* observer = platform_event_observers_.Lookup(type); 1125 CHECK(observer); 1126 1127 void* data = 0; 1128 1129 switch (type) { 1130 case blink::WebPlatformEventDeviceMotion: 1131 if (!(g_test_device_motion_data == 0)) 1132 data = &g_test_device_motion_data.Get(); 1133 break; 1134 case blink::WebPlatformEventDeviceOrientation: 1135 if (!(g_test_device_orientation_data == 0)) 1136 data = &g_test_device_orientation_data.Get(); 1137 break; 1138 case blink::WebPlatformEventDeviceLight: 1139 if (g_test_device_light_data >= 0) 1140 data = &g_test_device_light_data; 1141 break; 1142 default: 1143 NOTREACHED(); 1144 break; 1145 } 1146 1147 if (!data) 1148 return; 1149 1150 base::MessageLoopProxy::current()->PostTask( 1151 FROM_HERE, 1152 base::Bind(&PlatformEventObserverBase::SendFakeDataForTesting, 1153 base::Unretained(observer), data)); 1154 } 1155 1156 void RendererWebKitPlatformSupportImpl::stopListening( 1157 blink::WebPlatformEventType type) { 1158 PlatformEventObserverBase* observer = platform_event_observers_.Lookup(type); 1159 if (!observer) 1160 return; 1161 observer->Stop(); 1162 } 1163 1164 //------------------------------------------------------------------------------ 1165 1166 void RendererWebKitPlatformSupportImpl::queryStorageUsageAndQuota( 1167 const blink::WebURL& storage_partition, 1168 blink::WebStorageQuotaType type, 1169 blink::WebStorageQuotaCallbacks callbacks) { 1170 if (!thread_safe_sender_.get() || !quota_message_filter_.get()) 1171 return; 1172 QuotaDispatcher::ThreadSpecificInstance(thread_safe_sender_.get(), 1173 quota_message_filter_.get()) 1174 ->QueryStorageUsageAndQuota( 1175 storage_partition, 1176 static_cast<storage::StorageType>(type), 1177 QuotaDispatcher::CreateWebStorageQuotaCallbacksWrapper(callbacks)); 1178 } 1179 1180 //------------------------------------------------------------------------------ 1181 1182 void RendererWebKitPlatformSupportImpl::MockBatteryStatusChangedForTesting( 1183 const blink::WebBatteryStatus& status) { 1184 PlatformEventObserverBase* observer = 1185 platform_event_observers_.Lookup(blink::WebPlatformEventBattery); 1186 if (!observer) 1187 return; 1188 observer->SendFakeDataForTesting((void*)&status); 1189 } 1190 1191 } // namespace content 1192