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
++ )
708 if ( v
< ( FT_ULONG_MAX
- 9 ) / 10 )
709 v
= v
* 10 + a2i
[(int)*s
];
721 /* Routine to convert a decimal ASCII string to a signed long integer. */
728 if ( s
== 0 || *s
== 0 )
731 /* Check for a minus sign. */
739 for ( v
= 0; sbitset( ddigits
, *s
); s
++ )
741 if ( v
< ( FT_LONG_MAX
- 9 ) / 10 )
742 v
= v
* 10 + a2i
[(int)*s
];
750 return ( !neg
) ? v
: -v
;
754 /* Routine to convert a decimal ASCII string to an unsigned short integer. */
755 static unsigned short
756 _bdf_atous( char* s
)
761 if ( s
== 0 || *s
== 0 )
764 for ( v
= 0; sbitset( ddigits
, *s
); s
++ )
766 if ( v
< ( FT_USHORT_MAX
- 9 ) / 10 )
767 v
= (unsigned short)( v
* 10 + a2i
[(int)*s
] );
779 /* Routine to convert a decimal ASCII string to a signed short integer. */
786 if ( s
== 0 || *s
== 0 )
789 /* Check for a minus. */
797 for ( v
= 0; sbitset( ddigits
, *s
); s
++ )
799 if ( v
< ( SHRT_MAX
- 9 ) / 10 )
800 v
= (short)( v
* 10 + a2i
[(int)*s
] );
808 return (short)( ( !neg
) ? v
: -v
);
812 /* Routine to compare two glyphs by encoding so they can be sorted. */
814 by_encoding( const void* a
,
817 bdf_glyph_t
*c1
, *c2
;
820 c1
= (bdf_glyph_t
*)a
;
821 c2
= (bdf_glyph_t
*)b
;
823 if ( c1
->encoding
< c2
->encoding
)
826 if ( c1
->encoding
> c2
->encoding
)
834 bdf_create_property( char* name
,
840 FT_Memory memory
= font
->memory
;
841 FT_Error error
= FT_Err_Ok
;
844 /* First check whether the property has */
845 /* already been added or not. If it has, then */
846 /* simply ignore it. */
847 if ( ft_hash_str_lookup( name
, &(font
->proptbl
) ) )
850 if ( FT_RENEW_ARRAY( font
->user_props
,
852 font
->nuser_props
+ 1 ) )
855 p
= font
->user_props
+ font
->nuser_props
;
858 n
= ft_strlen( name
) + 1;
859 if ( n
> FT_ULONG_MAX
)
860 return FT_THROW( Invalid_Argument
);
862 if ( FT_NEW_ARRAY( p
->name
, n
) )
865 FT_MEM_COPY( (char *)p
->name
, name
, n
);
870 n
= _num_bdf_properties
+ font
->nuser_props
;
872 error
= ft_hash_str_insert( p
->name
, n
, &(font
->proptbl
), memory
);
883 FT_LOCAL_DEF( bdf_property_t
* )
884 bdf_get_property( char* name
,
890 if ( name
== 0 || *name
== 0 )
893 if ( ( propid
= ft_hash_str_lookup( name
, &(font
->proptbl
) ) ) == NULL
)
896 if ( *propid
>= _num_bdf_properties
)
897 return font
->user_props
+ ( *propid
- _num_bdf_properties
);
899 return (bdf_property_t
*)_bdf_properties
+ *propid
;
903 /*************************************************************************/
905 /* BDF font file parsing flags and functions. */
907 /*************************************************************************/
912 #define BDF_START_ 0x0001U
913 #define BDF_FONT_NAME_ 0x0002U
914 #define BDF_SIZE_ 0x0004U
915 #define BDF_FONT_BBX_ 0x0008U
916 #define BDF_PROPS_ 0x0010U
917 #define BDF_GLYPHS_ 0x0020U
918 #define BDF_GLYPH_ 0x0040U
919 #define BDF_ENCODING_ 0x0080U
920 #define BDF_SWIDTH_ 0x0100U
921 #define BDF_DWIDTH_ 0x0200U
922 #define BDF_BBX_ 0x0400U
923 #define BDF_BITMAP_ 0x0800U
925 #define BDF_SWIDTH_ADJ_ 0x1000U
927 #define BDF_GLYPH_BITS_ ( BDF_GLYPH_ | \
934 #define BDF_GLYPH_WIDTH_CHECK_ 0x40000000UL
935 #define BDF_GLYPH_HEIGHT_CHECK_ 0x80000000UL
939 _bdf_add_comment( bdf_font_t
* font
,
944 FT_Memory memory
= font
->memory
;
945 FT_Error error
= FT_Err_Ok
;
948 if ( FT_RENEW_ARRAY( font
->comments
,
950 font
->comments_len
+ len
+ 1 ) )
953 cp
= font
->comments
+ font
->comments_len
;
955 FT_MEM_COPY( cp
, comment
, len
);
958 font
->comments_len
+= len
+ 1;
965 /* Set the spacing from the font name if it exists, or set it to the */
966 /* default specified in the options. */
968 _bdf_set_default_spacing( bdf_font_t
* font
,
970 unsigned long lineno
)
976 FT_Error error
= FT_Err_Ok
;
978 FT_UNUSED( lineno
); /* only used in debug mode */
981 if ( font
== 0 || font
->name
== 0 || font
->name
[0] == 0 )
983 error
= FT_THROW( Invalid_Argument
);
987 memory
= font
->memory
;
989 _bdf_list_init( &list
, memory
);
991 font
->spacing
= opts
->font_spacing
;
993 len
= ft_strlen( font
->name
) + 1;
994 /* Limit ourselves to 256 characters in the font name. */
997 FT_ERROR(( "_bdf_set_default_spacing: " ERRMSG7
, lineno
));
998 error
= FT_THROW( Invalid_Argument
);
1002 FT_MEM_COPY( name
, font
->name
, len
);
1004 error
= _bdf_list_split( &list
, (char *)"-", name
, (unsigned long)len
);
1008 if ( list
.used
== 15 )
1010 switch ( list
.field
[11][0] )
1014 font
->spacing
= BDF_CHARCELL
;
1018 font
->spacing
= BDF_MONOWIDTH
;
1022 font
->spacing
= BDF_PROPORTIONAL
;
1028 _bdf_list_done( &list
);
1035 /* Determine whether the property is an atom or not. If it is, then */
1036 /* clean it up so the double quotes are removed if they exist. */
1038 _bdf_is_atom( char* line
,
1039 unsigned long linelen
,
1049 *name
= sp
= ep
= line
;
1051 while ( *ep
&& *ep
!= ' ' && *ep
!= '\t' )
1061 p
= bdf_get_property( sp
, font
);
1063 /* Restore the character that was saved before any return can happen. */
1067 /* If the property exists and is not an atom, just return here. */
1068 if ( p
&& p
->format
!= BDF_ATOM
)
1071 /* The property is an atom. Trim all leading and trailing whitespace */
1072 /* and double quotes for the atom value. */
1074 ep
= line
+ linelen
;
1076 /* Trim the leading whitespace if it exists. */
1080 ( *sp
== ' ' || *sp
== '\t' ) )
1083 /* Trim the leading double quote if it exists. */
1088 /* Trim the trailing whitespace if it exists. */
1090 ( *( ep
- 1 ) == ' ' || *( ep
- 1 ) == '\t' ) )
1093 /* Trim the trailing double quote if it exists. */
1094 if ( ep
> sp
&& *( ep
- 1 ) == '"' )
1102 _bdf_add_property( bdf_font_t
* font
,
1105 unsigned long lineno
)
1108 bdf_property_t
*prop
, *fp
;
1109 FT_Memory memory
= font
->memory
;
1110 FT_Error error
= FT_Err_Ok
;
1112 FT_UNUSED( lineno
); /* only used in debug mode */
1115 /* First, check whether the property already exists in the font. */
1116 if ( ( propid
= ft_hash_str_lookup( name
,
1117 (FT_Hash
)font
->internal
) ) != NULL
)
1119 /* The property already exists in the font, so simply replace */
1120 /* the value of the property with the current value. */
1121 fp
= font
->props
+ *propid
;
1123 switch ( fp
->format
)
1126 /* Delete the current atom if it exists. */
1127 FT_FREE( fp
->value
.atom
);
1129 if ( value
&& value
[0] != 0 )
1131 if ( FT_STRDUP( fp
->value
.atom
, value
) )
1137 fp
->value
.l
= _bdf_atol( value
);
1141 fp
->value
.ul
= _bdf_atoul( value
);
1151 /* See whether this property type exists yet or not. */
1152 /* If not, create it. */
1153 propid
= ft_hash_str_lookup( name
, &(font
->proptbl
) );
1156 error
= bdf_create_property( name
, BDF_ATOM
, font
);
1159 propid
= ft_hash_str_lookup( name
, &(font
->proptbl
) );
1162 /* Allocate another property if this is overflowing. */
1163 if ( font
->props_used
== font
->props_size
)
1165 if ( font
->props_size
== 0 )
1167 if ( FT_NEW_ARRAY( font
->props
, 1 ) )
1172 if ( FT_RENEW_ARRAY( font
->props
,
1174 font
->props_size
+ 1 ) )
1178 fp
= font
->props
+ font
->props_size
;
1183 if ( *propid
>= _num_bdf_properties
)
1184 prop
= font
->user_props
+ ( *propid
- _num_bdf_properties
);
1186 prop
= (bdf_property_t
*)_bdf_properties
+ *propid
;
1188 fp
= font
->props
+ font
->props_used
;
1190 fp
->name
= prop
->name
;
1191 fp
->format
= prop
->format
;
1192 fp
->builtin
= prop
->builtin
;
1194 switch ( prop
->format
)
1198 if ( value
!= 0 && value
[0] )
1200 if ( FT_STRDUP( fp
->value
.atom
, value
) )
1206 fp
->value
.l
= _bdf_atol( value
);
1210 fp
->value
.ul
= _bdf_atoul( value
);
1214 /* If the property happens to be a comment, then it doesn't need */
1215 /* to be added to the internal hash table. */
1216 if ( _bdf_strncmp( name
, "COMMENT", 7 ) != 0 )
1218 /* Add the property to the font property table. */
1219 error
= ft_hash_str_insert( fp
->name
,
1221 (FT_Hash
)font
->internal
,
1229 /* Some special cases need to be handled here. The DEFAULT_CHAR */
1230 /* property needs to be located if it exists in the property list, the */
1231 /* FONT_ASCENT and FONT_DESCENT need to be assigned if they are */
1232 /* present, and the SPACING property should override the default */
1234 if ( _bdf_strncmp( name
, "DEFAULT_CHAR", 12 ) == 0 )
1235 font
->default_char
= fp
->value
.l
;
1236 else if ( _bdf_strncmp( name
, "FONT_ASCENT", 11 ) == 0 )
1237 font
->font_ascent
= fp
->value
.l
;
1238 else if ( _bdf_strncmp( name
, "FONT_DESCENT", 12 ) == 0 )
1239 font
->font_descent
= fp
->value
.l
;
1240 else if ( _bdf_strncmp( name
, "SPACING", 7 ) == 0 )
1242 if ( !fp
->value
.atom
)
1244 FT_ERROR(( "_bdf_add_property: " ERRMSG8
, lineno
, "SPACING" ));
1245 error
= FT_THROW( Invalid_File_Format
);
1249 if ( fp
->value
.atom
[0] == 'p' || fp
->value
.atom
[0] == 'P' )
1250 font
->spacing
= BDF_PROPORTIONAL
;
1251 else if ( fp
->value
.atom
[0] == 'm' || fp
->value
.atom
[0] == 'M' )
1252 font
->spacing
= BDF_MONOWIDTH
;
1253 else if ( fp
->value
.atom
[0] == 'c' || fp
->value
.atom
[0] == 'C' )
1254 font
->spacing
= BDF_CHARCELL
;
1262 static const unsigned char nibble_mask
[8] =
1264 0xFF, 0x80, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC, 0xFE
1268 /* Actually parse the glyph info and bitmaps. */
1270 _bdf_parse_glyphs( char* line
,
1271 unsigned long linelen
,
1272 unsigned long lineno
,
1279 unsigned long i
, slen
, nibbles
;
1286 FT_Error error
= FT_Err_Ok
;
1288 FT_UNUSED( call_data
);
1289 FT_UNUSED( lineno
); /* only used in debug mode */
1292 p
= (_bdf_parse_t
*)client_data
;
1295 memory
= font
->memory
;
1297 /* Check for a comment. */
1298 if ( _bdf_strncmp( line
, "COMMENT", 7 ) == 0 )
1308 error
= _bdf_add_comment( p
->font
, s
, linelen
);
1312 /* The very first thing expected is the number of glyphs. */
1313 if ( !( p
->flags
& BDF_GLYPHS_
) )
1315 if ( _bdf_strncmp( line
, "CHARS", 5 ) != 0 )
1317 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1
, lineno
, "CHARS" ));
1318 error
= FT_THROW( Missing_Chars_Field
);
1322 error
= _bdf_list_split( &p
->list
, (char *)" +", line
, linelen
);
1325 p
->cnt
= font
->glyphs_size
= _bdf_atoul( p
->list
.field
[1] );
1327 /* We need at least 20 bytes per glyph. */
1328 if ( p
->cnt
> p
->size
/ 20 )
1330 p
->cnt
= font
->glyphs_size
= p
->size
/ 20;
1331 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG17
, p
->cnt
));
1334 /* Make sure the number of glyphs is non-zero. */
1336 font
->glyphs_size
= 64;
1338 /* Limit ourselves to 1,114,112 glyphs in the font (this is the */
1339 /* number of code points available in Unicode). */
1340 if ( p
->cnt
>= 0x110000UL
)
1342 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG5
, lineno
, "CHARS" ));
1343 error
= FT_THROW( Invalid_Argument
);
1347 if ( FT_NEW_ARRAY( font
->glyphs
, font
->glyphs_size
) )
1350 p
->flags
|= BDF_GLYPHS_
;
1355 /* Check for the ENDFONT field. */
1356 if ( _bdf_strncmp( line
, "ENDFONT", 7 ) == 0 )
1358 if ( p
->flags
& BDF_GLYPH_BITS_
)
1360 /* Missing ENDCHAR field. */
1361 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1
, lineno
, "ENDCHAR" ));
1362 error
= FT_THROW( Corrupted_Font_Glyphs
);
1366 /* Sort the glyphs by encoding. */
1367 ft_qsort( (char *)font
->glyphs
,
1369 sizeof ( bdf_glyph_t
),
1372 p
->flags
&= ~BDF_START_
;
1377 /* Check for the ENDCHAR field. */
1378 if ( _bdf_strncmp( line
, "ENDCHAR", 7 ) == 0 )
1381 p
->flags
&= ~BDF_GLYPH_BITS_
;
1386 /* Check whether a glyph is being scanned but should be */
1387 /* ignored because it is an unencoded glyph. */
1388 if ( ( p
->flags
& BDF_GLYPH_
) &&
1389 p
->glyph_enc
== -1 &&
1390 p
->opts
->keep_unencoded
== 0 )
1393 /* Check for the STARTCHAR field. */
1394 if ( _bdf_strncmp( line
, "STARTCHAR", 9 ) == 0 )
1396 if ( p
->flags
& BDF_GLYPH_BITS_
)
1398 /* Missing ENDCHAR field. */
1399 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1
, lineno
, "ENDCHAR" ));
1400 error
= FT_THROW( Missing_Startchar_Field
);
1404 /* Set the character name in the parse info first until the */
1405 /* encoding can be checked for an unencoded character. */
1406 FT_FREE( p
->glyph_name
);
1408 error
= _bdf_list_split( &p
->list
, (char *)" +", line
, linelen
);
1412 _bdf_list_shift( &p
->list
, 1 );
1414 s
= _bdf_list_join( &p
->list
, ' ', &slen
);
1418 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG8
, lineno
, "STARTCHAR" ));
1419 error
= FT_THROW( Invalid_File_Format
);
1423 if ( FT_NEW_ARRAY( p
->glyph_name
, slen
+ 1 ) )
1426 FT_MEM_COPY( p
->glyph_name
, s
, slen
+ 1 );
1428 p
->flags
|= BDF_GLYPH_
;
1430 FT_TRACE4(( DBGMSG1
, lineno
, s
));
1435 /* Check for the ENCODING field. */
1436 if ( _bdf_strncmp( line
, "ENCODING", 8 ) == 0 )
1438 if ( !( p
->flags
& BDF_GLYPH_
) )
1440 /* Missing STARTCHAR field. */
1441 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1
, lineno
, "STARTCHAR" ));
1442 error
= FT_THROW( Missing_Startchar_Field
);
1446 error
= _bdf_list_split( &p
->list
, (char *)" +", line
, linelen
);
1450 p
->glyph_enc
= _bdf_atol( p
->list
.field
[1] );
1452 /* Normalize negative encoding values. The specification only */
1453 /* allows -1, but we can be more generous here. */
1454 if ( p
->glyph_enc
< -1 )
1457 /* Check for alternative encoding format. */
1458 if ( p
->glyph_enc
== -1 && p
->list
.used
> 2 )
1459 p
->glyph_enc
= _bdf_atol( p
->list
.field
[2] );
1461 if ( p
->glyph_enc
< -1 )
1464 FT_TRACE4(( DBGMSG2
, p
->glyph_enc
));
1466 /* Check that the encoding is in the Unicode range because */
1467 /* otherwise p->have (a bitmap with static size) overflows. */
1468 if ( p
->glyph_enc
> 0 &&
1469 (size_t)p
->glyph_enc
>= sizeof ( p
->have
) /
1470 sizeof ( unsigned long ) * 32 )
1472 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG5
, lineno
, "ENCODING" ));
1473 error
= FT_THROW( Invalid_File_Format
);
1477 /* Check whether this encoding has already been encountered. */
1478 /* If it has then change it to unencoded so it gets added if */
1480 if ( p
->glyph_enc
>= 0 )
1482 if ( _bdf_glyph_modified( p
->have
, p
->glyph_enc
) )
1484 /* Emit a message saying a glyph has been moved to the */
1485 /* unencoded area. */
1486 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG12
,
1487 p
->glyph_enc
, p
->glyph_name
));
1492 _bdf_set_glyph_modified( p
->have
, p
->glyph_enc
);
1495 if ( p
->glyph_enc
>= 0 )
1497 /* Make sure there are enough glyphs allocated in case the */
1498 /* number of characters happen to be wrong. */
1499 if ( font
->glyphs_used
== font
->glyphs_size
)
1501 if ( FT_RENEW_ARRAY( font
->glyphs
,
1503 font
->glyphs_size
+ 64 ) )
1506 font
->glyphs_size
+= 64;
1509 glyph
= font
->glyphs
+ font
->glyphs_used
++;
1510 glyph
->name
= p
->glyph_name
;
1511 glyph
->encoding
= p
->glyph_enc
;
1513 /* Reset the initial glyph info. */
1514 p
->glyph_name
= NULL
;
1518 /* Unencoded glyph. Check whether it should */
1519 /* be added or not. */
1520 if ( p
->opts
->keep_unencoded
!= 0 )
1522 /* Allocate the next unencoded glyph. */
1523 if ( font
->unencoded_used
== font
->unencoded_size
)
1525 if ( FT_RENEW_ARRAY( font
->unencoded
,
1526 font
->unencoded_size
,
1527 font
->unencoded_size
+ 4 ) )
1530 font
->unencoded_size
+= 4;
1533 glyph
= font
->unencoded
+ font
->unencoded_used
;
1534 glyph
->name
= p
->glyph_name
;
1535 glyph
->encoding
= (long)font
->unencoded_used
++;
1537 /* Reset the initial glyph info. */
1538 p
->glyph_name
= NULL
;
1542 /* Free up the glyph name if the unencoded shouldn't be */
1544 FT_FREE( p
->glyph_name
);
1547 p
->glyph_name
= NULL
;
1550 /* Clear the flags that might be added when width and height are */
1551 /* checked for consistency. */
1552 p
->flags
&= ~( BDF_GLYPH_WIDTH_CHECK_
| BDF_GLYPH_HEIGHT_CHECK_
);
1554 p
->flags
|= BDF_ENCODING_
;
1559 /* Point at the glyph being constructed. */
1560 if ( p
->glyph_enc
== -1 )
1561 glyph
= font
->unencoded
+ ( font
->unencoded_used
- 1 );
1563 glyph
= font
->glyphs
+ ( font
->glyphs_used
- 1 );
1565 /* Check whether a bitmap is being constructed. */
1566 if ( p
->flags
& BDF_BITMAP_
)
1568 /* If there are more rows than are specified in the glyph metrics, */
1569 /* ignore the remaining lines. */
1570 if ( p
->row
>= (unsigned long)glyph
->bbx
.height
)
1572 if ( !( p
->flags
& BDF_GLYPH_HEIGHT_CHECK_
) )
1574 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG13
, glyph
->encoding
));
1575 p
->flags
|= BDF_GLYPH_HEIGHT_CHECK_
;
1582 /* Only collect the number of nibbles indicated by the glyph */
1583 /* metrics. If there are more columns, they are simply ignored. */
1584 nibbles
= glyph
->bpr
<< 1;
1585 bp
= glyph
->bitmap
+ p
->row
* glyph
->bpr
;
1587 for ( i
= 0; i
< nibbles
; i
++ )
1590 if ( !sbitset( hdigits
, c
) )
1592 *bp
= (FT_Byte
)( ( *bp
<< 4 ) + a2i
[c
] );
1593 if ( i
+ 1 < nibbles
&& ( i
& 1 ) )
1597 /* If any line has not enough columns, */
1598 /* indicate they have been padded with zero bits. */
1600 !( p
->flags
& BDF_GLYPH_WIDTH_CHECK_
) )
1602 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG16
, glyph
->encoding
));
1603 p
->flags
|= BDF_GLYPH_WIDTH_CHECK_
;
1607 /* Remove possible garbage at the right. */
1608 mask_index
= ( glyph
->bbx
.width
* p
->font
->bpp
) & 7;
1609 if ( glyph
->bbx
.width
)
1610 *bp
&= nibble_mask
[mask_index
];
1612 /* If any line has extra columns, indicate they have been removed. */
1613 if ( i
== nibbles
&&
1614 sbitset( hdigits
, line
[nibbles
] ) &&
1615 !( p
->flags
& BDF_GLYPH_WIDTH_CHECK_
) )
1617 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG14
, glyph
->encoding
));
1618 p
->flags
|= BDF_GLYPH_WIDTH_CHECK_
;
1626 /* Expect the SWIDTH (scalable width) field next. */
1627 if ( _bdf_strncmp( line
, "SWIDTH", 6 ) == 0 )
1629 if ( !( p
->flags
& BDF_ENCODING_
) )
1630 goto Missing_Encoding
;
1632 error
= _bdf_list_split( &p
->list
, (char *)" +", line
, linelen
);
1636 glyph
->swidth
= (unsigned short)_bdf_atoul( p
->list
.field
[1] );
1637 p
->flags
|= BDF_SWIDTH_
;
1642 /* Expect the DWIDTH (scalable width) field next. */
1643 if ( _bdf_strncmp( line
, "DWIDTH", 6 ) == 0 )
1645 if ( !( p
->flags
& BDF_ENCODING_
) )
1646 goto Missing_Encoding
;
1648 error
= _bdf_list_split( &p
->list
, (char *)" +", line
, linelen
);
1652 glyph
->dwidth
= (unsigned short)_bdf_atoul( p
->list
.field
[1] );
1654 if ( !( p
->flags
& BDF_SWIDTH_
) )
1656 /* Missing SWIDTH field. Emit an auto correction message and set */
1657 /* the scalable width from the device width. */
1658 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG9
, lineno
));
1660 glyph
->swidth
= (unsigned short)FT_MulDiv(
1661 glyph
->dwidth
, 72000L,
1662 (FT_Long
)( font
->point_size
*
1663 font
->resolution_x
) );
1666 p
->flags
|= BDF_DWIDTH_
;
1670 /* Expect the BBX field next. */
1671 if ( _bdf_strncmp( line
, "BBX", 3 ) == 0 )
1673 if ( !( p
->flags
& BDF_ENCODING_
) )
1674 goto Missing_Encoding
;
1676 error
= _bdf_list_split( &p
->list
, (char *)" +", line
, linelen
);
1680 glyph
->bbx
.width
= _bdf_atous( p
->list
.field
[1] );
1681 glyph
->bbx
.height
= _bdf_atous( p
->list
.field
[2] );
1682 glyph
->bbx
.x_offset
= _bdf_atos( p
->list
.field
[3] );
1683 glyph
->bbx
.y_offset
= _bdf_atos( p
->list
.field
[4] );
1685 /* Generate the ascent and descent of the character. */
1686 glyph
->bbx
.ascent
= (short)( glyph
->bbx
.height
+ glyph
->bbx
.y_offset
);
1687 glyph
->bbx
.descent
= (short)( -glyph
->bbx
.y_offset
);
1689 /* Determine the overall font bounding box as the characters are */
1690 /* loaded so corrections can be done later if indicated. */
1691 p
->maxas
= (short)FT_MAX( glyph
->bbx
.ascent
, p
->maxas
);
1692 p
->maxds
= (short)FT_MAX( glyph
->bbx
.descent
, p
->maxds
);
1694 p
->rbearing
= (short)( glyph
->bbx
.width
+ glyph
->bbx
.x_offset
);
1696 p
->maxrb
= (short)FT_MAX( p
->rbearing
, p
->maxrb
);
1697 p
->minlb
= (short)FT_MIN( glyph
->bbx
.x_offset
, p
->minlb
);
1698 p
->maxlb
= (short)FT_MAX( glyph
->bbx
.x_offset
, p
->maxlb
);
1700 if ( !( p
->flags
& BDF_DWIDTH_
) )
1702 /* Missing DWIDTH field. Emit an auto correction message and set */
1703 /* the device width to the glyph width. */
1704 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG10
, lineno
));
1705 glyph
->dwidth
= glyph
->bbx
.width
;
1708 /* If the BDF_CORRECT_METRICS flag is set, then adjust the SWIDTH */
1709 /* value if necessary. */
1710 if ( p
->opts
->correct_metrics
!= 0 )
1712 /* Determine the point size of the glyph. */
1713 unsigned short sw
= (unsigned short)FT_MulDiv(
1714 glyph
->dwidth
, 72000L,
1715 (FT_Long
)( font
->point_size
*
1716 font
->resolution_x
) );
1719 if ( sw
!= glyph
->swidth
)
1723 if ( p
->glyph_enc
== -1 )
1724 _bdf_set_glyph_modified( font
->umod
,
1725 font
->unencoded_used
- 1 );
1727 _bdf_set_glyph_modified( font
->nmod
, glyph
->encoding
);
1729 p
->flags
|= BDF_SWIDTH_ADJ_
;
1734 p
->flags
|= BDF_BBX_
;
1738 /* And finally, gather up the bitmap. */
1739 if ( _bdf_strncmp( line
, "BITMAP", 6 ) == 0 )
1741 unsigned long bitmap_size
;
1744 if ( !( p
->flags
& BDF_BBX_
) )
1746 /* Missing BBX field. */
1747 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1
, lineno
, "BBX" ));
1748 error
= FT_THROW( Missing_Bbx_Field
);
1752 /* Allocate enough space for the bitmap. */
1753 glyph
->bpr
= ( glyph
->bbx
.width
* p
->font
->bpp
+ 7 ) >> 3;
1755 bitmap_size
= glyph
->bpr
* glyph
->bbx
.height
;
1756 if ( glyph
->bpr
> 0xFFFFU
|| bitmap_size
> 0xFFFFU
)
1758 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG4
, lineno
));
1759 error
= FT_THROW( Bbx_Too_Big
);
1763 glyph
->bytes
= (unsigned short)bitmap_size
;
1765 if ( FT_NEW_ARRAY( glyph
->bitmap
, glyph
->bytes
) )
1769 p
->flags
|= BDF_BITMAP_
;
1774 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG9
, lineno
));
1775 error
= FT_THROW( Invalid_File_Format
);
1779 /* Missing ENCODING field. */
1780 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1
, lineno
, "ENCODING" ));
1781 error
= FT_THROW( Missing_Encoding_Field
);
1784 if ( error
&& ( p
->flags
& BDF_GLYPH_
) )
1785 FT_FREE( p
->glyph_name
);
1791 /* Load the font properties. */
1793 _bdf_parse_properties( char* line
,
1794 unsigned long linelen
,
1795 unsigned long lineno
,
1800 _bdf_line_func_t
* next
;
1805 FT_Error error
= FT_Err_Ok
;
1807 FT_UNUSED( lineno
);
1810 next
= (_bdf_line_func_t
*)call_data
;
1811 p
= (_bdf_parse_t
*) client_data
;
1813 /* Check for the end of the properties. */
1814 if ( _bdf_strncmp( line
, "ENDPROPERTIES", 13 ) == 0 )
1816 /* If the FONT_ASCENT or FONT_DESCENT properties have not been */
1817 /* encountered yet, then make sure they are added as properties and */
1818 /* make sure they are set from the font bounding box info. */
1820 /* This is *always* done regardless of the options, because X11 */
1821 /* requires these two fields to compile fonts. */
1822 if ( bdf_get_font_property( p
->font
, "FONT_ASCENT" ) == 0 )
1824 p
->font
->font_ascent
= p
->font
->bbx
.ascent
;
1825 ft_sprintf( nbuf
, "%hd", p
->font
->bbx
.ascent
);
1826 error
= _bdf_add_property( p
->font
, (char *)"FONT_ASCENT",
1831 FT_TRACE2(( "_bdf_parse_properties: " ACMSG1
, p
->font
->bbx
.ascent
));
1832 p
->font
->modified
= 1;
1835 if ( bdf_get_font_property( p
->font
, "FONT_DESCENT" ) == 0 )
1837 p
->font
->font_descent
= p
->font
->bbx
.descent
;
1838 ft_sprintf( nbuf
, "%hd", p
->font
->bbx
.descent
);
1839 error
= _bdf_add_property( p
->font
, (char *)"FONT_DESCENT",
1844 FT_TRACE2(( "_bdf_parse_properties: " ACMSG2
, p
->font
->bbx
.descent
));
1845 p
->font
->modified
= 1;
1848 p
->flags
&= ~BDF_PROPS_
;
1849 *next
= _bdf_parse_glyphs
;
1854 /* Ignore the _XFREE86_GLYPH_RANGES properties. */
1855 if ( _bdf_strncmp( line
, "_XFREE86_GLYPH_RANGES", 21 ) == 0 )
1858 /* Handle COMMENT fields and properties in a special way to preserve */
1860 if ( _bdf_strncmp( line
, "COMMENT", 7 ) == 0 )
1862 name
= value
= line
;
1866 error
= _bdf_add_property( p
->font
, name
, value
, lineno
);
1870 else if ( _bdf_is_atom( line
, linelen
, &name
, &value
, p
->font
) )
1872 error
= _bdf_add_property( p
->font
, name
, value
, lineno
);
1878 error
= _bdf_list_split( &p
->list
, (char *)" +", line
, linelen
);
1881 name
= p
->list
.field
[0];
1883 _bdf_list_shift( &p
->list
, 1 );
1884 value
= _bdf_list_join( &p
->list
, ' ', &vlen
);
1886 error
= _bdf_add_property( p
->font
, name
, value
, lineno
);
1896 /* Load the font header. */
1898 _bdf_parse_start( char* line
,
1899 unsigned long linelen
,
1900 unsigned long lineno
,
1905 _bdf_line_func_t
* next
;
1910 FT_Memory memory
= NULL
;
1911 FT_Error error
= FT_Err_Ok
;
1913 FT_UNUSED( lineno
); /* only used in debug mode */
1916 next
= (_bdf_line_func_t
*)call_data
;
1917 p
= (_bdf_parse_t
*) client_data
;
1920 memory
= p
->font
->memory
;
1922 /* Check for a comment. This is done to handle those fonts that have */
1923 /* comments before the STARTFONT line for some reason. */
1924 if ( _bdf_strncmp( line
, "COMMENT", 7 ) == 0 )
1926 if ( p
->opts
->keep_comments
!= 0 && p
->font
!= 0 )
1937 error
= _bdf_add_comment( p
->font
, s
, linelen
);
1940 /* here font is not defined! */
1946 if ( !( p
->flags
& BDF_START_
) )
1950 if ( _bdf_strncmp( line
, "STARTFONT", 9 ) != 0 )
1952 /* we don't emit an error message since this code gets */
1953 /* explicitly caught one level higher */
1954 error
= FT_THROW( Missing_Startfont_Field
);
1958 p
->flags
= BDF_START_
;
1961 if ( FT_NEW( font
) )
1965 font
->memory
= p
->memory
;
1970 bdf_property_t
* prop
;
1973 error
= ft_hash_str_init( &(font
->proptbl
), memory
);
1976 for ( i
= 0, prop
= (bdf_property_t
*)_bdf_properties
;
1977 i
< _num_bdf_properties
; i
++, prop
++ )
1979 error
= ft_hash_str_insert( prop
->name
, i
,
1980 &(font
->proptbl
), memory
);
1986 if ( FT_ALLOC( p
->font
->internal
, sizeof ( FT_HashRec
) ) )
1988 error
= ft_hash_str_init( (FT_Hash
)p
->font
->internal
, memory
);
1991 p
->font
->spacing
= p
->opts
->font_spacing
;
1992 p
->font
->default_char
= -1;
1997 /* Check for the start of the properties. */
1998 if ( _bdf_strncmp( line
, "STARTPROPERTIES", 15 ) == 0 )
2000 if ( !( p
->flags
& BDF_FONT_BBX_
) )
2002 /* Missing the FONTBOUNDINGBOX field. */
2003 FT_ERROR(( "_bdf_parse_start: " ERRMSG1
, lineno
, "FONTBOUNDINGBOX" ));
2004 error
= FT_THROW( Missing_Fontboundingbox_Field
);
2008 error
= _bdf_list_split( &p
->list
, (char *)" +", line
, linelen
);
2012 /* at this point, `p->font' can't be NULL */
2013 p
->cnt
= p
->font
->props_size
= _bdf_atoul( p
->list
.field
[1] );
2014 /* We need at least 4 bytes per property. */
2015 if ( p
->cnt
> p
->size
/ 4 )
2017 p
->font
->props_size
= 0;
2019 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG5
, lineno
, "STARTPROPERTIES" ));
2020 error
= FT_THROW( Invalid_Argument
);
2024 if ( FT_NEW_ARRAY( p
->font
->props
, p
->cnt
) )
2026 p
->font
->props_size
= 0;
2030 p
->flags
|= BDF_PROPS_
;
2031 *next
= _bdf_parse_properties
;
2036 /* Check for the FONTBOUNDINGBOX field. */
2037 if ( _bdf_strncmp( line
, "FONTBOUNDINGBOX", 15 ) == 0 )
2039 if ( !( p
->flags
& BDF_SIZE_
) )
2041 /* Missing the SIZE field. */
2042 FT_ERROR(( "_bdf_parse_start: " ERRMSG1
, lineno
, "SIZE" ));
2043 error
= FT_THROW( Missing_Size_Field
);
2047 error
= _bdf_list_split( &p
->list
, (char *)" +", line
, linelen
);
2051 p
->font
->bbx
.width
= _bdf_atous( p
->list
.field
[1] );
2052 p
->font
->bbx
.height
= _bdf_atous( p
->list
.field
[2] );
2054 p
->font
->bbx
.x_offset
= _bdf_atos( p
->list
.field
[3] );
2055 p
->font
->bbx
.y_offset
= _bdf_atos( p
->list
.field
[4] );
2057 p
->font
->bbx
.ascent
= (short)( p
->font
->bbx
.height
+
2058 p
->font
->bbx
.y_offset
);
2060 p
->font
->bbx
.descent
= (short)( -p
->font
->bbx
.y_offset
);
2062 p
->flags
|= BDF_FONT_BBX_
;
2067 /* The next thing to check for is the FONT field. */
2068 if ( _bdf_strncmp( line
, "FONT", 4 ) == 0 )
2070 error
= _bdf_list_split( &p
->list
, (char *)" +", line
, linelen
);
2073 _bdf_list_shift( &p
->list
, 1 );
2075 s
= _bdf_list_join( &p
->list
, ' ', &slen
);
2079 FT_ERROR(( "_bdf_parse_start: " ERRMSG8
, lineno
, "FONT" ));
2080 error
= FT_THROW( Invalid_File_Format
);
2084 /* Allowing multiple `FONT' lines (which is invalid) doesn't hurt... */
2085 FT_FREE( p
->font
->name
);
2087 if ( FT_NEW_ARRAY( p
->font
->name
, slen
+ 1 ) )
2089 FT_MEM_COPY( p
->font
->name
, s
, slen
+ 1 );
2091 /* If the font name is an XLFD name, set the spacing to the one in */
2092 /* the font name. If there is no spacing fall back on the default. */
2093 error
= _bdf_set_default_spacing( p
->font
, p
->opts
, lineno
);
2097 p
->flags
|= BDF_FONT_NAME_
;
2102 /* Check for the SIZE field. */
2103 if ( _bdf_strncmp( line
, "SIZE", 4 ) == 0 )
2105 if ( !( p
->flags
& BDF_FONT_NAME_
) )
2107 /* Missing the FONT field. */
2108 FT_ERROR(( "_bdf_parse_start: " ERRMSG1
, lineno
, "FONT" ));
2109 error
= FT_THROW( Missing_Font_Field
);
2113 error
= _bdf_list_split( &p
->list
, (char *)" +", line
, linelen
);
2117 p
->font
->point_size
= _bdf_atoul( p
->list
.field
[1] );
2118 p
->font
->resolution_x
= _bdf_atoul( p
->list
.field
[2] );
2119 p
->font
->resolution_y
= _bdf_atoul( p
->list
.field
[3] );
2121 /* Check for the bits per pixel field. */
2122 if ( p
->list
.used
== 5 )
2127 bpp
= (unsigned short)_bdf_atos( p
->list
.field
[4] );
2129 /* Only values 1, 2, 4, 8 are allowed for greymap fonts. */
2139 if ( p
->font
->bpp
!= bpp
)
2140 FT_TRACE2(( "_bdf_parse_start: " ACMSG11
, p
->font
->bpp
));
2145 p
->flags
|= BDF_SIZE_
;
2150 /* Check for the CHARS field -- font properties are optional */
2151 if ( _bdf_strncmp( line
, "CHARS", 5 ) == 0 )
2156 if ( !( p
->flags
& BDF_FONT_BBX_
) )
2158 /* Missing the FONTBOUNDINGBOX field. */
2159 FT_ERROR(( "_bdf_parse_start: " ERRMSG1
, lineno
, "FONTBOUNDINGBOX" ));
2160 error
= FT_THROW( Missing_Fontboundingbox_Field
);
2164 /* Add the two standard X11 properties which are required */
2165 /* for compiling fonts. */
2166 p
->font
->font_ascent
= p
->font
->bbx
.ascent
;
2167 ft_sprintf( nbuf
, "%hd", p
->font
->bbx
.ascent
);
2168 error
= _bdf_add_property( p
->font
, (char *)"FONT_ASCENT",
2172 FT_TRACE2(( "_bdf_parse_properties: " ACMSG1
, p
->font
->bbx
.ascent
));
2174 p
->font
->font_descent
= p
->font
->bbx
.descent
;
2175 ft_sprintf( nbuf
, "%hd", p
->font
->bbx
.descent
);
2176 error
= _bdf_add_property( p
->font
, (char *)"FONT_DESCENT",
2180 FT_TRACE2(( "_bdf_parse_properties: " ACMSG2
, p
->font
->bbx
.descent
));
2182 p
->font
->modified
= 1;
2184 *next
= _bdf_parse_glyphs
;
2186 /* A special return value. */
2191 FT_ERROR(( "_bdf_parse_start: " ERRMSG9
, lineno
));
2192 error
= FT_THROW( Invalid_File_Format
);
2199 /*************************************************************************/
2203 /*************************************************************************/
2206 FT_LOCAL_DEF( FT_Error
)
2207 bdf_load_font( FT_Stream stream
,
2208 FT_Memory extmemory
,
2209 bdf_options_t
* opts
,
2212 unsigned long lineno
= 0; /* make compiler happy */
2213 _bdf_parse_t
*p
= NULL
;
2215 FT_Memory memory
= extmemory
; /* needed for FT_NEW */
2216 FT_Error error
= FT_Err_Ok
;
2223 p
->opts
= (bdf_options_t
*)( ( opts
!= 0 ) ? opts
: &_bdf_opts
);
2225 p
->size
= stream
->size
;
2226 p
->memory
= extmemory
; /* only during font creation */
2228 _bdf_list_init( &p
->list
, extmemory
);
2230 error
= _bdf_readstream( stream
, _bdf_parse_start
,
2231 (void *)p
, &lineno
);
2237 /* If the font is not proportional, set the font's monowidth */
2238 /* field to the width of the font bounding box. */
2240 if ( p
->font
->spacing
!= BDF_PROPORTIONAL
)
2241 p
->font
->monowidth
= p
->font
->bbx
.width
;
2243 /* If the number of glyphs loaded is not that of the original count, */
2244 /* indicate the difference. */
2245 if ( p
->cnt
!= p
->font
->glyphs_used
+ p
->font
->unencoded_used
)
2247 FT_TRACE2(( "bdf_load_font: " ACMSG15
, p
->cnt
,
2248 p
->font
->glyphs_used
+ p
->font
->unencoded_used
));
2249 p
->font
->modified
= 1;
2252 /* Once the font has been loaded, adjust the overall font metrics if */
2254 if ( p
->opts
->correct_metrics
!= 0 &&
2255 ( p
->font
->glyphs_used
> 0 || p
->font
->unencoded_used
> 0 ) )
2257 if ( p
->maxrb
- p
->minlb
!= p
->font
->bbx
.width
)
2259 FT_TRACE2(( "bdf_load_font: " ACMSG3
,
2260 p
->font
->bbx
.width
, p
->maxrb
- p
->minlb
));
2261 p
->font
->bbx
.width
= (unsigned short)( p
->maxrb
- p
->minlb
);
2262 p
->font
->modified
= 1;
2265 if ( p
->font
->bbx
.x_offset
!= p
->minlb
)
2267 FT_TRACE2(( "bdf_load_font: " ACMSG4
,
2268 p
->font
->bbx
.x_offset
, p
->minlb
));
2269 p
->font
->bbx
.x_offset
= p
->minlb
;
2270 p
->font
->modified
= 1;
2273 if ( p
->font
->bbx
.ascent
!= p
->maxas
)
2275 FT_TRACE2(( "bdf_load_font: " ACMSG5
,
2276 p
->font
->bbx
.ascent
, p
->maxas
));
2277 p
->font
->bbx
.ascent
= p
->maxas
;
2278 p
->font
->modified
= 1;
2281 if ( p
->font
->bbx
.descent
!= p
->maxds
)
2283 FT_TRACE2(( "bdf_load_font: " ACMSG6
,
2284 p
->font
->bbx
.descent
, p
->maxds
));
2285 p
->font
->bbx
.descent
= p
->maxds
;
2286 p
->font
->bbx
.y_offset
= (short)( -p
->maxds
);
2287 p
->font
->modified
= 1;
2290 if ( p
->maxas
+ p
->maxds
!= p
->font
->bbx
.height
)
2292 FT_TRACE2(( "bdf_load_font: " ACMSG7
,
2293 p
->font
->bbx
.height
, p
->maxas
+ p
->maxds
));
2294 p
->font
->bbx
.height
= (unsigned short)( p
->maxas
+ p
->maxds
);
2297 if ( p
->flags
& BDF_SWIDTH_ADJ_
)
2298 FT_TRACE2(( "bdf_load_font: " ACMSG8
));
2302 if ( p
->flags
& BDF_START_
)
2304 /* The ENDFONT field was never reached or did not exist. */
2305 if ( !( p
->flags
& BDF_GLYPHS_
) )
2307 /* Error happened while parsing header. */
2308 FT_ERROR(( "bdf_load_font: " ERRMSG2
, lineno
));
2309 error
= FT_THROW( Corrupted_Font_Header
);
2314 /* Error happened when parsing glyphs. */
2315 FT_ERROR(( "bdf_load_font: " ERRMSG3
, lineno
));
2316 error
= FT_THROW( Corrupted_Font_Glyphs
);
2323 /* Make sure the comments are NULL terminated if they exist. */
2324 memory
= p
->font
->memory
;
2326 if ( p
->font
->comments_len
> 0 )
2328 if ( FT_RENEW_ARRAY( p
->font
->comments
,
2329 p
->font
->comments_len
,
2330 p
->font
->comments_len
+ 1 ) )
2333 p
->font
->comments
[p
->font
->comments_len
] = 0;
2337 error
= FT_THROW( Invalid_File_Format
);
2344 _bdf_list_done( &p
->list
);
2348 FT_FREE( p
->glyph_name
);
2355 bdf_free_font( p
->font
);
2365 FT_LOCAL_DEF( void )
2366 bdf_free_font( bdf_font_t
* font
)
2368 bdf_property_t
* prop
;
2370 bdf_glyph_t
* glyphs
;
2377 memory
= font
->memory
;
2379 FT_FREE( font
->name
);
2381 /* Free up the internal hash table of property names. */
2382 if ( font
->internal
)
2384 ft_hash_str_free( (FT_Hash
)font
->internal
, memory
);
2385 FT_FREE( font
->internal
);
2388 /* Free up the comment info. */
2389 FT_FREE( font
->comments
);
2391 /* Free up the properties. */
2392 for ( i
= 0; i
< font
->props_size
; i
++ )
2394 if ( font
->props
[i
].format
== BDF_ATOM
)
2395 FT_FREE( font
->props
[i
].value
.atom
);
2398 FT_FREE( font
->props
);
2400 /* Free up the character info. */
2401 for ( i
= 0, glyphs
= font
->glyphs
;
2402 i
< font
->glyphs_used
; i
++, glyphs
++ )
2404 FT_FREE( glyphs
->name
);
2405 FT_FREE( glyphs
->bitmap
);
2408 for ( i
= 0, glyphs
= font
->unencoded
; i
< font
->unencoded_used
;
2411 FT_FREE( glyphs
->name
);
2412 FT_FREE( glyphs
->bitmap
);
2415 FT_FREE( font
->glyphs
);
2416 FT_FREE( font
->unencoded
);
2418 /* Free up the overflow storage if it was used. */
2419 for ( i
= 0, glyphs
= font
->overflow
.glyphs
;
2420 i
< font
->overflow
.glyphs_used
; i
++, glyphs
++ )
2422 FT_FREE( glyphs
->name
);
2423 FT_FREE( glyphs
->bitmap
);
2426 FT_FREE( font
->overflow
.glyphs
);
2429 ft_hash_str_free( &(font
->proptbl
), memory
);
2431 /* Free up the user defined properties. */
2432 for ( prop
= font
->user_props
, i
= 0;
2433 i
< font
->nuser_props
; i
++, prop
++ )
2435 FT_FREE( prop
->name
);
2436 if ( prop
->format
== BDF_ATOM
)
2437 FT_FREE( prop
->value
.atom
);
2440 FT_FREE( font
->user_props
);
2442 /* FREE( font ); */ /* XXX Fixme */
2446 FT_LOCAL_DEF( bdf_property_t
* )
2447 bdf_get_font_property( bdf_font_t
* font
,
2453 if ( font
== 0 || font
->props_size
== 0 || name
== 0 || *name
== 0 )
2456 propid
= ft_hash_str_lookup( name
, (FT_Hash
)font
->internal
);
2458 return propid
? ( font
->props
+ *propid
) : 0;