Home | History | Annotate | Download | only in renderer
      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