2 * Copyright 2000 Computing Research Labs, New Mexico State University
3 * Copyright 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2009, 2010
4 * Francesco Zappa Nardelli
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 * and/or sell copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following conditions:
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE COMPUTING RESEARCH LAB OR NEW MEXICO STATE UNIVERSITY BE LIABLE FOR ANY
20 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT
21 * OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
22 * THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 /*************************************************************************/
27 /* This file is based on bdf.c,v 1.22 2000/03/16 20:08:50 */
29 /* taken from Mark Leisher's xmbdfed package */
31 /*************************************************************************/
36 #include FT_FREETYPE_H
37 #include FT_INTERNAL_DEBUG_H
38 #include FT_INTERNAL_STREAM_H
39 #include FT_INTERNAL_OBJECTS_H
45 /*************************************************************************/
47 /* The macro FT_COMPONENT is used in trace mode. It is an implicit */
48 /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
49 /* messages during execution. */
52 #define FT_COMPONENT trace_bdflib
55 /*************************************************************************/
57 /* Default BDF font options. */
59 /*************************************************************************/
62 static const bdf_options_t _bdf_opts
=
64 1, /* Correct metrics. */
65 1, /* Preserve unencoded glyphs. */
66 0, /* Preserve comments. */
67 BDF_PROPORTIONAL
/* Default spacing. */
71 /*************************************************************************/
73 /* Builtin BDF font properties. */
75 /*************************************************************************/
77 /* List of most properties that might appear in a font. Doesn't include */
78 /* the RAW_* and AXIS_* properties in X11R6 polymorphic fonts. */
80 static const bdf_property_t _bdf_properties
[] =
82 { (char *)"ADD_STYLE_NAME", BDF_ATOM
, 1, { 0 } },
83 { (char *)"AVERAGE_WIDTH", BDF_INTEGER
, 1, { 0 } },
84 { (char *)"AVG_CAPITAL_WIDTH", BDF_INTEGER
, 1, { 0 } },
85 { (char *)"AVG_LOWERCASE_WIDTH", BDF_INTEGER
, 1, { 0 } },
86 { (char *)"CAP_HEIGHT", BDF_INTEGER
, 1, { 0 } },
87 { (char *)"CHARSET_COLLECTIONS", BDF_ATOM
, 1, { 0 } },
88 { (char *)"CHARSET_ENCODING", BDF_ATOM
, 1, { 0 } },
89 { (char *)"CHARSET_REGISTRY", BDF_ATOM
, 1, { 0 } },
90 { (char *)"COMMENT", BDF_ATOM
, 1, { 0 } },
91 { (char *)"COPYRIGHT", BDF_ATOM
, 1, { 0 } },
92 { (char *)"DEFAULT_CHAR", BDF_CARDINAL
, 1, { 0 } },
93 { (char *)"DESTINATION", BDF_CARDINAL
, 1, { 0 } },
94 { (char *)"DEVICE_FONT_NAME", BDF_ATOM
, 1, { 0 } },
95 { (char *)"END_SPACE", BDF_INTEGER
, 1, { 0 } },
96 { (char *)"FACE_NAME", BDF_ATOM
, 1, { 0 } },
97 { (char *)"FAMILY_NAME", BDF_ATOM
, 1, { 0 } },
98 { (char *)"FIGURE_WIDTH", BDF_INTEGER
, 1, { 0 } },
99 { (char *)"FONT", BDF_ATOM
, 1, { 0 } },
100 { (char *)"FONTNAME_REGISTRY", BDF_ATOM
, 1, { 0 } },
101 { (char *)"FONT_ASCENT", BDF_INTEGER
, 1, { 0 } },
102 { (char *)"FONT_DESCENT", BDF_INTEGER
, 1, { 0 } },
103 { (char *)"FOUNDRY", BDF_ATOM
, 1, { 0 } },
104 { (char *)"FULL_NAME", BDF_ATOM
, 1, { 0 } },
105 { (char *)"ITALIC_ANGLE", BDF_INTEGER
, 1, { 0 } },
106 { (char *)"MAX_SPACE", BDF_INTEGER
, 1, { 0 } },
107 { (char *)"MIN_SPACE", BDF_INTEGER
, 1, { 0 } },
108 { (char *)"NORM_SPACE", BDF_INTEGER
, 1, { 0 } },
109 { (char *)"NOTICE", BDF_ATOM
, 1, { 0 } },
110 { (char *)"PIXEL_SIZE", BDF_INTEGER
, 1, { 0 } },
111 { (char *)"POINT_SIZE", BDF_INTEGER
, 1, { 0 } },
112 { (char *)"QUAD_WIDTH", BDF_INTEGER
, 1, { 0 } },
113 { (char *)"RAW_ASCENT", BDF_INTEGER
, 1, { 0 } },
114 { (char *)"RAW_AVERAGE_WIDTH", BDF_INTEGER
, 1, { 0 } },
115 { (char *)"RAW_AVG_CAPITAL_WIDTH", BDF_INTEGER
, 1, { 0 } },
116 { (char *)"RAW_AVG_LOWERCASE_WIDTH", BDF_INTEGER
, 1, { 0 } },
117 { (char *)"RAW_CAP_HEIGHT", BDF_INTEGER
, 1, { 0 } },
118 { (char *)"RAW_DESCENT", BDF_INTEGER
, 1, { 0 } },
119 { (char *)"RAW_END_SPACE", BDF_INTEGER
, 1, { 0 } },
120 { (char *)"RAW_FIGURE_WIDTH", BDF_INTEGER
, 1, { 0 } },
121 { (char *)"RAW_MAX_SPACE", BDF_INTEGER
, 1, { 0 } },
122 { (char *)"RAW_MIN_SPACE", BDF_INTEGER
, 1, { 0 } },
123 { (char *)"RAW_NORM_SPACE", BDF_INTEGER
, 1, { 0 } },
124 { (char *)"RAW_PIXEL_SIZE", BDF_INTEGER
, 1, { 0 } },
125 { (char *)"RAW_POINT_SIZE", BDF_INTEGER
, 1, { 0 } },
126 { (char *)"RAW_PIXELSIZE", BDF_INTEGER
, 1, { 0 } },
127 { (char *)"RAW_POINTSIZE", BDF_INTEGER
, 1, { 0 } },
128 { (char *)"RAW_QUAD_WIDTH", BDF_INTEGER
, 1, { 0 } },
129 { (char *)"RAW_SMALL_CAP_SIZE", BDF_INTEGER
, 1, { 0 } },
130 { (char *)"RAW_STRIKEOUT_ASCENT", BDF_INTEGER
, 1, { 0 } },
131 { (char *)"RAW_STRIKEOUT_DESCENT", BDF_INTEGER
, 1, { 0 } },
132 { (char *)"RAW_SUBSCRIPT_SIZE", BDF_INTEGER
, 1, { 0 } },
133 { (char *)"RAW_SUBSCRIPT_X", BDF_INTEGER
, 1, { 0 } },
134 { (char *)"RAW_SUBSCRIPT_Y", BDF_INTEGER
, 1, { 0 } },
135 { (char *)"RAW_SUPERSCRIPT_SIZE", BDF_INTEGER
, 1, { 0 } },
136 { (char *)"RAW_SUPERSCRIPT_X", BDF_INTEGER
, 1, { 0 } },
137 { (char *)"RAW_SUPERSCRIPT_Y", BDF_INTEGER
, 1, { 0 } },
138 { (char *)"RAW_UNDERLINE_POSITION", BDF_INTEGER
, 1, { 0 } },
139 { (char *)"RAW_UNDERLINE_THICKNESS", BDF_INTEGER
, 1, { 0 } },
140 { (char *)"RAW_X_HEIGHT", BDF_INTEGER
, 1, { 0 } },
141 { (char *)"RELATIVE_SETWIDTH", BDF_CARDINAL
, 1, { 0 } },
142 { (char *)"RELATIVE_WEIGHT", BDF_CARDINAL
, 1, { 0 } },
143 { (char *)"RESOLUTION", BDF_INTEGER
, 1, { 0 } },
144 { (char *)"RESOLUTION_X", BDF_CARDINAL
, 1, { 0 } },
145 { (char *)"RESOLUTION_Y", BDF_CARDINAL
, 1, { 0 } },
146 { (char *)"SETWIDTH_NAME", BDF_ATOM
, 1, { 0 } },
147 { (char *)"SLANT", BDF_ATOM
, 1, { 0 } },
148 { (char *)"SMALL_CAP_SIZE", BDF_INTEGER
, 1, { 0 } },
149 { (char *)"SPACING", BDF_ATOM
, 1, { 0 } },
150 { (char *)"STRIKEOUT_ASCENT", BDF_INTEGER
, 1, { 0 } },
151 { (char *)"STRIKEOUT_DESCENT", BDF_INTEGER
, 1, { 0 } },
152 { (char *)"SUBSCRIPT_SIZE", BDF_INTEGER
, 1, { 0 } },
153 { (char *)"SUBSCRIPT_X", BDF_INTEGER
, 1, { 0 } },
154 { (char *)"SUBSCRIPT_Y", BDF_INTEGER
, 1, { 0 } },
155 { (char *)"SUPERSCRIPT_SIZE", BDF_INTEGER
, 1, { 0 } },
156 { (char *)"SUPERSCRIPT_X", BDF_INTEGER
, 1, { 0 } },
157 { (char *)"SUPERSCRIPT_Y", BDF_INTEGER
, 1, { 0 } },
158 { (char *)"UNDERLINE_POSITION", BDF_INTEGER
, 1, { 0 } },
159 { (char *)"UNDERLINE_THICKNESS", BDF_INTEGER
, 1, { 0 } },
160 { (char *)"WEIGHT", BDF_CARDINAL
, 1, { 0 } },
161 { (char *)"WEIGHT_NAME", BDF_ATOM
, 1, { 0 } },
162 { (char *)"X_HEIGHT", BDF_INTEGER
, 1, { 0 } },
163 { (char *)"_MULE_BASELINE_OFFSET", BDF_INTEGER
, 1, { 0 } },
164 { (char *)"_MULE_RELATIVE_COMPOSE", BDF_INTEGER
, 1, { 0 } },
167 static const unsigned long
168 _num_bdf_properties
= sizeof ( _bdf_properties
) /
169 sizeof ( _bdf_properties
[0] );
172 /*************************************************************************/
174 /* Hash table utilities for the properties. */
176 /*************************************************************************/
178 /* XXX: Replace this with FreeType's hash functions */
181 #define INITIAL_HT_SIZE 241
184 (*hash_free_func
)( hashnode node
);
187 hash_bucket( const char* key
,
190 const char* kp
= key
;
191 unsigned long res
= 0;
192 hashnode
* bp
= ht
->table
, *ndp
;
195 /* Mocklisp hash function. */
197 res
= ( res
<< 5 ) - res
+ *kp
++;
199 ndp
= bp
+ ( res
% ht
->size
);
203 if ( kp
[0] == key
[0] && ft_strcmp( kp
, key
) == 0 )
207 ndp
= bp
+ ( ht
->size
- 1 );
215 hash_rehash( hashtable
* ht
,
218 hashnode
* obp
= ht
->table
, *bp
, *nbp
;
219 int i
, sz
= ht
->size
;
220 FT_Error error
= BDF_Err_Ok
;
224 ht
->limit
= ht
->size
/ 3;
226 if ( FT_NEW_ARRAY( ht
->table
, ht
->size
) )
229 for ( i
= 0, bp
= obp
; i
< sz
; i
++, bp
++ )
233 nbp
= hash_bucket( (*bp
)->key
, ht
);
245 hash_init( hashtable
* ht
,
248 int sz
= INITIAL_HT_SIZE
;
249 FT_Error error
= BDF_Err_Ok
;
256 if ( FT_NEW_ARRAY( ht
->table
, sz
) )
265 hash_free( hashtable
* ht
,
270 int i
, sz
= ht
->size
;
271 hashnode
* bp
= ht
->table
;
274 for ( i
= 0; i
< sz
; i
++, bp
++ )
277 FT_FREE( ht
->table
);
283 hash_insert( char* key
,
288 hashnode nn
, *bp
= hash_bucket( key
, ht
);
289 FT_Error error
= BDF_Err_Ok
;
302 if ( ht
->used
>= ht
->limit
)
304 error
= hash_rehash( ht
, memory
);
319 hash_lookup( const char* key
,
322 hashnode
*np
= hash_bucket( key
, ht
);
329 /*************************************************************************/
331 /* Utility types and functions. */
333 /*************************************************************************/
336 /* Function type for parsing lines of a BDF font. */
339 (*_bdf_line_func_t
)( char* line
,
340 unsigned long linelen
,
341 unsigned long lineno
,
346 /* List structure for splitting lines into fields. */
348 typedef struct _bdf_list_t_
358 /* Structure used while loading BDF fonts. */
360 typedef struct _bdf_parse_t_
380 unsigned long have
[2048];
388 #define setsbit( m, cc ) \
389 ( m[(FT_Byte)(cc) >> 3] |= (FT_Byte)( 1 << ( (cc) & 7 ) ) )
390 #define sbitset( m, cc ) \
391 ( m[(FT_Byte)(cc) >> 3] & ( 1 << ( (cc) & 7 ) ) )
395 _bdf_list_init( _bdf_list_t
* list
,
399 list
->memory
= memory
;
404 _bdf_list_done( _bdf_list_t
* list
)
406 FT_Memory memory
= list
->memory
;
411 FT_FREE( list
->field
);
418 _bdf_list_ensure( _bdf_list_t
* list
,
419 unsigned long num_items
) /* same as _bdf_list_t.used */
421 FT_Error error
= BDF_Err_Ok
;
424 if ( num_items
> list
->size
)
426 unsigned long oldsize
= list
->size
; /* same as _bdf_list_t.size */
427 unsigned long newsize
= oldsize
+ ( oldsize
>> 1 ) + 4;
428 unsigned long bigsize
= (unsigned long)( FT_INT_MAX
/ sizeof ( char* ) );
429 FT_Memory memory
= list
->memory
;
432 if ( oldsize
== bigsize
)
434 error
= BDF_Err_Out_Of_Memory
;
437 else if ( newsize
< oldsize
|| newsize
> bigsize
)
440 if ( FT_RENEW_ARRAY( list
->field
, oldsize
, newsize
) )
443 list
->size
= newsize
;
452 _bdf_list_shift( _bdf_list_t
* list
,
458 if ( list
== 0 || list
->used
== 0 || n
== 0 )
461 if ( n
>= list
->used
)
467 for ( u
= n
, i
= 0; u
< list
->used
; i
++, u
++ )
468 list
->field
[i
] = list
->field
[u
];
473 /* An empty string for empty fields. */
475 static const char empty
[1] = { 0 }; /* XXX eliminate this */
479 _bdf_list_join( _bdf_list_t
* list
,
481 unsigned long *alen
)
489 if ( list
== 0 || list
->used
== 0 )
493 for ( i
= j
= 0; i
< list
->used
; i
++ )
499 if ( i
+ 1 < list
->used
)
511 _bdf_list_split( _bdf_list_t
* list
,
514 unsigned long linelen
)
516 int mult
, final_empty
;
519 FT_Error error
= BDF_Err_Ok
;
522 /* Initialize the list. */
525 /* If the line is empty, then simply return. */
526 if ( linelen
== 0 || line
[0] == 0 )
529 /* In the original code, if the `separators' parameter is NULL or */
530 /* empty, the list is split into individual bytes. We don't need */
531 /* this, so an error is signaled. */
532 if ( separators
== 0 || *separators
== 0 )
534 error
= BDF_Err_Invalid_Argument
;
538 /* Prepare the separator bitmap. */
539 FT_MEM_ZERO( seps
, 32 );
541 /* If the very last character of the separator string is a plus, then */
542 /* set the `mult' flag to indicate that multiple separators should be */
543 /* collapsed into one. */
544 for ( mult
= 0, sp
= separators
; sp
&& *sp
; sp
++ )
546 if ( *sp
== '+' && *( sp
+ 1 ) == 0 )
549 setsbit( seps
, *sp
);
552 /* Break the line up into fields. */
553 for ( final_empty
= 0, sp
= ep
= line
, end
= sp
+ linelen
;
556 /* Collect everything that is not a separator. */
557 for ( ; *ep
&& !sbitset( seps
, *ep
); ep
++ )
560 /* Resize the list if necessary. */
561 if ( list
->used
== list
->size
)
563 error
= _bdf_list_ensure( list
, list
->used
+ 1 );
568 /* Assign the field appropriately. */
569 list
->field
[list
->used
++] = ( ep
> sp
) ? sp
: (char*)empty
;
575 /* If multiple separators should be collapsed, do it now by */
576 /* setting all the separator characters to 0. */
577 for ( ; *ep
&& sbitset( seps
, *ep
); ep
++ )
581 /* Don't collapse multiple separators by making them 0, so just */
582 /* make the one encountered 0. */
585 final_empty
= ( ep
> sp
&& *ep
== 0 );
589 /* Finally, NULL-terminate the list. */
590 if ( list
->used
+ final_empty
>= list
->size
)
592 error
= _bdf_list_ensure( list
, list
->used
+ final_empty
+ 1 );
598 list
->field
[list
->used
++] = (char*)empty
;
600 list
->field
[list
->used
] = 0;
607 #define NO_SKIP 256 /* this value cannot be stored in a 'char' */
611 _bdf_readstream( FT_Stream stream
,
612 _bdf_line_func_t callback
,
617 unsigned long lineno
, buf_size
;
618 int refill
, hold
, to_skip
;
619 ptrdiff_t bytes
, start
, end
, cursor
, avail
;
621 FT_Memory memory
= stream
->memory
;
622 FT_Error error
= BDF_Err_Ok
;
627 error
= BDF_Err_Invalid_Argument
;
631 /* initial size and allocation of the input buffer */
634 if ( FT_NEW_ARRAY( buf
, buf_size
) )
646 bytes
= 0; /* make compiler happy */
652 bytes
= (ptrdiff_t)FT_Stream_TryRead(
653 stream
, (FT_Byte
*)buf
+ cursor
,
654 (FT_ULong
)( buf_size
- cursor
) );
655 avail
= cursor
+ bytes
;
662 /* should we skip an optional character like \n or \r? */
663 if ( start
< avail
&& buf
[start
] == to_skip
)
670 /* try to find the end of the line */
671 while ( end
< avail
&& buf
[end
] != '\n' && buf
[end
] != '\r' )
674 /* if we hit the end of the buffer, try shifting its content */
675 /* or even resizing it */
678 if ( bytes
== 0 ) /* last line in file doesn't end in \r or \n */
679 break; /* ignore it then exit */
683 /* this line is definitely too long; try resizing the input */
684 /* buffer a bit to handle it. */
688 if ( buf_size
>= 65536UL ) /* limit ourselves to 64KByte */
690 error
= BDF_Err_Invalid_Argument
;
694 new_size
= buf_size
* 2;
695 if ( FT_RENEW_ARRAY( buf
, buf_size
, new_size
) )
703 bytes
= avail
- start
;
705 FT_MEM_COPY( buf
, buf
+ start
, bytes
);
715 /* Temporarily NUL-terminate the line. */
719 /* XXX: Use encoding independent value for 0x1a */
720 if ( buf
[start
] != '#' && buf
[start
] != 0x1a && end
> start
)
722 error
= (*cb
)( buf
+ start
, end
- start
, lineno
,
723 (void*)&cb
, client_data
);
724 /* Redo if we have encountered CHARS without properties. */
726 error
= (*cb
)( buf
+ start
, end
- start
, lineno
,
727 (void*)&cb
, client_data
);
733 buf
[end
] = (char)hold
;
738 else if ( hold
== '\r' )
752 /* XXX: make this work with EBCDIC also */
754 static const unsigned char a2i
[128] =
756 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
757 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
758 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
759 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
760 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x00, 0x00,
761 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00,
762 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
763 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
764 0x00, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00,
765 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
766 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
769 static const unsigned char odigits
[32] =
771 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00,
772 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
773 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
774 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
777 static const unsigned char ddigits
[32] =
779 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x03,
780 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
781 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
782 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
785 static const unsigned char hdigits
[32] =
787 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x03,
788 0x7e, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00,
789 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
790 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
794 #define isdigok( m, d ) (m[(d) >> 3] & ( 1 << ( (d) & 7 ) ) )
797 /* Routine to convert an ASCII string into an unsigned long integer. */
804 const unsigned char* dmap
;
807 if ( s
== 0 || *s
== 0 )
810 /* Make sure the radix is something recognizable. Default to 10. */
825 /* Check for the special hex prefix. */
827 ( *( s
+ 1 ) == 'x' || *( s
+ 1 ) == 'X' ) )
834 for ( v
= 0; isdigok( dmap
, *s
); s
++ )
835 v
= v
* base
+ a2i
[(int)*s
];
844 /* Routine to convert an ASCII string into an signed long integer. */
851 const unsigned char* dmap
;
854 if ( s
== 0 || *s
== 0 )
857 /* Make sure the radix is something recognizable. Default to 10. */
872 /* Check for a minus sign. */
880 /* Check for the special hex prefix. */
882 ( *( s
+ 1 ) == 'x' || *( s
+ 1 ) == 'X' ) )
889 for ( v
= 0; isdigok( dmap
, *s
); s
++ )
890 v
= v
* base
+ a2i
[(int)*s
];
895 return ( !neg
) ? v
: -v
;
899 /* Routine to convert an ASCII string into an signed short integer. */
906 const unsigned char* dmap
;
909 if ( s
== 0 || *s
== 0 )
912 /* Make sure the radix is something recognizable. Default to 10. */
927 /* Check for a minus. */
935 /* Check for the special hex prefix. */
937 ( *( s
+ 1 ) == 'x' || *( s
+ 1 ) == 'X' ) )
944 for ( v
= 0; isdigok( dmap
, *s
); s
++ )
945 v
= (short)( v
* base
+ a2i
[(int)*s
] );
950 return (short)( ( !neg
) ? v
: -v
);
954 /* Routine to compare two glyphs by encoding so they can be sorted. */
956 by_encoding( const void* a
,
959 bdf_glyph_t
*c1
, *c2
;
962 c1
= (bdf_glyph_t
*)a
;
963 c2
= (bdf_glyph_t
*)b
;
965 if ( c1
->encoding
< c2
->encoding
)
968 if ( c1
->encoding
> c2
->encoding
)
976 bdf_create_property( char* name
,
982 FT_Memory memory
= font
->memory
;
983 FT_Error error
= BDF_Err_Ok
;
986 /* First check to see if the property has */
987 /* already been added or not. If it has, then */
988 /* simply ignore it. */
989 if ( hash_lookup( name
, &(font
->proptbl
) ) )
992 if ( FT_RENEW_ARRAY( font
->user_props
,
994 font
->nuser_props
+ 1 ) )
997 p
= font
->user_props
+ font
->nuser_props
;
1000 n
= ft_strlen( name
) + 1;
1001 if ( n
> FT_ULONG_MAX
)
1002 return BDF_Err_Invalid_Argument
;
1004 if ( FT_NEW_ARRAY( p
->name
, n
) )
1007 FT_MEM_COPY( (char *)p
->name
, name
, n
);
1012 n
= _num_bdf_properties
+ font
->nuser_props
;
1014 error
= hash_insert( p
->name
, n
, &(font
->proptbl
), memory
);
1018 font
->nuser_props
++;
1025 FT_LOCAL_DEF( bdf_property_t
* )
1026 bdf_get_property( char* name
,
1033 if ( name
== 0 || *name
== 0 )
1036 if ( ( hn
= hash_lookup( name
, &(font
->proptbl
) ) ) == 0 )
1040 if ( propid
>= _num_bdf_properties
)
1041 return font
->user_props
+ ( propid
- _num_bdf_properties
);
1043 return (bdf_property_t
*)_bdf_properties
+ propid
;
1047 /*************************************************************************/
1049 /* BDF font file parsing flags and functions. */
1051 /*************************************************************************/
1056 #define _BDF_START 0x0001
1057 #define _BDF_FONT_NAME 0x0002
1058 #define _BDF_SIZE 0x0004
1059 #define _BDF_FONT_BBX 0x0008
1060 #define _BDF_PROPS 0x0010
1061 #define _BDF_GLYPHS 0x0020
1062 #define _BDF_GLYPH 0x0040
1063 #define _BDF_ENCODING 0x0080
1064 #define _BDF_SWIDTH 0x0100
1065 #define _BDF_DWIDTH 0x0200
1066 #define _BDF_BBX 0x0400
1067 #define _BDF_BITMAP 0x0800
1069 #define _BDF_SWIDTH_ADJ 0x1000
1071 #define _BDF_GLYPH_BITS ( _BDF_GLYPH | \
1078 #define _BDF_GLYPH_WIDTH_CHECK 0x40000000UL
1079 #define _BDF_GLYPH_HEIGHT_CHECK 0x80000000UL
1082 /* Auto correction messages. */
1083 #define ACMSG1 "FONT_ASCENT property missing. " \
1084 "Added \"FONT_ASCENT %hd\".\n"
1085 #define ACMSG2 "FONT_DESCENT property missing. " \
1086 "Added \"FONT_DESCENT %hd\".\n"
1087 #define ACMSG3 "Font width != actual width. Old: %hd New: %hd.\n"
1088 #define ACMSG4 "Font left bearing != actual left bearing. " \
1089 "Old: %hd New: %hd.\n"
1090 #define ACMSG5 "Font ascent != actual ascent. Old: %hd New: %hd.\n"
1091 #define ACMSG6 "Font descent != actual descent. Old: %hd New: %hd.\n"
1092 #define ACMSG7 "Font height != actual height. Old: %hd New: %hd.\n"
1093 #define ACMSG8 "Glyph scalable width (SWIDTH) adjustments made.\n"
1094 #define ACMSG9 "SWIDTH field missing at line %ld. Set automatically.\n"
1095 #define ACMSG10 "DWIDTH field missing at line %ld. Set to glyph width.\n"
1096 #define ACMSG11 "SIZE bits per pixel field adjusted to %hd.\n"
1097 #define ACMSG12 "Duplicate encoding %ld (%s) changed to unencoded.\n"
1098 #define ACMSG13 "Glyph %ld extra rows removed.\n"
1099 #define ACMSG14 "Glyph %ld extra columns removed.\n"
1100 #define ACMSG15 "Incorrect glyph count: %ld indicated but %ld found.\n"
1102 /* Error messages. */
1103 #define ERRMSG1 "[line %ld] Missing \"%s\" line.\n"
1104 #define ERRMSG2 "[line %ld] Font header corrupted or missing fields.\n"
1105 #define ERRMSG3 "[line %ld] Font glyphs corrupted or missing fields.\n"
1106 #define ERRMSG4 "[line %ld] BBX too big.\n"
1110 _bdf_add_comment( bdf_font_t
* font
,
1115 FT_Memory memory
= font
->memory
;
1116 FT_Error error
= BDF_Err_Ok
;
1119 if ( FT_RENEW_ARRAY( font
->comments
,
1121 font
->comments_len
+ len
+ 1 ) )
1124 cp
= font
->comments
+ font
->comments_len
;
1126 FT_MEM_COPY( cp
, comment
, len
);
1129 font
->comments_len
+= len
+ 1;
1136 /* Set the spacing from the font name if it exists, or set it to the */
1137 /* default specified in the options. */
1139 _bdf_set_default_spacing( bdf_font_t
* font
,
1140 bdf_options_t
* opts
)
1146 FT_Error error
= BDF_Err_Ok
;
1149 if ( font
== 0 || font
->name
== 0 || font
->name
[0] == 0 )
1151 error
= BDF_Err_Invalid_Argument
;
1155 memory
= font
->memory
;
1157 _bdf_list_init( &list
, memory
);
1159 font
->spacing
= opts
->font_spacing
;
1161 len
= ft_strlen( font
->name
) + 1;
1162 /* Limit ourselves to 256 characters in the font name. */
1165 error
= BDF_Err_Invalid_Argument
;
1169 FT_MEM_COPY( name
, font
->name
, len
);
1171 error
= _bdf_list_split( &list
, (char *)"-", name
, len
);
1175 if ( list
.used
== 15 )
1177 switch ( list
.field
[11][0] )
1181 font
->spacing
= BDF_CHARCELL
;
1185 font
->spacing
= BDF_MONOWIDTH
;
1189 font
->spacing
= BDF_PROPORTIONAL
;
1195 _bdf_list_done( &list
);
1202 /* Determine whether the property is an atom or not. If it is, then */
1203 /* clean it up so the double quotes are removed if they exist. */
1205 _bdf_is_atom( char* line
,
1206 unsigned long linelen
,
1216 *name
= sp
= ep
= line
;
1218 while ( *ep
&& *ep
!= ' ' && *ep
!= '\t' )
1228 p
= bdf_get_property( sp
, font
);
1230 /* Restore the character that was saved before any return can happen. */
1234 /* If the property exists and is not an atom, just return here. */
1235 if ( p
&& p
->format
!= BDF_ATOM
)
1238 /* The property is an atom. Trim all leading and trailing whitespace */
1239 /* and double quotes for the atom value. */
1241 ep
= line
+ linelen
;
1243 /* Trim the leading whitespace if it exists. */
1246 ( *sp
== ' ' || *sp
== '\t' ) )
1249 /* Trim the leading double quote if it exists. */
1254 /* Trim the trailing whitespace if it exists. */
1256 ( *( ep
- 1 ) == ' ' || *( ep
- 1 ) == '\t' ) )
1259 /* Trim the trailing double quote if it exists. */
1260 if ( ep
> sp
&& *( ep
- 1 ) == '"' )
1268 _bdf_add_property( bdf_font_t
* font
,
1274 bdf_property_t
*prop
, *fp
;
1275 FT_Memory memory
= font
->memory
;
1276 FT_Error error
= BDF_Err_Ok
;
1279 /* First, check to see if the property already exists in the font. */
1280 if ( ( hn
= hash_lookup( name
, (hashtable
*)font
->internal
) ) != 0 )
1282 /* The property already exists in the font, so simply replace */
1283 /* the value of the property with the current value. */
1284 fp
= font
->props
+ hn
->data
;
1286 switch ( fp
->format
)
1289 /* Delete the current atom if it exists. */
1290 FT_FREE( fp
->value
.atom
);
1292 if ( value
&& value
[0] != 0 )
1294 if ( FT_STRDUP( fp
->value
.atom
, value
) )
1300 fp
->value
.l
= _bdf_atol( value
, 0, 10 );
1304 fp
->value
.ul
= _bdf_atoul( value
, 0, 10 );
1314 /* See whether this property type exists yet or not. */
1315 /* If not, create it. */
1316 hn
= hash_lookup( name
, &(font
->proptbl
) );
1319 error
= bdf_create_property( name
, BDF_ATOM
, font
);
1322 hn
= hash_lookup( name
, &(font
->proptbl
) );
1325 /* Allocate another property if this is overflow. */
1326 if ( font
->props_used
== font
->props_size
)
1328 if ( font
->props_size
== 0 )
1330 if ( FT_NEW_ARRAY( font
->props
, 1 ) )
1335 if ( FT_RENEW_ARRAY( font
->props
,
1337 font
->props_size
+ 1 ) )
1341 fp
= font
->props
+ font
->props_size
;
1342 FT_MEM_ZERO( fp
, sizeof ( bdf_property_t
) );
1347 if ( propid
>= _num_bdf_properties
)
1348 prop
= font
->user_props
+ ( propid
- _num_bdf_properties
);
1350 prop
= (bdf_property_t
*)_bdf_properties
+ propid
;
1352 fp
= font
->props
+ font
->props_used
;
1354 fp
->name
= prop
->name
;
1355 fp
->format
= prop
->format
;
1356 fp
->builtin
= prop
->builtin
;
1358 switch ( prop
->format
)
1362 if ( value
!= 0 && value
[0] )
1364 if ( FT_STRDUP( fp
->value
.atom
, value
) )
1370 fp
->value
.l
= _bdf_atol( value
, 0, 10 );
1374 fp
->value
.ul
= _bdf_atoul( value
, 0, 10 );
1378 /* If the property happens to be a comment, then it doesn't need */
1379 /* to be added to the internal hash table. */
1380 if ( ft_memcmp( name
, "COMMENT", 7 ) != 0 )
1382 /* Add the property to the font property table. */
1383 error
= hash_insert( fp
->name
,
1385 (hashtable
*)font
->internal
,
1393 /* Some special cases need to be handled here. The DEFAULT_CHAR */
1394 /* property needs to be located if it exists in the property list, the */
1395 /* FONT_ASCENT and FONT_DESCENT need to be assigned if they are */
1396 /* present, and the SPACING property should override the default */
1398 if ( ft_memcmp( name
, "DEFAULT_CHAR", 12 ) == 0 )
1399 font
->default_char
= fp
->value
.l
;
1400 else if ( ft_memcmp( name
, "FONT_ASCENT", 11 ) == 0 )
1401 font
->font_ascent
= fp
->value
.l
;
1402 else if ( ft_memcmp( name
, "FONT_DESCENT", 12 ) == 0 )
1403 font
->font_descent
= fp
->value
.l
;
1404 else if ( ft_memcmp( name
, "SPACING", 7 ) == 0 )
1406 if ( !fp
->value
.atom
)
1408 error
= BDF_Err_Invalid_File_Format
;
1412 if ( fp
->value
.atom
[0] == 'p' || fp
->value
.atom
[0] == 'P' )
1413 font
->spacing
= BDF_PROPORTIONAL
;
1414 else if ( fp
->value
.atom
[0] == 'm' || fp
->value
.atom
[0] == 'M' )
1415 font
->spacing
= BDF_MONOWIDTH
;
1416 else if ( fp
->value
.atom
[0] == 'c' || fp
->value
.atom
[0] == 'C' )
1417 font
->spacing
= BDF_CHARCELL
;
1425 static const unsigned char nibble_mask
[8] =
1427 0xFF, 0x80, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC, 0xFE
1431 /* Actually parse the glyph info and bitmaps. */
1433 _bdf_parse_glyphs( char* line
,
1434 unsigned long linelen
,
1435 unsigned long lineno
,
1442 unsigned long i
, slen
, nibbles
;
1449 FT_Error error
= BDF_Err_Ok
;
1451 FT_UNUSED( call_data
);
1452 FT_UNUSED( lineno
); /* only used in debug mode */
1455 p
= (_bdf_parse_t
*)client_data
;
1458 memory
= font
->memory
;
1460 /* Check for a comment. */
1461 if ( ft_memcmp( line
, "COMMENT", 7 ) == 0 )
1471 error
= _bdf_add_comment( p
->font
, s
, linelen
);
1475 /* The very first thing expected is the number of glyphs. */
1476 if ( !( p
->flags
& _BDF_GLYPHS
) )
1478 if ( ft_memcmp( line
, "CHARS", 5 ) != 0 )
1480 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1
, lineno
, "CHARS" ));
1481 error
= BDF_Err_Missing_Chars_Field
;
1485 error
= _bdf_list_split( &p
->list
, (char *)" +", line
, linelen
);
1488 p
->cnt
= font
->glyphs_size
= _bdf_atoul( p
->list
.field
[1], 0, 10 );
1490 /* Make sure the number of glyphs is non-zero. */
1492 font
->glyphs_size
= 64;
1494 /* Limit ourselves to 1,114,112 glyphs in the font (this is the */
1495 /* number of code points available in Unicode). */
1496 if ( p
->cnt
>= 1114112UL )
1498 error
= BDF_Err_Invalid_Argument
;
1502 if ( FT_NEW_ARRAY( font
->glyphs
, font
->glyphs_size
) )
1505 p
->flags
|= _BDF_GLYPHS
;
1510 /* Check for the ENDFONT field. */
1511 if ( ft_memcmp( line
, "ENDFONT", 7 ) == 0 )
1513 /* Sort the glyphs by encoding. */
1514 ft_qsort( (char *)font
->glyphs
,
1516 sizeof ( bdf_glyph_t
),
1519 p
->flags
&= ~_BDF_START
;
1524 /* Check for the ENDCHAR field. */
1525 if ( ft_memcmp( line
, "ENDCHAR", 7 ) == 0 )
1528 p
->flags
&= ~_BDF_GLYPH_BITS
;
1533 /* Check to see whether a glyph is being scanned but should be */
1534 /* ignored because it is an unencoded glyph. */
1535 if ( ( p
->flags
& _BDF_GLYPH
) &&
1536 p
->glyph_enc
== -1 &&
1537 p
->opts
->keep_unencoded
== 0 )
1540 /* Check for the STARTCHAR field. */
1541 if ( ft_memcmp( line
, "STARTCHAR", 9 ) == 0 )
1543 /* Set the character name in the parse info first until the */
1544 /* encoding can be checked for an unencoded character. */
1545 FT_FREE( p
->glyph_name
);
1547 error
= _bdf_list_split( &p
->list
, (char *)" +", line
, linelen
);
1551 _bdf_list_shift( &p
->list
, 1 );
1553 s
= _bdf_list_join( &p
->list
, ' ', &slen
);
1557 error
= BDF_Err_Invalid_File_Format
;
1561 if ( FT_NEW_ARRAY( p
->glyph_name
, slen
+ 1 ) )
1564 FT_MEM_COPY( p
->glyph_name
, s
, slen
+ 1 );
1566 p
->flags
|= _BDF_GLYPH
;
1571 /* Check for the ENCODING field. */
1572 if ( ft_memcmp( line
, "ENCODING", 8 ) == 0 )
1574 if ( !( p
->flags
& _BDF_GLYPH
) )
1576 /* Missing STARTCHAR field. */
1577 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1
, lineno
, "STARTCHAR" ));
1578 error
= BDF_Err_Missing_Startchar_Field
;
1582 error
= _bdf_list_split( &p
->list
, (char *)" +", line
, linelen
);
1586 p
->glyph_enc
= _bdf_atol( p
->list
.field
[1], 0, 10 );
1588 /* Check that the encoding is in the range [0,65536] because */
1589 /* otherwise p->have (a bitmap with static size) overflows. */
1590 if ( (size_t)p
->glyph_enc
>= sizeof ( p
->have
) * 8 )
1592 error
= BDF_Err_Invalid_File_Format
;
1596 /* Check to see whether this encoding has already been encountered. */
1597 /* If it has then change it to unencoded so it gets added if */
1599 if ( p
->glyph_enc
>= 0 )
1601 if ( _bdf_glyph_modified( p
->have
, p
->glyph_enc
) )
1603 /* Emit a message saying a glyph has been moved to the */
1604 /* unencoded area. */
1605 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG12
,
1606 p
->glyph_enc
, p
->glyph_name
));
1611 _bdf_set_glyph_modified( p
->have
, p
->glyph_enc
);
1614 if ( p
->glyph_enc
>= 0 )
1616 /* Make sure there are enough glyphs allocated in case the */
1617 /* number of characters happen to be wrong. */
1618 if ( font
->glyphs_used
== font
->glyphs_size
)
1620 if ( FT_RENEW_ARRAY( font
->glyphs
,
1622 font
->glyphs_size
+ 64 ) )
1625 font
->glyphs_size
+= 64;
1628 glyph
= font
->glyphs
+ font
->glyphs_used
++;
1629 glyph
->name
= p
->glyph_name
;
1630 glyph
->encoding
= p
->glyph_enc
;
1632 /* Reset the initial glyph info. */
1637 /* Unencoded glyph. Check to see whether it should */
1638 /* be added or not. */
1639 if ( p
->opts
->keep_unencoded
!= 0 )
1641 /* Allocate the next unencoded glyph. */
1642 if ( font
->unencoded_used
== font
->unencoded_size
)
1644 if ( FT_RENEW_ARRAY( font
->unencoded
,
1645 font
->unencoded_size
,
1646 font
->unencoded_size
+ 4 ) )
1649 font
->unencoded_size
+= 4;
1652 glyph
= font
->unencoded
+ font
->unencoded_used
;
1653 glyph
->name
= p
->glyph_name
;
1654 glyph
->encoding
= font
->unencoded_used
++;
1657 /* Free up the glyph name if the unencoded shouldn't be */
1659 FT_FREE( p
->glyph_name
);
1664 /* Clear the flags that might be added when width and height are */
1665 /* checked for consistency. */
1666 p
->flags
&= ~( _BDF_GLYPH_WIDTH_CHECK
| _BDF_GLYPH_HEIGHT_CHECK
);
1668 p
->flags
|= _BDF_ENCODING
;
1673 /* Point at the glyph being constructed. */
1674 if ( p
->glyph_enc
== -1 )
1675 glyph
= font
->unencoded
+ ( font
->unencoded_used
- 1 );
1677 glyph
= font
->glyphs
+ ( font
->glyphs_used
- 1 );
1679 /* Check to see whether a bitmap is being constructed. */
1680 if ( p
->flags
& _BDF_BITMAP
)
1682 /* If there are more rows than are specified in the glyph metrics, */
1683 /* ignore the remaining lines. */
1684 if ( p
->row
>= (unsigned long)glyph
->bbx
.height
)
1686 if ( !( p
->flags
& _BDF_GLYPH_HEIGHT_CHECK
) )
1688 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG13
, glyph
->encoding
));
1689 p
->flags
|= _BDF_GLYPH_HEIGHT_CHECK
;
1696 /* Only collect the number of nibbles indicated by the glyph */
1697 /* metrics. If there are more columns, they are simply ignored. */
1698 nibbles
= glyph
->bpr
<< 1;
1699 bp
= glyph
->bitmap
+ p
->row
* glyph
->bpr
;
1701 for ( i
= 0; i
< nibbles
; i
++ )
1704 *bp
= (FT_Byte
)( ( *bp
<< 4 ) + a2i
[c
] );
1705 if ( i
+ 1 < nibbles
&& ( i
& 1 ) )
1709 /* Remove possible garbage at the right. */
1710 mask_index
= ( glyph
->bbx
.width
* p
->font
->bpp
) & 7;
1711 if ( glyph
->bbx
.width
)
1712 *bp
&= nibble_mask
[mask_index
];
1714 /* If any line has extra columns, indicate they have been removed. */
1715 if ( ( line
[nibbles
] == '0' || a2i
[(int)line
[nibbles
]] != 0 ) &&
1716 !( p
->flags
& _BDF_GLYPH_WIDTH_CHECK
) )
1718 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG14
, glyph
->encoding
));
1719 p
->flags
|= _BDF_GLYPH_WIDTH_CHECK
;
1727 /* Expect the SWIDTH (scalable width) field next. */
1728 if ( ft_memcmp( line
, "SWIDTH", 6 ) == 0 )
1730 if ( !( p
->flags
& _BDF_ENCODING
) )
1732 /* Missing ENCODING field. */
1733 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1
, lineno
, "ENCODING" ));
1734 error
= BDF_Err_Missing_Encoding_Field
;
1738 error
= _bdf_list_split( &p
->list
, (char *)" +", line
, linelen
);
1742 glyph
->swidth
= (unsigned short)_bdf_atoul( p
->list
.field
[1], 0, 10 );
1743 p
->flags
|= _BDF_SWIDTH
;
1748 /* Expect the DWIDTH (scalable width) field next. */
1749 if ( ft_memcmp( line
, "DWIDTH", 6 ) == 0 )
1751 error
= _bdf_list_split( &p
->list
, (char *)" +", line
, linelen
);
1755 glyph
->dwidth
= (unsigned short)_bdf_atoul( p
->list
.field
[1], 0, 10 );
1757 if ( !( p
->flags
& _BDF_SWIDTH
) )
1759 /* Missing SWIDTH field. Emit an auto correction message and set */
1760 /* the scalable width from the device width. */
1761 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG9
, lineno
));
1763 glyph
->swidth
= (unsigned short)FT_MulDiv(
1764 glyph
->dwidth
, 72000L,
1765 (FT_Long
)( font
->point_size
*
1766 font
->resolution_x
) );
1769 p
->flags
|= _BDF_DWIDTH
;
1773 /* Expect the BBX field next. */
1774 if ( ft_memcmp( line
, "BBX", 3 ) == 0 )
1776 error
= _bdf_list_split( &p
->list
, (char *)" +", line
, linelen
);
1780 glyph
->bbx
.width
= _bdf_atos( p
->list
.field
[1], 0, 10 );
1781 glyph
->bbx
.height
= _bdf_atos( p
->list
.field
[2], 0, 10 );
1782 glyph
->bbx
.x_offset
= _bdf_atos( p
->list
.field
[3], 0, 10 );
1783 glyph
->bbx
.y_offset
= _bdf_atos( p
->list
.field
[4], 0, 10 );
1785 /* Generate the ascent and descent of the character. */
1786 glyph
->bbx
.ascent
= (short)( glyph
->bbx
.height
+ glyph
->bbx
.y_offset
);
1787 glyph
->bbx
.descent
= (short)( -glyph
->bbx
.y_offset
);
1789 /* Determine the overall font bounding box as the characters are */
1790 /* loaded so corrections can be done later if indicated. */
1791 p
->maxas
= (short)FT_MAX( glyph
->bbx
.ascent
, p
->maxas
);
1792 p
->maxds
= (short)FT_MAX( glyph
->bbx
.descent
, p
->maxds
);
1794 p
->rbearing
= (short)( glyph
->bbx
.width
+ glyph
->bbx
.x_offset
);
1796 p
->maxrb
= (short)FT_MAX( p
->rbearing
, p
->maxrb
);
1797 p
->minlb
= (short)FT_MIN( glyph
->bbx
.x_offset
, p
->minlb
);
1798 p
->maxlb
= (short)FT_MAX( glyph
->bbx
.x_offset
, p
->maxlb
);
1800 if ( !( p
->flags
& _BDF_DWIDTH
) )
1802 /* Missing DWIDTH field. Emit an auto correction message and set */
1803 /* the device width to the glyph width. */
1804 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG10
, lineno
));
1805 glyph
->dwidth
= glyph
->bbx
.width
;
1808 /* If the BDF_CORRECT_METRICS flag is set, then adjust the SWIDTH */
1809 /* value if necessary. */
1810 if ( p
->opts
->correct_metrics
!= 0 )
1812 /* Determine the point size of the glyph. */
1813 unsigned short sw
= (unsigned short)FT_MulDiv(
1814 glyph
->dwidth
, 72000L,
1815 (FT_Long
)( font
->point_size
*
1816 font
->resolution_x
) );
1819 if ( sw
!= glyph
->swidth
)
1823 if ( p
->glyph_enc
== -1 )
1824 _bdf_set_glyph_modified( font
->umod
,
1825 font
->unencoded_used
- 1 );
1827 _bdf_set_glyph_modified( font
->nmod
, glyph
->encoding
);
1829 p
->flags
|= _BDF_SWIDTH_ADJ
;
1834 p
->flags
|= _BDF_BBX
;
1838 /* And finally, gather up the bitmap. */
1839 if ( ft_memcmp( line
, "BITMAP", 6 ) == 0 )
1841 unsigned long bitmap_size
;
1844 if ( !( p
->flags
& _BDF_BBX
) )
1846 /* Missing BBX field. */
1847 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1
, lineno
, "BBX" ));
1848 error
= BDF_Err_Missing_Bbx_Field
;
1852 /* Allocate enough space for the bitmap. */
1853 glyph
->bpr
= ( glyph
->bbx
.width
* p
->font
->bpp
+ 7 ) >> 3;
1855 bitmap_size
= glyph
->bpr
* glyph
->bbx
.height
;
1856 if ( bitmap_size
> 0xFFFFU
)
1858 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG4
, lineno
));
1859 error
= BDF_Err_Bbx_Too_Big
;
1863 glyph
->bytes
= (unsigned short)bitmap_size
;
1865 if ( FT_NEW_ARRAY( glyph
->bitmap
, glyph
->bytes
) )
1869 p
->flags
|= _BDF_BITMAP
;
1874 error
= BDF_Err_Invalid_File_Format
;
1877 if ( error
&& ( p
->flags
& _BDF_GLYPH
) )
1878 FT_FREE( p
->glyph_name
);
1884 /* Load the font properties. */
1886 _bdf_parse_properties( char* line
,
1887 unsigned long linelen
,
1888 unsigned long lineno
,
1893 _bdf_line_func_t
* next
;
1898 FT_Error error
= BDF_Err_Ok
;
1900 FT_UNUSED( lineno
);
1903 next
= (_bdf_line_func_t
*)call_data
;
1904 p
= (_bdf_parse_t
*) client_data
;
1906 /* Check for the end of the properties. */
1907 if ( ft_memcmp( line
, "ENDPROPERTIES", 13 ) == 0 )
1909 /* If the FONT_ASCENT or FONT_DESCENT properties have not been */
1910 /* encountered yet, then make sure they are added as properties and */
1911 /* make sure they are set from the font bounding box info. */
1913 /* This is *always* done regardless of the options, because X11 */
1914 /* requires these two fields to compile fonts. */
1915 if ( bdf_get_font_property( p
->font
, "FONT_ASCENT" ) == 0 )
1917 p
->font
->font_ascent
= p
->font
->bbx
.ascent
;
1918 ft_sprintf( nbuf
, "%hd", p
->font
->bbx
.ascent
);
1919 error
= _bdf_add_property( p
->font
, (char *)"FONT_ASCENT", nbuf
);
1923 FT_TRACE2(( "_bdf_parse_properties: " ACMSG1
, p
->font
->bbx
.ascent
));
1924 p
->font
->modified
= 1;
1927 if ( bdf_get_font_property( p
->font
, "FONT_DESCENT" ) == 0 )
1929 p
->font
->font_descent
= p
->font
->bbx
.descent
;
1930 ft_sprintf( nbuf
, "%hd", p
->font
->bbx
.descent
);
1931 error
= _bdf_add_property( p
->font
, (char *)"FONT_DESCENT", nbuf
);
1935 FT_TRACE2(( "_bdf_parse_properties: " ACMSG2
, p
->font
->bbx
.descent
));
1936 p
->font
->modified
= 1;
1939 p
->flags
&= ~_BDF_PROPS
;
1940 *next
= _bdf_parse_glyphs
;
1945 /* Ignore the _XFREE86_GLYPH_RANGES properties. */
1946 if ( ft_memcmp( line
, "_XFREE86_GLYPH_RANGES", 21 ) == 0 )
1949 /* Handle COMMENT fields and properties in a special way to preserve */
1951 if ( ft_memcmp( line
, "COMMENT", 7 ) == 0 )
1953 name
= value
= line
;
1957 error
= _bdf_add_property( p
->font
, name
, value
);
1961 else if ( _bdf_is_atom( line
, linelen
, &name
, &value
, p
->font
) )
1963 error
= _bdf_add_property( p
->font
, name
, value
);
1969 error
= _bdf_list_split( &p
->list
, (char *)" +", line
, linelen
);
1972 name
= p
->list
.field
[0];
1974 _bdf_list_shift( &p
->list
, 1 );
1975 value
= _bdf_list_join( &p
->list
, ' ', &vlen
);
1977 error
= _bdf_add_property( p
->font
, name
, value
);
1987 /* Load the font header. */
1989 _bdf_parse_start( char* line
,
1990 unsigned long linelen
,
1991 unsigned long lineno
,
1996 _bdf_line_func_t
* next
;
2001 FT_Memory memory
= NULL
;
2002 FT_Error error
= BDF_Err_Ok
;
2004 FT_UNUSED( lineno
); /* only used in debug mode */
2007 next
= (_bdf_line_func_t
*)call_data
;
2008 p
= (_bdf_parse_t
*) client_data
;
2011 memory
= p
->font
->memory
;
2013 /* Check for a comment. This is done to handle those fonts that have */
2014 /* comments before the STARTFONT line for some reason. */
2015 if ( ft_memcmp( line
, "COMMENT", 7 ) == 0 )
2017 if ( p
->opts
->keep_comments
!= 0 && p
->font
!= 0 )
2028 error
= _bdf_add_comment( p
->font
, s
, linelen
);
2031 /* here font is not defined! */
2037 if ( !( p
->flags
& _BDF_START
) )
2041 if ( ft_memcmp( line
, "STARTFONT", 9 ) != 0 )
2043 /* No STARTFONT field is a good indication of a problem. */
2044 error
= BDF_Err_Missing_Startfont_Field
;
2048 p
->flags
= _BDF_START
;
2051 if ( FT_NEW( font
) )
2055 font
->memory
= p
->memory
;
2060 bdf_property_t
* prop
;
2063 error
= hash_init( &(font
->proptbl
), memory
);
2066 for ( i
= 0, prop
= (bdf_property_t
*)_bdf_properties
;
2067 i
< _num_bdf_properties
; i
++, prop
++ )
2069 error
= hash_insert( prop
->name
, i
,
2070 &(font
->proptbl
), memory
);
2076 if ( FT_ALLOC( p
->font
->internal
, sizeof ( hashtable
) ) )
2078 error
= hash_init( (hashtable
*)p
->font
->internal
,memory
);
2081 p
->font
->spacing
= p
->opts
->font_spacing
;
2082 p
->font
->default_char
= -1;
2087 /* Check for the start of the properties. */
2088 if ( ft_memcmp( line
, "STARTPROPERTIES", 15 ) == 0 )
2090 if ( !( p
->flags
& _BDF_FONT_BBX
) )
2092 /* Missing the FONTBOUNDINGBOX field. */
2093 FT_ERROR(( "_bdf_parse_start: " ERRMSG1
, lineno
, "FONTBOUNDINGBOX" ));
2094 error
= BDF_Err_Missing_Fontboundingbox_Field
;
2098 error
= _bdf_list_split( &p
->list
, (char *)" +", line
, linelen
);
2101 /* at this point, `p->font' can't be NULL */
2102 p
->cnt
= p
->font
->props_size
= _bdf_atoul( p
->list
.field
[1], 0, 10 );
2104 if ( FT_NEW_ARRAY( p
->font
->props
, p
->cnt
) )
2107 p
->flags
|= _BDF_PROPS
;
2108 *next
= _bdf_parse_properties
;
2113 /* Check for the FONTBOUNDINGBOX field. */
2114 if ( ft_memcmp( line
, "FONTBOUNDINGBOX", 15 ) == 0 )
2116 if ( !( p
->flags
& _BDF_SIZE
) )
2118 /* Missing the SIZE field. */
2119 FT_ERROR(( "_bdf_parse_start: " ERRMSG1
, lineno
, "SIZE" ));
2120 error
= BDF_Err_Missing_Size_Field
;
2124 error
= _bdf_list_split( &p
->list
, (char *)" +", line
, linelen
);
2128 p
->font
->bbx
.width
= _bdf_atos( p
->list
.field
[1], 0, 10 );
2129 p
->font
->bbx
.height
= _bdf_atos( p
->list
.field
[2], 0, 10 );
2131 p
->font
->bbx
.x_offset
= _bdf_atos( p
->list
.field
[3], 0, 10 );
2132 p
->font
->bbx
.y_offset
= _bdf_atos( p
->list
.field
[4], 0, 10 );
2134 p
->font
->bbx
.ascent
= (short)( p
->font
->bbx
.height
+
2135 p
->font
->bbx
.y_offset
);
2137 p
->font
->bbx
.descent
= (short)( -p
->font
->bbx
.y_offset
);
2139 p
->flags
|= _BDF_FONT_BBX
;
2144 /* The next thing to check for is the FONT field. */
2145 if ( ft_memcmp( line
, "FONT", 4 ) == 0 )
2147 error
= _bdf_list_split( &p
->list
, (char *)" +", line
, linelen
);
2150 _bdf_list_shift( &p
->list
, 1 );
2152 s
= _bdf_list_join( &p
->list
, ' ', &slen
);
2156 error
= BDF_Err_Invalid_File_Format
;
2160 /* Allowing multiple `FONT' lines (which is invalid) doesn't hurt... */
2161 FT_FREE( p
->font
->name
);
2163 if ( FT_NEW_ARRAY( p
->font
->name
, slen
+ 1 ) )
2165 FT_MEM_COPY( p
->font
->name
, s
, slen
+ 1 );
2167 /* If the font name is an XLFD name, set the spacing to the one in */
2168 /* the font name. If there is no spacing fall back on the default. */
2169 error
= _bdf_set_default_spacing( p
->font
, p
->opts
);
2173 p
->flags
|= _BDF_FONT_NAME
;
2178 /* Check for the SIZE field. */
2179 if ( ft_memcmp( line
, "SIZE", 4 ) == 0 )
2181 if ( !( p
->flags
& _BDF_FONT_NAME
) )
2183 /* Missing the FONT field. */
2184 FT_ERROR(( "_bdf_parse_start: " ERRMSG1
, lineno
, "FONT" ));
2185 error
= BDF_Err_Missing_Font_Field
;
2189 error
= _bdf_list_split( &p
->list
, (char *)" +", line
, linelen
);
2193 p
->font
->point_size
= _bdf_atoul( p
->list
.field
[1], 0, 10 );
2194 p
->font
->resolution_x
= _bdf_atoul( p
->list
.field
[2], 0, 10 );
2195 p
->font
->resolution_y
= _bdf_atoul( p
->list
.field
[3], 0, 10 );
2197 /* Check for the bits per pixel field. */
2198 if ( p
->list
.used
== 5 )
2200 unsigned short bitcount
, i
, shift
;
2203 p
->font
->bpp
= (unsigned short)_bdf_atos( p
->list
.field
[4], 0, 10 );
2205 /* Only values 1, 2, 4, 8 are allowed. */
2206 shift
= p
->font
->bpp
;
2208 for ( i
= 0; shift
> 0; i
++ )
2215 shift
= (short)( ( bitcount
> 3 ) ? 8 : ( 1 << bitcount
) );
2217 if ( p
->font
->bpp
> shift
|| p
->font
->bpp
!= shift
)
2219 /* select next higher value */
2220 p
->font
->bpp
= (unsigned short)( shift
<< 1 );
2221 FT_TRACE2(( "_bdf_parse_start: " ACMSG11
, p
->font
->bpp
));
2227 p
->flags
|= _BDF_SIZE
;
2232 /* Check for the CHARS field -- font properties are optional */
2233 if ( ft_memcmp( line
, "CHARS", 5 ) == 0 )
2238 if ( !( p
->flags
& _BDF_FONT_BBX
) )
2240 /* Missing the FONTBOUNDINGBOX field. */
2241 FT_ERROR(( "_bdf_parse_start: " ERRMSG1
, lineno
, "FONTBOUNDINGBOX" ));
2242 error
= BDF_Err_Missing_Fontboundingbox_Field
;
2246 /* Add the two standard X11 properties which are required */
2247 /* for compiling fonts. */
2248 p
->font
->font_ascent
= p
->font
->bbx
.ascent
;
2249 ft_sprintf( nbuf
, "%hd", p
->font
->bbx
.ascent
);
2250 error
= _bdf_add_property( p
->font
, (char *)"FONT_ASCENT", nbuf
);
2253 FT_TRACE2(( "_bdf_parse_properties: " ACMSG1
, p
->font
->bbx
.ascent
));
2255 p
->font
->font_descent
= p
->font
->bbx
.descent
;
2256 ft_sprintf( nbuf
, "%hd", p
->font
->bbx
.descent
);
2257 error
= _bdf_add_property( p
->font
, (char *)"FONT_DESCENT", nbuf
);
2260 FT_TRACE2(( "_bdf_parse_properties: " ACMSG2
, p
->font
->bbx
.descent
));
2262 p
->font
->modified
= 1;
2264 *next
= _bdf_parse_glyphs
;
2266 /* A special return value. */
2271 error
= BDF_Err_Invalid_File_Format
;
2278 /*************************************************************************/
2282 /*************************************************************************/
2285 FT_LOCAL_DEF( FT_Error
)
2286 bdf_load_font( FT_Stream stream
,
2287 FT_Memory extmemory
,
2288 bdf_options_t
* opts
,
2291 unsigned long lineno
= 0; /* make compiler happy */
2292 _bdf_parse_t
*p
= NULL
;
2294 FT_Memory memory
= extmemory
;
2295 FT_Error error
= BDF_Err_Ok
;
2302 p
->opts
= (bdf_options_t
*)( ( opts
!= 0 ) ? opts
: &_bdf_opts
);
2304 p
->memory
= extmemory
; /* only during font creation */
2306 _bdf_list_init( &p
->list
, extmemory
);
2308 error
= _bdf_readstream( stream
, _bdf_parse_start
,
2309 (void *)p
, &lineno
);
2315 /* If the font is not proportional, set the font's monowidth */
2316 /* field to the width of the font bounding box. */
2317 memory
= p
->font
->memory
;
2319 if ( p
->font
->spacing
!= BDF_PROPORTIONAL
)
2320 p
->font
->monowidth
= p
->font
->bbx
.width
;
2322 /* If the number of glyphs loaded is not that of the original count, */
2323 /* indicate the difference. */
2324 if ( p
->cnt
!= p
->font
->glyphs_used
+ p
->font
->unencoded_used
)
2326 FT_TRACE2(( "bdf_load_font: " ACMSG15
, p
->cnt
,
2327 p
->font
->glyphs_used
+ p
->font
->unencoded_used
));
2328 p
->font
->modified
= 1;
2331 /* Once the font has been loaded, adjust the overall font metrics if */
2333 if ( p
->opts
->correct_metrics
!= 0 &&
2334 ( p
->font
->glyphs_used
> 0 || p
->font
->unencoded_used
> 0 ) )
2336 if ( p
->maxrb
- p
->minlb
!= p
->font
->bbx
.width
)
2338 FT_TRACE2(( "bdf_load_font: " ACMSG3
,
2339 p
->font
->bbx
.width
, p
->maxrb
- p
->minlb
));
2340 p
->font
->bbx
.width
= (unsigned short)( p
->maxrb
- p
->minlb
);
2341 p
->font
->modified
= 1;
2344 if ( p
->font
->bbx
.x_offset
!= p
->minlb
)
2346 FT_TRACE2(( "bdf_load_font: " ACMSG4
,
2347 p
->font
->bbx
.x_offset
, p
->minlb
));
2348 p
->font
->bbx
.x_offset
= p
->minlb
;
2349 p
->font
->modified
= 1;
2352 if ( p
->font
->bbx
.ascent
!= p
->maxas
)
2354 FT_TRACE2(( "bdf_load_font: " ACMSG5
,
2355 p
->font
->bbx
.ascent
, p
->maxas
));
2356 p
->font
->bbx
.ascent
= p
->maxas
;
2357 p
->font
->modified
= 1;
2360 if ( p
->font
->bbx
.descent
!= p
->maxds
)
2362 FT_TRACE2(( "bdf_load_font: " ACMSG6
,
2363 p
->font
->bbx
.descent
, p
->maxds
));
2364 p
->font
->bbx
.descent
= p
->maxds
;
2365 p
->font
->bbx
.y_offset
= (short)( -p
->maxds
);
2366 p
->font
->modified
= 1;
2369 if ( p
->maxas
+ p
->maxds
!= p
->font
->bbx
.height
)
2371 FT_TRACE2(( "bdf_load_font: " ACMSG7
,
2372 p
->font
->bbx
.height
, p
->maxas
+ p
->maxds
));
2373 p
->font
->bbx
.height
= (unsigned short)( p
->maxas
+ p
->maxds
);
2376 if ( p
->flags
& _BDF_SWIDTH_ADJ
)
2377 FT_TRACE2(( "bdf_load_font: " ACMSG8
));
2381 if ( p
->flags
& _BDF_START
)
2384 /* The ENDFONT field was never reached or did not exist. */
2385 if ( !( p
->flags
& _BDF_GLYPHS
) )
2387 /* Error happened while parsing header. */
2388 FT_ERROR(( "bdf_load_font: " ERRMSG2
, lineno
));
2389 error
= BDF_Err_Corrupted_Font_Header
;
2394 /* Error happened when parsing glyphs. */
2395 FT_ERROR(( "bdf_load_font: " ERRMSG3
, lineno
));
2396 error
= BDF_Err_Corrupted_Font_Glyphs
;
2404 /* Make sure the comments are NULL terminated if they exist. */
2405 memory
= p
->font
->memory
;
2407 if ( p
->font
->comments_len
> 0 )
2409 if ( FT_RENEW_ARRAY( p
->font
->comments
,
2410 p
->font
->comments_len
,
2411 p
->font
->comments_len
+ 1 ) )
2414 p
->font
->comments
[p
->font
->comments_len
] = 0;
2417 else if ( error
== BDF_Err_Ok
)
2418 error
= BDF_Err_Invalid_File_Format
;
2425 _bdf_list_done( &p
->list
);
2435 bdf_free_font( p
->font
);
2445 FT_LOCAL_DEF( void )
2446 bdf_free_font( bdf_font_t
* font
)
2448 bdf_property_t
* prop
;
2450 bdf_glyph_t
* glyphs
;
2457 memory
= font
->memory
;
2459 FT_FREE( font
->name
);
2461 /* Free up the internal hash table of property names. */
2462 if ( font
->internal
)
2464 hash_free( (hashtable
*)font
->internal
, memory
);
2465 FT_FREE( font
->internal
);
2468 /* Free up the comment info. */
2469 FT_FREE( font
->comments
);
2471 /* Free up the properties. */
2472 for ( i
= 0; i
< font
->props_size
; i
++ )
2474 if ( font
->props
[i
].format
== BDF_ATOM
)
2475 FT_FREE( font
->props
[i
].value
.atom
);
2478 FT_FREE( font
->props
);
2480 /* Free up the character info. */
2481 for ( i
= 0, glyphs
= font
->glyphs
;
2482 i
< font
->glyphs_used
; i
++, glyphs
++ )
2484 FT_FREE( glyphs
->name
);
2485 FT_FREE( glyphs
->bitmap
);
2488 for ( i
= 0, glyphs
= font
->unencoded
; i
< font
->unencoded_used
;
2491 FT_FREE( glyphs
->name
);
2492 FT_FREE( glyphs
->bitmap
);
2495 FT_FREE( font
->glyphs
);
2496 FT_FREE( font
->unencoded
);
2498 /* Free up the overflow storage if it was used. */
2499 for ( i
= 0, glyphs
= font
->overflow
.glyphs
;
2500 i
< font
->overflow
.glyphs_used
; i
++, glyphs
++ )
2502 FT_FREE( glyphs
->name
);
2503 FT_FREE( glyphs
->bitmap
);
2506 FT_FREE( font
->overflow
.glyphs
);
2509 hash_free( &(font
->proptbl
), memory
);
2511 /* Free up the user defined properties. */
2512 for ( prop
= font
->user_props
, i
= 0;
2513 i
< font
->nuser_props
; i
++, prop
++ )
2515 FT_FREE( prop
->name
);
2516 if ( prop
->format
== BDF_ATOM
)
2517 FT_FREE( prop
->value
.atom
);
2520 FT_FREE( font
->user_props
);
2522 /* FREE( font ); */ /* XXX Fixme */
2526 FT_LOCAL_DEF( bdf_property_t
* )
2527 bdf_get_font_property( bdf_font_t
* font
,
2533 if ( font
== 0 || font
->props_size
== 0 || name
== 0 || *name
== 0 )
2536 hn
= hash_lookup( name
, (hashtable
*)font
->internal
);
2538 return hn
? ( font
->props
+ hn
->data
) : 0;