Index: content/common/font_cache_dispatcher_win.cc |
=================================================================== |
--- content/common/font_cache_dispatcher_win.cc (revision 0) |
+++ content/common/font_cache_dispatcher_win.cc (revision 0) |
@@ -0,0 +1,185 @@ |
+// Copyright (c) 2011 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#include "content/common/font_cache_dispatcher_win.h" |
+ |
+#include <vector> |
+#include <map> |
+ |
+#include "base/logging.h" |
+#include "base/string16.h" |
+#include "content/common/child_process_messages.h" |
+ |
+namespace { |
+typedef std::vector<string16> FontNameVector; |
+typedef std::map<FontCacheDispatcher*, FontNameVector> DispatcherToFontNames; |
+ |
+class FontCache { |
+ public: |
+ static FontCache* GetInstance() { |
+ return Singleton<FontCache>::get(); |
+ } |
+ |
+ void PreCacheFont(LOGFONT font, FontCacheDispatcher* dispatcher) { |
+ typedef std::map<string16, FontCache::CacheElement> FontNameToElement; |
+ |
+ base::AutoLock lock(mutex_); |
+ |
+ // Fetch the font into memory. |
+ // No matter the font is cached or not, we load it to avoid GDI swapping out |
+ // that font file. |
+ HDC hdc = GetDC(NULL); |
+ HFONT font_handle = CreateFontIndirect(&font); |
+ DCHECK(NULL != font_handle); |
+ |
+ HGDIOBJ old_font = SelectObject(hdc, font_handle); |
+ DCHECK(NULL != old_font); |
+ |
+ TEXTMETRIC tm; |
+ BOOL ret = GetTextMetrics(hdc, &tm); |
+ DCHECK(ret); |
+ |
+ string16 font_name = font.lfFaceName; |
+ int ref_count_inc = 1; |
+ FontNameVector::iterator it = |
+ std::find(dispatcher_font_map_[dispatcher].begin(), |
+ dispatcher_font_map_[dispatcher].end(), |
+ font_name); |
+ if (it == dispatcher_font_map_[dispatcher].end()) { |
+ // Requested font is new to cache. |
+ dispatcher_font_map_[dispatcher].push_back(font_name); |
+ } else { |
+ ref_count_inc = 0; |
+ } |
+ |
+ if (cache_[font_name].ref_count_ == 0) { // Requested font is new to cache. |
+ cache_[font_name].ref_count_ = 1; |
+ } else { // Requested font is already in cache, release old handles. |
+ 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 ReleaseCachedFonts(FontCacheDispatcher* dispatcher) { |
+ typedef std::map<string16, FontCache::CacheElement> FontNameToElement; |
+ |
+ base::AutoLock lock(mutex_); |
+ |
+ DispatcherToFontNames::iterator it; |
+ it = dispatcher_font_map_.find(dispatcher); |
+ if (it == dispatcher_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_); |
+ } |
+ } |
+ |
+ dispatcher_font_map_.erase(it); |
+ for (FontNameToElement::iterator i = cache_.begin(); i != cache_.end(); ) { |
+ if (i->second.ref_count_ == 0) { |
+ cache_.erase(i++); |
+ } else { |
+ ++i; |
+ } |
+ } |
+ } |
+ |
+ private: |
+ struct CacheElement { |
+ CacheElement() |
+ : font_(NULL), dc_(NULL), ref_count_(0) { |
+ } |
+ |
+ ~CacheElement() { |
+ if (font_) { |
+ DeleteObject(font_); |
+ } |
+ if (dc_) { |
+ DeleteDC(dc_); |
+ } |
+ } |
+ |
+ HFONT font_; |
+ HDC dc_; |
+ int ref_count_; |
+ }; |
+ friend struct DefaultSingletonTraits<FontCache>; |
+ |
+ FontCache() { |
+ } |
+ |
+ std::map<string16, CacheElement> cache_; |
+ DispatcherToFontNames dispatcher_font_map_; |
+ base::Lock mutex_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(FontCache); |
+}; |
+ |
+} |
+ |
+FontCacheDispatcher::FontCacheDispatcher() |
+ : channel_(NULL) { |
+} |
+ |
+FontCacheDispatcher::~FontCacheDispatcher() { |
+} |
+ |
+void FontCacheDispatcher::OnFilterAdded(IPC::Channel* channel) { |
+ channel_ = channel; |
+} |
+ |
+bool FontCacheDispatcher::OnMessageReceived(const IPC::Message& message) { |
+ bool handled = true; |
+ IPC_BEGIN_MESSAGE_MAP(FontCacheDispatcher, message) |
+ IPC_MESSAGE_HANDLER(ChildProcessHostMsg_PreCacheFont, OnPreCacheFont) |
+ IPC_MESSAGE_HANDLER(ChildProcessHostMsg_ReleaseCachedFonts, |
+ OnReleaseCachedFonts) |
+ IPC_MESSAGE_UNHANDLED(handled = false) |
+ IPC_END_MESSAGE_MAP() |
+ return handled; |
+} |
+ |
+void FontCacheDispatcher::OnChannelClosing() { |
+ channel_ = NULL; |
+} |
+ |
+bool FontCacheDispatcher::Send(IPC::Message* message) { |
+ if (channel_) |
+ return channel_->Send(message); |
+ |
+ delete message; |
+ return false; |
+} |
+ |
+void FontCacheDispatcher::OnPreCacheFont(const 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. |
+ // This means the browser process just loads the font into memory so that |
+ // when GDI attempt to query that font info in child process, it does not |
+ // need to load that file, hence no permission issues there. Therefore, |
+ // when a font is asked to be cached, we always recreates the font object |
+ // to avoid the case that an in-cache font is swapped out by GDI. |
+ FontCache::GetInstance()->PreCacheFont(font, this); |
+} |
+ |
+void FontCacheDispatcher::OnReleaseCachedFonts() { |
+ // Release cached fonts that requested from a pid by decrementing the ref |
+ // count. When ref count is zero, the handles are released. |
+ FontCache::GetInstance()->ReleaseCachedFonts(this); |
+} |
Property changes on: content\common\font_cache_dispatcher_win.cc |
___________________________________________________________________ |
Added: svn:eol-style |
+ LF |