Subversion Repositories Kolibri OS

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
4349 Serge 1
/***************************************************************************/
2
/*                                                                         */
3
/*  t1afm.c                                                                */
4
/*                                                                         */
5
/*    AFM support for Type 1 fonts (body).                                 */
6
/*                                                                         */
7
/*  Copyright 1996-2011, 2013 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 
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_Int        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 */