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