misc/libfreetype/src/type1/t1afm.c
branchwebgl
changeset 9521 8054d9d775fd
parent 9282 92af50454cf2
parent 9519 b8b5c82eb61b
child 9950 2759212a27de
equal deleted inserted replaced
9282:92af50454cf2 9521:8054d9d775fd
     1 /***************************************************************************/
       
     2 /*                                                                         */
       
     3 /*  t1afm.c                                                                */
       
     4 /*                                                                         */
       
     5 /*    AFM support for Type 1 fonts (body).                                 */
       
     6 /*                                                                         */
       
     7 /*  Copyright 1996-2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009,   */
       
     8 /*            2010 by                                                      */
       
     9 /*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
       
    10 /*                                                                         */
       
    11 /*  This file is part of the FreeType project, and may only be used,       */
       
    12 /*  modified, and distributed under the terms of the FreeType project      */
       
    13 /*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
       
    14 /*  this file you indicate that you have read the license and              */
       
    15 /*  understand and accept it fully.                                        */
       
    16 /*                                                                         */
       
    17 /***************************************************************************/
       
    18 
       
    19 
       
    20 #include <ft2build.h>
       
    21 #include "t1afm.h"
       
    22 #include "t1errors.h"
       
    23 #include FT_INTERNAL_STREAM_H
       
    24 #include FT_INTERNAL_POSTSCRIPT_AUX_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 = T1_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     p     = start;
       
   126 
       
   127     /* Figure out how long the width table is.          */
       
   128     /* This info is a little-endian short at offset 99. */
       
   129     p = start + 99;
       
   130     if ( p + 2 > limit )
       
   131     {
       
   132       error = T1_Err_Unknown_File_Format;
       
   133       goto Exit;
       
   134     }
       
   135     width_table_length = FT_PEEK_USHORT_LE( p );
       
   136 
       
   137     p += 18 + width_table_length;
       
   138     if ( p + 0x12 > limit || FT_PEEK_USHORT_LE( p ) < 0x12 )
       
   139       /* extension table is probably optional */
       
   140       goto Exit;
       
   141 
       
   142     /* Kerning offset is 14 bytes from start of extensions table. */
       
   143     p += 14;
       
   144     p = start + FT_PEEK_ULONG_LE( p );
       
   145 
       
   146     if ( p == start )
       
   147       /* zero offset means no table */
       
   148       goto Exit;
       
   149 
       
   150     if ( p + 2 > limit )
       
   151     {
       
   152       error = T1_Err_Unknown_File_Format;
       
   153       goto Exit;
       
   154     }
       
   155 
       
   156     fi->NumKernPair = FT_PEEK_USHORT_LE( p );
       
   157     p += 2;
       
   158     if ( p + 4 * fi->NumKernPair > limit )
       
   159     {
       
   160       error = T1_Err_Unknown_File_Format;
       
   161       goto Exit;
       
   162     }
       
   163 
       
   164     /* Actually, kerning pairs are simply optional! */
       
   165     if ( fi->NumKernPair == 0 )
       
   166       goto Exit;
       
   167 
       
   168     /* allocate the pairs */
       
   169     if ( FT_QNEW_ARRAY( fi->KernPairs, fi->NumKernPair ) )
       
   170       goto Exit;
       
   171 
       
   172     /* now, read each kern pair */
       
   173     kp             = fi->KernPairs;
       
   174     limit          = p + 4 * fi->NumKernPair;
       
   175 
       
   176     /* PFM kerning data are stored by encoding rather than glyph index, */
       
   177     /* so find the PostScript charmap of this font and install it       */
       
   178     /* temporarily.  If we find no PostScript charmap, then just use    */
       
   179     /* the default and hope it is the right one.                        */
       
   180     oldcharmap = t1_face->charmap;
       
   181     charmap    = NULL;
       
   182 
       
   183     for ( n = 0; n < t1_face->num_charmaps; n++ )
       
   184     {
       
   185       charmap = t1_face->charmaps[n];
       
   186       /* check against PostScript pseudo platform */
       
   187       if ( charmap->platform_id == 7 )
       
   188       {
       
   189         error = FT_Set_Charmap( t1_face, charmap );
       
   190         if ( error )
       
   191           goto Exit;
       
   192         break;
       
   193       }
       
   194     }
       
   195 
       
   196     /* Kerning info is stored as:             */
       
   197     /*                                        */
       
   198     /*   encoding of first glyph (1 byte)     */
       
   199     /*   encoding of second glyph (1 byte)    */
       
   200     /*   offset (little-endian short)         */
       
   201     for ( ; p < limit ; p += 4 )
       
   202     {
       
   203       kp->index1 = FT_Get_Char_Index( t1_face, p[0] );
       
   204       kp->index2 = FT_Get_Char_Index( t1_face, p[1] );
       
   205 
       
   206       kp->x = (FT_Int)FT_PEEK_SHORT_LE(p + 2);
       
   207       kp->y = 0;
       
   208 
       
   209       kp++;
       
   210     }
       
   211 
       
   212     if ( oldcharmap != NULL )
       
   213       error = FT_Set_Charmap( t1_face, oldcharmap );
       
   214     if ( error )
       
   215       goto Exit;
       
   216 
       
   217     /* now, sort the kern pairs according to their glyph indices */
       
   218     ft_qsort( fi->KernPairs, fi->NumKernPair, sizeof ( AFM_KernPairRec ),
       
   219               compare_kern_pairs );
       
   220 
       
   221   Exit:
       
   222     if ( error )
       
   223     {
       
   224       FT_FREE( fi->KernPairs );
       
   225       fi->NumKernPair = 0;
       
   226     }
       
   227 
       
   228     return error;
       
   229   }
       
   230 
       
   231 
       
   232   /* parse a metrics file -- either AFM or PFM depending on what */
       
   233   /* it turns out to be                                          */
       
   234   FT_LOCAL_DEF( FT_Error )
       
   235   T1_Read_Metrics( FT_Face    t1_face,
       
   236                    FT_Stream  stream )
       
   237   {
       
   238     PSAux_Service  psaux;
       
   239     FT_Memory      memory  = stream->memory;
       
   240     AFM_ParserRec  parser;
       
   241     AFM_FontInfo   fi      = NULL;
       
   242     FT_Error       error   = T1_Err_Unknown_File_Format;
       
   243     T1_Font        t1_font = &( (T1_Face)t1_face )->type1;
       
   244 
       
   245 
       
   246     if ( FT_NEW( fi )                   ||
       
   247          FT_FRAME_ENTER( stream->size ) )
       
   248       goto Exit;
       
   249 
       
   250     fi->FontBBox  = t1_font->font_bbox;
       
   251     fi->Ascender  = t1_font->font_bbox.yMax;
       
   252     fi->Descender = t1_font->font_bbox.yMin;
       
   253 
       
   254     psaux = (PSAux_Service)( (T1_Face)t1_face )->psaux;
       
   255     if ( psaux && psaux->afm_parser_funcs )
       
   256     {
       
   257       error = psaux->afm_parser_funcs->init( &parser,
       
   258                                              stream->memory,
       
   259                                              stream->cursor,
       
   260                                              stream->limit );
       
   261 
       
   262       if ( !error )
       
   263       {
       
   264         parser.FontInfo  = fi;
       
   265         parser.get_index = t1_get_index;
       
   266         parser.user_data = t1_font;
       
   267 
       
   268         error = psaux->afm_parser_funcs->parse( &parser );
       
   269         psaux->afm_parser_funcs->done( &parser );
       
   270       }
       
   271     }
       
   272 
       
   273     if ( error == T1_Err_Unknown_File_Format )
       
   274     {
       
   275       FT_Byte*  start = stream->cursor;
       
   276 
       
   277 
       
   278       /* MS Windows allows versions up to 0x3FF without complaining */
       
   279       if ( stream->size > 6                              &&
       
   280            start[1] < 4                                  &&
       
   281            FT_PEEK_ULONG_LE( start + 2 ) == stream->size )
       
   282         error = T1_Read_PFM( t1_face, stream, fi );
       
   283     }
       
   284 
       
   285     if ( !error )
       
   286     {
       
   287       t1_font->font_bbox = fi->FontBBox;
       
   288 
       
   289       t1_face->bbox.xMin =   fi->FontBBox.xMin            >> 16;
       
   290       t1_face->bbox.yMin =   fi->FontBBox.yMin            >> 16;
       
   291       /* no `U' suffix here to 0xFFFF! */
       
   292       t1_face->bbox.xMax = ( fi->FontBBox.xMax + 0xFFFF ) >> 16;
       
   293       t1_face->bbox.yMax = ( fi->FontBBox.yMax + 0xFFFF ) >> 16;
       
   294 
       
   295       /* no `U' suffix here to 0x8000! */
       
   296       t1_face->ascender  = (FT_Short)( ( fi->Ascender  + 0x8000 ) >> 16 );
       
   297       t1_face->descender = (FT_Short)( ( fi->Descender + 0x8000 ) >> 16 );
       
   298 
       
   299       if ( fi->NumKernPair )
       
   300       {
       
   301         t1_face->face_flags |= FT_FACE_FLAG_KERNING;
       
   302         ( (T1_Face)t1_face )->afm_data = fi;
       
   303         fi = NULL;
       
   304       }
       
   305     }
       
   306 
       
   307     FT_FRAME_EXIT();
       
   308 
       
   309   Exit:
       
   310     if ( fi != NULL )
       
   311       T1_Done_Metrics( memory, fi );
       
   312 
       
   313     return error;
       
   314   }
       
   315 
       
   316 
       
   317   /* find the kerning for a given glyph pair */
       
   318   FT_LOCAL_DEF( void )
       
   319   T1_Get_Kerning( AFM_FontInfo  fi,
       
   320                   FT_UInt       glyph1,
       
   321                   FT_UInt       glyph2,
       
   322                   FT_Vector*    kerning )
       
   323   {
       
   324     AFM_KernPair  min, mid, max;
       
   325     FT_ULong      idx = KERN_INDEX( glyph1, glyph2 );
       
   326 
       
   327 
       
   328     /* simple binary search */
       
   329     min = fi->KernPairs;
       
   330     max = min + fi->NumKernPair - 1;
       
   331 
       
   332     while ( min <= max )
       
   333     {
       
   334       FT_ULong  midi;
       
   335 
       
   336 
       
   337       mid  = min + ( max - min ) / 2;
       
   338       midi = KERN_INDEX( mid->index1, mid->index2 );
       
   339 
       
   340       if ( midi == idx )
       
   341       {
       
   342         kerning->x = mid->x;
       
   343         kerning->y = mid->y;
       
   344 
       
   345         return;
       
   346       }
       
   347 
       
   348       if ( midi < idx )
       
   349         min = mid + 1;
       
   350       else
       
   351         max = mid - 1;
       
   352     }
       
   353 
       
   354     kerning->x = 0;
       
   355     kerning->y = 0;
       
   356   }
       
   357 
       
   358 
       
   359   FT_LOCAL_DEF( FT_Error )
       
   360   T1_Get_Track_Kerning( FT_Face    face,
       
   361                         FT_Fixed   ptsize,
       
   362                         FT_Int     degree,
       
   363                         FT_Fixed*  kerning )
       
   364   {
       
   365     AFM_FontInfo  fi = (AFM_FontInfo)( (T1_Face)face )->afm_data;
       
   366     FT_Int        i;
       
   367 
       
   368 
       
   369     if ( !fi )
       
   370       return T1_Err_Invalid_Argument;
       
   371 
       
   372     for ( i = 0; i < fi->NumTrackKern; i++ )
       
   373     {
       
   374       AFM_TrackKern  tk = fi->TrackKerns + i;
       
   375 
       
   376 
       
   377       if ( tk->degree != degree )
       
   378         continue;
       
   379 
       
   380       if ( ptsize < tk->min_ptsize )
       
   381         *kerning = tk->min_kern;
       
   382       else if ( ptsize > tk->max_ptsize )
       
   383         *kerning = tk->max_kern;
       
   384       else
       
   385       {
       
   386         *kerning = FT_MulDiv( ptsize - tk->min_ptsize,
       
   387                               tk->max_kern - tk->min_kern,
       
   388                               tk->max_ptsize - tk->min_ptsize ) +
       
   389                    tk->min_kern;
       
   390       }
       
   391     }
       
   392 
       
   393     return T1_Err_Ok;
       
   394   }
       
   395 
       
   396 
       
   397 /* END */