PageRenderTime 70ms CodeModel.GetById 16ms app.highlight 49ms RepoModel.GetById 1ms app.codeStats 0ms

/modules/freetype2/src/type1/t1afm.c

http://github.com/zpao/v8monkey
C | 397 lines | 258 code | 85 blank | 54 comment | 52 complexity | 7b54f6e4bead7ded59951433c4709536 MD5 | raw file
  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 */