| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2010 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 "build/build_config.h" | |
| 6 | |
| 7 #if defined(OS_WIN) | |
| 8 #include <windows.h> | |
| 9 #include <objidl.h> | |
| 10 #include <mlang.h> | |
| 11 #endif | |
| 12 | |
| 13 #include "chrome/renderer/render_process.h" | |
| 14 | |
| 15 #include "app/surface/transport_dib.h" | |
| 16 #include "base/basictypes.h" | |
| 17 #include "base/command_line.h" | |
| 18 #include "base/compiler_specific.h" | |
| 19 #include "base/file_util.h" | |
| 20 #include "base/message_loop.h" | |
| 21 #include "base/histogram.h" | |
| 22 #include "base/path_service.h" | |
| 23 #include "base/sys_info.h" | |
| 24 // TODO(jar): DNS calls should be renderer specific, not including browser. | |
| 25 #include "chrome/browser/net/dns_global.h" | |
| 26 #include "chrome/common/chrome_switches.h" | |
| 27 #include "chrome/common/chrome_paths.h" | |
| 28 #include "chrome/common/render_messages.h" | |
| 29 #include "chrome/common/nacl_types.h" | |
| 30 #include "chrome/renderer/render_view.h" | |
| 31 #include "ipc/ipc_channel.h" | |
| 32 #include "ipc/ipc_message_utils.h" | |
| 33 #include "media/base/media.h" | |
| 34 #include "media/base/media_switches.h" | |
| 35 #include "native_client/src/trusted/plugin/nacl_entry_points.h" | |
| 36 #include "webkit/glue/webkit_glue.h" | |
| 37 | |
| 38 #if defined(OS_MACOSX) | |
| 39 #include "base/mac_util.h" | |
| 40 #endif | |
| 41 | |
| 42 //----------------------------------------------------------------------------- | |
| 43 | |
| 44 RenderProcess::RenderProcess() | |
| 45 : ALLOW_THIS_IN_INITIALIZER_LIST(shared_mem_cache_cleaner_( | |
| 46 base::TimeDelta::FromSeconds(5), | |
| 47 this, &RenderProcess::ClearTransportDIBCache)), | |
| 48 sequence_number_(0) { | |
| 49 in_process_plugins_ = InProcessPlugins(); | |
| 50 for (size_t i = 0; i < arraysize(shared_mem_cache_); ++i) | |
| 51 shared_mem_cache_[i] = NULL; | |
| 52 | |
| 53 #if defined(OS_WIN) | |
| 54 // HACK: See http://b/issue?id=1024307 for rationale. | |
| 55 if (GetModuleHandle(L"LPK.DLL") == NULL) { | |
| 56 // Makes sure lpk.dll is loaded by gdi32 to make sure ExtTextOut() works | |
| 57 // when buffering into a EMF buffer for printing. | |
| 58 typedef BOOL (__stdcall *GdiInitializeLanguagePack)(int LoadedShapingDLLs); | |
| 59 GdiInitializeLanguagePack gdi_init_lpk = | |
| 60 reinterpret_cast<GdiInitializeLanguagePack>(GetProcAddress( | |
| 61 GetModuleHandle(L"GDI32.DLL"), | |
| 62 "GdiInitializeLanguagePack")); | |
| 63 DCHECK(gdi_init_lpk); | |
| 64 if (gdi_init_lpk) { | |
| 65 gdi_init_lpk(0); | |
| 66 } | |
| 67 } | |
| 68 #endif | |
| 69 | |
| 70 // Out of process dev tools rely upon auto break behavior. | |
| 71 webkit_glue::SetJavaScriptFlags( | |
| 72 L"--debugger-auto-break" | |
| 73 // Enable lazy in-memory profiling. | |
| 74 L" --prof --prof-lazy --logfile=* --compress-log"); | |
| 75 | |
| 76 const CommandLine& command_line = *CommandLine::ForCurrentProcess(); | |
| 77 if (command_line.HasSwitch(switches::kJavaScriptFlags)) { | |
| 78 webkit_glue::SetJavaScriptFlags( | |
| 79 command_line.GetSwitchValue(switches::kJavaScriptFlags)); | |
| 80 } | |
| 81 | |
| 82 if (command_line.HasSwitch(switches::kEnableWatchdog)) { | |
| 83 // TODO(JAR): Need to implement renderer IO msgloop watchdog. | |
| 84 } | |
| 85 | |
| 86 if (command_line.HasSwitch(switches::kDumpHistogramsOnExit)) { | |
| 87 StatisticsRecorder::set_dump_on_exit(true); | |
| 88 } | |
| 89 | |
| 90 #ifndef DISABLE_NACL | |
| 91 if (command_line.HasSwitch(switches::kInternalNaCl)) | |
| 92 RegisterInternalNaClPlugin(RenderProcess::LaunchNaClProcess); | |
| 93 #endif | |
| 94 | |
| 95 if (!command_line.HasSwitch(switches::kDisableByteRangeSupport)) { | |
| 96 webkit_glue::SetMediaCacheEnabled(true); | |
| 97 } | |
| 98 | |
| 99 #if defined(OS_MACOSX) | |
| 100 FilePath bundle_path = mac_util::MainAppBundlePath(); | |
| 101 | |
| 102 initialized_media_library_ = | |
| 103 media::InitializeMediaLibrary(bundle_path.Append("Libraries")); | |
| 104 #else | |
| 105 FilePath module_path; | |
| 106 initialized_media_library_ = | |
| 107 PathService::Get(base::DIR_MODULE, &module_path) && | |
| 108 media::InitializeMediaLibrary(module_path); | |
| 109 | |
| 110 // TODO(hclam): Add more checks here. Currently this is not used. | |
| 111 if (CommandLine::ForCurrentProcess()->HasSwitch( | |
| 112 switches::kEnableOpenMax)) { | |
| 113 media::InitializeOpenMaxLibrary(module_path); | |
| 114 } | |
| 115 #endif | |
| 116 } | |
| 117 | |
| 118 RenderProcess::~RenderProcess() { | |
| 119 // TODO(port): Try and limit what we pull in for our non-Win unit test bundle. | |
| 120 #ifndef NDEBUG | |
| 121 // log important leaked objects | |
| 122 webkit_glue::CheckForLeaks(); | |
| 123 #endif | |
| 124 | |
| 125 GetShutDownEvent()->Signal(); | |
| 126 ClearTransportDIBCache(); | |
| 127 } | |
| 128 | |
| 129 bool RenderProcess::InProcessPlugins() { | |
| 130 const CommandLine& command_line = *CommandLine::ForCurrentProcess(); | |
| 131 #if defined(OS_LINUX) | |
| 132 // Plugin processes require a UI message loop, and the Linux message loop | |
| 133 // implementation only allows one UI loop per process. | |
| 134 if (command_line.HasSwitch(switches::kInProcessPlugins)) | |
| 135 NOTIMPLEMENTED() << ": in process plugins not supported on Linux"; | |
| 136 return command_line.HasSwitch(switches::kInProcessPlugins); | |
| 137 #else | |
| 138 return command_line.HasSwitch(switches::kInProcessPlugins) || | |
| 139 command_line.HasSwitch(switches::kSingleProcess); | |
| 140 #endif | |
| 141 } | |
| 142 | |
| 143 bool RenderProcess::LaunchNaClProcess(const char* url, | |
| 144 int imc_fd, | |
| 145 nacl::Handle* imc_handle, | |
| 146 nacl::Handle* nacl_process_handle, | |
| 147 int* nacl_process_id) { | |
| 148 // TODO(gregoryd): nacl::FileDescriptor will be soon merged with | |
| 149 // base::FileDescriptor | |
| 150 nacl::FileDescriptor imc_descriptor; | |
| 151 base::ProcessHandle nacl_process; | |
| 152 if (!RenderThread::current()->Send( | |
| 153 new ViewHostMsg_LaunchNaCl(ASCIIToWide(url), | |
| 154 imc_fd, | |
| 155 &imc_descriptor, | |
| 156 &nacl_process, | |
| 157 reinterpret_cast<base::ProcessId*>(nacl_process_id)))) { | |
| 158 return false; | |
| 159 } | |
| 160 *imc_handle = nacl::ToNativeHandle(imc_descriptor); | |
| 161 *nacl_process_handle = nacl_process; | |
| 162 return true; | |
| 163 } | |
| 164 | |
| 165 // ----------------------------------------------------------------------------- | |
| 166 // Platform specific code for dealing with bitmap transport... | |
| 167 | |
| 168 TransportDIB* RenderProcess::CreateTransportDIB(size_t size) { | |
| 169 #if defined(OS_WIN) || defined(OS_LINUX) | |
| 170 // Windows and Linux create transport DIBs inside the renderer | |
| 171 return TransportDIB::Create(size, sequence_number_++); | |
| 172 #elif defined(OS_MACOSX) // defined(OS_WIN) || defined(OS_LINUX) | |
| 173 // Mac creates transport DIBs in the browser, so we need to do a sync IPC to | |
| 174 // get one. The TransportDIB is cached in the browser. | |
| 175 TransportDIB::Handle handle; | |
| 176 IPC::Message* msg = new ViewHostMsg_AllocTransportDIB(size, true, &handle); | |
| 177 if (!main_thread()->Send(msg)) | |
| 178 return NULL; | |
| 179 if (handle.fd < 0) | |
| 180 return NULL; | |
| 181 return TransportDIB::Map(handle); | |
| 182 #endif // defined(OS_MACOSX) | |
| 183 } | |
| 184 | |
| 185 void RenderProcess::FreeTransportDIB(TransportDIB* dib) { | |
| 186 if (!dib) | |
| 187 return; | |
| 188 | |
| 189 #if defined(OS_MACOSX) | |
| 190 // On Mac we need to tell the browser that it can drop a reference to the | |
| 191 // shared memory. | |
| 192 IPC::Message* msg = new ViewHostMsg_FreeTransportDIB(dib->id()); | |
| 193 main_thread()->Send(msg); | |
| 194 #endif | |
| 195 | |
| 196 delete dib; | |
| 197 } | |
| 198 | |
| 199 // ----------------------------------------------------------------------------- | |
| 200 | |
| 201 | |
| 202 skia::PlatformCanvas* RenderProcess::GetDrawingCanvas( | |
| 203 TransportDIB** memory, const gfx::Rect& rect) { | |
| 204 int width = rect.width(); | |
| 205 int height = rect.height(); | |
| 206 const size_t stride = skia::PlatformCanvas::StrideForWidth(rect.width()); | |
| 207 #if defined(OS_LINUX) | |
| 208 const size_t max_size = base::SysInfo::MaxSharedMemorySize(); | |
| 209 #else | |
| 210 const size_t max_size = 0; | |
| 211 #endif | |
| 212 | |
| 213 // If the requested size is too big, reduce the height. Ideally we might like | |
| 214 // to reduce the width as well to make the size reduction more "balanced", but | |
| 215 // it rarely comes up in practice. | |
| 216 if ((max_size != 0) && (height * stride > max_size)) | |
| 217 height = max_size / stride; | |
| 218 | |
| 219 const size_t size = height * stride; | |
| 220 | |
| 221 if (!GetTransportDIBFromCache(memory, size)) { | |
| 222 *memory = CreateTransportDIB(size); | |
| 223 if (!*memory) | |
| 224 return false; | |
| 225 } | |
| 226 | |
| 227 return (*memory)->GetPlatformCanvas(width, height); | |
| 228 } | |
| 229 | |
| 230 void RenderProcess::ReleaseTransportDIB(TransportDIB* mem) { | |
| 231 if (PutSharedMemInCache(mem)) { | |
| 232 shared_mem_cache_cleaner_.Reset(); | |
| 233 return; | |
| 234 } | |
| 235 | |
| 236 FreeTransportDIB(mem); | |
| 237 } | |
| 238 | |
| 239 bool RenderProcess::GetTransportDIBFromCache(TransportDIB** mem, | |
| 240 size_t size) { | |
| 241 // look for a cached object that is suitable for the requested size. | |
| 242 for (size_t i = 0; i < arraysize(shared_mem_cache_); ++i) { | |
| 243 if (shared_mem_cache_[i] && | |
| 244 size <= shared_mem_cache_[i]->size()) { | |
| 245 *mem = shared_mem_cache_[i]; | |
| 246 shared_mem_cache_[i] = NULL; | |
| 247 return true; | |
| 248 } | |
| 249 } | |
| 250 | |
| 251 return false; | |
| 252 } | |
| 253 | |
| 254 int RenderProcess::FindFreeCacheSlot(size_t size) { | |
| 255 // simple algorithm: | |
| 256 // - look for an empty slot to store mem, or | |
| 257 // - if full, then replace smallest entry which is smaller than |size| | |
| 258 for (size_t i = 0; i < arraysize(shared_mem_cache_); ++i) { | |
| 259 if (shared_mem_cache_[i] == NULL) | |
| 260 return i; | |
| 261 } | |
| 262 | |
| 263 size_t smallest_size = size; | |
| 264 int smallest_index = -1; | |
| 265 | |
| 266 for (size_t i = 1; i < arraysize(shared_mem_cache_); ++i) { | |
| 267 const size_t entry_size = shared_mem_cache_[i]->size(); | |
| 268 if (entry_size < smallest_size) { | |
| 269 smallest_size = entry_size; | |
| 270 smallest_index = i; | |
| 271 } | |
| 272 } | |
| 273 | |
| 274 if (smallest_index != -1) { | |
| 275 FreeTransportDIB(shared_mem_cache_[smallest_index]); | |
| 276 shared_mem_cache_[smallest_index] = NULL; | |
| 277 } | |
| 278 | |
| 279 return smallest_index; | |
| 280 } | |
| 281 | |
| 282 bool RenderProcess::PutSharedMemInCache(TransportDIB* mem) { | |
| 283 const int slot = FindFreeCacheSlot(mem->size()); | |
| 284 if (slot == -1) | |
| 285 return false; | |
| 286 | |
| 287 shared_mem_cache_[slot] = mem; | |
| 288 return true; | |
| 289 } | |
| 290 | |
| 291 void RenderProcess::ClearTransportDIBCache() { | |
| 292 for (size_t i = 0; i < arraysize(shared_mem_cache_); ++i) { | |
| 293 if (shared_mem_cache_[i]) { | |
| 294 FreeTransportDIB(shared_mem_cache_[i]); | |
| 295 shared_mem_cache_[i] = NULL; | |
| 296 } | |
| 297 } | |
| 298 } | |
| OLD | NEW |