CAMLprim value pattern_font_sort(value plist, value trim) { CAMLparam0(); CAMLlocal2(res, nres); FcPattern *pat; FcFontSet *match; FcResult result; int i; pat = FcPattern_val(plist); FcConfigSubstitute(NULL, pat, FcMatchPattern); FcDefaultSubstitute(pat); match = FcFontSort(NULL, pat, Bool_val(trim) ? FcTrue : FcFalse, NULL, &result); /* Reconstruire la belle liste */ res = Val_int(0); /* empty list */ for(i = match->nfont; i >= 0; i--) { nres = caml_alloc(2, 0); Store_field(nres, 0, caml_copy_pattern(match->fonts[i])); Store_field(nres, 1, res); res = nres; } FcFontSetDestroy(match); FcPatternDestroy(pat); CAMLreturn(res); }
const SimpleFontData* FontCache::getFontDataForCharacters(const Font& font, const UChar* characters, int length) { #if defined(USE_FREETYPE) FcResult fresult; FontPlatformData* prim = const_cast<FontPlatformData*>(&font.primaryFont()->platformData()); if (!prim->m_fallbacks) prim->m_fallbacks = FcFontSort(NULL, prim->m_pattern, FcTrue, NULL, &fresult); FcFontSet* fs = prim->m_fallbacks; for (int i = 0; i < fs->nfont; i++) { FcPattern* fin = FcFontRenderPrepare(NULL, prim->m_pattern, fs->fonts[i]); cairo_font_face_t* fontFace = cairo_ft_font_face_create_for_pattern(fin); FontPlatformData alternateFont(fontFace, font.fontDescription().computedPixelSize(), false, false); cairo_font_face_destroy(fontFace); alternateFont.m_pattern = fin; SimpleFontData* sfd = getCachedFontData(&alternateFont); if (sfd->containsCharacters(characters, length)) return sfd; } #endif return 0; }
static void initfonts(void) { FcResult result; FcPattern *pat = FcPatternCreate(); FcPatternAddString(pat, FC_FAMILY, (uint8_t*)"Roboto"); FcConfigSubstitute(0, pat, FcMatchPattern); FcDefaultSubstitute(pat); fs = FcFontSort(NULL, pat, 0, &charset, &result); FcPatternDestroy(pat); #define F(x) (x * SCALE / 2.0) font[FONT_TEXT][0] = XftFontOpen(display, screen, XFT_FAMILY, XftTypeString, "Roboto", XFT_PIXEL_SIZE, XftTypeDouble, F(12.0), NULL); font[FONT_TITLE][0] = XftFontOpen(display, screen, XFT_FAMILY, XftTypeString, "Roboto", XFT_PIXEL_SIZE, XftTypeDouble, F(12.0), XFT_WEIGHT, XftTypeInteger, FC_WEIGHT_BOLD, NULL); font[FONT_SELF_NAME][0] = XftFontOpen(display, screen, XFT_FAMILY, XftTypeString, "Roboto", XFT_PIXEL_SIZE, XftTypeDouble, F(14.0), XFT_WEIGHT, XftTypeInteger, FC_WEIGHT_BOLD, NULL); font[FONT_STATUS][0] = XftFontOpen(display, screen, XFT_FAMILY, XftTypeString, "Roboto", XFT_PIXEL_SIZE, XftTypeDouble, F(11.0), NULL); font[FONT_LIST_NAME][0] = XftFontOpen(display, screen, XFT_FAMILY, XftTypeString, "Roboto", XFT_PIXEL_SIZE, XftTypeDouble, F(12.0), NULL); font[FONT_MSG][0] = XftFontOpen(display, screen, XFT_FAMILY, XftTypeString, "Roboto", XFT_PIXEL_SIZE, XftTypeDouble, F(11.0), XFT_WEIGHT, XftTypeInteger, FC_WEIGHT_LIGHT, NULL); font[FONT_MSG_NAME][0] = XftFontOpen(display, screen, XFT_FAMILY, XftTypeString, "Roboto", XFT_PIXEL_SIZE, XftTypeDouble, F(10.0), XFT_WEIGHT, XftTypeInteger, FC_WEIGHT_LIGHT, NULL); font[FONT_MISC][0] = XftFontOpen(display, screen, XFT_FAMILY, XftTypeString, "Roboto", XFT_PIXEL_SIZE, XftTypeDouble, F(10.0), NULL); font[FONT_MSG_LINK][0] = font[FONT_MSG][0]; #undef F }
QStringList QFontconfigDatabase::fallbacksForFamily(const QString family, const QFont::Style &style, const QFont::StyleHint &styleHint, const QUnicodeTables::Script &script) const { QStringList fallbackFamilies; FcPattern *pattern = FcPatternCreate(); if (!pattern) return fallbackFamilies; FcValue value; value.type = FcTypeString; QByteArray cs = family.toUtf8(); value.u.s = (const FcChar8 *)cs.data(); FcPatternAdd(pattern,FC_FAMILY,value,true); int slant_value = FC_SLANT_ROMAN; if (style == QFont::StyleItalic) slant_value = FC_SLANT_ITALIC; else if (style == QFont::StyleOblique) slant_value = FC_SLANT_OBLIQUE; FcPatternAddInteger(pattern, FC_SLANT, slant_value); if (script != QUnicodeTables::Common && *specialLanguages[script] != '\0') { Q_ASSERT(script < QUnicodeTables::ScriptCount); FcLangSet *ls = FcLangSetCreate(); FcLangSetAdd(ls, (const FcChar8*)specialLanguages[script]); FcPatternAddLangSet(pattern, FC_LANG, ls); FcLangSetDestroy(ls); } const char *stylehint = getFcFamilyForStyleHint(styleHint); if (stylehint) { value.u.s = (const FcChar8 *)stylehint; FcPatternAddWeak(pattern, FC_FAMILY, value, FcTrue); } FcConfigSubstitute(0, pattern, FcMatchPattern); FcDefaultSubstitute(pattern); FcResult result = FcResultMatch; FcFontSet *fontSet = FcFontSort(0,pattern,FcFalse,0,&result); FcPatternDestroy(pattern); if (fontSet) { for (int i = 0; i < fontSet->nfont; i++) { FcChar8 *value = 0; if (FcPatternGetString(fontSet->fonts[i], FC_FAMILY, 0, &value) != FcResultMatch) continue; // capitalize(value); QString familyName = QString::fromUtf8((const char *)value); if (!fallbackFamilies.contains(familyName,Qt::CaseInsensitive)) { fallbackFamilies << familyName; } } FcFontSetDestroy(fontSet); } // qDebug() << "fallbackFamilies for:" << family << fallbackFamilies; return fallbackFamilies; }
// This method just need to bypass the cache as we could register our alternative font. // This is a pity but is required to have asian fonts working. PassRefPtr<SimpleFontData> FontCache::getFontDataForCharacters(const Font& font, const UChar* characters, int length) { // Avoid copying FontPlatformData. RefPtr<FontPlatformData> primaryFontPlatformData = font.primaryFont()->m_font; // Check if the cache was already filled. if (fallbacks.contains(&font)) { ASSERT(primaryFontPlatformData->m_fallbacks); FontFallbackCache::iterator it = fallbacks.find(&font); return it->second; } if (!primaryFontPlatformData->m_fallbacks) { FcResult fresult; primaryFontPlatformData->m_fallbacks = FcFontSort(NULL, primaryFontPlatformData->m_pattern, FcTrue, NULL, &fresult); } FcFontSet* fs = primaryFontPlatformData->m_fallbacks; for (int i = 0; i < fs->nfont; i++) { FcPattern* fin = FcFontRenderPrepare(0, primaryFontPlatformData->m_pattern, fs->fonts[i]); FcChar8* fc_filename; if (FcPatternGetString(fin, FC_FILE, 0, &fc_filename) != FcResultMatch) continue; char* filename = (char *) fc_filename; // Use C cast as FcChar is a fontconfig type. int id; if (FcPatternGetInteger(fin, FC_INDEX, 0, &id) != FcResultMatch) continue; FT_Face face; if (FT_Error error = FT_New_Face(FontPlatformData::m_library, filename, id, &face)) { printf("FT_New_Face failed for filename = %s with FT_Error = %d\n", filename, error); continue; } // FIXME: is it really necessary ? FT_Set_Pixel_Sizes(face, 0, static_cast<uint> (font.fontDescription().computedSize())); RefPtr<FontPlatformData> platformData = adoptRef(new FontPlatformData(face, font.fontDescription().computedPixelSize(), false, false)); platformData->m_pattern = fin; if (platformData->containsCharacters(characters, length)) { RefPtr<SimpleFontData> fontData = adoptRef(new SimpleFontData(platformData.get())); fallbacks.add(&font, fontData); return fontData; } } // Fallback: use the font in the main cache. RefPtr<SimpleFontData> fontData = getCachedFontData(font.fontDescription(), font.family().family()); return fontData; }
FcPattern* findBestFontGivenFallbacks(const FontPlatformData& fontData, FcPattern* pattern) { if (!fontData.m_pattern) return 0; if (!fontData.m_fallbacks) { FcResult fontConfigResult; fontData.m_fallbacks = FcFontSort(0, fontData.m_pattern.get(), FcTrue, 0, &fontConfigResult); } if (!fontData.m_fallbacks) return 0; FcFontSet* sets[] = { fontData.m_fallbacks }; FcResult fontConfigResult; return FcFontSetMatch(0, sets, 1, pattern, &fontConfigResult); }
static RefPtr<FcPattern> findBestFontGivenFallbacks(const FontPlatformData& fontData, FcPattern* pattern) { if (!fontData.m_pattern) return nullptr; if (!fontData.m_fallbacks) { FcResult fontConfigResult; fontData.m_fallbacks = FcFontSort(nullptr, fontData.m_pattern.get(), FcTrue, nullptr, &fontConfigResult); } if (!fontData.m_fallbacks) return nullptr; FcFontSet* sets[] = { fontData.m_fallbacks }; FcResult fontConfigResult; return FcFontSetMatch(nullptr, sets, 1, pattern, &fontConfigResult); }
const SimpleFontData* FontCache::getFontDataForCharacters(const Font& font, const UChar* characters, int length) { FcResult fresult; // Avoid copying FontPlatformData. FontPlatformData* prim = const_cast<FontPlatformData*>(&font.primaryFont()->m_font); if (!prim->m_fallbacks) prim->m_fallbacks = FcFontSort(NULL, prim->m_pattern, FcTrue, NULL, &fresult); FcFontSet* fs = prim->m_fallbacks; FT_Library library = FontPlatformData::m_library; FcChar8* fc_filename; char* filename; int id; FT_Face face; for (int i = 0; i < fs->nfont; i++) { FcPattern* fin = FcFontRenderPrepare(0, prim->m_pattern, fs->fonts[i]); if (FcPatternGetString(fin, FC_FILE, 0, &fc_filename) != FcResultMatch) continue; filename = (char *) fc_filename; // Use C cast as FcChar is a fontconfig type. if (FcPatternGetInteger(fin, FC_INDEX, 0, &id) != FcResultMatch) continue; if (FT_Error error = FT_New_Face(library, filename, id, &face)) continue; // FIXME: is it really necessary ? FT_Set_Pixel_Sizes(face, 0, static_cast<uint> (font.fontDescription().computedSize())); FontPlatformData alternateFont(face, font.fontDescription().computedPixelSize(), false, false); // FIXME: FT_Done_Face(face); we should clean the face correctly the FT_Face but we can't do that here... alternateFont.m_pattern = fin; SimpleFontData* sfd = getCachedFontData(&alternateFont); if (sfd->containsCharacters(characters, length)) return sfd; } return 0; }
bool SkFontConfigInterfaceDirect::matchFamilySet(const char inFamilyName[], SkString* outFamilyName, SkTArray<FontIdentity>* ids) { SkAutoMutexAcquire ac(mutex_); #if 0 SkString familyStr(familyName ? familyName : ""); if (familyStr.size() > kMaxFontFamilyLength) { return false; } SkAutoMutexAcquire ac(mutex_); FcPattern* pattern = FcPatternCreate(); if (familyName) { FcPatternAddString(pattern, FC_FAMILY, (FcChar8*)familyName); } FcPatternAddBool(pattern, FC_SCALABLE, FcTrue); FcConfigSubstitute(NULL, pattern, FcMatchPattern); FcDefaultSubstitute(pattern); // Font matching: // CSS often specifies a fallback list of families: // font-family: a, b, c, serif; // However, fontconfig will always do its best to find *a* font when asked // for something so we need a way to tell if the match which it has found is // "good enough" for us. Otherwise, we can return NULL which gets piped up // and lets WebKit know to try the next CSS family name. However, fontconfig // configs allow substitutions (mapping "Arial -> Helvetica" etc) and we // wish to support that. // // Thus, if a specific family is requested we set @family_requested. Then we // record two strings: the family name after config processing and the // family name after resolving. If the two are equal, it's a good match. // // So consider the case where a user has mapped Arial to Helvetica in their // config. // requested family: "Arial" // post_config_family: "Helvetica" // post_match_family: "Helvetica" // -> good match // // and for a missing font: // requested family: "Monaco" // post_config_family: "Monaco" // post_match_family: "Times New Roman" // -> BAD match // // However, we special-case fallback fonts; see IsFallbackFontAllowed(). const char* post_config_family = get_name(pattern, FC_FAMILY); FcResult result; FcFontSet* font_set = FcFontSort(0, pattern, 0, 0, &result); if (!font_set) { FcPatternDestroy(pattern); return false; } FcPattern* match = MatchFont(font_set, post_config_family, familyStr); if (!match) { FcPatternDestroy(pattern); FcFontSetDestroy(font_set); return false; } FcPatternDestroy(pattern); // From here out we just extract our results from 'match' if (FcPatternGetString(match, FC_FAMILY, 0, &post_config_family) != FcResultMatch) { FcFontSetDestroy(font_set); return false; } FcChar8* c_filename; if (FcPatternGetString(match, FC_FILE, 0, &c_filename) != FcResultMatch) { FcFontSetDestroy(font_set); return false; } int face_index; if (FcPatternGetInteger(match, FC_INDEX, 0, &face_index) != FcResultMatch) { FcFontSetDestroy(font_set); return false; } FcFontSetDestroy(font_set); if (outIdentity) { outIdentity->fTTCIndex = face_index; outIdentity->fString.set((const char*)c_filename); } if (outFamilyName) { outFamilyName->set((const char*)post_config_family); } if (outStyle) { *outStyle = GetFontStyle(match); } return true; //////////////////// int count; FcPattern** match = MatchFont(font_set, post_config_family, &count); if (!match) { FcPatternDestroy(pattern); FcFontSetDestroy(font_set); return NULL; } FcPatternDestroy(pattern); SkTDArray<FcPattern*> trimmedMatches; for (int i = 0; i < count; ++i) { const char* justName = find_just_name(get_name(match[i], FC_FILE)); if (!is_lower(*justName)) { *trimmedMatches.append() = match[i]; } } SkFontStyleSet_FC* sset = new SkFontStyleSet_FC (trimmedMatches.begin(), trimmedMatches.count()); #endif return false; }
bool SkFontConfigInterfaceDirect::matchFamilyName(const char familyName[], SkTypeface::Style style, FontIdentity* outIdentity, SkString* outFamilyName, SkTypeface::Style* outStyle) { SkString familyStr(familyName ? familyName : ""); if (familyStr.size() > kMaxFontFamilyLength) { return false; } SkAutoMutexAcquire ac(mutex_); FcPattern* pattern = FcPatternCreate(); if (familyName) { FcPatternAddString(pattern, FC_FAMILY, (FcChar8*)familyName); } FcPatternAddInteger(pattern, FC_WEIGHT, (style & SkTypeface::kBold) ? FC_WEIGHT_BOLD : FC_WEIGHT_NORMAL); FcPatternAddInteger(pattern, FC_SLANT, (style & SkTypeface::kItalic) ? FC_SLANT_ITALIC : FC_SLANT_ROMAN); FcPatternAddBool(pattern, FC_SCALABLE, FcTrue); FcConfigSubstitute(NULL, pattern, FcMatchPattern); FcDefaultSubstitute(pattern); // Font matching: // CSS often specifies a fallback list of families: // font-family: a, b, c, serif; // However, fontconfig will always do its best to find *a* font when asked // for something so we need a way to tell if the match which it has found is // "good enough" for us. Otherwise, we can return NULL which gets piped up // and lets WebKit know to try the next CSS family name. However, fontconfig // configs allow substitutions (mapping "Arial -> Helvetica" etc) and we // wish to support that. // // Thus, if a specific family is requested we set @family_requested. Then we // record two strings: the family name after config processing and the // family name after resolving. If the two are equal, it's a good match. // // So consider the case where a user has mapped Arial to Helvetica in their // config. // requested family: "Arial" // post_config_family: "Helvetica" // post_match_family: "Helvetica" // -> good match // // and for a missing font: // requested family: "Monaco" // post_config_family: "Monaco" // post_match_family: "Times New Roman" // -> BAD match // // However, we special-case fallback fonts; see IsFallbackFontAllowed(). const char* post_config_family = get_name(pattern, FC_FAMILY); if (!post_config_family) { // we can just continue with an empty name, e.g. default font post_config_family = ""; } FcResult result; FcFontSet* font_set = FcFontSort(0, pattern, 0, 0, &result); if (!font_set) { FcPatternDestroy(pattern); return false; } FcPattern* match = MatchFont(font_set, post_config_family, familyStr); if (!match) { FcPatternDestroy(pattern); FcFontSetDestroy(font_set); return false; } FcPatternDestroy(pattern); // From here out we just extract our results from 'match' post_config_family = get_name(match, FC_FAMILY); if (!post_config_family) { FcFontSetDestroy(font_set); return false; } const char* c_filename = get_name(match, FC_FILE); if (!c_filename) { FcFontSetDestroy(font_set); return false; } int face_index; if (FcPatternGetInteger(match, FC_INDEX, 0, &face_index) != FcResultMatch) { FcFontSetDestroy(font_set); return false; } FcFontSetDestroy(font_set); if (outIdentity) { outIdentity->fTTCIndex = face_index; outIdentity->fString.set(c_filename); } if (outFamilyName) { outFamilyName->set(post_config_family); } if (outStyle) { *outStyle = GetFontStyle(match); } return true; }
/** * \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; }
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; }
/** * \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; }
vlc_family_t *FontConfig_GetFallbacks( filter_t *p_filter, const char *psz_family, uni_char_t codepoint ) { VLC_UNUSED( codepoint ); vlc_family_t *p_family = NULL; filter_sys_t *p_sys = p_filter->p_sys; char *psz_lc = ToLower( psz_family ); if( unlikely( !psz_lc ) ) return NULL; p_family = vlc_dictionary_value_for_key( &p_sys->fallback_map, psz_lc ); if( p_family != kVLCDictionaryNotFound ) { free( psz_lc ); return p_family; } else p_family = NULL; const char *psz_last_name = ""; FcPattern *p_pattern = FcPatternCreate(); FcValue family; family.type = FcTypeString; family.u.s = ( const FcChar8* ) psz_family; FcPatternAdd( p_pattern, FC_FAMILY, family, FcFalse ); if( FcConfigSubstitute( NULL, p_pattern, FcMatchPattern ) == FcTrue ) { FcDefaultSubstitute( p_pattern ); FcResult result; FcFontSet* p_font_set = FcFontSort( NULL, p_pattern, FcTrue, NULL, &result ); if( p_font_set ) { for( int i = 0; i < p_font_set->nfont; ++i ) { char* psz_name = NULL; FcPatternGetString( p_font_set->fonts[i], FC_FAMILY, 0, ( FcChar8** )( &psz_name ) ); /* Avoid duplicate family names */ if( strcasecmp( psz_last_name, psz_name ) ) { vlc_family_t *p_temp = NewFamily( p_filter, psz_name, &p_family, NULL, NULL ); if( unlikely( !p_temp ) ) { FcFontSetDestroy( p_font_set ); FcPatternDestroy( p_pattern ); if( p_family ) FreeFamilies( p_family, NULL ); free( psz_lc ); return NULL; } psz_last_name = p_temp->psz_name; } } FcFontSetDestroy( p_font_set ); } } FcPatternDestroy( p_pattern ); if( p_family ) vlc_dictionary_insert( &p_sys->fallback_map, psz_lc, p_family ); free( psz_lc ); return p_family; }
QStringList QFontconfigDatabase::fallbacksForFamily(const QString &family, QFont::Style style, QFont::StyleHint styleHint, QChar::Script script) const { QStringList fallbackFamilies; FcPattern *pattern = FcPatternCreate(); if (!pattern) return fallbackFamilies; FcValue value; value.type = FcTypeString; QByteArray cs = family.toUtf8(); value.u.s = (const FcChar8 *)cs.data(); FcPatternAdd(pattern,FC_FAMILY,value,true); int slant_value = FC_SLANT_ROMAN; if (style == QFont::StyleItalic) slant_value = FC_SLANT_ITALIC; else if (style == QFont::StyleOblique) slant_value = FC_SLANT_OBLIQUE; FcPatternAddInteger(pattern, FC_SLANT, slant_value); Q_ASSERT(uint(script) < QChar::ScriptCount); if (*specialLanguages[script] != '\0') { FcLangSet *ls = FcLangSetCreate(); FcLangSetAdd(ls, (const FcChar8*)specialLanguages[script]); FcPatternAddLangSet(pattern, FC_LANG, ls); FcLangSetDestroy(ls); } else if (!family.isEmpty()) { // If script is Common or Han, then it may include languages like CJK, // we should attach system default language set to the pattern // to obtain correct font fallback list (i.e. if LANG=zh_CN // then we normally want to use a Chinese font for CJK text; // while a Japanese font should be used for that if LANG=ja) FcPattern *dummy = FcPatternCreate(); FcDefaultSubstitute(dummy); FcChar8 *lang = 0; FcResult res = FcPatternGetString(dummy, FC_LANG, 0, &lang); if (res == FcResultMatch) FcPatternAddString(pattern, FC_LANG, lang); FcPatternDestroy(dummy); } const char *stylehint = getFcFamilyForStyleHint(styleHint); if (stylehint) { value.u.s = (const FcChar8 *)stylehint; FcPatternAddWeak(pattern, FC_FAMILY, value, FcTrue); } FcConfigSubstitute(0, pattern, FcMatchPattern); FcDefaultSubstitute(pattern); FcResult result = FcResultMatch; FcFontSet *fontSet = FcFontSort(0,pattern,FcFalse,0,&result); FcPatternDestroy(pattern); if (fontSet) { for (int i = 0; i < fontSet->nfont; i++) { FcChar8 *value = 0; if (FcPatternGetString(fontSet->fonts[i], FC_FAMILY, 0, &value) != FcResultMatch) continue; // capitalize(value); QString familyName = QString::fromUtf8((const char *)value); if (!fallbackFamilies.contains(familyName,Qt::CaseInsensitive) && familyName.compare(family, Qt::CaseInsensitive)) { fallbackFamilies << familyName; } } FcFontSetDestroy(fontSet); } // qDebug() << "fallbackFamilies for:" << family << style << styleHint << script << fallbackFamilies; return fallbackFamilies; }
void WebFontInfo::fallbackFontForChar(WebUChar32 c, const char* preferredLocale, WebFallbackFont* fallbackFont) { FcCharSet* cset = FcCharSetCreate(); FcCharSetAddChar(cset, c); FcPattern* pattern = FcPatternCreate(); FcValue fcvalue; fcvalue.type = FcTypeCharSet; fcvalue.u.c = cset; FcPatternAdd(pattern, FC_CHARSET, fcvalue, FcFalse); fcvalue.type = FcTypeBool; fcvalue.u.b = FcTrue; FcPatternAdd(pattern, FC_SCALABLE, fcvalue, FcFalse); if (preferredLocale) { FcLangSet* langset = FcLangSetCreate(); FcLangSetAdd(langset, reinterpret_cast<const FcChar8 *>(preferredLocale)); FcPatternAddLangSet(pattern, FC_LANG, langset); FcLangSetDestroy(langset); } FcConfigSubstitute(0, pattern, FcMatchPattern); FcDefaultSubstitute(pattern); FcResult result; FcFontSet* fontSet = FcFontSort(0, pattern, 0, 0, &result); FcPatternDestroy(pattern); FcCharSetDestroy(cset); if (!fontSet) { fallbackFont->name = WebCString(); fallbackFont->isBold = false; fallbackFont->isItalic = false; return; } // Older versions of fontconfig have a bug where they cannot select // only scalable fonts so we have to manually filter the results. for (int i = 0; i < fontSet->nfont; ++i) { FcPattern* current = fontSet->fonts[i]; FcBool isScalable; if (FcPatternGetBool(current, FC_SCALABLE, 0, &isScalable) != FcResultMatch || !isScalable) continue; // fontconfig can also return fonts which are unreadable FcChar8* cFilename; if (FcPatternGetString(current, FC_FILE, 0, &cFilename) != FcResultMatch) continue; if (access(reinterpret_cast<char*>(cFilename), R_OK)) continue; const char* fontFilename = reinterpret_cast<char*>(cFilename); fallbackFont->filename = WebCString(fontFilename, strlen(fontFilename)); // Index into font collection. int ttcIndex; if (FcPatternGetInteger(current, FC_INDEX, 0, &ttcIndex) != FcResultMatch && ttcIndex < 0) continue; fallbackFont->ttcIndex = ttcIndex; FcChar8* familyName; if (FcPatternGetString(current, FC_FAMILY, 0, &familyName) == FcResultMatch) { const char* charFamily = reinterpret_cast<char*>(familyName); fallbackFont->name = WebCString(charFamily, strlen(charFamily)); } int weight; if (FcPatternGetInteger(current, FC_WEIGHT, 0, &weight) == FcResultMatch) fallbackFont->isBold = weight >= FC_WEIGHT_BOLD; else fallbackFont->isBold = false; int slant; if (FcPatternGetInteger(current, FC_SLANT, 0, &slant) == FcResultMatch) fallbackFont->isItalic = slant != FC_SLANT_ROMAN; else fallbackFont->isItalic = false; FcFontSetDestroy(fontSet); return; } FcFontSetDestroy(fontSet); }
bool FontConfigDirect::Match(std::string* result_family, unsigned* result_filefaceid, bool filefaceid_valid, unsigned filefaceid, const std::string& family, const void* data, size_t characters_bytes, bool* is_bold, bool* is_italic) { if (family.length() > kMaxFontFamilyLength) return false; SkAutoMutexAcquire ac(mutex_); // Given |family|, |is_bold| and |is_italic| but not |data|, the result will // be a function of these three parameters, and thus eligible for caching. // This is the fast path for |SkTypeface::CreateFromName()|. bool eligible_for_cache = !family.empty() && is_bold && is_italic && !data; if (eligible_for_cache) { int style = (*is_bold ? SkTypeface::kBold : 0 ) | (*is_italic ? SkTypeface::kItalic : 0); FontMatchKey key = FontMatchKey(family, style); const std::map<FontMatchKey, FontMatch>::const_iterator i = font_match_cache_.find(key); if (i != font_match_cache_.end()) { *is_bold = i->second.is_bold; *is_italic = i->second.is_italic; if (result_family) *result_family = i->second.family; if (result_filefaceid) *result_filefaceid = i->second.filefaceid; return true; } } FcPattern* pattern = FcPatternCreate(); if (filefaceid_valid) { const std::map<unsigned, std::string>::const_iterator i = fileid_to_filename_.find(FileFaceIdToFileId(filefaceid)); if (i == fileid_to_filename_.end()) { FcPatternDestroy(pattern); return false; } int face_index = filefaceid & 0xfu; FcPatternAddString(pattern, FC_FILE, reinterpret_cast<const FcChar8*>(i->second.c_str())); // face_index is added only when family is empty because it is not // necessary to uniquiely identify a font if both file and // family are given. if (family.empty()) FcPatternAddInteger(pattern, FC_INDEX, face_index); } if (!family.empty()) { FcPatternAddString(pattern, FC_FAMILY, (FcChar8*) family.c_str()); } FcCharSet* charset = NULL; if (data) { charset = FcCharSetCreate(); const uint16_t* chars = (const uint16_t*) data; size_t num_chars = characters_bytes / 2; for (size_t i = 0; i < num_chars; ++i) { if (U16_IS_SURROGATE(chars[i]) && U16_IS_SURROGATE_LEAD(chars[i]) && i != num_chars - 1 && U16_IS_TRAIL(chars[i + 1])) { FcCharSetAddChar(charset, U16_GET_SUPPLEMENTARY(chars[i], chars[i+1])); i++; } else { FcCharSetAddChar(charset, chars[i]); } } FcPatternAddCharSet(pattern, FC_CHARSET, charset); FcCharSetDestroy(charset); // pattern now owns it. } FcPatternAddInteger(pattern, FC_WEIGHT, is_bold && *is_bold ? FC_WEIGHT_BOLD : FC_WEIGHT_NORMAL); FcPatternAddInteger(pattern, FC_SLANT, is_italic && *is_italic ? FC_SLANT_ITALIC : FC_SLANT_ROMAN); FcPatternAddBool(pattern, FC_SCALABLE, FcTrue); FcConfigSubstitute(NULL, pattern, FcMatchPattern); FcDefaultSubstitute(pattern); // Font matching: // CSS often specifies a fallback list of families: // font-family: a, b, c, serif; // However, fontconfig will always do its best to find *a* font when asked // for something so we need a way to tell if the match which it has found is // "good enough" for us. Otherwise, we can return NULL which gets piped up // and lets WebKit know to try the next CSS family name. However, fontconfig // configs allow substitutions (mapping "Arial -> Helvetica" etc) and we // wish to support that. // // Thus, if a specific family is requested we set @family_requested. Then we // record two strings: the family name after config processing and the // family name after resolving. If the two are equal, it's a good match. // // So consider the case where a user has mapped Arial to Helvetica in their // config. // requested family: "Arial" // post_config_family: "Helvetica" // post_match_family: "Helvetica" // -> good match // // and for a missing font: // requested family: "Monaco" // post_config_family: "Monaco" // post_match_family: "Times New Roman" // -> BAD match // // However, we special-case fallback fonts; see IsFallbackFontAllowed(). FcChar8* post_config_family; FcPatternGetString(pattern, FC_FAMILY, 0, &post_config_family); FcResult result; FcFontSet* font_set = FcFontSort(0, pattern, 0, 0, &result); if (!font_set) { FcPatternDestroy(pattern); return false; } FcPattern* match = MatchFont(font_set, post_config_family, family); if (!match) { FcPatternDestroy(pattern); FcFontSetDestroy(font_set); return false; } FcPatternDestroy(pattern); FcChar8* c_filename; if (FcPatternGetString(match, FC_FILE, 0, &c_filename) != FcResultMatch) { FcFontSetDestroy(font_set); return false; } int face_index; if (FcPatternGetInteger(match, FC_INDEX, 0, &face_index) != FcResultMatch) { FcFontSetDestroy(font_set); return false; } FontMatch font_match; if (filefaceid_valid) { font_match.filefaceid = filefaceid; } else { unsigned out_fileid; const std::string filename(reinterpret_cast<char*>(c_filename)); const std::map<std::string, unsigned>::const_iterator i = filename_to_fileid_.find(filename); if (i == filename_to_fileid_.end()) { out_fileid = next_file_id_++; filename_to_fileid_[filename] = out_fileid; fileid_to_filename_[out_fileid] = filename; } else { out_fileid = i->second; } // fileid stored in filename_to_fileid_ and fileid_to_filename_ is // unique only up to the font file. We have to encode face_index for // the out param. font_match.filefaceid = FileIdAndFaceIndexToFileFaceId(out_fileid, face_index); } bool success = GetFontProperties(match, &font_match.family, &font_match.is_bold, &font_match.is_italic); FcFontSetDestroy(font_set); if (success) { // If eligible, cache the result of the matching. if (eligible_for_cache) { int style = (*is_bold ? SkTypeface::kBold : 0 ) | (*is_italic ? SkTypeface::kItalic : 0); font_match_cache_[FontMatchKey(family, style)] = font_match; } if (result_family) *result_family = font_match.family; if (result_filefaceid) *result_filefaceid = font_match.filefaceid; if (is_bold) *is_bold = font_match.is_bold; if (is_italic) *is_italic = font_match.is_italic; } return success; }
int main (int argc, char **argv) { int verbose = 0; int sort = 0, all = 0; const FcChar8 *format = NULL; int i; FcObjectSet *os = 0; FcFontSet *fs; FcPattern *pat; FcResult result; #if HAVE_GETOPT_LONG || HAVE_GETOPT int c; #if HAVE_GETOPT_LONG while ((c = getopt_long (argc, argv, "asvf:Vh", longopts, NULL)) != -1) #else while ((c = getopt (argc, argv, "asvf:Vh")) != -1) #endif { switch (c) { case 'a': all = 1; break; case 's': sort = 1; break; case 'v': verbose = 1; break; case 'f': format = (FcChar8 *) strdup (optarg); break; case 'V': fprintf (stderr, "fontconfig version %d.%d.%d\n", FC_MAJOR, FC_MINOR, FC_REVISION); exit (0); case 'h': usage (argv[0], 0); default: usage (argv[0], 1); } } i = optind; #else i = 1; #endif if (!FcInit ()) { fprintf (stderr, "Can't init font config library\n"); return 1; } if (argv[i]) { pat = FcNameParse ((FcChar8 *) argv[i]); while (argv[++i]) { if (!os) os = FcObjectSetCreate (); FcObjectSetAdd (os, argv[i]); } } else pat = FcPatternCreate (); if (!pat) return 1; FcConfigSubstitute (0, pat, FcMatchPattern); FcDefaultSubstitute (pat); fs = FcFontSetCreate (); if (sort || all) { FcFontSet *font_patterns; int j; font_patterns = FcFontSort (0, pat, all ? FcFalse : FcTrue, 0, &result); if (!font_patterns || font_patterns->nfont == 0) { fputs("No fonts installed on the system\n", stderr); return 1; } for (j = 0; j < font_patterns->nfont; j++) { FcPattern *font_pattern; font_pattern = FcFontRenderPrepare (NULL, pat, font_patterns->fonts[j]); if (font_pattern) FcFontSetAdd (fs, font_pattern); } FcFontSetSortDestroy (font_patterns); } else { FcPattern *match; match = FcFontMatch (0, pat, &result); if (match) FcFontSetAdd (fs, match); } FcPatternDestroy (pat); if (!format) { if (os) format = (const FcChar8 *) "%{=unparse}\n"; else format = (const FcChar8 *) "%{=fcmatch}\n"; } if (fs) { int j; for (j = 0; j < fs->nfont; j++) { FcPattern *font; font = FcPatternFilter (fs->fonts[j], os); if (verbose) { FcPatternPrint (font); } else { FcChar8 *s; s = FcPatternFormat (font, format); if (s) { printf ("%s", s); free (s); } } FcPatternDestroy (font); } FcFontSetDestroy (fs); } if (os) FcObjectSetDestroy (os); FcFini (); return 0; }
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; }
Common::SeekableReadStream *FontconfigFontProvider::createReadStreamForFont(const Common::String &name, uint32 style) { if (!_config) return 0; Common::String styleName = makeStyleString(style); FcPattern *pattern = FcPatternCreate(); // Match on the family name FcValue value; value.type = FcTypeString; value.u.s = reinterpret_cast<const FcChar8 *>(name.c_str()); if (!FcPatternAdd(pattern, FC_FAMILY, value, FcFalse)) { FcPatternDestroy(pattern); return 0; } // Match on the style string value.u.s = reinterpret_cast<const FcChar8 *>(styleName.c_str()); if (!FcPatternAdd(pattern, FC_STYLE, value, FcFalse)) { FcPatternDestroy(pattern); return 0; } // Only allow TrueType fonts // Might change in the future. value.u.s = reinterpret_cast<const FcChar8 *>("TrueType"); if (!FcPatternAdd(pattern, FC_FONTFORMAT, value, FcFalse)) { FcPatternDestroy(pattern); return 0; } // Call these functions // Might be doing pattern matching. Documentation is awful. FcConfigSubstitute(0, pattern, FcMatchPattern); FcDefaultSubstitute(pattern); // Fetch the match FcResult result; FcFontSet* fontSet = FcFontSort(0, pattern, 0, 0, &result); FcPatternDestroy(pattern); if (!fontSet) return 0; for (int i = 0; i < fontSet->nfont; i++) { FcPattern *foundPattern = fontSet->fonts[i]; // Get the family name of the font FcChar8 *familyName; if (FcPatternGetString(foundPattern, FC_FAMILY, 0, &familyName) != FcResultMatch) continue; // If we don't actually match, bail out. We don't want to end // up with the default fontconfig font, which would look horrible. if (!name.equalsIgnoreCase(reinterpret_cast<const char *>(familyName))) continue; // Get the name of the font FcChar8 *fileName; if (FcPatternGetString(foundPattern, FC_FILE, 0, &fileName) != FcResultMatch) continue; // Let's make sure we can actually get that Common::FSNode fontNode(reinterpret_cast<const char *>(fileName)); if (!fontNode.exists() || !fontNode.isReadable()) continue; debug(1, "Matched %s %s -> '%s'", name.c_str(), styleName.c_str(), fontNode.getPath().c_str()); FcFontSetDestroy(fontSet); return fontNode.createReadStream(); } // We ain't found s#&t FcFontSetDestroy(fontSet); return 0; }
int main (int argc, char **argv) { int verbose = 0; int sort = 0; int i; FcFontSet *fs; FcPattern *pat; FcResult result; #if HAVE_GETOPT_LONG || HAVE_GETOPT int c; #if HAVE_GETOPT_LONG while ((c = getopt_long (argc, argv, "Vv?", longopts, NULL)) != -1) #else while ((c = getopt (argc, argv, "sVv?")) != -1) #endif { switch (c) { case 's': sort = 1; break; case 'V': fprintf (stderr, "fontconfig version %d.%d.%d\n", FC_MAJOR, FC_MINOR, FC_REVISION); exit (0); case 'v': verbose = 1; break; default: usage (argv[0]); } } i = optind; #else i = 1; #endif if (!FcInit ()) { fprintf (stderr, "Can't init font config library\n"); return 1; } if (argv[i]) pat = FcNameParse ((FcChar8 *) argv[i]); else pat = FcPatternCreate (); FcConfigSubstitute (0, pat, FcMatchPattern); FcDefaultSubstitute (pat); if (sort) fs = FcFontSort (0, pat, FcTrue, 0, &result); else { FcPattern *match; fs = FcFontSetCreate (); match = FcFontMatch (0, pat, &result); if (match) FcFontSetAdd (fs, match); } if (pat) FcPatternDestroy (pat); if (fs) { int j; for (j = 0; j < fs->nfont; j++) { if (verbose) { FcPatternPrint (fs->fonts[j]); } else { FcChar8 *family; FcChar8 *style; FcChar8 *file; if (FcPatternGetString (fs->fonts[j], FC_FILE, 0, &file) != FcResultMatch) file = "<unknown filename>"; else { FcChar8 *slash = strrchr (file, '/'); if (slash) file = slash+1; } if (FcPatternGetString (fs->fonts[j], FC_FAMILY, 0, &family) != FcResultMatch) family = "<unknown family>"; if (FcPatternGetString (fs->fonts[j], FC_STYLE, 0, &style) != FcResultMatch) file = "<unknown style>"; printf ("%s: \"%s\" \"%s\"\n", file, family, style); } } FcFontSetDestroy (fs); } return 0; }