source: trunk/poppler/freetype2/src/type1/t1afm.c @ 262

Last change on this file since 262 was 262, checked in by Eugene Romanenko, 12 years ago

PDF plugin: freetype library updated to version 2.3.8

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