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 base::AutoLock
lock(mutex_
);
33 // Fetch the font into memory.
34 // No matter the font is cached or not, we load it to avoid GDI swapping out
36 HDC hdc
= GetDC(NULL
);
37 HFONT font_handle
= CreateFontIndirect(&font
);
38 DCHECK(NULL
!= font_handle
);
40 HGDIOBJ old_font
= SelectObject(hdc
, font_handle
);
41 DCHECK(NULL
!= old_font
);
44 BOOL ret
= GetTextMetrics(hdc
, &tm
);
47 base::string16 font_name
= font
.lfFaceName
;
48 int ref_count_inc
= 1;
49 FontNameVector::iterator it
=
50 std::find(dispatcher_font_map_
[dispatcher
].begin(),
51 dispatcher_font_map_
[dispatcher
].end(),
53 if (it
== dispatcher_font_map_
[dispatcher
].end()) {
54 // Requested font is new to cache.
55 dispatcher_font_map_
[dispatcher
].push_back(font_name
);
60 if (cache_
[font_name
].ref_count_
== 0) { // Requested font is new to cache.
61 cache_
[font_name
].ref_count_
= 1;
62 } else { // Requested font is already in cache, release old handles.
63 SelectObject(cache_
[font_name
].dc_
, cache_
[font_name
].old_font_
);
64 DeleteObject(cache_
[font_name
].font_
);
65 ReleaseDC(NULL
, cache_
[font_name
].dc_
);
67 cache_
[font_name
].font_
= font_handle
;
68 cache_
[font_name
].dc_
= hdc
;
69 cache_
[font_name
].old_font_
= old_font
;
70 cache_
[font_name
].ref_count_
+= ref_count_inc
;
73 void ReleaseCachedFonts(FontCacheDispatcher
* dispatcher
) {
74 typedef std::map
<base::string16
, FontCache::CacheElement
> FontNameToElement
;
76 base::AutoLock
lock(mutex_
);
78 DispatcherToFontNames::iterator it
;
79 it
= dispatcher_font_map_
.find(dispatcher
);
80 if (it
== dispatcher_font_map_
.end()) {
84 for (FontNameVector::iterator i
= it
->second
.begin(), e
= it
->second
.end();
86 FontNameToElement::iterator element
;
87 element
= cache_
.find(*i
);
88 if (element
!= cache_
.end()) {
89 --((*element
).second
.ref_count_
);
93 dispatcher_font_map_
.erase(it
);
94 for (FontNameToElement::iterator i
= cache_
.begin(); i
!= cache_
.end(); ) {
95 if (i
->second
.ref_count_
== 0) {
104 struct CacheElement
{
106 : font_(NULL
), old_font_(NULL
), dc_(NULL
), ref_count_(0) {
111 if (dc_
&& old_font_
) {
112 SelectObject(dc_
, old_font_
);
117 ReleaseDC(NULL
, dc_
);
126 friend struct DefaultSingletonTraits
<FontCache
>;
131 std::map
<base::string16
, CacheElement
> cache_
;
132 DispatcherToFontNames dispatcher_font_map_
;
135 DISALLOW_COPY_AND_ASSIGN(FontCache
);
140 FontCacheDispatcher::FontCacheDispatcher()
144 bool FontCacheDispatcher::Send(IPC::Message
* message
) {
146 return sender_
->Send(message
);
152 FontCacheDispatcher::~FontCacheDispatcher() {
155 void FontCacheDispatcher::OnFilterAdded(IPC::Sender
* sender
) {
159 bool FontCacheDispatcher::OnMessageReceived(const IPC::Message
& message
) {
161 IPC_BEGIN_MESSAGE_MAP(FontCacheDispatcher
, message
)
162 IPC_MESSAGE_HANDLER(ChildProcessHostMsg_PreCacheFont
, OnPreCacheFont
)
163 IPC_MESSAGE_HANDLER(ChildProcessHostMsg_ReleaseCachedFonts
,
164 OnReleaseCachedFonts
)
165 IPC_MESSAGE_UNHANDLED(handled
= false)
166 IPC_END_MESSAGE_MAP()
170 void FontCacheDispatcher::OnChannelClosing() {
174 void FontCacheDispatcher::OnPreCacheFont(const LOGFONT
& font
) {
175 // If a child process is running in a sandbox, GetTextMetrics()
176 // can sometimes fail. If a font has not been loaded
177 // previously, GetTextMetrics() will try to load the font
178 // from the font file. However, the sandboxed process does
179 // not have permissions to access any font files and
180 // the call fails. So we make the browser pre-load the
181 // font for us by using a dummy call to GetTextMetrics of
183 // This means the browser process just loads the font into memory so that
184 // when GDI attempt to query that font info in child process, it does not
185 // need to load that file, hence no permission issues there. Therefore,
186 // when a font is asked to be cached, we always recreates the font object
187 // to avoid the case that an in-cache font is swapped out by GDI.
188 FontCache::GetInstance()->PreCacheFont(font
, this);
191 void FontCacheDispatcher::OnReleaseCachedFonts() {
192 // Release cached fonts that requested from a pid by decrementing the ref
193 // count. When ref count is zero, the handles are released.
194 FontCache::GetInstance()->ReleaseCachedFonts(this);
197 } // namespace content