FcFontSet *fcinfo_fontformat_family_index(const FcChar8 *format, const FcPattern *filter) { FcFontSet *fontset, *result; FcPattern *pattern; FcPattern *font; FcResult r; int f; pattern = FcPatternDuplicate(filter); FcPatternAddString(pattern, FC_FONTFORMAT, format); fontset = fcinfo(NULL, pattern, FcTrue, 1, FC_FAMILY); result = FcFontSetCreate(); for (f = 0; f < fontset->nfont; f++) { font = FcFontMatch(NULL, fontset->fonts[f], &r); assert(r == FcResultMatch); /* don't add ethio16f-uni.pcf, johabg16.pcf and similar with reported empty charset */ /* could be done with fcinfo_match(), but that is superfluous there like for fcinfo_language_font_index() - it will be needed when we will need to display some kind of specimen in fontformat index */ if (!empty_charset(font)) FcFontSetAdd(result, FcPatternDuplicate(fontset->fonts[f])); FcPatternDestroy(font); } FcPatternDestroy(pattern); FcFontSetDestroy(fontset); return result; }
static AliasStrength strengthOfFirstAlias(const FcPattern& original) { // Ideally there would exist a call like // FcResult FcPatternIsWeak(pattern, object, id, FcBool* isWeak); // // However, there is no such call and as of Fc 2.11.0 even FcPatternEquals ignores the weak bit. // Currently, the only reliable way of finding the weak bit is by its effect on matching. // The weak bit only affects the matching of FC_FAMILY and FC_POSTSCRIPT_NAME object values. // A element with the weak bit is scored after FC_LANG, without the weak bit is scored before. // Note that the weak bit is stored on the element, not on the value it holds. FcValue value; FcResult result = FcPatternGet(&original, FC_FAMILY, 0, &value); if (result != FcResultMatch) return AliasStrength::Done; RefPtr<FcPattern> pattern = adoptRef(FcPatternDuplicate(&original)); FcBool hasMultipleFamilies = true; while (hasMultipleFamilies) hasMultipleFamilies = FcPatternRemove(pattern.get(), FC_FAMILY, 1); // Create a font set with two patterns. // 1. the same FC_FAMILY as pattern and a lang object with only 'nomatchlang'. // 2. a different FC_FAMILY from pattern and a lang object with only 'matchlang'. FcUniquePtr<FcFontSet> fontSet(FcFontSetCreate()); FcUniquePtr<FcLangSet> strongLangSet(FcLangSetCreate()); FcLangSetAdd(strongLangSet.get(), reinterpret_cast<const FcChar8*>("nomatchlang")); // Ownership of this FcPattern will be transferred with FcFontSetAdd. FcPattern* strong = FcPatternDuplicate(pattern.get()); FcPatternAddLangSet(strong, FC_LANG, strongLangSet.get()); FcUniquePtr<FcLangSet> weakLangSet(FcLangSetCreate()); FcLangSetAdd(weakLangSet.get(), reinterpret_cast<const FcChar8*>("matchlang")); // Ownership of this FcPattern will be transferred via FcFontSetAdd. FcPattern* weak = FcPatternCreate(); FcPatternAddString(weak, FC_FAMILY, reinterpret_cast<const FcChar8*>("nomatchstring")); FcPatternAddLangSet(weak, FC_LANG, weakLangSet.get()); FcFontSetAdd(fontSet.get(), strong); FcFontSetAdd(fontSet.get(), weak); // Add 'matchlang' to the copy of the pattern. FcPatternAddLangSet(pattern.get(), FC_LANG, weakLangSet.get()); // Run a match against the copy of the pattern. // If the first element was weak, then we should match the pattern with 'matchlang'. // If the first element was strong, then we should match the pattern with 'nomatchlang'. // Note that this config is only used for FcFontRenderPrepare, which we don't even want. // However, there appears to be no way to match/sort without it. RefPtr<FcConfig> config = adoptRef(FcConfigCreate()); FcFontSet* fontSets[1] = { fontSet.get() }; RefPtr<FcPattern> match = adoptRef(FcFontSetMatch(config.get(), fontSets, 1, pattern.get(), &result)); FcLangSet* matchLangSet; FcPatternGetLangSet(match.get(), FC_LANG, 0, &matchLangSet); return FcLangEqual == FcLangSetHasLang(matchLangSet, reinterpret_cast<const FcChar8*>("matchlang")) ? AliasStrength::Weak : AliasStrength::Strong; }
FcFontSet *fcinfo_language_font_index(const FcChar8 *lang, const FcPattern *filter) { FcFontSet *fontset; FcPattern *pattern; FcLangSet *langset; FcInit(); pattern = FcPatternDuplicate(filter); langset = FcLangSetCreate(); FcLangSetAdd(langset, lang); FcPatternAddLangSet(pattern, FC_LANG, langset); fontset = fcinfo(NULL, pattern, FcFalse, 2, FC_FAMILY, FC_STYLE); /*result = fcinfo_match(fontset, filter, FcFalse); this is redundant right now */ /* but language index could want to display spcimen or so in the future be sure to include also size, charset and file FcObjects when turning this on: see above call of fcinfo() */ /* we don't need to remove ethio16f-uni.pcf, johabg16.pcf and similar as they have reported empty charset, so they do not cover any language */ FcPatternDestroy(pattern); FcLangSetDestroy(langset); return fontset; }
FcFontSet *fcinfo_styles_index(const FcChar8 *family, const FcPattern *filter, family_info_t *fi) { FcFontSet *fontset, *result; FcPattern *pattern; pattern = FcPatternDuplicate(filter); FcPatternDel(pattern, FC_FAMILY); /* perhaps shouldn't be needed */ FcPatternAddString(pattern, FC_FAMILY, family); fontset = fcinfo(NULL, pattern, 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 */ FcPatternDestroy(pattern); if (fontset->nfont == 0) return fontset; result = fcinfo_match(fontset, filter); /* assuming family_info entries all same for each style of family; might not be true always */ if (fi) family_info(result->fonts[0], fi); FcFontSetDestroy(fontset); return result; }
static PyObject* Py_Config_add_pattern(Py_Config *self, PyObject *args, PyObject *kwds) { PyObject *py_pattern; FcPattern *pattern; FcFontSet *font_set; static char *kwlist[] = {"pattern", NULL}; if (!PyArg_ParseTupleAndKeywords( args, kwds, "O:add_pattern", kwlist, &py_pattern)) { return NULL; } if (Py_TYPE(py_pattern) != &Py_Pattern_Type) { PyErr_SetString(PyExc_TypeError, "pattern must be Pattern object"); return NULL; } pattern = FcPatternDuplicate(((Py_Pattern *)py_pattern)->x); font_set = FcConfigGetFonts(self->x, FcSetApplication); if (font_set == NULL) { PyErr_SetString(PyExc_RuntimeError, "couldn't get application FontSet"); return NULL; } if (!FcFontSetAdd(font_set, pattern)) { PyErr_SetString(PyExc_MemoryError, "allocation error"); return NULL; } Py_RETURN_NONE; }
GpStatus GdipCloneFontFamily (GpFontFamily *fontFamily, GpFontFamily **clonedFontFamily) { GpFontFamily *result; if (!fontFamily || !clonedFontFamily) return InvalidParameter; gdip_createFontFamily (&result); if (!result) return OutOfMemory; result->height = fontFamily->height; result->linespacing = fontFamily->linespacing; result->celldescent = fontFamily->celldescent; result->cellascent = fontFamily->cellascent; if (fontFamily->pattern) { result->pattern = FcPatternDuplicate (fontFamily->pattern); result->allocated = TRUE; } *clonedFontFamily = result; return Ok; }
FcPattern* BC_Resources::find_similar_font(FT_ULong char_code, FcPattern *oldfont) { FcPattern *pat, *font; FcFontSet *fs; FcObjectSet *os; FcCharSet *fcs; FcChar8 *file; double dval; int ival; // Do not search control codes if(char_code < ' ') return 0; fontconfig_lock.lock("BC_Resources::find_similar_font"); pat = FcPatternCreate(); os = FcObjectSetBuild(FC_FILE, FC_CHARSET, FC_SCALABLE, FC_FAMILY, FC_SLANT, FC_WEIGHT, FC_WIDTH, (char *)0); FcPatternAddBool(pat, FC_SCALABLE, true); fcs = FcCharSetCreate(); if(FcCharSetAddChar(fcs, char_code)) FcPatternAddCharSet(pat, FC_CHARSET, fcs); FcCharSetDestroy(fcs); for(int i = 0; i < LEN_FCPROP; i++) { if(FcPatternGetInteger(oldfont, fc_properties[i], 0, &ival) == FcResultMatch) FcPatternAddInteger(pat, fc_properties[i], ival); } fs = FcFontList(0, pat, os); for(int i = LEN_FCPROP - 1; i >= 0 && fs->nfont == 0; i--) { FcFontSetDestroy(fs); FcPatternDel(pat, fc_properties[i]); fs = FcFontList(0, pat, os); } FcPatternDestroy(pat); FcObjectSetDestroy(os); pat = 0; for (int i = 0; i < fs->nfont; i++) { font = fs->fonts[i]; if(FcPatternGetCharSet(font, FC_CHARSET, 0, &fcs) == FcResultMatch) { if(FcCharSetHasChar(fcs, char_code)) { pat = FcPatternDuplicate(font); break; } } } FcFontSetDestroy(fs); fontconfig_lock.unlock(); return pat; }
FcFontSet * fcinfo(const FcConfig *config, const FcPattern *pattern, FcBool remove_duplicities, int argnum, ...) { va_list va; const char *elements[argnum + 1]; int a; FcFontSet *fontset; FcObjectSet *objectset; FcInit(); objectset = FcObjectSetCreate(); va_start(va, argnum); for (a = 0; a < argnum; a++) { elements[a] = va_arg(va, const char *); FcObjectSetAdd(objectset, elements[a]); } va_end(va); fontset = FcFontList((FcConfig *)config, (FcPattern *)pattern, objectset); elements[argnum] = NULL; font_set_sort(fontset, elements); FcObjectSetDestroy(objectset); if (remove_duplicities) { FcFontSet *result = FcFontSetCreate(); int f; FcPattern *added = NULL; /* fontlist is linearly ordered */ f = 0; while (f < fontset->nfont) { FcFontSetAdd(result, FcPatternDuplicate(fontset->fonts[f])); added = fontset->fonts[f++]; while (f < fontset->nfont && !pattern_compare(&fontset->fonts[f], &added, elements)) f++; } FcFontSetDestroy(fontset); return result; } return fontset; }
/** * \brief Case-insensitive match ASS/SSA font family against full name. (also * known as "name for humans") * * \param lib library instance * \param priv fontconfig instance * \param family font fullname * \param bold weight attribute * \param italic italic attribute * \return font set */ static FcFontSet * match_fullname(ASS_Library *lib, FCInstance *priv, const char *family, unsigned bold, unsigned italic) { FcFontSet *sets[2]; FcFontSet *result = FcFontSetCreate(); int nsets = 0; int i, fi; if (!result) return NULL; if ((sets[nsets] = FcConfigGetFonts(priv->config, FcSetSystem))) nsets++; if ((sets[nsets] = FcConfigGetFonts(priv->config, FcSetApplication))) nsets++; // Run over font sets and patterns and try to match against full name for (i = 0; i < nsets; i++) { FcFontSet *set = sets[i]; for (fi = 0; fi < set->nfont; fi++) { FcPattern *pat = set->fonts[fi]; char *fullname; int pi = 0, at; FcBool ol; while (FcPatternGetString(pat, FC_FULLNAME, pi++, (FcChar8 **) &fullname) == FcResultMatch) { if (FcPatternGetBool(pat, FC_OUTLINE, 0, &ol) != FcResultMatch || ol != FcTrue) continue; if (FcPatternGetInteger(pat, FC_SLANT, 0, &at) != FcResultMatch || at < italic) continue; if (FcPatternGetInteger(pat, FC_WEIGHT, 0, &at) != FcResultMatch || at < bold) continue; if (strcasecmp(fullname, family) == 0) { FcFontSetAdd(result, FcPatternDuplicate(pat)); break; } } } } return result; }
void SkScalerContext_CairoFT::resolvePattern(FcPattern* pattern) { if (!pattern) { return; } FcValue value; if (FcPatternGet(pattern, FC_PIXEL_SIZE, 0, &value) == FcResultNoMatch) { SkAutoTUnref<FcPattern> scalePattern(FcPatternDuplicate(pattern)); if (scalePattern && FcPatternAddDouble(scalePattern, FC_PIXEL_SIZE, fScaleY) && FcConfigSubstitute(nullptr, scalePattern, FcMatchPattern)) { FcDefaultSubstitute(scalePattern); FcResult result; SkAutoTUnref<FcPattern> resolved(FcFontMatch(nullptr, scalePattern, &result)); if (resolved) { parsePattern(resolved); return; } } } parsePattern(pattern); }
value fcFindFont( value _familyName, value _weight, value _slant, value _size ) { val_check(_familyName,string); val_check(_weight,number); val_check(_slant,number); val_check(_size,number); const char *familyName = val_string(_familyName); int weight = val_number(_weight); int slant = val_number(_slant); float size = val_number(_size); FcPattern *pattern; pattern = FcNameParse( (FcChar8*)familyName ); FcDefaultSubstitute( pattern ); FcConfigSubstitute( FcConfigGetCurrent(), pattern, FcMatchPattern ); FcResult result; FcPattern *match = FcFontMatch( 0, pattern, &result ); FcPatternDestroy( pattern ); if( !match ) val_throw(alloc_string("Could not find font")); FcChar8 *temp; int id; pattern = FcPatternDuplicate(match); if( FcPatternGetString( pattern, FC_FILE, 0, &temp ) != FcResultMatch || FcPatternGetInteger( pattern, FC_INDEX, 0, &id ) != FcResultMatch ) { val_throw(alloc_string("Could not load font")); } value ret = alloc_string((const char *)temp); FcPatternDestroy( pattern ); FcPatternDestroy( match ); return ret; }
static XftFont* getfont(XftFont **font, uint32_t ch) { XftFont *first = font[0]; if(!FcCharSetHasChar(charset, ch)) { return first; } while(*font) { if(XftGlyphExists(display, *font, ch)) { return *font; } font++; } FcResult result; int i; for(i = 0; i != fs->nfont; i++) { FcCharSet *cs; result = FcPatternGetCharSet(fs->fonts[i], FC_CHARSET, 0, &cs); if(FcCharSetHasChar(cs, ch)) { FcPattern *p = FcPatternDuplicate(fs->fonts[i]), *pp; double size; if(!FcPatternGetDouble(first->pattern, FC_PIXEL_SIZE, 0, &size)) { FcPatternAddDouble(p, FC_PIXEL_SIZE, size); } pp = XftFontMatch(display, screen, p, &result); *font = XftFontOpenPattern(display, pp); FcPatternDestroy(p); return *font; } } //should never happen return first; }
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; }
XftPattern * XftPatternDuplicate (XftPattern *orig) { return FcPatternDuplicate (orig); }
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; }
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; }
TGlyphInfo *glyph_cache_get_info(TGlyphCache *cache, gunichar glyph) { TGlyphInfo *gfi; XftFont *xftfont; PangoFont *font; PangoGlyph pglyph; PangoRectangle ink, logical; gint ascent, descent; gint x_offset; gint nominal_width; double scale_y, scale_x; if (!cache->hash) return NULL; gfi = g_hash_table_lookup(cache->hash, GINT_TO_POINTER(glyph)); if (gfi) return gfi; font = pango_fontset_get_font(cache->font_set, glyph); pglyph = pango_fc_font_get_glyph(PANGO_FC_FONT(font), glyph); if (!pglyph) { fprintf (stderr, "Error: Unable to find glyph %d.\n", glyph); if (!pglyph) pglyph = pango_fc_font_get_glyph(PANGO_FC_FONT(font), glyph); if (!pglyph) pglyph = PANGO_GET_UNKNOWN_GLYPH (glyph); if (!pglyph) return NULL; } pango_font_get_glyph_extents(font, pglyph, &ink, &logical); ascent = PANGO_ASCENT(logical); descent = PANGO_DESCENT(logical); xftfont = pango_xft_font_get_font(font); x_offset = 0; nominal_width = cache->width; if (g_unichar_iswide(glyph)) nominal_width *= 2; scale_x = scale_y = 1.0; if (logical.width > nominal_width) { if (logical.width) scale_x = (double)nominal_width / (double)logical.width; else scale_x = 1.0; } if (logical.height != cache->height) { double scale; if (ascent) { scale_y = (double)cache->ascent / (double)ascent; } else { scale_y = 1.0; } if (descent) { scale = (double)cache->descent / (double)descent; if (scale < scale_y) scale_y = scale; } } if (scale_x >= 1.0) { scale_x = 1.0; x_offset += (nominal_width - logical.width) / 2; } if (scale_x < 1.0 || scale_y != 1.0) { FcBool scalable; FcPatternGetBool(xftfont->pattern, FC_SCALABLE, 0, &scalable); if (!scalable) { /* Bah. Need better handling of non-scalable fonts */ if (scale_x < 1.0) scale_x = 1.0; scale_y = 1.0; } else if (scale_x < 1.0 || scale_y != 1.0) { FcPattern *pattern; FcMatrix mat; pattern = FcPatternDuplicate(xftfont->pattern); FcMatrixInit (&mat); FcMatrixScale(&mat, scale_x, scale_y); FcPatternDel (pattern, FC_MATRIX); FcPatternAddMatrix(pattern, FC_MATRIX, &mat); xftfont = XftFontOpenPattern( GDK_DISPLAY_XDISPLAY(cache->display), pattern ); } ascent = ascent * scale_y; } g_object_unref(font); // gfi = calloc(sizeof(TGlyphInfo), 1); gfi = g_slice_new(TGlyphInfo); gfi->font = xftfont; gfi->x_offset = PANGO_PIXELS(x_offset); gfi->y_offset = cache->ascent + (cache->ascent - ascent); gfi->y_offset = PANGO_PIXELS(gfi->y_offset); g_hash_table_insert(cache->hash, GINT_TO_POINTER(glyph), gfi); return gfi; }
value caml_copy_pattern(FcPattern *pat) { CAMLparam0(); CAMLlocal1(res); CAMLreturn(caml_box_fcpattern(FcPatternDuplicate(pat))); }