]> Pileus Git - ~andy/gtk/blob - gdk/win32/gdkfont.c
d28c1f77c0615491ab1ad52cb0eb032e83fc7d97
[~andy/gtk] / gdk / win32 / gdkfont.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 "gdkprivate.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, GdkFont *font, const gchar *font_name)
40 {
41   GdkFontPrivate *private = (GdkFontPrivate *)font;
42   GHashTable **hashp = (type == GDK_FONT_FONT) ?
43     &font_name_hash : &fontset_name_hash;
44
45   if (!*hashp)
46     *hashp = g_hash_table_new (g_str_hash, g_str_equal);
47
48   private->names = g_slist_prepend (private->names, g_strdup (font_name));
49   g_hash_table_insert (*hashp, private->names->data, font);
50 }
51
52 static void
53 gdk_font_hash_remove (GdkFontType type, GdkFont *font)
54 {
55   GdkFontPrivate *private = (GdkFontPrivate *)font;
56   GSList *tmp_list;
57   GHashTable *hash = (type == GDK_FONT_FONT) ?
58     font_name_hash : fontset_name_hash;
59
60   tmp_list = private->names;
61   while (tmp_list)
62     {
63       g_hash_table_remove (hash, tmp_list->data);
64       g_free (tmp_list->data);
65       
66       tmp_list = tmp_list->next;
67     }
68
69   g_slist_free (private->names);
70   private->names = NULL;
71 }
72
73 static GdkFont *
74 gdk_font_hash_lookup (GdkFontType type, const gchar *font_name)
75 {
76   GdkFont *result;
77   GHashTable *hash = (type == GDK_FONT_FONT) ?
78     font_name_hash : fontset_name_hash;
79
80   if (!hash)
81     return NULL;
82   else
83     {
84       result = g_hash_table_lookup (hash, font_name);
85       if (result)
86         gdk_font_ref (result);
87       
88       return result;
89     }
90 }
91
92 static const char *
93 charset_name (DWORD charset)
94 {
95   switch (charset)
96     {
97     case ANSI_CHARSET: return "ANSI";
98     case DEFAULT_CHARSET: return "DEFAULT";
99     case SYMBOL_CHARSET: return "SYMBOL";
100     case SHIFTJIS_CHARSET: return "SHIFTJIS";
101     case HANGEUL_CHARSET: return "HANGEUL";
102     case GB2312_CHARSET: return "GB2312";
103     case CHINESEBIG5_CHARSET: return "CHINESEBIG5";
104     case JOHAB_CHARSET: return "JOHAB";
105     case HEBREW_CHARSET: return "HEBREW";
106     case ARABIC_CHARSET: return "ARABIC";
107     case GREEK_CHARSET: return "GREEK";
108     case TURKISH_CHARSET: return "TURKISH";
109     case VIETNAMESE_CHARSET: return "VIETNAMESE";
110     case THAI_CHARSET: return "THAI";
111     case EASTEUROPE_CHARSET: return "EASTEUROPE";
112     case RUSSIAN_CHARSET: return "RUSSIAN";
113     case MAC_CHARSET: return "MAC";
114     case BALTIC_CHARSET: return "BALTIC";
115     }
116   return "unknown";
117 }
118
119 GdkFont*
120 gdk_font_load (const gchar *font_name)
121 {
122   GdkFont *font;
123   GdkFontPrivate *private;
124   HFONT hfont;
125   LOGFONT logfont;
126   HGDIOBJ oldfont;
127   TEXTMETRIC textmetric;
128   CHARSETINFO csi;
129   HANDLE *f;
130   DWORD fdwItalic, fdwUnderline, fdwStrikeOut, fdwCharSet,
131     fdwOutputPrecision, fdwClipPrecision, fdwQuality, fdwPitchAndFamily;
132   const char *lpszFace;
133
134   int numfields, n1, n2, tries;
135   char foundry[32], family[100], weight[32], slant[32], set_width[32],
136     spacing[32], registry[32], encoding[32];
137   char pixel_size[10], point_size[10], res_x[10], res_y[10], avg_width[10];
138   int c;
139   char *p;
140   int nHeight, nWidth, nEscapement, nOrientation, fnWeight;
141   int logpixelsy;
142
143   g_return_val_if_fail (font_name != NULL, NULL);
144
145   GDK_NOTE (MISC, g_print ("gdk_font_load: %s\n", font_name));
146
147   font = gdk_font_hash_lookup (GDK_FONT_FONT, font_name);
148   if (font)
149     return font;
150
151   numfields = sscanf (font_name,
152                       "-%30[^-]-%100[^-]-%30[^-]-%30[^-]-%30[^-]-%n",
153                       foundry,
154                       family,
155                       weight,
156                       slant,
157                       set_width,
158                       &n1);
159   if (numfields == 0)
160     {
161       /* Probably a plain Windows font name */
162       nHeight = 0;
163       nWidth = 0;
164       nEscapement = 0;
165       nOrientation = 0;
166       fnWeight = FW_DONTCARE;
167       fdwItalic = FALSE;
168       fdwUnderline = FALSE;
169       fdwStrikeOut = FALSE;
170       fdwCharSet = ANSI_CHARSET;
171       fdwOutputPrecision = OUT_TT_PRECIS;
172       fdwClipPrecision = CLIP_DEFAULT_PRECIS;
173       fdwQuality = PROOF_QUALITY;
174       fdwPitchAndFamily = DEFAULT_PITCH;
175       lpszFace = font_name;
176     }
177   else if (numfields != 5)
178     {
179       g_warning ("gdk_font_load: font name %s illegal", font_name);
180       g_free (font);
181       return NULL;
182     }
183   else
184     {
185       /* It must be a XLFD name */
186
187       /* Check for hex escapes in the font family,
188        * put in there by gtkfontsel.
189        */
190       p = family;
191       while (*p)
192         {
193           if (*p == '%' && isxdigit (p[1]) && isxdigit (p[2]))
194             {
195               sscanf (p+1, "%2x", &c);
196               *p = c;
197               strcpy (p+1, p+3);
198             }
199           p++;
200         }
201
202       /* Skip add_style which often is empty in the requested font name */
203       while (font_name[n1] && font_name[n1] != '-')
204         n1++;
205       numfields++;
206
207       numfields += sscanf (font_name + n1,
208                            "-%8[^-]-%8[^-]-%8[^-]-%8[^-]-%30[^-]-%8[^-]-%30[^-]-%30[^-]%n",
209                            pixel_size,
210                            point_size,
211                            res_x,
212                            res_y,
213                            spacing,
214                            avg_width,
215                            registry,
216                            encoding,
217                            &n2);
218
219       if (numfields != 14 || font_name[n1 + n2] != '\0')
220         {
221           g_warning ("gdk_font_load: font name %s illegal", font_name);
222           g_free (font);
223           return NULL;
224         }
225
226       logpixelsy = GetDeviceCaps (gdk_DC, LOGPIXELSY);
227
228       if (strcmp (pixel_size, "*") == 0)
229         if (strcmp (point_size, "*") == 0)
230           nHeight = 0;
231         else
232           nHeight = (int) (((double) atoi (point_size))/720.*logpixelsy);
233       else
234         nHeight = atoi (pixel_size);
235
236       nWidth = 0;
237       nEscapement = 0;
238       nOrientation = 0;
239
240       if (g_strcasecmp (weight, "thin") == 0)
241         fnWeight = FW_THIN;
242       else if (g_strcasecmp (weight, "extralight") == 0)
243         fnWeight = FW_EXTRALIGHT;
244       else if (g_strcasecmp (weight, "ultralight") == 0)
245 #ifdef FW_ULTRALIGHT
246         fnWeight = FW_ULTRALIGHT;
247 #else
248         fnWeight = FW_EXTRALIGHT; /* In fact, FW_ULTRALIGHT really is 
249                                    * defined as FW_EXTRALIGHT anyway.
250                                    */
251 #endif
252       else if (g_strcasecmp (weight, "light") == 0)
253         fnWeight = FW_LIGHT;
254       else if (g_strcasecmp (weight, "normal") == 0)
255         fnWeight = FW_NORMAL;
256       else if (g_strcasecmp (weight, "regular") == 0)
257         fnWeight = FW_REGULAR;
258       else if (g_strcasecmp (weight, "medium") == 0)
259         fnWeight = FW_MEDIUM;
260       else if (g_strcasecmp (weight, "semibold") == 0)
261         fnWeight = FW_SEMIBOLD;
262       else if (g_strcasecmp (weight, "demibold") == 0)
263 #ifdef FW_DEMIBOLD
264         fnWeight = FW_DEMIBOLD;
265 #else
266         fnWeight = FW_SEMIBOLD; /* As above */
267 #endif
268       else if (g_strcasecmp (weight, "bold") == 0)
269         fnWeight = FW_BOLD;
270       else if (g_strcasecmp (weight, "extrabold") == 0)
271         fnWeight = FW_EXTRABOLD;
272       else if (g_strcasecmp (weight, "ultrabold") == 0)
273 #ifdef FW_ULTRABOLD
274         fnWeight = FW_ULTRABOLD;
275 #else
276         fnWeight = FW_EXTRABOLD; /* As above */
277 #endif
278       else if (g_strcasecmp (weight, "heavy") == 0)
279         fnWeight = FW_HEAVY;
280       else if (g_strcasecmp (weight, "black") == 0)
281 #ifdef FW_BLACK
282         fnWeight = FW_BLACK;
283 #else
284         fnWeight = FW_HEAVY;    /* As above */
285 #endif
286       else
287         fnWeight = FW_DONTCARE;
288
289       if (g_strcasecmp (slant, "italic") == 0
290           || g_strcasecmp (slant, "oblique") == 0
291           || g_strcasecmp (slant, "i") == 0
292           || g_strcasecmp (slant, "o") == 0)
293         fdwItalic = TRUE;
294       else
295         fdwItalic = FALSE;
296       fdwUnderline = FALSE;
297       fdwStrikeOut = FALSE;
298       if (g_strcasecmp (registry, "iso8859") == 0)
299         if (strcmp (encoding, "1") == 0)
300           fdwCharSet = ANSI_CHARSET;
301         else
302           fdwCharSet = ANSI_CHARSET; /* XXX ??? */
303       else if (g_strcasecmp (registry, "windows") == 0)
304         if (g_strcasecmp (encoding, "symbol") == 0)
305           fdwCharSet = SYMBOL_CHARSET;
306         else if (g_strcasecmp (encoding, "shiftjis") == 0)
307           fdwCharSet = SHIFTJIS_CHARSET;
308         else if (g_strcasecmp (encoding, "gb2312") == 0)
309           fdwCharSet = GB2312_CHARSET;
310         else if (g_strcasecmp (encoding, "hangeul") == 0)
311           fdwCharSet = HANGEUL_CHARSET;
312         else if (g_strcasecmp (encoding, "chinesebig5") == 0)
313           fdwCharSet = CHINESEBIG5_CHARSET;
314         else if (g_strcasecmp (encoding, "johab") == 0)
315           fdwCharSet = JOHAB_CHARSET;
316         else if (g_strcasecmp (encoding, "hebrew") == 0)
317           fdwCharSet = HEBREW_CHARSET;
318         else if (g_strcasecmp (encoding, "arabic") == 0)
319           fdwCharSet = ARABIC_CHARSET;
320         else if (g_strcasecmp (encoding, "greek") == 0)
321           fdwCharSet = GREEK_CHARSET;
322         else if (g_strcasecmp (encoding, "turkish") == 0)
323           fdwCharSet = TURKISH_CHARSET;
324         else if (g_strcasecmp (encoding, "easteurope") == 0)
325           fdwCharSet = EASTEUROPE_CHARSET;
326         else if (g_strcasecmp (encoding, "russian") == 0)
327           fdwCharSet = RUSSIAN_CHARSET;
328         else if (g_strcasecmp (encoding, "mac") == 0)
329           fdwCharSet = MAC_CHARSET;
330         else if (g_strcasecmp (encoding, "baltic") == 0)
331           fdwCharSet = BALTIC_CHARSET;
332         else
333           fdwCharSet = ANSI_CHARSET; /* XXX ??? */
334       else
335         fdwCharSet = ANSI_CHARSET; /* XXX ??? */
336       fdwOutputPrecision = OUT_TT_PRECIS;
337       fdwClipPrecision = CLIP_DEFAULT_PRECIS;
338       fdwQuality = PROOF_QUALITY;
339       if (g_strcasecmp (spacing, "m") == 0)
340         fdwPitchAndFamily = FIXED_PITCH;
341       else if (g_strcasecmp (spacing, "p") == 0)
342         fdwPitchAndFamily = VARIABLE_PITCH;
343       else 
344         fdwPitchAndFamily = DEFAULT_PITCH;
345       lpszFace = family;
346     }
347
348   for (tries = 0; ; tries++)
349     {
350       GDK_NOTE (MISC, g_print ("...trying CreateFont(%d,%d,%d,%d,"
351                                "%d,%d,%d,%d,"
352                                "%d,%d,%d,"
353                                "%d,%#.02x,\"%s\")\n",
354                                nHeight, nWidth, nEscapement, nOrientation,
355                                fnWeight, fdwItalic, fdwUnderline, fdwStrikeOut,
356                                fdwCharSet, fdwOutputPrecision, fdwClipPrecision,
357                                fdwQuality, fdwPitchAndFamily, lpszFace));
358       if ((hfont =
359            CreateFont (nHeight, nWidth, nEscapement, nOrientation,
360                        fnWeight, fdwItalic, fdwUnderline, fdwStrikeOut,
361                        fdwCharSet, fdwOutputPrecision, fdwClipPrecision,
362                        fdwQuality, fdwPitchAndFamily, lpszFace)) != NULL)
363         break;
364
365       /* If we fail, try some similar fonts often found on Windows. */
366
367       if (tries == 0)
368         {
369           if (g_strcasecmp (family, "helvetica") == 0)
370             lpszFace = "arial";
371           else if (g_strcasecmp (family, "new century schoolbook") == 0)
372             lpszFace = "century schoolbook";
373           else if (g_strcasecmp (family, "courier") == 0)
374             lpszFace = "courier new";
375           else if (g_strcasecmp (family, "lucida") == 0)
376             lpszFace = "lucida sans unicode";
377           else if (g_strcasecmp (family, "lucidatypewriter") == 0)
378             lpszFace = "lucida console";
379           else if (g_strcasecmp (family, "times") == 0)
380             lpszFace = "times new roman";
381         }
382       else if (tries == 1)
383         {
384           if (g_strcasecmp (family, "courier") == 0)
385             {
386               lpszFace = "";
387               fdwPitchAndFamily |= FF_MODERN;
388             }
389           else if (g_strcasecmp (family, "times new roman") == 0)
390             {
391               lpszFace = "";
392               fdwPitchAndFamily |= FF_ROMAN;
393             }
394           else if (g_strcasecmp (family, "helvetica") == 0
395                    || g_strcasecmp (family, "lucida") == 0)
396             {
397               lpszFace = "";
398               fdwPitchAndFamily |= FF_SWISS;
399             }
400           else
401             {
402               lpszFace = "";
403               fdwPitchAndFamily = (fdwPitchAndFamily & 0x0F) | FF_DONTCARE;
404             }
405         }
406       else
407         break;
408       tries++;
409     }
410   
411   if (!hfont)
412     return NULL;
413       
414   private = g_new (GdkFontPrivate, 1);
415   font = (GdkFont*) private;
416
417   private->xfont = hfont;
418   private->ref_count = 1;
419   private->names = NULL;
420   font->type = GDK_FONT_FONT;
421   GetObject (private->xfont, sizeof (logfont), &logfont);
422   oldfont = SelectObject (gdk_DC, private->xfont);
423   GetTextMetrics (gdk_DC, &textmetric);
424   private->charset = GetTextCharsetInfo (gdk_DC, &private->fs, 0);
425   SelectObject (gdk_DC, oldfont);
426   TranslateCharsetInfo ((DWORD *) private->charset, &csi, TCI_SRCCHARSET);
427   private->codepage = csi.ciACP;
428   GetCPInfo (private->codepage, &private->cpinfo);
429   font->ascent = textmetric.tmAscent;
430   font->descent = textmetric.tmDescent;
431
432   GDK_NOTE (MISC, g_print ("... = %#x charset %s codepage %d (max %d bytes) "
433                            "asc %d desc %d\n",
434                            private->xfont,
435                            charset_name (private->charset),
436                            private->codepage,
437                            private->cpinfo.MaxCharSize,
438                            font->ascent, font->descent));
439
440   /* This memory is leaked, so shoot me. */
441   f = g_new (HANDLE, 1);
442   *f = (HANDLE) ((guint) private->xfont + HFONT_DITHER);
443   gdk_xid_table_insert (f, font);
444
445   gdk_font_hash_insert (GDK_FONT_FONT, font, font_name);
446
447   return font;
448 }
449
450 GdkFont*
451 gdk_fontset_load (gchar *fontset_name)
452 {
453   g_warning ("gdk_fontset_load: Not implemented");
454
455   return NULL;
456 }
457
458 GdkFont*
459 gdk_font_ref (GdkFont *font)
460 {
461   GdkFontPrivate *private;
462
463   g_return_val_if_fail (font != NULL, NULL);
464
465   private = (GdkFontPrivate*) font;
466   private->ref_count += 1;
467
468   GDK_NOTE (MISC, g_print ("gdk_font_ref %#x %d\n",
469                            private->xfont, private->ref_count));
470   return font;
471 }
472
473 void
474 gdk_font_unref (GdkFont *font)
475 {
476   GdkFontPrivate *private;
477   private = (GdkFontPrivate*) font;
478
479   g_return_if_fail (font != NULL);
480   g_return_if_fail (private->ref_count > 0);
481
482   private->ref_count -= 1;
483
484   GDK_NOTE (MISC, g_print ("gdk_font_unref %#x %d%s\n",
485                            private->xfont,
486                            private->ref_count,
487                            (private->ref_count == 0 ? " freeing" : "")));
488
489   if (private->ref_count == 0)
490     {
491       gdk_font_hash_remove (font->type, font);
492       
493       switch (font->type)
494         {
495         case GDK_FONT_FONT:
496           gdk_xid_table_remove ((HANDLE) ((guint) private->xfont + HFONT_DITHER));
497           DeleteObject (private->xfont);
498           break;
499
500         default:
501           g_assert_not_reached ();
502         }
503       g_free (font);
504     }
505 }
506
507 gint
508 gdk_font_id (const GdkFont *font)
509 {
510   const GdkFontPrivate *font_private;
511
512   g_return_val_if_fail (font != NULL, 0);
513
514   font_private = (const GdkFontPrivate*) font;
515
516   if (font->type == GDK_FONT_FONT)
517     return (gint) font_private->xfont;
518
519   g_assert_not_reached ();
520   return 0;
521 }
522
523 gint
524 gdk_font_equal (const GdkFont *fonta,
525                 const GdkFont *fontb)
526 {
527   const GdkFontPrivate *privatea;
528   const GdkFontPrivate *privateb;
529
530   g_return_val_if_fail (fonta != NULL, FALSE);
531   g_return_val_if_fail (fontb != NULL, FALSE);
532
533   privatea = (const GdkFontPrivate*) fonta;
534   privateb = (const GdkFontPrivate*) fontb;
535
536   if (fonta->type == GDK_FONT_FONT && fontb->type == GDK_FONT_FONT)
537     return (privatea->xfont == privateb->xfont);
538
539   g_assert_not_reached ();
540   return 0;
541 }
542
543 gint
544 gdk_string_width (GdkFont     *font,
545                   const gchar *string)
546 {
547   return gdk_text_width (font, string, strlen (string));
548 }
549
550 gint
551 gdk_text_width (GdkFont      *font,
552                 const gchar  *text,
553                 gint          text_length)
554 {
555   GdkFontPrivate *private;
556   HGDIOBJ oldfont;
557   SIZE size;
558   gint width, wlen;
559   wchar_t *wcstr;
560
561   g_return_val_if_fail (font != NULL, -1);
562   g_return_val_if_fail (text != NULL, -1);
563
564   if (text_length == 0)
565     return 0;
566
567   private = (GdkFontPrivate*) font;
568
569   switch (font->type)
570     {
571     case GDK_FONT_FONT:
572       oldfont = SelectObject (gdk_DC, private->xfont);
573       if (private->cpinfo.MaxCharSize > 1)
574         {
575           wcstr = g_new (wchar_t, text_length);
576           if ((wlen = MultiByteToWideChar (private->codepage, 0,
577                                            text, text_length,
578                                            wcstr, text_length)) == 0)
579             {
580               g_warning ("gdk_text_width: MultiByteToWideChar failed");
581               size.cx = 0;
582             }
583           else
584             GetTextExtentPoint32W (gdk_DC, wcstr, wlen, &size);
585           g_free (wcstr);
586         }
587       else
588         {
589           GetTextExtentPoint32A (gdk_DC, text, text_length, &size);
590         }
591       SelectObject (gdk_DC, oldfont);
592       width = size.cx;
593       break;
594
595     default:
596       g_assert_not_reached ();
597     }
598   return width;
599 }
600
601 gint
602 gdk_text_width_wc (GdkFont        *font,
603                    const GdkWChar *text,
604                    gint            text_length)
605 {
606   GdkFontPrivate *private;
607   HGDIOBJ oldfont;
608   SIZE size;
609   wchar_t *wcstr;
610   guchar *str;
611   gint i, width, wlen;
612
613   g_return_val_if_fail (font != NULL, -1);
614   g_return_val_if_fail (text != NULL, -1);
615
616   if (text_length == 0)
617     return 0;
618
619   private = (GdkFontPrivate*) font;
620
621   switch (font->type)
622     {
623     case GDK_FONT_FONT:
624       oldfont = SelectObject (gdk_DC, private->xfont);
625 #if 0 /* No. Don't assume Unicode here either.
626        * (Read the comments in gdk_draw_text_wc.)
627        */
628       wcstr = g_new (wchar_t, text_length);
629       for (i = 0; i < text_length; i++)
630         wcstr[i] = text[i];
631       GetTextExtentPoint32W (gdk_DC, wcstr, text_length, &size);
632       g_free (wcstr);
633 #else
634       str = g_new (guchar, text_length);
635       for (i = 0; i < text_length; i++)
636         str[i] = text[i];
637       if (private->cpinfo.MaxCharSize > 1)
638         {
639           wcstr = g_new (wchar_t, text_length);
640           if ((wlen = MultiByteToWideChar (private->codepage, 0,
641                                            str, text_length,
642                                            wcstr, text_length)) == 0)
643             {
644               g_warning ("gdk_text_width_wc: MultiByteToWideChar failed");
645               size.cx = 0;
646             }
647           else
648             GetTextExtentPoint32W (gdk_DC, wcstr, wlen, &size);
649           g_free (wcstr);
650         }
651       else
652         {
653           GetTextExtentPoint32A (gdk_DC, str, text_length, &size);
654         }
655       g_free (str);
656 #endif
657       SelectObject (gdk_DC, oldfont);
658       width = size.cx;
659       break;
660
661     default:
662       width = 0;
663     }
664   return width;
665 }
666
667 gint
668 gdk_char_width (GdkFont *font,
669                 gchar    character)
670 {
671   return gdk_text_width (font, &character, 1);
672 }
673
674 gint
675 gdk_char_width_wc (GdkFont *font,
676                    GdkWChar character)
677 {
678   return gdk_text_width_wc (font, &character, 1);
679 }
680
681 gint
682 gdk_string_measure (GdkFont     *font,
683                     const gchar *string)
684 {
685   g_return_val_if_fail (font != NULL, -1);
686   g_return_val_if_fail (string != NULL, -1);
687
688   return gdk_text_measure (font, string, strlen (string));
689 }
690
691 void
692 gdk_text_extents (GdkFont     *font,
693                   const gchar *text,
694                   gint         text_length,
695                   gint        *lbearing,
696                   gint        *rbearing,
697                   gint        *width,
698                   gint        *ascent,
699                   gint        *descent)
700 {
701   GdkFontPrivate *private;
702   HGDIOBJ oldfont;
703   SIZE size;
704   gint wlen;
705   wchar_t *wcstr;
706
707   g_return_if_fail (font != NULL);
708   g_return_if_fail (text != NULL);
709
710   if (text_length == 0)
711     {
712       if (lbearing)
713         *lbearing = 0;
714       if (rbearing)
715         *rbearing = 0;
716       if (width)
717         *width = 0;
718       if (ascent)
719         *ascent = 0;
720       if (descent)
721         *descent = 0;
722       return;
723     }
724
725   private = (GdkFontPrivate*) font;
726
727   switch (font->type)
728     {
729     case GDK_FONT_FONT:
730       oldfont = SelectObject (gdk_DC, private->xfont);
731       if (private->cpinfo.MaxCharSize > 1)
732         {
733           wcstr = g_new (wchar_t, text_length);
734           if ((wlen = MultiByteToWideChar (private->codepage, 0,
735                                            text, text_length,
736                                            wcstr, text_length)) == 0)
737             {
738               g_warning ("gdk_text_extents: MultiByteToWideChar failed");
739               size.cx = 0;
740               size.cy = 0;
741             }
742           else
743             GetTextExtentPoint32W (gdk_DC, wcstr, wlen, &size);
744           g_free (wcstr);
745         }
746       else
747         {
748           GetTextExtentPoint32A (gdk_DC, text, text_length, &size);
749         }
750       SelectObject (gdk_DC, oldfont);
751       /* XXX This is all quite bogus */
752       if (lbearing)
753         *lbearing = 0;
754       if (rbearing)
755         *rbearing = 0;
756       if (width)
757         *width = size.cx;
758       if (ascent)
759         *ascent = size.cy + 1;
760       if (descent)
761         *descent = font->descent + 1;
762       break;
763
764     default:
765       g_assert_not_reached ();
766     }
767 }
768
769 void
770 gdk_text_extents_wc (GdkFont        *font,
771                      const GdkWChar *text,
772                      gint            text_length,
773                      gint           *lbearing,
774                      gint           *rbearing,
775                      gint           *width,
776                      gint           *ascent,
777                      gint           *descent)
778 {
779   GdkFontPrivate *private;
780   HGDIOBJ oldfont;
781   SIZE size;
782   wchar_t *wcstr;
783   gint i;
784
785   g_return_if_fail (font != NULL);
786   g_return_if_fail (text != NULL);
787
788   if (text_length == 0)
789     {
790       if (lbearing)
791         *lbearing = 0;
792       if (rbearing)
793         *rbearing = 0;
794       if (width)
795         *width = 0;
796       if (ascent)
797         *ascent = 0;
798       if (descent)
799         *descent = 0;
800       return;
801     }
802
803   private = (GdkFontPrivate*) font;
804
805   switch (font->type)
806     {
807     case GDK_FONT_FONT:
808       wcstr = g_new (wchar_t, text_length);
809       for (i = 0; i < text_length; i++)
810         wcstr[i] = text[i];
811       oldfont = SelectObject (gdk_DC, private->xfont);
812       GetTextExtentPoint32W (gdk_DC, wcstr, text_length, &size);
813       g_free (wcstr);
814       SelectObject (gdk_DC, oldfont);
815
816       /* XXX This is all quite bogus */
817       if (lbearing)
818         *lbearing = 0;
819       if (rbearing)
820         *rbearing = 0;
821       if (width)
822         *width = size.cx;
823       if (ascent)
824         *ascent = size.cy + 1;
825       if (descent)
826         *descent = font->descent + 1;
827       break;
828
829     default:
830       g_assert_not_reached ();
831     }
832 }
833
834 void
835 gdk_string_extents (GdkFont     *font,
836                     const gchar *string,
837                     gint        *lbearing,
838                     gint        *rbearing,
839                     gint        *width,
840                     gint        *ascent,
841                     gint        *descent)
842 {
843   g_return_if_fail (font != NULL);
844   g_return_if_fail (string != NULL);
845
846   gdk_text_extents (font, string, strlen (string),
847                     lbearing, rbearing, width, ascent, descent);
848 }
849
850
851 gint
852 gdk_text_measure (GdkFont     *font,
853                   const gchar *text,
854                   gint         text_length)
855 {
856   GdkFontPrivate *private;
857   gint width;
858
859   g_return_val_if_fail (font != NULL, -1);
860   g_return_val_if_fail (text != NULL, -1);
861
862   private = (GdkFontPrivate*) font;
863
864   switch (font->type)
865     {
866     case GDK_FONT_FONT:
867       return gdk_text_width (font, text, text_length); /* ??? */
868       break;
869
870     default:
871       g_assert_not_reached ();
872     }
873   return 0;
874 }
875
876 gint
877 gdk_char_measure (GdkFont *font,
878                   gchar    character)
879 {
880   return gdk_text_measure (font, &character, 1);
881 }
882
883 gint
884 gdk_string_height (GdkFont     *font,
885                    const gchar *string)
886 {
887   g_return_val_if_fail (font != NULL, -1);
888   g_return_val_if_fail (string != NULL, -1);
889
890   return gdk_text_height (font, string, strlen (string));
891 }
892
893 gint
894 gdk_text_height (GdkFont     *font,
895                  const gchar *text,
896                  gint         text_length)
897 {
898   GdkFontPrivate *private;
899   HGDIOBJ oldfont;
900   SIZE size;
901   gint height, wlen;
902   wchar_t *wcstr;
903
904   g_return_val_if_fail (font != NULL, -1);
905   g_return_val_if_fail (text != NULL, -1);
906
907   if (text_length == 0)
908     return 0;
909
910   private = (GdkFontPrivate*) font;
911
912   switch (font->type)
913     {
914     case GDK_FONT_FONT:
915       oldfont = SelectObject (gdk_DC, private->xfont);
916       if (private->cpinfo.MaxCharSize > 1)
917         {
918           wcstr = g_new (wchar_t, text_length);
919           if ((wlen = MultiByteToWideChar (private->codepage, 0,
920                                            text, text_length,
921                                            wcstr, text_length)) == 0)
922             {
923               g_warning ("gdk_text_height: MultiByteToWideChar failed "
924                          "text = %.*s (%d)",
925                          text_length, text, text_length);
926               size.cy = 0;
927             }
928           else
929             GetTextExtentPoint32W (gdk_DC, wcstr, wlen, &size);
930           g_free (wcstr);
931         }
932       else
933         {
934           GetTextExtentPoint32A (gdk_DC, text, text_length, &size);
935         }
936       SelectObject (gdk_DC, oldfont);
937       height = size.cy;
938       break;
939
940     default:
941       g_error ("font->type = %d", font->type);
942     }
943   return height;
944 }
945
946 gint
947 gdk_char_height (GdkFont *font,
948                  gchar    character)
949 {
950   return gdk_text_height (font, &character, 1);
951 }