blob: 55e1e5a212e818958e7461f99b2cd62523882e98 [file] [log] [blame]
license.botbf09a502008-08-24 00:55:551// 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
3// found in the LICENSE file.
initial.commit09911bf2008-07-26 23:55:294
5#include <windows.h>
6#include <objidl.h>
7#include <mlang.h>
8
9#include "chrome/renderer/render_process.h"
10
11#include "base/basictypes.h"
12#include "base/command_line.h"
13#include "base/message_loop.h"
14#include "base/histogram.h"
15#include "chrome/browser/net/dns_global.h" // TODO(jar): DNS calls should be renderer specific, not including browser.
16#include "chrome/common/chrome_switches.h"
17#include "chrome/common/ipc_channel.h"
18#include "chrome/common/ipc_message_utils.h"
19#include "chrome/common/render_messages.h"
20#include "chrome/renderer/render_view.h"
21#include "webkit/glue/webkit_glue.h"
22
23//-----------------------------------------------------------------------------
24
25IMLangFontLink2* RenderProcess::lang_font_link_ = NULL;
26bool RenderProcess::load_plugins_in_process_ = false;
27
28//-----------------------------------------------------------------------------
29
30RenderProcess::RenderProcess(const std::wstring& channel_name)
31 : render_thread_(channel_name),
32#pragma warning(suppress: 4355) // Okay to pass "this" here.
33 clearer_factory_(this) {
34 for (int i = 0; i < arraysize(shared_mem_cache_); ++i)
35 shared_mem_cache_[i] = NULL;
36}
37
38RenderProcess::~RenderProcess() {
39 // We need to stop the RenderThread as the clearer_factory_
40 // member could be in use while the object itself is destroyed,
41 // as a result of the containing RenderProcess object being destroyed.
42 // This race condition causes a crash when the renderer process is shutting
43 // down.
44 render_thread_.Stop();
45 ClearSharedMemCache();
46}
47
48// static
49bool RenderProcess::GlobalInit(const std::wstring &channel_name) {
50 // HACK: See http://b/issue?id=1024307 for rationale.
51 if (GetModuleHandle(L"LPK.DLL") == NULL) {
52 // Makes sure lpk.dll is loaded by gdi32 to make sure ExtTextOut() works
53 // when buffering into a EMF buffer for printing.
54 typedef BOOL (__stdcall *GdiInitializeLanguagePack)(int LoadedShapingDLLs);
55 GdiInitializeLanguagePack gdi_init_lpk =
56 reinterpret_cast<GdiInitializeLanguagePack>(GetProcAddress(
57 GetModuleHandle(L"GDI32.DLL"),
58 "GdiInitializeLanguagePack"));
59 DCHECK(gdi_init_lpk);
60 if (gdi_init_lpk) {
61 gdi_init_lpk(0);
62 }
63 }
64
65 InitializeLangFontLink();
66
67 CommandLine command_line;
68 if (command_line.HasSwitch(switches::kJavaScriptFlags)) {
69 webkit_glue::SetJavaScriptFlags(
70 command_line.GetSwitchValue(switches::kJavaScriptFlags));
71 }
72 if (command_line.HasSwitch(switches::kPlaybackMode) ||
73 command_line.HasSwitch(switches::kRecordMode)) {
74 webkit_glue::SetRecordPlaybackMode(true);
75 }
76
77 if (command_line.HasSwitch(switches::kInProcessPlugins) ||
78 command_line.HasSwitch(switches::kSingleProcess))
79 load_plugins_in_process_ = true;
80
initial.commit09911bf2008-07-26 23:55:2981 if (command_line.HasSwitch(switches::kEnableWatchdog)) {
82 // TODO(JAR): Need to implement renderer IO msgloop watchdog.
83 }
84
85 if (command_line.HasSwitch(switches::kDumpHistogramsOnExit)) {
86 StatisticsRecorder::set_dump_on_exit(true);
87 }
88
89 ChildProcessFactory<RenderProcess> factory;
90 return ChildProcess::GlobalInit(channel_name, &factory);
91}
92
93// static
94void RenderProcess::GlobalCleanup() {
95 ChildProcess::GlobalCleanup();
96 ReleaseLangFontLink();
97}
98
99// static
100void RenderProcess::InitializeLangFontLink() {
101 // TODO(hbono): http://b/1072298 Experimentally commented out this code to
102 // prevent registry leaks caused by this IMLangFontLink2 interface.
103 // If you find any font-rendering regressions. Please feel free to blame me.
104#ifdef USE_IMLANGFONTLINK2
105 IMultiLanguage* multi_language = NULL;
106 lang_font_link_ = NULL;
107 if (S_OK != CoCreateInstance(CLSID_CMultiLanguage,
108 0,
109 CLSCTX_ALL,
110 IID_IMultiLanguage,
111 reinterpret_cast<void**>(&multi_language))) {
112 DLOG(ERROR) << "Cannot CoCreate CMultiLanguage";
113 } else {
114 if (S_OK != multi_language->QueryInterface(IID_IMLangFontLink2,
115 reinterpret_cast<void**>(&lang_font_link_))) {
116 DLOG(ERROR) << "Cannot query LangFontLink2 interface";
117 }
118 }
119
120 if (multi_language)
121 multi_language->Release();
122#endif
123}
124
125// static
126void RenderProcess::ReleaseLangFontLink() {
127 // TODO(hbono): http://b/1072298 Experimentally commented out this code to
128 // prevent registry leaks caused by this IMLangFontLink2 interface.
129 // If you find any font-rendering regressions. Please feel free to blame me.
130#ifdef USE_IMLANGFONTLINK2
131 if (lang_font_link_)
132 lang_font_link_->Release();
133#endif
134}
135
136// static
137IMLangFontLink2* RenderProcess::GetLangFontLink() {
138 return lang_font_link_;
139}
140
141// static
142bool RenderProcess::ShouldLoadPluginsInProcess() {
143 return load_plugins_in_process_;
144}
145
146// static
147SharedMemory* RenderProcess::AllocSharedMemory(size_t size) {
148 self()->clearer_factory_.RevokeAll();
149
150 SharedMemory* mem = self()->GetSharedMemFromCache(size);
151 if (mem)
152 return mem;
153
154 // Round-up size to allocation granularity
155 SYSTEM_INFO info;
156 GetSystemInfo(&info);
157
158 size = size / info.dwAllocationGranularity + 1;
159 size = size * info.dwAllocationGranularity;
160
161 mem = new SharedMemory();
162 if (!mem)
163 return NULL;
164 if (!mem->Create(L"", false, true, size)) {
165 delete mem;
166 return NULL;
167 }
168
169 return mem;
170}
171
172// static
173void RenderProcess::FreeSharedMemory(SharedMemory* mem) {
174 if (self()->PutSharedMemInCache(mem)) {
175 self()->ScheduleCacheClearer();
176 return;
177 }
178 DeleteSharedMem(mem);
179}
180
181// static
182void RenderProcess::DeleteSharedMem(SharedMemory* mem) {
183 delete mem;
184}
185
186SharedMemory* RenderProcess::GetSharedMemFromCache(size_t size) {
187 // look for a cached object that is suitable for the requested size.
188 for (int i = 0; i < arraysize(shared_mem_cache_); ++i) {
189 SharedMemory* mem = shared_mem_cache_[i];
190 if (mem && mem->max_size() >= size) {
191 shared_mem_cache_[i] = NULL;
192 return mem;
193 }
194 }
195 return NULL;
196}
197
198bool RenderProcess::PutSharedMemInCache(SharedMemory* mem) {
199 // simple algorithm:
200 // - look for an empty slot to store mem, or
201 // - if full, then replace any existing cache entry that is smaller than the
202 // given shared memory object.
203 for (int i = 0; i < arraysize(shared_mem_cache_); ++i) {
204 if (!shared_mem_cache_[i]) {
205 shared_mem_cache_[i] = mem;
206 return true;
207 }
208 }
209 for (int i = 0; i < arraysize(shared_mem_cache_); ++i) {
210 SharedMemory* cached_mem = shared_mem_cache_[i];
211 if (cached_mem->max_size() < mem->max_size()) {
212 shared_mem_cache_[i] = mem;
213 DeleteSharedMem(cached_mem);
214 return true;
215 }
216 }
217 return false;
218}
219
220void RenderProcess::ClearSharedMemCache() {
221 for (int i = 0; i < arraysize(shared_mem_cache_); ++i) {
222 if (shared_mem_cache_[i]) {
223 DeleteSharedMem(shared_mem_cache_[i]);
224 shared_mem_cache_[i] = NULL;
225 }
226 }
227}
228
229void RenderProcess::ScheduleCacheClearer() {
230 // If we already have a deferred clearer, then revoke it so we effectively
231 // delay cache clearing until idle for our desired interval.
232 clearer_factory_.RevokeAll();
233
234 MessageLoop::current()->PostDelayedTask(FROM_HERE,
235 clearer_factory_.NewRunnableMethod(&RenderProcess::ClearSharedMemCache),
236 5000 /* 5 seconds */);
237}
238
239void RenderProcess::Cleanup() {
240#ifndef NDEBUG
241 // log important leaked objects
242 webkit_glue::CheckForLeaks();
243#endif
244}
license.botbf09a502008-08-24 00:55:55245