]> Pileus Git - ~andy/gtk/blob - gdk/win32/gdkfont-win32.c
Update gcc build instructions. Mention gettext is GPL.
[~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 <gdk/gdk.h>
33 #include "gdkprivate.h"
34
35 GdkFont*
36 gdk_font_load (const gchar *font_name)
37 {
38   GdkFont *font;
39   GdkFontPrivate *private;
40   LOGFONT logfont;
41   HGDIOBJ oldfont;
42   TEXTMETRIC textmetric;
43   HANDLE *f;
44   DWORD fdwItalic, fdwUnderline, fdwStrikeOut, fdwCharSet,
45     fdwOutputPrecision, fdwClipPrecision, fdwQuality, fdwPitchAndFamily;
46   const char *lpszFace;
47
48   int numfields, n1, n2, tries;
49   char foundry[32], family[100], weight[32], slant[32], set_width[32],
50     spacing[32], registry[32], encoding[32];
51   char pixel_size[10], point_size[10], res_x[10], res_y[10], avg_width[10];
52   int c;
53   char *p;
54   int nHeight, nWidth, nEscapement, nOrientation, fnWeight;
55   int logpixelsy;
56
57   g_return_val_if_fail (font_name != NULL, NULL);
58
59   private = g_new (GdkFontPrivate, 1);
60   font = (GdkFont*) private;
61
62   numfields = sscanf (font_name,
63                       "-%30[^-]-%100[^-]-%30[^-]-%30[^-]-%30[^-]-%n",
64                       foundry,
65                       family,
66                       weight,
67                       slant,
68                       set_width,
69                       &n1);
70   if (numfields == 0)
71     {
72       /* Probably a plain Windows font name */
73       nHeight = 0;
74       nWidth = 0;
75       nEscapement = 0;
76       nOrientation = 0;
77       fnWeight = FW_DONTCARE;
78       fdwItalic = FALSE;
79       fdwUnderline = FALSE;
80       fdwStrikeOut = FALSE;
81       fdwCharSet = ANSI_CHARSET;
82       fdwOutputPrecision = OUT_TT_PRECIS;
83       fdwClipPrecision = CLIP_DEFAULT_PRECIS;
84       fdwQuality = PROOF_QUALITY;
85       fdwPitchAndFamily = DEFAULT_PITCH;
86       lpszFace = font_name;
87     }
88   else if (numfields != 5)
89     {
90       g_warning ("gdk_font_load: font name %s illegal", font_name);
91       g_free (font);
92       return NULL;
93     }
94   else
95     {
96       /* It must be a XLFD name */
97
98       /* Check for hex escapes in the font family,
99        * put in there by gtkfontsel.
100        */
101       p = family;
102       while (*p)
103         {
104           if (*p == '%' && isxdigit (p[1]) && isxdigit (p[2]))
105             {
106               sscanf (p+1, "%2x", &c);
107               *p = c;
108               strcpy (p+1, p+3);
109             }
110           p++;
111         }
112
113       /* Skip add_style which often is empty in the requested font name */
114       while (font_name[n1] && font_name[n1] != '-')
115         n1++;
116       numfields++;
117
118       numfields += sscanf (font_name + n1,
119                            "-%8[^-]-%8[^-]-%8[^-]-%8[^-]-%30[^-]-%8[^-]-%30[^-]-%30[^-]%n",
120                            pixel_size,
121                            point_size,
122                            res_x,
123                            res_y,
124                            spacing,
125                            avg_width,
126                            registry,
127                            encoding,
128                            &n2);
129
130       if (numfields != 14 || font_name[n1 + n2] != '\0')
131         {
132           g_warning ("gdk_font_load: font name %s illegal", font_name);
133           g_free (font);
134           return NULL;
135         }
136
137       logpixelsy = GetDeviceCaps (gdk_DC, LOGPIXELSY);
138
139       if (strcmp (pixel_size, "*") == 0)
140         if (strcmp (point_size, "*") == 0)
141           nHeight = 0;
142         else
143           nHeight = (int) (((double) atoi (point_size))/720.*logpixelsy);
144       else
145         nHeight = atoi (pixel_size);
146
147       nWidth = 0;
148       nEscapement = 0;
149       nOrientation = 0;
150
151       if (g_strcasecmp (weight, "thin") == 0)
152         fnWeight = FW_THIN;
153       else if (g_strcasecmp (weight, "extralight") == 0)
154         fnWeight = FW_EXTRALIGHT;
155 #ifdef FW_ULTRALIGHT
156       else if (g_strcasecmp (weight, "ultralight") == 0)
157         fnWeight = FW_ULTRALIGHT;
158 #endif
159       else if (g_strcasecmp (weight, "light") == 0)
160         fnWeight = FW_LIGHT;
161       else if (g_strcasecmp (weight, "normal") == 0)
162         fnWeight = FW_NORMAL;
163       else if (g_strcasecmp (weight, "regular") == 0)
164         fnWeight = FW_REGULAR;
165       else if (g_strcasecmp (weight, "medium") == 0)
166         fnWeight = FW_MEDIUM;
167       else if (g_strcasecmp (weight, "semibold") == 0)
168         fnWeight = FW_SEMIBOLD;
169 #ifdef FW_DEMIBOLD
170       else if (g_strcasecmp (weight, "demibold") == 0)
171         fnWeight = FW_DEMIBOLD;
172 #endif
173       else if (g_strcasecmp (weight, "bold") == 0)
174         fnWeight = FW_BOLD;
175       else if (g_strcasecmp (weight, "extrabold") == 0)
176         fnWeight = FW_EXTRABOLD;
177 #ifdef FW_ULTRABOLD
178       else if (g_strcasecmp (weight, "ultrabold") == 0)
179         fnWeight = FW_ULTRABOLD;
180 #endif
181       else if (g_strcasecmp (weight, "heavy") == 0)
182         fnWeight = FW_HEAVY;
183 #ifdef FW_BLACK
184       else if (g_strcasecmp (weight, "black") == 0)
185         fnWeight = FW_BLACK;
186 #endif
187       else
188         fnWeight = FW_DONTCARE;
189
190       if (g_strcasecmp (slant, "italic") == 0
191           || g_strcasecmp (slant, "oblique") == 0
192           || g_strcasecmp (slant, "i") == 0
193           || g_strcasecmp (slant, "o") == 0)
194         fdwItalic = TRUE;
195       else
196         fdwItalic = FALSE;
197       fdwUnderline = FALSE;
198       fdwStrikeOut = FALSE;
199       if (g_strcasecmp (registry, "iso8859") == 0)
200         if (strcmp (encoding, "1") == 0)
201           fdwCharSet = ANSI_CHARSET;
202         else
203           fdwCharSet = ANSI_CHARSET; /* XXX ??? */
204       else if (g_strcasecmp (registry, "windows") == 0)
205         if (g_strcasecmp (encoding, "symbol") == 0)
206           fdwCharSet = SYMBOL_CHARSET;
207         else if (g_strcasecmp (encoding, "shiftjis") == 0)
208           fdwCharSet = SHIFTJIS_CHARSET;
209         else if (g_strcasecmp (encoding, "gb2312") == 0)
210           fdwCharSet = GB2312_CHARSET;
211         else if (g_strcasecmp (encoding, "hangeul") == 0)
212           fdwCharSet = HANGEUL_CHARSET;
213         else if (g_strcasecmp (encoding, "chinesebig5") == 0)
214           fdwCharSet = CHINESEBIG5_CHARSET;
215 #ifdef JOHAB_CHARSET
216         else if (g_strcasecmp (encoding, "johab") == 0)
217           fdwCharSet = JOHAB_CHARSET;
218 #endif
219         else if (g_strcasecmp (encoding, "hebrew") == 0)
220           fdwCharSet = HEBREW_CHARSET;
221         else if (g_strcasecmp (encoding, "arabic") == 0)
222           fdwCharSet = ARABIC_CHARSET;
223         else if (g_strcasecmp (encoding, "greek") == 0)
224           fdwCharSet = GREEK_CHARSET;
225         else if (g_strcasecmp (encoding, "turkish") == 0)
226           fdwCharSet = TURKISH_CHARSET;
227         else if (g_strcasecmp (encoding, "easteurope") == 0)
228           fdwCharSet = EASTEUROPE_CHARSET;
229         else if (g_strcasecmp (encoding, "russian") == 0)
230           fdwCharSet = RUSSIAN_CHARSET;
231         else if (g_strcasecmp (encoding, "mac") == 0)
232           fdwCharSet = MAC_CHARSET;
233         else if (g_strcasecmp (encoding, "baltic") == 0)
234           fdwCharSet = BALTIC_CHARSET;
235         else
236           fdwCharSet = ANSI_CHARSET; /* XXX ??? */
237       else
238         fdwCharSet = ANSI_CHARSET; /* XXX ??? */
239       fdwOutputPrecision = OUT_TT_PRECIS;
240       fdwClipPrecision = CLIP_DEFAULT_PRECIS;
241       fdwQuality = PROOF_QUALITY;
242       if (g_strcasecmp (spacing, "m") == 0)
243         fdwPitchAndFamily = FIXED_PITCH;
244       else if (g_strcasecmp (spacing, "p") == 0)
245         fdwPitchAndFamily = VARIABLE_PITCH;
246       else 
247         fdwPitchAndFamily = DEFAULT_PITCH;
248       lpszFace = family;
249     }
250
251   for (tries = 0; ; tries++)
252     {
253       GDK_NOTE (MISC, g_print ("gdk_font_load: trying CreateFont(%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%#.02x,\"%s\")\n",
254                                nHeight, nWidth, nEscapement, nOrientation,
255                                fnWeight, fdwItalic, fdwUnderline, fdwStrikeOut,
256                                fdwCharSet, fdwOutputPrecision, fdwClipPrecision,
257                                fdwQuality, fdwPitchAndFamily, lpszFace));
258       if ((private->xfont =
259            CreateFont (nHeight, nWidth, nEscapement, nOrientation,
260                        fnWeight, fdwItalic, fdwUnderline, fdwStrikeOut,
261                        fdwCharSet, fdwOutputPrecision, fdwClipPrecision,
262                        fdwQuality, fdwPitchAndFamily, lpszFace)) != NULL)
263         break;
264
265       /* If we fail, try some similar fonts often found on Windows. */
266
267       if (tries == 0)
268         {
269           if (g_strcasecmp (family, "helvetica") == 0)
270             lpszFace = "arial";
271           else if (g_strcasecmp (family, "new century schoolbook") == 0)
272             lpszFace = "century schoolbook";
273           else if (g_strcasecmp (family, "courier") == 0)
274             lpszFace = "courier new";
275           else if (g_strcasecmp (family, "lucida") == 0)
276             lpszFace = "lucida sans unicode";
277           else if (g_strcasecmp (family, "lucidatypewriter") == 0)
278             lpszFace = "lucida console";
279           else if (g_strcasecmp (family, "times") == 0)
280             lpszFace = "times new roman";
281         }
282       else if (tries == 1)
283         {
284           if (g_strcasecmp (family, "courier") == 0)
285             {
286               lpszFace = "";
287               fdwPitchAndFamily |= FF_MODERN;
288             }
289           else if (g_strcasecmp (family, "times new roman") == 0)
290             {
291               lpszFace = "";
292               fdwPitchAndFamily |= FF_ROMAN;
293             }
294           else if (g_strcasecmp (family, "helvetica") == 0
295                    || g_strcasecmp (family, "lucida") == 0)
296             {
297               lpszFace = "";
298               fdwPitchAndFamily |= FF_SWISS;
299             }
300           else
301             {
302               lpszFace = "";
303               fdwPitchAndFamily = (fdwPitchAndFamily & 0x0F) | FF_DONTCARE;
304             }
305         }
306       else
307         break;
308       tries++;
309     }
310   
311   if (!private->xfont)
312     {
313       g_warning ("gdk_font_load: font %s not found", font_name);
314       g_free (font);
315       return NULL;
316     }
317       
318   private->ref_count = 1;
319   font->type = GDK_FONT_FONT;
320   GetObject (private->xfont, sizeof (logfont), &logfont);
321   oldfont = SelectObject (gdk_DC, private->xfont);
322   GetTextMetrics (gdk_DC, &textmetric);
323   SelectObject (gdk_DC, oldfont);
324   font->ascent = textmetric.tmAscent;
325   font->descent = textmetric.tmDescent;
326
327   GDK_NOTE (MISC, g_print ("gdk_font_load: %s = %#x asc %d desc %d\n",
328                            font_name, private->xfont,
329                            font->ascent, font->descent));
330
331   /* This memory is leaked, so shoot me. */
332   f = g_new (HANDLE, 1);
333   *f = (HANDLE) ((guint) private->xfont + HFONT_DITHER);
334   gdk_xid_table_insert (f, font);
335
336   return font;
337 }
338
339 GdkFont*
340 gdk_fontset_load (gchar *fontset_name)
341 {
342   g_warning ("gdk_fontset_load: Not implemented");
343   return NULL;
344 }
345
346 GdkFont*
347 gdk_font_ref (GdkFont *font)
348 {
349   GdkFontPrivate *private;
350
351   g_return_val_if_fail (font != NULL, NULL);
352
353   private = (GdkFontPrivate*) font;
354   private->ref_count += 1;
355   return font;
356 }
357
358 void
359 gdk_font_unref (GdkFont *font)
360 {
361   GdkFontPrivate *private;
362
363   g_return_if_fail (font != NULL);
364
365   private = (GdkFontPrivate*) font;
366
367   private->ref_count -= 1;
368   if (private->ref_count == 0)
369     {
370       switch (font->type)
371         {
372         case GDK_FONT_FONT:
373           GDK_NOTE (MISC, g_print ("gdk_font_unref %#x\n", private->xfont));
374
375           gdk_xid_table_remove ((HANDLE) ((guint) private->xfont + HFONT_DITHER));
376           DeleteObject (private->xfont);
377           break;
378
379         default:
380           g_assert_not_reached ();
381         }
382       g_free (font);
383     }
384 }
385
386 gint
387 gdk_font_id (const GdkFont *font)
388 {
389   const GdkFontPrivate *font_private;
390
391   g_return_val_if_fail (font != NULL, 0);
392
393   font_private = (const GdkFontPrivate*) font;
394
395   if (font->type == GDK_FONT_FONT)
396     return (gint) font_private->xfont;
397
398   g_assert_not_reached ();
399   return 0;
400 }
401
402 gint
403 gdk_font_equal (const GdkFont *fonta,
404                 const GdkFont *fontb)
405 {
406   const GdkFontPrivate *privatea;
407   const GdkFontPrivate *privateb;
408
409   g_return_val_if_fail (fonta != NULL, FALSE);
410   g_return_val_if_fail (fontb != NULL, FALSE);
411
412   privatea = (const GdkFontPrivate*) fonta;
413   privateb = (const GdkFontPrivate*) fontb;
414
415   if (fonta->type == GDK_FONT_FONT && fontb->type == GDK_FONT_FONT)
416     return (privatea->xfont == privateb->xfont);
417
418   g_assert_not_reached ();
419   return 0;
420 }
421
422 gint
423 gdk_string_width (GdkFont     *font,
424                   const gchar *string)
425 {
426   return gdk_text_width (font, string, strlen (string));
427 }
428
429 gint
430 gdk_text_width (GdkFont      *font,
431                 const gchar  *text,
432                 gint          text_length)
433 {
434   GdkFontPrivate *private;
435   HGDIOBJ oldfont;
436   SIZE size;
437   gint width;
438
439   g_return_val_if_fail (font != NULL, -1);
440   g_return_val_if_fail (text != NULL, -1);
441
442   private = (GdkFontPrivate*) font;
443
444   switch (font->type)
445     {
446     case GDK_FONT_FONT:
447       oldfont = SelectObject (gdk_DC, private->xfont);
448       GetTextExtentPoint32A (gdk_DC, text, text_length, &size);
449       SelectObject (gdk_DC, oldfont);
450       width = size.cx;
451       break;
452
453     default:
454       g_assert_not_reached ();
455     }
456   return width;
457 }
458
459 gint
460 gdk_text_width_wc (GdkFont        *font,
461                    const GdkWChar *text,
462                    gint            text_length)
463 {
464   GdkFontPrivate *private;
465   HGDIOBJ oldfont;
466   SIZE size;
467   wchar_t *wcstr;
468   gint i, width;
469
470   g_return_val_if_fail (font != NULL, -1);
471   g_return_val_if_fail (text != NULL, -1);
472
473   private = (GdkFontPrivate*) font;
474
475   switch (font->type)
476     {
477     case GDK_FONT_FONT:
478       wcstr = g_new (wchar_t, text_length);
479       for (i = 0; i < text_length; i++)
480         wcstr[i] = text[i];
481       oldfont = SelectObject (gdk_DC, private->xfont);
482       GetTextExtentPoint32W (gdk_DC, wcstr, text_length, &size);
483       g_free (wcstr);
484       SelectObject (gdk_DC, oldfont);
485       width = size.cx;
486       break;
487
488     default:
489       width = 0;
490     }
491   return width;
492 }
493
494 gint
495 gdk_char_width (GdkFont *font,
496                 gchar    character)
497 {
498   return gdk_text_width (font, &character, 1);
499 }
500
501 gint
502 gdk_char_width_wc (GdkFont *font,
503                    GdkWChar character)
504 {
505   return gdk_text_width_wc (font, &character, 1);
506 }
507
508 gint
509 gdk_string_measure (GdkFont     *font,
510                     const gchar *string)
511 {
512   g_return_val_if_fail (font != NULL, -1);
513   g_return_val_if_fail (string != NULL, -1);
514
515   return gdk_text_measure (font, string, strlen (string));
516 }
517
518 void
519 gdk_text_extents (GdkFont     *font,
520                   const gchar *text,
521                   gint         text_length,
522                   gint        *lbearing,
523                   gint        *rbearing,
524                   gint        *width,
525                   gint        *ascent,
526                   gint        *descent)
527 {
528   GdkFontPrivate *private;
529   HGDIOBJ oldfont;
530   SIZE size;
531
532   g_return_if_fail (font != NULL);
533   g_return_if_fail (text != NULL);
534
535   private = (GdkFontPrivate*) font;
536
537   switch (font->type)
538     {
539     case GDK_FONT_FONT:
540       oldfont = SelectObject (gdk_DC, private->xfont);
541       GetTextExtentPoint32A (gdk_DC, text, text_length, &size);
542       SelectObject (gdk_DC, oldfont);
543       /* XXX This is all quite bogus */
544       if (lbearing)
545         *lbearing = 0;
546       if (rbearing)
547         *rbearing = 0;
548       if (width)
549         *width = size.cx;
550       if (ascent)
551         *ascent = size.cy + 1;
552       if (descent)
553         *descent = font->descent + 1;
554       break;
555
556     default:
557       g_assert_not_reached ();
558     }
559 }
560
561 void
562 gdk_text_extents_wc (GdkFont        *font,
563                      const GdkWChar *text,
564                      gint            text_length,
565                      gint           *lbearing,
566                      gint           *rbearing,
567                      gint           *width,
568                      gint           *ascent,
569                      gint           *descent)
570 {
571   GdkFontPrivate *private;
572   HGDIOBJ oldfont;
573   SIZE size;
574   wchar_t *wcstr;
575   gint i;
576
577   g_return_if_fail (font != NULL);
578   g_return_if_fail (text != NULL);
579
580   private = (GdkFontPrivate*) font;
581
582   switch (font->type)
583     {
584     case GDK_FONT_FONT:
585       wcstr = g_new (wchar_t, text_length);
586       for (i = 0; i < text_length; i++)
587         wcstr[i] = text[i];
588       oldfont = SelectObject (gdk_DC, private->xfont);
589       GetTextExtentPoint32W (gdk_DC, wcstr, text_length, &size);
590       g_free (wcstr);
591       SelectObject (gdk_DC, oldfont);
592
593       /* XXX This is all quite bogus */
594       if (lbearing)
595         *lbearing = 0;
596       if (rbearing)
597         *rbearing = 0;
598       if (width)
599         *width = size.cx;
600       if (ascent)
601         *ascent = size.cy + 1;
602       if (descent)
603         *descent = font->descent + 1;
604       break;
605
606     default:
607       g_assert_not_reached ();
608     }
609 }
610
611 void
612 gdk_string_extents (GdkFont     *font,
613                     const gchar *string,
614                     gint        *lbearing,
615                     gint        *rbearing,
616                     gint        *width,
617                     gint        *ascent,
618                     gint        *descent)
619 {
620   g_return_if_fail (font != NULL);
621   g_return_if_fail (string != NULL);
622
623   gdk_text_extents (font, string, strlen (string),
624                     lbearing, rbearing, width, ascent, descent);
625 }
626
627
628 gint
629 gdk_text_measure (GdkFont     *font,
630                   const gchar *text,
631                   gint         text_length)
632 {
633   GdkFontPrivate *private;
634   gint width;
635
636   g_return_val_if_fail (font != NULL, -1);
637   g_return_val_if_fail (text != NULL, -1);
638
639   private = (GdkFontPrivate*) font;
640
641   switch (font->type)
642     {
643     case GDK_FONT_FONT:
644       return gdk_text_width (font, text, text_length); /* ??? */
645       break;
646
647     default:
648       g_assert_not_reached ();
649     }
650   return 0;
651 }
652
653 gint
654 gdk_char_measure (GdkFont *font,
655                   gchar    character)
656 {
657   g_return_val_if_fail (font != NULL, -1);
658
659   return gdk_text_measure (font, &character, 1);
660 }
661
662 gint
663 gdk_string_height (GdkFont     *font,
664                    const gchar *string)
665 {
666   g_return_val_if_fail (font != NULL, -1);
667   g_return_val_if_fail (string != NULL, -1);
668
669   return gdk_text_height (font, string, strlen (string));
670 }
671
672 gint
673 gdk_text_height (GdkFont     *font,
674                  const gchar *text,
675                  gint         text_length)
676 {
677   GdkFontPrivate *private;
678   HGDIOBJ oldfont;
679   SIZE size;
680   gint height;
681
682   g_return_val_if_fail (font != NULL, -1);
683   g_return_val_if_fail (text != NULL, -1);
684
685   private = (GdkFontPrivate*) font;
686
687   switch (font->type)
688     {
689     case GDK_FONT_FONT:
690       oldfont = SelectObject (gdk_DC, private->xfont);
691       GetTextExtentPoint32 (gdk_DC, text, text_length, &size);
692       SelectObject (gdk_DC, oldfont);
693       height = size.cy;
694       break;
695
696     default:
697       g_error ("font->type = %d", font->type);
698     }
699   return height;
700 }
701
702 gint
703 gdk_char_height (GdkFont *font,
704                  gchar    character)
705 {
706   g_return_val_if_fail (font != NULL, -1);
707
708   return gdk_text_height (font, &character, 1);
709 }