]> Pileus Git - ~andy/gtk/blob - gdk/win32/gdkfont-win32.c
New font private structures, related to fontsets.
[~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 "gdkx.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   GdkFontPrivate *private = (GdkFontPrivate *) 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   GdkFontPrivate *private = (GdkFontPrivate *) 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_xlfd_create (GdkFont *font)
256 {
257   GdkFontPrivate *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 = (GdkFontPrivate *) 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_win32_font_xlfd: 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_xlfd_free (gchar *xlfd)
295 {
296   g_free (xlfd);
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 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 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 GdkWin32SingleFont*
442 gdk_font_load_internal (const gchar *font_name)
443 {
444   GdkWin32SingleFont *singlefont;
445   HFONT hfont;
446   LOGFONT logfont;
447   CHARSETINFO csi;
448   DWORD fdwItalic, fdwUnderline, fdwStrikeOut, fdwCharSet,
449     fdwOutputPrecision, fdwClipPrecision, fdwQuality, fdwPitchAndFamily;
450   const char *lpszFace;
451
452   int numfields, n1, n2, tries;
453   char foundry[32], family[100], weight[32], slant[32], set_width[32],
454     spacing[32], registry[32], encoding[32];
455   char pixel_size[10], point_size[10], res_x[10], res_y[10], avg_width[10];
456   int c;
457   char *p;
458   int nHeight, nWidth, nEscapement, nOrientation, fnWeight;
459   int logpixelsy;
460
461   g_return_val_if_fail (font_name != NULL, NULL);
462
463   GDK_NOTE (MISC, g_print ("gdk_font_load_internal: %s\n", font_name));
464
465   numfields = sscanf (font_name,
466                       "-%30[^-]-%100[^-]-%30[^-]-%30[^-]-%30[^-]-%n",
467                       foundry,
468                       family,
469                       weight,
470                       slant,
471                       set_width,
472                       &n1);
473   if (numfields == 0)
474     {
475       /* Probably a plain Windows font name */
476       nHeight = 0;
477       nWidth = 0;
478       nEscapement = 0;
479       nOrientation = 0;
480       fnWeight = FW_DONTCARE;
481       fdwItalic = FALSE;
482       fdwUnderline = FALSE;
483       fdwStrikeOut = FALSE;
484       fdwCharSet = ANSI_CHARSET;
485       fdwOutputPrecision = OUT_TT_PRECIS;
486       fdwClipPrecision = CLIP_DEFAULT_PRECIS;
487       fdwQuality = PROOF_QUALITY;
488       fdwPitchAndFamily = DEFAULT_PITCH;
489       lpszFace = font_name;
490     }
491   else if (numfields != 5)
492     {
493       g_warning ("gdk_font_load: font name %s illegal", font_name);
494       return NULL;
495     }
496   else
497     {
498       /* It must be a XLFD name */
499
500       /* Check for hex escapes in the font family,
501        * put in there by gtkfontsel.
502        */
503       p = family;
504       while (*p)
505         {
506           if (*p == '%' && isxdigit (p[1]) && isxdigit (p[2]))
507             {
508               sscanf (p+1, "%2x", &c);
509               *p = c;
510               strcpy (p+1, p+3);
511             }
512           p++;
513         }
514
515       /* Skip add_style which often is empty in the requested font name */
516       while (font_name[n1] && font_name[n1] != '-')
517         n1++;
518       numfields++;
519
520       numfields += sscanf (font_name + n1,
521                            "-%8[^-]-%8[^-]-%8[^-]-%8[^-]-%30[^-]-%8[^-]-%30[^-]-%30[^-]%n",
522                            pixel_size,
523                            point_size,
524                            res_x,
525                            res_y,
526                            spacing,
527                            avg_width,
528                            registry,
529                            encoding,
530                            &n2);
531
532       if (numfields != 14 || font_name[n1 + n2] != '\0')
533         {
534           g_warning ("gdk_font_load: font name %s illegal", font_name);
535           return NULL;
536         }
537
538       logpixelsy = GetDeviceCaps (gdk_DC, LOGPIXELSY);
539
540       if (strcmp (pixel_size, "*") == 0)
541         if (strcmp (point_size, "*") == 0)
542           nHeight = 0;
543         else
544           nHeight = (int) (((double) atoi (point_size))/720.*logpixelsy);
545       else
546         nHeight = atoi (pixel_size);
547
548       nWidth = 0;
549       nEscapement = 0;
550       nOrientation = 0;
551
552       if (g_strcasecmp (weight, "thin") == 0)
553         fnWeight = FW_THIN;
554       else if (g_strcasecmp (weight, "extralight") == 0)
555         fnWeight = FW_EXTRALIGHT;
556       else if (g_strcasecmp (weight, "ultralight") == 0)
557 #ifdef FW_ULTRALIGHT
558         fnWeight = FW_ULTRALIGHT;
559 #else
560         fnWeight = FW_EXTRALIGHT; /* In fact, FW_ULTRALIGHT really is 
561                                    * defined as FW_EXTRALIGHT anyway.
562                                    */
563 #endif
564       else if (g_strcasecmp (weight, "light") == 0)
565         fnWeight = FW_LIGHT;
566       else if (g_strcasecmp (weight, "normal") == 0)
567         fnWeight = FW_NORMAL;
568       else if (g_strcasecmp (weight, "regular") == 0)
569         fnWeight = FW_REGULAR;
570       else if (g_strcasecmp (weight, "medium") == 0)
571         fnWeight = FW_MEDIUM;
572       else if (g_strcasecmp (weight, "semibold") == 0)
573         fnWeight = FW_SEMIBOLD;
574       else if (g_strcasecmp (weight, "demibold") == 0)
575 #ifdef FW_DEMIBOLD
576         fnWeight = FW_DEMIBOLD;
577 #else
578         fnWeight = FW_SEMIBOLD; /* As above */
579 #endif
580       else if (g_strcasecmp (weight, "bold") == 0)
581         fnWeight = FW_BOLD;
582       else if (g_strcasecmp (weight, "extrabold") == 0)
583         fnWeight = FW_EXTRABOLD;
584       else if (g_strcasecmp (weight, "ultrabold") == 0)
585 #ifdef FW_ULTRABOLD
586         fnWeight = FW_ULTRABOLD;
587 #else
588         fnWeight = FW_EXTRABOLD; /* As above */
589 #endif
590       else if (g_strcasecmp (weight, "heavy") == 0)
591         fnWeight = FW_HEAVY;
592       else if (g_strcasecmp (weight, "black") == 0)
593 #ifdef FW_BLACK
594         fnWeight = FW_BLACK;
595 #else
596         fnWeight = FW_HEAVY;    /* As above */
597 #endif
598       else
599         fnWeight = FW_DONTCARE;
600
601       if (g_strcasecmp (slant, "italic") == 0
602           || g_strcasecmp (slant, "oblique") == 0
603           || g_strcasecmp (slant, "i") == 0
604           || g_strcasecmp (slant, "o") == 0)
605         fdwItalic = TRUE;
606       else
607         fdwItalic = FALSE;
608       fdwUnderline = FALSE;
609       fdwStrikeOut = FALSE;
610       if (g_strcasecmp (registry, "iso8859") == 0)
611         if (strcmp (encoding, "1") == 0)
612           fdwCharSet = ANSI_CHARSET;
613         else if (strcmp (encoding, "2") == 0)
614           fdwCharSet = EASTEUROPE_CHARSET;
615         else if (strcmp (encoding, "7") == 0)
616           fdwCharSet = GREEK_CHARSET;
617         else if (strcmp (encoding, "8") == 0)
618           fdwCharSet = HEBREW_CHARSET;
619         else if (strcmp (encoding, "9") == 0)
620           fdwCharSet = TURKISH_CHARSET;
621         else
622           fdwCharSet = ANSI_CHARSET; /* XXX ??? */
623       else if (g_strcasecmp (registry, "jisx0208.1983") == 0)
624         fdwCharSet = SHIFTJIS_CHARSET;
625       else if (g_strcasecmp (registry, "ksc5601.1987") == 0)
626         fdwCharSet = HANGEUL_CHARSET;
627       else if (g_strcasecmp (registry, "gb2312.1980") == 0)
628         fdwCharSet = GB2312_CHARSET;
629       else if (g_strcasecmp (registry, "big5") == 0)
630         fdwCharSet = CHINESEBIG5_CHARSET;
631       else if (g_strcasecmp (registry, "windows") == 0
632                || g_strcasecmp (registry, "microsoft") == 0)
633         if (g_strcasecmp (encoding, "symbol") == 0)
634           fdwCharSet = SYMBOL_CHARSET;
635         else if (g_strcasecmp (encoding, "shiftjis") == 0)
636           fdwCharSet = SHIFTJIS_CHARSET;
637         else if (g_strcasecmp (encoding, "gb2312") == 0)
638           fdwCharSet = GB2312_CHARSET;
639         else if (g_strcasecmp (encoding, "hangeul") == 0)
640           fdwCharSet = HANGEUL_CHARSET;
641         else if (g_strcasecmp (encoding, "big5") == 0)
642           fdwCharSet = CHINESEBIG5_CHARSET;
643         else if (g_strcasecmp (encoding, "johab") == 0)
644           fdwCharSet = JOHAB_CHARSET;
645         else if (g_strcasecmp (encoding, "hebrew") == 0)
646           fdwCharSet = HEBREW_CHARSET;
647         else if (g_strcasecmp (encoding, "arabic") == 0)
648           fdwCharSet = ARABIC_CHARSET;
649         else if (g_strcasecmp (encoding, "greek") == 0)
650           fdwCharSet = GREEK_CHARSET;
651         else if (g_strcasecmp (encoding, "turkish") == 0)
652           fdwCharSet = TURKISH_CHARSET;
653         else if (g_strcasecmp (encoding, "easteurope") == 0)
654           fdwCharSet = EASTEUROPE_CHARSET;
655         else if (g_strcasecmp (encoding, "russian") == 0)
656           fdwCharSet = RUSSIAN_CHARSET;
657         else if (g_strcasecmp (encoding, "mac") == 0)
658           fdwCharSet = MAC_CHARSET;
659         else if (g_strcasecmp (encoding, "baltic") == 0)
660           fdwCharSet = BALTIC_CHARSET;
661         else if (g_strcasecmp (encoding, "cp1251") == 0)
662           fdwCharSet = RUSSIAN_CHARSET;
663         else
664           fdwCharSet = ANSI_CHARSET; /* XXX ??? */
665       else
666         fdwCharSet = ANSI_CHARSET; /* XXX ??? */
667       fdwOutputPrecision = OUT_TT_PRECIS;
668       fdwClipPrecision = CLIP_DEFAULT_PRECIS;
669       fdwQuality = PROOF_QUALITY;
670       if (g_strcasecmp (spacing, "m") == 0)
671         fdwPitchAndFamily = FIXED_PITCH;
672       else if (g_strcasecmp (spacing, "p") == 0)
673         fdwPitchAndFamily = VARIABLE_PITCH;
674       else 
675         fdwPitchAndFamily = DEFAULT_PITCH;
676       lpszFace = family;
677     }
678
679   for (tries = 0; ; tries++)
680     {
681       GDK_NOTE (MISC, g_print ("...trying CreateFont(%d,%d,%d,%d,"
682                                "%d,%d,%d,%d,"
683                                "%d,%d,%d,"
684                                "%d,%#.02x,\"%s\")\n",
685                                nHeight, nWidth, nEscapement, nOrientation,
686                                fnWeight, fdwItalic, fdwUnderline, fdwStrikeOut,
687                                fdwCharSet, fdwOutputPrecision, fdwClipPrecision,
688                                fdwQuality, fdwPitchAndFamily, lpszFace));
689       if ((hfont =
690            CreateFont (nHeight, nWidth, nEscapement, nOrientation,
691                        fnWeight, fdwItalic, fdwUnderline, fdwStrikeOut,
692                        fdwCharSet, fdwOutputPrecision, fdwClipPrecision,
693                        fdwQuality, fdwPitchAndFamily, lpszFace)) != NULL)
694         break;
695
696       /* If we fail, try some similar fonts often found on Windows. */
697
698       if (tries == 0)
699         {
700           if (g_strcasecmp (family, "helvetica") == 0)
701             lpszFace = "arial";
702           else if (g_strcasecmp (family, "new century schoolbook") == 0)
703             lpszFace = "century schoolbook";
704           else if (g_strcasecmp (family, "courier") == 0)
705             lpszFace = "courier new";
706           else if (g_strcasecmp (family, "lucida") == 0)
707             lpszFace = "lucida sans unicode";
708           else if (g_strcasecmp (family, "lucidatypewriter") == 0)
709             lpszFace = "lucida console";
710           else if (g_strcasecmp (family, "times") == 0)
711             lpszFace = "times new roman";
712         }
713       else if (tries == 1)
714         {
715           if (g_strcasecmp (family, "courier") == 0)
716             {
717               lpszFace = "";
718               fdwPitchAndFamily |= FF_MODERN;
719             }
720           else if (g_strcasecmp (family, "times new roman") == 0)
721             {
722               lpszFace = "";
723               fdwPitchAndFamily |= FF_ROMAN;
724             }
725           else if (g_strcasecmp (family, "helvetica") == 0
726                    || g_strcasecmp (family, "lucida") == 0)
727             {
728               lpszFace = "";
729               fdwPitchAndFamily |= FF_SWISS;
730             }
731           else
732             {
733               lpszFace = "";
734               fdwPitchAndFamily = (fdwPitchAndFamily & 0x0F) | FF_DONTCARE;
735             }
736         }
737       else
738         break;
739       tries++;
740     }
741   
742   if (!hfont)
743     return NULL;
744       
745   singlefont = g_new (GdkWin32SingleFont, 1);
746   singlefont->xfont = hfont;
747   GetObject (singlefont->xfont, sizeof (logfont), &logfont);
748   TranslateCharsetInfo ((DWORD *) singlefont->charset, &csi, TCI_SRCCHARSET);
749   singlefont->codepage = csi.ciACP;
750   GetCPInfo (singlefont->codepage, &singlefont->cpinfo);
751
752   return singlefont;
753 }
754
755 GdkFont*
756 gdk_font_load (const gchar *font_name)
757 {
758   GdkFont *font;
759   GdkFontPrivate *private;
760   GdkWin32SingleFont *singlefont;
761   HGDIOBJ oldfont;
762   HANDLE *f;
763   TEXTMETRIC textmetric;
764
765   g_return_val_if_fail (font_name != NULL, NULL);
766
767   font = gdk_font_hash_lookup (GDK_FONT_FONTSET, font_name);
768   if (font)
769     return font;
770
771   singlefont = gdk_font_load_internal (font_name);
772
773   private = g_new (GdkFontPrivate, 1);
774   font = (GdkFont*) private;
775
776   private->ref_count = 1;
777   private->names = NULL;
778   private->fonts = g_slist_append (NULL, singlefont);
779
780   /* Pretend all fonts are fontsets... Gtktext and gtkentry work better
781    * that way, they use wide chars, which is necessary for non-ASCII
782    * chars to work. (Yes, even Latin-1, as we use Unicode internally.)
783    */
784   font->type = GDK_FONT_FONTSET;
785   oldfont = SelectObject (gdk_DC, singlefont->xfont);
786   GetTextMetrics (gdk_DC, &textmetric);
787   singlefont->charset = GetTextCharsetInfo (gdk_DC, &singlefont->fs, 0);
788   SelectObject (gdk_DC, oldfont);
789   font->ascent = textmetric.tmAscent;
790   font->descent = textmetric.tmDescent;
791
792   GDK_NOTE (MISC, g_print ("... = %#x charset %s codepage %d (max %d bytes) "
793                            "asc %d desc %d\n",
794                            singlefont->xfont,
795                            charset_name (singlefont->charset),
796                            singlefont->codepage,
797                            singlefont->cpinfo.MaxCharSize,
798                            font->ascent, font->descent));
799
800   gdk_font_hash_insert (GDK_FONT_FONTSET, font, font_name);
801
802   return font;
803 }
804
805 GdkFont*
806 gdk_fontset_load (gchar *fontset_name)
807 {
808   GdkFont *font;
809   GdkFontPrivate *private;
810   GdkWin32SingleFont *singlefont;
811   HGDIOBJ oldfont;
812   HANDLE *f;
813   TEXTMETRIC textmetric;
814   GSList *base_font_list = NULL;
815   gchar *fs;
816   gchar *b, *p, *s;
817
818   g_return_val_if_fail (fontset_name != NULL, NULL);
819
820   font = gdk_font_hash_lookup (GDK_FONT_FONTSET, fontset_name);
821   if (font)
822     return font;
823
824   s = fs = g_strdup (fontset_name);
825   while (*s && isspace (*s))
826     s++;
827
828   g_return_val_if_fail (*s, NULL);
829
830   private = g_new (GdkFontPrivate, 1);
831   font = (GdkFont*) private;
832
833   private->ref_count = 1;
834   private->names = NULL;
835   private->fonts = NULL;
836
837   font->type = GDK_FONT_FONTSET;
838   font->ascent = 0;
839   font->descent = 0;
840
841   while (TRUE)
842     {
843       if ((p = strchr (s, ',')) != NULL)
844         b = p;
845       else
846         b = s + strlen (s);
847
848       while (isspace (b[-1]))
849         b--;
850       *b = '\0';
851       singlefont = gdk_font_load_internal (s);
852       if (singlefont)
853         {
854           private->fonts = g_slist_append (private->fonts, singlefont);
855           oldfont = SelectObject (gdk_DC, singlefont->xfont);
856           GetTextMetrics (gdk_DC, &textmetric);
857           singlefont->charset = GetTextCharsetInfo (gdk_DC, &singlefont->fs, 0);
858           SelectObject (gdk_DC, oldfont);
859           font->ascent = MAX (font->ascent, textmetric.tmAscent);
860           font->descent = MAX (font->descent, textmetric.tmDescent);
861         }
862       if (p)
863         {
864           s = p + 1;
865           while (*s && isspace (*s))
866             s++;
867         }
868       else
869         break;
870       if (!*s)
871         break;
872     }
873   
874   g_free (fs);
875
876   gdk_font_hash_insert (GDK_FONT_FONTSET, font, fontset_name);
877
878   return font;
879 }
880
881 GdkFont*
882 gdk_font_ref (GdkFont *font)
883 {
884   GdkFontPrivate *private;
885
886   g_return_val_if_fail (font != NULL, NULL);
887
888   private = (GdkFontPrivate*) font;
889   private->ref_count += 1;
890
891   GDK_NOTE (MISC,
892             g_print ("gdk_font_ref %#x %d\n",
893                      ((GdkWin32SingleFont *) private->fonts->data)->xfont,
894                      private->ref_count));
895   return font;
896 }
897
898 void
899 gdk_font_unref (GdkFont *font)
900 {
901   GdkFontPrivate *private;
902   GdkWin32SingleFont *singlefont;
903   GSList *list;
904   private = (GdkFontPrivate*) font;
905
906   g_return_if_fail (font != NULL);
907   g_return_if_fail (private->ref_count > 0);
908
909   private->ref_count -= 1;
910
911   singlefont = (GdkWin32SingleFont *) private->fonts->data;
912   GDK_NOTE (MISC, g_print ("gdk_font_unref %#x %d%s\n",
913                            singlefont->xfont, private->ref_count,
914                            (private->ref_count == 0 ? " freeing" : "")));
915
916   if (private->ref_count == 0)
917     {
918       gdk_font_hash_remove (font->type, font);
919       
920       switch (font->type)
921         {
922         case GDK_FONT_FONT:
923           DeleteObject (singlefont->xfont);
924           break;
925
926         case GDK_FONT_FONTSET:
927           list = private->fonts;
928           while (list)
929             {
930               singlefont = (GdkWin32SingleFont *) list->data;
931               DeleteObject (singlefont->xfont);
932
933               list = list->next;
934             }
935           break;
936
937         default:
938           g_assert_not_reached ();
939         }
940       g_free (font);
941     }
942 }
943
944 gint
945 gdk_font_id (const GdkFont *font)
946 {
947   const GdkFontPrivate *font_private;
948
949   g_return_val_if_fail (font != NULL, 0);
950
951   font_private = (const GdkFontPrivate*) font;
952
953   if (font->type == GDK_FONT_FONT)
954     return (gint) ((GdkWin32SingleFont *) font_private->fonts->data)->xfont;
955   else
956     return 0;
957 }
958
959 gint
960 gdk_font_equal (const GdkFont *fonta,
961                 const GdkFont *fontb)
962 {
963   const GdkFontPrivate *privatea;
964   const GdkFontPrivate *privateb;
965
966   g_return_val_if_fail (fonta != NULL, FALSE);
967   g_return_val_if_fail (fontb != NULL, FALSE);
968
969   privatea = (const GdkFontPrivate*) fonta;
970   privateb = (const GdkFontPrivate*) fontb;
971
972   if (fonta->type == GDK_FONT_FONT && fontb->type == GDK_FONT_FONT)
973     return (((GdkWin32SingleFont *) privatea->fonts->data)->xfont
974             == ((GdkWin32SingleFont *) privateb->fonts->data)->xfont);
975   else if (fonta->type == GDK_FONT_FONTSET && fontb->type == GDK_FONT_FONTSET)
976     {
977       GSList *lista = privatea->fonts;
978       GSList *listb = privateb->fonts;
979
980       while (lista && listb)
981         {
982           if (((GdkWin32SingleFont *) lista->data)->xfont
983               != ((GdkWin32SingleFont *) listb->data)->xfont)
984             return 0;
985           lista = lista->next;
986           listb = listb->next;
987         }
988       if (lista || listb)
989         return 0;
990       else
991         return 1;
992     }
993   else
994     return 0;
995 }
996
997 gint
998 gdk_string_width (GdkFont     *font,
999                   const gchar *string)
1000 {
1001   return gdk_text_width (font, string, strlen (string));
1002 }
1003
1004 /* This table classifies Unicode characters according to the Microsoft
1005  * Unicode subset numbering. This is from the table in "Developing
1006  * International Software for Windows 95 and Windows NT". This is almost,
1007  * but not quite, the same as the official Unicode block table in
1008  * Blocks.txt from ftp.unicode.org. The bit number field is the bitfield
1009  * number as in the FONTSIGNATURE struct's fsUsb field.
1010  */
1011 static struct {
1012   wchar_t low, high;
1013   guint bit; 
1014   gchar *name;
1015 } utab[] =
1016 {
1017   { 0x0000, 0x007E, 0, "Basic Latin" },
1018   { 0x00A0, 0x00FF, 1, "Latin-1 Supplement" },
1019   { 0x0100, 0x017F, 2, "Latin Extended-A" },
1020   { 0x0180, 0x024F, 3, "Latin Extended-B" },
1021   { 0x0250, 0x02AF, 4, "IPA Extensions" },
1022   { 0x02B0, 0x02FF, 5, "Spacing Modifier Letters" },
1023   { 0x0300, 0x036F, 6, "Combining Diacritical Marks" },
1024   { 0x0370, 0x03CF, 7, "Basic Greek" },
1025   { 0x03D0, 0x03FF, 8, "Greek Symbols and Coptic" },
1026   { 0x0400, 0x04FF, 9, "Cyrillic" },
1027   { 0x0530, 0x058F, 10, "Armenian" },
1028   { 0x0590, 0x05CF, 12, "Hebrew Extended" },
1029   { 0x05D0, 0x05FF, 11, "Basic Hebrew" },
1030   { 0x0600, 0x0652, 13, "Basic Arabic" },
1031   { 0x0653, 0x06FF, 14, "Arabic Extended" },
1032   { 0x0900, 0x097F, 15, "Devanagari" },
1033   { 0x0980, 0x09FF, 16, "Bengali" },
1034   { 0x0A00, 0x0A7F, 17, "Gurmukhi" },
1035   { 0x0A80, 0x0AFF, 18, "Gujarati" },
1036   { 0x0B00, 0x0B7F, 19, "Oriya" },
1037   { 0x0B80, 0x0BFF, 20, "Tamil" },
1038   { 0x0C00, 0x0C7F, 21, "Telugu" },
1039   { 0x0C80, 0x0CFF, 22, "Kannada" },
1040   { 0x0D00, 0x0D7F, 23, "Malayalam" },
1041   { 0x0E00, 0x0E7F, 24, "Thai" },
1042   { 0x0E80, 0x0EFF, 25, "Lao" },
1043   { 0x10A0, 0x10CF, 27, "Georgian Extended" },
1044   { 0x10D0, 0x10FF, 26, "Basic Georgian" },
1045   { 0x1100, 0x11FF, 28, "Hangul Jamo" },
1046   { 0x1E00, 0x1EFF, 29, "Latin Extended Additional" },
1047   { 0x1F00, 0x1FFF, 30, "Greek Extended" },
1048   { 0x2000, 0x206F, 31, "General Punctuation" },
1049   { 0x2070, 0x209F, 32, "Superscripts and Subscripts" },
1050   { 0x20A0, 0x20CF, 33, "Currency Symbols" },
1051   { 0x20D0, 0x20FF, 34, "Combining Diacritical Marks for Symbols" },
1052   { 0x2100, 0x214F, 35, "Letterlike Symbols" },
1053   { 0x2150, 0x218F, 36, "Number Forms" },
1054   { 0x2190, 0x21FF, 37, "Arrows" },
1055   { 0x2200, 0x22FF, 38, "Mathematical Operators" },
1056   { 0x2300, 0x23FF, 39, "Miscellaneous Technical" },
1057   { 0x2400, 0x243F, 40, "Control Pictures" },
1058   { 0x2440, 0x245F, 41, "Optical Character Recognition" },
1059   { 0x2460, 0x24FF, 42, "Enclosed Alphanumerics" },
1060   { 0x2500, 0x257F, 43, "Box Drawing" },
1061   { 0x2580, 0x259F, 44, "Block Elements" },
1062   { 0x25A0, 0x25FF, 45, "Geometric Shapes" },
1063   { 0x2600, 0x26FF, 46, "Miscellaneous Symbols" },
1064   { 0x2700, 0x27BF, 47, "Dingbats" },
1065   { 0x3000, 0x303F, 48, "CJK Symbols and Punctuation" },
1066   { 0x3040, 0x309F, 49, "Hiragana" },
1067   { 0x30A0, 0x30FF, 50, "Katakana" },
1068   { 0x3100, 0x312F, 51, "Bopomofo" },
1069   { 0x3130, 0x318F, 52, "Hangul Compatibility Jamo" },
1070   { 0x3190, 0x319F, 53, "CJK Miscellaneous" },
1071   { 0x3200, 0x32FF, 54, "Enclosed CJK" },
1072   { 0x3300, 0x33FF, 55, "CJK Compatibility" },
1073   { 0x3400, 0x3D2D, 56, "Hangul" },
1074   { 0x3D2E, 0x44B7, 57, "Hangul Supplementary-A" },
1075   { 0x44B8, 0x4DFF, 58, "Hangul Supplementary-B" },
1076   { 0x4E00, 0x9FFF, 59, "CJK Unified Ideographs" },
1077   { 0xE000, 0xF8FF, 60, "Private Use Area" },
1078   { 0xF900, 0xFAFF, 61, "CJK Compatibility Ideographs" },
1079   { 0xFB00, 0xFB4F, 62, "Alphabetic Presentation Forms" },
1080   { 0xFB50, 0xFDFF, 63, "Arabic Presentation Forms-A" },
1081   { 0xFE20, 0xFE2F, 64, "Combining Half Marks" },
1082   { 0xFE30, 0xFE4F, 65, "CJK Compatibility Forms" },
1083   { 0xFE50, 0xFE6F, 66, "Small Form Variants" },
1084   { 0xFE70, 0xFEFE, 67, "Arabic Presentation Forms-B" },
1085   { 0xFEFF, 0xFEFF, 69, "Specials" },
1086   { 0xFF00, 0xFFEF, 68, "Halfwidth and Fullwidth Forms" },
1087   { 0xFFF0, 0xFFFD, 69, "Specials" }
1088 };
1089
1090 /* Return the Unicode Subset bitfield number for a Unicode character */
1091
1092 static int
1093 unicode_classify (wchar_t wc)
1094 {
1095   int min = 0;
1096   int max = sizeof (utab) / sizeof (utab[0]) - 1;
1097   int mid;
1098
1099   while (max >= min)
1100     {
1101       mid = (min + max) / 2;
1102       if (utab[mid].high < wc)
1103         min = mid + 1;
1104       else if (wc < utab[mid].low)
1105         max = mid - 1;
1106       else if (utab[mid].low <= wc && wc <= utab[mid].high)
1107         return utab[mid].bit;
1108       else
1109         return -1;
1110     }
1111 }
1112
1113 void
1114 gdk_wchar_text_handle (GdkFont       *font,
1115                        const wchar_t *wcstr,
1116                        int            wclen,
1117                        void         (*handler)(GdkWin32SingleFont *,
1118                                                const wchar_t *,
1119                                                int,
1120                                                void *),
1121                        void          *arg)
1122 {
1123   GdkFontPrivate *private;
1124   GdkWin32SingleFont *singlefont;
1125   GSList *list;
1126   int i, block;
1127   const wchar_t *start, *end, *wcp;
1128
1129   wcp = wcstr;
1130   end = wcp + wclen;
1131   private = (GdkFontPrivate *) font;
1132
1133   while (wcp < end)
1134     {
1135       /* Split Unicode string into pieces of the same class */
1136       start = wcp;
1137       block = unicode_classify (*wcp);
1138       while (wcp + 1 < end && unicode_classify (wcp[1]) == block)
1139         wcp++;
1140
1141       /* Find a font in the fontset that can handle this class */
1142       list = private->fonts;
1143       while (list)
1144         {
1145           singlefont = (GdkWin32SingleFont *) list->data;
1146           
1147           if (singlefont->fs.fsUsb[block/32] & (1 << (block % 32)))
1148             break;
1149
1150           list = list->next;
1151         }
1152
1153       if (!list)
1154         singlefont = NULL;
1155
1156       /* Call the callback function */
1157       (*handler) (singlefont, start, wcp+1 - start, arg);
1158       wcp++;
1159     }
1160 }
1161
1162 typedef struct
1163 {
1164   SIZE total;
1165   SIZE max;
1166 } gdk_text_size_arg;
1167
1168 static void
1169 gdk_text_size_handler (GdkWin32SingleFont *singlefont,
1170                        const wchar_t      *wcstr,
1171                        int                 wclen,
1172                        void               *argp)
1173 {
1174   SIZE this_size;
1175   HGDIOBJ oldfont;
1176   gdk_text_size_arg *arg = (gdk_text_size_arg *) argp;
1177
1178   if ((oldfont = SelectObject (gdk_DC, singlefont->xfont)) == NULL)
1179     {
1180       g_warning ("gdk_text_size_handler: SelectObject failed");
1181       return;
1182     }
1183   GetTextExtentPoint32W (gdk_DC, wcstr, wclen, &this_size);
1184   SelectObject (gdk_DC, oldfont);
1185
1186   arg->total.cx += this_size.cx;
1187   arg->total.cy += this_size.cy;
1188   arg->max.cx = MAX (this_size.cx, arg->max.cx);
1189   arg->max.cy = MAX (this_size.cy, arg->max.cy);
1190 }
1191
1192 static gboolean
1193 gdk_text_size (GdkFont           *font,
1194                const gchar       *text,
1195                gint               text_length,
1196                gdk_text_size_arg *arg)
1197 {
1198   gint wlen;
1199   wchar_t *wcstr;
1200
1201   g_return_val_if_fail (font != NULL, FALSE);
1202   g_return_val_if_fail (text != NULL, FALSE);
1203
1204   if (text_length == 0)
1205     return 0;
1206
1207   g_assert (font->type == GDK_FONT_FONT || font->type == GDK_FONT_FONTSET);
1208
1209   wcstr = g_new (wchar_t, text_length);
1210   if ((wlen = gdk_nmbstowchar_ts (wcstr, text, text_length, text_length)) == -1)
1211     {
1212       g_warning ("gdk_text_size: gdk_nmbstowchar_ts failed");
1213       return FALSE;
1214     }
1215
1216   gdk_wchar_text_handle (font, wcstr, wlen, gdk_text_size_handler, arg);
1217
1218   g_free (wcstr);
1219
1220   return TRUE;
1221 }
1222
1223 gint
1224 gdk_text_width (GdkFont      *font,
1225                 const gchar  *text,
1226                 gint          text_length)
1227 {
1228   gdk_text_size_arg arg;
1229
1230   arg.total.cx = arg.total.cy = 0;
1231   arg.max.cx = arg.max.cy = 0;
1232
1233   if (!gdk_text_size (font, text, text_length, &arg))
1234     return -1;
1235
1236   return arg.total.cx;
1237 }
1238
1239 gint
1240 gdk_text_width_wc (GdkFont        *font,
1241                    const GdkWChar *text,
1242                    gint            text_length)
1243 {
1244   gdk_text_size_arg arg;
1245   wchar_t *wcstr;
1246   gint i;
1247
1248   g_return_val_if_fail (font != NULL, -1);
1249   g_return_val_if_fail (text != NULL, -1);
1250
1251   if (text_length == 0)
1252     return 0;
1253
1254   g_assert (font->type == GDK_FONT_FONT || font->type == GDK_FONT_FONTSET);
1255
1256   if (sizeof (wchar_t) != sizeof (GdkWChar))
1257     {
1258       wcstr = g_new (wchar_t, text_length);
1259       for (i = 0; i < text_length; i++)
1260         wcstr[i] = text[i];
1261     }
1262   else
1263     wcstr = (wchar_t *) text;
1264
1265   arg.total.cx = arg.total.cy = 0;
1266   arg.max.cx = arg.max.cy = 0;
1267
1268   gdk_wchar_text_handle (font, wcstr, text_length,
1269                          gdk_text_size_handler, &arg);
1270
1271   if (sizeof (wchar_t) != sizeof (GdkWChar))
1272     g_free (wcstr);
1273
1274   return arg.total.cx;
1275 }
1276
1277 gint
1278 gdk_char_width (GdkFont *font,
1279                 gchar    character)
1280 {
1281   if (((guchar) character) >= 128)
1282     {
1283       /* gtktext calls us with non-ASCII characters, sigh */
1284       GdkWChar wc = (guchar) character;
1285       return gdk_text_width_wc (font, &wc, 1);
1286     }
1287   return gdk_text_width (font, &character, 1);
1288 }
1289
1290 gint
1291 gdk_char_width_wc (GdkFont *font,
1292                    GdkWChar character)
1293 {
1294   return gdk_text_width_wc (font, &character, 1);
1295 }
1296
1297 gint
1298 gdk_string_measure (GdkFont     *font,
1299                     const gchar *string)
1300 {
1301   g_return_val_if_fail (font != NULL, -1);
1302   g_return_val_if_fail (string != NULL, -1);
1303
1304   return gdk_text_measure (font, string, strlen (string));
1305 }
1306
1307 void
1308 gdk_text_extents (GdkFont     *font,
1309                   const gchar *text,
1310                   gint         text_length,
1311                   gint        *lbearing,
1312                   gint        *rbearing,
1313                   gint        *width,
1314                   gint        *ascent,
1315                   gint        *descent)
1316 {
1317   gdk_text_size_arg arg;
1318   gint wlen;
1319   wchar_t *wcstr;
1320
1321   g_return_if_fail (font != NULL);
1322   g_return_if_fail (text != NULL);
1323
1324   if (text_length == 0)
1325     {
1326       if (lbearing)
1327         *lbearing = 0;
1328       if (rbearing)
1329         *rbearing = 0;
1330       if (width)
1331         *width = 0;
1332       if (ascent)
1333         *ascent = 0;
1334       if (descent)
1335         *descent = 0;
1336       return;
1337     }
1338
1339   g_assert (font->type == GDK_FONT_FONT || font->type == GDK_FONT_FONTSET);
1340
1341   arg.total.cx = arg.total.cy = 0;
1342   arg.max.cx = arg.max.cy = 0;
1343
1344   wcstr = g_new (wchar_t, text_length);
1345   if ((wlen = gdk_nmbstowchar_ts (wcstr, text, text_length, text_length)) == -1)
1346     g_warning ("gdk_text_extents: gdk_nmbstowchar_ts failed");
1347   else
1348     gdk_wchar_text_handle (font, wcstr, wlen, gdk_text_size_handler, &arg);
1349
1350   /* XXX This is quite bogus */
1351   if (lbearing)
1352     *lbearing = 0;
1353   if (rbearing)
1354     *rbearing = 0;
1355   if (width)
1356     *width = arg.total.cx;
1357   if (ascent)
1358     *ascent = arg.max.cy + 1;
1359   if (descent)
1360     *descent = font->descent + 1;
1361 }
1362
1363 void
1364 gdk_text_extents_wc (GdkFont        *font,
1365                      const GdkWChar *text,
1366                      gint            text_length,
1367                      gint           *lbearing,
1368                      gint           *rbearing,
1369                      gint           *width,
1370                      gint           *ascent,
1371                      gint           *descent)
1372 {
1373   gdk_text_size_arg arg;
1374   wchar_t *wcstr;
1375   gint i;
1376
1377   g_return_if_fail (font != NULL);
1378   g_return_if_fail (text != NULL);
1379
1380   if (text_length == 0)
1381     {
1382       if (lbearing)
1383         *lbearing = 0;
1384       if (rbearing)
1385         *rbearing = 0;
1386       if (width)
1387         *width = 0;
1388       if (ascent)
1389         *ascent = 0;
1390       if (descent)
1391         *descent = 0;
1392       return;
1393     }
1394
1395   g_assert (font->type == GDK_FONT_FONT || font->type == GDK_FONT_FONTSET);
1396
1397   if (sizeof (wchar_t) != sizeof (GdkWChar))
1398     {
1399       wcstr = g_new (wchar_t, text_length);
1400       for (i = 0; i < text_length; i++)
1401         wcstr[i] = text[i];
1402     }
1403   else
1404     wcstr = (wchar_t *) text;
1405
1406   arg.total.cx = arg.total.cy = 0;
1407   arg.max.cx = arg.max.cy = 0;
1408
1409   gdk_wchar_text_handle (font, wcstr, text_length,
1410                          gdk_text_size_handler, &arg);
1411
1412   if (sizeof (wchar_t) != sizeof (GdkWChar))
1413     g_free (wcstr);
1414
1415   /* XXX This is quite bogus */
1416   if (lbearing)
1417     *lbearing = 0;
1418   if (rbearing)
1419     *rbearing = 0;
1420   if (width)
1421     *width = arg.total.cx;
1422   if (ascent)
1423     *ascent = arg.max.cy + 1;
1424   if (descent)
1425     *descent = font->descent + 1;
1426 }
1427
1428 void
1429 gdk_string_extents (GdkFont     *font,
1430                     const gchar *string,
1431                     gint        *lbearing,
1432                     gint        *rbearing,
1433                     gint        *width,
1434                     gint        *ascent,
1435                     gint        *descent)
1436 {
1437   g_return_if_fail (font != NULL);
1438   g_return_if_fail (string != NULL);
1439
1440   gdk_text_extents (font, string, strlen (string),
1441                     lbearing, rbearing, width, ascent, descent);
1442 }
1443
1444
1445 gint
1446 gdk_text_measure (GdkFont     *font,
1447                   const gchar *text,
1448                   gint         text_length)
1449 {
1450   return gdk_text_width (font, text, text_length); /* ??? */
1451 }
1452
1453 gint
1454 gdk_char_measure (GdkFont *font,
1455                   gchar    character)
1456 {
1457   return gdk_text_measure (font, &character, 1);
1458 }
1459
1460 gint
1461 gdk_string_height (GdkFont     *font,
1462                    const gchar *string)
1463 {
1464   g_return_val_if_fail (font != NULL, -1);
1465   g_return_val_if_fail (string != NULL, -1);
1466
1467   return gdk_text_height (font, string, strlen (string));
1468 }
1469
1470 gint
1471 gdk_text_height (GdkFont     *font,
1472                  const gchar *text,
1473                  gint         text_length)
1474 {
1475   gdk_text_size_arg arg;
1476
1477   arg.total.cx = arg.total.cy = 0;
1478   arg.max.cx = arg.max.cy = 0;
1479
1480   if (!gdk_text_size (font, text, text_length, &arg))
1481     return -1;
1482
1483   return arg.max.cy;
1484 }
1485
1486 gint
1487 gdk_char_height (GdkFont *font,
1488                  gchar    character)
1489 {
1490   return gdk_text_height (font, &character, 1);
1491 }