Upstream version 11.39.250.0
[platform/framework/web/crosswalk.git] / src / content / renderer / renderer_font_platform_win.cc
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.
4
5 #include "content/renderer/renderer_font_platform_win.h"
6
7 #include <dwrite.h>
8 #include <string>
9 #include <vector>
10 #include <wrl/implements.h>
11 #include <wrl/wrappers/corewrappers.h>
12
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"
27
28 namespace {
29
30 namespace mswr = Microsoft::WRL;
31 namespace mswrw = Microsoft::WRL::Wrappers;
32
33 static const char kFontKeyName[] = "font_key_name";
34
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);
45
46   static HRESULT Initialize(IDWriteFactory* factory);
47
48   UINT32 GetFontMapSize();
49
50   std::wstring GetFontNameFromKey(UINT32 idx);
51
52   bool LoadFontListFromRegistry();
53   bool LoadRestrictedFontList();
54
55   FontCollectionLoader() {};
56   virtual ~FontCollectionLoader() {};
57
58  private:
59   mswr::ComPtr<IDWriteFontFileLoader> file_loader_;
60
61   std::vector<std::wstring> reg_fonts_;
62 };
63
64 mswr::ComPtr<FontCollectionLoader> g_font_loader;
65
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;
80
81     *fragment_start = static_cast<BYTE const*>(memory_->data()) +
82                       static_cast<size_t>(file_offset);
83     *context = NULL;
84     return S_OK;
85   }
86
87   virtual void STDMETHODCALLTYPE ReleaseFileFragment(void* context) {}
88
89   virtual HRESULT STDMETHODCALLTYPE GetFileSize(UINT64* file_size) {
90     if (!memory_.get() || !memory_->IsValid())
91       return E_FAIL;
92
93     *file_size = memory_->length();
94     return S_OK;
95   }
96
97   virtual HRESULT STDMETHODCALLTYPE GetLastWriteTime(UINT64* last_write_time) {
98     if (!memory_.get() || !memory_->IsValid())
99       return E_FAIL;
100
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;
109   }
110
111   FontFileStream::FontFileStream() : font_key_(0) {
112   };
113
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());
120
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);
125
126     if (!memory_->Initialize(path)) {
127       memory_.reset();
128       return E_FAIL;
129     }
130
131     font_key_ = font_key;
132
133     base::debug::SetCrashKeyValue(kFontKeyName,
134                                   base::WideToUTF8(font_key_name));
135     return S_OK;
136   }
137
138   virtual ~FontFileStream() {}
139
140   UINT32 font_key_;
141   scoped_ptr<base::MemoryMappedFile> memory_;
142 };
143
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;
155
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;
163     }
164     return E_FAIL;
165   }
166
167   FontFileLoader() {}
168   virtual ~FontFileLoader() {}
169 };
170
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;
178
179     if (current_file_)
180       current_file_.ReleaseAndGetAddressOf();
181
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_++;
191     }
192     return S_OK;
193   }
194
195   virtual HRESULT STDMETHODCALLTYPE
196   GetCurrentFontFile(IDWriteFontFile** font_file) {
197     if (!current_file_) {
198       *font_file = NULL;
199       return E_FAIL;
200     }
201
202     *font_file = current_file_.Detach();
203     return S_OK;
204   }
205
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) {}
211
212   virtual ~FontFileEnumerator() {}
213
214   mswr::ComPtr<IDWriteFactory> factory_;
215   mswr::ComPtr<IDWriteFontFile> current_file_;
216   mswr::ComPtr<IDWriteFontFileLoader> file_loader_;
217   UINT32 font_idx_;
218 };
219
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;
229 }
230
231 // static
232 HRESULT FontCollectionLoader::Initialize(IDWriteFactory* factory) {
233   DCHECK(g_font_loader == NULL);
234
235   g_font_loader = mswr::Make<FontCollectionLoader>();
236   if (!g_font_loader) {
237     DCHECK(FALSE);
238     return E_FAIL;
239   }
240
241   CHECK(g_font_loader->LoadFontListFromRegistry());
242
243   g_font_loader->file_loader_ = mswr::Make<FontFileLoader>().Detach();
244
245   factory->RegisterFontFileLoader(g_font_loader->file_loader_.Get());
246   factory->RegisterFontCollectionLoader(g_font_loader.Get());
247
248   return S_OK;
249 }
250
251 UINT32 FontCollectionLoader::GetFontMapSize() {
252   return reg_fonts_.size();
253 }
254
255 std::wstring FontCollectionLoader::GetFontNameFromKey(UINT32 idx) {
256   DCHECK(idx < reg_fonts_.size());
257   return reg_fonts_[idx];
258 }
259
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;
268   }
269
270   base::FilePath system_font_path;
271   PathService::Get(base::DIR_WINDOWS_FONTS, &system_font_path);
272
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());
287       }
288     }
289   }
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;
294 }
295
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"segoeui.ttf",   // IDS_PICTOGRAPH_FONT_FAMILY
321   L"segoeuib.ttf",  // IDS_PICTOGRAPH_FONT_FAMILY
322   L"segoeuii.ttf",  // IDS_PICTOGRAPH_FONT_FAMILY
323   L"msgothic.ttc",  // IDS_STANDARD_FONT_FAMILY_JAPANESE
324   L"msmincho.ttc",  // IDS_SERIF_FONT_FAMILY_JAPANESE
325   L"gulim.ttc",     // IDS_FIXED_FONT_FAMILY_KOREAN
326   L"batang.ttc",    // IDS_SERIF_FONT_FAMILY_KOREAN
327   L"simsun.ttc",    // IDS_STANDARD_FONT_FAMILY_SIMPLIFIED_HAN
328   L"mingliu.ttc",   // IDS_SERIF_FONT_FAMILY_TRADITIONAL_HAN
329
330   // These are from the Blink fallback list.
331   L"david.ttf",     // USCRIPT_HEBREW
332   L"davidbd.ttf",   // USCRIPT_HEBREW
333   L"euphemia.ttf",  // USCRIPT_CANADIAN_ABORIGINAL
334   L"gautami.ttf",   // USCRIPT_TELUGU
335   L"gautamib.ttf",  // USCRIPT_TELUGU
336   L"latha.ttf",     // USCRIPT_TAMIL
337   L"lathab.ttf",    // USCRIPT_TAMIL
338   L"mangal.ttf",    // USCRIPT_DEVANAGARI
339   L"mangalb.ttf",   // USCRIPT_DEVANAGARI
340   L"monbaiti.ttf",  // USCRIPT_MONGOLIAN
341   L"mvboli.ttf",    // USCRIPT_THAANA
342   L"plantc.ttf",    // USCRIPT_CHEROKEE
343   L"raavi.ttf",     // USCRIPT_GURMUKHI
344   L"raavib.ttf",    // USCRIPT_GURMUKHI
345   L"shruti.ttf",    // USCRIPT_GUJARATI
346   L"shrutib.ttf",   // USCRIPT_GUJARATI
347   L"sylfaen.ttf",   // USCRIPT_GEORGIAN and USCRIPT_ARMENIAN
348   L"tahoma.ttf",    // USCRIPT_ARABIC,
349   L"tahomabd.ttf",  // USCRIPT_ARABIC,
350   L"tunga.ttf",     // USCRIPT_KANNADA
351   L"tungab.ttf",    // USCRIPT_KANNADA
352   L"vrinda.ttf",    // USCRIPT_BENGALI
353   L"vrindab.ttf",   // USCRIPT_BENGALI
354 };
355
356 bool FontCollectionLoader::LoadRestrictedFontList() {
357   reg_fonts_.clear();
358   reg_fonts_.assign(kRestrictedFontSet,
359                     kRestrictedFontSet + _countof(kRestrictedFontSet));
360   return true;
361 }
362
363 }  // namespace
364
365 namespace content {
366
367 mswr::ComPtr<IDWriteFontCollection> g_font_collection;
368
369 IDWriteFontCollection* GetCustomFontCollection(IDWriteFactory* factory) {
370   if (g_font_collection.Get() != NULL)
371     return g_font_collection.Get();
372
373   base::TimeTicks start_tick = base::TimeTicks::Now();
374
375   FontCollectionLoader::Initialize(factory);
376
377   // We try here to put arbitrary limit on max number of fonts that could
378   // be loaded, otherwise we fallback to restricted set of fonts.
379   const UINT32 kMaxFontThreshold = 1750;
380   HRESULT hr = E_FAIL;
381   if (g_font_loader->GetFontMapSize() < kMaxFontThreshold) {
382     hr = factory->CreateCustomFontCollection(
383         g_font_loader.Get(), NULL, 0, g_font_collection.GetAddressOf());
384   }
385
386   bool loadingRestricted = false;
387   if (FAILED(hr) || !g_font_collection.Get()) {
388     // We will try here just one more time with restricted font set.
389     g_font_loader->LoadRestrictedFontList();
390     hr = factory->CreateCustomFontCollection(
391         g_font_loader.Get(), NULL, 0, g_font_collection.GetAddressOf());
392   }
393
394   base::TimeDelta time_delta = base::TimeTicks::Now() - start_tick;
395   int64 delta = time_delta.ToInternalValue();
396   base::debug::Alias(&delta);
397   UINT32 size = g_font_loader->GetFontMapSize();
398   base::debug::Alias(&size);
399   base::debug::Alias(&loadingRestricted);
400
401   CHECK(SUCCEEDED(hr));
402   CHECK(g_font_collection.Get() != NULL);
403
404   UMA_HISTOGRAM_TIMES("DirectWrite.Fonts.LoadTime", time_delta);
405
406   base::debug::ClearCrashKey(kFontKeyName);
407
408   return g_font_collection.Get();
409 }
410
411 }  // namespace content