Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(124)

Side by Side Diff: content/common/dwrite_font_platform_win.cc

Issue 1847173002: Revert "Revert of Remove font cache code (patchset #3 id:40001 of https://codereview.chromium.org/1… (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Add test expectations to rebaseline tests on Win10 Created 4 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « content/child/font_warmup_win.cc ('k') | content/common/dwrite_font_platform_win_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
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/public/common/dwrite_font_platform_win.h"
6
7 #include <windows.h>
8 #include <stddef.h>
9 #include <stdint.h>
10
11 #include <dwrite.h>
12 #include <wrl/implements.h>
13 #include <wrl/wrappers/corewrappers.h>
14
15 #include <limits>
16 #include <map>
17 #include <string>
18 #include <utility>
19 #include <vector>
20
21 #include "base/command_line.h"
22 #include "base/debug/alias.h"
23 #include "base/debug/crash_logging.h"
24 #include "base/files/file_enumerator.h"
25 #include "base/files/file_path.h"
26 #include "base/files/file_util.h"
27 #include "base/files/memory_mapped_file.h"
28 #include "base/macros.h"
29 #include "base/memory/scoped_ptr.h"
30 #include "base/memory/shared_memory.h"
31 #include "base/metrics/field_trial.h"
32 #include "base/metrics/histogram.h"
33 #include "base/path_service.h"
34 #include "base/process/process_handle.h"
35 #include "base/stl_util.h"
36 #include "base/strings/string_number_conversions.h"
37 #include "base/strings/string_util.h"
38 #include "base/strings/utf_string_conversions.h"
39 #include "base/synchronization/lock.h"
40 #include "base/time/time.h"
41 #include "base/trace_event/trace_event.h"
42 #include "base/win/registry.h"
43 #include "base/win/scoped_comptr.h"
44 #include "content/public/common/content_switches.h"
45
46 namespace {
47
48 // Font Cache implementation short story:
49 // Due to our sandboxing restrictions, we cannot connect to Windows font cache
50 // service from Renderer and need to use DirectWrite isolated font loading
51 // mechanism.
52 // DirectWrite needs to be initialized before any of the API could be used.
53 // During initialization DirectWrite loads all font files and populates
54 // internal cache, we refer this phase as enumeration and we are trying
55 // to optimize this phase in our cache approach. Using cache during
56 // initialization will help improve on startup latency in each renderer
57 // instance.
58 // During enumeration DirectWrite reads various fragments from .ttf/.ttc
59 // font files. Our assumption is that these fragments are being read to
60 // cache information such as font families, supported sizes etc.
61 // For reading fragments DirectWrite calls ReadFragment of our FontFileStream
62 // implementation with parameters start_offset and length. We cache these
63 // parameters along with associated data chunk.
64 // Here is small example of how segments are read
65 // start_offset: 0, length: 16
66 // start_offset: 0, length: 12
67 // start_offset: 0, length: 117
68 // For better cache management we collapse segments if they overlap or are
69 // adjacent.
70
71 namespace mswr = Microsoft::WRL;
72
73 const char kFontKeyName[] = "font_key_name";
74
75 // We use this value to determine whether to cache file fragments
76 // or not. In our trials we observed that for some font files
77 // direct write ends up reading almost entire file during enumeration
78 // phase. If we don't use this percentile formula we will end up
79 // increasing significant cache size by caching entire file contents
80 // for some of the font files.
81 const double kMaxPercentileOfFontFileSizeToCache = 0.6;
82
83 // With current implementation we map entire shared section into memory during
84 // renderer startup. This causes increase in working set of Chrome. As first
85 // step we want to see if caching is really improving any performance for our
86 // users, so we are putting arbitrary limit on cache file size. There are
87 // multiple ways we can tune our working size, like mapping only required part
88 // of section at any given time.
89 const double kArbitraryCacheFileSizeLimit = (30 * 1024 * 1024);
90
91 // We have chosen current font file length arbitrarily. In our logic
92 // if we don't find file we are looking for in cache we end up loading
93 // that file directly from system fonts folder.
94 const unsigned int kMaxFontFileNameLength = 34;
95
96 const DWORD kCacheFileVersion = 103;
97 const DWORD kFileSignature = 0x4D4F5243; // CROM
98 const DWORD kMagicCompletionSignature = 0x454E4F44; // DONE
99
100 const DWORD kUndefinedDWORDS = 36;
101
102 // Make sure that all structure sizes align with 8 byte boundary otherwise
103 // dr. memory test may complain.
104 #pragma pack(push, 8)
105 // Cache file header, includes signature, completion bits and version.
106 struct CacheFileHeader {
107 CacheFileHeader() {
108 file_signature = kFileSignature;
109 magic_completion_signature = 0;
110 version = kCacheFileVersion;
111 ::ZeroMemory(undefined, sizeof(undefined));
112 }
113
114 DWORD file_signature;
115 DWORD magic_completion_signature;
116 DWORD version;
117 BYTE undefined[kUndefinedDWORDS];
118 };
119
120 // Entry for a particular font file within this cache.
121 struct CacheFileEntry {
122 CacheFileEntry() {
123 file_size = 0;
124 entry_count = 0;
125 ::ZeroMemory(file_name, sizeof(file_name));
126 }
127
128 UINT64 file_size;
129 DWORD entry_count;
130 wchar_t file_name[kMaxFontFileNameLength];
131 };
132
133 // Offsets or data chunks that are cached for particular font file.
134 struct CacheFileOffsetEntry {
135 CacheFileOffsetEntry() {
136 start_offset = 0;
137 length = 0;
138 }
139
140 UINT64 start_offset;
141 UINT64 length;
142 /* BYTE blob_[]; // Place holder for the blob that follows. */
143 };
144 #pragma pack(pop)
145
146 bool ValidateFontCacheHeader(CacheFileHeader* header) {
147 return (header->file_signature == kFileSignature &&
148 header->magic_completion_signature == kMagicCompletionSignature &&
149 header->version == kCacheFileVersion);
150 }
151
152 class FontCacheWriter;
153
154 // This class implements main interface required for loading custom font
155 // collection as specified by DirectWrite. We also use this class for storing
156 // some state information as this is one of the centralized entity.
157 class FontCollectionLoader
158 : public mswr::RuntimeClass<mswr::RuntimeClassFlags<mswr::ClassicCom>,
159 IDWriteFontCollectionLoader> {
160 public:
161 FontCollectionLoader()
162 : in_collection_building_mode_(false),
163 create_static_cache_(false) {}
164
165 ~FontCollectionLoader() override;
166
167 HRESULT RuntimeClassInitialize() {
168 return S_OK;
169 }
170
171 // IDWriteFontCollectionLoader methods.
172 HRESULT STDMETHODCALLTYPE
173 CreateEnumeratorFromKey(IDWriteFactory* factory,
174 void const* key,
175 UINT32 key_size,
176 IDWriteFontFileEnumerator** file_enumerator) override;
177
178 // Does all the initialization for required loading fonts from registry.
179 static HRESULT Initialize(IDWriteFactory* factory);
180
181 // Returns font cache map size.
182 UINT32 GetFontMapSize();
183
184 // Returns font name string when given font index.
185 base::string16 GetFontNameFromKey(UINT32 idx);
186
187 // Loads internal structure with fonts from registry.
188 bool LoadFontListFromRegistry();
189
190 // Loads restricted web safe fonts as fallback method to registry fonts.
191 bool LoadRestrictedFontList();
192
193 // Puts class in collection building mode. In collection building mode
194 // we use static cache if it is available as a look aside buffer.
195 void EnableCollectionBuildingMode(bool enable);
196
197 // Returns current state of collection building.
198 bool InCollectionBuildingMode();
199
200 // Loads static cache file.
201 bool LoadCacheFile();
202
203 // Unloads cache file and related data.
204 void UnloadCacheFile();
205
206 // Puts class in static cache creating mode. In this mode we record all
207 // direct write requests and store chunks of font data.
208 void EnterStaticCacheMode(const WCHAR* file_name);
209
210 // Gets out of static cache building mode.
211 void LeaveStaticCacheMode();
212
213 // Returns if class is currently in static cache building mode.
214 bool IsBuildStaticCacheMode();
215
216 // Validates cache file for consistency.
217 bool ValidateCacheFile(base::File* file);
218
219 private:
220 // Structure to represent each chunk within font file that we load in memory.
221 struct CacheTableOffsetEntry {
222 UINT64 start_offset;
223 UINT64 length;
224 BYTE* inside_file_ptr;
225 };
226
227 typedef std::vector<CacheTableOffsetEntry> OffsetVector;
228
229 // Structure representing each font entry with cache.
230 struct CacheTableEntry {
231 UINT64 file_size;
232 OffsetVector offset_entries;
233 };
234
235 public:
236 // Returns whether file we have particular font entry within cache or not.
237 bool IsFileCached(UINT32 font_key);
238 // Returns cache fragment corresponding to specific font key.
239 void* GetCachedFragment(UINT32 font_key, UINT64 start_offset, UINT64 length);
240 // Returns actual font file size at the time of caching.
241 UINT64 GetCachedFileSize(UINT32 font_key);
242
243 // Returns instance of font cache writer. This class manages actual font
244 // file format.
245 FontCacheWriter* GetFontCacheWriter();
246
247 private:
248 // Functions validates and loads cache into internal map.
249 bool ValidateAndLoadCacheMap();
250
251 mswr::ComPtr<IDWriteFontFileLoader> file_loader_;
252
253 std::vector<base::string16> reg_fonts_;
254 bool in_collection_building_mode_;
255 bool create_static_cache_;
256 scoped_ptr<base::SharedMemory> cache_;
257 scoped_ptr<FontCacheWriter> cache_writer_;
258
259 typedef std::map<base::string16, CacheTableEntry*> CacheMap;
260 CacheMap cache_map_;
261
262 DISALLOW_COPY_AND_ASSIGN(FontCollectionLoader);
263 };
264
265 mswr::ComPtr<FontCollectionLoader> g_font_loader;
266 base::win::ScopedHandle g_shared_font_cache;
267
268 // Class responsible for handling font cache file format details as well as
269 // tracking various cache region requests by direct write.
270 class FontCacheWriter {
271 public:
272 FontCacheWriter() : count_font_entries_ignored_(0), cookie_counter_(0) {}
273
274 ~FontCacheWriter() {
275 if (static_cache_.get()) {
276 static_cache_->Close();
277 }
278 }
279
280 public:
281 // Holds data related to individual region as requested by direct write.
282 struct CacheRegion {
283 UINT64 start_offset;
284 UINT64 length;
285 const BYTE* ptr;
286 /* BYTE blob_[]; // Place holder for the blob that follows. */
287 };
288
289 // Function to create static font cache file.
290 bool Create(const wchar_t* file_name) {
291 static_cache_.reset(new base::File(base::FilePath(file_name),
292 base::File::FLAG_OPEN_ALWAYS | base::File::FLAG_WRITE |
293 base::File::FLAG_EXCLUSIVE_WRITE));
294 if (!static_cache_->IsValid()) {
295 static_cache_.reset();
296 return false;
297 }
298 CacheFileHeader header;
299
300 // At offset 0 write cache version
301 static_cache_->Write(0,
302 reinterpret_cast<const char*>(&header),
303 sizeof(header));
304
305 static_cache_->Flush();
306 return true;
307 }
308
309 // Closes static font cache file. Also writes completion signature to mark
310 // it as completely written.
311 void Close() {
312 if (static_cache_.get()) {
313 CacheFileHeader header;
314 header.magic_completion_signature = kMagicCompletionSignature;
315 // At offset 0 write cache version
316 int bytes_written = static_cache_->Write(0,
317 reinterpret_cast<const char*>(&header),
318 sizeof(header));
319 DCHECK_NE(bytes_written, -1);
320
321 UMA_HISTOGRAM_MEMORY_KB("DirectWrite.Fonts.BuildCache.File.Size",
322 static_cache_->GetLength() / 1024);
323
324 UMA_HISTOGRAM_COUNTS("DirectWrite.Fonts.BuildCache.Ignored",
325 count_font_entries_ignored_);
326
327 static_cache_->Close();
328 static_cache_.reset(NULL);
329 }
330 }
331
332 private:
333 typedef std::vector<CacheRegion> RegionVector;
334
335 // Structure to track various regions requested by direct write for particular
336 // font file.
337 struct FontEntryInternal {
338 FontEntryInternal(const wchar_t* name, UINT64 size)
339 : file_name(name),
340 file_size(size) {
341 }
342
343 base::string16 file_name;
344 UINT64 file_size;
345 RegionVector regions;
346 };
347
348 public:
349 // Starts up new font entry to be tracked, returns cookie to identify this
350 // particular entry.
351 UINT NewFontEntry(const wchar_t* file_name, UINT64 file_size) {
352 base::AutoLock lock(lock_);
353 UINT old_counter = cookie_counter_;
354 FontEntryInternal* font_entry = new FontEntryInternal(file_name, file_size);
355 cookie_map_[cookie_counter_].reset(font_entry);
356 cookie_counter_++;
357 return old_counter;
358 }
359
360 // AddRegion function lets caller add various regions to be cached for
361 // particular font file. Once enumerating that particular font file is done
362 // (based on uniquely identifying cookie) changes could be committed using
363 // CommitFontEntry
364 bool AddRegion(UINT64 cookie, UINT64 start, UINT64 length, const BYTE* ptr) {
365 base::AutoLock lock(lock_);
366 if (cookie_map_.find(cookie) == cookie_map_.end())
367 return false;
368 RegionVector& regions = cookie_map_[cookie].get()->regions;
369 CacheRegion region;
370 region.start_offset = start;
371 region.length = length;
372 region.ptr = ptr;
373 regions.push_back(region);
374 return true;
375 }
376
377 // Function which commits after merging all collected regions into cache file.
378 bool CommitFontEntry(UINT cookie) {
379 base::AutoLock lock(lock_);
380 if (cookie_map_.find(cookie) == cookie_map_.end())
381 return false;
382
383 // We will skip writing entries beyond allowed limit. Following condition
384 // doesn't enforce hard file size. We need to write complete font entry.
385 int64_t length = static_cache_->GetLength();
386 if (length == -1 || length >= kArbitraryCacheFileSizeLimit) {
387 count_font_entries_ignored_++;
388 return false;
389 }
390
391 FontEntryInternal* font_entry = cookie_map_[cookie].get();
392 RegionVector& regions = font_entry->regions;
393 std::sort(regions.begin(), regions.end(), SortCacheRegions);
394
395 // At this point, we have collected all regions to be cached. These regions
396 // are tuples of start, length, data for particular data segment.
397 // These tuples can overlap.
398 // e.g. (0, 12, data), (0, 117, data), (21, 314, data), (335, 15, data)
399 // In this case as you can see first three segments overlap and
400 // 4th is adjacent. If we cache them individually then we will end up
401 // caching duplicate data, so we merge these segments together to find
402 // superset for the cache. In above example our algorithm should
403 // produce (cache) single segment starting at offset 0 with length 350.
404 RegionVector merged_regions;
405 RegionVector::iterator iter;
406 int idx = 0;
407 for (iter = regions.begin(); iter != regions.end(); iter++) {
408 if (iter == regions.begin()) {
409 merged_regions.push_back(*iter);
410 continue;
411 }
412 CacheRegion& base_region = merged_regions[idx];
413 if (IsOverlap(&base_region, &(*iter))) {
414 UINT64 end1 = base_region.start_offset + base_region.length;
415 UINT64 end2 = iter->start_offset + iter->length;
416 if (base_region.start_offset > iter->start_offset) {
417 base_region.start_offset = iter->start_offset;
418 base_region.ptr = iter->ptr;
419 }
420 base_region.length = std::max(end1, end2) - base_region.start_offset;
421 } else {
422 merged_regions.push_back(*iter);
423 idx++;
424 }
425 }
426
427 UINT64 total_merged_cache_in_bytes = 0;
428 for (iter = merged_regions.begin(); iter != merged_regions.end(); iter++) {
429 total_merged_cache_in_bytes += iter->length;
430 }
431
432 // We want to adjust following parameter based on experiments. But general
433 // logic here is that if we are going to end up caching most of the contents
434 // for a file (e.g. simsunb.ttf > 90%) then we should avoid caching that
435 // file.
436 double percentile = static_cast<double>(total_merged_cache_in_bytes) /
437 font_entry->file_size;
438 if (percentile > kMaxPercentileOfFontFileSizeToCache) {
439 count_font_entries_ignored_++;
440 return false;
441 }
442
443 CacheFileEntry entry;
444 wcsncpy_s(entry.file_name, kMaxFontFileNameLength,
445 font_entry->file_name.c_str(), _TRUNCATE);
446 entry.file_size = font_entry->file_size;
447 entry.entry_count = merged_regions.size();
448 static_cache_->WriteAtCurrentPos(
449 reinterpret_cast<const char*>(&entry),
450 sizeof(entry));
451 for (iter = merged_regions.begin(); iter != merged_regions.end(); iter++) {
452 CacheFileOffsetEntry offset_entry;
453 offset_entry.start_offset = iter->start_offset;
454 offset_entry.length = iter->length;
455 static_cache_->WriteAtCurrentPos(
456 reinterpret_cast<const char*>(&offset_entry),
457 sizeof(offset_entry));
458 static_cache_->WriteAtCurrentPos(
459 reinterpret_cast<const char*>(iter->ptr),
460 iter->length);
461 }
462 return true;
463 }
464
465 private:
466 // This is the count of font entries that we reject based on size to be
467 // cached.
468 unsigned int count_font_entries_ignored_;
469 scoped_ptr<base::File> static_cache_;
470 std::map<UINT, scoped_ptr<FontEntryInternal>> cookie_map_;
471 UINT cookie_counter_;
472
473 // Lock is required to protect internal data structures and access to file,
474 // According to MSDN documentation on ReadFileFragment and based on our
475 // experiments so far, there is possibility of ReadFileFragment getting called
476 // from multiple threads.
477 base::Lock lock_;
478
479 // Function checks if two regions overlap or are adjacent.
480 bool IsOverlap(CacheRegion* region1, CacheRegion* region2) {
481 return
482 !((region1->start_offset + region1->length) < region2->start_offset ||
483 region1->start_offset > (region2->start_offset + region2->length));
484 }
485
486 // Function to sort cached regions.
487 static bool SortCacheRegions(const CacheRegion& region1,
488 const CacheRegion& region2) {
489 return
490 region1.start_offset == region2.start_offset ?
491 region1.length < region2.length :
492 region1.start_offset < region2.start_offset;
493 }
494
495 DISALLOW_COPY_AND_ASSIGN(FontCacheWriter);
496 };
497
498 // Class implements IDWriteFontFileStream interface as required by direct write.
499 class FontFileStream
500 : public mswr::RuntimeClass<mswr::RuntimeClassFlags<mswr::ClassicCom>,
501 IDWriteFontFileStream> {
502 public:
503 // IDWriteFontFileStream methods.
504 HRESULT STDMETHODCALLTYPE ReadFileFragment(
505 void const** fragment_start,
506 UINT64 file_offset,
507 UINT64 fragment_size,
508 void** context) override {
509 if (cached_data_) {
510 *fragment_start = g_font_loader->GetCachedFragment(font_key_,
511 file_offset,
512 fragment_size);
513 if (*fragment_start == NULL) {
514 DCHECK(false);
515 }
516 *context = NULL;
517 return *fragment_start != NULL ? S_OK : E_FAIL;
518 }
519 if (!memory_.get() || !memory_->IsValid() ||
520 file_offset >= memory_->length() ||
521 (file_offset + fragment_size) > memory_->length())
522 return E_FAIL;
523
524 *fragment_start = static_cast<BYTE const*>(memory_->data()) +
525 static_cast<size_t>(file_offset);
526 *context = NULL;
527 if (g_font_loader->IsBuildStaticCacheMode()) {
528 FontCacheWriter* cache_writer = g_font_loader->GetFontCacheWriter();
529 cache_writer->AddRegion(writer_cookie_,
530 file_offset,
531 fragment_size,
532 static_cast<const BYTE*>(*fragment_start));
533 }
534 return S_OK;
535 }
536
537 void STDMETHODCALLTYPE ReleaseFileFragment(void* context) override {}
538
539 HRESULT STDMETHODCALLTYPE GetFileSize(UINT64* file_size) override {
540 if (cached_data_) {
541 *file_size = g_font_loader->GetCachedFileSize(font_key_);
542 return S_OK;
543 }
544
545 if (!memory_.get() || !memory_->IsValid())
546 return E_FAIL;
547
548 *file_size = memory_->length();
549 return S_OK;
550 }
551
552 HRESULT STDMETHODCALLTYPE GetLastWriteTime(UINT64* last_write_time) override {
553 if (cached_data_) {
554 *last_write_time = 0;
555 return S_OK;
556 }
557
558 if (!memory_.get() || !memory_->IsValid())
559 return E_FAIL;
560
561 // According to MSDN article http://goo.gl/rrSYzi the "last modified time"
562 // is used by DirectWrite font selection algorithms to determine whether
563 // one font resource is more up to date than another one.
564 // So by returning 0 we are assuming that it will treat all fonts to be
565 // equally up to date.
566 // TODO(shrikant): We should further investigate this.
567 *last_write_time = 0;
568 return S_OK;
569 }
570
571 FontFileStream() : font_key_(0), cached_data_(false) {}
572
573 HRESULT RuntimeClassInitialize(UINT32 font_key) {
574 if (g_font_loader->InCollectionBuildingMode() &&
575 g_font_loader->IsFileCached(font_key)) {
576 cached_data_ = true;
577 font_key_ = font_key;
578 return S_OK;
579 }
580
581 base::FilePath path;
582 PathService::Get(base::DIR_WINDOWS_FONTS, &path);
583 base::string16 font_key_name(g_font_loader->GetFontNameFromKey(font_key));
584 path = path.Append(font_key_name.c_str());
585 memory_.reset(new base::MemoryMappedFile());
586
587 // Put some debug information on stack.
588 WCHAR font_name[MAX_PATH];
589 path.value().copy(font_name, arraysize(font_name));
590 base::debug::Alias(font_name);
591
592 if (!memory_->Initialize(path)) {
593 memory_.reset();
594 return E_FAIL;
595 }
596
597 font_key_ = font_key;
598
599 base::debug::SetCrashKeyValue(kFontKeyName,
600 base::WideToUTF8(font_key_name));
601
602 if (g_font_loader->IsBuildStaticCacheMode()) {
603 FontCacheWriter* cache_writer = g_font_loader->GetFontCacheWriter();
604 writer_cookie_ = cache_writer->NewFontEntry(font_key_name.c_str(),
605 memory_->length());
606 }
607 return S_OK;
608 }
609
610 ~FontFileStream() override {
611 if (g_font_loader->IsBuildStaticCacheMode()) {
612 FontCacheWriter* cache_writer = g_font_loader->GetFontCacheWriter();
613 cache_writer->CommitFontEntry(writer_cookie_);
614 }
615 }
616
617 private:
618 UINT32 font_key_;
619 scoped_ptr<base::MemoryMappedFile> memory_;
620 bool cached_data_;
621 UINT writer_cookie_;
622
623 DISALLOW_COPY_AND_ASSIGN(FontFileStream);
624 };
625
626 // Implements IDWriteFontFileLoader as required by FontFileLoader.
627 class FontFileLoader
628 : public mswr::RuntimeClass<mswr::RuntimeClassFlags<mswr::ClassicCom>,
629 IDWriteFontFileLoader> {
630 public:
631 // IDWriteFontFileLoader methods.
632 HRESULT STDMETHODCALLTYPE
633 CreateStreamFromKey(void const* ref_key,
634 UINT32 ref_key_size,
635 IDWriteFontFileStream** stream) override {
636 if (ref_key_size != sizeof(UINT32))
637 return E_FAIL;
638
639 UINT32 font_key = *static_cast<const UINT32*>(ref_key);
640 mswr::ComPtr<FontFileStream> font_stream;
641 HRESULT hr = mswr::MakeAndInitialize<FontFileStream>(&font_stream,
642 font_key);
643 if (SUCCEEDED(hr)) {
644 *stream = font_stream.Detach();
645 return S_OK;
646 }
647 return E_FAIL;
648 }
649
650 FontFileLoader() {}
651 ~FontFileLoader() override {}
652
653 private:
654 DISALLOW_COPY_AND_ASSIGN(FontFileLoader);
655 };
656
657 // Implements IDWriteFontFileEnumerator as required by direct write.
658 class FontFileEnumerator
659 : public mswr::RuntimeClass<mswr::RuntimeClassFlags<mswr::ClassicCom>,
660 IDWriteFontFileEnumerator> {
661 public:
662 // IDWriteFontFileEnumerator methods.
663 HRESULT STDMETHODCALLTYPE MoveNext(BOOL* has_current_file) override {
664 *has_current_file = FALSE;
665
666 if (current_file_)
667 current_file_.ReleaseAndGetAddressOf();
668
669 if (font_idx_ < g_font_loader->GetFontMapSize()) {
670 HRESULT hr =
671 factory_->CreateCustomFontFileReference(&font_idx_,
672 sizeof(UINT32),
673 file_loader_.Get(),
674 current_file_.GetAddressOf());
675 DCHECK(SUCCEEDED(hr));
676 *has_current_file = TRUE;
677 font_idx_++;
678 }
679 return S_OK;
680 }
681
682 HRESULT STDMETHODCALLTYPE
683 GetCurrentFontFile(IDWriteFontFile** font_file) override {
684 if (!current_file_) {
685 *font_file = NULL;
686 return E_FAIL;
687 }
688
689 *font_file = current_file_.Detach();
690 return S_OK;
691 }
692
693 FontFileEnumerator(const void* keys,
694 UINT32 buffer_size,
695 IDWriteFactory* factory,
696 IDWriteFontFileLoader* file_loader)
697 : factory_(factory), file_loader_(file_loader), font_idx_(0) {}
698
699 ~FontFileEnumerator() override {}
700
701 mswr::ComPtr<IDWriteFactory> factory_;
702 mswr::ComPtr<IDWriteFontFile> current_file_;
703 mswr::ComPtr<IDWriteFontFileLoader> file_loader_;
704 UINT32 font_idx_;
705
706 private:
707 DISALLOW_COPY_AND_ASSIGN(FontFileEnumerator);
708 };
709
710 // IDWriteFontCollectionLoader methods.
711 HRESULT STDMETHODCALLTYPE FontCollectionLoader::CreateEnumeratorFromKey(
712 IDWriteFactory* factory,
713 void const* key,
714 UINT32 key_size,
715 IDWriteFontFileEnumerator** file_enumerator) {
716 *file_enumerator = mswr::Make<FontFileEnumerator>(
717 key, key_size, factory, file_loader_.Get()).Detach();
718 return S_OK;
719 }
720
721 // static
722 HRESULT FontCollectionLoader::Initialize(IDWriteFactory* factory) {
723 DCHECK(g_font_loader == NULL);
724
725 HRESULT result;
726 result = mswr::MakeAndInitialize<FontCollectionLoader>(&g_font_loader);
727 if (FAILED(result) || !g_font_loader) {
728 DCHECK(false);
729 return E_FAIL;
730 }
731
732 CHECK(g_font_loader->LoadFontListFromRegistry());
733
734 g_font_loader->file_loader_ = mswr::Make<FontFileLoader>().Detach();
735
736 factory->RegisterFontFileLoader(g_font_loader->file_loader_.Get());
737 factory->RegisterFontCollectionLoader(g_font_loader.Get());
738
739 return S_OK;
740 }
741
742 FontCollectionLoader::~FontCollectionLoader() {
743 STLDeleteContainerPairSecondPointers(cache_map_.begin(), cache_map_.end());
744 }
745
746 UINT32 FontCollectionLoader::GetFontMapSize() {
747 return reg_fonts_.size();
748 }
749
750 base::string16 FontCollectionLoader::GetFontNameFromKey(UINT32 idx) {
751 DCHECK(idx < reg_fonts_.size());
752 return reg_fonts_[idx];
753 }
754
755 const base::FilePath::CharType* kFontExtensionsToIgnore[] {
756 FILE_PATH_LITERAL(".FON"), // Bitmap or vector
757 FILE_PATH_LITERAL(".PFM"), // Adobe Type 1
758 FILE_PATH_LITERAL(".PFB"), // Adobe Type 1
759 };
760
761 const wchar_t* kFontsToIgnore[] = {
762 // "Gill Sans Ultra Bold" turns into an Ultra Bold weight "Gill Sans" in
763 // DirectWrite, but most users don't have any other weights. The regular
764 // weight font is named "Gill Sans MT", but that ends up in a different
765 // family with that name. On Mac, there's a "Gill Sans" with various weights,
766 // so CSS authors use { 'font-family': 'Gill Sans', 'Gill Sans MT', ... } and
767 // because of the DirectWrite family futzing, they end up with an Ultra Bold
768 // font, when they just wanted "Gill Sans". Mozilla implemented a more
769 // complicated hack where they effectively rename the Ultra Bold font to
770 // "Gill Sans MT Ultra Bold", but because the Ultra Bold font is so ugly
771 // anyway, we simply ignore it. See
772 // http://www.microsoft.com/typography/fonts/font.aspx?FMID=978 for a picture
773 // of the font, and the file name. We also ignore "Gill Sans Ultra Bold
774 // Condensed".
775 L"gilsanub.ttf",
776 L"gillubcd.ttf",
777 };
778
779 bool FontCollectionLoader::LoadFontListFromRegistry() {
780 const wchar_t kFontsRegistry[] =
781 L"Software\\Microsoft\\Windows NT\\CurrentVersion\\Fonts";
782 CHECK(reg_fonts_.empty());
783 base::win::RegKey regkey;
784 if (regkey.Open(HKEY_LOCAL_MACHINE, kFontsRegistry, KEY_READ) !=
785 ERROR_SUCCESS) {
786 return false;
787 }
788
789 base::FilePath system_font_path;
790 PathService::Get(base::DIR_WINDOWS_FONTS, &system_font_path);
791
792 base::string16 name;
793 base::string16 value;
794 for (DWORD idx = 0; idx < regkey.GetValueCount(); idx++) {
795 if (regkey.GetValueNameAt(idx, &name) == ERROR_SUCCESS &&
796 regkey.ReadValue(name.c_str(), &value) == ERROR_SUCCESS) {
797 base::FilePath path(value.c_str());
798 // We need to check if path in registry is absolute, if it is then
799 // we check if it is same as DIR_WINDOWS_FONTS otherwise we ignore.
800 bool absolute = path.IsAbsolute();
801 if (absolute &&
802 !base::FilePath::CompareEqualIgnoreCase(system_font_path.value(),
803 path.DirName().value())) {
804 continue;
805 }
806
807 // Ignore if path ends with a separator.
808 if (path.EndsWithSeparator())
809 continue;
810
811 if (absolute)
812 value = path.BaseName().value();
813
814 bool should_ignore = false;
815 for (const auto& ignore : kFontsToIgnore) {
816 if (base::FilePath::CompareEqualIgnoreCase(value, ignore)) {
817 should_ignore = true;
818 break;
819 }
820 }
821 // DirectWrite doesn't support bitmap/vector fonts and Adobe type 1
822 // fonts, we will ignore those font extensions.
823 // MSDN article: http://goo.gl/TfCOA
824 if (!should_ignore) {
825 for (const auto& ignore : kFontExtensionsToIgnore) {
826 if (path.MatchesExtension(ignore)) {
827 should_ignore = true;
828 break;
829 }
830 }
831 }
832
833 if (!should_ignore)
834 reg_fonts_.push_back(value.c_str());
835 }
836 }
837 UMA_HISTOGRAM_COUNTS("DirectWrite.Fonts.Loaded", reg_fonts_.size());
838 UMA_HISTOGRAM_COUNTS("DirectWrite.Fonts.Ignored",
839 regkey.GetValueCount() - reg_fonts_.size());
840 return true;
841 }
842
843 // This list is mainly based on prefs/prefs_tab_helper.cc kFontDefaults.
844 const wchar_t* kRestrictedFontSet[] = {
845 // These are the "Web Safe" fonts.
846 L"times.ttf", // IDS_STANDARD_FONT_FAMILY
847 L"timesbd.ttf", // IDS_STANDARD_FONT_FAMILY
848 L"timesbi.ttf", // IDS_STANDARD_FONT_FAMILY
849 L"timesi.ttf", // IDS_STANDARD_FONT_FAMILY
850 L"cour.ttf", // IDS_FIXED_FONT_FAMILY
851 L"courbd.ttf", // IDS_FIXED_FONT_FAMILY
852 L"courbi.ttf", // IDS_FIXED_FONT_FAMILY
853 L"couri.ttf", // IDS_FIXED_FONT_FAMILY
854 L"consola.ttf", // IDS_FIXED_FONT_FAMILY_ALT_WIN
855 L"consolab.ttf", // IDS_FIXED_FONT_FAMILY_ALT_WIN
856 L"consolai.ttf", // IDS_FIXED_FONT_FAMILY_ALT_WIN
857 L"consolaz.ttf", // IDS_FIXED_FONT_FAMILY_ALT_WIN
858 L"arial.ttf", // IDS_SANS_SERIF_FONT_FAMILY
859 L"arialbd.ttf", // IDS_SANS_SERIF_FONT_FAMILY
860 L"arialbi.ttf", // IDS_SANS_SERIF_FONT_FAMILY
861 L"ariali.ttf", // IDS_SANS_SERIF_FONT_FAMILY
862 L"comic.ttf", // IDS_CURSIVE_FONT_FAMILY
863 L"comicbd.ttf", // IDS_CURSIVE_FONT_FAMILY
864 L"comici.ttf", // IDS_CURSIVE_FONT_FAMILY
865 L"comicz.ttf", // IDS_CURSIVE_FONT_FAMILY
866 L"impact.ttf", // IDS_FANTASY_FONT_FAMILY
867 L"georgia.ttf",
868 L"georgiab.ttf",
869 L"georgiai.ttf",
870 L"georgiaz.ttf",
871 L"trebuc.ttf",
872 L"trebucbd.ttf",
873 L"trebucbi.ttf",
874 L"trebucit.ttf",
875 L"verdana.ttf",
876 L"verdanab.ttf",
877 L"verdanai.ttf",
878 L"verdanaz.ttf",
879 L"segoeui.ttf", // IDS_PICTOGRAPH_FONT_FAMILY
880 L"segoeuib.ttf", // IDS_PICTOGRAPH_FONT_FAMILY
881 L"segoeuii.ttf", // IDS_PICTOGRAPH_FONT_FAMILY
882 L"msgothic.ttc", // IDS_STANDARD_FONT_FAMILY_JAPANESE
883 L"msmincho.ttc", // IDS_SERIF_FONT_FAMILY_JAPANESE
884 L"gulim.ttc", // IDS_FIXED_FONT_FAMILY_KOREAN
885 L"batang.ttc", // IDS_SERIF_FONT_FAMILY_KOREAN
886 L"simsun.ttc", // IDS_STANDARD_FONT_FAMILY_SIMPLIFIED_HAN
887 L"mingliu.ttc", // IDS_SERIF_FONT_FAMILY_TRADITIONAL_HAN
888
889 // These are from the Blink fallback list.
890 L"david.ttf", // USCRIPT_HEBREW
891 L"davidbd.ttf", // USCRIPT_HEBREW
892 L"euphemia.ttf", // USCRIPT_CANADIAN_ABORIGINAL
893 L"gautami.ttf", // USCRIPT_TELUGU
894 L"gautamib.ttf", // USCRIPT_TELUGU
895 L"latha.ttf", // USCRIPT_TAMIL
896 L"lathab.ttf", // USCRIPT_TAMIL
897 L"mangal.ttf", // USCRIPT_DEVANAGARI
898 L"mangalb.ttf", // USCRIPT_DEVANAGARI
899 L"monbaiti.ttf", // USCRIPT_MONGOLIAN
900 L"mvboli.ttf", // USCRIPT_THAANA
901 L"plantc.ttf", // USCRIPT_CHEROKEE
902 L"raavi.ttf", // USCRIPT_GURMUKHI
903 L"raavib.ttf", // USCRIPT_GURMUKHI
904 L"shruti.ttf", // USCRIPT_GUJARATI
905 L"shrutib.ttf", // USCRIPT_GUJARATI
906 L"sylfaen.ttf", // USCRIPT_GEORGIAN and USCRIPT_ARMENIAN
907 L"tahoma.ttf", // USCRIPT_ARABIC,
908 L"tahomabd.ttf", // USCRIPT_ARABIC,
909 L"tunga.ttf", // USCRIPT_KANNADA
910 L"tungab.ttf", // USCRIPT_KANNADA
911 L"vrinda.ttf", // USCRIPT_BENGALI
912 L"vrindab.ttf", // USCRIPT_BENGALI
913 };
914
915 bool FontCollectionLoader::LoadRestrictedFontList() {
916 reg_fonts_.clear();
917 reg_fonts_.assign(kRestrictedFontSet,
918 kRestrictedFontSet + _countof(kRestrictedFontSet));
919 return true;
920 }
921
922 void FontCollectionLoader::EnableCollectionBuildingMode(bool enable) {
923 in_collection_building_mode_ = enable;
924 }
925
926 bool FontCollectionLoader::InCollectionBuildingMode() {
927 return in_collection_building_mode_;
928 }
929
930 bool FontCollectionLoader::IsFileCached(UINT32 font_key) {
931 if (!cache_.get() || cache_->memory() == NULL) {
932 return false;
933 }
934 CacheMap::iterator iter = cache_map_.find(
935 GetFontNameFromKey(font_key).c_str());
936 return iter != cache_map_.end();
937 }
938
939 bool FontCollectionLoader::LoadCacheFile() {
940 TRACE_EVENT0("startup", "FontCollectionLoader::LoadCacheFile");
941
942 std::string font_cache_handle_string =
943 base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
944 switches::kFontCacheSharedHandle);
945 if (font_cache_handle_string.empty())
946 return false;
947
948 unsigned int handle_uint;
949 base::StringToUint(font_cache_handle_string, &handle_uint);
950 DCHECK(handle_uint);
951 if (handle_uint > static_cast<unsigned int>(std::numeric_limits<long>::max()))
952 return false;
953 base::SharedMemoryHandle font_cache_handle(LongToHandle(handle_uint),
954 base::GetCurrentProcId());
955
956 base::SharedMemory* shared_mem = new base::SharedMemory(
957 font_cache_handle, true);
958 // Map the cache file into memory.
959 shared_mem->Map(0);
960
961 cache_.reset(shared_mem);
962
963 if (base::StartsWith(base::FieldTrialList::FindFullName("LightSpeed"),
964 "PrefetchDWriteFontCache",
965 base::CompareCase::SENSITIVE)) {
966 // Prefetch the cache, to avoid unordered IO when it is used.
967 // PrefetchVirtualMemory() is loaded dynamically because it is only
968 // available from Win8.
969 decltype(PrefetchVirtualMemory)* prefetch_virtual_memory =
970 reinterpret_cast<decltype(PrefetchVirtualMemory)*>(::GetProcAddress(
971 ::GetModuleHandle(L"kernel32.dll"), "PrefetchVirtualMemory"));
972 if (prefetch_virtual_memory != NULL) {
973 WIN32_MEMORY_RANGE_ENTRY memory_range;
974 memory_range.VirtualAddress = shared_mem->memory();
975 memory_range.NumberOfBytes = shared_mem->mapped_size();
976 prefetch_virtual_memory(::GetCurrentProcess(), 1, &memory_range, 0);
977 }
978 }
979
980 if (!ValidateAndLoadCacheMap()) {
981 cache_.reset();
982 return false;
983 }
984
985 return true;
986 }
987
988 void FontCollectionLoader::UnloadCacheFile() {
989 cache_.reset();
990 STLDeleteContainerPairSecondPointers(cache_map_.begin(), cache_map_.end());
991 cache_map_.clear();
992 }
993
994 void FontCollectionLoader::EnterStaticCacheMode(const WCHAR* file_name) {
995 cache_writer_.reset(new FontCacheWriter());
996 if (cache_writer_->Create(file_name))
997 create_static_cache_ = true;
998 }
999
1000 void FontCollectionLoader::LeaveStaticCacheMode() {
1001 cache_writer_->Close();
1002 cache_writer_.reset(NULL);
1003 create_static_cache_ = false;
1004 }
1005
1006 bool FontCollectionLoader::IsBuildStaticCacheMode() {
1007 return create_static_cache_;
1008 }
1009
1010 bool FontCollectionLoader::ValidateAndLoadCacheMap() {
1011 BYTE* mem_file_start = static_cast<BYTE*>(cache_->memory());
1012 BYTE* mem_file_end = mem_file_start + cache_->mapped_size();
1013
1014 BYTE* current_ptr = mem_file_start;
1015 CacheFileHeader* file_header =
1016 reinterpret_cast<CacheFileHeader*>(current_ptr);
1017 if (!ValidateFontCacheHeader(file_header))
1018 return false;
1019
1020 current_ptr = current_ptr + sizeof(CacheFileHeader);
1021 if (current_ptr >= mem_file_end)
1022 return false;
1023
1024 while ((current_ptr + sizeof(CacheFileEntry)) < mem_file_end) {
1025 CacheFileEntry* entry = reinterpret_cast<CacheFileEntry*>(current_ptr);
1026 current_ptr += sizeof(CacheFileEntry);
1027 WCHAR file_name[kMaxFontFileNameLength];
1028 wcsncpy_s(file_name,
1029 kMaxFontFileNameLength,
1030 entry->file_name,
1031 _TRUNCATE);
1032 CacheTableEntry* table_entry = NULL;
1033 CacheMap::iterator iter = cache_map_.find(file_name);
1034 if (iter == cache_map_.end()) {
1035 table_entry = new CacheTableEntry();
1036 cache_map_[file_name] = table_entry;
1037 } else {
1038 table_entry = iter->second;
1039 }
1040 table_entry->file_size = entry->file_size;
1041 for (DWORD idx = 0;
1042 (current_ptr + sizeof(CacheFileOffsetEntry)) < mem_file_end &&
1043 idx < entry->entry_count;
1044 idx++) {
1045 CacheFileOffsetEntry* offset_entry =
1046 reinterpret_cast<CacheFileOffsetEntry*>(current_ptr);
1047 CacheTableOffsetEntry table_offset_entry;
1048 table_offset_entry.start_offset = offset_entry->start_offset;
1049 table_offset_entry.length = offset_entry->length;
1050 table_offset_entry.inside_file_ptr =
1051 current_ptr + sizeof(CacheFileOffsetEntry);
1052 table_entry->offset_entries.push_back(table_offset_entry);
1053 current_ptr += sizeof(CacheFileOffsetEntry);
1054 current_ptr += offset_entry->length;
1055 }
1056 }
1057
1058 return true;
1059 }
1060
1061 void* FontCollectionLoader::GetCachedFragment(UINT32 font_key,
1062 UINT64 start_offset,
1063 UINT64 length) {
1064 UINT64 just_past_end = start_offset + length;
1065 CacheMap::iterator iter = cache_map_.find(
1066 GetFontNameFromKey(font_key).c_str());
1067 if (iter != cache_map_.end()) {
1068 CacheTableEntry* entry = iter->second;
1069 OffsetVector::iterator offset_iter = entry->offset_entries.begin();
1070 while (offset_iter != entry->offset_entries.end()) {
1071 UINT64 available_just_past_end =
1072 offset_iter->start_offset + offset_iter->length;
1073 if (offset_iter->start_offset <= start_offset &&
1074 just_past_end <= available_just_past_end) {
1075 return offset_iter->inside_file_ptr +
1076 (start_offset - offset_iter->start_offset);
1077 }
1078 offset_iter++;
1079 }
1080 }
1081 return NULL;
1082 }
1083
1084 UINT64 FontCollectionLoader::GetCachedFileSize(UINT32 font_key) {
1085 CacheMap::iterator iter = cache_map_.find(
1086 GetFontNameFromKey(font_key).c_str());
1087 if (iter != cache_map_.end()) {
1088 return iter->second->file_size;
1089 }
1090 return 0;
1091 }
1092
1093 FontCacheWriter* FontCollectionLoader::GetFontCacheWriter() {
1094 return cache_writer_.get();
1095 }
1096
1097 } // namespace
1098
1099 namespace content {
1100
1101 const char kFontCacheSharedSectionName[] = "ChromeDWriteFontCache";
1102
1103 mswr::ComPtr<IDWriteFontCollection> g_font_collection;
1104
1105 IDWriteFontCollection* GetCustomFontCollection(IDWriteFactory* factory) {
1106 if (g_font_collection.Get() != NULL)
1107 return g_font_collection.Get();
1108
1109 TRACE_EVENT0("startup", "content::GetCustomFontCollection");
1110
1111 base::TimeTicks start_tick = base::TimeTicks::Now();
1112
1113 FontCollectionLoader::Initialize(factory);
1114
1115 bool cache_file_loaded = g_font_loader->LoadCacheFile();
1116
1117 // Arbitrary threshold to stop loading enormous number of fonts. Usual
1118 // side effect of loading large number of fonts results in renderer getting
1119 // killed as it appears to hang.
1120 const UINT32 kMaxFontThreshold = 1750;
1121 HRESULT hr = E_FAIL;
1122 if (cache_file_loaded ||
1123 g_font_loader->GetFontMapSize() < kMaxFontThreshold) {
1124 g_font_loader->EnableCollectionBuildingMode(true);
1125 hr = factory->CreateCustomFontCollection(
1126 g_font_loader.Get(), NULL, 0, g_font_collection.GetAddressOf());
1127 g_font_loader->UnloadCacheFile();
1128 g_font_loader->EnableCollectionBuildingMode(false);
1129 }
1130 bool loading_restricted = false;
1131 if (FAILED(hr) || !g_font_collection.Get()) {
1132 loading_restricted = true;
1133 // We will try here just one more time with restricted font set.
1134 g_font_loader->LoadRestrictedFontList();
1135 hr = factory->CreateCustomFontCollection(
1136 g_font_loader.Get(), NULL, 0, g_font_collection.GetAddressOf());
1137 }
1138
1139 base::TimeDelta time_delta = base::TimeTicks::Now() - start_tick;
1140 int64_t delta = time_delta.ToInternalValue();
1141 base::debug::Alias(&delta);
1142 UINT32 size = g_font_loader->GetFontMapSize();
1143 base::debug::Alias(&size);
1144 base::debug::Alias(&loading_restricted);
1145
1146 CHECK(SUCCEEDED(hr));
1147 CHECK(g_font_collection.Get() != NULL);
1148
1149 if (cache_file_loaded)
1150 UMA_HISTOGRAM_TIMES("DirectWrite.Fonts.LoadTime.Cached", time_delta);
1151 else
1152 UMA_HISTOGRAM_TIMES("DirectWrite.Fonts.LoadTime", time_delta);
1153
1154 base::debug::ClearCrashKey(kFontKeyName);
1155
1156 return g_font_collection.Get();
1157 }
1158
1159 bool BuildFontCacheInternal(const WCHAR* file_name) {
1160 typedef decltype(DWriteCreateFactory)* DWriteCreateFactoryProc;
1161 HMODULE dwrite_dll = LoadLibraryW(L"dwrite.dll");
1162 if (!dwrite_dll) {
1163 DWORD load_library_get_last_error = GetLastError();
1164 base::debug::Alias(&dwrite_dll);
1165 base::debug::Alias(&load_library_get_last_error);
1166 CHECK(false);
1167 }
1168
1169 DWriteCreateFactoryProc dwrite_create_factory_proc =
1170 reinterpret_cast<DWriteCreateFactoryProc>(
1171 GetProcAddress(dwrite_dll, "DWriteCreateFactory"));
1172
1173 if (!dwrite_create_factory_proc) {
1174 DWORD get_proc_address_get_last_error = GetLastError();
1175 base::debug::Alias(&dwrite_create_factory_proc);
1176 base::debug::Alias(&get_proc_address_get_last_error);
1177 CHECK(false);
1178 }
1179
1180 mswr::ComPtr<IDWriteFactory> factory;
1181
1182 CHECK(SUCCEEDED(
1183 dwrite_create_factory_proc(
1184 DWRITE_FACTORY_TYPE_ISOLATED,
1185 __uuidof(IDWriteFactory),
1186 reinterpret_cast<IUnknown**>(factory.GetAddressOf()))));
1187
1188 base::TimeTicks start_tick = base::TimeTicks::Now();
1189
1190 FontCollectionLoader::Initialize(factory.Get());
1191
1192 g_font_loader->EnterStaticCacheMode(file_name);
1193
1194 mswr::ComPtr<IDWriteFontCollection> font_collection;
1195
1196 HRESULT hr = E_FAIL;
1197 g_font_loader->EnableCollectionBuildingMode(true);
1198 hr = factory->CreateCustomFontCollection(
1199 g_font_loader.Get(), NULL, 0, font_collection.GetAddressOf());
1200 g_font_loader->EnableCollectionBuildingMode(false);
1201
1202 bool loading_restricted = false;
1203 if (FAILED(hr) || !font_collection.Get()) {
1204 loading_restricted = true;
1205 // We will try here just one more time with restricted font set.
1206 g_font_loader->LoadRestrictedFontList();
1207 hr = factory->CreateCustomFontCollection(
1208 g_font_loader.Get(), NULL, 0, font_collection.GetAddressOf());
1209 }
1210
1211 g_font_loader->LeaveStaticCacheMode();
1212
1213 base::TimeDelta time_delta = base::TimeTicks::Now() - start_tick;
1214 int64_t delta = time_delta.ToInternalValue();
1215 base::debug::Alias(&delta);
1216 UINT32 size = g_font_loader->GetFontMapSize();
1217 base::debug::Alias(&size);
1218 base::debug::Alias(&loading_restricted);
1219
1220 CHECK(SUCCEEDED(hr));
1221 CHECK(font_collection.Get() != NULL);
1222
1223 base::debug::ClearCrashKey(kFontKeyName);
1224
1225 return true;
1226 }
1227
1228 bool ValidateFontCacheFile(base::File* file) {
1229 DCHECK(file != NULL);
1230 CacheFileHeader file_header;
1231 if (file->Read(0, reinterpret_cast<char*>(&file_header), sizeof(file_header))
1232 == -1) {
1233 return false;
1234 }
1235 return ValidateFontCacheHeader(&file_header);
1236 }
1237
1238 bool LoadFontCache(const base::FilePath& path) {
1239 scoped_ptr<base::File> file(new base::File(path,
1240 base::File::FLAG_OPEN | base::File::FLAG_READ));
1241 if (!file->IsValid())
1242 return false;
1243
1244 if (!ValidateFontCacheFile(file.get()))
1245 return false;
1246
1247 base::string16 name(base::ASCIIToUTF16(content::kFontCacheSharedSectionName));
1248 name.append(base::UintToString16(base::GetCurrentProcId()));
1249 HANDLE mapping = ::CreateFileMapping(
1250 file->GetPlatformFile(),
1251 NULL,
1252 PAGE_READONLY,
1253 0,
1254 0,
1255 name.c_str());
1256 if (mapping == INVALID_HANDLE_VALUE)
1257 return false;
1258
1259 if (::GetLastError() == ERROR_ALREADY_EXISTS) {
1260 CloseHandle(mapping);
1261 // We crash here, as no one should have created this mapping except Chrome.
1262 CHECK(false);
1263 return false;
1264 }
1265
1266 DCHECK(!g_shared_font_cache.IsValid());
1267 g_shared_font_cache.Set(mapping);
1268
1269 return true;
1270 }
1271
1272 bool BuildFontCache(const base::FilePath& file) {
1273 return BuildFontCacheInternal(file.value().c_str());
1274 }
1275
1276 bool ShouldUseDirectWriteFontProxyFieldTrial() {
1277 return base::StartsWith(
1278 base::FieldTrialList::FindFullName("DirectWriteFontProxy"),
1279 "UseDirectWriteFontProxy", base::CompareCase::SENSITIVE);
1280 }
1281
1282 } // namespace content
OLDNEW
« no previous file with comments | « content/child/font_warmup_win.cc ('k') | content/common/dwrite_font_platform_win_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698