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