OLD | NEW |
1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "build/build_config.h" | 5 #include "build/build_config.h" |
6 | 6 |
7 #if defined(OS_WIN) | 7 #if defined(OS_WIN) |
8 #include <windows.h> | 8 #include <windows.h> |
9 #include <objidl.h> | 9 #include <objidl.h> |
10 #include <mlang.h> | 10 #include <mlang.h> |
11 #endif | 11 #endif |
12 | 12 |
13 #include "chrome/renderer/render_process.h" | 13 #include "chrome/renderer/render_process.h" |
14 | 14 |
15 #include "base/basictypes.h" | 15 #include "base/basictypes.h" |
16 #include "base/command_line.h" | 16 #include "base/command_line.h" |
17 #include "base/compiler_specific.h" | 17 #include "base/compiler_specific.h" |
18 #include "base/message_loop.h" | 18 #include "base/message_loop.h" |
19 #include "base/histogram.h" | 19 #include "base/histogram.h" |
20 #include "base/path_service.h" | 20 #include "base/path_service.h" |
21 #include "base/sys_info.h" | 21 #include "base/sys_info.h" |
22 #include "chrome/browser/net/dns_global.h" // TODO(jar): DNS calls should be re
nderer specific, not including browser. | 22 #include "chrome/browser/net/dns_global.h" // TODO(jar): DNS calls should be re
nderer specific, not including browser. |
23 #include "chrome/common/chrome_switches.h" | 23 #include "chrome/common/chrome_switches.h" |
24 #include "chrome/common/chrome_paths.h" | 24 #include "chrome/common/chrome_paths.h" |
25 #include "chrome/common/ipc_channel.h" | 25 #include "chrome/common/ipc_channel.h" |
26 #include "chrome/common/ipc_message_utils.h" | 26 #include "chrome/common/ipc_message_utils.h" |
27 #include "chrome/common/render_messages.h" | 27 #include "chrome/common/render_messages.h" |
| 28 #include "chrome/common/transport_dib.h" |
28 #include "chrome/renderer/render_view.h" | 29 #include "chrome/renderer/render_view.h" |
29 #include "webkit/glue/webkit_glue.h" | 30 #include "webkit/glue/webkit_glue.h" |
30 | 31 |
31 //----------------------------------------------------------------------------- | 32 //----------------------------------------------------------------------------- |
32 | 33 |
33 bool RenderProcess::load_plugins_in_process_ = false; | 34 bool RenderProcess::load_plugins_in_process_ = false; |
34 | 35 |
35 //----------------------------------------------------------------------------- | 36 //----------------------------------------------------------------------------- |
36 | 37 |
37 RenderProcess::RenderProcess(const std::wstring& channel_name) | 38 RenderProcess::RenderProcess(const std::wstring& channel_name) |
38 : render_thread_(channel_name), | 39 : render_thread_(channel_name), |
39 ALLOW_THIS_IN_INITIALIZER_LIST(clearer_factory_(this)) { | 40 ALLOW_THIS_IN_INITIALIZER_LIST(shared_mem_cache_cleaner_( |
| 41 base::TimeDelta::FromSeconds(5), |
| 42 this, &RenderProcess::ClearTransportDIBCache)), |
| 43 sequence_number_(0) { |
40 for (size_t i = 0; i < arraysize(shared_mem_cache_); ++i) | 44 for (size_t i = 0; i < arraysize(shared_mem_cache_); ++i) |
41 shared_mem_cache_[i] = NULL; | 45 shared_mem_cache_[i] = NULL; |
42 } | 46 } |
43 | 47 |
44 RenderProcess::~RenderProcess() { | 48 RenderProcess::~RenderProcess() { |
45 // We need to stop the RenderThread as the clearer_factory_ | 49 // We need to stop the RenderThread as the clearer_factory_ |
46 // member could be in use while the object itself is destroyed, | 50 // member could be in use while the object itself is destroyed, |
47 // as a result of the containing RenderProcess object being destroyed. | 51 // as a result of the containing RenderProcess object being destroyed. |
48 // This race condition causes a crash when the renderer process is shutting | 52 // This race condition causes a crash when the renderer process is shutting |
49 // down. | 53 // down. |
50 render_thread_.Stop(); | 54 render_thread_.Stop(); |
51 ClearSharedMemCache(); | 55 ClearTransportDIBCache(); |
52 } | 56 } |
53 | 57 |
54 // static | 58 // static |
55 bool RenderProcess::GlobalInit(const std::wstring &channel_name) { | 59 bool RenderProcess::GlobalInit(const std::wstring &channel_name) { |
56 #if defined(OS_WIN) | 60 #if defined(OS_WIN) |
57 // HACK: See http://b/issue?id=1024307 for rationale. | 61 // HACK: See http://b/issue?id=1024307 for rationale. |
58 if (GetModuleHandle(L"LPK.DLL") == NULL) { | 62 if (GetModuleHandle(L"LPK.DLL") == NULL) { |
59 // Makes sure lpk.dll is loaded by gdi32 to make sure ExtTextOut() works | 63 // Makes sure lpk.dll is loaded by gdi32 to make sure ExtTextOut() works |
60 // when buffering into a EMF buffer for printing. | 64 // when buffering into a EMF buffer for printing. |
61 typedef BOOL (__stdcall *GdiInitializeLanguagePack)(int LoadedShapingDLLs); | 65 typedef BOOL (__stdcall *GdiInitializeLanguagePack)(int LoadedShapingDLLs); |
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
117 // static | 121 // static |
118 void RenderProcess::GlobalCleanup() { | 122 void RenderProcess::GlobalCleanup() { |
119 ChildProcess::GlobalCleanup(); | 123 ChildProcess::GlobalCleanup(); |
120 } | 124 } |
121 | 125 |
122 // static | 126 // static |
123 bool RenderProcess::ShouldLoadPluginsInProcess() { | 127 bool RenderProcess::ShouldLoadPluginsInProcess() { |
124 return load_plugins_in_process_; | 128 return load_plugins_in_process_; |
125 } | 129 } |
126 | 130 |
| 131 // ----------------------------------------------------------------------------- |
| 132 // Platform specific code for dealing with bitmap transport... |
| 133 |
| 134 // ----------------------------------------------------------------------------- |
| 135 // Create a platform canvas object which renders into the given transport |
| 136 // memory. |
| 137 // ----------------------------------------------------------------------------- |
| 138 static skia::PlatformCanvas* CanvasFromTransportDIB( |
| 139 TransportDIB* dib, const gfx::Rect& rect) { |
| 140 #if defined(OS_WIN) |
| 141 return new skia::PlatformCanvas(rect.width(), rect.height(), true, |
| 142 dib->handle()); |
| 143 #elif defined(OS_LINUX) || defined(OS_MACOSX) |
| 144 return new skia::PlatformCanvas(rect.width(), rect.height(), true, |
| 145 reinterpret_cast<uint8_t*>(dib->memory())); |
| 146 #endif |
| 147 } |
| 148 |
| 149 TransportDIB* RenderProcess::CreateTransportDIB(size_t size) { |
| 150 #if defined(OS_WIN) || defined(OS_LINUX) |
| 151 // Windows and Linux create transport DIBs inside the renderer |
| 152 return TransportDIB::Create(size, sequence_number_++); |
| 153 #elif defined(OS_MACOSX) // defined(OS_WIN) || defined(OS_LINUX) |
| 154 // Mac creates transport DIBs in the browser, so we need to do a sync IPC to |
| 155 // get one. |
| 156 IPC::Maybe<TransportDIB::Handle> mhandle; |
| 157 IPC::Message* msg = new ViewHostMsg_AllocTransportDIB(size, &mhandle); |
| 158 if (!render_thread_.Send(msg)) |
| 159 return NULL; |
| 160 if (!mhandle.valid) |
| 161 return NULL; |
| 162 return TransportDIB::Map(mhandle.value); |
| 163 #endif // defined(OS_MACOSX) |
| 164 } |
| 165 |
| 166 void RenderProcess::FreeTransportDIB(TransportDIB* dib) { |
| 167 if (!dib) |
| 168 return; |
| 169 |
| 170 #if defined(OS_MACOSX) |
| 171 // On Mac we need to tell the browser that it can drop a reference to the |
| 172 // shared memory. |
| 173 IPC::Message* msg = new ViewHostMsg_FreeTransportDIB(dib->id()); |
| 174 render_thread_.Send(msg); |
| 175 #endif |
| 176 |
| 177 delete dib; |
| 178 } |
| 179 |
| 180 // ----------------------------------------------------------------------------- |
| 181 |
| 182 |
127 // static | 183 // static |
128 base::SharedMemory* RenderProcess::AllocSharedMemory(size_t size) { | 184 skia::PlatformCanvas* RenderProcess::GetDrawingCanvas( |
129 self()->clearer_factory_.RevokeAll(); | 185 TransportDIB** memory, const gfx::Rect& rect) { |
| 186 const size_t stride = skia::PlatformCanvas::StrideForWidth(rect.width()); |
| 187 const size_t size = stride * rect.height(); |
130 | 188 |
131 base::SharedMemory* mem = self()->GetSharedMemFromCache(size); | 189 if (!self()->GetTransportDIBFromCache(memory, size)) { |
132 if (mem) | 190 *memory = self()->CreateTransportDIB(size); |
133 return mem; | 191 if (!*memory) |
134 | 192 return false; |
135 // Round-up size to allocation granularity | |
136 size_t allocation_granularity = base::SysInfo::VMAllocationGranularity(); | |
137 size = size / allocation_granularity + 1; | |
138 size = size * allocation_granularity; | |
139 | |
140 mem = new base::SharedMemory(); | |
141 if (!mem) | |
142 return NULL; | |
143 if (!mem->Create(L"", false, true, size)) { | |
144 delete mem; | |
145 return NULL; | |
146 } | 193 } |
147 | 194 |
148 return mem; | 195 return CanvasFromTransportDIB(*memory, rect); |
149 } | 196 } |
150 | 197 |
151 // static | 198 // static |
152 void RenderProcess::FreeSharedMemory(base::SharedMemory* mem) { | 199 void RenderProcess::ReleaseTransportDIB(TransportDIB* mem) { |
153 if (self()->PutSharedMemInCache(mem)) { | 200 if (self()->PutSharedMemInCache(mem)) { |
154 self()->ScheduleCacheClearer(); | 201 self()->shared_mem_cache_cleaner_.Reset(); |
155 return; | 202 return; |
156 } | 203 } |
157 DeleteSharedMem(mem); | 204 |
| 205 self()->FreeTransportDIB(mem); |
158 } | 206 } |
159 | 207 |
160 // static | 208 bool RenderProcess::GetTransportDIBFromCache(TransportDIB** mem, |
161 void RenderProcess::DeleteSharedMem(base::SharedMemory* mem) { | 209 size_t size) { |
162 delete mem; | |
163 } | |
164 | |
165 base::SharedMemory* RenderProcess::GetSharedMemFromCache(size_t size) { | |
166 // look for a cached object that is suitable for the requested size. | 210 // look for a cached object that is suitable for the requested size. |
167 for (size_t i = 0; i < arraysize(shared_mem_cache_); ++i) { | 211 for (size_t i = 0; i < arraysize(shared_mem_cache_); ++i) { |
168 base::SharedMemory* mem = shared_mem_cache_[i]; | 212 if (shared_mem_cache_[i] && |
169 if (mem && mem->max_size() >= size) { | 213 size <= shared_mem_cache_[i]->size()) { |
| 214 *mem = shared_mem_cache_[i]; |
170 shared_mem_cache_[i] = NULL; | 215 shared_mem_cache_[i] = NULL; |
171 return mem; | |
172 } | |
173 } | |
174 return NULL; | |
175 } | |
176 | |
177 bool RenderProcess::PutSharedMemInCache(base::SharedMemory* mem) { | |
178 // simple algorithm: | |
179 // - look for an empty slot to store mem, or | |
180 // - if full, then replace any existing cache entry that is smaller than the | |
181 // given shared memory object. | |
182 for (size_t i = 0; i < arraysize(shared_mem_cache_); ++i) { | |
183 if (!shared_mem_cache_[i]) { | |
184 shared_mem_cache_[i] = mem; | |
185 return true; | 216 return true; |
186 } | 217 } |
187 } | 218 } |
188 for (size_t i = 0; i < arraysize(shared_mem_cache_); ++i) { | 219 |
189 base::SharedMemory* cached_mem = shared_mem_cache_[i]; | |
190 if (cached_mem->max_size() < mem->max_size()) { | |
191 shared_mem_cache_[i] = mem; | |
192 DeleteSharedMem(cached_mem); | |
193 return true; | |
194 } | |
195 } | |
196 return false; | 220 return false; |
197 } | 221 } |
198 | 222 |
199 void RenderProcess::ClearSharedMemCache() { | 223 int RenderProcess::FindFreeCacheSlot(size_t size) { |
| 224 // simple algorithm: |
| 225 // - look for an empty slot to store mem, or |
| 226 // - if full, then replace smallest entry which is smaller than |size| |
| 227 for (size_t i = 0; i < arraysize(shared_mem_cache_); ++i) { |
| 228 if (shared_mem_cache_[i] == NULL) |
| 229 return i; |
| 230 } |
| 231 |
| 232 size_t smallest_size = size; |
| 233 int smallest_index = -1; |
| 234 |
| 235 for (size_t i = 1; i < arraysize(shared_mem_cache_); ++i) { |
| 236 const size_t entry_size = shared_mem_cache_[i]->size(); |
| 237 if (entry_size < smallest_size) { |
| 238 smallest_size = entry_size; |
| 239 smallest_index = i; |
| 240 } |
| 241 } |
| 242 |
| 243 if (smallest_index != -1) { |
| 244 FreeTransportDIB(shared_mem_cache_[smallest_index]); |
| 245 shared_mem_cache_[smallest_index] = NULL; |
| 246 } |
| 247 |
| 248 return smallest_index; |
| 249 } |
| 250 |
| 251 bool RenderProcess::PutSharedMemInCache(TransportDIB* mem) { |
| 252 const int slot = FindFreeCacheSlot(mem->size()); |
| 253 if (slot == -1) |
| 254 return false; |
| 255 |
| 256 shared_mem_cache_[slot] = mem; |
| 257 return true; |
| 258 } |
| 259 |
| 260 void RenderProcess::ClearTransportDIBCache() { |
200 for (size_t i = 0; i < arraysize(shared_mem_cache_); ++i) { | 261 for (size_t i = 0; i < arraysize(shared_mem_cache_); ++i) { |
201 if (shared_mem_cache_[i]) { | 262 if (shared_mem_cache_[i]) { |
202 DeleteSharedMem(shared_mem_cache_[i]); | 263 FreeTransportDIB(shared_mem_cache_[i]); |
203 shared_mem_cache_[i] = NULL; | 264 shared_mem_cache_[i] = NULL; |
204 } | 265 } |
205 } | 266 } |
206 } | 267 } |
207 | 268 |
208 void RenderProcess::ScheduleCacheClearer() { | |
209 // If we already have a deferred clearer, then revoke it so we effectively | |
210 // delay cache clearing until idle for our desired interval. | |
211 clearer_factory_.RevokeAll(); | |
212 | |
213 MessageLoop::current()->PostDelayedTask(FROM_HERE, | |
214 clearer_factory_.NewRunnableMethod(&RenderProcess::ClearSharedMemCache), | |
215 5000 /* 5 seconds */); | |
216 } | |
217 | |
218 void RenderProcess::Cleanup() { | 269 void RenderProcess::Cleanup() { |
219 // TODO(port) | 270 // TODO(port) |
220 // Try and limit what we pull in for our non-Win unit test bundle | 271 // Try and limit what we pull in for our non-Win unit test bundle |
221 #ifndef NDEBUG | 272 #ifndef NDEBUG |
222 // log important leaked objects | 273 // log important leaked objects |
223 webkit_glue::CheckForLeaks(); | 274 webkit_glue::CheckForLeaks(); |
224 #endif | 275 #endif |
225 } | 276 } |
OLD | NEW |