Home | History | Annotate | Download | only in type1
      1 /***************************************************************************/
      2 /*                                                                         */
      3 /*  t1afm.c                                                                */
      4 /*                                                                         */
      5 /*    AFM support for Type 1 fonts (body).                                 */
      6 /*                                                                         */
      7 /*  Copyright 1996-2015 by                                                 */
      8 /*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
      9 /*                                                                         */
     10 /*  This file is part of the FreeType project, and may only be used,       */
     11 /*  modified, and distributed under the terms of the FreeType project      */
     12 /*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
     13 /*  this file you indicate that you have read the license and              */
     14 /*  understand and accept it fully.                                        */
     15 /*                                                                         */
     16 /***************************************************************************/
     17 
     18 
     19 #include <ft2build.h>
     20 #include "t1afm.h"
     21 #include FT_INTERNAL_DEBUG_H
     22 #include FT_INTERNAL_STREAM_H
     23 #include FT_INTERNAL_POSTSCRIPT_AUX_H
     24 #include "t1errors.h"
     25 
     26 
     27   /*************************************************************************/
     28   /*                                                                       */
     29   /* The macro FT_COMPONENT is used in trace mode.  It is an implicit      */
     30   /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log  */
     31   /* messages during execution.                                            */
     32   /*                                                                       */
     33 #undef  FT_COMPONENT
     34 #define FT_COMPONENT  trace_t1afm
     35 
     36 
     37   FT_LOCAL_DEF( void )
     38   T1_Done_Metrics( FT_Memory     memory,
     39                    AFM_FontInfo  fi )
     40   {
     41     FT_FREE( fi->KernPairs );
     42     fi->NumKernPair = 0;
     43 
     44     FT_FREE( fi->TrackKerns );
     45     fi->NumTrackKern = 0;
     46 
     47     FT_FREE( fi );
     48   }
     49 
     50 
     51   /* read a glyph name and return the equivalent glyph index */
     52   static FT_Int
     53   t1_get_index( const char*  name,
     54                 FT_Offset    len,
     55                 void*        user_data )
     56   {
     57     T1_Font  type1 = (T1_Font)user_data;
     58     FT_Int   n;
     59 
     60 
     61     /* PS string/name length must be < 16-bit */
     62     if ( len > 0xFFFFU )
     63       return 0;
     64 
     65     for ( n = 0; n < type1->num_glyphs; n++ )
     66     {
     67       char*  gname = (char*)type1->glyph_names[n];
     68 
     69 
     70       if ( gname && gname[0] == name[0]        &&
     71            ft_strlen( gname ) == len           &&
     72            ft_strncmp( gname, name, len ) == 0 )
     73         return n;
     74     }
     75 
     76     return 0;
     77   }
     78 
     79 
     80 #undef  KERN_INDEX
     81 #define KERN_INDEX( g1, g2 )  ( ( (FT_ULong)(g1) << 16 ) | (g2) )
     82 
     83 
     84   /* compare two kerning pairs */
     85   FT_CALLBACK_DEF( int )
     86   compare_kern_pairs( const void*  a,
     87                       const void*  b )
     88   {
     89     AFM_KernPair  pair1 = (AFM_KernPair)a;
     90     AFM_KernPair  pair2 = (AFM_KernPair)b;
     91 
     92     FT_ULong  index1 = KERN_INDEX( pair1->index1, pair1->index2 );
     93     FT_ULong  index2 = KERN_INDEX( pair2->index1, pair2->index2 );
     94 
     95 
     96     if ( index1 > index2 )
     97       return 1;
     98     else if ( index1 < index2 )
     99       return -1;
    100     else
    101       return 0;
    102   }
    103 
    104 
    105   /* parse a PFM file -- for now, only read the kerning pairs */
    106   static FT_Error
    107   T1_Read_PFM( FT_Face       t1_face,
    108                FT_Stream     stream,
    109                AFM_FontInfo  fi )
    110   {
    111     FT_Error      error  = FT_Err_Ok;
    112     FT_Memory     memory = stream->memory;
    113     FT_Byte*      start;
    114     FT_Byte*      limit;
    115     FT_Byte*      p;
    116     AFM_KernPair  kp;
    117     FT_Int        width_table_length;
    118     FT_CharMap    oldcharmap;
    119     FT_CharMap    charmap;
    120     FT_Int        n;
    121 
    122 
    123     start = (FT_Byte*)stream->cursor;
    124     limit = (FT_Byte*)stream->limit;
    125 
    126     /* Figure out how long the width table is.          */
    127     /* This info is a little-endian short at offset 99. */
    128     p = start + 99;
    129     if ( p + 2 > limit )
    130     {
    131       error = FT_THROW( Unknown_File_Format );
    132       goto Exit;
    133     }
    134     width_table_length = FT_PEEK_USHORT_LE( p );
    135 
    136     p += 18 + width_table_length;
    137     if ( p + 0x12 > limit || FT_PEEK_USHORT_LE( p ) < 0x12 )
    138       /* extension table is probably optional */
    139       goto Exit;
    140 
    141     /* Kerning offset is 14 bytes from start of extensions table. */
    142     p += 14;
    143     p = start + FT_PEEK_ULONG_LE( p );
    144 
    145     if ( p == start )
    146       /* zero offset means no table */
    147       goto Exit;
    148 
    149     if ( p + 2 > limit )
    150     {
    151       error = FT_THROW( Unknown_File_Format );
    152       goto Exit;
    153     }
    154 
    155     fi->NumKernPair = FT_PEEK_USHORT_LE( p );
    156     p += 2;
    157     if ( p + 4 * fi->NumKernPair > limit )
    158     {
    159       error = FT_THROW( Unknown_File_Format );
    160       goto Exit;
    161     }
    162 
    163     /* Actually, kerning pairs are simply optional! */
    164     if ( fi->NumKernPair == 0 )
    165       goto Exit;
    166 
    167     /* allocate the pairs */
    168     if ( FT_QNEW_ARRAY( fi->KernPairs, fi->NumKernPair ) )
    169       goto Exit;
    170 
    171     /* now, read each kern pair */
    172     kp    = fi->KernPairs;
    173     limit = p + 4 * fi->NumKernPair;
    174 
    175     /* PFM kerning data are stored by encoding rather than glyph index, */
    176     /* so find the PostScript charmap of this font and install it       */
    177     /* temporarily.  If we find no PostScript charmap, then just use    */
    178     /* the default and hope it is the right one.                        */
    179     oldcharmap = t1_face->charmap;
    180     charmap    = NULL;
    181 
    182     for ( n = 0; n < t1_face->num_charmaps; n++ )
    183     {
    184       charmap = t1_face->charmaps[n];
    185       /* check against PostScript pseudo platform */
    186       if ( charmap->platform_id == 7 )
    187       {
    188         error = FT_Set_Charmap( t1_face, charmap );
    189         if ( error )
    190           goto Exit;
    191         break;
    192       }
    193     }
    194 
    195     /* Kerning info is stored as:             */
    196     /*                                        */
    197     /*   encoding of first glyph (1 byte)     */
    198     /*   encoding of second glyph (1 byte)    */
    199     /*   offset (little-endian short)         */
    200     for ( ; p < limit ; p += 4 )
    201     {
    202       kp->index1 = FT_Get_Char_Index( t1_face, p[0] );
    203       kp->index2 = FT_Get_Char_Index( t1_face, p[1] );
    204 
    205       kp->x = (FT_Int)FT_PEEK_SHORT_LE(p + 2);
    206       kp->y = 0;
    207 
    208       kp++;
    209     }
    210 
    211     if ( oldcharmap != NULL )
    212       error = FT_Set_Charmap( t1_face, oldcharmap );
    213     if ( error )
    214       goto Exit;
    215 
    216     /* now, sort the kern pairs according to their glyph indices */
    217     ft_qsort( fi->KernPairs, fi->NumKernPair, sizeof ( AFM_KernPairRec ),
    218               compare_kern_pairs );
    219 
    220   Exit:
    221     if ( error )
    222     {
    223       FT_FREE( fi->KernPairs );
    224       fi->NumKernPair = 0;
    225     }
    226 
    227     return error;
    228   }
    229 
    230 
    231   /* parse a metrics file -- either AFM or PFM depending on what */
    232   /* it turns out to be                                          */
    233   FT_LOCAL_DEF( FT_Error )
    234   T1_Read_Metrics( FT_Face    t1_face,
    235                    FT_Stream  stream )
    236   {
    237     PSAux_Service  psaux;
    238     FT_Memory      memory  = stream->memory;
    239     AFM_ParserRec  parser;
    240     AFM_FontInfo   fi      = NULL;
    241     FT_Error       error   = FT_ERR( Unknown_File_Format );
    242     T1_Font        t1_font = &( (T1_Face)t1_face )->type1;
    243 
    244 
    245     if ( FT_NEW( fi )                   ||
    246          FT_FRAME_ENTER( stream->size ) )
    247       goto Exit;
    248 
    249     fi->FontBBox  = t1_font->font_bbox;
    250     fi->Ascender  = t1_font->font_bbox.yMax;
    251     fi->Descender = t1_font->font_bbox.yMin;
    252 
    253     psaux = (PSAux_Service)( (T1_Face)t1_face )->psaux;
    254     if ( psaux->afm_parser_funcs )
    255     {
    256       error = psaux->afm_parser_funcs->init( &parser,
    257                                              stream->memory,
    258                                              stream->cursor,
    259                                              stream->limit );
    260 
    261       if ( !error )
    262       {
    263         parser.FontInfo  = fi;
    264         parser.get_index = t1_get_index;
    265         parser.user_data = t1_font;
    266 
    267         error = psaux->afm_parser_funcs->parse( &parser );
    268         psaux->afm_parser_funcs->done( &parser );
    269       }
    270     }
    271 
    272     if ( FT_ERR_EQ( error, Unknown_File_Format ) )
    273     {
    274       FT_Byte*  start = stream->cursor;
    275 
    276 
    277       /* MS Windows allows versions up to 0x3FF without complaining */
    278       if ( stream->size > 6                              &&
    279            start[1] < 4                                  &&
    280            FT_PEEK_ULONG_LE( start + 2 ) == stream->size )
    281         error = T1_Read_PFM( t1_face, stream, fi );
    282     }
    283 
    284     if ( !error )
    285     {
    286       t1_font->font_bbox = fi->FontBBox;
    287 
    288       t1_face->bbox.xMin =   fi->FontBBox.xMin            >> 16;
    289       t1_face->bbox.yMin =   fi->FontBBox.yMin            >> 16;
    290       /* no `U' suffix here to 0xFFFF! */
    291       t1_face->bbox.xMax = ( fi->FontBBox.xMax + 0xFFFF ) >> 16;
    292       t1_face->bbox.yMax = ( fi->FontBBox.yMax + 0xFFFF ) >> 16;
    293 
    294       /* no `U' suffix here to 0x8000! */
    295       t1_face->ascender  = (FT_Short)( ( fi->Ascender  + 0x8000 ) >> 16 );
    296       t1_face->descender = (FT_Short)( ( fi->Descender + 0x8000 ) >> 16 );
    297 
    298       if ( fi->NumKernPair )
    299       {
    300         t1_face->face_flags |= FT_FACE_FLAG_KERNING;
    301         ( (T1_Face)t1_face )->afm_data = fi;
    302         fi = NULL;
    303       }
    304     }
    305 
    306     FT_FRAME_EXIT();
    307 
    308   Exit:
    309     if ( fi != NULL )
    310       T1_Done_Metrics( memory, fi );
    311 
    312     return error;
    313   }
    314 
    315 
    316   /* find the kerning for a given glyph pair */
    317   FT_LOCAL_DEF( void )
    318   T1_Get_Kerning( AFM_FontInfo  fi,
    319                   FT_UInt       glyph1,
    320                   FT_UInt       glyph2,
    321                   FT_Vector*    kerning )
    322   {
    323     AFM_KernPair  min, mid, max;
    324     FT_ULong      idx = KERN_INDEX( glyph1, glyph2 );
    325 
    326 
    327     /* simple binary search */
    328     min = fi->KernPairs;
    329     max = min + fi->NumKernPair - 1;
    330 
    331     while ( min <= max )
    332     {
    333       FT_ULong  midi;
    334 
    335 
    336       mid  = min + ( max - min ) / 2;
    337       midi = KERN_INDEX( mid->index1, mid->index2 );
    338 
    339       if ( midi == idx )
    340       {
    341         kerning->x = mid->x;
    342         kerning->y = mid->y;
    343 
    344         return;
    345       }
    346 
    347       if ( midi < idx )
    348         min = mid + 1;
    349       else
    350         max = mid - 1;
    351     }
    352 
    353     kerning->x = 0;
    354     kerning->y = 0;
    355   }
    356 
    357 
    358   FT_LOCAL_DEF( FT_Error )
    359   T1_Get_Track_Kerning( FT_Face    face,
    360                         FT_Fixed   ptsize,
    361                         FT_Int     degree,
    362                         FT_Fixed*  kerning )
    363   {
    364     AFM_FontInfo  fi = (AFM_FontInfo)( (T1_Face)face )->afm_data;
    365     FT_UInt       i;
    366 
    367 
    368     if ( !fi )
    369       return FT_THROW( Invalid_Argument );
    370 
    371     for ( i = 0; i < fi->NumTrackKern; i++ )
    372     {
    373       AFM_TrackKern  tk = fi->TrackKerns + i;
    374 
    375 
    376       if ( tk->degree != degree )
    377         continue;
    378 
    379       if ( ptsize < tk->min_ptsize )
    380         *kerning = tk->min_kern;
    381       else if ( ptsize > tk->max_ptsize )
    382         *kerning = tk->max_kern;
    383       else
    384       {
    385         *kerning = FT_MulDiv( ptsize - tk->min_ptsize,
    386                               tk->max_kern - tk->min_kern,
    387                               tk->max_ptsize - tk->min_ptsize ) +
    388                    tk->min_kern;
    389       }
    390     }
    391 
    392     return FT_Err_Ok;
    393   }
    394 
    395 
    396 /* END */
    397