Chromecast: extracts Linux window creation code to a common place.
[chromium-blink-merge.git] / content / renderer / renderer_font_platform_win.cc
blob380bbd446699c3ef1a59099000d4f1ea6e822ce5
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/metrics/histogram.h"
21 #include "base/path_service.h"
22 #include "base/strings/utf_string_conversions.h"
23 #include "base/time/time.h"
24 #include "base/win/iat_patch_function.h"
25 #include "base/win/registry.h"
26 #include "base/win/scoped_comptr.h"
28 namespace {
30 namespace mswr = Microsoft::WRL;
31 namespace mswrw = Microsoft::WRL::Wrappers;
33 static const char kFontKeyName[] = "font_key_name";
35 class FontCollectionLoader
36 : public mswr::RuntimeClass<mswr::RuntimeClassFlags<mswr::ClassicCom>,
37 IDWriteFontCollectionLoader> {
38 public:
39 // IDWriteFontCollectionLoader methods.
40 virtual HRESULT STDMETHODCALLTYPE
41 CreateEnumeratorFromKey(IDWriteFactory* factory,
42 void const* key,
43 UINT32 key_size,
44 IDWriteFontFileEnumerator** file_enumerator);
46 static HRESULT Initialize(IDWriteFactory* factory);
48 UINT32 GetFontMapSize();
50 std::wstring GetFontNameFromKey(UINT32 idx);
52 bool LoadFontListFromRegistry();
53 bool LoadRestrictedFontList();
55 FontCollectionLoader() {};
56 virtual ~FontCollectionLoader() {};
58 private:
59 mswr::ComPtr<IDWriteFontFileLoader> file_loader_;
61 std::vector<std::wstring> reg_fonts_;
64 mswr::ComPtr<FontCollectionLoader> g_font_loader;
66 class FontFileStream
67 : public mswr::RuntimeClass<mswr::RuntimeClassFlags<mswr::ClassicCom>,
68 IDWriteFontFileStream> {
69 public:
70 // IDWriteFontFileStream methods.
71 virtual HRESULT STDMETHODCALLTYPE
72 ReadFileFragment(void const** fragment_start,
73 UINT64 file_offset,
74 UINT64 fragment_size,
75 void** context) {
76 if (!memory_.get() || !memory_->IsValid() ||
77 file_offset >= memory_->length() ||
78 (file_offset + fragment_size) > memory_->length())
79 return E_FAIL;
81 *fragment_start = static_cast<BYTE const*>(memory_->data()) +
82 static_cast<size_t>(file_offset);
83 *context = NULL;
84 return S_OK;
87 virtual void STDMETHODCALLTYPE ReleaseFileFragment(void* context) {}
89 virtual HRESULT STDMETHODCALLTYPE GetFileSize(UINT64* file_size) {
90 if (!memory_.get() || !memory_->IsValid())
91 return E_FAIL;
93 *file_size = memory_->length();
94 return S_OK;
97 virtual HRESULT STDMETHODCALLTYPE GetLastWriteTime(UINT64* last_write_time) {
98 if (!memory_.get() || !memory_->IsValid())
99 return E_FAIL;
101 // According to MSDN article http://goo.gl/rrSYzi the "last modified time"
102 // is used by DirectWrite font selection algorithms to determine whether
103 // one font resource is more up to date than another one.
104 // So by returning 0 we are assuming that it will treat all fonts to be
105 // equally up to date.
106 // TODO(shrikant): We should further investigate this.
107 *last_write_time = 0;
108 return S_OK;
111 FontFileStream::FontFileStream() : font_key_(0) {
114 HRESULT RuntimeClassInitialize(UINT32 font_key) {
115 base::FilePath path;
116 PathService::Get(base::DIR_WINDOWS_FONTS, &path);
117 std::wstring font_key_name(g_font_loader->GetFontNameFromKey(font_key));
118 path = path.Append(font_key_name.c_str());
119 memory_.reset(new base::MemoryMappedFile());
121 // Put some debug information on stack.
122 WCHAR font_name[256];
123 path.value().copy(font_name, arraysize(font_name));
124 base::debug::Alias(font_name);
126 if (!memory_->Initialize(path)) {
127 memory_.reset();
128 return E_FAIL;
131 font_key_ = font_key;
133 base::debug::SetCrashKeyValue(kFontKeyName,
134 base::WideToUTF8(font_key_name));
135 return S_OK;
138 virtual ~FontFileStream() {}
140 UINT32 font_key_;
141 scoped_ptr<base::MemoryMappedFile> memory_;
144 class FontFileLoader
145 : public mswr::RuntimeClass<mswr::RuntimeClassFlags<mswr::ClassicCom>,
146 IDWriteFontFileLoader> {
147 public:
148 // IDWriteFontFileLoader methods.
149 virtual HRESULT STDMETHODCALLTYPE
150 CreateStreamFromKey(void const* ref_key,
151 UINT32 ref_key_size,
152 IDWriteFontFileStream** stream) {
153 if (ref_key_size != sizeof(UINT32))
154 return E_FAIL;
156 UINT32 font_key = *static_cast<const UINT32*>(ref_key);
157 mswr::ComPtr<FontFileStream> font_stream;
158 HRESULT hr = mswr::MakeAndInitialize<FontFileStream>(&font_stream,
159 font_key);
160 if (SUCCEEDED(hr)) {
161 *stream = font_stream.Detach();
162 return S_OK;
164 return E_FAIL;
167 FontFileLoader() {}
168 virtual ~FontFileLoader() {}
171 class FontFileEnumerator
172 : public mswr::RuntimeClass<mswr::RuntimeClassFlags<mswr::ClassicCom>,
173 IDWriteFontFileEnumerator> {
174 public:
175 // IDWriteFontFileEnumerator methods.
176 virtual HRESULT STDMETHODCALLTYPE MoveNext(BOOL* has_current_file) {
177 *has_current_file = FALSE;
179 if (current_file_)
180 current_file_.ReleaseAndGetAddressOf();
182 if (font_idx_ < g_font_loader->GetFontMapSize()) {
183 HRESULT hr =
184 factory_->CreateCustomFontFileReference(&font_idx_,
185 sizeof(UINT32),
186 file_loader_.Get(),
187 current_file_.GetAddressOf());
188 DCHECK(SUCCEEDED(hr));
189 *has_current_file = TRUE;
190 font_idx_++;
192 return S_OK;
195 virtual HRESULT STDMETHODCALLTYPE
196 GetCurrentFontFile(IDWriteFontFile** font_file) {
197 if (!current_file_) {
198 *font_file = NULL;
199 return E_FAIL;
202 *font_file = current_file_.Detach();
203 return S_OK;
206 FontFileEnumerator(const void* keys,
207 UINT32 buffer_size,
208 IDWriteFactory* factory,
209 IDWriteFontFileLoader* file_loader)
210 : factory_(factory), file_loader_(file_loader), font_idx_(0) {}
212 virtual ~FontFileEnumerator() {}
214 mswr::ComPtr<IDWriteFactory> factory_;
215 mswr::ComPtr<IDWriteFontFile> current_file_;
216 mswr::ComPtr<IDWriteFontFileLoader> file_loader_;
217 UINT32 font_idx_;
220 // IDWriteFontCollectionLoader methods.
221 HRESULT STDMETHODCALLTYPE FontCollectionLoader::CreateEnumeratorFromKey(
222 IDWriteFactory* factory,
223 void const* key,
224 UINT32 key_size,
225 IDWriteFontFileEnumerator** file_enumerator) {
226 *file_enumerator = mswr::Make<FontFileEnumerator>(
227 key, key_size, factory, file_loader_.Get()).Detach();
228 return S_OK;
231 // static
232 HRESULT FontCollectionLoader::Initialize(IDWriteFactory* factory) {
233 DCHECK(g_font_loader == NULL);
235 g_font_loader = mswr::Make<FontCollectionLoader>();
236 if (!g_font_loader) {
237 DCHECK(FALSE);
238 return E_FAIL;
241 CHECK(g_font_loader->LoadFontListFromRegistry());
243 g_font_loader->file_loader_ = mswr::Make<FontFileLoader>().Detach();
245 factory->RegisterFontFileLoader(g_font_loader->file_loader_.Get());
246 factory->RegisterFontCollectionLoader(g_font_loader.Get());
248 return S_OK;
251 UINT32 FontCollectionLoader::GetFontMapSize() {
252 return reg_fonts_.size();
255 std::wstring FontCollectionLoader::GetFontNameFromKey(UINT32 idx) {
256 DCHECK(idx < reg_fonts_.size());
257 return reg_fonts_[idx];
260 bool FontCollectionLoader::LoadFontListFromRegistry() {
261 const wchar_t kFontsRegistry[] =
262 L"Software\\Microsoft\\Windows NT\\CurrentVersion\\Fonts";
263 CHECK(reg_fonts_.empty());
264 base::win::RegKey regkey;
265 if (regkey.Open(HKEY_LOCAL_MACHINE, kFontsRegistry, KEY_READ) !=
266 ERROR_SUCCESS) {
267 return false;
270 base::FilePath system_font_path;
271 PathService::Get(base::DIR_WINDOWS_FONTS, &system_font_path);
273 std::wstring name;
274 std::wstring value;
275 for (DWORD idx = 0; idx < regkey.GetValueCount(); idx++) {
276 if (regkey.GetValueNameAt(idx, &name) == ERROR_SUCCESS &&
277 regkey.ReadValue(name.c_str(), &value) == ERROR_SUCCESS) {
278 base::FilePath path(value.c_str());
279 // We need to check if file name is the only component that exists,
280 // we will ignore all other registry entries.
281 std::vector<base::FilePath::StringType> components;
282 path.GetComponents(&components);
283 if (components.size() == 1 ||
284 base::FilePath::CompareEqualIgnoreCase(system_font_path.value(),
285 path.DirName().value())) {
286 reg_fonts_.push_back(path.BaseName().value());
290 UMA_HISTOGRAM_COUNTS("DirectWrite.Fonts.Loaded", reg_fonts_.size());
291 UMA_HISTOGRAM_COUNTS("DirectWrite.Fonts.Ignored",
292 regkey.GetValueCount() - reg_fonts_.size());
293 return true;
296 // This list is mainly based on prefs/prefs_tab_helper.cc kFontDefaults.
297 const wchar_t* kRestrictedFontSet[] = {
298 // These are the "Web Safe" fonts.
299 L"times.ttf", // IDS_STANDARD_FONT_FAMILY
300 L"timesbd.ttf", // IDS_STANDARD_FONT_FAMILY
301 L"timesbi.ttf", // IDS_STANDARD_FONT_FAMILY
302 L"timesi.ttf", // IDS_STANDARD_FONT_FAMILY
303 L"cour.ttf", // IDS_FIXED_FONT_FAMILY
304 L"courbd.ttf", // IDS_FIXED_FONT_FAMILY
305 L"courbi.ttf", // IDS_FIXED_FONT_FAMILY
306 L"couri.ttf", // IDS_FIXED_FONT_FAMILY
307 L"consola.ttf", // IDS_FIXED_FONT_FAMILY_ALT_WIN
308 L"consolab.ttf", // IDS_FIXED_FONT_FAMILY_ALT_WIN
309 L"consolai.ttf", // IDS_FIXED_FONT_FAMILY_ALT_WIN
310 L"consolaz.ttf", // IDS_FIXED_FONT_FAMILY_ALT_WIN
311 L"arial.ttf", // IDS_SANS_SERIF_FONT_FAMILY
312 L"arialbd.ttf", // IDS_SANS_SERIF_FONT_FAMILY
313 L"arialbi.ttf", // IDS_SANS_SERIF_FONT_FAMILY
314 L"ariali.ttf", // IDS_SANS_SERIF_FONT_FAMILY
315 L"comic.ttf", // IDS_CURSIVE_FONT_FAMILY
316 L"comicbd.ttf", // IDS_CURSIVE_FONT_FAMILY
317 L"comici.ttf", // IDS_CURSIVE_FONT_FAMILY
318 L"comicz.ttf", // IDS_CURSIVE_FONT_FAMILY
319 L"impact.ttf", // IDS_FANTASY_FONT_FAMILY
320 L"georgia.ttf",
321 L"georgiab.ttf",
322 L"georgiai.ttf",
323 L"georgiaz.ttf",
324 L"trebuc.ttf",
325 L"trebucbd.ttf",
326 L"trebucbi.ttf",
327 L"trebucit.ttf",
328 L"verdana.ttf",
329 L"verdanab.ttf",
330 L"verdanai.ttf",
331 L"verdanaz.ttf",
332 L"segoeui.ttf", // IDS_PICTOGRAPH_FONT_FAMILY
333 L"segoeuib.ttf", // IDS_PICTOGRAPH_FONT_FAMILY
334 L"segoeuii.ttf", // IDS_PICTOGRAPH_FONT_FAMILY
335 L"msgothic.ttc", // IDS_STANDARD_FONT_FAMILY_JAPANESE
336 L"msmincho.ttc", // IDS_SERIF_FONT_FAMILY_JAPANESE
337 L"gulim.ttc", // IDS_FIXED_FONT_FAMILY_KOREAN
338 L"batang.ttc", // IDS_SERIF_FONT_FAMILY_KOREAN
339 L"simsun.ttc", // IDS_STANDARD_FONT_FAMILY_SIMPLIFIED_HAN
340 L"mingliu.ttc", // IDS_SERIF_FONT_FAMILY_TRADITIONAL_HAN
342 // These are from the Blink fallback list.
343 L"david.ttf", // USCRIPT_HEBREW
344 L"davidbd.ttf", // USCRIPT_HEBREW
345 L"euphemia.ttf", // USCRIPT_CANADIAN_ABORIGINAL
346 L"gautami.ttf", // USCRIPT_TELUGU
347 L"gautamib.ttf", // USCRIPT_TELUGU
348 L"latha.ttf", // USCRIPT_TAMIL
349 L"lathab.ttf", // USCRIPT_TAMIL
350 L"mangal.ttf", // USCRIPT_DEVANAGARI
351 L"mangalb.ttf", // USCRIPT_DEVANAGARI
352 L"monbaiti.ttf", // USCRIPT_MONGOLIAN
353 L"mvboli.ttf", // USCRIPT_THAANA
354 L"plantc.ttf", // USCRIPT_CHEROKEE
355 L"raavi.ttf", // USCRIPT_GURMUKHI
356 L"raavib.ttf", // USCRIPT_GURMUKHI
357 L"shruti.ttf", // USCRIPT_GUJARATI
358 L"shrutib.ttf", // USCRIPT_GUJARATI
359 L"sylfaen.ttf", // USCRIPT_GEORGIAN and USCRIPT_ARMENIAN
360 L"tahoma.ttf", // USCRIPT_ARABIC,
361 L"tahomabd.ttf", // USCRIPT_ARABIC,
362 L"tunga.ttf", // USCRIPT_KANNADA
363 L"tungab.ttf", // USCRIPT_KANNADA
364 L"vrinda.ttf", // USCRIPT_BENGALI
365 L"vrindab.ttf", // USCRIPT_BENGALI
368 bool FontCollectionLoader::LoadRestrictedFontList() {
369 reg_fonts_.clear();
370 reg_fonts_.assign(kRestrictedFontSet,
371 kRestrictedFontSet + _countof(kRestrictedFontSet));
372 return true;
375 } // namespace
377 namespace content {
379 mswr::ComPtr<IDWriteFontCollection> g_font_collection;
381 IDWriteFontCollection* GetCustomFontCollection(IDWriteFactory* factory) {
382 if (g_font_collection.Get() != NULL)
383 return g_font_collection.Get();
385 base::TimeTicks start_tick = base::TimeTicks::Now();
387 FontCollectionLoader::Initialize(factory);
389 // We try here to put arbitrary limit on max number of fonts that could
390 // be loaded, otherwise we fallback to restricted set of fonts.
391 const UINT32 kMaxFontThreshold = 1750;
392 HRESULT hr = E_FAIL;
393 if (g_font_loader->GetFontMapSize() < kMaxFontThreshold) {
394 hr = factory->CreateCustomFontCollection(
395 g_font_loader.Get(), NULL, 0, g_font_collection.GetAddressOf());
398 bool loadingRestricted = false;
399 if (FAILED(hr) || !g_font_collection.Get()) {
400 // We will try here just one more time with restricted font set.
401 g_font_loader->LoadRestrictedFontList();
402 hr = factory->CreateCustomFontCollection(
403 g_font_loader.Get(), NULL, 0, g_font_collection.GetAddressOf());
406 base::TimeDelta time_delta = base::TimeTicks::Now() - start_tick;
407 int64 delta = time_delta.ToInternalValue();
408 base::debug::Alias(&delta);
409 UINT32 size = g_font_loader->GetFontMapSize();
410 base::debug::Alias(&size);
411 base::debug::Alias(&loadingRestricted);
413 CHECK(SUCCEEDED(hr));
414 CHECK(g_font_collection.Get() != NULL);
416 UMA_HISTOGRAM_TIMES("DirectWrite.Fonts.LoadTime", time_delta);
418 base::debug::ClearCrashKey(kFontKeyName);
420 return g_font_collection.Get();
423 } // namespace content