render_thread_impl.cc revision 7d4cd473f85ac64c3747c96c277f9e506a0d2246
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/render_thread_impl.h"
6
7#include <algorithm>
8#include <limits>
9#include <map>
10#include <vector>
11
12#include "base/allocator/allocator_extension.h"
13#include "base/command_line.h"
14#include "base/debug/trace_event.h"
15#include "base/lazy_instance.h"
16#include "base/logging.h"
17#include "base/metrics/field_trial.h"
18#include "base/metrics/histogram.h"
19#include "base/metrics/stats_table.h"
20#include "base/path_service.h"
21#include "base/shared_memory.h"
22#include "base/strings/string16.h"
23#include "base/strings/string_number_conversions.h"  // Temporary
24#include "base/strings/utf_string_conversions.h"
25#include "base/threading/thread_local.h"
26#include "base/threading/thread_restrictions.h"
27#include "base/values.h"
28#include "content/child/appcache_dispatcher.h"
29#include "content/child/child_histogram_message_filter.h"
30#include "content/child/indexed_db/indexed_db_dispatcher.h"
31#include "content/child/indexed_db/indexed_db_message_filter.h"
32#include "content/child/npobject_util.h"
33#include "content/child/plugin_messages.h"
34#include "content/child/resource_dispatcher.h"
35#include "content/child/runtime_features.h"
36#include "content/child/web_database_observer_impl.h"
37#include "content/common/child_process_messages.h"
38#include "content/common/database_messages.h"
39#include "content/common/db_message_filter.h"
40#include "content/common/dom_storage_messages.h"
41#include "content/common/gpu/client/context_provider_command_buffer.h"
42#include "content/common/gpu/client/gpu_channel_host.h"
43#include "content/common/gpu/gpu_messages.h"
44#include "content/common/resource_messages.h"
45#include "content/common/view_messages.h"
46#include "content/public/common/content_constants.h"
47#include "content/public/common/content_paths.h"
48#include "content/public/common/content_switches.h"
49#include "content/public/common/renderer_preferences.h"
50#include "content/public/common/url_constants.h"
51#include "content/public/renderer/content_renderer_client.h"
52#include "content/public/renderer/render_process_observer.h"
53#include "content/public/renderer/render_view_visitor.h"
54#include "content/renderer/devtools/devtools_agent_filter.h"
55#include "content/renderer/dom_storage/dom_storage_dispatcher.h"
56#include "content/renderer/dom_storage/webstoragearea_impl.h"
57#include "content/renderer/dom_storage/webstoragenamespace_impl.h"
58#include "content/renderer/gpu/compositor_output_surface.h"
59#include "content/renderer/gpu/gpu_benchmarking_extension.h"
60#include "content/renderer/gpu/input_event_filter.h"
61#include "content/renderer/gpu/input_handler_manager.h"
62#include "content/renderer/media/audio_input_message_filter.h"
63#include "content/renderer/media/audio_message_filter.h"
64#include "content/renderer/media/audio_renderer_mixer_manager.h"
65#include "content/renderer/media/media_stream_center.h"
66#include "content/renderer/media/media_stream_dependency_factory.h"
67#include "content/renderer/media/peer_connection_tracker.h"
68#include "content/renderer/media/video_capture_impl_manager.h"
69#include "content/renderer/media/video_capture_message_filter.h"
70#include "content/renderer/memory_benchmarking_extension.h"
71#include "content/renderer/p2p/socket_dispatcher.h"
72#include "content/renderer/plugin_channel_host.h"
73#include "content/renderer/render_process_impl.h"
74#include "content/renderer/render_view_impl.h"
75#include "content/renderer/renderer_webkitplatformsupport_impl.h"
76#include "content/renderer/skia_benchmarking_extension.h"
77#include "grit/content_resources.h"
78#include "ipc/ipc_channel_handle.h"
79#include "ipc/ipc_forwarding_message_filter.h"
80#include "ipc/ipc_platform_file.h"
81#include "media/base/audio_hardware_config.h"
82#include "media/base/media.h"
83#include "net/base/net_errors.h"
84#include "net/base/net_util.h"
85#include "third_party/WebKit/public/web/WebColorName.h"
86#include "third_party/WebKit/public/web/WebDatabase.h"
87#include "third_party/WebKit/public/web/WebDocument.h"
88#include "third_party/WebKit/public/web/WebFrame.h"
89#include "third_party/WebKit/public/web/WebKit.h"
90#include "third_party/WebKit/public/web/WebNetworkStateNotifier.h"
91#include "third_party/WebKit/public/web/WebPopupMenu.h"
92#include "third_party/WebKit/public/web/WebRuntimeFeatures.h"
93#include "third_party/WebKit/public/web/WebScriptController.h"
94#include "third_party/WebKit/public/web/WebSecurityPolicy.h"
95#include "third_party/WebKit/public/web/WebSharedWorkerRepository.h"
96#include "third_party/WebKit/public/web/WebView.h"
97#include "third_party/WebKit/public/platform/WebString.h"
98#include "ui/base/layout.h"
99#include "ui/base/ui_base_switches.h"
100#include "v8/include/v8.h"
101#include "webkit/glue/webkit_glue.h"
102#include "webkit/child/worker_task_runner.h"
103#include "webkit/renderer/appcache/appcache_frontend_impl.h"
104
105#if defined(OS_WIN)
106#include <windows.h>
107#include <objbase.h>
108#include "base/win/scoped_com_initializer.h"
109#else
110// TODO(port)
111#include "base/memory/scoped_handle.h"
112#include "content/child/np_channel_base.h"
113#endif
114
115#if defined(OS_POSIX)
116#include "ipc/ipc_channel_posix.h"
117#endif
118
119#if defined(OS_ANDROID)
120#include <cpu-features.h>
121#include "content/renderer/android/synchronous_compositor_factory.h"
122#endif
123
124using base::ThreadRestrictions;
125using WebKit::WebDocument;
126using WebKit::WebFrame;
127using WebKit::WebNetworkStateNotifier;
128using WebKit::WebRuntimeFeatures;
129using WebKit::WebScriptController;
130using WebKit::WebSecurityPolicy;
131using WebKit::WebString;
132using WebKit::WebView;
133
134namespace content {
135
136namespace {
137
138const int64 kInitialIdleHandlerDelayMs = 1000;
139const int64 kShortIdleHandlerDelayMs = 1000;
140const int64 kLongIdleHandlerDelayMs = 30*1000;
141const int kIdleCPUUsageThresholdInPercents = 3;
142
143// Keep the global RenderThreadImpl in a TLS slot so it is impossible to access
144// incorrectly from the wrong thread.
145base::LazyInstance<base::ThreadLocalPointer<RenderThreadImpl> >
146    lazy_tls = LAZY_INSTANCE_INITIALIZER;
147
148class RenderViewZoomer : public RenderViewVisitor {
149 public:
150  RenderViewZoomer(const std::string& scheme,
151                   const std::string& host,
152                   double zoom_level) : scheme_(scheme),
153                                        host_(host),
154                                        zoom_level_(zoom_level) {
155  }
156
157  virtual bool Visit(RenderView* render_view) OVERRIDE {
158    WebView* webview = render_view->GetWebView();
159    WebDocument document = webview->mainFrame()->document();
160
161    // Don't set zoom level for full-page plugin since they don't use the same
162    // zoom settings.
163    if (document.isPluginDocument())
164      return true;
165    GURL url(document.url());
166    // Empty scheme works as wildcard that matches any scheme,
167    if ((net::GetHostOrSpecFromURL(url) == host_) &&
168        (scheme_.empty() || scheme_ == url.scheme())) {
169      webview->setZoomLevel(false, zoom_level_);
170    }
171    return true;
172  }
173
174 private:
175  const std::string scheme_;
176  const std::string host_;
177  const double zoom_level_;
178
179  DISALLOW_COPY_AND_ASSIGN(RenderViewZoomer);
180};
181
182std::string HostToCustomHistogramSuffix(const std::string& host) {
183  if (host == "mail.google.com")
184    return ".gmail";
185  if (host == "docs.google.com" || host == "drive.google.com")
186    return ".docs";
187  if (host == "plus.google.com")
188    return ".plus";
189  return std::string();
190}
191
192void* CreateHistogram(
193    const char *name, int min, int max, size_t buckets) {
194  if (min <= 0)
195    min = 1;
196  std::string histogram_name;
197  RenderThreadImpl* render_thread_impl = RenderThreadImpl::current();
198  if (render_thread_impl) {  // Can be null in tests.
199    histogram_name = render_thread_impl->
200        histogram_customizer()->ConvertToCustomHistogramName(name);
201  } else {
202    histogram_name = std::string(name);
203  }
204  base::HistogramBase* histogram = base::Histogram::FactoryGet(
205      histogram_name, min, max, buckets,
206      base::Histogram::kUmaTargetedHistogramFlag);
207  return histogram;
208}
209
210void AddHistogramSample(void* hist, int sample) {
211  base::Histogram* histogram = static_cast<base::Histogram*>(hist);
212  histogram->Add(sample);
213}
214
215}  // namespace
216
217class RenderThreadImpl::GpuVDAContextLostCallback
218    : public WebKit::WebGraphicsContext3D::WebGraphicsContextLostCallback {
219 public:
220  GpuVDAContextLostCallback() {}
221  virtual ~GpuVDAContextLostCallback() {}
222  virtual void onContextLost() {
223    ChildThread::current()->message_loop()->PostTask(FROM_HERE, base::Bind(
224        &RenderThreadImpl::OnGpuVDAContextLoss));
225  }
226};
227
228class RenderThreadImpl::RendererContextProviderCommandBuffer
229    : public ContextProviderCommandBuffer {
230 public:
231  static scoped_refptr<RendererContextProviderCommandBuffer> Create() {
232    scoped_refptr<RendererContextProviderCommandBuffer> provider =
233        new RendererContextProviderCommandBuffer();
234    if (!provider->InitializeOnMainThread())
235      return NULL;
236    return provider;
237  }
238
239 protected:
240  virtual ~RendererContextProviderCommandBuffer() {}
241
242  virtual scoped_ptr<WebGraphicsContext3DCommandBufferImpl>
243  CreateOffscreenContext3d() OVERRIDE {
244    RenderThreadImpl* self = RenderThreadImpl::current();
245    DCHECK(self);
246    return self->CreateOffscreenContext3d().Pass();
247  }
248};
249
250RenderThreadImpl::HistogramCustomizer::HistogramCustomizer() {
251  custom_histograms_.insert("V8.MemoryExternalFragmentationTotal");
252  custom_histograms_.insert("V8.MemoryHeapSampleTotalCommitted");
253  custom_histograms_.insert("V8.MemoryHeapSampleTotalUsed");
254}
255
256RenderThreadImpl::HistogramCustomizer::~HistogramCustomizer() {}
257
258void RenderThreadImpl::HistogramCustomizer::RenderViewNavigatedToHost(
259    const std::string& host, size_t view_count) {
260  if (CommandLine::ForCurrentProcess()->HasSwitch(
261      switches::kDisableHistogramCustomizer)) {
262    return;
263  }
264  // Check if all RenderViews are displaying a page from the same host. If there
265  // is only one RenderView, the common host is this view's host. If there are
266  // many, check if this one shares the common host of the other
267  // RenderViews. It's ok to not detect some cases where the RenderViews share a
268  // common host. This information is only used for producing custom histograms.
269  if (view_count == 1)
270    SetCommonHost(host);
271  else if (host != common_host_)
272    SetCommonHost(std::string());
273}
274
275std::string RenderThreadImpl::HistogramCustomizer::ConvertToCustomHistogramName(
276    const char* histogram_name) const {
277  std::string name(histogram_name);
278  if (!common_host_histogram_suffix_.empty() &&
279      custom_histograms_.find(name) != custom_histograms_.end())
280    name += common_host_histogram_suffix_;
281  return name;
282}
283
284void RenderThreadImpl::HistogramCustomizer::SetCommonHost(
285    const std::string& host) {
286  if (host != common_host_) {
287    common_host_ = host;
288    common_host_histogram_suffix_ = HostToCustomHistogramSuffix(host);
289    v8::V8::SetCreateHistogramFunction(CreateHistogram);
290  }
291}
292
293RenderThreadImpl* RenderThreadImpl::current() {
294  return lazy_tls.Pointer()->Get();
295}
296
297// When we run plugins in process, we actually run them on the render thread,
298// which means that we need to make the render thread pump UI events.
299RenderThreadImpl::RenderThreadImpl() {
300  Init();
301}
302
303RenderThreadImpl::RenderThreadImpl(const std::string& channel_name)
304    : ChildThread(channel_name) {
305  Init();
306}
307
308void RenderThreadImpl::Init() {
309  TRACE_EVENT_BEGIN_ETW("RenderThreadImpl::Init", 0, "");
310
311  v8::V8::SetCounterFunction(base::StatsTable::FindLocation);
312  v8::V8::SetCreateHistogramFunction(CreateHistogram);
313  v8::V8::SetAddHistogramSampleFunction(AddHistogramSample);
314
315#if defined(OS_MACOSX) || defined(OS_ANDROID)
316  // On Mac and Android, the select popups are rendered by the browser.
317  WebKit::WebView::setUseExternalPopupMenus(true);
318#endif
319
320  lazy_tls.Pointer()->Set(this);
321
322#if defined(OS_WIN)
323  // If you are running plugins in this thread you need COM active but in
324  // the normal case you don't.
325  if (RenderProcessImpl::InProcessPlugins())
326    initialize_com_.reset(new base::win::ScopedCOMInitializer());
327#endif
328
329  // Register this object as the main thread.
330  ChildProcess::current()->set_main_thread(this);
331
332  // In single process the single process is all there is.
333  suspend_webkit_shared_timer_ = true;
334  notify_webkit_of_modal_loop_ = true;
335  widget_count_ = 0;
336  hidden_widget_count_ = 0;
337  idle_notification_delay_in_ms_ = kInitialIdleHandlerDelayMs;
338  idle_notifications_to_skip_ = 0;
339  layout_test_mode_ = false;
340
341  appcache_dispatcher_.reset(
342      new AppCacheDispatcher(Get(), new appcache::AppCacheFrontendImpl()));
343  dom_storage_dispatcher_.reset(new DomStorageDispatcher());
344  main_thread_indexed_db_dispatcher_.reset(new IndexedDBDispatcher());
345
346  media_stream_center_ = NULL;
347
348  db_message_filter_ = new DBMessageFilter();
349  AddFilter(db_message_filter_.get());
350
351#if defined(ENABLE_WEBRTC)
352  peer_connection_tracker_.reset(new PeerConnectionTracker());
353  AddObserver(peer_connection_tracker_.get());
354
355  p2p_socket_dispatcher_ =
356      new P2PSocketDispatcher(GetIOMessageLoopProxy().get());
357  AddFilter(p2p_socket_dispatcher_.get());
358#endif  // defined(ENABLE_WEBRTC)
359  vc_manager_ = new VideoCaptureImplManager();
360  AddFilter(vc_manager_->video_capture_message_filter());
361
362  audio_input_message_filter_ =
363      new AudioInputMessageFilter(GetIOMessageLoopProxy());
364  AddFilter(audio_input_message_filter_.get());
365
366  audio_message_filter_ = new AudioMessageFilter(GetIOMessageLoopProxy());
367  AddFilter(audio_message_filter_.get());
368
369  AddFilter(new IndexedDBMessageFilter);
370
371  GetContentClient()->renderer()->RenderThreadStarted();
372
373  const CommandLine& command_line = *CommandLine::ForCurrentProcess();
374  if (command_line.HasSwitch(switches::kEnableGpuBenchmarking))
375      RegisterExtension(GpuBenchmarkingExtension::Get());
376
377#if defined(USE_TCMALLOC) && (defined(OS_LINUX) || defined(OS_ANDROID))
378  if (command_line.HasSwitch(switches::kEnableMemoryBenchmarking))
379    RegisterExtension(MemoryBenchmarkingExtension::Get());
380#endif  // USE_TCMALLOC
381
382  if (command_line.HasSwitch(switches::kEnableSkiaBenchmarking)) {
383    LOG(WARNING) << "Enabling unsafe Skia benchmarking extension.";
384    RegisterExtension(SkiaBenchmarkingExtension::Get());
385  }
386
387  context_lost_cb_.reset(new GpuVDAContextLostCallback());
388
389  // Note that under Linux, the media library will normally already have
390  // been initialized by the Zygote before this instance became a Renderer.
391  base::FilePath media_path;
392  PathService::Get(DIR_MEDIA_LIBS, &media_path);
393  if (!media_path.empty())
394    media::InitializeMediaLibrary(media_path);
395
396  TRACE_EVENT_END_ETW("RenderThreadImpl::Init", 0, "");
397}
398
399RenderThreadImpl::~RenderThreadImpl() {
400}
401
402void RenderThreadImpl::Shutdown() {
403  FOR_EACH_OBSERVER(
404      RenderProcessObserver, observers_, OnRenderProcessShutdown());
405
406  // Wait for all databases to be closed.
407  if (web_database_observer_impl_)
408    web_database_observer_impl_->WaitForAllDatabasesToClose();
409
410  // Shutdown in reverse of the initialization order.
411  if (devtools_agent_message_filter_.get()) {
412    RemoveFilter(devtools_agent_message_filter_.get());
413    devtools_agent_message_filter_ = NULL;
414  }
415
416  RemoveFilter(audio_input_message_filter_.get());
417  audio_input_message_filter_ = NULL;
418
419  RemoveFilter(audio_message_filter_.get());
420  audio_message_filter_ = NULL;
421
422  RemoveFilter(vc_manager_->video_capture_message_filter());
423
424  RemoveFilter(db_message_filter_.get());
425  db_message_filter_ = NULL;
426
427  // Shutdown the file thread if it's running.
428  if (file_thread_)
429    file_thread_->Stop();
430
431  if (compositor_output_surface_filter_.get()) {
432    RemoveFilter(compositor_output_surface_filter_.get());
433    compositor_output_surface_filter_ = NULL;
434  }
435
436  compositor_thread_.reset();
437  input_handler_manager_.reset();
438  if (input_event_filter_.get()) {
439    RemoveFilter(input_event_filter_.get());
440    input_event_filter_ = NULL;
441  }
442
443  if (webkit_platform_support_)
444    WebKit::shutdown();
445
446  lazy_tls.Pointer()->Set(NULL);
447
448  // TODO(port)
449#if defined(OS_WIN)
450  // Clean up plugin channels before this thread goes away.
451  NPChannelBase::CleanupChannels();
452#endif
453
454  // Leak shared contexts on other threads, as we can not get to the correct
455  // thread to destroy them.
456  if (shared_contexts_compositor_thread_.get())
457    shared_contexts_compositor_thread_->set_leak_on_destroy();
458}
459
460bool RenderThreadImpl::Send(IPC::Message* msg) {
461  // Certain synchronous messages cannot always be processed synchronously by
462  // the browser, e.g., Chrome frame communicating with the embedding browser.
463  // This could cause a complete hang of Chrome if a windowed plug-in is trying
464  // to communicate with the renderer thread since the browser's UI thread
465  // could be stuck (within a Windows API call) trying to synchronously
466  // communicate with the plug-in.  The remedy is to pump messages on this
467  // thread while the browser is processing this request. This creates an
468  // opportunity for re-entrancy into WebKit, so we need to take care to disable
469  // callbacks, timers, and pending network loads that could trigger such
470  // callbacks.
471  bool pumping_events = false;
472  if (msg->is_sync()) {
473    if (msg->is_caller_pumping_messages()) {
474      pumping_events = true;
475    } else {
476      if ((msg->type() == ViewHostMsg_GetCookies::ID ||
477           msg->type() == ViewHostMsg_GetRawCookies::ID ||
478           msg->type() == ViewHostMsg_CookiesEnabled::ID) &&
479          GetContentClient()->renderer()->
480              ShouldPumpEventsDuringCookieMessage()) {
481        pumping_events = true;
482      }
483    }
484  }
485
486  bool suspend_webkit_shared_timer = true;  // default value
487  std::swap(suspend_webkit_shared_timer, suspend_webkit_shared_timer_);
488
489  bool notify_webkit_of_modal_loop = true;  // default value
490  std::swap(notify_webkit_of_modal_loop, notify_webkit_of_modal_loop_);
491
492  int render_view_id = MSG_ROUTING_NONE;
493
494  if (pumping_events) {
495    if (suspend_webkit_shared_timer)
496      webkit_platform_support_->SuspendSharedTimer();
497
498    if (notify_webkit_of_modal_loop)
499      WebView::willEnterModalLoop();
500
501    RenderViewImpl* render_view =
502        RenderViewImpl::FromRoutingID(msg->routing_id());
503    if (render_view) {
504      render_view_id = msg->routing_id();
505      PluginChannelHost::Broadcast(
506          new PluginMsg_SignalModalDialogEvent(render_view_id));
507    }
508  }
509
510  bool rv = ChildThread::Send(msg);
511
512  if (pumping_events) {
513    if (render_view_id != MSG_ROUTING_NONE) {
514      PluginChannelHost::Broadcast(
515          new PluginMsg_ResetModalDialogEvent(render_view_id));
516    }
517
518    if (notify_webkit_of_modal_loop)
519      WebView::didExitModalLoop();
520
521    if (suspend_webkit_shared_timer)
522      webkit_platform_support_->ResumeSharedTimer();
523  }
524
525  return rv;
526}
527
528base::MessageLoop* RenderThreadImpl::GetMessageLoop() {
529  return message_loop();
530}
531
532IPC::SyncChannel* RenderThreadImpl::GetChannel() {
533  return channel();
534}
535
536std::string RenderThreadImpl::GetLocale() {
537  // The browser process should have passed the locale to the renderer via the
538  // --lang command line flag.
539  const CommandLine& parsed_command_line = *CommandLine::ForCurrentProcess();
540  const std::string& lang =
541      parsed_command_line.GetSwitchValueASCII(switches::kLang);
542  DCHECK(!lang.empty());
543  return lang;
544}
545
546IPC::SyncMessageFilter* RenderThreadImpl::GetSyncMessageFilter() {
547  return sync_message_filter();
548}
549
550scoped_refptr<base::MessageLoopProxy>
551    RenderThreadImpl::GetIOMessageLoopProxy() {
552  return ChildProcess::current()->io_message_loop_proxy();
553}
554
555void RenderThreadImpl::AddRoute(int32 routing_id, IPC::Listener* listener) {
556  widget_count_++;
557  return ChildThread::AddRoute(routing_id, listener);
558}
559
560void RenderThreadImpl::RemoveRoute(int32 routing_id) {
561  widget_count_--;
562  return ChildThread::RemoveRoute(routing_id);
563}
564
565int RenderThreadImpl::GenerateRoutingID() {
566  int routing_id = MSG_ROUTING_NONE;
567  Send(new ViewHostMsg_GenerateRoutingID(&routing_id));
568  return routing_id;
569}
570
571void RenderThreadImpl::AddFilter(IPC::ChannelProxy::MessageFilter* filter) {
572  channel()->AddFilter(filter);
573}
574
575void RenderThreadImpl::RemoveFilter(IPC::ChannelProxy::MessageFilter* filter) {
576  channel()->RemoveFilter(filter);
577}
578
579void RenderThreadImpl::SetOutgoingMessageFilter(
580    IPC::ChannelProxy::OutgoingMessageFilter* filter) {
581}
582
583void RenderThreadImpl::AddObserver(RenderProcessObserver* observer) {
584  observers_.AddObserver(observer);
585}
586
587void RenderThreadImpl::RemoveObserver(RenderProcessObserver* observer) {
588  observers_.RemoveObserver(observer);
589}
590
591void RenderThreadImpl::SetResourceDispatcherDelegate(
592    ResourceDispatcherDelegate* delegate) {
593  resource_dispatcher()->set_delegate(delegate);
594}
595
596void RenderThreadImpl::WidgetHidden() {
597  DCHECK(hidden_widget_count_ < widget_count_);
598  hidden_widget_count_++;
599
600  if (!GetContentClient()->renderer()->RunIdleHandlerWhenWidgetsHidden()) {
601    return;
602  }
603
604  if (widget_count_ && hidden_widget_count_ == widget_count_)
605    ScheduleIdleHandler(kInitialIdleHandlerDelayMs);
606}
607
608void RenderThreadImpl::WidgetRestored() {
609  DCHECK_GT(hidden_widget_count_, 0);
610  hidden_widget_count_--;
611  if (!GetContentClient()->renderer()->RunIdleHandlerWhenWidgetsHidden()) {
612    return;
613  }
614
615  ScheduleIdleHandler(kLongIdleHandlerDelayMs);
616}
617
618void RenderThreadImpl::EnsureWebKitInitialized() {
619  if (webkit_platform_support_)
620    return;
621
622  webkit_platform_support_.reset(new RendererWebKitPlatformSupportImpl);
623  WebKit::initialize(webkit_platform_support_.get());
624  WebKit::setSharedWorkerRepository(
625      webkit_platform_support_.get()->sharedWorkerRepository());
626
627  const CommandLine& command_line = *CommandLine::ForCurrentProcess();
628
629  bool enable = command_line.HasSwitch(switches::kEnableThreadedCompositing);
630  if (enable) {
631#if defined(OS_ANDROID)
632    if (SynchronousCompositorFactory* factory =
633        SynchronousCompositorFactory::GetInstance())
634      compositor_message_loop_proxy_ =
635          factory->GetCompositorMessageLoop();
636#endif
637    if (!compositor_message_loop_proxy_.get()) {
638      compositor_thread_.reset(new base::Thread("Compositor"));
639      compositor_thread_->Start();
640#if defined(OS_ANDROID)
641      compositor_thread_->SetPriority(base::kThreadPriority_Display);
642#endif
643      compositor_message_loop_proxy_ =
644          compositor_thread_->message_loop_proxy();
645      compositor_message_loop_proxy_->PostTask(
646          FROM_HERE,
647          base::Bind(base::IgnoreResult(&ThreadRestrictions::SetIOAllowed),
648                     false));
649    }
650
651    InputHandlerManagerClient* input_handler_manager_client = NULL;
652#if defined(OS_ANDROID)
653    if (SynchronousCompositorFactory* factory =
654        SynchronousCompositorFactory::GetInstance()) {
655      input_handler_manager_client = factory->GetInputHandlerManagerClient();
656    }
657#endif
658    if (!input_handler_manager_client) {
659      input_event_filter_ =
660          new InputEventFilter(this, compositor_message_loop_proxy_);
661      AddFilter(input_event_filter_.get());
662      input_handler_manager_client = input_event_filter_.get();
663    }
664    input_handler_manager_.reset(
665        new InputHandlerManager(compositor_message_loop_proxy_,
666                                input_handler_manager_client));
667  }
668
669  scoped_refptr<base::MessageLoopProxy> output_surface_loop;
670  if (enable)
671    output_surface_loop = compositor_message_loop_proxy_;
672  else
673    output_surface_loop = base::MessageLoopProxy::current();
674
675  compositor_output_surface_filter_ =
676      CompositorOutputSurface::CreateFilter(output_surface_loop.get());
677  AddFilter(compositor_output_surface_filter_.get());
678
679  WebScriptController::enableV8SingleThreadMode();
680
681  RenderThreadImpl::RegisterSchemes();
682
683  webkit_glue::EnableWebCoreLogChannels(
684      command_line.GetSwitchValueASCII(switches::kWebCoreLogChannels));
685
686  web_database_observer_impl_.reset(
687      new WebDatabaseObserverImpl(sync_message_filter()));
688  WebKit::WebDatabase::setObserver(web_database_observer_impl_.get());
689
690  SetRuntimeFeaturesDefaultsAndUpdateFromArgs(command_line);
691
692  if (!media::IsMediaLibraryInitialized()) {
693    WebRuntimeFeatures::enableMediaPlayer(false);
694    WebRuntimeFeatures::enableWebAudio(false);
695  }
696
697  FOR_EACH_OBSERVER(RenderProcessObserver, observers_, WebKitInitialized());
698
699  devtools_agent_message_filter_ = new DevToolsAgentFilter();
700  AddFilter(devtools_agent_message_filter_.get());
701
702  if (GetContentClient()->renderer()->RunIdleHandlerWhenWidgetsHidden())
703    ScheduleIdleHandler(kLongIdleHandlerDelayMs);
704}
705
706void RenderThreadImpl::RegisterSchemes() {
707  // swappedout: pages should not be accessible, and should also
708  // be treated as empty documents that can commit synchronously.
709  WebString swappedout_scheme(ASCIIToUTF16(chrome::kSwappedOutScheme));
710  WebSecurityPolicy::registerURLSchemeAsDisplayIsolated(swappedout_scheme);
711  WebSecurityPolicy::registerURLSchemeAsEmptyDocument(swappedout_scheme);
712}
713
714void RenderThreadImpl::RecordUserMetrics(const std::string& action) {
715  Send(new ViewHostMsg_UserMetricsRecordAction(action));
716}
717
718scoped_ptr<base::SharedMemory>
719    RenderThreadImpl::HostAllocateSharedMemoryBuffer(size_t size) {
720  if (size > static_cast<size_t>(std::numeric_limits<int>::max()))
721    return scoped_ptr<base::SharedMemory>();
722
723  base::SharedMemoryHandle handle;
724  bool success;
725  IPC::Message* message =
726      new ChildProcessHostMsg_SyncAllocateSharedMemory(size, &handle);
727
728  // Allow calling this from the compositor thread.
729  if (base::MessageLoop::current() == message_loop())
730    success = ChildThread::Send(message);
731  else
732    success = sync_message_filter()->Send(message);
733
734  if (!success)
735    return scoped_ptr<base::SharedMemory>();
736
737  if (!base::SharedMemory::IsHandleValid(handle))
738    return scoped_ptr<base::SharedMemory>();
739
740  return scoped_ptr<base::SharedMemory>(new base::SharedMemory(handle, false));
741}
742
743void RenderThreadImpl::RegisterExtension(v8::Extension* extension) {
744  WebScriptController::registerExtension(extension);
745}
746
747void RenderThreadImpl::ScheduleIdleHandler(int64 initial_delay_ms) {
748  idle_notification_delay_in_ms_ = initial_delay_ms;
749  idle_timer_.Stop();
750  idle_timer_.Start(FROM_HERE,
751      base::TimeDelta::FromMilliseconds(initial_delay_ms),
752      this, &RenderThreadImpl::IdleHandler);
753}
754
755void RenderThreadImpl::IdleHandler() {
756  bool run_in_foreground_tab = (widget_count_ > hidden_widget_count_) &&
757                               GetContentClient()->renderer()->
758                                   RunIdleHandlerWhenWidgetsHidden();
759  if (run_in_foreground_tab) {
760    IdleHandlerInForegroundTab();
761    return;
762  }
763
764  base::allocator::ReleaseFreeMemory();
765
766  v8::V8::IdleNotification();
767
768  // Schedule next invocation.
769  // Dampen the delay using the algorithm (if delay is in seconds):
770  //    delay = delay + 1 / (delay + 2)
771  // Using floor(delay) has a dampening effect such as:
772  //    1s, 1, 1, 2, 2, 2, 2, 3, 3, ...
773  // If the delay is in milliseconds, the above formula is equivalent to:
774  //    delay_ms / 1000 = delay_ms / 1000 + 1 / (delay_ms / 1000 + 2)
775  // which is equivalent to
776  //    delay_ms = delay_ms + 1000*1000 / (delay_ms + 2000).
777  // Note that idle_notification_delay_in_ms_ would be reset to
778  // kInitialIdleHandlerDelayMs in RenderThreadImpl::WidgetHidden.
779  ScheduleIdleHandler(idle_notification_delay_in_ms_ +
780                      1000000 / (idle_notification_delay_in_ms_ + 2000));
781
782  FOR_EACH_OBSERVER(RenderProcessObserver, observers_, IdleNotification());
783}
784
785void RenderThreadImpl::IdleHandlerInForegroundTab() {
786  // Increase the delay in the same way as in IdleHandler,
787  // but make it periodic by reseting it once it is too big.
788  int64 new_delay_ms = idle_notification_delay_in_ms_ +
789                       1000000 / (idle_notification_delay_in_ms_ + 2000);
790  if (new_delay_ms >= kLongIdleHandlerDelayMs)
791    new_delay_ms = kShortIdleHandlerDelayMs;
792
793  if (idle_notifications_to_skip_ > 0) {
794    idle_notifications_to_skip_--;
795  } else  {
796    int cpu_usage = 0;
797    Send(new ViewHostMsg_GetCPUUsage(&cpu_usage));
798    // Idle notification hint roughly specifies the expected duration of the
799    // idle pause. We set it proportional to the idle timer delay.
800    int idle_hint = static_cast<int>(new_delay_ms / 10);
801    if (cpu_usage < kIdleCPUUsageThresholdInPercents) {
802      base::allocator::ReleaseFreeMemory();
803      if (v8::V8::IdleNotification(idle_hint)) {
804        // V8 finished collecting garbage.
805        new_delay_ms = kLongIdleHandlerDelayMs;
806      }
807    }
808  }
809  ScheduleIdleHandler(new_delay_ms);
810}
811
812int64 RenderThreadImpl::GetIdleNotificationDelayInMs() const {
813  return idle_notification_delay_in_ms_;
814}
815
816void RenderThreadImpl::SetIdleNotificationDelayInMs(
817    int64 idle_notification_delay_in_ms) {
818  idle_notification_delay_in_ms_ = idle_notification_delay_in_ms;
819}
820
821void RenderThreadImpl::ToggleWebKitSharedTimer(bool suspend) {
822  if (suspend_webkit_shared_timer_) {
823    EnsureWebKitInitialized();
824    if (suspend) {
825      webkit_platform_support_->SuspendSharedTimer();
826    } else {
827      webkit_platform_support_->ResumeSharedTimer();
828    }
829  }
830}
831
832void RenderThreadImpl::UpdateHistograms(int sequence_number) {
833  child_histogram_message_filter()->SendHistograms(sequence_number);
834}
835
836int RenderThreadImpl::PostTaskToAllWebWorkers(const base::Closure& closure) {
837  return webkit_glue::WorkerTaskRunner::Instance()->PostTaskToAllThreads(
838      closure);
839}
840
841bool RenderThreadImpl::ResolveProxy(const GURL& url, std::string* proxy_list) {
842  bool result = false;
843  Send(new ViewHostMsg_ResolveProxy(url, &result, proxy_list));
844  return result;
845}
846
847void RenderThreadImpl::PostponeIdleNotification() {
848  idle_notifications_to_skip_ = 2;
849}
850
851/* static */
852void RenderThreadImpl::OnGpuVDAContextLoss() {
853  RenderThreadImpl* self = RenderThreadImpl::current();
854  DCHECK(self);
855  if (!self->gpu_vda_context3d_)
856    return;
857  if (self->compositor_message_loop_proxy().get()) {
858    self->compositor_message_loop_proxy()
859        ->DeleteSoon(FROM_HERE, self->gpu_vda_context3d_.release());
860  } else {
861    self->gpu_vda_context3d_.reset();
862  }
863}
864
865WebGraphicsContext3DCommandBufferImpl*
866RenderThreadImpl::GetGpuVDAContext3D() {
867  if (!gpu_vda_context3d_) {
868    gpu_vda_context3d_.reset(
869        WebGraphicsContext3DCommandBufferImpl::CreateOffscreenContext(
870            this, WebKit::WebGraphicsContext3D::Attributes(),
871            GURL("chrome://gpu/RenderThreadImpl::GetGpuVDAContext3D")));
872    if (gpu_vda_context3d_)
873      gpu_vda_context3d_->setContextLostCallback(context_lost_cb_.get());
874  }
875  return gpu_vda_context3d_.get();
876}
877
878scoped_ptr<WebGraphicsContext3DCommandBufferImpl>
879RenderThreadImpl::CreateOffscreenContext3d() {
880  WebKit::WebGraphicsContext3D::Attributes attributes;
881  attributes.shareResources = true;
882  attributes.depth = false;
883  attributes.stencil = false;
884  attributes.antialias = false;
885  attributes.noAutomaticFlushes = true;
886
887  return make_scoped_ptr(
888      WebGraphicsContext3DCommandBufferImpl::CreateOffscreenContext(
889          this,
890          attributes,
891          GURL("chrome://gpu/RenderThreadImpl::CreateOffscreenContext3d")));
892}
893
894scoped_refptr<cc::ContextProvider>
895RenderThreadImpl::OffscreenContextProviderForMainThread() {
896  DCHECK(IsMainThread());
897
898#if defined(OS_ANDROID)
899  if (SynchronousCompositorFactory* factory =
900      SynchronousCompositorFactory::GetInstance()) {
901    return factory->GetOffscreenContextProviderForMainThread();
902  }
903#endif
904
905  if (!shared_contexts_main_thread_.get() ||
906      shared_contexts_main_thread_->DestroyedOnMainThread()) {
907    shared_contexts_main_thread_ =
908        RendererContextProviderCommandBuffer::Create();
909    if (shared_contexts_main_thread_.get() &&
910        !shared_contexts_main_thread_->BindToCurrentThread())
911      shared_contexts_main_thread_ = NULL;
912  }
913  return shared_contexts_main_thread_;
914}
915
916scoped_refptr<cc::ContextProvider>
917RenderThreadImpl::OffscreenContextProviderForCompositorThread() {
918  DCHECK(IsMainThread());
919
920#if defined(OS_ANDROID)
921  if (SynchronousCompositorFactory* factory =
922      SynchronousCompositorFactory::GetInstance()) {
923    return factory->GetOffscreenContextProviderForCompositorThread();
924  }
925#endif
926
927  if (!shared_contexts_compositor_thread_.get() ||
928      shared_contexts_compositor_thread_->DestroyedOnMainThread()) {
929    shared_contexts_compositor_thread_ =
930        RendererContextProviderCommandBuffer::Create();
931  }
932  return shared_contexts_compositor_thread_;
933}
934
935AudioRendererMixerManager* RenderThreadImpl::GetAudioRendererMixerManager() {
936  if (!audio_renderer_mixer_manager_) {
937    audio_renderer_mixer_manager_.reset(new AudioRendererMixerManager(
938        GetAudioHardwareConfig()));
939  }
940
941  return audio_renderer_mixer_manager_.get();
942}
943
944media::AudioHardwareConfig* RenderThreadImpl::GetAudioHardwareConfig() {
945  if (!audio_hardware_config_) {
946    media::AudioParameters input_params;
947    media::AudioParameters output_params;
948    Send(new ViewHostMsg_GetAudioHardwareConfig(
949        &input_params, &output_params));
950
951    audio_hardware_config_.reset(new media::AudioHardwareConfig(
952        input_params, output_params));
953    audio_message_filter_->SetAudioHardwareConfig(audio_hardware_config_.get());
954  }
955
956  return audio_hardware_config_.get();
957}
958
959#if defined(OS_WIN)
960void RenderThreadImpl::PreCacheFontCharacters(const LOGFONT& log_font,
961                                              const string16& str) {
962  Send(new ViewHostMsg_PreCacheFontCharacters(log_font, str));
963}
964
965void RenderThreadImpl::PreCacheFont(const LOGFONT& log_font) {
966  Send(new ChildProcessHostMsg_PreCacheFont(log_font));
967}
968
969void RenderThreadImpl::ReleaseCachedFonts() {
970  Send(new ChildProcessHostMsg_ReleaseCachedFonts());
971}
972
973#endif  // OS_WIN
974
975bool RenderThreadImpl::IsWebFrameValid(WebKit::WebFrame* web_frame) {
976  if (!web_frame)
977    return false;  // We must be shutting down.
978
979  RenderViewImpl* render_view = RenderViewImpl::FromWebView(web_frame->view());
980  if (!render_view)
981    return false;  // We must be shutting down.
982
983  return true;
984}
985
986bool RenderThreadImpl::IsMainThread() {
987  return !!current();
988}
989
990base::MessageLoop* RenderThreadImpl::GetMainLoop() {
991  return message_loop();
992}
993
994scoped_refptr<base::MessageLoopProxy> RenderThreadImpl::GetIOLoopProxy() {
995  return ChildProcess::current()->io_message_loop_proxy();
996}
997
998base::WaitableEvent* RenderThreadImpl::GetShutDownEvent() {
999  return ChildProcess::current()->GetShutDownEvent();
1000}
1001
1002scoped_ptr<base::SharedMemory> RenderThreadImpl::AllocateSharedMemory(
1003    size_t size) {
1004  return scoped_ptr<base::SharedMemory>(
1005      HostAllocateSharedMemoryBuffer(size));
1006}
1007
1008int32 RenderThreadImpl::CreateViewCommandBuffer(
1009      int32 surface_id, const GPUCreateCommandBufferConfig& init_params) {
1010  TRACE_EVENT1("gpu",
1011               "RenderThreadImpl::CreateViewCommandBuffer",
1012               "surface_id",
1013               surface_id);
1014
1015  int32 route_id = MSG_ROUTING_NONE;
1016  IPC::Message* message = new GpuHostMsg_CreateViewCommandBuffer(
1017      surface_id,
1018      init_params,
1019      &route_id);
1020
1021  // Allow calling this from the compositor thread.
1022  if (base::MessageLoop::current() == message_loop())
1023    ChildThread::Send(message);
1024  else
1025    sync_message_filter()->Send(message);
1026
1027  return route_id;
1028}
1029
1030void RenderThreadImpl::CreateImage(
1031    gfx::PluginWindowHandle window,
1032    int32 image_id,
1033    const CreateImageCallback& callback) {
1034  NOTREACHED();
1035}
1036
1037void RenderThreadImpl::DeleteImage(int32 image_id, int32 sync_point) {
1038  NOTREACHED();
1039}
1040
1041void RenderThreadImpl::DoNotSuspendWebKitSharedTimer() {
1042  suspend_webkit_shared_timer_ = false;
1043}
1044
1045void RenderThreadImpl::DoNotNotifyWebKitOfModalLoop() {
1046  notify_webkit_of_modal_loop_ = false;
1047}
1048
1049void RenderThreadImpl::OnSetZoomLevelForCurrentURL(const std::string& scheme,
1050                                                   const std::string& host,
1051                                                   double zoom_level) {
1052  RenderViewZoomer zoomer(scheme, host, zoom_level);
1053  RenderView::ForEach(&zoomer);
1054}
1055
1056bool RenderThreadImpl::OnControlMessageReceived(const IPC::Message& msg) {
1057  ObserverListBase<RenderProcessObserver>::Iterator it(observers_);
1058  RenderProcessObserver* observer;
1059  while ((observer = it.GetNext()) != NULL) {
1060    if (observer->OnControlMessageReceived(msg))
1061      return true;
1062  }
1063
1064  // Some messages are handled by delegates.
1065  if (appcache_dispatcher_->OnMessageReceived(msg) ||
1066      dom_storage_dispatcher_->OnMessageReceived(msg)) {
1067    return true;
1068  }
1069
1070  bool handled = true;
1071  IPC_BEGIN_MESSAGE_MAP(RenderThreadImpl, msg)
1072    IPC_MESSAGE_HANDLER(ViewMsg_SetZoomLevelForCurrentURL,
1073                        OnSetZoomLevelForCurrentURL)
1074    // TODO(port): removed from render_messages_internal.h;
1075    // is there a new non-windows message I should add here?
1076    IPC_MESSAGE_HANDLER(ViewMsg_New, OnCreateNewView)
1077    IPC_MESSAGE_HANDLER(ViewMsg_PurgePluginListCache, OnPurgePluginListCache)
1078    IPC_MESSAGE_HANDLER(ViewMsg_NetworkStateChanged, OnNetworkStateChanged)
1079    IPC_MESSAGE_HANDLER(ViewMsg_TempCrashWithData, OnTempCrashWithData)
1080    IPC_MESSAGE_HANDLER(ViewMsg_SetWebKitSharedTimersSuspended,
1081                        OnSetWebKitSharedTimersSuspended)
1082    IPC_MESSAGE_UNHANDLED(handled = false)
1083  IPC_END_MESSAGE_MAP()
1084  return handled;
1085}
1086
1087void RenderThreadImpl::OnCreateNewView(const ViewMsg_New_Params& params) {
1088  EnsureWebKitInitialized();
1089  // When bringing in render_view, also bring in webkit's glue and jsbindings.
1090  RenderViewImpl::Create(
1091      params.opener_route_id,
1092      params.renderer_preferences,
1093      params.web_preferences,
1094      new SharedRenderViewCounter(0),
1095      params.view_id,
1096      params.main_frame_routing_id,
1097      params.surface_id,
1098      params.session_storage_namespace_id,
1099      params.frame_name,
1100      false,
1101      params.swapped_out,
1102      params.next_page_id,
1103      params.screen_info,
1104      params.accessibility_mode,
1105      params.allow_partial_swap);
1106}
1107
1108GpuChannelHost* RenderThreadImpl::EstablishGpuChannelSync(
1109    CauseForGpuLaunch cause_for_gpu_launch) {
1110  TRACE_EVENT0("gpu", "RenderThreadImpl::EstablishGpuChannelSync");
1111
1112  if (gpu_channel_.get()) {
1113    // Do nothing if we already have a GPU channel or are already
1114    // establishing one.
1115    if (!gpu_channel_->IsLost())
1116      return gpu_channel_.get();
1117
1118    // Recreate the channel if it has been lost.
1119    gpu_channel_ = NULL;
1120  }
1121
1122  // Ask the browser for the channel name.
1123  int client_id = 0;
1124  IPC::ChannelHandle channel_handle;
1125  gpu::GPUInfo gpu_info;
1126  if (!Send(new GpuHostMsg_EstablishGpuChannel(cause_for_gpu_launch,
1127                                               &client_id,
1128                                               &channel_handle,
1129                                               &gpu_info)) ||
1130#if defined(OS_POSIX)
1131      channel_handle.socket.fd == -1 ||
1132#endif
1133      channel_handle.name.empty()) {
1134    // Otherwise cancel the connection.
1135    return NULL;
1136  }
1137
1138  GetContentClient()->SetGpuInfo(gpu_info);
1139  gpu_channel_ = GpuChannelHost::Create(
1140      this, 0, client_id, gpu_info, channel_handle);
1141  return gpu_channel_.get();
1142}
1143
1144WebKit::WebMediaStreamCenter* RenderThreadImpl::CreateMediaStreamCenter(
1145    WebKit::WebMediaStreamCenterClient* client) {
1146#if defined(OS_ANDROID)
1147  if (CommandLine::ForCurrentProcess()->HasSwitch(
1148      switches::kDisableWebRTC))
1149    return NULL;
1150#endif
1151
1152#if defined(ENABLE_WEBRTC)
1153  if (!media_stream_center_) {
1154    media_stream_center_ = GetContentClient()->renderer()
1155        ->OverrideCreateWebMediaStreamCenter(client);
1156    if (!media_stream_center_) {
1157      media_stream_center_ = new MediaStreamCenter(
1158          client, GetMediaStreamDependencyFactory());
1159    }
1160  }
1161#endif
1162  return media_stream_center_;
1163}
1164
1165MediaStreamDependencyFactory*
1166RenderThreadImpl::GetMediaStreamDependencyFactory() {
1167#if defined(ENABLE_WEBRTC)
1168  if (!media_stream_factory_) {
1169    media_stream_factory_.reset(new MediaStreamDependencyFactory(
1170        vc_manager_.get(), p2p_socket_dispatcher_.get()));
1171  }
1172#endif
1173  return media_stream_factory_.get();
1174}
1175
1176GpuChannelHost* RenderThreadImpl::GetGpuChannel() {
1177  if (!gpu_channel_.get())
1178    return NULL;
1179
1180  if (gpu_channel_->IsLost())
1181    return NULL;
1182
1183  return gpu_channel_.get();
1184}
1185
1186void RenderThreadImpl::OnPurgePluginListCache(bool reload_pages) {
1187  EnsureWebKitInitialized();
1188  // The call below will cause a GetPlugins call with refresh=true, but at this
1189  // point we already know that the browser has refreshed its list, so disable
1190  // refresh temporarily to prevent each renderer process causing the list to be
1191  // regenerated.
1192  webkit_platform_support_->set_plugin_refresh_allowed(false);
1193  WebKit::resetPluginCache(reload_pages);
1194  webkit_platform_support_->set_plugin_refresh_allowed(true);
1195
1196  FOR_EACH_OBSERVER(RenderProcessObserver, observers_, PluginListChanged());
1197}
1198
1199void RenderThreadImpl::OnNetworkStateChanged(bool online) {
1200  EnsureWebKitInitialized();
1201  WebNetworkStateNotifier::setOnLine(online);
1202}
1203
1204void RenderThreadImpl::OnTempCrashWithData(const GURL& data) {
1205  GetContentClient()->SetActiveURL(data);
1206  CHECK(false);
1207}
1208
1209void RenderThreadImpl::OnSetWebKitSharedTimersSuspended(bool suspend) {
1210  ToggleWebKitSharedTimer(suspend);
1211}
1212
1213scoped_refptr<base::MessageLoopProxy>
1214RenderThreadImpl::GetFileThreadMessageLoopProxy() {
1215  DCHECK(message_loop() == base::MessageLoop::current());
1216  if (!file_thread_) {
1217    file_thread_.reset(new base::Thread("Renderer::FILE"));
1218    file_thread_->Start();
1219  }
1220  return file_thread_->message_loop_proxy();
1221}
1222
1223scoped_refptr<base::MessageLoopProxy>
1224RenderThreadImpl::GetMediaThreadMessageLoopProxy() {
1225  DCHECK(message_loop() == base::MessageLoop::current());
1226  if (!media_thread_) {
1227    media_thread_.reset(new base::Thread("Media"));
1228    media_thread_->Start();
1229  }
1230  return media_thread_->message_loop_proxy();
1231}
1232
1233void RenderThreadImpl::SetFlingCurveParameters(
1234    const std::vector<float>& new_touchpad,
1235    const std::vector<float>& new_touchscreen) {
1236  webkit_platform_support_->SetFlingCurveParameters(new_touchpad,
1237                                                    new_touchscreen);
1238
1239}
1240
1241}  // namespace content
1242