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