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