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
35 #include <freetype/freetype.h>
36 #include <freetype/internal/ftdebug.h>
37 #include <freetype/internal/ftstream.h>
38 #include <freetype/internal/ftobjs.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 bdflib
57 /**************************************************************************
59 * Default BDF font options.
64 static const bdf_options_t bdf_opts_ =
66 1, /* Correct metrics. */
67 1, /* Preserve unencoded glyphs. */
68 0, /* Preserve comments. */
69 BDF_PROPORTIONAL /* Default spacing. */
73 /**************************************************************************
75 * Builtin BDF font properties.
79 /* List of most properties that might appear in a font. Doesn't include */
80 /* the RAW_* and AXIS_* properties in X11R6 polymorphic fonts. */
82 static const bdf_property_t bdf_properties_[] =
84 { "ADD_STYLE_NAME", BDF_ATOM, 1, { 0 } },
85 { "AVERAGE_WIDTH", BDF_INTEGER, 1, { 0 } },
86 { "AVG_CAPITAL_WIDTH", BDF_INTEGER, 1, { 0 } },
87 { "AVG_LOWERCASE_WIDTH", BDF_INTEGER, 1, { 0 } },
88 { "CAP_HEIGHT", BDF_INTEGER, 1, { 0 } },
89 { "CHARSET_COLLECTIONS", BDF_ATOM, 1, { 0 } },
90 { "CHARSET_ENCODING", BDF_ATOM, 1, { 0 } },
91 { "CHARSET_REGISTRY", BDF_ATOM, 1, { 0 } },
92 { "COMMENT", BDF_ATOM, 1, { 0 } },
93 { "COPYRIGHT", BDF_ATOM, 1, { 0 } },
94 { "DEFAULT_CHAR", BDF_CARDINAL, 1, { 0 } },
95 { "DESTINATION", BDF_CARDINAL, 1, { 0 } },
96 { "DEVICE_FONT_NAME", BDF_ATOM, 1, { 0 } },
97 { "END_SPACE", BDF_INTEGER, 1, { 0 } },
98 { "FACE_NAME", BDF_ATOM, 1, { 0 } },
99 { "FAMILY_NAME", BDF_ATOM, 1, { 0 } },
100 { "FIGURE_WIDTH", BDF_INTEGER, 1, { 0 } },
101 { "FONT", BDF_ATOM, 1, { 0 } },
102 { "FONTNAME_REGISTRY", BDF_ATOM, 1, { 0 } },
103 { "FONT_ASCENT", BDF_INTEGER, 1, { 0 } },
104 { "FONT_DESCENT", BDF_INTEGER, 1, { 0 } },
105 { "FOUNDRY", BDF_ATOM, 1, { 0 } },
106 { "FULL_NAME", BDF_ATOM, 1, { 0 } },
107 { "ITALIC_ANGLE", BDF_INTEGER, 1, { 0 } },
108 { "MAX_SPACE", BDF_INTEGER, 1, { 0 } },
109 { "MIN_SPACE", BDF_INTEGER, 1, { 0 } },
110 { "NORM_SPACE", BDF_INTEGER, 1, { 0 } },
111 { "NOTICE", BDF_ATOM, 1, { 0 } },
112 { "PIXEL_SIZE", BDF_INTEGER, 1, { 0 } },
113 { "POINT_SIZE", BDF_INTEGER, 1, { 0 } },
114 { "QUAD_WIDTH", BDF_INTEGER, 1, { 0 } },
115 { "RAW_ASCENT", BDF_INTEGER, 1, { 0 } },
116 { "RAW_AVERAGE_WIDTH", BDF_INTEGER, 1, { 0 } },
117 { "RAW_AVG_CAPITAL_WIDTH", BDF_INTEGER, 1, { 0 } },
118 { "RAW_AVG_LOWERCASE_WIDTH", BDF_INTEGER, 1, { 0 } },
119 { "RAW_CAP_HEIGHT", BDF_INTEGER, 1, { 0 } },
120 { "RAW_DESCENT", BDF_INTEGER, 1, { 0 } },
121 { "RAW_END_SPACE", BDF_INTEGER, 1, { 0 } },
122 { "RAW_FIGURE_WIDTH", BDF_INTEGER, 1, { 0 } },
123 { "RAW_MAX_SPACE", BDF_INTEGER, 1, { 0 } },
124 { "RAW_MIN_SPACE", BDF_INTEGER, 1, { 0 } },
125 { "RAW_NORM_SPACE", BDF_INTEGER, 1, { 0 } },
126 { "RAW_PIXEL_SIZE", BDF_INTEGER, 1, { 0 } },
127 { "RAW_POINT_SIZE", BDF_INTEGER, 1, { 0 } },
128 { "RAW_PIXELSIZE", BDF_INTEGER, 1, { 0 } },
129 { "RAW_POINTSIZE", BDF_INTEGER, 1, { 0 } },
130 { "RAW_QUAD_WIDTH", BDF_INTEGER, 1, { 0 } },
131 { "RAW_SMALL_CAP_SIZE", BDF_INTEGER, 1, { 0 } },
132 { "RAW_STRIKEOUT_ASCENT", BDF_INTEGER, 1, { 0 } },
133 { "RAW_STRIKEOUT_DESCENT", BDF_INTEGER, 1, { 0 } },
134 { "RAW_SUBSCRIPT_SIZE", BDF_INTEGER, 1, { 0 } },
135 { "RAW_SUBSCRIPT_X", BDF_INTEGER, 1, { 0 } },
136 { "RAW_SUBSCRIPT_Y", BDF_INTEGER, 1, { 0 } },
137 { "RAW_SUPERSCRIPT_SIZE", BDF_INTEGER, 1, { 0 } },
138 { "RAW_SUPERSCRIPT_X", BDF_INTEGER, 1, { 0 } },
139 { "RAW_SUPERSCRIPT_Y", BDF_INTEGER, 1, { 0 } },
140 { "RAW_UNDERLINE_POSITION", BDF_INTEGER, 1, { 0 } },
141 { "RAW_UNDERLINE_THICKNESS", BDF_INTEGER, 1, { 0 } },
142 { "RAW_X_HEIGHT", BDF_INTEGER, 1, { 0 } },
143 { "RELATIVE_SETWIDTH", BDF_CARDINAL, 1, { 0 } },
144 { "RELATIVE_WEIGHT", BDF_CARDINAL, 1, { 0 } },
145 { "RESOLUTION", BDF_INTEGER, 1, { 0 } },
146 { "RESOLUTION_X", BDF_CARDINAL, 1, { 0 } },
147 { "RESOLUTION_Y", BDF_CARDINAL, 1, { 0 } },
148 { "SETWIDTH_NAME", BDF_ATOM, 1, { 0 } },
149 { "SLANT", BDF_ATOM, 1, { 0 } },
150 { "SMALL_CAP_SIZE", BDF_INTEGER, 1, { 0 } },
151 { "SPACING", BDF_ATOM, 1, { 0 } },
152 { "STRIKEOUT_ASCENT", BDF_INTEGER, 1, { 0 } },
153 { "STRIKEOUT_DESCENT", BDF_INTEGER, 1, { 0 } },
154 { "SUBSCRIPT_SIZE", BDF_INTEGER, 1, { 0 } },
155 { "SUBSCRIPT_X", BDF_INTEGER, 1, { 0 } },
156 { "SUBSCRIPT_Y", BDF_INTEGER, 1, { 0 } },
157 { "SUPERSCRIPT_SIZE", BDF_INTEGER, 1, { 0 } },
158 { "SUPERSCRIPT_X", BDF_INTEGER, 1, { 0 } },
159 { "SUPERSCRIPT_Y", BDF_INTEGER, 1, { 0 } },
160 { "UNDERLINE_POSITION", BDF_INTEGER, 1, { 0 } },
161 { "UNDERLINE_THICKNESS", BDF_INTEGER, 1, { 0 } },
162 { "WEIGHT", BDF_CARDINAL, 1, { 0 } },
163 { "WEIGHT_NAME", BDF_ATOM, 1, { 0 } },
164 { "X_HEIGHT", BDF_INTEGER, 1, { 0 } },
165 { "_MULE_BASELINE_OFFSET", BDF_INTEGER, 1, { 0 } },
166 { "_MULE_RELATIVE_COMPOSE", BDF_INTEGER, 1, { 0 } },
169 static const unsigned long
170 num_bdf_properties_ = sizeof ( bdf_properties_ ) /
171 sizeof ( bdf_properties_[0] );
174 /* An auxiliary macro to parse properties, to be used in conditionals. */
175 /* It behaves like `strncmp' but also tests the following character */
176 /* whether it is a whitespace or null. */
177 /* `property' is a constant string of length `n' to compare with. */
178 #define _bdf_strncmp( name, property, n ) \
179 ( ft_strncmp( name, property, n ) || \
180 !( name[n] == ' ' || \
186 /* Auto correction messages. */
187 #define ACMSG1 "FONT_ASCENT property missing. " \
188 "Added `FONT_ASCENT %hd'.\n"
189 #define ACMSG2 "FONT_DESCENT property missing. " \
190 "Added `FONT_DESCENT %hd'.\n"
191 #define ACMSG3 "Font width != actual width. Old: %d New: %d.\n"
192 #define ACMSG4 "Font left bearing != actual left bearing. " \
193 "Old: %hd New: %hd.\n"
194 #define ACMSG5 "Font ascent != actual ascent. Old: %hd New: %hd.\n"
195 #define ACMSG6 "Font descent != actual descent. Old: %d New: %d.\n"
196 #define ACMSG7 "Font height != actual height. Old: %d New: %d.\n"
197 #define ACMSG8 "Glyph scalable width (SWIDTH) adjustments made.\n"
198 #define ACMSG9 "SWIDTH field missing at line %ld. Set automatically.\n"
199 #define ACMSG10 "DWIDTH field missing at line %ld. Set to glyph width.\n"
200 #define ACMSG11 "SIZE bits per pixel field adjusted to %hd.\n"
201 #define ACMSG13 "Glyph %lu extra rows removed.\n"
202 #define ACMSG14 "Glyph %lu extra columns removed.\n"
203 #define ACMSG15 "Incorrect glyph count: %ld indicated but %ld found.\n"
204 #define ACMSG16 "Glyph %lu missing columns padded with zero bits.\n"
205 #define ACMSG17 "Adjusting number of glyphs to %ld.\n"
207 /* Error messages. */
208 #define ERRMSG1 "[line %ld] Missing `%s' line.\n"
209 #define ERRMSG2 "[line %ld] Font header corrupted or missing fields.\n"
210 #define ERRMSG3 "[line %ld] Font glyphs corrupted or missing fields.\n"
211 #define ERRMSG4 "[line %ld] BBX too big.\n"
212 #define ERRMSG5 "[line %ld] `%s' value too big.\n"
213 #define ERRMSG6 "[line %ld] Input line too long.\n"
214 #define ERRMSG7 "[line %ld] Font name too long.\n"
215 #define ERRMSG8 "[line %ld] Invalid `%s' value.\n"
216 #define ERRMSG9 "[line %ld] Invalid keyword.\n"
218 /* Debug messages. */
219 #define DBGMSG1 " [%6ld] %s" /* no \n */
220 #define DBGMSG2 " (0x%lX)\n"
223 /**************************************************************************
225 * Utility types and functions.
230 /* Function type for parsing lines of a BDF font. */
233 (*bdf_line_func_t_)( char* line,
234 unsigned long linelen,
235 unsigned long lineno,
240 /* List structure for splitting lines into fields. */
242 typedef struct bdf_list_t__
252 /* Structure used while loading BDF fonts. */
254 typedef struct bdf_parse_t__
277 unsigned long size; /* the stream size */
282 #define setsbit( m, cc ) \
283 ( m[(FT_Byte)(cc) >> 3] |= (FT_Byte)( 1 << ( (cc) & 7 ) ) )
284 #define sbitset( m, cc ) \
285 ( m[(FT_Byte)(cc) >> 3] & ( 1 << ( (cc) & 7 ) ) )
289 bdf_list_init_( bdf_list_t_* list,
293 list->memory = memory;
298 bdf_list_done_( bdf_list_t_* list )
300 FT_Memory memory = list->memory;
305 FT_FREE( list->field );
312 bdf_list_ensure_( bdf_list_t_* list,
313 unsigned long num_items ) /* same as bdf_list_t_.used */
315 FT_Error error = FT_Err_Ok;
318 if ( num_items > list->size )
320 unsigned long oldsize = list->size; /* same as bdf_list_t_.size */
321 unsigned long newsize = oldsize + ( oldsize >> 1 ) + 5;
322 unsigned long bigsize = (unsigned long)( FT_INT_MAX / sizeof ( char* ) );
323 FT_Memory memory = list->memory;
326 if ( oldsize == bigsize )
328 error = FT_THROW( Out_Of_Memory );
331 else if ( newsize < oldsize || newsize > bigsize )
334 if ( FT_QRENEW_ARRAY( list->field, oldsize, newsize ) )
337 list->size = newsize;
346 bdf_list_shift_( bdf_list_t_* list,
352 if ( list == NULL || list->used == 0 || n == 0 )
355 if ( n >= list->used )
361 for ( u = n, i = 0; u < list->used; i++, u++ )
362 list->field[i] = list->field[u];
367 /* An empty string for empty fields. */
369 static const char empty[] = ""; /* XXX eliminate this */
373 bdf_list_join_( bdf_list_t_* list,
375 unsigned long *alen )
383 if ( list == NULL || list->used == 0 )
387 for ( i = j = 0; i < list->used; i++ )
389 char* fp = list->field[i];
395 if ( i + 1 < list->used )
406 /* The code below ensures that we have at least 4 + 1 `field' */
407 /* elements in `list' (which are possibly NULL) so that we */
408 /* don't have to check the number of fields in most cases. */
411 bdf_list_split_( bdf_list_t_* list,
412 const char* separators,
414 unsigned long linelen )
416 unsigned long final_empty;
418 const char *sp, *end;
421 FT_Error error = FT_Err_Ok;
424 /* Initialize the list. */
428 list->field[0] = (char*)empty;
429 list->field[1] = (char*)empty;
430 list->field[2] = (char*)empty;
431 list->field[3] = (char*)empty;
432 list->field[4] = (char*)empty;
435 /* If the line is empty, then simply return. */
436 if ( linelen == 0 || line[0] == 0 )
439 /* In the original code, if the `separators' parameter is NULL or */
440 /* empty, the list is split into individual bytes. We don't need */
441 /* this, so an error is signaled. */
442 if ( separators == NULL || *separators == 0 )
444 error = FT_THROW( Invalid_Argument );
448 /* Prepare the separator bitmap. */
449 FT_MEM_ZERO( seps, 32 );
451 /* If the very last character of the separator string is a plus, then */
452 /* set the `mult' flag to indicate that multiple separators should be */
453 /* collapsed into one. */
454 for ( mult = 0, sp = separators; sp && *sp; sp++ )
456 if ( *sp == '+' && *( sp + 1 ) == 0 )
459 setsbit( seps, *sp );
462 /* Break the line up into fields. */
463 for ( final_empty = 0, sp = ep = line, end = sp + linelen;
466 /* Collect everything that is not a separator. */
467 for ( ; *ep && !sbitset( seps, *ep ); ep++ )
470 /* Resize the list if necessary. */
471 if ( list->used == list->size )
473 error = bdf_list_ensure_( list, list->used + 1 );
478 /* Assign the field appropriately. */
479 list->field[list->used++] = ( ep > sp ) ? (char*)sp : (char*)empty;
485 /* If multiple separators should be collapsed, do it now by */
486 /* setting all the separator characters to 0. */
487 for ( ; *ep && sbitset( seps, *ep ); ep++ )
491 /* Don't collapse multiple separators by making them 0, so just */
492 /* make the one encountered 0. */
495 final_empty = ( ep > sp && *ep == 0 );
499 /* Finally, NULL-terminate the list. */
500 if ( list->used + final_empty >= list->size )
502 error = bdf_list_ensure_( list, list->used + final_empty + 1 );
508 list->field[list->used++] = (char*)empty;
510 list->field[list->used] = NULL;
517 #define NO_SKIP 256 /* this value cannot be stored in a 'char' */
521 bdf_readstream_( FT_Stream stream,
522 bdf_line_func_t_ callback,
527 unsigned long lineno, buf_size;
528 int refill, hold, to_skip;
529 ptrdiff_t bytes, start, end, cursor, avail;
531 FT_Memory memory = stream->memory;
532 FT_Error error = FT_Err_Ok;
535 if ( callback == NULL )
537 error = FT_THROW( Invalid_Argument );
541 /* initial size and allocation of the input buffer */
544 if ( FT_QALLOC( buf, buf_size ) )
555 bytes = 0; /* make compiler happy */
561 bytes = (ptrdiff_t)FT_Stream_TryRead(
562 stream, (FT_Byte*)buf + cursor,
563 buf_size - (unsigned long)cursor );
564 avail = cursor + bytes;
571 /* should we skip an optional character like \n or \r? */
572 if ( start < avail && buf[start] == to_skip )
579 /* try to find the end of the line */
580 while ( end < avail && buf[end] != '\n' && buf[end] != '\r' )
583 /* if we hit the end of the buffer, try shifting its content */
584 /* or even resizing it */
589 /* last line in file doesn't end in \r or \n; */
590 /* ignore it then exit */
592 error = FT_THROW( Missing_Startfont_Field );
598 /* this line is definitely too long; try resizing the input */
599 /* buffer a bit to handle it. */
603 if ( buf_size >= 65536UL ) /* limit ourselves to 64KByte */
606 error = FT_THROW( Missing_Startfont_Field );
609 FT_ERROR(( "bdf_readstream_: " ERRMSG6, lineno ));
610 error = FT_THROW( Invalid_Argument );
615 new_size = buf_size * 2;
616 if ( FT_QREALLOC( buf, buf_size, new_size ) )
624 bytes = avail - start;
626 FT_MEM_MOVE( buf, buf + start, bytes );
635 /* Temporarily NUL-terminate the line. */
639 /* XXX: Use encoding independent value for 0x1A */
640 if ( buf[start] != '#' && buf[start] != 0x1A && end > start )
642 error = (*cb)( buf + start, (unsigned long)( end - start ), lineno,
643 (void*)&cb, client_data );
644 /* Redo if we have encountered CHARS without properties. */
646 error = (*cb)( buf + start, (unsigned long)( end - start ), lineno,
647 (void*)&cb, client_data );
653 buf[end] = (char)hold;
658 else if ( hold == '\r' )
672 /* XXX: make this work with EBCDIC also */
674 static const unsigned char a2i[128] =
676 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
677 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
678 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
679 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
680 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x00, 0x00,
681 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x00,
682 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
683 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
684 0x00, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00,
685 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
686 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
689 static const unsigned char ddigits[32] =
691 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x03,
692 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
693 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
694 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
697 static const unsigned char hdigits[32] =
699 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x03,
700 0x7E, 0x00, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x00,
701 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
702 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
706 /* Routine to convert a decimal ASCII string to an unsigned long integer. */
708 bdf_atoul_( const char* s )
713 if ( s == NULL || *s == 0 )
716 for ( v = 0; sbitset( ddigits, *s ); s++ )
718 if ( v < ( FT_ULONG_MAX - 9 ) / 10 )
719 v = v * 10 + a2i[(int)*s];
731 /* Routine to convert a decimal ASCII string to a signed long integer. */
733 bdf_atol_( const char* s )
738 if ( s == NULL || *s == 0 )
741 /* Check for a minus sign. */
749 for ( v = 0; sbitset( ddigits, *s ); s++ )
751 if ( v < ( FT_LONG_MAX - 9 ) / 10 )
752 v = v * 10 + a2i[(int)*s];
760 return ( !neg ) ? v : -v;
764 /* Routine to convert a decimal ASCII string to an unsigned short integer. */
765 static unsigned short
766 bdf_atous_( const char* s )
771 if ( s == NULL || *s == 0 )
774 for ( v = 0; sbitset( ddigits, *s ); s++ )
776 if ( v < ( FT_USHORT_MAX - 9 ) / 10 )
777 v = (unsigned short)( v * 10 + a2i[(int)*s] );
789 /* Routine to convert a decimal ASCII string to a signed short integer. */
791 bdf_atos_( const char* s )
796 if ( s == NULL || *s == 0 )
799 /* Check for a minus. */
807 for ( v = 0; sbitset( ddigits, *s ); s++ )
809 if ( v < ( SHRT_MAX - 9 ) / 10 )
810 v = (short)( v * 10 + a2i[(int)*s] );
818 return (short)( ( !neg ) ? v : -v );
822 /* Routine to compare two glyphs by encoding so they can be sorted. */
823 FT_COMPARE_DEF( int )
824 by_encoding( const void* a,
827 bdf_glyph_t *c1, *c2;
830 c1 = (bdf_glyph_t *)a;
831 c2 = (bdf_glyph_t *)b;
833 if ( c1->encoding < c2->encoding )
836 if ( c1->encoding > c2->encoding )
844 bdf_create_property( const char* name,
850 FT_Memory memory = font->memory;
851 FT_Error error = FT_Err_Ok;
854 /* First check whether the property has */
855 /* already been added or not. If it has, then */
856 /* simply ignore it. */
857 if ( ft_hash_str_lookup( name, &(font->proptbl) ) )
860 if ( FT_QRENEW_ARRAY( font->user_props,
862 font->nuser_props + 1 ) )
865 p = font->user_props + font->nuser_props;
867 n = ft_strlen( name ) + 1;
868 if ( n > FT_LONG_MAX )
869 return FT_THROW( Invalid_Argument );
871 if ( FT_QALLOC( p->name, n ) )
874 FT_MEM_COPY( (char *)p->name, name, n );
878 p->value.atom = NULL; /* nothing is ever stored here */
880 n = num_bdf_properties_ + font->nuser_props;
882 error = ft_hash_str_insert( p->name, n, &(font->proptbl), memory );
893 static bdf_property_t*
894 bdf_get_property( const char* name,
900 if ( name == NULL || *name == 0 )
903 if ( ( propid = ft_hash_str_lookup( name, &(font->proptbl) ) ) == NULL )
906 if ( *propid >= num_bdf_properties_ )
907 return font->user_props + ( *propid - num_bdf_properties_ );
909 return (bdf_property_t*)bdf_properties_ + *propid;
913 /**************************************************************************
915 * BDF font file parsing flags and functions.
922 #define BDF_START_ 0x0001U
923 #define BDF_FONT_NAME_ 0x0002U
924 #define BDF_SIZE_ 0x0004U
925 #define BDF_FONT_BBX_ 0x0008U
926 #define BDF_PROPS_ 0x0010U
927 #define BDF_GLYPHS_ 0x0020U
928 #define BDF_GLYPH_ 0x0040U
929 #define BDF_ENCODING_ 0x0080U
930 #define BDF_SWIDTH_ 0x0100U
931 #define BDF_DWIDTH_ 0x0200U
932 #define BDF_BBX_ 0x0400U
933 #define BDF_BITMAP_ 0x0800U
935 #define BDF_SWIDTH_ADJ_ 0x1000U
937 #define BDF_GLYPH_BITS_ ( BDF_GLYPH_ | \
944 #define BDF_GLYPH_WIDTH_CHECK_ 0x40000000UL
945 #define BDF_GLYPH_HEIGHT_CHECK_ 0x80000000UL
949 bdf_add_comment_( bdf_font_t* font,
954 FT_Memory memory = font->memory;
955 FT_Error error = FT_Err_Ok;
958 if ( FT_QRENEW_ARRAY( font->comments,
960 font->comments_len + len + 1 ) )
963 cp = font->comments + font->comments_len;
965 FT_MEM_COPY( cp, comment, len );
968 font->comments_len += len + 1;
975 /* Set the spacing from the font name if it exists, or set it to the */
976 /* default specified in the options. */
978 bdf_set_default_spacing_( bdf_font_t* font,
980 unsigned long lineno )
986 FT_Error error = FT_Err_Ok;
988 FT_UNUSED( lineno ); /* only used in debug mode */
991 if ( font == NULL || font->name == NULL || font->name[0] == 0 )
993 error = FT_THROW( Invalid_Argument );
997 memory = font->memory;
999 bdf_list_init_( &list, memory );
1001 font->spacing = opts->font_spacing;
1003 len = ft_strlen( font->name ) + 1;
1004 /* Limit ourselves to 256 characters in the font name. */
1007 FT_ERROR(( "bdf_set_default_spacing_: " ERRMSG7, lineno ));
1008 error = FT_THROW( Invalid_Argument );
1012 FT_MEM_COPY( name, font->name, len );
1014 error = bdf_list_split_( &list, "-", name, (unsigned long)len );
1018 if ( list.used == 15 )
1020 switch ( list.field[11][0] )
1024 font->spacing = BDF_CHARCELL;
1028 font->spacing = BDF_MONOWIDTH;
1032 font->spacing = BDF_PROPORTIONAL;
1038 bdf_list_done_( &list );
1045 /* Determine whether the property is an atom or not. If it is, then */
1046 /* clean it up so the double quotes are removed if they exist. */
1048 bdf_is_atom_( char* line,
1049 unsigned long linelen,
1061 while ( *ep && *ep != ' ' && *ep != '\t' )
1067 p = bdf_get_property( sp, font );
1069 /* If the property exists and is not an atom, just return here. */
1070 if ( p && p->format != BDF_ATOM )
1072 *ep = (char)hold; /* Undo NUL-termination. */
1078 /* The property is an atom. Trim all leading and trailing whitespace */
1079 /* and double quotes for the atom value. */
1081 ep = line + linelen;
1083 /* Trim the leading whitespace if it exists. */
1087 while ( *sp == ' ' || *sp == '\t' );
1089 /* Trim the leading double quote if it exists. */
1095 /* Trim the trailing whitespace if it exists. */
1099 while ( *ep == ' ' || *ep == '\t' );
1101 /* Trim the trailing double quote if it exists. */
1110 bdf_add_property_( bdf_font_t* font,
1113 unsigned long lineno )
1116 bdf_property_t *prop, *fp;
1117 FT_Memory memory = font->memory;
1118 FT_Error error = FT_Err_Ok;
1120 FT_UNUSED( lineno ); /* only used in debug mode */
1123 /* First, check whether the property already exists in the font. */
1124 if ( ( propid = ft_hash_str_lookup( name,
1125 (FT_Hash)font->internal ) ) != NULL )
1127 /* The property already exists in the font, so simply replace */
1128 /* the value of the property with the current value. */
1129 fp = font->props + *propid;
1131 switch ( fp->format )
1134 /* Delete the current atom if it exists. */
1135 FT_FREE( fp->value.atom );
1137 if ( value && value[0] != 0 )
1139 if ( FT_STRDUP( fp->value.atom, value ) )
1145 fp->value.l = bdf_atol_( value );
1149 fp->value.ul = bdf_atoul_( value );
1159 /* See whether this property type exists yet or not. */
1160 /* If not, create it. */
1161 propid = ft_hash_str_lookup( name, &(font->proptbl) );
1164 error = bdf_create_property( name, BDF_ATOM, font );
1167 propid = ft_hash_str_lookup( name, &(font->proptbl) );
1170 /* Allocate another property if this is overflowing. */
1171 if ( font->props_used == font->props_size )
1173 if ( FT_QRENEW_ARRAY( font->props,
1175 font->props_size + 1 ) )
1181 if ( *propid >= num_bdf_properties_ )
1182 prop = font->user_props + ( *propid - num_bdf_properties_ );
1184 prop = (bdf_property_t*)bdf_properties_ + *propid;
1186 fp = font->props + font->props_used;
1188 fp->name = prop->name;
1189 fp->format = prop->format;
1190 fp->builtin = prop->builtin;
1192 switch ( prop->format )
1195 fp->value.atom = NULL;
1196 if ( value && value[0] )
1198 if ( FT_STRDUP( fp->value.atom, value ) )
1204 fp->value.l = bdf_atol_( value );
1208 fp->value.ul = bdf_atoul_( value );
1212 /* If the property happens to be a comment, then it doesn't need */
1213 /* to be added to the internal hash table. */
1214 if ( _bdf_strncmp( name, "COMMENT", 7 ) != 0 )
1216 /* Add the property to the font property table. */
1217 error = ft_hash_str_insert( fp->name,
1219 (FT_Hash)font->internal,
1227 /* Some special cases need to be handled here. The DEFAULT_CHAR */
1228 /* property needs to be located if it exists in the property list, the */
1229 /* FONT_ASCENT and FONT_DESCENT need to be assigned if they are */
1230 /* present, and the SPACING property should override the default */
1232 if ( _bdf_strncmp( name, "DEFAULT_CHAR", 12 ) == 0 )
1233 font->default_char = fp->value.ul;
1234 else if ( _bdf_strncmp( name, "FONT_ASCENT", 11 ) == 0 )
1235 font->font_ascent = fp->value.l;
1236 else if ( _bdf_strncmp( name, "FONT_DESCENT", 12 ) == 0 )
1237 font->font_descent = fp->value.l;
1238 else if ( _bdf_strncmp( name, "SPACING", 7 ) == 0 )
1240 if ( !fp->value.atom )
1242 FT_ERROR(( "bdf_add_property_: " ERRMSG8, lineno, "SPACING" ));
1243 error = FT_THROW( Invalid_File_Format );
1247 if ( fp->value.atom[0] == 'p' || fp->value.atom[0] == 'P' )
1248 font->spacing = BDF_PROPORTIONAL;
1249 else if ( fp->value.atom[0] == 'm' || fp->value.atom[0] == 'M' )
1250 font->spacing = BDF_MONOWIDTH;
1251 else if ( fp->value.atom[0] == 'c' || fp->value.atom[0] == 'C' )
1252 font->spacing = BDF_CHARCELL;
1260 static const unsigned char nibble_mask[8] =
1262 0xFF, 0x80, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC, 0xFE
1267 bdf_parse_end_( char* line,
1268 unsigned long linelen,
1269 unsigned long lineno,
1273 /* a no-op; we ignore everything after `ENDFONT' */
1276 FT_UNUSED( linelen );
1277 FT_UNUSED( lineno );
1278 FT_UNUSED( call_data );
1279 FT_UNUSED( client_data );
1285 /* Actually parse the glyph info and bitmaps. */
1287 bdf_parse_glyphs_( char* line,
1288 unsigned long linelen,
1289 unsigned long lineno,
1296 unsigned long i, slen, nibbles;
1298 bdf_line_func_t_* next;
1304 FT_Error error = FT_Err_Ok;
1306 FT_UNUSED( lineno ); /* only used in debug mode */
1309 next = (bdf_line_func_t_ *)call_data;
1310 p = (bdf_parse_t_ *) client_data;
1313 memory = font->memory;
1315 /* Check for a comment. */
1316 if ( _bdf_strncmp( line, "COMMENT", 7 ) == 0 )
1318 if ( p->opts->keep_comments )
1328 error = bdf_add_comment_( p->font, s, linelen );
1333 /* The very first thing expected is the number of glyphs. */
1334 if ( !( p->flags & BDF_GLYPHS_ ) )
1336 if ( _bdf_strncmp( line, "CHARS", 5 ) != 0 )
1338 FT_ERROR(( "bdf_parse_glyphs_: " ERRMSG1, lineno, "CHARS" ));
1339 error = FT_THROW( Missing_Chars_Field );
1343 error = bdf_list_split_( &p->list, " +", line, linelen );
1346 p->cnt = font->glyphs_size = bdf_atoul_( p->list.field[1] );
1348 /* We need at least 20 bytes per glyph. */
1349 if ( p->cnt > p->size / 20 )
1351 p->cnt = font->glyphs_size = p->size / 20;
1352 FT_TRACE2(( "bdf_parse_glyphs_: " ACMSG17, p->cnt ));
1355 /* Make sure the number of glyphs is non-zero. */
1357 font->glyphs_size = 64;
1359 /* Limit ourselves to 1,114,112 glyphs in the font (this is the */
1360 /* number of code points available in Unicode). */
1361 if ( p->cnt >= 0x110000UL )
1363 FT_ERROR(( "bdf_parse_glyphs_: " ERRMSG5, lineno, "CHARS" ));
1364 error = FT_THROW( Invalid_Argument );
1368 if ( FT_NEW_ARRAY( font->glyphs, font->glyphs_size ) )
1371 p->flags |= BDF_GLYPHS_;
1376 /* Check for the ENDFONT field. */
1377 if ( _bdf_strncmp( line, "ENDFONT", 7 ) == 0 )
1379 if ( p->flags & BDF_GLYPH_BITS_ )
1381 /* Missing ENDCHAR field. */
1382 FT_ERROR(( "bdf_parse_glyphs_: " ERRMSG1, lineno, "ENDCHAR" ));
1383 error = FT_THROW( Corrupted_Font_Glyphs );
1387 /* Sort the glyphs by encoding. */
1388 ft_qsort( (char *)font->glyphs,
1390 sizeof ( bdf_glyph_t ),
1393 p->flags &= ~BDF_START_;
1394 *next = bdf_parse_end_;
1399 /* Check for the ENDCHAR field. */
1400 if ( _bdf_strncmp( line, "ENDCHAR", 7 ) == 0 )
1403 p->flags &= ~BDF_GLYPH_BITS_;
1408 /* Check whether a glyph is being scanned but should be */
1409 /* ignored because it is an unencoded glyph. */
1410 if ( ( p->flags & BDF_GLYPH_ ) &&
1411 p->glyph_enc == -1 &&
1412 p->opts->keep_unencoded == 0 )
1415 /* Check for the STARTCHAR field. */
1416 if ( _bdf_strncmp( line, "STARTCHAR", 9 ) == 0 )
1418 if ( p->flags & BDF_GLYPH_BITS_ )
1420 /* Missing ENDCHAR field. */
1421 FT_ERROR(( "bdf_parse_glyphs_: " ERRMSG1, lineno, "ENDCHAR" ));
1422 error = FT_THROW( Missing_Startchar_Field );
1426 /* Set the character name in the parse info first until the */
1427 /* encoding can be checked for an unencoded character. */
1428 FT_FREE( p->glyph_name );
1430 error = bdf_list_split_( &p->list, " +", line, linelen );
1434 bdf_list_shift_( &p->list, 1 );
1436 s = bdf_list_join_( &p->list, ' ', &slen );
1440 FT_ERROR(( "bdf_parse_glyphs_: " ERRMSG8, lineno, "STARTCHAR" ));
1441 error = FT_THROW( Invalid_File_Format );
1445 if ( FT_QALLOC( p->glyph_name, slen + 1 ) )
1448 FT_MEM_COPY( p->glyph_name, s, slen + 1 );
1450 p->flags |= BDF_GLYPH_;
1452 FT_TRACE4(( DBGMSG1, lineno, s ));
1457 /* Check for the ENCODING field. */
1458 if ( _bdf_strncmp( line, "ENCODING", 8 ) == 0 )
1460 if ( !( p->flags & BDF_GLYPH_ ) )
1462 /* Missing STARTCHAR field. */
1463 FT_ERROR(( "bdf_parse_glyphs_: " ERRMSG1, lineno, "STARTCHAR" ));
1464 error = FT_THROW( Missing_Startchar_Field );
1468 error = bdf_list_split_( &p->list, " +", line, linelen );
1472 p->glyph_enc = bdf_atol_( p->list.field[1] );
1474 /* Normalize negative encoding values. The specification only */
1475 /* allows -1, but we can be more generous here. */
1476 if ( p->glyph_enc < -1 )
1479 /* Check for alternative encoding format. */
1480 if ( p->glyph_enc == -1 && p->list.used > 2 )
1481 p->glyph_enc = bdf_atol_( p->list.field[2] );
1483 if ( p->glyph_enc < -1 || p->glyph_enc >= 0x110000L )
1486 FT_TRACE4(( DBGMSG2, p->glyph_enc ));
1488 if ( p->glyph_enc >= 0 )
1490 /* Make sure there are enough glyphs allocated in case the */
1491 /* number of characters happen to be wrong. */
1492 if ( font->glyphs_used == font->glyphs_size )
1494 if ( FT_RENEW_ARRAY( font->glyphs,
1496 font->glyphs_size + 64 ) )
1499 font->glyphs_size += 64;
1502 glyph = font->glyphs + font->glyphs_used++;
1503 glyph->name = p->glyph_name;
1504 glyph->encoding = (unsigned long)p->glyph_enc;
1506 /* Reset the initial glyph info. */
1507 p->glyph_name = NULL;
1511 /* Unencoded glyph. Check whether it should */
1512 /* be added or not. */
1513 if ( p->opts->keep_unencoded )
1515 /* Allocate the next unencoded glyph. */
1516 if ( font->unencoded_used == font->unencoded_size )
1518 if ( FT_RENEW_ARRAY( font->unencoded ,
1519 font->unencoded_size,
1520 font->unencoded_size + 4 ) )
1523 font->unencoded_size += 4;
1526 glyph = font->unencoded + font->unencoded_used;
1527 glyph->name = p->glyph_name;
1528 glyph->encoding = font->unencoded_used++;
1530 /* Reset the initial glyph info. */
1531 p->glyph_name = NULL;
1535 /* Free up the glyph name if the unencoded shouldn't be */
1537 FT_FREE( p->glyph_name );
1541 /* Clear the flags that might be added when width and height are */
1542 /* checked for consistency. */
1543 p->flags &= ~( BDF_GLYPH_WIDTH_CHECK_ | BDF_GLYPH_HEIGHT_CHECK_ );
1545 p->flags |= BDF_ENCODING_;
1550 if ( !( p->flags & BDF_ENCODING_ ) )
1551 goto Missing_Encoding;
1553 /* Point at the glyph being constructed. */
1554 if ( p->glyph_enc == -1 )
1555 glyph = font->unencoded + ( font->unencoded_used - 1 );
1557 glyph = font->glyphs + ( font->glyphs_used - 1 );
1559 /* Check whether a bitmap is being constructed. */
1560 if ( p->flags & BDF_BITMAP_ )
1562 /* If there are more rows than are specified in the glyph metrics, */
1563 /* ignore the remaining lines. */
1564 if ( p->row >= (unsigned long)glyph->bbx.height )
1566 if ( !( p->flags & BDF_GLYPH_HEIGHT_CHECK_ ) )
1568 FT_TRACE2(( "bdf_parse_glyphs_: " ACMSG13, glyph->encoding ));
1569 p->flags |= BDF_GLYPH_HEIGHT_CHECK_;
1575 /* Only collect the number of nibbles indicated by the glyph */
1576 /* metrics. If there are more columns, they are simply ignored. */
1577 nibbles = glyph->bpr << 1;
1578 bp = glyph->bitmap + p->row * glyph->bpr;
1580 for ( i = 0; i < nibbles; i++ )
1583 if ( !sbitset( hdigits, c ) )
1585 *bp = (FT_Byte)( ( *bp << 4 ) + a2i[c] );
1586 if ( i + 1 < nibbles && ( i & 1 ) )
1590 /* If any line has not enough columns, */
1591 /* indicate they have been padded with zero bits. */
1593 !( p->flags & BDF_GLYPH_WIDTH_CHECK_ ) )
1595 FT_TRACE2(( "bdf_parse_glyphs_: " ACMSG16, glyph->encoding ));
1596 p->flags |= BDF_GLYPH_WIDTH_CHECK_;
1599 /* Remove possible garbage at the right. */
1600 mask_index = ( glyph->bbx.width * p->font->bpp ) & 7;
1601 if ( glyph->bbx.width )
1602 *bp &= nibble_mask[mask_index];
1604 /* If any line has extra columns, indicate they have been removed. */
1605 if ( i == nibbles &&
1606 sbitset( hdigits, line[nibbles] ) &&
1607 !( p->flags & BDF_GLYPH_WIDTH_CHECK_ ) )
1609 FT_TRACE2(( "bdf_parse_glyphs_: " ACMSG14, glyph->encoding ));
1610 p->flags |= BDF_GLYPH_WIDTH_CHECK_;
1617 /* Expect the SWIDTH (scalable width) field next. */
1618 if ( _bdf_strncmp( line, "SWIDTH", 6 ) == 0 )
1620 error = bdf_list_split_( &p->list, " +", line, linelen );
1624 glyph->swidth = bdf_atous_( p->list.field[1] );
1625 p->flags |= BDF_SWIDTH_;
1630 /* Expect the DWIDTH (device width) field next. */
1631 if ( _bdf_strncmp( line, "DWIDTH", 6 ) == 0 )
1633 error = bdf_list_split_( &p->list, " +", line, linelen );
1637 glyph->dwidth = bdf_atous_( p->list.field[1] );
1639 if ( !( p->flags & BDF_SWIDTH_ ) )
1641 /* Missing SWIDTH field. Emit an auto correction message and set */
1642 /* the scalable width from the device width. */
1643 FT_TRACE2(( "bdf_parse_glyphs_: " ACMSG9, lineno ));
1645 glyph->swidth = (unsigned short)FT_MulDiv(
1646 glyph->dwidth, 72000L,
1647 (FT_Long)( font->point_size *
1648 font->resolution_x ) );
1651 p->flags |= BDF_DWIDTH_;
1655 /* Expect the BBX field next. */
1656 if ( _bdf_strncmp( line, "BBX", 3 ) == 0 )
1658 error = bdf_list_split_( &p->list, " +", line, linelen );
1662 glyph->bbx.width = bdf_atous_( p->list.field[1] );
1663 glyph->bbx.height = bdf_atous_( p->list.field[2] );
1664 glyph->bbx.x_offset = bdf_atos_( p->list.field[3] );
1665 glyph->bbx.y_offset = bdf_atos_( p->list.field[4] );
1667 /* Generate the ascent and descent of the character. */
1668 glyph->bbx.ascent = (short)( glyph->bbx.height + glyph->bbx.y_offset );
1669 glyph->bbx.descent = (short)( -glyph->bbx.y_offset );
1671 /* Determine the overall font bounding box as the characters are */
1672 /* loaded so corrections can be done later if indicated. */
1673 p->maxas = (short)FT_MAX( glyph->bbx.ascent, p->maxas );
1674 p->maxds = (short)FT_MAX( glyph->bbx.descent, p->maxds );
1676 p->rbearing = (short)( glyph->bbx.width + glyph->bbx.x_offset );
1678 p->maxrb = (short)FT_MAX( p->rbearing, p->maxrb );
1679 p->minlb = (short)FT_MIN( glyph->bbx.x_offset, p->minlb );
1680 p->maxlb = (short)FT_MAX( glyph->bbx.x_offset, p->maxlb );
1682 if ( !( p->flags & BDF_DWIDTH_ ) )
1684 /* Missing DWIDTH field. Emit an auto correction message and set */
1685 /* the device width to the glyph width. */
1686 FT_TRACE2(( "bdf_parse_glyphs_: " ACMSG10, lineno ));
1687 glyph->dwidth = glyph->bbx.width;
1690 /* If the BDF_CORRECT_METRICS flag is set, then adjust the SWIDTH */
1691 /* value if necessary. */
1692 if ( p->opts->correct_metrics )
1694 /* Determine the point size of the glyph. */
1695 unsigned short sw = (unsigned short)FT_MulDiv(
1696 glyph->dwidth, 72000L,
1697 (FT_Long)( font->point_size *
1698 font->resolution_x ) );
1701 if ( sw != glyph->swidth )
1705 p->flags |= BDF_SWIDTH_ADJ_;
1709 p->flags |= BDF_BBX_;
1713 /* And finally, gather up the bitmap. */
1714 if ( _bdf_strncmp( line, "BITMAP", 6 ) == 0 )
1716 unsigned long bitmap_size;
1719 if ( !( p->flags & BDF_BBX_ ) )
1721 /* Missing BBX field. */
1722 FT_ERROR(( "bdf_parse_glyphs_: " ERRMSG1, lineno, "BBX" ));
1723 error = FT_THROW( Missing_Bbx_Field );
1727 /* Allocate enough space for the bitmap. */
1728 glyph->bpr = ( glyph->bbx.width * p->font->bpp + 7 ) >> 3;
1730 bitmap_size = glyph->bpr * glyph->bbx.height;
1731 if ( glyph->bpr > 0xFFFFU || bitmap_size > 0xFFFFU )
1733 FT_ERROR(( "bdf_parse_glyphs_: " ERRMSG4, lineno ));
1734 error = FT_THROW( Bbx_Too_Big );
1738 glyph->bytes = (unsigned short)bitmap_size;
1740 if ( FT_ALLOC( glyph->bitmap, glyph->bytes ) )
1744 p->flags |= BDF_BITMAP_;
1749 FT_ERROR(( "bdf_parse_glyphs_: " ERRMSG9, lineno ));
1750 error = FT_THROW( Invalid_File_Format );
1754 /* Missing ENCODING field. */
1755 FT_ERROR(( "bdf_parse_glyphs_: " ERRMSG1, lineno, "ENCODING" ));
1756 error = FT_THROW( Missing_Encoding_Field );
1759 if ( error && ( p->flags & BDF_GLYPH_ ) )
1760 FT_FREE( p->glyph_name );
1766 /* Load the font properties. */
1768 bdf_parse_properties_( char* line,
1769 unsigned long linelen,
1770 unsigned long lineno,
1775 bdf_line_func_t_* next;
1780 FT_Error error = FT_Err_Ok;
1782 FT_UNUSED( lineno );
1785 next = (bdf_line_func_t_ *)call_data;
1786 p = (bdf_parse_t_ *) client_data;
1788 /* Check for the end of the properties. */
1789 if ( _bdf_strncmp( line, "ENDPROPERTIES", 13 ) == 0 )
1791 /* If the FONT_ASCENT or FONT_DESCENT properties have not been */
1792 /* encountered yet, then make sure they are added as properties and */
1793 /* make sure they are set from the font bounding box info. */
1795 /* This is *always* done regardless of the options, because X11 */
1796 /* requires these two fields to compile fonts. */
1797 if ( bdf_get_font_property( p->font, "FONT_ASCENT" ) == 0 )
1799 p->font->font_ascent = p->font->bbx.ascent;
1800 ft_snprintf( nbuf, BUFSIZE, "%hd", p->font->bbx.ascent );
1801 error = bdf_add_property_( p->font, "FONT_ASCENT",
1806 FT_TRACE2(( "bdf_parse_properties_: " ACMSG1, p->font->bbx.ascent ));
1809 if ( bdf_get_font_property( p->font, "FONT_DESCENT" ) == 0 )
1811 p->font->font_descent = p->font->bbx.descent;
1812 ft_snprintf( nbuf, BUFSIZE, "%hd", p->font->bbx.descent );
1813 error = bdf_add_property_( p->font, "FONT_DESCENT",
1818 FT_TRACE2(( "bdf_parse_properties_: " ACMSG2, p->font->bbx.descent ));
1821 p->flags &= ~BDF_PROPS_;
1822 *next = bdf_parse_glyphs_;
1827 /* Ignore the _XFREE86_GLYPH_RANGES properties. */
1828 if ( _bdf_strncmp( line, "_XFREE86_GLYPH_RANGES", 21 ) == 0 )
1831 /* Handle COMMENT fields and properties in a special way to preserve */
1833 if ( _bdf_strncmp( line, "COMMENT", 7 ) == 0 )
1835 name = value = line;
1839 error = bdf_add_property_( p->font, name, value, lineno );
1843 else if ( bdf_is_atom_( line, linelen, &name, &value, p->font ) )
1845 error = bdf_add_property_( p->font, name, value, lineno );
1851 error = bdf_list_split_( &p->list, " +", line, linelen );
1854 name = p->list.field[0];
1856 bdf_list_shift_( &p->list, 1 );
1857 value = bdf_list_join_( &p->list, ' ', &vlen );
1859 error = bdf_add_property_( p->font, name, value, lineno );
1869 /* Load the font header. */
1871 bdf_parse_start_( char* line,
1872 unsigned long linelen,
1873 unsigned long lineno,
1878 bdf_line_func_t_* next;
1883 FT_Memory memory = NULL;
1884 FT_Error error = FT_Err_Ok;
1886 FT_UNUSED( lineno ); /* only used in debug mode */
1889 next = (bdf_line_func_t_ *)call_data;
1890 p = (bdf_parse_t_ *) client_data;
1893 memory = p->font->memory;
1895 /* Check for a comment. This is done to handle those fonts that have */
1896 /* comments before the STARTFONT line for some reason. */
1897 if ( _bdf_strncmp( line, "COMMENT", 7 ) == 0 )
1899 if ( p->opts->keep_comments && p->font )
1909 error = bdf_add_comment_( p->font, s, linelen );
1914 if ( !( p->flags & BDF_START_ ) )
1918 if ( _bdf_strncmp( line, "STARTFONT", 9 ) != 0 )
1920 /* we don't emit an error message since this code gets */
1921 /* explicitly caught one level higher */
1922 error = FT_THROW( Missing_Startfont_Field );
1926 p->flags = BDF_START_;
1927 font = p->font = NULL;
1929 if ( FT_NEW( font ) )
1933 font->memory = p->memory;
1937 bdf_property_t* prop;
1940 error = ft_hash_str_init( &(font->proptbl), memory );
1943 for ( i = 0, prop = (bdf_property_t*)bdf_properties_;
1944 i < num_bdf_properties_; i++, prop++ )
1946 error = ft_hash_str_insert( prop->name, i,
1947 &(font->proptbl), memory );
1953 if ( FT_QALLOC( p->font->internal, sizeof ( FT_HashRec ) ) )
1955 error = ft_hash_str_init( (FT_Hash)p->font->internal, memory );
1958 p->font->spacing = p->opts->font_spacing;
1959 p->font->default_char = ~0UL;
1964 /* Check for the start of the properties. */
1965 if ( _bdf_strncmp( line, "STARTPROPERTIES", 15 ) == 0 )
1967 if ( !( p->flags & BDF_FONT_BBX_ ) )
1969 /* Missing the FONTBOUNDINGBOX field. */
1970 FT_ERROR(( "bdf_parse_start_: " ERRMSG1, lineno, "FONTBOUNDINGBOX" ));
1971 error = FT_THROW( Missing_Fontboundingbox_Field );
1975 error = bdf_list_split_( &p->list, " +", line, linelen );
1979 /* at this point, `p->font' can't be NULL */
1980 p->cnt = p->font->props_size = bdf_atoul_( p->list.field[1] );
1981 /* We need at least 4 bytes per property. */
1982 if ( p->cnt > p->size / 4 )
1984 p->font->props_size = 0;
1986 FT_ERROR(( "bdf_parse_glyphs_: " ERRMSG5, lineno, "STARTPROPERTIES" ));
1987 error = FT_THROW( Invalid_Argument );
1991 if ( FT_NEW_ARRAY( p->font->props, p->cnt ) )
1993 p->font->props_size = 0;
1997 p->flags |= BDF_PROPS_;
1998 *next = bdf_parse_properties_;
2003 /* Check for the FONTBOUNDINGBOX field. */
2004 if ( _bdf_strncmp( line, "FONTBOUNDINGBOX", 15 ) == 0 )
2006 if ( !( p->flags & BDF_SIZE_ ) )
2008 /* Missing the SIZE field. */
2009 FT_ERROR(( "bdf_parse_start_: " ERRMSG1, lineno, "SIZE" ));
2010 error = FT_THROW( Missing_Size_Field );
2014 error = bdf_list_split_( &p->list, " +", line, linelen );
2018 p->font->bbx.width = bdf_atous_( p->list.field[1] );
2019 p->font->bbx.height = bdf_atous_( p->list.field[2] );
2021 p->font->bbx.x_offset = bdf_atos_( p->list.field[3] );
2022 p->font->bbx.y_offset = bdf_atos_( p->list.field[4] );
2024 p->font->bbx.ascent = (short)( p->font->bbx.height +
2025 p->font->bbx.y_offset );
2027 p->font->bbx.descent = (short)( -p->font->bbx.y_offset );
2029 p->flags |= BDF_FONT_BBX_;
2034 /* The next thing to check for is the FONT field. */
2035 if ( _bdf_strncmp( line, "FONT", 4 ) == 0 )
2037 error = bdf_list_split_( &p->list, " +", line, linelen );
2040 bdf_list_shift_( &p->list, 1 );
2042 s = bdf_list_join_( &p->list, ' ', &slen );
2046 FT_ERROR(( "bdf_parse_start_: " ERRMSG8, lineno, "FONT" ));
2047 error = FT_THROW( Invalid_File_Format );
2051 /* Allowing multiple `FONT' lines (which is invalid) doesn't hurt... */
2052 FT_FREE( p->font->name );
2054 if ( FT_QALLOC( p->font->name, slen + 1 ) )
2056 FT_MEM_COPY( p->font->name, s, slen + 1 );
2058 /* If the font name is an XLFD name, set the spacing to the one in */
2059 /* the font name. If there is no spacing fall back on the default. */
2060 error = bdf_set_default_spacing_( p->font, p->opts, lineno );
2064 p->flags |= BDF_FONT_NAME_;
2069 /* Check for the SIZE field. */
2070 if ( _bdf_strncmp( line, "SIZE", 4 ) == 0 )
2072 if ( !( p->flags & BDF_FONT_NAME_ ) )
2074 /* Missing the FONT field. */
2075 FT_ERROR(( "bdf_parse_start_: " ERRMSG1, lineno, "FONT" ));
2076 error = FT_THROW( Missing_Font_Field );
2080 error = bdf_list_split_( &p->list, " +", line, linelen );
2084 p->font->point_size = bdf_atoul_( p->list.field[1] );
2085 p->font->resolution_x = bdf_atoul_( p->list.field[2] );
2086 p->font->resolution_y = bdf_atoul_( p->list.field[3] );
2088 /* Check for the bits per pixel field. */
2089 if ( p->list.used == 5 )
2094 bpp = bdf_atous_( p->list.field[4] );
2096 /* Only values 1, 2, 4, 8 are allowed for greymap fonts. */
2106 if ( p->font->bpp != bpp )
2107 FT_TRACE2(( "bdf_parse_start_: " ACMSG11, p->font->bpp ));
2112 p->flags |= BDF_SIZE_;
2117 /* Check for the CHARS field -- font properties are optional */
2118 if ( _bdf_strncmp( line, "CHARS", 5 ) == 0 )
2123 if ( !( p->flags & BDF_FONT_BBX_ ) )
2125 /* Missing the FONTBOUNDINGBOX field. */
2126 FT_ERROR(( "bdf_parse_start_: " ERRMSG1, lineno, "FONTBOUNDINGBOX" ));
2127 error = FT_THROW( Missing_Fontboundingbox_Field );
2131 /* Add the two standard X11 properties which are required */
2132 /* for compiling fonts. */
2133 p->font->font_ascent = p->font->bbx.ascent;
2134 ft_snprintf( nbuf, BUFSIZE, "%hd", p->font->bbx.ascent );
2135 error = bdf_add_property_( p->font, "FONT_ASCENT",
2139 FT_TRACE2(( "bdf_parse_properties_: " ACMSG1, p->font->bbx.ascent ));
2141 p->font->font_descent = p->font->bbx.descent;
2142 ft_snprintf( nbuf, BUFSIZE, "%hd", p->font->bbx.descent );
2143 error = bdf_add_property_( p->font, "FONT_DESCENT",
2147 FT_TRACE2(( "bdf_parse_properties_: " ACMSG2, p->font->bbx.descent ));
2149 *next = bdf_parse_glyphs_;
2151 /* A special return value. */
2156 FT_ERROR(( "bdf_parse_start_: " ERRMSG9, lineno ));
2157 error = FT_THROW( Invalid_File_Format );
2164 /**************************************************************************
2171 FT_LOCAL_DEF( FT_Error )
2172 bdf_load_font( FT_Stream stream,
2174 bdf_options_t* opts,
2177 unsigned long lineno = 0; /* make compiler happy */
2178 bdf_parse_t_ *p = NULL;
2180 FT_Error error = FT_Err_Ok;
2186 p->opts = (bdf_options_t*)( opts ? opts : &bdf_opts_ );
2188 p->size = stream->size;
2189 p->memory = memory; /* only during font creation */
2191 bdf_list_init_( &p->list, memory );
2193 error = bdf_readstream_( stream, bdf_parse_start_,
2194 (void *)p, &lineno );
2200 /* If the font is not proportional, set the font's monowidth */
2201 /* field to the width of the font bounding box. */
2203 if ( p->font->spacing != BDF_PROPORTIONAL )
2204 p->font->monowidth = p->font->bbx.width;
2206 /* If the number of glyphs loaded is not that of the original count, */
2207 /* indicate the difference. */
2208 if ( p->cnt != p->font->glyphs_used + p->font->unencoded_used )
2210 FT_TRACE2(( "bdf_load_font: " ACMSG15, p->cnt,
2211 p->font->glyphs_used + p->font->unencoded_used ));
2214 /* Once the font has been loaded, adjust the overall font metrics if */
2216 if ( p->opts->correct_metrics != 0 &&
2217 ( p->font->glyphs_used > 0 || p->font->unencoded_used > 0 ) )
2219 if ( p->maxrb - p->minlb != p->font->bbx.width )
2221 FT_TRACE2(( "bdf_load_font: " ACMSG3,
2222 p->font->bbx.width, p->maxrb - p->minlb ));
2223 p->font->bbx.width = (unsigned short)( p->maxrb - p->minlb );
2226 if ( p->font->bbx.x_offset != p->minlb )
2228 FT_TRACE2(( "bdf_load_font: " ACMSG4,
2229 p->font->bbx.x_offset, p->minlb ));
2230 p->font->bbx.x_offset = p->minlb;
2233 if ( p->font->bbx.ascent != p->maxas )
2235 FT_TRACE2(( "bdf_load_font: " ACMSG5,
2236 p->font->bbx.ascent, p->maxas ));
2237 p->font->bbx.ascent = p->maxas;
2240 if ( p->font->bbx.descent != p->maxds )
2242 FT_TRACE2(( "bdf_load_font: " ACMSG6,
2243 p->font->bbx.descent, p->maxds ));
2244 p->font->bbx.descent = p->maxds;
2245 p->font->bbx.y_offset = (short)( -p->maxds );
2248 if ( p->maxas + p->maxds != p->font->bbx.height )
2250 FT_TRACE2(( "bdf_load_font: " ACMSG7,
2251 p->font->bbx.height, p->maxas + p->maxds ));
2252 p->font->bbx.height = (unsigned short)( p->maxas + p->maxds );
2255 if ( p->flags & BDF_SWIDTH_ADJ_ )
2256 FT_TRACE2(( "bdf_load_font: " ACMSG8 ));
2260 if ( p->flags & BDF_START_ )
2262 /* The ENDFONT field was never reached or did not exist. */
2263 if ( !( p->flags & BDF_GLYPHS_ ) )
2265 /* Error happened while parsing header. */
2266 FT_ERROR(( "bdf_load_font: " ERRMSG2, lineno ));
2267 error = FT_THROW( Corrupted_Font_Header );
2272 /* Error happened when parsing glyphs. */
2273 FT_ERROR(( "bdf_load_font: " ERRMSG3, lineno ));
2274 error = FT_THROW( Corrupted_Font_Glyphs );
2279 if ( !p->font && !error )
2280 error = FT_THROW( Invalid_File_Format );
2287 bdf_list_done_( &p->list );
2289 FT_FREE( p->glyph_name );
2296 bdf_free_font( p->font );
2304 FT_LOCAL_DEF( void )
2305 bdf_free_font( bdf_font_t* font )
2307 bdf_property_t* prop;
2309 bdf_glyph_t* glyphs;
2316 memory = font->memory;
2318 FT_FREE( font->name );
2320 /* Free up the internal hash table of property names. */
2321 if ( font->internal )
2323 ft_hash_str_free( (FT_Hash)font->internal, memory );
2324 FT_FREE( font->internal );
2327 /* Free up the comment info. */
2328 FT_FREE( font->comments );
2330 /* Free up the properties. */
2331 for ( i = 0; i < font->props_size; i++ )
2333 if ( font->props[i].format == BDF_ATOM )
2334 FT_FREE( font->props[i].value.atom );
2337 FT_FREE( font->props );
2339 /* Free up the character info. */
2340 for ( i = 0, glyphs = font->glyphs;
2341 i < font->glyphs_used; i++, glyphs++ )
2343 FT_FREE( glyphs->name );
2344 FT_FREE( glyphs->bitmap );
2347 for ( i = 0, glyphs = font->unencoded; i < font->unencoded_used;
2350 FT_FREE( glyphs->name );
2351 FT_FREE( glyphs->bitmap );
2354 FT_FREE( font->glyphs );
2355 FT_FREE( font->unencoded );
2358 ft_hash_str_free( &(font->proptbl), memory );
2360 /* Free up the user defined properties. */
2361 for ( prop = font->user_props, i = 0;
2362 i < font->nuser_props; i++, prop++ )
2363 FT_FREE( prop->name );
2365 FT_FREE( font->user_props );
2367 /* FREE( font ); */ /* XXX Fixme */
2371 FT_LOCAL_DEF( bdf_property_t * )
2372 bdf_get_font_property( bdf_font_t* font,
2378 if ( font == NULL || font->props_size == 0 || name == NULL || *name == 0 )
2381 propid = ft_hash_str_lookup( name, (FT_Hash)font->internal );
2383 return propid ? ( font->props + *propid ) : 0;