t1afm.c

Go to the documentation of this file.
00001 /***************************************************************************/
00002 /*                                                                         */
00003 /*  t1afm.c                                                                */
00004 /*                                                                         */
00005 /*    AFM support for Type 1 fonts (body).                                 */
00006 /*                                                                         */
00007 /*  Copyright 1996-2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 by */
00008 /*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
00009 /*                                                                         */
00010 /*  This file is part of the FreeType project, and may only be used,       */
00011 /*  modified, and distributed under the terms of the FreeType project      */
00012 /*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
00013 /*  this file you indicate that you have read the license and              */
00014 /*  understand and accept it fully.                                        */
00015 /*                                                                         */
00016 /***************************************************************************/
00017 
00018 
00019 #include <ft2build.h>
00020 #include "t1afm.h"
00021 #include "t1errors.h"
00022 #include FT_INTERNAL_STREAM_H
00023 #include FT_INTERNAL_POSTSCRIPT_AUX_H
00024 
00025 
00026   /*************************************************************************/
00027   /*                                                                       */
00028   /* The macro FT_COMPONENT is used in trace mode.  It is an implicit      */
00029   /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log  */
00030   /* messages during execution.                                            */
00031   /*                                                                       */
00032 #undef  FT_COMPONENT
00033 #define FT_COMPONENT  trace_t1afm
00034 
00035 
00036   FT_LOCAL_DEF( void )
00037   T1_Done_Metrics( FT_Memory     memory,
00038                    AFM_FontInfo  fi )
00039   {
00040     FT_FREE( fi->KernPairs );
00041     fi->NumKernPair = 0;
00042 
00043     FT_FREE( fi->TrackKerns );
00044     fi->NumTrackKern = 0;
00045 
00046     FT_FREE( fi );
00047   }
00048 
00049 
00050   /* read a glyph name and return the equivalent glyph index */
00051   static FT_Int
00052   t1_get_index( const char*  name,
00053                 FT_Offset    len,
00054                 void*        user_data )
00055   {
00056     T1_Font  type1 = (T1_Font)user_data;
00057     FT_Int   n;
00058 
00059 
00060     /* PS string/name length must be < 16-bit */
00061     if ( len > 0xFFFFU )
00062       return 0;
00063 
00064     for ( n = 0; n < type1->num_glyphs; n++ )
00065     {
00066       char*  gname = (char*)type1->glyph_names[n];
00067 
00068 
00069       if ( gname && gname[0] == name[0]        &&
00070            ft_strlen( gname ) == len           &&
00071            ft_strncmp( gname, name, len ) == 0 )
00072         return n;
00073     }
00074 
00075     return 0;
00076   }
00077 
00078 
00079 #undef  KERN_INDEX
00080 #define KERN_INDEX( g1, g2 )  ( ( (FT_ULong)(g1) << 16 ) | (g2) )
00081 
00082 
00083   /* compare two kerning pairs */
00084   FT_CALLBACK_DEF( int )
00085   compare_kern_pairs( const void*  a,
00086                       const void*  b )
00087   {
00088     AFM_KernPair  pair1 = (AFM_KernPair)a;
00089     AFM_KernPair  pair2 = (AFM_KernPair)b;
00090 
00091     FT_ULong  index1 = KERN_INDEX( pair1->index1, pair1->index2 );
00092     FT_ULong  index2 = KERN_INDEX( pair2->index1, pair2->index2 );
00093 
00094 
00095     if ( index1 > index2 )
00096       return 1;
00097     else if ( index1 < index2 )
00098       return -1;
00099     else
00100       return 0;
00101   }
00102 
00103 
00104   /* parse a PFM file -- for now, only read the kerning pairs */
00105   static FT_Error
00106   T1_Read_PFM( FT_Face       t1_face,
00107                FT_Stream     stream,
00108                AFM_FontInfo  fi )
00109   {
00110     FT_Error      error = T1_Err_Ok;
00111     FT_Memory     memory = stream->memory;
00112     FT_Byte*      start;
00113     FT_Byte*      limit;
00114     FT_Byte*      p;
00115     AFM_KernPair  kp;
00116     FT_Int        width_table_length;
00117     FT_CharMap    oldcharmap;
00118     FT_CharMap    charmap;
00119     FT_Int        n;
00120 
00121 
00122     start = (FT_Byte*)stream->cursor;
00123     limit = (FT_Byte*)stream->limit;
00124     p     = start;
00125 
00126     /* Figure out how long the width table is.          */
00127     /* This info is a little-endian short at offset 99. */
00128     p = start + 99;
00129     if ( p + 2 > limit )
00130     {
00131       error = T1_Err_Unknown_File_Format;
00132       goto Exit;
00133     }
00134     width_table_length = FT_PEEK_USHORT_LE( p );
00135 
00136     p += 18 + width_table_length;
00137     if ( p + 0x12 > limit || FT_PEEK_USHORT_LE( p ) < 0x12 )
00138       /* extension table is probably optional */
00139       goto Exit;
00140 
00141     /* Kerning offset is 14 bytes from start of extensions table. */
00142     p += 14;
00143     p = start + FT_PEEK_ULONG_LE( p );
00144 
00145     if ( p == start )
00146       /* zero offset means no table */
00147       goto Exit;
00148 
00149     if ( p + 2 > limit )
00150     {
00151       error = T1_Err_Unknown_File_Format;
00152       goto Exit;
00153     }
00154 
00155     fi->NumKernPair = FT_PEEK_USHORT_LE( p );
00156     p += 2;
00157     if ( p + 4 * fi->NumKernPair > limit )
00158     {
00159       error = T1_Err_Unknown_File_Format;
00160       goto Exit;
00161     }
00162 
00163     /* Actually, kerning pairs are simply optional! */
00164     if ( fi->NumKernPair == 0 )
00165       goto Exit;
00166 
00167     /* allocate the pairs */
00168     if ( FT_QNEW_ARRAY( fi->KernPairs, fi->NumKernPair ) )
00169       goto Exit;
00170 
00171     /* now, read each kern pair */
00172     kp             = fi->KernPairs;
00173     limit          = p + 4 * fi->NumKernPair;
00174 
00175     /* PFM kerning data are stored by encoding rather than glyph index, */
00176     /* so find the PostScript charmap of this font and install it       */
00177     /* temporarily.  If we find no PostScript charmap, then just use    */
00178     /* the default and hope it is the right one.                        */
00179     oldcharmap = t1_face->charmap;
00180     charmap    = NULL;
00181 
00182     for ( n = 0; n < t1_face->num_charmaps; n++ )
00183     {
00184       charmap = t1_face->charmaps[n];
00185       /* check against PostScript pseudo platform */
00186       if ( charmap->platform_id == 7 )
00187       {
00188         error = FT_Set_Charmap( t1_face, charmap );
00189         if ( error )
00190           goto Exit;
00191         break;
00192       }
00193     }
00194 
00195     /* Kerning info is stored as:             */
00196     /*                                        */
00197     /*   encoding of first glyph (1 byte)     */
00198     /*   encoding of second glyph (1 byte)    */
00199     /*   offset (little-endian short)         */
00200     for ( ; p < limit ; p += 4 )
00201     {
00202       kp->index1 = FT_Get_Char_Index( t1_face, p[0] );
00203       kp->index2 = FT_Get_Char_Index( t1_face, p[1] );
00204 
00205       kp->x = (FT_Int)FT_PEEK_SHORT_LE(p + 2);
00206       kp->y = 0;
00207 
00208       kp++;
00209     }
00210 
00211     if ( oldcharmap != NULL )
00212       error = FT_Set_Charmap( t1_face, oldcharmap );
00213     if ( error )
00214       goto Exit;
00215 
00216     /* now, sort the kern pairs according to their glyph indices */
00217     ft_qsort( fi->KernPairs, fi->NumKernPair, sizeof ( AFM_KernPairRec ),
00218               compare_kern_pairs );
00219 
00220   Exit:
00221     if ( error )
00222     {
00223       FT_FREE( fi->KernPairs );
00224       fi->NumKernPair = 0;
00225     }
00226 
00227     return error;
00228   }
00229 
00230 
00231   /* parse a metrics file -- either AFM or PFM depending on what */
00232   /* it turns out to be                                          */
00233   FT_LOCAL_DEF( FT_Error )
00234   T1_Read_Metrics( FT_Face    t1_face,
00235                    FT_Stream  stream )
00236   {
00237     PSAux_Service  psaux;
00238     FT_Memory      memory = stream->memory;
00239     AFM_ParserRec  parser;
00240     AFM_FontInfo   fi;
00241     FT_Error       error = T1_Err_Unknown_File_Format;
00242     T1_Font        t1_font = &( (T1_Face)t1_face )->type1;
00243 
00244 
00245     if ( FT_NEW( fi )                   ||
00246          FT_FRAME_ENTER( stream->size ) )
00247       goto Exit;
00248 
00249     fi->FontBBox  = t1_font->font_bbox;
00250     fi->Ascender  = t1_font->font_bbox.yMax;
00251     fi->Descender = t1_font->font_bbox.yMin;
00252 
00253     psaux = (PSAux_Service)( (T1_Face)t1_face )->psaux;
00254     if ( psaux && psaux->afm_parser_funcs )
00255     {
00256       error = psaux->afm_parser_funcs->init( &parser,
00257                                              stream->memory,
00258                                              stream->cursor,
00259                                              stream->limit );
00260 
00261       if ( !error )
00262       {
00263         parser.FontInfo  = fi;
00264         parser.get_index = t1_get_index;
00265         parser.user_data = t1_font;
00266 
00267         error = psaux->afm_parser_funcs->parse( &parser );
00268         psaux->afm_parser_funcs->done( &parser );
00269       }
00270     }
00271 
00272     if ( error == T1_Err_Unknown_File_Format )
00273     {
00274       FT_Byte*  start = stream->cursor;
00275 
00276 
00277       /* MS Windows allows versions up to 0x3FF without complaining */
00278       if ( stream->size > 6                              &&
00279            start[1] < 4                                  &&
00280            FT_PEEK_ULONG_LE( start + 2 ) == stream->size )
00281         error = T1_Read_PFM( t1_face, stream, fi );
00282     }
00283 
00284     if ( !error )
00285     {
00286       t1_font->font_bbox = fi->FontBBox;
00287 
00288       t1_face->bbox.xMin =   fi->FontBBox.xMin            >> 16;
00289       t1_face->bbox.yMin =   fi->FontBBox.yMin            >> 16;
00290       /* no `U' suffix here to 0xFFFF! */
00291       t1_face->bbox.xMax = ( fi->FontBBox.xMax + 0xFFFF ) >> 16;
00292       t1_face->bbox.yMax = ( fi->FontBBox.yMax + 0xFFFF ) >> 16;
00293 
00294       /* no `U' suffix here to 0x8000! */
00295       t1_face->ascender  = (FT_Short)( ( fi->Ascender  + 0x8000 ) >> 16 );
00296       t1_face->descender = (FT_Short)( ( fi->Descender + 0x8000 ) >> 16 );
00297 
00298       if ( fi->NumKernPair )
00299       {
00300         t1_face->face_flags |= FT_FACE_FLAG_KERNING;
00301         ( (T1_Face)t1_face )->afm_data = fi;
00302         fi = NULL;
00303       }
00304     }
00305 
00306     FT_FRAME_EXIT();
00307 
00308   Exit:
00309     if ( fi != NULL )
00310       T1_Done_Metrics( memory, fi );
00311 
00312     return error;
00313   }
00314 
00315 
00316   /* find the kerning for a given glyph pair */
00317   FT_LOCAL_DEF( void )
00318   T1_Get_Kerning( AFM_FontInfo  fi,
00319                   FT_UInt       glyph1,
00320                   FT_UInt       glyph2,
00321                   FT_Vector*    kerning )
00322   {
00323     AFM_KernPair  min, mid, max;
00324     FT_ULong      idx = KERN_INDEX( glyph1, glyph2 );
00325 
00326 
00327     /* simple binary search */
00328     min = fi->KernPairs;
00329     max = min + fi->NumKernPair - 1;
00330 
00331     while ( min <= max )
00332     {
00333       FT_ULong  midi;
00334 
00335 
00336       mid  = min + ( max - min ) / 2;
00337       midi = KERN_INDEX( mid->index1, mid->index2 );
00338 
00339       if ( midi == idx )
00340       {
00341         kerning->x = mid->x;
00342         kerning->y = mid->y;
00343 
00344         return;
00345       }
00346 
00347       if ( midi < idx )
00348         min = mid + 1;
00349       else
00350         max = mid - 1;
00351     }
00352 
00353     kerning->x = 0;
00354     kerning->y = 0;
00355   }
00356 
00357 
00358   FT_LOCAL_DEF( FT_Error )
00359   T1_Get_Track_Kerning( FT_Face    face,
00360                         FT_Fixed   ptsize,
00361                         FT_Int     degree,
00362                         FT_Fixed*  kerning )
00363   {
00364     AFM_FontInfo  fi = (AFM_FontInfo)( (T1_Face)face )->afm_data;
00365     FT_Int        i;
00366 
00367 
00368     if ( !fi )
00369       return T1_Err_Invalid_Argument;
00370 
00371     for ( i = 0; i < fi->NumTrackKern; i++ )
00372     {
00373       AFM_TrackKern  tk = fi->TrackKerns + i;
00374 
00375 
00376       if ( tk->degree != degree )
00377         continue;
00378 
00379       if ( ptsize < tk->min_ptsize )
00380         *kerning = tk->min_kern;
00381       else if ( ptsize > tk->max_ptsize )
00382         *kerning = tk->max_kern;
00383       else
00384       {
00385         *kerning = FT_MulDiv( ptsize - tk->min_ptsize,
00386                               tk->max_kern - tk->min_kern,
00387                               tk->max_ptsize - tk->min_ptsize ) +
00388                    tk->min_kern;
00389       }
00390     }
00391 
00392     return T1_Err_Ok;
00393   }
00394 
00395 
00396 /* END */

Generated on Tue Jul 5 14:13:54 2011 for ROOT_528-00b_version by  doxygen 1.5.1