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; }
FcPattern* BC_Resources::find_similar_font(FT_ULong char_code, FcPattern *oldfont) { FcPattern *pat, *font; FcFontSet *fs; FcObjectSet *os; FcCharSet *fcs; FcChar8 *file; double dval; int ival; // Do not search control codes if(char_code < ' ') return 0; fontconfig_lock.lock("BC_Resources::find_similar_font"); pat = FcPatternCreate(); os = FcObjectSetBuild(FC_FILE, FC_CHARSET, FC_SCALABLE, FC_FAMILY, FC_SLANT, FC_WEIGHT, FC_WIDTH, (char *)0); FcPatternAddBool(pat, FC_SCALABLE, true); fcs = FcCharSetCreate(); if(FcCharSetAddChar(fcs, char_code)) FcPatternAddCharSet(pat, FC_CHARSET, fcs); FcCharSetDestroy(fcs); for(int i = 0; i < LEN_FCPROP; i++) { if(FcPatternGetInteger(oldfont, fc_properties[i], 0, &ival) == FcResultMatch) FcPatternAddInteger(pat, fc_properties[i], ival); } fs = FcFontList(0, pat, os); for(int i = LEN_FCPROP - 1; i >= 0 && fs->nfont == 0; i--) { FcFontSetDestroy(fs); FcPatternDel(pat, fc_properties[i]); fs = FcFontList(0, pat, os); } FcPatternDestroy(pat); FcObjectSetDestroy(os); pat = 0; for (int i = 0; i < fs->nfont; i++) { font = fs->fonts[i]; if(FcPatternGetCharSet(font, FC_CHARSET, 0, &fcs) == FcResultMatch) { if(FcCharSetHasChar(fcs, char_code)) { pat = FcPatternDuplicate(font); break; } } } FcFontSetDestroy(fs); fontconfig_lock.unlock(); return pat; }
static FcBool empty_charset(FcPattern *pattern) { FcCharSet *charset; assert(FcPatternGetCharSet(pattern, FC_CHARSET, 0, &charset) == FcResultMatch); return FcCharSetCount(charset) == 0; }
int fontconf() { FcFontSet* fs = NULL; FcPattern* pat = NULL; FcObjectSet* os = NULL; FcChar8* strpat = (FcChar8*) ":lang=ja"; pat = FcNameParse(strpat); os = FcObjectSetBuild(FC_FAMILY, FC_CHARSET, FC_FILE, (char *) 0); fs = FcFontList(0, pat, os); if (os) FcObjectSetDestroy(os); os = NULL; FcPatternDestroy(pat); pat = NULL; if (!fs || fs->nfont <= 0) goto nofont; FcChar8 *family; FcChar8 *file; FcCharSet* cs; FcChar32 ch; FcUtf8ToUcs4((FcChar8*) "��", &ch, 3); int i; for (i = 0; i < fs->nfont; i++) { if (FcPatternGetCharSet(fs->fonts[i], FC_CHARSET, 0, &cs) != FcResultMatch) { fprintf(stderr, "no match\n"); FcPatternPrint(fs->fonts[i]); goto nofont; } if(FcPatternGetString(fs->fonts[i], FC_FAMILY, 1, &family) !=FcResultMatch) if(FcPatternGetString(fs->fonts[i], FC_FAMILY, 0, &family) != FcResultMatch) goto nofont; printf("[%d] %s ", i, (char *)family); if(FcPatternGetString(fs->fonts[i], FC_FILE, 0, &file) != FcResultMatch) goto nofont; printf("(%s): ", (char *)file); if(FcCharSetHasChar(cs, ch)){ puts("Yes"); }else{ puts("No"); } } FcFontSetDestroy(fs); return 0; nofont: return 1; }
FontFileLister::CollectionResult FontConfigFontFileLister::GetFontPaths(std::string const& facename, int bold, bool italic, std::set<wxUniChar> const& characters) { CollectionResult ret; std::string family(facename); if (family[0] == '@') family.erase(0, 1); boost::to_lower(family); int weight = bold == 0 ? 80 : bold == 1 ? 200 : bold; int slant = italic ? 110 : 0; // Create a fontconfig pattern to match the desired weight/slant agi::scoped_holder<FcPattern*> pat(FcPatternCreate(), FcPatternDestroy); if (!pat) return ret; FcPatternAddBool(pat, FC_OUTLINE, true); FcPatternAddInteger(pat, FC_SLANT, slant); FcPatternAddInteger(pat, FC_WEIGHT, weight); FcDefaultSubstitute(pat); if (!FcConfigSubstitute(config, pat, FcMatchPattern)) return ret; // Create a font set with only correctly named fonts // This is needed because the patterns returned by font matching only // include the first family and fullname, so we can't always verify that // we got the actual font we were asking for after the fact agi::scoped_holder<FcFontSet*> fset(FcFontSetCreate(), FcFontSetDestroy); find_font(FcConfigGetFonts(config, FcSetApplication), fset, family); find_font(FcConfigGetFonts(config, FcSetSystem), fset, family); // Get the best match from fontconfig FcResult result; FcFontSet *sets[] = { (FcFontSet*)fset }; agi::scoped_holder<FcPattern*> match(FcFontSetMatch(config, sets, 1, pat, &result), FcPatternDestroy); if (!match) return ret; FcChar8 *file; if(FcPatternGetString(match, FC_FILE, 0, &file) != FcResultMatch) return ret; FcCharSet *charset; if (FcPatternGetCharSet(match, FC_CHARSET, 0, &charset) == FcResultMatch) { for (wxUniChar chr : characters) { if (!FcCharSetHasChar(charset, chr)) ret.missing += chr; } } ret.paths.emplace_back((const char *)file); return ret; }
FcFontSet *fcinfo_uinterval_statistics(const FcPattern *filter, double *uinterval_stat[], uinterval_type_t uintype) { FcFontSet *fontset, *tmp; FcCharSet *charset; int s, f; FcChar8 *file; FcInit(); /* bitmap font files sort according to FC_LANG, identified by FC_FILE */ fontset = fcinfo(NULL, filter, FcFalse, 5, FC_FAMILY, FC_STYLE, FC_CHARSET, FC_LANG, FC_FILE); tmp = fcinfo_match(fontset, filter); /* wipe duplicite (family, style)s */ FcFontSetDestroy(fontset); fontset = tmp; for (s = 0; s < uinterval_num(uintype); s++) { uinterval_stat[s] = malloc(sizeof(double)*fontset->nfont); if (! uinterval_stat[s]) { fprintf(stderr, "fcinfo_uinterval_statistics(): out of memory\n"); exit(1); } } for (f = 0; f < fontset->nfont; f++) { FcPatternGetString(fontset->fonts[f], FC_FILE, 0, &file); assert(FcPatternGetCharSet(fontset->fonts[f], FC_CHARSET, 0, &charset) == FcResultMatch); for (s = 0; s < uinterval_num(uintype); s++) uinterval_stat[s][f] = charset_uinterval_coverage(charset, uinterval_name(s, uintype), uintype, NULL, NULL); } return fontset; /* holds one of table headers */ }
static XftFont* getfont(XftFont **font, uint32_t ch) { XftFont *first = font[0]; if(!FcCharSetHasChar(charset, ch)) { return first; } while(*font) { if(XftGlyphExists(display, *font, ch)) { return *font; } font++; } FcResult result; int i; for(i = 0; i != fs->nfont; i++) { FcCharSet *cs; result = FcPatternGetCharSet(fs->fonts[i], FC_CHARSET, 0, &cs); if(FcCharSetHasChar(cs, ch)) { FcPattern *p = FcPatternDuplicate(fs->fonts[i]), *pp; double size; if(!FcPatternGetDouble(first->pattern, FC_PIXEL_SIZE, 0, &size)) { FcPatternAddDouble(p, FC_PIXEL_SIZE, size); } pp = XftFontMatch(display, screen, p, &result); *font = XftFontOpenPattern(display, pp); FcPatternDestroy(p); return *font; } } //should never happen return first; }
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; FcBool scalable; FcBool antialias; { FcObjectSet *os = FcObjectSetCreate(); FcPattern *pattern = FcPatternCreate(); const char *properties [] = { FC_FAMILY, 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_MEDIUM; 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_MEDIUM; 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(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) { for (int i = 1; i < LanguageCount; ++i) { const FcChar8 *lang = (const FcChar8*) languageForWritingSystem[i]; if (lang) { FcLangResult langRes = FcLangSetHasLang(langset, lang); if (langRes != FcLangDifferentLang) writingSystems.setSupported(QFontDatabase::WritingSystem(i)); } } } 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); } FcCharSet *cs = 0; res = FcPatternGetCharSet(fonts->fonts[i], FC_CHARSET, 0, &cs); if (res == FcResultMatch) { // some languages are not supported by FontConfig, we rather check the // charset to detect these for (int i = 1; i < SampleCharCount; ++i) { if (!sampleCharForWritingSystem[i]) continue; if (FcCharSetHasChar(cs, sampleCharForWritingSystem[i])) writingSystems.setSupported(QFontDatabase::WritingSystem(i)); } } #if FC_VERSION >= 20297 for (int j = 1; j < LanguageCount; ++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); } QFont::Stretch stretch = QFont::Unstretched; QPlatformFontDatabase::registerFont(familyName,QLatin1String((const char *)foundry_value),weight,style,stretch,antialias,scalable,pixel_size,writingSystems,fontFile); // qDebug() << familyName << (const char *)foundry_value << weight << style << &writingSystems << scalable << true << pixel_size; } 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) { registerFont(f->qtname,QLatin1String(""),QFont::Normal,QFont::StyleNormal,QFont::Unstretched,true,true,0,ws,0); registerFont(f->qtname,QLatin1String(""),QFont::Normal,QFont::StyleItalic,QFont::Unstretched,true,true,0,ws,0); registerFont(f->qtname,QLatin1String(""),QFont::Normal,QFont::StyleOblique,QFont::Unstretched,true,true,0,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); }
/** * \brief Low-level font selection. * \param priv private data * \param family font family * \param treat_family_as_pattern treat family as fontconfig pattern * \param bold font weight value * \param italic font slant value * \param index out: font index inside a file * \param code: the character that should be present in the font, can be 0 * \return font file path */ static char *select_font(ASS_Library *library, FCInstance *priv, const char *family, int treat_family_as_pattern, unsigned bold, unsigned italic, int *index, uint32_t code) { FcBool rc; FcResult result; FcPattern *pat = NULL, *rpat = NULL; int r_index, r_slant, r_weight; FcChar8 *r_family, *r_style, *r_file, *r_fullname; FcBool r_outline, r_embolden; FcCharSet *r_charset; FcFontSet *ffullname = NULL, *fsorted = NULL, *fset = NULL; int curf; char *retval = NULL; int family_cnt = 0; *index = 0; if (treat_family_as_pattern) pat = FcNameParse((const FcChar8 *) family); else pat = FcPatternCreate(); if (!pat) goto error; if (!treat_family_as_pattern) { FcPatternAddString(pat, FC_FAMILY, (const FcChar8 *) family); // In SSA/ASS fonts are sometimes referenced by their "full name", // which is usually a concatenation of family name and font // style (ex. Ottawa Bold). Full name is available from // FontConfig pattern element FC_FULLNAME, but it is never // used for font matching. // Therefore, I'm removing words from the end of the name one // by one, and adding shortened names to the pattern. It seems // that the first value (full name in this case) has // precedence in matching. // An alternative approach could be to reimplement FcFontSort // using FC_FULLNAME instead of FC_FAMILY. family_cnt = 1; { char *s = strdup(family); char *p = s + strlen(s); while (--p > s) if (*p == ' ' || *p == '-') { *p = '\0'; FcPatternAddString(pat, FC_FAMILY, (const FcChar8 *) s); ++family_cnt; } free(s); } } FcPatternAddBool(pat, FC_OUTLINE, FcTrue); FcPatternAddInteger(pat, FC_SLANT, italic); FcPatternAddInteger(pat, FC_WEIGHT, bold); FcDefaultSubstitute(pat); rc = FcConfigSubstitute(priv->config, pat, FcMatchPattern); if (!rc) goto error; /* Fontconfig defaults include a language setting, which it sets based on * some environment variables or defaults to "en". Unset this as we don't * know the real language, and because some some attached fonts lack * non-ascii characters included in fontconfig's list of characters * required for English support and therefore don't match the lang=en * criterion. */ FcPatternDel(pat, "lang"); fsorted = FcFontSort(priv->config, pat, FcTrue, NULL, &result); ffullname = match_fullname(library, priv, family, bold, italic); if (!fsorted || !ffullname) goto error; fset = FcFontSetCreate(); for (curf = 0; curf < ffullname->nfont; ++curf) { FcPattern *curp = ffullname->fonts[curf]; FcPatternReference(curp); FcFontSetAdd(fset, curp); } for (curf = 0; curf < fsorted->nfont; ++curf) { FcPattern *curp = fsorted->fonts[curf]; FcPatternReference(curp); FcFontSetAdd(fset, curp); } for (curf = 0; curf < fset->nfont; ++curf) { FcPattern *curp = fset->fonts[curf]; result = FcPatternGetBool(curp, FC_OUTLINE, 0, &r_outline); if (result != FcResultMatch) continue; if (r_outline != FcTrue) continue; if (!code) break; result = FcPatternGetCharSet(curp, FC_CHARSET, 0, &r_charset); if (result != FcResultMatch) continue; if (FcCharSetHasChar(r_charset, code)) break; } if (curf >= fset->nfont) goto error; if (!treat_family_as_pattern) { // Remove all extra family names from original pattern. // After this, FcFontRenderPrepare will select the most relevant family // name in case there are more than one of them. for (; family_cnt > 1; --family_cnt) FcPatternRemove(pat, FC_FAMILY, family_cnt - 1); } rpat = FcFontRenderPrepare(priv->config, pat, fset->fonts[curf]); if (!rpat) goto error; result = FcPatternGetInteger(rpat, FC_INDEX, 0, &r_index); if (result != FcResultMatch) goto error; *index = r_index; result = FcPatternGetString(rpat, FC_FILE, 0, &r_file); if (result != FcResultMatch) goto error; retval = strdup((const char *) r_file); result = FcPatternGetString(rpat, FC_FAMILY, 0, &r_family); if (result != FcResultMatch) r_family = NULL; result = FcPatternGetString(rpat, FC_FULLNAME, 0, &r_fullname); if (result != FcResultMatch) r_fullname = NULL; if (!treat_family_as_pattern && !(r_family && strcasecmp((const char *) r_family, family) == 0) && !(r_fullname && strcasecmp((const char *) r_fullname, family) == 0)) { char *fallback = (char *) (r_fullname ? r_fullname : r_family); if (code) { ass_msg(library, MSGL_WARN, "fontconfig: cannot find glyph U+%04X in font '%s', falling back to '%s'", (unsigned int)code, family, fallback); } else { ass_msg(library, MSGL_WARN, "fontconfig: cannot find font '%s', falling back to '%s'", family, fallback); } } result = FcPatternGetString(rpat, FC_STYLE, 0, &r_style); if (result != FcResultMatch) r_style = NULL; result = FcPatternGetInteger(rpat, FC_SLANT, 0, &r_slant); if (result != FcResultMatch) r_slant = 0; result = FcPatternGetInteger(rpat, FC_WEIGHT, 0, &r_weight); if (result != FcResultMatch) r_weight = 0; result = FcPatternGetBool(rpat, FC_EMBOLDEN, 0, &r_embolden); if (result != FcResultMatch) r_embolden = 0; ass_msg(library, MSGL_V, "Font info: family '%s', style '%s', fullname '%s'," " slant %d, weight %d%s", (const char *) r_family, (const char *) r_style, (const char *) r_fullname, r_slant, r_weight, r_embolden ? ", embolden" : ""); error: if (pat) FcPatternDestroy(pat); if (rpat) FcPatternDestroy(rpat); if (fsorted) FcFontSetDestroy(fsorted); if (ffullname) FcFontSetDestroy(ffullname); if (fset) FcFontSetDestroy(fset); return retval; }
/** * \brief Low-level font selection. * \param priv private data * \param family font family * \param bold font weight value * \param italic font slant value * \param index out: font index inside a file * \param code: the character that should be present in the font, can be 0 * \return font file path */ static char* _select_font(fc_instance_t* priv, const char* family, unsigned bold, unsigned italic, int* index, uint32_t code) { FcBool rc; FcResult result; FcPattern *pat = 0, *rpat; int val_i; FcChar8* val_s; FcBool val_b; FcCharSet* val_cs; FcFontSet* fset = 0; int curf; char* retval = 0; *index = 0; pat = FcPatternCreate(); if (!pat) goto error; FcPatternAddString(pat, FC_FAMILY, (const FcChar8*)family); FcPatternAddBool(pat, FC_OUTLINE, FcTrue); FcPatternAddInteger(pat, FC_SLANT, italic); FcPatternAddInteger(pat, FC_WEIGHT, bold); FcDefaultSubstitute(pat); rc = FcConfigSubstitute(priv->config, pat, FcMatchPattern); if (!rc) goto error; fset = FcFontSort(priv->config, pat, FcTrue, NULL, &result); for (curf = 0; curf < fset->nfont; ++curf) { rpat = fset->fonts[curf]; result = FcPatternGetBool(rpat, FC_OUTLINE, 0, &val_b); if (result != FcResultMatch) continue; if (val_b != FcTrue) continue; if (!code) break; result = FcPatternGetCharSet(rpat, FC_CHARSET, 0, &val_cs); if (result != FcResultMatch) continue; if (FcCharSetHasChar(val_cs, code)) break; } if (curf >= fset->nfont) goto error; rpat = fset->fonts[curf]; result = FcPatternGetInteger(rpat, FC_INDEX, 0, &val_i); if (result != FcResultMatch) goto error; *index = val_i; result = FcPatternGetString(rpat, FC_FAMILY, 0, &val_s); if (result != FcResultMatch) goto error; if (strcasecmp((const char*)val_s, family) != 0) mp_msg(MSGT_ASS, MSGL_WARN, MSGTR_LIBASS_SelectedFontFamilyIsNotTheRequestedOne, (const char*)val_s, family); result = FcPatternGetString(rpat, FC_FILE, 0, &val_s); if (result != FcResultMatch) goto error; retval = strdup((const char*)val_s); error: if (pat) FcPatternDestroy(pat); if (fset) FcFontSetDestroy(fset); return retval; }
/** * \brief Low-level font selection. * \param priv private data * \param family font family * \param bold font weight value * \param italic font slant value * \param index out: font index inside a file * \param code: the character that should be present in the font, can be 0 * \return font file path */ static char* _select_font(fc_instance_t* priv, const char* family, unsigned bold, unsigned italic, int* index, uint32_t code) { FcBool rc; FcResult result; FcPattern *pat = NULL, *rpat = NULL; int r_index, r_slant, r_weight; FcChar8 *r_family, *r_style, *r_file, *r_fullname; FcBool r_outline, r_embolden; FcCharSet* r_charset; FcFontSet* fset = NULL; int curf; char* retval = NULL; int family_cnt; *index = 0; pat = FcPatternCreate(); if (!pat) goto error; FcPatternAddString(pat, FC_FAMILY, (const FcChar8*)family); // In SSA/ASS fonts are sometimes referenced by their "full name", // which is usually a concatenation of family name and font // style (ex. Ottawa Bold). Full name is available from // FontConfig pattern element FC_FULLNAME, but it is never // used for font matching. // Therefore, I'm removing words from the end of the name one // by one, and adding shortened names to the pattern. It seems // that the first value (full name in this case) has // precedence in matching. // An alternative approach could be to reimplement FcFontSort // using FC_FULLNAME instead of FC_FAMILY. family_cnt = 1; { char* s = strdup(family); char* p = s + strlen(s); while (--p > s) if (*p == ' ' || *p == '-') { *p = '\0'; FcPatternAddString(pat, FC_FAMILY, (const FcChar8*)s); ++ family_cnt; } free(s); } FcPatternAddBool(pat, FC_OUTLINE, FcTrue); FcPatternAddInteger(pat, FC_SLANT, italic); FcPatternAddInteger(pat, FC_WEIGHT, bold); FcDefaultSubstitute(pat); rc = FcConfigSubstitute(priv->config, pat, FcMatchPattern); if (!rc) goto error; fset = FcFontSort(priv->config, pat, FcTrue, NULL, &result); if (!fset) goto error; for (curf = 0; curf < fset->nfont; ++curf) { FcPattern* curp = fset->fonts[curf]; result = FcPatternGetBool(curp, FC_OUTLINE, 0, &r_outline); if (result != FcResultMatch) continue; if (r_outline != FcTrue) continue; if (!code) break; result = FcPatternGetCharSet(curp, FC_CHARSET, 0, &r_charset); if (result != FcResultMatch) continue; if (FcCharSetHasChar(r_charset, code)) break; } if (curf >= fset->nfont) goto error; #if (FC_VERSION >= 20297) // Remove all extra family names from original pattern. // After this, FcFontRenderPrepare will select the most relevant family // name in case there are more than one of them. for (; family_cnt > 1; --family_cnt) FcPatternRemove(pat, FC_FAMILY, family_cnt - 1); #endif rpat = FcFontRenderPrepare(priv->config, pat, fset->fonts[curf]); if (!rpat) goto error; result = FcPatternGetInteger(rpat, FC_INDEX, 0, &r_index); if (result != FcResultMatch) goto error; *index = r_index; result = FcPatternGetString(rpat, FC_FILE, 0, &r_file); if (result != FcResultMatch) goto error; retval = strdup((const char*)r_file); result = FcPatternGetString(rpat, FC_FAMILY, 0, &r_family); if (result != FcResultMatch) r_family = NULL; result = FcPatternGetString(rpat, FC_FULLNAME, 0, &r_fullname); if (result != FcResultMatch) r_fullname = NULL; if (!(r_family && strcasecmp((const char*)r_family, family) == 0) && !(r_fullname && strcasecmp((const char*)r_fullname, family) == 0)) mp_msg(MSGT_ASS, MSGL_WARN, MSGTR_LIBASS_SelectedFontFamilyIsNotTheRequestedOne, (const char*)(r_fullname ? r_fullname : r_family), family); result = FcPatternGetString(rpat, FC_STYLE, 0, &r_style); if (result != FcResultMatch) r_style = NULL; result = FcPatternGetInteger(rpat, FC_SLANT, 0, &r_slant); if (result != FcResultMatch) r_slant = 0; result = FcPatternGetInteger(rpat, FC_WEIGHT, 0, &r_weight); if (result != FcResultMatch) r_weight = 0; result = FcPatternGetBool(rpat, FC_EMBOLDEN, 0, &r_embolden); if (result != FcResultMatch) r_embolden = 0; mp_msg(MSGT_ASS, MSGL_V, "[ass] Font info: family '%s', style '%s', fullname '%s'," " slant %d, weight %d%s\n", (const char*)r_family, (const char*)r_style, (const char*)r_fullname, r_slant, r_weight, r_embolden ? ", embolden" : ""); error: if (pat) FcPatternDestroy(pat); if (rpat) FcPatternDestroy(rpat); if (fset) FcFontSetDestroy(fset); return retval; }
int zaFont::fontconf(const char * charset) { FcFontSet* fs = NULL; FcPattern* pat = NULL; FcObjectSet* os = NULL; //FcChar8* strpat = (FcChar8*)":lang=ja"; string ls = ":lang="; ls.append(charset); FcChar8* strpat = (FcChar8*)ls.c_str(); fprintf(stderr,"zaFont::fontconf charset %s\n",strpat); pat = FcNameParse(strpat); os = FcObjectSetBuild(FC_FAMILY, FC_CHARSET, FC_STYLE,FC_FILE, (char *)0); fs = FcFontList(0, pat, os); if(os) FcObjectSetDestroy(os); os = NULL; FcPatternDestroy(pat); pat = NULL; if(!fs || fs->nfont <= 0) goto nofont; FcChar8 *family; FcChar8 *style; FcChar8 *file; FcCharSet* cs; FcChar32 ch; FcUtf8ToUcs4((FcChar8*)"这", &ch, 3); int i; for(i=0; i<fs->nfont; i++) { if(FcPatternGetCharSet(fs->fonts[i], FC_CHARSET, 0, &cs) != FcResultMatch) { fprintf(stderr, "no match\n"); FcPatternPrint(fs->fonts[i]); goto nofont; } if(FcPatternGetString(fs->fonts[i], FC_FAMILY, 1, &family) != FcResultMatch) if(FcPatternGetString(fs->fonts[i], FC_FAMILY, 0, &family) != FcResultMatch) goto nofont; // fprintf(stderr,"zaFont::fontconf [%d] %s \n", i, (char *)family); if(FcPatternGetString(fs->fonts[i], FC_STYLE, 0, &style) != FcResultMatch) goto nofont; // fprintf(stderr,"zaFont::fontconf [%d] %s \n", i, (char *)style); if(FcPatternGetString(fs->fonts[i], FC_FILE, 0, &file) != FcResultMatch) goto nofont; // fprintf(stderr, "zaFont::fontconf (%s): \n", (char *)file); strcpy(m_charset,charset); strcpy(this->m_path,(char *)file); if(strstr((char*)file,"arial.ttf")) break; // if(FcCharSetHasChar(cs, ch)) // { // puts("Yes"); // }else // { // puts("No"); // } } FcFontSetDestroy(fs); return 0; nofont: return 1; }
static UnixFtFont * InitFont( Tk_Window tkwin, FcPattern *pattern, UnixFtFont *fontPtr) { FcFontSet *set; FcCharSet *charset; FcResult result; XftFont *ftFont; int i; if (!fontPtr) { fontPtr = (UnixFtFont *) ckalloc(sizeof(UnixFtFont)); } FcConfigSubstitute(0, pattern, FcMatchPattern); XftDefaultSubstitute(Tk_Display(tkwin), Tk_ScreenNumber(tkwin), pattern); /* * Generate the list of fonts */ set = FcFontSort(0, pattern, FcTrue, NULL, &result); if (!set) { FcPatternDestroy(pattern); ckfree((char *)fontPtr); return NULL; } fontPtr->fontset = set; fontPtr->pattern = pattern; fontPtr->faces = (UnixFtFace *) ckalloc(set->nfont * sizeof(UnixFtFace)); fontPtr->nfaces = set->nfont; /* * Fill in information about each returned font */ for (i = 0; i < set->nfont; i++) { fontPtr->faces[i].ftFont = 0; fontPtr->faces[i].source = set->fonts[i]; if (FcPatternGetCharSet(set->fonts[i], FC_CHARSET, 0, &charset) == FcResultMatch) { fontPtr->faces[i].charset = FcCharSetCopy(charset); } else { fontPtr->faces[i].charset = 0; } } fontPtr->display = Tk_Display(tkwin); fontPtr->screen = Tk_ScreenNumber(tkwin); fontPtr->ftDraw = 0; fontPtr->color.color.red = 0; fontPtr->color.color.green = 0; fontPtr->color.color.blue = 0; fontPtr->color.color.alpha = 0xffff; fontPtr->color.pixel = 0xffffffff; /* * Fill in platform-specific fields of TkFont. */ ftFont = GetFont(fontPtr, 0); fontPtr->font.fid = XLoadFont(Tk_Display(tkwin), "fixed"); GetTkFontAttributes(ftFont, &fontPtr->font.fa); GetTkFontMetrics(ftFont, &fontPtr->font.fm); return fontPtr; }
/* Constructor of the object : it allocates memory and initializes the member * of the new object. * The user must give the FcPattern of the font or the master (which may be NULL * in which case the character map will be empty). */ __GLCcharMap* __glcCharMapCreate(const __GLCmaster* inMaster, const __GLCcontext* inContext) { __GLCcharMap* This = NULL; assert(inContext); This = (__GLCcharMap*)__glcMalloc(sizeof(__GLCcharMap)); if (!This) { __glcRaiseError(GLC_RESOURCE_ERROR); return NULL; } memset(This, 0, sizeof(__GLCcharMap)); This->charSet = FcCharSetCreate(); if (!This->charSet) { __glcRaiseError(GLC_RESOURCE_ERROR); __glcFree(This); return NULL; } if (inMaster) { FcCharSet* charSet = NULL; FcFontSet* fontSet = NULL; int i = 0; FcObjectSet* objectSet = NULL; FcPattern* pattern = FcPatternCreate(); if (!pattern) { __glcRaiseError(GLC_RESOURCE_ERROR); FcCharSetDestroy(This->charSet); __glcFree(This); return NULL; } objectSet = FcObjectSetBuild(FC_FAMILY, FC_FOUNDRY, FC_SPACING, FC_OUTLINE, FC_CHARSET, NULL); if (!objectSet) { __glcRaiseError(GLC_RESOURCE_ERROR); FcPatternDestroy(pattern); FcCharSetDestroy(This->charSet); __glcFree(This); return NULL; } fontSet = FcFontList(inContext->config, pattern, objectSet); FcObjectSetDestroy(objectSet); FcPatternDestroy(pattern); if (!fontSet) { __glcRaiseError(GLC_RESOURCE_ERROR); FcCharSetDestroy(This->charSet); __glcFree(This); return NULL; } for (i = 0; i < fontSet->nfont; i++) { FcChar8* family = NULL; int fixed = 0; FcChar8* foundry = NULL; FcBool outline = FcFalse; FcBool equal = FcFalse; #ifdef DEBUGMODE FcResult result = FcResultMatch; result = FcPatternGetBool(fontSet->fonts[i], FC_OUTLINE, 0, &outline); assert(result != FcResultTypeMismatch); #else FcPatternGetBool(fontSet->fonts[i], FC_OUTLINE, 0, &outline); #endif /* Check whether the glyphs are outlines */ if (!outline) continue; #ifdef DEBUGMODE result = FcPatternGetString(fontSet->fonts[i], FC_FAMILY, 0, &family); assert(result != FcResultTypeMismatch); result = FcPatternGetString(fontSet->fonts[i], FC_FOUNDRY, 0, &foundry); assert(result != FcResultTypeMismatch); result = FcPatternGetInteger(fontSet->fonts[i], FC_SPACING, 0, &fixed); assert(result != FcResultTypeMismatch); #else FcPatternGetString(fontSet->fonts[i], FC_FAMILY, 0, &family); FcPatternGetString(fontSet->fonts[i], FC_FOUNDRY, 0, &foundry); FcPatternGetInteger(fontSet->fonts[i], FC_SPACING, 0, &fixed); #endif if (foundry) pattern = FcPatternBuild(NULL, FC_FAMILY, FcTypeString, family, FC_FOUNDRY, FcTypeString, foundry, FC_SPACING, FcTypeInteger, fixed, NULL); else pattern = FcPatternBuild(NULL, FC_FAMILY, FcTypeString, family, FC_SPACING, FcTypeInteger, fixed, NULL); if (!pattern) { __glcRaiseError(GLC_RESOURCE_ERROR); FcCharSetDestroy(This->charSet); FcFontSetDestroy(fontSet); __glcFree(This); return NULL; } equal = FcPatternEqual(pattern, inMaster->pattern); FcPatternDestroy(pattern); if (equal) { FcCharSet* newCharSet = NULL; #ifdef DEBUGMODE result = FcPatternGetCharSet(fontSet->fonts[i], FC_CHARSET, 0, &charSet); assert(result != FcResultTypeMismatch); #else FcPatternGetCharSet(fontSet->fonts[i], FC_CHARSET, 0, &charSet); #endif newCharSet = FcCharSetUnion(This->charSet, charSet); if (!newCharSet) { __glcRaiseError(GLC_RESOURCE_ERROR); FcCharSetDestroy(This->charSet); FcFontSetDestroy(fontSet); __glcFree(This); return NULL; } FcCharSetDestroy(This->charSet); This->charSet = newCharSet; } } FcFontSetDestroy(fontSet); } /* The array 'map' will contain the actual character map */ This->map = __glcArrayCreate(sizeof(__GLCcharMapElement)); if (!This->map) { FcCharSetDestroy(This->charSet); __glcFree(This); return NULL; } return This; }
static XftFont *gui_find_font(winlist_t *win, FcChar32 ucs4) { unsigned int i; int weight, slant, scalable; double font_size; FcFontSet *fontset; XftFont *font = NULL; /* 缺字列表有這個字,那就不用再找啦 */ if (FcCharSetHasChar(gui->missing_chars, ucs4)) { return NULL; } /* 找出 Cache 相符的字型 */ for (i=0 ; i < gui->num_fonts ; i++) { XftPatternGetDouble(gui->xftfonts[i]->pattern, XFT_PIXEL_SIZE, 0, &font_size); if ((int)font_size == win->font_size && FcCharSetHasChar(gui->xftfonts[i]->charset, ucs4)) { return gui->xftfonts[i]; } } /* 列出所有可能的字型 */ FcObjectSet *os = FcObjectSetBuild(FC_FAMILY, FC_FILE, FC_INDEX, FC_CHARSET, NULL); /* 只要標準、非斜體、可縮放字型即可 */ FcPattern *listpat = FcPatternBuild(NULL, FC_SLANT, FcTypeInteger, FC_SLANT_ROMAN, FC_SCALABLE, FcTypeBool, FcTrue, NULL); fontset = FcFontList(NULL, listpat, os); FcPatternDestroy(listpat); FcObjectSetDestroy(os); for (i=0; i< fontset->nfont; i++) { FcPattern *pat = fontset->fonts[i]; FcCharSet *fcs = NULL; if (FcPatternGetCharSet(pat, FC_CHARSET, 0, &fcs) != FcResultMatch) continue; if (!FcCharSetHasChar(fcs, ucs4)) continue; FcResult res; FcPattern *mpat = FcFontMatch(0, pat, &res); if (!mpat) continue; XftPatternAddDouble(mpat, XFT_PIXEL_SIZE, (double)win->font_size); XftFont *chkfont = XftFontOpenPattern(gui->display, mpat); if (chkfont) { gui->num_fonts ++; gui->xftfonts = (XftFont **)oxim_realloc(gui->xftfonts, gui->num_fonts * sizeof(XftFont *)); if (!gui->xftfonts) { FcPatternDestroy(mpat); continue; } gui->xftfonts[gui->num_fonts - 1] = chkfont; font = chkfont; break; } else { FcPatternDestroy(mpat); } } FcFontSetDestroy(fontset); if (!font) FcCharSetAddChar(gui->missing_chars, ucs4); return font; }
static UnixFtFont * InitFont( Tk_Window tkwin, FcPattern *pattern, UnixFtFont *fontPtr) { FcFontSet *set; FcCharSet *charset; FcResult result; XftFont *ftFont; int i, iWidth; if (!fontPtr) { fontPtr = ckalloc(sizeof(UnixFtFont)); } FcConfigSubstitute(0, pattern, FcMatchPattern); XftDefaultSubstitute(Tk_Display(tkwin), Tk_ScreenNumber(tkwin), pattern); /* * Generate the list of fonts */ set = FcFontSort(0, pattern, FcTrue, NULL, &result); if (!set) { ckfree(fontPtr); return NULL; } fontPtr->fontset = set; fontPtr->pattern = pattern; fontPtr->faces = ckalloc(set->nfont * sizeof(UnixFtFace)); fontPtr->nfaces = set->nfont; /* * Fill in information about each returned font */ for (i = 0; i < set->nfont; i++) { fontPtr->faces[i].ftFont = 0; fontPtr->faces[i].ft0Font = 0; fontPtr->faces[i].source = set->fonts[i]; if (FcPatternGetCharSet(set->fonts[i], FC_CHARSET, 0, &charset) == FcResultMatch) { fontPtr->faces[i].charset = FcCharSetCopy(charset); } else { fontPtr->faces[i].charset = 0; } fontPtr->faces[i].angle = 0.0; } fontPtr->display = Tk_Display(tkwin); fontPtr->screen = Tk_ScreenNumber(tkwin); fontPtr->ftDraw = 0; fontPtr->color.color.red = 0; fontPtr->color.color.green = 0; fontPtr->color.color.blue = 0; fontPtr->color.color.alpha = 0xffff; fontPtr->color.pixel = 0xffffffff; /* * Fill in platform-specific fields of TkFont. */ ftFont = GetFont(fontPtr, 0, 0.0); fontPtr->font.fid = XLoadFont(Tk_Display(tkwin), "fixed"); GetTkFontAttributes(ftFont, &fontPtr->font.fa); GetTkFontMetrics(ftFont, &fontPtr->font.fm); /* * Fontconfig can't report any information about the position or thickness * of underlines or overstrikes. Thus, we use some defaults that are * hacked around from backup defaults in tkUnixFont.c, which are in turn * based on recommendations in the X manual. The comments from that file * leading to these computations were: * * If the XA_UNDERLINE_POSITION property does not exist, the X manual * recommends using half the descent. * * If the XA_UNDERLINE_THICKNESS property does not exist, the X * manual recommends using the width of the stem on a capital letter. * I don't know of a way to get the stem width of a letter, so guess * and use 1/3 the width of a capital I. * * Note that nothing corresponding to *either* property is reported by * Fontconfig at all. [Bug 1961455] */ { TkFont *fPtr = &fontPtr->font; fPtr->underlinePos = fPtr->fm.descent / 2; Tk_MeasureChars((Tk_Font) fPtr, "I", 1, -1, 0, &iWidth); fPtr->underlineHeight = iWidth / 3; if (fPtr->underlineHeight == 0) { fPtr->underlineHeight = 1; } if (fPtr->underlineHeight + fPtr->underlinePos > fPtr->fm.descent) { fPtr->underlineHeight = fPtr->fm.descent - fPtr->underlinePos; if (fPtr->underlineHeight == 0) { fPtr->underlinePos--; fPtr->underlineHeight = 1; } } } return fontPtr; }