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                              FT_FACE_FLAG_FAST_GLYPHS;
    406 
    407       prop = bdf_get_font_property( font, "SPACING" );
    408       if ( prop && prop->format == BDF_ATOM                             &&
    409            prop->value.atom                                             &&
    410            ( *(prop->value.atom) == 'M' || *(prop->value.atom) == 'm' ||
    411              *(prop->value.atom) == 'C' || *(prop->value.atom) == 'c' ) )
    412         bdfface->face_flags |= FT_FACE_FLAG_FIXED_WIDTH;
    413 
    414       /* FZ XXX: TO DO: FT_FACE_FLAGS_VERTICAL   */
    415       /* FZ XXX: I need a font to implement this */
    416 
    417       prop = bdf_get_font_property( font, "FAMILY_NAME" );
    418       if ( prop && prop->value.atom )
    419       {
    420         if ( FT_STRDUP( bdfface->family_name, prop->value.atom ) )
    421           goto Exit;
    422       }
    423       else
    424         bdfface->family_name = NULL;
    425 
    426       if ( FT_SET_ERROR( bdf_interpret_style( face ) ) )
    427         goto Exit;
    428 
    429       /* the number of glyphs (with one slot for the undefined glyph */
    430       /* at position 0 and all unencoded glyphs)                     */
    431       bdfface->num_glyphs = (FT_Long)( font->glyphs_size + 1 );
    432 
    433       bdfface->num_fixed_sizes = 1;
    434       if ( FT_NEW_ARRAY( bdfface->available_sizes, 1 ) )
    435         goto Exit;
    436 
    437       {
    438         FT_Bitmap_Size*  bsize = bdfface->available_sizes;
    439         FT_Short         resolution_x = 0, resolution_y = 0;
    440         long             value;
    441 
    442 
    443         FT_ZERO( bsize );
    444 
    445         /* sanity checks */
    446         if ( font->font_ascent > 0x7FFF || font->font_ascent < -0x7FFF )
    447         {
    448           font->font_ascent = font->font_ascent < 0 ? -0x7FFF : 0x7FFF;
    449           FT_TRACE0(( "BDF_Face_Init: clamping font ascent to value %d\n",
    450                       font->font_ascent ));
    451         }
    452         if ( font->font_descent > 0x7FFF || font->font_descent < -0x7FFF )
    453         {
    454           font->font_descent = font->font_descent < 0 ? -0x7FFF : 0x7FFF;
    455           FT_TRACE0(( "BDF_Face_Init: clamping font descent to value %d\n",
    456                       font->font_descent ));
    457         }
    458 
    459         bsize->height = (FT_Short)( font->font_ascent + font->font_descent );
    460 
    461         prop = bdf_get_font_property( font, "AVERAGE_WIDTH" );
    462         if ( prop )
    463         {
    464 #ifdef FT_DEBUG_LEVEL_TRACE
    465           if ( prop->value.l < 0 )
    466             FT_TRACE0(( "BDF_Face_Init: negative average width\n" ));
    467 #endif
    468           if ( prop->value.l >    0x7FFFL * 10 - 5   ||
    469                prop->value.l < -( 0x7FFFL * 10 - 5 ) )
    470           {
    471             bsize->width = 0x7FFF;
    472             FT_TRACE0(( "BDF_Face_Init: clamping average width to value %d\n",
    473                         bsize->width ));
    474           }
    475           else
    476             bsize->width = FT_ABS( (FT_Short)( ( prop->value.l + 5 ) / 10 ) );
    477         }
    478         else
    479         {
    480           /* this is a heuristical value */
    481           bsize->width = (FT_Short)FT_MulDiv( bsize->height, 2, 3 );
    482         }
    483 
    484         prop = bdf_get_font_property( font, "POINT_SIZE" );
    485         if ( prop )
    486         {
    487 #ifdef FT_DEBUG_LEVEL_TRACE
    488           if ( prop->value.l < 0 )
    489             FT_TRACE0(( "BDF_Face_Init: negative point size\n" ));
    490 #endif
    491           /* convert from 722.7 decipoints to 72 points per inch */
    492           if ( prop->value.l >  0x504C2L || /* 0x7FFF * 72270/7200 */
    493                prop->value.l < -0x504C2L )
    494           {
    495             bsize->size = 0x7FFF;
    496             FT_TRACE0(( "BDF_Face_Init: clamping point size to value %d\n",
    497                         bsize->size ));
    498           }
    499           else
    500             bsize->size = FT_MulDiv( FT_ABS( prop->value.l ),
    501                                      64 * 7200,
    502                                      72270L );
    503         }
    504         else if ( font->point_size )
    505         {
    506           if ( font->point_size > 0x7FFF )
    507           {
    508             bsize->size = 0x7FFF;
    509             FT_TRACE0(( "BDF_Face_Init: clamping point size to value %d\n",
    510                         bsize->size ));
    511           }
    512           else
    513             bsize->size = (FT_Pos)font->point_size << 6;
    514         }
    515         else
    516         {
    517           /* this is a heuristical value */
    518           bsize->size = bsize->width * 64;
    519         }
    520 
    521         prop = bdf_get_font_property( font, "PIXEL_SIZE" );
    522         if ( prop )
    523         {
    524 #ifdef FT_DEBUG_LEVEL_TRACE
    525           if ( prop->value.l < 0 )
    526             FT_TRACE0(( "BDF_Face_Init: negative pixel size\n" ));
    527 #endif
    528           if ( prop->value.l > 0x7FFF || prop->value.l < -0x7FFF )
    529           {
    530             bsize->y_ppem = 0x7FFF << 6;
    531             FT_TRACE0(( "BDF_Face_Init: clamping pixel size to value %d\n",
    532                         bsize->y_ppem ));
    533           }
    534           else
    535             bsize->y_ppem = FT_ABS( (FT_Short)prop->value.l ) << 6;
    536         }
    537 
    538         prop = bdf_get_font_property( font, "RESOLUTION_X" );
    539         if ( prop )
    540           value = prop->value.l;
    541         else
    542           value = (long)font->resolution_x;
    543         if ( value )
    544         {
    545 #ifdef FT_DEBUG_LEVEL_TRACE
    546           if ( value < 0 )
    547             FT_TRACE0(( "BDF_Face_Init: negative X resolution\n" ));
    548 #endif
    549           if ( value > 0x7FFF || value < -0x7FFF )
    550           {
    551             resolution_x = 0x7FFF;
    552             FT_TRACE0(( "BDF_Face_Init: clamping X resolution to value %d\n",
    553                         resolution_x ));
    554           }
    555           else
    556             resolution_x = FT_ABS( (FT_Short)value );
    557         }
    558 
    559         prop = bdf_get_font_property( font, "RESOLUTION_Y" );
    560         if ( prop )
    561           value = prop->value.l;
    562         else
    563           value = (long)font->resolution_y;
    564         if ( value )
    565         {
    566 #ifdef FT_DEBUG_LEVEL_TRACE
    567           if ( value < 0 )
    568             FT_TRACE0(( "BDF_Face_Init: negative Y resolution\n" ));
    569 #endif
    570           if ( value > 0x7FFF || value < -0x7FFF )
    571           {
    572             resolution_y = 0x7FFF;
    573             FT_TRACE0(( "BDF_Face_Init: clamping Y resolution to value %d\n",
    574                         resolution_y ));
    575           }
    576           else
    577             resolution_y = FT_ABS( (FT_Short)value );
    578         }
    579 
    580         if ( bsize->y_ppem == 0 )
    581         {
    582           bsize->y_ppem = bsize->size;
    583           if ( resolution_y )
    584             bsize->y_ppem = FT_MulDiv( bsize->y_ppem, resolution_y, 72 );
    585         }
    586         if ( resolution_x && resolution_y )
    587           bsize->x_ppem = FT_MulDiv( bsize->y_ppem,
    588                                      resolution_x,
    589                                      resolution_y );
    590         else
    591           bsize->x_ppem = bsize->y_ppem;
    592       }
    593 
    594       /* encoding table */
    595       {
    596         bdf_glyph_t*   cur = font->glyphs;
    597         unsigned long  n;
    598 
    599 
    600         if ( FT_NEW_ARRAY( face->en_table, font->glyphs_size ) )
    601           goto Exit;
    602 
    603         face->default_glyph = 0;
    604         for ( n = 0; n < font->glyphs_size; n++ )
    605         {
    606           (face->en_table[n]).enc = cur[n].encoding;
    607           FT_TRACE4(( "  idx %d, val 0x%lX\n", n, cur[n].encoding ));
    608           (face->en_table[n]).glyph = (FT_UShort)n;
    609 
    610           if ( cur[n].encoding == font->default_char )
    611           {
    612             if ( n < FT_UINT_MAX )
    613               face->default_glyph = (FT_UInt)n;
    614             else
    615               FT_TRACE1(( "BDF_Face_Init:"
    616                           " idx %d is too large for this system\n", n ));
    617           }
    618         }
    619       }
    620 
    621       /* charmaps */
    622       {
    623         bdf_property_t  *charset_registry, *charset_encoding;
    624         FT_Bool          unicode_charmap  = 0;
    625 
    626 
    627         charset_registry =
    628           bdf_get_font_property( font, "CHARSET_REGISTRY" );
    629         charset_encoding =
    630           bdf_get_font_property( font, "CHARSET_ENCODING" );
    631         if ( charset_registry && charset_encoding )
    632         {
    633           if ( charset_registry->format == BDF_ATOM &&
    634                charset_encoding->format == BDF_ATOM &&
    635                charset_registry->value.atom         &&
    636                charset_encoding->value.atom         )
    637           {
    638             const char*  s;
    639 
    640 
    641             if ( FT_STRDUP( face->charset_encoding,
    642                             charset_encoding->value.atom ) ||
    643                  FT_STRDUP( face->charset_registry,
    644                             charset_registry->value.atom ) )
    645               goto Exit;
    646 
    647             /* Uh, oh, compare first letters manually to avoid dependency */
    648             /* on locales.                                                */
    649             s = face->charset_registry;
    650             if ( ( s[0] == 'i' || s[0] == 'I' ) &&
    651                  ( s[1] == 's' || s[1] == 'S' ) &&
    652                  ( s[2] == 'o' || s[2] == 'O' ) )
    653             {
    654               s += 3;
    655               if ( !ft_strcmp( s, "10646" )                      ||
    656                    ( !ft_strcmp( s, "8859" ) &&
    657                      !ft_strcmp( face->charset_encoding, "1" ) ) )
    658                 unicode_charmap = 1;
    659               /* another name for ASCII */
    660               else if ( !ft_strcmp( s, "646.1991" )                 &&
    661                         !ft_strcmp( face->charset_encoding, "IRV" ) )
    662                 unicode_charmap = 1;
    663             }
    664 
    665             {
    666               FT_CharMapRec  charmap;
    667 
    668 
    669               charmap.face        = FT_FACE( face );
    670               charmap.encoding    = FT_ENCODING_NONE;
    671               /* initial platform/encoding should indicate unset status? */
    672               charmap.platform_id = TT_PLATFORM_APPLE_UNICODE;
    673               charmap.encoding_id = TT_APPLE_ID_DEFAULT;
    674 
    675               if ( unicode_charmap )
    676               {
    677                 charmap.encoding    = FT_ENCODING_UNICODE;
    678                 charmap.platform_id = TT_PLATFORM_MICROSOFT;
    679                 charmap.encoding_id = TT_MS_ID_UNICODE_CS;
    680               }
    681 
    682               error = FT_CMap_New( &bdf_cmap_class, NULL, &charmap, NULL );
    683             }
    684 
    685             goto Exit;
    686           }
    687         }
    688 
    689         /* otherwise assume Adobe standard encoding */
    690 
    691         {
    692           FT_CharMapRec  charmap;
    693 
    694 
    695           charmap.face        = FT_FACE( face );
    696           charmap.encoding    = FT_ENCODING_ADOBE_STANDARD;
    697           charmap.platform_id = TT_PLATFORM_ADOBE;
    698           charmap.encoding_id = TT_ADOBE_ID_STANDARD;
    699 
    700           error = FT_CMap_New( &bdf_cmap_class, NULL, &charmap, NULL );
    701 
    702           /* Select default charmap */
    703           if ( bdfface->num_charmaps )
    704             bdfface->charmap = bdfface->charmaps[0];
    705         }
    706       }
    707     }
    708 
    709   Exit:
    710     return error;
    711 
    712   Fail:
    713     BDF_Face_Done( bdfface );
    714     return FT_THROW( Unknown_File_Format );
    715   }
    716 
    717 
    718   FT_CALLBACK_DEF( FT_Error )
    719   BDF_Size_Select( FT_Size   size,
    720                    FT_ULong  strike_index )
    721   {
    722     bdf_font_t*  bdffont = ( (BDF_Face)size->face )->bdffont;
    723 
    724 
    725     FT_Select_Metrics( size->face, strike_index );
    726 
    727     size->metrics.ascender    = bdffont->font_ascent * 64;
    728     size->metrics.descender   = -bdffont->font_descent * 64;
    729     size->metrics.max_advance = bdffont->bbx.width * 64;
    730 
    731     return FT_Err_Ok;
    732   }
    733 
    734 
    735   FT_CALLBACK_DEF( FT_Error )
    736   BDF_Size_Request( FT_Size          size,
    737                     FT_Size_Request  req )
    738   {
    739     FT_Face          face    = size->face;
    740     FT_Bitmap_Size*  bsize   = face->available_sizes;
    741     bdf_font_t*      bdffont = ( (BDF_Face)face )->bdffont;
    742     FT_Error         error   = FT_ERR( Invalid_Pixel_Size );
    743     FT_Long          height;
    744 
    745 
    746     height = FT_REQUEST_HEIGHT( req );
    747     height = ( height + 32 ) >> 6;
    748 
    749     switch ( req->type )
    750     {
    751     case FT_SIZE_REQUEST_TYPE_NOMINAL:
    752       if ( height == ( ( bsize->y_ppem + 32 ) >> 6 ) )
    753         error = FT_Err_Ok;
    754       break;
    755 
    756     case FT_SIZE_REQUEST_TYPE_REAL_DIM:
    757       if ( height == ( bdffont->font_ascent +
    758                        bdffont->font_descent ) )
    759         error = FT_Err_Ok;
    760       break;
    761 
    762     default:
    763       error = FT_THROW( Unimplemented_Feature );
    764       break;
    765     }
    766 
    767     if ( error )
    768       return error;
    769     else
    770       return BDF_Size_Select( size, 0 );
    771   }
    772 
    773 
    774 
    775   FT_CALLBACK_DEF( FT_Error )
    776   BDF_Glyph_Load( FT_GlyphSlot  slot,
    777                   FT_Size       size,
    778                   FT_UInt       glyph_index,
    779                   FT_Int32      load_flags )
    780   {
    781     BDF_Face     bdf    = (BDF_Face)FT_SIZE_FACE( size );
    782     FT_Face      face   = FT_FACE( bdf );
    783     FT_Error     error  = FT_Err_Ok;
    784     FT_Bitmap*   bitmap = &slot->bitmap;
    785     bdf_glyph_t  glyph;
    786     int          bpp    = bdf->bdffont->bpp;
    787 
    788     FT_UNUSED( load_flags );
    789 
    790 
    791     if ( !face )
    792     {
    793       error = FT_THROW( Invalid_Face_Handle );
    794       goto Exit;
    795     }
    796 
    797     if ( glyph_index >= (FT_UInt)face->num_glyphs )
    798     {
    799       error = FT_THROW( Invalid_Argument );
    800       goto Exit;
    801     }
    802 
    803     FT_TRACE1(( "BDF_Glyph_Load: glyph index %d\n", glyph_index ));
    804 
    805     /* index 0 is the undefined glyph */
    806     if ( glyph_index == 0 )
    807       glyph_index = bdf->default_glyph;
    808     else
    809       glyph_index--;
    810 
    811     /* slot, bitmap => freetype, glyph => bdflib */
    812     glyph = bdf->bdffont->glyphs[glyph_index];
    813 
    814     bitmap->rows  = glyph.bbx.height;
    815     bitmap->width = glyph.bbx.width;
    816     if ( glyph.bpr > FT_INT_MAX )
    817       FT_TRACE1(( "BDF_Glyph_Load: too large pitch %d is truncated\n",
    818                    glyph.bpr ));
    819     bitmap->pitch = (int)glyph.bpr; /* same as FT_Bitmap.pitch */
    820 
    821     /* note: we don't allocate a new array to hold the bitmap; */
    822     /*       we can simply point to it                         */
    823     ft_glyphslot_set_bitmap( slot, glyph.bitmap );
    824 
    825     switch ( bpp )
    826     {
    827     case 1:
    828       bitmap->pixel_mode = FT_PIXEL_MODE_MONO;
    829       break;
    830     case 2:
    831       bitmap->pixel_mode = FT_PIXEL_MODE_GRAY2;
    832       break;
    833     case 4:
    834       bitmap->pixel_mode = FT_PIXEL_MODE_GRAY4;
    835       break;
    836     case 8:
    837       bitmap->pixel_mode = FT_PIXEL_MODE_GRAY;
    838       bitmap->num_grays  = 256;
    839       break;
    840     }
    841 
    842     slot->format      = FT_GLYPH_FORMAT_BITMAP;
    843     slot->bitmap_left = glyph.bbx.x_offset;
    844     slot->bitmap_top  = glyph.bbx.ascent;
    845 
    846     slot->metrics.horiAdvance  = (FT_Pos)( glyph.dwidth * 64 );
    847     slot->metrics.horiBearingX = (FT_Pos)( glyph.bbx.x_offset * 64 );
    848     slot->metrics.horiBearingY = (FT_Pos)( glyph.bbx.ascent * 64 );
    849     slot->metrics.width        = (FT_Pos)( bitmap->width * 64 );
    850     slot->metrics.height       = (FT_Pos)( bitmap->rows * 64 );
    851 
    852     /*
    853      * XXX DWIDTH1 and VVECTOR should be parsed and
    854      * used here, provided such fonts do exist.
    855      */
    856     ft_synthesize_vertical_metrics( &slot->metrics,
    857                                     bdf->bdffont->bbx.height * 64 );
    858 
    859   Exit:
    860     return error;
    861   }
    862 
    863 
    864  /*
    865   *
    866   *  BDF SERVICE
    867   *
    868   */
    869 
    870   static FT_Error
    871   bdf_get_bdf_property( BDF_Face          face,
    872                         const char*       prop_name,
    873                         BDF_PropertyRec  *aproperty )
    874   {
    875     bdf_property_t*  prop;
    876 
    877 
    878     FT_ASSERT( face && face->bdffont );
    879 
    880     prop = bdf_get_font_property( face->bdffont, prop_name );
    881     if ( prop )
    882     {
    883       switch ( prop->format )
    884       {
    885       case BDF_ATOM:
    886         aproperty->type   = BDF_PROPERTY_TYPE_ATOM;
    887         aproperty->u.atom = prop->value.atom;
    888         break;
    889 
    890       case BDF_INTEGER:
    891         if ( prop->value.l > 0x7FFFFFFFL || prop->value.l < ( -1 - 0x7FFFFFFFL ) )
    892         {
    893           FT_TRACE1(( "bdf_get_bdf_property:"
    894                       " too large integer 0x%x is truncated\n" ));
    895         }
    896         aproperty->type      = BDF_PROPERTY_TYPE_INTEGER;
    897         aproperty->u.integer = (FT_Int32)prop->value.l;
    898         break;
    899 
    900       case BDF_CARDINAL:
    901         if ( prop->value.ul > 0xFFFFFFFFUL )
    902         {
    903           FT_TRACE1(( "bdf_get_bdf_property:"
    904                       " too large cardinal 0x%x is truncated\n" ));
    905         }
    906         aproperty->type       = BDF_PROPERTY_TYPE_CARDINAL;
    907         aproperty->u.cardinal = (FT_UInt32)prop->value.ul;
    908         break;
    909 
    910       default:
    911         goto Fail;
    912       }
    913       return 0;
    914     }
    915 
    916   Fail:
    917     return FT_THROW( Invalid_Argument );
    918   }
    919 
    920 
    921   static FT_Error
    922   bdf_get_charset_id( BDF_Face      face,
    923                       const char*  *acharset_encoding,
    924                       const char*  *acharset_registry )
    925   {
    926     *acharset_encoding = face->charset_encoding;
    927     *acharset_registry = face->charset_registry;
    928 
    929     return 0;
    930   }
    931 
    932 
    933   static const FT_Service_BDFRec  bdf_service_bdf =
    934   {
    935     (FT_BDF_GetCharsetIdFunc)bdf_get_charset_id,       /* get_charset_id */
    936     (FT_BDF_GetPropertyFunc) bdf_get_bdf_property      /* get_property   */
    937   };
    938 
    939 
    940  /*
    941   *
    942   *  SERVICES LIST
    943   *
    944   */
    945 
    946   static const FT_ServiceDescRec  bdf_services[] =
    947   {
    948     { FT_SERVICE_ID_BDF,         &bdf_service_bdf },
    949     { FT_SERVICE_ID_FONT_FORMAT, FT_FONT_FORMAT_BDF },
    950     { NULL, NULL }
    951   };
    952 
    953 
    954   FT_CALLBACK_DEF( FT_Module_Interface )
    955   bdf_driver_requester( FT_Module    module,
    956                         const char*  name )
    957   {
    958     FT_UNUSED( module );
    959 
    960     return ft_service_list_lookup( bdf_services, name );
    961   }
    962 
    963 
    964 
    965   FT_CALLBACK_TABLE_DEF
    966   const FT_Driver_ClassRec  bdf_driver_class =
    967   {
    968     {
    969       FT_MODULE_FONT_DRIVER         |
    970       FT_MODULE_DRIVER_NO_OUTLINES,
    971       sizeof ( FT_DriverRec ),
    972 
    973       "bdf",
    974       0x10000L,
    975       0x20000L,
    976 
    977       NULL,    /* module-specific interface */
    978 
    979       NULL,                     /* FT_Module_Constructor  module_init   */
    980       NULL,                     /* FT_Module_Destructor   module_done   */
    981       bdf_driver_requester      /* FT_Module_Requester    get_interface */
    982     },
    983 
    984     sizeof ( BDF_FaceRec ),
    985     sizeof ( FT_SizeRec ),
    986     sizeof ( FT_GlyphSlotRec ),
    987 
    988     BDF_Face_Init,              /* FT_Face_InitFunc  init_face */
    989     BDF_Face_Done,              /* FT_Face_DoneFunc  done_face */
    990     NULL,                       /* FT_Size_InitFunc  init_size */
    991     NULL,                       /* FT_Size_DoneFunc  done_size */
    992     NULL,                       /* FT_Slot_InitFunc  init_slot */
    993     NULL,                       /* FT_Slot_DoneFunc  done_slot */
    994 
    995     BDF_Glyph_Load,             /* FT_Slot_LoadFunc  load_glyph */
    996 
    997     NULL,                       /* FT_Face_GetKerningFunc   get_kerning  */
    998     NULL,                       /* FT_Face_AttachFunc       attach_file  */
    999     NULL,                       /* FT_Face_GetAdvancesFunc  get_advances */
   1000 
   1001     BDF_Size_Request,           /* FT_Size_RequestFunc  request_size */
   1002     BDF_Size_Select             /* FT_Size_SelectFunc   select_size  */
   1003   };
   1004 
   1005 
   1006 /* END */
   1007