OLD | NEW |
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 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 | 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 "content/common/child_process_host.h" | 5 #include "content/common/child_process_host.h" |
6 | 6 |
7 #include "base/command_line.h" | 7 #include "base/command_line.h" |
8 #include "base/file_path.h" | 8 #include "base/file_path.h" |
9 #include "base/logging.h" | 9 #include "base/logging.h" |
10 #include "base/metrics/histogram.h" | 10 #include "base/metrics/histogram.h" |
(...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
123 // intolerant of a non-executable heap to work properly on 10.7. This | 123 // intolerant of a non-executable heap to work properly on 10.7. This |
124 // results in Chromium Helper EH.app or Google Chrome Helper EH.app. | 124 // results in Chromium Helper EH.app or Google Chrome Helper EH.app. |
125 child_path = TransformPathForFeature(child_path, "EH"); | 125 child_path = TransformPathForFeature(child_path, "EH"); |
126 } | 126 } |
127 #endif | 127 #endif |
128 | 128 |
129 return child_path; | 129 return child_path; |
130 } | 130 } |
131 | 131 |
132 #if defined(OS_WIN) | 132 #if defined(OS_WIN) |
| 133 ChildProcessHost::FontCache::CacheElement::CacheElement() |
| 134 : font_(NULL), dc_(NULL), ref_count_(0) { |
| 135 } |
| 136 |
| 137 ChildProcessHost::FontCache::CacheElement::~CacheElement() { |
| 138 if (font_) { |
| 139 DeleteObject(font_); |
| 140 } |
| 141 if (dc_) { |
| 142 DeleteDC(dc_); |
| 143 } |
| 144 } |
| 145 |
133 // static | 146 // static |
134 void ChildProcessHost::PreCacheFont(LOGFONT font) { | 147 ChildProcessHost::FontCache* ChildProcessHost::FontCache::GetInstance() { |
135 // If a child process is running in a sandbox, GetTextMetrics() | 148 return Singleton<ChildProcessHost::FontCache>::get(); |
136 // can sometimes fail. If a font has not been loaded | 149 } |
137 // previously, GetTextMetrics() will try to load the font | |
138 // from the font file. However, the sandboxed process does | |
139 // not have permissions to access any font files and | |
140 // the call fails. So we make the browser pre-load the | |
141 // font for us by using a dummy call to GetTextMetrics of | |
142 // the same font. | |
143 | 150 |
144 // Maintain a circular queue for the fonts and DCs to be cached. | 151 void ChildProcessHost::FontCache::PreCacheFont(LOGFONT font, int pid) { |
145 // font_index maintains next available location in the queue. | 152 typedef std::map<std::wstring, ChildProcessHost::FontCache::CacheElement> |
146 static const int kFontCacheSize = 32; | 153 FontNameToElement; |
147 static HFONT fonts[kFontCacheSize] = {0}; | |
148 static HDC hdcs[kFontCacheSize] = {0}; | |
149 static size_t font_index = 0; | |
150 | 154 |
151 UMA_HISTOGRAM_COUNTS_100("Memory.CachedFontAndDC", | 155 base::AutoLock lock(mutex_); |
152 fonts[kFontCacheSize-1] ? kFontCacheSize : static_cast<int>(font_index)); | |
153 | 156 |
| 157 // Fetch the font into memory |
154 HDC hdc = GetDC(NULL); | 158 HDC hdc = GetDC(NULL); |
155 HFONT font_handle = CreateFontIndirect(&font); | 159 HFONT font_handle = CreateFontIndirect(&font); |
156 DCHECK(NULL != font_handle); | 160 DCHECK(NULL != font_handle); |
157 | 161 |
158 HGDIOBJ old_font = SelectObject(hdc, font_handle); | 162 HGDIOBJ old_font = SelectObject(hdc, font_handle); |
159 DCHECK(NULL != old_font); | 163 DCHECK(NULL != old_font); |
160 | 164 |
161 TEXTMETRIC tm; | 165 TEXTMETRIC tm; |
162 BOOL ret = GetTextMetrics(hdc, &tm); | 166 BOOL ret = GetTextMetrics(hdc, &tm); |
163 DCHECK(ret); | 167 DCHECK(ret); |
164 | 168 |
165 if (fonts[font_index] || hdcs[font_index]) { | 169 std::wstring font_name = font.lfFaceName; |
166 // We already have too many fonts, we will delete one and take it's place. | 170 int ref_count_inc = 1; |
167 DeleteObject(fonts[font_index]); | 171 FontNameVector::iterator it = std::find(pid_font_map_[pid].begin(), |
168 ReleaseDC(NULL, hdcs[font_index]); | 172 pid_font_map_[pid].end(), |
| 173 font_name); |
| 174 if (it == pid_font_map_[pid].end()) { // New font |
| 175 pid_font_map_[pid].push_back(font_name); |
| 176 } else { |
| 177 ref_count_inc = 0; |
169 } | 178 } |
170 | 179 |
171 fonts[font_index] = font_handle; | 180 if (cache_[font_name].ref_count_ == 0) { // New element |
172 hdcs[font_index] = hdc; | 181 cache_[font_name].ref_count_ = 1; |
173 font_index = (font_index + 1) % kFontCacheSize; | 182 } else { |
| 183 DeleteObject(cache_[font_name].font_); |
| 184 DeleteDC(cache_[font_name].dc_); |
| 185 } |
| 186 cache_[font_name].font_ = font_handle; |
| 187 cache_[font_name].dc_ = hdc; |
| 188 cache_[font_name].ref_count_ += ref_count_inc; |
| 189 } |
| 190 |
| 191 void ChildProcessHost::FontCache::ReleaseCachedFont(int pid) { |
| 192 typedef std::map<std::wstring, ChildProcessHost::FontCache::CacheElement> |
| 193 FontNameToElement; |
| 194 |
| 195 base::AutoLock lock(mutex_); |
| 196 |
| 197 PidToFontNames::iterator it; |
| 198 it = pid_font_map_.find(pid); |
| 199 if (it == pid_font_map_.end()) { |
| 200 return; |
| 201 } |
| 202 |
| 203 for (FontNameVector::iterator i = it->second.begin(), e = it->second.end(); |
| 204 i != e; ++i) { |
| 205 FontNameToElement::iterator element; |
| 206 element = cache_.find(*i); |
| 207 if (element != cache_.end()) { |
| 208 --((*element).second.ref_count_); |
| 209 } |
| 210 } |
| 211 |
| 212 pid_font_map_.erase(it); |
| 213 for (FontNameToElement::iterator i = cache_.begin(); i != cache_.end(); ) { |
| 214 if (i->second.ref_count_ == 0) { |
| 215 cache_.erase(i++); |
| 216 } else { |
| 217 ++i; |
| 218 } |
| 219 } |
| 220 } |
| 221 |
| 222 // static |
| 223 void ChildProcessHost::PreCacheFont(LOGFONT font, int pid) { |
| 224 // If a child process is running in a sandbox, GetTextMetrics() |
| 225 // can sometimes fail. If a font has not been loaded |
| 226 // previously, GetTextMetrics() will try to load the font |
| 227 // from the font file. However, the sandboxed process does |
| 228 // not have permissions to access any font files and |
| 229 // the call fails. So we make the browser pre-load the |
| 230 // font for us by using a dummy call to GetTextMetrics of |
| 231 // the same font. |
| 232 ChildProcessHost::FontCache::GetInstance()->PreCacheFont(font, pid); |
| 233 } |
| 234 |
| 235 // static |
| 236 void ChildProcessHost::ReleaseCachedFont(int pid) { |
| 237 ChildProcessHost::FontCache::GetInstance()->ReleaseCachedFont(pid); |
174 } | 238 } |
175 #endif // OS_WIN | 239 #endif // OS_WIN |
176 | 240 |
177 | 241 |
178 bool ChildProcessHost::CreateChannel() { | 242 bool ChildProcessHost::CreateChannel() { |
179 channel_id_ = ChildProcessInfo::GenerateRandomChannelID(this); | 243 channel_id_ = ChildProcessInfo::GenerateRandomChannelID(this); |
180 channel_.reset(new IPC::Channel( | 244 channel_.reset(new IPC::Channel( |
181 channel_id_, IPC::Channel::MODE_SERVER, &listener_)); | 245 channel_id_, IPC::Channel::MODE_SERVER, &listener_)); |
182 if (!channel_->Connect()) | 246 if (!channel_->Connect()) |
183 return false; | 247 return false; |
(...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
288 for (size_t i = 0; i < host_->filters_.size(); ++i) | 352 for (size_t i = 0; i < host_->filters_.size(); ++i) |
289 host_->filters_[i]->OnChannelError(); | 353 host_->filters_[i]->OnChannelError(); |
290 | 354 |
291 // This will delete host_, which will also destroy this! | 355 // This will delete host_, which will also destroy this! |
292 host_->OnChildDied(); | 356 host_->OnChildDied(); |
293 } | 357 } |
294 | 358 |
295 void ChildProcessHost::ForceShutdown() { | 359 void ChildProcessHost::ForceShutdown() { |
296 Send(new ChildProcessMsg_Shutdown()); | 360 Send(new ChildProcessMsg_Shutdown()); |
297 } | 361 } |
OLD | NEW |