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 306