gchar* find_font_with_property (FcConfig* fontconfig, const gchar* characters, const gchar* property) { FcPattern* pattern; FcCharSet* character_set; FcObjectSet* font_properties; FcFontSet* fonts; FcPattern* font; FcChar8* path; gchar* result; gchar* remaining_characters; gunichar character; if (fontconfig == NULL) { g_warning("Font config not loaded."); return NULL; } result = NULL; pattern = FcPatternCreate (); character_set = FcCharSetCreate (); remaining_characters = (gchar*) characters; while (TRUE) { character = g_utf8_get_char (remaining_characters); if (character == '\0') { break; } FcCharSetAddChar(character_set, character); remaining_characters = g_utf8_next_char (remaining_characters); } FcPatternAddCharSet (pattern, FC_CHARSET, character_set); FcCharSetDestroy (character_set); FcPatternAddInteger (pattern, FC_SLANT, FC_SLANT_ROMAN); FcPatternAddBool(pattern, FC_SCALABLE, FcTrue); font_properties = FcObjectSetBuild (property, NULL); fonts = FcFontList (fontconfig, pattern, font_properties); if (fonts && fonts->nfont > 0) { font = fonts->fonts[0]; if (FcPatternGetString(font, property, 0, &path) == FcResultMatch) { result = g_strdup ((gchar*) path); } } if (fonts) { FcFontSetDestroy(fonts); } if (pattern) { FcPatternDestroy(pattern); } return result; }
FcPattern* BC_Resources::find_similar_font(FT_ULong char_code, FcPattern *oldfont) { FcPattern *pat, *font; FcFontSet *fs; FcObjectSet *os; FcCharSet *fcs; FcChar8 *file; double dval; int ival; // Do not search control codes if(char_code < ' ') return 0; fontconfig_lock.lock("BC_Resources::find_similar_font"); pat = FcPatternCreate(); os = FcObjectSetBuild(FC_FILE, FC_CHARSET, FC_SCALABLE, FC_FAMILY, FC_SLANT, FC_WEIGHT, FC_WIDTH, (char *)0); FcPatternAddBool(pat, FC_SCALABLE, true); fcs = FcCharSetCreate(); if(FcCharSetAddChar(fcs, char_code)) FcPatternAddCharSet(pat, FC_CHARSET, fcs); FcCharSetDestroy(fcs); for(int i = 0; i < LEN_FCPROP; i++) { if(FcPatternGetInteger(oldfont, fc_properties[i], 0, &ival) == FcResultMatch) FcPatternAddInteger(pat, fc_properties[i], ival); } fs = FcFontList(0, pat, os); for(int i = LEN_FCPROP - 1; i >= 0 && fs->nfont == 0; i--) { FcFontSetDestroy(fs); FcPatternDel(pat, fc_properties[i]); fs = FcFontList(0, pat, os); } FcPatternDestroy(pat); FcObjectSetDestroy(os); pat = 0; for (int i = 0; i < fs->nfont; i++) { font = fs->fonts[i]; if(FcPatternGetCharSet(font, FC_CHARSET, 0, &fcs) == FcResultMatch) { if(FcCharSetHasChar(fcs, char_code)) { pat = FcPatternDuplicate(font); break; } } } FcFontSetDestroy(fs); fontconfig_lock.unlock(); return pat; }
static String getFontFamilyForCharacters(const UChar* characters, size_t numCharacters) { FcCharSet* cset = FcCharSetCreate(); for (size_t i = 0; i < numCharacters; ++i) { if (U16_IS_SURROGATE(characters[i]) && U16_IS_SURROGATE_LEAD(characters[i]) && i != numCharacters - 1 && U16_IS_TRAIL(characters[i + 1])) { if (FcCharSetAddChar(cset, U16_GET_SUPPLEMENTARY(characters[i], characters[i+1])) == FcFalse) return String(); i++; } else if (FcCharSetAddChar(cset, characters[i]) == FcFalse) return String(); } FcPattern *pattern = FcPatternCreate(); FcPatternAddCharSet(pattern, FC_CHARSET, cset); FcConfigSubstitute(0, pattern, FcMatchPattern); FcDefaultSubstitute(pattern); FcResult result; FcPattern *match = FcFontMatch(0, pattern, &result); FcChar8 *filename; if (FcPatternGetString(match, FC_FILE, 0, &filename) != FcResultMatch) { FcCharSetDestroy(cset); FcPatternDestroy(match); FcPatternDestroy(pattern); return String(); } FcChar8* family; if (FcPatternGetString(match, FC_FAMILY, 0, &family) == FcResultMatch) { FcCharSetDestroy(cset); FcPatternDestroy(match); FcPatternDestroy(pattern); const char* charFamily = reinterpret_cast<char*>(family); return String(charFamily); } FcPatternDestroy(match); FcCharSetDestroy(cset); FcPatternDestroy(pattern); return String(); }
static RefPtr<FcPattern> createFontConfigPatternForCharacters(const UChar* characters, int bufferLength) { RefPtr<FcPattern> pattern = adoptRef(FcPatternCreate()); FcUniquePtr<FcCharSet> fontConfigCharSet(FcCharSetCreate()); UTF16UChar32Iterator iterator(characters, bufferLength); UChar32 character = iterator.next(); while (character != iterator.end()) { FcCharSetAddChar(fontConfigCharSet.get(), character); character = iterator.next(); } FcPatternAddCharSet(pattern.get(), FC_CHARSET, fontConfigCharSet.get()); FcPatternAddBool(pattern.get(), FC_SCALABLE, FcTrue); FcConfigSubstitute(nullptr, pattern.get(), FcMatchPattern); FcDefaultSubstitute(pattern.get()); return pattern; }
FcPattern* createFontConfigPatternForCharacters(const UChar* characters, int bufferLength) { FcPattern* pattern = FcPatternCreate(); FcCharSet* fontConfigCharSet = FcCharSetCreate(); UTF16UChar32Iterator iterator(characters, bufferLength); UChar32 character = iterator.next(); while (character != iterator.end()) { FcCharSetAddChar(fontConfigCharSet, character); character = iterator.next(); } FcPatternAddCharSet(pattern, FC_CHARSET, fontConfigCharSet); FcCharSetDestroy(fontConfigCharSet); FcPatternAddBool(pattern, FC_SCALABLE, FcTrue); FcConfigSubstitute(0, pattern, FcMatchPattern); FcDefaultSubstitute(pattern); return pattern; }
FcPattern* createFontConfigPatternForCharacters(const UChar* characters, int length) { FcPattern* pattern = FcPatternCreate(); FcCharSet* fontConfigCharSet = FcCharSetCreate(); for (int i = 0; i < length; ++i) { if (U16_IS_SURROGATE(characters[i]) && U16_IS_SURROGATE_LEAD(characters[i]) && i != length - 1 && U16_IS_TRAIL(characters[i + 1])) { FcCharSetAddChar(fontConfigCharSet, U16_GET_SUPPLEMENTARY(characters[i], characters[i+1])); i++; } else FcCharSetAddChar(fontConfigCharSet, characters[i]); } FcPatternAddCharSet(pattern, FC_CHARSET, fontConfigCharSet); FcCharSetDestroy(fontConfigCharSet); FcPatternAddBool(pattern, FC_SCALABLE, FcTrue); FcConfigSubstitute(0, pattern, FcMatchPattern); FcDefaultSubstitute(pattern); return pattern; }
static inline XftFont * get_font(Display *xdisplay, FT_Face face, gint size, FcCharSet *charset) { FcPattern *pattern; XftFont *font; int screen = DefaultScreen (xdisplay); pattern = FcPatternBuild(NULL, FC_FT_FACE, FcTypeFTFace, face, FC_PIXEL_SIZE, FcTypeDouble, (double)size, NULL); if (charset) FcPatternAddCharSet (pattern, "charset", charset); FcConfigSubstitute (NULL, pattern, FcMatchPattern); XftDefaultSubstitute (xdisplay, screen, pattern); font = XftFontOpenPattern(xdisplay, pattern); return font; }
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; }
/** * grx_font_load_full: * @family: (nullable): the font family name or %NULL * @size: the preferred size in points or -1 for any size * @dpi: the screen resolution or -1 to ignore dpi * @weight: the font weight (e.g. bold) or -1 for any weight * @slant: the font slant (e.g. italic) or -1 for any slant * @width: the font width (e.g. narrow) or -1 for any width * @monospace: set to %TRUE to prefer a monospace font * @lang: (nullable): a RFC-3066-style language code or %NULL * @script: (nullable): an ISO 15924 script code or %NULL * @err: pointer to hold an error * * Loads the font that best matches the parameters. * * Uses fontconfig for font matching. * * Returns: (transfer full) (nullable): the font or %NULL if there was an error */ GrxFont *grx_font_load_full(const gchar *family, gint size, gint dpi, GrxFontWeight weight, GrxFontSlant slant, GrxFontWidth width, gboolean monospace, const gchar *lang, const gchar *script, GError **err) { FcPattern *pattern, *match; FcResult result; GrxFont *font; FcChar8 *file; if (!FcInit()) { g_set_error_literal(err, GRX_ERROR, GRX_ERROR_FONT_ERROR, "Failed to init fontconfig"); return NULL; } pattern = FcPatternCreate(); FcPatternAddBool(pattern, FC_SCALABLE, FcFalse); FcPatternAddBool(pattern, FC_OUTLINE, FcFalse); FcPatternAddString(pattern, FC_FONTFORMAT, (FcChar8 *)"PCF"); if (family) { FcPatternAddString(pattern, FC_FAMILY, (FcChar8 *)family); } if (size >= 0) { FcPatternAddDouble(pattern, FC_SIZE, size); } if (dpi >= 0) { FcPatternAddDouble(pattern, FC_DPI, dpi); } switch (weight) { case GRX_FONT_WEIGHT_REGULAR: FcPatternAddInteger(pattern, FC_WEIGHT, 80); break; case GRX_FONT_WEIGHT_BOLD: FcPatternAddInteger(pattern, FC_WEIGHT, 200); break; } switch (slant) { case GRX_FONT_SLANT_REGULAR: FcPatternAddInteger(pattern, FC_SLANT, 0); break; case GRX_FONT_SLANT_ITALIC: FcPatternAddInteger(pattern, FC_SLANT, 100); break; } switch (width) { case GRX_FONT_WIDTH_NARROW: FcPatternAddInteger(pattern, FC_WIDTH, 75); break; case GRX_FONT_WIDTH_REGULAR: FcPatternAddInteger(pattern, FC_WIDTH, 100); break; case GRX_FONT_WIDTH_WIDE: FcPatternAddInteger(pattern, FC_WIDTH, 125); break; } if (monospace) { FcPatternAddInteger(pattern, FC_SPACING, 100); } if (lang) { FcPatternAddString(pattern, FC_LANG, (FcChar8 *)lang); } if (script) { FcPatternAddCharSet(pattern, FC_CHARSET, script_to_charset(script)); } { FcChar8 *pattern_str; pattern_str = FcNameUnparse(pattern); g_debug("searching for pattern: %s", pattern_str); free(pattern_str); } FcConfigSubstitute(NULL, pattern, FcMatchPattern); FcDefaultSubstitute(pattern); match = FcFontMatch(NULL, pattern, &result); if (!match) { // TODO: use result for better error g_set_error_literal(err, GRX_ERROR, GRX_ERROR_FONT_ERROR, "Failed to find match"); FcPatternDestroy(pattern); return NULL; } if (FcPatternGetString(match, FC_FILE, 0, &file) != FcResultMatch) { g_set_error_literal(err, GRX_ERROR, GRX_ERROR_FONT_ERROR, "Failed to get file name"); FcPatternDestroy(match); FcPatternDestroy(pattern); return NULL; } font = grx_font_load_from_file((gchar *)file, err); FcPatternDestroy(match); FcPatternDestroy(pattern); return font; }
int drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, const char *text) { char buf[1024]; int tx, ty, th; Extnts tex; XftDraw *d = NULL; Fnt *curfont, *nextfont; size_t i, len; int utf8strlen, utf8charlen, render; long utf8codepoint = 0; const char *utf8str; FcCharSet *fccharset; FcPattern *fcpattern; FcPattern *match; XftResult result; int charexists = 0; if (!drw->scheme || !drw->fontcount) return 0; if (!(render = x || y || w || h)) { w = ~w; } else { XSetForeground(drw->dpy, drw->gc, drw->scheme->bg->pix); XFillRectangle(drw->dpy, drw->drawable, drw->gc, x, y, w, h); d = XftDrawCreate(drw->dpy, drw->drawable, DefaultVisual(drw->dpy, drw->screen), DefaultColormap(drw->dpy, drw->screen)); } curfont = drw->fonts[0]; while (1) { utf8strlen = 0; utf8str = text; nextfont = NULL; while (*text) { utf8charlen = utf8decode(text, &utf8codepoint, UTF_SIZ); for (i = 0; i < drw->fontcount; i++) { charexists = charexists || XftCharExists(drw->dpy, drw->fonts[i]->xfont, utf8codepoint); if (charexists) { if (drw->fonts[i] == curfont) { utf8strlen += utf8charlen; text += utf8charlen; } else { nextfont = drw->fonts[i]; } break; } } if (!charexists || (nextfont && nextfont != curfont)) break; else charexists = 0; } if (utf8strlen) { drw_font_getexts(curfont, utf8str, utf8strlen, &tex); /* shorten text if necessary */ for (len = MIN(utf8strlen, (sizeof buf) - 1); len && (tex.w > w - drw->fonts[0]->h || w < drw->fonts[0]->h); len--) drw_font_getexts(curfont, utf8str, len, &tex); if (len) { memcpy(buf, utf8str, len); buf[len] = '\0'; if (len < utf8strlen) for (i = len; i && i > len - 3; buf[--i] = '.'); if (render) { th = curfont->ascent + curfont->descent; ty = y + (h / 2) - (th / 2) + curfont->ascent; tx = x + (h / 2); XftDrawStringUtf8(d, &drw->scheme->fg->rgb, curfont->xfont, tx, ty, (XftChar8 *)buf, len); } x += tex.w; w -= tex.w; } } if (!*text) { break; } else if (nextfont) { charexists = 0; curfont = nextfont; } else { /* Regardless of whether or not a fallback font is found, the * character must be drawn. */ charexists = 1; if (drw->fontcount >= DRW_FONT_CACHE_SIZE) continue; fccharset = FcCharSetCreate(); FcCharSetAddChar(fccharset, utf8codepoint); if (!drw->fonts[0]->pattern) { /* Refer to the comment in drw_font_xcreate for more * information. */ die("the first font in the cache must be loaded from a font string.\n"); } fcpattern = FcPatternDuplicate(drw->fonts[0]->pattern); FcPatternAddCharSet(fcpattern, FC_CHARSET, fccharset); FcPatternAddBool(fcpattern, FC_SCALABLE, FcTrue); FcConfigSubstitute(NULL, fcpattern, FcMatchPattern); FcDefaultSubstitute(fcpattern); match = XftFontMatch(drw->dpy, drw->screen, fcpattern, &result); FcCharSetDestroy(fccharset); FcPatternDestroy(fcpattern); if (match) { curfont = drw_font_xcreate(drw, NULL, match); if (curfont && XftCharExists(drw->dpy, curfont->xfont, utf8codepoint)) { drw->fonts[drw->fontcount++] = curfont; } else { drw_font_free(curfont); curfont = drw->fonts[0]; } } } } if (d) XftDrawDestroy(d); return x; }
bool FontConfigDirect::Match(std::string* result_family, unsigned* result_filefaceid, bool filefaceid_valid, unsigned filefaceid, const std::string& family, const void* data, size_t characters_bytes, bool* is_bold, bool* is_italic) { if (family.length() > kMaxFontFamilyLength) return false; SkAutoMutexAcquire ac(mutex_); // Given |family|, |is_bold| and |is_italic| but not |data|, the result will // be a function of these three parameters, and thus eligible for caching. // This is the fast path for |SkTypeface::CreateFromName()|. bool eligible_for_cache = !family.empty() && is_bold && is_italic && !data; if (eligible_for_cache) { int style = (*is_bold ? SkTypeface::kBold : 0 ) | (*is_italic ? SkTypeface::kItalic : 0); FontMatchKey key = FontMatchKey(family, style); const std::map<FontMatchKey, FontMatch>::const_iterator i = font_match_cache_.find(key); if (i != font_match_cache_.end()) { *is_bold = i->second.is_bold; *is_italic = i->second.is_italic; if (result_family) *result_family = i->second.family; if (result_filefaceid) *result_filefaceid = i->second.filefaceid; return true; } } FcPattern* pattern = FcPatternCreate(); if (filefaceid_valid) { const std::map<unsigned, std::string>::const_iterator i = fileid_to_filename_.find(FileFaceIdToFileId(filefaceid)); if (i == fileid_to_filename_.end()) { FcPatternDestroy(pattern); return false; } int face_index = filefaceid & 0xfu; FcPatternAddString(pattern, FC_FILE, reinterpret_cast<const FcChar8*>(i->second.c_str())); // face_index is added only when family is empty because it is not // necessary to uniquiely identify a font if both file and // family are given. if (family.empty()) FcPatternAddInteger(pattern, FC_INDEX, face_index); } if (!family.empty()) { FcPatternAddString(pattern, FC_FAMILY, (FcChar8*) family.c_str()); } FcCharSet* charset = NULL; if (data) { charset = FcCharSetCreate(); const uint16_t* chars = (const uint16_t*) data; size_t num_chars = characters_bytes / 2; for (size_t i = 0; i < num_chars; ++i) { if (U16_IS_SURROGATE(chars[i]) && U16_IS_SURROGATE_LEAD(chars[i]) && i != num_chars - 1 && U16_IS_TRAIL(chars[i + 1])) { FcCharSetAddChar(charset, U16_GET_SUPPLEMENTARY(chars[i], chars[i+1])); i++; } else { FcCharSetAddChar(charset, chars[i]); } } FcPatternAddCharSet(pattern, FC_CHARSET, charset); FcCharSetDestroy(charset); // pattern now owns it. } FcPatternAddInteger(pattern, FC_WEIGHT, is_bold && *is_bold ? FC_WEIGHT_BOLD : FC_WEIGHT_NORMAL); FcPatternAddInteger(pattern, FC_SLANT, is_italic && *is_italic ? FC_SLANT_ITALIC : FC_SLANT_ROMAN); FcPatternAddBool(pattern, FC_SCALABLE, FcTrue); FcConfigSubstitute(NULL, pattern, FcMatchPattern); FcDefaultSubstitute(pattern); // Font matching: // CSS often specifies a fallback list of families: // font-family: a, b, c, serif; // However, fontconfig will always do its best to find *a* font when asked // for something so we need a way to tell if the match which it has found is // "good enough" for us. Otherwise, we can return NULL which gets piped up // and lets WebKit know to try the next CSS family name. However, fontconfig // configs allow substitutions (mapping "Arial -> Helvetica" etc) and we // wish to support that. // // Thus, if a specific family is requested we set @family_requested. Then we // record two strings: the family name after config processing and the // family name after resolving. If the two are equal, it's a good match. // // So consider the case where a user has mapped Arial to Helvetica in their // config. // requested family: "Arial" // post_config_family: "Helvetica" // post_match_family: "Helvetica" // -> good match // // and for a missing font: // requested family: "Monaco" // post_config_family: "Monaco" // post_match_family: "Times New Roman" // -> BAD match // // However, we special-case fallback fonts; see IsFallbackFontAllowed(). FcChar8* post_config_family; FcPatternGetString(pattern, FC_FAMILY, 0, &post_config_family); FcResult result; FcFontSet* font_set = FcFontSort(0, pattern, 0, 0, &result); if (!font_set) { FcPatternDestroy(pattern); return false; } FcPattern* match = MatchFont(font_set, post_config_family, family); if (!match) { FcPatternDestroy(pattern); FcFontSetDestroy(font_set); return false; } FcPatternDestroy(pattern); FcChar8* c_filename; if (FcPatternGetString(match, FC_FILE, 0, &c_filename) != FcResultMatch) { FcFontSetDestroy(font_set); return false; } int face_index; if (FcPatternGetInteger(match, FC_INDEX, 0, &face_index) != FcResultMatch) { FcFontSetDestroy(font_set); return false; } FontMatch font_match; if (filefaceid_valid) { font_match.filefaceid = filefaceid; } else { unsigned out_fileid; const std::string filename(reinterpret_cast<char*>(c_filename)); const std::map<std::string, unsigned>::const_iterator i = filename_to_fileid_.find(filename); if (i == filename_to_fileid_.end()) { out_fileid = next_file_id_++; filename_to_fileid_[filename] = out_fileid; fileid_to_filename_[out_fileid] = filename; } else { out_fileid = i->second; } // fileid stored in filename_to_fileid_ and fileid_to_filename_ is // unique only up to the font file. We have to encode face_index for // the out param. font_match.filefaceid = FileIdAndFaceIndexToFileFaceId(out_fileid, face_index); } bool success = GetFontProperties(match, &font_match.family, &font_match.is_bold, &font_match.is_italic); FcFontSetDestroy(font_set); if (success) { // If eligible, cache the result of the matching. if (eligible_for_cache) { int style = (*is_bold ? SkTypeface::kBold : 0 ) | (*is_italic ? SkTypeface::kItalic : 0); font_match_cache_[FontMatchKey(family, style)] = font_match; } if (result_family) *result_family = font_match.family; if (result_filefaceid) *result_filefaceid = font_match.filefaceid; if (is_bold) *is_bold = font_match.is_bold; if (is_italic) *is_italic = font_match.is_italic; } return success; }