Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
4349 Serge 1
/***************************************************************************/
2
/*                                                                         */
3
/*  ttpost.c                                                               */
4
/*                                                                         */
5
/*    Postcript name table processing for TrueType and OpenType fonts      */
6
/*    (body).                                                              */
7
/*                                                                         */
8
/*  Copyright 1996-2003, 2006-2010, 2013 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
  /*                                                                       */
21
  /* The post table is not completely loaded by the core engine.  This     */
22
  /* file loads the missing PS glyph names and implements an API to access */
23
  /* them.                                                                 */
24
  /*                                                                       */
25
  /*************************************************************************/
26
 
27
 
28
#include 
29
#include FT_INTERNAL_DEBUG_H
30
#include FT_INTERNAL_STREAM_H
31
#include FT_TRUETYPE_TAGS_H
32
#include "ttpost.h"
33
 
34
#include "sferrors.h"
35
 
36
 
37
  /*************************************************************************/
38
  /*                                                                       */
39
  /* The macro FT_COMPONENT is used in trace mode.  It is an implicit      */
40
  /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log  */
41
  /* messages during execution.                                            */
42
  /*                                                                       */
43
#undef  FT_COMPONENT
44
#define FT_COMPONENT  trace_ttpost
45
 
46
 
47
  /* If this configuration macro is defined, we rely on the `PSNames' */
48
  /* module to grab the glyph names.                                  */
49
 
50
#ifdef FT_CONFIG_OPTION_POSTSCRIPT_NAMES
51
 
52
 
53
#include FT_SERVICE_POSTSCRIPT_CMAPS_H
54
 
55
#define MAC_NAME( x )  ( (FT_String*)psnames->macintosh_name( x ) )
56
 
57
 
58
#else /* FT_CONFIG_OPTION_POSTSCRIPT_NAMES */
59
 
60
 
61
   /* Otherwise, we ignore the `PSNames' module, and provide our own  */
62
   /* table of Mac names.  Thus, it is possible to build a version of */
63
   /* FreeType without the Type 1 driver & PSNames module.            */
64
 
65
#define MAC_NAME( x )  ( (FT_String*)tt_post_default_names[x] )
66
 
67
  /* the 258 default Mac PS glyph names */
68
 
69
  static const FT_String* const  tt_post_default_names[258] =
70
  {
71
    /*   0 */
72
    ".notdef", ".null", "CR", "space", "exclam",
73
    "quotedbl", "numbersign", "dollar", "percent", "ampersand",
74
    /*  10 */
75
    "quotesingle", "parenleft", "parenright", "asterisk", "plus",
76
    "comma", "hyphen", "period", "slash", "zero",
77
    /*  20 */
78
    "one", "two", "three", "four", "five",
79
    "six", "seven", "eight", "nine", "colon",
80
    /*  30 */
81
    "semicolon", "less", "equal", "greater", "question",
82
    "at", "A", "B", "C", "D",
83
    /*  40 */
84
    "E", "F", "G", "H", "I",
85
    "J", "K", "L", "M", "N",
86
    /*  50 */
87
    "O", "P", "Q", "R", "S",
88
    "T", "U", "V", "W", "X",
89
    /*  60 */
90
    "Y", "Z", "bracketleft", "backslash", "bracketright",
91
    "asciicircum", "underscore", "grave", "a", "b",
92
    /*  70 */
93
    "c", "d", "e", "f", "g",
94
    "h", "i", "j", "k", "l",
95
    /*  80 */
96
    "m", "n", "o", "p", "q",
97
    "r", "s", "t", "u", "v",
98
    /*  90 */
99
    "w", "x", "y", "z", "braceleft",
100
    "bar", "braceright", "asciitilde", "Adieresis", "Aring",
101
    /* 100 */
102
    "Ccedilla", "Eacute", "Ntilde", "Odieresis", "Udieresis",
103
    "aacute", "agrave", "acircumflex", "adieresis", "atilde",
104
    /* 110 */
105
    "aring", "ccedilla", "eacute", "egrave", "ecircumflex",
106
    "edieresis", "iacute", "igrave", "icircumflex", "idieresis",
107
    /* 120 */
108
    "ntilde", "oacute", "ograve", "ocircumflex", "odieresis",
109
    "otilde", "uacute", "ugrave", "ucircumflex", "udieresis",
110
    /* 130 */
111
    "dagger", "degree", "cent", "sterling", "section",
112
    "bullet", "paragraph", "germandbls", "registered", "copyright",
113
    /* 140 */
114
    "trademark", "acute", "dieresis", "notequal", "AE",
115
    "Oslash", "infinity", "plusminus", "lessequal", "greaterequal",
116
    /* 150 */
117
    "yen", "mu", "partialdiff", "summation", "product",
118
    "pi", "integral", "ordfeminine", "ordmasculine", "Omega",
119
    /* 160 */
120
    "ae", "oslash", "questiondown", "exclamdown", "logicalnot",
121
    "radical", "florin", "approxequal", "Delta", "guillemotleft",
122
    /* 170 */
123
    "guillemotright", "ellipsis", "nbspace", "Agrave", "Atilde",
124
    "Otilde", "OE", "oe", "endash", "emdash",
125
    /* 180 */
126
    "quotedblleft", "quotedblright", "quoteleft", "quoteright", "divide",
127
    "lozenge", "ydieresis", "Ydieresis", "fraction", "currency",
128
    /* 190 */
129
    "guilsinglleft", "guilsinglright", "fi", "fl", "daggerdbl",
130
    "periodcentered", "quotesinglbase", "quotedblbase", "perthousand", "Acircumflex",
131
    /* 200 */
132
    "Ecircumflex", "Aacute", "Edieresis", "Egrave", "Iacute",
133
    "Icircumflex", "Idieresis", "Igrave", "Oacute", "Ocircumflex",
134
    /* 210 */
135
    "apple", "Ograve", "Uacute", "Ucircumflex", "Ugrave",
136
    "dotlessi", "circumflex", "tilde", "macron", "breve",
137
    /* 220 */
138
    "dotaccent", "ring", "cedilla", "hungarumlaut", "ogonek",
139
    "caron", "Lslash", "lslash", "Scaron", "scaron",
140
    /* 230 */
141
    "Zcaron", "zcaron", "brokenbar", "Eth", "eth",
142
    "Yacute", "yacute", "Thorn", "thorn", "minus",
143
    /* 240 */
144
    "multiply", "onesuperior", "twosuperior", "threesuperior", "onehalf",
145
    "onequarter", "threequarters", "franc", "Gbreve", "gbreve",
146
    /* 250 */
147
    "Idot", "Scedilla", "scedilla", "Cacute", "cacute",
148
    "Ccaron", "ccaron", "dmacron",
149
  };
150
 
151
 
152
#endif /* FT_CONFIG_OPTION_POSTSCRIPT_NAMES */
153
 
154
 
155
  static FT_Error
156
  load_format_20( TT_Face    face,
157
                  FT_Stream  stream,
158
                  FT_Long    post_limit )
159
  {
160
    FT_Memory   memory = stream->memory;
161
    FT_Error    error;
162
 
163
    FT_Int      num_glyphs;
164
    FT_UShort   num_names;
165
 
166
    FT_UShort*  glyph_indices = 0;
167
    FT_Char**   name_strings  = 0;
168
 
169
 
170
    if ( FT_READ_USHORT( num_glyphs ) )
171
      goto Exit;
172
 
173
    /* UNDOCUMENTED!  The number of glyphs in this table can be smaller */
174
    /* than the value in the maxp table (cf. cyberbit.ttf).             */
175
 
176
    /* There already exist fonts which have more than 32768 glyph names */
177
    /* in this table, so the test for this threshold has been dropped.  */
178
 
179
    if ( num_glyphs > face->max_profile.numGlyphs )
180
    {
181
      error = FT_THROW( Invalid_File_Format );
182
      goto Exit;
183
    }
184
 
185
    /* load the indices */
186
    {
187
      FT_Int  n;
188
 
189
 
190
      if ( FT_NEW_ARRAY ( glyph_indices, num_glyphs ) ||
191
           FT_FRAME_ENTER( num_glyphs * 2L )          )
192
        goto Fail;
193
 
194
      for ( n = 0; n < num_glyphs; n++ )
195
        glyph_indices[n] = FT_GET_USHORT();
196
 
197
      FT_FRAME_EXIT();
198
    }
199
 
200
    /* compute number of names stored in table */
201
    {
202
      FT_Int  n;
203
 
204
 
205
      num_names = 0;
206
 
207
      for ( n = 0; n < num_glyphs; n++ )
208
      {
209
        FT_Int  idx;
210
 
211
 
212
        idx = glyph_indices[n];
213
        if ( idx >= 258 )
214
        {
215
          idx -= 257;
216
          if ( idx > num_names )
217
            num_names = (FT_UShort)idx;
218
        }
219
      }
220
    }
221
 
222
    /* now load the name strings */
223
    {
224
      FT_UShort  n;
225
 
226
 
227
      if ( FT_NEW_ARRAY( name_strings, num_names ) )
228
        goto Fail;
229
 
230
      for ( n = 0; n < num_names; n++ )
231
      {
232
        FT_UInt  len;
233
 
234
 
235
        if ( FT_STREAM_POS() >= post_limit )
236
          break;
237
        else
238
        {
239
          FT_TRACE6(( "load_format_20: %d byte left in post table\n",
240
                      post_limit - FT_STREAM_POS() ));
241
 
242
          if ( FT_READ_BYTE( len ) )
243
            goto Fail1;
244
        }
245
 
246
        if ( (FT_Int)len > post_limit                   ||
247
             FT_STREAM_POS() > post_limit - (FT_Int)len )
248
        {
249
          FT_ERROR(( "load_format_20:"
250
                     " exceeding string length (%d),"
251
                     " truncating at end of post table (%d byte left)\n",
252
                     len, post_limit - FT_STREAM_POS() ));
253
          len = FT_MAX( 0, post_limit - FT_STREAM_POS() );
254
        }
255
 
256
        if ( FT_NEW_ARRAY( name_strings[n], len + 1 ) ||
257
             FT_STREAM_READ( name_strings[n], len   ) )
258
          goto Fail1;
259
 
260
        name_strings[n][len] = '\0';
261
      }
262
 
263
      if ( n < num_names )
264
      {
265
        FT_ERROR(( "load_format_20:"
266
                   " all entries in post table are already parsed,"
267
                   " using NULL names for gid %d - %d\n",
268
                    n, num_names - 1 ));
269
        for ( ; n < num_names; n++ )
270
          if ( FT_NEW_ARRAY( name_strings[n], 1 ) )
271
            goto Fail1;
272
          else
273
            name_strings[n][0] = '\0';
274
      }
275
    }
276
 
277
    /* all right, set table fields and exit successfully */
278
    {
279
      TT_Post_20  table = &face->postscript_names.names.format_20;
280
 
281
 
282
      table->num_glyphs    = (FT_UShort)num_glyphs;
283
      table->num_names     = (FT_UShort)num_names;
284
      table->glyph_indices = glyph_indices;
285
      table->glyph_names   = name_strings;
286
    }
287
    return FT_Err_Ok;
288
 
289
  Fail1:
290
    {
291
      FT_UShort  n;
292
 
293
 
294
      for ( n = 0; n < num_names; n++ )
295
        FT_FREE( name_strings[n] );
296
    }
297
 
298
  Fail:
299
    FT_FREE( name_strings );
300
    FT_FREE( glyph_indices );
301
 
302
  Exit:
303
    return error;
304
  }
305
 
306
 
307
  static FT_Error
308
  load_format_25( TT_Face    face,
309
                  FT_Stream  stream,
310
                  FT_Long    post_limit )
311
  {
312
    FT_Memory  memory = stream->memory;
313
    FT_Error   error;
314
 
315
    FT_Int     num_glyphs;
316
    FT_Char*   offset_table = 0;
317
 
318
    FT_UNUSED( post_limit );
319
 
320
 
321
    /* UNDOCUMENTED!  This value appears only in the Apple TT specs. */
322
    if ( FT_READ_USHORT( num_glyphs ) )
323
      goto Exit;
324
 
325
    /* check the number of glyphs */
326
    if ( num_glyphs > face->max_profile.numGlyphs || num_glyphs > 258 )
327
    {
328
      error = FT_THROW( Invalid_File_Format );
329
      goto Exit;
330
    }
331
 
332
    if ( FT_NEW_ARRAY( offset_table, num_glyphs )   ||
333
         FT_STREAM_READ( offset_table, num_glyphs ) )
334
      goto Fail;
335
 
336
    /* now check the offset table */
337
    {
338
      FT_Int  n;
339
 
340
 
341
      for ( n = 0; n < num_glyphs; n++ )
342
      {
343
        FT_Long  idx = (FT_Long)n + offset_table[n];
344
 
345
 
346
        if ( idx < 0 || idx > num_glyphs )
347
        {
348
          error = FT_THROW( Invalid_File_Format );
349
          goto Fail;
350
        }
351
      }
352
    }
353
 
354
    /* OK, set table fields and exit successfully */
355
    {
356
      TT_Post_25  table = &face->postscript_names.names.format_25;
357
 
358
 
359
      table->num_glyphs = (FT_UShort)num_glyphs;
360
      table->offsets    = offset_table;
361
    }
362
 
363
    return FT_Err_Ok;
364
 
365
  Fail:
366
    FT_FREE( offset_table );
367
 
368
  Exit:
369
    return error;
370
  }
371
 
372
 
373
  static FT_Error
374
  load_post_names( TT_Face  face )
375
  {
376
    FT_Stream  stream;
377
    FT_Error   error;
378
    FT_Fixed   format;
379
    FT_ULong   post_len;
380
    FT_Long    post_limit;
381
 
382
 
383
    /* get a stream for the face's resource */
384
    stream = face->root.stream;
385
 
386
    /* seek to the beginning of the PS names table */
387
    error = face->goto_table( face, TTAG_post, stream, &post_len );
388
    if ( error )
389
      goto Exit;
390
 
391
    post_limit = FT_STREAM_POS() + post_len;
392
 
393
    format = face->postscript.FormatType;
394
 
395
    /* go to beginning of subtable */
396
    if ( FT_STREAM_SKIP( 32 ) )
397
      goto Exit;
398
 
399
    /* now read postscript table */
400
    if ( format == 0x00020000L )
401
      error = load_format_20( face, stream, post_limit );
402
    else if ( format == 0x00028000L )
403
      error = load_format_25( face, stream, post_limit );
404
    else
405
      error = FT_THROW( Invalid_File_Format );
406
 
407
    face->postscript_names.loaded = 1;
408
 
409
  Exit:
410
    return error;
411
  }
412
 
413
 
414
  FT_LOCAL_DEF( void )
415
  tt_face_free_ps_names( TT_Face  face )
416
  {
417
    FT_Memory      memory = face->root.memory;
418
    TT_Post_Names  names  = &face->postscript_names;
419
    FT_Fixed       format;
420
 
421
 
422
    if ( names->loaded )
423
    {
424
      format = face->postscript.FormatType;
425
 
426
      if ( format == 0x00020000L )
427
      {
428
        TT_Post_20  table = &names->names.format_20;
429
        FT_UShort   n;
430
 
431
 
432
        FT_FREE( table->glyph_indices );
433
        table->num_glyphs = 0;
434
 
435
        for ( n = 0; n < table->num_names; n++ )
436
          FT_FREE( table->glyph_names[n] );
437
 
438
        FT_FREE( table->glyph_names );
439
        table->num_names = 0;
440
      }
441
      else if ( format == 0x00028000L )
442
      {
443
        TT_Post_25  table = &names->names.format_25;
444
 
445
 
446
        FT_FREE( table->offsets );
447
        table->num_glyphs = 0;
448
      }
449
    }
450
    names->loaded = 0;
451
  }
452
 
453
 
454
  /*************************************************************************/
455
  /*                                                                       */
456
  /*                                                             */
457
  /*    tt_face_get_ps_name                                                */
458
  /*                                                                       */
459
  /*                                                          */
460
  /*    Get the PostScript glyph name of a glyph.                          */
461
  /*                                                                       */
462
  /*                                                                */
463
  /*    face   :: A handle to the parent face.                             */
464
  /*                                                                       */
465
  /*    idx    :: The glyph index.                                         */
466
  /*                                                                       */
467
  /*                                                                */
468
  /*    PSname :: The address of a string pointer.  Will be NULL in case   */
469
  /*              of error, otherwise it is a pointer to the glyph name.   */
470
  /*                                                                       */
471
  /*              You must not modify the returned string!                 */
472
  /*                                                                       */
473
  /*                                                               */
474
  /*    FreeType error code.  0 means success.                             */
475
  /*                                                                       */
476
  FT_LOCAL_DEF( FT_Error )
477
  tt_face_get_ps_name( TT_Face      face,
478
                       FT_UInt      idx,
479
                       FT_String**  PSname )
480
  {
481
    FT_Error       error;
482
    TT_Post_Names  names;
483
    FT_Fixed       format;
484
 
485
#ifdef FT_CONFIG_OPTION_POSTSCRIPT_NAMES
486
    FT_Service_PsCMaps  psnames;
487
#endif
488
 
489
 
490
    if ( !face )
491
      return FT_THROW( Invalid_Face_Handle );
492
 
493
    if ( idx >= (FT_UInt)face->max_profile.numGlyphs )
494
      return FT_THROW( Invalid_Glyph_Index );
495
 
496
#ifdef FT_CONFIG_OPTION_POSTSCRIPT_NAMES
497
    psnames = (FT_Service_PsCMaps)face->psnames;
498
    if ( !psnames )
499
      return FT_THROW( Unimplemented_Feature );
500
#endif
501
 
502
    names = &face->postscript_names;
503
 
504
    /* `.notdef' by default */
505
    *PSname = MAC_NAME( 0 );
506
 
507
    format = face->postscript.FormatType;
508
 
509
    if ( format == 0x00010000L )
510
    {
511
      if ( idx < 258 )                    /* paranoid checking */
512
        *PSname = MAC_NAME( idx );
513
    }
514
    else if ( format == 0x00020000L )
515
    {
516
      TT_Post_20  table = &names->names.format_20;
517
 
518
 
519
      if ( !names->loaded )
520
      {
521
        error = load_post_names( face );
522
        if ( error )
523
          goto End;
524
      }
525
 
526
      if ( idx < (FT_UInt)table->num_glyphs )
527
      {
528
        FT_UShort  name_index = table->glyph_indices[idx];
529
 
530
 
531
        if ( name_index < 258 )
532
          *PSname = MAC_NAME( name_index );
533
        else
534
          *PSname = (FT_String*)table->glyph_names[name_index - 258];
535
      }
536
    }
537
    else if ( format == 0x00028000L )
538
    {
539
      TT_Post_25  table = &names->names.format_25;
540
 
541
 
542
      if ( !names->loaded )
543
      {
544
        error = load_post_names( face );
545
        if ( error )
546
          goto End;
547
      }
548
 
549
      if ( idx < (FT_UInt)table->num_glyphs )    /* paranoid checking */
550
      {
551
        idx    += table->offsets[idx];
552
        *PSname = MAC_NAME( idx );
553
      }
554
    }
555
 
556
    /* nothing to do for format == 0x00030000L */
557
 
558
  End:
559
    return FT_Err_Ok;
560
  }
561
 
562
 
563
/* END */