1 /* Pango
2  * pangowin32-fontmap.c: Win32 font handling
3  *
4  * Copyright (C) 2000 Red Hat Software
5  * Copyright (C) 2000 Tor Lillqvist
6  * Copyright (C) 2001 Alexander Larsson
7  * Copyright (C) 2007 Novell, Inc.
8  *
9  * This library is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Library General Public
11  * License as published by the Free Software Foundation; either
12  * version 2 of the License, or (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the GNU
17  * Library General Public License for more details.
18  *
19  * You should have received a copy of the GNU Library General Public
20  * License along with this library; if not, write to the
21  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
22  * Boston, MA 02111-1307, USA.
23  */
24 
25 #include "config.h"
26 
27 #include <ctype.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <errno.h>
32 #include <glib/gstdio.h>
33 
34 #include "pango-fontmap.h"
35 #include "pango-impl-utils.h"
36 #include "pangowin32-private.h"
37 
38 typedef struct _PangoWin32Family PangoWin32Family;
39 typedef PangoFontFamilyClass PangoWin32FamilyClass;
40 
41 struct _PangoWin32Family
42 {
43   PangoFontFamily parent_instance;
44 
45   char *family_name;
46   GSList *faces;
47 
48   gboolean is_monospace;
49 };
50 
51 
52 #if !defined(NTM_PS_OPENTYPE)
53 # define NTM_PS_OPENTYPE 0x20000
54 #endif
55 
56 #if !defined(NTM_TYPE1)
57 # define NTM_TYPE1 0x100000
58 #endif
59 
60 #define PANGO_WIN32_TYPE_FAMILY              (pango_win32_family_get_type ())
61 #define PANGO_WIN32_FAMILY(object)           (G_TYPE_CHECK_INSTANCE_CAST ((object), PANGO_WIN32_TYPE_FAMILY, PangoWin32Family))
62 #define PANGO_WIN32_IS_FAMILY (object)       (G_TYPE_CHECK_INSTANCE_TYPE ((object), PANGO_WIN32_TYPE_FAMILY))
63 #define PANGO_WIN32_FAMILY_CLASS (klass)     (G_TYPE_CHECK_CLASS_CAST (klass), PANGO_WIN32_TYPE_FAMILY, PangoWin32Family))
64 #define PANGO_WIN32_IS_FAMILY_CLASS (klass)  (G_TYPE_CHECK_CLASS_CAST (klass), PANGO_WIN32_TYPE_FAMILY))
65 #define PANGO_WIN32_FAMILY_GET_CLASS(object) (G_TYPE_INSTANCE_GET_CLASS((object), PANGO_WIN32_FAMILY, PangoWin32FamilyClass))
66 
67 #define PANGO_WIN32_TYPE_FACE              (pango_win32_face_get_type ())
68 #define PANGO_WIN32_FACE(object)           (G_TYPE_CHECK_INSTANCE_CAST ((object), PANGO_WIN32_TYPE_FACE, PangoWin32Face))
69 #define PANGO_WIN32_IS_FACE(object)        (G_TYPE_CHECK_INSTANCE_TYPE ((object), PANGO_WIN32_TYPE_FACE))
70 #define PANGO_WIN32_FACE_CLASS (klass)     (G_TYPE_CHECK_CLASS_CAST (klass), PANGO_WIN32_TYPE_FACE, PangoWin32Face))
71 #define PANGO_WIN32_IS_FACE_CLASS (klass)  (G_TYPE_CHECK_CLASS_CAST (klass), PANGO_WIN32_TYPE_FACE))
72 #define PANGO_WIN32_FACE_GET_CLASS(object) (G_TYPE_INSTANCE_GET_CLASS((object), PANGO_WIN32_FACE, PangoWin32FaceClass))
73 
74 static GType      pango_win32_face_get_type          (void);
75 
76 static GType      pango_win32_family_get_type        (void);
77 
78 static void       pango_win32_face_list_sizes        (PangoFontFace  *face,
79                                                       int           **sizes,
80                                                       int            *n_sizes);
81 
82 static void       pango_win32_font_map_finalize      (GObject                      *object);
83 static PangoFont *pango_win32_font_map_load_font     (PangoFontMap                 *fontmap,
84                                                       PangoContext                 *context,
85                                                       const PangoFontDescription   *description);
86 static PangoFontset *pango_win32_font_map_load_fontset (PangoFontMap               *fontmap,
87                                                         PangoContext                 *context,
88                                                         const PangoFontDescription   *desc,
89                                                         PangoLanguage                *language);
90 static void       pango_win32_font_map_list_families (PangoFontMap                 *fontmap,
91                                                       PangoFontFamily            ***families,
92                                                       int                          *n_families);
93 
94 static PangoFont *pango_win32_font_map_real_find_font (PangoWin32FontMap           *win32fontmap,
95                                                        PangoContext                *context,
96                                                        PangoWin32Face              *face,
97                                                        const PangoFontDescription  *description);
98 
99 static void       pango_win32_fontmap_cache_clear    (PangoWin32FontMap            *win32fontmap);
100 
101 static void       pango_win32_insert_font            (PangoWin32FontMap            *fontmap,
102                                                       LOGFONTW                     *lfp,
103                                                       gboolean                      is_synthetic);
104 
105 static PangoWin32Family *pango_win32_get_font_family (PangoWin32FontMap            *win32fontmap,
106                                                       const char                   *family_name);
107 
108 static const char *pango_win32_face_get_face_name    (PangoFontFace *face);
109 
110 static PangoWin32FontMap *default_fontmap = NULL; /* MT-safe */
111 
G_DEFINE_TYPE(PangoWin32FontMap,_pango_win32_font_map,PANGO_TYPE_FONT_MAP)112 G_DEFINE_TYPE (PangoWin32FontMap, _pango_win32_font_map, PANGO_TYPE_FONT_MAP)
113 
114 #define TOLOWER(c) \
115   (((c) >= 'A' && (c) <= 'Z') ? (c) - 'A' + 'a' : (c))
116 
117 static guint
118 case_insensitive_str_hash (const char *key)
119 {
120   const char *p = key;
121   guint h = TOLOWER (*p);
122 
123   if (h)
124     {
125       for (p += 1; *p != '\0'; p++)
126         h = (h << 5) - h + TOLOWER (*p);
127     }
128 
129   return h;
130 }
131 
132 static gboolean
case_insensitive_str_equal(const char * key1,const char * key2)133 case_insensitive_str_equal (const char *key1,
134                             const char *key2)
135 {
136   while (*key1 && *key2 && TOLOWER (*key1) == TOLOWER (*key2))
137     key1++, key2++;
138   return (!*key1 && !*key2);
139 }
140 
141 static guint
case_insensitive_wcs_hash(const wchar_t * key)142 case_insensitive_wcs_hash (const wchar_t *key)
143 {
144   const wchar_t *p = key;
145   guint h = TOLOWER (*p);
146 
147   if (h)
148     {
149       for (p += 1; *p != '\0'; p++)
150         h = (h << 5) - h + TOLOWER (*p);
151     }
152 
153   return h;
154 }
155 
156 static gboolean
case_insensitive_wcs_equal(const wchar_t * key1,const wchar_t * key2)157 case_insensitive_wcs_equal (const wchar_t *key1,
158                             const wchar_t *key2)
159 {
160   while (*key1 && *key2 && TOLOWER (*key1) == TOLOWER (*key2))
161     key1++, key2++;
162   return (!*key1 && !*key2);
163 }
164 
165 /* A hash function for LOGFONTWs that takes into consideration only
166  * those fields that indicate a specific .ttf file is in use:
167  * lfFaceName, lfItalic and lfWeight. Dunno how correct this is.
168  */
169 static guint
logfontw_nosize_hash(const LOGFONTW * lfp)170 logfontw_nosize_hash (const LOGFONTW *lfp)
171 {
172   return case_insensitive_wcs_hash (lfp->lfFaceName) + (lfp->lfItalic != 0) + lfp->lfWeight;
173 }
174 
175 /* Ditto comparison function */
176 static gboolean
logfontw_nosize_equal(const LOGFONTW * lfp1,const LOGFONTW * lfp2)177 logfontw_nosize_equal (const LOGFONTW *lfp1,
178                        const LOGFONTW *lfp2)
179 {
180   return (case_insensitive_wcs_equal (lfp1->lfFaceName, lfp2->lfFaceName) &&
181           (lfp1->lfItalic != 0) == (lfp2->lfItalic != 0) &&
182           lfp1->lfWeight == lfp2->lfWeight);
183 }
184 
185 static int CALLBACK
pango_win32_inner_enum_proc(LOGFONTW * lfp,TEXTMETRICW * metrics,DWORD fontType,LPARAM lParam)186 pango_win32_inner_enum_proc (LOGFONTW    *lfp,
187                              TEXTMETRICW *metrics,
188                              DWORD        fontType,
189                              LPARAM       lParam)
190 {
191   PangoWin32FontMap *win32fontmap = (PangoWin32FontMap *)lParam;
192 
193   /* Windows generates synthetic vertical writing versions of East
194    * Asian fonts with @ prepended to their name, ignore them.
195    */
196   if (lfp->lfFaceName[0] != '@')
197     pango_win32_insert_font (win32fontmap, lfp, FALSE);
198 
199   return 1;
200 }
201 
202 struct EnumProcData
203 {
204   HDC hdc;
205   PangoWin32FontMap *font_map;
206 };
207 
208 static int CALLBACK
pango_win32_enum_proc(LOGFONTW * lfp,NEWTEXTMETRICW * metrics,DWORD fontType,LPARAM lParam)209 pango_win32_enum_proc (LOGFONTW       *lfp,
210                        NEWTEXTMETRICW *metrics,
211                        DWORD           fontType,
212                        LPARAM          lParam)
213 {
214   LOGFONTW lf;
215   struct EnumProcData *data = (struct EnumProcData *) lParam;
216 
217   PING (("%S: %lu %lx", lfp->lfFaceName, fontType, metrics->ntmFlags));
218 
219   if (fontType == TRUETYPE_FONTTYPE || ((metrics->ntmFlags & NTM_PS_OPENTYPE) || (metrics->ntmFlags & NTM_TYPE1)))
220     {
221       lf = *lfp;
222 
223       EnumFontFamiliesExW (data->hdc, &lf,
224                            (FONTENUMPROCW) pango_win32_inner_enum_proc,
225                            (LPARAM) data->font_map, 0);
226     }
227 
228   return 1;
229 }
230 
231 static void
synthesize_foreach(gpointer key,gpointer value,gpointer user_data)232 synthesize_foreach (gpointer key,
233                     gpointer value,
234                     gpointer user_data)
235 {
236   PangoWin32Family *win32family = value;
237   PangoWin32FontMap *win32fontmap = user_data;
238 
239   enum { NORMAL, BOLDER, SLANTED };
240   PangoWin32Face *variant[4] = { NULL, NULL, NULL, NULL };
241 
242   GSList *p;
243 
244   LOGFONTW lf;
245 
246   p = win32family->faces;
247   while (p)
248     {
249       PangoWin32Face *win32face = p->data;
250 
251       /* Don't synthesize anything unless it's a monospace, serif, or sans font */
252       if (!((win32face->logfontw.lfPitchAndFamily & 0xF0) == FF_MODERN ||
253           (win32face->logfontw.lfPitchAndFamily & 0xF0) == FF_ROMAN ||
254           (win32face->logfontw.lfPitchAndFamily & 0xF0) == FF_SWISS))
255         return;
256 
257       if (pango_font_description_get_weight (win32face->description) == PANGO_WEIGHT_NORMAL &&
258           pango_font_description_get_style (win32face->description) == PANGO_STYLE_NORMAL)
259         variant[NORMAL] = win32face;
260 
261       if (pango_font_description_get_weight (win32face->description) > PANGO_WEIGHT_NORMAL &&
262           pango_font_description_get_style (win32face->description) == PANGO_STYLE_NORMAL)
263         variant[BOLDER] = win32face;
264 
265       if (pango_font_description_get_weight (win32face->description) == PANGO_WEIGHT_NORMAL &&
266           pango_font_description_get_style (win32face->description) >= PANGO_STYLE_OBLIQUE)
267         variant[SLANTED] = win32face;
268 
269       if (pango_font_description_get_weight (win32face->description) > PANGO_WEIGHT_NORMAL &&
270           pango_font_description_get_style (win32face->description) >= PANGO_STYLE_OBLIQUE)
271         variant[BOLDER+SLANTED] = win32face;
272 
273       p = p->next;
274     }
275 
276   if (variant[NORMAL] != NULL && variant[BOLDER] == NULL)
277     {
278       lf = variant[NORMAL]->logfontw;
279       lf.lfWeight = FW_BOLD;
280 
281       pango_win32_insert_font (win32fontmap, &lf, TRUE);
282     }
283 
284   if (variant[NORMAL] != NULL && variant[SLANTED] == NULL)
285     {
286       lf = variant[NORMAL]->logfontw;
287       lf.lfItalic = 255;
288 
289       pango_win32_insert_font (win32fontmap, &lf, TRUE);
290     }
291 
292   if (variant[NORMAL] != NULL &&
293       variant[BOLDER+SLANTED] == NULL)
294     {
295       lf = variant[NORMAL]->logfontw;
296       lf.lfWeight = FW_BOLD;
297       lf.lfItalic = 255;
298 
299       pango_win32_insert_font (win32fontmap, &lf, TRUE);
300     }
301   else if (variant[BOLDER] != NULL &&
302            variant[BOLDER+SLANTED] == NULL)
303     {
304       lf = variant[BOLDER]->logfontw;
305       lf.lfItalic = 255;
306 
307       pango_win32_insert_font (win32fontmap, &lf, TRUE);
308     }
309   else if (variant[SLANTED] != NULL &&
310            variant[BOLDER+SLANTED] == NULL)
311     {
312       lf = variant[SLANTED]->logfontw;
313       lf.lfWeight = FW_BOLD;
314 
315       pango_win32_insert_font (win32fontmap, &lf, TRUE);
316     }
317 }
318 
319 struct PangoAlias
320 {
321   char *alias;
322   int n_families;
323   char **families;
324   gboolean visible; /* Do we want/need this? */
325 };
326 
327 static guint
alias_hash(struct PangoAlias * alias)328 alias_hash (struct PangoAlias *alias)
329 {
330   return g_str_hash (alias->alias);
331 }
332 
333 static gboolean
alias_equal(struct PangoAlias * alias1,struct PangoAlias * alias2)334 alias_equal (struct PangoAlias *alias1,
335              struct PangoAlias *alias2)
336 {
337   return g_str_equal (alias1->alias,
338                       alias2->alias);
339 }
340 
341 static void
alias_free(struct PangoAlias * alias)342 alias_free (struct PangoAlias *alias)
343 {
344   int i;
345   g_free (alias->alias);
346 
347   for (i = 0; i < alias->n_families; i++)
348     g_free (alias->families[i]);
349 
350   g_free (alias->families);
351 
352   g_slice_free (struct PangoAlias, alias);
353 }
354 
355 static void
handle_alias_line(GString * line_buffer,char ** errstring,GHashTable * ht_aliases)356 handle_alias_line (GString    *line_buffer,
357                    char       **errstring,
358                    GHashTable *ht_aliases)
359 {
360   GString *tmp_buffer1;
361   GString *tmp_buffer2;
362   const char *pos;
363   struct PangoAlias alias_key;
364   struct PangoAlias *alias;
365   gboolean append = FALSE;
366   char **new_families;
367   int n_new;
368   int i;
369 
370   tmp_buffer1 = g_string_new (NULL);
371   tmp_buffer2 = g_string_new (NULL);
372 
373   pos = line_buffer->str;
374   if (!pango_skip_space (&pos))
375     return;
376 
377   if (!pango_scan_string (&pos, tmp_buffer1) ||
378       !pango_skip_space (&pos))
379     {
380       *errstring = g_strdup ("Line is not of the form KEY=VALUE or KEY+=VALUE");
381       goto error;
382     }
383 
384   if (*pos == '+')
385     {
386       append = TRUE;
387       pos++;
388     }
389 
390   if (*(pos++) != '=')
391     {
392       *errstring = g_strdup ("Line is not of the form KEY=VALUE or KEY+=VALUE");
393       goto error;
394     }
395 
396   if (!pango_scan_string (&pos, tmp_buffer2))
397     {
398       *errstring = g_strdup ("Error parsing value string");
399       goto error;
400     }
401   if (pango_skip_space (&pos))
402     {
403       *errstring = g_strdup ("Junk after value string");
404       goto error;
405     }
406 
407   alias_key.alias = g_ascii_strdown (tmp_buffer1->str, -1);
408 
409   /* Remove any existing values */
410   alias = g_hash_table_lookup (ht_aliases, &alias_key);
411 
412   if (!alias)
413     {
414       alias = g_slice_new0 (struct PangoAlias);
415       alias->alias = alias_key.alias;
416 
417       g_hash_table_insert (ht_aliases, alias, alias);
418     }
419   else
420     g_free (alias_key.alias);
421 
422   new_families = g_strsplit (tmp_buffer2->str, ",", -1);
423 
424   n_new = 0;
425   while (new_families[n_new])
426     n_new++;
427 
428   if (alias->families && append)
429     {
430       alias->families = g_realloc (alias->families,
431                                    sizeof (char *) *(n_new + alias->n_families));
432       for (i = 0; i < n_new; i++)
433         alias->families[alias->n_families + i] = new_families[i];
434       g_free (new_families);
435       alias->n_families += n_new;
436     }
437   else
438     {
439       for (i = 0; i < alias->n_families; i++)
440         g_free (alias->families[i]);
441       g_free (alias->families);
442 
443       alias->families = new_families;
444       alias->n_families = n_new;
445     }
446 
447  error:
448 
449   g_string_free (tmp_buffer1, TRUE);
450   g_string_free (tmp_buffer2, TRUE);
451 }
452 
453 #ifdef HAVE_CAIRO_WIN32
454 
455 static const char * const builtin_aliases[] = {
456   "courier = \"courier new\"",
457   /* It sucks to use the same GulimChe, MS Gothic, Sylfaen, Kartika,
458    * Latha, Mangal and Raavi fonts for all three of sans, serif and
459    * mono, but it isn't like there would be much choice. For most
460    * non-Latin scripts that Windows includes any font at all for, it
461    * has ony one. One solution is to install the free DejaVu fonts
462    * that are popular on Linux. They are listed here first.
463    */
464   "sans = \"dejavu sans,tahoma,arial unicode ms,lucida sans unicode,browallia new,mingliu,simhei,gulimche,ms gothic,sylfaen,kartika,latha,mangal,raavi\"",
465   "sans-serif = \"dejavu sans,tahoma,arial unicode ms,lucida sans unicode,browallia new,mingliu,simhei,gulimche,ms gothic,sylfaen,kartika,latha,mangal,raavi\"",
466   "serif = \"dejavu serif,georgia,angsana new,mingliu,simsun,gulimche,ms gothic,sylfaen,kartika,latha,mangal,raavi\"",
467  "mono = \"dejavu sans mono,courier new,lucida console,courier monothai,mingliu,simsun,gulimche,ms gothic,sylfaen,kartika,latha,mangal,raavi\"",
468   "monospace = \"dejavu sans mono,courier new,lucida console,courier monothai,mingliu,simsun,gulimche,ms gothic,sylfaen,kartika,latha,mangal,raavi\"",
469   "emoji = \"segoe ui emoji,segoe ui symbol,segoe ui\"",
470   "cursive = \"comic sans ms\"",
471   "fantasy = \"gabriola,impact\"",
472   "system-ui = \"yu gothic ui,segoe ui,meiryo\"",
473 };
474 
475 static void
read_builtin_aliases(GHashTable * ht_aliases)476 read_builtin_aliases (GHashTable *ht_aliases)
477 {
478 
479   GString *line_buffer;
480   char *errstring = NULL;
481   int line;
482 
483   line_buffer = g_string_new (NULL);
484 
485   for (line = 0; line < G_N_ELEMENTS (builtin_aliases) && errstring == NULL; line++)
486     {
487       g_string_assign (line_buffer, builtin_aliases[line]);
488       handle_alias_line (line_buffer, &errstring, ht_aliases);
489     }
490 
491   if (errstring)
492     {
493       g_error ("error in built-in aliases:%d: %s\n", line, errstring);
494       g_free (errstring);
495     }
496 
497   g_string_free (line_buffer, TRUE);
498 }
499 
500 #define MAX_VALUE_NAME 16383
501 
502 static void
read_windows_fallbacks(GHashTable * ht_aliases)503 read_windows_fallbacks (GHashTable *ht_aliases)
504 {
505   DWORD value_index;
506   HKEY hkey;
507   LSTATUS status;
508   GString *line_buffer;
509 
510   /* https://docs.microsoft.com/en-us/globalization/input/font-technology */
511   status = RegOpenKeyExW (HKEY_LOCAL_MACHINE,
512                           L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\FontLink\\SystemLink",
513                           0,
514                           KEY_READ,
515                           &hkey);
516   if (status != ERROR_SUCCESS)
517     return;
518 
519   line_buffer = g_string_new (NULL);
520   status = ERROR_SUCCESS;
521   for (value_index = 0; status != ERROR_NO_MORE_ITEMS; value_index++)
522     {
523       wchar_t name[MAX_VALUE_NAME];
524       DWORD name_length = MAX_VALUE_NAME, value_length = 0;
525       char *errstring = NULL;
526       gchar *utf8_name;
527       wchar_t *value_data, *entry;
528       size_t entry_len;
529 
530       status = RegEnumValueW (hkey, value_index, name, &name_length,
531                               NULL, NULL, NULL, NULL);
532 
533       if (status != ERROR_SUCCESS)
534         continue;
535 
536       utf8_name = g_utf16_to_utf8 (name, -1, NULL, NULL, NULL);
537       if (utf8_name == NULL)
538         continue;
539       g_string_truncate (line_buffer, 0);
540       g_string_append_printf (line_buffer,
541                               "\"%s\" = \"%s",
542                               utf8_name,
543                               utf8_name);
544       g_free (utf8_name);
545 
546       status = RegGetValueW (hkey, NULL, name, RRF_RT_REG_MULTI_SZ,
547                              NULL, NULL, &value_length);
548       if (status != ERROR_SUCCESS)
549         continue;
550 
551       value_data = g_malloc (value_length);
552       status = RegGetValueW (hkey, NULL, name, RRF_RT_REG_MULTI_SZ, NULL,
553                              value_data, &value_length);
554       if (status != ERROR_SUCCESS)
555         {
556           g_free (value_data);
557           continue;
558         }
559 
560       entry = value_data;
561       entry_len = wcslen (entry);
562       while (entry_len > 0)
563         {
564           wchar_t *comma;
565           gchar *entry_utf8;
566 
567           comma = wcsstr (entry, L",");
568           /* The value after the first comma, as long as it isn't followed
569            * by another comma with a font scale */
570           if (comma && wcsstr (comma + 1, L",") == NULL)
571             {
572               g_string_append (line_buffer, ",");
573               entry_utf8 = g_utf16_to_utf8 (comma + 1, -1, NULL, NULL, NULL);
574               if (entry_utf8 != NULL)
575                 {
576                   g_string_append (line_buffer, entry_utf8);
577                   g_free (entry_utf8);
578                 }
579             }
580 
581           entry += entry_len + 1;
582           entry_len = wcslen (entry);
583         }
584       g_free (value_data);
585 
586       /* For some reason the default fallback list doesn't cover all of Unicode
587        * and Windows has additional fonts for certain languages.
588        * Some of them are listed in
589        * SOFTWARE\Microsoft\Windows NT\CurrentVersion\FontMapperFamilyFallback
590        * but I couldn't find any docs for it. Feel free to improve this */
591       g_string_append (line_buffer,
592                        ",gisha,leelawadee,arial unicode ms,browallia new,"
593                        "mingliu,simhei,gulimche,ms gothic,sylfaen,kartika,"
594                        "latha,mangal,raavi");
595 
596       g_string_append (line_buffer, "\"");
597 
598       handle_alias_line (line_buffer, &errstring, ht_aliases);
599       if (errstring != NULL)
600         {
601           g_warning ("error in windows fallback: %s (%s)\n",
602                      errstring, line_buffer->str);
603           g_free (errstring);
604           errstring = NULL;
605         }
606     }
607 
608   RegCloseKey (hkey);
609   g_string_free (line_buffer, TRUE);
610 }
611 
612 #endif
613 
614 static void
lookup_aliases(GHashTable * aliases_ht,const char * fontname,char *** families,int * n_families)615 lookup_aliases (GHashTable   *aliases_ht,
616                 const char   *fontname,
617                 char       ***families,
618                 int          *n_families)
619 {
620   struct PangoAlias alias_key;
621   struct PangoAlias *alias;
622 
623   alias_key.alias = g_ascii_strdown (fontname, -1);
624   alias = g_hash_table_lookup (aliases_ht, &alias_key);
625   g_free (alias_key.alias);
626 
627   if (alias)
628     {
629       *families = alias->families;
630       *n_families = alias->n_families;
631     }
632   else
633     {
634       *families = NULL;
635       *n_families = 0;
636     }
637 }
638 
639 static void
create_standard_family(PangoWin32FontMap * win32fontmap,const char * standard_family_name)640 create_standard_family (PangoWin32FontMap *win32fontmap,
641                         const char        *standard_family_name)
642 {
643   int i;
644   int n_aliases;
645   char **aliases;
646   PangoWin32FontMapClass *class = (PangoWin32FontMapClass*) G_OBJECT_GET_CLASS (win32fontmap);
647 
648   lookup_aliases (class->aliases, standard_family_name, &aliases, &n_aliases);
649   for (i = 0; i < n_aliases; i++)
650     {
651       PangoWin32Family *existing_family = g_hash_table_lookup (win32fontmap->families, aliases[i]);
652 
653       if (existing_family)
654         {
655           PangoWin32Family *new_family = pango_win32_get_font_family (win32fontmap, standard_family_name);
656           GSList *p = existing_family->faces;
657 
658           new_family->is_monospace = existing_family->is_monospace;
659 
660           while (p)
661             {
662               const PangoWin32Face *old_face = p->data;
663               PangoWin32Face *new_face = g_object_new (PANGO_WIN32_TYPE_FACE, NULL);
664 
665               new_face->logfontw = old_face->logfontw;
666               new_face->description = pango_font_description_copy_static (old_face->description);
667               pango_font_description_set_family_static (new_face->description, standard_family_name);
668 
669               if (old_face->coverage != NULL)
670                 new_face->coverage = pango_coverage_ref (old_face->coverage);
671               else
672                 new_face->coverage = NULL;
673 
674               new_face->face_name = NULL;
675 
676               new_face->is_synthetic = TRUE;
677 
678               new_face->has_cmap = old_face->has_cmap;
679               new_face->cmap_format = old_face->cmap_format;
680               new_face->cmap = _pango_win32_copy_cmap (old_face->cmap, old_face->cmap_format);
681 
682               new_face->cached_fonts = NULL;
683 
684               new_face->family = new_family;
685 
686               new_family->faces = g_slist_append (new_family->faces, new_face);
687 
688               p = p->next;
689             }
690           return;
691         }
692     }
693 
694   /* XXX What to do if none of the members of aliases for standard_family_name
695    * exists on this machine?
696    */
697 }
698 
699 static void
_pango_win32_font_map_init(PangoWin32FontMap * win32fontmap)700 _pango_win32_font_map_init (PangoWin32FontMap *win32fontmap)
701 {
702   LOGFONTW logfont;
703   HDC hdc = _pango_win32_get_display_dc ();
704   struct EnumProcData enum_proc_data;
705 
706   win32fontmap->families =
707     g_hash_table_new_full ((GHashFunc) case_insensitive_str_hash,
708                            (GEqualFunc) case_insensitive_str_equal, NULL, g_object_unref);
709   win32fontmap->fonts =
710     g_hash_table_new_full ((GHashFunc) logfontw_nosize_hash,
711                            (GEqualFunc) logfontw_nosize_equal, NULL, g_free);
712 
713   win32fontmap->font_cache = pango_win32_font_cache_new ();
714   win32fontmap->freed_fonts = g_queue_new ();
715   win32fontmap->warned_fonts = g_hash_table_new_full (g_str_hash,
716                                                       g_str_equal,
717                                                       g_free,
718                                                       NULL);
719 
720   memset (&logfont, 0, sizeof (logfont));
721   logfont.lfCharSet = DEFAULT_CHARSET;
722 
723   enum_proc_data.hdc = hdc;
724   enum_proc_data.font_map = win32fontmap;
725 
726   EnumFontFamiliesExW (hdc, &logfont,
727                        (FONTENUMPROCW) pango_win32_enum_proc,
728                        (LPARAM) &enum_proc_data, 0);
729 
730   g_hash_table_foreach (win32fontmap->families, synthesize_foreach, win32fontmap);
731 
732   /* Create synthetic "Sans", "Serif", "Monospace", "Cursive", "Fantasy" and "System-ui" families */
733   create_standard_family (win32fontmap, "Sans");
734   create_standard_family (win32fontmap, "Serif");
735   create_standard_family (win32fontmap, "Monospace");
736   create_standard_family (win32fontmap, "Cursive");
737   create_standard_family (win32fontmap, "Fantasy");
738   create_standard_family (win32fontmap, "System-ui");
739 
740   win32fontmap->resolution = (PANGO_SCALE / (double) GetDeviceCaps (hdc, LOGPIXELSY)) * 72.0;
741 }
742 
743 static void
pango_win32_font_map_fontset_add_fonts(PangoFontMap * fontmap,PangoContext * context,PangoFontsetSimple * fonts,PangoFontDescription * desc,const char * family)744 pango_win32_font_map_fontset_add_fonts (PangoFontMap          *fontmap,
745                                         PangoContext          *context,
746                                         PangoFontsetSimple *fonts,
747                                         PangoFontDescription  *desc,
748                                         const char            *family)
749 {
750   /* Mostly use the "old" pango_font_map_fontset_add_fonts() */
751   /* on Windows so that we can go through the .aliases file */
752   /* to load the appropriate fontset for various texts */
753   PangoFont *font;
754   char **aliases;
755   int n_aliases;
756   int j;
757   PangoWin32FontMap *win32fontmap = PANGO_WIN32_FONT_MAP (fontmap);
758   PangoWin32FontMapClass *class = (PangoWin32FontMapClass*)G_OBJECT_GET_CLASS(win32fontmap);
759 
760   lookup_aliases (class->aliases, family, &aliases, &n_aliases);
761   if (n_aliases)
762   {
763     for (j = 0; j < n_aliases; j++)
764     {
765       pango_font_description_set_family_static (desc, aliases[j]);
766       font = pango_win32_font_map_load_font (fontmap, context, desc);
767       if (font)
768         pango_fontset_simple_append (fonts, font);
769     }
770   }
771   else
772   {
773     pango_font_description_set_family_static (desc, family);
774     font = pango_win32_font_map_load_font (fontmap, context, desc);
775     if (font)
776       pango_fontset_simple_append (fonts, font);
777   }
778 }
779 
780 static PangoFontFace *
pango_win32_font_map_get_face(PangoFontMap * fontmap,PangoFont * font)781 pango_win32_font_map_get_face (PangoFontMap *fontmap,
782                                PangoFont    *font)
783 {
784   PangoWin32Font *win32font = PANGO_WIN32_FONT (font);
785 
786   return PANGO_FONT_FACE (win32font->win32face);
787 }
788 
789 static void
_pango_win32_font_map_class_init(PangoWin32FontMapClass * class)790 _pango_win32_font_map_class_init (PangoWin32FontMapClass *class)
791 {
792   GObjectClass *object_class = G_OBJECT_CLASS (class);
793   PangoFontMapClass *fontmap_class = PANGO_FONT_MAP_CLASS (class);
794 
795   class->find_font = pango_win32_font_map_real_find_font;
796   object_class->finalize = pango_win32_font_map_finalize;
797   fontmap_class->load_font = pango_win32_font_map_load_font;
798   /* we now need a load_fontset implementation for the Win32 backend */
799   fontmap_class->load_fontset = pango_win32_font_map_load_fontset;
800   fontmap_class->list_families = pango_win32_font_map_list_families;
801   fontmap_class->shape_engine_type = PANGO_RENDER_TYPE_WIN32;
802   fontmap_class->get_face = pango_win32_font_map_get_face;
803   class->aliases = g_hash_table_new_full ((GHashFunc)alias_hash,
804                                           (GEqualFunc)alias_equal,
805                                           (GDestroyNotify)alias_free,
806                                           NULL);
807 #ifdef HAVE_CAIRO_WIN32
808   read_windows_fallbacks (class->aliases);
809   read_builtin_aliases (class->aliases);
810 #endif
811 
812   _pango_win32_get_display_dc ();
813 }
814 
815 /**
816  * pango_win32_font_map_for_display:
817  *
818  * Returns a `PangoWin32FontMap`.
819  *
820  * Font maps are cached and should not be freed. If
821  * the font map is no longer needed, it can be released
822  * with [func@Pango.win32_shutdown_display].
823  *
824  * Return value: a `PangoFontMap`
825  **/
826 PangoFontMap *
pango_win32_font_map_for_display(void)827 pango_win32_font_map_for_display (void)
828 {
829   if (g_once_init_enter ((gsize*)&default_fontmap))
830     g_once_init_leave((gsize*)&default_fontmap, (gsize)g_object_new (PANGO_TYPE_WIN32_FONT_MAP, NULL));
831 
832   return PANGO_FONT_MAP (default_fontmap);
833 }
834 
835 /**
836  * pango_win32_shutdown_display:
837  *
838  * Free cached resources.
839  **/
840 void
pango_win32_shutdown_display(void)841 pango_win32_shutdown_display (void)
842 {
843   if (default_fontmap)
844     {
845       pango_win32_fontmap_cache_clear (default_fontmap);
846       g_object_unref (default_fontmap);
847 
848       default_fontmap = NULL;
849     }
850 }
851 
852 static void
pango_win32_font_map_finalize(GObject * object)853 pango_win32_font_map_finalize (GObject *object)
854 {
855   PangoWin32FontMap *win32fontmap = PANGO_WIN32_FONT_MAP (object);
856 
857   g_list_foreach (win32fontmap->freed_fonts->head, (GFunc)g_object_unref, NULL);
858   g_queue_free (win32fontmap->freed_fonts);
859 
860   pango_win32_font_cache_free (win32fontmap->font_cache);
861 
862   g_hash_table_destroy (win32fontmap->warned_fonts);
863   g_hash_table_destroy (win32fontmap->fonts);
864   g_hash_table_destroy (win32fontmap->families);
865 
866   G_OBJECT_CLASS (_pango_win32_font_map_parent_class)->finalize (object);
867 }
868 
869 /*
870  * PangoWin32Family
871  */
872 static void
pango_win32_family_list_faces(PangoFontFamily * family,PangoFontFace *** faces,int * n_faces)873 pango_win32_family_list_faces (PangoFontFamily  *family,
874                                PangoFontFace  ***faces,
875                                int              *n_faces)
876 {
877   PangoWin32Family *win32family = PANGO_WIN32_FAMILY (family);
878   GSList *p;
879   int n;
880 
881   p = win32family->faces;
882   n = 0;
883   while (p)
884     {
885       n++;
886       p = p->next;
887     }
888 
889   if (faces)
890     {
891       int i;
892 
893       *faces = g_new (PangoFontFace *, n);
894 
895       p = win32family->faces;
896       i = 0;
897       while (p)
898         {
899           (*faces)[i++] = p->data;
900           p = p->next;
901         }
902     }
903   if (n_faces)
904     *n_faces = n;
905 }
906 
907 static const char *
pango_win32_family_get_name(PangoFontFamily * family)908 pango_win32_family_get_name (PangoFontFamily  *family)
909 {
910   PangoWin32Family *win32family = PANGO_WIN32_FAMILY (family);
911 
912   return win32family->family_name;
913 }
914 
915 static gboolean
pango_win32_family_is_monospace(PangoFontFamily * family)916 pango_win32_family_is_monospace (PangoFontFamily *family)
917 {
918   PangoWin32Family *win32family = PANGO_WIN32_FAMILY (family);
919 
920   return win32family->is_monospace;
921 }
922 
G_DEFINE_TYPE(PangoWin32Family,pango_win32_family,PANGO_TYPE_FONT_FAMILY)923 G_DEFINE_TYPE (PangoWin32Family, pango_win32_family, PANGO_TYPE_FONT_FAMILY)
924 
925 static void
926 pango_win32_family_finalize (GObject *object)
927 {
928   PangoWin32Family *win32family = PANGO_WIN32_FAMILY (object);
929 
930   g_free (win32family->family_name);
931 
932   g_slist_free_full (win32family->faces, g_object_unref);
933 
934   G_OBJECT_CLASS (pango_win32_family_parent_class)->finalize (object);
935 }
936 
937 static void
pango_win32_family_class_init(PangoFontFamilyClass * class)938 pango_win32_family_class_init (PangoFontFamilyClass *class)
939 {
940   GObjectClass *object_class = G_OBJECT_CLASS (class);
941 
942   object_class->finalize = pango_win32_family_finalize;
943   class->list_faces = pango_win32_family_list_faces;
944   class->get_name = pango_win32_family_get_name;
945   class->is_monospace = pango_win32_family_is_monospace;
946 }
947 
948 static void
pango_win32_family_init(PangoWin32Family * family)949 pango_win32_family_init (PangoWin32Family *family)
950 {
951 }
952 
953 static void
list_families_foreach(gpointer key,gpointer value,gpointer user_data)954 list_families_foreach (gpointer key,
955                        gpointer value,
956                        gpointer user_data)
957 {
958   GSList **list = user_data;
959 
960   *list = g_slist_prepend (*list, value);
961 }
962 
963 static void
pango_win32_font_map_list_families(PangoFontMap * fontmap,PangoFontFamily *** families,int * n_families)964 pango_win32_font_map_list_families (PangoFontMap      *fontmap,
965                                     PangoFontFamily ***families,
966                                     int               *n_families)
967 {
968   GSList *family_list = NULL;
969   GSList *tmp_list;
970   PangoWin32FontMap *win32fontmap = (PangoWin32FontMap *)fontmap;
971 
972   if (!n_families)
973     return;
974 
975   g_hash_table_foreach (win32fontmap->families, list_families_foreach, &family_list);
976 
977   *n_families = g_slist_length (family_list);
978 
979   if (families)
980     {
981       int i = 0;
982 
983       *families = g_new (PangoFontFamily *, *n_families);
984 
985       tmp_list = family_list;
986       while (tmp_list)
987         {
988           (*families)[i] = tmp_list->data;
989           i++;
990           tmp_list = tmp_list->next;
991         }
992     }
993 
994   g_slist_free (family_list);
995 }
996 
997 static PangoWin32Family *
pango_win32_get_font_family(PangoWin32FontMap * win32fontmap,const char * family_name)998 pango_win32_get_font_family (PangoWin32FontMap *win32fontmap,
999                              const char        *family_name)
1000 {
1001   PangoWin32Family *win32family = g_hash_table_lookup (win32fontmap->families, family_name);
1002   if (!win32family)
1003     {
1004       win32family = g_object_new (PANGO_WIN32_TYPE_FAMILY, NULL);
1005       win32family->family_name = g_strdup (family_name);
1006       win32family->faces = NULL;
1007 
1008       g_hash_table_insert (win32fontmap->families, win32family->family_name, win32family);
1009     }
1010 
1011   return win32family;
1012 }
1013 
1014 static PangoFont *
pango_win32_font_map_load_font(PangoFontMap * fontmap,PangoContext * context,const PangoFontDescription * description)1015 pango_win32_font_map_load_font (PangoFontMap               *fontmap,
1016                                 PangoContext               *context,
1017                                 const PangoFontDescription *description)
1018 {
1019   PangoWin32FontMap *win32fontmap = (PangoWin32FontMap *)fontmap;
1020   PangoWin32Face *best_match = NULL;
1021   PangoFont *result = NULL;
1022   GSList *tmp_list;
1023   const char *family;
1024   char **families;
1025   int i;
1026 
1027   g_return_val_if_fail (description != NULL, NULL);
1028 
1029   family = pango_font_description_get_family (description);
1030   families = g_strsplit (family ? family : "", ",", -1);
1031 
1032   for (i = 0; families[i] && !best_match; ++i)
1033     {
1034       PangoWin32Family *win32family;
1035       PING (("name=%s", families[i]));
1036 
1037       win32family = g_hash_table_lookup (win32fontmap->families, families[i]);
1038       if (win32family)
1039         {
1040           PangoFontDescription *new_desc;
1041           PangoFontDescription *best_desc = NULL;
1042 
1043           PING (("got win32family"));
1044           tmp_list = win32family->faces;
1045 
1046           while (tmp_list)
1047             {
1048               PangoWin32Face *face = tmp_list->data;
1049               new_desc = pango_font_face_describe (PANGO_FONT_FACE (face));
1050               pango_font_description_set_gravity (new_desc,
1051                                                   pango_font_description_get_gravity (description));
1052 
1053               if (pango_font_description_better_match (description,
1054                                                        best_desc,
1055                                                        new_desc))
1056                 {
1057                   pango_font_description_free (best_desc);
1058                   best_desc = new_desc;
1059                   best_match = face;
1060                 }
1061               else
1062                 pango_font_description_free (new_desc);
1063 
1064               tmp_list = tmp_list->next;
1065             }
1066 
1067           if (best_desc != NULL)
1068             pango_font_description_free (best_desc);
1069         }
1070     }
1071 
1072   g_strfreev (families);
1073 
1074   if (best_match)
1075     result = PANGO_WIN32_FONT_MAP_GET_CLASS (win32fontmap)->find_font (win32fontmap, context,
1076                                                                        best_match,
1077                                                                        description);
1078       /* TODO: Handle the case that result == NULL. */
1079   else
1080     PING (("no best match!"));
1081 
1082   return result;
1083 }
1084 
1085 static PangoWin32Font *
pango_win32_font_neww(PangoFontMap * fontmap,const LOGFONTW * lfp,int size)1086 pango_win32_font_neww (PangoFontMap   *fontmap,
1087                        const LOGFONTW *lfp,
1088                        int             size)
1089 {
1090   PangoWin32Font *result;
1091 
1092   g_return_val_if_fail (fontmap != NULL, NULL);
1093   g_return_val_if_fail (lfp != NULL, NULL);
1094 
1095   result = (PangoWin32Font *)g_object_new (PANGO_TYPE_WIN32_FONT, NULL);
1096 
1097   if (G_UNLIKELY(result->fontmap))
1098     return result;
1099   g_weak_ref_set ((GWeakRef *)&result->fontmap, fontmap);
1100 
1101   result->size = size;
1102   _pango_win32_make_matching_logfontw (fontmap, lfp, size, &result->logfontw);
1103 
1104   return result;
1105 }
1106 
1107 static PangoFont *
pango_win32_font_map_real_find_font(PangoWin32FontMap * win32fontmap,PangoContext * context,PangoWin32Face * face,const PangoFontDescription * description)1108 pango_win32_font_map_real_find_font (PangoWin32FontMap          *win32fontmap,
1109                                      PangoContext               *context,
1110                                      PangoWin32Face             *face,
1111                                      const PangoFontDescription *description)
1112 {
1113   PangoFontMap *fontmap = PANGO_FONT_MAP (win32fontmap);
1114   PangoWin32Font *win32font;
1115   GSList *tmp_list = face->cached_fonts;
1116   int size = pango_font_description_get_size (description);
1117 
1118   if (pango_font_description_get_size_is_absolute (description))
1119     size = (int) 0.5 + (size * win32fontmap->resolution) / PANGO_SCALE;
1120 
1121   PING (("got best match:%S size=%d",face->logfontw.lfFaceName,size));
1122 
1123   while (tmp_list)
1124     {
1125       win32font = tmp_list->data;
1126       if (win32font->size == size)
1127         {
1128           PING (("size matches"));
1129 
1130           g_object_ref (win32font);
1131           if (win32font->in_cache)
1132             _pango_win32_fontmap_cache_remove (fontmap, win32font);
1133 
1134           return (PangoFont *)win32font;
1135         }
1136 
1137       tmp_list = tmp_list->next;
1138     }
1139 
1140   win32font = pango_win32_font_neww (fontmap, &face->logfontw, size);
1141 
1142   if (!win32font)
1143     return NULL;
1144 
1145   win32font->win32face = face;
1146   face->cached_fonts = g_slist_prepend (face->cached_fonts, win32font);
1147 
1148   return (PangoFont *)win32font;
1149 }
1150 
1151 static gboolean
_pango_win32_get_name_header(HDC hdc,struct name_header * header)1152 _pango_win32_get_name_header (HDC                 hdc,
1153 			      struct name_header *header)
1154 {
1155   if (GetFontData (hdc, NAME, 0, header, sizeof (*header)) != sizeof (*header))
1156     return FALSE;
1157 
1158   header->num_records = GUINT16_FROM_BE (header->num_records);
1159   header->string_storage_offset = GUINT16_FROM_BE (header->string_storage_offset);
1160 
1161   return TRUE;
1162 }
1163 
1164 static gboolean
_pango_win32_get_name_record(HDC hdc,gint i,struct name_record * record)1165 _pango_win32_get_name_record (HDC                 hdc,
1166 			      gint                i,
1167 			      struct name_record *record)
1168 {
1169   if (GetFontData (hdc, NAME, 6 + i * sizeof (*record),
1170 		   record, sizeof (*record)) != sizeof (*record))
1171     return FALSE;
1172 
1173   record->platform_id = GUINT16_FROM_BE (record->platform_id);
1174   record->encoding_id = GUINT16_FROM_BE (record->encoding_id);
1175   record->language_id = GUINT16_FROM_BE (record->language_id);
1176   record->name_id = GUINT16_FROM_BE (record->name_id);
1177   record->string_length = GUINT16_FROM_BE (record->string_length);
1178   record->string_offset = GUINT16_FROM_BE (record->string_offset);
1179 
1180   return TRUE;
1181 }
1182 
1183 static gchar *
get_family_nameA(const LOGFONTA * lfp)1184 get_family_nameA (const LOGFONTA *lfp)
1185 {
1186   HFONT hfont;
1187   HFONT oldhfont;
1188   HDC hdc;
1189 
1190   struct name_header header;
1191   struct name_record record;
1192 
1193   gint unicode_ix = -1, mac_ix = -1, microsoft_ix = -1;
1194   gint name_ix;
1195   gchar *codeset;
1196 
1197   gchar *string = NULL;
1198   gchar *name;
1199 
1200   gint i, l;
1201   gsize nbytes;
1202 
1203   /* If lfFaceName is ASCII, assume it is the common (English) name
1204    * for the font. Is this valid? Do some TrueType fonts have
1205    * different names in French, German, etc, and does the system
1206    * return these if the locale is set to use French, German, etc?
1207    */
1208   l = strlen (lfp->lfFaceName);
1209   for (i = 0; i < l; i++)
1210     if (lfp->lfFaceName[i] < ' ' || lfp->lfFaceName[i] > '~')
1211       break;
1212 
1213   if (i == l)
1214     return g_strdup (lfp->lfFaceName);
1215 
1216   if ((hfont = CreateFontIndirect (lfp)) == NULL)
1217     goto fail0;
1218 
1219   hdc = _pango_win32_get_display_dc ();
1220 
1221   if ((oldhfont = SelectObject (hdc, hfont)) == NULL)
1222     goto fail1;
1223 
1224   if (!_pango_win32_get_name_header (hdc, &header))
1225     goto fail2;
1226 
1227   PING (("%d name records", header.num_records));
1228 
1229   for (i = 0; i < header.num_records; i++)
1230     {
1231       if (!_pango_win32_get_name_record (hdc, i, &record))
1232         goto fail2;
1233 
1234       if ((record.name_id != 1 && record.name_id != 16) || record.string_length <= 0)
1235         continue;
1236 
1237       PING (("platform:%d encoding:%d language:%04x name_id:%d",
1238              record.platform_id, record.encoding_id, record.language_id, record.name_id));
1239 
1240       if (record.platform_id == APPLE_UNICODE_PLATFORM_ID ||
1241           record.platform_id == ISO_PLATFORM_ID)
1242         unicode_ix = i;
1243 
1244       else if (record.platform_id == MACINTOSH_PLATFORM_ID &&
1245                record.encoding_id == 0 && /* Roman */
1246                record.language_id == 0)   /* English */
1247         mac_ix = i;
1248 
1249       else if (record.platform_id == MICROSOFT_PLATFORM_ID)
1250         if ((microsoft_ix == -1 || PRIMARYLANGID (record.language_id) == LANG_ENGLISH) &&
1251             (record.encoding_id == SYMBOL_ENCODING_ID ||
1252              record.encoding_id == UNICODE_ENCODING_ID ||
1253              record.encoding_id == UCS4_ENCODING_ID))
1254           microsoft_ix = i;
1255     }
1256 
1257   if (microsoft_ix >= 0)
1258     name_ix = microsoft_ix;
1259   else if (mac_ix >= 0)
1260     name_ix = mac_ix;
1261   else if (unicode_ix >= 0)
1262     name_ix = unicode_ix;
1263   else
1264     goto fail2;
1265 
1266   if (!_pango_win32_get_name_record (hdc, name_ix, &record))
1267     goto fail2;
1268 
1269   string = g_malloc (record.string_length + 1);
1270   if (GetFontData (hdc, NAME,
1271                    header.string_storage_offset + record.string_offset,
1272                    string, record.string_length) != record.string_length)
1273     goto fail2;
1274 
1275   string[record.string_length] = '\0';
1276 
1277   if (name_ix == microsoft_ix)
1278     if (record.encoding_id == SYMBOL_ENCODING_ID ||
1279         record.encoding_id == UNICODE_ENCODING_ID ||
1280         record.encoding_id == UCS4_ENCODING_ID)
1281       codeset = "UTF-16BE";
1282     else
1283       codeset = "UCS-4BE";
1284   else if (name_ix == mac_ix)
1285     codeset = "MacRoman";
1286   else /* name_ix == unicode_ix */
1287     codeset = "UCS-4BE";
1288 
1289   name = g_convert (string, record.string_length, "UTF-8", codeset, NULL, &nbytes, NULL);
1290   if (name == NULL)
1291     goto fail2;
1292   g_free (string);
1293 
1294   PING (("%s", name));
1295 
1296   SelectObject (hdc, oldhfont);
1297   DeleteObject (hfont);
1298 
1299   return name;
1300 
1301  fail2:
1302   g_free (string);
1303   SelectObject (hdc, oldhfont);
1304 
1305  fail1:
1306   DeleteObject (hfont);
1307 
1308  fail0:
1309   return g_locale_to_utf8 (lfp->lfFaceName, -1, NULL, NULL, NULL);
1310 }
1311 
1312 /**
1313  * pango_win32_font_description_from_logfont:
1314  * @lfp: a LOGFONTA
1315  *
1316  * Creates a `PangoFontDescription` that matches the specified LOGFONTA.
1317  *
1318  * The face name, italicness and weight fields in the LOGFONTA are used
1319  * to set up the resulting `PangoFontDescription`. If the face name in
1320  * the LOGFONTA contains non-ASCII characters the font is temporarily
1321  * loaded (using CreateFontIndirect()) and an ASCII (usually English)
1322  * name for it is looked up from the font name tables in the font
1323  * data. If that doesn't work, the face name is converted from the
1324  * system codepage to UTF-8 and that is used.
1325  *
1326  * Return value: the newly allocated `PangoFontDescription`, which
1327  *  should be freed using [method@Pango.FontDescription.free]
1328  *
1329  * Since: 1.12
1330  */
1331 PangoFontDescription *
pango_win32_font_description_from_logfont(const LOGFONT * lfp)1332 pango_win32_font_description_from_logfont (const LOGFONT *lfp)
1333 {
1334   PangoFontDescription *description;
1335   gchar *family;
1336   PangoStyle style;
1337   PangoVariant variant;
1338   PangoWeight weight;
1339   PangoStretch stretch;
1340 
1341   family = get_family_nameA (lfp);
1342 
1343   if (!lfp->lfItalic)
1344     style = PANGO_STYLE_NORMAL;
1345   else
1346     style = PANGO_STYLE_ITALIC;
1347 
1348   variant = PANGO_VARIANT_NORMAL;
1349 
1350   if (lfp->lfWeight == FW_DONTCARE)
1351     weight = PANGO_WEIGHT_NORMAL;
1352   else
1353     /* The PangoWeight values PANGO_WEIGHT_* map exactly to Windows FW_*. */
1354     weight = (PangoWeight) lfp->lfWeight;
1355 
1356   /* XXX No idea how to figure out the stretch */
1357   stretch = PANGO_STRETCH_NORMAL;
1358 
1359   description = pango_font_description_new ();
1360   pango_font_description_set_family (description, family);
1361   g_free(family);
1362   pango_font_description_set_style (description, style);
1363   pango_font_description_set_weight (description, weight);
1364   pango_font_description_set_stretch (description, stretch);
1365   pango_font_description_set_variant (description, variant);
1366 
1367   return description;
1368 }
1369 
1370 static gchar *
get_family_nameW(const LOGFONTW * lfp)1371 get_family_nameW (const LOGFONTW *lfp)
1372 {
1373   HFONT hfont;
1374   HFONT oldhfont;
1375   HDC hdc;
1376 
1377   struct name_header header;
1378   struct name_record record;
1379 
1380   gint unicode_ix = -1, mac_ix = -1, microsoft_ix = -1;
1381   gint name_ix;
1382   gchar *codeset;
1383 
1384   gchar *string = NULL;
1385   gchar *name;
1386 
1387   gint i, l;
1388   gsize nbytes;
1389 
1390   /* If lfFaceName is ASCII, assume it is the common (English) name
1391    * for the font. Is this valid? Do some TrueType fonts have
1392    * different names in French, German, etc, and does the system
1393    * return these if the locale is set to use French, German, etc?
1394    */
1395   l = wcslen (lfp->lfFaceName);
1396   for (i = 0; i < l; i++)
1397     if (lfp->lfFaceName[i] < ' ' || lfp->lfFaceName[i] > '~')
1398       break;
1399 
1400   if (i == l)
1401     return g_utf16_to_utf8 (lfp->lfFaceName, -1, NULL, NULL, NULL);
1402 
1403   if ((hfont = CreateFontIndirectW (lfp)) == NULL)
1404     goto fail0;
1405 
1406   hdc = _pango_win32_get_display_dc ();
1407 
1408   if ((oldhfont = SelectObject (hdc, hfont)) == NULL)
1409     goto fail1;
1410 
1411   if (!_pango_win32_get_name_header (hdc, &header))
1412     goto fail2;
1413 
1414   PING (("%d name records", header.num_records));
1415 
1416   for (i = 0; i < header.num_records; i++)
1417     {
1418       if (!_pango_win32_get_name_record (hdc, i, &record))
1419         goto fail2;
1420 
1421       if ((record.name_id != 1 && record.name_id != 16) || record.string_length <= 0)
1422         continue;
1423 
1424       PING (("platform:%d encoding:%d language:%04x name_id:%d",
1425             record.platform_id, record.encoding_id, record.language_id, record.name_id));
1426 
1427       if (record.platform_id == APPLE_UNICODE_PLATFORM_ID ||
1428           record.platform_id == ISO_PLATFORM_ID)
1429         unicode_ix = i;
1430       else if (record.platform_id == MACINTOSH_PLATFORM_ID &&
1431                record.encoding_id == 0 && /* Roman */
1432                record.language_id == 0)   /* English */
1433         mac_ix = i;
1434       else if (record.platform_id == MICROSOFT_PLATFORM_ID)
1435         if ((microsoft_ix == -1 || PRIMARYLANGID (record.language_id) == LANG_ENGLISH) &&
1436             (record.encoding_id == SYMBOL_ENCODING_ID ||
1437              record.encoding_id == UNICODE_ENCODING_ID ||
1438              record.encoding_id == UCS4_ENCODING_ID))
1439           microsoft_ix = i;
1440     }
1441 
1442   if (microsoft_ix >= 0)
1443     name_ix = microsoft_ix;
1444   else if (mac_ix >= 0)
1445     name_ix = mac_ix;
1446   else if (unicode_ix >= 0)
1447     name_ix = unicode_ix;
1448   else
1449     goto fail2;
1450 
1451   if (!_pango_win32_get_name_record (hdc, name_ix, &record))
1452     goto fail2;
1453 
1454   string = g_malloc (record.string_length + 1);
1455   if (GetFontData (hdc, NAME,
1456                    header.string_storage_offset + record.string_offset,
1457                    string, record.string_length) != record.string_length)
1458     goto fail2;
1459 
1460   string[record.string_length] = '\0';
1461 
1462   if (name_ix == microsoft_ix)
1463     if (record.encoding_id == SYMBOL_ENCODING_ID ||
1464         record.encoding_id == UNICODE_ENCODING_ID ||
1465         record.encoding_id == UCS4_ENCODING_ID)
1466       codeset = "UTF-16BE";
1467     else
1468       codeset = "UCS-4BE";
1469   else if (name_ix == mac_ix)
1470     codeset = "MacRoman";
1471   else /* name_ix == unicode_ix */
1472     codeset = "UCS-4BE";
1473 
1474   name = g_convert (string, record.string_length, "UTF-8", codeset, NULL, &nbytes, NULL);
1475   if (name == NULL)
1476     goto fail2;
1477   g_free (string);
1478 
1479   PING (("%s", name));
1480 
1481   SelectObject (hdc, oldhfont);
1482   DeleteObject (hfont);
1483 
1484   return name;
1485 
1486  fail2:
1487   g_free (string);
1488   SelectObject (hdc, oldhfont);
1489 
1490  fail1:
1491   DeleteObject (hfont);
1492 
1493  fail0:
1494   return g_utf16_to_utf8 (lfp->lfFaceName, -1, NULL, NULL, NULL);
1495 }
1496 
1497 /**
1498  * pango_win32_font_description_from_logfontw:
1499  * @lfp: a LOGFONTW
1500  *
1501  * Creates a `PangoFontDescription` that matches the specified LOGFONTW.
1502  *
1503  * The face name, italicness and weight fields in the LOGFONTW are used
1504  * to set up the resulting `PangoFontDescription`. If the face name in
1505  * the LOGFONTW contains non-ASCII characters the font is temporarily
1506  * loaded (using CreateFontIndirect()) and an ASCII (usually English)
1507  * name for it is looked up from the font name tables in the font
1508  * data. If that doesn't work, the face name is converted from UTF-16
1509  * to UTF-8 and that is used.
1510  *
1511  * Return value: the newly allocated `PangoFontDescription`, which
1512  *  should be freed using [method@Pango.FontDescription.free]
1513  *
1514  * Since: 1.16
1515  */
1516 PangoFontDescription *
pango_win32_font_description_from_logfontw(const LOGFONTW * lfp)1517 pango_win32_font_description_from_logfontw (const LOGFONTW *lfp)
1518 {
1519   PangoFontDescription *description;
1520   gchar *family;
1521   PangoStyle style;
1522   PangoVariant variant;
1523   PangoWeight weight;
1524   PangoStretch stretch;
1525 
1526   family = get_family_nameW (lfp);
1527 
1528   if ((lfp->lfPitchAndFamily & 0xF0) == FF_ROMAN && lfp->lfItalic)
1529     style = PANGO_STYLE_ITALIC;
1530   else if (lfp->lfItalic)
1531     style = PANGO_STYLE_OBLIQUE;
1532   else
1533     style = PANGO_STYLE_NORMAL;
1534 
1535   variant = PANGO_VARIANT_NORMAL;
1536 
1537   if (lfp->lfWeight == FW_DONTCARE)
1538     weight = PANGO_WEIGHT_NORMAL;
1539   else
1540     /* The PangoWeight values PANGO_WEIGHT_* map exactly to Windows FW_*. */
1541     weight = (PangoWeight) lfp->lfWeight;
1542 
1543   /* XXX No idea how to figure out the stretch */
1544   stretch = PANGO_STRETCH_NORMAL;
1545 
1546   description = pango_font_description_new ();
1547   pango_font_description_set_family (description, family);
1548   g_free(family);
1549   pango_font_description_set_style (description, style);
1550   pango_font_description_set_weight (description, weight);
1551   pango_font_description_set_stretch (description, stretch);
1552   pango_font_description_set_variant (description, variant);
1553 
1554   return description;
1555 }
1556 
1557 static char *
charset_name(int charset,char * num)1558 charset_name (int charset, char* num)
1559 {
1560   switch (charset)
1561     {
1562 #define CASE(x) case x##_CHARSET: return #x
1563       CASE (ANSI);
1564       CASE (DEFAULT);
1565       CASE (SYMBOL);
1566       CASE (SHIFTJIS);
1567       CASE (HANGUL);
1568       CASE (GB2312);
1569       CASE (CHINESEBIG5);
1570       CASE (GREEK);
1571       CASE (TURKISH);
1572       CASE (HEBREW);
1573       CASE (ARABIC);
1574       CASE (BALTIC);
1575       CASE (RUSSIAN);
1576       CASE (THAI);
1577       CASE (EASTEUROPE);
1578       CASE (OEM);
1579       CASE (JOHAB);
1580       CASE (VIETNAMESE);
1581       CASE (MAC);
1582 #undef CASE
1583     default:
1584       sprintf (num, "%d", charset);
1585       return num;
1586     }
1587 }
1588 
1589 static char *
ff_name(int ff,char * num)1590 ff_name (int ff, char* num)
1591 {
1592   switch (ff)
1593     {
1594 #define CASE(x) case FF_##x: return #x
1595       CASE (DECORATIVE);
1596       CASE (DONTCARE);
1597       CASE (MODERN);
1598       CASE (ROMAN);
1599       CASE (SCRIPT);
1600       CASE (SWISS);
1601 #undef CASE
1602     default:
1603       sprintf (num, "%d", ff);
1604       return num;
1605     }
1606 }
1607 
1608 static void
pango_win32_insert_font(PangoWin32FontMap * win32fontmap,LOGFONTW * lfp,gboolean is_synthetic)1609 pango_win32_insert_font (PangoWin32FontMap *win32fontmap,
1610                          LOGFONTW          *lfp,
1611                          gboolean           is_synthetic)
1612 {
1613   LOGFONTW *lfp2 = NULL;
1614   PangoFontDescription *description;
1615   PangoWin32Family *win32family;
1616   PangoWin32Face *win32face;
1617 
1618   char tmp_for_charset_name[10];
1619   char tmp_for_ff_name[10];
1620 
1621   PING (("face=%S,charset=%s,it=%s,wt=%ld,ht=%ld,ff=%s%s",
1622          lfp->lfFaceName,
1623          charset_name (lfp->lfCharSet, tmp_for_charset_name),
1624          lfp->lfItalic ? "yes" : "no",
1625          lfp->lfWeight,
1626          lfp->lfHeight,
1627          ff_name (lfp->lfPitchAndFamily & 0xF0, tmp_for_ff_name),
1628          is_synthetic ? " synthetic" : ""));
1629 
1630   /* Ignore Symbol fonts (which don't have any Unicode mapping
1631    * table). We could also be fancy and use the PostScript glyph name
1632    * table for such if present, and build a Unicode map by mapping
1633    * each PostScript glyph name to Unicode character. Oh well.
1634    */
1635   if (lfp->lfCharSet == SYMBOL_CHARSET)
1636     return;
1637 
1638   if (g_hash_table_lookup (win32fontmap->fonts, lfp))
1639     {
1640       PING (("already have it"));
1641       return;
1642     }
1643 
1644   PING (("not found"));
1645   lfp2 = g_new (LOGFONTW, 1);
1646   *lfp2 = *lfp;
1647   g_hash_table_insert (win32fontmap->fonts, lfp2, lfp2);
1648 
1649   description = pango_win32_font_description_from_logfontw (lfp2);
1650 
1651   /* In some cases, extracting a name for a font can fail; such fonts
1652    * aren't usable for us
1653    */
1654   if (!pango_font_description_get_family (description))
1655     {
1656       pango_font_description_free (description);
1657       return;
1658     }
1659 
1660   win32face = g_object_new (PANGO_WIN32_TYPE_FACE, NULL);
1661 
1662   PING (("win32face created: %p for %S", win32face, lfp->lfFaceName));
1663 
1664   win32face->logfontw = *lfp;
1665   win32face->description = description;
1666 
1667   win32face->coverage = NULL;
1668 
1669   win32face->face_name = NULL;
1670 
1671   win32face->is_synthetic = is_synthetic;
1672 
1673   win32face->has_cmap = TRUE;
1674   win32face->cmap_format = 0;
1675   win32face->cmap = NULL;
1676 
1677   win32face->cached_fonts = NULL;
1678 
1679   win32face->family = win32family =
1680     pango_win32_get_font_family (win32fontmap,
1681                                  pango_font_description_get_family (win32face->description));
1682   if ((lfp->lfPitchAndFamily & 0xF0) == FF_MODERN)
1683     win32family->is_monospace = TRUE;
1684 
1685   win32family->faces = g_slist_append (win32family->faces, win32face);
1686 
1687   PING (("name=%s, length(faces)=%d",
1688         win32family->family_name, g_slist_length (win32family->faces)));
1689 }
1690 
1691 /* Given a LOGFONTW and size, make a matching LOGFONTW corresponding to
1692  * an installed font.
1693  */
1694 void
_pango_win32_make_matching_logfontw(PangoFontMap * fontmap,const LOGFONTW * lfp,int size,LOGFONTW * out)1695 _pango_win32_make_matching_logfontw (PangoFontMap   *fontmap,
1696                                      const LOGFONTW *lfp,
1697                                      int             size,
1698                                      LOGFONTW       *out)
1699 {
1700   PangoWin32FontMap *win32fontmap;
1701   LOGFONTW *match;
1702 
1703   PING (("lfp.face=%S,wt=%ld,ht=%ld,size:%d",
1704         lfp->lfFaceName, lfp->lfWeight, lfp->lfHeight, size));
1705   win32fontmap = PANGO_WIN32_FONT_MAP (fontmap);
1706 
1707   match = g_hash_table_lookup (win32fontmap->fonts, lfp);
1708 
1709   if (!match)
1710     {
1711       PING (("not found"));
1712       return;
1713     }
1714 
1715   /* OK, we have a match; let's modify it to fit this size */
1716 
1717   *out = *match;
1718   out->lfHeight = -(int)((double)size / win32fontmap->resolution + 0.5);
1719   out->lfWidth = 0;
1720 }
1721 
1722 static PangoFontDescription *
pango_win32_face_describe(PangoFontFace * face)1723 pango_win32_face_describe (PangoFontFace *face)
1724 {
1725   PangoWin32Face *win32face = PANGO_WIN32_FACE (face);
1726 
1727   return pango_font_description_copy (win32face->description);
1728 }
1729 
1730 static const char *
pango_win32_face_get_face_name(PangoFontFace * face)1731 pango_win32_face_get_face_name (PangoFontFace *face)
1732 {
1733   PangoWin32Face *win32face = PANGO_WIN32_FACE (face);
1734 
1735   if (!win32face->face_name)
1736     {
1737       PangoFontDescription *desc = pango_font_face_describe (face);
1738 
1739       pango_font_description_unset_fields (desc,
1740                                            PANGO_FONT_MASK_FAMILY | PANGO_FONT_MASK_SIZE);
1741 
1742       win32face->face_name = pango_font_description_to_string (desc);
1743       pango_font_description_free (desc);
1744     }
1745 
1746   return win32face->face_name;
1747 }
1748 
1749 static gboolean
pango_win32_face_is_synthesized(PangoFontFace * face)1750 pango_win32_face_is_synthesized (PangoFontFace *face)
1751 {
1752   PangoWin32Face *win32face = PANGO_WIN32_FACE (face);
1753 
1754   return win32face->is_synthetic;
1755 }
1756 
1757 static PangoFontFamily *
pango_win32_face_get_family(PangoFontFace * face)1758 pango_win32_face_get_family (PangoFontFace *face)
1759 {
1760   PangoWin32Face *win32face = PANGO_WIN32_FACE (face);
1761 
1762   return PANGO_FONT_FAMILY (win32face->family);
1763 }
1764 
G_DEFINE_TYPE(PangoWin32Face,pango_win32_face,PANGO_TYPE_FONT_FACE)1765 G_DEFINE_TYPE (PangoWin32Face, pango_win32_face, PANGO_TYPE_FONT_FACE)
1766 
1767 static void
1768 pango_win32_face_finalize (GObject *object)
1769 {
1770   PangoWin32Face *win32face = PANGO_WIN32_FACE (object);
1771 
1772   pango_font_description_free (win32face->description);
1773 
1774   if (win32face->coverage != NULL)
1775     pango_coverage_unref (win32face->coverage);
1776 
1777   g_free (win32face->face_name);
1778 
1779   g_free (win32face->cmap);
1780 
1781   g_slist_free (win32face->cached_fonts);
1782 //  g_slist_free_full (win32face->cached_fonts, g_object_unref); // This doesn't work.
1783 
1784   G_OBJECT_CLASS (pango_win32_family_parent_class)->finalize (object);
1785 }
1786 
1787 static void
pango_win32_face_class_init(PangoFontFaceClass * class)1788 pango_win32_face_class_init (PangoFontFaceClass *class)
1789 {
1790   GObjectClass *object_class = G_OBJECT_CLASS (class);
1791 
1792   object_class->finalize = pango_win32_face_finalize;
1793   class->describe = pango_win32_face_describe;
1794   class->get_face_name = pango_win32_face_get_face_name;
1795   class->list_sizes = pango_win32_face_list_sizes;
1796   class->is_synthesized = pango_win32_face_is_synthesized;
1797   class->get_family = pango_win32_face_get_family;
1798 }
1799 
1800 static void
pango_win32_face_init(PangoWin32Face * face)1801 pango_win32_face_init (PangoWin32Face *face)
1802 {
1803 }
1804 
1805 static void
pango_win32_face_list_sizes(PangoFontFace * face,int ** sizes,int * n_sizes)1806 pango_win32_face_list_sizes (PangoFontFace  *face,
1807                              int           **sizes,
1808                              int            *n_sizes)
1809 {
1810   /*
1811    * for scalable fonts it's simple, and currently we only have such
1812    * see : pango_win32_enum_proc(), TRUETYPE_FONTTYPE
1813    */
1814   if (sizes)
1815     *sizes = NULL;
1816   *n_sizes = 0;
1817 }
1818 
1819 /**
1820  * pango_win32_font_map_get_font_cache:
1821  * @font_map: a `PangoWin32FontMap`
1822  *
1823  * Obtains the font cache associated with the given font map.
1824  *
1825  * Return value: the `PangoWin32FontCache` of @font_map.
1826  */
1827 PangoWin32FontCache *
pango_win32_font_map_get_font_cache(PangoFontMap * font_map)1828 pango_win32_font_map_get_font_cache (PangoFontMap *font_map)
1829 {
1830   if (G_UNLIKELY (!font_map))
1831     return NULL;
1832 
1833   g_return_val_if_fail (PANGO_WIN32_IS_FONT_MAP (font_map), NULL);
1834 
1835   return PANGO_WIN32_FONT_MAP (font_map)->font_cache;
1836 }
1837 
1838 void
_pango_win32_fontmap_cache_remove(PangoFontMap * fontmap,PangoWin32Font * win32font)1839 _pango_win32_fontmap_cache_remove (PangoFontMap   *fontmap,
1840                                    PangoWin32Font *win32font)
1841 {
1842   PangoWin32FontMap *win32fontmap = PANGO_WIN32_FONT_MAP (fontmap);
1843   GList *link = g_queue_find (win32fontmap->freed_fonts, win32font);
1844 
1845   if (link)
1846     g_queue_delete_link (win32fontmap->freed_fonts, link);
1847   win32font->in_cache = FALSE;
1848 
1849   g_object_unref (win32font);
1850 }
1851 
1852 static void
pango_win32_fontmap_cache_clear(PangoWin32FontMap * win32fontmap)1853 pango_win32_fontmap_cache_clear (PangoWin32FontMap *win32fontmap)
1854 {
1855   g_list_foreach (win32fontmap->freed_fonts->head, (GFunc)g_object_unref, NULL);
1856   g_queue_free (win32fontmap->freed_fonts);
1857   win32fontmap->freed_fonts = g_queue_new ();
1858 }
1859 
1860 static PangoFontset *
pango_win32_font_map_load_fontset(PangoFontMap * fontmap,PangoContext * context,const PangoFontDescription * desc,PangoLanguage * language)1861 pango_win32_font_map_load_fontset (PangoFontMap                 *fontmap,
1862                                    PangoContext                 *context,
1863                                    const PangoFontDescription   *desc,
1864                                    PangoLanguage                *language)
1865 {
1866   /* This "adds" a load_fontset() for the Win32 backend */
1867   /* which is needed to make sure we use an appropriate */
1868   /* font for various texts when we are on Windows */
1869   /* (Copied directly from pango-fontmap.c) */
1870   PangoFontDescription *tmp_desc = pango_font_description_copy_static (desc);
1871   const char *family;
1872   char **families;
1873   int i;
1874   PangoFontsetSimple *fonts;
1875   PangoWin32FontMap *win32fontmap = NULL;
1876   GHashTable *warned_fonts = NULL;
1877 
1878   g_return_val_if_fail (fontmap != NULL, NULL);
1879 
1880   win32fontmap = PANGO_WIN32_FONT_MAP (fontmap);
1881   warned_fonts = win32fontmap->warned_fonts;
1882 
1883   family = pango_font_description_get_family (desc);
1884   families = g_strsplit (family ? family : "", ",", -1);
1885 
1886   fonts = pango_fontset_simple_new (language);
1887 
1888   for (i = 0; families[i]; i++)
1889     pango_win32_font_map_fontset_add_fonts (fontmap,
1890                                             context,
1891                                             fonts,
1892                                             tmp_desc,
1893                                             families[i]);
1894 
1895   g_strfreev (families);
1896 
1897   /* The font description was completely unloadable, try with
1898    * family == "Sans"
1899    */
1900   if (pango_fontset_simple_size (fonts) == 0)
1901     {
1902       char *ctmp1, *ctmp2;
1903 
1904       pango_font_description_set_family_static (tmp_desc,
1905                                                 pango_font_description_get_family (desc));
1906 
1907       ctmp1 = pango_font_description_to_string (desc);
1908       pango_font_description_set_family_static (tmp_desc, "Sans");
1909 
1910       if (!g_hash_table_lookup (warned_fonts, ctmp1))
1911         {
1912 
1913           g_hash_table_insert (warned_fonts, g_strdup (ctmp1), GINT_TO_POINTER (1));
1914 
1915           ctmp2 = pango_font_description_to_string (tmp_desc);
1916           g_warning ("couldn't load font \"%s\", falling back to \"%s\", "
1917                      "expect ugly output.", ctmp1, ctmp2);
1918           g_free (ctmp2);
1919         }
1920 
1921       g_free (ctmp1);
1922 
1923       pango_win32_font_map_fontset_add_fonts (fontmap,
1924                                               context,
1925                                               fonts,
1926                                               tmp_desc,
1927                                               "Sans");
1928     }
1929 
1930   /* We couldn't try with Sans and the specified style. Try Sans Normal */
1931   if (pango_fontset_simple_size (fonts) == 0)
1932     {
1933       char *ctmp1, *ctmp2;
1934 
1935       pango_font_description_set_family_static (tmp_desc, "Sans");
1936       ctmp1 = pango_font_description_to_string (tmp_desc);
1937       pango_font_description_set_style (tmp_desc, PANGO_STYLE_NORMAL);
1938       pango_font_description_set_weight (tmp_desc, PANGO_WEIGHT_NORMAL);
1939       pango_font_description_set_variant (tmp_desc, PANGO_VARIANT_NORMAL);
1940       pango_font_description_set_stretch (tmp_desc, PANGO_STRETCH_NORMAL);
1941 
1942 
1943       if (!g_hash_table_lookup (warned_fonts, ctmp1))
1944         {
1945           g_hash_table_insert (warned_fonts, g_strdup (ctmp1), GINT_TO_POINTER (1));
1946 
1947           ctmp2 = pango_font_description_to_string (tmp_desc);
1948 
1949           g_warning ("couldn't load font \"%s\", falling back to \"%s\", "
1950                      "expect ugly output.", ctmp1, ctmp2);
1951           g_free (ctmp2);
1952         }
1953 
1954       g_free (ctmp1);
1955 
1956       pango_win32_font_map_fontset_add_fonts (fontmap,
1957                                               context,
1958                                               fonts,
1959                                               tmp_desc,
1960                                               "Sans");
1961     }
1962 
1963   pango_font_description_free (tmp_desc);
1964 
1965   /* Everything failed, we are screwed, there is no way to continue,
1966    * but lets just not crash here.
1967    */
1968   if (pango_fontset_simple_size (fonts) == 0)
1969     g_warning ("All font fallbacks failed!!!!");
1970 
1971   return PANGO_FONTSET (fonts);
1972 }
1973