Upstream version 9.37.197.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/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"
24
25 namespace {
26
27 namespace mswr = Microsoft::WRL;
28 namespace mswrw = Microsoft::WRL::Wrappers;
29
30 class FontCollectionLoader
31     : public mswr::RuntimeClass<mswr::RuntimeClassFlags<mswr::ClassicCom>,
32                                 IDWriteFontCollectionLoader> {
33  public:
34   // IDWriteFontCollectionLoader methods.
35   virtual HRESULT STDMETHODCALLTYPE
36       CreateEnumeratorFromKey(IDWriteFactory* factory,
37                               void const* key,
38                               UINT32 key_size,
39                               IDWriteFontFileEnumerator** file_enumerator);
40
41   static HRESULT Initialize(IDWriteFactory* factory);
42
43   UINT32 GetFontMapSize();
44
45   std::wstring GetFontNameFromKey(UINT32 idx);
46
47   bool LoadFontListFromRegistry();
48
49   FontCollectionLoader() {};
50   virtual ~FontCollectionLoader() {};
51
52  private:
53   mswr::ComPtr<IDWriteFontFileLoader> file_loader_;
54
55   std::vector<std::wstring> reg_fonts_;
56 };
57
58 mswr::ComPtr<FontCollectionLoader> g_font_loader;
59
60 class FontFileStream
61     : public mswr::RuntimeClass<mswr::RuntimeClassFlags<mswr::ClassicCom>,
62                                 IDWriteFontFileStream> {
63  public:
64   // IDWriteFontFileStream methods.
65   virtual HRESULT STDMETHODCALLTYPE
66   ReadFileFragment(void const** fragment_start,
67                    UINT64 file_offset,
68                    UINT64 fragment_size,
69                    void** context) {
70     if (!memory_.get() || !memory_->IsValid())
71       return E_FAIL;
72
73     *fragment_start = static_cast<BYTE const*>(memory_->data()) +
74                       static_cast<size_t>(file_offset);
75     *context = NULL;
76     return S_OK;
77   }
78
79   virtual void STDMETHODCALLTYPE ReleaseFileFragment(void* context) {}
80
81   virtual HRESULT STDMETHODCALLTYPE GetFileSize(UINT64* file_size) {
82     if (!memory_.get() || !memory_->IsValid())
83       return E_FAIL;
84
85     *file_size = memory_->length();
86     return S_OK;
87   }
88
89   virtual HRESULT STDMETHODCALLTYPE GetLastWriteTime(UINT64* last_write_time) {
90     if (!memory_.get() || !memory_->IsValid())
91       return E_FAIL;
92
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.
99     *last_write_time = 0;
100     return S_OK;
101   }
102
103   FontFileStream::FontFileStream() : font_key_(0) {
104   };
105
106   HRESULT RuntimeClassInitialize(UINT32 font_key) {
107     base::FilePath path;
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());
111
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);
116
117     if (!memory_->Initialize(path)) {
118       memory_.reset();
119       return E_FAIL;
120     }
121
122     font_key_ = font_key;
123     return S_OK;
124   }
125
126   virtual ~FontFileStream() {}
127
128   UINT32 font_key_;
129   scoped_ptr<base::MemoryMappedFile> memory_;
130 };
131
132 class FontFileLoader
133     : public mswr::RuntimeClass<mswr::RuntimeClassFlags<mswr::ClassicCom>,
134                                 IDWriteFontFileLoader> {
135  public:
136   // IDWriteFontFileLoader methods.
137   virtual HRESULT STDMETHODCALLTYPE
138   CreateStreamFromKey(void const* ref_key,
139                       UINT32 ref_key_size,
140                       IDWriteFontFileStream** stream) {
141     if (ref_key_size != sizeof(UINT32))
142       return E_FAIL;
143
144     UINT32 font_key = *static_cast<const UINT32*>(ref_key);
145     mswr::ComPtr<FontFileStream> font_stream;
146     HRESULT hr = mswr::MakeAndInitialize<FontFileStream>(&font_stream,
147                                                          font_key);
148     if (SUCCEEDED(hr)) {
149       *stream = font_stream.Detach();
150       return S_OK;
151     }
152     return E_FAIL;
153   }
154
155   FontFileLoader() {}
156   virtual ~FontFileLoader() {}
157 };
158
159 class FontFileEnumerator
160     : public mswr::RuntimeClass<mswr::RuntimeClassFlags<mswr::ClassicCom>,
161                                 IDWriteFontFileEnumerator> {
162  public:
163   // IDWriteFontFileEnumerator methods.
164   virtual HRESULT STDMETHODCALLTYPE MoveNext(BOOL* has_current_file) {
165     *has_current_file = FALSE;
166
167     if (current_file_)
168       current_file_.ReleaseAndGetAddressOf();
169
170     if (font_idx_ < g_font_loader->GetFontMapSize()) {
171       HRESULT hr =
172           factory_->CreateCustomFontFileReference(&font_idx_,
173                                                   sizeof(UINT32),
174                                                   file_loader_.Get(),
175                                                   current_file_.GetAddressOf());
176       DCHECK(SUCCEEDED(hr));
177       *has_current_file = TRUE;
178       font_idx_++;
179     }
180     return S_OK;
181   }
182
183   virtual HRESULT STDMETHODCALLTYPE
184   GetCurrentFontFile(IDWriteFontFile** font_file) {
185     if (!current_file_) {
186       *font_file = NULL;
187       return E_FAIL;
188     }
189
190     *font_file = current_file_.Detach();
191     return S_OK;
192   }
193
194   FontFileEnumerator(const void* keys,
195                      UINT32 buffer_size,
196                      IDWriteFactory* factory,
197                      IDWriteFontFileLoader* file_loader)
198       : factory_(factory), file_loader_(file_loader), font_idx_(0) {}
199
200   virtual ~FontFileEnumerator() {}
201
202   mswr::ComPtr<IDWriteFactory> factory_;
203   mswr::ComPtr<IDWriteFontFile> current_file_;
204   mswr::ComPtr<IDWriteFontFileLoader> file_loader_;
205   UINT32 font_idx_;
206 };
207
208 // IDWriteFontCollectionLoader methods.
209 HRESULT STDMETHODCALLTYPE FontCollectionLoader::CreateEnumeratorFromKey(
210     IDWriteFactory* factory,
211     void const* key,
212     UINT32 key_size,
213     IDWriteFontFileEnumerator** file_enumerator) {
214   *file_enumerator = mswr::Make<FontFileEnumerator>(
215                          key, key_size, factory, file_loader_.Get()).Detach();
216   return S_OK;
217 }
218
219 // static
220 HRESULT FontCollectionLoader::Initialize(IDWriteFactory* factory) {
221   DCHECK(g_font_loader == NULL);
222
223   g_font_loader = mswr::Make<FontCollectionLoader>();
224   if (!g_font_loader) {
225     DCHECK(FALSE);
226     return E_FAIL;
227   }
228
229   CHECK(g_font_loader->LoadFontListFromRegistry());
230
231   g_font_loader->file_loader_ = mswr::Make<FontFileLoader>().Detach();
232
233   factory->RegisterFontFileLoader(g_font_loader->file_loader_.Get());
234   factory->RegisterFontCollectionLoader(g_font_loader.Get());
235
236   return S_OK;
237 }
238
239 UINT32 FontCollectionLoader::GetFontMapSize() {
240   return reg_fonts_.size();
241 }
242
243 std::wstring FontCollectionLoader::GetFontNameFromKey(UINT32 idx) {
244   DCHECK(idx < reg_fonts_.size());
245   return reg_fonts_[idx];
246 }
247
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) !=
254       ERROR_SUCCESS) {
255     return false;
256   }
257
258   std::wstring name;
259   std::wstring value;
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());
270       }
271     }
272   }
273   return true;
274 }
275
276 }  // namespace
277
278 namespace content {
279
280 mswr::ComPtr<IDWriteFontCollection> g_font_collection;
281
282 IDWriteFontCollection* GetCustomFontCollection(IDWriteFactory* factory) {
283   if (g_font_collection.Get() != NULL)
284     return g_font_collection.Get();
285
286   base::TimeTicks start_tick = base::TimeTicks::Now();
287
288   FontCollectionLoader::Initialize(factory);
289
290   HRESULT hr = factory->CreateCustomFontCollection(
291       g_font_loader.Get(), NULL, 0, g_font_collection.GetAddressOf());
292
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);
298
299   CHECK(SUCCEEDED(hr));
300   CHECK(g_font_collection.Get() != NULL);
301
302   return g_font_collection.Get();
303 }
304
305 }  // namespace content