OLD | NEW |
| (Empty) |
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 "../../include/ft2build.h" | |
29 #include "../../include/freetype/internal/ftdebug.h" | |
30 #include "../../include/freetype/internal/ftstream.h" | |
31 #include "../../include/freetype/tttags.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 "../../include/freetype/internal/services/svpscmap.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", "Acircumf
lex", | |
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 /* <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 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 */ | |
OLD | NEW |