]> Pileus Git - ~andy/gtk/blob - gdk/win32/gdkfont.c
38b8523383d813aa235ecebb0d2721b96f7c2770
[~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 <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       else if (g_strcasecmp (weight, "ultralight") == 0)
156         fnWeight = FW_ULTRALIGHT;
157       else if (g_strcasecmp (weight, "light") == 0)
158         fnWeight = FW_LIGHT;
159       else if (g_strcasecmp (weight, "normal") == 0)
160         fnWeight = FW_NORMAL;
161       else if (g_strcasecmp (weight, "regular") == 0)
162         fnWeight = FW_REGULAR;
163       else if (g_strcasecmp (weight, "medium") == 0)
164         fnWeight = FW_MEDIUM;
165       else if (g_strcasecmp (weight, "semibold") == 0)
166         fnWeight = FW_SEMIBOLD;
167       else if (g_strcasecmp (weight, "demibold") == 0)
168         fnWeight = FW_DEMIBOLD;
169       else if (g_strcasecmp (weight, "bold") == 0)
170         fnWeight = FW_BOLD;
171       else if (g_strcasecmp (weight, "extrabold") == 0)
172         fnWeight = FW_EXTRABOLD;
173       else if (g_strcasecmp (weight, "ultrabold") == 0)
174         fnWeight = FW_ULTRABOLD;
175       else if (g_strcasecmp (weight, "heavy") == 0)
176         fnWeight = FW_HEAVY;
177       else if (g_strcasecmp (weight, "black") == 0)
178         fnWeight = FW_BLACK;
179       else
180         fnWeight = FW_DONTCARE;
181
182       if (g_strcasecmp (slant, "italic") == 0
183           || g_strcasecmp (slant, "oblique") == 0
184           || g_strcasecmp (slant, "i") == 0
185           || g_strcasecmp (slant, "o") == 0)
186         fdwItalic = TRUE;
187       else
188         fdwItalic = FALSE;
189       fdwUnderline = FALSE;
190       fdwStrikeOut = FALSE;
191       if (g_strcasecmp (registry, "iso8859") == 0)
192         if (strcmp (encoding, "1") == 0)
193           fdwCharSet = ANSI_CHARSET;
194         else
195           fdwCharSet = ANSI_CHARSET; /* XXX ??? */
196       else if (g_strcasecmp (registry, "windows") == 0)
197         if (g_strcasecmp (encoding, "symbol") == 0)
198           fdwCharSet = SYMBOL_CHARSET;
199         else if (g_strcasecmp (encoding, "shiftjis") == 0)
200           fdwCharSet = SHIFTJIS_CHARSET;
201         else if (g_strcasecmp (encoding, "gb2312") == 0)
202           fdwCharSet = GB2312_CHARSET;
203         else if (g_strcasecmp (encoding, "hangeul") == 0)
204           fdwCharSet = HANGEUL_CHARSET;
205         else if (g_strcasecmp (encoding, "chinesebig5") == 0)
206           fdwCharSet = CHINESEBIG5_CHARSET;
207         else if (g_strcasecmp (encoding, "johab") == 0)
208           fdwCharSet = JOHAB_CHARSET;
209         else if (g_strcasecmp (encoding, "hebrew") == 0)
210           fdwCharSet = HEBREW_CHARSET;
211         else if (g_strcasecmp (encoding, "arabic") == 0)
212           fdwCharSet = ARABIC_CHARSET;
213         else if (g_strcasecmp (encoding, "greek") == 0)
214           fdwCharSet = GREEK_CHARSET;
215         else if (g_strcasecmp (encoding, "turkish") == 0)
216           fdwCharSet = TURKISH_CHARSET;
217         else if (g_strcasecmp (encoding, "easteurope") == 0)
218           fdwCharSet = EASTEUROPE_CHARSET;
219         else if (g_strcasecmp (encoding, "russian") == 0)
220           fdwCharSet = RUSSIAN_CHARSET;
221         else if (g_strcasecmp (encoding, "mac") == 0)
222           fdwCharSet = MAC_CHARSET;
223         else if (g_strcasecmp (encoding, "baltic") == 0)
224           fdwCharSet = BALTIC_CHARSET;
225         else
226           fdwCharSet = ANSI_CHARSET; /* XXX ??? */
227       else
228         fdwCharSet = ANSI_CHARSET; /* XXX ??? */
229       fdwOutputPrecision = OUT_TT_PRECIS;
230       fdwClipPrecision = CLIP_DEFAULT_PRECIS;
231       fdwQuality = PROOF_QUALITY;
232       if (g_strcasecmp (spacing, "m") == 0)
233         fdwPitchAndFamily = FIXED_PITCH;
234       else if (g_strcasecmp (spacing, "p") == 0)
235         fdwPitchAndFamily = VARIABLE_PITCH;
236       else 
237         fdwPitchAndFamily = DEFAULT_PITCH;
238       lpszFace = family;
239     }
240
241   for (tries = 0; ; tries++)
242     {
243       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",
244                                nHeight, nWidth, nEscapement, nOrientation,
245                                fnWeight, fdwItalic, fdwUnderline, fdwStrikeOut,
246                                fdwCharSet, fdwOutputPrecision, fdwClipPrecision,
247                                fdwQuality, fdwPitchAndFamily, lpszFace));
248       if ((private->xfont =
249            CreateFont (nHeight, nWidth, nEscapement, nOrientation,
250                        fnWeight, fdwItalic, fdwUnderline, fdwStrikeOut,
251                        fdwCharSet, fdwOutputPrecision, fdwClipPrecision,
252                        fdwQuality, fdwPitchAndFamily, lpszFace)) != NULL)
253         break;
254
255       /* If we fail, try some similar fonts often found on Windows. */
256
257       if (tries == 0)
258         {
259           if (g_strcasecmp (family, "helvetica") == 0)
260             lpszFace = "arial";
261           else if (g_strcasecmp (family, "new century schoolbook") == 0)
262             lpszFace = "century schoolbook";
263           else if (g_strcasecmp (family, "courier") == 0)
264             lpszFace = "courier new";
265           else if (g_strcasecmp (family, "lucida") == 0)
266             lpszFace = "lucida sans unicode";
267           else if (g_strcasecmp (family, "lucidatypewriter") == 0)
268             lpszFace = "lucida console";
269           else if (g_strcasecmp (family, "times") == 0)
270             lpszFace = "times new roman";
271         }
272       else if (tries == 1)
273         {
274           if (g_strcasecmp (family, "courier") == 0)
275             {
276               lpszFace = "";
277               fdwPitchAndFamily |= FF_MODERN;
278             }
279           else if (g_strcasecmp (family, "times new roman") == 0)
280             {
281               lpszFace = "";
282               fdwPitchAndFamily |= FF_ROMAN;
283             }
284           else if (g_strcasecmp (family, "helvetica") == 0
285                    || g_strcasecmp (family, "lucida") == 0)
286             {
287               lpszFace = "";
288               fdwPitchAndFamily |= FF_SWISS;
289             }
290           else
291             {
292               lpszFace = "";
293               fdwPitchAndFamily = (fdwPitchAndFamily & 0x0F) | FF_DONTCARE;
294             }
295         }
296       else
297         break;
298       tries++;
299     }
300   
301   if (!private->xfont)
302     {
303       g_warning ("gdk_font_load: font %s not found", font_name);
304       g_free (font);
305       return NULL;
306     }
307       
308   private->ref_count = 1;
309   font->type = GDK_FONT_FONT;
310   GetObject (private->xfont, sizeof (logfont), &logfont);
311   oldfont = SelectObject (gdk_DC, private->xfont);
312   GetTextMetrics (gdk_DC, &textmetric);
313   SelectObject (gdk_DC, oldfont);
314   font->ascent = textmetric.tmAscent;
315   font->descent = textmetric.tmDescent;
316
317   GDK_NOTE (MISC, g_print ("gdk_font_load: %s = %#x asc %d desc %d\n",
318                            font_name, private->xfont,
319                            font->ascent, font->descent));
320
321   /* This memory is leaked, so shoot me. */
322   f = g_new (HANDLE, 1);
323   *f = (HANDLE) ((guint) private->xfont + HFONT_DITHER);
324   gdk_xid_table_insert (f, font);
325
326   return font;
327 }
328
329 GdkFont*
330 gdk_fontset_load (gchar *fontset_name)
331 {
332   g_warning ("gdk_fontset_load: Not implemented");
333   return NULL;
334 }
335
336 GdkFont*
337 gdk_font_ref (GdkFont *font)
338 {
339   GdkFontPrivate *private;
340
341   g_return_val_if_fail (font != NULL, NULL);
342
343   private = (GdkFontPrivate*) font;
344   private->ref_count += 1;
345   return font;
346 }
347
348 void
349 gdk_font_unref (GdkFont *font)
350 {
351   GdkFontPrivate *private;
352
353   g_return_if_fail (font != NULL);
354
355   private = (GdkFontPrivate*) font;
356
357   private->ref_count -= 1;
358   if (private->ref_count == 0)
359     {
360       switch (font->type)
361         {
362         case GDK_FONT_FONT:
363           GDK_NOTE (MISC, g_print ("gdk_font_unref %#x\n", private->xfont));
364
365           gdk_xid_table_remove ((HANDLE) ((guint) private->xfont + HFONT_DITHER));
366           DeleteObject (private->xfont);
367           break;
368
369         default:
370           g_assert_not_reached ();
371         }
372       g_free (font);
373     }
374 }
375
376 gint
377 gdk_font_id (const GdkFont *font)
378 {
379   const GdkFontPrivate *font_private;
380
381   g_return_val_if_fail (font != NULL, 0);
382
383   font_private = (const GdkFontPrivate*) font;
384
385   if (font->type == GDK_FONT_FONT)
386     return (gint) font_private->xfont;
387
388   g_assert_not_reached ();
389   return 0;
390 }
391
392 gint
393 gdk_font_equal (const GdkFont *fonta,
394                 const GdkFont *fontb)
395 {
396   const GdkFontPrivate *privatea;
397   const GdkFontPrivate *privateb;
398
399   g_return_val_if_fail (fonta != NULL, FALSE);
400   g_return_val_if_fail (fontb != NULL, FALSE);
401
402   privatea = (const GdkFontPrivate*) fonta;
403   privateb = (const GdkFontPrivate*) fontb;
404
405   if (fonta->type == GDK_FONT_FONT && fontb->type == GDK_FONT_FONT)
406     return (privatea->xfont == privateb->xfont);
407
408   g_assert_not_reached ();
409   return 0;
410 }
411
412 gint
413 gdk_string_width (GdkFont     *font,
414                   const gchar *string)
415 {
416   return gdk_text_width (font, string, strlen (string));
417 }
418
419 gint
420 gdk_text_width (GdkFont      *font,
421                 const gchar  *text,
422                 gint          text_length)
423 {
424   GdkFontPrivate *private;
425   HGDIOBJ oldfont;
426   SIZE size;
427   gint width;
428
429   g_return_val_if_fail (font != NULL, -1);
430   g_return_val_if_fail (text != NULL, -1);
431
432   private = (GdkFontPrivate*) font;
433
434   switch (font->type)
435     {
436     case GDK_FONT_FONT:
437       oldfont = SelectObject (gdk_DC, private->xfont);
438       GetTextExtentPoint32A (gdk_DC, text, text_length, &size);
439       SelectObject (gdk_DC, oldfont);
440       width = size.cx;
441       break;
442
443     default:
444       g_assert_not_reached ();
445     }
446   return width;
447 }
448
449 gint
450 gdk_text_width_wc (GdkFont        *font,
451                    const GdkWChar *text,
452                    gint            text_length)
453 {
454   GdkFontPrivate *private;
455   HGDIOBJ oldfont;
456   SIZE size;
457   wchar_t *wcstr;
458   gint i, width;
459
460   g_return_val_if_fail (font != NULL, -1);
461   g_return_val_if_fail (text != NULL, -1);
462
463   private = (GdkFontPrivate*) font;
464
465   switch (font->type)
466     {
467     case GDK_FONT_FONT:
468       wcstr = g_new (wchar_t, text_length);
469       for (i = 0; i < text_length; i++)
470         wcstr[i] = text[i];
471       oldfont = SelectObject (gdk_DC, private->xfont);
472       GetTextExtentPoint32W (gdk_DC, wcstr, text_length, &size);
473       g_free (wcstr);
474       SelectObject (gdk_DC, oldfont);
475       width = size.cx;
476       break;
477
478     default:
479       width = 0;
480     }
481   return width;
482 }
483
484 gint
485 gdk_char_width (GdkFont *font,
486                 gchar    character)
487 {
488   return gdk_text_width (font, &character, 1);
489 }
490
491 gint
492 gdk_char_width_wc (GdkFont *font,
493                    GdkWChar character)
494 {
495   return gdk_text_width_wc (font, &character, 1);
496 }
497
498 gint
499 gdk_string_measure (GdkFont     *font,
500                     const gchar *string)
501 {
502   g_return_val_if_fail (font != NULL, -1);
503   g_return_val_if_fail (string != NULL, -1);
504
505   return gdk_text_measure (font, string, strlen (string));
506 }
507
508 void
509 gdk_text_extents (GdkFont     *font,
510                   const gchar *text,
511                   gint         text_length,
512                   gint        *lbearing,
513                   gint        *rbearing,
514                   gint        *width,
515                   gint        *ascent,
516                   gint        *descent)
517 {
518   GdkFontPrivate *private;
519   HGDIOBJ oldfont;
520   SIZE size;
521
522   g_return_if_fail (font != NULL);
523   g_return_if_fail (text != NULL);
524
525   private = (GdkFontPrivate*) font;
526
527   switch (font->type)
528     {
529     case GDK_FONT_FONT:
530       oldfont = SelectObject (gdk_DC, private->xfont);
531       GetTextExtentPoint32A (gdk_DC, text, text_length, &size);
532       SelectObject (gdk_DC, oldfont);
533       /* XXX This is all quite bogus */
534       if (lbearing)
535         *lbearing = 0;
536       if (rbearing)
537         *rbearing = 0;
538       if (width)
539         *width = size.cx;
540       if (ascent)
541         *ascent = size.cy + 1;
542       if (descent)
543         *descent = font->descent + 1;
544       break;
545
546     default:
547       g_assert_not_reached ();
548     }
549 }
550
551 void
552 gdk_text_extents_wc (GdkFont        *font,
553                      const GdkWChar *text,
554                      gint            text_length,
555                      gint           *lbearing,
556                      gint           *rbearing,
557                      gint           *width,
558                      gint           *ascent,
559                      gint           *descent)
560 {
561   GdkFontPrivate *private;
562   HGDIOBJ oldfont;
563   SIZE size;
564   wchar_t *wcstr;
565   gint i;
566
567   g_return_if_fail (font != NULL);
568   g_return_if_fail (text != NULL);
569
570   private = (GdkFontPrivate*) font;
571
572   switch (font->type)
573     {
574     case GDK_FONT_FONT:
575       wcstr = g_new (wchar_t, text_length);
576       for (i = 0; i < text_length; i++)
577         wcstr[i] = text[i];
578       oldfont = SelectObject (gdk_DC, private->xfont);
579       GetTextExtentPoint32W (gdk_DC, wcstr, text_length, &size);
580       g_free (wcstr);
581       SelectObject (gdk_DC, oldfont);
582
583       /* XXX This is all quite bogus */
584       if (lbearing)
585         *lbearing = 0;
586       if (rbearing)
587         *rbearing = 0;
588       if (width)
589         *width = size.cx;
590       if (ascent)
591         *ascent = size.cy + 1;
592       if (descent)
593         *descent = font->descent + 1;
594       break;
595
596     default:
597       g_assert_not_reached ();
598     }
599 }
600
601 void
602 gdk_string_extents (GdkFont     *font,
603                     const gchar *string,
604                     gint        *lbearing,
605                     gint        *rbearing,
606                     gint        *width,
607                     gint        *ascent,
608                     gint        *descent)
609 {
610   g_return_if_fail (font != NULL);
611   g_return_if_fail (string != NULL);
612
613   gdk_text_extents (font, string, strlen (string),
614                     lbearing, rbearing, width, ascent, descent);
615 }
616
617
618 gint
619 gdk_text_measure (GdkFont     *font,
620                   const gchar *text,
621                   gint         text_length)
622 {
623   GdkFontPrivate *private;
624   gint width;
625
626   g_return_val_if_fail (font != NULL, -1);
627   g_return_val_if_fail (text != NULL, -1);
628
629   private = (GdkFontPrivate*) font;
630
631   switch (font->type)
632     {
633     case GDK_FONT_FONT:
634       return gdk_text_width (font, text, text_length); /* ??? */
635       break;
636
637     default:
638       g_assert_not_reached ();
639     }
640   return 0;
641 }
642
643 gint
644 gdk_char_measure (GdkFont *font,
645                   gchar    character)
646 {
647   g_return_val_if_fail (font != NULL, -1);
648
649   return gdk_text_measure (font, &character, 1);
650 }
651
652 gint
653 gdk_string_height (GdkFont     *font,
654                    const gchar *string)
655 {
656   g_return_val_if_fail (font != NULL, -1);
657   g_return_val_if_fail (string != NULL, -1);
658
659   return gdk_text_height (font, string, strlen (string));
660 }
661
662 gint
663 gdk_text_height (GdkFont     *font,
664                  const gchar *text,
665                  gint         text_length)
666 {
667   GdkFontPrivate *private;
668   HGDIOBJ oldfont;
669   SIZE size;
670   gint height;
671
672   g_return_val_if_fail (font != NULL, -1);
673   g_return_val_if_fail (text != NULL, -1);
674
675   private = (GdkFontPrivate*) font;
676
677   switch (font->type)
678     {
679     case GDK_FONT_FONT:
680       oldfont = SelectObject (gdk_DC, private->xfont);
681       GetTextExtentPoint32 (gdk_DC, text, text_length, &size);
682       SelectObject (gdk_DC, oldfont);
683       height = size.cy;
684       break;
685
686     default:
687       g_error ("font->type = %d", font->type);
688     }
689   return height;
690 }
691
692 gint
693 gdk_char_height (GdkFont *font,
694                  gchar    character)
695 {
696   g_return_val_if_fail (font != NULL, -1);
697
698   return gdk_text_height (font, &character, 1);
699 }