Home | History | Annotate | Download | only in pcf
      1 /*  pcfdrivr.c
      2 
      3     FreeType font driver for pcf files
      4 
      5     Copyright (C) 2000-2004, 2006-2011, 2013, 2014 by
      6     Francesco Zappa Nardelli
      7 
      8 Permission is hereby granted, free of charge, to any person obtaining a copy
      9 of this software and associated documentation files (the "Software"), to deal
     10 in the Software without restriction, including without limitation the rights
     11 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
     12 copies of the Software, and to permit persons to whom the Software is
     13 furnished to do so, subject to the following conditions:
     14 
     15 The above copyright notice and this permission notice shall be included in
     16 all copies or substantial portions of the Software.
     17 
     18 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     19 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     20 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
     21 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     22 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
     23 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
     24 THE SOFTWARE.
     25 */
     26 
     27 
     28 #include <ft2build.h>
     29 
     30 #include FT_INTERNAL_DEBUG_H
     31 #include FT_INTERNAL_STREAM_H
     32 #include FT_INTERNAL_OBJECTS_H
     33 #include FT_GZIP_H
     34 #include FT_LZW_H
     35 #include FT_BZIP2_H
     36 #include FT_ERRORS_H
     37 #include FT_BDF_H
     38 #include FT_TRUETYPE_IDS_H
     39 
     40 #include "pcf.h"
     41 #include "pcfdrivr.h"
     42 #include "pcfread.h"
     43 
     44 #include "pcferror.h"
     45 #include "pcfutil.h"
     46 
     47 #undef  FT_COMPONENT
     48 #define FT_COMPONENT  trace_pcfread
     49 
     50 #include FT_SERVICE_BDF_H
     51 #include FT_SERVICE_FONT_FORMAT_H
     52 #include FT_SERVICE_PROPERTIES_H
     53 #include FT_DRIVER_H
     54 
     55 
     56   /*************************************************************************/
     57   /*                                                                       */
     58   /* The macro FT_COMPONENT is used in trace mode.  It is an implicit      */
     59   /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log  */
     60   /* messages during execution.                                            */
     61   /*                                                                       */
     62 #undef  FT_COMPONENT
     63 #define FT_COMPONENT  trace_pcfdriver
     64 
     65 
     66   typedef struct  PCF_CMapRec_
     67   {
     68     FT_CMapRec    root;
     69     FT_ULong      num_encodings;
     70     PCF_Encoding  encodings;
     71 
     72   } PCF_CMapRec, *PCF_CMap;
     73 
     74 
     75   FT_CALLBACK_DEF( FT_Error )
     76   pcf_cmap_init( FT_CMap     pcfcmap,   /* PCF_CMap */
     77                  FT_Pointer  init_data )
     78   {
     79     PCF_CMap  cmap = (PCF_CMap)pcfcmap;
     80     PCF_Face  face = (PCF_Face)FT_CMAP_FACE( pcfcmap );
     81 
     82     FT_UNUSED( init_data );
     83 
     84 
     85     cmap->num_encodings = face->nencodings;
     86     cmap->encodings     = face->encodings;
     87 
     88     return FT_Err_Ok;
     89   }
     90 
     91 
     92   FT_CALLBACK_DEF( void )
     93   pcf_cmap_done( FT_CMap  pcfcmap )         /* PCF_CMap */
     94   {
     95     PCF_CMap  cmap = (PCF_CMap)pcfcmap;
     96 
     97 
     98     cmap->encodings     = NULL;
     99     cmap->num_encodings = 0;
    100   }
    101 
    102 
    103   FT_CALLBACK_DEF( FT_UInt )
    104   pcf_cmap_char_index( FT_CMap    pcfcmap,  /* PCF_CMap */
    105                        FT_UInt32  charcode )
    106   {
    107     PCF_CMap      cmap      = (PCF_CMap)pcfcmap;
    108     PCF_Encoding  encodings = cmap->encodings;
    109     FT_ULong      min, max, mid;
    110     FT_UInt       result    = 0;
    111 
    112 
    113     min = 0;
    114     max = cmap->num_encodings;
    115 
    116     while ( min < max )
    117     {
    118       FT_ULong  code;
    119 
    120 
    121       mid  = ( min + max ) >> 1;
    122       code = (FT_ULong)encodings[mid].enc;
    123 
    124       if ( charcode == code )
    125       {
    126         result = encodings[mid].glyph + 1;
    127         break;
    128       }
    129 
    130       if ( charcode < code )
    131         max = mid;
    132       else
    133         min = mid + 1;
    134     }
    135 
    136     return result;
    137   }
    138 
    139 
    140   FT_CALLBACK_DEF( FT_UInt )
    141   pcf_cmap_char_next( FT_CMap    pcfcmap,   /* PCF_CMap */
    142                       FT_UInt32  *acharcode )
    143   {
    144     PCF_CMap      cmap      = (PCF_CMap)pcfcmap;
    145     PCF_Encoding  encodings = cmap->encodings;
    146     FT_ULong      min, max, mid;
    147     FT_ULong      charcode  = *acharcode + 1;
    148     FT_UInt       result    = 0;
    149 
    150 
    151     min = 0;
    152     max = cmap->num_encodings;
    153 
    154     while ( min < max )
    155     {
    156       FT_ULong  code;
    157 
    158 
    159       mid  = ( min + max ) >> 1;
    160       code = (FT_ULong)encodings[mid].enc;
    161 
    162       if ( charcode == code )
    163       {
    164         result = encodings[mid].glyph + 1;
    165         goto Exit;
    166       }
    167 
    168       if ( charcode < code )
    169         max = mid;
    170       else
    171         min = mid + 1;
    172     }
    173 
    174     charcode = 0;
    175     if ( min < cmap->num_encodings )
    176     {
    177       charcode = (FT_ULong)encodings[min].enc;
    178       result   = encodings[min].glyph + 1;
    179     }
    180 
    181   Exit:
    182     if ( charcode > 0xFFFFFFFFUL )
    183     {
    184       FT_TRACE1(( "pcf_cmap_char_next: charcode 0x%x > 32bit API" ));
    185       *acharcode = 0;
    186       /* XXX: result should be changed to indicate an overflow error */
    187     }
    188     else
    189       *acharcode = (FT_UInt32)charcode;
    190     return result;
    191   }
    192 
    193 
    194   static
    195   const FT_CMap_ClassRec  pcf_cmap_class =
    196   {
    197     sizeof ( PCF_CMapRec ),
    198     pcf_cmap_init,
    199     pcf_cmap_done,
    200     pcf_cmap_char_index,
    201     pcf_cmap_char_next,
    202 
    203     NULL, NULL, NULL, NULL, NULL
    204   };
    205 
    206 
    207   FT_CALLBACK_DEF( void )
    208   PCF_Face_Done( FT_Face  pcfface )         /* PCF_Face */
    209   {
    210     PCF_Face   face = (PCF_Face)pcfface;
    211     FT_Memory  memory;
    212 
    213 
    214     if ( !face )
    215       return;
    216 
    217     memory = FT_FACE_MEMORY( face );
    218 
    219     FT_FREE( face->encodings );
    220     FT_FREE( face->metrics );
    221 
    222     /* free properties */
    223     if ( face->properties )
    224     {
    225       FT_Int  i;
    226 
    227 
    228       for ( i = 0; i < face->nprops; i++ )
    229       {
    230         PCF_Property  prop = &face->properties[i];
    231 
    232 
    233         if ( prop )
    234         {
    235           FT_FREE( prop->name );
    236           if ( prop->isString )
    237             FT_FREE( prop->value.atom );
    238         }
    239       }
    240 
    241       FT_FREE( face->properties );
    242     }
    243 
    244     FT_FREE( face->toc.tables );
    245     FT_FREE( pcfface->family_name );
    246     FT_FREE( pcfface->style_name );
    247     FT_FREE( pcfface->available_sizes );
    248     FT_FREE( face->charset_encoding );
    249     FT_FREE( face->charset_registry );
    250 
    251     /* close compressed stream if any */
    252     if ( pcfface->stream == &face->comp_stream )
    253     {
    254       FT_Stream_Close( &face->comp_stream );
    255       pcfface->stream = face->comp_source;
    256     }
    257   }
    258 
    259 
    260   FT_CALLBACK_DEF( FT_Error )
    261   PCF_Face_Init( FT_Stream      stream,
    262                  FT_Face        pcfface,        /* PCF_Face */
    263                  FT_Int         face_index,
    264                  FT_Int         num_params,
    265                  FT_Parameter*  params )
    266   {
    267     PCF_Face  face  = (PCF_Face)pcfface;
    268     FT_Error  error;
    269 
    270     FT_UNUSED( num_params );
    271     FT_UNUSED( params );
    272 
    273 
    274     FT_TRACE2(( "PCF driver\n" ));
    275 
    276     error = pcf_load_font( stream, face, face_index );
    277     if ( error )
    278     {
    279       PCF_Face_Done( pcfface );
    280 
    281 #if defined( FT_CONFIG_OPTION_USE_ZLIB )  || \
    282     defined( FT_CONFIG_OPTION_USE_LZW )   || \
    283     defined( FT_CONFIG_OPTION_USE_BZIP2 )
    284 
    285 #ifdef FT_CONFIG_OPTION_USE_ZLIB
    286       {
    287         FT_Error  error2;
    288 
    289 
    290         /* this didn't work, try gzip support! */
    291         FT_TRACE2(( "  ... try gzip stream\n" ));
    292         error2 = FT_Stream_OpenGzip( &face->comp_stream, stream );
    293         if ( FT_ERR_EQ( error2, Unimplemented_Feature ) )
    294           goto Fail;
    295 
    296         error = error2;
    297       }
    298 #endif /* FT_CONFIG_OPTION_USE_ZLIB */
    299 
    300 #ifdef FT_CONFIG_OPTION_USE_LZW
    301       if ( error )
    302       {
    303         FT_Error  error3;
    304 
    305 
    306         /* this didn't work, try LZW support! */
    307         FT_TRACE2(( "  ... try LZW stream\n" ));
    308         error3 = FT_Stream_OpenLZW( &face->comp_stream, stream );
    309         if ( FT_ERR_EQ( error3, Unimplemented_Feature ) )
    310           goto Fail;
    311 
    312         error = error3;
    313       }
    314 #endif /* FT_CONFIG_OPTION_USE_LZW */
    315 
    316 #ifdef FT_CONFIG_OPTION_USE_BZIP2
    317       if ( error )
    318       {
    319         FT_Error  error4;
    320 
    321 
    322         /* this didn't work, try Bzip2 support! */
    323         FT_TRACE2(( "  ... try Bzip2 stream\n" ));
    324         error4 = FT_Stream_OpenBzip2( &face->comp_stream, stream );
    325         if ( FT_ERR_EQ( error4, Unimplemented_Feature ) )
    326           goto Fail;
    327 
    328         error = error4;
    329       }
    330 #endif /* FT_CONFIG_OPTION_USE_BZIP2 */
    331 
    332       if ( error )
    333         goto Fail;
    334 
    335       face->comp_source = stream;
    336       pcfface->stream   = &face->comp_stream;
    337 
    338       stream = pcfface->stream;
    339 
    340       error = pcf_load_font( stream, face, face_index );
    341       if ( error )
    342         goto Fail;
    343 
    344 #else /* !(FT_CONFIG_OPTION_USE_ZLIB ||
    345            FT_CONFIG_OPTION_USE_LZW ||
    346            FT_CONFIG_OPTION_USE_BZIP2) */
    347 
    348       goto Fail;
    349 
    350 #endif
    351     }
    352 
    353     /* PCF cannot have multiple faces in a single font file.
    354      * XXX: A non-zero face_index is already an invalid argument, but
    355      *      Type1, Type42 drivers have a convention to return
    356      *      an invalid argument error when the font could be
    357      *      opened by the specified driver.
    358      */
    359     if ( face_index < 0 )
    360       goto Exit;
    361     else if ( face_index > 0 && ( face_index & 0xFFFF ) > 0 )
    362     {
    363       FT_ERROR(( "PCF_Face_Init: invalid face index\n" ));
    364       PCF_Face_Done( pcfface );
    365       return FT_THROW( Invalid_Argument );
    366     }
    367 
    368     /* set up charmap */
    369     {
    370       FT_String  *charset_registry = face->charset_registry;
    371       FT_String  *charset_encoding = face->charset_encoding;
    372       FT_Bool     unicode_charmap  = 0;
    373 
    374 
    375       if ( charset_registry && charset_encoding )
    376       {
    377         char*  s = charset_registry;
    378 
    379 
    380         /* Uh, oh, compare first letters manually to avoid dependency
    381            on locales. */
    382         if ( ( s[0] == 'i' || s[0] == 'I' ) &&
    383              ( s[1] == 's' || s[1] == 'S' ) &&
    384              ( s[2] == 'o' || s[2] == 'O' ) )
    385         {
    386           s += 3;
    387           if ( !ft_strcmp( s, "10646" )                      ||
    388                ( !ft_strcmp( s, "8859" ) &&
    389                  !ft_strcmp( face->charset_encoding, "1" ) ) )
    390             unicode_charmap = 1;
    391           /* another name for ASCII */
    392           else if ( !ft_strcmp( s, "646.1991" )                 &&
    393                     !ft_strcmp( face->charset_encoding, "IRV" ) )
    394             unicode_charmap = 1;
    395         }
    396       }
    397 
    398       {
    399         FT_CharMapRec  charmap;
    400 
    401 
    402         charmap.face        = FT_FACE( face );
    403         charmap.encoding    = FT_ENCODING_NONE;
    404         /* initial platform/encoding should indicate unset status? */
    405         charmap.platform_id = TT_PLATFORM_APPLE_UNICODE;
    406         charmap.encoding_id = TT_APPLE_ID_DEFAULT;
    407 
    408         if ( unicode_charmap )
    409         {
    410           charmap.encoding    = FT_ENCODING_UNICODE;
    411           charmap.platform_id = TT_PLATFORM_MICROSOFT;
    412           charmap.encoding_id = TT_MS_ID_UNICODE_CS;
    413         }
    414 
    415         error = FT_CMap_New( &pcf_cmap_class, NULL, &charmap, NULL );
    416       }
    417     }
    418 
    419   Exit:
    420     return error;
    421 
    422   Fail:
    423     FT_TRACE2(( "  not a PCF file\n" ));
    424     PCF_Face_Done( pcfface );
    425     error = FT_THROW( Unknown_File_Format );  /* error */
    426     goto Exit;
    427   }
    428 
    429 
    430   FT_CALLBACK_DEF( FT_Error )
    431   PCF_Size_Select( FT_Size   size,
    432                    FT_ULong  strike_index )
    433   {
    434     PCF_Accel  accel = &( (PCF_Face)size->face )->accel;
    435 
    436 
    437     FT_Select_Metrics( size->face, strike_index );
    438 
    439     size->metrics.ascender    =  accel->fontAscent * 64;
    440     size->metrics.descender   = -accel->fontDescent * 64;
    441     size->metrics.max_advance =  accel->maxbounds.characterWidth * 64;
    442 
    443     return FT_Err_Ok;
    444   }
    445 
    446 
    447   FT_CALLBACK_DEF( FT_Error )
    448   PCF_Size_Request( FT_Size          size,
    449                     FT_Size_Request  req )
    450   {
    451     PCF_Face         face  = (PCF_Face)size->face;
    452     FT_Bitmap_Size*  bsize = size->face->available_sizes;
    453     FT_Error         error = FT_ERR( Invalid_Pixel_Size );
    454     FT_Long          height;
    455 
    456 
    457     height = FT_REQUEST_HEIGHT( req );
    458     height = ( height + 32 ) >> 6;
    459 
    460     switch ( req->type )
    461     {
    462     case FT_SIZE_REQUEST_TYPE_NOMINAL:
    463       if ( height == ( ( bsize->y_ppem + 32 ) >> 6 ) )
    464         error = FT_Err_Ok;
    465       break;
    466 
    467     case FT_SIZE_REQUEST_TYPE_REAL_DIM:
    468       if ( height == ( face->accel.fontAscent +
    469                        face->accel.fontDescent ) )
    470         error = FT_Err_Ok;
    471       break;
    472 
    473     default:
    474       error = FT_THROW( Unimplemented_Feature );
    475       break;
    476     }
    477 
    478     if ( error )
    479       return error;
    480     else
    481       return PCF_Size_Select( size, 0 );
    482   }
    483 
    484 
    485   FT_CALLBACK_DEF( FT_Error )
    486   PCF_Glyph_Load( FT_GlyphSlot  slot,
    487                   FT_Size       size,
    488                   FT_UInt       glyph_index,
    489                   FT_Int32      load_flags )
    490   {
    491     PCF_Face    face   = (PCF_Face)FT_SIZE_FACE( size );
    492     FT_Stream   stream;
    493     FT_Error    error  = FT_Err_Ok;
    494     FT_Bitmap*  bitmap = &slot->bitmap;
    495     PCF_Metric  metric;
    496     FT_ULong    bytes;
    497 
    498 
    499     FT_TRACE1(( "PCF_Glyph_Load: glyph index %d\n", glyph_index ));
    500 
    501     if ( !face )
    502     {
    503       error = FT_THROW( Invalid_Face_Handle );
    504       goto Exit;
    505     }
    506 
    507     if ( glyph_index >= (FT_UInt)face->root.num_glyphs )
    508     {
    509       error = FT_THROW( Invalid_Argument );
    510       goto Exit;
    511     }
    512 
    513     stream = face->root.stream;
    514 
    515     if ( glyph_index > 0 )
    516       glyph_index--;
    517 
    518     metric = face->metrics + glyph_index;
    519 
    520     bitmap->rows       = (unsigned int)( metric->ascent +
    521                                          metric->descent );
    522     bitmap->width      = (unsigned int)( metric->rightSideBearing -
    523                                          metric->leftSideBearing );
    524     bitmap->num_grays  = 1;
    525     bitmap->pixel_mode = FT_PIXEL_MODE_MONO;
    526 
    527     switch ( PCF_GLYPH_PAD( face->bitmapsFormat ) )
    528     {
    529     case 1:
    530       bitmap->pitch = (int)( ( bitmap->width + 7 ) >> 3 );
    531       break;
    532 
    533     case 2:
    534       bitmap->pitch = (int)( ( ( bitmap->width + 15 ) >> 4 ) << 1 );
    535       break;
    536 
    537     case 4:
    538       bitmap->pitch = (int)( ( ( bitmap->width + 31 ) >> 5 ) << 2 );
    539       break;
    540 
    541     case 8:
    542       bitmap->pitch = (int)( ( ( bitmap->width + 63 ) >> 6 ) << 3 );
    543       break;
    544 
    545     default:
    546       return FT_THROW( Invalid_File_Format );
    547     }
    548 
    549     slot->format      = FT_GLYPH_FORMAT_BITMAP;
    550     slot->bitmap_left = metric->leftSideBearing;
    551     slot->bitmap_top  = metric->ascent;
    552 
    553     slot->metrics.horiAdvance  = (FT_Pos)( metric->characterWidth * 64 );
    554     slot->metrics.horiBearingX = (FT_Pos)( metric->leftSideBearing * 64 );
    555     slot->metrics.horiBearingY = (FT_Pos)( metric->ascent * 64 );
    556     slot->metrics.width        = (FT_Pos)( ( metric->rightSideBearing -
    557                                              metric->leftSideBearing ) * 64 );
    558     slot->metrics.height       = (FT_Pos)( bitmap->rows * 64 );
    559 
    560     ft_synthesize_vertical_metrics( &slot->metrics,
    561                                     ( face->accel.fontAscent +
    562                                       face->accel.fontDescent ) * 64 );
    563 
    564     if ( load_flags & FT_LOAD_BITMAP_METRICS_ONLY )
    565       goto Exit;
    566 
    567     /* XXX: to do: are there cases that need repadding the bitmap? */
    568     bytes = (FT_ULong)bitmap->pitch * bitmap->rows;
    569 
    570     error = ft_glyphslot_alloc_bitmap( slot, (FT_ULong)bytes );
    571     if ( error )
    572       goto Exit;
    573 
    574     if ( FT_STREAM_SEEK( metric->bits )          ||
    575          FT_STREAM_READ( bitmap->buffer, bytes ) )
    576       goto Exit;
    577 
    578     if ( PCF_BIT_ORDER( face->bitmapsFormat ) != MSBFirst )
    579       BitOrderInvert( bitmap->buffer, bytes );
    580 
    581     if ( ( PCF_BYTE_ORDER( face->bitmapsFormat ) !=
    582            PCF_BIT_ORDER( face->bitmapsFormat )  ) )
    583     {
    584       switch ( PCF_SCAN_UNIT( face->bitmapsFormat ) )
    585       {
    586       case 1:
    587         break;
    588 
    589       case 2:
    590         TwoByteSwap( bitmap->buffer, bytes );
    591         break;
    592 
    593       case 4:
    594         FourByteSwap( bitmap->buffer, bytes );
    595         break;
    596       }
    597     }
    598 
    599   Exit:
    600     return error;
    601   }
    602 
    603 
    604  /*
    605   *
    606   *  BDF SERVICE
    607   *
    608   */
    609 
    610   static FT_Error
    611   pcf_get_bdf_property( PCF_Face          face,
    612                         const char*       prop_name,
    613                         BDF_PropertyRec  *aproperty )
    614   {
    615     PCF_Property  prop;
    616 
    617 
    618     prop = pcf_find_property( face, prop_name );
    619     if ( prop )
    620     {
    621       if ( prop->isString )
    622       {
    623         aproperty->type   = BDF_PROPERTY_TYPE_ATOM;
    624         aproperty->u.atom = prop->value.atom;
    625       }
    626       else
    627       {
    628         if ( prop->value.l > 0x7FFFFFFFL          ||
    629              prop->value.l < ( -1 - 0x7FFFFFFFL ) )
    630         {
    631           FT_TRACE1(( "pcf_get_bdf_property:" ));
    632           FT_TRACE1(( " too large integer 0x%x is truncated\n" ));
    633         }
    634 
    635         /*
    636          *  The PCF driver loads all properties as signed integers.
    637          *  This really doesn't seem to be a problem, because this is
    638          *  sufficient for any meaningful values.
    639          */
    640         aproperty->type      = BDF_PROPERTY_TYPE_INTEGER;
    641         aproperty->u.integer = (FT_Int32)prop->value.l;
    642       }
    643 
    644       return FT_Err_Ok;
    645     }
    646 
    647     return FT_THROW( Invalid_Argument );
    648   }
    649 
    650 
    651   static FT_Error
    652   pcf_get_charset_id( PCF_Face      face,
    653                       const char*  *acharset_encoding,
    654                       const char*  *acharset_registry )
    655   {
    656     *acharset_encoding = face->charset_encoding;
    657     *acharset_registry = face->charset_registry;
    658 
    659     return FT_Err_Ok;
    660   }
    661 
    662 
    663   static const FT_Service_BDFRec  pcf_service_bdf =
    664   {
    665     (FT_BDF_GetCharsetIdFunc)pcf_get_charset_id,     /* get_charset_id */
    666     (FT_BDF_GetPropertyFunc) pcf_get_bdf_property    /* get_property   */
    667   };
    668 
    669 
    670   /*
    671    *  PROPERTY SERVICE
    672    *
    673    */
    674   static FT_Error
    675   pcf_property_set( FT_Module    module,         /* PCF_Driver */
    676                     const char*  property_name,
    677                     const void*  value,
    678                     FT_Bool      value_is_string )
    679   {
    680 #ifdef PCF_CONFIG_OPTION_LONG_FAMILY_NAMES
    681 
    682     FT_Error    error  = FT_Err_Ok;
    683     PCF_Driver  driver = (PCF_Driver)module;
    684 
    685 #ifndef FT_CONFIG_OPTION_ENVIRONMENT_PROPERTIES
    686     FT_UNUSED( value_is_string );
    687 #endif
    688 
    689 
    690     if ( !ft_strcmp( property_name, "no-long-family-names" ) )
    691     {
    692 #ifdef FT_CONFIG_OPTION_ENVIRONMENT_PROPERTIES
    693       if ( value_is_string )
    694       {
    695         const char*  s   = (const char*)value;
    696         long         lfn = ft_strtol( s, NULL, 10 );
    697 
    698 
    699         if ( lfn == 0 )
    700           driver->no_long_family_names = 0;
    701         else if ( lfn == 1 )
    702           driver->no_long_family_names = 1;
    703         else
    704           return FT_THROW( Invalid_Argument );
    705       }
    706       else
    707 #endif
    708       {
    709         FT_Bool*  no_long_family_names = (FT_Bool*)value;
    710 
    711 
    712         driver->no_long_family_names = *no_long_family_names;
    713       }
    714 
    715       return error;
    716     }
    717 
    718 #else /* !PCF_CONFIG_OPTION_LONG_FAMILY_NAMES */
    719 
    720     FT_UNUSED( module );
    721     FT_UNUSED( value );
    722     FT_UNUSED( value_is_string );
    723 #ifndef FT_DEBUG_LEVEL_TRACE
    724     FT_UNUSED( property_name );
    725 #endif
    726 
    727 #endif /* !PCF_CONFIG_OPTION_LONG_FAMILY_NAMES */
    728 
    729     FT_TRACE0(( "pcf_property_set: missing property `%s'\n",
    730                 property_name ));
    731     return FT_THROW( Missing_Property );
    732   }
    733 
    734 
    735   static FT_Error
    736   pcf_property_get( FT_Module    module,         /* PCF_Driver */
    737                     const char*  property_name,
    738                     const void*  value )
    739   {
    740 #ifdef PCF_CONFIG_OPTION_LONG_FAMILY_NAMES
    741 
    742     FT_Error    error  = FT_Err_Ok;
    743     PCF_Driver  driver = (PCF_Driver)module;
    744 
    745 
    746     if ( !ft_strcmp( property_name, "no-long-family-names" ) )
    747     {
    748       FT_Bool   no_long_family_names = driver->no_long_family_names;
    749       FT_Bool*  val                  = (FT_Bool*)value;
    750 
    751 
    752       *val = no_long_family_names;
    753 
    754       return error;
    755     }
    756 
    757 #else /* !PCF_CONFIG_OPTION_LONG_FAMILY_NAMES */
    758 
    759     FT_UNUSED( module );
    760     FT_UNUSED( value );
    761 #ifndef FT_DEBUG_LEVEL_TRACE
    762     FT_UNUSED( property_name );
    763 #endif
    764 
    765 #endif /* !PCF_CONFIG_OPTION_LONG_FAMILY_NAMES */
    766 
    767     FT_TRACE0(( "pcf_property_get: missing property `%s'\n",
    768                 property_name ));
    769     return FT_THROW( Missing_Property );
    770   }
    771 
    772 
    773   FT_DEFINE_SERVICE_PROPERTIESREC(
    774     pcf_service_properties,
    775 
    776     (FT_Properties_SetFunc)pcf_property_set,      /* set_property */
    777     (FT_Properties_GetFunc)pcf_property_get )     /* get_property */
    778 
    779 
    780  /*
    781   *
    782   *  SERVICE LIST
    783   *
    784   */
    785 
    786   static const FT_ServiceDescRec  pcf_services[] =
    787   {
    788     { FT_SERVICE_ID_BDF,         &pcf_service_bdf },
    789     { FT_SERVICE_ID_FONT_FORMAT, FT_FONT_FORMAT_PCF },
    790     { FT_SERVICE_ID_PROPERTIES,  &pcf_service_properties },
    791     { NULL, NULL }
    792   };
    793 
    794 
    795   FT_CALLBACK_DEF( FT_Module_Interface )
    796   pcf_driver_requester( FT_Module    module,
    797                         const char*  name )
    798   {
    799     FT_UNUSED( module );
    800 
    801     return ft_service_list_lookup( pcf_services, name );
    802   }
    803 
    804 
    805   FT_CALLBACK_DEF( FT_Error )
    806   pcf_driver_init( FT_Module  module )      /* PCF_Driver */
    807   {
    808 #ifdef PCF_CONFIG_OPTION_LONG_FAMILY_NAMES
    809     PCF_Driver  driver = (PCF_Driver)module;
    810 
    811 
    812     driver->no_long_family_names = 0;
    813 #else
    814     FT_UNUSED( module );
    815 #endif
    816 
    817     return FT_Err_Ok;
    818   }
    819 
    820 
    821   FT_CALLBACK_DEF( void )
    822   pcf_driver_done( FT_Module  module )      /* PCF_Driver */
    823   {
    824     FT_UNUSED( module );
    825   }
    826 
    827 
    828   FT_CALLBACK_TABLE_DEF
    829   const FT_Driver_ClassRec  pcf_driver_class =
    830   {
    831     {
    832       FT_MODULE_FONT_DRIVER        |
    833       FT_MODULE_DRIVER_NO_OUTLINES,
    834 
    835       sizeof ( PCF_DriverRec ),
    836       "pcf",
    837       0x10000L,
    838       0x20000L,
    839 
    840       NULL,   /* module-specific interface */
    841 
    842       pcf_driver_init,          /* FT_Module_Constructor  module_init   */
    843       pcf_driver_done,          /* FT_Module_Destructor   module_done   */
    844       pcf_driver_requester      /* FT_Module_Requester    get_interface */
    845     },
    846 
    847     sizeof ( PCF_FaceRec ),
    848     sizeof ( FT_SizeRec ),
    849     sizeof ( FT_GlyphSlotRec ),
    850 
    851     PCF_Face_Init,              /* FT_Face_InitFunc  init_face */
    852     PCF_Face_Done,              /* FT_Face_DoneFunc  done_face */
    853     NULL,                       /* FT_Size_InitFunc  init_size */
    854     NULL,                       /* FT_Size_DoneFunc  done_size */
    855     NULL,                       /* FT_Slot_InitFunc  init_slot */
    856     NULL,                       /* FT_Slot_DoneFunc  done_slot */
    857 
    858     PCF_Glyph_Load,             /* FT_Slot_LoadFunc  load_glyph */
    859 
    860     NULL,                       /* FT_Face_GetKerningFunc   get_kerning  */
    861     NULL,                       /* FT_Face_AttachFunc       attach_file  */
    862     NULL,                       /* FT_Face_GetAdvancesFunc  get_advances */
    863 
    864     PCF_Size_Request,           /* FT_Size_RequestFunc  request_size */
    865     PCF_Size_Select             /* FT_Size_SelectFunc   select_size  */
    866   };
    867 
    868 
    869 /* END */
    870