1 // Copyright (c) 2012 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.
5 #include "content/common/font_cache_dispatcher_win.h"
10 #include "base/logging.h"
11 #include "base/profiler/scoped_tracker.h"
12 #include "base/strings/string16.h"
13 #include "content/common/child_process_messages.h"
17 typedef std::vector
<base::string16
> FontNameVector
;
18 typedef std::map
<FontCacheDispatcher
*, FontNameVector
> DispatcherToFontNames
;
22 static FontCache
* GetInstance() {
23 return Singleton
<FontCache
>::get();
26 void PreCacheFont(const LOGFONT
& font
, FontCacheDispatcher
* dispatcher
) {
27 // TODO(ananta): Remove ScopedTracker below once crbug.com/90127 is fixed.
28 tracked_objects::ScopedTracker
tracking_profile(
29 FROM_HERE_WITH_EXPLICIT_FUNCTION("90127 FontCache::PreCacheFont"));
31 typedef std::map
<base::string16
, FontCache::CacheElement
> FontNameToElement
;
33 base::AutoLock
lock(mutex_
);
35 // Fetch the font into memory.
36 // No matter the font is cached or not, we load it to avoid GDI swapping out
38 HDC hdc
= GetDC(NULL
);
39 HFONT font_handle
= CreateFontIndirect(&font
);
40 DCHECK(NULL
!= font_handle
);
42 HGDIOBJ old_font
= SelectObject(hdc
, font_handle
);
43 DCHECK(NULL
!= old_font
);
46 BOOL ret
= GetTextMetrics(hdc
, &tm
);
49 base::string16 font_name
= font
.lfFaceName
;
50 int ref_count_inc
= 1;
51 FontNameVector::iterator it
=
52 std::find(dispatcher_font_map_
[dispatcher
].begin(),
53 dispatcher_font_map_
[dispatcher
].end(),
55 if (it
== dispatcher_font_map_
[dispatcher
].end()) {
56 // Requested font is new to cache.
57 dispatcher_font_map_
[dispatcher
].push_back(font_name
);
62 if (cache_
[font_name
].ref_count_
== 0) { // Requested font is new to cache.
63 cache_
[font_name
].ref_count_
= 1;
64 } else { // Requested font is already in cache, release old handles.
65 SelectObject(cache_
[font_name
].dc_
, cache_
[font_name
].old_font_
);
66 DeleteObject(cache_
[font_name
].font_
);
67 ReleaseDC(NULL
, cache_
[font_name
].dc_
);
69 cache_
[font_name
].font_
= font_handle
;
70 cache_
[font_name
].dc_
= hdc
;
71 cache_
[font_name
].old_font_
= old_font
;
72 cache_
[font_name
].ref_count_
+= ref_count_inc
;
75 void ReleaseCachedFonts(FontCacheDispatcher
* dispatcher
) {
76 typedef std::map
<base::string16
, FontCache::CacheElement
> FontNameToElement
;
78 base::AutoLock
lock(mutex_
);
80 DispatcherToFontNames::iterator it
;
81 it
= dispatcher_font_map_
.find(dispatcher
);
82 if (it
== dispatcher_font_map_
.end()) {
86 for (FontNameVector::iterator i
= it
->second
.begin(), e
= it
->second
.end();
88 FontNameToElement::iterator element
;
89 element
= cache_
.find(*i
);
90 if (element
!= cache_
.end()) {
91 --((*element
).second
.ref_count_
);
95 dispatcher_font_map_
.erase(it
);
96 for (FontNameToElement::iterator i
= cache_
.begin(); i
!= cache_
.end(); ) {
97 if (i
->second
.ref_count_
== 0) {
106 struct CacheElement
{
108 : font_(NULL
), old_font_(NULL
), dc_(NULL
), ref_count_(0) {
113 if (dc_
&& old_font_
) {
114 SelectObject(dc_
, old_font_
);
119 ReleaseDC(NULL
, dc_
);
128 friend struct DefaultSingletonTraits
<FontCache
>;
133 std::map
<base::string16
, CacheElement
> cache_
;
134 DispatcherToFontNames dispatcher_font_map_
;
137 DISALLOW_COPY_AND_ASSIGN(FontCache
);
142 FontCacheDispatcher::FontCacheDispatcher()
146 FontCacheDispatcher::~FontCacheDispatcher() {
149 void FontCacheDispatcher::OnFilterAdded(IPC::Sender
* sender
) {
153 bool FontCacheDispatcher::OnMessageReceived(const IPC::Message
& message
) {
155 IPC_BEGIN_MESSAGE_MAP(FontCacheDispatcher
, message
)
156 IPC_MESSAGE_HANDLER(ChildProcessHostMsg_PreCacheFont
, OnPreCacheFont
)
157 IPC_MESSAGE_HANDLER(ChildProcessHostMsg_ReleaseCachedFonts
,
158 OnReleaseCachedFonts
)
159 IPC_MESSAGE_UNHANDLED(handled
= false)
160 IPC_END_MESSAGE_MAP()
164 void FontCacheDispatcher::OnChannelClosing() {
168 bool FontCacheDispatcher::Send(IPC::Message
* message
) {
170 return sender_
->Send(message
);
176 void FontCacheDispatcher::OnPreCacheFont(const LOGFONT
& font
) {
177 // If a child process is running in a sandbox, GetTextMetrics()
178 // can sometimes fail. If a font has not been loaded
179 // previously, GetTextMetrics() will try to load the font
180 // from the font file. However, the sandboxed process does
181 // not have permissions to access any font files and
182 // the call fails. So we make the browser pre-load the
183 // font for us by using a dummy call to GetTextMetrics of
185 // This means the browser process just loads the font into memory so that
186 // when GDI attempt to query that font info in child process, it does not
187 // need to load that file, hence no permission issues there. Therefore,
188 // when a font is asked to be cached, we always recreates the font object
189 // to avoid the case that an in-cache font is swapped out by GDI.
190 FontCache::GetInstance()->PreCacheFont(font
, this);
193 void FontCacheDispatcher::OnReleaseCachedFonts() {
194 // Release cached fonts that requested from a pid by decrementing the ref
195 // count. When ref count is zero, the handles are released.
196 FontCache::GetInstance()->ReleaseCachedFonts(this);
199 } // namespace content