void QFontconfigDatabase::populateFontDatabase() { FcFontSet *fonts; QString familyName; FcChar8 *value = 0; int weight_value; int slant_value; int spacing_value; FcChar8 *file_value; int indexValue; FcChar8 *foundry_value; FcBool scalable; FcBool antialias; { FcObjectSet *os = FcObjectSetCreate(); FcPattern *pattern = FcPatternCreate(); const char *properties [] = { FC_FAMILY, FC_WEIGHT, FC_SLANT, FC_SPACING, FC_FILE, FC_INDEX, FC_LANG, FC_CHARSET, FC_FOUNDRY, FC_SCALABLE, FC_PIXEL_SIZE, FC_WIDTH, #if FC_VERSION >= 20297 FC_CAPABILITY, #endif (const char *)0 }; const char **p = properties; while (*p) { FcObjectSetAdd(os, *p); ++p; } fonts = FcFontList(0, pattern, os); FcObjectSetDestroy(os); FcPatternDestroy(pattern); } for (int i = 0; i < fonts->nfont; i++) { if (FcPatternGetString(fonts->fonts[i], FC_FAMILY, 0, &value) != FcResultMatch) continue; // capitalize(value); familyName = QString::fromUtf8((const char *)value); slant_value = FC_SLANT_ROMAN; weight_value = FC_WEIGHT_MEDIUM; spacing_value = FC_PROPORTIONAL; file_value = 0; indexValue = 0; scalable = FcTrue; if (FcPatternGetInteger (fonts->fonts[i], FC_SLANT, 0, &slant_value) != FcResultMatch) slant_value = FC_SLANT_ROMAN; if (FcPatternGetInteger (fonts->fonts[i], FC_WEIGHT, 0, &weight_value) != FcResultMatch) weight_value = FC_WEIGHT_MEDIUM; if (FcPatternGetInteger (fonts->fonts[i], FC_SPACING, 0, &spacing_value) != FcResultMatch) spacing_value = FC_PROPORTIONAL; if (FcPatternGetString (fonts->fonts[i], FC_FILE, 0, &file_value) != FcResultMatch) file_value = 0; if (FcPatternGetInteger (fonts->fonts[i], FC_INDEX, 0, &indexValue) != FcResultMatch) indexValue = 0; if (FcPatternGetBool(fonts->fonts[i], FC_SCALABLE, 0, &scalable) != FcResultMatch) scalable = FcTrue; if (FcPatternGetString(fonts->fonts[i], FC_FOUNDRY, 0, &foundry_value) != FcResultMatch) foundry_value = 0; if(FcPatternGetBool(fonts->fonts[i],FC_ANTIALIAS,0,&antialias) != FcResultMatch) antialias = true; QSupportedWritingSystems writingSystems; FcLangSet *langset = 0; FcResult res = FcPatternGetLangSet(fonts->fonts[i], FC_LANG, 0, &langset); if (res == FcResultMatch) { for (int i = 1; i < LanguageCount; ++i) { const FcChar8 *lang = (const FcChar8*) languageForWritingSystem[i]; if (lang) { FcLangResult langRes = FcLangSetHasLang(langset, lang); if (langRes != FcLangDifferentLang) writingSystems.setSupported(QFontDatabase::WritingSystem(i)); } } } else { // we set Other to supported for symbol fonts. It makes no // sense to merge these with other ones, as they are // special in a way. writingSystems.setSupported(QFontDatabase::Other); } FcCharSet *cs = 0; res = FcPatternGetCharSet(fonts->fonts[i], FC_CHARSET, 0, &cs); if (res == FcResultMatch) { // some languages are not supported by FontConfig, we rather check the // charset to detect these for (int i = 1; i < SampleCharCount; ++i) { if (!sampleCharForWritingSystem[i]) continue; if (FcCharSetHasChar(cs, sampleCharForWritingSystem[i])) writingSystems.setSupported(QFontDatabase::WritingSystem(i)); } } #if FC_VERSION >= 20297 for (int j = 1; j < LanguageCount; ++j) { if (writingSystems.supported(QFontDatabase::WritingSystem(j)) && requiresOpenType(j) && openType[j]) { FcChar8 *cap; res = FcPatternGetString (fonts->fonts[i], FC_CAPABILITY, 0, &cap); if (res != FcResultMatch || !strstr((const char *)cap, openType[j])) writingSystems.setSupported(QFontDatabase::WritingSystem(j),false); } } #endif FontFile *fontFile = new FontFile; fontFile->fileName = QLatin1String((const char *)file_value); fontFile->indexValue = indexValue; QFont::Style style = (slant_value == FC_SLANT_ITALIC) ? QFont::StyleItalic : ((slant_value == FC_SLANT_OBLIQUE) ? QFont::StyleOblique : QFont::StyleNormal); QFont::Weight weight = QFont::Weight(getFCWeight(weight_value)); double pixel_size = 0; if (!scalable) FcPatternGetDouble (fonts->fonts[i], FC_PIXEL_SIZE, 0, &pixel_size); int width = FC_WIDTH_NORMAL; FcPatternGetInteger(fonts->fonts[i], FC_WIDTH, 0, &width); QFont::Stretch stretch; switch (width) { case FC_WIDTH_ULTRACONDENSED: stretch = QFont::UltraCondensed; break; case FC_WIDTH_EXTRACONDENSED: stretch = QFont::ExtraCondensed; break; case FC_WIDTH_CONDENSED: stretch = QFont::Condensed; break; case FC_WIDTH_SEMICONDENSED: stretch = QFont::SemiCondensed; break; case FC_WIDTH_NORMAL: stretch = QFont::Unstretched; break; case FC_WIDTH_SEMIEXPANDED: stretch = QFont::SemiExpanded; break; case FC_WIDTH_EXPANDED: stretch = QFont::Expanded; break; case FC_WIDTH_EXTRAEXPANDED: stretch = QFont::ExtraExpanded; break; case FC_WIDTH_ULTRAEXPANDED: stretch = QFont::UltraExpanded; break; default: stretch = QFont::Unstretched; break; } QPlatformFontDatabase::registerFont(familyName,QLatin1String((const char *)foundry_value),weight,style,stretch,antialias,scalable,pixel_size,writingSystems,fontFile); // qDebug() << familyName << (const char *)foundry_value << weight << style << &writingSystems << scalable << true << pixel_size; } FcFontSetDestroy (fonts); struct FcDefaultFont { const char *qtname; const char *rawname; bool fixed; }; const FcDefaultFont defaults[] = { { "Serif", "serif", false }, { "Sans Serif", "sans-serif", false }, { "Monospace", "monospace", true }, { 0, 0, false } }; const FcDefaultFont *f = defaults; // aliases only make sense for 'common', not for any of the specials QSupportedWritingSystems ws; ws.setSupported(QFontDatabase::Latin); while (f->qtname) { registerFont(f->qtname,QLatin1String(""),QFont::Normal,QFont::StyleNormal,QFont::Unstretched,true,true,0,ws,0); registerFont(f->qtname,QLatin1String(""),QFont::Normal,QFont::StyleItalic,QFont::Unstretched,true,true,0,ws,0); registerFont(f->qtname,QLatin1String(""),QFont::Normal,QFont::StyleOblique,QFont::Unstretched,true,true,0,ws,0); ++f; } //Lighthouse has very lazy population of the font db. We want it to be initialized when //QApplication is constructed, so that the population procedure can do something like this to //set the default font // const FcDefaultFont *s = defaults; // QFont font("Sans Serif"); // font.setPointSize(9); // QApplication::setFont(font); }
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; }
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; }
static void SearchFont(VALUE rbFilePathOrName, VALUE* volatile rbRealFilePath, int* ttcIndex) { *rbRealFilePath = Qnil; if (ttcIndex != NULL) { *ttcIndex = -1; } *rbRealFilePath = strb_GetCompletePath(rbFilePathOrName, false); if (!NIL_P(*rbRealFilePath)) { return; } volatile VALUE rbFontNameSymbol = ID2SYM(rb_intern_str(rbFilePathOrName)); FontFileInfo* info = fontFileInfos; while (info) { if (info->rbFontNameSymbol == rbFontNameSymbol) { *rbRealFilePath = rb_str_new2(rb_id2name(SYM2ID(info->rbFileNameSymbol))); #ifdef WIN32 volatile VALUE rbTemp = rb_str_new2(rb_id2name(SYM2ID(rbWindowsFontDirPathSymbol))); *rbRealFilePath = rb_str_concat(rb_str_cat2(rbTemp, "\\"), *rbRealFilePath); #endif if (ttcIndex != NULL) { *ttcIndex = info->ttcIndex; } return; } info = info->next; } #ifdef HAVE_FONTCONFIG_FONTCONFIG_H if (!FcInit()) { FcFini(); rb_raise(strb_GetStarRubyErrorClass(), "can't initialize fontconfig library"); return; } int nameLength = RSTRING_LEN(rbFilePathOrName) + 1; char name[nameLength]; strncpy(name, StringValueCStr(rbFilePathOrName), nameLength); char* delimiter = strchr(name, ','); char* style = NULL; if (delimiter) { *delimiter = '\0'; style = delimiter + 1; char* nameTail = delimiter - 1; while (*nameTail == ' ') { *nameTail = '\0'; nameTail--; } while (*style == ' ') { style++; } } FcPattern* pattern = FcPatternBuild(NULL, FC_FAMILY, FcTypeString, name, NULL); if (style && 0 < strlen(style)) { FcPatternAddString(pattern, FC_STYLE, (FcChar8*)style); } FcObjectSet* objectSet = FcObjectSetBuild(FC_FAMILY, FC_FILE, NULL); FcFontSet* fontSet = FcFontList(NULL, pattern, objectSet); if (objectSet) { FcObjectSetDestroy(objectSet); } if (pattern) { FcPatternDestroy(pattern); } if (fontSet) { for (int i = 0; i < fontSet->nfont; i++) { FcChar8* fileName = NULL; if (FcPatternGetString(fontSet->fonts[i], FC_FILE, 0, &fileName) == FcResultMatch) { FcChar8* fontName = FcNameUnparse(fontSet->fonts[i]); *rbRealFilePath = rb_str_new2((char*)fileName); volatile VALUE rbFontName = rb_str_new2((char*)fontName); free(fontName); fontName = NULL; if (ttcIndex != NULL && strchr(StringValueCStr(rbFontName), ',')) { *ttcIndex = 0; } } } FcFontSetDestroy(fontSet); } FcFini(); if (!NIL_P(*rbRealFilePath)) { return; } #endif return; }
int ZaListFont::init(const char * lang) { m_top = m_height; m_v.clear(); m_path.clear(); FcFontSet* fs = NULL; FcPattern* pat = NULL; FcObjectSet* os = NULL; //FcChar8* strpat = (FcChar8*)":lang=ja"; string ls = ":lang="; ls.append(lang); FcChar8* strpat = (FcChar8*)ls.c_str(); fprintf(stderr,"ZaListFont::fontconf charset %s\n",strpat); pat = FcNameParse(strpat); os = FcObjectSetBuild(FC_FAMILY, FC_CHARSET, FC_FILE, (char *)0); fs = FcFontList(0, pat, os); if(os) FcObjectSetDestroy(os); os = NULL; FcPatternDestroy(pat); pat = NULL; if(!fs || fs->nfont <= 0) goto nofont; FcChar8 *family; FcChar8 *file; FcCharSet* cs; FcChar32 ch; FcUtf8ToUcs4((FcChar8*)"��", &ch, 3); int i; for(i=0; i<fs->nfont; i++) { if(FcPatternGetCharSet(fs->fonts[i], FC_CHARSET, 0, &cs) != FcResultMatch) { fprintf(stderr, "no match\n"); FcPatternPrint(fs->fonts[i]); goto nofont; } if(FcPatternGetString(fs->fonts[i], FC_FAMILY, 1, &family) != FcResultMatch) if(FcPatternGetString(fs->fonts[i], FC_FAMILY, 0, &family) != FcResultMatch) goto nofont; // fprintf(stderr,"ZaListFont::fontconf [%d] %s \n", i, (char *)family); m_v.push_back(string((char *)family)); if(FcPatternGetString(fs->fonts[i], FC_FILE, 0, &file) != FcResultMatch) goto nofont; // fprintf(stderr, "ZaListFont::fontconf (%s): \n", (char *)file); //strcpy(m_charset,charset); //strcpy(this->m_path,(char *)file); m_path.push_back(string((char *)file)); // if(FcCharSetHasChar(cs, ch)) // { // puts("Yes"); // }else // { // puts("No"); // } } FcFontSetDestroy(fs); return 0; nofont: return 1; }
static void apply_xft_settings (struct x_display_info *dpyinfo, struct xsettings *settings) { #ifdef HAVE_XFT FcPattern *pat; struct xsettings oldsettings; bool changed = false; memset (&oldsettings, 0, sizeof (oldsettings)); pat = FcPatternCreate (); XftDefaultSubstitute (dpyinfo->display, XScreenNumberOfScreen (dpyinfo->screen), pat); FcPatternGetBool (pat, FC_ANTIALIAS, 0, &oldsettings.aa); FcPatternGetBool (pat, FC_HINTING, 0, &oldsettings.hinting); #ifdef FC_HINT_STYLE FcPatternGetInteger (pat, FC_HINT_STYLE, 0, &oldsettings.hintstyle); #endif FcPatternGetInteger (pat, FC_LCD_FILTER, 0, &oldsettings.lcdfilter); FcPatternGetInteger (pat, FC_RGBA, 0, &oldsettings.rgba); FcPatternGetDouble (pat, FC_DPI, 0, &oldsettings.dpi); if ((settings->seen & SEEN_AA) != 0 && oldsettings.aa != settings->aa) { FcPatternDel (pat, FC_ANTIALIAS); FcPatternAddBool (pat, FC_ANTIALIAS, settings->aa); changed = true; oldsettings.aa = settings->aa; } if ((settings->seen & SEEN_HINTING) != 0 && oldsettings.hinting != settings->hinting) { FcPatternDel (pat, FC_HINTING); FcPatternAddBool (pat, FC_HINTING, settings->hinting); changed = true; oldsettings.hinting = settings->hinting; } if ((settings->seen & SEEN_RGBA) != 0 && oldsettings.rgba != settings->rgba) { FcPatternDel (pat, FC_RGBA); FcPatternAddInteger (pat, FC_RGBA, settings->rgba); oldsettings.rgba = settings->rgba; changed = true; } /* Older fontconfig versions don't have FC_LCD_FILTER. */ if ((settings->seen & SEEN_LCDFILTER) != 0 && oldsettings.lcdfilter != settings->lcdfilter) { FcPatternDel (pat, FC_LCD_FILTER); FcPatternAddInteger (pat, FC_LCD_FILTER, settings->lcdfilter); changed = true; oldsettings.lcdfilter = settings->lcdfilter; } #ifdef FC_HINT_STYLE if ((settings->seen & SEEN_HINTSTYLE) != 0 && oldsettings.hintstyle != settings->hintstyle) { FcPatternDel (pat, FC_HINT_STYLE); FcPatternAddInteger (pat, FC_HINT_STYLE, settings->hintstyle); changed = true; oldsettings.hintstyle = settings->hintstyle; } #endif if ((settings->seen & SEEN_DPI) != 0 && settings->dpi > 0 /* The following conjunct avoids setting `changed' to true when old and new dpi settings do not differ "substantially". Otherwise, the dynamic-setting Elisp code may process all sorts of unrelated settings that override users' font customizations, among others. Compare: https://lists.gnu.org/r/emacs-devel/2016-05/msg00557.html https://lists.gnu.org/r/bug-gnu-emacs/2016-12/msg00820.html As soon as the dynamic-settings code has been tested and verified, this Emacs 25.2 workaround should be removed. */ && ((oldsettings.dpi >= settings->dpi && (oldsettings.dpi - settings->dpi) > 2) || ((settings->dpi > oldsettings.dpi) && (settings->dpi - oldsettings.dpi) > 2))) { FcPatternDel (pat, FC_DPI); FcPatternAddDouble (pat, FC_DPI, settings->dpi); changed = true; oldsettings.dpi = settings->dpi; /* Changing the DPI on this display affects all frames on it. Check FRAME_RES_X and FRAME_RES_Y in frame.h to see how. */ dpyinfo->resy = dpyinfo->resx = settings->dpi; } if (changed) { static char const format[] = "Antialias: %d, Hinting: %d, RGBA: %d, LCDFilter: %d, " "Hintstyle: %d, DPI: %f"; enum { d_formats = 5, d_growth = INT_BUFSIZE_BOUND (int) - sizeof "%d", lf_formats = 1, max_f_integer_digits = DBL_MAX_10_EXP + 1, f_precision = 6, lf_growth = (sizeof "-." + max_f_integer_digits + f_precision - sizeof "%f") }; char buf[sizeof format + d_formats * d_growth + lf_formats * lf_growth]; XftDefaultSet (dpyinfo->display, pat); store_config_changed_event (Qfont_render, XCAR (dpyinfo->name_list_element)); Vxft_settings = make_formatted_string (buf, format, oldsettings.aa, oldsettings.hinting, oldsettings.rgba, oldsettings.lcdfilter, oldsettings.hintstyle, oldsettings.dpi); } else FcPatternDestroy (pat); #endif /* HAVE_XFT */ }
MagickExport MagickBooleanType LoadFontConfigFonts(SplayTreeInfo *type_list, ExceptionInfo *exception) { char extension[MaxTextExtent], name[MaxTextExtent]; FcChar8 *family, *file, *style; FcConfig *font_config; FcFontSet *font_set; FcObjectSet *object_set; FcPattern *pattern; FcResult status; int slant, width, weight; register long i; TypeInfo *type_info; /* Load system fonts. */ (void) exception; font_config=FcInitLoadConfigAndFonts(); if (font_config == (FcConfig *) NULL) return(MagickFalse); font_set=(FcFontSet *) NULL; object_set=FcObjectSetBuild(FC_FAMILY,FC_STYLE,FC_SLANT,FC_WIDTH,FC_WEIGHT, FC_FILE,(char *) NULL); if (object_set != (FcObjectSet *) NULL) { pattern=FcPatternCreate(); if (pattern != (FcPattern *) NULL) { font_set=FcFontList(0,pattern,object_set); FcPatternDestroy(pattern); } FcObjectSetDestroy(object_set); } if (font_set == (FcFontSet *) NULL) { FcConfigDestroy(font_config); return(MagickFalse); } for (i=0; i < (long) font_set->nfont; i++) { status=FcPatternGetString(font_set->fonts[i],FC_FAMILY,0,&family); if (status != FcResultMatch) continue; status=FcPatternGetString(font_set->fonts[i],FC_FILE,0,&file); if (status != FcResultMatch) continue; *extension='\0'; GetPathComponent((const char *) file,ExtensionPath,extension); if ((*extension != '\0') && (LocaleCompare(extension,"gz") == 0)) continue; type_info=(TypeInfo *) AcquireAlignedMemory(1,sizeof(*type_info)); if (type_info == (TypeInfo *) NULL) continue; (void) ResetMagickMemory(type_info,0,sizeof(*type_info)); type_info->path=ConstantString("System Fonts"); type_info->signature=MagickSignature; (void) CopyMagickString(name,(const char *) family,MaxTextExtent); (void) ConcatenateMagickString(name," ",MaxTextExtent); status=FcPatternGetString(font_set->fonts[i],FC_STYLE,0,&style); if (status == FcResultMatch) (void) ConcatenateMagickString(name,(const char *) style,MaxTextExtent); type_info->name=ConstantString(name); (void) SubstituteString(&type_info->name," ","-"); (void) SubstituteString(&type_info->name,"-L-","-"); (void) SubstituteString(&type_info->name,"semicondensed","SemiCondensed"); type_info->family=ConstantString((const char *) family); (void) SubstituteString(&type_info->family," L",""); status=FcPatternGetInteger(font_set->fonts[i],FC_SLANT,0,&slant); type_info->style=NormalStyle; if (slant == FC_SLANT_ITALIC) type_info->style=ItalicStyle; if (slant == FC_SLANT_OBLIQUE) type_info->style=ObliqueStyle; status=FcPatternGetInteger(font_set->fonts[i],FC_WIDTH,0,&width); type_info->stretch=NormalStretch; if (width >= FC_WIDTH_ULTRACONDENSED) type_info->stretch=UltraCondensedStretch; if (width >= FC_WIDTH_EXTRACONDENSED) type_info->stretch=ExtraCondensedStretch; if (width >= FC_WIDTH_CONDENSED) type_info->stretch=CondensedStretch; if (width >= FC_WIDTH_SEMICONDENSED) type_info->stretch=SemiCondensedStretch; if (width >= FC_WIDTH_NORMAL) type_info->stretch=NormalStretch; if (width >= FC_WIDTH_SEMIEXPANDED) type_info->stretch=SemiExpandedStretch; if (width >= FC_WIDTH_EXPANDED) type_info->stretch=ExpandedStretch; if (width >= FC_WIDTH_EXTRAEXPANDED) type_info->stretch=ExtraExpandedStretch; if (width >= FC_WIDTH_ULTRAEXPANDED) type_info->stretch=UltraExpandedStretch; type_info->weight=400; status=FcPatternGetInteger(font_set->fonts[i],FC_WEIGHT,0,&weight); if (weight >= FC_WEIGHT_THIN) type_info->weight=100; if (weight >= FC_WEIGHT_EXTRALIGHT) type_info->weight=200; if (weight >= FC_WEIGHT_LIGHT) type_info->weight=300; if (weight >= FC_WEIGHT_NORMAL) type_info->weight=400; if (weight >= FC_WEIGHT_MEDIUM) type_info->weight=500; if (weight >= FC_WEIGHT_DEMIBOLD) type_info->weight=600; if (weight >= FC_WEIGHT_BOLD) type_info->weight=700; if (weight >= FC_WEIGHT_EXTRABOLD) type_info->weight=800; if (weight >= FC_WEIGHT_BLACK) type_info->weight=900; type_info->glyphs=ConstantString((const char *) file); (void) AddValueToSplayTree(type_list,type_info->name,type_info); } FcFontSetDestroy(font_set); FcConfigDestroy(font_config); return(MagickTrue); }
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_families_index(const FcPattern *filter) { int unused_int, f, nfamilies; FcPattern *pattern, *match; FcFontSet *fontset, *tmp, *families; FcResult r; FcChar8 *family, *next_family, *normal_style, *style; FcInit(); pattern = FcPatternDuplicate(filter); fontset = fcinfo(NULL, filter, FcFalse, 5, FC_FAMILY, FC_STYLE, FC_LANG,/* fonts like Misc Fixed need to be sorted by LANG (subset-like) */ FC_PIXEL_SIZE, FC_FILE); /* for identifying the best font in FC_LANG terms */ if (fontset->nfont == 0) return fontset; tmp = fcinfo_match(fontset, pattern); FcFontSetDestroy(fontset); fontset = tmp; if (FcPatternGetInteger(pattern, FC_WEIGHT, 0, &unused_int) != FcResultMatch) FcPatternAddInteger(pattern, FC_WEIGHT, FC_WEIGHT_REGULAR); if (FcPatternGetInteger(pattern, FC_SLANT, 0, &unused_int) != FcResultMatch) FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ROMAN); if (FcPatternGetInteger(pattern, FC_WIDTH, 0, &unused_int) != FcResultMatch) FcPatternAddInteger(pattern, FC_WIDTH, FC_WIDTH_NORMAL); /* choose 'normal' styles according to pattern */ families = FcFontSetCreate(); nfamilies = 0; for (f = 0; f < fontset->nfont; ) { assert(fcinfo_get_translated_string(fontset->fonts[f], FC_FAMILY, LANG_EN, &family) == FcResultMatch); FcPatternDel(pattern, FC_FAMILY); FcPatternAddString(pattern, FC_FAMILY, family); match = FcFontSetMatch(NULL, &fontset, 1, pattern, &r); assert(fcinfo_get_translated_string(match, FC_STYLE, LANG_EN, &normal_style) == FcResultMatch); do { assert(fcinfo_get_translated_string(fontset->fonts[f], FC_STYLE, LANG_EN, &style) == FcResultMatch); if (FcStrCmpIgnoreCase(style, normal_style) == 0) FcFontSetAdd(families, FcPatternDuplicate(fontset->fonts[f])); if (++f == fontset->nfont) break; assert(fcinfo_get_translated_string(fontset->fonts[f], FC_FAMILY, LANG_EN, &next_family) == FcResultMatch); } while (FcStrCmpIgnoreCase(family, next_family) == 0); nfamilies++; } FcPatternDestroy(pattern); FcFontSetDestroy(fontset); return families; }
static void apply_xft_settings (struct x_display_info *dpyinfo, struct xsettings *settings) { #ifdef HAVE_XFT FcPattern *pat; struct xsettings oldsettings; bool changed = false; memset (&oldsettings, 0, sizeof (oldsettings)); pat = FcPatternCreate (); XftDefaultSubstitute (dpyinfo->display, XScreenNumberOfScreen (dpyinfo->screen), pat); FcPatternGetBool (pat, FC_ANTIALIAS, 0, &oldsettings.aa); FcPatternGetBool (pat, FC_HINTING, 0, &oldsettings.hinting); #ifdef FC_HINT_STYLE FcPatternGetInteger (pat, FC_HINT_STYLE, 0, &oldsettings.hintstyle); #endif FcPatternGetInteger (pat, FC_LCD_FILTER, 0, &oldsettings.lcdfilter); FcPatternGetInteger (pat, FC_RGBA, 0, &oldsettings.rgba); FcPatternGetDouble (pat, FC_DPI, 0, &oldsettings.dpi); if ((settings->seen & SEEN_AA) != 0 && oldsettings.aa != settings->aa) { FcPatternDel (pat, FC_ANTIALIAS); FcPatternAddBool (pat, FC_ANTIALIAS, settings->aa); changed = true; oldsettings.aa = settings->aa; } if ((settings->seen & SEEN_HINTING) != 0 && oldsettings.hinting != settings->hinting) { FcPatternDel (pat, FC_HINTING); FcPatternAddBool (pat, FC_HINTING, settings->hinting); changed = true; oldsettings.hinting = settings->hinting; } if ((settings->seen & SEEN_RGBA) != 0 && oldsettings.rgba != settings->rgba) { FcPatternDel (pat, FC_RGBA); FcPatternAddInteger (pat, FC_RGBA, settings->rgba); oldsettings.rgba = settings->rgba; changed = true; } /* Older fontconfig versions don't have FC_LCD_FILTER. */ if ((settings->seen & SEEN_LCDFILTER) != 0 && oldsettings.lcdfilter != settings->lcdfilter) { FcPatternDel (pat, FC_LCD_FILTER); FcPatternAddInteger (pat, FC_LCD_FILTER, settings->lcdfilter); changed = true; oldsettings.lcdfilter = settings->lcdfilter; } #ifdef FC_HINT_STYLE if ((settings->seen & SEEN_HINTSTYLE) != 0 && oldsettings.hintstyle != settings->hintstyle) { FcPatternDel (pat, FC_HINT_STYLE); FcPatternAddInteger (pat, FC_HINT_STYLE, settings->hintstyle); changed = true; oldsettings.hintstyle = settings->hintstyle; } #endif if ((settings->seen & SEEN_DPI) != 0 && oldsettings.dpi != settings->dpi && settings->dpi > 0) { FcPatternDel (pat, FC_DPI); FcPatternAddDouble (pat, FC_DPI, settings->dpi); changed = true; oldsettings.dpi = settings->dpi; /* Changing the DPI on this display affects all frames on it. Check FRAME_RES_X and FRAME_RES_Y in frame.h to see how. */ dpyinfo->resy = dpyinfo->resx = settings->dpi; } if (changed) { static char const format[] = "Antialias: %d, Hinting: %d, RGBA: %d, LCDFilter: %d, " "Hintstyle: %d, DPI: %f"; enum { d_formats = 5, d_growth = INT_BUFSIZE_BOUND (int) - sizeof "%d", lf_formats = 1, max_f_integer_digits = DBL_MAX_10_EXP + 1, f_precision = 6, lf_growth = (sizeof "-." + max_f_integer_digits + f_precision - sizeof "%f") }; char buf[sizeof format + d_formats * d_growth + lf_formats * lf_growth]; XftDefaultSet (dpyinfo->display, pat); store_config_changed_event (Qfont_render, XCAR (dpyinfo->name_list_element)); Vxft_settings = make_formatted_string (buf, format, oldsettings.aa, oldsettings.hinting, oldsettings.rgba, oldsettings.lcdfilter, oldsettings.hintstyle, oldsettings.dpi); } else FcPatternDestroy (pat); #endif /* HAVE_XFT */ }
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; }
QFontEngine *QFontconfigDatabase::fontEngine(const QFontDef &f, QUnicodeTables::Script script, void *usrPtr) { if (!usrPtr) return 0; QFontDef fontDef = f; QFontEngineFT *engine; FontFile *fontfile = static_cast<FontFile *> (usrPtr); QFontEngine::FaceId fid; fid.filename = fontfile->fileName.toLocal8Bit(); fid.index = fontfile->indexValue; bool antialias = !(fontDef.styleStrategy & QFont::NoAntialias); QFontEngineFT::GlyphFormat format = antialias? QFontEngineFT::Format_A8 : QFontEngineFT::Format_Mono; engine = new QFontEngineFT(fontDef); // try and get the pattern FcPattern *pattern = FcPatternCreate(); FcValue value; value.type = FcTypeString; QByteArray cs = fontDef.family.toUtf8(); value.u.s = (const FcChar8 *)cs.data(); FcPatternAdd(pattern,FC_FAMILY,value,true); value.u.s = (const FcChar8 *)fid.filename.data(); FcPatternAdd(pattern,FC_FILE,value,true); value.type = FcTypeInteger; value.u.i = fid.index; FcPatternAdd(pattern,FC_INDEX,value,true); if (FcConfigSubstitute(0,pattern,FcMatchPattern)) { QFontEngineFT::HintStyle default_hint_style; //hinting int hint_style = 0; if (FcPatternGetInteger (pattern, FC_HINT_STYLE, 0, &hint_style) == FcResultNoMatch) hint_style = QFontEngineFT::HintFull; switch (hint_style) { case FC_HINT_NONE: default_hint_style = QFontEngineFT::HintNone; break; case FC_HINT_SLIGHT: default_hint_style = QFontEngineFT::HintLight; break; case FC_HINT_MEDIUM: default_hint_style = QFontEngineFT::HintMedium; break; default: default_hint_style = QFontEngineFT::HintFull; break; } engine->setDefaultHintStyle(default_hint_style); } FcPatternDestroy(pattern); if (!engine->init(fid,antialias,format)) { delete engine; engine = 0; return engine; } if (engine->invalid()) { delete engine; engine = 0; } else if (scriptRequiresOpenType(script)) { HB_Face hbFace = engine->harfbuzzFace(); if (!hbFace || !hbFace->supported_scripts[script]) { delete engine; engine = 0; } } return engine; }
/** * \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; 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)) ass_msg(library, MSGL_WARN, "fontconfig: Selected font is not the requested one: " "'%s' != '%s'", (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; 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 Lisp_Object xftfont_open (struct frame *f, Lisp_Object entity, int pixel_size) { FcResult result; Display *display = FRAME_X_DISPLAY (f); Lisp_Object val, filename, idx, font_object; FcPattern *pat = NULL, *match; struct xftfont_info *xftfont_info = NULL; struct font *font; double size = 0; XftFont *xftfont = NULL; int spacing; char name[256]; int len, i; XGlyphInfo extents; FT_Face ft_face; FcMatrix *matrix; val = assq_no_quit (QCfont_entity, AREF (entity, FONT_EXTRA_INDEX)); if (! CONSP (val)) return Qnil; val = XCDR (val); filename = XCAR (val); idx = XCDR (val); size = XINT (AREF (entity, FONT_SIZE_INDEX)); if (size == 0) size = pixel_size; pat = FcPatternCreate (); FcPatternAddInteger (pat, FC_WEIGHT, FONT_WEIGHT_NUMERIC (entity)); i = FONT_SLANT_NUMERIC (entity) - 100; if (i < 0) i = 0; FcPatternAddInteger (pat, FC_SLANT, i); FcPatternAddInteger (pat, FC_WIDTH, FONT_WIDTH_NUMERIC (entity)); FcPatternAddDouble (pat, FC_PIXEL_SIZE, pixel_size); val = AREF (entity, FONT_FAMILY_INDEX); if (! NILP (val)) FcPatternAddString (pat, FC_FAMILY, (FcChar8 *) SDATA (SYMBOL_NAME (val))); val = AREF (entity, FONT_FOUNDRY_INDEX); if (! NILP (val)) FcPatternAddString (pat, FC_FOUNDRY, (FcChar8 *) SDATA (SYMBOL_NAME (val))); val = AREF (entity, FONT_SPACING_INDEX); if (! NILP (val)) FcPatternAddInteger (pat, FC_SPACING, XINT (val)); val = AREF (entity, FONT_DPI_INDEX); if (! NILP (val)) { double dbl = XINT (val); FcPatternAddDouble (pat, FC_DPI, dbl); } val = AREF (entity, FONT_AVGWIDTH_INDEX); if (INTEGERP (val) && XINT (val) == 0) FcPatternAddBool (pat, FC_SCALABLE, FcTrue); /* This is necessary to identify the exact font (e.g. 10x20.pcf.gz over 10x20-ISO8859-1.pcf.gz). */ FcPatternAddCharSet (pat, FC_CHARSET, ftfont_get_fc_charset (entity)); xftfont_add_rendering_parameters (pat, entity); FcPatternAddString (pat, FC_FILE, (FcChar8 *) SDATA (filename)); FcPatternAddInteger (pat, FC_INDEX, XINT (idx)); block_input (); /* Make sure that the Xrender extension is added before the Xft one. Otherwise, the close-display hook set by Xft is called after the one for Xrender, and the former tries to re-add the latter. This results in inconsistency of internal states and leads to X protocol error when one reconnects to the same X server. (Bug#1696) */ { int event_base, error_base; XRenderQueryExtension (display, &event_base, &error_base); } /* Substitute in values from X resources and XftDefaultSet. */ XftDefaultSubstitute (display, FRAME_X_SCREEN_NUMBER (f), pat); match = XftFontMatch (display, FRAME_X_SCREEN_NUMBER (f), pat, &result); xftfont_fix_match (pat, match); FcPatternDestroy (pat); xftfont = XftFontOpenPattern (display, match); if (!xftfont) { unblock_input (); XftPatternDestroy (match); return Qnil; } ft_face = XftLockFace (xftfont); unblock_input (); /* We should not destroy PAT here because it is kept in XFTFONT and destroyed automatically when XFTFONT is closed. */ font_object = font_make_object (VECSIZE (struct xftfont_info), entity, size); ASET (font_object, FONT_TYPE_INDEX, Qxft); len = font_unparse_xlfd (entity, size, name, 256); if (len > 0) ASET (font_object, FONT_NAME_INDEX, make_string (name, len)); len = font_unparse_fcname (entity, size, name, 256); if (len > 0) ASET (font_object, FONT_FULLNAME_INDEX, make_string (name, len)); else ASET (font_object, FONT_FULLNAME_INDEX, AREF (font_object, FONT_NAME_INDEX)); ASET (font_object, FONT_FILE_INDEX, filename); ASET (font_object, FONT_FORMAT_INDEX, ftfont_font_format (xftfont->pattern, filename)); font = XFONT_OBJECT (font_object); font->pixel_size = size; font->driver = &xftfont_driver; font->encoding_charset = font->repertory_charset = -1; xftfont_info = (struct xftfont_info *) font; xftfont_info->display = display; xftfont_info->xftfont = xftfont; /* This means that there's no need of transformation. */ xftfont_info->matrix.xx = 0; if (FcPatternGetMatrix (xftfont->pattern, FC_MATRIX, 0, &matrix) == FcResultMatch) { xftfont_info->matrix.xx = 0x10000L * matrix->xx; xftfont_info->matrix.yy = 0x10000L * matrix->yy; xftfont_info->matrix.xy = 0x10000L * matrix->xy; xftfont_info->matrix.yx = 0x10000L * matrix->yx; } if (INTEGERP (AREF (entity, FONT_SPACING_INDEX))) spacing = XINT (AREF (entity, FONT_SPACING_INDEX)); else spacing = FC_PROPORTIONAL; if (! ascii_printable[0]) { int ch; for (ch = 0; ch < 95; ch++) ascii_printable[ch] = ' ' + ch; } block_input (); /* Unfortunately Xft doesn't provide a way to get minimum char width. So, we set min_width to space_width. */ if (spacing != FC_PROPORTIONAL #ifdef FC_DUAL && spacing != FC_DUAL #endif /* FC_DUAL */ ) { font->min_width = font->max_width = font->average_width = font->space_width = xftfont->max_advance_width; XftTextExtents8 (display, xftfont, ascii_printable + 1, 94, &extents); } else { XftTextExtents8 (display, xftfont, ascii_printable, 1, &extents); font->min_width = font->max_width = font->space_width = extents.xOff; if (font->space_width <= 0) /* dirty workaround */ font->space_width = pixel_size; XftTextExtents8 (display, xftfont, ascii_printable + 1, 94, &extents); font->average_width = (font->space_width + extents.xOff) / 95; } unblock_input (); font->ascent = xftfont->ascent; font->descent = xftfont->descent; if (pixel_size >= 5) { /* The above condition is a dirty workaround because XftTextExtents8 behaves strangely for some fonts (e.g. "Dejavu Sans Mono") when pixel_size is less than 5. */ if (font->ascent < extents.y) font->ascent = extents.y; if (font->descent < extents.height - extents.y) font->descent = extents.height - extents.y; } font->height = font->ascent + font->descent; if (XINT (AREF (entity, FONT_SIZE_INDEX)) == 0) { int upEM = ft_face->units_per_EM; font->underline_position = -ft_face->underline_position * size / upEM; font->underline_thickness = ft_face->underline_thickness * size / upEM; if (font->underline_thickness > 2) font->underline_position -= font->underline_thickness / 2; } else { font->underline_position = -1; font->underline_thickness = 0; } #ifdef HAVE_LIBOTF xftfont_info->maybe_otf = (ft_face->face_flags & FT_FACE_FLAG_SFNT) != 0; xftfont_info->otf = NULL; #endif /* HAVE_LIBOTF */ xftfont_info->ft_size = ft_face->size; font->baseline_offset = 0; font->relative_compose = 0; font->default_ascent = 0; font->vertical_centering = 0; #ifdef FT_BDF_H if (! (ft_face->face_flags & FT_FACE_FLAG_SFNT)) { BDF_PropertyRec rec; if (FT_Get_BDF_Property (ft_face, "_MULE_BASELINE_OFFSET", &rec) == 0 && rec.type == BDF_PROPERTY_TYPE_INTEGER) font->baseline_offset = rec.u.integer; if (FT_Get_BDF_Property (ft_face, "_MULE_RELATIVE_COMPOSE", &rec) == 0 && rec.type == BDF_PROPERTY_TYPE_INTEGER) font->relative_compose = rec.u.integer; if (FT_Get_BDF_Property (ft_face, "_MULE_DEFAULT_ASCENT", &rec) == 0 && rec.type == BDF_PROPERTY_TYPE_INTEGER) font->default_ascent = rec.u.integer; } #endif return font_object; }
FontInfo * get_font_info_list (int *num) { FcInit(); *num = -1; FcPattern *pat = FcPatternCreate(); if (!pat) { fprintf(stderr, "Create FcPattern Failed\n"); return NULL; } FcObjectSet *os = FcObjectSetBuild( FC_FAMILY, FC_FAMILYLANG, FC_STYLE, FC_FILE, FC_LANG, FC_SPACING, NULL); if (!os) { fprintf(stderr, "Build FcObjectSet Failed\n"); FcPatternDestroy(pat); return NULL; } FcFontSet *fs = FcFontList(0, pat, os); FcObjectSetDestroy(os); FcPatternDestroy(pat); if (!fs) { fprintf(stderr, "List Font Failed\n"); return NULL; } int i; int cnt = 0; FontInfo *list = NULL; for (i = 0; i < fs->nfont; i++) { FontInfo *info = calloc(1, sizeof(FontInfo)); if (!info) { fprintf(stderr, "Alloc memory failed"); continue; } info->family = (char*)FcPatternFormat(fs->fonts[i], (FcChar8*)"%{family}"); info->familylang = (char*)FcPatternFormat(fs->fonts[i], (FcChar8*)"%{familylang}"); info->style = (char*)FcPatternFormat(fs->fonts[i], (FcChar8*)"%{style}"); info->filename = (char*)FcPatternFormat(fs->fonts[i], (FcChar8*)"%{file}"); info->lang = (char*)FcPatternFormat(fs->fonts[i], (FcChar8*)"%{lang}"); info->spacing = (char*)FcPatternFormat(fs->fonts[i], (FcChar8*)"%{spacing}"); if (!info->family || !info->familylang || !info->style || !info->filename || !info->lang || !info->spacing) { font_info_free(info); continue; } FontInfo *tmp = malloc((cnt+1) * sizeof(FontInfo)); if (!tmp) { fprintf(stderr, "Alloc memory failed\n"); font_info_free(info); continue; } memcpy(tmp+cnt, info, sizeof(FontInfo)); free(info); if (cnt != 0 ) { memcpy(tmp, list, cnt * sizeof(FontInfo)); free(list); list = NULL; } list = tmp; tmp = NULL; cnt++; } FcFontSetDestroy(fs); FcFini(); // Error: FcCacheFini *num = cnt; return list; }
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; }
TkFont * TkpGetFontFromAttributes( TkFont *tkFontPtr, /* If non-NULL, store the information in this * existing TkFont structure, rather than * allocating a new structure to hold the * font; the existing contents of the font * will be released. If NULL, a new TkFont * structure is allocated. */ Tk_Window tkwin, /* For display where font will be used. */ const TkFontAttributes *faPtr) /* Set of attributes to match. */ { XftPattern *pattern; int weight, slant; UnixFtFont *fontPtr; #if DEBUG_FONTSEL printf("TkpGetFontFromAttributes %s-%d %d %d\n", faPtr->family, faPtr->size, faPtr->weight, faPtr->slant); #endif /* DEBUG_FONTSEL */ pattern = XftPatternCreate(); if (faPtr->family) { XftPatternAddString(pattern, XFT_FAMILY, faPtr->family); } if (faPtr->size > 0) { XftPatternAddDouble(pattern, XFT_SIZE, (double)faPtr->size); } else if (faPtr->size < 0) { XftPatternAddInteger(pattern, XFT_PIXEL_SIZE, -faPtr->size); } else { XftPatternAddDouble(pattern, XFT_SIZE, 12.0); } switch (faPtr->weight) { case TK_FW_NORMAL: default: weight = XFT_WEIGHT_MEDIUM; break; case TK_FW_BOLD: weight = XFT_WEIGHT_BOLD; break; } XftPatternAddInteger(pattern, XFT_WEIGHT, weight); switch (faPtr->slant) { case TK_FS_ROMAN: default: slant = XFT_SLANT_ROMAN; break; case TK_FS_ITALIC: slant = XFT_SLANT_ITALIC; break; case TK_FS_OBLIQUE: slant = XFT_SLANT_OBLIQUE; break; } XftPatternAddInteger(pattern, XFT_SLANT, slant); fontPtr = (UnixFtFont *) tkFontPtr; if (fontPtr != NULL) { FinishedWithFont(fontPtr); } fontPtr = InitFont(tkwin, pattern, fontPtr); /* * Hack to work around issues with weird issues with Xft/Xrender * connection. For details, see comp.lang.tcl thread starting from * <*****@*****.**> */ if (!fontPtr) { XftPatternAddBool(pattern, XFT_RENDER, FcFalse); fontPtr = InitFont(tkwin, pattern, fontPtr); } if (!fontPtr) { FcPatternDestroy(pattern); return NULL; } fontPtr->font.fa.underline = faPtr->underline; fontPtr->font.fa.overstrike = faPtr->overstrike; return &fontPtr->font; }
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; }
/* ======================================================================================== * FontConfig (unix) support * ======================================================================================== */ static 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; }
int face_from_options(lua_State* L) { FT_Face face; FcChar8 * font_path; FcPattern* p; FcPattern* matched; FcResult result; int index = 0; const char *family = "Gentium"; double pointSize = 12; int slant = FC_SLANT_ROMAN; int weight = 100; const char *script = "latin"; const char *language = "eng"; int direction = HB_DIRECTION_LTR; if (!lua_istable(L, 1)) return 0; lua_pushstring(L, "font"); lua_gettable(L, -2); if (lua_isstring(L, -1)) { family = lua_tostring(L, -1); } lua_pop(L,1); lua_pushstring(L, "weight"); lua_gettable(L, -2); if (lua_isnumber(L, -1)) { int newWeight = lua_tointeger(L, -1); if (newWeight <= 100) newWeight = FC_WEIGHT_THIN; else if (newWeight <= 200) newWeight = FC_WEIGHT_ULTRALIGHT; else if (newWeight <= 300) newWeight = FC_WEIGHT_LIGHT; else if (newWeight <= 400) newWeight = FC_WEIGHT_NORMAL; else if (newWeight <= 500) newWeight = FC_WEIGHT_MEDIUM; else if (newWeight <= 600) newWeight = FC_WEIGHT_DEMIBOLD; else if (newWeight <= 700) newWeight = FC_WEIGHT_BOLD; else if (newWeight <= 800) newWeight = FC_WEIGHT_ULTRABOLD; else newWeight = FC_WEIGHT_HEAVY; weight = newWeight; } lua_pop(L,1); lua_pushstring(L, "size"); lua_gettable(L, -2); if (lua_isnumber(L, -1)) { pointSize = lua_tonumber(L, -1); } lua_pop(L,1); lua_pushstring(L, "language"); lua_gettable(L, -2); if (lua_isstring(L, -1)) { language = lua_tostring(L, -1); } lua_pop(L,1); lua_pushstring(L, "style"); lua_gettable(L, -2); if (lua_isstring(L, -1)) { const char* newStyleAsText = lua_tostring(L, -1); if (!strcmp(newStyleAsText, "italic")) slant = FC_SLANT_ITALIC; } lua_pop(L,1); p = FcPatternCreate(); FcPatternAddString (p, FC_FAMILY, (FcChar8*)(family)); FcPatternAddDouble (p, FC_SIZE, pointSize); FcPatternAddInteger(p, FC_SLANT, slant); FcPatternAddInteger(p, FC_WEIGHT, weight); // /* Add fallback fonts here. Some of the standard 14 should be fine. */ FcPatternAddString (p, FC_FAMILY,(FcChar8*) "Times-Roman"); FcPatternAddString (p, FC_FAMILY,(FcChar8*) "Times"); FcPatternAddString (p, FC_FAMILY,(FcChar8*) "Helvetica"); matched = FcFontMatch (0, p, &result); if (FcPatternGetString (matched, FC_FILE, 0, &font_path) != FcResultMatch) return 0; FcPatternGetInteger(matched, FC_INDEX, 0, &index); font_path = (FcChar8 *)strdup((char*)font_path); /* XXX signedness problems? */ if (!font_path) { printf("Finding font path failed\n"); return 0; } /* Push back slant and weight, we need to pass them to libpdftex */ FcPatternGetInteger(matched, FC_SLANT, 0, &slant); FcPatternGetInteger(matched, FC_WEIGHT, 0, &weight); /* Find out which family we did actually pick up */ if (FcPatternGetString (matched, FC_FAMILY, 0, &family) != FcResultMatch) return 0; lua_newtable(L); lua_pushstring(L, "filename"); lua_pushstring(L, (char*)font_path); lua_settable(L, -3); lua_pushstring(L, "family"); lua_pushstring(L, (char*)(family)); lua_settable(L, -3); FcPatternDestroy (matched); FcPatternDestroy (p); face = (FT_Face)malloc(sizeof(FT_Face)); if (FT_New_Face(ft_library, (char*)font_path, index, &face)) return 0; if (FT_Set_Char_Size(face,pointSize * 64.0, 0, 0, 0)) return 0; lua_pushstring(L, "index"); lua_pushinteger(L, index); lua_settable(L, -3); lua_pushstring(L, "pointsize"); lua_pushnumber(L, pointSize); lua_settable(L, -3); lua_pushstring(L, "face"); lua_pushlightuserdata(L, face); lua_settable(L, -3); return 1; }
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 (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); FcStrFree (s); } } FcPatternDestroy (font); } FcFontSetDestroy (fs); } if (os) FcObjectSetDestroy (os); FcFini (); return 0; }
static FcBool FcListAppend (FcListHashTable *table, FcPattern *font, FcObjectSet *os, const FcChar8 *lang) { int o; FcPatternElt *e; FcValueListPtr v; FcChar32 hash; FcListBucket **prev, *bucket; int familyidx = -1; int fullnameidx = -1; int styleidx = -1; int defidx = 0; int idx; hash = FcListPatternHash (font, os); for (prev = &table->buckets[hash % FC_LIST_HASH_SIZE]; (bucket = *prev); prev = &(bucket->next)) { if (bucket->hash == hash && FcListPatternEqual (bucket->pattern, font, os)) return FcTrue; } bucket = (FcListBucket *) malloc (sizeof (FcListBucket)); if (!bucket) goto bail0; bucket->next = 0; bucket->hash = hash; bucket->pattern = FcPatternCreate (); if (!bucket->pattern) goto bail1; for (o = 0; o < os->nobject; o++) { if (!strcmp (os->objects[o], FC_FAMILY) || !strcmp (os->objects[o], FC_FAMILYLANG)) { if (familyidx < 0) familyidx = FcGetDefaultObjectLangIndex (font, FC_FAMILYLANG_OBJECT, lang); defidx = familyidx; } else if (!strcmp (os->objects[o], FC_FULLNAME) || !strcmp (os->objects[o], FC_FULLNAMELANG)) { if (fullnameidx < 0) fullnameidx = FcGetDefaultObjectLangIndex (font, FC_FULLNAMELANG_OBJECT, lang); defidx = fullnameidx; } else if (!strcmp (os->objects[o], FC_STYLE) || !strcmp (os->objects[o], FC_STYLELANG)) { if (styleidx < 0) styleidx = FcGetDefaultObjectLangIndex (font, FC_STYLELANG_OBJECT, lang); defidx = styleidx; } else defidx = 0; e = FcPatternObjectFindElt (font, FcObjectFromName (os->objects[o])); if (e) { for (v = FcPatternEltValues(e), idx = 0; v; v = FcValueListNext(v), ++idx) { if (!FcPatternAdd (bucket->pattern, os->objects[o], FcValueCanonicalize(&v->value), defidx != idx)) goto bail2; } } } *prev = bucket; ++table->entries; return FcTrue; bail2: FcPatternDestroy (bucket->pattern); bail1: free (bucket); bail0: return FcFalse; }
int PsychRebuildFont(fontCacheItem* fi) { int faceIndex = 0; char fontFileName[FILENAME_MAX] = { 0 }; // Destroy old font object, if any: if (fi->faceT || fi->faceM) { // Delete OGLFT face object: if (fi->faceT) delete(fi->faceT); fi->faceT = NULL; if (fi->faceM) delete(fi->faceM); fi->faceM = NULL; if (_verbosity > 12) fprintf(stdout, "libptbdrawtext_ftgl: Destroying old font face...\n"); // Delete underlying FreeType representation: FT_Done_Face(fi->ft_face); fi->ft_face = NULL; } if (_useOwnFontmapper) { FcResult result = FcResultMatch; // Must init this due to weirdness in libfontconfig... 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); } // Set default settings for missing pattern properties: FcDefaultSubstitute(target); if (!FcConfigSubstitute(NULL, target, FcMatchPattern)) { // Failed! if (_verbosity > 1) fprintf(stdout, "libptbdrawtext_ftgl: FontConfig failed to substitute default properties for family %s, size %f pts and style flags %i.\n", _fontName, (float) _fontSize, _fontStyle); FcPatternDestroy(target); return(1); } // Have a matching pattern: if (_verbosity > 5) { fprintf(stdout, "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(NULL, target, &result); if ((matched == NULL) || (result == FcResultNoMatch)) { // Failed! if (_verbosity > 1) fprintf(stdout, "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 > 5) { fprintf(stdout, "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(stdout, "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(stdout, "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); } // Retrieve font family name for matched font: if (FcPatternGetString(matched, FC_FAMILY, 0, (FcChar8**) &localfontFileName) != FcResultMatch) { // Failed! if (_verbosity > 1) fprintf(stdout, "libptbdrawtext_ftgl: FontConfig did not return actual font family name for font with requested family %s, size %f pts and style flags %i.\n", _fontName, (float) _fontSize, _fontStyle); FcPatternDestroy(target); FcPatternDestroy(matched); return(1); } // Store it as actual name in fi: strcpy(fi->fontRealName, (char*) localfontFileName); // Release target pattern and matched pattern objects: FcPatternDestroy(target); FcPatternDestroy(matched); } else { // Use "raw" values as passed by calling client code: strcpy(fontFileName, _fontName); strcpy(fi->fontRealName, fontFileName); 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, &fi->ft_face ); if (error) { if (_verbosity > 1) fprintf(stdout, "libptbdrawtext_ftgl: Freetype did not load face with index %i from font file %s.\n", faceIndex, fontFileName); return(1); } else { if (_verbosity > 5) fprintf(stdout, "libptbdrawtext_ftgl: Freetype loaded face %p with index %i from font file %s.\n", fi->ft_face, faceIndex, fontFileName); } // Create FTGL face from Freetype face with given size and a 72 DPI resolution, aka _fontSize == pixelsize: if (_antiAliasing != 0) { fi->faceT = new OGLFT::TranslucentTexture(fi->ft_face, _fontSize, 72); // Test the created face to make sure it will work correctly: if (!fi->faceT->isValid()) { if (_verbosity > 1) fprintf(stdout, "libptbdrawtext_ftgl: Freetype did not recognize %s as a font file.\n", _fontName); delete(fi->faceT); fi->faceT = NULL; return(1); } } else { fi->faceM = new OGLFT::MonochromeTexture(fi->ft_face, _fontSize, 72); // Test the created face to make sure it will work correctly: if (!fi->faceM->isValid()) { if (_verbosity > 1) fprintf(stdout, "libptbdrawtext_ftgl: Freetype did not recognize %s as a font file.\n", _fontName); delete(fi->faceM); fi->faceM = NULL; return(1); } } // Ready! return(0); }
void QFontconfigDatabase::populateFontDatabase() { FcInitReinitialize(); FcFontSet *fonts; { FcObjectSet *os = FcObjectSetCreate(); FcPattern *pattern = FcPatternCreate(); const char *properties [] = { FC_FAMILY, FC_STYLE, FC_WEIGHT, FC_SLANT, FC_SPACING, FC_FILE, FC_INDEX, FC_LANG, FC_CHARSET, FC_FOUNDRY, FC_SCALABLE, FC_PIXEL_SIZE, FC_WIDTH, #if FC_VERSION >= 20297 FC_CAPABILITY, #endif (const char *)0 }; const char **p = properties; while (*p) { FcObjectSetAdd(os, *p); ++p; } fonts = FcFontList(0, pattern, os); FcObjectSetDestroy(os); FcPatternDestroy(pattern); } for (int i = 0; i < fonts->nfont; i++) populateFromPattern(fonts->fonts[i]); FcFontSetDestroy (fonts); struct FcDefaultFont { const char *qtname; const char *rawname; bool fixed; }; const FcDefaultFont defaults[] = { { "Serif", "serif", false }, { "Sans Serif", "sans-serif", false }, { "Monospace", "monospace", true }, { 0, 0, false } }; const FcDefaultFont *f = defaults; // aliases only make sense for 'common', not for any of the specials QSupportedWritingSystems ws; ws.setSupported(QFontDatabase::Latin); while (f->qtname) { QString familyQtName = QString::fromLatin1(f->qtname); registerFont(familyQtName,QString(),QString(),QFont::Normal,QFont::StyleNormal,QFont::Unstretched,true,true,0,f->fixed,ws,0); registerFont(familyQtName,QString(),QString(),QFont::Normal,QFont::StyleItalic,QFont::Unstretched,true,true,0,f->fixed,ws,0); registerFont(familyQtName,QString(),QString(),QFont::Normal,QFont::StyleOblique,QFont::Unstretched,true,true,0,f->fixed,ws,0); ++f; } //Lighthouse has very lazy population of the font db. We want it to be initialized when //QApplication is constructed, so that the population procedure can do something like this to //set the default font // const FcDefaultFont *s = defaults; // QFont font("Sans Serif"); // font.setPointSize(9); // QApplication::setFont(font); }
void fcpattern_finalize(value v) { FcPatternDestroy(FcPattern_val(v)); }
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; }
Q_FOREACH (FcPattern *pattern, cachedMatchPatterns) { if (pattern) FcPatternDestroy(pattern); }
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; }