Git init
[external/pango1.0.git] / pango / pangox-fontmap.c
1 /* Pango
2  * pangox-fontmap.c: X font handling
3  *
4  * Copyright (C) 2000 Red Hat Software
5  *
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.
10  *
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.
15  *
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.
20  */
21
22 #include "config.h"
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <errno.h>
27 #include <glib.h>
28
29 #include <X11/Xatom.h>
30
31 /* For XExtSetCloseDisplay */
32 #include <X11/Xlibint.h>
33
34 #include "pango-engine-private.h"
35 #include "pango-fontmap.h"
36 #include "pango-impl-utils.h"
37 #include "modules.h"
38
39 #undef PANGO_DISABLE_DEPRECATED
40
41 #include "pangox-private.h"
42
43 typedef struct _PangoXFamily       PangoXFamily;
44 typedef struct _PangoXSizeInfo     PangoXSizeInfo;
45
46 /* Number of freed fonts */
47 #define MAX_FREED_FONTS 16
48
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
53
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 */
56 typedef enum
57 {
58   XLFD_FOUNDRY          = 0,
59   XLFD_FAMILY           = 1,
60   XLFD_WEIGHT           = 2,
61   XLFD_SLANT            = 3,
62   XLFD_SET_WIDTH        = 4,
63   XLFD_ADD_STYLE        = 5,
64   XLFD_PIXELS           = 6,
65   XLFD_POINTS           = 7,
66   XLFD_RESOLUTION_X     = 8,
67   XLFD_RESOLUTION_Y     = 9,
68   XLFD_SPACING          = 10,
69   XLFD_AVERAGE_WIDTH    = 11,
70   XLFD_CHARSET          = 12,
71   XLFD_NUM_FIELDS
72 } FontField;
73
74 struct _PangoXFamily
75 {
76   PangoFontFamily parent_instance;
77
78   char *family_name;
79   GSList *font_entries;
80 };
81
82 struct _PangoXFace
83 {
84   PangoFontFace parent_instance;
85
86   char *xlfd;
87   PangoFontDescription *description;
88   PangoCoverage *coverage;
89
90   char *face_name;
91
92   GSList *cached_fonts;
93 };
94
95 struct _PangoXSizeInfo
96 {
97   char *identifier;
98   GSList *xlfds;
99 };
100
101 static const struct {
102   const gchar text[12];
103   PangoWeight value;
104 } weights_map[] = {
105   { "light",     300 },
106   { "regular",   400 },
107   { "book",      400 },
108   { "medium",    500 },
109   { "semibold",  600 },
110   { "demibold",  600 },
111   { "bold",      700 },
112   { "extrabold", 800 },
113   { "ultrabold", 800 },
114   { "heavy",     900 },
115   { "black",     900 }
116 };
117
118 static const struct {
119   const gchar text[4];
120   PangoStyle value;
121 } styles_map[] = {
122   { "r", PANGO_STYLE_NORMAL },
123   { "i", PANGO_STYLE_ITALIC },
124   { "o", PANGO_STYLE_OBLIQUE }
125 };
126
127 static const struct {
128   const gchar text[16];
129   PangoStretch value;
130 } stretches_map[] = {
131   { "normal",        PANGO_STRETCH_NORMAL },
132   { "semicondensed", PANGO_STRETCH_SEMI_CONDENSED },
133   { "condensed",     PANGO_STRETCH_CONDENSED },
134 };
135
136 static void     pango_x_font_map_init       (PangoXFontMap      *fontmap);
137 static void     pango_x_font_map_class_init (PangoFontMapClass *class);
138
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,
145                                                   int                          *n_families);
146
147 static void     pango_x_fontmap_cache_clear (PangoXFontMap   *xfontmap);
148 static void     pango_x_font_map_read_aliases (PangoXFontMap *xfontmap);
149
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,
156                                              FontField           field_num,
157                                              char               *buffer);
158 static char *   pango_x_get_identifier      (const char         *fontname);
159
160
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))
164
165 GType           pango_x_family_get_type (void);
166
167
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))
171
172 GType           pango_x_face_get_type (void);
173
174
175 static PangoFontClass *font_map_parent_class;   /* Parent class structure for PangoXFontMap */
176
177 GType
178 pango_x_font_map_get_type (void)
179 {
180   static GType object_type = 0;
181
182   if (G_UNLIKELY (!object_type))
183     {
184       const GTypeInfo object_info =
185       {
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),
193         0,              /* n_preallocs */
194         (GInstanceInitFunc) pango_x_font_map_init,
195         NULL            /* value_table */
196       };
197
198       object_type = g_type_register_static (PANGO_TYPE_FONT_MAP,
199                                             I_("PangoXFontMap"),
200                                             &object_info, 0);
201     }
202
203   return object_type;
204 }
205
206 static void
207 pango_x_font_map_init (PangoXFontMap *xfontmap)
208 {
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;
214 }
215
216 static void
217 pango_x_font_map_class_init (PangoFontMapClass *class)
218 {
219   GObjectClass *object_class = G_OBJECT_CLASS (class);
220
221   font_map_parent_class = g_type_class_peek_parent (class);
222
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;
227 }
228
229 /*
230  * Hackery to set up notification when a Display is closed
231  */
232 static GSList *registered_displays;
233
234 static int
235 close_display_cb (Display   *display,
236                   XExtCodes *extcodes G_GNUC_UNUSED)
237 {
238   pango_x_shutdown_display (display);
239   registered_displays = g_slist_remove (registered_displays, display);
240
241   return 0;
242 }
243
244 static void
245 register_display (Display *display)
246 {
247   XExtCodes *extcodes;
248   GSList *tmp_list;
249
250   for (tmp_list = registered_displays; tmp_list; tmp_list = tmp_list->next)
251     {
252       if (tmp_list->data == display)
253         return;
254     }
255
256   registered_displays = g_slist_prepend (registered_displays, display);
257
258   extcodes = XAddExtension (display);
259   XESetCloseDisplay (display, extcodes->extension, close_display_cb);
260 }
261
262 static GList *fontmaps = NULL;
263
264 /**
265  * pango_x_font_map_for_display:
266  * @display: an X #Display.
267  *
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().
271  *
272  * Return value: a #PangoXFontMap for @display.
273  **/
274 PangoFontMap *
275 pango_x_font_map_for_display (Display *display)
276 {
277   PangoXFontMap *xfontmap;
278   GList *tmp_list = fontmaps;
279   char **xfontnames;
280   int num_fonts, i;
281   int screen;
282   static gboolean registered_modules = FALSE;
283
284   g_return_val_if_fail (display != NULL, NULL);
285
286   if (!registered_modules)
287     {
288       registered_modules = TRUE;
289
290       for (i = 0; _pango_included_x_modules[i].list; i++)
291         pango_module_register (&_pango_included_x_modules[i]);
292     }
293
294   /* Make sure that the type system is initialized */
295   g_type_init ();
296
297   while (tmp_list)
298     {
299       xfontmap = tmp_list->data;
300
301       if (xfontmap->display == display)
302         return PANGO_FONT_MAP (xfontmap);
303
304       tmp_list = tmp_list->next;
305     }
306
307   xfontmap = g_object_new (PANGO_TYPE_X_FONT_MAP, NULL);
308
309   xfontmap->display = display;
310   xfontmap->font_cache = pango_x_font_cache_new (display);
311   xfontmap->freed_fonts = g_queue_new ();
312
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.");
320
321   /* Insert the font families into the main table */
322   for (i = 0; i < num_fonts; i++)
323     {
324       if (pango_x_is_xlfd_font_name (xfontnames[i]))
325         pango_x_insert_font (xfontmap, xfontnames[i]);
326     }
327
328   XFreeFontNames (xfontnames);
329
330   pango_x_font_map_read_aliases (xfontmap);
331
332   fontmaps = g_list_prepend (fontmaps, xfontmap);
333
334   /* This is a little screwed up, since different screens on the same display
335    * might have different resolutions
336    */
337   screen = DefaultScreen (xfontmap->display);
338   xfontmap->resolution = (PANGO_SCALE * 72.27 / 25.4) * ((double) DisplayWidthMM (xfontmap->display, screen) /
339                                                          DisplayWidth (xfontmap->display, screen));
340
341   register_display (xfontmap->display);
342
343   return PANGO_FONT_MAP (xfontmap);
344 }
345
346 /**
347  * pango_x_shutdown_display:
348  * @display: an X #Display
349  *
350  * Free cached resources for the given X display structure.
351  **/
352 void
353 pango_x_shutdown_display (Display *display)
354 {
355   GList *tmp_list;
356
357   g_return_if_fail (display != NULL);
358
359   tmp_list = fontmaps;
360   while (tmp_list)
361     {
362       PangoXFontMap *xfontmap = tmp_list->data;
363
364       if (xfontmap->display == display)
365         {
366           fontmaps = g_list_delete_link (fontmaps, tmp_list);
367           pango_x_fontmap_cache_clear (xfontmap);
368           g_object_unref (xfontmap);
369
370           return;
371         }
372
373       tmp_list = tmp_list->next;
374     }
375 }
376
377 static void
378 pango_x_font_map_finalize (GObject *object)
379 {
380   PangoXFontMap *xfontmap = PANGO_X_FONT_MAP (object);
381
382   g_list_foreach (xfontmap->freed_fonts->head, (GFunc)g_object_unref, NULL);
383   g_queue_free (xfontmap->freed_fonts);
384
385   pango_x_font_cache_free (xfontmap->font_cache);
386
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);
392   */
393
394   fontmaps = g_list_remove (fontmaps, xfontmap);
395
396   G_OBJECT_CLASS (font_map_parent_class)->finalize (object);
397 }
398
399 static void
400 list_families_foreach (gpointer key G_GNUC_UNUSED,
401                        gpointer value,
402                        gpointer user_data)
403 {
404   GSList **list = user_data;
405
406   *list = g_slist_prepend (*list, value);
407 }
408
409 static void
410 pango_x_font_map_list_families (PangoFontMap           *fontmap,
411                                 PangoFontFamily      ***families,
412                                 int                    *n_families)
413 {
414   GSList *family_list = NULL;
415   GSList *tmp_list;
416   PangoXFontMap *xfontmap = (PangoXFontMap *)fontmap;
417
418   if (!n_families)
419     return;
420
421   g_hash_table_foreach (xfontmap->families, list_families_foreach, &family_list);
422
423   *n_families = g_slist_length (family_list);
424
425   if (families)
426     {
427       int i = 0;
428
429       *families = g_new (PangoFontFamily *, *n_families);
430
431       tmp_list = family_list;
432       while (tmp_list)
433         {
434           (*families)[i] = tmp_list->data;
435           i++;
436           tmp_list = tmp_list->next;
437         }
438     }
439
440   g_slist_free (family_list);
441 }
442
443 static PangoXFamily *
444 pango_x_get_font_family (PangoXFontMap *xfontmap,
445                          const char    *family_name)
446 {
447   PangoXFamily *font_family = g_hash_table_lookup (xfontmap->families, family_name);
448   if (!font_family)
449     {
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;
453
454       g_hash_table_insert (xfontmap->families, font_family->family_name, font_family);
455     }
456
457   return font_family;
458 }
459
460 static PangoFont *
461 pango_x_font_map_load_font (PangoFontMap               *fontmap,
462                             PangoContext               *context G_GNUC_UNUSED,
463                             const PangoFontDescription *description)
464 {
465   PangoXFontMap *xfontmap = (PangoXFontMap *)fontmap;
466   PangoXFamily *font_family;
467   PangoFont *result = NULL;
468   GSList *tmp_list;
469   const gchar *family;
470   gchar *name;
471   gint size;
472
473   g_return_val_if_fail (description != NULL, NULL);
474
475   family = pango_font_description_get_family (description);
476   name = g_ascii_strdown (family ? family : "", -1);
477   size = pango_font_description_get_size (description);
478
479   if (size < 0)
480     return NULL;
481
482   font_family = g_hash_table_lookup (xfontmap->families, name);
483   if (font_family)
484     {
485       PangoXFace *best_match = NULL;
486
487       tmp_list = font_family->font_entries;
488       while (tmp_list)
489         {
490           PangoXFace *font_entry = tmp_list->data;
491
492           if (pango_font_description_better_match (description,
493                                                    best_match ? best_match->description : NULL,
494                                                    font_entry->description))
495             best_match = font_entry;
496
497           tmp_list = tmp_list->next;
498         }
499
500       if (best_match)
501         {
502           GSList *tmp_list = best_match->cached_fonts;
503
504           while (tmp_list)
505             {
506               PangoXFont *xfont = tmp_list->data;
507               if (xfont->size == size)
508                 {
509                   result = (PangoFont *)xfont;
510
511                   g_object_ref (result);
512                   if (xfont->in_cache)
513                     pango_x_fontmap_cache_remove (fontmap, xfont);
514
515                   break;
516                 }
517               tmp_list = tmp_list->next;
518             }
519
520           if (!result)
521             {
522               PangoXFont *xfont = pango_x_font_new (fontmap, best_match->xlfd, size);
523
524               xfont->xface = best_match;
525               best_match->cached_fonts = g_slist_prepend (best_match->cached_fonts, xfont);
526
527               result = (PangoFont *)xfont;
528             }
529         }
530     }
531
532   g_free (name);
533   return result;
534 }
535
536 \f
537 /************************
538  * Coverage Map Caching *
539  ************************/
540
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
545  * XChangeProperty
546  */
547 static gboolean error_occurred;
548
549 static int
550 ignore_error (Display     *d G_GNUC_UNUSED,
551               XErrorEvent *e G_GNUC_UNUSED)
552 {
553   return 0;
554 }
555
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
562  */
563 static Window
564 pango_x_real_get_coverage_win (Display *display)
565 {
566   Atom type;
567   int format;
568   gulong n_items;
569   gulong bytes_after;
570   guchar *data;
571   Window retval = None;
572   int (*old_handler) (Display *, XErrorEvent *);
573
574   Atom coverage_win_atom = XInternAtom (display,
575                                         "PANGO_COVERAGE_WIN",
576                                         False);
577
578   XGetWindowProperty (display,
579                       DefaultRootWindow (display),
580                       coverage_win_atom,
581                       0, 4,
582                       False, XA_WINDOW,
583                       &type, &format, &n_items, &bytes_after,
584                       &data);
585
586   if (type == XA_WINDOW)
587     {
588       if (format == 32 && n_items == 1 && bytes_after == 0)
589         retval = *(Atom *)data;
590
591       XFree (data);
592     }
593
594   old_handler= XSetErrorHandler (ignore_error);
595
596   if (XGetWindowProperty (display,
597                           retval,
598                           coverage_win_atom,
599                           0, 4,
600                           False, XA_WINDOW,
601                           &type, &format, &n_items, &bytes_after,
602                           &data) == Success &&
603       type == XA_WINDOW)
604     {
605       if (format != 32 || n_items != 1 || bytes_after != 0 ||
606           *(Atom *)data != retval)
607         retval = None;
608
609       XFree (data);
610     }
611   else
612     retval = None;
613
614   XSync (display, False);
615   XSetErrorHandler (old_handler);
616
617   return retval;
618 }
619
620 /* Find or create the persistent window for caching font coverage
621  * information.
622  *
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.
626  */
627 static Window
628 pango_x_get_coverage_win (PangoXFontMap *xfontmap)
629 {
630   if (!xfontmap->coverage_win)
631     xfontmap->coverage_win = pango_x_real_get_coverage_win (xfontmap->display);
632
633   if (!xfontmap->coverage_win)
634     {
635       Display *persistant_display;
636
637       persistant_display = XOpenDisplay (DisplayString (xfontmap->display));
638       if (!persistant_display)
639         {
640           g_warning ("Cannot create or retrieve display for font coverage cache");
641           return None;
642         }
643
644       XGrabServer (persistant_display);
645
646       xfontmap->coverage_win = pango_x_real_get_coverage_win (xfontmap->display);
647       if (!xfontmap->coverage_win)
648         {
649           XSetWindowAttributes attr;
650
651           attr.override_redirect = True;
652
653           XSetCloseDownMode (persistant_display, RetainPermanent);
654
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);
661
662           XChangeProperty (persistant_display,
663                            DefaultRootWindow (persistant_display),
664                            XInternAtom (persistant_display,
665                                         "PANGO_COVERAGE_WIN",
666                                         FALSE),
667                            XA_WINDOW,
668                            32, PropModeReplace,
669                            (guchar *)&xfontmap->coverage_win, 1);
670
671
672           XChangeProperty (persistant_display,
673                            xfontmap->coverage_win,
674                            XInternAtom (persistant_display,
675                                         "PANGO_COVERAGE_WIN",
676                                         FALSE),
677                            XA_WINDOW,
678                            32, PropModeReplace,
679                            (guchar *)&xfontmap->coverage_win, 1);
680         }
681
682       XUngrabServer (persistant_display);
683
684       XSync (persistant_display, False);
685       XCloseDisplay (persistant_display);
686     }
687
688   return xfontmap->coverage_win;
689 }
690
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
695  */
696 static PangoCoverage *
697 pango_x_get_cached_coverage (PangoXFontMap *xfontmap,
698                              const char    *str,
699                              Atom          *atom)
700 {
701   int (*old_handler) (Display *, XErrorEvent *);
702   Window coverage_win;
703   PangoCoverage *result = NULL;
704
705   Atom type;
706   int format;
707   int tries = 5;
708   gulong n_items;
709   gulong bytes_after;
710   guchar *data;
711
712   *atom = XInternAtom (xfontmap->display, str, False);
713
714   while (tries--)
715     {
716       coverage_win = pango_x_get_coverage_win (xfontmap);
717
718       if (!coverage_win)
719         return NULL;
720
721       old_handler= XSetErrorHandler (ignore_error);
722
723       if (XGetWindowProperty (xfontmap->display,
724                               coverage_win, *atom,
725                               0, G_MAXLONG,
726                               False, XA_STRING,
727                               &type, &format, &n_items, &bytes_after,
728                               &data) == Success
729           && type == XA_STRING)
730         {
731           if (format == 8 && bytes_after == 0)
732             result = pango_coverage_from_bytes (data, n_items);
733
734           XSetErrorHandler (old_handler);
735           XFree (data);
736           break;
737         }
738       else
739         {
740           /* Window disappeared out from under us */
741           XSetErrorHandler (old_handler);
742           xfontmap->coverage_win = None;
743         }
744
745     }
746
747   return result;
748 }
749
750 /* Store the given coverage map on the coverage cache window.
751  * atom is the intern'ed value of the string that identifies
752  * the cache entry.
753  */
754 static void
755 pango_x_store_cached_coverage (PangoXFontMap *xfontmap,
756                                Atom           atom,
757                                PangoCoverage *coverage)
758 {
759   int (*old_handler) (Display *, XErrorEvent *);
760   guchar *bytes;
761   gint size;
762
763   int tries = 5;
764
765   pango_coverage_to_bytes (coverage, &bytes, &size);
766
767   while (tries--)
768     {
769       Window coverage_win = pango_x_get_coverage_win (xfontmap);
770
771       if (!coverage_win)
772         break;
773
774       old_handler = XSetErrorHandler (ignore_error);
775       error_occurred = False;
776
777       XChangeProperty (xfontmap->display,
778                        coverage_win,
779                        atom,
780                        XA_STRING,
781                        8, PropModeReplace,
782                        bytes, size);
783
784       XSync (xfontmap->display, False);
785       XSetErrorHandler (old_handler);
786
787       if (!error_occurred)
788         break;
789       else
790         {
791           /* Window disappeared out from under us */
792           XSetErrorHandler (old_handler);
793           xfontmap->coverage_win = None;
794         }
795     }
796
797   g_free (bytes);
798 }
799 \f
800
801 static void
802 pango_x_font_map_read_alias_file (PangoXFontMap *xfontmap,
803                                   const char   *filename)
804 {
805   FILE *infile;
806   char **xlfds;
807   int lineno = 0;
808   int i;
809   PangoXFace *xface = NULL;
810
811   infile = fopen (filename, "r");
812   if (infile)
813     {
814       GString *line_buf = g_string_new (NULL);
815       GString *tmp_buf = g_string_new (NULL);
816       gint lines_read;
817
818       while ((lines_read = pango_read_line (infile, line_buf)))
819         {
820           PangoXFamily *font_family;
821           PangoStyle style;
822           PangoVariant variant;
823           PangoWeight weight;
824           PangoStretch stretch;
825
826           const char *p = line_buf->str;
827
828           lineno += lines_read;
829
830           if (!pango_skip_space (&p))
831             continue;
832
833           if (!pango_scan_string (&p, tmp_buf))
834             goto error;
835
836           xface = g_object_new (PANGO_X_TYPE_FACE, NULL);
837           xface->xlfd = NULL;
838           xface->description = pango_font_description_new ();
839
840           g_string_ascii_down (tmp_buf);
841           pango_font_description_set_family (xface->description, tmp_buf->str);
842
843           if (!pango_scan_string (&p, tmp_buf))
844             goto error;
845
846           if (!pango_parse_style (tmp_buf->str, &style, TRUE))
847             goto error;
848           pango_font_description_set_style (xface->description, style);
849
850           if (!pango_scan_string (&p, tmp_buf))
851             goto error;
852
853           if (!pango_parse_variant (tmp_buf->str, &variant, TRUE))
854             goto error;
855           pango_font_description_set_variant (xface->description, variant);
856
857           if (!pango_scan_string (&p, tmp_buf))
858             goto error;
859
860           if (!pango_parse_weight (tmp_buf->str, &weight, TRUE))
861             goto error;
862           pango_font_description_set_weight (xface->description, weight);
863
864           if (!pango_scan_string (&p, tmp_buf))
865             goto error;
866
867           if (!pango_parse_stretch (tmp_buf->str, &stretch, TRUE))
868             goto error;
869           pango_font_description_set_stretch (xface->description, stretch);
870
871           if (!pango_scan_string (&p, tmp_buf))
872             goto error;
873
874           /* Remove excess whitespace and check for complete fields */
875
876           xlfds = g_strsplit (tmp_buf->str, ",", -1);
877           for (i=0; xlfds[i]; i++)
878             {
879               char *trimmed = pango_trim_string (xlfds[i]);
880               g_free (xlfds[i]);
881               xlfds[i] = trimmed;
882
883               if (!pango_x_is_xlfd_font_name (xlfds[i]))
884                 {
885                   g_warning ("XLFD '%s' must be complete (14 fields)", xlfds[i]);
886                   g_strfreev (xlfds);
887                   goto error;
888                 }
889             }
890
891           xface->xlfd = g_strjoinv (",", xlfds);
892           g_strfreev (xlfds);
893
894           /* Insert the font entry into our structures */
895
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);
899           xfontmap->n_fonts++;
900
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;
905         }
906
907       if (ferror (infile))
908         g_warning ("Error reading '%s': %s", filename, g_strerror(errno));
909
910       goto out;
911
912     error:
913       if (xface)
914         {
915           g_free (xface->xlfd);
916           if (xface->description)
917             pango_font_description_free (xface->description);
918           g_free (xface);
919         }
920
921       g_warning ("Error parsing line %d of alias file '%s'", lineno, filename);
922
923     out:
924       g_string_free (tmp_buf, TRUE);
925       g_string_free (line_buf, TRUE);
926
927       fclose (infile);
928     }
929
930 }
931
932 static void
933 pango_x_font_map_read_aliases (PangoXFontMap *xfontmap)
934 {
935   char **files;
936   char *files_str = pango_config_key_get ("PangoX/AliasFiles");
937   int n;
938
939   if (!files_str)
940     files_str = g_strdup ("~/.pangox_aliases:" SYSCONFDIR "/pango/pangox.aliases");
941
942   files = pango_split_file_list (files_str);
943
944   n = 0;
945   while (files[n])
946     n++;
947
948   while (n-- > 0)
949     pango_x_font_map_read_alias_file (xfontmap, files[n]);
950
951   g_strfreev (files);
952   g_free (files_str);
953 }
954
955 /*
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).
960  */
961 static gboolean
962 pango_x_is_xlfd_font_name (const char *fontname)
963 {
964   int i = 0;
965   int field_len = 0;
966
967   while (*fontname)
968     {
969       if (*fontname++ == '-')
970         {
971           if (field_len > XLFD_MAX_FIELD_LEN) return FALSE;
972           field_len = 0;
973           i++;
974         }
975       else
976         field_len++;
977     }
978
979   return (i == 14) ? TRUE : FALSE;
980 }
981
982 static int
983 pango_x_get_size (PangoXFontMap *xfontmap, const char *fontname)
984 {
985   char size_buffer[XLFD_MAX_FIELD_LEN];
986   int size;
987
988   if (!pango_x_get_xlfd_field (fontname, XLFD_PIXELS, size_buffer))
989     return -1;
990
991   size = atoi (size_buffer);
992   if (size != 0)
993     {
994       return (int)(0.5 + size * xfontmap->resolution);
995     }
996   else
997     {
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))
1001         return -1;
1002
1003       if (atoi (size_buffer) == 0)
1004         return 0;
1005       else
1006         return -1;
1007     }
1008 }
1009
1010 static char *
1011 pango_x_get_identifier (const char *fontname)
1012 {
1013   const char *p = fontname;
1014   const char *start;
1015   int n_dashes = 0;
1016
1017   while (n_dashes < 2)
1018     {
1019       if (*p == '-')
1020         n_dashes++;
1021       p++;
1022     }
1023
1024   start = p;
1025
1026   while (n_dashes < 6)
1027     {
1028       if (*p == '-')
1029         n_dashes++;
1030       p++;
1031     }
1032
1033   return g_strndup (start, (p - 1 - start));
1034 }
1035
1036 /*
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'.
1041  */
1042 static char*
1043 pango_x_get_xlfd_field (const char *fontname,
1044                         FontField   field_num,
1045                         char       *buffer)
1046 {
1047   const char *t1, *t2;
1048   char *p;
1049   int countdown, len, num_dashes;
1050
1051   if (!fontname)
1052     return NULL;
1053
1054   /* we assume this is a valid fontname...that is, it has 14 fields */
1055
1056   countdown = field_num;
1057   t1 = fontname;
1058   while (*t1 && (countdown >= 0))
1059     if (*t1++ == '-')
1060       countdown--;
1061
1062   num_dashes = (field_num == XLFD_CHARSET) ? 2 : 1;
1063   for (t2 = t1; *t2; t2++)
1064     {
1065       if (*t2 == '-' && --num_dashes == 0)
1066         break;
1067     }
1068
1069   if (t1 != t2)
1070     {
1071       /* Check we don't overflow the buffer */
1072       len = (long) t2 - (long) t1;
1073       if (len > XLFD_MAX_FIELD_LEN - 1)
1074         return NULL;
1075       strncpy (buffer, t1, len);
1076       buffer[len] = 0;
1077       /* Convert to lower case. */
1078       for (p = buffer; *p; p++)
1079         *p = g_ascii_tolower (*p);
1080     }
1081   else
1082     strcpy(buffer, "(nil)");
1083
1084   return buffer;
1085 }
1086
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. */
1091 static void
1092 pango_x_insert_font (PangoXFontMap *xfontmap,
1093                      const char    *fontname)
1094 {
1095   PangoFontDescription *description;
1096   char *family_name;
1097   PangoStyle style;
1098   PangoVariant variant;
1099   PangoWeight weight;
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];
1105   GSList *tmp_list;
1106   PangoXFamily *font_family;
1107   PangoXFace *xface;
1108   PangoXSizeInfo *size_info;
1109   char *identifier;
1110   unsigned int i;
1111
1112   /* First insert the XLFD into the list of XLFDs for the "identifier" - which
1113    * is the 2-4th fields of the XLFD
1114    */
1115   identifier = pango_x_get_identifier (fontname);
1116   size_info = g_hash_table_lookup (xfontmap->size_infos, identifier);
1117   if (!size_info)
1118     {
1119       size_info = g_slice_new (PangoXSizeInfo);
1120       size_info->identifier = identifier;
1121       size_info->xlfds = NULL;
1122
1123       g_hash_table_insert (xfontmap->size_infos, identifier, size_info);
1124     }
1125   else
1126     g_free (identifier);
1127
1128   size_info->xlfds = g_slist_prepend (size_info->xlfds, g_strdup (fontname));
1129
1130   /* Convert the XLFD into a PangoFontDescription */
1131
1132   family_name = pango_x_get_xlfd_field (fontname, XLFD_FAMILY, family_buffer);
1133   if (!family_name)
1134     return;
1135
1136   style = PANGO_STYLE_NORMAL;
1137   if (pango_x_get_xlfd_field (fontname, XLFD_SLANT, slant_buffer))
1138     {
1139       for (i=0; i<G_N_ELEMENTS(styles_map); i++)
1140         {
1141           if (!strcmp (styles_map[i].text, slant_buffer))
1142             {
1143               style = styles_map[i].value;
1144               break;
1145             }
1146         }
1147     }
1148   else
1149     strcpy (slant_buffer, "*");
1150
1151   variant = PANGO_VARIANT_NORMAL;
1152
1153   weight = PANGO_WEIGHT_NORMAL;
1154   if (pango_x_get_xlfd_field (fontname, XLFD_WEIGHT, weight_buffer))
1155     {
1156       for (i=0; i<G_N_ELEMENTS(weights_map); i++)
1157         {
1158           if (!strcmp (weights_map[i].text, weight_buffer))
1159             {
1160               weight = weights_map[i].value;
1161               break;
1162             }
1163         }
1164     }
1165   else
1166     strcpy (weight_buffer, "*");
1167
1168   stretch = PANGO_STRETCH_NORMAL;
1169   if (pango_x_get_xlfd_field (fontname, XLFD_SET_WIDTH, set_width_buffer))
1170     {
1171       for (i=0; i<G_N_ELEMENTS(stretches_map); i++)
1172         {
1173           if (!strcmp (stretches_map[i].text, set_width_buffer))
1174             {
1175               stretch = stretches_map[i].value;
1176               break;
1177             }
1178         }
1179     }
1180   else
1181     strcpy (set_width_buffer, "*");
1182
1183   font_family = pango_x_get_font_family (xfontmap, family_name);
1184
1185   tmp_list = font_family->font_entries;
1186   while (tmp_list)
1187     {
1188       xface = tmp_list->data;
1189
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)
1194         return;
1195
1196       tmp_list = tmp_list->next;
1197     }
1198
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);
1205
1206   xface = g_object_new (PANGO_X_TYPE_FACE, NULL);
1207   xface->description = description;
1208   xface->cached_fonts = NULL;
1209   xface->coverage = NULL;
1210
1211   xface->xlfd = g_strconcat ("-*-",
1212                                   family_buffer,
1213                                   "-",
1214                                   weight_buffer,
1215                                   "-",
1216                                   slant_buffer,
1217                                   "-",
1218                                   set_width_buffer,
1219                                   "--*-*-*-*-*-*-*-*",
1220                                   NULL);
1221
1222   font_family->font_entries = g_slist_append (font_family->font_entries, xface);
1223   xfontmap->n_fonts++;
1224 }
1225
1226 /* Compare the tail of a to b */
1227 static gboolean
1228 match_end (const char *a, const char *b)
1229 {
1230   size_t len_a = strlen (a);
1231   size_t len_b = strlen (b);
1232
1233   if (len_b > len_a)
1234     return FALSE;
1235   else
1236     return (strcmp (a + len_a - len_b, b) == 0);
1237 }
1238
1239 /* Given a XLFD, charset and size, find the best matching installed X font.
1240  * The XLFD must be a full XLFD (14 fields)
1241  */
1242 char *
1243 pango_x_make_matching_xlfd (PangoFontMap *fontmap, char *xlfd, const char *charset, int size)
1244 {
1245   PangoXFontMap *xfontmap;
1246
1247   GSList *tmp_list;
1248   PangoXSizeInfo *size_info;
1249   char *identifier;
1250   char *closest_match = NULL;
1251   gint match_distance = 0;
1252   gboolean match_scaleable = FALSE;
1253   char *result = NULL;
1254
1255   char *dash_charset;
1256
1257   xfontmap = PANGO_X_FONT_MAP (fontmap);
1258
1259   dash_charset = g_strconcat ("-", charset, NULL);
1260
1261   if (!match_end (xlfd, "-*-*") && !match_end (xlfd, dash_charset))
1262     {
1263       g_free (dash_charset);
1264       return NULL;
1265     }
1266
1267   identifier = pango_x_get_identifier (xlfd);
1268   size_info = g_hash_table_lookup (xfontmap->size_infos, identifier);
1269   g_free (identifier);
1270
1271   if (!size_info)
1272     {
1273       g_free (dash_charset);
1274       return NULL;
1275     }
1276
1277   tmp_list = size_info->xlfds;
1278   while (tmp_list)
1279     {
1280       char *tmp_xlfd = tmp_list->data;
1281
1282       if (match_end (tmp_xlfd, dash_charset))
1283         {
1284           int font_size = pango_x_get_size (xfontmap, tmp_xlfd);
1285
1286           if (size != -1)
1287             {
1288               int new_distance = (font_size == 0) ? 0 : abs (font_size - size);
1289
1290               if (!closest_match ||
1291                   new_distance < match_distance ||
1292                   (new_distance < PANGO_SCALE && match_scaleable && font_size != 0))
1293                 {
1294                   closest_match = tmp_xlfd;
1295                   match_scaleable = (font_size == 0);
1296                   match_distance = new_distance;
1297                 }
1298             }
1299         }
1300
1301       tmp_list = tmp_list->next;
1302     }
1303
1304   if (closest_match)
1305     {
1306       if (match_scaleable)
1307         {
1308           char *prefix_end, *p;
1309           int n_dashes = 0;
1310           int target_size;
1311           char *prefix;
1312
1313           /* OK, we have a match; let's modify it to fit this size and charset */
1314
1315           p = closest_match;
1316           while (n_dashes < 6)
1317             {
1318               if (*p == '-')
1319                 n_dashes++;
1320               p++;
1321             }
1322
1323           prefix_end = p - 1;
1324
1325           while (n_dashes < 9)
1326             {
1327               if (*p == '-')
1328                 n_dashes++;
1329               p++;
1330             }
1331
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);
1335           g_free (prefix);
1336         }
1337       else
1338         {
1339           result = g_strdup (closest_match);
1340         }
1341     }
1342
1343   g_free (dash_charset);
1344
1345   return result;
1346 }
1347
1348 /**
1349  * pango_x_font_map_get_font_cache:
1350  * @font_map: a #PangoXFontMap.
1351  *
1352  * Obtains the font cache associated with the given font map.
1353  *
1354  * Return value: the #PangoXFontCache of @font_map.
1355  **/
1356 PangoXFontCache *
1357 pango_x_font_map_get_font_cache (PangoFontMap *font_map)
1358 {
1359   g_return_val_if_fail (font_map != NULL, NULL);
1360   g_return_val_if_fail (PANGO_X_IS_FONT_MAP (font_map), NULL);
1361
1362   return PANGO_X_FONT_MAP (font_map)->font_cache;
1363 }
1364
1365 Display *
1366 pango_x_fontmap_get_display (PangoFontMap    *fontmap)
1367 {
1368   g_return_val_if_fail (fontmap != NULL, NULL);
1369   g_return_val_if_fail (PANGO_X_IS_FONT_MAP (fontmap), NULL);
1370
1371   return PANGO_X_FONT_MAP (fontmap)->display;
1372 }
1373
1374 void
1375 pango_x_fontmap_cache_add (PangoFontMap    *fontmap,
1376                            PangoXFont      *xfont)
1377 {
1378   PangoXFontMap *xfontmap = PANGO_X_FONT_MAP (fontmap);
1379
1380   if (xfontmap->freed_fonts->length == MAX_FREED_FONTS)
1381     {
1382       PangoXFont *old_font = g_queue_pop_tail (xfontmap->freed_fonts);
1383       g_object_unref (old_font);
1384     }
1385
1386   g_object_ref (xfont);
1387   g_queue_push_head (xfontmap->freed_fonts, xfont);
1388   xfont->in_cache = TRUE;
1389 }
1390
1391 void
1392 pango_x_fontmap_cache_remove (PangoFontMap    *fontmap,
1393                               PangoXFont      *xfont)
1394 {
1395   PangoXFontMap *xfontmap = PANGO_X_FONT_MAP (fontmap);
1396
1397   GList *link = g_list_find (xfontmap->freed_fonts->head, xfont);
1398   if (link == xfontmap->freed_fonts->tail)
1399     {
1400       xfontmap->freed_fonts->tail = xfontmap->freed_fonts->tail->prev;
1401       if (xfontmap->freed_fonts->tail)
1402         xfontmap->freed_fonts->tail->next = NULL;
1403     }
1404
1405   xfontmap->freed_fonts->head = g_list_delete_link (xfontmap->freed_fonts->head, link);
1406   xfontmap->freed_fonts->length--;
1407   xfont->in_cache = FALSE;
1408
1409   g_object_unref (xfont);
1410 }
1411
1412 static void
1413 pango_x_fontmap_cache_clear (PangoXFontMap   *xfontmap)
1414 {
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;
1420 }
1421
1422
1423 Atom
1424 pango_x_fontmap_atom_from_name (PangoFontMap *fontmap,
1425                                 const char   *atomname)
1426 {
1427   PangoXFontMap *xfm = PANGO_X_FONT_MAP(fontmap);
1428   gpointer found;
1429   Atom atom;
1430
1431   found = g_hash_table_lookup (xfm->to_atom_cache, atomname);
1432
1433   if (found)
1434     return (Atom)(GPOINTER_TO_UINT(found));
1435
1436   atom = XInternAtom (xfm->display, atomname, FALSE);
1437   g_hash_table_insert (xfm->to_atom_cache, g_strdup (atomname),
1438                        (gpointer)atom);
1439
1440   return atom;
1441 }
1442
1443
1444 G_CONST_RETURN char *
1445 pango_x_fontmap_name_from_atom (PangoFontMap *fontmap,
1446                                 Atom          atom)
1447 {
1448   PangoXFontMap *xfm = PANGO_X_FONT_MAP(fontmap);
1449   gpointer found;
1450   char *name, *name2;
1451
1452   found = g_hash_table_lookup (xfm->from_atom_cache, GUINT_TO_POINTER(atom));
1453
1454   if (found)
1455     return (const char *)found;
1456
1457   name = XGetAtomName (xfm->display, atom);
1458   name2 = g_strdup (name);
1459   XFree (name);
1460
1461   g_hash_table_insert (xfm->from_atom_cache, (gpointer)atom, name2);
1462
1463   return name2;
1464 }
1465
1466 /*
1467  * PangoXFace
1468  */
1469
1470 static PangoFontDescription *
1471 pango_x_face_describe (PangoFontFace *face)
1472 {
1473   PangoXFace *xface = PANGO_X_FACE (face);
1474
1475   return pango_font_description_copy (xface->description);
1476 }
1477
1478 static const char *
1479 pango_x_face_get_face_name (PangoFontFace *face)
1480 {
1481   PangoXFace *xface = PANGO_X_FACE (face);
1482
1483   if (!xface->face_name)
1484     {
1485       PangoFontDescription *desc = pango_font_face_describe (face);
1486
1487       pango_font_description_unset_fields (desc,
1488                                            PANGO_FONT_MASK_FAMILY | PANGO_FONT_MASK_SIZE);
1489
1490       xface->face_name = pango_font_description_to_string (desc);
1491       pango_font_description_free (desc);
1492     }
1493
1494   return xface->face_name;
1495 }
1496
1497 static void
1498 pango_x_face_class_init (PangoFontFaceClass *class)
1499 {
1500   class->describe = pango_x_face_describe;
1501   class->get_face_name = pango_x_face_get_face_name;
1502 }
1503
1504 GType
1505 pango_x_face_get_type (void)
1506 {
1507   static GType object_type = 0;
1508
1509   if (G_UNLIKELY (!object_type))
1510     {
1511       const GTypeInfo object_info =
1512       {
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 */
1523       };
1524
1525       object_type = g_type_register_static (PANGO_TYPE_FONT_FACE,
1526                                             I_("PangoXFace"),
1527                                             &object_info, 0);
1528     }
1529
1530   return object_type;
1531 }
1532
1533 /* Cut and paste here to avoid an inter-module dependency */
1534 static PangoCoverageLevel
1535 engine_shape_covers (PangoEngineShape *engine,
1536                      PangoFont        *font,
1537                      PangoLanguage    *language,
1538                      gunichar          wc)
1539 {
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);
1542
1543   return PANGO_ENGINE_SHAPE_GET_CLASS (engine)->covers (engine,
1544                                                         font,
1545                                                         language,
1546                                                         wc);
1547 }
1548
1549 PangoCoverage *
1550 pango_x_face_get_coverage (PangoXFace      *xface,
1551                            PangoFont       *font,
1552                            PangoLanguage   *language)
1553 {
1554   PangoXFont *xfont;
1555   PangoXFontMap *xfontmap = NULL; /* Quiet gcc */
1556   PangoCoverage *result = NULL;
1557   Atom atom = None;
1558
1559   if (xface)
1560     {
1561       if (xface->coverage)
1562         {
1563           pango_coverage_ref (xface->coverage);
1564           return xface->coverage;
1565         }
1566
1567       xfont = (PangoXFont *)font;
1568
1569       xfontmap = (PangoXFontMap *)pango_x_font_map_for_display (xfont->display);
1570       if (xface->xlfd)
1571         {
1572           const char *lang_str = language ? pango_language_to_string (language) : "*";
1573
1574           char *str = g_strconcat (lang_str, "|", xface->xlfd, NULL);
1575           result = pango_x_get_cached_coverage (xfontmap, str, &atom);
1576           g_free (str);
1577         }
1578     }
1579
1580   if (!result)
1581     {
1582       PangoMap *shape_map;
1583       PangoEngineShape *engine;
1584       gunichar wc;
1585
1586       result = pango_coverage_new ();
1587
1588       shape_map = pango_x_get_shaper_map (language);
1589       engine = (PangoEngineShape *)pango_map_get_engine (shape_map, PANGO_SCRIPT_COMMON);
1590
1591       for (wc = 0; wc < 65536; wc++)
1592         {
1593           PangoCoverageLevel level;
1594
1595           level = engine_shape_covers (engine, font, language, wc);
1596           if (level != PANGO_COVERAGE_NONE)
1597             pango_coverage_set (result, wc, level);
1598         }
1599
1600       if (atom)
1601         pango_x_store_cached_coverage (xfontmap, atom, result);
1602     }
1603
1604   if (xface)
1605     {
1606       xface->coverage = result;
1607       pango_coverage_ref (result);
1608     }
1609
1610   return result;
1611 }
1612
1613 void
1614 pango_x_face_remove (PangoXFace  *xface,
1615                      PangoFont   *font)
1616 {
1617   xface->cached_fonts = g_slist_remove (xface->cached_fonts, font);
1618 }
1619
1620 /*
1621  * PangoXFontFamily
1622  */
1623
1624 static void
1625 pango_x_family_list_faces (PangoFontFamily  *family,
1626                            PangoFontFace  ***faces,
1627                            int              *n_faces)
1628 {
1629   PangoXFamily *xfamily = PANGO_X_FAMILY (family);
1630
1631   *n_faces = g_slist_length (xfamily->font_entries);
1632   if (faces)
1633     {
1634       GSList *tmp_list;
1635       int i = 0;
1636
1637       *faces = g_new (PangoFontFace *, *n_faces);
1638
1639       tmp_list = xfamily->font_entries;
1640       while (tmp_list)
1641         {
1642           (*faces)[i++] = tmp_list->data;
1643           tmp_list = tmp_list->next;
1644         }
1645     }
1646 }
1647
1648 static G_CONST_RETURN char *
1649 pango_x_family_get_name (PangoFontFamily  *family)
1650 {
1651   PangoXFamily *xfamily = PANGO_X_FAMILY (family);
1652
1653   return xfamily->family_name;
1654 }
1655
1656 static void
1657 pango_x_family_class_init (PangoFontFamilyClass *class)
1658 {
1659   class->list_faces = pango_x_family_list_faces;
1660   class->get_name = pango_x_family_get_name;
1661 }
1662
1663 GType
1664 pango_x_family_get_type (void)
1665 {
1666   static GType object_type = 0;
1667
1668   if (G_UNLIKELY (!object_type))
1669     {
1670       const GTypeInfo object_info =
1671       {
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 */
1682       };
1683
1684       object_type = g_type_register_static (PANGO_TYPE_FONT_FAMILY,
1685                                             I_("PangoXFamily"),
1686                                             &object_info, 0);
1687     }
1688
1689   return object_type;
1690 }
1691