1 // Copyright 2014 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/renderer/renderer_font_platform_win.h"
10 #include <wrl/implements.h>
11 #include <wrl/wrappers/corewrappers.h>
13 #include "base/debug/alias.h"
14 #include "base/debug/crash_logging.h"
15 #include "base/files/file_enumerator.h"
16 #include "base/files/file_path.h"
17 #include "base/files/memory_mapped_file.h"
18 #include "base/memory/scoped_ptr.h"
19 #include "base/memory/scoped_vector.h"
20 #include "base/path_service.h"
21 #include "base/strings/utf_string_conversions.h"
22 #include "base/time/time.h"
23 #include "base/win/iat_patch_function.h"
24 #include "base/win/registry.h"
25 #include "base/win/scoped_comptr.h"
29 namespace mswr
= Microsoft::WRL
;
30 namespace mswrw
= Microsoft::WRL::Wrappers
;
32 static const char kFontKeyName
[] = "font_key_name";
34 class FontCollectionLoader
35 : public mswr::RuntimeClass
<mswr::RuntimeClassFlags
<mswr::ClassicCom
>,
36 IDWriteFontCollectionLoader
> {
38 // IDWriteFontCollectionLoader methods.
39 virtual HRESULT STDMETHODCALLTYPE
40 CreateEnumeratorFromKey(IDWriteFactory
* factory
,
43 IDWriteFontFileEnumerator
** file_enumerator
);
45 static HRESULT
Initialize(IDWriteFactory
* factory
);
47 UINT32
GetFontMapSize();
49 std::wstring
GetFontNameFromKey(UINT32 idx
);
51 bool LoadFontListFromRegistry();
53 FontCollectionLoader() {};
54 virtual ~FontCollectionLoader() {};
57 mswr::ComPtr
<IDWriteFontFileLoader
> file_loader_
;
59 std::vector
<std::wstring
> reg_fonts_
;
62 mswr::ComPtr
<FontCollectionLoader
> g_font_loader
;
65 : public mswr::RuntimeClass
<mswr::RuntimeClassFlags
<mswr::ClassicCom
>,
66 IDWriteFontFileStream
> {
68 // IDWriteFontFileStream methods.
69 virtual HRESULT STDMETHODCALLTYPE
70 ReadFileFragment(void const** fragment_start
,
74 if (!memory_
.get() || !memory_
->IsValid() ||
75 file_offset
>= memory_
->length() ||
76 (file_offset
+ fragment_size
) > memory_
->length())
79 *fragment_start
= static_cast<BYTE
const*>(memory_
->data()) +
80 static_cast<size_t>(file_offset
);
85 virtual void STDMETHODCALLTYPE
ReleaseFileFragment(void* context
) {}
87 virtual HRESULT STDMETHODCALLTYPE
GetFileSize(UINT64
* file_size
) {
88 if (!memory_
.get() || !memory_
->IsValid())
91 *file_size
= memory_
->length();
95 virtual HRESULT STDMETHODCALLTYPE
GetLastWriteTime(UINT64
* last_write_time
) {
96 if (!memory_
.get() || !memory_
->IsValid())
99 // According to MSDN article http://goo.gl/rrSYzi the "last modified time"
100 // is used by DirectWrite font selection algorithms to determine whether
101 // one font resource is more up to date than another one.
102 // So by returning 0 we are assuming that it will treat all fonts to be
103 // equally up to date.
104 // TODO(shrikant): We should further investigate this.
105 *last_write_time
= 0;
109 FontFileStream::FontFileStream() : font_key_(0) {
112 HRESULT
RuntimeClassInitialize(UINT32 font_key
) {
114 PathService::Get(base::DIR_WINDOWS_FONTS
, &path
);
115 std::wstring
font_key_name(g_font_loader
->GetFontNameFromKey(font_key
));
116 path
= path
.Append(font_key_name
.c_str());
117 memory_
.reset(new base::MemoryMappedFile());
119 // Put some debug information on stack.
120 WCHAR font_name
[256];
121 path
.value().copy(font_name
, arraysize(font_name
));
122 base::debug::Alias(font_name
);
124 if (!memory_
->Initialize(path
)) {
129 font_key_
= font_key
;
131 base::debug::SetCrashKeyValue(kFontKeyName
,
132 base::WideToUTF8(font_key_name
));
136 virtual ~FontFileStream() {}
139 scoped_ptr
<base::MemoryMappedFile
> memory_
;
143 : public mswr::RuntimeClass
<mswr::RuntimeClassFlags
<mswr::ClassicCom
>,
144 IDWriteFontFileLoader
> {
146 // IDWriteFontFileLoader methods.
147 virtual HRESULT STDMETHODCALLTYPE
148 CreateStreamFromKey(void const* ref_key
,
150 IDWriteFontFileStream
** stream
) {
151 if (ref_key_size
!= sizeof(UINT32
))
154 UINT32 font_key
= *static_cast<const UINT32
*>(ref_key
);
155 mswr::ComPtr
<FontFileStream
> font_stream
;
156 HRESULT hr
= mswr::MakeAndInitialize
<FontFileStream
>(&font_stream
,
159 *stream
= font_stream
.Detach();
166 virtual ~FontFileLoader() {}
169 class FontFileEnumerator
170 : public mswr::RuntimeClass
<mswr::RuntimeClassFlags
<mswr::ClassicCom
>,
171 IDWriteFontFileEnumerator
> {
173 // IDWriteFontFileEnumerator methods.
174 virtual HRESULT STDMETHODCALLTYPE
MoveNext(BOOL
* has_current_file
) {
175 *has_current_file
= FALSE
;
178 current_file_
.ReleaseAndGetAddressOf();
180 if (font_idx_
< g_font_loader
->GetFontMapSize()) {
182 factory_
->CreateCustomFontFileReference(&font_idx_
,
185 current_file_
.GetAddressOf());
186 DCHECK(SUCCEEDED(hr
));
187 *has_current_file
= TRUE
;
193 virtual HRESULT STDMETHODCALLTYPE
194 GetCurrentFontFile(IDWriteFontFile
** font_file
) {
195 if (!current_file_
) {
200 *font_file
= current_file_
.Detach();
204 FontFileEnumerator(const void* keys
,
206 IDWriteFactory
* factory
,
207 IDWriteFontFileLoader
* file_loader
)
208 : factory_(factory
), file_loader_(file_loader
), font_idx_(0) {}
210 virtual ~FontFileEnumerator() {}
212 mswr::ComPtr
<IDWriteFactory
> factory_
;
213 mswr::ComPtr
<IDWriteFontFile
> current_file_
;
214 mswr::ComPtr
<IDWriteFontFileLoader
> file_loader_
;
218 // IDWriteFontCollectionLoader methods.
219 HRESULT STDMETHODCALLTYPE
FontCollectionLoader::CreateEnumeratorFromKey(
220 IDWriteFactory
* factory
,
223 IDWriteFontFileEnumerator
** file_enumerator
) {
224 *file_enumerator
= mswr::Make
<FontFileEnumerator
>(
225 key
, key_size
, factory
, file_loader_
.Get()).Detach();
230 HRESULT
FontCollectionLoader::Initialize(IDWriteFactory
* factory
) {
231 DCHECK(g_font_loader
== NULL
);
233 g_font_loader
= mswr::Make
<FontCollectionLoader
>();
234 if (!g_font_loader
) {
239 CHECK(g_font_loader
->LoadFontListFromRegistry());
241 g_font_loader
->file_loader_
= mswr::Make
<FontFileLoader
>().Detach();
243 factory
->RegisterFontFileLoader(g_font_loader
->file_loader_
.Get());
244 factory
->RegisterFontCollectionLoader(g_font_loader
.Get());
249 UINT32
FontCollectionLoader::GetFontMapSize() {
250 return reg_fonts_
.size();
253 std::wstring
FontCollectionLoader::GetFontNameFromKey(UINT32 idx
) {
254 DCHECK(idx
< reg_fonts_
.size());
255 return reg_fonts_
[idx
];
258 bool FontCollectionLoader::LoadFontListFromRegistry() {
259 const wchar_t kFontsRegistry
[] =
260 L
"Software\\Microsoft\\Windows NT\\CurrentVersion\\Fonts";
261 CHECK(reg_fonts_
.empty());
262 base::win::RegKey regkey
;
263 if (regkey
.Open(HKEY_LOCAL_MACHINE
, kFontsRegistry
, KEY_READ
) !=
270 for (DWORD idx
= 0; idx
< regkey
.GetValueCount(); idx
++) {
271 if (regkey
.GetValueNameAt(idx
, &name
) == ERROR_SUCCESS
&&
272 regkey
.ReadValue(name
.c_str(), &value
) == ERROR_SUCCESS
) {
273 base::FilePath
path(value
.c_str());
274 // We need to check if file name is the only component that exists,
275 // we will ignore all other registry entries.
276 std::vector
<base::FilePath::StringType
> components
;
277 path
.GetComponents(&components
);
278 if (components
.size() == 1) {
279 reg_fonts_
.push_back(value
.c_str());
290 mswr::ComPtr
<IDWriteFontCollection
> g_font_collection
;
292 IDWriteFontCollection
* GetCustomFontCollection(IDWriteFactory
* factory
) {
293 if (g_font_collection
.Get() != NULL
)
294 return g_font_collection
.Get();
296 base::TimeTicks start_tick
= base::TimeTicks::Now();
298 FontCollectionLoader::Initialize(factory
);
300 HRESULT hr
= factory
->CreateCustomFontCollection(
301 g_font_loader
.Get(), NULL
, 0, g_font_collection
.GetAddressOf());
303 base::TimeDelta time_delta
= base::TimeTicks::Now() - start_tick
;
304 int64 delta
= time_delta
.ToInternalValue();
305 base::debug::Alias(&delta
);
306 UINT32 size
= g_font_loader
->GetFontMapSize();
307 base::debug::Alias(&size
);
309 CHECK(SUCCEEDED(hr
));
310 CHECK(g_font_collection
.Get() != NULL
);
312 base::debug::ClearCrashKey(kFontKeyName
);
314 return g_font_collection
.Get();
317 } // namespace content