Chromium Code Reviews| 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 |