2 * Copyright 2000 Computing Research Labs, New Mexico State University
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 /* An auxiliary macro to parse properties, to be used in conditionals. */
173 /* It behaves like `strncmp' but also tests the following character */
174 /* whether it is a whitespace or NULL. */
175 /* `property' is a constant string of length `n' to compare with. */
176 #define _bdf_strncmp( name, property, n ) \
177 ( ft_strncmp( name, property, n ) || \
178 !( name[n] == ' ' || \
184 /* Auto correction messages. */
185 #define ACMSG1 "FONT_ASCENT property missing. " \
186 "Added `FONT_ASCENT %hd'.\n"
187 #define ACMSG2 "FONT_DESCENT property missing. " \
188 "Added `FONT_DESCENT %hd'.\n"
189 #define ACMSG3 "Font width != actual width. Old: %hd New: %hd.\n"
190 #define ACMSG4 "Font left bearing != actual left bearing. " \
191 "Old: %hd New: %hd.\n"
192 #define ACMSG5 "Font ascent != actual ascent. Old: %hd New: %hd.\n"
193 #define ACMSG6 "Font descent != actual descent. Old: %hd New: %hd.\n"
194 #define ACMSG7 "Font height != actual height. Old: %hd New: %hd.\n"
195 #define ACMSG8 "Glyph scalable width (SWIDTH) adjustments made.\n"
196 #define ACMSG9 "SWIDTH field missing at line %ld. Set automatically.\n"
197 #define ACMSG10 "DWIDTH field missing at line %ld. Set to glyph width.\n"
198 #define ACMSG11 "SIZE bits per pixel field adjusted to %hd.\n"
199 #define ACMSG12 "Duplicate encoding %ld (%s) changed to unencoded.\n"
200 #define ACMSG13 "Glyph %ld extra rows removed.\n"
201 #define ACMSG14 "Glyph %ld extra columns removed.\n"
202 #define ACMSG15 "Incorrect glyph count: %ld indicated but %ld found.\n"
203 #define ACMSG16 "Glyph %ld missing columns padded with zero bits.\n"
204 #define ACMSG17 "Adjusting number of glyphs to %ld.\n"
206 /* Error messages. */
207 #define ERRMSG1 "[line %ld] Missing `%s' line.\n"
208 #define ERRMSG2 "[line %ld] Font header corrupted or missing fields.\n"
209 #define ERRMSG3 "[line %ld] Font glyphs corrupted or missing fields.\n"
210 #define ERRMSG4 "[line %ld] BBX too big.\n"
211 #define ERRMSG5 "[line %ld] `%s' value too big.\n"
212 #define ERRMSG6 "[line %ld] Input line too long.\n"
213 #define ERRMSG7 "[line %ld] Font name too long.\n"
214 #define ERRMSG8 "[line %ld] Invalid `%s' value.\n"
215 #define ERRMSG9 "[line %ld] Invalid keyword.\n"
217 /* Debug messages. */
218 #define DBGMSG1 " [%6ld] %s" /* no \n */
219 #define DBGMSG2 " (0x%lX)\n"
222 /*************************************************************************/
224 /* Utility types and functions. */
226 /*************************************************************************/
229 /* Function type for parsing lines of a BDF font. */
232 (*_bdf_line_func_t
)( char* line
,
233 unsigned long linelen
,
234 unsigned long lineno
,
239 /* List structure for splitting lines into fields. */
241 typedef struct _bdf_list_t_
251 /* Structure used while loading BDF fonts. */
253 typedef struct _bdf_parse_t_
273 unsigned long have
[34816]; /* must be in sync with `nmod' and `umod' */
274 /* arrays from `bdf_font_t' structure */
278 unsigned long size
; /* the stream size */
283 #define setsbit( m, cc ) \
284 ( m[(FT_Byte)(cc) >> 3] |= (FT_Byte)( 1 << ( (cc) & 7 ) ) )
285 #define sbitset( m, cc ) \
286 ( m[(FT_Byte)(cc) >> 3] & ( 1 << ( (cc) & 7 ) ) )
290 _bdf_list_init( _bdf_list_t
* list
,
294 list
->memory
= memory
;
299 _bdf_list_done( _bdf_list_t
* list
)
301 FT_Memory memory
= list
->memory
;
306 FT_FREE( list
->field
);
313 _bdf_list_ensure( _bdf_list_t
* list
,
314 unsigned long num_items
) /* same as _bdf_list_t.used */
316 FT_Error error
= FT_Err_Ok
;
319 if ( num_items
> list
->size
)
321 unsigned long oldsize
= list
->size
; /* same as _bdf_list_t.size */
322 unsigned long newsize
= oldsize
+ ( oldsize
>> 1 ) + 5;
323 unsigned long bigsize
= (unsigned long)( FT_INT_MAX
/ sizeof ( char* ) );
324 FT_Memory memory
= list
->memory
;
327 if ( oldsize
== bigsize
)
329 error
= FT_THROW( Out_Of_Memory
);
332 else if ( newsize
< oldsize
|| newsize
> bigsize
)
335 if ( FT_RENEW_ARRAY( list
->field
, oldsize
, newsize
) )
338 list
->size
= newsize
;
347 _bdf_list_shift( _bdf_list_t
* list
,
353 if ( list
== 0 || list
->used
== 0 || n
== 0 )
356 if ( n
>= list
->used
)
362 for ( u
= n
, i
= 0; u
< list
->used
; i
++, u
++ )
363 list
->field
[i
] = list
->field
[u
];
368 /* An empty string for empty fields. */
370 static const char empty
[1] = { 0 }; /* XXX eliminate this */
374 _bdf_list_join( _bdf_list_t
* list
,
376 unsigned long *alen
)
384 if ( list
== 0 || list
->used
== 0 )
388 for ( i
= j
= 0; i
< list
->used
; i
++ )
390 char* fp
= list
->field
[i
];
396 if ( i
+ 1 < list
->used
)
407 /* The code below ensures that we have at least 4 + 1 `field' */
408 /* elements in `list' (which are possibly NULL) so that we */
409 /* don't have to check the number of fields in most cases. */
412 _bdf_list_split( _bdf_list_t
* list
,
415 unsigned long linelen
)
417 unsigned long final_empty
;
421 FT_Error error
= FT_Err_Ok
;
424 /* Initialize the list. */
428 list
->field
[0] = (char*)empty
;
429 list
->field
[1] = (char*)empty
;
430 list
->field
[2] = (char*)empty
;
431 list
->field
[3] = (char*)empty
;
432 list
->field
[4] = (char*)empty
;
435 /* If the line is empty, then simply return. */
436 if ( linelen
== 0 || line
[0] == 0 )
439 /* In the original code, if the `separators' parameter is NULL or */
440 /* empty, the list is split into individual bytes. We don't need */
441 /* this, so an error is signaled. */
442 if ( separators
== 0 || *separators
== 0 )
444 error
= FT_THROW( Invalid_Argument
);
448 /* Prepare the separator bitmap. */
449 FT_MEM_ZERO( seps
, 32 );
451 /* If the very last character of the separator string is a plus, then */
452 /* set the `mult' flag to indicate that multiple separators should be */
453 /* collapsed into one. */
454 for ( mult
= 0, sp
= separators
; sp
&& *sp
; sp
++ )
456 if ( *sp
== '+' && *( sp
+ 1 ) == 0 )
459 setsbit( seps
, *sp
);
462 /* Break the line up into fields. */
463 for ( final_empty
= 0, sp
= ep
= line
, end
= sp
+ linelen
;
466 /* Collect everything that is not a separator. */
467 for ( ; *ep
&& !sbitset( seps
, *ep
); ep
++ )
470 /* Resize the list if necessary. */
471 if ( list
->used
== list
->size
)
473 error
= _bdf_list_ensure( list
, list
->used
+ 1 );
478 /* Assign the field appropriately. */
479 list
->field
[list
->used
++] = ( ep
> sp
) ? sp
: (char*)empty
;
485 /* If multiple separators should be collapsed, do it now by */
486 /* setting all the separator characters to 0. */
487 for ( ; *ep
&& sbitset( seps
, *ep
); ep
++ )
491 /* Don't collapse multiple separators by making them 0, so just */
492 /* make the one encountered 0. */
495 final_empty
= ( ep
> sp
&& *ep
== 0 );
499 /* Finally, NULL-terminate the list. */
500 if ( list
->used
+ final_empty
>= list
->size
)
502 error
= _bdf_list_ensure( list
, list
->used
+ final_empty
+ 1 );
508 list
->field
[list
->used
++] = (char*)empty
;
510 list
->field
[list
->used
] = 0;
517 #define NO_SKIP 256 /* this value cannot be stored in a 'char' */
521 _bdf_readstream( FT_Stream stream
,
522 _bdf_line_func_t callback
,
527 unsigned long lineno
, buf_size
;
528 int refill
, hold
, to_skip
;
529 ptrdiff_t bytes
, start
, end
, cursor
, avail
;
531 FT_Memory memory
= stream
->memory
;
532 FT_Error error
= FT_Err_Ok
;
537 error
= FT_THROW( Invalid_Argument
);
541 /* initial size and allocation of the input buffer */
544 if ( FT_NEW_ARRAY( buf
, buf_size
) )
555 bytes
= 0; /* make compiler happy */
561 bytes
= (ptrdiff_t)FT_Stream_TryRead(
562 stream
, (FT_Byte
*)buf
+ cursor
,
563 buf_size
- (unsigned long)cursor
);
564 avail
= cursor
+ bytes
;
571 /* should we skip an optional character like \n or \r? */
572 if ( start
< avail
&& buf
[start
] == to_skip
)
579 /* try to find the end of the line */
580 while ( end
< avail
&& buf
[end
] != '\n' && buf
[end
] != '\r' )
583 /* if we hit the end of the buffer, try shifting its content */
584 /* or even resizing it */
587 if ( bytes
== 0 ) /* last line in file doesn't end in \r or \n */
588 break; /* ignore it then exit */
592 /* this line is definitely too long; try resizing the input */
593 /* buffer a bit to handle it. */
597 if ( buf_size
>= 65536UL ) /* limit ourselves to 64KByte */
599 FT_ERROR(( "_bdf_readstream: " ERRMSG6
, lineno
));
600 error
= FT_THROW( Invalid_Argument
);
604 new_size
= buf_size
* 2;
605 if ( FT_RENEW_ARRAY( buf
, buf_size
, new_size
) )
608 cursor
= (ptrdiff_t)buf_size
;
613 bytes
= avail
- start
;
615 FT_MEM_MOVE( buf
, buf
+ start
, bytes
);
625 /* Temporarily NUL-terminate the line. */
629 /* XXX: Use encoding independent value for 0x1A */
630 if ( buf
[start
] != '#' && buf
[start
] != 0x1A && end
> start
)
632 error
= (*cb
)( buf
+ start
, (unsigned long)( end
- start
), lineno
,
633 (void*)&cb
, client_data
);
634 /* Redo if we have encountered CHARS without properties. */
636 error
= (*cb
)( buf
+ start
, (unsigned long)( end
- start
), lineno
,
637 (void*)&cb
, client_data
);
643 buf
[end
] = (char)hold
;
648 else if ( hold
== '\r' )
662 /* XXX: make this work with EBCDIC also */
664 static const unsigned char a2i
[128] =
666 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
667 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
668 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
669 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
670 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x00, 0x00,
671 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x00,
672 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
673 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
674 0x00, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00,
675 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
676 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
679 static const unsigned char ddigits
[32] =
681 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x03,
682 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
683 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
684 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
687 static const unsigned char hdigits
[32] =
689 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x03,
690 0x7E, 0x00, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x00,
691 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
692 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
696 /* Routine to convert a decimal ASCII string to an unsigned long integer. */
698 _bdf_atoul( char* s
)
703 if ( s
== 0 || *s
== 0 )
706 for ( v
= 0; sbitset( ddigits
, *s
); s
++ )
707 v
= v
* 10 + a2i
[(int)*s
];
713 /* Routine to convert a decimal ASCII string to a signed long integer. */
720 if ( s
== 0 || *s
== 0 )
723 /* Check for a minus sign. */
731 for ( v
= 0; sbitset( ddigits
, *s
); s
++ )
732 v
= v
* 10 + a2i
[(int)*s
];
734 return ( !neg
) ? v
: -v
;
738 /* Routine to convert a decimal ASCII string to an unsigned short integer. */
739 static unsigned short
740 _bdf_atous( char* s
)
745 if ( s
== 0 || *s
== 0 )
748 for ( v
= 0; sbitset( ddigits
, *s
); s
++ )
749 v
= (unsigned short)( v
* 10 + a2i
[(int)*s
] );
755 /* Routine to convert a decimal ASCII string to a signed short integer. */
762 if ( s
== 0 || *s
== 0 )
765 /* Check for a minus. */
773 for ( v
= 0; sbitset( ddigits
, *s
); s
++ )
774 v
= (short)( v
* 10 + a2i
[(int)*s
] );
776 return (short)( ( !neg
) ? v
: -v
);
780 /* Routine to compare two glyphs by encoding so they can be sorted. */
782 by_encoding( const void* a
,
785 bdf_glyph_t
*c1
, *c2
;
788 c1
= (bdf_glyph_t
*)a
;
789 c2
= (bdf_glyph_t
*)b
;
791 if ( c1
->encoding
< c2
->encoding
)
794 if ( c1
->encoding
> c2
->encoding
)
802 bdf_create_property( char* name
,
808 FT_Memory memory
= font
->memory
;
809 FT_Error error
= FT_Err_Ok
;
812 /* First check whether the property has */
813 /* already been added or not. If it has, then */
814 /* simply ignore it. */
815 if ( ft_hash_str_lookup( name
, &(font
->proptbl
) ) )
818 if ( FT_RENEW_ARRAY( font
->user_props
,
820 font
->nuser_props
+ 1 ) )
823 p
= font
->user_props
+ font
->nuser_props
;
826 n
= ft_strlen( name
) + 1;
827 if ( n
> FT_ULONG_MAX
)
828 return FT_THROW( Invalid_Argument
);
830 if ( FT_NEW_ARRAY( p
->name
, n
) )
833 FT_MEM_COPY( (char *)p
->name
, name
, n
);
838 n
= _num_bdf_properties
+ font
->nuser_props
;
840 error
= ft_hash_str_insert( p
->name
, n
, &(font
->proptbl
), memory
);
851 FT_LOCAL_DEF( bdf_property_t
* )
852 bdf_get_property( char* name
,
858 if ( name
== 0 || *name
== 0 )
861 if ( ( propid
= ft_hash_str_lookup( name
, &(font
->proptbl
) ) ) == NULL
)
864 if ( *propid
>= _num_bdf_properties
)
865 return font
->user_props
+ ( *propid
- _num_bdf_properties
);
867 return (bdf_property_t
*)_bdf_properties
+ *propid
;
871 /*************************************************************************/
873 /* BDF font file parsing flags and functions. */
875 /*************************************************************************/
880 #define BDF_START_ 0x0001U
881 #define BDF_FONT_NAME_ 0x0002U
882 #define BDF_SIZE_ 0x0004U
883 #define BDF_FONT_BBX_ 0x0008U
884 #define BDF_PROPS_ 0x0010U
885 #define BDF_GLYPHS_ 0x0020U
886 #define BDF_GLYPH_ 0x0040U
887 #define BDF_ENCODING_ 0x0080U
888 #define BDF_SWIDTH_ 0x0100U
889 #define BDF_DWIDTH_ 0x0200U
890 #define BDF_BBX_ 0x0400U
891 #define BDF_BITMAP_ 0x0800U
893 #define BDF_SWIDTH_ADJ_ 0x1000U
895 #define BDF_GLYPH_BITS_ ( BDF_GLYPH_ | \
902 #define BDF_GLYPH_WIDTH_CHECK_ 0x40000000UL
903 #define BDF_GLYPH_HEIGHT_CHECK_ 0x80000000UL
907 _bdf_add_comment( bdf_font_t
* font
,
912 FT_Memory memory
= font
->memory
;
913 FT_Error error
= FT_Err_Ok
;
916 if ( FT_RENEW_ARRAY( font
->comments
,
918 font
->comments_len
+ len
+ 1 ) )
921 cp
= font
->comments
+ font
->comments_len
;
923 FT_MEM_COPY( cp
, comment
, len
);
926 font
->comments_len
+= len
+ 1;
933 /* Set the spacing from the font name if it exists, or set it to the */
934 /* default specified in the options. */
936 _bdf_set_default_spacing( bdf_font_t
* font
,
938 unsigned long lineno
)
944 FT_Error error
= FT_Err_Ok
;
946 FT_UNUSED( lineno
); /* only used in debug mode */
949 if ( font
== 0 || font
->name
== 0 || font
->name
[0] == 0 )
951 error
= FT_THROW( Invalid_Argument
);
955 memory
= font
->memory
;
957 _bdf_list_init( &list
, memory
);
959 font
->spacing
= opts
->font_spacing
;
961 len
= ft_strlen( font
->name
) + 1;
962 /* Limit ourselves to 256 characters in the font name. */
965 FT_ERROR(( "_bdf_set_default_spacing: " ERRMSG7
, lineno
));
966 error
= FT_THROW( Invalid_Argument
);
970 FT_MEM_COPY( name
, font
->name
, len
);
972 error
= _bdf_list_split( &list
, (char *)"-", name
, (unsigned long)len
);
976 if ( list
.used
== 15 )
978 switch ( list
.field
[11][0] )
982 font
->spacing
= BDF_CHARCELL
;
986 font
->spacing
= BDF_MONOWIDTH
;
990 font
->spacing
= BDF_PROPORTIONAL
;
996 _bdf_list_done( &list
);
1003 /* Determine whether the property is an atom or not. If it is, then */
1004 /* clean it up so the double quotes are removed if they exist. */
1006 _bdf_is_atom( char* line
,
1007 unsigned long linelen
,
1017 *name
= sp
= ep
= line
;
1019 while ( *ep
&& *ep
!= ' ' && *ep
!= '\t' )
1029 p
= bdf_get_property( sp
, font
);
1031 /* Restore the character that was saved before any return can happen. */
1035 /* If the property exists and is not an atom, just return here. */
1036 if ( p
&& p
->format
!= BDF_ATOM
)
1039 /* The property is an atom. Trim all leading and trailing whitespace */
1040 /* and double quotes for the atom value. */
1042 ep
= line
+ linelen
;
1044 /* Trim the leading whitespace if it exists. */
1048 ( *sp
== ' ' || *sp
== '\t' ) )
1051 /* Trim the leading double quote if it exists. */
1056 /* Trim the trailing whitespace if it exists. */
1058 ( *( ep
- 1 ) == ' ' || *( ep
- 1 ) == '\t' ) )
1061 /* Trim the trailing double quote if it exists. */
1062 if ( ep
> sp
&& *( ep
- 1 ) == '"' )
1070 _bdf_add_property( bdf_font_t
* font
,
1073 unsigned long lineno
)
1076 bdf_property_t
*prop
, *fp
;
1077 FT_Memory memory
= font
->memory
;
1078 FT_Error error
= FT_Err_Ok
;
1080 FT_UNUSED( lineno
); /* only used in debug mode */
1083 /* First, check whether the property already exists in the font. */
1084 if ( ( propid
= ft_hash_str_lookup( name
,
1085 (FT_Hash
)font
->internal
) ) != NULL
)
1087 /* The property already exists in the font, so simply replace */
1088 /* the value of the property with the current value. */
1089 fp
= font
->props
+ *propid
;
1091 switch ( fp
->format
)
1094 /* Delete the current atom if it exists. */
1095 FT_FREE( fp
->value
.atom
);
1097 if ( value
&& value
[0] != 0 )
1099 if ( FT_STRDUP( fp
->value
.atom
, value
) )
1105 fp
->value
.l
= _bdf_atol( value
);
1109 fp
->value
.ul
= _bdf_atoul( value
);
1119 /* See whether this property type exists yet or not. */
1120 /* If not, create it. */
1121 propid
= ft_hash_str_lookup( name
, &(font
->proptbl
) );
1122 if ( propid
== NULL
)
1124 error
= bdf_create_property( name
, BDF_ATOM
, font
);
1127 propid
= ft_hash_str_lookup( name
, &(font
->proptbl
) );
1130 /* Allocate another property if this is overflow. */
1131 if ( font
->props_used
== font
->props_size
)
1133 if ( font
->props_size
== 0 )
1135 if ( FT_NEW_ARRAY( font
->props
, 1 ) )
1140 if ( FT_RENEW_ARRAY( font
->props
,
1142 font
->props_size
+ 1 ) )
1146 fp
= font
->props
+ font
->props_size
;
1147 FT_MEM_ZERO( fp
, sizeof ( bdf_property_t
) );
1151 if ( *propid
>= _num_bdf_properties
)
1152 prop
= font
->user_props
+ ( *propid
- _num_bdf_properties
);
1154 prop
= (bdf_property_t
*)_bdf_properties
+ *propid
;
1156 fp
= font
->props
+ font
->props_used
;
1158 fp
->name
= prop
->name
;
1159 fp
->format
= prop
->format
;
1160 fp
->builtin
= prop
->builtin
;
1162 switch ( prop
->format
)
1166 if ( value
!= 0 && value
[0] )
1168 if ( FT_STRDUP( fp
->value
.atom
, value
) )
1174 fp
->value
.l
= _bdf_atol( value
);
1178 fp
->value
.ul
= _bdf_atoul( value
);
1182 /* If the property happens to be a comment, then it doesn't need */
1183 /* to be added to the internal hash table. */
1184 if ( _bdf_strncmp( name
, "COMMENT", 7 ) != 0 )
1186 /* Add the property to the font property table. */
1187 error
= ft_hash_str_insert( fp
->name
,
1189 (FT_Hash
)font
->internal
,
1197 /* Some special cases need to be handled here. The DEFAULT_CHAR */
1198 /* property needs to be located if it exists in the property list, the */
1199 /* FONT_ASCENT and FONT_DESCENT need to be assigned if they are */
1200 /* present, and the SPACING property should override the default */
1202 if ( _bdf_strncmp( name
, "DEFAULT_CHAR", 12 ) == 0 )
1203 font
->default_char
= fp
->value
.l
;
1204 else if ( _bdf_strncmp( name
, "FONT_ASCENT", 11 ) == 0 )
1205 font
->font_ascent
= fp
->value
.l
;
1206 else if ( _bdf_strncmp( name
, "FONT_DESCENT", 12 ) == 0 )
1207 font
->font_descent
= fp
->value
.l
;
1208 else if ( _bdf_strncmp( name
, "SPACING", 7 ) == 0 )
1210 if ( !fp
->value
.atom
)
1212 FT_ERROR(( "_bdf_add_property: " ERRMSG8
, lineno
, "SPACING" ));
1213 error
= FT_THROW( Invalid_File_Format
);
1217 if ( fp
->value
.atom
[0] == 'p' || fp
->value
.atom
[0] == 'P' )
1218 font
->spacing
= BDF_PROPORTIONAL
;
1219 else if ( fp
->value
.atom
[0] == 'm' || fp
->value
.atom
[0] == 'M' )
1220 font
->spacing
= BDF_MONOWIDTH
;
1221 else if ( fp
->value
.atom
[0] == 'c' || fp
->value
.atom
[0] == 'C' )
1222 font
->spacing
= BDF_CHARCELL
;
1230 static const unsigned char nibble_mask
[8] =
1232 0xFF, 0x80, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC, 0xFE
1236 /* Actually parse the glyph info and bitmaps. */
1238 _bdf_parse_glyphs( char* line
,
1239 unsigned long linelen
,
1240 unsigned long lineno
,
1247 unsigned long i
, slen
, nibbles
;
1254 FT_Error error
= FT_Err_Ok
;
1256 FT_UNUSED( call_data
);
1257 FT_UNUSED( lineno
); /* only used in debug mode */
1260 p
= (_bdf_parse_t
*)client_data
;
1263 memory
= font
->memory
;
1265 /* Check for a comment. */
1266 if ( _bdf_strncmp( line
, "COMMENT", 7 ) == 0 )
1276 error
= _bdf_add_comment( p
->font
, s
, linelen
);
1280 /* The very first thing expected is the number of glyphs. */
1281 if ( !( p
->flags
& BDF_GLYPHS_
) )
1283 if ( _bdf_strncmp( line
, "CHARS", 5 ) != 0 )
1285 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1
, lineno
, "CHARS" ));
1286 error
= FT_THROW( Missing_Chars_Field
);
1290 error
= _bdf_list_split( &p
->list
, (char *)" +", line
, linelen
);
1293 p
->cnt
= font
->glyphs_size
= _bdf_atoul( p
->list
.field
[1] );
1295 /* We need at least 20 bytes per glyph. */
1296 if ( p
->cnt
> p
->size
/ 20 )
1298 p
->cnt
= font
->glyphs_size
= p
->size
/ 20;
1299 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG17
, p
->cnt
));
1302 /* Make sure the number of glyphs is non-zero. */
1304 font
->glyphs_size
= 64;
1306 /* Limit ourselves to 1,114,112 glyphs in the font (this is the */
1307 /* number of code points available in Unicode). */
1308 if ( p
->cnt
>= 0x110000UL
)
1310 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG5
, lineno
, "CHARS" ));
1311 error
= FT_THROW( Invalid_Argument
);
1315 if ( FT_NEW_ARRAY( font
->glyphs
, font
->glyphs_size
) )
1318 p
->flags
|= BDF_GLYPHS_
;
1323 /* Check for the ENDFONT field. */
1324 if ( _bdf_strncmp( line
, "ENDFONT", 7 ) == 0 )
1326 if ( p
->flags
& BDF_GLYPH_BITS_
)
1328 /* Missing ENDCHAR field. */
1329 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1
, lineno
, "ENDCHAR" ));
1330 error
= FT_THROW( Corrupted_Font_Glyphs
);
1334 /* Sort the glyphs by encoding. */
1335 ft_qsort( (char *)font
->glyphs
,
1337 sizeof ( bdf_glyph_t
),
1340 p
->flags
&= ~BDF_START_
;
1345 /* Check for the ENDCHAR field. */
1346 if ( _bdf_strncmp( line
, "ENDCHAR", 7 ) == 0 )
1349 p
->flags
&= ~BDF_GLYPH_BITS_
;
1354 /* Check whether a glyph is being scanned but should be */
1355 /* ignored because it is an unencoded glyph. */
1356 if ( ( p
->flags
& BDF_GLYPH_
) &&
1357 p
->glyph_enc
== -1 &&
1358 p
->opts
->keep_unencoded
== 0 )
1361 /* Check for the STARTCHAR field. */
1362 if ( _bdf_strncmp( line
, "STARTCHAR", 9 ) == 0 )
1364 if ( p
->flags
& BDF_GLYPH_BITS_
)
1366 /* Missing ENDCHAR field. */
1367 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1
, lineno
, "ENDCHAR" ));
1368 error
= FT_THROW( Missing_Startchar_Field
);
1372 /* Set the character name in the parse info first until the */
1373 /* encoding can be checked for an unencoded character. */
1374 FT_FREE( p
->glyph_name
);
1376 error
= _bdf_list_split( &p
->list
, (char *)" +", line
, linelen
);
1380 _bdf_list_shift( &p
->list
, 1 );
1382 s
= _bdf_list_join( &p
->list
, ' ', &slen
);
1386 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG8
, lineno
, "STARTCHAR" ));
1387 error
= FT_THROW( Invalid_File_Format
);
1391 if ( FT_NEW_ARRAY( p
->glyph_name
, slen
+ 1 ) )
1394 FT_MEM_COPY( p
->glyph_name
, s
, slen
+ 1 );
1396 p
->flags
|= BDF_GLYPH_
;
1398 FT_TRACE4(( DBGMSG1
, lineno
, s
));
1403 /* Check for the ENCODING field. */
1404 if ( _bdf_strncmp( line
, "ENCODING", 8 ) == 0 )
1406 if ( !( p
->flags
& BDF_GLYPH_
) )
1408 /* Missing STARTCHAR field. */
1409 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1
, lineno
, "STARTCHAR" ));
1410 error
= FT_THROW( Missing_Startchar_Field
);
1414 error
= _bdf_list_split( &p
->list
, (char *)" +", line
, linelen
);
1418 p
->glyph_enc
= _bdf_atol( p
->list
.field
[1] );
1420 /* Normalize negative encoding values. The specification only */
1421 /* allows -1, but we can be more generous here. */
1422 if ( p
->glyph_enc
< -1 )
1425 /* Check for alternative encoding format. */
1426 if ( p
->glyph_enc
== -1 && p
->list
.used
> 2 )
1427 p
->glyph_enc
= _bdf_atol( p
->list
.field
[2] );
1429 if ( p
->glyph_enc
< -1 )
1432 FT_TRACE4(( DBGMSG2
, p
->glyph_enc
));
1434 /* Check that the encoding is in the Unicode range because */
1435 /* otherwise p->have (a bitmap with static size) overflows. */
1436 if ( p
->glyph_enc
> 0 &&
1437 (size_t)p
->glyph_enc
>= sizeof ( p
->have
) /
1438 sizeof ( unsigned long ) * 32 )
1440 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG5
, lineno
, "ENCODING" ));
1441 error
= FT_THROW( Invalid_File_Format
);
1445 /* Check whether this encoding has already been encountered. */
1446 /* If it has then change it to unencoded so it gets added if */
1448 if ( p
->glyph_enc
>= 0 )
1450 if ( _bdf_glyph_modified( p
->have
, p
->glyph_enc
) )
1452 /* Emit a message saying a glyph has been moved to the */
1453 /* unencoded area. */
1454 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG12
,
1455 p
->glyph_enc
, p
->glyph_name
));
1460 _bdf_set_glyph_modified( p
->have
, p
->glyph_enc
);
1463 if ( p
->glyph_enc
>= 0 )
1465 /* Make sure there are enough glyphs allocated in case the */
1466 /* number of characters happen to be wrong. */
1467 if ( font
->glyphs_used
== font
->glyphs_size
)
1469 if ( FT_RENEW_ARRAY( font
->glyphs
,
1471 font
->glyphs_size
+ 64 ) )
1474 font
->glyphs_size
+= 64;
1477 glyph
= font
->glyphs
+ font
->glyphs_used
++;
1478 glyph
->name
= p
->glyph_name
;
1479 glyph
->encoding
= p
->glyph_enc
;
1481 /* Reset the initial glyph info. */
1482 p
->glyph_name
= NULL
;
1486 /* Unencoded glyph. Check whether it should */
1487 /* be added or not. */
1488 if ( p
->opts
->keep_unencoded
!= 0 )
1490 /* Allocate the next unencoded glyph. */
1491 if ( font
->unencoded_used
== font
->unencoded_size
)
1493 if ( FT_RENEW_ARRAY( font
->unencoded
,
1494 font
->unencoded_size
,
1495 font
->unencoded_size
+ 4 ) )
1498 font
->unencoded_size
+= 4;
1501 glyph
= font
->unencoded
+ font
->unencoded_used
;
1502 glyph
->name
= p
->glyph_name
;
1503 glyph
->encoding
= (long)font
->unencoded_used
++;
1505 /* Reset the initial glyph info. */
1506 p
->glyph_name
= NULL
;
1510 /* Free up the glyph name if the unencoded shouldn't be */
1512 FT_FREE( p
->glyph_name
);
1515 p
->glyph_name
= NULL
;
1518 /* Clear the flags that might be added when width and height are */
1519 /* checked for consistency. */
1520 p
->flags
&= ~( BDF_GLYPH_WIDTH_CHECK_
| BDF_GLYPH_HEIGHT_CHECK_
);
1522 p
->flags
|= BDF_ENCODING_
;
1527 /* Point at the glyph being constructed. */
1528 if ( p
->glyph_enc
== -1 )
1529 glyph
= font
->unencoded
+ ( font
->unencoded_used
- 1 );
1531 glyph
= font
->glyphs
+ ( font
->glyphs_used
- 1 );
1533 /* Check whether a bitmap is being constructed. */
1534 if ( p
->flags
& BDF_BITMAP_
)
1536 /* If there are more rows than are specified in the glyph metrics, */
1537 /* ignore the remaining lines. */
1538 if ( p
->row
>= (unsigned long)glyph
->bbx
.height
)
1540 if ( !( p
->flags
& BDF_GLYPH_HEIGHT_CHECK_
) )
1542 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG13
, glyph
->encoding
));
1543 p
->flags
|= BDF_GLYPH_HEIGHT_CHECK_
;
1550 /* Only collect the number of nibbles indicated by the glyph */
1551 /* metrics. If there are more columns, they are simply ignored. */
1552 nibbles
= glyph
->bpr
<< 1;
1553 bp
= glyph
->bitmap
+ p
->row
* glyph
->bpr
;
1555 for ( i
= 0; i
< nibbles
; i
++ )
1558 if ( !sbitset( hdigits
, c
) )
1560 *bp
= (FT_Byte
)( ( *bp
<< 4 ) + a2i
[c
] );
1561 if ( i
+ 1 < nibbles
&& ( i
& 1 ) )
1565 /* If any line has not enough columns, */
1566 /* indicate they have been padded with zero bits. */
1568 !( p
->flags
& BDF_GLYPH_WIDTH_CHECK_
) )
1570 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG16
, glyph
->encoding
));
1571 p
->flags
|= BDF_GLYPH_WIDTH_CHECK_
;
1575 /* Remove possible garbage at the right. */
1576 mask_index
= ( glyph
->bbx
.width
* p
->font
->bpp
) & 7;
1577 if ( glyph
->bbx
.width
)
1578 *bp
&= nibble_mask
[mask_index
];
1580 /* If any line has extra columns, indicate they have been removed. */
1581 if ( i
== nibbles
&&
1582 sbitset( hdigits
, line
[nibbles
] ) &&
1583 !( p
->flags
& BDF_GLYPH_WIDTH_CHECK_
) )
1585 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG14
, glyph
->encoding
));
1586 p
->flags
|= BDF_GLYPH_WIDTH_CHECK_
;
1594 /* Expect the SWIDTH (scalable width) field next. */
1595 if ( _bdf_strncmp( line
, "SWIDTH", 6 ) == 0 )
1597 if ( !( p
->flags
& BDF_ENCODING_
) )
1598 goto Missing_Encoding
;
1600 error
= _bdf_list_split( &p
->list
, (char *)" +", line
, linelen
);
1604 glyph
->swidth
= (unsigned short)_bdf_atoul( p
->list
.field
[1] );
1605 p
->flags
|= BDF_SWIDTH_
;
1610 /* Expect the DWIDTH (scalable width) field next. */
1611 if ( _bdf_strncmp( line
, "DWIDTH", 6 ) == 0 )
1613 if ( !( p
->flags
& BDF_ENCODING_
) )
1614 goto Missing_Encoding
;
1616 error
= _bdf_list_split( &p
->list
, (char *)" +", line
, linelen
);
1620 glyph
->dwidth
= (unsigned short)_bdf_atoul( p
->list
.field
[1] );
1622 if ( !( p
->flags
& BDF_SWIDTH_
) )
1624 /* Missing SWIDTH field. Emit an auto correction message and set */
1625 /* the scalable width from the device width. */
1626 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG9
, lineno
));
1628 glyph
->swidth
= (unsigned short)FT_MulDiv(
1629 glyph
->dwidth
, 72000L,
1630 (FT_Long
)( font
->point_size
*
1631 font
->resolution_x
) );
1634 p
->flags
|= BDF_DWIDTH_
;
1638 /* Expect the BBX field next. */
1639 if ( _bdf_strncmp( line
, "BBX", 3 ) == 0 )
1641 if ( !( p
->flags
& BDF_ENCODING_
) )
1642 goto Missing_Encoding
;
1644 error
= _bdf_list_split( &p
->list
, (char *)" +", line
, linelen
);
1648 glyph
->bbx
.width
= _bdf_atous( p
->list
.field
[1] );
1649 glyph
->bbx
.height
= _bdf_atous( p
->list
.field
[2] );
1650 glyph
->bbx
.x_offset
= _bdf_atos( p
->list
.field
[3] );
1651 glyph
->bbx
.y_offset
= _bdf_atos( p
->list
.field
[4] );
1653 /* Generate the ascent and descent of the character. */
1654 glyph
->bbx
.ascent
= (short)( glyph
->bbx
.height
+ glyph
->bbx
.y_offset
);
1655 glyph
->bbx
.descent
= (short)( -glyph
->bbx
.y_offset
);
1657 /* Determine the overall font bounding box as the characters are */
1658 /* loaded so corrections can be done later if indicated. */
1659 p
->maxas
= (short)FT_MAX( glyph
->bbx
.ascent
, p
->maxas
);
1660 p
->maxds
= (short)FT_MAX( glyph
->bbx
.descent
, p
->maxds
);
1662 p
->rbearing
= (short)( glyph
->bbx
.width
+ glyph
->bbx
.x_offset
);
1664 p
->maxrb
= (short)FT_MAX( p
->rbearing
, p
->maxrb
);
1665 p
->minlb
= (short)FT_MIN( glyph
->bbx
.x_offset
, p
->minlb
);
1666 p
->maxlb
= (short)FT_MAX( glyph
->bbx
.x_offset
, p
->maxlb
);
1668 if ( !( p
->flags
& BDF_DWIDTH_
) )
1670 /* Missing DWIDTH field. Emit an auto correction message and set */
1671 /* the device width to the glyph width. */
1672 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG10
, lineno
));
1673 glyph
->dwidth
= glyph
->bbx
.width
;
1676 /* If the BDF_CORRECT_METRICS flag is set, then adjust the SWIDTH */
1677 /* value if necessary. */
1678 if ( p
->opts
->correct_metrics
!= 0 )
1680 /* Determine the point size of the glyph. */
1681 unsigned short sw
= (unsigned short)FT_MulDiv(
1682 glyph
->dwidth
, 72000L,
1683 (FT_Long
)( font
->point_size
*
1684 font
->resolution_x
) );
1687 if ( sw
!= glyph
->swidth
)
1691 if ( p
->glyph_enc
== -1 )
1692 _bdf_set_glyph_modified( font
->umod
,
1693 font
->unencoded_used
- 1 );
1695 _bdf_set_glyph_modified( font
->nmod
, glyph
->encoding
);
1697 p
->flags
|= BDF_SWIDTH_ADJ_
;
1702 p
->flags
|= BDF_BBX_
;
1706 /* And finally, gather up the bitmap. */
1707 if ( _bdf_strncmp( line
, "BITMAP", 6 ) == 0 )
1709 unsigned long bitmap_size
;
1712 if ( !( p
->flags
& BDF_BBX_
) )
1714 /* Missing BBX field. */
1715 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1
, lineno
, "BBX" ));
1716 error
= FT_THROW( Missing_Bbx_Field
);
1720 /* Allocate enough space for the bitmap. */
1721 glyph
->bpr
= ( glyph
->bbx
.width
* p
->font
->bpp
+ 7 ) >> 3;
1723 bitmap_size
= glyph
->bpr
* glyph
->bbx
.height
;
1724 if ( glyph
->bpr
> 0xFFFFU
|| bitmap_size
> 0xFFFFU
)
1726 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG4
, lineno
));
1727 error
= FT_THROW( Bbx_Too_Big
);
1731 glyph
->bytes
= (unsigned short)bitmap_size
;
1733 if ( FT_NEW_ARRAY( glyph
->bitmap
, glyph
->bytes
) )
1737 p
->flags
|= BDF_BITMAP_
;
1742 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG9
, lineno
));
1743 error
= FT_THROW( Invalid_File_Format
);
1747 /* Missing ENCODING field. */
1748 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1
, lineno
, "ENCODING" ));
1749 error
= FT_THROW( Missing_Encoding_Field
);
1752 if ( error
&& ( p
->flags
& BDF_GLYPH_
) )
1753 FT_FREE( p
->glyph_name
);
1759 /* Load the font properties. */
1761 _bdf_parse_properties( char* line
,
1762 unsigned long linelen
,
1763 unsigned long lineno
,
1768 _bdf_line_func_t
* next
;
1773 FT_Error error
= FT_Err_Ok
;
1775 FT_UNUSED( lineno
);
1778 next
= (_bdf_line_func_t
*)call_data
;
1779 p
= (_bdf_parse_t
*) client_data
;
1781 /* Check for the end of the properties. */
1782 if ( _bdf_strncmp( line
, "ENDPROPERTIES", 13 ) == 0 )
1784 /* If the FONT_ASCENT or FONT_DESCENT properties have not been */
1785 /* encountered yet, then make sure they are added as properties and */
1786 /* make sure they are set from the font bounding box info. */
1788 /* This is *always* done regardless of the options, because X11 */
1789 /* requires these two fields to compile fonts. */
1790 if ( bdf_get_font_property( p
->font
, "FONT_ASCENT" ) == 0 )
1792 p
->font
->font_ascent
= p
->font
->bbx
.ascent
;
1793 ft_sprintf( nbuf
, "%hd", p
->font
->bbx
.ascent
);
1794 error
= _bdf_add_property( p
->font
, (char *)"FONT_ASCENT",
1799 FT_TRACE2(( "_bdf_parse_properties: " ACMSG1
, p
->font
->bbx
.ascent
));
1800 p
->font
->modified
= 1;
1803 if ( bdf_get_font_property( p
->font
, "FONT_DESCENT" ) == 0 )
1805 p
->font
->font_descent
= p
->font
->bbx
.descent
;
1806 ft_sprintf( nbuf
, "%hd", p
->font
->bbx
.descent
);
1807 error
= _bdf_add_property( p
->font
, (char *)"FONT_DESCENT",
1812 FT_TRACE2(( "_bdf_parse_properties: " ACMSG2
, p
->font
->bbx
.descent
));
1813 p
->font
->modified
= 1;
1816 p
->flags
&= ~BDF_PROPS_
;
1817 *next
= _bdf_parse_glyphs
;
1822 /* Ignore the _XFREE86_GLYPH_RANGES properties. */
1823 if ( _bdf_strncmp( line
, "_XFREE86_GLYPH_RANGES", 21 ) == 0 )
1826 /* Handle COMMENT fields and properties in a special way to preserve */
1828 if ( _bdf_strncmp( line
, "COMMENT", 7 ) == 0 )
1830 name
= value
= line
;
1834 error
= _bdf_add_property( p
->font
, name
, value
, lineno
);
1838 else if ( _bdf_is_atom( line
, linelen
, &name
, &value
, p
->font
) )
1840 error
= _bdf_add_property( p
->font
, name
, value
, lineno
);
1846 error
= _bdf_list_split( &p
->list
, (char *)" +", line
, linelen
);
1849 name
= p
->list
.field
[0];
1851 _bdf_list_shift( &p
->list
, 1 );
1852 value
= _bdf_list_join( &p
->list
, ' ', &vlen
);
1854 error
= _bdf_add_property( p
->font
, name
, value
, lineno
);
1864 /* Load the font header. */
1866 _bdf_parse_start( char* line
,
1867 unsigned long linelen
,
1868 unsigned long lineno
,
1873 _bdf_line_func_t
* next
;
1878 FT_Memory memory
= NULL
;
1879 FT_Error error
= FT_Err_Ok
;
1881 FT_UNUSED( lineno
); /* only used in debug mode */
1884 next
= (_bdf_line_func_t
*)call_data
;
1885 p
= (_bdf_parse_t
*) client_data
;
1888 memory
= p
->font
->memory
;
1890 /* Check for a comment. This is done to handle those fonts that have */
1891 /* comments before the STARTFONT line for some reason. */
1892 if ( _bdf_strncmp( line
, "COMMENT", 7 ) == 0 )
1894 if ( p
->opts
->keep_comments
!= 0 && p
->font
!= 0 )
1905 error
= _bdf_add_comment( p
->font
, s
, linelen
);
1908 /* here font is not defined! */
1914 if ( !( p
->flags
& BDF_START_
) )
1918 if ( _bdf_strncmp( line
, "STARTFONT", 9 ) != 0 )
1920 /* we don't emit an error message since this code gets */
1921 /* explicitly caught one level higher */
1922 error
= FT_THROW( Missing_Startfont_Field
);
1926 p
->flags
= BDF_START_
;
1929 if ( FT_NEW( font
) )
1933 font
->memory
= p
->memory
;
1938 bdf_property_t
* prop
;
1941 error
= ft_hash_str_init( &(font
->proptbl
), memory
);
1944 for ( i
= 0, prop
= (bdf_property_t
*)_bdf_properties
;
1945 i
< _num_bdf_properties
; i
++, prop
++ )
1947 error
= ft_hash_str_insert( prop
->name
, i
,
1948 &(font
->proptbl
), memory
);
1954 if ( FT_ALLOC( p
->font
->internal
, sizeof ( FT_HashRec
) ) )
1956 error
= ft_hash_str_init( (FT_Hash
)p
->font
->internal
, memory
);
1959 p
->font
->spacing
= p
->opts
->font_spacing
;
1960 p
->font
->default_char
= -1;
1965 /* Check for the start of the properties. */
1966 if ( _bdf_strncmp( line
, "STARTPROPERTIES", 15 ) == 0 )
1968 if ( !( p
->flags
& BDF_FONT_BBX_
) )
1970 /* Missing the FONTBOUNDINGBOX field. */
1971 FT_ERROR(( "_bdf_parse_start: " ERRMSG1
, lineno
, "FONTBOUNDINGBOX" ));
1972 error
= FT_THROW( Missing_Fontboundingbox_Field
);
1976 error
= _bdf_list_split( &p
->list
, (char *)" +", line
, linelen
);
1979 /* at this point, `p->font' can't be NULL */
1980 p
->cnt
= p
->font
->props_size
= _bdf_atoul( p
->list
.field
[1] );
1982 if ( FT_NEW_ARRAY( p
->font
->props
, p
->cnt
) )
1984 p
->font
->props_size
= 0;
1988 p
->flags
|= BDF_PROPS_
;
1989 *next
= _bdf_parse_properties
;
1994 /* Check for the FONTBOUNDINGBOX field. */
1995 if ( _bdf_strncmp( line
, "FONTBOUNDINGBOX", 15 ) == 0 )
1997 if ( !( p
->flags
& BDF_SIZE_
) )
1999 /* Missing the SIZE field. */
2000 FT_ERROR(( "_bdf_parse_start: " ERRMSG1
, lineno
, "SIZE" ));
2001 error
= FT_THROW( Missing_Size_Field
);
2005 error
= _bdf_list_split( &p
->list
, (char *)" +", line
, linelen
);
2009 p
->font
->bbx
.width
= _bdf_atous( p
->list
.field
[1] );
2010 p
->font
->bbx
.height
= _bdf_atous( p
->list
.field
[2] );
2012 p
->font
->bbx
.x_offset
= _bdf_atos( p
->list
.field
[3] );
2013 p
->font
->bbx
.y_offset
= _bdf_atos( p
->list
.field
[4] );
2015 p
->font
->bbx
.ascent
= (short)( p
->font
->bbx
.height
+
2016 p
->font
->bbx
.y_offset
);
2018 p
->font
->bbx
.descent
= (short)( -p
->font
->bbx
.y_offset
);
2020 p
->flags
|= BDF_FONT_BBX_
;
2025 /* The next thing to check for is the FONT field. */
2026 if ( _bdf_strncmp( line
, "FONT", 4 ) == 0 )
2028 error
= _bdf_list_split( &p
->list
, (char *)" +", line
, linelen
);
2031 _bdf_list_shift( &p
->list
, 1 );
2033 s
= _bdf_list_join( &p
->list
, ' ', &slen
);
2037 FT_ERROR(( "_bdf_parse_start: " ERRMSG8
, lineno
, "FONT" ));
2038 error
= FT_THROW( Invalid_File_Format
);
2042 /* Allowing multiple `FONT' lines (which is invalid) doesn't hurt... */
2043 FT_FREE( p
->font
->name
);
2045 if ( FT_NEW_ARRAY( p
->font
->name
, slen
+ 1 ) )
2047 FT_MEM_COPY( p
->font
->name
, s
, slen
+ 1 );
2049 /* If the font name is an XLFD name, set the spacing to the one in */
2050 /* the font name. If there is no spacing fall back on the default. */
2051 error
= _bdf_set_default_spacing( p
->font
, p
->opts
, lineno
);
2055 p
->flags
|= BDF_FONT_NAME_
;
2060 /* Check for the SIZE field. */
2061 if ( _bdf_strncmp( line
, "SIZE", 4 ) == 0 )
2063 if ( !( p
->flags
& BDF_FONT_NAME_
) )
2065 /* Missing the FONT field. */
2066 FT_ERROR(( "_bdf_parse_start: " ERRMSG1
, lineno
, "FONT" ));
2067 error
= FT_THROW( Missing_Font_Field
);
2071 error
= _bdf_list_split( &p
->list
, (char *)" +", line
, linelen
);
2075 p
->font
->point_size
= _bdf_atoul( p
->list
.field
[1] );
2076 p
->font
->resolution_x
= _bdf_atoul( p
->list
.field
[2] );
2077 p
->font
->resolution_y
= _bdf_atoul( p
->list
.field
[3] );
2079 /* Check for the bits per pixel field. */
2080 if ( p
->list
.used
== 5 )
2085 bpp
= (unsigned short)_bdf_atos( p
->list
.field
[4] );
2087 /* Only values 1, 2, 4, 8 are allowed for greymap fonts. */
2097 if ( p
->font
->bpp
!= bpp
)
2098 FT_TRACE2(( "_bdf_parse_start: " ACMSG11
, p
->font
->bpp
));
2103 p
->flags
|= BDF_SIZE_
;
2108 /* Check for the CHARS field -- font properties are optional */
2109 if ( _bdf_strncmp( line
, "CHARS", 5 ) == 0 )
2114 if ( !( p
->flags
& BDF_FONT_BBX_
) )
2116 /* Missing the FONTBOUNDINGBOX field. */
2117 FT_ERROR(( "_bdf_parse_start: " ERRMSG1
, lineno
, "FONTBOUNDINGBOX" ));
2118 error
= FT_THROW( Missing_Fontboundingbox_Field
);
2122 /* Add the two standard X11 properties which are required */
2123 /* for compiling fonts. */
2124 p
->font
->font_ascent
= p
->font
->bbx
.ascent
;
2125 ft_sprintf( nbuf
, "%hd", p
->font
->bbx
.ascent
);
2126 error
= _bdf_add_property( p
->font
, (char *)"FONT_ASCENT",
2130 FT_TRACE2(( "_bdf_parse_properties: " ACMSG1
, p
->font
->bbx
.ascent
));
2132 p
->font
->font_descent
= p
->font
->bbx
.descent
;
2133 ft_sprintf( nbuf
, "%hd", p
->font
->bbx
.descent
);
2134 error
= _bdf_add_property( p
->font
, (char *)"FONT_DESCENT",
2138 FT_TRACE2(( "_bdf_parse_properties: " ACMSG2
, p
->font
->bbx
.descent
));
2140 p
->font
->modified
= 1;
2142 *next
= _bdf_parse_glyphs
;
2144 /* A special return value. */
2149 FT_ERROR(( "_bdf_parse_start: " ERRMSG9
, lineno
));
2150 error
= FT_THROW( Invalid_File_Format
);
2157 /*************************************************************************/
2161 /*************************************************************************/
2164 FT_LOCAL_DEF( FT_Error
)
2165 bdf_load_font( FT_Stream stream
,
2166 FT_Memory extmemory
,
2167 bdf_options_t
* opts
,
2170 unsigned long lineno
= 0; /* make compiler happy */
2171 _bdf_parse_t
*p
= NULL
;
2173 FT_Memory memory
= extmemory
; /* needed for FT_NEW */
2174 FT_Error error
= FT_Err_Ok
;
2181 p
->opts
= (bdf_options_t
*)( ( opts
!= 0 ) ? opts
: &_bdf_opts
);
2183 p
->size
= stream
->size
;
2184 p
->memory
= extmemory
; /* only during font creation */
2186 _bdf_list_init( &p
->list
, extmemory
);
2188 error
= _bdf_readstream( stream
, _bdf_parse_start
,
2189 (void *)p
, &lineno
);
2195 /* If the font is not proportional, set the font's monowidth */
2196 /* field to the width of the font bounding box. */
2198 if ( p
->font
->spacing
!= BDF_PROPORTIONAL
)
2199 p
->font
->monowidth
= p
->font
->bbx
.width
;
2201 /* If the number of glyphs loaded is not that of the original count, */
2202 /* indicate the difference. */
2203 if ( p
->cnt
!= p
->font
->glyphs_used
+ p
->font
->unencoded_used
)
2205 FT_TRACE2(( "bdf_load_font: " ACMSG15
, p
->cnt
,
2206 p
->font
->glyphs_used
+ p
->font
->unencoded_used
));
2207 p
->font
->modified
= 1;
2210 /* Once the font has been loaded, adjust the overall font metrics if */
2212 if ( p
->opts
->correct_metrics
!= 0 &&
2213 ( p
->font
->glyphs_used
> 0 || p
->font
->unencoded_used
> 0 ) )
2215 if ( p
->maxrb
- p
->minlb
!= p
->font
->bbx
.width
)
2217 FT_TRACE2(( "bdf_load_font: " ACMSG3
,
2218 p
->font
->bbx
.width
, p
->maxrb
- p
->minlb
));
2219 p
->font
->bbx
.width
= (unsigned short)( p
->maxrb
- p
->minlb
);
2220 p
->font
->modified
= 1;
2223 if ( p
->font
->bbx
.x_offset
!= p
->minlb
)
2225 FT_TRACE2(( "bdf_load_font: " ACMSG4
,
2226 p
->font
->bbx
.x_offset
, p
->minlb
));
2227 p
->font
->bbx
.x_offset
= p
->minlb
;
2228 p
->font
->modified
= 1;
2231 if ( p
->font
->bbx
.ascent
!= p
->maxas
)
2233 FT_TRACE2(( "bdf_load_font: " ACMSG5
,
2234 p
->font
->bbx
.ascent
, p
->maxas
));
2235 p
->font
->bbx
.ascent
= p
->maxas
;
2236 p
->font
->modified
= 1;
2239 if ( p
->font
->bbx
.descent
!= p
->maxds
)
2241 FT_TRACE2(( "bdf_load_font: " ACMSG6
,
2242 p
->font
->bbx
.descent
, p
->maxds
));
2243 p
->font
->bbx
.descent
= p
->maxds
;
2244 p
->font
->bbx
.y_offset
= (short)( -p
->maxds
);
2245 p
->font
->modified
= 1;
2248 if ( p
->maxas
+ p
->maxds
!= p
->font
->bbx
.height
)
2250 FT_TRACE2(( "bdf_load_font: " ACMSG7
,
2251 p
->font
->bbx
.height
, p
->maxas
+ p
->maxds
));
2252 p
->font
->bbx
.height
= (unsigned short)( p
->maxas
+ p
->maxds
);
2255 if ( p
->flags
& BDF_SWIDTH_ADJ_
)
2256 FT_TRACE2(( "bdf_load_font: " ACMSG8
));
2260 if ( p
->flags
& BDF_START_
)
2262 /* The ENDFONT field was never reached or did not exist. */
2263 if ( !( p
->flags
& BDF_GLYPHS_
) )
2265 /* Error happened while parsing header. */
2266 FT_ERROR(( "bdf_load_font: " ERRMSG2
, lineno
));
2267 error
= FT_THROW( Corrupted_Font_Header
);
2272 /* Error happened when parsing glyphs. */
2273 FT_ERROR(( "bdf_load_font: " ERRMSG3
, lineno
));
2274 error
= FT_THROW( Corrupted_Font_Glyphs
);
2281 /* Make sure the comments are NULL terminated if they exist. */
2282 memory
= p
->font
->memory
;
2284 if ( p
->font
->comments_len
> 0 )
2286 if ( FT_RENEW_ARRAY( p
->font
->comments
,
2287 p
->font
->comments_len
,
2288 p
->font
->comments_len
+ 1 ) )
2291 p
->font
->comments
[p
->font
->comments_len
] = 0;
2294 else if ( error
== FT_Err_Ok
)
2295 error
= FT_THROW( Invalid_File_Format
);
2302 _bdf_list_done( &p
->list
);
2306 FT_FREE( p
->glyph_name
);
2313 bdf_free_font( p
->font
);
2323 FT_LOCAL_DEF( void )
2324 bdf_free_font( bdf_font_t
* font
)
2326 bdf_property_t
* prop
;
2328 bdf_glyph_t
* glyphs
;
2335 memory
= font
->memory
;
2337 FT_FREE( font
->name
);
2339 /* Free up the internal hash table of property names. */
2340 if ( font
->internal
)
2342 ft_hash_str_free( (FT_Hash
)font
->internal
, memory
);
2343 FT_FREE( font
->internal
);
2346 /* Free up the comment info. */
2347 FT_FREE( font
->comments
);
2349 /* Free up the properties. */
2350 for ( i
= 0; i
< font
->props_size
; i
++ )
2352 if ( font
->props
[i
].format
== BDF_ATOM
)
2353 FT_FREE( font
->props
[i
].value
.atom
);
2356 FT_FREE( font
->props
);
2358 /* Free up the character info. */
2359 for ( i
= 0, glyphs
= font
->glyphs
;
2360 i
< font
->glyphs_used
; i
++, glyphs
++ )
2362 FT_FREE( glyphs
->name
);
2363 FT_FREE( glyphs
->bitmap
);
2366 for ( i
= 0, glyphs
= font
->unencoded
; i
< font
->unencoded_used
;
2369 FT_FREE( glyphs
->name
);
2370 FT_FREE( glyphs
->bitmap
);
2373 FT_FREE( font
->glyphs
);
2374 FT_FREE( font
->unencoded
);
2376 /* Free up the overflow storage if it was used. */
2377 for ( i
= 0, glyphs
= font
->overflow
.glyphs
;
2378 i
< font
->overflow
.glyphs_used
; i
++, glyphs
++ )
2380 FT_FREE( glyphs
->name
);
2381 FT_FREE( glyphs
->bitmap
);
2384 FT_FREE( font
->overflow
.glyphs
);
2387 ft_hash_str_free( &(font
->proptbl
), memory
);
2389 /* Free up the user defined properties. */
2390 for ( prop
= font
->user_props
, i
= 0;
2391 i
< font
->nuser_props
; i
++, prop
++ )
2393 FT_FREE( prop
->name
);
2394 if ( prop
->format
== BDF_ATOM
)
2395 FT_FREE( prop
->value
.atom
);
2398 FT_FREE( font
->user_props
);
2400 /* FREE( font ); */ /* XXX Fixme */
2404 FT_LOCAL_DEF( bdf_property_t
* )
2405 bdf_get_font_property( bdf_font_t
* font
,
2411 if ( font
== 0 || font
->props_size
== 0 || name
== 0 || *name
== 0 )
2414 propid
= ft_hash_str_lookup( name
, (FT_Hash
)font
->internal
);
2416 return propid
? ( font
->props
+ *propid
) : 0;