blob: e7d9eff5326025da69d0849fc838712a4dddc206 [file] [log] [blame]
[email protected]ef31c68d2012-03-23 21:58:551// Copyright (c) 2012 The Chromium Authors. All rights reserved.
[email protected]e35c9a82011-12-01 18:48:412// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "content/common/font_cache_dispatcher_win.h"
6
[email protected]e35c9a82011-12-01 18:48:417#include <map>
[email protected]30fe1f92013-06-12 16:34:348#include <vector>
[email protected]e35c9a82011-12-01 18:48:419
10#include "base/logging.h"
pkasting8581fa52015-04-10 04:45:4111#include "base/profiler/scoped_tracker.h"
[email protected]30fe1f92013-06-12 16:34:3412#include "base/strings/string16.h"
[email protected]e35c9a82011-12-01 18:48:4113#include "content/common/child_process_messages.h"
14
[email protected]130757672012-10-24 00:26:1915namespace content {
[email protected]e35c9a82011-12-01 18:48:4116namespace {
[email protected]fcf75d42013-12-03 20:11:2617typedef std::vector<base::string16> FontNameVector;
[email protected]e35c9a82011-12-01 18:48:4118typedef std::map<FontCacheDispatcher*, FontNameVector> DispatcherToFontNames;
19
20class FontCache {
21 public:
22 static FontCache* GetInstance() {
23 return Singleton<FontCache>::get();
24 }
25
[email protected]53b6b582011-12-21 17:48:5426 void PreCacheFont(const LOGFONT& font, FontCacheDispatcher* dispatcher) {
pkasting8581fa52015-04-10 04:45:4127 // 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"));
30
[email protected]e35c9a82011-12-01 18:48:4131 base::AutoLock lock(mutex_);
32
33 // Fetch the font into memory.
34 // No matter the font is cached or not, we load it to avoid GDI swapping out
35 // that font file.
36 HDC hdc = GetDC(NULL);
37 HFONT font_handle = CreateFontIndirect(&font);
38 DCHECK(NULL != font_handle);
39
40 HGDIOBJ old_font = SelectObject(hdc, font_handle);
41 DCHECK(NULL != old_font);
42
43 TEXTMETRIC tm;
44 BOOL ret = GetTextMetrics(hdc, &tm);
45 DCHECK(ret);
46
[email protected]fcf75d42013-12-03 20:11:2647 base::string16 font_name = font.lfFaceName;
[email protected]e35c9a82011-12-01 18:48:4148 int ref_count_inc = 1;
49 FontNameVector::iterator it =
50 std::find(dispatcher_font_map_[dispatcher].begin(),
51 dispatcher_font_map_[dispatcher].end(),
52 font_name);
53 if (it == dispatcher_font_map_[dispatcher].end()) {
54 // Requested font is new to cache.
55 dispatcher_font_map_[dispatcher].push_back(font_name);
56 } else {
57 ref_count_inc = 0;
58 }
59
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.
[email protected]ef31c68d2012-03-23 21:58:5563 SelectObject(cache_[font_name].dc_, cache_[font_name].old_font_);
[email protected]e35c9a82011-12-01 18:48:4164 DeleteObject(cache_[font_name].font_);
[email protected]ef31c68d2012-03-23 21:58:5565 ReleaseDC(NULL, cache_[font_name].dc_);
[email protected]e35c9a82011-12-01 18:48:4166 }
67 cache_[font_name].font_ = font_handle;
68 cache_[font_name].dc_ = hdc;
[email protected]ef31c68d2012-03-23 21:58:5569 cache_[font_name].old_font_ = old_font;
[email protected]e35c9a82011-12-01 18:48:4170 cache_[font_name].ref_count_ += ref_count_inc;
71 }
72
73 void ReleaseCachedFonts(FontCacheDispatcher* dispatcher) {
[email protected]fcf75d42013-12-03 20:11:2674 typedef std::map<base::string16, FontCache::CacheElement> FontNameToElement;
[email protected]e35c9a82011-12-01 18:48:4175
76 base::AutoLock lock(mutex_);
77
78 DispatcherToFontNames::iterator it;
79 it = dispatcher_font_map_.find(dispatcher);
80 if (it == dispatcher_font_map_.end()) {
81 return;
82 }
83
84 for (FontNameVector::iterator i = it->second.begin(), e = it->second.end();
85 i != e; ++i) {
86 FontNameToElement::iterator element;
87 element = cache_.find(*i);
88 if (element != cache_.end()) {
89 --((*element).second.ref_count_);
90 }
91 }
92
93 dispatcher_font_map_.erase(it);
94 for (FontNameToElement::iterator i = cache_.begin(); i != cache_.end(); ) {
95 if (i->second.ref_count_ == 0) {
96 cache_.erase(i++);
97 } else {
98 ++i;
99 }
100 }
101 }
102
103 private:
104 struct CacheElement {
105 CacheElement()
[email protected]ef31c68d2012-03-23 21:58:55106 : font_(NULL), old_font_(NULL), dc_(NULL), ref_count_(0) {
[email protected]e35c9a82011-12-01 18:48:41107 }
108
109 ~CacheElement() {
110 if (font_) {
[email protected]ef31c68d2012-03-23 21:58:55111 if (dc_ && old_font_) {
112 SelectObject(dc_, old_font_);
113 }
[email protected]e35c9a82011-12-01 18:48:41114 DeleteObject(font_);
115 }
116 if (dc_) {
[email protected]ef31c68d2012-03-23 21:58:55117 ReleaseDC(NULL, dc_);
[email protected]e35c9a82011-12-01 18:48:41118 }
119 }
120
121 HFONT font_;
[email protected]ef31c68d2012-03-23 21:58:55122 HGDIOBJ old_font_;
[email protected]e35c9a82011-12-01 18:48:41123 HDC dc_;
124 int ref_count_;
125 };
126 friend struct DefaultSingletonTraits<FontCache>;
127
128 FontCache() {
129 }
130
[email protected]fcf75d42013-12-03 20:11:26131 std::map<base::string16, CacheElement> cache_;
[email protected]e35c9a82011-12-01 18:48:41132 DispatcherToFontNames dispatcher_font_map_;
133 base::Lock mutex_;
134
135 DISALLOW_COPY_AND_ASSIGN(FontCache);
136};
137
138}
139
140FontCacheDispatcher::FontCacheDispatcher()
[email protected]d1549b82014-06-13 06:07:14141 : sender_(NULL) {
[email protected]e35c9a82011-12-01 18:48:41142}
143
thakisefa363a2015-05-02 01:28:44144bool FontCacheDispatcher::Send(IPC::Message* message) {
145 if (sender_)
146 return sender_->Send(message);
147
148 delete message;
149 return false;
150}
151
[email protected]e35c9a82011-12-01 18:48:41152FontCacheDispatcher::~FontCacheDispatcher() {
153}
154
[email protected]d1549b82014-06-13 06:07:14155void FontCacheDispatcher::OnFilterAdded(IPC::Sender* sender) {
156 sender_ = sender;
[email protected]e35c9a82011-12-01 18:48:41157}
158
159bool FontCacheDispatcher::OnMessageReceived(const IPC::Message& message) {
160 bool handled = true;
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()
167 return handled;
168}
169
170void FontCacheDispatcher::OnChannelClosing() {
[email protected]d1549b82014-06-13 06:07:14171 sender_ = NULL;
[email protected]e35c9a82011-12-01 18:48:41172}
173
[email protected]e35c9a82011-12-01 18:48:41174void 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
182 // the same font.
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);
189}
190
191void 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);
195}
[email protected]130757672012-10-24 00:26:19196
197} // namespace content