1 /***************************************************************************/
5 /* Postcript name table processing for TrueType and OpenType fonts */
8 /* Copyright 1996-2001, 2002, 2003, 2006, 2007 by */
9 /* David Turner, Robert Wilhelm, and Werner Lemberg. */
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. */
17 /***************************************************************************/
19 /*************************************************************************/
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 */
25 /*************************************************************************/
29 #include FT_INTERNAL_STREAM_H
30 #include FT_TRUETYPE_TAGS_H
37 /*************************************************************************/
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. */
44 #define FT_COMPONENT trace_ttpost
47 /* If this configuration macro is defined, we rely on the `PSNames' */
48 /* module to grab the glyph names. */
50 #ifdef FT_CONFIG_OPTION_POSTSCRIPT_NAMES
53 #include FT_SERVICE_POSTSCRIPT_CMAPS_H
55 #define MAC_NAME( x ) ( (FT_String*)psnames->macintosh_name( x ) )
58 #else /* FT_CONFIG_OPTION_POSTSCRIPT_NAMES */
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. */
65 #define MAC_NAME( x ) tt_post_default_names[x]
67 /* the 258 default Mac PS glyph names */
69 static const FT_String
* tt_post_default_names
[258] =
72 ".notdef", ".null", "CR", "space", "exclam",
73 "quotedbl", "numbersign", "dollar", "percent", "ampersand",
75 "quotesingle", "parenleft", "parenright", "asterisk", "plus",
76 "comma", "hyphen", "period", "slash", "zero",
78 "one", "two", "three", "four", "five",
79 "six", "seven", "eight", "nine", "colon",
81 "semicolon", "less", "equal", "greater", "question",
82 "at", "A", "B", "C", "D",
84 "E", "F", "G", "H", "I",
85 "J", "K", "L", "M", "N",
87 "O", "P", "Q", "R", "S",
88 "T", "U", "V", "W", "X",
90 "Y", "Z", "bracketleft", "backslash", "bracketright",
91 "asciicircum", "underscore", "grave", "a", "b",
93 "c", "d", "e", "f", "g",
94 "h", "i", "j", "k", "l",
96 "m", "n", "o", "p", "q",
97 "r", "s", "t", "u", "v",
99 "w", "x", "y", "z", "braceleft",
100 "bar", "braceright", "asciitilde", "Adieresis", "Aring",
102 "Ccedilla", "Eacute", "Ntilde", "Odieresis", "Udieresis",
103 "aacute", "agrave", "acircumflex", "adieresis", "atilde",
105 "aring", "ccedilla", "eacute", "egrave", "ecircumflex",
106 "edieresis", "iacute", "igrave", "icircumflex", "idieresis",
108 "ntilde", "oacute", "ograve", "ocircumflex", "odieresis",
109 "otilde", "uacute", "ugrave", "ucircumflex", "udieresis",
111 "dagger", "degree", "cent", "sterling", "section",
112 "bullet", "paragraph", "germandbls", "registered", "copyright",
114 "trademark", "acute", "dieresis", "notequal", "AE",
115 "Oslash", "infinity", "plusminus", "lessequal", "greaterequal",
117 "yen", "mu", "partialdiff", "summation", "product",
118 "pi", "integral", "ordfeminine", "ordmasculine", "Omega",
120 "ae", "oslash", "questiondown", "exclamdown", "logicalnot",
121 "radical", "florin", "approxequal", "Delta", "guillemotleft",
123 "guillemotright", "ellipsis", "nbspace", "Agrave", "Atilde",
124 "Otilde", "OE", "oe", "endash", "emdash",
126 "quotedblleft", "quotedblright", "quoteleft", "quoteright", "divide",
127 "lozenge", "ydieresis", "Ydieresis", "fraction", "currency",
129 "guilsinglleft", "guilsinglright", "fi", "fl", "daggerdbl",
130 "periodcentered", "quotesinglbase", "quotedblbase", "perthousand", "Acircumflex",
132 "Ecircumflex", "Aacute", "Edieresis", "Egrave", "Iacute",
133 "Icircumflex", "Idieresis", "Igrave", "Oacute", "Ocircumflex",
135 "apple", "Ograve", "Uacute", "Ucircumflex", "Ugrave",
136 "dotlessi", "circumflex", "tilde", "macron", "breve",
138 "dotaccent", "ring", "cedilla", "hungarumlaut", "ogonek",
139 "caron", "Lslash", "lslash", "Scaron", "scaron",
141 "Zcaron", "zcaron", "brokenbar", "Eth", "eth",
142 "Yacute", "yacute", "Thorn", "thorn", "minus",
144 "multiply", "onesuperior", "twosuperior", "threesuperior", "onehalf",
145 "onequarter", "threequarters", "franc", "Gbreve", "gbreve",
147 "Idot", "Scedilla", "scedilla", "Cacute", "cacute",
148 "Ccaron", "ccaron", "dmacron",
152 #endif /* FT_CONFIG_OPTION_POSTSCRIPT_NAMES */
156 load_format_20( TT_Face face
,
159 FT_Memory memory
= stream
->memory
;
165 FT_UShort
* glyph_indices
= 0;
166 FT_Char
** name_strings
= 0;
169 if ( FT_READ_USHORT( num_glyphs
) )
172 /* UNDOCUMENTED! The number of glyphs in this table can be smaller */
173 /* than the value in the maxp table (cf. cyberbit.ttf). */
175 /* There already exist fonts which have more than 32768 glyph names */
176 /* in this table, so the test for this threshold has been dropped. */
178 if ( num_glyphs
> face
->max_profile
.numGlyphs
)
180 error
= SFNT_Err_Invalid_File_Format
;
184 /* load the indices */
189 if ( FT_NEW_ARRAY ( glyph_indices
, num_glyphs
) ||
190 FT_FRAME_ENTER( num_glyphs
* 2L ) )
193 for ( n
= 0; n
< num_glyphs
; n
++ )
194 glyph_indices
[n
] = FT_GET_USHORT();
199 /* compute number of names stored in table */
206 for ( n
= 0; n
< num_glyphs
; n
++ )
211 idx
= glyph_indices
[n
];
215 if ( idx
> num_names
)
216 num_names
= (FT_UShort
)idx
;
221 /* now load the name strings */
226 if ( FT_NEW_ARRAY( name_strings
, num_names
) )
229 for ( n
= 0; n
< num_names
; n
++ )
234 if ( FT_READ_BYTE ( len
) ||
235 FT_NEW_ARRAY( name_strings
[n
], len
+ 1 ) ||
236 FT_STREAM_READ ( name_strings
[n
], len
) )
239 name_strings
[n
][len
] = '\0';
243 /* all right, set table fields and exit successfully */
245 TT_Post_20 table
= &face
->postscript_names
.names
.format_20
;
248 table
->num_glyphs
= (FT_UShort
)num_glyphs
;
249 table
->num_names
= (FT_UShort
)num_names
;
250 table
->glyph_indices
= glyph_indices
;
251 table
->glyph_names
= name_strings
;
260 for ( n
= 0; n
< num_names
; n
++ )
261 FT_FREE( name_strings
[n
] );
265 FT_FREE( name_strings
);
266 FT_FREE( glyph_indices
);
274 load_format_25( TT_Face face
,
277 FT_Memory memory
= stream
->memory
;
281 FT_Char
* offset_table
= 0;
284 /* UNDOCUMENTED! This value appears only in the Apple TT specs. */
285 if ( FT_READ_USHORT( num_glyphs
) )
288 /* check the number of glyphs */
289 if ( num_glyphs
> face
->max_profile
.numGlyphs
|| num_glyphs
> 258 )
291 error
= SFNT_Err_Invalid_File_Format
;
295 if ( FT_NEW_ARRAY( offset_table
, num_glyphs
) ||
296 FT_STREAM_READ( offset_table
, num_glyphs
) )
299 /* now check the offset table */
304 for ( n
= 0; n
< num_glyphs
; n
++ )
306 FT_Long idx
= (FT_Long
)n
+ offset_table
[n
];
309 if ( idx
< 0 || idx
> num_glyphs
)
311 error
= SFNT_Err_Invalid_File_Format
;
317 /* OK, set table fields and exit successfully */
319 TT_Post_25 table
= &face
->postscript_names
.names
.format_25
;
322 table
->num_glyphs
= (FT_UShort
)num_glyphs
;
323 table
->offsets
= offset_table
;
329 FT_FREE( offset_table
);
337 load_post_names( TT_Face face
)
344 /* get a stream for the face's resource */
345 stream
= face
->root
.stream
;
347 /* seek to the beginning of the PS names table */
348 error
= face
->goto_table( face
, TTAG_post
, stream
, 0 );
352 format
= face
->postscript
.FormatType
;
354 /* go to beginning of subtable */
355 if ( FT_STREAM_SKIP( 32 ) )
358 /* now read postscript table */
359 if ( format
== 0x00020000L
)
360 error
= load_format_20( face
, stream
);
361 else if ( format
== 0x00028000L
)
362 error
= load_format_25( face
, stream
);
364 error
= SFNT_Err_Invalid_File_Format
;
366 face
->postscript_names
.loaded
= 1;
374 tt_face_free_ps_names( TT_Face face
)
376 FT_Memory memory
= face
->root
.memory
;
377 TT_Post_Names names
= &face
->postscript_names
;
383 format
= face
->postscript
.FormatType
;
385 if ( format
== 0x00020000L
)
387 TT_Post_20 table
= &names
->names
.format_20
;
391 FT_FREE( table
->glyph_indices
);
392 table
->num_glyphs
= 0;
394 for ( n
= 0; n
< table
->num_names
; n
++ )
395 FT_FREE( table
->glyph_names
[n
] );
397 FT_FREE( table
->glyph_names
);
398 table
->num_names
= 0;
400 else if ( format
== 0x00028000L
)
402 TT_Post_25 table
= &names
->names
.format_25
;
405 FT_FREE( table
->offsets
);
406 table
->num_glyphs
= 0;
413 /*************************************************************************/
416 /* tt_face_get_ps_name */
419 /* Gets the PostScript glyph name of a glyph. */
422 /* face :: A handle to the parent face. */
424 /* idx :: The glyph index. */
426 /* PSname :: The address of a string pointer. Will be NULL in case */
427 /* of error, otherwise it is a pointer to the glyph name. */
429 /* You must not modify the returned string! */
432 /* FreeType error code. 0 means success. */
434 FT_LOCAL_DEF( FT_Error
)
435 tt_face_get_ps_name( TT_Face face
,
443 #ifdef FT_CONFIG_OPTION_POSTSCRIPT_NAMES
444 FT_Service_PsCMaps psnames
;
449 return SFNT_Err_Invalid_Face_Handle
;
451 if ( idx
>= (FT_UInt
)face
->max_profile
.numGlyphs
)
452 return SFNT_Err_Invalid_Glyph_Index
;
454 #ifdef FT_CONFIG_OPTION_POSTSCRIPT_NAMES
455 psnames
= (FT_Service_PsCMaps
)face
->psnames
;
457 return SFNT_Err_Unimplemented_Feature
;
460 names
= &face
->postscript_names
;
462 /* `.notdef' by default */
463 *PSname
= MAC_NAME( 0 );
465 format
= face
->postscript
.FormatType
;
467 if ( format
== 0x00010000L
)
469 if ( idx
< 258 ) /* paranoid checking */
470 *PSname
= MAC_NAME( idx
);
472 else if ( format
== 0x00020000L
)
474 TT_Post_20 table
= &names
->names
.format_20
;
477 if ( !names
->loaded
)
479 error
= load_post_names( face
);
484 if ( idx
< (FT_UInt
)table
->num_glyphs
)
486 FT_UShort name_index
= table
->glyph_indices
[idx
];
489 if ( name_index
< 258 )
490 *PSname
= MAC_NAME( name_index
);
492 *PSname
= (FT_String
*)table
->glyph_names
[name_index
- 258];
495 else if ( format
== 0x00028000L
)
497 TT_Post_25 table
= &names
->names
.format_25
;
500 if ( !names
->loaded
)
502 error
= load_post_names( face
);
507 if ( idx
< (FT_UInt
)table
->num_glyphs
) /* paranoid checking */
509 idx
+= table
->offsets
[idx
];
510 *PSname
= MAC_NAME( idx
);
514 /* nothing to do for format == 0x00030000L */