2 * pangox-fontmap.c: X font handling
4 * Copyright (C) 2000 Red Hat Software
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Library General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Library General Public License for more details.
16 * You should have received a copy of the GNU Library General Public
17 * License along with this library; if not, write to the
18 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 * Boston, MA 02111-1307, USA.
29 #include <X11/Xatom.h>
31 /* For XExtSetCloseDisplay */
32 #include <X11/Xlibint.h>
34 #include "pango-engine-private.h"
35 #include "pango-fontmap.h"
36 #include "pango-impl-utils.h"
39 #undef PANGO_DISABLE_DEPRECATED
41 #include "pangox-private.h"
43 typedef struct _PangoXFamily PangoXFamily;
44 typedef struct _PangoXSizeInfo PangoXSizeInfo;
46 /* Number of freed fonts */
47 #define MAX_FREED_FONTS 16
49 /* This is the largest field length we will accept. If a fontname has a field
50 larger than this we will skip it. */
51 #define XLFD_MAX_FIELD_LEN 64
52 #define MAX_FONTS 32767
54 /* These are the field numbers in the X Logical Font Description fontnames,
55 e.g. -adobe-courier-bold-o-normal--25-180-100-100-m-150-iso8859-1 */
66 XLFD_RESOLUTION_X = 8,
67 XLFD_RESOLUTION_Y = 9,
69 XLFD_AVERAGE_WIDTH = 11,
76 PangoFontFamily parent_instance;
84 PangoFontFace parent_instance;
87 PangoFontDescription *description;
88 PangoCoverage *coverage;
95 struct _PangoXSizeInfo
101 static const struct {
102 const gchar text[12];
112 { "extrabold", 800 },
113 { "ultrabold", 800 },
118 static const struct {
122 { "r", PANGO_STYLE_NORMAL },
123 { "i", PANGO_STYLE_ITALIC },
124 { "o", PANGO_STYLE_OBLIQUE }
127 static const struct {
128 const gchar text[16];
130 } stretches_map[] = {
131 { "normal", PANGO_STRETCH_NORMAL },
132 { "semicondensed", PANGO_STRETCH_SEMI_CONDENSED },
133 { "condensed", PANGO_STRETCH_CONDENSED },
136 static void pango_x_font_map_init (PangoXFontMap *fontmap);
137 static void pango_x_font_map_class_init (PangoFontMapClass *class);
139 static void pango_x_font_map_finalize (GObject *object);
140 static PangoFont *pango_x_font_map_load_font (PangoFontMap *fontmap,
141 PangoContext *context,
142 const PangoFontDescription *description);
143 static void pango_x_font_map_list_families (PangoFontMap *fontmap,
144 PangoFontFamily ***families,
147 static void pango_x_fontmap_cache_clear (PangoXFontMap *xfontmap);
148 static void pango_x_font_map_read_aliases (PangoXFontMap *xfontmap);
150 static gint pango_x_get_size (PangoXFontMap *fontmap,
151 const char *fontname);
152 static void pango_x_insert_font (PangoXFontMap *fontmap,
153 const char *fontname);
154 static gboolean pango_x_is_xlfd_font_name (const char *fontname);
155 static char * pango_x_get_xlfd_field (const char *fontname,
158 static char * pango_x_get_identifier (const char *fontname);
161 #define PANGO_X_TYPE_FAMILY (pango_x_family_get_type ())
162 #define PANGO_X_FAMILY(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), PANGO_X_TYPE_FAMILY, PangoXFamily))
163 #define PANGO_X_IS_FAMILY(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), PANGO_X_TYPE_FAMILY))
165 GType pango_x_family_get_type (void);
168 #define PANGO_X_TYPE_FACE (pango_x_face_get_type ())
169 #define PANGO_X_FACE(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), PANGO_X_TYPE_FACE, PangoXFace))
170 #define PANGO_X_IS_FACE(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), PANGO_X_TYPE_FACE))
172 GType pango_x_face_get_type (void);
175 static PangoFontClass *font_map_parent_class; /* Parent class structure for PangoXFontMap */
178 pango_x_font_map_get_type (void)
180 static GType object_type = 0;
182 if (G_UNLIKELY (!object_type))
184 const GTypeInfo object_info =
186 sizeof (PangoFontMapClass),
187 (GBaseInitFunc) NULL,
188 (GBaseFinalizeFunc) NULL,
189 (GClassInitFunc) pango_x_font_map_class_init,
190 NULL, /* class_finalize */
191 NULL, /* class_data */
192 sizeof (PangoXFontMap),
194 (GInstanceInitFunc) pango_x_font_map_init,
195 NULL /* value_table */
198 object_type = g_type_register_static (PANGO_TYPE_FONT_MAP,
207 pango_x_font_map_init (PangoXFontMap *xfontmap)
209 xfontmap->families = g_hash_table_new (g_str_hash, g_str_equal);
210 xfontmap->size_infos = g_hash_table_new (g_str_hash, g_str_equal);
211 xfontmap->to_atom_cache = g_hash_table_new (g_str_hash, g_str_equal);
212 xfontmap->from_atom_cache = g_hash_table_new (g_direct_hash, g_direct_equal);
213 xfontmap->n_fonts = 0;
217 pango_x_font_map_class_init (PangoFontMapClass *class)
219 GObjectClass *object_class = G_OBJECT_CLASS (class);
221 font_map_parent_class = g_type_class_peek_parent (class);
223 object_class->finalize = pango_x_font_map_finalize;
224 class->load_font = pango_x_font_map_load_font;
225 class->list_families = pango_x_font_map_list_families;
226 class->shape_engine_type = PANGO_RENDER_TYPE_X;
230 * Hackery to set up notification when a Display is closed
232 static GSList *registered_displays;
235 close_display_cb (Display *display,
236 XExtCodes *extcodes G_GNUC_UNUSED)
238 pango_x_shutdown_display (display);
239 registered_displays = g_slist_remove (registered_displays, display);
245 register_display (Display *display)
250 for (tmp_list = registered_displays; tmp_list; tmp_list = tmp_list->next)
252 if (tmp_list->data == display)
256 registered_displays = g_slist_prepend (registered_displays, display);
258 extcodes = XAddExtension (display);
259 XESetCloseDisplay (display, extcodes->extension, close_display_cb);
262 static GList *fontmaps = NULL;
265 * pango_x_font_map_for_display:
266 * @display: an X #Display.
268 * Returns a #PangoXFontMap for @display. Font maps are cached and should
269 * not be freed. If the font map for a display is no longer needed, it can
270 * be released with pango_x_shutdown_display().
272 * Return value: a #PangoXFontMap for @display.
275 pango_x_font_map_for_display (Display *display)
277 PangoXFontMap *xfontmap;
278 GList *tmp_list = fontmaps;
282 static gboolean registered_modules = FALSE;
284 g_return_val_if_fail (display != NULL, NULL);
286 if (!registered_modules)
288 registered_modules = TRUE;
290 for (i = 0; _pango_included_x_modules[i].list; i++)
291 pango_module_register (&_pango_included_x_modules[i]);
294 /* Make sure that the type system is initialized */
299 xfontmap = tmp_list->data;
301 if (xfontmap->display == display)
302 return PANGO_FONT_MAP (xfontmap);
304 tmp_list = tmp_list->next;
307 xfontmap = g_object_new (PANGO_TYPE_X_FONT_MAP, NULL);
309 xfontmap->display = display;
310 xfontmap->font_cache = pango_x_font_cache_new (display);
311 xfontmap->freed_fonts = g_queue_new ();
313 /* Get a maximum of MAX_FONTS fontnames from the X server.
314 Use "-*" as the pattern rather than "-*-*-*-*-*-*-*-*-*-*-*-*-*-*" since
315 the latter may result in fonts being returned which don't actually exist.
316 xlsfonts also uses "*" so I think it's OK. "-*" gets rid of aliases. */
317 xfontnames = XListFonts (xfontmap->display, "-*", MAX_FONTS, &num_fonts);
318 if (num_fonts == MAX_FONTS)
319 g_warning("MAX_FONTS exceeded. Some fonts may be missing.");
321 /* Insert the font families into the main table */
322 for (i = 0; i < num_fonts; i++)
324 if (pango_x_is_xlfd_font_name (xfontnames[i]))
325 pango_x_insert_font (xfontmap, xfontnames[i]);
328 XFreeFontNames (xfontnames);
330 pango_x_font_map_read_aliases (xfontmap);
332 fontmaps = g_list_prepend (fontmaps, xfontmap);
334 /* This is a little screwed up, since different screens on the same display
335 * might have different resolutions
337 screen = DefaultScreen (xfontmap->display);
338 xfontmap->resolution = (PANGO_SCALE * 72.27 / 25.4) * ((double) DisplayWidthMM (xfontmap->display, screen) /
339 DisplayWidth (xfontmap->display, screen));
341 register_display (xfontmap->display);
343 return PANGO_FONT_MAP (xfontmap);
347 * pango_x_shutdown_display:
348 * @display: an X #Display
350 * Free cached resources for the given X display structure.
353 pango_x_shutdown_display (Display *display)
357 g_return_if_fail (display != NULL);
362 PangoXFontMap *xfontmap = tmp_list->data;
364 if (xfontmap->display == display)
366 fontmaps = g_list_delete_link (fontmaps, tmp_list);
367 pango_x_fontmap_cache_clear (xfontmap);
368 g_object_unref (xfontmap);
373 tmp_list = tmp_list->next;
378 pango_x_font_map_finalize (GObject *object)
380 PangoXFontMap *xfontmap = PANGO_X_FONT_MAP (object);
382 g_list_foreach (xfontmap->freed_fonts->head, (GFunc)g_object_unref, NULL);
383 g_queue_free (xfontmap->freed_fonts);
385 pango_x_font_cache_free (xfontmap->font_cache);
387 /* FIXME: None of these hashtables free their key/values
388 g_hash_table_destroy (xfontmap->families);
389 g_hash_table_destroy (xfontmap->size_infos);
390 g_hash_table_destroy (xfontmap->to_atom_cache);
391 g_hash_table_destroy (xfontmap->from_atom_cache);
394 fontmaps = g_list_remove (fontmaps, xfontmap);
396 G_OBJECT_CLASS (font_map_parent_class)->finalize (object);
400 list_families_foreach (gpointer key G_GNUC_UNUSED,
404 GSList **list = user_data;
406 *list = g_slist_prepend (*list, value);
410 pango_x_font_map_list_families (PangoFontMap *fontmap,
411 PangoFontFamily ***families,
414 GSList *family_list = NULL;
416 PangoXFontMap *xfontmap = (PangoXFontMap *)fontmap;
421 g_hash_table_foreach (xfontmap->families, list_families_foreach, &family_list);
423 *n_families = g_slist_length (family_list);
429 *families = g_new (PangoFontFamily *, *n_families);
431 tmp_list = family_list;
434 (*families)[i] = tmp_list->data;
436 tmp_list = tmp_list->next;
440 g_slist_free (family_list);
443 static PangoXFamily *
444 pango_x_get_font_family (PangoXFontMap *xfontmap,
445 const char *family_name)
447 PangoXFamily *font_family = g_hash_table_lookup (xfontmap->families, family_name);
450 font_family = g_object_new (PANGO_X_TYPE_FAMILY, NULL);
451 font_family->family_name = g_strdup (family_name);
452 font_family->font_entries = NULL;
454 g_hash_table_insert (xfontmap->families, font_family->family_name, font_family);
461 pango_x_font_map_load_font (PangoFontMap *fontmap,
462 PangoContext *context G_GNUC_UNUSED,
463 const PangoFontDescription *description)
465 PangoXFontMap *xfontmap = (PangoXFontMap *)fontmap;
466 PangoXFamily *font_family;
467 PangoFont *result = NULL;
473 g_return_val_if_fail (description != NULL, NULL);
475 family = pango_font_description_get_family (description);
476 name = g_ascii_strdown (family ? family : "", -1);
477 size = pango_font_description_get_size (description);
482 font_family = g_hash_table_lookup (xfontmap->families, name);
485 PangoXFace *best_match = NULL;
487 tmp_list = font_family->font_entries;
490 PangoXFace *font_entry = tmp_list->data;
492 if (pango_font_description_better_match (description,
493 best_match ? best_match->description : NULL,
494 font_entry->description))
495 best_match = font_entry;
497 tmp_list = tmp_list->next;
502 GSList *tmp_list = best_match->cached_fonts;
506 PangoXFont *xfont = tmp_list->data;
507 if (xfont->size == size)
509 result = (PangoFont *)xfont;
511 g_object_ref (result);
513 pango_x_fontmap_cache_remove (fontmap, xfont);
517 tmp_list = tmp_list->next;
522 PangoXFont *xfont = pango_x_font_new (fontmap, best_match->xlfd, size);
524 xfont->xface = best_match;
525 best_match->cached_fonts = g_slist_prepend (best_match->cached_fonts, xfont);
527 result = (PangoFont *)xfont;
537 /************************
538 * Coverage Map Caching *
539 ************************/
541 /* We need to be robust against errors accessing the coverage
542 * cache window, since it is not our window. So we temporarily
543 * set this error handler while accessing it. The error_occurred
544 * global allows us to tell whether an error occurred for
547 static gboolean error_occurred;
550 ignore_error (Display *d G_GNUC_UNUSED,
551 XErrorEvent *e G_GNUC_UNUSED)
556 /* Retrieve the coverage window for the given display.
557 * We look for a property on the root window, and then
558 * check that the window that property points to also
559 * has the same property pointing to itself. The second
560 * check allows us to make sure that a stale property
561 * isn't just pointing to some other apps window
564 pango_x_real_get_coverage_win (Display *display)
571 Window retval = None;
572 int (*old_handler) (Display *, XErrorEvent *);
574 Atom coverage_win_atom = XInternAtom (display,
575 "PANGO_COVERAGE_WIN",
578 XGetWindowProperty (display,
579 DefaultRootWindow (display),
583 &type, &format, &n_items, &bytes_after,
586 if (type == XA_WINDOW)
588 if (format == 32 && n_items == 1 && bytes_after == 0)
589 retval = *(Atom *)data;
594 old_handler= XSetErrorHandler (ignore_error);
596 if (XGetWindowProperty (display,
601 &type, &format, &n_items, &bytes_after,
605 if (format != 32 || n_items != 1 || bytes_after != 0 ||
606 *(Atom *)data != retval)
614 XSync (display, False);
615 XSetErrorHandler (old_handler);
620 /* Find or create the persistent window for caching font coverage
623 * To assure atomic creation, we first look for the window, then if we
624 * don't find it, grab the server, look for it again, and then if that
625 * still didn't find it, create it and ungrab.
628 pango_x_get_coverage_win (PangoXFontMap *xfontmap)
630 if (!xfontmap->coverage_win)
631 xfontmap->coverage_win = pango_x_real_get_coverage_win (xfontmap->display);
633 if (!xfontmap->coverage_win)
635 Display *persistant_display;
637 persistant_display = XOpenDisplay (DisplayString (xfontmap->display));
638 if (!persistant_display)
640 g_warning ("Cannot create or retrieve display for font coverage cache");
644 XGrabServer (persistant_display);
646 xfontmap->coverage_win = pango_x_real_get_coverage_win (xfontmap->display);
647 if (!xfontmap->coverage_win)
649 XSetWindowAttributes attr;
651 attr.override_redirect = True;
653 XSetCloseDownMode (persistant_display, RetainPermanent);
655 xfontmap->coverage_win =
656 XCreateWindow (persistant_display,
657 DefaultRootWindow (persistant_display),
658 -100, -100, 10, 10, 0, 0,
659 InputOnly, (Visual *)CopyFromParent,
660 CWOverrideRedirect, &attr);
662 XChangeProperty (persistant_display,
663 DefaultRootWindow (persistant_display),
664 XInternAtom (persistant_display,
665 "PANGO_COVERAGE_WIN",
669 (guchar *)&xfontmap->coverage_win, 1);
672 XChangeProperty (persistant_display,
673 xfontmap->coverage_win,
674 XInternAtom (persistant_display,
675 "PANGO_COVERAGE_WIN",
679 (guchar *)&xfontmap->coverage_win, 1);
682 XUngrabServer (persistant_display);
684 XSync (persistant_display, False);
685 XCloseDisplay (persistant_display);
688 return xfontmap->coverage_win;
691 /* Find the cached value for the coverage map on the
692 * coverage cache window, if it exists. *atom is set
693 * to the interned value of str for later use in storing
694 * the property if the lookup fails
696 static PangoCoverage *
697 pango_x_get_cached_coverage (PangoXFontMap *xfontmap,
701 int (*old_handler) (Display *, XErrorEvent *);
703 PangoCoverage *result = NULL;
712 *atom = XInternAtom (xfontmap->display, str, False);
716 coverage_win = pango_x_get_coverage_win (xfontmap);
721 old_handler= XSetErrorHandler (ignore_error);
723 if (XGetWindowProperty (xfontmap->display,
727 &type, &format, &n_items, &bytes_after,
729 && type == XA_STRING)
731 if (format == 8 && bytes_after == 0)
732 result = pango_coverage_from_bytes (data, n_items);
734 XSetErrorHandler (old_handler);
740 /* Window disappeared out from under us */
741 XSetErrorHandler (old_handler);
742 xfontmap->coverage_win = None;
750 /* Store the given coverage map on the coverage cache window.
751 * atom is the intern'ed value of the string that identifies
755 pango_x_store_cached_coverage (PangoXFontMap *xfontmap,
757 PangoCoverage *coverage)
759 int (*old_handler) (Display *, XErrorEvent *);
765 pango_coverage_to_bytes (coverage, &bytes, &size);
769 Window coverage_win = pango_x_get_coverage_win (xfontmap);
774 old_handler = XSetErrorHandler (ignore_error);
775 error_occurred = False;
777 XChangeProperty (xfontmap->display,
784 XSync (xfontmap->display, False);
785 XSetErrorHandler (old_handler);
791 /* Window disappeared out from under us */
792 XSetErrorHandler (old_handler);
793 xfontmap->coverage_win = None;
802 pango_x_font_map_read_alias_file (PangoXFontMap *xfontmap,
803 const char *filename)
809 PangoXFace *xface = NULL;
811 infile = fopen (filename, "r");
814 GString *line_buf = g_string_new (NULL);
815 GString *tmp_buf = g_string_new (NULL);
818 while ((lines_read = pango_read_line (infile, line_buf)))
820 PangoXFamily *font_family;
822 PangoVariant variant;
824 PangoStretch stretch;
826 const char *p = line_buf->str;
828 lineno += lines_read;
830 if (!pango_skip_space (&p))
833 if (!pango_scan_string (&p, tmp_buf))
836 xface = g_object_new (PANGO_X_TYPE_FACE, NULL);
838 xface->description = pango_font_description_new ();
840 g_string_ascii_down (tmp_buf);
841 pango_font_description_set_family (xface->description, tmp_buf->str);
843 if (!pango_scan_string (&p, tmp_buf))
846 if (!pango_parse_style (tmp_buf->str, &style, TRUE))
848 pango_font_description_set_style (xface->description, style);
850 if (!pango_scan_string (&p, tmp_buf))
853 if (!pango_parse_variant (tmp_buf->str, &variant, TRUE))
855 pango_font_description_set_variant (xface->description, variant);
857 if (!pango_scan_string (&p, tmp_buf))
860 if (!pango_parse_weight (tmp_buf->str, &weight, TRUE))
862 pango_font_description_set_weight (xface->description, weight);
864 if (!pango_scan_string (&p, tmp_buf))
867 if (!pango_parse_stretch (tmp_buf->str, &stretch, TRUE))
869 pango_font_description_set_stretch (xface->description, stretch);
871 if (!pango_scan_string (&p, tmp_buf))
874 /* Remove excess whitespace and check for complete fields */
876 xlfds = g_strsplit (tmp_buf->str, ",", -1);
877 for (i=0; xlfds[i]; i++)
879 char *trimmed = pango_trim_string (xlfds[i]);
883 if (!pango_x_is_xlfd_font_name (xlfds[i]))
885 g_warning ("XLFD '%s' must be complete (14 fields)", xlfds[i]);
891 xface->xlfd = g_strjoinv (",", xlfds);
894 /* Insert the font entry into our structures */
896 font_family = pango_x_get_font_family (xfontmap,
897 pango_font_description_get_family (xface->description));
898 font_family->font_entries = g_slist_prepend (font_family->font_entries, xface);
901 /* Save space by consolidating duplicated string */
902 pango_font_description_set_family_static (xface->description, font_family->family_name);
903 xface->cached_fonts = NULL;
904 xface->coverage = NULL;
908 g_warning ("Error reading '%s': %s", filename, g_strerror(errno));
915 g_free (xface->xlfd);
916 if (xface->description)
917 pango_font_description_free (xface->description);
921 g_warning ("Error parsing line %d of alias file '%s'", lineno, filename);
924 g_string_free (tmp_buf, TRUE);
925 g_string_free (line_buf, TRUE);
933 pango_x_font_map_read_aliases (PangoXFontMap *xfontmap)
936 char *files_str = pango_config_key_get ("PangoX/AliasFiles");
940 files_str = g_strdup ("~/.pangox_aliases:" SYSCONFDIR "/pango/pangox.aliases");
942 files = pango_split_file_list (files_str);
949 pango_x_font_map_read_alias_file (xfontmap, files[n]);
956 * Returns %TRUE if the fontname is a valid XLFD.
957 * (It just checks if the number of dashes is 14, and that each
958 * field < XLFD_MAX_FIELD_LEN characters long - that's not in the XLFD but it
959 * makes it easier for me).
962 pango_x_is_xlfd_font_name (const char *fontname)
969 if (*fontname++ == '-')
971 if (field_len > XLFD_MAX_FIELD_LEN) return FALSE;
979 return (i == 14) ? TRUE : FALSE;
983 pango_x_get_size (PangoXFontMap *xfontmap, const char *fontname)
985 char size_buffer[XLFD_MAX_FIELD_LEN];
988 if (!pango_x_get_xlfd_field (fontname, XLFD_PIXELS, size_buffer))
991 size = atoi (size_buffer);
994 return (int)(0.5 + size * xfontmap->resolution);
998 /* We use the trick that scaled bitmaps have a non-zero RESOLUTION_X, while
999 * actual scaleable fonts have a zero RESOLUTION_X */
1000 if (!pango_x_get_xlfd_field (fontname, XLFD_RESOLUTION_X, size_buffer))
1003 if (atoi (size_buffer) == 0)
1011 pango_x_get_identifier (const char *fontname)
1013 const char *p = fontname;
1017 while (n_dashes < 2)
1026 while (n_dashes < 6)
1033 return g_strndup (start, (p - 1 - start));
1037 * This fills the buffer with the specified field from the X Logical Font
1038 * Description name, and returns it. If fontname is %NULL or the field is
1039 * longer than XFLD_MAX_FIELD_LEN it returns %NULL.
1040 * Note: For the charset field, we also return the encoding, e.g. 'iso8859-1'.
1043 pango_x_get_xlfd_field (const char *fontname,
1044 FontField field_num,
1047 const char *t1, *t2;
1049 int countdown, len, num_dashes;
1054 /* we assume this is a valid fontname...that is, it has 14 fields */
1056 countdown = field_num;
1058 while (*t1 && (countdown >= 0))
1062 num_dashes = (field_num == XLFD_CHARSET) ? 2 : 1;
1063 for (t2 = t1; *t2; t2++)
1065 if (*t2 == '-' && --num_dashes == 0)
1071 /* Check we don't overflow the buffer */
1072 len = (long) t2 - (long) t1;
1073 if (len > XLFD_MAX_FIELD_LEN - 1)
1075 strncpy (buffer, t1, len);
1077 /* Convert to lower case. */
1078 for (p = buffer; *p; p++)
1079 *p = g_ascii_tolower (*p);
1082 strcpy(buffer, "(nil)");
1087 /* This inserts the given fontname into the FontInfo table.
1088 If a FontInfo already exists with the same family and foundry, then the
1089 fontname is added to the FontInfos list of fontnames, else a new FontInfo
1090 is created and inserted in alphabetical order in the table. */
1092 pango_x_insert_font (PangoXFontMap *xfontmap,
1093 const char *fontname)
1095 PangoFontDescription *description;
1098 PangoVariant variant;
1100 PangoStretch stretch;
1101 char family_buffer[XLFD_MAX_FIELD_LEN];
1102 char weight_buffer[XLFD_MAX_FIELD_LEN];
1103 char slant_buffer[XLFD_MAX_FIELD_LEN];
1104 char set_width_buffer[XLFD_MAX_FIELD_LEN];
1106 PangoXFamily *font_family;
1108 PangoXSizeInfo *size_info;
1112 /* First insert the XLFD into the list of XLFDs for the "identifier" - which
1113 * is the 2-4th fields of the XLFD
1115 identifier = pango_x_get_identifier (fontname);
1116 size_info = g_hash_table_lookup (xfontmap->size_infos, identifier);
1119 size_info = g_slice_new (PangoXSizeInfo);
1120 size_info->identifier = identifier;
1121 size_info->xlfds = NULL;
1123 g_hash_table_insert (xfontmap->size_infos, identifier, size_info);
1126 g_free (identifier);
1128 size_info->xlfds = g_slist_prepend (size_info->xlfds, g_strdup (fontname));
1130 /* Convert the XLFD into a PangoFontDescription */
1132 family_name = pango_x_get_xlfd_field (fontname, XLFD_FAMILY, family_buffer);
1136 style = PANGO_STYLE_NORMAL;
1137 if (pango_x_get_xlfd_field (fontname, XLFD_SLANT, slant_buffer))
1139 for (i=0; i<G_N_ELEMENTS(styles_map); i++)
1141 if (!strcmp (styles_map[i].text, slant_buffer))
1143 style = styles_map[i].value;
1149 strcpy (slant_buffer, "*");
1151 variant = PANGO_VARIANT_NORMAL;
1153 weight = PANGO_WEIGHT_NORMAL;
1154 if (pango_x_get_xlfd_field (fontname, XLFD_WEIGHT, weight_buffer))
1156 for (i=0; i<G_N_ELEMENTS(weights_map); i++)
1158 if (!strcmp (weights_map[i].text, weight_buffer))
1160 weight = weights_map[i].value;
1166 strcpy (weight_buffer, "*");
1168 stretch = PANGO_STRETCH_NORMAL;
1169 if (pango_x_get_xlfd_field (fontname, XLFD_SET_WIDTH, set_width_buffer))
1171 for (i=0; i<G_N_ELEMENTS(stretches_map); i++)
1173 if (!strcmp (stretches_map[i].text, set_width_buffer))
1175 stretch = stretches_map[i].value;
1181 strcpy (set_width_buffer, "*");
1183 font_family = pango_x_get_font_family (xfontmap, family_name);
1185 tmp_list = font_family->font_entries;
1188 xface = tmp_list->data;
1190 if (pango_font_description_get_style (xface->description) == style &&
1191 pango_font_description_get_weight (xface->description) == weight &&
1192 pango_font_description_get_stretch (xface->description) == stretch &&
1193 pango_font_description_get_variant (xface->description) == variant)
1196 tmp_list = tmp_list->next;
1199 description = pango_font_description_new ();
1200 pango_font_description_set_family_static (description, font_family->family_name);
1201 pango_font_description_set_style (description, style);
1202 pango_font_description_set_weight (description, weight);
1203 pango_font_description_set_stretch (description, stretch);
1204 pango_font_description_set_variant (description, variant);
1206 xface = g_object_new (PANGO_X_TYPE_FACE, NULL);
1207 xface->description = description;
1208 xface->cached_fonts = NULL;
1209 xface->coverage = NULL;
1211 xface->xlfd = g_strconcat ("-*-",
1219 "--*-*-*-*-*-*-*-*",
1222 font_family->font_entries = g_slist_append (font_family->font_entries, xface);
1223 xfontmap->n_fonts++;
1226 /* Compare the tail of a to b */
1228 match_end (const char *a, const char *b)
1230 size_t len_a = strlen (a);
1231 size_t len_b = strlen (b);
1236 return (strcmp (a + len_a - len_b, b) == 0);
1239 /* Given a XLFD, charset and size, find the best matching installed X font.
1240 * The XLFD must be a full XLFD (14 fields)
1243 pango_x_make_matching_xlfd (PangoFontMap *fontmap, char *xlfd, const char *charset, int size)
1245 PangoXFontMap *xfontmap;
1248 PangoXSizeInfo *size_info;
1250 char *closest_match = NULL;
1251 gint match_distance = 0;
1252 gboolean match_scaleable = FALSE;
1253 char *result = NULL;
1257 xfontmap = PANGO_X_FONT_MAP (fontmap);
1259 dash_charset = g_strconcat ("-", charset, NULL);
1261 if (!match_end (xlfd, "-*-*") && !match_end (xlfd, dash_charset))
1263 g_free (dash_charset);
1267 identifier = pango_x_get_identifier (xlfd);
1268 size_info = g_hash_table_lookup (xfontmap->size_infos, identifier);
1269 g_free (identifier);
1273 g_free (dash_charset);
1277 tmp_list = size_info->xlfds;
1280 char *tmp_xlfd = tmp_list->data;
1282 if (match_end (tmp_xlfd, dash_charset))
1284 int font_size = pango_x_get_size (xfontmap, tmp_xlfd);
1288 int new_distance = (font_size == 0) ? 0 : abs (font_size - size);
1290 if (!closest_match ||
1291 new_distance < match_distance ||
1292 (new_distance < PANGO_SCALE && match_scaleable && font_size != 0))
1294 closest_match = tmp_xlfd;
1295 match_scaleable = (font_size == 0);
1296 match_distance = new_distance;
1301 tmp_list = tmp_list->next;
1306 if (match_scaleable)
1308 char *prefix_end, *p;
1313 /* OK, we have a match; let's modify it to fit this size and charset */
1316 while (n_dashes < 6)
1325 while (n_dashes < 9)
1332 target_size = (int)((double)size / xfontmap->resolution + 0.5);
1333 prefix = g_strndup (closest_match, prefix_end - closest_match);
1334 result = g_strdup_printf ("%s--%d-*-*-*-*-*-%s", prefix, target_size, charset);
1339 result = g_strdup (closest_match);
1343 g_free (dash_charset);
1349 * pango_x_font_map_get_font_cache:
1350 * @font_map: a #PangoXFontMap.
1352 * Obtains the font cache associated with the given font map.
1354 * Return value: the #PangoXFontCache of @font_map.
1357 pango_x_font_map_get_font_cache (PangoFontMap *font_map)
1359 g_return_val_if_fail (font_map != NULL, NULL);
1360 g_return_val_if_fail (PANGO_X_IS_FONT_MAP (font_map), NULL);
1362 return PANGO_X_FONT_MAP (font_map)->font_cache;
1366 pango_x_fontmap_get_display (PangoFontMap *fontmap)
1368 g_return_val_if_fail (fontmap != NULL, NULL);
1369 g_return_val_if_fail (PANGO_X_IS_FONT_MAP (fontmap), NULL);
1371 return PANGO_X_FONT_MAP (fontmap)->display;
1375 pango_x_fontmap_cache_add (PangoFontMap *fontmap,
1378 PangoXFontMap *xfontmap = PANGO_X_FONT_MAP (fontmap);
1380 if (xfontmap->freed_fonts->length == MAX_FREED_FONTS)
1382 PangoXFont *old_font = g_queue_pop_tail (xfontmap->freed_fonts);
1383 g_object_unref (old_font);
1386 g_object_ref (xfont);
1387 g_queue_push_head (xfontmap->freed_fonts, xfont);
1388 xfont->in_cache = TRUE;
1392 pango_x_fontmap_cache_remove (PangoFontMap *fontmap,
1395 PangoXFontMap *xfontmap = PANGO_X_FONT_MAP (fontmap);
1397 GList *link = g_list_find (xfontmap->freed_fonts->head, xfont);
1398 if (link == xfontmap->freed_fonts->tail)
1400 xfontmap->freed_fonts->tail = xfontmap->freed_fonts->tail->prev;
1401 if (xfontmap->freed_fonts->tail)
1402 xfontmap->freed_fonts->tail->next = NULL;
1405 xfontmap->freed_fonts->head = g_list_delete_link (xfontmap->freed_fonts->head, link);
1406 xfontmap->freed_fonts->length--;
1407 xfont->in_cache = FALSE;
1409 g_object_unref (xfont);
1413 pango_x_fontmap_cache_clear (PangoXFontMap *xfontmap)
1415 g_list_foreach (xfontmap->freed_fonts->head, (GFunc)g_object_unref, NULL);
1416 g_list_free (xfontmap->freed_fonts->head);
1417 xfontmap->freed_fonts->head = NULL;
1418 xfontmap->freed_fonts->tail = NULL;
1419 xfontmap->freed_fonts->length = 0;
1424 pango_x_fontmap_atom_from_name (PangoFontMap *fontmap,
1425 const char *atomname)
1427 PangoXFontMap *xfm = PANGO_X_FONT_MAP(fontmap);
1431 found = g_hash_table_lookup (xfm->to_atom_cache, atomname);
1434 return (Atom)(GPOINTER_TO_UINT(found));
1436 atom = XInternAtom (xfm->display, atomname, FALSE);
1437 g_hash_table_insert (xfm->to_atom_cache, g_strdup (atomname),
1444 G_CONST_RETURN char *
1445 pango_x_fontmap_name_from_atom (PangoFontMap *fontmap,
1448 PangoXFontMap *xfm = PANGO_X_FONT_MAP(fontmap);
1452 found = g_hash_table_lookup (xfm->from_atom_cache, GUINT_TO_POINTER(atom));
1455 return (const char *)found;
1457 name = XGetAtomName (xfm->display, atom);
1458 name2 = g_strdup (name);
1461 g_hash_table_insert (xfm->from_atom_cache, (gpointer)atom, name2);
1470 static PangoFontDescription *
1471 pango_x_face_describe (PangoFontFace *face)
1473 PangoXFace *xface = PANGO_X_FACE (face);
1475 return pango_font_description_copy (xface->description);
1479 pango_x_face_get_face_name (PangoFontFace *face)
1481 PangoXFace *xface = PANGO_X_FACE (face);
1483 if (!xface->face_name)
1485 PangoFontDescription *desc = pango_font_face_describe (face);
1487 pango_font_description_unset_fields (desc,
1488 PANGO_FONT_MASK_FAMILY | PANGO_FONT_MASK_SIZE);
1490 xface->face_name = pango_font_description_to_string (desc);
1491 pango_font_description_free (desc);
1494 return xface->face_name;
1498 pango_x_face_class_init (PangoFontFaceClass *class)
1500 class->describe = pango_x_face_describe;
1501 class->get_face_name = pango_x_face_get_face_name;
1505 pango_x_face_get_type (void)
1507 static GType object_type = 0;
1509 if (G_UNLIKELY (!object_type))
1511 const GTypeInfo object_info =
1513 sizeof (PangoFontFaceClass),
1514 (GBaseInitFunc) NULL,
1515 (GBaseFinalizeFunc) NULL,
1516 (GClassInitFunc) pango_x_face_class_init,
1517 NULL, /* class_finalize */
1518 NULL, /* class_data */
1519 sizeof (PangoXFace),
1520 0, /* n_preallocs */
1521 (GInstanceInitFunc) NULL,
1522 NULL /* value_table */
1525 object_type = g_type_register_static (PANGO_TYPE_FONT_FACE,
1533 /* Cut and paste here to avoid an inter-module dependency */
1534 static PangoCoverageLevel
1535 engine_shape_covers (PangoEngineShape *engine,
1537 PangoLanguage *language,
1540 g_return_val_if_fail (PANGO_IS_ENGINE_SHAPE (engine), PANGO_COVERAGE_NONE);
1541 g_return_val_if_fail (PANGO_IS_FONT (font), PANGO_COVERAGE_NONE);
1543 return PANGO_ENGINE_SHAPE_GET_CLASS (engine)->covers (engine,
1550 pango_x_face_get_coverage (PangoXFace *xface,
1552 PangoLanguage *language)
1555 PangoXFontMap *xfontmap = NULL; /* Quiet gcc */
1556 PangoCoverage *result = NULL;
1561 if (xface->coverage)
1563 pango_coverage_ref (xface->coverage);
1564 return xface->coverage;
1567 xfont = (PangoXFont *)font;
1569 xfontmap = (PangoXFontMap *)pango_x_font_map_for_display (xfont->display);
1572 const char *lang_str = language ? pango_language_to_string (language) : "*";
1574 char *str = g_strconcat (lang_str, "|", xface->xlfd, NULL);
1575 result = pango_x_get_cached_coverage (xfontmap, str, &atom);
1582 PangoMap *shape_map;
1583 PangoEngineShape *engine;
1586 result = pango_coverage_new ();
1588 shape_map = pango_x_get_shaper_map (language);
1589 engine = (PangoEngineShape *)pango_map_get_engine (shape_map, PANGO_SCRIPT_COMMON);
1591 for (wc = 0; wc < 65536; wc++)
1593 PangoCoverageLevel level;
1595 level = engine_shape_covers (engine, font, language, wc);
1596 if (level != PANGO_COVERAGE_NONE)
1597 pango_coverage_set (result, wc, level);
1601 pango_x_store_cached_coverage (xfontmap, atom, result);
1606 xface->coverage = result;
1607 pango_coverage_ref (result);
1614 pango_x_face_remove (PangoXFace *xface,
1617 xface->cached_fonts = g_slist_remove (xface->cached_fonts, font);
1625 pango_x_family_list_faces (PangoFontFamily *family,
1626 PangoFontFace ***faces,
1629 PangoXFamily *xfamily = PANGO_X_FAMILY (family);
1631 *n_faces = g_slist_length (xfamily->font_entries);
1637 *faces = g_new (PangoFontFace *, *n_faces);
1639 tmp_list = xfamily->font_entries;
1642 (*faces)[i++] = tmp_list->data;
1643 tmp_list = tmp_list->next;
1648 static G_CONST_RETURN char *
1649 pango_x_family_get_name (PangoFontFamily *family)
1651 PangoXFamily *xfamily = PANGO_X_FAMILY (family);
1653 return xfamily->family_name;
1657 pango_x_family_class_init (PangoFontFamilyClass *class)
1659 class->list_faces = pango_x_family_list_faces;
1660 class->get_name = pango_x_family_get_name;
1664 pango_x_family_get_type (void)
1666 static GType object_type = 0;
1668 if (G_UNLIKELY (!object_type))
1670 const GTypeInfo object_info =
1672 sizeof (PangoFontFamilyClass),
1673 (GBaseInitFunc) NULL,
1674 (GBaseFinalizeFunc) NULL,
1675 (GClassInitFunc) pango_x_family_class_init,
1676 NULL, /* class_finalize */
1677 NULL, /* class_data */
1678 sizeof (PangoXFamily),
1679 0, /* n_preallocs */
1680 (GInstanceInitFunc) NULL,
1681 NULL /* value_table */
1684 object_type = g_type_register_static (PANGO_TYPE_FONT_FAMILY,