misc/libfreetype/src/pcf/pcfread.c
branchwebgl
changeset 9521 8054d9d775fd
parent 9282 92af50454cf2
parent 9519 b8b5c82eb61b
child 9950 2759212a27de
equal deleted inserted replaced
9282:92af50454cf2 9521:8054d9d775fd
     1 /*  pcfread.c
       
     2 
       
     3     FreeType font driver for pcf fonts
       
     4 
       
     5   Copyright 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009,
       
     6             2010 by
       
     7   Francesco Zappa Nardelli
       
     8 
       
     9 Permission is hereby granted, free of charge, to any person obtaining a copy
       
    10 of this software and associated documentation files (the "Software"), to deal
       
    11 in the Software without restriction, including without limitation the rights
       
    12 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
       
    13 copies of the Software, and to permit persons to whom the Software is
       
    14 furnished to do so, subject to the following conditions:
       
    15 
       
    16 The above copyright notice and this permission notice shall be included in
       
    17 all copies or substantial portions of the Software.
       
    18 
       
    19 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
       
    20 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
       
    21 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
       
    22 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
       
    23 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
       
    24 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
       
    25 THE SOFTWARE.
       
    26 */
       
    27 
       
    28 
       
    29 #include <ft2build.h>
       
    30 
       
    31 #include FT_INTERNAL_DEBUG_H
       
    32 #include FT_INTERNAL_STREAM_H
       
    33 #include FT_INTERNAL_OBJECTS_H
       
    34 
       
    35 #include "pcf.h"
       
    36 #include "pcfread.h"
       
    37 
       
    38 #include "pcferror.h"
       
    39 
       
    40 
       
    41   /*************************************************************************/
       
    42   /*                                                                       */
       
    43   /* The macro FT_COMPONENT is used in trace mode.  It is an implicit      */
       
    44   /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log  */
       
    45   /* messages during execution.                                            */
       
    46   /*                                                                       */
       
    47 #undef  FT_COMPONENT
       
    48 #define FT_COMPONENT  trace_pcfread
       
    49 
       
    50 
       
    51 #ifdef FT_DEBUG_LEVEL_TRACE
       
    52   static const char* const  tableNames[] =
       
    53   {
       
    54     "prop", "accl", "mtrcs", "bmps", "imtrcs",
       
    55     "enc", "swidth", "names", "accel"
       
    56   };
       
    57 #endif
       
    58 
       
    59 
       
    60   static
       
    61   const FT_Frame_Field  pcf_toc_header[] =
       
    62   {
       
    63 #undef  FT_STRUCTURE
       
    64 #define FT_STRUCTURE  PCF_TocRec
       
    65 
       
    66     FT_FRAME_START( 8 ),
       
    67       FT_FRAME_ULONG_LE( version ),
       
    68       FT_FRAME_ULONG_LE( count ),
       
    69     FT_FRAME_END
       
    70   };
       
    71 
       
    72 
       
    73   static
       
    74   const FT_Frame_Field  pcf_table_header[] =
       
    75   {
       
    76 #undef  FT_STRUCTURE
       
    77 #define FT_STRUCTURE  PCF_TableRec
       
    78 
       
    79     FT_FRAME_START( 16  ),
       
    80       FT_FRAME_ULONG_LE( type ),
       
    81       FT_FRAME_ULONG_LE( format ),
       
    82       FT_FRAME_ULONG_LE( size ),
       
    83       FT_FRAME_ULONG_LE( offset ),
       
    84     FT_FRAME_END
       
    85   };
       
    86 
       
    87 
       
    88   static FT_Error
       
    89   pcf_read_TOC( FT_Stream  stream,
       
    90                 PCF_Face   face )
       
    91   {
       
    92     FT_Error   error;
       
    93     PCF_Toc    toc = &face->toc;
       
    94     PCF_Table  tables;
       
    95 
       
    96     FT_Memory  memory = FT_FACE(face)->memory;
       
    97     FT_UInt    n;
       
    98 
       
    99 
       
   100     if ( FT_STREAM_SEEK ( 0 )                          ||
       
   101          FT_STREAM_READ_FIELDS ( pcf_toc_header, toc ) )
       
   102       return PCF_Err_Cannot_Open_Resource;
       
   103 
       
   104     if ( toc->version != PCF_FILE_VERSION                 ||
       
   105          toc->count   >  FT_ARRAY_MAX( face->toc.tables ) ||
       
   106          toc->count   == 0                                )
       
   107       return PCF_Err_Invalid_File_Format;
       
   108 
       
   109     if ( FT_NEW_ARRAY( face->toc.tables, toc->count ) )
       
   110       return PCF_Err_Out_Of_Memory;
       
   111 
       
   112     tables = face->toc.tables;
       
   113     for ( n = 0; n < toc->count; n++ )
       
   114     {
       
   115       if ( FT_STREAM_READ_FIELDS( pcf_table_header, tables ) )
       
   116         goto Exit;
       
   117       tables++;
       
   118     }
       
   119 
       
   120     /* Sort tables and check for overlaps.  Because they are almost      */
       
   121     /* always ordered already, an in-place bubble sort with simultaneous */
       
   122     /* boundary checking seems appropriate.                              */
       
   123     tables = face->toc.tables;
       
   124 
       
   125     for ( n = 0; n < toc->count - 1; n++ )
       
   126     {
       
   127       FT_UInt  i, have_change;
       
   128 
       
   129 
       
   130       have_change = 0;
       
   131 
       
   132       for ( i = 0; i < toc->count - 1 - n; i++ )
       
   133       {
       
   134         PCF_TableRec  tmp;
       
   135 
       
   136 
       
   137         if ( tables[i].offset > tables[i + 1].offset )
       
   138         {
       
   139           tmp           = tables[i];
       
   140           tables[i]     = tables[i + 1];
       
   141           tables[i + 1] = tmp;
       
   142 
       
   143           have_change = 1;
       
   144         }
       
   145 
       
   146         if ( ( tables[i].size   > tables[i + 1].offset )                  ||
       
   147              ( tables[i].offset > tables[i + 1].offset - tables[i].size ) )
       
   148           return PCF_Err_Invalid_Offset;
       
   149       }
       
   150 
       
   151       if ( !have_change )
       
   152         break;
       
   153     }
       
   154 
       
   155 #ifdef FT_DEBUG_LEVEL_TRACE
       
   156 
       
   157     {
       
   158       FT_UInt      i, j;
       
   159       const char*  name = "?";
       
   160 
       
   161 
       
   162       FT_TRACE4(( "pcf_read_TOC:\n" ));
       
   163 
       
   164       FT_TRACE4(( "  number of tables: %ld\n", face->toc.count ));
       
   165 
       
   166       tables = face->toc.tables;
       
   167       for ( i = 0; i < toc->count; i++ )
       
   168       {
       
   169         for ( j = 0; j < sizeof ( tableNames ) / sizeof ( tableNames[0] );
       
   170               j++ )
       
   171           if ( tables[i].type == (FT_UInt)( 1 << j ) )
       
   172             name = tableNames[j];
       
   173 
       
   174         FT_TRACE4(( "  %d: type=%s, format=0x%X, "
       
   175                     "size=%ld (0x%lX), offset=%ld (0x%lX)\n",
       
   176                     i, name,
       
   177                     tables[i].format,
       
   178                     tables[i].size, tables[i].size,
       
   179                     tables[i].offset, tables[i].offset ));
       
   180       }
       
   181     }
       
   182 
       
   183 #endif
       
   184 
       
   185     return PCF_Err_Ok;
       
   186 
       
   187   Exit:
       
   188     FT_FREE( face->toc.tables );
       
   189     return error;
       
   190   }
       
   191 
       
   192 
       
   193 #define PCF_METRIC_SIZE  12
       
   194 
       
   195   static
       
   196   const FT_Frame_Field  pcf_metric_header[] =
       
   197   {
       
   198 #undef  FT_STRUCTURE
       
   199 #define FT_STRUCTURE  PCF_MetricRec
       
   200 
       
   201     FT_FRAME_START( PCF_METRIC_SIZE ),
       
   202       FT_FRAME_SHORT_LE( leftSideBearing ),
       
   203       FT_FRAME_SHORT_LE( rightSideBearing ),
       
   204       FT_FRAME_SHORT_LE( characterWidth ),
       
   205       FT_FRAME_SHORT_LE( ascent ),
       
   206       FT_FRAME_SHORT_LE( descent ),
       
   207       FT_FRAME_SHORT_LE( attributes ),
       
   208     FT_FRAME_END
       
   209   };
       
   210 
       
   211 
       
   212   static
       
   213   const FT_Frame_Field  pcf_metric_msb_header[] =
       
   214   {
       
   215 #undef  FT_STRUCTURE
       
   216 #define FT_STRUCTURE  PCF_MetricRec
       
   217 
       
   218     FT_FRAME_START( PCF_METRIC_SIZE ),
       
   219       FT_FRAME_SHORT( leftSideBearing ),
       
   220       FT_FRAME_SHORT( rightSideBearing ),
       
   221       FT_FRAME_SHORT( characterWidth ),
       
   222       FT_FRAME_SHORT( ascent ),
       
   223       FT_FRAME_SHORT( descent ),
       
   224       FT_FRAME_SHORT( attributes ),
       
   225     FT_FRAME_END
       
   226   };
       
   227 
       
   228 
       
   229 #define PCF_COMPRESSED_METRIC_SIZE  5
       
   230 
       
   231   static
       
   232   const FT_Frame_Field  pcf_compressed_metric_header[] =
       
   233   {
       
   234 #undef  FT_STRUCTURE
       
   235 #define FT_STRUCTURE  PCF_Compressed_MetricRec
       
   236 
       
   237     FT_FRAME_START( PCF_COMPRESSED_METRIC_SIZE ),
       
   238       FT_FRAME_BYTE( leftSideBearing ),
       
   239       FT_FRAME_BYTE( rightSideBearing ),
       
   240       FT_FRAME_BYTE( characterWidth ),
       
   241       FT_FRAME_BYTE( ascent ),
       
   242       FT_FRAME_BYTE( descent ),
       
   243     FT_FRAME_END
       
   244   };
       
   245 
       
   246 
       
   247   static FT_Error
       
   248   pcf_get_metric( FT_Stream   stream,
       
   249                   FT_ULong    format,
       
   250                   PCF_Metric  metric )
       
   251   {
       
   252     FT_Error  error = PCF_Err_Ok;
       
   253 
       
   254 
       
   255     if ( PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) )
       
   256     {
       
   257       const FT_Frame_Field*  fields;
       
   258 
       
   259 
       
   260       /* parsing normal metrics */
       
   261       fields = PCF_BYTE_ORDER( format ) == MSBFirst
       
   262                ? pcf_metric_msb_header
       
   263                : pcf_metric_header;
       
   264 
       
   265       /* the following sets `error' but doesn't return in case of failure */
       
   266       (void)FT_STREAM_READ_FIELDS( fields, metric );
       
   267     }
       
   268     else
       
   269     {
       
   270       PCF_Compressed_MetricRec  compr;
       
   271 
       
   272 
       
   273       /* parsing compressed metrics */
       
   274       if ( FT_STREAM_READ_FIELDS( pcf_compressed_metric_header, &compr ) )
       
   275         goto Exit;
       
   276 
       
   277       metric->leftSideBearing  = (FT_Short)( compr.leftSideBearing  - 0x80 );
       
   278       metric->rightSideBearing = (FT_Short)( compr.rightSideBearing - 0x80 );
       
   279       metric->characterWidth   = (FT_Short)( compr.characterWidth   - 0x80 );
       
   280       metric->ascent           = (FT_Short)( compr.ascent           - 0x80 );
       
   281       metric->descent          = (FT_Short)( compr.descent          - 0x80 );
       
   282       metric->attributes       = 0;
       
   283     }
       
   284 
       
   285   Exit:
       
   286     return error;
       
   287   }
       
   288 
       
   289 
       
   290   static FT_Error
       
   291   pcf_seek_to_table_type( FT_Stream  stream,
       
   292                           PCF_Table  tables,
       
   293                           FT_ULong   ntables, /* same as PCF_Toc->count */
       
   294                           FT_ULong   type,
       
   295                           FT_ULong  *aformat,
       
   296                           FT_ULong  *asize )
       
   297   {
       
   298     FT_Error  error = PCF_Err_Invalid_File_Format;
       
   299     FT_ULong  i;
       
   300 
       
   301 
       
   302     for ( i = 0; i < ntables; i++ )
       
   303       if ( tables[i].type == type )
       
   304       {
       
   305         if ( stream->pos > tables[i].offset )
       
   306         {
       
   307           error = PCF_Err_Invalid_Stream_Skip;
       
   308           goto Fail;
       
   309         }
       
   310 
       
   311         if ( FT_STREAM_SKIP( tables[i].offset - stream->pos ) )
       
   312         {
       
   313           error = PCF_Err_Invalid_Stream_Skip;
       
   314           goto Fail;
       
   315         }
       
   316 
       
   317         *asize   = tables[i].size;
       
   318         *aformat = tables[i].format;
       
   319 
       
   320         return PCF_Err_Ok;
       
   321       }
       
   322 
       
   323   Fail:
       
   324     *asize = 0;
       
   325     return error;
       
   326   }
       
   327 
       
   328 
       
   329   static FT_Bool
       
   330   pcf_has_table_type( PCF_Table  tables,
       
   331                       FT_ULong   ntables, /* same as PCF_Toc->count */
       
   332                       FT_ULong   type )
       
   333   {
       
   334     FT_ULong  i;
       
   335 
       
   336 
       
   337     for ( i = 0; i < ntables; i++ )
       
   338       if ( tables[i].type == type )
       
   339         return TRUE;
       
   340 
       
   341     return FALSE;
       
   342   }
       
   343 
       
   344 
       
   345 #define PCF_PROPERTY_SIZE  9
       
   346 
       
   347   static
       
   348   const FT_Frame_Field  pcf_property_header[] =
       
   349   {
       
   350 #undef  FT_STRUCTURE
       
   351 #define FT_STRUCTURE  PCF_ParsePropertyRec
       
   352 
       
   353     FT_FRAME_START( PCF_PROPERTY_SIZE ),
       
   354       FT_FRAME_LONG_LE( name ),
       
   355       FT_FRAME_BYTE   ( isString ),
       
   356       FT_FRAME_LONG_LE( value ),
       
   357     FT_FRAME_END
       
   358   };
       
   359 
       
   360 
       
   361   static
       
   362   const FT_Frame_Field  pcf_property_msb_header[] =
       
   363   {
       
   364 #undef  FT_STRUCTURE
       
   365 #define FT_STRUCTURE  PCF_ParsePropertyRec
       
   366 
       
   367     FT_FRAME_START( PCF_PROPERTY_SIZE ),
       
   368       FT_FRAME_LONG( name ),
       
   369       FT_FRAME_BYTE( isString ),
       
   370       FT_FRAME_LONG( value ),
       
   371     FT_FRAME_END
       
   372   };
       
   373 
       
   374 
       
   375   FT_LOCAL_DEF( PCF_Property )
       
   376   pcf_find_property( PCF_Face          face,
       
   377                      const FT_String*  prop )
       
   378   {
       
   379     PCF_Property  properties = face->properties;
       
   380     FT_Bool       found      = 0;
       
   381     int           i;
       
   382 
       
   383 
       
   384     for ( i = 0 ; i < face->nprops && !found; i++ )
       
   385     {
       
   386       if ( !ft_strcmp( properties[i].name, prop ) )
       
   387         found = 1;
       
   388     }
       
   389 
       
   390     if ( found )
       
   391       return properties + i - 1;
       
   392     else
       
   393       return NULL;
       
   394   }
       
   395 
       
   396 
       
   397   static FT_Error
       
   398   pcf_get_properties( FT_Stream  stream,
       
   399                       PCF_Face   face )
       
   400   {
       
   401     PCF_ParseProperty  props      = 0;
       
   402     PCF_Property       properties;
       
   403     FT_ULong           nprops, i;
       
   404     FT_ULong           format, size;
       
   405     FT_Error           error;
       
   406     FT_Memory          memory     = FT_FACE(face)->memory;
       
   407     FT_ULong           string_size;
       
   408     FT_String*         strings    = 0;
       
   409 
       
   410 
       
   411     error = pcf_seek_to_table_type( stream,
       
   412                                     face->toc.tables,
       
   413                                     face->toc.count,
       
   414                                     PCF_PROPERTIES,
       
   415                                     &format,
       
   416                                     &size );
       
   417     if ( error )
       
   418       goto Bail;
       
   419 
       
   420     if ( FT_READ_ULONG_LE( format ) )
       
   421       goto Bail;
       
   422 
       
   423     FT_TRACE4(( "pcf_get_properties:\n" ));
       
   424 
       
   425     FT_TRACE4(( "  format = %ld\n", format ));
       
   426 
       
   427     if ( !PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) )
       
   428       goto Bail;
       
   429 
       
   430     if ( PCF_BYTE_ORDER( format ) == MSBFirst )
       
   431       (void)FT_READ_ULONG( nprops );
       
   432     else
       
   433       (void)FT_READ_ULONG_LE( nprops );
       
   434     if ( error )
       
   435       goto Bail;
       
   436 
       
   437     FT_TRACE4(( "  nprop = %d (truncate %d props)\n",
       
   438                 (int)nprops, nprops - (int)nprops ));
       
   439 
       
   440     nprops = (int)nprops;
       
   441 
       
   442     /* rough estimate */
       
   443     if ( nprops > size / PCF_PROPERTY_SIZE )
       
   444     {
       
   445       error = PCF_Err_Invalid_Table;
       
   446       goto Bail;
       
   447     }
       
   448 
       
   449     face->nprops = (int)nprops;
       
   450 
       
   451     if ( FT_NEW_ARRAY( props, nprops ) )
       
   452       goto Bail;
       
   453 
       
   454     for ( i = 0; i < nprops; i++ )
       
   455     {
       
   456       if ( PCF_BYTE_ORDER( format ) == MSBFirst )
       
   457       {
       
   458         if ( FT_STREAM_READ_FIELDS( pcf_property_msb_header, props + i ) )
       
   459           goto Bail;
       
   460       }
       
   461       else
       
   462       {
       
   463         if ( FT_STREAM_READ_FIELDS( pcf_property_header, props + i ) )
       
   464           goto Bail;
       
   465       }
       
   466     }
       
   467 
       
   468     /* pad the property array                                            */
       
   469     /*                                                                   */
       
   470     /* clever here - nprops is the same as the number of odd-units read, */
       
   471     /* as only isStringProp are odd length   (Keith Packard)             */
       
   472     /*                                                                   */
       
   473     if ( nprops & 3 )
       
   474     {
       
   475       i = 4 - ( nprops & 3 );
       
   476       if ( FT_STREAM_SKIP( i ) )
       
   477       {
       
   478         error = PCF_Err_Invalid_Stream_Skip;
       
   479         goto Bail;
       
   480       }
       
   481     }
       
   482 
       
   483     if ( PCF_BYTE_ORDER( format ) == MSBFirst )
       
   484       (void)FT_READ_ULONG( string_size );
       
   485     else
       
   486       (void)FT_READ_ULONG_LE( string_size );
       
   487     if ( error )
       
   488       goto Bail;
       
   489 
       
   490     FT_TRACE4(( "  string_size = %ld\n", string_size ));
       
   491 
       
   492     /* rough estimate */
       
   493     if ( string_size > size - nprops * PCF_PROPERTY_SIZE )
       
   494     {
       
   495       error = PCF_Err_Invalid_Table;
       
   496       goto Bail;
       
   497     }
       
   498 
       
   499     if ( FT_NEW_ARRAY( strings, string_size ) )
       
   500       goto Bail;
       
   501 
       
   502     error = FT_Stream_Read( stream, (FT_Byte*)strings, string_size );
       
   503     if ( error )
       
   504       goto Bail;
       
   505 
       
   506     if ( FT_NEW_ARRAY( properties, nprops ) )
       
   507       goto Bail;
       
   508 
       
   509     face->properties = properties;
       
   510 
       
   511     for ( i = 0; i < nprops; i++ )
       
   512     {
       
   513       FT_Long  name_offset = props[i].name;
       
   514 
       
   515 
       
   516       if ( ( name_offset < 0 )                     ||
       
   517            ( (FT_ULong)name_offset > string_size ) )
       
   518       {
       
   519         error = PCF_Err_Invalid_Offset;
       
   520         goto Bail;
       
   521       }
       
   522 
       
   523       if ( FT_STRDUP( properties[i].name, strings + name_offset ) )
       
   524         goto Bail;
       
   525 
       
   526       FT_TRACE4(( "  %s:", properties[i].name ));
       
   527 
       
   528       properties[i].isString = props[i].isString;
       
   529 
       
   530       if ( props[i].isString )
       
   531       {
       
   532         FT_Long  value_offset = props[i].value;
       
   533 
       
   534 
       
   535         if ( ( value_offset < 0 )                     ||
       
   536              ( (FT_ULong)value_offset > string_size ) )
       
   537         {
       
   538           error = PCF_Err_Invalid_Offset;
       
   539           goto Bail;
       
   540         }
       
   541 
       
   542         if ( FT_STRDUP( properties[i].value.atom, strings + value_offset ) )
       
   543           goto Bail;
       
   544 
       
   545         FT_TRACE4(( " `%s'\n", properties[i].value.atom ));
       
   546       }
       
   547       else
       
   548       {
       
   549         properties[i].value.l = props[i].value;
       
   550 
       
   551         FT_TRACE4(( " %d\n", properties[i].value.l ));
       
   552       }
       
   553     }
       
   554 
       
   555     error = PCF_Err_Ok;
       
   556 
       
   557   Bail:
       
   558     FT_FREE( props );
       
   559     FT_FREE( strings );
       
   560 
       
   561     return error;
       
   562   }
       
   563 
       
   564 
       
   565   static FT_Error
       
   566   pcf_get_metrics( FT_Stream  stream,
       
   567                    PCF_Face   face )
       
   568   {
       
   569     FT_Error    error    = PCF_Err_Ok;
       
   570     FT_Memory   memory   = FT_FACE(face)->memory;
       
   571     FT_ULong    format, size;
       
   572     PCF_Metric  metrics  = 0;
       
   573     FT_ULong    nmetrics, i;
       
   574 
       
   575 
       
   576     error = pcf_seek_to_table_type( stream,
       
   577                                     face->toc.tables,
       
   578                                     face->toc.count,
       
   579                                     PCF_METRICS,
       
   580                                     &format,
       
   581                                     &size );
       
   582     if ( error )
       
   583       return error;
       
   584 
       
   585     if ( FT_READ_ULONG_LE( format ) )
       
   586       goto Bail;
       
   587 
       
   588     if ( !PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT )     &&
       
   589          !PCF_FORMAT_MATCH( format, PCF_COMPRESSED_METRICS ) )
       
   590       return PCF_Err_Invalid_File_Format;
       
   591 
       
   592     if ( PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) )
       
   593     {
       
   594       if ( PCF_BYTE_ORDER( format ) == MSBFirst )
       
   595         (void)FT_READ_ULONG( nmetrics );
       
   596       else
       
   597         (void)FT_READ_ULONG_LE( nmetrics );
       
   598     }
       
   599     else
       
   600     {
       
   601       if ( PCF_BYTE_ORDER( format ) == MSBFirst )
       
   602         (void)FT_READ_USHORT( nmetrics );
       
   603       else
       
   604         (void)FT_READ_USHORT_LE( nmetrics );
       
   605     }
       
   606     if ( error )
       
   607       return PCF_Err_Invalid_File_Format;
       
   608 
       
   609     face->nmetrics = nmetrics;
       
   610 
       
   611     if ( !nmetrics )
       
   612       return PCF_Err_Invalid_Table;
       
   613 
       
   614     FT_TRACE4(( "pcf_get_metrics:\n" ));
       
   615 
       
   616     FT_TRACE4(( "  number of metrics: %d\n", nmetrics ));
       
   617 
       
   618     /* rough estimate */
       
   619     if ( PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) )
       
   620     {
       
   621       if ( nmetrics > size / PCF_METRIC_SIZE )
       
   622         return PCF_Err_Invalid_Table;
       
   623     }
       
   624     else
       
   625     {
       
   626       if ( nmetrics > size / PCF_COMPRESSED_METRIC_SIZE )
       
   627         return PCF_Err_Invalid_Table;
       
   628     }
       
   629 
       
   630     if ( FT_NEW_ARRAY( face->metrics, nmetrics ) )
       
   631       return PCF_Err_Out_Of_Memory;
       
   632 
       
   633     metrics = face->metrics;
       
   634     for ( i = 0; i < nmetrics; i++ )
       
   635     {
       
   636       error = pcf_get_metric( stream, format, metrics + i );
       
   637 
       
   638       metrics[i].bits = 0;
       
   639 
       
   640       FT_TRACE5(( "  idx %d: width=%d, "
       
   641                   "lsb=%d, rsb=%d, ascent=%d, descent=%d, swidth=%d\n",
       
   642                   i,
       
   643                   ( metrics + i )->characterWidth,
       
   644                   ( metrics + i )->leftSideBearing,
       
   645                   ( metrics + i )->rightSideBearing,
       
   646                   ( metrics + i )->ascent,
       
   647                   ( metrics + i )->descent,
       
   648                   ( metrics + i )->attributes ));
       
   649 
       
   650       if ( error )
       
   651         break;
       
   652     }
       
   653 
       
   654     if ( error )
       
   655       FT_FREE( face->metrics );
       
   656 
       
   657   Bail:
       
   658     return error;
       
   659   }
       
   660 
       
   661 
       
   662   static FT_Error
       
   663   pcf_get_bitmaps( FT_Stream  stream,
       
   664                    PCF_Face   face )
       
   665   {
       
   666     FT_Error   error  = PCF_Err_Ok;
       
   667     FT_Memory  memory = FT_FACE(face)->memory;
       
   668     FT_Long*   offsets;
       
   669     FT_Long    bitmapSizes[GLYPHPADOPTIONS];
       
   670     FT_ULong   format, size;
       
   671     FT_ULong   nbitmaps, i, sizebitmaps = 0;
       
   672 
       
   673 
       
   674     error = pcf_seek_to_table_type( stream,
       
   675                                     face->toc.tables,
       
   676                                     face->toc.count,
       
   677                                     PCF_BITMAPS,
       
   678                                     &format,
       
   679                                     &size );
       
   680     if ( error )
       
   681       return error;
       
   682 
       
   683     error = FT_Stream_EnterFrame( stream, 8 );
       
   684     if ( error )
       
   685       return error;
       
   686 
       
   687     format = FT_GET_ULONG_LE();
       
   688     if ( PCF_BYTE_ORDER( format ) == MSBFirst )
       
   689       nbitmaps  = FT_GET_ULONG();
       
   690     else
       
   691       nbitmaps  = FT_GET_ULONG_LE();
       
   692 
       
   693     FT_Stream_ExitFrame( stream );
       
   694 
       
   695     if ( !PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) )
       
   696       return PCF_Err_Invalid_File_Format;
       
   697 
       
   698     FT_TRACE4(( "pcf_get_bitmaps:\n" ));
       
   699 
       
   700     FT_TRACE4(( "  number of bitmaps: %d\n", nbitmaps ));
       
   701 
       
   702     /* XXX: PCF_Face->nmetrics is singed FT_Long, see pcf.h */
       
   703     if ( face->nmetrics < 0 || nbitmaps != ( FT_ULong )face->nmetrics )
       
   704       return PCF_Err_Invalid_File_Format;
       
   705 
       
   706     if ( FT_NEW_ARRAY( offsets, nbitmaps ) )
       
   707       return error;
       
   708 
       
   709     for ( i = 0; i < nbitmaps; i++ )
       
   710     {
       
   711       if ( PCF_BYTE_ORDER( format ) == MSBFirst )
       
   712         (void)FT_READ_LONG( offsets[i] );
       
   713       else
       
   714         (void)FT_READ_LONG_LE( offsets[i] );
       
   715 
       
   716       FT_TRACE5(( "  bitmap %d: offset %ld (0x%lX)\n",
       
   717                   i, offsets[i], offsets[i] ));
       
   718     }
       
   719     if ( error )
       
   720       goto Bail;
       
   721 
       
   722     for ( i = 0; i < GLYPHPADOPTIONS; i++ )
       
   723     {
       
   724       if ( PCF_BYTE_ORDER( format ) == MSBFirst )
       
   725         (void)FT_READ_LONG( bitmapSizes[i] );
       
   726       else
       
   727         (void)FT_READ_LONG_LE( bitmapSizes[i] );
       
   728       if ( error )
       
   729         goto Bail;
       
   730 
       
   731       sizebitmaps = bitmapSizes[PCF_GLYPH_PAD_INDEX( format )];
       
   732 
       
   733       FT_TRACE4(( "  padding %d implies a size of %ld\n", i, bitmapSizes[i] ));
       
   734     }
       
   735 
       
   736     FT_TRACE4(( "  %d bitmaps, padding index %ld\n",
       
   737                 nbitmaps,
       
   738                 PCF_GLYPH_PAD_INDEX( format ) ));
       
   739     FT_TRACE4(( "  bitmap size = %d\n", sizebitmaps ));
       
   740 
       
   741     FT_UNUSED( sizebitmaps );       /* only used for debugging */
       
   742 
       
   743     for ( i = 0; i < nbitmaps; i++ )
       
   744     {
       
   745       /* rough estimate */
       
   746       if ( ( offsets[i] < 0 )              ||
       
   747            ( (FT_ULong)offsets[i] > size ) )
       
   748       {
       
   749         FT_TRACE0(( "pcf_get_bitmaps:"
       
   750                     " invalid offset to bitmap data of glyph %d\n", i ));
       
   751       }
       
   752       else
       
   753         face->metrics[i].bits = stream->pos + offsets[i];
       
   754     }
       
   755 
       
   756     face->bitmapsFormat = format;
       
   757 
       
   758   Bail:
       
   759     FT_FREE( offsets );
       
   760     return error;
       
   761   }
       
   762 
       
   763 
       
   764   static FT_Error
       
   765   pcf_get_encodings( FT_Stream  stream,
       
   766                      PCF_Face   face )
       
   767   {
       
   768     FT_Error      error  = PCF_Err_Ok;
       
   769     FT_Memory     memory = FT_FACE(face)->memory;
       
   770     FT_ULong      format, size;
       
   771     int           firstCol, lastCol;
       
   772     int           firstRow, lastRow;
       
   773     int           nencoding, encodingOffset;
       
   774     int           i, j;
       
   775     PCF_Encoding  tmpEncoding, encoding = 0;
       
   776 
       
   777 
       
   778     error = pcf_seek_to_table_type( stream,
       
   779                                     face->toc.tables,
       
   780                                     face->toc.count,
       
   781                                     PCF_BDF_ENCODINGS,
       
   782                                     &format,
       
   783                                     &size );
       
   784     if ( error )
       
   785       return error;
       
   786 
       
   787     error = FT_Stream_EnterFrame( stream, 14 );
       
   788     if ( error )
       
   789       return error;
       
   790 
       
   791     format = FT_GET_ULONG_LE();
       
   792 
       
   793     if ( PCF_BYTE_ORDER( format ) == MSBFirst )
       
   794     {
       
   795       firstCol          = FT_GET_SHORT();
       
   796       lastCol           = FT_GET_SHORT();
       
   797       firstRow          = FT_GET_SHORT();
       
   798       lastRow           = FT_GET_SHORT();
       
   799       face->defaultChar = FT_GET_SHORT();
       
   800     }
       
   801     else
       
   802     {
       
   803       firstCol          = FT_GET_SHORT_LE();
       
   804       lastCol           = FT_GET_SHORT_LE();
       
   805       firstRow          = FT_GET_SHORT_LE();
       
   806       lastRow           = FT_GET_SHORT_LE();
       
   807       face->defaultChar = FT_GET_SHORT_LE();
       
   808     }
       
   809 
       
   810     FT_Stream_ExitFrame( stream );
       
   811 
       
   812     if ( !PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) )
       
   813       return PCF_Err_Invalid_File_Format;
       
   814 
       
   815     FT_TRACE4(( "pdf_get_encodings:\n" ));
       
   816 
       
   817     FT_TRACE4(( "  firstCol %d, lastCol %d, firstRow %d, lastRow %d\n",
       
   818                 firstCol, lastCol, firstRow, lastRow ));
       
   819 
       
   820     nencoding = ( lastCol - firstCol + 1 ) * ( lastRow - firstRow + 1 );
       
   821 
       
   822     if ( FT_NEW_ARRAY( tmpEncoding, nencoding ) )
       
   823       return PCF_Err_Out_Of_Memory;
       
   824 
       
   825     error = FT_Stream_EnterFrame( stream, 2 * nencoding );
       
   826     if ( error )
       
   827       goto Bail;
       
   828 
       
   829     for ( i = 0, j = 0 ; i < nencoding; i++ )
       
   830     {
       
   831       if ( PCF_BYTE_ORDER( format ) == MSBFirst )
       
   832         encodingOffset = FT_GET_SHORT();
       
   833       else
       
   834         encodingOffset = FT_GET_SHORT_LE();
       
   835 
       
   836       if ( encodingOffset != -1 )
       
   837       {
       
   838         tmpEncoding[j].enc = ( ( ( i / ( lastCol - firstCol + 1 ) ) +
       
   839                                  firstRow ) * 256 ) +
       
   840                                ( ( i % ( lastCol - firstCol + 1 ) ) +
       
   841                                  firstCol );
       
   842 
       
   843         tmpEncoding[j].glyph = (FT_Short)encodingOffset;
       
   844 
       
   845         FT_TRACE5(( "  code %d (0x%04X): idx %d\n",
       
   846                     tmpEncoding[j].enc, tmpEncoding[j].enc,
       
   847                     tmpEncoding[j].glyph ));
       
   848 
       
   849         j++;
       
   850       }
       
   851     }
       
   852     FT_Stream_ExitFrame( stream );
       
   853 
       
   854     if ( FT_NEW_ARRAY( encoding, j ) )
       
   855       goto Bail;
       
   856 
       
   857     for ( i = 0; i < j; i++ )
       
   858     {
       
   859       encoding[i].enc   = tmpEncoding[i].enc;
       
   860       encoding[i].glyph = tmpEncoding[i].glyph;
       
   861     }
       
   862 
       
   863     face->nencodings = j;
       
   864     face->encodings  = encoding;
       
   865     FT_FREE( tmpEncoding );
       
   866 
       
   867     return error;
       
   868 
       
   869   Bail:
       
   870     FT_FREE( encoding );
       
   871     FT_FREE( tmpEncoding );
       
   872     return error;
       
   873   }
       
   874 
       
   875 
       
   876   static
       
   877   const FT_Frame_Field  pcf_accel_header[] =
       
   878   {
       
   879 #undef  FT_STRUCTURE
       
   880 #define FT_STRUCTURE  PCF_AccelRec
       
   881 
       
   882     FT_FRAME_START( 20 ),
       
   883       FT_FRAME_BYTE      ( noOverlap ),
       
   884       FT_FRAME_BYTE      ( constantMetrics ),
       
   885       FT_FRAME_BYTE      ( terminalFont ),
       
   886       FT_FRAME_BYTE      ( constantWidth ),
       
   887       FT_FRAME_BYTE      ( inkInside ),
       
   888       FT_FRAME_BYTE      ( inkMetrics ),
       
   889       FT_FRAME_BYTE      ( drawDirection ),
       
   890       FT_FRAME_SKIP_BYTES( 1 ),
       
   891       FT_FRAME_LONG_LE   ( fontAscent ),
       
   892       FT_FRAME_LONG_LE   ( fontDescent ),
       
   893       FT_FRAME_LONG_LE   ( maxOverlap ),
       
   894     FT_FRAME_END
       
   895   };
       
   896 
       
   897 
       
   898   static
       
   899   const FT_Frame_Field  pcf_accel_msb_header[] =
       
   900   {
       
   901 #undef  FT_STRUCTURE
       
   902 #define FT_STRUCTURE  PCF_AccelRec
       
   903 
       
   904     FT_FRAME_START( 20 ),
       
   905       FT_FRAME_BYTE      ( noOverlap ),
       
   906       FT_FRAME_BYTE      ( constantMetrics ),
       
   907       FT_FRAME_BYTE      ( terminalFont ),
       
   908       FT_FRAME_BYTE      ( constantWidth ),
       
   909       FT_FRAME_BYTE      ( inkInside ),
       
   910       FT_FRAME_BYTE      ( inkMetrics ),
       
   911       FT_FRAME_BYTE      ( drawDirection ),
       
   912       FT_FRAME_SKIP_BYTES( 1 ),
       
   913       FT_FRAME_LONG      ( fontAscent ),
       
   914       FT_FRAME_LONG      ( fontDescent ),
       
   915       FT_FRAME_LONG      ( maxOverlap ),
       
   916     FT_FRAME_END
       
   917   };
       
   918 
       
   919 
       
   920   static FT_Error
       
   921   pcf_get_accel( FT_Stream  stream,
       
   922                  PCF_Face   face,
       
   923                  FT_ULong   type )
       
   924   {
       
   925     FT_ULong   format, size;
       
   926     FT_Error   error = PCF_Err_Ok;
       
   927     PCF_Accel  accel = &face->accel;
       
   928 
       
   929 
       
   930     error = pcf_seek_to_table_type( stream,
       
   931                                     face->toc.tables,
       
   932                                     face->toc.count,
       
   933                                     type,
       
   934                                     &format,
       
   935                                     &size );
       
   936     if ( error )
       
   937       goto Bail;
       
   938 
       
   939     if ( FT_READ_ULONG_LE( format ) )
       
   940       goto Bail;
       
   941 
       
   942     if ( !PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT )    &&
       
   943          !PCF_FORMAT_MATCH( format, PCF_ACCEL_W_INKBOUNDS ) )
       
   944       goto Bail;
       
   945 
       
   946     if ( PCF_BYTE_ORDER( format ) == MSBFirst )
       
   947     {
       
   948       if ( FT_STREAM_READ_FIELDS( pcf_accel_msb_header, accel ) )
       
   949         goto Bail;
       
   950     }
       
   951     else
       
   952     {
       
   953       if ( FT_STREAM_READ_FIELDS( pcf_accel_header, accel ) )
       
   954         goto Bail;
       
   955     }
       
   956 
       
   957     error = pcf_get_metric( stream,
       
   958                             format & ( ~PCF_FORMAT_MASK ),
       
   959                             &(accel->minbounds) );
       
   960     if ( error )
       
   961       goto Bail;
       
   962 
       
   963     error = pcf_get_metric( stream,
       
   964                             format & ( ~PCF_FORMAT_MASK ),
       
   965                             &(accel->maxbounds) );
       
   966     if ( error )
       
   967       goto Bail;
       
   968 
       
   969     if ( PCF_FORMAT_MATCH( format, PCF_ACCEL_W_INKBOUNDS ) )
       
   970     {
       
   971       error = pcf_get_metric( stream,
       
   972                               format & ( ~PCF_FORMAT_MASK ),
       
   973                               &(accel->ink_minbounds) );
       
   974       if ( error )
       
   975         goto Bail;
       
   976 
       
   977       error = pcf_get_metric( stream,
       
   978                               format & ( ~PCF_FORMAT_MASK ),
       
   979                               &(accel->ink_maxbounds) );
       
   980       if ( error )
       
   981         goto Bail;
       
   982     }
       
   983     else
       
   984     {
       
   985       accel->ink_minbounds = accel->minbounds; /* I'm not sure about this */
       
   986       accel->ink_maxbounds = accel->maxbounds;
       
   987     }
       
   988 
       
   989   Bail:
       
   990     return error;
       
   991   }
       
   992 
       
   993 
       
   994   static FT_Error
       
   995   pcf_interpret_style( PCF_Face  pcf )
       
   996   {
       
   997     FT_Error   error  = PCF_Err_Ok;
       
   998     FT_Face    face   = FT_FACE( pcf );
       
   999     FT_Memory  memory = face->memory;
       
  1000 
       
  1001     PCF_Property  prop;
       
  1002 
       
  1003     size_t  nn, len;
       
  1004     char*   strings[4] = { NULL, NULL, NULL, NULL };
       
  1005     size_t  lengths[4];
       
  1006 
       
  1007 
       
  1008     face->style_flags = 0;
       
  1009 
       
  1010     prop = pcf_find_property( pcf, "SLANT" );
       
  1011     if ( prop && prop->isString                                       &&
       
  1012          ( *(prop->value.atom) == 'O' || *(prop->value.atom) == 'o' ||
       
  1013            *(prop->value.atom) == 'I' || *(prop->value.atom) == 'i' ) )
       
  1014     {
       
  1015       face->style_flags |= FT_STYLE_FLAG_ITALIC;
       
  1016       strings[2] = ( *(prop->value.atom) == 'O' ||
       
  1017                      *(prop->value.atom) == 'o' ) ? (char *)"Oblique"
       
  1018                                                   : (char *)"Italic";
       
  1019     }
       
  1020 
       
  1021     prop = pcf_find_property( pcf, "WEIGHT_NAME" );
       
  1022     if ( prop && prop->isString                                       &&
       
  1023          ( *(prop->value.atom) == 'B' || *(prop->value.atom) == 'b' ) )
       
  1024     {
       
  1025       face->style_flags |= FT_STYLE_FLAG_BOLD;
       
  1026       strings[1] = (char *)"Bold";
       
  1027     }
       
  1028 
       
  1029     prop = pcf_find_property( pcf, "SETWIDTH_NAME" );
       
  1030     if ( prop && prop->isString                                        &&
       
  1031          *(prop->value.atom)                                           &&
       
  1032          !( *(prop->value.atom) == 'N' || *(prop->value.atom) == 'n' ) )
       
  1033       strings[3] = (char *)(prop->value.atom);
       
  1034 
       
  1035     prop = pcf_find_property( pcf, "ADD_STYLE_NAME" );
       
  1036     if ( prop && prop->isString                                        &&
       
  1037          *(prop->value.atom)                                           &&
       
  1038          !( *(prop->value.atom) == 'N' || *(prop->value.atom) == 'n' ) )
       
  1039       strings[0] = (char *)(prop->value.atom);
       
  1040 
       
  1041     for ( len = 0, nn = 0; nn < 4; nn++ )
       
  1042     {
       
  1043       lengths[nn] = 0;
       
  1044       if ( strings[nn] )
       
  1045       {
       
  1046         lengths[nn] = ft_strlen( strings[nn] );
       
  1047         len        += lengths[nn] + 1;
       
  1048       }
       
  1049     }
       
  1050 
       
  1051     if ( len == 0 )
       
  1052     {
       
  1053       strings[0] = (char *)"Regular";
       
  1054       lengths[0] = ft_strlen( strings[0] );
       
  1055       len        = lengths[0] + 1;
       
  1056     }
       
  1057 
       
  1058     {
       
  1059       char*  s;
       
  1060 
       
  1061 
       
  1062       if ( FT_ALLOC( face->style_name, len ) )
       
  1063         return error;
       
  1064 
       
  1065       s = face->style_name;
       
  1066 
       
  1067       for ( nn = 0; nn < 4; nn++ )
       
  1068       {
       
  1069         char*  src = strings[nn];
       
  1070 
       
  1071 
       
  1072         len = lengths[nn];
       
  1073 
       
  1074         if ( src == NULL )
       
  1075           continue;
       
  1076 
       
  1077         /* separate elements with a space */
       
  1078         if ( s != face->style_name )
       
  1079           *s++ = ' ';
       
  1080 
       
  1081         ft_memcpy( s, src, len );
       
  1082 
       
  1083         /* need to convert spaces to dashes for */
       
  1084         /* add_style_name and setwidth_name     */
       
  1085         if ( nn == 0 || nn == 3 )
       
  1086         {
       
  1087           size_t  mm;
       
  1088 
       
  1089 
       
  1090           for ( mm = 0; mm < len; mm++ )
       
  1091             if (s[mm] == ' ')
       
  1092               s[mm] = '-';
       
  1093         }
       
  1094 
       
  1095         s += len;
       
  1096       }
       
  1097       *s = 0;
       
  1098     }
       
  1099 
       
  1100     return error;
       
  1101   }
       
  1102 
       
  1103 
       
  1104   FT_LOCAL_DEF( FT_Error )
       
  1105   pcf_load_font( FT_Stream  stream,
       
  1106                  PCF_Face   face )
       
  1107   {
       
  1108     FT_Error   error  = PCF_Err_Ok;
       
  1109     FT_Memory  memory = FT_FACE(face)->memory;
       
  1110     FT_Bool    hasBDFAccelerators;
       
  1111 
       
  1112 
       
  1113     error = pcf_read_TOC( stream, face );
       
  1114     if ( error )
       
  1115       goto Exit;
       
  1116 
       
  1117     error = pcf_get_properties( stream, face );
       
  1118     if ( error )
       
  1119       goto Exit;
       
  1120 
       
  1121     /* Use the old accelerators if no BDF accelerators are in the file. */
       
  1122     hasBDFAccelerators = pcf_has_table_type( face->toc.tables,
       
  1123                                              face->toc.count,
       
  1124                                              PCF_BDF_ACCELERATORS );
       
  1125     if ( !hasBDFAccelerators )
       
  1126     {
       
  1127       error = pcf_get_accel( stream, face, PCF_ACCELERATORS );
       
  1128       if ( error )
       
  1129         goto Exit;
       
  1130     }
       
  1131 
       
  1132     /* metrics */
       
  1133     error = pcf_get_metrics( stream, face );
       
  1134     if ( error )
       
  1135       goto Exit;
       
  1136 
       
  1137     /* bitmaps */
       
  1138     error = pcf_get_bitmaps( stream, face );
       
  1139     if ( error )
       
  1140       goto Exit;
       
  1141 
       
  1142     /* encodings */
       
  1143     error = pcf_get_encodings( stream, face );
       
  1144     if ( error )
       
  1145       goto Exit;
       
  1146 
       
  1147     /* BDF style accelerators (i.e. bounds based on encoded glyphs) */
       
  1148     if ( hasBDFAccelerators )
       
  1149     {
       
  1150       error = pcf_get_accel( stream, face, PCF_BDF_ACCELERATORS );
       
  1151       if ( error )
       
  1152         goto Exit;
       
  1153     }
       
  1154 
       
  1155     /* XXX: TO DO: inkmetrics and glyph_names are missing */
       
  1156 
       
  1157     /* now construct the face object */
       
  1158     {
       
  1159       FT_Face       root = FT_FACE( face );
       
  1160       PCF_Property  prop;
       
  1161 
       
  1162 
       
  1163       root->num_faces  = 1;
       
  1164       root->face_index = 0;
       
  1165       root->face_flags = FT_FACE_FLAG_FIXED_SIZES |
       
  1166                          FT_FACE_FLAG_HORIZONTAL  |
       
  1167                          FT_FACE_FLAG_FAST_GLYPHS;
       
  1168 
       
  1169       if ( face->accel.constantWidth )
       
  1170         root->face_flags |= FT_FACE_FLAG_FIXED_WIDTH;
       
  1171 
       
  1172       if ( ( error = pcf_interpret_style( face ) ) != 0 )
       
  1173          goto Exit;
       
  1174 
       
  1175       prop = pcf_find_property( face, "FAMILY_NAME" );
       
  1176       if ( prop && prop->isString )
       
  1177       {
       
  1178         if ( FT_STRDUP( root->family_name, prop->value.atom ) )
       
  1179           goto Exit;
       
  1180       }
       
  1181       else
       
  1182         root->family_name = NULL;
       
  1183 
       
  1184       /*
       
  1185        * Note: We shift all glyph indices by +1 since we must
       
  1186        * respect the convention that glyph 0 always corresponds
       
  1187        * to the `missing glyph'.
       
  1188        *
       
  1189        * This implies bumping the number of `available' glyphs by 1.
       
  1190        */
       
  1191       root->num_glyphs = face->nmetrics + 1;
       
  1192 
       
  1193       root->num_fixed_sizes = 1;
       
  1194       if ( FT_NEW_ARRAY( root->available_sizes, 1 ) )
       
  1195         goto Exit;
       
  1196 
       
  1197       {
       
  1198         FT_Bitmap_Size*  bsize = root->available_sizes;
       
  1199         FT_Short         resolution_x = 0, resolution_y = 0;
       
  1200 
       
  1201 
       
  1202         FT_MEM_ZERO( bsize, sizeof ( FT_Bitmap_Size ) );
       
  1203 
       
  1204 #if 0
       
  1205         bsize->height = face->accel.maxbounds.ascent << 6;
       
  1206 #endif
       
  1207         bsize->height = (FT_Short)( face->accel.fontAscent +
       
  1208                                     face->accel.fontDescent );
       
  1209 
       
  1210         prop = pcf_find_property( face, "AVERAGE_WIDTH" );
       
  1211         if ( prop )
       
  1212           bsize->width = (FT_Short)( ( prop->value.l + 5 ) / 10 );
       
  1213         else
       
  1214           bsize->width = (FT_Short)( bsize->height * 2/3 );
       
  1215 
       
  1216         prop = pcf_find_property( face, "POINT_SIZE" );
       
  1217         if ( prop )
       
  1218           /* convert from 722.7 decipoints to 72 points per inch */
       
  1219           bsize->size =
       
  1220             (FT_Pos)( ( prop->value.l * 64 * 7200 + 36135L ) / 72270L );
       
  1221 
       
  1222         prop = pcf_find_property( face, "PIXEL_SIZE" );
       
  1223         if ( prop )
       
  1224           bsize->y_ppem = (FT_Short)prop->value.l << 6;
       
  1225 
       
  1226         prop = pcf_find_property( face, "RESOLUTION_X" );
       
  1227         if ( prop )
       
  1228           resolution_x = (FT_Short)prop->value.l;
       
  1229 
       
  1230         prop = pcf_find_property( face, "RESOLUTION_Y" );
       
  1231         if ( prop )
       
  1232           resolution_y = (FT_Short)prop->value.l;
       
  1233 
       
  1234         if ( bsize->y_ppem == 0 )
       
  1235         {
       
  1236           bsize->y_ppem = bsize->size;
       
  1237           if ( resolution_y )
       
  1238             bsize->y_ppem = bsize->y_ppem * resolution_y / 72;
       
  1239         }
       
  1240         if ( resolution_x && resolution_y )
       
  1241           bsize->x_ppem = bsize->y_ppem * resolution_x / resolution_y;
       
  1242         else
       
  1243           bsize->x_ppem = bsize->y_ppem;
       
  1244       }
       
  1245 
       
  1246       /* set up charset */
       
  1247       {
       
  1248         PCF_Property  charset_registry = 0, charset_encoding = 0;
       
  1249 
       
  1250 
       
  1251         charset_registry = pcf_find_property( face, "CHARSET_REGISTRY" );
       
  1252         charset_encoding = pcf_find_property( face, "CHARSET_ENCODING" );
       
  1253 
       
  1254         if ( charset_registry && charset_registry->isString &&
       
  1255              charset_encoding && charset_encoding->isString )
       
  1256         {
       
  1257           if ( FT_STRDUP( face->charset_encoding,
       
  1258                           charset_encoding->value.atom ) ||
       
  1259                FT_STRDUP( face->charset_registry,
       
  1260                           charset_registry->value.atom ) )
       
  1261             goto Exit;
       
  1262         }
       
  1263       }
       
  1264     }
       
  1265 
       
  1266   Exit:
       
  1267     if ( error )
       
  1268     {
       
  1269       /* This is done to respect the behaviour of the original */
       
  1270       /* PCF font driver.                                      */
       
  1271       error = PCF_Err_Invalid_File_Format;
       
  1272     }
       
  1273 
       
  1274     return error;
       
  1275   }
       
  1276 
       
  1277 
       
  1278 /* END */