summaryrefslogtreecommitdiff
path: root/pango/pangofc-fontmap.cI
diff options
context:
space:
mode:
authorOwen Taylor <otaylor@redhat.com>2002-08-16 22:00:28 +0000
committerOwen Taylor <otaylor@src.gnome.org>2002-08-16 22:00:28 +0000
commit2c1bc52c9d3429c34a26ad643eff8f84c339034e (patch)
treef75461f1804c334783f86d3092204a70bf3cd86e /pango/pangofc-fontmap.cI
parentc968ee2b826db913e4ccda3389009d1e2e9047df (diff)
downloadpango-2c1bc52c9d3429c34a26ad643eff8f84c339034e.tar.gz
Move the common code between PangoXftFontmap and PangoFT2Fontmap into a
Fri Aug 16 17:49:38 2002 Owen Taylor <otaylor@redhat.com> * pango/pangofc-fontmap.cI pango/pangoxft-fontmap.c pango/pangoft2-fontmap.c pango/pangoxft-private.h pango/pangoft2-private.h pango/pangoxft-font.c pango/pangoft2.h: Move the common code between PangoXftFontmap and PangoFT2Fontmap into a new file that is included from both with appropriate #defines. This provides most of the recent Xft backend improvements for the FT2 backend as well.
Diffstat (limited to 'pango/pangofc-fontmap.cI')
-rw-r--r--pango/pangofc-fontmap.cI1054
1 files changed, 1054 insertions, 0 deletions
diff --git a/pango/pangofc-fontmap.cI b/pango/pangofc-fontmap.cI
new file mode 100644
index 00000000..13b5c1cd
--- /dev/null
+++ b/pango/pangofc-fontmap.cI
@@ -0,0 +1,1054 @@
+/* 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;
+}