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

Side by Side Diff: skia/ext/SkFontHost_fontconfig_direct.cpp

Issue 668127: linux: handle basic metric-compatibile font fallback (Closed)
Patch Set: wrap Created 10 years, 9 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 | « skia/ext/SkFontHost_fontconfig_direct.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 /* libs/graphics/ports/SkFontHost_fontconfig_direct.cpp 1 /* libs/graphics/ports/SkFontHost_fontconfig_direct.cpp
2 ** 2 **
3 ** Copyright 2009, Google Inc. 3 ** Copyright 2009, Google Inc.
4 ** 4 **
5 ** Licensed under the Apache License, Version 2.0 (the "License"); 5 ** Licensed under the Apache License, Version 2.0 (the "License");
6 ** you may not use this file except in compliance with the License. 6 ** you may not use this file except in compliance with the License.
7 ** You may obtain a copy of the License at 7 ** You may obtain a copy of the License at
8 ** 8 **
9 ** http://www.apache.org/licenses/LICENSE-2.0 9 ** http://www.apache.org/licenses/LICENSE-2.0
10 ** 10 **
11 ** Unless required by applicable law or agreed to in writing, software 11 ** Unless required by applicable law or agreed to in writing, software
12 ** distributed under the License is distributed on an "AS IS" BASIS, 12 ** distributed under the License is distributed on an "AS IS" BASIS,
13 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 ** See the License for the specific language governing permissions and 14 ** See the License for the specific language governing permissions and
15 ** limitations under the License. 15 ** limitations under the License.
16 */ 16 */
17 17
18 #include "SkFontHost_fontconfig_direct.h" 18 #include "SkFontHost_fontconfig_direct.h"
19 19
20 #include <unistd.h> 20 #include <unistd.h>
21 #include <fcntl.h> 21 #include <fcntl.h>
22 22
23 #include <fontconfig/fontconfig.h> 23 #include <fontconfig/fontconfig.h>
24 24
25 FontConfigDirect::FontConfigDirect() 25 FontConfigDirect::FontConfigDirect()
26 : next_file_id_(0) { 26 : next_file_id_(0) {
27 FcInit(); 27 FcInit();
28 } 28 }
29 29
30 bool FontConfigDirect::IsMetricCompatibleReplacement(const char* font_a,
31 const char* font_b)
32 {
33 // It would be nice for fontconfig to tell us whether a given suggested
34 // replacement is a "strong" match (that is, an equivalent font) or
35 // a "weak" match (that is, fontconfig's next-best attempt at finding a
36 // substitute). However, I played around with the fontconfig API for
37 // a good few hours and could not make it reveal this information.
38 //
39 // So instead, we hardcode. These are from
40 // /etc/fonts/conf.d/30-metric-aliases.conf on my Ubuntu Karmic
41 // system.
42
43 // We represent the data with a table. Two names with the same
44 // id are in the same class.
45 struct FontEquivClass {
46 char id;
47 const char name[20];
48 };
49 static const FontEquivClass kFontEquivClasses[] = {
50 { 0, "Arial" },
51 { 0, "Liberation Sans" },
52 { 0, "Albany" },
53 { 0, "Albany Amt" },
54
55 { 1, "Times New Roman" },
56 { 1, "Liberation Serif" },
57 { 1, "Thorndale" },
58 { 1, "Thorndale AMT" },
59
60 // Note that Liberation Mono doesn't much *look* like Courier New,
61 // but it's reportedly metric-compatible.
62 { 2, "Courier New" },
63 { 2, "Liberation Mono" },
64 { 2, "Cumberland" },
65 { 2, "Cumberland AMT" },
66
67 { 3, "Helvetica" },
68 { 3, "Nimbus Sans L" },
69
70 { 4, "Times" },
71 { 4, "Nimbus Roman No9 L" },
72
73 { 5, "Courier" },
74 { 5, "Nimbus Mono L" },
75 };
76 static const int kClassCount =
agl 2010/03/08 18:31:40 s/int/size_t/
77 sizeof(kFontEquivClasses)/sizeof(kFontEquivClasses[0]);
78
79 int class_a = -1;
80 for (size_t i = 0; i < kClassCount; ++i) {
81 if (strcasecmp(kFontEquivClasses[i].name, font_a) == 0) {
82 class_a = kFontEquivClasses[i].id;
83 break;
84 }
85 }
86 if (class_a == -1)
87 return false;
88
89 int class_b = -1;
90 for (size_t i = 0; i < kClassCount; ++i) {
91 if (strcasecmp(kFontEquivClasses[i].name, font_b) == 0) {
92 class_b = kFontEquivClasses[i].id;
93 break;
94 }
95 }
96
97 return class_a == class_b;
98 }
99
30 // ----------------------------------------------------------------------------- 100 // -----------------------------------------------------------------------------
31 // Normally we only return exactly the font asked for. In last-resort cases, 101 // Normally we only return exactly the font asked for. In last-resort cases,
32 // the request is for one of the basic font names "Sans", "Serif" or 102 // the request is for one of the basic font names "Sans", "Serif" or
33 // "Monospace". This function tells you whether a given request is for such a 103 // "Monospace". This function tells you whether a given request is for such a
34 // fallback. 104 // fallback.
35 // ----------------------------------------------------------------------------- 105 // -----------------------------------------------------------------------------
36 static bool IsFallbackFontAllowed(const std::string& family) 106 static bool IsFallbackFontAllowed(const std::string& family)
37 { 107 {
38 const char* family_cstr = family.c_str(); 108 const char* family_cstr = family.c_str();
39 return strcasecmp(family_cstr, "sans") == 0 || 109 return strcasecmp(family_cstr, "sans") == 0 ||
40 strcasecmp(family_cstr, "serif") == 0 || 110 strcasecmp(family_cstr, "serif") == 0 ||
41 strcasecmp(family_cstr, "monospace") == 0 || 111 strcasecmp(family_cstr, "monospace") == 0 ||
42 // This is a special case used for a layout test 112 // This is a special case used for a layout test
43 strcasecmp(family_cstr, "NonAntiAliasedSans") == 0; 113 strcasecmp(family_cstr, "NonAntiAliasedSans") == 0;
44 } 114 }
45 115
46 bool FontConfigDirect::Match(std::string* result_family, 116 bool FontConfigDirect::Match(std::string* result_family,
47 unsigned* result_fileid, 117 unsigned* result_fileid,
48 bool fileid_valid, unsigned fileid, 118 bool fileid_valid, unsigned fileid,
49 const std::string& family, bool* is_bold, 119 const std::string& family, bool* is_bold,
50 bool* is_italic) { 120 bool* is_italic) {
51 if (family.length() > kMaxFontFamilyLength) 121 if (family.length() > kMaxFontFamilyLength)
52 return false; 122 return false;
53 123
54 SkAutoMutexAcquire ac(mutex_); 124 SkAutoMutexAcquire ac(mutex_);
55 FcPattern* pattern = FcPatternCreate(); 125 FcPattern* pattern = FcPatternCreate();
56 126
57 FcValue fcvalue;
58 if (fileid_valid) { 127 if (fileid_valid) {
59 const std::map<unsigned, std::string>::const_iterator 128 const std::map<unsigned, std::string>::const_iterator
60 i = fileid_to_filename_.find(fileid); 129 i = fileid_to_filename_.find(fileid);
61 if (i == fileid_to_filename_.end()) { 130 if (i == fileid_to_filename_.end()) {
62 FcPatternDestroy(pattern); 131 FcPatternDestroy(pattern);
63 return false; 132 return false;
64 } 133 }
65 134
66 fcvalue.type = FcTypeString; 135 FcPatternAddString(pattern, FC_FILE, (FcChar8*) i->second.c_str());
67 fcvalue.u.s = (FcChar8*) i->second.c_str();
68 FcPatternAdd(pattern, FC_FILE, fcvalue, 0);
69 } 136 }
70 if (!family.empty()) { 137 if (!family.empty()) {
71 fcvalue.type = FcTypeString; 138 FcPatternAddString(pattern, FC_FAMILY, (FcChar8*) family.c_str());
72 fcvalue.u.s = (FcChar8*) family.c_str();
73 FcPatternAdd(pattern, FC_FAMILY, fcvalue, 0);
74 } 139 }
75 140
76 fcvalue.type = FcTypeInteger; 141 FcPatternAddInteger(pattern, FC_WEIGHT,
77 fcvalue.u.i = is_bold && *is_bold ? FC_WEIGHT_BOLD : FC_WEIGHT_NORMAL; 142 is_bold && *is_bold ? FC_WEIGHT_BOLD
78 FcPatternAdd(pattern, FC_WEIGHT, fcvalue, 0); 143 : FC_WEIGHT_NORMAL);
144 FcPatternAddInteger(pattern, FC_SLANT,
145 is_italic && *is_italic ? FC_SLANT_ITALIC
146 : FC_SLANT_ROMAN);
147 FcPatternAddBool(pattern, FC_SCALABLE, FcTrue);
79 148
80 fcvalue.type = FcTypeInteger; 149 FcConfigSubstitute(NULL, pattern, FcMatchPattern);
81 fcvalue.u.i = is_italic && *is_italic ? FC_SLANT_ITALIC : FC_SLANT_ROMAN;
82 FcPatternAdd(pattern, FC_SLANT, fcvalue, 0);
83
84 fcvalue.type = FcTypeBool;
85 fcvalue.u.b = FcTrue;
86 FcPatternAdd(pattern, FC_SCALABLE, fcvalue, 0);
87
88 FcConfigSubstitute(0, pattern, FcMatchPattern);
89 FcDefaultSubstitute(pattern); 150 FcDefaultSubstitute(pattern);
90 151
91 // Font matching: 152 // Font matching:
92 // CSS often specifies a fallback list of families: 153 // CSS often specifies a fallback list of families:
93 // font-family: a, b, c, serif; 154 // font-family: a, b, c, serif;
94 // However, fontconfig will always do its best to find *a* font when asked 155 // However, fontconfig will always do its best to find *a* font when asked
95 // for something so we need a way to tell if the match which it has found is 156 // for something so we need a way to tell if the match which it has found is
96 // "good enough" for us. Otherwise, we can return NULL which gets piped up 157 // "good enough" for us. Otherwise, we can return NULL which gets piped up
97 // and lets WebKit know to try the next CSS family name. However, fontconfig 158 // and lets WebKit know to try the next CSS family name. However, fontconfig
98 // configs allow substitutions (mapping "Arial -> Helvetica" etc) and we 159 // configs allow substitutions (mapping "Arial -> Helvetica" etc) and we
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after
151 break; 212 break;
152 } 213 }
153 214
154 if (!match) { 215 if (!match) {
155 FcPatternDestroy(pattern); 216 FcPatternDestroy(pattern);
156 FcFontSetDestroy(font_set); 217 FcFontSetDestroy(font_set);
157 return false; 218 return false;
158 } 219 }
159 220
160 if (!IsFallbackFontAllowed(family)) { 221 if (!IsFallbackFontAllowed(family)) {
161 bool family_names_match = false; 222 bool acceptable_substitute = false;
162 for (int id = 0; id < 255; ++id) { 223 for (int id = 0; id < 255; ++id) {
163 FcChar8* post_match_family; 224 FcChar8* post_match_family;
164 if (FcPatternGetString(match, FC_FAMILY, id, &post_match_family) != 225 if (FcPatternGetString(match, FC_FAMILY, id, &post_match_family) !=
165 FcResultMatch) 226 FcResultMatch)
166 break; 227 break;
167 family_names_match = 228 acceptable_substitute =
168 family.empty() ? 229 family.empty() ?
169 true : 230 true :
170 (strcasecmp((char *)post_config_family, 231 (strcasecmp((char *)post_config_family,
171 (char *)post_match_family) == 0 || 232 (char *)post_match_family) == 0 ||
172 // Workaround for Issue 12530: 233 // Workaround for Issue 12530:
173 // requested family: "Bitstream Vera Sans" 234 // requested family: "Bitstream Vera Sans"
174 // post_config_family: "Arial" 235 // post_config_family: "Arial"
175 // post_match_family: "Bitstream Vera Sans" 236 // post_match_family: "Bitstream Vera Sans"
176 // -> We should treat this case as a good match. 237 // -> We should treat this case as a good match.
177 strcasecmp(family.c_str(), 238 strcasecmp(family.c_str(),
178 (char *)post_match_family) == 0); 239 (char *)post_match_family) == 0) ||
179 if (family_names_match) 240 IsMetricCompatibleReplacement(family.c_str(),
241 (char*)post_match_family);
242 if (acceptable_substitute)
180 break; 243 break;
181 } 244 }
182 if (!family.empty() && !family_names_match) { 245 if (!acceptable_substitute) {
183 FcPatternDestroy(pattern); 246 FcPatternDestroy(pattern);
184 FcFontSetDestroy(font_set); 247 FcFontSetDestroy(font_set);
185 return false; 248 return false;
186 } 249 }
187 } 250 }
188 251
189 FcPatternDestroy(pattern); 252 FcPatternDestroy(pattern);
190 253
191 FcChar8* c_filename; 254 FcChar8* c_filename;
192 if (FcPatternGetString(match, FC_FILE, 0, &c_filename) != FcResultMatch) { 255 if (FcPatternGetString(match, FC_FILE, 0, &c_filename) != FcResultMatch) {
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after
255 318
256 int FontConfigDirect::Open(unsigned fileid) { 319 int FontConfigDirect::Open(unsigned fileid) {
257 SkAutoMutexAcquire ac(mutex_); 320 SkAutoMutexAcquire ac(mutex_);
258 const std::map<unsigned, std::string>::const_iterator 321 const std::map<unsigned, std::string>::const_iterator
259 i = fileid_to_filename_.find(fileid); 322 i = fileid_to_filename_.find(fileid);
260 if (i == fileid_to_filename_.end()) 323 if (i == fileid_to_filename_.end())
261 return -1; 324 return -1;
262 325
263 return open(i->second.c_str(), O_RDONLY); 326 return open(i->second.c_str(), O_RDONLY);
264 } 327 }
OLDNEW
« no previous file with comments | « skia/ext/SkFontHost_fontconfig_direct.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698