/* Pango * pangofc-fontmap.cI: Common font handling between Xft and FT2 * * Copyright (C) 2000,2001,2002 Red Hat, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ /* * This file is included by both pangoxft-fontmap.c and pangoft2-fontmap.c * after making appropriate #defines for public symbols. */ /* Number of freed fonts to keep around */ #define MAX_FREED_FONTS 128 typedef struct _PangoFcCoverageKey PangoFcCoverageKey; typedef struct _PangoFcFace PangoFcFace; typedef struct _PangoFcPatternSet PangoFcPatternSet; #define PANGO_FC_TYPE_FAMILY (pango_fc_family_get_type ()) #define PANGO_FC_FAMILY(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), PANGO_FC_TYPE_FAMILY, PangoFcFamily)) #define PANGO_FC_IS_FAMILY(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), PANGO_FC_TYPE_FAMILY)) #define PANGO_FC_TYPE_FACE (pango_fc_face_get_type ()) #define PANGO_FC_FACE(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), PANGO_FC_TYPE_FACE, PangoFcFace)) #define PANGO_FC_IS_FACE(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), PANGO_FC_TYPE_FACE)) struct _PangoFcCoverageKey { char *filename; int id; /* needed to handle TTC files with multiple faces */ }; struct _PangoFcFace { PangoFontFace parent_instance; PangoFcFamily *family; char *style; }; struct _PangoFcFamily { PangoFontFamily parent_instance; PangoFcFontMap *fontmap; char *family_name; PangoFcFace **faces; int n_faces; /* -1 == uninitialized */ }; struct _PangoFcPatternSet { int n_patterns; FcPattern **patterns; }; GType pango_fc_font_map_get_type (void); static GType pango_fc_family_get_type (void); static GType pango_fc_face_get_type (void); static void pango_fc_font_map_init (PangoFcFontMap *fontmap); static void pango_fc_font_map_class_init (PangoFontMapClass *class); static void pango_fc_font_map_finalize (GObject *object); static PangoFont * pango_fc_font_map_load_font (PangoFontMap *fontmap, PangoContext *context, const PangoFontDescription *description); static PangoFontset *pango_fc_font_map_load_fontset (PangoFontMap *fontmap, PangoContext *context, const PangoFontDescription *desc, PangoLanguage *language); static void pango_fc_font_map_list_families (PangoFontMap *fontmap, PangoFontFamily ***families, int *n_families); static void pango_fc_font_set_free (PangoFcPatternSet *font_set); static void pango_fc_font_map_cache_clear (PangoFcFontMap *fcfontmap); static void pango_fc_font_map_cache_remove (PangoFontMap *fontmap, PangoFcFont *xfont); static void pango_fc_default_substitute (PangoFcFontMap *fontmap, FcPattern *pattern); static void pango_fc_do_finalize (PangoFcFontMap *fontmap); static guint pango_fc_pattern_hash (FcPattern *pattern); static gboolean pango_fc_pattern_equal (FcPattern *pattern1, FcPattern *pattern2); static guint pango_fc_coverage_key_hash (PangoFcCoverageKey *key); static gboolean pango_fc_coverage_key_equal (PangoFcCoverageKey *key1, PangoFcCoverageKey *key2); static PangoFontClass *parent_class; /* Parent class structure for PangoFcFontMap */ GType pango_fc_font_map_get_type (void) { static GType object_type = 0; if (!object_type) { static const GTypeInfo object_info = { sizeof (PangoFontMapClass), (GBaseInitFunc) NULL, (GBaseFinalizeFunc) NULL, (GClassInitFunc) pango_fc_font_map_class_init, NULL, /* class_finalize */ NULL, /* class_data */ sizeof (PangoFcFontMap), 0, /* n_preallocs */ (GInstanceInitFunc) pango_fc_font_map_init, }; object_type = g_type_register_static (PANGO_TYPE_FONT_MAP, PANGO_FC_NAME "FontMap", &object_info, 0); } return object_type; } static void pango_fc_font_map_init (PangoFcFontMap *fcfontmap) { fcfontmap->n_families = -1; fcfontmap->fonts = g_hash_table_new ((GHashFunc)pango_fc_pattern_hash, (GEqualFunc)pango_fc_pattern_equal); fcfontmap->coverage_hash = g_hash_table_new_full ((GHashFunc)pango_fc_coverage_key_hash, (GEqualFunc)pango_fc_coverage_key_equal, (GDestroyNotify)g_free, (GDestroyNotify)pango_coverage_unref); fcfontmap->freed_fonts = g_queue_new (); } static void pango_fc_font_map_class_init (PangoFontMapClass *class) { GObjectClass *object_class = G_OBJECT_CLASS (class); parent_class = g_type_class_peek_parent (class); object_class->finalize = pango_fc_font_map_finalize; class->load_font = pango_fc_font_map_load_font; class->load_fontset = pango_fc_font_map_load_fontset; class->list_families = pango_fc_font_map_list_families; } static GSList *fontmaps = NULL; static guint pango_fc_pattern_hash (FcPattern *pattern) { #if 1 return FcPatternHash (pattern); #else /* Hashing only part of the pattern can improve speed a bit. */ char *str; int i; double d; guint hash = 0; FcPatternGetString (pattern, FC_FILE, 0, (FcChar8 **) &str); if (str) hash = g_str_hash (str); if (FcPatternGetInteger (pattern, FC_INDEX, 0, &i) == FcResultMatch) hash ^= i; if (FcPatternGetDouble (pattern, FC_PIXEL_SIZE, 0, &d) == FcResultMatch) hash ^= (guint) (d*1000.0); return hash; #endif } static gboolean pango_fc_pattern_equal (FcPattern *pattern1, FcPattern *pattern2) { if (pattern1 == pattern2) return TRUE; else return FcPatternEqual (pattern1, pattern2); } static guint pango_fc_coverage_key_hash (PangoFcCoverageKey *key) { return g_str_hash (key->filename) ^ key->id; } static gboolean pango_fc_coverage_key_equal (PangoFcCoverageKey *key1, PangoFcCoverageKey *key2) { return key1->id == key2->id && strcmp (key1->filename, key2->filename) == 0; } typedef struct _FontsetHashListNode FontsetHashListNode; struct _FontsetHashListNode { GHashTable *fontset_hash; PangoLanguage *language; }; /* Get the description => fontset map for a particular * language tag. */ static GHashTable * pango_fc_get_fontset_hash (PangoFcFontMap *fcfontmap, PangoLanguage *language) { /* We treat NULL as a distinct language tag, but * we should actually determine the real language * tag it corresponds to to avoid duplicate entries * in the list. */ GList *tmp_list = fcfontmap->fontset_hash_list; while (tmp_list) { FontsetHashListNode *node = tmp_list->data; if (node->language == language) { if (tmp_list != fcfontmap->fontset_hash_list) { /* Put the found node at the beginning */ fcfontmap->fontset_hash_list = g_list_remove_link (fcfontmap->fontset_hash_list, tmp_list); fcfontmap->fontset_hash_list->prev = tmp_list; tmp_list->next = fcfontmap->fontset_hash_list; fcfontmap->fontset_hash_list = tmp_list; } return node->fontset_hash; } tmp_list = tmp_list->next; } { FontsetHashListNode *node = g_new (FontsetHashListNode, 1); fcfontmap->fontset_hash_list = g_list_prepend (fcfontmap->fontset_hash_list, node); node->fontset_hash = g_hash_table_new_full ((GHashFunc)pango_font_description_hash, (GEqualFunc)pango_font_description_equal, (GDestroyNotify)pango_font_description_free, (GDestroyNotify)pango_fc_font_set_free); node->language = language; return node->fontset_hash; } } static void pango_fc_clear_fontset_hash_list (PangoFcFontMap *fcfontmap) { GList *tmp_list = fcfontmap->fontset_hash_list; while (tmp_list) { FontsetHashListNode *node = tmp_list->data; g_hash_table_destroy (node->fontset_hash); g_free (node); tmp_list = tmp_list->next; } g_list_free (fcfontmap->fontset_hash_list); fcfontmap->fontset_hash_list = NULL; } static void pango_fc_font_map_finalize (GObject *object) { PangoFcFontMap *fcfontmap = PANGO_FC_FONT_MAP (object); fontmaps = g_slist_remove (fontmaps, object); if (fcfontmap->substitute_destroy) fcfontmap->substitute_destroy (fcfontmap->substitute_data); pango_fc_font_map_cache_clear (fcfontmap); g_queue_free (fcfontmap->freed_fonts); pango_fc_clear_fontset_hash_list (fcfontmap); g_hash_table_destroy (fcfontmap->coverage_hash); if (fcfontmap->fonts) g_hash_table_destroy (fcfontmap->fonts); pango_fc_do_finalize (fcfontmap); G_OBJECT_CLASS (parent_class)->finalize (object); } /* Add a mapping from xfont->font_pattern to xfont */ void _pango_fc_font_map_add (PangoFontMap *fontmap, PangoFcFont *xfont) { PangoFcFontMap *fcfontmap = PANGO_FC_FONT_MAP (fontmap); g_hash_table_insert (fcfontmap->fonts, xfont->font_pattern, xfont); } /* Remove mapping from xfont->font_pattern to xfont */ void _pango_fc_font_map_remove (PangoFontMap *fontmap, PangoFcFont *xfont) { PangoFcFontMap *fcfontmap = PANGO_FC_FONT_MAP (fontmap); g_hash_table_remove (fcfontmap->fonts, xfont->font_pattern); } static PangoFcFamily * create_family (PangoFcFontMap *fcfontmap, const char *family_name) { PangoFcFamily *family = g_object_new (PANGO_FC_TYPE_FAMILY, NULL); family->fontmap = fcfontmap; family->family_name = g_strdup (family_name); return family; } static gboolean is_alias_family (const char *family_name) { switch (family_name[0]) { case 'm': case 'M': return (g_ascii_strcasecmp (family_name, "monospace") == 0); case 's': case 'S': return (g_ascii_strcasecmp (family_name, "sans") == 0 || g_ascii_strcasecmp (family_name, "serif") == 0); } return FALSE; } static void pango_fc_font_map_list_families (PangoFontMap *fontmap, PangoFontFamily ***families, int *n_families) { PangoFcFontMap *fcfontmap = PANGO_FC_FONT_MAP (fontmap); FcFontSet *fontset; int i; int count; if (fcfontmap->closed) { if (families) *families = NULL; if (n_families) n_families = 0; return; } if (fcfontmap->n_families < 0) { FcObjectSet *os = FcObjectSetBuild (FC_FAMILY, NULL); FcPattern *pat = FcPatternCreate (); fontset = FcFontList (NULL, pat, os); FcPatternDestroy (pat); FcObjectSetDestroy (os); fcfontmap->families = g_new (PangoFcFamily *, fontset->nfont + 3); /* 3 standard aliases */ count = 0; for (i = 0; i < fontset->nfont; i++) { char *s; FcResult res; res = FcPatternGetString (fontset->fonts[i], FC_FAMILY, 0, (FcChar8 **) &s); g_assert (res == FcResultMatch); if (!is_alias_family (s)) fcfontmap->families[count++] = create_family (fcfontmap, s); } FcFontSetDestroy (fontset); fcfontmap->families[count++] = create_family (fcfontmap, "Sans"); fcfontmap->families[count++] = create_family (fcfontmap, "Serif"); fcfontmap->families[count++] = create_family (fcfontmap, "Monospace"); fcfontmap->n_families = count; } if (n_families) *n_families = fcfontmap->n_families; if (families) *families = g_memdup (fcfontmap->families, fcfontmap->n_families * sizeof (PangoFontFamily *)); } static int pango_fc_convert_weight (PangoWeight pango_weight) { int weight; if (pango_weight < (PANGO_WEIGHT_NORMAL + PANGO_WEIGHT_LIGHT) / 2) weight = FC_WEIGHT_LIGHT; else if (pango_weight < (PANGO_WEIGHT_NORMAL + 600) / 2) weight = FC_WEIGHT_MEDIUM; else if (pango_weight < (600 + PANGO_WEIGHT_BOLD) / 2) weight = FC_WEIGHT_DEMIBOLD; else if (pango_weight < (PANGO_WEIGHT_BOLD + PANGO_WEIGHT_ULTRABOLD) / 2) weight = FC_WEIGHT_BOLD; else weight = FC_WEIGHT_BLACK; return weight; } static int pango_fc_convert_slant (PangoStyle pango_style) { int slant; if (pango_style == PANGO_STYLE_ITALIC) slant = FC_SLANT_ITALIC; else if (pango_style == PANGO_STYLE_OBLIQUE) slant = FC_SLANT_OBLIQUE; else slant = FC_SLANT_ROMAN; return slant; } static FcPattern * pango_fc_make_pattern (const PangoFontDescription *description) { FcPattern *pattern; PangoStyle pango_style; int slant; int weight; char **families; int i; pango_style = pango_font_description_get_style (description); slant = pango_fc_convert_slant (pango_style); weight = pango_fc_convert_weight (pango_font_description_get_weight (description)); pattern = FcPatternBuild (0, FC_WEIGHT, FcTypeInteger, weight, FC_SLANT, FcTypeInteger, slant, FC_SIZE, FcTypeDouble, (double)pango_font_description_get_size (description)/PANGO_SCALE, NULL); families = g_strsplit (pango_font_description_get_family (description), ",", -1); for (i = 0; families[i]; i++) FcPatternAddString (pattern, FC_FAMILY, families[i]); g_strfreev (families); return pattern; } static PangoFont * pango_fc_font_map_new_font (PangoFontMap *fontmap, FcPattern *match) { PangoFcFontMap *fcfontmap = (PangoFcFontMap *)fontmap; PangoFcFont *font; /* Returning NULL here actually violates a contract * that loading load_font() will never return NULL. * We probably should actually create a dummy * font that doesn't draw anything and has empty * metrics. */ if (fcfontmap->closed) return NULL; /* Look up cache */ font = g_hash_table_lookup (fcfontmap->fonts, match); if (font) { g_object_ref (font); /* Revive font from cache */ if (font->in_cache) pango_fc_font_map_cache_remove (fontmap, font); return (PangoFont *)font; } FcPatternReference (match); return (PangoFont *)_pango_fc_font_new (fontmap, match); } static PangoFcPatternSet * pango_fc_font_map_get_patterns (PangoFontMap *fontmap, PangoContext *context, const PangoFontDescription *desc, PangoLanguage *language) { PangoFcFontMap *fcfontmap = (PangoFcFontMap *)fontmap; FcPattern *pattern, *font_pattern; FcResult res; int f; PangoFcPatternSet *patterns; FcFontSet *font_patterns; GHashTable *fontset_hash; if (!language && context) language = pango_context_get_language (context); fontset_hash = pango_fc_get_fontset_hash (fcfontmap, language); patterns = g_hash_table_lookup (fontset_hash, desc); if (patterns == NULL) { pattern = pango_fc_make_pattern (desc); if (language) FcPatternAddString (pattern, FC_LANG, (FcChar8 *) pango_language_to_string (language)); pango_fc_default_substitute (fcfontmap, pattern); font_patterns = FcFontSort (NULL, pattern, FcTrue, 0, &res); if (!font_patterns) return NULL; patterns = g_new (PangoFcPatternSet, 1); patterns->patterns = g_new (FcPattern *, font_patterns->nfont); patterns->n_patterns = 0; for (f = 0; f < font_patterns->nfont; f++) { font_pattern = FcFontRenderPrepare (NULL, pattern, font_patterns->fonts[f]); if (font_pattern) patterns->patterns[patterns->n_patterns++] = font_pattern; } FcPatternDestroy (pattern); FcFontSetSortDestroy (font_patterns); g_hash_table_insert (fontset_hash, pango_font_description_copy (desc), patterns); } return patterns; } static PangoFont * pango_fc_font_map_load_font (PangoFontMap *fontmap, PangoContext *context, const PangoFontDescription *description) { PangoFcPatternSet *patterns = pango_fc_font_map_get_patterns (fontmap, context, description, NULL); if (!patterns) return NULL; if (patterns->n_patterns > 0) return pango_fc_font_map_new_font (fontmap, patterns->patterns[0]); return NULL; } static void pango_fc_font_set_free (PangoFcPatternSet *font_set) { int i; for (i = 0; i < font_set->n_patterns; i++) FcPatternDestroy (font_set->patterns[i]); g_free (font_set); } static PangoFontset * pango_fc_font_map_load_fontset (PangoFontMap *fontmap, PangoContext *context, const PangoFontDescription *desc, PangoLanguage *language) { PangoFontsetSimple *simple; int i; PangoFcPatternSet *patterns = pango_fc_font_map_get_patterns (fontmap, context, desc, language); if (!patterns) return NULL; simple = pango_fontset_simple_new (language); for (i = 0; i < patterns->n_patterns; i++) { PangoFont *font = pango_fc_font_map_new_font (fontmap, patterns->patterns[i]); if (font) pango_fontset_simple_append (simple, font); } return PANGO_FONTSET (simple); } void _pango_fc_font_map_cache_add (PangoFontMap *fontmap, PangoFcFont *xfont) { PangoFcFontMap *fcfontmap = PANGO_FC_FONT_MAP (fontmap); g_object_ref (G_OBJECT (xfont)); g_queue_push_head (fcfontmap->freed_fonts, xfont); xfont->in_cache = TRUE; if (fcfontmap->freed_fonts->length > MAX_FREED_FONTS) { GObject *old_font = g_queue_pop_tail (fcfontmap->freed_fonts); g_object_unref (old_font); } } static void pango_fc_font_map_cache_remove (PangoFontMap *fontmap, PangoFcFont *xfont) { PangoFcFontMap *fcfontmap = PANGO_FC_FONT_MAP (fontmap); GList *link = g_list_find (fcfontmap->freed_fonts->head, xfont); if (link == fcfontmap->freed_fonts->tail) { fcfontmap->freed_fonts->tail = fcfontmap->freed_fonts->tail->prev; if (fcfontmap->freed_fonts->tail) fcfontmap->freed_fonts->tail->next = NULL; } fcfontmap->freed_fonts->head = g_list_delete_link (fcfontmap->freed_fonts->head, link); fcfontmap->freed_fonts->length--; xfont->in_cache = FALSE; g_object_unref (G_OBJECT (xfont)); } static void pango_fc_font_map_cache_clear (PangoFcFontMap *fcfontmap) { g_list_foreach (fcfontmap->freed_fonts->head, (GFunc)g_object_unref, NULL); g_list_free (fcfontmap->freed_fonts->head); fcfontmap->freed_fonts->head = NULL; fcfontmap->freed_fonts->tail = NULL; fcfontmap->freed_fonts->length = 0; } static void pango_fc_font_map_set_coverage (PangoFcFontMap *fcfontmap, PangoFcCoverageKey *key, PangoCoverage *coverage) { PangoFcCoverageKey *key_dup; key_dup = g_malloc (sizeof (PangoFcCoverageKey) + strlen (key->filename) + 1); key_dup->id = key->id; key_dup->filename = (char *) (key_dup + 1); strcpy (key_dup->filename, key->filename); g_hash_table_insert (fcfontmap->coverage_hash, key_dup, pango_coverage_ref (coverage)); } PangoCoverage * _pango_fc_font_map_get_coverage (PangoFontMap *fontmap, FcPattern *pattern) { PangoFcFontMap *fcfontmap = PANGO_FC_FONT_MAP (fontmap); PangoFcCoverageKey key; PangoCoverage *coverage; FcChar32 map[FC_CHARSET_MAP_SIZE]; FcChar32 ucs4, pos; FcCharSet *charset; int i; /* * Assume that coverage information is identified by * a filename/index pair; there shouldn't be any reason * this isn't true, but it's not specified anywhere */ if (FcPatternGetString (pattern, FC_FILE, 0, (FcChar8 **) &key.filename) != FcResultMatch) return NULL; if (FcPatternGetInteger (pattern, FC_INDEX, 0, &key.id) != FcResultMatch) return NULL; coverage = g_hash_table_lookup (fcfontmap->coverage_hash, &key); if (coverage) return pango_coverage_ref (coverage); /* * Pull the coverage out of the pattern, this * doesn't require loading the font */ if (FcPatternGetCharSet (pattern, FC_CHARSET, 0, &charset) != FcResultMatch) return NULL; /* * Convert an Fc CharSet into a pango coverage structure. Sure * would be nice to just use the Fc structure in place... */ coverage = pango_coverage_new (); for (ucs4 = FcCharSetFirstPage (charset, map, &pos); ucs4 != FC_CHARSET_DONE; ucs4 = FcCharSetNextPage (charset, map, &pos)) { for (i = 0; i < FC_CHARSET_MAP_SIZE; i++) { FcChar32 bits = map[i]; FcChar32 base = ucs4 + i * 32; int b = 0; bits = map[i]; while (bits) { if (bits & 1) pango_coverage_set (coverage, base + b, PANGO_COVERAGE_EXACT); bits >>= 1; b++; } } } pango_fc_font_map_set_coverage (fcfontmap, &key, coverage); return coverage; } /* * PangoFcFace */ PangoFontDescription * _pango_fc_font_desc_from_pattern (FcPattern *pattern, gboolean include_size) { PangoFontDescription *desc; PangoStyle style; PangoWeight weight; double size; char *s; int i; desc = pango_font_description_new (); g_assert (FcPatternGetString (pattern, FC_FAMILY, 0, (FcChar8 **) &s) == FcResultMatch); pango_font_description_set_family (desc, s); if (FcPatternGetInteger (pattern, FC_SLANT, 0, &i) == FcResultMatch) { if (i == FC_SLANT_ROMAN) style = PANGO_STYLE_NORMAL; else if (i == FC_SLANT_OBLIQUE) style = PANGO_STYLE_OBLIQUE; else style = PANGO_STYLE_ITALIC; } else style = PANGO_STYLE_NORMAL; pango_font_description_set_style (desc, style); if (FcPatternGetInteger (pattern, FC_WEIGHT, 0, &i) == FcResultMatch) { if (i < FC_WEIGHT_LIGHT) weight = PANGO_WEIGHT_ULTRALIGHT; else if (i < (FC_WEIGHT_LIGHT + FC_WEIGHT_MEDIUM) / 2) weight = PANGO_WEIGHT_LIGHT; else if (i < (FC_WEIGHT_MEDIUM + FC_WEIGHT_DEMIBOLD) / 2) weight = PANGO_WEIGHT_NORMAL; else if (i < (FC_WEIGHT_DEMIBOLD + FC_WEIGHT_BOLD) / 2) weight = 600; else if (i < (FC_WEIGHT_BOLD + FC_WEIGHT_BLACK) / 2) weight = PANGO_WEIGHT_BOLD; else weight = PANGO_WEIGHT_ULTRABOLD; } else weight = PANGO_WEIGHT_NORMAL; if (include_size && FcPatternGetDouble (pattern, FC_SIZE, 0, &size) == FcResultMatch) pango_font_description_set_size (desc, size * PANGO_SCALE); pango_font_description_set_weight (desc, weight); pango_font_description_set_variant (desc, PANGO_VARIANT_NORMAL); pango_font_description_set_stretch (desc, PANGO_STRETCH_NORMAL); return desc; } static PangoFontDescription * make_alias_description (PangoFcFamily *fcfamily, gboolean bold, gboolean italic) { PangoFontDescription *desc = pango_font_description_new (); pango_font_description_set_family (desc, fcfamily->family_name); pango_font_description_set_style (desc, italic ? PANGO_STYLE_ITALIC : PANGO_STYLE_NORMAL); pango_font_description_set_variant (desc, PANGO_VARIANT_NORMAL); pango_font_description_set_weight (desc, bold ? PANGO_WEIGHT_BOLD : PANGO_WEIGHT_NORMAL); pango_font_description_set_stretch (desc, PANGO_STRETCH_NORMAL); return desc; } static PangoFontDescription * pango_fc_face_describe (PangoFontFace *face) { PangoFcFace *fcface = PANGO_FC_FACE (face); PangoFcFamily *fcfamily = fcface->family; PangoFontDescription *desc = NULL; FcResult res; FcPattern *match_pattern; FcPattern *result_pattern; if (is_alias_family (fcfamily->family_name)) { if (strcmp (fcface->style, "Regular") == 0) return make_alias_description (fcfamily, FALSE, FALSE); else if (strcmp (fcface->style, "Bold") == 0) return make_alias_description (fcfamily, TRUE, FALSE); else if (strcmp (fcface->style, "Italic") == 0) return make_alias_description (fcfamily, FALSE, TRUE); else /* Bold Italic */ return make_alias_description (fcfamily, TRUE, TRUE); } match_pattern = FcPatternBuild (NULL, FC_FAMILY, FcTypeString, fcfamily->family_name, FC_STYLE, FcTypeString, fcface->style, NULL); g_assert (match_pattern); result_pattern = FcFontMatch (NULL, match_pattern, &res); if (result_pattern) { desc = _pango_fc_font_desc_from_pattern (result_pattern, FALSE); FcPatternDestroy (result_pattern); } FcPatternDestroy (match_pattern); return desc; } static const char * pango_fc_face_get_face_name (PangoFontFace *face) { PangoFcFace *fcface = PANGO_FC_FACE (face); return fcface->style; } static void pango_fc_face_class_init (PangoFontFaceClass *class) { class->describe = pango_fc_face_describe; class->get_face_name = pango_fc_face_get_face_name; } static GType pango_fc_face_get_type (void) { static GType object_type = 0; if (!object_type) { static const GTypeInfo object_info = { sizeof (PangoFontFaceClass), (GBaseInitFunc) NULL, (GBaseFinalizeFunc) NULL, (GClassInitFunc) pango_fc_face_class_init, NULL, /* class_finalize */ NULL, /* class_data */ sizeof (PangoFcFace), 0, /* n_preallocs */ (GInstanceInitFunc) NULL, }; object_type = g_type_register_static (PANGO_TYPE_FONT_FACE, PANGO_FC_NAME "Face", &object_info, 0); } return object_type; } /* * PangoFcFamily */ static PangoFcFace * create_face (PangoFcFamily *fcfamily, const char *style) { PangoFcFace *face = g_object_new (PANGO_FC_TYPE_FACE, NULL); face->style = g_strdup (style); face->family = fcfamily; return face; } static void pango_fc_family_list_faces (PangoFontFamily *family, PangoFontFace ***faces, int *n_faces) { PangoFcFamily *fcfamily = PANGO_FC_FAMILY (family); PangoFcFontMap *fcfontmap = fcfamily->fontmap; if (fcfamily->n_faces < 0) { FcFontSet *fontset; int i; if (is_alias_family (fcfamily->family_name) || fcfontmap->closed) { fcfamily->n_faces = 4; fcfamily->faces = g_new (PangoFcFace *, fcfamily->n_faces); i = 0; fcfamily->faces[i++] = create_face (fcfamily, "Regular"); fcfamily->faces[i++] = create_face (fcfamily, "Bold"); fcfamily->faces[i++] = create_face (fcfamily, "Italic"); fcfamily->faces[i++] = create_face (fcfamily, "Bold Italic"); } else { FcObjectSet *os = FcObjectSetBuild (FC_STYLE, NULL); FcPattern *pat = FcPatternBuild (NULL, FC_FAMILY, FcTypeString, fcfamily->family_name, NULL); fontset = FcFontList (NULL, pat, os); FcPatternDestroy (pat); FcObjectSetDestroy (os); fcfamily->n_faces = fontset->nfont; fcfamily->faces = g_new (PangoFcFace *, fcfamily->n_faces); for (i = 0; i < fontset->nfont; i++) { FcChar8 *s; FcResult res; res = FcPatternGetString (fontset->fonts[i], FC_STYLE, 0, &s); if (res != FcResultMatch) s = "Regular"; fcfamily->faces[i] = create_face (fcfamily, s); } FcFontSetDestroy (fontset); } } if (n_faces) *n_faces = fcfamily->n_faces; if (faces) *faces = g_memdup (fcfamily->faces, fcfamily->n_faces * sizeof (PangoFontFace *)); } static const char * pango_fc_family_get_name (PangoFontFamily *family) { PangoFcFamily *fcfamily = PANGO_FC_FAMILY (family); return fcfamily->family_name; } static void pango_fc_family_class_init (PangoFontFamilyClass *class) { class->list_faces = pango_fc_family_list_faces; class->get_name = pango_fc_family_get_name; } static void pango_fc_family_init (PangoFcFamily *fcfamily) { fcfamily->n_faces = -1; } static GType pango_fc_family_get_type (void) { static GType object_type = 0; if (!object_type) { static const GTypeInfo object_info = { sizeof (PangoFontFamilyClass), (GBaseInitFunc) NULL, (GBaseFinalizeFunc) NULL, (GClassInitFunc) pango_fc_family_class_init, NULL, /* class_finalize */ NULL, /* class_data */ sizeof (PangoFcFamily), 0, /* n_preallocs */ (GInstanceInitFunc) pango_fc_family_init, }; object_type = g_type_register_static (PANGO_TYPE_FONT_FAMILY, PANGO_FC_NAME "Family", &object_info, 0); } return object_type; }