summaryrefslogtreecommitdiffstats
path: root/content/common/dwrite_font_platform_win.cc
diff options
context:
space:
mode:
Diffstat (limited to 'content/common/dwrite_font_platform_win.cc')
-rw-r--r--content/common/dwrite_font_platform_win.cc1166
1 files changed, 0 insertions, 1166 deletions
diff --git a/content/common/dwrite_font_platform_win.cc b/content/common/dwrite_font_platform_win.cc
deleted file mode 100644
index 21c2000..0000000
--- a/content/common/dwrite_font_platform_win.cc
+++ /dev/null
@@ -1,1166 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "content/common/dwrite_font_platform_win.h"
-
-#include <dwrite.h>
-#include <map>
-#include <string>
-#include <utility>
-#include <vector>
-#include <wrl/implements.h>
-#include <wrl/wrappers/corewrappers.h>
-
-#include "base/command_line.h"
-#include "base/debug/alias.h"
-#include "base/debug/crash_logging.h"
-#include "base/files/file_enumerator.h"
-#include "base/files/file_path.h"
-#include "base/files/file_util.h"
-#include "base/files/memory_mapped_file.h"
-#include "base/memory/scoped_ptr.h"
-#include "base/memory/scoped_vector.h"
-#include "base/memory/shared_memory.h"
-#include "base/metrics/histogram.h"
-#include "base/path_service.h"
-#include "base/process/process_handle.h"
-#include "base/stl_util.h"
-#include "base/strings/string_number_conversions.h"
-#include "base/strings/utf_string_conversions.h"
-#include "base/synchronization/lock.h"
-#include "base/time/time.h"
-#include "base/win/registry.h"
-#include "base/win/scoped_comptr.h"
-#include "content/public/common/content_switches.h"
-#include "content/public/common/dwrite_font_cache_win.h"
-
-namespace {
-
-// Font Cache implementation short story:
-// Due to our sandboxing restrictions, we cannot connect to Windows font cache
-// service from Renderer and need to use DirectWrite isolated font loading
-// mechanism.
-// DirectWrite needs to be initialized before any of the API could be used.
-// During initialization DirectWrite loads all font files and populates
-// internal cache, we refer this phase as enumeration and we are trying
-// to optimize this phase in our cache approach. Using cache during
-// initialization will help improve on startup latency in each renderer
-// instance.
-// During enumeration DirectWrite reads various fragments from .ttf/.ttc
-// font files. Our assumption is that these fragments are being read to
-// cache information such as font families, supported sizes etc.
-// For reading fragments DirectWrite calls ReadFragment of our FontFileStream
-// implementation with parameters start_offset and length. We cache these
-// parameters along with associated data chunk.
-// Here is small example of how segments are read
-// start_offset: 0, length: 16
-// start_offset: 0, length: 12
-// start_offset: 0, length: 117
-// For better cache management we collapse segments if they overlap or are
-// adjacent.
-
-namespace mswr = Microsoft::WRL;
-
-const char kFontKeyName[] = "font_key_name";
-
-// We use this value to determine whether to cache file fragments
-// or not. In our trials we observed that for some font files
-// direct write ends up reading almost entire file during enumeration
-// phase. If we don't use this percentile formula we will end up
-// increasing significant cache size by caching entire file contents
-// for some of the font files.
-const double kMaxPercentileOfFontFileSizeToCache = 0.7;
-
-// We have chosen current font file length arbitrarily. In our logic
-// if we don't find file we are looking for in cache we end up loading
-// that file directly from system fonts folder.
-const unsigned int kMaxFontFileNameLength = 32;
-
-const DWORD kCacheFileVersion = 101;
-const DWORD kFileSignature = 0x4D4F5243; // CROM
-const DWORD kMagicCompletionSignature = 0x454E4F44; // DONE
-
-const DWORD kUndefinedDWORDS = 32;
-
-#pragma pack(push, 8)
-// Cache file header, includes signature, completion bits and version.
-struct CacheFileHeader {
- CacheFileHeader() {
- file_signature = kFileSignature;
- magic_completion_signature = 0;
- version = kCacheFileVersion;
- ::ZeroMemory(undefined, sizeof(undefined));
- }
-
- DWORD file_signature;
- DWORD magic_completion_signature;
- DWORD version;
- BYTE undefined[kUndefinedDWORDS];
-};
-
-// Entry for a particular font file within this cache.
-struct CacheFileEntry {
- CacheFileEntry() {
- file_size = 0;
- entry_count = 0;
- ::ZeroMemory(file_name, sizeof(file_name));
- }
-
- UINT64 file_size;
- DWORD entry_count;
- wchar_t file_name[kMaxFontFileNameLength];
-};
-
-// Offsets or data chunks that are cached for particular font file.
-struct CacheFileOffsetEntry {
- CacheFileOffsetEntry() {
- start_offset = 0;
- length = 0;
- }
-
- UINT64 start_offset;
- UINT64 length;
- /* BYTE blob_[]; // Place holder for the blob that follows. */
-};
-#pragma pack(pop)
-
-bool ValidateFontCacheHeader(CacheFileHeader* header) {
- return (header->file_signature == kFileSignature &&
- header->magic_completion_signature == kMagicCompletionSignature &&
- header->version == kCacheFileVersion);
-}
-
-class FontCacheWriter;
-
-// This class implements main interface required for loading custom font
-// collection as specified by DirectWrite. We also use this class for storing
-// some state information as this is one of the centralized entity.
-class FontCollectionLoader
- : public mswr::RuntimeClass<mswr::RuntimeClassFlags<mswr::ClassicCom>,
- IDWriteFontCollectionLoader> {
- public:
- FontCollectionLoader()
- : in_collection_building_mode_(false),
- create_static_cache_(false) {};
-
- virtual ~FontCollectionLoader();
-
- HRESULT RuntimeClassInitialize() {
- return S_OK;
- }
-
- // IDWriteFontCollectionLoader methods.
- virtual HRESULT STDMETHODCALLTYPE
- CreateEnumeratorFromKey(
- IDWriteFactory* factory,
- void const* key,
- UINT32 key_size,
- IDWriteFontFileEnumerator** file_enumerator) override;
-
- // Does all the initialization for required loading fonts from registry.
- static HRESULT Initialize(IDWriteFactory* factory);
-
- // Returns font cache map size.
- UINT32 GetFontMapSize();
-
- // Returns font name string when given font index.
- base::string16 GetFontNameFromKey(UINT32 idx);
-
- // Loads internal structure with fonts from registry.
- bool LoadFontListFromRegistry();
-
- // Loads restricted web safe fonts as fallback method to registry fonts.
- bool LoadRestrictedFontList();
-
- // Puts class in collection building mode. In collection building mode
- // we use static cache if it is available as a look aside buffer.
- void EnableCollectionBuildingMode(bool enable);
-
- // Returns current state of collection building.
- bool InCollectionBuildingMode();
-
- // Loads static cache file.
- bool LoadCacheFile();
-
- // Puts class in static cache creating mode. In this mode we record all
- // direct write requests and store chunks of font data.
- void EnterStaticCacheMode(const WCHAR* file_name);
-
- // Gets out of static cache building mode.
- void LeaveStaticCacheMode();
-
- // Returns if class is currently in static cache building mode.
- bool IsBuildStaticCacheMode();
-
- // Validates cache file for consistency.
- bool ValidateCacheFile(base::File* file);
-
- private:
- // Structure to represent each chunk within font file that we load in memory.
- struct CacheTableOffsetEntry {
- UINT64 start_offset;
- UINT64 length;
- BYTE* inside_file_ptr;
- };
-
- typedef std::vector<CacheTableOffsetEntry> OffsetVector;
-
- // Structure representing each font entry with cache.
- struct CacheTableEntry {
- UINT64 file_size;
- OffsetVector offset_entries;
- };
-
- public:
- // Returns whether file we have particular font entry within cache or not.
- bool IsFileCached(UINT32 font_key);
- // Returns cache fragment corresponding to specific font key.
- void* GetCachedFragment(UINT32 font_key, UINT64 start_offset, UINT64 length);
- // Returns actual font file size at the time of caching.
- UINT64 GetCachedFileSize(UINT32 font_key);
-
- // Returns instance of font cache writer. This class manages actual font
- // file format.
- FontCacheWriter* GetFontCacheWriter();
-
- private:
- // Functions validates and loads cache into internal map.
- bool ValidateAndLoadCacheMap();
-
- mswr::ComPtr<IDWriteFontFileLoader> file_loader_;
-
- std::vector<base::string16> reg_fonts_;
- bool in_collection_building_mode_;
- bool create_static_cache_;
- scoped_ptr<base::SharedMemory> cache_;
- scoped_ptr<FontCacheWriter> cache_writer_;
-
- typedef std::map<base::string16, CacheTableEntry*> CacheMap;
- CacheMap cache_map_;
-
- DISALLOW_COPY_AND_ASSIGN(FontCollectionLoader);
-};
-
-mswr::ComPtr<FontCollectionLoader> g_font_loader;
-base::win::ScopedHandle g_shared_font_cache;
-
-// Class responsible for handling font cache file format details as well as
-// tracking various cache region requests by direct write.
-class FontCacheWriter {
- public:
- FontCacheWriter() : cookie_counter_(0) {
- }
-
- ~FontCacheWriter() {
- if (static_cache_.get()) {
- static_cache_->Close();
- }
- }
-
- public:
- // Holds data related to individual region as requested by direct write.
- struct CacheRegion {
- UINT64 start_offset;
- UINT64 length;
- const BYTE* ptr;
- /* BYTE blob_[]; // Place holder for the blob that follows. */
- };
-
- // Function to create static font cache file.
- bool Create(const wchar_t* file_name) {
- static_cache_.reset(new base::File(base::FilePath(file_name),
- base::File::FLAG_OPEN_ALWAYS | base::File::FLAG_WRITE));
- if (!static_cache_->IsValid()) {
- static_cache_.reset();
- // TODO(shrikant): Convert this CHECK to DCHECK post canary.
- // We have all fallbacks built in, so if we are not able to create
- // static cache, browser can still run with old way of loading all fonts.
- CHECK(FALSE);
- return false;
- }
- CacheFileHeader header;
-
- // At offset 0 write cache version
- static_cache_->Write(0,
- reinterpret_cast<const char*>(&header),
- sizeof(header));
-
- static_cache_->Flush();
- return true;
- }
-
- // Closes static font cache file. Also writes completion signature to mark
- // it as completely written.
- void Close() {
- if (static_cache_.get()) {
- CacheFileHeader header;
- header.magic_completion_signature = kMagicCompletionSignature;
- // At offset 0 write cache version
- int bytes_written = static_cache_->Write(0,
- reinterpret_cast<const char*>(&header),
- sizeof(header));
- DCHECK(bytes_written != -1);
- static_cache_->Close();
- static_cache_.reset(NULL);
- }
- }
-
- private:
- typedef std::vector<CacheRegion> RegionVector;
-
- // Structure to track various regions requested by direct write for particular
- // font file.
- struct FontEntryInternal {
- FontEntryInternal(const wchar_t* name, UINT64 size)
- : file_name(name),
- file_size(size) {
- }
-
- base::string16 file_name;
- UINT64 file_size;
- RegionVector regions;
- };
-
- public:
- // Starts up new font entry to be tracked, returns cookie to identify this
- // particular entry.
- UINT NewFontEntry(const wchar_t* file_name, UINT64 file_size) {
- base::AutoLock lock(lock_);
- UINT old_counter = cookie_counter_;
- FontEntryInternal* font_entry = new FontEntryInternal(file_name, file_size);
- cookie_map_[cookie_counter_].reset(font_entry);
- cookie_counter_++;
- return old_counter;
- }
-
- // AddRegion function lets caller add various regions to be cached for
- // particular font file. Once enumerating that particular font file is done
- // (based on uniquely identifying cookie) changes could be committed using
- // CommitFontEntry
- bool AddRegion(UINT64 cookie, UINT64 start, UINT64 length, const BYTE* ptr) {
- base::AutoLock lock(lock_);
- if (cookie_map_.find(cookie) == cookie_map_.end())
- return false;
- RegionVector& regions = cookie_map_[cookie].get()->regions;
- CacheRegion region;
- region.start_offset = start;
- region.length = length;
- region.ptr = ptr;
- regions.push_back(region);
- return true;
- }
-
- // Function which commits after merging all collected regions into cache file.
- bool CommitFontEntry(UINT cookie) {
- base::AutoLock lock(lock_);
- if (cookie_map_.find(cookie) == cookie_map_.end())
- return false;
-
- FontEntryInternal* font_entry = cookie_map_[cookie].get();
- RegionVector& regions = font_entry->regions;
- std::sort(regions.begin(), regions.end(), SortCacheRegions);
-
- // At this point, we have collected all regions to be cached. These regions
- // are tuples of start, length, data for particular data segment.
- // These tuples can overlap.
- // e.g. (0, 12, data), (0, 117, data), (21, 314, data), (335, 15, data)
- // In this case as you can see first three segments overlap and
- // 4th is adjacent. If we cache them individually then we will end up
- // caching duplicate data, so we merge these segments together to find
- // superset for the cache. In above example our algorithm should
- // produce (cache) single segment starting at offset 0 with length 350.
- RegionVector merged_regions;
- RegionVector::iterator iter;
- int idx = 0;
- for (iter = regions.begin(); iter != regions.end(); iter++) {
- if (iter == regions.begin()) {
- merged_regions.push_back(*iter);
- continue;
- }
- CacheRegion& base_region = merged_regions[idx];
- if (IsOverlap(&base_region, &(*iter))) {
- UINT64 end1 = base_region.start_offset + base_region.length;
- UINT64 end2 = iter->start_offset + iter->length;
- if (base_region.start_offset > iter->start_offset) {
- base_region.start_offset = iter->start_offset;
- base_region.ptr = iter->ptr;
- }
- base_region.length = std::max(end1, end2) - base_region.start_offset;
- } else {
- merged_regions.push_back(*iter);
- idx++;
- }
- }
-
- UINT64 total_merged_cache_in_bytes = 0;
- for (iter = merged_regions.begin(); iter != merged_regions.end(); iter++) {
- total_merged_cache_in_bytes += iter->length;
- }
-
- // We want to adjust following parameter based on experiments. But general
- // logic here is that if we are going to end up caching most of the contents
- // for a file (e.g. simsunb.ttf > 90%) then we should avoid caching that
- // file.
- double percentile = static_cast<double>(total_merged_cache_in_bytes) /
- font_entry->file_size;
- if (percentile > kMaxPercentileOfFontFileSizeToCache) {
- return false;
- }
-
- CacheFileEntry entry;
- wcsncpy_s(entry.file_name, kMaxFontFileNameLength,
- font_entry->file_name.c_str(), _TRUNCATE);
- entry.file_size = font_entry->file_size;
- entry.entry_count = merged_regions.size();
- static_cache_->WriteAtCurrentPos(
- reinterpret_cast<const char*>(&entry),
- sizeof(entry));
- for (iter = merged_regions.begin(); iter != merged_regions.end(); iter++) {
- CacheFileOffsetEntry offset_entry;
- offset_entry.start_offset = iter->start_offset;
- offset_entry.length = iter->length;
- static_cache_->WriteAtCurrentPos(
- reinterpret_cast<const char*>(&offset_entry),
- sizeof(offset_entry));
- static_cache_->WriteAtCurrentPos(
- reinterpret_cast<const char*>(iter->ptr),
- iter->length);
- }
- return true;
- }
-
- private:
- scoped_ptr<base::File> static_cache_;
- std::map<UINT, scoped_ptr<FontEntryInternal>> cookie_map_;
- UINT cookie_counter_;
-
- // Lock is required to protect internal data structures and access to file,
- // According to MSDN documentation on ReadFileFragment and based on our
- // experiments so far, there is possibility of ReadFileFragment getting called
- // from multiple threads.
- base::Lock lock_;
-
- // Function checks if two regions overlap or are adjacent.
- bool IsOverlap(CacheRegion* region1, CacheRegion* region2) {
- return
- !((region1->start_offset + region1->length) < region2->start_offset ||
- region1->start_offset > (region2->start_offset + region2->length));
- }
-
- // Function to sort cached regions.
- static bool SortCacheRegions(const CacheRegion& region1,
- const CacheRegion& region2) {
- return
- region1.start_offset == region2.start_offset ?
- region1.length < region2.length :
- region1.start_offset < region2.start_offset;
- }
-
- DISALLOW_COPY_AND_ASSIGN(FontCacheWriter);
-};
-
-// Class implements IDWriteFontFileStream interface as required by direct write.
-class FontFileStream
- : public mswr::RuntimeClass<mswr::RuntimeClassFlags<mswr::ClassicCom>,
- IDWriteFontFileStream> {
- public:
- // IDWriteFontFileStream methods.
- virtual HRESULT STDMETHODCALLTYPE ReadFileFragment(
- void const** fragment_start,
- UINT64 file_offset,
- UINT64 fragment_size,
- void** context) override {
- if (cached_data_) {
- *fragment_start = g_font_loader->GetCachedFragment(font_key_,
- file_offset,
- fragment_size);
- if (*fragment_start == NULL) {
- DCHECK(false);
- }
- *context = NULL;
- return *fragment_start != NULL ? S_OK : E_FAIL;
- }
- if (!memory_.get() || !memory_->IsValid() ||
- file_offset >= memory_->length() ||
- (file_offset + fragment_size) > memory_->length())
- return E_FAIL;
-
- *fragment_start = static_cast<BYTE const*>(memory_->data()) +
- static_cast<size_t>(file_offset);
- *context = NULL;
- if (g_font_loader->IsBuildStaticCacheMode()) {
- FontCacheWriter* cache_writer = g_font_loader->GetFontCacheWriter();
- cache_writer->AddRegion(writer_cookie_,
- file_offset,
- fragment_size,
- static_cast<const BYTE*>(*fragment_start));
- }
- return S_OK;
- }
-
- virtual void STDMETHODCALLTYPE ReleaseFileFragment(void* context) override {}
-
- virtual HRESULT STDMETHODCALLTYPE GetFileSize(UINT64* file_size) override {
- if (cached_data_) {
- *file_size = g_font_loader->GetCachedFileSize(font_key_);
- return S_OK;
- }
-
- if (!memory_.get() || !memory_->IsValid())
- return E_FAIL;
-
- *file_size = memory_->length();
- return S_OK;
- }
-
- virtual HRESULT STDMETHODCALLTYPE GetLastWriteTime(
- UINT64* last_write_time) override {
- if (cached_data_) {
- *last_write_time = 0;
- return S_OK;
- }
-
- if (!memory_.get() || !memory_->IsValid())
- return E_FAIL;
-
- // According to MSDN article http://goo.gl/rrSYzi the "last modified time"
- // is used by DirectWrite font selection algorithms to determine whether
- // one font resource is more up to date than another one.
- // So by returning 0 we are assuming that it will treat all fonts to be
- // equally up to date.
- // TODO(shrikant): We should further investigate this.
- *last_write_time = 0;
- return S_OK;
- }
-
- FontFileStream::FontFileStream() : font_key_(0), cached_data_(false) {
- };
-
- HRESULT RuntimeClassInitialize(UINT32 font_key) {
- if (g_font_loader->InCollectionBuildingMode() &&
- g_font_loader->IsFileCached(font_key)) {
- cached_data_ = true;
- font_key_ = font_key;
- return S_OK;
- }
-
- base::FilePath path;
- PathService::Get(base::DIR_WINDOWS_FONTS, &path);
- base::string16 font_key_name(g_font_loader->GetFontNameFromKey(font_key));
- path = path.Append(font_key_name.c_str());
- memory_.reset(new base::MemoryMappedFile());
-
- // Put some debug information on stack.
- WCHAR font_name[MAX_PATH];
- path.value().copy(font_name, arraysize(font_name));
- base::debug::Alias(font_name);
-
- if (!memory_->Initialize(path)) {
- memory_.reset();
- return E_FAIL;
- }
-
- font_key_ = font_key;
-
- base::debug::SetCrashKeyValue(kFontKeyName,
- base::WideToUTF8(font_key_name));
-
- if (g_font_loader->IsBuildStaticCacheMode()) {
- FontCacheWriter* cache_writer = g_font_loader->GetFontCacheWriter();
- writer_cookie_ = cache_writer->NewFontEntry(font_key_name.c_str(),
- memory_->length());
- }
- return S_OK;
- }
-
- virtual ~FontFileStream() {
- if (g_font_loader->IsBuildStaticCacheMode()) {
- FontCacheWriter* cache_writer = g_font_loader->GetFontCacheWriter();
- cache_writer->CommitFontEntry(writer_cookie_);
- }
- }
-
- private:
- UINT32 font_key_;
- scoped_ptr<base::MemoryMappedFile> memory_;
- bool cached_data_;
- UINT writer_cookie_;
-
- DISALLOW_COPY_AND_ASSIGN(FontFileStream);
-};
-
-// Implements IDWriteFontFileLoader as required by FontFileLoader.
-class FontFileLoader
- : public mswr::RuntimeClass<mswr::RuntimeClassFlags<mswr::ClassicCom>,
- IDWriteFontFileLoader> {
- public:
- // IDWriteFontFileLoader methods.
- virtual HRESULT STDMETHODCALLTYPE
- CreateStreamFromKey(void const* ref_key,
- UINT32 ref_key_size,
- IDWriteFontFileStream** stream) override {
- if (ref_key_size != sizeof(UINT32))
- return E_FAIL;
-
- UINT32 font_key = *static_cast<const UINT32*>(ref_key);
- mswr::ComPtr<FontFileStream> font_stream;
- HRESULT hr = mswr::MakeAndInitialize<FontFileStream>(&font_stream,
- font_key);
- if (SUCCEEDED(hr)) {
- *stream = font_stream.Detach();
- return S_OK;
- }
- return E_FAIL;
- }
-
- FontFileLoader() {}
- virtual ~FontFileLoader() {}
-
- private:
-
- DISALLOW_COPY_AND_ASSIGN(FontFileLoader);
-};
-
-// Implements IDWriteFontFileEnumerator as required by direct write.
-class FontFileEnumerator
- : public mswr::RuntimeClass<mswr::RuntimeClassFlags<mswr::ClassicCom>,
- IDWriteFontFileEnumerator> {
- public:
- // IDWriteFontFileEnumerator methods.
- virtual HRESULT STDMETHODCALLTYPE MoveNext(BOOL* has_current_file) override {
- *has_current_file = FALSE;
-
- if (current_file_)
- current_file_.ReleaseAndGetAddressOf();
-
- if (font_idx_ < g_font_loader->GetFontMapSize()) {
- HRESULT hr =
- factory_->CreateCustomFontFileReference(&font_idx_,
- sizeof(UINT32),
- file_loader_.Get(),
- current_file_.GetAddressOf());
- DCHECK(SUCCEEDED(hr));
- *has_current_file = TRUE;
- font_idx_++;
- }
- return S_OK;
- }
-
- virtual HRESULT STDMETHODCALLTYPE
- GetCurrentFontFile(IDWriteFontFile** font_file) override {
- if (!current_file_) {
- *font_file = NULL;
- return E_FAIL;
- }
-
- *font_file = current_file_.Detach();
- return S_OK;
- }
-
- FontFileEnumerator(const void* keys,
- UINT32 buffer_size,
- IDWriteFactory* factory,
- IDWriteFontFileLoader* file_loader)
- : factory_(factory), file_loader_(file_loader), font_idx_(0) {}
-
- virtual ~FontFileEnumerator() {}
-
- mswr::ComPtr<IDWriteFactory> factory_;
- mswr::ComPtr<IDWriteFontFile> current_file_;
- mswr::ComPtr<IDWriteFontFileLoader> file_loader_;
- UINT32 font_idx_;
-
- private:
-
- DISALLOW_COPY_AND_ASSIGN(FontFileEnumerator);
-};
-
-// IDWriteFontCollectionLoader methods.
-HRESULT STDMETHODCALLTYPE FontCollectionLoader::CreateEnumeratorFromKey(
- IDWriteFactory* factory,
- void const* key,
- UINT32 key_size,
- IDWriteFontFileEnumerator** file_enumerator) {
- *file_enumerator = mswr::Make<FontFileEnumerator>(
- key, key_size, factory, file_loader_.Get()).Detach();
- return S_OK;
-}
-
-// static
-HRESULT FontCollectionLoader::Initialize(IDWriteFactory* factory) {
- DCHECK(g_font_loader == NULL);
-
- HRESULT result;
- result = mswr::MakeAndInitialize<FontCollectionLoader>(&g_font_loader);
- if (FAILED(result) || !g_font_loader) {
- DCHECK(false);
- return E_FAIL;
- }
-
- CHECK(g_font_loader->LoadFontListFromRegistry());
-
- g_font_loader->file_loader_ = mswr::Make<FontFileLoader>().Detach();
-
- factory->RegisterFontFileLoader(g_font_loader->file_loader_.Get());
- factory->RegisterFontCollectionLoader(g_font_loader.Get());
-
- return S_OK;
-}
-
-FontCollectionLoader::~FontCollectionLoader() {
- STLDeleteContainerPairSecondPointers(cache_map_.begin(), cache_map_.end());
-}
-
-UINT32 FontCollectionLoader::GetFontMapSize() {
- return reg_fonts_.size();
-}
-
-base::string16 FontCollectionLoader::GetFontNameFromKey(UINT32 idx) {
- DCHECK(idx < reg_fonts_.size());
- return reg_fonts_[idx];
-}
-
-bool FontCollectionLoader::LoadFontListFromRegistry() {
- const wchar_t kFontsRegistry[] =
- L"Software\\Microsoft\\Windows NT\\CurrentVersion\\Fonts";
- CHECK(reg_fonts_.empty());
- base::win::RegKey regkey;
- if (regkey.Open(HKEY_LOCAL_MACHINE, kFontsRegistry, KEY_READ) !=
- ERROR_SUCCESS) {
- return false;
- }
-
- base::FilePath system_font_path;
- PathService::Get(base::DIR_WINDOWS_FONTS, &system_font_path);
-
- base::string16 name;
- base::string16 value;
- for (DWORD idx = 0; idx < regkey.GetValueCount(); idx++) {
- if (regkey.GetValueNameAt(idx, &name) == ERROR_SUCCESS &&
- regkey.ReadValue(name.c_str(), &value) == ERROR_SUCCESS) {
- base::FilePath path(value.c_str());
- // We need to check if file name is the only component that exists,
- // we will ignore all other registry entries.
- std::vector<base::FilePath::StringType> components;
- path.GetComponents(&components);
- if ((components.size() == 1 &&
- value.size() < kMaxFontFileNameLength - 1) ||
- base::FilePath::CompareEqualIgnoreCase(system_font_path.value(),
- path.DirName().value())) {
- reg_fonts_.push_back(value.c_str());
- }
- }
- }
- UMA_HISTOGRAM_COUNTS("DirectWrite.Fonts.Loaded", reg_fonts_.size());
- UMA_HISTOGRAM_COUNTS("DirectWrite.Fonts.Ignored",
- regkey.GetValueCount() - reg_fonts_.size());
- return true;
-}
-
-// This list is mainly based on prefs/prefs_tab_helper.cc kFontDefaults.
-const wchar_t* kRestrictedFontSet[] = {
- // These are the "Web Safe" fonts.
- L"times.ttf", // IDS_STANDARD_FONT_FAMILY
- L"timesbd.ttf", // IDS_STANDARD_FONT_FAMILY
- L"timesbi.ttf", // IDS_STANDARD_FONT_FAMILY
- L"timesi.ttf", // IDS_STANDARD_FONT_FAMILY
- L"cour.ttf", // IDS_FIXED_FONT_FAMILY
- L"courbd.ttf", // IDS_FIXED_FONT_FAMILY
- L"courbi.ttf", // IDS_FIXED_FONT_FAMILY
- L"couri.ttf", // IDS_FIXED_FONT_FAMILY
- L"consola.ttf", // IDS_FIXED_FONT_FAMILY_ALT_WIN
- L"consolab.ttf", // IDS_FIXED_FONT_FAMILY_ALT_WIN
- L"consolai.ttf", // IDS_FIXED_FONT_FAMILY_ALT_WIN
- L"consolaz.ttf", // IDS_FIXED_FONT_FAMILY_ALT_WIN
- L"arial.ttf", // IDS_SANS_SERIF_FONT_FAMILY
- L"arialbd.ttf", // IDS_SANS_SERIF_FONT_FAMILY
- L"arialbi.ttf", // IDS_SANS_SERIF_FONT_FAMILY
- L"ariali.ttf", // IDS_SANS_SERIF_FONT_FAMILY
- L"comic.ttf", // IDS_CURSIVE_FONT_FAMILY
- L"comicbd.ttf", // IDS_CURSIVE_FONT_FAMILY
- L"comici.ttf", // IDS_CURSIVE_FONT_FAMILY
- L"comicz.ttf", // IDS_CURSIVE_FONT_FAMILY
- L"impact.ttf", // IDS_FANTASY_FONT_FAMILY
- L"georgia.ttf",
- L"georgiab.ttf",
- L"georgiai.ttf",
- L"georgiaz.ttf",
- L"trebuc.ttf",
- L"trebucbd.ttf",
- L"trebucbi.ttf",
- L"trebucit.ttf",
- L"verdana.ttf",
- L"verdanab.ttf",
- L"verdanai.ttf",
- L"verdanaz.ttf",
- L"segoeui.ttf", // IDS_PICTOGRAPH_FONT_FAMILY
- L"segoeuib.ttf", // IDS_PICTOGRAPH_FONT_FAMILY
- L"segoeuii.ttf", // IDS_PICTOGRAPH_FONT_FAMILY
- L"msgothic.ttc", // IDS_STANDARD_FONT_FAMILY_JAPANESE
- L"msmincho.ttc", // IDS_SERIF_FONT_FAMILY_JAPANESE
- L"gulim.ttc", // IDS_FIXED_FONT_FAMILY_KOREAN
- L"batang.ttc", // IDS_SERIF_FONT_FAMILY_KOREAN
- L"simsun.ttc", // IDS_STANDARD_FONT_FAMILY_SIMPLIFIED_HAN
- L"mingliu.ttc", // IDS_SERIF_FONT_FAMILY_TRADITIONAL_HAN
-
- // These are from the Blink fallback list.
- L"david.ttf", // USCRIPT_HEBREW
- L"davidbd.ttf", // USCRIPT_HEBREW
- L"euphemia.ttf", // USCRIPT_CANADIAN_ABORIGINAL
- L"gautami.ttf", // USCRIPT_TELUGU
- L"gautamib.ttf", // USCRIPT_TELUGU
- L"latha.ttf", // USCRIPT_TAMIL
- L"lathab.ttf", // USCRIPT_TAMIL
- L"mangal.ttf", // USCRIPT_DEVANAGARI
- L"mangalb.ttf", // USCRIPT_DEVANAGARI
- L"monbaiti.ttf", // USCRIPT_MONGOLIAN
- L"mvboli.ttf", // USCRIPT_THAANA
- L"plantc.ttf", // USCRIPT_CHEROKEE
- L"raavi.ttf", // USCRIPT_GURMUKHI
- L"raavib.ttf", // USCRIPT_GURMUKHI
- L"shruti.ttf", // USCRIPT_GUJARATI
- L"shrutib.ttf", // USCRIPT_GUJARATI
- L"sylfaen.ttf", // USCRIPT_GEORGIAN and USCRIPT_ARMENIAN
- L"tahoma.ttf", // USCRIPT_ARABIC,
- L"tahomabd.ttf", // USCRIPT_ARABIC,
- L"tunga.ttf", // USCRIPT_KANNADA
- L"tungab.ttf", // USCRIPT_KANNADA
- L"vrinda.ttf", // USCRIPT_BENGALI
- L"vrindab.ttf", // USCRIPT_BENGALI
-};
-
-bool FontCollectionLoader::LoadRestrictedFontList() {
- reg_fonts_.clear();
- reg_fonts_.assign(kRestrictedFontSet,
- kRestrictedFontSet + _countof(kRestrictedFontSet));
- return true;
-}
-
-void FontCollectionLoader::EnableCollectionBuildingMode(bool enable) {
- in_collection_building_mode_ = enable;
-}
-
-bool FontCollectionLoader::InCollectionBuildingMode() {
- return in_collection_building_mode_;
-}
-
-bool FontCollectionLoader::IsFileCached(UINT32 font_key) {
- if (!cache_.get() || cache_->memory() == NULL) {
- return false;
- }
- CacheMap::iterator iter = cache_map_.find(
- GetFontNameFromKey(font_key).c_str());
- return iter != cache_map_.end();;
-}
-
-bool FontCollectionLoader::LoadCacheFile() {
- if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kFontCacheSharedMemSuffix)) {
- return false;
- }
- base::SharedMemory* shared_mem = new base::SharedMemory();
- std::string name(content::kFontCacheSharedSectionName);
- name.append(base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
- switches::kFontCacheSharedMemSuffix));
- if (!shared_mem->Open(name.c_str(), true))
- return false;
-
- // Map while file
- shared_mem->Map(0);
-
- cache_.reset(shared_mem);
-
- if (!ValidateAndLoadCacheMap()) {
- cache_.reset();
- return false;
- }
-
- return true;
-}
-
-void FontCollectionLoader::EnterStaticCacheMode(const WCHAR* file_name) {
- cache_writer_.reset(new FontCacheWriter());
- cache_writer_->Create(file_name);
- create_static_cache_ = true;
-}
-
-void FontCollectionLoader::LeaveStaticCacheMode() {
- cache_writer_->Close();
- cache_writer_.reset(NULL);
- create_static_cache_ = false;
-}
-
-bool FontCollectionLoader::IsBuildStaticCacheMode() {
- return create_static_cache_;
-}
-
-bool FontCollectionLoader::ValidateAndLoadCacheMap() {
- BYTE* mem_file_start = static_cast<BYTE*>(cache_->memory());
- BYTE* mem_file_end = mem_file_start + cache_->mapped_size();
-
- BYTE* current_ptr = mem_file_start;
- CacheFileHeader* file_header =
- reinterpret_cast<CacheFileHeader*>(current_ptr);
- if (!ValidateFontCacheHeader(file_header))
- return false;
-
- current_ptr = current_ptr + sizeof(CacheFileHeader);
- if (current_ptr >= mem_file_end)
- return false;
-
- while ((current_ptr + sizeof(CacheFileEntry)) < mem_file_end) {
- CacheFileEntry* entry = reinterpret_cast<CacheFileEntry*>(current_ptr);
- current_ptr += sizeof(CacheFileEntry);
- WCHAR file_name[kMaxFontFileNameLength];
- wcsncpy_s(file_name,
- kMaxFontFileNameLength,
- entry->file_name,
- _TRUNCATE);
- CacheTableEntry* table_entry = NULL;
- CacheMap::iterator iter = cache_map_.find(file_name);
- if (iter == cache_map_.end()) {
- table_entry = new CacheTableEntry();
- cache_map_[file_name] = table_entry;
- } else {
- table_entry = iter->second;
- }
- table_entry->file_size = entry->file_size;
- for (DWORD idx = 0; current_ptr < mem_file_end && idx < entry->entry_count;
- idx++) {
- CacheFileOffsetEntry* offset_entry =
- reinterpret_cast<CacheFileOffsetEntry*>(current_ptr);
- CacheTableOffsetEntry table_offset_entry;
- table_offset_entry.start_offset = offset_entry->start_offset;
- table_offset_entry.length = offset_entry->length;
- table_offset_entry.inside_file_ptr =
- current_ptr + sizeof(CacheFileOffsetEntry);
- table_entry->offset_entries.push_back(table_offset_entry);
- current_ptr += sizeof(CacheFileOffsetEntry);
- current_ptr += offset_entry->length;
- }
- }
-
- return true;
-}
-
-void* FontCollectionLoader::GetCachedFragment(UINT32 font_key,
- UINT64 start_offset,
- UINT64 length) {
- UINT64 just_past_end = start_offset + length;
- CacheMap::iterator iter = cache_map_.find(
- GetFontNameFromKey(font_key).c_str());
- if (iter != cache_map_.end()) {
- CacheTableEntry* entry = iter->second;
- OffsetVector::iterator offset_iter = entry->offset_entries.begin();
- while (offset_iter != entry->offset_entries.end()) {
- UINT64 available_just_past_end =
- offset_iter->start_offset + offset_iter->length;
- if (offset_iter->start_offset <= start_offset &&
- just_past_end <= available_just_past_end) {
- return offset_iter->inside_file_ptr +
- (start_offset - offset_iter->start_offset);
- }
- offset_iter++;
- }
- }
- return NULL;
-}
-
-UINT64 FontCollectionLoader::GetCachedFileSize(UINT32 font_key) {
- CacheMap::iterator iter = cache_map_.find(
- GetFontNameFromKey(font_key).c_str());
- if (iter != cache_map_.end()) {
- return iter->second->file_size;
- }
- return 0;
-}
-
-FontCacheWriter* FontCollectionLoader::GetFontCacheWriter() {
- return cache_writer_.get();
-}
-
-} // namespace
-
-namespace content {
-
-const char kFontCacheSharedSectionName[] = "ChromeDWriteFontCache";
-
-mswr::ComPtr<IDWriteFontCollection> g_font_collection;
-
-IDWriteFontCollection* GetCustomFontCollection(IDWriteFactory* factory) {
- if (g_font_collection.Get() != NULL)
- return g_font_collection.Get();
-
- base::TimeTicks start_tick = base::TimeTicks::Now();
-
- FontCollectionLoader::Initialize(factory);
-
- g_font_loader->LoadCacheFile();
-
- // We try here to put arbitrary limit on max number of fonts that could
- // be loaded, otherwise we fallback to restricted set of fonts.
- const UINT32 kMaxFontThreshold = 1750;
- HRESULT hr = E_FAIL;
- if (g_font_loader->GetFontMapSize() < kMaxFontThreshold) {
- g_font_loader->EnableCollectionBuildingMode(true);
- hr = factory->CreateCustomFontCollection(
- g_font_loader.Get(), NULL, 0, g_font_collection.GetAddressOf());
- g_font_loader->EnableCollectionBuildingMode(false);
- }
-
- bool loading_restricted = false;
- if (FAILED(hr) || !g_font_collection.Get()) {
- loading_restricted = true;
- // We will try here just one more time with restricted font set.
- g_font_loader->LoadRestrictedFontList();
- hr = factory->CreateCustomFontCollection(
- g_font_loader.Get(), NULL, 0, g_font_collection.GetAddressOf());
- }
-
- base::TimeDelta time_delta = base::TimeTicks::Now() - start_tick;
- int64 delta = time_delta.ToInternalValue();
- base::debug::Alias(&delta);
- UINT32 size = g_font_loader->GetFontMapSize();
- base::debug::Alias(&size);
- base::debug::Alias(&loading_restricted);
-
- CHECK(SUCCEEDED(hr));
- CHECK(g_font_collection.Get() != NULL);
-
- UMA_HISTOGRAM_TIMES("DirectWrite.Fonts.LoadTime", time_delta);
-
- base::debug::ClearCrashKey(kFontKeyName);
-
- return g_font_collection.Get();
-}
-
-bool BuildFontCacheInternal(const WCHAR* file_name) {
- typedef decltype(DWriteCreateFactory)* DWriteCreateFactoryProc;
- HMODULE dwrite_dll = LoadLibraryW(L"dwrite.dll");
- if (!dwrite_dll) {
- DWORD load_library_get_last_error = GetLastError();
- base::debug::Alias(&dwrite_dll);
- base::debug::Alias(&load_library_get_last_error);
- CHECK(false);
- }
-
- DWriteCreateFactoryProc dwrite_create_factory_proc =
- reinterpret_cast<DWriteCreateFactoryProc>(
- GetProcAddress(dwrite_dll, "DWriteCreateFactory"));
-
- if (!dwrite_create_factory_proc) {
- DWORD get_proc_address_get_last_error = GetLastError();
- base::debug::Alias(&dwrite_create_factory_proc);
- base::debug::Alias(&get_proc_address_get_last_error);
- CHECK(false);
- }
-
- mswr::ComPtr<IDWriteFactory> factory;
-
- CHECK(SUCCEEDED(
- dwrite_create_factory_proc(
- DWRITE_FACTORY_TYPE_ISOLATED,
- __uuidof(IDWriteFactory),
- reinterpret_cast<IUnknown**>(factory.GetAddressOf()))));
-
- base::TimeTicks start_tick = base::TimeTicks::Now();
-
- FontCollectionLoader::Initialize(factory.Get());
-
- g_font_loader->EnterStaticCacheMode(file_name);
-
- mswr::ComPtr<IDWriteFontCollection> font_collection;
-
- // We try here to put arbitrary limit on max number of fonts that could
- // be loaded, otherwise we fallback to restricted set of fonts.
- const UINT32 kMaxFontThreshold = 1750;
- HRESULT hr = E_FAIL;
- if (g_font_loader->GetFontMapSize() < kMaxFontThreshold) {
- g_font_loader->EnableCollectionBuildingMode(true);
- hr = factory->CreateCustomFontCollection(
- g_font_loader.Get(), NULL, 0, font_collection.GetAddressOf());
- g_font_loader->EnableCollectionBuildingMode(false);
- }
-
- bool loading_restricted = false;
- if (FAILED(hr) || !font_collection.Get()) {
- loading_restricted = true;
- // We will try here just one more time with restricted font set.
- g_font_loader->LoadRestrictedFontList();
- hr = factory->CreateCustomFontCollection(
- g_font_loader.Get(), NULL, 0, font_collection.GetAddressOf());
- }
-
- g_font_loader->LeaveStaticCacheMode();
-
- base::TimeDelta time_delta = base::TimeTicks::Now() - start_tick;
- int64 delta = time_delta.ToInternalValue();
- base::debug::Alias(&delta);
- UINT32 size = g_font_loader->GetFontMapSize();
- base::debug::Alias(&size);
- base::debug::Alias(&loading_restricted);
-
- CHECK(SUCCEEDED(hr));
- CHECK(font_collection.Get() != NULL);
-
- UMA_HISTOGRAM_TIMES("DirectWrite.Fonts.LoadTime", time_delta);
-
- base::debug::ClearCrashKey(kFontKeyName);
-
- return true;
-}
-
-bool ValidateFontCacheFile(base::File* file) {
- DCHECK(file != NULL);
- CacheFileHeader file_header;
- if (file->Read(0, reinterpret_cast<char*>(&file_header), sizeof(file_header))
- == -1) {
- return false;
- }
- return ValidateFontCacheHeader(&file_header);
-}
-
-bool LoadFontCache(const base::FilePath& path) {
- scoped_ptr<base::File> file(new base::File(path,
- base::File::FLAG_OPEN | base::File::FLAG_READ));
- if (!file->IsValid())
- return false;
-
- if (!ValidateFontCacheFile(file.get()))
- return false;
-
- std::string name(content::kFontCacheSharedSectionName);
- name.append(base::UintToString(base::GetCurrentProcId()));
- HANDLE mapping = ::CreateFileMapping(
- file->GetPlatformFile(),
- NULL,
- PAGE_READONLY,
- 0,
- 0,
- base::ASCIIToWide(name).c_str());
- if (mapping == INVALID_HANDLE_VALUE)
- return false;
-
- if (::GetLastError() == ERROR_ALREADY_EXISTS) {
- CloseHandle(mapping);
- // We crash here, as no one should have created this mapping except Chrome.
- CHECK(false);
- return false;
- }
-
- DCHECK(!g_shared_font_cache.IsValid());
- g_shared_font_cache.Set(mapping);
-
- return true;
-}
-
-// Assumption for this function is that it will get called through a posted task
-// on FILE thread.
-bool BuildAndLoadFontCache(const base::FilePath& file) {
- if (BuildFontCacheInternal(file.value().c_str()))
- return LoadFontCache(file);
- return false;
-}
-
-} // namespace content