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