2 * Copyright 2000 Computing Research Labs, New Mexico State University
3 * Copyright 2001, 2002, 2003, 2004, 2005, 2006, 2007
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
,
421 FT_Error error
= BDF_Err_Ok
;
424 if ( num_items
> (int)list
->size
)
426 int oldsize
= list
->size
;
427 int newsize
= oldsize
+ ( oldsize
>> 1 ) + 4;
428 int bigsize
= 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
];
474 _bdf_list_join( _bdf_list_t
* list
,
476 unsigned long *alen
)
484 if ( list
== 0 || list
->used
== 0 )
488 for ( i
= j
= 0; i
< list
->used
; i
++ )
494 if ( i
+ 1 < list
->used
)
504 /* An empty string for empty fields. */
506 static const char empty
[1] = { 0 }; /* XXX eliminate this */
510 _bdf_list_split( _bdf_list_t
* list
,
513 unsigned long linelen
)
515 int mult
, final_empty
;
518 FT_Error error
= BDF_Err_Ok
;
521 /* Initialize the list. */
524 /* If the line is empty, then simply return. */
525 if ( linelen
== 0 || line
[0] == 0 )
528 /* In the original code, if the `separators' parameter is NULL or */
529 /* empty, the list is split into individual bytes. We don't need */
530 /* this, so an error is signaled. */
531 if ( separators
== 0 || *separators
== 0 )
533 error
= BDF_Err_Invalid_Argument
;
537 /* Prepare the separator bitmap. */
538 FT_MEM_ZERO( seps
, 32 );
540 /* If the very last character of the separator string is a plus, then */
541 /* set the `mult' flag to indicate that multiple separators should be */
542 /* collapsed into one. */
543 for ( mult
= 0, sp
= separators
; sp
&& *sp
; sp
++ )
545 if ( *sp
== '+' && *( sp
+ 1 ) == 0 )
548 setsbit( seps
, *sp
);
551 /* Break the line up into fields. */
552 for ( final_empty
= 0, sp
= ep
= line
, end
= sp
+ linelen
;
555 /* Collect everything that is not a separator. */
556 for ( ; *ep
&& !sbitset( seps
, *ep
); ep
++ )
559 /* Resize the list if necessary. */
560 if ( list
->used
== list
->size
)
562 error
= _bdf_list_ensure( list
, list
->used
+ 1 );
567 /* Assign the field appropriately. */
568 list
->field
[list
->used
++] = ( ep
> sp
) ? sp
: (char*)empty
;
574 /* If multiple separators should be collapsed, do it now by */
575 /* setting all the separator characters to 0. */
576 for ( ; *ep
&& sbitset( seps
, *ep
); ep
++ )
580 /* Don't collapse multiple separators by making them 0, so just */
581 /* make the one encountered 0. */
584 final_empty
= ( ep
> sp
&& *ep
== 0 );
588 /* Finally, NULL-terminate the list. */
589 if ( list
->used
+ final_empty
>= list
->size
)
591 error
= _bdf_list_ensure( list
, list
->used
+ final_empty
+ 1 );
597 list
->field
[list
->used
++] = (char*)empty
;
599 list
->field
[list
->used
] = 0;
606 #define NO_SKIP 256 /* this value cannot be stored in a 'char' */
610 _bdf_readstream( FT_Stream stream
,
611 _bdf_line_func_t callback
,
616 unsigned long lineno
, buf_size
;
617 int refill
, bytes
, hold
, to_skip
;
618 int start
, end
, cursor
, avail
;
620 FT_Memory memory
= stream
->memory
;
621 FT_Error error
= BDF_Err_Ok
;
626 error
= BDF_Err_Invalid_Argument
;
630 /* initial size and allocation of the input buffer */
633 if ( FT_NEW_ARRAY( buf
, buf_size
) )
645 bytes
= 0; /* make compiler happy */
651 bytes
= (int)FT_Stream_TryRead( stream
, (FT_Byte
*)buf
+ cursor
,
652 (FT_ULong
)(buf_size
- cursor
) );
653 avail
= cursor
+ bytes
;
660 /* should we skip an optional character like \n or \r? */
661 if ( start
< avail
&& buf
[start
] == to_skip
)
668 /* try to find the end of the line */
669 while ( end
< avail
&& buf
[end
] != '\n' && buf
[end
] != '\r' )
672 /* if we hit the end of the buffer, try shifting its content */
673 /* or even resizing it */
676 if ( bytes
== 0 ) /* last line in file doesn't end in \r or \n */
677 break; /* ignore it then exit */
681 /* this line is definitely too long; try resizing the input */
682 /* buffer a bit to handle it. */
686 if ( buf_size
>= 65536UL ) /* limit ourselves to 64KByte */
688 error
= BDF_Err_Invalid_Argument
;
692 new_size
= buf_size
* 2;
693 if ( FT_RENEW_ARRAY( buf
, buf_size
, new_size
) )
701 bytes
= avail
- start
;
703 FT_MEM_COPY( buf
, buf
+ start
, bytes
);
713 /* Temporarily NUL-terminate the line. */
717 /* XXX: Use encoding independent value for 0x1a */
718 if ( buf
[start
] != '#' && buf
[start
] != 0x1a && end
> start
)
720 error
= (*cb
)( buf
+ start
, end
- start
, lineno
,
721 (void*)&cb
, client_data
);
727 buf
[end
] = (char)hold
;
732 else if ( hold
== '\r' )
746 /* XXX: make this work with EBCDIC also */
748 static const unsigned char a2i
[128] =
750 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
751 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
752 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
753 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
754 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x00, 0x00,
755 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00,
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, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00,
759 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
760 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
763 static const unsigned char odigits
[32] =
765 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00,
766 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
767 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
768 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
771 static const unsigned char ddigits
[32] =
773 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x03,
774 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
775 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
776 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
779 static const unsigned char hdigits
[32] =
781 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x03,
782 0x7e, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00,
783 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
784 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
788 #define isdigok( m, d ) (m[(d) >> 3] & ( 1 << ( (d) & 7 ) ) )
791 /* Routine to convert an ASCII string into an unsigned long integer. */
798 const unsigned char* dmap
;
801 if ( s
== 0 || *s
== 0 )
804 /* Make sure the radix is something recognizable. Default to 10. */
819 /* Check for the special hex prefix. */
821 ( *( s
+ 1 ) == 'x' || *( s
+ 1 ) == 'X' ) )
828 for ( v
= 0; isdigok( dmap
, *s
); s
++ )
829 v
= v
* base
+ a2i
[(int)*s
];
838 /* Routine to convert an ASCII string into an signed long integer. */
845 const unsigned char* dmap
;
848 if ( s
== 0 || *s
== 0 )
851 /* Make sure the radix is something recognizable. Default to 10. */
866 /* Check for a minus sign. */
874 /* Check for the special hex prefix. */
876 ( *( s
+ 1 ) == 'x' || *( s
+ 1 ) == 'X' ) )
883 for ( v
= 0; isdigok( dmap
, *s
); s
++ )
884 v
= v
* base
+ a2i
[(int)*s
];
889 return ( !neg
) ? v
: -v
;
893 /* Routine to convert an ASCII string into an signed short integer. */
900 const unsigned char* dmap
;
903 if ( s
== 0 || *s
== 0 )
906 /* Make sure the radix is something recognizable. Default to 10. */
921 /* Check for a minus. */
929 /* Check for the special hex prefix. */
931 ( *( s
+ 1 ) == 'x' || *( s
+ 1 ) == 'X' ) )
938 for ( v
= 0; isdigok( dmap
, *s
); s
++ )
939 v
= (short)( v
* base
+ a2i
[(int)*s
] );
944 return (short)( ( !neg
) ? v
: -v
);
948 /* Routine to compare two glyphs by encoding so they can be sorted. */
950 by_encoding( const void* a
,
953 bdf_glyph_t
*c1
, *c2
;
956 c1
= (bdf_glyph_t
*)a
;
957 c2
= (bdf_glyph_t
*)b
;
959 if ( c1
->encoding
< c2
->encoding
)
962 if ( c1
->encoding
> c2
->encoding
)
970 bdf_create_property( char* name
,
976 FT_Memory memory
= font
->memory
;
977 FT_Error error
= BDF_Err_Ok
;
980 /* First check to see if the property has */
981 /* already been added or not. If it has, then */
982 /* simply ignore it. */
983 if ( hash_lookup( name
, &(font
->proptbl
) ) )
986 if ( FT_RENEW_ARRAY( font
->user_props
,
988 font
->nuser_props
+ 1 ) )
991 p
= font
->user_props
+ font
->nuser_props
;
994 n
= (unsigned long)( ft_strlen( name
) + 1 );
996 if ( FT_NEW_ARRAY( p
->name
, n
) )
999 FT_MEM_COPY( (char *)p
->name
, name
, n
);
1004 n
= _num_bdf_properties
+ font
->nuser_props
;
1006 error
= hash_insert( p
->name
, (void *)n
, &(font
->proptbl
), memory
);
1010 font
->nuser_props
++;
1017 FT_LOCAL_DEF( bdf_property_t
* )
1018 bdf_get_property( char* name
,
1022 unsigned long propid
;
1025 if ( name
== 0 || *name
== 0 )
1028 if ( ( hn
= hash_lookup( name
, &(font
->proptbl
) ) ) == 0 )
1031 propid
= (unsigned long)hn
->data
;
1032 if ( propid
>= _num_bdf_properties
)
1033 return font
->user_props
+ ( propid
- _num_bdf_properties
);
1035 return (bdf_property_t
*)_bdf_properties
+ propid
;
1039 /*************************************************************************/
1041 /* BDF font file parsing flags and functions. */
1043 /*************************************************************************/
1048 #define _BDF_START 0x0001
1049 #define _BDF_FONT_NAME 0x0002
1050 #define _BDF_SIZE 0x0004
1051 #define _BDF_FONT_BBX 0x0008
1052 #define _BDF_PROPS 0x0010
1053 #define _BDF_GLYPHS 0x0020
1054 #define _BDF_GLYPH 0x0040
1055 #define _BDF_ENCODING 0x0080
1056 #define _BDF_SWIDTH 0x0100
1057 #define _BDF_DWIDTH 0x0200
1058 #define _BDF_BBX 0x0400
1059 #define _BDF_BITMAP 0x0800
1061 #define _BDF_SWIDTH_ADJ 0x1000
1063 #define _BDF_GLYPH_BITS ( _BDF_GLYPH | \
1070 #define _BDF_GLYPH_WIDTH_CHECK 0x40000000UL
1071 #define _BDF_GLYPH_HEIGHT_CHECK 0x80000000UL
1074 /* Auto correction messages. */
1075 #define ACMSG1 "FONT_ASCENT property missing. " \
1076 "Added \"FONT_ASCENT %hd\".\n"
1077 #define ACMSG2 "FONT_DESCENT property missing. " \
1078 "Added \"FONT_DESCENT %hd\".\n"
1079 #define ACMSG3 "Font width != actual width. Old: %hd New: %hd.\n"
1080 #define ACMSG4 "Font left bearing != actual left bearing. " \
1081 "Old: %hd New: %hd.\n"
1082 #define ACMSG5 "Font ascent != actual ascent. Old: %hd New: %hd.\n"
1083 #define ACMSG6 "Font descent != actual descent. Old: %hd New: %hd.\n"
1084 #define ACMSG7 "Font height != actual height. Old: %hd New: %hd.\n"
1085 #define ACMSG8 "Glyph scalable width (SWIDTH) adjustments made.\n"
1086 #define ACMSG9 "SWIDTH field missing at line %ld. Set automatically.\n"
1087 #define ACMSG10 "DWIDTH field missing at line %ld. Set to glyph width.\n"
1088 #define ACMSG11 "SIZE bits per pixel field adjusted to %hd.\n"
1089 #define ACMSG12 "Duplicate encoding %ld (%s) changed to unencoded.\n"
1090 #define ACMSG13 "Glyph %ld extra rows removed.\n"
1091 #define ACMSG14 "Glyph %ld extra columns removed.\n"
1092 #define ACMSG15 "Incorrect glyph count: %ld indicated but %ld found.\n"
1094 /* Error messages. */
1095 #define ERRMSG1 "[line %ld] Missing \"%s\" line.\n"
1096 #define ERRMSG2 "[line %ld] Font header corrupted or missing fields.\n"
1097 #define ERRMSG3 "[line %ld] Font glyphs corrupted or missing fields.\n"
1098 #define ERRMSG4 "[line %ld] BBX too big.\n"
1102 _bdf_add_comment( bdf_font_t
* font
,
1107 FT_Memory memory
= font
->memory
;
1108 FT_Error error
= BDF_Err_Ok
;
1111 if ( FT_RENEW_ARRAY( font
->comments
,
1113 font
->comments_len
+ len
+ 1 ) )
1116 cp
= font
->comments
+ font
->comments_len
;
1118 FT_MEM_COPY( cp
, comment
, len
);
1121 font
->comments_len
+= len
+ 1;
1128 /* Set the spacing from the font name if it exists, or set it to the */
1129 /* default specified in the options. */
1131 _bdf_set_default_spacing( bdf_font_t
* font
,
1132 bdf_options_t
* opts
)
1138 FT_Error error
= BDF_Err_Ok
;
1141 if ( font
== 0 || font
->name
== 0 || font
->name
[0] == 0 )
1143 error
= BDF_Err_Invalid_Argument
;
1147 memory
= font
->memory
;
1149 _bdf_list_init( &list
, memory
);
1151 font
->spacing
= opts
->font_spacing
;
1153 len
= (unsigned long)( ft_strlen( font
->name
) + 1 );
1154 /* Limit ourselves to 256 characters in the font name. */
1157 error
= BDF_Err_Invalid_Argument
;
1161 FT_MEM_COPY( name
, font
->name
, len
);
1163 error
= _bdf_list_split( &list
, (char *)"-", name
, len
);
1167 if ( list
.used
== 15 )
1169 switch ( list
.field
[11][0] )
1173 font
->spacing
= BDF_CHARCELL
;
1177 font
->spacing
= BDF_MONOWIDTH
;
1181 font
->spacing
= BDF_PROPORTIONAL
;
1187 _bdf_list_done( &list
);
1194 /* Determine whether the property is an atom or not. If it is, then */
1195 /* clean it up so the double quotes are removed if they exist. */
1197 _bdf_is_atom( char* line
,
1198 unsigned long linelen
,
1208 *name
= sp
= ep
= line
;
1210 while ( *ep
&& *ep
!= ' ' && *ep
!= '\t' )
1220 p
= bdf_get_property( sp
, font
);
1222 /* Restore the character that was saved before any return can happen. */
1226 /* If the property exists and is not an atom, just return here. */
1227 if ( p
&& p
->format
!= BDF_ATOM
)
1230 /* The property is an atom. Trim all leading and trailing whitespace */
1231 /* and double quotes for the atom value. */
1233 ep
= line
+ linelen
;
1235 /* Trim the leading whitespace if it exists. */
1238 ( *sp
== ' ' || *sp
== '\t' ) )
1241 /* Trim the leading double quote if it exists. */
1246 /* Trim the trailing whitespace if it exists. */
1248 ( *( ep
- 1 ) == ' ' || *( ep
- 1 ) == '\t' ) )
1251 /* Trim the trailing double quote if it exists. */
1252 if ( ep
> sp
&& *( ep
- 1 ) == '"' )
1260 _bdf_add_property( bdf_font_t
* font
,
1264 unsigned long propid
;
1266 bdf_property_t
*prop
, *fp
;
1267 FT_Memory memory
= font
->memory
;
1268 FT_Error error
= BDF_Err_Ok
;
1271 /* First, check to see if the property already exists in the font. */
1272 if ( ( hn
= hash_lookup( name
, (hashtable
*)font
->internal
) ) != 0 )
1274 /* The property already exists in the font, so simply replace */
1275 /* the value of the property with the current value. */
1276 fp
= font
->props
+ (unsigned long)hn
->data
;
1278 switch ( fp
->format
)
1281 /* Delete the current atom if it exists. */
1282 FT_FREE( fp
->value
.atom
);
1284 if ( value
&& value
[0] != 0 )
1286 if ( FT_STRDUP( fp
->value
.atom
, value
) )
1292 fp
->value
.int32
= _bdf_atol( value
, 0, 10 );
1296 fp
->value
.card32
= _bdf_atoul( value
, 0, 10 );
1306 /* See whether this property type exists yet or not. */
1307 /* If not, create it. */
1308 hn
= hash_lookup( name
, &(font
->proptbl
) );
1311 error
= bdf_create_property( name
, BDF_ATOM
, font
);
1314 hn
= hash_lookup( name
, &(font
->proptbl
) );
1317 /* Allocate another property if this is overflow. */
1318 if ( font
->props_used
== font
->props_size
)
1320 if ( font
->props_size
== 0 )
1322 if ( FT_NEW_ARRAY( font
->props
, 1 ) )
1327 if ( FT_RENEW_ARRAY( font
->props
,
1329 font
->props_size
+ 1 ) )
1333 fp
= font
->props
+ font
->props_size
;
1334 FT_MEM_ZERO( fp
, sizeof ( bdf_property_t
) );
1338 propid
= (unsigned long)hn
->data
;
1339 if ( propid
>= _num_bdf_properties
)
1340 prop
= font
->user_props
+ ( propid
- _num_bdf_properties
);
1342 prop
= (bdf_property_t
*)_bdf_properties
+ propid
;
1344 fp
= font
->props
+ font
->props_used
;
1346 fp
->name
= prop
->name
;
1347 fp
->format
= prop
->format
;
1348 fp
->builtin
= prop
->builtin
;
1350 switch ( prop
->format
)
1354 if ( value
!= 0 && value
[0] )
1356 if ( FT_STRDUP( fp
->value
.atom
, value
) )
1362 fp
->value
.int32
= _bdf_atol( value
, 0, 10 );
1366 fp
->value
.card32
= _bdf_atoul( value
, 0, 10 );
1370 /* If the property happens to be a comment, then it doesn't need */
1371 /* to be added to the internal hash table. */
1372 if ( ft_memcmp( name
, "COMMENT", 7 ) != 0 ) {
1373 /* Add the property to the font property table. */
1374 error
= hash_insert( fp
->name
,
1375 (void *)font
->props_used
,
1376 (hashtable
*)font
->internal
,
1384 /* Some special cases need to be handled here. The DEFAULT_CHAR */
1385 /* property needs to be located if it exists in the property list, the */
1386 /* FONT_ASCENT and FONT_DESCENT need to be assigned if they are */
1387 /* present, and the SPACING property should override the default */
1389 if ( ft_memcmp( name
, "DEFAULT_CHAR", 12 ) == 0 )
1390 font
->default_char
= fp
->value
.int32
;
1391 else if ( ft_memcmp( name
, "FONT_ASCENT", 11 ) == 0 )
1392 font
->font_ascent
= fp
->value
.int32
;
1393 else if ( ft_memcmp( name
, "FONT_DESCENT", 12 ) == 0 )
1394 font
->font_descent
= fp
->value
.int32
;
1395 else if ( ft_memcmp( name
, "SPACING", 7 ) == 0 )
1397 if ( fp
->value
.atom
[0] == 'p' || fp
->value
.atom
[0] == 'P' )
1398 font
->spacing
= BDF_PROPORTIONAL
;
1399 else if ( fp
->value
.atom
[0] == 'm' || fp
->value
.atom
[0] == 'M' )
1400 font
->spacing
= BDF_MONOWIDTH
;
1401 else if ( fp
->value
.atom
[0] == 'c' || fp
->value
.atom
[0] == 'C' )
1402 font
->spacing
= BDF_CHARCELL
;
1410 static const unsigned char nibble_mask
[8] =
1412 0xFF, 0x80, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC, 0xFE
1416 /* Actually parse the glyph info and bitmaps. */
1418 _bdf_parse_glyphs( char* line
,
1419 unsigned long linelen
,
1420 unsigned long lineno
,
1427 unsigned long i
, slen
, nibbles
;
1434 FT_Error error
= BDF_Err_Ok
;
1436 FT_UNUSED( call_data
);
1437 FT_UNUSED( lineno
); /* only used in debug mode */
1440 p
= (_bdf_parse_t
*)client_data
;
1443 memory
= font
->memory
;
1445 /* Check for a comment. */
1446 if ( ft_memcmp( line
, "COMMENT", 7 ) == 0 )
1456 error
= _bdf_add_comment( p
->font
, s
, linelen
);
1460 /* The very first thing expected is the number of glyphs. */
1461 if ( !( p
->flags
& _BDF_GLYPHS
) )
1463 if ( ft_memcmp( line
, "CHARS", 5 ) != 0 )
1465 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1
, lineno
, "CHARS" ));
1466 error
= BDF_Err_Missing_Chars_Field
;
1470 error
= _bdf_list_split( &p
->list
, (char *)" +", line
, linelen
);
1473 p
->cnt
= font
->glyphs_size
= _bdf_atoul( p
->list
.field
[1], 0, 10 );
1475 /* Make sure the number of glyphs is non-zero. */
1477 font
->glyphs_size
= 64;
1479 /* Limit ourselves to 1,114,112 glyphs in the font (this is the */
1480 /* number of code points available in Unicode). */
1481 if ( p
->cnt
>= 1114112UL )
1483 error
= BDF_Err_Invalid_Argument
;
1487 if ( FT_NEW_ARRAY( font
->glyphs
, font
->glyphs_size
) )
1490 p
->flags
|= _BDF_GLYPHS
;
1495 /* Check for the ENDFONT field. */
1496 if ( ft_memcmp( line
, "ENDFONT", 7 ) == 0 )
1498 /* Sort the glyphs by encoding. */
1499 ft_qsort( (char *)font
->glyphs
,
1501 sizeof ( bdf_glyph_t
),
1504 p
->flags
&= ~_BDF_START
;
1509 /* Check for the ENDCHAR field. */
1510 if ( ft_memcmp( line
, "ENDCHAR", 7 ) == 0 )
1513 p
->flags
&= ~_BDF_GLYPH_BITS
;
1518 /* Check to see whether a glyph is being scanned but should be */
1519 /* ignored because it is an unencoded glyph. */
1520 if ( ( p
->flags
& _BDF_GLYPH
) &&
1521 p
->glyph_enc
== -1 &&
1522 p
->opts
->keep_unencoded
== 0 )
1525 /* Check for the STARTCHAR field. */
1526 if ( ft_memcmp( line
, "STARTCHAR", 9 ) == 0 )
1528 /* Set the character name in the parse info first until the */
1529 /* encoding can be checked for an unencoded character. */
1530 FT_FREE( p
->glyph_name
);
1532 error
= _bdf_list_split( &p
->list
, (char *)" +", line
, linelen
);
1536 _bdf_list_shift( &p
->list
, 1 );
1538 s
= _bdf_list_join( &p
->list
, ' ', &slen
);
1542 error
= BDF_Err_Invalid_File_Format
;
1546 if ( FT_NEW_ARRAY( p
->glyph_name
, slen
+ 1 ) )
1549 FT_MEM_COPY( p
->glyph_name
, s
, slen
+ 1 );
1551 p
->flags
|= _BDF_GLYPH
;
1556 /* Check for the ENCODING field. */
1557 if ( ft_memcmp( line
, "ENCODING", 8 ) == 0 )
1559 if ( !( p
->flags
& _BDF_GLYPH
) )
1561 /* Missing STARTCHAR field. */
1562 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1
, lineno
, "STARTCHAR" ));
1563 error
= BDF_Err_Missing_Startchar_Field
;
1567 error
= _bdf_list_split( &p
->list
, (char *)" +", line
, linelen
);
1571 p
->glyph_enc
= _bdf_atol( p
->list
.field
[1], 0, 10 );
1573 /* Check that the encoding is in the range [0,65536] because */
1574 /* otherwise p->have (a bitmap with static size) overflows. */
1575 if ( (size_t)p
->glyph_enc
>= sizeof ( p
->have
) * 8 )
1577 error
= BDF_Err_Invalid_File_Format
;
1581 /* Check to see whether this encoding has already been encountered. */
1582 /* If it has then change it to unencoded so it gets added if */
1584 if ( p
->glyph_enc
>= 0 )
1586 if ( _bdf_glyph_modified( p
->have
, p
->glyph_enc
) )
1588 /* Emit a message saying a glyph has been moved to the */
1589 /* unencoded area. */
1590 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG12
,
1591 p
->glyph_enc
, p
->glyph_name
));
1596 _bdf_set_glyph_modified( p
->have
, p
->glyph_enc
);
1599 if ( p
->glyph_enc
>= 0 )
1601 /* Make sure there are enough glyphs allocated in case the */
1602 /* number of characters happen to be wrong. */
1603 if ( font
->glyphs_used
== font
->glyphs_size
)
1605 if ( FT_RENEW_ARRAY( font
->glyphs
,
1607 font
->glyphs_size
+ 64 ) )
1610 font
->glyphs_size
+= 64;
1613 glyph
= font
->glyphs
+ font
->glyphs_used
++;
1614 glyph
->name
= p
->glyph_name
;
1615 glyph
->encoding
= p
->glyph_enc
;
1617 /* Reset the initial glyph info. */
1622 /* Unencoded glyph. Check to see whether it should */
1623 /* be added or not. */
1624 if ( p
->opts
->keep_unencoded
!= 0 )
1626 /* Allocate the next unencoded glyph. */
1627 if ( font
->unencoded_used
== font
->unencoded_size
)
1629 if ( FT_RENEW_ARRAY( font
->unencoded
,
1630 font
->unencoded_size
,
1631 font
->unencoded_size
+ 4 ) )
1634 font
->unencoded_size
+= 4;
1637 glyph
= font
->unencoded
+ font
->unencoded_used
;
1638 glyph
->name
= p
->glyph_name
;
1639 glyph
->encoding
= font
->unencoded_used
++;
1642 /* Free up the glyph name if the unencoded shouldn't be */
1644 FT_FREE( p
->glyph_name
);
1649 /* Clear the flags that might be added when width and height are */
1650 /* checked for consistency. */
1651 p
->flags
&= ~( _BDF_GLYPH_WIDTH_CHECK
| _BDF_GLYPH_HEIGHT_CHECK
);
1653 p
->flags
|= _BDF_ENCODING
;
1658 /* Point at the glyph being constructed. */
1659 if ( p
->glyph_enc
== -1 )
1660 glyph
= font
->unencoded
+ ( font
->unencoded_used
- 1 );
1662 glyph
= font
->glyphs
+ ( font
->glyphs_used
- 1 );
1664 /* Check to see whether a bitmap is being constructed. */
1665 if ( p
->flags
& _BDF_BITMAP
)
1667 /* If there are more rows than are specified in the glyph metrics, */
1668 /* ignore the remaining lines. */
1669 if ( p
->row
>= (unsigned long)glyph
->bbx
.height
)
1671 if ( !( p
->flags
& _BDF_GLYPH_HEIGHT_CHECK
) )
1673 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG13
, glyph
->encoding
));
1674 p
->flags
|= _BDF_GLYPH_HEIGHT_CHECK
;
1681 /* Only collect the number of nibbles indicated by the glyph */
1682 /* metrics. If there are more columns, they are simply ignored. */
1683 nibbles
= glyph
->bpr
<< 1;
1684 bp
= glyph
->bitmap
+ p
->row
* glyph
->bpr
;
1686 for ( i
= 0; i
< nibbles
; i
++ )
1689 *bp
= (FT_Byte
)( ( *bp
<< 4 ) + a2i
[c
] );
1690 if ( i
+ 1 < nibbles
&& ( i
& 1 ) )
1694 /* Remove possible garbage at the right. */
1695 mask_index
= ( glyph
->bbx
.width
* p
->font
->bpp
) & 7;
1696 if ( glyph
->bbx
.width
)
1697 *bp
&= nibble_mask
[mask_index
];
1699 /* If any line has extra columns, indicate they have been removed. */
1700 if ( ( line
[nibbles
] == '0' || a2i
[(int)line
[nibbles
]] != 0 ) &&
1701 !( p
->flags
& _BDF_GLYPH_WIDTH_CHECK
) )
1703 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG14
, glyph
->encoding
));
1704 p
->flags
|= _BDF_GLYPH_WIDTH_CHECK
;
1712 /* Expect the SWIDTH (scalable width) field next. */
1713 if ( ft_memcmp( line
, "SWIDTH", 6 ) == 0 )
1715 if ( !( p
->flags
& _BDF_ENCODING
) )
1717 /* Missing ENCODING field. */
1718 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1
, lineno
, "ENCODING" ));
1719 error
= BDF_Err_Missing_Encoding_Field
;
1723 error
= _bdf_list_split( &p
->list
, (char *)" +", line
, linelen
);
1727 glyph
->swidth
= (unsigned short)_bdf_atoul( p
->list
.field
[1], 0, 10 );
1728 p
->flags
|= _BDF_SWIDTH
;
1733 /* Expect the DWIDTH (scalable width) field next. */
1734 if ( ft_memcmp( line
, "DWIDTH", 6 ) == 0 )
1736 error
= _bdf_list_split( &p
->list
, (char *)" +", line
, linelen
);
1740 glyph
->dwidth
= (unsigned short)_bdf_atoul( p
->list
.field
[1], 0, 10 );
1742 if ( !( p
->flags
& _BDF_SWIDTH
) )
1744 /* Missing SWIDTH field. Emit an auto correction message and set */
1745 /* the scalable width from the device width. */
1746 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG9
, lineno
));
1748 glyph
->swidth
= (unsigned short)FT_MulDiv(
1749 glyph
->dwidth
, 72000L,
1750 (FT_Long
)( font
->point_size
*
1751 font
->resolution_x
) );
1754 p
->flags
|= _BDF_DWIDTH
;
1758 /* Expect the BBX field next. */
1759 if ( ft_memcmp( line
, "BBX", 3 ) == 0 )
1761 error
= _bdf_list_split( &p
->list
, (char *)" +", line
, linelen
);
1765 glyph
->bbx
.width
= _bdf_atos( p
->list
.field
[1], 0, 10 );
1766 glyph
->bbx
.height
= _bdf_atos( p
->list
.field
[2], 0, 10 );
1767 glyph
->bbx
.x_offset
= _bdf_atos( p
->list
.field
[3], 0, 10 );
1768 glyph
->bbx
.y_offset
= _bdf_atos( p
->list
.field
[4], 0, 10 );
1770 /* Generate the ascent and descent of the character. */
1771 glyph
->bbx
.ascent
= (short)( glyph
->bbx
.height
+ glyph
->bbx
.y_offset
);
1772 glyph
->bbx
.descent
= (short)( -glyph
->bbx
.y_offset
);
1774 /* Determine the overall font bounding box as the characters are */
1775 /* loaded so corrections can be done later if indicated. */
1776 p
->maxas
= (short)FT_MAX( glyph
->bbx
.ascent
, p
->maxas
);
1777 p
->maxds
= (short)FT_MAX( glyph
->bbx
.descent
, p
->maxds
);
1779 p
->rbearing
= (short)( glyph
->bbx
.width
+ glyph
->bbx
.x_offset
);
1781 p
->maxrb
= (short)FT_MAX( p
->rbearing
, p
->maxrb
);
1782 p
->minlb
= (short)FT_MIN( glyph
->bbx
.x_offset
, p
->minlb
);
1783 p
->maxlb
= (short)FT_MAX( glyph
->bbx
.x_offset
, p
->maxlb
);
1785 if ( !( p
->flags
& _BDF_DWIDTH
) )
1787 /* Missing DWIDTH field. Emit an auto correction message and set */
1788 /* the device width to the glyph width. */
1789 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG10
, lineno
));
1790 glyph
->dwidth
= glyph
->bbx
.width
;
1793 /* If the BDF_CORRECT_METRICS flag is set, then adjust the SWIDTH */
1794 /* value if necessary. */
1795 if ( p
->opts
->correct_metrics
!= 0 )
1797 /* Determine the point size of the glyph. */
1798 unsigned short sw
= (unsigned short)FT_MulDiv(
1799 glyph
->dwidth
, 72000L,
1800 (FT_Long
)( font
->point_size
*
1801 font
->resolution_x
) );
1804 if ( sw
!= glyph
->swidth
)
1808 if ( p
->glyph_enc
== -1 )
1809 _bdf_set_glyph_modified( font
->umod
,
1810 font
->unencoded_used
- 1 );
1812 _bdf_set_glyph_modified( font
->nmod
, glyph
->encoding
);
1814 p
->flags
|= _BDF_SWIDTH_ADJ
;
1819 p
->flags
|= _BDF_BBX
;
1823 /* And finally, gather up the bitmap. */
1824 if ( ft_memcmp( line
, "BITMAP", 6 ) == 0 )
1826 unsigned long bitmap_size
;
1829 if ( !( p
->flags
& _BDF_BBX
) )
1831 /* Missing BBX field. */
1832 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1
, lineno
, "BBX" ));
1833 error
= BDF_Err_Missing_Bbx_Field
;
1837 /* Allocate enough space for the bitmap. */
1838 glyph
->bpr
= ( glyph
->bbx
.width
* p
->font
->bpp
+ 7 ) >> 3;
1840 bitmap_size
= glyph
->bpr
* glyph
->bbx
.height
;
1841 if ( bitmap_size
> 0xFFFFU
)
1843 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG4
, lineno
));
1844 error
= BDF_Err_Bbx_Too_Big
;
1848 glyph
->bytes
= (unsigned short)bitmap_size
;
1850 if ( FT_NEW_ARRAY( glyph
->bitmap
, glyph
->bytes
) )
1854 p
->flags
|= _BDF_BITMAP
;
1859 error
= BDF_Err_Invalid_File_Format
;
1866 /* Load the font properties. */
1868 _bdf_parse_properties( char* line
,
1869 unsigned long linelen
,
1870 unsigned long lineno
,
1875 _bdf_line_func_t
* next
;
1880 FT_Error error
= BDF_Err_Ok
;
1882 FT_UNUSED( lineno
);
1885 next
= (_bdf_line_func_t
*)call_data
;
1886 p
= (_bdf_parse_t
*) client_data
;
1888 /* Check for the end of the properties. */
1889 if ( ft_memcmp( line
, "ENDPROPERTIES", 13 ) == 0 )
1891 /* If the FONT_ASCENT or FONT_DESCENT properties have not been */
1892 /* encountered yet, then make sure they are added as properties and */
1893 /* make sure they are set from the font bounding box info. */
1895 /* This is *always* done regardless of the options, because X11 */
1896 /* requires these two fields to compile fonts. */
1897 if ( bdf_get_font_property( p
->font
, "FONT_ASCENT" ) == 0 )
1899 p
->font
->font_ascent
= p
->font
->bbx
.ascent
;
1900 ft_sprintf( nbuf
, "%hd", p
->font
->bbx
.ascent
);
1901 error
= _bdf_add_property( p
->font
, (char *)"FONT_ASCENT", nbuf
);
1905 FT_TRACE2(( "_bdf_parse_properties: " ACMSG1
, p
->font
->bbx
.ascent
));
1906 p
->font
->modified
= 1;
1909 if ( bdf_get_font_property( p
->font
, "FONT_DESCENT" ) == 0 )
1911 p
->font
->font_descent
= p
->font
->bbx
.descent
;
1912 ft_sprintf( nbuf
, "%hd", p
->font
->bbx
.descent
);
1913 error
= _bdf_add_property( p
->font
, (char *)"FONT_DESCENT", nbuf
);
1917 FT_TRACE2(( "_bdf_parse_properties: " ACMSG2
, p
->font
->bbx
.descent
));
1918 p
->font
->modified
= 1;
1921 p
->flags
&= ~_BDF_PROPS
;
1922 *next
= _bdf_parse_glyphs
;
1927 /* Ignore the _XFREE86_GLYPH_RANGES properties. */
1928 if ( ft_memcmp( line
, "_XFREE86_GLYPH_RANGES", 21 ) == 0 )
1931 /* Handle COMMENT fields and properties in a special way to preserve */
1933 if ( ft_memcmp( line
, "COMMENT", 7 ) == 0 )
1935 name
= value
= line
;
1939 error
= _bdf_add_property( p
->font
, name
, value
);
1943 else if ( _bdf_is_atom( line
, linelen
, &name
, &value
, p
->font
) )
1945 error
= _bdf_add_property( p
->font
, name
, value
);
1951 error
= _bdf_list_split( &p
->list
, (char *)" +", line
, linelen
);
1954 name
= p
->list
.field
[0];
1956 _bdf_list_shift( &p
->list
, 1 );
1957 value
= _bdf_list_join( &p
->list
, ' ', &vlen
);
1959 error
= _bdf_add_property( p
->font
, name
, value
);
1969 /* Load the font header. */
1971 _bdf_parse_start( char* line
,
1972 unsigned long linelen
,
1973 unsigned long lineno
,
1978 _bdf_line_func_t
* next
;
1983 FT_Memory memory
= NULL
;
1984 FT_Error error
= BDF_Err_Ok
;
1986 FT_UNUSED( lineno
); /* only used in debug mode */
1989 next
= (_bdf_line_func_t
*)call_data
;
1990 p
= (_bdf_parse_t
*) client_data
;
1993 memory
= p
->font
->memory
;
1995 /* Check for a comment. This is done to handle those fonts that have */
1996 /* comments before the STARTFONT line for some reason. */
1997 if ( ft_memcmp( line
, "COMMENT", 7 ) == 0 )
1999 if ( p
->opts
->keep_comments
!= 0 && p
->font
!= 0 )
2010 error
= _bdf_add_comment( p
->font
, s
, linelen
);
2013 /* here font is not defined! */
2019 if ( !( p
->flags
& _BDF_START
) )
2023 if ( ft_memcmp( line
, "STARTFONT", 9 ) != 0 )
2025 /* No STARTFONT field is a good indication of a problem. */
2026 error
= BDF_Err_Missing_Startfont_Field
;
2030 p
->flags
= _BDF_START
;
2033 if ( FT_NEW( font
) )
2037 font
->memory
= p
->memory
;
2042 bdf_property_t
* prop
;
2045 error
= hash_init( &(font
->proptbl
), memory
);
2048 for ( i
= 0, prop
= (bdf_property_t
*)_bdf_properties
;
2049 i
< _num_bdf_properties
; i
++, prop
++ )
2051 error
= hash_insert( prop
->name
, (void *)i
,
2052 &(font
->proptbl
), memory
);
2058 if ( FT_ALLOC( p
->font
->internal
, sizeof ( hashtable
) ) )
2060 error
= hash_init( (hashtable
*)p
->font
->internal
,memory
);
2063 p
->font
->spacing
= p
->opts
->font_spacing
;
2064 p
->font
->default_char
= -1;
2069 /* Check for the start of the properties. */
2070 if ( ft_memcmp( line
, "STARTPROPERTIES", 15 ) == 0 )
2072 error
= _bdf_list_split( &p
->list
, (char *)" +", line
, linelen
);
2075 p
->cnt
= p
->font
->props_size
= _bdf_atoul( p
->list
.field
[1], 0, 10 );
2077 if ( FT_NEW_ARRAY( p
->font
->props
, p
->cnt
) )
2080 p
->flags
|= _BDF_PROPS
;
2081 *next
= _bdf_parse_properties
;
2086 /* Check for the FONTBOUNDINGBOX field. */
2087 if ( ft_memcmp( line
, "FONTBOUNDINGBOX", 15 ) == 0 )
2089 if ( !(p
->flags
& _BDF_SIZE
) )
2091 /* Missing the SIZE field. */
2092 FT_ERROR(( "_bdf_parse_start: " ERRMSG1
, lineno
, "SIZE" ));
2093 error
= BDF_Err_Missing_Size_Field
;
2097 error
= _bdf_list_split( &p
->list
, (char *)" +", line
, linelen
);
2101 p
->font
->bbx
.width
= _bdf_atos( p
->list
.field
[1], 0, 10 );
2102 p
->font
->bbx
.height
= _bdf_atos( p
->list
.field
[2], 0, 10 );
2104 p
->font
->bbx
.x_offset
= _bdf_atos( p
->list
.field
[3], 0, 10 );
2105 p
->font
->bbx
.y_offset
= _bdf_atos( p
->list
.field
[4], 0, 10 );
2107 p
->font
->bbx
.ascent
= (short)( p
->font
->bbx
.height
+
2108 p
->font
->bbx
.y_offset
);
2110 p
->font
->bbx
.descent
= (short)( -p
->font
->bbx
.y_offset
);
2112 p
->flags
|= _BDF_FONT_BBX
;
2117 /* The next thing to check for is the FONT field. */
2118 if ( ft_memcmp( line
, "FONT", 4 ) == 0 )
2120 error
= _bdf_list_split( &p
->list
, (char *)" +", line
, linelen
);
2123 _bdf_list_shift( &p
->list
, 1 );
2125 s
= _bdf_list_join( &p
->list
, ' ', &slen
);
2129 error
= BDF_Err_Invalid_File_Format
;
2133 if ( FT_NEW_ARRAY( p
->font
->name
, slen
+ 1 ) )
2135 FT_MEM_COPY( p
->font
->name
, s
, slen
+ 1 );
2137 /* If the font name is an XLFD name, set the spacing to the one in */
2138 /* the font name. If there is no spacing fall back on the default. */
2139 error
= _bdf_set_default_spacing( p
->font
, p
->opts
);
2143 p
->flags
|= _BDF_FONT_NAME
;
2148 /* Check for the SIZE field. */
2149 if ( ft_memcmp( line
, "SIZE", 4 ) == 0 )
2151 if ( !( p
->flags
& _BDF_FONT_NAME
) )
2153 /* Missing the FONT field. */
2154 FT_ERROR(( "_bdf_parse_start: " ERRMSG1
, lineno
, "FONT" ));
2155 error
= BDF_Err_Missing_Font_Field
;
2159 error
= _bdf_list_split( &p
->list
, (char *)" +", line
, linelen
);
2163 p
->font
->point_size
= _bdf_atoul( p
->list
.field
[1], 0, 10 );
2164 p
->font
->resolution_x
= _bdf_atoul( p
->list
.field
[2], 0, 10 );
2165 p
->font
->resolution_y
= _bdf_atoul( p
->list
.field
[3], 0, 10 );
2167 /* Check for the bits per pixel field. */
2168 if ( p
->list
.used
== 5 )
2170 unsigned short bitcount
, i
, shift
;
2173 p
->font
->bpp
= (unsigned short)_bdf_atos( p
->list
.field
[4], 0, 10 );
2175 /* Only values 1, 2, 4, 8 are allowed. */
2176 shift
= p
->font
->bpp
;
2178 for ( i
= 0; shift
> 0; i
++ )
2185 shift
= (short)( ( bitcount
> 3 ) ? 8 : ( 1 << bitcount
) );
2187 if ( p
->font
->bpp
> shift
|| p
->font
->bpp
!= shift
)
2189 /* select next higher value */
2190 p
->font
->bpp
= (unsigned short)( shift
<< 1 );
2191 FT_TRACE2(( "_bdf_parse_start: " ACMSG11
, p
->font
->bpp
));
2197 p
->flags
|= _BDF_SIZE
;
2202 error
= BDF_Err_Invalid_File_Format
;
2209 /*************************************************************************/
2213 /*************************************************************************/
2216 FT_LOCAL_DEF( FT_Error
)
2217 bdf_load_font( FT_Stream stream
,
2218 FT_Memory extmemory
,
2219 bdf_options_t
* opts
,
2222 unsigned long lineno
= 0; /* make compiler happy */
2225 FT_Memory memory
= extmemory
;
2226 FT_Error error
= BDF_Err_Ok
;
2233 p
->opts
= (bdf_options_t
*)( ( opts
!= 0 ) ? opts
: &_bdf_opts
);
2235 p
->memory
= extmemory
; /* only during font creation */
2237 _bdf_list_init( &p
->list
, extmemory
);
2239 error
= _bdf_readstream( stream
, _bdf_parse_start
,
2240 (void *)p
, &lineno
);
2246 /* If the font is not proportional, set the font's monowidth */
2247 /* field to the width of the font bounding box. */
2248 memory
= p
->font
->memory
;
2250 if ( p
->font
->spacing
!= BDF_PROPORTIONAL
)
2251 p
->font
->monowidth
= p
->font
->bbx
.width
;
2253 /* If the number of glyphs loaded is not that of the original count, */
2254 /* indicate the difference. */
2255 if ( p
->cnt
!= p
->font
->glyphs_used
+ p
->font
->unencoded_used
)
2257 FT_TRACE2(( "bdf_load_font: " ACMSG15
, p
->cnt
,
2258 p
->font
->glyphs_used
+ p
->font
->unencoded_used
));
2259 p
->font
->modified
= 1;
2262 /* Once the font has been loaded, adjust the overall font metrics if */
2264 if ( p
->opts
->correct_metrics
!= 0 &&
2265 ( p
->font
->glyphs_used
> 0 || p
->font
->unencoded_used
> 0 ) )
2267 if ( p
->maxrb
- p
->minlb
!= p
->font
->bbx
.width
)
2269 FT_TRACE2(( "bdf_load_font: " ACMSG3
,
2270 p
->font
->bbx
.width
, p
->maxrb
- p
->minlb
));
2271 p
->font
->bbx
.width
= (unsigned short)( p
->maxrb
- p
->minlb
);
2272 p
->font
->modified
= 1;
2275 if ( p
->font
->bbx
.x_offset
!= p
->minlb
)
2277 FT_TRACE2(( "bdf_load_font: " ACMSG4
,
2278 p
->font
->bbx
.x_offset
, p
->minlb
));
2279 p
->font
->bbx
.x_offset
= p
->minlb
;
2280 p
->font
->modified
= 1;
2283 if ( p
->font
->bbx
.ascent
!= p
->maxas
)
2285 FT_TRACE2(( "bdf_load_font: " ACMSG5
,
2286 p
->font
->bbx
.ascent
, p
->maxas
));
2287 p
->font
->bbx
.ascent
= p
->maxas
;
2288 p
->font
->modified
= 1;
2291 if ( p
->font
->bbx
.descent
!= p
->maxds
)
2293 FT_TRACE2(( "bdf_load_font: " ACMSG6
,
2294 p
->font
->bbx
.descent
, p
->maxds
));
2295 p
->font
->bbx
.descent
= p
->maxds
;
2296 p
->font
->bbx
.y_offset
= (short)( -p
->maxds
);
2297 p
->font
->modified
= 1;
2300 if ( p
->maxas
+ p
->maxds
!= p
->font
->bbx
.height
)
2302 FT_TRACE2(( "bdf_load_font: " ACMSG7
,
2303 p
->font
->bbx
.height
, p
->maxas
+ p
->maxds
));
2304 p
->font
->bbx
.height
= (unsigned short)( p
->maxas
+ p
->maxds
);
2307 if ( p
->flags
& _BDF_SWIDTH_ADJ
)
2308 FT_TRACE2(( "bdf_load_font: " ACMSG8
));
2312 if ( p
->flags
& _BDF_START
)
2315 /* The ENDFONT field was never reached or did not exist. */
2316 if ( !( p
->flags
& _BDF_GLYPHS
) )
2318 /* Error happened while parsing header. */
2319 FT_ERROR(( "bdf_load_font: " ERRMSG2
, lineno
));
2320 error
= BDF_Err_Corrupted_Font_Header
;
2325 /* Error happened when parsing glyphs. */
2326 FT_ERROR(( "bdf_load_font: " ERRMSG3
, lineno
));
2327 error
= BDF_Err_Corrupted_Font_Glyphs
;
2335 /* Make sure the comments are NULL terminated if they exist. */
2336 memory
= p
->font
->memory
;
2338 if ( p
->font
->comments_len
> 0 ) {
2339 if ( FT_RENEW_ARRAY( p
->font
->comments
,
2340 p
->font
->comments_len
,
2341 p
->font
->comments_len
+ 1 ) )
2344 p
->font
->comments
[p
->font
->comments_len
] = 0;
2347 else if ( error
== BDF_Err_Ok
)
2348 error
= BDF_Err_Invalid_File_Format
;
2355 _bdf_list_done( &p
->list
);
2365 bdf_free_font( p
->font
);
2375 FT_LOCAL_DEF( void )
2376 bdf_free_font( bdf_font_t
* font
)
2378 bdf_property_t
* prop
;
2380 bdf_glyph_t
* glyphs
;
2387 memory
= font
->memory
;
2389 FT_FREE( font
->name
);
2391 /* Free up the internal hash table of property names. */
2392 if ( font
->internal
)
2394 hash_free( (hashtable
*)font
->internal
, memory
);
2395 FT_FREE( font
->internal
);
2398 /* Free up the comment info. */
2399 FT_FREE( font
->comments
);
2401 /* Free up the properties. */
2402 for ( i
= 0; i
< font
->props_size
; i
++ )
2404 if ( font
->props
[i
].format
== BDF_ATOM
)
2405 FT_FREE( font
->props
[i
].value
.atom
);
2408 FT_FREE( font
->props
);
2410 /* Free up the character info. */
2411 for ( i
= 0, glyphs
= font
->glyphs
;
2412 i
< font
->glyphs_used
; i
++, glyphs
++ )
2414 FT_FREE( glyphs
->name
);
2415 FT_FREE( glyphs
->bitmap
);
2418 for ( i
= 0, glyphs
= font
->unencoded
; i
< font
->unencoded_used
;
2421 FT_FREE( glyphs
->name
);
2422 FT_FREE( glyphs
->bitmap
);
2425 FT_FREE( font
->glyphs
);
2426 FT_FREE( font
->unencoded
);
2428 /* Free up the overflow storage if it was used. */
2429 for ( i
= 0, glyphs
= font
->overflow
.glyphs
;
2430 i
< font
->overflow
.glyphs_used
; i
++, glyphs
++ )
2432 FT_FREE( glyphs
->name
);
2433 FT_FREE( glyphs
->bitmap
);
2436 FT_FREE( font
->overflow
.glyphs
);
2439 hash_free( &(font
->proptbl
), memory
);
2441 /* Free up the user defined properties. */
2442 for (prop
= font
->user_props
, i
= 0;
2443 i
< font
->nuser_props
; i
++, prop
++ )
2445 FT_FREE( prop
->name
);
2446 if ( prop
->format
== BDF_ATOM
)
2447 FT_FREE( prop
->value
.atom
);
2450 FT_FREE( font
->user_props
);
2452 /* FREE( font ); */ /* XXX Fixme */
2456 FT_LOCAL_DEF( bdf_property_t
* )
2457 bdf_get_font_property( bdf_font_t
* font
,
2463 if ( font
== 0 || font
->props_size
== 0 || name
== 0 || *name
== 0 )
2466 hn
= hash_lookup( name
, (hashtable
*)font
->internal
);
2468 return hn
? ( font
->props
+ (unsigned long)hn
->data
) : 0;