summaryrefslogtreecommitdiffstats
path: root/chromium/content/renderer/render_thread_impl.cc
diff options
context:
space:
mode:
authorZeno Albisser <zeno.albisser@digia.com>2013-08-15 21:46:11 +0200
committerZeno Albisser <zeno.albisser@digia.com>2013-08-15 21:46:11 +0200
commit679147eead574d186ebf3069647b4c23e8ccace6 (patch)
treefc247a0ac8ff119f7c8550879ebb6d3dd8d1ff69 /chromium/content/renderer/render_thread_impl.cc
Initial import.
Diffstat (limited to 'chromium/content/renderer/render_thread_impl.cc')
-rw-r--r--chromium/content/renderer/render_thread_impl.cc1319
1 files changed, 1319 insertions, 0 deletions
diff --git a/chromium/content/renderer/render_thread_impl.cc b/chromium/content/renderer/render_thread_impl.cc
new file mode 100644
index 00000000000..f15738dd00a
--- /dev/null
+++ b/chromium/content/renderer/render_thread_impl.cc
@@ -0,0 +1,1319 @@
+// 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 "content/renderer/render_thread_impl.h"
+
+#include <algorithm>
+#include <limits>
+#include <map>
+#include <vector>
+
+#include "base/allocator/allocator_extension.h"
+#include "base/command_line.h"
+#include "base/debug/trace_event.h"
+#include "base/lazy_instance.h"
+#include "base/logging.h"
+#include "base/memory/discardable_memory.h"
+#include "base/memory/shared_memory.h"
+#include "base/metrics/field_trial.h"
+#include "base/metrics/histogram.h"
+#include "base/metrics/stats_table.h"
+#include "base/path_service.h"
+#include "base/strings/string16.h"
+#include "base/strings/string_tokenizer.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/threading/thread_local.h"
+#include "base/threading/thread_restrictions.h"
+#include "base/values.h"
+#include "content/child/appcache/appcache_dispatcher.h"
+#include "content/child/appcache/appcache_frontend_impl.h"
+#include "content/child/child_histogram_message_filter.h"
+#include "content/child/db_message_filter.h"
+#include "content/child/indexed_db/indexed_db_dispatcher.h"
+#include "content/child/indexed_db/indexed_db_message_filter.h"
+#include "content/child/npapi/npobject_util.h"
+#include "content/child/plugin_messages.h"
+#include "content/child/resource_dispatcher.h"
+#include "content/child/runtime_features.h"
+#include "content/child/thread_safe_sender.h"
+#include "content/child/web_database_observer_impl.h"
+#include "content/common/child_process_messages.h"
+#include "content/common/content_constants_internal.h"
+#include "content/common/database_messages.h"
+#include "content/common/dom_storage/dom_storage_messages.h"
+#include "content/common/gpu/client/context_provider_command_buffer.h"
+#include "content/common/gpu/client/gpu_channel_host.h"
+#include "content/common/gpu/gpu_messages.h"
+#include "content/common/resource_messages.h"
+#include "content/common/view_messages.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/common/renderer_preferences.h"
+#include "content/public/common/url_constants.h"
+#include "content/public/renderer/content_renderer_client.h"
+#include "content/public/renderer/render_process_observer.h"
+#include "content/public/renderer/render_view_visitor.h"
+#include "content/renderer/devtools/devtools_agent_filter.h"
+#include "content/renderer/dom_storage/dom_storage_dispatcher.h"
+#include "content/renderer/dom_storage/webstoragearea_impl.h"
+#include "content/renderer/dom_storage/webstoragenamespace_impl.h"
+#include "content/renderer/gamepad_shared_memory_reader.h"
+#include "content/renderer/gpu/compositor_output_surface.h"
+#include "content/renderer/gpu/gpu_benchmarking_extension.h"
+#include "content/renderer/gpu/input_event_filter.h"
+#include "content/renderer/gpu/input_handler_manager.h"
+#include "content/renderer/media/audio_input_message_filter.h"
+#include "content/renderer/media/audio_message_filter.h"
+#include "content/renderer/media/audio_renderer_mixer_manager.h"
+#include "content/renderer/media/media_stream_center.h"
+#include "content/renderer/media/media_stream_dependency_factory.h"
+#include "content/renderer/media/midi_message_filter.h"
+#include "content/renderer/media/peer_connection_tracker.h"
+#include "content/renderer/media/video_capture_impl_manager.h"
+#include "content/renderer/media/video_capture_message_filter.h"
+#include "content/renderer/media/webrtc_identity_service.h"
+#include "content/renderer/memory_benchmarking_extension.h"
+#include "content/renderer/p2p/socket_dispatcher.h"
+#include "content/renderer/render_process_impl.h"
+#include "content/renderer/render_process_visibility_manager.h"
+#include "content/renderer/render_view_impl.h"
+#include "content/renderer/renderer_webkitplatformsupport_impl.h"
+#include "content/renderer/skia_benchmarking_extension.h"
+#include "grit/content_resources.h"
+#include "ipc/ipc_channel_handle.h"
+#include "ipc/ipc_forwarding_message_filter.h"
+#include "ipc/ipc_platform_file.h"
+#include "media/base/audio_hardware_config.h"
+#include "media/base/media.h"
+#include "media/filters/gpu_video_accelerator_factories.h"
+#include "net/base/net_errors.h"
+#include "net/base/net_util.h"
+#include "third_party/WebKit/public/platform/WebString.h"
+#include "third_party/WebKit/public/web/WebColorName.h"
+#include "third_party/WebKit/public/web/WebDatabase.h"
+#include "third_party/WebKit/public/web/WebDocument.h"
+#include "third_party/WebKit/public/web/WebFrame.h"
+#include "third_party/WebKit/public/web/WebImageCache.h"
+#include "third_party/WebKit/public/web/WebKit.h"
+#include "third_party/WebKit/public/web/WebNetworkStateNotifier.h"
+#include "third_party/WebKit/public/web/WebPopupMenu.h"
+#include "third_party/WebKit/public/web/WebRuntimeFeatures.h"
+#include "third_party/WebKit/public/web/WebScriptController.h"
+#include "third_party/WebKit/public/web/WebSecurityPolicy.h"
+#include "third_party/WebKit/public/web/WebSharedWorkerRepository.h"
+#include "third_party/WebKit/public/web/WebView.h"
+#include "ui/base/layout.h"
+#include "ui/base/ui_base_switches.h"
+#include "v8/include/v8.h"
+#include "webkit/child/worker_task_runner.h"
+#include "webkit/glue/webkit_glue.h"
+#include "webkit/renderer/compositor_bindings/web_external_bitmap_impl.h"
+
+#if defined(OS_WIN)
+#include <windows.h>
+#include <objbase.h>
+#include "base/win/scoped_com_initializer.h"
+#else
+// TODO(port)
+#include "base/memory/scoped_handle.h"
+#include "content/child/npapi/np_channel_base.h"
+#endif
+
+#if defined(OS_POSIX)
+#include "ipc/ipc_channel_posix.h"
+#endif
+
+#if defined(OS_ANDROID)
+#include <cpu-features.h>
+#include "content/renderer/android/synchronous_compositor_factory.h"
+#endif
+
+#if defined(ENABLE_PLUGINS)
+#include "content/renderer/npapi/plugin_channel_host.h"
+#endif
+
+using base::ThreadRestrictions;
+using WebKit::WebDocument;
+using WebKit::WebFrame;
+using WebKit::WebNetworkStateNotifier;
+using WebKit::WebRuntimeFeatures;
+using WebKit::WebScriptController;
+using WebKit::WebSecurityPolicy;
+using WebKit::WebString;
+using WebKit::WebView;
+
+namespace content {
+
+namespace {
+
+const int64 kInitialIdleHandlerDelayMs = 1000;
+const int64 kShortIdleHandlerDelayMs = 1000;
+const int64 kLongIdleHandlerDelayMs = 30*1000;
+const int kIdleCPUUsageThresholdInPercents = 3;
+
+// Keep the global RenderThreadImpl in a TLS slot so it is impossible to access
+// incorrectly from the wrong thread.
+base::LazyInstance<base::ThreadLocalPointer<RenderThreadImpl> >
+ lazy_tls = LAZY_INSTANCE_INITIALIZER;
+
+class RenderViewZoomer : public RenderViewVisitor {
+ public:
+ RenderViewZoomer(const std::string& scheme,
+ const std::string& host,
+ double zoom_level) : scheme_(scheme),
+ host_(host),
+ zoom_level_(zoom_level) {
+ }
+
+ virtual bool Visit(RenderView* render_view) OVERRIDE {
+ WebView* webview = render_view->GetWebView();
+ WebDocument document = webview->mainFrame()->document();
+
+ // Don't set zoom level for full-page plugin since they don't use the same
+ // zoom settings.
+ if (document.isPluginDocument())
+ return true;
+ GURL url(document.url());
+ // Empty scheme works as wildcard that matches any scheme,
+ if ((net::GetHostOrSpecFromURL(url) == host_) &&
+ (scheme_.empty() || scheme_ == url.scheme())) {
+ webview->setZoomLevel(false, zoom_level_);
+ }
+ return true;
+ }
+
+ private:
+ const std::string scheme_;
+ const std::string host_;
+ const double zoom_level_;
+
+ DISALLOW_COPY_AND_ASSIGN(RenderViewZoomer);
+};
+
+std::string HostToCustomHistogramSuffix(const std::string& host) {
+ if (host == "mail.google.com")
+ return ".gmail";
+ if (host == "docs.google.com" || host == "drive.google.com")
+ return ".docs";
+ if (host == "plus.google.com")
+ return ".plus";
+ return std::string();
+}
+
+void* CreateHistogram(
+ const char *name, int min, int max, size_t buckets) {
+ if (min <= 0)
+ min = 1;
+ std::string histogram_name;
+ RenderThreadImpl* render_thread_impl = RenderThreadImpl::current();
+ if (render_thread_impl) { // Can be null in tests.
+ histogram_name = render_thread_impl->
+ histogram_customizer()->ConvertToCustomHistogramName(name);
+ } else {
+ histogram_name = std::string(name);
+ }
+ base::HistogramBase* histogram = base::Histogram::FactoryGet(
+ histogram_name, min, max, buckets,
+ base::Histogram::kUmaTargetedHistogramFlag);
+ return histogram;
+}
+
+void AddHistogramSample(void* hist, int sample) {
+ base::Histogram* histogram = static_cast<base::Histogram*>(hist);
+ histogram->Add(sample);
+}
+
+scoped_ptr<base::SharedMemory> AllocateSharedMemoryFunction(size_t size) {
+ return RenderThreadImpl::Get()->HostAllocateSharedMemoryBuffer(size);
+}
+
+void EnableWebCoreLogChannels(const std::string& channels) {
+ if (channels.empty())
+ return;
+ base::StringTokenizer t(channels, ", ");
+ while (t.GetNext())
+ WebKit::enableLogChannel(t.token().c_str());
+}
+
+} // namespace
+
+class RenderThreadImpl::GpuVDAContextLostCallback
+ : public WebKit::WebGraphicsContext3D::WebGraphicsContextLostCallback {
+ public:
+ GpuVDAContextLostCallback()
+ : main_message_loop_(base::MessageLoopProxy::current()) {}
+ virtual ~GpuVDAContextLostCallback() {}
+ virtual void onContextLost() {
+ main_message_loop_->PostTask(FROM_HERE, base::Bind(
+ &RenderThreadImpl::OnGpuVDAContextLoss));
+ }
+
+ private:
+ scoped_refptr<base::MessageLoopProxy> main_message_loop_;
+};
+
+RenderThreadImpl::HistogramCustomizer::HistogramCustomizer() {
+ custom_histograms_.insert("V8.MemoryExternalFragmentationTotal");
+ custom_histograms_.insert("V8.MemoryHeapSampleTotalCommitted");
+ custom_histograms_.insert("V8.MemoryHeapSampleTotalUsed");
+}
+
+RenderThreadImpl::HistogramCustomizer::~HistogramCustomizer() {}
+
+void RenderThreadImpl::HistogramCustomizer::RenderViewNavigatedToHost(
+ const std::string& host, size_t view_count) {
+ if (CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kDisableHistogramCustomizer)) {
+ return;
+ }
+ // Check if all RenderViews are displaying a page from the same host. If there
+ // is only one RenderView, the common host is this view's host. If there are
+ // many, check if this one shares the common host of the other
+ // RenderViews. It's ok to not detect some cases where the RenderViews share a
+ // common host. This information is only used for producing custom histograms.
+ if (view_count == 1)
+ SetCommonHost(host);
+ else if (host != common_host_)
+ SetCommonHost(std::string());
+}
+
+std::string RenderThreadImpl::HistogramCustomizer::ConvertToCustomHistogramName(
+ const char* histogram_name) const {
+ std::string name(histogram_name);
+ if (!common_host_histogram_suffix_.empty() &&
+ custom_histograms_.find(name) != custom_histograms_.end())
+ name += common_host_histogram_suffix_;
+ return name;
+}
+
+void RenderThreadImpl::HistogramCustomizer::SetCommonHost(
+ const std::string& host) {
+ if (host != common_host_) {
+ common_host_ = host;
+ common_host_histogram_suffix_ = HostToCustomHistogramSuffix(host);
+ v8::V8::SetCreateHistogramFunction(CreateHistogram);
+ }
+}
+
+RenderThreadImpl* RenderThreadImpl::current() {
+ return lazy_tls.Pointer()->Get();
+}
+
+// When we run plugins in process, we actually run them on the render thread,
+// which means that we need to make the render thread pump UI events.
+RenderThreadImpl::RenderThreadImpl() {
+ Init();
+}
+
+RenderThreadImpl::RenderThreadImpl(const std::string& channel_name)
+ : ChildThread(channel_name) {
+ Init();
+}
+
+void RenderThreadImpl::Init() {
+ TRACE_EVENT_BEGIN_ETW("RenderThreadImpl::Init", 0, "");
+
+ base::debug::TraceLog::GetInstance()->SetThreadSortIndex(
+ base::PlatformThread::CurrentId(),
+ kTraceEventRendererMainThreadSortIndex);
+
+ v8::V8::SetCounterFunction(base::StatsTable::FindLocation);
+ v8::V8::SetCreateHistogramFunction(CreateHistogram);
+ v8::V8::SetAddHistogramSampleFunction(AddHistogramSample);
+
+#if defined(OS_MACOSX) || defined(OS_ANDROID)
+ // On Mac and Android, the select popups are rendered by the browser.
+ WebKit::WebView::setUseExternalPopupMenus(true);
+#endif
+
+ lazy_tls.Pointer()->Set(this);
+
+#if defined(OS_WIN)
+ // If you are running plugins in this thread you need COM active but in
+ // the normal case you don't.
+ if (RenderProcessImpl::InProcessPlugins())
+ initialize_com_.reset(new base::win::ScopedCOMInitializer());
+#endif
+
+ // Register this object as the main thread.
+ ChildProcess::current()->set_main_thread(this);
+
+ // In single process the single process is all there is.
+ suspend_webkit_shared_timer_ = true;
+ notify_webkit_of_modal_loop_ = true;
+ widget_count_ = 0;
+ hidden_widget_count_ = 0;
+ idle_notification_delay_in_ms_ = kInitialIdleHandlerDelayMs;
+ idle_notifications_to_skip_ = 0;
+ layout_test_mode_ = false;
+ shutdown_event_ = NULL;
+
+ appcache_dispatcher_.reset(
+ new AppCacheDispatcher(Get(), new AppCacheFrontendImpl()));
+ dom_storage_dispatcher_.reset(new DomStorageDispatcher());
+ main_thread_indexed_db_dispatcher_.reset(new IndexedDBDispatcher(
+ thread_safe_sender()));
+
+ media_stream_center_ = NULL;
+
+ db_message_filter_ = new DBMessageFilter();
+ AddFilter(db_message_filter_.get());
+
+#if defined(ENABLE_WEBRTC)
+ peer_connection_tracker_.reset(new PeerConnectionTracker());
+ AddObserver(peer_connection_tracker_.get());
+
+ p2p_socket_dispatcher_ =
+ new P2PSocketDispatcher(GetIOMessageLoopProxy().get());
+ AddFilter(p2p_socket_dispatcher_.get());
+
+ webrtc_identity_service_.reset(new WebRTCIdentityService());
+#endif // defined(ENABLE_WEBRTC)
+ vc_manager_ = new VideoCaptureImplManager();
+ AddFilter(vc_manager_->video_capture_message_filter());
+
+ audio_input_message_filter_ =
+ new AudioInputMessageFilter(GetIOMessageLoopProxy());
+ AddFilter(audio_input_message_filter_.get());
+
+ audio_message_filter_ = new AudioMessageFilter(GetIOMessageLoopProxy());
+ AddFilter(audio_message_filter_.get());
+
+ midi_message_filter_ = new MIDIMessageFilter(GetIOMessageLoopProxy());
+ AddFilter(midi_message_filter_.get());
+
+ AddFilter(new IndexedDBMessageFilter(thread_safe_sender()));
+
+ GetContentClient()->renderer()->RenderThreadStarted();
+
+ const CommandLine& command_line = *CommandLine::ForCurrentProcess();
+ if (command_line.HasSwitch(switches::kEnableGpuBenchmarking))
+ RegisterExtension(GpuBenchmarkingExtension::Get());
+
+#if defined(USE_TCMALLOC) && (defined(OS_LINUX) || defined(OS_ANDROID))
+ if (command_line.HasSwitch(switches::kEnableMemoryBenchmarking))
+ RegisterExtension(MemoryBenchmarkingExtension::Get());
+#endif // USE_TCMALLOC
+
+ if (command_line.HasSwitch(switches::kEnableSkiaBenchmarking)) {
+ LOG(WARNING) << "Enabling unsafe Skia benchmarking extension.";
+ RegisterExtension(SkiaBenchmarkingExtension::Get());
+ }
+
+ context_lost_cb_.reset(new GpuVDAContextLostCallback());
+
+ // Note that under Linux, the media library will normally already have
+ // been initialized by the Zygote before this instance became a Renderer.
+ base::FilePath media_path;
+ PathService::Get(DIR_MEDIA_LIBS, &media_path);
+ if (!media_path.empty())
+ media::InitializeMediaLibrary(media_path);
+
+ memory_pressure_listener_.reset(new base::MemoryPressureListener(
+ base::Bind(&RenderThreadImpl::OnMemoryPressure, base::Unretained(this))));
+
+ TRACE_EVENT_END_ETW("RenderThreadImpl::Init", 0, "");
+}
+
+RenderThreadImpl::~RenderThreadImpl() {
+}
+
+void RenderThreadImpl::Shutdown() {
+ FOR_EACH_OBSERVER(
+ RenderProcessObserver, observers_, OnRenderProcessShutdown());
+
+ ChildThread::Shutdown();
+
+ // Wait for all databases to be closed.
+ if (web_database_observer_impl_)
+ web_database_observer_impl_->WaitForAllDatabasesToClose();
+
+ // Shutdown in reverse of the initialization order.
+ if (devtools_agent_message_filter_.get()) {
+ RemoveFilter(devtools_agent_message_filter_.get());
+ devtools_agent_message_filter_ = NULL;
+ }
+
+ RemoveFilter(audio_input_message_filter_.get());
+ audio_input_message_filter_ = NULL;
+
+ RemoveFilter(audio_message_filter_.get());
+ audio_message_filter_ = NULL;
+
+ RemoveFilter(vc_manager_->video_capture_message_filter());
+
+ RemoveFilter(db_message_filter_.get());
+ db_message_filter_ = NULL;
+
+ // Shutdown the file thread if it's running.
+ if (file_thread_)
+ file_thread_->Stop();
+
+ if (compositor_output_surface_filter_.get()) {
+ RemoveFilter(compositor_output_surface_filter_.get());
+ compositor_output_surface_filter_ = NULL;
+ }
+
+ compositor_thread_.reset();
+ input_handler_manager_.reset();
+ if (input_event_filter_.get()) {
+ RemoveFilter(input_event_filter_.get());
+ input_event_filter_ = NULL;
+ }
+
+ if (webkit_platform_support_)
+ WebKit::shutdown();
+
+ lazy_tls.Pointer()->Set(NULL);
+
+ // TODO(port)
+#if defined(OS_WIN)
+ // Clean up plugin channels before this thread goes away.
+ NPChannelBase::CleanupChannels();
+#endif
+
+ // Leak shared contexts on other threads, as we can not get to the correct
+ // thread to destroy them.
+ if (shared_contexts_compositor_thread_.get())
+ shared_contexts_compositor_thread_->set_leak_on_destroy();
+}
+
+bool RenderThreadImpl::Send(IPC::Message* msg) {
+ // Certain synchronous messages cannot always be processed synchronously by
+ // the browser, e.g., Chrome frame communicating with the embedding browser.
+ // This could cause a complete hang of Chrome if a windowed plug-in is trying
+ // to communicate with the renderer thread since the browser's UI thread
+ // could be stuck (within a Windows API call) trying to synchronously
+ // communicate with the plug-in. The remedy is to pump messages on this
+ // thread while the browser is processing this request. This creates an
+ // opportunity for re-entrancy into WebKit, so we need to take care to disable
+ // callbacks, timers, and pending network loads that could trigger such
+ // callbacks.
+ bool pumping_events = false;
+ if (msg->is_sync()) {
+ if (msg->is_caller_pumping_messages()) {
+ pumping_events = true;
+ } else {
+ if ((msg->type() == ViewHostMsg_GetCookies::ID ||
+ msg->type() == ViewHostMsg_GetRawCookies::ID ||
+ msg->type() == ViewHostMsg_CookiesEnabled::ID) &&
+ GetContentClient()->renderer()->
+ ShouldPumpEventsDuringCookieMessage()) {
+ pumping_events = true;
+ }
+ }
+ }
+
+ bool suspend_webkit_shared_timer = true; // default value
+ std::swap(suspend_webkit_shared_timer, suspend_webkit_shared_timer_);
+
+ bool notify_webkit_of_modal_loop = true; // default value
+ std::swap(notify_webkit_of_modal_loop, notify_webkit_of_modal_loop_);
+
+#if defined(ENABLE_PLUGINS)
+ int render_view_id = MSG_ROUTING_NONE;
+#endif
+
+ if (pumping_events) {
+ if (suspend_webkit_shared_timer)
+ webkit_platform_support_->SuspendSharedTimer();
+
+ if (notify_webkit_of_modal_loop)
+ WebView::willEnterModalLoop();
+#if defined(ENABLE_PLUGINS)
+ RenderViewImpl* render_view =
+ RenderViewImpl::FromRoutingID(msg->routing_id());
+ if (render_view) {
+ render_view_id = msg->routing_id();
+ PluginChannelHost::Broadcast(
+ new PluginMsg_SignalModalDialogEvent(render_view_id));
+ }
+#endif
+ }
+
+ bool rv = ChildThread::Send(msg);
+
+ if (pumping_events) {
+#if defined(ENABLE_PLUGINS)
+ if (render_view_id != MSG_ROUTING_NONE) {
+ PluginChannelHost::Broadcast(
+ new PluginMsg_ResetModalDialogEvent(render_view_id));
+ }
+#endif
+
+ if (notify_webkit_of_modal_loop)
+ WebView::didExitModalLoop();
+
+ if (suspend_webkit_shared_timer)
+ webkit_platform_support_->ResumeSharedTimer();
+ }
+
+ return rv;
+}
+
+base::MessageLoop* RenderThreadImpl::GetMessageLoop() {
+ return message_loop();
+}
+
+IPC::SyncChannel* RenderThreadImpl::GetChannel() {
+ return channel();
+}
+
+std::string RenderThreadImpl::GetLocale() {
+ // The browser process should have passed the locale to the renderer via the
+ // --lang command line flag.
+ const CommandLine& parsed_command_line = *CommandLine::ForCurrentProcess();
+ const std::string& lang =
+ parsed_command_line.GetSwitchValueASCII(switches::kLang);
+ DCHECK(!lang.empty());
+ return lang;
+}
+
+IPC::SyncMessageFilter* RenderThreadImpl::GetSyncMessageFilter() {
+ return sync_message_filter();
+}
+
+scoped_refptr<base::MessageLoopProxy>
+ RenderThreadImpl::GetIOMessageLoopProxy() {
+ return ChildProcess::current()->io_message_loop_proxy();
+}
+
+void RenderThreadImpl::AddRoute(int32 routing_id, IPC::Listener* listener) {
+ widget_count_++;
+ return ChildThread::AddRoute(routing_id, listener);
+}
+
+void RenderThreadImpl::RemoveRoute(int32 routing_id) {
+ widget_count_--;
+ return ChildThread::RemoveRoute(routing_id);
+}
+
+int RenderThreadImpl::GenerateRoutingID() {
+ int routing_id = MSG_ROUTING_NONE;
+ Send(new ViewHostMsg_GenerateRoutingID(&routing_id));
+ return routing_id;
+}
+
+void RenderThreadImpl::AddFilter(IPC::ChannelProxy::MessageFilter* filter) {
+ channel()->AddFilter(filter);
+}
+
+void RenderThreadImpl::RemoveFilter(IPC::ChannelProxy::MessageFilter* filter) {
+ channel()->RemoveFilter(filter);
+}
+
+void RenderThreadImpl::SetOutgoingMessageFilter(
+ IPC::ChannelProxy::OutgoingMessageFilter* filter) {
+}
+
+void RenderThreadImpl::AddObserver(RenderProcessObserver* observer) {
+ observers_.AddObserver(observer);
+}
+
+void RenderThreadImpl::RemoveObserver(RenderProcessObserver* observer) {
+ observers_.RemoveObserver(observer);
+}
+
+void RenderThreadImpl::SetResourceDispatcherDelegate(
+ ResourceDispatcherDelegate* delegate) {
+ resource_dispatcher()->set_delegate(delegate);
+}
+
+void RenderThreadImpl::WidgetHidden() {
+ DCHECK(hidden_widget_count_ < widget_count_);
+ hidden_widget_count_++;
+
+ RenderProcessVisibilityManager* manager =
+ RenderProcessVisibilityManager::GetInstance();
+ manager->WidgetVisibilityChanged(false);
+
+ if (!GetContentClient()->renderer()->RunIdleHandlerWhenWidgetsHidden()) {
+ return;
+ }
+
+ if (widget_count_ && hidden_widget_count_ == widget_count_)
+ ScheduleIdleHandler(kInitialIdleHandlerDelayMs);
+}
+
+void RenderThreadImpl::WidgetRestored() {
+ DCHECK_GT(hidden_widget_count_, 0);
+ hidden_widget_count_--;
+
+ RenderProcessVisibilityManager* manager =
+ RenderProcessVisibilityManager::GetInstance();
+ manager->WidgetVisibilityChanged(true);
+
+ if (!GetContentClient()->renderer()->RunIdleHandlerWhenWidgetsHidden()) {
+ return;
+ }
+
+ ScheduleIdleHandler(kLongIdleHandlerDelayMs);
+}
+
+void RenderThreadImpl::EnsureWebKitInitialized() {
+ if (webkit_platform_support_)
+ return;
+
+ webkit_platform_support_.reset(new RendererWebKitPlatformSupportImpl);
+ WebKit::initialize(webkit_platform_support_.get());
+ WebKit::setSharedWorkerRepository(
+ webkit_platform_support_.get()->sharedWorkerRepository());
+
+ const CommandLine& command_line = *CommandLine::ForCurrentProcess();
+
+ bool enable = command_line.HasSwitch(switches::kEnableThreadedCompositing);
+ if (enable) {
+#if defined(OS_ANDROID)
+ if (SynchronousCompositorFactory* factory =
+ SynchronousCompositorFactory::GetInstance())
+ compositor_message_loop_proxy_ =
+ factory->GetCompositorMessageLoop();
+#endif
+ if (!compositor_message_loop_proxy_.get()) {
+ compositor_thread_.reset(new base::Thread("Compositor"));
+ compositor_thread_->Start();
+#if defined(OS_ANDROID)
+ compositor_thread_->SetPriority(base::kThreadPriority_Display);
+#endif
+ compositor_message_loop_proxy_ =
+ compositor_thread_->message_loop_proxy();
+ compositor_message_loop_proxy_->PostTask(
+ FROM_HERE,
+ base::Bind(base::IgnoreResult(&ThreadRestrictions::SetIOAllowed),
+ false));
+ }
+
+ InputHandlerManagerClient* input_handler_manager_client = NULL;
+#if defined(OS_ANDROID)
+ if (SynchronousCompositorFactory* factory =
+ SynchronousCompositorFactory::GetInstance()) {
+ input_handler_manager_client = factory->GetInputHandlerManagerClient();
+ }
+#endif
+ if (!input_handler_manager_client) {
+ input_event_filter_ =
+ new InputEventFilter(this, compositor_message_loop_proxy_);
+ AddFilter(input_event_filter_.get());
+ input_handler_manager_client = input_event_filter_.get();
+ }
+ input_handler_manager_.reset(
+ new InputHandlerManager(compositor_message_loop_proxy_,
+ input_handler_manager_client));
+ }
+
+ scoped_refptr<base::MessageLoopProxy> output_surface_loop;
+ if (enable)
+ output_surface_loop = compositor_message_loop_proxy_;
+ else
+ output_surface_loop = base::MessageLoopProxy::current();
+
+ compositor_output_surface_filter_ =
+ CompositorOutputSurface::CreateFilter(output_surface_loop.get());
+ AddFilter(compositor_output_surface_filter_.get());
+
+ WebScriptController::enableV8SingleThreadMode();
+
+ RenderThreadImpl::RegisterSchemes();
+
+ EnableWebCoreLogChannels(
+ command_line.GetSwitchValueASCII(switches::kWebCoreLogChannels));
+
+ web_database_observer_impl_.reset(
+ new WebDatabaseObserverImpl(sync_message_filter()));
+ WebKit::WebDatabase::setObserver(web_database_observer_impl_.get());
+
+ SetRuntimeFeaturesDefaultsAndUpdateFromArgs(command_line);
+
+ if (!media::IsMediaLibraryInitialized()) {
+ WebRuntimeFeatures::enableMediaPlayer(false);
+ WebRuntimeFeatures::enableWebAudio(false);
+ }
+
+ FOR_EACH_OBSERVER(RenderProcessObserver, observers_, WebKitInitialized());
+
+ devtools_agent_message_filter_ = new DevToolsAgentFilter();
+ AddFilter(devtools_agent_message_filter_.get());
+
+ if (GetContentClient()->renderer()->RunIdleHandlerWhenWidgetsHidden())
+ ScheduleIdleHandler(kLongIdleHandlerDelayMs);
+
+ webkit::SetSharedMemoryAllocationFunction(AllocateSharedMemoryFunction);
+}
+
+void RenderThreadImpl::RegisterSchemes() {
+ // swappedout: pages should not be accessible, and should also
+ // be treated as empty documents that can commit synchronously.
+ WebString swappedout_scheme(ASCIIToUTF16(kSwappedOutScheme));
+ WebSecurityPolicy::registerURLSchemeAsDisplayIsolated(swappedout_scheme);
+ WebSecurityPolicy::registerURLSchemeAsEmptyDocument(swappedout_scheme);
+}
+
+void RenderThreadImpl::RecordUserMetrics(const std::string& action) {
+ Send(new ViewHostMsg_UserMetricsRecordAction(action));
+}
+
+scoped_ptr<base::SharedMemory>
+ RenderThreadImpl::HostAllocateSharedMemoryBuffer(size_t size) {
+ if (size > static_cast<size_t>(std::numeric_limits<int>::max()))
+ return scoped_ptr<base::SharedMemory>();
+
+ base::SharedMemoryHandle handle;
+ bool success;
+ IPC::Message* message =
+ new ChildProcessHostMsg_SyncAllocateSharedMemory(size, &handle);
+
+ // Allow calling this from the compositor thread.
+ if (base::MessageLoop::current() == message_loop())
+ success = ChildThread::Send(message);
+ else
+ success = sync_message_filter()->Send(message);
+
+ if (!success)
+ return scoped_ptr<base::SharedMemory>();
+
+ if (!base::SharedMemory::IsHandleValid(handle))
+ return scoped_ptr<base::SharedMemory>();
+
+ return scoped_ptr<base::SharedMemory>(new base::SharedMemory(handle, false));
+}
+
+void RenderThreadImpl::RegisterExtension(v8::Extension* extension) {
+ WebScriptController::registerExtension(extension);
+}
+
+void RenderThreadImpl::ScheduleIdleHandler(int64 initial_delay_ms) {
+ idle_notification_delay_in_ms_ = initial_delay_ms;
+ idle_timer_.Stop();
+ idle_timer_.Start(FROM_HERE,
+ base::TimeDelta::FromMilliseconds(initial_delay_ms),
+ this, &RenderThreadImpl::IdleHandler);
+}
+
+void RenderThreadImpl::IdleHandler() {
+ bool run_in_foreground_tab = (widget_count_ > hidden_widget_count_) &&
+ GetContentClient()->renderer()->
+ RunIdleHandlerWhenWidgetsHidden();
+ if (run_in_foreground_tab) {
+ IdleHandlerInForegroundTab();
+ return;
+ }
+
+ base::allocator::ReleaseFreeMemory();
+
+ v8::V8::IdleNotification();
+
+ // Schedule next invocation.
+ // Dampen the delay using the algorithm (if delay is in seconds):
+ // delay = delay + 1 / (delay + 2)
+ // Using floor(delay) has a dampening effect such as:
+ // 1s, 1, 1, 2, 2, 2, 2, 3, 3, ...
+ // If the delay is in milliseconds, the above formula is equivalent to:
+ // delay_ms / 1000 = delay_ms / 1000 + 1 / (delay_ms / 1000 + 2)
+ // which is equivalent to
+ // delay_ms = delay_ms + 1000*1000 / (delay_ms + 2000).
+ // Note that idle_notification_delay_in_ms_ would be reset to
+ // kInitialIdleHandlerDelayMs in RenderThreadImpl::WidgetHidden.
+ ScheduleIdleHandler(idle_notification_delay_in_ms_ +
+ 1000000 / (idle_notification_delay_in_ms_ + 2000));
+
+ FOR_EACH_OBSERVER(RenderProcessObserver, observers_, IdleNotification());
+}
+
+void RenderThreadImpl::IdleHandlerInForegroundTab() {
+ // Increase the delay in the same way as in IdleHandler,
+ // but make it periodic by reseting it once it is too big.
+ int64 new_delay_ms = idle_notification_delay_in_ms_ +
+ 1000000 / (idle_notification_delay_in_ms_ + 2000);
+ if (new_delay_ms >= kLongIdleHandlerDelayMs)
+ new_delay_ms = kShortIdleHandlerDelayMs;
+
+ if (idle_notifications_to_skip_ > 0) {
+ idle_notifications_to_skip_--;
+ } else {
+ int cpu_usage = 0;
+ Send(new ViewHostMsg_GetCPUUsage(&cpu_usage));
+ // Idle notification hint roughly specifies the expected duration of the
+ // idle pause. We set it proportional to the idle timer delay.
+ int idle_hint = static_cast<int>(new_delay_ms / 10);
+ if (cpu_usage < kIdleCPUUsageThresholdInPercents) {
+ base::allocator::ReleaseFreeMemory();
+ if (v8::V8::IdleNotification(idle_hint)) {
+ // V8 finished collecting garbage.
+ new_delay_ms = kLongIdleHandlerDelayMs;
+ }
+ }
+ }
+ ScheduleIdleHandler(new_delay_ms);
+}
+
+int64 RenderThreadImpl::GetIdleNotificationDelayInMs() const {
+ return idle_notification_delay_in_ms_;
+}
+
+void RenderThreadImpl::SetIdleNotificationDelayInMs(
+ int64 idle_notification_delay_in_ms) {
+ idle_notification_delay_in_ms_ = idle_notification_delay_in_ms;
+}
+
+void RenderThreadImpl::ToggleWebKitSharedTimer(bool suspend) {
+ if (suspend_webkit_shared_timer_) {
+ EnsureWebKitInitialized();
+ if (suspend) {
+ webkit_platform_support_->SuspendSharedTimer();
+ } else {
+ webkit_platform_support_->ResumeSharedTimer();
+ }
+ }
+}
+
+void RenderThreadImpl::UpdateHistograms(int sequence_number) {
+ child_histogram_message_filter()->SendHistograms(sequence_number);
+}
+
+int RenderThreadImpl::PostTaskToAllWebWorkers(const base::Closure& closure) {
+ return webkit_glue::WorkerTaskRunner::Instance()->PostTaskToAllThreads(
+ closure);
+}
+
+bool RenderThreadImpl::ResolveProxy(const GURL& url, std::string* proxy_list) {
+ bool result = false;
+ Send(new ViewHostMsg_ResolveProxy(url, &result, proxy_list));
+ return result;
+}
+
+void RenderThreadImpl::PostponeIdleNotification() {
+ idle_notifications_to_skip_ = 2;
+}
+
+scoped_refptr<RendererGpuVideoAcceleratorFactories>
+RenderThreadImpl::GetGpuFactories(
+ const scoped_refptr<base::MessageLoopProxy>& factories_loop) {
+ DCHECK(IsMainThread());
+
+ const CommandLine* cmd_line = CommandLine::ForCurrentProcess();
+ scoped_refptr<RendererGpuVideoAcceleratorFactories> gpu_factories;
+ WebGraphicsContext3DCommandBufferImpl* context3d = NULL;
+ if (!cmd_line->HasSwitch(switches::kDisableAcceleratedVideoDecode))
+ context3d = GetGpuVDAContext3D();
+ GpuChannelHost* gpu_channel_host = GetGpuChannel();
+ if (gpu_channel_host) {
+ gpu_factories = new RendererGpuVideoAcceleratorFactories(
+ gpu_channel_host, factories_loop, context3d);
+ }
+ return gpu_factories;
+}
+
+/* static */
+void RenderThreadImpl::OnGpuVDAContextLoss() {
+ RenderThreadImpl* self = RenderThreadImpl::current();
+ DCHECK(self);
+ if (!self->gpu_vda_context3d_)
+ return;
+ if (self->compositor_message_loop_proxy().get()) {
+ self->compositor_message_loop_proxy()
+ ->DeleteSoon(FROM_HERE, self->gpu_vda_context3d_.release());
+ } else {
+ self->gpu_vda_context3d_.reset();
+ }
+}
+
+WebGraphicsContext3DCommandBufferImpl*
+RenderThreadImpl::GetGpuVDAContext3D() {
+ if (!gpu_vda_context3d_) {
+ gpu_vda_context3d_.reset(
+ WebGraphicsContext3DCommandBufferImpl::CreateOffscreenContext(
+ this, WebKit::WebGraphicsContext3D::Attributes(),
+ GURL("chrome://gpu/RenderThreadImpl::GetGpuVDAContext3D")));
+ if (gpu_vda_context3d_)
+ gpu_vda_context3d_->setContextLostCallback(context_lost_cb_.get());
+ }
+ return gpu_vda_context3d_.get();
+}
+
+scoped_ptr<WebGraphicsContext3DCommandBufferImpl>
+RenderThreadImpl::CreateOffscreenContext3d() {
+ WebKit::WebGraphicsContext3D::Attributes attributes;
+ attributes.shareResources = true;
+ attributes.depth = false;
+ attributes.stencil = false;
+ attributes.antialias = false;
+ attributes.noAutomaticFlushes = true;
+
+ return make_scoped_ptr(
+ WebGraphicsContext3DCommandBufferImpl::CreateOffscreenContext(
+ this,
+ attributes,
+ GURL("chrome://gpu/RenderThreadImpl::CreateOffscreenContext3d")));
+}
+
+scoped_refptr<cc::ContextProvider>
+RenderThreadImpl::OffscreenContextProviderForMainThread() {
+ DCHECK(IsMainThread());
+
+#if defined(OS_ANDROID)
+ if (SynchronousCompositorFactory* factory =
+ SynchronousCompositorFactory::GetInstance()) {
+ return factory->GetOffscreenContextProviderForMainThread();
+ }
+#endif
+
+ if (!shared_contexts_main_thread_.get() ||
+ shared_contexts_main_thread_->DestroyedOnMainThread()) {
+ shared_contexts_main_thread_ =
+ ContextProviderCommandBuffer::Create(
+ base::Bind(&RenderThreadImpl::CreateOffscreenContext3d,
+ base::Unretained(this)));
+ if (shared_contexts_main_thread_.get() &&
+ !shared_contexts_main_thread_->BindToCurrentThread())
+ shared_contexts_main_thread_ = NULL;
+ }
+ return shared_contexts_main_thread_;
+}
+
+scoped_refptr<cc::ContextProvider>
+RenderThreadImpl::OffscreenContextProviderForCompositorThread() {
+ DCHECK(IsMainThread());
+
+#if defined(OS_ANDROID)
+ if (SynchronousCompositorFactory* factory =
+ SynchronousCompositorFactory::GetInstance()) {
+ return factory->GetOffscreenContextProviderForCompositorThread();
+ }
+#endif
+
+ if (!shared_contexts_compositor_thread_.get() ||
+ shared_contexts_compositor_thread_->DestroyedOnMainThread()) {
+ shared_contexts_compositor_thread_ =
+ ContextProviderCommandBuffer::Create(
+ base::Bind(&RenderThreadImpl::CreateOffscreenContext3d,
+ base::Unretained(this)));
+ }
+ return shared_contexts_compositor_thread_;
+}
+
+AudioRendererMixerManager* RenderThreadImpl::GetAudioRendererMixerManager() {
+ if (!audio_renderer_mixer_manager_) {
+ audio_renderer_mixer_manager_.reset(new AudioRendererMixerManager(
+ GetAudioHardwareConfig()));
+ }
+
+ return audio_renderer_mixer_manager_.get();
+}
+
+media::AudioHardwareConfig* RenderThreadImpl::GetAudioHardwareConfig() {
+ if (!audio_hardware_config_) {
+ media::AudioParameters input_params;
+ media::AudioParameters output_params;
+ Send(new ViewHostMsg_GetAudioHardwareConfig(
+ &input_params, &output_params));
+
+ audio_hardware_config_.reset(new media::AudioHardwareConfig(
+ input_params, output_params));
+ audio_message_filter_->SetAudioHardwareConfig(audio_hardware_config_.get());
+ }
+
+ return audio_hardware_config_.get();
+}
+
+#if defined(OS_WIN)
+void RenderThreadImpl::PreCacheFontCharacters(const LOGFONT& log_font,
+ const string16& str) {
+ Send(new ViewHostMsg_PreCacheFontCharacters(log_font, str));
+}
+
+void RenderThreadImpl::PreCacheFont(const LOGFONT& log_font) {
+ Send(new ChildProcessHostMsg_PreCacheFont(log_font));
+}
+
+void RenderThreadImpl::ReleaseCachedFonts() {
+ Send(new ChildProcessHostMsg_ReleaseCachedFonts());
+}
+
+#endif // OS_WIN
+
+bool RenderThreadImpl::IsMainThread() {
+ return !!current();
+}
+
+base::MessageLoop* RenderThreadImpl::GetMainLoop() {
+ return message_loop();
+}
+
+scoped_refptr<base::MessageLoopProxy> RenderThreadImpl::GetIOLoopProxy() {
+ return io_message_loop_proxy_;
+}
+
+base::WaitableEvent* RenderThreadImpl::GetShutDownEvent() {
+ return shutdown_event_;
+}
+
+scoped_ptr<base::SharedMemory> RenderThreadImpl::AllocateSharedMemory(
+ size_t size) {
+ return scoped_ptr<base::SharedMemory>(
+ HostAllocateSharedMemoryBuffer(size));
+}
+
+int32 RenderThreadImpl::CreateViewCommandBuffer(
+ int32 surface_id, const GPUCreateCommandBufferConfig& init_params) {
+ TRACE_EVENT1("gpu",
+ "RenderThreadImpl::CreateViewCommandBuffer",
+ "surface_id",
+ surface_id);
+
+ int32 route_id = MSG_ROUTING_NONE;
+ IPC::Message* message = new GpuHostMsg_CreateViewCommandBuffer(
+ surface_id,
+ init_params,
+ &route_id);
+
+ // Allow calling this from the compositor thread.
+ thread_safe_sender()->Send(message);
+
+ return route_id;
+}
+
+void RenderThreadImpl::CreateImage(
+ gfx::PluginWindowHandle window,
+ int32 image_id,
+ const CreateImageCallback& callback) {
+ NOTREACHED();
+}
+
+void RenderThreadImpl::DeleteImage(int32 image_id, int32 sync_point) {
+ NOTREACHED();
+}
+
+void RenderThreadImpl::DoNotSuspendWebKitSharedTimer() {
+ suspend_webkit_shared_timer_ = false;
+}
+
+void RenderThreadImpl::DoNotNotifyWebKitOfModalLoop() {
+ notify_webkit_of_modal_loop_ = false;
+}
+
+void RenderThreadImpl::OnSetZoomLevelForCurrentURL(const std::string& scheme,
+ const std::string& host,
+ double zoom_level) {
+ RenderViewZoomer zoomer(scheme, host, zoom_level);
+ RenderView::ForEach(&zoomer);
+}
+
+bool RenderThreadImpl::OnControlMessageReceived(const IPC::Message& msg) {
+ ObserverListBase<RenderProcessObserver>::Iterator it(observers_);
+ RenderProcessObserver* observer;
+ while ((observer = it.GetNext()) != NULL) {
+ if (observer->OnControlMessageReceived(msg))
+ return true;
+ }
+
+ // Some messages are handled by delegates.
+ if (appcache_dispatcher_->OnMessageReceived(msg) ||
+ dom_storage_dispatcher_->OnMessageReceived(msg)) {
+ return true;
+ }
+
+ bool handled = true;
+ IPC_BEGIN_MESSAGE_MAP(RenderThreadImpl, msg)
+ IPC_MESSAGE_HANDLER(ViewMsg_SetZoomLevelForCurrentURL,
+ OnSetZoomLevelForCurrentURL)
+ // TODO(port): removed from render_messages_internal.h;
+ // is there a new non-windows message I should add here?
+ IPC_MESSAGE_HANDLER(ViewMsg_New, OnCreateNewView)
+ IPC_MESSAGE_HANDLER(ViewMsg_PurgePluginListCache, OnPurgePluginListCache)
+ IPC_MESSAGE_HANDLER(ViewMsg_NetworkStateChanged, OnNetworkStateChanged)
+ IPC_MESSAGE_HANDLER(ViewMsg_TempCrashWithData, OnTempCrashWithData)
+ IPC_MESSAGE_HANDLER(ViewMsg_SetWebKitSharedTimersSuspended,
+ OnSetWebKitSharedTimersSuspended)
+ IPC_MESSAGE_UNHANDLED(handled = false)
+ IPC_END_MESSAGE_MAP()
+ return handled;
+}
+
+void RenderThreadImpl::OnCreateNewView(const ViewMsg_New_Params& params) {
+ EnsureWebKitInitialized();
+ // When bringing in render_view, also bring in webkit's glue and jsbindings.
+ RenderViewImpl::Create(
+ params.opener_route_id,
+ params.renderer_preferences,
+ params.web_preferences,
+ new SharedRenderViewCounter(0),
+ params.view_id,
+ params.main_frame_routing_id,
+ params.surface_id,
+ params.session_storage_namespace_id,
+ params.frame_name,
+ false,
+ params.swapped_out,
+ params.next_page_id,
+ params.screen_info,
+ params.accessibility_mode,
+ params.allow_partial_swap);
+}
+
+GpuChannelHost* RenderThreadImpl::EstablishGpuChannelSync(
+ CauseForGpuLaunch cause_for_gpu_launch) {
+ TRACE_EVENT0("gpu", "RenderThreadImpl::EstablishGpuChannelSync");
+
+ if (gpu_channel_.get()) {
+ // Do nothing if we already have a GPU channel or are already
+ // establishing one.
+ if (!gpu_channel_->IsLost())
+ return gpu_channel_.get();
+
+ // Recreate the channel if it has been lost.
+ gpu_channel_ = NULL;
+ }
+
+ // Ask the browser for the channel name.
+ int client_id = 0;
+ IPC::ChannelHandle channel_handle;
+ gpu::GPUInfo gpu_info;
+ if (!Send(new GpuHostMsg_EstablishGpuChannel(cause_for_gpu_launch,
+ &client_id,
+ &channel_handle,
+ &gpu_info)) ||
+#if defined(OS_POSIX)
+ channel_handle.socket.fd == -1 ||
+#endif
+ channel_handle.name.empty()) {
+ // Otherwise cancel the connection.
+ return NULL;
+ }
+
+ GetContentClient()->SetGpuInfo(gpu_info);
+
+ // Cache some variables that are needed on the compositor thread for our
+ // implementation of GpuChannelHostFactory.
+ io_message_loop_proxy_ = ChildProcess::current()->io_message_loop_proxy();
+ shutdown_event_ = ChildProcess::current()->GetShutDownEvent();
+
+ gpu_channel_ = GpuChannelHost::Create(
+ this, 0, client_id, gpu_info, channel_handle);
+ return gpu_channel_.get();
+}
+
+WebKit::WebMediaStreamCenter* RenderThreadImpl::CreateMediaStreamCenter(
+ WebKit::WebMediaStreamCenterClient* client) {
+#if defined(OS_ANDROID)
+ if (CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kDisableWebRTC))
+ return NULL;
+#endif
+
+#if defined(ENABLE_WEBRTC)
+ if (!media_stream_center_) {
+ media_stream_center_ = GetContentClient()->renderer()
+ ->OverrideCreateWebMediaStreamCenter(client);
+ if (!media_stream_center_) {
+ scoped_ptr<MediaStreamCenter> media_stream_center(
+ new MediaStreamCenter(client, GetMediaStreamDependencyFactory()));
+ AddObserver(media_stream_center.get());
+ media_stream_center_ = media_stream_center.release();
+ }
+ }
+#endif
+ return media_stream_center_;
+}
+
+MediaStreamDependencyFactory*
+RenderThreadImpl::GetMediaStreamDependencyFactory() {
+#if defined(ENABLE_WEBRTC)
+ if (!media_stream_factory_) {
+ media_stream_factory_.reset(new MediaStreamDependencyFactory(
+ vc_manager_.get(), p2p_socket_dispatcher_.get()));
+ }
+#endif
+ return media_stream_factory_.get();
+}
+
+GpuChannelHost* RenderThreadImpl::GetGpuChannel() {
+ if (!gpu_channel_.get())
+ return NULL;
+
+ if (gpu_channel_->IsLost())
+ return NULL;
+
+ return gpu_channel_.get();
+}
+
+void RenderThreadImpl::OnPurgePluginListCache(bool reload_pages) {
+ EnsureWebKitInitialized();
+ // The call below will cause a GetPlugins call with refresh=true, but at this
+ // point we already know that the browser has refreshed its list, so disable
+ // refresh temporarily to prevent each renderer process causing the list to be
+ // regenerated.
+ webkit_platform_support_->set_plugin_refresh_allowed(false);
+ WebKit::resetPluginCache(reload_pages);
+ webkit_platform_support_->set_plugin_refresh_allowed(true);
+
+ FOR_EACH_OBSERVER(RenderProcessObserver, observers_, PluginListChanged());
+}
+
+void RenderThreadImpl::OnNetworkStateChanged(bool online) {
+ EnsureWebKitInitialized();
+ WebNetworkStateNotifier::setOnLine(online);
+}
+
+void RenderThreadImpl::OnTempCrashWithData(const GURL& data) {
+ GetContentClient()->SetActiveURL(data);
+ CHECK(false);
+}
+
+void RenderThreadImpl::OnSetWebKitSharedTimersSuspended(bool suspend) {
+ ToggleWebKitSharedTimer(suspend);
+}
+
+void RenderThreadImpl::OnMemoryPressure(
+ base::MemoryPressureListener::MemoryPressureLevel memory_pressure_level) {
+ base::allocator::ReleaseFreeMemory();
+
+ if (memory_pressure_level ==
+ base::MemoryPressureListener::MEMORY_PRESSURE_CRITICAL) {
+ // Trigger full v8 garbage collection on critical memory notification.
+ v8::V8::LowMemoryNotification();
+ // Clear the image cache.
+ WebKit::WebImageCache::clear();
+ } else {
+ // Otherwise trigger a couple of v8 GCs using IdleNotification.
+ if (!v8::V8::IdleNotification())
+ v8::V8::IdleNotification();
+ }
+}
+
+scoped_refptr<base::MessageLoopProxy>
+RenderThreadImpl::GetFileThreadMessageLoopProxy() {
+ DCHECK(message_loop() == base::MessageLoop::current());
+ if (!file_thread_) {
+ file_thread_.reset(new base::Thread("Renderer::FILE"));
+ file_thread_->Start();
+ }
+ return file_thread_->message_loop_proxy();
+}
+
+scoped_refptr<base::MessageLoopProxy>
+RenderThreadImpl::GetMediaThreadMessageLoopProxy() {
+ DCHECK(message_loop() == base::MessageLoop::current());
+ if (!media_thread_) {
+ media_thread_.reset(new base::Thread("Media"));
+ media_thread_->Start();
+ }
+ return media_thread_->message_loop_proxy();
+}
+
+void RenderThreadImpl::SetFlingCurveParameters(
+ const std::vector<float>& new_touchpad,
+ const std::vector<float>& new_touchscreen) {
+ webkit_platform_support_->SetFlingCurveParameters(new_touchpad,
+ new_touchscreen);
+
+}
+
+void RenderThreadImpl::SampleGamepads(WebKit::WebGamepads* data) {
+ if (!gamepad_shared_memory_reader_)
+ gamepad_shared_memory_reader_.reset(new GamepadSharedMemoryReader);
+ gamepad_shared_memory_reader_->SampleGamepads(*data);
+}
+
+} // namespace content