| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2011 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.h" | |
| 6 | |
| 7 #include <algorithm> | |
| 8 #include <limits> | |
| 9 #include <map> | |
| 10 #include <vector> | |
| 11 | |
| 12 #include "base/command_line.h" | |
| 13 #include "base/debug/trace_event.h" | |
| 14 #include "base/lazy_instance.h" | |
| 15 #include "base/logging.h" | |
| 16 #include "base/metrics/field_trial.h" | |
| 17 #include "base/metrics/histogram.h" | |
| 18 #include "base/metrics/stats_table.h" | |
| 19 #include "base/process_util.h" | |
| 20 #include "base/shared_memory.h" | |
| 21 #include "base/task.h" | |
| 22 #include "base/threading/thread_local.h" | |
| 23 #include "base/values.h" | |
| 24 #include "content/common/appcache/appcache_dispatcher.h" | |
| 25 #include "content/common/content_switches.h" | |
| 26 #include "content/common/database_messages.h" | |
| 27 #include "content/common/db_message_filter.h" | |
| 28 #include "content/common/dom_storage_messages.h" | |
| 29 #include "content/common/gpu/gpu_messages.h" | |
| 30 #include "content/common/npobject_util.h" | |
| 31 #include "content/common/plugin_messages.h" | |
| 32 #include "content/common/renderer_preferences.h" | |
| 33 #include "content/common/resource_messages.h" | |
| 34 #include "content/common/view_messages.h" | |
| 35 #include "content/common/web_database_observer_impl.h" | |
| 36 #include "content/public/renderer/content_renderer_client.h" | |
| 37 #include "content/public/renderer/render_process_observer.h" | |
| 38 #include "content/public/renderer/render_view_visitor.h" | |
| 39 #include "content/renderer/devtools_agent_filter.h" | |
| 40 #include "content/renderer/gpu/compositor_thread.h" | |
| 41 #include "content/renderer/gpu/gpu_channel_host.h" | |
| 42 #include "content/renderer/indexed_db_dispatcher.h" | |
| 43 #include "content/renderer/media/audio_input_message_filter.h" | |
| 44 #include "content/renderer/media/audio_message_filter.h" | |
| 45 #include "content/renderer/media/video_capture_impl_manager.h" | |
| 46 #include "content/renderer/media/video_capture_message_filter.h" | |
| 47 #include "content/renderer/plugin_channel_host.h" | |
| 48 #include "content/renderer/render_process_impl.h" | |
| 49 #include "content/renderer/render_view.h" | |
| 50 #include "content/renderer/renderer_webidbfactory_impl.h" | |
| 51 #include "content/renderer/renderer_webkitplatformsupport_impl.h" | |
| 52 #include "ipc/ipc_channel_handle.h" | |
| 53 #include "ipc/ipc_platform_file.h" | |
| 54 #include "net/base/net_errors.h" | |
| 55 #include "net/base/net_util.h" | |
| 56 #include "third_party/tcmalloc/chromium/src/google/malloc_extension.h" | |
| 57 #include "third_party/WebKit/Source/WebKit/chromium/public/WebColor.h" | |
| 58 #include "third_party/WebKit/Source/WebKit/chromium/public/WebDatabase.h" | |
| 59 #include "third_party/WebKit/Source/WebKit/chromium/public/WebDocument.h" | |
| 60 #include "third_party/WebKit/Source/WebKit/chromium/public/WebFrame.h" | |
| 61 #include "third_party/WebKit/Source/WebKit/chromium/public/WebKit.h" | |
| 62 #include "third_party/WebKit/Source/WebKit/chromium/public/WebNetworkStateNotifi
er.h" | |
| 63 #include "third_party/WebKit/Source/WebKit/chromium/public/WebPopupMenu.h" | |
| 64 #include "third_party/WebKit/Source/WebKit/chromium/public/WebRuntimeFeatures.h" | |
| 65 #include "third_party/WebKit/Source/WebKit/chromium/public/WebScriptController.h
" | |
| 66 #include "third_party/WebKit/Source/WebKit/chromium/public/WebStorageEventDispat
cher.h" | |
| 67 #include "third_party/WebKit/Source/WebKit/chromium/public/WebString.h" | |
| 68 #include "third_party/WebKit/Source/WebKit/chromium/public/WebView.h" | |
| 69 #include "ui/base/ui_base_switches.h" | |
| 70 #include "v8/include/v8.h" | |
| 71 #include "webkit/extensions/v8/playback_extension.h" | |
| 72 #include "webkit/glue/webkit_glue.h" | |
| 73 | |
| 74 // TODO(port) | |
| 75 #if defined(OS_WIN) | |
| 76 #include "content/common/child_process_messages.h" | |
| 77 #else | |
| 78 #include "base/memory/scoped_handle.h" | |
| 79 #include "content/common/np_channel_base.h" | |
| 80 #endif | |
| 81 | |
| 82 #if defined(OS_WIN) | |
| 83 #include <windows.h> | |
| 84 #include <objbase.h> | |
| 85 #endif | |
| 86 | |
| 87 #if defined(OS_POSIX) | |
| 88 #include "ipc/ipc_channel_posix.h" | |
| 89 #endif | |
| 90 | |
| 91 using WebKit::WebDocument; | |
| 92 using WebKit::WebFrame; | |
| 93 using WebKit::WebNetworkStateNotifier; | |
| 94 using WebKit::WebRuntimeFeatures; | |
| 95 using WebKit::WebScriptController; | |
| 96 using WebKit::WebString; | |
| 97 using WebKit::WebStorageEventDispatcher; | |
| 98 using WebKit::WebView; | |
| 99 using content::RenderProcessObserver; | |
| 100 | |
| 101 namespace { | |
| 102 static const double kInitialIdleHandlerDelayS = 1.0 /* seconds */; | |
| 103 | |
| 104 #if defined(TOUCH_UI) | |
| 105 static const int kPopupListBoxMinimumRowHeight = 60; | |
| 106 #endif | |
| 107 | |
| 108 // Keep the global RenderThread in a TLS slot so it is impossible to access | |
| 109 // incorrectly from the wrong thread. | |
| 110 static base::LazyInstance<base::ThreadLocalPointer<RenderThread> > lazy_tls( | |
| 111 base::LINKER_INITIALIZED); | |
| 112 | |
| 113 class RenderViewZoomer : public content::RenderViewVisitor { | |
| 114 public: | |
| 115 RenderViewZoomer(const GURL& url, double zoom_level) | |
| 116 : zoom_level_(zoom_level) { | |
| 117 host_ = net::GetHostOrSpecFromURL(url); | |
| 118 } | |
| 119 | |
| 120 virtual bool Visit(RenderView* render_view) { | |
| 121 WebView* webview = render_view->webview(); | |
| 122 WebDocument document = webview->mainFrame()->document(); | |
| 123 | |
| 124 // Don't set zoom level for full-page plugin since they don't use the same | |
| 125 // zoom settings. | |
| 126 if (document.isPluginDocument()) | |
| 127 return true; | |
| 128 | |
| 129 if (net::GetHostOrSpecFromURL(GURL(document.url())) == host_) | |
| 130 webview->setZoomLevel(false, zoom_level_); | |
| 131 return true; | |
| 132 } | |
| 133 | |
| 134 private: | |
| 135 std::string host_; | |
| 136 double zoom_level_; | |
| 137 | |
| 138 DISALLOW_COPY_AND_ASSIGN(RenderViewZoomer); | |
| 139 }; | |
| 140 | |
| 141 } // namespace | |
| 142 | |
| 143 // TODO(jam): move this to content/public/renderer/render_thread.cc once this fi
le is renamed | |
| 144 namespace content { | |
| 145 | |
| 146 // Keep the global RenderThread in a TLS slot so it is impossible to access | |
| 147 // incorrectly from the wrong thread. | |
| 148 static base::LazyInstance<base::ThreadLocalPointer<RenderThread> > lazy_tls( | |
| 149 base::LINKER_INITIALIZED); | |
| 150 | |
| 151 RenderThread* RenderThread::Get() { | |
| 152 return lazy_tls.Pointer()->Get(); | |
| 153 } | |
| 154 | |
| 155 RenderThread::RenderThread() { | |
| 156 lazy_tls.Pointer()->Set(this); | |
| 157 } | |
| 158 | |
| 159 RenderThread::~RenderThread() { | |
| 160 lazy_tls.Pointer()->Set(NULL); | |
| 161 } | |
| 162 | |
| 163 } // namespace content | |
| 164 | |
| 165 | |
| 166 static void* CreateHistogram( | |
| 167 const char *name, int min, int max, size_t buckets) { | |
| 168 if (min <= 0) | |
| 169 min = 1; | |
| 170 base::Histogram* histogram = base::Histogram::FactoryGet( | |
| 171 name, min, max, buckets, base::Histogram::kUmaTargetedHistogramFlag); | |
| 172 return histogram; | |
| 173 } | |
| 174 | |
| 175 static void AddHistogramSample(void* hist, int sample) { | |
| 176 base::Histogram* histogram = static_cast<base::Histogram*>(hist); | |
| 177 histogram->Add(sample); | |
| 178 } | |
| 179 | |
| 180 RenderThread* RenderThread::current() { | |
| 181 return lazy_tls.Pointer()->Get(); | |
| 182 } | |
| 183 | |
| 184 // When we run plugins in process, we actually run them on the render thread, | |
| 185 // which means that we need to make the render thread pump UI events. | |
| 186 RenderThread::RenderThread() { | |
| 187 Init(); | |
| 188 } | |
| 189 | |
| 190 RenderThread::RenderThread(const std::string& channel_name) | |
| 191 : ChildThread(channel_name) { | |
| 192 Init(); | |
| 193 } | |
| 194 | |
| 195 void RenderThread::Init() { | |
| 196 TRACE_EVENT_BEGIN_ETW("RenderThread::Init", 0, ""); | |
| 197 | |
| 198 #if defined(OS_MACOSX) | |
| 199 // On Mac, the select popups are rendered by the browser. | |
| 200 WebKit::WebView::setUseExternalPopupMenus(true); | |
| 201 #endif | |
| 202 | |
| 203 lazy_tls.Pointer()->Set(this); | |
| 204 #if defined(OS_WIN) | |
| 205 // If you are running plugins in this thread you need COM active but in | |
| 206 // the normal case you don't. | |
| 207 if (RenderProcessImpl::InProcessPlugins()) | |
| 208 CoInitialize(0); | |
| 209 #endif | |
| 210 | |
| 211 // In single process the single process is all there is. | |
| 212 suspend_webkit_shared_timer_ = true; | |
| 213 notify_webkit_of_modal_loop_ = true; | |
| 214 plugin_refresh_allowed_ = true; | |
| 215 widget_count_ = 0; | |
| 216 hidden_widget_count_ = 0; | |
| 217 idle_notification_delay_in_s_ = kInitialIdleHandlerDelayS; | |
| 218 task_factory_.reset(new ScopedRunnableMethodFactory<RenderThread>(this)); | |
| 219 | |
| 220 appcache_dispatcher_.reset(new AppCacheDispatcher(Get())); | |
| 221 indexed_db_dispatcher_.reset(new IndexedDBDispatcher()); | |
| 222 | |
| 223 db_message_filter_ = new DBMessageFilter(); | |
| 224 AddFilter(db_message_filter_.get()); | |
| 225 | |
| 226 vc_manager_ = new VideoCaptureImplManager(); | |
| 227 AddFilter(vc_manager_->video_capture_message_filter()); | |
| 228 | |
| 229 audio_input_message_filter_ = new AudioInputMessageFilter(); | |
| 230 AddFilter(audio_input_message_filter_.get()); | |
| 231 | |
| 232 audio_message_filter_ = new AudioMessageFilter(); | |
| 233 AddFilter(audio_message_filter_.get()); | |
| 234 | |
| 235 devtools_agent_message_filter_ = new DevToolsAgentFilter(); | |
| 236 AddFilter(devtools_agent_message_filter_.get()); | |
| 237 | |
| 238 content::GetContentClient()->renderer()->RenderThreadStarted(); | |
| 239 | |
| 240 TRACE_EVENT_END_ETW("RenderThread::Init", 0, ""); | |
| 241 } | |
| 242 | |
| 243 RenderThread::~RenderThread() { | |
| 244 FOR_EACH_OBSERVER( | |
| 245 RenderProcessObserver, observers_, OnRenderProcessShutdown()); | |
| 246 | |
| 247 // Wait for all databases to be closed. | |
| 248 if (web_database_observer_impl_.get()) | |
| 249 web_database_observer_impl_->WaitForAllDatabasesToClose(); | |
| 250 | |
| 251 // Shutdown in reverse of the initialization order. | |
| 252 RemoveFilter(devtools_agent_message_filter_.get()); | |
| 253 devtools_agent_message_filter_ = NULL; | |
| 254 | |
| 255 RemoveFilter(audio_input_message_filter_.get()); | |
| 256 audio_input_message_filter_ = NULL; | |
| 257 | |
| 258 RemoveFilter(audio_message_filter_.get()); | |
| 259 audio_message_filter_ = NULL; | |
| 260 | |
| 261 RemoveFilter(vc_manager_->video_capture_message_filter()); | |
| 262 | |
| 263 RemoveFilter(db_message_filter_.get()); | |
| 264 db_message_filter_ = NULL; | |
| 265 | |
| 266 // Shutdown the file thread if it's running. | |
| 267 if (file_thread_.get()) | |
| 268 file_thread_->Stop(); | |
| 269 | |
| 270 if (compositor_thread_.get()) { | |
| 271 RemoveFilter(compositor_thread_->GetMessageFilter()); | |
| 272 compositor_thread_.reset(); | |
| 273 } | |
| 274 | |
| 275 if (webkit_platform_support_.get()) | |
| 276 WebKit::shutdown(); | |
| 277 | |
| 278 lazy_tls.Pointer()->Set(NULL); | |
| 279 | |
| 280 // TODO(port) | |
| 281 #if defined(OS_WIN) | |
| 282 // Clean up plugin channels before this thread goes away. | |
| 283 NPChannelBase::CleanupChannels(); | |
| 284 // Don't call COM if the renderer is in the sandbox. | |
| 285 if (RenderProcessImpl::InProcessPlugins()) | |
| 286 CoUninitialize(); | |
| 287 #endif | |
| 288 } | |
| 289 | |
| 290 bool RenderThread::Send(IPC::Message* msg) { | |
| 291 // Certain synchronous messages cannot always be processed synchronously by | |
| 292 // the browser, e.g., Chrome frame communicating with the embedding browser. | |
| 293 // This could cause a complete hang of Chrome if a windowed plug-in is trying | |
| 294 // to communicate with the renderer thread since the browser's UI thread | |
| 295 // could be stuck (within a Windows API call) trying to synchronously | |
| 296 // communicate with the plug-in. The remedy is to pump messages on this | |
| 297 // thread while the browser is processing this request. This creates an | |
| 298 // opportunity for re-entrancy into WebKit, so we need to take care to disable | |
| 299 // callbacks, timers, and pending network loads that could trigger such | |
| 300 // callbacks. | |
| 301 bool pumping_events = false; | |
| 302 if (msg->is_sync()) { | |
| 303 if (msg->is_caller_pumping_messages()) { | |
| 304 pumping_events = true; | |
| 305 } else { | |
| 306 if ((msg->type() == ViewHostMsg_GetCookies::ID || | |
| 307 msg->type() == ViewHostMsg_GetRawCookies::ID || | |
| 308 msg->type() == ViewHostMsg_CookiesEnabled::ID) && | |
| 309 content::GetContentClient()->renderer()-> | |
| 310 ShouldPumpEventsDuringCookieMessage()) { | |
| 311 pumping_events = true; | |
| 312 } | |
| 313 } | |
| 314 } | |
| 315 | |
| 316 bool suspend_webkit_shared_timer = true; // default value | |
| 317 std::swap(suspend_webkit_shared_timer, suspend_webkit_shared_timer_); | |
| 318 | |
| 319 bool notify_webkit_of_modal_loop = true; // default value | |
| 320 std::swap(notify_webkit_of_modal_loop, notify_webkit_of_modal_loop_); | |
| 321 | |
| 322 gfx::NativeViewId host_window = 0; | |
| 323 | |
| 324 if (pumping_events) { | |
| 325 if (suspend_webkit_shared_timer) | |
| 326 webkit_platform_support_->SuspendSharedTimer(); | |
| 327 | |
| 328 if (notify_webkit_of_modal_loop) | |
| 329 WebView::willEnterModalLoop(); | |
| 330 | |
| 331 RenderWidget* widget = | |
| 332 static_cast<RenderWidget*>(ResolveRoute(msg->routing_id())); | |
| 333 if (widget) { | |
| 334 host_window = widget->host_window(); | |
| 335 PluginChannelHost::Broadcast( | |
| 336 new PluginMsg_SignalModalDialogEvent(host_window)); | |
| 337 } | |
| 338 } | |
| 339 | |
| 340 bool rv = ChildThread::Send(msg); | |
| 341 | |
| 342 if (pumping_events) { | |
| 343 if (host_window) { | |
| 344 PluginChannelHost::Broadcast( | |
| 345 new PluginMsg_ResetModalDialogEvent(host_window)); | |
| 346 } | |
| 347 | |
| 348 if (notify_webkit_of_modal_loop) | |
| 349 WebView::didExitModalLoop(); | |
| 350 | |
| 351 if (suspend_webkit_shared_timer) | |
| 352 webkit_platform_support_->ResumeSharedTimer(); | |
| 353 } | |
| 354 | |
| 355 return rv; | |
| 356 } | |
| 357 | |
| 358 MessageLoop* RenderThread::GetMessageLoop() { | |
| 359 return message_loop(); | |
| 360 } | |
| 361 | |
| 362 IPC::SyncChannel* RenderThread::GetChannel() { | |
| 363 return channel(); | |
| 364 } | |
| 365 | |
| 366 ResourceDispatcher* RenderThread::GetResourceDispatcher() { | |
| 367 return resource_dispatcher(); | |
| 368 } | |
| 369 | |
| 370 std::string RenderThread::GetLocale() { | |
| 371 // The browser process should have passed the locale to the renderer via the | |
| 372 // --lang command line flag. In single process mode, this will return the | |
| 373 // wrong value. TODO(tc): Fix this for single process mode. | |
| 374 const CommandLine& parsed_command_line = *CommandLine::ForCurrentProcess(); | |
| 375 const std::string& lang = | |
| 376 parsed_command_line.GetSwitchValueASCII(switches::kLang); | |
| 377 DCHECK(!lang.empty() || | |
| 378 (!parsed_command_line.HasSwitch(switches::kRendererProcess) && | |
| 379 !parsed_command_line.HasSwitch(switches::kPluginProcess))); | |
| 380 return lang; | |
| 381 } | |
| 382 | |
| 383 void RenderThread::AddRoute(int32 routing_id, | |
| 384 IPC::Channel::Listener* listener) { | |
| 385 widget_count_++; | |
| 386 return ChildThread::AddRoute(routing_id, listener); | |
| 387 } | |
| 388 | |
| 389 void RenderThread::RemoveRoute(int32 routing_id) { | |
| 390 widget_count_--; | |
| 391 return ChildThread::RemoveRoute(routing_id); | |
| 392 } | |
| 393 | |
| 394 void RenderThread::AddFilter(IPC::ChannelProxy::MessageFilter* filter) { | |
| 395 channel()->AddFilter(filter); | |
| 396 } | |
| 397 | |
| 398 void RenderThread::RemoveFilter(IPC::ChannelProxy::MessageFilter* filter) { | |
| 399 channel()->RemoveFilter(filter); | |
| 400 } | |
| 401 | |
| 402 void RenderThread::SetOutgoingMessageFilter( | |
| 403 IPC::ChannelProxy::OutgoingMessageFilter* filter) { | |
| 404 } | |
| 405 | |
| 406 void RenderThread::AddObserver(content::RenderProcessObserver* observer) { | |
| 407 observers_.AddObserver(observer); | |
| 408 } | |
| 409 | |
| 410 void RenderThread::RemoveObserver(content::RenderProcessObserver* observer) { | |
| 411 observers_.RemoveObserver(observer); | |
| 412 } | |
| 413 | |
| 414 void RenderThread::WidgetHidden() { | |
| 415 DCHECK(hidden_widget_count_ < widget_count_); | |
| 416 hidden_widget_count_++; | |
| 417 | |
| 418 if (!content::GetContentClient()->renderer()-> | |
| 419 RunIdleHandlerWhenWidgetsHidden()) { | |
| 420 return; | |
| 421 } | |
| 422 | |
| 423 if (widget_count_ && hidden_widget_count_ == widget_count_) | |
| 424 ScheduleIdleHandler(kInitialIdleHandlerDelayS); | |
| 425 } | |
| 426 | |
| 427 void RenderThread::WidgetRestored() { | |
| 428 DCHECK_GT(hidden_widget_count_, 0); | |
| 429 hidden_widget_count_--; | |
| 430 if (!content::GetContentClient()->renderer()-> | |
| 431 RunIdleHandlerWhenWidgetsHidden()) { | |
| 432 return; | |
| 433 } | |
| 434 | |
| 435 idle_timer_.Stop(); | |
| 436 } | |
| 437 | |
| 438 void RenderThread::EnsureWebKitInitialized() { | |
| 439 if (webkit_platform_support_.get()) | |
| 440 return; | |
| 441 | |
| 442 v8::V8::SetCounterFunction(base::StatsTable::FindLocation); | |
| 443 v8::V8::SetCreateHistogramFunction(CreateHistogram); | |
| 444 v8::V8::SetAddHistogramSampleFunction(AddHistogramSample); | |
| 445 | |
| 446 webkit_platform_support_.reset(new RendererWebKitPlatformSupportImpl); | |
| 447 WebKit::initialize(webkit_platform_support_.get()); | |
| 448 | |
| 449 compositor_thread_.reset(new CompositorThread(this)); | |
| 450 AddFilter(compositor_thread_->GetMessageFilter()); | |
| 451 | |
| 452 WebScriptController::enableV8SingleThreadMode(); | |
| 453 | |
| 454 const CommandLine& command_line = *CommandLine::ForCurrentProcess(); | |
| 455 | |
| 456 webkit_glue::EnableWebCoreLogChannels( | |
| 457 command_line.GetSwitchValueASCII(switches::kWebCoreLogChannels)); | |
| 458 | |
| 459 if (command_line.HasSwitch(switches::kPlaybackMode) || | |
| 460 command_line.HasSwitch(switches::kRecordMode) || | |
| 461 command_line.HasSwitch(switches::kNoJsRandomness)) { | |
| 462 RegisterExtension(extensions_v8::PlaybackExtension::Get()); | |
| 463 } | |
| 464 | |
| 465 web_database_observer_impl_.reset(new WebDatabaseObserverImpl(Get())); | |
| 466 WebKit::WebDatabase::setObserver(web_database_observer_impl_.get()); | |
| 467 | |
| 468 WebRuntimeFeatures::enableSockets( | |
| 469 !command_line.HasSwitch(switches::kDisableWebSockets)); | |
| 470 | |
| 471 WebRuntimeFeatures::enableDatabase( | |
| 472 !command_line.HasSwitch(switches::kDisableDatabases)); | |
| 473 | |
| 474 WebRuntimeFeatures::enableDataTransferItems( | |
| 475 !command_line.HasSwitch(switches::kDisableDataTransferItems)); | |
| 476 | |
| 477 WebRuntimeFeatures::enableApplicationCache( | |
| 478 !command_line.HasSwitch(switches::kDisableApplicationCache)); | |
| 479 | |
| 480 WebRuntimeFeatures::enableNotifications( | |
| 481 !command_line.HasSwitch(switches::kDisableDesktopNotifications)); | |
| 482 | |
| 483 WebRuntimeFeatures::enableLocalStorage( | |
| 484 !command_line.HasSwitch(switches::kDisableLocalStorage)); | |
| 485 WebRuntimeFeatures::enableSessionStorage( | |
| 486 !command_line.HasSwitch(switches::kDisableSessionStorage)); | |
| 487 | |
| 488 WebRuntimeFeatures::enableIndexedDatabase( | |
| 489 !command_line.HasSwitch(switches::kDisableIndexedDatabase)); | |
| 490 | |
| 491 WebRuntimeFeatures::enableGeolocation( | |
| 492 !command_line.HasSwitch(switches::kDisableGeolocation)); | |
| 493 | |
| 494 WebKit::WebRuntimeFeatures::enableMediaStream( | |
| 495 command_line.HasSwitch(switches::kEnableMediaStream)); | |
| 496 | |
| 497 WebKit::WebRuntimeFeatures::enableFullScreenAPI( | |
| 498 !command_line.HasSwitch(switches::kDisableFullScreen)); | |
| 499 | |
| 500 #if defined(OS_CHROMEOS) | |
| 501 // TODO(crogers): enable once Web Audio has been tested and optimized. | |
| 502 WebRuntimeFeatures::enableWebAudio(false); | |
| 503 #else | |
| 504 WebRuntimeFeatures::enableWebAudio( | |
| 505 !command_line.HasSwitch(switches::kDisableWebAudio)); | |
| 506 #endif | |
| 507 | |
| 508 WebRuntimeFeatures::enablePushState(true); | |
| 509 | |
| 510 #ifdef TOUCH_UI | |
| 511 WebRuntimeFeatures::enableTouch(true); | |
| 512 WebKit::WebPopupMenu::setMinimumRowHeight(kPopupListBoxMinimumRowHeight); | |
| 513 #else | |
| 514 // TODO(saintlou): in the future touch should always be enabled | |
| 515 WebRuntimeFeatures::enableTouch(false); | |
| 516 #endif | |
| 517 | |
| 518 WebRuntimeFeatures::enableDeviceMotion( | |
| 519 command_line.HasSwitch(switches::kEnableDeviceMotion)); | |
| 520 | |
| 521 WebRuntimeFeatures::enableDeviceOrientation( | |
| 522 !command_line.HasSwitch(switches::kDisableDeviceOrientation)); | |
| 523 | |
| 524 WebRuntimeFeatures::enableSpeechInput( | |
| 525 !command_line.HasSwitch(switches::kDisableSpeechInput)); | |
| 526 | |
| 527 WebRuntimeFeatures::enableFileSystem( | |
| 528 !command_line.HasSwitch(switches::kDisableFileSystem)); | |
| 529 | |
| 530 WebRuntimeFeatures::enableJavaScriptI18NAPI( | |
| 531 !command_line.HasSwitch(switches::kDisableJavaScriptI18NAPI)); | |
| 532 | |
| 533 WebRuntimeFeatures::enableQuota(true); | |
| 534 | |
| 535 FOR_EACH_OBSERVER(RenderProcessObserver, observers_, WebKitInitialized()); | |
| 536 } | |
| 537 | |
| 538 void RenderThread::RecordUserMetrics(const std::string& action) { | |
| 539 Send(new ViewHostMsg_UserMetricsRecordAction(action)); | |
| 540 } | |
| 541 | |
| 542 void RenderThread::RegisterExtension(v8::Extension* extension) { | |
| 543 WebScriptController::registerExtension(extension); | |
| 544 v8_extensions_.insert(extension->name()); | |
| 545 } | |
| 546 | |
| 547 bool RenderThread::IsRegisteredExtension( | |
| 548 const std::string& v8_extension_name) const { | |
| 549 return v8_extensions_.find(v8_extension_name) != v8_extensions_.end(); | |
| 550 } | |
| 551 | |
| 552 void RenderThread::ScheduleIdleHandler(double initial_delay_s) { | |
| 553 idle_notification_delay_in_s_ = initial_delay_s; | |
| 554 idle_timer_.Stop(); | |
| 555 idle_timer_.Start(FROM_HERE, | |
| 556 base::TimeDelta::FromSeconds(static_cast<int64>(initial_delay_s)), | |
| 557 this, &RenderThread::IdleHandler); | |
| 558 } | |
| 559 | |
| 560 void RenderThread::IdleHandler() { | |
| 561 #if !defined(OS_MACOSX) && defined(USE_TCMALLOC) | |
| 562 MallocExtension::instance()->ReleaseFreeMemory(); | |
| 563 #endif | |
| 564 | |
| 565 v8::V8::IdleNotification(); | |
| 566 | |
| 567 // Schedule next invocation. | |
| 568 // Dampen the delay using the algorithm: | |
| 569 // delay = delay + 1 / (delay + 2) | |
| 570 // Using floor(delay) has a dampening effect such as: | |
| 571 // 1s, 1, 1, 2, 2, 2, 2, 3, 3, ... | |
| 572 // Note that idle_notification_delay_in_s_ would be reset to | |
| 573 // kInitialIdleHandlerDelayS in RenderThread::WidgetHidden. | |
| 574 ScheduleIdleHandler(idle_notification_delay_in_s_ + | |
| 575 1.0 / (idle_notification_delay_in_s_ + 2.0)); | |
| 576 | |
| 577 FOR_EACH_OBSERVER(RenderProcessObserver, observers_, IdleNotification()); | |
| 578 } | |
| 579 | |
| 580 double RenderThread::GetIdleNotificationDelayInS() const { | |
| 581 return idle_notification_delay_in_s_; | |
| 582 } | |
| 583 | |
| 584 void RenderThread::SetIdleNotificationDelayInS( | |
| 585 double idle_notification_delay_in_s) { | |
| 586 idle_notification_delay_in_s_ = idle_notification_delay_in_s; | |
| 587 } | |
| 588 | |
| 589 #if defined(OS_WIN) | |
| 590 void RenderThread::PreCacheFont(const LOGFONT& log_font) { | |
| 591 Send(new ChildProcessHostMsg_PreCacheFont(log_font)); | |
| 592 } | |
| 593 | |
| 594 void RenderThread::ReleaseCachedFonts() { | |
| 595 Send(new ChildProcessHostMsg_ReleaseCachedFonts()); | |
| 596 } | |
| 597 | |
| 598 #endif // OS_WIN | |
| 599 | |
| 600 int32 RenderThread::RoutingIDForCurrentContext() { | |
| 601 int32 routing_id = MSG_ROUTING_CONTROL; | |
| 602 if (v8::Context::InContext()) { | |
| 603 WebFrame* frame = WebFrame::frameForCurrentContext(); | |
| 604 if (frame) { | |
| 605 RenderView* view = RenderView::FromWebView(frame->view()); | |
| 606 if (view) | |
| 607 routing_id = view->routing_id(); | |
| 608 } | |
| 609 } else { | |
| 610 DLOG(WARNING) << "Not called within a script context!"; | |
| 611 } | |
| 612 return routing_id; | |
| 613 } | |
| 614 | |
| 615 void RenderThread::DoNotSuspendWebKitSharedTimer() { | |
| 616 suspend_webkit_shared_timer_ = false; | |
| 617 } | |
| 618 | |
| 619 void RenderThread::DoNotNotifyWebKitOfModalLoop() { | |
| 620 notify_webkit_of_modal_loop_ = false; | |
| 621 } | |
| 622 | |
| 623 void RenderThread::OnSetZoomLevelForCurrentURL(const GURL& url, | |
| 624 double zoom_level) { | |
| 625 RenderViewZoomer zoomer(url, zoom_level); | |
| 626 RenderView::ForEach(&zoomer); | |
| 627 } | |
| 628 | |
| 629 void RenderThread::OnDOMStorageEvent( | |
| 630 const DOMStorageMsg_Event_Params& params) { | |
| 631 if (!dom_storage_event_dispatcher_.get()) | |
| 632 dom_storage_event_dispatcher_.reset(WebStorageEventDispatcher::create()); | |
| 633 dom_storage_event_dispatcher_->dispatchStorageEvent(params.key, | |
| 634 params.old_value, params.new_value, params.origin, params.url, | |
| 635 params.storage_type == DOM_STORAGE_LOCAL); | |
| 636 } | |
| 637 | |
| 638 bool RenderThread::OnControlMessageReceived(const IPC::Message& msg) { | |
| 639 ObserverListBase<RenderProcessObserver>::Iterator it(observers_); | |
| 640 RenderProcessObserver* observer; | |
| 641 while ((observer = it.GetNext()) != NULL) { | |
| 642 if (observer->OnControlMessageReceived(msg)) | |
| 643 return true; | |
| 644 } | |
| 645 | |
| 646 // Some messages are handled by delegates. | |
| 647 if (appcache_dispatcher_->OnMessageReceived(msg)) | |
| 648 return true; | |
| 649 if (indexed_db_dispatcher_->OnMessageReceived(msg)) | |
| 650 return true; | |
| 651 | |
| 652 bool handled = true; | |
| 653 IPC_BEGIN_MESSAGE_MAP(RenderThread, msg) | |
| 654 IPC_MESSAGE_HANDLER(ViewMsg_SetZoomLevelForCurrentURL, | |
| 655 OnSetZoomLevelForCurrentURL) | |
| 656 IPC_MESSAGE_HANDLER(ViewMsg_SetNextPageID, OnSetNextPageID) | |
| 657 IPC_MESSAGE_HANDLER(ViewMsg_SetCSSColors, OnSetCSSColors) | |
| 658 // TODO(port): removed from render_messages_internal.h; | |
| 659 // is there a new non-windows message I should add here? | |
| 660 IPC_MESSAGE_HANDLER(ViewMsg_New, OnCreateNewView) | |
| 661 IPC_MESSAGE_HANDLER(ViewMsg_PurgePluginListCache, OnPurgePluginListCache) | |
| 662 IPC_MESSAGE_HANDLER(ViewMsg_NetworkStateChanged, OnNetworkStateChanged) | |
| 663 IPC_MESSAGE_HANDLER(DOMStorageMsg_Event, OnDOMStorageEvent) | |
| 664 IPC_MESSAGE_UNHANDLED(handled = false) | |
| 665 IPC_END_MESSAGE_MAP() | |
| 666 return handled; | |
| 667 } | |
| 668 | |
| 669 void RenderThread::OnSetNextPageID(int32 next_page_id) { | |
| 670 // This should only be called at process initialization time, so we shouldn't | |
| 671 // have to worry about thread-safety. | |
| 672 RenderView::SetNextPageID(next_page_id); | |
| 673 } | |
| 674 | |
| 675 // Called when to register CSS Color name->system color mappings. | |
| 676 // We update the colors one by one and then tell WebKit to refresh all render | |
| 677 // views. | |
| 678 void RenderThread::OnSetCSSColors( | |
| 679 const std::vector<CSSColors::CSSColorMapping>& colors) { | |
| 680 EnsureWebKitInitialized(); | |
| 681 size_t num_colors = colors.size(); | |
| 682 scoped_array<WebKit::WebColorName> color_names( | |
| 683 new WebKit::WebColorName[num_colors]); | |
| 684 scoped_array<WebKit::WebColor> web_colors(new WebKit::WebColor[num_colors]); | |
| 685 size_t i = 0; | |
| 686 for (std::vector<CSSColors::CSSColorMapping>::const_iterator it = | |
| 687 colors.begin(); | |
| 688 it != colors.end(); | |
| 689 ++it, ++i) { | |
| 690 color_names[i] = it->first; | |
| 691 web_colors[i] = it->second; | |
| 692 } | |
| 693 WebKit::setNamedColors(color_names.get(), web_colors.get(), num_colors); | |
| 694 } | |
| 695 | |
| 696 void RenderThread::OnCreateNewView(const ViewMsg_New_Params& params) { | |
| 697 EnsureWebKitInitialized(); | |
| 698 // When bringing in render_view, also bring in webkit's glue and jsbindings. | |
| 699 RenderView::Create( | |
| 700 this, | |
| 701 params.parent_window, | |
| 702 MSG_ROUTING_NONE, | |
| 703 params.renderer_preferences, | |
| 704 params.web_preferences, | |
| 705 new SharedRenderViewCounter(0), | |
| 706 params.view_id, | |
| 707 params.session_storage_namespace_id, | |
| 708 params.frame_name); | |
| 709 } | |
| 710 | |
| 711 GpuChannelHost* RenderThread::EstablishGpuChannelSync( | |
| 712 content::CauseForGpuLaunch cause_for_gpu_launch) { | |
| 713 if (gpu_channel_.get()) { | |
| 714 // Do nothing if we already have a GPU channel or are already | |
| 715 // establishing one. | |
| 716 if (gpu_channel_->state() == GpuChannelHost::kUnconnected || | |
| 717 gpu_channel_->state() == GpuChannelHost::kConnected) | |
| 718 return GetGpuChannel(); | |
| 719 | |
| 720 // Recreate the channel if it has been lost. | |
| 721 if (gpu_channel_->state() == GpuChannelHost::kLost) | |
| 722 gpu_channel_ = NULL; | |
| 723 } | |
| 724 | |
| 725 if (!gpu_channel_.get()) | |
| 726 gpu_channel_ = new GpuChannelHost; | |
| 727 | |
| 728 // Ask the browser for the channel name. | |
| 729 IPC::ChannelHandle channel_handle; | |
| 730 base::ProcessHandle renderer_process_for_gpu; | |
| 731 GPUInfo gpu_info; | |
| 732 if (!Send(new GpuHostMsg_EstablishGpuChannel(cause_for_gpu_launch, | |
| 733 &channel_handle, | |
| 734 &renderer_process_for_gpu, | |
| 735 &gpu_info)) || | |
| 736 channel_handle.name.empty() || | |
| 737 renderer_process_for_gpu == base::kNullProcessHandle) { | |
| 738 // Otherwise cancel the connection. | |
| 739 gpu_channel_ = NULL; | |
| 740 return NULL; | |
| 741 } | |
| 742 | |
| 743 gpu_channel_->set_gpu_info(gpu_info); | |
| 744 content::GetContentClient()->SetGpuInfo(gpu_info); | |
| 745 | |
| 746 // Connect to the GPU process if a channel name was received. | |
| 747 gpu_channel_->Connect(channel_handle, renderer_process_for_gpu); | |
| 748 | |
| 749 return GetGpuChannel(); | |
| 750 } | |
| 751 | |
| 752 GpuChannelHost* RenderThread::GetGpuChannel() { | |
| 753 if (!gpu_channel_.get()) | |
| 754 return NULL; | |
| 755 | |
| 756 if (gpu_channel_->state() != GpuChannelHost::kConnected) | |
| 757 return NULL; | |
| 758 | |
| 759 return gpu_channel_.get(); | |
| 760 } | |
| 761 | |
| 762 void RenderThread::OnPurgePluginListCache(bool reload_pages) { | |
| 763 EnsureWebKitInitialized(); | |
| 764 // The call below will cause a GetPlugins call with refresh=true, but at this | |
| 765 // point we already know that the browser has refreshed its list, so disable | |
| 766 // refresh temporarily to prevent each renderer process causing the list to be | |
| 767 // regenerated. | |
| 768 plugin_refresh_allowed_ = false; | |
| 769 WebKit::resetPluginCache(reload_pages); | |
| 770 plugin_refresh_allowed_ = true; | |
| 771 } | |
| 772 | |
| 773 void RenderThread::OnNetworkStateChanged(bool online) { | |
| 774 EnsureWebKitInitialized(); | |
| 775 WebNetworkStateNotifier::setOnLine(online); | |
| 776 } | |
| 777 | |
| 778 scoped_refptr<base::MessageLoopProxy> | |
| 779 RenderThread::GetFileThreadMessageLoopProxy() { | |
| 780 DCHECK(message_loop() == MessageLoop::current()); | |
| 781 if (!file_thread_.get()) { | |
| 782 file_thread_.reset(new base::Thread("Renderer::FILE")); | |
| 783 file_thread_->Start(); | |
| 784 } | |
| 785 return file_thread_->message_loop_proxy(); | |
| 786 } | |
| OLD | NEW |