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