| Index: content/common/child_process_host.cc
|
| diff --git a/content/common/child_process_host.cc b/content/common/child_process_host.cc
|
| index 13d6ba6a3320aae83db9fc8e865e311672cbdd76..218d3b649303414aa0b444d06aa60fe47cf3854b 100644
|
| --- a/content/common/child_process_host.cc
|
| +++ b/content/common/child_process_host.cc
|
| @@ -130,27 +130,31 @@ FilePath ChildProcessHost::GetChildPath(int flags) {
|
| }
|
|
|
| #if defined(OS_WIN)
|
| +ChildProcessHost::FontCache::CacheElement::CacheElement()
|
| + : font_(NULL), dc_(NULL), ref_count_(0) {
|
| +}
|
| +
|
| +ChildProcessHost::FontCache::CacheElement::~CacheElement() {
|
| + if (font_) {
|
| + DeleteObject(font_);
|
| + }
|
| + if (dc_) {
|
| + DeleteDC(dc_);
|
| + }
|
| +}
|
| +
|
| // static
|
| -void ChildProcessHost::PreCacheFont(LOGFONT font) {
|
| - // If a child process is running in a sandbox, GetTextMetrics()
|
| - // can sometimes fail. If a font has not been loaded
|
| - // previously, GetTextMetrics() will try to load the font
|
| - // from the font file. However, the sandboxed process does
|
| - // not have permissions to access any font files and
|
| - // the call fails. So we make the browser pre-load the
|
| - // font for us by using a dummy call to GetTextMetrics of
|
| - // the same font.
|
| +ChildProcessHost::FontCache* ChildProcessHost::FontCache::GetInstance() {
|
| + return Singleton<ChildProcessHost::FontCache>::get();
|
| +}
|
|
|
| - // Maintain a circular queue for the fonts and DCs to be cached.
|
| - // font_index maintains next available location in the queue.
|
| - static const int kFontCacheSize = 32;
|
| - static HFONT fonts[kFontCacheSize] = {0};
|
| - static HDC hdcs[kFontCacheSize] = {0};
|
| - static size_t font_index = 0;
|
| +void ChildProcessHost::FontCache::PreCacheFont(LOGFONT font, int pid) {
|
| + typedef std::map<std::wstring, ChildProcessHost::FontCache::CacheElement>
|
| + FontNameToElement;
|
|
|
| - UMA_HISTOGRAM_COUNTS_100("Memory.CachedFontAndDC",
|
| - fonts[kFontCacheSize-1] ? kFontCacheSize : static_cast<int>(font_index));
|
| + base::AutoLock lock(mutex_);
|
|
|
| + // Fetch the font into memory
|
| HDC hdc = GetDC(NULL);
|
| HFONT font_handle = CreateFontIndirect(&font);
|
| DCHECK(NULL != font_handle);
|
| @@ -162,15 +166,75 @@ void ChildProcessHost::PreCacheFont(LOGFONT font) {
|
| BOOL ret = GetTextMetrics(hdc, &tm);
|
| DCHECK(ret);
|
|
|
| - if (fonts[font_index] || hdcs[font_index]) {
|
| - // We already have too many fonts, we will delete one and take it's place.
|
| - DeleteObject(fonts[font_index]);
|
| - ReleaseDC(NULL, hdcs[font_index]);
|
| + std::wstring font_name = font.lfFaceName;
|
| + int ref_count_inc = 1;
|
| + FontNameVector::iterator it = std::find(pid_font_map_[pid].begin(),
|
| + pid_font_map_[pid].end(),
|
| + font_name);
|
| + if (it == pid_font_map_[pid].end()) { // New font
|
| + pid_font_map_[pid].push_back(font_name);
|
| + } else {
|
| + ref_count_inc = 0;
|
| + }
|
| +
|
| + if (cache_[font_name].ref_count_ == 0) { // New element
|
| + cache_[font_name].ref_count_ = 1;
|
| + } else {
|
| + DeleteObject(cache_[font_name].font_);
|
| + DeleteDC(cache_[font_name].dc_);
|
| }
|
| + cache_[font_name].font_ = font_handle;
|
| + cache_[font_name].dc_ = hdc;
|
| + cache_[font_name].ref_count_ += ref_count_inc;
|
| +}
|
| +
|
| +void ChildProcessHost::FontCache::ReleaseCachedFont(int pid) {
|
| + typedef std::map<std::wstring, ChildProcessHost::FontCache::CacheElement>
|
| + FontNameToElement;
|
|
|
| - fonts[font_index] = font_handle;
|
| - hdcs[font_index] = hdc;
|
| - font_index = (font_index + 1) % kFontCacheSize;
|
| + base::AutoLock lock(mutex_);
|
| +
|
| + PidToFontNames::iterator it;
|
| + it = pid_font_map_.find(pid);
|
| + if (it == pid_font_map_.end()) {
|
| + return;
|
| + }
|
| +
|
| + for (FontNameVector::iterator i = it->second.begin(), e = it->second.end();
|
| + i != e; ++i) {
|
| + FontNameToElement::iterator element;
|
| + element = cache_.find(*i);
|
| + if (element != cache_.end()) {
|
| + --((*element).second.ref_count_);
|
| + }
|
| + }
|
| +
|
| + pid_font_map_.erase(it);
|
| + for (FontNameToElement::iterator i = cache_.begin(); i != cache_.end(); ) {
|
| + if (i->second.ref_count_ == 0) {
|
| + cache_.erase(i++);
|
| + } else {
|
| + ++i;
|
| + }
|
| + }
|
| +}
|
| +
|
| +// static
|
| +void ChildProcessHost::PreCacheFont(LOGFONT font, int pid) {
|
| + // If a child process is running in a sandbox, GetTextMetrics()
|
| + // can sometimes fail. If a font has not been loaded
|
| + // previously, GetTextMetrics() will try to load the font
|
| + // from the font file. However, the sandboxed process does
|
| + // not have permissions to access any font files and
|
| + // the call fails. So we make the browser pre-load the
|
| + // font for us by using a dummy call to GetTextMetrics of
|
| + // the same font.
|
| + ChildProcessHost::FontCache::GetInstance()->PreCacheFont(font, pid);
|
| +}
|
| +
|
| +// static
|
| +void ChildProcessHost::ReleaseCachedFont(int pid) {
|
| + ChildProcessHost::FontCache::GetInstance()->ReleaseCachedFont(pid);
|
| }
|
| #endif // OS_WIN
|
|
|
|
|