Updating trunk VERSION from 2139.0 to 2140.0
[chromium-blink-merge.git] / content / renderer / renderer_font_platform_win.cc
blob089e876fb8959a7adc664d6d01b8b702ac3da21f
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"
7 #include <dwrite.h>
8 #include <string>
9 #include <vector>
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"
27 namespace {
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> {
37 public:
38 // IDWriteFontCollectionLoader methods.
39 virtual HRESULT STDMETHODCALLTYPE
40 CreateEnumeratorFromKey(IDWriteFactory* factory,
41 void const* key,
42 UINT32 key_size,
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() {};
56 private:
57 mswr::ComPtr<IDWriteFontFileLoader> file_loader_;
59 std::vector<std::wstring> reg_fonts_;
62 mswr::ComPtr<FontCollectionLoader> g_font_loader;
64 class FontFileStream
65 : public mswr::RuntimeClass<mswr::RuntimeClassFlags<mswr::ClassicCom>,
66 IDWriteFontFileStream> {
67 public:
68 // IDWriteFontFileStream methods.
69 virtual HRESULT STDMETHODCALLTYPE
70 ReadFileFragment(void const** fragment_start,
71 UINT64 file_offset,
72 UINT64 fragment_size,
73 void** context) {
74 if (!memory_.get() || !memory_->IsValid() ||
75 file_offset >= memory_->length() ||
76 (file_offset + fragment_size) > memory_->length())
77 return E_FAIL;
79 *fragment_start = static_cast<BYTE const*>(memory_->data()) +
80 static_cast<size_t>(file_offset);
81 *context = NULL;
82 return S_OK;
85 virtual void STDMETHODCALLTYPE ReleaseFileFragment(void* context) {}
87 virtual HRESULT STDMETHODCALLTYPE GetFileSize(UINT64* file_size) {
88 if (!memory_.get() || !memory_->IsValid())
89 return E_FAIL;
91 *file_size = memory_->length();
92 return S_OK;
95 virtual HRESULT STDMETHODCALLTYPE GetLastWriteTime(UINT64* last_write_time) {
96 if (!memory_.get() || !memory_->IsValid())
97 return E_FAIL;
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;
106 return S_OK;
109 FontFileStream::FontFileStream() : font_key_(0) {
112 HRESULT RuntimeClassInitialize(UINT32 font_key) {
113 base::FilePath path;
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)) {
125 memory_.reset();
126 return E_FAIL;
129 font_key_ = font_key;
131 base::debug::SetCrashKeyValue(kFontKeyName,
132 base::WideToUTF8(font_key_name));
133 return S_OK;
136 virtual ~FontFileStream() {}
138 UINT32 font_key_;
139 scoped_ptr<base::MemoryMappedFile> memory_;
142 class FontFileLoader
143 : public mswr::RuntimeClass<mswr::RuntimeClassFlags<mswr::ClassicCom>,
144 IDWriteFontFileLoader> {
145 public:
146 // IDWriteFontFileLoader methods.
147 virtual HRESULT STDMETHODCALLTYPE
148 CreateStreamFromKey(void const* ref_key,
149 UINT32 ref_key_size,
150 IDWriteFontFileStream** stream) {
151 if (ref_key_size != sizeof(UINT32))
152 return E_FAIL;
154 UINT32 font_key = *static_cast<const UINT32*>(ref_key);
155 mswr::ComPtr<FontFileStream> font_stream;
156 HRESULT hr = mswr::MakeAndInitialize<FontFileStream>(&font_stream,
157 font_key);
158 if (SUCCEEDED(hr)) {
159 *stream = font_stream.Detach();
160 return S_OK;
162 return E_FAIL;
165 FontFileLoader() {}
166 virtual ~FontFileLoader() {}
169 class FontFileEnumerator
170 : public mswr::RuntimeClass<mswr::RuntimeClassFlags<mswr::ClassicCom>,
171 IDWriteFontFileEnumerator> {
172 public:
173 // IDWriteFontFileEnumerator methods.
174 virtual HRESULT STDMETHODCALLTYPE MoveNext(BOOL* has_current_file) {
175 *has_current_file = FALSE;
177 if (current_file_)
178 current_file_.ReleaseAndGetAddressOf();
180 if (font_idx_ < g_font_loader->GetFontMapSize()) {
181 HRESULT hr =
182 factory_->CreateCustomFontFileReference(&font_idx_,
183 sizeof(UINT32),
184 file_loader_.Get(),
185 current_file_.GetAddressOf());
186 DCHECK(SUCCEEDED(hr));
187 *has_current_file = TRUE;
188 font_idx_++;
190 return S_OK;
193 virtual HRESULT STDMETHODCALLTYPE
194 GetCurrentFontFile(IDWriteFontFile** font_file) {
195 if (!current_file_) {
196 *font_file = NULL;
197 return E_FAIL;
200 *font_file = current_file_.Detach();
201 return S_OK;
204 FontFileEnumerator(const void* keys,
205 UINT32 buffer_size,
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_;
215 UINT32 font_idx_;
218 // IDWriteFontCollectionLoader methods.
219 HRESULT STDMETHODCALLTYPE FontCollectionLoader::CreateEnumeratorFromKey(
220 IDWriteFactory* factory,
221 void const* key,
222 UINT32 key_size,
223 IDWriteFontFileEnumerator** file_enumerator) {
224 *file_enumerator = mswr::Make<FontFileEnumerator>(
225 key, key_size, factory, file_loader_.Get()).Detach();
226 return S_OK;
229 // static
230 HRESULT FontCollectionLoader::Initialize(IDWriteFactory* factory) {
231 DCHECK(g_font_loader == NULL);
233 g_font_loader = mswr::Make<FontCollectionLoader>();
234 if (!g_font_loader) {
235 DCHECK(FALSE);
236 return E_FAIL;
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());
246 return S_OK;
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) !=
264 ERROR_SUCCESS) {
265 return false;
268 std::wstring name;
269 std::wstring value;
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());
283 return true;
286 } // namespace
288 namespace content {
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