1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/gfx/skia/trunk/src/ports/SkFontConfigInterface_direct.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,736 @@ 1.4 +/* 1.5 + * Copyright 2009 Google Inc. 1.6 + * 1.7 + * Use of this source code is governed by a BSD-style license that can be 1.8 + * found in the LICENSE file. 1.9 + */ 1.10 + 1.11 +/* migrated from chrome/src/skia/ext/SkFontHost_fontconfig_direct.cpp */ 1.12 + 1.13 +#include <string> 1.14 +#include <unistd.h> 1.15 +#include <fcntl.h> 1.16 + 1.17 +#include <fontconfig/fontconfig.h> 1.18 + 1.19 +#include "SkBuffer.h" 1.20 +#include "SkFontConfigInterface.h" 1.21 +#include "SkStream.h" 1.22 + 1.23 +size_t SkFontConfigInterface::FontIdentity::writeToMemory(void* addr) const { 1.24 + size_t size = sizeof(fID) + sizeof(fTTCIndex); 1.25 + size += sizeof(int32_t) + sizeof(int32_t) + sizeof(uint8_t); // weight, width, italic 1.26 + size += sizeof(int32_t) + fString.size(); // store length+data 1.27 + if (addr) { 1.28 + SkWBuffer buffer(addr, size); 1.29 + 1.30 + buffer.write32(fID); 1.31 + buffer.write32(fTTCIndex); 1.32 + buffer.write32(fString.size()); 1.33 + buffer.write32(fStyle.weight()); 1.34 + buffer.write32(fStyle.width()); 1.35 + buffer.write8(fStyle.slant()); 1.36 + buffer.write(fString.c_str(), fString.size()); 1.37 + buffer.padToAlign4(); 1.38 + 1.39 + SkASSERT(buffer.pos() == size); 1.40 + } 1.41 + return size; 1.42 +} 1.43 + 1.44 +size_t SkFontConfigInterface::FontIdentity::readFromMemory(const void* addr, 1.45 + size_t size) { 1.46 + SkRBuffer buffer(addr, size); 1.47 + 1.48 + (void)buffer.readU32(&fID); 1.49 + (void)buffer.readS32(&fTTCIndex); 1.50 + uint32_t strLen, weight, width; 1.51 + (void)buffer.readU32(&strLen); 1.52 + (void)buffer.readU32(&weight); 1.53 + (void)buffer.readU32(&width); 1.54 + uint8_t u8; 1.55 + (void)buffer.readU8(&u8); 1.56 + SkFontStyle::Slant slant = (SkFontStyle::Slant)u8; 1.57 + fStyle = SkFontStyle(weight, width, slant); 1.58 + fString.resize(strLen); 1.59 + (void)buffer.read(fString.writable_str(), strLen); 1.60 + buffer.skipToAlign4(); 1.61 + 1.62 + return buffer.pos(); // the actual number of bytes read 1.63 +} 1.64 + 1.65 +#ifdef SK_DEBUG 1.66 +static void make_iden(SkFontConfigInterface::FontIdentity* iden) { 1.67 + iden->fID = 10; 1.68 + iden->fTTCIndex = 2; 1.69 + iden->fString.set("Hello world"); 1.70 + iden->fStyle = SkFontStyle(300, 6, SkFontStyle::kItalic_Slant); 1.71 +} 1.72 + 1.73 +static void test_writeToMemory(const SkFontConfigInterface::FontIdentity& iden0, 1.74 + int initValue) { 1.75 + SkFontConfigInterface::FontIdentity iden1; 1.76 + 1.77 + size_t size0 = iden0.writeToMemory(NULL); 1.78 + 1.79 + SkAutoMalloc storage(size0); 1.80 + memset(storage.get(), initValue, size0); 1.81 + 1.82 + size_t size1 = iden0.writeToMemory(storage.get()); 1.83 + SkASSERT(size0 == size1); 1.84 + 1.85 + SkASSERT(iden0 != iden1); 1.86 + size_t size2 = iden1.readFromMemory(storage.get(), size1); 1.87 + SkASSERT(size2 == size1); 1.88 + SkASSERT(iden0 == iden1); 1.89 +} 1.90 + 1.91 +static void fontconfiginterface_unittest() { 1.92 + SkFontConfigInterface::FontIdentity iden0, iden1; 1.93 + 1.94 + SkASSERT(iden0 == iden1); 1.95 + 1.96 + make_iden(&iden0); 1.97 + SkASSERT(iden0 != iden1); 1.98 + 1.99 + make_iden(&iden1); 1.100 + SkASSERT(iden0 == iden1); 1.101 + 1.102 + test_writeToMemory(iden0, 0); 1.103 + test_writeToMemory(iden0, 0); 1.104 +} 1.105 +#endif 1.106 + 1.107 +class SkFontConfigInterfaceDirect : public SkFontConfigInterface { 1.108 +public: 1.109 + SkFontConfigInterfaceDirect(); 1.110 + virtual ~SkFontConfigInterfaceDirect(); 1.111 + 1.112 + virtual bool matchFamilyName(const char familyName[], 1.113 + SkTypeface::Style requested, 1.114 + FontIdentity* outFontIdentifier, 1.115 + SkString* outFamilyName, 1.116 + SkTypeface::Style* outStyle) SK_OVERRIDE; 1.117 + virtual SkStream* openStream(const FontIdentity&) SK_OVERRIDE; 1.118 + 1.119 + // new APIs 1.120 + virtual SkDataTable* getFamilyNames() SK_OVERRIDE; 1.121 + virtual bool matchFamilySet(const char inFamilyName[], 1.122 + SkString* outFamilyName, 1.123 + SkTArray<FontIdentity>*) SK_OVERRIDE; 1.124 + 1.125 +private: 1.126 + SkMutex mutex_; 1.127 +}; 1.128 + 1.129 +SkFontConfigInterface* SkFontConfigInterface::GetSingletonDirectInterface() { 1.130 + static SkFontConfigInterface* gDirect; 1.131 + if (NULL == gDirect) { 1.132 + static SkMutex gMutex; 1.133 + SkAutoMutexAcquire ac(gMutex); 1.134 + 1.135 + if (NULL == gDirect) { 1.136 + gDirect = new SkFontConfigInterfaceDirect; 1.137 + } 1.138 + } 1.139 + return gDirect; 1.140 +} 1.141 + 1.142 +/////////////////////////////////////////////////////////////////////////////// 1.143 + 1.144 +// Returns the string from the pattern, or NULL 1.145 +static const char* get_name(FcPattern* pattern, const char field[], 1.146 + int index = 0) { 1.147 + const char* name; 1.148 + if (FcPatternGetString(pattern, field, index, 1.149 + (FcChar8**)&name) != FcResultMatch) { 1.150 + name = NULL; 1.151 + } 1.152 + return name; 1.153 +} 1.154 + 1.155 +/////////////////////////////////////////////////////////////////////////////// 1.156 + 1.157 +namespace { 1.158 + 1.159 +// Equivalence classes, used to match the Liberation and other fonts 1.160 +// with their metric-compatible replacements. See the discussion in 1.161 +// GetFontEquivClass(). 1.162 +enum FontEquivClass 1.163 +{ 1.164 + OTHER, 1.165 + SANS, 1.166 + SERIF, 1.167 + MONO, 1.168 + SYMBOL, 1.169 + PGOTHIC, 1.170 + GOTHIC, 1.171 + PMINCHO, 1.172 + MINCHO, 1.173 + SIMSUN, 1.174 + NSIMSUN, 1.175 + SIMHEI, 1.176 + PMINGLIU, 1.177 + MINGLIU, 1.178 + PMINGLIUHK, 1.179 + MINGLIUHK, 1.180 + CAMBRIA, 1.181 + CALIBRI, 1.182 +}; 1.183 + 1.184 +// Match the font name against a whilelist of fonts, returning the equivalence 1.185 +// class. 1.186 +FontEquivClass GetFontEquivClass(const char* fontname) 1.187 +{ 1.188 + // It would be nice for fontconfig to tell us whether a given suggested 1.189 + // replacement is a "strong" match (that is, an equivalent font) or 1.190 + // a "weak" match (that is, fontconfig's next-best attempt at finding a 1.191 + // substitute). However, I played around with the fontconfig API for 1.192 + // a good few hours and could not make it reveal this information. 1.193 + // 1.194 + // So instead, we hardcode. Initially this function emulated 1.195 + // /etc/fonts/conf.d/30-metric-aliases.conf 1.196 + // from my Ubuntu system, but we're better off being very conservative. 1.197 + 1.198 + // Arimo, Tinos and Cousine are a set of fonts metric-compatible with 1.199 + // Arial, Times New Roman and Courier New with a character repertoire 1.200 + // much larger than Liberation. Note that Cousine is metrically 1.201 + // compatible with Courier New, but the former is sans-serif while 1.202 + // the latter is serif. 1.203 + 1.204 + 1.205 + struct FontEquivMap { 1.206 + FontEquivClass clazz; 1.207 + const char name[40]; 1.208 + }; 1.209 + 1.210 + static const FontEquivMap kFontEquivMap[] = { 1.211 + { SANS, "Arial" }, 1.212 + { SANS, "Arimo" }, 1.213 + { SANS, "Liberation Sans" }, 1.214 + 1.215 + { SERIF, "Times New Roman" }, 1.216 + { SERIF, "Tinos" }, 1.217 + { SERIF, "Liberation Serif" }, 1.218 + 1.219 + { MONO, "Courier New" }, 1.220 + { MONO, "Cousine" }, 1.221 + { MONO, "Liberation Mono" }, 1.222 + 1.223 + { SYMBOL, "Symbol" }, 1.224 + { SYMBOL, "Symbol Neu" }, 1.225 + 1.226 + // MS Pゴシック 1.227 + { PGOTHIC, "MS PGothic" }, 1.228 + { PGOTHIC, "\xef\xbc\xad\xef\xbc\xb3 \xef\xbc\xb0" 1.229 + "\xe3\x82\xb4\xe3\x82\xb7\xe3\x83\x83\xe3\x82\xaf" }, 1.230 + { PGOTHIC, "IPAPGothic" }, 1.231 + { PGOTHIC, "MotoyaG04Gothic" }, 1.232 + 1.233 + // MS ゴシック 1.234 + { GOTHIC, "MS Gothic" }, 1.235 + { GOTHIC, "\xef\xbc\xad\xef\xbc\xb3 " 1.236 + "\xe3\x82\xb4\xe3\x82\xb7\xe3\x83\x83\xe3\x82\xaf" }, 1.237 + { GOTHIC, "IPAGothic" }, 1.238 + { GOTHIC, "MotoyaG04GothicMono" }, 1.239 + 1.240 + // MS P明朝 1.241 + { PMINCHO, "MS PMincho" }, 1.242 + { PMINCHO, "\xef\xbc\xad\xef\xbc\xb3 \xef\xbc\xb0" 1.243 + "\xe6\x98\x8e\xe6\x9c\x9d"}, 1.244 + { PMINCHO, "IPAPMincho" }, 1.245 + { PMINCHO, "MotoyaG04Mincho" }, 1.246 + 1.247 + // MS 明朝 1.248 + { MINCHO, "MS Mincho" }, 1.249 + { MINCHO, "\xef\xbc\xad\xef\xbc\xb3 \xe6\x98\x8e\xe6\x9c\x9d" }, 1.250 + { MINCHO, "IPAMincho" }, 1.251 + { MINCHO, "MotoyaG04MinchoMono" }, 1.252 + 1.253 + // 宋体 1.254 + { SIMSUN, "Simsun" }, 1.255 + { SIMSUN, "\xe5\xae\x8b\xe4\xbd\x93" }, 1.256 + { SIMSUN, "MSung GB18030" }, 1.257 + { SIMSUN, "Song ASC" }, 1.258 + 1.259 + // 新宋体 1.260 + { NSIMSUN, "NSimsun" }, 1.261 + { NSIMSUN, "\xe6\x96\xb0\xe5\xae\x8b\xe4\xbd\x93" }, 1.262 + { NSIMSUN, "MSung GB18030" }, 1.263 + { NSIMSUN, "N Song ASC" }, 1.264 + 1.265 + // 黑体 1.266 + { SIMHEI, "Simhei" }, 1.267 + { SIMHEI, "\xe9\xbb\x91\xe4\xbd\x93" }, 1.268 + { SIMHEI, "MYingHeiGB18030" }, 1.269 + { SIMHEI, "MYingHeiB5HK" }, 1.270 + 1.271 + // 新細明體 1.272 + { PMINGLIU, "PMingLiU"}, 1.273 + { PMINGLIU, "\xe6\x96\xb0\xe7\xb4\xb0\xe6\x98\x8e\xe9\xab\x94" }, 1.274 + { PMINGLIU, "MSung B5HK"}, 1.275 + 1.276 + // 細明體 1.277 + { MINGLIU, "MingLiU"}, 1.278 + { MINGLIU, "\xe7\xb4\xb0\xe6\x98\x8e\xe9\xab\x94" }, 1.279 + { MINGLIU, "MSung B5HK"}, 1.280 + 1.281 + // 新細明體 1.282 + { PMINGLIUHK, "PMingLiU_HKSCS"}, 1.283 + { PMINGLIUHK, "\xe6\x96\xb0\xe7\xb4\xb0\xe6\x98\x8e\xe9\xab\x94_HKSCS" }, 1.284 + { PMINGLIUHK, "MSung B5HK"}, 1.285 + 1.286 + // 細明體 1.287 + { MINGLIUHK, "MingLiU_HKSCS"}, 1.288 + { MINGLIUHK, "\xe7\xb4\xb0\xe6\x98\x8e\xe9\xab\x94_HKSCS" }, 1.289 + { MINGLIUHK, "MSung B5HK"}, 1.290 + 1.291 + // Cambria 1.292 + { CAMBRIA, "Cambria" }, 1.293 + { CAMBRIA, "Caladea" }, 1.294 + 1.295 + // Calibri 1.296 + { CALIBRI, "Calibri" }, 1.297 + { CALIBRI, "Carlito" }, 1.298 + }; 1.299 + 1.300 + static const size_t kFontCount = 1.301 + sizeof(kFontEquivMap)/sizeof(kFontEquivMap[0]); 1.302 + 1.303 + // TODO(jungshik): If this loop turns out to be hot, turn 1.304 + // the array to a static (hash)map to speed it up. 1.305 + for (size_t i = 0; i < kFontCount; ++i) { 1.306 + if (strcasecmp(kFontEquivMap[i].name, fontname) == 0) 1.307 + return kFontEquivMap[i].clazz; 1.308 + } 1.309 + return OTHER; 1.310 +} 1.311 + 1.312 + 1.313 +// Return true if |font_a| and |font_b| are visually and at the metrics 1.314 +// level interchangeable. 1.315 +bool IsMetricCompatibleReplacement(const char* font_a, const char* font_b) 1.316 +{ 1.317 + FontEquivClass class_a = GetFontEquivClass(font_a); 1.318 + FontEquivClass class_b = GetFontEquivClass(font_b); 1.319 + 1.320 + return class_a != OTHER && class_a == class_b; 1.321 +} 1.322 + 1.323 +// Normally we only return exactly the font asked for. In last-resort 1.324 +// cases, the request either doesn't specify a font or is one of the 1.325 +// basic font names like "Sans", "Serif" or "Monospace". This function 1.326 +// tells you whether a given request is for such a fallback. 1.327 +bool IsFallbackFontAllowed(const std::string& family) { 1.328 + const char* family_cstr = family.c_str(); 1.329 + return family.empty() || 1.330 + strcasecmp(family_cstr, "sans") == 0 || 1.331 + strcasecmp(family_cstr, "serif") == 0 || 1.332 + strcasecmp(family_cstr, "monospace") == 0; 1.333 +} 1.334 + 1.335 +static bool valid_pattern(FcPattern* pattern) { 1.336 +#ifdef SK_FONT_CONFIG_ONLY_ALLOW_SCALABLE_FONTS 1.337 + FcBool is_scalable; 1.338 + if (FcPatternGetBool(pattern, FC_SCALABLE, 0, &is_scalable) != FcResultMatch 1.339 + || !is_scalable) { 1.340 + return false; 1.341 + } 1.342 +#endif 1.343 + 1.344 + // fontconfig can also return fonts which are unreadable 1.345 + const char* c_filename = get_name(pattern, FC_FILE); 1.346 + if (!c_filename) { 1.347 + return false; 1.348 + } 1.349 + if (access(c_filename, R_OK) != 0) { 1.350 + return false; 1.351 + } 1.352 + return true; 1.353 +} 1.354 + 1.355 +// Find matching font from |font_set| for the given font family. 1.356 +FcPattern* MatchFont(FcFontSet* font_set, 1.357 + const char* post_config_family, 1.358 + const std::string& family) { 1.359 + // Older versions of fontconfig have a bug where they cannot select 1.360 + // only scalable fonts so we have to manually filter the results. 1.361 + FcPattern* match = NULL; 1.362 + for (int i = 0; i < font_set->nfont; ++i) { 1.363 + FcPattern* current = font_set->fonts[i]; 1.364 + if (valid_pattern(current)) { 1.365 + match = current; 1.366 + break; 1.367 + } 1.368 + } 1.369 + 1.370 + if (match && !IsFallbackFontAllowed(family)) { 1.371 + bool acceptable_substitute = false; 1.372 + for (int id = 0; id < 255; ++id) { 1.373 + const char* post_match_family = get_name(match, FC_FAMILY, id); 1.374 + if (!post_match_family) 1.375 + break; 1.376 + acceptable_substitute = 1.377 + (strcasecmp(post_config_family, post_match_family) == 0 || 1.378 + // Workaround for Issue 12530: 1.379 + // requested family: "Bitstream Vera Sans" 1.380 + // post_config_family: "Arial" 1.381 + // post_match_family: "Bitstream Vera Sans" 1.382 + // -> We should treat this case as a good match. 1.383 + strcasecmp(family.c_str(), post_match_family) == 0) || 1.384 + IsMetricCompatibleReplacement(family.c_str(), post_match_family); 1.385 + if (acceptable_substitute) 1.386 + break; 1.387 + } 1.388 + if (!acceptable_substitute) 1.389 + return NULL; 1.390 + } 1.391 + 1.392 + return match; 1.393 +} 1.394 + 1.395 +// Retrieves |is_bold|, |is_italic| and |font_family| properties from |font|. 1.396 +SkTypeface::Style GetFontStyle(FcPattern* font) { 1.397 + int resulting_bold; 1.398 + if (FcPatternGetInteger(font, FC_WEIGHT, 0, &resulting_bold)) 1.399 + resulting_bold = FC_WEIGHT_NORMAL; 1.400 + 1.401 + int resulting_italic; 1.402 + if (FcPatternGetInteger(font, FC_SLANT, 0, &resulting_italic)) 1.403 + resulting_italic = FC_SLANT_ROMAN; 1.404 + 1.405 + // If we ask for an italic font, fontconfig might take a roman font and set 1.406 + // the undocumented property FC_MATRIX to a skew matrix. It'll then say 1.407 + // that the font is italic or oblique. So, if we see a matrix, we don't 1.408 + // believe that it's italic. 1.409 + FcValue matrix; 1.410 + const bool have_matrix = FcPatternGet(font, FC_MATRIX, 0, &matrix) == 0; 1.411 + 1.412 + // If we ask for an italic font, fontconfig might take a roman font and set 1.413 + // FC_EMBOLDEN. 1.414 + FcValue embolden; 1.415 + const bool have_embolden = FcPatternGet(font, FC_EMBOLDEN, 0, &embolden) == 0; 1.416 + 1.417 + int styleBits = 0; 1.418 + if (resulting_bold > FC_WEIGHT_MEDIUM && !have_embolden) { 1.419 + styleBits |= SkTypeface::kBold; 1.420 + } 1.421 + if (resulting_italic > FC_SLANT_ROMAN && !have_matrix) { 1.422 + styleBits |= SkTypeface::kItalic; 1.423 + } 1.424 + 1.425 + return (SkTypeface::Style)styleBits; 1.426 +} 1.427 + 1.428 +} // anonymous namespace 1.429 + 1.430 +/////////////////////////////////////////////////////////////////////////////// 1.431 + 1.432 +#define kMaxFontFamilyLength 2048 1.433 + 1.434 +SkFontConfigInterfaceDirect::SkFontConfigInterfaceDirect() { 1.435 + SkAutoMutexAcquire ac(mutex_); 1.436 + 1.437 + FcInit(); 1.438 + 1.439 + SkDEBUGCODE(fontconfiginterface_unittest();) 1.440 +} 1.441 + 1.442 +SkFontConfigInterfaceDirect::~SkFontConfigInterfaceDirect() { 1.443 +} 1.444 + 1.445 +bool SkFontConfigInterfaceDirect::matchFamilyName(const char familyName[], 1.446 + SkTypeface::Style style, 1.447 + FontIdentity* outIdentity, 1.448 + SkString* outFamilyName, 1.449 + SkTypeface::Style* outStyle) { 1.450 + std::string familyStr(familyName ? familyName : ""); 1.451 + if (familyStr.length() > kMaxFontFamilyLength) { 1.452 + return false; 1.453 + } 1.454 + 1.455 + SkAutoMutexAcquire ac(mutex_); 1.456 + 1.457 + FcPattern* pattern = FcPatternCreate(); 1.458 + 1.459 + if (familyName) { 1.460 + FcPatternAddString(pattern, FC_FAMILY, (FcChar8*)familyName); 1.461 + } 1.462 + FcPatternAddInteger(pattern, FC_WEIGHT, 1.463 + (style & SkTypeface::kBold) ? FC_WEIGHT_BOLD 1.464 + : FC_WEIGHT_NORMAL); 1.465 + FcPatternAddInteger(pattern, FC_SLANT, 1.466 + (style & SkTypeface::kItalic) ? FC_SLANT_ITALIC 1.467 + : FC_SLANT_ROMAN); 1.468 + FcPatternAddBool(pattern, FC_SCALABLE, FcTrue); 1.469 + 1.470 + FcConfigSubstitute(NULL, pattern, FcMatchPattern); 1.471 + FcDefaultSubstitute(pattern); 1.472 + 1.473 + // Font matching: 1.474 + // CSS often specifies a fallback list of families: 1.475 + // font-family: a, b, c, serif; 1.476 + // However, fontconfig will always do its best to find *a* font when asked 1.477 + // for something so we need a way to tell if the match which it has found is 1.478 + // "good enough" for us. Otherwise, we can return NULL which gets piped up 1.479 + // and lets WebKit know to try the next CSS family name. However, fontconfig 1.480 + // configs allow substitutions (mapping "Arial -> Helvetica" etc) and we 1.481 + // wish to support that. 1.482 + // 1.483 + // Thus, if a specific family is requested we set @family_requested. Then we 1.484 + // record two strings: the family name after config processing and the 1.485 + // family name after resolving. If the two are equal, it's a good match. 1.486 + // 1.487 + // So consider the case where a user has mapped Arial to Helvetica in their 1.488 + // config. 1.489 + // requested family: "Arial" 1.490 + // post_config_family: "Helvetica" 1.491 + // post_match_family: "Helvetica" 1.492 + // -> good match 1.493 + // 1.494 + // and for a missing font: 1.495 + // requested family: "Monaco" 1.496 + // post_config_family: "Monaco" 1.497 + // post_match_family: "Times New Roman" 1.498 + // -> BAD match 1.499 + // 1.500 + // However, we special-case fallback fonts; see IsFallbackFontAllowed(). 1.501 + 1.502 + const char* post_config_family = get_name(pattern, FC_FAMILY); 1.503 + if (!post_config_family) { 1.504 + // we can just continue with an empty name, e.g. default font 1.505 + post_config_family = ""; 1.506 + } 1.507 + 1.508 + FcResult result; 1.509 + FcFontSet* font_set = FcFontSort(0, pattern, 0, 0, &result); 1.510 + if (!font_set) { 1.511 + FcPatternDestroy(pattern); 1.512 + return false; 1.513 + } 1.514 + 1.515 + FcPattern* match = MatchFont(font_set, post_config_family, familyStr); 1.516 + if (!match) { 1.517 + FcPatternDestroy(pattern); 1.518 + FcFontSetDestroy(font_set); 1.519 + return false; 1.520 + } 1.521 + 1.522 + FcPatternDestroy(pattern); 1.523 + 1.524 + // From here out we just extract our results from 'match' 1.525 + 1.526 + post_config_family = get_name(match, FC_FAMILY); 1.527 + if (!post_config_family) { 1.528 + FcFontSetDestroy(font_set); 1.529 + return false; 1.530 + } 1.531 + 1.532 + const char* c_filename = get_name(match, FC_FILE); 1.533 + if (!c_filename) { 1.534 + FcFontSetDestroy(font_set); 1.535 + return false; 1.536 + } 1.537 + 1.538 + int face_index; 1.539 + if (FcPatternGetInteger(match, FC_INDEX, 0, &face_index) != FcResultMatch) { 1.540 + FcFontSetDestroy(font_set); 1.541 + return false; 1.542 + } 1.543 + 1.544 + FcFontSetDestroy(font_set); 1.545 + 1.546 + if (outIdentity) { 1.547 + outIdentity->fTTCIndex = face_index; 1.548 + outIdentity->fString.set(c_filename); 1.549 + } 1.550 + if (outFamilyName) { 1.551 + outFamilyName->set(post_config_family); 1.552 + } 1.553 + if (outStyle) { 1.554 + *outStyle = GetFontStyle(match); 1.555 + } 1.556 + return true; 1.557 +} 1.558 + 1.559 +SkStream* SkFontConfigInterfaceDirect::openStream(const FontIdentity& identity) { 1.560 + return SkStream::NewFromFile(identity.fString.c_str()); 1.561 +} 1.562 + 1.563 +/////////////////////////////////////////////////////////////////////////////// 1.564 + 1.565 +static bool find_name(const SkTDArray<const char*>& list, const char* str) { 1.566 + int count = list.count(); 1.567 + for (int i = 0; i < count; ++i) { 1.568 + if (!strcmp(list[i], str)) { 1.569 + return true; 1.570 + } 1.571 + } 1.572 + return false; 1.573 +} 1.574 + 1.575 +SkDataTable* SkFontConfigInterfaceDirect::getFamilyNames() { 1.576 + SkAutoMutexAcquire ac(mutex_); 1.577 + 1.578 + FcPattern* pat = FcPatternCreate(); 1.579 + SkAutoTCallVProc<FcPattern, FcPatternDestroy> autoDestroyPat(pat); 1.580 + if (NULL == pat) { 1.581 + return NULL; 1.582 + } 1.583 + 1.584 + FcObjectSet* os = FcObjectSetBuild(FC_FAMILY, (char *)0); 1.585 + SkAutoTCallVProc<FcObjectSet, FcObjectSetDestroy> autoDestroyOs(os); 1.586 + if (NULL == os) { 1.587 + return NULL; 1.588 + } 1.589 + 1.590 + FcFontSet* fs = FcFontList(NULL, pat, os); 1.591 + SkAutoTCallVProc<FcFontSet, FcFontSetDestroy> autoDestroyFs(fs); 1.592 + if (NULL == fs) { 1.593 + return NULL; 1.594 + } 1.595 + 1.596 + SkTDArray<const char*> names; 1.597 + SkTDArray<size_t> sizes; 1.598 + for (int i = 0; i < fs->nfont; ++i) { 1.599 + FcPattern* match = fs->fonts[i]; 1.600 + const char* famName = get_name(match, FC_FAMILY); 1.601 + if (famName && !find_name(names, famName)) { 1.602 + *names.append() = famName; 1.603 + *sizes.append() = strlen(famName) + 1; 1.604 + } 1.605 + } 1.606 + 1.607 + return SkDataTable::NewCopyArrays((const void*const*)names.begin(), 1.608 + sizes.begin(), names.count()); 1.609 +} 1.610 + 1.611 +bool SkFontConfigInterfaceDirect::matchFamilySet(const char inFamilyName[], 1.612 + SkString* outFamilyName, 1.613 + SkTArray<FontIdentity>* ids) { 1.614 + SkAutoMutexAcquire ac(mutex_); 1.615 + 1.616 +#if 0 1.617 + std::string familyStr(familyName ? familyName : ""); 1.618 + if (familyStr.length() > kMaxFontFamilyLength) { 1.619 + return false; 1.620 + } 1.621 + 1.622 + SkAutoMutexAcquire ac(mutex_); 1.623 + 1.624 + FcPattern* pattern = FcPatternCreate(); 1.625 + 1.626 + if (familyName) { 1.627 + FcPatternAddString(pattern, FC_FAMILY, (FcChar8*)familyName); 1.628 + } 1.629 + FcPatternAddBool(pattern, FC_SCALABLE, FcTrue); 1.630 + 1.631 + FcConfigSubstitute(NULL, pattern, FcMatchPattern); 1.632 + FcDefaultSubstitute(pattern); 1.633 + 1.634 + // Font matching: 1.635 + // CSS often specifies a fallback list of families: 1.636 + // font-family: a, b, c, serif; 1.637 + // However, fontconfig will always do its best to find *a* font when asked 1.638 + // for something so we need a way to tell if the match which it has found is 1.639 + // "good enough" for us. Otherwise, we can return NULL which gets piped up 1.640 + // and lets WebKit know to try the next CSS family name. However, fontconfig 1.641 + // configs allow substitutions (mapping "Arial -> Helvetica" etc) and we 1.642 + // wish to support that. 1.643 + // 1.644 + // Thus, if a specific family is requested we set @family_requested. Then we 1.645 + // record two strings: the family name after config processing and the 1.646 + // family name after resolving. If the two are equal, it's a good match. 1.647 + // 1.648 + // So consider the case where a user has mapped Arial to Helvetica in their 1.649 + // config. 1.650 + // requested family: "Arial" 1.651 + // post_config_family: "Helvetica" 1.652 + // post_match_family: "Helvetica" 1.653 + // -> good match 1.654 + // 1.655 + // and for a missing font: 1.656 + // requested family: "Monaco" 1.657 + // post_config_family: "Monaco" 1.658 + // post_match_family: "Times New Roman" 1.659 + // -> BAD match 1.660 + // 1.661 + // However, we special-case fallback fonts; see IsFallbackFontAllowed(). 1.662 + 1.663 + const char* post_config_family = get_name(pattern, FC_FAMILY); 1.664 + 1.665 + FcResult result; 1.666 + FcFontSet* font_set = FcFontSort(0, pattern, 0, 0, &result); 1.667 + if (!font_set) { 1.668 + FcPatternDestroy(pattern); 1.669 + return false; 1.670 + } 1.671 + 1.672 + FcPattern* match = MatchFont(font_set, post_config_family, familyStr); 1.673 + if (!match) { 1.674 + FcPatternDestroy(pattern); 1.675 + FcFontSetDestroy(font_set); 1.676 + return false; 1.677 + } 1.678 + 1.679 + FcPatternDestroy(pattern); 1.680 + 1.681 + // From here out we just extract our results from 'match' 1.682 + 1.683 + if (FcPatternGetString(match, FC_FAMILY, 0, &post_config_family) != FcResultMatch) { 1.684 + FcFontSetDestroy(font_set); 1.685 + return false; 1.686 + } 1.687 + 1.688 + FcChar8* c_filename; 1.689 + if (FcPatternGetString(match, FC_FILE, 0, &c_filename) != FcResultMatch) { 1.690 + FcFontSetDestroy(font_set); 1.691 + return false; 1.692 + } 1.693 + 1.694 + int face_index; 1.695 + if (FcPatternGetInteger(match, FC_INDEX, 0, &face_index) != FcResultMatch) { 1.696 + FcFontSetDestroy(font_set); 1.697 + return false; 1.698 + } 1.699 + 1.700 + FcFontSetDestroy(font_set); 1.701 + 1.702 + if (outIdentity) { 1.703 + outIdentity->fTTCIndex = face_index; 1.704 + outIdentity->fString.set((const char*)c_filename); 1.705 + } 1.706 + if (outFamilyName) { 1.707 + outFamilyName->set((const char*)post_config_family); 1.708 + } 1.709 + if (outStyle) { 1.710 + *outStyle = GetFontStyle(match); 1.711 + } 1.712 + return true; 1.713 + 1.714 +//////////////////// 1.715 + 1.716 + int count; 1.717 + FcPattern** match = MatchFont(font_set, post_config_family, &count); 1.718 + if (!match) { 1.719 + FcPatternDestroy(pattern); 1.720 + FcFontSetDestroy(font_set); 1.721 + return NULL; 1.722 + } 1.723 + 1.724 + FcPatternDestroy(pattern); 1.725 + 1.726 + SkTDArray<FcPattern*> trimmedMatches; 1.727 + for (int i = 0; i < count; ++i) { 1.728 + const char* justName = find_just_name(get_name(match[i], FC_FILE)); 1.729 + if (!is_lower(*justName)) { 1.730 + *trimmedMatches.append() = match[i]; 1.731 + } 1.732 + } 1.733 + 1.734 + SkFontStyleSet_FC* sset = SkNEW_ARGS(SkFontStyleSet_FC, 1.735 + (trimmedMatches.begin(), 1.736 + trimmedMatches.count())); 1.737 +#endif 1.738 + return false; 1.739 +}