diff options
author | Owen Taylor <otaylor@redhat.com> | 2000-05-28 00:38:05 +0000 |
---|---|---|
committer | Owen Taylor <otaylor@src.gnome.org> | 2000-05-28 00:38:05 +0000 |
commit | 1a23b2c124df6830bc8a8027bd8b38ccc2c75531 (patch) | |
tree | 36998ab8a3d8d1211d5eec8069a8d84c98a96041 /pango | |
parent | 62244f7210302bf7608c6130185c17d3d2e714e0 (diff) | |
download | pango-1a23b2c124df6830bc8a8027bd8b38ccc2c75531.tar.gz |
Add libgobject.
Sat May 27 20:36:56 2000 Owen Taylor <otaylor@redhat.com>
* pango/Makefile.am configure.in: Add libgobject.
* pango/pango-fontmap.[ch]: GObject'ify PangoFontMap.
(Pango now requires GLib-1.3 to compile)
* pango/pangox-fontmap.c pango/pangox-private.h: Break
the fontmap code in libpangox out into a separate file.
Tue May 23 10:32:25 2000 Owen Taylor <otaylor@redhat.com>
* pango/pango-layout.c (pango_layout_set_text): Allow -1 for
the length.
Diffstat (limited to 'pango')
-rw-r--r-- | pango/Makefile.am | 6 | ||||
-rw-r--r-- | pango/fonts.c | 131 | ||||
-rw-r--r-- | pango/pango-context.c | 2 | ||||
-rw-r--r-- | pango/pango-context.h | 1 | ||||
-rw-r--r-- | pango/pango-font.h | 40 | ||||
-rw-r--r-- | pango/pango-fontmap.c | 146 | ||||
-rw-r--r-- | pango/pango-fontmap.h | 80 | ||||
-rw-r--r-- | pango/pango-layout.c | 32 | ||||
-rw-r--r-- | pango/pango.h | 1 | ||||
-rw-r--r-- | pango/pangox-fontmap.c | 1387 | ||||
-rw-r--r-- | pango/pangox-private.h | 71 | ||||
-rw-r--r-- | pango/pangox.c | 1331 | ||||
-rw-r--r-- | pango/pangox.h | 5 |
13 files changed, 1732 insertions, 1501 deletions
diff --git a/pango/Makefile.am b/pango/Makefile.am index e9f663e6..74518397 100644 --- a/pango/Makefile.am +++ b/pango/Makefile.am @@ -16,6 +16,7 @@ libpango_la_SOURCES = \ pango-attributes.c \ pango-context.c \ pango-coverage.c \ + pango-fontmap.c \ pango-item.c \ pango-layout.c \ reorder-items.c \ @@ -24,13 +25,14 @@ libpango_la_SOURCES = \ utils.h libpangox_la_SOURCES = \ - pangox.c + pangox.c \ + pangox-fontmap.c # We use the -release flag for now until the API settles # down at which point we'll either use the GTK+ versioning # scheme or the standard libtool scheme. # -libpango_la_LDFLAGS = -release $(VERSION) +libpango_la_LDFLAGS = -release $(VERSION) $(GLIB_LIBS) libpangox_la_LDFLAGS = -release $(VERSION) libpangox_la_LIBADD = $(INCLUDED_MODULES) diff --git a/pango/fonts.c b/pango/fonts.c index ad6de117..bfe022fd 100644 --- a/pango/fonts.c +++ b/pango/fonts.c @@ -549,134 +549,3 @@ pango_font_get_metrics (PangoFont *font, font->klass->get_metrics (font, lang, metrics); } - -/** - * pango_font_map_init: - * @fontmap: a #PangoFontMap - * - * Initialize a #PangoFontMap structure. This should - * only be called from the "new" routine of code which - * is implementing a "subclass" of #PangoFontMap - */ -void -pango_font_map_init (PangoFontMap *fontmap) -{ - g_return_if_fail (fontmap != NULL); - - fontmap->ref_count = 1; -} - -/** - * pango_font_map_ref: - * @fontmap: a #PangoFontMap - * - * Increase the reference count of a #PangoFontMap. - */ -void -pango_font_map_ref (PangoFontMap *fontmap) -{ - g_return_if_fail (fontmap != NULL); - - fontmap->ref_count++; -} - - -/** - * pango_font_map_unref: - * @fontmap: a #PangoFontMap - * - * Decrease the reference count of a #PangoFontMap. - * if the result is zero, destroy the font - * and free the associated memory. - */ -void -pango_font_map_unref (PangoFontMap *fontmap) -{ - g_return_if_fail (fontmap != NULL); - g_return_if_fail (fontmap->ref_count > 0); - - fontmap->ref_count--; - if (fontmap->ref_count == 0) - fontmap->klass->destroy (fontmap); -} - -/** - * pango_font_map_load_font: - * @fontmap: a #PangoFontMap - * @desc: a #PangoFontDescription describing the font to load - * - * Load the font in the fontmap that is the closest match for @desc. - * - * Returns the font loaded, or %NULL if no font matched. - **/ -PangoFont * -pango_font_map_load_font (PangoFontMap *fontmap, - const PangoFontDescription *desc) -{ - g_return_val_if_fail (fontmap != NULL, NULL); - - return fontmap->klass->load_font (fontmap, desc); -} - -/** - * pango_font_map_list_fonts: - * @fontmap: a #PangoFontMap - * @family: the family for which to list the fonts, or %NULL - * to list fonts in all families. - * @descs: location to store a pointer to an array of pointers to - * #PangoFontDescription. This array should be freed - * with pango_font_descriptions_free(). - * @n_descs: location to store the number of elements in @descs - * - * List all fonts in a fontmap, or the fonts in a particular family. - **/ -void -pango_font_map_list_fonts (PangoFontMap *fontmap, - const char *family, - PangoFontDescription ***descs, - int *n_descs) -{ - g_return_if_fail (fontmap != NULL); - - fontmap->klass->list_fonts (fontmap, family, descs, n_descs); -} - -/** - * pango_font_map_list_families: - * @fontmap: a #PangoFontMap - * @families: location to store a pointer to an array of strings. - * This array should be freed with pango_font_map_free_families(). - * @n_families: location to store the number of elements in @descs - * - * List all families for a fontmap. - **/ -void -pango_font_map_list_families (PangoFontMap *fontmap, - gchar ***families, - int *n_families) -{ - g_return_if_fail (fontmap != NULL); - - fontmap->klass->list_families (fontmap, families, n_families); -} - -/** - * pango_font_map_free_families: - * @families: a list of families - * @n_families: number of elements in @families - * - * Free a list of families returned from pango_font_map_list_families() - **/ -void -pango_font_map_free_families (gchar **families, - int n_families) -{ - int i; - - g_return_if_fail (n_families == 0 || families != NULL); - - for (i=0; i<n_families; i++) - g_free (families[i]); - - g_free (families); -} diff --git a/pango/pango-context.c b/pango/pango-context.c index 9b1db987..60a54a7d 100644 --- a/pango/pango-context.c +++ b/pango/pango-context.c @@ -111,7 +111,7 @@ pango_context_unref (PangoContext *context) if (context->lang) g_free (context->lang); - g_slist_foreach (context->font_maps, (GFunc)pango_font_map_unref, NULL); + g_slist_foreach (context->font_maps, (GFunc)g_object_unref, NULL); g_slist_free (context->font_maps); } } diff --git a/pango/pango-context.h b/pango/pango-context.h index 26228b1c..5b5d663d 100644 --- a/pango/pango-context.h +++ b/pango/pango-context.h @@ -23,6 +23,7 @@ #define __PANGO_CONTEXT_H__ #include <pango/pango-font.h> +#include <pango/pango-fontmap.h> #include <pango/pango-attributes.h> #ifdef __cplusplus diff --git a/pango/pango-font.h b/pango/pango-font.h index 063b0cea..62d18e44 100644 --- a/pango/pango-font.h +++ b/pango/pango-font.h @@ -31,8 +31,6 @@ extern "C" { typedef struct _PangoFontDescription PangoFontDescription; typedef struct _PangoFontClass PangoFontClass; -typedef struct _PangoFontMap PangoFontMap; -typedef struct _PangoFontMapClass PangoFontMapClass; typedef struct _PangoFontMetrics PangoFontMetrics; typedef enum { @@ -150,44 +148,6 @@ void pango_font_get_glyph_extents (PangoFont *font, * Font Map */ -struct _PangoFontMap -{ - PangoFontMapClass *klass; - - /*< private >*/ - gint ref_count; -}; - -struct _PangoFontMapClass -{ - void (*destroy) (PangoFontMap *fontmap); - PangoFont *(*load_font) (PangoFontMap *fontmap, - const PangoFontDescription *desc); - void (*list_fonts) (PangoFontMap *fontmap, - const gchar *family, - PangoFontDescription ***descs, - int *n_descs); - void (*list_families) (PangoFontMap *fontmap, - gchar ***families, - int *n_families); -}; - -void pango_font_map_init (PangoFontMap *fontmap); -void pango_font_map_ref (PangoFontMap *fontmap); -void pango_font_map_unref (PangoFontMap *fontmap); -PangoFont *pango_font_map_load_font (PangoFontMap *fontmap, - const PangoFontDescription *desc); - -void pango_font_map_list_fonts (PangoFontMap *fontmap, - const gchar *family, - PangoFontDescription ***descs, - int *n_descs); -void pango_font_map_list_families (PangoFontMap *fontmap, - gchar ***families, - int *n_families); -void pango_font_map_free_families (gchar **families, - int n_families); - #ifdef __cplusplus } #endif /* __cplusplus */ diff --git a/pango/pango-fontmap.c b/pango/pango-fontmap.c new file mode 100644 index 00000000..c5cadec3 --- /dev/null +++ b/pango/pango-fontmap.c @@ -0,0 +1,146 @@ +/* Pango + * pango-font.h: Font handling + * + * Copyright (C) 2000 Red Hat Software + * + * 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. + */ + +#include "pango-fontmap.h" + +static void pango_font_map_init (PangoFontMap *fontmap); +static void pango_font_map_class_init (PangoFontMapClass *class); + +GType +pango_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_font_map_class_init, + NULL, /* class_finalize */ + NULL, /* class_data */ + sizeof (PangoFontMap), + 0, /* n_preallocs */ + (GInstanceInitFunc) pango_font_map_init, + }; + + object_type = g_type_register_static (G_TYPE_OBJECT, + "PangoFontMap", + &object_info); + } + + return object_type; +} + +static void +pango_font_map_init (PangoFontMap *fontmap) +{ +} + +static void +pango_font_map_class_init (PangoFontMapClass *class) +{ +} + +/** + * pango_font_map_load_font: + * @fontmap: a #PangoFontMap + * @desc: a #PangoFontDescription describing the font to load + * + * Load the font in the fontmap that is the closest match for @desc. + * + * Returns the font loaded, or %NULL if no font matched. + **/ +PangoFont * +pango_font_map_load_font (PangoFontMap *fontmap, + const PangoFontDescription *desc) +{ + g_return_val_if_fail (fontmap != NULL, NULL); + + return PANGO_FONT_MAP_GET_CLASS (fontmap)->load_font (fontmap, desc); +} + +/** + * pango_font_map_list_fonts: + * @fontmap: a #PangoFontMap + * @family: the family for which to list the fonts, or %NULL + * to list fonts in all families. + * @descs: location to store a pointer to an array of pointers to + * #PangoFontDescription. This array should be freed + * with pango_font_descriptions_free(). + * @n_descs: location to store the number of elements in @descs + * + * List all fonts in a fontmap, or the fonts in a particular family. + **/ +void +pango_font_map_list_fonts (PangoFontMap *fontmap, + const char *family, + PangoFontDescription ***descs, + int *n_descs) +{ + g_return_if_fail (fontmap != NULL); + + return PANGO_FONT_MAP_GET_CLASS (fontmap)->list_fonts (fontmap, family, descs, n_descs); +} + +/** + * pango_font_map_list_families: + * @fontmap: a #PangoFontMap + * @families: location to store a pointer to an array of strings. + * This array should be freed with pango_font_map_free_families(). + * @n_families: location to store the number of elements in @descs + * + * List all families for a fontmap. + **/ +void +pango_font_map_list_families (PangoFontMap *fontmap, + gchar ***families, + int *n_families) +{ + g_return_if_fail (fontmap != NULL); + + return PANGO_FONT_MAP_GET_CLASS (fontmap)->list_families (fontmap, families, n_families); +} + +/** + * pango_font_map_free_families: + * @families: a list of families + * @n_families: number of elements in @families + * + * Free a list of families returned from pango_font_map_list_families() + **/ +void +pango_font_map_free_families (gchar **families, + int n_families) +{ + int i; + + g_return_if_fail (n_families == 0 || families != NULL); + + for (i=0; i<n_families; i++) + g_free (families[i]); + + g_free (families); +} + + diff --git a/pango/pango-fontmap.h b/pango/pango-fontmap.h new file mode 100644 index 00000000..7fbe3785 --- /dev/null +++ b/pango/pango-fontmap.h @@ -0,0 +1,80 @@ +/* Pango + * pango-font.h: Font handling + * + * Copyright (C) 2000 Red Hat Software + * + * 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. + */ + +#ifndef __PANGO_FONTMAP_H__ +#define __PANGO_FONTMAP_H__ + +#include <pango/pango-font.h> +#include <glib-object.h> + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#define PANGO_TYPE_FONT_MAP (pango_font_map_get_type ()) +#define PANGO_FONT_MAP(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), PANGO_TYPE_FONT_MAP, PangoFontMap)) +#define PANGO_FONT_MAP_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PANGO_TYPE_FONT_MAP, PangoFontMapClass)) +#define PANGO_IS_FONT_MAP(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), PANGO_TYPE_FONT_MAP)) +#define PANGO_IS_FONT_MAP_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PANGO_TYPE_FONT_MAP)) +#define PANGO_FONT_MAP_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PANGO_TYPE_FONT_MAP, PangoFontMapClass)) + +typedef struct _PangoFontMap PangoFontMap; +typedef struct _PangoFontMapClass PangoFontMapClass; + +struct _PangoFontMap +{ + GObject parent_instance; +}; + +struct _PangoFontMapClass +{ + GObjectClass parent_class; + + void (*destroy) (PangoFontMap *fontmap); + PangoFont *(*load_font) (PangoFontMap *fontmap, + const PangoFontDescription *desc); + void (*list_fonts) (PangoFontMap *fontmap, + const gchar *family, + PangoFontDescription ***descs, + int *n_descs); + void (*list_families) (PangoFontMap *fontmap, + gchar ***families, + int *n_families); +}; + +GType pango_font_map_get_type (void); +PangoFont *pango_font_map_load_font (PangoFontMap *fontmap, + const PangoFontDescription *desc); +void pango_font_map_list_fonts (PangoFontMap *fontmap, + const gchar *family, + PangoFontDescription ***descs, + int *n_descs); +void pango_font_map_list_families (PangoFontMap *fontmap, + gchar ***families, + int *n_families); +void pango_font_map_free_families (gchar **families, + int n_families); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif __PANGO_FONTMAP_H__ diff --git a/pango/pango-layout.c b/pango/pango-layout.c index 08af0edc..9cfa39f8 100644 --- a/pango/pango-layout.c +++ b/pango/pango-layout.c @@ -377,7 +377,9 @@ pango_layout_get_alignment (PangoLayout *layout) * pango_layout_set_text: * @layout: a #PangoLayout * @text: a UTF8-string - * @length: the length of @text, in bytes. + * @length: the length of @text, in bytes. -1 indicates that + * the string is null terminated and the length should be + * calculated. * * Set the text of the layout. **/ @@ -392,22 +394,35 @@ pango_layout_set_text (PangoLayout *layout, if (layout->text) g_free (layout->text); - if (length > 0) + if (length == 0) + { + layout->text = g_strdup (""); + layout->n_chars = 0; + } + else { - int n_chars = unicode_strlen (text, length); unicode_char_t junk; char *p = text; - int i; + int n_chars = 0; - for (i=0; i<n_chars; i++) + while (*p && (length < 0 || p < text + length)) { p = unicode_get_utf8 (p, &junk); - if (!p || !junk) + if (!p) { g_warning ("Invalid UTF8 string passed to pango_layout_set_text()"); return; } + n_chars++; } + + if (length < 0) + length = p - text; + + if (length >= 0 && p != text + length) + g_warning ("string passed to pango_layout_set_text() contains embedded NULL"); + + length = p - text; /* NULL-terminate the text, since we currently use unicode_next_utf8() * in quite a few places, and for convenience. @@ -419,11 +434,6 @@ pango_layout_set_text (PangoLayout *layout, layout->n_chars = n_chars; } - else - { - layout->text = g_strdup (""); - layout->n_chars = 0; - } layout->length = length; diff --git a/pango/pango.h b/pango/pango.h index 3e7d1d5d..5d083b9f 100644 --- a/pango/pango.h +++ b/pango/pango.h @@ -33,6 +33,7 @@ extern "C" { #include <pango/pango-coverage.h> #include <pango/pango-engine.h> #include <pango/pango-font.h> +#include <pango/pango-fontmap.h> #include <pango/pango-glyph.h> #include <pango/pango-item.h> #include <pango/pango-layout.h> diff --git a/pango/pangox-fontmap.c b/pango/pangox-fontmap.c new file mode 100644 index 00000000..49cbfb06 --- /dev/null +++ b/pango/pangox-fontmap.c @@ -0,0 +1,1387 @@ +/* Pango + * pango-font.h: Font handling + * + * Copyright (C) 2000 Red Hat Software + * + * 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. + */ + +#include <ctype.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> + +#include "pango-fontmap.h" +#include "pangox-private.h" + +#define PANGO_TYPE_X_FONT_MAP (pango_x_font_map_get_type ()) +#define PANGO_X_FONT_MAP(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), PANGO_TYPE_X_FONT_MAP, PangoXFontMap)) +#define PANGO_X_FONT_MAP_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PANGO_TYPE_X_FONT_MAP, PangoXFontMapClass)) +#define PANGO_IS_X_FONT_MAP(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), PANGO_TYPE_X_FONT_MAP)) +#define PANGO_IS_X_FONT_MAP_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PANGO_TYPE_X_FONT_MAP)) +#define PANGO_X_FONT_MAP_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PANGO_TYPE_X_FONT_MAP, PangoXFontMapClass)) + +typedef struct _PangoXFamilyEntry PangoXFamilyEntry; +typedef struct _PangoXFontMap PangoXFontMap; +typedef struct _PangoXFontMapClass PangoXFontMapClass; +typedef struct _PangoXSizeInfo PangoXSizeInfo; + +/* This is the largest field length we will accept. If a fontname has a field + larger than this we will skip it. */ +#define XLFD_MAX_FIELD_LEN 64 +#define MAX_FONTS 32767 + +/* These are the field numbers in the X Logical Font Description fontnames, + e.g. -adobe-courier-bold-o-normal--25-180-100-100-m-150-iso8859-1 */ +typedef enum +{ + XLFD_FOUNDRY = 0, + XLFD_FAMILY = 1, + XLFD_WEIGHT = 2, + XLFD_SLANT = 3, + XLFD_SET_WIDTH = 4, + XLFD_ADD_STYLE = 5, + XLFD_PIXELS = 6, + XLFD_POINTS = 7, + XLFD_RESOLUTION_X = 8, + XLFD_RESOLUTION_Y = 9, + XLFD_SPACING = 10, + XLFD_AVERAGE_WIDTH = 11, + XLFD_CHARSET = 12, + XLFD_NUM_FIELDS +} FontField; + +struct _PangoXFontMap +{ + PangoFontMap parent_instance; + + Display *display; + + GHashTable *families; + GHashTable *size_infos; + + int n_fonts; + + double resolution; /* (points / pixel) * PANGO_SCALE */ +}; + +struct _PangoXFontMapClass +{ + PangoFontMapClass parent_class; +}; + +struct _PangoXFamilyEntry +{ + char *family_name; + GSList *font_entries; +}; + +struct _PangoXFontEntry +{ + char *xlfd; + PangoFontDescription description; + PangoCoverage *coverage; + + GSList *cached_fonts; +}; + +struct _PangoXSizeInfo +{ + char *identifier; + GSList *xlfds; +}; + +const struct { + const gchar *text; + PangoWeight value; +} weights_map[] = { + { "light", 300 }, + { "regular", 400 }, + { "book", 400 }, + { "medium", 500 }, + { "semibold", 600 }, + { "demibold", 600 }, + { "bold", 700 }, + { "extrabold", 800 }, + { "ultrabold", 800 }, + { "heavy", 900 }, + { "black", 900 } +}; + +const struct { + const gchar *text; + PangoStyle value; +} styles_map[] = { + { "r", PANGO_STYLE_NORMAL }, + { "i", PANGO_STYLE_ITALIC }, + { "o", PANGO_STYLE_OBLIQUE } +}; + +const struct { + const gchar *text; + PangoStretch value; +} stretches_map[] = { + { "normal", PANGO_STRETCH_NORMAL }, + { "semicondensed", PANGO_STRETCH_SEMI_CONDENSED }, + { "condensed", PANGO_STRETCH_CONDENSED }, +}; + +static GType pango_x_font_map_get_type (void); +static void pango_x_font_map_init (PangoXFontMap *fontmap); +static void pango_x_font_map_class_init (PangoXFontMapClass *class); + +static void pango_x_font_map_finalize (GObject *object); +static PangoFont *pango_x_font_map_load_font (PangoFontMap *fontmap, + const PangoFontDescription *description); +static void pango_x_font_map_list_fonts (PangoFontMap *fontmap, + const gchar *family, + PangoFontDescription ***descs, + int *n_descs); +static void pango_x_font_map_list_families (PangoFontMap *fontmap, + gchar ***families, + int *n_families); + +static void pango_x_font_map_read_aliases (PangoXFontMap *xfontmap); + +static gint pango_x_get_size (PangoXFontMap *fontmap, + const char *fontname); +static void pango_x_insert_font (PangoXFontMap *fontmap, + const char *fontname); +static gboolean pango_x_is_xlfd_font_name (const char *fontname); +static char * pango_x_get_xlfd_field (const char *fontname, + FontField field_num, + char *buffer); +static char * pango_x_get_identifier (const char *fontname); + +static GType +pango_x_font_map_get_type (void) +{ + static GType object_type = 0; + + if (!object_type) + { + static const GTypeInfo object_info = + { + sizeof (PangoXFontMapClass), + (GBaseInitFunc) NULL, + (GBaseFinalizeFunc) NULL, + (GClassInitFunc) pango_x_font_map_class_init, + NULL, /* class_finalize */ + NULL, /* class_data */ + sizeof (PangoXFontMap), + 0, /* n_preallocs */ + (GInstanceInitFunc) pango_x_font_map_init, + }; + + object_type = g_type_register_static (PANGO_TYPE_FONT_MAP, + "PangoXFontMap", + &object_info); + } + + return object_type; +} + +static void +pango_x_font_map_init (PangoXFontMap *xfontmap) +{ + xfontmap->families = g_hash_table_new (g_str_hash, g_str_equal); + xfontmap->size_infos = g_hash_table_new (g_str_hash, g_str_equal); + xfontmap->n_fonts = 0; +} + +static void +pango_x_font_map_class_init (PangoXFontMapClass *class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (class); + PangoFontMapClass *font_map_class = PANGO_FONT_MAP_CLASS (class); + + object_class->finalize = pango_x_font_map_finalize; + font_map_class->load_font = pango_x_font_map_load_font; + font_map_class->list_fonts = pango_x_font_map_list_fonts; + font_map_class->list_families = pango_x_font_map_list_families; +} + +static GList *fontmaps = NULL; + +PangoFontMap * +pango_x_font_map_for_display (Display *display) +{ + PangoXFontMap *xfontmap; + GList *tmp_list = fontmaps; + char **xfontnames; + int num_fonts, i; + int screen; + + /* Make sure that the type system is initialized */ + g_type_init(); + + while (tmp_list) + { + xfontmap = tmp_list->data; + + if (xfontmap->display == display) + { + g_object_ref (G_OBJECT (xfontmap)); + return PANGO_FONT_MAP (xfontmap); + } + } + + xfontmap = (PangoXFontMap *)g_type_create_instance (PANGO_TYPE_X_FONT_MAP); + + xfontmap->display = display; + + /* Get a maximum of MAX_FONTS fontnames from the X server. + Use "-*" as the pattern rather than "-*-*-*-*-*-*-*-*-*-*-*-*-*-*" since + the latter may result in fonts being returned which don't actually exist. + xlsfonts also uses "*" so I think it's OK. "-*" gets rid of aliases. */ + xfontnames = XListFonts (xfontmap->display, "-*", MAX_FONTS, &num_fonts); + if (num_fonts == MAX_FONTS) + g_warning("MAX_FONTS exceeded. Some fonts may be missing."); + + /* Insert the font families into the main table */ + for (i = 0; i < num_fonts; i++) + { + if (pango_x_is_xlfd_font_name (xfontnames[i])) + pango_x_insert_font (xfontmap, xfontnames[i]); + } + + XFreeFontNames (xfontnames); + + pango_x_font_map_read_aliases (xfontmap); + + fontmaps = g_list_prepend (fontmaps, xfontmap); + + /* This is a little screwed up, since different screens on the same display + * might have different resolutions + */ + screen = DefaultScreen (xfontmap->display); + xfontmap->resolution = (PANGO_SCALE * 72.27 / 25.4) * ((double) DisplayWidthMM (xfontmap->display, screen) / + DisplayWidth (xfontmap->display, screen)); + + g_object_ref (G_OBJECT (xfontmap)); + return PANGO_FONT_MAP (xfontmap); +} + +static void +pango_x_font_map_finalize (GObject *object) +{ + fontmaps = g_list_remove (fontmaps, object); +} + +typedef struct +{ + int n_found; + PangoFontDescription **descs; +} ListFontsInfo; + +static void +list_fonts_foreach (gpointer key, gpointer value, gpointer user_data) +{ + PangoXFamilyEntry *entry = value; + ListFontsInfo *info = user_data; + + GSList *tmp_list = entry->font_entries; + + while (tmp_list) + { + PangoXFontEntry *font_entry = tmp_list->data; + + info->descs[info->n_found++] = pango_font_description_copy (&font_entry->description); + tmp_list = tmp_list->next; + } +} + +static void +pango_x_font_map_list_fonts (PangoFontMap *fontmap, + const gchar *family, + PangoFontDescription ***descs, + int *n_descs) +{ + PangoXFontMap *xfontmap = (PangoXFontMap *)fontmap; + ListFontsInfo info; + + if (!n_descs) + return; + + if (family) + { + PangoXFamilyEntry *entry = g_hash_table_lookup (xfontmap->families, family); + if (entry) + { + *n_descs = g_slist_length (entry->font_entries); + if (descs) + { + *descs = g_new (PangoFontDescription *, *n_descs); + + info.descs = *descs; + info.n_found = 0; + + list_fonts_foreach ((gpointer)family, (gpointer)entry, &info); + } + } + else + { + *n_descs = 0; + if (descs) + *descs = NULL; + } + } + else + { + *n_descs = xfontmap->n_fonts; + if (descs) + { + *descs = g_new (PangoFontDescription *, xfontmap->n_fonts); + + info.descs = *descs; + info.n_found = 0; + + g_hash_table_foreach (xfontmap->families, list_fonts_foreach, &info); + } + } +} + +static void +list_families_foreach (gpointer key, gpointer value, gpointer user_data) +{ + GSList **list = user_data; + + *list = g_slist_prepend (*list, key); +} + +static void +pango_x_font_map_list_families (PangoFontMap *fontmap, + gchar ***families, + int *n_families) +{ + GSList *family_list = NULL; + GSList *tmp_list; + PangoXFontMap *xfontmap = (PangoXFontMap *)fontmap; + + if (!n_families) + return; + + g_hash_table_foreach (xfontmap->families, list_families_foreach, &family_list); + + *n_families = g_slist_length (family_list); + + if (families) + { + int i = 0; + + *families = g_new (gchar *, *n_families); + + tmp_list = family_list; + while (tmp_list) + { + (*families)[i] = g_strdup (tmp_list->data); + i++; + tmp_list = tmp_list->next; + } + } + + g_slist_free (family_list); +} + +static PangoXFamilyEntry * +pango_x_get_family_entry (PangoXFontMap *xfontmap, + const char *family_name) +{ + PangoXFamilyEntry *family_entry = g_hash_table_lookup (xfontmap->families, family_name); + if (!family_entry) + { + family_entry = g_new (PangoXFamilyEntry, 1); + family_entry->family_name = g_strdup (family_name); + family_entry->font_entries = NULL; + + g_hash_table_insert (xfontmap->families, family_entry->family_name, family_entry); + } + + return family_entry; +} + +static PangoFont * +pango_x_font_map_load_font (PangoFontMap *fontmap, + const PangoFontDescription *description) +{ + PangoXFontMap *xfontmap = (PangoXFontMap *)fontmap; + PangoXFamilyEntry *family_entry; + PangoFont *result = NULL; + GSList *tmp_list; + gchar *name; + + g_return_val_if_fail (description != NULL, NULL); + g_return_val_if_fail (description->size > 0, NULL); + + name = g_strdup (description->family_name); + g_strdown (name); + + family_entry = g_hash_table_lookup (xfontmap->families, name); + if (family_entry) + { + PangoXFontEntry *best_match = NULL; + + tmp_list = family_entry->font_entries; + while (tmp_list) + { + PangoXFontEntry *font_entry = tmp_list->data; + + if (font_entry->description.style == description->style && + font_entry->description.variant == description->variant && + font_entry->description.stretch == description->stretch) + { + int distance = abs(font_entry->description.weight - description->weight); + int old_distance = best_match ? abs(best_match->description.weight - description->weight) : G_MAXINT; + + if (distance < old_distance) + { + best_match = font_entry; + } + } + + tmp_list = tmp_list->next; + } + + if (best_match) + { + GSList *tmp_list = best_match->cached_fonts; + + while (tmp_list) + { + PangoXFont *xfont = tmp_list->data; + if (xfont->size == description->size) + { + result = (PangoFont *)xfont; + pango_font_ref (result); + break; + } + tmp_list = tmp_list->next; + } + + if (!result) + { + result = pango_x_load_font_with_size (xfontmap->display, best_match->xlfd, description->size); + ((PangoXFont *)result)->entry = best_match; + best_match->cached_fonts = g_slist_prepend (best_match->cached_fonts, result); + } + + /* HORRIBLE performance hack until some better caching scheme is arrived at + */ + if (result) + pango_font_ref (result); + } + } + + g_free (name); + return result; +} + +/* Similar to GNU libc's getline, but buffer is g_malloc'd */ +static size_t +pango_getline (char **lineptr, size_t *n, FILE *stream) +{ +#define EXPAND_CHUNK 16 + + int n_read = 0; + int result = -1; + + g_return_val_if_fail (lineptr != NULL, -1); + g_return_val_if_fail (n != NULL, -1); + g_return_val_if_fail (*lineptr != NULL || *n == 0, -1); + +#ifdef HAVE_FLOCKFILE + flockfile (stream); +#endif + + while (1) + { + int c; + +#ifdef HAVE_FLOCKFILE + c = getc_unlocked (stream); +#else + c = getc (stream); +#endif + + if (c == EOF) + { + if (n_read > 0) + { + result = n_read; + (*lineptr)[n_read] = '\0'; + } + break; + } + + if (n_read + 2 >= *n) + { + *n += EXPAND_CHUNK; + *lineptr = g_realloc (*lineptr, *n); + } + + (*lineptr)[n_read] = c; + n_read++; + + if (c == '\n' || c == '\r') + { + result = n_read; + (*lineptr)[n_read] = '\0'; + break; + } + } + +#ifdef HAVE_FLOCKFILE + funlockfile (stream); +#endif + + return n_read - 1; +} + +static int +find_tok (char **start, char **tok) +{ + char *p = *start; + + while (*p && (*p == ' ' || *p == '\t')) + p++; + + if (*p == 0 || *p == '\n' || *p == '\r') + return -1; + + if (*p == '"') + { + p++; + *tok = p; + + while (*p && *p != '"') + p++; + + if (*p != '"') + return -1; + + *start = p + 1; + return p - *tok; + } + else + { + *tok = p; + + while (*p && *p != ' ' && *p != '\t' && *p != '\r' && *p != '\n') + p++; + + *start = p; + return p - *tok; + } +} + +static gboolean +get_style (char *tok, int toksize, PangoFontDescription *desc) +{ + if (toksize == 0) + return FALSE; + + switch (tok[0]) + { + case 'n': + case 'N': + if (strncasecmp (tok, "normal", toksize) == 0) + { + desc->style = PANGO_STYLE_NORMAL; + return TRUE; + } + break; + case 'i': + if (strncasecmp (tok, "italic", toksize) == 0) + { + desc->style = PANGO_STYLE_ITALIC; + return TRUE; + } + break; + case 'o': + if (strncasecmp (tok, "oblique", toksize) == 0) + { + desc->style = PANGO_STYLE_OBLIQUE; + return TRUE; + } + break; + } + g_warning ("Style must be normal, italic, or oblique"); + + return FALSE; +} + +static gboolean +get_variant (char *tok, int toksize, PangoFontDescription *desc) +{ + if (toksize == 0) + return FALSE; + + switch (tok[0]) + { + case 'n': + case 'N': + if (strncasecmp (tok, "normal", toksize) == 0) + { + desc->variant = PANGO_VARIANT_NORMAL; + return TRUE; + } + break; + case 's': + case 'S': + if (strncasecmp (tok, "small_caps", toksize) == 0) + { + desc->variant = PANGO_VARIANT_SMALL_CAPS; + return TRUE; + } + break; + } + + g_warning ("Variant must be normal, or small_caps"); + return FALSE; +} + +static gboolean +get_weight (char *tok, int toksize, PangoFontDescription *desc) +{ + if (toksize == 0) + return FALSE; + + switch (tok[0]) + { + case 'n': + case 'N': + if (strncasecmp (tok, "normal", toksize) == 0) + { + desc->weight = PANGO_WEIGHT_NORMAL; + return TRUE; + } + break; + case 'b': + case 'B': + if (strncasecmp (tok, "bold", toksize) == 0) + { + desc->weight = PANGO_WEIGHT_BOLD; + return TRUE; + } + break; + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + { + char *numstr, *end; + + numstr = g_strndup (tok, toksize); + + desc->weight = strtol (numstr, &end, 0); + if (*end != '\0') + { + g_warning ("Cannot parse numerical weight '%s'", numstr); + g_free (numstr); + return FALSE; + } + + g_free (numstr); + return TRUE; + } + } + + g_warning ("Weight must be normal, bold, or an integer"); + return FALSE; +} + +static gboolean +get_stretch (char *tok, int toksize, PangoFontDescription *desc) +{ + if (toksize == 0) + return FALSE; + + switch (tok[0]) + { + case 'c': + case 'C': + if (strncasecmp (tok, "condensed", toksize) == 0) + { + desc->stretch = PANGO_STRETCH_CONDENSED; + return TRUE; + } + break; + case 'e': + case 'E': + if (strncasecmp (tok, "extra_condensed", toksize) == 0) + { + desc->stretch = PANGO_STRETCH_EXTRA_CONDENSED; + return TRUE; + } + if (strncasecmp (tok, "extra_expanded", toksize) == 0) + { + desc->stretch = PANGO_STRETCH_EXTRA_EXPANDED; + return TRUE; + } + if (strncasecmp (tok, "expanded", toksize) == 0) + { + desc->stretch = PANGO_STRETCH_EXPANDED; + return TRUE; + } + break; + case 'n': + case 'N': + if (strncasecmp (tok, "normal", toksize) == 0) + { + desc->stretch = PANGO_STRETCH_NORMAL; + return TRUE; + } + break; + case 's': + case 'S': + if (strncasecmp (tok, "semi_condensed", toksize) == 0) + { + desc->stretch = PANGO_STRETCH_SEMI_CONDENSED; + return TRUE; + } + if (strncasecmp (tok, "semi_expanded", toksize) == 0) + { + desc->stretch = PANGO_STRETCH_SEMI_EXPANDED; + return TRUE; + } + break; + case 'u': + case 'U': + if (strncasecmp (tok, "ultra_condensed", toksize) == 0) + { + desc->stretch = PANGO_STRETCH_ULTRA_CONDENSED; + return TRUE; + } + if (strncasecmp (tok, "ultra_expanded", toksize) == 0) + { + desc->variant = PANGO_STRETCH_ULTRA_EXPANDED; + return TRUE; + } + break; + } + + g_warning ("Stretch must be ultra_condensed, extra_condensed, condensed, semi_condensed, normal, semi_expanded, expanded, extra_expanded, or ultra_expanded"); + return FALSE; +} + +static void +pango_x_font_map_read_alias_file (PangoXFontMap *xfontmap, + const char *filename) +{ + FILE *infile; + char **xlfds; + char *buf = NULL; + size_t bufsize = 0; + int lineno = 0; + int i; + PangoXFontEntry *font_entry = NULL; + + infile = fopen (filename, "r"); + if (infile) + { + while (pango_getline (&buf, &bufsize, infile) != EOF) + { + PangoXFamilyEntry *family_entry; + + char *tok; + char *p = buf; + + int toksize; + lineno++; + + while (*p && (*p == ' ' || *p == '\t')) + p++; + + if (*p == 0 || *p == '#' || *p == '\n' || *p == '\r') + continue; + + toksize = find_tok (&p, &tok); + if (toksize == -1) + goto error; + + font_entry = g_new (PangoXFontEntry, 1); + font_entry->xlfd = NULL; + font_entry->description.family_name = g_strndup (tok, toksize); + g_strdown (font_entry->description.family_name); + + toksize = find_tok (&p, &tok); + if (toksize == -1) + goto error; + + if (!get_style (tok, toksize, &font_entry->description)) + goto error; + + toksize = find_tok (&p, &tok); + if (toksize == -1) + goto error; + + if (!get_variant (tok, toksize, &font_entry->description)) + goto error; + + toksize = find_tok (&p, &tok); + if (toksize == -1) + goto error; + + if (!get_weight (tok, toksize, &font_entry->description)) + goto error; + + toksize = find_tok (&p, &tok); + if (toksize == -1) + goto error; + + if (!get_stretch (tok, toksize, &font_entry->description)) + goto error; + + toksize = find_tok (&p, &tok); + if (toksize == -1) + goto error; + + font_entry->xlfd = g_strndup (tok, toksize); + + /* Check for complete fields */ + + xlfds = g_strsplit (font_entry->xlfd, ",", -1); + for (i=0; xlfds[i]; i++) + if (!pango_x_is_xlfd_font_name (xlfds[i])) + { + g_warning ("XLFD '%s' must be complete (14 fields)", xlfds[i]); + g_strfreev (xlfds); + goto error; + } + + g_strfreev (xlfds); + + + /* Insert the font entry into our structures */ + + family_entry = pango_x_get_family_entry (xfontmap, font_entry->description.family_name); + family_entry->font_entries = g_slist_prepend (family_entry->font_entries, font_entry); + xfontmap->n_fonts++; + + g_free (font_entry->description.family_name); + font_entry->description.family_name = family_entry->family_name; + font_entry->cached_fonts = NULL; + font_entry->coverage = NULL; + } + + if (ferror (infile)) + g_warning ("Error reading '%s': %s", filename, g_strerror(errno)); + + goto out; + + error: + if (font_entry) + { + if (font_entry->xlfd) + g_free (font_entry->xlfd); + if (font_entry->description.family_name) + g_free (font_entry->description.family_name); + g_free (font_entry); + } + + g_warning ("Error parsing line %d of alias file '%s'", lineno, filename); + + out: + g_free (buf); + fclose (infile); + return; + } + +} + +static void +pango_x_font_map_read_aliases (PangoXFontMap *xfontmap) +{ + char *filename; + + pango_x_font_map_read_alias_file (xfontmap, SYSCONFDIR "/pango/pangox_aliases"); + + filename = g_strconcat (g_get_home_dir(), "/.pangox_aliases", NULL); + pango_x_font_map_read_alias_file (xfontmap, filename); + g_free (filename); + + /* FIXME: Remove this one */ + pango_x_font_map_read_alias_file (xfontmap, "pangox_aliases"); +} + +/* + * Returns TRUE if the fontname is a valid XLFD. + * (It just checks if the number of dashes is 14, and that each + * field < XLFD_MAX_FIELD_LEN characters long - that's not in the XLFD but it + * makes it easier for me). + */ +static gboolean +pango_x_is_xlfd_font_name (const char *fontname) +{ + int i = 0; + int field_len = 0; + + while (*fontname) + { + if (*fontname++ == '-') + { + if (field_len > XLFD_MAX_FIELD_LEN) return FALSE; + field_len = 0; + i++; + } + else + field_len++; + } + + return (i == 14) ? TRUE : FALSE; +} + +static int +pango_x_get_size (PangoXFontMap *xfontmap, const char *fontname) +{ + char size_buffer[XLFD_MAX_FIELD_LEN]; + int size; + + if (!pango_x_get_xlfd_field (fontname, XLFD_PIXELS, size_buffer)) + return -1; + + size = atoi (size_buffer); + if (size != 0) + { + return (int)(0.5 + size * xfontmap->resolution); + } + else + { + /* We use the trick that scaled bitmaps have a non-zero RESOLUTION_X, while + * actual scaleable fonts have a zero RESOLUTION_X */ + if (!pango_x_get_xlfd_field (fontname, XLFD_RESOLUTION_X, size_buffer)) + return -1; + + if (atoi (size_buffer) == 0) + return 0; + else + return -1; + } +} + +static char * +pango_x_get_identifier (const char *fontname) +{ + const char *p = fontname; + const char *start; + int n_dashes = 0; + + while (n_dashes < 2) + { + if (*p == '-') + n_dashes++; + p++; + } + + start = p; + + while (n_dashes < 6) + { + if (*p == '-') + n_dashes++; + p++; + } + + return g_strndup (start, (p - 1 - start)); +} + +/* + * This fills the buffer with the specified field from the X Logical Font + * Description name, and returns it. If fontname is NULL or the field is + * longer than XFLD_MAX_FIELD_LEN it returns NULL. + * Note: For the charset field, we also return the encoding, e.g. 'iso8859-1'. + */ +static char* +pango_x_get_xlfd_field (const char *fontname, + FontField field_num, + char *buffer) +{ + const char *t1, *t2; + int countdown, len, num_dashes; + + if (!fontname) + return NULL; + + /* we assume this is a valid fontname...that is, it has 14 fields */ + + countdown = field_num; + t1 = fontname; + while (*t1 && (countdown >= 0)) + if (*t1++ == '-') + countdown--; + + num_dashes = (field_num == XLFD_CHARSET) ? 2 : 1; + for (t2 = t1; *t2; t2++) + { + if (*t2 == '-' && --num_dashes == 0) + break; + } + + if (t1 != t2) + { + /* Check we don't overflow the buffer */ + len = (long) t2 - (long) t1; + if (len > XLFD_MAX_FIELD_LEN - 1) + return NULL; + strncpy (buffer, t1, len); + buffer[len] = 0; + /* Convert to lower case. */ + g_strdown (buffer); + } + else + strcpy(buffer, "(nil)"); + + return buffer; +} + +/* This inserts the given fontname into the FontInfo table. + If a FontInfo already exists with the same family and foundry, then the + fontname is added to the FontInfos list of fontnames, else a new FontInfo + is created and inserted in alphabetical order in the table. */ +static void +pango_x_insert_font (PangoXFontMap *xfontmap, + const char *fontname) +{ + PangoFontDescription description; + char family_buffer[XLFD_MAX_FIELD_LEN]; + char weight_buffer[XLFD_MAX_FIELD_LEN]; + char slant_buffer[XLFD_MAX_FIELD_LEN]; + char set_width_buffer[XLFD_MAX_FIELD_LEN]; + GSList *tmp_list; + PangoXFamilyEntry *family_entry; + PangoXFontEntry *font_entry; + PangoXSizeInfo *size_info; + char *identifier; + int i; + + description.size = 0; + + /* First insert the XLFD into the list of XLFDs for the "identifier" - which + * is the 2-4th fields of the XLFD + */ + identifier = pango_x_get_identifier (fontname); + size_info = g_hash_table_lookup (xfontmap->size_infos, identifier); + if (!size_info) + { + size_info = g_new (PangoXSizeInfo, 1); + size_info->identifier = identifier; + size_info->xlfds = NULL; + + g_hash_table_insert (xfontmap->size_infos, identifier, size_info); + } + else + g_free (identifier); + + size_info->xlfds = g_slist_prepend (size_info->xlfds, g_strdup (fontname)); + + /* Convert the XLFD into a PangoFontDescription */ + + description.family_name = pango_x_get_xlfd_field (fontname, XLFD_FAMILY, family_buffer); + g_strdown (description.family_name); + + if (!description.family_name) + return; + + description.style = PANGO_STYLE_NORMAL; + if (pango_x_get_xlfd_field (fontname, XLFD_SLANT, slant_buffer)) + { + for (i=0; i<G_N_ELEMENTS(styles_map); i++) + { + if (!strcmp (styles_map[i].text, slant_buffer)) + { + description.style = styles_map[i].value; + break; + } + } + } + else + strcpy (slant_buffer, "*"); + + description.variant = PANGO_VARIANT_NORMAL; + + description.weight = PANGO_WEIGHT_NORMAL; + if (pango_x_get_xlfd_field (fontname, XLFD_WEIGHT, weight_buffer)) + { + for (i=0; i<G_N_ELEMENTS(weights_map); i++) + { + if (!strcmp (weights_map[i].text, weight_buffer)) + { + description.weight = weights_map[i].value; + break; + } + } + } + else + strcpy (weight_buffer, "*"); + + description.stretch = PANGO_STRETCH_NORMAL; + if (pango_x_get_xlfd_field (fontname, XLFD_SET_WIDTH, set_width_buffer)) + { + for (i=0; i<G_N_ELEMENTS(stretches_map); i++) + { + if (!strcmp (stretches_map[i].text, set_width_buffer)) + { + description.stretch = stretches_map[i].value; + break; + } + } + } + else + strcpy (set_width_buffer, "*"); + + family_entry = pango_x_get_family_entry (xfontmap, description.family_name); + + tmp_list = family_entry->font_entries; + while (tmp_list) + { + font_entry = tmp_list->data; + + if (font_entry->description.style == description.style && + font_entry->description.variant == description.variant && + font_entry->description.weight == description.weight && + font_entry->description.stretch == description.stretch) + return; + + tmp_list = tmp_list->next; + } + + font_entry = g_new (PangoXFontEntry, 1); + font_entry->description = description; + font_entry->description.family_name = family_entry->family_name; + font_entry->cached_fonts = NULL; + font_entry->coverage = NULL; + + font_entry->xlfd = g_strconcat ("-*-", + family_buffer, + "-", + weight_buffer, + "-", + slant_buffer, + "-", + set_width_buffer, + "--*-*-*-*-*-*-*-*", + NULL); + + family_entry->font_entries = g_slist_append (family_entry->font_entries, font_entry); + xfontmap->n_fonts++; +} + +/* Compare the tail of a to b */ +static gboolean +match_end (char *a, char *b) +{ + size_t len_a = strlen (a); + size_t len_b = strlen (b); + + if (len_b > len_a) + return FALSE; + else + return (strcmp (a + len_a - len_b, b) == 0); +} + +/* Given a xlfd, charset and size, find the best matching installed X font. + * The XLFD must be a full XLFD (14 fields) + */ +char * +pango_x_make_matching_xlfd (PangoFontMap *fontmap, char *xlfd, const char *charset, int size) +{ + PangoXFontMap *xfontmap; + + GSList *tmp_list; + PangoXSizeInfo *size_info; + char *identifier; + char *closest_match = NULL; + gint match_distance = 0; + gboolean match_scaleable = FALSE; + char *result = NULL; + + char *dash_charset; + + xfontmap = PANGO_X_FONT_MAP (fontmap); + + dash_charset = g_strconcat ("-", charset, NULL); + + if (!match_end (xlfd, "-*-*") && !match_end (xlfd, dash_charset)) + { + g_free (dash_charset); + return NULL; + } + + identifier = pango_x_get_identifier (xlfd); + size_info = g_hash_table_lookup (xfontmap->size_infos, identifier); + g_free (identifier); + + if (!size_info) + { + g_free (dash_charset); + return NULL; + } + + tmp_list = size_info->xlfds; + while (tmp_list) + { + char *tmp_xlfd = tmp_list->data; + + if (match_end (tmp_xlfd, dash_charset)) + { + int font_size = pango_x_get_size (xfontmap, tmp_xlfd); + + if (size != -1) + { + int new_distance = (font_size == 0) ? 0 : abs (font_size - size); + + if (!closest_match || + new_distance < match_distance || + (new_distance < PANGO_SCALE && match_scaleable && font_size != 0)) + { + closest_match = tmp_xlfd; + match_scaleable = (font_size == 0); + match_distance = new_distance; + } + } + } + + tmp_list = tmp_list->next; + } + + if (closest_match) + { + if (match_scaleable) + { + char *prefix_end, *p; + char *size_end; + int n_dashes = 0; + int target_size; + char *prefix; + + /* OK, we have a match; let's modify it to fit this size and charset */ + + p = closest_match; + while (n_dashes < 6) + { + if (*p == '-') + n_dashes++; + p++; + } + + prefix_end = p - 1; + + while (n_dashes < 9) + { + if (*p == '-') + n_dashes++; + p++; + } + + size_end = p - 1; + + target_size = (int)((double)size / xfontmap->resolution + 0.5); + prefix = g_strndup (closest_match, prefix_end - closest_match); + result = g_strdup_printf ("%s--%d-*-*-*-*-*-%s", prefix, target_size, charset); + g_free (prefix); + } + else + { + result = g_strdup (closest_match); + } + } + + g_free (dash_charset); + + return result; +} + +static void +free_coverages_foreach (gpointer key, + gpointer value, + gpointer data) +{ + pango_coverage_unref (value); +} + +PangoCoverage * +pango_x_font_entry_get_coverage (PangoXFontEntry *entry, + PangoFont *font, + const char *lang) +{ + guint32 ch; + PangoMap *shape_map; + PangoCoverage *coverage; + PangoCoverage *result; + PangoCoverageLevel font_level; + PangoMapEntry *map_entry; + GHashTable *coverage_hash; + + if (entry) + if (entry->coverage) + { + pango_coverage_ref (entry->coverage); + return entry->coverage; + } + + result = pango_coverage_new (); + + coverage_hash = g_hash_table_new (g_str_hash, g_str_equal); + + shape_map = pango_x_get_shaper_map (lang); + + for (ch = 0; ch < 65536; ch++) + { + map_entry = _pango_map_get_entry (shape_map, ch); + if (map_entry->info) + { + coverage = g_hash_table_lookup (coverage_hash, map_entry->info->id); + if (!coverage) + { + PangoEngineShape *engine = (PangoEngineShape *)_pango_map_get_engine (shape_map, ch); + coverage = engine->get_coverage (font, lang); + g_hash_table_insert (coverage_hash, map_entry->info->id, coverage); + } + + font_level = pango_coverage_get (coverage, ch); + if (font_level == PANGO_COVERAGE_EXACT && !map_entry->is_exact) + font_level = PANGO_COVERAGE_APPROXIMATE; + + if (font_level != PANGO_COVERAGE_NONE) + pango_coverage_set (result, ch, font_level); + } + } + + g_hash_table_foreach (coverage_hash, free_coverages_foreach, NULL); + g_hash_table_destroy (coverage_hash); + + if (entry) + { + entry->coverage = result; + pango_coverage_ref (result); + } + + return result; +} + +void +pango_x_font_entry_remove (PangoXFontEntry *entry, + PangoFont *font) +{ + entry->cached_fonts = g_slist_remove (entry->cached_fonts, font); +} diff --git a/pango/pangox-private.h b/pango/pangox-private.h new file mode 100644 index 00000000..345213d5 --- /dev/null +++ b/pango/pangox-private.h @@ -0,0 +1,71 @@ +/* Pango + * pangox-private.h: + * + * Copyright (C) 1999 Red Hat Software + * + * 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. + */ + +#ifndef __PANGOX_PRIVATE_H__ +#define __PANGOX_PRIVATE_H__ + +#include "modules.h" +#include "pangox.h" +#include "pangox-private.h" + +typedef struct _PangoXFont PangoXFont; +typedef struct _PangoXFontEntry PangoXFontEntry; +typedef struct _PangoXSubfontInfo PangoXSubfontInfo; + +struct _PangoXFont +{ + PangoFont font; + Display *display; + + char **fonts; + int n_fonts; + int size; + + /* hash table mapping from charset-name to array of PangoXSubfont ids, + * of length n_fonts + */ + GHashTable *subfonts_by_charset; + + PangoXSubfontInfo **subfonts; + + int n_subfonts; + int max_subfonts; + + GSList *metrics_by_lang; + + PangoXFontEntry *entry; /* Used to remove cached fonts */ +}; + +PangoFont * pango_x_load_font_with_size (Display *display, + char *spec, + int size); +PangoMap * pango_x_get_shaper_map (const char *lang); +char * pango_x_make_matching_xlfd (PangoFontMap *fontmap, + char *xlfd, + const char *charset, + int size); +PangoCoverage *pango_x_font_entry_get_coverage (PangoXFontEntry *entry, + PangoFont *font, + const char *lang); +void pango_x_font_entry_remove (PangoXFontEntry *entry, + PangoFont *font); + +#endif /* __PANGOX_PRIVATE_H__ */ diff --git a/pango/pangox.c b/pango/pangox.c index d45989bf..407aa574 100644 --- a/pango/pangox.c +++ b/pango/pangox.c @@ -19,53 +19,23 @@ * Boston, MA 02111-1307, USA. */ +#include <string.h> +#include <math.h> + #include <X11/Xlib.h> #include <fribidi/fribidi.h> #include <unicode.h> -#include "modules.h" #include "pangox.h" +#include "pangox-private.h" + #include "utils.h" -#include <ctype.h> -#include <math.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <errno.h> #include <config.h> -typedef struct _PangoXFont PangoXFont; -typedef struct _PangoXFontMap PangoXFontMap; -typedef struct _PangoXSubfontInfo PangoXSubfontInfo; - -typedef struct _PangoXSizeInfo PangoXSizeInfo; typedef struct _PangoXMetricsInfo PangoXMetricsInfo; -typedef struct _PangoXFamilyEntry PangoXFamilyEntry; -typedef struct _PangoXFontEntry PangoXFontEntry; typedef struct _PangoXContextInfo PangoXContextInfo; -struct _PangoXSizeInfo -{ - char *identifier; - GSList *xlfds; -}; - -struct _PangoXFontEntry -{ - char *xlfd; - PangoFontDescription description; - PangoCoverage *coverage; - - GSList *cached_fonts; -}; - -struct _PangoXFamilyEntry -{ - char *family_name; - GSList *font_entries; -}; - struct _PangoXSubfontInfo { char *xlfd; @@ -81,122 +51,12 @@ struct _PangoXMetricsInfo PangoFontMetrics metrics; }; -struct _PangoXFont -{ - PangoFont font; - Display *display; - - char **fonts; - int n_fonts; - int size; - - /* hash table mapping from charset-name to array of PangoXSubfont ids, - * of length n_fonts - */ - GHashTable *subfonts_by_charset; - - PangoXSubfontInfo **subfonts; - - int n_subfonts; - int max_subfonts; - - GSList *metrics_by_lang; - - PangoXFontEntry *entry; /* Used to remove cached fonts */ -}; - -struct _PangoXFontMap -{ - PangoFontMap fontmap; - - Display *display; - - GHashTable *families; - GHashTable *size_infos; - - int n_fonts; - - double resolution; /* (points / pixel) * PANGO_SCALE */ -}; - struct _PangoXContextInfo { PangoGetGCFunc get_gc_func; PangoFreeGCFunc free_gc_func; }; -/* This is the largest field length we will accept. If a fontname has a field - larger than this we will skip it. */ -#define XLFD_MAX_FIELD_LEN 64 -#define MAX_FONTS 32767 - -/* These are the field numbers in the X Logical Font Description fontnames, - e.g. -adobe-courier-bold-o-normal--25-180-100-100-m-150-iso8859-1 */ -typedef enum -{ - XLFD_FOUNDRY = 0, - XLFD_FAMILY = 1, - XLFD_WEIGHT = 2, - XLFD_SLANT = 3, - XLFD_SET_WIDTH = 4, - XLFD_ADD_STYLE = 5, - XLFD_PIXELS = 6, - XLFD_POINTS = 7, - XLFD_RESOLUTION_X = 8, - XLFD_RESOLUTION_Y = 9, - XLFD_SPACING = 10, - XLFD_AVERAGE_WIDTH = 11, - XLFD_CHARSET = 12, - XLFD_NUM_FIELDS -} FontField; - -const struct { - const gchar *text; - PangoWeight value; -} weights_map[] = { - { "light", 300 }, - { "regular", 400 }, - { "book", 400 }, - { "medium", 500 }, - { "semibold", 600 }, - { "demibold", 600 }, - { "bold", 700 }, - { "extrabold", 800 }, - { "ultrabold", 800 }, - { "heavy", 900 }, - { "black", 900 } -}; - -const struct { - const gchar *text; - PangoStyle value; -} styles_map[] = { - { "r", PANGO_STYLE_NORMAL }, - { "i", PANGO_STYLE_ITALIC }, - { "o", PANGO_STYLE_OBLIQUE } -}; - -const struct { - const gchar *text; - PangoStretch value; -} stretches_map[] = { - { "normal", PANGO_STRETCH_NORMAL }, - { "semicondensed", PANGO_STRETCH_SEMI_CONDENSED }, - { "condensed", PANGO_STRETCH_CONDENSED }, -}; - -static void pango_x_font_map_destroy (PangoFontMap *fontmap); -static PangoFont *pango_x_font_map_load_font (PangoFontMap *fontmap, - const PangoFontDescription *desc); -static void pango_x_font_map_list_fonts (PangoFontMap *fontmap, - const gchar *family, - PangoFontDescription ***descs, - int *n_descs); -static void pango_x_font_map_list_families (PangoFontMap *fontmap, - gchar ***families, - int *n_families); -static void pango_x_font_map_read_aliases (PangoXFontMap *xfontmap); - static void pango_x_font_destroy (PangoFont *font); static PangoFontDescription *pango_x_font_describe (PangoFont *font); static PangoCoverage * pango_x_font_get_coverage (PangoFont *font, @@ -224,19 +84,6 @@ static gboolean pango_x_find_glyph (PangoFont *font, static XFontStruct * pango_x_get_font_struct (PangoFont *font, PangoXSubfontInfo *info); -static PangoFont *pango_x_load_font_with_size (Display *display, - char *spec, - int size); - -static gboolean pango_x_is_xlfd_font_name (const char *fontname); -static char * pango_x_get_xlfd_field (const char *fontname, - FontField field_num, - char *buffer); -static char * pango_x_get_identifier (const char *fontname); -static gint pango_x_get_size (PangoXFontMap *fontmap, - const char *fontname); -static void pango_x_insert_font (PangoXFontMap *fontmap, - const char *fontname); static void pango_x_get_item_properties (PangoItem *item, PangoUnderline *uline, PangoAttrColor *fg_color, @@ -244,8 +91,6 @@ static void pango_x_get_item_properties (PangoItem *item, PangoAttrColor *bg_color, gboolean *bg_set); -static GList *fontmaps; - PangoFontClass pango_x_font_class = { pango_x_font_destroy, pango_x_font_describe, @@ -255,13 +100,6 @@ PangoFontClass pango_x_font_class = { pango_x_font_get_metrics }; -PangoFontMapClass pango_x_font_map_class = { - pango_x_font_map_destroy, - pango_x_font_map_load_font, - pango_x_font_map_list_fonts, - pango_x_font_map_list_families -}; - static inline PangoXSubfontInfo * pango_x_find_subfont (PangoFont *font, PangoXSubfont subfont_index) @@ -300,981 +138,6 @@ pango_x_get_font_struct (PangoFont *font, PangoXSubfontInfo *info) return info->font_struct; } -static PangoFontMap * -pango_x_font_map_for_display (Display *display) -{ - PangoXFontMap *xfontmap; - GList *tmp_list = fontmaps; - char **xfontnames; - int num_fonts, i; - int screen; - - while (tmp_list) - { - xfontmap = tmp_list->data; - - if (xfontmap->display == display) - { - pango_font_map_ref ((PangoFontMap *)xfontmap); - return (PangoFontMap *)xfontmap; - } - } - - xfontmap = g_new (PangoXFontMap, 1); - - xfontmap->fontmap.klass = &pango_x_font_map_class; - xfontmap->display = display; - xfontmap->families = g_hash_table_new (g_str_hash, g_str_equal); - xfontmap->size_infos = g_hash_table_new (g_str_hash, g_str_equal); - xfontmap->n_fonts = 0; - - pango_font_map_init ((PangoFontMap *)xfontmap); - - /* Get a maximum of MAX_FONTS fontnames from the X server. - Use "-*" as the pattern rather than "-*-*-*-*-*-*-*-*-*-*-*-*-*-*" since - the latter may result in fonts being returned which don't actually exist. - xlsfonts also uses "*" so I think it's OK. "-*" gets rid of aliases. */ - xfontnames = XListFonts (xfontmap->display, "-*", MAX_FONTS, &num_fonts); - if (num_fonts == MAX_FONTS) - g_warning("MAX_FONTS exceeded. Some fonts may be missing."); - - /* Insert the font families into the main table */ - for (i = 0; i < num_fonts; i++) - { - if (pango_x_is_xlfd_font_name (xfontnames[i])) - pango_x_insert_font (xfontmap, xfontnames[i]); - } - - XFreeFontNames (xfontnames); - - pango_x_font_map_read_aliases (xfontmap); - - fontmaps = g_list_prepend (fontmaps, xfontmap); - - /* This is a little screwed up, since different screens on the same display - * might have different resolutions - */ - screen = DefaultScreen (xfontmap->display); - xfontmap->resolution = (PANGO_SCALE * 72.27 / 25.4) * ((double) DisplayWidthMM (xfontmap->display, screen) / - DisplayWidth (xfontmap->display, screen)); - - return (PangoFontMap *)xfontmap; -} - -static void -pango_x_font_map_destroy (PangoFontMap *fontmap) -{ - fontmaps = g_list_remove (fontmaps, fontmap); - - g_free (fontmap); -} - -static PangoXFamilyEntry * -pango_x_get_family_entry (PangoXFontMap *xfontmap, - const char *family_name) -{ - PangoXFamilyEntry *family_entry = g_hash_table_lookup (xfontmap->families, family_name); - if (!family_entry) - { - family_entry = g_new (PangoXFamilyEntry, 1); - family_entry->family_name = g_strdup (family_name); - family_entry->font_entries = NULL; - - g_hash_table_insert (xfontmap->families, family_entry->family_name, family_entry); - } - - return family_entry; -} - -static PangoFont * -pango_x_font_map_load_font (PangoFontMap *fontmap, - const PangoFontDescription *description) -{ - PangoXFontMap *xfontmap = (PangoXFontMap *)fontmap; - PangoXFamilyEntry *family_entry; - PangoFont *result = NULL; - GSList *tmp_list; - gchar *name; - - g_return_val_if_fail (description != NULL, NULL); - g_return_val_if_fail (description->size > 0, NULL); - - name = g_strdup (description->family_name); - g_strdown (name); - - family_entry = g_hash_table_lookup (xfontmap->families, name); - if (family_entry) - { - PangoXFontEntry *best_match = NULL; - - tmp_list = family_entry->font_entries; - while (tmp_list) - { - PangoXFontEntry *font_entry = tmp_list->data; - - if (font_entry->description.style == description->style && - font_entry->description.variant == description->variant && - font_entry->description.stretch == description->stretch) - { - int distance = abs(font_entry->description.weight - description->weight); - int old_distance = best_match ? abs(best_match->description.weight - description->weight) : G_MAXINT; - - if (distance < old_distance) - { - best_match = font_entry; - } - } - - tmp_list = tmp_list->next; - } - - if (best_match) - { - GSList *tmp_list = best_match->cached_fonts; - - while (tmp_list) - { - PangoXFont *xfont = tmp_list->data; - if (xfont->size == description->size) - { - result = (PangoFont *)xfont; - pango_font_ref (result); - break; - } - tmp_list = tmp_list->next; - } - - if (!result) - { - result = pango_x_load_font_with_size (xfontmap->display, best_match->xlfd, description->size); - ((PangoXFont *)result)->entry = best_match; - best_match->cached_fonts = g_slist_prepend (best_match->cached_fonts, result); - } - - /* HORRIBLE performance hack until some better caching scheme is arrived at - */ - if (result) - pango_font_ref (result); - } - } - - g_free (name); - return result; -} - -typedef struct -{ - int n_found; - PangoFontDescription **descs; -} ListFontsInfo; - -static void -list_fonts_foreach (gpointer key, gpointer value, gpointer user_data) -{ - PangoXFamilyEntry *entry = value; - ListFontsInfo *info = user_data; - - GSList *tmp_list = entry->font_entries; - - while (tmp_list) - { - PangoXFontEntry *font_entry = tmp_list->data; - - info->descs[info->n_found++] = pango_font_description_copy (&font_entry->description); - tmp_list = tmp_list->next; - } -} - -static void -pango_x_font_map_list_fonts (PangoFontMap *fontmap, - const gchar *family, - PangoFontDescription ***descs, - int *n_descs) -{ - PangoXFontMap *xfontmap = (PangoXFontMap *)fontmap; - ListFontsInfo info; - - if (!n_descs) - return; - - if (family) - { - PangoXFamilyEntry *entry = g_hash_table_lookup (xfontmap->families, family); - if (entry) - { - *n_descs = g_slist_length (entry->font_entries); - if (descs) - { - *descs = g_new (PangoFontDescription *, *n_descs); - - info.descs = *descs; - info.n_found = 0; - - list_fonts_foreach ((gpointer)family, (gpointer)entry, &info); - } - } - else - { - *n_descs = 0; - if (descs) - *descs = NULL; - } - } - else - { - *n_descs = xfontmap->n_fonts; - if (descs) - { - *descs = g_new (PangoFontDescription *, xfontmap->n_fonts); - - info.descs = *descs; - info.n_found = 0; - - g_hash_table_foreach (xfontmap->families, list_fonts_foreach, &info); - } - } -} - -static void -list_families_foreach (gpointer key, gpointer value, gpointer user_data) -{ - GSList **list = user_data; - - *list = g_slist_prepend (*list, key); -} - -static void -pango_x_font_map_list_families (PangoFontMap *fontmap, - gchar ***families, - int *n_families) -{ - GSList *family_list = NULL; - GSList *tmp_list; - PangoXFontMap *xfontmap = (PangoXFontMap *)fontmap; - - if (!n_families) - return; - - g_hash_table_foreach (xfontmap->families, list_families_foreach, &family_list); - - *n_families = g_slist_length (family_list); - - if (families) - { - int i = 0; - - *families = g_new (gchar *, *n_families); - - tmp_list = family_list; - while (tmp_list) - { - (*families)[i] = g_strdup (tmp_list->data); - i++; - tmp_list = tmp_list->next; - } - } - - g_slist_free (family_list); -} - -/* Similar to GNU libc's getline, but buffer is g_malloc'd */ -static size_t -pango_getline (char **lineptr, size_t *n, FILE *stream) -{ -#define EXPAND_CHUNK 16 - - int n_read = 0; - int result = -1; - - g_return_val_if_fail (lineptr != NULL, -1); - g_return_val_if_fail (n != NULL, -1); - g_return_val_if_fail (*lineptr != NULL || *n == 0, -1); - -#ifdef HAVE_FLOCKFILE - flockfile (stream); -#endif - - while (1) - { - int c; - -#ifdef HAVE_FLOCKFILE - c = getc_unlocked (stream); -#else - c = getc (stream); -#endif - - if (c == EOF) - { - if (n_read > 0) - { - result = n_read; - (*lineptr)[n_read] = '\0'; - } - break; - } - - if (n_read + 2 >= *n) - { - *n += EXPAND_CHUNK; - *lineptr = g_realloc (*lineptr, *n); - } - - (*lineptr)[n_read] = c; - n_read++; - - if (c == '\n' || c == '\r') - { - result = n_read; - (*lineptr)[n_read] = '\0'; - break; - } - } - -#ifdef HAVE_FLOCKFILE - funlockfile (stream); -#endif - - return n_read - 1; -} - -static int -find_tok (char **start, char **tok) -{ - char *p = *start; - - while (*p && (*p == ' ' || *p == '\t')) - p++; - - if (*p == 0 || *p == '\n' || *p == '\r') - return -1; - - if (*p == '"') - { - p++; - *tok = p; - - while (*p && *p != '"') - p++; - - if (*p != '"') - return -1; - - *start = p + 1; - return p - *tok; - } - else - { - *tok = p; - - while (*p && *p != ' ' && *p != '\t' && *p != '\r' && *p != '\n') - p++; - - *start = p; - return p - *tok; - } -} - -static gboolean -get_style (char *tok, int toksize, PangoFontDescription *desc) -{ - if (toksize == 0) - return FALSE; - - switch (tok[0]) - { - case 'n': - case 'N': - if (strncasecmp (tok, "normal", toksize) == 0) - { - desc->style = PANGO_STYLE_NORMAL; - return TRUE; - } - break; - case 'i': - if (strncasecmp (tok, "italic", toksize) == 0) - { - desc->style = PANGO_STYLE_ITALIC; - return TRUE; - } - break; - case 'o': - if (strncasecmp (tok, "oblique", toksize) == 0) - { - desc->style = PANGO_STYLE_OBLIQUE; - return TRUE; - } - break; - } - g_warning ("Style must be normal, italic, or oblique"); - - return FALSE; -} - -static gboolean -get_variant (char *tok, int toksize, PangoFontDescription *desc) -{ - if (toksize == 0) - return FALSE; - - switch (tok[0]) - { - case 'n': - case 'N': - if (strncasecmp (tok, "normal", toksize) == 0) - { - desc->variant = PANGO_VARIANT_NORMAL; - return TRUE; - } - break; - case 's': - case 'S': - if (strncasecmp (tok, "small_caps", toksize) == 0) - { - desc->variant = PANGO_VARIANT_SMALL_CAPS; - return TRUE; - } - break; - } - - g_warning ("Variant must be normal, or small_caps"); - return FALSE; -} - -static gboolean -get_weight (char *tok, int toksize, PangoFontDescription *desc) -{ - if (toksize == 0) - return FALSE; - - switch (tok[0]) - { - case 'n': - case 'N': - if (strncasecmp (tok, "normal", toksize) == 0) - { - desc->weight = PANGO_WEIGHT_NORMAL; - return TRUE; - } - break; - case 'b': - case 'B': - if (strncasecmp (tok, "bold", toksize) == 0) - { - desc->weight = PANGO_WEIGHT_BOLD; - return TRUE; - } - break; - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - { - char *numstr, *end; - - numstr = g_strndup (tok, toksize); - - desc->weight = strtol (numstr, &end, 0); - if (*end != '\0') - { - g_warning ("Cannot parse numerical weight '%s'", numstr); - g_free (numstr); - return FALSE; - } - - g_free (numstr); - return TRUE; - } - } - - g_warning ("Weight must be normal, bold, or an integer"); - return FALSE; -} - -static gboolean -get_stretch (char *tok, int toksize, PangoFontDescription *desc) -{ - if (toksize == 0) - return FALSE; - - switch (tok[0]) - { - case 'c': - case 'C': - if (strncasecmp (tok, "condensed", toksize) == 0) - { - desc->stretch = PANGO_STRETCH_CONDENSED; - return TRUE; - } - break; - case 'e': - case 'E': - if (strncasecmp (tok, "extra_condensed", toksize) == 0) - { - desc->stretch = PANGO_STRETCH_EXTRA_CONDENSED; - return TRUE; - } - if (strncasecmp (tok, "extra_expanded", toksize) == 0) - { - desc->stretch = PANGO_STRETCH_EXTRA_EXPANDED; - return TRUE; - } - if (strncasecmp (tok, "expanded", toksize) == 0) - { - desc->stretch = PANGO_STRETCH_EXPANDED; - return TRUE; - } - break; - case 'n': - case 'N': - if (strncasecmp (tok, "normal", toksize) == 0) - { - desc->stretch = PANGO_STRETCH_NORMAL; - return TRUE; - } - break; - case 's': - case 'S': - if (strncasecmp (tok, "semi_condensed", toksize) == 0) - { - desc->stretch = PANGO_STRETCH_SEMI_CONDENSED; - return TRUE; - } - if (strncasecmp (tok, "semi_expanded", toksize) == 0) - { - desc->stretch = PANGO_STRETCH_SEMI_EXPANDED; - return TRUE; - } - break; - case 'u': - case 'U': - if (strncasecmp (tok, "ultra_condensed", toksize) == 0) - { - desc->stretch = PANGO_STRETCH_ULTRA_CONDENSED; - return TRUE; - } - if (strncasecmp (tok, "ultra_expanded", toksize) == 0) - { - desc->variant = PANGO_STRETCH_ULTRA_EXPANDED; - return TRUE; - } - break; - } - - g_warning ("Stretch must be ultra_condensed, extra_condensed, condensed, semi_condensed, normal, semi_expanded, expanded, extra_expanded, or ultra_expanded"); - return FALSE; -} - -static void -pango_x_font_map_read_alias_file (PangoXFontMap *xfontmap, - const char *filename) -{ - FILE *infile; - char **xlfds; - char *buf = NULL; - size_t bufsize = 0; - int lineno = 0; - int i; - PangoXFontEntry *font_entry = NULL; - - infile = fopen (filename, "r"); - if (infile) - { - while (pango_getline (&buf, &bufsize, infile) != EOF) - { - PangoXFamilyEntry *family_entry; - - char *tok; - char *p = buf; - - int toksize; - lineno++; - - while (*p && (*p == ' ' || *p == '\t')) - p++; - - if (*p == 0 || *p == '#' || *p == '\n' || *p == '\r') - continue; - - toksize = find_tok (&p, &tok); - if (toksize == -1) - goto error; - - font_entry = g_new (PangoXFontEntry, 1); - font_entry->xlfd = NULL; - font_entry->description.family_name = g_strndup (tok, toksize); - g_strdown (font_entry->description.family_name); - - toksize = find_tok (&p, &tok); - if (toksize == -1) - goto error; - - if (!get_style (tok, toksize, &font_entry->description)) - goto error; - - toksize = find_tok (&p, &tok); - if (toksize == -1) - goto error; - - if (!get_variant (tok, toksize, &font_entry->description)) - goto error; - - toksize = find_tok (&p, &tok); - if (toksize == -1) - goto error; - - if (!get_weight (tok, toksize, &font_entry->description)) - goto error; - - toksize = find_tok (&p, &tok); - if (toksize == -1) - goto error; - - if (!get_stretch (tok, toksize, &font_entry->description)) - goto error; - - toksize = find_tok (&p, &tok); - if (toksize == -1) - goto error; - - font_entry->xlfd = g_strndup (tok, toksize); - - /* Check for complete fields */ - - xlfds = g_strsplit (font_entry->xlfd, ",", -1); - for (i=0; xlfds[i]; i++) - if (!pango_x_is_xlfd_font_name (xlfds[i])) - { - g_warning ("XLFD '%s' must be complete (14 fields)", xlfds[i]); - g_strfreev (xlfds); - goto error; - } - - g_strfreev (xlfds); - - - /* Insert the font entry into our structures */ - - family_entry = pango_x_get_family_entry (xfontmap, font_entry->description.family_name); - family_entry->font_entries = g_slist_prepend (family_entry->font_entries, font_entry); - xfontmap->n_fonts++; - - g_free (font_entry->description.family_name); - font_entry->description.family_name = family_entry->family_name; - font_entry->cached_fonts = NULL; - font_entry->coverage = NULL; - } - - if (ferror (infile)) - g_warning ("Error reading '%s': %s", filename, g_strerror(errno)); - - goto out; - - error: - if (font_entry) - { - if (font_entry->xlfd) - g_free (font_entry->xlfd); - if (font_entry->description.family_name) - g_free (font_entry->description.family_name); - g_free (font_entry); - } - - g_warning ("Error parsing line %d of alias file '%s'", lineno, filename); - - out: - g_free (buf); - fclose (infile); - return; - } - -} - -static void -pango_x_font_map_read_aliases (PangoXFontMap *xfontmap) -{ - char *filename; - - pango_x_font_map_read_alias_file (xfontmap, SYSCONFDIR "/pango/pangox_aliases"); - - filename = g_strconcat (g_get_home_dir(), "/.pangox_aliases", NULL); - pango_x_font_map_read_alias_file (xfontmap, filename); - g_free (filename); - - /* FIXME: Remove this one */ - pango_x_font_map_read_alias_file (xfontmap, "pangox_aliases"); -} - - -/* - * Returns TRUE if the fontname is a valid XLFD. - * (It just checks if the number of dashes is 14, and that each - * field < XLFD_MAX_FIELD_LEN characters long - that's not in the XLFD but it - * makes it easier for me). - */ -static gboolean -pango_x_is_xlfd_font_name (const char *fontname) -{ - int i = 0; - int field_len = 0; - - while (*fontname) - { - if (*fontname++ == '-') - { - if (field_len > XLFD_MAX_FIELD_LEN) return FALSE; - field_len = 0; - i++; - } - else - field_len++; - } - - return (i == 14) ? TRUE : FALSE; -} - -static int -pango_x_get_size (PangoXFontMap *xfontmap, const char *fontname) -{ - char size_buffer[XLFD_MAX_FIELD_LEN]; - int size; - - if (!pango_x_get_xlfd_field (fontname, XLFD_PIXELS, size_buffer)) - return -1; - - size = atoi (size_buffer); - if (size != 0) - { - return (int)(0.5 + size * xfontmap->resolution); - } - else - { - /* We use the trick that scaled bitmaps have a non-zero RESOLUTION_X, while - * actual scaleable fonts have a zero RESOLUTION_X */ - if (!pango_x_get_xlfd_field (fontname, XLFD_RESOLUTION_X, size_buffer)) - return -1; - - if (atoi (size_buffer) == 0) - return 0; - else - return -1; - } -} - -static char * -pango_x_get_identifier (const char *fontname) -{ - const char *p = fontname; - const char *start; - int n_dashes = 0; - - while (n_dashes < 2) - { - if (*p == '-') - n_dashes++; - p++; - } - - start = p; - - while (n_dashes < 6) - { - if (*p == '-') - n_dashes++; - p++; - } - - return g_strndup (start, (p - 1 - start)); -} - -/* - * This fills the buffer with the specified field from the X Logical Font - * Description name, and returns it. If fontname is NULL or the field is - * longer than XFLD_MAX_FIELD_LEN it returns NULL. - * Note: For the charset field, we also return the encoding, e.g. 'iso8859-1'. - */ -static char* -pango_x_get_xlfd_field (const char *fontname, - FontField field_num, - char *buffer) -{ - const char *t1, *t2; - int countdown, len, num_dashes; - - if (!fontname) - return NULL; - - /* we assume this is a valid fontname...that is, it has 14 fields */ - - countdown = field_num; - t1 = fontname; - while (*t1 && (countdown >= 0)) - if (*t1++ == '-') - countdown--; - - num_dashes = (field_num == XLFD_CHARSET) ? 2 : 1; - for (t2 = t1; *t2; t2++) - { - if (*t2 == '-' && --num_dashes == 0) - break; - } - - if (t1 != t2) - { - /* Check we don't overflow the buffer */ - len = (long) t2 - (long) t1; - if (len > XLFD_MAX_FIELD_LEN - 1) - return NULL; - strncpy (buffer, t1, len); - buffer[len] = 0; - /* Convert to lower case. */ - g_strdown (buffer); - } - else - strcpy(buffer, "(nil)"); - - return buffer; -} - -/* This inserts the given fontname into the FontInfo table. - If a FontInfo already exists with the same family and foundry, then the - fontname is added to the FontInfos list of fontnames, else a new FontInfo - is created and inserted in alphabetical order in the table. */ -static void -pango_x_insert_font (PangoXFontMap *xfontmap, - const char *fontname) -{ - PangoFontDescription description; - char family_buffer[XLFD_MAX_FIELD_LEN]; - char weight_buffer[XLFD_MAX_FIELD_LEN]; - char slant_buffer[XLFD_MAX_FIELD_LEN]; - char set_width_buffer[XLFD_MAX_FIELD_LEN]; - GSList *tmp_list; - PangoXFamilyEntry *family_entry; - PangoXFontEntry *font_entry; - PangoXSizeInfo *size_info; - char *identifier; - int i; - - description.size = 0; - - /* First insert the XLFD into the list of XLFDs for the "identifier" - which - * is the 2-4th fields of the XLFD - */ - identifier = pango_x_get_identifier (fontname); - size_info = g_hash_table_lookup (xfontmap->size_infos, identifier); - if (!size_info) - { - size_info = g_new (PangoXSizeInfo, 1); - size_info->identifier = identifier; - size_info->xlfds = NULL; - - g_hash_table_insert (xfontmap->size_infos, identifier, size_info); - } - else - g_free (identifier); - - size_info->xlfds = g_slist_prepend (size_info->xlfds, g_strdup (fontname)); - - /* Convert the XLFD into a PangoFontDescription */ - - description.family_name = pango_x_get_xlfd_field (fontname, XLFD_FAMILY, family_buffer); - g_strdown (description.family_name); - - if (!description.family_name) - return; - - description.style = PANGO_STYLE_NORMAL; - if (pango_x_get_xlfd_field (fontname, XLFD_SLANT, slant_buffer)) - { - for (i=0; i<G_N_ELEMENTS(styles_map); i++) - { - if (!strcmp (styles_map[i].text, slant_buffer)) - { - description.style = styles_map[i].value; - break; - } - } - } - else - strcpy (slant_buffer, "*"); - - description.variant = PANGO_VARIANT_NORMAL; - - description.weight = PANGO_WEIGHT_NORMAL; - if (pango_x_get_xlfd_field (fontname, XLFD_WEIGHT, weight_buffer)) - { - for (i=0; i<G_N_ELEMENTS(weights_map); i++) - { - if (!strcmp (weights_map[i].text, weight_buffer)) - { - description.weight = weights_map[i].value; - break; - } - } - } - else - strcpy (weight_buffer, "*"); - - description.stretch = PANGO_STRETCH_NORMAL; - if (pango_x_get_xlfd_field (fontname, XLFD_SET_WIDTH, set_width_buffer)) - { - for (i=0; i<G_N_ELEMENTS(stretches_map); i++) - { - if (!strcmp (stretches_map[i].text, set_width_buffer)) - { - description.stretch = stretches_map[i].value; - break; - } - } - } - else - strcpy (set_width_buffer, "*"); - - family_entry = pango_x_get_family_entry (xfontmap, description.family_name); - - tmp_list = family_entry->font_entries; - while (tmp_list) - { - font_entry = tmp_list->data; - - if (font_entry->description.style == description.style && - font_entry->description.variant == description.variant && - font_entry->description.weight == description.weight && - font_entry->description.stretch == description.stretch) - return; - - tmp_list = tmp_list->next; - } - - font_entry = g_new (PangoXFontEntry, 1); - font_entry->description = description; - font_entry->description.family_name = family_entry->family_name; - font_entry->cached_fonts = NULL; - font_entry->coverage = NULL; - - font_entry->xlfd = g_strconcat ("-*-", - family_buffer, - "-", - weight_buffer, - "-", - slant_buffer, - "-", - set_width_buffer, - "--*-*-*-*-*-*-*-*", - NULL); - - family_entry->font_entries = g_slist_append (family_entry->font_entries, font_entry); - xfontmap->n_fonts++; -} - - /** * pango_x_get_context: * @display: an X display (As returned by XOpenDisplay().) @@ -1383,7 +246,7 @@ pango_x_load_font (Display *display, * * Returns a new #PangoFont */ -static PangoFont * +PangoFont * pango_x_load_font_with_size (Display *display, char *spec, int size) @@ -1831,114 +694,6 @@ name_for_charset (char *xlfd, char *charset) return result; } -/* Given a xlfd, charset and size, find the best matching installed X font. - * The XLFD must be a full XLFD (14 fields) - */ -static char * -pango_x_make_matching_xlfd (PangoXFontMap *xfontmap, char *xlfd, const char *charset, int size) -{ - GSList *tmp_list; - PangoXSizeInfo *size_info; - char *identifier; - char *closest_match = NULL; - gint match_distance = 0; - gboolean match_scaleable = FALSE; - char *result = NULL; - - char *dash_charset; - - dash_charset = g_strconcat ("-", charset, NULL); - - if (!match_end (xlfd, "-*-*") && !match_end (xlfd, dash_charset)) - { - g_free (dash_charset); - return NULL; - } - - identifier = pango_x_get_identifier (xlfd); - size_info = g_hash_table_lookup (xfontmap->size_infos, identifier); - g_free (identifier); - - if (!size_info) - { - g_free (dash_charset); - return NULL; - } - - tmp_list = size_info->xlfds; - while (tmp_list) - { - char *tmp_xlfd = tmp_list->data; - - if (match_end (tmp_xlfd, dash_charset)) - { - int font_size = pango_x_get_size (xfontmap, tmp_xlfd); - - if (size != -1) - { - int new_distance = (font_size == 0) ? 0 : abs (font_size - size); - - if (!closest_match || - new_distance < match_distance || - (new_distance < PANGO_SCALE && match_scaleable && font_size != 0)) - { - closest_match = tmp_xlfd; - match_scaleable = (font_size == 0); - match_distance = new_distance; - } - } - } - - tmp_list = tmp_list->next; - } - - if (closest_match) - { - if (match_scaleable) - { - char *prefix_end, *p; - char *size_end; - int n_dashes = 0; - int target_size; - char *prefix; - - /* OK, we have a match; let's modify it to fit this size and charset */ - - p = closest_match; - while (n_dashes < 6) - { - if (*p == '-') - n_dashes++; - p++; - } - - prefix_end = p - 1; - - while (n_dashes < 9) - { - if (*p == '-') - n_dashes++; - p++; - } - - size_end = p - 1; - - target_size = (int)((double)size / xfontmap->resolution + 0.5); - prefix = g_strndup (closest_match, prefix_end - closest_match); - result = g_strdup_printf ("%s--%d-*-*-*-*-*-%s", prefix, target_size, charset); - g_free (prefix); - } - else - { - result = g_strdup (closest_match); - } - } - - g_free (dash_charset); - - return result; -} - static PangoXSubfont pango_x_insert_subfont (PangoFont *font, const char *xlfd) { @@ -1984,14 +739,14 @@ pango_x_list_subfonts (PangoFont *font, { PangoXFont *xfont = (PangoXFont *)font; PangoXSubfont **subfont_lists; - PangoXFontMap *xfontmap; + PangoFontMap *fontmap; int i, j; int n_subfonts = 0; g_return_val_if_fail (font != NULL, 0); g_return_val_if_fail (n_charsets == 0 || charsets != NULL, 0); - xfontmap = (PangoXFontMap *)pango_x_font_map_for_display (xfont->display); + fontmap = pango_x_font_map_for_display (xfont->display); subfont_lists = g_new (PangoXSubfont *, n_charsets); @@ -2024,7 +779,7 @@ pango_x_list_subfonts (PangoFont *font, } else { - xlfd = pango_x_make_matching_xlfd (xfontmap, xfont->fonts[i], charsets[j], xfont->size); + xlfd = pango_x_make_matching_xlfd (fontmap, xfont->fonts[i], charsets[j], xfont->size); if (xlfd) { subfont = pango_x_insert_subfont (font, xlfd); @@ -2117,7 +872,7 @@ pango_x_font_destroy (PangoFont *font) g_slist_free (xfont->metrics_by_lang); if (xfont->entry) - xfont->entry->cached_fonts = g_slist_remove (xfont->entry->cached_fonts, xfont); + pango_x_font_entry_remove (xfont->entry, font); g_strfreev (xfont->fonts); g_free (font); @@ -2130,15 +885,7 @@ pango_x_font_describe (PangoFont *font) return NULL; } -static void -free_coverages_foreach (gpointer key, - gpointer value, - gpointer data) -{ - pango_coverage_unref (value); -} - -static PangoMap * +PangoMap * pango_x_get_shaper_map (const char *lang) { static guint engine_type_id = 0; @@ -2157,60 +904,9 @@ static PangoCoverage * pango_x_font_get_coverage (PangoFont *font, const char *lang) { - guint32 ch; - PangoMap *shape_map; - PangoCoverage *coverage; - PangoCoverage *result; - PangoCoverageLevel font_level; - PangoMapEntry *entry; - GHashTable *coverage_hash; PangoXFont *xfont = (PangoXFont *)font; - if (xfont->entry) - if (xfont->entry->coverage) - { - pango_coverage_ref (xfont->entry->coverage); - return xfont->entry->coverage; - } - - result = pango_coverage_new (); - - coverage_hash = g_hash_table_new (g_str_hash, g_str_equal); - - shape_map = pango_x_get_shaper_map (lang); - - for (ch = 0; ch < 65536; ch++) - { - entry = _pango_map_get_entry (shape_map, ch); - if (entry->info) - { - coverage = g_hash_table_lookup (coverage_hash, entry->info->id); - if (!coverage) - { - PangoEngineShape *engine = (PangoEngineShape *)_pango_map_get_engine (shape_map, ch); - coverage = engine->get_coverage (font, lang); - g_hash_table_insert (coverage_hash, entry->info->id, coverage); - } - - font_level = pango_coverage_get (coverage, ch); - if (font_level == PANGO_COVERAGE_EXACT && !entry->is_exact) - font_level = PANGO_COVERAGE_APPROXIMATE; - - if (font_level != PANGO_COVERAGE_NONE) - pango_coverage_set (result, ch, font_level); - } - } - - g_hash_table_foreach (coverage_hash, free_coverages_foreach, NULL); - g_hash_table_destroy (coverage_hash); - - if (xfont->entry) - { - xfont->entry->coverage = result; - pango_coverage_ref (result); - } - - return result; + return pango_x_font_entry_get_coverage (xfont->entry, font, lang); } static PangoEngineShape * @@ -2578,3 +1274,6 @@ pango_x_get_item_properties (PangoItem *item, tmp_list = tmp_list->next; } } + + + diff --git a/pango/pangox.h b/pango/pangox.h index c81eba70..2c465b61 100644 --- a/pango/pangox.h +++ b/pango/pangox.h @@ -82,6 +82,11 @@ gboolean pango_x_has_glyph (PangoFont *font, PangoGlyph glyph); PangoGlyph pango_x_get_unknown_glyph (PangoFont *font); + +/* API for libraries that want to use PangoX mixed with classic X fonts. + */ +PangoFontMap *pango_x_font_map_for_display (Display *display); + #ifdef __cplusplus } #endif /* __cplusplus */ |