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