1 /*
2 * This file is part of the XForms library package.
3 *
4 * XForms is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU Lesser General Public License as
6 * published by the Free Software Foundation; either version 2.1, or
7 * (at your option) any later version.
8 *
9 * XForms is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public License
15 * along with XForms. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18
19 /**
20 * \file fonts.c
21 *
22 * This file is part of the XForms library package.
23 * Copyright (c) 1996-2002 T.C. Zhao and Mark Overmars
24 * All rights reserved.
25 *
26 * All font and string size query routines. There are rooms for speed ups.
27 * For one, font switching can be reduced somewhat.
28 *
29 */
30
31 #ifdef HAVE_CONFIG_H
32 #include "config.h"
33 #endif
34
35 #include "include/forms.h"
36 #include "flinternal.h"
37 #include "private/flvasprintf.h"
38 #include <string.h>
39 #include <ctype.h>
40
41 static XFontStruct * defaultfs;
42
43 static XFontStruct * try_get_font_struct( int,
44 int,
45 int );
46 static char * get_fname( const char *,
47 int );
48
49
50 /*
51 * Question marks indicate the sizes in tenth of a point. It will be
52 * replaced on the fly by the font requesting routines. Depending on
53 * the availability of the fonts and capabilities of the server, the
54 * font may or may not be scalable.
55 *
56 * Resolution field is left blank on purpose as the resolution reported
57 * by the server is not reliable thus the program can't force the
58 * resolution. This way the admins can set the proper font path.
59 *
60 * Order is important as it has to agree with FL_TIMES_STYLE etc
61 * defined in Basic.h
62 *
63 */
64
65 /* These default fonts may not be the most beuatiful X11 fonts available
66 on the system but they are part of X11 distributions since at least
67 20 years, so we can be rather sure that they're available everywhere.
68 (And, remember, these fonts must be available on the machine where the
69 X server is running on, which is not necessarily the machine where the
70 program using XForms is executed.) */
71
72 static const char *default_fonts[ ] =
73 {
74 "-*-helvetica-medium-r-*-*-*-?-*-*-p-*-*-*",
75 "-*-helvetica-bold-r-*-*-*-?-*-*-p-*-*-*",
76 "-*-helvetica-medium-o-*-*-*-?-*-*-p-*-*-*",
77 "-*-helvetica-bold-o-*-*-*-?-*-*-p-*-*-*",
78
79 "-*-courier-medium-r-*-*-*-?-*-*-*-*-*-*",
80 "-*-courier-bold-r-*-*-*-?-*-*-*-*-*-*",
81 "-*-courier-medium-o-*-*-*-?-*-*-*-*-*-*",
82 "-*-courier-bold-o-*-*-*-?-*-*-*-*-*-*",
83
84 "-*-times-medium-r-*-*-*-?-*-*-p-*-*-*",
85 "-*-times-bold-r-*-*-*-?-*-*-p-*-*-*",
86 "-*-times-medium-i-*-*-*-?-*-*-p-*-*-*",
87 "-*-times-bold-i-*-*-*-?-*-*-p-*-*-*",
88
89 "-*-charter-medium-r-*-*-*-?-*-*-*-*-*-*",
90 "-*-charter-bold-r-*-*-*-?-*-*-*-*-*-*",
91 "-*-charter-medium-i-*-*-*-?-*-*-*-*-*-*",
92 "-*-charter-bold-i-*-*-*-?-*-*-*-*-*-*",
93
94 NULL
95 };
96
97 static FL_FONT fl_fonts[ FL_MAXFONTS ];
98
99 static const char *cv_fname( const char * );
100
101 #define DEFAULTF1 "fixed"
102 #define DEFAULTF2 "6x13"
103
104
105 /***************************************
106 * Global initialization routine. Must be called before any font
107 * routine can be used. We can place fli_init_font in all font switching
108 * and string size query routines so a seperate initialization is not
109 * needed, and it has the added bonus that startup *may* be faster,
110 * but we pay a function call overhead in every call to any of these
111 * font related routines.
112 ***************************************/
113
114 void
fli_init_font(void)115 fli_init_font( void )
116 {
117 FL_FONT *flf;
118 const char *const *f = default_fonts;
119 static int initialized;
120
121 if ( initialized )
122 return;
123
124 initialized = 1;
125
126 /* If fl_set_font_name() has been called before fl_initialize() we need
127 to keep the changes */
128
129 for ( flf = fl_fonts, f = default_fonts; *f; f++, flf++ )
130 if ( ! *flf->fname )
131 strcpy( flf->fname, *f );
132
133 /* Load a default font */
134
135 if ( ! defaultfs
136 && ! ( defaultfs = XLoadQueryFont( flx->display, DEFAULTF1 ) ) )
137 defaultfs = XLoadQueryFont( flx->display, DEFAULTF2 );
138
139 /* Load a couple of fonts at normal size to prevent the caching code from
140 using bad looking replacement if strange sizes are requested */
141
142 fl_get_font_struct( FL_NORMAL_STYLE, FL_DEFAULT_SIZE );
143 fl_get_font_struct( FL_BOLD_STYLE, FL_DEFAULT_SIZE );
144 fl_get_font_struct( FL_FIXED_STYLE, FL_DEFAULT_SIZE );
145 }
146
147
148 /***************************************
149 * In addition to get the font handle, we also make the font current
150 * in default GC
151 ***************************************/
152
153 void
fl_set_font(int numb,int size)154 fl_set_font( int numb,
155 int size )
156 {
157 int dh;
158 XCharStruct overall;
159 XFontStruct *fs;
160
161 fs = fl_get_font_struct( numb, size );
162
163 /* cur_font is always the one in current GC */
164
165 if ( fl_state[ fl_vmode ].cur_fnt == fs )
166 {
167 #if FL_DEBUG >= ML_DEBUG
168 M_debug( "fl_set_font", "current", fli_curfnt );
169 #endif
170 return;
171 }
172
173 fl_state[ fl_vmode ].cur_fnt = flx->fs = fs;
174
175 /* Basic font info (no need to send a string, we just want the maximum
176 ascent and descent) */
177
178 XTextExtents( flx->fs, "", 0, &dh, &flx->fasc, &flx->fdesc, &overall );
179 flx->fheight = flx->fasc + flx->fdesc;
180
181 XSetFont( flx->display, flx->textgc, flx->fs->fid );
182
183 if ( fli_cntl.debug > 1 )
184 {
185 unsigned long res = 0;
186
187 if ( XGetFontProperty( flx->fs, XA_RESOLUTION, &res ) )
188 M_info2( "fl_set_font", "FontResolution: %lu", res );
189 }
190 }
191
192
193 /***************************************
194 * Add a new font (indexed by n) or change an existing font.
195 * Preferably the font name constains a '?' in the size
196 * position so different sizes can be used.
197 ***************************************/
198
199 int
fl_set_font_name(int n,const char * name)200 fl_set_font_name( int n,
201 const char * name )
202 {
203 FL_FONT *flf;
204
205 if ( n < 0 || n >= FL_MAXFONTS )
206 {
207 M_warn( "fl_set_font_name", "Bad font number (%d)", n );
208 return -1;
209 }
210
211 if ( ! name || ! *name )
212 {
213 M_warn( "fl_set_font_name", "Bad font name" );
214 return -1;
215 }
216
217 if ( strlen( name ) > FL_MAX_FONTNAME_LENGTH )
218 {
219 M_warn( "fl_set_font_name", "Font name too long" );
220 return -1;
221 }
222
223 flf = fl_fonts + n;
224
225 if ( *flf->fname )
226 {
227 int i;
228
229 for ( i = 0; i < flf->nsize; i++ )
230 if ( flf->size[ i ] > 0 )
231 XFreeFont( flx->display, flf->fs[ i ] );
232 *flf->fname = '\0';
233 }
234
235 flf->nsize = 0;
236 strcpy( flf->fname, name );
237
238 if ( ! flx || ! flx->display )
239 return 1;
240
241 return try_get_font_struct( n, FL_DEFAULT_SIZE, 1 ) ? 0 : -1;
242 }
243
244
245 /***************************************
246 * Add a new font (indexed by n) or change an existing font.
247 ***************************************/
248
249 int
fl_set_font_name_f(int n,const char * fmt,...)250 fl_set_font_name_f( int n,
251 const char * fmt,
252 ... )
253 {
254 char *buf;
255 int ret;
256
257 EXPAND_FORMAT_STRING( buf, fmt );
258 ret = fl_set_font_name( n, buf );
259 fl_free( buf );
260 return ret;
261 }
262
263
264 /***************************************
265 * Returns the name of the indexed font
266 ***************************************/
267
268 const char *
fl_get_font_name(int n)269 fl_get_font_name( int n )
270 {
271 if ( n < 0 || n >= FL_MAXFONTS )
272 return NULL;
273
274 return fl_fonts[ n ].fname;
275 }
276
277
278 /***************************************
279 * List built-in fonts
280 ***************************************/
281
282 int
fl_enumerate_fonts(void (* output)(const char * s),int shortform)283 fl_enumerate_fonts( void ( * output )( const char *s ),
284 int shortform )
285 {
286 FL_FONT *flf = fl_fonts,
287 *fe = flf + FL_MAXFONTS;
288 int n = 0;
289
290 for ( ; output && flf < fe; flf++ )
291 if ( *flf->fname )
292 {
293 output( shortform ? cv_fname( flf->fname ) : flf->fname );
294 n++;
295 }
296
297 return n;
298 }
299
300
301 /***************************************
302 * All font changes go through this routine. If with_fail is false,
303 * this routine will not fail even if requested font can't be loaded.
304 * A substitution will be made.
305 ***************************************/
306
307 static XFontStruct *
try_get_font_struct(int numb,int size,int with_fail)308 try_get_font_struct( int numb,
309 int size,
310 int with_fail )
311 {
312 FL_FONT *flf = fl_fonts;
313 XFontStruct *fs = NULL;
314 int i,
315 is_subst = 0;
316
317 if ( special_style( numb ) )
318 numb %= FL_SHADOW_STYLE;
319
320 /* Avoid trying to use negative or zero font size */
321
322 if ( size <= 0 )
323 {
324 M_info( "try_get_font_struct",
325 "Bad font size requested (%d), using %d istead",
326 size, size < 0 ? -size : 1 );
327 size = size < 0 ? -size : 1;
328 }
329
330 flf = fl_fonts + numb;
331
332 if ( numb < 0 || numb >= FL_MAXFONTS || ! *flf->fname )
333 {
334 if ( ! fli_no_connection ) {
335
336 /* This function is typically used to test whether a font is
337 loadable or not, so it's not a fatal error if it fails. Issue
338 a message for information therefore. */
339
340 M_info( "try_get_font_struct", "Bad FontStyle requested: %d: %s",
341 numb, flf->fname );
342 }
343
344 if ( ! fl_state[ fl_vmode ].cur_fnt )
345 M_warn( "try_get_font_struct", "bad font returned" );
346
347 return fl_state[ fl_vmode ].cur_fnt;
348 }
349
350 strcpy( fli_curfnt, get_fname( flf->fname, size ) );
351
352 /* Search for requested size in the cached fonts - fonts with "negative
353 sizes" are replacement fonts found before */
354
355 for ( fs = NULL, i = 0; ! fs && i < flf->nsize; i++ )
356 if ( size == abs( flf->size[ i ] ) )
357 fs = flf->fs[ i ];
358
359 /* Return it if font has already been loaded (i.e. is in the cache) */
360
361 if ( fs )
362 return fs;
363
364 /* Try to load the font */
365
366 fs = XLoadQueryFont( flx->display, fli_curfnt );
367
368 /* If that didn't work try to find a replacement font, i.e. an already
369 loaded font with the nearest size or, if there's none, the very most
370 basic font. */
371
372 if ( ! fs )
373 {
374 int mdiff = INT_MAX,
375 k;
376
377 if ( with_fail )
378 return NULL;
379
380 M_warn( "try_get_font_struct", "Can't load %s, using subsitute",
381 fli_curfnt );
382
383 /* Search for a replacement with the nearest size */
384
385 for ( k = -1, i = 0; i < flf->nsize; i++ )
386 {
387 if ( mdiff > FL_abs( size - flf->size[ i ] ) )
388 {
389 mdiff = FL_abs( size - flf->size[ i ] );
390 k = i;
391 }
392 }
393
394 if ( k != -1 )
395 fs = flf->fs[ k ];
396 else
397 fs = flx->fs ? flx->fs : defaultfs;
398
399 is_subst = 1;
400 }
401
402 /* If cache is full make space at the end */
403
404 if ( flf->nsize == FL_MAX_FONTSIZES )
405 {
406 if ( flf->size[ FL_MAX_FONTSIZES - 1 ] > 0 )
407 XFreeFont( flx->display, flf->fs[ FL_MAX_FONTSIZES - 1 ] );
408 flf->nsize--;
409 }
410
411 flf->fs[ flf->nsize ] = fs;
412 flf->size[ flf->nsize++ ] = is_subst ? - size : size;
413
414 /* Here we are guranteed a valid font handle although there is no
415 gurantee the font handle corresponds to the font requested */
416
417 return fs;
418 }
419
420
421 /***************************************
422 ***************************************/
423
424 XFontStruct *
fl_get_font_struct(int style,int size)425 fl_get_font_struct( int style,
426 int size )
427 {
428 return try_get_font_struct( style, size, 0 );
429 }
430
431
432 /***************************************
433 * Similar to fl_get_string_xxxGC except that there is no side effects.
434 * Must not free the fontstruct as structure FL_FONT caches the
435 * structure for possible future use.
436 ***************************************/
437
438 int
fl_get_string_width(int style,int size,const char * s,int len)439 fl_get_string_width( int style,
440 int size,
441 const char * s,
442 int len )
443 {
444 XFontStruct *fs = fl_get_font_struct( style, size );
445
446 return fli_no_connection ? ( len * size ) : XTextWidth( fs, s, len );
447 }
448
449
450 /***************************************
451 ***************************************/
452
453 int
fli_get_string_widthTABfs(XFontStruct * fs,const char * s,int len)454 fli_get_string_widthTABfs( XFontStruct * fs,
455 const char * s,
456 int len )
457 {
458 int w,
459 tab;
460 const char *p,
461 *q;
462
463 if ( fli_no_connection )
464 return 12 * len;
465
466 tab = fli_get_tabpixels( fs );
467
468 for ( w = 0, q = s; *q && ( p = strchr( q, '\t' ) ) && ( p - s ) < len;
469 q = p + 1 )
470 {
471 w += XTextWidth( fs, q, p - q );
472 w = ( ( w / tab ) + 1 ) * tab;
473 }
474
475 return w += XTextWidth( fs, q, len - ( q - s ) );
476 }
477
478
479 /***************************************
480 ***************************************/
481
482 int
fl_get_string_widthTAB(int style,int size,const char * s,int len)483 fl_get_string_widthTAB( int style,
484 int size,
485 const char * s,
486 int len )
487 {
488 XFontStruct *fs = fl_get_font_struct( style, size );
489
490 return fli_get_string_widthTABfs( fs, s, len );
491 }
492
493
494 /***************************************
495 * Function returns the height of the string, calculated from adding the
496 * largest ascent and descent of all its characters in the string, via 'asc'
497 * and 'desc' (but which both can be NULL pointers), the maximum ascent
498 * and descent.
499 ***************************************/
500
501 int
fl_get_string_height(int style,int size,const char * s,int len,int * asc,int * desc)502 fl_get_string_height( int style,
503 int size,
504 const char * s,
505 int len,
506 int * asc,
507 int * desc )
508 {
509 int a, d;
510
511 if ( fli_no_connection )
512 a = d = size / 2;
513 else
514 {
515 XFontStruct *fs = fl_get_font_struct( style, size );
516 XCharStruct overall;
517 int dh;
518
519 XTextExtents( fs, s, len, &dh, &a, &d, &overall );
520 }
521
522 if ( asc )
523 *asc = a;
524 if ( desc )
525 *desc = d;
526
527 return a + d;
528 }
529
530
531 /***************************************
532 * Returns font height and, via 'asc' and 'desc' (but which both can be NULL
533 * pointers), the fonts ascent and descent.
534 ***************************************/
535
536 int
fl_get_char_height(int style,int size,int * asc,int * desc)537 fl_get_char_height( int style,
538 int size,
539 int * asc,
540 int * desc )
541 {
542 int a, d;
543
544 if ( fli_no_connection )
545 a = d = size / 2;
546 else
547 {
548 XFontStruct *fs = fl_get_font_struct( style, size );
549
550 a = fs->ascent;
551 d = fs->descent;
552
553 if ( asc )
554 *asc = a;
555 if ( desc )
556 *desc = d;
557 }
558
559 return a + d;
560 }
561
562
563 /***************************************
564 * Function returns the width of the widest character in the requested font
565 ***************************************/
566
567 int
fl_get_char_width(int style,int size)568 fl_get_char_width( int style,
569 int size )
570 {
571 XFontStruct *fs = fl_get_font_struct( style, size );
572
573 return fs->max_bounds.width;
574 }
575
576
577 /***************************************
578 ***************************************/
579
580 void
fl_get_string_dimension(int fntstyle,int fntsize,const char * s,int len,int * width,int * height)581 fl_get_string_dimension( int fntstyle,
582 int fntsize,
583 const char * s,
584 int len,
585 int * width,
586 int * height )
587 {
588 const char *p,
589 *q;
590 int h,
591 maxw = 0,
592 maxh = 0;
593
594 h = fl_get_char_height( fntstyle, fntsize, NULL, NULL );
595
596 for ( q = s; *q && ( p = strchr( q, '\n' ) ); q = p + 1 )
597 {
598 maxw = FL_max( maxw,
599 fl_get_string_width( fntstyle, fntsize, q, p - q ) );
600 maxh += h;
601 }
602
603 maxw = FL_max( maxw, fl_get_string_width( fntstyle, fntsize,
604 q, len - ( q - s ) ) );
605 maxh += h;
606
607 *width = maxw;
608 *height = maxh;
609 }
610
611
612 /*
613 * Tab handling. Currently only one tab
614 */
615
616 #define MaxTabs 5
617
618 static char *tabstop[ MaxTabs ] = { "aaaaaaaa", 0 };
619 static int tabstopNchar[ MaxTabs ] = { 7 };
620
621
622 /***************************************
623 ***************************************/
624
625 void
fl_set_tabstop(const char * s)626 fl_set_tabstop( const char *s )
627 {
628 static int set;
629
630 if ( s )
631 {
632 if ( set )
633 fl_free( *tabstop );
634 *tabstop = fl_strdup( s );
635 *tabstopNchar = strlen( *tabstop );
636 set = 1;
637 }
638 }
639
640
641 /***************************************
642 ***************************************/
643
644 int
fli_get_tabpixels(XFontStruct * fs)645 fli_get_tabpixels( XFontStruct * fs )
646 {
647 return XTextWidth( fs, *tabstop, *tabstopNchar )
648 + XTextWidth( fs, " ", 1 );
649 }
650
651
652 /***************************************
653 * Convert X font names to more conventional names by stripping the
654 * auxiliary info.
655 ***************************************/
656
657 static const char *
cv_fname(const char * f)658 cv_fname( const char *f )
659 {
660 static char fname[ FL_MAX_FONTNAME_LENGTH + 1 ];
661 char *q,
662 *p;
663
664 /* Remove all the garbages from head */
665
666 for ( q = strcpy( fname, f ); *q && ! isalnum( ( unsigned char ) *q ); q++ )
667 /* empty */ ;
668
669 /* Remove all the garbage from the end, starting from '?' */
670
671 if ( ( p = strchr( fname, '?' ) ) )
672 *--p = '\0';
673
674 /* Remove all remaining garbages */
675
676 for ( p = fname + strlen( fname ) - 1;
677 p > q && ! isalnum( ( unsigned char ) *p ); p-- )
678 /* empty */ ;
679
680 *++p = '\0';
681
682 return q;
683 }
684
685
686 /***************************************
687 * Given a font name and a size (in points), assemble the complete name
688 ***************************************/
689
690 static char *
get_fname(const char * str,int size)691 get_fname( const char * str,
692 int size )
693 {
694 static char fname[ sizeof fli_curfnt ];
695 char len_str[ 50 ]; /* should be enough for all ints */
696 char *p;
697
698 /* If necessary truncate font names that are too long, the caller
699 expects a real string */
700
701 strncpy( fname, str, sizeof fname - 1 );
702 fname[ sizeof fname - 1 ] = '\0';
703
704 if ( ( p = strchr( fname, '?' ) ) )
705 {
706 int len = sprintf( len_str, "%d0", size );
707
708 if ( len + strlen( str ) <= sizeof fname - 1 )
709 {
710 memmove( p + len, p + 1, strlen( p ) );
711 strncpy( p, len_str, len );
712 }
713 }
714
715 return fname;
716 }
717
718
719 /***************************************
720 * Some compatibility stuff, i.e. functions that were never documented
721 * and were removed from V0.89, but apparently this broke some applications
722 * that were using them. Put back in 10/22/00.
723 ***************************************/
724
725 int
fl_fdesc_(void)726 fl_fdesc_( void )
727 {
728 return flx->fdesc;
729 }
730
731
732 /***************************************
733 ***************************************/
734
735 int
fl_fheight_(void)736 fl_fheight_( void )
737 {
738 return flx->fheight;
739 }
740
741
742 /***************************************
743 ***************************************/
744
745 GC
fl_gc_(void)746 fl_gc_( void )
747 {
748 return flx->gc;
749 }
750
751
752 /***************************************
753 ***************************************/
754
755 GC
fl_textgc_(void)756 fl_textgc_( void )
757 {
758 return flx->textgc;
759 }
760
761
762 /***************************************
763 ***************************************/
764
765 Window
fl_cur_win_(void)766 fl_cur_win_( void )
767 {
768 return flx->win;
769 }
770
771
772 /***************************************
773 ***************************************/
774
775 XFontStruct *
fl_cur_fs_(void)776 fl_cur_fs_( void )
777 {
778 return flx->fs;
779 }
780
781
782 /***************************************
783 ***************************************/
784
785 Display *
fl_display_(void)786 fl_display_( void )
787 {
788 return flx->display;
789 }
790
791
792 /*
793 * Local variables:
794 * tab-width: 4
795 * indent-tabs-mode: nil
796 * End:
797 */
798