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; }
void find_font(font & f, std::string const& name, int height, int weight, int style) { // FIXME: shouldn't require fonts to be empty BOOST_ASSERT(!f); FcValue fcval; // build pattern FcPattern * pattern = FcPatternCreate(); // typeface name fcval.type = FcTypeString; fcval.u.s = (FcChar8 const*) name.c_str(); FcPatternAdd(pattern, FC_FAMILY, fcval, FcTrue); // pixel size fcval.type = FcTypeInteger; fcval.u.i = height; FcPatternAdd(pattern, FC_PIXEL_SIZE, fcval, FcTrue); // italic if (style & font_style::italic) { fcval.type = FcTypeInteger; fcval.u.i = FC_SLANT_ITALIC; FcPatternAdd(pattern, FC_SLANT, fcval, FcTrue); } // weight fcval.type = FcTypeInteger; switch (weight) { case font_weight::thin: fcval.u.i = FC_WEIGHT_THIN; break; case font_weight::extra_light: fcval.u.i = FC_WEIGHT_EXTRALIGHT; break; case font_weight::light: fcval.u.i = FC_WEIGHT_LIGHT; break; case font_weight::normal: fcval.u.i = FC_WEIGHT_NORMAL; break; case font_weight::medium: fcval.u.i = FC_WEIGHT_MEDIUM; break; case font_weight::semi_bold: fcval.u.i = FC_WEIGHT_SEMIBOLD; break; case font_weight::bold: fcval.u.i = FC_WEIGHT_BOLD; break; case font_weight::ultra_bold: fcval.u.i = FC_WEIGHT_ULTRABOLD; break; case font_weight::heavy: fcval.u.i = FC_WEIGHT_HEAVY; break; default: fcval.u.i = FC_WEIGHT_NORMAL; break; }; FcPatternAdd(pattern, FC_WEIGHT, fcval, FcTrue); // transform pattern FcConfigSubstitute(NULL, pattern, FcMatchPattern); FcDefaultSubstitute(pattern); FcResult res; FcPattern * real_pattern = FcFontMatch(NULL, pattern, &res); FcPatternDestroy(pattern); // get filename if (real_pattern) { char * fname; int id; FcPatternGetString(real_pattern, FC_FILE, 0, (FcChar8 **) &fname); FcPatternGetInteger(real_pattern, FC_INDEX, 0, &id); // load font FT_Face face; if (FT_New_Face(::ftlib, fname, id, &face)) return; FcPatternDestroy(real_pattern); // create font ft_font_extra * extra = static_cast<ft_font_extra *>(f.extra_data); extra->face = face; FT_Set_Pixel_Sizes(face, 0, height); // get avg char width/height point pt = detail::font_units_to_pixels(face, face->max_advance_width, face->max_advance_height); extra->width = pt.x; extra->height = pt.y; pt = detail::font_units_to_pixels(face, 0, face->ascender); extra->ascender = pt.y; pt = detail::font_units_to_pixels(face, 0, face->descender); extra->descender = pt.y; } }
static cairo_status_t create_scaled_font (cairo_t * cr, cairo_scaled_font_t **out) { FcPattern *pattern, *resolved; FcResult result; cairo_font_face_t *font_face; cairo_scaled_font_t *scaled_font; cairo_font_options_t *font_options; cairo_matrix_t font_matrix, ctm; cairo_status_t status; double pixel_size; font_options = cairo_font_options_create (); cairo_get_font_options (cr, font_options); pattern = FcPatternCreate (); if (pattern == NULL) return CAIRO_STATUS_NO_MEMORY; FcPatternAddString (pattern, FC_FAMILY, (FcChar8 *)"Nimbus Sans L"); FcPatternAddDouble (pattern, FC_PIXEL_SIZE, TEXT_SIZE); FcConfigSubstitute (NULL, pattern, FcMatchPattern); cairo_ft_font_options_substitute (font_options, pattern); FcDefaultSubstitute (pattern); resolved = FcFontMatch (NULL, pattern, &result); if (resolved == NULL) { FcPatternDestroy (pattern); return CAIRO_STATUS_NO_MEMORY; } /* set layout to vertical */ FcPatternDel (resolved, FC_VERTICAL_LAYOUT); FcPatternAddBool (resolved, FC_VERTICAL_LAYOUT, FcTrue); FcPatternGetDouble (resolved, FC_PIXEL_SIZE, 0, &pixel_size); font_face = cairo_ft_font_face_create_for_pattern (resolved); cairo_matrix_init_translate (&font_matrix, 10, 30); cairo_matrix_rotate (&font_matrix, M_PI_2/3); cairo_matrix_scale (&font_matrix, pixel_size, pixel_size); cairo_get_matrix (cr, &ctm); scaled_font = cairo_scaled_font_create (font_face, &font_matrix, &ctm, font_options); cairo_font_options_destroy (font_options); cairo_font_face_destroy (font_face); FcPatternDestroy (pattern); FcPatternDestroy (resolved); status = cairo_scaled_font_status (scaled_font); if (status) { cairo_scaled_font_destroy (scaled_font); return status; } *out = scaled_font; return CAIRO_STATUS_SUCCESS; }
std::unique_ptr<FontPlatformData> FontCache::createFontPlatformData(const FontDescription& fontDescription, const AtomicString& family, const FontFeatureSettings*, const FontVariantSettings*) { // The CSS font matching algorithm (http://www.w3.org/TR/css3-fonts/#font-matching-algorithm) // says that we must find an exact match for font family, slant (italic or oblique can be used) // and font weight (we only match bold/non-bold here). RefPtr<FcPattern> pattern = adoptRef(FcPatternCreate()); // Never choose unscalable fonts, as they pixelate when displayed at different sizes. FcPatternAddBool(pattern.get(), FC_SCALABLE, FcTrue); String familyNameString(getFamilyNameStringFromFamily(family)); if (!FcPatternAddString(pattern.get(), FC_FAMILY, reinterpret_cast<const FcChar8*>(familyNameString.utf8().data()))) return nullptr; bool italic = fontDescription.italic(); if (!FcPatternAddInteger(pattern.get(), FC_SLANT, italic ? FC_SLANT_ITALIC : FC_SLANT_ROMAN)) return nullptr; if (!FcPatternAddInteger(pattern.get(), FC_WEIGHT, fontWeightToFontconfigWeight(fontDescription.weight()))) return nullptr; if (!FcPatternAddDouble(pattern.get(), FC_PIXEL_SIZE, fontDescription.computedPixelSize())) return nullptr; // The strategy is originally from Skia (src/ports/SkFontHost_fontconfig.cpp): // // We do not normally allow fontconfig to substitute one font family for another, since this // would break CSS font family fallback: the website should be in control of fallback. During // normal font matching, the only font family substitution permitted is for generic families // (sans, serif, monospace) or for strongly-aliased fonts (which are to be treated as // effectively identical). This is because the font matching step is designed to always find a // match for the font, which we don't want. // // Fontconfig is used in two stages: (1) configuration and (2) matching. During the // configuration step, before any matching occurs, we allow arbitrary family substitutions, // since this is an exact matter of respecting the user's font configuration. FcConfigSubstitute(nullptr, pattern.get(), FcMatchPattern); FcDefaultSubstitute(pattern.get()); FcChar8* fontConfigFamilyNameAfterConfiguration; FcPatternGetString(pattern.get(), FC_FAMILY, 0, &fontConfigFamilyNameAfterConfiguration); String familyNameAfterConfiguration = String::fromUTF8(reinterpret_cast<char*>(fontConfigFamilyNameAfterConfiguration)); FcResult fontConfigResult; RefPtr<FcPattern> resultPattern = adoptRef(FcFontMatch(nullptr, pattern.get(), &fontConfigResult)); if (!resultPattern) // No match. return nullptr; FcChar8* fontConfigFamilyNameAfterMatching; FcPatternGetString(resultPattern.get(), FC_FAMILY, 0, &fontConfigFamilyNameAfterMatching); String familyNameAfterMatching = String::fromUTF8(reinterpret_cast<char*>(fontConfigFamilyNameAfterMatching)); // If Fontconfig gave us a different font family than the one we requested, we should ignore it // and allow WebCore to give us the next font on the CSS fallback list. The exceptions are if // this family name is a commonly-used generic family, or if the families are strongly-aliased. // Checking for a strong alias comes last, since it is slow. if (!equalIgnoringASCIICase(familyNameAfterConfiguration, familyNameAfterMatching) && !isCommonlyUsedGenericFamily(familyNameString) && !areStronglyAliased(familyNameAfterConfiguration, familyNameAfterMatching)) return nullptr; // Verify that this font has an encoding compatible with Fontconfig. Fontconfig currently // supports three encodings in FcFreeTypeCharIndex: Unicode, Symbol and AppleRoman. // If this font doesn't have one of these three encodings, don't select it. auto platformData = std::make_unique<FontPlatformData>(resultPattern.get(), fontDescription); if (!platformData->hasCompatibleCharmap()) return nullptr; return platformData; }
/* ======================================================================================== * FontConfig (unix) support * ======================================================================================== */ FT_Error GetFontByFaceName(const char *font_name, FT_Face *face) { FT_Error err = FT_Err_Cannot_Open_Resource; if (!FcInit()) { ShowInfoF("Unable to load font configuration"); } else { FcPattern *match; FcPattern *pat; FcFontSet *fs; FcResult result; char *font_style; char *font_family; /* Split & strip the font's style */ font_family = strdup(font_name); font_style = strchr(font_family, ','); if (font_style != NULL) { font_style[0] = '\0'; font_style++; while (*font_style == ' ' || *font_style == '\t') font_style++; } /* Resolve the name and populate the information structure */ pat = FcNameParse((FcChar8*)font_family); if (font_style != NULL) FcPatternAddString(pat, FC_STYLE, (FcChar8*)font_style); FcConfigSubstitute(0, pat, FcMatchPattern); FcDefaultSubstitute(pat); fs = FcFontSetCreate(); match = FcFontMatch(0, pat, &result); if (fs != NULL && match != NULL) { int i; FcChar8 *family; FcChar8 *style; FcChar8 *file; FcFontSetAdd(fs, match); for (i = 0; err != FT_Err_Ok && i < fs->nfont; i++) { /* Try the new filename */ if (FcPatternGetString(fs->fonts[i], FC_FILE, 0, &file) == FcResultMatch && FcPatternGetString(fs->fonts[i], FC_FAMILY, 0, &family) == FcResultMatch && FcPatternGetString(fs->fonts[i], FC_STYLE, 0, &style) == FcResultMatch) { /* The correct style? */ if (font_style != NULL && strcasecmp(font_style, (char*)style) != 0) continue; /* Font config takes the best shot, which, if the family name is spelled * wrongly a 'random' font, so check whether the family name is the * same as the supplied name */ if (strcasecmp(font_family, (char*)family) == 0) { err = FT_New_Face(_library, (char *)file, 0, face); } } } } free(font_family); FcPatternDestroy(pat); FcFontSetDestroy(fs); FcFini(); } return err; }
void font_impl::loadSystemFont(const char* const pName, int pFontSize) { //TODO do error checking once it is working std::string ttf_file_path; #ifndef OS_WIN // use fontconfig to get the file FcConfig* config = FcInitLoadConfigAndFonts(); if (!config) { FT_THROW_ERROR("fontconfig initilization failed", fg::FG_ERR_FREETYPE_ERROR); } // configure the search pattern, FcPattern* pat = FcNameParse((const FcChar8*)(pName)); if (!pat) { FT_THROW_ERROR("fontconfig pattern creation failed", fg::FG_ERR_FREETYPE_ERROR); } FcConfigSubstitute(config, pat, FcMatchPattern); FcDefaultSubstitute(pat); // find the font FcResult res; FcPattern* font = FcFontMatch(config, pat, &res); FcConfigSubstitute(config, pat, FcMatchPattern); if (font) { FcChar8* file = NULL; if (FcPatternGetString(font, FC_FILE, 0, &file) == FcResultMatch) { // save the file to another std::string ttf_file_path = (char*)file; } FcPatternDestroy(font); } // destroy fontconfig pattern object FcPatternDestroy(pat); #else char buf[512]; GetWindowsDirectory(buf, 512); std::regex fontRegex(std::string(pName), std::regex_constants::egrep | std::regex_constants::icase); std::vector<std::string> fontFiles; std::vector<std::string> matchedFontFiles; getFontFilePaths(fontFiles, std::string(buf)+"\\Fonts\\", std::string("ttf")); for (const auto &fontName : fontFiles) { if (std::regex_search(fontName, fontRegex)) { matchedFontFiles.push_back(fontName); } } /* out of all the possible matches, we choose the first possible match for given input font name parameter */ if (matchedFontFiles.size()==0) FT_THROW_ERROR("loadSystemFont failed to find the given font name", fg::FG_ERR_FREETYPE_ERROR); ttf_file_path = buf; ttf_file_path += "\\Fonts\\"; ttf_file_path += matchedFontFiles[0]; #endif loadFont(ttf_file_path.c_str(), pFontSize); }
/** * grx_font_load_full: * @family: (nullable): the font family name or %NULL * @size: the preferred size in points or -1 for any size * @dpi: the screen resolution or -1 to ignore dpi * @weight: the font weight (e.g. bold) or -1 for any weight * @slant: the font slant (e.g. italic) or -1 for any slant * @width: the font width (e.g. narrow) or -1 for any width * @monospace: set to %TRUE to prefer a monospace font * @lang: (nullable): a RFC-3066-style language code or %NULL * @script: (nullable): an ISO 15924 script code or %NULL * @err: pointer to hold an error * * Loads the font that best matches the parameters. * * Uses fontconfig for font matching. * * Returns: (transfer full) (nullable): the font or %NULL if there was an error */ GrxFont *grx_font_load_full(const gchar *family, gint size, gint dpi, GrxFontWeight weight, GrxFontSlant slant, GrxFontWidth width, gboolean monospace, const gchar *lang, const gchar *script, GError **err) { FcPattern *pattern, *match; FcResult result; GrxFont *font; FcChar8 *file; if (!FcInit()) { g_set_error_literal(err, GRX_ERROR, GRX_ERROR_FONT_ERROR, "Failed to init fontconfig"); return NULL; } pattern = FcPatternCreate(); FcPatternAddBool(pattern, FC_SCALABLE, FcFalse); FcPatternAddBool(pattern, FC_OUTLINE, FcFalse); FcPatternAddString(pattern, FC_FONTFORMAT, (FcChar8 *)"PCF"); if (family) { FcPatternAddString(pattern, FC_FAMILY, (FcChar8 *)family); } if (size >= 0) { FcPatternAddDouble(pattern, FC_SIZE, size); } if (dpi >= 0) { FcPatternAddDouble(pattern, FC_DPI, dpi); } switch (weight) { case GRX_FONT_WEIGHT_REGULAR: FcPatternAddInteger(pattern, FC_WEIGHT, 80); break; case GRX_FONT_WEIGHT_BOLD: FcPatternAddInteger(pattern, FC_WEIGHT, 200); break; } switch (slant) { case GRX_FONT_SLANT_REGULAR: FcPatternAddInteger(pattern, FC_SLANT, 0); break; case GRX_FONT_SLANT_ITALIC: FcPatternAddInteger(pattern, FC_SLANT, 100); break; } switch (width) { case GRX_FONT_WIDTH_NARROW: FcPatternAddInteger(pattern, FC_WIDTH, 75); break; case GRX_FONT_WIDTH_REGULAR: FcPatternAddInteger(pattern, FC_WIDTH, 100); break; case GRX_FONT_WIDTH_WIDE: FcPatternAddInteger(pattern, FC_WIDTH, 125); break; } if (monospace) { FcPatternAddInteger(pattern, FC_SPACING, 100); } if (lang) { FcPatternAddString(pattern, FC_LANG, (FcChar8 *)lang); } if (script) { FcPatternAddCharSet(pattern, FC_CHARSET, script_to_charset(script)); } { FcChar8 *pattern_str; pattern_str = FcNameUnparse(pattern); g_debug("searching for pattern: %s", pattern_str); free(pattern_str); } FcConfigSubstitute(NULL, pattern, FcMatchPattern); FcDefaultSubstitute(pattern); match = FcFontMatch(NULL, pattern, &result); if (!match) { // TODO: use result for better error g_set_error_literal(err, GRX_ERROR, GRX_ERROR_FONT_ERROR, "Failed to find match"); FcPatternDestroy(pattern); return NULL; } if (FcPatternGetString(match, FC_FILE, 0, &file) != FcResultMatch) { g_set_error_literal(err, GRX_ERROR, GRX_ERROR_FONT_ERROR, "Failed to get file name"); FcPatternDestroy(match); FcPatternDestroy(pattern); return NULL; } font = grx_font_load_from_file((gchar *)file, err); FcPatternDestroy(match); FcPatternDestroy(pattern); return font; }
bool SetFallbackFont(FreeTypeSettings *settings, const char *language_isocode, int winlangid, const char *str) { if (!FcInit()) return false; bool ret = false; /* Fontconfig doesn't handle full language isocodes, only the part * before the _ of e.g. en_GB is used, so "remove" everything after * the _. */ char lang[16]; strecpy(lang, language_isocode, lastof(lang)); char *split = strchr(lang, '_'); if (split != NULL) *split = '\0'; FcPattern *pat; FcPattern *match; FcResult result; FcChar8 *file; FcFontSet *fs; FcValue val; val.type = FcTypeString; val.u.s = (FcChar8*)lang; /* First create a pattern to match the wanted language */ pat = FcPatternCreate(); /* And fill it with the language and other defaults */ if (pat == NULL || !FcPatternAdd(pat, "lang", val, false) || !FcConfigSubstitute(0, pat, FcMatchPattern)) { goto error_pattern; } FcDefaultSubstitute(pat); /* Then create a font set and match that */ match = FcFontMatch(0, pat, &result); if (match == NULL) { goto error_pattern; } /* Find all fonts that do match */ fs = FcFontSetCreate(); FcFontSetAdd(fs, match); /* And take the first, if it exists */ if (fs->nfont <= 0 || FcPatternGetString(fs->fonts[0], FC_FILE, 0, &file)) { goto error_fontset; } strecpy(settings->small_font, (const char*)file, lastof(settings->small_font)); strecpy(settings->medium_font, (const char*)file, lastof(settings->medium_font)); strecpy(settings->large_font, (const char*)file, lastof(settings->large_font)); ret = true; error_fontset: FcFontSetDestroy(fs); error_pattern: if (pat != NULL) FcPatternDestroy(pat); FcFini(); return ret; }
CAMLprim value default_substitute(value pat) { CAMLparam0(); FcDefaultSubstitute(FcPattern_val(pat)); CAMLreturn(Val_unit); }
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; }
const vlc_family_t *FontConfig_GetFamily( filter_t *p_filter, const char *psz_family ) { filter_sys_t *p_sys = p_filter->p_sys; char *psz_lc = ToLower( psz_family ); if( unlikely( !psz_lc ) ) return NULL; vlc_family_t *p_family = vlc_dictionary_value_for_key( &p_sys->family_map, psz_lc ); if( p_family != kVLCDictionaryNotFound ) { free( psz_lc ); return p_family; } p_family = NewFamily( p_filter, psz_lc, &p_sys->p_families, &p_sys->family_map, psz_lc ); free( psz_lc ); if( !p_family ) return NULL; bool b_bold, b_italic; for( int i = 0; i < 4; ++i ) { switch( i ) { case 0: b_bold = false; b_italic = false; break; case 1: b_bold = true; b_italic = false; break; case 2: b_bold = false; b_italic = true; break; case 3: b_bold = true; b_italic = true; break; } int i_index = 0; FcResult result = FcResultMatch; FcPattern *pat, *p_pat; FcChar8* val_s; FcBool val_b; char *psz_fontfile = NULL; FcConfig* config = NULL; /* Create a pattern and fill it */ pat = FcPatternCreate(); if (!pat) continue; /* */ FcPatternAddString( pat, FC_FAMILY, (const FcChar8*) psz_family ); FcPatternAddBool( pat, FC_OUTLINE, FcTrue ); FcPatternAddInteger( pat, FC_SLANT, b_italic ? FC_SLANT_ITALIC : FC_SLANT_ROMAN ); FcPatternAddInteger( pat, FC_WEIGHT, b_bold ? FC_WEIGHT_EXTRABOLD : FC_WEIGHT_NORMAL ); /* */ FcDefaultSubstitute( pat ); if( !FcConfigSubstitute( config, pat, FcMatchPattern ) ) { FcPatternDestroy( pat ); continue; } /* Find the best font for the pattern, destroy the pattern */ p_pat = FcFontMatch( config, pat, &result ); FcPatternDestroy( pat ); if( !p_pat || result == FcResultNoMatch ) continue; /* Check the new pattern */ if( ( FcResultMatch != FcPatternGetBool( p_pat, FC_OUTLINE, 0, &val_b ) ) || ( val_b != FcTrue ) ) { FcPatternDestroy( p_pat ); continue; } if( FcResultMatch != FcPatternGetInteger( p_pat, FC_INDEX, 0, &i_index ) ) { i_index = 0; } if( FcResultMatch != FcPatternGetString( p_pat, FC_FAMILY, 0, &val_s ) ) { FcPatternDestroy( p_pat ); continue; } if( FcResultMatch == FcPatternGetString( p_pat, FC_FILE, 0, &val_s ) ) psz_fontfile = strdup( (const char*)val_s ); FcPatternDestroy( p_pat ); if( !psz_fontfile ) continue; NewFont( psz_fontfile, i_index, b_bold, b_italic, p_family ); } return p_family; }
FcFontSet * fcinfo_match(FcFontSet *fontset, const FcPattern *filter) { int f; FcFontSet *result; FcChar8 *family, *style, *file; FcChar8 *next_family, *next_style; double size; FcBool scalable; FcPattern *pat, *match = NULL; FcResult r; FcInit(); if (fontset->nfont == 0) { result = FcFontSetCreate(); return result; } /* fc-match "Misc Fixed:style=Bold" gives many files with various pixelsizes plus two "encodings" ('general' and 'ISO8859-1', ISO8859-1 is subset of general) we want only one card for family,style pair for MiscFixedBold.html we will take informations from file 9x18B.pcf.gz (biggest size and general encoding) from fcinfo(), fontset is sorted a way that pattern created from 9x18B.pcf.gz comes first in "Misc Fixed:style=Bold" interval (the biggest pixel size and subset of supported languages, see pattern_compare()). */ result = FcFontSetCreate(); for (f = 0; f < fontset->nfont; ) { /* bitmap fonts: */ /* we are here always on the best file in FC_LANG terms */ /* we need it for displaying the widest range of supported languages */ /* identify it by FC_FILE for FcFontMatch() */ if (filter) pat = FcPatternDuplicate(filter); else pat = FcPatternCreate(); assert(fcinfo_get_translated_string(fontset->fonts[f], FC_FAMILY, LANG_EN, &family) == FcResultMatch); FcPatternAddString(pat, FC_FAMILY, family); if (fcinfo_get_translated_string(fontset->fonts[f], FC_STYLE, LANG_EN, &style) == FcResultMatch) FcPatternAddString(pat, FC_STYLE, style); if (FcPatternGetString(fontset->fonts[f], FC_FILE, 0, &file) == FcResultMatch) FcPatternAddString(pat, FC_FILE, file); FcConfigSubstitute(NULL, pat, FcMatchPattern); FcDefaultSubstitute(pat); match = FcFontMatch(NULL, pat, &r); assert(r == FcResultMatch); /* should not be needed: FcConfigSubstitute(NULL, match, FcMatchFont); */ FcPatternDestroy(pat); assert(FcPatternGetBool(match, FC_SCALABLE, 0, &scalable) == FcResultMatch); /* fprintf(stdout, "Family: %s Style: %s\n", next_family, next_style); fprintf(stdout, " %s\n", file);*/ /* figure out sizes font provide (needed for specimen) and skip same */ /* family,style pairs (see e. g. Misc Fixed) */ if (! scalable) { next_family = family; next_style = style; /* unfortunately e. g. 'ETL Fixed' and 'ETL fixed' are present on my system */ while (FcStrCmpIgnoreCase(next_family, family) == 0 && FcStrCmpIgnoreCase(next_style, style) == 0) { if (FcPatternGetDouble(fontset->fonts[f], FC_PIXEL_SIZE, 0, &size) == FcResultMatch) { if (! pattern_contains_size(match, size)) { FcPatternAddDouble(match, FC_PIXEL_SIZE, size); if (FcPatternGetString(fontset->fonts[f], FC_FILE, 0, &file) == FcResultMatch) FcPatternAddString(match, FC_FILE, file); /*fprintf(stdout, " %s\n", file);*/ } } if (f + 1 == fontset->nfont) /* last family,style pair at all */ { f++; break; } assert(fcinfo_get_translated_string(fontset->fonts[f + 1], FC_FAMILY, LANG_EN, &next_family) == FcResultMatch); assert(fcinfo_get_translated_string(fontset->fonts[f + 1], FC_STYLE, LANG_EN, &next_style) == FcResultMatch); f++; } } else /* family Efont Serif Regular is spread (unintentionally) over */ { /* 5 files (Efont Serif <X> should be spread over 2 files, */ /* normal and 'Alternate'), so this is needed anyway: */ FcPatternDel(match, FC_FILE); next_family = family; next_style = style; while (FcStrCmpIgnoreCase(next_family, family) == 0 && FcStrCmpIgnoreCase(next_style, style) == 0) { if (FcPatternGetString(fontset->fonts[f], FC_FILE, 0, &file) == FcResultMatch) FcPatternAddString(match, FC_FILE, file); if (f + 1 == fontset->nfont) /* last family,style pair at all */ { f++; break; } assert(fcinfo_get_translated_string(fontset->fonts[f + 1], FC_FAMILY, LANG_EN, &next_family) == FcResultMatch); assert(fcinfo_get_translated_string(fontset->fonts[f + 1], FC_STYLE, LANG_EN, &next_style) == FcResultMatch); f++; } } /* don't add ethio16f-uni.pcf, johabg16.pcf and similar with reported empty charset */ if (! empty_charset(match)) FcFontSetAdd(result, FcPatternDuplicate(match)); } if (match) FcPatternDestroy(match); return result; }
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) { if (result == FcResultMatch) { 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; }
bool SkFontConfigInterfaceDirect::matchFamilyName(const char familyName[], SkFontStyle style, FontIdentity* outIdentity, SkString* outFamilyName, SkFontStyle* 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); } fcpattern_from_skfontstyle(style, pattern); FcPatternAddBool(pattern, FC_SCALABLE, FcTrue); FcConfigSubstitute(nullptr, 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 nullptr 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 = this->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 = skfontstyle_from_fcpattern(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); if (!s) goto error; 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, FcFalse, 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); if (!retval) goto error; 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; }
FontPlatformData::FontPlatformData(const FontDescription& fontDescription, const AtomicString& familyName) : m_pattern(0) , m_size(fontDescription.computedSize()) , m_syntheticBold(false) , m_syntheticOblique(false) , m_scaledFont(0) , m_face(0) { FontPlatformData::init(); CString familyNameString = familyName.string().utf8(); const char* fcfamily = familyNameString.data(); int fcslant = FC_SLANT_ROMAN; // FIXME: Map all FontWeight values to fontconfig weights. int fcweight = FC_WEIGHT_NORMAL; float fcsize = fontDescription.computedSize(); if (fontDescription.italic()) fcslant = FC_SLANT_ITALIC; if (fontDescription.weight() >= FontWeight600) fcweight = FC_WEIGHT_BOLD; FcConfig *config = FcConfigGetCurrent(); //printf("family = %s\n", fcfamily); int type = fontDescription.genericFamily(); FcPattern* pattern = FcPatternCreate(); if (!FcPatternAddString(pattern, FC_FAMILY, reinterpret_cast<const FcChar8*>(fcfamily))) goto freePattern; switch (type) { case FontDescription::SerifFamily: fcfamily = "serif"; break; case FontDescription::SansSerifFamily: fcfamily = "sans-serif"; break; case FontDescription::MonospaceFamily: fcfamily = "monospace"; break; case FontDescription::NoFamily: case FontDescription::StandardFamily: default: fcfamily = "sans-serif"; } if (!FcPatternAddString(pattern, FC_FAMILY, reinterpret_cast<const FcChar8*>(fcfamily))) goto freePattern; if (!FcPatternAddInteger(pattern, FC_SLANT, fcslant)) goto freePattern; if (!FcPatternAddInteger(pattern, FC_WEIGHT, fcweight)) goto freePattern; if (!FcPatternAddDouble(pattern, FC_PIXEL_SIZE, fcsize)) goto freePattern; FcConfigSubstitute(config, pattern, FcMatchPattern); FcDefaultSubstitute(pattern); FcResult fcresult; m_pattern = FcFontMatch(config, pattern, &fcresult); FcPatternReference(m_pattern); // FIXME: should we set some default font? if (!m_pattern) goto freePattern; FcChar8 *fc_filename; char *filename; int id; id = 0; if (FcPatternGetString(m_pattern, FC_FILE, 0, &fc_filename) != FcResultMatch) { DS_WAR("cannot retrieve font\n"); goto freePattern; } filename = (char *) fc_filename; //use C cast as FcChar is a fontconfig type //printf("filename = %s\n", filename); if (FcPatternGetInteger(m_pattern, FC_INDEX, 0, &id) != FcResultMatch) { DS_WAR("cannot retrieve font index\n"); goto freePattern; } if (FT_Error error = FT_New_Face(m_library, filename, id, &m_face)) { //if (FT_Error error = FT_New_Face(m_library, too, id, &m_face)) { DS_WAR("fail to open font" << filename << "with index " << id << " (error = 0x%x)\n" << error); m_face = 0; goto freePattern; } FT_Set_Pixel_Sizes(m_face, 0, static_cast<uint> (fontDescription.computedSize())); //DBGML(MODULE_FONTS, LEVEL_INFO, "open font %s with size %d\n", filename, static_cast<uint> (fontDescription.specifiedSize())); freePattern: FcPatternDestroy(pattern); FcConfigDestroy(config); }
int PsychRebuildFont(void) { // Destroy old font object, if any: if (faceT || faceM) { // Delete OGLFT face object: if (faceT) delete(faceT); faceT = NULL; if (faceM) delete(faceM); faceM = NULL; if (_verbosity > 3) fprintf(stderr, "libptbdrawtext_ftgl: Destroying old font face...\n"); // Delete underlying FreeType representation: FT_Done_Face(ft_face); ft_face = NULL; } if (_useOwnFontmapper) { FcResult result; FcPattern* target = NULL; if (_fontName[0] == '-') { // _fontName starts with a '-' dash: This is not a simple font family string but a special // fontspec string in FontConfig's special format. It contains many possible required font // properties encoded in the string. Parse it into a font matching pattern: target = FcNameParse((FcChar8*) &(_fontName[1])); // Need to manually add the current _fontSize, otherwise inconsistent stuff may happen: FcPatternAddDouble(target, FC_PIXEL_SIZE, _fontSize); } else { // _fontName contains only font family name: Build matching pattern based on _fontSize and // the flags provided in _fontStyle, according to the conventions in Psychtoolbox Screen('TextStyle'): target = FcPatternBuild (0, FC_FAMILY, FcTypeString, _fontName, FC_PIXEL_SIZE, FcTypeDouble, _fontSize, FC_WEIGHT, FcTypeInteger, ((_fontStyle & 1) ? FC_WEIGHT_BOLD : FC_WEIGHT_NORMAL), FC_SLANT, FcTypeInteger, ((_fontStyle & 2) ? FC_SLANT_ITALIC : FC_SLANT_ROMAN), FC_OUTLINE, FcTypeBool, ((_fontStyle & 8) ? true : false), FC_WIDTH, FcTypeInteger, ( (_fontStyle & 32) ? FC_WIDTH_CONDENSED : ((_fontStyle & 64) ? FC_WIDTH_EXPANDED : FC_WIDTH_NORMAL) ), FC_DPI, FcTypeDouble, (double) 72.0, FC_SCALABLE, FcTypeBool, true, FC_ANTIALIAS, FcTypeBool, ((_antiAliasing != 0) ? true : false), NULL); } FcDefaultSubstitute(target); // Have a matching pattern: if (_verbosity > 3) { fprintf(stderr, "libptbdrawtext_ftgl: Trying to find font that closely matches following specification:\n"); FcPatternPrint(target); } // Perform font matching for the font in the default configuration (0) that best matches the // specified target pattern: FcPattern* matched = FcFontMatch(0, target, &result); if (result == FcResultNoMatch) { // Failed! if (_verbosity > 1) fprintf(stderr, "libptbdrawtext_ftgl: FontConfig failed to find a matching font for family %s, size %f pts and style flags %i.\n", _fontName, (float) _fontSize, _fontStyle); FcPatternDestroy(target); return(1); } // Success: Extract relevant information for Freetype-2, the font filename and faceIndex: if (_verbosity > 3) { fprintf(stderr, "libptbdrawtext_ftgl: Best matching font which will be selected for drawing has following specs:\n"); FcPatternPrint(matched); } // Retrieve font filename for matched font: FcChar8* localfontFileName = NULL; if (FcPatternGetString(matched, FC_FILE, 0, (FcChar8**) &localfontFileName) != FcResultMatch) { // Failed! if (_verbosity > 1) fprintf(stderr, "libptbdrawtext_ftgl: FontConfig did not find filename for font with family %s, size %f pts and style flags %i.\n", _fontName, (float) _fontSize, _fontStyle); FcPatternDestroy(target); FcPatternDestroy(matched); return(1); } strcpy(_fontFileName, (char*) localfontFileName); // Retrieve faceIndex within fontfile: if (FcPatternGetInteger(matched, FC_INDEX, 0, &_faceIndex) != FcResultMatch) { // Failed! if (_verbosity > 1) fprintf(stderr, "libptbdrawtext_ftgl: FontConfig did not find faceIndex for font file %s, family %s, size %f pts and style flags %i.\n", _fontFileName, _fontName, (float) _fontSize, _fontStyle); FcPatternDestroy(target); FcPatternDestroy(matched); return(1); } // Release target pattern and matched pattern objects: FcPatternDestroy(target); FcPatternDestroy(matched); } else { // Use "raw" values as passed by calling client code: strcpy(_fontFileName, _fontName); _faceIndex = (int) _fontStyle; } // Load & Create new font and face object, based on current spec settings: // We directly use the Freetype library, so we can spec the faceIndex for selection of textstyle, which wouldn't be // possible with the higher-level OGLFT constructor... FT_Error error = FT_New_Face( OGLFT::Library::instance(), _fontFileName, _faceIndex, &ft_face ); if (error) { if (_verbosity > 1) fprintf(stderr, "libptbdrawtext_ftgl: Freetype did not load face with index %i from font file %s.\n", _faceIndex, _fontFileName); return(1); } else { if (_verbosity > 3) fprintf(stderr, "libptbdrawtext_ftgl: Freetype loaded face %p with index %i from font file %s.\n", ft_face, _faceIndex, _fontFileName); } // Create FTGL face from Freetype face with given size and a 72 DPI resolution, aka _fontSize == pixelsize: if (_antiAliasing != 0) { faceT = new OGLFT::TranslucentTexture(ft_face, _fontSize, 72); // Test the created face to make sure it will work correctly: if (!faceT->isValid()) { if (_verbosity > 1) fprintf(stderr, "libptbdrawtext_ftgl: Freetype did not recognize %s as a font file.\n", _fontName); return(1); } } else { faceM = new OGLFT::MonochromeTexture(ft_face, _fontSize, 72); // Test the created face to make sure it will work correctly: if (!faceM->isValid()) { if (_verbosity > 1) fprintf(stderr, "libptbdrawtext_ftgl: Freetype did not recognize %s as a font file.\n", _fontName); return(1); } } // Ready! _needsRebuild = false; return(0); }
static int load_font_fontconfig(AVFilterContext *ctx) { DrawTextContext *s = ctx->priv; FcConfig *fontconfig; FcPattern *pat, *best; FcResult result = FcResultMatch; FcChar8 *filename; int index; double size; int err = AVERROR(ENOENT); fontconfig = FcInitLoadConfigAndFonts(); if (!fontconfig) { av_log(ctx, AV_LOG_ERROR, "impossible to init fontconfig\n"); return AVERROR_UNKNOWN; } pat = FcNameParse(s->fontfile ? s->fontfile : (uint8_t *)(intptr_t)"default"); if (!pat) { av_log(ctx, AV_LOG_ERROR, "could not parse fontconfig pat"); return AVERROR(EINVAL); } FcPatternAddString(pat, FC_FAMILY, s->font); if (s->fontsize) FcPatternAddDouble(pat, FC_SIZE, (double)s->fontsize); FcDefaultSubstitute(pat); if (!FcConfigSubstitute(fontconfig, pat, FcMatchPattern)) { av_log(ctx, AV_LOG_ERROR, "could not substitue fontconfig options"); /* very unlikely */ FcPatternDestroy(pat); return AVERROR(ENOMEM); } best = FcFontMatch(fontconfig, pat, &result); FcPatternDestroy(pat); if (!best || result != FcResultMatch) { av_log(ctx, AV_LOG_ERROR, "Cannot find a valid font for the family %s\n", s->font); goto fail; } if ( FcPatternGetInteger(best, FC_INDEX, 0, &index ) != FcResultMatch || FcPatternGetDouble (best, FC_SIZE, 0, &size ) != FcResultMatch) { av_log(ctx, AV_LOG_ERROR, "impossible to find font information"); return AVERROR(EINVAL); } if (FcPatternGetString(best, FC_FILE, 0, &filename) != FcResultMatch) { av_log(ctx, AV_LOG_ERROR, "No file path for %s\n", s->font); goto fail; } av_log(ctx, AV_LOG_INFO, "Using \"%s\"\n", filename); if (!s->fontsize) s->fontsize = size + 0.5; err = load_font_file(ctx, filename, index); if (err) return err; FcConfigDestroy(fontconfig); fail: FcPatternDestroy(best); return err; }
int drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, const char *text) { char buf[1024]; int tx, ty, th; Extnts tex; XftDraw *d = NULL; Fnt *curfont, *nextfont; size_t i, len; int utf8strlen, utf8charlen, render; long utf8codepoint = 0; const char *utf8str; FcCharSet *fccharset; FcPattern *fcpattern; FcPattern *match; XftResult result; int charexists = 0; if (!drw->scheme || !drw->fontcount) return 0; if (!(render = x || y || w || h)) { w = ~w; } else { XSetForeground(drw->dpy, drw->gc, drw->scheme->bg->pix); XFillRectangle(drw->dpy, drw->drawable, drw->gc, x, y, w, h); d = XftDrawCreate(drw->dpy, drw->drawable, DefaultVisual(drw->dpy, drw->screen), DefaultColormap(drw->dpy, drw->screen)); } curfont = drw->fonts[0]; while (1) { utf8strlen = 0; utf8str = text; nextfont = NULL; while (*text) { utf8charlen = utf8decode(text, &utf8codepoint, UTF_SIZ); for (i = 0; i < drw->fontcount; i++) { charexists = charexists || XftCharExists(drw->dpy, drw->fonts[i]->xfont, utf8codepoint); if (charexists) { if (drw->fonts[i] == curfont) { utf8strlen += utf8charlen; text += utf8charlen; } else { nextfont = drw->fonts[i]; } break; } } if (!charexists || (nextfont && nextfont != curfont)) break; else charexists = 0; } if (utf8strlen) { drw_font_getexts(curfont, utf8str, utf8strlen, &tex); /* shorten text if necessary */ for (len = MIN(utf8strlen, (sizeof buf) - 1); len && (tex.w > w - drw->fonts[0]->h || w < drw->fonts[0]->h); len--) drw_font_getexts(curfont, utf8str, len, &tex); if (len) { memcpy(buf, utf8str, len); buf[len] = '\0'; if (len < utf8strlen) for (i = len; i && i > len - 3; buf[--i] = '.'); if (render) { th = curfont->ascent + curfont->descent; ty = y + (h / 2) - (th / 2) + curfont->ascent; tx = x + (h / 2); XftDrawStringUtf8(d, &drw->scheme->fg->rgb, curfont->xfont, tx, ty, (XftChar8 *)buf, len); } x += tex.w; w -= tex.w; } } if (!*text) { break; } else if (nextfont) { charexists = 0; curfont = nextfont; } else { /* Regardless of whether or not a fallback font is found, the * character must be drawn. */ charexists = 1; if (drw->fontcount >= DRW_FONT_CACHE_SIZE) continue; fccharset = FcCharSetCreate(); FcCharSetAddChar(fccharset, utf8codepoint); if (!drw->fonts[0]->pattern) { /* Refer to the comment in drw_font_xcreate for more * information. */ die("the first font in the cache must be loaded from a font string.\n"); } fcpattern = FcPatternDuplicate(drw->fonts[0]->pattern); FcPatternAddCharSet(fcpattern, FC_CHARSET, fccharset); FcPatternAddBool(fcpattern, FC_SCALABLE, FcTrue); FcConfigSubstitute(NULL, fcpattern, FcMatchPattern); FcDefaultSubstitute(fcpattern); match = XftFontMatch(drw->dpy, drw->screen, fcpattern, &result); FcCharSetDestroy(fccharset); FcPatternDestroy(fcpattern); if (match) { curfont = drw_font_xcreate(drw, NULL, match); if (curfont && XftCharExists(drw->dpy, curfont->xfont, utf8codepoint)) { drw->fonts[drw->fontcount++] = curfont; } else { drw_font_free(curfont); curfont = drw->fonts[0]; } } } } if (d) XftDrawDestroy(d); return x; }
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; }
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); }
/** * \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; }
void WebFontInfo::renderStyleForStrike(const char* family, int sizeAndStyle, WebFontRenderStyle* out) { bool isBold = sizeAndStyle & 1; bool isItalic = sizeAndStyle & 2; int pixelSize = sizeAndStyle >> 2; FcPattern* pattern = FcPatternCreate(); FcValue fcvalue; fcvalue.type = FcTypeString; fcvalue.u.s = reinterpret_cast<const FcChar8 *>(family); FcPatternAdd(pattern, FC_FAMILY, fcvalue, FcFalse); fcvalue.type = FcTypeInteger; fcvalue.u.i = isBold ? FC_WEIGHT_BOLD : FC_WEIGHT_NORMAL; FcPatternAdd(pattern, FC_WEIGHT, fcvalue, FcFalse); fcvalue.type = FcTypeInteger; fcvalue.u.i = isItalic ? FC_SLANT_ITALIC : FC_SLANT_ROMAN; FcPatternAdd(pattern, FC_SLANT, fcvalue, FcFalse); fcvalue.type = FcTypeBool; fcvalue.u.b = FcTrue; FcPatternAdd(pattern, FC_SCALABLE, fcvalue, FcFalse); fcvalue.type = FcTypeDouble; fcvalue.u.d = pixelSize; FcPatternAdd(pattern, FC_SIZE, fcvalue, FcFalse); FcConfigSubstitute(0, pattern, FcMatchPattern); FcDefaultSubstitute(pattern); FcResult result; // Some versions of fontconfig don't actually write a value into result. // However, it's not clear from the documentation if result should be a // non-0 pointer: future versions might expect to be able to write to // it. So we pass in a valid pointer and ignore it. FcPattern* match = FcFontMatch(0, pattern, &result); FcPatternDestroy(pattern); out->setDefaults(); if (!match) return; FcBool b; int i; if (FcPatternGetBool(match, FC_ANTIALIAS, 0, &b) == FcResultMatch) out->useAntiAlias = b; if (FcPatternGetBool(match, FC_EMBEDDED_BITMAP, 0, &b) == FcResultMatch) out->useBitmaps = b; if (FcPatternGetBool(match, FC_AUTOHINT, 0, &b) == FcResultMatch) out->useAutoHint = b; if (FcPatternGetBool(match, FC_HINTING, 0, &b) == FcResultMatch) out->useHinting = b; if (FcPatternGetInteger(match, FC_HINT_STYLE, 0, &i) == FcResultMatch) out->hintStyle = i; if (FcPatternGetInteger(match, FC_RGBA, 0, &i) == FcResultMatch) { switch (i) { case FC_RGBA_NONE: out->useSubpixelRendering = 0; break; case FC_RGBA_RGB: case FC_RGBA_BGR: case FC_RGBA_VRGB: case FC_RGBA_VBGR: out->useSubpixelRendering = 1; break; default: // This includes FC_RGBA_UNKNOWN. out->useSubpixelRendering = 2; break; } } // FontConfig doesn't provide parameters to configure whether subpixel // positioning should be used or not, so we just use a global setting. out->useSubpixelPositioning = useSubpixelPositioning; FcPatternDestroy(match); }
static int parse_font(AVFilterContext *ctx) { DrawTextContext *s = ctx->priv; #if !CONFIG_LIBFONTCONFIG if (!s->fontfile) { av_log(ctx, AV_LOG_ERROR, "No font filename provided\n"); return AVERROR(EINVAL); } return 0; #else FcPattern *pat, *best; FcResult result = FcResultMatch; FcBool fc_bool; FcChar8* fc_string; int err = AVERROR(ENOENT); if (s->fontfile) return 0; if (!FcInit()) return AVERROR_UNKNOWN; if (!(pat = FcPatternCreate())) return AVERROR(ENOMEM); FcPatternAddString(pat, FC_FAMILY, s->font); FcPatternAddBool(pat, FC_OUTLINE, FcTrue); FcPatternAddDouble(pat, FC_SIZE, (double)s->fontsize); FcDefaultSubstitute(pat); if (!FcConfigSubstitute(NULL, pat, FcMatchPattern)) { FcPatternDestroy(pat); return AVERROR(ENOMEM); } best = FcFontMatch(NULL, pat, &result); FcPatternDestroy(pat); if (!best || result == FcResultNoMatch) { av_log(ctx, AV_LOG_ERROR, "Cannot find a valid font for the family %s\n", s->font); goto fail; } if (FcPatternGetBool(best, FC_OUTLINE, 0, &fc_bool) != FcResultMatch || !fc_bool) { av_log(ctx, AV_LOG_ERROR, "Outline not available for %s\n", s->font); goto fail; } if (FcPatternGetString(best, FC_FAMILY, 0, &fc_string) != FcResultMatch) { av_log(ctx, AV_LOG_ERROR, "No matches for %s\n", s->font); goto fail; } if (FcPatternGetString(best, FC_FILE, 0, &fc_string) != FcResultMatch) { av_log(ctx, AV_LOG_ERROR, "No file path for %s\n", s->font); goto fail; } s->fontfile = av_strdup(fc_string); if (!s->fontfile) err = AVERROR(ENOMEM); else err = 0; fail: FcPatternDestroy(best); return err; #endif }
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; }