OLD | NEW |
---|---|
(Empty) | |
1 // Copyright 2016 The Chromium Authors. All rights reserved. | |
Sami
2017/05/12 16:35:52
++year
altimin
2017/05/12 17:39:10
Done.
| |
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 "headless/public/util/fontconfig.h" | |
6 | |
7 #include <dirent.h> | |
8 #include <fontconfig/fontconfig.h> | |
9 #include <freetype/freetype.h> | |
10 #include <ft2build.h> | |
11 #include <set> | |
12 #include <string> | |
13 | |
14 #include "base/logging.h" | |
15 | |
16 namespace headless { | |
17 namespace { | |
18 void GetFontFileNames(const FcFontSet* font_set, | |
19 std::set<std::string>* file_names) { | |
20 if (font_set == NULL) | |
21 return; | |
22 for (int i = 0; i < font_set->nfont; ++i) { | |
23 FcPattern* pattern = font_set->fonts[i]; | |
24 FcValue font_file; | |
25 if (FcPatternGet(pattern, "file", 0, &font_file) == FcResultMatch) { | |
26 file_names->insert(reinterpret_cast<const char*>(font_file.u.s)); | |
27 } else { | |
28 VLOG(1) << "Failed to find filename."; | |
29 FcPatternPrint(pattern); | |
30 } | |
31 } | |
32 } | |
33 FcConfig* g_config = nullptr; | |
34 } // namespace | |
35 | |
36 void InitFonts(const char* fontconfig_path) { | |
37 // The following is roughly equivalent to calling FcInit(). We jump through | |
38 // a bunch of hoops here to avoid using fontconfig's directory scanning | |
39 // logic. The problem with fontconfig is that it follows symlinks when doing | |
40 // recursive directory scans. | |
41 // | |
42 // The approach below ignores any <dir>...</dir> entries in fonts.conf. This | |
43 // is deliberate. Specifying dirs is problematic because they're either | |
44 // absolute or relative to our process's current working directory which | |
45 // could be anything. Instead we assume that all font files will be in the | |
46 // same directory as fonts.conf. We'll scan + load them here. | |
47 FcConfig* config = FcConfigCreate(); | |
48 g_config = config; | |
49 CHECK(config); | |
50 | |
51 // FcConfigParseAndLoad is a seriously goofy function. Depending on whether | |
52 // name passed in begins with a slash, it will treat it either as a file name | |
53 // to be found in the directory where it expects to find the font | |
54 // configuration OR it will will treat it as a directory where it expects to | |
55 // find fonts.conf. The latter behavior is the one we want. Passing | |
56 // fontconfig_path via the environment is a quick and dirty way to get | |
57 // uniform behavior regardless whether it's a relative path or not. | |
58 setenv("FONTCONFIG_PATH", fontconfig_path, 1); | |
59 CHECK(FcConfigParseAndLoad(config, nullptr, FcTrue)) | |
60 << "Failed to load font configuration. FONTCONFIG_PATH=" | |
61 << fontconfig_path; | |
62 | |
63 DIR* fc_dir = opendir(fontconfig_path); | |
64 CHECK(fc_dir) << "Failed to open font directory " << fontconfig_path << ": " | |
65 << strerror(errno); | |
66 | |
67 // The fonts must be loaded in a consistent order. This makes the rendered | |
Sami
2017/05/12 16:35:52
rendered?
altimin
2017/05/12 17:39:10
Done.
| |
68 // results stable across runs, otherwise replacement font picks are random | |
69 // and cause flakiness. | |
70 std::set<std::string> fonts; | |
71 struct dirent entry, *result; | |
72 while (readdir_r(fc_dir, &entry, &result) == 0 && result != NULL) { | |
73 fonts.insert(result->d_name); | |
74 } | |
75 for (const std::string& font : fonts) { | |
76 const std::string full_path = fontconfig_path + ("/" + font); | |
77 struct stat statbuf; | |
78 CHECK_EQ(0, stat(full_path.c_str(), &statbuf)) | |
79 << "Failed to stat " << full_path << ": " << strerror(errno); | |
80 if (S_ISREG(statbuf.st_mode)) { | |
81 // FcConfigAppFontAddFile will silently ignore non-fonts. | |
82 FcConfigAppFontAddFile( | |
83 config, reinterpret_cast<const FcChar8*>(full_path.c_str())); | |
84 } | |
85 } | |
86 closedir(fc_dir); | |
87 CHECK(FcConfigSetCurrent(config)); | |
88 | |
89 // Retrieve font from both of fontconfig's font sets for pre-loading. | |
90 std::set<std::string> font_files; | |
91 GetFontFileNames(FcConfigGetFonts(NULL, FcSetSystem), &font_files); | |
92 GetFontFileNames(FcConfigGetFonts(NULL, FcSetApplication), &font_files); | |
93 CHECK_GT(font_files.size(), 0u) | |
94 << "Font configuration doesn't contain any fonts!"; | |
95 | |
96 // Get freetype to load every font file we know about. This will cause the | |
97 // font files to get cached in memory. Once that's done we shouldn't have to | |
98 // access the file system for fonts at all. | |
99 FT_Library library; | |
100 FT_Init_FreeType(&library); | |
101 for (std::set<std::string>::const_iterator iter = font_files.begin(); | |
102 iter != font_files.end(); ++iter) { | |
103 FT_Face face; | |
104 CHECK_EQ(0, FT_New_Face(library, iter->c_str(), 0, &face)) | |
105 << "Failed to load font face: " << *iter; | |
106 FT_Done_Face(face); | |
107 } | |
108 FT_Done_FreeType(library); // Cached stuff will stick around... ? | |
109 } | |
110 | |
111 void ReleaseFonts() { | |
112 CHECK(g_config); | |
113 FcConfigDestroy(g_config); | |
114 FcFini(); | |
115 } | |
116 | |
117 } // namespace headless | |
OLD | NEW |