]> Pileus Git - ~andy/gtk/blob - gdk/win32/gdkfont-win32.c
Fix braino, actually do check each char, not just the first one, when
[~andy/gtk] / gdk / win32 / gdkfont-win32.c
1 /* GDK - The GIMP Drawing Kit
2  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
3  * Copyright (C) 1998-2002 Tor Lillqvist
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the
17  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18  * Boston, MA 02111-1307, USA.
19  */
20
21 /*
22  * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
23  * file for a list of people on the GTK+ Team.  See the ChangeLog
24  * files for a list of changes.  These files are distributed with
25  * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
26  */
27
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <ctype.h>
31
32 #include <pango/pangowin32.h>
33
34 #include "gdkfont.h"
35 #include "gdkpango.h" /* gdk_pango_context_get() */
36 #include "gdkdisplay.h"
37 #include "gdkprivate-win32.h"
38
39 static GHashTable *font_name_hash = NULL;
40 static GHashTable *fontset_name_hash = NULL;
41
42 static void
43 gdk_font_hash_insert (GdkFontType  type,
44                       GdkFont     *font,
45                       const gchar *font_name)
46 {
47   GdkFontPrivateWin32 *private = (GdkFontPrivateWin32 *) font;
48   GHashTable **hashp = (type == GDK_FONT_FONT) ?
49     &font_name_hash : &fontset_name_hash;
50
51   if (!*hashp)
52     *hashp = g_hash_table_new (g_str_hash, g_str_equal);
53
54   private->names = g_slist_prepend (private->names, g_strdup (font_name));
55   g_hash_table_insert (*hashp, private->names->data, font);
56 }
57
58 static void
59 gdk_font_hash_remove (GdkFontType type,
60                       GdkFont    *font)
61 {
62   GdkFontPrivateWin32 *private = (GdkFontPrivateWin32 *) font;
63   GSList *tmp_list;
64   GHashTable *hash = (type == GDK_FONT_FONT) ?
65     font_name_hash : fontset_name_hash;
66
67   tmp_list = private->names;
68   while (tmp_list)
69     {
70       g_hash_table_remove (hash, tmp_list->data);
71       g_free (tmp_list->data);
72       
73       tmp_list = tmp_list->next;
74     }
75
76   g_slist_free (private->names);
77   private->names = NULL;
78 }
79
80 static GdkFont *
81 gdk_font_hash_lookup (GdkFontType  type,
82                       const gchar *font_name)
83 {
84   GdkFont *result;
85   GHashTable *hash = (type == GDK_FONT_FONT) ?
86     font_name_hash : fontset_name_hash;
87
88   if (!hash)
89     return NULL;
90   else
91     {
92       result = g_hash_table_lookup (hash, font_name);
93       if (result)
94         gdk_font_ref (result);
95       
96       return result;
97     }
98 }
99
100 static const char *
101 charset_name (DWORD charset)
102 {
103   switch (charset)
104     {
105     case ANSI_CHARSET: return "ansi";
106     case DEFAULT_CHARSET: return "default";
107     case SYMBOL_CHARSET: return "symbol";
108     case SHIFTJIS_CHARSET: return "shiftjis";
109     case HANGEUL_CHARSET: return "hangeul";
110     case GB2312_CHARSET: return "gb2312";
111     case CHINESEBIG5_CHARSET: return "big5";
112     case JOHAB_CHARSET: return "johab";
113     case HEBREW_CHARSET: return "hebrew";
114     case ARABIC_CHARSET: return "arabic";
115     case GREEK_CHARSET: return "greek";
116     case TURKISH_CHARSET: return "turkish";
117     case VIETNAMESE_CHARSET: return "vietnamese";
118     case THAI_CHARSET: return "thai";
119     case EASTEUROPE_CHARSET: return "easteurope";
120     case RUSSIAN_CHARSET: return "russian";
121     case MAC_CHARSET: return "mac";
122     case BALTIC_CHARSET: return "baltic";
123     }
124   return "unknown";
125 }
126
127 static gint num_fonts;
128 static gint font_names_size;
129 static gchar **xfontnames;
130
131 static gchar *
132 logfont_to_xlfd (const LOGFONT *lfp,
133                  int            size,
134                  int            res,
135                  int            avg_width)
136 {
137   const gchar *weight;
138   const gchar *registry, *encoding;
139   int point_size;
140   static int logpixelsy = 0;
141   gchar facename[LF_FACESIZE*5];
142   gchar *utf8_facename;
143   gchar *p;
144   const gchar *q;
145
146   if (logpixelsy == 0)
147     {
148       logpixelsy = GetDeviceCaps (gdk_display_hdc, LOGPIXELSY);
149     }
150
151   if (lfp->lfWeight >= FW_HEAVY)
152     weight = "heavy";
153   else if (lfp->lfWeight >= FW_EXTRABOLD)
154     weight = "extrabold";
155   else if (lfp->lfWeight >= FW_BOLD)
156     weight = "bold";
157 #ifdef FW_DEMIBOLD
158   else if (lfp->lfWeight >= FW_DEMIBOLD)
159     weight = "demibold";
160 #endif
161   else if (lfp->lfWeight >= FW_MEDIUM)
162     weight = "medium";
163   else if (lfp->lfWeight >= FW_NORMAL)
164     weight = "normal";
165   else if (lfp->lfWeight >= FW_LIGHT)
166     weight = "light";
167   else if (lfp->lfWeight >= FW_EXTRALIGHT)
168     weight = "extralight";
169   else if (lfp->lfWeight >= FW_THIN)
170     weight = "thin";
171   else
172     weight = "regular";
173
174   switch (lfp->lfCharSet)
175     {
176     case ANSI_CHARSET:
177       registry = "iso8859";
178       encoding = "1";
179       break;
180     case SHIFTJIS_CHARSET:
181       registry = "jisx0208.1983";
182       encoding = "0";
183       break;
184     case HANGEUL_CHARSET:
185       registry = "ksc5601.1987";
186       encoding = "0";
187       break;
188     case GB2312_CHARSET:
189       registry = "gb2312.1980";
190       encoding = "0";
191       break;
192     case CHINESEBIG5_CHARSET:
193       registry = "big5";
194       encoding = "0";
195       break;
196     case GREEK_CHARSET:
197       registry = "iso8859";
198       encoding = "7";
199       break;
200     case TURKISH_CHARSET:
201       registry = "iso8859";
202       encoding = "9";
203       break;
204 #if 0 /* Not a good idea, I think, to use ISO8859-8 and -6 for the Windows
205        * hebrew and arabic codepages, they differ too much.
206        */
207     case HEBREW_CHARSET:
208       registry = "iso8859";
209       encoding = "8";
210       break;
211     case ARABIC_CHARSET:
212       registry = "iso8859";
213       encoding = "6";
214       break;
215 #endif
216     default:
217       registry = "microsoft";
218       encoding = charset_name (lfp->lfCharSet);
219     }
220   
221   point_size = (int) (((double) size/logpixelsy) * 720.);
222
223   if (res == -1)
224     res = logpixelsy;
225
226   /* Convert the facename Windows fives us from the locale-dependent
227    * codepage to UTF-8.
228    */
229   utf8_facename = g_filename_to_utf8 (lfp->lfFaceName, -1, NULL, NULL, NULL);
230
231   /* Replace characters illegal in an XLFD with hex escapes. */
232   p = facename;
233   q = utf8_facename;
234   while (*q)
235     {
236       if (*q == '-' || *q == '*' || *q == '?' || *q == '%')
237         p += sprintf (p, "%%%.02x", *q);
238       else
239         *p++ = *q;
240       q++;
241     }
242   *p = '\0';
243   g_free (utf8_facename);
244
245   return g_strdup_printf
246     ("-%s-%s-%s-%s-%s-%s-%d-%d-%d-%d-%s-%d-%s-%s",
247      "unknown", 
248      facename,
249      weight,
250      (lfp->lfItalic ?
251       ((lfp->lfPitchAndFamily & 0xF0) == FF_ROMAN
252        || (lfp->lfPitchAndFamily & 0xF0) == FF_SCRIPT ?
253        "i" : "o") : "r"),
254      "normal",
255      "",
256      size,
257      point_size,
258      res,
259      res,
260      ((lfp->lfPitchAndFamily & 0x03) == FIXED_PITCH ? "m" : "p"),
261      avg_width,
262      registry, encoding);
263 }
264
265 gchar *
266 gdk_font_full_name_get (GdkFont *font)
267 {
268   GdkFontPrivateWin32 *private;
269   GdkWin32SingleFont *singlefont;
270   GSList *list;
271   GString *string;
272   gchar *result;
273   gchar *xlfd;
274   LOGFONT logfont;
275
276   g_return_val_if_fail (font != NULL, NULL);
277
278   private = (GdkFontPrivateWin32 *) font;
279
280   list = private->fonts;
281   string = g_string_new ("");
282
283   while (list)
284     {
285       singlefont = (GdkWin32SingleFont *) list->data;
286
287       if (GetObject (singlefont->hfont, sizeof (LOGFONT), &logfont) == 0)
288         {
289           WIN32_GDI_FAILED ("GetObject");
290           return NULL;
291         }
292
293       xlfd = logfont_to_xlfd (&logfont, logfont.lfHeight, -1, 0);
294       string = g_string_append (string, xlfd);
295       g_free (xlfd);
296       list = list->next;
297       if (list)
298         string = g_string_append_c (string, ',');
299     }
300   result = string->str;
301   g_string_free (string, FALSE);
302   return result;
303 }
304
305 void
306 gdk_font_full_name_free (gchar *name)
307 {
308   g_free (name);
309 }
310
311 static gboolean
312 pattern_match (const gchar *pattern,
313                const gchar *string)
314 {
315   const gchar *p = pattern, *n = string;
316   gchar c, c1;
317
318   /* Common case first */
319   if ((pattern[0] == '*'
320        && pattern[1] == '\0')
321       || (pattern[0] == '-'
322           && pattern[1] == '*'
323           && pattern[2] == '\0'))
324     return TRUE;
325
326   while ((c = *p++) != '\0')
327     {
328       c = tolower (c);
329
330       switch (c)
331         {
332         case '?':
333           if (*n == '\0')
334             return FALSE;
335           break;
336
337         case '*':
338           for (c = *p++; c == '?' || c == '*'; c = *p++, ++n)
339             if (c == '?' && *n == '\0')
340             return FALSE;
341
342           if (c == '\0')
343             return TRUE;
344
345           c1 = tolower (c);
346           for (--p; *n != '\0'; ++n)
347             if (tolower (*n) == c1
348                 && pattern_match (p, n))
349               return TRUE;
350           return FALSE;
351
352         default:
353           if (c != tolower (*n))
354             return FALSE;
355         }
356
357       ++n;
358     }
359
360   if (*n == '\0')
361     return TRUE;
362
363   return FALSE;
364 }
365
366 static int CALLBACK
367 InnerEnumFontFamExProc (const LOGFONT    *lfp,
368                         const TEXTMETRIC *metrics,
369                         DWORD             fontType,
370                         LPARAM            lParam)
371 {
372   int size;
373   gchar *xlfd;
374
375   if (fontType == TRUETYPE_FONTTYPE)
376     {
377       size = 0;
378     }
379   else
380     {
381       size = lfp->lfHeight;
382     }
383
384   xlfd = logfont_to_xlfd (lfp, size, 0, 0);
385
386   if (!pattern_match ((gchar *) lParam, xlfd))
387     {
388       g_free (xlfd);
389       return 1;
390     }
391
392   num_fonts++;
393   if (num_fonts == font_names_size)
394     {
395       font_names_size *= 2;
396       xfontnames = g_realloc (xfontnames, font_names_size * sizeof (gchar *));
397     }
398   xfontnames[num_fonts-1] = xlfd;
399     
400   return 1;
401 }
402
403 static int CALLBACK
404 EnumFontFamExProc (const LOGFONT    *lfp,
405                    const TEXTMETRIC *metrics,
406                    DWORD             fontType,
407                    LPARAM            lParam)
408 {
409   if (fontType == TRUETYPE_FONTTYPE)
410     {
411       LOGFONT lf;
412
413       lf = *lfp;
414
415       EnumFontFamiliesEx (gdk_display_hdc, &lf, InnerEnumFontFamExProc, lParam, 0);
416     }
417   else
418     InnerEnumFontFamExProc (lfp, metrics, fontType, lParam);
419
420   return 1;
421 }
422
423 gchar **
424 gdk_font_list_new (const gchar *font_pattern,
425                    gint        *n_returned)
426 {
427   LOGFONT logfont;
428   gchar **result;
429
430   num_fonts = 0;
431   font_names_size = 100;
432   xfontnames = g_new (gchar *, font_names_size);
433   memset (&logfont, 0, sizeof (logfont));
434   logfont.lfCharSet = DEFAULT_CHARSET;
435   EnumFontFamiliesEx (gdk_display_hdc, &logfont, EnumFontFamExProc,
436                       (LPARAM) font_pattern, 0);
437
438   result = g_new (gchar *, num_fonts + 1);
439   memmove (result, xfontnames, num_fonts * sizeof (gchar *));
440   result[num_fonts] = NULL;
441   g_free (xfontnames);
442
443   *n_returned = num_fonts;
444   return result;
445 }
446
447 void
448 gdk_font_list_free (gchar **font_list)
449 {
450   g_strfreev (font_list);
451 }
452
453 /* This table classifies Unicode characters according to the Microsoft
454  * Unicode subset numbering. This is based on the table in "Developing
455  * International Software for Windows 95 and Windows NT". This is almost,
456  * but not quite, the same as the official Unicode block table in
457  * Blocks.txt from ftp.unicode.org. The bit number field is the bitfield
458  * number as in the FONTSIGNATURE struct's fsUsb field.
459  * There are some grave bugs in the table in the books. For instance
460  * it claims there are Hangul at U+3400..U+4DFF while this range in
461  * fact contains CJK Unified Ideographs Extension A. Also, the whole
462  * block of Hangul Syllables U+AC00..U+D7A3 is missing from the book.
463  */
464
465 typedef enum
466 {
467   U_BASIC_LATIN = 0,
468   U_LATIN_1_SUPPLEMENT = 1,
469   U_LATIN_EXTENDED_A = 2,
470   U_LATIN_EXTENDED_B = 3,
471   U_IPA_EXTENSIONS = 4,
472   U_SPACING_MODIFIER_LETTERS = 5,
473   U_COMBINING_DIACRITICAL_MARKS = 6,
474   U_BASIC_GREEK = 7,
475   U_GREEK_SYMBOLS_AND_COPTIC = 8,
476   U_CYRILLIC = 9,
477   U_ARMENIAN = 10,
478   U_HEBREW_EXTENDED = 12,
479   U_BASIC_HEBREW = 11,
480   U_BASIC_ARABIC = 13,
481   U_ARABIC_EXTENDED = 14,
482   U_DEVANAGARI = 15,
483   U_BENGALI = 16,
484   U_GURMUKHI = 17,
485   U_GUJARATI = 18,
486   U_ORIYA = 19,
487   U_TAMIL = 20,
488   U_TELUGU = 21,
489   U_KANNADA = 22,
490   U_MALAYALAM = 23,
491   U_THAI = 24,
492   U_LAO = 25,
493   U_GEORGIAN_EXTENDED = 27,
494   U_BASIC_GEORGIAN = 26,
495   U_HANGUL_JAMO = 28,
496   U_LATIN_EXTENDED_ADDITIONAL = 29,
497   U_GREEK_EXTENDED = 30,
498   U_GENERAL_PUNCTUATION = 31,
499   U_SUPERSCRIPTS_AND_SUBSCRIPTS = 32,
500   U_CURRENCY_SYMBOLS = 33,
501   U_COMBINING_DIACRITICAL_MARKS_FOR_SYMBOLS = 34,
502   U_LETTERLIKE_SYMBOLS = 35,
503   U_NUMBER_FORMS = 36,
504   U_ARROWS = 37,
505   U_MATHEMATICAL_OPERATORS = 38,
506   U_MISCELLANEOUS_TECHNICAL = 39,
507   U_CONTROL_PICTURES = 40,
508   U_OPTICAL_CHARACTER_RECOGNITION = 41,
509   U_ENCLOSED_ALPHANUMERICS = 42,
510   U_BOX_DRAWING = 43,
511   U_BLOCK_ELEMENTS = 44,
512   U_GEOMETRIC_SHAPES = 45,
513   U_MISCELLANEOUS_SYMBOLS = 46,
514   U_DINGBATS = 47,
515   U_CJK_SYMBOLS_AND_PUNCTUATION = 48,
516   U_HIRAGANA = 49,
517   U_KATAKANA = 50,
518   U_BOPOMOFO = 51,
519   U_HANGUL_COMPATIBILITY_JAMO = 52,
520   U_CJK_MISCELLANEOUS = 53,
521   U_ENCLOSED_CJK = 54,
522   U_CJK_COMPATIBILITY = 55,
523   U_HANGUL = 56,
524   U_HANGUL_SUPPLEMENTARY_A = 57,
525   U_HANGUL_SUPPLEMENTARY_B = 58,
526   U_CJK_UNIFIED_IDEOGRAPHS = 59,
527   U_PRIVATE_USE_AREA = 60,
528   U_CJK_COMPATIBILITY_IDEOGRAPHS = 61,
529   U_ALPHABETIC_PRESENTATION_FORMS = 62,
530   U_ARABIC_PRESENTATION_FORMS_A = 63,
531   U_COMBINING_HALF_MARKS = 64,
532   U_CJK_COMPATIBILITY_FORMS = 65,
533   U_SMALL_FORM_VARIANTS = 66,
534   U_ARABIC_PRESENTATION_FORMS_B = 67,
535   U_SPECIALS = 69,
536   U_HALFWIDTH_AND_FULLWIDTH_FORMS = 68,
537   U_LAST_PLUS_ONE
538 } unicode_subset;
539
540 static struct {
541   wchar_t low, high;
542   unicode_subset bit; 
543   gchar *name;
544 } utab[] =
545 {
546   { 0x0000, 0x007E,
547     U_BASIC_LATIN, "Basic Latin" },
548   { 0x00A0, 0x00FF,
549     U_LATIN_1_SUPPLEMENT, "Latin-1 Supplement" },
550   { 0x0100, 0x017F,
551     U_LATIN_EXTENDED_A, "Latin Extended-A" },
552   { 0x0180, 0x024F,
553     U_LATIN_EXTENDED_B, "Latin Extended-B" },
554   { 0x0250, 0x02AF,
555     U_IPA_EXTENSIONS, "IPA Extensions" },
556   { 0x02B0, 0x02FF,
557     U_SPACING_MODIFIER_LETTERS, "Spacing Modifier Letters" },
558   { 0x0300, 0x036F,
559     U_COMBINING_DIACRITICAL_MARKS, "Combining Diacritical Marks" },
560   { 0x0370, 0x03CF,
561     U_BASIC_GREEK, "Basic Greek" },
562   { 0x03D0, 0x03FF,
563     U_GREEK_SYMBOLS_AND_COPTIC, "Greek Symbols and Coptic" },
564   { 0x0400, 0x04FF,
565     U_CYRILLIC, "Cyrillic" },
566   { 0x0530, 0x058F,
567     U_ARMENIAN, "Armenian" },
568   { 0x0590, 0x05CF,
569     U_HEBREW_EXTENDED, "Hebrew Extended" },
570   { 0x05D0, 0x05FF,
571     U_BASIC_HEBREW, "Basic Hebrew" },
572   { 0x0600, 0x0652,
573     U_BASIC_ARABIC, "Basic Arabic" },
574   { 0x0653, 0x06FF,
575     U_ARABIC_EXTENDED, "Arabic Extended" },
576   { 0x0900, 0x097F,
577     U_DEVANAGARI, "Devanagari" },
578   { 0x0980, 0x09FF,
579     U_BENGALI, "Bengali" },
580   { 0x0A00, 0x0A7F,
581     U_GURMUKHI, "Gurmukhi" },
582   { 0x0A80, 0x0AFF,
583     U_GUJARATI, "Gujarati" },
584   { 0x0B00, 0x0B7F,
585     U_ORIYA, "Oriya" },
586   { 0x0B80, 0x0BFF,
587     U_TAMIL, "Tamil" },
588   { 0x0C00, 0x0C7F,
589     U_TELUGU, "Telugu" },
590   { 0x0C80, 0x0CFF,
591     U_KANNADA, "Kannada" },
592   { 0x0D00, 0x0D7F,
593     U_MALAYALAM, "Malayalam" },
594   { 0x0E00, 0x0E7F,
595     U_THAI, "Thai" },
596   { 0x0E80, 0x0EFF,
597     U_LAO, "Lao" },
598   { 0x10A0, 0x10CF,
599     U_GEORGIAN_EXTENDED, "Georgian Extended" },
600   { 0x10D0, 0x10FF,
601     U_BASIC_GEORGIAN, "Basic Georgian" },
602   { 0x1100, 0x11FF,
603     U_HANGUL_JAMO, "Hangul Jamo" },
604   { 0x1E00, 0x1EFF,
605     U_LATIN_EXTENDED_ADDITIONAL, "Latin Extended Additional" },
606   { 0x1F00, 0x1FFF,
607     U_GREEK_EXTENDED, "Greek Extended" },
608   { 0x2000, 0x206F,
609     U_GENERAL_PUNCTUATION, "General Punctuation" },
610   { 0x2070, 0x209F,
611     U_SUPERSCRIPTS_AND_SUBSCRIPTS, "Superscripts and Subscripts" },
612   { 0x20A0, 0x20CF,
613     U_CURRENCY_SYMBOLS, "Currency Symbols" },
614   { 0x20D0, 0x20FF,
615     U_COMBINING_DIACRITICAL_MARKS_FOR_SYMBOLS, "Combining Diacritical Marks for Symbols" },
616   { 0x2100, 0x214F,
617     U_LETTERLIKE_SYMBOLS, "Letterlike Symbols" },
618   { 0x2150, 0x218F,
619     U_NUMBER_FORMS, "Number Forms" },
620   { 0x2190, 0x21FF,
621     U_ARROWS, "Arrows" },
622   { 0x2200, 0x22FF,
623     U_MATHEMATICAL_OPERATORS, "Mathematical Operators" },
624   { 0x2300, 0x23FF,
625     U_MISCELLANEOUS_TECHNICAL, "Miscellaneous Technical" },
626   { 0x2400, 0x243F,
627     U_CONTROL_PICTURES, "Control Pictures" },
628   { 0x2440, 0x245F,
629     U_OPTICAL_CHARACTER_RECOGNITION, "Optical Character Recognition" },
630   { 0x2460, 0x24FF,
631     U_ENCLOSED_ALPHANUMERICS, "Enclosed Alphanumerics" },
632   { 0x2500, 0x257F,
633     U_BOX_DRAWING, "Box Drawing" },
634   { 0x2580, 0x259F,
635     U_BLOCK_ELEMENTS, "Block Elements" },
636   { 0x25A0, 0x25FF,
637     U_GEOMETRIC_SHAPES, "Geometric Shapes" },
638   { 0x2600, 0x26FF,
639     U_MISCELLANEOUS_SYMBOLS, "Miscellaneous Symbols" },
640   { 0x2700, 0x27BF,
641     U_DINGBATS, "Dingbats" },
642   { 0x3000, 0x303F,
643     U_CJK_SYMBOLS_AND_PUNCTUATION, "CJK Symbols and Punctuation" },
644   { 0x3040, 0x309F,
645     U_HIRAGANA, "Hiragana" },
646   { 0x30A0, 0x30FF,
647     U_KATAKANA, "Katakana" },
648   { 0x3100, 0x312F,
649     U_BOPOMOFO, "Bopomofo" },
650   { 0x3130, 0x318F,
651     U_HANGUL_COMPATIBILITY_JAMO, "Hangul Compatibility Jamo" },
652   { 0x3190, 0x319F,
653     U_CJK_MISCELLANEOUS, "CJK Miscellaneous" },
654   { 0x3200, 0x32FF,
655     U_ENCLOSED_CJK, "Enclosed CJK" },
656   { 0x3300, 0x33FF,
657     U_CJK_COMPATIBILITY, "CJK Compatibility" },
658   /* The book claims:
659    * U+3400..U+3D2D = Hangul
660    * U+3D2E..U+44B7 = Hangul Supplementary A
661    * U+44B8..U+4DFF = Hangul Supplementary B
662    * but actually in Unicode
663    * U+3400..U+4DB5 = CJK Unified Ideographs Extension A
664    */
665   { 0x3400, 0x4DB5,
666     U_CJK_UNIFIED_IDEOGRAPHS, "CJK Unified Ideographs Extension A" },
667   { 0x4E00, 0x9FFF,
668     U_CJK_UNIFIED_IDEOGRAPHS, "CJK Unified Ideographs" },
669   /* This was missing completely from the book's table. */
670   { 0xAC00, 0xD7A3,
671     U_HANGUL, "Hangul Syllables" },
672   { 0xE000, 0xF8FF,
673     U_PRIVATE_USE_AREA, "Private Use Area" },
674   { 0xF900, 0xFAFF,
675     U_CJK_COMPATIBILITY_IDEOGRAPHS, "CJK Compatibility Ideographs" },
676   { 0xFB00, 0xFB4F,
677     U_ALPHABETIC_PRESENTATION_FORMS, "Alphabetic Presentation Forms" },
678   { 0xFB50, 0xFDFF,
679     U_ARABIC_PRESENTATION_FORMS_A, "Arabic Presentation Forms-A" },
680   { 0xFE20, 0xFE2F,
681     U_COMBINING_HALF_MARKS, "Combining Half Marks" },
682   { 0xFE30, 0xFE4F,
683     U_CJK_COMPATIBILITY_FORMS, "CJK Compatibility Forms" },
684   { 0xFE50, 0xFE6F,
685     U_SMALL_FORM_VARIANTS, "Small Form Variants" },
686   { 0xFE70, 0xFEFE,
687     U_ARABIC_PRESENTATION_FORMS_B, "Arabic Presentation Forms-B" },
688   { 0xFEFF, 0xFEFF,
689     U_SPECIALS, "Specials" },
690   { 0xFF00, 0xFFEF,
691     U_HALFWIDTH_AND_FULLWIDTH_FORMS, "Halfwidth and Fullwidth Forms" },
692   { 0xFFF0, 0xFFFD,
693     U_SPECIALS, "Specials" }
694 };
695
696 static void
697 print_unicode_subranges (FONTSIGNATURE *fsp)
698 {
699   int i;
700   gboolean checked[G_N_ELEMENTS (utab)];
701   gboolean need_comma = FALSE;
702
703   memset (checked, 0, sizeof (checked));
704
705   for (i = 0; i < G_N_ELEMENTS (utab); i++)
706     if (!checked[i]
707         && (fsp->fsUsb[utab[i].bit/32] & (1 << (utab[i].bit % 32))))
708       {
709         g_print ("%s %s", (need_comma ? "," : ""), utab[i].name);
710         need_comma = TRUE;
711         checked[i] = TRUE;
712       }
713   if (!need_comma)
714     g_print (" none!");
715   g_print ("\n");
716 }
717
718 static gboolean
719 check_unicode_subranges (UINT           charset,
720                          FONTSIGNATURE *fsp)
721 {
722   gint i;
723   gboolean retval = FALSE;
724
725   /* If the fsUsb bit array has at least one of the bits set, trust it */
726   for (i = 0; i < U_LAST_PLUS_ONE; i++)
727     if (i != U_PRIVATE_USE_AREA && (fsp->fsUsb[i/32] & (1 << (i % 32))))
728       return FALSE;
729
730   /* Otherwise, guess what subranges there should be in the font */
731   fsp->fsUsb[0] = fsp->fsUsb[1] = fsp->fsUsb[2] = fsp->fsUsb[3] = 0;
732
733 #define set_bit(bitno) (fsp->fsUsb[(bitno)/32] |= (1 << ((bitno) % 32)))
734
735   /* Set Unicode subrange bits based on code pages supported.
736    * This is mostly just guesswork.
737    */
738
739 #define check_cp(bit) (fsp->fsCsb[0] & (bit))
740
741   if (check_cp(FS_LATIN1))
742     {
743       set_bit (U_BASIC_LATIN);
744       set_bit (U_LATIN_1_SUPPLEMENT);
745       set_bit (U_CURRENCY_SYMBOLS);
746       retval = TRUE;
747     }
748   if (check_cp (FS_LATIN2))
749     {
750       set_bit (U_BASIC_LATIN);
751       set_bit (U_LATIN_1_SUPPLEMENT);
752       set_bit (U_LATIN_EXTENDED_A);
753       set_bit (U_CURRENCY_SYMBOLS);
754       retval = TRUE;
755     }
756   if (check_cp (FS_CYRILLIC))
757     {
758       set_bit (U_BASIC_LATIN);
759       set_bit (U_CYRILLIC);
760       retval = TRUE;
761     }
762   if (check_cp (FS_GREEK))
763     {
764       set_bit (U_BASIC_LATIN);
765       set_bit (U_BASIC_GREEK);
766       retval = TRUE;
767     }
768   if (check_cp (FS_TURKISH))
769     {
770       set_bit (U_BASIC_LATIN);
771       set_bit (U_LATIN_1_SUPPLEMENT);
772       set_bit (U_LATIN_EXTENDED_A);
773       set_bit (U_CURRENCY_SYMBOLS);
774       retval = TRUE;
775     }
776   if (check_cp (FS_HEBREW))
777     {
778       set_bit (U_BASIC_LATIN);
779       set_bit (U_CURRENCY_SYMBOLS);
780       set_bit (U_BASIC_HEBREW);
781       set_bit (U_HEBREW_EXTENDED);
782       retval = TRUE;
783     }
784   if (check_cp (FS_ARABIC))
785     {
786       set_bit (U_BASIC_LATIN);
787       set_bit (U_CURRENCY_SYMBOLS);
788       set_bit (U_BASIC_ARABIC);
789       set_bit (U_ARABIC_EXTENDED);
790       retval = TRUE;
791     }
792   if (check_cp (FS_BALTIC))
793     {
794       set_bit (U_BASIC_LATIN);
795       set_bit (U_LATIN_1_SUPPLEMENT);
796       set_bit (U_CURRENCY_SYMBOLS);
797       set_bit (U_LATIN_EXTENDED_A);
798       set_bit (U_LATIN_EXTENDED_B);
799       retval = TRUE;
800     }
801   if (check_cp (FS_VIETNAMESE))
802     {
803       /* ??? */
804       set_bit (U_BASIC_LATIN);
805       retval = TRUE;
806     }
807   if (check_cp (FS_THAI))
808     {
809       set_bit (U_BASIC_LATIN);
810       set_bit (U_THAI);
811       retval = TRUE;
812     }
813   if (check_cp (FS_JISJAPAN))
814     {
815       /* Based on MS Gothic */
816       set_bit (U_BASIC_LATIN);
817       set_bit (U_CJK_SYMBOLS_AND_PUNCTUATION);
818       set_bit (U_HIRAGANA);
819       set_bit (U_KATAKANA);
820       set_bit (U_CJK_UNIFIED_IDEOGRAPHS);
821       set_bit (U_HALFWIDTH_AND_FULLWIDTH_FORMS);
822       retval = TRUE;
823     }
824   if (check_cp (FS_CHINESESIMP))
825     {
826       /* Based on MS Hei */
827       set_bit (U_BASIC_LATIN);
828       set_bit (U_HIRAGANA);
829       set_bit (U_KATAKANA);
830       set_bit (U_BOPOMOFO);
831       set_bit (U_CJK_UNIFIED_IDEOGRAPHS);
832       retval = TRUE;
833     }
834   if (check_cp (FS_WANSUNG)
835       || check_cp (FS_JOHAB))   /* ??? */
836     {
837       /* Based on GulimChe. I wonder if all Korean fonts
838        * really support this large range of Unicode subranges?
839        */
840       set_bit (U_BASIC_LATIN);
841       set_bit (U_LATIN_1_SUPPLEMENT);
842       set_bit (U_LATIN_EXTENDED_A);
843       set_bit (U_SPACING_MODIFIER_LETTERS);
844       set_bit (U_BASIC_GREEK);
845       set_bit (U_CYRILLIC);
846       set_bit (U_HANGUL_JAMO);
847       set_bit (U_GENERAL_PUNCTUATION);
848       set_bit (U_SUPERSCRIPTS_AND_SUBSCRIPTS);
849       set_bit (U_CURRENCY_SYMBOLS);
850       set_bit (U_LETTERLIKE_SYMBOLS);
851       set_bit (U_NUMBER_FORMS);
852       set_bit (U_ARROWS);
853       set_bit (U_MATHEMATICAL_OPERATORS);
854       set_bit (U_MISCELLANEOUS_TECHNICAL);
855       set_bit (U_ENCLOSED_ALPHANUMERICS);
856       set_bit (U_BOX_DRAWING);
857       set_bit (U_BLOCK_ELEMENTS);
858       set_bit (U_GEOMETRIC_SHAPES);
859       set_bit (U_MISCELLANEOUS_SYMBOLS);
860       set_bit (U_CJK_SYMBOLS_AND_PUNCTUATION);
861       set_bit (U_HIRAGANA);
862       set_bit (U_KATAKANA);
863       set_bit (U_HANGUL_COMPATIBILITY_JAMO);
864       set_bit (U_ENCLOSED_CJK);
865       set_bit (U_CJK_COMPATIBILITY_FORMS);
866       set_bit (U_HANGUL);
867       set_bit (U_CJK_UNIFIED_IDEOGRAPHS);
868       set_bit (U_CJK_COMPATIBILITY_IDEOGRAPHS);
869       set_bit (U_HALFWIDTH_AND_FULLWIDTH_FORMS);
870       retval = TRUE;
871     }
872   if (check_cp (FS_CHINESETRAD))
873     {
874       /* Based on MingLiU */
875       set_bit (U_BASIC_LATIN);
876       set_bit (U_GENERAL_PUNCTUATION);
877       set_bit (U_BOX_DRAWING);
878       set_bit (U_BLOCK_ELEMENTS);
879       set_bit (U_CJK_SYMBOLS_AND_PUNCTUATION);
880       set_bit (U_BOPOMOFO);
881       set_bit (U_CJK_UNIFIED_IDEOGRAPHS);
882       set_bit (U_CJK_COMPATIBILITY_IDEOGRAPHS);
883       set_bit (U_SMALL_FORM_VARIANTS);
884       set_bit (U_HALFWIDTH_AND_FULLWIDTH_FORMS);
885       retval = TRUE;
886     }
887   if (check_cp (FS_SYMBOL) || charset == MAC_CHARSET)
888     {
889       /* Non-Unicode encoding, I guess. Pretend it covers
890        * the single-byte range of values.
891        */
892       set_bit (U_BASIC_LATIN);
893       set_bit (U_LATIN_1_SUPPLEMENT);
894       retval = TRUE;
895     }
896
897   if (retval)
898     return TRUE;
899
900   GDK_NOTE (MISC, g_print ("... No code page bits set!\n"));
901
902   /* Sigh. Not even any code page bits were set. Guess based on
903    * charset, then. These somewhat optimistic guesses are based on the
904    * table in Appendix M in the book "Developing ..."  mentioned
905    * above.
906    */
907   switch (charset)
908     {
909     case ANSI_CHARSET:
910       set_bit (U_BASIC_LATIN);
911       set_bit (U_LATIN_1_SUPPLEMENT);
912       set_bit (U_LATIN_EXTENDED_A);
913       set_bit (U_LATIN_EXTENDED_B);
914       set_bit (U_SPACING_MODIFIER_LETTERS);
915       set_bit (U_COMBINING_DIACRITICAL_MARKS);
916       set_bit (U_GENERAL_PUNCTUATION);
917       set_bit (U_SUPERSCRIPTS_AND_SUBSCRIPTS);
918       set_bit (U_CURRENCY_SYMBOLS);
919 #if 0 /* I find this too hard to believe... */
920       set_bit (U_BASIC_GREEK);
921       set_bit (U_CYRILLIC);
922       set_bit (U_BASIC_HEBREW);
923       set_bit (U_HEBREW_EXTENDED);
924       set_bit (U_BASIC_ARABIC);
925       set_bit (U_ARABIC_EXTENDED);
926       set_bit (U_LETTERLIKE_SYMBOLS);
927       set_bit (U_NUMBER_FORMS);
928       set_bit (U_ARROWS);
929       set_bit (U_MATHEMATICAL_OPERATORS);
930       set_bit (U_MISCELLANEOUS_TECHNICAL);
931       set_bit (U_ENCLOSED_ALPHANUMERICS);
932       set_bit (U_BOX_DRAWING);
933       set_bit (U_BLOCK_ELEMENTS);
934       set_bit (U_GEOMETRIC_SHAPES);
935       set_bit (U_MISCELLANEOUS_SYMBOLS);
936       set_bit (U_HIRAGANA);
937       set_bit (U_KATAKANA);
938       set_bit (U_BOPOMOFO);
939       set_bit (U_HANGUL_COMPATIBILITY_JAMO);
940       set_bit (U_CJK_MISCELLANEOUS);
941       set_bit (U_CJK_COMPATIBILITY);
942       set_bit (U_HANGUL);
943       set_bit (U_HANGUL_SUPPLEMENTARY_A);
944       set_bit (U_CJK_COMPATIBILITY_IDEOGRAPHS);
945       set_bit (U_ALPHABETIC_PRESENTATION_FORMS);
946       set_bit (U_SMALL_FORM_VARIANTS);
947       set_bit (U_ARABIC_PRESENTATION_FORMS_B);
948       set_bit (U_HALFWIDTH_AND_FULLWIDTH_FORMS);
949       set_bit (U_SPECIALS);
950 #endif
951       retval = TRUE;
952       break;
953     case SYMBOL_CHARSET:
954       /* Unggh */
955       set_bit (U_BASIC_LATIN);
956       set_bit (U_LATIN_1_SUPPLEMENT);
957       retval = TRUE;
958       break;
959     case SHIFTJIS_CHARSET:
960     case HANGEUL_CHARSET:
961     case GB2312_CHARSET:
962     case CHINESEBIG5_CHARSET:
963     case JOHAB_CHARSET:
964       /* The table really does claim these "locales" (it doesn't
965        * talk about charsets per se) cover the same Unicode
966        * subranges
967        */
968       set_bit (U_BASIC_LATIN);
969       set_bit (U_LATIN_1_SUPPLEMENT);
970       set_bit (U_LATIN_EXTENDED_A);
971       set_bit (U_LATIN_EXTENDED_B);
972       set_bit (U_SPACING_MODIFIER_LETTERS);
973       set_bit (U_COMBINING_DIACRITICAL_MARKS_FOR_SYMBOLS);
974       set_bit (U_BASIC_GREEK);
975       set_bit (U_CYRILLIC);
976       set_bit (U_HANGUL_JAMO);
977       set_bit (U_GENERAL_PUNCTUATION);
978       set_bit (U_SUPERSCRIPTS_AND_SUBSCRIPTS);
979       set_bit (U_CURRENCY_SYMBOLS);
980       set_bit (U_LETTERLIKE_SYMBOLS);
981       set_bit (U_NUMBER_FORMS);
982       set_bit (U_ARROWS);
983       set_bit (U_MATHEMATICAL_OPERATORS);
984       set_bit (U_MISCELLANEOUS_TECHNICAL);
985       set_bit (U_ENCLOSED_ALPHANUMERICS);
986       set_bit (U_BOX_DRAWING);
987       set_bit (U_BLOCK_ELEMENTS);
988       set_bit (U_GEOMETRIC_SHAPES);
989       set_bit (U_MISCELLANEOUS_SYMBOLS);
990       set_bit (U_CJK_SYMBOLS_AND_PUNCTUATION);
991       set_bit (U_HIRAGANA);
992       set_bit (U_KATAKANA);
993       set_bit (U_BOPOMOFO);
994       set_bit (U_HANGUL_COMPATIBILITY_JAMO);
995       set_bit (U_CJK_MISCELLANEOUS);
996       set_bit (U_CJK_COMPATIBILITY);
997       set_bit (U_HANGUL);
998       set_bit (U_HANGUL_SUPPLEMENTARY_A);
999       set_bit (U_CJK_UNIFIED_IDEOGRAPHS);
1000       set_bit (U_CJK_COMPATIBILITY_IDEOGRAPHS);
1001       set_bit (U_ALPHABETIC_PRESENTATION_FORMS);
1002       set_bit (U_SMALL_FORM_VARIANTS);
1003       set_bit (U_ARABIC_PRESENTATION_FORMS_B);
1004       set_bit (U_SPECIALS);
1005       retval = TRUE;
1006       break;
1007     case HEBREW_CHARSET:
1008       set_bit (U_BASIC_LATIN);
1009       set_bit (U_LATIN_1_SUPPLEMENT);
1010       set_bit (U_LATIN_EXTENDED_B);
1011       set_bit (U_SPACING_MODIFIER_LETTERS);
1012       set_bit (U_BASIC_HEBREW);
1013       set_bit (U_HEBREW_EXTENDED);
1014       set_bit (U_GENERAL_PUNCTUATION);
1015       set_bit (U_LETTERLIKE_SYMBOLS);
1016       retval = TRUE; 
1017       break;
1018     case ARABIC_CHARSET:
1019       set_bit (U_BASIC_LATIN);
1020       set_bit (U_LATIN_1_SUPPLEMENT);
1021       set_bit (U_LATIN_EXTENDED_A);
1022       set_bit (U_LATIN_EXTENDED_B);
1023       set_bit (U_SPACING_MODIFIER_LETTERS);
1024       set_bit (U_BASIC_GREEK);
1025       set_bit (U_BASIC_ARABIC);
1026       set_bit (U_ARABIC_EXTENDED);
1027       set_bit (U_GENERAL_PUNCTUATION);
1028       set_bit (U_LETTERLIKE_SYMBOLS);
1029       set_bit (U_ARROWS);
1030       set_bit (U_MATHEMATICAL_OPERATORS);
1031       set_bit (U_MISCELLANEOUS_TECHNICAL);
1032       set_bit (U_BOX_DRAWING);
1033       set_bit (U_BLOCK_ELEMENTS);
1034       set_bit (U_GEOMETRIC_SHAPES);
1035       set_bit (U_MISCELLANEOUS_SYMBOLS);
1036       set_bit (U_HALFWIDTH_AND_FULLWIDTH_FORMS);
1037       retval = TRUE;
1038       break;
1039     case GREEK_CHARSET:
1040       set_bit (U_BASIC_LATIN);
1041       set_bit (U_LATIN_1_SUPPLEMENT);
1042       set_bit (U_LATIN_EXTENDED_B);
1043       set_bit (U_BASIC_GREEK);
1044       set_bit (U_GENERAL_PUNCTUATION);
1045       set_bit (U_SUPERSCRIPTS_AND_SUBSCRIPTS);
1046       set_bit (U_LETTERLIKE_SYMBOLS);
1047       set_bit (U_ARROWS);
1048       set_bit (U_MATHEMATICAL_OPERATORS);
1049       set_bit (U_MISCELLANEOUS_TECHNICAL);
1050       set_bit (U_BOX_DRAWING);
1051       set_bit (U_BLOCK_ELEMENTS);
1052       set_bit (U_GEOMETRIC_SHAPES);
1053       set_bit (U_MISCELLANEOUS_SYMBOLS);
1054       retval = TRUE;
1055       break;
1056     case TURKISH_CHARSET:
1057       set_bit (U_BASIC_LATIN);
1058       set_bit (U_LATIN_1_SUPPLEMENT);
1059       set_bit (U_LATIN_EXTENDED_A);
1060       set_bit (U_LATIN_EXTENDED_B);
1061       set_bit (U_SPACING_MODIFIER_LETTERS);
1062       set_bit (U_BASIC_GREEK);
1063       set_bit (U_GENERAL_PUNCTUATION);
1064       set_bit (U_SUPERSCRIPTS_AND_SUBSCRIPTS);
1065       set_bit (U_CURRENCY_SYMBOLS);
1066       set_bit (U_LETTERLIKE_SYMBOLS);
1067       set_bit (U_ARROWS);
1068       set_bit (U_MATHEMATICAL_OPERATORS);
1069       set_bit (U_MISCELLANEOUS_TECHNICAL);
1070       set_bit (U_BOX_DRAWING);
1071       set_bit (U_BLOCK_ELEMENTS);
1072       set_bit (U_GEOMETRIC_SHAPES);
1073       set_bit (U_MISCELLANEOUS_SYMBOLS);
1074       retval = TRUE;
1075       break;
1076     case VIETNAMESE_CHARSET:
1077     case THAI_CHARSET:
1078       /* These are not in the table, so I have no idea */
1079       break;
1080     case BALTIC_CHARSET:
1081       set_bit (U_BASIC_LATIN);
1082       set_bit (U_LATIN_1_SUPPLEMENT);
1083       set_bit (U_LATIN_EXTENDED_A);
1084       set_bit (U_LATIN_EXTENDED_B);
1085       set_bit (U_SPACING_MODIFIER_LETTERS);
1086       set_bit (U_BASIC_GREEK);
1087       set_bit (U_GENERAL_PUNCTUATION);
1088       set_bit (U_SUPERSCRIPTS_AND_SUBSCRIPTS);
1089       set_bit (U_CURRENCY_SYMBOLS);
1090       set_bit (U_LETTERLIKE_SYMBOLS);
1091       set_bit (U_ARROWS);
1092       set_bit (U_MATHEMATICAL_OPERATORS);
1093       set_bit (U_MISCELLANEOUS_TECHNICAL);
1094       set_bit (U_BOX_DRAWING);
1095       set_bit (U_BLOCK_ELEMENTS);
1096       set_bit (U_GEOMETRIC_SHAPES);
1097       set_bit (U_MISCELLANEOUS_SYMBOLS);
1098       retval = TRUE;
1099       break;
1100     case EASTEUROPE_CHARSET:
1101       set_bit (U_BASIC_LATIN);
1102       set_bit (U_LATIN_1_SUPPLEMENT);
1103       set_bit (U_LATIN_EXTENDED_A);
1104       set_bit (U_LATIN_EXTENDED_B);
1105       set_bit (U_SPACING_MODIFIER_LETTERS);
1106       set_bit (U_BASIC_GREEK);
1107       set_bit (U_GENERAL_PUNCTUATION);
1108       set_bit (U_SUPERSCRIPTS_AND_SUBSCRIPTS);
1109       set_bit (U_CURRENCY_SYMBOLS);
1110       set_bit (U_LETTERLIKE_SYMBOLS);
1111       set_bit (U_ARROWS);
1112       set_bit (U_MATHEMATICAL_OPERATORS);
1113       set_bit (U_MISCELLANEOUS_TECHNICAL);
1114       set_bit (U_BOX_DRAWING);
1115       set_bit (U_BLOCK_ELEMENTS);
1116       set_bit (U_GEOMETRIC_SHAPES);
1117       set_bit (U_MISCELLANEOUS_SYMBOLS);
1118       retval = TRUE;
1119       break;
1120     case RUSSIAN_CHARSET:
1121       set_bit (U_BASIC_LATIN);
1122       set_bit (U_LATIN_1_SUPPLEMENT);
1123       set_bit (U_CYRILLIC);
1124       set_bit (U_GENERAL_PUNCTUATION);
1125       set_bit (U_LETTERLIKE_SYMBOLS);
1126       set_bit (U_ARROWS);
1127       set_bit (U_MATHEMATICAL_OPERATORS);
1128       set_bit (U_MISCELLANEOUS_TECHNICAL);
1129       set_bit (U_BOX_DRAWING);
1130       set_bit (U_BLOCK_ELEMENTS);
1131       set_bit (U_GEOMETRIC_SHAPES);
1132       set_bit (U_MISCELLANEOUS_SYMBOLS);
1133       retval = TRUE;
1134       break;
1135     }
1136
1137 #undef set_bit
1138   return retval;
1139 }
1140
1141 static GdkWin32SingleFont *
1142 gdk_font_load_logfont (LOGFONT *lfp)
1143 {
1144   GdkWin32SingleFont *singlefont;
1145   HFONT hfont;
1146   LOGFONT logfont;
1147   CHARSETINFO csi;
1148   HGDIOBJ oldfont;
1149   int tries;
1150   gchar face[100];
1151
1152   for (tries = 0; ; tries++)
1153     {
1154       GDK_NOTE (MISC, g_print ("... trying %ld,%ld,%ld,%ld,"
1155                                "%ld,%d,%d,%d,"
1156                                "%d,%d,%d,"
1157                                "%d,%#.02x,\"%s\"\n",
1158                                lfp->lfHeight, lfp->lfWidth,
1159                                lfp->lfEscapement, lfp->lfOrientation,
1160                                lfp->lfWeight, lfp->lfItalic,
1161                                lfp->lfUnderline, lfp->lfStrikeOut,
1162                                lfp->lfCharSet,
1163                                lfp->lfOutPrecision, lfp->lfClipPrecision,
1164                                lfp->lfQuality, lfp->lfPitchAndFamily,
1165                                lfp->lfFaceName));
1166       hfont = CreateFontIndirect (lfp);
1167
1168       if (hfont != NULL)
1169         break;
1170       
1171       /* If we fail, try some similar fonts often found on Windows. */
1172       if (tries == 0)
1173         {
1174           if (g_strcasecmp (lfp->lfFaceName, "helvetica") == 0)
1175             strcpy (lfp->lfFaceName, "arial");
1176           else if (g_strcasecmp (lfp->lfFaceName, "new century schoolbook") == 0)
1177             strcpy (lfp->lfFaceName, "century schoolbook");
1178           else if (g_strcasecmp (lfp->lfFaceName, "courier") == 0)
1179             strcpy (lfp->lfFaceName, "courier new");
1180           else if (g_strcasecmp (lfp->lfFaceName, "lucida") == 0)
1181             strcpy (lfp->lfFaceName, "lucida sans unicode");
1182           else if (g_strcasecmp (lfp->lfFaceName, "lucidatypewriter") == 0)
1183             strcpy (lfp->lfFaceName, "lucida console");
1184           else if (g_strcasecmp (lfp->lfFaceName, "times") == 0)
1185             strcpy (lfp->lfFaceName, "times new roman");
1186         }
1187       else if (tries == 1)
1188         {
1189           if (g_strcasecmp (lfp->lfFaceName, "courier") == 0)
1190             {
1191               strcpy (lfp->lfFaceName, "");
1192               lfp->lfPitchAndFamily |= FF_MODERN;
1193             }
1194           else if (g_strcasecmp (lfp->lfFaceName, "times new roman") == 0)
1195             {
1196               strcpy (lfp->lfFaceName, "");
1197               lfp->lfPitchAndFamily |= FF_ROMAN;
1198             }
1199           else if (g_strcasecmp (lfp->lfFaceName, "helvetica") == 0
1200                    || g_strcasecmp (lfp->lfFaceName, "lucida") == 0)
1201             {
1202               strcpy (lfp->lfFaceName, "");
1203               lfp->lfPitchAndFamily |= FF_SWISS;
1204             }
1205           else
1206             {
1207               strcpy (lfp->lfFaceName, "");
1208               lfp->lfPitchAndFamily = (lfp->lfPitchAndFamily & 0x0F) | FF_DONTCARE;
1209             }
1210         }
1211       else
1212         break;
1213       tries++;
1214     }
1215
1216   if (!hfont)
1217     return NULL;
1218       
1219   singlefont = g_new (GdkWin32SingleFont, 1);
1220   singlefont->hfont = hfont;
1221   GetObject (singlefont->hfont, sizeof (logfont), &logfont);
1222   oldfont = SelectObject (gdk_display_hdc, singlefont->hfont);
1223   memset (&singlefont->fs, 0, sizeof (singlefont->fs));
1224   singlefont->charset = GetTextCharsetInfo (gdk_display_hdc, &singlefont->fs, 0);
1225   GetTextFace (gdk_display_hdc, sizeof (face), face);
1226   SelectObject (gdk_display_hdc, oldfont);
1227   if (TranslateCharsetInfo ((DWORD *) singlefont->charset, &csi,
1228                             TCI_SRCCHARSET)
1229       && singlefont->charset != MAC_CHARSET)
1230     singlefont->codepage = csi.ciACP;
1231   else
1232     singlefont->codepage = 0;
1233
1234   GDK_NOTE (MISC, (g_print ("... = %#x %s cs %s cp%d\n",
1235                             (guint) singlefont->hfont, face,
1236                             charset_name (singlefont->charset),
1237                             singlefont->codepage),
1238                    g_print ("... Unicode subranges:"),
1239                    print_unicode_subranges (&singlefont->fs)));
1240   if (check_unicode_subranges (singlefont->charset, &singlefont->fs))
1241     GDK_NOTE (MISC, (g_print ("... Guesstimated Unicode subranges:"),
1242                      print_unicode_subranges (&singlefont->fs)));
1243
1244   return singlefont;
1245 }
1246
1247 static GdkWin32SingleFont *
1248 gdk_font_load_internal (const gchar *font_name)
1249 {
1250   LOGFONT logfont;
1251
1252   char *fn;
1253   int numfields, n1, n2;
1254   char foundry[32], family[100], weight[32], slant[32], set_width[32],
1255     spacing[32], registry[32], encoding[32];
1256   char pixel_size[10], point_size[10], res_x[10], res_y[10], avg_width[10];
1257   int c;
1258   char *p;
1259   int logpixelsy;
1260
1261   g_return_val_if_fail (font_name != NULL, NULL);
1262
1263   GDK_NOTE (MISC, g_print ("gdk_font_load_internal: %s\n", font_name));
1264
1265   numfields = sscanf (font_name,
1266                       "-%30[^-]-%100[^-]-%30[^-]-%30[^-]-%30[^-]-%n",
1267                       foundry,
1268                       family,
1269                       weight,
1270                       slant,
1271                       set_width,
1272                       &n1);
1273   if (numfields == 0)
1274     {
1275       /* Probably a plain Windows font name */
1276       logfont.lfHeight = 0;
1277       logfont.lfWidth = 0;
1278       logfont.lfEscapement = 0;
1279       logfont.lfOrientation = 0;
1280       logfont.lfWeight = FW_DONTCARE;
1281       logfont.lfItalic = FALSE;
1282       logfont.lfUnderline = FALSE;
1283       logfont.lfStrikeOut = FALSE;
1284       logfont.lfCharSet = ANSI_CHARSET;
1285       logfont.lfOutPrecision = OUT_TT_ONLY_PRECIS;
1286       logfont.lfClipPrecision = CLIP_DEFAULT_PRECIS;
1287       logfont.lfQuality = PROOF_QUALITY;
1288       logfont.lfPitchAndFamily = DEFAULT_PITCH;
1289       fn = g_filename_from_utf8 (font_name, -1, NULL, NULL, NULL);
1290       strcpy (logfont.lfFaceName, fn);
1291       g_free (fn);
1292     }
1293   else if (numfields != 5)
1294     {
1295       g_warning ("gdk_font_load: font name %s illegal", font_name);
1296       return NULL;
1297     }
1298   else
1299     {
1300       /* It must be a XLFD name */
1301
1302       /* Check for hex escapes in the font family,
1303        * put in there by logfont_to_xlfd. Convert them in-place.
1304        */
1305       p = family;
1306       while (*p)
1307         {
1308           if (*p == '%' && isxdigit (p[1]) && isxdigit (p[2]))
1309             {
1310               sscanf (p+1, "%2x", &c);
1311               *p = c;
1312               strcpy (p+1, p+3);
1313             }
1314           p++;
1315         }
1316
1317       /* Skip add_style which often is empty in the requested font name */
1318       while (font_name[n1] && font_name[n1] != '-')
1319         n1++;
1320       numfields++;
1321
1322       numfields += sscanf (font_name + n1,
1323                            "-%8[^-]-%8[^-]-%8[^-]-%8[^-]-%30[^-]-%8[^-]-%30[^-]-%30[^-]%n",
1324                            pixel_size,
1325                            point_size,
1326                            res_x,
1327                            res_y,
1328                            spacing,
1329                            avg_width,
1330                            registry,
1331                            encoding,
1332                            &n2);
1333
1334       if (numfields != 14 || font_name[n1 + n2] != '\0')
1335         {
1336           g_warning ("gdk_font_load: font name %s illegal", font_name);
1337           return NULL;
1338         }
1339
1340       logpixelsy = GetDeviceCaps (gdk_display_hdc, LOGPIXELSY);
1341
1342       if (strcmp (pixel_size, "*") == 0)
1343         if (strcmp (point_size, "*") == 0)
1344           logfont.lfHeight = 0;
1345         else
1346           logfont.lfHeight = (int) (((double) atoi (point_size))/720.*logpixelsy);
1347       else
1348         logfont.lfHeight = atoi (pixel_size);
1349
1350       logfont.lfWidth = 0;
1351       logfont.lfEscapement = 0;
1352       logfont.lfOrientation = 0;
1353
1354       if (g_strcasecmp (weight, "thin") == 0)
1355         logfont.lfWeight = FW_THIN;
1356       else if (g_strcasecmp (weight, "extralight") == 0)
1357         logfont.lfWeight = FW_EXTRALIGHT;
1358       else if (g_strcasecmp (weight, "ultralight") == 0)
1359 #ifdef FW_ULTRALIGHT
1360         logfont.lfWeight = FW_ULTRALIGHT;
1361 #else
1362         logfont.lfWeight = FW_EXTRALIGHT; /* In fact, FW_ULTRALIGHT really is 
1363                                            * defined as FW_EXTRALIGHT anyway.
1364                                            */
1365 #endif
1366       else if (g_strcasecmp (weight, "light") == 0)
1367         logfont.lfWeight = FW_LIGHT;
1368       else if (g_strcasecmp (weight, "normal") == 0)
1369         logfont.lfWeight = FW_NORMAL;
1370       else if (g_strcasecmp (weight, "regular") == 0)
1371         logfont.lfWeight = FW_REGULAR;
1372       else if (g_strcasecmp (weight, "medium") == 0)
1373         logfont.lfWeight = FW_MEDIUM;
1374       else if (g_strcasecmp (weight, "semibold") == 0)
1375         logfont.lfWeight = FW_SEMIBOLD;
1376       else if (g_strcasecmp (weight, "demibold") == 0)
1377 #ifdef FW_DEMIBOLD
1378         logfont.lfWeight = FW_DEMIBOLD;
1379 #else
1380         logfont.lfWeight = FW_SEMIBOLD; /* As above */
1381 #endif
1382       else if (g_strcasecmp (weight, "bold") == 0)
1383         logfont.lfWeight = FW_BOLD;
1384       else if (g_strcasecmp (weight, "extrabold") == 0)
1385         logfont.lfWeight = FW_EXTRABOLD;
1386       else if (g_strcasecmp (weight, "ultrabold") == 0)
1387 #ifdef FW_ULTRABOLD
1388         logfont.lfWeight = FW_ULTRABOLD;
1389 #else
1390         logfont.lfWeight = FW_EXTRABOLD; /* As above */
1391 #endif
1392       else if (g_strcasecmp (weight, "heavy") == 0)
1393         logfont.lfWeight = FW_HEAVY;
1394       else if (g_strcasecmp (weight, "black") == 0)
1395 #ifdef FW_BLACK
1396         logfont.lfWeight = FW_BLACK;
1397 #else
1398         logfont.lfWeight = FW_HEAVY;    /* As above */
1399 #endif
1400       else
1401         logfont.lfWeight = FW_DONTCARE;
1402
1403       if (g_strcasecmp (slant, "italic") == 0
1404           || g_strcasecmp (slant, "oblique") == 0
1405           || g_strcasecmp (slant, "i") == 0
1406           || g_strcasecmp (slant, "o") == 0)
1407         logfont.lfItalic = TRUE;
1408       else
1409         logfont.lfItalic = FALSE;
1410       logfont.lfUnderline = FALSE;
1411       logfont.lfStrikeOut = FALSE;
1412       if (g_strcasecmp (registry, "iso8859") == 0)
1413         if (strcmp (encoding, "1") == 0)
1414           logfont.lfCharSet = ANSI_CHARSET;
1415         else if (strcmp (encoding, "2") == 0)
1416           logfont.lfCharSet = EASTEUROPE_CHARSET;
1417         else if (strcmp (encoding, "7") == 0)
1418           logfont.lfCharSet = GREEK_CHARSET;
1419         else if (strcmp (encoding, "8") == 0)
1420           logfont.lfCharSet = HEBREW_CHARSET;
1421         else if (strcmp (encoding, "9") == 0)
1422           logfont.lfCharSet = TURKISH_CHARSET;
1423         else
1424           logfont.lfCharSet = ANSI_CHARSET; /* XXX ??? */
1425       else if (g_strcasecmp (registry, "jisx0208.1983") == 0)
1426         logfont.lfCharSet = SHIFTJIS_CHARSET;
1427       else if (g_strcasecmp (registry, "ksc5601.1987") == 0)
1428         logfont.lfCharSet = HANGEUL_CHARSET;
1429       else if (g_strcasecmp (registry, "gb2312.1980") == 0)
1430         logfont.lfCharSet = GB2312_CHARSET;
1431       else if (g_strcasecmp (registry, "big5") == 0)
1432         logfont.lfCharSet = CHINESEBIG5_CHARSET;
1433       else if (g_strcasecmp (registry, "windows") == 0
1434                || g_strcasecmp (registry, "microsoft") == 0)
1435         if (g_strcasecmp (encoding, "symbol") == 0)
1436           logfont.lfCharSet = SYMBOL_CHARSET;
1437         else if (g_strcasecmp (encoding, "shiftjis") == 0)
1438           logfont.lfCharSet = SHIFTJIS_CHARSET;
1439         else if (g_strcasecmp (encoding, "gb2312") == 0)
1440           logfont.lfCharSet = GB2312_CHARSET;
1441         else if (g_strcasecmp (encoding, "hangeul") == 0)
1442           logfont.lfCharSet = HANGEUL_CHARSET;
1443         else if (g_strcasecmp (encoding, "big5") == 0)
1444           logfont.lfCharSet = CHINESEBIG5_CHARSET;
1445         else if (g_strcasecmp (encoding, "johab") == 0)
1446           logfont.lfCharSet = JOHAB_CHARSET;
1447         else if (g_strcasecmp (encoding, "hebrew") == 0)
1448           logfont.lfCharSet = HEBREW_CHARSET;
1449         else if (g_strcasecmp (encoding, "arabic") == 0)
1450           logfont.lfCharSet = ARABIC_CHARSET;
1451         else if (g_strcasecmp (encoding, "greek") == 0)
1452           logfont.lfCharSet = GREEK_CHARSET;
1453         else if (g_strcasecmp (encoding, "turkish") == 0)
1454           logfont.lfCharSet = TURKISH_CHARSET;
1455         else if (g_strcasecmp (encoding, "easteurope") == 0)
1456           logfont.lfCharSet = EASTEUROPE_CHARSET;
1457         else if (g_strcasecmp (encoding, "russian") == 0)
1458           logfont.lfCharSet = RUSSIAN_CHARSET;
1459         else if (g_strcasecmp (encoding, "mac") == 0)
1460           logfont.lfCharSet = MAC_CHARSET;
1461         else if (g_strcasecmp (encoding, "baltic") == 0)
1462           logfont.lfCharSet = BALTIC_CHARSET;
1463         else if (g_strcasecmp (encoding, "cp1251") == 0)
1464           logfont.lfCharSet = RUSSIAN_CHARSET;
1465         else
1466           logfont.lfCharSet = ANSI_CHARSET; /* XXX ??? */
1467       else
1468         logfont.lfCharSet = ANSI_CHARSET; /* XXX ??? */
1469       logfont.lfOutPrecision = OUT_TT_PRECIS;
1470       logfont.lfClipPrecision = CLIP_DEFAULT_PRECIS;
1471       logfont.lfQuality = PROOF_QUALITY;
1472       if (g_strcasecmp (spacing, "m") == 0)
1473         logfont.lfPitchAndFamily = FIXED_PITCH;
1474       else if (g_strcasecmp (spacing, "p") == 0)
1475         logfont.lfPitchAndFamily = VARIABLE_PITCH;
1476       else 
1477         logfont.lfPitchAndFamily = DEFAULT_PITCH;
1478       fn = g_filename_from_utf8 (family, -1, NULL, NULL, NULL);
1479       strcpy (logfont.lfFaceName, fn);
1480       g_free (fn);
1481     }
1482
1483   return gdk_font_load_logfont (&logfont);
1484 }
1485
1486 static GdkFont *
1487 gdk_font_from_one_singlefont (GdkWin32SingleFont *singlefont)
1488 {
1489   GdkFont *font;
1490   GdkFontPrivateWin32 *private;
1491   HGDIOBJ oldfont;
1492   TEXTMETRIC textmetric;
1493
1494   private = g_new (GdkFontPrivateWin32, 1);
1495   font = (GdkFont*) private;
1496
1497   private->base.ref_count = 1;
1498   private->names = NULL;
1499   private->fonts = g_slist_append (NULL, singlefont);
1500
1501   /* Pretend all fonts are fontsets... Gtktext and gtkentry work better
1502    * that way, they use wide chars, which is necessary for non-ASCII
1503    * chars to work. (Yes, even Latin-1, as we use Unicode internally.)
1504    */
1505   font->type = GDK_FONT_FONTSET;
1506   oldfont = SelectObject (gdk_display_hdc, singlefont->hfont);
1507   GetTextMetrics (gdk_display_hdc, &textmetric);
1508   SelectObject (gdk_display_hdc, oldfont);
1509   font->ascent = textmetric.tmAscent;
1510   font->descent = textmetric.tmDescent;
1511
1512   GDK_NOTE (MISC, g_print ("... asc %d desc %d\n",
1513                            font->ascent, font->descent));
1514
1515   return font;
1516 }
1517
1518 GdkFont*
1519 gdk_font_load_for_display (GdkDisplay  *display,
1520                            const gchar *font_name)
1521 {
1522   GdkFont *font;
1523   GdkFontPrivateWin32 *private;
1524   GdkWin32SingleFont *singlefont;
1525   HGDIOBJ oldfont;
1526   TEXTMETRIC textmetric;
1527
1528   g_return_val_if_fail (font_name != NULL, NULL);
1529   g_return_val_if_fail (display == gdk_display_get_default (), NULL);
1530
1531   font = gdk_font_hash_lookup (GDK_FONT_FONTSET, font_name);
1532   if (font)
1533     return font;
1534
1535   private = g_new (GdkFontPrivateWin32, 1);
1536   font = (GdkFont*) private;
1537
1538   singlefont = gdk_font_load_internal (font_name);
1539
1540   private->base.ref_count = 1;
1541   private->names = NULL;
1542   private->fonts = g_slist_append (NULL, singlefont);
1543
1544   /* Pretend all fonts are fontsets... Gtktext and gtkentry work better
1545    * that way, they use wide chars, which is necessary for non-ASCII
1546    * chars to work. (Yes, even Latin-1, as we use Unicode internally.)
1547    */
1548   font->type = GDK_FONT_FONTSET;
1549   oldfont = SelectObject (gdk_display_hdc, singlefont->hfont);
1550   GetTextMetrics (gdk_display_hdc, &textmetric);
1551   SelectObject (gdk_display_hdc, oldfont);
1552   font->ascent = textmetric.tmAscent;
1553   font->descent = textmetric.tmDescent;
1554
1555   GDK_NOTE (MISC, g_print ("... asc %d desc %d\n",
1556                            font->ascent, font->descent));
1557
1558   gdk_font_hash_insert (GDK_FONT_FONTSET, font, font_name);
1559
1560   return gdk_font_from_one_singlefont (gdk_font_load_internal (font_name));
1561 }
1562
1563 /**
1564  * gdk_font_from_description:
1565  * @font_desc: a #PangoFontDescription.
1566  * 
1567  * Load a #GdkFont based on a Pango font description. This font will
1568  * only be an approximation of the Pango font, and
1569  * internationalization will not be handled correctly. This function
1570  * should only be used for legacy code that cannot be easily converted
1571  * to use Pango. Using Pango directly will produce better results.
1572  * 
1573  * Return value: the newly loaded font, or %NULL if the font
1574  * cannot be loaded.
1575  **/
1576 GdkFont*
1577 gdk_font_from_description_for_display (GdkDisplay           *display,
1578                                        PangoFontDescription *font_desc)
1579 {
1580   PangoFontMap *font_map;
1581   PangoFont *font;
1582   GdkFont *result = NULL;
1583
1584   g_return_val_if_fail (font_desc != NULL, NULL);
1585   g_return_val_if_fail (display == gdk_display_get_default (), NULL);
1586
1587   font_map = pango_win32_font_map_for_display ();
1588   font = pango_font_map_load_font (font_map, gdk_pango_context_get (), font_desc);
1589
1590   if (font)
1591     {
1592       LOGFONT *lfp =
1593         pango_win32_font_logfont (font);
1594       result = gdk_font_from_one_singlefont (gdk_font_load_logfont (lfp));
1595       g_free (lfp);
1596
1597       g_object_unref (G_OBJECT (font));
1598     }
1599
1600   return result;
1601 }
1602
1603 GdkFont*
1604 gdk_fontset_load (const gchar *fontset_name)
1605 {
1606   GdkFont *font;
1607   GdkFontPrivateWin32 *private;
1608   GdkWin32SingleFont *singlefont;
1609   HGDIOBJ oldfont;
1610   TEXTMETRIC textmetric;
1611   gchar *fs;
1612   gchar *b, *p, *s;
1613
1614   g_return_val_if_fail (fontset_name != NULL, NULL);
1615
1616   font = gdk_font_hash_lookup (GDK_FONT_FONTSET, fontset_name);
1617   if (font)
1618     return font;
1619
1620   s = fs = g_strdup (fontset_name);
1621   while (*s && isspace (*s))
1622     s++;
1623
1624   g_return_val_if_fail (*s, NULL);
1625
1626   private = g_new (GdkFontPrivateWin32, 1);
1627   font = (GdkFont*) private;
1628
1629   private->base.ref_count = 1;
1630   private->names = NULL;
1631   private->fonts = NULL;
1632
1633   font->type = GDK_FONT_FONTSET;
1634   font->ascent = 0;
1635   font->descent = 0;
1636
1637   while (TRUE)
1638     {
1639       if ((p = strchr (s, ',')) != NULL)
1640         b = p;
1641       else
1642         b = s + strlen (s);
1643
1644       while (isspace (b[-1]))
1645         b--;
1646       *b = '\0';
1647       singlefont = gdk_font_load_internal (s);
1648       if (singlefont)
1649         {
1650           private->fonts = g_slist_append (private->fonts, singlefont);
1651           oldfont = SelectObject (gdk_display_hdc, singlefont->hfont);
1652           GetTextMetrics (gdk_display_hdc, &textmetric);
1653           SelectObject (gdk_display_hdc, oldfont);
1654           font->ascent = MAX (font->ascent, textmetric.tmAscent);
1655           font->descent = MAX (font->descent, textmetric.tmDescent);
1656         }
1657       if (p)
1658         {
1659           s = p + 1;
1660           while (*s && isspace (*s))
1661             s++;
1662         }
1663       else
1664         break;
1665       if (!*s)
1666         break;
1667     }
1668   
1669   g_free (fs);
1670
1671   gdk_font_hash_insert (GDK_FONT_FONTSET, font, fontset_name);
1672
1673   return font;
1674 }
1675
1676 void
1677 _gdk_font_destroy (GdkFont *font)
1678 {
1679   GdkFontPrivateWin32 *private = (GdkFontPrivateWin32 *) font;
1680   GdkWin32SingleFont *singlefont;
1681   GSList *list;
1682
1683   singlefont = (GdkWin32SingleFont *) private->fonts->data;
1684   GDK_NOTE (MISC, g_print ("_gdk_font_destroy %#x\n",
1685                            (guint)singlefont->hfont));
1686
1687   gdk_font_hash_remove (font->type, font);
1688   
1689   switch (font->type)
1690     {
1691     case GDK_FONT_FONT:
1692       DeleteObject (singlefont->hfont);
1693       break;
1694       
1695     case GDK_FONT_FONTSET:
1696       list = private->fonts;
1697       while (list)
1698         {
1699           singlefont = (GdkWin32SingleFont *) list->data;
1700           DeleteObject (singlefont->hfont);
1701           
1702           list = list->next;
1703         }
1704       g_slist_free (private->fonts);
1705       break;
1706     }
1707   g_free (font);
1708 }
1709
1710 gint
1711 _gdk_font_strlen (GdkFont     *font,
1712                   const gchar *str)
1713 {
1714   g_return_val_if_fail (font != NULL, -1);
1715   g_return_val_if_fail (str != NULL, -1);
1716
1717   return strlen (str);
1718 }
1719
1720 gint
1721 gdk_font_id (const GdkFont *font)
1722 {
1723   const GdkFontPrivateWin32 *private;
1724
1725   g_return_val_if_fail (font != NULL, 0);
1726
1727   private = (const GdkFontPrivateWin32 *) font;
1728
1729   if (font->type == GDK_FONT_FONT)
1730     return (gint) ((GdkWin32SingleFont *) private->fonts->data)->hfont;
1731   else
1732     return 0;
1733 }
1734
1735 gboolean
1736 gdk_font_equal (const GdkFont *fonta,
1737                 const GdkFont *fontb)
1738 {
1739   const GdkFontPrivateWin32 *privatea;
1740   const GdkFontPrivateWin32 *privateb;
1741
1742   g_return_val_if_fail (fonta != NULL, FALSE);
1743   g_return_val_if_fail (fontb != NULL, FALSE);
1744
1745   privatea = (const GdkFontPrivateWin32 *) fonta;
1746   privateb = (const GdkFontPrivateWin32 *) fontb;
1747
1748   if (fonta->type == GDK_FONT_FONT && fontb->type == GDK_FONT_FONT)
1749     return (((GdkWin32SingleFont *) privatea->fonts->data)->hfont
1750             == ((GdkWin32SingleFont *) privateb->fonts->data)->hfont);
1751   else if (fonta->type == GDK_FONT_FONTSET && fontb->type == GDK_FONT_FONTSET)
1752     {
1753       GSList *lista = privatea->fonts;
1754       GSList *listb = privateb->fonts;
1755
1756       while (lista && listb)
1757         {
1758           if (((GdkWin32SingleFont *) lista->data)->hfont
1759               != ((GdkWin32SingleFont *) listb->data)->hfont)
1760             return 0;
1761           lista = lista->next;
1762           listb = listb->next;
1763         }
1764       if (lista || listb)
1765         return 0;
1766       else
1767         return 1;
1768     }
1769   else
1770     return 0;
1771 }
1772
1773 /* Return the Unicode Subset bitfield number for a Unicode character */
1774
1775 static int
1776 unicode_classify (wchar_t wc)
1777 {
1778   int min = 0;
1779   int max = G_N_ELEMENTS (utab) - 1;
1780   int mid;
1781
1782   while (max >= min)
1783     {
1784       mid = (min + max) / 2;
1785       if (utab[mid].high < wc)
1786         min = mid + 1;
1787       else if (wc < utab[mid].low)
1788         max = mid - 1;
1789       else if (utab[mid].low <= wc && wc <= utab[mid].high)
1790         return utab[mid].bit;
1791       else
1792         break;
1793     }
1794   /* Fallback... returning -1 might cause problems. Returning
1795    * U_BASIC_LATIN won't help handling strange characters, but won't
1796    * do harm either.
1797    */
1798   return U_BASIC_LATIN;
1799 }
1800
1801 void
1802 _gdk_wchar_text_handle (GdkFont       *font,
1803                        const wchar_t *wcstr,
1804                        int            wclen,
1805                        void         (*handler)(GdkWin32SingleFont *,
1806                                                const wchar_t *,
1807                                                int,
1808                                                void *),
1809                        void          *arg)
1810 {
1811   GdkFontPrivateWin32 *private;
1812   GdkWin32SingleFont *singlefont;
1813   GSList *list;
1814   int  block;
1815   const wchar_t *start, *end, *wcp;
1816
1817   wcp = wcstr;
1818   end = wcp + wclen;
1819   private = (GdkFontPrivateWin32 *) font;
1820
1821   g_assert (private->base.ref_count > 0);
1822
1823   GDK_NOTE (MISC, g_print ("_gdk_wchar_text_handle: "));
1824
1825   while (wcp < end)
1826     {
1827       /* Split Unicode string into pieces of the same class */
1828       start = wcp;
1829       block = unicode_classify (*wcp);
1830       while (wcp + 1 < end && unicode_classify (wcp[1]) == block)
1831         wcp++;
1832
1833       /* Find a font in the fontset that can handle this class */
1834       list = private->fonts;
1835       while (list)
1836         {
1837           singlefont = (GdkWin32SingleFont *) list->data;
1838           
1839           if (singlefont->fs.fsUsb[block/32] & (1 << (block % 32)))
1840             break;
1841
1842           list = list->next;
1843         }
1844
1845       if (!list)
1846         singlefont = NULL;
1847
1848       GDK_NOTE (MISC, g_print ("%d:%d:%d:%#x ",
1849                                start-wcstr, wcp-wcstr, block,
1850                                (singlefont ? (guint) singlefont->hfont : 0)));
1851
1852       /* Call the callback function */
1853       (*handler) (singlefont, start, wcp+1 - start, arg);
1854       wcp++;
1855     }
1856   GDK_NOTE (MISC, g_print ("\n"));
1857 }
1858
1859 typedef struct
1860 {
1861   SIZE total;
1862 } gdk_text_size_arg;
1863
1864 static void
1865 gdk_text_size_handler (GdkWin32SingleFont *singlefont,
1866                        const wchar_t      *wcstr,
1867                        int                 wclen,
1868                        void               *argp)
1869 {
1870   SIZE this_size;
1871   HGDIOBJ oldfont;
1872   gdk_text_size_arg *arg = (gdk_text_size_arg *) argp;
1873
1874   if (!singlefont)
1875     return;
1876
1877   if ((oldfont = SelectObject (gdk_display_hdc, singlefont->hfont)) == NULL)
1878     {
1879       WIN32_GDI_FAILED ("SelectObject");
1880       return;
1881     }
1882   GetTextExtentPoint32W (gdk_display_hdc, wcstr, wclen, &this_size);
1883   SelectObject (gdk_display_hdc, oldfont);
1884
1885   arg->total.cx += this_size.cx;
1886   arg->total.cy = MAX (arg->total.cy, this_size.cy);
1887 }
1888
1889 static gboolean
1890 gdk_text_size (GdkFont           *font,
1891                const gchar       *text,
1892                gint               text_length,
1893                gdk_text_size_arg *arg)
1894 {
1895   gint wlen;
1896   wchar_t *wcstr;
1897
1898   g_return_val_if_fail (font != NULL, FALSE);
1899   g_return_val_if_fail (text != NULL, FALSE);
1900
1901   if (text_length == 0)
1902     return 0;
1903
1904   g_assert (font->type == GDK_FONT_FONT || font->type == GDK_FONT_FONTSET);
1905
1906   wcstr = g_new (wchar_t, text_length);
1907   if (text_length == 1)
1908     {
1909       /* For single characters, don't try to interpret as UTF-8.
1910        */
1911       wcstr[0] = (guchar) text[0];
1912       _gdk_wchar_text_handle (font, wcstr, 1, gdk_text_size_handler, arg);
1913     }
1914   else
1915     {
1916       if ((wlen = _gdk_utf8_to_ucs2 (wcstr, text, text_length, text_length)) == -1)
1917         g_warning ("gdk_text_size: _gdk_utf8_to_ucs2 failed");
1918       else
1919         _gdk_wchar_text_handle (font, wcstr, wlen, gdk_text_size_handler, arg);
1920     }
1921
1922   g_free (wcstr);
1923
1924   return TRUE;
1925 }
1926
1927 gint
1928 gdk_text_width (GdkFont      *font,
1929                 const gchar  *text,
1930                 gint          text_length)
1931 {
1932   gdk_text_size_arg arg;
1933
1934   arg.total.cx = arg.total.cy = 0;
1935
1936   if (!gdk_text_size (font, text, text_length, &arg))
1937     return -1;
1938
1939   return arg.total.cx;
1940 }
1941
1942 gint
1943 gdk_text_width_wc (GdkFont        *font,
1944                    const GdkWChar *text,
1945                    gint            text_length)
1946 {
1947   gdk_text_size_arg arg;
1948   wchar_t *wcstr;
1949   gint i;
1950
1951   g_return_val_if_fail (font != NULL, -1);
1952   g_return_val_if_fail (text != NULL, -1);
1953
1954   if (text_length == 0)
1955     return 0;
1956
1957   g_assert (font->type == GDK_FONT_FONT || font->type == GDK_FONT_FONTSET);
1958
1959   if (sizeof (wchar_t) != sizeof (GdkWChar))
1960     {
1961       wcstr = g_new (wchar_t, text_length);
1962       for (i = 0; i < text_length; i++)
1963         wcstr[i] = text[i];
1964     }
1965   else
1966     wcstr = (wchar_t *) text;
1967
1968   arg.total.cx = arg.total.cy = 0;
1969
1970   _gdk_wchar_text_handle (font, wcstr, text_length,
1971                          gdk_text_size_handler, &arg);
1972
1973   if (sizeof (wchar_t) != sizeof (GdkWChar))
1974     g_free (wcstr);
1975
1976   return arg.total.cx;
1977 }
1978
1979 void
1980 gdk_text_extents (GdkFont     *font,
1981                   const gchar *text,
1982                   gint         text_length,
1983                   gint        *lbearing,
1984                   gint        *rbearing,
1985                   gint        *width,
1986                   gint        *ascent,
1987                   gint        *descent)
1988 {
1989   gdk_text_size_arg arg;
1990   gint wlen;
1991   wchar_t *wcstr;
1992
1993   g_return_if_fail (font != NULL);
1994   g_return_if_fail (text != NULL);
1995
1996   if (text_length == 0)
1997     {
1998       if (lbearing)
1999         *lbearing = 0;
2000       if (rbearing)
2001         *rbearing = 0;
2002       if (width)
2003         *width = 0;
2004       if (ascent)
2005         *ascent = 0;
2006       if (descent)
2007         *descent = 0;
2008       return;
2009     }
2010
2011   g_assert (font->type == GDK_FONT_FONT || font->type == GDK_FONT_FONTSET);
2012
2013   arg.total.cx = arg.total.cy = 0;
2014
2015   wcstr = g_new (wchar_t, text_length);
2016   if (text_length == 1)
2017     {
2018       wcstr[0] = (guchar) text[0];
2019       _gdk_wchar_text_handle (font, wcstr, 1, gdk_text_size_handler, &arg);
2020     }
2021   else
2022     {
2023       if ((wlen = _gdk_utf8_to_ucs2 (wcstr, text, text_length, text_length)) == -1)
2024         g_warning ("gdk_text_extents: _gdk_utf8_to_ucs2 failed");
2025       else
2026         _gdk_wchar_text_handle (font, wcstr, wlen, gdk_text_size_handler, &arg);
2027     }
2028
2029   g_free (wcstr);
2030
2031   /* XXX This is quite bogus */
2032   if (lbearing)
2033     *lbearing = 0;
2034   if (rbearing)
2035     *rbearing = arg.total.cx;
2036   /* What should be the difference between width and rbearing? */
2037   if (width)
2038     *width = arg.total.cx;
2039   if (ascent)
2040     *ascent = arg.total.cy + 1;
2041   if (descent)
2042     *descent = font->descent + 1;
2043 }
2044
2045 void
2046 gdk_text_extents_wc (GdkFont        *font,
2047                      const GdkWChar *text,
2048                      gint            text_length,
2049                      gint           *lbearing,
2050                      gint           *rbearing,
2051                      gint           *width,
2052                      gint           *ascent,
2053                      gint           *descent)
2054 {
2055   gdk_text_size_arg arg;
2056   wchar_t *wcstr;
2057   gint i;
2058
2059   g_return_if_fail (font != NULL);
2060   g_return_if_fail (text != NULL);
2061
2062   if (text_length == 0)
2063     {
2064       if (lbearing)
2065         *lbearing = 0;
2066       if (rbearing)
2067         *rbearing = 0;
2068       if (width)
2069         *width = 0;
2070       if (ascent)
2071         *ascent = 0;
2072       if (descent)
2073         *descent = 0;
2074       return;
2075     }
2076
2077   g_assert (font->type == GDK_FONT_FONT || font->type == GDK_FONT_FONTSET);
2078
2079   if (sizeof (wchar_t) != sizeof (GdkWChar))
2080     {
2081       wcstr = g_new (wchar_t, text_length);
2082       for (i = 0; i < text_length; i++)
2083         wcstr[i] = text[i];
2084     }
2085   else
2086     wcstr = (wchar_t *) text;
2087
2088   arg.total.cx = arg.total.cy = 0;
2089
2090   _gdk_wchar_text_handle (font, wcstr, text_length,
2091                          gdk_text_size_handler, &arg);
2092
2093   if (sizeof (wchar_t) != sizeof (GdkWChar))
2094     g_free (wcstr);
2095
2096   /* XXX This is quite bogus */
2097   if (lbearing)
2098     *lbearing = 0;
2099   if (rbearing)
2100     *rbearing = arg.total.cx;
2101   if (width)
2102     *width = arg.total.cx;
2103   if (ascent)
2104     *ascent = arg.total.cy + 1;
2105   if (descent)
2106     *descent = font->descent + 1;
2107 }