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