📄 pangox-fontmap.c
字号:
/* Pango * pangox-fontmap.c: X 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 <config.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include <errno.h>#include <glib.h>#include <X11/Xatom.h>/* For XExtSetCloseDisplay */#include <X11/Xlibint.h>#include "pango-engine-private.h"#include "pango-fontmap.h"#include "pango-impl-utils.h"#undef PANGO_DISABLE_DEPRECATED#include "pangox-private.h"typedef struct _PangoXFamily PangoXFamily;typedef struct _PangoXSizeInfo PangoXSizeInfo;/* Number of freed fonts */#define MAX_FREED_FONTS 16/* 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 _PangoXFamily{ PangoFontFamily parent_instance; char *family_name; GSList *font_entries;};struct _PangoXFace{ PangoFontFace parent_instance; char *xlfd; PangoFontDescription *description; PangoCoverage *coverage; char *face_name; GSList *cached_fonts;};struct _PangoXSizeInfo{ char *identifier; GSList *xlfds;};static const struct { const gchar text[12]; 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 }};static const struct { const gchar text[4]; PangoStyle value;} styles_map[] = { { "r", PANGO_STYLE_NORMAL }, { "i", PANGO_STYLE_ITALIC }, { "o", PANGO_STYLE_OBLIQUE }};static const struct { const gchar text[16]; PangoStretch value;} stretches_map[] = { { "normal", PANGO_STRETCH_NORMAL }, { "semicondensed", PANGO_STRETCH_SEMI_CONDENSED }, { "condensed", PANGO_STRETCH_CONDENSED },};static void pango_x_font_map_init (PangoXFontMap *fontmap);static void pango_x_font_map_class_init (PangoFontMapClass *class);static void pango_x_font_map_finalize (GObject *object);static PangoFont *pango_x_font_map_load_font (PangoFontMap *fontmap, PangoContext *context, const PangoFontDescription *description);static void pango_x_font_map_list_families (PangoFontMap *fontmap, PangoFontFamily ***families, int *n_families);static void pango_x_fontmap_cache_clear (PangoXFontMap *xfontmap);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);#define PANGO_X_TYPE_FAMILY (pango_x_family_get_type ())#define PANGO_X_FAMILY(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), PANGO_X_TYPE_FAMILY, PangoXFamily))#define PANGO_X_IS_FAMILY(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), PANGO_X_TYPE_FAMILY))GType pango_x_family_get_type (void);#define PANGO_X_TYPE_FACE (pango_x_face_get_type ())#define PANGO_X_FACE(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), PANGO_X_TYPE_FACE, PangoXFace))#define PANGO_X_IS_FACE(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), PANGO_X_TYPE_FACE))GType pango_x_face_get_type (void);static PangoFontClass *font_map_parent_class; /* Parent class structure for PangoXFontMap */GTypepango_x_font_map_get_type (void){ static GType object_type = 0; if (!object_type) { const GTypeInfo object_info = { sizeof (PangoFontMapClass), (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, NULL /* value_table */ }; object_type = g_type_register_static (PANGO_TYPE_FONT_MAP, I_("PangoXFontMap"), &object_info, 0); } return object_type;}static voidpango_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->to_atom_cache = g_hash_table_new (g_str_hash, g_str_equal); xfontmap->from_atom_cache = g_hash_table_new (g_direct_hash, g_direct_equal); xfontmap->n_fonts = 0;}static voidpango_x_font_map_class_init (PangoFontMapClass *class){ GObjectClass *object_class = G_OBJECT_CLASS (class); font_map_parent_class = g_type_class_peek_parent (class); object_class->finalize = pango_x_font_map_finalize; class->load_font = pango_x_font_map_load_font; class->list_families = pango_x_font_map_list_families; class->shape_engine_type = PANGO_RENDER_TYPE_X;}/* * Hackery to set up notification when a Display is closed */static GSList *registered_displays;static intclose_display_cb (Display *display, XExtCodes *extcodes){ pango_x_shutdown_display (display); registered_displays = g_slist_remove (registered_displays, display); return 0;}static voidregister_display (Display *display){ XExtCodes *extcodes; GSList *tmp_list; for (tmp_list = registered_displays; tmp_list; tmp_list = tmp_list->next) { if (tmp_list->data == display) return; } registered_displays = g_slist_prepend (registered_displays, display); extcodes = XAddExtension (display); XESetCloseDisplay (display, extcodes->extension, close_display_cb);}static GList *fontmaps = NULL;/** * pango_x_font_map_for_display: * @display: an X #Display. * * Returns a #PangoXFontMap for @display. Font maps are cached and should * not be freed. If the font map for a display is no longer needed, it can * be released with pango_x_shutdown_display(). * * Return value: a #PangoXFontMap for @display. **/PangoFontMap *pango_x_font_map_for_display (Display *display){ PangoXFontMap *xfontmap; GList *tmp_list = fontmaps; char **xfontnames; int num_fonts, i; int screen; g_return_val_if_fail (display != NULL, NULL); /* Make sure that the type system is initialized */ g_type_init (); while (tmp_list) { xfontmap = tmp_list->data; if (xfontmap->display == display) return PANGO_FONT_MAP (xfontmap); tmp_list = tmp_list->next; } xfontmap = g_object_new (PANGO_TYPE_X_FONT_MAP, NULL); xfontmap->display = display; xfontmap->font_cache = pango_x_font_cache_new (display); xfontmap->freed_fonts = g_queue_new (); /* 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)); register_display (xfontmap->display); return PANGO_FONT_MAP (xfontmap);}/** * pango_x_shutdown_display: * @display: an X #Display * * Free cached resources for the given X display structure. **/voidpango_x_shutdown_display (Display *display){ GList *tmp_list; g_return_if_fail (display != NULL); tmp_list = fontmaps; while (tmp_list) { PangoXFontMap *xfontmap = tmp_list->data; if (xfontmap->display == display) { fontmaps = g_list_delete_link (fontmaps, tmp_list); pango_x_fontmap_cache_clear (xfontmap); g_object_unref (xfontmap); return; } tmp_list = tmp_list->next; }}static voidpango_x_font_map_finalize (GObject *object){ PangoXFontMap *xfontmap = PANGO_X_FONT_MAP (object); g_list_foreach (xfontmap->freed_fonts->head, (GFunc)g_object_unref, NULL); g_queue_free (xfontmap->freed_fonts); pango_x_font_cache_free (xfontmap->font_cache); /* FIXME: Lots more here */ fontmaps = g_list_remove (fontmaps, xfontmap); G_OBJECT_CLASS (font_map_parent_class)->finalize (object);}static voidlist_families_foreach (gpointer key, gpointer value, gpointer user_data){ GSList **list = user_data; *list = g_slist_prepend (*list, value);}static voidpango_x_font_map_list_families (PangoFontMap *fontmap, PangoFontFamily ***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 (PangoFontFamily *, *n_families); tmp_list = family_list; while (tmp_list) { (*families)[i] = tmp_list->data; i++; tmp_list = tmp_list->next; } } g_slist_free (family_list);}static PangoXFamily *pango_x_get_font_family (PangoXFontMap *xfontmap, const char *family_name){ PangoXFamily *font_family = g_hash_table_lookup (xfontmap->families, family_name); if (!font_family) { font_family = g_object_new (PANGO_X_TYPE_FAMILY, NULL); font_family->family_name = g_strdup (family_name); font_family->font_entries = NULL; g_hash_table_insert (xfontmap->families, font_family->family_name, font_family); } return font_family;}static PangoFont *pango_x_font_map_load_font (PangoFontMap *fontmap, PangoContext *context, const PangoFontDescription *description){ PangoXFontMap *xfontmap = (PangoXFontMap *)fontmap; PangoXFamily *font_family; PangoFont *result = NULL; GSList *tmp_list; gchar *name; gint size; g_return_val_if_fail (description != NULL, NULL); name = g_ascii_strdown (pango_font_description_get_family (description), -1); size = pango_font_description_get_size (description); if (size < 0) return NULL; font_family = g_hash_table_lookup (xfontmap->families, name); if (font_family) { PangoXFace *best_match = NULL; tmp_list = font_family->font_entries; while (tmp_list) { PangoXFace *font_entry = tmp_list->data; if (pango_font_description_better_match (description, best_match ? best_match->description : NULL, font_entry->description)) 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 == size) { result = (PangoFont *)xfont; g_object_ref (result); if (xfont->in_cache) pango_x_fontmap_cache_remove (fontmap, xfont); break; } tmp_list = tmp_list->next; } if (!result) { PangoXFont *xfont = pango_x_font_new (fontmap, best_match->xlfd, size); xfont->fontmap = fontmap; xfont->xface = best_match; best_match->cached_fonts = g_slist_prepend (best_match->cached_fonts, xfont); result = (PangoFont *)xfont; } } } g_free (name); return result;}/************************ * Coverage Map Caching * ************************//* We need to be robust against errors accessing the coverage * cache window, since it is not our window. So we temporarily * set this error handler while accessing it. The error_occurred * global allows us to tell whether an error occurred for * XChangeProperty */static gboolean error_occurred;static intignore_error (Display *d, XErrorEvent *e){ return 0;}/* Retrieve the coverage window for the given display. * We look for a property on the root window, and then * check that the window that property points to also * has the same property pointing to itself. The second * check allows us to make sure that a stale property * isn't just pointing to some other apps window */static Windowpango_x_real_get_coverage_win (Display *display){ Atom type; int format; gulong n_items; gulong bytes_after; guchar *data; Window retval = None; int (*old_handler) (Display *, XErrorEvent *); Atom coverage_win_atom = XInternAtom (display, "PANGO_COVERAGE_WIN",
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -