From 2c1bc52c9d3429c34a26ad643eff8f84c339034e Mon Sep 17 00:00:00 2001 From: Owen Taylor Date: Fri, 16 Aug 2002 22:00:28 +0000 Subject: Move the common code between PangoXftFontmap and PangoFT2Fontmap into a Fri Aug 16 17:49:38 2002 Owen Taylor * 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. --- ChangeLog | 11 + ChangeLog.pre-1-10 | 11 + ChangeLog.pre-1-2 | 11 + ChangeLog.pre-1-4 | 11 + ChangeLog.pre-1-6 | 11 + ChangeLog.pre-1-8 | 11 + pango/Makefile.am | 3 +- pango/pangofc-fontmap.c | 1054 +++++++++++++++++++++++++++++++++++++++++++++ pango/pangofc-fontmap.cI | 1054 +++++++++++++++++++++++++++++++++++++++++++++ pango/pangoft2-fontmap.c | 984 ++++-------------------------------------- pango/pangoft2-private.h | 17 +- pango/pangoft2.c | 60 +-- pango/pangoxft-font.c | 62 +-- pango/pangoxft-fontmap.c | 1056 ++++------------------------------------------ pango/pangoxft-private.h | 12 +- 15 files changed, 2333 insertions(+), 2035 deletions(-) create mode 100644 pango/pangofc-fontmap.c create mode 100644 pango/pangofc-fontmap.cI diff --git a/ChangeLog b/ChangeLog index 334a706f..662dab15 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,14 @@ +Fri Aug 16 17:49:38 2002 Owen Taylor + + * 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. + Tue Aug 13 16:38:19 2002 Owen Taylor * pango/pangoxft-fontmap.c (pango_xft_font_map_get_patterns): diff --git a/ChangeLog.pre-1-10 b/ChangeLog.pre-1-10 index 334a706f..662dab15 100644 --- a/ChangeLog.pre-1-10 +++ b/ChangeLog.pre-1-10 @@ -1,3 +1,14 @@ +Fri Aug 16 17:49:38 2002 Owen Taylor + + * 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. + Tue Aug 13 16:38:19 2002 Owen Taylor * pango/pangoxft-fontmap.c (pango_xft_font_map_get_patterns): diff --git a/ChangeLog.pre-1-2 b/ChangeLog.pre-1-2 index 334a706f..662dab15 100644 --- a/ChangeLog.pre-1-2 +++ b/ChangeLog.pre-1-2 @@ -1,3 +1,14 @@ +Fri Aug 16 17:49:38 2002 Owen Taylor + + * 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. + Tue Aug 13 16:38:19 2002 Owen Taylor * pango/pangoxft-fontmap.c (pango_xft_font_map_get_patterns): diff --git a/ChangeLog.pre-1-4 b/ChangeLog.pre-1-4 index 334a706f..662dab15 100644 --- a/ChangeLog.pre-1-4 +++ b/ChangeLog.pre-1-4 @@ -1,3 +1,14 @@ +Fri Aug 16 17:49:38 2002 Owen Taylor + + * 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. + Tue Aug 13 16:38:19 2002 Owen Taylor * pango/pangoxft-fontmap.c (pango_xft_font_map_get_patterns): diff --git a/ChangeLog.pre-1-6 b/ChangeLog.pre-1-6 index 334a706f..662dab15 100644 --- a/ChangeLog.pre-1-6 +++ b/ChangeLog.pre-1-6 @@ -1,3 +1,14 @@ +Fri Aug 16 17:49:38 2002 Owen Taylor + + * 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. + Tue Aug 13 16:38:19 2002 Owen Taylor * pango/pangoxft-fontmap.c (pango_xft_font_map_get_patterns): diff --git a/ChangeLog.pre-1-8 b/ChangeLog.pre-1-8 index 334a706f..662dab15 100644 --- a/ChangeLog.pre-1-8 +++ b/ChangeLog.pre-1-8 @@ -1,3 +1,14 @@ +Fri Aug 16 17:49:38 2002 Owen Taylor + + * 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. + Tue Aug 13 16:38:19 2002 Owen Taylor * pango/pangoxft-fontmap.c (pango_xft_font_map_get_patterns): diff --git a/pango/Makefile.am b/pango/Makefile.am index 16bd611b..6924cba4 100644 --- a/pango/Makefile.am +++ b/pango/Makefile.am @@ -290,12 +290,13 @@ EXTRA_DIST = \ module-defs-ft2.c.win32 \ module-defs-win32.c.win32 \ module-defs.h \ + pangofc-fontmap.cI \ pango.def \ pangowin32.def \ pangoft2.def \ makefile.mingw \ makefile.mingw.in \ - makefile.msc \ + makefile.msc \ pango.rc \ pango.rc.in \ pangoft2.rc \ diff --git a/pango/pangofc-fontmap.c b/pango/pangofc-fontmap.c new file mode 100644 index 00000000..13b5c1cd --- /dev/null +++ b/pango/pangofc-fontmap.c @@ -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; +} 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; +} diff --git a/pango/pangoft2-fontmap.c b/pango/pangoft2-fontmap.c index 47132f01..ad15e6d1 100644 --- a/pango/pangoft2-fontmap.c +++ b/pango/pangoft2-fontmap.c @@ -43,23 +43,7 @@ #include #endif -typedef struct _PangoFT2SizeInfo PangoFT2SizeInfo; -typedef struct _PangoFT2PatternSet PangoFT2PatternSet; - -/* Number of freed fonts */ -#define MAX_FREED_FONTS 16 - -struct _PangoFT2Family -{ - PangoFontFamily parent_instance; - - PangoFT2FontMap *fontmap; - char *family_name; - - PangoFT2Face **faces; - int n_faces; /* -1 == uninitialized */ -}; - +typedef struct _PangoFT2Family PangoFT2Family; struct _PangoFT2FontMap { @@ -67,7 +51,10 @@ struct _PangoFT2FontMap FT_Library library; - GHashTable *fontset_hash; /* Maps PangoFontDescription -> PangoXftFontSet */ + /* We have one map from PangoFontDescription -> PangoXftPatternSet + * per language tag. + */ + GList *fontset_hash_list; GHashTable *coverage_hash; /* Maps font file name -> PangoCoverage */ GHashTable *fonts; /* Maps XftPattern -> PangoFT2Font */ @@ -80,6 +67,8 @@ struct _PangoFT2FontMap double dpi_x; double dpi_y; + guint closed : 1; + /* Function to call on prepared patterns to do final * config tweaking. */ @@ -88,157 +77,37 @@ struct _PangoFT2FontMap GDestroyNotify substitute_destroy; }; -struct _PangoFT2PatternSet -{ - int n_patterns; - FcPattern **patterns; -}; - -#define PANGO_FT2_TYPE_FAMILY (pango_ft2_family_get_type ()) -#define PANGO_FT2_FAMILY(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), PANGO_FT2_TYPE_FAMILY, PangoFT2Family)) -#define PANGO_FT2_IS_FAMILY(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), PANGO_FT2_TYPE_FAMILY)) +/************************************************************ + * Code shared with PangoXft * + ************************************************************/ -#define PANGO_FT2_TYPE_FACE (pango_ft2_face_get_type ()) -#define PANGO_FT2_FACE(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), PANGO_FT2_TYPE_FACE, PangoFT2Face)) -#define PANGO_FT2_IS_FACE(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), PANGO_FT2_TYPE_FACE)) +#define PangoFcFamily PangoFT2Family +#define _PangoFcFamily _PangoFT2Family +#define PangoFcFontMap PangoFT2FontMap +#define PangoFcFont PangoFT2Font -GType pango_ft2_family_get_type (void); -GType pango_ft2_face_get_type (void); +#define PANGO_FC_FONT_MAP PANGO_FT2_FONT_MAP -static void pango_ft2_font_map_init (PangoFT2FontMap *fontmap); -static void pango_ft2_font_map_class_init (PangoFontMapClass *class); -static void pango_ft2_font_map_finalize (GObject *object); -static PangoFont * pango_ft2_font_map_load_font (PangoFontMap *fontmap, - PangoContext *context, - const PangoFontDescription *description); -static PangoFontset *pango_ft2_font_map_load_fontset (PangoFontMap *fontmap, - PangoContext *context, - const PangoFontDescription *desc, - PangoLanguage *language); -static void pango_ft2_font_set_free (PangoFT2PatternSet *font_set); -static void pango_ft2_font_map_list_families (PangoFontMap *fontmap, - PangoFontFamily ***families, - int *n_families); -static void pango_ft2_font_map_cache_remove (PangoFontMap *fontmap, - PangoFT2Font *ft2font); -static void pango_ft2_font_map_cache_clear (PangoFT2FontMap *ft2fontmap); +#define pango_fc_font_map_get_type pango_ft2_font_map_get_type +#define _pango_fc_font_map_add _pango_ft2_font_map_add +#define _pango_fc_font_map_remove _pango_ft2_font_map_remove +#define _pango_fc_font_map_cache_add _pango_ft2_font_map_cache_add +#define _pango_fc_font_map_cache_remove _pango_ft2_font_map_cache_remove +#define _pango_fc_font_map_get_coverage _pango_ft2_font_map_get_coverage +#define _pango_fc_font_map_set_coverage _pango_ft2_font_map_set_coverage +#define _pango_fc_font_desc_from_pattern _pango_ft2_font_desc_from_pattern +#define _pango_fc_font_new _pango_ft2_font_new +#define PANGO_FC_NAME "PangoFT2" +#include "pangofc-fontmap.cI" -static PangoFontClass *parent_class; /* Parent class structure for PangoFT2FontMap */ +/************************************************************* + * FreeType specific code * + *************************************************************/ static PangoFT2FontMap *pango_ft2_global_fontmap = NULL; -GType -pango_ft2_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_ft2_font_map_class_init, - NULL, /* class_finalize */ - NULL, /* class_data */ - sizeof (PangoFT2FontMap), - 0, /* n_preallocs */ - (GInstanceInitFunc) pango_ft2_font_map_init, - }; - - object_type = g_type_register_static (PANGO_TYPE_FONT_MAP, - "PangoFT2FontMap", - &object_info, 0); - } - - return object_type; -} - -static void -pango_ft2_font_set_free (PangoFT2PatternSet *font_set) -{ - int i; - - for (i = 0; i < font_set->n_patterns; i++) - FcPatternDestroy (font_set->patterns[i]); - - g_free (font_set); -} - -static guint -pango_ft2_pattern_hash (FcPattern *pattern) -{ - FcChar8 *str; - int i; - double d; - guint hash = 0; - - if (FcPatternGetString (pattern, FC_FILE, 0, &str) == FcResultMatch) - hash = g_str_hash ((char *) 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; -} - -static gboolean -pango_ft2_pattern_equal (FcPattern *pattern1, - FcPattern *pattern2) -{ - return FcPatternEqual (pattern1, pattern2); -} - -static void -pango_ft2_init_fontset_hash (PangoFT2FontMap *ft2fontmap) -{ - if (ft2fontmap->fontset_hash) - g_hash_table_destroy (ft2fontmap->fontset_hash); - - ft2fontmap->fontset_hash = - g_hash_table_new_full ((GHashFunc)pango_font_description_hash, - (GEqualFunc)pango_font_description_equal, - (GDestroyNotify)pango_font_description_free, - (GDestroyNotify)pango_ft2_font_set_free); -} - -static void -pango_ft2_font_map_init (PangoFT2FontMap *ft2fontmap) -{ - ft2fontmap->n_families = -1; - - ft2fontmap->fonts = - g_hash_table_new ((GHashFunc)pango_ft2_pattern_hash, - (GEqualFunc)pango_ft2_pattern_equal); - - pango_ft2_init_fontset_hash (ft2fontmap); - - ft2fontmap->coverage_hash = - g_hash_table_new_full (g_str_hash, g_str_equal, - (GDestroyNotify)g_free, - (GDestroyNotify)pango_coverage_unref); - ft2fontmap->freed_fonts = g_queue_new (); -} - -static void -pango_ft2_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_ft2_font_map_finalize; - class->load_font = pango_ft2_font_map_load_font; - class->load_fontset = pango_ft2_font_map_load_fontset; - class->list_families = pango_ft2_font_map_list_families; -} - /** * pango_ft2_font_map_new: * @@ -284,6 +153,22 @@ pango_ft2_font_map_new (void) return (PangoFontMap *)ft2fontmap; } +/** + * pango_ft2_font_map_substitute_changed: + * @fontmap: a #PangoFT2Fontmap + * + * Call this function any time the results of the + * default substitution function set with + * pango_ft2_font_map_set_default_substitute() change. + * That is, if your subsitution function will return different + * results for the same input pattern, you must call this function. + **/ +void +pango_ft2_font_map_substitute_changed (PangoFT2FontMap *fontmap) +{ + pango_fc_clear_fontset_hash_list (fontmap); +} + /** * pango_ft2_font_map_set_resolution: * @fontmap: a #PangoFT2Fontmap @@ -305,53 +190,6 @@ pango_ft2_font_map_set_resolution (PangoFT2FontMap *fontmap, pango_ft2_font_map_substitute_changed (fontmap); } -/** - * pango_ft2_font_map_set_default_substitute: - * @fontmap: a #PangoFT2Fontmap - * @func: function to call to to do final config tweaking - * on #FcPattern objects. - * @data: data to pass to @func - * @notify: function to call when @data is no longer used. - * - * Sets a function that will be called to do final configuration - * substitution on a #FcPattern before it is used to load - * the font. This function can be used to do things like set - * hinting and antiasing options. - **/ -void -pango_ft2_font_map_set_default_substitute (PangoFT2FontMap *fontmap, - PangoFT2SubstituteFunc func, - gpointer data, - GDestroyNotify notify) -{ - g_return_if_fail (PANGO_FT2_IS_FONT_MAP (fontmap)); - - if (fontmap->substitute_destroy) - fontmap->substitute_destroy (fontmap->substitute_data); - - fontmap->substitute_func = func; - fontmap->substitute_data = data; - fontmap->substitute_destroy = notify; - - pango_ft2_font_map_substitute_changed (fontmap); -} - -/** - * pango_ft2_font_map_substitute_changed: - * @fontmap: a #PangoFT2Fontmap - * - * Call this function any time the results of the - * default substitution function set with - * pango_ft2_font_map_set_default_substitute() change. - * That is, if your subsitution function will return different - * results for the same input pattern, you must call this function. - **/ -void -pango_ft2_font_map_substitute_changed (PangoFT2FontMap *fontmap) -{ - pango_ft2_init_fontset_hash (fontmap); -} - /** * pango_ft2_font_map_create_context: * @fontmap: a #PangoFT2Fontmap @@ -373,26 +211,6 @@ pango_ft2_font_map_create_context (PangoFT2FontMap *fontmap) return context; } -/** - * pango_ft2_font_map_for_display: - * - * Returns a #PangoFT2FontMap. This font map is cached and should - * not be freed. If the font map is no longer needed, it can - * be released with pango_ft2_shutdown_display(). - * - * Returns: a #PangoFT2FontMap. - **/ -PangoFontMap * -pango_ft2_font_map_for_display (void) -{ - if (pango_ft2_global_fontmap != NULL) - return PANGO_FONT_MAP (pango_ft2_global_fontmap); - - pango_ft2_global_fontmap = (PangoFT2FontMap *)pango_ft2_font_map_new (); - - return PANGO_FONT_MAP (pango_ft2_global_fontmap); -} - /** * pango_ft2_get_context: * @dpi_x: the horizontal dpi of the target device @@ -418,6 +236,26 @@ pango_ft2_get_context (double dpi_x, double dpi_y) return pango_ft2_font_map_create_context (PANGO_FT2_FONT_MAP (fontmap)); } +/** + * pango_ft2_font_map_for_display: + * + * Returns a #PangoFT2FontMap. This font map is cached and should + * not be freed. If the font map is no longer needed, it can + * be released with pango_ft2_shutdown_display(). + * + * Returns: a #PangoFT2FontMap. + **/ +PangoFontMap * +pango_ft2_font_map_for_display (void) +{ + if (pango_ft2_global_fontmap != NULL) + return PANGO_FONT_MAP (pango_ft2_global_fontmap); + + pango_ft2_global_fontmap = (PangoFT2FontMap *)pango_ft2_font_map_new (); + + return PANGO_FONT_MAP (pango_ft2_global_fontmap); +} + /** * pango_ft2_shutdown_display: * @@ -428,7 +266,7 @@ pango_ft2_shutdown_display (void) { if (pango_ft2_global_fontmap) { - pango_ft2_font_map_cache_clear (pango_ft2_global_fontmap); + pango_fc_font_map_cache_clear (pango_ft2_global_fontmap); g_object_unref (G_OBJECT (pango_ft2_global_fontmap)); @@ -436,576 +274,6 @@ pango_ft2_shutdown_display (void) } } - -static void -pango_ft2_font_map_finalize (GObject *object) -{ - PangoFT2FontMap *ft2fontmap = PANGO_FT2_FONT_MAP (object); - - g_queue_free (ft2fontmap->freed_fonts); - g_hash_table_destroy (ft2fontmap->fontset_hash); - g_hash_table_destroy (ft2fontmap->coverage_hash); - - if (ft2fontmap->substitute_destroy) - ft2fontmap->substitute_destroy (ft2fontmap->substitute_data); - - FT_Done_FreeType (ft2fontmap->library); - - G_OBJECT_CLASS (parent_class)->finalize (object); -} - -/* Add a mapping from xfont->font_pattern to xfont */ -void -_pango_ft2_font_map_add (PangoFontMap *fontmap, - PangoFT2Font *ft2font) -{ - PangoFT2FontMap *ft2fontmap = (PangoFT2FontMap *) fontmap; - - g_hash_table_insert (ft2fontmap->fonts, - ft2font->font_pattern, - ft2font); -} - -/* Remove mapping from xfont->font_pattern to xfont */ -void -_pango_ft2_font_map_remove (PangoFontMap *fontmap, - PangoFT2Font *ft2font) -{ - PangoFT2FontMap *ft2fontmap = (PangoFT2FontMap *) fontmap; - - g_hash_table_remove (ft2fontmap->fonts, - ft2font->font_pattern); -} - -static PangoFT2Family * -create_family (PangoFT2FontMap *ft2fontmap, - const char *family_name) -{ - PangoFT2Family *family = g_object_new (PANGO_FT2_TYPE_FAMILY, NULL); - family->fontmap = ft2fontmap; - family->family_name = g_strdup (family_name); - family->n_faces = -1; - - 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_ft2_font_map_list_families (PangoFontMap *fontmap, - PangoFontFamily ***families, - int *n_families) -{ - PangoFT2FontMap *ft2fontmap = (PangoFT2FontMap *)fontmap; - FcFontSet *fontset; - int i; - int count; - - if (ft2fontmap->n_families < 0) - { - FcObjectSet *os = FcObjectSetBuild (FC_FAMILY, NULL); - FcPattern *pat = FcPatternCreate (); - fontset = FcFontList (NULL, pat, os); - FcPatternDestroy (pat); - FcObjectSetDestroy (os); - - ft2fontmap->families = g_new (PangoFT2Family *, fontset->nfont + 3); /* 3 standard aliases */ - - count = 0; - for (i = 0; i < fontset->nfont; i++) - { - FcChar8 *s; - FcResult res; - - res = FcPatternGetString (fontset->fonts[i], FC_FAMILY, 0, &s); - g_assert (res == FcResultMatch); - - if (!is_alias_family (s)) - ft2fontmap->families[count++] = create_family (ft2fontmap, s); - - } - - ft2fontmap->families[count++] = create_family (ft2fontmap, "Sans"); - ft2fontmap->families[count++] = create_family (ft2fontmap, "Serif"); - ft2fontmap->families[count++] = create_family (ft2fontmap, "Monospace"); - - FcFontSetDestroy (fontset); - - ft2fontmap->n_families = count; - } - - if (n_families) - *n_families = ft2fontmap->n_families; - - if (families) - *families = g_memdup (ft2fontmap->families, - ft2fontmap->n_families * sizeof (PangoFontFamily *)); -} - -static int -pango_ft2_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_ft2_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_ft2_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_ft2_convert_slant (pango_style); - weight = pango_ft2_convert_weight (pango_font_description_get_weight (description)); - - /* To fool Xft into not munging glyph indices, we open it as glyphs-fontspecific - * then set the encoding ourself - */ - pattern = FcPatternBuild (NULL, - 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_ft2_font_map_new_font (PangoFontMap *fontmap, - FcPattern *match) -{ - PangoFT2FontMap *ft2fontmap = (PangoFT2FontMap *)fontmap; - PangoFT2Font *font; - - /* Look up cache */ - font = g_hash_table_lookup (ft2fontmap->fonts, match); - - if (font) - { - g_object_ref (font); - - /* Revive font from cache */ - if (font->in_cache) - pango_ft2_font_map_cache_remove (fontmap, font); - - return (PangoFont *)font; - } - - return (PangoFont *)_pango_ft2_font_new (fontmap, FcPatternDuplicate (match)); -} - - -static PangoFont * -pango_ft2_font_map_load_font (PangoFontMap *fontmap, - PangoContext *context, - const PangoFontDescription *description) -{ - FcPattern *pattern, *match; - FcResult res; - PangoFont *font; - - pattern = pango_ft2_make_pattern (description); - - match = FcFontMatch (0, pattern, &res); - FcPatternDestroy (pattern); - - font = NULL; - - if (match) - { - font = pango_ft2_font_map_new_font (fontmap, match); - FcPatternDestroy (match); - } - - return font; -} - -static void -pango_ft2_default_substitute (PangoFT2FontMap *fontmap, - FcPattern *pattern) -{ - FcValue v; - - if (fontmap->substitute_func) - fontmap->substitute_func (pattern, fontmap->substitute_data); - - if (FcPatternGet (pattern, FC_DPI, 0, &v) == FcResultNoMatch) - FcPatternAddDouble (pattern, FC_DPI, fontmap->dpi_y); -} - -static PangoFontset * -pango_ft2_font_map_load_fontset (PangoFontMap *fontmap, - PangoContext *context, - const PangoFontDescription *desc, - PangoLanguage *language) -{ - PangoFT2FontMap *ft2fontmap = (PangoFT2FontMap *)fontmap; - FcPattern *pattern, *pattern_copy; - FcPattern *match; - int i; - FcChar8 *family, *family_res; - FcResult res; - GPtrArray *array; - int id; - PangoFT2PatternSet *patterns; - PangoFontsetSimple *simple; - - patterns = g_hash_table_lookup (ft2fontmap->fontset_hash, desc); - - if (patterns == NULL) - { - pattern = pango_ft2_make_pattern (desc); - - if (!FcInit ()) - { - g_warning ("Cannot initialize fontconfig"); - return NULL; - } - FcConfigSubstitute (0, pattern, FcMatchPattern); - FcDefaultSubstitute (pattern); - pango_ft2_default_substitute (ft2fontmap, pattern); - - pattern_copy = FcPatternDuplicate (pattern); - - array = g_ptr_array_new (); - patterns = g_new (PangoFT2PatternSet, 1); - - match = NULL; - id = 0; - while (FcPatternGetString (pattern, FC_FAMILY, id++, &family) == FcResultMatch) - { - FcPatternDel (pattern_copy, FC_FAMILY); - FcPatternAddString (pattern_copy, FC_FAMILY, family); - - match = FcFontMatch (NULL, pattern_copy, &res); - - if (match && - FcPatternGetString (match, FC_FAMILY, 0, &family_res) == FcResultMatch && - FcStrCmpIgnoreCase (family, family_res) == 0) - { - g_ptr_array_add (array, match); - match = NULL; - } - if (match) - FcPatternDestroy (match); - } - - if (array->len == 0) - { - match = FcFontMatch (0, pattern, &res); - g_ptr_array_add (array, match); - } - - FcPatternDestroy (pattern); - FcPatternDestroy (pattern_copy); - - patterns->n_patterns = array->len; - patterns->patterns = (FcPattern **)g_ptr_array_free (array, FALSE); - - g_hash_table_insert (ft2fontmap->fontset_hash, - pango_font_description_copy (desc), - patterns); - } - - simple = pango_fontset_simple_new (language); - - for (i = 0; i < patterns->n_patterns; i++) - pango_fontset_simple_append (simple, - pango_ft2_font_map_new_font (fontmap, patterns->patterns[i])); - - return PANGO_FONTSET (simple); -} - -void -_pango_ft2_font_map_cache_add (PangoFontMap *fontmap, - PangoFT2Font *ft2font) -{ - PangoFT2FontMap *ft2fontmap = PANGO_FT2_FONT_MAP (fontmap); - - if (ft2fontmap->freed_fonts->length == MAX_FREED_FONTS) - { - PangoFT2Font *old_font = g_queue_pop_tail (ft2fontmap->freed_fonts); - g_object_unref (G_OBJECT (old_font)); - } - - g_object_ref (G_OBJECT (ft2font)); - g_queue_push_head (ft2fontmap->freed_fonts, ft2font); - ft2font->in_cache = TRUE; -} - -static void -pango_ft2_font_map_cache_remove (PangoFontMap *fontmap, - PangoFT2Font *ft2font) -{ - PangoFT2FontMap *ft2fontmap = PANGO_FT2_FONT_MAP (fontmap); - - GList *link = g_list_find (ft2fontmap->freed_fonts->head, ft2font); - if (link == ft2fontmap->freed_fonts->tail) - { - ft2fontmap->freed_fonts->tail = ft2fontmap->freed_fonts->tail->prev; - if (ft2fontmap->freed_fonts->tail) - ft2fontmap->freed_fonts->tail->next = NULL; - } - - ft2fontmap->freed_fonts->head = g_list_delete_link (ft2fontmap->freed_fonts->head, link); - ft2fontmap->freed_fonts->length--; - ft2font->in_cache = FALSE; - - g_object_unref (G_OBJECT (ft2font)); -} - -static void -pango_ft2_font_map_cache_clear (PangoFT2FontMap *ft2fontmap) -{ - g_list_foreach (ft2fontmap->freed_fonts->head, (GFunc)g_object_unref, NULL); - g_list_free (ft2fontmap->freed_fonts->head); - ft2fontmap->freed_fonts->head = NULL; - ft2fontmap->freed_fonts->tail = NULL; - ft2fontmap->freed_fonts->length = 0; -} - -/* - * PangoFT2Face - */ - -PangoFontDescription * -_pango_ft2_font_desc_from_pattern (FcPattern *pattern, - gboolean include_size) -{ - PangoFontDescription *desc; - PangoStyle style; - PangoWeight weight; - double size; - - FcChar8 *s; - int i; - - desc = pango_font_description_new (); - - g_assert (FcPatternGetString (pattern, FC_FAMILY, 0, &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 (PangoFT2Family *ft2family, - gboolean bold, - gboolean italic) -{ - PangoFontDescription *desc = pango_font_description_new (); - - pango_font_description_set_family (desc, ft2family->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_ft2_face_describe (PangoFontFace *face) -{ - PangoFT2Face *ft2face = (PangoFT2Face *) face; - PangoFT2Family *ft2family = ft2face->family; - PangoFontDescription *desc = NULL; - FcResult res; - FcPattern *match_pattern; - FcPattern *result_pattern; - - if (is_alias_family (ft2family->family_name)) - { - if (strcmp (ft2face->style, "Regular") == 0) - return make_alias_description (ft2family, FALSE, FALSE); - else if (strcmp (ft2face->style, "Bold") == 0) - return make_alias_description (ft2family, TRUE, FALSE); - else if (strcmp (ft2face->style, "Italic") == 0) - return make_alias_description (ft2family, FALSE, TRUE); - else /* Bold Italic */ - return make_alias_description (ft2family, TRUE, TRUE); - } - - match_pattern = FcPatternBuild (NULL, - FC_FAMILY, FcTypeString, ft2family->family_name, - FC_STYLE, FcTypeString, ft2face->style, - NULL); - - g_assert (match_pattern); - - result_pattern = FcFontMatch (NULL, match_pattern, &res); - if (result_pattern) - { - desc = _pango_ft2_font_desc_from_pattern (result_pattern, FALSE); - FcPatternDestroy (result_pattern); - } - - FcPatternDestroy (match_pattern); - - return desc; -} - -static const char * -pango_ft2_face_get_face_name (PangoFontFace *face) -{ - PangoFT2Face *ft2face = PANGO_FT2_FACE (face); - - return ft2face->style; -} - -static void -pango_ft2_face_class_init (PangoFontFaceClass *class) -{ - class->describe = pango_ft2_face_describe; - class->get_face_name = pango_ft2_face_get_face_name; -} - -GType -pango_ft2_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_ft2_face_class_init, - NULL, /* class_finalize */ - NULL, /* class_data */ - sizeof (PangoFT2Face), - 0, /* n_preallocs */ - (GInstanceInitFunc) NULL, - }; - - object_type = g_type_register_static (PANGO_TYPE_FONT_FACE, - "PangoFT2Face", - &object_info, 0); - } - - return object_type; -} - -void -_pango_ft2_font_map_set_coverage (PangoFontMap *fontmap, - const char *name, - PangoCoverage *coverage) -{ - PangoFT2FontMap *ft2fontmap = (PangoFT2FontMap *)fontmap; - - g_hash_table_insert (ft2fontmap->coverage_hash, g_strdup (name), - pango_coverage_ref (coverage)); -} - -PangoCoverage * -_pango_ft2_font_map_get_coverage (PangoFontMap *fontmap, - const char *name) -{ - PangoFT2FontMap *ft2fontmap = (PangoFT2FontMap *)fontmap; - - return g_hash_table_lookup (ft2fontmap->coverage_hash, name); -} - FT_Library _pango_ft2_font_map_get_library (PangoFontMap *fontmap) { @@ -1014,120 +282,24 @@ _pango_ft2_font_map_get_library (PangoFontMap *fontmap) return ft2fontmap->library; } -/* - * PangoFT2FontFamily - */ -static PangoFT2Face * -create_face (PangoFT2Family *ft2family, - const char *style) -{ - PangoFT2Face *face = g_object_new (PANGO_FT2_TYPE_FACE, NULL); - face->style = g_strdup (style); - face->family = ft2family; - - return face; -} - static void -pango_ft2_family_list_faces (PangoFontFamily *family, - PangoFontFace ***faces, - int *n_faces) -{ - PangoFT2Family *ft2family = PANGO_FT2_FAMILY (family); - - if (ft2family->n_faces < 0) - { - FcFontSet *fontset; - FcPattern *pat; - FcObjectSet *os; - int i; - - if (is_alias_family (ft2family->family_name)) - { - ft2family->n_faces = 4; - ft2family->faces = g_new (PangoFT2Face *, ft2family->n_faces); - - i = 0; - ft2family->faces[i++] = create_face (ft2family, "Regular"); - ft2family->faces[i++] = create_face (ft2family, "Bold"); - ft2family->faces[i++] = create_face (ft2family, "Italic"); - ft2family->faces[i++] = create_face (ft2family, "Bold Italic"); - } - else - { - os = FcObjectSetBuild (FC_STYLE, NULL); - pat = FcPatternBuild (NULL, - FC_FAMILY, FcTypeString, ft2family->family_name, - NULL); - - fontset = FcFontList (NULL, pat, os); - - FcPatternDestroy (pat); - FcObjectSetDestroy (os); - - ft2family->n_faces = fontset->nfont; - ft2family->faces = g_new (PangoFT2Face *, ft2family->n_faces); - - for (i = 0; i < fontset->nfont; i++) - { - FcChar8 *s; - FcResult res; - - res = FcPatternGetString (fontset->fonts[i], FC_STYLE, 0, &s); - g_assert (res == FcResultMatch); - - ft2family->faces[i] = create_face (ft2family, s); - } - - FcFontSetDestroy (fontset); - } - } - - if (n_faces) - *n_faces = ft2family->n_faces; - - if (faces) - *faces = g_memdup (ft2family->faces, ft2family->n_faces * sizeof (PangoFontFace *)); -} - -const char * -pango_ft2_family_get_name (PangoFontFamily *family) +pango_fc_do_finalize (PangoFT2FontMap *fontmap) { - PangoFT2Family *ft2family = PANGO_FT2_FAMILY (family); - return ft2family->family_name; + FT_Done_FreeType (fontmap->library); } static void -pango_ft2_family_class_init (PangoFontFamilyClass *class) +pango_fc_default_substitute (PangoFT2FontMap *fontmap, + FcPattern *pattern) { - class->list_faces = pango_ft2_family_list_faces; - class->get_name = pango_ft2_family_get_name; -} + FcValue v; + + FcConfigSubstitute (NULL, pattern, FcMatchPattern); -GType -pango_ft2_family_get_type (void) -{ - static GType object_type = 0; + if (fontmap->substitute_func) + fontmap->substitute_func (pattern, fontmap->substitute_data); - if (!object_type) - { - static const GTypeInfo object_info = - { - sizeof (PangoFontFamilyClass), - (GBaseInitFunc) NULL, - (GBaseFinalizeFunc) NULL, - (GClassInitFunc) pango_ft2_family_class_init, - NULL, /* class_finalize */ - NULL, /* class_data */ - sizeof (PangoFT2Family), - 0, /* n_preallocs */ - (GInstanceInitFunc) NULL, - }; - - object_type = g_type_register_static (PANGO_TYPE_FONT_FAMILY, - "PangoFT2Family", - &object_info, 0); - } - - return object_type; + FcDefaultSubstitute (pattern); + if (FcPatternGet (pattern, FC_DPI, 0, &v) == FcResultNoMatch) + FcPatternAddDouble (pattern, FC_DPI, fontmap->dpi_y); } diff --git a/pango/pangoft2-private.h b/pango/pangoft2-private.h index 2fe8f719..d8d20eae 100644 --- a/pango/pangoft2-private.h +++ b/pango/pangoft2-private.h @@ -55,8 +55,6 @@ typedef struct _PangoFT2Font PangoFT2Font; typedef struct _PangoFT2GlyphInfo PangoFT2GlyphInfo; -typedef struct _PangoFT2Face PangoFT2Face; -typedef struct _PangoFT2Family PangoFT2Family; struct _PangoFT2Font @@ -89,24 +87,11 @@ struct _PangoFT2GlyphInfo void *cached_glyph; }; -struct _PangoFT2Face -{ - PangoFontFace parent_instance; - - PangoFT2Family *family; - char *style; -}; - PangoFT2Font * _pango_ft2_font_new (PangoFontMap *font, FcPattern *pattern); PangoMap *_pango_ft2_get_shaper_map (PangoLanguage *language); -void _pango_ft2_font_map_set_coverage (PangoFontMap *fontmap, - const char *name, - PangoCoverage *coverage); PangoCoverage *_pango_ft2_font_map_get_coverage (PangoFontMap *fontmap, - const char *name); -void _pango_ft2_face_remove (PangoFT2Face *face, - PangoFont *font); + FcPattern *pattern); FT_Library _pango_ft2_font_map_get_library (PangoFontMap *fontmap); void _pango_ft2_font_map_cache_add (PangoFontMap *fontmap, PangoFT2Font *ft2font); diff --git a/pango/pangoft2.c b/pango/pangoft2.c index fce91a5e..0851840c 100644 --- a/pango/pangoft2.c +++ b/pango/pangoft2.c @@ -677,46 +677,6 @@ pango_ft2_font_get_metrics (PangoFont *font, return pango_font_metrics_ref (info->metrics); } -static PangoCoverage * -pango_ft2_calc_coverage (PangoFont *font, - PangoLanguage *language) -{ - PangoCoverage *coverage; - FT_Face face; - - coverage = pango_coverage_new (); - face = pango_ft2_font_get_face (font); - -#ifdef HAVE_FT_GET_FIRST_CHAR - { - FT_UInt gindex; - FT_ULong charcode; - - charcode = FT_Get_First_Char (face, &gindex); - while (gindex) - { - pango_coverage_set (coverage, charcode, PANGO_COVERAGE_EXACT); - charcode = FT_Get_Next_Char (face, charcode, &gindex); - } - } -#else - /* Ugh, this is going to be SLOW */ - { - gunichar wc; - - for (wc = 0; wc < G_MAXUSHORT; wc++) - { - FT_UInt glyph = FT_Get_Char_Index (face, wc); - - if (glyph && glyph < face->num_glyphs) - pango_coverage_set (coverage, wc, PANGO_COVERAGE_EXACT); - } - } -#endif - - return coverage; -} - static void pango_ft2_font_dispose (GObject *object) { @@ -822,26 +782,8 @@ pango_ft2_font_get_coverage (PangoFont *font, PangoLanguage *language) { PangoFT2Font *ft2font = (PangoFT2Font *)font; - FcChar8 *filename = NULL; - FT_Face face; - PangoCoverage *coverage; - - FcPatternGetString (ft2font->font_pattern, FC_FILE, 0, &filename); - - coverage = _pango_ft2_font_map_get_coverage (ft2font->fontmap, filename); - - if (coverage) - return pango_coverage_ref (coverage); - /* Ugh, this is going to be SLOW */ - - face = pango_ft2_font_get_face (font); - - coverage = pango_ft2_calc_coverage (font, language); - - _pango_ft2_font_map_set_coverage (ft2font->fontmap, filename, coverage); - - return coverage; + return _pango_ft2_font_map_get_coverage (ft2font->fontmap, ft2font->font_pattern); } static PangoEngineShape * diff --git a/pango/pangoxft-font.c b/pango/pangoxft-font.c index 315e0795..bd388787 100644 --- a/pango/pangoxft-font.c +++ b/pango/pangoxft-font.c @@ -551,68 +551,8 @@ pango_xft_font_get_coverage (PangoFont *font, PangoLanguage *language) { PangoXftFont *xfont = (PangoXftFont *)font; - PangoXftCoverageKey key; - PangoCoverage *coverage; - Display *display; - FcChar32 map[FC_CHARSET_MAP_SIZE]; - FcChar32 ucs4, pos; - FcCharSet *charset; - int i; - - _pango_xft_font_map_get_info (xfont->fontmap, &display, NULL); - - /* - * 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 (xfont->font_pattern, FC_FILE, 0, (FcChar8 **) &key.filename) != FcResultMatch) - return NULL; - - if (FcPatternGetInteger (xfont->font_pattern, FC_INDEX, 0, &key.id) != FcResultMatch) - return NULL; - - coverage = _pango_xft_font_map_get_coverage (xfont->fontmap, &key); - - if (coverage) - return pango_coverage_ref (coverage); - - /* - * Pull the coverage out of the pattern, this - * doesn't require loading the font - */ - if (FcPatternGetCharSet (xfont->font_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_xft_font_map_set_coverage (xfont->fontmap, &key, coverage); - - return coverage; + return _pango_xft_font_map_get_coverage (xfont->fontmap, xfont->font_pattern); } static void diff --git a/pango/pangoxft-fontmap.c b/pango/pangoxft-fontmap.c index 05804e9e..a49cf797 100644 --- a/pango/pangoxft-fontmap.c +++ b/pango/pangoxft-fontmap.c @@ -29,13 +29,8 @@ /* For XExtSetCloseDisplay */ #include -/* Number of freed fonts */ -#define MAX_FREED_FONTS 128 - -typedef struct _PangoXftFontMap PangoXftFontMap; typedef struct _PangoXftFamily PangoXftFamily; -typedef struct _PangoXftFace PangoXftFace; -typedef struct _PangoXftPatternSet PangoXftPatternSet; +typedef struct _PangoXftFontMap PangoXftFontMap; #define PANGO_TYPE_XFT_FONT_MAP (pango_xft_font_map_get_type ()) #define PANGO_XFT_FONT_MAP(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), PANGO_TYPE_XFT_FONT_MAP, PangoXftFontMap)) @@ -60,6 +55,7 @@ struct _PangoXftFontMap Display *display; int screen; + guint closed : 1; /* Function to call on prepared patterns to do final * config tweaking. @@ -69,238 +65,34 @@ struct _PangoXftFontMap GDestroyNotify substitute_destroy; }; -#define PANGO_XFT_TYPE_FAMILY (pango_xft_family_get_type ()) -#define PANGO_XFT_FAMILY(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), PANGO_XFT_TYPE_FAMILY, PangoXftFamily)) -#define PANGO_XFT_IS_FAMILY(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), PANGO_XFT_TYPE_FAMILY)) - -struct _PangoXftFamily -{ - PangoFontFamily parent_instance; - - PangoXftFontMap *fontmap; - char *family_name; - - PangoXftFace **faces; - int n_faces; /* -1 == uninitialized */ -}; - -struct _PangoXftPatternSet -{ - int n_patterns; - FcPattern **patterns; -}; - -#define PANGO_XFT_TYPE_FACE (pango_xft_face_get_type ()) -#define PANGO_XFT_FACE(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), PANGO_XFT_TYPE_FACE, PangoXftFace)) -#define PANGO_XFT_IS_FACE(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), PANGO_XFT_TYPE_FACE)) - -struct _PangoXftFace -{ - PangoFontFace parent_instance; - - PangoXftFamily *family; - char *style; -}; +/************************************************************ + * Code shared with PangoFT2 * + ************************************************************/ -static GType pango_xft_font_map_get_type (void); -GType pango_xft_family_get_type (void); -GType pango_xft_face_get_type (void); +#define PangoFcFamily PangoXftFamily +#define _PangoFcFamily _PangoXftFamily +#define PangoFcFontMap PangoXftFontMap +#define PangoFcFont PangoXftFont -static void pango_xft_font_map_init (PangoXftFontMap *fontmap); -static void pango_xft_font_map_class_init (PangoFontMapClass *class); -static void pango_xft_font_map_finalize (GObject *object); -static PangoFont * pango_xft_font_map_load_font (PangoFontMap *fontmap, - PangoContext *context, - const PangoFontDescription *description); -static PangoFontset *pango_xft_font_map_load_fontset (PangoFontMap *fontmap, - PangoContext *context, - const PangoFontDescription *desc, - PangoLanguage *language); -static void pango_xft_font_map_list_families (PangoFontMap *fontmap, - PangoFontFamily ***families, - int *n_families); +#define PANGO_FC_FONT_MAP PANGO_XFT_FONT_MAP +#define pango_fc_font_map_get_type pango_xft_font_map_get_type +#define _pango_fc_font_map_add _pango_xft_font_map_add +#define _pango_fc_font_map_remove _pango_xft_font_map_remove +#define _pango_fc_font_map_cache_add _pango_xft_font_map_cache_add +#define _pango_fc_font_map_cache_remove _pango_xft_font_map_cache_remove +#define _pango_fc_font_map_get_coverage _pango_xft_font_map_get_coverage +#define _pango_fc_font_map_set_coverage _pango_xft_font_map_set_coverage +#define _pango_fc_font_desc_from_pattern _pango_xft_font_desc_from_pattern +#define _pango_fc_font_new _pango_xft_font_new -static void pango_xft_font_set_free (PangoXftPatternSet *font_set); +#define PANGO_FC_NAME "PangoXft" -static void pango_xft_font_map_cache_clear (PangoXftFontMap *xfontmap); -static void pango_xft_font_map_cache_remove (PangoFontMap *fontmap, - PangoXftFont *xfont); +#include "pangofc-fontmap.cI" -static PangoFontClass *parent_class; /* Parent class structure for PangoXftFontMap */ - -static GType -pango_xft_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_xft_font_map_class_init, - NULL, /* class_finalize */ - NULL, /* class_data */ - sizeof (PangoXftFontMap), - 0, /* n_preallocs */ - (GInstanceInitFunc) pango_xft_font_map_init, - }; - - object_type = g_type_register_static (PANGO_TYPE_FONT_MAP, - "PangoXftFontMap", - &object_info, 0); - } - - return object_type; -} - -static void -pango_xft_font_map_init (PangoXftFontMap *xfontmap) -{ - xfontmap->n_families = -1; -} - -static void -pango_xft_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_xft_font_map_finalize; - class->load_font = pango_xft_font_map_load_font; - class->load_fontset = pango_xft_font_map_load_fontset; - class->list_families = pango_xft_font_map_list_families; -} - -static GSList *fontmaps = NULL; - -guint -pango_xft_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 -} - -gboolean -pango_xft_pattern_equal (FcPattern *pattern1, - FcPattern *pattern2) -{ - if (pattern1 == pattern2) - return TRUE; - else - return FcPatternEqual (pattern1, pattern2); -} - -static guint -pango_xft_coverage_key_hash (PangoXftCoverageKey *key) -{ - return g_str_hash (key->filename) ^ key->id; -} - -static gboolean -pango_xft_coverage_key_equal (PangoXftCoverageKey *key1, - PangoXftCoverageKey *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_xft_get_fontset_hash (PangoXftFontMap *xfontmap, - 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 = xfontmap->fontset_hash_list; - while (tmp_list) - { - FontsetHashListNode *node = tmp_list->data; - if (node->language == language) - { - if (tmp_list != xfontmap->fontset_hash_list) - { - /* Put the found node at the beginning - */ - xfontmap->fontset_hash_list = g_list_remove_link (xfontmap->fontset_hash_list, tmp_list); - xfontmap->fontset_hash_list->prev = tmp_list; - tmp_list->next = xfontmap->fontset_hash_list; - xfontmap->fontset_hash_list = tmp_list; - } - - return node->fontset_hash; - } - - tmp_list = tmp_list->next; - } - - { - FontsetHashListNode *node = g_new (FontsetHashListNode, 1); - xfontmap->fontset_hash_list = g_list_prepend (xfontmap->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_xft_font_set_free); - node->language = language; - - return node->fontset_hash; - } -} - -static void -pango_xft_clear_fontset_hash_list (PangoXftFontMap *xfontmap) -{ - GList *tmp_list = xfontmap->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 (xfontmap->fontset_hash_list); - xfontmap->fontset_hash_list = NULL; -} +/************************************************************* + * Xft specific code * + *************************************************************/ static PangoFontMap * pango_xft_find_font_map (Display *display, @@ -311,11 +103,11 @@ pango_xft_find_font_map (Display *display, tmp_list = fontmaps; while (tmp_list) { - PangoXftFontMap *xfontmap = tmp_list->data; + PangoXftFontMap *xftfontmap = tmp_list->data; - if (xfontmap->display == display && - xfontmap->screen == screen) - return PANGO_FONT_MAP (xfontmap); + if (xftfontmap->display == display && + xftfontmap->screen == screen) + return PANGO_FONT_MAP (xftfontmap); tmp_list = tmp_list->next; } @@ -337,11 +129,11 @@ close_display_cb (Display *display, tmp_list = fontmaps; while (tmp_list) { - PangoXftFontMap *xfontmap = tmp_list->data; + PangoXftFontMap *xftfontmap = tmp_list->data; tmp_list = tmp_list->next; - if (xfontmap->display == display) - pango_xft_shutdown_display (display, xfontmap->screen); + if (xftfontmap->display == display) + pango_xft_shutdown_display (display, xftfontmap->screen); } registered_displays = g_slist_remove (registered_displays, display); @@ -384,7 +176,7 @@ pango_xft_get_font_map (Display *display, { static gboolean registered_modules = FALSE; PangoFontMap *fontmap; - PangoXftFontMap *xfontmap; + PangoXftFontMap *xftfontmap; g_return_val_if_fail (display != NULL, NULL); @@ -405,34 +197,25 @@ pango_xft_get_font_map (Display *display, if (fontmap) return fontmap; - xfontmap = (PangoXftFontMap *)g_object_new (PANGO_TYPE_XFT_FONT_MAP, NULL); + xftfontmap = (PangoXftFontMap *)g_object_new (PANGO_TYPE_XFT_FONT_MAP, NULL); - xfontmap->display = display; - xfontmap->screen = screen; - - xfontmap->fonts = g_hash_table_new ((GHashFunc)pango_xft_pattern_hash, - (GEqualFunc)pango_xft_pattern_equal); - - xfontmap->coverage_hash = g_hash_table_new_full ((GHashFunc)pango_xft_coverage_key_hash, - (GEqualFunc)pango_xft_coverage_key_equal, - (GDestroyNotify)g_free, - (GDestroyNotify)pango_coverage_unref); - xfontmap->freed_fonts = g_queue_new (); + xftfontmap->display = display; + xftfontmap->screen = screen; register_display (display); - fontmaps = g_slist_prepend (fontmaps, xfontmap); + fontmaps = g_slist_prepend (fontmaps, xftfontmap); - return PANGO_FONT_MAP (xfontmap); + return PANGO_FONT_MAP (xftfontmap); } static void cleanup_font (gpointer key, PangoXftFont *xfont, - PangoXftFontMap *xfontmap) + PangoXftFontMap *xftfontmap) { if (xfont->xft_font) - XftFontClose (xfontmap->display, xfont->xft_font); + XftFontClose (xftfontmap->display, xfont->xft_font); xfont->fontmap = NULL; } @@ -454,16 +237,17 @@ pango_xft_shutdown_display (Display *display, fontmap = pango_xft_find_font_map (display, screen); if (fontmap) { - PangoXftFontMap *xfontmap = PANGO_XFT_FONT_MAP (fontmap); + PangoXftFontMap *xftfontmap = PANGO_XFT_FONT_MAP (fontmap); fontmaps = g_slist_remove (fontmaps, fontmap); - pango_xft_font_map_cache_clear (xfontmap); + pango_fc_font_map_cache_clear (xftfontmap); - g_hash_table_foreach (xfontmap->fonts, (GHFunc)cleanup_font, fontmap); - g_hash_table_destroy (xfontmap->fonts); - xfontmap->fonts = NULL; + g_hash_table_foreach (xftfontmap->fonts, (GHFunc)cleanup_font, fontmap); + g_hash_table_destroy (xftfontmap->fonts); + xftfontmap->fonts = NULL; - xfontmap->display = NULL; + xftfontmap->display = NULL; + xftfontmap->closed = TRUE; g_object_unref (G_OBJECT (fontmap)); } } @@ -489,16 +273,16 @@ pango_xft_set_default_substitute (Display *display, gpointer data, GDestroyNotify notify) { - PangoXftFontMap *xfontmap = (PangoXftFontMap *)pango_xft_get_font_map (display, screen); + PangoXftFontMap *xftfontmap = (PangoXftFontMap *)pango_xft_get_font_map (display, screen); - if (xfontmap->substitute_destroy) - xfontmap->substitute_destroy (xfontmap->substitute_data); + if (xftfontmap->substitute_destroy) + xftfontmap->substitute_destroy (xftfontmap->substitute_data); - xfontmap->substitute_func = func; - xfontmap->substitute_data = data; - xfontmap->substitute_destroy = notify; + xftfontmap->substitute_func = func; + xftfontmap->substitute_data = data; + xftfontmap->substitute_destroy = notify; - pango_xft_clear_fontset_hash_list (xfontmap); + pango_fc_clear_fontset_hash_list (xftfontmap); } /** @@ -515,9 +299,22 @@ void pango_xft_substitute_changed (Display *display, int screen) { - PangoXftFontMap *xfontmap = (PangoXftFontMap *)pango_xft_get_font_map (display, screen); + PangoXftFontMap *xftfontmap = (PangoXftFontMap *)pango_xft_get_font_map (display, screen); - pango_xft_clear_fontset_hash_list (xfontmap); + pango_fc_clear_fontset_hash_list (xftfontmap); +} + +void +_pango_xft_font_map_get_info (PangoFontMap *fontmap, + Display **display, + int *screen) +{ + PangoXftFontMap *xftfontmap = PANGO_XFT_FONT_MAP (fontmap); + + if (display) + *display = xftfontmap->display; + if (screen) + *screen = xftfontmap->screen; } /** @@ -545,719 +342,16 @@ pango_xft_get_context (Display *display, } static void -pango_xft_font_map_finalize (GObject *object) -{ - PangoXftFontMap *xfontmap = PANGO_XFT_FONT_MAP (object); - - fontmaps = g_slist_remove (fontmaps, object); - - if (xfontmap->substitute_destroy) - xfontmap->substitute_destroy (xfontmap->substitute_data); - - pango_xft_font_map_cache_clear (xfontmap); - g_queue_free (xfontmap->freed_fonts); - pango_xft_clear_fontset_hash_list (xfontmap); - g_hash_table_destroy (xfontmap->coverage_hash); - - if (xfontmap->fonts) - g_hash_table_destroy (xfontmap->fonts); - - G_OBJECT_CLASS (parent_class)->finalize (object); -} - - -/* Add a mapping from xfont->font_pattern to xfont */ -void -_pango_xft_font_map_add (PangoFontMap *fontmap, - PangoXftFont *xfont) -{ - PangoXftFontMap *xfontmap = PANGO_XFT_FONT_MAP (fontmap); - - g_hash_table_insert (xfontmap->fonts, - xfont->font_pattern, - xfont); -} - -/* Remove mapping from xfont->font_pattern to xfont */ -void -_pango_xft_font_map_remove (PangoFontMap *fontmap, - PangoXftFont *xfont) -{ - PangoXftFontMap *xfontmap = PANGO_XFT_FONT_MAP (fontmap); - - g_hash_table_remove (xfontmap->fonts, - xfont->font_pattern); -} - -static PangoXftFamily * -create_family (PangoXftFontMap *xfontmap, - const char *family_name) -{ - PangoXftFamily *family = g_object_new (PANGO_XFT_TYPE_FAMILY, NULL); - family->fontmap = xfontmap; - 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_xft_font_map_list_families (PangoFontMap *fontmap, - PangoFontFamily ***families, - int *n_families) -{ - PangoXftFontMap *xfontmap = PANGO_XFT_FONT_MAP (fontmap); - FcFontSet *fontset; - int i; - int count; - - if (!xfontmap->display) - { - if (families) - *families = NULL; - if (n_families) - n_families = 0; - - return; - } - - if (xfontmap->n_families < 0) - { - fontset = XftListFonts (xfontmap->display, xfontmap->screen, - NULL, - FC_FAMILY, - NULL); - - xfontmap->families = g_new (PangoXftFamily *, 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)) - xfontmap->families[count++] = create_family (xfontmap, s); - } - - FcFontSetDestroy (fontset); - - xfontmap->families[count++] = create_family (xfontmap, "Sans"); - xfontmap->families[count++] = create_family (xfontmap, "Serif"); - xfontmap->families[count++] = create_family (xfontmap, "Monospace"); - - xfontmap->n_families = count; - } - - if (n_families) - *n_families = xfontmap->n_families; - - if (families) - *families = g_memdup (xfontmap->families, xfontmap->n_families * sizeof (PangoFontFamily *)); -} - -static int -pango_xft_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_xft_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_xft_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_xft_convert_slant (pango_style); - weight = pango_xft_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_xft_font_map_new_font (PangoFontMap *fontmap, - FcPattern *match) -{ - PangoXftFontMap *xfontmap = (PangoXftFontMap *)fontmap; - PangoXftFont *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 (!xfontmap->display) - return NULL; - - /* Look up cache */ - font = g_hash_table_lookup (xfontmap->fonts, match); - - if (font) - { - g_object_ref (font); - - /* Revive font from cache */ - if (font->in_cache) - pango_xft_font_map_cache_remove (fontmap, font); - - return (PangoFont *)font; - } - - FcPatternReference (match); - return (PangoFont *)_pango_xft_font_new (fontmap, match); -} - -static PangoXftPatternSet * -pango_xft_font_map_get_patterns (PangoFontMap *fontmap, - PangoContext *context, - const PangoFontDescription *desc, - PangoLanguage *language) -{ - PangoXftFontMap *xfontmap = (PangoXftFontMap *)fontmap; - FcPattern *pattern, *font_pattern; - FcResult res; - int f; - PangoXftPatternSet *patterns; - FcFontSet *font_patterns; - GHashTable *fontset_hash; - - if (!language && context) - language = pango_context_get_language (context); - - fontset_hash = pango_xft_get_fontset_hash (xfontmap, language); - patterns = g_hash_table_lookup (fontset_hash, desc); - - if (patterns == NULL) - { - pattern = pango_xft_make_pattern (desc); - if (language) - FcPatternAddString (pattern, FC_LANG, (FcChar8 *) pango_language_to_string (language)); - - FcConfigSubstitute (NULL, pattern, FcMatchPattern); - if (xfontmap->substitute_func) - xfontmap->substitute_func (pattern, xfontmap->substitute_data); - XftDefaultSubstitute (xfontmap->display, xfontmap->screen, pattern); - - font_patterns = FcFontSort (NULL, pattern, FcTrue, 0, &res); - - if (!font_patterns) - return NULL; - - patterns = g_new (PangoXftPatternSet, 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_xft_font_map_load_font (PangoFontMap *fontmap, - PangoContext *context, - const PangoFontDescription *description) -{ - PangoXftPatternSet *patterns = pango_xft_font_map_get_patterns (fontmap, context, description, NULL); - if (!patterns) - return NULL; - - if (patterns->n_patterns > 0) - return pango_xft_font_map_new_font (fontmap, patterns->patterns[0]); - - return NULL; -} - -static void -pango_xft_font_set_free (PangoXftPatternSet *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_xft_font_map_load_fontset (PangoFontMap *fontmap, - PangoContext *context, - const PangoFontDescription *desc, - PangoLanguage *language) -{ - PangoFontsetSimple *simple; - int i; - PangoXftPatternSet *patterns = pango_xft_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_xft_font_map_new_font (fontmap, patterns->patterns[i]); - if (font) - pango_fontset_simple_append (simple, font); - } - - return PANGO_FONTSET (simple); -} - - -void -_pango_xft_font_map_cache_add (PangoFontMap *fontmap, - PangoXftFont *xfont) -{ - PangoXftFontMap *xfontmap = PANGO_XFT_FONT_MAP (fontmap); - - g_object_ref (G_OBJECT (xfont)); - g_queue_push_head (xfontmap->freed_fonts, xfont); - xfont->in_cache = TRUE; - - if (xfontmap->freed_fonts->length > MAX_FREED_FONTS) - { - GObject *old_font = g_queue_pop_tail (xfontmap->freed_fonts); - g_object_unref (old_font); - } -} - -static void -pango_xft_font_map_cache_remove (PangoFontMap *fontmap, - PangoXftFont *xfont) -{ - PangoXftFontMap *xfontmap = PANGO_XFT_FONT_MAP (fontmap); - - GList *link = g_list_find (xfontmap->freed_fonts->head, xfont); - if (link == xfontmap->freed_fonts->tail) - { - xfontmap->freed_fonts->tail = xfontmap->freed_fonts->tail->prev; - if (xfontmap->freed_fonts->tail) - xfontmap->freed_fonts->tail->next = NULL; - } - - xfontmap->freed_fonts->head = g_list_delete_link (xfontmap->freed_fonts->head, link); - xfontmap->freed_fonts->length--; - xfont->in_cache = FALSE; - - g_object_unref (G_OBJECT (xfont)); -} - -static void -pango_xft_font_map_cache_clear (PangoXftFontMap *xfontmap) -{ - g_list_foreach (xfontmap->freed_fonts->head, (GFunc)g_object_unref, NULL); - g_list_free (xfontmap->freed_fonts->head); - xfontmap->freed_fonts->head = NULL; - xfontmap->freed_fonts->tail = NULL; - xfontmap->freed_fonts->length = 0; -} - -void -_pango_xft_font_map_set_coverage (PangoFontMap *fontmap, - const PangoXftCoverageKey *key, - PangoCoverage *coverage) -{ - PangoXftFontMap *xfontmap = PANGO_XFT_FONT_MAP (fontmap); - PangoXftCoverageKey *key_dup; - - key_dup = g_malloc (sizeof (PangoXftCoverageKey) + 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 (xfontmap->coverage_hash, - key_dup, pango_coverage_ref (coverage)); -} - -PangoCoverage * -_pango_xft_font_map_get_coverage (PangoFontMap *fontmap, - const PangoXftCoverageKey *key) -{ - PangoXftFontMap *xfontmap = PANGO_XFT_FONT_MAP (fontmap); - - return g_hash_table_lookup (xfontmap->coverage_hash, key); -} - -void -_pango_xft_font_map_get_info (PangoFontMap *fontmap, - Display **display, - int *screen) -{ - PangoXftFontMap *xfontmap = PANGO_XFT_FONT_MAP (fontmap); - - if (display) - *display = xfontmap->display; - if (screen) - *screen = xfontmap->screen; -} - - -/* - * PangoXftFace - */ - -PangoFontDescription * -_pango_xft_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 (PangoXftFamily *xfamily, - gboolean bold, - gboolean italic) -{ - PangoFontDescription *desc = pango_font_description_new (); - - pango_font_description_set_family (desc, xfamily->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_xft_face_describe (PangoFontFace *face) -{ - PangoXftFace *xface = PANGO_XFT_FACE (face); - PangoXftFamily *xfamily = xface->family; - PangoXftFontMap *xfontmap = xfamily->fontmap; - PangoFontDescription *desc = NULL; - FcResult res; - FcPattern *match_pattern; - FcPattern *result_pattern; - - if (is_alias_family (xfamily->family_name)) - { - if (strcmp (xface->style, "Regular") == 0) - return make_alias_description (xfamily, FALSE, FALSE); - else if (strcmp (xface->style, "Bold") == 0) - return make_alias_description (xfamily, TRUE, FALSE); - else if (strcmp (xface->style, "Italic") == 0) - return make_alias_description (xfamily, FALSE, TRUE); - else /* Bold Italic */ - return make_alias_description (xfamily, TRUE, TRUE); - } - - match_pattern = FcPatternBuild (NULL, - FC_FAMILY, FcTypeString, xfamily->family_name, - FC_STYLE, FcTypeString, xface->style, - NULL); - - g_assert (match_pattern); - - result_pattern = XftFontMatch (xfontmap->display, xfontmap->screen, match_pattern, &res); - if (result_pattern) - { - desc = _pango_xft_font_desc_from_pattern (result_pattern, FALSE); - FcPatternDestroy (result_pattern); - } - - FcPatternDestroy (match_pattern); - - return desc; -} - -static const char * -pango_xft_face_get_face_name (PangoFontFace *face) -{ - PangoXftFace *xface = PANGO_XFT_FACE (face); - - return xface->style; -} - -static void -pango_xft_face_class_init (PangoFontFaceClass *class) +pango_fc_do_finalize (PangoXftFontMap *fontmap) { - class->describe = pango_xft_face_describe; - class->get_face_name = pango_xft_face_get_face_name; -} - -GType -pango_xft_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_xft_face_class_init, - NULL, /* class_finalize */ - NULL, /* class_data */ - sizeof (PangoXftFace), - 0, /* n_preallocs */ - (GInstanceInitFunc) NULL, - }; - - object_type = g_type_register_static (PANGO_TYPE_FONT_FACE, - "PangoXftFace", - &object_info, 0); - } - - return object_type; -} - -/* - * PangoXFontFamily - */ -static PangoXftFace * -create_face (PangoXftFamily *xfamily, - const char *style) -{ - PangoXftFace *face = g_object_new (PANGO_XFT_TYPE_FACE, NULL); - face->style = g_strdup (style); - face->family = xfamily; - - return face; -} - -static void -pango_xft_family_list_faces (PangoFontFamily *family, - PangoFontFace ***faces, - int *n_faces) -{ - PangoXftFamily *xfamily = PANGO_XFT_FAMILY (family); - PangoXftFontMap *xfontmap = xfamily->fontmap; - - if (xfamily->n_faces < 0) - { - FcFontSet *fontset; - int i; - - if (is_alias_family (xfamily->family_name) || !xfontmap->display) - { - xfamily->n_faces = 4; - xfamily->faces = g_new (PangoXftFace *, xfamily->n_faces); - - i = 0; - xfamily->faces[i++] = create_face (xfamily, "Regular"); - xfamily->faces[i++] = create_face (xfamily, "Bold"); - xfamily->faces[i++] = create_face (xfamily, "Italic"); - xfamily->faces[i++] = create_face (xfamily, "Bold Italic"); - } - else - { - fontset = XftListFonts (xfontmap->display, xfontmap->screen, - FC_FAMILY, FcTypeString, xfamily->family_name, - NULL, - FC_STYLE, - NULL); - - xfamily->n_faces = fontset->nfont; - xfamily->faces = g_new (PangoXftFace *, xfamily->n_faces); - - for (i = 0; i < fontset->nfont; i++) - { - FcChar8 *s; - FcResult res; - - res = FcPatternGetString (fontset->fonts[i], FC_STYLE, 0, (FcChar8 **) &s); - if (res != FcResultMatch) - s = "Regular"; - - xfamily->faces[i] = create_face (xfamily, s); - } - - FcFontSetDestroy (fontset); - } - } - - if (n_faces) - *n_faces = xfamily->n_faces; - - if (faces) - *faces = g_memdup (xfamily->faces, xfamily->n_faces * sizeof (PangoFontFace *)); -} - -const char * -pango_xft_family_get_name (PangoFontFamily *family) -{ - PangoXftFamily *xfamily = PANGO_XFT_FAMILY (family); - - return xfamily->family_name; } static void -pango_xft_family_class_init (PangoFontFamilyClass *class) +pango_fc_default_substitute (PangoXftFontMap *fontmap, + FcPattern *pattern) { - class->list_faces = pango_xft_family_list_faces; - class->get_name = pango_xft_family_get_name; -} - -void -pango_xft_family_init (PangoXftFamily *xfamily) -{ - xfamily->n_faces = -1; -} - -GType -pango_xft_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_xft_family_class_init, - NULL, /* class_finalize */ - NULL, /* class_data */ - sizeof (PangoXftFamily), - 0, /* n_preallocs */ - (GInstanceInitFunc) pango_xft_family_init, - }; - - object_type = g_type_register_static (PANGO_TYPE_FONT_FAMILY, - "PangoXftFamily", - &object_info, 0); - } - - return object_type; + FcConfigSubstitute (NULL, pattern, FcMatchPattern); + if (fontmap->substitute_func) + fontmap->substitute_func (pattern, fontmap->substitute_data); + XftDefaultSubstitute (fontmap->display, fontmap->screen, pattern); } diff --git a/pango/pangoxft-private.h b/pango/pangoxft-private.h index 07dbad44..194c4f2b 100644 --- a/pango/pangoxft-private.h +++ b/pango/pangoxft-private.h @@ -28,7 +28,6 @@ G_BEGIN_DECLS typedef struct _PangoXftFont PangoXftFont; -typedef struct _PangoXftCoverageKey PangoXftCoverageKey; struct _PangoXftFont { @@ -49,12 +48,6 @@ struct _PangoXftFont gboolean in_cache; }; -struct _PangoXftCoverageKey -{ - char *filename; - int id; /* needed to handle TTC files with multiple faces */ -}; - PangoXftFont * _pango_xft_font_new (PangoFontMap *font, FcPattern *pattern); void _pango_xft_font_map_cache_add (PangoFontMap *fontmap, @@ -63,11 +56,8 @@ void _pango_xft_font_map_add (PangoFontMap *fo PangoXftFont *xfont); void _pango_xft_font_map_remove (PangoFontMap *fontmap, PangoXftFont *xfont); -void _pango_xft_font_map_set_coverage (PangoFontMap *fontmap, - const PangoXftCoverageKey *key, - PangoCoverage *coverage); PangoCoverage *_pango_xft_font_map_get_coverage (PangoFontMap *fontmap, - const PangoXftCoverageKey *key); + FcPattern *pattern); void _pango_xft_font_map_get_info (PangoFontMap *fontmap, Display **display, int *screen); -- cgit v1.2.1