qulonglong WritingSystems::get(FcPattern *pat) const { qulonglong ws(0); FcLangSet *langset(0); if (FcResultMatch==FcPatternGetLangSet(pat, FC_LANG, 0, &langset)) { for (int i = 0; constLanguageForWritingSystem[i].lang; ++i) if (FcLangDifferentLang!=FcLangSetHasLang(langset, constLanguageForWritingSystem[i].lang)) ws|=toBit(constLanguageForWritingSystem[i].ws); } else ws|=toBit(QFontDatabase::Other); FcCharSet *cs(0); if (FcResultMatch == FcPatternGetCharSet(pat, FC_CHARSET, 0, &cs)) { // some languages are not supported by FontConfig, we rather check the // charset to detect these for (int i = 0; QFontDatabase::Any!=sampleCharForWritingSystem[i].ws; ++i) if (FcCharSetHasChar(cs, sampleCharForWritingSystem[i].ch)) ws|=toBit(sampleCharForWritingSystem[i].ws); } return ws; }
static AliasStrength strengthOfFirstAlias(const FcPattern& original) { // Ideally there would exist a call like // FcResult FcPatternIsWeak(pattern, object, id, FcBool* isWeak); // // However, there is no such call and as of Fc 2.11.0 even FcPatternEquals ignores the weak bit. // Currently, the only reliable way of finding the weak bit is by its effect on matching. // The weak bit only affects the matching of FC_FAMILY and FC_POSTSCRIPT_NAME object values. // A element with the weak bit is scored after FC_LANG, without the weak bit is scored before. // Note that the weak bit is stored on the element, not on the value it holds. FcValue value; FcResult result = FcPatternGet(&original, FC_FAMILY, 0, &value); if (result != FcResultMatch) return AliasStrength::Done; RefPtr<FcPattern> pattern = adoptRef(FcPatternDuplicate(&original)); FcBool hasMultipleFamilies = true; while (hasMultipleFamilies) hasMultipleFamilies = FcPatternRemove(pattern.get(), FC_FAMILY, 1); // Create a font set with two patterns. // 1. the same FC_FAMILY as pattern and a lang object with only 'nomatchlang'. // 2. a different FC_FAMILY from pattern and a lang object with only 'matchlang'. FcUniquePtr<FcFontSet> fontSet(FcFontSetCreate()); FcUniquePtr<FcLangSet> strongLangSet(FcLangSetCreate()); FcLangSetAdd(strongLangSet.get(), reinterpret_cast<const FcChar8*>("nomatchlang")); // Ownership of this FcPattern will be transferred with FcFontSetAdd. FcPattern* strong = FcPatternDuplicate(pattern.get()); FcPatternAddLangSet(strong, FC_LANG, strongLangSet.get()); FcUniquePtr<FcLangSet> weakLangSet(FcLangSetCreate()); FcLangSetAdd(weakLangSet.get(), reinterpret_cast<const FcChar8*>("matchlang")); // Ownership of this FcPattern will be transferred via FcFontSetAdd. FcPattern* weak = FcPatternCreate(); FcPatternAddString(weak, FC_FAMILY, reinterpret_cast<const FcChar8*>("nomatchstring")); FcPatternAddLangSet(weak, FC_LANG, weakLangSet.get()); FcFontSetAdd(fontSet.get(), strong); FcFontSetAdd(fontSet.get(), weak); // Add 'matchlang' to the copy of the pattern. FcPatternAddLangSet(pattern.get(), FC_LANG, weakLangSet.get()); // Run a match against the copy of the pattern. // If the first element was weak, then we should match the pattern with 'matchlang'. // If the first element was strong, then we should match the pattern with 'nomatchlang'. // Note that this config is only used for FcFontRenderPrepare, which we don't even want. // However, there appears to be no way to match/sort without it. RefPtr<FcConfig> config = adoptRef(FcConfigCreate()); FcFontSet* fontSets[1] = { fontSet.get() }; RefPtr<FcPattern> match = adoptRef(FcFontSetMatch(config.get(), fontSets, 1, pattern.get(), &result)); FcLangSet* matchLangSet; FcPatternGetLangSet(match.get(), FC_LANG, 0, &matchLangSet); return FcLangEqual == FcLangSetHasLang(matchLangSet, reinterpret_cast<const FcChar8*>("matchlang")) ? AliasStrength::Weak : AliasStrength::Strong; }
static double FcCompareLang (FcValue *v1, FcValue *v2) { FcLangResult result; FcValue value1 = FcValueCanonicalize(v1), value2 = FcValueCanonicalize(v2); switch (value1.type) { case FcTypeLangSet: switch (value2.type) { case FcTypeLangSet: result = FcLangSetCompare (value1.u.l, value2.u.l); break; case FcTypeString: result = FcLangSetHasLang (value1.u.l, value2.u.s); break; default: return -1.0; } break; case FcTypeString: switch (value2.type) { case FcTypeLangSet: result = FcLangSetHasLang (value2.u.l, value1.u.s); break; case FcTypeString: result = FcLangCompare (value1.u.s, value2.u.s); break; default: return -1.0; } break; default: return -1.0; } switch (result) { case FcLangEqual: return 0; case FcLangDifferentCountry: return 1; case FcLangDifferentLang: default: return 2; } }
static double FcCompareLang (char *object, FcValue value1, FcValue value2) { FcLangResult result; switch (value1.type) { case FcTypeLangSet: switch (value2.type) { case FcTypeLangSet: result = FcLangSetCompare (value1.u.l, value2.u.l); break; case FcTypeString: result = FcLangSetHasLang (value1.u.l, value2.u.s); break; default: return -1.0; } break; case FcTypeString: switch (value2.type) { case FcTypeLangSet: result = FcLangSetHasLang (value2.u.l, value1.u.s); break; case FcTypeString: result = FcLangCompare (value1.u.s, value2.u.s); break; default: return -1.0; } break; default: return -1.0; } switch (result) { case FcLangEqual: return 0; case FcLangDifferentCountry: return 1; case FcLangDifferentLang: default: return 2; } }
FcStrSet *fcinfo_languages(const FcPattern *filter) { FcObjectSet *objectset; FcFontSet *fontset; FcLangSet *union_langset; FcStrSet *result; int f; FcInit(); objectset = FcObjectSetBuild(FC_LANG, NULL); fontset = FcFontList(NULL, (FcPattern *)filter, objectset); FcObjectSetDestroy(objectset); union_langset = FcLangSetCreate(); for (f = 0; f < fontset->nfont; f++) { FcLangSet *langset; FcStrList *strlist; FcChar8 *lang; if (FcPatternGetLangSet(fontset->fonts[f], FC_LANG, 0, &langset) != FcResultMatch) continue; if (! langset) continue; strlist = FcStrListCreate(FcLangSetGetLangs(langset)); while ((lang = FcStrListNext(strlist))) if (FcLangSetHasLang(union_langset, lang)) FcLangSetAdd(union_langset, FcStrCopy(lang)); } result = FcLangSetGetLangs(union_langset); FcFontSetDestroy(fontset); FcLangSetDestroy(union_langset); return result; }
void QFontconfigDatabase::populateFontDatabase() { FcFontSet *fonts; QString familyName; FcChar8 *value = 0; int weight_value; int slant_value; int spacing_value; FcChar8 *file_value; int indexValue; FcChar8 *foundry_value; FcChar8 *style_value; FcBool scalable; FcBool antialias; { FcObjectSet *os = FcObjectSetCreate(); FcPattern *pattern = FcPatternCreate(); const char *properties [] = { FC_FAMILY, FC_STYLE, FC_WEIGHT, FC_SLANT, FC_SPACING, FC_FILE, FC_INDEX, FC_LANG, FC_CHARSET, FC_FOUNDRY, FC_SCALABLE, FC_PIXEL_SIZE, FC_WEIGHT, FC_WIDTH, #if FC_VERSION >= 20297 FC_CAPABILITY, #endif (const char *)0 }; const char **p = properties; while (*p) { FcObjectSetAdd(os, *p); ++p; } fonts = FcFontList(0, pattern, os); FcObjectSetDestroy(os); FcPatternDestroy(pattern); } for (int i = 0; i < fonts->nfont; i++) { if (FcPatternGetString(fonts->fonts[i], FC_FAMILY, 0, &value) != FcResultMatch) continue; // capitalize(value); familyName = QString::fromUtf8((const char *)value); slant_value = FC_SLANT_ROMAN; weight_value = FC_WEIGHT_REGULAR; spacing_value = FC_PROPORTIONAL; file_value = 0; indexValue = 0; scalable = FcTrue; if (FcPatternGetInteger (fonts->fonts[i], FC_SLANT, 0, &slant_value) != FcResultMatch) slant_value = FC_SLANT_ROMAN; if (FcPatternGetInteger (fonts->fonts[i], FC_WEIGHT, 0, &weight_value) != FcResultMatch) weight_value = FC_WEIGHT_REGULAR; if (FcPatternGetInteger (fonts->fonts[i], FC_SPACING, 0, &spacing_value) != FcResultMatch) spacing_value = FC_PROPORTIONAL; if (FcPatternGetString (fonts->fonts[i], FC_FILE, 0, &file_value) != FcResultMatch) file_value = 0; if (FcPatternGetInteger (fonts->fonts[i], FC_INDEX, 0, &indexValue) != FcResultMatch) indexValue = 0; if (FcPatternGetBool(fonts->fonts[i], FC_SCALABLE, 0, &scalable) != FcResultMatch) scalable = FcTrue; if (FcPatternGetString(fonts->fonts[i], FC_FOUNDRY, 0, &foundry_value) != FcResultMatch) foundry_value = 0; if (FcPatternGetString(fonts->fonts[i], FC_STYLE, 0, &style_value) != FcResultMatch) style_value = 0; if(FcPatternGetBool(fonts->fonts[i],FC_ANTIALIAS,0,&antialias) != FcResultMatch) antialias = true; QSupportedWritingSystems writingSystems; FcLangSet *langset = 0; FcResult res = FcPatternGetLangSet(fonts->fonts[i], FC_LANG, 0, &langset); if (res == FcResultMatch) { bool hasLang = false; for (int j = 1; j < QFontDatabase::WritingSystemsCount; ++j) { const FcChar8 *lang = (const FcChar8*) languageForWritingSystem[j]; if (lang) { FcLangResult langRes = FcLangSetHasLang(langset, lang); if (langRes != FcLangDifferentLang) { writingSystems.setSupported(QFontDatabase::WritingSystem(j)); hasLang = true; } } } if (!hasLang) // none of our known languages, add it to the other set writingSystems.setSupported(QFontDatabase::Other); } else { // we set Other to supported for symbol fonts. It makes no // sense to merge these with other ones, as they are // special in a way. writingSystems.setSupported(QFontDatabase::Other); } #if FC_VERSION >= 20297 for (int j = 1; j < QFontDatabase::WritingSystemsCount; ++j) { if (writingSystems.supported(QFontDatabase::WritingSystem(j)) && requiresOpenType(j) && openType[j]) { FcChar8 *cap; res = FcPatternGetString (fonts->fonts[i], FC_CAPABILITY, 0, &cap); if (res != FcResultMatch || !strstr((const char *)cap, openType[j])) writingSystems.setSupported(QFontDatabase::WritingSystem(j),false); } } #endif FontFile *fontFile = new FontFile; fontFile->fileName = QLatin1String((const char *)file_value); fontFile->indexValue = indexValue; QFont::Style style = (slant_value == FC_SLANT_ITALIC) ? QFont::StyleItalic : ((slant_value == FC_SLANT_OBLIQUE) ? QFont::StyleOblique : QFont::StyleNormal); QFont::Weight weight = QFont::Weight(getFCWeight(weight_value)); double pixel_size = 0; if (!scalable) { int width = 100; FcPatternGetInteger (fonts->fonts[i], FC_WIDTH, 0, &width); FcPatternGetDouble (fonts->fonts[i], FC_PIXEL_SIZE, 0, &pixel_size); } bool fixedPitch = spacing_value >= FC_MONO; QFont::Stretch stretch = QFont::Unstretched; QString styleName = style_value ? QString::fromUtf8((const char *) style_value) : QString(); QPlatformFontDatabase::registerFont(familyName,styleName,QLatin1String((const char *)foundry_value),weight,style,stretch,antialias,scalable,pixel_size,fixedPitch,writingSystems,fontFile); // qDebug() << familyName << (const char *)foundry_value << weight << style << &writingSystems << scalable << true << pixel_size; for (int k = 1; FcPatternGetString(fonts->fonts[i], FC_FAMILY, k, &value) == FcResultMatch; ++k) QPlatformFontDatabase::registerAliasToFontFamily(familyName, QString::fromUtf8((const char *)value)); } FcFontSetDestroy (fonts); struct FcDefaultFont { const char *qtname; const char *rawname; bool fixed; }; const FcDefaultFont defaults[] = { { "Serif", "serif", false }, { "Sans Serif", "sans-serif", false }, { "Monospace", "monospace", true }, { 0, 0, false } }; const FcDefaultFont *f = defaults; // aliases only make sense for 'common', not for any of the specials QSupportedWritingSystems ws; ws.setSupported(QFontDatabase::Latin); while (f->qtname) { QString familyQtName = QString::fromLatin1(f->qtname); registerFont(familyQtName,QString(),QString(),QFont::Normal,QFont::StyleNormal,QFont::Unstretched,true,true,0,f->fixed,ws,0); registerFont(familyQtName,QString(),QString(),QFont::Normal,QFont::StyleItalic,QFont::Unstretched,true,true,0,f->fixed,ws,0); registerFont(familyQtName,QString(),QString(),QFont::Normal,QFont::StyleOblique,QFont::Unstretched,true,true,0,f->fixed,ws,0); ++f; } //Lighthouse has very lazy population of the font db. We want it to be initialized when //QApplication is constructed, so that the population procedure can do something like this to //set the default font // const FcDefaultFont *s = defaults; // QFont font("Sans Serif"); // font.setPointSize(9); // QApplication::setFont(font); }
static void populateFromPattern(FcPattern *pattern) { QString familyName; FcChar8 *value = 0; int weight_value; int slant_value; int spacing_value; int width_value; FcChar8 *file_value; int indexValue; FcChar8 *foundry_value; FcChar8 *style_value; FcBool scalable; FcBool antialias; if (FcPatternGetString(pattern, FC_FAMILY, 0, &value) != FcResultMatch) return; familyName = QString::fromUtf8((const char *)value); slant_value = FC_SLANT_ROMAN; weight_value = FC_WEIGHT_REGULAR; spacing_value = FC_PROPORTIONAL; file_value = 0; indexValue = 0; scalable = FcTrue; if (FcPatternGetInteger(pattern, FC_SLANT, 0, &slant_value) != FcResultMatch) slant_value = FC_SLANT_ROMAN; if (FcPatternGetInteger(pattern, FC_WEIGHT, 0, &weight_value) != FcResultMatch) weight_value = FC_WEIGHT_REGULAR; if (FcPatternGetInteger(pattern, FC_WIDTH, 0, &width_value) != FcResultMatch) width_value = FC_WIDTH_NORMAL; if (FcPatternGetInteger(pattern, FC_SPACING, 0, &spacing_value) != FcResultMatch) spacing_value = FC_PROPORTIONAL; if (FcPatternGetString(pattern, FC_FILE, 0, &file_value) != FcResultMatch) file_value = 0; if (FcPatternGetInteger(pattern, FC_INDEX, 0, &indexValue) != FcResultMatch) indexValue = 0; if (FcPatternGetBool(pattern, FC_SCALABLE, 0, &scalable) != FcResultMatch) scalable = FcTrue; if (FcPatternGetString(pattern, FC_FOUNDRY, 0, &foundry_value) != FcResultMatch) foundry_value = 0; if (FcPatternGetString(pattern, FC_STYLE, 0, &style_value) != FcResultMatch) style_value = 0; if (FcPatternGetBool(pattern,FC_ANTIALIAS,0,&antialias) != FcResultMatch) antialias = true; QSupportedWritingSystems writingSystems; FcLangSet *langset = 0; FcResult res = FcPatternGetLangSet(pattern, FC_LANG, 0, &langset); if (res == FcResultMatch) { bool hasLang = false; for (int j = 1; j < QFontDatabase::WritingSystemsCount; ++j) { const FcChar8 *lang = (const FcChar8*) languageForWritingSystem[j]; if (lang) { FcLangResult langRes = FcLangSetHasLang(langset, lang); if (langRes != FcLangDifferentLang) { writingSystems.setSupported(QFontDatabase::WritingSystem(j)); hasLang = true; } } } if (!hasLang) // none of our known languages, add it to the other set writingSystems.setSupported(QFontDatabase::Other); } else { // we set Other to supported for symbol fonts. It makes no // sense to merge these with other ones, as they are // special in a way. writingSystems.setSupported(QFontDatabase::Other); } #if FC_VERSION >= 20297 for (int j = 1; j < QFontDatabase::WritingSystemsCount; ++j) { if (writingSystems.supported(QFontDatabase::WritingSystem(j)) && requiresOpenType(j) && openType[j]) { FcChar8 *cap; res = FcPatternGetString (pattern, FC_CAPABILITY, 0, &cap); if (res != FcResultMatch || !strstr((const char *)cap, openType[j])) writingSystems.setSupported(QFontDatabase::WritingSystem(j),false); } } #endif FontFile *fontFile = new FontFile; fontFile->fileName = QString::fromLocal8Bit((const char *)file_value); fontFile->indexValue = indexValue; QFont::Style style = (slant_value == FC_SLANT_ITALIC) ? QFont::StyleItalic : ((slant_value == FC_SLANT_OBLIQUE) ? QFont::StyleOblique : QFont::StyleNormal); // Note: weight should really be an int but registerFont incorrectly uses an enum QFont::Weight weight = QFont::Weight(weightFromFcWeight(weight_value)); double pixel_size = 0; if (!scalable) FcPatternGetDouble (pattern, FC_PIXEL_SIZE, 0, &pixel_size); bool fixedPitch = spacing_value >= FC_MONO; // Note: stretch should really be an int but registerFont incorrectly uses an enum QFont::Stretch stretch = QFont::Stretch(stretchFromFcWidth(width_value)); QString styleName = style_value ? QString::fromUtf8((const char *) style_value) : QString(); QPlatformFontDatabase::registerFont(familyName,styleName,QLatin1String((const char *)foundry_value),weight,style,stretch,antialias,scalable,pixel_size,fixedPitch,writingSystems,fontFile); // qDebug() << familyName << (const char *)foundry_value << weight << style << &writingSystems << scalable << true << pixel_size; for (int k = 1; FcPatternGetString(pattern, FC_FAMILY, k, &value) == FcResultMatch; ++k) QPlatformFontDatabase::registerAliasToFontFamily(familyName, QString::fromUtf8((const char *)value)); }