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 /* Auto correction messages. */
173 #define ACMSG1 "FONT_ASCENT property missing. " \
174 "Added `FONT_ASCENT %hd'.\n"
175 #define ACMSG2 "FONT_DESCENT property missing. " \
176 "Added `FONT_DESCENT %hd'.\n"
177 #define ACMSG3 "Font width != actual width. Old: %hd New: %hd.\n"
178 #define ACMSG4 "Font left bearing != actual left bearing. " \
179 "Old: %hd New: %hd.\n"
180 #define ACMSG5 "Font ascent != actual ascent. Old: %hd New: %hd.\n"
181 #define ACMSG6 "Font descent != actual descent. Old: %hd New: %hd.\n"
182 #define ACMSG7 "Font height != actual height. Old: %hd New: %hd.\n"
183 #define ACMSG8 "Glyph scalable width (SWIDTH) adjustments made.\n"
184 #define ACMSG9 "SWIDTH field missing at line %ld. Set automatically.\n"
185 #define ACMSG10 "DWIDTH field missing at line %ld. Set to glyph width.\n"
186 #define ACMSG11 "SIZE bits per pixel field adjusted to %hd.\n"
187 #define ACMSG12 "Duplicate encoding %ld (%s) changed to unencoded.\n"
188 #define ACMSG13 "Glyph %ld extra rows removed.\n"
189 #define ACMSG14 "Glyph %ld extra columns removed.\n"
190 #define ACMSG15 "Incorrect glyph count: %ld indicated but %ld found.\n"
191 #define ACMSG16 "Glyph %ld missing columns padded with zero bits.\n"
193 /* Error messages. */
194 #define ERRMSG1 "[line %ld] Missing `%s' line.\n"
195 #define ERRMSG2 "[line %ld] Font header corrupted or missing fields.\n"
196 #define ERRMSG3 "[line %ld] Font glyphs corrupted or missing fields.\n"
197 #define ERRMSG4 "[line %ld] BBX too big.\n"
198 #define ERRMSG5 "[line %ld] `%s' value too big.\n"
199 #define ERRMSG6 "[line %ld] Input line too long.\n"
200 #define ERRMSG7 "[line %ld] Font name too long.\n"
201 #define ERRMSG8 "[line %ld] Invalid `%s' value.\n"
202 #define ERRMSG9 "[line %ld] Invalid keyword.\n"
204 /* Debug messages. */
205 #define DBGMSG1 " [%6ld] %s" /* no \n */
206 #define DBGMSG2 " (0x%lX)\n"
209 /*************************************************************************/
211 /* Hash table utilities for the properties. */
213 /*************************************************************************/
215 /* XXX: Replace this with FreeType's hash functions */
218 #define INITIAL_HT_SIZE 241
221 (*hash_free_func)( hashnode node );
224 hash_bucket( const char* key,
227 const char* kp = key;
228 unsigned long res = 0;
229 hashnode* bp = ht->table, *ndp;
232 /* Mocklisp hash function. */
234 res = ( res << 5 ) - res + *kp++;
236 ndp = bp + ( res % ht->size );
240 if ( kp[0] == key[0] && ft_strcmp( kp, key ) == 0 )
244 ndp = bp + ( ht->size - 1 );
252 hash_rehash( hashtable* ht,
255 hashnode* obp = ht->table, *bp, *nbp;
256 int i, sz = ht->size;
257 FT_Error error = BDF_Err_Ok;
261 ht->limit = ht->size / 3;
263 if ( FT_NEW_ARRAY( ht->table, ht->size ) )
266 for ( i = 0, bp = obp; i < sz; i++, bp++ )
270 nbp = hash_bucket( (*bp)->key, ht );
282 hash_init( hashtable* ht,
285 int sz = INITIAL_HT_SIZE;
286 FT_Error error = BDF_Err_Ok;
293 if ( FT_NEW_ARRAY( ht->table, sz ) )
302 hash_free( hashtable* ht,
307 int i, sz = ht->size;
308 hashnode* bp = ht->table;
311 for ( i = 0; i < sz; i++, bp++ )
314 FT_FREE( ht->table );
320 hash_insert( char* key,
325 hashnode nn, *bp = hash_bucket( key, ht );
326 FT_Error error = BDF_Err_Ok;
339 if ( ht->used >= ht->limit )
341 error = hash_rehash( ht, memory );
356 hash_lookup( const char* key,
359 hashnode *np = hash_bucket( key, ht );
366 /*************************************************************************/
368 /* Utility types and functions. */
370 /*************************************************************************/
373 /* Function type for parsing lines of a BDF font. */
376 (*_bdf_line_func_t)( char* line,
377 unsigned long linelen,
378 unsigned long lineno,
383 /* List structure for splitting lines into fields. */
385 typedef struct _bdf_list_t_
395 /* Structure used while loading BDF fonts. */
397 typedef struct _bdf_parse_t_
417 unsigned long have[34816]; /* must be in sync with `nmod' and `umod' */
418 /* arrays from `bdf_font_t' structure */
426 #define setsbit( m, cc ) \
427 ( m[(FT_Byte)(cc) >> 3] |= (FT_Byte)( 1 << ( (cc) & 7 ) ) )
428 #define sbitset( m, cc ) \
429 ( m[(FT_Byte)(cc) >> 3] & ( 1 << ( (cc) & 7 ) ) )
433 _bdf_list_init( _bdf_list_t* list,
437 list->memory = memory;
442 _bdf_list_done( _bdf_list_t* list )
444 FT_Memory memory = list->memory;
449 FT_FREE( list->field );
456 _bdf_list_ensure( _bdf_list_t* list,
457 unsigned long num_items ) /* same as _bdf_list_t.used */
459 FT_Error error = BDF_Err_Ok;
462 if ( num_items > list->size )
464 unsigned long oldsize = list->size; /* same as _bdf_list_t.size */
465 unsigned long newsize = oldsize + ( oldsize >> 1 ) + 5;
466 unsigned long bigsize = (unsigned long)( FT_INT_MAX / sizeof ( char* ) );
467 FT_Memory memory = list->memory;
470 if ( oldsize == bigsize )
472 error = BDF_Err_Out_Of_Memory;
475 else if ( newsize < oldsize || newsize > bigsize )
478 if ( FT_RENEW_ARRAY( list->field, oldsize, newsize ) )
481 list->size = newsize;
490 _bdf_list_shift( _bdf_list_t* list,
496 if ( list == 0 || list->used == 0 || n == 0 )
499 if ( n >= list->used )
505 for ( u = n, i = 0; u < list->used; i++, u++ )
506 list->field[i] = list->field[u];
511 /* An empty string for empty fields. */
513 static const char empty[1] = { 0 }; /* XXX eliminate this */
517 _bdf_list_join( _bdf_list_t* list,
519 unsigned long *alen )
527 if ( list == 0 || list->used == 0 )
531 for ( i = j = 0; i < list->used; i++ )
537 if ( i + 1 < list->used )
548 /* The code below ensures that we have at least 4 + 1 `field' */
549 /* elements in `list' (which are possibly NULL) so that we */
550 /* don't have to check the number of fields in most cases. */
553 _bdf_list_split( _bdf_list_t* list,
556 unsigned long linelen )
558 int mult, final_empty;
561 FT_Error error = BDF_Err_Ok;
564 /* Initialize the list. */
568 list->field[0] = (char*)empty;
569 list->field[1] = (char*)empty;
570 list->field[2] = (char*)empty;
571 list->field[3] = (char*)empty;
574 /* If the line is empty, then simply return. */
575 if ( linelen == 0 || line[0] == 0 )
578 /* In the original code, if the `separators' parameter is NULL or */
579 /* empty, the list is split into individual bytes. We don't need */
580 /* this, so an error is signaled. */
581 if ( separators == 0 || *separators == 0 )
583 error = BDF_Err_Invalid_Argument;
587 /* Prepare the separator bitmap. */
588 FT_MEM_ZERO( seps, 32 );
590 /* If the very last character of the separator string is a plus, then */
591 /* set the `mult' flag to indicate that multiple separators should be */
592 /* collapsed into one. */
593 for ( mult = 0, sp = separators; sp && *sp; sp++ )
595 if ( *sp == '+' && *( sp + 1 ) == 0 )
598 setsbit( seps, *sp );
601 /* Break the line up into fields. */
602 for ( final_empty = 0, sp = ep = line, end = sp + linelen;
605 /* Collect everything that is not a separator. */
606 for ( ; *ep && !sbitset( seps, *ep ); ep++ )
609 /* Resize the list if necessary. */
610 if ( list->used == list->size )
612 error = _bdf_list_ensure( list, list->used + 1 );
617 /* Assign the field appropriately. */
618 list->field[list->used++] = ( ep > sp ) ? sp : (char*)empty;
624 /* If multiple separators should be collapsed, do it now by */
625 /* setting all the separator characters to 0. */
626 for ( ; *ep && sbitset( seps, *ep ); ep++ )
630 /* Don't collapse multiple separators by making them 0, so just */
631 /* make the one encountered 0. */
634 final_empty = ( ep > sp && *ep == 0 );
638 /* Finally, NULL-terminate the list. */
639 if ( list->used + final_empty >= list->size )
641 error = _bdf_list_ensure( list, list->used + final_empty + 1 );
647 list->field[list->used++] = (char*)empty;
649 list->field[list->used] = 0;
656 #define NO_SKIP 256 /* this value cannot be stored in a 'char' */
660 _bdf_readstream( FT_Stream stream,
661 _bdf_line_func_t callback,
666 unsigned long lineno, buf_size;
667 int refill, hold, to_skip;
668 ptrdiff_t bytes, start, end, cursor, avail;
670 FT_Memory memory = stream->memory;
671 FT_Error error = BDF_Err_Ok;
676 error = BDF_Err_Invalid_Argument;
680 /* initial size and allocation of the input buffer */
683 if ( FT_NEW_ARRAY( buf, buf_size ) )
695 bytes = 0; /* make compiler happy */
701 bytes = (ptrdiff_t)FT_Stream_TryRead(
702 stream, (FT_Byte*)buf + cursor,
703 (FT_ULong)( buf_size - cursor ) );
704 avail = cursor + bytes;
711 /* should we skip an optional character like \n or \r? */
712 if ( start < avail && buf[start] == to_skip )
719 /* try to find the end of the line */
720 while ( end < avail && buf[end] != '\n' && buf[end] != '\r' )
723 /* if we hit the end of the buffer, try shifting its content */
724 /* or even resizing it */
727 if ( bytes == 0 ) /* last line in file doesn't end in \r or \n */
728 break; /* ignore it then exit */
732 /* this line is definitely too long; try resizing the input */
733 /* buffer a bit to handle it. */
737 if ( buf_size >= 65536UL ) /* limit ourselves to 64KByte */
739 FT_ERROR(( "_bdf_readstream: " ERRMSG6, lineno ));
740 error = BDF_Err_Invalid_Argument;
744 new_size = buf_size * 2;
745 if ( FT_RENEW_ARRAY( buf, buf_size, new_size ) )
753 bytes = avail - start;
755 FT_MEM_COPY( buf, buf + start, bytes );
765 /* Temporarily NUL-terminate the line. */
769 /* XXX: Use encoding independent value for 0x1a */
770 if ( buf[start] != '#' && buf[start] != 0x1a && end > start )
772 error = (*cb)( buf + start, end - start, lineno,
773 (void*)&cb, client_data );
774 /* Redo if we have encountered CHARS without properties. */
776 error = (*cb)( buf + start, end - start, lineno,
777 (void*)&cb, client_data );
783 buf[end] = (char)hold;
788 else if ( hold == '\r' )
802 /* XXX: make this work with EBCDIC also */
804 static const unsigned char a2i[128] =
806 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
807 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
808 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
809 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
810 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x00, 0x00,
811 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00,
812 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
813 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
814 0x00, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00,
815 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
816 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
819 static const unsigned char odigits[32] =
821 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00,
822 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
823 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
824 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
827 static const unsigned char ddigits[32] =
829 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x03,
830 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
831 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
832 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
835 static const unsigned char hdigits[32] =
837 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x03,
838 0x7e, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00,
839 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
840 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
844 #define isdigok( m, d ) (m[(d) >> 3] & ( 1 << ( (d) & 7 ) ) )
847 /* Routine to convert an ASCII string into an unsigned long integer. */
854 const unsigned char* dmap;
857 if ( s == 0 || *s == 0 )
860 /* Make sure the radix is something recognizable. Default to 10. */
875 /* Check for the special hex prefix. */
877 ( *( s + 1 ) == 'x' || *( s + 1 ) == 'X' ) )
884 for ( v = 0; isdigok( dmap, *s ); s++ )
885 v = v * base + a2i[(int)*s];
894 /* Routine to convert an ASCII string into an signed long integer. */
901 const unsigned char* dmap;
904 if ( s == 0 || *s == 0 )
907 /* Make sure the radix is something recognizable. Default to 10. */
922 /* Check for a minus sign. */
930 /* Check for the special hex prefix. */
932 ( *( s + 1 ) == 'x' || *( s + 1 ) == 'X' ) )
939 for ( v = 0; isdigok( dmap, *s ); s++ )
940 v = v * base + a2i[(int)*s];
945 return ( !neg ) ? v : -v;
949 /* Routine to convert an ASCII string into an signed short integer. */
956 const unsigned char* dmap;
959 if ( s == 0 || *s == 0 )
962 /* Make sure the radix is something recognizable. Default to 10. */
977 /* Check for a minus. */
985 /* Check for the special hex prefix. */
987 ( *( s + 1 ) == 'x' || *( s + 1 ) == 'X' ) )
994 for ( v = 0; isdigok( dmap, *s ); s++ )
995 v = (short)( v * base + a2i[(int)*s] );
1000 return (short)( ( !neg ) ? v : -v );
1004 /* Routine to compare two glyphs by encoding so they can be sorted. */
1006 by_encoding( const void* a,
1009 bdf_glyph_t *c1, *c2;
1012 c1 = (bdf_glyph_t *)a;
1013 c2 = (bdf_glyph_t *)b;
1015 if ( c1->encoding < c2->encoding )
1018 if ( c1->encoding > c2->encoding )
1026 bdf_create_property( char* name,
1032 FT_Memory memory = font->memory;
1033 FT_Error error = BDF_Err_Ok;
1036 /* First check whether the property has */
1037 /* already been added or not. If it has, then */
1038 /* simply ignore it. */
1039 if ( hash_lookup( name, &(font->proptbl) ) )
1042 if ( FT_RENEW_ARRAY( font->user_props,
1044 font->nuser_props + 1 ) )
1047 p = font->user_props + font->nuser_props;
1050 n = ft_strlen( name ) + 1;
1051 if ( n > FT_ULONG_MAX )
1052 return BDF_Err_Invalid_Argument;
1054 if ( FT_NEW_ARRAY( p->name, n ) )
1057 FT_MEM_COPY( (char *)p->name, name, n );
1062 n = _num_bdf_properties + font->nuser_props;
1064 error = hash_insert( p->name, n, &(font->proptbl), memory );
1068 font->nuser_props++;
1075 FT_LOCAL_DEF( bdf_property_t * )
1076 bdf_get_property( char* name,
1083 if ( name == 0 || *name == 0 )
1086 if ( ( hn = hash_lookup( name, &(font->proptbl) ) ) == 0 )
1090 if ( propid >= _num_bdf_properties )
1091 return font->user_props + ( propid - _num_bdf_properties );
1093 return (bdf_property_t*)_bdf_properties + propid;
1097 /*************************************************************************/
1099 /* BDF font file parsing flags and functions. */
1101 /*************************************************************************/
1106 #define _BDF_START 0x0001
1107 #define _BDF_FONT_NAME 0x0002
1108 #define _BDF_SIZE 0x0004
1109 #define _BDF_FONT_BBX 0x0008
1110 #define _BDF_PROPS 0x0010
1111 #define _BDF_GLYPHS 0x0020
1112 #define _BDF_GLYPH 0x0040
1113 #define _BDF_ENCODING 0x0080
1114 #define _BDF_SWIDTH 0x0100
1115 #define _BDF_DWIDTH 0x0200
1116 #define _BDF_BBX 0x0400
1117 #define _BDF_BITMAP 0x0800
1119 #define _BDF_SWIDTH_ADJ 0x1000
1121 #define _BDF_GLYPH_BITS ( _BDF_GLYPH | \
1128 #define _BDF_GLYPH_WIDTH_CHECK 0x40000000UL
1129 #define _BDF_GLYPH_HEIGHT_CHECK 0x80000000UL
1133 _bdf_add_comment( bdf_font_t* font,
1138 FT_Memory memory = font->memory;
1139 FT_Error error = BDF_Err_Ok;
1142 if ( FT_RENEW_ARRAY( font->comments,
1144 font->comments_len + len + 1 ) )
1147 cp = font->comments + font->comments_len;
1149 FT_MEM_COPY( cp, comment, len );
1152 font->comments_len += len + 1;
1159 /* Set the spacing from the font name if it exists, or set it to the */
1160 /* default specified in the options. */
1162 _bdf_set_default_spacing( bdf_font_t* font,
1163 bdf_options_t* opts,
1164 unsigned long lineno )
1170 FT_Error error = BDF_Err_Ok;
1173 if ( font == 0 || font->name == 0 || font->name[0] == 0 )
1175 error = BDF_Err_Invalid_Argument;
1179 memory = font->memory;
1181 _bdf_list_init( &list, memory );
1183 font->spacing = opts->font_spacing;
1185 len = ft_strlen( font->name ) + 1;
1186 /* Limit ourselves to 256 characters in the font name. */
1189 FT_ERROR(( "_bdf_set_default_spacing: " ERRMSG7, lineno ));
1190 error = BDF_Err_Invalid_Argument;
1194 FT_MEM_COPY( name, font->name, len );
1196 error = _bdf_list_split( &list, (char *)"-", name, len );
1200 if ( list.used == 15 )
1202 switch ( list.field[11][0] )
1206 font->spacing = BDF_CHARCELL;
1210 font->spacing = BDF_MONOWIDTH;
1214 font->spacing = BDF_PROPORTIONAL;
1220 _bdf_list_done( &list );
1227 /* Determine whether the property is an atom or not. If it is, then */
1228 /* clean it up so the double quotes are removed if they exist. */
1230 _bdf_is_atom( char* line,
1231 unsigned long linelen,
1241 *name = sp = ep = line;
1243 while ( *ep && *ep != ' ' && *ep != '\t' )
1253 p = bdf_get_property( sp, font );
1255 /* Restore the character that was saved before any return can happen. */
1259 /* If the property exists and is not an atom, just return here. */
1260 if ( p && p->format != BDF_ATOM )
1263 /* The property is an atom. Trim all leading and trailing whitespace */
1264 /* and double quotes for the atom value. */
1266 ep = line + linelen;
1268 /* Trim the leading whitespace if it exists. */
1272 ( *sp == ' ' || *sp == '\t' ) )
1275 /* Trim the leading double quote if it exists. */
1280 /* Trim the trailing whitespace if it exists. */
1282 ( *( ep - 1 ) == ' ' || *( ep - 1 ) == '\t' ) )
1285 /* Trim the trailing double quote if it exists. */
1286 if ( ep > sp && *( ep - 1 ) == '"' )
1294 _bdf_add_property( bdf_font_t* font,
1297 unsigned long lineno )
1301 bdf_property_t *prop, *fp;
1302 FT_Memory memory = font->memory;
1303 FT_Error error = BDF_Err_Ok;
1306 /* First, check whether the property already exists in the font. */
1307 if ( ( hn = hash_lookup( name, (hashtable *)font->internal ) ) != 0 )
1309 /* The property already exists in the font, so simply replace */
1310 /* the value of the property with the current value. */
1311 fp = font->props + hn->data;
1313 switch ( fp->format )
1316 /* Delete the current atom if it exists. */
1317 FT_FREE( fp->value.atom );
1319 if ( value && value[0] != 0 )
1321 if ( FT_STRDUP( fp->value.atom, value ) )
1327 fp->value.l = _bdf_atol( value, 0, 10 );
1331 fp->value.ul = _bdf_atoul( value, 0, 10 );
1341 /* See whether this property type exists yet or not. */
1342 /* If not, create it. */
1343 hn = hash_lookup( name, &(font->proptbl) );
1346 error = bdf_create_property( name, BDF_ATOM, font );
1349 hn = hash_lookup( name, &(font->proptbl) );
1352 /* Allocate another property if this is overflow. */
1353 if ( font->props_used == font->props_size )
1355 if ( font->props_size == 0 )
1357 if ( FT_NEW_ARRAY( font->props, 1 ) )
1362 if ( FT_RENEW_ARRAY( font->props,
1364 font->props_size + 1 ) )
1368 fp = font->props + font->props_size;
1369 FT_MEM_ZERO( fp, sizeof ( bdf_property_t ) );
1374 if ( propid >= _num_bdf_properties )
1375 prop = font->user_props + ( propid - _num_bdf_properties );
1377 prop = (bdf_property_t*)_bdf_properties + propid;
1379 fp = font->props + font->props_used;
1381 fp->name = prop->name;
1382 fp->format = prop->format;
1383 fp->builtin = prop->builtin;
1385 switch ( prop->format )
1389 if ( value != 0 && value[0] )
1391 if ( FT_STRDUP( fp->value.atom, value ) )
1397 fp->value.l = _bdf_atol( value, 0, 10 );
1401 fp->value.ul = _bdf_atoul( value, 0, 10 );
1405 /* If the property happens to be a comment, then it doesn't need */
1406 /* to be added to the internal hash table. */
1407 if ( ft_memcmp( name, "COMMENT", 7 ) != 0 )
1409 /* Add the property to the font property table. */
1410 error = hash_insert( fp->name,
1412 (hashtable *)font->internal,
1420 /* Some special cases need to be handled here. The DEFAULT_CHAR */
1421 /* property needs to be located if it exists in the property list, the */
1422 /* FONT_ASCENT and FONT_DESCENT need to be assigned if they are */
1423 /* present, and the SPACING property should override the default */
1425 if ( ft_memcmp( name, "DEFAULT_CHAR", 12 ) == 0 )
1426 font->default_char = fp->value.l;
1427 else if ( ft_memcmp( name, "FONT_ASCENT", 11 ) == 0 )
1428 font->font_ascent = fp->value.l;
1429 else if ( ft_memcmp( name, "FONT_DESCENT", 12 ) == 0 )
1430 font->font_descent = fp->value.l;
1431 else if ( ft_memcmp( name, "SPACING", 7 ) == 0 )
1433 if ( !fp->value.atom )
1435 FT_ERROR(( "_bdf_add_property: " ERRMSG8, lineno, "SPACING" ));
1436 error = BDF_Err_Invalid_File_Format;
1440 if ( fp->value.atom[0] == 'p' || fp->value.atom[0] == 'P' )
1441 font->spacing = BDF_PROPORTIONAL;
1442 else if ( fp->value.atom[0] == 'm' || fp->value.atom[0] == 'M' )
1443 font->spacing = BDF_MONOWIDTH;
1444 else if ( fp->value.atom[0] == 'c' || fp->value.atom[0] == 'C' )
1445 font->spacing = BDF_CHARCELL;
1453 static const unsigned char nibble_mask[8] =
1455 0xFF, 0x80, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC, 0xFE
1459 /* Actually parse the glyph info and bitmaps. */
1461 _bdf_parse_glyphs( char* line,
1462 unsigned long linelen,
1463 unsigned long lineno,
1470 unsigned long i, slen, nibbles;
1477 FT_Error error = BDF_Err_Ok;
1479 FT_UNUSED( call_data );
1480 FT_UNUSED( lineno ); /* only used in debug mode */
1483 p = (_bdf_parse_t *)client_data;
1486 memory = font->memory;
1488 /* Check for a comment. */
1489 if ( ft_memcmp( line, "COMMENT", 7 ) == 0 )
1499 error = _bdf_add_comment( p->font, s, linelen );
1503 /* The very first thing expected is the number of glyphs. */
1504 if ( !( p->flags & _BDF_GLYPHS ) )
1506 if ( ft_memcmp( line, "CHARS", 5 ) != 0 )
1508 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "CHARS" ));
1509 error = BDF_Err_Missing_Chars_Field;
1513 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
1516 p->cnt = font->glyphs_size = _bdf_atoul( p->list.field[1], 0, 10 );
1518 /* Make sure the number of glyphs is non-zero. */
1520 font->glyphs_size = 64;
1522 /* Limit ourselves to 1,114,112 glyphs in the font (this is the */
1523 /* number of code points available in Unicode). */
1524 if ( p->cnt >= 0x110000UL )
1526 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG5, lineno, "CHARS" ));
1527 error = BDF_Err_Invalid_Argument;
1531 if ( FT_NEW_ARRAY( font->glyphs, font->glyphs_size ) )
1534 p->flags |= _BDF_GLYPHS;
1539 /* Check for the ENDFONT field. */
1540 if ( ft_memcmp( line, "ENDFONT", 7 ) == 0 )
1542 /* Sort the glyphs by encoding. */
1543 ft_qsort( (char *)font->glyphs,
1545 sizeof ( bdf_glyph_t ),
1548 p->flags &= ~_BDF_START;
1553 /* Check for the ENDCHAR field. */
1554 if ( ft_memcmp( line, "ENDCHAR", 7 ) == 0 )
1557 p->flags &= ~_BDF_GLYPH_BITS;
1562 /* Check whether a glyph is being scanned but should be */
1563 /* ignored because it is an unencoded glyph. */
1564 if ( ( p->flags & _BDF_GLYPH ) &&
1565 p->glyph_enc == -1 &&
1566 p->opts->keep_unencoded == 0 )
1569 /* Check for the STARTCHAR field. */
1570 if ( ft_memcmp( line, "STARTCHAR", 9 ) == 0 )
1572 /* Set the character name in the parse info first until the */
1573 /* encoding can be checked for an unencoded character. */
1574 FT_FREE( p->glyph_name );
1576 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
1580 _bdf_list_shift( &p->list, 1 );
1582 s = _bdf_list_join( &p->list, ' ', &slen );
1586 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG8, lineno, "STARTCHAR" ));
1587 error = BDF_Err_Invalid_File_Format;
1591 if ( FT_NEW_ARRAY( p->glyph_name, slen + 1 ) )
1594 FT_MEM_COPY( p->glyph_name, s, slen + 1 );
1596 p->flags |= _BDF_GLYPH;
1598 FT_TRACE4(( DBGMSG1, lineno, s ));
1603 /* Check for the ENCODING field. */
1604 if ( ft_memcmp( line, "ENCODING", 8 ) == 0 )
1606 if ( !( p->flags & _BDF_GLYPH ) )
1608 /* Missing STARTCHAR field. */
1609 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "STARTCHAR" ));
1610 error = BDF_Err_Missing_Startchar_Field;
1614 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
1618 p->glyph_enc = _bdf_atol( p->list.field[1], 0, 10 );
1620 /* Normalize negative encoding values. The specification only */
1621 /* allows -1, but we can be more generous here. */
1622 if ( p->glyph_enc < -1 )
1625 /* Check for alternative encoding format. */
1626 if ( p->glyph_enc == -1 && p->list.used > 2 )
1627 p->glyph_enc = _bdf_atol( p->list.field[2], 0, 10 );
1629 FT_TRACE4(( DBGMSG2, p->glyph_enc ));
1631 /* Check that the encoding is in the Unicode range because */
1632 /* otherwise p->have (a bitmap with static size) overflows. */
1633 if ( p->glyph_enc > 0 &&
1634 (size_t)p->glyph_enc >= sizeof ( p->have ) * 8 )
1636 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG5, lineno, "ENCODING" ));
1637 error = BDF_Err_Invalid_File_Format;
1641 /* Check whether this encoding has already been encountered. */
1642 /* If it has then change it to unencoded so it gets added if */
1644 if ( p->glyph_enc >= 0 )
1646 if ( _bdf_glyph_modified( p->have, p->glyph_enc ) )
1648 /* Emit a message saying a glyph has been moved to the */
1649 /* unencoded area. */
1650 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG12,
1651 p->glyph_enc, p->glyph_name ));
1656 _bdf_set_glyph_modified( p->have, p->glyph_enc );
1659 if ( p->glyph_enc >= 0 )
1661 /* Make sure there are enough glyphs allocated in case the */
1662 /* number of characters happen to be wrong. */
1663 if ( font->glyphs_used == font->glyphs_size )
1665 if ( FT_RENEW_ARRAY( font->glyphs,
1667 font->glyphs_size + 64 ) )
1670 font->glyphs_size += 64;
1673 glyph = font->glyphs + font->glyphs_used++;
1674 glyph->name = p->glyph_name;
1675 glyph->encoding = p->glyph_enc;
1677 /* Reset the initial glyph info. */
1682 /* Unencoded glyph. Check whether it should */
1683 /* be added or not. */
1684 if ( p->opts->keep_unencoded != 0 )
1686 /* Allocate the next unencoded glyph. */
1687 if ( font->unencoded_used == font->unencoded_size )
1689 if ( FT_RENEW_ARRAY( font->unencoded ,
1690 font->unencoded_size,
1691 font->unencoded_size + 4 ) )
1694 font->unencoded_size += 4;
1697 glyph = font->unencoded + font->unencoded_used;
1698 glyph->name = p->glyph_name;
1699 glyph->encoding = font->unencoded_used++;
1702 /* Free up the glyph name if the unencoded shouldn't be */
1704 FT_FREE( p->glyph_name );
1709 /* Clear the flags that might be added when width and height are */
1710 /* checked for consistency. */
1711 p->flags &= ~( _BDF_GLYPH_WIDTH_CHECK | _BDF_GLYPH_HEIGHT_CHECK );
1713 p->flags |= _BDF_ENCODING;
1718 /* Point at the glyph being constructed. */
1719 if ( p->glyph_enc == -1 )
1720 glyph = font->unencoded + ( font->unencoded_used - 1 );
1722 glyph = font->glyphs + ( font->glyphs_used - 1 );
1724 /* Check whether a bitmap is being constructed. */
1725 if ( p->flags & _BDF_BITMAP )
1727 /* If there are more rows than are specified in the glyph metrics, */
1728 /* ignore the remaining lines. */
1729 if ( p->row >= (unsigned long)glyph->bbx.height )
1731 if ( !( p->flags & _BDF_GLYPH_HEIGHT_CHECK ) )
1733 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG13, glyph->encoding ));
1734 p->flags |= _BDF_GLYPH_HEIGHT_CHECK;
1741 /* Only collect the number of nibbles indicated by the glyph */
1742 /* metrics. If there are more columns, they are simply ignored. */
1743 nibbles = glyph->bpr << 1;
1744 bp = glyph->bitmap + p->row * glyph->bpr;
1746 for ( i = 0; i < nibbles; i++ )
1749 if ( !isdigok( hdigits, c ) )
1751 *bp = (FT_Byte)( ( *bp << 4 ) + a2i[c] );
1752 if ( i + 1 < nibbles && ( i & 1 ) )
1756 /* If any line has not enough columns, */
1757 /* indicate they have been padded with zero bits. */
1759 !( p->flags & _BDF_GLYPH_WIDTH_CHECK ) )
1761 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG16, glyph->encoding ));
1762 p->flags |= _BDF_GLYPH_WIDTH_CHECK;
1766 /* Remove possible garbage at the right. */
1767 mask_index = ( glyph->bbx.width * p->font->bpp ) & 7;
1768 if ( glyph->bbx.width )
1769 *bp &= nibble_mask[mask_index];
1771 /* If any line has extra columns, indicate they have been removed. */
1772 if ( i == nibbles &&
1773 isdigok( hdigits, line[nibbles] ) &&
1774 !( p->flags & _BDF_GLYPH_WIDTH_CHECK ) )
1776 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG14, glyph->encoding ));
1777 p->flags |= _BDF_GLYPH_WIDTH_CHECK;
1785 /* Expect the SWIDTH (scalable width) field next. */
1786 if ( ft_memcmp( line, "SWIDTH", 6 ) == 0 )
1788 if ( !( p->flags & _BDF_ENCODING ) )
1789 goto Missing_Encoding;
1791 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
1795 glyph->swidth = (unsigned short)_bdf_atoul( p->list.field[1], 0, 10 );
1796 p->flags |= _BDF_SWIDTH;
1801 /* Expect the DWIDTH (scalable width) field next. */
1802 if ( ft_memcmp( line, "DWIDTH", 6 ) == 0 )
1804 if ( !( p->flags & _BDF_ENCODING ) )
1805 goto Missing_Encoding;
1807 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
1811 glyph->dwidth = (unsigned short)_bdf_atoul( p->list.field[1], 0, 10 );
1813 if ( !( p->flags & _BDF_SWIDTH ) )
1815 /* Missing SWIDTH field. Emit an auto correction message and set */
1816 /* the scalable width from the device width. */
1817 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG9, lineno ));
1819 glyph->swidth = (unsigned short)FT_MulDiv(
1820 glyph->dwidth, 72000L,
1821 (FT_Long)( font->point_size *
1822 font->resolution_x ) );
1825 p->flags |= _BDF_DWIDTH;
1829 /* Expect the BBX field next. */
1830 if ( ft_memcmp( line, "BBX", 3 ) == 0 )
1832 if ( !( p->flags & _BDF_ENCODING ) )
1833 goto Missing_Encoding;
1835 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
1839 glyph->bbx.width = _bdf_atos( p->list.field[1], 0, 10 );
1840 glyph->bbx.height = _bdf_atos( p->list.field[2], 0, 10 );
1841 glyph->bbx.x_offset = _bdf_atos( p->list.field[3], 0, 10 );
1842 glyph->bbx.y_offset = _bdf_atos( p->list.field[4], 0, 10 );
1844 /* Generate the ascent and descent of the character. */
1845 glyph->bbx.ascent = (short)( glyph->bbx.height + glyph->bbx.y_offset );
1846 glyph->bbx.descent = (short)( -glyph->bbx.y_offset );
1848 /* Determine the overall font bounding box as the characters are */
1849 /* loaded so corrections can be done later if indicated. */
1850 p->maxas = (short)FT_MAX( glyph->bbx.ascent, p->maxas );
1851 p->maxds = (short)FT_MAX( glyph->bbx.descent, p->maxds );
1853 p->rbearing = (short)( glyph->bbx.width + glyph->bbx.x_offset );
1855 p->maxrb = (short)FT_MAX( p->rbearing, p->maxrb );
1856 p->minlb = (short)FT_MIN( glyph->bbx.x_offset, p->minlb );
1857 p->maxlb = (short)FT_MAX( glyph->bbx.x_offset, p->maxlb );
1859 if ( !( p->flags & _BDF_DWIDTH ) )
1861 /* Missing DWIDTH field. Emit an auto correction message and set */
1862 /* the device width to the glyph width. */
1863 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG10, lineno ));
1864 glyph->dwidth = glyph->bbx.width;
1867 /* If the BDF_CORRECT_METRICS flag is set, then adjust the SWIDTH */
1868 /* value if necessary. */
1869 if ( p->opts->correct_metrics != 0 )
1871 /* Determine the point size of the glyph. */
1872 unsigned short sw = (unsigned short)FT_MulDiv(
1873 glyph->dwidth, 72000L,
1874 (FT_Long)( font->point_size *
1875 font->resolution_x ) );
1878 if ( sw != glyph->swidth )
1882 if ( p->glyph_enc == -1 )
1883 _bdf_set_glyph_modified( font->umod,
1884 font->unencoded_used - 1 );
1886 _bdf_set_glyph_modified( font->nmod, glyph->encoding );
1888 p->flags |= _BDF_SWIDTH_ADJ;
1893 p->flags |= _BDF_BBX;
1897 /* And finally, gather up the bitmap. */
1898 if ( ft_memcmp( line, "BITMAP", 6 ) == 0 )
1900 unsigned long bitmap_size;
1903 if ( !( p->flags & _BDF_BBX ) )
1905 /* Missing BBX field. */
1906 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "BBX" ));
1907 error = BDF_Err_Missing_Bbx_Field;
1911 /* Allocate enough space for the bitmap. */
1912 glyph->bpr = ( glyph->bbx.width * p->font->bpp + 7 ) >> 3;
1914 bitmap_size = glyph->bpr * glyph->bbx.height;
1915 if ( glyph->bpr > 0xFFFFU || bitmap_size > 0xFFFFU )
1917 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG4, lineno ));
1918 error = BDF_Err_Bbx_Too_Big;
1922 glyph->bytes = (unsigned short)bitmap_size;
1924 if ( FT_NEW_ARRAY( glyph->bitmap, glyph->bytes ) )
1928 p->flags |= _BDF_BITMAP;
1933 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG9, lineno ));
1934 error = BDF_Err_Invalid_File_Format;
1938 /* Missing ENCODING field. */
1939 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "ENCODING" ));
1940 error = BDF_Err_Missing_Encoding_Field;
1943 if ( error && ( p->flags & _BDF_GLYPH ) )
1944 FT_FREE( p->glyph_name );
1950 /* Load the font properties. */
1952 _bdf_parse_properties( char* line,
1953 unsigned long linelen,
1954 unsigned long lineno,
1959 _bdf_line_func_t* next;
1964 FT_Error error = BDF_Err_Ok;
1966 FT_UNUSED( lineno );
1969 next = (_bdf_line_func_t *)call_data;
1970 p = (_bdf_parse_t *) client_data;
1972 /* Check for the end of the properties. */
1973 if ( ft_memcmp( line, "ENDPROPERTIES", 13 ) == 0 )
1975 /* If the FONT_ASCENT or FONT_DESCENT properties have not been */
1976 /* encountered yet, then make sure they are added as properties and */
1977 /* make sure they are set from the font bounding box info. */
1979 /* This is *always* done regardless of the options, because X11 */
1980 /* requires these two fields to compile fonts. */
1981 if ( bdf_get_font_property( p->font, "FONT_ASCENT" ) == 0 )
1983 p->font->font_ascent = p->font->bbx.ascent;
1984 ft_sprintf( nbuf, "%hd", p->font->bbx.ascent );
1985 error = _bdf_add_property( p->font, (char *)"FONT_ASCENT",
1990 FT_TRACE2(( "_bdf_parse_properties: " ACMSG1, p->font->bbx.ascent ));
1991 p->font->modified = 1;
1994 if ( bdf_get_font_property( p->font, "FONT_DESCENT" ) == 0 )
1996 p->font->font_descent = p->font->bbx.descent;
1997 ft_sprintf( nbuf, "%hd", p->font->bbx.descent );
1998 error = _bdf_add_property( p->font, (char *)"FONT_DESCENT",
2003 FT_TRACE2(( "_bdf_parse_properties: " ACMSG2, p->font->bbx.descent ));
2004 p->font->modified = 1;
2007 p->flags &= ~_BDF_PROPS;
2008 *next = _bdf_parse_glyphs;
2013 /* Ignore the _XFREE86_GLYPH_RANGES properties. */
2014 if ( ft_memcmp( line, "_XFREE86_GLYPH_RANGES", 21 ) == 0 )
2017 /* Handle COMMENT fields and properties in a special way to preserve */
2019 if ( ft_memcmp( line, "COMMENT", 7 ) == 0 )
2021 name = value = line;
2025 error = _bdf_add_property( p->font, name, value, lineno );
2029 else if ( _bdf_is_atom( line, linelen, &name, &value, p->font ) )
2031 error = _bdf_add_property( p->font, name, value, lineno );
2037 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
2040 name = p->list.field[0];
2042 _bdf_list_shift( &p->list, 1 );
2043 value = _bdf_list_join( &p->list, ' ', &vlen );
2045 error = _bdf_add_property( p->font, name, value, lineno );
2055 /* Load the font header. */
2057 _bdf_parse_start( char* line,
2058 unsigned long linelen,
2059 unsigned long lineno,
2064 _bdf_line_func_t* next;
2069 FT_Memory memory = NULL;
2070 FT_Error error = BDF_Err_Ok;
2072 FT_UNUSED( lineno ); /* only used in debug mode */
2075 next = (_bdf_line_func_t *)call_data;
2076 p = (_bdf_parse_t *) client_data;
2079 memory = p->font->memory;
2081 /* Check for a comment. This is done to handle those fonts that have */
2082 /* comments before the STARTFONT line for some reason. */
2083 if ( ft_memcmp( line, "COMMENT", 7 ) == 0 )
2085 if ( p->opts->keep_comments != 0 && p->font != 0 )
2096 error = _bdf_add_comment( p->font, s, linelen );
2099 /* here font is not defined! */
2105 if ( !( p->flags & _BDF_START ) )
2109 if ( ft_memcmp( line, "STARTFONT", 9 ) != 0 )
2111 /* we don't emit an error message since this code gets */
2112 /* explicitly caught one level higher */
2113 error = BDF_Err_Missing_Startfont_Field;
2117 p->flags = _BDF_START;
2120 if ( FT_NEW( font ) )
2124 font->memory = p->memory;
2129 bdf_property_t* prop;
2132 error = hash_init( &(font->proptbl), memory );
2135 for ( i = 0, prop = (bdf_property_t*)_bdf_properties;
2136 i < _num_bdf_properties; i++, prop++ )
2138 error = hash_insert( prop->name, i,
2139 &(font->proptbl), memory );
2145 if ( FT_ALLOC( p->font->internal, sizeof ( hashtable ) ) )
2147 error = hash_init( (hashtable *)p->font->internal,memory );
2150 p->font->spacing = p->opts->font_spacing;
2151 p->font->default_char = -1;
2156 /* Check for the start of the properties. */
2157 if ( ft_memcmp( line, "STARTPROPERTIES", 15 ) == 0 )
2159 if ( !( p->flags & _BDF_FONT_BBX ) )
2161 /* Missing the FONTBOUNDINGBOX field. */
2162 FT_ERROR(( "_bdf_parse_start: " ERRMSG1, lineno, "FONTBOUNDINGBOX" ));
2163 error = BDF_Err_Missing_Fontboundingbox_Field;
2167 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
2170 /* at this point, `p->font' can't be NULL */
2171 p->cnt = p->font->props_size = _bdf_atoul( p->list.field[1], 0, 10 );
2173 if ( FT_NEW_ARRAY( p->font->props, p->cnt ) )
2176 p->flags |= _BDF_PROPS;
2177 *next = _bdf_parse_properties;
2182 /* Check for the FONTBOUNDINGBOX field. */
2183 if ( ft_memcmp( line, "FONTBOUNDINGBOX", 15 ) == 0 )
2185 if ( !( p->flags & _BDF_SIZE ) )
2187 /* Missing the SIZE field. */
2188 FT_ERROR(( "_bdf_parse_start: " ERRMSG1, lineno, "SIZE" ));
2189 error = BDF_Err_Missing_Size_Field;
2193 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
2197 p->font->bbx.width = _bdf_atos( p->list.field[1], 0, 10 );
2198 p->font->bbx.height = _bdf_atos( p->list.field[2], 0, 10 );
2200 p->font->bbx.x_offset = _bdf_atos( p->list.field[3], 0, 10 );
2201 p->font->bbx.y_offset = _bdf_atos( p->list.field[4], 0, 10 );
2203 p->font->bbx.ascent = (short)( p->font->bbx.height +
2204 p->font->bbx.y_offset );
2206 p->font->bbx.descent = (short)( -p->font->bbx.y_offset );
2208 p->flags |= _BDF_FONT_BBX;
2213 /* The next thing to check for is the FONT field. */
2214 if ( ft_memcmp( line, "FONT", 4 ) == 0 )
2216 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
2219 _bdf_list_shift( &p->list, 1 );
2221 s = _bdf_list_join( &p->list, ' ', &slen );
2225 FT_ERROR(( "_bdf_parse_start: " ERRMSG8, lineno, "FONT" ));
2226 error = BDF_Err_Invalid_File_Format;
2230 /* Allowing multiple `FONT' lines (which is invalid) doesn't hurt... */
2231 FT_FREE( p->font->name );
2233 if ( FT_NEW_ARRAY( p->font->name, slen + 1 ) )
2235 FT_MEM_COPY( p->font->name, s, slen + 1 );
2237 /* If the font name is an XLFD name, set the spacing to the one in */
2238 /* the font name. If there is no spacing fall back on the default. */
2239 error = _bdf_set_default_spacing( p->font, p->opts, lineno );
2243 p->flags |= _BDF_FONT_NAME;
2248 /* Check for the SIZE field. */
2249 if ( ft_memcmp( line, "SIZE", 4 ) == 0 )
2251 if ( !( p->flags & _BDF_FONT_NAME ) )
2253 /* Missing the FONT field. */
2254 FT_ERROR(( "_bdf_parse_start: " ERRMSG1, lineno, "FONT" ));
2255 error = BDF_Err_Missing_Font_Field;
2259 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
2263 p->font->point_size = _bdf_atoul( p->list.field[1], 0, 10 );
2264 p->font->resolution_x = _bdf_atoul( p->list.field[2], 0, 10 );
2265 p->font->resolution_y = _bdf_atoul( p->list.field[3], 0, 10 );
2267 /* Check for the bits per pixel field. */
2268 if ( p->list.used == 5 )
2270 unsigned short bitcount, i, shift;
2273 p->font->bpp = (unsigned short)_bdf_atos( p->list.field[4], 0, 10 );
2275 /* Only values 1, 2, 4, 8 are allowed. */
2276 shift = p->font->bpp;
2278 for ( i = 0; shift > 0; i++ )
2285 shift = (short)( ( bitcount > 3 ) ? 8 : ( 1 << bitcount ) );
2287 if ( p->font->bpp > shift || p->font->bpp != shift )
2289 /* select next higher value */
2290 p->font->bpp = (unsigned short)( shift << 1 );
2291 FT_TRACE2(( "_bdf_parse_start: " ACMSG11, p->font->bpp ));
2297 p->flags |= _BDF_SIZE;
2302 /* Check for the CHARS field -- font properties are optional */
2303 if ( ft_memcmp( line, "CHARS", 5 ) == 0 )
2308 if ( !( p->flags & _BDF_FONT_BBX ) )
2310 /* Missing the FONTBOUNDINGBOX field. */
2311 FT_ERROR(( "_bdf_parse_start: " ERRMSG1, lineno, "FONTBOUNDINGBOX" ));
2312 error = BDF_Err_Missing_Fontboundingbox_Field;
2316 /* Add the two standard X11 properties which are required */
2317 /* for compiling fonts. */
2318 p->font->font_ascent = p->font->bbx.ascent;
2319 ft_sprintf( nbuf, "%hd", p->font->bbx.ascent );
2320 error = _bdf_add_property( p->font, (char *)"FONT_ASCENT",
2324 FT_TRACE2(( "_bdf_parse_properties: " ACMSG1, p->font->bbx.ascent ));
2326 p->font->font_descent = p->font->bbx.descent;
2327 ft_sprintf( nbuf, "%hd", p->font->bbx.descent );
2328 error = _bdf_add_property( p->font, (char *)"FONT_DESCENT",
2332 FT_TRACE2(( "_bdf_parse_properties: " ACMSG2, p->font->bbx.descent ));
2334 p->font->modified = 1;
2336 *next = _bdf_parse_glyphs;
2338 /* A special return value. */
2343 FT_ERROR(( "_bdf_parse_start: " ERRMSG9, lineno ));
2344 error = BDF_Err_Invalid_File_Format;
2351 /*************************************************************************/
2355 /*************************************************************************/
2358 FT_LOCAL_DEF( FT_Error )
2359 bdf_load_font( FT_Stream stream,
2360 FT_Memory extmemory,
2361 bdf_options_t* opts,
2364 unsigned long lineno = 0; /* make compiler happy */
2365 _bdf_parse_t *p = NULL;
2367 FT_Memory memory = extmemory;
2368 FT_Error error = BDF_Err_Ok;
2375 p->opts = (bdf_options_t*)( ( opts != 0 ) ? opts : &_bdf_opts );
2377 p->memory = extmemory; /* only during font creation */
2379 _bdf_list_init( &p->list, extmemory );
2381 error = _bdf_readstream( stream, _bdf_parse_start,
2382 (void *)p, &lineno );
2388 /* If the font is not proportional, set the font's monowidth */
2389 /* field to the width of the font bounding box. */
2390 memory = p->font->memory;
2392 if ( p->font->spacing != BDF_PROPORTIONAL )
2393 p->font->monowidth = p->font->bbx.width;
2395 /* If the number of glyphs loaded is not that of the original count, */
2396 /* indicate the difference. */
2397 if ( p->cnt != p->font->glyphs_used + p->font->unencoded_used )
2399 FT_TRACE2(( "bdf_load_font: " ACMSG15, p->cnt,
2400 p->font->glyphs_used + p->font->unencoded_used ));
2401 p->font->modified = 1;
2404 /* Once the font has been loaded, adjust the overall font metrics if */
2406 if ( p->opts->correct_metrics != 0 &&
2407 ( p->font->glyphs_used > 0 || p->font->unencoded_used > 0 ) )
2409 if ( p->maxrb - p->minlb != p->font->bbx.width )
2411 FT_TRACE2(( "bdf_load_font: " ACMSG3,
2412 p->font->bbx.width, p->maxrb - p->minlb ));
2413 p->font->bbx.width = (unsigned short)( p->maxrb - p->minlb );
2414 p->font->modified = 1;
2417 if ( p->font->bbx.x_offset != p->minlb )
2419 FT_TRACE2(( "bdf_load_font: " ACMSG4,
2420 p->font->bbx.x_offset, p->minlb ));
2421 p->font->bbx.x_offset = p->minlb;
2422 p->font->modified = 1;
2425 if ( p->font->bbx.ascent != p->maxas )
2427 FT_TRACE2(( "bdf_load_font: " ACMSG5,
2428 p->font->bbx.ascent, p->maxas ));
2429 p->font->bbx.ascent = p->maxas;
2430 p->font->modified = 1;
2433 if ( p->font->bbx.descent != p->maxds )
2435 FT_TRACE2(( "bdf_load_font: " ACMSG6,
2436 p->font->bbx.descent, p->maxds ));
2437 p->font->bbx.descent = p->maxds;
2438 p->font->bbx.y_offset = (short)( -p->maxds );
2439 p->font->modified = 1;
2442 if ( p->maxas + p->maxds != p->font->bbx.height )
2444 FT_TRACE2(( "bdf_load_font: " ACMSG7,
2445 p->font->bbx.height, p->maxas + p->maxds ));
2446 p->font->bbx.height = (unsigned short)( p->maxas + p->maxds );
2449 if ( p->flags & _BDF_SWIDTH_ADJ )
2450 FT_TRACE2(( "bdf_load_font: " ACMSG8 ));
2454 if ( p->flags & _BDF_START )
2456 /* The ENDFONT field was never reached or did not exist. */
2457 if ( !( p->flags & _BDF_GLYPHS ) )
2459 /* Error happened while parsing header. */
2460 FT_ERROR(( "bdf_load_font: " ERRMSG2, lineno ));
2461 error = BDF_Err_Corrupted_Font_Header;
2466 /* Error happened when parsing glyphs. */
2467 FT_ERROR(( "bdf_load_font: " ERRMSG3, lineno ));
2468 error = BDF_Err_Corrupted_Font_Glyphs;
2475 /* Make sure the comments are NULL terminated if they exist. */
2476 memory = p->font->memory;
2478 if ( p->font->comments_len > 0 )
2480 if ( FT_RENEW_ARRAY( p->font->comments,
2481 p->font->comments_len,
2482 p->font->comments_len + 1 ) )
2485 p->font->comments[p->font->comments_len] = 0;
2488 else if ( error == BDF_Err_Ok )
2489 error = BDF_Err_Invalid_File_Format;
2496 _bdf_list_done( &p->list );
2506 bdf_free_font( p->font );
2516 FT_LOCAL_DEF( void )
2517 bdf_free_font( bdf_font_t* font )
2519 bdf_property_t* prop;
2521 bdf_glyph_t* glyphs;
2528 memory = font->memory;
2530 FT_FREE( font->name );
2532 /* Free up the internal hash table of property names. */
2533 if ( font->internal )
2535 hash_free( (hashtable *)font->internal, memory );
2536 FT_FREE( font->internal );
2539 /* Free up the comment info. */
2540 FT_FREE( font->comments );
2542 /* Free up the properties. */
2543 for ( i = 0; i < font->props_size; i++ )
2545 if ( font->props[i].format == BDF_ATOM )
2546 FT_FREE( font->props[i].value.atom );
2549 FT_FREE( font->props );
2551 /* Free up the character info. */
2552 for ( i = 0, glyphs = font->glyphs;
2553 i < font->glyphs_used; i++, glyphs++ )
2555 FT_FREE( glyphs->name );
2556 FT_FREE( glyphs->bitmap );
2559 for ( i = 0, glyphs = font->unencoded; i < font->unencoded_used;
2562 FT_FREE( glyphs->name );
2563 FT_FREE( glyphs->bitmap );
2566 FT_FREE( font->glyphs );
2567 FT_FREE( font->unencoded );
2569 /* Free up the overflow storage if it was used. */
2570 for ( i = 0, glyphs = font->overflow.glyphs;
2571 i < font->overflow.glyphs_used; i++, glyphs++ )
2573 FT_FREE( glyphs->name );
2574 FT_FREE( glyphs->bitmap );
2577 FT_FREE( font->overflow.glyphs );
2580 hash_free( &(font->proptbl), memory );
2582 /* Free up the user defined properties. */
2583 for ( prop = font->user_props, i = 0;
2584 i < font->nuser_props; i++, prop++ )
2586 FT_FREE( prop->name );
2587 if ( prop->format == BDF_ATOM )
2588 FT_FREE( prop->value.atom );
2591 FT_FREE( font->user_props );
2593 /* FREE( font ); */ /* XXX Fixme */
2597 FT_LOCAL_DEF( bdf_property_t * )
2598 bdf_get_font_property( bdf_font_t* font,
2604 if ( font == 0 || font->props_size == 0 || name == 0 || *name == 0 )
2607 hn = hash_lookup( name, (hashtable *)font->internal );
2609 return hn ? ( font->props + hn->data ) : 0;