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