1 /***************************************************************************/ |
|
2 /* */ |
|
3 /* ttpost.c */ |
|
4 /* */ |
|
5 /* Postcript name table processing for TrueType and OpenType fonts */ |
|
6 /* (body). */ |
|
7 /* */ |
|
8 /* Copyright 1996-2001, 2002, 2003, 2006, 2007, 2008, 2009, 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 /* */ |
|
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 <ft2build.h> |
|
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 = SFNT_Err_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 SFNT_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 = SFNT_Err_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 = SFNT_Err_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 SFNT_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 = SFNT_Err_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 /* <Function> */ |
|
457 /* tt_face_get_ps_name */ |
|
458 /* */ |
|
459 /* <Description> */ |
|
460 /* Get the PostScript glyph name of a glyph. */ |
|
461 /* */ |
|
462 /* <Input> */ |
|
463 /* face :: A handle to the parent face. */ |
|
464 /* */ |
|
465 /* idx :: The glyph index. */ |
|
466 /* */ |
|
467 /* <InOut> */ |
|
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 /* <Output> */ |
|
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 SFNT_Err_Invalid_Face_Handle; |
|
492 |
|
493 if ( idx >= (FT_UInt)face->max_profile.numGlyphs ) |
|
494 return SFNT_Err_Invalid_Glyph_Index; |
|
495 |
|
496 #ifdef FT_CONFIG_OPTION_POSTSCRIPT_NAMES |
|
497 psnames = (FT_Service_PsCMaps)face->psnames; |
|
498 if ( !psnames ) |
|
499 return SFNT_Err_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 SFNT_Err_Ok; |
|
560 } |
|
561 |
|
562 |
|
563 /* END */ |
|