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/files/file_enumerator.h"
15 #include "base/files/file_path.h"
16 #include "base/files/memory_mapped_file.h"
17 #include "base/memory/scoped_ptr.h"
18 #include "base/memory/scoped_vector.h"
19 #include "base/path_service.h"
20 #include "base/time/time.h"
21 #include "base/win/iat_patch_function.h"
22 #include "base/win/registry.h"
23 #include "base/win/scoped_comptr.h"
27 namespace mswr = Microsoft::WRL;
28 namespace mswrw = Microsoft::WRL::Wrappers;
30 class FontCollectionLoader
31 : public mswr::RuntimeClass<mswr::RuntimeClassFlags<mswr::ClassicCom>,
32 IDWriteFontCollectionLoader> {
34 // IDWriteFontCollectionLoader methods.
35 virtual HRESULT STDMETHODCALLTYPE
36 CreateEnumeratorFromKey(IDWriteFactory* factory,
39 IDWriteFontFileEnumerator** file_enumerator);
41 static HRESULT Initialize(IDWriteFactory* factory);
43 UINT32 GetFontMapSize();
45 std::wstring GetFontNameFromKey(UINT32 idx);
47 bool LoadFontListFromRegistry();
49 FontCollectionLoader() {};
50 virtual ~FontCollectionLoader() {};
53 mswr::ComPtr<IDWriteFontFileLoader> file_loader_;
55 std::vector<std::wstring> reg_fonts_;
58 mswr::ComPtr<FontCollectionLoader> g_font_loader;
61 : public mswr::RuntimeClass<mswr::RuntimeClassFlags<mswr::ClassicCom>,
62 IDWriteFontFileStream> {
64 // IDWriteFontFileStream methods.
65 virtual HRESULT STDMETHODCALLTYPE
66 ReadFileFragment(void const** fragment_start,
70 if (!memory_.get() || !memory_->IsValid())
73 *fragment_start = static_cast<BYTE const*>(memory_->data()) +
74 static_cast<size_t>(file_offset);
79 virtual void STDMETHODCALLTYPE ReleaseFileFragment(void* context) {}
81 virtual HRESULT STDMETHODCALLTYPE GetFileSize(UINT64* file_size) {
82 if (!memory_.get() || !memory_->IsValid())
85 *file_size = memory_->length();
89 virtual HRESULT STDMETHODCALLTYPE GetLastWriteTime(UINT64* last_write_time) {
90 if (!memory_.get() || !memory_->IsValid())
93 // According to MSDN article http://goo.gl/rrSYzi the "last modified time"
94 // is used by DirectWrite font selection algorithms to determine whether
95 // one font resource is more up to date than another one.
96 // So by returning 0 we are assuming that it will treat all fonts to be
97 // equally up to date.
98 // TODO(shrikant): We should further investigate this.
103 FontFileStream::FontFileStream() : font_key_(0) {
106 HRESULT RuntimeClassInitialize(UINT32 font_key) {
108 PathService::Get(base::DIR_WINDOWS_FONTS, &path);
109 path = path.Append(g_font_loader->GetFontNameFromKey(font_key).c_str());
110 memory_.reset(new base::MemoryMappedFile());
112 // Put some debug information on stack.
113 WCHAR font_name[256];
114 path.value().copy(font_name, arraysize(font_name));
115 base::debug::Alias(font_name);
117 if (!memory_->Initialize(path)) {
122 font_key_ = font_key;
126 virtual ~FontFileStream() {}
129 scoped_ptr<base::MemoryMappedFile> memory_;
133 : public mswr::RuntimeClass<mswr::RuntimeClassFlags<mswr::ClassicCom>,
134 IDWriteFontFileLoader> {
136 // IDWriteFontFileLoader methods.
137 virtual HRESULT STDMETHODCALLTYPE
138 CreateStreamFromKey(void const* ref_key,
140 IDWriteFontFileStream** stream) {
141 if (ref_key_size != sizeof(UINT32))
144 UINT32 font_key = *static_cast<const UINT32*>(ref_key);
145 mswr::ComPtr<FontFileStream> font_stream;
146 HRESULT hr = mswr::MakeAndInitialize<FontFileStream>(&font_stream,
149 *stream = font_stream.Detach();
156 virtual ~FontFileLoader() {}
159 class FontFileEnumerator
160 : public mswr::RuntimeClass<mswr::RuntimeClassFlags<mswr::ClassicCom>,
161 IDWriteFontFileEnumerator> {
163 // IDWriteFontFileEnumerator methods.
164 virtual HRESULT STDMETHODCALLTYPE MoveNext(BOOL* has_current_file) {
165 *has_current_file = FALSE;
168 current_file_.ReleaseAndGetAddressOf();
170 if (font_idx_ < g_font_loader->GetFontMapSize()) {
172 factory_->CreateCustomFontFileReference(&font_idx_,
175 current_file_.GetAddressOf());
176 DCHECK(SUCCEEDED(hr));
177 *has_current_file = TRUE;
183 virtual HRESULT STDMETHODCALLTYPE
184 GetCurrentFontFile(IDWriteFontFile** font_file) {
185 if (!current_file_) {
190 *font_file = current_file_.Detach();
194 FontFileEnumerator(const void* keys,
196 IDWriteFactory* factory,
197 IDWriteFontFileLoader* file_loader)
198 : factory_(factory), file_loader_(file_loader), font_idx_(0) {}
200 virtual ~FontFileEnumerator() {}
202 mswr::ComPtr<IDWriteFactory> factory_;
203 mswr::ComPtr<IDWriteFontFile> current_file_;
204 mswr::ComPtr<IDWriteFontFileLoader> file_loader_;
208 // IDWriteFontCollectionLoader methods.
209 HRESULT STDMETHODCALLTYPE FontCollectionLoader::CreateEnumeratorFromKey(
210 IDWriteFactory* factory,
213 IDWriteFontFileEnumerator** file_enumerator) {
214 *file_enumerator = mswr::Make<FontFileEnumerator>(
215 key, key_size, factory, file_loader_.Get()).Detach();
220 HRESULT FontCollectionLoader::Initialize(IDWriteFactory* factory) {
221 DCHECK(g_font_loader == NULL);
223 g_font_loader = mswr::Make<FontCollectionLoader>();
224 if (!g_font_loader) {
229 CHECK(g_font_loader->LoadFontListFromRegistry());
231 g_font_loader->file_loader_ = mswr::Make<FontFileLoader>().Detach();
233 factory->RegisterFontFileLoader(g_font_loader->file_loader_.Get());
234 factory->RegisterFontCollectionLoader(g_font_loader.Get());
239 UINT32 FontCollectionLoader::GetFontMapSize() {
240 return reg_fonts_.size();
243 std::wstring FontCollectionLoader::GetFontNameFromKey(UINT32 idx) {
244 DCHECK(idx < reg_fonts_.size());
245 return reg_fonts_[idx];
248 bool FontCollectionLoader::LoadFontListFromRegistry() {
249 const wchar_t kFontsRegistry[] =
250 L"Software\\Microsoft\\Windows NT\\CurrentVersion\\Fonts";
251 CHECK(reg_fonts_.empty());
252 base::win::RegKey regkey;
253 if (regkey.Open(HKEY_LOCAL_MACHINE, kFontsRegistry, KEY_READ) !=
260 for (DWORD idx = 0; idx < regkey.GetValueCount(); idx++) {
261 if (regkey.GetValueNameAt(idx, &name) == ERROR_SUCCESS &&
262 regkey.ReadValue(name.c_str(), &value) == ERROR_SUCCESS) {
263 base::FilePath path(value.c_str());
264 // We need to check if file name is the only component that exists,
265 // we will ignore all other registry entries.
266 std::vector<base::FilePath::StringType> components;
267 path.GetComponents(&components);
268 if (components.size() == 1) {
269 reg_fonts_.push_back(value.c_str());
280 mswr::ComPtr<IDWriteFontCollection> g_font_collection;
282 IDWriteFontCollection* GetCustomFontCollection(IDWriteFactory* factory) {
283 if (g_font_collection.Get() != NULL)
284 return g_font_collection.Get();
286 base::TimeTicks start_tick = base::TimeTicks::Now();
288 FontCollectionLoader::Initialize(factory);
290 HRESULT hr = factory->CreateCustomFontCollection(
291 g_font_loader.Get(), NULL, 0, g_font_collection.GetAddressOf());
293 base::TimeDelta time_delta = base::TimeTicks::Now() - start_tick;
294 int64 delta = time_delta.ToInternalValue();
295 base::debug::Alias(&delta);
296 UINT32 size = g_font_loader->GetFontMapSize();
297 base::debug::Alias(&size);
299 CHECK(SUCCEEDED(hr));
300 CHECK(g_font_collection.Get() != NULL);
302 return g_font_collection.Get();
305 } // namespace content