2 * Copyright 2000 Computing Research Labs, New Mexico State University
3 * Copyright 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2009
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
];
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
, hold
, to_skip
;
618 ptrdiff_t bytes
, 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
= (ptrdiff_t)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
= ft_strlen( name
) + 1;
995 if ( n
> FT_ULONG_MAX
)
996 return BDF_Err_Invalid_Argument
;
998 if ( FT_NEW_ARRAY( p
->name
, n
) )
1001 FT_MEM_COPY( (char *)p
->name
, name
, n
);
1006 n
= _num_bdf_properties
+ font
->nuser_props
;
1008 error
= hash_insert( p
->name
, n
, &(font
->proptbl
), memory
);
1012 font
->nuser_props
++;
1019 FT_LOCAL_DEF( bdf_property_t
* )
1020 bdf_get_property( char* name
,
1027 if ( name
== 0 || *name
== 0 )
1030 if ( ( hn
= hash_lookup( name
, &(font
->proptbl
) ) ) == 0 )
1034 if ( propid
>= _num_bdf_properties
)
1035 return font
->user_props
+ ( propid
- _num_bdf_properties
);
1037 return (bdf_property_t
*)_bdf_properties
+ propid
;
1041 /*************************************************************************/
1043 /* BDF font file parsing flags and functions. */
1045 /*************************************************************************/
1050 #define _BDF_START 0x0001
1051 #define _BDF_FONT_NAME 0x0002
1052 #define _BDF_SIZE 0x0004
1053 #define _BDF_FONT_BBX 0x0008
1054 #define _BDF_PROPS 0x0010
1055 #define _BDF_GLYPHS 0x0020
1056 #define _BDF_GLYPH 0x0040
1057 #define _BDF_ENCODING 0x0080
1058 #define _BDF_SWIDTH 0x0100
1059 #define _BDF_DWIDTH 0x0200
1060 #define _BDF_BBX 0x0400
1061 #define _BDF_BITMAP 0x0800
1063 #define _BDF_SWIDTH_ADJ 0x1000
1065 #define _BDF_GLYPH_BITS ( _BDF_GLYPH | \
1072 #define _BDF_GLYPH_WIDTH_CHECK 0x40000000UL
1073 #define _BDF_GLYPH_HEIGHT_CHECK 0x80000000UL
1076 /* Auto correction messages. */
1077 #define ACMSG1 "FONT_ASCENT property missing. " \
1078 "Added \"FONT_ASCENT %hd\".\n"
1079 #define ACMSG2 "FONT_DESCENT property missing. " \
1080 "Added \"FONT_DESCENT %hd\".\n"
1081 #define ACMSG3 "Font width != actual width. Old: %hd New: %hd.\n"
1082 #define ACMSG4 "Font left bearing != actual left bearing. " \
1083 "Old: %hd New: %hd.\n"
1084 #define ACMSG5 "Font ascent != actual ascent. Old: %hd New: %hd.\n"
1085 #define ACMSG6 "Font descent != actual descent. Old: %hd New: %hd.\n"
1086 #define ACMSG7 "Font height != actual height. Old: %hd New: %hd.\n"
1087 #define ACMSG8 "Glyph scalable width (SWIDTH) adjustments made.\n"
1088 #define ACMSG9 "SWIDTH field missing at line %ld. Set automatically.\n"
1089 #define ACMSG10 "DWIDTH field missing at line %ld. Set to glyph width.\n"
1090 #define ACMSG11 "SIZE bits per pixel field adjusted to %hd.\n"
1091 #define ACMSG12 "Duplicate encoding %ld (%s) changed to unencoded.\n"
1092 #define ACMSG13 "Glyph %ld extra rows removed.\n"
1093 #define ACMSG14 "Glyph %ld extra columns removed.\n"
1094 #define ACMSG15 "Incorrect glyph count: %ld indicated but %ld found.\n"
1096 /* Error messages. */
1097 #define ERRMSG1 "[line %ld] Missing \"%s\" line.\n"
1098 #define ERRMSG2 "[line %ld] Font header corrupted or missing fields.\n"
1099 #define ERRMSG3 "[line %ld] Font glyphs corrupted or missing fields.\n"
1100 #define ERRMSG4 "[line %ld] BBX too big.\n"
1104 _bdf_add_comment( bdf_font_t
* font
,
1109 FT_Memory memory
= font
->memory
;
1110 FT_Error error
= BDF_Err_Ok
;
1113 if ( FT_RENEW_ARRAY( font
->comments
,
1115 font
->comments_len
+ len
+ 1 ) )
1118 cp
= font
->comments
+ font
->comments_len
;
1120 FT_MEM_COPY( cp
, comment
, len
);
1123 font
->comments_len
+= len
+ 1;
1130 /* Set the spacing from the font name if it exists, or set it to the */
1131 /* default specified in the options. */
1133 _bdf_set_default_spacing( bdf_font_t
* font
,
1134 bdf_options_t
* opts
)
1140 FT_Error error
= BDF_Err_Ok
;
1143 if ( font
== 0 || font
->name
== 0 || font
->name
[0] == 0 )
1145 error
= BDF_Err_Invalid_Argument
;
1149 memory
= font
->memory
;
1151 _bdf_list_init( &list
, memory
);
1153 font
->spacing
= opts
->font_spacing
;
1155 len
= ft_strlen( font
->name
) + 1;
1156 /* Limit ourselves to 256 characters in the font name. */
1159 error
= BDF_Err_Invalid_Argument
;
1163 FT_MEM_COPY( name
, font
->name
, len
);
1165 error
= _bdf_list_split( &list
, (char *)"-", name
, len
);
1169 if ( list
.used
== 15 )
1171 switch ( list
.field
[11][0] )
1175 font
->spacing
= BDF_CHARCELL
;
1179 font
->spacing
= BDF_MONOWIDTH
;
1183 font
->spacing
= BDF_PROPORTIONAL
;
1189 _bdf_list_done( &list
);
1196 /* Determine whether the property is an atom or not. If it is, then */
1197 /* clean it up so the double quotes are removed if they exist. */
1199 _bdf_is_atom( char* line
,
1200 unsigned long linelen
,
1210 *name
= sp
= ep
= line
;
1212 while ( *ep
&& *ep
!= ' ' && *ep
!= '\t' )
1222 p
= bdf_get_property( sp
, font
);
1224 /* Restore the character that was saved before any return can happen. */
1228 /* If the property exists and is not an atom, just return here. */
1229 if ( p
&& p
->format
!= BDF_ATOM
)
1232 /* The property is an atom. Trim all leading and trailing whitespace */
1233 /* and double quotes for the atom value. */
1235 ep
= line
+ linelen
;
1237 /* Trim the leading whitespace if it exists. */
1240 ( *sp
== ' ' || *sp
== '\t' ) )
1243 /* Trim the leading double quote if it exists. */
1248 /* Trim the trailing whitespace if it exists. */
1250 ( *( ep
- 1 ) == ' ' || *( ep
- 1 ) == '\t' ) )
1253 /* Trim the trailing double quote if it exists. */
1254 if ( ep
> sp
&& *( ep
- 1 ) == '"' )
1262 _bdf_add_property( bdf_font_t
* font
,
1268 bdf_property_t
*prop
, *fp
;
1269 FT_Memory memory
= font
->memory
;
1270 FT_Error error
= BDF_Err_Ok
;
1273 /* First, check to see if the property already exists in the font. */
1274 if ( ( hn
= hash_lookup( name
, (hashtable
*)font
->internal
) ) != 0 )
1276 /* The property already exists in the font, so simply replace */
1277 /* the value of the property with the current value. */
1278 fp
= font
->props
+ hn
->data
;
1280 switch ( fp
->format
)
1283 /* Delete the current atom if it exists. */
1284 FT_FREE( fp
->value
.atom
);
1286 if ( value
&& value
[0] != 0 )
1288 if ( FT_STRDUP( fp
->value
.atom
, value
) )
1294 fp
->value
.l
= _bdf_atol( value
, 0, 10 );
1298 fp
->value
.ul
= _bdf_atoul( value
, 0, 10 );
1308 /* See whether this property type exists yet or not. */
1309 /* If not, create it. */
1310 hn
= hash_lookup( name
, &(font
->proptbl
) );
1313 error
= bdf_create_property( name
, BDF_ATOM
, font
);
1316 hn
= hash_lookup( name
, &(font
->proptbl
) );
1319 /* Allocate another property if this is overflow. */
1320 if ( font
->props_used
== font
->props_size
)
1322 if ( font
->props_size
== 0 )
1324 if ( FT_NEW_ARRAY( font
->props
, 1 ) )
1329 if ( FT_RENEW_ARRAY( font
->props
,
1331 font
->props_size
+ 1 ) )
1335 fp
= font
->props
+ font
->props_size
;
1336 FT_MEM_ZERO( fp
, sizeof ( bdf_property_t
) );
1341 if ( propid
>= _num_bdf_properties
)
1342 prop
= font
->user_props
+ ( propid
- _num_bdf_properties
);
1344 prop
= (bdf_property_t
*)_bdf_properties
+ propid
;
1346 fp
= font
->props
+ font
->props_used
;
1348 fp
->name
= prop
->name
;
1349 fp
->format
= prop
->format
;
1350 fp
->builtin
= prop
->builtin
;
1352 switch ( prop
->format
)
1356 if ( value
!= 0 && value
[0] )
1358 if ( FT_STRDUP( fp
->value
.atom
, value
) )
1364 fp
->value
.l
= _bdf_atol( value
, 0, 10 );
1368 fp
->value
.ul
= _bdf_atoul( value
, 0, 10 );
1372 /* If the property happens to be a comment, then it doesn't need */
1373 /* to be added to the internal hash table. */
1374 if ( ft_memcmp( name
, "COMMENT", 7 ) != 0 ) {
1375 /* Add the property to the font property table. */
1376 error
= hash_insert( fp
->name
,
1378 (hashtable
*)font
->internal
,
1386 /* Some special cases need to be handled here. The DEFAULT_CHAR */
1387 /* property needs to be located if it exists in the property list, the */
1388 /* FONT_ASCENT and FONT_DESCENT need to be assigned if they are */
1389 /* present, and the SPACING property should override the default */
1391 if ( ft_memcmp( name
, "DEFAULT_CHAR", 12 ) == 0 )
1392 font
->default_char
= fp
->value
.l
;
1393 else if ( ft_memcmp( name
, "FONT_ASCENT", 11 ) == 0 )
1394 font
->font_ascent
= fp
->value
.l
;
1395 else if ( ft_memcmp( name
, "FONT_DESCENT", 12 ) == 0 )
1396 font
->font_descent
= fp
->value
.l
;
1397 else if ( ft_memcmp( name
, "SPACING", 7 ) == 0 )
1399 if ( !fp
->value
.atom
)
1401 error
= BDF_Err_Invalid_File_Format
;
1405 if ( fp
->value
.atom
[0] == 'p' || fp
->value
.atom
[0] == 'P' )
1406 font
->spacing
= BDF_PROPORTIONAL
;
1407 else if ( fp
->value
.atom
[0] == 'm' || fp
->value
.atom
[0] == 'M' )
1408 font
->spacing
= BDF_MONOWIDTH
;
1409 else if ( fp
->value
.atom
[0] == 'c' || fp
->value
.atom
[0] == 'C' )
1410 font
->spacing
= BDF_CHARCELL
;
1418 static const unsigned char nibble_mask
[8] =
1420 0xFF, 0x80, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC, 0xFE
1424 /* Actually parse the glyph info and bitmaps. */
1426 _bdf_parse_glyphs( char* line
,
1427 unsigned long linelen
,
1428 unsigned long lineno
,
1435 unsigned long i
, slen
, nibbles
;
1442 FT_Error error
= BDF_Err_Ok
;
1444 FT_UNUSED( call_data
);
1445 FT_UNUSED( lineno
); /* only used in debug mode */
1448 p
= (_bdf_parse_t
*)client_data
;
1451 memory
= font
->memory
;
1453 /* Check for a comment. */
1454 if ( ft_memcmp( line
, "COMMENT", 7 ) == 0 )
1464 error
= _bdf_add_comment( p
->font
, s
, linelen
);
1468 /* The very first thing expected is the number of glyphs. */
1469 if ( !( p
->flags
& _BDF_GLYPHS
) )
1471 if ( ft_memcmp( line
, "CHARS", 5 ) != 0 )
1473 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1
, lineno
, "CHARS" ));
1474 error
= BDF_Err_Missing_Chars_Field
;
1478 error
= _bdf_list_split( &p
->list
, (char *)" +", line
, linelen
);
1481 p
->cnt
= font
->glyphs_size
= _bdf_atoul( p
->list
.field
[1], 0, 10 );
1483 /* Make sure the number of glyphs is non-zero. */
1485 font
->glyphs_size
= 64;
1487 /* Limit ourselves to 1,114,112 glyphs in the font (this is the */
1488 /* number of code points available in Unicode). */
1489 if ( p
->cnt
>= 1114112UL )
1491 error
= BDF_Err_Invalid_Argument
;
1495 if ( FT_NEW_ARRAY( font
->glyphs
, font
->glyphs_size
) )
1498 p
->flags
|= _BDF_GLYPHS
;
1503 /* Check for the ENDFONT field. */
1504 if ( ft_memcmp( line
, "ENDFONT", 7 ) == 0 )
1506 /* Sort the glyphs by encoding. */
1507 ft_qsort( (char *)font
->glyphs
,
1509 sizeof ( bdf_glyph_t
),
1512 p
->flags
&= ~_BDF_START
;
1517 /* Check for the ENDCHAR field. */
1518 if ( ft_memcmp( line
, "ENDCHAR", 7 ) == 0 )
1521 p
->flags
&= ~_BDF_GLYPH_BITS
;
1526 /* Check to see whether a glyph is being scanned but should be */
1527 /* ignored because it is an unencoded glyph. */
1528 if ( ( p
->flags
& _BDF_GLYPH
) &&
1529 p
->glyph_enc
== -1 &&
1530 p
->opts
->keep_unencoded
== 0 )
1533 /* Check for the STARTCHAR field. */
1534 if ( ft_memcmp( line
, "STARTCHAR", 9 ) == 0 )
1536 /* Set the character name in the parse info first until the */
1537 /* encoding can be checked for an unencoded character. */
1538 FT_FREE( p
->glyph_name
);
1540 error
= _bdf_list_split( &p
->list
, (char *)" +", line
, linelen
);
1544 _bdf_list_shift( &p
->list
, 1 );
1546 s
= _bdf_list_join( &p
->list
, ' ', &slen
);
1550 error
= BDF_Err_Invalid_File_Format
;
1554 if ( FT_NEW_ARRAY( p
->glyph_name
, slen
+ 1 ) )
1557 FT_MEM_COPY( p
->glyph_name
, s
, slen
+ 1 );
1559 p
->flags
|= _BDF_GLYPH
;
1564 /* Check for the ENCODING field. */
1565 if ( ft_memcmp( line
, "ENCODING", 8 ) == 0 )
1567 if ( !( p
->flags
& _BDF_GLYPH
) )
1569 /* Missing STARTCHAR field. */
1570 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1
, lineno
, "STARTCHAR" ));
1571 error
= BDF_Err_Missing_Startchar_Field
;
1575 error
= _bdf_list_split( &p
->list
, (char *)" +", line
, linelen
);
1579 p
->glyph_enc
= _bdf_atol( p
->list
.field
[1], 0, 10 );
1581 /* Check that the encoding is in the range [0,65536] because */
1582 /* otherwise p->have (a bitmap with static size) overflows. */
1583 if ( (size_t)p
->glyph_enc
>= sizeof ( p
->have
) * 8 )
1585 error
= BDF_Err_Invalid_File_Format
;
1589 /* Check to see whether this encoding has already been encountered. */
1590 /* If it has then change it to unencoded so it gets added if */
1592 if ( p
->glyph_enc
>= 0 )
1594 if ( _bdf_glyph_modified( p
->have
, p
->glyph_enc
) )
1596 /* Emit a message saying a glyph has been moved to the */
1597 /* unencoded area. */
1598 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG12
,
1599 p
->glyph_enc
, p
->glyph_name
));
1604 _bdf_set_glyph_modified( p
->have
, p
->glyph_enc
);
1607 if ( p
->glyph_enc
>= 0 )
1609 /* Make sure there are enough glyphs allocated in case the */
1610 /* number of characters happen to be wrong. */
1611 if ( font
->glyphs_used
== font
->glyphs_size
)
1613 if ( FT_RENEW_ARRAY( font
->glyphs
,
1615 font
->glyphs_size
+ 64 ) )
1618 font
->glyphs_size
+= 64;
1621 glyph
= font
->glyphs
+ font
->glyphs_used
++;
1622 glyph
->name
= p
->glyph_name
;
1623 glyph
->encoding
= p
->glyph_enc
;
1625 /* Reset the initial glyph info. */
1630 /* Unencoded glyph. Check to see whether it should */
1631 /* be added or not. */
1632 if ( p
->opts
->keep_unencoded
!= 0 )
1634 /* Allocate the next unencoded glyph. */
1635 if ( font
->unencoded_used
== font
->unencoded_size
)
1637 if ( FT_RENEW_ARRAY( font
->unencoded
,
1638 font
->unencoded_size
,
1639 font
->unencoded_size
+ 4 ) )
1642 font
->unencoded_size
+= 4;
1645 glyph
= font
->unencoded
+ font
->unencoded_used
;
1646 glyph
->name
= p
->glyph_name
;
1647 glyph
->encoding
= font
->unencoded_used
++;
1650 /* Free up the glyph name if the unencoded shouldn't be */
1652 FT_FREE( p
->glyph_name
);
1657 /* Clear the flags that might be added when width and height are */
1658 /* checked for consistency. */
1659 p
->flags
&= ~( _BDF_GLYPH_WIDTH_CHECK
| _BDF_GLYPH_HEIGHT_CHECK
);
1661 p
->flags
|= _BDF_ENCODING
;
1666 /* Point at the glyph being constructed. */
1667 if ( p
->glyph_enc
== -1 )
1668 glyph
= font
->unencoded
+ ( font
->unencoded_used
- 1 );
1670 glyph
= font
->glyphs
+ ( font
->glyphs_used
- 1 );
1672 /* Check to see whether a bitmap is being constructed. */
1673 if ( p
->flags
& _BDF_BITMAP
)
1675 /* If there are more rows than are specified in the glyph metrics, */
1676 /* ignore the remaining lines. */
1677 if ( p
->row
>= (unsigned long)glyph
->bbx
.height
)
1679 if ( !( p
->flags
& _BDF_GLYPH_HEIGHT_CHECK
) )
1681 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG13
, glyph
->encoding
));
1682 p
->flags
|= _BDF_GLYPH_HEIGHT_CHECK
;
1689 /* Only collect the number of nibbles indicated by the glyph */
1690 /* metrics. If there are more columns, they are simply ignored. */
1691 nibbles
= glyph
->bpr
<< 1;
1692 bp
= glyph
->bitmap
+ p
->row
* glyph
->bpr
;
1694 for ( i
= 0; i
< nibbles
; i
++ )
1697 *bp
= (FT_Byte
)( ( *bp
<< 4 ) + a2i
[c
] );
1698 if ( i
+ 1 < nibbles
&& ( i
& 1 ) )
1702 /* Remove possible garbage at the right. */
1703 mask_index
= ( glyph
->bbx
.width
* p
->font
->bpp
) & 7;
1704 if ( glyph
->bbx
.width
)
1705 *bp
&= nibble_mask
[mask_index
];
1707 /* If any line has extra columns, indicate they have been removed. */
1708 if ( ( line
[nibbles
] == '0' || a2i
[(int)line
[nibbles
]] != 0 ) &&
1709 !( p
->flags
& _BDF_GLYPH_WIDTH_CHECK
) )
1711 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG14
, glyph
->encoding
));
1712 p
->flags
|= _BDF_GLYPH_WIDTH_CHECK
;
1720 /* Expect the SWIDTH (scalable width) field next. */
1721 if ( ft_memcmp( line
, "SWIDTH", 6 ) == 0 )
1723 if ( !( p
->flags
& _BDF_ENCODING
) )
1725 /* Missing ENCODING field. */
1726 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1
, lineno
, "ENCODING" ));
1727 error
= BDF_Err_Missing_Encoding_Field
;
1731 error
= _bdf_list_split( &p
->list
, (char *)" +", line
, linelen
);
1735 glyph
->swidth
= (unsigned short)_bdf_atoul( p
->list
.field
[1], 0, 10 );
1736 p
->flags
|= _BDF_SWIDTH
;
1741 /* Expect the DWIDTH (scalable width) field next. */
1742 if ( ft_memcmp( line
, "DWIDTH", 6 ) == 0 )
1744 error
= _bdf_list_split( &p
->list
, (char *)" +", line
, linelen
);
1748 glyph
->dwidth
= (unsigned short)_bdf_atoul( p
->list
.field
[1], 0, 10 );
1750 if ( !( p
->flags
& _BDF_SWIDTH
) )
1752 /* Missing SWIDTH field. Emit an auto correction message and set */
1753 /* the scalable width from the device width. */
1754 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG9
, lineno
));
1756 glyph
->swidth
= (unsigned short)FT_MulDiv(
1757 glyph
->dwidth
, 72000L,
1758 (FT_Long
)( font
->point_size
*
1759 font
->resolution_x
) );
1762 p
->flags
|= _BDF_DWIDTH
;
1766 /* Expect the BBX field next. */
1767 if ( ft_memcmp( line
, "BBX", 3 ) == 0 )
1769 error
= _bdf_list_split( &p
->list
, (char *)" +", line
, linelen
);
1773 glyph
->bbx
.width
= _bdf_atos( p
->list
.field
[1], 0, 10 );
1774 glyph
->bbx
.height
= _bdf_atos( p
->list
.field
[2], 0, 10 );
1775 glyph
->bbx
.x_offset
= _bdf_atos( p
->list
.field
[3], 0, 10 );
1776 glyph
->bbx
.y_offset
= _bdf_atos( p
->list
.field
[4], 0, 10 );
1778 /* Generate the ascent and descent of the character. */
1779 glyph
->bbx
.ascent
= (short)( glyph
->bbx
.height
+ glyph
->bbx
.y_offset
);
1780 glyph
->bbx
.descent
= (short)( -glyph
->bbx
.y_offset
);
1782 /* Determine the overall font bounding box as the characters are */
1783 /* loaded so corrections can be done later if indicated. */
1784 p
->maxas
= (short)FT_MAX( glyph
->bbx
.ascent
, p
->maxas
);
1785 p
->maxds
= (short)FT_MAX( glyph
->bbx
.descent
, p
->maxds
);
1787 p
->rbearing
= (short)( glyph
->bbx
.width
+ glyph
->bbx
.x_offset
);
1789 p
->maxrb
= (short)FT_MAX( p
->rbearing
, p
->maxrb
);
1790 p
->minlb
= (short)FT_MIN( glyph
->bbx
.x_offset
, p
->minlb
);
1791 p
->maxlb
= (short)FT_MAX( glyph
->bbx
.x_offset
, p
->maxlb
);
1793 if ( !( p
->flags
& _BDF_DWIDTH
) )
1795 /* Missing DWIDTH field. Emit an auto correction message and set */
1796 /* the device width to the glyph width. */
1797 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG10
, lineno
));
1798 glyph
->dwidth
= glyph
->bbx
.width
;
1801 /* If the BDF_CORRECT_METRICS flag is set, then adjust the SWIDTH */
1802 /* value if necessary. */
1803 if ( p
->opts
->correct_metrics
!= 0 )
1805 /* Determine the point size of the glyph. */
1806 unsigned short sw
= (unsigned short)FT_MulDiv(
1807 glyph
->dwidth
, 72000L,
1808 (FT_Long
)( font
->point_size
*
1809 font
->resolution_x
) );
1812 if ( sw
!= glyph
->swidth
)
1816 if ( p
->glyph_enc
== -1 )
1817 _bdf_set_glyph_modified( font
->umod
,
1818 font
->unencoded_used
- 1 );
1820 _bdf_set_glyph_modified( font
->nmod
, glyph
->encoding
);
1822 p
->flags
|= _BDF_SWIDTH_ADJ
;
1827 p
->flags
|= _BDF_BBX
;
1831 /* And finally, gather up the bitmap. */
1832 if ( ft_memcmp( line
, "BITMAP", 6 ) == 0 )
1834 unsigned long bitmap_size
;
1837 if ( !( p
->flags
& _BDF_BBX
) )
1839 /* Missing BBX field. */
1840 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1
, lineno
, "BBX" ));
1841 error
= BDF_Err_Missing_Bbx_Field
;
1845 /* Allocate enough space for the bitmap. */
1846 glyph
->bpr
= ( glyph
->bbx
.width
* p
->font
->bpp
+ 7 ) >> 3;
1848 bitmap_size
= glyph
->bpr
* glyph
->bbx
.height
;
1849 if ( bitmap_size
> 0xFFFFU
)
1851 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG4
, lineno
));
1852 error
= BDF_Err_Bbx_Too_Big
;
1856 glyph
->bytes
= (unsigned short)bitmap_size
;
1858 if ( FT_NEW_ARRAY( glyph
->bitmap
, glyph
->bytes
) )
1862 p
->flags
|= _BDF_BITMAP
;
1867 error
= BDF_Err_Invalid_File_Format
;
1874 /* Load the font properties. */
1876 _bdf_parse_properties( char* line
,
1877 unsigned long linelen
,
1878 unsigned long lineno
,
1883 _bdf_line_func_t
* next
;
1888 FT_Error error
= BDF_Err_Ok
;
1890 FT_UNUSED( lineno
);
1893 next
= (_bdf_line_func_t
*)call_data
;
1894 p
= (_bdf_parse_t
*) client_data
;
1896 /* Check for the end of the properties. */
1897 if ( ft_memcmp( line
, "ENDPROPERTIES", 13 ) == 0 )
1899 /* If the FONT_ASCENT or FONT_DESCENT properties have not been */
1900 /* encountered yet, then make sure they are added as properties and */
1901 /* make sure they are set from the font bounding box info. */
1903 /* This is *always* done regardless of the options, because X11 */
1904 /* requires these two fields to compile fonts. */
1905 if ( bdf_get_font_property( p
->font
, "FONT_ASCENT" ) == 0 )
1907 p
->font
->font_ascent
= p
->font
->bbx
.ascent
;
1908 ft_sprintf( nbuf
, "%hd", p
->font
->bbx
.ascent
);
1909 error
= _bdf_add_property( p
->font
, (char *)"FONT_ASCENT", nbuf
);
1913 FT_TRACE2(( "_bdf_parse_properties: " ACMSG1
, p
->font
->bbx
.ascent
));
1914 p
->font
->modified
= 1;
1917 if ( bdf_get_font_property( p
->font
, "FONT_DESCENT" ) == 0 )
1919 p
->font
->font_descent
= p
->font
->bbx
.descent
;
1920 ft_sprintf( nbuf
, "%hd", p
->font
->bbx
.descent
);
1921 error
= _bdf_add_property( p
->font
, (char *)"FONT_DESCENT", nbuf
);
1925 FT_TRACE2(( "_bdf_parse_properties: " ACMSG2
, p
->font
->bbx
.descent
));
1926 p
->font
->modified
= 1;
1929 p
->flags
&= ~_BDF_PROPS
;
1930 *next
= _bdf_parse_glyphs
;
1935 /* Ignore the _XFREE86_GLYPH_RANGES properties. */
1936 if ( ft_memcmp( line
, "_XFREE86_GLYPH_RANGES", 21 ) == 0 )
1939 /* Handle COMMENT fields and properties in a special way to preserve */
1941 if ( ft_memcmp( line
, "COMMENT", 7 ) == 0 )
1943 name
= value
= line
;
1947 error
= _bdf_add_property( p
->font
, name
, value
);
1951 else if ( _bdf_is_atom( line
, linelen
, &name
, &value
, p
->font
) )
1953 error
= _bdf_add_property( p
->font
, name
, value
);
1959 error
= _bdf_list_split( &p
->list
, (char *)" +", line
, linelen
);
1962 name
= p
->list
.field
[0];
1964 _bdf_list_shift( &p
->list
, 1 );
1965 value
= _bdf_list_join( &p
->list
, ' ', &vlen
);
1967 error
= _bdf_add_property( p
->font
, name
, value
);
1977 /* Load the font header. */
1979 _bdf_parse_start( char* line
,
1980 unsigned long linelen
,
1981 unsigned long lineno
,
1986 _bdf_line_func_t
* next
;
1991 FT_Memory memory
= NULL
;
1992 FT_Error error
= BDF_Err_Ok
;
1994 FT_UNUSED( lineno
); /* only used in debug mode */
1997 next
= (_bdf_line_func_t
*)call_data
;
1998 p
= (_bdf_parse_t
*) client_data
;
2001 memory
= p
->font
->memory
;
2003 /* Check for a comment. This is done to handle those fonts that have */
2004 /* comments before the STARTFONT line for some reason. */
2005 if ( ft_memcmp( line
, "COMMENT", 7 ) == 0 )
2007 if ( p
->opts
->keep_comments
!= 0 && p
->font
!= 0 )
2018 error
= _bdf_add_comment( p
->font
, s
, linelen
);
2021 /* here font is not defined! */
2027 if ( !( p
->flags
& _BDF_START
) )
2031 if ( ft_memcmp( line
, "STARTFONT", 9 ) != 0 )
2033 /* No STARTFONT field is a good indication of a problem. */
2034 error
= BDF_Err_Missing_Startfont_Field
;
2038 p
->flags
= _BDF_START
;
2041 if ( FT_NEW( font
) )
2045 font
->memory
= p
->memory
;
2050 bdf_property_t
* prop
;
2053 error
= hash_init( &(font
->proptbl
), memory
);
2056 for ( i
= 0, prop
= (bdf_property_t
*)_bdf_properties
;
2057 i
< _num_bdf_properties
; i
++, prop
++ )
2059 error
= hash_insert( prop
->name
, i
,
2060 &(font
->proptbl
), memory
);
2066 if ( FT_ALLOC( p
->font
->internal
, sizeof ( hashtable
) ) )
2068 error
= hash_init( (hashtable
*)p
->font
->internal
,memory
);
2071 p
->font
->spacing
= p
->opts
->font_spacing
;
2072 p
->font
->default_char
= -1;
2077 /* Check for the start of the properties. */
2078 if ( ft_memcmp( line
, "STARTPROPERTIES", 15 ) == 0 )
2080 error
= _bdf_list_split( &p
->list
, (char *)" +", line
, linelen
);
2083 /* at this point, `p->font' can't be NULL */
2084 p
->cnt
= p
->font
->props_size
= _bdf_atoul( p
->list
.field
[1], 0, 10 );
2086 if ( FT_NEW_ARRAY( p
->font
->props
, p
->cnt
) )
2089 p
->flags
|= _BDF_PROPS
;
2090 *next
= _bdf_parse_properties
;
2095 /* Check for the FONTBOUNDINGBOX field. */
2096 if ( ft_memcmp( line
, "FONTBOUNDINGBOX", 15 ) == 0 )
2098 if ( !(p
->flags
& _BDF_SIZE
) )
2100 /* Missing the SIZE field. */
2101 FT_ERROR(( "_bdf_parse_start: " ERRMSG1
, lineno
, "SIZE" ));
2102 error
= BDF_Err_Missing_Size_Field
;
2106 error
= _bdf_list_split( &p
->list
, (char *)" +", line
, linelen
);
2110 p
->font
->bbx
.width
= _bdf_atos( p
->list
.field
[1], 0, 10 );
2111 p
->font
->bbx
.height
= _bdf_atos( p
->list
.field
[2], 0, 10 );
2113 p
->font
->bbx
.x_offset
= _bdf_atos( p
->list
.field
[3], 0, 10 );
2114 p
->font
->bbx
.y_offset
= _bdf_atos( p
->list
.field
[4], 0, 10 );
2116 p
->font
->bbx
.ascent
= (short)( p
->font
->bbx
.height
+
2117 p
->font
->bbx
.y_offset
);
2119 p
->font
->bbx
.descent
= (short)( -p
->font
->bbx
.y_offset
);
2121 p
->flags
|= _BDF_FONT_BBX
;
2126 /* The next thing to check for is the FONT field. */
2127 if ( ft_memcmp( line
, "FONT", 4 ) == 0 )
2129 error
= _bdf_list_split( &p
->list
, (char *)" +", line
, linelen
);
2132 _bdf_list_shift( &p
->list
, 1 );
2134 s
= _bdf_list_join( &p
->list
, ' ', &slen
);
2138 error
= BDF_Err_Invalid_File_Format
;
2142 if ( FT_NEW_ARRAY( p
->font
->name
, slen
+ 1 ) )
2144 FT_MEM_COPY( p
->font
->name
, s
, slen
+ 1 );
2146 /* If the font name is an XLFD name, set the spacing to the one in */
2147 /* the font name. If there is no spacing fall back on the default. */
2148 error
= _bdf_set_default_spacing( p
->font
, p
->opts
);
2152 p
->flags
|= _BDF_FONT_NAME
;
2157 /* Check for the SIZE field. */
2158 if ( ft_memcmp( line
, "SIZE", 4 ) == 0 )
2160 if ( !( p
->flags
& _BDF_FONT_NAME
) )
2162 /* Missing the FONT field. */
2163 FT_ERROR(( "_bdf_parse_start: " ERRMSG1
, lineno
, "FONT" ));
2164 error
= BDF_Err_Missing_Font_Field
;
2168 error
= _bdf_list_split( &p
->list
, (char *)" +", line
, linelen
);
2172 p
->font
->point_size
= _bdf_atoul( p
->list
.field
[1], 0, 10 );
2173 p
->font
->resolution_x
= _bdf_atoul( p
->list
.field
[2], 0, 10 );
2174 p
->font
->resolution_y
= _bdf_atoul( p
->list
.field
[3], 0, 10 );
2176 /* Check for the bits per pixel field. */
2177 if ( p
->list
.used
== 5 )
2179 unsigned short bitcount
, i
, shift
;
2182 p
->font
->bpp
= (unsigned short)_bdf_atos( p
->list
.field
[4], 0, 10 );
2184 /* Only values 1, 2, 4, 8 are allowed. */
2185 shift
= p
->font
->bpp
;
2187 for ( i
= 0; shift
> 0; i
++ )
2194 shift
= (short)( ( bitcount
> 3 ) ? 8 : ( 1 << bitcount
) );
2196 if ( p
->font
->bpp
> shift
|| p
->font
->bpp
!= shift
)
2198 /* select next higher value */
2199 p
->font
->bpp
= (unsigned short)( shift
<< 1 );
2200 FT_TRACE2(( "_bdf_parse_start: " ACMSG11
, p
->font
->bpp
));
2206 p
->flags
|= _BDF_SIZE
;
2211 error
= BDF_Err_Invalid_File_Format
;
2218 /*************************************************************************/
2222 /*************************************************************************/
2225 FT_LOCAL_DEF( FT_Error
)
2226 bdf_load_font( FT_Stream stream
,
2227 FT_Memory extmemory
,
2228 bdf_options_t
* opts
,
2231 unsigned long lineno
= 0; /* make compiler happy */
2234 FT_Memory memory
= extmemory
;
2235 FT_Error error
= BDF_Err_Ok
;
2242 p
->opts
= (bdf_options_t
*)( ( opts
!= 0 ) ? opts
: &_bdf_opts
);
2244 p
->memory
= extmemory
; /* only during font creation */
2246 _bdf_list_init( &p
->list
, extmemory
);
2248 error
= _bdf_readstream( stream
, _bdf_parse_start
,
2249 (void *)p
, &lineno
);
2255 /* If the font is not proportional, set the font's monowidth */
2256 /* field to the width of the font bounding box. */
2257 memory
= p
->font
->memory
;
2259 if ( p
->font
->spacing
!= BDF_PROPORTIONAL
)
2260 p
->font
->monowidth
= p
->font
->bbx
.width
;
2262 /* If the number of glyphs loaded is not that of the original count, */
2263 /* indicate the difference. */
2264 if ( p
->cnt
!= p
->font
->glyphs_used
+ p
->font
->unencoded_used
)
2266 FT_TRACE2(( "bdf_load_font: " ACMSG15
, p
->cnt
,
2267 p
->font
->glyphs_used
+ p
->font
->unencoded_used
));
2268 p
->font
->modified
= 1;
2271 /* Once the font has been loaded, adjust the overall font metrics if */
2273 if ( p
->opts
->correct_metrics
!= 0 &&
2274 ( p
->font
->glyphs_used
> 0 || p
->font
->unencoded_used
> 0 ) )
2276 if ( p
->maxrb
- p
->minlb
!= p
->font
->bbx
.width
)
2278 FT_TRACE2(( "bdf_load_font: " ACMSG3
,
2279 p
->font
->bbx
.width
, p
->maxrb
- p
->minlb
));
2280 p
->font
->bbx
.width
= (unsigned short)( p
->maxrb
- p
->minlb
);
2281 p
->font
->modified
= 1;
2284 if ( p
->font
->bbx
.x_offset
!= p
->minlb
)
2286 FT_TRACE2(( "bdf_load_font: " ACMSG4
,
2287 p
->font
->bbx
.x_offset
, p
->minlb
));
2288 p
->font
->bbx
.x_offset
= p
->minlb
;
2289 p
->font
->modified
= 1;
2292 if ( p
->font
->bbx
.ascent
!= p
->maxas
)
2294 FT_TRACE2(( "bdf_load_font: " ACMSG5
,
2295 p
->font
->bbx
.ascent
, p
->maxas
));
2296 p
->font
->bbx
.ascent
= p
->maxas
;
2297 p
->font
->modified
= 1;
2300 if ( p
->font
->bbx
.descent
!= p
->maxds
)
2302 FT_TRACE2(( "bdf_load_font: " ACMSG6
,
2303 p
->font
->bbx
.descent
, p
->maxds
));
2304 p
->font
->bbx
.descent
= p
->maxds
;
2305 p
->font
->bbx
.y_offset
= (short)( -p
->maxds
);
2306 p
->font
->modified
= 1;
2309 if ( p
->maxas
+ p
->maxds
!= p
->font
->bbx
.height
)
2311 FT_TRACE2(( "bdf_load_font: " ACMSG7
,
2312 p
->font
->bbx
.height
, p
->maxas
+ p
->maxds
));
2313 p
->font
->bbx
.height
= (unsigned short)( p
->maxas
+ p
->maxds
);
2316 if ( p
->flags
& _BDF_SWIDTH_ADJ
)
2317 FT_TRACE2(( "bdf_load_font: " ACMSG8
));
2321 if ( p
->flags
& _BDF_START
)
2324 /* The ENDFONT field was never reached or did not exist. */
2325 if ( !( p
->flags
& _BDF_GLYPHS
) )
2327 /* Error happened while parsing header. */
2328 FT_ERROR(( "bdf_load_font: " ERRMSG2
, lineno
));
2329 error
= BDF_Err_Corrupted_Font_Header
;
2334 /* Error happened when parsing glyphs. */
2335 FT_ERROR(( "bdf_load_font: " ERRMSG3
, lineno
));
2336 error
= BDF_Err_Corrupted_Font_Glyphs
;
2344 /* Make sure the comments are NULL terminated if they exist. */
2345 memory
= p
->font
->memory
;
2347 if ( p
->font
->comments_len
> 0 ) {
2348 if ( FT_RENEW_ARRAY( p
->font
->comments
,
2349 p
->font
->comments_len
,
2350 p
->font
->comments_len
+ 1 ) )
2353 p
->font
->comments
[p
->font
->comments_len
] = 0;
2356 else if ( error
== BDF_Err_Ok
)
2357 error
= BDF_Err_Invalid_File_Format
;
2364 _bdf_list_done( &p
->list
);
2374 bdf_free_font( p
->font
);
2384 FT_LOCAL_DEF( void )
2385 bdf_free_font( bdf_font_t
* font
)
2387 bdf_property_t
* prop
;
2389 bdf_glyph_t
* glyphs
;
2396 memory
= font
->memory
;
2398 FT_FREE( font
->name
);
2400 /* Free up the internal hash table of property names. */
2401 if ( font
->internal
)
2403 hash_free( (hashtable
*)font
->internal
, memory
);
2404 FT_FREE( font
->internal
);
2407 /* Free up the comment info. */
2408 FT_FREE( font
->comments
);
2410 /* Free up the properties. */
2411 for ( i
= 0; i
< font
->props_size
; i
++ )
2413 if ( font
->props
[i
].format
== BDF_ATOM
)
2414 FT_FREE( font
->props
[i
].value
.atom
);
2417 FT_FREE( font
->props
);
2419 /* Free up the character info. */
2420 for ( i
= 0, glyphs
= font
->glyphs
;
2421 i
< font
->glyphs_used
; i
++, glyphs
++ )
2423 FT_FREE( glyphs
->name
);
2424 FT_FREE( glyphs
->bitmap
);
2427 for ( i
= 0, glyphs
= font
->unencoded
; i
< font
->unencoded_used
;
2430 FT_FREE( glyphs
->name
);
2431 FT_FREE( glyphs
->bitmap
);
2434 FT_FREE( font
->glyphs
);
2435 FT_FREE( font
->unencoded
);
2437 /* Free up the overflow storage if it was used. */
2438 for ( i
= 0, glyphs
= font
->overflow
.glyphs
;
2439 i
< font
->overflow
.glyphs_used
; i
++, glyphs
++ )
2441 FT_FREE( glyphs
->name
);
2442 FT_FREE( glyphs
->bitmap
);
2445 FT_FREE( font
->overflow
.glyphs
);
2448 hash_free( &(font
->proptbl
), memory
);
2450 /* Free up the user defined properties. */
2451 for (prop
= font
->user_props
, i
= 0;
2452 i
< font
->nuser_props
; i
++, prop
++ )
2454 FT_FREE( prop
->name
);
2455 if ( prop
->format
== BDF_ATOM
)
2456 FT_FREE( prop
->value
.atom
);
2459 FT_FREE( font
->user_props
);
2461 /* FREE( font ); */ /* XXX Fixme */
2465 FT_LOCAL_DEF( bdf_property_t
* )
2466 bdf_get_font_property( bdf_font_t
* font
,
2472 if ( font
== 0 || font
->props_size
== 0 || name
== 0 || *name
== 0 )
2475 hn
= hash_lookup( name
, (hashtable
*)font
->internal
);
2477 return hn
? ( font
->props
+ hn
->data
) : 0;