| 1 | /*  bdfdrivr.c | 
| 2 |  | 
| 3 |     FreeType font driver for bdf files | 
| 4 |  | 
| 5 |     Copyright (C) 2001-2008, 2011, 2013, 2014 by | 
| 6 |     Francesco Zappa Nardelli | 
| 7 |  | 
| 8 | Permission is hereby granted, free of charge, to any person obtaining a copy | 
| 9 | of this software and associated documentation files (the "Software"), to deal | 
| 10 | in the Software without restriction, including without limitation the rights | 
| 11 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | 
| 12 | copies of the Software, and to permit persons to whom the Software is | 
| 13 | furnished to do so, subject to the following conditions: | 
| 14 |  | 
| 15 | The above copyright notice and this permission notice shall be included in | 
| 16 | all copies or substantial portions of the Software. | 
| 17 |  | 
| 18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | 
| 19 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | 
| 20 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE | 
| 21 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | 
| 22 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | 
| 23 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | 
| 24 | THE SOFTWARE. | 
| 25 | */ | 
| 26 |  | 
| 27 |  | 
| 28 | #include <freetype/internal/ftdebug.h> | 
| 29 | #include <freetype/internal/ftstream.h> | 
| 30 | #include <freetype/internal/ftobjs.h> | 
| 31 | #include <freetype/ftbdf.h> | 
| 32 | #include <freetype/ttnameid.h> | 
| 33 |  | 
| 34 | #include <freetype/internal/services/svbdf.h> | 
| 35 | #include <freetype/internal/services/svfntfmt.h> | 
| 36 |  | 
| 37 | #include "bdf.h" | 
| 38 | #include "bdfdrivr.h" | 
| 39 |  | 
| 40 | #include "bdferror.h" | 
| 41 |  | 
| 42 |  | 
| 43 |   /************************************************************************** | 
| 44 |    * | 
| 45 |    * The macro FT_COMPONENT is used in trace mode.  It is an implicit | 
| 46 |    * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log | 
| 47 |    * messages during execution. | 
| 48 |    */ | 
| 49 | #undef  FT_COMPONENT | 
| 50 | #define FT_COMPONENT  bdfdriver | 
| 51 |  | 
| 52 |  | 
| 53 |   typedef struct  BDF_CMapRec_ | 
| 54 |   { | 
| 55 |     FT_CMapRec        cmap; | 
| 56 |     FT_ULong          num_encodings; /* ftobjs.h: FT_CMap->clazz->size */ | 
| 57 |     BDF_encoding_el*  encodings; | 
| 58 |  | 
| 59 |   } BDF_CMapRec, *BDF_CMap; | 
| 60 |  | 
| 61 |  | 
| 62 |   FT_CALLBACK_DEF( FT_Error ) | 
| 63 |   bdf_cmap_init( FT_CMap     bdfcmap, | 
| 64 |                  FT_Pointer  init_data ) | 
| 65 |   { | 
| 66 |     BDF_CMap  cmap = (BDF_CMap)bdfcmap; | 
| 67 |     BDF_Face  face = (BDF_Face)FT_CMAP_FACE( cmap ); | 
| 68 |     FT_UNUSED( init_data ); | 
| 69 |  | 
| 70 |  | 
| 71 |     cmap->num_encodings = face->bdffont->glyphs_used; | 
| 72 |     cmap->encodings     = face->en_table; | 
| 73 |  | 
| 74 |     return FT_Err_Ok; | 
| 75 |   } | 
| 76 |  | 
| 77 |  | 
| 78 |   FT_CALLBACK_DEF( void ) | 
| 79 |   bdf_cmap_done( FT_CMap  bdfcmap ) | 
| 80 |   { | 
| 81 |     BDF_CMap  cmap = (BDF_CMap)bdfcmap; | 
| 82 |  | 
| 83 |  | 
| 84 |     cmap->encodings     = NULL; | 
| 85 |     cmap->num_encodings = 0; | 
| 86 |   } | 
| 87 |  | 
| 88 |  | 
| 89 |   FT_CALLBACK_DEF( FT_UInt ) | 
| 90 |   bdf_cmap_char_index( FT_CMap    bdfcmap, | 
| 91 |                        FT_UInt32  charcode ) | 
| 92 |   { | 
| 93 |     BDF_CMap          cmap      = (BDF_CMap)bdfcmap; | 
| 94 |     BDF_encoding_el*  encodings = cmap->encodings; | 
| 95 |     FT_UShort         result    = 0; /* encodings->glyph */ | 
| 96 |  | 
| 97 |     FT_ULong  min = 0; | 
| 98 |     FT_ULong  max = cmap->num_encodings; | 
| 99 |     FT_ULong  mid = ( min + max ) >> 1; | 
| 100 |  | 
| 101 |  | 
| 102 |     while ( min < max ) | 
| 103 |     { | 
| 104 |       FT_ULong  code = encodings[mid].enc; | 
| 105 |  | 
| 106 |  | 
| 107 |       if ( charcode == code ) | 
| 108 |       { | 
| 109 |         /* increase glyph index by 1 --              */ | 
| 110 |         /* we reserve slot 0 for the undefined glyph */ | 
| 111 |         result = encodings[mid].glyph + 1; | 
| 112 |         break; | 
| 113 |       } | 
| 114 |  | 
| 115 |       if ( charcode < code ) | 
| 116 |         max = mid; | 
| 117 |       else | 
| 118 |         min = mid + 1; | 
| 119 |  | 
| 120 |       /* reasonable prediction in a continuous block */ | 
| 121 |       mid += charcode - code; | 
| 122 |       if ( mid >= max || mid < min ) | 
| 123 |         mid = ( min + max ) >> 1; | 
| 124 |     } | 
| 125 |  | 
| 126 |     return result; | 
| 127 |   } | 
| 128 |  | 
| 129 |  | 
| 130 |   FT_CALLBACK_DEF( FT_UInt ) | 
| 131 |   bdf_cmap_char_next( FT_CMap     bdfcmap, | 
| 132 |                       FT_UInt32  *acharcode ) | 
| 133 |   { | 
| 134 |     BDF_CMap          cmap      = (BDF_CMap)bdfcmap; | 
| 135 |     BDF_encoding_el*  encodings = cmap->encodings; | 
| 136 |     FT_UShort         result   = 0;  /* encodings->glyph */ | 
| 137 |     FT_ULong          charcode = *acharcode + 1; | 
| 138 |  | 
| 139 |     FT_ULong  min = 0; | 
| 140 |     FT_ULong  max = cmap->num_encodings; | 
| 141 |     FT_ULong  mid = ( min + max ) >> 1; | 
| 142 |  | 
| 143 |  | 
| 144 |     while ( min < max ) | 
| 145 |     { | 
| 146 |       FT_ULong  code = encodings[mid].enc; | 
| 147 |  | 
| 148 |  | 
| 149 |       if ( charcode == code ) | 
| 150 |       { | 
| 151 |         /* increase glyph index by 1 --              */ | 
| 152 |         /* we reserve slot 0 for the undefined glyph */ | 
| 153 |         result = encodings[mid].glyph + 1; | 
| 154 |         goto Exit; | 
| 155 |       } | 
| 156 |  | 
| 157 |       if ( charcode < code ) | 
| 158 |         max = mid; | 
| 159 |       else | 
| 160 |         min = mid + 1; | 
| 161 |  | 
| 162 |       /* prediction in a continuous block */ | 
| 163 |       mid += charcode - code; | 
| 164 |       if ( mid >= max || mid < min ) | 
| 165 |         mid = ( min + max ) >> 1; | 
| 166 |     } | 
| 167 |  | 
| 168 |     charcode = 0; | 
| 169 |     if ( min < cmap->num_encodings ) | 
| 170 |     { | 
| 171 |       charcode = encodings[min].enc; | 
| 172 |       result   = encodings[min].glyph + 1; | 
| 173 |     } | 
| 174 |  | 
| 175 |   Exit: | 
| 176 |     if ( charcode > 0xFFFFFFFFUL ) | 
| 177 |     { | 
| 178 |       FT_TRACE1(( "bdf_cmap_char_next: charcode 0x%lx > 32bit API" , | 
| 179 |                   charcode )); | 
| 180 |       *acharcode = 0; | 
| 181 |       /* XXX: result should be changed to indicate an overflow error */ | 
| 182 |     } | 
| 183 |     else | 
| 184 |       *acharcode = (FT_UInt32)charcode; | 
| 185 |     return result; | 
| 186 |   } | 
| 187 |  | 
| 188 |  | 
| 189 |   static | 
| 190 |   const FT_CMap_ClassRec  bdf_cmap_class = | 
| 191 |   { | 
| 192 |     sizeof ( BDF_CMapRec ), | 
| 193 |     bdf_cmap_init, | 
| 194 |     bdf_cmap_done, | 
| 195 |     bdf_cmap_char_index, | 
| 196 |     bdf_cmap_char_next, | 
| 197 |  | 
| 198 |     NULL, NULL, NULL, NULL, NULL | 
| 199 |   }; | 
| 200 |  | 
| 201 |  | 
| 202 |   static FT_Error | 
| 203 |   bdf_interpret_style( BDF_Face  bdf ) | 
| 204 |   { | 
| 205 |     FT_Error         error  = FT_Err_Ok; | 
| 206 |     FT_Face          face   = FT_FACE( bdf ); | 
| 207 |     FT_Memory        memory = face->memory; | 
| 208 |     bdf_font_t*      font   = bdf->bdffont; | 
| 209 |     bdf_property_t*  prop; | 
| 210 |  | 
| 211 |     const char*   strings[4] = { NULL, NULL, NULL, NULL }; | 
| 212 |     size_t        lengths[4], nn, len; | 
| 213 |  | 
| 214 |  | 
| 215 |     face->style_flags = 0; | 
| 216 |  | 
| 217 |     prop = bdf_get_font_property( font, "SLANT"  ); | 
| 218 |     if ( prop && prop->format == BDF_ATOM                             && | 
| 219 |          prop->value.atom                                             && | 
| 220 |          ( *(prop->value.atom) == 'O' || *(prop->value.atom) == 'o' || | 
| 221 |            *(prop->value.atom) == 'I' || *(prop->value.atom) == 'i' ) ) | 
| 222 |     { | 
| 223 |       face->style_flags |= FT_STYLE_FLAG_ITALIC; | 
| 224 |       strings[2] = ( *(prop->value.atom) == 'O' || *(prop->value.atom) == 'o' ) | 
| 225 |                    ? "Oblique"  | 
| 226 |                    : "Italic" ; | 
| 227 |     } | 
| 228 |  | 
| 229 |     prop = bdf_get_font_property( font, "WEIGHT_NAME"  ); | 
| 230 |     if ( prop && prop->format == BDF_ATOM                             && | 
| 231 |          prop->value.atom                                             && | 
| 232 |          ( *(prop->value.atom) == 'B' || *(prop->value.atom) == 'b' ) ) | 
| 233 |     { | 
| 234 |       face->style_flags |= FT_STYLE_FLAG_BOLD; | 
| 235 |       strings[1] = "Bold" ; | 
| 236 |     } | 
| 237 |  | 
| 238 |     prop = bdf_get_font_property( font, "SETWIDTH_NAME"  ); | 
| 239 |     if ( prop && prop->format == BDF_ATOM                              && | 
| 240 |          prop->value.atom && *(prop->value.atom)                       && | 
| 241 |          !( *(prop->value.atom) == 'N' || *(prop->value.atom) == 'n' ) ) | 
| 242 |       strings[3] = (const char *)(prop->value.atom); | 
| 243 |  | 
| 244 |     prop = bdf_get_font_property( font, "ADD_STYLE_NAME"  ); | 
| 245 |     if ( prop && prop->format == BDF_ATOM                              && | 
| 246 |          prop->value.atom && *(prop->value.atom)                       && | 
| 247 |          !( *(prop->value.atom) == 'N' || *(prop->value.atom) == 'n' ) ) | 
| 248 |       strings[0] = (const char *)(prop->value.atom); | 
| 249 |  | 
| 250 |     for ( len = 0, nn = 0; nn < 4; nn++ ) | 
| 251 |     { | 
| 252 |       lengths[nn] = 0; | 
| 253 |       if ( strings[nn] ) | 
| 254 |       { | 
| 255 |         lengths[nn] = ft_strlen( strings[nn] ); | 
| 256 |         len        += lengths[nn] + 1; | 
| 257 |       } | 
| 258 |     } | 
| 259 |  | 
| 260 |     if ( len == 0 ) | 
| 261 |     { | 
| 262 |       strings[0] = "Regular" ; | 
| 263 |       lengths[0] = ft_strlen( strings[0] ); | 
| 264 |       len        = lengths[0] + 1; | 
| 265 |     } | 
| 266 |  | 
| 267 |     { | 
| 268 |       char*  s; | 
| 269 |  | 
| 270 |  | 
| 271 |       if ( FT_QALLOC( face->style_name, len ) ) | 
| 272 |         return error; | 
| 273 |  | 
| 274 |       s = face->style_name; | 
| 275 |  | 
| 276 |       for ( nn = 0; nn < 4; nn++ ) | 
| 277 |       { | 
| 278 |         const char*  src = strings[nn]; | 
| 279 |  | 
| 280 |  | 
| 281 |         len = lengths[nn]; | 
| 282 |  | 
| 283 |         if ( !src ) | 
| 284 |           continue; | 
| 285 |  | 
| 286 |         /* separate elements with a space */ | 
| 287 |         if ( s != face->style_name ) | 
| 288 |           *s++ = ' '; | 
| 289 |  | 
| 290 |         ft_memcpy( s, src, len ); | 
| 291 |  | 
| 292 |         /* need to convert spaces to dashes for */ | 
| 293 |         /* add_style_name and setwidth_name     */ | 
| 294 |         if ( nn == 0 || nn == 3 ) | 
| 295 |         { | 
| 296 |           size_t  mm; | 
| 297 |  | 
| 298 |  | 
| 299 |           for ( mm = 0; mm < len; mm++ ) | 
| 300 |             if ( s[mm] == ' ' ) | 
| 301 |               s[mm] = '-'; | 
| 302 |         } | 
| 303 |  | 
| 304 |         s += len; | 
| 305 |       } | 
| 306 |       *s = 0; | 
| 307 |     } | 
| 308 |  | 
| 309 |     return error; | 
| 310 |   } | 
| 311 |  | 
| 312 |  | 
| 313 |   FT_CALLBACK_DEF( void ) | 
| 314 |   BDF_Face_Done( FT_Face  face )         /* BDF_Face */ | 
| 315 |   { | 
| 316 |     BDF_Face   bdfface = (BDF_Face)face; | 
| 317 |     FT_Memory  memory; | 
| 318 |  | 
| 319 |  | 
| 320 |     if ( !face ) | 
| 321 |       return; | 
| 322 |  | 
| 323 |     memory = FT_FACE_MEMORY( face ); | 
| 324 |  | 
| 325 |     bdf_free_font( bdfface->bdffont ); | 
| 326 |  | 
| 327 |     FT_FREE( bdfface->en_table ); | 
| 328 |  | 
| 329 |     FT_FREE( bdfface->charset_encoding ); | 
| 330 |     FT_FREE( bdfface->charset_registry ); | 
| 331 |     FT_FREE( face->family_name ); | 
| 332 |     FT_FREE( face->style_name ); | 
| 333 |  | 
| 334 |     FT_FREE( face->available_sizes ); | 
| 335 |  | 
| 336 |     FT_FREE( bdfface->bdffont ); | 
| 337 |   } | 
| 338 |  | 
| 339 |  | 
| 340 |   FT_CALLBACK_DEF( FT_Error ) | 
| 341 |   BDF_Face_Init( FT_Stream      stream, | 
| 342 |                  FT_Face        face,        /* BDF_Face */ | 
| 343 |                  FT_Int         face_index, | 
| 344 |                  FT_Int         num_params, | 
| 345 |                  FT_Parameter*  params ) | 
| 346 |   { | 
| 347 |     FT_Error       error   = FT_Err_Ok; | 
| 348 |     BDF_Face       bdfface = (BDF_Face)face; | 
| 349 |     FT_Memory      memory  = FT_FACE_MEMORY( face ); | 
| 350 |  | 
| 351 |     bdf_font_t*    font = NULL; | 
| 352 |     bdf_options_t  options; | 
| 353 |  | 
| 354 |     FT_UNUSED( num_params ); | 
| 355 |     FT_UNUSED( params ); | 
| 356 |  | 
| 357 |  | 
| 358 |     FT_TRACE2(( "BDF driver\n"  )); | 
| 359 |  | 
| 360 |     if ( FT_STREAM_SEEK( 0 ) ) | 
| 361 |       goto Exit; | 
| 362 |  | 
| 363 |     options.correct_metrics = 1;   /* FZ XXX: options semantics */ | 
| 364 |     options.keep_unencoded  = 1; | 
| 365 |     options.keep_comments   = 0; | 
| 366 |     options.font_spacing    = BDF_PROPORTIONAL; | 
| 367 |  | 
| 368 |     error = bdf_load_font( stream, memory, &options, &font ); | 
| 369 |     if ( FT_ERR_EQ( error, Missing_Startfont_Field ) ) | 
| 370 |     { | 
| 371 |       FT_TRACE2(( "  not a BDF file\n"  )); | 
| 372 |       goto Fail; | 
| 373 |     } | 
| 374 |     else if ( error ) | 
| 375 |       goto Exit; | 
| 376 |  | 
| 377 |     /* we have a bdf font: let's construct the face object */ | 
| 378 |     bdfface->bdffont = font; | 
| 379 |  | 
| 380 |     /* BDF cannot have multiple faces in a single font file. | 
| 381 |      * XXX: non-zero face_index is already invalid argument, but | 
| 382 |      *      Type1, Type42 driver has a convention to return | 
| 383 |      *      an invalid argument error when the font could be | 
| 384 |      *      opened by the specified driver. | 
| 385 |      */ | 
| 386 |     if ( face_index > 0 && ( face_index & 0xFFFF ) > 0 ) | 
| 387 |     { | 
| 388 |       FT_ERROR(( "BDF_Face_Init: invalid face index\n"  )); | 
| 389 |       BDF_Face_Done( face ); | 
| 390 |       return FT_THROW( Invalid_Argument ); | 
| 391 |     } | 
| 392 |  | 
| 393 |     { | 
| 394 |       bdf_property_t*  prop = NULL; | 
| 395 |  | 
| 396 |  | 
| 397 |       FT_TRACE4(( "  number of glyphs: allocated %ld (used %ld)\n" , | 
| 398 |                   font->glyphs_size, | 
| 399 |                   font->glyphs_used )); | 
| 400 |       FT_TRACE4(( "  number of unencoded glyphs: allocated %ld (used %ld)\n" , | 
| 401 |                   font->unencoded_size, | 
| 402 |                   font->unencoded_used )); | 
| 403 |  | 
| 404 |       face->num_faces  = 1; | 
| 405 |       face->face_index = 0; | 
| 406 |  | 
| 407 |       face->face_flags |= FT_FACE_FLAG_FIXED_SIZES | | 
| 408 |                           FT_FACE_FLAG_HORIZONTAL; | 
| 409 |  | 
| 410 |       prop = bdf_get_font_property( font, "SPACING"  ); | 
| 411 |       if ( prop && prop->format == BDF_ATOM                             && | 
| 412 |            prop->value.atom                                             && | 
| 413 |            ( *(prop->value.atom) == 'M' || *(prop->value.atom) == 'm' || | 
| 414 |              *(prop->value.atom) == 'C' || *(prop->value.atom) == 'c' ) ) | 
| 415 |         face->face_flags |= FT_FACE_FLAG_FIXED_WIDTH; | 
| 416 |  | 
| 417 |       /* FZ XXX: TO DO: FT_FACE_FLAGS_VERTICAL   */ | 
| 418 |       /* FZ XXX: I need a font to implement this */ | 
| 419 |  | 
| 420 |       prop = bdf_get_font_property( font, "FAMILY_NAME"  ); | 
| 421 |       if ( prop && prop->value.atom ) | 
| 422 |       { | 
| 423 |         if ( FT_STRDUP( face->family_name, prop->value.atom ) ) | 
| 424 |           goto Exit; | 
| 425 |       } | 
| 426 |       else | 
| 427 |         face->family_name = NULL; | 
| 428 |  | 
| 429 |       if ( FT_SET_ERROR( bdf_interpret_style( bdfface ) ) ) | 
| 430 |         goto Exit; | 
| 431 |  | 
| 432 |       /* the number of glyphs (with one slot for the undefined glyph */ | 
| 433 |       /* at position 0 and all unencoded glyphs)                     */ | 
| 434 |       face->num_glyphs = (FT_Long)( font->glyphs_size + 1 ); | 
| 435 |  | 
| 436 |       face->num_fixed_sizes = 1; | 
| 437 |       if ( FT_NEW( face->available_sizes ) ) | 
| 438 |         goto Exit; | 
| 439 |  | 
| 440 |       { | 
| 441 |         FT_Bitmap_Size*  bsize        = face->available_sizes; | 
| 442 |         FT_Short         resolution_x = 0; | 
| 443 |         FT_Short         resolution_y = 0; | 
| 444 |         long             value; | 
| 445 |  | 
| 446 |  | 
| 447 |         /* sanity checks */ | 
| 448 |         if ( font->font_ascent > 0x7FFF || font->font_ascent < -0x7FFF ) | 
| 449 |         { | 
| 450 |           font->font_ascent = font->font_ascent < 0 ? -0x7FFF : 0x7FFF; | 
| 451 |           FT_TRACE0(( "BDF_Face_Init: clamping font ascent to value %ld\n" , | 
| 452 |                       font->font_ascent )); | 
| 453 |         } | 
| 454 |         if ( font->font_descent > 0x7FFF || font->font_descent < -0x7FFF ) | 
| 455 |         { | 
| 456 |           font->font_descent = font->font_descent < 0 ? -0x7FFF : 0x7FFF; | 
| 457 |           FT_TRACE0(( "BDF_Face_Init: clamping font descent to value %ld\n" , | 
| 458 |                       font->font_descent )); | 
| 459 |         } | 
| 460 |  | 
| 461 |         bsize->height = (FT_Short)( font->font_ascent + font->font_descent ); | 
| 462 |  | 
| 463 |         prop = bdf_get_font_property( font, "AVERAGE_WIDTH"  ); | 
| 464 |         if ( prop ) | 
| 465 |         { | 
| 466 | #ifdef FT_DEBUG_LEVEL_TRACE | 
| 467 |           if ( prop->value.l < 0 ) | 
| 468 |             FT_TRACE0(( "BDF_Face_Init: negative average width\n"  )); | 
| 469 | #endif | 
| 470 |           if ( prop->value.l >    0x7FFFL * 10 - 5   || | 
| 471 |                prop->value.l < -( 0x7FFFL * 10 - 5 ) ) | 
| 472 |           { | 
| 473 |             bsize->width = 0x7FFF; | 
| 474 |             FT_TRACE0(( "BDF_Face_Init: clamping average width to value %d\n" , | 
| 475 |                         bsize->width )); | 
| 476 |           } | 
| 477 |           else | 
| 478 |             bsize->width = FT_ABS( (FT_Short)( ( prop->value.l + 5 ) / 10 ) ); | 
| 479 |         } | 
| 480 |         else | 
| 481 |         { | 
| 482 |           /* this is a heuristical value */ | 
| 483 |           bsize->width = ( bsize->height * 2 + 1 ) / 3; | 
| 484 |         } | 
| 485 |  | 
| 486 |         prop = bdf_get_font_property( font, "POINT_SIZE"  ); | 
| 487 |         if ( prop ) | 
| 488 |         { | 
| 489 | #ifdef FT_DEBUG_LEVEL_TRACE | 
| 490 |           if ( prop->value.l < 0 ) | 
| 491 |             FT_TRACE0(( "BDF_Face_Init: negative point size\n"  )); | 
| 492 | #endif | 
| 493 |           /* convert from 722.7 decipoints to 72 points per inch */ | 
| 494 |           if ( prop->value.l >  0x504C2L || /* 0x7FFF * 72270/7200 */ | 
| 495 |                prop->value.l < -0x504C2L ) | 
| 496 |           { | 
| 497 |             bsize->size = 0x7FFF; | 
| 498 |             FT_TRACE0(( "BDF_Face_Init: clamping point size to value %ld\n" , | 
| 499 |                         bsize->size )); | 
| 500 |           } | 
| 501 |           else | 
| 502 |             bsize->size = FT_MulDiv( FT_ABS( prop->value.l ), | 
| 503 |                                      64 * 7200, | 
| 504 |                                      72270L ); | 
| 505 |         } | 
| 506 |         else if ( font->point_size ) | 
| 507 |         { | 
| 508 |           if ( font->point_size > 0x7FFF ) | 
| 509 |           { | 
| 510 |             bsize->size = 0x7FFF; | 
| 511 |             FT_TRACE0(( "BDF_Face_Init: clamping point size to value %ld\n" , | 
| 512 |                         bsize->size )); | 
| 513 |           } | 
| 514 |           else | 
| 515 |             bsize->size = (FT_Pos)font->point_size << 6; | 
| 516 |         } | 
| 517 |         else | 
| 518 |         { | 
| 519 |           /* this is a heuristical value */ | 
| 520 |           bsize->size = bsize->width * 64; | 
| 521 |         } | 
| 522 |  | 
| 523 |         prop = bdf_get_font_property( font, "PIXEL_SIZE"  ); | 
| 524 |         if ( prop ) | 
| 525 |         { | 
| 526 | #ifdef FT_DEBUG_LEVEL_TRACE | 
| 527 |           if ( prop->value.l < 0 ) | 
| 528 |             FT_TRACE0(( "BDF_Face_Init: negative pixel size\n"  )); | 
| 529 | #endif | 
| 530 |           if ( prop->value.l > 0x7FFF || prop->value.l < -0x7FFF ) | 
| 531 |           { | 
| 532 |             bsize->y_ppem = 0x7FFF << 6; | 
| 533 |             FT_TRACE0(( "BDF_Face_Init: clamping pixel size to value %ld\n" , | 
| 534 |                         bsize->y_ppem )); | 
| 535 |           } | 
| 536 |           else | 
| 537 |             bsize->y_ppem = FT_ABS( (FT_Short)prop->value.l ) << 6; | 
| 538 |         } | 
| 539 |  | 
| 540 |         prop = bdf_get_font_property( font, "RESOLUTION_X"  ); | 
| 541 |         if ( prop ) | 
| 542 |           value = prop->value.l; | 
| 543 |         else | 
| 544 |           value = (long)font->resolution_x; | 
| 545 |         if ( value ) | 
| 546 |         { | 
| 547 | #ifdef FT_DEBUG_LEVEL_TRACE | 
| 548 |           if ( value < 0 ) | 
| 549 |             FT_TRACE0(( "BDF_Face_Init: negative X resolution\n"  )); | 
| 550 | #endif | 
| 551 |           if ( value > 0x7FFF || value < -0x7FFF ) | 
| 552 |           { | 
| 553 |             resolution_x = 0x7FFF; | 
| 554 |             FT_TRACE0(( "BDF_Face_Init: clamping X resolution to value %d\n" , | 
| 555 |                         resolution_x )); | 
| 556 |           } | 
| 557 |           else | 
| 558 |             resolution_x = FT_ABS( (FT_Short)value ); | 
| 559 |         } | 
| 560 |  | 
| 561 |         prop = bdf_get_font_property( font, "RESOLUTION_Y"  ); | 
| 562 |         if ( prop ) | 
| 563 |           value = prop->value.l; | 
| 564 |         else | 
| 565 |           value = (long)font->resolution_y; | 
| 566 |         if ( value ) | 
| 567 |         { | 
| 568 | #ifdef FT_DEBUG_LEVEL_TRACE | 
| 569 |           if ( value < 0 ) | 
| 570 |             FT_TRACE0(( "BDF_Face_Init: negative Y resolution\n"  )); | 
| 571 | #endif | 
| 572 |           if ( value > 0x7FFF || value < -0x7FFF ) | 
| 573 |           { | 
| 574 |             resolution_y = 0x7FFF; | 
| 575 |             FT_TRACE0(( "BDF_Face_Init: clamping Y resolution to value %d\n" , | 
| 576 |                         resolution_y )); | 
| 577 |           } | 
| 578 |           else | 
| 579 |             resolution_y = FT_ABS( (FT_Short)value ); | 
| 580 |         } | 
| 581 |  | 
| 582 |         if ( bsize->y_ppem == 0 ) | 
| 583 |         { | 
| 584 |           bsize->y_ppem = bsize->size; | 
| 585 |           if ( resolution_y ) | 
| 586 |             bsize->y_ppem = FT_MulDiv( bsize->y_ppem, resolution_y, 72 ); | 
| 587 |         } | 
| 588 |         if ( resolution_x && resolution_y ) | 
| 589 |           bsize->x_ppem = FT_MulDiv( bsize->y_ppem, | 
| 590 |                                      resolution_x, | 
| 591 |                                      resolution_y ); | 
| 592 |         else | 
| 593 |           bsize->x_ppem = bsize->y_ppem; | 
| 594 |       } | 
| 595 |  | 
| 596 |       /* encoding table */ | 
| 597 |       { | 
| 598 |         bdf_glyph_t*   cur = font->glyphs; | 
| 599 |         unsigned long  n; | 
| 600 |  | 
| 601 |  | 
| 602 |         if ( FT_QNEW_ARRAY( bdfface->en_table, font->glyphs_size ) ) | 
| 603 |           goto Exit; | 
| 604 |  | 
| 605 |         bdfface->default_glyph = 0; | 
| 606 |         for ( n = 0; n < font->glyphs_size; n++ ) | 
| 607 |         { | 
| 608 |           (bdfface->en_table[n]).enc = cur[n].encoding; | 
| 609 |           FT_TRACE4(( "  idx %ld, val 0x%lX\n" , n, cur[n].encoding )); | 
| 610 |           (bdfface->en_table[n]).glyph = (FT_UShort)n; | 
| 611 |  | 
| 612 |           if ( cur[n].encoding == font->default_char ) | 
| 613 |           { | 
| 614 |             if ( n < FT_UINT_MAX ) | 
| 615 |               bdfface->default_glyph = (FT_UInt)n; | 
| 616 |             else | 
| 617 |               FT_TRACE1(( "BDF_Face_Init:"  | 
| 618 |                           " idx %ld is too large for this system\n" , n )); | 
| 619 |           } | 
| 620 |         } | 
| 621 |       } | 
| 622 |  | 
| 623 |       /* charmaps */ | 
| 624 |       { | 
| 625 |         bdf_property_t  *charset_registry, *charset_encoding; | 
| 626 |         FT_Bool          unicode_charmap  = 0; | 
| 627 |  | 
| 628 |  | 
| 629 |         charset_registry = | 
| 630 |           bdf_get_font_property( font, "CHARSET_REGISTRY"  ); | 
| 631 |         charset_encoding = | 
| 632 |           bdf_get_font_property( font, "CHARSET_ENCODING"  ); | 
| 633 |         if ( charset_registry && charset_encoding ) | 
| 634 |         { | 
| 635 |           if ( charset_registry->format == BDF_ATOM && | 
| 636 |                charset_encoding->format == BDF_ATOM && | 
| 637 |                charset_registry->value.atom         && | 
| 638 |                charset_encoding->value.atom         ) | 
| 639 |           { | 
| 640 |             const char*  s; | 
| 641 |  | 
| 642 |  | 
| 643 |             if ( FT_STRDUP( bdfface->charset_encoding, | 
| 644 |                             charset_encoding->value.atom ) || | 
| 645 |                  FT_STRDUP( bdfface->charset_registry, | 
| 646 |                             charset_registry->value.atom ) ) | 
| 647 |               goto Exit; | 
| 648 |  | 
| 649 |             /* Uh, oh, compare first letters manually to avoid dependency */ | 
| 650 |             /* on locales.                                                */ | 
| 651 |             s = bdfface->charset_registry; | 
| 652 |             if ( ( s[0] == 'i' || s[0] == 'I' ) && | 
| 653 |                  ( s[1] == 's' || s[1] == 'S' ) && | 
| 654 |                  ( s[2] == 'o' || s[2] == 'O' ) ) | 
| 655 |             { | 
| 656 |               s += 3; | 
| 657 |               if ( !ft_strcmp( s, "10646"  )                         || | 
| 658 |                    ( !ft_strcmp( s, "8859"  )                      && | 
| 659 |                      !ft_strcmp( bdfface->charset_encoding, "1"  ) ) ) | 
| 660 |                 unicode_charmap = 1; | 
| 661 |               /* another name for ASCII */ | 
| 662 |               else if ( !ft_strcmp( s, "646.1991"  )                    && | 
| 663 |                         !ft_strcmp( bdfface->charset_encoding, "IRV"  ) ) | 
| 664 |                 unicode_charmap = 1; | 
| 665 |             } | 
| 666 |  | 
| 667 |             { | 
| 668 |               FT_CharMapRec  charmap; | 
| 669 |  | 
| 670 |  | 
| 671 |               charmap.face        = face; | 
| 672 |               charmap.encoding    = FT_ENCODING_NONE; | 
| 673 |               /* initial platform/encoding should indicate unset status? */ | 
| 674 |               charmap.platform_id = TT_PLATFORM_APPLE_UNICODE; | 
| 675 |               charmap.encoding_id = TT_APPLE_ID_DEFAULT; | 
| 676 |  | 
| 677 |               if ( unicode_charmap ) | 
| 678 |               { | 
| 679 |                 charmap.encoding    = FT_ENCODING_UNICODE; | 
| 680 |                 charmap.platform_id = TT_PLATFORM_MICROSOFT; | 
| 681 |                 charmap.encoding_id = TT_MS_ID_UNICODE_CS; | 
| 682 |               } | 
| 683 |  | 
| 684 |               error = FT_CMap_New( &bdf_cmap_class, NULL, &charmap, NULL ); | 
| 685 |             } | 
| 686 |  | 
| 687 |             goto Exit; | 
| 688 |           } | 
| 689 |         } | 
| 690 |  | 
| 691 |         /* otherwise assume Adobe standard encoding */ | 
| 692 |  | 
| 693 |         { | 
| 694 |           FT_CharMapRec  charmap; | 
| 695 |  | 
| 696 |  | 
| 697 |           charmap.face        = face; | 
| 698 |           charmap.encoding    = FT_ENCODING_ADOBE_STANDARD; | 
| 699 |           charmap.platform_id = TT_PLATFORM_ADOBE; | 
| 700 |           charmap.encoding_id = TT_ADOBE_ID_STANDARD; | 
| 701 |  | 
| 702 |           error = FT_CMap_New( &bdf_cmap_class, NULL, &charmap, NULL ); | 
| 703 |  | 
| 704 |           /* Select default charmap */ | 
| 705 |           if ( face->num_charmaps ) | 
| 706 |             face->charmap = face->charmaps[0]; | 
| 707 |         } | 
| 708 |       } | 
| 709 |     } | 
| 710 |  | 
| 711 |   Exit: | 
| 712 |     return error; | 
| 713 |  | 
| 714 |   Fail: | 
| 715 |     BDF_Face_Done( face ); | 
| 716 |     return FT_THROW( Unknown_File_Format ); | 
| 717 |   } | 
| 718 |  | 
| 719 |  | 
| 720 |   FT_CALLBACK_DEF( FT_Error ) | 
| 721 |   BDF_Size_Select( FT_Size   size, | 
| 722 |                    FT_ULong  strike_index ) | 
| 723 |   { | 
| 724 |     bdf_font_t*  bdffont = ( (BDF_Face)size->face )->bdffont; | 
| 725 |  | 
| 726 |  | 
| 727 |     FT_Select_Metrics( size->face, strike_index ); | 
| 728 |  | 
| 729 |     size->metrics.ascender    = bdffont->font_ascent * 64; | 
| 730 |     size->metrics.descender   = -bdffont->font_descent * 64; | 
| 731 |     size->metrics.max_advance = bdffont->bbx.width * 64; | 
| 732 |  | 
| 733 |     return FT_Err_Ok; | 
| 734 |   } | 
| 735 |  | 
| 736 |  | 
| 737 |   FT_CALLBACK_DEF( FT_Error ) | 
| 738 |   BDF_Size_Request( FT_Size          size, | 
| 739 |                     FT_Size_Request  req ) | 
| 740 |   { | 
| 741 |     FT_Face          face    = size->face; | 
| 742 |     FT_Bitmap_Size*  bsize   = face->available_sizes; | 
| 743 |     bdf_font_t*      bdffont = ( (BDF_Face)face )->bdffont; | 
| 744 |     FT_Error         error   = FT_ERR( Invalid_Pixel_Size ); | 
| 745 |     FT_Long          height; | 
| 746 |  | 
| 747 |  | 
| 748 |     height = FT_REQUEST_HEIGHT( req ); | 
| 749 |     height = ( height + 32 ) >> 6; | 
| 750 |  | 
| 751 |     switch ( req->type ) | 
| 752 |     { | 
| 753 |     case FT_SIZE_REQUEST_TYPE_NOMINAL: | 
| 754 |       if ( height == ( ( bsize->y_ppem + 32 ) >> 6 ) ) | 
| 755 |         error = FT_Err_Ok; | 
| 756 |       break; | 
| 757 |  | 
| 758 |     case FT_SIZE_REQUEST_TYPE_REAL_DIM: | 
| 759 |       if ( height == ( bdffont->font_ascent + | 
| 760 |                        bdffont->font_descent ) ) | 
| 761 |         error = FT_Err_Ok; | 
| 762 |       break; | 
| 763 |  | 
| 764 |     default: | 
| 765 |       error = FT_THROW( Unimplemented_Feature ); | 
| 766 |       break; | 
| 767 |     } | 
| 768 |  | 
| 769 |     if ( error ) | 
| 770 |       return error; | 
| 771 |     else | 
| 772 |       return BDF_Size_Select( size, 0 ); | 
| 773 |   } | 
| 774 |  | 
| 775 |  | 
| 776 |  | 
| 777 |   FT_CALLBACK_DEF( FT_Error ) | 
| 778 |   BDF_Glyph_Load( FT_GlyphSlot  slot, | 
| 779 |                   FT_Size       size, | 
| 780 |                   FT_UInt       glyph_index, | 
| 781 |                   FT_Int32      load_flags ) | 
| 782 |   { | 
| 783 |     BDF_Face     bdf    = (BDF_Face)FT_SIZE_FACE( size ); | 
| 784 |     FT_Face      face   = FT_FACE( bdf ); | 
| 785 |     FT_Error     error  = FT_Err_Ok; | 
| 786 |     FT_Bitmap*   bitmap = &slot->bitmap; | 
| 787 |     bdf_glyph_t  glyph; | 
| 788 |     int          bpp    = bdf->bdffont->bpp; | 
| 789 |  | 
| 790 |     FT_UNUSED( load_flags ); | 
| 791 |  | 
| 792 |  | 
| 793 |     if ( !face ) | 
| 794 |     { | 
| 795 |       error = FT_THROW( Invalid_Face_Handle ); | 
| 796 |       goto Exit; | 
| 797 |     } | 
| 798 |  | 
| 799 |     if ( glyph_index >= (FT_UInt)face->num_glyphs ) | 
| 800 |     { | 
| 801 |       error = FT_THROW( Invalid_Argument ); | 
| 802 |       goto Exit; | 
| 803 |     } | 
| 804 |  | 
| 805 |     FT_TRACE1(( "BDF_Glyph_Load: glyph index %d\n" , glyph_index )); | 
| 806 |  | 
| 807 |     /* index 0 is the undefined glyph */ | 
| 808 |     if ( glyph_index == 0 ) | 
| 809 |       glyph_index = bdf->default_glyph; | 
| 810 |     else | 
| 811 |       glyph_index--; | 
| 812 |  | 
| 813 |     /* slot, bitmap => freetype, glyph => bdflib */ | 
| 814 |     glyph = bdf->bdffont->glyphs[glyph_index]; | 
| 815 |  | 
| 816 |     bitmap->rows  = glyph.bbx.height; | 
| 817 |     bitmap->width = glyph.bbx.width; | 
| 818 |     if ( glyph.bpr > FT_INT_MAX ) | 
| 819 |       FT_TRACE1(( "BDF_Glyph_Load: too large pitch %ld is truncated\n" , | 
| 820 |                    glyph.bpr )); | 
| 821 |     bitmap->pitch = (int)glyph.bpr; /* same as FT_Bitmap.pitch */ | 
| 822 |  | 
| 823 |     /* note: we don't allocate a new array to hold the bitmap; */ | 
| 824 |     /*       we can simply point to it                         */ | 
| 825 |     ft_glyphslot_set_bitmap( slot, glyph.bitmap ); | 
| 826 |  | 
| 827 |     switch ( bpp ) | 
| 828 |     { | 
| 829 |     case 1: | 
| 830 |       bitmap->pixel_mode = FT_PIXEL_MODE_MONO; | 
| 831 |       break; | 
| 832 |     case 2: | 
| 833 |       bitmap->pixel_mode = FT_PIXEL_MODE_GRAY2; | 
| 834 |       break; | 
| 835 |     case 4: | 
| 836 |       bitmap->pixel_mode = FT_PIXEL_MODE_GRAY4; | 
| 837 |       break; | 
| 838 |     case 8: | 
| 839 |       bitmap->pixel_mode = FT_PIXEL_MODE_GRAY; | 
| 840 |       bitmap->num_grays  = 256; | 
| 841 |       break; | 
| 842 |     } | 
| 843 |  | 
| 844 |     slot->format      = FT_GLYPH_FORMAT_BITMAP; | 
| 845 |     slot->bitmap_left = glyph.bbx.x_offset; | 
| 846 |     slot->bitmap_top  = glyph.bbx.ascent; | 
| 847 |  | 
| 848 |     slot->metrics.horiAdvance  = (FT_Pos)( glyph.dwidth * 64 ); | 
| 849 |     slot->metrics.horiBearingX = (FT_Pos)( glyph.bbx.x_offset * 64 ); | 
| 850 |     slot->metrics.horiBearingY = (FT_Pos)( glyph.bbx.ascent * 64 ); | 
| 851 |     slot->metrics.width        = (FT_Pos)( bitmap->width * 64 ); | 
| 852 |     slot->metrics.height       = (FT_Pos)( bitmap->rows * 64 ); | 
| 853 |  | 
| 854 |     /* | 
| 855 |      * XXX DWIDTH1 and VVECTOR should be parsed and | 
| 856 |      * used here, provided such fonts do exist. | 
| 857 |      */ | 
| 858 |     ft_synthesize_vertical_metrics( &slot->metrics, | 
| 859 |                                     bdf->bdffont->bbx.height * 64 ); | 
| 860 |  | 
| 861 |   Exit: | 
| 862 |     return error; | 
| 863 |   } | 
| 864 |  | 
| 865 |  | 
| 866 |  /* | 
| 867 |   * | 
| 868 |   * BDF SERVICE | 
| 869 |   * | 
| 870 |   */ | 
| 871 |  | 
| 872 |   FT_CALLBACK_DEF( FT_Error ) | 
| 873 |   bdf_get_bdf_property( FT_Face           face,       /* BDF_Face */ | 
| 874 |                         const char*       prop_name, | 
| 875 |                         BDF_PropertyRec  *aproperty ) | 
| 876 |   { | 
| 877 |     BDF_Face         bdfface = (BDF_Face)face; | 
| 878 |     bdf_property_t*  prop; | 
| 879 |  | 
| 880 |  | 
| 881 |     FT_ASSERT( bdfface && bdfface->bdffont ); | 
| 882 |  | 
| 883 |     prop = bdf_get_font_property( bdfface->bdffont, prop_name ); | 
| 884 |     if ( prop ) | 
| 885 |     { | 
| 886 |       switch ( prop->format ) | 
| 887 |       { | 
| 888 |       case BDF_ATOM: | 
| 889 |         aproperty->type   = BDF_PROPERTY_TYPE_ATOM; | 
| 890 |         aproperty->u.atom = prop->value.atom; | 
| 891 |         break; | 
| 892 |  | 
| 893 |       case BDF_INTEGER: | 
| 894 |         if ( prop->value.l > 0x7FFFFFFFL || prop->value.l < ( -1 - 0x7FFFFFFFL ) ) | 
| 895 |         { | 
| 896 |           FT_TRACE1(( "bdf_get_bdf_property:"  | 
| 897 |                       " too large integer 0x%lx is truncated\n" , | 
| 898 |                       prop->value.l )); | 
| 899 |         } | 
| 900 |         aproperty->type      = BDF_PROPERTY_TYPE_INTEGER; | 
| 901 |         aproperty->u.integer = (FT_Int32)prop->value.l; | 
| 902 |         break; | 
| 903 |  | 
| 904 |       case BDF_CARDINAL: | 
| 905 |         if ( prop->value.ul > 0xFFFFFFFFUL ) | 
| 906 |         { | 
| 907 |           FT_TRACE1(( "bdf_get_bdf_property:"  | 
| 908 |                       " too large cardinal 0x%lx is truncated\n" , | 
| 909 |                       prop->value.ul )); | 
| 910 |         } | 
| 911 |         aproperty->type       = BDF_PROPERTY_TYPE_CARDINAL; | 
| 912 |         aproperty->u.cardinal = (FT_UInt32)prop->value.ul; | 
| 913 |         break; | 
| 914 |  | 
| 915 |       default: | 
| 916 |         goto Fail; | 
| 917 |       } | 
| 918 |       return 0; | 
| 919 |     } | 
| 920 |  | 
| 921 |   Fail: | 
| 922 |     return FT_THROW( Invalid_Argument ); | 
| 923 |   } | 
| 924 |  | 
| 925 |  | 
| 926 |   FT_CALLBACK_DEF( FT_Error ) | 
| 927 |   bdf_get_charset_id( FT_Face       face,               /* BDF_Face */ | 
| 928 |                       const char*  *acharset_encoding, | 
| 929 |                       const char*  *acharset_registry ) | 
| 930 |   { | 
| 931 |     BDF_Face  bdfface = (BDF_Face)face; | 
| 932 |  | 
| 933 |  | 
| 934 |     *acharset_encoding = bdfface->charset_encoding; | 
| 935 |     *acharset_registry = bdfface->charset_registry; | 
| 936 |  | 
| 937 |     return 0; | 
| 938 |   } | 
| 939 |  | 
| 940 |  | 
| 941 |   static const FT_Service_BDFRec  bdf_service_bdf = | 
| 942 |   { | 
| 943 |     (FT_BDF_GetCharsetIdFunc)bdf_get_charset_id,       /* get_charset_id */ | 
| 944 |     (FT_BDF_GetPropertyFunc) bdf_get_bdf_property      /* get_property   */ | 
| 945 |   }; | 
| 946 |  | 
| 947 |  | 
| 948 |  /* | 
| 949 |   * | 
| 950 |   * SERVICES LIST | 
| 951 |   * | 
| 952 |   */ | 
| 953 |  | 
| 954 |   static const FT_ServiceDescRec  bdf_services[] = | 
| 955 |   { | 
| 956 |     { FT_SERVICE_ID_BDF,         &bdf_service_bdf }, | 
| 957 |     { FT_SERVICE_ID_FONT_FORMAT, FT_FONT_FORMAT_BDF }, | 
| 958 |     { NULL, NULL } | 
| 959 |   }; | 
| 960 |  | 
| 961 |  | 
| 962 |   FT_CALLBACK_DEF( FT_Module_Interface ) | 
| 963 |   bdf_driver_requester( FT_Module    module, | 
| 964 |                         const char*  name ) | 
| 965 |   { | 
| 966 |     FT_UNUSED( module ); | 
| 967 |  | 
| 968 |     return ft_service_list_lookup( bdf_services, name ); | 
| 969 |   } | 
| 970 |  | 
| 971 |  | 
| 972 |   FT_CALLBACK_TABLE_DEF | 
| 973 |   const FT_Driver_ClassRec  bdf_driver_class = | 
| 974 |   { | 
| 975 |     { | 
| 976 |       FT_MODULE_FONT_DRIVER         | | 
| 977 |       FT_MODULE_DRIVER_NO_OUTLINES, | 
| 978 |       sizeof ( FT_DriverRec ), | 
| 979 |  | 
| 980 |       "bdf" , | 
| 981 |       0x10000L, | 
| 982 |       0x20000L, | 
| 983 |  | 
| 984 |       NULL,    /* module-specific interface */ | 
| 985 |  | 
| 986 |       NULL,                     /* FT_Module_Constructor  module_init   */ | 
| 987 |       NULL,                     /* FT_Module_Destructor   module_done   */ | 
| 988 |       bdf_driver_requester      /* FT_Module_Requester    get_interface */ | 
| 989 |     }, | 
| 990 |  | 
| 991 |     sizeof ( BDF_FaceRec ), | 
| 992 |     sizeof ( FT_SizeRec ), | 
| 993 |     sizeof ( FT_GlyphSlotRec ), | 
| 994 |  | 
| 995 |     BDF_Face_Init,              /* FT_Face_InitFunc  init_face */ | 
| 996 |     BDF_Face_Done,              /* FT_Face_DoneFunc  done_face */ | 
| 997 |     NULL,                       /* FT_Size_InitFunc  init_size */ | 
| 998 |     NULL,                       /* FT_Size_DoneFunc  done_size */ | 
| 999 |     NULL,                       /* FT_Slot_InitFunc  init_slot */ | 
| 1000 |     NULL,                       /* FT_Slot_DoneFunc  done_slot */ | 
| 1001 |  | 
| 1002 |     BDF_Glyph_Load,             /* FT_Slot_LoadFunc  load_glyph */ | 
| 1003 |  | 
| 1004 |     NULL,                       /* FT_Face_GetKerningFunc   get_kerning  */ | 
| 1005 |     NULL,                       /* FT_Face_AttachFunc       attach_file  */ | 
| 1006 |     NULL,                       /* FT_Face_GetAdvancesFunc  get_advances */ | 
| 1007 |  | 
| 1008 |     BDF_Size_Request,           /* FT_Size_RequestFunc  request_size */ | 
| 1009 |     BDF_Size_Select             /* FT_Size_SelectFunc   select_size  */ | 
| 1010 |   }; | 
| 1011 |  | 
| 1012 |  | 
| 1013 | /* END */ | 
| 1014 |  |