OLD | NEW |
---|---|
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 Loading... | |
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 Loading... | |
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 } |
OLD | NEW |