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;
572 list->field[4] = (char*)empty;
575 /* If the line is empty, then simply return. */
576 if ( linelen == 0 || line[0] == 0 )
579 /* In the original code, if the `separators' parameter is NULL or */
580 /* empty, the list is split into individual bytes. We don't need */
581 /* this, so an error is signaled. */
582 if ( separators == 0 || *separators == 0 )
584 error = BDF_Err_Invalid_Argument;
588 /* Prepare the separator bitmap. */
589 FT_MEM_ZERO( seps, 32 );
591 /* If the very last character of the separator string is a plus, then */
592 /* set the `mult' flag to indicate that multiple separators should be */
593 /* collapsed into one. */
594 for ( mult = 0, sp = separators; sp && *sp; sp++ )
596 if ( *sp == '+' && *( sp + 1 ) == 0 )
599 setsbit( seps, *sp );
602 /* Break the line up into fields. */
603 for ( final_empty = 0, sp = ep = line, end = sp + linelen;
606 /* Collect everything that is not a separator. */
607 for ( ; *ep && !sbitset( seps, *ep ); ep++ )
610 /* Resize the list if necessary. */
611 if ( list->used == list->size )
613 error = _bdf_list_ensure( list, list->used + 1 );
618 /* Assign the field appropriately. */
619 list->field[list->used++] = ( ep > sp ) ? sp : (char*)empty;
625 /* If multiple separators should be collapsed, do it now by */
626 /* setting all the separator characters to 0. */
627 for ( ; *ep && sbitset( seps, *ep ); ep++ )
631 /* Don't collapse multiple separators by making them 0, so just */
632 /* make the one encountered 0. */
635 final_empty = ( ep > sp && *ep == 0 );
639 /* Finally, NULL-terminate the list. */
640 if ( list->used + final_empty >= list->size )
642 error = _bdf_list_ensure( list, list->used + final_empty + 1 );
648 list->field[list->used++] = (char*)empty;
650 list->field[list->used] = 0;
657 #define NO_SKIP 256 /* this value cannot be stored in a 'char' */
661 _bdf_readstream( FT_Stream stream,
662 _bdf_line_func_t callback,
667 unsigned long lineno, buf_size;
668 int refill, hold, to_skip;
669 ptrdiff_t bytes, start, end, cursor, avail;
671 FT_Memory memory = stream->memory;
672 FT_Error error = BDF_Err_Ok;
677 error = BDF_Err_Invalid_Argument;
681 /* initial size and allocation of the input buffer */
684 if ( FT_NEW_ARRAY( buf, buf_size ) )
696 bytes = 0; /* make compiler happy */
702 bytes = (ptrdiff_t)FT_Stream_TryRead(
703 stream, (FT_Byte*)buf + cursor,
704 (FT_ULong)( buf_size - cursor ) );
705 avail = cursor + bytes;
712 /* should we skip an optional character like \n or \r? */
713 if ( start < avail && buf[start] == to_skip )
720 /* try to find the end of the line */
721 while ( end < avail && buf[end] != '\n' && buf[end] != '\r' )
724 /* if we hit the end of the buffer, try shifting its content */
725 /* or even resizing it */
728 if ( bytes == 0 ) /* last line in file doesn't end in \r or \n */
729 break; /* ignore it then exit */
733 /* this line is definitely too long; try resizing the input */
734 /* buffer a bit to handle it. */
738 if ( buf_size >= 65536UL ) /* limit ourselves to 64KByte */
740 FT_ERROR(( "_bdf_readstream: " ERRMSG6, lineno ));
741 error = BDF_Err_Invalid_Argument;
745 new_size = buf_size * 2;
746 if ( FT_RENEW_ARRAY( buf, buf_size, new_size ) )
754 bytes = avail - start;
756 FT_MEM_COPY( buf, buf + start, bytes );
766 /* Temporarily NUL-terminate the line. */
770 /* XXX: Use encoding independent value for 0x1a */
771 if ( buf[start] != '#' && buf[start] != 0x1a && end > start )
773 error = (*cb)( buf + start, (unsigned long)( end - start ), lineno,
774 (void*)&cb, client_data );
775 /* Redo if we have encountered CHARS without properties. */
777 error = (*cb)( buf + start, (unsigned long)( end - start ), lineno,
778 (void*)&cb, client_data );
784 buf[end] = (char)hold;
789 else if ( hold == '\r' )
803 /* XXX: make this work with EBCDIC also */
805 static const unsigned char a2i[128] =
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, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
811 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x00, 0x00,
812 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00,
813 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
814 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
815 0x00, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00,
816 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
817 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
820 static const unsigned char odigits[32] =
822 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00,
823 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
824 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
825 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
828 static const unsigned char ddigits[32] =
830 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x03,
831 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
832 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
833 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
836 static const unsigned char hdigits[32] =
838 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x03,
839 0x7e, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00,
840 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
841 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
845 /* Routine to convert an ASCII string into an unsigned long integer. */
852 const unsigned char* dmap;
855 if ( s == 0 || *s == 0 )
858 /* Make sure the radix is something recognizable. Default to 10. */
873 /* Check for the special hex prefix. */
875 ( *( s + 1 ) == 'x' || *( s + 1 ) == 'X' ) )
882 for ( v = 0; sbitset( dmap, *s ); s++ )
883 v = v * base + a2i[(int)*s];
892 /* Routine to convert an ASCII string into an signed long integer. */
899 const unsigned char* dmap;
902 if ( s == 0 || *s == 0 )
905 /* Make sure the radix is something recognizable. Default to 10. */
920 /* Check for a minus sign. */
928 /* Check for the special hex prefix. */
930 ( *( s + 1 ) == 'x' || *( s + 1 ) == 'X' ) )
937 for ( v = 0; sbitset( dmap, *s ); s++ )
938 v = v * base + a2i[(int)*s];
943 return ( !neg ) ? v : -v;
947 /* Routine to convert an ASCII string into an signed short integer. */
954 const unsigned char* dmap;
957 if ( s == 0 || *s == 0 )
960 /* Make sure the radix is something recognizable. Default to 10. */
975 /* Check for a minus. */
983 /* Check for the special hex prefix. */
985 ( *( s + 1 ) == 'x' || *( s + 1 ) == 'X' ) )
992 for ( v = 0; sbitset( dmap, *s ); s++ )
993 v = (short)( v * base + a2i[(int)*s] );
998 return (short)( ( !neg ) ? v : -v );
1002 /* Routine to compare two glyphs by encoding so they can be sorted. */
1004 by_encoding( const void* a,
1007 bdf_glyph_t *c1, *c2;
1010 c1 = (bdf_glyph_t *)a;
1011 c2 = (bdf_glyph_t *)b;
1013 if ( c1->encoding < c2->encoding )
1016 if ( c1->encoding > c2->encoding )
1024 bdf_create_property( char* name,
1030 FT_Memory memory = font->memory;
1031 FT_Error error = BDF_Err_Ok;
1034 /* First check whether the property has */
1035 /* already been added or not. If it has, then */
1036 /* simply ignore it. */
1037 if ( hash_lookup( name, &(font->proptbl) ) )
1040 if ( FT_RENEW_ARRAY( font->user_props,
1042 font->nuser_props + 1 ) )
1045 p = font->user_props + font->nuser_props;
1048 n = ft_strlen( name ) + 1;
1049 if ( n > FT_ULONG_MAX )
1050 return BDF_Err_Invalid_Argument;
1052 if ( FT_NEW_ARRAY( p->name, n ) )
1055 FT_MEM_COPY( (char *)p->name, name, n );
1060 n = _num_bdf_properties + font->nuser_props;
1062 error = hash_insert( p->name, n, &(font->proptbl), memory );
1066 font->nuser_props++;
1073 FT_LOCAL_DEF( bdf_property_t * )
1074 bdf_get_property( char* name,
1081 if ( name == 0 || *name == 0 )
1084 if ( ( hn = hash_lookup( name, &(font->proptbl) ) ) == 0 )
1088 if ( propid >= _num_bdf_properties )
1089 return font->user_props + ( propid - _num_bdf_properties );
1091 return (bdf_property_t*)_bdf_properties + propid;
1095 /*************************************************************************/
1097 /* BDF font file parsing flags and functions. */
1099 /*************************************************************************/
1104 #define _BDF_START 0x0001
1105 #define _BDF_FONT_NAME 0x0002
1106 #define _BDF_SIZE 0x0004
1107 #define _BDF_FONT_BBX 0x0008
1108 #define _BDF_PROPS 0x0010
1109 #define _BDF_GLYPHS 0x0020
1110 #define _BDF_GLYPH 0x0040
1111 #define _BDF_ENCODING 0x0080
1112 #define _BDF_SWIDTH 0x0100
1113 #define _BDF_DWIDTH 0x0200
1114 #define _BDF_BBX 0x0400
1115 #define _BDF_BITMAP 0x0800
1117 #define _BDF_SWIDTH_ADJ 0x1000
1119 #define _BDF_GLYPH_BITS ( _BDF_GLYPH | \
1126 #define _BDF_GLYPH_WIDTH_CHECK 0x40000000UL
1127 #define _BDF_GLYPH_HEIGHT_CHECK 0x80000000UL
1131 _bdf_add_comment( bdf_font_t* font,
1136 FT_Memory memory = font->memory;
1137 FT_Error error = BDF_Err_Ok;
1140 if ( FT_RENEW_ARRAY( font->comments,
1142 font->comments_len + len + 1 ) )
1145 cp = font->comments + font->comments_len;
1147 FT_MEM_COPY( cp, comment, len );
1150 font->comments_len += len + 1;
1157 /* Set the spacing from the font name if it exists, or set it to the */
1158 /* default specified in the options. */
1160 _bdf_set_default_spacing( bdf_font_t* font,
1161 bdf_options_t* opts,
1162 unsigned long lineno )
1168 FT_Error error = BDF_Err_Ok;
1171 if ( font == 0 || font->name == 0 || font->name[0] == 0 )
1173 error = BDF_Err_Invalid_Argument;
1177 memory = font->memory;
1179 _bdf_list_init( &list, memory );
1181 font->spacing = opts->font_spacing;
1183 len = ft_strlen( font->name ) + 1;
1184 /* Limit ourselves to 256 characters in the font name. */
1187 FT_ERROR(( "_bdf_set_default_spacing: " ERRMSG7, lineno ));
1188 error = BDF_Err_Invalid_Argument;
1192 FT_MEM_COPY( name, font->name, len );
1194 error = _bdf_list_split( &list, (char *)"-", name, len );
1198 if ( list.used == 15 )
1200 switch ( list.field[11][0] )
1204 font->spacing = BDF_CHARCELL;
1208 font->spacing = BDF_MONOWIDTH;
1212 font->spacing = BDF_PROPORTIONAL;
1218 _bdf_list_done( &list );
1225 /* Determine whether the property is an atom or not. If it is, then */
1226 /* clean it up so the double quotes are removed if they exist. */
1228 _bdf_is_atom( char* line,
1229 unsigned long linelen,
1239 *name = sp = ep = line;
1241 while ( *ep && *ep != ' ' && *ep != '\t' )
1251 p = bdf_get_property( sp, font );
1253 /* Restore the character that was saved before any return can happen. */
1257 /* If the property exists and is not an atom, just return here. */
1258 if ( p && p->format != BDF_ATOM )
1261 /* The property is an atom. Trim all leading and trailing whitespace */
1262 /* and double quotes for the atom value. */
1264 ep = line + linelen;
1266 /* Trim the leading whitespace if it exists. */
1270 ( *sp == ' ' || *sp == '\t' ) )
1273 /* Trim the leading double quote if it exists. */
1278 /* Trim the trailing whitespace if it exists. */
1280 ( *( ep - 1 ) == ' ' || *( ep - 1 ) == '\t' ) )
1283 /* Trim the trailing double quote if it exists. */
1284 if ( ep > sp && *( ep - 1 ) == '"' )
1292 _bdf_add_property( bdf_font_t* font,
1295 unsigned long lineno )
1299 bdf_property_t *prop, *fp;
1300 FT_Memory memory = font->memory;
1301 FT_Error error = BDF_Err_Ok;
1304 /* First, check whether the property already exists in the font. */
1305 if ( ( hn = hash_lookup( name, (hashtable *)font->internal ) ) != 0 )
1307 /* The property already exists in the font, so simply replace */
1308 /* the value of the property with the current value. */
1309 fp = font->props + hn->data;
1311 switch ( fp->format )
1314 /* Delete the current atom if it exists. */
1315 FT_FREE( fp->value.atom );
1317 if ( value && value[0] != 0 )
1319 if ( FT_STRDUP( fp->value.atom, value ) )
1325 fp->value.l = _bdf_atol( value, 0, 10 );
1329 fp->value.ul = _bdf_atoul( value, 0, 10 );
1339 /* See whether this property type exists yet or not. */
1340 /* If not, create it. */
1341 hn = hash_lookup( name, &(font->proptbl) );
1344 error = bdf_create_property( name, BDF_ATOM, font );
1347 hn = hash_lookup( name, &(font->proptbl) );
1350 /* Allocate another property if this is overflow. */
1351 if ( font->props_used == font->props_size )
1353 if ( font->props_size == 0 )
1355 if ( FT_NEW_ARRAY( font->props, 1 ) )
1360 if ( FT_RENEW_ARRAY( font->props,
1362 font->props_size + 1 ) )
1366 fp = font->props + font->props_size;
1367 FT_MEM_ZERO( fp, sizeof ( bdf_property_t ) );
1372 if ( propid >= _num_bdf_properties )
1373 prop = font->user_props + ( propid - _num_bdf_properties );
1375 prop = (bdf_property_t*)_bdf_properties + propid;
1377 fp = font->props + font->props_used;
1379 fp->name = prop->name;
1380 fp->format = prop->format;
1381 fp->builtin = prop->builtin;
1383 switch ( prop->format )
1387 if ( value != 0 && value[0] )
1389 if ( FT_STRDUP( fp->value.atom, value ) )
1395 fp->value.l = _bdf_atol( value, 0, 10 );
1399 fp->value.ul = _bdf_atoul( value, 0, 10 );
1403 /* If the property happens to be a comment, then it doesn't need */
1404 /* to be added to the internal hash table. */
1405 if ( ft_memcmp( name, "COMMENT", 7 ) != 0 )
1407 /* Add the property to the font property table. */
1408 error = hash_insert( fp->name,
1410 (hashtable *)font->internal,
1418 /* Some special cases need to be handled here. The DEFAULT_CHAR */
1419 /* property needs to be located if it exists in the property list, the */
1420 /* FONT_ASCENT and FONT_DESCENT need to be assigned if they are */
1421 /* present, and the SPACING property should override the default */
1423 if ( ft_memcmp( name, "DEFAULT_CHAR", 12 ) == 0 )
1424 font->default_char = fp->value.l;
1425 else if ( ft_memcmp( name, "FONT_ASCENT", 11 ) == 0 )
1426 font->font_ascent = fp->value.l;
1427 else if ( ft_memcmp( name, "FONT_DESCENT", 12 ) == 0 )
1428 font->font_descent = fp->value.l;
1429 else if ( ft_memcmp( name, "SPACING", 7 ) == 0 )
1431 if ( !fp->value.atom )
1433 FT_ERROR(( "_bdf_add_property: " ERRMSG8, lineno, "SPACING" ));
1434 error = BDF_Err_Invalid_File_Format;
1438 if ( fp->value.atom[0] == 'p' || fp->value.atom[0] == 'P' )
1439 font->spacing = BDF_PROPORTIONAL;
1440 else if ( fp->value.atom[0] == 'm' || fp->value.atom[0] == 'M' )
1441 font->spacing = BDF_MONOWIDTH;
1442 else if ( fp->value.atom[0] == 'c' || fp->value.atom[0] == 'C' )
1443 font->spacing = BDF_CHARCELL;
1451 static const unsigned char nibble_mask[8] =
1453 0xFF, 0x80, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC, 0xFE
1457 /* Actually parse the glyph info and bitmaps. */
1459 _bdf_parse_glyphs( char* line,
1460 unsigned long linelen,
1461 unsigned long lineno,
1468 unsigned long i, slen, nibbles;
1475 FT_Error error = BDF_Err_Ok;
1477 FT_UNUSED( call_data );
1478 FT_UNUSED( lineno ); /* only used in debug mode */
1481 p = (_bdf_parse_t *)client_data;
1484 memory = font->memory;
1486 /* Check for a comment. */
1487 if ( ft_memcmp( line, "COMMENT", 7 ) == 0 )
1497 error = _bdf_add_comment( p->font, s, linelen );
1501 /* The very first thing expected is the number of glyphs. */
1502 if ( !( p->flags & _BDF_GLYPHS ) )
1504 if ( ft_memcmp( line, "CHARS", 5 ) != 0 )
1506 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "CHARS" ));
1507 error = BDF_Err_Missing_Chars_Field;
1511 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
1514 p->cnt = font->glyphs_size = _bdf_atoul( p->list.field[1], 0, 10 );
1516 /* Make sure the number of glyphs is non-zero. */
1518 font->glyphs_size = 64;
1520 /* Limit ourselves to 1,114,112 glyphs in the font (this is the */
1521 /* number of code points available in Unicode). */
1522 if ( p->cnt >= 0x110000UL )
1524 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG5, lineno, "CHARS" ));
1525 error = BDF_Err_Invalid_Argument;
1529 if ( FT_NEW_ARRAY( font->glyphs, font->glyphs_size ) )
1532 p->flags |= _BDF_GLYPHS;
1537 /* Check for the ENDFONT field. */
1538 if ( ft_memcmp( line, "ENDFONT", 7 ) == 0 )
1540 /* Sort the glyphs by encoding. */
1541 ft_qsort( (char *)font->glyphs,
1543 sizeof ( bdf_glyph_t ),
1546 p->flags &= ~_BDF_START;
1551 /* Check for the ENDCHAR field. */
1552 if ( ft_memcmp( line, "ENDCHAR", 7 ) == 0 )
1555 p->flags &= ~_BDF_GLYPH_BITS;
1560 /* Check whether a glyph is being scanned but should be */
1561 /* ignored because it is an unencoded glyph. */
1562 if ( ( p->flags & _BDF_GLYPH ) &&
1563 p->glyph_enc == -1 &&
1564 p->opts->keep_unencoded == 0 )
1567 /* Check for the STARTCHAR field. */
1568 if ( ft_memcmp( line, "STARTCHAR", 9 ) == 0 )
1570 /* Set the character name in the parse info first until the */
1571 /* encoding can be checked for an unencoded character. */
1572 FT_FREE( p->glyph_name );
1574 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
1578 _bdf_list_shift( &p->list, 1 );
1580 s = _bdf_list_join( &p->list, ' ', &slen );
1584 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG8, lineno, "STARTCHAR" ));
1585 error = BDF_Err_Invalid_File_Format;
1589 if ( FT_NEW_ARRAY( p->glyph_name, slen + 1 ) )
1592 FT_MEM_COPY( p->glyph_name, s, slen + 1 );
1594 p->flags |= _BDF_GLYPH;
1596 FT_TRACE4(( DBGMSG1, lineno, s ));
1601 /* Check for the ENCODING field. */
1602 if ( ft_memcmp( line, "ENCODING", 8 ) == 0 )
1604 if ( !( p->flags & _BDF_GLYPH ) )
1606 /* Missing STARTCHAR field. */
1607 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "STARTCHAR" ));
1608 error = BDF_Err_Missing_Startchar_Field;
1612 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
1616 p->glyph_enc = _bdf_atol( p->list.field[1], 0, 10 );
1618 /* Normalize negative encoding values. The specification only */
1619 /* allows -1, but we can be more generous here. */
1620 if ( p->glyph_enc < -1 )
1623 /* Check for alternative encoding format. */
1624 if ( p->glyph_enc == -1 && p->list.used > 2 )
1625 p->glyph_enc = _bdf_atol( p->list.field[2], 0, 10 );
1627 if ( p->glyph_enc < -1 )
1630 FT_TRACE4(( DBGMSG2, p->glyph_enc ));
1632 /* Check that the encoding is in the Unicode range because */
1633 /* otherwise p->have (a bitmap with static size) overflows. */
1634 if ( p->glyph_enc > 0 &&
1635 (size_t)p->glyph_enc >= sizeof ( p->have ) /
1636 sizeof ( unsigned long ) * 32 )
1638 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG5, lineno, "ENCODING" ));
1639 error = BDF_Err_Invalid_File_Format;
1643 /* Check whether this encoding has already been encountered. */
1644 /* If it has then change it to unencoded so it gets added if */
1646 if ( p->glyph_enc >= 0 )
1648 if ( _bdf_glyph_modified( p->have, p->glyph_enc ) )
1650 /* Emit a message saying a glyph has been moved to the */
1651 /* unencoded area. */
1652 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG12,
1653 p->glyph_enc, p->glyph_name ));
1658 _bdf_set_glyph_modified( p->have, p->glyph_enc );
1661 if ( p->glyph_enc >= 0 )
1663 /* Make sure there are enough glyphs allocated in case the */
1664 /* number of characters happen to be wrong. */
1665 if ( font->glyphs_used == font->glyphs_size )
1667 if ( FT_RENEW_ARRAY( font->glyphs,
1669 font->glyphs_size + 64 ) )
1672 font->glyphs_size += 64;
1675 glyph = font->glyphs + font->glyphs_used++;
1676 glyph->name = p->glyph_name;
1677 glyph->encoding = p->glyph_enc;
1679 /* Reset the initial glyph info. */
1684 /* Unencoded glyph. Check whether it should */
1685 /* be added or not. */
1686 if ( p->opts->keep_unencoded != 0 )
1688 /* Allocate the next unencoded glyph. */
1689 if ( font->unencoded_used == font->unencoded_size )
1691 if ( FT_RENEW_ARRAY( font->unencoded ,
1692 font->unencoded_size,
1693 font->unencoded_size + 4 ) )
1696 font->unencoded_size += 4;
1699 glyph = font->unencoded + font->unencoded_used;
1700 glyph->name = p->glyph_name;
1701 glyph->encoding = font->unencoded_used++;
1704 /* Free up the glyph name if the unencoded shouldn't be */
1706 FT_FREE( p->glyph_name );
1711 /* Clear the flags that might be added when width and height are */
1712 /* checked for consistency. */
1713 p->flags &= ~( _BDF_GLYPH_WIDTH_CHECK | _BDF_GLYPH_HEIGHT_CHECK );
1715 p->flags |= _BDF_ENCODING;
1720 /* Point at the glyph being constructed. */
1721 if ( p->glyph_enc == -1 )
1722 glyph = font->unencoded + ( font->unencoded_used - 1 );
1724 glyph = font->glyphs + ( font->glyphs_used - 1 );
1726 /* Check whether a bitmap is being constructed. */
1727 if ( p->flags & _BDF_BITMAP )
1729 /* If there are more rows than are specified in the glyph metrics, */
1730 /* ignore the remaining lines. */
1731 if ( p->row >= (unsigned long)glyph->bbx.height )
1733 if ( !( p->flags & _BDF_GLYPH_HEIGHT_CHECK ) )
1735 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG13, glyph->encoding ));
1736 p->flags |= _BDF_GLYPH_HEIGHT_CHECK;
1743 /* Only collect the number of nibbles indicated by the glyph */
1744 /* metrics. If there are more columns, they are simply ignored. */
1745 nibbles = glyph->bpr << 1;
1746 bp = glyph->bitmap + p->row * glyph->bpr;
1748 for ( i = 0; i < nibbles; i++ )
1751 if ( !sbitset( hdigits, c ) )
1753 *bp = (FT_Byte)( ( *bp << 4 ) + a2i[c] );
1754 if ( i + 1 < nibbles && ( i & 1 ) )
1758 /* If any line has not enough columns, */
1759 /* indicate they have been padded with zero bits. */
1761 !( p->flags & _BDF_GLYPH_WIDTH_CHECK ) )
1763 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG16, glyph->encoding ));
1764 p->flags |= _BDF_GLYPH_WIDTH_CHECK;
1768 /* Remove possible garbage at the right. */
1769 mask_index = ( glyph->bbx.width * p->font->bpp ) & 7;
1770 if ( glyph->bbx.width )
1771 *bp &= nibble_mask[mask_index];
1773 /* If any line has extra columns, indicate they have been removed. */
1774 if ( i == nibbles &&
1775 sbitset( hdigits, line[nibbles] ) &&
1776 !( p->flags & _BDF_GLYPH_WIDTH_CHECK ) )
1778 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG14, glyph->encoding ));
1779 p->flags |= _BDF_GLYPH_WIDTH_CHECK;
1787 /* Expect the SWIDTH (scalable width) field next. */
1788 if ( ft_memcmp( line, "SWIDTH", 6 ) == 0 )
1790 if ( !( p->flags & _BDF_ENCODING ) )
1791 goto Missing_Encoding;
1793 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
1797 glyph->swidth = (unsigned short)_bdf_atoul( p->list.field[1], 0, 10 );
1798 p->flags |= _BDF_SWIDTH;
1803 /* Expect the DWIDTH (scalable width) field next. */
1804 if ( ft_memcmp( line, "DWIDTH", 6 ) == 0 )
1806 if ( !( p->flags & _BDF_ENCODING ) )
1807 goto Missing_Encoding;
1809 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
1813 glyph->dwidth = (unsigned short)_bdf_atoul( p->list.field[1], 0, 10 );
1815 if ( !( p->flags & _BDF_SWIDTH ) )
1817 /* Missing SWIDTH field. Emit an auto correction message and set */
1818 /* the scalable width from the device width. */
1819 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG9, lineno ));
1821 glyph->swidth = (unsigned short)FT_MulDiv(
1822 glyph->dwidth, 72000L,
1823 (FT_Long)( font->point_size *
1824 font->resolution_x ) );
1827 p->flags |= _BDF_DWIDTH;
1831 /* Expect the BBX field next. */
1832 if ( ft_memcmp( line, "BBX", 3 ) == 0 )
1834 if ( !( p->flags & _BDF_ENCODING ) )
1835 goto Missing_Encoding;
1837 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
1841 glyph->bbx.width = _bdf_atos( p->list.field[1], 0, 10 );
1842 glyph->bbx.height = _bdf_atos( p->list.field[2], 0, 10 );
1843 glyph->bbx.x_offset = _bdf_atos( p->list.field[3], 0, 10 );
1844 glyph->bbx.y_offset = _bdf_atos( p->list.field[4], 0, 10 );
1846 /* Generate the ascent and descent of the character. */
1847 glyph->bbx.ascent = (short)( glyph->bbx.height + glyph->bbx.y_offset );
1848 glyph->bbx.descent = (short)( -glyph->bbx.y_offset );
1850 /* Determine the overall font bounding box as the characters are */
1851 /* loaded so corrections can be done later if indicated. */
1852 p->maxas = (short)FT_MAX( glyph->bbx.ascent, p->maxas );
1853 p->maxds = (short)FT_MAX( glyph->bbx.descent, p->maxds );
1855 p->rbearing = (short)( glyph->bbx.width + glyph->bbx.x_offset );
1857 p->maxrb = (short)FT_MAX( p->rbearing, p->maxrb );
1858 p->minlb = (short)FT_MIN( glyph->bbx.x_offset, p->minlb );
1859 p->maxlb = (short)FT_MAX( glyph->bbx.x_offset, p->maxlb );
1861 if ( !( p->flags & _BDF_DWIDTH ) )
1863 /* Missing DWIDTH field. Emit an auto correction message and set */
1864 /* the device width to the glyph width. */
1865 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG10, lineno ));
1866 glyph->dwidth = glyph->bbx.width;
1869 /* If the BDF_CORRECT_METRICS flag is set, then adjust the SWIDTH */
1870 /* value if necessary. */
1871 if ( p->opts->correct_metrics != 0 )
1873 /* Determine the point size of the glyph. */
1874 unsigned short sw = (unsigned short)FT_MulDiv(
1875 glyph->dwidth, 72000L,
1876 (FT_Long)( font->point_size *
1877 font->resolution_x ) );
1880 if ( sw != glyph->swidth )
1884 if ( p->glyph_enc == -1 )
1885 _bdf_set_glyph_modified( font->umod,
1886 font->unencoded_used - 1 );
1888 _bdf_set_glyph_modified( font->nmod, glyph->encoding );
1890 p->flags |= _BDF_SWIDTH_ADJ;
1895 p->flags |= _BDF_BBX;
1899 /* And finally, gather up the bitmap. */
1900 if ( ft_memcmp( line, "BITMAP", 6 ) == 0 )
1902 unsigned long bitmap_size;
1905 if ( !( p->flags & _BDF_BBX ) )
1907 /* Missing BBX field. */
1908 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "BBX" ));
1909 error = BDF_Err_Missing_Bbx_Field;
1913 /* Allocate enough space for the bitmap. */
1914 glyph->bpr = ( glyph->bbx.width * p->font->bpp + 7 ) >> 3;
1916 bitmap_size = glyph->bpr * glyph->bbx.height;
1917 if ( glyph->bpr > 0xFFFFU || bitmap_size > 0xFFFFU )
1919 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG4, lineno ));
1920 error = BDF_Err_Bbx_Too_Big;
1924 glyph->bytes = (unsigned short)bitmap_size;
1926 if ( FT_NEW_ARRAY( glyph->bitmap, glyph->bytes ) )
1930 p->flags |= _BDF_BITMAP;
1935 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG9, lineno ));
1936 error = BDF_Err_Invalid_File_Format;
1940 /* Missing ENCODING field. */
1941 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "ENCODING" ));
1942 error = BDF_Err_Missing_Encoding_Field;
1945 if ( error && ( p->flags & _BDF_GLYPH ) )
1946 FT_FREE( p->glyph_name );
1952 /* Load the font properties. */
1954 _bdf_parse_properties( char* line,
1955 unsigned long linelen,
1956 unsigned long lineno,
1961 _bdf_line_func_t* next;
1966 FT_Error error = BDF_Err_Ok;
1968 FT_UNUSED( lineno );
1971 next = (_bdf_line_func_t *)call_data;
1972 p = (_bdf_parse_t *) client_data;
1974 /* Check for the end of the properties. */
1975 if ( ft_memcmp( line, "ENDPROPERTIES", 13 ) == 0 )
1977 /* If the FONT_ASCENT or FONT_DESCENT properties have not been */
1978 /* encountered yet, then make sure they are added as properties and */
1979 /* make sure they are set from the font bounding box info. */
1981 /* This is *always* done regardless of the options, because X11 */
1982 /* requires these two fields to compile fonts. */
1983 if ( bdf_get_font_property( p->font, "FONT_ASCENT" ) == 0 )
1985 p->font->font_ascent = p->font->bbx.ascent;
1986 ft_sprintf( nbuf, "%hd", p->font->bbx.ascent );
1987 error = _bdf_add_property( p->font, (char *)"FONT_ASCENT",
1992 FT_TRACE2(( "_bdf_parse_properties: " ACMSG1, p->font->bbx.ascent ));
1993 p->font->modified = 1;
1996 if ( bdf_get_font_property( p->font, "FONT_DESCENT" ) == 0 )
1998 p->font->font_descent = p->font->bbx.descent;
1999 ft_sprintf( nbuf, "%hd", p->font->bbx.descent );
2000 error = _bdf_add_property( p->font, (char *)"FONT_DESCENT",
2005 FT_TRACE2(( "_bdf_parse_properties: " ACMSG2, p->font->bbx.descent ));
2006 p->font->modified = 1;
2009 p->flags &= ~_BDF_PROPS;
2010 *next = _bdf_parse_glyphs;
2015 /* Ignore the _XFREE86_GLYPH_RANGES properties. */
2016 if ( ft_memcmp( line, "_XFREE86_GLYPH_RANGES", 21 ) == 0 )
2019 /* Handle COMMENT fields and properties in a special way to preserve */
2021 if ( ft_memcmp( line, "COMMENT", 7 ) == 0 )
2023 name = value = line;
2027 error = _bdf_add_property( p->font, name, value, lineno );
2031 else if ( _bdf_is_atom( line, linelen, &name, &value, p->font ) )
2033 error = _bdf_add_property( p->font, name, value, lineno );
2039 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
2042 name = p->list.field[0];
2044 _bdf_list_shift( &p->list, 1 );
2045 value = _bdf_list_join( &p->list, ' ', &vlen );
2047 error = _bdf_add_property( p->font, name, value, lineno );
2057 /* Load the font header. */
2059 _bdf_parse_start( char* line,
2060 unsigned long linelen,
2061 unsigned long lineno,
2066 _bdf_line_func_t* next;
2071 FT_Memory memory = NULL;
2072 FT_Error error = BDF_Err_Ok;
2074 FT_UNUSED( lineno ); /* only used in debug mode */
2077 next = (_bdf_line_func_t *)call_data;
2078 p = (_bdf_parse_t *) client_data;
2081 memory = p->font->memory;
2083 /* Check for a comment. This is done to handle those fonts that have */
2084 /* comments before the STARTFONT line for some reason. */
2085 if ( ft_memcmp( line, "COMMENT", 7 ) == 0 )
2087 if ( p->opts->keep_comments != 0 && p->font != 0 )
2098 error = _bdf_add_comment( p->font, s, linelen );
2101 /* here font is not defined! */
2107 if ( !( p->flags & _BDF_START ) )
2111 if ( ft_memcmp( line, "STARTFONT", 9 ) != 0 )
2113 /* we don't emit an error message since this code gets */
2114 /* explicitly caught one level higher */
2115 error = BDF_Err_Missing_Startfont_Field;
2119 p->flags = _BDF_START;
2122 if ( FT_NEW( font ) )
2126 font->memory = p->memory;
2131 bdf_property_t* prop;
2134 error = hash_init( &(font->proptbl), memory );
2137 for ( i = 0, prop = (bdf_property_t*)_bdf_properties;
2138 i < _num_bdf_properties; i++, prop++ )
2140 error = hash_insert( prop->name, i,
2141 &(font->proptbl), memory );
2147 if ( FT_ALLOC( p->font->internal, sizeof ( hashtable ) ) )
2149 error = hash_init( (hashtable *)p->font->internal,memory );
2152 p->font->spacing = p->opts->font_spacing;
2153 p->font->default_char = -1;
2158 /* Check for the start of the properties. */
2159 if ( ft_memcmp( line, "STARTPROPERTIES", 15 ) == 0 )
2161 if ( !( p->flags & _BDF_FONT_BBX ) )
2163 /* Missing the FONTBOUNDINGBOX field. */
2164 FT_ERROR(( "_bdf_parse_start: " ERRMSG1, lineno, "FONTBOUNDINGBOX" ));
2165 error = BDF_Err_Missing_Fontboundingbox_Field;
2169 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
2172 /* at this point, `p->font' can't be NULL */
2173 p->cnt = p->font->props_size = _bdf_atoul( p->list.field[1], 0, 10 );
2175 if ( FT_NEW_ARRAY( p->font->props, p->cnt ) )
2177 p->font->props_size = 0;
2181 p->flags |= _BDF_PROPS;
2182 *next = _bdf_parse_properties;
2187 /* Check for the FONTBOUNDINGBOX field. */
2188 if ( ft_memcmp( line, "FONTBOUNDINGBOX", 15 ) == 0 )
2190 if ( !( p->flags & _BDF_SIZE ) )
2192 /* Missing the SIZE field. */
2193 FT_ERROR(( "_bdf_parse_start: " ERRMSG1, lineno, "SIZE" ));
2194 error = BDF_Err_Missing_Size_Field;
2198 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
2202 p->font->bbx.width = _bdf_atos( p->list.field[1], 0, 10 );
2203 p->font->bbx.height = _bdf_atos( p->list.field[2], 0, 10 );
2205 p->font->bbx.x_offset = _bdf_atos( p->list.field[3], 0, 10 );
2206 p->font->bbx.y_offset = _bdf_atos( p->list.field[4], 0, 10 );
2208 p->font->bbx.ascent = (short)( p->font->bbx.height +
2209 p->font->bbx.y_offset );
2211 p->font->bbx.descent = (short)( -p->font->bbx.y_offset );
2213 p->flags |= _BDF_FONT_BBX;
2218 /* The next thing to check for is the FONT field. */
2219 if ( ft_memcmp( line, "FONT", 4 ) == 0 )
2221 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
2224 _bdf_list_shift( &p->list, 1 );
2226 s = _bdf_list_join( &p->list, ' ', &slen );
2230 FT_ERROR(( "_bdf_parse_start: " ERRMSG8, lineno, "FONT" ));
2231 error = BDF_Err_Invalid_File_Format;
2235 /* Allowing multiple `FONT' lines (which is invalid) doesn't hurt... */
2236 FT_FREE( p->font->name );
2238 if ( FT_NEW_ARRAY( p->font->name, slen + 1 ) )
2240 FT_MEM_COPY( p->font->name, s, slen + 1 );
2242 /* If the font name is an XLFD name, set the spacing to the one in */
2243 /* the font name. If there is no spacing fall back on the default. */
2244 error = _bdf_set_default_spacing( p->font, p->opts, lineno );
2248 p->flags |= _BDF_FONT_NAME;
2253 /* Check for the SIZE field. */
2254 if ( ft_memcmp( line, "SIZE", 4 ) == 0 )
2256 if ( !( p->flags & _BDF_FONT_NAME ) )
2258 /* Missing the FONT field. */
2259 FT_ERROR(( "_bdf_parse_start: " ERRMSG1, lineno, "FONT" ));
2260 error = BDF_Err_Missing_Font_Field;
2264 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
2268 p->font->point_size = _bdf_atoul( p->list.field[1], 0, 10 );
2269 p->font->resolution_x = _bdf_atoul( p->list.field[2], 0, 10 );
2270 p->font->resolution_y = _bdf_atoul( p->list.field[3], 0, 10 );
2272 /* Check for the bits per pixel field. */
2273 if ( p->list.used == 5 )
2275 unsigned short bitcount, i, shift;
2278 p->font->bpp = (unsigned short)_bdf_atos( p->list.field[4], 0, 10 );
2280 /* Only values 1, 2, 4, 8 are allowed. */
2281 shift = p->font->bpp;
2283 for ( i = 0; shift > 0; i++ )
2290 shift = (short)( ( bitcount > 3 ) ? 8 : ( 1 << bitcount ) );
2292 if ( p->font->bpp > shift || p->font->bpp != shift )
2294 /* select next higher value */
2295 p->font->bpp = (unsigned short)( shift << 1 );
2296 FT_TRACE2(( "_bdf_parse_start: " ACMSG11, p->font->bpp ));
2302 p->flags |= _BDF_SIZE;
2307 /* Check for the CHARS field -- font properties are optional */
2308 if ( ft_memcmp( line, "CHARS", 5 ) == 0 )
2313 if ( !( p->flags & _BDF_FONT_BBX ) )
2315 /* Missing the FONTBOUNDINGBOX field. */
2316 FT_ERROR(( "_bdf_parse_start: " ERRMSG1, lineno, "FONTBOUNDINGBOX" ));
2317 error = BDF_Err_Missing_Fontboundingbox_Field;
2321 /* Add the two standard X11 properties which are required */
2322 /* for compiling fonts. */
2323 p->font->font_ascent = p->font->bbx.ascent;
2324 ft_sprintf( nbuf, "%hd", p->font->bbx.ascent );
2325 error = _bdf_add_property( p->font, (char *)"FONT_ASCENT",
2329 FT_TRACE2(( "_bdf_parse_properties: " ACMSG1, p->font->bbx.ascent ));
2331 p->font->font_descent = p->font->bbx.descent;
2332 ft_sprintf( nbuf, "%hd", p->font->bbx.descent );
2333 error = _bdf_add_property( p->font, (char *)"FONT_DESCENT",
2337 FT_TRACE2(( "_bdf_parse_properties: " ACMSG2, p->font->bbx.descent ));
2339 p->font->modified = 1;
2341 *next = _bdf_parse_glyphs;
2343 /* A special return value. */
2348 FT_ERROR(( "_bdf_parse_start: " ERRMSG9, lineno ));
2349 error = BDF_Err_Invalid_File_Format;
2356 /*************************************************************************/
2360 /*************************************************************************/
2363 FT_LOCAL_DEF( FT_Error )
2364 bdf_load_font( FT_Stream stream,
2365 FT_Memory extmemory,
2366 bdf_options_t* opts,
2369 unsigned long lineno = 0; /* make compiler happy */
2370 _bdf_parse_t *p = NULL;
2372 FT_Memory memory = extmemory;
2373 FT_Error error = BDF_Err_Ok;
2380 p->opts = (bdf_options_t*)( ( opts != 0 ) ? opts : &_bdf_opts );
2382 p->memory = extmemory; /* only during font creation */
2384 _bdf_list_init( &p->list, extmemory );
2386 error = _bdf_readstream( stream, _bdf_parse_start,
2387 (void *)p, &lineno );
2393 /* If the font is not proportional, set the font's monowidth */
2394 /* field to the width of the font bounding box. */
2395 memory = p->font->memory;
2397 if ( p->font->spacing != BDF_PROPORTIONAL )
2398 p->font->monowidth = p->font->bbx.width;
2400 /* If the number of glyphs loaded is not that of the original count, */
2401 /* indicate the difference. */
2402 if ( p->cnt != p->font->glyphs_used + p->font->unencoded_used )
2404 FT_TRACE2(( "bdf_load_font: " ACMSG15, p->cnt,
2405 p->font->glyphs_used + p->font->unencoded_used ));
2406 p->font->modified = 1;
2409 /* Once the font has been loaded, adjust the overall font metrics if */
2411 if ( p->opts->correct_metrics != 0 &&
2412 ( p->font->glyphs_used > 0 || p->font->unencoded_used > 0 ) )
2414 if ( p->maxrb - p->minlb != p->font->bbx.width )
2416 FT_TRACE2(( "bdf_load_font: " ACMSG3,
2417 p->font->bbx.width, p->maxrb - p->minlb ));
2418 p->font->bbx.width = (unsigned short)( p->maxrb - p->minlb );
2419 p->font->modified = 1;
2422 if ( p->font->bbx.x_offset != p->minlb )
2424 FT_TRACE2(( "bdf_load_font: " ACMSG4,
2425 p->font->bbx.x_offset, p->minlb ));
2426 p->font->bbx.x_offset = p->minlb;
2427 p->font->modified = 1;
2430 if ( p->font->bbx.ascent != p->maxas )
2432 FT_TRACE2(( "bdf_load_font: " ACMSG5,
2433 p->font->bbx.ascent, p->maxas ));
2434 p->font->bbx.ascent = p->maxas;
2435 p->font->modified = 1;
2438 if ( p->font->bbx.descent != p->maxds )
2440 FT_TRACE2(( "bdf_load_font: " ACMSG6,
2441 p->font->bbx.descent, p->maxds ));
2442 p->font->bbx.descent = p->maxds;
2443 p->font->bbx.y_offset = (short)( -p->maxds );
2444 p->font->modified = 1;
2447 if ( p->maxas + p->maxds != p->font->bbx.height )
2449 FT_TRACE2(( "bdf_load_font: " ACMSG7,
2450 p->font->bbx.height, p->maxas + p->maxds ));
2451 p->font->bbx.height = (unsigned short)( p->maxas + p->maxds );
2454 if ( p->flags & _BDF_SWIDTH_ADJ )
2455 FT_TRACE2(( "bdf_load_font: " ACMSG8 ));
2459 if ( p->flags & _BDF_START )
2461 /* The ENDFONT field was never reached or did not exist. */
2462 if ( !( p->flags & _BDF_GLYPHS ) )
2464 /* Error happened while parsing header. */
2465 FT_ERROR(( "bdf_load_font: " ERRMSG2, lineno ));
2466 error = BDF_Err_Corrupted_Font_Header;
2471 /* Error happened when parsing glyphs. */
2472 FT_ERROR(( "bdf_load_font: " ERRMSG3, lineno ));
2473 error = BDF_Err_Corrupted_Font_Glyphs;
2480 /* Make sure the comments are NULL terminated if they exist. */
2481 memory = p->font->memory;
2483 if ( p->font->comments_len > 0 )
2485 if ( FT_RENEW_ARRAY( p->font->comments,
2486 p->font->comments_len,
2487 p->font->comments_len + 1 ) )
2490 p->font->comments[p->font->comments_len] = 0;
2493 else if ( error == BDF_Err_Ok )
2494 error = BDF_Err_Invalid_File_Format;
2501 _bdf_list_done( &p->list );
2511 bdf_free_font( p->font );
2521 FT_LOCAL_DEF( void )
2522 bdf_free_font( bdf_font_t* font )
2524 bdf_property_t* prop;
2526 bdf_glyph_t* glyphs;
2533 memory = font->memory;
2535 FT_FREE( font->name );
2537 /* Free up the internal hash table of property names. */
2538 if ( font->internal )
2540 hash_free( (hashtable *)font->internal, memory );
2541 FT_FREE( font->internal );
2544 /* Free up the comment info. */
2545 FT_FREE( font->comments );
2547 /* Free up the properties. */
2548 for ( i = 0; i < font->props_size; i++ )
2550 if ( font->props[i].format == BDF_ATOM )
2551 FT_FREE( font->props[i].value.atom );
2554 FT_FREE( font->props );
2556 /* Free up the character info. */
2557 for ( i = 0, glyphs = font->glyphs;
2558 i < font->glyphs_used; i++, glyphs++ )
2560 FT_FREE( glyphs->name );
2561 FT_FREE( glyphs->bitmap );
2564 for ( i = 0, glyphs = font->unencoded; i < font->unencoded_used;
2567 FT_FREE( glyphs->name );
2568 FT_FREE( glyphs->bitmap );
2571 FT_FREE( font->glyphs );
2572 FT_FREE( font->unencoded );
2574 /* Free up the overflow storage if it was used. */
2575 for ( i = 0, glyphs = font->overflow.glyphs;
2576 i < font->overflow.glyphs_used; i++, glyphs++ )
2578 FT_FREE( glyphs->name );
2579 FT_FREE( glyphs->bitmap );
2582 FT_FREE( font->overflow.glyphs );
2585 hash_free( &(font->proptbl), memory );
2587 /* Free up the user defined properties. */
2588 for ( prop = font->user_props, i = 0;
2589 i < font->nuser_props; i++, prop++ )
2591 FT_FREE( prop->name );
2592 if ( prop->format == BDF_ATOM )
2593 FT_FREE( prop->value.atom );
2596 FT_FREE( font->user_props );
2598 /* FREE( font ); */ /* XXX Fixme */
2602 FT_LOCAL_DEF( bdf_property_t * )
2603 bdf_get_font_property( bdf_font_t* font,
2609 if ( font == 0 || font->props_size == 0 || name == 0 || *name == 0 )
2612 hn = hash_lookup( name, (hashtable *)font->internal );
2614 return hn ? ( font->props + hn->data ) : 0;