2 * Copyright 2000 Computing Research Labs, New Mexico State University
3 * Copyright 2001, 2002 Francesco Zappa Nardelli
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the "Software"),
7 * to deal in the Software without restriction, including without limitation
8 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 * and/or sell copies of the Software, and to permit persons to whom the
10 * Software is furnished to do so, subject to the following conditions:
12 * The above copyright notice and this permission notice shall be included in
13 * all copies or substantial portions of the Software.
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE COMPUTING RESEARCH LAB OR NEW MEXICO STATE UNIVERSITY BE LIABLE FOR ANY
19 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT
20 * OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
21 * THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24 /*************************************************************************/
26 /* This file is based on bdf.c,v 1.22 2000/03/16 20:08:50 */
28 /* taken from Mark Leisher's xmbdfed package */
30 /*************************************************************************/
35 #include FT_FREETYPE_H
36 #include FT_INTERNAL_DEBUG_H
37 #include FT_INTERNAL_STREAM_H
38 #include FT_INTERNAL_OBJECTS_H
44 /*************************************************************************/
46 /* The macro FT_COMPONENT is used in trace mode. It is an implicit */
47 /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
48 /* messages during execution. */
51 #define FT_COMPONENT trace_bdflib
54 /*************************************************************************/
56 /* Default BDF font options. */
58 /*************************************************************************/
61 static const bdf_options_t _bdf_opts =
63 1, /* Correct metrics. */
64 1, /* Preserve unencoded glyphs. */
65 0, /* Preserve comments. */
66 BDF_PROPORTIONAL /* Default spacing. */
70 /*************************************************************************/
72 /* Builtin BDF font properties. */
74 /*************************************************************************/
76 /* List of most properties that might appear in a font. Doesn't include */
77 /* the RAW_* and AXIS_* properties in X11R6 polymorphic fonts. */
79 static const bdf_property_t _bdf_properties[] =
81 { (char *)"ADD_STYLE_NAME", BDF_ATOM, 1, { 0 } },
82 { (char *)"AVERAGE_WIDTH", BDF_INTEGER, 1, { 0 } },
83 { (char *)"AVG_CAPITAL_WIDTH", BDF_INTEGER, 1, { 0 } },
84 { (char *)"AVG_LOWERCASE_WIDTH", BDF_INTEGER, 1, { 0 } },
85 { (char *)"CAP_HEIGHT", BDF_INTEGER, 1, { 0 } },
86 { (char *)"CHARSET_COLLECTIONS", BDF_ATOM, 1, { 0 } },
87 { (char *)"CHARSET_ENCODING", BDF_ATOM, 1, { 0 } },
88 { (char *)"CHARSET_REGISTRY", BDF_ATOM, 1, { 0 } },
89 { (char *)"COMMENT", BDF_ATOM, 1, { 0 } },
90 { (char *)"COPYRIGHT", BDF_ATOM, 1, { 0 } },
91 { (char *)"DEFAULT_CHAR", BDF_CARDINAL, 1, { 0 } },
92 { (char *)"DESTINATION", BDF_CARDINAL, 1, { 0 } },
93 { (char *)"DEVICE_FONT_NAME", BDF_ATOM, 1, { 0 } },
94 { (char *)"END_SPACE", BDF_INTEGER, 1, { 0 } },
95 { (char *)"FACE_NAME", BDF_ATOM, 1, { 0 } },
96 { (char *)"FAMILY_NAME", BDF_ATOM, 1, { 0 } },
97 { (char *)"FIGURE_WIDTH", BDF_INTEGER, 1, { 0 } },
98 { (char *)"FONT", BDF_ATOM, 1, { 0 } },
99 { (char *)"FONTNAME_REGISTRY", BDF_ATOM, 1, { 0 } },
100 { (char *)"FONT_ASCENT", BDF_INTEGER, 1, { 0 } },
101 { (char *)"FONT_DESCENT", BDF_INTEGER, 1, { 0 } },
102 { (char *)"FOUNDRY", BDF_ATOM, 1, { 0 } },
103 { (char *)"FULL_NAME", BDF_ATOM, 1, { 0 } },
104 { (char *)"ITALIC_ANGLE", BDF_INTEGER, 1, { 0 } },
105 { (char *)"MAX_SPACE", BDF_INTEGER, 1, { 0 } },
106 { (char *)"MIN_SPACE", BDF_INTEGER, 1, { 0 } },
107 { (char *)"NORM_SPACE", BDF_INTEGER, 1, { 0 } },
108 { (char *)"NOTICE", BDF_ATOM, 1, { 0 } },
109 { (char *)"PIXEL_SIZE", BDF_INTEGER, 1, { 0 } },
110 { (char *)"POINT_SIZE", BDF_INTEGER, 1, { 0 } },
111 { (char *)"QUAD_WIDTH", BDF_INTEGER, 1, { 0 } },
112 { (char *)"RAW_ASCENT", BDF_INTEGER, 1, { 0 } },
113 { (char *)"RAW_AVERAGE_WIDTH", BDF_INTEGER, 1, { 0 } },
114 { (char *)"RAW_AVG_CAPITAL_WIDTH", BDF_INTEGER, 1, { 0 } },
115 { (char *)"RAW_AVG_LOWERCASE_WIDTH", BDF_INTEGER, 1, { 0 } },
116 { (char *)"RAW_CAP_HEIGHT", BDF_INTEGER, 1, { 0 } },
117 { (char *)"RAW_DESCENT", BDF_INTEGER, 1, { 0 } },
118 { (char *)"RAW_END_SPACE", BDF_INTEGER, 1, { 0 } },
119 { (char *)"RAW_FIGURE_WIDTH", BDF_INTEGER, 1, { 0 } },
120 { (char *)"RAW_MAX_SPACE", BDF_INTEGER, 1, { 0 } },
121 { (char *)"RAW_MIN_SPACE", BDF_INTEGER, 1, { 0 } },
122 { (char *)"RAW_NORM_SPACE", BDF_INTEGER, 1, { 0 } },
123 { (char *)"RAW_PIXEL_SIZE", BDF_INTEGER, 1, { 0 } },
124 { (char *)"RAW_POINT_SIZE", BDF_INTEGER, 1, { 0 } },
125 { (char *)"RAW_PIXELSIZE", BDF_INTEGER, 1, { 0 } },
126 { (char *)"RAW_POINTSIZE", BDF_INTEGER, 1, { 0 } },
127 { (char *)"RAW_QUAD_WIDTH", BDF_INTEGER, 1, { 0 } },
128 { (char *)"RAW_SMALL_CAP_SIZE", BDF_INTEGER, 1, { 0 } },
129 { (char *)"RAW_STRIKEOUT_ASCENT", BDF_INTEGER, 1, { 0 } },
130 { (char *)"RAW_STRIKEOUT_DESCENT", BDF_INTEGER, 1, { 0 } },
131 { (char *)"RAW_SUBSCRIPT_SIZE", BDF_INTEGER, 1, { 0 } },
132 { (char *)"RAW_SUBSCRIPT_X", BDF_INTEGER, 1, { 0 } },
133 { (char *)"RAW_SUBSCRIPT_Y", BDF_INTEGER, 1, { 0 } },
134 { (char *)"RAW_SUPERSCRIPT_SIZE", BDF_INTEGER, 1, { 0 } },
135 { (char *)"RAW_SUPERSCRIPT_X", BDF_INTEGER, 1, { 0 } },
136 { (char *)"RAW_SUPERSCRIPT_Y", BDF_INTEGER, 1, { 0 } },
137 { (char *)"RAW_UNDERLINE_POSITION", BDF_INTEGER, 1, { 0 } },
138 { (char *)"RAW_UNDERLINE_THICKNESS", BDF_INTEGER, 1, { 0 } },
139 { (char *)"RAW_X_HEIGHT", BDF_INTEGER, 1, { 0 } },
140 { (char *)"RELATIVE_SETWIDTH", BDF_CARDINAL, 1, { 0 } },
141 { (char *)"RELATIVE_WEIGHT", BDF_CARDINAL, 1, { 0 } },
142 { (char *)"RESOLUTION", BDF_INTEGER, 1, { 0 } },
143 { (char *)"RESOLUTION_X", BDF_CARDINAL, 1, { 0 } },
144 { (char *)"RESOLUTION_Y", BDF_CARDINAL, 1, { 0 } },
145 { (char *)"SETWIDTH_NAME", BDF_ATOM, 1, { 0 } },
146 { (char *)"SLANT", BDF_ATOM, 1, { 0 } },
147 { (char *)"SMALL_CAP_SIZE", BDF_INTEGER, 1, { 0 } },
148 { (char *)"SPACING", BDF_ATOM, 1, { 0 } },
149 { (char *)"STRIKEOUT_ASCENT", BDF_INTEGER, 1, { 0 } },
150 { (char *)"STRIKEOUT_DESCENT", BDF_INTEGER, 1, { 0 } },
151 { (char *)"SUBSCRIPT_SIZE", BDF_INTEGER, 1, { 0 } },
152 { (char *)"SUBSCRIPT_X", BDF_INTEGER, 1, { 0 } },
153 { (char *)"SUBSCRIPT_Y", BDF_INTEGER, 1, { 0 } },
154 { (char *)"SUPERSCRIPT_SIZE", BDF_INTEGER, 1, { 0 } },
155 { (char *)"SUPERSCRIPT_X", BDF_INTEGER, 1, { 0 } },
156 { (char *)"SUPERSCRIPT_Y", BDF_INTEGER, 1, { 0 } },
157 { (char *)"UNDERLINE_POSITION", BDF_INTEGER, 1, { 0 } },
158 { (char *)"UNDERLINE_THICKNESS", BDF_INTEGER, 1, { 0 } },
159 { (char *)"WEIGHT", BDF_CARDINAL, 1, { 0 } },
160 { (char *)"WEIGHT_NAME", BDF_ATOM, 1, { 0 } },
161 { (char *)"X_HEIGHT", BDF_INTEGER, 1, { 0 } },
162 { (char *)"_MULE_BASELINE_OFFSET", BDF_INTEGER, 1, { 0 } },
163 { (char *)"_MULE_RELATIVE_COMPOSE", BDF_INTEGER, 1, { 0 } },
167 _num_bdf_properties = sizeof ( _bdf_properties ) /
168 sizeof ( _bdf_properties[0] );
171 /*************************************************************************/
173 /* Hash table utilities for the properties. */
175 /*************************************************************************/
177 /* XXX: Replace this with FreeType's hash functions */
180 #define INITIAL_HT_SIZE 241
183 (*hash_free_func)( hashnode node );
186 hash_bucket( char* key,
190 unsigned long res = 0;
191 hashnode* bp = ht->table, *ndp;
194 /* Mocklisp hash function. */
196 res = ( res << 5 ) - res + *kp++;
198 ndp = bp + ( res % ht->size );
202 if ( kp[0] == key[0] && ft_strcmp( kp, key ) == 0 )
206 ndp = bp + ( ht->size - 1 );
214 hash_rehash( hashtable* ht,
217 hashnode* obp = ht->table, *bp, *nbp;
218 int i, sz = ht->size;
219 FT_Error error = BDF_Err_Ok;
223 ht->limit = ht->size / 3;
225 if ( FT_NEW_ARRAY( ht->table, ht->size ) )
227 FT_MEM_ZERO( ht->table, sizeof ( hashnode ) * ht->size );
229 for ( i = 0, bp = obp; i < sz; i++, bp++ )
233 nbp = hash_bucket( (*bp)->key, ht );
245 hash_init( hashtable* ht,
248 int sz = INITIAL_HT_SIZE;
249 FT_Error error = BDF_Err_Ok;
256 if ( FT_NEW_ARRAY( ht->table, sz ) )
258 FT_MEM_ZERO( ht->table, sizeof ( hashnode ) * sz );
266 hash_free( hashtable* ht,
271 int i, sz = ht->size;
272 hashnode* bp = ht->table;
275 for ( i = 0; i < sz; i++, bp++ )
278 FT_FREE( ht->table );
284 hash_insert( char* key,
289 hashnode nn, *bp = hash_bucket( key, ht );
290 FT_Error error = BDF_Err_Ok;
303 if ( ht->used >= ht->limit )
305 error = hash_rehash( ht, memory );
320 hash_lookup( char* key,
323 hashnode *np = hash_bucket( key, ht );
330 /*************************************************************************/
332 /* Utility types and functions. */
334 /*************************************************************************/
337 /* Function type for parsing lines of a BDF font. */
340 (*_bdf_line_func_t)( char* line,
341 unsigned long linelen,
342 unsigned long lineno,
347 /* List structure for splitting lines into fields. */
349 typedef struct _bdf_list_t_
358 /* Structure used while loading BDF fonts. */
360 typedef struct _bdf_parse_t_
380 unsigned long have[2048];
388 #define setsbit( m, cc ) ( m[(cc) >> 3] |= (FT_Byte)( 1 << ( (cc) & 7 ) ) )
389 #define sbitset( m, cc ) ( m[(cc) >> 3] & ( 1 << ( (cc) & 7 ) ) )
392 /* An empty string for empty fields. */
394 static char empty[1] = { 0 }; /* XXX eliminate this */
397 /* Assume the line is NULL-terminated and that the `list' parameter */
398 /* was initialized the first time it was used. */
401 _bdf_split( char* separators,
403 unsigned long linelen,
407 int mult, final_empty;
410 FT_Error error = BDF_Err_Ok;
413 /* Initialize the list. */
416 /* If the line is empty, then simply return. */
417 if ( linelen == 0 || line[0] == 0 )
420 /* In the original code, if the `separators' parameter is NULL or */
421 /* empty, the list is split into individual bytes. We don't need */
422 /* this, so an error is signaled. */
423 if ( separators == 0 || *separators == 0 )
425 error = BDF_Err_Invalid_Argument;
429 /* Prepare the separator bitmap. */
430 FT_MEM_ZERO( seps, 32 );
432 /* If the very last character of the separator string is a plus, then */
433 /* set the `mult' flag to indicate that multiple separators should be */
434 /* collapsed into one. */
435 for ( mult = 0, sp = separators; sp && *sp; sp++ )
437 if ( *sp == '+' && *( sp + 1 ) == 0 )
440 setsbit( seps, *sp );
443 /* Break the line up into fields. */
444 for ( final_empty = 0, sp = ep = line, end = sp + linelen;
447 /* Collect everything that is not a separator. */
448 for ( ; *ep && !sbitset( seps, *ep ); ep++ )
451 /* Resize the list if necessary. */
452 if ( list->used == list->size )
454 if ( list->size == 0 )
456 if ( FT_NEW_ARRAY( list->field, 5 ) )
461 if ( FT_RENEW_ARRAY ( list->field ,
470 /* Assign the field appropriately. */
471 list->field[list->used++] = ( ep > sp ) ? sp : empty;
477 /* If multiple separators should be collapsed, do it now by */
478 /* setting all the separator characters to 0. */
479 for ( ; *ep && sbitset( seps, *ep ); ep++ )
483 /* Don't collapse multiple separators by making them 0, so just */
484 /* make the one encountered 0. */
487 final_empty = ( ep > sp && *ep == 0 );
491 /* Finally, NULL-terminate the list. */
492 if ( list->used + final_empty + 1 >= list->size )
494 if ( list->used == list->size )
496 if ( list->size == 0 )
498 if ( FT_NEW_ARRAY( list->field, 5 ) )
503 if ( FT_RENEW_ARRAY( list->field,
514 list->field[list->used++] = empty;
516 if ( list->used == list->size )
518 if ( list->size == 0 )
520 if ( FT_NEW_ARRAY( list->field, 5 ) )
525 if ( FT_RENEW_ARRAY( list->field,
534 list->field[list->used] = 0;
542 _bdf_shift( unsigned long n,
548 if ( list == 0 || list->used == 0 || n == 0 )
551 if ( n >= list->used )
557 for ( u = n, i = 0; u < list->used; i++, u++ )
558 list->field[i] = list->field[u];
572 if ( list == 0 || list->used == 0 )
578 for ( i = j = 0; i < list->used; i++ )
584 if ( i + 1 < list->used )
594 /* High speed file reader that passes each line to a callback. */
596 bdf_internal_readstream( FT_Stream stream,
602 unsigned long pos = stream->pos;
603 FT_Error error = BDF_Err_Ok;
606 if ( pos > stream->size )
608 FT_ERROR(( "bdf_internal_readstream:" ));
609 FT_ERROR(( " invalid i/o; pos = 0x%lx, size = 0x%lx\n",
610 pos, stream->size ));
611 error = BDF_Err_Invalid_Stream_Operation;
616 rbytes = stream->read( stream, pos,
617 (unsigned char *)buffer, count );
620 rbytes = stream->size - pos;
621 if ( rbytes > count )
624 FT_MEM_COPY( buffer, stream->base + pos, rbytes );
627 stream->pos = pos + rbytes;
629 *read_bytes = rbytes;
637 _bdf_readstream( FT_Stream stream,
638 _bdf_line_func_t callback,
643 unsigned long lineno;
644 int n, res, done, refill, bytes, hold;
645 char *ls, *le, *pp, *pe, *hp;
647 FT_Memory memory = stream->memory;
648 FT_Error error = BDF_Err_Ok;
653 error = BDF_Err_Invalid_Argument;
657 if ( FT_NEW_ARRAY( buf, 65536L ) )
671 error = bdf_internal_readstream( stream, pp, bytes, &n );
678 /* Determine the new end of the buffer pages. */
681 for ( refill = 0; done == 0 && refill == 0; )
683 while ( le < pe && *le != '\n' && *le != '\r' )
688 /* Hit the end of the last page in the buffer. Need to find */
689 /* out how many pages to shift and how many pages need to be */
690 /* read in. Adjust the line start and end pointers down to */
691 /* point to the right places in the pages. */
693 pp = buf + ( ( ( ls - buf ) >> 13 ) << 13 );
699 FT_MEM_COPY( buf, pp, n );
707 /* Temporarily NULL-terminate the line. */
712 /* XXX: Use encoding independent value for 0x1a */
713 if ( *ls != '#' && *ls != 0x1a &&
715 ( error = (*cb)( ls, le - ls, lineno, (void *)&cb,
716 client_data ) ) != BDF_Err_Ok )
721 /* Handle the case of DOS crlf sequences. */
722 if ( le < pe && hold == '\n' && *le =='\r' )
726 /* Increment the line number. */
729 /* Restore the character at the end of the line. */
743 /* XXX: make this work with EBCDIC also */
745 static const unsigned char a2i[128] =
747 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
748 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
749 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
750 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
751 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x00, 0x00,
752 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00,
753 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
754 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
755 0x00, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00,
756 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
757 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
760 static const unsigned char odigits[32] =
762 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00,
763 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
764 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
765 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
768 static const unsigned char ddigits[32] =
770 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x03,
771 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
772 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
773 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
776 static const unsigned char hdigits[32] =
778 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x03,
779 0x7e, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00,
780 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
781 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
785 #define isdigok( m, d ) (m[(d) >> 3] & ( 1 << ( (d) & 7 ) ) )
788 /* Routine to convert an ASCII string into an unsigned long integer. */
795 const unsigned char* dmap;
798 if ( s == 0 || *s == 0 )
801 /* Make sure the radix is something recognizable. Default to 10. */
816 /* Check for the special hex prefix. */
818 ( *( s + 1 ) == 'x' || *( s + 1 ) == 'X' ) )
825 for ( v = 0; isdigok( dmap, *s ); s++ )
826 v = v * base + a2i[(int)*s];
835 /* Routine to convert an ASCII string into an signed long integer. */
842 const unsigned char* dmap;
845 if ( s == 0 || *s == 0 )
848 /* Make sure the radix is something recognizable. Default to 10. */
863 /* Check for a minus sign. */
871 /* Check for the special hex prefix. */
873 ( *( s + 1 ) == 'x' || *( s + 1 ) == 'X' ) )
880 for ( v = 0; isdigok( dmap, *s ); s++ )
881 v = v * base + a2i[(int)*s];
886 return ( !neg ) ? v : -v;
890 /* Routine to convert an ASCII string into an signed short integer. */
897 const unsigned char* dmap;
900 if ( s == 0 || *s == 0 )
903 /* Make sure the radix is something recognizable. Default to 10. */
918 /* Check for a minus. */
926 /* Check for the special hex prefix. */
928 ( *( s + 1 ) == 'x' || *( s + 1 ) == 'X' ) )
935 for ( v = 0; isdigok( dmap, *s ); s++ )
936 v = (short)( v * base + a2i[(int)*s] );
941 return (short)( ( !neg ) ? v : -v );
945 /* Routine to compare two glyphs by encoding so they can be sorted. */
947 by_encoding( const void* a,
950 bdf_glyph_t *c1, *c2;
953 c1 = (bdf_glyph_t *)a;
954 c2 = (bdf_glyph_t *)b;
956 if ( c1->encoding < c2->encoding )
958 else if ( c1->encoding > c2->encoding )
966 bdf_create_property( char* name,
972 FT_Memory memory = font->memory;
973 FT_Error error = BDF_Err_Ok;
976 /* First check to see if the property has */
977 /* already been added or not. If it has, then */
978 /* simply ignore it. */
979 if ( hash_lookup( name, &(font->proptbl) ) )
982 if ( font->nuser_props == 0 )
984 if ( FT_NEW_ARRAY( font->user_props, 1 ) )
989 if ( FT_RENEW_ARRAY( font->user_props,
991 font->nuser_props + 1 ) )
995 p = font->user_props + font->nuser_props;
996 FT_MEM_ZERO( p, sizeof ( bdf_property_t ) );
998 n = (unsigned long)( ft_strlen( name ) + 1 );
999 if ( FT_NEW_ARRAY( p->name, n ) )
1002 FT_MEM_COPY( (char *)p->name, name, n );
1007 n = _num_bdf_properties + font->nuser_props;
1009 error = hash_insert( p->name, (void *)n, &(font->proptbl), memory );
1013 font->nuser_props++;
1020 FT_LOCAL_DEF( bdf_property_t * )
1021 bdf_get_property( char* name,
1025 unsigned long propid;
1028 if ( name == 0 || *name == 0 )
1031 if ( ( hn = hash_lookup( name, &(font->proptbl) ) ) == 0 )
1034 propid = (unsigned long)hn->data;
1035 if ( propid >= _num_bdf_properties )
1036 return font->user_props + ( propid - _num_bdf_properties );
1038 return (bdf_property_t*)_bdf_properties + propid;
1042 /*************************************************************************/
1044 /* BDF font file parsing flags and functions. */
1046 /*************************************************************************/
1051 #define _BDF_START 0x0001
1052 #define _BDF_FONT_NAME 0x0002
1053 #define _BDF_SIZE 0x0004
1054 #define _BDF_FONT_BBX 0x0008
1055 #define _BDF_PROPS 0x0010
1056 #define _BDF_GLYPHS 0x0020
1057 #define _BDF_GLYPH 0x0040
1058 #define _BDF_ENCODING 0x0080
1059 #define _BDF_SWIDTH 0x0100
1060 #define _BDF_DWIDTH 0x0200
1061 #define _BDF_BBX 0x0400
1062 #define _BDF_BITMAP 0x0800
1064 #define _BDF_SWIDTH_ADJ 0x1000
1066 #define _BDF_GLYPH_BITS ( _BDF_GLYPH | \
1073 #define _BDF_GLYPH_WIDTH_CHECK 0x40000000L
1074 #define _BDF_GLYPH_HEIGHT_CHECK 0x80000000L
1077 /* Auto correction messages. */
1078 #define ACMSG1 "FONT_ASCENT property missing. " \
1079 "Added \"FONT_ASCENT %hd\".\n"
1080 #define ACMSG2 "FONT_DESCENT property missing. " \
1081 "Added \"FONT_DESCENT %hd\".\n"
1082 #define ACMSG3 "Font width != actual width. Old: %hd New: %hd.\n"
1083 #define ACMSG4 "Font left bearing != actual left bearing. " \
1084 "Old: %hd New: %hd.\n"
1085 #define ACMSG5 "Font ascent != actual ascent. Old: %hd New: %hd.\n"
1086 #define ACMSG6 "Font descent != actual descent. Old: %hd New: %hd.\n"
1087 #define ACMSG7 "Font height != actual height. Old: %hd New: %hd.\n"
1088 #define ACMSG8 "Glyph scalable width (SWIDTH) adjustments made.\n"
1089 #define ACMSG9 "SWIDTH field missing at line %ld. Set automatically.\n"
1090 #define ACMSG10 "DWIDTH field missing at line %ld. Set to glyph width.\n"
1091 #define ACMSG11 "SIZE bits per pixel field adjusted to %hd.\n"
1092 #define ACMSG12 "Duplicate encoding %ld (%s) changed to unencoded.\n"
1093 #define ACMSG13 "Glyph %ld extra rows removed.\n"
1094 #define ACMSG14 "Glyph %ld extra columns removed.\n"
1095 #define ACMSG15 "Incorrect glyph count: %ld indicated but %ld found.\n"
1097 /* Error messages. */
1098 #define ERRMSG1 "[line %ld] Missing \"%s\" line.\n"
1099 #define ERRMSG2 "[line %ld] Font header corrupted or missing fields.\n"
1100 #define ERRMSG3 "[line %ld] Font glyphs corrupted or missing fields.\n"
1104 _bdf_add_comment( bdf_font_t* font,
1109 FT_Memory memory = font->memory;
1110 FT_Error error = BDF_Err_Ok;
1113 if ( font->comments_len == 0 )
1115 if ( FT_NEW_ARRAY( font->comments, len + 1 ) )
1120 if ( FT_RENEW_ARRAY( font->comments,
1122 font->comments_len + len + 1 ) )
1126 cp = font->comments + font->comments_len;
1127 FT_MEM_COPY( cp, comment, len );
1130 font->comments_len += len + 1;
1137 /* Set the spacing from the font name if it exists, or set it to the */
1138 /* default specified in the options. */
1140 _bdf_set_default_spacing( bdf_font_t* font,
1141 bdf_options_t* opts )
1147 FT_Error error = BDF_Err_Ok;
1150 if ( font == 0 || font->name == 0 || font->name[0] == 0 )
1152 error = BDF_Err_Invalid_Argument;
1156 memory = font->memory;
1158 font->spacing = opts->font_spacing;
1160 len = (unsigned long)( ft_strlen( font->name ) + 1 );
1161 FT_MEM_COPY( name, font->name, len );
1163 list.size = list.used = 0;
1165 error = _bdf_split( (char *)"-", name, len, &list, memory );
1169 if ( list.used == 15 )
1171 switch ( list.field[11][0] )
1175 font->spacing = BDF_CHARCELL;
1179 font->spacing = BDF_MONOWIDTH;
1183 font->spacing = BDF_PROPORTIONAL;
1188 FT_FREE( list.field );
1195 /* Determine whether the property is an atom or not. If it is, then */
1196 /* clean it up so the double quotes are removed if they exist. */
1198 _bdf_is_atom( char* line,
1199 unsigned long linelen,
1209 *name = sp = ep = line;
1211 while ( *ep && *ep != ' ' && *ep != '\t' )
1221 p = bdf_get_property( sp, font );
1223 /* Restore the character that was saved before any return can happen. */
1227 /* If the property exists and is not an atom, just return here. */
1228 if ( p && p->format != BDF_ATOM )
1231 /* The property is an atom. Trim all leading and trailing whitespace */
1232 /* and double quotes for the atom value. */
1234 ep = line + linelen;
1236 /* Trim the leading whitespace if it exists. */
1239 ( *sp == ' ' || *sp == '\t' ) )
1242 /* Trim the leading double quote if it exists. */
1247 /* Trim the trailing whitespace if it exists. */
1249 ( *( ep - 1 ) == ' ' || *( ep - 1 ) == '\t' ) )
1252 /* Trim the trailing double quote if it exists. */
1253 if ( ep > sp && *( ep - 1 ) == '"' )
1261 _bdf_add_property( bdf_font_t* font,
1265 unsigned long propid;
1268 bdf_property_t *prop, *fp;
1269 FT_Memory memory = font->memory;
1270 FT_Error error = BDF_Err_Ok;
1273 /* First, check to see if the property already exists in the font. */
1274 if ( ( hn = hash_lookup( name, (hashtable *)font->internal ) ) != 0 )
1276 /* The property already exists in the font, so simply replace */
1277 /* the value of the property with the current value. */
1278 fp = font->props + (unsigned long)hn->data;
1280 switch ( fp->format )
1283 /* Delete the current atom if it exists. */
1284 FT_FREE( fp->value.atom );
1289 len = ft_strlen( value ) + 1;
1293 if ( FT_NEW_ARRAY( fp->value.atom, len ) )
1295 FT_MEM_COPY( fp->value.atom, value, len );
1302 fp->value.int32 = _bdf_atol( value, 0, 10 );
1306 fp->value.card32 = _bdf_atoul( value, 0, 10 );
1316 /* See whether this property type exists yet or not. */
1317 /* If not, create it. */
1318 hn = hash_lookup( name, &(font->proptbl) );
1321 error = bdf_create_property( name, BDF_ATOM, font );
1324 hn = hash_lookup( name, &(font->proptbl) );
1327 /* Allocate another property if this is overflow. */
1328 if ( font->props_used == font->props_size )
1330 if ( font->props_size == 0 )
1332 if ( FT_NEW_ARRAY( font->props, 1 ) )
1337 if ( FT_RENEW_ARRAY( font->props,
1339 font->props_size + 1 ) )
1343 fp = font->props + font->props_size;
1344 FT_MEM_ZERO( fp, sizeof ( bdf_property_t ) );
1348 propid = (unsigned long)hn->data;
1349 if ( propid >= _num_bdf_properties )
1350 prop = font->user_props + ( propid - _num_bdf_properties );
1352 prop = (bdf_property_t*)_bdf_properties + propid;
1354 fp = font->props + font->props_used;
1356 fp->name = prop->name;
1357 fp->format = prop->format;
1358 fp->builtin = prop->builtin;
1360 switch ( prop->format )
1366 len = ft_strlen( value ) + 1;
1370 if ( FT_NEW_ARRAY( fp->value.atom, len ) )
1372 FT_MEM_COPY( fp->value.atom, value, len );
1379 fp->value.int32 = _bdf_atol( value, 0, 10 );
1383 fp->value.card32 = _bdf_atoul( value, 0, 10 );
1387 /* If the property happens to be a comment, then it doesn't need */
1388 /* to be added to the internal hash table. */
1389 if ( ft_memcmp( name, "COMMENT", 7 ) != 0 ) {
1390 /* Add the property to the font property table. */
1391 error = hash_insert( fp->name,
1392 (void *)font->props_used,
1393 (hashtable *)font->internal,
1401 /* Some special cases need to be handled here. The DEFAULT_CHAR */
1402 /* property needs to be located if it exists in the property list, the */
1403 /* FONT_ASCENT and FONT_DESCENT need to be assigned if they are */
1404 /* present, and the SPACING property should override the default */
1406 if ( ft_memcmp( name, "DEFAULT_CHAR", 12 ) == 0 )
1407 font->default_glyph = fp->value.int32;
1408 else if ( ft_memcmp( name, "FONT_ASCENT", 11 ) == 0 )
1409 font->font_ascent = fp->value.int32;
1410 else if ( ft_memcmp( name, "FONT_DESCENT", 12 ) == 0 )
1411 font->font_descent = fp->value.int32;
1412 else if ( ft_memcmp( name, "SPACING", 7 ) == 0 )
1414 if ( fp->value.atom[0] == 'p' || fp->value.atom[0] == 'P' )
1415 font->spacing = BDF_PROPORTIONAL;
1416 else if ( fp->value.atom[0] == 'm' || fp->value.atom[0] == 'M' )
1417 font->spacing = BDF_MONOWIDTH;
1418 else if ( fp->value.atom[0] == 'c' || fp->value.atom[0] == 'C' )
1419 font->spacing = BDF_CHARCELL;
1427 static const unsigned char nibble_mask[8] =
1429 0xFF, 0x80, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC, 0xFE
1433 /* Actually parse the glyph info and bitmaps. */
1435 _bdf_parse_glyphs( char* line,
1436 unsigned long linelen,
1437 unsigned long lineno,
1444 unsigned long i, slen, nibbles;
1446 _bdf_line_func_t* next;
1452 FT_Error error = BDF_Err_Ok;
1454 FT_UNUSED( lineno ); /* only used in debug mode */
1457 next = (_bdf_line_func_t *)call_data;
1458 p = (_bdf_parse_t *) client_data;
1461 memory = font->memory;
1463 /* Check for a comment. */
1464 if ( ft_memcmp( line, "COMMENT", 7 ) == 0 )
1474 error = _bdf_add_comment( p->font, s, linelen );
1478 /* The very first thing expected is the number of glyphs. */
1479 if ( !( p->flags & _BDF_GLYPHS ) )
1481 if ( ft_memcmp( line, "CHARS", 5 ) != 0 )
1483 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "CHARS" ));
1484 error = BDF_Err_Missing_Chars_Field;
1488 error = _bdf_split( (char *)" +", line, linelen, &p->list, memory );
1491 p->cnt = font->glyphs_size = _bdf_atoul( p->list.field[1], 0, 10 );
1493 /* Make sure the number of glyphs is non-zero. */
1495 font->glyphs_size = 64;
1497 if ( FT_NEW_ARRAY( font->glyphs, font->glyphs_size ) )
1500 p->flags |= _BDF_GLYPHS;
1505 /* Check for the ENDFONT field. */
1506 if ( ft_memcmp( line, "ENDFONT", 7 ) == 0 )
1508 /* Sort the glyphs by encoding. */
1509 ft_qsort( (char *)font->glyphs,
1511 sizeof ( bdf_glyph_t ),
1514 p->flags &= ~_BDF_START;
1519 /* Check for the ENDCHAR field. */
1520 if ( ft_memcmp( line, "ENDCHAR", 7 ) == 0 )
1523 p->flags &= ~_BDF_GLYPH_BITS;
1528 /* Check to see whether a glyph is being scanned but should be */
1529 /* ignored because it is an unencoded glyph. */
1530 if ( ( p->flags & _BDF_GLYPH ) &&
1531 p->glyph_enc == -1 &&
1532 p->opts->keep_unencoded == 0 )
1535 /* Check for the STARTCHAR field. */
1536 if ( ft_memcmp( line, "STARTCHAR", 9 ) == 0 )
1538 /* Set the character name in the parse info first until the */
1539 /* encoding can be checked for an unencoded character. */
1540 FT_FREE( p->glyph_name );
1542 error = _bdf_split( (char *)" +", line, linelen, &p->list,memory );
1545 _bdf_shift( 1, &p->list );
1547 s = _bdf_join( ' ', &slen, &p->list );
1549 if ( FT_NEW_ARRAY( p->glyph_name, slen + 1 ) )
1551 FT_MEM_COPY( p->glyph_name, s, slen + 1 );
1553 p->flags |= _BDF_GLYPH;
1558 /* Check for the ENCODING field. */
1559 if ( ft_memcmp( line, "ENCODING", 8 ) == 0 )
1561 if ( !( p->flags & _BDF_GLYPH ) )
1563 /* Missing STARTCHAR field. */
1564 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "STARTCHAR" ));
1565 error = BDF_Err_Missing_Startchar_Field;
1569 error = _bdf_split( (char *)" +", line, linelen, &p->list, memory );
1572 p->glyph_enc = _bdf_atol( p->list.field[1], 0, 10 );
1574 /* Check to see whether this encoding has already been encountered. */
1575 /* If it has then change it to unencoded so it gets added if */
1577 if ( p->glyph_enc >= 0 )
1579 if ( _bdf_glyph_modified( p->have, p->glyph_enc ) )
1581 /* Emit a message saying a glyph has been moved to the */
1582 /* unencoded area. */
1583 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG12,
1584 p->glyph_enc, p->glyph_name ));
1589 _bdf_set_glyph_modified( p->have, p->glyph_enc );
1592 if ( p->glyph_enc >= 0 )
1594 /* Make sure there are enough glyphs allocated in case the */
1595 /* number of characters happen to be wrong. */
1596 if ( font->glyphs_used == font->glyphs_size )
1598 if ( FT_RENEW_ARRAY( font->glyphs,
1600 font->glyphs_size + 64 ) )
1602 FT_MEM_ZERO( font->glyphs + font->glyphs_size,
1603 sizeof ( bdf_glyph_t ) * 64 ); /* FZ inutile */
1604 font->glyphs_size += 64;
1607 glyph = font->glyphs + font->glyphs_used++;
1608 glyph->name = p->glyph_name;
1609 glyph->encoding = p->glyph_enc;
1611 /* Reset the initial glyph info. */
1616 /* Unencoded glyph. Check to see whether it should */
1617 /* be added or not. */
1618 if ( p->opts->keep_unencoded != 0 )
1620 /* Allocate the next unencoded glyph. */
1621 if ( font->unencoded_used == font->unencoded_size )
1623 if ( font->unencoded_size == 0 )
1625 if ( FT_NEW_ARRAY( font->unencoded, 4 ) )
1630 if ( FT_RENEW_ARRAY( font->unencoded ,
1631 font->unencoded_size,
1632 font->unencoded_size + 4 ) )
1635 font->unencoded_size += 4;
1638 glyph = font->unencoded + font->unencoded_used;
1639 glyph->name = p->glyph_name;
1640 glyph->encoding = font->unencoded_used++;
1643 /* Free up the glyph name if the unencoded shouldn't be */
1645 FT_FREE( p->glyph_name );
1650 /* Clear the flags that might be added when width and height are */
1651 /* checked for consistency. */
1652 p->flags &= ~( _BDF_GLYPH_WIDTH_CHECK | _BDF_GLYPH_HEIGHT_CHECK );
1654 p->flags |= _BDF_ENCODING;
1659 /* Point at the glyph being constructed. */
1660 if ( p->glyph_enc == -1 )
1661 glyph = font->unencoded + ( font->unencoded_used - 1 );
1663 glyph = font->glyphs + ( font->glyphs_used - 1 );
1665 /* Check to see whether a bitmap is being constructed. */
1666 if ( p->flags & _BDF_BITMAP )
1668 /* If there are more rows than are specified in the glyph metrics, */
1669 /* ignore the remaining lines. */
1670 if ( p->row >= (unsigned long)glyph->bbx.height )
1672 if ( !( p->flags & _BDF_GLYPH_HEIGHT_CHECK ) )
1674 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG13, glyph->encoding ));
1675 p->flags |= _BDF_GLYPH_HEIGHT_CHECK;
1682 /* Only collect the number of nibbles indicated by the glyph */
1683 /* metrics. If there are more columns, they are simply ignored. */
1684 nibbles = glyph->bpr << 1;
1685 bp = glyph->bitmap + p->row * glyph->bpr;
1687 for ( i = 0, *bp = 0; i < nibbles; i++ )
1690 *bp = (FT_Byte)( ( *bp << 4 ) + a2i[c] );
1691 if ( i + 1 < nibbles && ( i & 1 ) )
1695 /* Remove possible garbage at the right. */
1696 mask_index = ( glyph->bbx.width * p->font->bpp ) & 7;
1697 *bp &= nibble_mask[mask_index];
1699 /* If any line has extra columns, indicate they have been removed. */
1700 if ( ( line[nibbles] == '0' || a2i[(int)line[nibbles]] != 0 ) &&
1701 !( p->flags & _BDF_GLYPH_WIDTH_CHECK ) )
1703 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG14, glyph->encoding ));
1704 p->flags |= _BDF_GLYPH_WIDTH_CHECK;
1712 /* Expect the SWIDTH (scalable width) field next. */
1713 if ( ft_memcmp( line, "SWIDTH", 6 ) == 0 )
1715 if ( !( p->flags & _BDF_ENCODING ) )
1717 /* Missing ENCODING field. */
1718 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "ENCODING" ));
1719 error = BDF_Err_Missing_Encoding_Field;
1723 error = _bdf_split( (char *)" +", line, linelen, &p->list, memory );
1726 glyph->swidth = (unsigned short)_bdf_atoul( p->list.field[1], 0, 10 );
1727 p->flags |= _BDF_SWIDTH;
1732 /* Expect the DWIDTH (scalable width) field next. */
1733 if ( ft_memcmp( line, "DWIDTH", 6 ) == 0 )
1735 error = _bdf_split( (char *)" +", line, linelen, &p->list,memory );
1738 glyph->dwidth = (unsigned short)_bdf_atoul( p->list.field[1], 0, 10 );
1740 if ( !( p->flags & _BDF_SWIDTH ) )
1742 /* Missing SWIDTH field. Emit an auto correction message and set */
1743 /* the scalable width from the device width. */
1744 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG9, lineno ));
1746 glyph->swidth = (unsigned short)FT_MulDiv(
1747 glyph->dwidth, 72000L,
1748 (FT_Long)( font->point_size *
1749 font->resolution_x ) );
1752 p->flags |= _BDF_DWIDTH;
1756 /* Expect the BBX field next. */
1757 if ( ft_memcmp( line, "BBX", 3 ) == 0 )
1759 error = _bdf_split( (char *)" +", line, linelen, &p->list, memory );
1763 glyph->bbx.width = _bdf_atos( p->list.field[1], 0, 10 );
1764 glyph->bbx.height = _bdf_atos( p->list.field[2], 0, 10 );
1765 glyph->bbx.x_offset = _bdf_atos( p->list.field[3], 0, 10 );
1766 glyph->bbx.y_offset = _bdf_atos( p->list.field[4], 0, 10 );
1768 /* Generate the ascent and descent of the character. */
1769 glyph->bbx.ascent = (short)( glyph->bbx.height + glyph->bbx.y_offset );
1770 glyph->bbx.descent = (short)( -glyph->bbx.y_offset );
1772 /* Determine the overall font bounding box as the characters are */
1773 /* loaded so corrections can be done later if indicated. */
1774 p->maxas = (short)MAX( glyph->bbx.ascent, p->maxas );
1775 p->maxds = (short)MAX( glyph->bbx.descent, p->maxds );
1777 p->rbearing = (short)( glyph->bbx.width + glyph->bbx.x_offset );
1779 p->maxrb = (short)MAX( p->rbearing, p->maxrb );
1780 p->minlb = (short)MIN( glyph->bbx.x_offset, p->minlb );
1781 p->maxlb = (short)MAX( glyph->bbx.x_offset, p->maxlb );
1783 if ( !( p->flags & _BDF_DWIDTH ) )
1785 /* Missing DWIDTH field. Emit an auto correction message and set */
1786 /* the device width to the glyph width. */
1787 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG10, lineno ));
1788 glyph->dwidth = glyph->bbx.width;
1791 /* If the BDF_CORRECT_METRICS flag is set, then adjust the SWIDTH */
1792 /* value if necessary. */
1793 if ( p->opts->correct_metrics != 0 )
1795 /* Determine the point size of the glyph. */
1796 unsigned short sw = (unsigned short)FT_MulDiv(
1797 glyph->dwidth, 72000L,
1798 (FT_Long)( font->point_size *
1799 font->resolution_x ) );
1802 if ( sw != glyph->swidth )
1806 if ( p->glyph_enc == -1 )
1807 _bdf_set_glyph_modified( font->umod,
1808 font->unencoded_used - 1 );
1810 _bdf_set_glyph_modified( font->nmod, glyph->encoding );
1812 p->flags |= _BDF_SWIDTH_ADJ;
1817 p->flags |= _BDF_BBX;
1821 /* And finally, gather up the bitmap. */
1822 if ( ft_memcmp( line, "BITMAP", 6 ) == 0 )
1824 if ( !( p->flags & _BDF_BBX ) )
1826 /* Missing BBX field. */
1827 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "BBX" ));
1828 error = BDF_Err_Missing_Bbx_Field;
1832 /* Allocate enough space for the bitmap. */
1833 glyph->bpr = ( glyph->bbx.width * p->font->bpp + 7 ) >> 3;
1834 glyph->bytes = (unsigned short)( glyph->bpr * glyph->bbx.height );
1836 if ( FT_NEW_ARRAY( glyph->bitmap, glyph->bytes ) )
1840 p->flags |= _BDF_BITMAP;
1845 error = BDF_Err_Invalid_File_Format;
1852 /* Load the font properties. */
1854 _bdf_parse_properties( char* line,
1855 unsigned long linelen,
1856 unsigned long lineno,
1861 _bdf_line_func_t* next;
1867 FT_Error error = BDF_Err_Ok;
1869 FT_UNUSED( lineno );
1872 next = (_bdf_line_func_t *)call_data;
1873 p = (_bdf_parse_t *) client_data;
1875 memory = p->font->memory;
1877 /* Check for the end of the properties. */
1878 if ( ft_memcmp( line, "ENDPROPERTIES", 13 ) == 0 )
1880 /* If the FONT_ASCENT or FONT_DESCENT properties have not been */
1881 /* encountered yet, then make sure they are added as properties and */
1882 /* make sure they are set from the font bounding box info. */
1884 /* This is *always* done regardless of the options, because X11 */
1885 /* requires these two fields to compile fonts. */
1886 if ( bdf_get_font_property( p->font, (char *)"FONT_ASCENT" ) == 0 )
1888 p->font->font_ascent = p->font->bbx.ascent;
1889 ft_sprintf( nbuf, "%hd", p->font->bbx.ascent );
1890 error = _bdf_add_property( p->font, (char *)"FONT_ASCENT", nbuf );
1894 FT_TRACE2(( "_bdf_parse_properties: " ACMSG1, p->font->bbx.ascent ));
1895 p->font->modified = 1;
1898 if ( bdf_get_font_property( p->font, (char *)"FONT_DESCENT" ) == 0 )
1900 p->font->font_descent = p->font->bbx.descent;
1901 ft_sprintf( nbuf, "%hd", p->font->bbx.descent );
1902 error = _bdf_add_property( p->font, (char *)"FONT_DESCENT", nbuf );
1906 FT_TRACE2(( "_bdf_parse_properties: " ACMSG2, p->font->bbx.descent ));
1907 p->font->modified = 1;
1910 p->flags &= ~_BDF_PROPS;
1911 *next = _bdf_parse_glyphs;
1916 /* Ignore the _XFREE86_GLYPH_RANGES properties. */
1917 if ( ft_memcmp( line, "_XFREE86_GLYPH_RANGES", 21 ) == 0 )
1920 /* Handle COMMENT fields and properties in a special way to preserve */
1922 if ( ft_memcmp( line, "COMMENT", 7 ) == 0 )
1924 name = value = line;
1928 error = _bdf_add_property( p->font, name, value );
1932 else if ( _bdf_is_atom( line, linelen, &name, &value, p->font ) )
1934 error = _bdf_add_property( p->font, name, value );
1940 error = _bdf_split( (char *)" +", line, linelen, &p->list, memory );
1943 name = p->list.field[0];
1945 _bdf_shift( 1, &p->list );
1946 value = _bdf_join( ' ', &vlen, &p->list );
1948 error = _bdf_add_property( p->font, name, value );
1958 /* Load the font header. */
1960 _bdf_parse_start( char* line,
1961 unsigned long linelen,
1962 unsigned long lineno,
1967 _bdf_line_func_t* next;
1972 FT_Memory memory = NULL;
1973 FT_Error error = BDF_Err_Ok;
1975 FT_UNUSED( lineno ); /* only used in debug mode */
1978 next = (_bdf_line_func_t *)call_data;
1979 p = (_bdf_parse_t *) client_data;
1982 memory = p->font->memory;
1984 /* Check for a comment. This is done to handle those fonts that have */
1985 /* comments before the STARTFONT line for some reason. */
1986 if ( ft_memcmp( line, "COMMENT", 7 ) == 0 )
1988 if ( p->opts->keep_comments != 0 && p->font != 0 )
1999 error = _bdf_add_comment( p->font, s, linelen );
2002 /* here font is not defined! */
2008 if ( !( p->flags & _BDF_START ) )
2012 if ( ft_memcmp( line, "STARTFONT", 9 ) != 0 )
2014 /* No STARTFONT field is a good indication of a problem. */
2015 error = BDF_Err_Missing_Startfont_Field;
2019 p->flags = _BDF_START;
2022 if ( FT_NEW( font ) )
2026 font->memory = p->memory;
2031 bdf_property_t* prop;
2034 error = hash_init( &(font->proptbl), memory );
2037 for ( i = 0, prop = (bdf_property_t*)_bdf_properties;
2038 i < _num_bdf_properties; i++, prop++ )
2040 error = hash_insert( prop->name, (void *)i,
2041 &(font->proptbl), memory );
2047 if ( FT_ALLOC( p->font->internal, sizeof ( hashtable ) ) )
2049 error = hash_init( (hashtable *)p->font->internal,memory );
2052 p->font->spacing = p->opts->font_spacing;
2053 p->font->default_glyph = -1;
2058 /* Check for the start of the properties. */
2059 if ( ft_memcmp( line, "STARTPROPERTIES", 15 ) == 0 )
2061 error = _bdf_split( (char *)" +", line, linelen, &p->list, memory );
2064 p->cnt = p->font->props_size = _bdf_atoul( p->list.field[1], 0, 10 );
2066 if ( FT_NEW_ARRAY( p->font->props, p->cnt ) )
2069 p->flags |= _BDF_PROPS;
2070 *next = _bdf_parse_properties;
2075 /* Check for the FONTBOUNDINGBOX field. */
2076 if ( ft_memcmp( line, "FONTBOUNDINGBOX", 15 ) == 0 )
2078 if ( !(p->flags & _BDF_SIZE ) )
2080 /* Missing the SIZE field. */
2081 FT_ERROR(( "_bdf_parse_start: " ERRMSG1, lineno, "SIZE" ));
2082 error = BDF_Err_Missing_Size_Field;
2086 error = _bdf_split( (char *)" +", line, linelen, &p->list , memory );
2090 p->font->bbx.width = _bdf_atos( p->list.field[1], 0, 10 );
2091 p->font->bbx.height = _bdf_atos( p->list.field[2], 0, 10 );
2093 p->font->bbx.x_offset = _bdf_atos( p->list.field[3], 0, 10 );
2094 p->font->bbx.y_offset = _bdf_atos( p->list.field[4], 0, 10 );
2096 p->font->bbx.ascent = (short)( p->font->bbx.height +
2097 p->font->bbx.y_offset );
2099 p->font->bbx.descent = (short)( -p->font->bbx.y_offset );
2101 p->flags |= _BDF_FONT_BBX;
2106 /* The next thing to check for is the FONT field. */
2107 if ( ft_memcmp( line, "FONT", 4 ) == 0 )
2109 error = _bdf_split( (char *)" +", line, linelen, &p->list , memory );
2112 _bdf_shift( 1, &p->list );
2114 s = _bdf_join( ' ', &slen, &p->list );
2115 if ( FT_NEW_ARRAY( p->font->name, slen + 1 ) )
2117 FT_MEM_COPY( p->font->name, s, slen + 1 );
2119 /* If the font name is an XLFD name, set the spacing to the one in */
2120 /* the font name. If there is no spacing fall back on the default. */
2121 error = _bdf_set_default_spacing( p->font, p->opts );
2125 p->flags |= _BDF_FONT_NAME;
2130 /* Check for the SIZE field. */
2131 if ( ft_memcmp( line, "SIZE", 4 ) == 0 )
2133 if ( !( p->flags & _BDF_FONT_NAME ) )
2135 /* Missing the FONT field. */
2136 FT_ERROR(( "_bdf_parse_start: " ERRMSG1, lineno, "FONT" ));
2137 error = BDF_Err_Missing_Font_Field;
2141 error = _bdf_split( (char *)" +", line, linelen, &p->list, memory );
2145 p->font->point_size = _bdf_atoul( p->list.field[1], 0, 10 );
2146 p->font->resolution_x = _bdf_atoul( p->list.field[2], 0, 10 );
2147 p->font->resolution_y = _bdf_atoul( p->list.field[3], 0, 10 );
2149 /* Check for the bits per pixel field. */
2150 if ( p->list.used == 5 )
2152 unsigned short bitcount, i, shift;
2155 p->font->bpp = (unsigned short)_bdf_atos( p->list.field[4], 0, 10 );
2157 /* Only values 1, 2, 4, 8 are allowed. */
2158 shift = p->font->bpp;
2160 for ( i = 0; shift > 0; i++ )
2167 shift = (short)( ( bitcount > 3 ) ? 8 : ( 1 << bitcount ) );
2169 if ( p->font->bpp > shift || p->font->bpp != shift )
2171 /* select next higher value */
2172 p->font->bpp = (unsigned short)( shift << 1 );
2173 FT_TRACE2(( "_bdf_parse_start: " ACMSG11, p->font->bpp ));
2179 p->flags |= _BDF_SIZE;
2184 error = BDF_Err_Invalid_File_Format;
2191 /*************************************************************************/
2195 /*************************************************************************/
2198 FT_LOCAL_DEF( FT_Error )
2199 bdf_load_font( FT_Stream stream,
2200 FT_Memory extmemory,
2201 bdf_options_t* opts,
2204 unsigned long lineno;
2207 FT_Memory memory = extmemory;
2208 FT_Error error = BDF_Err_Ok;
2211 if ( FT_ALLOC( p, sizeof ( _bdf_parse_t ) ) )
2215 p->opts = (bdf_options_t*)( ( opts != 0 ) ? opts : &_bdf_opts );
2217 p->memory = extmemory; /* only during font creation */
2219 error = _bdf_readstream( stream, _bdf_parse_start,
2220 (void *)p, &lineno );
2226 /* If the font is not proportional, set the font's monowidth */
2227 /* field to the width of the font bounding box. */
2228 memory = p->font->memory;
2230 if ( p->font->spacing != BDF_PROPORTIONAL )
2231 p->font->monowidth = p->font->bbx.width;
2233 /* If the number of glyphs loaded is not that of the original count, */
2234 /* indicate the difference. */
2235 if ( p->cnt != p->font->glyphs_used + p->font->unencoded_used )
2237 FT_TRACE2(( "bdf_load_font: " ACMSG15, p->cnt,
2238 p->font->glyphs_used + p->font->unencoded_used ));
2239 p->font->modified = 1;
2242 /* Once the font has been loaded, adjust the overall font metrics if */
2244 if ( p->opts->correct_metrics != 0 &&
2245 ( p->font->glyphs_used > 0 || p->font->unencoded_used > 0 ) )
2247 if ( p->maxrb - p->minlb != p->font->bbx.width )
2249 FT_TRACE2(( "bdf_load_font: " ACMSG3,
2250 p->font->bbx.width, p->maxrb - p->minlb ));
2251 p->font->bbx.width = (unsigned short)( p->maxrb - p->minlb );
2252 p->font->modified = 1;
2255 if ( p->font->bbx.x_offset != p->minlb )
2257 FT_TRACE2(( "bdf_load_font: " ACMSG4,
2258 p->font->bbx.x_offset, p->minlb ));
2259 p->font->bbx.x_offset = p->minlb;
2260 p->font->modified = 1;
2263 if ( p->font->bbx.ascent != p->maxas )
2265 FT_TRACE2(( "bdf_load_font: " ACMSG5,
2266 p->font->bbx.ascent, p->maxas ));
2267 p->font->bbx.ascent = p->maxas;
2268 p->font->modified = 1;
2271 if ( p->font->bbx.descent != p->maxds )
2273 FT_TRACE2(( "bdf_load_font: " ACMSG6,
2274 p->font->bbx.descent, p->maxds ));
2275 p->font->bbx.descent = p->maxds;
2276 p->font->bbx.y_offset = (short)( -p->maxds );
2277 p->font->modified = 1;
2280 if ( p->maxas + p->maxds != p->font->bbx.height )
2282 FT_TRACE2(( "bdf_load_font: " ACMSG7,
2283 p->font->bbx.height, p->maxas + p->maxds ));
2284 p->font->bbx.height = (unsigned short)( p->maxas + p->maxds );
2287 if ( p->flags & _BDF_SWIDTH_ADJ )
2288 FT_TRACE2(( "bdf_load_font: " ACMSG8 ));
2292 if ( p->flags & _BDF_START )
2295 /* The ENDFONT field was never reached or did not exist. */
2296 if ( !( p->flags & _BDF_GLYPHS ) )
2297 /* Error happened while parsing header. */
2298 FT_ERROR(( "bdf_load_font: " ERRMSG2, lineno ));
2300 /* Error happened when parsing glyphs. */
2301 FT_ERROR(( "bdf_load_font: " ERRMSG3, lineno ));
2305 /* Free up the list used during the parsing. */
2306 if ( memory != NULL )
2307 FT_FREE( p->list.field );
2311 /* Make sure the comments are NULL terminated if they exist. */
2312 memory = p->font->memory;
2314 if ( p->font->comments_len > 0 ) {
2315 if ( FT_RENEW_ARRAY( p->font->comments,
2316 p->font->comments_len,
2317 p->font->comments_len + 1 ) )
2320 p->font->comments[p->font->comments_len] = 0;
2323 else if ( error == BDF_Err_Ok )
2324 error = BDF_Err_Invalid_File_Format;
2339 FT_LOCAL_DEF( void )
2340 bdf_free_font( bdf_font_t* font )
2342 bdf_property_t* prop;
2344 bdf_glyph_t* glyphs;
2351 memory = font->memory;
2353 FT_FREE( font->name );
2355 /* Free up the internal hash table of property names. */
2356 if ( font->internal )
2358 hash_free( (hashtable *)font->internal, memory );
2359 FT_FREE( font->internal );
2362 /* Free up the comment info. */
2363 FT_FREE( font->comments );
2365 /* Free up the properties. */
2366 for ( i = 0; i < font->props_size; i++ )
2368 if ( font->props[i].format == BDF_ATOM )
2369 FT_FREE( font->props[i].value.atom );
2372 FT_FREE( font->props );
2374 /* Free up the character info. */
2375 for ( i = 0, glyphs = font->glyphs;
2376 i < font->glyphs_used; i++, glyphs++ )
2378 FT_FREE( glyphs->name );
2379 FT_FREE( glyphs->bitmap );
2382 for ( i = 0, glyphs = font->unencoded; i < font->unencoded_used;
2385 FT_FREE( glyphs->name );
2386 FT_FREE( glyphs->bitmap );
2389 FT_FREE( font->glyphs );
2390 FT_FREE( font->unencoded );
2392 /* Free up the overflow storage if it was used. */
2393 for ( i = 0, glyphs = font->overflow.glyphs;
2394 i < font->overflow.glyphs_used; i++, glyphs++ )
2396 FT_FREE( glyphs->name );
2397 FT_FREE( glyphs->bitmap );
2400 FT_FREE( font->overflow.glyphs );
2403 hash_free( &(font->proptbl), memory );
2405 /* Free up the user defined properties. */
2406 for (prop = font->user_props, i = 0;
2407 i < font->nuser_props; i++, prop++ )
2409 FT_FREE( prop->name );
2410 if ( prop->format == BDF_ATOM )
2411 FT_FREE( prop->value.atom );
2414 FT_FREE( font->user_props );
2416 /* FREE( font ); */ /* XXX Fixme */
2420 FT_LOCAL_DEF( bdf_property_t * )
2421 bdf_get_font_property( bdf_font_t* font,
2427 if ( font == 0 || font->props_size == 0 || name == 0 || *name == 0 )
2430 hn = hash_lookup( name, (hashtable *)font->internal );
2432 return hn ? ( font->props + (unsigned long)hn->data ) : 0;