Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(481)

Side by Side Diff: content/common/child_process_host.cc

Issue 7866019: New implementation of font precache on Windows. (Closed) Base URL: http://git.chromium.org/git/chromium.git@trunk
Patch Set: Merge to latest trunk Created 9 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « content/common/child_process_host.h ('k') | content/common/child_process_messages.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 48 matching lines...) Expand 10 before | Expand all | Expand 10 after
59 .Append(kContentsName) 59 .Append(kContentsName)
60 .Append(kMacOSName) 60 .Append(kMacOSName)
61 .Append(new_basename); 61 .Append(new_basename);
62 62
63 return new_path; 63 return new_path;
64 } 64 }
65 65
66 } // namespace 66 } // namespace
67 #endif // OS_MACOSX 67 #endif // OS_MACOSX
68 68
69 #if defined (OS_WIN)
70 // Types used in PreCacheFont
71 namespace {
72 typedef std::vector<string16> FontNameVector;
73 typedef std::map<int, FontNameVector> PidToFontNames;
74 }
75 #endif // OS_WIN
76
69 ChildProcessHost::ChildProcessHost() 77 ChildProcessHost::ChildProcessHost()
70 : ALLOW_THIS_IN_INITIALIZER_LIST(listener_(this)), 78 : ALLOW_THIS_IN_INITIALIZER_LIST(listener_(this)),
71 opening_channel_(false) { 79 opening_channel_(false) {
72 } 80 }
73 81
74 ChildProcessHost::~ChildProcessHost() { 82 ChildProcessHost::~ChildProcessHost() {
75 for (size_t i = 0; i < filters_.size(); ++i) { 83 for (size_t i = 0; i < filters_.size(); ++i) {
76 filters_[i]->OnChannelClosing(); 84 filters_[i]->OnChannelClosing();
77 filters_[i]->OnFilterRemoved(); 85 filters_[i]->OnFilterRemoved();
78 } 86 }
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after
124 // intolerant of a non-executable heap to work properly on 10.7. This 132 // intolerant of a non-executable heap to work properly on 10.7. This
125 // results in Chromium Helper EH.app or Google Chrome Helper EH.app. 133 // results in Chromium Helper EH.app or Google Chrome Helper EH.app.
126 child_path = TransformPathForFeature(child_path, "EH"); 134 child_path = TransformPathForFeature(child_path, "EH");
127 } 135 }
128 #endif 136 #endif
129 137
130 return child_path; 138 return child_path;
131 } 139 }
132 140
133 #if defined(OS_WIN) 141 #if defined(OS_WIN)
142 ChildProcessHost::FontCache::CacheElement::CacheElement()
143 : font_(NULL), dc_(NULL), ref_count_(0) {
144 }
145
146 ChildProcessHost::FontCache::CacheElement::~CacheElement() {
147 if (font_) {
148 DeleteObject(font_);
149 }
150 if (dc_) {
151 DeleteDC(dc_);
152 }
153 }
154
155 ChildProcessHost::FontCache::FontCache() {
156 }
157
158 ChildProcessHost::FontCache::~FontCache() {
159 }
160
134 // static 161 // static
135 void ChildProcessHost::PreCacheFont(LOGFONT font) { 162 ChildProcessHost::FontCache* ChildProcessHost::FontCache::GetInstance() {
136 // If a child process is running in a sandbox, GetTextMetrics() 163 return Singleton<ChildProcessHost::FontCache>::get();
137 // can sometimes fail. If a font has not been loaded 164 }
138 // previously, GetTextMetrics() will try to load the font
139 // from the font file. However, the sandboxed process does
140 // not have permissions to access any font files and
141 // the call fails. So we make the browser pre-load the
142 // font for us by using a dummy call to GetTextMetrics of
143 // the same font.
144 165
145 // Maintain a circular queue for the fonts and DCs to be cached. 166 void ChildProcessHost::FontCache::PreCacheFont(LOGFONT font, int process_id) {
146 // font_index maintains next available location in the queue. 167 typedef std::map<string16, ChildProcessHost::FontCache::CacheElement>
147 static const int kFontCacheSize = 32; 168 FontNameToElement;
148 static HFONT fonts[kFontCacheSize] = {0};
149 static HDC hdcs[kFontCacheSize] = {0};
150 static size_t font_index = 0;
151 169
152 UMA_HISTOGRAM_COUNTS_100("Memory.CachedFontAndDC", 170 base::AutoLock lock(mutex_);
153 fonts[kFontCacheSize-1] ? kFontCacheSize : static_cast<int>(font_index));
154 171
172 // Fetch the font into memory.
173 // No matter the font is cached or not, we load it to avoid GDI swapping out
174 // that font file.
155 HDC hdc = GetDC(NULL); 175 HDC hdc = GetDC(NULL);
156 HFONT font_handle = CreateFontIndirect(&font); 176 HFONT font_handle = CreateFontIndirect(&font);
157 DCHECK(NULL != font_handle); 177 DCHECK(NULL != font_handle);
158 178
159 HGDIOBJ old_font = SelectObject(hdc, font_handle); 179 HGDIOBJ old_font = SelectObject(hdc, font_handle);
160 DCHECK(NULL != old_font); 180 DCHECK(NULL != old_font);
161 181
162 TEXTMETRIC tm; 182 TEXTMETRIC tm;
163 BOOL ret = GetTextMetrics(hdc, &tm); 183 BOOL ret = GetTextMetrics(hdc, &tm);
164 DCHECK(ret); 184 DCHECK(ret);
165 185
166 if (fonts[font_index] || hdcs[font_index]) { 186 string16 font_name = font.lfFaceName;
167 // We already have too many fonts, we will delete one and take it's place. 187 int ref_count_inc = 1;
168 DeleteObject(fonts[font_index]); 188 FontNameVector::iterator it =
169 ReleaseDC(NULL, hdcs[font_index]); 189 std::find(process_id_font_map_[process_id].begin(),
190 process_id_font_map_[process_id].end(),
191 font_name);
192 if (it == process_id_font_map_[process_id].end()) {
193 // Requested font is new to cache.
194 process_id_font_map_[process_id].push_back(font_name);
195 } else {
196 ref_count_inc = 0;
170 } 197 }
171 198
172 fonts[font_index] = font_handle; 199 if (cache_[font_name].ref_count_ == 0) { // Requested font is new to cache.
173 hdcs[font_index] = hdc; 200 cache_[font_name].ref_count_ = 1;
174 font_index = (font_index + 1) % kFontCacheSize; 201 } else { // Requested font is already in cache, release old handles.
202 DeleteObject(cache_[font_name].font_);
203 DeleteDC(cache_[font_name].dc_);
204 }
205 cache_[font_name].font_ = font_handle;
206 cache_[font_name].dc_ = hdc;
207 cache_[font_name].ref_count_ += ref_count_inc;
208 }
209
210 void ChildProcessHost::FontCache::ReleaseCachedFonts(int process_id) {
211 typedef std::map<string16, ChildProcessHost::FontCache::CacheElement>
212 FontNameToElement;
213
214 base::AutoLock lock(mutex_);
215
216 PidToFontNames::iterator it;
217 it = process_id_font_map_.find(process_id);
218 if (it == process_id_font_map_.end()) {
219 return;
220 }
221
222 for (FontNameVector::iterator i = it->second.begin(), e = it->second.end();
223 i != e; ++i) {
224 FontNameToElement::iterator element;
225 element = cache_.find(*i);
226 if (element != cache_.end()) {
227 --((*element).second.ref_count_);
228 }
229 }
230
231 process_id_font_map_.erase(it);
232 for (FontNameToElement::iterator i = cache_.begin(); i != cache_.end(); ) {
233 if (i->second.ref_count_ == 0) {
234 cache_.erase(i++);
235 } else {
236 ++i;
237 }
238 }
239 }
240
241 // static
242 void ChildProcessHost::PreCacheFont(LOGFONT font, int pid) {
243 // If a child process is running in a sandbox, GetTextMetrics()
244 // can sometimes fail. If a font has not been loaded
245 // previously, GetTextMetrics() will try to load the font
246 // from the font file. However, the sandboxed process does
247 // not have permissions to access any font files and
248 // the call fails. So we make the browser pre-load the
249 // font for us by using a dummy call to GetTextMetrics of
250 // the same font.
251 // This means the browser process just loads the font into memory so that
252 // when GDI attempt to query that font info in child process, it does not
253 // need to load that file, hence no permission issues there. Therefore,
254 // when a font is asked to be cached, we always recreates the font object
255 // to avoid the case that an in-cache font is swapped out by GDI.
256 ChildProcessHost::FontCache::GetInstance()->PreCacheFont(font, pid);
257 }
258
259 // static
260 void ChildProcessHost::ReleaseCachedFonts(int pid) {
261 // Release cached fonts that requested from a pid by decrementing the ref
262 // count. When ref count is zero, the handles are released.
263 ChildProcessHost::FontCache::GetInstance()->ReleaseCachedFonts(pid);
175 } 264 }
176 #endif // OS_WIN 265 #endif // OS_WIN
177 266
178 267
179 bool ChildProcessHost::CreateChannel() { 268 bool ChildProcessHost::CreateChannel() {
180 channel_id_ = ChildProcessInfo::GenerateRandomChannelID(this); 269 channel_id_ = ChildProcessInfo::GenerateRandomChannelID(this);
181 channel_.reset(new IPC::Channel( 270 channel_.reset(new IPC::Channel(
182 channel_id_, IPC::Channel::MODE_SERVER, &listener_)); 271 channel_id_, IPC::Channel::MODE_SERVER, &listener_));
183 if (!channel_->Connect()) 272 if (!channel_->Connect())
184 return false; 273 return false;
(...skipping 119 matching lines...) Expand 10 before | Expand all | Expand 10 after
304 for (size_t i = 0; i < host_->filters_.size(); ++i) 393 for (size_t i = 0; i < host_->filters_.size(); ++i)
305 host_->filters_[i]->OnChannelError(); 394 host_->filters_[i]->OnChannelError();
306 395
307 // This will delete host_, which will also destroy this! 396 // This will delete host_, which will also destroy this!
308 host_->OnChildDisconnected(); 397 host_->OnChildDisconnected();
309 } 398 }
310 399
311 void ChildProcessHost::ForceShutdown() { 400 void ChildProcessHost::ForceShutdown() {
312 Send(new ChildProcessMsg_Shutdown()); 401 Send(new ChildProcessMsg_Shutdown());
313 } 402 }
OLDNEW
« no previous file with comments | « content/common/child_process_host.h ('k') | content/common/child_process_messages.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698