]> Pileus Git - ~andy/gtk/blob - gdk/gdkfont.c
d1f779a06424a3933e31389527d01c5f1baa4fa0
[~andy/gtk] / gdk / 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 <X11/Xlib.h>
28 #include <X11/Xos.h>
29 #include "gdk.h"
30 #include "gdkprivate.h"
31
32 GdkFont*
33 gdk_font_load (const gchar *font_name)
34 {
35   GdkFont *font;
36   GdkFontPrivate *private;
37   XFontStruct *xfont;
38
39   g_return_val_if_fail (font_name != NULL, NULL);
40
41   xfont = XLoadQueryFont (gdk_display, font_name);
42   if (xfont == NULL)
43     return NULL;
44
45   font = gdk_font_lookup (xfont->fid);
46   if (font != NULL)
47     {
48       private = (GdkFontPrivate *) font;
49       if (xfont != private->xfont)
50         XFreeFont (gdk_display, xfont);
51
52       gdk_font_ref (font);
53     }
54   else
55     {
56       private = g_new (GdkFontPrivate, 1);
57       private->xdisplay = gdk_display;
58       private->xfont = xfont;
59       private->ref_count = 1;
60
61       font = (GdkFont*) private;
62       font->type = GDK_FONT_FONT;
63       font->ascent =  xfont->ascent;
64       font->descent = xfont->descent;
65
66       gdk_xid_table_insert (&xfont->fid, font);
67     }
68
69   return font;
70 }
71
72 GdkFont*
73 gdk_fontset_load (gchar *fontset_name)
74 {
75   GdkFont *font;
76   GdkFontPrivate *private;
77   XFontSet fontset;
78   gint  missing_charset_count;
79   gchar **missing_charset_list;
80   gchar *def_string;
81
82   private = g_new (GdkFontPrivate, 1);
83   font = (GdkFont*) private;
84
85   private->xdisplay = gdk_display;
86   fontset = XCreateFontSet (gdk_display, fontset_name,
87                             &missing_charset_list, &missing_charset_count,
88                             &def_string);
89
90   if (missing_charset_count)
91     {
92       gint i;
93       g_warning ("Missing charsets in FontSet creation\n");
94       for (i=0;i<missing_charset_count;i++)
95         g_warning ("    %s\n", missing_charset_list[i]);
96       XFreeStringList (missing_charset_list);
97     }
98
99   private->ref_count = 1;
100
101   if (!fontset)
102     {
103       g_free (font);
104       return NULL;
105     }
106   else
107     {
108       gint num_fonts;
109       gint i;
110       XFontStruct **font_structs;
111       gchar **font_names;
112       
113       private->xfont = fontset;
114       font->type = GDK_FONT_FONTSET;
115       num_fonts = XFontsOfFontSet (fontset, &font_structs, &font_names);
116
117       font->ascent = font->descent = 0;
118       
119       for (i = 0; i < num_fonts; i++)
120         {
121           font->ascent = MAX (font->ascent, font_structs[i]->ascent);
122           font->descent = MAX (font->descent, font_structs[i]->descent);
123         }
124     }
125   return font;
126 }
127
128 GdkFont*
129 gdk_font_ref (GdkFont *font)
130 {
131   GdkFontPrivate *private;
132
133   g_return_val_if_fail (font != NULL, NULL);
134
135   private = (GdkFontPrivate*) font;
136   private->ref_count += 1;
137   return font;
138 }
139
140 void
141 gdk_font_unref (GdkFont *font)
142 {
143   GdkFontPrivate *private;
144
145   g_return_if_fail (font != NULL);
146
147   private = (GdkFontPrivate*) font;
148
149   private->ref_count -= 1;
150   if (private->ref_count == 0)
151     {
152       switch (font->type)
153         {
154         case GDK_FONT_FONT:
155           gdk_xid_table_remove (((XFontStruct *) private->xfont)->fid);
156           XFreeFont (private->xdisplay, (XFontStruct *) private->xfont);
157           break;
158         case GDK_FONT_FONTSET:
159           XFreeFontSet (private->xdisplay, (XFontSet) private->xfont);
160           break;
161         default:
162           g_error ("unknown font type.");
163           break;
164         }
165       g_free (font);
166     }
167 }
168
169 gint
170 gdk_font_id (const GdkFont *font)
171 {
172   const GdkFontPrivate *font_private;
173
174   g_return_val_if_fail (font != NULL, 0);
175
176   font_private = (const GdkFontPrivate*) font;
177
178   if (font->type == GDK_FONT_FONT)
179     {
180       return ((XFontStruct *) font_private->xfont)->fid;
181     }
182   else
183     {
184       return 0;
185     }
186 }
187
188 gint
189 gdk_font_equal (const GdkFont *fonta,
190                 const GdkFont *fontb)
191 {
192   const GdkFontPrivate *privatea;
193   const GdkFontPrivate *privateb;
194
195   g_return_val_if_fail (fonta != NULL, FALSE);
196   g_return_val_if_fail (fontb != NULL, FALSE);
197
198   privatea = (const GdkFontPrivate*) fonta;
199   privateb = (const GdkFontPrivate*) fontb;
200
201   if (fonta->type == GDK_FONT_FONT && fontb->type == GDK_FONT_FONT)
202     {
203       return (((XFontStruct *) privatea->xfont)->fid ==
204               ((XFontStruct *) privateb->xfont)->fid);
205     }
206   else if (fonta->type == GDK_FONT_FONTSET && fontb->type == GDK_FONT_FONTSET)
207     {
208       /* how to compare two fontsets ?? by basename or XFontSet ?? */
209       return (((XFontSet) privatea->xfont) == ((XFontSet) privateb->xfont));
210     }
211   else
212     /* fontset != font */
213     return 0;
214 }
215
216 gint
217 gdk_string_width (GdkFont     *font,
218                   const gchar *string)
219 {
220   GdkFontPrivate *font_private;
221   gint width;
222   XFontStruct *xfont;
223   XFontSet fontset;
224
225   g_return_val_if_fail (font != NULL, -1);
226   g_return_val_if_fail (string != NULL, -1);
227
228   font_private = (GdkFontPrivate*) font;
229
230   switch (font->type)
231     {
232     case GDK_FONT_FONT:
233       xfont = (XFontStruct *) font_private->xfont;
234       if ((xfont->min_byte1 == 0) && (xfont->max_byte1 == 0))
235         {
236           width = XTextWidth (xfont, string, strlen (string));
237         }
238       else
239         {
240           width = XTextWidth16 (xfont, (XChar2b *) string, strlen (string) / 2);
241         }
242       break;
243     case GDK_FONT_FONTSET:
244       fontset = (XFontSet) font_private->xfont;
245       width = XmbTextEscapement (fontset, string, strlen(string));
246       break;
247     default:
248       width = 0;
249     }
250
251   return width;
252 }
253
254 gint
255 gdk_text_width (GdkFont      *font,
256                 const gchar  *text,
257                 gint          text_length)
258 {
259   GdkFontPrivate *private;
260   gint width;
261   XFontStruct *xfont;
262   XFontSet fontset;
263
264   g_return_val_if_fail (font != NULL, -1);
265   g_return_val_if_fail (text != NULL, -1);
266
267   private = (GdkFontPrivate*) font;
268
269   switch (font->type)
270     {
271     case GDK_FONT_FONT:
272       xfont = (XFontStruct *) private->xfont;
273       if ((xfont->min_byte1 == 0) && (xfont->max_byte1 == 0))
274         {
275           width = XTextWidth (xfont, text, text_length);
276         }
277       else
278         {
279           width = XTextWidth16 (xfont, (XChar2b *) text, text_length / 2);
280         }
281       break;
282     case GDK_FONT_FONTSET:
283       fontset = (XFontSet) private->xfont;
284       width = XmbTextEscapement (fontset, text, text_length);
285       break;
286     default:
287       width = 0;
288     }
289   return width;
290 }
291
292 gint
293 gdk_text_width_wc (GdkFont        *font,
294                    const GdkWChar *text,
295                    gint            text_length)
296 {
297   GdkFontPrivate *private;
298   gint width;
299   XFontStruct *xfont;
300   XFontSet fontset;
301
302   g_return_val_if_fail (font != NULL, -1);
303   g_return_val_if_fail (text != NULL, -1);
304
305   private = (GdkFontPrivate*) font;
306
307   switch (font->type)
308     {
309     case GDK_FONT_FONT:
310       xfont = (XFontStruct *) private->xfont;
311       if ((xfont->min_byte1 == 0) && (xfont->max_byte1 == 0))
312         {
313           gchar *text_8bit;
314           gint i;
315           text_8bit = g_new (gchar, text_length);
316           for (i=0; i<text_length; i++) text_8bit[i] = text[i];
317           width = XTextWidth (xfont, text_8bit, text_length);
318           g_free (text_8bit);
319         }
320       else
321         {
322           width = 0;
323         }
324       break;
325     case GDK_FONT_FONTSET:
326       if (sizeof(GdkWChar) == sizeof(wchar_t))
327         {
328           fontset = (XFontSet) private->xfont;
329           width = XwcTextEscapement (fontset, (wchar_t *)text, text_length);
330         }
331       else
332         {
333           wchar_t *text_wchar;
334           gint i;
335           fontset = (XFontSet) private->xfont;
336           text_wchar = g_new(wchar_t, text_length);
337           for (i=0; i<text_length; i++) text_wchar[i] = text[i];
338           width = XwcTextEscapement (fontset, text_wchar, text_length);
339           g_free (text_wchar);
340         }
341       break;
342     default:
343       width = 0;
344     }
345   return width;
346 }
347
348 /* Problem: What if a character is a 16 bits character ?? */
349 gint
350 gdk_char_width (GdkFont *font,
351                 gchar    character)
352 {
353   GdkFontPrivate *private;
354   XCharStruct *chars;
355   gint width;
356   guint ch = character & 0xff;  /* get rid of sign-extension */
357   XFontStruct *xfont;
358   XFontSet fontset;
359
360   g_return_val_if_fail (font != NULL, -1);
361
362   private = (GdkFontPrivate*) font;
363
364   switch (font->type)
365     {
366     case GDK_FONT_FONT:
367       /* only 8 bits characters are considered here */
368       xfont = (XFontStruct *) private->xfont;
369       if ((xfont->min_byte1 == 0) &&
370           (xfont->max_byte1 == 0) &&
371           (ch >= xfont->min_char_or_byte2) &&
372           (ch <= xfont->max_char_or_byte2))
373         {
374           chars = xfont->per_char;
375           if (chars)
376             width = chars[ch - xfont->min_char_or_byte2].width;
377           else
378             width = xfont->min_bounds.width;
379         }
380       else
381         {
382           width = XTextWidth (xfont, &character, 1);
383         }
384       break;
385     case GDK_FONT_FONTSET:
386       fontset = (XFontSet) private->xfont;
387       width = XmbTextEscapement (fontset, &character, 1) ;
388       break;
389     default:
390       width = 0;
391     }
392   return width;
393 }
394
395 gint
396 gdk_char_width_wc (GdkFont *font,
397                    GdkWChar character)
398 {
399   GdkFontPrivate *private;
400   XCharStruct *chars;
401   gint width;
402   guint ch = character & 0xff;  /* get rid of sign-extension */
403   XFontStruct *xfont;
404   XFontSet fontset;
405
406   g_return_val_if_fail (font != NULL, -1);
407
408   private = (GdkFontPrivate*) font;
409
410   switch (font->type)
411     {
412     case GDK_FONT_FONT:
413       /* only 8 bits characters are considered here */
414       xfont = (XFontStruct *) private->xfont;
415       if ((xfont->min_byte1 == 0) &&
416           (xfont->max_byte1 == 0) &&
417           (ch >= xfont->min_char_or_byte2) &&
418           (ch <= xfont->max_char_or_byte2))
419         {
420           chars = xfont->per_char;
421           if (chars)
422             width = chars[ch - xfont->min_char_or_byte2].width;
423           else
424             width = xfont->min_bounds.width;
425         }
426       else
427         {
428           char ch2 = character;
429           width = XTextWidth (xfont, &ch2, 1);
430         }
431       break;
432     case GDK_FONT_FONTSET:
433       fontset = (XFontSet) private->xfont;
434       {
435         wchar_t char_wc = character;
436         width = XwcTextEscapement (fontset, &char_wc, 1) ;
437       }
438       break;
439     default:
440       width = 0;
441     }
442   return width;
443 }
444
445 gint
446 gdk_string_measure (GdkFont     *font,
447                     const gchar *string)
448 {
449   g_return_val_if_fail (font != NULL, -1);
450   g_return_val_if_fail (string != NULL, -1);
451
452   return gdk_text_measure (font, string, strlen (string));
453 }
454
455 void
456 gdk_text_extents (GdkFont     *font,
457                   const gchar *text,
458                   gint         text_length,
459                   gint        *lbearing,
460                   gint        *rbearing,
461                   gint        *width,
462                   gint        *ascent,
463                   gint        *descent)
464 {
465   GdkFontPrivate *private;
466   XCharStruct overall;
467   XFontStruct *xfont;
468   XFontSet    fontset;
469   XRectangle  ink, logical;
470   int direction;
471   int font_ascent;
472   int font_descent;
473
474   g_return_if_fail (font != NULL);
475   g_return_if_fail (text != NULL);
476
477   private = (GdkFontPrivate*) font;
478
479   switch (font->type)
480     {
481     case GDK_FONT_FONT:
482       xfont = (XFontStruct *) private->xfont;
483       if ((xfont->min_byte1 == 0) && (xfont->max_byte1 == 0))
484         {
485           XTextExtents (xfont, text, text_length,
486                         &direction, &font_ascent, &font_descent,
487                         &overall);
488         }
489       else
490         {
491           XTextExtents16 (xfont, (XChar2b *) text, text_length / 2,
492                           &direction, &font_ascent, &font_descent,
493                           &overall);
494         }
495       if (lbearing)
496         *lbearing = overall.lbearing;
497       if (rbearing)
498         *rbearing = overall.rbearing;
499       if (width)
500         *width = overall.width;
501       if (ascent)
502         *ascent = overall.ascent;
503       if (descent)
504         *descent = overall.descent;
505       break;
506     case GDK_FONT_FONTSET:
507       fontset = (XFontSet) private->xfont;
508       XmbTextExtents (fontset, text, text_length, &ink, &logical);
509       if (lbearing)
510         *lbearing = ink.x;
511       if (rbearing)
512         *rbearing = ink.x + ink.width;
513       if (width)
514         *width = logical.width;
515       if (ascent)
516         *ascent = -ink.y;
517       if (descent)
518         *descent = ink.y + ink.height;
519       break;
520     }
521
522 }
523
524 void
525 gdk_text_extents_wc (GdkFont        *font,
526                      const GdkWChar *text,
527                      gint            text_length,
528                      gint           *lbearing,
529                      gint           *rbearing,
530                      gint           *width,
531                      gint           *ascent,
532                      gint           *descent)
533 {
534   GdkFontPrivate *private;
535   XCharStruct overall;
536   XFontStruct *xfont;
537   XFontSet    fontset;
538   XRectangle  ink, logical;
539   int direction;
540   int font_ascent;
541   int font_descent;
542
543   g_return_if_fail (font != NULL);
544   g_return_if_fail (text != NULL);
545
546   private = (GdkFontPrivate*) font;
547
548   switch (font->type)
549     {
550     case GDK_FONT_FONT:
551       {
552         gchar *text_8bit;
553         gint i;
554
555         xfont = (XFontStruct *) private->xfont;
556         g_return_if_fail ((xfont->min_byte1 == 0) && (xfont->max_byte1 == 0));
557
558         text_8bit = g_new (gchar, text_length);
559         for (i=0; i<text_length; i++) 
560           text_8bit[i] = text[i];
561
562         XTextExtents (xfont, text_8bit, text_length,
563                       &direction, &font_ascent, &font_descent,
564                       &overall);
565         g_free (text_8bit);
566         
567         if (lbearing)
568           *lbearing = overall.lbearing;
569         if (rbearing)
570           *rbearing = overall.rbearing;
571         if (width)
572           *width = overall.width;
573         if (ascent)
574           *ascent = overall.ascent;
575         if (descent)
576           *descent = overall.descent;
577         break;
578       }
579     case GDK_FONT_FONTSET:
580       fontset = (XFontSet) private->xfont;
581       XwcTextExtents (fontset, text, text_length, &ink, &logical);
582       if (lbearing)
583         *lbearing = ink.x;
584       if (rbearing)
585         *rbearing = ink.x + ink.width;
586       if (width)
587         *width = logical.width;
588       if (ascent)
589         *ascent = -ink.y;
590       if (descent)
591         *descent = ink.y + ink.height;
592       break;
593     }
594
595 }
596
597 void
598 gdk_string_extents (GdkFont     *font,
599                     const gchar *string,
600                     gint        *lbearing,
601                     gint        *rbearing,
602                     gint        *width,
603                     gint        *ascent,
604                     gint        *descent)
605 {
606   g_return_if_fail (font != NULL);
607   g_return_if_fail (string != NULL);
608
609   gdk_text_extents (font, string, strlen (string),
610                     lbearing, rbearing, width, ascent, descent);
611 }
612
613
614 gint
615 gdk_text_measure (GdkFont     *font,
616                   const gchar *text,
617                   gint         text_length)
618 {
619   GdkFontPrivate *private;
620   XCharStruct overall;
621   XFontStruct *xfont;
622   XFontSet    fontset;
623   XRectangle  ink, log;
624   int direction;
625   int font_ascent;
626   int font_descent;
627   gint width;
628
629   g_return_val_if_fail (font != NULL, -1);
630   g_return_val_if_fail (text != NULL, -1);
631
632   private = (GdkFontPrivate*) font;
633
634   switch (font->type)
635     {
636     case GDK_FONT_FONT:
637       xfont = (XFontStruct *) private->xfont;
638       if ((xfont->min_byte1 == 0) && (xfont->max_byte1 == 0))
639         {
640           XTextExtents (xfont, text, text_length,
641                         &direction, &font_ascent, &font_descent,
642                         &overall);
643         }
644       else
645         {
646           XTextExtents16 (xfont, (XChar2b *) text, text_length / 2,
647                           &direction, &font_ascent, &font_descent,
648                           &overall);
649         }
650       width = overall.rbearing;
651       break;
652     case GDK_FONT_FONTSET:
653       fontset = (XFontSet) private->xfont;
654       XmbTextExtents (fontset, text, text_length, &ink, &log);
655       width = log.width;
656       break;
657     default:
658       width = 0;
659     }
660   return width;
661 }
662
663 gint
664 gdk_char_measure (GdkFont *font,
665                   gchar    character)
666 {
667   g_return_val_if_fail (font != NULL, -1);
668
669   return gdk_text_measure (font, &character, 1);
670 }
671
672 gint
673 gdk_string_height (GdkFont     *font,
674                    const gchar *string)
675 {
676   g_return_val_if_fail (font != NULL, -1);
677   g_return_val_if_fail (string != NULL, -1);
678
679   return gdk_text_height (font, string, strlen (string));
680 }
681
682 gint
683 gdk_text_height (GdkFont     *font,
684                  const gchar *text,
685                  gint         text_length)
686 {
687   GdkFontPrivate *private;
688   XCharStruct overall;
689   XFontStruct *xfont;
690   XFontSet    fontset;
691   XRectangle  ink, log;
692   int direction;
693   int font_ascent;
694   int font_descent;
695   gint height;
696
697   g_return_val_if_fail (font != NULL, -1);
698   g_return_val_if_fail (text != NULL, -1);
699
700   private = (GdkFontPrivate*) font;
701
702   switch (font->type)
703     {
704     case GDK_FONT_FONT:
705       xfont = (XFontStruct *) private->xfont;
706       if ((xfont->min_byte1 == 0) && (xfont->max_byte1 == 0))
707         {
708           XTextExtents (xfont, text, text_length,
709                         &direction, &font_ascent, &font_descent,
710                         &overall);
711         }
712       else
713         {
714           XTextExtents16 (xfont, (XChar2b *) text, text_length / 2,
715                           &direction, &font_ascent, &font_descent,
716                           &overall);
717         }
718       height = overall.ascent + overall.descent;
719       break;
720     case GDK_FONT_FONTSET:
721       fontset = (XFontSet) private->xfont;
722       XmbTextExtents (fontset, text, text_length, &ink, &log);
723       height = log.height;
724       break;
725     default:
726       height = 0;
727     }
728   return height;
729 }
730
731 gint
732 gdk_char_height (GdkFont *font,
733                  gchar    character)
734 {
735   g_return_val_if_fail (font != NULL, -1);
736
737   return gdk_text_height (font, &character, 1);
738 }