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